From 9a2c2ef814bbbfb302d493f05d037edfb92270d7 Mon Sep 17 00:00:00 2001 From: Dmitrii Fediuk Date: Wed, 26 Jun 2024 17:49:33 +0100 Subject: [PATCH] https://github.com/thehcginstitute-com/wp/issues/31 --- wp-content/plugins/wp-rocket/SECURITY.md | 6 + .../wp-rocket/assets/css/wpr-admin-rtl.css | 333 +- .../assets/css/wpr-admin-rtl.min.css | 1 + .../wp-rocket/assets/css/wpr-admin.css | 3103 +++++++- .../wp-rocket/assets/css/wpr-admin.min.css | 1 + .../wp-rocket/assets/css/wpr-modal.css | 76 +- .../wp-rocket/assets/img/automatic.svg | 27 +- .../wp-rocket/assets/img/bandwidth.svg | 34 +- .../wp-rocket/assets/img/bg-activated.svg | 13 +- .../wp-rocket/assets/img/configuration.svg | 32 +- .../wp-rocket/assets/img/heartbeat-hover.svg | 6 +- .../wp-rocket/assets/img/heartbeat.svg | 6 +- .../wp-rocket/assets/img/icon-128x128.png | Bin 11341 -> 10719 bytes .../wp-rocket/assets/img/icon-256x256.png | Bin 4832 -> 4187 bytes .../wp-rocket/assets/img/icon-i-circle.svg | 3 + .../wp-rocket/assets/img/icon-user-cache.svg | 100 + .../wp-rocket/assets/img/imagify-hover.svg | 32 +- .../wp-rocket/assets/img/imagify-info.svg | 1 + .../wp-rocket/assets/img/imagify-install.svg | 16 + .../wp-rocket/assets/img/imagify-score.png | Bin 0 -> 54956 bytes .../plugins/wp-rocket/assets/img/imagify.svg | 32 +- .../plugins/wp-rocket/assets/img/infinite.svg | 6 +- .../wp-rocket/assets/img/logo-adblock.svg | 31 - .../wp-rocket/assets/img/logo-cloudflare.svg | 25 +- .../wp-rocket/assets/img/logo-cloudflare2.svg | 25 +- .../wp-rocket/assets/img/logo-facebook.svg | 1 - .../assets/img/logo-google-analytics.svg | 166 - .../wp-rocket/assets/img/logo-sucuri.png | Bin 21221 -> 13153 bytes .../wp-rocket/assets/img/logo-varnish.svg | 2 +- .../wp-rocket/assets/img/logo-webp.svg | 1 + .../assets/img/logo-wprocket-dark.svg | 41 +- .../assets/img/logo-wprocket-light.svg | 42 - .../wp-rocket/assets/img/one-com-logo.svg | 9 + .../assets/img/picto-wprocket-dark.svg | 40 +- .../assets/img/picto-wprocket-light.svg | 47 - .../plugins/wp-rocket/assets/img/play-alt.svg | 3 +- .../wp-rocket/assets/img/play-hover.svg | 3 +- .../plugins/wp-rocket/assets/img/play.svg | 3 +- .../plugins/wp-rocket/assets/img/plus.svg | 13 +- .../plugins/wp-rocket/assets/img/warning.svg | 15 +- .../wp-rocket/assets/js/cpcss-removal.js | 23 +- .../wp-rocket/assets/js/cpcss-removal.min.js | 2 +- .../wp-rocket/assets/js/editor/editor.js | 1 - .../assets/js/elementor-animation.js | 1 + .../plugins/wp-rocket/assets/js/heartbeat.js | 0 .../wp-rocket/assets/js/lazyload-css.js | 81 + .../assets/js/lazyload-css.js.min.map | 1 + .../wp-rocket/assets/js/lazyload-css.min.js | 2 + .../assets/js/lazyload-css.min.js.map | 1 + .../wp-rocket/assets/js/lazyload-scripts.js | 108 - .../assets/js/lazyload-scripts.min.js | 4 +- .../assets/js/lazyload/17.5/lazyload.js | 813 +++ .../assets/js/lazyload/17.5/lazyload.min.js | 1 + .../assets/js/lazyload/17.8.3/lazyload.js | 862 +++ .../assets/js/lazyload/17.8.3/lazyload.min.js | 1 + .../plugins/wp-rocket/assets/js/lcp-beacon.js | 369 + .../wp-rocket/assets/js/lcp-beacon.min.js | 2 + .../wp-rocket/assets/js/lcp-beacon.min.js.map | 1 + .../wp-rocket/assets/js/micromodal.min.js | 2 +- .../wp-rocket/assets/js/wpr-admin-common.js | 55 + .../plugins/wp-rocket/assets/js/wpr-admin.js | 3103 +++++++- .../wp-rocket/assets/js/wpr-admin.js.map | 2 +- .../wp-rocket/assets/js/wpr-admin.js.min.map | 1 + .../wp-rocket/assets/js/wpr-admin.min.js | 2 + .../wp-rocket/assets/js/wpr-admin.min.js.map | 1 + .../plugins/wp-rocket/assets/js/wpr-cpcss.js | 34 +- .../plugins/wp-rocket/assets/js/wpr-modal.js | 202 - wp-content/plugins/wp-rocket/composer.json | 130 +- wp-content/plugins/wp-rocket/composer.lock | 4625 ------------ wp-content/plugins/wp-rocket/contributors.txt | 21 +- .../wp-rocket/dynamic-lists-delayjs.json | 1 + .../dynamic-lists-incompatible-plugins.json | 1 + .../plugins/wp-rocket/dynamic-lists.json | 1 + .../wp-rocket/inc/3rd-party/3rd-party.php | 18 - .../inc/3rd-party/hosting/flywheel.php | 2 +- .../inc/3rd-party/hosting/kinsta.php | 166 - .../inc/3rd-party/hosting/pagely.php | 2 +- .../inc/3rd-party/hosting/pressidium.php | 61 - .../inc/3rd-party/hosting/presslabs.php | 8 +- .../inc/3rd-party/hosting/siteground.php | 29 +- .../inc/3rd-party/plugins/age-verify.php | 59 - .../inc/3rd-party/plugins/autoptimize.php | 26 +- .../plugins/cookies/weepie-cookie-allow.php | 2 +- .../inc/3rd-party/plugins/custom-login.php | 11 +- .../ecommerce/woocommerce-multilingual.php | 125 +- .../inc/3rd-party/plugins/envira-gallery.php | 2 - .../inc/3rd-party/plugins/i18n/polylang.php | 2 +- .../inc/3rd-party/plugins/i18n/wpml.php | 11 - .../inc/3rd-party/plugins/jetpack.php | 187 - .../inc/3rd-party/plugins/nginx-helper.php | 11 +- .../3rd-party/plugins/security/secupress.php | 12 +- .../plugins/security/sf-move-login.php | 10 +- .../plugins/security/wps-hide-login.php | 11 +- .../plugins/seo/all-in-one-seo-pack.php | 101 - .../3rd-party/plugins/seo/rank-math-seo.php | 91 - .../inc/3rd-party/plugins/seo/seopress.php | 98 - .../plugins/seo/the-seo-framework.php | 153 - .../inc/3rd-party/plugins/seo/yoast-seo.php | 99 - .../3rd-party/plugins/varnish-http-purge.php | 2 +- .../inc/3rd-party/plugins/wp-rest-api.php | 2 +- .../inc/3rd-party/themes/studiopress.php | 6 +- .../wp-rocket/inc/3rd-party/themes/uncode.php | 64 - .../plugins/wp-rocket/inc/API/bypass.php | 5 +- .../plugins/wp-rocket/inc/API/preload.php | 112 - .../inc/Addon/Cloudflare/API/Client.php | 226 + .../inc/Addon/Cloudflare/API/Endpoints.php | 174 + .../inc/Addon/Cloudflare/APIClient.php | 394 - .../inc/Addon/Cloudflare/Admin/Subscriber.php | 131 + .../inc/Addon/Cloudflare/Auth/APIKey.php | 71 + .../Addon/Cloudflare/Auth/APIKeyFactory.php | 44 + .../Cloudflare/Auth/AuthFactoryInterface.php | 16 + .../Addon/Cloudflare/Auth/AuthInterface.php | 21 + .../Cloudflare/AuthenticationException.php | 7 - .../inc/Addon/Cloudflare/Cloudflare.php | 520 +- .../inc/Addon/Cloudflare/ServiceProvider.php | 68 + .../inc/Addon/Cloudflare/Subscriber.php | 674 +- .../Cloudflare/UnauthorizedException.php | 7 - .../inc/Addon/Cloudflare/composer.json | 51 - .../wp-rocket/inc/Addon/ServiceProvider.php | 94 +- .../Sucuri/Subscriber.php} | 202 +- .../inc/Addon/Varnish/ServiceProvider.php | 35 +- .../inc/Addon/Varnish/Subscriber.php | 8 +- .../wp-rocket/inc/Addon/Varnish/composer.json | 42 +- .../wp-rocket/inc/Addon/WebP/AbstractWebp.php | 103 + .../inc/Addon/WebP/AdminSubscriber.php | 214 + .../wp-rocket/inc/Addon/WebP/Subscriber.php | 598 ++ .../ActionScheduler/action-scheduler.php | 65 + .../ActionScheduler/changelog.txt | 81 + .../classes/ActionScheduler_ActionClaim.php | 23 + .../classes/ActionScheduler_ActionFactory.php | 259 + .../classes/ActionScheduler_AdminView.php | 252 + ...tionScheduler_AsyncRequest_QueueRunner.php | 97 + .../classes/ActionScheduler_Compatibility.php | 109 + .../ActionScheduler_DataController.php | 187 + .../classes/ActionScheduler_DateTime.php | 79 + .../classes/ActionScheduler_Exception.php | 11 + .../ActionScheduler_FatalErrorMonitor.php | 55 + ...ActionScheduler_InvalidActionException.php | 47 + .../classes/ActionScheduler_ListTable.php | 657 ++ .../classes/ActionScheduler_LogEntry.php | 67 + .../classes/ActionScheduler_NullLogEntry.php | 11 + .../classes/ActionScheduler_OptionLock.php | 49 + .../classes/ActionScheduler_QueueCleaner.php | 158 + .../classes/ActionScheduler_QueueRunner.php | 220 + .../classes/ActionScheduler_Versions.php | 62 + .../ActionScheduler_WPCommentCleaner.php | 115 + .../ActionScheduler_wcSystemStatus.php | 166 + .../ActionScheduler_WPCLI_QueueRunner.php | 197 + ...ctionScheduler_WPCLI_Scheduler_command.php | 188 + .../classes/WP_CLI/Migration_Command.php | 148 + .../classes/WP_CLI/ProgressBar.php | 119 + .../classes/abstracts/ActionScheduler.php | 304 + .../ActionScheduler_Abstract_ListTable.php | 766 ++ .../ActionScheduler_Abstract_QueueRunner.php | 303 + ...onScheduler_Abstract_RecurringSchedule.php | 102 + .../ActionScheduler_Abstract_Schedule.php | 83 + .../ActionScheduler_Abstract_Schema.php | 172 + .../abstracts/ActionScheduler_Lock.php | 62 + .../abstracts/ActionScheduler_Logger.php | 176 + .../abstracts/ActionScheduler_Store.php | 450 ++ .../ActionScheduler_TimezoneHelper.php | 152 + .../actions/ActionScheduler_Action.php | 96 + .../ActionScheduler_CanceledAction.php | 23 + .../ActionScheduler_FinishedAction.php | 16 + .../actions/ActionScheduler_NullAction.php | 16 + .../data-stores/ActionScheduler_DBLogger.php | 154 + .../data-stores/ActionScheduler_DBStore.php | 1081 +++ .../ActionScheduler_HybridStore.php | 426 ++ .../ActionScheduler_wpCommentLogger.php | 240 + .../ActionScheduler_wpPostStore.php | 1075 +++ ...eduler_wpPostStore_PostStatusRegistrar.php | 58 + ...cheduler_wpPostStore_PostTypeRegistrar.php | 50 + ...cheduler_wpPostStore_TaxonomyRegistrar.php | 26 + .../classes/migration/ActionMigrator.php | 109 + .../ActionScheduler_DBStoreMigrator.php | 47 + .../classes/migration/BatchFetcher.php | 86 + .../classes/migration/Config.php | 168 + .../classes/migration/Controller.php | 226 + .../migration/DryRun_ActionMigrator.php | 28 + .../classes/migration/DryRun_LogMigrator.php | 23 + .../classes/migration/LogMigrator.php | 49 + .../classes/migration/Runner.php | 136 + .../classes/migration/Scheduler.php | 128 + .../ActionScheduler_CanceledSchedule.php | 57 + .../ActionScheduler_CronSchedule.php | 102 + .../ActionScheduler_IntervalSchedule.php | 81 + .../ActionScheduler_NullSchedule.php | 31 + .../schedules/ActionScheduler_Schedule.php | 18 + .../ActionScheduler_SimpleSchedule.php | 71 + .../schema/ActionScheduler_LoggerSchema.php | 90 + .../schema/ActionScheduler_StoreSchema.php | 129 + ...eduler_Abstract_QueueRunner_Deprecated.php | 27 + .../ActionScheduler_AdminView_Deprecated.php | 147 + .../ActionScheduler_Schedule_Deprecated.php | 29 + .../ActionScheduler_Store_Deprecated.php | 49 + .../ActionScheduler/deprecated/functions.php | 126 + .../ActionScheduler/functions.php | 424 ++ .../ActionScheduler/lib/WP_Async_Request.php | 191 + .../lib/cron-expression/CronExpression.php | 318 + .../CronExpression_AbstractField.php | 100 + .../CronExpression_DayOfMonthField.php | 110 + .../CronExpression_DayOfWeekField.php | 124 + .../CronExpression_FieldFactory.php | 55 + .../CronExpression_FieldInterface.php | 39 + .../CronExpression_HoursField.php | 47 + .../CronExpression_MinutesField.php | 39 + .../CronExpression_MonthField.php | 55 + .../CronExpression_YearField.php | 43 + .../Dependencies/ActionScheduler/license.txt | 674 ++ .../Dependencies/ActionScheduler/readme.txt | 125 + .../inc/Dependencies/Database/Base.php | 344 + .../inc/Dependencies/Database/Column.php | 965 +++ .../Dependencies/Database/Queries/Compare.php | 180 + .../Dependencies/Database/Queries/Date.php | 1317 ++++ .../Dependencies/Database/Queries/Meta.php | 29 + .../inc/Dependencies/Database/Query.php | 3162 ++++++++ .../inc/Dependencies/Database/Row.php | 65 + .../inc/Dependencies/Database/Schema.php | 88 + .../inc/Dependencies/Database/Table.php | 998 +++ .../Container/Argument/ArgumentInterface.php | 13 + .../Argument/ArgumentResolverInterface.php | 14 + .../Argument/ArgumentResolverTrait.php | 111 + .../Argument/DefaultValueArgument.php | 24 + .../Argument/DefaultValueInterface.php | 13 + .../Argument/Literal/ArrayArgument.php | 15 + .../Argument/Literal/BooleanArgument.php | 15 + .../Argument/Literal/CallableArgument.php | 15 + .../Argument/Literal/FloatArgument.php | 15 + .../Argument/Literal/IntegerArgument.php | 15 + .../Argument/Literal/ObjectArgument.php | 15 + .../Argument/Literal/StringArgument.php | 15 + .../Container/Argument/LiteralArgument.php | 48 + .../Argument/LiteralArgumentInterface.php | 9 + .../Container/Argument/ResolvableArgument.php | 20 + .../Argument/ResolvableArgumentInterface.php | 10 + .../League/Container/Container.php | 210 + .../Container/ContainerAwareInterface.php | 11 + .../League/Container/ContainerAwareTrait.php | 40 + .../Container/Definition/Definition.php | 238 + .../Definition/DefinitionAggregate.php | 117 + .../DefinitionAggregateInterface.php | 21 + .../Definition/DefinitionInterface.php | 25 + .../DefinitionContainerInterface.php | 20 + .../Exception/ContainerException.php | 12 + .../Container/Exception/NotFoundException.php | 12 + .../League/Container/Inflector/Inflector.php | 97 + .../Inflector/InflectorAggregate.php | 44 + .../Inflector/InflectorAggregateInterface.php | 14 + .../Inflector/InflectorInterface.php | 15 + .../League/Container/ReflectionContainer.php | 107 + .../AbstractServiceProvider.php | 28 + .../BootableServiceProviderInterface.php | 6 +- .../ServiceProviderAggregate.php | 76 + .../ServiceProviderAggregateInterface.php | 15 + .../ServiceProviderInterface.php | 15 + .../wp-rocket/inc/Dependencies/Minify/CSS.php | 64 +- .../wp-rocket/inc/Dependencies/Minify/JS.php | 26 +- .../inc/Dependencies/Minify/Minify.php | 84 +- .../Dependencies}/Monolog/ErrorHandler.php | 12 +- .../Monolog/Formatter/FormatterInterface.php | 4 +- .../Monolog/Formatter/HtmlFormatter.php | 10 +- .../Monolog/Formatter/LineFormatter.php | 6 +- .../Monolog/Formatter/NormalizerFormatter.php | 35 +- .../Monolog/Handler/AbstractHandler.php | 12 +- .../Handler/AbstractProcessingHandler.php | 6 +- .../Handler/FormattableHandlerInterface.php | 6 +- .../Handler/FormattableHandlerTrait.php | 8 +- .../Monolog/Handler/HandlerInterface.php | 8 +- .../Handler/ProcessableHandlerInterface.php | 6 +- .../Handler/ProcessableHandlerTrait.php | 6 +- .../Monolog/Handler/StreamHandler.php | 23 +- .../Dependencies}/Monolog/Logger.php | 20 +- .../Processor/IntrospectionProcessor.php | 8 +- .../Monolog/Processor/ProcessorInterface.php | 6 +- .../Dependencies}/Monolog/Registry.php | 18 +- .../Monolog/ResettableInterface.php | 4 +- .../Dependencies}/Monolog/SignalHandler.php | 10 +- .../Dependencies}/Monolog/Utils.php | 6 +- .../ContainerExceptionInterface.php | 5 +- .../Psr/Container}/ContainerInterface.php | 11 +- .../Container}/NotFoundExceptionInterface.php | 5 +- .../Dependencies}/Psr/Log/AbstractLogger.php | 34 +- .../Psr/Log/InvalidArgumentException.php | 2 +- .../Dependencies}/Psr/Log/LogLevel.php | 2 +- .../Psr/Log/LoggerAwareInterface.php | 2 +- .../Psr/Log/LoggerAwareTrait.php | 4 +- .../Dependencies}/Psr/Log/LoggerInterface.php | 4 +- .../Dependencies}/Psr/Log/LoggerTrait.php | 4 +- .../Dependencies}/Psr/Log/NullLogger.php | 4 +- .../Psr/SimpleCache/CacheException.php | 10 + .../Psr/SimpleCache/CacheInterface.php | 97 + .../SimpleCache/InvalidArgumentException.php | 13 + .../Dependencies/RocketLazyload/Assets.php | 98 +- .../Dependencies/RocketLazyload/Iframe.php | 9 +- .../inc/Dependencies/RocketLazyload/Image.php | 147 +- .../inc/Engine/Activation/Activation.php | 43 +- .../inc/Engine/Activation/ServiceProvider.php | 48 +- .../inc/Engine/Admin/API/ServiceProvider.php | 36 + .../inc/Engine/Admin/API/Subscriber.php | 82 + .../Admin/ActionSchedulerSubscriber.php | 39 + .../inc/Engine/Admin/Beacon/Beacon.php | 332 +- .../Engine/Admin/Beacon/ServiceProvider.php | 37 +- .../Admin/Database/Optimization.php} | 41 +- .../Admin/Database/OptimizationProcess.php} | 31 +- .../Engine/Admin/Database/ServiceProvider.php | 46 + .../Admin/Database/Subscriber.php} | 26 +- .../Admin/Deactivation/DeactivationIntent.php | 190 +- .../Engine/Admin/Deactivation/Subscriber.php | 107 + .../Admin/DomainChange/ServiceProvider.php | 41 + .../Engine/Admin/DomainChange/Subscriber.php | 210 + .../Metaboxes/PostEditOptionsSubscriber.php | 205 + .../inc/Engine/Admin/ServiceProvider.php | 58 +- .../inc/Engine/Admin/Settings/Page.php | 1059 +-- .../inc/Engine/Admin/Settings/Render.php | 197 +- .../Engine/Admin/Settings/ServiceProvider.php | 59 +- .../inc/Engine/Admin/Settings/Settings.php | 147 +- .../inc/Engine/Admin/Settings/Subscriber.php | 89 +- .../inc/Engine/CDN/Admin/Subscriber.php | 32 + .../plugins/wp-rocket/inc/Engine/CDN/CDN.php | 112 +- .../inc/Engine/CDN/RocketCDN/APIClient.php | 25 +- .../CDN/RocketCDN/AdminPageSubscriber.php | 39 +- .../CDN/RocketCDN/NoticesSubscriber.php | 68 +- .../Engine/CDN/RocketCDN/RESTSubscriber.php | 8 +- .../Engine/CDN/RocketCDN/ServiceProvider.php | 66 +- .../inc/Engine/CDN/RocketCDN/composer.json | 55 - .../Engine/CDN/RocketCDN/views/cta-big.php | 48 +- .../inc/Engine/CDN/ServiceProvider.php | 40 +- .../wp-rocket/inc/Engine/CDN/Subscriber.php | 80 +- .../inc/Engine/Cache/AdminSubscriber.php | 132 +- .../inc/Engine/Cache/AdvancedCache.php | 2 +- .../Engine/Cache/Config/ConfigSubscriber.php | 108 + .../inc/Engine/Cache/Config/Subscriber.php | 30 + .../wp-rocket/inc/Engine/Cache/Purge.php | 104 +- .../Engine/Cache/PurgeActionsSubscriber.php | 89 +- .../Cache/PurgeExpired/PurgeExpiredCache.php | 5 +- .../inc/Engine/Cache/ServiceProvider.php | 81 +- .../wp-rocket/inc/Engine/Cache/WPCache.php | 21 +- .../inc/Engine/Capabilities/Manager.php | 29 +- .../Engine/Capabilities/ServiceProvider.php | 33 +- .../inc/Engine/Capabilities/Subscriber.php | 17 + .../inc/Engine/Common/Ajax/AjaxHandler.php | 35 + .../Engine/Common/Cache/CacheInterface.php | 36 + .../Engine/Common/Cache/FilesystemCache.php | 236 + .../Engine/Common/Clock/ClockInterface.php | 27 + .../inc/Engine/Common/Clock/WPRClock.php | 35 + .../Engine/Common/Context/AbstractContext.php | 76 + .../Common/Context/ContextInterface.php | 14 + .../Common/Database/Queries/AbstractQuery.php | 650 ++ .../Engine/Common/Database/TableInterface.php | 40 + .../Common/Database/Tables/AbstractTable.php | 145 + .../Common/ExtractCSS/ServiceProvider.php | 49 + .../Engine/Common/ExtractCSS/Subscriber.php | 168 + .../JobManager/APIHandler/APIClient.php | 144 + .../APIHandler/AbstractAPIClient.php | 144 + .../AbstractFactory/SaasFactory.php | 23 + .../Common/JobManager/Cron/Subscriber.php | 358 + .../Engine/Common/JobManager/JobProcessor.php | 652 ++ .../JobManager/Managers/AbstractManager.php | 223 + .../JobManager/Managers/ManagerInterface.php | 49 + .../Engine/Common/JobManager/Queue/Queue.php | 79 + .../Common/JobManager/ServiceProvider.php | 91 + .../Strategy/Context/RetryContext.php | 37 + .../Strategy/Factory/StrategyFactory.php | 64 + .../Strategy/Strategies/DefaultProcess.php | 123 + .../Strategy/Strategies/JobSetFail.php | 45 + .../Strategy/Strategies/ResetRetryProcess.php | 38 + .../Strategy/Strategies/StrategyInterface.php | 15 + .../Engine/Common/Queue/AbstractASQueue.php | 253 + .../inc/Engine/Common/Queue/Cleaner.php | 103 + .../Engine/Common/Queue/QueueInterface.php | 118 + .../Engine/Common/Queue/RUCSSQueueRunner.php | 280 + .../wp-rocket/inc/Engine/Common/Utils.php | 31 + .../Argument/ArgumentResolverInterface.php | 26 - .../Argument/ArgumentResolverTrait.php | 82 - .../Engine/Container/Argument/RawArgument.php | 27 - .../Argument/RawArgumentInterface.php | 13 - .../inc/Engine/Container/Container.php | 305 - .../Container/ContainerAwareInterface.php | 20 - .../Engine/Container/ContainerAwareTrait.php | 34 - .../Engine/Container/ContainerInterface.php | 59 - .../Definition/AbstractDefinition.php | 62 - .../Definition/CallableDefinition.php | 23 - .../Container/Definition/ClassDefinition.php | 67 - .../Definition/ClassDefinitionInterface.php | 23 - .../Definition/DefinitionFactory.php | 28 - .../Definition/DefinitionFactoryInterface.php | 17 - .../Definition/DefinitionInterface.php | 30 - .../Container/Exception/NotFoundException.php | 10 - .../ImmutableContainerAwareInterface.php | 22 - .../ImmutableContainerAwareTrait.php | 36 - .../Container/ImmutableContainerInterface.php | 10 - .../Engine/Container/Inflector/Inflector.php | 103 - .../Inflector/InflectorAggregate.php | 53 - .../Inflector/InflectorAggregateInterface.php | 25 - .../Engine/Container/ReflectionContainer.php | 87 - .../AbstractServiceProvider.php | 27 - .../AbstractSignatureServiceProvider.php | 31 - .../ServiceProviderAggregate.php | 88 - .../ServiceProviderAggregateInterface.php | 32 - .../ServiceProviderInterface.php | 26 - .../SignatureServiceProviderInterface.php | 24 - .../inc/Engine/CriticalPath/APIClient.php | 4 +- .../inc/Engine/CriticalPath/Admin/Admin.php | 10 +- .../inc/Engine/CriticalPath/Admin/Post.php | 24 +- .../Engine/CriticalPath/Admin/Subscriber.php | 15 + .../inc/Engine/CriticalPath/CriticalCSS.php | 132 +- .../CriticalPath/CriticalCSSSubscriber.php | 174 +- .../inc/Engine/CriticalPath/DataManager.php | 8 +- .../Engine/CriticalPath/ProcessorService.php | 6 +- .../Engine/CriticalPath/RESTCSSSubscriber.php | 1 - .../inc/Engine/CriticalPath/RESTWP.php | 2 - .../Engine/CriticalPath/RESTWPInterface.php | 1 - .../Engine/CriticalPath/ServiceProvider.php | 114 +- .../inc/Engine/Deactivation/Deactivation.php | 25 +- .../Engine/Deactivation/ServiceProvider.php | 54 +- .../inc/Engine/Debug/DebugSubscriber.php | 59 + .../inc/Engine/Debug/RUCSS/Subscriber.php | 134 + .../wp-rocket/inc/Engine/Debug/Resolver.php | 62 + .../inc/Engine/Debug/ServiceProvider.php | 77 + .../HealthCheck/ActionSchedulerCheck.php | 154 + .../Engine/HealthCheck/CacheDirSizeCheck.php | 187 - .../Engine/HealthCheck/ServiceProvider.php | 39 +- .../Engine/Heartbeat/HeartbeatSubscriber.php | 8 +- .../inc/Engine/Heartbeat/ServiceProvider.php | 35 +- .../inc/Engine/License/API/PricingClient.php | 35 +- .../wp-rocket/inc/Engine/License/API/User.php | 13 + .../inc/Engine/License/API/UserClient.php | 5 - .../wp-rocket/inc/Engine/License/Renewal.php | 487 +- .../inc/Engine/License/ServiceProvider.php | 58 +- .../inc/Engine/License/Subscriber.php | 70 +- .../wp-rocket/inc/Engine/License/Upgrade.php | 13 + .../inc/Engine/License/views/promo-banner.php | 2 +- .../renewal-expired-banner-ocd-disabled.php | 33 + .../views/renewal-expired-banner-ocd.php | 43 + .../License/views/renewal-expired-banner.php | 53 +- .../License/views/renewal-soon-banner.php | 15 +- .../Media/AboveTheFold/AJAX/Controller.php | 257 + .../Media/AboveTheFold/AJAX/Subscriber.php | 56 + .../AboveTheFold/Activation/Activation.php | 55 + .../Activation/ServiceProvider.php | 75 + .../Media/AboveTheFold/Admin/Controller.php | 168 + .../Media/AboveTheFold/Admin/Subscriber.php | 96 + .../Media/AboveTheFold/Context/Context.php | 34 + .../Media/AboveTheFold/Cron/Controller.php | 65 + .../Media/AboveTheFold/Cron/Subscriber.php | 70 + .../Database/Queries/AboveTheFold.php | 140 + .../Database/Rows/AboveTheFold.php | 112 + .../Database/Schemas/AboveTheFold.php | 111 + .../Database/Tables/AboveTheFold.php | 102 + .../AboveTheFold/Frontend/Controller.php | 553 ++ .../AboveTheFold/Frontend/Subscriber.php | 59 + .../Media/AboveTheFold/ServiceProvider.php | 124 + .../Media/AboveTheFold/WarmUp/APIClient.php | 37 + .../Media/AboveTheFold/WarmUp/Controller.php | 245 + .../Media/AboveTheFold/WarmUp/Queue.php | 35 + .../Media/AboveTheFold/WarmUp/Subscriber.php | 94 + .../Media/ImageDimensions/AdminSubscriber.php | 6 +- .../Media/ImageDimensions/ImageDimensions.php | 279 +- .../Media/ImageDimensions/Subscriber.php | 52 +- .../Engine/Media/Lazyload/AdminSubscriber.php | 22 +- .../Lazyload/CSS/Admin/ServiceProvider.php | 41 + .../Media/Lazyload/CSS/Admin/Subscriber.php | 81 + .../CSS/Context/LazyloadCSSContext.php | 55 + .../CSS/Data/LazyloadCSSContentFactory.php | 34 + .../Lazyload/CSS/Data/LazyloadedContent.php | 58 + .../Lazyload/CSS/Data/ProtectedContent.php | 58 + .../Lazyload/CSS/Front/ContentFetcher.php | 68 + .../Media/Lazyload/CSS/Front/Extractor.php | 347 + .../Media/Lazyload/CSS/Front/FileResolver.php | 23 + .../Lazyload/CSS/Front/MappingFormatter.php | 126 + .../Lazyload/CSS/Front/RuleFormatter.php | 71 + .../Media/Lazyload/CSS/Front/TagGenerator.php | 50 + .../Media/Lazyload/CSS/ServiceProvider.php | 79 + .../Engine/Media/Lazyload/CSS/Subscriber.php | 723 ++ .../Media/Lazyload/CanLazyloadTrait.php | 61 + .../inc/Engine/Media/Lazyload/Subscriber.php | 197 +- .../inc/Engine/Media/ServiceProvider.php | 89 +- .../Optimization/AbstractOptimization.php | 46 +- .../Optimization/AdminServiceProvider.php | 44 +- .../Engine/Optimization/AssetsLocalCache.php | 1 - .../Optimization/Buffer/Optimization.php} | 38 +- .../Optimization/Buffer/Subscriber.php} | 14 +- .../inc/Engine/Optimization/CSSTrait.php | 387 +- .../Optimization/CacheDynamicResource.php | 2 +- .../inc/Engine/Optimization/ContentTrait.php | 124 + .../Optimization/DeferJS/AdminSubscriber.php | 18 +- .../Engine/Optimization/DeferJS/DeferJS.php | 140 +- .../Optimization/DeferJS/ServiceProvider.php | 41 +- .../Optimization/DeferJS/Subscriber.php | 8 +- .../Optimization/DelayJS/Admin/Settings.php | 270 +- .../Optimization/DelayJS/Admin/SiteList.php | 535 ++ .../Optimization/DelayJS/Admin/Subscriber.php | 188 +- .../inc/Engine/Optimization/DelayJS/HTML.php | 261 +- .../Optimization/DelayJS/ServiceProvider.php | 59 +- .../Optimization/DelayJS/Subscriber.php | 109 +- .../DynamicLists/AbstractAPIClient.php | 140 + .../DynamicLists/AbstractDataManager.php | 160 + .../DynamicLists/DefaultLists/APIClient.php | 18 + .../DynamicLists/DefaultLists/DataManager.php | 27 + .../DynamicLists/DelayJSLists/APIClient.php | 18 + .../DynamicLists/DelayJSLists/DataManager.php | 27 + .../DynamicLists/DynamicLists.php | 294 + .../IncompatiblePluginsLists/APIClient.php | 18 + .../IncompatiblePluginsLists/DataManager.php | 84 + .../DynamicLists/ServiceProvider.php | 98 + .../Optimization/DynamicLists/Subscriber.php | 216 + .../GoogleFonts/AbstractGFOptimization.php | 58 +- .../Optimization/GoogleFonts/Combine.php | 37 +- .../Optimization/GoogleFonts/CombineV2.php | 57 +- .../Optimization/GoogleFonts/Subscriber.php | 16 +- .../Minify/AbstractMinifySubscriber.php | 13 +- .../Optimization/Minify/AdminSubscriber.php | 68 + .../Minify/CSS/AbstractCSSOptimization.php | 5 +- .../Minify/CSS/AdminSubscriber.php | 49 +- .../Optimization/Minify/CSS/Combine.php | 336 - .../Engine/Optimization/Minify/CSS/Minify.php | 12 +- .../Optimization/Minify/CSS/Subscriber.php | 4 +- .../Minify/JS/AbstractJSOptimization.php | 89 +- .../Engine/Optimization/Minify/JS/Combine.php | 398 +- .../Engine/Optimization/Minify/JS/Minify.php | 26 +- .../Optimization/Minify/JS/Subscriber.php | 3 +- .../Optimization/RUCSS/Admin/Database.php | 105 + .../RUCSS/Admin/OptionSubscriber.php | 78 + .../Optimization/RUCSS/Admin/Settings.php | 288 + .../Optimization/RUCSS/Admin/Subscriber.php | 592 ++ .../RUCSS/Context/RUCSSContext.php | 56 + .../RUCSS/Context/RUCSSContextSaas.php | 23 + .../RUCSS/Context/RUCSSOptimizeContext.php | 39 + .../RUCSS/Controller/Filesystem.php | 173 + .../Optimization/RUCSS/Controller/UsedCSS.php | 692 ++ .../Optimization/RUCSS/Cron/Subscriber.php | 62 + .../RUCSS/Database/Queries/UsedCSS.php | 128 + .../RUCSS/Database/Row/UsedCSS.php | 148 + .../RUCSS/Database/Schemas/UsedCSS.php | 177 + .../RUCSS/Database/Tables/UsedCSS.php | 260 + .../RUCSS/Frontend/Subscriber.php | 116 + .../Optimization/RUCSS/Jobs/Factory.php | 54 + .../Optimization/RUCSS/Jobs/Manager.php | 222 + .../Optimization/RUCSS/ServiceProvider.php | 131 + .../inc/Engine/Optimization/RegexTrait.php | 265 + .../Engine/Optimization/ServiceProvider.php | 93 +- .../inc/Engine/Optimization/UrlTrait.php | 140 + .../Engine/Plugin/InformationSubscriber.php | 258 + .../inc/Engine/Plugin/RenewalNotice.php | 103 + .../inc/Engine/Plugin/ServiceProvider.php | 82 + .../Plugin/UpdaterApiCommonSubscriber.php} | 60 +- .../Plugin/UpdaterApiTools.php} | 33 +- .../Plugin/UpdaterSubscriber.php} | 301 +- .../inc/Engine/Preload/AbstractPreload.php | 166 - .../inc/Engine/Preload/AbstractProcess.php | 258 - .../Engine/Preload/Activation/Activation.php | 135 + .../Preload/Activation/ServiceProvider.php | 71 + .../inc/Engine/Preload/Admin/Settings.php | 112 + .../inc/Engine/Preload/Admin/Subscriber.php | 109 + .../Preload/Controller/CheckExcludedTrait.php | 82 + .../Preload/Controller/CheckFinished.php | 57 + .../Engine/Preload/Controller/ClearCache.php | 66 + .../Preload/Controller/CrawlHomepage.php | 66 + .../Preload/Controller/LoadInitialSitemap.php | 193 + .../Engine/Preload/Controller/PreloadUrl.php | 271 + .../inc/Engine/Preload/Controller/Queue.php | 142 + .../inc/Engine/Preload/Cron/Subscriber.php | 265 + .../Engine/Preload/Database/Queries/Cache.php | 703 ++ .../Engine/Preload/Database/Rows/CacheRow.php | 71 + .../Engine/Preload/Database/Schemas/Cache.php | 82 + .../Engine/Preload/Database/Tables/Cache.php | 99 + .../wp-rocket/inc/Engine/Preload/Fonts.php | 41 +- .../Engine/Preload/Frontend/FetchSitemap.php | 82 + .../Engine/Preload/Frontend/SitemapParser.php | 76 + .../Engine/Preload/Frontend/Subscriber.php | 106 + .../inc/Engine/Preload/FullProcess.php | 88 - .../wp-rocket/inc/Engine/Preload/Homepage.php | 315 - .../Engine/Preload/Links/ServiceProvider.php | 33 +- .../inc/Engine/Preload/Links/Subscriber.php | 70 +- .../Preload/PartialPreloadSubscriber.php | 236 - .../inc/Engine/Preload/PartialProcess.php | 44 - .../inc/Engine/Preload/PreloadSubscriber.php | 374 - .../inc/Engine/Preload/ServiceProvider.php | 178 +- .../wp-rocket/inc/Engine/Preload/Sitemap.php | 367 - .../Preload/SitemapPreloadSubscriber.php | 132 - .../inc/Engine/Preload/Subscriber.php | 573 ++ .../inc/Engine/Saas/Admin/AdminBar.php | 225 + .../wp-rocket/inc/Engine/Saas/Admin/Clean.php | 73 + .../inc/Engine/Saas/Admin/Notices.php | 355 + .../inc/Engine/Saas/Admin/Subscriber.php | 173 + .../inc/Engine/Saas/ServiceProvider.php | 58 + .../wp-rocket/inc/Engine/Support/Data.php | 9 +- .../wp-rocket/inc/Engine/Support/Rest.php | 4 +- .../inc/Engine/Support/ServiceProvider.php | 32 +- .../inc/Engine/WPRocketUninstall.php | 115 +- .../wp-rocket/inc/Logger/HTMLFormatter.php | 58 + .../plugins/wp-rocket/inc/Logger/Logger.php | 508 ++ .../wp-rocket/inc/Logger/LoggerAware.php | 23 + .../inc/Logger/LoggerAwareInterface.php | 14 + .../wp-rocket/inc/Logger/ServiceProvider.php | 37 + .../wp-rocket/inc/Logger/StreamHandler.php | 147 + wp-content/plugins/wp-rocket/inc/Plugin.php | 232 +- .../inc/ThirdParty/Hostings/Godaddy.php | 193 + .../inc/ThirdParty/Hostings/HostResolver.php | 38 + .../Hostings/HostSubscriberFactory.php | 14 + .../inc/ThirdParty/Hostings/Kinsta.php | 163 + .../inc/ThirdParty/Hostings/LiteSpeed.php | 153 + .../inc/ThirdParty/Hostings/OneCom.php | 170 + .../inc/ThirdParty/Hostings/Pressable.php | 2 +- .../inc/ThirdParty/Hostings/Pressidium.php | 139 + .../inc/ThirdParty/Hostings/ProIsp.php | 66 + .../inc/ThirdParty/Hostings/Savvii.php | 10 +- .../ThirdParty/Hostings/ServiceProvider.php | 27 +- .../inc/ThirdParty/Hostings/SpinUpWP.php | 62 +- .../inc/ThirdParty/Hostings/WPEngine.php | 28 +- .../inc/ThirdParty/Hostings/WPXCloud.php | 90 + .../inc/ThirdParty/Hostings/WordPressCom.php | 2 +- .../inc/ThirdParty/Plugins/Ads/Adthrive.php | 114 + .../inc/ThirdParty/Plugins/CDN/Cloudflare.php | 503 ++ .../Plugins/CDN/CloudflareFacade.php | 53 + .../inc/ThirdParty/Plugins/ContactForm7.php | 133 + .../inc/ThirdParty/Plugins/ConvertPlug.php | 48 + .../Plugins/Ecommerce/BigCommerce.php} | 14 +- .../Ecommerce/WooCommerceSubscriber.php | 264 +- .../Plugins/I18n/TranslatePress.php | 318 + .../inc/ThirdParty/Plugins/I18n/WPML.php | 195 + .../inc/ThirdParty/Plugins/I18n/Weglot.php | 40 + .../ThirdParty/Plugins/InlineRelatedPosts.php | 38 + .../inc/ThirdParty/Plugins/Jetpack.php | 61 + .../inc/ThirdParty/Plugins/ModPagespeed.php | 113 + .../ThirdParty/Plugins/Optimization/AMP.php | 61 +- .../Plugins/Optimization/Autoptimize.php | 177 + .../ThirdParty/Plugins/Optimization/Ezoic.php | 52 + .../Plugins/Optimization/Hummingbird.php | 15 +- .../Plugins/Optimization/Perfmatters.php | 61 + .../Plugins/Optimization/RapidLoad.php | 81 + .../Plugins/Optimization/RocketLazyLoad.php | 34 + .../Plugins/Optimization/WPMeteor.php | 112 + .../inc/ThirdParty/Plugins/PDFEmbedder.php | 6 +- .../wp-rocket/inc/ThirdParty/Plugins/PWA.php | 34 + .../Plugins/PageBuilder/Elementor.php | 183 +- .../ThirdParty/Plugins/RevolutionSlider.php | 48 + .../Plugins/SEO/AllInOneSEOPack.php | 76 + .../ThirdParty/Plugins/SEO/RankMathSEO.php | 56 + .../inc/ThirdParty/Plugins/SEO/SEOPress.php | 55 + .../Plugins/SEO/TheSEOFramework.php | 90 + .../inc/ThirdParty/Plugins/SEO/Yoast.php | 95 + .../Security/WordFenceCompatibility.php | 141 + .../inc/ThirdParty/Plugins/Smush.php | 13 +- .../ThirdParty/Plugins/TheEventsCalendar.php | 44 + .../ThirdParty/Plugins/ThirstyAffiliates.php | 50 + .../ThirdParty/Plugins/UnlimitedElements.php | 37 + .../inc/ThirdParty/Plugins/WPGeotargeting.php | 118 + .../inc/ThirdParty/ServiceProvider.php | 257 +- .../wp-rocket/inc/ThirdParty/Themes/Avada.php | 59 +- .../inc/ThirdParty/Themes/Bridge.php | 33 +- .../wp-rocket/inc/ThirdParty/Themes/Divi.php | 280 +- .../inc/ThirdParty/Themes/Flatsome.php | 59 + .../inc/ThirdParty/Themes/Jevelin.php | 71 + .../ThirdParty/Themes/MinimalistBlogger.php | 32 + .../inc/ThirdParty/Themes/Polygon.php | 29 + .../inc/ThirdParty/Themes/ServiceProvider.php | 67 + .../inc/ThirdParty/Themes/Shoptimizer.php | 33 + .../ThirdParty/Themes/SubscriberFactory.php | 88 + .../inc/ThirdParty/Themes/ThemeResolver.php | 56 + .../inc/ThirdParty/Themes/Themify.php | 155 + .../inc/ThirdParty/Themes/Uncode.php | 97 + .../inc/ThirdParty/Themes/Xstore.php | 35 + .../plugins/wp-rocket/inc/admin/admin.php | 221 +- .../plugins/wp-rocket/inc/admin/options.php | 177 +- .../wp-rocket/inc/admin/ui/enqueue.php | 22 +- .../wp-rocket/inc/admin/ui/meta-boxes.php | 164 +- .../wp-rocket/inc/admin/ui/notices.php | 194 +- .../plugins/wp-rocket/inc/admin/upgrader.php | 160 +- .../inc/classes/Buffer/class-cache.php | 170 +- .../inc/classes/Buffer/class-config.php | 71 +- .../inc/classes/Buffer/class-tests.php | 294 +- .../class-common-subscribers.php | 46 +- .../ServiceProvider/class-database.php | 41 - .../classes/ServiceProvider/class-options.php | 33 +- .../class-updater-subscribers.php | 74 - .../admin/deactivation/class-render.php | 30 - .../inc/classes/class-abstract-render.php | 11 +- .../mobiledetectlib/Mobile_Detect.php | 323 +- .../wp-async-request.php | 2 +- .../wp-background-process.php | 10 +- .../classes/logger/class-html-formatter.php | 58 +- .../inc/classes/logger/class-logger.php | 557 +- .../classes/logger/class-stream-handler.php | 154 +- .../Media/class-webp-subscriber.php | 847 --- .../Plugin/class-information-subscriber.php | 161 - .../class-detect-missing-tags-subscriber.php | 12 +- .../Hostings/class-litespeed-subscriber.php | 121 - .../Images/Webp/class-imagify-subscriber.php | 46 +- .../plugins/Images/Webp/webp-interface.php | 29 +- .../plugins/class-mobile-subscriber.php | 4 +- .../plugins/class-ngg-subscriber.php | 8 +- .../inc/classes/traits/trait-memoize.php | 2 +- .../wp-rocket/inc/common/admin-bar.php | 220 +- .../inc/common/cloudflare-flexible-ssl.php | 111 - .../plugins/wp-rocket/inc/common/purge.php | 288 +- wp-content/plugins/wp-rocket/inc/compat.php | 31 + .../plugins/wp-rocket/inc/constants.php | 2 +- .../plugins/wp-rocket/inc/deprecated/3.10.php | 176 + .../plugins/wp-rocket/inc/deprecated/3.11.php | 286 + .../plugins/wp-rocket/inc/deprecated/3.12.php | 727 ++ .../3.13.php} | 34 +- .../ip_in_range.php => deprecated/3.14.php} | 233 +- .../plugins/wp-rocket/inc/deprecated/3.15.php | 179 + .../plugins/wp-rocket/inc/deprecated/3.5.php | 12 +- .../plugins/wp-rocket/inc/deprecated/3.6.php | 8 - .../plugins/wp-rocket/inc/deprecated/3.7.php | 2 +- .../plugins/wp-rocket/inc/deprecated/3.8.php | 53 + .../godaddy.php => deprecated/3.9.php} | 30 +- .../Engine}/Addon/Busting/BustingFactory.php | 5 + .../Addon/Busting/FileBustingTrait.php | 0 .../Addon/FacebookTracking/Subscriber.php | 5 + .../Addon/GoogleTracking/GoogleAnalytics.php | 7 +- .../Addon/GoogleTracking/GoogleTagManager.php | 5 + .../Addon/GoogleTracking/Subscriber.php | 5 + .../Engine/Media/Embeds/EmbedsSubscriber.php | 18 +- .../busting/class-abstract-busting.php | 0 .../busting/class-facebook-pickles.php | 7 +- .../classes/busting/class-facebook-sdk.php | 7 +- .../plugins/wp-rocket/inc/domain-mapping.php | 2 +- .../wp-rocket/inc/front/dns-prefetch.php | 1 - .../plugins/wp-rocket/inc/front/process.php | 514 -- .../plugins/wp-rocket/inc/front/protocol.php | 55 - .../plugins/wp-rocket/inc/functions/admin.php | 166 +- .../plugins/wp-rocket/inc/functions/api.php | 49 +- .../plugins/wp-rocket/inc/functions/files.php | 315 +- .../wp-rocket/inc/functions/formatting.php | 48 +- .../wp-rocket/inc/functions/htaccess.php | 181 +- .../plugins/wp-rocket/inc/functions/i18n.php | 227 +- .../wp-rocket/inc/functions/options.php | 217 +- .../plugins/wp-rocket/inc/functions/posts.php | 204 + wp-content/plugins/wp-rocket/inc/main.php | 29 +- .../plugins/wp-rocket/languages/rocket-ar.mo | Bin 30865 -> 27580 bytes .../plugins/wp-rocket/languages/rocket-ar.po | 3837 +++++----- .../wp-rocket/languages/rocket-bg_BG.mo | Bin 28761 -> 51323 bytes .../wp-rocket/languages/rocket-bg_BG.po | 4207 ++++++----- .../wp-rocket/languages/rocket-cs_CZ.mo | Bin 103060 -> 73241 bytes .../wp-rocket/languages/rocket-cs_CZ.po | 4227 +++++------ .../wp-rocket/languages/rocket-de_DE.mo | Bin 52808 -> 110898 bytes .../wp-rocket/languages/rocket-de_DE.po | 4984 ++++++++----- .../plugins/wp-rocket/languages/rocket-el.mo | Bin 12103 -> 10554 bytes .../plugins/wp-rocket/languages/rocket-el.po | 3753 ++++++---- .../wp-rocket/languages/rocket-es_ES.mo | Bin 103898 -> 76381 bytes .../wp-rocket/languages/rocket-es_ES.po | 4160 +++++------ .../wp-rocket/languages/rocket-fa_IR.mo | Bin 0 -> 132086 bytes .../wp-rocket/languages/rocket-fa_IR.po | 4506 ++++++++++++ .../plugins/wp-rocket/languages/rocket-fi.mo | Bin 74903 -> 48457 bytes .../plugins/wp-rocket/languages/rocket-fi.po | 4269 ++++++----- .../wp-rocket/languages/rocket-fr_CA.mo | Bin 102122 -> 105516 bytes .../wp-rocket/languages/rocket-fr_CA.po | 4276 +++++------ .../wp-rocket/languages/rocket-fr_FR.mo | Bin 103989 -> 115476 bytes .../wp-rocket/languages/rocket-fr_FR.po | 6488 +++++++++-------- .../wp-rocket/languages/rocket-gl_ES.mo | Bin 904 -> 922 bytes .../wp-rocket/languages/rocket-gl_ES.po | 3711 ++++++---- .../wp-rocket/languages/rocket-he_IL.mo | Bin 9578 -> 8488 bytes .../wp-rocket/languages/rocket-he_IL.po | 3765 ++++++---- .../plugins/wp-rocket/languages/rocket-hr.mo | Bin 105558 -> 94745 bytes .../plugins/wp-rocket/languages/rocket-hr.po | 4081 +++++------ .../wp-rocket/languages/rocket-hu_HU.mo | Bin 907 -> 101835 bytes .../wp-rocket/languages/rocket-hu_HU.po | 4878 +++++++------ .../wp-rocket/languages/rocket-it_IT.mo | Bin 103959 -> 76040 bytes .../wp-rocket/languages/rocket-it_IT.po | 4161 +++++------ .../wp-rocket/languages/rocket-ja_JP.mo | Bin 0 -> 92701 bytes .../wp-rocket/languages/rocket-ja_JP.po | 3542 +++++++++ .../plugins/wp-rocket/languages/rocket-ms.mo | Bin 5023 -> 4416 bytes .../plugins/wp-rocket/languages/rocket-ms.po | 3733 ++++++---- .../wp-rocket/languages/rocket-nb_NO.mo | Bin 914 -> 932 bytes .../wp-rocket/languages/rocket-nb_NO.po | 3711 ++++++---- .../wp-rocket/languages/rocket-nl_NL.mo | Bin 35158 -> 108414 bytes .../wp-rocket/languages/rocket-nl_NL.po | 4911 ++++++++----- .../wp-rocket/languages/rocket-pl_PL.mo | Bin 112928 -> 108100 bytes .../wp-rocket/languages/rocket-pl_PL.po | 4285 +++++------ .../wp-rocket/languages/rocket-pt_BR.mo | Bin 103743 -> 112335 bytes .../wp-rocket/languages/rocket-pt_BR.po | 6245 ++++++++-------- .../wp-rocket/languages/rocket-pt_PT.mo | Bin 0 -> 113832 bytes .../wp-rocket/languages/rocket-pt_PT.po | 4687 ++++++++++++ .../wp-rocket/languages/rocket-ro_RO.mo | Bin 106672 -> 115648 bytes .../wp-rocket/languages/rocket-ro_RO.po | 6412 ++++++++-------- .../plugins/wp-rocket/languages/rocket-ru.mo | Bin 1027 -> 1045 bytes .../plugins/wp-rocket/languages/rocket-ru.po | 3723 ++++++---- .../wp-rocket/languages/rocket-ru_RU.mo | Bin 126294 -> 100263 bytes .../wp-rocket/languages/rocket-ru_RU.po | 3888 +++++----- .../plugins/wp-rocket/languages/rocket-sr.mo | Bin 8387 -> 7689 bytes .../plugins/wp-rocket/languages/rocket-sr.po | 3732 ++++++---- .../wp-rocket/languages/rocket-sv_SE.mo | Bin 3006 -> 2788 bytes .../wp-rocket/languages/rocket-sv_SE.po | 3704 ++++++---- .../wp-rocket/languages/rocket-tr_TR.mo | Bin 106648 -> 114420 bytes .../wp-rocket/languages/rocket-tr_TR.po | 6268 ++++++++-------- .../plugins/wp-rocket/languages/rocket-uk.mo | Bin 119003 -> 79266 bytes .../plugins/wp-rocket/languages/rocket-uk.po | 4367 ++++++----- .../wp-rocket/languages/rocket-uk_UA.mo | Bin 119003 -> 79266 bytes .../wp-rocket/languages/rocket-uk_UA.po | 4367 ++++++----- .../wp-rocket/languages/rocket-zh_CN.mo | Bin 89334 -> 96272 bytes .../wp-rocket/languages/rocket-zh_CN.po | 5483 +++++++------- .../wp-rocket/languages/rocket-zh_TW.mo | Bin 48619 -> 32546 bytes .../wp-rocket/languages/rocket-zh_TW.po | 3773 ++++++---- .../plugins/wp-rocket/languages/rocket.pot | 4122 +++++------ wp-content/plugins/wp-rocket/licence-data.php | 18 + wp-content/plugins/wp-rocket/uninstall.php | 30 +- .../plugins/wp-rocket/vendor/autoload.php | 7 - .../wp-rocket/vendor/composer/ClassLoader.php | 445 -- .../plugins/wp-rocket/vendor/composer/LICENSE | 21 - .../vendor/composer/autoload_classmap.php | 485 -- .../vendor/composer/autoload_namespaces.php | 9 - .../vendor/composer/autoload_psr4.php | 15 - .../vendor/composer/autoload_real.php | 55 - .../vendor/composer/autoload_static.php | 545 -- .../wp-rocket/vendor/composer/installed.json | 310 - .../vendor/composer/installers/LICENSE | 19 - .../vendor/composer/installers/composer.json | 107 - .../src/Composer/Installers/AglInstaller.php | 21 - .../Composer/Installers/AimeosInstaller.php | 9 - .../Installers/AnnotateCmsInstaller.php | 11 - .../Composer/Installers/AsgardInstaller.php | 49 - .../Composer/Installers/AttogramInstaller.php | 9 - .../src/Composer/Installers/BaseInstaller.php | 136 - .../Composer/Installers/BitrixInstaller.php | 126 - .../Composer/Installers/BonefishInstaller.php | 9 - .../Composer/Installers/CakePHPInstaller.php | 82 - .../src/Composer/Installers/ChefInstaller.php | 11 - .../Composer/Installers/CiviCrmInstaller.php | 9 - .../Installers/ClanCatsFrameworkInstaller.php | 10 - .../Composer/Installers/CockpitInstaller.php | 34 - .../Installers/CodeIgniterInstaller.php | 11 - .../Installers/Concrete5Installer.php | 13 - .../Composer/Installers/CraftInstaller.php | 35 - .../Composer/Installers/CroogoInstaller.php | 21 - .../Composer/Installers/DecibelInstaller.php | 10 - .../Composer/Installers/DframeInstaller.php | 10 - .../Composer/Installers/DokuWikiInstaller.php | 50 - .../Composer/Installers/DolibarrInstaller.php | 16 - .../Composer/Installers/DrupalInstaller.php | 20 - .../src/Composer/Installers/ElggInstaller.php | 9 - .../Composer/Installers/EliasisInstaller.php | 12 - .../Installers/ExpressionEngineInstaller.php | 29 - .../Installers/EzPlatformInstaller.php | 10 - .../src/Composer/Installers/FuelInstaller.php | 11 - .../Composer/Installers/FuelphpInstaller.php | 9 - .../src/Composer/Installers/GravInstaller.php | 30 - .../Composer/Installers/HuradInstaller.php | 25 - .../Composer/Installers/ImageCMSInstaller.php | 11 - .../src/Composer/Installers/Installer.php | 278 - .../src/Composer/Installers/ItopInstaller.php | 9 - .../Composer/Installers/JoomlaInstaller.php | 15 - .../Composer/Installers/KanboardInstaller.php | 18 - .../Composer/Installers/KirbyInstaller.php | 11 - .../Composer/Installers/KnownInstaller.php | 11 - .../Composer/Installers/KodiCMSInstaller.php | 10 - .../Composer/Installers/KohanaInstaller.php | 9 - .../LanManagementSystemInstaller.php | 27 - .../Composer/Installers/LaravelInstaller.php | 9 - .../Composer/Installers/LavaLiteInstaller.php | 10 - .../Composer/Installers/LithiumInstaller.php | 10 - .../Installers/MODULEWorkInstaller.php | 9 - .../Composer/Installers/MODXEvoInstaller.php | 16 - .../Composer/Installers/MagentoInstaller.php | 11 - .../Composer/Installers/MajimaInstaller.php | 37 - .../src/Composer/Installers/MakoInstaller.php | 9 - .../Composer/Installers/MauticInstaller.php | 25 - .../src/Composer/Installers/MayaInstaller.php | 33 - .../Installers/MediaWikiInstaller.php | 51 - .../Installers/MicroweberInstaller.php | 119 - .../src/Composer/Installers/ModxInstaller.php | 12 - .../Composer/Installers/MoodleInstaller.php | 58 - .../Composer/Installers/OctoberInstaller.php | 47 - .../Composer/Installers/OntoWikiInstaller.php | 24 - .../Composer/Installers/OsclassInstaller.php | 14 - .../src/Composer/Installers/OxidInstaller.php | 59 - .../src/Composer/Installers/PPIInstaller.php | 9 - .../Composer/Installers/PhiftyInstaller.php | 11 - .../Composer/Installers/PhpBBInstaller.php | 11 - .../Composer/Installers/PimcoreInstaller.php | 21 - .../Composer/Installers/PiwikInstaller.php | 32 - .../Installers/PlentymarketsInstaller.php | 29 - .../src/Composer/Installers/Plugin.php | 17 - .../Composer/Installers/PortoInstaller.php | 9 - .../Installers/PrestashopInstaller.php | 10 - .../Composer/Installers/PuppetInstaller.php | 11 - .../Composer/Installers/PxcmsInstaller.php | 63 - .../Composer/Installers/RadPHPInstaller.php | 24 - .../Composer/Installers/ReIndexInstaller.php | 10 - .../Composer/Installers/Redaxo5Installer.php | 10 - .../Composer/Installers/RedaxoInstaller.php | 10 - .../Installers/RoundcubeInstaller.php | 22 - .../src/Composer/Installers/SMFInstaller.php | 10 - .../Composer/Installers/ShopwareInstaller.php | 60 - .../Installers/SilverStripeInstaller.php | 35 - .../Installers/SiteDirectInstaller.php | 25 - .../Composer/Installers/SyDESInstaller.php | 49 - .../Composer/Installers/Symfony1Installer.php | 26 - .../Composer/Installers/TYPO3CmsInstaller.php | 16 - .../Installers/TYPO3FlowInstaller.php | 38 - .../src/Composer/Installers/TaoInstaller.php | 12 - .../Composer/Installers/TheliaInstaller.php | 12 - .../src/Composer/Installers/TuskInstaller.php | 14 - .../Installers/UserFrostingInstaller.php | 9 - .../Composer/Installers/VanillaInstaller.php | 10 - .../Composer/Installers/VgmcpInstaller.php | 49 - .../Composer/Installers/WHMCSInstaller.php | 21 - .../Composer/Installers/WolfCMSInstaller.php | 9 - .../Installers/WordPressInstaller.php | 12 - .../Composer/Installers/YawikInstaller.php | 32 - .../src/Composer/Installers/ZendInstaller.php | 11 - .../Composer/Installers/ZikulaInstaller.php | 10 - .../composer/installers/src/bootstrap.php | 13 - .../vendor/monolog/monolog/CHANGELOG.md | 419 -- .../wp-rocket/vendor/monolog/monolog/LICENSE | 19 - .../vendor/monolog/monolog/README.md | 94 - .../vendor/monolog/monolog/composer.json | 58 - .../vendor/monolog/monolog/phpstan.neon.dist | 16 - .../Monolog/Formatter/ChromePHPFormatter.php | 78 - .../Monolog/Formatter/ElasticaFormatter.php | 89 - .../Monolog/Formatter/FlowdockFormatter.php | 116 - .../Monolog/Formatter/FluentdFormatter.php | 88 - .../Formatter/GelfMessageFormatter.php | 138 - .../src/Monolog/Formatter/JsonFormatter.php | 212 - .../src/Monolog/Formatter/LogglyFormatter.php | 47 - .../Monolog/Formatter/LogstashFormatter.php | 166 - .../Monolog/Formatter/MongoDBFormatter.php | 107 - .../src/Monolog/Formatter/ScalarFormatter.php | 48 - .../Monolog/Formatter/WildfireFormatter.php | 113 - .../Monolog/Handler/AbstractSyslogHandler.php | 101 - .../src/Monolog/Handler/AmqpHandler.php | 148 - .../Monolog/Handler/BrowserConsoleHandler.php | 241 - .../src/Monolog/Handler/BufferHandler.php | 148 - .../src/Monolog/Handler/ChromePHPHandler.php | 212 - .../src/Monolog/Handler/CouchDBHandler.php | 72 - .../src/Monolog/Handler/CubeHandler.php | 152 - .../monolog/src/Monolog/Handler/Curl/Util.php | 57 - .../Monolog/Handler/DeduplicationHandler.php | 169 - .../Handler/DoctrineCouchDBHandler.php | 45 - .../src/Monolog/Handler/DynamoDbHandler.php | 108 - .../Monolog/Handler/ElasticSearchHandler.php | 128 - .../src/Monolog/Handler/ErrorLogHandler.php | 82 - .../src/Monolog/Handler/FilterHandler.php | 172 - .../ActivationStrategyInterface.php | 28 - .../ChannelLevelActivationStrategy.php | 59 - .../ErrorLevelActivationStrategy.php | 34 - .../Monolog/Handler/FingersCrossedHandler.php | 207 - .../src/Monolog/Handler/FirePHPHandler.php | 195 - .../src/Monolog/Handler/FleepHookHandler.php | 126 - .../src/Monolog/Handler/FlowdockHandler.php | 128 - .../src/Monolog/Handler/GelfHandler.php | 65 - .../src/Monolog/Handler/GroupHandler.php | 117 - .../src/Monolog/Handler/HandlerWrapper.php | 116 - .../src/Monolog/Handler/HipChatHandler.php | 367 - .../src/Monolog/Handler/IFTTTHandler.php | 70 - .../src/Monolog/Handler/InsightOpsHandler.php | 62 - .../src/Monolog/Handler/LogEntriesHandler.php | 55 - .../src/Monolog/Handler/LogglyHandler.php | 102 - .../src/Monolog/Handler/MailHandler.php | 67 - .../src/Monolog/Handler/MandrillHandler.php | 68 - .../Handler/MissingExtensionException.php | 21 - .../src/Monolog/Handler/MongoDBHandler.php | 59 - .../Monolog/Handler/NativeMailerHandler.php | 185 - .../src/Monolog/Handler/NewRelicHandler.php | 205 - .../src/Monolog/Handler/NullHandler.php | 45 - .../src/Monolog/Handler/PHPConsoleHandler.php | 243 - .../src/Monolog/Handler/PsrHandler.php | 56 - .../src/Monolog/Handler/PushoverHandler.php | 185 - .../src/Monolog/Handler/RavenHandler.php | 234 - .../src/Monolog/Handler/RedisHandler.php | 98 - .../src/Monolog/Handler/RollbarHandler.php | 144 - .../Monolog/Handler/RotatingFileHandler.php | 191 - .../src/Monolog/Handler/SamplingHandler.php | 113 - .../src/Monolog/Handler/Slack/SlackRecord.php | 299 - .../src/Monolog/Handler/SlackHandler.php | 221 - .../Monolog/Handler/SlackWebhookHandler.php | 121 - .../src/Monolog/Handler/SlackbotHandler.php | 84 - .../src/Monolog/Handler/SocketHandler.php | 385 - .../Monolog/Handler/SwiftMailerHandler.php | 111 - .../src/Monolog/Handler/SyslogHandler.php | 67 - .../Monolog/Handler/SyslogUdp/UdpSocket.php | 56 - .../src/Monolog/Handler/SyslogUdpHandler.php | 124 - .../src/Monolog/Handler/TestHandler.php | 177 - .../Handler/WhatFailureGroupHandler.php | 72 - .../Monolog/Handler/ZendMonitorHandler.php | 101 - .../src/Monolog/Processor/GitProcessor.php | 64 - .../Processor/MemoryPeakUsageProcessor.php | 35 - .../src/Monolog/Processor/MemoryProcessor.php | 63 - .../Processor/MemoryUsageProcessor.php | 35 - .../Monolog/Processor/MercurialProcessor.php | 63 - .../Monolog/Processor/ProcessIdProcessor.php | 31 - .../Processor/PsrLogMessageProcessor.php | 81 - .../src/Monolog/Processor/TagProcessor.php | 44 - .../src/Monolog/Processor/UidProcessor.php | 59 - .../src/Monolog/Processor/WebProcessor.php | 113 - .../wp-rocket/vendor/psr/container/.gitignore | 3 - .../wp-rocket/vendor/psr/container/LICENSE | 21 - .../wp-rocket/vendor/psr/container/README.md | 5 - .../vendor/psr/container/composer.json | 27 - .../plugins/wp-rocket/vendor/psr/log/LICENSE | 19 - .../vendor/psr/log/Psr/Log/Test/DummyTest.php | 18 - .../log/Psr/Log/Test/LoggerInterfaceTest.php | 138 - .../psr/log/Psr/Log/Test/TestLogger.php | 147 - .../wp-rocket/vendor/psr/log/README.md | 58 - .../wp-rocket/vendor/psr/log/composer.json | 26 - .../wp-rocket/views/cache/advanced-cache.php | 55 +- .../views/cpcss/activate-cpcss-mobile.php | 2 +- .../views/deactivation-intent/form.php | 211 +- .../views/metaboxes/post_edit_options.php | 49 + .../plugins/update-renewal-expired-notice.php | 39 + .../wp-rocket/views/settings/beacon.php | 2 + .../views/settings/dynamic-lists-update.php | 32 + .../fields/categorized_multiselect.php | 103 + .../views/settings/fields/checkbox.php | 13 +- .../views/settings/fields/cnames.php | 27 +- .../views/settings/fields/one-click-addon.php | 92 +- .../views/settings/fields/radio-buttons.php | 77 + .../views/settings/fields/rocket-addon.php | 32 +- .../settings/fields/sliding-checkbox.php | 4 +- .../wp-rocket/views/settings/mobile-cache.php | 37 + .../settings/page-sections/dashboard.php | 113 +- .../views/settings/page-sections/imagify.php | 102 +- .../settings/page-sections/tutorials.php | 15 +- .../plugins/wp-rocket/views/settings/page.php | 21 +- .../views/settings/partials/sidebar.php | 16 +- .../views/settings/sections/clean-section.php | 30 + .../settings/sections/fields-container.php | 14 +- wp-content/plugins/wp-rocket/wp-rocket.php | 31 +- 1020 files changed, 155809 insertions(+), 98096 deletions(-) create mode 100644 wp-content/plugins/wp-rocket/SECURITY.md create mode 100644 wp-content/plugins/wp-rocket/assets/css/wpr-admin-rtl.min.css create mode 100644 wp-content/plugins/wp-rocket/assets/css/wpr-admin.min.css create mode 100644 wp-content/plugins/wp-rocket/assets/img/icon-i-circle.svg create mode 100644 wp-content/plugins/wp-rocket/assets/img/icon-user-cache.svg create mode 100644 wp-content/plugins/wp-rocket/assets/img/imagify-info.svg create mode 100644 wp-content/plugins/wp-rocket/assets/img/imagify-install.svg create mode 100644 wp-content/plugins/wp-rocket/assets/img/imagify-score.png delete mode 100644 wp-content/plugins/wp-rocket/assets/img/logo-adblock.svg delete mode 100644 wp-content/plugins/wp-rocket/assets/img/logo-facebook.svg delete mode 100644 wp-content/plugins/wp-rocket/assets/img/logo-google-analytics.svg create mode 100644 wp-content/plugins/wp-rocket/assets/img/logo-webp.svg delete mode 100644 wp-content/plugins/wp-rocket/assets/img/logo-wprocket-light.svg create mode 100644 wp-content/plugins/wp-rocket/assets/img/one-com-logo.svg delete mode 100644 wp-content/plugins/wp-rocket/assets/img/picto-wprocket-light.svg delete mode 100644 wp-content/plugins/wp-rocket/assets/js/editor/editor.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/elementor-animation.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/heartbeat.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lazyload-css.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lazyload-css.js.min.map create mode 100644 wp-content/plugins/wp-rocket/assets/js/lazyload-css.min.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lazyload-css.min.js.map delete mode 100644 wp-content/plugins/wp-rocket/assets/js/lazyload-scripts.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lazyload/17.5/lazyload.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lazyload/17.5/lazyload.min.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lazyload/17.8.3/lazyload.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lazyload/17.8.3/lazyload.min.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lcp-beacon.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lcp-beacon.min.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/lcp-beacon.min.js.map create mode 100644 wp-content/plugins/wp-rocket/assets/js/wpr-admin.js.min.map create mode 100644 wp-content/plugins/wp-rocket/assets/js/wpr-admin.min.js create mode 100644 wp-content/plugins/wp-rocket/assets/js/wpr-admin.min.js.map delete mode 100644 wp-content/plugins/wp-rocket/assets/js/wpr-modal.js delete mode 100644 wp-content/plugins/wp-rocket/composer.lock create mode 100644 wp-content/plugins/wp-rocket/dynamic-lists-delayjs.json create mode 100644 wp-content/plugins/wp-rocket/dynamic-lists-incompatible-plugins.json create mode 100644 wp-content/plugins/wp-rocket/dynamic-lists.json delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/hosting/kinsta.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/hosting/pressidium.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/plugins/age-verify.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/plugins/i18n/wpml.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/plugins/jetpack.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/all-in-one-seo-pack.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/rank-math-seo.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/seopress.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/the-seo-framework.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/yoast-seo.php delete mode 100644 wp-content/plugins/wp-rocket/inc/3rd-party/themes/uncode.php delete mode 100644 wp-content/plugins/wp-rocket/inc/API/preload.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/API/Client.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/API/Endpoints.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/APIClient.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Admin/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/APIKey.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/APIKeyFactory.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/AuthFactoryInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/AuthInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/AuthenticationException.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/ServiceProvider.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/UnauthorizedException.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/composer.json rename wp-content/plugins/wp-rocket/inc/{classes/subscriber/third-party/plugins/security/class-sucuri-subscriber.php => Addon/Sucuri/Subscriber.php} (56%) create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/WebP/AbstractWebp.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/WebP/AdminSubscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Addon/WebP/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/action-scheduler.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/changelog.txt create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_ActionClaim.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_ActionFactory.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_AdminView.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Compatibility.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_DataController.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_DateTime.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Exception.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_FatalErrorMonitor.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_InvalidActionException.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_ListTable.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_LogEntry.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_NullLogEntry.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_OptionLock.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_QueueCleaner.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_QueueRunner.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Versions.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_WPCommentCleaner.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_wcSystemStatus.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/ActionScheduler_WPCLI_QueueRunner.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/Migration_Command.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/ProgressBar.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_ListTable.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Lock.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Logger.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Store.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_TimezoneHelper.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_Action.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_CanceledAction.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_FinishedAction.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_NullAction.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_DBLogger.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_DBStore.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_HybridStore.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/ActionMigrator.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/ActionScheduler_DBStoreMigrator.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/BatchFetcher.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Config.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Controller.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/DryRun_ActionMigrator.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/DryRun_LogMigrator.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/LogMigrator.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Runner.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Scheduler.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_CanceledSchedule.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_CronSchedule.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_IntervalSchedule.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_NullSchedule.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_Schedule.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_SimpleSchedule.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schema/ActionScheduler_LoggerSchema.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schema/ActionScheduler_StoreSchema.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_Abstract_QueueRunner_Deprecated.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_AdminView_Deprecated.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_Schedule_Deprecated.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_Store_Deprecated.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/functions.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/functions.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/WP_Async_Request.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_AbstractField.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_DayOfMonthField.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_DayOfWeekField.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_FieldFactory.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_FieldInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_HoursField.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_MinutesField.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_MonthField.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_YearField.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/license.txt create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/readme.txt create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Database/Base.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Database/Column.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Compare.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Date.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Meta.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Database/Query.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Database/Row.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Database/Schema.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Database/Table.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ArgumentInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ArgumentResolverInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ArgumentResolverTrait.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/DefaultValueArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/DefaultValueInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/Literal/ArrayArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/Literal/BooleanArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/Literal/CallableArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/Literal/FloatArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/Literal/IntegerArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/Literal/ObjectArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/Literal/StringArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/LiteralArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/LiteralArgumentInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ResolvableArgument.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ResolvableArgumentInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Container.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ContainerAwareInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ContainerAwareTrait.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/Definition.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/DefinitionAggregate.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/DefinitionAggregateInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/DefinitionInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/DefinitionContainerInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Exception/ContainerException.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Exception/NotFoundException.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/Inflector.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/InflectorAggregate.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/InflectorAggregateInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/InflectorInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ReflectionContainer.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/AbstractServiceProvider.php rename wp-content/plugins/wp-rocket/inc/{Engine => Dependencies/League}/Container/ServiceProvider/BootableServiceProviderInterface.php (69%) create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/ServiceProviderAggregate.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/ServiceProviderAggregateInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/ServiceProviderInterface.php rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/ErrorHandler.php (96%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Formatter/FormatterInterface.php (85%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Formatter/HtmlFormatter.php (93%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Formatter/LineFormatter.php (97%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Formatter/NormalizerFormatter.php (86%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Handler/AbstractHandler.php (92%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Handler/AbstractProcessingHandler.php (89%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Handler/FormattableHandlerInterface.php (81%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Handler/FormattableHandlerTrait.php (83%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Handler/HandlerInterface.php (90%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Handler/ProcessableHandlerInterface.php (83%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Handler/ProcessableHandlerTrait.php (89%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Handler/StreamHandler.php (89%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Logger.php (97%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Processor/IntrospectionProcessor.php (92%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Processor/ProcessorInterface.php (64%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Registry.php (85%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/ResettableInterface.php (88%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/SignalHandler.php (93%) rename wp-content/plugins/wp-rocket/{vendor/monolog/monolog/src => inc/Dependencies}/Monolog/Utils.php (96%) rename wp-content/plugins/wp-rocket/{vendor/psr/container/src => inc/Dependencies/Psr/Container}/ContainerExceptionInterface.php (50%) rename wp-content/plugins/wp-rocket/{vendor/psr/container/src => inc/Dependencies/Psr/Container}/ContainerInterface.php (83%) rename wp-content/plugins/wp-rocket/{vendor/psr/container/src => inc/Dependencies/Psr/Container}/NotFoundExceptionInterface.php (51%) rename wp-content/plugins/wp-rocket/{vendor/psr/log => inc/Dependencies}/Psr/Log/AbstractLogger.php (82%) rename wp-content/plugins/wp-rocket/{vendor/psr/log => inc/Dependencies}/Psr/Log/InvalidArgumentException.php (64%) rename wp-content/plugins/wp-rocket/{vendor/psr/log => inc/Dependencies}/Psr/Log/LogLevel.php (88%) rename wp-content/plugins/wp-rocket/{vendor/psr/log => inc/Dependencies}/Psr/Log/LoggerAwareInterface.php (86%) rename wp-content/plugins/wp-rocket/{vendor/psr/log => inc/Dependencies}/Psr/Log/LoggerAwareTrait.php (82%) rename wp-content/plugins/wp-rocket/{vendor/psr/log => inc/Dependencies}/Psr/Log/LoggerInterface.php (96%) rename wp-content/plugins/wp-rocket/{vendor/psr/log => inc/Dependencies}/Psr/Log/LoggerTrait.php (96%) rename wp-content/plugins/wp-rocket/{vendor/psr/log => inc/Dependencies}/Psr/Log/NullLogger.php (84%) create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Psr/SimpleCache/CacheException.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Psr/SimpleCache/CacheInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Dependencies/Psr/SimpleCache/InvalidArgumentException.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Admin/API/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Admin/API/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Admin/ActionSchedulerSubscriber.php rename wp-content/plugins/wp-rocket/inc/{classes/admin/Database/class-optimization.php => Engine/Admin/Database/Optimization.php} (64%) rename wp-content/plugins/wp-rocket/inc/{classes/admin/Database/class-optimization-process.php => Engine/Admin/Database/OptimizationProcess.php} (82%) create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/ServiceProvider.php rename wp-content/plugins/wp-rocket/inc/{classes/subscriber/admin/Database/class-optimization-subscriber.php => Engine/Admin/Database/Subscriber.php} (91%) create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Admin/Deactivation/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Admin/DomainChange/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Admin/DomainChange/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Admin/Metaboxes/PostEditOptionsSubscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/CDN/Admin/Subscriber.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/composer.json create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Cache/Config/ConfigSubscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Cache/Config/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Ajax/AjaxHandler.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Cache/CacheInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Cache/FilesystemCache.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Clock/ClockInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Clock/WPRClock.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Context/AbstractContext.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Context/ContextInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Database/Queries/AbstractQuery.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Database/TableInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Database/Tables/AbstractTable.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/ExtractCSS/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/ExtractCSS/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/APIHandler/APIClient.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/APIHandler/AbstractAPIClient.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/AbstractFactory/SaasFactory.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Cron/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/JobProcessor.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Managers/AbstractManager.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Managers/ManagerInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Queue/Queue.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Context/RetryContext.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Factory/StrategyFactory.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/DefaultProcess.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/JobSetFail.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/ResetRetryProcess.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/StrategyInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/AbstractASQueue.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/Cleaner.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/QueueInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/RUCSSQueueRunner.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Common/Utils.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/ArgumentResolverInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/ArgumentResolverTrait.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/RawArgument.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/RawArgumentInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Container.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerAwareInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerAwareTrait.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/AbstractDefinition.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/CallableDefinition.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/ClassDefinition.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/ClassDefinitionInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionFactory.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionFactoryInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Exception/NotFoundException.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerAwareInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerAwareTrait.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/Inflector.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/InflectorAggregate.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/InflectorAggregateInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ReflectionContainer.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/AbstractServiceProvider.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/AbstractSignatureServiceProvider.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderAggregate.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderAggregateInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderInterface.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/SignatureServiceProviderInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Debug/DebugSubscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Debug/RUCSS/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Debug/Resolver.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Debug/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/ActionSchedulerCheck.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/CacheDirSizeCheck.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner-ocd-disabled.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner-ocd.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/AJAX/Controller.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/AJAX/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Activation/Activation.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Activation/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Admin/Controller.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Admin/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Context/Context.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Cron/Controller.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Cron/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Queries/AboveTheFold.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Rows/AboveTheFold.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Schemas/AboveTheFold.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Tables/AboveTheFold.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Frontend/Controller.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Frontend/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/APIClient.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Controller.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Queue.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Admin/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Admin/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Context/LazyloadCSSContext.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/LazyloadCSSContentFactory.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/LazyloadedContent.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/ProtectedContent.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/ContentFetcher.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/Extractor.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/FileResolver.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/MappingFormatter.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/RuleFormatter.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/TagGenerator.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CanLazyloadTrait.php rename wp-content/plugins/wp-rocket/inc/{classes/Buffer/class-optimization.php => Engine/Optimization/Buffer/Optimization.php} (76%) rename wp-content/plugins/wp-rocket/inc/{classes/subscriber/Optimization/class-buffer-subscriber.php => Engine/Optimization/Buffer/Subscriber.php} (75%) create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/ContentTrait.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/SiteList.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/AbstractAPIClient.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/AbstractDataManager.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DefaultLists/APIClient.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DefaultLists/DataManager.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DelayJSLists/APIClient.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DelayJSLists/DataManager.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DynamicLists.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/IncompatiblePluginsLists/APIClient.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/IncompatiblePluginsLists/DataManager.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/AdminSubscriber.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Combine.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Database.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/OptionSubscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Settings.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSContext.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSContextSaas.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSOptimizeContext.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Controller/Filesystem.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Controller/UsedCSS.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Cron/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Queries/UsedCSS.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Row/UsedCSS.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Schemas/UsedCSS.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Tables/UsedCSS.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Frontend/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Jobs/Factory.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Jobs/Manager.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/RegexTrait.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Optimization/UrlTrait.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Plugin/InformationSubscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Plugin/RenewalNotice.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Plugin/ServiceProvider.php rename wp-content/plugins/wp-rocket/inc/{classes/subscriber/Plugin/class-updater-api-common-subscriber.php => Engine/Plugin/UpdaterApiCommonSubscriber.php} (70%) rename wp-content/plugins/wp-rocket/inc/{classes/traits/trait-updater-api-tools.php => Engine/Plugin/UpdaterApiTools.php} (65%) rename wp-content/plugins/wp-rocket/inc/{classes/subscriber/Plugin/class-updater-subscriber.php => Engine/Plugin/UpdaterSubscriber.php} (57%) delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/AbstractPreload.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/AbstractProcess.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Activation/Activation.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Activation/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Admin/Settings.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Admin/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Controller/CheckExcludedTrait.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Controller/CheckFinished.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Controller/ClearCache.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Controller/CrawlHomepage.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Controller/LoadInitialSitemap.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Controller/PreloadUrl.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Controller/Queue.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Cron/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Database/Queries/Cache.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Database/Rows/CacheRow.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Database/Schemas/Cache.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Database/Tables/Cache.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Frontend/FetchSitemap.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Frontend/SitemapParser.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Frontend/Subscriber.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/FullProcess.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Homepage.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/PartialPreloadSubscriber.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/PartialProcess.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/PreloadSubscriber.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Sitemap.php delete mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/SitemapPreloadSubscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Preload/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Saas/Admin/AdminBar.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Saas/Admin/Clean.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Saas/Admin/Notices.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Saas/Admin/Subscriber.php create mode 100644 wp-content/plugins/wp-rocket/inc/Engine/Saas/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Logger/HTMLFormatter.php create mode 100644 wp-content/plugins/wp-rocket/inc/Logger/Logger.php create mode 100644 wp-content/plugins/wp-rocket/inc/Logger/LoggerAware.php create mode 100644 wp-content/plugins/wp-rocket/inc/Logger/LoggerAwareInterface.php create mode 100644 wp-content/plugins/wp-rocket/inc/Logger/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/Logger/StreamHandler.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Hostings/Godaddy.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Hostings/Kinsta.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Hostings/LiteSpeed.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Hostings/OneCom.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Hostings/Pressidium.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Hostings/ProIsp.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Hostings/WPXCloud.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/Ads/Adthrive.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/CDN/Cloudflare.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/CDN/CloudflareFacade.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/ContactForm7.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/ConvertPlug.php rename wp-content/plugins/wp-rocket/inc/{classes/subscriber/third-party/plugins/ecommerce/class-bigcommerce-subscriber.php => ThirdParty/Plugins/Ecommerce/BigCommerce.php} (93%) create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/I18n/TranslatePress.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/I18n/WPML.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/I18n/Weglot.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/InlineRelatedPosts.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/Jetpack.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/ModPagespeed.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/Optimization/Autoptimize.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/Optimization/Ezoic.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/Optimization/Perfmatters.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/Optimization/RapidLoad.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/Optimization/RocketLazyLoad.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/Optimization/WPMeteor.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/PWA.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/RevolutionSlider.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/SEO/AllInOneSEOPack.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/SEO/RankMathSEO.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/SEO/SEOPress.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/SEO/TheSEOFramework.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/SEO/Yoast.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/Security/WordFenceCompatibility.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/TheEventsCalendar.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/ThirstyAffiliates.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/UnlimitedElements.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Plugins/WPGeotargeting.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/Flatsome.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/Jevelin.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/MinimalistBlogger.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/Polygon.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/ServiceProvider.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/Shoptimizer.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/SubscriberFactory.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/ThemeResolver.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/Themify.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/Uncode.php create mode 100644 wp-content/plugins/wp-rocket/inc/ThirdParty/Themes/Xstore.php delete mode 100644 wp-content/plugins/wp-rocket/inc/classes/ServiceProvider/class-database.php delete mode 100644 wp-content/plugins/wp-rocket/inc/classes/ServiceProvider/class-updater-subscribers.php delete mode 100644 wp-content/plugins/wp-rocket/inc/classes/admin/deactivation/class-render.php delete mode 100644 wp-content/plugins/wp-rocket/inc/classes/subscriber/Media/class-webp-subscriber.php delete mode 100644 wp-content/plugins/wp-rocket/inc/classes/subscriber/Plugin/class-information-subscriber.php delete mode 100644 wp-content/plugins/wp-rocket/inc/classes/subscriber/third-party/Hostings/class-litespeed-subscriber.php delete mode 100644 wp-content/plugins/wp-rocket/inc/common/cloudflare-flexible-ssl.php create mode 100644 wp-content/plugins/wp-rocket/inc/deprecated/3.10.php create mode 100644 wp-content/plugins/wp-rocket/inc/deprecated/3.11.php create mode 100644 wp-content/plugins/wp-rocket/inc/deprecated/3.12.php rename wp-content/plugins/wp-rocket/inc/{3rd-party/plugins/geotargetingwp.php => deprecated/3.13.php} (71%) rename wp-content/plugins/wp-rocket/inc/{vendors/ip_in_range.php => deprecated/3.14.php} (58%) create mode 100644 wp-content/plugins/wp-rocket/inc/deprecated/3.15.php rename wp-content/plugins/wp-rocket/inc/{3rd-party/hosting/godaddy.php => deprecated/3.9.php} (71%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated/Engine}/Addon/Busting/BustingFactory.php (90%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated/Engine}/Addon/Busting/FileBustingTrait.php (100%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated/Engine}/Addon/FacebookTracking/Subscriber.php (96%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated/Engine}/Addon/GoogleTracking/GoogleAnalytics.php (97%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated/Engine}/Addon/GoogleTracking/GoogleTagManager.php (97%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated/Engine}/Addon/GoogleTracking/Subscriber.php (96%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated}/Engine/Media/Embeds/EmbedsSubscriber.php (94%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated}/classes/busting/class-abstract-busting.php (100%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated}/classes/busting/class-facebook-pickles.php (99%) rename wp-content/plugins/wp-rocket/inc/{ => deprecated}/classes/busting/class-facebook-sdk.php (99%) delete mode 100644 wp-content/plugins/wp-rocket/inc/front/protocol.php create mode 100644 wp-content/plugins/wp-rocket/languages/rocket-fa_IR.mo create mode 100644 wp-content/plugins/wp-rocket/languages/rocket-fa_IR.po create mode 100644 wp-content/plugins/wp-rocket/languages/rocket-ja_JP.mo create mode 100644 wp-content/plugins/wp-rocket/languages/rocket-ja_JP.po create mode 100644 wp-content/plugins/wp-rocket/languages/rocket-pt_PT.mo create mode 100644 wp-content/plugins/wp-rocket/languages/rocket-pt_PT.po create mode 100644 wp-content/plugins/wp-rocket/licence-data.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/autoload.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/ClassLoader.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/LICENSE delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/autoload_classmap.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/autoload_namespaces.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/autoload_psr4.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/autoload_real.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/autoload_static.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installed.json delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/LICENSE delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/composer.json delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/AglInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/AimeosInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/AnnotateCmsInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/AsgardInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/AttogramInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/BaseInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/BitrixInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/BonefishInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/CakePHPInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ChefInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/CiviCrmInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ClanCatsFrameworkInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/CockpitInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/CodeIgniterInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/Concrete5Installer.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/CraftInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/CroogoInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/DecibelInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/DframeInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/DokuWikiInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/DolibarrInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/DrupalInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ElggInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/EliasisInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ExpressionEngineInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/EzPlatformInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/FuelInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/FuelphpInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/GravInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/HuradInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ImageCMSInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/Installer.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ItopInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/JoomlaInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/KanboardInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/KirbyInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/KnownInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/KodiCMSInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/KohanaInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/LanManagementSystemInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/LaravelInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/LavaLiteInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/LithiumInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MODULEWorkInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MODXEvoInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MagentoInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MajimaInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MakoInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MauticInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MayaInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MediaWikiInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MicroweberInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ModxInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/MoodleInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/OctoberInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/OntoWikiInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/OsclassInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/OxidInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PPIInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PhiftyInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PhpBBInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PimcoreInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PiwikInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PlentymarketsInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/Plugin.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PortoInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PrestashopInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PuppetInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/PxcmsInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/RadPHPInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ReIndexInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/Redaxo5Installer.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/RedaxoInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/RoundcubeInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/SMFInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ShopwareInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/SilverStripeInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/SiteDirectInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/SyDESInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/Symfony1Installer.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/TYPO3CmsInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/TYPO3FlowInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/TaoInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/TheliaInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/TuskInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/UserFrostingInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/VanillaInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/VgmcpInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/WHMCSInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/WolfCMSInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/WordPressInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/YawikInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ZendInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/Composer/Installers/ZikulaInstaller.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/composer/installers/src/bootstrap.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/CHANGELOG.md delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/LICENSE delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/README.md delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/composer.json delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/phpstan.neon.dist delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/container/.gitignore delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/container/LICENSE delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/container/README.md delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/container/composer.json delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/log/LICENSE delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/log/Psr/Log/Test/DummyTest.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/log/Psr/Log/Test/LoggerInterfaceTest.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/log/Psr/Log/Test/TestLogger.php delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/log/README.md delete mode 100644 wp-content/plugins/wp-rocket/vendor/psr/log/composer.json create mode 100644 wp-content/plugins/wp-rocket/views/metaboxes/post_edit_options.php create mode 100644 wp-content/plugins/wp-rocket/views/plugins/update-renewal-expired-notice.php create mode 100644 wp-content/plugins/wp-rocket/views/settings/dynamic-lists-update.php create mode 100644 wp-content/plugins/wp-rocket/views/settings/fields/categorized_multiselect.php create mode 100644 wp-content/plugins/wp-rocket/views/settings/fields/radio-buttons.php create mode 100644 wp-content/plugins/wp-rocket/views/settings/mobile-cache.php create mode 100644 wp-content/plugins/wp-rocket/views/settings/sections/clean-section.php diff --git a/wp-content/plugins/wp-rocket/SECURITY.md b/wp-content/plugins/wp-rocket/SECURITY.md new file mode 100644 index 000000000..5abc080ec --- /dev/null +++ b/wp-content/plugins/wp-rocket/SECURITY.md @@ -0,0 +1,6 @@ +# Security Policy + +## Reporting Security Bugs + +Please report security bugs found in the site-reviews plugin's source code through the [Patchstack Vulnerability Disclosure Program](https://patchstack.com/database/vdp/wp-rocket). The Patchstack team will assist you with verification, CVE assignment and take care of notifying the developers of this plugin. +--- \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/css/wpr-admin-rtl.css b/wp-content/plugins/wp-rocket/assets/css/wpr-admin-rtl.css index e2acc4554..9a898719c 100644 --- a/wp-content/plugins/wp-rocket/assets/css/wpr-admin-rtl.css +++ b/wp-content/plugins/wp-rocket/assets/css/wpr-admin-rtl.css @@ -1 +1,332 @@ -.wpr-wrap{margin:0 -20px 0 0}#hs-beacon iframe:nth-child(1){right:inherit !important;left:18px !important}#hs-beacon iframe:nth-child(2){right:inherit !important;left:6px !important}.wpr-Page-col--fixed{margin-left:0;margin-right:24px}@media (max-width: 1239px){.wpr-Page-col--fixed{margin-right:0}}.wpr-Content{border:1px solid #E0E4E9;border-right:none}.wpr-Content-tips{right:unset;left:24px}.wpr-Sidebar-notice{border:1px solid #E8EBEE;border-right:2px solid #1EADBF}.wpr-Sidebar .wpr-Sidebar-info h4{padding-left:inherit;padding-right:56px}.wpr-menuItem{padding:16px 20px 18px 44px}.wpr-menuItem:before{right:inherit !important;left:18px !important}.wpr-menuItem:after{border-width:12px 0 12px 10px;border-color:transparent transparent transparent #fff;left:0;right:inherit;transform:translateX(-12px)}.wpr-menuItem:hover{transform:translateX(0)}.wpr-menuItem.wpr-subMenuItem{padding:10px 25px 8px 20px}.wpr-sectionHeader:before{left:inherit;right:0}.wpr-sectionHeader .wpr-title1:before{margin-left:24px;margin-right:0}.wpr-optionHeader .wpr-title2{padding-right:0;padding-left:40px}.wpr-infoAction:before{right:-26px}.wpr-fieldWarning{padding:16px 56px 24px 16px}.wpr-fieldWarning:after{left:inherit;right:20px}.wpr-fieldWarning:before{left:inherit;right:-16px}.wpr-fieldWarning-title:before{left:inherit;right:-40px}.wpr-checkbox{padding-left:0;padding-right:32px}.wpr-checkbox [type="checkbox"]:not(:checked),.wpr-checkbox [type="checkbox"]:checked{right:-9999px}.wpr-checkbox [type="checkbox"]:not(:checked)+label:before,.wpr-checkbox [type="checkbox"]:checked+label:before{left:inherit;right:0}.wpr-checkbox [type="checkbox"]:not(:checked)+label:after,.wpr-checkbox [type="checkbox"]:checked+label:after{left:inherit;right:2px}.wpr-radio{padding-left:0;padding-right:88px}.wpr-radio [type="checkbox"]:not(:checked),.wpr-radio [type="checkbox"]:checked{right:-9999px}.wpr-radio [type="checkbox"]:not(:checked)+label:before,.wpr-radio [type="checkbox"]:checked+label:before{left:inherit;right:0}.wpr-radio [type="checkbox"]:not(:checked)+label:after,.wpr-radio [type="checkbox"]:checked+label:after{left:inherit;right:3px}.wpr-radio [type="checkbox"]:checked+label:after{right:33px}.wpr-radio [type="checkbox"]:checked+label .wpr-radio-ui,.wpr-radio [type="checkbox"]:not(:checked)+label .wpr-radio-ui:before,.wpr-radio [type="checkbox"]:checked+label .wpr-radio-ui:after{right:4px}.wpr-radio [type="checkbox"]:not(:checked)+label .wpr-radio-ui:before{right:27px}.wpr-radio--reverse{padding-left:0;padding-right:72px}.wpr-radio--reverse [type="checkbox"]:not(:checked)+label:before,.wpr-radio--reverse [type="checkbox"]:checked+label:before{right:0;left:inherit}.wpr-radio--reverse [type="checkbox"]:not(:checked)+label:after,.wpr-radio--reverse [type="checkbox"]:checked+label:after{right:33px;left:inherit}.wpr-radio--reverse [type="checkbox"]:checked+label:after{right:3px;left:inherit}.wpr-radio--reverse [type="checkbox"]:checked+label .wpr-radio-ui,.wpr-radio--reverse [type="checkbox"]:not(:checked)+label .wpr-radio-ui:before,.wpr-radio--reverse [type="checkbox"]:checked+label .wpr-radio-ui:after{right:15px;left:inherit}.wpr-radio--reverse [type="checkbox"]:not(:checked)+label .wpr-radio-ui:before{right:6px;left:inherit}.wpr-multiple .wpr-button{margin-right:16px;margin-left:0}.wpr-multiple-close{margin-right:0;margin-left:16px}.wpr-addon .wpr-flex>div{text-align:right}.wpr-addon .wpr-addon-text{margin-left:inherit;margin-right:32px}@media (max-width: 1239px){.wpr-addon .wpr-addon-text{margin-right:16px}}@media (max-width: 1083px){.wpr-addon .wpr-addon-text{margin-right:32px}}@media (max-width: 783px){.wpr-addon .wpr-addon-text{margin-right:0}}.wpr-tools-col:first-child{padding-right:72px;padding-left:24px}.wpr-tools-col:last-child{text-align:left}@media (max-width: 783px){.wpr-tools-col:last-child{text-align:right}}.wpr-tools-label:before{left:inherit;right:0}.wpr-field .wpr-flex--egal>div:last-child{text-align:left}.wpr-field-list li:before{display:inline-block;margin-right:0;margin-left:8px}.wpr-field--split{padding-right:0}.wpr-field--split+.wpr-field--split{padding-left:0;padding-right:16px}.wpr-field--children{padding-left:0;padding-right:32px}.wpr-field--children.wpr-field--textarea{padding-left:80px;padding-right:32px}@media (max-width: 1239px){.wpr-field--children.wpr-field--textarea{padding-left:32px;padding-right:0}}@media (max-width: 783px){.wpr-field--children.wpr-field--textarea{padding-left:0}}.wpr-field--checkbox .wpr-field-description{margin-left:0;margin-right:32px}.wpr-field--radio .wpr-field-description{margin-left:0;margin-right:88px}.wpr-adblock img{margin-right:0;margin-left:16px}.wpr-adblock-close{right:inherit;left:24px}.wpr-notice{background-position:10% bottom}.wpr-notice-container{padding:24px 40px 24px 25%}.wpr-notice-close{right:inherit;left:24px} +/*-----------------------------------------------*\ + +Author: Thomas Geisen (www.thomasgeisen.fr) +Method : SUITCSS (modified) + +--- This file is only for RTL languages + +\*-----------------------------------------------*/ +.wpr-wrap { + margin: 0 -20px 0 0; +} + +#hs-beacon iframe:nth-child(1) { + right: inherit !important; + left: 18px !important; +} +#hs-beacon iframe:nth-child(2) { + right: inherit !important; + left: 6px !important; +} + +.wpr-Page-col--fixed { + margin-left: 0; + margin-right: 24px; +} +@media (max-width: 1239px) { + .wpr-Page-col--fixed { + margin-right: 0; + } +} + +.wpr-Content { + border: 1px solid #E0E4E9; + border-right: none; +} + +.wpr-Content-tips { + right: unset; + left: 24px; +} + +.wpr-Sidebar-notice { + border: 1px solid #E8EBEE; + border-right: 2px solid #1EADBF; +} +.wpr-Sidebar .wpr-Sidebar-info h4 { + padding-left: inherit; + padding-right: 56px; +} + +.wpr-menuItem { + padding: 16px 20px 18px 44px; +} +.wpr-menuItem:before { + right: inherit !important; + left: 18px !important; +} +.wpr-menuItem:after { + border-width: 12px 0 12px 10px; + border-color: transparent transparent transparent #fff; + left: 0; + right: inherit; + transform: translateX(-12px); +} +.wpr-menuItem:hover { + transform: translateX(0); +} +.wpr-menuItem.wpr-subMenuItem { + padding: 10px 25px 8px 20px; +} + +.wpr-sectionHeader:before { + left: inherit; + right: 0; +} +.wpr-sectionHeader .wpr-title1:before { + margin-left: 24px; + margin-right: 0; +} + +.wpr-optionHeader .wpr-title2 { + padding-right: 0; + padding-left: 40px; +} + +.wpr-infoAction:before { + right: -26px; +} + +.wpr-fieldWarning { + padding: 16px 56px 24px 16px; +} +.wpr-fieldWarning:after { + left: inherit; + right: 20px; +} +.wpr-fieldWarning:before { + left: inherit; + right: -16px; +} +.wpr-fieldWarning-title:before { + left: inherit; + right: -40px; +} +.wpr-fieldWarning.wpr-radio-warning { + margin-left: 0; + margin-right: -32px; +} +.wpr-fieldWarning.wpr-radio-warning:after { + left: inherit; + right: 40px; +} + +@media only screen and (max-width: 400px) { + .wpr-fieldWarning.wpr-radio-warning { + margin-left: 0; + margin-right: -32px; + } + .wpr-fieldWarning.wpr-radio-warning .wpr-button { + padding-right: 8px; + padding-left: 32px; + } +} +@media only screen and (max-width: 350px) { + .wpr-radio-buttons { + padding-left: 0; + padding-right: 24px; + } + + .wpr-fieldWarning.wpr-radio-warning { + margin-left: 0; + margin-right: -24px; + padding-left: 0; + padding-right: 30px; + } + .wpr-fieldWarning.wpr-radio-warning .wpr-button { + white-space: normal; + padding-right: 8px; + padding-left: 25px; + } +} +.wpr-checkbox { + padding-left: 0; + padding-right: 32px; +} +.wpr-checkbox [type=checkbox]:not(:checked), +.wpr-checkbox [type=checkbox]:checked { + right: -9999px; +} +.wpr-checkbox [type=checkbox]:not(:checked) + label:before, +.wpr-checkbox [type=checkbox]:checked + label:before { + left: inherit; + right: 0; +} +.wpr-checkbox [type=checkbox]:not(:checked) + label:after, +.wpr-checkbox [type=checkbox]:checked + label:after { + left: inherit; + right: 2px; +} + +.wpr-radio { + padding-left: 0; + padding-right: 88px; +} +.wpr-radio [type=checkbox]:not(:checked), +.wpr-radio [type=checkbox]:checked { + right: -9999px; +} +.wpr-radio [type=checkbox]:not(:checked) + label:before, +.wpr-radio [type=checkbox]:checked + label:before { + left: inherit; + right: 0; +} +.wpr-radio [type=checkbox]:not(:checked) + label:after, +.wpr-radio [type=checkbox]:checked + label:after { + left: inherit; + right: 3px; +} +.wpr-radio [type=checkbox]:checked + label:after { + right: 33px; +} +.wpr-radio [type=checkbox]:checked + label .wpr-radio-ui, +.wpr-radio [type=checkbox]:not(:checked) + label .wpr-radio-ui:before, +.wpr-radio [type=checkbox]:checked + label .wpr-radio-ui:after { + right: 4px; +} +.wpr-radio [type=checkbox]:not(:checked) + label .wpr-radio-ui:before { + right: 27px; +} +.wpr-radio--reverse { + padding-left: 0; + padding-right: 72px; +} +.wpr-radio--reverse [type=checkbox]:not(:checked) + label:before, +.wpr-radio--reverse [type=checkbox]:checked + label:before { + right: 0; + left: inherit; +} +.wpr-radio--reverse [type=checkbox]:not(:checked) + label:after, +.wpr-radio--reverse [type=checkbox]:checked + label:after { + right: 33px; + left: inherit; +} +.wpr-radio--reverse [type=checkbox]:checked + label:after { + right: 3px; + left: inherit; +} +.wpr-radio--reverse [type=checkbox]:checked + label .wpr-radio-ui, +.wpr-radio--reverse [type=checkbox]:not(:checked) + label .wpr-radio-ui:before, +.wpr-radio--reverse [type=checkbox]:checked + label .wpr-radio-ui:after { + right: 15px; + left: inherit; +} +.wpr-radio--reverse [type=checkbox]:not(:checked) + label .wpr-radio-ui:before { + right: 6px; + left: inherit; +} + +.wpr-multiple .wpr-button { + margin-right: 16px; + margin-left: 0; +} +.wpr-multiple-close { + margin-right: 0; + margin-left: 16px; +} + +.wpr-addon .wpr-flex > div { + text-align: right; +} +.wpr-addon .wpr-addon-text { + margin-left: inherit; + margin-right: 32px; +} +@media (max-width: 1239px) { + .wpr-addon .wpr-addon-text { + margin-right: 16px; + } +} +@media (max-width: 1083px) { + .wpr-addon .wpr-addon-text { + margin-right: 32px; + } +} +@media (max-width: 783px) { + .wpr-addon .wpr-addon-text { + margin-right: 0; + } +} + +.wpr-tools-col:first-child { + padding-right: 72px; + padding-left: 24px; +} +.wpr-tools-col:last-child { + text-align: left; +} +@media (max-width: 783px) { + .wpr-tools-col:last-child { + text-align: right; + } +} +.wpr-tools-label:before { + left: inherit; + right: 0; +} + +.wpr-field .wpr-flex--egal > div:last-child { + text-align: left; +} +.wpr-field-list li:before { + display: inline-block; + margin-right: 0; + margin-left: 8px; +} +.wpr-field--split { + padding-right: 0; +} +.wpr-field--split + .wpr-field--split { + padding-left: 0; + padding-right: 16px; +} +.wpr-field--children { + padding-left: 0; + padding-right: 32px; +} +.wpr-field--children.wpr-field--textarea { + padding-left: 80px; + padding-right: 32px; +} +@media (max-width: 1239px) { + .wpr-field--children.wpr-field--textarea { + padding-left: 32px; + padding-right: 0; + } +} +@media (max-width: 783px) { + .wpr-field--children.wpr-field--textarea { + padding-left: 0; + } +} +.wpr-field--children.no-space { + padding-right: 0; +} +.wpr-field--checkbox .wpr-field-description { + margin-left: 0; + margin-right: 32px; +} +.wpr-field--radio .wpr-field-description { + margin-left: 0; + margin-right: 88px; +} + +.wpr-adblock img { + margin-right: 0; + margin-left: 16px; +} +.wpr-adblock-close { + right: inherit; + left: 24px; +} + +.wpr-notice { + background-position: 10% bottom; +} +.wpr-notice-container { + padding: 24px 40px 24px 25%; +} +.wpr-notice-close { + right: inherit; + left: 24px; +} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/css/wpr-admin-rtl.min.css b/wp-content/plugins/wp-rocket/assets/css/wpr-admin-rtl.min.css new file mode 100644 index 000000000..8eade5491 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/css/wpr-admin-rtl.min.css @@ -0,0 +1 @@ +.wpr-wrap{margin:0 -20px 0 0}#hs-beacon iframe:nth-child(1){right:inherit !important;left:18px !important}#hs-beacon iframe:nth-child(2){right:inherit !important;left:6px !important}.wpr-Page-col--fixed{margin-left:0;margin-right:24px}@media(max-width: 1239px){.wpr-Page-col--fixed{margin-right:0}}.wpr-Content{border:1px solid #e0e4e9;border-right:none}.wpr-Content-tips{right:unset;left:24px}.wpr-Sidebar-notice{border:1px solid #e8ebee;border-right:2px solid #1eadbf}.wpr-Sidebar .wpr-Sidebar-info h4{padding-left:inherit;padding-right:56px}.wpr-menuItem{padding:16px 20px 18px 44px}.wpr-menuItem:before{right:inherit !important;left:18px !important}.wpr-menuItem:after{border-width:12px 0 12px 10px;border-color:transparent transparent transparent #fff;left:0;right:inherit;transform:translateX(-12px)}.wpr-menuItem:hover{transform:translateX(0)}.wpr-menuItem.wpr-subMenuItem{padding:10px 25px 8px 20px}.wpr-sectionHeader:before{left:inherit;right:0}.wpr-sectionHeader .wpr-title1:before{margin-left:24px;margin-right:0}.wpr-optionHeader .wpr-title2{padding-right:0;padding-left:40px}.wpr-infoAction:before{right:-26px}.wpr-fieldWarning{padding:16px 56px 24px 16px}.wpr-fieldWarning:after{left:inherit;right:20px}.wpr-fieldWarning:before{left:inherit;right:-16px}.wpr-fieldWarning-title:before{left:inherit;right:-40px}.wpr-fieldWarning.wpr-radio-warning{margin-left:0;margin-right:-32px}.wpr-fieldWarning.wpr-radio-warning:after{left:inherit;right:40px}@media only screen and (max-width: 400px){.wpr-fieldWarning.wpr-radio-warning{margin-left:0;margin-right:-32px}.wpr-fieldWarning.wpr-radio-warning .wpr-button{padding-right:8px;padding-left:32px}}@media only screen and (max-width: 350px){.wpr-radio-buttons{padding-left:0;padding-right:24px}.wpr-fieldWarning.wpr-radio-warning{margin-left:0;margin-right:-24px;padding-left:0;padding-right:30px}.wpr-fieldWarning.wpr-radio-warning .wpr-button{white-space:normal;padding-right:8px;padding-left:25px}}.wpr-checkbox{padding-left:0;padding-right:32px}.wpr-checkbox [type=checkbox]:not(:checked),.wpr-checkbox [type=checkbox]:checked{right:-9999px}.wpr-checkbox [type=checkbox]:not(:checked)+label:before,.wpr-checkbox [type=checkbox]:checked+label:before{left:inherit;right:0}.wpr-checkbox [type=checkbox]:not(:checked)+label:after,.wpr-checkbox [type=checkbox]:checked+label:after{left:inherit;right:2px}.wpr-radio{padding-left:0;padding-right:88px}.wpr-radio [type=checkbox]:not(:checked),.wpr-radio [type=checkbox]:checked{right:-9999px}.wpr-radio [type=checkbox]:not(:checked)+label:before,.wpr-radio [type=checkbox]:checked+label:before{left:inherit;right:0}.wpr-radio [type=checkbox]:not(:checked)+label:after,.wpr-radio [type=checkbox]:checked+label:after{left:inherit;right:3px}.wpr-radio [type=checkbox]:checked+label:after{right:33px}.wpr-radio [type=checkbox]:checked+label .wpr-radio-ui,.wpr-radio [type=checkbox]:not(:checked)+label .wpr-radio-ui:before,.wpr-radio [type=checkbox]:checked+label .wpr-radio-ui:after{right:4px}.wpr-radio [type=checkbox]:not(:checked)+label .wpr-radio-ui:before{right:27px}.wpr-radio--reverse{padding-left:0;padding-right:72px}.wpr-radio--reverse [type=checkbox]:not(:checked)+label:before,.wpr-radio--reverse [type=checkbox]:checked+label:before{right:0;left:inherit}.wpr-radio--reverse [type=checkbox]:not(:checked)+label:after,.wpr-radio--reverse [type=checkbox]:checked+label:after{right:33px;left:inherit}.wpr-radio--reverse [type=checkbox]:checked+label:after{right:3px;left:inherit}.wpr-radio--reverse [type=checkbox]:checked+label .wpr-radio-ui,.wpr-radio--reverse [type=checkbox]:not(:checked)+label .wpr-radio-ui:before,.wpr-radio--reverse [type=checkbox]:checked+label .wpr-radio-ui:after{right:15px;left:inherit}.wpr-radio--reverse [type=checkbox]:not(:checked)+label .wpr-radio-ui:before{right:6px;left:inherit}.wpr-multiple .wpr-button{margin-right:16px;margin-left:0}.wpr-multiple-close{margin-right:0;margin-left:16px}.wpr-addon .wpr-flex>div{text-align:right}.wpr-addon .wpr-addon-text{margin-left:inherit;margin-right:32px}@media(max-width: 1239px){.wpr-addon .wpr-addon-text{margin-right:16px}}@media(max-width: 1083px){.wpr-addon .wpr-addon-text{margin-right:32px}}@media(max-width: 783px){.wpr-addon .wpr-addon-text{margin-right:0}}.wpr-tools-col:first-child{padding-right:72px;padding-left:24px}.wpr-tools-col:last-child{text-align:left}@media(max-width: 783px){.wpr-tools-col:last-child{text-align:right}}.wpr-tools-label:before{left:inherit;right:0}.wpr-field .wpr-flex--egal>div:last-child{text-align:left}.wpr-field-list li:before{display:inline-block;margin-right:0;margin-left:8px}.wpr-field--split{padding-right:0}.wpr-field--split+.wpr-field--split{padding-left:0;padding-right:16px}.wpr-field--children{padding-left:0;padding-right:32px}.wpr-field--children.wpr-field--textarea{padding-left:80px;padding-right:32px}@media(max-width: 1239px){.wpr-field--children.wpr-field--textarea{padding-left:32px;padding-right:0}}@media(max-width: 783px){.wpr-field--children.wpr-field--textarea{padding-left:0}}.wpr-field--children.no-space{padding-right:0}.wpr-field--checkbox .wpr-field-description{margin-left:0;margin-right:32px}.wpr-field--radio .wpr-field-description{margin-left:0;margin-right:88px}.wpr-adblock img{margin-right:0;margin-left:16px}.wpr-adblock-close{right:inherit;left:24px}.wpr-notice{background-position:10% bottom}.wpr-notice-container{padding:24px 40px 24px 25%}.wpr-notice-close{right:inherit;left:24px} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/css/wpr-admin.css b/wp-content/plugins/wp-rocket/assets/css/wpr-admin.css index 77053a1c9..29bef7e14 100644 --- a/wp-content/plugins/wp-rocket/assets/css/wpr-admin.css +++ b/wp-content/plugins/wp-rocket/assets/css/wpr-admin.css @@ -1 +1,3102 @@ -h1,h2,h3,h4{color:currentColor;margin:0;font-weight:normal}button{padding:0;border:none;background:none;cursor:pointer}a{color:currentColor;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}a:hover{color:currentColor}input[type=submit]{cursor:pointer;border:none}a:active,button:active{outline:none}a:focus,button:focus{color:currentColor;box-shadow:none}.wpr-wrap{padding:16px;margin:0 0 0 -20px}@media (max-width: 783px){.wpr-wrap{padding:0;margin:0 0 0 -10px}}.wpr-body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-interpolation-mode:nearest-neighbor;image-rendering:optimizeQuality;text-rendering:optimizeLegibility;display:flex;color:#121116;font-size:.875rem;line-height:1.5}.wpr-body *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@media (max-width: 783px){#hs-beacon{display:none !important}}.wpr-u-flex{display:flex;align-items:center;justify-content:center}@font-face{font-family:'wpr-icomoon';src:url("../fonts/icomoon.eot");src:url("../fonts/icomoon.eot?#iefix") format("embedded-opentype"),url("../fonts/icomoon.woff") format("woff"),url("../fonts/icomoon.ttf") format("truetype"),url("../fonts/icomoon.svg#icomoon") format("svg");font-weight:normal;font-style:normal}[class^="wpr-icon-"]:before,[class*=" wpr-icon-"]:after,[class^="wpr-icon-"]:after,[class*=" wpr-icon-"]:before,[id^="wpr-nav-"]:before,[id*=" wpr-nav-"]:after,[id^="wpr-nav-"]:after,[id*=" wpr-nav-"]:before{font-family:'wpr-icomoon';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}[class^="wpr-icon-"] span.hidden,[class*=" wpr-icon-"] span.hidden{display:inline-block;height:0;width:0;overflow:hidden}.wpr-icon-chevron-right:before{content:"\e900"}.wpr-icon-chevron-left:before{content:"\e900";transform:rotate(180deg)}.wpr-icon-chevron-down:before{content:"\e901";transform:scale(0.6)}.wpr-icon-chevron-up:before{content:"\e902";top:50%;transform:translateY(-50%) scale(0.6)}.wpr-icon-rollback:before{content:"\e903"}.wpr-icon-addon:before,.wpr-addonSubMenuItem:before{content:"\e904"}.wpr-icon-addons:before,#wpr-nav-addons:before{content:"\e905"}.wpr-icon-book:before{content:"\e906"}.wpr-icon-cdn:before,#wpr-nav-page_cdn:before{content:"\e907"}.wpr-icon-database:before,#wpr-nav-database:before{content:"\e908"}.wpr-icon-export:before{content:"\e909"}.wpr-icon-files:before,#wpr-nav-cache:before{content:"\e90a"}.wpr-icon-help:before{content:"\e90b"}.wpr-icon-home:before,#wpr-nav-dashboard:before{content:"\e90c"}.wpr-icon-import:before{content:"\e90d"}.wpr-icon-important:before{content:"\e90e"}.wpr-icon-information:before{content:"\e90f"}.wpr-icon-information2:before{content:"\e910"}.wpr-icon-interrogation:before{content:"\e911"}.wpr-icon-media:before,#wpr-nav-media:before{content:"\e912"}.wpr-icon-plus:before{content:"\e913"}.wpr-icon-refresh:before,#wpr-nav-preload:before{content:"\e914"}.wpr-icon-rules:before,#wpr-nav-advanced_cache:before{content:"\e915"}.wpr-icon-stack:before,#wpr-nav-file_optimization:before{content:"\e916"}.wpr-icon-tools:before,#wpr-nav-tools:before{content:"\e917"}.wpr-icon-trash:before{content:"\e918"}.wpr-icon-user:before{content:"\e919"}.wpr-icon-check:before{content:"\e920"}.wpr-icon-check2:before{content:"\e921"}.wpr-icon-close:before{content:"\e922"}.wpr-icon-heartbeat:before,#wpr-nav-heartbeat:before{content:url("../img/heartbeat.svg")}.wpr-icon-heartbeat-hover:before,#wpr-nav-heartbeat:hover:before,#wpr-nav-heartbeat.isActive:before{content:url("../img/heartbeat-hover.svg")}.wpr-icon-imagify:before,#wpr-nav-imagify:before{content:url("../img/imagify.svg")}.wpr-icon-imagify-hover:before,#wpr-nav-imagify:hover:before,#wpr-nav-imagify.isActive:before{content:url("../img/imagify-hover.svg")}.wpr-icon-tutorial:before,#wpr-nav-tutorials:before{content:url("../img/play.svg")}.wpr-icon-tutorial-hover:before,#wpr-nav-tutorials:hover:before,#wpr-nav-tutorials.isActive:before{content:url("../img/play-hover.svg")}.wpr-icon-tutorial-alt:before{content:url("../img/play-alt.svg")}.wpr-title1{font-size:1.625rem;line-height:1;font-weight:600;letter-spacing:0.01em}.wpr-title2{font-size:1rem;line-height:1.5;font-weight:bold;letter-spacing:-0.02em}.wpr-title3,.wpr-field--radio label,.wpr-select select,.wpr-select label{font-size:.875rem;line-height:1.71429;font-weight:bold;letter-spacing:-0.011em}.wpr-Header{display:flex;flex-direction:column;flex:0 0 225px}@media (max-width: 783px){.wpr-Header{flex:0 0 50px}}.wpr-Header-logo{padding:32px 0 24px;text-align:center}@media (max-width: 783px){.wpr-Header-logo{padding:16px 0 8px}}@media (max-width: 783px){.wpr-Header-logo-desktop{display:none}}.wpr-Header-logo-mobile{display:none}@media (max-width: 783px){.wpr-Header-logo-mobile{display:inline-block}}.wpr-Header-footer{margin-top:auto;padding:48px 20px 0;font-size:.6875rem;line-height:4.36364;color:#666;opacity:0.6;font-weight:bold}@media (max-width: 783px){.wpr-Header-footer{display:none}}.wpr-Sidebar{position:relative;display:none;flex:0 0 290px;padding:24px 16px}@media (max-width: 1239px){.wpr-Sidebar{flex:0 0 260px}}@media (max-width: 1083px){.wpr-Sidebar{display:none !important}}.wpr-Sidebar-title{margin-bottom:32px}.wpr-Sidebar-notice{padding:8px 16px;margin-bottom:16px;background:#fff;border:1px solid #E8EBEE;border-left:2px solid #1EADBF;border-radius:0 3px 3px 0;color:#666}.wpr-Sidebar-notice p{margin:0}.wpr-Sidebar-notice-link{display:inline-block;margin-top:8px;font-size:.6875rem;line-height:1.81818;color:#02707F;letter-spacing:-0.05em;text-transform:uppercase;text-decoration:none;font-weight:bold}.wpr-Sidebar-notice-link:hover,.wpr-Sidebar-notice-link:focus{color:#40BACB}.wpr-Sidebar-info{padding:16px;background:#EBFAF5;margin-bottom:16px;border-radius:3px}.wpr-Sidebar-info h4{padding-left:48px;font-weight:500}.wpr-Sidebar-info p{margin:8px 0 0;font-size:.6875rem;line-height:1.45455;color:#666}.wpr-Sidebar-info i{position:absolute;display:block;margin-top:-1px;width:40px;height:40px;color:#00A66B;font-size:1.0625rem;line-height:2.35294;background:#C6F0DE;border-radius:3px;text-align:center}.wpr-Content{position:relative;background:#fff;padding:32px 24px;flex:1 1 auto;max-width:calc(960px + 270px)}@media (max-width: 783px){.wpr-Content{padding:24px 16px}}.wpr-Content form>input:last-child{margin-top:24px;color:#fff !important}.wpr-Content.isNotFull{max-width:960px}.wpr-Content-tips{position:absolute;top:48px;right:24px;font-weight:bold;color:#666}@media (max-width: 1083px){.wpr-Content-tips{display:none !important}}.wpr-Page{margin-bottom:32px}.wpr-Page-row{display:flex;flex-direction:row}@media (max-width: 1239px){.wpr-Page-row{flex-direction:column}}.wpr-Page-col{flex:1 1 auto}.wpr-Page-col--fixed{margin-left:24px;flex:0 0 325px}@media (max-width: 1239px){.wpr-Page-col--fixed{margin-left:0}}.wpr-Page#dashboard #wpr-action-refresh_account:before{transition:all 200ms ease-out;opacity:1;transform:translateY(0)}.wpr-Page#dashboard #wpr-action-refresh_account.wpr-isLoading:before{animation:loading 1.2s infinite}.wpr-Page#dashboard #wpr-action-refresh_account.wpr-isHidden:before{opacity:0}.wpr-Page#dashboard #wpr-action-refresh_account.wpr-isShown:before{opacity:1}@keyframes loading{from{transform:rotate(0)}to{transform:rotate(360deg)}}.wpr-Page#dashboard .wpr-documentation{margin-top:98px;padding:43px 16px}@media (max-width: 1239px){.wpr-Page#dashboard .wpr-documentation{margin-top:40px}}.wpr-Page#dashboard .wpr-documentation .wpr-button{margin-top:8px}.wpr-Page#dashboard .wpr-documentation i{font-size:3.375rem;line-height:1}.wpr-Page#dashboard .wpr-radio{padding-left:72px}.wpr-Page#dashboard .wpr-field--radio{padding:16px 8px}.wpr-Page#dashboard .wpr-field--radio:first-child{padding-top:0}.wpr-Page#dashboard .wpr-field--radio:last-child{padding-bottom:0}.wpr-Page#dashboard .wpr-field--radio .wpr-field-description{font-style:normal;color:#666;margin-left:72px}.wpr-Page#dashboard .wpr-field-account{padding-bottom:0}.wpr-Page#dashboard .wpr-infoAccount{font-weight:bold;margin-left:8px;color:#444}.wpr-Page#dashboard .wpr-infoAccount:before{content:"";position:relative;display:inline-block;width:13px;height:13px;background:#E0E4E9;border-radius:50%;color:#fff;margin-right:6px;text-align:center;top:2px;font-size:.5rem;line-height:1.625}.wpr-Page#dashboard .wpr-infoAccount.wpr-isValid{color:#00A66B}.wpr-Page#dashboard .wpr-infoAccount.wpr-isValid:before{content:"\e920";font-family:'wpr-icomoon';speak:none;background:#3ECE9D;top:-1px}.wpr-Page#dashboard .wpr-infoAccount.wpr-isInvalid{color:#D60E5B}.wpr-Page#dashboard .wpr-infoAccount.wpr-isInvalid:before{content:"!";font-weight:bold;font-size:.625rem;line-height:1.3;speak:none;background:#D33F49;top:-1px}.wpr-Page#dashboard #wpr-account-data:before{content:none}.wpr-Page#tools #wpr-action-rocket_enable_mobile_cpcss:before{transition:all 200ms ease-out;opacity:1;transform:translateY(0)}.wpr-Page#tools #wpr-action-rocket_enable_mobile_cpcss.wpr-isLoading:before{animation:loading 1.2s infinite}.wpr-Popin{display:none;position:fixed;width:772px;height:auto;top:50%;left:50%;background:#fff;border-radius:3px;transform:translateX(-50%) translateY(-50%);z-index:100000}.wpr-Popin-overlay{display:none;position:fixed;opacity:0;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,0.8);z-index:99999}.wpr-Popin-header{display:flex;align-items:center;justify-content:space-between;height:64px;padding:0 32px;background:#2D1656;color:#fff;font-weight:600}.wpr-Popin-close{color:#665090;font-size:1.5rem;line-height:1;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}.wpr-Popin-close:hover,.wpr-Popin-close:focus{color:#fff;outline:none}.wpr-Popin-content{padding:8px 32px;color:#666}.wpr-Popin-flex{display:flex;flex-direction:row;align-items:center}.wpr-Popin-flex div{margin-left:32px}.wpr-Popin p{margin:16px 0}.wpr-Popin .wp-rocket-data-table{padding:12px 24px;background:#F2F3F6 !important;border:none}.wpr-Popin .wp-rocket-data-table td{width:50%;color:#121116;padding:8px 0;padding-left:4px;border-bottom:1px solid #c2cad4}.wpr-Popin .wp-rocket-data-table td:not(.column-primary){font-family:"Monaco";font-size:.75rem;line-height:1.66667;color:#666;letter-spacing:-0.01em}.wpr-Popin .wp-rocket-data-table tr{background:#F2F3F6;border-bottom:1px solid #E0E4E9}.wpr-Popin .wp-rocket-data-table tr:last-child td{border-bottom:none}.wpr-Popin .wp-rocket-data-table strong{font-weight:500}.wpr-Popin .wp-rocket-data-table em{font-style:normal}.wpr-Popin .wp-rocket-data-table code{padding:0;margin:0;background:transparent}.wpr-rocketcdn-cta-small{border-radius:5px;margin:24px 0;padding:16px}.wpr-rocketcdn-cta-small.wpr-isHidden{display:none}.wpr-rocketcdn-cta-small .notice-title{font-weight:700}.wpr-rocketcdn-cta-small .wpr-flex{display:flex;justify-content:space-between;align-items:center}@media (max-width: 783px){.wpr-rocketcdn-cta-small .wpr-flex{text-align:start;flex-direction:column}}.wpr-rocketcdn-cta{margin:10px 0;position:relative}.wpr-rocketcdn-cta.wpr-isHidden{display:none}.wpr-rocketcdn-cta-close{position:absolute;top:16px;right:16px;background:transparent;border:0;color:rgba(255,255,255,0.5)}.wpr-rocketcdn-cta-close--no-promo{position:absolute;top:16px;right:16px;background:transparent;border:0;color:rgba(0,0,0,0.5)}.wpr-rocketcdn-cta-close--no-promo:before{content:"\2715";font-size:2rem;line-height:0.5}.wpr-rocketcdn-cta-close:before{content:"\2715";font-size:2rem;line-height:0.5}.wpr-rocketcdn-cta .wpr-rocketcdn-promo{background:#F56640;border-top-left-radius:2px;border-top-right-radius:2px;color:#fff;padding:16px 48px 16px 16px}.wpr-rocketcdn-cta .wpr-rocketcdn-promo-date{margin:0}.wpr-rocketcdn-cta-subtitle{color:#444;margin-top:0;font-size:1rem;line-height:1.5}.wpr-rocketcdn-cta-content{background:#F9FAFB;border-top:1px solid #E8EBEE;border-left:1px solid #E8EBEE;border-right:1px solid #E8EBEE;padding:16px}.wpr-rocketcdn-cta-content--no-promo{border-top-left-radius:2px;border-top-right-radius:2px;background:#F9FAFB;border-top:1px solid #E8EBEE;border-left:1px solid #E8EBEE;border-right:1px solid #E8EBEE;padding:16px}.wpr-rocketcdn-cta .wpr-flex{display:flex;justify-content:space-between;align-items:center}@media (max-width: 783px){.wpr-rocketcdn-cta .wpr-flex{text-align:start;flex-direction:column}}.wpr-rocketcdn-cta .wpr-rocketcdn-features{border-right:2px solid #cdd1d5;margin:0;padding-right:16px}@media (max-width: 783px){.wpr-rocketcdn-cta .wpr-rocketcdn-features{border-right:none}}.wpr-rocketcdn-cta .wpr-rocketcdn-pricing{align-items:center;display:flex;flex-direction:column;padding:8px 16px;width:calc( 100% / 3)}@media (max-width: 783px){.wpr-rocketcdn-cta .wpr-rocketcdn-pricing{width:auto}}.wpr-rocketcdn-cta .wpr-rocketcdn-pricing-regular{color:#72777C;margin-bottom:8px}.wpr-rocketcdn-cta .wpr-rocketcdn-pricing-current{margin-bottom:16px}.wpr-rocketcdn-cta .wpr-rocketcdn-feature{margin:16px 0;min-height:30px;padding-left:62px;position:relative}.wpr-rocketcdn-cta .wpr-rocketcdn-feature:before{position:absolute;top:50%;left:16px;transform:translateY(-50%)}.wpr-rocketcdn-cta .wpr-rocketcdn-bandwidth:before{content:url(../img/bandwidth.svg)}.wpr-rocketcdn-cta .wpr-rocketcdn-configuration:before{content:url(../img/configuration.svg)}.wpr-rocketcdn-cta .wpr-rocketcdn-automatic:before{content:url(../img/automatic.svg)}.wpr-rocketcdn-cta-footer{background:#72777C;border-bottom-left-radius:2px;border-bottom-right-radius:2px;color:#fff;font-weight:700;padding:8px;text-align:center;text-transform:uppercase;font-size:.6875rem;line-height:1.81818}.wpr-rocketcdn-cta-footer a{text-decoration:none}.wpr-rocketcdn-cta-footer a:before{content:"\00a1";border:1px solid #fff;color:#fff;margin-right:8px;width:18px;height:18px;display:inline-block;border-radius:18px;font-size:.875rem;line-height:1.14286;font-style:italic}.wpr-rocketcdn-subscription{text-align:end}.wpr-rocketcdn-subscription .wpr-rocketcdn-open{color:#666;text-decoration:underline}.wpr-license-upgrade-button{font-weight:bold;text-decoration:underline}.wpr-license-upgrade-button:hover{text-decoration:none}.wpr-field.wpr-field-account .wpr-flex{align-items:flex-start}.wpr-infoAccount-License{flex:1 0 60%;margin-right:16px}@media (max-width: 783px){.wpr-field.wpr-field-account .wpr-flex>div{width:100%}}.wpr-field.wpr-field-account .wpr-flex>div:last-child{text-align:right}@media (max-width: 783px){.wpr-field.wpr-field-account .wpr-flex>div:last-child{text-align:left}}.wpr-Popin-Upgrade .wpr-Popin-content{padding-bottom:32px}.wpr-Popin-Upgrade .wpr-Popin-flex{justify-content:space-between}.wpr-Popin-Upgrade .wpr-Popin-flex>div{align-items:center;border:1px solid #DADADA;border-radius:24px;display:flex;flex-direction:column;margin:0 16px 0 0;padding:24px;text-align:center;width:50%}.wpr-Popin-Upgrade .wpr-Popin-flex>div:last-child{margin-right:0}@media (max-width: 783px){.wpr-Popin-Upgrade .wpr-Popin-flex>div{margin:0;width:100%}}.wpr-Upgrade-Plus .wpr-upgrade-title::before{content:url(../img/plus.svg);display:block;width:117px;height:31px;top:0;position:absolute;left:50%;transform:translateX(-50%)}.wpr-Upgrade-Infinite .wpr-upgrade-title::before{content:url(../img/infinite.svg);display:block;width:48px;height:31px;top:0;position:absolute;left:50%;transform:translateX(-50%)}div.wpr-upgrade-saving{background:#FFD147;border-radius:44px;color:#121116;font-weight:bold;margin:0 0 24px 0;padding:8px 16px;text-align:center}.wpr-upgrade-title{color:#F56F46;font-size:1.875rem;line-height:1.2;margin-bottom:16px;padding-top:55px;position:relative}div.wpr-upgrade-prices{color:#121116;font-size:3rem;line-height:1;font-weight:bold;margin:0 0 16px 0}.wpr-upgrade-price-symbol{font-size:1.875rem;line-height:1;vertical-align:super}.wpr-upgrade-price-regular{color:#72777C;font-size:1rem;line-height:1;vertical-align:top}div.wpr-upgrade-websites{color:#121116;font-size:.875rem;line-height:1;font-weight:bold;margin:0 0 24px 0}.wpr-upgrade-link{background:#fff;border:1px solid #F56F46;border-radius:800px;color:#F56F46;display:block;font-size:1rem;line-height:1.125;font-weight:bold;padding:16px 24px;text-decoration:none}.wpr-upgrade-link:hover{background:#F56F46;color:#fff}.wpr-upgrade-link::after{content:"\2192";font-weight:normal;margin-left:8px}.rocket-promo-banner{background:#FFD147;display:flex;justify-content:space-around;margin-top:16px;padding:24px;position:relative}@media (max-width: 783px){.rocket-promo-banner{flex-flow:column}}.rocket-promo-banner>div{display:flex;flex-flow:column;width:50%}@media (max-width: 783px){.rocket-promo-banner>div{width:100%}}.rocket-promo-title{font-weight:bold;margin-bottom:24px}.rocket-promo-discount{background:#fff;border-radius:44px;display:inline-block;margin-right:8px;padding:8px 16px;text-transform:uppercase}.rocket-promo-message,.rocket-promo-deal{font-size:1rem;line-height:1.5;margin-bottom:0}.rocket-promo-deal{margin-top:8px}.rocket-promo-cta-block{align-items:center;margin-right:24px}.rocket-promo-countdown{display:flex;flex-flow:row wrap;width:66%}.rocket-promo-countdown>.rocket-countdown-item{background:#fff;border-radius:8px;flex:1;margin-right:8px;padding:8px;text-align:center}.rocket-promo-countdown>.rocket-countdown-item>.rocket-countdown-value{display:block;font-size:1.5rem;line-height:1;font-weight:bold}.rocket-promo-cta{background:#172153;border-radius:44px;color:#fff;font-weight:bold;padding:16px 32px}.rocket-renewal-banner{background:#FFD147;display:flex;flex-flow:row wrap;align-items:center;justify-content:space-evenly;margin-top:16px;padding:8px}.rocket-renew-message{margin:0 16px}.rocket-renew-message>p{font-size:.875rem;line-height:1.5}.rocket-expired-message>p{font-size:.875rem;line-height:1.5;padding-left:80px}.rocket-expired-title{font-size:1.375rem;line-height:1.5;font-weight:bold}.rocket-expired-title::before{content:url(../img/warning.svg);display:inline-block;height:48px;width:63px;margin-right:17px;vertical-align:middle}.rocket-expired-cta-container{justify-content:center;align-items:center}.rocket-renew-cta{display:block;background:#172153;border-radius:44px;color:#fff;font-size:1rem;line-height:1.125;font-weight:bold;padding:16px 24px;text-decoration:none}.rocket-renew-cta:hover,.rocket-renew-cta:active,.rocket-renew-cta:focus{color:#fff}.rocket-renew-cta::after{content:"\2192";font-weight:normal;margin-left:8px}.wpr-menuItem{position:relative;display:block;padding:16px 44px 18px 20px;text-decoration:none;color:#121116;border-top:1px solid #E0E4E9;border-left:2px solid transparent;overflow:hidden;transition:all 100ms ease-out;-webkit-transition:all 100ms ease-out}@media (max-width: 783px){.wpr-menuItem{width:57px;height:50px;padding:0}}.wpr-menuItem:before{position:absolute;top:calc(50% - 12px);right:18px;text-align:center;font-size:1.4375rem;line-height:1;color:#121116;opacity:0.4;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-menuItem:hover,.wpr-menuItem.isActive{color:#121116;background:#fff;border-left:2px solid #F56640}.wpr-menuItem:hover .wpr-menuItem-title,.wpr-menuItem.isActive .wpr-menuItem-title{color:#F56640}.wpr-menuItem:hover:before,.wpr-menuItem.isActive:before{color:#F56640;opacity:1}.wpr-menuItem:focus{color:#121116}.wpr-menuItem:focus:before{color:#121116}.wpr-menuItem-title{font-size:.8125rem;line-height:1.46154;font-weight:bold;letter-spacing:-0.08px;text-transform:uppercase;color:#121116}@media (max-width: 783px){.wpr-menuItem-title{display:none !important}}.wpr-menuItem-description{margin-top:2px;color:#72777C;font-size:.8125rem;line-height:1.23077;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}@media (max-width: 783px){.wpr-menuItem-description{display:none}}.wpr-menuItem.wpr-subMenuItem{display:none;padding:10px 20px 8px 25px}@media (max-width: 783px){.wpr-menuItem.wpr-subMenuItem{padding:8px 20px 8px 23px;height:35px}}.wpr-menuItem.wpr-subMenuItem .wpr-menuItem-title{display:inline-block;font-size:.8125rem;line-height:1.84615;text-transform:inherit;font-weight:600}.wpr-menuItem.wpr-subMenuItem:before{position:relative;display:inline-block;top:2px;right:2px;margin-right:8px;font-size:1rem;line-height:1}#wpr-nav-cache:before{right:20px}#wpr-nav-tools:before{right:20px}.wpr-sectionHeader{position:relative;border-bottom:1px solid #E0E4E9;padding-bottom:24px}.wpr-sectionHeader:before{content:'';position:absolute;display:block;width:48px;height:2px;bottom:-1px;left:0;background:#F56640}.wpr-sectionHeader .wpr-title1{line-height:48px}.wpr-sectionHeader .wpr-title1:before{display:inline-block;width:48px;height:48px;margin-right:24px;background:#FDE0D9;color:#F56640;text-align:center;border-radius:3px}.wpr-sectionHeader-title{margin-top:8px;padding-left:72px}.wpr-sectionHeader-description{color:#666;margin-top:8px;padding-left:72px}.wpr-sectionHeader-logo{vertical-align:top;margin-right:24px}.wpr-optionHeader{position:relative;display:flex;justify-content:space-between;margin-top:48px;padding-bottom:9px;border-bottom:1px solid #E0E4E9}.wpr-optionHeader .wpr-title2{line-height:24px;color:#F56640;padding-right:40px}.wpr-optionHeader .wpr-infoAction{margin-right:8px}.wpr-optionHeader.wpr-isHidden{display:none}.wpr-fieldsContainer{margin-top:8px}.wpr-fieldsContainer-description{color:#666}.wpr-fieldsContainer-description a:hover,.wpr-fieldsContainer-description a:focus{color:#1EADBF}.wpr-fieldsContainer-fieldset{margin-top:16px;background:#F9FAFB;padding:16px;border:1px solid #E8EBEE;border-radius:2px}.wpr-fieldsContainer-fieldset--split{display:flex}.wpr-fieldsContainer-fieldset--split .wpr-field+.wpr-field{border:none}.wpr-fieldsContainer-fieldset--split .wpr-field{flex:0 0 50%;padding:0}.wpr-fieldsContainer-fieldset--split .wpr-field:first-child{padding-right:15px}.wpr-fieldsContainer-fieldset--split .wpr-field:last-child{padding-left:15px}.wpr-fieldsContainer-helper{margin-top:16px;color:#D60E5B;font-weight:500}.wpr-fieldsContainer-helper:before{position:relative;top:3px;font-size:1.125rem;line-height:1;margin-right:4px}.wpr-fieldsContainer.wpr-isHidden{display:none}.wpr-infoAction{position:relative;height:24px;font-size:.8125rem;line-height:1.84615;vertical-align:middle;letter-spacing:-0.03em;font-weight:500;color:#666;white-space:nowrap;text-decoration:none;transition:all 200ms ease-out;-webkit-transition:all 200ms ease-out}.wpr-infoAction:before{position:absolute;margin-left:-26px;font-size:1.125rem;line-height:1.33333;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}.wpr-infoAction--help{text-transform:uppercase;color:#02707F;font-weight:bold;font-size:.75rem;line-height:2;letter-spacing:0}@media (max-width: 783px){.wpr-infoAction--help{display:none}}.wpr-infoAction--help:before{color:#1EADBF}.wpr-infoAction:hover,.wpr-infoAction:focus{color:#F56640;outline:none}.wpr-infoAction:hover:before,.wpr-infoAction:focus:before{color:#FFA58B}.wpr-button{position:relative;display:inline-block;width:auto;padding:8px 24px;text-align:center;background:#F56640;box-shadow:0 4px 6px rgba(50,50,93,0.11),0 1px 3px rgba(0,0,0,0.08);text-transform:uppercase;text-decoration:none;letter-spacing:-0.08px;font-weight:bold;border-radius:4px;color:#fff !important;white-space:nowrap;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:all 200ms ease-out;-webkit-transition:all 200ms ease-out;font-size:.8125rem;line-height:1.53846}.wpr-button:hover,.wpr-button:focus{color:#fff !important;transform:translateY(-2px);box-shadow:0 7px 14px rgba(50,50,93,0.25),0 3px 6px rgba(0,0,0,0.2)}.wpr-button--small{padding:5px 0;letter-spacing:-0.08px;font-size:.6875rem;line-height:1.81818}.wpr-button--icon{min-width:160px;padding-left:8px;padding-right:40px;text-align:left}.wpr-button--icon:before{position:absolute;right:8px;font-size:.9375rem;line-height:1.33333}.wpr-button--fixed{position:fixed;display:flex;padding:8px 16px;right:24px;bottom:32px;border-radius:16px}.wpr-button--fixed:before{font-size:1.125rem;line-height:1;margin-right:8px}.wpr-button--purple{background:#2D1656}.wpr-button--blue{min-width:inherit;background:#1EADBF}.wpr-button--lightBlue{min-width:inherit;background:#40BACB}.wpr-button--red{background:#D33F49}.wpr-button--blueDark{background:#02707F}.wpr-button:focus{outline:none;color:#fff !important}.wpr-field{padding:16px 0;transition:opacity 150ms ease-out;-webkit-transition:opacity 150ms ease-out}.wpr-field+.wpr-field,.wpr-field+.wpr-warningContainer{border-top:1px solid #E0E4E9}.wpr-field:first-child{padding-top:0}.wpr-field:last-child{padding-bottom:0}.wpr-field-description{margin-top:4px;color:#666;font-size:.8125rem;line-height:1.53846}.wpr-field-description .wpr-js-popin{color:#444;text-decoration:underline}.wpr-field-description .wpr-js-popin:hover,.wpr-field-description .wpr-js-popin:focus{color:#1EADBF}.wpr-field-description a:hover,.wpr-field-description a:focus{color:#1EADBF}.wpr-field-description-helper{color:#00A66B}.wpr-field-description-label{font-size:.875rem;line-height:1.42857;font-weight:500;color:#666}.wpr-field-list{margin:0;color:#666;font-weight:500}.wpr-field-list li+li{margin-top:16px}.wpr-field-list li:before{position:relative;top:3px;margin-right:8px;color:#02707F;font-size:1.125rem;line-height:1.11111}.wpr-field-list a{text-decoration:none}.wpr-field-list a:hover,.wpr-field-list a:focus{color:#1EADBF}.wpr-field-betweenText{margin:0 16px;font-weight:bold}.wpr-field .wpr-button{margin:8px 0}.wpr-field .wpr-flex{display:flex;justify-content:space-between;align-items:center}@media (max-width: 783px){.wpr-field .wpr-flex{text-align:left;flex-direction:column}}.wpr-field .wpr-flex--egal>div{flex:0 0 50%}@media (max-width: 783px){.wpr-field .wpr-flex--egal>div{width:100%}}.wpr-field .wpr-flex--egal>div:last-child{text-align:right}@media (max-width: 783px){.wpr-field .wpr-flex--egal>div:last-child{text-align:left}}.wpr-field .wpr-flex--egal>div .wpr-field-description{font-style:normal;color:#666}.wpr-field p{margin-bottom:0}.wpr-field label{font-weight:500}.wpr-field h4{font-size:.875rem;line-height:1.71429}.wpr-field.wpr-isDisabled{opacity:0.55}.wpr-field.wpr-isParent{padding-bottom:0}.wpr-field.wpr-Delayjs{margin-top:16px}.wpr-field.wpr-isLastElem{margin-top:16px}.wpr-field.wpr-isHidden{display:none}.wpr-field .wpr-isHidden{display:none}.wpr-field--children{display:none;padding-left:32px}.wpr-field--children.wpr-isOpen{display:block;margin-top:16px}.wpr-field--children.wpr-field--textarea{padding-right:80px}@media (max-width: 1239px){.wpr-field--children.wpr-field--textarea{padding-right:32px}}@media (max-width: 783px){.wpr-field--children.wpr-field--textarea{padding-right:0}}.wpr-field--checkbox .wpr-field-description{margin-left:32px}.wpr-field--radio{padding:24px 16px}.wpr-field--radio:first-child{padding-top:8px}.wpr-field--radio:last-child{padding-bottom:8px}.wpr-field--radio .wpr-field-description{margin-left:88px}.wpr-field--radio .wpr-field-description button{color:#666}.wpr-field--split{display:inline-block;width:50%;padding-right:16px;padding-bottom:0}.wpr-field--split+.wpr-field--split{padding-left:16px;padding-right:0}.wpr-field--split+.wpr-field--split:nth-child(2){padding-top:0;border-top:none}.wpr-field--cache .wpr-field--number,.wpr-field--cache .wpr-field--select{display:inline-block;padding-top:0;width:auto;padding-bottom:0;font-weight:bold}.wpr-field--cache .wpr-field--select{position:relative;padding-left:8px;top:-2px;border-top:none}.wpr-field--cache .wpr-field--number .wpr-text input[type=number]{background:#F2F3F6;height:35px;border:1px solid #E0E4E9;font-family:inherit;font-size:1em}.wpr-field--cache .wpr-field-description{margin:8px 0;color:#00A66B}.wpr-field--cache .wpr-field-description-label{color:#121116}.wpr-fieldWarning{display:none;position:relative;padding:16px 16px 24px 56px;background:#19073B;margin:8px 0 0;color:#fff}.wpr-fieldWarning.wpr-isOpen{display:block}.wpr-fieldWarning:after{content:'';position:absolute;display:block;top:-8px;left:20px;width:0;height:0;border-style:solid;border-width:0 12px 8px 12px;border-color:transparent transparent #19073B transparent}.wpr-fieldWarning:before{content:'';position:absolute;display:block;width:calc(100% + 32px);height:100%;top:0;left:-16px;background:#19073B}.wpr-fieldWarning-title{position:relative;color:#F56640;font-size:.875rem;line-height:1.42857;font-weight:bold}.wpr-fieldWarning-title:before{position:absolute;left:-36px;font-size:1.5rem;line-height:.83333}.wpr-fieldWarning-description{position:relative;margin-top:8px}.wpr-fieldWarning .wpr-button{margin-top:16px}.wpr-warningContainer+.wpr-warningContainer,.wpr-warningContainer+.wpr-field,.wpr-field+.wpr-warningContainer{border-top:1px solid #E0E4E9;padding-top:16px}.wpr-documentation{padding:24px 16px;border-radius:4px;color:#fff;text-align:center;background:#40BACB}.wpr-documentation p{margin:8px 0 16px;font-weight:500}.wpr-documentation i{display:block;font-size:2.25rem;line-height:1;margin-bottom:8px}.wpr-documentation .wpr-button{padding-left:16px;padding-right:16px}.wpr-addon{padding:24px 0}.wpr-addon .wpr-flex{align-items:flex-start}@media (max-width: 783px){.wpr-addon .wpr-flex{align-items:center}}.wpr-addon .wpr-flex>div{text-align:left}.wpr-addon .wpr-addon-title{margin-bottom:16px;font-weight:500}.wpr-addon .wpr-field-description{font-style:normal}.wpr-addon .wpr-addon-logo{text-align:center;flex:0 0 160px}@media (max-width: 1239px){.wpr-addon .wpr-addon-logo{max-width:100px}.wpr-addon .wpr-addon-logo img{width:100%;height:auto}}@media (max-width: 1083px){.wpr-addon .wpr-addon-logo{max-width:160px}}@media (max-width: 783px){.wpr-addon .wpr-addon-logo{flex:0 0 auto;margin-bottom:16px}}.wpr-addon .wpr-addon-text{margin-left:32px;flex:1 1 auto}@media (max-width: 1239px){.wpr-addon .wpr-addon-text{margin-left:16px}}@media (max-width: 1083px){.wpr-addon .wpr-addon-text{margin-left:32px}}@media (max-width: 783px){.wpr-addon .wpr-addon-text{margin-left:0}}.wpr-addon .wpr-addon-text a{display:inline-block;margin-top:24px}.wpr-addon .wpr-addon-text .button{margin-top:24px}.wpr-notice{position:relative;color:#444;background:#EBFAF5 url("../img/bg-activated.svg") no-repeat 90% bottom;background-size:350px;margin-top:24px;border-radius:4px;overflow:hidden}.wpr-notice-container{padding:24px 25% 24px 40px}.wpr-notice-supTitle{font-size:1rem;line-height:1.375;font-weight:bold}.wpr-notice-title{font-size:1.5rem;line-height:1.33333;color:#3ECE9D;margin-top:16px;font-weight:bold}.wpr-notice-description{font-size:.875rem;line-height:1.57143;margin:16px 0 24px}.wpr-notice-continue{color:#666}.wpr-notice-close{position:absolute;top:24px;right:24px;color:#666;text-decoration:none;font-size:1.5rem;line-height:1;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}.wpr-notice-close:hover{color:#444}.wpr-notice-close:focus{outline:none}.wpr-tools{position:relative;display:flex;flex-direction:row;padding:32px 0}@media (max-width: 1239px){.wpr-tools{flex-direction:column}}@media (max-width: 1083px){.wpr-tools{flex-direction:row}}@media (max-width: 783px){.wpr-tools{flex-direction:column}}.wpr-tools:nth-child(2){margin-top:16px}.wpr-tools+.wpr-tools{border-top:1px solid #E0E4E9}.wpr-tools-label{display:block}.wpr-tools-label:before{position:absolute;left:0;margin-top:5px;font-size:2.25rem;line-height:1;color:#F56640}.wpr-tools-col{flex:1 1 auto}.wpr-tools-col:first-child{padding-left:72px;padding-right:24px;min-width:340px}.wpr-tools-col:last-child{text-align:right}@media (max-width: 783px){.wpr-tools-col:last-child{text-align:left}}.wpr-tools .wpr-button{margin-top:24px;white-space:normal}.wpr-tools .wpr-field-description{font-style:normal;color:#666}.wpr-imagify{display:flex;justify-content:space-between;flex-wrap:wrap;margin-top:30px}.wpr-imagify-description{width:calc(100% / 3 * 1);padding-right:60px}@media (max-width: 1239px){.wpr-imagify-description{width:auto;padding-right:0}}.wpr-imagify-screenshot{width:calc(100% / 3 * 2)}@media (max-width: 1239px){.wpr-imagify-screenshot{margin-top:60px;width:auto}}.wpr-imagify-screenshot img{max-width:100%;height:auto}.wpr-imagify-more,.wpr-imagify-name{color:#00a8dc;font-weight:700;margin-bottom:0}.wpr-imagify-more::before{content:'\2713';color:#000;font-size:2rem;margin-right:5px}.wpr-imagify p{font-size:1rem}.wpr-imagify p:first-child{margin-top:0}.wpr-imagify ul{margin-top:0;margin-left:40px;list-style-type:'>'}.wpr-imagify li{padding-left:7px}.wpr-imagify a{text-decoration:none}.wpr-imagify a:hover{color:#00a8dc}.wpr-imagify .button-primary{background:#2abb9b;border:1px solid #bebebe;box-shadow:none;font-size:1rem;font-weight:700;height:auto;line-height:1;margin-top:60px;padding:20px 45px;text-shadow:none;text-transform:uppercase}.wpr-tutorials-section{display:flex;flex-flow:row wrap;justify-content:space-between}div.wpr-tutorial-item{width:calc( 96% / 3);margin-bottom:10px}.wpr-tutorial-link{cursor:pointer;transition:color 200ms ease-out}.wpr-tutorial-link:hover{color:#1EADBF}@media (max-width: 1083px){div.wpr-tutorial-item{width:calc( 96% / 2)}}@media (max-width: 783px){div.wpr-tutorial-item{width:100%}}.wpr-rocketcdn-modal{display:none}.wpr-rocketcdn-modal.is-open{display:block}.wpr-rocketcdn-modal__overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.6);display:flex;justify-content:center;align-items:center}.wpr-rocketcdn-modal__container{max-width:674px;max-height:100vh;overflow-y:auto;box-sizing:border-box}.wpr-rocketcdn-modal iframe{max-width:100%}.wpr-checkbox{position:relative;padding-left:32px}.wpr-checkbox label{user-select:none}.wpr-checkbox [type="checkbox"]:not(:checked),.wpr-checkbox [type="checkbox"]:checked{position:absolute;left:-9999px}.wpr-checkbox [type="checkbox"]:not(:checked)+label:before,.wpr-checkbox [type="checkbox"]:checked+label:before{content:'';position:absolute;left:0;top:4px;width:14px;height:14px;border:2px solid #444;border-radius:3px;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-checkbox [type="checkbox"]:not(:checked)+label:after,.wpr-checkbox [type="checkbox"]:checked+label:after{content:"\e921";position:absolute;top:5px;left:2px;color:#fff;font-family:'wpr-icomoon';speak:none;font-size:.875rem;line-height:1.28571;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-checkbox [type="checkbox"]:not(:checked)+label:after{opacity:0;transform:scale(2)}.wpr-checkbox [type="checkbox"]:checked+label:after{opacity:1;transform:scale(1)}.wpr-checkbox [type="checkbox"]:checked+label:before{background:#19073B;border-color:#19073B}.wpr-checkbox [type="checkbox"]:checked:focus+label:before{background:#665090;border:2px dotted #665090}.wpr-checkbox [type="checkbox"]:focus+label:before{border:2px dotted #444}.wpr-radio{position:relative;padding-left:88px}.wpr-radio label{user-select:none;font-weight:bold}.wpr-radio [type="checkbox"]:not(:checked),.wpr-radio [type="checkbox"]:checked{position:absolute;left:-9999px}.wpr-radio [type="checkbox"]:not(:checked)+label:before,.wpr-radio [type="checkbox"]:checked+label:before,.wpr-radio [type="checkbox"]:not(:checked)+label:after,.wpr-radio [type="checkbox"]:checked+label:after{content:'';position:absolute}.wpr-radio [type="checkbox"]:not(:checked)+label:before,.wpr-radio [type="checkbox"]:checked+label:before{left:0;width:52px;height:22px;background:#fff;border-radius:12px;border:1px solid #444;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-radio [type="checkbox"]:not(:checked)+label:after,.wpr-radio [type="checkbox"]:checked+label:after{width:18px;height:18px;border-radius:100%;background:#444;top:3px;left:3px;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-radio [type="checkbox"]:checked+label:before{border-color:#1EADBF}.wpr-radio [type="checkbox"]:checked+label:after{background:#1EADBF;left:33px}.wpr-radio [type="checkbox"]:checked+label .wpr-radio-ui,.wpr-radio [type="checkbox"]:not(:checked)+label .wpr-radio-ui:before,.wpr-radio [type="checkbox"]:checked+label .wpr-radio-ui:after{position:absolute;left:4px;width:52px;text-transform:uppercase;letter-spacing:-0.01em;font-weight:bold;font-size:.6875rem;line-height:2.18182;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-radio [type="checkbox"]:not(:checked)+label .wpr-radio-ui:before{content:attr(data-l10n-inactive);left:27px;color:#666}.wpr-radio [type="checkbox"]:checked+label .wpr-radio-ui:after{content:attr(data-l10n-active);color:#02707F}.wpr-radio--reverse{padding-right:72px;padding-left:0}.wpr-radio--reverse [type="checkbox"]:not(:checked)+label:before,.wpr-radio--reverse [type="checkbox"]:checked+label:before{right:0;left:inherit}.wpr-radio--reverse [type="checkbox"]:not(:checked)+label:after,.wpr-radio--reverse [type="checkbox"]:checked+label:after{right:33px;left:inherit}.wpr-radio--reverse [type="checkbox"]:checked+label:after{right:3px;left:inherit}.wpr-radio--reverse [type="checkbox"]:checked+label .wpr-radio-ui,.wpr-radio--reverse [type="checkbox"]:not(:checked)+label .wpr-radio-ui:before,.wpr-radio--reverse [type="checkbox"]:checked+label .wpr-radio-ui:after{right:-2px;left:inherit}.wpr-radio--reverse [type="checkbox"]:not(:checked)+label .wpr-radio-ui:before{right:-25px;left:inherit}.wpr-radio [type="checkbox"]:not(:checked):focus+label:before{border:1px dashed #444}.wpr-radio [type="checkbox"]:checked:focus+label:before{border:1px dashed #1EADBF}.wpr-radio--tips [type="checkbox"]:checked+label:before{border-color:#3ECE9D}.wpr-radio--tips [type="checkbox"]:checked+label:after{background:#3ECE9D}.wpr-radio--tips [type="checkbox"]:checked+label .wpr-radio-ui:after{color:#00A66B}.wpr-radio--tips [type="checkbox"]:checked:focus+label:before{border:1px dashed #3ECE9D}.wpr-select{position:relative}.wpr-select select{margin:0;padding:0 8px;height:36px;border:1px solid #E0E4E9;background:#F2F3F6;color:#121116;box-shadow:none;border-radius:0;letter-spacing:0.011em}.wpr-select select:focus{outline:none;border-color:#444;box-shadow:none}.wpr-select label{font-weight:bold;margin-left:8px}.wpr-textarea{margin-top:8px}.wpr-textarea textarea{padding:8px;width:100%;height:100px;font-family:Monaco;color:#121116;background:#fff;border:2px solid #c2cad4;border-radius:3px;font-size:.8125rem;line-height:1.23077;transition:border 200ms ease-out;-webkit-transition:border 200ms ease-out}.wpr-textarea textarea:focus{outline:none;border-color:#444;box-shadow:none}.wpr-textarea #delay_js_scripts{height:200px}.wpr-textarea+.wpr-field-description{color:#00A66B}.wpr-text label{color:#666}.wpr-text input[type=text],.wpr-text input[type=number]{margin-top:8px;padding:0 8px;width:100%;height:32px;color:#121116;background:#fff;border:2px solid #c2cad4;border-radius:3px;font-family:Monaco;font-size:.75rem;line-height:1.33333;transition:border 200ms ease-out;-webkit-transition:border 200ms ease-out}.wpr-text input[type=text]:focus,.wpr-text input[type=number]:focus{outline:none;border-color:#444;box-shadow:none}.wpr-text input[type=text].wpr-isError,.wpr-text input[type=number].wpr-isError{border-color:#D33F49}.wpr-text input[type=number]{width:80px}.wpr-text--number label{margin-right:8px}.wpr-upload input[type=file]{display:block;width:252px;margin:8px 8px 8px 0;padding:8px;border:1px solid #E0E4E9;background:#F2F3F6;color:#121116;font-size:.6875rem;line-height:1.45455}.wpr-upload input[type=file]:focus{outline:none;border-color:#444;box-shadow:none}.wpr-multiple{display:flex;align-items:center;flex-wrap:wrap}@media (max-width: 783px){.wpr-multiple{align-items:center;flex-direction:column}}.wpr-multiple .wpr-text{flex:1 1 auto;position:relative;top:-2px}@media (max-width: 783px){.wpr-multiple .wpr-text{width:100%}}.wpr-multiple .wpr-button{margin-left:16px;width:auto;min-width:inherit;padding-right:30px}@media (max-width: 783px){.wpr-multiple .wpr-button{margin-left:0}}.wpr-multiple input[type=text]{flex-grow:2}.wpr-multiple select{height:30px}.wpr-multiple-default{margin-right:20px}.wpr-multiple-list{display:none;padding:8px 0;margin:16px 0 0;background:#F2F3F6;border-radius:2px}.wpr-multiple-list li{margin-bottom:0;padding:4px 16px;font-size:.8125rem;line-height:1.23077;font-family:Monaco}.wpr-multiple-list li span{display:inline-block;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-multiple-close{position:relative;top:3px;font-size:1rem;line-height:1;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}.wpr-multiple-close:focus{outline:none}.wpr-multiple-close:hover,.wpr-multiple-close:focus{color:#D33F49}.wpr-multiple-close:hover+span,.wpr-multiple-close:focus+span{color:#D33F49} +@charset "UTF-8"; +/*-----------------------------------------------*\ + +Author: Thomas Geisen (www.thomasgeisen.fr) +Method : SUITCSS (modified) + +.ComponentName => Name of component (Ex : .SiteHeader) +.ComponentName--modifierName => Modifier of component (.SiteHeader--white, .SiteHeader--fixed) +.ComponentName-descendantName => Children of componant (.SiteHeader-logo, .SiteHeader-menu) +.ComponentName.isState => State of component (.isActive, .isOpen) + +More informations here : https://suitcss.github.io/ or http://www.alsacreations.com/article/lire/1641-bonnes-pratiques-en-css-bem-et-oocss.html (french) + +--- EVERY CLASS are prefixed with "wpr-" + +\*-----------------------------------------------*/ +h1, +h2, +h3, +h4 { + color: currentColor; + margin: 0; + font-weight: normal; +} + +button { + padding: 0; + border: none; + background: none; + cursor: pointer; +} + +a { + color: currentColor; + transition: color 200ms ease-out; + -webkit-transition: color 200ms ease-out; +} +a:hover { + color: currentColor; +} + +input[type=submit] { + cursor: pointer; + border: none; +} + +a:active, button:active { + outline: none; +} +a:focus, button:focus { + color: currentColor; + box-shadow: none; +} + +.wpr-wrap { + padding: 16px; + margin: 0 0 0 -20px; +} +@media (max-width: 783px) { + .wpr-wrap { + padding: 0; + margin: 0 0 0 -10px; + } +} + +.wpr-body { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -ms-interpolation-mode: nearest-neighbor; + image-rendering: optimizeQuality; + text-rendering: optimizeLegibility; + display: flex; + color: #121116; + font-size: 0.875rem; + line-height: 1.5; +} + +.wpr-body * { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +@media (max-width: 783px) { + #hs-beacon { + display: none !important; + } +} +.wpr-u-flex { + display: flex; + align-items: center; + justify-content: center; +} + +.wpr-mt-2 { + margin-top: 20px; +} + +.wpr-fs-sm { + font-size: 0.9em; +} + +.wpr-fs-md { + font-size: 1em; +} + +/*-----------------------------------------------*\ + + Icons in a font-icon with icomoon (https://icomoon.io/app) + +\*-----------------------------------------------*/ +@font-face { + font-family: "wpr-icomoon"; + src: url("../fonts/icomoon.eot"); + src: url("../fonts/icomoon.eot?#iefix") format("embedded-opentype"), url("../fonts/icomoon.woff") format("woff"), url("../fonts/icomoon.ttf") format("truetype"), url("../fonts/icomoon.svg#icomoon") format("svg"); + font-weight: normal; + font-style: normal; +} +[class^=wpr-icon-]:before, [class*=" wpr-icon-"]:after, +[class^=wpr-icon-]:after, [class*=" wpr-icon-"]:before, +[id^=wpr-nav-]:before, [id*=" wpr-nav-"]:after, +[id^=wpr-nav-]:after, [id*=" wpr-nav-"]:before { + font-family: "wpr-icomoon"; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +[class^=wpr-icon-] span.hidden, +[class*=" wpr-icon-"] span.hidden { + display: inline-block; + height: 0; + width: 0; + overflow: hidden; +} + +.wpr-icon-chevron-right:before { + content: "\e900"; +} + +.wpr-icon-chevron-left:before { + content: "\e900"; + transform: rotate(180deg); +} + +.wpr-icon-chevron-down:before { + content: "\e901"; + transform: scale(0.6); +} + +.wpr-icon-chevron-up:before { + content: "\e902"; + top: 50%; + transform: translateY(-50%) scale(0.6); +} + +.wpr-icon-rollback:before { + content: "\e903"; +} + +.wpr-icon-addon:before, .wpr-addonSubMenuItem:before { + content: "\e904"; +} + +.wpr-icon-addons:before, #wpr-nav-addons:before { + content: "\e905"; +} + +.wpr-icon-book:before { + content: "\e906"; +} + +.wpr-icon-cdn:before, #wpr-nav-page_cdn:before { + content: "\e907"; +} + +.wpr-icon-database:before, #wpr-nav-database:before { + content: "\e908"; +} + +.wpr-icon-export:before { + content: "\e909"; +} + +.wpr-icon-files:before, #wpr-nav-cache:before { + content: "\e90a"; +} + +.wpr-icon-help:before { + content: "\e90b"; +} + +.wpr-icon-home:before, #wpr-nav-dashboard:before { + content: "\e90c"; +} + +.wpr-icon-import:before { + content: "\e90d"; +} + +.wpr-icon-important:before { + content: "\e90e"; +} + +.wpr-icon-information:before { + content: "\e90f"; +} + +.wpr-icon-information2:before { + content: "\e910"; +} + +.wpr-icon-interrogation:before { + content: "\e911"; +} + +.wpr-icon-media:before, #wpr-nav-media:before { + content: "\e912"; +} + +.wpr-icon-plus:before { + content: "\e913"; +} + +.wpr-icon-refresh:before, #wpr-nav-preload:before { + content: "\e914"; +} + +.wpr-icon-rules:before, #wpr-nav-advanced_cache:before { + content: "\e915"; +} + +.wpr-icon-stack:before, #wpr-nav-file_optimization:before { + content: "\e916"; +} + +.wpr-icon-tools:before, #wpr-nav-tools:before { + content: "\e917"; +} + +.wpr-icon-trash:before { + content: "\e918"; +} + +.wpr-icon-user:before { + content: "\e919"; +} + +.wpr-icon-check:before { + content: "\e920"; +} + +.wpr-icon-check2:before { + content: "\e921"; +} + +.wpr-icon-close:before { + content: "\e922"; +} + +.wpr-icon-heartbeat:before, #wpr-nav-heartbeat:before { + content: url("../img/heartbeat.svg"); +} + +.wpr-icon-heartbeat-hover:before, #wpr-nav-heartbeat.isActive:before, #wpr-nav-heartbeat:hover:before { + content: url("../img/heartbeat-hover.svg"); +} + +.wpr-icon-imagify:before, #wpr-nav-imagify:before { + content: url("../img/imagify.svg"); +} + +.wpr-icon-imagify-hover:before, #wpr-nav-imagify.isActive:before, #wpr-nav-imagify:hover:before { + content: url("../img/imagify-hover.svg"); +} + +.wpr-icon-tutorial:before, #wpr-nav-tutorials:before { + content: url("../img/play.svg"); +} + +.wpr-icon-tutorial-hover:before, #wpr-nav-tutorials.isActive:before, #wpr-nav-tutorials:hover:before { + content: url("../img/play-hover.svg"); +} + +.wpr-icon-tutorial-alt:before { + content: url("../img/play-alt.svg"); +} + +.wpr-imagify-info:before { + content: url("../img/imagify-info.svg"); +} + +.wpr-imagify-install:before { + content: url("../img/imagify-install.svg"); +} + +.wpr-title1 { + font-size: 1.625rem; + line-height: 1; + font-weight: 600; + letter-spacing: 0.01em; +} + +.wpr-title2 { + font-size: 1rem; + line-height: 1.5; + font-weight: bold; + letter-spacing: -0.02em; +} + +.wpr-title3, .wpr-select label, .wpr-select select, .wpr-field--radio label { + font-size: 0.875rem; + line-height: 1.7142857143; + font-weight: bold; + letter-spacing: -0.011em; +} + +/*-----------------------------------------------*\ + + Header / Navigation (left bar) + +\*-----------------------------------------------*/ +.wpr-Header { + display: flex; + flex-direction: column; + flex: 0 0 225px; +} +@media (max-width: 783px) { + .wpr-Header { + flex: 0 0 50px; + } +} +.wpr-Header-logo { + padding: 32px 0 24px; + text-align: center; +} +@media (max-width: 783px) { + .wpr-Header-logo { + padding: 16px 0 8px; + } +} +@media (max-width: 783px) { + .wpr-Header-logo-desktop { + display: none; + } +} +.wpr-Header-logo-mobile { + display: none; +} +@media (max-width: 783px) { + .wpr-Header-logo-mobile { + display: inline-block; + } +} +.wpr-Header-footer { + margin-top: auto; + padding: 48px 20px 0; + font-size: 0.6875rem; + line-height: 4.3636363636; + color: #666666; + opacity: 0.6; + font-weight: bold; +} +@media (max-width: 783px) { + .wpr-Header-footer { + display: none; + } +} + +/*-----------------------------------------------*\ + + Sidebar (right) + +\*-----------------------------------------------*/ +.wpr-Sidebar { + position: relative; + display: none; + flex: 0 0 290px; + padding: 24px 16px; +} +@media (max-width: 1239px) { + .wpr-Sidebar { + flex: 0 0 260px; + } +} +@media (max-width: 1083px) { + .wpr-Sidebar { + display: none !important; + } +} +.wpr-Sidebar-title { + margin-bottom: 32px; +} +.wpr-Sidebar-notice { + padding: 8px 16px; + margin-bottom: 16px; + background: #fff; + border: 1px solid #E8EBEE; + border-left: 2px solid #1EADBF; + border-radius: 0 3px 3px 0; + color: #666666; +} +.wpr-Sidebar-notice p { + margin: 0; +} +.wpr-Sidebar-notice-link { + display: inline-block; + margin-top: 8px; + font-size: 0.6875rem; + line-height: 1.8181818182; + color: #02707F; + letter-spacing: -0.05em; + text-transform: uppercase; + text-decoration: none; + font-weight: bold; +} +.wpr-Sidebar-notice-link:hover, .wpr-Sidebar-notice-link:focus { + color: #40BACB; +} +.wpr-Sidebar-info { + padding: 16px; + background: #EBFAF5; + margin-bottom: 16px; + border-radius: 3px; +} +.wpr-Sidebar-info h4 { + padding-left: 48px; + font-weight: 500; +} +.wpr-Sidebar-info p { + margin: 8px 0 0; + font-size: 0.6875rem; + line-height: 1.4545454545; + color: #666666; +} +.wpr-Sidebar-info i { + position: absolute; + display: block; + margin-top: -1px; + width: 40px; + height: 40px; + color: #00A66B; + font-size: 1.0625rem; + line-height: 2.3529411765; + background: #C6F0DE; + border-radius: 3px; + text-align: center; +} + +/*-----------------------------------------------*\ + + Main content of the page + +\*-----------------------------------------------*/ +.wpr-Content { + position: relative; + background: #fff; + padding: 32px 24px; + flex: 1 1 auto; + max-width: 1230px; +} +@media (max-width: 783px) { + .wpr-Content { + padding: 24px 16px; + } +} +.wpr-Content form > input:last-child { + margin-top: 24px; + color: #fff !important; +} +.wpr-Content.isNotFull { + max-width: 960px; +} +.wpr-Content-tips { + position: absolute; + top: 48px; + right: 24px; + font-weight: bold; + color: #666666; +} +@media (max-width: 1083px) { + .wpr-Content-tips { + display: none !important; + } +} + +/*-----------------------------------------------*\ + + Page / section + +\*-----------------------------------------------*/ +.wpr-Page { + margin-bottom: 32px; +} +.wpr-Page-row { + display: flex; + flex-direction: row; +} +@media (max-width: 1239px) { + .wpr-Page-row { + flex-direction: column; + } +} +.wpr-Page-col { + flex: 1 1 auto; +} +.wpr-Page-col--fixed { + margin-left: 24px; + flex: 0 0 325px; +} +@media (max-width: 1239px) { + .wpr-Page-col--fixed { + margin-left: 0; + } +} +.wpr-Page#dashboard #wpr-action-refresh_account:before { + transition: all 200ms ease-out; + opacity: 1; + transform: translateY(0); +} +.wpr-Page#dashboard #wpr-action-refresh_account.wpr-isLoading:before { + animation: loading 1.2s infinite; +} +.wpr-Page#dashboard #wpr-action-refresh_account.wpr-isHidden:before { + opacity: 0; +} +.wpr-Page#dashboard #wpr-action-refresh_account.wpr-isShown:before { + opacity: 1; +} +@keyframes loading { + from { + transform: rotate(0); + } + to { + transform: rotate(360deg); + } +} +.wpr-Page#dashboard .wpr-documentation { + margin-top: 98px; + padding: 43px 16px; +} +@media (max-width: 1239px) { + .wpr-Page#dashboard .wpr-documentation { + margin-top: 40px; + } +} +.wpr-Page#dashboard .wpr-documentation .wpr-button { + margin-top: 8px; +} +.wpr-Page#dashboard .wpr-documentation i { + font-size: 3.375rem; + line-height: 1; +} +.wpr-Page#dashboard .wpr-radio { + padding-left: 72px; +} +.wpr-Page#dashboard .wpr-field--radio { + padding: 16px 8px; +} +.wpr-Page#dashboard .wpr-field--radio:first-child { + padding-top: 0; +} +.wpr-Page#dashboard .wpr-field--radio:last-child { + padding-bottom: 0; +} +.wpr-Page#dashboard .wpr-field--radio .wpr-field-description { + font-style: normal; + color: #666666; + margin-left: 72px; +} +.wpr-Page#dashboard .wpr-field-account { + padding-bottom: 0; +} +.wpr-Page#dashboard .wpr-infoAccount { + font-weight: bold; + margin-left: 8px; + color: #444444; +} +.wpr-Page#dashboard .wpr-infoAccount:before { + content: ""; + position: relative; + display: inline-block; + width: 13px; + height: 13px; + background: #E0E4E9; + border-radius: 50%; + color: #fff; + margin-right: 6px; + text-align: center; + top: 2px; + font-size: 0.5rem; + line-height: 1.625; +} +.wpr-Page#dashboard .wpr-infoAccount.wpr-isValid { + color: #00A66B; +} +.wpr-Page#dashboard .wpr-infoAccount.wpr-isValid:before { + content: "\e920"; + font-family: "wpr-icomoon"; + speak: none; + background: #3ECE9D; + top: -1px; +} +.wpr-Page#dashboard .wpr-infoAccount.wpr-isInvalid { + color: #D60E5B; +} +.wpr-Page#dashboard .wpr-infoAccount.wpr-isInvalid:before { + content: "!"; + font-weight: bold; + font-size: 0.625rem; + line-height: 1.3; + speak: none; + background: #D33F49; + top: -1px; +} +.wpr-Page#dashboard #wpr-account-data:before { + content: none; +} +.wpr-Page#tools #wpr-action-rocket_enable_mobile_cpcss:before { + transition: all 200ms ease-out; + opacity: 1; + transform: translateY(0); +} +.wpr-Page#tools #wpr-action-rocket_enable_mobile_cpcss.wpr-isLoading:before { + animation: loading 1.2s infinite; +} + +/*-----------------------------------------------*\ + + Popin analytics + +\*-----------------------------------------------*/ +.wpr-Popin { + display: none; + position: fixed; + width: 772px; + height: auto; + top: 50%; + left: 50%; + background: #fff; + border-radius: 3px; + transform: translateX(-50%) translateY(-50%); + z-index: 100000; +} +.wpr-Popin-overlay { + display: none; + position: fixed; + opacity: 0; + width: 100%; + height: 100%; + top: 0; + left: 0; + background: rgba(0, 0, 0, 0.8); + z-index: 99999; +} +.wpr-Popin-header { + display: flex; + align-items: center; + justify-content: space-between; + height: 64px; + padding: 0 32px; + background: #2D1656; + color: #fff; + font-weight: 600; +} +.wpr-Popin-close { + color: #665090; + font-size: 1.5rem; + line-height: 1; + transition: color 200ms ease-out; + -webkit-transition: color 200ms ease-out; +} +.wpr-Popin-close:hover, .wpr-Popin-close:focus { + color: #fff; + outline: none; +} +.wpr-Popin-content { + padding: 8px 32px; + color: #666666; +} +.wpr-Popin-flex { + display: flex; + flex-direction: row; + align-items: center; +} +.wpr-Popin-flex div { + margin-left: 32px; +} +.wpr-Popin p { + margin: 16px 0; +} +.wpr-Popin .wp-rocket-data-table { + padding: 12px 24px; + background: #F2F3F6 !important; + border: none; +} +.wpr-Popin .wp-rocket-data-table td { + width: 50%; + color: #121116; + padding: 8px 0; + padding-left: 4px; + border-bottom: 1px solid #c2cad4; +} +.wpr-Popin .wp-rocket-data-table td:not(.column-primary) { + font-family: "Monaco"; + font-size: 0.75rem; + line-height: 1.6666666667; + color: #666666; + letter-spacing: -0.01em; +} +.wpr-Popin .wp-rocket-data-table tr { + background: #F2F3F6; + border-bottom: 1px solid #E0E4E9; +} +.wpr-Popin .wp-rocket-data-table tr:last-child td { + border-bottom: none; +} +.wpr-Popin .wp-rocket-data-table strong { + font-weight: 500; +} +.wpr-Popin .wp-rocket-data-table em { + font-style: normal; +} +.wpr-Popin .wp-rocket-data-table code { + padding: 0; + margin: 0; + background: transparent; +} + +/*-----------------------------------------------*\ + + RocketCDN Banners & CTA + +\*-----------------------------------------------*/ +.wpr-rocketcdn-cta-small { + border-radius: 5px; + margin: 24px 0; + padding: 16px; +} +.wpr-rocketcdn-cta-small.wpr-isHidden { + display: none; +} +.wpr-rocketcdn-cta-small .notice-title { + font-weight: 700; +} +.wpr-rocketcdn-cta-small .wpr-flex { + display: flex; + justify-content: space-between; + align-items: center; +} +@media (max-width: 783px) { + .wpr-rocketcdn-cta-small .wpr-flex { + text-align: start; + flex-direction: column; + } +} + +.wpr-rocketcdn-cta { + margin: 10px 0; + position: relative; +} +.wpr-rocketcdn-cta.wpr-isHidden { + display: none; +} +.wpr-rocketcdn-cta-close { + position: absolute; + top: 16px; + right: 16px; + background: transparent; + border: 0; + color: rgba(255, 255, 255, 0.5); +} +.wpr-rocketcdn-cta-close--no-promo { + position: absolute; + top: 16px; + right: 16px; + background: transparent; + border: 0; + color: rgba(0, 0, 0, 0.5); +} +.wpr-rocketcdn-cta-close--no-promo:before { + content: "✕"; + font-weight: 700; + font-size: 1.5rem; + line-height: 1.3333333333; +} +.wpr-rocketcdn-cta-close:before { + content: "✕"; + color: #121116; + font-weight: 700; + font-size: 1.5rem; + line-height: 1.3333333333; +} +.wpr-rocketcdn-cta .wpr-rocketcdn-promo { + background: #FFD147; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + padding: 16px 48px 16px 16px; +} +.wpr-rocketcdn-cta .wpr-rocketcdn-promo-title { + font-weight: 700; + font-size: 1.5rem; + line-height: 1.3333333333; +} +.wpr-rocketcdn-cta .wpr-rocketcdn-promo-date { + margin: 0; + font-weight: 500; + font-size: 1rem; + line-height: 1.5; +} +.wpr-rocketcdn-cta-subtitle { + color: #444444; + margin-top: 0; + font-size: 0.875rem; + line-height: 1.7142857143; +} +.wpr-rocketcdn-cta-content { + background: #F9FAFB; + border-top: 1px solid #E8EBEE; + border-left: 1px solid #E8EBEE; + border-right: 1px solid #E8EBEE; + padding: 16px; +} +.wpr-rocketcdn-cta-content--no-promo { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + background: #F9FAFB; + border-top: 1px solid #E8EBEE; + border-left: 1px solid #E8EBEE; + border-right: 1px solid #E8EBEE; + padding: 16px; +} +.wpr-rocketcdn-cta .wpr-flex { + display: flex; + justify-content: space-between; + align-items: center; +} +@media (max-width: 783px) { + .wpr-rocketcdn-cta .wpr-flex { + text-align: start; + flex-direction: column; + } +} +.wpr-rocketcdn-cta .wpr-rocketcdn-features { + margin: 0; + padding-right: 16px; +} +@media (max-width: 783px) { + .wpr-rocketcdn-cta .wpr-rocketcdn-features { + border-right: none; + } +} +.wpr-rocketcdn-cta .wpr-rocketcdn-pricing { + background-color: #fff; + align-items: center; + display: flex; + flex-direction: column; + padding: 16px; + padding-bottom: 32px; + width: 33.3333333333%; + max-width: 219px; +} +@media (max-width: 783px) { + .wpr-rocketcdn-cta .wpr-rocketcdn-pricing { + width: auto; + } +} +.wpr-rocketcdn-cta .wpr-rocketcdn-pricing-regular { + color: #72777C; + margin-bottom: 8px; +} +.wpr-rocketcdn-cta .wpr-rocketcdn-pricing .wpr-rocketcdn-cta-billing-detail { + margin-bottom: 16px; + font-size: 1rem; + line-height: 1.375; +} +.wpr-rocketcdn-cta .wpr-rocketcdn-pricing .wpr-rocketcdn-cta-currency-major { + font-weight: 700; + font-size: 3rem; + line-height: 1.1666666667; +} +.wpr-rocketcdn-cta .wpr-rocketcdn-pricing .wpr-rocketcdn-cta-currency-minor { + font-weight: 700; + vertical-align: top; + font-size: 1.5rem; + line-height: 1.3333333333; +} +.wpr-rocketcdn-cta .wpr-rocketcdn-feature { + margin: 24px 0; + min-height: 30px; + padding-left: 62px; + position: relative; +} +.wpr-rocketcdn-cta .wpr-rocketcdn-feature:before { + position: absolute; + top: 50%; + left: 5px; + transform: translateY(-50%); +} +.wpr-rocketcdn-cta .wpr-rocketcdn-bandwidth:before { + content: url(../img/bandwidth.svg); +} +.wpr-rocketcdn-cta .wpr-rocketcdn-configuration:before { + content: url(../img/configuration.svg); +} +.wpr-rocketcdn-cta .wpr-rocketcdn-automatic:before { + content: url(../img/automatic.svg); +} +.wpr-rocketcdn-cta-footer { + color: #121116; + font-weight: 600; + padding: 16px 8px 8px; + font-size: 0.875rem; + line-height: 1.5714285714; +} +.wpr-rocketcdn-cta-footer a { + position: relative; + padding-left: 22px; +} +.wpr-rocketcdn-cta-footer a:before { + content: ""; + position: absolute; + width: 14px; + height: 15px; + background: url("../img/icon-i-circle.svg") no-repeat center center; + top: 3px; + left: 0; +} +.wpr-rocketcdn-cta-promo-footer { + color: #121116; + padding: 16px 8px 8px; + font-size: 0.875rem; + line-height: 1.5714285714; +} + +.wpr-rocketcdn-subscription { + text-align: end; +} +.wpr-rocketcdn-subscription .wpr-rocketcdn-open { + color: #666666; + text-decoration: underline; +} + +/* ----------------------------------------------- *\ + + Rocket Analytics CTA + +/* ----------------------------------------------- */ +.wpr-rocket-analytics-cta.wpr-isHidden { + display: none; +} + +/*-----------------------------------------------*\ + + Upgrade popin + +\*-----------------------------------------------*/ +.wpr-license-upgrade-button { + font-weight: bold; + text-decoration: underline; +} +.wpr-license-upgrade-button:hover { + text-decoration: none; +} + +.wpr-field.wpr-field-account .wpr-flex { + align-items: flex-start; +} + +.wpr-infoAccount-License { + flex: 1 0 60%; + margin-right: 16px; +} + +@media (max-width: 783px) { + .wpr-field.wpr-field-account .wpr-flex > div { + width: 100%; + } +} +.wpr-field.wpr-field-account .wpr-flex > div:last-child { + text-align: right; +} +@media (max-width: 783px) { + .wpr-field.wpr-field-account .wpr-flex > div:last-child { + text-align: left; + } +} + +.wpr-Popin-Upgrade .wpr-Popin-content { + padding-bottom: 32px; +} + +.wpr-Popin-Upgrade .wpr-Popin-flex { + justify-content: space-between; +} + +.wpr-Popin-Upgrade .wpr-Popin-flex > div { + align-items: center; + border: 1px solid #DADADA; + border-radius: 24px; + display: flex; + flex-direction: column; + margin: 0 16px 0 0; + padding: 24px; + text-align: center; + width: 50%; +} +.wpr-Popin-Upgrade .wpr-Popin-flex > div:last-child { + margin-right: 0; +} +@media (max-width: 783px) { + .wpr-Popin-Upgrade .wpr-Popin-flex > div { + margin: 0; + width: 100%; + } +} + +.wpr-Upgrade-Plus .wpr-upgrade-title::before { + content: url(../img/plus.svg); + display: block; + width: 117px; + height: 31px; + top: 0; + position: absolute; + left: 50%; + transform: translateX(-50%); +} + +.wpr-Upgrade-Infinite .wpr-upgrade-title::before { + content: url(../img/infinite.svg); + display: block; + width: 48px; + height: 31px; + top: 0; + position: absolute; + left: 50%; + transform: translateX(-50%); +} + +div.wpr-upgrade-saving { + background: #FFD147; + border-radius: 44px; + color: #121116; + font-weight: bold; + margin: 0 0 24px 0; + padding: 8px 16px; + text-align: center; +} + +.wpr-upgrade-title { + color: #F56F46; + font-size: 1.875rem; + line-height: 1.2; + margin-bottom: 16px; + padding-top: 55px; + position: relative; +} + +div.wpr-upgrade-prices { + color: #121116; + font-size: 3rem; + line-height: 1; + font-weight: bold; + margin: 0 0 16px 0; +} + +.wpr-upgrade-price-symbol { + font-size: 1.875rem; + line-height: 1; + vertical-align: super; +} + +.wpr-upgrade-price-regular { + color: #72777C; + font-size: 1rem; + line-height: 1; + vertical-align: top; +} + +div.wpr-upgrade-websites { + color: #121116; + font-size: 0.875rem; + line-height: 1; + font-weight: bold; + margin: 0 0 24px 0; +} + +.wpr-upgrade-link { + background: #fff; + border: 1px solid #F56F46; + border-radius: 800px; + color: #F56F46; + display: block; + font-size: 1rem; + line-height: 1.125; + font-weight: bold; + padding: 16px 24px; + text-decoration: none; +} +.wpr-upgrade-link:hover { + background: #F56F46; + color: #fff; +} +.wpr-upgrade-link::after { + content: "→"; + font-weight: normal; + margin-left: 8px; +} + +/*-----------------------------------------------*\ + + Promotions banner + +\*-----------------------------------------------*/ +.rocket-promo-banner { + background: #FFD147; + display: flex; + justify-content: space-around; + margin-top: 16px; + padding: 24px; + position: relative; +} +@media (max-width: 783px) { + .rocket-promo-banner { + flex-flow: column; + } +} +.rocket-promo-banner > div { + display: flex; + flex-flow: column; + width: 50%; +} +@media (max-width: 783px) { + .rocket-promo-banner > div { + width: 100%; + } +} + +.rocket-promo-title { + font-weight: bold; + margin-bottom: 24px; +} + +.rocket-promo-discount { + background: #fff; + border-radius: 44px; + display: inline-block; + margin-right: 8px; + padding: 8px 16px; + text-transform: uppercase; +} + +.rocket-promo-message, +.rocket-promo-deal { + font-size: 1rem; + line-height: 1.5; + margin-bottom: 0; +} + +.rocket-promo-deal { + margin-top: 8px; +} + +.rocket-promo-cta-block { + align-items: center; + margin-right: 24px; +} + +.rocket-promo-countdown { + display: flex; + flex-flow: row wrap; + width: 66%; +} +.rocket-promo-countdown > .rocket-countdown-item { + background: #fff; + border-radius: 8px; + flex: 1; + margin-right: 8px; + padding: 8px; + text-align: center; +} +.rocket-promo-countdown > .rocket-countdown-item > .rocket-countdown-value { + display: block; + font-size: 1.5rem; + line-height: 1; + font-weight: bold; +} + +.rocket-promo-cta { + background: #172153; + border-radius: 44px; + color: #fff; + font-weight: bold; + padding: 16px 32px; +} + +/*-----------------------------------------------*\ + + Renewals banner + +\*-----------------------------------------------*/ +.rocket-renewal-banner { + background: #FFD147; + display: flex; + flex-flow: row wrap; + align-items: center; + justify-content: space-evenly; + margin-top: 16px; + padding: 8px; +} + +.rocket-renewal-expired-banner { + background: #FFD147; + margin-top: 16px; + padding: 24px; + position: relative; +} + +.rocket-renewal-expired-banner-container { + display: flex; + justify-content: space-around; +} +@media (max-width: 783px) { + .rocket-renewal-expired-banner-container { + flex-flow: column; + } +} +.rocket-renewal-expired-banner-container > div { + display: flex; + flex-flow: column; + width: 50%; +} +@media (max-width: 783px) { + .rocket-renewal-expired-banner-container > div { + width: 100%; + } +} + +.rocket-renew-message { + margin: 0 16px; +} +.rocket-renew-message > p { + font-size: 0.875rem; + line-height: 1.5; +} + +.rocket-expired-message > p { + font-size: 0.875rem; + line-height: 1.5; + padding-left: 80px; +} + +.rocket-expired-title { + font-size: 1.375rem; + line-height: 1.5; + font-weight: bold; +} +.rocket-expired-title::before { + content: url(../img/warning.svg); + display: inline-block; + height: 48px; + width: 63px; + margin-right: 17px; + vertical-align: middle; +} + +.rocket-expired-cta-container { + justify-content: center; + align-items: center; +} + +.rocket-renew-cta { + display: block; + background: #172153; + border-radius: 44px; + color: #fff; + font-size: 1rem; + line-height: 1.125; + font-weight: bold; + padding: 16px 24px; + text-decoration: none; +} +.rocket-renew-cta:hover, .rocket-renew-cta:active, .rocket-renew-cta:focus { + color: #fff; +} +.rocket-renew-cta::after { + content: "→"; + font-weight: normal; + margin-left: 8px; +} + +/*-----------------------------------------------*\ + + Navigation menu item + +\*-----------------------------------------------*/ +.wpr-menuItem { + position: relative; + display: block; + padding: 16px 44px 18px 20px; + text-decoration: none; + color: #121116; + border-top: 1px solid #E0E4E9; + border-left: 2px solid transparent; + overflow: hidden; + transition: all 100ms ease-out; + -webkit-transition: all 100ms ease-out; +} +@media (max-width: 783px) { + .wpr-menuItem { + width: 57px; + height: 50px; + padding: 0; + } +} +.wpr-menuItem:before { + position: absolute; + top: calc(50% - 12px); + right: 18px; + text-align: center; + font-size: 1.4375rem; + line-height: 1; + color: #121116; + opacity: 0.4; + transition: all 150ms ease-out; + -webkit-transition: all 150ms ease-out; +} +.wpr-menuItem:hover, .wpr-menuItem.isActive { + color: #121116; + background: #fff; + border-left: 2px solid #F56640; +} +.wpr-menuItem:hover .wpr-menuItem-title, .wpr-menuItem.isActive .wpr-menuItem-title { + color: #F56640; +} +.wpr-menuItem:hover:before, .wpr-menuItem.isActive:before { + color: #F56640; + opacity: 1; +} +.wpr-menuItem:focus { + color: #121116; +} +.wpr-menuItem:focus:before { + color: #121116; +} +.wpr-menuItem-title { + font-size: 0.8125rem; + line-height: 1.4615384615; + font-weight: bold; + letter-spacing: -0.08px; + text-transform: uppercase; + color: #121116; +} +@media (max-width: 783px) { + .wpr-menuItem-title { + display: none !important; + } +} +.wpr-menuItem-description { + margin-top: 2px; + color: #72777C; + font-size: 0.8125rem; + line-height: 1.2307692308; + transition: all 150ms ease-out; + -webkit-transition: all 150ms ease-out; +} +@media (max-width: 783px) { + .wpr-menuItem-description { + display: none; + } +} +.wpr-menuItem.wpr-subMenuItem { + display: none; + padding: 10px 20px 8px 25px; +} +@media (max-width: 783px) { + .wpr-menuItem.wpr-subMenuItem { + padding: 8px 20px 8px 23px; + height: 35px; + } +} +.wpr-menuItem.wpr-subMenuItem .wpr-menuItem-title { + display: inline-block; + font-size: 0.8125rem; + line-height: 1.8461538462; + text-transform: inherit; + font-weight: 600; +} +.wpr-menuItem.wpr-subMenuItem:before { + position: relative; + display: inline-block; + top: 2px; + right: 2px; + margin-right: 8px; + font-size: 1rem; + line-height: 1; +} + +#wpr-nav-cache:before { + right: 20px; +} +#wpr-nav-tools:before { + right: 20px; +} +/*-----------------------------------------------*\ + + Section header of the page + +\*-----------------------------------------------*/ +.wpr-sectionHeader { + position: relative; + border-bottom: 1px solid #E0E4E9; + padding-bottom: 24px; +} +.wpr-sectionHeader:before { + content: ""; + position: absolute; + display: block; + width: 48px; + height: 2px; + bottom: -1px; + left: 0; + background: #F56640; +} +.wpr-sectionHeader .wpr-title1 { + line-height: 48px; +} +.wpr-sectionHeader .wpr-title1:before { + display: inline-block; + width: 48px; + height: 48px; + margin-right: 24px; + background: #FDE0D9; + color: #F56640; + text-align: center; + border-radius: 3px; +} +.wpr-sectionHeader-title { + margin-top: 8px; + padding-left: 72px; +} +.wpr-sectionHeader-description { + color: #666666; + margin-top: 8px; + padding-left: 72px; +} +.wpr-sectionHeader-logo { + vertical-align: top; + margin-right: 24px; +} + +/*-----------------------------------------------*\ + + Header of option group + +\*-----------------------------------------------*/ +.wpr-optionHeader { + position: relative; + display: flex; + justify-content: space-between; + margin-top: 48px; + padding-bottom: 9px; + border-bottom: 1px solid #E0E4E9; +} +.wpr-optionHeader .wpr-title2 { + line-height: 24px; + color: #F56640; + padding-right: 40px; +} +.wpr-optionHeader .wpr-infoAction { + margin-right: 8px; +} + +.wpr-optionHeader.wpr-isHidden { + display: none; +} + +/*-----------------------------------------------*\ + + Group of fields (fieldset) + +\*-----------------------------------------------*/ +.wpr-fieldsContainer { + margin-top: 8px; +} +.wpr-fieldsContainer-description { + color: #666666; +} +.wpr-fieldsContainer-description a:hover, +.wpr-fieldsContainer-description a:focus { + color: #1EADBF; +} +.wpr-fieldsContainer-fieldset { + margin-top: 16px; + background: #F9FAFB; + padding: 16px; + border: 1px solid #E8EBEE; + border-radius: 2px; +} +.wpr-fieldsContainer-fieldset--split { + display: flex; +} +.wpr-fieldsContainer-fieldset--split .wpr-field + .wpr-field { + border: none; +} +.wpr-fieldsContainer-fieldset--split .wpr-field { + flex: 0 0 50%; + padding: 0; +} +.wpr-fieldsContainer-fieldset--split .wpr-field:first-child { + padding-right: 15px; +} +.wpr-fieldsContainer-fieldset--split .wpr-field:last-child { + padding-left: 15px; +} +.wpr-fieldsContainer-helper { + margin-top: 16px; + color: #D60E5B; + font-weight: 500; +} +.wpr-fieldsContainer-helper:before { + position: relative; + top: 3px; + font-size: 1.125rem; + line-height: 1; + margin-right: 4px; +} + +.wpr-fieldsContainer.wpr-isHidden { + display: none; +} + +/*-----------------------------------------------*\ + + Link action inside .optionHeader (ex: Need help ?) + +\*-----------------------------------------------*/ +.wpr-infoAction { + position: relative; + height: 24px; + font-size: 0.8125rem; + line-height: 1.8461538462; + vertical-align: middle; + letter-spacing: -0.03em; + font-weight: 500; + color: #666666; + white-space: nowrap; + text-decoration: none; + transition: all 200ms ease-out; + -webkit-transition: all 200ms ease-out; +} +.wpr-infoAction:before { + position: absolute; + margin-left: -26px; + font-size: 1.125rem; + line-height: 1.3333333333; + transition: color 200ms ease-out; + -webkit-transition: color 200ms ease-out; +} +.wpr-infoAction--help { + text-transform: uppercase; + color: #02707F; + font-weight: bold; + font-size: 0.75rem; + line-height: 2; + letter-spacing: 0; +} +@media (max-width: 783px) { + .wpr-infoAction--help { + display: none; + } +} +.wpr-infoAction--help:before { + color: #1EADBF; +} +.wpr-infoAction:hover, .wpr-infoAction:focus { + color: #F56640; + outline: none; +} +.wpr-infoAction:hover:before, .wpr-infoAction:focus:before { + color: #FFA58B; +} + +/*-----------------------------------------------*\ + + Button call to action + +\*-----------------------------------------------*/ +.wpr-button { + position: relative; + display: inline-block; + width: auto; + padding: 8px 24px; + text-align: center; + background: #F56640; + box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08); + text-transform: uppercase; + text-decoration: none; + letter-spacing: -0.08px; + font-weight: bold; + border-radius: 4px; + color: #fff !important; + white-space: nowrap; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + transition: all 200ms ease-out; + -webkit-transition: all 200ms ease-out; + font-size: 0.8125rem; + line-height: 1.5384615385; +} +.wpr-button:hover, .wpr-button:focus { + color: #fff !important; + transform: translateY(-2px); + box-shadow: 0 7px 14px rgba(50, 50, 93, 0.25), 0 3px 6px rgba(0, 0, 0, 0.2); +} +.wpr-button--small { + padding: 5px 0; + letter-spacing: -0.08px; + font-size: 0.6875rem; + line-height: 1.8181818182; +} +.wpr-button--icon { + min-width: 160px; + padding-left: 8px; + padding-right: 40px; + text-align: left; +} +.wpr-button--icon:before { + position: absolute; + right: 8px; + font-size: 0.9375rem; + line-height: 1.3333333333; +} +.wpr-button--fixed { + position: fixed; + display: flex; + padding: 8px 16px; + right: 24px; + bottom: 32px; + border-radius: 16px; +} +.wpr-button--fixed:before { + font-size: 1.125rem; + line-height: 1; + margin-right: 8px; +} +.wpr-button--purple { + background: #2D1656; +} +.wpr-button--blue { + min-width: inherit; + background: #1EADBF; +} +.wpr-button--lightBlue { + min-width: inherit; + background: #40BACB; +} +.wpr-button--red { + background: #D33F49; +} +.wpr-button--gray { + background: #E0E4E9; + color: #121116 !important; +} +.wpr-button--gray:hover, .wpr-button--gray:active, .wpr-button--gray:focus { + color: #121116 !important; +} +.wpr-button--gray.radio-active { + background: #2D1656 !important; + color: #fff !important; +} +.wpr-button--gray.radio-active:hover, .wpr-button--gray.radio-active:active, .wpr-button--gray.radio-active:focus { + color: #fff !important; +} +.wpr-button--blueDark { + background: #02707F; +} +.wpr-button:focus { + outline: none; + color: #fff !important; +} + +/*-----------------------------------------------*\ + + Field container + +\*-----------------------------------------------*/ +.wpr-field { + padding: 16px 0; + transition: opacity 150ms ease-out; + -webkit-transition: opacity 150ms ease-out; +} +.wpr-field + .wpr-field, .wpr-field + .wpr-warningContainer { + border-top: 1px solid #E0E4E9; +} +.wpr-field:first-child { + padding-top: 0; +} +.wpr-field:last-child { + padding-bottom: 0; +} +.wpr-field-description { + margin-top: 4px; + color: #666666; + font-size: 0.8125rem; + line-height: 1.5384615385; +} +.wpr-field-description .wpr-js-popin { + color: #444444; + text-decoration: underline; +} +.wpr-field-description .wpr-js-popin:hover, .wpr-field-description .wpr-js-popin:focus { + color: #1EADBF; +} +.wpr-field-description a:hover, +.wpr-field-description a:focus { + color: #1EADBF; +} +.wpr-field-description-helper { + color: #00A66B; +} +.wpr-field-description-label { + font-size: 0.875rem; + line-height: 1.4285714286; + font-weight: 500; + color: #666666; +} +.wpr-field-list { + margin: 0; + color: #666666; + font-weight: 500; +} +.wpr-field-list li + li { + margin-top: 16px; +} +.wpr-field-list li:before { + position: relative; + top: 3px; + margin-right: 8px; + color: #02707F; + font-size: 1.125rem; + line-height: 1.1111111111; +} +.wpr-field-list a { + text-decoration: none; +} +.wpr-field-list a:hover, .wpr-field-list a:focus { + color: #1EADBF; +} +.wpr-field-betweenText { + margin: 0 16px; + font-weight: bold; +} +.wpr-field .wpr-button { + margin: 8px 0; +} +.wpr-field .wpr-flex { + display: flex; + justify-content: space-between; + align-items: center; +} +@media (max-width: 783px) { + .wpr-field .wpr-flex { + text-align: left; + flex-direction: column; + } +} +.wpr-field .wpr-flex--egal > div { + flex: 0 0 50%; +} +@media (max-width: 783px) { + .wpr-field .wpr-flex--egal > div { + width: 100%; + } +} +.wpr-field .wpr-flex--egal > div:last-child { + text-align: right; +} +@media (max-width: 783px) { + .wpr-field .wpr-flex--egal > div:last-child { + text-align: left; + } +} +.wpr-field .wpr-flex--egal > div .wpr-field-description { + font-style: normal; + color: #666666; +} +.wpr-field p { + margin-bottom: 0; +} +.wpr-field label { + font-weight: 500; +} +.wpr-field h4 { + font-size: 0.875rem; + line-height: 1.7142857143; +} +.wpr-field.wpr-isDisabled { + opacity: 0.55; +} +.wpr-field.wpr-isParent { + padding-bottom: 0; + margin-bottom: 16px; +} +.wpr-field.wpr-Delayjs { + margin-top: 16px; +} +.wpr-field.wpr-RemoveUnUsedCss { + margin-bottom: 0; +} +.wpr-field.wpr-NoPaddingBottom { + padding-bottom: 0; +} +.wpr-field.wpr-isLastElem { + margin-top: 16px; +} +.wpr-field.wpr-isHidden { + display: none; +} +.wpr-field .wpr-isHidden { + display: none; +} +.wpr-field--children { + display: none; + padding-left: 32px; +} +.wpr-field--children.wpr-isOpen { + display: block; +} +.wpr-field--children.wpr-field--textarea { + padding-right: 80px; +} +@media (max-width: 1239px) { + .wpr-field--children.wpr-field--textarea { + padding-right: 32px; + } +} +@media (max-width: 783px) { + .wpr-field--children.wpr-field--textarea { + padding-right: 0; + } +} +.wpr-field--children.no-space { + padding-left: 0; +} +.wpr-field--checkbox .wpr-field-description { + margin-left: 32px; +} +.wpr-field--radio { + padding: 24px 16px; +} +.wpr-field--radio:first-child { + padding-top: 8px; +} +.wpr-field--radio:last-child { + padding-bottom: 8px; +} +.wpr-field--radio .wpr-field-description { + margin-left: 88px; +} +.wpr-field--radio .wpr-field-description button { + color: #666666; +} +.wpr-field--split { + display: inline-block; + width: 50%; + padding-right: 16px; + padding-bottom: 0; +} +.wpr-field--split + .wpr-field--split { + padding-left: 16px; + padding-right: 0; +} +.wpr-field--split + .wpr-field--split:nth-child(2) { + padding-top: 0; + border-top: none; +} +.wpr-field--cache .wpr-field--number, +.wpr-field--cache .wpr-field--select { + display: inline-block; + padding-top: 0; + width: auto; + padding-bottom: 0; + font-weight: bold; +} +.wpr-field--cache .wpr-field--select { + position: relative; + padding-left: 8px; + top: -2px; + border-top: none; +} +.wpr-field--cache .wpr-field--number .wpr-text input[type=number] { + background: #F2F3F6; + height: 35px; + border: 1px solid #E0E4E9; + font-family: inherit; + font-size: 1em; +} +.wpr-field--cache .wpr-field-description { + margin: 8px 0; + color: #00A66B; +} +.wpr-field--cache .wpr-field-description-label { + color: #121116; +} +.wpr-field--textarea .wpr-field-description pre { + background: rgba(0, 0, 0, 0.07); + padding: 1em; + margin: 1em 0 0; + white-space: normal; +} +.wpr-field--textarea .wpr-field-description pre code { + background: transparent; + -webkit-touch-callout: all; + -webkit-user-select: all; + -khtml-user-select: all; + -moz-user-select: all; + -ms-user-select: all; + user-select: all; + color: #121116; +} + +/*-----------------------------------------------*\ + + Field warning + +\*-----------------------------------------------*/ +.wpr-fieldWarning { + display: none; + position: relative; + padding: 16px 16px 24px 56px; + background: #19073B; + margin: 8px 0 0; + color: #fff; +} +.wpr-fieldWarning.wpr-isOpen { + display: block; +} +.wpr-fieldWarning:after { + content: ""; + position: absolute; + display: block; + top: -8px; + left: 20px; + width: 0; + height: 0; + border-style: solid; + border-width: 0 12px 8px 12px; + border-color: transparent transparent #19073B transparent; +} +.wpr-fieldWarning:before { + content: ""; + position: absolute; + display: block; + width: calc(100% + 32px); + height: 100%; + top: 0; + left: -16px; + background: #19073B; +} +.wpr-fieldWarning-title { + position: relative; + color: #F56640; + font-size: 0.875rem; + line-height: 1.4285714286; + font-weight: bold; +} +.wpr-fieldWarning-title:before { + position: absolute; + left: -36px; + font-size: 1.5rem; + line-height: 0.8333333333; +} +.wpr-fieldWarning-description { + position: relative; + margin-top: 8px; +} +.wpr-fieldWarning .wpr-button { + margin-top: 16px; +} +.wpr-fieldWarning.wpr-radio-warning { + margin-left: -32px; +} +.wpr-fieldWarning.wpr-radio-warning:after { + left: 40px; +} + +.wpr-warningContainer + .wpr-warningContainer, +.wpr-warningContainer + .wpr-field, +.wpr-field + .wpr-warningContainer { + border-top: 1px solid #E0E4E9; + padding-top: 16px; +} + +.wpr-warningContainer + .wpr-warningContainer, +.wpr-field + .wpr-warningContainer { + padding-bottom: 16px; +} + +@media only screen and (max-width: 400px) { + .wpr-fieldWarning.wpr-radio-warning { + margin-left: -32px; + } + .wpr-fieldWarning.wpr-radio-warning .wpr-button { + white-space: normal; + padding-right: 32px; + } +} +@media only screen and (max-width: 350px) { + .wpr-radio-buttons { + padding-left: 24px; + } + + .wpr-fieldWarning.wpr-radio-warning { + margin-left: -24px; + padding-left: 30px; + padding-right: 0; + } + .wpr-fieldWarning.wpr-radio-warning .wpr-button { + padding-right: 24px; + } +} +/*-----------------------------------------------*\ + + Documentation + +\*-----------------------------------------------*/ +.wpr-documentation { + padding: 24px 16px; + border-radius: 4px; + color: #fff; + text-align: center; + background: #40BACB; +} +.wpr-documentation p { + margin: 8px 0 16px; + font-weight: 500; +} +.wpr-documentation i { + display: block; + font-size: 2.25rem; + line-height: 1; + margin-bottom: 8px; +} +.wpr-documentation .wpr-button { + padding-left: 16px; + padding-right: 16px; +} + +/*-----------------------------------------------*\ + + Addon style + +\*-----------------------------------------------*/ +.wpr-addon { + padding: 24px 0; +} +.wpr-addon .wpr-flex { + align-items: flex-start; +} +@media (max-width: 783px) { + .wpr-addon .wpr-flex { + align-items: center; + } +} +.wpr-addon .wpr-flex > div { + text-align: left; +} +.wpr-addon .wpr-addon-title { + margin-bottom: 16px; + font-weight: 500; +} +.wpr-addon .wpr-field-description { + font-style: normal; +} +.wpr-addon .wpr-field-helper { + font-size: 0.8125rem; + line-height: 1.5384615385; + color: #666666; + background-color: #E0E4E9; + padding: 8px; + margin: 8px 0; +} +.wpr-addon .wpr-field-helper span.wpr-helper-title { + font-weight: 600; +} +.wpr-addon .wpr-field-helper span.wpr-helper-title::after { + content: "\a"; + white-space: pre; +} +.wpr-addon .wpr-addon-logo { + text-align: center; + flex: 0 0 160px; +} +@media (max-width: 1239px) { + .wpr-addon .wpr-addon-logo { + max-width: 100px; + } + .wpr-addon .wpr-addon-logo img { + width: 100%; + height: auto; + } +} +@media (max-width: 1083px) { + .wpr-addon .wpr-addon-logo { + max-width: 160px; + } +} +@media (max-width: 783px) { + .wpr-addon .wpr-addon-logo { + flex: 0 0 auto; + margin-bottom: 16px; + } +} +.wpr-addon .wpr-addon-text { + margin-left: 32px; + flex: 1 1 auto; +} +@media (max-width: 1239px) { + .wpr-addon .wpr-addon-text { + margin-left: 16px; + } +} +@media (max-width: 1083px) { + .wpr-addon .wpr-addon-text { + margin-left: 32px; + } +} +@media (max-width: 783px) { + .wpr-addon .wpr-addon-text { + margin-left: 0; + } +} +.wpr-addon .wpr-addon-text a { + display: inline-block; + margin-top: 24px; +} +.wpr-addon .wpr-addon-text .button { + margin-top: 24px; +} +.wpr-addon .wpr-addon-text .wpr-add-on-helper { + font-weight: normal; + color: #1eadbf; +} +.wpr-addon .wpr-addon-text .wpr-add-on-helper a { + margin-top: 0; +} + +.wpr-webp-addon .wpr-addon .wpr-addon-text a { + margin-top: 0px; +} + +/*-----------------------------------------------*\ + + Notice for first time on dashboard + +\*-----------------------------------------------*/ +.notice-wpr-warning { + background: #FFD147; + display: flex; + flex-flow: row wrap; + align-items: center; + margin-top: 16px; + padding: 8px 32px; + border: 0; +} +.notice-wpr-warning p:first-child { + font-size: 1rem; + line-height: 1.125; + margin-left: 80px; +} +.notice-wpr-warning p:first-child::before { + content: url(../img/warning.svg); + display: inline-block; + height: 48px; + width: 63px; + margin-right: 17px; + vertical-align: middle; + margin-left: -80px; +} +@media (max-width: 1239px) { + .notice-wpr-warning p:first-child::before { + margin-bottom: -30px; + } +} +.notice-wpr-warning p:last-child { + margin-left: 63px; + flex-basis: 100%; + align-items: center; + justify-content: flex-start; + display: flex; +} +@media (max-width: 783px) { + .notice-wpr-warning p:last-child { + align-content: center; + flex-direction: column; + margin-left: 0; + } +} +.notice-wpr-warning p:last-child a { + margin: 0 16px; +} +@media (max-width: 783px) { + .notice-wpr-warning p:last-child a { + margin: 8px 16px; + } +} +.notice-wpr-warning p:last-child a:first-child { + display: block; + background: #172153; + border-radius: 44px; + color: #fff; + font-size: 1rem; + line-height: 1.125; + font-weight: bold; + padding: 16px 24px; + text-decoration: none; +} +.notice-wpr-warning p:last-child a:first-child:hover, .notice-wpr-warning p:last-child a:first-child:active, .notice-wpr-warning p:last-child a:first-child:focus { + color: #fff; +} +.notice-wpr-warning p:last-child a:first-child::after { + content: "→"; + font-weight: normal; + margin-left: 8px; +} + +.wpr-notice { + position: relative; + color: #444444; + background: #EBFAF5 url("../img/bg-activated.svg") no-repeat 90% bottom; + background-size: 350px; + margin-top: 24px; + border-radius: 4px; + overflow: hidden; +} +.wpr-notice-container { + padding: 24px 25% 24px 40px; +} +.wpr-notice-supTitle { + font-size: 1rem; + line-height: 1.375; + font-weight: bold; +} +.wpr-notice-title { + font-size: 1.5rem; + line-height: 1.3333333333; + color: #3ECE9D; + margin-top: 16px; + font-weight: bold; +} +.wpr-notice-description { + font-size: 0.875rem; + line-height: 1.5714285714; + margin: 16px 0 24px; +} +.wpr-notice-continue { + color: #666666; +} +.wpr-notice-close { + position: absolute; + top: 24px; + right: 24px; + color: #666666; + text-decoration: none; + font-size: 1.5rem; + line-height: 1; + transition: color 200ms ease-out; + -webkit-transition: color 200ms ease-out; +} +.wpr-notice-close:hover { + color: #444444; +} +.wpr-notice-close:focus { + outline: none; +} + +/*-----------------------------------------------*\ + + Tools style + +\*-----------------------------------------------*/ +.wpr-tools { + position: relative; + display: flex; + flex-direction: row; + padding: 32px 0; +} +@media (max-width: 1239px) { + .wpr-tools { + flex-direction: column; + } +} +@media (max-width: 1083px) { + .wpr-tools { + flex-direction: row; + } +} +@media (max-width: 783px) { + .wpr-tools { + flex-direction: column; + } +} +.wpr-tools:nth-child(2) { + margin-top: 16px; +} +.wpr-tools + .wpr-tools { + border-top: 1px solid #E0E4E9; +} +.wpr-tools-label { + display: block; +} +.wpr-tools-label:before { + position: absolute; + left: 0; + margin-top: 5px; + font-size: 2.25rem; + line-height: 1; + color: #F56640; +} +@media (max-width: 783px) { + .wpr-tools-label:before { + display: block; + position: initial; + } +} +.wpr-tools-col { + flex: 1 1 auto; +} +.wpr-tools-col:first-child { + padding-left: 72px; + padding-right: 24px; + min-width: 340px; +} +@media (max-width: 783px) { + .wpr-tools-col:first-child { + padding-left: 0; + padding-right: 0; + min-width: auto; + } +} +.wpr-tools-col:last-child { + text-align: right; +} +@media (max-width: 783px) { + .wpr-tools-col:last-child { + text-align: left; + } +} +.wpr-tools .wpr-button { + margin-top: 24px; + white-space: normal; +} +.wpr-tools .wpr-field-description { + font-style: normal; + color: #666666; +} +.wpr-tools #wpr-update-exclusion-msg { + min-height: 20px; +} + +/*-----------------------------------------------*\ + + Imagify Tab style + +\*-----------------------------------------------*/ +.wpr-imagify { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + margin-top: 30px; +} +.wpr-imagify-description { + width: 40%; + padding-right: 60px; +} +@media (max-width: 1239px) { + .wpr-imagify-description { + width: auto; + padding-right: 0; + } +} +.wpr-imagify-screenshot { + width: 60%; +} +@media (max-width: 1239px) { + .wpr-imagify-screenshot { + margin-top: 60px; + width: auto; + } +} +.wpr-imagify-screenshot img { + max-width: 100%; + height: auto; +} +.wpr-imagify-more, .wpr-imagify-name { + color: #00a8dc; + font-weight: 700; + margin-bottom: 0; +} +.wpr-imagify-more::before { + content: "✓"; + color: #000; + font-size: 2rem; + margin-right: 5px; +} +.wpr-imagify p { + font-size: 1rem; +} +.wpr-imagify p:first-child { + margin-top: 0; +} +.wpr-imagify ul { + margin-top: 40px; +} +.wpr-imagify li { + display: flex; + align-items: flex-start; + margin-bottom: 35px; +} +.wpr-imagify li:before { + width: 24px; + height: 24px; + margin-right: 10px; + flex-shrink: 0; +} +.wpr-imagify li .text { + flex-grow: 1; + display: inline-block; +} +.wpr-imagify a { + text-decoration: none; +} +.wpr-imagify a:hover { + color: #00a8dc; +} +.wpr-imagify .button-primary { + background: #2abb9b; + border: 1px solid #bebebe; + box-shadow: none; + font-size: 1rem; + font-weight: 700; + height: auto; + line-height: 1; + margin-top: 60px; + padding: 20px 45px; + text-shadow: none; + text-transform: uppercase; +} + +.wpr-imagify-plugin-tile { + display: flex; + align-items: center; + width: 100%; + padding: 20px; + background-color: #f9fafb; + margin-top: 20px; + border: 1px solid #ebe9e9; +} +.wpr-imagify-plugin-tile-info { + margin-left: 20px; +} +.wpr-imagify-plugin-tile-info .wpr-star-rating { + display: flex; + align-items: center; +} +.wpr-imagify-plugin-tile-info .star-rating .star { + font-size: 16px; + width: 16px; + height: 13px; +} +.wpr-imagify-plugin-tile-info .num-ratings { + font-size: 13px; + margin-left: 10px; +} +.wpr-imagify-plugin-tile-title { + margin-bottom: 5px; +} +.wpr-imagify-plugin-tile .wpr-button { + margin-left: auto; +} +.wpr-imagify-plugin-tile .wpr-button:before { + margin-right: 5px; +} + +.wpr-tutorials-section { + display: flex; + flex-flow: row wrap; +} + +div.wpr-tutorial-item { + width: 32%; + margin-bottom: 10px; + margin-right: 1%; +} + +.wpr-tutorial-link { + cursor: pointer; + transition: color 200ms ease-out; +} +.wpr-tutorial-link:hover { + color: #1EADBF; +} + +@media (max-width: 1083px) { + div.wpr-tutorial-item { + width: 48%; + } +} +@media (max-width: 783px) { + div.wpr-tutorial-item { + width: 100%; + } +} +/*-----------------------------------------------*\ + + RocketCDN modal style + +\*-----------------------------------------------*/ +.wpr-rocketcdn-modal { + display: none; +} +.wpr-rocketcdn-modal.is-open { + display: block; +} +.wpr-rocketcdn-modal__overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.6); + display: flex; + justify-content: center; + align-items: center; +} +.wpr-rocketcdn-modal__container { + max-width: 674px; + max-height: 100vh; + overflow-y: auto; + box-sizing: border-box; +} +.wpr-rocketcdn-modal iframe { + max-width: 100%; +} + +/*-----------------------------------------------*\ + + Custom checkbox + +\*-----------------------------------------------*/ +.wpr-checkbox { + position: relative; + padding-left: 32px; +} +.wpr-checkbox label { + user-select: none; +} + +.wpr-checkbox [type=checkbox]:not(:checked), +.wpr-checkbox [type=checkbox]:checked { + position: absolute; + left: -9999px; +} + +.wpr-checkbox [type=checkbox]:not(:checked) + label:before, +.wpr-checkbox [type=checkbox]:checked + label:before { + content: ""; + position: absolute; + left: 0; + top: 4px; + width: 14px; + height: 14px; + border: 2px solid #444444; + border-radius: 3px; + transition: all 150ms ease-out; + -webkit-transition: all 150ms ease-out; +} + +.wpr-checkbox [type=checkbox]:not(:checked) + label:after, +.wpr-checkbox [type=checkbox]:checked + label:after { + content: "\e921"; + position: absolute; + top: 5px; + left: 2px; + color: #fff; + font-family: "wpr-icomoon"; + speak: none; + font-size: 0.875rem; + line-height: 1.2857142857; + transition: all 150ms ease-out; + -webkit-transition: all 150ms ease-out; +} + +.wpr-checkbox [type=checkbox]:not(:checked) + label:after { + opacity: 0; + transform: scale(2); +} + +.wpr-checkbox [type=checkbox]:checked + label:after { + opacity: 1; + transform: scale(1); +} + +.wpr-checkbox [type=checkbox]:checked + label:before { + background: #19073B; + border-color: #19073B; +} + +.wpr-checkbox [type=checkbox]:checked:focus + label:before { + background: #665090; + border: 2px dotted #665090; +} + +.wpr-checkbox [type=checkbox]:focus + label:before { + border: 2px dotted #444444; +} + +.wpr-checkbox-warning { + color: #D33F49; + margin-left: 16px; +} + +.wpr-checkbox-warning::before { + margin-right: 8px; +} + +/*-----------------------------------------------*\ + + Custom radio (radio on/off) + +\*-----------------------------------------------*/ +.wpr-radio { + position: relative; + padding-left: 88px; +} +.wpr-radio label { + user-select: none; + font-weight: bold; +} +.wpr-radio [type=checkbox]:not(:checked), +.wpr-radio [type=checkbox]:checked { + position: absolute; + left: -9999px; +} +.wpr-radio [type=checkbox]:not(:checked) + label:before, +.wpr-radio [type=checkbox]:checked + label:before, +.wpr-radio [type=checkbox]:not(:checked) + label:after, +.wpr-radio [type=checkbox]:checked + label:after { + content: ""; + position: absolute; +} +.wpr-radio [type=checkbox]:not(:checked) + label:before, +.wpr-radio [type=checkbox]:checked + label:before { + left: 0; + width: 52px; + height: 22px; + background: #fff; + border-radius: 12px; + border: 1px solid #444444; + transition: all 150ms ease-out; + -webkit-transition: all 150ms ease-out; +} +.wpr-radio [type=checkbox]:not(:checked) + label:after, +.wpr-radio [type=checkbox]:checked + label:after { + width: 18px; + height: 18px; + border-radius: 100%; + background: #444444; + top: 3px; + left: 3px; + transition: all 150ms ease-out; + -webkit-transition: all 150ms ease-out; +} +.wpr-radio [type=checkbox]:disabled + label:after, +.wpr-radio [type=checkbox]:disabled + label:after { + background: #E0E4E9; +} +.wpr-radio [type=checkbox]:disabled + label:before, +.wpr-radio [type=checkbox]:disabled + label:before { + border: 1px solid #E0E4E9; +} +.wpr-radio [type=checkbox]:checked + label:before { + border-color: #1EADBF; +} +.wpr-radio [type=checkbox]:checked + label:after { + background: #1EADBF; + left: 33px; +} +.wpr-radio [type=checkbox]:checked + label .wpr-radio-ui, +.wpr-radio [type=checkbox]:not(:checked) + label .wpr-radio-ui:before, +.wpr-radio [type=checkbox]:checked + label .wpr-radio-ui:after { + position: absolute; + left: 4px; + width: 52px; + text-transform: uppercase; + letter-spacing: -0.01em; + font-weight: bold; + font-size: 0.6875rem; + line-height: 2.1818181818; + transition: all 150ms ease-out; + -webkit-transition: all 150ms ease-out; +} +.wpr-radio [type=checkbox]:not(:checked) + label .wpr-radio-ui:before { + content: attr(data-l10n-inactive); + left: 27px; + color: #666666; +} +.wpr-radio [type=checkbox]:checked + label .wpr-radio-ui:after { + content: attr(data-l10n-active); + color: #02707F; +} +.wpr-radio--reverse { + padding-right: 72px; + padding-left: 0; +} +.wpr-radio--reverse [type=checkbox]:not(:checked) + label:before, +.wpr-radio--reverse [type=checkbox]:checked + label:before { + right: 0; + left: inherit; +} +.wpr-radio--reverse [type=checkbox]:not(:checked) + label:after, +.wpr-radio--reverse [type=checkbox]:checked + label:after { + right: 33px; + left: inherit; +} +.wpr-radio--reverse [type=checkbox]:checked + label:after { + right: 3px; + left: inherit; +} +.wpr-radio--reverse [type=checkbox]:checked + label .wpr-radio-ui, +.wpr-radio--reverse [type=checkbox]:not(:checked) + label .wpr-radio-ui:before, +.wpr-radio--reverse [type=checkbox]:checked + label .wpr-radio-ui:after { + right: -2px; + left: inherit; +} +.wpr-radio--reverse [type=checkbox]:not(:checked) + label .wpr-radio-ui:before { + right: -25px; + left: inherit; +} +.wpr-radio [type=checkbox]:not(:checked):focus + label:before { + border: 1px dashed #444444; +} +.wpr-radio [type=checkbox]:checked:focus + label:before { + border: 1px dashed #1EADBF; +} +.wpr-radio--tips [type=checkbox]:checked + label:before { + border-color: #3ECE9D; +} +.wpr-radio--tips [type=checkbox]:checked + label:after { + background: #3ECE9D; +} +.wpr-radio--tips [type=checkbox]:checked + label .wpr-radio-ui:after { + color: #00A66B; +} +.wpr-radio--tips [type=checkbox]:checked:focus + label:before { + border: 1px dashed #3ECE9D; +} + +/*-----------------------------------------------*\ + + Type = select + +\*-----------------------------------------------*/ +.wpr-select { + position: relative; +} +.wpr-select select { + margin: 0; + padding: 0 8px; + height: 36px; + border: 1px solid #E0E4E9; + background: #F2F3F6; + color: #121116; + box-shadow: none; + border-radius: 0; + letter-spacing: 0.011em; +} +.wpr-select select:focus { + outline: none; + border-color: #444444; + box-shadow: none; +} +.wpr-select select:disabled { + background-image: none; +} +.wpr-select label { + font-weight: bold; + margin-left: 8px; +} + +/*-----------------------------------------------*\ + + Type = textearea + +\*-----------------------------------------------*/ +.wpr-textarea { + margin-top: 8px; +} +.wpr-textarea textarea { + padding: 8px; + width: 100%; + height: 100px; + font-family: Monaco; + color: #121116; + background: #fff; + border: 2px solid #c2cad4; + border-radius: 3px; + font-size: 0.8125rem; + line-height: 1.2307692308; + transition: border 200ms ease-out; + -webkit-transition: border 200ms ease-out; +} +.wpr-textarea textarea:focus { + outline: none; + border-color: #444444; + box-shadow: none; +} +.wpr-textarea + .wpr-field-description { + color: #00A66B; +} + +/*-----------------------------------------------*\ + + Type = text + +\*-----------------------------------------------*/ +.wpr-text label { + color: #666666; +} +.wpr-text input[type=text], +.wpr-text input[type=number] { + margin-top: 8px; + padding: 0 8px; + width: 100%; + height: 32px; + color: #121116; + background: #fff; + border: 2px solid #c2cad4; + border-radius: 3px; + font-family: Monaco; + font-size: 0.75rem; + line-height: 1.3333333333; + transition: border 200ms ease-out; + -webkit-transition: border 200ms ease-out; +} +.wpr-text input[type=text]:focus, +.wpr-text input[type=number]:focus { + outline: none; + border-color: #444444; + box-shadow: none; +} +.wpr-text input[type=text].wpr-isError, +.wpr-text input[type=number].wpr-isError { + border-color: #D33F49; +} +.wpr-text input[type=number] { + width: 80px; +} +.wpr-text--number label { + margin-right: 8px; +} + +/*-----------------------------------------------*\ + + Type = File + +\*-----------------------------------------------*/ +.wpr-upload input[type=file] { + display: block; + width: 252px; + margin: 8px 8px 8px 0; + padding: 8px; + border: 1px solid #E0E4E9; + background: #F2F3F6; + color: #121116; + font-size: 0.6875rem; + line-height: 1.4545454545; +} +.wpr-upload input[type=file]:focus { + outline: none; + border-color: #444444; + box-shadow: none; +} + +/*-----------------------------------------------*\ + + Multiple field + +\*-----------------------------------------------*/ +.wpr-multiple { + display: flex; + align-items: center; + flex-wrap: wrap; +} +@media (max-width: 783px) { + .wpr-multiple { + align-items: center; + flex-direction: column; + } +} +.wpr-multiple .wpr-text { + flex: 1 1 auto; + position: relative; + top: -2px; +} +@media (max-width: 783px) { + .wpr-multiple .wpr-text { + width: 100%; + } +} +.wpr-multiple .wpr-button { + margin-left: 16px; + width: auto; + min-width: inherit; + padding-right: 30px; +} +@media (max-width: 783px) { + .wpr-multiple .wpr-button { + margin-left: 0; + } +} +.wpr-multiple input[type=text] { + flex-grow: 2; +} +.wpr-multiple select { + height: 30px; +} +.wpr-multiple-default { + margin-right: 20px; +} +.wpr-multiple-list { + display: none; + padding: 8px 0; + margin: 16px 0 0; + background: #F2F3F6; + border-radius: 2px; +} +.wpr-multiple-list li { + margin-bottom: 0; + padding: 4px 16px; + font-size: 0.8125rem; + line-height: 1.2307692308; + font-family: Monaco; +} +.wpr-multiple-list li span { + display: inline-block; + transition: all 150ms ease-out; + -webkit-transition: all 150ms ease-out; +} +.wpr-multiple-close { + position: relative; + top: 3px; + font-size: 1rem; + line-height: 1; + transition: color 200ms ease-out; + -webkit-transition: color 200ms ease-out; +} +.wpr-multiple-close:focus { + outline: none; +} +.wpr-multiple-close:hover, .wpr-multiple-close:focus { + color: #D33F49; +} +.wpr-multiple-close:hover + span, .wpr-multiple-close:focus + span { + color: #D33F49; +} + +/*-----------------------------------------------*\ + + Multiple select field + +\*-----------------------------------------------*/ +.wpr-multiple-select .wpr-list { + border: 2px solid #c2cad4; + background-color: #fff; + border-radius: 5px; + padding: 10px; + margin: 8px 0; +} +.wpr-multiple-select .wpr-list .wpr-list-header { + display: flex; + justify-content: space-between; +} +.wpr-multiple-select .wpr-list .wpr-list-header .wpr-multiple-select-exclude_js_ads:before { + font-family: "wpr-icomoon"; + content: "\e9b7"; + padding-right: 8px; +} +.wpr-multiple-select .wpr-list .wpr-list-header .wpr-multiple-select-exclude_js_plugins:before { + font-family: "wpr-icomoon"; + content: "\e991"; + padding-right: 8px; +} +.wpr-multiple-select .wpr-list .wpr-list-header .wpr-multiple-select-exclude_js_themes:before { + font-family: "wpr-icomoon"; + content: "\e927"; + padding-right: 8px; +} +.wpr-multiple-select .wpr-list .wpr-list-header .wpr-list-header-arrow { + width: 15px; + cursor: pointer; + display: flex; + transform: rotate(180deg); +} +.wpr-multiple-select .wpr-list .wpr-list-header h3 { + font-weight: 500; + color: #121116; + font-size: 0.875rem; + line-height: 1.5; +} +.wpr-multiple-select .wpr-list .wpr-list-body { + display: none; +} +.wpr-multiple-select .wpr-list .wpr-list-body li { + padding-left: 30px; +} +.wpr-multiple-select .wpr-list .wpr-list-body li .wpr-checkbox img { + width: 15px; +} +.wpr-multiple-select .wpr-list.open .wpr-list-body { + display: block; +} +.wpr-multiple-select .wpr-list.open .wpr-list-body .wpr-checkbox label { + color: #72777C; +} +.wpr-multiple-select .wpr-list.open .wpr-list-body .wpr-checkbox input[checked=checked] + label { + color: #121116; +} +.wpr-multiple-select .wpr-list.open .wpr-list-header { + border-bottom: 1px solid #c2cad4; + margin-bottom: 10px; + padding-bottom: 5px; +} +.wpr-multiple-select .wpr-list.open .wpr-list-header-arrow { + transform: rotate(0deg); +} + +/*-----------------------------------------------*\ + + Type = User Exclusion Textarea + +\*-----------------------------------------------*/ +.wpr-field--categorizedmultiselect .wpr-list { + padding-right: 15px; + padding-left: 15px; +} +.wpr-field--categorizedmultiselect .wpr-list.open .wpr-list-header { + padding-bottom: 9px; + margin-bottom: 10px; +} +.wpr-field--categorizedmultiselect .wpr-list.open .wpr-list-header { + max-height: 32px; +} +.wpr-field--categorizedmultiselect .wpr-list .wpr-list-header { + max-height: 32px; +} +.wpr-field--categorizedmultiselect .wpr-list [type=checkbox] + label:before { + top: 4px; +} +.wpr-field--categorizedmultiselect .wpr-list [type=checkbox]:checked + label:after { + top: 4px; +} +.wpr-field--categorizedmultiselect .wpr-list-header .wpr-checkbox { + padding-left: 29px; +} +.wpr-field--categorizedmultiselect .wpr-list-body { + display: block; + max-height: 250px; + overflow-y: auto; +} +.wpr-field--categorizedmultiselect .wpr-list-body ul { + margin: 0; +} +.wpr-field--categorizedmultiselect .wpr-list-body ul li { + margin-bottom: 10px; +} +.wpr-field--categorizedmultiselect .wpr-list-body ul li .wpr-checkbox { + padding-left: 25px; +} +.wpr-field--categorizedmultiselect .wpr-list-body ul li .wpr-checkbox label { + color: #121116 !important; + font-weight: normal; +} +.wpr-field--categorizedmultiselect .dashicons { + color: #72777c; +} +.wpr-field--categorizedmultiselect .wpr-multiple-select-title { + font-weight: bold; + margin-left: 5px; +} + +@media only screen and (min-width: 782px) { + .wpr-field--categorizedmultiselect { + padding-right: 80px; + } +} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/css/wpr-admin.min.css b/wp-content/plugins/wp-rocket/assets/css/wpr-admin.min.css new file mode 100644 index 000000000..174b9bf9e --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/css/wpr-admin.min.css @@ -0,0 +1 @@ +h1,h2,h3,h4{color:currentColor;margin:0;font-weight:normal}button{padding:0;border:none;background:none;cursor:pointer}a{color:currentColor;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}a:hover{color:currentColor}input[type=submit]{cursor:pointer;border:none}a:active,button:active{outline:none}a:focus,button:focus{color:currentColor;box-shadow:none}.wpr-wrap{padding:16px;margin:0 0 0 -20px}@media(max-width: 783px){.wpr-wrap{padding:0;margin:0 0 0 -10px}}.wpr-body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-interpolation-mode:nearest-neighbor;image-rendering:optimizeQuality;text-rendering:optimizeLegibility;display:flex;color:#121116;font-size:0.875rem;line-height:1.5}.wpr-body *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@media(max-width: 783px){#hs-beacon{display:none !important}}.wpr-u-flex{display:flex;align-items:center;justify-content:center}.wpr-mt-2{margin-top:20px}.wpr-fs-sm{font-size:.9em}.wpr-fs-md{font-size:1em}@font-face{font-family:"wpr-icomoon";src:url("../fonts/icomoon.eot");src:url("../fonts/icomoon.eot?#iefix") format("embedded-opentype"),url("../fonts/icomoon.woff") format("woff"),url("../fonts/icomoon.ttf") format("truetype"),url("../fonts/icomoon.svg#icomoon") format("svg");font-weight:normal;font-style:normal}[class^=wpr-icon-]:before,[class*=" wpr-icon-"]:after,[class^=wpr-icon-]:after,[class*=" wpr-icon-"]:before,[id^=wpr-nav-]:before,[id*=" wpr-nav-"]:after,[id^=wpr-nav-]:after,[id*=" wpr-nav-"]:before{font-family:"wpr-icomoon";speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}[class^=wpr-icon-] span.hidden,[class*=" wpr-icon-"] span.hidden{display:inline-block;height:0;width:0;overflow:hidden}.wpr-icon-chevron-right:before{content:""}.wpr-icon-chevron-left:before{content:"";transform:rotate(180deg)}.wpr-icon-chevron-down:before{content:"";transform:scale(0.6)}.wpr-icon-chevron-up:before{content:"";top:50%;transform:translateY(-50%) scale(0.6)}.wpr-icon-rollback:before{content:""}.wpr-icon-addon:before,.wpr-addonSubMenuItem:before{content:""}.wpr-icon-addons:before,#wpr-nav-addons:before{content:""}.wpr-icon-book:before{content:""}.wpr-icon-cdn:before,#wpr-nav-page_cdn:before{content:""}.wpr-icon-database:before,#wpr-nav-database:before{content:""}.wpr-icon-export:before{content:""}.wpr-icon-files:before,#wpr-nav-cache:before{content:""}.wpr-icon-help:before{content:""}.wpr-icon-home:before,#wpr-nav-dashboard:before{content:""}.wpr-icon-import:before{content:""}.wpr-icon-important:before{content:""}.wpr-icon-information:before{content:""}.wpr-icon-information2:before{content:""}.wpr-icon-interrogation:before{content:""}.wpr-icon-media:before,#wpr-nav-media:before{content:""}.wpr-icon-plus:before{content:""}.wpr-icon-refresh:before,#wpr-nav-preload:before{content:""}.wpr-icon-rules:before,#wpr-nav-advanced_cache:before{content:""}.wpr-icon-stack:before,#wpr-nav-file_optimization:before{content:""}.wpr-icon-tools:before,#wpr-nav-tools:before{content:""}.wpr-icon-trash:before{content:""}.wpr-icon-user:before{content:""}.wpr-icon-check:before{content:""}.wpr-icon-check2:before{content:""}.wpr-icon-close:before{content:""}.wpr-icon-heartbeat:before,#wpr-nav-heartbeat:before{content:url("../img/heartbeat.svg")}.wpr-icon-heartbeat-hover:before,#wpr-nav-heartbeat.isActive:before,#wpr-nav-heartbeat:hover:before{content:url("../img/heartbeat-hover.svg")}.wpr-icon-imagify:before,#wpr-nav-imagify:before{content:url("../img/imagify.svg")}.wpr-icon-imagify-hover:before,#wpr-nav-imagify.isActive:before,#wpr-nav-imagify:hover:before{content:url("../img/imagify-hover.svg")}.wpr-icon-tutorial:before,#wpr-nav-tutorials:before{content:url("../img/play.svg")}.wpr-icon-tutorial-hover:before,#wpr-nav-tutorials.isActive:before,#wpr-nav-tutorials:hover:before{content:url("../img/play-hover.svg")}.wpr-icon-tutorial-alt:before{content:url("../img/play-alt.svg")}.wpr-imagify-info:before{content:url("../img/imagify-info.svg")}.wpr-imagify-install:before{content:url("../img/imagify-install.svg")}.wpr-title1{font-size:1.625rem;line-height:1;font-weight:600;letter-spacing:.01em}.wpr-title2{font-size:1rem;line-height:1.5;font-weight:bold;letter-spacing:-0.02em}.wpr-title3,.wpr-select label,.wpr-select select,.wpr-field--radio label{font-size:0.875rem;line-height:1.7142857143;font-weight:bold;letter-spacing:-0.011em}.wpr-Header{display:flex;flex-direction:column;flex:0 0 225px}@media(max-width: 783px){.wpr-Header{flex:0 0 50px}}.wpr-Header-logo{padding:32px 0 24px;text-align:center}@media(max-width: 783px){.wpr-Header-logo{padding:16px 0 8px}}@media(max-width: 783px){.wpr-Header-logo-desktop{display:none}}.wpr-Header-logo-mobile{display:none}@media(max-width: 783px){.wpr-Header-logo-mobile{display:inline-block}}.wpr-Header-footer{margin-top:auto;padding:48px 20px 0;font-size:0.6875rem;line-height:4.3636363636;color:#666;opacity:.6;font-weight:bold}@media(max-width: 783px){.wpr-Header-footer{display:none}}.wpr-Sidebar{position:relative;display:none;flex:0 0 290px;padding:24px 16px}@media(max-width: 1239px){.wpr-Sidebar{flex:0 0 260px}}@media(max-width: 1083px){.wpr-Sidebar{display:none !important}}.wpr-Sidebar-title{margin-bottom:32px}.wpr-Sidebar-notice{padding:8px 16px;margin-bottom:16px;background:#fff;border:1px solid #e8ebee;border-left:2px solid #1eadbf;border-radius:0 3px 3px 0;color:#666}.wpr-Sidebar-notice p{margin:0}.wpr-Sidebar-notice-link{display:inline-block;margin-top:8px;font-size:0.6875rem;line-height:1.8181818182;color:#02707f;letter-spacing:-0.05em;text-transform:uppercase;text-decoration:none;font-weight:bold}.wpr-Sidebar-notice-link:hover,.wpr-Sidebar-notice-link:focus{color:#40bacb}.wpr-Sidebar-info{padding:16px;background:#ebfaf5;margin-bottom:16px;border-radius:3px}.wpr-Sidebar-info h4{padding-left:48px;font-weight:500}.wpr-Sidebar-info p{margin:8px 0 0;font-size:0.6875rem;line-height:1.4545454545;color:#666}.wpr-Sidebar-info i{position:absolute;display:block;margin-top:-1px;width:40px;height:40px;color:#00a66b;font-size:1.0625rem;line-height:2.3529411765;background:#c6f0de;border-radius:3px;text-align:center}.wpr-Content{position:relative;background:#fff;padding:32px 24px;flex:1 1 auto;max-width:1230px}@media(max-width: 783px){.wpr-Content{padding:24px 16px}}.wpr-Content form>input:last-child{margin-top:24px;color:#fff !important}.wpr-Content.isNotFull{max-width:960px}.wpr-Content-tips{position:absolute;top:48px;right:24px;font-weight:bold;color:#666}@media(max-width: 1083px){.wpr-Content-tips{display:none !important}}.wpr-Page{margin-bottom:32px}.wpr-Page-row{display:flex;flex-direction:row}@media(max-width: 1239px){.wpr-Page-row{flex-direction:column}}.wpr-Page-col{flex:1 1 auto}.wpr-Page-col--fixed{margin-left:24px;flex:0 0 325px}@media(max-width: 1239px){.wpr-Page-col--fixed{margin-left:0}}.wpr-Page#dashboard #wpr-action-refresh_account:before{transition:all 200ms ease-out;opacity:1;transform:translateY(0)}.wpr-Page#dashboard #wpr-action-refresh_account.wpr-isLoading:before{animation:loading 1.2s infinite}.wpr-Page#dashboard #wpr-action-refresh_account.wpr-isHidden:before{opacity:0}.wpr-Page#dashboard #wpr-action-refresh_account.wpr-isShown:before{opacity:1}@keyframes loading{from{transform:rotate(0)}to{transform:rotate(360deg)}}.wpr-Page#dashboard .wpr-documentation{margin-top:98px;padding:43px 16px}@media(max-width: 1239px){.wpr-Page#dashboard .wpr-documentation{margin-top:40px}}.wpr-Page#dashboard .wpr-documentation .wpr-button{margin-top:8px}.wpr-Page#dashboard .wpr-documentation i{font-size:3.375rem;line-height:1}.wpr-Page#dashboard .wpr-radio{padding-left:72px}.wpr-Page#dashboard .wpr-field--radio{padding:16px 8px}.wpr-Page#dashboard .wpr-field--radio:first-child{padding-top:0}.wpr-Page#dashboard .wpr-field--radio:last-child{padding-bottom:0}.wpr-Page#dashboard .wpr-field--radio .wpr-field-description{font-style:normal;color:#666;margin-left:72px}.wpr-Page#dashboard .wpr-field-account{padding-bottom:0}.wpr-Page#dashboard .wpr-infoAccount{font-weight:bold;margin-left:8px;color:#444}.wpr-Page#dashboard .wpr-infoAccount:before{content:"";position:relative;display:inline-block;width:13px;height:13px;background:#e0e4e9;border-radius:50%;color:#fff;margin-right:6px;text-align:center;top:2px;font-size:0.5rem;line-height:1.625}.wpr-Page#dashboard .wpr-infoAccount.wpr-isValid{color:#00a66b}.wpr-Page#dashboard .wpr-infoAccount.wpr-isValid:before{content:"";font-family:"wpr-icomoon";speak:none;background:#3ece9d;top:-1px}.wpr-Page#dashboard .wpr-infoAccount.wpr-isInvalid{color:#d60e5b}.wpr-Page#dashboard .wpr-infoAccount.wpr-isInvalid:before{content:"!";font-weight:bold;font-size:0.625rem;line-height:1.3;speak:none;background:#d33f49;top:-1px}.wpr-Page#dashboard #wpr-account-data:before{content:none}.wpr-Page#tools #wpr-action-rocket_enable_mobile_cpcss:before{transition:all 200ms ease-out;opacity:1;transform:translateY(0)}.wpr-Page#tools #wpr-action-rocket_enable_mobile_cpcss.wpr-isLoading:before{animation:loading 1.2s infinite}.wpr-Popin{display:none;position:fixed;width:772px;height:auto;top:50%;left:50%;background:#fff;border-radius:3px;transform:translateX(-50%) translateY(-50%);z-index:100000}.wpr-Popin-overlay{display:none;position:fixed;opacity:0;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,.8);z-index:99999}.wpr-Popin-header{display:flex;align-items:center;justify-content:space-between;height:64px;padding:0 32px;background:#2d1656;color:#fff;font-weight:600}.wpr-Popin-close{color:#665090;font-size:1.5rem;line-height:1;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}.wpr-Popin-close:hover,.wpr-Popin-close:focus{color:#fff;outline:none}.wpr-Popin-content{padding:8px 32px;color:#666}.wpr-Popin-flex{display:flex;flex-direction:row;align-items:center}.wpr-Popin-flex div{margin-left:32px}.wpr-Popin p{margin:16px 0}.wpr-Popin .wp-rocket-data-table{padding:12px 24px;background:#f2f3f6 !important;border:none}.wpr-Popin .wp-rocket-data-table td{width:50%;color:#121116;padding:8px 0;padding-left:4px;border-bottom:1px solid #c2cad4}.wpr-Popin .wp-rocket-data-table td:not(.column-primary){font-family:"Monaco";font-size:0.75rem;line-height:1.6666666667;color:#666;letter-spacing:-0.01em}.wpr-Popin .wp-rocket-data-table tr{background:#f2f3f6;border-bottom:1px solid #e0e4e9}.wpr-Popin .wp-rocket-data-table tr:last-child td{border-bottom:none}.wpr-Popin .wp-rocket-data-table strong{font-weight:500}.wpr-Popin .wp-rocket-data-table em{font-style:normal}.wpr-Popin .wp-rocket-data-table code{padding:0;margin:0;background:transparent}.wpr-rocketcdn-cta-small{border-radius:5px;margin:24px 0;padding:16px}.wpr-rocketcdn-cta-small.wpr-isHidden{display:none}.wpr-rocketcdn-cta-small .notice-title{font-weight:700}.wpr-rocketcdn-cta-small .wpr-flex{display:flex;justify-content:space-between;align-items:center}@media(max-width: 783px){.wpr-rocketcdn-cta-small .wpr-flex{text-align:start;flex-direction:column}}.wpr-rocketcdn-cta{margin:10px 0;position:relative}.wpr-rocketcdn-cta.wpr-isHidden{display:none}.wpr-rocketcdn-cta-close{position:absolute;top:16px;right:16px;background:transparent;border:0;color:rgba(255,255,255,.5)}.wpr-rocketcdn-cta-close--no-promo{position:absolute;top:16px;right:16px;background:transparent;border:0;color:rgba(0,0,0,.5)}.wpr-rocketcdn-cta-close--no-promo:before{content:"✕";font-weight:700;font-size:1.5rem;line-height:1.3333333333}.wpr-rocketcdn-cta-close:before{content:"✕";color:#121116;font-weight:700;font-size:1.5rem;line-height:1.3333333333}.wpr-rocketcdn-cta .wpr-rocketcdn-promo{background:#ffd147;border-top-left-radius:2px;border-top-right-radius:2px;padding:16px 48px 16px 16px}.wpr-rocketcdn-cta .wpr-rocketcdn-promo-title{font-weight:700;font-size:1.5rem;line-height:1.3333333333}.wpr-rocketcdn-cta .wpr-rocketcdn-promo-date{margin:0;font-weight:500;font-size:1rem;line-height:1.5}.wpr-rocketcdn-cta-subtitle{color:#444;margin-top:0;font-size:0.875rem;line-height:1.7142857143}.wpr-rocketcdn-cta-content{background:#f9fafb;border-top:1px solid #e8ebee;border-left:1px solid #e8ebee;border-right:1px solid #e8ebee;padding:16px}.wpr-rocketcdn-cta-content--no-promo{border-top-left-radius:2px;border-top-right-radius:2px;background:#f9fafb;border-top:1px solid #e8ebee;border-left:1px solid #e8ebee;border-right:1px solid #e8ebee;padding:16px}.wpr-rocketcdn-cta .wpr-flex{display:flex;justify-content:space-between;align-items:center}@media(max-width: 783px){.wpr-rocketcdn-cta .wpr-flex{text-align:start;flex-direction:column}}.wpr-rocketcdn-cta .wpr-rocketcdn-features{margin:0;padding-right:16px}@media(max-width: 783px){.wpr-rocketcdn-cta .wpr-rocketcdn-features{border-right:none}}.wpr-rocketcdn-cta .wpr-rocketcdn-pricing{background-color:#fff;align-items:center;display:flex;flex-direction:column;padding:16px;padding-bottom:32px;width:33.3333333333%;max-width:219px}@media(max-width: 783px){.wpr-rocketcdn-cta .wpr-rocketcdn-pricing{width:auto}}.wpr-rocketcdn-cta .wpr-rocketcdn-pricing-regular{color:#72777c;margin-bottom:8px}.wpr-rocketcdn-cta .wpr-rocketcdn-pricing .wpr-rocketcdn-cta-billing-detail{margin-bottom:16px;font-size:1rem;line-height:1.375}.wpr-rocketcdn-cta .wpr-rocketcdn-pricing .wpr-rocketcdn-cta-currency-major{font-weight:700;font-size:3rem;line-height:1.1666666667}.wpr-rocketcdn-cta .wpr-rocketcdn-pricing .wpr-rocketcdn-cta-currency-minor{font-weight:700;vertical-align:top;font-size:1.5rem;line-height:1.3333333333}.wpr-rocketcdn-cta .wpr-rocketcdn-feature{margin:24px 0;min-height:30px;padding-left:62px;position:relative}.wpr-rocketcdn-cta .wpr-rocketcdn-feature:before{position:absolute;top:50%;left:5px;transform:translateY(-50%)}.wpr-rocketcdn-cta .wpr-rocketcdn-bandwidth:before{content:url(../img/bandwidth.svg)}.wpr-rocketcdn-cta .wpr-rocketcdn-configuration:before{content:url(../img/configuration.svg)}.wpr-rocketcdn-cta .wpr-rocketcdn-automatic:before{content:url(../img/automatic.svg)}.wpr-rocketcdn-cta-footer{color:#121116;font-weight:600;padding:16px 8px 8px;font-size:0.875rem;line-height:1.5714285714}.wpr-rocketcdn-cta-footer a{position:relative;padding-left:22px}.wpr-rocketcdn-cta-footer a:before{content:"";position:absolute;width:14px;height:15px;background:url("../img/icon-i-circle.svg") no-repeat center center;top:3px;left:0}.wpr-rocketcdn-cta-promo-footer{color:#121116;padding:16px 8px 8px;font-size:0.875rem;line-height:1.5714285714}.wpr-rocketcdn-subscription{text-align:end}.wpr-rocketcdn-subscription .wpr-rocketcdn-open{color:#666;text-decoration:underline}.wpr-rocket-analytics-cta.wpr-isHidden{display:none}.wpr-license-upgrade-button{font-weight:bold;text-decoration:underline}.wpr-license-upgrade-button:hover{text-decoration:none}.wpr-field.wpr-field-account .wpr-flex{align-items:flex-start}.wpr-infoAccount-License{flex:1 0 60%;margin-right:16px}@media(max-width: 783px){.wpr-field.wpr-field-account .wpr-flex>div{width:100%}}.wpr-field.wpr-field-account .wpr-flex>div:last-child{text-align:right}@media(max-width: 783px){.wpr-field.wpr-field-account .wpr-flex>div:last-child{text-align:left}}.wpr-Popin-Upgrade .wpr-Popin-content{padding-bottom:32px}.wpr-Popin-Upgrade .wpr-Popin-flex{justify-content:space-between}.wpr-Popin-Upgrade .wpr-Popin-flex>div{align-items:center;border:1px solid #dadada;border-radius:24px;display:flex;flex-direction:column;margin:0 16px 0 0;padding:24px;text-align:center;width:50%}.wpr-Popin-Upgrade .wpr-Popin-flex>div:last-child{margin-right:0}@media(max-width: 783px){.wpr-Popin-Upgrade .wpr-Popin-flex>div{margin:0;width:100%}}.wpr-Upgrade-Plus .wpr-upgrade-title::before{content:url(../img/plus.svg);display:block;width:117px;height:31px;top:0;position:absolute;left:50%;transform:translateX(-50%)}.wpr-Upgrade-Infinite .wpr-upgrade-title::before{content:url(../img/infinite.svg);display:block;width:48px;height:31px;top:0;position:absolute;left:50%;transform:translateX(-50%)}div.wpr-upgrade-saving{background:#ffd147;border-radius:44px;color:#121116;font-weight:bold;margin:0 0 24px 0;padding:8px 16px;text-align:center}.wpr-upgrade-title{color:#f56f46;font-size:1.875rem;line-height:1.2;margin-bottom:16px;padding-top:55px;position:relative}div.wpr-upgrade-prices{color:#121116;font-size:3rem;line-height:1;font-weight:bold;margin:0 0 16px 0}.wpr-upgrade-price-symbol{font-size:1.875rem;line-height:1;vertical-align:super}.wpr-upgrade-price-regular{color:#72777c;font-size:1rem;line-height:1;vertical-align:top}div.wpr-upgrade-websites{color:#121116;font-size:0.875rem;line-height:1;font-weight:bold;margin:0 0 24px 0}.wpr-upgrade-link{background:#fff;border:1px solid #f56f46;border-radius:800px;color:#f56f46;display:block;font-size:1rem;line-height:1.125;font-weight:bold;padding:16px 24px;text-decoration:none}.wpr-upgrade-link:hover{background:#f56f46;color:#fff}.wpr-upgrade-link::after{content:"→";font-weight:normal;margin-left:8px}.rocket-promo-banner{background:#ffd147;display:flex;justify-content:space-around;margin-top:16px;padding:24px;position:relative}@media(max-width: 783px){.rocket-promo-banner{flex-flow:column}}.rocket-promo-banner>div{display:flex;flex-flow:column;width:50%}@media(max-width: 783px){.rocket-promo-banner>div{width:100%}}.rocket-promo-title{font-weight:bold;margin-bottom:24px}.rocket-promo-discount{background:#fff;border-radius:44px;display:inline-block;margin-right:8px;padding:8px 16px;text-transform:uppercase}.rocket-promo-message,.rocket-promo-deal{font-size:1rem;line-height:1.5;margin-bottom:0}.rocket-promo-deal{margin-top:8px}.rocket-promo-cta-block{align-items:center;margin-right:24px}.rocket-promo-countdown{display:flex;flex-flow:row wrap;width:66%}.rocket-promo-countdown>.rocket-countdown-item{background:#fff;border-radius:8px;flex:1;margin-right:8px;padding:8px;text-align:center}.rocket-promo-countdown>.rocket-countdown-item>.rocket-countdown-value{display:block;font-size:1.5rem;line-height:1;font-weight:bold}.rocket-promo-cta{background:#172153;border-radius:44px;color:#fff;font-weight:bold;padding:16px 32px}.rocket-renewal-banner{background:#ffd147;display:flex;flex-flow:row wrap;align-items:center;justify-content:space-evenly;margin-top:16px;padding:8px}.rocket-renewal-expired-banner{background:#ffd147;margin-top:16px;padding:24px;position:relative}.rocket-renewal-expired-banner-container{display:flex;justify-content:space-around}@media(max-width: 783px){.rocket-renewal-expired-banner-container{flex-flow:column}}.rocket-renewal-expired-banner-container>div{display:flex;flex-flow:column;width:50%}@media(max-width: 783px){.rocket-renewal-expired-banner-container>div{width:100%}}.rocket-renew-message{margin:0 16px}.rocket-renew-message>p{font-size:0.875rem;line-height:1.5}.rocket-expired-message>p{font-size:0.875rem;line-height:1.5;padding-left:80px}.rocket-expired-title{font-size:1.375rem;line-height:1.5;font-weight:bold}.rocket-expired-title::before{content:url(../img/warning.svg);display:inline-block;height:48px;width:63px;margin-right:17px;vertical-align:middle}.rocket-expired-cta-container{justify-content:center;align-items:center}.rocket-renew-cta{display:block;background:#172153;border-radius:44px;color:#fff;font-size:1rem;line-height:1.125;font-weight:bold;padding:16px 24px;text-decoration:none}.rocket-renew-cta:hover,.rocket-renew-cta:active,.rocket-renew-cta:focus{color:#fff}.rocket-renew-cta::after{content:"→";font-weight:normal;margin-left:8px}.wpr-menuItem{position:relative;display:block;padding:16px 44px 18px 20px;text-decoration:none;color:#121116;border-top:1px solid #e0e4e9;border-left:2px solid transparent;overflow:hidden;transition:all 100ms ease-out;-webkit-transition:all 100ms ease-out}@media(max-width: 783px){.wpr-menuItem{width:57px;height:50px;padding:0}}.wpr-menuItem:before{position:absolute;top:calc(50% - 12px);right:18px;text-align:center;font-size:1.4375rem;line-height:1;color:#121116;opacity:.4;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-menuItem:hover,.wpr-menuItem.isActive{color:#121116;background:#fff;border-left:2px solid #f56640}.wpr-menuItem:hover .wpr-menuItem-title,.wpr-menuItem.isActive .wpr-menuItem-title{color:#f56640}.wpr-menuItem:hover:before,.wpr-menuItem.isActive:before{color:#f56640;opacity:1}.wpr-menuItem:focus{color:#121116}.wpr-menuItem:focus:before{color:#121116}.wpr-menuItem-title{font-size:0.8125rem;line-height:1.4615384615;font-weight:bold;letter-spacing:-0.08px;text-transform:uppercase;color:#121116}@media(max-width: 783px){.wpr-menuItem-title{display:none !important}}.wpr-menuItem-description{margin-top:2px;color:#72777c;font-size:0.8125rem;line-height:1.2307692308;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}@media(max-width: 783px){.wpr-menuItem-description{display:none}}.wpr-menuItem.wpr-subMenuItem{display:none;padding:10px 20px 8px 25px}@media(max-width: 783px){.wpr-menuItem.wpr-subMenuItem{padding:8px 20px 8px 23px;height:35px}}.wpr-menuItem.wpr-subMenuItem .wpr-menuItem-title{display:inline-block;font-size:0.8125rem;line-height:1.8461538462;text-transform:inherit;font-weight:600}.wpr-menuItem.wpr-subMenuItem:before{position:relative;display:inline-block;top:2px;right:2px;margin-right:8px;font-size:1rem;line-height:1}#wpr-nav-cache:before{right:20px}#wpr-nav-tools:before{right:20px}.wpr-sectionHeader{position:relative;border-bottom:1px solid #e0e4e9;padding-bottom:24px}.wpr-sectionHeader:before{content:"";position:absolute;display:block;width:48px;height:2px;bottom:-1px;left:0;background:#f56640}.wpr-sectionHeader .wpr-title1{line-height:48px}.wpr-sectionHeader .wpr-title1:before{display:inline-block;width:48px;height:48px;margin-right:24px;background:#fde0d9;color:#f56640;text-align:center;border-radius:3px}.wpr-sectionHeader-title{margin-top:8px;padding-left:72px}.wpr-sectionHeader-description{color:#666;margin-top:8px;padding-left:72px}.wpr-sectionHeader-logo{vertical-align:top;margin-right:24px}.wpr-optionHeader{position:relative;display:flex;justify-content:space-between;margin-top:48px;padding-bottom:9px;border-bottom:1px solid #e0e4e9}.wpr-optionHeader .wpr-title2{line-height:24px;color:#f56640;padding-right:40px}.wpr-optionHeader .wpr-infoAction{margin-right:8px}.wpr-optionHeader.wpr-isHidden{display:none}.wpr-fieldsContainer{margin-top:8px}.wpr-fieldsContainer-description{color:#666}.wpr-fieldsContainer-description a:hover,.wpr-fieldsContainer-description a:focus{color:#1eadbf}.wpr-fieldsContainer-fieldset{margin-top:16px;background:#f9fafb;padding:16px;border:1px solid #e8ebee;border-radius:2px}.wpr-fieldsContainer-fieldset--split{display:flex}.wpr-fieldsContainer-fieldset--split .wpr-field+.wpr-field{border:none}.wpr-fieldsContainer-fieldset--split .wpr-field{flex:0 0 50%;padding:0}.wpr-fieldsContainer-fieldset--split .wpr-field:first-child{padding-right:15px}.wpr-fieldsContainer-fieldset--split .wpr-field:last-child{padding-left:15px}.wpr-fieldsContainer-helper{margin-top:16px;color:#d60e5b;font-weight:500}.wpr-fieldsContainer-helper:before{position:relative;top:3px;font-size:1.125rem;line-height:1;margin-right:4px}.wpr-fieldsContainer.wpr-isHidden{display:none}.wpr-infoAction{position:relative;height:24px;font-size:0.8125rem;line-height:1.8461538462;vertical-align:middle;letter-spacing:-0.03em;font-weight:500;color:#666;white-space:nowrap;text-decoration:none;transition:all 200ms ease-out;-webkit-transition:all 200ms ease-out}.wpr-infoAction:before{position:absolute;margin-left:-26px;font-size:1.125rem;line-height:1.3333333333;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}.wpr-infoAction--help{text-transform:uppercase;color:#02707f;font-weight:bold;font-size:0.75rem;line-height:2;letter-spacing:0}@media(max-width: 783px){.wpr-infoAction--help{display:none}}.wpr-infoAction--help:before{color:#1eadbf}.wpr-infoAction:hover,.wpr-infoAction:focus{color:#f56640;outline:none}.wpr-infoAction:hover:before,.wpr-infoAction:focus:before{color:#ffa58b}.wpr-button{position:relative;display:inline-block;width:auto;padding:8px 24px;text-align:center;background:#f56640;box-shadow:0 4px 6px rgba(50,50,93,.11),0 1px 3px rgba(0,0,0,.08);text-transform:uppercase;text-decoration:none;letter-spacing:-0.08px;font-weight:bold;border-radius:4px;color:#fff !important;white-space:nowrap;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:all 200ms ease-out;-webkit-transition:all 200ms ease-out;font-size:0.8125rem;line-height:1.5384615385}.wpr-button:hover,.wpr-button:focus{color:#fff !important;transform:translateY(-2px);box-shadow:0 7px 14px rgba(50,50,93,.25),0 3px 6px rgba(0,0,0,.2)}.wpr-button--small{padding:5px 0;letter-spacing:-0.08px;font-size:0.6875rem;line-height:1.8181818182}.wpr-button--icon{min-width:160px;padding-left:8px;padding-right:40px;text-align:left}.wpr-button--icon:before{position:absolute;right:8px;font-size:0.9375rem;line-height:1.3333333333}.wpr-button--fixed{position:fixed;display:flex;padding:8px 16px;right:24px;bottom:32px;border-radius:16px}.wpr-button--fixed:before{font-size:1.125rem;line-height:1;margin-right:8px}.wpr-button--purple{background:#2d1656}.wpr-button--blue{min-width:inherit;background:#1eadbf}.wpr-button--lightBlue{min-width:inherit;background:#40bacb}.wpr-button--red{background:#d33f49}.wpr-button--gray{background:#e0e4e9;color:#121116 !important}.wpr-button--gray:hover,.wpr-button--gray:active,.wpr-button--gray:focus{color:#121116 !important}.wpr-button--gray.radio-active{background:#2d1656 !important;color:#fff !important}.wpr-button--gray.radio-active:hover,.wpr-button--gray.radio-active:active,.wpr-button--gray.radio-active:focus{color:#fff !important}.wpr-button--blueDark{background:#02707f}.wpr-button:focus{outline:none;color:#fff !important}.wpr-field{padding:16px 0;transition:opacity 150ms ease-out;-webkit-transition:opacity 150ms ease-out}.wpr-field+.wpr-field,.wpr-field+.wpr-warningContainer{border-top:1px solid #e0e4e9}.wpr-field:first-child{padding-top:0}.wpr-field:last-child{padding-bottom:0}.wpr-field-description{margin-top:4px;color:#666;font-size:0.8125rem;line-height:1.5384615385}.wpr-field-description .wpr-js-popin{color:#444;text-decoration:underline}.wpr-field-description .wpr-js-popin:hover,.wpr-field-description .wpr-js-popin:focus{color:#1eadbf}.wpr-field-description a:hover,.wpr-field-description a:focus{color:#1eadbf}.wpr-field-description-helper{color:#00a66b}.wpr-field-description-label{font-size:0.875rem;line-height:1.4285714286;font-weight:500;color:#666}.wpr-field-list{margin:0;color:#666;font-weight:500}.wpr-field-list li+li{margin-top:16px}.wpr-field-list li:before{position:relative;top:3px;margin-right:8px;color:#02707f;font-size:1.125rem;line-height:1.1111111111}.wpr-field-list a{text-decoration:none}.wpr-field-list a:hover,.wpr-field-list a:focus{color:#1eadbf}.wpr-field-betweenText{margin:0 16px;font-weight:bold}.wpr-field .wpr-button{margin:8px 0}.wpr-field .wpr-flex{display:flex;justify-content:space-between;align-items:center}@media(max-width: 783px){.wpr-field .wpr-flex{text-align:left;flex-direction:column}}.wpr-field .wpr-flex--egal>div{flex:0 0 50%}@media(max-width: 783px){.wpr-field .wpr-flex--egal>div{width:100%}}.wpr-field .wpr-flex--egal>div:last-child{text-align:right}@media(max-width: 783px){.wpr-field .wpr-flex--egal>div:last-child{text-align:left}}.wpr-field .wpr-flex--egal>div .wpr-field-description{font-style:normal;color:#666}.wpr-field p{margin-bottom:0}.wpr-field label{font-weight:500}.wpr-field h4{font-size:0.875rem;line-height:1.7142857143}.wpr-field.wpr-isDisabled{opacity:.55}.wpr-field.wpr-isParent{padding-bottom:0;margin-bottom:16px}.wpr-field.wpr-Delayjs{margin-top:16px}.wpr-field.wpr-RemoveUnUsedCss{margin-bottom:0}.wpr-field.wpr-NoPaddingBottom{padding-bottom:0}.wpr-field.wpr-isLastElem{margin-top:16px}.wpr-field.wpr-isHidden{display:none}.wpr-field .wpr-isHidden{display:none}.wpr-field--children{display:none;padding-left:32px}.wpr-field--children.wpr-isOpen{display:block}.wpr-field--children.wpr-field--textarea{padding-right:80px}@media(max-width: 1239px){.wpr-field--children.wpr-field--textarea{padding-right:32px}}@media(max-width: 783px){.wpr-field--children.wpr-field--textarea{padding-right:0}}.wpr-field--children.no-space{padding-left:0}.wpr-field--checkbox .wpr-field-description{margin-left:32px}.wpr-field--radio{padding:24px 16px}.wpr-field--radio:first-child{padding-top:8px}.wpr-field--radio:last-child{padding-bottom:8px}.wpr-field--radio .wpr-field-description{margin-left:88px}.wpr-field--radio .wpr-field-description button{color:#666}.wpr-field--split{display:inline-block;width:50%;padding-right:16px;padding-bottom:0}.wpr-field--split+.wpr-field--split{padding-left:16px;padding-right:0}.wpr-field--split+.wpr-field--split:nth-child(2){padding-top:0;border-top:none}.wpr-field--cache .wpr-field--number,.wpr-field--cache .wpr-field--select{display:inline-block;padding-top:0;width:auto;padding-bottom:0;font-weight:bold}.wpr-field--cache .wpr-field--select{position:relative;padding-left:8px;top:-2px;border-top:none}.wpr-field--cache .wpr-field--number .wpr-text input[type=number]{background:#f2f3f6;height:35px;border:1px solid #e0e4e9;font-family:inherit;font-size:1em}.wpr-field--cache .wpr-field-description{margin:8px 0;color:#00a66b}.wpr-field--cache .wpr-field-description-label{color:#121116}.wpr-field--textarea .wpr-field-description pre{background:rgba(0,0,0,.07);padding:1em;margin:1em 0 0;white-space:normal}.wpr-field--textarea .wpr-field-description pre code{background:transparent;-webkit-touch-callout:all;-webkit-user-select:all;-khtml-user-select:all;-moz-user-select:all;-ms-user-select:all;user-select:all;color:#121116}.wpr-fieldWarning{display:none;position:relative;padding:16px 16px 24px 56px;background:#19073b;margin:8px 0 0;color:#fff}.wpr-fieldWarning.wpr-isOpen{display:block}.wpr-fieldWarning:after{content:"";position:absolute;display:block;top:-8px;left:20px;width:0;height:0;border-style:solid;border-width:0 12px 8px 12px;border-color:transparent transparent #19073b transparent}.wpr-fieldWarning:before{content:"";position:absolute;display:block;width:calc(100% + 32px);height:100%;top:0;left:-16px;background:#19073b}.wpr-fieldWarning-title{position:relative;color:#f56640;font-size:0.875rem;line-height:1.4285714286;font-weight:bold}.wpr-fieldWarning-title:before{position:absolute;left:-36px;font-size:1.5rem;line-height:.8333333333}.wpr-fieldWarning-description{position:relative;margin-top:8px}.wpr-fieldWarning .wpr-button{margin-top:16px}.wpr-fieldWarning.wpr-radio-warning{margin-left:-32px}.wpr-fieldWarning.wpr-radio-warning:after{left:40px}.wpr-warningContainer+.wpr-warningContainer,.wpr-warningContainer+.wpr-field,.wpr-field+.wpr-warningContainer{border-top:1px solid #e0e4e9;padding-top:16px}.wpr-warningContainer+.wpr-warningContainer,.wpr-field+.wpr-warningContainer{padding-bottom:16px}@media only screen and (max-width: 400px){.wpr-fieldWarning.wpr-radio-warning{margin-left:-32px}.wpr-fieldWarning.wpr-radio-warning .wpr-button{white-space:normal;padding-right:32px}}@media only screen and (max-width: 350px){.wpr-radio-buttons{padding-left:24px}.wpr-fieldWarning.wpr-radio-warning{margin-left:-24px;padding-left:30px;padding-right:0}.wpr-fieldWarning.wpr-radio-warning .wpr-button{padding-right:24px}}.wpr-documentation{padding:24px 16px;border-radius:4px;color:#fff;text-align:center;background:#40bacb}.wpr-documentation p{margin:8px 0 16px;font-weight:500}.wpr-documentation i{display:block;font-size:2.25rem;line-height:1;margin-bottom:8px}.wpr-documentation .wpr-button{padding-left:16px;padding-right:16px}.wpr-addon{padding:24px 0}.wpr-addon .wpr-flex{align-items:flex-start}@media(max-width: 783px){.wpr-addon .wpr-flex{align-items:center}}.wpr-addon .wpr-flex>div{text-align:left}.wpr-addon .wpr-addon-title{margin-bottom:16px;font-weight:500}.wpr-addon .wpr-field-description{font-style:normal}.wpr-addon .wpr-field-helper{font-size:0.8125rem;line-height:1.5384615385;color:#666;background-color:#e0e4e9;padding:8px;margin:8px 0}.wpr-addon .wpr-field-helper span.wpr-helper-title{font-weight:600}.wpr-addon .wpr-field-helper span.wpr-helper-title::after{content:"\a";white-space:pre}.wpr-addon .wpr-addon-logo{text-align:center;flex:0 0 160px}@media(max-width: 1239px){.wpr-addon .wpr-addon-logo{max-width:100px}.wpr-addon .wpr-addon-logo img{width:100%;height:auto}}@media(max-width: 1083px){.wpr-addon .wpr-addon-logo{max-width:160px}}@media(max-width: 783px){.wpr-addon .wpr-addon-logo{flex:0 0 auto;margin-bottom:16px}}.wpr-addon .wpr-addon-text{margin-left:32px;flex:1 1 auto}@media(max-width: 1239px){.wpr-addon .wpr-addon-text{margin-left:16px}}@media(max-width: 1083px){.wpr-addon .wpr-addon-text{margin-left:32px}}@media(max-width: 783px){.wpr-addon .wpr-addon-text{margin-left:0}}.wpr-addon .wpr-addon-text a{display:inline-block;margin-top:24px}.wpr-addon .wpr-addon-text .button{margin-top:24px}.wpr-addon .wpr-addon-text .wpr-add-on-helper{font-weight:normal;color:#1eadbf}.wpr-addon .wpr-addon-text .wpr-add-on-helper a{margin-top:0}.wpr-webp-addon .wpr-addon .wpr-addon-text a{margin-top:0px}.notice-wpr-warning{background:#ffd147;display:flex;flex-flow:row wrap;align-items:center;margin-top:16px;padding:8px 32px;border:0}.notice-wpr-warning p:first-child{font-size:1rem;line-height:1.125;margin-left:80px}.notice-wpr-warning p:first-child::before{content:url(../img/warning.svg);display:inline-block;height:48px;width:63px;margin-right:17px;vertical-align:middle;margin-left:-80px}@media(max-width: 1239px){.notice-wpr-warning p:first-child::before{margin-bottom:-30px}}.notice-wpr-warning p:last-child{margin-left:63px;flex-basis:100%;align-items:center;justify-content:flex-start;display:flex}@media(max-width: 783px){.notice-wpr-warning p:last-child{align-content:center;flex-direction:column;margin-left:0}}.notice-wpr-warning p:last-child a{margin:0 16px}@media(max-width: 783px){.notice-wpr-warning p:last-child a{margin:8px 16px}}.notice-wpr-warning p:last-child a:first-child{display:block;background:#172153;border-radius:44px;color:#fff;font-size:1rem;line-height:1.125;font-weight:bold;padding:16px 24px;text-decoration:none}.notice-wpr-warning p:last-child a:first-child:hover,.notice-wpr-warning p:last-child a:first-child:active,.notice-wpr-warning p:last-child a:first-child:focus{color:#fff}.notice-wpr-warning p:last-child a:first-child::after{content:"→";font-weight:normal;margin-left:8px}.wpr-notice{position:relative;color:#444;background:#ebfaf5 url("../img/bg-activated.svg") no-repeat 90% bottom;background-size:350px;margin-top:24px;border-radius:4px;overflow:hidden}.wpr-notice-container{padding:24px 25% 24px 40px}.wpr-notice-supTitle{font-size:1rem;line-height:1.375;font-weight:bold}.wpr-notice-title{font-size:1.5rem;line-height:1.3333333333;color:#3ece9d;margin-top:16px;font-weight:bold}.wpr-notice-description{font-size:0.875rem;line-height:1.5714285714;margin:16px 0 24px}.wpr-notice-continue{color:#666}.wpr-notice-close{position:absolute;top:24px;right:24px;color:#666;text-decoration:none;font-size:1.5rem;line-height:1;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}.wpr-notice-close:hover{color:#444}.wpr-notice-close:focus{outline:none}.wpr-tools{position:relative;display:flex;flex-direction:row;padding:32px 0}@media(max-width: 1239px){.wpr-tools{flex-direction:column}}@media(max-width: 1083px){.wpr-tools{flex-direction:row}}@media(max-width: 783px){.wpr-tools{flex-direction:column}}.wpr-tools:nth-child(2){margin-top:16px}.wpr-tools+.wpr-tools{border-top:1px solid #e0e4e9}.wpr-tools-label{display:block}.wpr-tools-label:before{position:absolute;left:0;margin-top:5px;font-size:2.25rem;line-height:1;color:#f56640}@media(max-width: 783px){.wpr-tools-label:before{display:block;position:initial}}.wpr-tools-col{flex:1 1 auto}.wpr-tools-col:first-child{padding-left:72px;padding-right:24px;min-width:340px}@media(max-width: 783px){.wpr-tools-col:first-child{padding-left:0;padding-right:0;min-width:auto}}.wpr-tools-col:last-child{text-align:right}@media(max-width: 783px){.wpr-tools-col:last-child{text-align:left}}.wpr-tools .wpr-button{margin-top:24px;white-space:normal}.wpr-tools .wpr-field-description{font-style:normal;color:#666}.wpr-tools #wpr-update-exclusion-msg{min-height:20px}.wpr-imagify{display:flex;justify-content:space-between;flex-wrap:wrap;margin-top:30px}.wpr-imagify-description{width:40%;padding-right:60px}@media(max-width: 1239px){.wpr-imagify-description{width:auto;padding-right:0}}.wpr-imagify-screenshot{width:60%}@media(max-width: 1239px){.wpr-imagify-screenshot{margin-top:60px;width:auto}}.wpr-imagify-screenshot img{max-width:100%;height:auto}.wpr-imagify-more,.wpr-imagify-name{color:#00a8dc;font-weight:700;margin-bottom:0}.wpr-imagify-more::before{content:"✓";color:#000;font-size:2rem;margin-right:5px}.wpr-imagify p{font-size:1rem}.wpr-imagify p:first-child{margin-top:0}.wpr-imagify ul{margin-top:40px}.wpr-imagify li{display:flex;align-items:flex-start;margin-bottom:35px}.wpr-imagify li:before{width:24px;height:24px;margin-right:10px;flex-shrink:0}.wpr-imagify li .text{flex-grow:1;display:inline-block}.wpr-imagify a{text-decoration:none}.wpr-imagify a:hover{color:#00a8dc}.wpr-imagify .button-primary{background:#2abb9b;border:1px solid #bebebe;box-shadow:none;font-size:1rem;font-weight:700;height:auto;line-height:1;margin-top:60px;padding:20px 45px;text-shadow:none;text-transform:uppercase}.wpr-imagify-plugin-tile{display:flex;align-items:center;width:100%;padding:20px;background-color:#f9fafb;margin-top:20px;border:1px solid #ebe9e9}.wpr-imagify-plugin-tile-info{margin-left:20px}.wpr-imagify-plugin-tile-info .wpr-star-rating{display:flex;align-items:center}.wpr-imagify-plugin-tile-info .star-rating .star{font-size:16px;width:16px;height:13px}.wpr-imagify-plugin-tile-info .num-ratings{font-size:13px;margin-left:10px}.wpr-imagify-plugin-tile-title{margin-bottom:5px}.wpr-imagify-plugin-tile .wpr-button{margin-left:auto}.wpr-imagify-plugin-tile .wpr-button:before{margin-right:5px}.wpr-tutorials-section{display:flex;flex-flow:row wrap}div.wpr-tutorial-item{width:32%;margin-bottom:10px;margin-right:1%}.wpr-tutorial-link{cursor:pointer;transition:color 200ms ease-out}.wpr-tutorial-link:hover{color:#1eadbf}@media(max-width: 1083px){div.wpr-tutorial-item{width:48%}}@media(max-width: 783px){div.wpr-tutorial-item{width:100%}}.wpr-rocketcdn-modal{display:none}.wpr-rocketcdn-modal.is-open{display:block}.wpr-rocketcdn-modal__overlay{position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.6);display:flex;justify-content:center;align-items:center}.wpr-rocketcdn-modal__container{max-width:674px;max-height:100vh;overflow-y:auto;box-sizing:border-box}.wpr-rocketcdn-modal iframe{max-width:100%}.wpr-checkbox{position:relative;padding-left:32px}.wpr-checkbox label{user-select:none}.wpr-checkbox [type=checkbox]:not(:checked),.wpr-checkbox [type=checkbox]:checked{position:absolute;left:-9999px}.wpr-checkbox [type=checkbox]:not(:checked)+label:before,.wpr-checkbox [type=checkbox]:checked+label:before{content:"";position:absolute;left:0;top:4px;width:14px;height:14px;border:2px solid #444;border-radius:3px;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-checkbox [type=checkbox]:not(:checked)+label:after,.wpr-checkbox [type=checkbox]:checked+label:after{content:"";position:absolute;top:5px;left:2px;color:#fff;font-family:"wpr-icomoon";speak:none;font-size:0.875rem;line-height:1.2857142857;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-checkbox [type=checkbox]:not(:checked)+label:after{opacity:0;transform:scale(2)}.wpr-checkbox [type=checkbox]:checked+label:after{opacity:1;transform:scale(1)}.wpr-checkbox [type=checkbox]:checked+label:before{background:#19073b;border-color:#19073b}.wpr-checkbox [type=checkbox]:checked:focus+label:before{background:#665090;border:2px dotted #665090}.wpr-checkbox [type=checkbox]:focus+label:before{border:2px dotted #444}.wpr-checkbox-warning{color:#d33f49;margin-left:16px}.wpr-checkbox-warning::before{margin-right:8px}.wpr-radio{position:relative;padding-left:88px}.wpr-radio label{user-select:none;font-weight:bold}.wpr-radio [type=checkbox]:not(:checked),.wpr-radio [type=checkbox]:checked{position:absolute;left:-9999px}.wpr-radio [type=checkbox]:not(:checked)+label:before,.wpr-radio [type=checkbox]:checked+label:before,.wpr-radio [type=checkbox]:not(:checked)+label:after,.wpr-radio [type=checkbox]:checked+label:after{content:"";position:absolute}.wpr-radio [type=checkbox]:not(:checked)+label:before,.wpr-radio [type=checkbox]:checked+label:before{left:0;width:52px;height:22px;background:#fff;border-radius:12px;border:1px solid #444;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-radio [type=checkbox]:not(:checked)+label:after,.wpr-radio [type=checkbox]:checked+label:after{width:18px;height:18px;border-radius:100%;background:#444;top:3px;left:3px;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-radio [type=checkbox]:disabled+label:after,.wpr-radio [type=checkbox]:disabled+label:after{background:#e0e4e9}.wpr-radio [type=checkbox]:disabled+label:before,.wpr-radio [type=checkbox]:disabled+label:before{border:1px solid #e0e4e9}.wpr-radio [type=checkbox]:checked+label:before{border-color:#1eadbf}.wpr-radio [type=checkbox]:checked+label:after{background:#1eadbf;left:33px}.wpr-radio [type=checkbox]:checked+label .wpr-radio-ui,.wpr-radio [type=checkbox]:not(:checked)+label .wpr-radio-ui:before,.wpr-radio [type=checkbox]:checked+label .wpr-radio-ui:after{position:absolute;left:4px;width:52px;text-transform:uppercase;letter-spacing:-0.01em;font-weight:bold;font-size:0.6875rem;line-height:2.1818181818;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-radio [type=checkbox]:not(:checked)+label .wpr-radio-ui:before{content:attr(data-l10n-inactive);left:27px;color:#666}.wpr-radio [type=checkbox]:checked+label .wpr-radio-ui:after{content:attr(data-l10n-active);color:#02707f}.wpr-radio--reverse{padding-right:72px;padding-left:0}.wpr-radio--reverse [type=checkbox]:not(:checked)+label:before,.wpr-radio--reverse [type=checkbox]:checked+label:before{right:0;left:inherit}.wpr-radio--reverse [type=checkbox]:not(:checked)+label:after,.wpr-radio--reverse [type=checkbox]:checked+label:after{right:33px;left:inherit}.wpr-radio--reverse [type=checkbox]:checked+label:after{right:3px;left:inherit}.wpr-radio--reverse [type=checkbox]:checked+label .wpr-radio-ui,.wpr-radio--reverse [type=checkbox]:not(:checked)+label .wpr-radio-ui:before,.wpr-radio--reverse [type=checkbox]:checked+label .wpr-radio-ui:after{right:-2px;left:inherit}.wpr-radio--reverse [type=checkbox]:not(:checked)+label .wpr-radio-ui:before{right:-25px;left:inherit}.wpr-radio [type=checkbox]:not(:checked):focus+label:before{border:1px dashed #444}.wpr-radio [type=checkbox]:checked:focus+label:before{border:1px dashed #1eadbf}.wpr-radio--tips [type=checkbox]:checked+label:before{border-color:#3ece9d}.wpr-radio--tips [type=checkbox]:checked+label:after{background:#3ece9d}.wpr-radio--tips [type=checkbox]:checked+label .wpr-radio-ui:after{color:#00a66b}.wpr-radio--tips [type=checkbox]:checked:focus+label:before{border:1px dashed #3ece9d}.wpr-select{position:relative}.wpr-select select{margin:0;padding:0 8px;height:36px;border:1px solid #e0e4e9;background:#f2f3f6;color:#121116;box-shadow:none;border-radius:0;letter-spacing:.011em}.wpr-select select:focus{outline:none;border-color:#444;box-shadow:none}.wpr-select select:disabled{background-image:none}.wpr-select label{font-weight:bold;margin-left:8px}.wpr-textarea{margin-top:8px}.wpr-textarea textarea{padding:8px;width:100%;height:100px;font-family:Monaco;color:#121116;background:#fff;border:2px solid #c2cad4;border-radius:3px;font-size:0.8125rem;line-height:1.2307692308;transition:border 200ms ease-out;-webkit-transition:border 200ms ease-out}.wpr-textarea textarea:focus{outline:none;border-color:#444;box-shadow:none}.wpr-textarea+.wpr-field-description{color:#00a66b}.wpr-text label{color:#666}.wpr-text input[type=text],.wpr-text input[type=number]{margin-top:8px;padding:0 8px;width:100%;height:32px;color:#121116;background:#fff;border:2px solid #c2cad4;border-radius:3px;font-family:Monaco;font-size:0.75rem;line-height:1.3333333333;transition:border 200ms ease-out;-webkit-transition:border 200ms ease-out}.wpr-text input[type=text]:focus,.wpr-text input[type=number]:focus{outline:none;border-color:#444;box-shadow:none}.wpr-text input[type=text].wpr-isError,.wpr-text input[type=number].wpr-isError{border-color:#d33f49}.wpr-text input[type=number]{width:80px}.wpr-text--number label{margin-right:8px}.wpr-upload input[type=file]{display:block;width:252px;margin:8px 8px 8px 0;padding:8px;border:1px solid #e0e4e9;background:#f2f3f6;color:#121116;font-size:0.6875rem;line-height:1.4545454545}.wpr-upload input[type=file]:focus{outline:none;border-color:#444;box-shadow:none}.wpr-multiple{display:flex;align-items:center;flex-wrap:wrap}@media(max-width: 783px){.wpr-multiple{align-items:center;flex-direction:column}}.wpr-multiple .wpr-text{flex:1 1 auto;position:relative;top:-2px}@media(max-width: 783px){.wpr-multiple .wpr-text{width:100%}}.wpr-multiple .wpr-button{margin-left:16px;width:auto;min-width:inherit;padding-right:30px}@media(max-width: 783px){.wpr-multiple .wpr-button{margin-left:0}}.wpr-multiple input[type=text]{flex-grow:2}.wpr-multiple select{height:30px}.wpr-multiple-default{margin-right:20px}.wpr-multiple-list{display:none;padding:8px 0;margin:16px 0 0;background:#f2f3f6;border-radius:2px}.wpr-multiple-list li{margin-bottom:0;padding:4px 16px;font-size:0.8125rem;line-height:1.2307692308;font-family:Monaco}.wpr-multiple-list li span{display:inline-block;transition:all 150ms ease-out;-webkit-transition:all 150ms ease-out}.wpr-multiple-close{position:relative;top:3px;font-size:1rem;line-height:1;transition:color 200ms ease-out;-webkit-transition:color 200ms ease-out}.wpr-multiple-close:focus{outline:none}.wpr-multiple-close:hover,.wpr-multiple-close:focus{color:#d33f49}.wpr-multiple-close:hover+span,.wpr-multiple-close:focus+span{color:#d33f49}.wpr-multiple-select .wpr-list{border:2px solid #c2cad4;background-color:#fff;border-radius:5px;padding:10px;margin:8px 0}.wpr-multiple-select .wpr-list .wpr-list-header{display:flex;justify-content:space-between}.wpr-multiple-select .wpr-list .wpr-list-header .wpr-multiple-select-exclude_js_ads:before{font-family:"wpr-icomoon";content:"";padding-right:8px}.wpr-multiple-select .wpr-list .wpr-list-header .wpr-multiple-select-exclude_js_plugins:before{font-family:"wpr-icomoon";content:"";padding-right:8px}.wpr-multiple-select .wpr-list .wpr-list-header .wpr-multiple-select-exclude_js_themes:before{font-family:"wpr-icomoon";content:"";padding-right:8px}.wpr-multiple-select .wpr-list .wpr-list-header .wpr-list-header-arrow{width:15px;cursor:pointer;display:flex;transform:rotate(180deg)}.wpr-multiple-select .wpr-list .wpr-list-header h3{font-weight:500;color:#121116;font-size:0.875rem;line-height:1.5}.wpr-multiple-select .wpr-list .wpr-list-body{display:none}.wpr-multiple-select .wpr-list .wpr-list-body li{padding-left:30px}.wpr-multiple-select .wpr-list .wpr-list-body li .wpr-checkbox img{width:15px}.wpr-multiple-select .wpr-list.open .wpr-list-body{display:block}.wpr-multiple-select .wpr-list.open .wpr-list-body .wpr-checkbox label{color:#72777c}.wpr-multiple-select .wpr-list.open .wpr-list-body .wpr-checkbox input[checked=checked]+label{color:#121116}.wpr-multiple-select .wpr-list.open .wpr-list-header{border-bottom:1px solid #c2cad4;margin-bottom:10px;padding-bottom:5px}.wpr-multiple-select .wpr-list.open .wpr-list-header-arrow{transform:rotate(0deg)}.wpr-field--categorizedmultiselect .wpr-list{padding-right:15px;padding-left:15px}.wpr-field--categorizedmultiselect .wpr-list.open .wpr-list-header{padding-bottom:9px;margin-bottom:10px}.wpr-field--categorizedmultiselect .wpr-list.open .wpr-list-header{max-height:32px}.wpr-field--categorizedmultiselect .wpr-list .wpr-list-header{max-height:32px}.wpr-field--categorizedmultiselect .wpr-list [type=checkbox]+label:before{top:4px}.wpr-field--categorizedmultiselect .wpr-list [type=checkbox]:checked+label:after{top:4px}.wpr-field--categorizedmultiselect .wpr-list-header .wpr-checkbox{padding-left:29px}.wpr-field--categorizedmultiselect .wpr-list-body{display:block;max-height:250px;overflow-y:auto}.wpr-field--categorizedmultiselect .wpr-list-body ul{margin:0}.wpr-field--categorizedmultiselect .wpr-list-body ul li{margin-bottom:10px}.wpr-field--categorizedmultiselect .wpr-list-body ul li .wpr-checkbox{padding-left:25px}.wpr-field--categorizedmultiselect .wpr-list-body ul li .wpr-checkbox label{color:#121116 !important;font-weight:normal}.wpr-field--categorizedmultiselect .dashicons{color:#72777c}.wpr-field--categorizedmultiselect .wpr-multiple-select-title{font-weight:bold;margin-left:5px}@media only screen and (min-width: 782px){.wpr-field--categorizedmultiselect{padding-right:80px}} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/css/wpr-modal.css b/wp-content/plugins/wp-rocket/assets/css/wpr-modal.css index d7ce1fe18..84fc1ddf7 100644 --- a/wp-content/plugins/wp-rocket/assets/css/wpr-modal.css +++ b/wp-content/plugins/wp-rocket/assets/css/wpr-modal.css @@ -1 +1,75 @@ -@font-face{font-family:'wpr-icomoon';src:url("../fonts/icomoon.eot?-4yq2oj");src:url("../fonts/icomoon.eot?#iefix-4yq2oj") format("embedded-opentype"),url("../fonts/icomoon.woff?-4yq2oj") format("woff"),url("../fonts/icomoon.ttf?-4yq2oj") format("truetype"),url("../fonts/icomoon.svg?-4yq2oj#icomoon") format("svg");font-weight:normal;font-style:normal}[class^="wpr-icon-"]:before,[class*=" wpr-icon-"]:after,[class^="wpr-icon-"]:after,[class*=" wpr-icon-"]:before,[id^="wpr-nav-"]:before,[id*=" wpr-nav-"]:after,[id^="wpr-nav-"]:after,[id*=" wpr-nav-"]:before{font-family:'wpr-icomoon';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}[class^="wpr-icon-"] span.hidden,[class*=" wpr-icon-"] span.hidden{display:inline-block;height:0;width:0;overflow:hidden}.wpr-icon-chevron-right:before{content:"\e900"}.wpr-icon-chevron-left:before{content:"\e900";transform:rotate(180deg)}.wpr-icon-chevron-down:before{content:"\e901";transform:scale(0.6)}.wpr-icon-chevron-up:before{content:"\e902";top:50%;transform:translateY(-50%) scale(0.6)}.wpr-icon-rollback:before{content:"\e903"}.wpr-icon-addon:before{content:"\e904"}.wpr-icon-addons:before{content:"\e905"}.wpr-icon-book:before{content:"\e906"}.wpr-icon-cdn:before{content:"\e907"}.wpr-icon-database:before{content:"\e908"}.wpr-icon-export:before{content:"\e909"}.wpr-icon-files:before{content:"\e90a"}.wpr-icon-help:before{content:"\e90b"}.wpr-icon-home:before{content:"\e90c"}.wpr-icon-import:before{content:"\e90d"}.wpr-icon-important:before{content:"\e90e"}.wpr-icon-information:before{content:"\e90f"}.wpr-icon-information2:before{content:"\e910"}.wpr-icon-interrogation:before{content:"\e911"}.wpr-icon-media:before{content:"\e912"}.wpr-icon-plus:before{content:"\e913"}.wpr-icon-refresh:before{content:"\e914"}.wpr-icon-rules:before{content:"\e915"}.wpr-icon-stack:before{content:"\e916"}.wpr-icon-tools:before{content:"\e917"}.wpr-icon-trash:before{content:"\e918"}.wpr-icon-user:before{content:"\e919"}.wpr-icon-check:before{content:"\e920"}.wpr-icon-check2:before{content:"\e921"}.wpr-icon-close:before{content:"\e922"}.wpr-Modal{display:none;position:fixed;width:550px;height:auto;top:50%;left:50%;background:#fff;color:#444;transform:translateX(-50%) translateY(-50%);z-index:100000;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-ms-interpolation-mode:nearest-neighbor;image-rendering:optimizeQuality;text-rendering:optimizeLegibility}.wpr-Modal-overlay{display:none;position:fixed;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,0.7);z-index:99999}.wpr-Modal-header{display:flex;align-items:center;justify-content:space-between;padding:0 16px 0 32px;border-bottom:1px solid #EEE}.wpr-Modal-header>div{display:flex}.wpr-Modal-footer{display:flex;align-items:center;justify-content:space-between;height:64px;padding:0 32px;background:#F5F5F5}.wpr-Modal-close{font-size:0;color:#AAA;border:none;background:none;cursor:pointer}.wpr-Modal-close:hover{color:#008ec2}.wpr-Modal-close:before{font-size:1.25rem;line-height:1}.wpr-Modal-return{display:none;border:none;background:none;cursor:pointer;font-size:0;color:#777;position:relative;width:28px;left:-12px}.wpr-Modal-return.wpr-isOpen{display:inline-block}.wpr-Modal-return:before{font-size:14px;display:inline-block}.wpr-Modal-return:hover,.wpr-Modal-return:focus{outline:none;color:#008ec2}.wpr-Modal-cancel{color:#0073aa;text-decoration:underline;margin-left:8px;line-height:28px;border:none;background:none;cursor:pointer;font-weight:500}.wpr-Modal-cancel:hover{color:#008ec2}.wpr-Modal-question{display:none}.wpr-Modal-question.wpr-isOpen{display:block}.wpr-Modal-content{padding:8px 32px}.wpr-Modal-fieldHidden{display:none;padding-left:26px;margin-top:8px}.wpr-Modal-fieldHidden.wpr-isOpen{display:block}.wpr-Modal-fieldHidden input[type=text],.wpr-Modal-fieldHidden textarea{border:2px solid #A9ADB0;font-size:12px;border-radius:3px;transition:border 150ms ease-out;-webkit-transition:border 150ms ease-out}.wpr-Modal-fieldHidden input[type=text]:focus,.wpr-Modal-fieldHidden textarea:focus{outline:none;box-shadow:none;border-color:#777}.wpr-Modal-fieldHidden input[type=text]::-webkit-input-placeholder,.wpr-Modal-fieldHidden textarea::-webkit-input-placeholder{color:#ccc}.wpr-Modal-fieldHidden input[type=text] :-moz-placeholder,.wpr-Modal-fieldHidden textarea :-moz-placeholder{color:#ccc;opacity:1}.wpr-Modal-fieldHidden input[type=text]::-moz-placeholder,.wpr-Modal-fieldHidden textarea::-moz-placeholder{color:#ccc;opacity:1}.wpr-Modal-fieldHidden input[type=text] :-ms-input-placeholder,.wpr-Modal-fieldHidden textarea :-ms-input-placeholder{color:#ccc}.wpr-Modal-fieldHidden input[type=text]::-ms-input-placeholder,.wpr-Modal-fieldHidden textarea::-ms-input-placeholder{color:#ccc}.wpr-Modal-fieldHidden input[type=text]::placeholder,.wpr-Modal-fieldHidden textarea::placeholder{color:#ccc}.wpr-Modal-fieldHidden input[type=text]{width:300px;height:30px}.wpr-Modal-fieldHidden textarea{width:100%;height:60px;padding:5px}.wpr-Modal-hidden{display:none}.wpr-Modal-hidden.wpr-isOpen{display:block}.wpr-Modal-hidden button{cursor:pointer;border:none;margin-bottom:24px}.wpr-Modal-hidden .text-center{text-align:center}.wpr-Modal-hidden h3{display:none !important}.wpr-Modal-hidden a{color:#1B9AAA !important}.wpr-Modal-hidden a:hover{color:#0073aa !important}.wpr-Modal-safeMode{position:relative;padding:10px 12px 10px 52px;background:#EBFAF5;color:#00A66B;border-radius:2px;font-size:.8125rem;line-height:1.38462}.wpr-Modal-safeMode:before{position:absolute;display:block;width:24px;height:24px;left:12px;top:50%;margin-top:-14px;border-radius:50%;text-align:center;border:2px solid #00A66B;font-size:.875rem;line-height:1.71429}.wpr-Modal-safeMode-title{font-weight:bold;letter-spacing:0.011em;text-transform:uppercase}.wpr-Modal .button{font-weight:500;box-shadow:none;height:30px;border-bottom-width:3px}.wpr-Modal .button-primary.wpr-isDisabled{opacity:0.2;color:#fff !important;cursor:not-allowed;pointer-events:none}.wpr-Modal ul li{padding:4px 0}.wpr-Modal h2,.wpr-Modal h3{display:inline-block;font-size:1rem;line-height:1.1875}.wpr-Modal h2{max-width:430px;font-weight:600;color:#23282D;margin:12px 0}.wpr-Modal h3{font-weight:bold;color:#3D474E;margin:8px 0}.wpr-Modal input[type=radio]{margin-top:1px;margin-right:8px}.wpr-Modal .show-if-safe-mode{display:none}.wpr-button{position:relative;display:inline-block;width:auto;padding:8px 24px;text-align:center;background:#F56640;box-shadow:0 4px 6px rgba(50,50,93,0.11),0 1px 3px rgba(0,0,0,0.08);text-transform:uppercase;text-decoration:none;letter-spacing:-0.08px;font-weight:bold;border-radius:4px;color:#fff !important;white-space:nowrap;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:all 200ms ease-out;-webkit-transition:all 200ms ease-out;font-size:.8125rem;line-height:1.53846}.wpr-button:hover,.wpr-button:focus{color:#fff !important;transform:translateY(-2px);box-shadow:0 7px 14px rgba(50,50,93,0.25),0 3px 6px rgba(0,0,0,0.2)}.wpr-button--small{padding:5px 0;letter-spacing:-0.08px;font-size:.6875rem;line-height:1.81818}.wpr-button--icon{min-width:160px;padding-left:8px;padding-right:40px;text-align:left}.wpr-button--icon:before{position:absolute;right:8px;font-size:.9375rem;line-height:1.33333}.wpr-button--fixed{position:fixed;display:flex;padding:8px 16px;right:24px;bottom:32px;border-radius:16px}.wpr-button--fixed:before{font-size:1.125rem;line-height:1;margin-right:8px}.wpr-button--purple{background:#2D1656}.wpr-button--blue{min-width:inherit;background:#1EADBF}.wpr-button--lightBlue{min-width:inherit;background:#40BACB}.wpr-button--red{background:#D33F49}.wpr-button--blueDark{background:#02707F}.wpr-button:focus{outline:none;color:#fff !important}html[dir=rtl] .wpr-Modal-header{padding:0 32px 0 16px}html[dir=rtl] .wpr-Modal-return{left:12px;transform:rotate(180deg)}html[dir=rtl] .wpr-Modal-safeMode{padding:10px 52px 10px 12px}html[dir=rtl] .wpr-Modal-safeMode:before{left:inherit;right:12px} +.wpr-modal { + display: none; +} + +.wpr-modal.is-open { + display: block; +} + +.wpr-modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0,0,0,0.6); + display: flex; + justify-content: center; + align-items: center; + z-index: 100; +} + +.wpr-modal-container { + background-color: #fff; + padding: 30px; + max-width: 645px; + max-height: 100vh; + overflow-y: auto; + box-sizing: border-box; +} + +.wpr-modal-header, +.wpr-modal-footer { + display: flex; + justify-content: space-between; + align-items: center; +} + +.wpr-modal-title { + font-size: 26px; + font-weight: 600; + line-height: 1.2; + margin: 0; +} + +.wpr-modal-footer { + margin-top: 40px; +} + +.wpr-modal-button { + border-radius: 4px; + cursor: pointer; + padding: 8px 20px; + text-transform: uppercase; +} + +.wpr-modal-cancel { + background: transparent; + border: 1px solid #000; +} + +.wpr-modal-confirm { + background: #F56F46; + border: none; + box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2); + color: #fff; + transition: box-shadow 500ms ease-in; +} + +.wpr-modal-confirm:hover { + box-shadow: none; +} + +.wpr-modal .wpr-sub-list { + padding-left: 25px; +} diff --git a/wp-content/plugins/wp-rocket/assets/img/automatic.svg b/wp-content/plugins/wp-rocket/assets/img/automatic.svg index 35ee6fd44..ff9fd3ba5 100644 --- a/wp-content/plugins/wp-rocket/assets/img/automatic.svg +++ b/wp-content/plugins/wp-rocket/assets/img/automatic.svg @@ -1,16 +1,11 @@ - - - - streamline-icon-fitness-biceps@24x24 - Created with Sketch. - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + diff --git a/wp-content/plugins/wp-rocket/assets/img/bandwidth.svg b/wp-content/plugins/wp-rocket/assets/img/bandwidth.svg index fcb275494..3e28d022c 100644 --- a/wp-content/plugins/wp-rocket/assets/img/bandwidth.svg +++ b/wp-content/plugins/wp-rocket/assets/img/bandwidth.svg @@ -1,17 +1,17 @@ - - - - streamline-icon-space-rocket-earth@24x24 - Created with Sketch. - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + diff --git a/wp-content/plugins/wp-rocket/assets/img/bg-activated.svg b/wp-content/plugins/wp-rocket/assets/img/bg-activated.svg index 0d1abe290..7b9154a51 100644 --- a/wp-content/plugins/wp-rocket/assets/img/bg-activated.svg +++ b/wp-content/plugins/wp-rocket/assets/img/bg-activated.svg @@ -1,12 +1 @@ - - - - - - - - - - - - + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/configuration.svg b/wp-content/plugins/wp-rocket/assets/img/configuration.svg index 57095a8bc..c57019ad5 100644 --- a/wp-content/plugins/wp-rocket/assets/img/configuration.svg +++ b/wp-content/plugins/wp-rocket/assets/img/configuration.svg @@ -1,20 +1,12 @@ - - - - streamline-icon-show-hat-magician@24x24 - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + diff --git a/wp-content/plugins/wp-rocket/assets/img/heartbeat-hover.svg b/wp-content/plugins/wp-rocket/assets/img/heartbeat-hover.svg index bbb49d523..52dff42e7 100644 --- a/wp-content/plugins/wp-rocket/assets/img/heartbeat-hover.svg +++ b/wp-content/plugins/wp-rocket/assets/img/heartbeat-hover.svg @@ -1,5 +1 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/heartbeat.svg b/wp-content/plugins/wp-rocket/assets/img/heartbeat.svg index 6b580a59d..aa35a557a 100644 --- a/wp-content/plugins/wp-rocket/assets/img/heartbeat.svg +++ b/wp-content/plugins/wp-rocket/assets/img/heartbeat.svg @@ -1,5 +1 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/icon-128x128.png b/wp-content/plugins/wp-rocket/assets/img/icon-128x128.png index 0a863b92e0287cacc7b25809113e406dec3616c4..50d80491d58925b5b1beb592edb18dd18fae7ebe 100644 GIT binary patch literal 10719 zcmV<5DInH~P)f-fY-K}@Kr}q2ie!O-^M!feTqDo3x4Y)2Nqo%{S(6(zt zB9SV{!QBpVP?0<@{~v=oj#C+A@^e)X3zG5d5xpz$IdI($LNJ8ia9y_&a)a=Wl(h?^ z(K;gHR8L^q_B@?Pq&o6uh=YL2Kytiz2Ay`$c=0We=Tsz$q^EHaBEzXEw5}_b+4V)V zu#T|#c}GauKxn6K;y2Q%E$shZi-ef7 zq-=i~#RgqQ>0>Td=>a@nnjH;Z&aXY-{iWveahJ&0*ee)kS+V{i9&a*>W8`tc=or7c z59C375PYJ{9Pu+ve&sJ3zwS>8|M>?^_~Rp*ak8Mo=8j=Bj^yR}W&-bQh!5k%<3@)Y zC^j55?~51k0bHYEqfS+sy+uZD!k`)4ATU9NGXMy~ScS8%rlrHbwxf3zT1$dI(WF<_snA-km$}(L zFZ|n;f2#36y+rd1cp5ak&|X#_F)P#x_-FK2KaWL2lJ8hE&U52ox0uN-qTqpGM1#f>~2khmo4BW9&&%D3E#}s*#ixZ1w$crg}Men zx1N{F1~Bcm&s+0O*dT-MrtEPbw{&B6pv=Rj9kAo)_#KN;T*4-JgXWzqbbh zDd2TKL>1ER@~)nF4bH%M3_Js+MNBlWgkMfl8B-@`>UKx4Vfg>mQ$5!+-r+n=A{n~n zaXJ?MLrwUhgkZct$)>$<;=%hIoRnDs_ct}^L!tGsL$z*+N$c0es&7}fdAv7y$F?49 z=&on0jQKpqR-?;M1V}yrfS6KO2i-4d+M{hPt3To~>ZLl4Ap%6q<;gVNhH zrriuswwbY&KYxwpoGav^T~3k9Tgh^C8aRP@6Kh8v(*9AMmd%`O-JCe@06Fo@$%g%$ zrrj)5L2t)2+k)!~V*n3GDwlV+X_~#1GN%4W6W=NIh)$+h{?AGZf9H@H3TWNVvF*gp zOXZFLBq6V(Db@xeys2lM4Uu8WJ%~_R%-#75P5eBUGRH6HS}+A7Y#@e68aqy&?ELO; z(cFtlS;&pa@lmz~jls`PSPM@TGCml!AZ~>-0FuIfI*bj_gJ}Fa)~uU~J+hN182fPp zcgj6_krrl7r=v`>1+IJ<;y?kjc=!Am!9>)?AY;sLH1Wf|iLjA@Tw##s)q>-&F3zH8 zbDW**6xeb6#|@*ybft!VrKdbumZSl&28xJRlM4TKipq-3mvV3(QN=R=2*S8y)IUbb zF2YxyeYYnm)Lt-ScG@<%!@?Eif$NrsTAz3rL%~d3!|XJ3$)+}#NF(5 z|6W!Q4DypT`SsaEgG@dfHKn+MsyTec9wO@KBvw!O$D$M_BJ%l`Cchk2=JXsX`{m?h zwFV!4-KF5cFCd`?1?>2A(;9LrMWcW5?Mt$2z!TvIE?UInBe;v&r+Cp*72??};wYlw z->4}sxn2kEXXI{R<36GnDv_E0H#b)S9LKS3=QA@yn3?%U%xn;@w2~I4yJxf!o9$AV znVFfHOkrkD6i!UxNM_0V&slH(+H!q8>2Ar9^-?u4FHGM)_a5lkZnhu%r|N34IP^zE zj$Uu`;CY{}>HO8rRNSz{p>{&W| zkQ0sN_3M%+hm5@HIVpqoe6_$dm)2nib%PBMQl$eJ7tg^QalH`v1>5bIpCGZq6=I@90@3v@?s^ zvXgCU2Cz3h7!3Z?Y}eiMU-5yTGL;vt=1mv20Zz&gK-NC2YP1vT+?kVfOyCo6v6_Gy zCvgEH9eZK--#hG$t^cy`k`n&lX8(M-2{dqcWFhhW$2y4e{kc#?FUOc8zchu+yBRQ>q?UVVP&CsRbQ;C!H_P ziTQKr^#Kz(5^ZHCPSj(W18gfg8H+|$?_E=NC3pX7;q(m+gLHKHiKe+C2O0vUX+rO4 zD8TpUB2mP0Oy|xIncCRTDwF(QjDiCw#3#+PGY$>wV`fLAyZgSMK%$8$0D+%mK*-`08{l04He{K$2-Vqg;PR{$7CIPvHj?YME&Fr?8Rr=-Y3b z@(ZX+o&^3~Jq7`W_aFrEihtjUcJA}4s=Sm^E>T5VfIq72AI>*TnlzHbbs!+{0Vbja zSV@>{V4iB(4Z_6{kE!b82b8UR{3sZJFgdTk$FJ^npf1jVFvH>+#d!H6BGAeByPUqM z>XG{K^#<*03w!V?o%3P6ua2UYKv9a{Z=?y_@_)8LjiL>@?*G6Pdu~%&gD?;f|F%^} z%ajToK>8cDN3!nR0Q@Oy=9Xs|x7#eLBVS%t+5VcN$Bu*;K-7GEu zdLpLk64Jl<(da&S-G8xy*mz#fc)ws$f%{9+K@3m(JJGhnepR$sx)62{``Rsh&QWcL z_HhFK9ioio-t7Hk4ohI44k%KuErlOB3Vg2fUoOWiLKKKW+_6PCQVS$n5w#xhYi9nc zGB>PAiv?w_yI0lC`-^bw@IDk1+loLEpSb_5Di{p<|1{5p_SjDO8PA!@D+h&i(CPtn z=+4lM)2aaJ-6ObzHtoa3=|b-ZV(j;+DSDg*B=q!t00RI!%0(jAZ>*)CVP6!tzm;)}=jRpY+ z(m@P30$F(TP8eFKrya+hPCZ~G8pPixU#EKakg0a@@79Wxw~?5m8iQ0dP~<;d25qf%1GHE7nCXoUPQ} z9Aw_m)00dFn_eNFIBtCRAW6CYlC?38eNkoq&rc6cg`6- zTcAKH|7V_H3CyR}3HTQcyTS5d3K&fx zb?B)&7$PN-(7_aUZumY^GZT{NZdMQA4Npz{RG~N)sFwUK6F=j1Sz+i^Q+^5ZiqIt* z|D!XR9=80SIzbCQhp)mJU+Mf;?ROQ^Kd<6yCu%aS`^WEV;eS%J0P7C2FKhVmU8v;U zv@XLS_56^@5D!JX@gJI!8=clzA`(S=mb))`eju6nnYsP5UeyU}=x)0pIF^R~*kfdTwj$cBFgu#&g#(xY5>z#E;5-H!a~uFrZOecuGy_ zq1JG6GOfhjpUVFinW-o8?@9Q-rGKkb?q{>S=6VIxl)HahUkVnxg9g2_2WCz#D*9r$ zgFnL^TyNb$!4%E|99Mev^@oMb&a(lF-1*ezZRm2LH+9CK$`ln>y28*Guy+qO<`9NW ztVcm=Xj#bTrs(cu4q`|;X!h&kMWB%RGa>(S^H|zD=@7sQBQ`8*-NCPQ-dkd76a_qD zcQDpPJs`RB{=Ne-bUKeLu6|RrR31J_PZ$Ecuesl^HY_}*ez;4ySU%vt5nt2N{$1wl2NXiX+mv_`7fxsRvMKA+nH< zGx2ksY6$0m1_M|#h9ja1DA&$Z=lYTO z+2qN0KX={QbaMJhVdx6o5ZD)pM8T_1x9mvycQF#hgZ4axu>XHy@?Qw6aJdT6{c97r ze-nuS0(Y7R;b+mp)~XMZ+K-lo#h3(e@LW;GDV!-9wkEoox^hwJa}@2ZsPGT9z2!PKcM3A zeoIp`+&|Jkf%`YXEkNK7GS*xGcko(M--R1BuvW?SfaNfiTobPT7llGHl^1Xk>}v>R z-LJ3n>*lq4t?FG<^5A-H`?d@PmH|b46{-C1Xe{$-zv}D(&KA=7#=!kkMGNVf$lbq5 zPyp5)BxU2FkzUnWPj^rTl{P1r_2adsvFk9UYVjIx4{164^L^j*O72r8(mGp(!Z&+$ z^ML{@(y^pG&*ren0O!RgzF z)1s#d^Ctg=8WV0_q4GYE^8bYUr?Y<{DiR%uk}Z512>L%RXKP>l-*0kpph<*9-R4~w zmUt3$kh@2s+Y_SWhP$`;;ZF^ZdZlMCbFqt*s_%?MDxpslmqty+?WS(t&njcJP)o4( z?T?GSs*CAb+F3%89u+#uM{uZxkfnH5(SBdj&94E zhm+Ovvwsur2FlM4_M*~vQC<;!?_s$+80YY4xx3hFR|PK~tJL(w;)A<;;qb1#ZtKBE zL{$DGy85I6yNE)CkVvp5Em=8p&E2|g{(pkm5dH&!m@xZ431$FZsqWwmFR~XyB6J6B z8xZF9rFO5?+J_!7)6d*LqH}1rxS(51`nHEcdw9|4(G9L!4YlzVD^jH|DGTVI&iQ-} zqVs_N!}u%#wn?Jp@8#1=tvi^YgD3!=9sCtLAUzFVezQs0I&=uSje7(GtE5}}JRD9b zQtccyd5gVi=dTf3*6F8=GUzEheT-5i9YDo)priQVR1;4FR7zwW`5eGYOp|ZJpYo@XOgsw^Ut69Xd;$+YlAj$E#=21eD73r( z5rgL}NUa_$;4;zx2_Q`M=>58k@ zD0_3p4RWc{QTSO6m2XaF(r9S~{3lYx&Wyi#=cLLxn{Ka&KYv=Sa-7-!(%0^8Z;aWQ z8bO{?mB{BU6tn>m{1f&1Ot7&PLKM-E1z_QS^0xqyJLn#9wFz`!AR6+6qOgd4)oqX=0Z27b>Q z?Q!>Gft{oM9hRP48(V*C`B41M^7w|^$~P`Nv7z0`@pqUPb9XVwE%+$RdL69+Pk%N( z-t7s64yJMCe;^ydj6^UfcmF2s48SY(>|iHgImdMi-t$WDv_sc;!R)ut7`k=1sTC?; zCnR6SxH$vtHPt+rRfnyDB3m-2I|^%MSQ z0{Wd2e}{!9*0yiJ?%#ArISQbBIDS_}eBDjuYaUzB(Bw=rJ2P+Cj-A;SiDYRV4J?O( zI4sE>2;4s{aQ`Ne4j?}}NOy1*QaU5hLGewd)3`vlM4PofhWwtVhx$5^BK{9=ukWv` zdNQ&5Z!aIhg&!-1<9AoY-#>NAbxyXwPhV$vS3a3+mWdqVxL(2Y-W2hPrcuJAH~uq* zQl6Y93JTo6$>j#h-NC}=$KhmeLil-8|8IL&0o+EiwDmJHGaU2z7)`Q;<~YWHEndko zQ{u40=rHG)=`k}i9tVyY;#|zq?*8Am(&X*ilFPOpSoeEV)z!1J5S6>9r+M5D{S}DE z)laeC!Mz_@#P>B+&p&&t=#2V!2^l~JsIiBN6CHc6}v6hwOq6+k_Z*|!ddm- zU`}*DzdN3$GN_kKOo^woqtv7HqZG`%=-(_v2d!|3JP@wwWU{Ev98BBsLpvUd-wjO= z<9MXfxx<;mwiHe_e z6;qb5T?vMw)bkmme{)C)6!81{=wJ){;*1WaDQc-lG{*n zlya1IlzRH;-<*^H`siRUR$2`dqn*-%#&;0C6WhSdnn@LYpWZuq@fhB zvC=3S_At3JhkHMjzkZs2w}dW#acAix>YX6)F_%o@PaI1DoIm0q2DsuXnBc^YvIi}t zO;_|n0??O0DUgM@!so&jTN!7V{_o3HDb*<5DCK&M(Z9L91?W19dJ@sWJHvHt(=rEj z*~H%ommR$k$(3CQuX69#+`bi&|GInW!kVE&?$auXEEs@rGz9}3c8F_50Ukc&djD8w z{er9Of){jxnWC^NJW$|T5np&cWPMf^QfeCJAEg?l8>JkW$fiHsi-iH;vF>Q@`N?8HFXgX-Nb5;s0^$f2!r0>=VKc+L^?dOR^FtJo4= z+*5w9B^M?k6u|&|12hRQ^hI1>3zqK}1*Oy3o+#BQ-6-WK?ex*VIjsW-JwQYUc{B=E za^cgG>oL)1f6COVV9_HN!MV}_uN{fR=E}uz`}Ru>WrO?NFR57FX^Idw%|FdLxd*j>`8YjyA)+NR^B9$mlION$!~okde0swCOJbTjh(K>S;1u2KAZfEQFY-2UEf_mkS{-*1-z z#0e2ke1O+_u;HGV$C!AZT~_aOs_zcCpA6J`Zfk&P$)HlFL)UOnAbKhjG1LlA zqZ9pnpOajl7A+R7abf;kt{0Ow(>llO4Rc; zWA!s|L&p#8|D1aN^=}TizoQ-iA$JwZ<9iAd#ND05d$lpKeqPM!uK_k$J!n_o8Yudv zr4}w+5T7-CWH_Xn#+d9-8vUjGmXb7Jp3T3Le1f7sMR^ z5c8TqMiBP|bMTta>0t-&+2WJ}Csr0c0ngyoy~(^m#v8KW9{yCgatjD9%F2bb(wOu+ zkYW~p^DWEt(La*`rapI&8vW%k2hkn$(PZDfSn~WIc_PHD+L9wYQiY{n^wM$lGvnv( zNL|g~X50G;R`A$Bfg*@6fW#(nY@8R*rnslb_}-aq_IC!Ph4b03n93j-F97#213aue zP6ml$qEQ4RhxdnSJJ|Y#8Ade!4BEeG1*D1&vTl#bq8Gv%csx|y%ab?B1QfGsL~Ggp ze1CAUcM-gDOy1<)uf_aJqnAFty5vrEzm3F{^{ZGv7BJa8B5+Ba0}mba7mR%MjLC2S@!iN$ylES}%08yn_;6$MQ2qtz8#E!E*ms0{M|ClfFP zeI0rah~Ek9tbyrA3B_InEJU4J{F_^VfIr}BVHGc#fXWt2yOsm!g`>Zp`#wv$HOCM3 zWM8K*|J{v_<0=R>y4fm^ZXyP3%m?v+*XL{3BsT9&g>}Ghh`HqOMFc+Cd z%sAq2Boi>uBYr0>1QMTR-?VI|ul$)?0O5CqML2H*$XZm_P;)b0ffGoAQ)EI&r%o6UWNb> zMLos5(D39x=S`iXx5xK1%n@yxo(=7|9b zCQuaU1;=}e9NcN9=O7GGbU?nAhSh+d^uSmfRD|J}F za>JbNS$>=U$EhyIS85k{9nHw_p%hC0Y+o}YC~cr6K!1Q10xWn83j!({ z!3C@|U@=~97_ZXZU#+`Oz<78$7y$l;C%cLtwJZwfb;Hv~hm<(o>%$0Q@L>ZHIz~xZ z!+)a&?CM86RULyp`9tHYNG!nsGX%i^sX^g)$DwC@t*>&6r3Mu~(OEm)%lt@M2AF-1AdgxHz9QiDx?gH8{GO_<;2ilJF?lVB zEC}6AEQoAi1Owv?LjuV7#+xk#$Cr9MRSSX{;Q=(a0KouJWaMB)UUIWHXnm&5^)Xdj z$w>z20_cg`tpVpbC$N|o&*|@TURELgPqjI|T-E5eXMhLLv;qj+2EYUfk06>lvH;@; z(b7X|f}pY>s0M=Qoe3;NJH`Z#1>yC?7a;SSKWIWqI1Y(kHv1kx(-SB_R26G3;ZQW| z(}Aj0XWO#nQ4+i}N!%2`dwgcP&z)_}Q9d7-x4|Mw8F;?GnKJfQtPPk4zJtdSZ*5h<|v zu0YN5_gc}MvM0#|-8yLj7{@igY4JsG;{U<_i~py|02#CmFfWhZxeM5CHd47BgqO#3 zd;2gjnPRXtcj$4P5?<*K)wBh?b!aDFdtESG`Nd$xj**TWb*u-^wq+|xYeC^RhM)(0 zuBmeU`9A3;W&t-eWJHy(=?EeSQ;^5N(mQ8`OL&L0I55sb0*X;X` zX3f=YL2ofn3~vf~Z*B4WONxEL+Gm@bpNvxqwCBjfWPsLenM`x0HSf&!;NnI*>Jh1I zV%y0y2aqWNgiDxSx<2FvyxD9$L2(b_%bMu#&Q(uD9bc*Q`xl~)uZYE^z!&-f?DvCj zxKZf2=+!3M4}~9r@A4b3M+=|q@_6Pk??80w))?~82DW=)d-*a+at;I*HoxDI_eQ)+GZSMfVgS#zIX`}j zCtzdV0r&q5@&KAvfXEG?SZ1*(^Ys1&4I6&e?0zVYRZp>hrafo)<5Jc7d}#4Y607|@ z7IcalLv|#gBv^v&;MQQc;*(ADH=J$HnHa^p_z+)?g^M`$i z*t;l0?SGR21QC-W`d@hDn*>R~ZX!HAgbJS^z6H+$EP4<*hGZZ%dLR=~8ic*!^Lg?Z znTMuk25SGN6`;2UbW8wmU7~Xb-Nb_UlkMH2>R7zbcla)I4LBz8jgrH(0y5AV(7A^H zl!WX|5^lQ06Yq=8Bm~j?LEquav;s01NNCYnguwAkR<3wo013}I@s0ma@PFC`G5kc5 Rde8s>002ovPDHLkV1jBn`NRMK literal 11341 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 literal 4832 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 + + diff --git a/wp-content/plugins/wp-rocket/assets/img/icon-user-cache.svg b/wp-content/plugins/wp-rocket/assets/img/icon-user-cache.svg new file mode 100644 index 000000000..537826af3 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/img/icon-user-cache.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wp-content/plugins/wp-rocket/assets/img/imagify-hover.svg b/wp-content/plugins/wp-rocket/assets/img/imagify-hover.svg index babcf00f8..71069f2fe 100644 --- a/wp-content/plugins/wp-rocket/assets/img/imagify-hover.svg +++ b/wp-content/plugins/wp-rocket/assets/img/imagify-hover.svg @@ -1,31 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/imagify-info.svg b/wp-content/plugins/wp-rocket/assets/img/imagify-info.svg new file mode 100644 index 000000000..ca8389475 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/img/imagify-info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/imagify-install.svg b/wp-content/plugins/wp-rocket/assets/img/imagify-install.svg new file mode 100644 index 000000000..d9cac4d53 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/img/imagify-install.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/imagify-score.png b/wp-content/plugins/wp-rocket/assets/img/imagify-score.png new file mode 100644 index 0000000000000000000000000000000000000000..cde25d0f44fac04b9e2f5a5c2a40bc9462280a57 GIT binary patch literal 54956 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 literal 0 HcmV?d00001 diff --git a/wp-content/plugins/wp-rocket/assets/img/imagify.svg b/wp-content/plugins/wp-rocket/assets/img/imagify.svg index eab8de01d..4330643f6 100644 --- a/wp-content/plugins/wp-rocket/assets/img/imagify.svg +++ b/wp-content/plugins/wp-rocket/assets/img/imagify.svg @@ -1,31 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/infinite.svg b/wp-content/plugins/wp-rocket/assets/img/infinite.svg index eb78bc074..b283d4251 100644 --- a/wp-content/plugins/wp-rocket/assets/img/infinite.svg +++ b/wp-content/plugins/wp-rocket/assets/img/infinite.svg @@ -1,5 +1 @@ - - - - - + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-adblock.svg b/wp-content/plugins/wp-rocket/assets/img/logo-adblock.svg deleted file mode 100644 index 6bf79a07b..000000000 --- a/wp-content/plugins/wp-rocket/assets/img/logo-adblock.svg +++ /dev/null @@ -1,31 +0,0 @@ - - - - Group 15 - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-cloudflare.svg b/wp-content/plugins/wp-rocket/assets/img/logo-cloudflare.svg index cbf0bd1ed..1da5af777 100644 --- a/wp-content/plugins/wp-rocket/assets/img/logo-cloudflare.svg +++ b/wp-content/plugins/wp-rocket/assets/img/logo-cloudflare.svg @@ -1,24 +1 @@ - - -Logo cloudflare - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-cloudflare2.svg b/wp-content/plugins/wp-rocket/assets/img/logo-cloudflare2.svg index 6c828652e..f1241b917 100644 --- a/wp-content/plugins/wp-rocket/assets/img/logo-cloudflare2.svg +++ b/wp-content/plugins/wp-rocket/assets/img/logo-cloudflare2.svg @@ -1,24 +1 @@ - - -Logo cloudflare - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-facebook.svg b/wp-content/plugins/wp-rocket/assets/img/logo-facebook.svg deleted file mode 100644 index c42dc76ca..000000000 --- a/wp-content/plugins/wp-rocket/assets/img/logo-facebook.svg +++ /dev/null @@ -1 +0,0 @@ -flogo_RGB_HEX-114 \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-google-analytics.svg b/wp-content/plugins/wp-rocket/assets/img/logo-google-analytics.svg deleted file mode 100644 index 95a4a1555..000000000 --- a/wp-content/plugins/wp-rocket/assets/img/logo-google-analytics.svg +++ /dev/null @@ -1,166 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-sucuri.png b/wp-content/plugins/wp-rocket/assets/img/logo-sucuri.png index ed3a19912a7067ce289d2132591440a358109a84..da9818758c05d25d51f37ecdcf20c4f204ba7afc 100644 GIT binary patch literal 13153 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 literal 21221 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 UptG{|H2?qr07*qoM6N<$g0U6$B>(^b diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-varnish.svg b/wp-content/plugins/wp-rocket/assets/img/logo-varnish.svg index a68c4d7eb..31a5feee6 100644 --- a/wp-content/plugins/wp-rocket/assets/img/logo-varnish.svg +++ b/wp-content/plugins/wp-rocket/assets/img/logo-varnish.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-webp.svg b/wp-content/plugins/wp-rocket/assets/img/logo-webp.svg new file mode 100644 index 000000000..5f6afcc1b --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/img/logo-webp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-wprocket-dark.svg b/wp-content/plugins/wp-rocket/assets/img/logo-wprocket-dark.svg index 0e5612cd9..91efff47f 100644 --- a/wp-content/plugins/wp-rocket/assets/img/logo-wprocket-dark.svg +++ b/wp-content/plugins/wp-rocket/assets/img/logo-wprocket-dark.svg @@ -1,40 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/logo-wprocket-light.svg b/wp-content/plugins/wp-rocket/assets/img/logo-wprocket-light.svg deleted file mode 100644 index a96a01ac8..000000000 --- a/wp-content/plugins/wp-rocket/assets/img/logo-wprocket-light.svg +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/wp-content/plugins/wp-rocket/assets/img/one-com-logo.svg b/wp-content/plugins/wp-rocket/assets/img/one-com-logo.svg new file mode 100644 index 000000000..276e9becb --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/img/one-com-logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/wp-content/plugins/wp-rocket/assets/img/picto-wprocket-dark.svg b/wp-content/plugins/wp-rocket/assets/img/picto-wprocket-dark.svg index 5e0ac4599..b0e6e3ba8 100644 --- a/wp-content/plugins/wp-rocket/assets/img/picto-wprocket-dark.svg +++ b/wp-content/plugins/wp-rocket/assets/img/picto-wprocket-dark.svg @@ -1,39 +1 @@ - - - - Icons / WP Rocket / Light - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/picto-wprocket-light.svg b/wp-content/plugins/wp-rocket/assets/img/picto-wprocket-light.svg deleted file mode 100644 index fae7d2f72..000000000 --- a/wp-content/plugins/wp-rocket/assets/img/picto-wprocket-light.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/wp-content/plugins/wp-rocket/assets/img/play-alt.svg b/wp-content/plugins/wp-rocket/assets/img/play-alt.svg index b7d7b8bdc..4ca32724a 100644 --- a/wp-content/plugins/wp-rocket/assets/img/play-alt.svg +++ b/wp-content/plugins/wp-rocket/assets/img/play-alt.svg @@ -1,2 +1 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/play-hover.svg b/wp-content/plugins/wp-rocket/assets/img/play-hover.svg index 7e8b00c7e..c9f6f83e0 100644 --- a/wp-content/plugins/wp-rocket/assets/img/play-hover.svg +++ b/wp-content/plugins/wp-rocket/assets/img/play-hover.svg @@ -1,2 +1 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/play.svg b/wp-content/plugins/wp-rocket/assets/img/play.svg index c2765297f..0af490c59 100644 --- a/wp-content/plugins/wp-rocket/assets/img/play.svg +++ b/wp-content/plugins/wp-rocket/assets/img/play.svg @@ -1,2 +1 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/plus.svg b/wp-content/plugins/wp-rocket/assets/img/plus.svg index 2b78eaa75..f77148d34 100644 --- a/wp-content/plugins/wp-rocket/assets/img/plus.svg +++ b/wp-content/plugins/wp-rocket/assets/img/plus.svg @@ -1,12 +1 @@ - - - - - - - - - - - - + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/img/warning.svg b/wp-content/plugins/wp-rocket/assets/img/warning.svg index 33f5e44e5..01de968ef 100644 --- a/wp-content/plugins/wp-rocket/assets/img/warning.svg +++ b/wp-content/plugins/wp-rocket/assets/img/warning.svg @@ -1,14 +1 @@ - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/cpcss-removal.js b/wp-content/plugins/wp-rocket/assets/js/cpcss-removal.js index fd61292a0..cc55b4063 100644 --- a/wp-content/plugins/wp-rocket/assets/js/cpcss-removal.js +++ b/wp-content/plugins/wp-rocket/assets/js/cpcss-removal.js @@ -1,13 +1,20 @@ -const wprRemoveCPCSS = () => { - if ( document.querySelector( 'link[data-rocket-async="style"][rel="preload"]' ) ) { - setTimeout( wprRemoveCPCSS, 200 ); - } else { - const elem = document.getElementById( 'rocket-critical-css' ); - if ( elem && 'remove' in elem ) { - elem.remove(); +function wprRemoveCPCSS() { + let preload_stylesheets = document.querySelectorAll( 'link[data-rocket-async="style"][rel="preload"]' ); + if ( preload_stylesheets && preload_stylesheets.length > 0 ) { + for ( let stylesheet_index = 0;stylesheet_index < preload_stylesheets.length;stylesheet_index++ ){ + let media = preload_stylesheets[stylesheet_index].getAttribute('media') || 'all'; + if( window.matchMedia(media).matches ){ + setTimeout( wprRemoveCPCSS, 200 ); + return; + } } } -}; + + const elem = document.getElementById( 'rocket-critical-css' ); + if ( elem && 'remove' in elem ) { + elem.remove(); + } +} if ( window.addEventListener ) { window.addEventListener( 'load', wprRemoveCPCSS ); diff --git a/wp-content/plugins/wp-rocket/assets/js/cpcss-removal.min.js b/wp-content/plugins/wp-rocket/assets/js/cpcss-removal.min.js index 599a4d706..57fd10427 100644 --- a/wp-content/plugins/wp-rocket/assets/js/cpcss-removal.min.js +++ b/wp-content/plugins/wp-rocket/assets/js/cpcss-removal.min.js @@ -1 +1 @@ -"use strict";var wprRemoveCPCSS=function wprRemoveCPCSS(){var elem;document.querySelector('link[data-rocket-async="style"][rel="preload"]')?setTimeout(wprRemoveCPCSS,200):(elem=document.getElementById("rocket-critical-css"))&&"remove"in elem&&elem.remove()};window.addEventListener?window.addEventListener("load",wprRemoveCPCSS):window.attachEvent&&window.attachEvent("onload",wprRemoveCPCSS); \ No newline at end of file +"use strict";function wprRemoveCPCSS(){var preload_stylesheets=document.querySelectorAll('link[data-rocket-async="style"][rel="preload"]');if(preload_stylesheets&&0{const e=t.getBoundingClientRect();if(e.bottom>=0&&e.top<=window.innerHeight)try{this._animateElement(t)}catch(t){}})}_animateElement(t){const e=JSON.parse(t.dataset.settings),i=e._animation_delay||e.animation_delay||0,n=e[this.animationSettingKeys.find(t=>e[t])];if("none"===n)return void t.classList.remove("elementor-invisible");t.classList.remove(n),this.currentAnimation&&t.classList.remove(this.currentAnimation),this.currentAnimation=n;let s=setTimeout(()=>{t.classList.remove("elementor-invisible"),t.classList.add("animated",n),this._removeAnimationSettings(t,e)},i);window.addEventListener("rocket-startLoading",function(){clearTimeout(s)})}_listAnimationSettingsKeys(t="mobile"){const e=[""];switch(t){case"mobile":e.unshift("_mobile");case"tablet":e.unshift("_tablet");case"desktop":e.unshift("_desktop")}const i=[];return["animation","_animation"].forEach(t=>{e.forEach(e=>{i.push(t+e)})}),i}_removeAnimationSettings(t,e){this._listAnimationSettingsKeys().forEach(t=>delete e[t]),t.dataset.settings=JSON.stringify(e)}static run(){const t=new RocketElementorAnimation;requestAnimationFrame(t._detectAnimations.bind(t))}}document.addEventListener("DOMContentLoaded",RocketElementorAnimation.run); \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/heartbeat.js b/wp-content/plugins/wp-rocket/assets/js/heartbeat.js new file mode 100644 index 000000000..e69de29bb diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload-css.js b/wp-content/plugins/wp-rocket/assets/js/lazyload-css.js new file mode 100644 index 000000000..588d2c2f8 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lazyload-css.js @@ -0,0 +1,81 @@ +function rocket_css_lazyload_launch() { + + const usable_pairs = typeof rocket_pairs === 'undefined' ? [] : rocket_pairs; + + + const styleElement = document.querySelector('#wpr-lazyload-bg-container'); + + const threshold = rocket_lazyload_css_data.threshold || 300; + + const observer = new IntersectionObserver(entries => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const pairs = usable_pairs.filter(s => entry.target.matches(s.selector)); + pairs.map(pair => { + if (pair) { + styleElement.innerHTML += ``; + + pair.elements.forEach(el => { + // Stop observing the target element + observer.unobserve(el); + el.setAttribute(`data-rocket-lazy-bg-${pair.hash}`, 'loaded'); + }); + } + }) + } + }); + }, { + rootMargin: threshold + 'px' + }); + + function lazyload(e = []) { + + const pass = e.length > 0; + + if(! pass ) { + return; + } + + usable_pairs.forEach(pair => { + try { + + const elements = document.querySelectorAll(pair.selector); + elements.forEach(el => { + if(el.getAttribute(`data-rocket-lazy-bg-${pair.hash}`) === 'loaded') { + return; + } + observer.observe(el); + // Save el in the pair object (create a new empty array if it doesn't exist) + (pair.elements ||= []).push(el); + }); + } catch (error) { + console.error(error); + } + }); + } + + lazyload(); + + const observe_DOM = (function(){ + const MutationObserver = window.MutationObserver; + + return function( obj, callback ){ + if( !obj || obj.nodeType !== 1 ) return; + + // define a new observer + const mutationObserver = new MutationObserver(callback); + + // have the observer observe for changes in children + mutationObserver.observe( obj, { attributes: true, childList:true, subtree:true }) + return mutationObserver + + } + + })() + + const body = document.querySelector('body'); + + observe_DOM(body, lazyload) +} + +rocket_css_lazyload_launch(); \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload-css.js.min.map b/wp-content/plugins/wp-rocket/assets/js/lazyload-css.js.min.map new file mode 100644 index 000000000..2f0bdc0c9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lazyload-css.js.min.map @@ -0,0 +1 @@ +{"version":3,"names":[],"mappings":"","sources":["lazyload-css.js"],"sourcesContent":["!function o(n,c,s){function i(r,e){if(!c[r]){if(!n[r]){var t=\"function\"==typeof require&&require;if(!e&&t)return t(r,!0);if(a)return a(r,!0);throw(t=new Error(\"Cannot find module '\"+r+\"'\")).code=\"MODULE_NOT_FOUND\",t}t=c[r]={exports:{}},n[r][0].call(t.exports,function(e){return i(n[r][1][e]||e)},t,t.exports,o,n,c,s)}return c[r].exports}for(var a=\"function\"==typeof require&&require,e=0;e{e.forEach(r=>{if(r.isIntersecting){const e=rocket_pairs.filter(e=>r.target.matches(e.selector));e.map(e=>{e&&(t.innerHTML+=e.style,e.elements.forEach(e=>{e.setAttribute(\"data-rocket-lazy-bg\",\"loaded\"),o.unobserve(e)}))})}})},{rootMargin:r+\"px\"});e.forEach(r=>{try{const e=document.querySelectorAll(r.selector);e.forEach(e=>{o.observe(e),(r.elements||(r.elements=[])).push(e)})}catch(e){console.error(e)}})}()},{}]},{},[1]);"],"file":"lazyload-css.js"} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload-css.min.js b/wp-content/plugins/wp-rocket/assets/js/lazyload-css.min.js new file mode 100644 index 000000000..b0298f501 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lazyload-css.min.js @@ -0,0 +1,2 @@ +!function o(n,c,a){function u(t,e){if(!c[t]){if(!n[t]){var r="function"==typeof require&&require;if(!e&&r)return r(t,!0);if(s)return s(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}r=c[t]={exports:{}},n[t][0].call(r.exports,function(e){return u(n[t][1][e]||e)},r,r.exports,o,n,c,a)}return c[t].exports}for(var s="function"==typeof require&&require,e=0;e{var e=t.selector;document.querySelectorAll(e).forEach(e=>{e.setAttribute("data-rocket-lazy-bg-"+t.hash,"excluded")})}),document.querySelector("#wpr-lazyload-bg-container"));var o=rocket_lazyload_css_data.threshold||300;const u=new IntersectionObserver(e=>{e.forEach(t=>{t.isIntersecting&&c.filter(e=>t.target.matches(e.selector)).map(t=>{var e;t&&((e=document.createElement("style")).textContent=t.style,a.insertAdjacentElement("afterend",e),t.elements.forEach(e=>{u.unobserve(e),e.setAttribute("data-rocket-lazy-bg-"+t.hash,"loaded")}))})})},{rootMargin:o+"px"});function n(){0<(0{try{document.querySelectorAll(t.selector).forEach(e=>{"loaded"!==e.getAttribute("data-rocket-lazy-bg-"+t.hash)&&"excluded"!==e.getAttribute("data-rocket-lazy-bg-"+t.hash)&&(u.observe(e),(t.elements||=[]).push(e))})}catch(e){console.error(e)}})}n(),function(){const r=window.MutationObserver;return function(e,t){if(e&&1===e.nodeType)return(t=new r(t)).observe(e,{attributes:!0,childList:!0,subtree:!0}),t}}()(document.querySelector("body"),n)}},{}]},{},[1]); +//# sourceMappingURL=lazyload-css.min.js.map diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload-css.min.js.map b/wp-content/plugins/wp-rocket/assets/js/lazyload-css.min.js.map new file mode 100644 index 000000000..5ba3af90c --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lazyload-css.min.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"mappings":"","sources":["lazyload-css.min.js"],"sourcesContent":["!function o(n,c,a){function u(t,e){if(!c[t]){if(!n[t]){var r=\"function\"==typeof require&&require;if(!e&&r)return r(t,!0);if(s)return s(t,!0);throw(e=new Error(\"Cannot find module '\"+t+\"'\")).code=\"MODULE_NOT_FOUND\",e}r=c[t]={exports:{}},n[t][0].call(r.exports,function(e){return u(n[t][1][e]||e)},r,r.exports,o,n,c,a)}return c[t].exports}for(var s=\"function\"==typeof require&&require,e=0;e{var e=t.selector;document.querySelectorAll(e).forEach(e=>{e.setAttribute(\"data-rocket-lazy-bg-\"+t.hash,\"excluded\")})}),document.querySelector(\"#wpr-lazyload-bg-container\"));var o=rocket_lazyload_css_data.threshold||300;const u=new IntersectionObserver(e=>{e.forEach(t=>{t.isIntersecting&&c.filter(e=>t.target.matches(e.selector)).map(t=>{var e;t&&((e=document.createElement(\"style\")).textContent=t.style,a.insertAdjacentElement(\"afterend\",e),t.elements.forEach(e=>{u.unobserve(e),e.setAttribute(\"data-rocket-lazy-bg-\"+t.hash,\"loaded\")}))})})},{rootMargin:o+\"px\"});function n(){0<(0{try{document.querySelectorAll(t.selector).forEach(e=>{\"loaded\"!==e.getAttribute(\"data-rocket-lazy-bg-\"+t.hash)&&\"excluded\"!==e.getAttribute(\"data-rocket-lazy-bg-\"+t.hash)&&(u.observe(e),(t.elements||=[]).push(e))})}catch(e){console.error(e)}})}n(),function(){const r=window.MutationObserver;return function(e,t){if(e&&1===e.nodeType)return(t=new r(t)).observe(e,{attributes:!0,childList:!0,subtree:!0}),t}}()(document.querySelector(\"body\"),n)}},{}]},{},[1]);"],"file":"lazyload-css.min.js"} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload-scripts.js b/wp-content/plugins/wp-rocket/assets/js/lazyload-scripts.js deleted file mode 100644 index 1145806d6..000000000 --- a/wp-content/plugins/wp-rocket/assets/js/lazyload-scripts.js +++ /dev/null @@ -1,108 +0,0 @@ -class RocketLazyLoadScripts { - - constructor( triggerEvents, browser ) { - this.attrName = 'data-rocketlazyloadscript'; - this.browser = browser; - this.options = this.browser.options; - this.triggerEvents = triggerEvents; - this.userEventListener = this.triggerListener.bind( this ); - } - - /** - * Initializes the LazyLoad Scripts handler. - */ - init() { - this._addEventListener( this ); - } - - /** - * Resets the handler. - */ - reset() { - this._removeEventListener( this ); - } - - /** - * Adds a listener for each of the configured user interactivity event type. When an even is triggered, it invokes - * the triggerListener() method. - * - * @private - * - * @param self Instance of this object. - */ - _addEventListener( self ) { - this.triggerEvents.forEach( - eventName => window.addEventListener( eventName, self.userEventListener, self.options ) - ); - } - - /** - * Removes the listener for each of the configured user interactivity event type. - * - * @private - * - * @param self Instance of this object. - */ - _removeEventListener( self ) { - this.triggerEvents.forEach( - eventName => window.removeEventListener( eventName, self.userEventListener, self.options ) - ); - } - - /** - * Loads the script's src from the data attribute, which will then trigger the browser to request and - * load the script. - */ - _loadScriptSrc() { - const scripts = document.querySelectorAll( `script[${ this.attrName }]` ); - - if ( 0 === scripts.length ) { - this.reset(); - return; - } - - Array.prototype.slice.call( scripts ).forEach( elem => { - const scriptSrc = elem.getAttribute( this.attrName ); - - elem.setAttribute( 'src', scriptSrc ); - elem.removeAttribute( this.attrName ); - } ); - - this.reset(); - } - - /** - * Window event listener - when triggered, invokes the load script src handler and then resets. - */ - triggerListener() { - this._loadScriptSrc(); - this._removeEventListener( this ); - } - - /** - * Named static constructor to encapsulate how to create the object. - */ - static run() { - // Bail out if the browser checker does not exist. - if ( ! RocketBrowserCompatibilityChecker ) { - return; - } - - const options = { - passive: true - }; - const browser = new RocketBrowserCompatibilityChecker( options ); - const instance = new RocketLazyLoadScripts( - [ - 'keydown', - 'mouseover', - 'touchmove', - 'touchstart' - ], - browser - ); - instance.init(); - } -} - -RocketLazyLoadScripts.run(); diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload-scripts.min.js b/wp-content/plugins/wp-rocket/assets/js/lazyload-scripts.min.js index 4612e759d..2f412626d 100644 --- a/wp-content/plugins/wp-rocket/assets/js/lazyload-scripts.min.js +++ b/wp-content/plugins/wp-rocket/assets/js/lazyload-scripts.min.js @@ -1,3 +1 @@ -(function() { -"use strict";var e=function(){function n(e,t){for(var r=0;r{class RocketLazyLoadScripts{constructor(){this.v="1.2.6",this.triggerEvents=["keydown","mousedown","mousemove","touchmove","touchstart","touchend","wheel"],this.userEventHandler=this.t.bind(this),this.touchStartHandler=this.i.bind(this),this.touchMoveHandler=this.o.bind(this),this.touchEndHandler=this.h.bind(this),this.clickHandler=this.u.bind(this),this.interceptedClicks=[],this.interceptedClickListeners=[],this.l(this),window.addEventListener("pageshow",(t=>{this.persisted=t.persisted,this.everythingLoaded&&this.m()})),this.CSPIssue=sessionStorage.getItem("rocketCSPIssue"),document.addEventListener("securitypolicyviolation",(t=>{this.CSPIssue||"script-src-elem"!==t.violatedDirective||"data"!==t.blockedURI||(this.CSPIssue=!0,sessionStorage.setItem("rocketCSPIssue",!0))})),document.addEventListener("DOMContentLoaded",(()=>{this.k()})),this.delayedScripts={normal:[],async:[],defer:[]},this.trash=[],this.allJQueries=[]}p(t){document.hidden?t.t():(this.triggerEvents.forEach((e=>window.addEventListener(e,t.userEventHandler,{passive:!0}))),window.addEventListener("touchstart",t.touchStartHandler,{passive:!0}),window.addEventListener("mousedown",t.touchStartHandler),document.addEventListener("visibilitychange",t.userEventHandler))}_(){this.triggerEvents.forEach((t=>window.removeEventListener(t,this.userEventHandler,{passive:!0}))),document.removeEventListener("visibilitychange",this.userEventHandler)}i(t){"HTML"!==t.target.tagName&&(window.addEventListener("touchend",this.touchEndHandler),window.addEventListener("mouseup",this.touchEndHandler),window.addEventListener("touchmove",this.touchMoveHandler,{passive:!0}),window.addEventListener("mousemove",this.touchMoveHandler),t.target.addEventListener("click",this.clickHandler),this.L(t.target,!0),this.S(t.target,"onclick","rocket-onclick"),this.C())}o(t){window.removeEventListener("touchend",this.touchEndHandler),window.removeEventListener("mouseup",this.touchEndHandler),window.removeEventListener("touchmove",this.touchMoveHandler,{passive:!0}),window.removeEventListener("mousemove",this.touchMoveHandler),t.target.removeEventListener("click",this.clickHandler),this.L(t.target,!1),this.S(t.target,"rocket-onclick","onclick"),this.M()}h(){window.removeEventListener("touchend",this.touchEndHandler),window.removeEventListener("mouseup",this.touchEndHandler),window.removeEventListener("touchmove",this.touchMoveHandler,{passive:!0}),window.removeEventListener("mousemove",this.touchMoveHandler)}u(t){t.target.removeEventListener("click",this.clickHandler),this.L(t.target,!1),this.S(t.target,"rocket-onclick","onclick"),this.interceptedClicks.push(t),t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation(),this.M()}O(){window.removeEventListener("touchstart",this.touchStartHandler,{passive:!0}),window.removeEventListener("mousedown",this.touchStartHandler),this.interceptedClicks.forEach((t=>{t.target.dispatchEvent(new MouseEvent("click",{view:t.view,bubbles:!0,cancelable:!0}))}))}l(t){EventTarget.prototype.addEventListenerWPRocketBase=EventTarget.prototype.addEventListener,EventTarget.prototype.addEventListener=function(e,i,o){"click"!==e||t.windowLoaded||i===t.clickHandler||t.interceptedClickListeners.push({target:this,func:i,options:o}),(this||window).addEventListenerWPRocketBase(e,i,o)}}L(t,e){this.interceptedClickListeners.forEach((i=>{i.target===t&&(e?t.removeEventListener("click",i.func,i.options):t.addEventListener("click",i.func,i.options))})),t.parentNode!==document.documentElement&&this.L(t.parentNode,e)}D(){return new Promise((t=>{this.P?this.M=t:t()}))}C(){this.P=!0}M(){this.P=!1}S(t,e,i){t.hasAttribute&&t.hasAttribute(e)&&(event.target.setAttribute(i,event.target.getAttribute(e)),event.target.removeAttribute(e))}t(){this._(this),"loading"===document.readyState?document.addEventListener("DOMContentLoaded",this.R.bind(this)):this.R()}k(){let t=[];document.querySelectorAll("script[type=rocketlazyloadscript][data-rocket-src]").forEach((e=>{let i=e.getAttribute("data-rocket-src");if(i&&!i.startsWith("data:")){0===i.indexOf("//")&&(i=location.protocol+i);try{const o=new URL(i).origin;o!==location.origin&&t.push({src:o,crossOrigin:e.crossOrigin||"module"===e.getAttribute("data-rocket-type")})}catch(t){}}})),t=[...new Map(t.map((t=>[JSON.stringify(t),t]))).values()],this.T(t,"preconnect")}async R(){this.lastBreath=Date.now(),this.j(this),this.F(this),this.I(),this.W(),this.q(),await this.A(this.delayedScripts.normal),await this.A(this.delayedScripts.defer),await this.A(this.delayedScripts.async);try{await this.U(),await this.H(this),await this.J()}catch(t){console.error(t)}window.dispatchEvent(new Event("rocket-allScriptsLoaded")),this.everythingLoaded=!0,this.D().then((()=>{this.O()})),this.N()}W(){document.querySelectorAll("script[type=rocketlazyloadscript]").forEach((t=>{t.hasAttribute("data-rocket-src")?t.hasAttribute("async")&&!1!==t.async?this.delayedScripts.async.push(t):t.hasAttribute("defer")&&!1!==t.defer||"module"===t.getAttribute("data-rocket-type")?this.delayedScripts.defer.push(t):this.delayedScripts.normal.push(t):this.delayedScripts.normal.push(t)}))}async B(t){if(await this.G(),!0!==t.noModule||!("noModule"in HTMLScriptElement.prototype))return new Promise((e=>{let i;function o(){(i||t).setAttribute("data-rocket-status","executed"),e()}try{if(navigator.userAgent.indexOf("Firefox/")>0||""===navigator.vendor||this.CSPIssue)i=document.createElement("script"),[...t.attributes].forEach((t=>{let e=t.nodeName;"type"!==e&&("data-rocket-type"===e&&(e="type"),"data-rocket-src"===e&&(e="src"),i.setAttribute(e,t.nodeValue))})),t.text&&(i.text=t.text),i.hasAttribute("src")?(i.addEventListener("load",o),i.addEventListener("error",(function(){i.setAttribute("data-rocket-status","failed-network"),e()})),setTimeout((()=>{i.isConnected||e()}),1)):(i.text=t.text,o()),t.parentNode.replaceChild(i,t);else{const i=t.getAttribute("data-rocket-type"),s=t.getAttribute("data-rocket-src");i?(t.type=i,t.removeAttribute("data-rocket-type")):t.removeAttribute("type"),t.addEventListener("load",o),t.addEventListener("error",(i=>{this.CSPIssue&&i.target.src.startsWith("data:")?(console.log("WPRocket: data-uri blocked by CSP -> fallback"),t.removeAttribute("src"),this.B(t).then(e)):(t.setAttribute("data-rocket-status","failed-network"),e())})),s?(t.removeAttribute("data-rocket-src"),t.src=s):t.src="data:text/javascript;base64,"+window.btoa(unescape(encodeURIComponent(t.text)))}}catch(i){t.setAttribute("data-rocket-status","failed-transform"),e()}}));t.setAttribute("data-rocket-status","skipped")}async A(t){const e=t.shift();return e&&e.isConnected?(await this.B(e),this.A(t)):Promise.resolve()}q(){this.T([...this.delayedScripts.normal,...this.delayedScripts.defer,...this.delayedScripts.async],"preload")}T(t,e){var i=document.createDocumentFragment();t.forEach((t=>{const o=t.getAttribute&&t.getAttribute("data-rocket-src")||t.src;if(o&&!o.startsWith("data:")){const s=document.createElement("link");s.href=o,s.rel=e,"preconnect"!==e&&(s.as="script"),t.getAttribute&&"module"===t.getAttribute("data-rocket-type")&&(s.crossOrigin=!0),t.crossOrigin&&(s.crossOrigin=t.crossOrigin),t.integrity&&(s.integrity=t.integrity),i.appendChild(s),this.trash.push(s)}})),document.head.appendChild(i)}j(t){let e={};function i(i,o){return e[o].eventsToRewrite.indexOf(i)>=0&&!t.everythingLoaded?"rocket-"+i:i}function o(t,o){!function(t){e[t]||(e[t]={originalFunctions:{add:t.addEventListener,remove:t.removeEventListener},eventsToRewrite:[]},t.addEventListener=function(){arguments[0]=i(arguments[0],t),e[t].originalFunctions.add.apply(t,arguments)},t.removeEventListener=function(){arguments[0]=i(arguments[0],t),e[t].originalFunctions.remove.apply(t,arguments)})}(t),e[t].eventsToRewrite.push(o)}function s(e,i){let o=e[i];e[i]=null,Object.defineProperty(e,i,{get:()=>o||function(){},set(s){t.everythingLoaded?o=s:e["rocket"+i]=o=s}})}o(document,"DOMContentLoaded"),o(window,"DOMContentLoaded"),o(window,"load"),o(window,"pageshow"),o(document,"readystatechange"),s(document,"onreadystatechange"),s(window,"onload"),s(window,"onpageshow");try{Object.defineProperty(document,"readyState",{get:()=>t.rocketReadyState,set(e){t.rocketReadyState=e},configurable:!0}),document.readyState="loading"}catch(t){console.log("WPRocket DJE readyState conflict, bypassing")}}F(t){let e;function i(e){return t.everythingLoaded?e:e.split(" ").map((t=>"load"===t||0===t.indexOf("load.")?"rocket-jquery-load":t)).join(" ")}function o(o){function s(t){const e=o.fn[t];o.fn[t]=o.fn.init.prototype[t]=function(){return this[0]===window&&("string"==typeof arguments[0]||arguments[0]instanceof String?arguments[0]=i(arguments[0]):"object"==typeof arguments[0]&&Object.keys(arguments[0]).forEach((t=>{const e=arguments[0][t];delete arguments[0][t],arguments[0][i(t)]=e}))),e.apply(this,arguments),this}}o&&o.fn&&!t.allJQueries.includes(o)&&(o.fn.ready=o.fn.init.prototype.ready=function(e){return t.domReadyFired?e.bind(document)(o):document.addEventListener("rocket-DOMContentLoaded",(()=>e.bind(document)(o))),o([])},s("on"),s("one"),t.allJQueries.push(o)),e=o}o(window.jQuery),Object.defineProperty(window,"jQuery",{get:()=>e,set(t){o(t)}})}async H(t){const e=document.querySelector("script[data-webpack]");e&&(await async function(){return new Promise((t=>{e.addEventListener("load",t),e.addEventListener("error",t)}))}(),await t.K(),await t.H(t))}async U(){this.domReadyFired=!0;try{document.readyState="interactive"}catch(t){}await this.G(),document.dispatchEvent(new Event("rocket-readystatechange")),await this.G(),document.rocketonreadystatechange&&document.rocketonreadystatechange(),await this.G(),document.dispatchEvent(new Event("rocket-DOMContentLoaded")),await this.G(),window.dispatchEvent(new Event("rocket-DOMContentLoaded"))}async J(){try{document.readyState="complete"}catch(t){}await this.G(),document.dispatchEvent(new Event("rocket-readystatechange")),await this.G(),document.rocketonreadystatechange&&document.rocketonreadystatechange(),await this.G(),window.dispatchEvent(new Event("rocket-load")),await this.G(),window.rocketonload&&window.rocketonload(),await this.G(),this.allJQueries.forEach((t=>t(window).trigger("rocket-jquery-load"))),await this.G();const t=new Event("rocket-pageshow");t.persisted=this.persisted,window.dispatchEvent(t),await this.G(),window.rocketonpageshow&&window.rocketonpageshow({persisted:this.persisted}),this.windowLoaded=!0}m(){document.onreadystatechange&&document.onreadystatechange(),window.onload&&window.onload(),window.onpageshow&&window.onpageshow({persisted:this.persisted})}I(){const t=new Map;document.write=document.writeln=function(e){const i=document.currentScript;i||console.error("WPRocket unable to document.write this: "+e);const o=document.createRange(),s=i.parentElement;let n=t.get(i);void 0===n&&(n=i.nextSibling,t.set(i,n));const c=document.createDocumentFragment();o.setStart(c,0),c.appendChild(o.createContextualFragment(e)),s.insertBefore(c,n)}}async G(){Date.now()-this.lastBreath>45&&(await this.K(),this.lastBreath=Date.now())}async K(){return document.hidden?new Promise((t=>setTimeout(t))):new Promise((t=>requestAnimationFrame(t)))}N(){this.trash.forEach((t=>t.remove()))}static run(){const t=new RocketLazyLoadScripts;t.p(t)}}RocketLazyLoadScripts.run()})(); \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload/17.5/lazyload.js b/wp-content/plugins/wp-rocket/assets/js/lazyload/17.5/lazyload.js new file mode 100644 index 000000000..a1bf5c100 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lazyload/17.5/lazyload.js @@ -0,0 +1,813 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.LazyLoad = factory()); + }(this, (function () { 'use strict'; + + function _extends() { + _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); + } + + var runningOnBrowser = typeof window !== "undefined"; + var isBot = runningOnBrowser && !("onscroll" in window) || typeof navigator !== "undefined" && /(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent); + var supportsIntersectionObserver = runningOnBrowser && "IntersectionObserver" in window; + var supportsClassList = runningOnBrowser && "classList" in document.createElement("p"); + var isHiDpi = runningOnBrowser && window.devicePixelRatio > 1; + + var defaultSettings = { + elements_selector: ".lazy", + container: isBot || runningOnBrowser ? document : null, + threshold: 300, + thresholds: null, + data_src: "src", + data_srcset: "srcset", + data_sizes: "sizes", + data_bg: "bg", + data_bg_hidpi: "bg-hidpi", + data_bg_multi: "bg-multi", + data_bg_multi_hidpi: "bg-multi-hidpi", + data_poster: "poster", + class_applied: "applied", + class_loading: "loading", + class_loaded: "loaded", + class_error: "error", + class_entered: "entered", + class_exited: "exited", + unobserve_completed: true, + unobserve_entered: false, + cancel_on_exit: true, + callback_enter: null, + callback_exit: null, + callback_applied: null, + callback_loading: null, + callback_loaded: null, + callback_error: null, + callback_finish: null, + callback_cancel: null, + use_native: false + }; + var getExtendedSettings = function getExtendedSettings(customSettings) { + return _extends({}, defaultSettings, customSettings); + }; + + /* Creates instance and notifies it through the window element */ + var createInstance = function createInstance(classObj, options) { + var event; + var eventString = "LazyLoad::Initialized"; + var instance = new classObj(options); + + try { + // Works in modern browsers + event = new CustomEvent(eventString, { + detail: { + instance: instance + } + }); + } catch (err) { + // Works in Internet Explorer (all versions) + event = document.createEvent("CustomEvent"); + event.initCustomEvent(eventString, false, false, { + instance: instance + }); + } + + window.dispatchEvent(event); + }; + /* Auto initialization of one or more instances of lazyload, depending on the + options passed in (plain object or an array) */ + + + var autoInitialize = function autoInitialize(classObj, options) { + if (!options) { + return; + } + + if (!options.length) { + // Plain object + createInstance(classObj, options); + } else { + // Array of objects + for (var i = 0, optionsItem; optionsItem = options[i]; i += 1) { + createInstance(classObj, optionsItem); + } + } + }; + + var SRC = "src"; + var SRCSET = "srcset"; + var SIZES = "sizes"; + var POSTER = "poster"; + var ORIGINALS = "llOriginalAttrs"; + + var statusLoading = "loading"; + var statusLoaded = "loaded"; + var statusApplied = "applied"; + var statusEntered = "entered"; + var statusError = "error"; + var statusNative = "native"; + + var dataPrefix = "data-"; + var statusDataName = "ll-status"; + var getData = function getData(element, attribute) { + return element.getAttribute(dataPrefix + attribute); + }; + var setData = function setData(element, attribute, value) { + var attrName = dataPrefix + attribute; + + if (value === null) { + element.removeAttribute(attrName); + return; + } + + element.setAttribute(attrName, value); + }; + var getStatus = function getStatus(element) { + return getData(element, statusDataName); + }; + var setStatus = function setStatus(element, status) { + return setData(element, statusDataName, status); + }; + var resetStatus = function resetStatus(element) { + return setStatus(element, null); + }; + var hasEmptyStatus = function hasEmptyStatus(element) { + return getStatus(element) === null; + }; + var hasStatusLoading = function hasStatusLoading(element) { + return getStatus(element) === statusLoading; + }; + var hasStatusError = function hasStatusError(element) { + return getStatus(element) === statusError; + }; + var hasStatusNative = function hasStatusNative(element) { + return getStatus(element) === statusNative; + }; + var statusesAfterLoading = [statusLoading, statusLoaded, statusApplied, statusError]; + var hadStartedLoading = function hadStartedLoading(element) { + return statusesAfterLoading.indexOf(getStatus(element)) >= 0; + }; + + var safeCallback = function safeCallback(callback, arg1, arg2, arg3) { + if (!callback) { + return; + } + + if (arg3 !== undefined) { + callback(arg1, arg2, arg3); + return; + } + + if (arg2 !== undefined) { + callback(arg1, arg2); + return; + } + + callback(arg1); + }; + + var addClass = function addClass(element, className) { + if (supportsClassList) { + element.classList.add(className); + return; + } + + element.className += (element.className ? " " : "") + className; + }; + var removeClass = function removeClass(element, className) { + if (supportsClassList) { + element.classList.remove(className); + return; + } + + element.className = element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), " ").replace(/^\s+/, "").replace(/\s+$/, ""); + }; + + var addTempImage = function addTempImage(element) { + element.llTempImage = document.createElement("IMG"); + }; + var deleteTempImage = function deleteTempImage(element) { + delete element.llTempImage; + }; + var getTempImage = function getTempImage(element) { + return element.llTempImage; + }; + + var unobserve = function unobserve(element, instance) { + if (!instance) return; + var observer = instance._observer; + if (!observer) return; + observer.unobserve(element); + }; + var resetObserver = function resetObserver(observer) { + observer.disconnect(); + }; + var unobserveEntered = function unobserveEntered(element, settings, instance) { + if (settings.unobserve_entered) unobserve(element, instance); + }; + + var updateLoadingCount = function updateLoadingCount(instance, delta) { + if (!instance) return; + instance.loadingCount += delta; + }; + var decreaseToLoadCount = function decreaseToLoadCount(instance) { + if (!instance) return; + instance.toLoadCount -= 1; + }; + var setToLoadCount = function setToLoadCount(instance, value) { + if (!instance) return; + instance.toLoadCount = value; + }; + var isSomethingLoading = function isSomethingLoading(instance) { + return instance.loadingCount > 0; + }; + var haveElementsToLoad = function haveElementsToLoad(instance) { + return instance.toLoadCount > 0; + }; + + var getSourceTags = function getSourceTags(parentTag) { + var sourceTags = []; + + for (var i = 0, childTag; childTag = parentTag.children[i]; i += 1) { + if (childTag.tagName === "SOURCE") { + sourceTags.push(childTag); + } + } + + return sourceTags; + }; + + var forEachPictureSource = function forEachPictureSource(element, fn) { + var parent = element.parentNode; + + if (!parent || parent.tagName !== "PICTURE") { + return; + } + + var sourceTags = getSourceTags(parent); + sourceTags.forEach(fn); + }; + var forEachVideoSource = function forEachVideoSource(element, fn) { + var sourceTags = getSourceTags(element); + sourceTags.forEach(fn); + }; + + var attrsSrc = [SRC]; + var attrsSrcPoster = [SRC, POSTER]; + var attrsSrcSrcsetSizes = [SRC, SRCSET, SIZES]; + var hasOriginalAttrs = function hasOriginalAttrs(element) { + return !!element[ORIGINALS]; + }; + var getOriginalAttrs = function getOriginalAttrs(element) { + return element[ORIGINALS]; + }; + var deleteOriginalAttrs = function deleteOriginalAttrs(element) { + return delete element[ORIGINALS]; + }; // ## SAVE ## + + var setOriginalsObject = function setOriginalsObject(element, attributes) { + if (hasOriginalAttrs(element)) { + return; + } + + var originals = {}; + attributes.forEach(function (attribute) { + originals[attribute] = element.getAttribute(attribute); + }); + element[ORIGINALS] = originals; + }; + var saveOriginalBackgroundStyle = function saveOriginalBackgroundStyle(element) { + if (hasOriginalAttrs(element)) { + return; + } + + element[ORIGINALS] = { + backgroundImage: element.style.backgroundImage + }; + }; // ## RESTORE ## + + var setOrResetAttribute = function setOrResetAttribute(element, attrName, value) { + if (!value) { + element.removeAttribute(attrName); + return; + } + + element.setAttribute(attrName, value); + }; + + var restoreOriginalAttrs = function restoreOriginalAttrs(element, attributes) { + if (!hasOriginalAttrs(element)) { + return; + } + + var originals = getOriginalAttrs(element); + attributes.forEach(function (attribute) { + setOrResetAttribute(element, attribute, originals[attribute]); + }); + }; + var restoreOriginalBgImage = function restoreOriginalBgImage(element) { + if (!hasOriginalAttrs(element)) { + return; + } + + var originals = getOriginalAttrs(element); + element.style.backgroundImage = originals.backgroundImage; + }; + + var manageApplied = function manageApplied(element, settings, instance) { + addClass(element, settings.class_applied); + setStatus(element, statusApplied); // Instance is not provided when loading is called from static class + + if (!instance) return; + + if (settings.unobserve_completed) { + // Unobserve now because we can't do it on load + unobserve(element, settings); + } + + safeCallback(settings.callback_applied, element, instance); + }; + var manageLoading = function manageLoading(element, settings, instance) { + addClass(element, settings.class_loading); + setStatus(element, statusLoading); // Instance is not provided when loading is called from static class + + if (!instance) return; + updateLoadingCount(instance, +1); + safeCallback(settings.callback_loading, element, instance); + }; + var setAttributeIfValue = function setAttributeIfValue(element, attrName, value) { + if (!value) { + return; + } + + element.setAttribute(attrName, value); + }; + var setImageAttributes = function setImageAttributes(element, settings) { + setAttributeIfValue(element, SIZES, getData(element, settings.data_sizes)); + setAttributeIfValue(element, SRCSET, getData(element, settings.data_srcset)); + setAttributeIfValue(element, SRC, getData(element, settings.data_src)); + }; + var setSourcesImg = function setSourcesImg(imgEl, settings) { + forEachPictureSource(imgEl, function (sourceTag) { + setOriginalsObject(sourceTag, attrsSrcSrcsetSizes); + setImageAttributes(sourceTag, settings); + }); + setOriginalsObject(imgEl, attrsSrcSrcsetSizes); + setImageAttributes(imgEl, settings); + }; + var setSourcesIframe = function setSourcesIframe(iframe, settings) { + setOriginalsObject(iframe, attrsSrc); + setAttributeIfValue(iframe, SRC, getData(iframe, settings.data_src)); + }; + var setSourcesVideo = function setSourcesVideo(videoEl, settings) { + forEachVideoSource(videoEl, function (sourceEl) { + setOriginalsObject(sourceEl, attrsSrc); + setAttributeIfValue(sourceEl, SRC, getData(sourceEl, settings.data_src)); + }); + setOriginalsObject(videoEl, attrsSrcPoster); + setAttributeIfValue(videoEl, POSTER, getData(videoEl, settings.data_poster)); + setAttributeIfValue(videoEl, SRC, getData(videoEl, settings.data_src)); + videoEl.load(); + }; + var setBackground = function setBackground(element, settings, instance) { + var bg1xValue = getData(element, settings.data_bg); + var bgHiDpiValue = getData(element, settings.data_bg_hidpi); + var bgDataValue = isHiDpi && bgHiDpiValue ? bgHiDpiValue : bg1xValue; + if (!bgDataValue) return; + element.style.backgroundImage = "url(\"".concat(bgDataValue, "\")"); + getTempImage(element).setAttribute(SRC, bgDataValue); + manageLoading(element, settings, instance); + }; // NOTE: THE TEMP IMAGE TRICK CANNOT BE DONE WITH data-multi-bg + // BECAUSE INSIDE ITS VALUES MUST BE WRAPPED WITH URL() AND ONE OF THEM + // COULD BE A GRADIENT BACKGROUND IMAGE + + var setMultiBackground = function setMultiBackground(element, settings, instance) { + var bg1xValue = getData(element, settings.data_bg_multi); + var bgHiDpiValue = getData(element, settings.data_bg_multi_hidpi); + var bgDataValue = isHiDpi && bgHiDpiValue ? bgHiDpiValue : bg1xValue; + + if (!bgDataValue) { + return; + } + + element.style.backgroundImage = bgDataValue; + manageApplied(element, settings, instance); + }; + var setSourcesFunctions = { + IMG: setSourcesImg, + IFRAME: setSourcesIframe, + VIDEO: setSourcesVideo + }; + var setSourcesNative = function setSourcesNative(element, settings) { + var setSourcesFunction = setSourcesFunctions[element.tagName]; + + if (!setSourcesFunction) { + return; + } + + setSourcesFunction(element, settings); + }; + var setSources = function setSources(element, settings, instance) { + var setSourcesFunction = setSourcesFunctions[element.tagName]; + + if (!setSourcesFunction) { + return; + } + + setSourcesFunction(element, settings); + manageLoading(element, settings, instance); + }; + + var elementsWithLoadEvent = ["IMG", "IFRAME", "VIDEO"]; + var hasLoadEvent = function hasLoadEvent(element) { + return elementsWithLoadEvent.indexOf(element.tagName) > -1; + }; + var checkFinish = function checkFinish(settings, instance) { + if (instance && !isSomethingLoading(instance) && !haveElementsToLoad(instance)) { + safeCallback(settings.callback_finish, instance); + } + }; + var addEventListener = function addEventListener(element, eventName, handler) { + element.addEventListener(eventName, handler); + element.llEvLisnrs[eventName] = handler; + }; + var removeEventListener = function removeEventListener(element, eventName, handler) { + element.removeEventListener(eventName, handler); + }; + var hasEventListeners = function hasEventListeners(element) { + return !!element.llEvLisnrs; + }; + var addEventListeners = function addEventListeners(element, loadHandler, errorHandler) { + if (!hasEventListeners(element)) element.llEvLisnrs = {}; + var loadEventName = element.tagName === "VIDEO" ? "loadeddata" : "load"; + addEventListener(element, loadEventName, loadHandler); + addEventListener(element, "error", errorHandler); + }; + var removeEventListeners = function removeEventListeners(element) { + if (!hasEventListeners(element)) { + return; + } + + var eventListeners = element.llEvLisnrs; + + for (var eventName in eventListeners) { + var handler = eventListeners[eventName]; + removeEventListener(element, eventName, handler); + } + + delete element.llEvLisnrs; + }; + var doneHandler = function doneHandler(element, settings, instance) { + deleteTempImage(element); + updateLoadingCount(instance, -1); + decreaseToLoadCount(instance); + removeClass(element, settings.class_loading); + + if (settings.unobserve_completed) { + unobserve(element, instance); + } + }; + var loadHandler = function loadHandler(event, element, settings, instance) { + var goingNative = hasStatusNative(element); + doneHandler(element, settings, instance); + addClass(element, settings.class_loaded); + setStatus(element, statusLoaded); + safeCallback(settings.callback_loaded, element, instance); + if (!goingNative) checkFinish(settings, instance); + }; + var errorHandler = function errorHandler(event, element, settings, instance) { + var goingNative = hasStatusNative(element); + doneHandler(element, settings, instance); + addClass(element, settings.class_error); + setStatus(element, statusError); + safeCallback(settings.callback_error, element, instance); + if (!goingNative) checkFinish(settings, instance); + }; + var addOneShotEventListeners = function addOneShotEventListeners(element, settings, instance) { + var elementToListenTo = getTempImage(element) || element; + + if (hasEventListeners(elementToListenTo)) { + // This happens when loading is retried twice + return; + } + + var _loadHandler = function _loadHandler(event) { + loadHandler(event, element, settings, instance); + removeEventListeners(elementToListenTo); + }; + + var _errorHandler = function _errorHandler(event) { + errorHandler(event, element, settings, instance); + removeEventListeners(elementToListenTo); + }; + + addEventListeners(elementToListenTo, _loadHandler, _errorHandler); + }; + + var loadBackground = function loadBackground(element, settings, instance) { + addTempImage(element); + addOneShotEventListeners(element, settings, instance); + saveOriginalBackgroundStyle(element); + setBackground(element, settings, instance); + setMultiBackground(element, settings, instance); + }; + + var loadRegular = function loadRegular(element, settings, instance) { + addOneShotEventListeners(element, settings, instance); + setSources(element, settings, instance); + }; + + var load = function load(element, settings, instance) { + if (hasLoadEvent(element)) { + loadRegular(element, settings, instance); + } else { + loadBackground(element, settings, instance); + } + }; + var loadNative = function loadNative(element, settings, instance) { + element.setAttribute("loading", "lazy"); + addOneShotEventListeners(element, settings, instance); + setSourcesNative(element, settings); + setStatus(element, statusNative); + }; + + var removeImageAttributes = function removeImageAttributes(element) { + element.removeAttribute(SRC); + element.removeAttribute(SRCSET); + element.removeAttribute(SIZES); + }; + + var resetSourcesImg = function resetSourcesImg(element) { + forEachPictureSource(element, function (sourceTag) { + removeImageAttributes(sourceTag); + }); + removeImageAttributes(element); + }; + + var restoreImg = function restoreImg(imgEl) { + forEachPictureSource(imgEl, function (sourceEl) { + restoreOriginalAttrs(sourceEl, attrsSrcSrcsetSizes); + }); + restoreOriginalAttrs(imgEl, attrsSrcSrcsetSizes); + }; + var restoreVideo = function restoreVideo(videoEl) { + forEachVideoSource(videoEl, function (sourceEl) { + restoreOriginalAttrs(sourceEl, attrsSrc); + }); + restoreOriginalAttrs(videoEl, attrsSrcPoster); + videoEl.load(); + }; + var restoreIframe = function restoreIframe(iframeEl) { + restoreOriginalAttrs(iframeEl, attrsSrc); + }; + var restoreFunctions = { + IMG: restoreImg, + IFRAME: restoreIframe, + VIDEO: restoreVideo + }; + + var restoreAttributes = function restoreAttributes(element) { + var restoreFunction = restoreFunctions[element.tagName]; + + if (!restoreFunction) { + restoreOriginalBgImage(element); + return; + } + + restoreFunction(element); + }; + + var resetClasses = function resetClasses(element, settings) { + if (hasEmptyStatus(element) || hasStatusNative(element)) { + return; + } + + removeClass(element, settings.class_entered); + removeClass(element, settings.class_exited); + removeClass(element, settings.class_applied); + removeClass(element, settings.class_loading); + removeClass(element, settings.class_loaded); + removeClass(element, settings.class_error); + }; + + var restore = function restore(element, settings) { + restoreAttributes(element); + resetClasses(element, settings); + resetStatus(element); + deleteOriginalAttrs(element); + }; + + var cancelLoading = function cancelLoading(element, entry, settings, instance) { + if (!settings.cancel_on_exit) return; + if (!hasStatusLoading(element)) return; + if (element.tagName !== "IMG") return; //Works only on images + + removeEventListeners(element); + resetSourcesImg(element); + restoreImg(element); + removeClass(element, settings.class_loading); + updateLoadingCount(instance, -1); + resetStatus(element); + safeCallback(settings.callback_cancel, element, entry, instance); + }; + + var onEnter = function onEnter(element, entry, settings, instance) { + var dontLoad = hadStartedLoading(element); + /* Save status + before setting it, to prevent loading it again. Fixes #526. */ + + setStatus(element, statusEntered); + addClass(element, settings.class_entered); + removeClass(element, settings.class_exited); + unobserveEntered(element, settings, instance); + safeCallback(settings.callback_enter, element, entry, instance); + if (dontLoad) return; + load(element, settings, instance); + }; + var onExit = function onExit(element, entry, settings, instance) { + if (hasEmptyStatus(element)) return; //Ignore the first pass, at landing + + addClass(element, settings.class_exited); + cancelLoading(element, entry, settings, instance); + safeCallback(settings.callback_exit, element, entry, instance); + }; + + var tagsWithNativeLazy = ["IMG", "IFRAME", "VIDEO"]; + var shouldUseNative = function shouldUseNative(settings) { + return settings.use_native && "loading" in HTMLImageElement.prototype; + }; + var loadAllNative = function loadAllNative(elements, settings, instance) { + elements.forEach(function (element) { + if (tagsWithNativeLazy.indexOf(element.tagName) === -1) { + return; + } + + loadNative(element, settings, instance); + }); + setToLoadCount(instance, 0); + }; + + var isIntersecting = function isIntersecting(entry) { + return entry.isIntersecting || entry.intersectionRatio > 0; + }; + + var getObserverSettings = function getObserverSettings(settings) { + return { + root: settings.container === document ? null : settings.container, + rootMargin: settings.thresholds || settings.threshold + "px" + }; + }; + + var intersectionHandler = function intersectionHandler(entries, settings, instance) { + entries.forEach(function (entry) { + return isIntersecting(entry) ? onEnter(entry.target, entry, settings, instance) : onExit(entry.target, entry, settings, instance); + }); + }; + + var observeElements = function observeElements(observer, elements) { + elements.forEach(function (element) { + observer.observe(element); + }); + }; + var updateObserver = function updateObserver(observer, elementsToObserve) { + resetObserver(observer); + observeElements(observer, elementsToObserve); + }; + var setObserver = function setObserver(settings, instance) { + if (!supportsIntersectionObserver || shouldUseNative(settings)) { + return; + } + + instance._observer = new IntersectionObserver(function (entries) { + intersectionHandler(entries, settings, instance); + }, getObserverSettings(settings)); + }; + + var toArray = function toArray(nodeSet) { + return Array.prototype.slice.call(nodeSet); + }; + var queryElements = function queryElements(settings) { + return settings.container.querySelectorAll(settings.elements_selector); + }; + var excludeManagedElements = function excludeManagedElements(elements) { + return toArray(elements).filter(hasEmptyStatus); + }; + var hasError = function hasError(element) { + return hasStatusError(element); + }; + var filterErrorElements = function filterErrorElements(elements) { + return toArray(elements).filter(hasError); + }; + var getElementsToLoad = function getElementsToLoad(elements, settings) { + return excludeManagedElements(elements || queryElements(settings)); + }; + + var retryLazyLoad = function retryLazyLoad(settings, instance) { + var errorElements = filterErrorElements(queryElements(settings)); + errorElements.forEach(function (element) { + removeClass(element, settings.class_error); + resetStatus(element); + }); + instance.update(); + }; + var setOnlineCheck = function setOnlineCheck(settings, instance) { + if (!runningOnBrowser) { + return; + } + + window.addEventListener("online", function () { + retryLazyLoad(settings, instance); + }); + }; + + var LazyLoad = function LazyLoad(customSettings, elements) { + var settings = getExtendedSettings(customSettings); + this._settings = settings; + this.loadingCount = 0; + setObserver(settings, this); + setOnlineCheck(settings, this); + this.update(elements); + }; + + LazyLoad.prototype = { + update: function update(givenNodeset) { + var settings = this._settings; + var elementsToLoad = getElementsToLoad(givenNodeset, settings); + setToLoadCount(this, elementsToLoad.length); + + if (isBot || !supportsIntersectionObserver) { + this.loadAll(elementsToLoad); + return; + } + + if (shouldUseNative(settings)) { + loadAllNative(elementsToLoad, settings, this); + return; + } + + updateObserver(this._observer, elementsToLoad); + }, + destroy: function destroy() { + // Observer + if (this._observer) { + this._observer.disconnect(); + } // Clean custom attributes on elements + + + queryElements(this._settings).forEach(function (element) { + deleteOriginalAttrs(element); + }); // Delete all internal props + + delete this._observer; + delete this._settings; + delete this.loadingCount; + delete this.toLoadCount; + }, + loadAll: function loadAll(elements) { + var _this = this; + + var settings = this._settings; + var elementsToLoad = getElementsToLoad(elements, settings); + elementsToLoad.forEach(function (element) { + unobserve(element, _this); + load(element, settings, _this); + }); + }, + restoreAll: function restoreAll() { + var settings = this._settings; + queryElements(settings).forEach(function (element) { + restore(element, settings); + }); + } + }; + + LazyLoad.load = function (element, customSettings) { + var settings = getExtendedSettings(customSettings); + load(element, settings); + }; + + LazyLoad.resetStatus = function (element) { + resetStatus(element); + }; // Automatic instances creation if required (useful for async script loading) + + + if (runningOnBrowser) { + autoInitialize(LazyLoad, window.lazyLoadOptions); + } + + return LazyLoad; + + }))); diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload/17.5/lazyload.min.js b/wp-content/plugins/wp-rocket/assets/js/lazyload/17.5/lazyload.min.js new file mode 100644 index 000000000..2b1b1969d --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lazyload/17.5/lazyload.min.js @@ -0,0 +1 @@ +!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(n="undefined"!=typeof globalThis?globalThis:n||self).LazyLoad=t()}(this,(function(){"use strict";function n(){return n=Object.assign||function(n){for(var t=1;t1,r={elements_selector:".lazy",container:e||t?document:null,threshold:300,thresholds:null,data_src:"src",data_srcset:"srcset",data_sizes:"sizes",data_bg:"bg",data_bg_hidpi:"bg-hidpi",data_bg_multi:"bg-multi",data_bg_multi_hidpi:"bg-multi-hidpi",data_poster:"poster",class_applied:"applied",class_loading:"loading",class_loaded:"loaded",class_error:"error",class_entered:"entered",class_exited:"exited",unobserve_completed:!0,unobserve_entered:!1,cancel_on_exit:!0,callback_enter:null,callback_exit:null,callback_applied:null,callback_loading:null,callback_loaded:null,callback_error:null,callback_finish:null,callback_cancel:null,use_native:!1},c=function(t){return n({},r,t)},u=function(n,t){var e,i="LazyLoad::Initialized",o=new n(t);try{e=new CustomEvent(i,{detail:{instance:o}})}catch(n){(e=document.createEvent("CustomEvent")).initCustomEvent(i,!1,!1,{instance:o})}window.dispatchEvent(e)},l="src",s="srcset",f="sizes",d="poster",_="llOriginalAttrs",g="loading",v="loaded",b="applied",p="error",h="native",m="data-",E="ll-status",I=function(n,t){return n.getAttribute(m+t)},y=function(n){return I(n,E)},A=function(n,t){return function(n,t,e){var i="data-ll-status";null!==e?n.setAttribute(i,e):n.removeAttribute(i)}(n,0,t)},k=function(n){return A(n,null)},L=function(n){return null===y(n)},w=function(n){return y(n)===h},x=[g,v,b,p],O=function(n,t,e,i){n&&(void 0===i?void 0===e?n(t):n(t,e):n(t,e,i))},N=function(n,t){o?n.classList.add(t):n.className+=(n.className?" ":"")+t},C=function(n,t){o?n.classList.remove(t):n.className=n.className.replace(new RegExp("(^|\\s+)"+t+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")},M=function(n){return n.llTempImage},z=function(n,t){if(t){var e=t._observer;e&&e.unobserve(n)}},R=function(n,t){n&&(n.loadingCount+=t)},T=function(n,t){n&&(n.toLoadCount=t)},G=function(n){for(var t,e=[],i=0;t=n.children[i];i+=1)"SOURCE"===t.tagName&&e.push(t);return e},D=function(n,t){var e=n.parentNode;e&&"PICTURE"===e.tagName&&G(e).forEach(t)},V=function(n,t){G(n).forEach(t)},F=[l],j=[l,d],P=[l,s,f],S=function(n){return!!n[_]},U=function(n){return n[_]},$=function(n){return delete n[_]},q=function(n,t){if(!S(n)){var e={};t.forEach((function(t){e[t]=n.getAttribute(t)})),n[_]=e}},H=function(n,t){if(S(n)){var e=U(n);t.forEach((function(t){!function(n,t,e){e?n.setAttribute(t,e):n.removeAttribute(t)}(n,t,e[t])}))}},B=function(n,t,e){N(n,t.class_loading),A(n,g),e&&(R(e,1),O(t.callback_loading,n,e))},J=function(n,t,e){e&&n.setAttribute(t,e)},K=function(n,t){J(n,f,I(n,t.data_sizes)),J(n,s,I(n,t.data_srcset)),J(n,l,I(n,t.data_src))},Q={IMG:function(n,t){D(n,(function(n){q(n,P),K(n,t)})),q(n,P),K(n,t)},IFRAME:function(n,t){q(n,F),J(n,l,I(n,t.data_src))},VIDEO:function(n,t){V(n,(function(n){q(n,F),J(n,l,I(n,t.data_src))})),q(n,j),J(n,d,I(n,t.data_poster)),J(n,l,I(n,t.data_src)),n.load()}},W=["IMG","IFRAME","VIDEO"],X=function(n,t){!t||function(n){return n.loadingCount>0}(t)||function(n){return n.toLoadCount>0}(t)||O(n.callback_finish,t)},Y=function(n,t,e){n.addEventListener(t,e),n.llEvLisnrs[t]=e},Z=function(n,t,e){n.removeEventListener(t,e)},nn=function(n){return!!n.llEvLisnrs},tn=function(n){if(nn(n)){var t=n.llEvLisnrs;for(var e in t){var i=t[e];Z(n,e,i)}delete n.llEvLisnrs}},en=function(n,t,e){!function(n){delete n.llTempImage}(n),R(e,-1),function(n){n&&(n.toLoadCount-=1)}(e),C(n,t.class_loading),t.unobserve_completed&&z(n,e)},on=function(n,t,e){var i=M(n)||n;nn(i)||function(n,t,e){nn(n)||(n.llEvLisnrs={});var i="VIDEO"===n.tagName?"loadeddata":"load";Y(n,i,t),Y(n,"error",e)}(i,(function(o){!function(n,t,e,i){var o=w(t);en(t,e,i),N(t,e.class_loaded),A(t,v),O(e.callback_loaded,t,i),o||X(e,i)}(0,n,t,e),tn(i)}),(function(o){!function(n,t,e,i){var o=w(t);en(t,e,i),N(t,e.class_error),A(t,p),O(e.callback_error,t,i),o||X(e,i)}(0,n,t,e),tn(i)}))},an=function(n,t,e){!function(n){n.llTempImage=document.createElement("IMG")}(n),on(n,t,e),function(n){S(n)||(n[_]={backgroundImage:n.style.backgroundImage})}(n),function(n,t,e){var i=I(n,t.data_bg),o=I(n,t.data_bg_hidpi),r=a&&o?o:i;r&&(n.style.backgroundImage='url("'.concat(r,'")'),M(n).setAttribute(l,r),B(n,t,e))}(n,t,e),function(n,t,e){var i=I(n,t.data_bg_multi),o=I(n,t.data_bg_multi_hidpi),r=a&&o?o:i;r&&(n.style.backgroundImage=r,function(n,t,e){N(n,t.class_applied),A(n,b),e&&(t.unobserve_completed&&z(n,t),O(t.callback_applied,n,e))}(n,t,e))}(n,t,e)},rn=function(n,t,e){!function(n){return W.indexOf(n.tagName)>-1}(n)?an(n,t,e):function(n,t,e){on(n,t,e),function(n,t,e){var i=Q[n.tagName];i&&(i(n,t),B(n,t,e))}(n,t,e)}(n,t,e)},cn=function(n){n.removeAttribute(l),n.removeAttribute(s),n.removeAttribute(f)},un=function(n){D(n,(function(n){H(n,P)})),H(n,P)},ln={IMG:un,IFRAME:function(n){H(n,F)},VIDEO:function(n){V(n,(function(n){H(n,F)})),H(n,j),n.load()}},sn=function(n,t){(function(n){var t=ln[n.tagName];t?t(n):function(n){if(S(n)){var t=U(n);n.style.backgroundImage=t.backgroundImage}}(n)})(n),function(n,t){L(n)||w(n)||(C(n,t.class_entered),C(n,t.class_exited),C(n,t.class_applied),C(n,t.class_loading),C(n,t.class_loaded),C(n,t.class_error))}(n,t),k(n),$(n)},fn=["IMG","IFRAME","VIDEO"],dn=function(n){return n.use_native&&"loading"in HTMLImageElement.prototype},_n=function(n,t,e){n.forEach((function(n){return function(n){return n.isIntersecting||n.intersectionRatio>0}(n)?function(n,t,e,i){var o=function(n){return x.indexOf(y(n))>=0}(n);A(n,"entered"),N(n,e.class_entered),C(n,e.class_exited),function(n,t,e){t.unobserve_entered&&z(n,e)}(n,e,i),O(e.callback_enter,n,t,i),o||rn(n,e,i)}(n.target,n,t,e):function(n,t,e,i){L(n)||(N(n,e.class_exited),function(n,t,e,i){e.cancel_on_exit&&function(n){return y(n)===g}(n)&&"IMG"===n.tagName&&(tn(n),function(n){D(n,(function(n){cn(n)})),cn(n)}(n),un(n),C(n,e.class_loading),R(i,-1),k(n),O(e.callback_cancel,n,t,i))}(n,t,e,i),O(e.callback_exit,n,t,i))}(n.target,n,t,e)}))},gn=function(n){return Array.prototype.slice.call(n)},vn=function(n){return n.container.querySelectorAll(n.elements_selector)},bn=function(n){return function(n){return y(n)===p}(n)},pn=function(n,t){return function(n){return gn(n).filter(L)}(n||vn(t))},hn=function(n,e){var o=c(n);this._settings=o,this.loadingCount=0,function(n,t){i&&!dn(n)&&(t._observer=new IntersectionObserver((function(e){_n(e,n,t)}),function(n){return{root:n.container===document?null:n.container,rootMargin:n.thresholds||n.threshold+"px"}}(n)))}(o,this),function(n,e){t&&window.addEventListener("online",(function(){!function(n,t){var e;(e=vn(n),gn(e).filter(bn)).forEach((function(t){C(t,n.class_error),k(t)})),t.update()}(n,e)}))}(o,this),this.update(e)};return hn.prototype={update:function(n){var t,o,a=this._settings,r=pn(n,a);T(this,r.length),!e&&i?dn(a)?function(n,t,e){n.forEach((function(n){-1!==fn.indexOf(n.tagName)&&function(n,t,e){n.setAttribute("loading","lazy"),on(n,t,e),function(n,t){var e=Q[n.tagName];e&&e(n,t)}(n,t),A(n,h)}(n,t,e)})),T(e,0)}(r,a,this):(o=r,function(n){n.disconnect()}(t=this._observer),function(n,t){t.forEach((function(t){n.observe(t)}))}(t,o)):this.loadAll(r)},destroy:function(){this._observer&&this._observer.disconnect(),vn(this._settings).forEach((function(n){$(n)})),delete this._observer,delete this._settings,delete this.loadingCount,delete this.toLoadCount},loadAll:function(n){var t=this,e=this._settings;pn(n,e).forEach((function(n){z(n,t),rn(n,e,t)}))},restoreAll:function(){var n=this._settings;vn(n).forEach((function(t){sn(t,n)}))}},hn.load=function(n,t){var e=c(t);rn(n,e)},hn.resetStatus=function(n){k(n)},t&&function(n,t){if(t)if(t.length)for(var e,i=0;e=t[i];i+=1)u(n,e);else u(n,t)}(hn,window.lazyLoadOptions),hn})); diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload/17.8.3/lazyload.js b/wp-content/plugins/wp-rocket/assets/js/lazyload/17.8.3/lazyload.js new file mode 100644 index 000000000..203fa75e2 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lazyload/17.8.3/lazyload.js @@ -0,0 +1,862 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.LazyLoad = factory()); +}(this, (function () { 'use strict'; + + function _extends() { + _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); + } + + var runningOnBrowser = typeof window !== "undefined"; + var isBot = runningOnBrowser && !("onscroll" in window) || typeof navigator !== "undefined" && /(gle|ing|ro)bot|crawl|spider/i.test(navigator.userAgent); + var supportsIntersectionObserver = runningOnBrowser && "IntersectionObserver" in window; + var supportsClassList = runningOnBrowser && "classList" in document.createElement("p"); + var isHiDpi = runningOnBrowser && window.devicePixelRatio > 1; + + var defaultSettings = { + elements_selector: ".lazy", + container: isBot || runningOnBrowser ? document : null, + threshold: 300, + thresholds: null, + data_src: "src", + data_srcset: "srcset", + data_sizes: "sizes", + data_bg: "bg", + data_bg_hidpi: "bg-hidpi", + data_bg_multi: "bg-multi", + data_bg_multi_hidpi: "bg-multi-hidpi", + data_bg_set: "bg-set", + data_poster: "poster", + class_applied: "applied", + class_loading: "loading", + class_loaded: "loaded", + class_error: "error", + class_entered: "entered", + class_exited: "exited", + unobserve_completed: true, + unobserve_entered: false, + cancel_on_exit: true, + callback_enter: null, + callback_exit: null, + callback_applied: null, + callback_loading: null, + callback_loaded: null, + callback_error: null, + callback_finish: null, + callback_cancel: null, + use_native: false, + restore_on_error: false + }; + var getExtendedSettings = function getExtendedSettings(customSettings) { + return _extends({}, defaultSettings, customSettings); + }; + + /* Creates instance and notifies it through the window element */ + var createInstance = function createInstance(classObj, options) { + var event; + var eventString = "LazyLoad::Initialized"; + var instance = new classObj(options); + + try { + // Works in modern browsers + event = new CustomEvent(eventString, { + detail: { + instance: instance + } + }); + } catch (err) { + // Works in Internet Explorer (all versions) + event = document.createEvent("CustomEvent"); + event.initCustomEvent(eventString, false, false, { + instance: instance + }); + } + + window.dispatchEvent(event); + }; + /* Auto initialization of one or more instances of lazyload, depending on the + options passed in (plain object or an array) */ + + + var autoInitialize = function autoInitialize(classObj, options) { + if (!options) { + return; + } + + if (!options.length) { + // Plain object + createInstance(classObj, options); + } else { + // Array of objects + for (var i = 0, optionsItem; optionsItem = options[i]; i += 1) { + createInstance(classObj, optionsItem); + } + } + }; + + var SRC = "src"; + var SRCSET = "srcset"; + var SIZES = "sizes"; + var POSTER = "poster"; + var ORIGINALS = "llOriginalAttrs"; + var DATA = "data"; + + var statusLoading = "loading"; + var statusLoaded = "loaded"; + var statusApplied = "applied"; + var statusEntered = "entered"; + var statusError = "error"; + var statusNative = "native"; + + var dataPrefix = "data-"; + var statusDataName = "ll-status"; + var getData = function getData(element, attribute) { + return element.getAttribute(dataPrefix + attribute); + }; + var setData = function setData(element, attribute, value) { + var attrName = dataPrefix + attribute; + + if (value === null) { + element.removeAttribute(attrName); + return; + } + + element.setAttribute(attrName, value); + }; + var getStatus = function getStatus(element) { + return getData(element, statusDataName); + }; + var setStatus = function setStatus(element, status) { + return setData(element, statusDataName, status); + }; + var resetStatus = function resetStatus(element) { + return setStatus(element, null); + }; + var hasEmptyStatus = function hasEmptyStatus(element) { + return getStatus(element) === null; + }; + var hasStatusLoading = function hasStatusLoading(element) { + return getStatus(element) === statusLoading; + }; + var hasStatusError = function hasStatusError(element) { + return getStatus(element) === statusError; + }; + var hasStatusNative = function hasStatusNative(element) { + return getStatus(element) === statusNative; + }; + var statusesAfterLoading = [statusLoading, statusLoaded, statusApplied, statusError]; + var hadStartedLoading = function hadStartedLoading(element) { + return statusesAfterLoading.indexOf(getStatus(element)) >= 0; + }; + + var safeCallback = function safeCallback(callback, arg1, arg2, arg3) { + if (!callback) { + return; + } + + if (arg3 !== undefined) { + callback(arg1, arg2, arg3); + return; + } + + if (arg2 !== undefined) { + callback(arg1, arg2); + return; + } + + callback(arg1); + }; + + var addClass = function addClass(element, className) { + if (supportsClassList) { + element.classList.add(className); + return; + } + + element.className += (element.className ? " " : "") + className; + }; + var removeClass = function removeClass(element, className) { + if (supportsClassList) { + element.classList.remove(className); + return; + } + + element.className = element.className.replace(new RegExp("(^|\\s+)" + className + "(\\s+|$)"), " ").replace(/^\s+/, "").replace(/\s+$/, ""); + }; + + var addTempImage = function addTempImage(element) { + element.llTempImage = document.createElement("IMG"); + }; + var deleteTempImage = function deleteTempImage(element) { + delete element.llTempImage; + }; + var getTempImage = function getTempImage(element) { + return element.llTempImage; + }; + + var unobserve = function unobserve(element, instance) { + if (!instance) return; + var observer = instance._observer; + if (!observer) return; + observer.unobserve(element); + }; + var resetObserver = function resetObserver(observer) { + observer.disconnect(); + }; + var unobserveEntered = function unobserveEntered(element, settings, instance) { + if (settings.unobserve_entered) unobserve(element, instance); + }; + + var updateLoadingCount = function updateLoadingCount(instance, delta) { + if (!instance) return; + instance.loadingCount += delta; + }; + var decreaseToLoadCount = function decreaseToLoadCount(instance) { + if (!instance) return; + instance.toLoadCount -= 1; + }; + var setToLoadCount = function setToLoadCount(instance, value) { + if (!instance) return; + instance.toLoadCount = value; + }; + var isSomethingLoading = function isSomethingLoading(instance) { + return instance.loadingCount > 0; + }; + var haveElementsToLoad = function haveElementsToLoad(instance) { + return instance.toLoadCount > 0; + }; + + var getSourceTags = function getSourceTags(parentTag) { + var sourceTags = []; + + for (var i = 0, childTag; childTag = parentTag.children[i]; i += 1) { + if (childTag.tagName === "SOURCE") { + sourceTags.push(childTag); + } + } + + return sourceTags; + }; + + var forEachPictureSource = function forEachPictureSource(element, fn) { + var parent = element.parentNode; + + if (!parent || parent.tagName !== "PICTURE") { + return; + } + + var sourceTags = getSourceTags(parent); + sourceTags.forEach(fn); + }; + var forEachVideoSource = function forEachVideoSource(element, fn) { + var sourceTags = getSourceTags(element); + sourceTags.forEach(fn); + }; + + var attrsSrc = [SRC]; + var attrsSrcPoster = [SRC, POSTER]; + var attrsSrcSrcsetSizes = [SRC, SRCSET, SIZES]; + var attrsData = [DATA]; + var hasOriginalAttrs = function hasOriginalAttrs(element) { + return !!element[ORIGINALS]; + }; + var getOriginalAttrs = function getOriginalAttrs(element) { + return element[ORIGINALS]; + }; + var deleteOriginalAttrs = function deleteOriginalAttrs(element) { + return delete element[ORIGINALS]; + }; // ## SAVE ## + + var setOriginalsObject = function setOriginalsObject(element, attributes) { + if (hasOriginalAttrs(element)) { + return; + } + + var originals = {}; + attributes.forEach(function (attribute) { + originals[attribute] = element.getAttribute(attribute); + }); + element[ORIGINALS] = originals; + }; + var saveOriginalBackgroundStyle = function saveOriginalBackgroundStyle(element) { + if (hasOriginalAttrs(element)) { + return; + } + + element[ORIGINALS] = { + backgroundImage: element.style.backgroundImage + }; + }; // ## RESTORE ## + + var setOrResetAttribute = function setOrResetAttribute(element, attrName, value) { + if (!value) { + element.removeAttribute(attrName); + return; + } + + element.setAttribute(attrName, value); + }; + + var restoreOriginalAttrs = function restoreOriginalAttrs(element, attributes) { + if (!hasOriginalAttrs(element)) { + return; + } + + var originals = getOriginalAttrs(element); + attributes.forEach(function (attribute) { + setOrResetAttribute(element, attribute, originals[attribute]); + }); + }; + var restoreOriginalBgImage = function restoreOriginalBgImage(element) { + if (!hasOriginalAttrs(element)) { + return; + } + + var originals = getOriginalAttrs(element); + element.style.backgroundImage = originals.backgroundImage; + }; + + var manageApplied = function manageApplied(element, settings, instance) { + addClass(element, settings.class_applied); + setStatus(element, statusApplied); // Instance is not provided when loading is called from static class + + if (!instance) return; + + if (settings.unobserve_completed) { + // Unobserve now because we can't do it on load + unobserve(element, settings); + } + + safeCallback(settings.callback_applied, element, instance); + }; + var manageLoading = function manageLoading(element, settings, instance) { + addClass(element, settings.class_loading); + setStatus(element, statusLoading); // Instance is not provided when loading is called from static class + + if (!instance) return; + updateLoadingCount(instance, +1); + safeCallback(settings.callback_loading, element, instance); + }; + var setAttributeIfValue = function setAttributeIfValue(element, attrName, value) { + if (!value) { + return; + } + + element.setAttribute(attrName, value); + }; + var setImageAttributes = function setImageAttributes(element, settings) { + setAttributeIfValue(element, SIZES, getData(element, settings.data_sizes)); + setAttributeIfValue(element, SRCSET, getData(element, settings.data_srcset)); + setAttributeIfValue(element, SRC, getData(element, settings.data_src)); + }; + var setSourcesImg = function setSourcesImg(imgEl, settings) { + forEachPictureSource(imgEl, function (sourceTag) { + setOriginalsObject(sourceTag, attrsSrcSrcsetSizes); + setImageAttributes(sourceTag, settings); + }); + setOriginalsObject(imgEl, attrsSrcSrcsetSizes); + setImageAttributes(imgEl, settings); + }; + var setSourcesIframe = function setSourcesIframe(iframe, settings) { + setOriginalsObject(iframe, attrsSrc); + setAttributeIfValue(iframe, SRC, getData(iframe, settings.data_src)); + }; + var setSourcesVideo = function setSourcesVideo(videoEl, settings) { + forEachVideoSource(videoEl, function (sourceEl) { + setOriginalsObject(sourceEl, attrsSrc); + setAttributeIfValue(sourceEl, SRC, getData(sourceEl, settings.data_src)); + }); + setOriginalsObject(videoEl, attrsSrcPoster); + setAttributeIfValue(videoEl, POSTER, getData(videoEl, settings.data_poster)); + setAttributeIfValue(videoEl, SRC, getData(videoEl, settings.data_src)); + videoEl.load(); + }; + var setSourcesObject = function setSourcesObject(object, settings) { + setOriginalsObject(object, attrsData); + setAttributeIfValue(object, DATA, getData(object, settings.data_src)); + }; + var setBackground = function setBackground(element, settings, instance) { + var bg1xValue = getData(element, settings.data_bg); + var bgHiDpiValue = getData(element, settings.data_bg_hidpi); + var bgDataValue = isHiDpi && bgHiDpiValue ? bgHiDpiValue : bg1xValue; + if (!bgDataValue) return; + element.style.backgroundImage = "url(\"".concat(bgDataValue, "\")"); + getTempImage(element).setAttribute(SRC, bgDataValue); + manageLoading(element, settings, instance); + }; // NOTE: THE TEMP IMAGE TRICK CANNOT BE DONE WITH data-multi-bg + // BECAUSE INSIDE ITS VALUES MUST BE WRAPPED WITH URL() AND ONE OF THEM + // COULD BE A GRADIENT BACKGROUND IMAGE + + var setMultiBackground = function setMultiBackground(element, settings, instance) { + var bg1xValue = getData(element, settings.data_bg_multi); + var bgHiDpiValue = getData(element, settings.data_bg_multi_hidpi); + var bgDataValue = isHiDpi && bgHiDpiValue ? bgHiDpiValue : bg1xValue; + + if (!bgDataValue) { + return; + } + + element.style.backgroundImage = bgDataValue; + manageApplied(element, settings, instance); + }; + var setImgsetBackground = function setImgsetBackground(element, settings, instance) { + var bgImgSetDataValue = getData(element, settings.data_bg_set); + + if (!bgImgSetDataValue) { + return; + } + + var imgSetValues = bgImgSetDataValue.split("|"); + var bgImageValues = imgSetValues.map(function (value) { + return "image-set(".concat(value, ")"); + }); + element.style.backgroundImage = bgImageValues.join(); // Temporary fix for Chromeium with the -webkit- prefix + + if (element.style.backgroundImage === '') { + bgImageValues = imgSetValues.map(function (value) { + return "-webkit-image-set(".concat(value, ")"); + }); + element.style.backgroundImage = bgImageValues.join(); + } + + manageApplied(element, settings, instance); + }; + var setSourcesFunctions = { + IMG: setSourcesImg, + IFRAME: setSourcesIframe, + VIDEO: setSourcesVideo, + OBJECT: setSourcesObject + }; + var setSourcesNative = function setSourcesNative(element, settings) { + var setSourcesFunction = setSourcesFunctions[element.tagName]; + + if (!setSourcesFunction) { + return; + } + + setSourcesFunction(element, settings); + }; + var setSources = function setSources(element, settings, instance) { + var setSourcesFunction = setSourcesFunctions[element.tagName]; + + if (!setSourcesFunction) { + return; + } + + setSourcesFunction(element, settings); + manageLoading(element, settings, instance); + }; + + var elementsWithLoadEvent = ["IMG", "IFRAME", "VIDEO", "OBJECT"]; + var hasLoadEvent = function hasLoadEvent(element) { + return elementsWithLoadEvent.indexOf(element.tagName) > -1; + }; + var checkFinish = function checkFinish(settings, instance) { + if (instance && !isSomethingLoading(instance) && !haveElementsToLoad(instance)) { + safeCallback(settings.callback_finish, instance); + } + }; + var addEventListener = function addEventListener(element, eventName, handler) { + element.addEventListener(eventName, handler); + element.llEvLisnrs[eventName] = handler; + }; + var removeEventListener = function removeEventListener(element, eventName, handler) { + element.removeEventListener(eventName, handler); + }; + var hasEventListeners = function hasEventListeners(element) { + return !!element.llEvLisnrs; + }; + var addEventListeners = function addEventListeners(element, loadHandler, errorHandler) { + if (!hasEventListeners(element)) element.llEvLisnrs = {}; + var loadEventName = element.tagName === "VIDEO" ? "loadeddata" : "load"; + addEventListener(element, loadEventName, loadHandler); + addEventListener(element, "error", errorHandler); + }; + var removeEventListeners = function removeEventListeners(element) { + if (!hasEventListeners(element)) { + return; + } + + var eventListeners = element.llEvLisnrs; + + for (var eventName in eventListeners) { + var handler = eventListeners[eventName]; + removeEventListener(element, eventName, handler); + } + + delete element.llEvLisnrs; + }; + var doneHandler = function doneHandler(element, settings, instance) { + deleteTempImage(element); + updateLoadingCount(instance, -1); + decreaseToLoadCount(instance); + removeClass(element, settings.class_loading); + + if (settings.unobserve_completed) { + unobserve(element, instance); + } + }; + var loadHandler = function loadHandler(event, element, settings, instance) { + var goingNative = hasStatusNative(element); + doneHandler(element, settings, instance); + addClass(element, settings.class_loaded); + setStatus(element, statusLoaded); + safeCallback(settings.callback_loaded, element, instance); + if (!goingNative) checkFinish(settings, instance); + }; + var errorHandler = function errorHandler(event, element, settings, instance) { + var goingNative = hasStatusNative(element); + doneHandler(element, settings, instance); + addClass(element, settings.class_error); + setStatus(element, statusError); + safeCallback(settings.callback_error, element, instance); + if (settings.restore_on_error) restoreOriginalAttrs(element, attrsSrcSrcsetSizes); + if (!goingNative) checkFinish(settings, instance); + }; + var addOneShotEventListeners = function addOneShotEventListeners(element, settings, instance) { + var elementToListenTo = getTempImage(element) || element; + + if (hasEventListeners(elementToListenTo)) { + // This happens when loading is retried twice + return; + } + + var _loadHandler = function _loadHandler(event) { + loadHandler(event, element, settings, instance); + removeEventListeners(elementToListenTo); + }; + + var _errorHandler = function _errorHandler(event) { + errorHandler(event, element, settings, instance); + removeEventListeners(elementToListenTo); + }; + + addEventListeners(elementToListenTo, _loadHandler, _errorHandler); + }; + + var loadBackground = function loadBackground(element, settings, instance) { + addTempImage(element); + addOneShotEventListeners(element, settings, instance); + saveOriginalBackgroundStyle(element); + setBackground(element, settings, instance); + setMultiBackground(element, settings, instance); + setImgsetBackground(element, settings, instance); + }; + + var loadRegular = function loadRegular(element, settings, instance) { + addOneShotEventListeners(element, settings, instance); + setSources(element, settings, instance); + }; + + var load = function load(element, settings, instance) { + if (hasLoadEvent(element)) { + loadRegular(element, settings, instance); + } else { + loadBackground(element, settings, instance); + } + }; + var loadNative = function loadNative(element, settings, instance) { + element.setAttribute("loading", "lazy"); + addOneShotEventListeners(element, settings, instance); + setSourcesNative(element, settings); + setStatus(element, statusNative); + }; + + var removeImageAttributes = function removeImageAttributes(element) { + element.removeAttribute(SRC); + element.removeAttribute(SRCSET); + element.removeAttribute(SIZES); + }; + + var resetSourcesImg = function resetSourcesImg(element) { + forEachPictureSource(element, function (sourceTag) { + removeImageAttributes(sourceTag); + }); + removeImageAttributes(element); + }; + + var restoreImg = function restoreImg(imgEl) { + forEachPictureSource(imgEl, function (sourceEl) { + restoreOriginalAttrs(sourceEl, attrsSrcSrcsetSizes); + }); + restoreOriginalAttrs(imgEl, attrsSrcSrcsetSizes); + }; + var restoreVideo = function restoreVideo(videoEl) { + forEachVideoSource(videoEl, function (sourceEl) { + restoreOriginalAttrs(sourceEl, attrsSrc); + }); + restoreOriginalAttrs(videoEl, attrsSrcPoster); + videoEl.load(); + }; + var restoreIframe = function restoreIframe(iframeEl) { + restoreOriginalAttrs(iframeEl, attrsSrc); + }; + var restoreObject = function restoreObject(objectEl) { + restoreOriginalAttrs(objectEl, attrsData); + }; + var restoreFunctions = { + IMG: restoreImg, + IFRAME: restoreIframe, + VIDEO: restoreVideo, + OBJECT: restoreObject + }; + + var restoreAttributes = function restoreAttributes(element) { + var restoreFunction = restoreFunctions[element.tagName]; + + if (!restoreFunction) { + restoreOriginalBgImage(element); + return; + } + + restoreFunction(element); + }; + + var resetClasses = function resetClasses(element, settings) { + if (hasEmptyStatus(element) || hasStatusNative(element)) { + return; + } + + removeClass(element, settings.class_entered); + removeClass(element, settings.class_exited); + removeClass(element, settings.class_applied); + removeClass(element, settings.class_loading); + removeClass(element, settings.class_loaded); + removeClass(element, settings.class_error); + }; + + var restore = function restore(element, settings) { + restoreAttributes(element); + resetClasses(element, settings); + resetStatus(element); + deleteOriginalAttrs(element); + }; + + var cancelLoading = function cancelLoading(element, entry, settings, instance) { + if (!settings.cancel_on_exit) return; + if (!hasStatusLoading(element)) return; + if (element.tagName !== "IMG") return; //Works only on images + + removeEventListeners(element); + resetSourcesImg(element); + restoreImg(element); + removeClass(element, settings.class_loading); + updateLoadingCount(instance, -1); + resetStatus(element); + safeCallback(settings.callback_cancel, element, entry, instance); + }; + + var onEnter = function onEnter(element, entry, settings, instance) { + var dontLoad = hadStartedLoading(element); + /* Save status + before setting it, to prevent loading it again. Fixes #526. */ + + setStatus(element, statusEntered); + addClass(element, settings.class_entered); + removeClass(element, settings.class_exited); + unobserveEntered(element, settings, instance); + safeCallback(settings.callback_enter, element, entry, instance); + if (dontLoad) return; + load(element, settings, instance); + }; + var onExit = function onExit(element, entry, settings, instance) { + if (hasEmptyStatus(element)) return; //Ignore the first pass, at landing + + addClass(element, settings.class_exited); + cancelLoading(element, entry, settings, instance); + safeCallback(settings.callback_exit, element, entry, instance); + }; + + var tagsWithNativeLazy = ["IMG", "IFRAME", "VIDEO"]; + var shouldUseNative = function shouldUseNative(settings) { + return settings.use_native && "loading" in HTMLImageElement.prototype; + }; + var loadAllNative = function loadAllNative(elements, settings, instance) { + elements.forEach(function (element) { + if (tagsWithNativeLazy.indexOf(element.tagName) === -1) { + return; + } + + loadNative(element, settings, instance); + }); + setToLoadCount(instance, 0); + }; + + var isIntersecting = function isIntersecting(entry) { + return entry.isIntersecting || entry.intersectionRatio > 0; + }; + + var getObserverSettings = function getObserverSettings(settings) { + return { + root: settings.container === document ? null : settings.container, + rootMargin: settings.thresholds || settings.threshold + "px" + }; + }; + + var intersectionHandler = function intersectionHandler(entries, settings, instance) { + entries.forEach(function (entry) { + return isIntersecting(entry) ? onEnter(entry.target, entry, settings, instance) : onExit(entry.target, entry, settings, instance); + }); + }; + + var observeElements = function observeElements(observer, elements) { + elements.forEach(function (element) { + observer.observe(element); + }); + }; + var updateObserver = function updateObserver(observer, elementsToObserve) { + resetObserver(observer); + observeElements(observer, elementsToObserve); + }; + var setObserver = function setObserver(settings, instance) { + if (!supportsIntersectionObserver || shouldUseNative(settings)) { + return; + } + + instance._observer = new IntersectionObserver(function (entries) { + intersectionHandler(entries, settings, instance); + }, getObserverSettings(settings)); + }; + + var toArray = function toArray(nodeSet) { + return Array.prototype.slice.call(nodeSet); + }; + var queryElements = function queryElements(settings) { + return settings.container.querySelectorAll(settings.elements_selector); + }; + var excludeManagedElements = function excludeManagedElements(elements) { + return toArray(elements).filter(hasEmptyStatus); + }; + var hasError = function hasError(element) { + return hasStatusError(element); + }; + var filterErrorElements = function filterErrorElements(elements) { + return toArray(elements).filter(hasError); + }; + var getElementsToLoad = function getElementsToLoad(elements, settings) { + return excludeManagedElements(elements || queryElements(settings)); + }; + + var retryLazyLoad = function retryLazyLoad(settings, instance) { + var errorElements = filterErrorElements(queryElements(settings)); + errorElements.forEach(function (element) { + removeClass(element, settings.class_error); + resetStatus(element); + }); + instance.update(); + }; + var setOnlineCheck = function setOnlineCheck(settings, instance) { + if (!runningOnBrowser) { + return; + } + + instance._onlineHandler = function () { + retryLazyLoad(settings, instance); + }; + + window.addEventListener("online", instance._onlineHandler); + }; + var resetOnlineCheck = function resetOnlineCheck(instance) { + if (!runningOnBrowser) { + return; + } + + window.removeEventListener("online", instance._onlineHandler); + }; + + var LazyLoad = function LazyLoad(customSettings, elements) { + var settings = getExtendedSettings(customSettings); + this._settings = settings; + this.loadingCount = 0; + setObserver(settings, this); + setOnlineCheck(settings, this); + this.update(elements); + }; + + LazyLoad.prototype = { + update: function update(givenNodeset) { + var settings = this._settings; + var elementsToLoad = getElementsToLoad(givenNodeset, settings); + setToLoadCount(this, elementsToLoad.length); + + if (isBot || !supportsIntersectionObserver) { + this.loadAll(elementsToLoad); + return; + } + + if (shouldUseNative(settings)) { + loadAllNative(elementsToLoad, settings, this); + return; + } + + updateObserver(this._observer, elementsToLoad); + }, + destroy: function destroy() { + // Observer + if (this._observer) { + this._observer.disconnect(); + } // Clean handlers + + + resetOnlineCheck(this); // Clean custom attributes on elements + + queryElements(this._settings).forEach(function (element) { + deleteOriginalAttrs(element); + }); // Delete all internal props + + delete this._observer; + delete this._settings; + delete this._onlineHandler; + delete this.loadingCount; + delete this.toLoadCount; + }, + loadAll: function loadAll(elements) { + var _this = this; + + var settings = this._settings; + var elementsToLoad = getElementsToLoad(elements, settings); + elementsToLoad.forEach(function (element) { + unobserve(element, _this); + load(element, settings, _this); + }); + }, + restoreAll: function restoreAll() { + var settings = this._settings; + queryElements(settings).forEach(function (element) { + restore(element, settings); + }); + } + }; + + LazyLoad.load = function (element, customSettings) { + var settings = getExtendedSettings(customSettings); + load(element, settings); + }; + + LazyLoad.resetStatus = function (element) { + resetStatus(element); + }; // Automatic instances creation if required (useful for async script loading) + + + if (runningOnBrowser) { + autoInitialize(LazyLoad, window.lazyLoadOptions); + } + + return LazyLoad; + +}))); \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/lazyload/17.8.3/lazyload.min.js b/wp-content/plugins/wp-rocket/assets/js/lazyload/17.8.3/lazyload.min.js new file mode 100644 index 000000000..d22c79417 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lazyload/17.8.3/lazyload.min.js @@ -0,0 +1 @@ +!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(n="undefined"!=typeof globalThis?globalThis:n||self).LazyLoad=t()}(this,(function(){"use strict";function n(){return n=Object.assign||function(n){for(var t=1;t1,r={elements_selector:".lazy",container:e||t?document:null,threshold:300,thresholds:null,data_src:"src",data_srcset:"srcset",data_sizes:"sizes",data_bg:"bg",data_bg_hidpi:"bg-hidpi",data_bg_multi:"bg-multi",data_bg_multi_hidpi:"bg-multi-hidpi",data_bg_set:"bg-set",data_poster:"poster",class_applied:"applied",class_loading:"loading",class_loaded:"loaded",class_error:"error",class_entered:"entered",class_exited:"exited",unobserve_completed:!0,unobserve_entered:!1,cancel_on_exit:!0,callback_enter:null,callback_exit:null,callback_applied:null,callback_loading:null,callback_loaded:null,callback_error:null,callback_finish:null,callback_cancel:null,use_native:!1,restore_on_error:!1},c=function(t){return n({},r,t)},l=function(n,t){var e,i="LazyLoad::Initialized",o=new n(t);try{e=new CustomEvent(i,{detail:{instance:o}})}catch(n){(e=document.createEvent("CustomEvent")).initCustomEvent(i,!1,!1,{instance:o})}window.dispatchEvent(e)},u="src",s="srcset",d="sizes",f="poster",_="llOriginalAttrs",g="data",v="loading",b="loaded",m="applied",p="error",h="native",E="data-",I="ll-status",y=function(n,t){return n.getAttribute(E+t)},k=function(n){return y(n,I)},w=function(n,t){return function(n,t,e){var i="data-ll-status";null!==e?n.setAttribute(i,e):n.removeAttribute(i)}(n,0,t)},A=function(n){return w(n,null)},L=function(n){return null===k(n)},O=function(n){return k(n)===h},x=[v,b,m,p],C=function(n,t,e,i){n&&(void 0===i?void 0===e?n(t):n(t,e):n(t,e,i))},N=function(n,t){o?n.classList.add(t):n.className+=(n.className?" ":"")+t},M=function(n,t){o?n.classList.remove(t):n.className=n.className.replace(new RegExp("(^|\\s+)"+t+"(\\s+|$)")," ").replace(/^\s+/,"").replace(/\s+$/,"")},z=function(n){return n.llTempImage},T=function(n,t){if(t){var e=t._observer;e&&e.unobserve(n)}},R=function(n,t){n&&(n.loadingCount+=t)},G=function(n,t){n&&(n.toLoadCount=t)},j=function(n){for(var t,e=[],i=0;t=n.children[i];i+=1)"SOURCE"===t.tagName&&e.push(t);return e},D=function(n,t){var e=n.parentNode;e&&"PICTURE"===e.tagName&&j(e).forEach(t)},H=function(n,t){j(n).forEach(t)},V=[u],F=[u,f],B=[u,s,d],J=[g],P=function(n){return!!n[_]},S=function(n){return n[_]},U=function(n){return delete n[_]},$=function(n,t){if(!P(n)){var e={};t.forEach((function(t){e[t]=n.getAttribute(t)})),n[_]=e}},q=function(n,t){if(P(n)){var e=S(n);t.forEach((function(t){!function(n,t,e){e?n.setAttribute(t,e):n.removeAttribute(t)}(n,t,e[t])}))}},K=function(n,t,e){N(n,t.class_applied),w(n,m),e&&(t.unobserve_completed&&T(n,t),C(t.callback_applied,n,e))},Q=function(n,t,e){N(n,t.class_loading),w(n,v),e&&(R(e,1),C(t.callback_loading,n,e))},W=function(n,t,e){e&&n.setAttribute(t,e)},X=function(n,t){W(n,d,y(n,t.data_sizes)),W(n,s,y(n,t.data_srcset)),W(n,u,y(n,t.data_src))},Y={IMG:function(n,t){D(n,(function(n){$(n,B),X(n,t)})),$(n,B),X(n,t)},IFRAME:function(n,t){$(n,V),W(n,u,y(n,t.data_src))},VIDEO:function(n,t){H(n,(function(n){$(n,V),W(n,u,y(n,t.data_src))})),$(n,F),W(n,f,y(n,t.data_poster)),W(n,u,y(n,t.data_src)),n.load()},OBJECT:function(n,t){$(n,J),W(n,g,y(n,t.data_src))}},Z=["IMG","IFRAME","VIDEO","OBJECT"],nn=function(n,t){!t||function(n){return n.loadingCount>0}(t)||function(n){return n.toLoadCount>0}(t)||C(n.callback_finish,t)},tn=function(n,t,e){n.addEventListener(t,e),n.llEvLisnrs[t]=e},en=function(n,t,e){n.removeEventListener(t,e)},on=function(n){return!!n.llEvLisnrs},an=function(n){if(on(n)){var t=n.llEvLisnrs;for(var e in t){var i=t[e];en(n,e,i)}delete n.llEvLisnrs}},rn=function(n,t,e){!function(n){delete n.llTempImage}(n),R(e,-1),function(n){n&&(n.toLoadCount-=1)}(e),M(n,t.class_loading),t.unobserve_completed&&T(n,e)},cn=function(n,t,e){var i=z(n)||n;on(i)||function(n,t,e){on(n)||(n.llEvLisnrs={});var i="VIDEO"===n.tagName?"loadeddata":"load";tn(n,i,t),tn(n,"error",e)}(i,(function(o){!function(n,t,e,i){var o=O(t);rn(t,e,i),N(t,e.class_loaded),w(t,b),C(e.callback_loaded,t,i),o||nn(e,i)}(0,n,t,e),an(i)}),(function(o){!function(n,t,e,i){var o=O(t);rn(t,e,i),N(t,e.class_error),w(t,p),C(e.callback_error,t,i),e.restore_on_error&&q(t,B),o||nn(e,i)}(0,n,t,e),an(i)}))},ln=function(n,t,e){!function(n){return Z.indexOf(n.tagName)>-1}(n)?function(n,t,e){!function(n){n.llTempImage=document.createElement("IMG")}(n),cn(n,t,e),function(n){P(n)||(n[_]={backgroundImage:n.style.backgroundImage})}(n),function(n,t,e){var i=y(n,t.data_bg),o=y(n,t.data_bg_hidpi),r=a&&o?o:i;r&&(n.style.backgroundImage='url("'.concat(r,'")'),z(n).setAttribute(u,r),Q(n,t,e))}(n,t,e),function(n,t,e){var i=y(n,t.data_bg_multi),o=y(n,t.data_bg_multi_hidpi),r=a&&o?o:i;r&&(n.style.backgroundImage=r,K(n,t,e))}(n,t,e),function(n,t,e){var i=y(n,t.data_bg_set);if(i){var o=i.split("|"),a=o.map((function(n){return"image-set(".concat(n,")")}));n.style.backgroundImage=a.join(),""===n.style.backgroundImage&&(a=o.map((function(n){return"-webkit-image-set(".concat(n,")")})),n.style.backgroundImage=a.join()),K(n,t,e)}}(n,t,e)}(n,t,e):function(n,t,e){cn(n,t,e),function(n,t,e){var i=Y[n.tagName];i&&(i(n,t),Q(n,t,e))}(n,t,e)}(n,t,e)},un=function(n){n.removeAttribute(u),n.removeAttribute(s),n.removeAttribute(d)},sn=function(n){D(n,(function(n){q(n,B)})),q(n,B)},dn={IMG:sn,IFRAME:function(n){q(n,V)},VIDEO:function(n){H(n,(function(n){q(n,V)})),q(n,F),n.load()},OBJECT:function(n){q(n,J)}},fn=function(n,t){(function(n){var t=dn[n.tagName];t?t(n):function(n){if(P(n)){var t=S(n);n.style.backgroundImage=t.backgroundImage}}(n)})(n),function(n,t){L(n)||O(n)||(M(n,t.class_entered),M(n,t.class_exited),M(n,t.class_applied),M(n,t.class_loading),M(n,t.class_loaded),M(n,t.class_error))}(n,t),A(n),U(n)},_n=["IMG","IFRAME","VIDEO"],gn=function(n){return n.use_native&&"loading"in HTMLImageElement.prototype},vn=function(n,t,e){n.forEach((function(n){return function(n){return n.isIntersecting||n.intersectionRatio>0}(n)?function(n,t,e,i){var o=function(n){return x.indexOf(k(n))>=0}(n);w(n,"entered"),N(n,e.class_entered),M(n,e.class_exited),function(n,t,e){t.unobserve_entered&&T(n,e)}(n,e,i),C(e.callback_enter,n,t,i),o||ln(n,e,i)}(n.target,n,t,e):function(n,t,e,i){L(n)||(N(n,e.class_exited),function(n,t,e,i){e.cancel_on_exit&&function(n){return k(n)===v}(n)&&"IMG"===n.tagName&&(an(n),function(n){D(n,(function(n){un(n)})),un(n)}(n),sn(n),M(n,e.class_loading),R(i,-1),A(n),C(e.callback_cancel,n,t,i))}(n,t,e,i),C(e.callback_exit,n,t,i))}(n.target,n,t,e)}))},bn=function(n){return Array.prototype.slice.call(n)},mn=function(n){return n.container.querySelectorAll(n.elements_selector)},pn=function(n){return function(n){return k(n)===p}(n)},hn=function(n,t){return function(n){return bn(n).filter(L)}(n||mn(t))},En=function(n,e){var o=c(n);this._settings=o,this.loadingCount=0,function(n,t){i&&!gn(n)&&(t._observer=new IntersectionObserver((function(e){vn(e,n,t)}),function(n){return{root:n.container===document?null:n.container,rootMargin:n.thresholds||n.threshold+"px"}}(n)))}(o,this),function(n,e){t&&(e._onlineHandler=function(){!function(n,t){var e;(e=mn(n),bn(e).filter(pn)).forEach((function(t){M(t,n.class_error),A(t)})),t.update()}(n,e)},window.addEventListener("online",e._onlineHandler))}(o,this),this.update(e)};return En.prototype={update:function(n){var t,o,a=this._settings,r=hn(n,a);G(this,r.length),!e&&i?gn(a)?function(n,t,e){n.forEach((function(n){-1!==_n.indexOf(n.tagName)&&function(n,t,e){n.setAttribute("loading","lazy"),cn(n,t,e),function(n,t){var e=Y[n.tagName];e&&e(n,t)}(n,t),w(n,h)}(n,t,e)})),G(e,0)}(r,a,this):(o=r,function(n){n.disconnect()}(t=this._observer),function(n,t){t.forEach((function(t){n.observe(t)}))}(t,o)):this.loadAll(r)},destroy:function(){this._observer&&this._observer.disconnect(),t&&window.removeEventListener("online",this._onlineHandler),mn(this._settings).forEach((function(n){U(n)})),delete this._observer,delete this._settings,delete this._onlineHandler,delete this.loadingCount,delete this.toLoadCount},loadAll:function(n){var t=this,e=this._settings;hn(n,e).forEach((function(n){T(n,t),ln(n,e,t)}))},restoreAll:function(){var n=this._settings;mn(n).forEach((function(t){fn(t,n)}))}},En.load=function(n,t){var e=c(t);ln(n,e)},En.resetStatus=function(n){A(n)},t&&function(n,t){if(t)if(t.length)for(var e,i=0;e=t[i];i+=1)l(n,e);else l(n,t)}(En,window.lazyLoadOptions),En})); \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/lcp-beacon.js b/wp-content/plugins/wp-rocket/assets/js/lcp-beacon.js new file mode 100644 index 000000000..eb74ebfee --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lcp-beacon.js @@ -0,0 +1,369 @@ +class RocketLcpBeacon { + constructor( config ) { + this.config = config; + this.performanceImages = []; + this.errorCode = ''; + this.scriptTimer = new Date(); + this.infiniteLoopId = null; + } + + async init() { + if ( ! await this._isValidPreconditions() ) { + this._finalize(); + return; + } + + this.infiniteLoopId = setTimeout( () => { + this._handleInfiniteLoop(); + }, 10000 ); + + try { + // Use _generateLcpCandidates method to get all the elements in the viewport. + const above_the_fold_images = this._generateLcpCandidates( Infinity ); + if ( above_the_fold_images ) { + this._initWithFirstElementWithInfo( above_the_fold_images ); + this._fillATFWithoutDuplications( above_the_fold_images ); + } + } catch ( err ) { + this.errorCode = 'script_error'; + this._logMessage( 'Script Error: ' + err ); + } + + this._saveFinalResultIntoDB(); + } + + async _isValidPreconditions() { + // Check the screensize first because starting any logic. + if ( this._isNotValidScreensize() ) { + this._logMessage('Bailing out because screen size is not acceptable'); + return false; + } + + if ( this._isPageCached() && await this._isGeneratedBefore() ) { + this._logMessage('Bailing out because data is already available'); + return false; + } + + return true; + } + + _isPageCached() { + const signature = document.documentElement.nextSibling && document.documentElement.nextSibling.data ? document.documentElement.nextSibling.data : ''; + + return signature && signature.includes( 'Debug: cached' ); + } + + async _isGeneratedBefore() { + // AJAX call to check if there are any records for the current URL. + let data_check = new FormData(); + data_check.append('action', 'rocket_check_lcp'); + data_check.append('rocket_lcp_nonce', this.config.nonce); + data_check.append('url', this.config.url); + data_check.append('is_mobile', this.config.is_mobile); + + const lcp_data_response = await fetch(this.config.ajax_url, { + method: "POST", + credentials: 'same-origin', + body: data_check + }) + .then(data => data.json()); + return lcp_data_response.success; + } + + _isNotValidScreensize() { + // Check screen size + const screenWidth = window.innerWidth || document.documentElement.clientWidth; + const screenHeight= window.innerHeight || document.documentElement.clientHeight; + + const isNotValidForMobile = this.config.is_mobile && + ( screenWidth > this.config.width_threshold || screenHeight > this.config.height_threshold ); + const isNotValidForDesktop = !this.config.is_mobile && + ( screenWidth < this.config.width_threshold || screenHeight < this.config.height_threshold ); + + return isNotValidForMobile || isNotValidForDesktop; + } + + _generateLcpCandidates( count ) { + const lcpElements = document.querySelectorAll( this.config.elements ); + + if ( lcpElements.length <= 0 ) { + return []; + } + + const potentialCandidates = Array.from( lcpElements ); + + const topCandidates = potentialCandidates.map(element => { + // Skip if the element is an img and its parent is a picture + if ('img' === element.nodeName.toLowerCase() && 'picture' === element.parentElement.nodeName.toLowerCase() ) { + return null; + } + let rect; + if ('picture' === element.nodeName.toLowerCase()) { + const imgElement = element.querySelector('img'); + if (imgElement) { + rect = imgElement.getBoundingClientRect(); + } else { + return null; + } + } else { + rect = element.getBoundingClientRect(); + } + + return { + element: element, + rect: rect, + }; + }) + .filter(item => item !== null) // Filter out null values here + .filter(item => { + return ( + item.rect.width > 0 && + item.rect.height > 0 && + this._isIntersecting(item.rect) + ); + }) + .map(item => ({ + item, + area: this._getElementArea(item.rect), + elementInfo: this._getElementInfo(item.element), + })) + .sort((a, b) => b.area - a.area) + .slice(0, count); + + return topCandidates.map(candidate => ({ + element: candidate.item.element, + elementInfo: candidate.elementInfo, + })); + } + + _isIntersecting(rect) { + // Check if any part of the image is within the viewport + return ( + rect.bottom >= 0 && + rect.right >= 0 && + rect.top <= (window.innerHeight || document.documentElement.clientHeight) && + rect.left <= (window.innerWidth || document.documentElement.clientWidth) + ); + } + + _getElementArea(rect) { + const visibleWidth = Math.min(rect.width, (window.innerWidth || document.documentElement.clientWidth) - rect.left); + const visibleHeight = Math.min(rect.height, (window.innerHeight || document.documentElement.clientHeight) - rect.top); + + return visibleWidth * visibleHeight; + } + + _getElementInfo(element) { + const nodeName = element.nodeName.toLowerCase(); + const element_info = { + type: "", + src: "", + srcset: "", + sizes: "", + sources: [], + bg_set: [], + current_src: "" + }; + + const css_bg_url_rgx = /url\(\s*?['"]?\s*?(.+?)\s*?["']?\s*?\)/ig; + + if (nodeName === "img" && element.srcset) { + element_info.type = "img-srcset"; + element_info.src = element.src; + element_info.srcset = element.srcset; // capture srcset + element_info.sizes = element.sizes; // capture sizes + element_info.current_src = element.currentSrc; + } else if (nodeName === "img") { + element_info.type = "img"; + element_info.src = element.src; + element_info.current_src = element.currentSrc; + } else if (nodeName === "video") { + element_info.type = "img"; + const source = element.querySelector('source'); + element_info.src = element.poster || (source ? source.src : ''); + element_info.current_src = element_info.src; + } else if (nodeName === "svg") { + const imageElement = element.querySelector('image'); + if (imageElement) { + element_info.type = "img"; + element_info.src = imageElement.getAttribute('href') || ''; + element_info.current_src = element_info.src; + } + } else if (nodeName === "picture") { + element_info.type = "picture"; + const img = element.querySelector('img'); + element_info.src = img ? img.src : ""; + element_info.sources = Array.from(element.querySelectorAll('source')).map(source => ({ + srcset: source.srcset || '', + media: source.media || '', + type: source.type || '', + sizes: source.sizes || '' + })); + } else { + const computed_style = window.getComputedStyle(element, null); + const bg_props = [ + computed_style.getPropertyValue("background-image"), + getComputedStyle(element, ":after").getPropertyValue("background-image"), + getComputedStyle(element, ":before").getPropertyValue("background-image") + ].filter(prop => prop !== "none"); + + if (bg_props.length === 0) { + return null; + } + const full_bg_prop = bg_props[0]; + element_info.type = "bg-img"; + if (full_bg_prop.includes("image-set(")) { + element_info.type = "bg-img-set"; + } + if (!full_bg_prop || full_bg_prop === "" || full_bg_prop.includes( 'data:image' ) ) { + return null; + } + + const matches = [...full_bg_prop.matchAll(css_bg_url_rgx)]; + element_info.bg_set = matches.map(m => m[1] ? {src: m[1].trim() + (m[2] ? " " + m[2].trim() : "")} : {}); + // Check if bg_set array is populated with empty objects + if (element_info.bg_set.every(item => item.src === "")) { + // If bg_set array is populated with empty objects, populate it with the URLs from the matches array + element_info.bg_set = matches.map(m => m[1] ? {src: m[1].trim()} : {}); + } + + if (element_info.bg_set.length > 0) { + element_info.src = element_info.bg_set[0].src; + if (element_info.type === "bg-img-set") { + element_info.src = element_info.bg_set; + } + } + } + + return element_info; + } + + _initWithFirstElementWithInfo(elements) { + const firstElementWithInfo = elements.find(item => item.elementInfo !== null); + + if ( ! firstElementWithInfo ) { + this._logMessage("No LCP candidate found."); + this.performanceImages = []; + return; + } + + this.performanceImages = [{ + ...firstElementWithInfo.elementInfo, + label: "lcp", + }]; + } + + _fillATFWithoutDuplications(elements) { + elements.forEach(({ element, elementInfo }) => { + if ( this._isDuplicateImage(element) ) { + return; + } + + this.performanceImages.push({ ...elementInfo, label: "above-the-fold" }); + }); + } + + _isDuplicateImage(image) { + const elementInfo = this._getElementInfo(image); + + if (elementInfo === null) { + return false; + } + + const isImageOrVideo = + elementInfo.type === "img" || + elementInfo.type === "img-srcset" || + elementInfo.type === "video"; + + const isBgImageOrPicture = + elementInfo.type === "bg-img" || + elementInfo.type === "bg-img-set" || + elementInfo.type === "picture"; + + return (isImageOrVideo || isBgImageOrPicture) + && + this.performanceImages.some(item => item.src === elementInfo.src); + } + + _getFinalStatus() { + if ( '' !== this.errorCode ) { + return this.errorCode; + } + + const scriptTime = ( new Date() - this.scriptTimer ) / 1000; + if ( 10 <= scriptTime ) { + return 'timeout'; + } + + return 'success'; + } + + _saveFinalResultIntoDB() { + const data = new FormData(); + data.append('action', 'rocket_lcp'); + data.append('rocket_lcp_nonce', this.config.nonce); + data.append('url', this.config.url); + data.append('is_mobile', this.config.is_mobile); + data.append('images', JSON.stringify(this.performanceImages)); + data.append('status', this._getFinalStatus()); + + fetch(this.config.ajax_url, { + method: "POST", + credentials: 'same-origin', + body: data, + headers: { + 'wpr-saas-no-intercept': true + } + }) + .then((response) => response.json()) + .then((data) => { + this._logMessage(data); + }) + .catch((error) => { + this._logMessage(error); + }) + .finally(() => { + this._finalize(); + }); + } + + _handleInfiniteLoop() { + this._saveFinalResultIntoDB(); + } + + _finalize() { + const beaconscript = document.querySelector('[data-name="wpr-lcp-beacon"]'); + beaconscript.setAttribute('beacon-completed', 'true'); + clearTimeout( this.infiniteLoopId ); + } + + _logMessage( msg ) { + if ( ! this.config.debug ) { + return; + } + console.log( msg ); + } + + static run() { + if ( !window.rocket_lcp_data ) { + return; + } + + const instance = new RocketLcpBeacon( window.rocket_lcp_data ); + + if (document.readyState !== 'loading') { + setTimeout(() => { + instance.init(); + }, window.rocket_lcp_data.delay); + return; + } + + document.addEventListener("DOMContentLoaded", () => { + setTimeout(() => { + instance.init(); + }, window.rocket_lcp_data.delay); + }); + } +} + +RocketLcpBeacon.run(); diff --git a/wp-content/plugins/wp-rocket/assets/js/lcp-beacon.min.js b/wp-content/plugins/wp-rocket/assets/js/lcp-beacon.min.js new file mode 100644 index 000000000..9695b4792 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lcp-beacon.min.js @@ -0,0 +1,2 @@ +!function n(r,s,o){function c(t,e){if(!s[t]){if(!r[t]){var i="function"==typeof require&&require;if(!e&&i)return i(t,!0);if(a)return a(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}i=s[t]={exports:{}},r[t][0].call(i.exports,function(e){return c(r[t][1][e]||e)},i,i.exports,n,r,s,o)}return s[t].exports}for(var a="function"==typeof require&&require,e=0;e{this._handleInfiniteLoop()},1e4);try{var e=this._generateLcpCandidates(1/0);e&&(this._initWithFirstElementWithInfo(e),this._fillATFWithoutDuplications(e))}catch(e){this.errorCode="script_error",this._logMessage("Script Error: "+e)}this._saveFinalResultIntoDB()}else this._finalize()}async _isValidPreconditions(){return this._isNotValidScreensize()?(this._logMessage("Bailing out because screen size is not acceptable"),!1):!this._isPageCached()||!await this._isGeneratedBefore()||(this._logMessage("Bailing out because data is already available"),!1)}_isPageCached(){var e=document.documentElement.nextSibling&&document.documentElement.nextSibling.data?document.documentElement.nextSibling.data:"";return e&&e.includes("Debug: cached")}async _isGeneratedBefore(){var e=new FormData;return e.append("action","rocket_check_lcp"),e.append("rocket_lcp_nonce",this.config.nonce),e.append("url",this.config.url),e.append("is_mobile",this.config.is_mobile),(e=await fetch(this.config.ajax_url,{method:"POST",credentials:"same-origin",body:e}).then(e=>e.json())).success}_isNotValidScreensize(){var e=window.innerWidth||document.documentElement.clientWidth,t=window.innerHeight||document.documentElement.clientHeight,i=this.config.is_mobile&&(e>this.config.width_threshold||t>this.config.height_threshold),e=!this.config.is_mobile&&(e{if("img"===e.nodeName.toLowerCase()&&"picture"===e.parentElement.nodeName.toLowerCase())return null;let t;if("picture"===e.nodeName.toLowerCase()){var i=e.querySelector("img");if(!i)return null;t=i.getBoundingClientRect()}else t=e.getBoundingClientRect();return{element:e,rect:t}}).filter(e=>null!==e).filter(e=>0({item:e,area:this._getElementArea(e.rect),elementInfo:this._getElementInfo(e.element)})).sort((e,t)=>t.area-e.area).slice(0,e).map(e=>({element:e.item.element,elementInfo:e.elementInfo}))}_isIntersecting(e){return 0<=e.bottom&&0<=e.right&&e.top<=(window.innerHeight||document.documentElement.clientHeight)&&e.left<=(window.innerWidth||document.documentElement.clientWidth)}_getElementArea(e){return Math.min(e.width,(window.innerWidth||document.documentElement.clientWidth)-e.left)*Math.min(e.height,(window.innerHeight||document.documentElement.clientHeight)-e.top)}_getElementInfo(e){var t=e.nodeName.toLowerCase(),i={type:"",src:"",srcset:"",sizes:"",sources:[],bg_set:[],current_src:""};if("img"===t&&e.srcset)i.type="img-srcset",i.src=e.src,i.srcset=e.srcset,i.sizes=e.sizes,i.current_src=e.currentSrc;else if("img"===t)i.type="img",i.src=e.src,i.current_src=e.currentSrc;else if("video"===t){i.type="img";var n=e.querySelector("source");i.src=e.poster||(n?n.src:""),i.current_src=i.src}else if("svg"===t)(n=e.querySelector("image"))&&(i.type="img",i.src=n.getAttribute("href")||"",i.current_src=i.src);else if("picture"===t)i.type="picture",n=e.querySelector("img"),i.src=n?n.src:"",i.sources=Array.from(e.querySelectorAll("source")).map(e=>({srcset:e.srcset||"",media:e.media||"",type:e.type||"",sizes:e.sizes||""}));else{if(0===(t=[window.getComputedStyle(e,null).getPropertyValue("background-image"),getComputedStyle(e,":after").getPropertyValue("background-image"),getComputedStyle(e,":before").getPropertyValue("background-image")].filter(e=>"none"!==e)).length)return null;if(n=t[0],i.type="bg-img",n.includes("image-set(")&&(i.type="bg-img-set"),!n||""===n||n.includes("data:image"))return null;e=[...n.matchAll(/url\(\s*?['"]?\s*?(.+?)\s*?["']?\s*?\)/gi)],i.bg_set=e.map(e=>e[1]?{src:e[1].trim()+(e[2]?" "+e[2].trim():"")}:{}),i.bg_set.every(e=>""===e.src)&&(i.bg_set=e.map(e=>e[1]?{src:e[1].trim()}:{})),0null!==e.elementInfo))?this.performanceImages=[{...e.elementInfo,label:"lcp"}]:(this._logMessage("No LCP candidate found."),this.performanceImages=[])}_fillATFWithoutDuplications(e){e.forEach(e=>{var{element:e,elementInfo:t}=e;this._isDuplicateImage(e)||this.performanceImages.push({...t,label:"above-the-fold"})})}_isDuplicateImage(e){const t=this._getElementInfo(e);var i;return null!==t&&(e="img"===t.type||"img-srcset"===t.type||"video"===t.type,i="bg-img"===t.type||"bg-img-set"===t.type||"picture"===t.type,e||i)&&this.performanceImages.some(e=>e.src===t.src)}_getFinalStatus(){return""!==this.errorCode?this.errorCode:10<=(new Date-this.scriptTimer)/1e3?"timeout":"success"}_saveFinalResultIntoDB(){var e=new FormData;e.append("action","rocket_lcp"),e.append("rocket_lcp_nonce",this.config.nonce),e.append("url",this.config.url),e.append("is_mobile",this.config.is_mobile),e.append("images",JSON.stringify(this.performanceImages)),e.append("status",this._getFinalStatus()),fetch(this.config.ajax_url,{method:"POST",credentials:"same-origin",body:e,headers:{"wpr-saas-no-intercept":!0}}).then(e=>e.json()).then(e=>{this._logMessage(e)}).catch(e=>{this._logMessage(e)}).finally(()=>{this._finalize()})}_handleInfiniteLoop(){this._saveFinalResultIntoDB()}_finalize(){document.querySelector('[data-name="wpr-lcp-beacon"]').setAttribute("beacon-completed","true"),clearTimeout(this.infiniteLoopId)}_logMessage(e){this.config.debug&&console.log(e)}static run(){if(window.rocket_lcp_data){const e=new n(window.rocket_lcp_data);"loading"!==document.readyState?setTimeout(()=>{e.init()},window.rocket_lcp_data.delay):document.addEventListener("DOMContentLoaded",()=>{setTimeout(()=>{e.init()},window.rocket_lcp_data.delay)})}}}).run()},{}]},{},[1]); +//# sourceMappingURL=lcp-beacon.min.js.map diff --git a/wp-content/plugins/wp-rocket/assets/js/lcp-beacon.min.js.map b/wp-content/plugins/wp-rocket/assets/js/lcp-beacon.min.js.map new file mode 100644 index 000000000..4db70f412 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/lcp-beacon.min.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"mappings":"","sources":["lcp-beacon.min.js"],"sourcesContent":["!function n(r,s,o){function c(t,e){if(!s[t]){if(!r[t]){var i=\"function\"==typeof require&&require;if(!e&&i)return i(t,!0);if(a)return a(t,!0);throw(e=new Error(\"Cannot find module '\"+t+\"'\")).code=\"MODULE_NOT_FOUND\",e}i=s[t]={exports:{}},r[t][0].call(i.exports,function(e){return c(r[t][1][e]||e)},i,i.exports,n,r,s,o)}return s[t].exports}for(var a=\"function\"==typeof require&&require,e=0;e{this._handleInfiniteLoop()},1e4);try{var e=this._generateLcpCandidates(1/0);e&&(this._initWithFirstElementWithInfo(e),this._fillATFWithoutDuplications(e))}catch(e){this.errorCode=\"script_error\",this._logMessage(\"Script Error: \"+e)}this._saveFinalResultIntoDB()}else this._finalize()}async _isValidPreconditions(){return this._isNotValidScreensize()?(this._logMessage(\"Bailing out because screen size is not acceptable\"),!1):!this._isPageCached()||!await this._isGeneratedBefore()||(this._logMessage(\"Bailing out because data is already available\"),!1)}_isPageCached(){var e=document.documentElement.nextSibling&&document.documentElement.nextSibling.data?document.documentElement.nextSibling.data:\"\";return e&&e.includes(\"Debug: cached\")}async _isGeneratedBefore(){var e=new FormData;return e.append(\"action\",\"rocket_check_lcp\"),e.append(\"rocket_lcp_nonce\",this.config.nonce),e.append(\"url\",this.config.url),e.append(\"is_mobile\",this.config.is_mobile),(e=await fetch(this.config.ajax_url,{method:\"POST\",credentials:\"same-origin\",body:e}).then(e=>e.json())).success}_isNotValidScreensize(){var e=window.innerWidth||document.documentElement.clientWidth,t=window.innerHeight||document.documentElement.clientHeight,i=this.config.is_mobile&&(e>this.config.width_threshold||t>this.config.height_threshold),e=!this.config.is_mobile&&(e{if(\"img\"===e.nodeName.toLowerCase()&&\"picture\"===e.parentElement.nodeName.toLowerCase())return null;let t;if(\"picture\"===e.nodeName.toLowerCase()){var i=e.querySelector(\"img\");if(!i)return null;t=i.getBoundingClientRect()}else t=e.getBoundingClientRect();return{element:e,rect:t}}).filter(e=>null!==e).filter(e=>0({item:e,area:this._getElementArea(e.rect),elementInfo:this._getElementInfo(e.element)})).sort((e,t)=>t.area-e.area).slice(0,e).map(e=>({element:e.item.element,elementInfo:e.elementInfo}))}_isIntersecting(e){return 0<=e.bottom&&0<=e.right&&e.top<=(window.innerHeight||document.documentElement.clientHeight)&&e.left<=(window.innerWidth||document.documentElement.clientWidth)}_getElementArea(e){return Math.min(e.width,(window.innerWidth||document.documentElement.clientWidth)-e.left)*Math.min(e.height,(window.innerHeight||document.documentElement.clientHeight)-e.top)}_getElementInfo(e){var t=e.nodeName.toLowerCase(),i={type:\"\",src:\"\",srcset:\"\",sizes:\"\",sources:[],bg_set:[],current_src:\"\"};if(\"img\"===t&&e.srcset)i.type=\"img-srcset\",i.src=e.src,i.srcset=e.srcset,i.sizes=e.sizes,i.current_src=e.currentSrc;else if(\"img\"===t)i.type=\"img\",i.src=e.src,i.current_src=e.currentSrc;else if(\"video\"===t){i.type=\"img\";var n=e.querySelector(\"source\");i.src=e.poster||(n?n.src:\"\"),i.current_src=i.src}else if(\"svg\"===t)(n=e.querySelector(\"image\"))&&(i.type=\"img\",i.src=n.getAttribute(\"href\")||\"\",i.current_src=i.src);else if(\"picture\"===t)i.type=\"picture\",n=e.querySelector(\"img\"),i.src=n?n.src:\"\",i.sources=Array.from(e.querySelectorAll(\"source\")).map(e=>({srcset:e.srcset||\"\",media:e.media||\"\",type:e.type||\"\",sizes:e.sizes||\"\"}));else{if(0===(t=[window.getComputedStyle(e,null).getPropertyValue(\"background-image\"),getComputedStyle(e,\":after\").getPropertyValue(\"background-image\"),getComputedStyle(e,\":before\").getPropertyValue(\"background-image\")].filter(e=>\"none\"!==e)).length)return null;if(n=t[0],i.type=\"bg-img\",n.includes(\"image-set(\")&&(i.type=\"bg-img-set\"),!n||\"\"===n||n.includes(\"data:image\"))return null;e=[...n.matchAll(/url\\(\\s*?['\"]?\\s*?(.+?)\\s*?[\"']?\\s*?\\)/gi)],i.bg_set=e.map(e=>e[1]?{src:e[1].trim()+(e[2]?\" \"+e[2].trim():\"\")}:{}),i.bg_set.every(e=>\"\"===e.src)&&(i.bg_set=e.map(e=>e[1]?{src:e[1].trim()}:{})),0null!==e.elementInfo))?this.performanceImages=[{...e.elementInfo,label:\"lcp\"}]:(this._logMessage(\"No LCP candidate found.\"),this.performanceImages=[])}_fillATFWithoutDuplications(e){e.forEach(e=>{var{element:e,elementInfo:t}=e;this._isDuplicateImage(e)||this.performanceImages.push({...t,label:\"above-the-fold\"})})}_isDuplicateImage(e){const t=this._getElementInfo(e);var i;return null!==t&&(e=\"img\"===t.type||\"img-srcset\"===t.type||\"video\"===t.type,i=\"bg-img\"===t.type||\"bg-img-set\"===t.type||\"picture\"===t.type,e||i)&&this.performanceImages.some(e=>e.src===t.src)}_getFinalStatus(){return\"\"!==this.errorCode?this.errorCode:10<=(new Date-this.scriptTimer)/1e3?\"timeout\":\"success\"}_saveFinalResultIntoDB(){var e=new FormData;e.append(\"action\",\"rocket_lcp\"),e.append(\"rocket_lcp_nonce\",this.config.nonce),e.append(\"url\",this.config.url),e.append(\"is_mobile\",this.config.is_mobile),e.append(\"images\",JSON.stringify(this.performanceImages)),e.append(\"status\",this._getFinalStatus()),fetch(this.config.ajax_url,{method:\"POST\",credentials:\"same-origin\",body:e,headers:{\"wpr-saas-no-intercept\":!0}}).then(e=>e.json()).then(e=>{this._logMessage(e)}).catch(e=>{this._logMessage(e)}).finally(()=>{this._finalize()})}_handleInfiniteLoop(){this._saveFinalResultIntoDB()}_finalize(){document.querySelector('[data-name=\"wpr-lcp-beacon\"]').setAttribute(\"beacon-completed\",\"true\"),clearTimeout(this.infiniteLoopId)}_logMessage(e){this.config.debug&&console.log(e)}static run(){if(window.rocket_lcp_data){const e=new n(window.rocket_lcp_data);\"loading\"!==document.readyState?setTimeout(()=>{e.init()},window.rocket_lcp_data.delay):document.addEventListener(\"DOMContentLoaded\",()=>{setTimeout(()=>{e.init()},window.rocket_lcp_data.delay)})}}}).run()},{}]},{},[1]);"],"file":"lcp-beacon.min.js"} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/micromodal.min.js b/wp-content/plugins/wp-rocket/assets/js/micromodal.min.js index 02ee0109f..09167d26a 100644 --- a/wp-content/plugins/wp-rocket/assets/js/micromodal.min.js +++ b/wp-content/plugins/wp-rocket/assets/js/micromodal.min.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).MicroModal=t()}(this,function(){"use strict";return(()=>{const e=["a[href]","area[href]",'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',"select:not([disabled]):not([aria-hidden])","textarea:not([disabled]):not([aria-hidden])","button:not([disabled]):not([aria-hidden])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex^="-"])'];class t{constructor({targetModal:e,triggers:t=[],onShow:o=(()=>{}),onClose:i=(()=>{}),openTrigger:n="data-micromodal-trigger",closeTrigger:s="data-micromodal-close",disableScroll:a=!1,disableFocus:l=!1,awaitCloseAnimation:d=!1,awaitOpenAnimation:r=!1,debugMode:c=!1}){this.modal=document.getElementById(e),this.config={debugMode:c,disableScroll:a,openTrigger:n,closeTrigger:s,onShow:o,onClose:i,awaitCloseAnimation:d,awaitOpenAnimation:r,disableFocus:l},t.length>0&&this.registerTriggers(...t),this.onClick=this.onClick.bind(this),this.onKeydown=this.onKeydown.bind(this)}registerTriggers(...e){e.filter(Boolean).forEach(e=>{e.addEventListener("click",e=>this.showModal(e))})}showModal(){if(this.activeElement=document.activeElement,this.modal.setAttribute("aria-hidden","false"),this.modal.classList.add("is-open"),this.scrollBehaviour("disable"),this.addEventListeners(),this.config.awaitOpenAnimation){const e=()=>{this.modal.removeEventListener("animationend",e,!1),this.setFocusToFirstNode()};this.modal.addEventListener("animationend",e,!1)}else this.setFocusToFirstNode();this.config.onShow(this.modal,this.activeElement)}closeModal(){const e=this.modal;this.modal.setAttribute("aria-hidden","true"),this.removeEventListeners(),this.scrollBehaviour("enable"),this.activeElement&&this.activeElement.focus(),this.config.onClose(this.modal),this.config.awaitCloseAnimation?this.modal.addEventListener("animationend",function t(){e.classList.remove("is-open"),e.removeEventListener("animationend",t,!1)},!1):e.classList.remove("is-open")}closeModalById(e){this.modal=document.getElementById(e),this.modal&&this.closeModal()}scrollBehaviour(e){if(!this.config.disableScroll)return;const t=document.querySelector("body");switch(e){case"enable":Object.assign(t.style,{overflow:"",height:""});break;case"disable":Object.assign(t.style,{overflow:"hidden",height:"100vh"})}}addEventListeners(){this.modal.addEventListener("touchstart",this.onClick),this.modal.addEventListener("click",this.onClick),document.addEventListener("keydown",this.onKeydown)}removeEventListeners(){this.modal.removeEventListener("touchstart",this.onClick),this.modal.removeEventListener("click",this.onClick),document.removeEventListener("keydown",this.onKeydown)}onClick(e){e.target.hasAttribute(this.config.closeTrigger)&&(this.closeModal(),e.preventDefault())}onKeydown(e){27===e.keyCode&&this.closeModal(e),9===e.keyCode&&this.maintainFocus(e)}getFocusableNodes(){const t=this.modal.querySelectorAll(e);return Array(...t)}setFocusToFirstNode(){if(this.config.disableFocus)return;const e=this.getFocusableNodes();e.length&&e[0].focus()}maintainFocus(e){const t=this.getFocusableNodes();if(this.modal.contains(document.activeElement)){const o=t.indexOf(document.activeElement);e.shiftKey&&0===o&&(t[t.length-1].focus(),e.preventDefault()),e.shiftKey||o!==t.length-1||(t[0].focus(),e.preventDefault())}else t[0].focus()}}let o=null;const i=e=>{if(!document.getElementById(e))return console.warn(`MicroModal: ❗Seems like you have missed %c'${e}'`,"background-color: #f8f9fa;color: #50596c;font-weight: bold;","ID somewhere in your code. Refer example below to resolve it."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",``),!1},n=(e,t)=>{if((e=>{if(e.length<=0)console.warn("MicroModal: ❗Please specify at least one %c'micromodal-trigger'","background-color: #f8f9fa;color: #50596c;font-weight: bold;","data attribute."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",'')})(e),!t)return!0;for(var o in t)i(o);return!0};return{init:e=>{const i=Object.assign({},{openTrigger:"data-micromodal-trigger"},e),s=[...document.querySelectorAll(`[${i.openTrigger}]`)],a=((e,t)=>{const o=[];return e.forEach(e=>{const i=e.attributes[t].value;void 0===o[i]&&(o[i]=[]),o[i].push(e)}),o})(s,i.openTrigger);if(!0!==i.debugMode||!1!==n(s,a))for(var l in a){let e=a[l];i.targetModal=l,i.triggers=[...e],o=new t(i)}},show:(e,n)=>{const s=n||{};s.targetModal=e,!0===s.debugMode&&!1===i(e)||(o=new t(s)).showModal()},close:e=>{e?o.closeModalById(e):o.closeModal()}}})()}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).MicroModal=t()}(this,(function(){"use strict";function e(e,t){for(var o=0;oe.length)&&(t=e.length);for(var o=0,n=new Array(t);o0&&this.registerTriggers.apply(this,t(a)),this.onClick=this.onClick.bind(this),this.onKeydown=this.onKeydown.bind(this)}var i,a,r;return i=o,(a=[{key:"registerTriggers",value:function(){for(var e=this,t=arguments.length,o=new Array(t),n=0;n0&&void 0!==arguments[0]?arguments[0]:null;if(this.activeElement=document.activeElement,this.modal.setAttribute("aria-hidden","false"),this.modal.classList.add(this.config.openClass),this.scrollBehaviour("disable"),this.addEventListeners(),this.config.awaitOpenAnimation){var o=function t(){e.modal.removeEventListener("animationend",t,!1),e.setFocusToFirstNode()};this.modal.addEventListener("animationend",o,!1)}else this.setFocusToFirstNode();this.config.onShow(this.modal,this.activeElement,t)}},{key:"closeModal",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=this.modal;if(this.modal.setAttribute("aria-hidden","true"),this.removeEventListeners(),this.scrollBehaviour("enable"),this.activeElement&&this.activeElement.focus&&this.activeElement.focus(),this.config.onClose(this.modal,this.activeElement,e),this.config.awaitCloseAnimation){var o=this.config.openClass;this.modal.addEventListener("animationend",(function e(){t.classList.remove(o),t.removeEventListener("animationend",e,!1)}),!1)}else t.classList.remove(this.config.openClass)}},{key:"closeModalById",value:function(e){this.modal=document.getElementById(e),this.modal&&this.closeModal()}},{key:"scrollBehaviour",value:function(e){if(this.config.disableScroll){var t=document.querySelector("body");switch(e){case"enable":Object.assign(t.style,{overflow:""});break;case"disable":Object.assign(t.style,{overflow:"hidden"})}}}},{key:"addEventListeners",value:function(){this.modal.addEventListener("touchstart",this.onClick),this.modal.addEventListener("click",this.onClick),document.addEventListener("keydown",this.onKeydown)}},{key:"removeEventListeners",value:function(){this.modal.removeEventListener("touchstart",this.onClick),this.modal.removeEventListener("click",this.onClick),document.removeEventListener("keydown",this.onKeydown)}},{key:"onClick",value:function(e){(e.target.hasAttribute(this.config.closeTrigger)||e.target.parentNode.hasAttribute(this.config.closeTrigger))&&(e.preventDefault(),e.stopPropagation(),this.closeModal(e))}},{key:"onKeydown",value:function(e){27===e.keyCode&&this.closeModal(e),9===e.keyCode&&this.retainFocus(e)}},{key:"getFocusableNodes",value:function(){var e=this.modal.querySelectorAll(n);return Array.apply(void 0,t(e))}},{key:"setFocusToFirstNode",value:function(){var e=this;if(!this.config.disableFocus){var t=this.getFocusableNodes();if(0!==t.length){var o=t.filter((function(t){return!t.hasAttribute(e.config.closeTrigger)}));o.length>0&&o[0].focus(),0===o.length&&t[0].focus()}}}},{key:"retainFocus",value:function(e){var t=this.getFocusableNodes();if(0!==t.length)if(t=t.filter((function(e){return null!==e.offsetParent})),this.modal.contains(document.activeElement)){var o=t.indexOf(document.activeElement);e.shiftKey&&0===o&&(t[t.length-1].focus(),e.preventDefault()),!e.shiftKey&&t.length>0&&o===t.length-1&&(t[0].focus(),e.preventDefault())}else t[0].focus()}}])&&e(i.prototype,a),r&&e(i,r),o}(),a=null,r=function(e){if(!document.getElementById(e))return console.warn("MicroModal: ❗Seems like you have missed %c'".concat(e,"'"),"background-color: #f8f9fa;color: #50596c;font-weight: bold;","ID somewhere in your code. Refer example below to resolve it."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",'')),!1},s=function(e,t){if(function(e){e.length<=0&&(console.warn("MicroModal: ❗Please specify at least one %c'micromodal-trigger'","background-color: #f8f9fa;color: #50596c;font-weight: bold;","data attribute."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",''))}(e),!t)return!0;for(var o in t)r(o);return!0},{init:function(e){var o=Object.assign({},{openTrigger:"data-micromodal-trigger"},e),n=t(document.querySelectorAll("[".concat(o.openTrigger,"]"))),r=function(e,t){var o=[];return e.forEach((function(e){var n=e.attributes[t].value;void 0===o[n]&&(o[n]=[]),o[n].push(e)})),o}(n,o.openTrigger);if(!0!==o.debugMode||!1!==s(n,r))for(var l in r){var c=r[l];o.targetModal=l,o.triggers=t(c),a=new i(o)}},show:function(e,t){var o=t||{};o.targetModal=e,!0===o.debugMode&&!1===r(e)||(a&&a.removeEventListeners(),(a=new i(o)).showModal())},close:function(e){e?a.closeModalById(e):a.closeModal()}});return"undefined"!=typeof window&&(window.MicroModal=l),l})); diff --git a/wp-content/plugins/wp-rocket/assets/js/wpr-admin-common.js b/wp-content/plugins/wp-rocket/assets/js/wpr-admin-common.js index 23ce05dc8..92a97f2cb 100644 --- a/wp-content/plugins/wp-rocket/assets/js/wpr-admin-common.js +++ b/wp-content/plugins/wp-rocket/assets/js/wpr-admin-common.js @@ -1,7 +1,62 @@ jQuery( document ).ready( function( $ ){ +var sent = false; $( '.rocket-dismiss' ).on( 'click', function( e ) { e.preventDefault(); var url = $( this ).attr( 'href' ).replace( 'admin-post', 'admin-ajax' ); $.get( url ).done( $( this ).closest( '.notice' ).hide( 'slow' ) ); }); + + $( '#deactivate' ).click( function() { + $( '#export_settings' ).prop( 'checked', false ); + $( '#export_settings' ).hide(); + $( 'label[for=export_settings]' ).hide(); + }); + + $( '#safe_mode' ).click( function() { + $( '#export_settings' ).show(); + $( 'label[for=export_settings]' ).show(); + $( '#export_settings' ).prop( 'checked', true ); + }); + + $( '#wpr-deactivation-intent-form' ).submit(function (e) { + const checked = $( '#export_settings' ).prop('checked'); + if(! checked || sent) { + return true; + } + + e.preventDefault(); + $.ajax( { + url: rocket_option_export.rest_url_option_export, + method: 'GET', + success: function( data, textStatus, xhr ) { + const disposition = xhr.getResponseHeader('content-disposition'); + + const filenames = disposition.match('filename="([^"]+)"'); + + if(! filenames.length) { + return; + } + + const filename = filenames.pop(); + + const url = URL.createObjectURL( new Blob( [ JSON.stringify(data, null, 2) ], { + type: "octet/stream" + })); + + var a = document.createElement("a"); + document.body.appendChild(a); + a.style = "display: none"; + a.href = url; + a.download = filename; + a.click(); + window.URL.revokeObjectURL(url); + }, + complete: function () { + sent = true; + $( '#wpr-deactivation-intent-form' ).submit(); + } + } ); + + return true; + }); } ); diff --git a/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js index df039ee28..db26a2756 100644 --- a/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js +++ b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js @@ -1,2 +1,3101 @@ -!function r(a,o,l){function h(e,t){if(!o[e]){if(!a[e]){var i="function"==typeof require&&require;if(!t&&i)return i(e,!0);if(c)return c(e,!0);var n=new Error("Cannot find module '"+e+"'");throw n.code="MODULE_NOT_FOUND",n}var s=o[e]={exports:{}};a[e][0].call(s.exports,function(t){return h(a[e][1][t]||t)},s,s.exports,r,a,o,l)}return o[e].exports}for(var c="function"==typeof require&&require,t=0;t form > #wpr-options-submit"),this.$pages=document.querySelectorAll(".wpr-Page"),this.$sidebar=document.querySelector(".wpr-Sidebar"),this.$content=document.querySelector(".wpr-Content"),this.$tips=document.querySelector(".wpr-Content-tips"),this.$links=document.querySelectorAll(".wpr-body a"),this.$menuItem=null,this.$page=null,this.pageId=null,this.bodyTop=0,this.buttonText=this.$submitButton.value,i.getBodyTop(),window.onhashchange=function(){i.detectID()},window.location.hash?(this.bodyTop=0,this.detectID()):(e=localStorage.getItem("wpr-hash"),this.bodyTop=0,e?(window.location.hash=e,this.detectID()):(this.$menuItems[0].classList.add("isActive"),localStorage.setItem("wpr-hash","dashboard"),window.location.hash="#dashboard"));for(var n=0;nl;l++)i.startAt&&(i.startAt=d(i.startAt)),h.to(t[l],e,d(i),l*n);return this.add(h,s)},t.staggerFrom=function(t,e,i,n,s,r,a,o){return i.immediateRender=0!=i.immediateRender,i.runBackwards=!0,this.staggerTo(t,e,i,n,s,r,a,o)},t.staggerFromTo=function(t,e,i,n,s,r,a,o,l){return n.startAt=i,n.immediateRender=0!=n.immediateRender&&0!=i.immediateRender,this.staggerTo(t,e,n,s,r,a,o,l)},t.call=function(t,e,i,n){return this.add(p.delayedCall(0,t,e,i),n)},t.set=function(t,e,i){return i=this._parseTimeOrLabel(i,0,!0),null==e.immediateRender&&(e.immediateRender=i===this._time&&!this._paused),this.add(new p(t,0,e),i)},f.exportRoot=function(t,e){null==(t=t||{}).smoothChildTiming&&(t.smoothChildTiming=!0);var i,n,s=new f(t),r=s._timeline;for(null==e&&(e=!0),r._remove(s,!0),s._startTime=0,s._rawPrevTime=s._time=s._totalTime=r._time,i=r._first;i;)n=i._next,e&&i instanceof p&&i.target===i.vars.onComplete||s.add(i,i._startTime-i._delay),i=n;return r.add(s,0),s},t.add=function(t,e,i,n){var s,r,a,o,l,h;if("number"!=typeof e&&(e=this._parseTimeOrLabel(e,0,!0,t)),!(t instanceof c)){if(t instanceof Array||t&&t.push&&g(t)){for(i=i||"normal",n=n||0,s=e,r=t.length,a=0;at._startTime;l._timeline;)h&&l._timeline.smoothChildTiming?l.totalTime(l._totalTime,!0):l._gc&&l._enabled(!0,!1),l=l._timeline;return this},t.remove=function(t){if(t instanceof c)return this._remove(t,!1);if(t instanceof Array||t&&t.push&&g(t)){for(var e=t.length;-1<--e;)this.remove(t[e]);return this}return"string"==typeof t?this.removeLabel(t):this.kill(null,t)},t._remove=function(t,e){u.prototype._remove.call(this,t,e);var i=this._last;return i?this._time>i._startTime+i._totalDuration/i._timeScale&&(this._time=this.duration(),this._totalTime=this._totalDuration):this._time=this._totalTime=this._duration=this._totalDuration=0,this},t.append=function(t,e){return this.add(t,this._parseTimeOrLabel(null,e,!0,t))},t.insert=t.insertMultiple=function(t,e,i,n){return this.add(t,e||0,i,n)},t.appendMultiple=function(t,e,i,n){return this.add(t,this._parseTimeOrLabel(null,e,!0,t),i,n)},t.addLabel=function(t,e){return this._labels[t]=this._parseTimeOrLabel(e),this},t.addPause=function(t,e,i,n){return this.call(s,["{self}",e,i,n],this,t)},t.removeLabel=function(t){return delete this._labels[t],this},t.getLabelTime=function(t){return null!=this._labels[t]?this._labels[t]:-1},t._parseTimeOrLabel=function(t,e,i,n){var s;if(n instanceof c&&n.timeline===this)this.remove(n);else if(n&&(n instanceof Array||n.push&&g(n)))for(s=n.length;-1<--s;)n[s]instanceof c&&n[s].timeline===this&&this.remove(n[s]);if("string"==typeof e)return this._parseTimeOrLabel(e,i&&"number"==typeof t&&null==this._labels[e]?t-this.duration():0,i);if(e=e||0,"string"!=typeof t||!isNaN(t)&&null==this._labels[t])null==t&&(t=this.duration());else{if(-1===(s=t.indexOf("=")))return null==this._labels[t]?i?this._labels[t]=this.duration()+e:e:this._labels[t]+e;e=parseInt(t.charAt(s-1)+"1",10)*Number(t.substr(s+1)),t=1_&&(a="onReverseComplete"))),this._rawPrevTime=this._duration||!e||t||this._rawPrevTime===t?t:_,t=l+1e-4):t<1e-7?(((this._totalTime=this._time=0)!==h||0===this._duration&&this._rawPrevTime!==_&&(0=h)for(n=this._first;n&&(r=n._next,!this._paused||p);)(n._active||n._startTime<=this._time&&!n._paused&&!n._gc)&&(n._reversed?n.render((n._dirty?n.totalDuration():n._totalDuration)-(t-n._startTime)*n._timeScale,e,i):n.render((t-n._startTime)*n._timeScale,e,i)),n=r;else for(n=this._last;n&&(r=n._prev,!this._paused||p);)(n._active||h>=n._startTime&&!n._paused&&!n._gc)&&(n._reversed?n.render((n._dirty?n.totalDuration():n._totalDuration)-(t-n._startTime)*n._timeScale,e,i):n.render((t-n._startTime)*n._timeScale,e,i)),n=r;this._onUpdate&&(e||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||v)),a&&(this._gc||c!==this._startTime&&u===this._timeScale||!(0===this._time||l>=this.totalDuration())||(s&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[a]&&this.vars[a].apply(this.vars[a+"Scope"]||this,this.vars[a+"Params"]||v)))}},t._hasPausedChild=function(){for(var t=this._first;t;){if(t._paused||t instanceof f&&t._hasPausedChild())return!0;t=t._next}return!1},t.getChildren=function(t,e,i,n){n=n||-9999999999;for(var s=[],r=this._first,a=0;r;)n>r._startTime||(r instanceof p?!1!==e&&(s[a++]=r):(!1!==i&&(s[a++]=r),!1!==t&&(a=(s=s.concat(r.getChildren(!0,e,i))).length))),r=r._next;return s},t.getTweensOf=function(t,e){var i,n,s=this._gc,r=[],a=0;for(s&&this._enabled(!0,!0),n=(i=p.getTweensOf(t)).length;-1<--n;)(i[n].timeline===this||e&&this._contains(i[n]))&&(r[a++]=i[n]);return s&&this._enabled(!1,!0),r},t._contains=function(t){for(var e=t.timeline;e;){if(e===this)return!0;e=e.timeline}return!1},t.shiftChildren=function(t,e,i){i=i||0;for(var n,s=this._first,r=this._labels;s;)s._startTime>=i&&(s._startTime+=t),s=s._next;if(e)for(n in r)r[n]>=i&&(r[n]+=t);return this._uncache(!0)},t._kill=function(t,e){if(!t&&!e)return this._enabled(!1,!1);for(var i=e?this.getTweensOf(e):this.getChildren(!0,!0,!1),n=i.length,s=!1;-1<--n;)i[n]._kill(t,e)&&(s=!0);return s},t.clear=function(t){var e=this.getChildren(!1,!0,!0),i=e.length;for(this._time=this._totalTime=0;-1<--i;)e[i]._enabled(!1,!1);return!1!==t&&(this._labels={}),this._uncache(!0)},t.invalidate=function(){for(var t=this._first;t;)t.invalidate(),t=t._next;return this},t._enabled=function(t,e){if(t===this._gc)for(var i=this._first;i;)i._enabled(t,!0),i=i._next;return u.prototype._enabled.call(this,t,e)},t.duration=function(t){return arguments.length?(0!==this.duration()&&0!==t&&this.timeScale(this._duration/t),this):(this._dirty&&this.totalDuration(),this._duration)},t.totalDuration=function(t){if(arguments.length)return 0!==this.totalDuration()&&0!==t&&this.timeScale(this._totalDuration/t),this;if(this._dirty){for(var e,i,n=0,s=this._last,r=999999999999;s;)e=s._prev,s._dirty&&s.totalDuration(),s._startTime>r&&this._sortChildren&&!s._paused?this.add(s,s._startTime-s._delay):r=s._startTime,s._startTime<0&&!s._paused&&(n-=s._startTime,this._timeline.smoothChildTiming&&(this._startTime+=s._startTime/this._timeScale),this.shiftChildren(-s._startTime,!1,-9999999999),r=0),n<(i=s._startTime+s._totalDuration/s._timeScale)&&(n=i),s=e;this._duration=this._totalDuration=n,this._dirty=!1}return this._totalDuration},t.usesFrames=function(){for(var t=this._timeline;t._timeline;)t=t._timeline;return t===c._rootFramesTimeline},t.rawTime=function(){return this._paused?this._totalTime:(this._timeline.rawTime()-this._startTime)*this._timeScale},f},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],10:[function(t,W,e){"use strict";var Q="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};!function(f){var e,i,d=f.GreenSockGlobals||f;if(!d.TweenLite){var _,m=function(t){for(var e=t.split("."),i=d,n=0;e.length>n;n++)i[e[n]]=i=i[e[n]]||{};return i},u=m("com.greensock"),g=1e-10,l=[].slice,n=function(){},c=(e=Object.prototype.toString,i=e.call([]),function(t){return null!=t&&(t instanceof Array||"object"==(void 0===t?"undefined":Q(t))&&!!t.push&&e.call(t)===i)}),v={},s=function o(l,h,c,u){this.sc=v[l]?v[l].sc:[],(v[l]=this).gsClass=null,this.func=c;var p=[];this.check=function(t){for(var e,i,n,s,r=h.length,a=r;-1<--r;)(e=v[h[r]]||new o(h[r],[])).gsClass?(p[r]=e.gsClass,a--):t&&e.sc.push(this);if(0===a&&c)for(n=(i=("com.greensock."+l).split(".")).pop(),s=m(i.join("."))[n]=this.gsClass=c.apply(c,p),u&&(d[n]=s,"function"==typeof define&&define.amd?define((f.GreenSockAMDPath?f.GreenSockAMDPath+"/":"")+l.split(".").join("/"),[],function(){return s}):void 0!==W&&W.exports&&(W.exports=s)),r=0;this.sc.length>r;r++)this.sc[r].check()},this.check(!0)},r=f._gsDefine=function(t,e,i,n){return new s(t,e,i,n)},p=u._class=function(t,e,i){return e=e||function(){},r(t,[],function(){return e},i),e};r.globals=d;var t,a=[0,0,1,1],w=[],y=p("easing.Ease",function(t,e,i,n){this._func=t,this._type=i||0,this._power=n||0,this._params=e?a.concat(e):a},!0),x=y.map={},o=y.register=function(t,e,i,n){for(var s,r,a,o,l=e.split(","),h=l.length,c=(i||"easeIn,easeOut,easeInOut").split(",");-1<--h;)for(r=l[h],s=n?p("easing."+r,null,!0):u.easing[r]||{},a=c.length;-1<--a;)o=c[a],x[r+"."+o]=x[o+r]=s[o]=t.getRatio?t:t[o]||new t};for((t=y.prototype)._calcEnd=!1,t.getRatio=function(t){if(this._func)return this._params[0]=t,this._func.apply(null,this._params);var e=this._type,i=this._power,n=1===e?1-t:2===e?t:t<.5?2*t:2*(1-t);return 1===i?n*=n:2===i?n*=n*n:3===i?n*=n*n*n:4===i&&(n*=n*n*n*n),1===e?1-n:2===e?n:t<.5?n/2:1-n/2},O=(h=["Linear","Quad","Cubic","Quart","Quint,Strong"]).length;-1<--O;)t=h[O]+",Power"+O,o(new y(null,null,1,O),t,"easeOut",!0),o(new y(null,null,2,O),t,"easeIn"+(0===O?",easeNone":"")),o(new y(null,null,3,O),t,"easeInOut");x.linear=u.easing.Linear.easeIn,x.swing=u.easing.Quad.easeInOut;var b=p("events.EventDispatcher",function(t){this._listeners={},this._eventTarget=t||this});(t=b.prototype).addEventListener=function(t,e,i,n,s){s=s||0;var r,a,o=this._listeners[t],l=0;for(null==o&&(this._listeners[t]=o=[]),a=o.length;-1<--a;)(r=o[a]).c===e&&r.s===i?o.splice(a,1):0===l&&s>r.pr&&(l=a+1);o.splice(l,0,{c:e,s:i,up:n,pr:s}),this!==A||_||A.wake()},t.removeEventListener=function(t,e){var i,n=this._listeners[t];if(n)for(i=n.length;-1<--i;)if(n[i].c===e)return void n.splice(i,1)},t.dispatchEvent=function(t){var e,i,n,s=this._listeners[t];if(s)for(e=s.length,i=this._eventTarget;-1<--e;)(n=s[e]).up?n.c.call(n.s||i,{type:t,target:i}):n.c.call(n.s||i)};for(var h,T=f.requestAnimationFrame,k=f.cancelAnimationFrame,P=Date.now||function(){return(new Date).getTime()},S=P(),O=(h=["ms","moz","webkit","o"]).length;-1<--O&&!T;)T=f[h[O]+"RequestAnimationFrame"],k=f[h[O]+"CancelAnimationFrame"]||f[h[O]+"CancelRequestAnimationFrame"];p("Ticker",function(t,e){function s(t){var e,i,n=P()-S;p=i&&i+this.totalDuration()/this._timeScale>t},t._enabled=function(t,e){return _||A.wake(),this._gc=!t,this._active=this.isActive(),!0!==e&&(t&&!this.timeline?this._timeline.add(this,this._startTime-this._delay):!t&&this.timeline&&this._timeline._remove(this,!0)),!1},t._kill=function(){return this._enabled(!1,!1)},t.kill=function(t,e){return this._kill(t,e),this},t._uncache=function(t){for(var e=t?this:this.timeline;e;)e._dirty=!0,e=e.timeline;return this},t._swapSelfInParams=function(t){for(var e=t.length,i=t.concat();-1<--e;)"{self}"===t[e]&&(i[e]=this);return i},t.eventCallback=function(t,e,i,n){if("on"===(t||"").substr(0,2)){var s=this.vars;if(1===arguments.length)return s[t];null==e?delete s[t]:(s[t]=e,s[t+"Params"]=c(i)&&-1!==i.join("").indexOf("{self}")?this._swapSelfInParams(i):i,s[t+"Scope"]=n),"onUpdate"===t&&(this._onUpdate=e)}return this},t.delay=function(t){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+t-this._delay),this._delay=t,this):this._delay},t.duration=function(t){return arguments.length?(this._duration=this._totalDuration=t,this._uncache(!0),this._timeline.smoothChildTiming&&0this._duration?this._duration:t,e)):this._time},t.totalTime=function(t,e,i){if(_||A.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(t<0&&!i&&(t+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var n=this._totalDuration,s=this._timeline;if(nn;)i=i._prev;return i?(t._next=i._next,i._next=t):(t._next=this._first,this._first=t),t._next?t._next._prev=t:this._last=t,t._prev=i,this._timeline&&this._uncache(!0),this},t._remove=function(t,e){return t.timeline===this&&(e||t._enabled(!1,!0),t.timeline=null,t._prev?t._prev._next=t._next:this._first===t&&(this._first=t._next),t._next?t._next._prev=t._prev:this._last===t&&(this._last=t._prev),this._timeline&&this._uncache(!0)),this},t.render=function(t,e,i){var n,s=this._first;for(this._totalTime=this._time=this._rawPrevTime=t;s;)n=s._next,(s._active||t>=s._startTime&&!s._paused)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=n},t.rawTime=function(){return _||A.wake(),this._totalTime};var R=p("TweenLite",function(t,e,i){if(C.call(this,e,i),this.render=R.prototype.render,null==t)throw"Cannot tween a null target.";this.target=t="string"==typeof t&&R.selector(t)||t;var n,s,r,a=t.jquery||t.length&&t!==f&&t[0]&&(t[0]===f||t[0].nodeType&&t[0].style&&!t.nodeType),o=this.vars.overwrite;if(this._overwrite=o=null==o?Y[R.defaultOverwrite]:"number"==typeof o?o>>0:Y[o],(a||t instanceof Array||t.push&&c(t))&&"number"!=typeof t[0])for(this._targets=r=l.call(t,0),this._propLookup=[],this._siblings=[],n=0;r.length>n;n++)(s=r[n])?"string"!=typeof s?s.length&&s!==f&&s[0]&&(s[0]===f||s[0].nodeType&&s[0].style&&!s.nodeType)?(r.splice(n--,1),this._targets=r=r.concat(l.call(s,0))):(this._siblings[n]=q(s,this,!1),1===o&&1=a._startTime&&a._startTime+a.totalDuration()/a._timeScale>h&&((p||!a._initted)&&h-a._startTime<=2e-10||(c[u++]=a)));for(f=u;-1<--f;)a=c[f],2===n&&a._kill(i,t)&&(r=!0),(2!==n||!a._firstPT&&a._initted)&&a._enabled(!1,!1)&&(r=!0);return r},H=function(t,e,i){for(var n=t._timeline,s=n._timeScale,r=t._startTime;n._timeline;){if(r+=n._startTime,s*=n._timeScale,n._paused)return-100;n=n._timeline}return e<(r/=s)?r-e:i&&r===e||!t._initted&&r-e<2*g?g:(r+=t.totalDuration()/t._timeScale/s)>e+g?0:r-e-g};t._init=function(){var t,e,i,n,s,r=this.vars,a=this._overwrittenProps,o=this._duration,l=!!r.immediateRender,h=r.ease;if(r.startAt){for(n in this._startAt&&(this._startAt.render(-1,!0),this._startAt.kill()),s={},r.startAt)s[n]=r.startAt[n];if(s.overwrite=!1,s.immediateRender=!0,s.lazy=l&&!1!==r.lazy,s.startAt=s.delay=null,this._startAt=R.to(this.target,0,s),l)if(0o.pr;)n=n._next;(o._prev=n?n._prev:r)?o._prev._next=o:s=o,(o._next=n)?n._prev=o:r=o,o=a}o=e._firstPT=s}for(;o;)o.pg&&"function"==typeof o.t[t]&&o.t[t]()&&(i=!0),o=o._next;return i},V.activate=function(t){for(var e=t.length;-1<--e;)t[e].API===V.API&&(X[(new t[e])._propName]=t[e]);return!0},r.plugin=function(t){if(!(t&&t.propName&&t.init&&t.API))throw"illegal plugin definition.";var e,i=t.propName,n=t.priority||0,s=t.overwriteProps,r={init:"_onInitTween",set:"setRatio",kill:"_kill",round:"_roundProps",initAll:"_onInitAllProps"},a=p("plugins."+i.charAt(0).toUpperCase()+i.substr(1)+"Plugin",function(){V.call(this,i,n),this._overwriteProps=s||[]},!0===t.global),o=a.prototype=new V(i);for(e in(o.constructor=a).API=t.API,r)"function"==typeof t[e]&&(o[r[e]]=t[e]);return a.version=t.version,V.activate([a]),a},h=f._gsQueue){for(O=0;h.length>O;O++)h[O]();for(t in v)v[t].func||f.console.log("GSAP encountered missing dependency: com.greensock."+t)}_=!1}}(window)},{}],11:[function(t,e,i){"use strict";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine("easing.Back",["easing.Ease"],function(m){function t(t,e){var i=c("easing."+t,function(){},!0),n=i.prototype=new m;return n.constructor=i,n.getRatio=e,i}function e(t,e,i,n){var s=c("easing."+t,{easeOut:new e,easeIn:new i,easeInOut:new n},!0);return u(s,t),s}function g(t,e,i){this.t=t,this.v=e,i&&(((this.next=i).prev=this).c=i.v-e,this.gap=i.t-t)}function i(t,e){var i=c("easing."+t,function(t){this._p1=t||0===t?t:1.70158,this._p2=1.525*this._p1},!0),n=i.prototype=new m;return n.constructor=i,n.getRatio=e,n.config=function(t){return new i(t)},i}var n,s,r,a=window.GreenSockGlobals||window,o=a.com.greensock,l=2*Math.PI,h=Math.PI/2,c=o._class,u=m.register||function(){},p=e("Back",i("BackOut",function(t){return--t*t*((this._p1+1)*t+this._p1)+1}),i("BackIn",function(t){return t*t*((this._p1+1)*t-this._p1)}),i("BackInOut",function(t){return(t*=2)<1?.5*t*t*((this._p2+1)*t-this._p2):.5*((t-=2)*t*((this._p2+1)*t+this._p2)+2)})),f=c("easing.SlowMo",function(t,e,i){e=e||0===e?e:.7,null==t?t=.7:1t?this._calcEnd?1-(t=1-t/this._p1)*t:e-(t=1-t/this._p1)*t*t*t*e:t>this._p3?this._calcEnd?1-(t=(t-this._p3)/this._p1)*t:e+(t-e)*(t=(t-this._p3)/this._p1)*t*t*t:this._calcEnd?1:e},f.ease=new f(.7,.7),d.config=f.config=function(t,e,i){return new f(t,e,i)},(d=(n=c("easing.SteppedEase",function(t){t=t||1,this._p1=1/t,this._p2=t+1},!0)).prototype=new m).constructor=n,d.getRatio=function(t){return t<0?t=0:1<=t&&(t=.999999999),(this._p2*t>>0)*this._p1},d.config=n.config=function(t){return new n(t)},(d=(s=c("easing.RoughEase",function(t){for(var e,i,n,s,r,a,o=(t=t||{}).taper||"none",l=[],h=0,c=0|(t.points||20),u=c,p=!1!==t.randomize,f=!0===t.clamp,d=t.template instanceof m?t.template:null,_="number"==typeof t.strength?.4*t.strength:.4;-1<--u;)e=p?Math.random():1/c*u,i=d?d.getRatio(e):e,n="none"===o?_:"out"===o?(s=1-e)*s*_:"in"===o?e*e*_:.5*(s=e<.5?2*e:2*(1-e))*s*_,p?i+=Math.random()*n-.5*n:u%2?i+=.5*n:i-=.5*n,f&&(1e.t){for(;e.next&&t>=e.t;)e=e.next;e=e.prev}else for(;e.prev&&e.t>=t;)e=e.prev;return(this._prev=e).v+(t-e.t)/e.gap*e.c},d.config=function(t){return new s(t)},s.ease=new s,e("Bounce",t("BounceOut",function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}),t("BounceIn",function(t){return 1/2.75>(t=1-t)?1-7.5625*t*t:t<2/2.75?1-(7.5625*(t-=1.5/2.75)*t+.75):t<2.5/2.75?1-(7.5625*(t-=2.25/2.75)*t+.9375):1-(7.5625*(t-=2.625/2.75)*t+.984375)}),t("BounceInOut",function(t){var e=t<.5;return t=(t=e?1-2*t:2*t-1)<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375,e?.5*(1-t):.5*t+.5})),e("Circ",t("CircOut",function(t){return Math.sqrt(1- --t*t)}),t("CircIn",function(t){return-(Math.sqrt(1-t*t)-1)}),t("CircInOut",function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)})),e("Elastic",(r=function(t,e,i){var n=c("easing."+t,function(t,e){this._p1=t||1,this._p2=e||i,this._p3=this._p2/l*(Math.asin(1/this._p1)||0)},!0),s=n.prototype=new m;return s.constructor=n,s.getRatio=e,s.config=function(t,e){return new n(t,e)},n})("ElasticOut",function(t){return this._p1*Math.pow(2,-10*t)*Math.sin((t-this._p3)*l/this._p2)+1},.3),r("ElasticIn",function(t){return-(this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*l/this._p2))},.3),r("ElasticInOut",function(t){return(t*=2)<1?-.5*this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*l/this._p2):.5*this._p1*Math.pow(2,-10*--t)*Math.sin((t-this._p3)*l/this._p2)+1},.45)),e("Expo",t("ExpoOut",function(t){return 1-Math.pow(2,-10*t)}),t("ExpoIn",function(t){return Math.pow(2,10*(t-1))-.001}),t("ExpoInOut",function(t){return(t*=2)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*(t-1)))})),e("Sine",t("SineOut",function(t){return Math.sin(t*h)}),t("SineIn",function(t){return 1-Math.cos(t*h)}),t("SineInOut",function(t){return-.5*(Math.cos(Math.PI*t)-1)})),c("easing.EaseLookup",{find:function(t){return m.map[t]}},!0),u(a.SlowMo,"SlowMo","ease,"),u(s,"RoughEase","ease,"),u(n,"SteppedEase","ease,"),p},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],12:[function(t,e,i){"use strict";var Lt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine("plugins.CSSPlugin",["plugins.TweenPlugin","TweenLite"],function(r,p){function J(){r.call(this,"css"),this._overwriteProps.length=0,this.setRatio=J.prototype.setRatio}var d,T,k,f,_={},t=J.prototype=new r("css");(t.constructor=J).version="1.12.1",J.API=2,J.defaultTransformPerspective=0,J.defaultSkewType="compensated",J.suffixMap={top:t="px",right:t,bottom:t,left:t,width:t,height:t,fontSize:t,padding:t,margin:t,perspective:t,lineHeight:""};function a(t,e){return e.toUpperCase()}function o(t){return E.test("string"==typeof t?t:(t.currentStyle?t.currentStyle.filter:t.style.filter)||"")?parseFloat(RegExp.$1)/100:1}function m(t){window.console&&console.log(t)}function P(t,e){var i,n,s=(e=e||V).style;if(void 0!==s[t])return t;for(t=t.charAt(0).toUpperCase()+t.substr(1),i=["O","Moz","ms","Ms","Webkit"],n=5;-1<--n&&void 0===s[i[n]+t];);return 0<=n?(G="-"+(K=3===n?"ms":i[n]).toLowerCase()+"-",K+t):null}function g(t,e){var i,n,s={};if(e=e||nt(t,null))if(i=e.length)for(;-1<--i;)s[e[i].replace(Y,a)]=e.getPropertyValue(e[i]);else for(i in e)s[i]=e[i];else if(e=t.currentStyle||t.style)for(i in e)"string"==typeof i&&void 0===s[i]&&(s[i.replace(Y,a)]=e[i]);return Z||(s.opacity=o(t)),n=St(t,e,!1),s.rotation=n.rotation,s.skewX=n.skewX,s.scaleX=n.scaleX,s.scaleY=n.scaleY,s.x=n.x,s.y=n.y,kt&&(s.z=n.z,s.rotationX=n.rotationX,s.rotationY=n.rotationY,s.scaleZ=n.scaleZ),s.filters&&delete s.filters,s}function v(t,e,i,n,s){var r,a,o,l={},h=t.style;for(a in i)"cssText"!==a&&"length"!==a&&isNaN(a)&&(e[a]!==(r=i[a])||s&&s[a])&&-1===a.indexOf("Origin")&&("number"==typeof r||"string"==typeof r)&&(l[a]="auto"!==r||"left"!==a&&"top"!==a?""!==r&&"auto"!==r&&"none"!==r||"string"!=typeof e[a]||""===e[a].replace(c,"")?r:0:at(t,a),void 0!==h[a]&&(o=new ft(h,a,h[a],o)));if(n)for(a in n)"className"!==a&&(l[a]=n[a]);return{difs:l,firstMPT:o}}function w(t,e){null!=t&&""!==t&&"auto"!==t&&"auto auto"!==t||(t="0 0");var i=t.split(" "),n=-1!==t.indexOf("left")?"0%":-1!==t.indexOf("right")?"100%":i[0],s=-1!==t.indexOf("top")?"0%":-1!==t.indexOf("bottom")?"100%":i[1];return null==s?s="0":"center"===s&&(s="50%"),("center"===n||isNaN(parseFloat(n))&&-1===(n+"").indexOf("="))&&(n="50%"),e&&(e.oxp=-1!==n.indexOf("%"),e.oyp=-1!==s.indexOf("%"),e.oxr="="===n.charAt(1),e.oyr="="===s.charAt(1),e.ox=parseFloat(n.replace(c,"")),e.oy=parseFloat(s.replace(c,""))),n+" "+s+(2>16,255&t>>8,255&t]:(","===t.charAt(t.length-1)&&(t=t.substr(0,t.length-1)),ht[t]?ht[t]:"#"===t.charAt(0)?(4===t.length&&(t="#"+(e=t.charAt(1))+e+(i=t.charAt(2))+i+(n=t.charAt(3))+n),[(t=parseInt(t.substr(1),16))>>16,255&t>>8,255&t]):("hsl"===t.substr(0,3)?(t=t.match(I),s=Number(t[0])%360/360,r=Number(t[1])/100,e=2*(a=Number(t[2])/100)-(i=a<=.5?a*(1+r):a+r-a*r),3a",!!(e=n.getElementsByTagName("a")[0])&&/^0.55/.test(e.style.opacity)),G="",K="",nt=H.defaultView?H.defaultView.getComputedStyle:function(){},st=J.getStyle=function(t,e,i,n,s){var r;return Z||"opacity"!==e?(!n&&t.style[e]?r=t.style[e]:(i=i||nt(t))?r=i[e]||i.getPropertyValue(e)||i.getPropertyValue(e.replace(u,"-$1").toLowerCase()):t.currentStyle&&(r=t.currentStyle[e]),null==s||r&&"none"!==r&&"auto"!==r&&"auto auto"!==r?r:s):o(t)},rt=s.convertToPixels=function(t,e,i,n,s){if("px"===n||!n)return i;if("auto"===n||!i)return 0;var r,a,o,l=$.test(e),h=t,c=V.style,u=i<0;if(u&&(i=-i),"%"===n&&-1!==e.indexOf("border"))r=i/100*(l?t.clientWidth:t.clientHeight);else{if(c.cssText="border:0 solid red;position:"+st(t,"position")+";line-height:0;","%"!==n&&h.appendChild)c[l?"borderLeftWidth":"borderTopWidth"]=i+n;else{if(a=(h=t.parentNode||H.body)._gsCache,o=p.ticker.frame,a&&l&&a.time===o)return a.width*i/100;c[l?"width":"height"]=i+n}h.appendChild(V),r=parseFloat(V[l?"offsetWidth":"offsetHeight"]),h.removeChild(V),l&&"%"===n&&!1!==J.cacheWidths&&((a=h._gsCache=h._gsCache||{}).time=o,a.width=r/i*100),0!==r||s||(r=rt(t,e,i,n,!0))}return u?-r:r},at=s.calculateOffset=function(t,e,i){if("absolute"!==st(t,"position",i))return 0;var n="left"===e?"Left":"Top",s=st(t,"margin"+n,i);return t["offset"+n]-(rt(t,e,parseFloat(s),s.replace(X,""))||0)},ot={width:["Left","Right"],height:["Top","Bottom"]},lt=["marginLeft","marginRight","marginTop","marginBottom"],ht={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},ct="(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b";for(t in ht)ct+="|"+t+"\\b";ct=RegExp(ct+")","gi");function ut(t,e,r,a){if(null==t)return function(t){return t};var o,l=e?(t.match(ct)||[""])[0]:"",h=t.split(l).join("").match(L)||[],c=t.substr(0,t.indexOf(h[0])),u=")"===t.charAt(t.length-1)?")":"",p=-1!==t.indexOf(" ")?" ":",",f=h.length,d=0n;n++)s[n]=o(s[n]);return s.join(",")}if(e=(t.match(ct)||[l])[0],n=(i=t.split(e).join("").match(L)||[]).length,f>n--)for(;f>++n;)i[n]=r?i[0|(n-1)/2]:h[n];return c+i.join(p)+p+e+u+(-1!==t.indexOf("inset")?" inset":"")}:function(t){var e,i,n;if("number"==typeof t)t+=d;else if(a&&q.test(t)){for(i=t.replace(q,"|").split("|"),n=0;i.length>n;n++)i[n]=o(i[n]);return i.join(",")}if(n=(e=t.match(L)||[]).length,f>n--)for(;f>++n;)e[n]=r?e[0|(n-1)/2]:h[n];return c+e.join(p)+u}:function(t){return t}}function pt(h){return h=h.split(","),function(t,e,i,n,s,r,a){var o,l=(e+"").split(" ");for(a={},o=0;o<4;o++)a[h[o]]=l[o]=l[o]||l[(o-1)/2>>0];return n.parse(t,a,s,r)}}var ft=(s._setPluginRatio=function(t){this.plugin.setRatio(t);for(var e,i,n,s,r=this.data,a=r.proxy,o=r.firstMPT;o;)e=a[o.v],o.r?e=Math.round(e):e<1e-6&&-1e-6n;n++)s+=i["xn"+n]+i["xs"+(n+1)];i.e=s}}else i.e=i.s+i.xs0;o=o._next}},function(t,e,i,n,s){this.t=t,this.p=e,this.v=i,this.r=s,n&&((n._prev=this)._next=n)}),dt=(s._parseToProxy=function(t,e,i,n,s,r){var a,o,l,h,c,u=n,p={},f={},d=i._transform,_=U;for(i._transform=null,U=e,n=c=i.parse(t,e,n,s),U=_,r&&(i._transform=d,u&&(u._prev=null,u._prev&&(u._prev._next=null)));n&&n!==u;){if(n.type<=1&&(f[o=n.p]=n.s+n.c,p[o]=n.s,r||(h=new ft(n,"s",o,h,n.r),n.c=0),1===n.type))for(a=n.l;0<--a;)l="xn"+a,f[o=n.p+"_"+l]=n.data[l],p[o]=n[l],r||(h=new ft(n,l,o,h,n.rxp[l]));n=n._next}return{proxy:p,end:f,firstMPT:h,pt:c}},s.CSSPropTween=function(t,e,i,n,s,r,a,o,l,h,c){this.t=t,this.p=e,this.s=i,this.c=n,this.n=a||e,t instanceof dt||f.push(this.n),this.r=o,this.type=r||0,l&&(this.pr=l,d=!0),this.b=void 0===h?i:h,this.e=void 0===c?i+n:c,s&&((this._next=s)._prev=this)}),_t=J.parseComplex=function(t,e,i,n,s,r,a,o,l,h){a=new dt(t,e,0,0,a,h?2:1,null,!1,o,i=i||r||"",n),n+="";var c,u,p,f,d,_,m,g,v,w,y,x,b=i.split(", ").join(",").split(" "),T=n.split(", ").join(",").split(" "),k=b.length,P=!1!==C;for(-1===n.indexOf(",")&&-1===i.indexOf(",")||(b=b.join(" ").replace(q,", ").split(" "),T=T.join(" ").replace(q,", ").split(" "),k=b.length),k!==T.length&&(k=(b=(r||"").split(" ")).length),a.plugin=l,a.setRatio=h,c=0;cu;u++)y=_[u],w=f.indexOf(y,p),a.appendXtra(f.substr(p,w-p),Number(y),S(m[u],y),"",P&&"px"===f.substr(w+y.length,2),0===u),p=w+y.length;a["xs"+a.l]+=f.substr(p)}else a["xs"+a.l]+=a.l?" "+f:f;if(-1!==n.indexOf("=")&&a.data){for(x=a.xs0+a.data.s,c=1;a.l>c;c++)x+=a["xs"+c]+a.data["xn"+c];a.e=x+a["xs"+c]}return a.l||(a.type=-1,a.xs0=a.e),a.xfirst||a},mt=9;for((t=dt.prototype).l=t.pr=0;0<--mt;)t["xn"+mt]=0,t["xs"+mt]="";t.xs0="",t._next=t._prev=t.xfirst=t.data=t.plugin=t.setRatio=t.rxp=null,t.appendXtra=function(t,e,i,n,s,r){var a=this,o=a.l;return a["xs"+o]+=r&&o?" "+t:t||"",i||0===o||a.plugin?(a.l++,a.type=a.setRatio?2:1,a["xs"+a.l]=n||"",0n;n++)e.prefix=0===n&&e.prefix,e.defaultValue=i[n]||r,new gt(s[n],e)};(t=gt.prototype).parseComplex=function(t,e,i,n,s,r){var a,o,l,h,c,u=this.keyword;if(this.multi&&(q.test(i)||q.test(e)?(o=e.replace(q,"|").split("|"),l=i.replace(q,"|").split("|")):u&&(o=[e],l=[i])),l){for(h=l.length>o.length?l.length:o.length,a=0;aH[a]&&H[a]>-W&&(H[a]=0);return i&&(t._gsTransform=H),H},Ot=s.set3DTransformRatio=function(t){var e,i,n,s,r,a,o,l,h,c,u,p,f,d,_,m,g,v,w,y,x,b,T,k=this.data,P=this.t.style,S=k.rotation*et,O=k.scaleX,C=k.scaleY,A=k.scaleZ,M=k.perspective;if(1!==t&&0!==t||"auto"!==k.force3D||k.rotationY||k.rotationX||1!==A||M||k.z){if(R&&(O<1e-4&&-1e-4b;b++)this.p.indexOf("border")&&(g[b]=P(g[b])),-1!==(o=a=st(t,g[b],k,!1,"0px")).indexOf(" ")&&(o=(a=o.split(" "))[0],a=a[1]),l=r=x[b],h=parseFloat(o),p=o.substr((h+"").length),""===(u=(f="="===l.charAt(1))?(c=parseInt(l.charAt(0)+"1",10),l=l.substr(2),c*=parseFloat(l),l.substr((c+"").length-(c<0?1:0))||""):(c=parseFloat(l),l.substr((c+"").length)))&&(u=T[i]||p),u!==p&&(d=rt(t,"borderLeft",h,p),_=rt(t,"borderTop",h,p),a="%"===u?(o=d/w*100+"%",_/y*100+"%"):"em"===u?(o=d/(m=rt(t,"borderLeft",1,"em"))+"em",_/m+"em"):(o=d+"px",_+"px"),f&&(l=parseFloat(o)+c+u,r=parseFloat(a)+c+u)),s=_t(v,g[b],o+" "+a,l+" "+r,!1,"0px",s);return s},prefix:!0,formatter:ut("0px 0px 0px 0px",!1,!0)}),vt("backgroundPosition",{defaultValue:"0 0",parser:function(t,e,i,n,s,r){var a,o,l,h,c,u,p="background-position",f=k||nt(t,null),d=this.format((f?D?f.getPropertyValue(p+"-x")+" "+f.getPropertyValue(p+"-y"):f.getPropertyValue(p):t.currentStyle.backgroundPositionX+" "+t.currentStyle.backgroundPositionY)||"0 0"),_=this.format(e);if(-1!==d.indexOf("%")!=(-1!==_.indexOf("%"))&&((u=st(t,"backgroundImage").replace(F,""))&&"none"!==u)){for(a=d.split(" "),o=_.split(" "),W.setAttribute("src",u),l=2;-1<--l;)(h=-1!==(d=a[l]).indexOf("%"))!=(-1!==o[l].indexOf("%"))&&(c=0===l?t.offsetWidth-W.width:t.offsetHeight-W.height,a[l]=h?parseFloat(d)/100*c+"px":parseFloat(d)/c*100+"%");d=a.join(" ")}return this.parseComplex(t.style,d,_,s,r)},formatter:w}),vt("backgroundSize",{defaultValue:"0 0",formatter:w}),vt("perspective",{defaultValue:"0px",prefix:!0}),vt("perspectiveOrigin",{defaultValue:"50% 50%",prefix:!0}),vt("transformStyle",{prefix:!0}),vt("backfaceVisibility",{prefix:!0}),vt("userSelect",{prefix:!0}),vt("margin",{parser:pt("marginTop,marginRight,marginBottom,marginLeft")}),vt("padding",{parser:pt("paddingTop,paddingRight,paddingBottom,paddingLeft")}),vt("clip",{defaultValue:"rect(0px,0px,0px,0px)",parser:function(t,e,i,n,s,r){var a,o,l;return e=D<9?(o=t.currentStyle,l=D<8?" ":",",a="rect("+o.clipTop+l+o.clipRight+l+o.clipBottom+l+o.clipLeft+")",this.format(e).split(",").join(l)):(a=this.format(st(t,this.p,k,!1,this.dflt)),this.format(e)),this.parseComplex(t.style,a,e,s,r)}}),vt("textShadow",{defaultValue:"0px 0px 0px #999",color:!0,multi:!0}),vt("autoRound,strictUnits",{parser:function(t,e,i,n,s){return s}}),vt("border",{defaultValue:"0px solid #000",parser:function(t,e,i,n,s,r){return this.parseComplex(t.style,this.format(st(t,"borderTopWidth",k,!1,"0px")+" "+st(t,"borderTopStyle",k,!1,"solid")+" "+st(t,"borderTopColor",k,!1,"#000")),this.format(e),s,r)},color:!0,formatter:function(t){var e=t.split(" ");return e[0]+" "+(e[1]||"solid")+" "+(t.match(ct)||["#000"])[0]}}),vt("borderWidth",{parser:pt("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}),vt("float,cssFloat,styleFloat",{parser:function(t,e,i,n,s){var r=t.style,a="cssFloat"in r?"cssFloat":"styleFloat";return new dt(r,a,0,0,s,-1,i,!1,0,r[a],e)}});function At(t){var e,i=this.t,n=i.filter||st(this.data,"filter"),s=0|this.s+this.c*t;100==s&&(e=-1===n.indexOf("atrix(")&&-1===n.indexOf("radient(")&&-1===n.indexOf("oader(")?(i.removeAttribute("filter"),!st(this.data,"filter")):(i.filter=n.replace(h,""),!0)),e||(this.xn1&&(i.filter=n=n||"alpha(opacity="+s+")"),-1===n.indexOf("pacity")?0==s&&this.xn1||(i.filter=n+" alpha(opacity="+s+")"):i.filter=n.replace(E,"opacity="+s))}vt("opacity,alpha,autoAlpha",{defaultValue:"1",parser:function(t,e,i,n,s,r){var a=parseFloat(st(t,"opacity",k,!1,"1")),o=t.style,l="autoAlpha"===i;return"string"==typeof e&&"="===e.charAt(1)&&(e=("-"===e.charAt(0)?-1:1)*parseFloat(e.substr(2))+a),l&&1===a&&"hidden"===st(t,"visibility",k)&&0!==e&&(a=0),Z?s=new dt(o,"opacity",a,e-a,s):((s=new dt(o,"opacity",100*a,100*(e-a),s)).xn1=l?1:0,o.zoom=1,s.type=2,s.b="alpha(opacity="+s.s+")",s.e="alpha(opacity="+(s.s+s.c)+")",s.data=t,s.plugin=r,s.setRatio=At),l&&((s=new dt(o,"visibility",0,0,s,-1,null,!1,0,0!==a?"inherit":"hidden",0===e?"hidden":"inherit")).xs0="inherit",n._overwriteProps.push(s.n),n._overwriteProps.push(i)),s}});function Mt(t,e){e&&(t.removeProperty?("ms"===e.substr(0,2)&&(e="M"+e.substr(1)),t.removeProperty(e.replace(u,"-$1").toLowerCase())):t.removeAttribute(e))}function Rt(t){if(this.t._gsClassPT=this,1===t||0===t){this.t.setAttribute("class",0===t?this.b:this.e);for(var e=this.data,i=this.t.style;e;)e.v?i[e.p]=e.v:Mt(i,e.p),e=e._next;1===t&&this.t._gsClassPT===this&&(this.t._gsClassPT=null)}else this.t.getAttribute("class")!==this.e&&this.t.setAttribute("class",this.e)}vt("className",{parser:function(t,e,i,n,s,r,a){var o,l,h,c,u,p=t.getAttribute("class")||"",f=t.style.cssText;if((s=n._classNamePT=new dt(t,i,0,0,s,2)).setRatio=Rt,s.pr=-11,d=!0,s.b=p,l=g(t,k),h=t._gsClassPT){for(c={},u=h.data;u;)c[u.p]=1,u=u._next;h.setRatio(1)}return(t._gsClassPT=s).e="="!==e.charAt(1)?e:p.replace(RegExp("\\s*\\b"+e.substr(2)+"\\b"),"")+("+"===e.charAt(0)?" "+e.substr(2):""),n._tween._duration&&(t.setAttribute("class",s.e),o=v(t,l,g(t),a,c),t.setAttribute("class",p),s.data=o.firstMPT,t.style.cssText=f,s=s.xfirst=n.parse(t,o.difs,s,r)),s}});function Dt(t){if((1===t||0===t)&&this.data._totalTime===this.data._totalDuration&&"isFromStart"!==this.data.data){var e,i,n,s,r=this.t.style,a=_.transform.parse;if("all"===this.e)s=!(r.cssText="");else for(n=(e=this.e.split(",")).length;-1<--n;)i=e[n],_[i]&&(_[i].parse===a?s=!0:i="transformOrigin"===i?Tt:_[i].p),Mt(r,i);s&&(Mt(r,xt),this.t._gsTransform&&delete this.t._gsTransform)}}for(vt("clearProps",{parser:function(t,e,i,n,s){return(s=new dt(t,i,0,0,s,2)).setRatio=Dt,s.e=e,s.pr=-10,s.data=n._tween,d=!0,s}}),t="bezier,throwProps,physicsProps,physics2D".split(","),mt=t.length;mt--;)!function(t){var l;_[t]||(l=t.charAt(0).toUpperCase()+t.substr(1)+"Plugin",vt(t,{parser:function(t,e,i,n,s,r,a){var o=(window.GreenSockGlobals||window).com.greensock.plugins[l];return o?(o._cssRegister(),_[i].parse(t,e,i,n,s,r,a)):(m("Error: "+l+" js file not loaded."),s)}}))}(t[mt]);(t=J.prototype)._firstPT=null,t._onInitTween=function(t,e,i){if(!t.nodeType)return!1;this._target=t,this._tween=i,this._vars=e,C=e.autoRound,d=!1,T=e.suffixMap||J.suffixMap,k=nt(t,""),f=this._overwriteProps;var n,s,r,a,o,l,h,c,u,p=t.style;if(b&&""===p.zIndex&&("auto"!==(n=st(t,"zIndex",k))&&""!==n||this._addLazySet(p,"zIndex",0)),"string"==typeof e&&(a=p.cssText,n=g(t,k),p.cssText=a+";"+e,n=v(t,n,g(t)).difs,!Z&&z.test(e)&&(n.opacity=parseFloat(RegExp.$1)),e=n,p.cssText=a),this._firstPT=s=this.parse(t,e,null),this._transformType){for(u=3===this._transformType,xt?A&&(b=!0,""===p.zIndex&&("auto"!==(h=st(t,"zIndex",k))&&""!==h||this._addLazySet(p,"zIndex",0)),M&&this._addLazySet(p,"WebkitBackfaceVisibility",this._vars.WebkitBackfaceVisibility||(u?"visible":"hidden"))):p.zoom=1,r=s;r&&r._next;)r=r._next;c=new dt(t,"transform",0,0,null,2),this._linkCSSP(c,null,r),c.setRatio=u&&kt?Ot:xt?Ct:wt,c.data=this._transform||St(t,k,!0),f.pop()}if(d){for(;s;){for(l=s._next,r=a;r&&r.pr>s.pr;)r=r._next;(s._prev=r?r._prev:o)?s._prev._next=s:a=s,(s._next=r)?r._prev=s:o=s,s=l}this._firstPT=a}return!0},t.parse=function(t,e,i,n){var s,r,a,o,l,h,c,u,p,f,d=t.style;for(s in e)h=e[s],(r=_[s])?i=r.parse(t,h,s,this,i,n,e):(l=st(t,s,k)+"",p="string"==typeof h,"color"===s||"fill"===s||"stroke"===s||-1!==s.indexOf("Color")||p&&N.test(h)?(p||(h=(3<(h=O(h)).length?"rgba(":"rgb(")+h.join(",")+")"),i=_t(d,s,l,h,!0,"transparent",i,0,n)):!p||-1===h.indexOf(" ")&&-1===h.indexOf(",")?(c=(a=parseFloat(l))||0===a?l.substr((a+"").length):"",""!==l&&"auto"!==l||(c="width"===s||"height"===s?(a=function(t,e,i){var n=parseFloat("width"===e?t.offsetWidth:t.offsetHeight),s=ot[e],r=s.length;for(i=i||nt(t,null);-1<--r;)n-=parseFloat(st(t,"padding"+s[r],i,!0))||0,n-=parseFloat(st(t,"border"+s[r]+"Width",i,!0))||0;return n}(t,s,k),"px"):"left"===s||"top"===s?(a=at(t,s,k),"px"):(a="opacity"!==s?0:1,"")),""===(u=(f=p&&"="===h.charAt(1))?(o=parseInt(h.charAt(0)+"1",10),h=h.substr(2),o*=parseFloat(h),h.replace(X,"")):(o=parseFloat(h),p&&h.substr((o+"").length)||""))&&(u=s in T?T[s]:c),h=o||0===o?(f?o+a:o)+u:e[s],c!==u&&""!==u&&(o||0===o)&&a&&(a=rt(t,s,a,c),"%"===u?(a/=rt(t,s,100,"%")/100,!0!==e.strictUnits&&(l=a+"%")):"em"===u?a/=rt(t,s,1,"em"):"px"!==u&&(o=rt(t,s,o,u),u="px"),f&&(o||0===o)&&(h=o+a+u)),f&&(o+=a),!a&&0!==a||!o&&0!==o?void 0!==d[s]&&(h||"NaN"!=h+""&&null!=h)?(i=new dt(d,s,o||a||0,0,i,-1,s,!1,0,l,h)).xs0="none"!==h||"display"!==s&&-1===s.indexOf("Style")?h:l:m("invalid "+s+" tween value: "+e[s]):(i=new dt(d,s,a,o-a,i,0,s,!1!==C&&("px"===u||"zIndex"===s),0,l,h)).xs0=u):i=_t(d,s,l,h,!0,null,i,0,n)),n&&i&&!i.plugin&&(i.plugin=n);return i},t.setRatio=function(t){var e,i,n,s=this._firstPT;if(1!==t||this._tween._time!==this._tween._duration&&0!==this._tween._time)if(t||this._tween._time!==this._tween._duration&&0!==this._tween._time||-1e-6===this._tween._rawPrevTime)for(;s;){if(e=s.c*t+s.s,s.r?e=Math.round(e):e<1e-6&&-1e-6n;n++)i+=s["xn"+n]+s["xs"+(n+1)];s.t[s.p]=i}else-1===s.type?s.t[s.p]=s.xs0:s.setRatio&&s.setRatio(t);else s.t[s.p]=e+s.xs0;s=s._next}else for(;s;)2!==s.type?s.t[s.p]=s.b:s.setRatio(t),s=s._next;else for(;s;)2!==s.type?s.t[s.p]=s.e:s.setRatio(t),s=s._next},t._enableTransforms=function(t){this._transformType=t||3===this._transformType?3:2,this._transform=this._transform||St(this._target,k,!0)};function It(){this.t[this.p]=this.e,this.data._linkCSSP(this,this._next,null,!0)}t._addLazySet=function(t,e,i){var n=this._firstPT=new dt(t,e,0,0,this._firstPT,2);n.e=i,n.setRatio=It,n.data=this},t._linkCSSP=function(t,e,i,n){return t&&(e&&(e._prev=t),t._next&&(t._next._prev=t._prev),t._prev?t._prev._next=t._next:this._firstPT===t&&(this._firstPT=t._next,n=!0),i?i._next=t:n||null!==this._firstPT||(this._firstPT=t),t._next=e,t._prev=i),t},t._kill=function(t){var e,i,n,s=t;if(t.autoAlpha||t.alpha){for(i in s={},t)s[i]=t[i];s.opacity=1,s.autoAlpha&&(s.visibility=1)}return t.className&&(e=this._classNamePT)&&((n=e.xfirst)&&n._prev?this._linkCSSP(n._prev,e._next,n._prev._prev):n===this._firstPT&&(this._firstPT=e._next),e._next&&this._linkCSSP(e._next,e._next._next,n._prev),this._classNamePT=null),r.prototype._kill.call(this,s)};function jt(t,e,i){var n,s,r,a;if(t.slice)for(s=t.length;-1<--s;)jt(t[s],e,i);else for(s=(n=t.childNodes).length;-1<--s;)a=(r=n[s]).type,r.style&&(e.push(g(r)),i&&i.push(r)),1!==a&&9!==a&&11!==a||!r.childNodes.length||jt(r,e,i)}return J.cascadeTo=function(t,e,i){var n,s,r,a=p.to(t,e,i),o=[a],l=[],h=[],c=[],u=p._internals.reservedProps;for(t=a._targets||a.target,jt(t,l,c),a.render(e,!0),jt(t,h),a.render(0,!0),a._enabled(!0),n=c.length;-1<--n;)if((s=v(c[n],l[n],h[n])).firstMPT){for(r in s=s.difs,i)u[r]&&(s[r]=i[r]);o.push(p.to(c[n],e,s))}return o},r.activate([J]),J},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],13:[function(t,e,i){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};(window._gsQueue||(window._gsQueue=[])).push(function(){function r(t,e){var i="x"===e?"Width":"Height",n="scroll"+i,s="client"+i,r=document.body;return t===o||t===a||t===r?Math.max(a[n],r[n])-(o["inner"+i]||Math.max(a[s],r[s])):t[n]-t["offset"+i]}var a=document.documentElement,o=window,t=window._gsDefine.plugin({propName:"scrollTo",API:2,version:"1.7.3",init:function(t,e,i){return this._wdw=t===o,this._target=t,this._tween=i,"object"!=(void 0===e?"undefined":n(e))&&(e={y:e}),this._autoKill=!1!==e.autoKill,this.x=this.xPrev=this.getX(),this.y=this.yPrev=this.getY(),null!=e.x?(this._addTween(this,"x",this.x,"max"===e.x?r(t,"x"):e.x,"scrollTo_x",!0),this._overwriteProps.push("scrollTo_x")):this.skipX=!0,null!=e.y?(this._addTween(this,"y",this.y,"max"===e.y?r(t,"y"):e.y,"scrollTo_y",!0),this._overwriteProps.push("scrollTo_y")):this.skipY=!0,!0},set:function(t){this._super.setRatio.call(this,t);var e=this._wdw||!this.skipX?this.getX():this.xPrev,i=this._wdw||!this.skipY?this.getY():this.yPrev,n=i-this.yPrev,s=e-this.xPrev;this._autoKill&&(!this.skipX&&(7e&&(this.skipX=!0),!this.skipY&&(7i&&(this.skipY=!0),this.skipX&&this.skipY&&this._tween.kill()),this._wdw?o.scrollTo(this.skipX?e:this.x,this.skipY?i:this.y):(this.skipY||(this._target.scrollTop=this.y),this.skipX||(this._target.scrollLeft=this.x)),this.xPrev=this.x,this.yPrev=this.y}}),e=t.prototype;t.max=r,e.getX=function(){return this._wdw?null!=o.pageXOffset?o.pageXOffset:null!=a.scrollLeft?a.scrollLeft:document.body.scrollLeft:this._target.scrollLeft},e.getY=function(){return this._wdw?null!=o.pageYOffset?o.pageYOffset:null!=a.scrollTop?a.scrollTop:document.body.scrollTop:this._target.scrollTop},e._kill=function(t){return t.scrollTo_x&&(this.skipX=!0),t.scrollTo_y&&(this.skipY=!0),this._super._kill.call(this,t)}}),window._gsDefine&&window._gsQueue.pop()()},{}]},{},[2]); -//# sourceMappingURL=wpr-admin.js.map +(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i= 0) { + return; + } + $.post(ajaxurl, { + action: 'rocket_toggle_option', + _ajax_nonce: rocket_ajax_data.nonce, + option: { + name: name, + value: value + } + }, function (response) {}); + }); + + /** + * Save enable CPCSS for mobiles option. + */ + $('#wpr-action-rocket_enable_mobile_cpcss').on('click', function (e) { + e.preventDefault(); + $('#wpr-action-rocket_enable_mobile_cpcss').addClass('wpr-isLoading'); + $.post(ajaxurl, { + action: 'rocket_enable_mobile_cpcss', + _ajax_nonce: rocket_ajax_data.nonce + }, function (response) { + if (response.success) { + // Hide Mobile CPCSS btn on success. + $('#wpr-action-rocket_enable_mobile_cpcss').hide(); + $('.wpr-hide-on-click').hide(); + $('.wpr-show-on-click').show(); + $('#wpr-action-rocket_enable_mobile_cpcss').removeClass('wpr-isLoading'); + } + }); + }); + + /** + * Save enable Google Fonts Optimization option. + */ + $('#wpr-action-rocket_enable_google_fonts').on('click', function (e) { + e.preventDefault(); + $('#wpr-action-rocket_enable_google_fonts').addClass('wpr-isLoading'); + $.post(ajaxurl, { + action: 'rocket_enable_google_fonts', + _ajax_nonce: rocket_ajax_data.nonce + }, function (response) { + if (response.success) { + // Hide Mobile CPCSS btn on success. + $('#wpr-action-rocket_enable_google_fonts').hide(); + $('.wpr-hide-on-click').hide(); + $('.wpr-show-on-click').show(); + $('#wpr-action-rocket_enable_google_fonts').removeClass('wpr-isLoading'); + $('#minify_google_fonts').val(1); + } + }); + }); + $('#rocket-dismiss-promotion').on('click', function (e) { + e.preventDefault(); + $.post(ajaxurl, { + action: 'rocket_dismiss_promo', + nonce: rocket_ajax_data.nonce + }, function (response) { + if (response.success) { + $('#rocket-promo-banner').hide('slow'); + } + }); + }); + $('#rocket-dismiss-renewal').on('click', function (e) { + e.preventDefault(); + $.post(ajaxurl, { + action: 'rocket_dismiss_renewal', + nonce: rocket_ajax_data.nonce + }, function (response) { + if (response.success) { + $('#rocket-renewal-banner').hide('slow'); + } + }); + }); + $('#wpr-update-exclusion-list').on('click', function (e) { + e.preventDefault(); + $('#wpr-update-exclusion-msg').html(''); + $.ajax({ + url: rocket_ajax_data.rest_url, + beforeSend: function (xhr) { + xhr.setRequestHeader('X-WP-Nonce', rocket_ajax_data.rest_nonce); + }, + method: "PUT", + success: function (responses) { + let exclusion_msg_container = $('#wpr-update-exclusion-msg'); + exclusion_msg_container.html(''); + if (undefined !== responses['success']) { + exclusion_msg_container.append('
' + responses['message'] + '
'); + return; + } + Object.keys(responses).forEach(response_key => { + exclusion_msg_container.append('' + response_key + ': '); + exclusion_msg_container.append(responses[response_key]['message']); + exclusion_msg_container.append('
'); + }); + } + }); + }); + + /** + * Enable mobile cache option. + */ + $('#wpr_enable_mobile_cache').on('click', function (e) { + e.preventDefault(); + $('#wpr_enable_mobile_cache').addClass('wpr-isLoading'); + $.post(ajaxurl, { + action: 'rocket_enable_mobile_cache', + _ajax_nonce: rocket_ajax_data.nonce + }, function (response) { + if (response.success) { + // Hide Mobile cache enable button on success. + $('#wpr_enable_mobile_cache').hide(); + $('#wpr_mobile_cache_default').hide(); + $('#wpr_mobile_cache_response').show(); + $('#wpr_enable_mobile_cache').removeClass('wpr-isLoading'); + + // Set values of mobile cache and separate cache files for mobiles option to 1. + $('#cache_mobile').val(1); + $('#do_caching_mobile_files').val(1); + } + }); + }); +}); + +},{}],2:[function(require,module,exports){ +"use strict"; + +require("../lib/greensock/TweenLite.min.js"); +require("../lib/greensock/TimelineLite.min.js"); +require("../lib/greensock/easing/EasePack.min.js"); +require("../lib/greensock/plugins/CSSPlugin.min.js"); +require("../lib/greensock/plugins/ScrollToPlugin.min.js"); +require("../global/pageManager.js"); +require("../global/main.js"); +require("../global/fields.js"); +require("../global/beacon.js"); +require("../global/ajax.js"); +require("../global/rocketcdn.js"); +require("../global/countdown.js"); + +},{"../global/ajax.js":1,"../global/beacon.js":3,"../global/countdown.js":4,"../global/fields.js":5,"../global/main.js":6,"../global/pageManager.js":7,"../global/rocketcdn.js":8,"../lib/greensock/TimelineLite.min.js":9,"../lib/greensock/TweenLite.min.js":10,"../lib/greensock/easing/EasePack.min.js":11,"../lib/greensock/plugins/CSSPlugin.min.js":12,"../lib/greensock/plugins/ScrollToPlugin.min.js":13}],3:[function(require,module,exports){ +"use strict"; + +var $ = jQuery; +$(document).ready(function () { + if ('Beacon' in window) { + /** + * Show beacons on button "help" click + */ + var $help = $('.wpr-infoAction--help'); + $help.on('click', function (e) { + var ids = $(this).data('beacon-id'); + wprCallBeacon(ids); + return false; + }); + function wprCallBeacon(aID) { + aID = aID.split(','); + if (aID.length === 0) { + return; + } + if (aID.length > 1) { + window.Beacon("suggest", aID); + setTimeout(function () { + window.Beacon("open"); + }, 200); + } else { + window.Beacon("article", aID.toString()); + } + } + } +}); + +},{}],4:[function(require,module,exports){ +"use strict"; + +function getTimeRemaining(endtime) { + const start = Date.now(); + const total = endtime * 1000 - start; + const seconds = Math.floor(total / 1000 % 60); + const minutes = Math.floor(total / 1000 / 60 % 60); + const hours = Math.floor(total / (1000 * 60 * 60) % 24); + const days = Math.floor(total / (1000 * 60 * 60 * 24)); + return { + total, + days, + hours, + minutes, + seconds + }; +} +function initializeClock(id, endtime) { + const clock = document.getElementById(id); + if (clock === null) { + return; + } + const daysSpan = clock.querySelector('.rocket-countdown-days'); + const hoursSpan = clock.querySelector('.rocket-countdown-hours'); + const minutesSpan = clock.querySelector('.rocket-countdown-minutes'); + const secondsSpan = clock.querySelector('.rocket-countdown-seconds'); + function updateClock() { + const t = getTimeRemaining(endtime); + if (t.total < 0) { + clearInterval(timeinterval); + return; + } + daysSpan.innerHTML = t.days; + hoursSpan.innerHTML = ('0' + t.hours).slice(-2); + minutesSpan.innerHTML = ('0' + t.minutes).slice(-2); + secondsSpan.innerHTML = ('0' + t.seconds).slice(-2); + } + updateClock(); + const timeinterval = setInterval(updateClock, 1000); +} +function rucssTimer(id, endtime) { + const timer = document.getElementById(id); + const notice = document.getElementById('rocket-notice-saas-processing'); + const success = document.getElementById('rocket-notice-saas-success'); + if (timer === null) { + return; + } + function updateTimer() { + const start = Date.now(); + const remaining = Math.floor((endtime * 1000 - start) / 1000); + if (remaining <= 0) { + clearInterval(timerInterval); + if (notice !== null) { + notice.classList.add('hidden'); + } + if (success !== null) { + success.classList.remove('hidden'); + } + if (rocket_ajax_data.cron_disabled) { + return; + } + const data = new FormData(); + data.append('action', 'rocket_spawn_cron'); + data.append('nonce', rocket_ajax_data.nonce); + fetch(ajaxurl, { + method: 'POST', + credentials: 'same-origin', + body: data + }); + return; + } + timer.innerHTML = remaining; + } + updateTimer(); + const timerInterval = setInterval(updateTimer, 1000); +} +if (!Date.now) { + Date.now = function now() { + return new Date().getTime(); + }; +} +if (typeof rocket_ajax_data.promo_end !== 'undefined') { + initializeClock('rocket-promo-countdown', rocket_ajax_data.promo_end); +} +if (typeof rocket_ajax_data.license_expiration !== 'undefined') { + initializeClock('rocket-renew-countdown', rocket_ajax_data.license_expiration); +} +if (typeof rocket_ajax_data.notice_end_time !== 'undefined') { + rucssTimer('rocket-rucss-timer', rocket_ajax_data.notice_end_time); +} + +},{}],5:[function(require,module,exports){ +"use strict"; + +var $ = jQuery; +$(document).ready(function () { + /*** + * Check parent / show children + ***/ + + function wprShowChildren(aElem) { + var parentId, $children; + aElem = $(aElem); + parentId = aElem.attr('id'); + $children = $('[data-parent="' + parentId + '"]'); + + // Test check for switch + if (aElem.is(':checked')) { + $children.addClass('wpr-isOpen'); + $children.each(function () { + if ($(this).find('input[type=checkbox]').is(':checked')) { + var id = $(this).find('input[type=checkbox]').attr('id'); + $('[data-parent="' + id + '"]').addClass('wpr-isOpen'); + } + }); + } else { + $children.removeClass('wpr-isOpen'); + $children.each(function () { + var id = $(this).find('input[type=checkbox]').attr('id'); + $('[data-parent="' + id + '"]').removeClass('wpr-isOpen'); + }); + } + } + + /** + * Tell if the given child field has an active parent field. + * + * @param object $field A jQuery object of a ".wpr-field" field. + * @return bool|null + */ + function wprIsParentActive($field) { + var $parent; + if (!$field.length) { + // ¯\_(ツ)_/¯ + return null; + } + $parent = $field.data('parent'); + if (typeof $parent !== 'string') { + // This field has no parent field: then we can display it. + return true; + } + $parent = $parent.replace(/^\s+|\s+$/g, ''); + if ('' === $parent) { + // This field has no parent field: then we can display it. + return true; + } + $parent = $('#' + $parent); + if (!$parent.length) { + // This field's parent is missing: let's consider it's not active then. + return false; + } + if (!$parent.is(':checked') && $parent.is('input')) { + // This field's parent is checkbox and not checked: don't display the field then. + return false; + } + if (!$parent.hasClass('radio-active') && $parent.is('button')) { + // This field's parent button and is not active: don't display the field then. + return false; + } + // Go recursive to the last parent. + return wprIsParentActive($parent.closest('.wpr-field')); + } + + /** + * Masks sensitive information in an input field by replacing all but the last 4 characters with asterisks. + * + * @param {string} id_selector - The ID of the input field to be masked. + * @returns {void} - Modifies the input field value in-place. + * + * @example + * // HTML: + * maskField('creditCardInput'); + * // Result: Updates the input field value to '************3456'. + */ + function maskField(proxy_selector, concrete_selector) { + var concrete = { + 'val': concrete_selector.val(), + 'length': concrete_selector.val().length + }; + if (concrete.length > 4) { + var hiddenPart = '\u2022'.repeat(Math.max(0, concrete.length - 4)); + var visiblePart = concrete.val.slice(-4); + + // Combine the hidden and visible parts + var maskedValue = hiddenPart + visiblePart; + proxy_selector.val(maskedValue); + } + // Ensure events are not added more than once + if (!proxy_selector.data('eventsAttached')) { + proxy_selector.on('input', handleInput); + proxy_selector.on('focus', handleFocus); + proxy_selector.data('eventsAttached', true); + } + + /** + * Handle the input event + */ + function handleInput() { + var proxyValue = proxy_selector.val(); + if (proxyValue.indexOf('\u2022') === -1) { + concrete_selector.val(proxyValue); + } + } + + /** + * Handle the focus event + */ + function handleFocus() { + var concrete_value = concrete_selector.val(); + proxy_selector.val(concrete_value); + } + } + + // Update the concrete field when the proxy is updated. + + maskField($('#cloudflare_api_key_mask'), $('#cloudflare_api_key')); + maskField($('#cloudflare_zone_id_mask'), $('#cloudflare_zone_id')); + + // Display/Hide childern fields on checkbox change. + $('.wpr-isParent input[type=checkbox]').on('change', function () { + wprShowChildren($(this)); + }); + + // On page load, display the active fields. + $('.wpr-field--children').each(function () { + var $field = $(this); + if (wprIsParentActive($field)) { + $field.addClass('wpr-isOpen'); + } + }); + + /*** + * Warning fields + ***/ + + var $warningParent = $('.wpr-field--parent'); + var $warningParentInput = $('.wpr-field--parent input[type=checkbox]'); + + // If already checked + $warningParentInput.each(function () { + wprShowChildren($(this)); + }); + $warningParent.on('change', function () { + wprShowWarning($(this)); + }); + function wprShowWarning(aElem) { + var $warningField = aElem.next('.wpr-fieldWarning'), + $thisCheckbox = aElem.find('input[type=checkbox]'), + $nextWarning = aElem.parent().next('.wpr-warningContainer'), + $nextFields = $nextWarning.find('.wpr-field'), + parentId = aElem.find('input[type=checkbox]').attr('id'), + $children = $('[data-parent="' + parentId + '"]'); + + // Check warning parent + if ($thisCheckbox.is(':checked')) { + $warningField.addClass('wpr-isOpen'); + $thisCheckbox.prop('checked', false); + aElem.trigger('change'); + var $warningButton = $warningField.find('.wpr-button'); + + // Validate the warning + $warningButton.on('click', function () { + $thisCheckbox.prop('checked', true); + $warningField.removeClass('wpr-isOpen'); + $children.addClass('wpr-isOpen'); + + // If next elem = disabled + if ($nextWarning.length > 0) { + $nextFields.removeClass('wpr-isDisabled'); + $nextFields.find('input').prop('disabled', false); + } + return false; + }); + } else { + $nextFields.addClass('wpr-isDisabled'); + $nextFields.find('input').prop('disabled', true); + $nextFields.find('input[type=checkbox]').prop('checked', false); + $children.removeClass('wpr-isOpen'); + } + } + + /** + * CNAMES add/remove lines + */ + $(document).on('click', '.wpr-multiple-close', function (e) { + e.preventDefault(); + $(this).parent().slideUp('slow', function () { + $(this).remove(); + }); + }); + $('.wpr-button--addMulti').on('click', function (e) { + e.preventDefault(); + $($('#wpr-cname-model').html()).appendTo('#wpr-cnames-list'); + }); + + /*** + * Wpr Radio button + ***/ + var disable_radio_warning = false; + $(document).on('click', '.wpr-radio-buttons-container button', function (e) { + e.preventDefault(); + if ($(this).hasClass('radio-active')) { + return false; + } + var $parent = $(this).parents('.wpr-radio-buttons'); + $parent.find('.wpr-radio-buttons-container button').removeClass('radio-active'); + $parent.find('.wpr-extra-fields-container').removeClass('wpr-isOpen'); + $parent.find('.wpr-fieldWarning').removeClass('wpr-isOpen'); + $(this).addClass('radio-active'); + wprShowRadioWarning($(this)); + }); + function wprShowRadioWarning($elm) { + disable_radio_warning = false; + $elm.trigger("before_show_radio_warning", [$elm]); + if (!$elm.hasClass('has-warning') || disable_radio_warning) { + wprShowRadioButtonChildren($elm); + $elm.trigger("radio_button_selected", [$elm]); + return false; + } + var $warningField = $('[data-parent="' + $elm.attr('id') + '"].wpr-fieldWarning'); + $warningField.addClass('wpr-isOpen'); + var $warningButton = $warningField.find('.wpr-button'); + + // Validate the warning + $warningButton.on('click', function () { + $warningField.removeClass('wpr-isOpen'); + wprShowRadioButtonChildren($elm); + $elm.trigger("radio_button_selected", [$elm]); + return false; + }); + } + function wprShowRadioButtonChildren($elm) { + var $parent = $elm.parents('.wpr-radio-buttons'); + var $children = $('.wpr-extra-fields-container[data-parent="' + $elm.attr('id') + '"]'); + $children.addClass('wpr-isOpen'); + } + + /*** + * Wpr Optimize Css Delivery Field + ***/ + var rucssActive = parseInt($('#remove_unused_css').val()); + $("#optimize_css_delivery_method .wpr-radio-buttons-container button").on("radio_button_selected", function (event, $elm) { + toggleActiveOptimizeCssDeliveryMethod($elm); + }); + $("#optimize_css_delivery").on("change", function () { + if ($(this).is(":not(:checked)")) { + disableOptimizeCssDelivery(); + } else { + var default_radio_button_id = '#' + $('#optimize_css_delivery_method').data('default'); + $(default_radio_button_id).trigger('click'); + } + }); + function toggleActiveOptimizeCssDeliveryMethod($elm) { + var optimize_method = $elm.data('value'); + if ('remove_unused_css' === optimize_method) { + $('#remove_unused_css').val(1); + $('#async_css').val(0); + } else { + $('#remove_unused_css').val(0); + $('#async_css').val(1); + } + } + function disableOptimizeCssDelivery() { + $('#remove_unused_css').val(0); + $('#async_css').val(0); + } + $("#optimize_css_delivery_method .wpr-radio-buttons-container button").on("before_show_radio_warning", function (event, $elm) { + disable_radio_warning = 'remove_unused_css' === $elm.data('value') && 1 === rucssActive; + }); + $(".wpr-multiple-select .wpr-list-header-arrow").click(function (e) { + $(e.target).closest('.wpr-multiple-select .wpr-list').toggleClass('open'); + }); + $('.wpr-multiple-select .wpr-checkbox').click(function (e) { + const checkbox = $(this).find('input'); + const is_checked = checkbox.attr('checked') !== undefined; + checkbox.attr('checked', is_checked ? null : 'checked'); + const sub_checkboxes = $(checkbox).closest('.wpr-list').find('.wpr-list-body input[type="checkbox"]'); + if (checkbox.hasClass('wpr-main-checkbox')) { + $.map(sub_checkboxes, checkbox => { + $(checkbox).attr('checked', is_checked ? null : 'checked'); + }); + return; + } + const main_checkbox = $(checkbox).closest('.wpr-list').find('.wpr-main-checkbox'); + const sub_checked = $.map(sub_checkboxes, checkbox => { + if ($(checkbox).attr('checked') === undefined) { + return; + } + return checkbox; + }); + main_checkbox.attr('checked', sub_checked.length === sub_checkboxes.length ? 'checked' : null); + }); + if ($('.wpr-main-checkbox').length > 0) { + $('.wpr-main-checkbox').each((checkbox_key, checkbox) => { + let parent_list = $(checkbox).parents('.wpr-list'); + let not_checked = parent_list.find('.wpr-list-body input[type=checkbox]:not(:checked)').length; + $(checkbox).attr('checked', not_checked <= 0 ? 'checked' : null); + }); + } +}); + +},{}],6:[function(require,module,exports){ +"use strict"; + +var $ = jQuery; +$(document).ready(function () { + /*** + * Dashboard notice + ***/ + + var $notice = $('.wpr-notice'); + var $noticeClose = $('#wpr-congratulations-notice'); + $noticeClose.on('click', function () { + wprCloseDashboardNotice(); + return false; + }); + function wprCloseDashboardNotice() { + var vTL = new TimelineLite().to($notice, 1, { + autoAlpha: 0, + x: 40, + ease: Power4.easeOut + }).to($notice, 0.6, { + height: 0, + marginTop: 0, + ease: Power4.easeOut + }, '=-.4').set($notice, { + 'display': 'none' + }); + } + + /** + * Rocket Analytics notice info collect + */ + $('.rocket-analytics-data-container').hide(); + $('.rocket-preview-analytics-data').on('click', function (e) { + e.preventDefault(); + $(this).parent().next('.rocket-analytics-data-container').toggle(); + }); + + /*** + * Hide / show Rocket addon tabs. + ***/ + + $('.wpr-toggle-button').each(function () { + var $button = $(this); + var $checkbox = $button.closest('.wpr-fieldsContainer-fieldset').find('.wpr-radio :checkbox'); + var $menuItem = $('[href="' + $button.attr('href') + '"].wpr-menuItem'); + $checkbox.on('change', function () { + if ($checkbox.is(':checked')) { + $menuItem.css('display', 'block'); + $button.css('display', 'inline-block'); + } else { + $menuItem.css('display', 'none'); + $button.css('display', 'none'); + } + }).trigger('change'); + }); + + /*** + * Show popin analytics + ***/ + + var $wprAnalyticsPopin = $('.wpr-Popin-Analytics'), + $wprPopinOverlay = $('.wpr-Popin-overlay'), + $wprAnalyticsClosePopin = $('.wpr-Popin-Analytics-close'), + $wprAnalyticsPopinButton = $('.wpr-Popin-Analytics .wpr-button'), + $wprAnalyticsOpenPopin = $('.wpr-js-popin'); + $wprAnalyticsOpenPopin.on('click', function (e) { + e.preventDefault(); + wprOpenAnalytics(); + return false; + }); + $wprAnalyticsClosePopin.on('click', function (e) { + e.preventDefault(); + wprCloseAnalytics(); + return false; + }); + $wprAnalyticsPopinButton.on('click', function (e) { + e.preventDefault(); + wprActivateAnalytics(); + return false; + }); + function wprOpenAnalytics() { + var vTL = new TimelineLite().set($wprAnalyticsPopin, { + 'display': 'block' + }).set($wprPopinOverlay, { + 'display': 'block' + }).fromTo($wprPopinOverlay, 0.6, { + autoAlpha: 0 + }, { + autoAlpha: 1, + ease: Power4.easeOut + }).fromTo($wprAnalyticsPopin, 0.6, { + autoAlpha: 0, + marginTop: -24 + }, { + autoAlpha: 1, + marginTop: 0, + ease: Power4.easeOut + }, '=-.5'); + } + function wprCloseAnalytics() { + var vTL = new TimelineLite().fromTo($wprAnalyticsPopin, 0.6, { + autoAlpha: 1, + marginTop: 0 + }, { + autoAlpha: 0, + marginTop: -24, + ease: Power4.easeOut + }).fromTo($wprPopinOverlay, 0.6, { + autoAlpha: 1 + }, { + autoAlpha: 0, + ease: Power4.easeOut + }, '=-.5').set($wprAnalyticsPopin, { + 'display': 'none' + }).set($wprPopinOverlay, { + 'display': 'none' + }); + } + function wprActivateAnalytics() { + wprCloseAnalytics(); + $('#analytics_enabled').prop('checked', true); + $('#analytics_enabled').trigger('change'); + } + + // Display CTA within the popin `What info will we collect?` + $('#analytics_enabled').on('change', function () { + $('.wpr-rocket-analytics-cta').toggleClass('wpr-isHidden'); + }); + + /*** + * Show popin upgrade + ***/ + + var $wprUpgradePopin = $('.wpr-Popin-Upgrade'), + $wprUpgradeClosePopin = $('.wpr-Popin-Upgrade-close'), + $wprUpgradeOpenPopin = $('.wpr-popin-upgrade-toggle'); + $wprUpgradeOpenPopin.on('click', function (e) { + e.preventDefault(); + wprOpenUpgradePopin(); + return false; + }); + $wprUpgradeClosePopin.on('click', function () { + wprCloseUpgradePopin(); + return false; + }); + function wprOpenUpgradePopin() { + var vTL = new TimelineLite(); + vTL.set($wprUpgradePopin, { + 'display': 'block' + }).set($wprPopinOverlay, { + 'display': 'block' + }).fromTo($wprPopinOverlay, 0.6, { + autoAlpha: 0 + }, { + autoAlpha: 1, + ease: Power4.easeOut + }).fromTo($wprUpgradePopin, 0.6, { + autoAlpha: 0, + marginTop: -24 + }, { + autoAlpha: 1, + marginTop: 0, + ease: Power4.easeOut + }, '=-.5'); + } + function wprCloseUpgradePopin() { + var vTL = new TimelineLite(); + vTL.fromTo($wprUpgradePopin, 0.6, { + autoAlpha: 1, + marginTop: 0 + }, { + autoAlpha: 0, + marginTop: -24, + ease: Power4.easeOut + }).fromTo($wprPopinOverlay, 0.6, { + autoAlpha: 1 + }, { + autoAlpha: 0, + ease: Power4.easeOut + }, '=-.5').set($wprUpgradePopin, { + 'display': 'none' + }).set($wprPopinOverlay, { + 'display': 'none' + }); + } + + /*** + * Sidebar on/off + ***/ + var $wprSidebar = $('.wpr-Sidebar'); + var $wprButtonTips = $('.wpr-js-tips'); + $wprButtonTips.on('change', function () { + wprDetectTips($(this)); + }); + function wprDetectTips(aElem) { + if (aElem.is(':checked')) { + $wprSidebar.css('display', 'block'); + localStorage.setItem('wpr-show-sidebar', 'on'); + } else { + $wprSidebar.css('display', 'none'); + localStorage.setItem('wpr-show-sidebar', 'off'); + } + } + + /*** + * Detect Adblock + ***/ + + if (document.getElementById('LKgOcCRpwmAj')) { + $('.wpr-adblock').css('display', 'none'); + } else { + $('.wpr-adblock').css('display', 'block'); + } + var $adblock = $('.wpr-adblock'); + var $adblockClose = $('.wpr-adblock-close'); + $adblockClose.on('click', function () { + wprCloseAdblockNotice(); + return false; + }); + function wprCloseAdblockNotice() { + var vTL = new TimelineLite().to($adblock, 1, { + autoAlpha: 0, + x: 40, + ease: Power4.easeOut + }).to($adblock, 0.4, { + height: 0, + marginTop: 0, + ease: Power4.easeOut + }, '=-.4').set($adblock, { + 'display': 'none' + }); + } +}); + +},{}],7:[function(require,module,exports){ +"use strict"; + +document.addEventListener('DOMContentLoaded', function () { + var $pageManager = document.querySelector(".wpr-Content"); + if ($pageManager) { + new PageManager($pageManager); + } +}); + +/*-----------------------------------------------*\ + CLASS PAGEMANAGER +\*-----------------------------------------------*/ +/** + * Manages the display of pages / section for WP Rocket plugin + * + * Public method : + detectID - Detect ID with hash + getBodyTop - Get body top position + change - Displays the corresponding page + * + */ + +function PageManager(aElem) { + var refThis = this; + this.$body = document.querySelector('.wpr-body'); + this.$menuItems = document.querySelectorAll('.wpr-menuItem'); + this.$submitButton = document.querySelector('.wpr-Content > form > #wpr-options-submit'); + this.$pages = document.querySelectorAll('.wpr-Page'); + this.$sidebar = document.querySelector('.wpr-Sidebar'); + this.$content = document.querySelector('.wpr-Content'); + this.$tips = document.querySelector('.wpr-Content-tips'); + this.$links = document.querySelectorAll('.wpr-body a'); + this.$menuItem = null; + this.$page = null; + this.pageId = null; + this.bodyTop = 0; + this.buttonText = this.$submitButton.value; + refThis.getBodyTop(); + + // If url page change + window.onhashchange = function () { + refThis.detectID(); + }; + + // If hash already exist (after refresh page for example) + if (window.location.hash) { + this.bodyTop = 0; + this.detectID(); + } else { + var session = localStorage.getItem('wpr-hash'); + this.bodyTop = 0; + if (session) { + window.location.hash = session; + this.detectID(); + } else { + this.$menuItems[0].classList.add('isActive'); + localStorage.setItem('wpr-hash', 'dashboard'); + window.location.hash = '#dashboard'; + } + } + + // Click link same hash + for (var i = 0; i < this.$links.length; i++) { + this.$links[i].onclick = function () { + refThis.getBodyTop(); + var hrefSplit = this.href.split('#')[1]; + if (hrefSplit == refThis.pageId && hrefSplit != undefined) { + refThis.detectID(); + return false; + } + }; + } + + // Click links not WP rocket to reset hash + var $otherlinks = document.querySelectorAll('#adminmenumain a, #wpadminbar a'); + for (var i = 0; i < $otherlinks.length; i++) { + $otherlinks[i].onclick = function () { + localStorage.setItem('wpr-hash', ''); + }; + } +} + +/* +* Page detect ID +*/ +PageManager.prototype.detectID = function () { + this.pageId = window.location.hash.split('#')[1]; + localStorage.setItem('wpr-hash', this.pageId); + this.$page = document.querySelector('.wpr-Page#' + this.pageId); + this.$menuItem = document.getElementById('wpr-nav-' + this.pageId); + this.change(); +}; + +/* +* Get body top position +*/ +PageManager.prototype.getBodyTop = function () { + var bodyPos = this.$body.getBoundingClientRect(); + this.bodyTop = bodyPos.top + window.pageYOffset - 47; // #wpadminbar + padding-top .wpr-wrap - 1 - 47 +}; + +/* +* Page change +*/ +PageManager.prototype.change = function () { + var refThis = this; + document.documentElement.scrollTop = refThis.bodyTop; + + // Hide other pages + for (var i = 0; i < this.$pages.length; i++) { + this.$pages[i].style.display = 'none'; + } + for (var i = 0; i < this.$menuItems.length; i++) { + this.$menuItems[i].classList.remove('isActive'); + } + + // Show current default page + this.$page.style.display = 'block'; + this.$submitButton.style.display = 'block'; + if (null === localStorage.getItem('wpr-show-sidebar')) { + localStorage.setItem('wpr-show-sidebar', 'on'); + } + if ('on' === localStorage.getItem('wpr-show-sidebar')) { + this.$sidebar.style.display = 'block'; + } else if ('off' === localStorage.getItem('wpr-show-sidebar')) { + this.$sidebar.style.display = 'none'; + document.querySelector('#wpr-js-tips').removeAttribute('checked'); + } + this.$tips.style.display = 'block'; + this.$menuItem.classList.add('isActive'); + this.$submitButton.value = this.buttonText; + this.$content.classList.add('isNotFull'); + + // Exception for dashboard + if (this.pageId == "dashboard") { + this.$sidebar.style.display = 'none'; + this.$tips.style.display = 'none'; + this.$submitButton.style.display = 'none'; + this.$content.classList.remove('isNotFull'); + } + + // Exception for addons + if (this.pageId == "addons") { + this.$submitButton.style.display = 'none'; + } + + // Exception for database + if (this.pageId == "database") { + this.$submitButton.style.display = 'none'; + } + + // Exception for tools and addons + if (this.pageId == "tools" || this.pageId == "addons") { + this.$submitButton.style.display = 'none'; + } + if (this.pageId == "imagify") { + this.$sidebar.style.display = 'none'; + this.$tips.style.display = 'none'; + this.$submitButton.style.display = 'none'; + } + if (this.pageId == "tutorials") { + this.$submitButton.style.display = 'none'; + } +}; + +},{}],8:[function(require,module,exports){ +"use strict"; + +/*eslint-env es6*/ +((document, window) => { + 'use strict'; + + document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('.wpr-rocketcdn-open').forEach(el => { + el.addEventListener('click', e => { + e.preventDefault(); + }); + }); + maybeOpenModal(); + MicroModal.init({ + disableScroll: true + }); + }); + window.addEventListener('load', () => { + let openCTA = document.querySelector('#wpr-rocketcdn-open-cta'), + closeCTA = document.querySelector('#wpr-rocketcdn-close-cta'), + smallCTA = document.querySelector('#wpr-rocketcdn-cta-small'), + bigCTA = document.querySelector('#wpr-rocketcdn-cta'); + if (null !== openCTA && null !== smallCTA && null !== bigCTA) { + openCTA.addEventListener('click', e => { + e.preventDefault(); + smallCTA.classList.add('wpr-isHidden'); + bigCTA.classList.remove('wpr-isHidden'); + sendHTTPRequest(getPostData('big')); + }); + } + if (null !== closeCTA && null !== smallCTA && null !== bigCTA) { + closeCTA.addEventListener('click', e => { + e.preventDefault(); + smallCTA.classList.remove('wpr-isHidden'); + bigCTA.classList.add('wpr-isHidden'); + sendHTTPRequest(getPostData('small')); + }); + } + function getPostData(status) { + let postData = ''; + postData += 'action=toggle_rocketcdn_cta'; + postData += '&status=' + status; + postData += '&nonce=' + rocket_ajax_data.nonce; + return postData; + } + }); + window.onmessage = e => { + const iframeURL = rocket_ajax_data.origin_url; + if (e.origin !== iframeURL) { + return; + } + setCDNFrameHeight(e.data); + closeModal(e.data); + tokenHandler(e.data, iframeURL); + processStatus(e.data); + enableCDN(e.data, iframeURL); + disableCDN(e.data, iframeURL); + validateTokenAndCNAME(e.data); + }; + function maybeOpenModal() { + let postData = ''; + postData += 'action=rocketcdn_process_status'; + postData += '&nonce=' + rocket_ajax_data.nonce; + const request = sendHTTPRequest(postData); + request.onreadystatechange = () => { + if (request.readyState === XMLHttpRequest.DONE && 200 === request.status) { + let responseTxt = JSON.parse(request.responseText); + if (true === responseTxt.success) { + MicroModal.show('wpr-rocketcdn-modal'); + } + } + }; + } + function closeModal(data) { + if (!data.hasOwnProperty('cdnFrameClose')) { + return; + } + MicroModal.close('wpr-rocketcdn-modal'); + let pages = ['iframe-payment-success', 'iframe-unsubscribe-success']; + if (!data.hasOwnProperty('cdn_page_message')) { + return; + } + if (pages.indexOf(data.cdn_page_message) === -1) { + return; + } + document.location.reload(); + } + function processStatus(data) { + if (!data.hasOwnProperty('rocketcdn_process')) { + return; + } + let postData = ''; + postData += 'action=rocketcdn_process_set'; + postData += '&status=' + data.rocketcdn_process; + postData += '&nonce=' + rocket_ajax_data.nonce; + sendHTTPRequest(postData); + } + function enableCDN(data, iframeURL) { + let iframe = document.querySelector('#rocketcdn-iframe').contentWindow; + if (!data.hasOwnProperty('rocketcdn_url')) { + return; + } + let postData = ''; + postData += 'action=rocketcdn_enable'; + postData += '&cdn_url=' + data.rocketcdn_url; + postData += '&nonce=' + rocket_ajax_data.nonce; + const request = sendHTTPRequest(postData); + request.onreadystatechange = () => { + if (request.readyState === XMLHttpRequest.DONE && 200 === request.status) { + let responseTxt = JSON.parse(request.responseText); + iframe.postMessage({ + 'success': responseTxt.success, + 'data': responseTxt.data, + 'rocketcdn': true + }, iframeURL); + } + }; + } + function disableCDN(data, iframeURL) { + let iframe = document.querySelector('#rocketcdn-iframe').contentWindow; + if (!data.hasOwnProperty('rocketcdn_disable')) { + return; + } + let postData = ''; + postData += 'action=rocketcdn_disable'; + postData += '&nonce=' + rocket_ajax_data.nonce; + const request = sendHTTPRequest(postData); + request.onreadystatechange = () => { + if (request.readyState === XMLHttpRequest.DONE && 200 === request.status) { + let responseTxt = JSON.parse(request.responseText); + iframe.postMessage({ + 'success': responseTxt.success, + 'data': responseTxt.data, + 'rocketcdn': true + }, iframeURL); + } + }; + } + function sendHTTPRequest(postData) { + const httpRequest = new XMLHttpRequest(); + httpRequest.open('POST', ajaxurl); + httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + httpRequest.send(postData); + return httpRequest; + } + function setCDNFrameHeight(data) { + if (!data.hasOwnProperty('cdnFrameHeight')) { + return; + } + document.getElementById('rocketcdn-iframe').style.height = `${data.cdnFrameHeight}px`; + } + function tokenHandler(data, iframeURL) { + let iframe = document.querySelector('#rocketcdn-iframe').contentWindow; + if (!data.hasOwnProperty('rocketcdn_token')) { + let data = { + process: "subscribe", + message: "token_not_received" + }; + iframe.postMessage({ + 'success': false, + 'data': data, + 'rocketcdn': true + }, iframeURL); + return; + } + let postData = ''; + postData += 'action=save_rocketcdn_token'; + postData += '&value=' + data.rocketcdn_token; + postData += '&nonce=' + rocket_ajax_data.nonce; + const request = sendHTTPRequest(postData); + request.onreadystatechange = () => { + if (request.readyState === XMLHttpRequest.DONE && 200 === request.status) { + let responseTxt = JSON.parse(request.responseText); + iframe.postMessage({ + 'success': responseTxt.success, + 'data': responseTxt.data, + 'rocketcdn': true + }, iframeURL); + } + }; + } + function validateTokenAndCNAME(data) { + if (!data.hasOwnProperty('rocketcdn_validate_token') || !data.hasOwnProperty('rocketcdn_validate_cname')) { + return; + } + let postData = ''; + postData += 'action=rocketcdn_validate_token_cname'; + postData += '&cdn_url=' + data.rocketcdn_validate_cname; + postData += '&cdn_token=' + data.rocketcdn_validate_token; + postData += '&nonce=' + rocket_ajax_data.nonce; + const request = sendHTTPRequest(postData); + } +})(document, window); + +},{}],9:[function(require,module,exports){ +"use strict"; + +/*! + * VERSION: 1.12.1 + * DATE: 2014-06-26 + * UPDATES AND DOCS AT: http://www.greensock.com + * + * @license Copyright (c) 2008-2014, GreenSock. All rights reserved. + * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for + * Club GreenSock members, the software agreement that was issued with your membership. + * + * @author: Jack Doyle, jack@greensock.com + */ +(window._gsQueue || (window._gsQueue = [])).push(function () { + "use strict"; + + window._gsDefine("TimelineLite", ["core.Animation", "core.SimpleTimeline", "TweenLite"], function (t, e, i) { + var s = function (t) { + e.call(this, t), this._labels = {}, this.autoRemoveChildren = this.vars.autoRemoveChildren === !0, this.smoothChildTiming = this.vars.smoothChildTiming === !0, this._sortChildren = !0, this._onUpdate = this.vars.onUpdate; + var i, + s, + r = this.vars; + for (s in r) i = r[s], a(i) && -1 !== i.join("").indexOf("{self}") && (r[s] = this._swapSelfInParams(i)); + a(r.tweens) && this.add(r.tweens, 0, r.align, r.stagger); + }, + r = 1e-10, + n = i._internals.isSelector, + a = i._internals.isArray, + o = [], + h = window._gsDefine.globals, + l = function (t) { + var e, + i = {}; + for (e in t) i[e] = t[e]; + return i; + }, + _ = function (t, e, i, s) { + t._timeline.pause(t._startTime), e && e.apply(s || t._timeline, i || o); + }, + u = o.slice, + f = s.prototype = new e(); + return s.version = "1.12.1", f.constructor = s, f.kill()._gc = !1, f.to = function (t, e, s, r) { + var n = s.repeat && h.TweenMax || i; + return e ? this.add(new n(t, e, s), r) : this.set(t, s, r); + }, f.from = function (t, e, s, r) { + return this.add((s.repeat && h.TweenMax || i).from(t, e, s), r); + }, f.fromTo = function (t, e, s, r, n) { + var a = r.repeat && h.TweenMax || i; + return e ? this.add(a.fromTo(t, e, s, r), n) : this.set(t, r, n); + }, f.staggerTo = function (t, e, r, a, o, h, _, f) { + var p, + c = new s({ + onComplete: h, + onCompleteParams: _, + onCompleteScope: f, + smoothChildTiming: this.smoothChildTiming + }); + for ("string" == typeof t && (t = i.selector(t) || t), n(t) && (t = u.call(t, 0)), a = a || 0, p = 0; t.length > p; p++) r.startAt && (r.startAt = l(r.startAt)), c.to(t[p], e, l(r), p * a); + return this.add(c, o); + }, f.staggerFrom = function (t, e, i, s, r, n, a, o) { + return i.immediateRender = 0 != i.immediateRender, i.runBackwards = !0, this.staggerTo(t, e, i, s, r, n, a, o); + }, f.staggerFromTo = function (t, e, i, s, r, n, a, o, h) { + return s.startAt = i, s.immediateRender = 0 != s.immediateRender && 0 != i.immediateRender, this.staggerTo(t, e, s, r, n, a, o, h); + }, f.call = function (t, e, s, r) { + return this.add(i.delayedCall(0, t, e, s), r); + }, f.set = function (t, e, s) { + return s = this._parseTimeOrLabel(s, 0, !0), null == e.immediateRender && (e.immediateRender = s === this._time && !this._paused), this.add(new i(t, 0, e), s); + }, s.exportRoot = function (t, e) { + t = t || {}, null == t.smoothChildTiming && (t.smoothChildTiming = !0); + var r, + n, + a = new s(t), + o = a._timeline; + for (null == e && (e = !0), o._remove(a, !0), a._startTime = 0, a._rawPrevTime = a._time = a._totalTime = o._time, r = o._first; r;) n = r._next, e && r instanceof i && r.target === r.vars.onComplete || a.add(r, r._startTime - r._delay), r = n; + return o.add(a, 0), a; + }, f.add = function (r, n, o, h) { + var l, _, u, f, p, c; + if ("number" != typeof n && (n = this._parseTimeOrLabel(n, 0, !0, r)), !(r instanceof t)) { + if (r instanceof Array || r && r.push && a(r)) { + for (o = o || "normal", h = h || 0, l = n, _ = r.length, u = 0; _ > u; u++) a(f = r[u]) && (f = new s({ + tweens: f + })), this.add(f, l), "string" != typeof f && "function" != typeof f && ("sequence" === o ? l = f._startTime + f.totalDuration() / f._timeScale : "start" === o && (f._startTime -= f.delay())), l += h; + return this._uncache(!0); + } + if ("string" == typeof r) return this.addLabel(r, n); + if ("function" != typeof r) throw "Cannot add " + r + " into the timeline; it is not a tween, timeline, function, or string."; + r = i.delayedCall(0, r); + } + if (e.prototype.add.call(this, r, n), (this._gc || this._time === this._duration) && !this._paused && this._duration < this.duration()) for (p = this, c = p.rawTime() > r._startTime; p._timeline;) c && p._timeline.smoothChildTiming ? p.totalTime(p._totalTime, !0) : p._gc && p._enabled(!0, !1), p = p._timeline; + return this; + }, f.remove = function (e) { + if (e instanceof t) return this._remove(e, !1); + if (e instanceof Array || e && e.push && a(e)) { + for (var i = e.length; --i > -1;) this.remove(e[i]); + return this; + } + return "string" == typeof e ? this.removeLabel(e) : this.kill(null, e); + }, f._remove = function (t, i) { + e.prototype._remove.call(this, t, i); + var s = this._last; + return s ? this._time > s._startTime + s._totalDuration / s._timeScale && (this._time = this.duration(), this._totalTime = this._totalDuration) : this._time = this._totalTime = this._duration = this._totalDuration = 0, this; + }, f.append = function (t, e) { + return this.add(t, this._parseTimeOrLabel(null, e, !0, t)); + }, f.insert = f.insertMultiple = function (t, e, i, s) { + return this.add(t, e || 0, i, s); + }, f.appendMultiple = function (t, e, i, s) { + return this.add(t, this._parseTimeOrLabel(null, e, !0, t), i, s); + }, f.addLabel = function (t, e) { + return this._labels[t] = this._parseTimeOrLabel(e), this; + }, f.addPause = function (t, e, i, s) { + return this.call(_, ["{self}", e, i, s], this, t); + }, f.removeLabel = function (t) { + return delete this._labels[t], this; + }, f.getLabelTime = function (t) { + return null != this._labels[t] ? this._labels[t] : -1; + }, f._parseTimeOrLabel = function (e, i, s, r) { + var n; + if (r instanceof t && r.timeline === this) this.remove(r);else if (r && (r instanceof Array || r.push && a(r))) for (n = r.length; --n > -1;) r[n] instanceof t && r[n].timeline === this && this.remove(r[n]); + if ("string" == typeof i) return this._parseTimeOrLabel(i, s && "number" == typeof e && null == this._labels[i] ? e - this.duration() : 0, s); + if (i = i || 0, "string" != typeof e || !isNaN(e) && null == this._labels[e]) null == e && (e = this.duration());else { + if (n = e.indexOf("="), -1 === n) return null == this._labels[e] ? s ? this._labels[e] = this.duration() + i : i : this._labels[e] + i; + i = parseInt(e.charAt(n - 1) + "1", 10) * Number(e.substr(n + 1)), e = n > 1 ? this._parseTimeOrLabel(e.substr(0, n - 1), 0, s) : this.duration(); + } + return Number(e) + i; + }, f.seek = function (t, e) { + return this.totalTime("number" == typeof t ? t : this._parseTimeOrLabel(t), e !== !1); + }, f.stop = function () { + return this.paused(!0); + }, f.gotoAndPlay = function (t, e) { + return this.play(t, e); + }, f.gotoAndStop = function (t, e) { + return this.pause(t, e); + }, f.render = function (t, e, i) { + this._gc && this._enabled(!0, !1); + var s, + n, + a, + h, + l, + _ = this._dirty ? this.totalDuration() : this._totalDuration, + u = this._time, + f = this._startTime, + p = this._timeScale, + c = this._paused; + if (t >= _ ? (this._totalTime = this._time = _, this._reversed || this._hasPausedChild() || (n = !0, h = "onComplete", 0 === this._duration && (0 === t || 0 > this._rawPrevTime || this._rawPrevTime === r) && this._rawPrevTime !== t && this._first && (l = !0, this._rawPrevTime > r && (h = "onReverseComplete"))), this._rawPrevTime = this._duration || !e || t || this._rawPrevTime === t ? t : r, t = _ + 1e-4) : 1e-7 > t ? (this._totalTime = this._time = 0, (0 !== u || 0 === this._duration && this._rawPrevTime !== r && (this._rawPrevTime > 0 || 0 > t && this._rawPrevTime >= 0)) && (h = "onReverseComplete", n = this._reversed), 0 > t ? (this._active = !1, 0 === this._duration && this._rawPrevTime >= 0 && this._first && (l = !0), this._rawPrevTime = t) : (this._rawPrevTime = this._duration || !e || t || this._rawPrevTime === t ? t : r, t = 0, this._initted || (l = !0))) : this._totalTime = this._time = this._rawPrevTime = t, this._time !== u && this._first || i || l) { + if (this._initted || (this._initted = !0), this._active || !this._paused && this._time !== u && t > 0 && (this._active = !0), 0 === u && this.vars.onStart && 0 !== this._time && (e || this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || o)), this._time >= u) for (s = this._first; s && (a = s._next, !this._paused || c);) (s._active || s._startTime <= this._time && !s._paused && !s._gc) && (s._reversed ? s.render((s._dirty ? s.totalDuration() : s._totalDuration) - (t - s._startTime) * s._timeScale, e, i) : s.render((t - s._startTime) * s._timeScale, e, i)), s = a;else for (s = this._last; s && (a = s._prev, !this._paused || c);) (s._active || u >= s._startTime && !s._paused && !s._gc) && (s._reversed ? s.render((s._dirty ? s.totalDuration() : s._totalDuration) - (t - s._startTime) * s._timeScale, e, i) : s.render((t - s._startTime) * s._timeScale, e, i)), s = a; + this._onUpdate && (e || this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || o)), h && (this._gc || (f === this._startTime || p !== this._timeScale) && (0 === this._time || _ >= this.totalDuration()) && (n && (this._timeline.autoRemoveChildren && this._enabled(!1, !1), this._active = !1), !e && this.vars[h] && this.vars[h].apply(this.vars[h + "Scope"] || this, this.vars[h + "Params"] || o))); + } + }, f._hasPausedChild = function () { + for (var t = this._first; t;) { + if (t._paused || t instanceof s && t._hasPausedChild()) return !0; + t = t._next; + } + return !1; + }, f.getChildren = function (t, e, s, r) { + r = r || -9999999999; + for (var n = [], a = this._first, o = 0; a;) r > a._startTime || (a instanceof i ? e !== !1 && (n[o++] = a) : (s !== !1 && (n[o++] = a), t !== !1 && (n = n.concat(a.getChildren(!0, e, s)), o = n.length))), a = a._next; + return n; + }, f.getTweensOf = function (t, e) { + var s, + r, + n = this._gc, + a = [], + o = 0; + for (n && this._enabled(!0, !0), s = i.getTweensOf(t), r = s.length; --r > -1;) (s[r].timeline === this || e && this._contains(s[r])) && (a[o++] = s[r]); + return n && this._enabled(!1, !0), a; + }, f._contains = function (t) { + for (var e = t.timeline; e;) { + if (e === this) return !0; + e = e.timeline; + } + return !1; + }, f.shiftChildren = function (t, e, i) { + i = i || 0; + for (var s, r = this._first, n = this._labels; r;) r._startTime >= i && (r._startTime += t), r = r._next; + if (e) for (s in n) n[s] >= i && (n[s] += t); + return this._uncache(!0); + }, f._kill = function (t, e) { + if (!t && !e) return this._enabled(!1, !1); + for (var i = e ? this.getTweensOf(e) : this.getChildren(!0, !0, !1), s = i.length, r = !1; --s > -1;) i[s]._kill(t, e) && (r = !0); + return r; + }, f.clear = function (t) { + var e = this.getChildren(!1, !0, !0), + i = e.length; + for (this._time = this._totalTime = 0; --i > -1;) e[i]._enabled(!1, !1); + return t !== !1 && (this._labels = {}), this._uncache(!0); + }, f.invalidate = function () { + for (var t = this._first; t;) t.invalidate(), t = t._next; + return this; + }, f._enabled = function (t, i) { + if (t === this._gc) for (var s = this._first; s;) s._enabled(t, !0), s = s._next; + return e.prototype._enabled.call(this, t, i); + }, f.duration = function (t) { + return arguments.length ? (0 !== this.duration() && 0 !== t && this.timeScale(this._duration / t), this) : (this._dirty && this.totalDuration(), this._duration); + }, f.totalDuration = function (t) { + if (!arguments.length) { + if (this._dirty) { + for (var e, i, s = 0, r = this._last, n = 999999999999; r;) e = r._prev, r._dirty && r.totalDuration(), r._startTime > n && this._sortChildren && !r._paused ? this.add(r, r._startTime - r._delay) : n = r._startTime, 0 > r._startTime && !r._paused && (s -= r._startTime, this._timeline.smoothChildTiming && (this._startTime += r._startTime / this._timeScale), this.shiftChildren(-r._startTime, !1, -9999999999), n = 0), i = r._startTime + r._totalDuration / r._timeScale, i > s && (s = i), r = e; + this._duration = this._totalDuration = s, this._dirty = !1; + } + return this._totalDuration; + } + return 0 !== this.totalDuration() && 0 !== t && this.timeScale(this._totalDuration / t), this; + }, f.usesFrames = function () { + for (var e = this._timeline; e._timeline;) e = e._timeline; + return e === t._rootFramesTimeline; + }, f.rawTime = function () { + return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale; + }, s; + }, !0); +}), window._gsDefine && window._gsQueue.pop()(); + +},{}],10:[function(require,module,exports){ +"use strict"; + +/*! + * VERSION: 1.12.1 + * DATE: 2014-06-26 + * UPDATES AND DOCS AT: http://www.greensock.com + * + * @license Copyright (c) 2008-2014, GreenSock. All rights reserved. + * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for + * Club GreenSock members, the software agreement that was issued with your membership. + * + * @author: Jack Doyle, jack@greensock.com + */ +(function (t) { + "use strict"; + + var e = t.GreenSockGlobals || t; + if (!e.TweenLite) { + var i, + s, + n, + r, + a, + o = function (t) { + var i, + s = t.split("."), + n = e; + for (i = 0; s.length > i; i++) n[s[i]] = n = n[s[i]] || {}; + return n; + }, + l = o("com.greensock"), + h = 1e-10, + _ = [].slice, + u = function () {}, + m = function () { + var t = Object.prototype.toString, + e = t.call([]); + return function (i) { + return null != i && (i instanceof Array || "object" == typeof i && !!i.push && t.call(i) === e); + }; + }(), + f = {}, + p = function (i, s, n, r) { + this.sc = f[i] ? f[i].sc : [], f[i] = this, this.gsClass = null, this.func = n; + var a = []; + this.check = function (l) { + for (var h, _, u, m, c = s.length, d = c; --c > -1;) (h = f[s[c]] || new p(s[c], [])).gsClass ? (a[c] = h.gsClass, d--) : l && h.sc.push(this); + if (0 === d && n) for (_ = ("com.greensock." + i).split("."), u = _.pop(), m = o(_.join("."))[u] = this.gsClass = n.apply(n, a), r && (e[u] = m, "function" == typeof define && define.amd ? define((t.GreenSockAMDPath ? t.GreenSockAMDPath + "/" : "") + i.split(".").join("/"), [], function () { + return m; + }) : "undefined" != typeof module && module.exports && (module.exports = m)), c = 0; this.sc.length > c; c++) this.sc[c].check(); + }, this.check(!0); + }, + c = t._gsDefine = function (t, e, i, s) { + return new p(t, e, i, s); + }, + d = l._class = function (t, e, i) { + return e = e || function () {}, c(t, [], function () { + return e; + }, i), e; + }; + c.globals = e; + var v = [0, 0, 1, 1], + g = [], + T = d("easing.Ease", function (t, e, i, s) { + this._func = t, this._type = i || 0, this._power = s || 0, this._params = e ? v.concat(e) : v; + }, !0), + y = T.map = {}, + w = T.register = function (t, e, i, s) { + for (var n, r, a, o, h = e.split(","), _ = h.length, u = (i || "easeIn,easeOut,easeInOut").split(","); --_ > -1;) for (r = h[_], n = s ? d("easing." + r, null, !0) : l.easing[r] || {}, a = u.length; --a > -1;) o = u[a], y[r + "." + o] = y[o + r] = n[o] = t.getRatio ? t : t[o] || new t(); + }; + for (n = T.prototype, n._calcEnd = !1, n.getRatio = function (t) { + if (this._func) return this._params[0] = t, this._func.apply(null, this._params); + var e = this._type, + i = this._power, + s = 1 === e ? 1 - t : 2 === e ? t : .5 > t ? 2 * t : 2 * (1 - t); + return 1 === i ? s *= s : 2 === i ? s *= s * s : 3 === i ? s *= s * s * s : 4 === i && (s *= s * s * s * s), 1 === e ? 1 - s : 2 === e ? s : .5 > t ? s / 2 : 1 - s / 2; + }, i = ["Linear", "Quad", "Cubic", "Quart", "Quint,Strong"], s = i.length; --s > -1;) n = i[s] + ",Power" + s, w(new T(null, null, 1, s), n, "easeOut", !0), w(new T(null, null, 2, s), n, "easeIn" + (0 === s ? ",easeNone" : "")), w(new T(null, null, 3, s), n, "easeInOut"); + y.linear = l.easing.Linear.easeIn, y.swing = l.easing.Quad.easeInOut; + var P = d("events.EventDispatcher", function (t) { + this._listeners = {}, this._eventTarget = t || this; + }); + n = P.prototype, n.addEventListener = function (t, e, i, s, n) { + n = n || 0; + var o, + l, + h = this._listeners[t], + _ = 0; + for (null == h && (this._listeners[t] = h = []), l = h.length; --l > -1;) o = h[l], o.c === e && o.s === i ? h.splice(l, 1) : 0 === _ && n > o.pr && (_ = l + 1); + h.splice(_, 0, { + c: e, + s: i, + up: s, + pr: n + }), this !== r || a || r.wake(); + }, n.removeEventListener = function (t, e) { + var i, + s = this._listeners[t]; + if (s) for (i = s.length; --i > -1;) if (s[i].c === e) return s.splice(i, 1), void 0; + }, n.dispatchEvent = function (t) { + var e, + i, + s, + n = this._listeners[t]; + if (n) for (e = n.length, i = this._eventTarget; --e > -1;) s = n[e], s.up ? s.c.call(s.s || i, { + type: t, + target: i + }) : s.c.call(s.s || i); + }; + var k = t.requestAnimationFrame, + b = t.cancelAnimationFrame, + A = Date.now || function () { + return new Date().getTime(); + }, + S = A(); + for (i = ["ms", "moz", "webkit", "o"], s = i.length; --s > -1 && !k;) k = t[i[s] + "RequestAnimationFrame"], b = t[i[s] + "CancelAnimationFrame"] || t[i[s] + "CancelRequestAnimationFrame"]; + d("Ticker", function (t, e) { + var i, + s, + n, + o, + l, + _ = this, + m = A(), + f = e !== !1 && k, + p = 500, + c = 33, + d = function (t) { + var e, + r, + a = A() - S; + a > p && (m += a - c), S += a, _.time = (S - m) / 1e3, e = _.time - l, (!i || e > 0 || t === !0) && (_.frame++, l += e + (e >= o ? .004 : o - e), r = !0), t !== !0 && (n = s(d)), r && _.dispatchEvent("tick"); + }; + P.call(_), _.time = _.frame = 0, _.tick = function () { + d(!0); + }, _.lagSmoothing = function (t, e) { + p = t || 1 / h, c = Math.min(e, p, 0); + }, _.sleep = function () { + null != n && (f && b ? b(n) : clearTimeout(n), s = u, n = null, _ === r && (a = !1)); + }, _.wake = function () { + null !== n ? _.sleep() : _.frame > 10 && (S = A() - p + 5), s = 0 === i ? u : f && k ? k : function (t) { + return setTimeout(t, 0 | 1e3 * (l - _.time) + 1); + }, _ === r && (a = !0), d(2); + }, _.fps = function (t) { + return arguments.length ? (i = t, o = 1 / (i || 60), l = this.time + o, _.wake(), void 0) : i; + }, _.useRAF = function (t) { + return arguments.length ? (_.sleep(), f = t, _.fps(i), void 0) : f; + }, _.fps(t), setTimeout(function () { + f && (!n || 5 > _.frame) && _.useRAF(!1); + }, 1500); + }), n = l.Ticker.prototype = new l.events.EventDispatcher(), n.constructor = l.Ticker; + var x = d("core.Animation", function (t, e) { + if (this.vars = e = e || {}, this._duration = this._totalDuration = t || 0, this._delay = Number(e.delay) || 0, this._timeScale = 1, this._active = e.immediateRender === !0, this.data = e.data, this._reversed = e.reversed === !0, B) { + a || r.wake(); + var i = this.vars.useFrames ? Q : B; + i.add(this, i._time), this.vars.paused && this.paused(!0); + } + }); + r = x.ticker = new l.Ticker(), n = x.prototype, n._dirty = n._gc = n._initted = n._paused = !1, n._totalTime = n._time = 0, n._rawPrevTime = -1, n._next = n._last = n._onUpdate = n._timeline = n.timeline = null, n._paused = !1; + var C = function () { + a && A() - S > 2e3 && r.wake(), setTimeout(C, 2e3); + }; + C(), n.play = function (t, e) { + return null != t && this.seek(t, e), this.reversed(!1).paused(!1); + }, n.pause = function (t, e) { + return null != t && this.seek(t, e), this.paused(!0); + }, n.resume = function (t, e) { + return null != t && this.seek(t, e), this.paused(!1); + }, n.seek = function (t, e) { + return this.totalTime(Number(t), e !== !1); + }, n.restart = function (t, e) { + return this.reversed(!1).paused(!1).totalTime(t ? -this._delay : 0, e !== !1, !0); + }, n.reverse = function (t, e) { + return null != t && this.seek(t || this.totalDuration(), e), this.reversed(!0).paused(!1); + }, n.render = function () {}, n.invalidate = function () { + return this; + }, n.isActive = function () { + var t, + e = this._timeline, + i = this._startTime; + return !e || !this._gc && !this._paused && e.isActive() && (t = e.rawTime()) >= i && i + this.totalDuration() / this._timeScale > t; + }, n._enabled = function (t, e) { + return a || r.wake(), this._gc = !t, this._active = this.isActive(), e !== !0 && (t && !this.timeline ? this._timeline.add(this, this._startTime - this._delay) : !t && this.timeline && this._timeline._remove(this, !0)), !1; + }, n._kill = function () { + return this._enabled(!1, !1); + }, n.kill = function (t, e) { + return this._kill(t, e), this; + }, n._uncache = function (t) { + for (var e = t ? this : this.timeline; e;) e._dirty = !0, e = e.timeline; + return this; + }, n._swapSelfInParams = function (t) { + for (var e = t.length, i = t.concat(); --e > -1;) "{self}" === t[e] && (i[e] = this); + return i; + }, n.eventCallback = function (t, e, i, s) { + if ("on" === (t || "").substr(0, 2)) { + var n = this.vars; + if (1 === arguments.length) return n[t]; + null == e ? delete n[t] : (n[t] = e, n[t + "Params"] = m(i) && -1 !== i.join("").indexOf("{self}") ? this._swapSelfInParams(i) : i, n[t + "Scope"] = s), "onUpdate" === t && (this._onUpdate = e); + } + return this; + }, n.delay = function (t) { + return arguments.length ? (this._timeline.smoothChildTiming && this.startTime(this._startTime + t - this._delay), this._delay = t, this) : this._delay; + }, n.duration = function (t) { + return arguments.length ? (this._duration = this._totalDuration = t, this._uncache(!0), this._timeline.smoothChildTiming && this._time > 0 && this._time < this._duration && 0 !== t && this.totalTime(this._totalTime * (t / this._duration), !0), this) : (this._dirty = !1, this._duration); + }, n.totalDuration = function (t) { + return this._dirty = !1, arguments.length ? this.duration(t) : this._totalDuration; + }, n.time = function (t, e) { + return arguments.length ? (this._dirty && this.totalDuration(), this.totalTime(t > this._duration ? this._duration : t, e)) : this._time; + }, n.totalTime = function (t, e, i) { + if (a || r.wake(), !arguments.length) return this._totalTime; + if (this._timeline) { + if (0 > t && !i && (t += this.totalDuration()), this._timeline.smoothChildTiming) { + this._dirty && this.totalDuration(); + var s = this._totalDuration, + n = this._timeline; + if (t > s && !i && (t = s), this._startTime = (this._paused ? this._pauseTime : n._time) - (this._reversed ? s - t : t) / this._timeScale, n._dirty || this._uncache(!1), n._timeline) for (; n._timeline;) n._timeline._time !== (n._startTime + n._totalTime) / n._timeScale && n.totalTime(n._totalTime, !0), n = n._timeline; + } + this._gc && this._enabled(!0, !1), (this._totalTime !== t || 0 === this._duration) && (this.render(t, e, !1), z.length && q()); + } + return this; + }, n.progress = n.totalProgress = function (t, e) { + return arguments.length ? this.totalTime(this.duration() * t, e) : this._time / this.duration(); + }, n.startTime = function (t) { + return arguments.length ? (t !== this._startTime && (this._startTime = t, this.timeline && this.timeline._sortChildren && this.timeline.add(this, t - this._delay)), this) : this._startTime; + }, n.timeScale = function (t) { + if (!arguments.length) return this._timeScale; + if (t = t || h, this._timeline && this._timeline.smoothChildTiming) { + var e = this._pauseTime, + i = e || 0 === e ? e : this._timeline.totalTime(); + this._startTime = i - (i - this._startTime) * this._timeScale / t; + } + return this._timeScale = t, this._uncache(!1); + }, n.reversed = function (t) { + return arguments.length ? (t != this._reversed && (this._reversed = t, this.totalTime(this._timeline && !this._timeline.smoothChildTiming ? this.totalDuration() - this._totalTime : this._totalTime, !0)), this) : this._reversed; + }, n.paused = function (t) { + if (!arguments.length) return this._paused; + if (t != this._paused && this._timeline) { + a || t || r.wake(); + var e = this._timeline, + i = e.rawTime(), + s = i - this._pauseTime; + !t && e.smoothChildTiming && (this._startTime += s, this._uncache(!1)), this._pauseTime = t ? i : null, this._paused = t, this._active = this.isActive(), !t && 0 !== s && this._initted && this.duration() && this.render(e.smoothChildTiming ? this._totalTime : (i - this._startTime) / this._timeScale, !0, !0); + } + return this._gc && !t && this._enabled(!0, !1), this; + }; + var R = d("core.SimpleTimeline", function (t) { + x.call(this, 0, t), this.autoRemoveChildren = this.smoothChildTiming = !0; + }); + n = R.prototype = new x(), n.constructor = R, n.kill()._gc = !1, n._first = n._last = null, n._sortChildren = !1, n.add = n.insert = function (t, e) { + var i, s; + if (t._startTime = Number(e || 0) + t._delay, t._paused && this !== t._timeline && (t._pauseTime = t._startTime + (this.rawTime() - t._startTime) / t._timeScale), t.timeline && t.timeline._remove(t, !0), t.timeline = t._timeline = this, t._gc && t._enabled(!0, !0), i = this._last, this._sortChildren) for (s = t._startTime; i && i._startTime > s;) i = i._prev; + return i ? (t._next = i._next, i._next = t) : (t._next = this._first, this._first = t), t._next ? t._next._prev = t : this._last = t, t._prev = i, this._timeline && this._uncache(!0), this; + }, n._remove = function (t, e) { + return t.timeline === this && (e || t._enabled(!1, !0), t.timeline = null, t._prev ? t._prev._next = t._next : this._first === t && (this._first = t._next), t._next ? t._next._prev = t._prev : this._last === t && (this._last = t._prev), this._timeline && this._uncache(!0)), this; + }, n.render = function (t, e, i) { + var s, + n = this._first; + for (this._totalTime = this._time = this._rawPrevTime = t; n;) s = n._next, (n._active || t >= n._startTime && !n._paused) && (n._reversed ? n.render((n._dirty ? n.totalDuration() : n._totalDuration) - (t - n._startTime) * n._timeScale, e, i) : n.render((t - n._startTime) * n._timeScale, e, i)), n = s; + }, n.rawTime = function () { + return a || r.wake(), this._totalTime; + }; + var D = d("TweenLite", function (e, i, s) { + if (x.call(this, i, s), this.render = D.prototype.render, null == e) throw "Cannot tween a null target."; + this.target = e = "string" != typeof e ? e : D.selector(e) || e; + var n, + r, + a, + o = e.jquery || e.length && e !== t && e[0] && (e[0] === t || e[0].nodeType && e[0].style && !e.nodeType), + l = this.vars.overwrite; + if (this._overwrite = l = null == l ? G[D.defaultOverwrite] : "number" == typeof l ? l >> 0 : G[l], (o || e instanceof Array || e.push && m(e)) && "number" != typeof e[0]) for (this._targets = a = _.call(e, 0), this._propLookup = [], this._siblings = [], n = 0; a.length > n; n++) r = a[n], r ? "string" != typeof r ? r.length && r !== t && r[0] && (r[0] === t || r[0].nodeType && r[0].style && !r.nodeType) ? (a.splice(n--, 1), this._targets = a = a.concat(_.call(r, 0))) : (this._siblings[n] = M(r, this, !1), 1 === l && this._siblings[n].length > 1 && $(r, this, null, 1, this._siblings[n])) : (r = a[n--] = D.selector(r), "string" == typeof r && a.splice(n + 1, 1)) : a.splice(n--, 1);else this._propLookup = {}, this._siblings = M(e, this, !1), 1 === l && this._siblings.length > 1 && $(e, this, null, 1, this._siblings); + (this.vars.immediateRender || 0 === i && 0 === this._delay && this.vars.immediateRender !== !1) && (this._time = -h, this.render(-this._delay)); + }, !0), + I = function (e) { + return e.length && e !== t && e[0] && (e[0] === t || e[0].nodeType && e[0].style && !e.nodeType); + }, + E = function (t, e) { + var i, + s = {}; + for (i in t) j[i] || i in e && "transform" !== i && "x" !== i && "y" !== i && "width" !== i && "height" !== i && "className" !== i && "border" !== i || !(!L[i] || L[i] && L[i]._autoCSS) || (s[i] = t[i], delete t[i]); + t.css = s; + }; + n = D.prototype = new x(), n.constructor = D, n.kill()._gc = !1, n.ratio = 0, n._firstPT = n._targets = n._overwrittenProps = n._startAt = null, n._notifyPluginsOfEnabled = n._lazy = !1, D.version = "1.12.1", D.defaultEase = n._ease = new T(null, null, 1, 1), D.defaultOverwrite = "auto", D.ticker = r, D.autoSleep = !0, D.lagSmoothing = function (t, e) { + r.lagSmoothing(t, e); + }, D.selector = t.$ || t.jQuery || function (e) { + return t.$ ? (D.selector = t.$, t.$(e)) : t.document ? t.document.getElementById("#" === e.charAt(0) ? e.substr(1) : e) : e; + }; + var z = [], + O = {}, + N = D._internals = { + isArray: m, + isSelector: I, + lazyTweens: z + }, + L = D._plugins = {}, + U = N.tweenLookup = {}, + F = 0, + j = N.reservedProps = { + ease: 1, + delay: 1, + overwrite: 1, + onComplete: 1, + onCompleteParams: 1, + onCompleteScope: 1, + useFrames: 1, + runBackwards: 1, + startAt: 1, + onUpdate: 1, + onUpdateParams: 1, + onUpdateScope: 1, + onStart: 1, + onStartParams: 1, + onStartScope: 1, + onReverseComplete: 1, + onReverseCompleteParams: 1, + onReverseCompleteScope: 1, + onRepeat: 1, + onRepeatParams: 1, + onRepeatScope: 1, + easeParams: 1, + yoyo: 1, + immediateRender: 1, + repeat: 1, + repeatDelay: 1, + data: 1, + paused: 1, + reversed: 1, + autoCSS: 1, + lazy: 1 + }, + G = { + none: 0, + all: 1, + auto: 2, + concurrent: 3, + allOnStart: 4, + preexisting: 5, + "true": 1, + "false": 0 + }, + Q = x._rootFramesTimeline = new R(), + B = x._rootTimeline = new R(), + q = function () { + var t = z.length; + for (O = {}; --t > -1;) i = z[t], i && i._lazy !== !1 && (i.render(i._lazy, !1, !0), i._lazy = !1); + z.length = 0; + }; + B._startTime = r.time, Q._startTime = r.frame, B._active = Q._active = !0, setTimeout(q, 1), x._updateRoot = D.render = function () { + var t, e, i; + if (z.length && q(), B.render((r.time - B._startTime) * B._timeScale, !1, !1), Q.render((r.frame - Q._startTime) * Q._timeScale, !1, !1), z.length && q(), !(r.frame % 120)) { + for (i in U) { + for (e = U[i].tweens, t = e.length; --t > -1;) e[t]._gc && e.splice(t, 1); + 0 === e.length && delete U[i]; + } + if (i = B._first, (!i || i._paused) && D.autoSleep && !Q._first && 1 === r._listeners.tick.length) { + for (; i && i._paused;) i = i._next; + i || r.sleep(); + } + } + }, r.addEventListener("tick", x._updateRoot); + var M = function (t, e, i) { + var s, + n, + r = t._gsTweenID; + if (U[r || (t._gsTweenID = r = "t" + F++)] || (U[r] = { + target: t, + tweens: [] + }), e && (s = U[r].tweens, s[n = s.length] = e, i)) for (; --n > -1;) s[n] === e && s.splice(n, 1); + return U[r].tweens; + }, + $ = function (t, e, i, s, n) { + var r, a, o, l; + if (1 === s || s >= 4) { + for (l = n.length, r = 0; l > r; r++) if ((o = n[r]) !== e) o._gc || o._enabled(!1, !1) && (a = !0);else if (5 === s) break; + return a; + } + var _, + u = e._startTime + h, + m = [], + f = 0, + p = 0 === e._duration; + for (r = n.length; --r > -1;) (o = n[r]) === e || o._gc || o._paused || (o._timeline !== e._timeline ? (_ = _ || K(e, 0, p), 0 === K(o, _, p) && (m[f++] = o)) : u >= o._startTime && o._startTime + o.totalDuration() / o._timeScale > u && ((p || !o._initted) && 2e-10 >= u - o._startTime || (m[f++] = o))); + for (r = f; --r > -1;) o = m[r], 2 === s && o._kill(i, t) && (a = !0), (2 !== s || !o._firstPT && o._initted) && o._enabled(!1, !1) && (a = !0); + return a; + }, + K = function (t, e, i) { + for (var s = t._timeline, n = s._timeScale, r = t._startTime; s._timeline;) { + if (r += s._startTime, n *= s._timeScale, s._paused) return -100; + s = s._timeline; + } + return r /= n, r > e ? r - e : i && r === e || !t._initted && 2 * h > r - e ? h : (r += t.totalDuration() / t._timeScale / n) > e + h ? 0 : r - e - h; + }; + n._init = function () { + var t, + e, + i, + s, + n, + r = this.vars, + a = this._overwrittenProps, + o = this._duration, + l = !!r.immediateRender, + h = r.ease; + if (r.startAt) { + this._startAt && (this._startAt.render(-1, !0), this._startAt.kill()), n = {}; + for (s in r.startAt) n[s] = r.startAt[s]; + if (n.overwrite = !1, n.immediateRender = !0, n.lazy = l && r.lazy !== !1, n.startAt = n.delay = null, this._startAt = D.to(this.target, 0, n), l) if (this._time > 0) this._startAt = null;else if (0 !== o) return; + } else if (r.runBackwards && 0 !== o) if (this._startAt) this._startAt.render(-1, !0), this._startAt.kill(), this._startAt = null;else { + i = {}; + for (s in r) j[s] && "autoCSS" !== s || (i[s] = r[s]); + if (i.overwrite = 0, i.data = "isFromStart", i.lazy = l && r.lazy !== !1, i.immediateRender = l, this._startAt = D.to(this.target, 0, i), l) { + if (0 === this._time) return; + } else this._startAt._init(), this._startAt._enabled(!1); + } + if (this._ease = h ? h instanceof T ? r.easeParams instanceof Array ? h.config.apply(h, r.easeParams) : h : "function" == typeof h ? new T(h, r.easeParams) : y[h] || D.defaultEase : D.defaultEase, this._easeType = this._ease._type, this._easePower = this._ease._power, this._firstPT = null, this._targets) for (t = this._targets.length; --t > -1;) this._initProps(this._targets[t], this._propLookup[t] = {}, this._siblings[t], a ? a[t] : null) && (e = !0);else e = this._initProps(this.target, this._propLookup, this._siblings, a); + if (e && D._onPluginEvent("_onInitAllProps", this), a && (this._firstPT || "function" != typeof this.target && this._enabled(!1, !1)), r.runBackwards) for (i = this._firstPT; i;) i.s += i.c, i.c = -i.c, i = i._next; + this._onUpdate = r.onUpdate, this._initted = !0; + }, n._initProps = function (e, i, s, n) { + var r, a, o, l, h, _; + if (null == e) return !1; + O[e._gsTweenID] && q(), this.vars.css || e.style && e !== t && e.nodeType && L.css && this.vars.autoCSS !== !1 && E(this.vars, e); + for (r in this.vars) { + if (_ = this.vars[r], j[r]) _ && (_ instanceof Array || _.push && m(_)) && -1 !== _.join("").indexOf("{self}") && (this.vars[r] = _ = this._swapSelfInParams(_, this));else if (L[r] && (l = new L[r]())._onInitTween(e, this.vars[r], this)) { + for (this._firstPT = h = { + _next: this._firstPT, + t: l, + p: "setRatio", + s: 0, + c: 1, + f: !0, + n: r, + pg: !0, + pr: l._priority + }, a = l._overwriteProps.length; --a > -1;) i[l._overwriteProps[a]] = this._firstPT; + (l._priority || l._onInitAllProps) && (o = !0), (l._onDisable || l._onEnable) && (this._notifyPluginsOfEnabled = !0); + } else this._firstPT = i[r] = h = { + _next: this._firstPT, + t: e, + p: r, + f: "function" == typeof e[r], + n: r, + pg: !1, + pr: 0 + }, h.s = h.f ? e[r.indexOf("set") || "function" != typeof e["get" + r.substr(3)] ? r : "get" + r.substr(3)]() : parseFloat(e[r]), h.c = "string" == typeof _ && "=" === _.charAt(1) ? parseInt(_.charAt(0) + "1", 10) * Number(_.substr(2)) : Number(_) - h.s || 0; + h && h._next && (h._next._prev = h); + } + return n && this._kill(n, e) ? this._initProps(e, i, s, n) : this._overwrite > 1 && this._firstPT && s.length > 1 && $(e, this, i, this._overwrite, s) ? (this._kill(i, e), this._initProps(e, i, s, n)) : (this._firstPT && (this.vars.lazy !== !1 && this._duration || this.vars.lazy && !this._duration) && (O[e._gsTweenID] = !0), o); + }, n.render = function (t, e, i) { + var s, + n, + r, + a, + o = this._time, + l = this._duration, + _ = this._rawPrevTime; + if (t >= l) this._totalTime = this._time = l, this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1, this._reversed || (s = !0, n = "onComplete"), 0 === l && (this._initted || !this.vars.lazy || i) && (this._startTime === this._timeline._duration && (t = 0), (0 === t || 0 > _ || _ === h) && _ !== t && (i = !0, _ > h && (n = "onReverseComplete")), this._rawPrevTime = a = !e || t || _ === t ? t : h);else if (1e-7 > t) this._totalTime = this._time = 0, this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0, (0 !== o || 0 === l && _ > 0 && _ !== h) && (n = "onReverseComplete", s = this._reversed), 0 > t ? (this._active = !1, 0 === l && (this._initted || !this.vars.lazy || i) && (_ >= 0 && (i = !0), this._rawPrevTime = a = !e || t || _ === t ? t : h)) : this._initted || (i = !0);else if (this._totalTime = this._time = t, this._easeType) { + var u = t / l, + m = this._easeType, + f = this._easePower; + (1 === m || 3 === m && u >= .5) && (u = 1 - u), 3 === m && (u *= 2), 1 === f ? u *= u : 2 === f ? u *= u * u : 3 === f ? u *= u * u * u : 4 === f && (u *= u * u * u * u), this.ratio = 1 === m ? 1 - u : 2 === m ? u : .5 > t / l ? u / 2 : 1 - u / 2; + } else this.ratio = this._ease.getRatio(t / l); + if (this._time !== o || i) { + if (!this._initted) { + if (this._init(), !this._initted || this._gc) return; + if (!i && this._firstPT && (this.vars.lazy !== !1 && this._duration || this.vars.lazy && !this._duration)) return this._time = this._totalTime = o, this._rawPrevTime = _, z.push(this), this._lazy = t, void 0; + this._time && !s ? this.ratio = this._ease.getRatio(this._time / l) : s && this._ease._calcEnd && (this.ratio = this._ease.getRatio(0 === this._time ? 0 : 1)); + } + for (this._lazy !== !1 && (this._lazy = !1), this._active || !this._paused && this._time !== o && t >= 0 && (this._active = !0), 0 === o && (this._startAt && (t >= 0 ? this._startAt.render(t, e, i) : n || (n = "_dummyGS")), this.vars.onStart && (0 !== this._time || 0 === l) && (e || this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || g))), r = this._firstPT; r;) r.f ? r.t[r.p](r.c * this.ratio + r.s) : r.t[r.p] = r.c * this.ratio + r.s, r = r._next; + this._onUpdate && (0 > t && this._startAt && this._startTime && this._startAt.render(t, e, i), e || (this._time !== o || s) && this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || g)), n && (this._gc || (0 > t && this._startAt && !this._onUpdate && this._startTime && this._startAt.render(t, e, i), s && (this._timeline.autoRemoveChildren && this._enabled(!1, !1), this._active = !1), !e && this.vars[n] && this.vars[n].apply(this.vars[n + "Scope"] || this, this.vars[n + "Params"] || g), 0 === l && this._rawPrevTime === h && a !== h && (this._rawPrevTime = 0))); + } + }, n._kill = function (t, e) { + if ("all" === t && (t = null), null == t && (null == e || e === this.target)) return this._lazy = !1, this._enabled(!1, !1); + e = "string" != typeof e ? e || this._targets || this.target : D.selector(e) || e; + var i, s, n, r, a, o, l, h; + if ((m(e) || I(e)) && "number" != typeof e[0]) for (i = e.length; --i > -1;) this._kill(t, e[i]) && (o = !0);else { + if (this._targets) { + for (i = this._targets.length; --i > -1;) if (e === this._targets[i]) { + a = this._propLookup[i] || {}, this._overwrittenProps = this._overwrittenProps || [], s = this._overwrittenProps[i] = t ? this._overwrittenProps[i] || {} : "all"; + break; + } + } else { + if (e !== this.target) return !1; + a = this._propLookup, s = this._overwrittenProps = t ? this._overwrittenProps || {} : "all"; + } + if (a) { + l = t || a, h = t !== s && "all" !== s && t !== a && ("object" != typeof t || !t._tempKill); + for (n in l) (r = a[n]) && (r.pg && r.t._kill(l) && (o = !0), r.pg && 0 !== r.t._overwriteProps.length || (r._prev ? r._prev._next = r._next : r === this._firstPT && (this._firstPT = r._next), r._next && (r._next._prev = r._prev), r._next = r._prev = null), delete a[n]), h && (s[n] = 1); + !this._firstPT && this._initted && this._enabled(!1, !1); + } + } + return o; + }, n.invalidate = function () { + return this._notifyPluginsOfEnabled && D._onPluginEvent("_onDisable", this), this._firstPT = null, this._overwrittenProps = null, this._onUpdate = null, this._startAt = null, this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = !1, this._propLookup = this._targets ? {} : [], this; + }, n._enabled = function (t, e) { + if (a || r.wake(), t && this._gc) { + var i, + s = this._targets; + if (s) for (i = s.length; --i > -1;) this._siblings[i] = M(s[i], this, !0);else this._siblings = M(this.target, this, !0); + } + return x.prototype._enabled.call(this, t, e), this._notifyPluginsOfEnabled && this._firstPT ? D._onPluginEvent(t ? "_onEnable" : "_onDisable", this) : !1; + }, D.to = function (t, e, i) { + return new D(t, e, i); + }, D.from = function (t, e, i) { + return i.runBackwards = !0, i.immediateRender = 0 != i.immediateRender, new D(t, e, i); + }, D.fromTo = function (t, e, i, s) { + return s.startAt = i, s.immediateRender = 0 != s.immediateRender && 0 != i.immediateRender, new D(t, e, s); + }, D.delayedCall = function (t, e, i, s, n) { + return new D(e, 0, { + delay: t, + onComplete: e, + onCompleteParams: i, + onCompleteScope: s, + onReverseComplete: e, + onReverseCompleteParams: i, + onReverseCompleteScope: s, + immediateRender: !1, + useFrames: n, + overwrite: 0 + }); + }, D.set = function (t, e) { + return new D(t, 0, e); + }, D.getTweensOf = function (t, e) { + if (null == t) return []; + t = "string" != typeof t ? t : D.selector(t) || t; + var i, s, n, r; + if ((m(t) || I(t)) && "number" != typeof t[0]) { + for (i = t.length, s = []; --i > -1;) s = s.concat(D.getTweensOf(t[i], e)); + for (i = s.length; --i > -1;) for (r = s[i], n = i; --n > -1;) r === s[n] && s.splice(i, 1); + } else for (s = M(t).concat(), i = s.length; --i > -1;) (s[i]._gc || e && !s[i].isActive()) && s.splice(i, 1); + return s; + }, D.killTweensOf = D.killDelayedCallsTo = function (t, e, i) { + "object" == typeof e && (i = e, e = !1); + for (var s = D.getTweensOf(t, e), n = s.length; --n > -1;) s[n]._kill(i, t); + }; + var H = d("plugins.TweenPlugin", function (t, e) { + this._overwriteProps = (t || "").split(","), this._propName = this._overwriteProps[0], this._priority = e || 0, this._super = H.prototype; + }, !0); + if (n = H.prototype, H.version = "1.10.1", H.API = 2, n._firstPT = null, n._addTween = function (t, e, i, s, n, r) { + var a, o; + return null != s && (a = "number" == typeof s || "=" !== s.charAt(1) ? Number(s) - i : parseInt(s.charAt(0) + "1", 10) * Number(s.substr(2))) ? (this._firstPT = o = { + _next: this._firstPT, + t: t, + p: e, + s: i, + c: a, + f: "function" == typeof t[e], + n: n || e, + r: r + }, o._next && (o._next._prev = o), o) : void 0; + }, n.setRatio = function (t) { + for (var e, i = this._firstPT, s = 1e-6; i;) e = i.c * t + i.s, i.r ? e = Math.round(e) : s > e && e > -s && (e = 0), i.f ? i.t[i.p](e) : i.t[i.p] = e, i = i._next; + }, n._kill = function (t) { + var e, + i = this._overwriteProps, + s = this._firstPT; + if (null != t[this._propName]) this._overwriteProps = [];else for (e = i.length; --e > -1;) null != t[i[e]] && i.splice(e, 1); + for (; s;) null != t[s.n] && (s._next && (s._next._prev = s._prev), s._prev ? (s._prev._next = s._next, s._prev = null) : this._firstPT === s && (this._firstPT = s._next)), s = s._next; + return !1; + }, n._roundProps = function (t, e) { + for (var i = this._firstPT; i;) (t[this._propName] || null != i.n && t[i.n.split(this._propName + "_").join("")]) && (i.r = e), i = i._next; + }, D._onPluginEvent = function (t, e) { + var i, + s, + n, + r, + a, + o = e._firstPT; + if ("_onInitAllProps" === t) { + for (; o;) { + for (a = o._next, s = n; s && s.pr > o.pr;) s = s._next; + (o._prev = s ? s._prev : r) ? o._prev._next = o : n = o, (o._next = s) ? s._prev = o : r = o, o = a; + } + o = e._firstPT = n; + } + for (; o;) o.pg && "function" == typeof o.t[t] && o.t[t]() && (i = !0), o = o._next; + return i; + }, H.activate = function (t) { + for (var e = t.length; --e > -1;) t[e].API === H.API && (L[new t[e]()._propName] = t[e]); + return !0; + }, c.plugin = function (t) { + if (!(t && t.propName && t.init && t.API)) throw "illegal plugin definition."; + var e, + i = t.propName, + s = t.priority || 0, + n = t.overwriteProps, + r = { + init: "_onInitTween", + set: "setRatio", + kill: "_kill", + round: "_roundProps", + initAll: "_onInitAllProps" + }, + a = d("plugins." + i.charAt(0).toUpperCase() + i.substr(1) + "Plugin", function () { + H.call(this, i, s), this._overwriteProps = n || []; + }, t.global === !0), + o = a.prototype = new H(i); + o.constructor = a, a.API = t.API; + for (e in r) "function" == typeof t[e] && (o[r[e]] = t[e]); + return a.version = t.version, H.activate([a]), a; + }, i = t._gsQueue) { + for (s = 0; i.length > s; s++) i[s](); + for (n in f) f[n].func || t.console.log("GSAP encountered missing dependency: com.greensock." + n); + } + a = !1; + } +})(window); + +},{}],11:[function(require,module,exports){ +"use strict"; + +/*! + * VERSION: beta 1.9.3 + * DATE: 2013-04-02 + * UPDATES AND DOCS AT: http://www.greensock.com + * + * @license Copyright (c) 2008-2014, GreenSock. All rights reserved. + * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for + * Club GreenSock members, the software agreement that was issued with your membership. + * + * @author: Jack Doyle, jack@greensock.com + **/ +(window._gsQueue || (window._gsQueue = [])).push(function () { + "use strict"; + + window._gsDefine("easing.Back", ["easing.Ease"], function (t) { + var e, + i, + s, + r = window.GreenSockGlobals || window, + n = r.com.greensock, + a = 2 * Math.PI, + o = Math.PI / 2, + h = n._class, + l = function (e, i) { + var s = h("easing." + e, function () {}, !0), + r = s.prototype = new t(); + return r.constructor = s, r.getRatio = i, s; + }, + _ = t.register || function () {}, + u = function (t, e, i, s) { + var r = h("easing." + t, { + easeOut: new e(), + easeIn: new i(), + easeInOut: new s() + }, !0); + return _(r, t), r; + }, + c = function (t, e, i) { + this.t = t, this.v = e, i && (this.next = i, i.prev = this, this.c = i.v - e, this.gap = i.t - t); + }, + f = function (e, i) { + var s = h("easing." + e, function (t) { + this._p1 = t || 0 === t ? t : 1.70158, this._p2 = 1.525 * this._p1; + }, !0), + r = s.prototype = new t(); + return r.constructor = s, r.getRatio = i, r.config = function (t) { + return new s(t); + }, s; + }, + p = u("Back", f("BackOut", function (t) { + return (t -= 1) * t * ((this._p1 + 1) * t + this._p1) + 1; + }), f("BackIn", function (t) { + return t * t * ((this._p1 + 1) * t - this._p1); + }), f("BackInOut", function (t) { + return 1 > (t *= 2) ? .5 * t * t * ((this._p2 + 1) * t - this._p2) : .5 * ((t -= 2) * t * ((this._p2 + 1) * t + this._p2) + 2); + })), + m = h("easing.SlowMo", function (t, e, i) { + e = e || 0 === e ? e : .7, null == t ? t = .7 : t > 1 && (t = 1), this._p = 1 !== t ? e : 0, this._p1 = (1 - t) / 2, this._p2 = t, this._p3 = this._p1 + this._p2, this._calcEnd = i === !0; + }, !0), + d = m.prototype = new t(); + return d.constructor = m, d.getRatio = function (t) { + var e = t + (.5 - t) * this._p; + return this._p1 > t ? this._calcEnd ? 1 - (t = 1 - t / this._p1) * t : e - (t = 1 - t / this._p1) * t * t * t * e : t > this._p3 ? this._calcEnd ? 1 - (t = (t - this._p3) / this._p1) * t : e + (t - e) * (t = (t - this._p3) / this._p1) * t * t * t : this._calcEnd ? 1 : e; + }, m.ease = new m(.7, .7), d.config = m.config = function (t, e, i) { + return new m(t, e, i); + }, e = h("easing.SteppedEase", function (t) { + t = t || 1, this._p1 = 1 / t, this._p2 = t + 1; + }, !0), d = e.prototype = new t(), d.constructor = e, d.getRatio = function (t) { + return 0 > t ? t = 0 : t >= 1 && (t = .999999999), (this._p2 * t >> 0) * this._p1; + }, d.config = e.config = function (t) { + return new e(t); + }, i = h("easing.RoughEase", function (e) { + e = e || {}; + for (var i, s, r, n, a, o, h = e.taper || "none", l = [], _ = 0, u = 0 | (e.points || 20), f = u, p = e.randomize !== !1, m = e.clamp === !0, d = e.template instanceof t ? e.template : null, g = "number" == typeof e.strength ? .4 * e.strength : .4; --f > -1;) i = p ? Math.random() : 1 / u * f, s = d ? d.getRatio(i) : i, "none" === h ? r = g : "out" === h ? (n = 1 - i, r = n * n * g) : "in" === h ? r = i * i * g : .5 > i ? (n = 2 * i, r = .5 * n * n * g) : (n = 2 * (1 - i), r = .5 * n * n * g), p ? s += Math.random() * r - .5 * r : f % 2 ? s += .5 * r : s -= .5 * r, m && (s > 1 ? s = 1 : 0 > s && (s = 0)), l[_++] = { + x: i, + y: s + }; + for (l.sort(function (t, e) { + return t.x - e.x; + }), o = new c(1, 1, null), f = u; --f > -1;) a = l[f], o = new c(a.x, a.y, o); + this._prev = new c(0, 0, 0 !== o.t ? o : o.next); + }, !0), d = i.prototype = new t(), d.constructor = i, d.getRatio = function (t) { + var e = this._prev; + if (t > e.t) { + for (; e.next && t >= e.t;) e = e.next; + e = e.prev; + } else for (; e.prev && e.t >= t;) e = e.prev; + return this._prev = e, e.v + (t - e.t) / e.gap * e.c; + }, d.config = function (t) { + return new i(t); + }, i.ease = new i(), u("Bounce", l("BounceOut", function (t) { + return 1 / 2.75 > t ? 7.5625 * t * t : 2 / 2.75 > t ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : 2.5 / 2.75 > t ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; + }), l("BounceIn", function (t) { + return 1 / 2.75 > (t = 1 - t) ? 1 - 7.5625 * t * t : 2 / 2.75 > t ? 1 - (7.5625 * (t -= 1.5 / 2.75) * t + .75) : 2.5 / 2.75 > t ? 1 - (7.5625 * (t -= 2.25 / 2.75) * t + .9375) : 1 - (7.5625 * (t -= 2.625 / 2.75) * t + .984375); + }), l("BounceInOut", function (t) { + var e = .5 > t; + return t = e ? 1 - 2 * t : 2 * t - 1, t = 1 / 2.75 > t ? 7.5625 * t * t : 2 / 2.75 > t ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : 2.5 / 2.75 > t ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375, e ? .5 * (1 - t) : .5 * t + .5; + })), u("Circ", l("CircOut", function (t) { + return Math.sqrt(1 - (t -= 1) * t); + }), l("CircIn", function (t) { + return -(Math.sqrt(1 - t * t) - 1); + }), l("CircInOut", function (t) { + return 1 > (t *= 2) ? -.5 * (Math.sqrt(1 - t * t) - 1) : .5 * (Math.sqrt(1 - (t -= 2) * t) + 1); + })), s = function (e, i, s) { + var r = h("easing." + e, function (t, e) { + this._p1 = t || 1, this._p2 = e || s, this._p3 = this._p2 / a * (Math.asin(1 / this._p1) || 0); + }, !0), + n = r.prototype = new t(); + return n.constructor = r, n.getRatio = i, n.config = function (t, e) { + return new r(t, e); + }, r; + }, u("Elastic", s("ElasticOut", function (t) { + return this._p1 * Math.pow(2, -10 * t) * Math.sin((t - this._p3) * a / this._p2) + 1; + }, .3), s("ElasticIn", function (t) { + return -(this._p1 * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - this._p3) * a / this._p2)); + }, .3), s("ElasticInOut", function (t) { + return 1 > (t *= 2) ? -.5 * this._p1 * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - this._p3) * a / this._p2) : .5 * this._p1 * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - this._p3) * a / this._p2) + 1; + }, .45)), u("Expo", l("ExpoOut", function (t) { + return 1 - Math.pow(2, -10 * t); + }), l("ExpoIn", function (t) { + return Math.pow(2, 10 * (t - 1)) - .001; + }), l("ExpoInOut", function (t) { + return 1 > (t *= 2) ? .5 * Math.pow(2, 10 * (t - 1)) : .5 * (2 - Math.pow(2, -10 * (t - 1))); + })), u("Sine", l("SineOut", function (t) { + return Math.sin(t * o); + }), l("SineIn", function (t) { + return -Math.cos(t * o) + 1; + }), l("SineInOut", function (t) { + return -.5 * (Math.cos(Math.PI * t) - 1); + })), h("easing.EaseLookup", { + find: function (e) { + return t.map[e]; + } + }, !0), _(r.SlowMo, "SlowMo", "ease,"), _(i, "RoughEase", "ease,"), _(e, "SteppedEase", "ease,"), p; + }, !0); +}), window._gsDefine && window._gsQueue.pop()(); + +},{}],12:[function(require,module,exports){ +"use strict"; + +/*! + * VERSION: 1.12.1 + * DATE: 2014-06-26 + * UPDATES AND DOCS AT: http://www.greensock.com + * + * @license Copyright (c) 2008-2014, GreenSock. All rights reserved. + * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for + * Club GreenSock members, the software agreement that was issued with your membership. + * + * @author: Jack Doyle, jack@greensock.com + */ +(window._gsQueue || (window._gsQueue = [])).push(function () { + "use strict"; + + window._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin", "TweenLite"], function (t, e) { + var i, + r, + s, + n, + a = function () { + t.call(this, "css"), this._overwriteProps.length = 0, this.setRatio = a.prototype.setRatio; + }, + o = {}, + l = a.prototype = new t("css"); + l.constructor = a, a.version = "1.12.1", a.API = 2, a.defaultTransformPerspective = 0, a.defaultSkewType = "compensated", l = "px", a.suffixMap = { + top: l, + right: l, + bottom: l, + left: l, + width: l, + height: l, + fontSize: l, + padding: l, + margin: l, + perspective: l, + lineHeight: "" + }; + var h, + u, + f, + _, + p, + c, + d = /(?:\d|\-\d|\.\d|\-\.\d)+/g, + m = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g, + g = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, + v = /[^\d\-\.]/g, + y = /(?:\d|\-|\+|=|#|\.)*/g, + T = /opacity *= *([^)]*)/i, + w = /opacity:([^;]*)/i, + x = /alpha\(opacity *=.+?\)/i, + b = /^(rgb|hsl)/, + P = /([A-Z])/g, + S = /-([a-z])/gi, + C = /(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi, + R = function (t, e) { + return e.toUpperCase(); + }, + k = /(?:Left|Right|Width)/i, + A = /(M11|M12|M21|M22)=[\d\-\.e]+/gi, + O = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i, + D = /,(?=[^\)]*(?:\(|$))/gi, + M = Math.PI / 180, + L = 180 / Math.PI, + N = {}, + X = document, + z = X.createElement("div"), + I = X.createElement("img"), + E = a._internals = { + _specialProps: o + }, + F = navigator.userAgent, + Y = function () { + var t, + e = F.indexOf("Android"), + i = X.createElement("div"); + return f = -1 !== F.indexOf("Safari") && -1 === F.indexOf("Chrome") && (-1 === e || Number(F.substr(e + 8, 1)) > 3), p = f && 6 > Number(F.substr(F.indexOf("Version/") + 8, 1)), _ = -1 !== F.indexOf("Firefox"), /MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(F) && (c = parseFloat(RegExp.$1)), i.innerHTML = "a", t = i.getElementsByTagName("a")[0], t ? /^0.55/.test(t.style.opacity) : !1; + }(), + B = function (t) { + return T.test("string" == typeof t ? t : (t.currentStyle ? t.currentStyle.filter : t.style.filter) || "") ? parseFloat(RegExp.$1) / 100 : 1; + }, + U = function (t) { + window.console && console.log(t); + }, + W = "", + j = "", + V = function (t, e) { + e = e || z; + var i, + r, + s = e.style; + if (void 0 !== s[t]) return t; + for (t = t.charAt(0).toUpperCase() + t.substr(1), i = ["O", "Moz", "ms", "Ms", "Webkit"], r = 5; --r > -1 && void 0 === s[i[r] + t];); + return r >= 0 ? (j = 3 === r ? "ms" : i[r], W = "-" + j.toLowerCase() + "-", j + t) : null; + }, + H = X.defaultView ? X.defaultView.getComputedStyle : function () {}, + q = a.getStyle = function (t, e, i, r, s) { + var n; + return Y || "opacity" !== e ? (!r && t.style[e] ? n = t.style[e] : (i = i || H(t)) ? n = i[e] || i.getPropertyValue(e) || i.getPropertyValue(e.replace(P, "-$1").toLowerCase()) : t.currentStyle && (n = t.currentStyle[e]), null == s || n && "none" !== n && "auto" !== n && "auto auto" !== n ? n : s) : B(t); + }, + Q = E.convertToPixels = function (t, i, r, s, n) { + if ("px" === s || !s) return r; + if ("auto" === s || !r) return 0; + var o, + l, + h, + u = k.test(i), + f = t, + _ = z.style, + p = 0 > r; + if (p && (r = -r), "%" === s && -1 !== i.indexOf("border")) o = r / 100 * (u ? t.clientWidth : t.clientHeight);else { + if (_.cssText = "border:0 solid red;position:" + q(t, "position") + ";line-height:0;", "%" !== s && f.appendChild) _[u ? "borderLeftWidth" : "borderTopWidth"] = r + s;else { + if (f = t.parentNode || X.body, l = f._gsCache, h = e.ticker.frame, l && u && l.time === h) return l.width * r / 100; + _[u ? "width" : "height"] = r + s; + } + f.appendChild(z), o = parseFloat(z[u ? "offsetWidth" : "offsetHeight"]), f.removeChild(z), u && "%" === s && a.cacheWidths !== !1 && (l = f._gsCache = f._gsCache || {}, l.time = h, l.width = 100 * (o / r)), 0 !== o || n || (o = Q(t, i, r, s, !0)); + } + return p ? -o : o; + }, + Z = E.calculateOffset = function (t, e, i) { + if ("absolute" !== q(t, "position", i)) return 0; + var r = "left" === e ? "Left" : "Top", + s = q(t, "margin" + r, i); + return t["offset" + r] - (Q(t, e, parseFloat(s), s.replace(y, "")) || 0); + }, + $ = function (t, e) { + var i, + r, + s = {}; + if (e = e || H(t, null)) { + if (i = e.length) for (; --i > -1;) s[e[i].replace(S, R)] = e.getPropertyValue(e[i]);else for (i in e) s[i] = e[i]; + } else if (e = t.currentStyle || t.style) for (i in e) "string" == typeof i && void 0 === s[i] && (s[i.replace(S, R)] = e[i]); + return Y || (s.opacity = B(t)), r = Pe(t, e, !1), s.rotation = r.rotation, s.skewX = r.skewX, s.scaleX = r.scaleX, s.scaleY = r.scaleY, s.x = r.x, s.y = r.y, xe && (s.z = r.z, s.rotationX = r.rotationX, s.rotationY = r.rotationY, s.scaleZ = r.scaleZ), s.filters && delete s.filters, s; + }, + G = function (t, e, i, r, s) { + var n, + a, + o, + l = {}, + h = t.style; + for (a in i) "cssText" !== a && "length" !== a && isNaN(a) && (e[a] !== (n = i[a]) || s && s[a]) && -1 === a.indexOf("Origin") && ("number" == typeof n || "string" == typeof n) && (l[a] = "auto" !== n || "left" !== a && "top" !== a ? "" !== n && "auto" !== n && "none" !== n || "string" != typeof e[a] || "" === e[a].replace(v, "") ? n : 0 : Z(t, a), void 0 !== h[a] && (o = new fe(h, a, h[a], o))); + if (r) for (a in r) "className" !== a && (l[a] = r[a]); + return { + difs: l, + firstMPT: o + }; + }, + K = { + width: ["Left", "Right"], + height: ["Top", "Bottom"] + }, + J = ["marginLeft", "marginRight", "marginTop", "marginBottom"], + te = function (t, e, i) { + var r = parseFloat("width" === e ? t.offsetWidth : t.offsetHeight), + s = K[e], + n = s.length; + for (i = i || H(t, null); --n > -1;) r -= parseFloat(q(t, "padding" + s[n], i, !0)) || 0, r -= parseFloat(q(t, "border" + s[n] + "Width", i, !0)) || 0; + return r; + }, + ee = function (t, e) { + (null == t || "" === t || "auto" === t || "auto auto" === t) && (t = "0 0"); + var i = t.split(" "), + r = -1 !== t.indexOf("left") ? "0%" : -1 !== t.indexOf("right") ? "100%" : i[0], + s = -1 !== t.indexOf("top") ? "0%" : -1 !== t.indexOf("bottom") ? "100%" : i[1]; + return null == s ? s = "0" : "center" === s && (s = "50%"), ("center" === r || isNaN(parseFloat(r)) && -1 === (r + "").indexOf("=")) && (r = "50%"), e && (e.oxp = -1 !== r.indexOf("%"), e.oyp = -1 !== s.indexOf("%"), e.oxr = "=" === r.charAt(1), e.oyr = "=" === s.charAt(1), e.ox = parseFloat(r.replace(v, "")), e.oy = parseFloat(s.replace(v, ""))), r + " " + s + (i.length > 2 ? " " + i[2] : ""); + }, + ie = function (t, e) { + return "string" == typeof t && "=" === t.charAt(1) ? parseInt(t.charAt(0) + "1", 10) * parseFloat(t.substr(2)) : parseFloat(t) - parseFloat(e); + }, + re = function (t, e) { + return null == t ? e : "string" == typeof t && "=" === t.charAt(1) ? parseInt(t.charAt(0) + "1", 10) * Number(t.substr(2)) + e : parseFloat(t); + }, + se = function (t, e, i, r) { + var s, + n, + a, + o, + l = 1e-6; + return null == t ? o = e : "number" == typeof t ? o = t : (s = 360, n = t.split("_"), a = Number(n[0].replace(v, "")) * (-1 === t.indexOf("rad") ? 1 : L) - ("=" === t.charAt(1) ? 0 : e), n.length && (r && (r[i] = e + a), -1 !== t.indexOf("short") && (a %= s, a !== a % (s / 2) && (a = 0 > a ? a + s : a - s)), -1 !== t.indexOf("_cw") && 0 > a ? a = (a + 9999999999 * s) % s - (0 | a / s) * s : -1 !== t.indexOf("ccw") && a > 0 && (a = (a - 9999999999 * s) % s - (0 | a / s) * s)), o = e + a), l > o && o > -l && (o = 0), o; + }, + ne = { + aqua: [0, 255, 255], + lime: [0, 255, 0], + silver: [192, 192, 192], + black: [0, 0, 0], + maroon: [128, 0, 0], + teal: [0, 128, 128], + blue: [0, 0, 255], + navy: [0, 0, 128], + white: [255, 255, 255], + fuchsia: [255, 0, 255], + olive: [128, 128, 0], + yellow: [255, 255, 0], + orange: [255, 165, 0], + gray: [128, 128, 128], + purple: [128, 0, 128], + green: [0, 128, 0], + red: [255, 0, 0], + pink: [255, 192, 203], + cyan: [0, 255, 255], + transparent: [255, 255, 255, 0] + }, + ae = function (t, e, i) { + return t = 0 > t ? t + 1 : t > 1 ? t - 1 : t, 0 | 255 * (1 > 6 * t ? e + 6 * (i - e) * t : .5 > t ? i : 2 > 3 * t ? e + 6 * (i - e) * (2 / 3 - t) : e) + .5; + }, + oe = function (t) { + var e, i, r, s, n, a; + return t && "" !== t ? "number" == typeof t ? [t >> 16, 255 & t >> 8, 255 & t] : ("," === t.charAt(t.length - 1) && (t = t.substr(0, t.length - 1)), ne[t] ? ne[t] : "#" === t.charAt(0) ? (4 === t.length && (e = t.charAt(1), i = t.charAt(2), r = t.charAt(3), t = "#" + e + e + i + i + r + r), t = parseInt(t.substr(1), 16), [t >> 16, 255 & t >> 8, 255 & t]) : "hsl" === t.substr(0, 3) ? (t = t.match(d), s = Number(t[0]) % 360 / 360, n = Number(t[1]) / 100, a = Number(t[2]) / 100, i = .5 >= a ? a * (n + 1) : a + n - a * n, e = 2 * a - i, t.length > 3 && (t[3] = Number(t[3])), t[0] = ae(s + 1 / 3, e, i), t[1] = ae(s, e, i), t[2] = ae(s - 1 / 3, e, i), t) : (t = t.match(d) || ne.transparent, t[0] = Number(t[0]), t[1] = Number(t[1]), t[2] = Number(t[2]), t.length > 3 && (t[3] = Number(t[3])), t)) : ne.black; + }, + le = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b"; + for (l in ne) le += "|" + l + "\\b"; + le = RegExp(le + ")", "gi"); + var he = function (t, e, i, r) { + if (null == t) return function (t) { + return t; + }; + var s, + n = e ? (t.match(le) || [""])[0] : "", + a = t.split(n).join("").match(g) || [], + o = t.substr(0, t.indexOf(a[0])), + l = ")" === t.charAt(t.length - 1) ? ")" : "", + h = -1 !== t.indexOf(" ") ? " " : ",", + u = a.length, + f = u > 0 ? a[0].replace(d, "") : ""; + return u ? s = e ? function (t) { + var e, _, p, c; + if ("number" == typeof t) t += f;else if (r && D.test(t)) { + for (c = t.replace(D, "|").split("|"), p = 0; c.length > p; p++) c[p] = s(c[p]); + return c.join(","); + } + if (e = (t.match(le) || [n])[0], _ = t.split(e).join("").match(g) || [], p = _.length, u > p--) for (; u > ++p;) _[p] = i ? _[0 | (p - 1) / 2] : a[p]; + return o + _.join(h) + h + e + l + (-1 !== t.indexOf("inset") ? " inset" : ""); + } : function (t) { + var e, n, _; + if ("number" == typeof t) t += f;else if (r && D.test(t)) { + for (n = t.replace(D, "|").split("|"), _ = 0; n.length > _; _++) n[_] = s(n[_]); + return n.join(","); + } + if (e = t.match(g) || [], _ = e.length, u > _--) for (; u > ++_;) e[_] = i ? e[0 | (_ - 1) / 2] : a[_]; + return o + e.join(h) + l; + } : function (t) { + return t; + }; + }, + ue = function (t) { + return t = t.split(","), function (e, i, r, s, n, a, o) { + var l, + h = (i + "").split(" "); + for (o = {}, l = 0; 4 > l; l++) o[t[l]] = h[l] = h[l] || h[(l - 1) / 2 >> 0]; + return s.parse(e, o, n, a); + }; + }, + fe = (E._setPluginRatio = function (t) { + this.plugin.setRatio(t); + for (var e, i, r, s, n = this.data, a = n.proxy, o = n.firstMPT, l = 1e-6; o;) e = a[o.v], o.r ? e = Math.round(e) : l > e && e > -l && (e = 0), o.t[o.p] = e, o = o._next; + if (n.autoRotate && (n.autoRotate.rotation = a.rotation), 1 === t) for (o = n.firstMPT; o;) { + if (i = o.t, i.type) { + if (1 === i.type) { + for (s = i.xs0 + i.s + i.xs1, r = 1; i.l > r; r++) s += i["xn" + r] + i["xs" + (r + 1)]; + i.e = s; + } + } else i.e = i.s + i.xs0; + o = o._next; + } + }, function (t, e, i, r, s) { + this.t = t, this.p = e, this.v = i, this.r = s, r && (r._prev = this, this._next = r); + }), + _e = (E._parseToProxy = function (t, e, i, r, s, n) { + var a, + o, + l, + h, + u, + f = r, + _ = {}, + p = {}, + c = i._transform, + d = N; + for (i._transform = null, N = e, r = u = i.parse(t, e, r, s), N = d, n && (i._transform = c, f && (f._prev = null, f._prev && (f._prev._next = null))); r && r !== f;) { + if (1 >= r.type && (o = r.p, p[o] = r.s + r.c, _[o] = r.s, n || (h = new fe(r, "s", o, h, r.r), r.c = 0), 1 === r.type)) for (a = r.l; --a > 0;) l = "xn" + a, o = r.p + "_" + l, p[o] = r.data[l], _[o] = r[l], n || (h = new fe(r, l, o, h, r.rxp[l])); + r = r._next; + } + return { + proxy: _, + end: p, + firstMPT: h, + pt: u + }; + }, E.CSSPropTween = function (t, e, r, s, a, o, l, h, u, f, _) { + this.t = t, this.p = e, this.s = r, this.c = s, this.n = l || e, t instanceof _e || n.push(this.n), this.r = h, this.type = o || 0, u && (this.pr = u, i = !0), this.b = void 0 === f ? r : f, this.e = void 0 === _ ? r + s : _, a && (this._next = a, a._prev = this); + }), + pe = a.parseComplex = function (t, e, i, r, s, n, a, o, l, u) { + i = i || n || "", a = new _e(t, e, 0, 0, a, u ? 2 : 1, null, !1, o, i, r), r += ""; + var f, + _, + p, + c, + g, + v, + y, + T, + w, + x, + P, + S, + C = i.split(", ").join(",").split(" "), + R = r.split(", ").join(",").split(" "), + k = C.length, + A = h !== !1; + for ((-1 !== r.indexOf(",") || -1 !== i.indexOf(",")) && (C = C.join(" ").replace(D, ", ").split(" "), R = R.join(" ").replace(D, ", ").split(" "), k = C.length), k !== R.length && (C = (n || "").split(" "), k = C.length), a.plugin = l, a.setRatio = u, f = 0; k > f; f++) if (c = C[f], g = R[f], T = parseFloat(c), T || 0 === T) a.appendXtra("", T, ie(g, T), g.replace(m, ""), A && -1 !== g.indexOf("px"), !0);else if (s && ("#" === c.charAt(0) || ne[c] || b.test(c))) S = "," === g.charAt(g.length - 1) ? ")," : ")", c = oe(c), g = oe(g), w = c.length + g.length > 6, w && !Y && 0 === g[3] ? (a["xs" + a.l] += a.l ? " transparent" : "transparent", a.e = a.e.split(R[f]).join("transparent")) : (Y || (w = !1), a.appendXtra(w ? "rgba(" : "rgb(", c[0], g[0] - c[0], ",", !0, !0).appendXtra("", c[1], g[1] - c[1], ",", !0).appendXtra("", c[2], g[2] - c[2], w ? "," : S, !0), w && (c = 4 > c.length ? 1 : c[3], a.appendXtra("", c, (4 > g.length ? 1 : g[3]) - c, S, !1)));else if (v = c.match(d)) { + if (y = g.match(m), !y || y.length !== v.length) return a; + for (p = 0, _ = 0; v.length > _; _++) P = v[_], x = c.indexOf(P, p), a.appendXtra(c.substr(p, x - p), Number(P), ie(y[_], P), "", A && "px" === c.substr(x + P.length, 2), 0 === _), p = x + P.length; + a["xs" + a.l] += c.substr(p); + } else a["xs" + a.l] += a.l ? " " + c : c; + if (-1 !== r.indexOf("=") && a.data) { + for (S = a.xs0 + a.data.s, f = 1; a.l > f; f++) S += a["xs" + f] + a.data["xn" + f]; + a.e = S + a["xs" + f]; + } + return a.l || (a.type = -1, a.xs0 = a.e), a.xfirst || a; + }, + ce = 9; + for (l = _e.prototype, l.l = l.pr = 0; --ce > 0;) l["xn" + ce] = 0, l["xs" + ce] = ""; + l.xs0 = "", l._next = l._prev = l.xfirst = l.data = l.plugin = l.setRatio = l.rxp = null, l.appendXtra = function (t, e, i, r, s, n) { + var a = this, + o = a.l; + return a["xs" + o] += n && o ? " " + t : t || "", i || 0 === o || a.plugin ? (a.l++, a.type = a.setRatio ? 2 : 1, a["xs" + a.l] = r || "", o > 0 ? (a.data["xn" + o] = e + i, a.rxp["xn" + o] = s, a["xn" + o] = e, a.plugin || (a.xfirst = new _e(a, "xn" + o, e, i, a.xfirst || a, 0, a.n, s, a.pr), a.xfirst.xs0 = 0), a) : (a.data = { + s: e + i + }, a.rxp = {}, a.s = e, a.c = i, a.r = s, a)) : (a["xs" + o] += e + (r || ""), a); + }; + var de = function (t, e) { + e = e || {}, this.p = e.prefix ? V(t) || t : t, o[t] = o[this.p] = this, this.format = e.formatter || he(e.defaultValue, e.color, e.collapsible, e.multi), e.parser && (this.parse = e.parser), this.clrs = e.color, this.multi = e.multi, this.keyword = e.keyword, this.dflt = e.defaultValue, this.pr = e.priority || 0; + }, + me = E._registerComplexSpecialProp = function (t, e, i) { + "object" != typeof e && (e = { + parser: i + }); + var r, + s, + n = t.split(","), + a = e.defaultValue; + for (i = i || [a], r = 0; n.length > r; r++) e.prefix = 0 === r && e.prefix, e.defaultValue = i[r] || a, s = new de(n[r], e); + }, + ge = function (t) { + if (!o[t]) { + var e = t.charAt(0).toUpperCase() + t.substr(1) + "Plugin"; + me(t, { + parser: function (t, i, r, s, n, a, l) { + var h = (window.GreenSockGlobals || window).com.greensock.plugins[e]; + return h ? (h._cssRegister(), o[r].parse(t, i, r, s, n, a, l)) : (U("Error: " + e + " js file not loaded."), n); + } + }); + } + }; + l = de.prototype, l.parseComplex = function (t, e, i, r, s, n) { + var a, + o, + l, + h, + u, + f, + _ = this.keyword; + if (this.multi && (D.test(i) || D.test(e) ? (o = e.replace(D, "|").split("|"), l = i.replace(D, "|").split("|")) : _ && (o = [e], l = [i])), l) { + for (h = l.length > o.length ? l.length : o.length, a = 0; h > a; a++) e = o[a] = o[a] || this.dflt, i = l[a] = l[a] || this.dflt, _ && (u = e.indexOf(_), f = i.indexOf(_), u !== f && (i = -1 === f ? l : o, i[a] += " " + _)); + e = o.join(", "), i = l.join(", "); + } + return pe(t, this.p, e, i, this.clrs, this.dflt, r, this.pr, s, n); + }, l.parse = function (t, e, i, r, n, a) { + return this.parseComplex(t.style, this.format(q(t, this.p, s, !1, this.dflt)), this.format(e), n, a); + }, a.registerSpecialProp = function (t, e, i) { + me(t, { + parser: function (t, r, s, n, a, o) { + var l = new _e(t, s, 0, 0, a, 2, s, !1, i); + return l.plugin = o, l.setRatio = e(t, r, n._tween, s), l; + }, + priority: i + }); + }; + var ve = "scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective".split(","), + ye = V("transform"), + Te = W + "transform", + we = V("transformOrigin"), + xe = null !== V("perspective"), + be = E.Transform = function () { + this.skewY = 0; + }, + Pe = E.getTransform = function (t, e, i, r) { + if (t._gsTransform && i && !r) return t._gsTransform; + var s, + n, + o, + l, + h, + u, + f, + _, + p, + c, + d, + m, + g, + v = i ? t._gsTransform || new be() : new be(), + y = 0 > v.scaleX, + T = 2e-5, + w = 1e5, + x = 179.99, + b = x * M, + P = xe ? parseFloat(q(t, we, e, !1, "0 0 0").split(" ")[2]) || v.zOrigin || 0 : 0; + for (ye ? s = q(t, Te, e, !0) : t.currentStyle && (s = t.currentStyle.filter.match(A), s = s && 4 === s.length ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), v.x || 0, v.y || 0].join(",") : ""), n = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || [], o = n.length; --o > -1;) l = Number(n[o]), n[o] = (h = l - (l |= 0)) ? (0 | h * w + (0 > h ? -.5 : .5)) / w + l : l; + if (16 === n.length) { + var S = n[8], + C = n[9], + R = n[10], + k = n[12], + O = n[13], + D = n[14]; + if (v.zOrigin && (D = -v.zOrigin, k = S * D - n[12], O = C * D - n[13], D = R * D + v.zOrigin - n[14]), !i || r || null == v.rotationX) { + var N, + X, + z, + I, + E, + F, + Y, + B = n[0], + U = n[1], + W = n[2], + j = n[3], + V = n[4], + H = n[5], + Q = n[6], + Z = n[7], + $ = n[11], + G = Math.atan2(Q, R), + K = -b > G || G > b; + v.rotationX = G * L, G && (I = Math.cos(-G), E = Math.sin(-G), N = V * I + S * E, X = H * I + C * E, z = Q * I + R * E, S = V * -E + S * I, C = H * -E + C * I, R = Q * -E + R * I, $ = Z * -E + $ * I, V = N, H = X, Q = z), G = Math.atan2(S, B), v.rotationY = G * L, G && (F = -b > G || G > b, I = Math.cos(-G), E = Math.sin(-G), N = B * I - S * E, X = U * I - C * E, z = W * I - R * E, C = U * E + C * I, R = W * E + R * I, $ = j * E + $ * I, B = N, U = X, W = z), G = Math.atan2(U, H), v.rotation = G * L, G && (Y = -b > G || G > b, I = Math.cos(-G), E = Math.sin(-G), B = B * I + V * E, X = U * I + H * E, H = U * -E + H * I, Q = W * -E + Q * I, U = X), Y && K ? v.rotation = v.rotationX = 0 : Y && F ? v.rotation = v.rotationY = 0 : F && K && (v.rotationY = v.rotationX = 0), v.scaleX = (0 | Math.sqrt(B * B + U * U) * w + .5) / w, v.scaleY = (0 | Math.sqrt(H * H + C * C) * w + .5) / w, v.scaleZ = (0 | Math.sqrt(Q * Q + R * R) * w + .5) / w, v.skewX = 0, v.perspective = $ ? 1 / (0 > $ ? -$ : $) : 0, v.x = k, v.y = O, v.z = D; + } + } else if (!(xe && !r && n.length && v.x === n[4] && v.y === n[5] && (v.rotationX || v.rotationY) || void 0 !== v.x && "none" === q(t, "display", e))) { + var J = n.length >= 6, + te = J ? n[0] : 1, + ee = n[1] || 0, + ie = n[2] || 0, + re = J ? n[3] : 1; + v.x = n[4] || 0, v.y = n[5] || 0, u = Math.sqrt(te * te + ee * ee), f = Math.sqrt(re * re + ie * ie), _ = te || ee ? Math.atan2(ee, te) * L : v.rotation || 0, p = ie || re ? Math.atan2(ie, re) * L + _ : v.skewX || 0, c = u - Math.abs(v.scaleX || 0), d = f - Math.abs(v.scaleY || 0), Math.abs(p) > 90 && 270 > Math.abs(p) && (y ? (u *= -1, p += 0 >= _ ? 180 : -180, _ += 0 >= _ ? 180 : -180) : (f *= -1, p += 0 >= p ? 180 : -180)), m = (_ - v.rotation) % 180, g = (p - v.skewX) % 180, (void 0 === v.skewX || c > T || -T > c || d > T || -T > d || m > -x && x > m && false | m * w || g > -x && x > g && false | g * w) && (v.scaleX = u, v.scaleY = f, v.rotation = _, v.skewX = p), xe && (v.rotationX = v.rotationY = v.z = 0, v.perspective = parseFloat(a.defaultTransformPerspective) || 0, v.scaleZ = 1); + } + v.zOrigin = P; + for (o in v) T > v[o] && v[o] > -T && (v[o] = 0); + return i && (t._gsTransform = v), v; + }, + Se = function (t) { + var e, + i, + r = this.data, + s = -r.rotation * M, + n = s + r.skewX * M, + a = 1e5, + o = (0 | Math.cos(s) * r.scaleX * a) / a, + l = (0 | Math.sin(s) * r.scaleX * a) / a, + h = (0 | Math.sin(n) * -r.scaleY * a) / a, + u = (0 | Math.cos(n) * r.scaleY * a) / a, + f = this.t.style, + _ = this.t.currentStyle; + if (_) { + i = l, l = -h, h = -i, e = _.filter, f.filter = ""; + var p, + d, + m = this.t.offsetWidth, + g = this.t.offsetHeight, + v = "absolute" !== _.position, + w = "progid:DXImageTransform.Microsoft.Matrix(M11=" + o + ", M12=" + l + ", M21=" + h + ", M22=" + u, + x = r.x, + b = r.y; + if (null != r.ox && (p = (r.oxp ? .01 * m * r.ox : r.ox) - m / 2, d = (r.oyp ? .01 * g * r.oy : r.oy) - g / 2, x += p - (p * o + d * l), b += d - (p * h + d * u)), v ? (p = m / 2, d = g / 2, w += ", Dx=" + (p - (p * o + d * l) + x) + ", Dy=" + (d - (p * h + d * u) + b) + ")") : w += ", sizingMethod='auto expand')", f.filter = -1 !== e.indexOf("DXImageTransform.Microsoft.Matrix(") ? e.replace(O, w) : w + " " + e, (0 === t || 1 === t) && 1 === o && 0 === l && 0 === h && 1 === u && (v && -1 === w.indexOf("Dx=0, Dy=0") || T.test(e) && 100 !== parseFloat(RegExp.$1) || -1 === e.indexOf("gradient(" && e.indexOf("Alpha")) && f.removeAttribute("filter")), !v) { + var P, + S, + C, + R = 8 > c ? 1 : -1; + for (p = r.ieOffsetX || 0, d = r.ieOffsetY || 0, r.ieOffsetX = Math.round((m - ((0 > o ? -o : o) * m + (0 > l ? -l : l) * g)) / 2 + x), r.ieOffsetY = Math.round((g - ((0 > u ? -u : u) * g + (0 > h ? -h : h) * m)) / 2 + b), ce = 0; 4 > ce; ce++) S = J[ce], P = _[S], i = -1 !== P.indexOf("px") ? parseFloat(P) : Q(this.t, S, parseFloat(P), P.replace(y, "")) || 0, C = i !== r[S] ? 2 > ce ? -r.ieOffsetX : -r.ieOffsetY : 2 > ce ? p - r.ieOffsetX : d - r.ieOffsetY, f[S] = (r[S] = Math.round(i - C * (0 === ce || 2 === ce ? 1 : R))) + "px"; + } + } + }, + Ce = E.set3DTransformRatio = function (t) { + var e, + i, + r, + s, + n, + a, + o, + l, + h, + u, + f, + p, + c, + d, + m, + g, + v, + y, + T, + w, + x, + b, + P, + S = this.data, + C = this.t.style, + R = S.rotation * M, + k = S.scaleX, + A = S.scaleY, + O = S.scaleZ, + D = S.perspective; + if (!(1 !== t && 0 !== t || "auto" !== S.force3D || S.rotationY || S.rotationX || 1 !== O || D || S.z)) return Re.call(this, t), void 0; + if (_) { + var L = 1e-4; + L > k && k > -L && (k = O = 2e-5), L > A && A > -L && (A = O = 2e-5), !D || S.z || S.rotationX || S.rotationY || (D = 0); + } + if (R || S.skewX) y = Math.cos(R), T = Math.sin(R), e = y, n = T, S.skewX && (R -= S.skewX * M, y = Math.cos(R), T = Math.sin(R), "simple" === S.skewType && (w = Math.tan(S.skewX * M), w = Math.sqrt(1 + w * w), y *= w, T *= w)), i = -T, a = y;else { + if (!(S.rotationY || S.rotationX || 1 !== O || D)) return C[ye] = "translate3d(" + S.x + "px," + S.y + "px," + S.z + "px)" + (1 !== k || 1 !== A ? " scale(" + k + "," + A + ")" : ""), void 0; + e = a = 1, i = n = 0; + } + f = 1, r = s = o = l = h = u = p = c = d = 0, m = D ? -1 / D : 0, g = S.zOrigin, v = 1e5, R = S.rotationY * M, R && (y = Math.cos(R), T = Math.sin(R), h = f * -T, c = m * -T, r = e * T, o = n * T, f *= y, m *= y, e *= y, n *= y), R = S.rotationX * M, R && (y = Math.cos(R), T = Math.sin(R), w = i * y + r * T, x = a * y + o * T, b = u * y + f * T, P = d * y + m * T, r = i * -T + r * y, o = a * -T + o * y, f = u * -T + f * y, m = d * -T + m * y, i = w, a = x, u = b, d = P), 1 !== O && (r *= O, o *= O, f *= O, m *= O), 1 !== A && (i *= A, a *= A, u *= A, d *= A), 1 !== k && (e *= k, n *= k, h *= k, c *= k), g && (p -= g, s = r * p, l = o * p, p = f * p + g), s = (w = (s += S.x) - (s |= 0)) ? (0 | w * v + (0 > w ? -.5 : .5)) / v + s : s, l = (w = (l += S.y) - (l |= 0)) ? (0 | w * v + (0 > w ? -.5 : .5)) / v + l : l, p = (w = (p += S.z) - (p |= 0)) ? (0 | w * v + (0 > w ? -.5 : .5)) / v + p : p, C[ye] = "matrix3d(" + [(0 | e * v) / v, (0 | n * v) / v, (0 | h * v) / v, (0 | c * v) / v, (0 | i * v) / v, (0 | a * v) / v, (0 | u * v) / v, (0 | d * v) / v, (0 | r * v) / v, (0 | o * v) / v, (0 | f * v) / v, (0 | m * v) / v, s, l, p, D ? 1 + -p / D : 1].join(",") + ")"; + }, + Re = E.set2DTransformRatio = function (t) { + var e, + i, + r, + s, + n, + a = this.data, + o = this.t, + l = o.style; + return a.rotationX || a.rotationY || a.z || a.force3D === !0 || "auto" === a.force3D && 1 !== t && 0 !== t ? (this.setRatio = Ce, Ce.call(this, t), void 0) : (a.rotation || a.skewX ? (e = a.rotation * M, i = e - a.skewX * M, r = 1e5, s = a.scaleX * r, n = a.scaleY * r, l[ye] = "matrix(" + (0 | Math.cos(e) * s) / r + "," + (0 | Math.sin(e) * s) / r + "," + (0 | Math.sin(i) * -n) / r + "," + (0 | Math.cos(i) * n) / r + "," + a.x + "," + a.y + ")") : l[ye] = "matrix(" + a.scaleX + ",0,0," + a.scaleY + "," + a.x + "," + a.y + ")", void 0); + }; + me("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType", { + parser: function (t, e, i, r, n, o, l) { + if (r._transform) return n; + var h, + u, + f, + _, + p, + c, + d, + m = r._transform = Pe(t, s, !0, l.parseTransform), + g = t.style, + v = 1e-6, + y = ve.length, + T = l, + w = {}; + if ("string" == typeof T.transform && ye) f = z.style, f[ye] = T.transform, f.display = "block", f.position = "absolute", X.body.appendChild(z), h = Pe(z, null, !1), X.body.removeChild(z);else if ("object" == typeof T) { + if (h = { + scaleX: re(null != T.scaleX ? T.scaleX : T.scale, m.scaleX), + scaleY: re(null != T.scaleY ? T.scaleY : T.scale, m.scaleY), + scaleZ: re(T.scaleZ, m.scaleZ), + x: re(T.x, m.x), + y: re(T.y, m.y), + z: re(T.z, m.z), + perspective: re(T.transformPerspective, m.perspective) + }, d = T.directionalRotation, null != d) if ("object" == typeof d) for (f in d) T[f] = d[f];else T.rotation = d; + h.rotation = se("rotation" in T ? T.rotation : "shortRotation" in T ? T.shortRotation + "_short" : "rotationZ" in T ? T.rotationZ : m.rotation, m.rotation, "rotation", w), xe && (h.rotationX = se("rotationX" in T ? T.rotationX : "shortRotationX" in T ? T.shortRotationX + "_short" : m.rotationX || 0, m.rotationX, "rotationX", w), h.rotationY = se("rotationY" in T ? T.rotationY : "shortRotationY" in T ? T.shortRotationY + "_short" : m.rotationY || 0, m.rotationY, "rotationY", w)), h.skewX = null == T.skewX ? m.skewX : se(T.skewX, m.skewX), h.skewY = null == T.skewY ? m.skewY : se(T.skewY, m.skewY), (u = h.skewY - m.skewY) && (h.skewX += u, h.rotation += u); + } + for (xe && null != T.force3D && (m.force3D = T.force3D, c = !0), m.skewType = T.skewType || m.skewType || a.defaultSkewType, p = m.force3D || m.z || m.rotationX || m.rotationY || h.z || h.rotationX || h.rotationY || h.perspective, p || null == T.scale || (h.scaleZ = 1); --y > -1;) i = ve[y], _ = h[i] - m[i], (_ > v || -v > _ || null != N[i]) && (c = !0, n = new _e(m, i, m[i], _, n), i in w && (n.e = w[i]), n.xs0 = 0, n.plugin = o, r._overwriteProps.push(n.n)); + return _ = T.transformOrigin, (_ || xe && p && m.zOrigin) && (ye ? (c = !0, i = we, _ = (_ || q(t, i, s, !1, "50% 50%")) + "", n = new _e(g, i, 0, 0, n, -1, "transformOrigin"), n.b = g[i], n.plugin = o, xe ? (f = m.zOrigin, _ = _.split(" "), m.zOrigin = (_.length > 2 && (0 === f || "0px" !== _[2]) ? parseFloat(_[2]) : f) || 0, n.xs0 = n.e = _[0] + " " + (_[1] || "50%") + " 0px", n = new _e(m, "zOrigin", 0, 0, n, -1, n.n), n.b = f, n.xs0 = n.e = m.zOrigin) : n.xs0 = n.e = _) : ee(_ + "", m)), c && (r._transformType = p || 3 === this._transformType ? 3 : 2), n; + }, + prefix: !0 + }), me("boxShadow", { + defaultValue: "0px 0px 0px 0px #999", + prefix: !0, + color: !0, + multi: !0, + keyword: "inset" + }), me("borderRadius", { + defaultValue: "0px", + parser: function (t, e, i, n, a) { + e = this.format(e); + var o, + l, + h, + u, + f, + _, + p, + c, + d, + m, + g, + v, + y, + T, + w, + x, + b = ["borderTopLeftRadius", "borderTopRightRadius", "borderBottomRightRadius", "borderBottomLeftRadius"], + P = t.style; + for (d = parseFloat(t.offsetWidth), m = parseFloat(t.offsetHeight), o = e.split(" "), l = 0; b.length > l; l++) this.p.indexOf("border") && (b[l] = V(b[l])), f = u = q(t, b[l], s, !1, "0px"), -1 !== f.indexOf(" ") && (u = f.split(" "), f = u[0], u = u[1]), _ = h = o[l], p = parseFloat(f), v = f.substr((p + "").length), y = "=" === _.charAt(1), y ? (c = parseInt(_.charAt(0) + "1", 10), _ = _.substr(2), c *= parseFloat(_), g = _.substr((c + "").length - (0 > c ? 1 : 0)) || "") : (c = parseFloat(_), g = _.substr((c + "").length)), "" === g && (g = r[i] || v), g !== v && (T = Q(t, "borderLeft", p, v), w = Q(t, "borderTop", p, v), "%" === g ? (f = 100 * (T / d) + "%", u = 100 * (w / m) + "%") : "em" === g ? (x = Q(t, "borderLeft", 1, "em"), f = T / x + "em", u = w / x + "em") : (f = T + "px", u = w + "px"), y && (_ = parseFloat(f) + c + g, h = parseFloat(u) + c + g)), a = pe(P, b[l], f + " " + u, _ + " " + h, !1, "0px", a); + return a; + }, + prefix: !0, + formatter: he("0px 0px 0px 0px", !1, !0) + }), me("backgroundPosition", { + defaultValue: "0 0", + parser: function (t, e, i, r, n, a) { + var o, + l, + h, + u, + f, + _, + p = "background-position", + d = s || H(t, null), + m = this.format((d ? c ? d.getPropertyValue(p + "-x") + " " + d.getPropertyValue(p + "-y") : d.getPropertyValue(p) : t.currentStyle.backgroundPositionX + " " + t.currentStyle.backgroundPositionY) || "0 0"), + g = this.format(e); + if (-1 !== m.indexOf("%") != (-1 !== g.indexOf("%")) && (_ = q(t, "backgroundImage").replace(C, ""), _ && "none" !== _)) { + for (o = m.split(" "), l = g.split(" "), I.setAttribute("src", _), h = 2; --h > -1;) m = o[h], u = -1 !== m.indexOf("%"), u !== (-1 !== l[h].indexOf("%")) && (f = 0 === h ? t.offsetWidth - I.width : t.offsetHeight - I.height, o[h] = u ? parseFloat(m) / 100 * f + "px" : 100 * (parseFloat(m) / f) + "%"); + m = o.join(" "); + } + return this.parseComplex(t.style, m, g, n, a); + }, + formatter: ee + }), me("backgroundSize", { + defaultValue: "0 0", + formatter: ee + }), me("perspective", { + defaultValue: "0px", + prefix: !0 + }), me("perspectiveOrigin", { + defaultValue: "50% 50%", + prefix: !0 + }), me("transformStyle", { + prefix: !0 + }), me("backfaceVisibility", { + prefix: !0 + }), me("userSelect", { + prefix: !0 + }), me("margin", { + parser: ue("marginTop,marginRight,marginBottom,marginLeft") + }), me("padding", { + parser: ue("paddingTop,paddingRight,paddingBottom,paddingLeft") + }), me("clip", { + defaultValue: "rect(0px,0px,0px,0px)", + parser: function (t, e, i, r, n, a) { + var o, l, h; + return 9 > c ? (l = t.currentStyle, h = 8 > c ? " " : ",", o = "rect(" + l.clipTop + h + l.clipRight + h + l.clipBottom + h + l.clipLeft + ")", e = this.format(e).split(",").join(h)) : (o = this.format(q(t, this.p, s, !1, this.dflt)), e = this.format(e)), this.parseComplex(t.style, o, e, n, a); + } + }), me("textShadow", { + defaultValue: "0px 0px 0px #999", + color: !0, + multi: !0 + }), me("autoRound,strictUnits", { + parser: function (t, e, i, r, s) { + return s; + } + }), me("border", { + defaultValue: "0px solid #000", + parser: function (t, e, i, r, n, a) { + return this.parseComplex(t.style, this.format(q(t, "borderTopWidth", s, !1, "0px") + " " + q(t, "borderTopStyle", s, !1, "solid") + " " + q(t, "borderTopColor", s, !1, "#000")), this.format(e), n, a); + }, + color: !0, + formatter: function (t) { + var e = t.split(" "); + return e[0] + " " + (e[1] || "solid") + " " + (t.match(le) || ["#000"])[0]; + } + }), me("borderWidth", { + parser: ue("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth") + }), me("float,cssFloat,styleFloat", { + parser: function (t, e, i, r, s) { + var n = t.style, + a = "cssFloat" in n ? "cssFloat" : "styleFloat"; + return new _e(n, a, 0, 0, s, -1, i, !1, 0, n[a], e); + } + }); + var ke = function (t) { + var e, + i = this.t, + r = i.filter || q(this.data, "filter"), + s = 0 | this.s + this.c * t; + 100 === s && (-1 === r.indexOf("atrix(") && -1 === r.indexOf("radient(") && -1 === r.indexOf("oader(") ? (i.removeAttribute("filter"), e = !q(this.data, "filter")) : (i.filter = r.replace(x, ""), e = !0)), e || (this.xn1 && (i.filter = r = r || "alpha(opacity=" + s + ")"), -1 === r.indexOf("pacity") ? 0 === s && this.xn1 || (i.filter = r + " alpha(opacity=" + s + ")") : i.filter = r.replace(T, "opacity=" + s)); + }; + me("opacity,alpha,autoAlpha", { + defaultValue: "1", + parser: function (t, e, i, r, n, a) { + var o = parseFloat(q(t, "opacity", s, !1, "1")), + l = t.style, + h = "autoAlpha" === i; + return "string" == typeof e && "=" === e.charAt(1) && (e = ("-" === e.charAt(0) ? -1 : 1) * parseFloat(e.substr(2)) + o), h && 1 === o && "hidden" === q(t, "visibility", s) && 0 !== e && (o = 0), Y ? n = new _e(l, "opacity", o, e - o, n) : (n = new _e(l, "opacity", 100 * o, 100 * (e - o), n), n.xn1 = h ? 1 : 0, l.zoom = 1, n.type = 2, n.b = "alpha(opacity=" + n.s + ")", n.e = "alpha(opacity=" + (n.s + n.c) + ")", n.data = t, n.plugin = a, n.setRatio = ke), h && (n = new _e(l, "visibility", 0, 0, n, -1, null, !1, 0, 0 !== o ? "inherit" : "hidden", 0 === e ? "hidden" : "inherit"), n.xs0 = "inherit", r._overwriteProps.push(n.n), r._overwriteProps.push(i)), n; + } + }); + var Ae = function (t, e) { + e && (t.removeProperty ? ("ms" === e.substr(0, 2) && (e = "M" + e.substr(1)), t.removeProperty(e.replace(P, "-$1").toLowerCase())) : t.removeAttribute(e)); + }, + Oe = function (t) { + if (this.t._gsClassPT = this, 1 === t || 0 === t) { + this.t.setAttribute("class", 0 === t ? this.b : this.e); + for (var e = this.data, i = this.t.style; e;) e.v ? i[e.p] = e.v : Ae(i, e.p), e = e._next; + 1 === t && this.t._gsClassPT === this && (this.t._gsClassPT = null); + } else this.t.getAttribute("class") !== this.e && this.t.setAttribute("class", this.e); + }; + me("className", { + parser: function (t, e, r, n, a, o, l) { + var h, + u, + f, + _, + p, + c = t.getAttribute("class") || "", + d = t.style.cssText; + if (a = n._classNamePT = new _e(t, r, 0, 0, a, 2), a.setRatio = Oe, a.pr = -11, i = !0, a.b = c, u = $(t, s), f = t._gsClassPT) { + for (_ = {}, p = f.data; p;) _[p.p] = 1, p = p._next; + f.setRatio(1); + } + return t._gsClassPT = a, a.e = "=" !== e.charAt(1) ? e : c.replace(RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ("+" === e.charAt(0) ? " " + e.substr(2) : ""), n._tween._duration && (t.setAttribute("class", a.e), h = G(t, u, $(t), l, _), t.setAttribute("class", c), a.data = h.firstMPT, t.style.cssText = d, a = a.xfirst = n.parse(t, h.difs, a, o)), a; + } + }); + var De = function (t) { + if ((1 === t || 0 === t) && this.data._totalTime === this.data._totalDuration && "isFromStart" !== this.data.data) { + var e, + i, + r, + s, + n = this.t.style, + a = o.transform.parse; + if ("all" === this.e) n.cssText = "", s = !0;else for (e = this.e.split(","), r = e.length; --r > -1;) i = e[r], o[i] && (o[i].parse === a ? s = !0 : i = "transformOrigin" === i ? we : o[i].p), Ae(n, i); + s && (Ae(n, ye), this.t._gsTransform && delete this.t._gsTransform); + } + }; + for (me("clearProps", { + parser: function (t, e, r, s, n) { + return n = new _e(t, r, 0, 0, n, 2), n.setRatio = De, n.e = e, n.pr = -10, n.data = s._tween, i = !0, n; + } + }), l = "bezier,throwProps,physicsProps,physics2D".split(","), ce = l.length; ce--;) ge(l[ce]); + l = a.prototype, l._firstPT = null, l._onInitTween = function (t, e, o) { + if (!t.nodeType) return !1; + this._target = t, this._tween = o, this._vars = e, h = e.autoRound, i = !1, r = e.suffixMap || a.suffixMap, s = H(t, ""), n = this._overwriteProps; + var l, + _, + c, + d, + m, + g, + v, + y, + T, + x = t.style; + if (u && "" === x.zIndex && (l = q(t, "zIndex", s), ("auto" === l || "" === l) && this._addLazySet(x, "zIndex", 0)), "string" == typeof e && (d = x.cssText, l = $(t, s), x.cssText = d + ";" + e, l = G(t, l, $(t)).difs, !Y && w.test(e) && (l.opacity = parseFloat(RegExp.$1)), e = l, x.cssText = d), this._firstPT = _ = this.parse(t, e, null), this._transformType) { + for (T = 3 === this._transformType, ye ? f && (u = !0, "" === x.zIndex && (v = q(t, "zIndex", s), ("auto" === v || "" === v) && this._addLazySet(x, "zIndex", 0)), p && this._addLazySet(x, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (T ? "visible" : "hidden"))) : x.zoom = 1, c = _; c && c._next;) c = c._next; + y = new _e(t, "transform", 0, 0, null, 2), this._linkCSSP(y, null, c), y.setRatio = T && xe ? Ce : ye ? Re : Se, y.data = this._transform || Pe(t, s, !0), n.pop(); + } + if (i) { + for (; _;) { + for (g = _._next, c = d; c && c.pr > _.pr;) c = c._next; + (_._prev = c ? c._prev : m) ? _._prev._next = _ : d = _, (_._next = c) ? c._prev = _ : m = _, _ = g; + } + this._firstPT = d; + } + return !0; + }, l.parse = function (t, e, i, n) { + var a, + l, + u, + f, + _, + p, + c, + d, + m, + g, + v = t.style; + for (a in e) p = e[a], l = o[a], l ? i = l.parse(t, p, a, this, i, n, e) : (_ = q(t, a, s) + "", m = "string" == typeof p, "color" === a || "fill" === a || "stroke" === a || -1 !== a.indexOf("Color") || m && b.test(p) ? (m || (p = oe(p), p = (p.length > 3 ? "rgba(" : "rgb(") + p.join(",") + ")"), i = pe(v, a, _, p, !0, "transparent", i, 0, n)) : !m || -1 === p.indexOf(" ") && -1 === p.indexOf(",") ? (u = parseFloat(_), c = u || 0 === u ? _.substr((u + "").length) : "", ("" === _ || "auto" === _) && ("width" === a || "height" === a ? (u = te(t, a, s), c = "px") : "left" === a || "top" === a ? (u = Z(t, a, s), c = "px") : (u = "opacity" !== a ? 0 : 1, c = "")), g = m && "=" === p.charAt(1), g ? (f = parseInt(p.charAt(0) + "1", 10), p = p.substr(2), f *= parseFloat(p), d = p.replace(y, "")) : (f = parseFloat(p), d = m ? p.substr((f + "").length) || "" : ""), "" === d && (d = a in r ? r[a] : c), p = f || 0 === f ? (g ? f + u : f) + d : e[a], c !== d && "" !== d && (f || 0 === f) && u && (u = Q(t, a, u, c), "%" === d ? (u /= Q(t, a, 100, "%") / 100, e.strictUnits !== !0 && (_ = u + "%")) : "em" === d ? u /= Q(t, a, 1, "em") : "px" !== d && (f = Q(t, a, f, d), d = "px"), g && (f || 0 === f) && (p = f + u + d)), g && (f += u), !u && 0 !== u || !f && 0 !== f ? void 0 !== v[a] && (p || "NaN" != p + "" && null != p) ? (i = new _e(v, a, f || u || 0, 0, i, -1, a, !1, 0, _, p), i.xs0 = "none" !== p || "display" !== a && -1 === a.indexOf("Style") ? p : _) : U("invalid " + a + " tween value: " + e[a]) : (i = new _e(v, a, u, f - u, i, 0, a, h !== !1 && ("px" === d || "zIndex" === a), 0, _, p), i.xs0 = d)) : i = pe(v, a, _, p, !0, null, i, 0, n)), n && i && !i.plugin && (i.plugin = n); + return i; + }, l.setRatio = function (t) { + var e, + i, + r, + s = this._firstPT, + n = 1e-6; + if (1 !== t || this._tween._time !== this._tween._duration && 0 !== this._tween._time) { + if (t || this._tween._time !== this._tween._duration && 0 !== this._tween._time || this._tween._rawPrevTime === -1e-6) for (; s;) { + if (e = s.c * t + s.s, s.r ? e = Math.round(e) : n > e && e > -n && (e = 0), s.type) { + if (1 === s.type) { + if (r = s.l, 2 === r) s.t[s.p] = s.xs0 + e + s.xs1 + s.xn1 + s.xs2;else if (3 === r) s.t[s.p] = s.xs0 + e + s.xs1 + s.xn1 + s.xs2 + s.xn2 + s.xs3;else if (4 === r) s.t[s.p] = s.xs0 + e + s.xs1 + s.xn1 + s.xs2 + s.xn2 + s.xs3 + s.xn3 + s.xs4;else if (5 === r) s.t[s.p] = s.xs0 + e + s.xs1 + s.xn1 + s.xs2 + s.xn2 + s.xs3 + s.xn3 + s.xs4 + s.xn4 + s.xs5;else { + for (i = s.xs0 + e + s.xs1, r = 1; s.l > r; r++) i += s["xn" + r] + s["xs" + (r + 1)]; + s.t[s.p] = i; + } + } else -1 === s.type ? s.t[s.p] = s.xs0 : s.setRatio && s.setRatio(t); + } else s.t[s.p] = e + s.xs0; + s = s._next; + } else for (; s;) 2 !== s.type ? s.t[s.p] = s.b : s.setRatio(t), s = s._next; + } else for (; s;) 2 !== s.type ? s.t[s.p] = s.e : s.setRatio(t), s = s._next; + }, l._enableTransforms = function (t) { + this._transformType = t || 3 === this._transformType ? 3 : 2, this._transform = this._transform || Pe(this._target, s, !0); + }; + var Me = function () { + this.t[this.p] = this.e, this.data._linkCSSP(this, this._next, null, !0); + }; + l._addLazySet = function (t, e, i) { + var r = this._firstPT = new _e(t, e, 0, 0, this._firstPT, 2); + r.e = i, r.setRatio = Me, r.data = this; + }, l._linkCSSP = function (t, e, i, r) { + return t && (e && (e._prev = t), t._next && (t._next._prev = t._prev), t._prev ? t._prev._next = t._next : this._firstPT === t && (this._firstPT = t._next, r = !0), i ? i._next = t : r || null !== this._firstPT || (this._firstPT = t), t._next = e, t._prev = i), t; + }, l._kill = function (e) { + var i, + r, + s, + n = e; + if (e.autoAlpha || e.alpha) { + n = {}; + for (r in e) n[r] = e[r]; + n.opacity = 1, n.autoAlpha && (n.visibility = 1); + } + return e.className && (i = this._classNamePT) && (s = i.xfirst, s && s._prev ? this._linkCSSP(s._prev, i._next, s._prev._prev) : s === this._firstPT && (this._firstPT = i._next), i._next && this._linkCSSP(i._next, i._next._next, s._prev), this._classNamePT = null), t.prototype._kill.call(this, n); + }; + var Le = function (t, e, i) { + var r, s, n, a; + if (t.slice) for (s = t.length; --s > -1;) Le(t[s], e, i);else for (r = t.childNodes, s = r.length; --s > -1;) n = r[s], a = n.type, n.style && (e.push($(n)), i && i.push(n)), 1 !== a && 9 !== a && 11 !== a || !n.childNodes.length || Le(n, e, i); + }; + return a.cascadeTo = function (t, i, r) { + var s, + n, + a, + o = e.to(t, i, r), + l = [o], + h = [], + u = [], + f = [], + _ = e._internals.reservedProps; + for (t = o._targets || o.target, Le(t, h, f), o.render(i, !0), Le(t, u), o.render(0, !0), o._enabled(!0), s = f.length; --s > -1;) if (n = G(f[s], h[s], u[s]), n.firstMPT) { + n = n.difs; + for (a in r) _[a] && (n[a] = r[a]); + l.push(e.to(f[s], i, n)); + } + return l; + }, t.activate([a]), a; + }, !0); +}), window._gsDefine && window._gsQueue.pop()(); + +},{}],13:[function(require,module,exports){ +"use strict"; + +/*! + * VERSION: 1.7.3 + * DATE: 2014-01-14 + * UPDATES AND DOCS AT: http://www.greensock.com + * + * @license Copyright (c) 2008-2014, GreenSock. All rights reserved. + * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for + * Club GreenSock members, the software agreement that was issued with your membership. + * + * @author: Jack Doyle, jack@greensock.com + **/ +(window._gsQueue || (window._gsQueue = [])).push(function () { + "use strict"; + + var t = document.documentElement, + e = window, + i = function (i, s) { + var r = "x" === s ? "Width" : "Height", + n = "scroll" + r, + a = "client" + r, + o = document.body; + return i === e || i === t || i === o ? Math.max(t[n], o[n]) - (e["inner" + r] || Math.max(t[a], o[a])) : i[n] - i["offset" + r]; + }, + s = window._gsDefine.plugin({ + propName: "scrollTo", + API: 2, + version: "1.7.3", + init: function (t, s, r) { + return this._wdw = t === e, this._target = t, this._tween = r, "object" != typeof s && (s = { + y: s + }), this._autoKill = s.autoKill !== !1, this.x = this.xPrev = this.getX(), this.y = this.yPrev = this.getY(), null != s.x ? (this._addTween(this, "x", this.x, "max" === s.x ? i(t, "x") : s.x, "scrollTo_x", !0), this._overwriteProps.push("scrollTo_x")) : this.skipX = !0, null != s.y ? (this._addTween(this, "y", this.y, "max" === s.y ? i(t, "y") : s.y, "scrollTo_y", !0), this._overwriteProps.push("scrollTo_y")) : this.skipY = !0, !0; + }, + set: function (t) { + this._super.setRatio.call(this, t); + var s = this._wdw || !this.skipX ? this.getX() : this.xPrev, + r = this._wdw || !this.skipY ? this.getY() : this.yPrev, + n = r - this.yPrev, + a = s - this.xPrev; + this._autoKill && (!this.skipX && (a > 7 || -7 > a) && i(this._target, "x") > s && (this.skipX = !0), !this.skipY && (n > 7 || -7 > n) && i(this._target, "y") > r && (this.skipY = !0), this.skipX && this.skipY && this._tween.kill()), this._wdw ? e.scrollTo(this.skipX ? s : this.x, this.skipY ? r : this.y) : (this.skipY || (this._target.scrollTop = this.y), this.skipX || (this._target.scrollLeft = this.x)), this.xPrev = this.x, this.yPrev = this.y; + } + }), + r = s.prototype; + s.max = i, r.getX = function () { + return this._wdw ? null != e.pageXOffset ? e.pageXOffset : null != t.scrollLeft ? t.scrollLeft : document.body.scrollLeft : this._target.scrollLeft; + }, r.getY = function () { + return this._wdw ? null != e.pageYOffset ? e.pageYOffset : null != t.scrollTop ? t.scrollTop : document.body.scrollTop : this._target.scrollTop; + }, r._kill = function (t) { + return t.scrollTo_x && (this.skipX = !0), t.scrollTo_y && (this.skipY = !0), this._super._kill.call(this, t); + }; +}), window._gsDefine && window._gsQueue.pop()(); + +},{}]},{},[2]) +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvanMvZ2xvYmFsL2FqYXguanMiLCJzcmMvanMvZ2xvYmFsL2FwcC5qcyIsInNyYy9qcy9nbG9iYWwvYmVhY29uLmpzIiwic3JjL2pzL2dsb2JhbC9jb3VudGRvd24uanMiLCJzcmMvanMvZ2xvYmFsL2ZpZWxkcy5qcyIsInNyYy9qcy9nbG9iYWwvbWFpbi5qcyIsInNyYy9qcy9nbG9iYWwvcGFnZU1hbmFnZXIuanMiLCJzcmMvanMvZ2xvYmFsL3JvY2tldGNkbi5qcyIsInNyYy9qcy9saWIvZ3JlZW5zb2NrL1RpbWVsaW5lTGl0ZS5taW4uanMiLCJzcmMvanMvbGliL2dyZWVuc29jay9Ud2VlbkxpdGUubWluLmpzIiwic3JjL2pzL2xpYi9ncmVlbnNvY2svZWFzaW5nL0Vhc2VQYWNrLm1pbi5qcyIsInNyYy9qcy9saWIvZ3JlZW5zb2NrL3BsdWdpbnMvQ1NTUGx1Z2luLm1pbi5qcyIsInNyYy9qcy9saWIvZ3JlZW5zb2NrL3BsdWdpbnMvU2Nyb2xsVG9QbHVnaW4ubWluLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7QUNBQSxJQUFJLENBQUMsR0FBRyxNQUFNO0FBQ2QsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEtBQUssQ0FBQyxZQUFVO0VBQ3hCO0FBQ0o7QUFDQTtFQUNJLElBQUksYUFBYSxHQUFHLEtBQUs7RUFDekIsQ0FBQyxDQUFDLDZCQUE2QixDQUFDLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxVQUFTLENBQUMsRUFBRTtJQUNyRCxJQUFHLENBQUMsYUFBYSxFQUFDO01BQ2QsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQztNQUNwQixJQUFJLE9BQU8sR0FBRyxDQUFDLENBQUMsbUJBQW1CLENBQUM7TUFDcEMsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDLHNCQUFzQixDQUFDO01BRXRDLENBQUMsQ0FBQyxjQUFjLENBQUMsQ0FBQztN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Q0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztNQUFBLENBQUM7TUFBQyxDQUFDLEdBQUMsS0FBSztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLFVBQVU7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxPQUFPO01BQUMsQ0FBQyxHQUFDLEVBQUU7TUFBQyxDQUFDLEdBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxPQUFPO01BQUMsQ0FBQyxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUM7UUFBQyxJQUFJLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO1FBQUMsS0FBSSxDQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsT0FBTyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsU0FBUyxFQUFDLENBQUMsSUFBRSxDQUFDLENBQUM7TUFBQSxDQUFDO01BQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO01BQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsSUFBSSxDQUFDLENBQUQsQ0FBQztJQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sR0FBQyxRQUFRLEVBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxJQUFFLENBQUMsQ0FBQyxRQUFRLElBQUUsQ0FBQztNQUFDLE9BQU8sQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFFLENBQUMsQ0FBQyxRQUFRLElBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLElBQUUsQ0FBQyxDQUFDLFFBQVEsSUFBRSxDQUFDO01BQUMsT0FBTyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUM7UUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLENBQUM7VUFBQyxVQUFVLEVBQUMsQ0FBQztVQUFDLGdCQUFnQixFQUFDLENBQUM7VUFBQyxlQUFlLEVBQUMsQ0FBQztVQUFDLGlCQUFpQixFQUFDLElBQUksQ0FBQztRQUFpQixDQUFDLENBQUM7TUFBQyxLQUFJLFFBQVEsSUFBRSxPQUFPLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsT0FBTyxLQUFHLENBQUMsQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQztNQUFDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsT0FBTyxDQUFDLENBQUMsZUFBZSxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsZUFBZSxFQUFDLENBQUMsQ0FBQyxZQUFZLEdBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxhQUFhLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLGVBQWUsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLGVBQWUsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLGVBQWUsRUFBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLENBQUMsR0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksSUFBRSxDQUFDLENBQUMsZUFBZSxLQUFHLENBQUMsQ0FBQyxlQUFlLEdBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxLQUFLLElBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsVUFBVSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEVBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxpQkFBaUIsS0FBRyxDQUFDLENBQUMsaUJBQWlCLEdBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQyxJQUFJLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUztNQUFDLEtBQUksSUFBSSxJQUFFLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxZQUFZLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsVUFBVSxHQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxFQUFDLENBQUMsSUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFFLENBQUMsQ0FBQyxNQUFNLEtBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUM7TUFBQyxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDO01BQUMsSUFBRyxRQUFRLElBQUUsT0FBTyxDQUFDLEtBQUcsQ0FBQyxHQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxDQUFDLEVBQUM7UUFBQyxJQUFHLENBQUMsWUFBWSxLQUFLLElBQUUsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDO1VBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxJQUFFLFFBQVEsRUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxJQUFJLENBQUMsQ0FBQztZQUFDLE1BQU0sRUFBQztVQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsUUFBUSxJQUFFLE9BQU8sQ0FBQyxJQUFFLFVBQVUsSUFBRSxPQUFPLENBQUMsS0FBRyxVQUFVLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsVUFBVSxHQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsT0FBTyxLQUFHLENBQUMsS0FBRyxDQUFDLENBQUMsVUFBVSxJQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQztVQUFDLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUFBO1FBQUMsSUFBRyxRQUFRLElBQUUsT0FBTyxDQUFDLEVBQUMsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7UUFBQyxJQUFHLFVBQVUsSUFBRSxPQUFPLENBQUMsRUFBQyxNQUFLLGFBQWEsR0FBQyxDQUFDLEdBQUMsdUVBQXVFO1FBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztNQUFBO01BQUMsSUFBRyxDQUFDLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUUsSUFBSSxDQUFDLEtBQUssS0FBRyxJQUFJLENBQUMsU0FBUyxLQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sSUFBRSxJQUFJLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFDLEtBQUksQ0FBQyxHQUFDLElBQUksRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLENBQUMsU0FBUyxHQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDLGlCQUFpQixHQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFHLElBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUztNQUFDLE9BQU8sSUFBSTtJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsSUFBRyxDQUFDLFlBQVksQ0FBQyxFQUFDLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQyxJQUFHLENBQUMsWUFBWSxLQUFLLElBQUUsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDO1FBQUMsS0FBSSxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsT0FBTyxJQUFJO01BQUE7TUFBQyxPQUFNLFFBQVEsSUFBRSxPQUFPLENBQUMsR0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsT0FBTyxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztNQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLO01BQUMsT0FBTyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsVUFBVSxHQUFDLENBQUMsQ0FBQyxjQUFjLEdBQUMsQ0FBQyxDQUFDLFVBQVUsS0FBRyxJQUFJLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxVQUFVLEdBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLFVBQVUsR0FBQyxJQUFJLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxjQUFjLEdBQUMsQ0FBQyxFQUFDLElBQUk7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLGNBQWMsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxjQUFjLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUk7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsQ0FBQyxRQUFRLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxPQUFPLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxZQUFZLEdBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksSUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxpQkFBaUIsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztNQUFDLElBQUcsQ0FBQyxZQUFZLENBQUMsSUFBRSxDQUFDLENBQUMsUUFBUSxLQUFHLElBQUksRUFBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssSUFBRyxDQUFDLEtBQUcsQ0FBQyxZQUFZLEtBQUssSUFBRSxDQUFDLENBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFXLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxLQUFHLElBQUksSUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUFDLElBQUcsUUFBUSxJQUFFLE9BQU8sQ0FBQyxFQUFDLE9BQU8sSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsUUFBUSxJQUFFLE9BQU8sQ0FBQyxJQUFFLElBQUksSUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO01BQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxRQUFRLElBQUUsT0FBTyxDQUFDLElBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUUsSUFBSSxJQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxJQUFFLENBQUMsS0FBRyxDQUFDLEdBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFJO1FBQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEVBQUMsT0FBTyxJQUFJLElBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQztRQUFDLENBQUMsR0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxFQUFDLEVBQUUsQ0FBQyxHQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztNQUFBO01BQUMsT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLElBQUUsT0FBTyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxZQUFVO01BQUMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUMsR0FBRyxJQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQyxJQUFJLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxNQUFNLEdBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLGNBQWM7UUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUs7UUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVU7UUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVU7UUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLE9BQU87TUFBQyxJQUFHLENBQUMsSUFBRSxDQUFDLElBQUUsSUFBSSxDQUFDLFVBQVUsR0FBQyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsU0FBUyxJQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsWUFBWSxFQUFDLENBQUMsS0FBRyxJQUFJLENBQUMsU0FBUyxLQUFHLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxHQUFDLElBQUksQ0FBQyxZQUFZLElBQUUsSUFBSSxDQUFDLFlBQVksS0FBRyxDQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsWUFBWSxLQUFHLENBQUMsSUFBRSxJQUFJLENBQUMsTUFBTSxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsWUFBWSxHQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFlBQVksR0FBQyxJQUFJLENBQUMsU0FBUyxJQUFFLENBQUMsQ0FBQyxJQUFFLENBQUMsSUFBRSxJQUFJLENBQUMsWUFBWSxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxJQUFFLElBQUksR0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLFVBQVUsR0FBQyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxLQUFHLElBQUksQ0FBQyxTQUFTLElBQUUsSUFBSSxDQUFDLFlBQVksS0FBRyxDQUFDLEtBQUcsSUFBSSxDQUFDLFlBQVksR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsWUFBWSxJQUFFLENBQUMsQ0FBQyxNQUFJLENBQUMsR0FBQyxtQkFBbUIsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLE9BQU8sR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsSUFBSSxDQUFDLFNBQVMsSUFBRSxJQUFJLENBQUMsWUFBWSxJQUFFLENBQUMsSUFBRSxJQUFJLENBQUMsTUFBTSxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxZQUFZLEdBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxZQUFZLEdBQUMsSUFBSSxDQUFDLFNBQVMsSUFBRSxDQUFDLENBQUMsSUFBRSxDQUFDLElBQUUsSUFBSSxDQUFDLFlBQVksS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxRQUFRLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsVUFBVSxHQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLFlBQVksR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEtBQUssS0FBRyxDQUFDLElBQUUsSUFBSSxDQUFDLE1BQU0sSUFBRSxDQUFDLElBQUUsQ0FBQyxFQUFDO1FBQUMsSUFBRyxJQUFJLENBQUMsUUFBUSxLQUFHLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsT0FBTyxJQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sSUFBRSxJQUFJLENBQUMsS0FBSyxLQUFHLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFFLENBQUMsS0FBRyxJQUFJLENBQUMsS0FBSyxLQUFHLENBQUMsSUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLElBQUUsSUFBSSxFQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEtBQUssSUFBRSxDQUFDLEVBQUMsS0FBSSxDQUFDLEdBQUMsSUFBSSxDQUFDLE1BQU0sRUFBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFFLENBQUMsQ0FBQyxHQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sSUFBRSxDQUFDLENBQUMsVUFBVSxJQUFFLElBQUksQ0FBQyxLQUFLLElBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBSSxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxjQUFjLElBQUUsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsSUFBRSxDQUFDLENBQUMsVUFBVSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLElBQUUsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssS0FBSSxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUssRUFBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFFLENBQUMsQ0FBQyxHQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLFVBQVUsSUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFJLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLGNBQWMsSUFBRSxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsVUFBVSxJQUFFLENBQUMsQ0FBQyxVQUFVLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsSUFBRSxDQUFDLENBQUMsVUFBVSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDO1FBQUMsSUFBSSxDQUFDLFNBQVMsS0FBRyxDQUFDLElBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLElBQUUsSUFBSSxFQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxHQUFHLElBQUUsQ0FBQyxDQUFDLEtBQUcsSUFBSSxDQUFDLFVBQVUsSUFBRSxDQUFDLEtBQUcsSUFBSSxDQUFDLFVBQVUsTUFBSSxDQUFDLEtBQUcsSUFBSSxDQUFDLEtBQUssSUFBRSxDQUFDLElBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEtBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsSUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLE9BQU8sR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUMsT0FBTyxDQUFDLElBQUUsSUFBSSxFQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFDLFFBQVEsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQTtJQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsZUFBZSxHQUFDLFlBQVU7TUFBQyxLQUFJLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxNQUFNLEVBQUMsQ0FBQyxHQUFFO1FBQUMsSUFBRyxDQUFDLENBQUMsT0FBTyxJQUFFLENBQUMsWUFBWSxDQUFDLElBQUUsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxDQUFDLEVBQUMsT0FBTSxDQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUs7TUFBQTtNQUFDLE9BQU0sQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsVUFBVTtNQUFDLEtBQUksSUFBSSxDQUFDLEdBQUMsRUFBRSxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsTUFBTSxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsVUFBVSxLQUFHLENBQUMsWUFBWSxDQUFDLEdBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUs7TUFBQyxPQUFPLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHO1FBQUMsQ0FBQyxHQUFDLEVBQUU7UUFBQyxDQUFDLEdBQUMsQ0FBQztNQUFDLEtBQUksQ0FBQyxJQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLEtBQUcsSUFBSSxJQUFFLENBQUMsSUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUFDLE9BQU8sQ0FBQyxJQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxLQUFJLElBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUMsQ0FBQyxHQUFFO1FBQUMsSUFBRyxDQUFDLEtBQUcsSUFBSSxFQUFDLE9BQU0sQ0FBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRO01BQUE7TUFBQyxPQUFNLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsYUFBYSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUM7TUFBQyxLQUFJLElBQUksQ0FBQyxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsTUFBTSxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsT0FBTyxFQUFDLENBQUMsR0FBRSxDQUFDLENBQUMsVUFBVSxJQUFFLENBQUMsS0FBRyxDQUFDLENBQUMsVUFBVSxJQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztNQUFDLElBQUcsQ0FBQyxFQUFDLEtBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUM7TUFBQyxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFHLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxFQUFDLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQztNQUFDLEtBQUksSUFBSSxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQyxPQUFPLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU07TUFBQyxLQUFJLElBQUksQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLFVBQVUsR0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQztNQUFDLE9BQU8sQ0FBQyxLQUFHLENBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsWUFBVTtNQUFDLEtBQUksSUFBSSxDQUFDLEdBQUMsSUFBSSxDQUFDLE1BQU0sRUFBQyxDQUFDLEdBQUUsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO01BQUMsT0FBTyxJQUFJO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsSUFBRyxDQUFDLEtBQUcsSUFBSSxDQUFDLEdBQUcsRUFBQyxLQUFJLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxNQUFNLEVBQUMsQ0FBQyxHQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO01BQUMsT0FBTyxDQUFDLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLE9BQU8sU0FBUyxDQUFDLE1BQU0sSUFBRSxDQUFDLEtBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsSUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxLQUFHLElBQUksQ0FBQyxNQUFNLElBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsYUFBYSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsSUFBRyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUM7UUFBQyxJQUFHLElBQUksQ0FBQyxNQUFNLEVBQUM7VUFBQyxLQUFJLElBQUksQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsS0FBSyxFQUFDLENBQUMsR0FBQyxZQUFZLEVBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxFQUFDLENBQUMsQ0FBQyxNQUFNLElBQUUsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLGFBQWEsSUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLElBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsVUFBVSxFQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsaUJBQWlCLEtBQUcsSUFBSSxDQUFDLFVBQVUsSUFBRSxDQUFDLENBQUMsVUFBVSxHQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLFVBQVUsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxDQUFDLENBQUMsY0FBYyxHQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUM7VUFBQyxJQUFJLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxjQUFjLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDO1FBQUE7UUFBQyxPQUFPLElBQUksQ0FBQyxjQUFjO01BQUE7TUFBQyxPQUFPLENBQUMsS0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxJQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLGNBQWMsR0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsWUFBVTtNQUFDLEtBQUksSUFBSSxDQUFDLEdBQUMsSUFBSSxDQUFDLFNBQVMsRUFBQyxDQUFDLENBQUMsU0FBUyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUztNQUFDLE9BQU8sQ0FBQyxLQUFHLENBQUMsQ0FBQyxtQkFBbUI7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxZQUFVO01BQUMsT0FBTyxJQUFJLENBQUMsT0FBTyxHQUFDLElBQUksQ0FBQyxVQUFVLEdBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVUsSUFBRSxJQUFJLENBQUMsVUFBVTtJQUFBLENBQUMsRUFBQyxDQUFDO0VBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDO0FBQUEsQ0FBQyxDQUFDLEVBQUMsTUFBTSxDQUFDLFNBQVMsSUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7Ozs7QUNYeHJUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLFVBQVMsQ0FBQyxFQUFDO0VBQUMsWUFBWTs7RUFBQyxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsZ0JBQWdCLElBQUUsQ0FBQztFQUFDLElBQUcsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFDO0lBQUMsSUFBSSxDQUFDO01BQUMsQ0FBQztNQUFDLENBQUM7TUFBQyxDQUFDO01BQUMsQ0FBQztNQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUM7UUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDO1FBQUMsT0FBTyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsZUFBZSxDQUFDO01BQUMsQ0FBQyxHQUFDLEtBQUs7TUFBQyxDQUFDLEdBQUMsRUFBRSxDQUFDLEtBQUs7TUFBQyxDQUFDLEdBQUMsU0FBQSxDQUFBLEVBQVUsQ0FBQyxDQUFDO01BQUMsQ0FBQyxHQUFDLFlBQVU7UUFBQyxJQUFJLENBQUMsR0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLFFBQVE7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFBQyxPQUFPLFVBQVMsQ0FBQyxFQUFDO1VBQUMsT0FBTyxJQUFJLElBQUUsQ0FBQyxLQUFHLENBQUMsWUFBWSxLQUFLLElBQUUsUUFBUSxJQUFFLE9BQU8sQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDO1FBQUEsQ0FBQztNQUFBLENBQUMsQ0FBQyxDQUFDO01BQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQztNQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDLEVBQUUsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksRUFBQyxJQUFJLENBQUMsT0FBTyxHQUFDLElBQUksRUFBQyxJQUFJLENBQUMsSUFBSSxHQUFDLENBQUM7UUFBQyxJQUFJLENBQUMsR0FBQyxFQUFFO1FBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxVQUFTLENBQUMsRUFBQztVQUFDLEtBQUksSUFBSSxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxFQUFFLE9BQU8sSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBQyxDQUFDLEVBQUUsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1VBQUMsSUFBRyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsRUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLGdCQUFnQixHQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsVUFBVSxJQUFFLE9BQU8sTUFBTSxJQUFFLE1BQU0sQ0FBQyxHQUFHLEdBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixHQUFDLENBQUMsQ0FBQyxnQkFBZ0IsR0FBQyxHQUFHLEdBQUMsRUFBRSxJQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFDLEVBQUUsRUFBQyxZQUFVO1lBQUMsT0FBTyxDQUFDO1VBQUEsQ0FBQyxDQUFDLEdBQUMsV0FBVyxJQUFFLE9BQU8sTUFBTSxJQUFFLE1BQU0sQ0FBQyxPQUFPLEtBQUcsTUFBTSxDQUFDLE9BQU8sR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFDLENBQUMsRUFBRSxFQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7UUFBQSxDQUFDLEVBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUFBLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxPQUFPLENBQUMsR0FBQyxDQUFDLElBQUUsWUFBVSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsRUFBQyxZQUFVO1VBQUMsT0FBTyxDQUFDO1FBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUM7TUFBQSxDQUFDO0lBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDO0lBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsRUFBRTtNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsYUFBYSxFQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLElBQUksQ0FBQyxNQUFNLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxJQUFJLENBQUMsT0FBTyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUM7TUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLEtBQUksSUFBSSxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLDBCQUEwQixFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsRUFBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxDQUFELENBQUM7TUFBQSxDQUFDO0lBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxJQUFHLElBQUksQ0FBQyxLQUFLLEVBQUMsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztNQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxNQUFNO1FBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxFQUFFLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUM7TUFBQyxPQUFPLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxFQUFFLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLFFBQVEsRUFBQyxNQUFNLEVBQUMsT0FBTyxFQUFDLE9BQU8sRUFBQyxjQUFjLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLFFBQVEsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBQyxJQUFJLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxTQUFTLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFDLElBQUksRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLFFBQVEsSUFBRSxDQUFDLEtBQUcsQ0FBQyxHQUFDLFdBQVcsR0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLEVBQUMsSUFBSSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsV0FBVyxDQUFDO0lBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTO0lBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLHdCQUF3QixFQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsSUFBSSxDQUFDLFVBQVUsR0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsWUFBWSxHQUFDLENBQUMsSUFBRSxJQUFJO0lBQUEsQ0FBQyxDQUFDO0lBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUMsQ0FBQyxDQUFDLGdCQUFnQixHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQztNQUFDLEtBQUksSUFBSSxJQUFFLENBQUMsS0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxFQUFFLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxDQUFDLEVBQUMsQ0FBQztRQUFDLENBQUMsRUFBQyxDQUFDO1FBQUMsRUFBRSxFQUFDLENBQUM7UUFBQyxFQUFFLEVBQUM7TUFBQyxDQUFDLENBQUMsRUFBQyxJQUFJLEtBQUcsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLG1CQUFtQixHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztNQUFDLElBQUcsQ0FBQyxFQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsSUFBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsRUFBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLEtBQUssQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsYUFBYSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsSUFBSSxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7TUFBQyxJQUFHLENBQUMsRUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsWUFBWSxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQztRQUFDLElBQUksRUFBQyxDQUFDO1FBQUMsTUFBTSxFQUFDO01BQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUM7SUFBQSxDQUFDO0lBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLHFCQUFxQjtNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsb0JBQW9CO01BQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLElBQUUsWUFBVTtRQUFDLE9BQU8sSUFBSSxJQUFJLENBQUQsQ0FBQyxDQUFFLE9BQU8sQ0FBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQztJQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsSUFBSSxFQUFDLEtBQUssRUFBQyxRQUFRLEVBQUMsR0FBRyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsdUJBQXVCLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxzQkFBc0IsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsNkJBQTZCLENBQUM7SUFBQyxDQUFDLENBQUMsUUFBUSxFQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsSUFBSTtRQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQztRQUFDLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLElBQUUsQ0FBQztRQUFDLENBQUMsR0FBQyxHQUFHO1FBQUMsQ0FBQyxHQUFDLEVBQUU7UUFBQyxDQUFDLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQztVQUFDLElBQUksQ0FBQztZQUFDLENBQUM7WUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsR0FBRyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsQ0FBQyxNQUFJLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLEdBQUMsSUFBSSxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQztRQUFBLENBQUM7TUFBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxZQUFVO1FBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxZQUFZLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsWUFBVTtRQUFDLElBQUksSUFBRSxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksRUFBQyxDQUFDLEtBQUcsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsWUFBVTtRQUFDLElBQUksS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxFQUFFLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxVQUFTLENBQUMsRUFBQztVQUFDLE9BQU8sVUFBVSxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsR0FBRyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDO1FBQUEsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLFVBQVMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxTQUFTLENBQUMsTUFBTSxJQUFFLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLElBQUUsRUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxJQUFJLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLEtBQUssQ0FBQyxJQUFFLENBQUM7TUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxVQUFTLENBQUMsRUFBQztRQUFDLE9BQU8sU0FBUyxDQUFDLE1BQU0sSUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUMsS0FBSyxDQUFDLElBQUUsQ0FBQztNQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDLFVBQVUsQ0FBQyxZQUFVO1FBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUFBLENBQUMsRUFBQyxJQUFJLENBQUM7SUFBQSxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLEdBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBRCxDQUFDLEVBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLENBQUMsTUFBTTtJQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxnQkFBZ0IsRUFBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFHLElBQUksQ0FBQyxJQUFJLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxjQUFjLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxJQUFJLENBQUMsTUFBTSxHQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUUsQ0FBQyxFQUFDLElBQUksQ0FBQyxVQUFVLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLGVBQWUsS0FBRyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUMsSUFBSSxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsUUFBUSxLQUFHLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7UUFBQyxJQUFJLENBQUMsR0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsR0FBQyxDQUFDLEdBQUMsQ0FBQztRQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sSUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQUE7SUFBQyxDQUFDLENBQUM7SUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUQsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsWUFBWSxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDLENBQUM7SUFBQyxJQUFJLENBQUMsR0FBQyxTQUFBLENBQUEsRUFBVTtNQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxHQUFHLElBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsVUFBVSxDQUFDLENBQUMsRUFBQyxHQUFHLENBQUM7SUFBQSxDQUFDO0lBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxJQUFFLENBQUMsSUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsT0FBTyxJQUFJLElBQUUsQ0FBQyxJQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksSUFBRSxDQUFDLElBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsR0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsT0FBTyxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxJQUFFLENBQUMsSUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsWUFBVSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsVUFBVSxHQUFDLFlBQVU7TUFBQyxPQUFPLElBQUk7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxZQUFVO01BQUMsSUFBSSxDQUFDO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxTQUFTO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxVQUFVO01BQUMsT0FBTSxDQUFDLENBQUMsSUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLEdBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVUsR0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsT0FBTyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsT0FBTyxHQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksRUFBQyxJQUFJLENBQUMsVUFBVSxHQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsUUFBUSxJQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLElBQUksRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsWUFBVTtNQUFDLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSTtJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsS0FBSSxJQUFJLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxHQUFDLElBQUksQ0FBQyxRQUFRLEVBQUMsQ0FBQyxHQUFFLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRO01BQUMsT0FBTyxJQUFJO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxpQkFBaUIsR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLEtBQUksSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsUUFBUSxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDO01BQUMsT0FBTyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxhQUFhLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFHLElBQUksS0FBRyxDQUFDLENBQUMsSUFBRSxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxJQUFJO1FBQUMsSUFBRyxDQUFDLEtBQUcsU0FBUyxDQUFDLE1BQU0sRUFBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQyxJQUFJLElBQUUsQ0FBQyxHQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxRQUFRLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEdBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLE9BQU8sQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLFVBQVUsS0FBRyxDQUFDLEtBQUcsSUFBSSxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUM7TUFBQTtNQUFDLE9BQU8sSUFBSTtJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsT0FBTyxTQUFTLENBQUMsTUFBTSxJQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsaUJBQWlCLElBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUMsSUFBSSxDQUFDLE1BQU0sR0FBQyxDQUFDLEVBQUMsSUFBSSxJQUFFLElBQUksQ0FBQyxNQUFNO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxPQUFPLFNBQVMsQ0FBQyxNQUFNLElBQUUsSUFBSSxDQUFDLFNBQVMsR0FBQyxJQUFJLENBQUMsY0FBYyxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsSUFBRSxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxTQUFTLElBQUUsQ0FBQyxLQUFHLENBQUMsSUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUUsQ0FBQyxHQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksS0FBRyxJQUFJLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxTQUFTLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLGFBQWEsR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsRUFBQyxTQUFTLENBQUMsTUFBTSxHQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLGNBQWM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLFNBQVMsQ0FBQyxNQUFNLElBQUUsSUFBSSxDQUFDLE1BQU0sSUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxTQUFTLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxLQUFLO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLENBQUMsU0FBUyxDQUFDLE1BQU0sRUFBQyxPQUFPLElBQUksQ0FBQyxVQUFVO01BQUMsSUFBRyxJQUFJLENBQUMsU0FBUyxFQUFDO1FBQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsaUJBQWlCLEVBQUM7VUFBQyxJQUFJLENBQUMsTUFBTSxJQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztVQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxjQUFjO1lBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxTQUFTO1VBQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsVUFBVSxHQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sR0FBQyxJQUFJLENBQUMsVUFBVSxHQUFDLENBQUMsQ0FBQyxLQUFLLElBQUUsQ0FBQyxJQUFJLENBQUMsU0FBUyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxVQUFVLEVBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBQyxPQUFLLENBQUMsQ0FBQyxTQUFTLEdBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEtBQUcsQ0FBQyxDQUFDLENBQUMsVUFBVSxHQUFDLENBQUMsQ0FBQyxVQUFVLElBQUUsQ0FBQyxDQUFDLFVBQVUsSUFBRSxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVM7UUFBQTtRQUFDLElBQUksQ0FBQyxHQUFHLElBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBSSxDQUFDLFVBQVUsS0FBRyxDQUFDLElBQUUsQ0FBQyxLQUFHLElBQUksQ0FBQyxTQUFTLE1BQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQUE7TUFBQyxPQUFPLElBQUk7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsYUFBYSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sU0FBUyxDQUFDLE1BQU0sR0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsU0FBUyxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsT0FBTyxTQUFTLENBQUMsTUFBTSxJQUFFLENBQUMsS0FBRyxJQUFJLENBQUMsVUFBVSxLQUFHLElBQUksQ0FBQyxVQUFVLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxRQUFRLElBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxhQUFhLElBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxJQUFJLElBQUUsSUFBSSxDQUFDLFVBQVU7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLElBQUcsQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFDLE9BQU8sSUFBSSxDQUFDLFVBQVU7TUFBQyxJQUFHLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLElBQUksQ0FBQyxTQUFTLElBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsRUFBQztRQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxVQUFVO1VBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQUMsSUFBSSxDQUFDLFVBQVUsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVUsSUFBRSxJQUFJLENBQUMsVUFBVSxHQUFDLENBQUM7TUFBQTtNQUFDLE9BQU8sSUFBSSxDQUFDLFVBQVUsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsT0FBTyxTQUFTLENBQUMsTUFBTSxJQUFFLENBQUMsSUFBRSxJQUFJLENBQUMsU0FBUyxLQUFHLElBQUksQ0FBQyxTQUFTLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsSUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsaUJBQWlCLEdBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVUsR0FBQyxJQUFJLENBQUMsVUFBVSxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLElBQUUsSUFBSSxDQUFDLFNBQVM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLElBQUcsQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFDLE9BQU8sSUFBSSxDQUFDLE9BQU87TUFBQyxJQUFHLENBQUMsSUFBRSxJQUFJLENBQUMsT0FBTyxJQUFFLElBQUksQ0FBQyxTQUFTLEVBQUM7UUFBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxTQUFTO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVU7UUFBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsaUJBQWlCLEtBQUcsSUFBSSxDQUFDLFVBQVUsSUFBRSxDQUFDLEVBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFVBQVUsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksRUFBQyxJQUFJLENBQUMsT0FBTyxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsT0FBTyxHQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsSUFBSSxDQUFDLFFBQVEsSUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsR0FBQyxJQUFJLENBQUMsVUFBVSxHQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxVQUFVLElBQUUsSUFBSSxDQUFDLFVBQVUsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQztNQUFBO01BQUMsT0FBTyxJQUFJLENBQUMsR0FBRyxJQUFFLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJO0lBQUEsQ0FBQztJQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxxQkFBcUIsRUFBQyxVQUFTLENBQUMsRUFBQztNQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsa0JBQWtCLEdBQUMsSUFBSSxDQUFDLGlCQUFpQixHQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsQ0FBQztJQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxDQUFELENBQUMsRUFBQyxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLElBQUksRUFBQyxDQUFDLENBQUMsYUFBYSxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUMsRUFBQyxDQUFDO01BQUMsSUFBRyxDQUFDLENBQUMsVUFBVSxHQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxDQUFDLENBQUMsT0FBTyxJQUFFLElBQUksS0FBRyxDQUFDLENBQUMsU0FBUyxLQUFHLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLElBQUUsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLElBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLElBQUksRUFBQyxDQUFDLENBQUMsR0FBRyxJQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUssRUFBQyxJQUFJLENBQUMsYUFBYSxFQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztNQUFDLE9BQU8sQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxNQUFNLEVBQUMsSUFBSSxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsU0FBUyxJQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsT0FBTyxDQUFDLENBQUMsUUFBUSxLQUFHLElBQUksS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxJQUFJLENBQUMsTUFBTSxLQUFHLENBQUMsS0FBRyxJQUFJLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLEtBQUssS0FBRyxDQUFDLEtBQUcsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUMsSUFBSSxDQUFDLFNBQVMsSUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsTUFBTTtNQUFDLEtBQUksSUFBSSxDQUFDLFVBQVUsR0FBQyxJQUFJLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxZQUFZLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLElBQUUsQ0FBQyxJQUFFLENBQUMsQ0FBQyxVQUFVLElBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxNQUFJLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLGNBQWMsSUFBRSxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsVUFBVSxJQUFFLENBQUMsQ0FBQyxVQUFVLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsSUFBRSxDQUFDLENBQUMsVUFBVSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsWUFBVTtNQUFDLE9BQU8sQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxVQUFVO0lBQUEsQ0FBQztJQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEVBQUMsSUFBSSxJQUFFLENBQUMsRUFBQyxNQUFLLDZCQUE2QjtRQUFDLElBQUksQ0FBQyxNQUFNLEdBQUMsQ0FBQyxHQUFDLFFBQVEsSUFBRSxPQUFPLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBRSxDQUFDLENBQUMsTUFBTSxJQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQztVQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVM7UUFBQyxJQUFHLElBQUksQ0FBQyxVQUFVLEdBQUMsQ0FBQyxHQUFDLElBQUksSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFDLFFBQVEsSUFBRSxPQUFPLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBRSxDQUFDLFlBQVksS0FBSyxJQUFFLENBQUMsQ0FBQyxJQUFJLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLFFBQVEsSUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxLQUFJLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxXQUFXLEdBQUMsRUFBRSxFQUFDLElBQUksQ0FBQyxTQUFTLEdBQUMsRUFBRSxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsUUFBUSxJQUFFLE9BQU8sQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLElBQUUsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLElBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsUUFBUSxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxFQUFDLElBQUksRUFBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsUUFBUSxJQUFFLE9BQU8sQ0FBQyxJQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsV0FBVyxHQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksRUFBQyxJQUFJLEVBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxTQUFTLENBQUM7UUFBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsZUFBZSxJQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxLQUFHLElBQUksQ0FBQyxNQUFNLElBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLEtBQUcsQ0FBQyxDQUFDLE1BQUksSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO01BQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDO01BQUMsQ0FBQyxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUM7UUFBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLElBQUUsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUUsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUM7UUFBQyxLQUFJLENBQUMsSUFBSSxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsSUFBSSxDQUFDLElBQUUsV0FBVyxLQUFHLENBQUMsSUFBRSxHQUFHLEtBQUcsQ0FBQyxJQUFFLEdBQUcsS0FBRyxDQUFDLElBQUUsT0FBTyxLQUFHLENBQUMsSUFBRSxRQUFRLEtBQUcsQ0FBQyxJQUFFLFdBQVcsS0FBRyxDQUFDLElBQUUsUUFBUSxLQUFHLENBQUMsSUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQztNQUFBLENBQUM7SUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxJQUFJLENBQUMsQ0FBRCxDQUFDLEVBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsaUJBQWlCLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLHVCQUF1QixHQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxRQUFRLEVBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBQyxJQUFJLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxnQkFBZ0IsR0FBQyxNQUFNLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsWUFBWSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLE1BQU0sSUFBRSxVQUFTLENBQUMsRUFBQztNQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsY0FBYyxDQUFDLEdBQUcsS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQztJQUFBLENBQUM7SUFBQyxJQUFJLENBQUMsR0FBQyxFQUFFO01BQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsVUFBVSxHQUFDO1FBQUMsT0FBTyxFQUFDLENBQUM7UUFBQyxVQUFVLEVBQUMsQ0FBQztRQUFDLFVBQVUsRUFBQztNQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsYUFBYSxHQUFDO1FBQUMsSUFBSSxFQUFDLENBQUM7UUFBQyxLQUFLLEVBQUMsQ0FBQztRQUFDLFNBQVMsRUFBQyxDQUFDO1FBQUMsVUFBVSxFQUFDLENBQUM7UUFBQyxnQkFBZ0IsRUFBQyxDQUFDO1FBQUMsZUFBZSxFQUFDLENBQUM7UUFBQyxTQUFTLEVBQUMsQ0FBQztRQUFDLFlBQVksRUFBQyxDQUFDO1FBQUMsT0FBTyxFQUFDLENBQUM7UUFBQyxRQUFRLEVBQUMsQ0FBQztRQUFDLGNBQWMsRUFBQyxDQUFDO1FBQUMsYUFBYSxFQUFDLENBQUM7UUFBQyxPQUFPLEVBQUMsQ0FBQztRQUFDLGFBQWEsRUFBQyxDQUFDO1FBQUMsWUFBWSxFQUFDLENBQUM7UUFBQyxpQkFBaUIsRUFBQyxDQUFDO1FBQUMsdUJBQXVCLEVBQUMsQ0FBQztRQUFDLHNCQUFzQixFQUFDLENBQUM7UUFBQyxRQUFRLEVBQUMsQ0FBQztRQUFDLGNBQWMsRUFBQyxDQUFDO1FBQUMsYUFBYSxFQUFDLENBQUM7UUFBQyxVQUFVLEVBQUMsQ0FBQztRQUFDLElBQUksRUFBQyxDQUFDO1FBQUMsZUFBZSxFQUFDLENBQUM7UUFBQyxNQUFNLEVBQUMsQ0FBQztRQUFDLFdBQVcsRUFBQyxDQUFDO1FBQUMsSUFBSSxFQUFDLENBQUM7UUFBQyxNQUFNLEVBQUMsQ0FBQztRQUFDLFFBQVEsRUFBQyxDQUFDO1FBQUMsT0FBTyxFQUFDLENBQUM7UUFBQyxJQUFJLEVBQUM7TUFBQyxDQUFDO01BQUMsQ0FBQyxHQUFDO1FBQUMsSUFBSSxFQUFDLENBQUM7UUFBQyxHQUFHLEVBQUMsQ0FBQztRQUFDLElBQUksRUFBQyxDQUFDO1FBQUMsVUFBVSxFQUFDLENBQUM7UUFBQyxVQUFVLEVBQUMsQ0FBQztRQUFDLFdBQVcsRUFBQyxDQUFDO1FBQUMsTUFBTSxFQUFDLENBQUM7UUFBQyxPQUFPLEVBQUM7TUFBQyxDQUFDO01BQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxtQkFBbUIsR0FBQyxJQUFJLENBQUMsQ0FBRCxDQUFDO01BQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxhQUFhLEdBQUMsSUFBSSxDQUFDLENBQUQsQ0FBQztNQUFDLENBQUMsR0FBQyxTQUFBLENBQUEsRUFBVTtRQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNO1FBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEtBQUssS0FBRyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDO01BQUEsQ0FBQztJQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxDQUFDLElBQUksRUFBQyxDQUFDLENBQUMsVUFBVSxHQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDLENBQUMsT0FBTyxHQUFDLENBQUMsQ0FBQyxFQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLFlBQVU7TUFBQyxJQUFJLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQztNQUFDLElBQUcsQ0FBQyxDQUFDLE1BQU0sSUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxVQUFVLElBQUUsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxVQUFVLElBQUUsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLElBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLEdBQUMsR0FBRyxDQUFDLEVBQUM7UUFBQyxLQUFJLENBQUMsSUFBSSxDQUFDLEVBQUM7VUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO1VBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxNQUFNLElBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUE7UUFBQyxJQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLE9BQU8sS0FBRyxDQUFDLENBQUMsU0FBUyxJQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBRSxDQUFDLEtBQUcsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFDO1VBQUMsT0FBSyxDQUFDLElBQUUsQ0FBQyxDQUFDLE9BQU8sR0FBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUs7VUFBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQUE7TUFBQztJQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxXQUFXLENBQUM7SUFBQyxJQUFJLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxJQUFJLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVO1FBQUMsSUFBRyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDO1VBQUMsTUFBTSxFQUFDLENBQUM7VUFBQyxNQUFNLEVBQUM7UUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLE9BQUssRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7UUFBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQztRQUFDLElBQUcsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxFQUFDO1VBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFFLEVBQUMsSUFBRyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQUksQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLElBQUUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssSUFBRyxDQUFDLEtBQUcsQ0FBQyxFQUFDO1VBQU0sT0FBTyxDQUFDO1FBQUE7UUFBQyxJQUFJLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLEVBQUU7VUFBQyxDQUFDLEdBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLFNBQVM7UUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBSSxDQUFDLElBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBRSxDQUFDLENBQUMsT0FBTyxLQUFHLENBQUMsQ0FBQyxTQUFTLEtBQUcsQ0FBQyxDQUFDLFNBQVMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLFVBQVUsSUFBRSxDQUFDLENBQUMsVUFBVSxHQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsS0FBRyxLQUFLLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLEtBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBRSxDQUFDLENBQUMsUUFBUSxLQUFHLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQyxPQUFPLENBQUM7TUFBQSxDQUFDO01BQUMsQ0FBQyxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLEtBQUksSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLENBQUMsU0FBUyxHQUFFO1VBQUMsSUFBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLFVBQVUsRUFBQyxDQUFDLENBQUMsT0FBTyxFQUFDLE9BQU0sQ0FBQyxHQUFHO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTO1FBQUE7UUFBQyxPQUFPLENBQUMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxhQUFhLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQztNQUFBLENBQUM7SUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLFlBQVU7TUFBQyxJQUFJLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxJQUFJO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxpQkFBaUI7UUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFNBQVM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxlQUFlO1FBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJO01BQUMsSUFBRyxDQUFDLENBQUMsT0FBTyxFQUFDO1FBQUMsSUFBSSxDQUFDLFFBQVEsS0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUM7UUFBQyxLQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztRQUFDLElBQUcsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsZUFBZSxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLEtBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLElBQUksRUFBQyxJQUFJLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLElBQUcsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFFBQVEsR0FBQyxJQUFJLENBQUMsS0FBSyxJQUFHLENBQUMsS0FBRyxDQUFDLEVBQUM7TUFBTSxDQUFDLE1BQUssSUFBRyxDQUFDLENBQUMsWUFBWSxJQUFFLENBQUMsS0FBRyxDQUFDLEVBQUMsSUFBRyxJQUFJLENBQUMsUUFBUSxFQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxRQUFRLEdBQUMsSUFBSSxDQUFDLEtBQUk7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO1FBQUMsS0FBSSxDQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxTQUFTLEtBQUcsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQyxJQUFHLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsYUFBYSxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLEtBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLGVBQWUsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztVQUFDLElBQUcsQ0FBQyxLQUFHLElBQUksQ0FBQyxLQUFLLEVBQUM7UUFBTSxDQUFDLE1BQUssSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQUE7TUFBQyxJQUFHLElBQUksQ0FBQyxLQUFLLEdBQUMsQ0FBQyxHQUFDLENBQUMsWUFBWSxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsWUFBWSxLQUFLLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBQyxDQUFDLEdBQUMsVUFBVSxJQUFFLE9BQU8sQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxXQUFXLEdBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBQyxJQUFJLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFDLElBQUksQ0FBQyxVQUFVLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUMsSUFBSSxDQUFDLFFBQVEsR0FBQyxJQUFJLEVBQUMsSUFBSSxDQUFDLFFBQVEsRUFBQyxLQUFJLENBQUMsR0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFDLElBQUksQ0FBQyxXQUFXLEVBQUMsSUFBSSxDQUFDLFNBQVMsRUFBQyxDQUFDLENBQUM7TUFBQyxJQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsY0FBYyxDQUFDLGlCQUFpQixFQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsS0FBRyxJQUFJLENBQUMsUUFBUSxJQUFFLFVBQVUsSUFBRSxPQUFPLElBQUksQ0FBQyxNQUFNLElBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFlBQVksRUFBQyxLQUFJLENBQUMsR0FBQyxJQUFJLENBQUMsUUFBUSxFQUFDLENBQUMsR0FBRSxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO01BQUMsSUFBSSxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsUUFBUSxFQUFDLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQztNQUFDLElBQUcsSUFBSSxJQUFFLENBQUMsRUFBQyxPQUFNLENBQUMsQ0FBQztNQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBRSxDQUFDLENBQUMsS0FBSyxJQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLFFBQVEsSUFBRSxDQUFDLENBQUMsR0FBRyxJQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxLQUFHLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQztNQUFDLEtBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUM7UUFBQyxJQUFHLENBQUMsR0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxZQUFZLEtBQUssSUFBRSxDQUFDLENBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFELENBQUMsRUFBRSxZQUFZLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEVBQUM7VUFBQyxLQUFJLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxHQUFDO1lBQUMsS0FBSyxFQUFDLElBQUksQ0FBQyxRQUFRO1lBQUMsQ0FBQyxFQUFDLENBQUM7WUFBQyxDQUFDLEVBQUMsVUFBVTtZQUFDLENBQUMsRUFBQyxDQUFDO1lBQUMsQ0FBQyxFQUFDLENBQUM7WUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO1lBQUMsQ0FBQyxFQUFDLENBQUM7WUFBQyxFQUFFLEVBQUMsQ0FBQyxDQUFDO1lBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQztVQUFTLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsUUFBUTtVQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsSUFBRSxDQUFDLENBQUMsZUFBZSxNQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsSUFBRSxDQUFDLENBQUMsU0FBUyxNQUFJLElBQUksQ0FBQyx1QkFBdUIsR0FBQyxDQUFDLENBQUMsQ0FBQztRQUFBLENBQUMsTUFBSyxJQUFJLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUM7VUFBQyxLQUFLLEVBQUMsSUFBSSxDQUFDLFFBQVE7VUFBQyxDQUFDLEVBQUMsQ0FBQztVQUFDLENBQUMsRUFBQyxDQUFDO1VBQUMsQ0FBQyxFQUFDLFVBQVUsSUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7VUFBQyxDQUFDLEVBQUMsQ0FBQztVQUFDLEVBQUUsRUFBQyxDQUFDLENBQUM7VUFBQyxFQUFFLEVBQUM7UUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFFLFVBQVUsSUFBRSxPQUFPLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxRQUFRLElBQUUsT0FBTyxDQUFDLElBQUUsR0FBRyxLQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxFQUFDLEVBQUUsQ0FBQyxHQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQztRQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBSyxLQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQztNQUFBO01BQUMsT0FBTyxDQUFDLElBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsVUFBVSxHQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsUUFBUSxJQUFFLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxFQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsVUFBVSxFQUFDLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUcsSUFBSSxDQUFDLFFBQVEsS0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksS0FBRyxDQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsU0FBUyxJQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsSUFBSSxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxTQUFTO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxZQUFZO01BQUMsSUFBRyxDQUFDLElBQUUsQ0FBQyxFQUFDLElBQUksQ0FBQyxVQUFVLEdBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsR0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFNBQVMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLFlBQVksQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEtBQUcsSUFBSSxDQUFDLFFBQVEsSUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxVQUFVLEtBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEtBQUcsQ0FBQyxLQUFHLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsbUJBQW1CLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxZQUFZLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUcsSUFBSSxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsVUFBVSxHQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsTUFBSSxDQUFDLEdBQUMsbUJBQW1CLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsS0FBRyxJQUFJLENBQUMsUUFBUSxJQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLElBQUUsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsWUFBWSxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLFFBQVEsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUcsSUFBSSxDQUFDLFVBQVUsR0FBQyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsU0FBUyxFQUFDO1FBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFNBQVM7VUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFVBQVU7UUFBQyxDQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLElBQUUsRUFBRSxNQUFJLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxLQUFHLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsRUFBRSxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUM7TUFBQSxDQUFDLE1BQUssSUFBSSxDQUFDLEtBQUssR0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO01BQUMsSUFBRyxJQUFJLENBQUMsS0FBSyxLQUFHLENBQUMsSUFBRSxDQUFDLEVBQUM7UUFBQyxJQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBQztVQUFDLElBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFFLElBQUksQ0FBQyxHQUFHLEVBQUM7VUFBTyxJQUFHLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxRQUFRLEtBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUcsQ0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLFNBQVMsSUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksSUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBQyxPQUFPLElBQUksQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLFVBQVUsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFlBQVksR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxLQUFLLENBQUM7VUFBQyxJQUFJLENBQUMsS0FBSyxJQUFFLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEtBQUcsSUFBSSxDQUFDLEtBQUssR0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEtBQUcsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQTtRQUFDLEtBQUksSUFBSSxDQUFDLEtBQUssS0FBRyxDQUFDLENBQUMsS0FBRyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLE9BQU8sSUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUUsSUFBSSxDQUFDLEtBQUssS0FBRyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsS0FBRyxJQUFJLENBQUMsT0FBTyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsS0FBRyxJQUFJLENBQUMsUUFBUSxLQUFHLENBQUMsSUFBRSxDQUFDLEdBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEtBQUcsQ0FBQyxLQUFHLElBQUksQ0FBQyxLQUFLLElBQUUsQ0FBQyxLQUFHLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLElBQUUsSUFBSSxFQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFFBQVEsRUFBQyxDQUFDLEdBQUUsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztRQUFDLElBQUksQ0FBQyxTQUFTLEtBQUcsQ0FBQyxHQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsUUFBUSxJQUFFLElBQUksQ0FBQyxVQUFVLElBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxLQUFHLENBQUMsSUFBRSxDQUFDLEtBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLElBQUUsSUFBSSxFQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxHQUFHLEtBQUcsQ0FBQyxHQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsUUFBUSxJQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsSUFBRSxJQUFJLENBQUMsVUFBVSxJQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsa0JBQWtCLElBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFDLE9BQU8sQ0FBQyxJQUFFLElBQUksRUFBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxRQUFRLENBQUMsSUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLElBQUksQ0FBQyxZQUFZLEtBQUcsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEtBQUcsSUFBSSxDQUFDLFlBQVksR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQUE7SUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFHLEtBQUssS0FBRyxDQUFDLEtBQUcsQ0FBQyxHQUFDLElBQUksQ0FBQyxFQUFDLElBQUksSUFBRSxDQUFDLEtBQUcsSUFBSSxJQUFFLENBQUMsSUFBRSxDQUFDLEtBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFDLE9BQU8sSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDO01BQUMsQ0FBQyxHQUFDLFFBQVEsSUFBRSxPQUFPLENBQUMsR0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLFFBQVEsSUFBRSxJQUFJLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQztNQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUM7TUFBQyxJQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBRyxRQUFRLElBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFJO1FBQUMsSUFBRyxJQUFJLENBQUMsUUFBUSxFQUFDO1VBQUMsS0FBSSxDQUFDLEdBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsSUFBRyxDQUFDLEtBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQztZQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxpQkFBaUIsR0FBQyxJQUFJLENBQUMsaUJBQWlCLElBQUUsRUFBRSxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsR0FBQyxLQUFLO1lBQUM7VUFBSztRQUFDLENBQUMsTUFBSTtVQUFDLElBQUcsQ0FBQyxLQUFHLElBQUksQ0FBQyxNQUFNLEVBQUMsT0FBTSxDQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFdBQVcsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLGlCQUFpQixHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsaUJBQWlCLElBQUUsQ0FBQyxDQUFDLEdBQUMsS0FBSztRQUFBO1FBQUMsSUFBRyxDQUFDLEVBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxLQUFLLEtBQUcsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEtBQUcsUUFBUSxJQUFFLE9BQU8sQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztVQUFDLEtBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQUksQ0FBQyxDQUFDLEVBQUUsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBRSxJQUFFLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxNQUFNLEtBQUcsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsS0FBRyxJQUFJLENBQUMsUUFBUSxLQUFHLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxJQUFJLENBQUMsRUFBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO1VBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFFLElBQUksQ0FBQyxRQUFRLElBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQztRQUFBO01BQUM7TUFBQyxPQUFPLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxZQUFVO01BQUMsT0FBTyxJQUFJLENBQUMsdUJBQXVCLElBQUUsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxZQUFZLEVBQUMsSUFBSSxDQUFDLEVBQUMsSUFBSSxDQUFDLFFBQVEsR0FBQyxJQUFJLEVBQUMsSUFBSSxDQUFDLGlCQUFpQixHQUFDLElBQUksRUFBQyxJQUFJLENBQUMsU0FBUyxHQUFDLElBQUksRUFBQyxJQUFJLENBQUMsUUFBUSxHQUFDLElBQUksRUFBQyxJQUFJLENBQUMsUUFBUSxHQUFDLElBQUksQ0FBQyxPQUFPLEdBQUMsSUFBSSxDQUFDLHVCQUF1QixHQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFdBQVcsR0FBQyxJQUFJLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxHQUFDLEVBQUUsRUFBQyxJQUFJO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsSUFBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxHQUFHLEVBQUM7UUFBQyxJQUFJLENBQUM7VUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFFBQVE7UUFBQyxJQUFHLENBQUMsRUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUksQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQyxDQUFDO01BQUE7TUFBQyxPQUFPLENBQUMsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyx1QkFBdUIsSUFBRSxJQUFJLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxjQUFjLENBQUMsQ0FBQyxHQUFDLFdBQVcsR0FBQyxZQUFZLEVBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsT0FBTyxDQUFDLENBQUMsWUFBWSxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxlQUFlLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxlQUFlLEVBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLGVBQWUsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLGVBQWUsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLGVBQWUsRUFBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsV0FBVyxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLEtBQUssRUFBQyxDQUFDO1FBQUMsVUFBVSxFQUFDLENBQUM7UUFBQyxnQkFBZ0IsRUFBQyxDQUFDO1FBQUMsZUFBZSxFQUFDLENBQUM7UUFBQyxpQkFBaUIsRUFBQyxDQUFDO1FBQUMsdUJBQXVCLEVBQUMsQ0FBQztRQUFDLHNCQUFzQixFQUFDLENBQUM7UUFBQyxlQUFlLEVBQUMsQ0FBQyxDQUFDO1FBQUMsU0FBUyxFQUFDLENBQUM7UUFBQyxTQUFTLEVBQUM7TUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsSUFBRyxJQUFJLElBQUUsQ0FBQyxFQUFDLE9BQU0sRUFBRTtNQUFDLENBQUMsR0FBQyxRQUFRLElBQUUsT0FBTyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQztNQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQztNQUFDLElBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLFFBQVEsSUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQztRQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxHQUFDLEVBQUUsRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQztRQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7TUFBQSxDQUFDLE1BQUssS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztNQUFDLE9BQU8sQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsWUFBWSxHQUFDLENBQUMsQ0FBQyxrQkFBa0IsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsUUFBUSxJQUFFLE9BQU8sQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDO01BQUMsS0FBSSxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDO0lBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLHFCQUFxQixFQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQyxlQUFlLEdBQUMsQ0FBQyxDQUFDLElBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBQyxJQUFJLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFNBQVMsR0FBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLElBQUksQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLFNBQVM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7SUFBQyxJQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxFQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsUUFBUSxFQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQyxFQUFDLENBQUM7TUFBQyxPQUFPLElBQUksSUFBRSxDQUFDLEtBQUcsQ0FBQyxHQUFDLFFBQVEsSUFBRSxPQUFPLENBQUMsSUFBRSxHQUFHLEtBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsRUFBQyxFQUFFLENBQUMsR0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLFFBQVEsR0FBQyxDQUFDLEdBQUM7UUFBQyxLQUFLLEVBQUMsSUFBSSxDQUFDLFFBQVE7UUFBQyxDQUFDLEVBQUMsQ0FBQztRQUFDLENBQUMsRUFBQyxDQUFDO1FBQUMsQ0FBQyxFQUFDLENBQUM7UUFBQyxDQUFDLEVBQUMsQ0FBQztRQUFDLENBQUMsRUFBQyxVQUFVLElBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDO1FBQUMsQ0FBQyxFQUFDO01BQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUcsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFFLEtBQUssQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsS0FBSSxJQUFJLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFFBQVEsRUFBQyxDQUFDLEdBQUMsSUFBSSxFQUFDLENBQUMsR0FBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUs7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsZUFBZTtRQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsUUFBUTtNQUFDLElBQUcsSUFBSSxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUMsSUFBSSxDQUFDLGVBQWUsR0FBQyxFQUFFLENBQUMsS0FBSyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLElBQUksSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO01BQUMsT0FBSyxDQUFDLEdBQUUsSUFBSSxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLEtBQUssS0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssSUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsSUFBSSxJQUFFLElBQUksQ0FBQyxRQUFRLEtBQUcsQ0FBQyxLQUFHLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO01BQUMsT0FBTSxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxLQUFJLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxRQUFRLEVBQUMsQ0FBQyxHQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBRSxJQUFJLElBQUUsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQVMsR0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsTUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsY0FBYyxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVE7TUFBQyxJQUFHLGlCQUFpQixLQUFHLENBQUMsRUFBQztRQUFDLE9BQUssQ0FBQyxHQUFFO1VBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsRUFBRSxHQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO1VBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUM7UUFBQTtRQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUM7TUFBQTtNQUFDLE9BQUssQ0FBQyxHQUFFLENBQUMsQ0FBQyxFQUFFLElBQUUsVUFBVSxJQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUs7TUFBQyxPQUFPLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLEtBQUksSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFHLENBQUMsQ0FBQyxHQUFHLEtBQUcsQ0FBQyxDQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFELENBQUMsQ0FBRSxTQUFTLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQyxPQUFNLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsSUFBRyxFQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsUUFBUSxJQUFFLENBQUMsQ0FBQyxJQUFJLElBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFDLE1BQUssNEJBQTRCO01BQUMsSUFBSSxDQUFDO1FBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRO1FBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLElBQUUsQ0FBQztRQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsY0FBYztRQUFDLENBQUMsR0FBQztVQUFDLElBQUksRUFBQyxjQUFjO1VBQUMsR0FBRyxFQUFDLFVBQVU7VUFBQyxJQUFJLEVBQUMsT0FBTztVQUFDLEtBQUssRUFBQyxhQUFhO1VBQUMsT0FBTyxFQUFDO1FBQWlCLENBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBQyxRQUFRLEVBQUMsWUFBVTtVQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsZUFBZSxHQUFDLENBQUMsSUFBRSxFQUFFO1FBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUcsQ0FBQyxDQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxHQUFHO01BQUMsS0FBSSxDQUFDLElBQUksQ0FBQyxFQUFDLFVBQVUsSUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxHQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBQztNQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUFDLEtBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHFEQUFxRCxHQUFDLENBQUMsQ0FBQztJQUFBO0lBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQztFQUFBO0FBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQzs7Ozs7QUNYMTR2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyxNQUFNLENBQUMsUUFBUSxLQUFHLE1BQU0sQ0FBQyxRQUFRLEdBQUMsRUFBRSxDQUFDLEVBQUUsSUFBSSxDQUFDLFlBQVU7RUFBQyxZQUFZOztFQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsYUFBYSxFQUFDLENBQUMsYUFBYSxDQUFDLEVBQUMsVUFBUyxDQUFDLEVBQUM7SUFBQyxJQUFJLENBQUM7TUFBQyxDQUFDO01BQUMsQ0FBQztNQUFDLENBQUMsR0FBQyxNQUFNLENBQUMsZ0JBQWdCLElBQUUsTUFBTTtNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLFNBQVM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxFQUFFO01BQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxFQUFFLEdBQUMsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTTtNQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxFQUFDLFlBQVUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxJQUFJLENBQUMsQ0FBRCxDQUFDO1FBQUMsT0FBTyxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsRUFBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxJQUFFLFlBQVUsQ0FBQyxDQUFDO01BQUMsQ0FBQyxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsRUFBQztVQUFDLE9BQU8sRUFBQyxJQUFJLENBQUMsQ0FBRCxDQUFDO1VBQUMsTUFBTSxFQUFDLElBQUksQ0FBQyxDQUFELENBQUM7VUFBQyxTQUFTLEVBQUMsSUFBSSxDQUFDLENBQUQ7UUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQztNQUFBLENBQUM7TUFBQyxDQUFDLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxJQUFJLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsSUFBSSxFQUFDLElBQUksQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQztNQUFBLENBQUM7TUFBQyxDQUFDLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsRUFBQyxVQUFTLENBQUMsRUFBQztZQUFDLElBQUksQ0FBQyxHQUFHLEdBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLE9BQU8sRUFBQyxJQUFJLENBQUMsR0FBRyxHQUFDLEtBQUssR0FBQyxJQUFJLENBQUMsR0FBRztVQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxDQUFELENBQUM7UUFBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsVUFBUyxDQUFDLEVBQUM7VUFBQyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUFBLENBQUMsRUFBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUMsVUFBUyxDQUFDLEVBQUM7UUFBQyxPQUFNLENBQUMsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFDLENBQUM7TUFBQSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxFQUFDLFVBQVMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7TUFBQSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsV0FBVyxFQUFDLFVBQVMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFDLEVBQUUsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBQyxFQUFFLElBQUUsQ0FBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLElBQUksQ0FBQyxHQUFHLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLGVBQWUsRUFBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxFQUFFLEVBQUMsSUFBSSxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsRUFBRSxHQUFDLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxFQUFFLEdBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxJQUFJLENBQUMsR0FBRyxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsR0FBRyxHQUFDLElBQUksQ0FBQyxHQUFHLEdBQUMsSUFBSSxDQUFDLEdBQUcsRUFBQyxJQUFJLENBQUMsUUFBUSxHQUFDLENBQUMsS0FBRyxDQUFDLENBQUM7TUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxJQUFJLENBQUMsQ0FBRCxDQUFDO0lBQUMsT0FBTyxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBRSxHQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsRUFBRTtNQUFDLE9BQU8sSUFBSSxDQUFDLEdBQUcsR0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLFFBQVEsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsR0FBQyxJQUFJLENBQUMsUUFBUSxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxJQUFFLElBQUksQ0FBQyxHQUFHLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLElBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxHQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUMsRUFBRSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsb0JBQW9CLEVBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxJQUFJLENBQUMsR0FBRyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEdBQUcsR0FBQyxDQUFDLEdBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxDQUFELENBQUMsRUFBQyxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsT0FBTyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEdBQUMsVUFBVSxDQUFDLEVBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFDLENBQUMsSUFBRSxDQUFDLElBQUUsSUFBSSxDQUFDLEdBQUc7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxrQkFBa0IsRUFBQyxVQUFTLENBQUMsRUFBQztNQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDO01BQUMsS0FBSSxJQUFJLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxJQUFFLE1BQU0sRUFBQyxDQUFDLEdBQUMsRUFBRSxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsTUFBTSxJQUFFLEVBQUUsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLEtBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLFlBQVksQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsSUFBSSxFQUFDLENBQUMsR0FBQyxRQUFRLElBQUUsT0FBTyxDQUFDLENBQUMsUUFBUSxHQUFDLEVBQUUsR0FBQyxDQUFDLENBQUMsUUFBUSxHQUFDLEVBQUUsRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsTUFBTSxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLEtBQUssS0FBRyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLElBQUksS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLEVBQUUsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLEVBQUUsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsRUFBRSxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsRUFBRSxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxFQUFFLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxFQUFFLEdBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBQztRQUFDLENBQUMsRUFBQyxDQUFDO1FBQUMsQ0FBQyxFQUFDO01BQUMsQ0FBQztNQUFDLEtBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQSxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7TUFBQyxJQUFJLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxJQUFJLENBQUMsQ0FBRCxDQUFDLEVBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLO01BQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQztRQUFDLE9BQUssQ0FBQyxDQUFDLElBQUksSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUk7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUk7TUFBQSxDQUFDLE1BQUssT0FBSyxDQUFDLENBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSTtNQUFDLE9BQU8sSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLE9BQU8sSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsSUFBSSxDQUFDLENBQUQsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBQyxVQUFTLENBQUMsRUFBQztNQUFDLE9BQU8sQ0FBQyxHQUFDLElBQUksR0FBQyxDQUFDLEdBQUMsTUFBTSxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksR0FBQyxDQUFDLEdBQUMsTUFBTSxJQUFFLENBQUMsSUFBRSxHQUFHLEdBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxHQUFDLEdBQUcsR0FBQyxHQUFHLEdBQUMsSUFBSSxHQUFDLENBQUMsR0FBQyxNQUFNLElBQUUsQ0FBQyxJQUFFLElBQUksR0FBQyxJQUFJLENBQUMsR0FBQyxDQUFDLEdBQUMsS0FBSyxHQUFDLE1BQU0sSUFBRSxDQUFDLElBQUUsS0FBSyxHQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsR0FBQyxPQUFPO0lBQUEsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFVBQVUsRUFBQyxVQUFTLENBQUMsRUFBQztNQUFDLE9BQU8sQ0FBQyxHQUFDLElBQUksSUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxNQUFNLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxHQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsTUFBTSxJQUFFLENBQUMsSUFBRSxHQUFHLEdBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxHQUFDLEdBQUcsQ0FBQyxHQUFDLEdBQUcsR0FBQyxJQUFJLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxNQUFNLElBQUUsQ0FBQyxJQUFFLElBQUksR0FBQyxJQUFJLENBQUMsR0FBQyxDQUFDLEdBQUMsS0FBSyxDQUFDLEdBQUMsQ0FBQyxJQUFFLE1BQU0sSUFBRSxDQUFDLElBQUUsS0FBSyxHQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsR0FBQyxPQUFPLENBQUM7SUFBQSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsYUFBYSxFQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsSUFBSSxDQUFDLEdBQUMsRUFBRSxHQUFDLENBQUM7TUFBQyxPQUFPLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLEdBQUMsQ0FBQyxHQUFDLE1BQU0sR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLEdBQUMsQ0FBQyxHQUFDLE1BQU0sSUFBRSxDQUFDLElBQUUsR0FBRyxHQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsR0FBQyxHQUFHLEdBQUMsR0FBRyxHQUFDLElBQUksR0FBQyxDQUFDLEdBQUMsTUFBTSxJQUFFLENBQUMsSUFBRSxJQUFJLEdBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxHQUFDLEtBQUssR0FBQyxNQUFNLElBQUUsQ0FBQyxJQUFFLEtBQUssR0FBQyxJQUFJLENBQUMsR0FBQyxDQUFDLEdBQUMsT0FBTyxFQUFDLENBQUMsR0FBQyxFQUFFLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLEVBQUUsR0FBQyxDQUFDLEdBQUMsRUFBRTtJQUFBLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxDQUFDLENBQUMsU0FBUyxFQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBQyxVQUFTLENBQUMsRUFBQztNQUFDLE9BQU0sRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBQyxVQUFTLENBQUMsRUFBQztNQUFDLE9BQU8sQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUUsSUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsRUFBRSxJQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsRUFBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7VUFBQyxJQUFJLENBQUMsR0FBRyxHQUFDLENBQUMsSUFBRSxDQUFDLEVBQUMsSUFBSSxDQUFDLEdBQUcsR0FBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLElBQUksQ0FBQyxHQUFHLEdBQUMsSUFBSSxDQUFDLEdBQUcsR0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQztRQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQztRQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxDQUFELENBQUM7TUFBQyxPQUFPLENBQUMsQ0FBQyxXQUFXLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQyxFQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBQyxDQUFDLENBQUMsWUFBWSxFQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsT0FBTyxJQUFJLENBQUMsR0FBRyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBRSxHQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsSUFBRSxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsRUFBRSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBQyxVQUFTLENBQUMsRUFBQztNQUFDLE9BQU0sRUFBRSxJQUFJLENBQUMsR0FBRyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLEVBQUUsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLElBQUUsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxFQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsY0FBYyxFQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsT0FBTyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBRSxHQUFDLElBQUksQ0FBQyxHQUFHLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUMsRUFBRSxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsSUFBRSxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFDLEVBQUUsR0FBQyxJQUFJLENBQUMsR0FBRyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBRSxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsSUFBRSxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsR0FBRyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxPQUFPLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsR0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxFQUFDLFVBQVMsQ0FBQyxFQUFDO01BQUMsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBQyxFQUFFLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSTtJQUFBLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxPQUFPLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLEdBQUMsRUFBRSxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLEVBQUUsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxFQUFFLElBQUUsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBRSxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxPQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQztJQUFBLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxXQUFXLEVBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxPQUFNLENBQUMsRUFBRSxJQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxtQkFBbUIsRUFBQztNQUFDLElBQUksRUFBQyxTQUFBLENBQVMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztNQUFBO0lBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsUUFBUSxFQUFDLE9BQU8sQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsV0FBVyxFQUFDLE9BQU8sQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsYUFBYSxFQUFDLE9BQU8sQ0FBQyxFQUFDLENBQUM7RUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7QUFBQSxDQUFDLENBQUMsRUFBQyxNQUFNLENBQUMsU0FBUyxJQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDOzs7OztBQ1h0bEo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsTUFBTSxDQUFDLFFBQVEsS0FBRyxNQUFNLENBQUMsUUFBUSxHQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxZQUFVO0VBQUMsWUFBWTs7RUFBQyxNQUFNLENBQUMsU0FBUyxDQUFDLG1CQUFtQixFQUFDLENBQUMscUJBQXFCLEVBQUMsV0FBVyxDQUFDLEVBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO0lBQUMsSUFBSSxDQUFDO01BQUMsQ0FBQztNQUFDLENBQUM7TUFBQyxDQUFDO01BQUMsQ0FBQyxHQUFDLFNBQUEsQ0FBQSxFQUFVO1FBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsS0FBSyxDQUFDLEVBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxRQUFRO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFBQyxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsT0FBTyxHQUFDLFFBQVEsRUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsMkJBQTJCLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxlQUFlLEdBQUMsYUFBYSxFQUFDLENBQUMsR0FBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQztNQUFDLEdBQUcsRUFBQyxDQUFDO01BQUMsS0FBSyxFQUFDLENBQUM7TUFBQyxNQUFNLEVBQUMsQ0FBQztNQUFDLElBQUksRUFBQyxDQUFDO01BQUMsS0FBSyxFQUFDLENBQUM7TUFBQyxNQUFNLEVBQUMsQ0FBQztNQUFDLFFBQVEsRUFBQyxDQUFDO01BQUMsT0FBTyxFQUFDLENBQUM7TUFBQyxNQUFNLEVBQUMsQ0FBQztNQUFDLFdBQVcsRUFBQyxDQUFDO01BQUMsVUFBVSxFQUFDO0lBQUUsQ0FBQztJQUFDLElBQUksQ0FBQztNQUFDLENBQUM7TUFBQyxDQUFDO01BQUMsQ0FBQztNQUFDLENBQUM7TUFBQyxDQUFDO01BQUMsQ0FBQyxHQUFDLDJCQUEyQjtNQUFDLENBQUMsR0FBQyxzREFBc0Q7TUFBQyxDQUFDLEdBQUMsa0RBQWtEO01BQUMsQ0FBQyxHQUFDLFlBQVk7TUFBQyxDQUFDLEdBQUMsdUJBQXVCO01BQUMsQ0FBQyxHQUFDLHNCQUFzQjtNQUFDLENBQUMsR0FBQyxrQkFBa0I7TUFBQyxDQUFDLEdBQUMseUJBQXlCO01BQUMsQ0FBQyxHQUFDLFlBQVk7TUFBQyxDQUFDLEdBQUMsVUFBVTtNQUFDLENBQUMsR0FBQyxZQUFZO01BQUMsQ0FBQyxHQUFDLHdDQUF3QztNQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLE9BQU8sQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyx1QkFBdUI7TUFBQyxDQUFDLEdBQUMsZ0NBQWdDO01BQUMsQ0FBQyxHQUFDLHFEQUFxRDtNQUFDLENBQUMsR0FBQyx1QkFBdUI7TUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEVBQUUsR0FBQyxHQUFHO01BQUMsQ0FBQyxHQUFDLEdBQUcsR0FBQyxJQUFJLENBQUMsRUFBRTtNQUFDLENBQUMsR0FBQyxDQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsUUFBUTtNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsVUFBVSxHQUFDO1FBQUMsYUFBYSxFQUFDO01BQUMsQ0FBQztNQUFDLENBQUMsR0FBQyxTQUFTLENBQUMsU0FBUztNQUFDLENBQUMsR0FBQyxZQUFVO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDO1FBQUMsT0FBTyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFHLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBQyw2QkFBNkIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsU0FBUyxHQUFDLHVDQUF1QyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsb0JBQW9CLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBQyxDQUFDLENBQUM7TUFBQSxDQUFDLENBQUMsQ0FBQztNQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsSUFBRSxPQUFPLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsWUFBWSxHQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsTUFBTSxLQUFHLEVBQUUsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUM7TUFBQSxDQUFDO01BQUMsQ0FBQyxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUM7UUFBQyxNQUFNLENBQUMsT0FBTyxJQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxFQUFFO01BQUMsQ0FBQyxHQUFDLEVBQUU7TUFBQyxDQUFDLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUM7UUFBQyxJQUFJLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO1FBQUMsSUFBRyxLQUFLLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsT0FBTyxDQUFDO1FBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBRyxFQUFDLEtBQUssRUFBQyxJQUFJLEVBQUMsSUFBSSxFQUFDLFFBQVEsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUUsS0FBSyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBRTtRQUFDLE9BQU8sQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEdBQUMsR0FBRyxFQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsSUFBSTtNQUFBLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLGdCQUFnQixHQUFDLFlBQVUsQ0FBQyxDQUFDO01BQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDO1FBQUMsT0FBTyxDQUFDLElBQUUsU0FBUyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFDLEtBQUssQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsWUFBWSxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxJQUFFLENBQUMsSUFBRSxDQUFDLElBQUUsTUFBTSxLQUFHLENBQUMsSUFBRSxNQUFNLEtBQUcsQ0FBQyxJQUFFLFdBQVcsS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsZUFBZSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUcsSUFBSSxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsRUFBQyxPQUFPLENBQUM7UUFBQyxJQUFHLE1BQU0sS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLEVBQUMsT0FBTyxDQUFDO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztVQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQztRQUFDLElBQUcsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLEdBQUcsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLEdBQUcsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsS0FBSTtVQUFDLElBQUcsQ0FBQyxDQUFDLE9BQU8sR0FBQyw4QkFBOEIsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLFVBQVUsQ0FBQyxHQUFDLGlCQUFpQixFQUFDLEdBQUcsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLGlCQUFpQixHQUFDLGdCQUFnQixDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFJO1lBQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsSUFBRSxDQUFDLENBQUMsSUFBSSxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLEtBQUcsQ0FBQyxFQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLEdBQUMsR0FBRztZQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsT0FBTyxHQUFDLFFBQVEsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDO1VBQUE7VUFBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxhQUFhLEdBQUMsY0FBYyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxHQUFHLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxXQUFXLEtBQUcsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLEdBQUcsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUE7UUFBQyxPQUFPLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsZUFBZSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxJQUFHLFVBQVUsS0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDLFVBQVUsRUFBQyxDQUFDLENBQUMsRUFBQyxPQUFPLENBQUM7UUFBQyxJQUFJLENBQUMsR0FBQyxNQUFNLEtBQUcsQ0FBQyxHQUFDLE1BQU0sR0FBQyxLQUFLO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsUUFBUSxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7UUFBQyxPQUFPLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO1FBQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDO1VBQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxPQUFLLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUFDLE9BQUssSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFlBQVksSUFBRSxDQUFDLENBQUMsS0FBSyxFQUFDLEtBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxRQUFRLElBQUUsT0FBTyxDQUFDLElBQUUsS0FBSyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUFDLE9BQU8sQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsUUFBUSxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxLQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsU0FBUyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFDLENBQUMsQ0FBQyxPQUFPLElBQUUsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFDLENBQUM7TUFBQSxDQUFDO01BQUMsQ0FBQyxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO1FBQUMsS0FBSSxDQUFDLElBQUksQ0FBQyxFQUFDLFNBQVMsS0FBRyxDQUFDLElBQUUsUUFBUSxLQUFHLENBQUMsSUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBRyxRQUFRLElBQUUsT0FBTyxDQUFDLElBQUUsUUFBUSxJQUFFLE9BQU8sQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLE1BQU0sS0FBRyxDQUFDLElBQUUsTUFBTSxLQUFHLENBQUMsSUFBRSxLQUFLLEtBQUcsQ0FBQyxHQUFDLEVBQUUsS0FBRyxDQUFDLElBQUUsTUFBTSxLQUFHLENBQUMsSUFBRSxNQUFNLEtBQUcsQ0FBQyxJQUFFLFFBQVEsSUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxFQUFFLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLEtBQUssQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUFDLElBQUcsQ0FBQyxFQUFDLEtBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxXQUFXLEtBQUcsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQyxPQUFNO1VBQUMsSUFBSSxFQUFDLENBQUM7VUFBQyxRQUFRLEVBQUM7UUFBQyxDQUFDO01BQUEsQ0FBQztNQUFDLENBQUMsR0FBQztRQUFDLEtBQUssRUFBQyxDQUFDLE1BQU0sRUFBQyxPQUFPLENBQUM7UUFBQyxNQUFNLEVBQUMsQ0FBQyxLQUFLLEVBQUMsUUFBUTtNQUFDLENBQUM7TUFBQyxDQUFDLEdBQUMsQ0FBQyxZQUFZLEVBQUMsYUFBYSxFQUFDLFdBQVcsRUFBQyxjQUFjLENBQUM7TUFBQyxFQUFFLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDLEdBQUMsVUFBVSxDQUFDLE9BQU8sS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFdBQVcsR0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU07UUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLElBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsU0FBUyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLElBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxPQUFPLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDO1FBQUMsT0FBTyxDQUFDO01BQUEsQ0FBQztNQUFDLEVBQUUsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLENBQUMsSUFBSSxJQUFFLENBQUMsSUFBRSxFQUFFLEtBQUcsQ0FBQyxJQUFFLE1BQU0sS0FBRyxDQUFDLElBQUUsV0FBVyxLQUFHLENBQUMsTUFBSSxDQUFDLEdBQUMsS0FBSyxDQUFDO1FBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsR0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFDLElBQUksR0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsT0FBTyxJQUFJLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxHQUFHLEdBQUMsUUFBUSxLQUFHLENBQUMsS0FBRyxDQUFDLEdBQUMsS0FBSyxDQUFDLEVBQUMsQ0FBQyxRQUFRLEtBQUcsQ0FBQyxJQUFFLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsR0FBQyxFQUFFLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFJLENBQUMsR0FBQyxLQUFLLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLEdBQUcsS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsR0FBRyxLQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBRSxHQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxFQUFFLENBQUM7TUFBQSxDQUFDO01BQUMsRUFBRSxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsT0FBTSxRQUFRLElBQUUsT0FBTyxDQUFDLElBQUUsR0FBRyxLQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxFQUFDLEVBQUUsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7TUFBQSxDQUFDO01BQUMsRUFBRSxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxJQUFJLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxRQUFRLElBQUUsT0FBTyxDQUFDLElBQUUsR0FBRyxLQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxFQUFDLEVBQUUsQ0FBQyxHQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7TUFBQSxDQUFDO01BQUMsRUFBRSxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxJQUFJLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsSUFBSTtRQUFDLE9BQU8sSUFBSSxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLFFBQVEsSUFBRSxPQUFPLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxHQUFHLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUMsQ0FBQyxHQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLEdBQUcsS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxLQUFHLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsVUFBVSxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxVQUFVLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQztNQUFBLENBQUM7TUFBQyxFQUFFLEdBQUM7UUFBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLEVBQUMsR0FBRyxFQUFDLEdBQUcsQ0FBQztRQUFDLElBQUksRUFBQyxDQUFDLENBQUMsRUFBQyxHQUFHLEVBQUMsQ0FBQyxDQUFDO1FBQUMsTUFBTSxFQUFDLENBQUMsR0FBRyxFQUFDLEdBQUcsRUFBQyxHQUFHLENBQUM7UUFBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztRQUFDLE1BQU0sRUFBQyxDQUFDLEdBQUcsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO1FBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQyxFQUFDLEdBQUcsRUFBQyxHQUFHLENBQUM7UUFBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLEdBQUcsQ0FBQztRQUFDLElBQUksRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsR0FBRyxDQUFDO1FBQUMsS0FBSyxFQUFDLENBQUMsR0FBRyxFQUFDLEdBQUcsRUFBQyxHQUFHLENBQUM7UUFBQyxPQUFPLEVBQUMsQ0FBQyxHQUFHLEVBQUMsQ0FBQyxFQUFDLEdBQUcsQ0FBQztRQUFDLEtBQUssRUFBQyxDQUFDLEdBQUcsRUFBQyxHQUFHLEVBQUMsQ0FBQyxDQUFDO1FBQUMsTUFBTSxFQUFDLENBQUMsR0FBRyxFQUFDLEdBQUcsRUFBQyxDQUFDLENBQUM7UUFBQyxNQUFNLEVBQUMsQ0FBQyxHQUFHLEVBQUMsR0FBRyxFQUFDLENBQUMsQ0FBQztRQUFDLElBQUksRUFBQyxDQUFDLEdBQUcsRUFBQyxHQUFHLEVBQUMsR0FBRyxDQUFDO1FBQUMsTUFBTSxFQUFDLENBQUMsR0FBRyxFQUFDLENBQUMsRUFBQyxHQUFHLENBQUM7UUFBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLEVBQUMsR0FBRyxFQUFDLENBQUMsQ0FBQztRQUFDLEdBQUcsRUFBQyxDQUFDLEdBQUcsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO1FBQUMsSUFBSSxFQUFDLENBQUMsR0FBRyxFQUFDLEdBQUcsRUFBQyxHQUFHLENBQUM7UUFBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLEVBQUMsR0FBRyxFQUFDLEdBQUcsQ0FBQztRQUFDLFdBQVcsRUFBQyxDQUFDLEdBQUcsRUFBQyxHQUFHLEVBQUMsR0FBRyxFQUFDLENBQUM7TUFBQyxDQUFDO01BQUMsRUFBRSxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLE9BQU8sQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxHQUFHLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLEVBQUUsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsRUFBRTtNQUFBLENBQUM7TUFBQyxFQUFFLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDO1FBQUMsT0FBTyxDQUFDLElBQUUsRUFBRSxLQUFHLENBQUMsR0FBQyxRQUFRLElBQUUsT0FBTyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUUsRUFBRSxFQUFDLEdBQUcsR0FBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsSUFBRSxHQUFHLEtBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBQyxHQUFHLEtBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxDQUFDLE1BQU0sS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFFLEVBQUUsRUFBQyxHQUFHLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLElBQUUsS0FBSyxLQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLEdBQUcsRUFBQyxDQUFDLEdBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsRUFBQyxDQUFDLEdBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsRUFBQyxDQUFDLEdBQUMsRUFBRSxJQUFFLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsRUFBRSxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUUsRUFBRSxDQUFDLFdBQVcsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxFQUFFLENBQUMsS0FBSztNQUFBLENBQUM7TUFBQyxFQUFFLEdBQUMscURBQXFEO0lBQUMsS0FBSSxDQUFDLElBQUksRUFBRSxFQUFDLEVBQUUsSUFBRSxHQUFHLEdBQUMsQ0FBQyxHQUFDLEtBQUs7SUFBQyxFQUFFLEdBQUMsTUFBTSxDQUFDLEVBQUUsR0FBQyxHQUFHLEVBQUMsSUFBSSxDQUFDO0lBQUMsSUFBSSxFQUFFLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUcsSUFBSSxJQUFFLENBQUMsRUFBQyxPQUFPLFVBQVMsQ0FBQyxFQUFDO1VBQUMsT0FBTyxDQUFDO1FBQUEsQ0FBQztRQUFDLElBQUksQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxJQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUMsRUFBRTtVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUUsRUFBRTtVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLEdBQUcsS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLEVBQUU7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBQyxHQUFHLEdBQUMsR0FBRztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTTtVQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxHQUFDLEVBQUU7UUFBQyxPQUFPLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLFVBQVMsQ0FBQyxFQUFDO1VBQUMsSUFBSSxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDO1VBQUMsSUFBRyxRQUFRLElBQUUsT0FBTyxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFLLElBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUM7WUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7VUFBQTtVQUFDLElBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUUsRUFBRSxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUUsRUFBQyxPQUFLLENBQUMsR0FBQyxFQUFFLENBQUMsR0FBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7VUFBQyxPQUFPLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUMsUUFBUSxHQUFDLEVBQUUsQ0FBQztRQUFBLENBQUMsR0FBQyxVQUFTLENBQUMsRUFBQztVQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDO1VBQUMsSUFBRyxRQUFRLElBQUUsT0FBTyxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFLLElBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUM7WUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7VUFBQTtVQUFDLElBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUUsRUFBRSxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUUsRUFBQyxPQUFLLENBQUMsR0FBQyxFQUFFLENBQUMsR0FBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7VUFBQyxPQUFPLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUM7UUFBQSxDQUFDLEdBQUMsVUFBUyxDQUFDLEVBQUM7VUFBQyxPQUFPLENBQUM7UUFBQSxDQUFDO01BQUEsQ0FBQztNQUFDLEVBQUUsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztVQUFDLElBQUksQ0FBQztZQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxFQUFFLEVBQUUsS0FBSyxDQUFDLEdBQUcsQ0FBQztVQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUM7VUFBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO1FBQUEsQ0FBQztNQUFBLENBQUM7TUFBQyxFQUFFLElBQUUsQ0FBQyxDQUFDLGVBQWUsR0FBQyxVQUFTLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUFDLEtBQUksSUFBSSxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUMsQ0FBQyxHQUFDLElBQUksRUFBQyxDQUFDLEdBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztRQUFDLElBQUcsQ0FBQyxDQUFDLFVBQVUsS0FBRyxDQUFDLENBQUMsVUFBVSxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsRUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxFQUFDLENBQUMsR0FBRTtVQUFDLElBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksRUFBQztZQUFDLElBQUcsQ0FBQyxLQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUM7Y0FBQyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsRUFBRSxFQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDO2NBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDO1lBQUE7VUFBQyxDQUFDLE1BQUssQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFHO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO1FBQUE7TUFBQyxDQUFDLEVBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxLQUFLLEdBQUMsSUFBSSxFQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQyxDQUFDO01BQUMsRUFBRSxJQUFFLENBQUMsQ0FBQyxhQUFhLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVO1VBQUMsQ0FBQyxHQUFDLENBQUM7UUFBQyxLQUFJLENBQUMsQ0FBQyxVQUFVLEdBQUMsSUFBSSxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsS0FBSyxHQUFDLElBQUksRUFBQyxDQUFDLENBQUMsS0FBSyxLQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsR0FBRTtVQUFDLElBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBQyxHQUFHLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxJQUFJLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUs7UUFBQTtRQUFDLE9BQU07VUFBQyxLQUFLLEVBQUMsQ0FBQztVQUFDLEdBQUcsRUFBQyxDQUFDO1VBQUMsUUFBUSxFQUFDLENBQUM7VUFBQyxFQUFFLEVBQUM7UUFBQyxDQUFDO01BQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxZQUFZLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLENBQUMsWUFBWSxFQUFFLElBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLElBQUksR0FBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLENBQUMsS0FBRyxJQUFJLENBQUMsRUFBRSxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsQ0FBQyxHQUFDLEtBQUssQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxDQUFDLEdBQUMsS0FBSyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQztNQUFBLENBQUMsQ0FBQztNQUFDLEVBQUUsR0FBQyxDQUFDLENBQUMsWUFBWSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLElBQUUsRUFBRSxFQUFDLENBQUMsR0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLElBQUksRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxFQUFFO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNO1VBQUMsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLENBQUM7UUFBQyxLQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxNQUFNLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFFLEVBQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsRUFBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssSUFBRyxDQUFDLEtBQUcsR0FBRyxLQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsR0FBRyxLQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLEdBQUMsR0FBRyxFQUFDLENBQUMsR0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxHQUFDLGNBQWMsR0FBQyxhQUFhLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUcsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxHQUFDLE9BQU8sR0FBQyxNQUFNLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsR0FBRyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxHQUFHLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsRUFBRSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLElBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUM7VUFBQyxJQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxNQUFNLEtBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBQyxPQUFPLENBQUM7VUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxFQUFFLEVBQUMsQ0FBQyxJQUFFLElBQUksS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNO1VBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFBQSxDQUFDLE1BQUssQ0FBQyxDQUFDLElBQUksR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxHQUFDLENBQUM7UUFBQyxJQUFHLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUksRUFBQztVQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUksR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksR0FBQyxDQUFDLENBQUM7VUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQztRQUFBO1FBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBRSxDQUFDO01BQUEsQ0FBQztNQUFDLEVBQUUsR0FBQyxDQUFDO0lBQUMsS0FBSSxDQUFDLEdBQUMsRUFBRSxDQUFDLFNBQVMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUMsQ0FBQyxFQUFDLEVBQUUsRUFBRSxHQUFDLENBQUMsR0FBRSxDQUFDLENBQUMsSUFBSSxHQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxHQUFDLEVBQUUsQ0FBQyxHQUFDLEVBQUU7SUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLElBQUksRUFBQyxDQUFDLENBQUMsVUFBVSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUMsR0FBQyxJQUFJO1FBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDO01BQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsRUFBRSxFQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxNQUFNLElBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxFQUFFLEVBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxLQUFHLENBQUMsQ0FBQyxNQUFNLEdBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFDLElBQUksR0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxJQUFFLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsSUFBSSxHQUFDO1FBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQztNQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsSUFBRSxFQUFFLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDO0lBQUMsSUFBSSxFQUFFLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLEVBQUMsSUFBSSxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsU0FBUyxJQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsWUFBWSxFQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sS0FBRyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBQyxJQUFJLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxFQUFDLElBQUksQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBQyxJQUFJLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxZQUFZLEVBQUMsSUFBSSxDQUFDLEVBQUUsR0FBQyxDQUFDLENBQUMsUUFBUSxJQUFFLENBQUM7TUFBQSxDQUFDO01BQUMsRUFBRSxHQUFDLENBQUMsQ0FBQywyQkFBMkIsR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsUUFBUSxJQUFFLE9BQU8sQ0FBQyxLQUFHLENBQUMsR0FBQztVQUFDLE1BQU0sRUFBQztRQUFDLENBQUMsQ0FBQztRQUFDLElBQUksQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFlBQVk7UUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFDLENBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxZQUFZLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztNQUFBLENBQUM7TUFBQyxFQUFFLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQztRQUFDLElBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUM7VUFBQyxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBQyxRQUFRO1VBQUMsRUFBRSxDQUFDLENBQUMsRUFBQztZQUFDLE1BQU0sRUFBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO2NBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLElBQUUsTUFBTSxFQUFFLEdBQUcsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztjQUFDLE9BQU8sQ0FBQyxJQUFFLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLEdBQUMsc0JBQXNCLENBQUMsRUFBQyxDQUFDLENBQUM7WUFBQTtVQUFDLENBQUMsQ0FBQztRQUFBO01BQUMsQ0FBQztJQUFDLENBQUMsR0FBQyxFQUFFLENBQUMsU0FBUyxFQUFDLENBQUMsQ0FBQyxZQUFZLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxPQUFPO01BQUMsSUFBRyxJQUFJLENBQUMsS0FBSyxLQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxLQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxJQUFJLEVBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxHQUFHLEdBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7TUFBQTtNQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLElBQUksRUFBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsRUFBRSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsbUJBQW1CLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUM7UUFBQyxNQUFNLEVBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1VBQUMsSUFBSSxDQUFDLEdBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztVQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUM7UUFBQSxDQUFDO1FBQUMsUUFBUSxFQUFDO01BQUMsQ0FBQyxDQUFDO0lBQUEsQ0FBQztJQUFDLElBQUksRUFBRSxHQUFDLGlGQUFpRixDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7TUFBQyxFQUFFLEdBQUMsQ0FBQyxDQUFDLFdBQVcsQ0FBQztNQUFDLEVBQUUsR0FBQyxDQUFDLEdBQUMsV0FBVztNQUFDLEVBQUUsR0FBQyxDQUFDLENBQUMsaUJBQWlCLENBQUM7TUFBQyxFQUFFLEdBQUMsSUFBSSxLQUFHLENBQUMsQ0FBQyxhQUFhLENBQUM7TUFBQyxFQUFFLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxZQUFVO1FBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDO01BQUEsQ0FBQztNQUFDLEVBQUUsR0FBQyxDQUFDLENBQUMsWUFBWSxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBRyxDQUFDLENBQUMsWUFBWSxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsRUFBQyxPQUFPLENBQUMsQ0FBQyxZQUFZO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsWUFBWSxJQUFFLElBQUksRUFBRSxDQUFELENBQUMsR0FBQyxJQUFJLEVBQUUsQ0FBRCxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTTtVQUFDLENBQUMsR0FBQyxJQUFJO1VBQUMsQ0FBQyxHQUFDLEdBQUc7VUFBQyxDQUFDLEdBQUMsTUFBTTtVQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxFQUFFLEdBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsT0FBTyxJQUFFLENBQUMsR0FBQyxDQUFDO1FBQUMsS0FBSSxFQUFFLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxZQUFZLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBQyxFQUFFLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxJQUFFLEVBQUUsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxDQUFDLEdBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUUsR0FBQyxFQUFFLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUM7UUFBQyxJQUFHLEVBQUUsS0FBRyxDQUFDLENBQUMsTUFBTSxFQUFDO1VBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7VUFBQyxJQUFHLENBQUMsQ0FBQyxPQUFPLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLElBQUksSUFBRSxDQUFDLENBQUMsU0FBUyxFQUFDO1lBQUMsSUFBSSxDQUFDO2NBQUMsQ0FBQztjQUFDLENBQUM7Y0FBQyxDQUFDO2NBQUMsQ0FBQztjQUFDLENBQUM7Y0FBQyxDQUFDO2NBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Y0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztjQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2NBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Y0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztjQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2NBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7Y0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztjQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2NBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztjQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUM7WUFBQyxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLEVBQUUsSUFBRSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxFQUFFLElBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsRUFBRSxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDO1VBQUE7UUFBQyxDQUFDLE1BQUssSUFBRyxFQUFFLEVBQUUsSUFBRSxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsTUFBTSxJQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxTQUFTLElBQUUsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxJQUFFLEtBQUssQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLElBQUUsTUFBTSxLQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUMsU0FBUyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUM7VUFBQyxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxJQUFFLENBQUM7WUFBQyxFQUFFLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDO1lBQUMsRUFBRSxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDO1lBQUMsRUFBRSxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDO1lBQUMsRUFBRSxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQztVQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFDLEVBQUUsR0FBQyxFQUFFLEdBQUMsRUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxHQUFDLEVBQUUsR0FBQyxFQUFFLEdBQUMsRUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLEVBQUUsSUFBRSxFQUFFLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLElBQUUsQ0FBQyxFQUFDLENBQUMsR0FBQyxFQUFFLElBQUUsRUFBRSxHQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssSUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLElBQUUsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBQyxFQUFFLElBQUUsR0FBRyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxHQUFHLEVBQUMsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUMsR0FBRyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxJQUFFLEdBQUcsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssSUFBRSxHQUFHLEVBQUMsQ0FBQyxLQUFLLENBQUMsS0FBRyxDQUFDLENBQUMsS0FBSyxJQUFFLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxJQUFFLEtBQUssR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxJQUFFLEtBQUssR0FBQyxDQUFDLEdBQUMsQ0FBQyxNQUFJLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxLQUFHLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsV0FBVyxHQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsMkJBQTJCLENBQUMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUM7UUFBQTtRQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsQ0FBQztRQUFDLEtBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO1FBQUMsT0FBTyxDQUFDLEtBQUcsQ0FBQyxDQUFDLFlBQVksR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDO01BQUEsQ0FBQztNQUFDLEVBQUUsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsSUFBSTtVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLEdBQUc7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsSUFBRSxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLElBQUUsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLElBQUUsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxJQUFFLENBQUM7VUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLO1VBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsWUFBWTtRQUFDLElBQUcsQ0FBQyxFQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsRUFBRTtVQUFDLElBQUksQ0FBQztZQUFDLENBQUM7WUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxXQUFXO1lBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsWUFBWTtZQUFDLENBQUMsR0FBQyxVQUFVLEtBQUcsQ0FBQyxDQUFDLFFBQVE7WUFBQyxDQUFDLEdBQUMsK0NBQStDLEdBQUMsQ0FBQyxHQUFDLFFBQVEsR0FBQyxDQUFDLEdBQUMsUUFBUSxHQUFDLENBQUMsR0FBQyxRQUFRLEdBQUMsQ0FBQztZQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQztZQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQztVQUFDLElBQUcsSUFBSSxJQUFFLENBQUMsQ0FBQyxFQUFFLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxHQUFHLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBRSxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsR0FBRyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBRSxHQUFDLENBQUMsQ0FBQyxFQUFFLElBQUUsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFFLE9BQU8sSUFBRSxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsT0FBTyxJQUFFLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxHQUFHLElBQUUsQ0FBQyxJQUFFLCtCQUErQixFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxvQ0FBb0MsQ0FBQyxHQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxLQUFHLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBRSxHQUFHLEtBQUcsVUFBVSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLFdBQVcsSUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDO1lBQUMsSUFBSSxDQUFDO2NBQUMsQ0FBQztjQUFDLENBQUM7Y0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO1lBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLElBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsU0FBUyxHQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsRUFBRSxFQUFDLEVBQUUsRUFBRSxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsRUFBRSxHQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxHQUFDLEVBQUUsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxFQUFFLElBQUUsQ0FBQyxLQUFHLEVBQUUsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxJQUFJO1VBQUE7UUFBQztNQUFDLENBQUM7TUFBQyxFQUFFLEdBQUMsQ0FBQyxDQUFDLG1CQUFtQixHQUFDLFVBQVMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsSUFBSTtVQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUs7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxXQUFXO1FBQUMsSUFBRyxFQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsSUFBRSxNQUFNLEtBQUcsQ0FBQyxDQUFDLE9BQU8sSUFBRSxDQUFDLENBQUMsU0FBUyxJQUFFLENBQUMsQ0FBQyxTQUFTLElBQUUsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLEVBQUMsS0FBSyxDQUFDO1FBQUMsSUFBRyxDQUFDLEVBQUM7VUFBQyxJQUFJLENBQUMsR0FBQyxJQUFJO1VBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLFNBQVMsSUFBRSxDQUFDLENBQUMsU0FBUyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUM7UUFBQTtRQUFDLElBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDLFFBQVEsS0FBRyxDQUFDLENBQUMsUUFBUSxLQUFHLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUk7VUFBQyxJQUFHLEVBQUUsQ0FBQyxDQUFDLFNBQVMsSUFBRSxDQUFDLENBQUMsU0FBUyxJQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLEVBQUMsT0FBTyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUMsY0FBYyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsS0FBSyxJQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsR0FBQyxTQUFTLEdBQUMsQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLEVBQUUsQ0FBQyxFQUFDLEtBQUssQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQztRQUFBO1FBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsT0FBTyxFQUFDLENBQUMsR0FBQyxHQUFHLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxHQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFFLEdBQUMsRUFBRSxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUUsR0FBQyxFQUFFLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBRSxHQUFDLEVBQUUsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBQyxXQUFXLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUMsR0FBRztNQUFBLENBQUM7TUFBQyxFQUFFLEdBQUMsQ0FBQyxDQUFDLG1CQUFtQixHQUFDLFVBQVMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsSUFBSTtVQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztRQUFDLE9BQU8sQ0FBQyxDQUFDLFNBQVMsSUFBRSxDQUFDLENBQUMsU0FBUyxJQUFFLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLE9BQU8sS0FBRyxDQUFDLENBQUMsSUFBRSxNQUFNLEtBQUcsQ0FBQyxDQUFDLE9BQU8sSUFBRSxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsSUFBSSxDQUFDLFFBQVEsR0FBQyxFQUFFLEVBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLEVBQUMsS0FBSyxDQUFDLEtBQUcsQ0FBQyxDQUFDLFFBQVEsSUFBRSxDQUFDLENBQUMsS0FBSyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxHQUFHLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUMsU0FBUyxHQUFDLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsSUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUMsU0FBUyxHQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsT0FBTyxHQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxFQUFDLEtBQUssQ0FBQyxDQUFDO01BQUEsQ0FBQztJQUFDLEVBQUUsQ0FBQyxtUEFBbVAsRUFBQztNQUFDLE1BQU0sRUFBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBRyxDQUFDLENBQUMsVUFBVSxFQUFDLE9BQU8sQ0FBQztRQUFDLElBQUksQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsVUFBVSxHQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxjQUFjLENBQUM7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUs7VUFBQyxDQUFDLEdBQUMsSUFBSTtVQUFDLENBQUMsR0FBQyxFQUFFLENBQUMsTUFBTTtVQUFDLENBQUMsR0FBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQztRQUFDLElBQUcsUUFBUSxJQUFFLE9BQU8sQ0FBQyxDQUFDLFNBQVMsSUFBRSxFQUFFLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxPQUFPLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxVQUFVLEVBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFHLFFBQVEsSUFBRSxPQUFPLENBQUMsRUFBQztVQUFDLElBQUcsQ0FBQyxHQUFDO1lBQUMsTUFBTSxFQUFDLEVBQUUsQ0FBQyxJQUFJLElBQUUsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztZQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsS0FBSyxFQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7WUFBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztZQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUFDLFdBQVcsRUFBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLG9CQUFvQixFQUFDLENBQUMsQ0FBQyxXQUFXO1VBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsbUJBQW1CLEVBQUMsSUFBSSxJQUFFLENBQUMsRUFBQyxJQUFHLFFBQVEsSUFBRSxPQUFPLENBQUMsRUFBQyxLQUFJLENBQUMsSUFBSSxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQztVQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsRUFBRSxDQUFDLFVBQVUsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxlQUFlLElBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxhQUFhLEdBQUMsUUFBUSxHQUFDLFdBQVcsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsUUFBUSxFQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUMsVUFBVSxFQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsS0FBRyxDQUFDLENBQUMsU0FBUyxHQUFDLEVBQUUsQ0FBQyxXQUFXLElBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsZ0JBQWdCLElBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxjQUFjLEdBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxTQUFTLElBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUMsV0FBVyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsRUFBRSxDQUFDLFdBQVcsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxnQkFBZ0IsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLGNBQWMsR0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLFNBQVMsSUFBRSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBQyxXQUFXLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxHQUFDLElBQUksSUFBRSxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxNQUFJLENBQUMsQ0FBQyxLQUFLLElBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLElBQUUsQ0FBQyxDQUFDO1FBQUE7UUFBQyxLQUFJLEVBQUUsSUFBRSxJQUFJLElBQUUsQ0FBQyxDQUFDLE9BQU8sS0FBRyxDQUFDLENBQUMsT0FBTyxHQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxDQUFDLENBQUMsUUFBUSxJQUFFLENBQUMsQ0FBQyxRQUFRLElBQUUsQ0FBQyxDQUFDLGVBQWUsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE9BQU8sSUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxTQUFTLElBQUUsQ0FBQyxDQUFDLFNBQVMsSUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxTQUFTLElBQUUsQ0FBQyxDQUFDLFNBQVMsSUFBRSxDQUFDLENBQUMsV0FBVyxFQUFDLENBQUMsSUFBRSxJQUFJLElBQUUsQ0FBQyxDQUFDLEtBQUssS0FBRyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxJQUFJLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBSSxDQUFDLEtBQUcsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQyxPQUFPLENBQUMsR0FBQyxDQUFDLENBQUMsZUFBZSxFQUFDLENBQUMsQ0FBQyxJQUFFLEVBQUUsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLE9BQU8sTUFBSSxFQUFFLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxFQUFFLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxTQUFTLENBQUMsSUFBRSxFQUFFLEVBQUMsQ0FBQyxHQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsaUJBQWlCLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxFQUFFLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxLQUFHLENBQUMsS0FBRyxDQUFDLElBQUUsS0FBSyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEtBQUcsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxJQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxLQUFLLENBQUMsR0FBQyxNQUFNLEVBQUMsQ0FBQyxHQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBQyxTQUFTLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsT0FBTyxJQUFFLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsRUFBRSxDQUFDLENBQUMsR0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLGNBQWMsR0FBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLElBQUksQ0FBQyxjQUFjLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUM7TUFBQSxDQUFDO01BQUMsTUFBTSxFQUFDLENBQUM7SUFBQyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsV0FBVyxFQUFDO01BQUMsWUFBWSxFQUFDLHNCQUFzQjtNQUFDLE1BQU0sRUFBQyxDQUFDLENBQUM7TUFBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDO01BQUMsS0FBSyxFQUFDLENBQUMsQ0FBQztNQUFDLE9BQU8sRUFBQztJQUFPLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxjQUFjLEVBQUM7TUFBQyxZQUFZLEVBQUMsS0FBSztNQUFDLE1BQU0sRUFBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUFDLElBQUksQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLHFCQUFxQixFQUFDLHNCQUFzQixFQUFDLHlCQUF5QixFQUFDLHdCQUF3QixDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO1FBQUMsS0FBSSxDQUFDLEdBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsRUFBQyxDQUFDLEdBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxFQUFDLENBQUMsRUFBRSxFQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxLQUFLLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsRUFBRSxFQUFFLE1BQU0sQ0FBQyxFQUFDLENBQUMsR0FBQyxHQUFHLEtBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsRUFBQyxFQUFFLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLEVBQUUsRUFBRSxNQUFNLElBQUUsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxFQUFFLEtBQUcsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsRUFBQyxFQUFFLEtBQUcsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxZQUFZLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLFdBQVcsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsR0FBRyxLQUFHLENBQUMsSUFBRSxDQUFDLEdBQUMsR0FBRyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxHQUFHLEVBQUMsQ0FBQyxHQUFDLEdBQUcsSUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxJQUFFLElBQUksS0FBRyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsWUFBWSxFQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxFQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDO1FBQUMsT0FBTyxDQUFDO01BQUEsQ0FBQztNQUFDLE1BQU0sRUFBQyxDQUFDLENBQUM7TUFBQyxTQUFTLEVBQUMsRUFBRSxDQUFDLGlCQUFpQixFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxvQkFBb0IsRUFBQztNQUFDLFlBQVksRUFBQyxLQUFLO01BQUMsTUFBTSxFQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLHFCQUFxQjtVQUFDLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUM7VUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxtQkFBbUIsR0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxtQkFBbUIsS0FBRyxLQUFLLENBQUM7VUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFBQyxJQUFHLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUcsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLGlCQUFpQixDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsRUFBQyxDQUFDLElBQUUsTUFBTSxLQUFHLENBQUMsQ0FBQyxFQUFDO1VBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBQyxDQUFDLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUMsQ0FBQyxNQUFJLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLFlBQVksR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLEdBQUMsSUFBSSxHQUFDLEdBQUcsSUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxDQUFDO1VBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO1FBQUE7UUFBQyxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7TUFBQSxDQUFDO01BQUMsU0FBUyxFQUFDO0lBQUUsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLGdCQUFnQixFQUFDO01BQUMsWUFBWSxFQUFDLEtBQUs7TUFBQyxTQUFTLEVBQUM7SUFBRSxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsYUFBYSxFQUFDO01BQUMsWUFBWSxFQUFDLEtBQUs7TUFBQyxNQUFNLEVBQUMsQ0FBQztJQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxtQkFBbUIsRUFBQztNQUFDLFlBQVksRUFBQyxTQUFTO01BQUMsTUFBTSxFQUFDLENBQUM7SUFBQyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsZ0JBQWdCLEVBQUM7TUFBQyxNQUFNLEVBQUMsQ0FBQztJQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxvQkFBb0IsRUFBQztNQUFDLE1BQU0sRUFBQyxDQUFDO0lBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLFlBQVksRUFBQztNQUFDLE1BQU0sRUFBQyxDQUFDO0lBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLFFBQVEsRUFBQztNQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsK0NBQStDO0lBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLFNBQVMsRUFBQztNQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsbURBQW1EO0lBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLE1BQU0sRUFBQztNQUFDLFlBQVksRUFBQyx1QkFBdUI7TUFBQyxNQUFNLEVBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUM7UUFBQyxPQUFPLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxZQUFZLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLEdBQUcsRUFBQyxDQUFDLEdBQUMsT0FBTyxHQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsR0FBRyxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7TUFBQTtJQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxZQUFZLEVBQUM7TUFBQyxZQUFZLEVBQUMsa0JBQWtCO01BQUMsS0FBSyxFQUFDLENBQUMsQ0FBQztNQUFDLEtBQUssRUFBQyxDQUFDO0lBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLHVCQUF1QixFQUFDO01BQUMsTUFBTSxFQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxDQUFDO01BQUE7SUFBQyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsUUFBUSxFQUFDO01BQUMsWUFBWSxFQUFDLGdCQUFnQjtNQUFDLE1BQU0sRUFBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7UUFBQyxPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsZ0JBQWdCLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLEtBQUssQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLGdCQUFnQixFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxPQUFPLENBQUMsR0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxnQkFBZ0IsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7TUFBQSxDQUFDO01BQUMsS0FBSyxFQUFDLENBQUMsQ0FBQztNQUFDLFNBQVMsRUFBQyxTQUFBLENBQVMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUM7UUFBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxHQUFHLElBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFFLE9BQU8sQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7TUFBQTtJQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxhQUFhLEVBQUM7TUFBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLG1FQUFtRTtJQUFDLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQywyQkFBMkIsRUFBQztNQUFDLE1BQU0sRUFBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO1VBQUMsQ0FBQyxHQUFDLFVBQVUsSUFBRyxDQUFDLEdBQUMsVUFBVSxHQUFDLFlBQVk7UUFBQyxPQUFPLElBQUksRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDO01BQUE7SUFBQyxDQUFDLENBQUM7SUFBQyxJQUFJLEVBQUUsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDO01BQUMsSUFBSSxDQUFDO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLElBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsUUFBUSxDQUFDO1FBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLEdBQUMsQ0FBQztNQUFDLEdBQUcsS0FBRyxDQUFDLEtBQUcsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUUsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxRQUFRLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksRUFBQyxRQUFRLENBQUMsS0FBRyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxHQUFHLEtBQUcsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLGdCQUFnQixHQUFDLENBQUMsR0FBQyxHQUFHLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFDLENBQUMsS0FBRyxDQUFDLElBQUUsSUFBSSxDQUFDLEdBQUcsS0FBRyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsR0FBQyxpQkFBaUIsR0FBQyxDQUFDLEdBQUMsR0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBQyxVQUFVLEdBQUMsQ0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDO0lBQUMsRUFBRSxDQUFDLHlCQUF5QixFQUFDO01BQUMsWUFBWSxFQUFDLEdBQUc7TUFBQyxNQUFNLEVBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDLEdBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsU0FBUyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxHQUFHLENBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztVQUFDLENBQUMsR0FBQyxXQUFXLEtBQUcsQ0FBQztRQUFDLE9BQU0sUUFBUSxJQUFFLE9BQU8sQ0FBQyxJQUFFLEdBQUcsS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUcsS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxJQUFFLFFBQVEsS0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDLFlBQVksRUFBQyxDQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBQyxTQUFTLEVBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxHQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBQyxTQUFTLEVBQUMsR0FBRyxHQUFDLENBQUMsRUFBQyxHQUFHLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxnQkFBZ0IsR0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLGdCQUFnQixJQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsRUFBQyxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLEVBQUUsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFDLFlBQVksRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsU0FBUyxHQUFDLFFBQVEsRUFBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLFFBQVEsR0FBQyxTQUFTLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLFNBQVMsRUFBQyxDQUFDLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDO01BQUE7SUFBQyxDQUFDLENBQUM7SUFBQyxJQUFJLEVBQUUsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQztRQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsY0FBYyxJQUFFLElBQUksS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFDLEtBQUssQ0FBQyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQUEsQ0FBQztNQUFDLEVBQUUsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDO1FBQUMsSUFBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxJQUFJLEVBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxFQUFDO1VBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1VBQUMsS0FBSSxJQUFJLENBQUMsR0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLEdBQUUsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO1VBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLFVBQVUsS0FBRyxJQUFJLEtBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxVQUFVLEdBQUMsSUFBSSxDQUFDO1FBQUEsQ0FBQyxNQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxLQUFHLElBQUksQ0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7TUFBQSxDQUFDO0lBQUMsRUFBRSxDQUFDLFdBQVcsRUFBQztNQUFDLE1BQU0sRUFBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFFLEVBQUU7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPO1FBQUMsSUFBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFlBQVksR0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUMsQ0FBQyxFQUFFLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsVUFBVSxFQUFDO1VBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUMsQ0FBQyxHQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztVQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1FBQUE7UUFBQyxPQUFPLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxLQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLFNBQVMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLEtBQUssQ0FBQyxFQUFDLEVBQUUsQ0FBQyxJQUFFLEdBQUcsS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLEVBQUUsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxLQUFHLENBQUMsQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQztNQUFBO0lBQUMsQ0FBQyxDQUFDO0lBQUMsSUFBSSxFQUFFLEdBQUMsU0FBQSxDQUFTLENBQUMsRUFBQztNQUFDLElBQUcsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEtBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLEtBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLElBQUUsYUFBYSxLQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDO1FBQUMsSUFBSSxDQUFDO1VBQUMsQ0FBQztVQUFDLENBQUM7VUFBQyxDQUFDO1VBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSztVQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUs7UUFBQyxJQUFHLEtBQUssS0FBRyxJQUFJLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxPQUFPLEdBQUMsRUFBRSxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUksQ0FBQyxHQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxFQUFDLEVBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsaUJBQWlCLEtBQUcsQ0FBQyxHQUFDLEVBQUUsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7UUFBQyxDQUFDLEtBQUcsRUFBRSxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsRUFBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLFlBQVksSUFBRSxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO01BQUE7SUFBQyxDQUFDO0lBQUMsS0FBSSxFQUFFLENBQUMsWUFBWSxFQUFDO01BQUMsTUFBTSxFQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxDQUFDLEdBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxHQUFDLEVBQUUsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBRSxHQUFDLENBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQztNQUFBO0lBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLDBDQUEwQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBQyxFQUFFLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLEVBQUUsR0FBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLFlBQVksR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsSUFBRyxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUMsT0FBTSxDQUFDLENBQUM7TUFBQyxJQUFJLENBQUMsT0FBTyxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsTUFBTSxHQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFNBQVMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTLElBQUUsQ0FBQyxDQUFDLFNBQVMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxFQUFFLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLGVBQWU7TUFBQyxJQUFJLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztNQUFDLElBQUcsQ0FBQyxJQUFFLEVBQUUsS0FBRyxDQUFDLENBQUMsTUFBTSxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLFFBQVEsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLE1BQU0sS0FBRyxDQUFDLElBQUUsRUFBRSxLQUFHLENBQUMsS0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsRUFBQyxRQUFRLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxRQUFRLElBQUUsT0FBTyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxPQUFPLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDLEdBQUMsR0FBRyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLE9BQU8sR0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsT0FBTyxHQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsRUFBQyxJQUFJLENBQUMsY0FBYyxFQUFDO1FBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxjQUFjLEVBQUMsRUFBRSxHQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxLQUFHLENBQUMsQ0FBQyxNQUFNLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsUUFBUSxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsTUFBTSxLQUFHLENBQUMsSUFBRSxFQUFFLEtBQUcsQ0FBQyxLQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFDLFFBQVEsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsRUFBQywwQkFBMEIsRUFBQyxJQUFJLENBQUMsS0FBSyxDQUFDLHdCQUF3QixLQUFHLENBQUMsR0FBQyxTQUFTLEdBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFLLEdBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO1FBQUMsQ0FBQyxHQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBQyxXQUFXLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsQ0FBQyxJQUFFLEVBQUUsR0FBQyxFQUFFLEdBQUMsRUFBRSxHQUFDLEVBQUUsR0FBQyxFQUFFLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxJQUFJLENBQUMsVUFBVSxJQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO01BQUE7TUFBQyxJQUFHLENBQUMsRUFBQztRQUFDLE9BQUssQ0FBQyxHQUFFO1VBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsRUFBRSxHQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxLQUFLO1VBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUM7UUFBQTtRQUFDLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQztNQUFBO01BQUMsT0FBTSxDQUFDLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxVQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztNQUFDLEtBQUksQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLElBQUksRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBQyxFQUFFLEVBQUMsQ0FBQyxHQUFDLFFBQVEsSUFBRSxPQUFPLENBQUMsRUFBQyxPQUFPLEtBQUcsQ0FBQyxJQUFFLE1BQU0sS0FBRyxDQUFDLElBQUUsUUFBUSxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEdBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUMsQ0FBQyxHQUFDLE9BQU8sR0FBQyxNQUFNLElBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBQyxHQUFHLENBQUMsRUFBQyxDQUFDLEdBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxhQUFhLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUUsQ0FBQyxHQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsR0FBQyxFQUFFLEVBQUUsTUFBTSxDQUFDLEdBQUMsRUFBRSxFQUFDLENBQUMsRUFBRSxLQUFHLENBQUMsSUFBRSxNQUFNLEtBQUcsQ0FBQyxNQUFJLE9BQU8sS0FBRyxDQUFDLElBQUUsUUFBUSxLQUFHLENBQUMsSUFBRSxDQUFDLEdBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLElBQUksSUFBRSxNQUFNLEtBQUcsQ0FBQyxJQUFFLEtBQUssS0FBRyxDQUFDLElBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxJQUFJLEtBQUcsQ0FBQyxHQUFDLFNBQVMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLEdBQUcsS0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUMsR0FBRyxFQUFDLEVBQUUsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsSUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFDLEVBQUUsQ0FBQyxLQUFHLENBQUMsR0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFDLEVBQUUsRUFBRSxNQUFNLENBQUMsSUFBRSxFQUFFLEdBQUMsRUFBRSxDQUFDLEVBQUMsRUFBRSxLQUFHLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxJQUFJLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxFQUFFLEtBQUcsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEVBQUMsR0FBRyxLQUFHLENBQUMsSUFBRSxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsR0FBRyxFQUFDLEdBQUcsQ0FBQyxHQUFDLEdBQUcsRUFBQyxDQUFDLENBQUMsV0FBVyxLQUFHLENBQUMsQ0FBQyxLQUFHLENBQUMsR0FBQyxDQUFDLEdBQUMsR0FBRyxDQUFDLElBQUUsSUFBSSxLQUFHLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxHQUFDLElBQUksS0FBRyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUUsQ0FBQyxLQUFHLENBQUMsR0FBQyxLQUFLLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLEtBQUssSUFBRSxDQUFDLEdBQUMsRUFBRSxJQUFFLElBQUksSUFBRSxDQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLElBQUUsQ0FBQyxJQUFFLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsTUFBTSxLQUFHLENBQUMsSUFBRSxTQUFTLEtBQUcsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsVUFBVSxHQUFDLENBQUMsR0FBQyxnQkFBZ0IsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLEdBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxDQUFDLEtBQUcsSUFBSSxLQUFHLENBQUMsSUFBRSxRQUFRLEtBQUcsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLEtBQUcsQ0FBQyxDQUFDLE1BQU0sR0FBQyxDQUFDLENBQUM7TUFBQyxPQUFPLENBQUM7SUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLFFBQVEsR0FBQyxVQUFTLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxRQUFRO1FBQUMsQ0FBQyxHQUFDLElBQUk7TUFBQyxJQUFHLENBQUMsS0FBRyxDQUFDLElBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEtBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLElBQUUsQ0FBQyxLQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSztRQUFDLElBQUcsQ0FBQyxJQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxLQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxJQUFFLENBQUMsS0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssSUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksS0FBRyxDQUFDLElBQUksRUFBQyxPQUFLLENBQUMsR0FBRTtVQUFDLElBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUk7WUFBQyxJQUFHLENBQUMsS0FBRyxDQUFDLENBQUMsSUFBSTtjQUFDLElBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxLQUFHLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUcsQ0FBQyxLQUFHLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxJQUFHLENBQUMsS0FBRyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUcsQ0FBQyxLQUFHLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsR0FBRyxHQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFJO2dCQUFDLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsRUFBQyxDQUFDLEVBQUUsRUFBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUksR0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBSSxJQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQztnQkFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDO2NBQUE7WUFBQyxPQUFJLENBQUMsQ0FBQyxLQUFHLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLENBQUMsUUFBUSxJQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO1VBQUMsT0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUc7VUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUs7UUFBQSxDQUFDLE1BQUssT0FBSyxDQUFDLEdBQUUsQ0FBQyxLQUFHLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztNQUFDLE9BQUssT0FBSyxDQUFDLEdBQUUsQ0FBQyxLQUFHLENBQUMsQ0FBQyxJQUFJLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsS0FBSztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsaUJBQWlCLEdBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUMsY0FBYyxHQUFDLENBQUMsSUFBRSxDQUFDLEtBQUcsSUFBSSxDQUFDLGNBQWMsR0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxVQUFVLEdBQUMsSUFBSSxDQUFDLFVBQVUsSUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7SUFBQSxDQUFDO0lBQUMsSUFBSSxFQUFFLEdBQUMsU0FBQSxDQUFBLEVBQVU7TUFBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksRUFBQyxJQUFJLENBQUMsS0FBSyxFQUFDLElBQUksRUFBQyxDQUFDLENBQUMsQ0FBQztJQUFBLENBQUM7SUFBQyxDQUFDLENBQUMsV0FBVyxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUMsR0FBQyxJQUFJLENBQUMsUUFBUSxHQUFDLElBQUksRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsUUFBUSxFQUFDLENBQUMsQ0FBQztNQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUMsRUFBRSxFQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUMsSUFBSTtJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsU0FBUyxHQUFDLFVBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsT0FBTyxDQUFDLEtBQUcsQ0FBQyxLQUFHLENBQUMsQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssS0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxRQUFRLEtBQUcsQ0FBQyxLQUFHLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLEdBQUMsQ0FBQyxJQUFFLElBQUksS0FBRyxJQUFJLENBQUMsUUFBUSxLQUFHLElBQUksQ0FBQyxRQUFRLEdBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDO0lBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxLQUFLLEdBQUMsVUFBUyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQztRQUFDLENBQUMsR0FBQyxDQUFDO01BQUMsSUFBRyxDQUFDLENBQUMsU0FBUyxJQUFFLENBQUMsQ0FBQyxLQUFLLEVBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDO1FBQUMsS0FBSSxDQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFNBQVMsS0FBRyxDQUFDLENBQUMsVUFBVSxHQUFDLENBQUMsQ0FBQztNQUFBO01BQUMsT0FBTyxDQUFDLENBQUMsU0FBUyxLQUFHLENBQUMsR0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEtBQUcsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSyxFQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBQyxDQUFDLEtBQUcsSUFBSSxDQUFDLFFBQVEsS0FBRyxJQUFJLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBQyxDQUFDLENBQUMsS0FBSyxJQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUMsSUFBSSxDQUFDLFlBQVksR0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUM7SUFBQyxJQUFJLEVBQUUsR0FBQyxTQUFBLENBQVMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLEVBQUM7TUFBQyxJQUFJLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUM7TUFBQyxJQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUksQ0FBQyxHQUFDLENBQUMsQ0FBQyxVQUFVLEVBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUMsRUFBRSxDQUFDLEdBQUMsQ0FBQyxDQUFDLEdBQUUsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUksRUFBQyxDQUFDLENBQUMsS0FBSyxLQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxJQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLElBQUUsRUFBRSxLQUFHLENBQUMsSUFBRSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsTUFBTSxJQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztJQUFBLENBQUM7SUFBQyxPQUFPLENBQUMsQ0FBQyxTQUFTLEdBQUMsVUFBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQztNQUFDLElBQUksQ0FBQztRQUFDLENBQUM7UUFBQyxDQUFDO1FBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFDLENBQUMsRUFBQyxDQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUM7UUFBQyxDQUFDLEdBQUMsRUFBRTtRQUFDLENBQUMsR0FBQyxFQUFFO1FBQUMsQ0FBQyxHQUFDLEVBQUU7UUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxhQUFhO01BQUMsS0FBSSxDQUFDLEdBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBRSxDQUFDLENBQUMsTUFBTSxFQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsRUFBRSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBQyxFQUFFLENBQUMsR0FBQyxDQUFDLENBQUMsR0FBRSxJQUFHLENBQUMsR0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxFQUFDO1FBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxJQUFJO1FBQ2x4K0IsS0FBSSxDQUFDLElBQUksQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQTtNQUFDLE9BQU8sQ0FBQztJQUFBLENBQUMsRUFBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDO0VBQUEsQ0FBQyxFQUFDLENBQUMsQ0FBQyxDQUFDO0FBQUEsQ0FBQyxDQUFDLEVBQUMsTUFBTSxDQUFDLFNBQVMsSUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7Ozs7QUNaaEk7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsTUFBTSxDQUFDLFFBQVEsS0FBRyxNQUFNLENBQUMsUUFBUSxHQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxZQUFVO0VBQUMsWUFBWTs7RUFBQyxJQUFJLENBQUMsR0FBQyxRQUFRLENBQUMsZUFBZTtJQUFDLENBQUMsR0FBQyxNQUFNO0lBQUMsQ0FBQyxHQUFDLFNBQUEsQ0FBUyxDQUFDLEVBQUMsQ0FBQyxFQUFDO01BQUMsSUFBSSxDQUFDLEdBQUMsR0FBRyxLQUFHLENBQUMsR0FBQyxPQUFPLEdBQUMsUUFBUTtRQUFDLENBQUMsR0FBQyxRQUFRLEdBQUMsQ0FBQztRQUFDLENBQUMsR0FBQyxRQUFRLEdBQUMsQ0FBQztRQUFDLENBQUMsR0FBQyxRQUFRLENBQUMsSUFBSTtNQUFDLE9BQU8sQ0FBQyxLQUFHLENBQUMsSUFBRSxDQUFDLEtBQUcsQ0FBQyxJQUFFLENBQUMsS0FBRyxDQUFDLEdBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLE9BQU8sR0FBQyxDQUFDLENBQUMsSUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsUUFBUSxHQUFDLENBQUMsQ0FBQztJQUFBLENBQUM7SUFBQyxDQUFDLEdBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7TUFBQyxRQUFRLEVBQUMsVUFBVTtNQUFDLEdBQUcsRUFBQyxDQUFDO01BQUMsT0FBTyxFQUFDLE9BQU87TUFBQyxJQUFJLEVBQUMsU0FBQSxDQUFTLENBQUMsRUFBQyxDQUFDLEVBQUMsQ0FBQyxFQUFDO1FBQUMsT0FBTyxJQUFJLENBQUMsSUFBSSxHQUFDLENBQUMsS0FBRyxDQUFDLEVBQUMsSUFBSSxDQUFDLE9BQU8sR0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLE1BQU0sR0FBQyxDQUFDLEVBQUMsUUFBUSxJQUFFLE9BQU8sQ0FBQyxLQUFHLENBQUMsR0FBQztVQUFDLENBQUMsRUFBQztRQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLFFBQVEsS0FBRyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLElBQUksSUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFDLEdBQUcsRUFBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLEtBQUssS0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsR0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxZQUFZLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBRSxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksSUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFDLEdBQUcsRUFBQyxJQUFJLENBQUMsQ0FBQyxFQUFDLEtBQUssS0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsR0FBRyxDQUFDLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxZQUFZLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBRSxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQztNQUFBLENBQUM7TUFBQyxHQUFHLEVBQUMsU0FBQSxDQUFTLENBQUMsRUFBQztRQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDO1FBQUMsSUFBSSxDQUFDLEdBQUMsSUFBSSxDQUFDLElBQUksSUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUs7VUFBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLElBQUksSUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLEdBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLEtBQUs7VUFBQyxDQUFDLEdBQUMsQ0FBQyxHQUFDLElBQUksQ0FBQyxLQUFLO1VBQUMsQ0FBQyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsS0FBSztRQUFDLElBQUksQ0FBQyxTQUFTLEtBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxLQUFHLENBQUMsR0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLEdBQUMsQ0FBQyxDQUFDLElBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUMsR0FBRyxDQUFDLEdBQUMsQ0FBQyxLQUFHLElBQUksQ0FBQyxLQUFLLEdBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxDQUFDLElBQUksQ0FBQyxLQUFLLEtBQUcsQ0FBQyxHQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsR0FBQyxDQUFDLENBQUMsSUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBQyxHQUFHLENBQUMsR0FBQyxDQUFDLEtBQUcsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDLElBQUksQ0FBQyxLQUFLLElBQUUsSUFBSSxDQUFDLEtBQUssSUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsSUFBSSxHQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxDQUFDLEdBQUMsSUFBSSxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsR0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUUsSUFBSSxDQUFDLEtBQUssS0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsR0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEtBQUssS0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsR0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQyxJQUFJLENBQUMsS0FBSyxHQUFDLElBQUksQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLEtBQUssR0FBQyxJQUFJLENBQUMsQ0FBQztNQUFBO0lBQUMsQ0FBQyxDQUFDO0lBQUMsQ0FBQyxHQUFDLENBQUMsQ0FBQyxTQUFTO0VBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxZQUFVO0lBQUMsT0FBTyxJQUFJLENBQUMsSUFBSSxHQUFDLElBQUksSUFBRSxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxVQUFVLEdBQUMsQ0FBQyxDQUFDLFVBQVUsR0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsR0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVU7RUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLElBQUksR0FBQyxZQUFVO0lBQUMsT0FBTyxJQUFJLENBQUMsSUFBSSxHQUFDLElBQUksSUFBRSxDQUFDLENBQUMsV0FBVyxHQUFDLENBQUMsQ0FBQyxXQUFXLEdBQUMsSUFBSSxJQUFFLENBQUMsQ0FBQyxTQUFTLEdBQUMsQ0FBQyxDQUFDLFNBQVMsR0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFNBQVMsR0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVM7RUFBQSxDQUFDLEVBQUMsQ0FBQyxDQUFDLEtBQUssR0FBQyxVQUFTLENBQUMsRUFBQztJQUFDLE9BQU8sQ0FBQyxDQUFDLFVBQVUsS0FBRyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxDQUFDLFVBQVUsS0FBRyxJQUFJLENBQUMsS0FBSyxHQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksRUFBQyxDQUFDLENBQUM7RUFBQSxDQUFDO0FBQUEsQ0FBQyxDQUFDLEVBQUMsTUFBTSxDQUFDLFNBQVMsSUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKCl7ZnVuY3Rpb24gcihlLG4sdCl7ZnVuY3Rpb24gbyhpLGYpe2lmKCFuW2ldKXtpZighZVtpXSl7dmFyIGM9XCJmdW5jdGlvblwiPT10eXBlb2YgcmVxdWlyZSYmcmVxdWlyZTtpZighZiYmYylyZXR1cm4gYyhpLCEwKTtpZih1KXJldHVybiB1KGksITApO3ZhciBhPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIraStcIidcIik7dGhyb3cgYS5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGF9dmFyIHA9bltpXT17ZXhwb3J0czp7fX07ZVtpXVswXS5jYWxsKHAuZXhwb3J0cyxmdW5jdGlvbihyKXt2YXIgbj1lW2ldWzFdW3JdO3JldHVybiBvKG58fHIpfSxwLHAuZXhwb3J0cyxyLGUsbix0KX1yZXR1cm4gbltpXS5leHBvcnRzfWZvcih2YXIgdT1cImZ1bmN0aW9uXCI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlLGk9MDtpPHQubGVuZ3RoO2krKylvKHRbaV0pO3JldHVybiBvfXJldHVybiByfSkoKSIsInZhciAkID0galF1ZXJ5O1xuJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXtcbiAgICAvKipcbiAgICAgKiBSZWZyZXNoIExpY2Vuc2UgZGF0YVxuICAgICAqL1xuICAgIHZhciBfaXNSZWZyZXNoaW5nID0gZmFsc2U7XG4gICAgJCgnI3dwci1hY3Rpb24tcmVmcmVzaF9hY2NvdW50Jykub24oJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuICAgICAgICBpZighX2lzUmVmcmVzaGluZyl7XG4gICAgICAgICAgICB2YXIgYnV0dG9uID0gJCh0aGlzKTtcbiAgICAgICAgICAgIHZhciBhY2NvdW50ID0gJCgnI3dwci1hY2NvdW50LWRhdGEnKTtcbiAgICAgICAgICAgIHZhciBleHBpcmUgPSAkKCcjd3ByLWV4cGlyYXRpb24tZGF0YScpO1xuXG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICBfaXNSZWZyZXNoaW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIGJ1dHRvbi50cmlnZ2VyKCAnYmx1cicgKTtcbiAgICAgICAgICAgIGJ1dHRvbi5hZGRDbGFzcygnd3ByLWlzTG9hZGluZycpO1xuICAgICAgICAgICAgZXhwaXJlLnJlbW92ZUNsYXNzKCd3cHItaXNWYWxpZCB3cHItaXNJbnZhbGlkJyk7XG5cbiAgICAgICAgICAgICQucG9zdChcbiAgICAgICAgICAgICAgICBhamF4dXJsLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgYWN0aW9uOiAncm9ja2V0X3JlZnJlc2hfY3VzdG9tZXJfZGF0YScsXG4gICAgICAgICAgICAgICAgICAgIF9hamF4X25vbmNlOiByb2NrZXRfYWpheF9kYXRhLm5vbmNlLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24ocmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgYnV0dG9uLnJlbW92ZUNsYXNzKCd3cHItaXNMb2FkaW5nJyk7XG4gICAgICAgICAgICAgICAgICAgIGJ1dHRvbi5hZGRDbGFzcygnd3ByLWlzSGlkZGVuJyk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCB0cnVlID09PSByZXNwb25zZS5zdWNjZXNzICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWNjb3VudC5odG1sKHJlc3BvbnNlLmRhdGEubGljZW5zZV90eXBlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4cGlyZS5hZGRDbGFzcyhyZXNwb25zZS5kYXRhLmxpY2Vuc2VfY2xhc3MpLmh0bWwocmVzcG9uc2UuZGF0YS5saWNlbnNlX2V4cGlyYXRpb24pO1xuICAgICAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b24ucmVtb3ZlQ2xhc3MoJ3dwci1pY29uLXJlZnJlc2ggd3ByLWlzSGlkZGVuJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9uLmFkZENsYXNzKCd3cHItaWNvbi1jaGVjaycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSwgMjUwKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNle1xuICAgICAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b24ucmVtb3ZlQ2xhc3MoJ3dwci1pY29uLXJlZnJlc2ggd3ByLWlzSGlkZGVuJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnV0dG9uLmFkZENsYXNzKCd3cHItaWNvbi1jbG9zZScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSwgMjUwKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgdlRMID0gbmV3IFRpbWVsaW5lTGl0ZSh7b25Db21wbGV0ZTpmdW5jdGlvbigpe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF9pc1JlZnJlc2hpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH19KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAuc2V0KGJ1dHRvbiwge2Nzczp7Y2xhc3NOYW1lOicrPXdwci1pc0hpZGRlbid9fSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLnNldChidXR0b24sIHtjc3M6e2NsYXNzTmFtZTonLT13cHItaWNvbi1jaGVjayd9fSwgMC4yNSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLnNldChidXR0b24sIHtjc3M6e2NsYXNzTmFtZTonLT13cHItaWNvbi1jbG9zZSd9fSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLnNldChidXR0b24sIHtjc3M6e2NsYXNzTmFtZTonKz13cHItaWNvbi1yZWZyZXNoJ319LCAwLjI1KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAuc2V0KGJ1dHRvbiwge2Nzczp7Y2xhc3NOYW1lOictPXdwci1pc0hpZGRlbid9fSlcbiAgICAgICAgICAgICAgICAgICAgICAgIDtcbiAgICAgICAgICAgICAgICAgICAgfSwgMjAwMCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSk7XG5cbiAgICAvKipcbiAgICAgKiBTYXZlIFRvZ2dsZSBvcHRpb24gdmFsdWVzIG9uIGNoYW5nZVxuICAgICAqL1xuICAgICQoJy53cHItcmFkaW8gaW5wdXRbdHlwZT1jaGVja2JveF0nKS5vbignY2hhbmdlJywgZnVuY3Rpb24oZSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIHZhciBuYW1lICA9ICQodGhpcykuYXR0cignaWQnKTtcbiAgICAgICAgdmFyIHZhbHVlID0gJCh0aGlzKS5wcm9wKCdjaGVja2VkJykgPyAxIDogMDtcblxuXHRcdHZhciBleGNsdWRlZCA9IFsgJ2Nsb3VkZmxhcmVfYXV0b19zZXR0aW5ncycsICdjbG91ZGZsYXJlX2Rldm1vZGUnIF07XG5cdFx0aWYgKCBleGNsdWRlZC5pbmRleE9mKCBuYW1lICkgPj0gMCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cbiAgICAgICAgJC5wb3N0KFxuICAgICAgICAgICAgYWpheHVybCxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhY3Rpb246ICdyb2NrZXRfdG9nZ2xlX29wdGlvbicsXG4gICAgICAgICAgICAgICAgX2FqYXhfbm9uY2U6IHJvY2tldF9hamF4X2RhdGEubm9uY2UsXG4gICAgICAgICAgICAgICAgb3B0aW9uOiB7XG4gICAgICAgICAgICAgICAgICAgIG5hbWU6IG5hbWUsXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiB2YWx1ZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbihyZXNwb25zZSkge31cbiAgICAgICAgKTtcblx0fSk7XG5cblx0LyoqXG4gICAgICogU2F2ZSBlbmFibGUgQ1BDU1MgZm9yIG1vYmlsZXMgb3B0aW9uLlxuICAgICAqL1xuICAgICQoJyN3cHItYWN0aW9uLXJvY2tldF9lbmFibGVfbW9iaWxlX2NwY3NzJykub24oJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHQkKCcjd3ByLWFjdGlvbi1yb2NrZXRfZW5hYmxlX21vYmlsZV9jcGNzcycpLmFkZENsYXNzKCd3cHItaXNMb2FkaW5nJyk7XG5cbiAgICAgICAgJC5wb3N0KFxuICAgICAgICAgICAgYWpheHVybCxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhY3Rpb246ICdyb2NrZXRfZW5hYmxlX21vYmlsZV9jcGNzcycsXG4gICAgICAgICAgICAgICAgX2FqYXhfbm9uY2U6IHJvY2tldF9hamF4X2RhdGEubm9uY2VcbiAgICAgICAgICAgIH0sXG5cdFx0XHRmdW5jdGlvbihyZXNwb25zZSkge1xuXHRcdFx0XHRpZiAoIHJlc3BvbnNlLnN1Y2Nlc3MgKSB7XG5cdFx0XHRcdFx0Ly8gSGlkZSBNb2JpbGUgQ1BDU1MgYnRuIG9uIHN1Y2Nlc3MuXG5cdFx0XHRcdFx0JCgnI3dwci1hY3Rpb24tcm9ja2V0X2VuYWJsZV9tb2JpbGVfY3Bjc3MnKS5oaWRlKCk7XG5cdFx0XHRcdFx0JCgnLndwci1oaWRlLW9uLWNsaWNrJykuaGlkZSgpO1xuXHRcdFx0XHRcdCQoJy53cHItc2hvdy1vbi1jbGljaycpLnNob3coKTtcblx0XHRcdFx0XHQkKCcjd3ByLWFjdGlvbi1yb2NrZXRfZW5hYmxlX21vYmlsZV9jcGNzcycpLnJlbW92ZUNsYXNzKCd3cHItaXNMb2FkaW5nJyk7XG5cdFx0XHRcdH1cblx0XHRcdH1cbiAgICAgICAgKTtcbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIFNhdmUgZW5hYmxlIEdvb2dsZSBGb250cyBPcHRpbWl6YXRpb24gb3B0aW9uLlxuICAgICAqL1xuICAgICQoJyN3cHItYWN0aW9uLXJvY2tldF9lbmFibGVfZ29vZ2xlX2ZvbnRzJykub24oJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHQkKCcjd3ByLWFjdGlvbi1yb2NrZXRfZW5hYmxlX2dvb2dsZV9mb250cycpLmFkZENsYXNzKCd3cHItaXNMb2FkaW5nJyk7XG5cbiAgICAgICAgJC5wb3N0KFxuICAgICAgICAgICAgYWpheHVybCxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhY3Rpb246ICdyb2NrZXRfZW5hYmxlX2dvb2dsZV9mb250cycsXG4gICAgICAgICAgICAgICAgX2FqYXhfbm9uY2U6IHJvY2tldF9hamF4X2RhdGEubm9uY2VcbiAgICAgICAgICAgIH0sXG5cdFx0XHRmdW5jdGlvbihyZXNwb25zZSkge1xuXHRcdFx0XHRpZiAoIHJlc3BvbnNlLnN1Y2Nlc3MgKSB7XG5cdFx0XHRcdFx0Ly8gSGlkZSBNb2JpbGUgQ1BDU1MgYnRuIG9uIHN1Y2Nlc3MuXG5cdFx0XHRcdFx0JCgnI3dwci1hY3Rpb24tcm9ja2V0X2VuYWJsZV9nb29nbGVfZm9udHMnKS5oaWRlKCk7XG5cdFx0XHRcdFx0JCgnLndwci1oaWRlLW9uLWNsaWNrJykuaGlkZSgpO1xuXHRcdFx0XHRcdCQoJy53cHItc2hvdy1vbi1jbGljaycpLnNob3coKTtcbiAgICAgICAgICAgICAgICAgICAgJCgnI3dwci1hY3Rpb24tcm9ja2V0X2VuYWJsZV9nb29nbGVfZm9udHMnKS5yZW1vdmVDbGFzcygnd3ByLWlzTG9hZGluZycpO1xuICAgICAgICAgICAgICAgICAgICAkKCcjbWluaWZ5X2dvb2dsZV9mb250cycpLnZhbCgxKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuICAgICAgICApO1xuICAgIH0pO1xuXG4gICAgJCggJyNyb2NrZXQtZGlzbWlzcy1wcm9tb3Rpb24nICkub24oICdjbGljaycsIGZ1bmN0aW9uKCBlICkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgJC5wb3N0KFxuICAgICAgICAgICAgYWpheHVybCxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhY3Rpb246ICdyb2NrZXRfZGlzbWlzc19wcm9tbycsXG4gICAgICAgICAgICAgICAgbm9uY2U6IHJvY2tldF9hamF4X2RhdGEubm9uY2VcbiAgICAgICAgICAgIH0sXG5cdFx0XHRmdW5jdGlvbihyZXNwb25zZSkge1xuXHRcdFx0XHRpZiAoIHJlc3BvbnNlLnN1Y2Nlc3MgKSB7XG5cdFx0XHRcdFx0JCgnI3JvY2tldC1wcm9tby1iYW5uZXInKS5oaWRlKCAnc2xvdycgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuICAgICAgICApO1xuICAgIH0gKTtcblxuICAgICQoICcjcm9ja2V0LWRpc21pc3MtcmVuZXdhbCcgKS5vbiggJ2NsaWNrJywgZnVuY3Rpb24oIGUgKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICAkLnBvc3QoXG4gICAgICAgICAgICBhamF4dXJsLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGFjdGlvbjogJ3JvY2tldF9kaXNtaXNzX3JlbmV3YWwnLFxuICAgICAgICAgICAgICAgIG5vbmNlOiByb2NrZXRfYWpheF9kYXRhLm5vbmNlXG4gICAgICAgICAgICB9LFxuXHRcdFx0ZnVuY3Rpb24ocmVzcG9uc2UpIHtcblx0XHRcdFx0aWYgKCByZXNwb25zZS5zdWNjZXNzICkge1xuXHRcdFx0XHRcdCQoJyNyb2NrZXQtcmVuZXdhbC1iYW5uZXInKS5oaWRlKCAnc2xvdycgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuICAgICAgICApO1xuICAgIH0gKTtcblx0JCggJyN3cHItdXBkYXRlLWV4Y2x1c2lvbi1saXN0JyApLm9uKCAnY2xpY2snLCBmdW5jdGlvbiggZSApIHtcblx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0JCgnI3dwci11cGRhdGUtZXhjbHVzaW9uLW1zZycpLmh0bWwoJycpO1xuXHRcdCQuYWpheCh7XG5cdFx0XHR1cmw6IHJvY2tldF9hamF4X2RhdGEucmVzdF91cmwsXG5cdFx0XHRiZWZvcmVTZW5kOiBmdW5jdGlvbiAoIHhociApIHtcblx0XHRcdFx0eGhyLnNldFJlcXVlc3RIZWFkZXIoICdYLVdQLU5vbmNlJywgcm9ja2V0X2FqYXhfZGF0YS5yZXN0X25vbmNlICk7XG5cdFx0XHR9LFxuXHRcdFx0bWV0aG9kOiBcIlBVVFwiLFxuXHRcdFx0c3VjY2VzczogZnVuY3Rpb24ocmVzcG9uc2VzKSB7XG5cdFx0XHRcdGxldCBleGNsdXNpb25fbXNnX2NvbnRhaW5lciA9ICQoJyN3cHItdXBkYXRlLWV4Y2x1c2lvbi1tc2cnKTtcblx0XHRcdFx0ZXhjbHVzaW9uX21zZ19jb250YWluZXIuaHRtbCgnJyk7XG5cdFx0XHRcdGlmICggdW5kZWZpbmVkICE9PSByZXNwb25zZXNbJ3N1Y2Nlc3MnXSApIHtcblx0XHRcdFx0XHRleGNsdXNpb25fbXNnX2NvbnRhaW5lci5hcHBlbmQoICc8ZGl2IGNsYXNzPVwibm90aWNlIG5vdGljZS1lcnJvclwiPicgKyByZXNwb25zZXNbJ21lc3NhZ2UnXSArICc8L2Rpdj4nICk7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cdFx0XHRcdE9iamVjdC5rZXlzKCByZXNwb25zZXMgKS5mb3JFYWNoKCggcmVzcG9uc2Vfa2V5ICkgPT4ge1xuXHRcdFx0XHRcdGV4Y2x1c2lvbl9tc2dfY29udGFpbmVyLmFwcGVuZCggJzxzdHJvbmc+JyArIHJlc3BvbnNlX2tleSArICc6IDwvc3Ryb25nPicgKTtcblx0XHRcdFx0XHRleGNsdXNpb25fbXNnX2NvbnRhaW5lci5hcHBlbmQoIHJlc3BvbnNlc1tyZXNwb25zZV9rZXldWydtZXNzYWdlJ10gKTtcblx0XHRcdFx0XHRleGNsdXNpb25fbXNnX2NvbnRhaW5lci5hcHBlbmQoICc8YnI+JyApO1xuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHR9KTtcblx0fSApO1xuXG4gICAgLyoqXG4gICAgICogRW5hYmxlIG1vYmlsZSBjYWNoZSBvcHRpb24uXG4gICAgICovXG4gICAgJCgnI3dwcl9lbmFibGVfbW9iaWxlX2NhY2hlJykub24oJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHQkKCcjd3ByX2VuYWJsZV9tb2JpbGVfY2FjaGUnKS5hZGRDbGFzcygnd3ByLWlzTG9hZGluZycpO1xuXG4gICAgICAgICQucG9zdChcbiAgICAgICAgICAgIGFqYXh1cmwsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYWN0aW9uOiAncm9ja2V0X2VuYWJsZV9tb2JpbGVfY2FjaGUnLFxuICAgICAgICAgICAgICAgIF9hamF4X25vbmNlOiByb2NrZXRfYWpheF9kYXRhLm5vbmNlXG4gICAgICAgICAgICB9LFxuXHRcdFx0ZnVuY3Rpb24ocmVzcG9uc2UpIHtcblx0XHRcdFx0aWYgKCByZXNwb25zZS5zdWNjZXNzICkge1xuXHRcdFx0XHRcdC8vIEhpZGUgTW9iaWxlIGNhY2hlIGVuYWJsZSBidXR0b24gb24gc3VjY2Vzcy5cblx0XHRcdFx0XHQkKCcjd3ByX2VuYWJsZV9tb2JpbGVfY2FjaGUnKS5oaWRlKCk7XG5cdFx0XHRcdFx0JCgnI3dwcl9tb2JpbGVfY2FjaGVfZGVmYXVsdCcpLmhpZGUoKTtcblx0XHRcdFx0XHQkKCcjd3ByX21vYmlsZV9jYWNoZV9yZXNwb25zZScpLnNob3coKTtcbiAgICAgICAgICAgICAgICAgICAgJCgnI3dwcl9lbmFibGVfbW9iaWxlX2NhY2hlJykucmVtb3ZlQ2xhc3MoJ3dwci1pc0xvYWRpbmcnKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBTZXQgdmFsdWVzIG9mIG1vYmlsZSBjYWNoZSBhbmQgc2VwYXJhdGUgY2FjaGUgZmlsZXMgZm9yIG1vYmlsZXMgb3B0aW9uIHRvIDEuXG4gICAgICAgICAgICAgICAgICAgICQoJyNjYWNoZV9tb2JpbGUnKS52YWwoMSk7XG4gICAgICAgICAgICAgICAgICAgICQoJyNkb19jYWNoaW5nX21vYmlsZV9maWxlcycpLnZhbCgxKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuICAgICAgICApO1xuICAgIH0pO1xufSk7XG5cbiIsIi8vIEFkZCBncmVlbnNvY2sgbGliIGZvciBhbmltYXRpb25zXHJcbmltcG9ydCAnLi4vbGliL2dyZWVuc29jay9Ud2VlbkxpdGUubWluLmpzJztcclxuaW1wb3J0ICcuLi9saWIvZ3JlZW5zb2NrL1RpbWVsaW5lTGl0ZS5taW4uanMnO1xyXG5pbXBvcnQgJy4uL2xpYi9ncmVlbnNvY2svZWFzaW5nL0Vhc2VQYWNrLm1pbi5qcyc7XHJcbmltcG9ydCAnLi4vbGliL2dyZWVuc29jay9wbHVnaW5zL0NTU1BsdWdpbi5taW4uanMnO1xyXG5pbXBvcnQgJy4uL2xpYi9ncmVlbnNvY2svcGx1Z2lucy9TY3JvbGxUb1BsdWdpbi5taW4uanMnO1xyXG5cclxuLy8gQWRkIHNjcmlwdHNcclxuaW1wb3J0ICcuLi9nbG9iYWwvcGFnZU1hbmFnZXIuanMnO1xyXG5pbXBvcnQgJy4uL2dsb2JhbC9tYWluLmpzJztcclxuaW1wb3J0ICcuLi9nbG9iYWwvZmllbGRzLmpzJztcclxuaW1wb3J0ICcuLi9nbG9iYWwvYmVhY29uLmpzJztcclxuaW1wb3J0ICcuLi9nbG9iYWwvYWpheC5qcyc7XHJcbmltcG9ydCAnLi4vZ2xvYmFsL3JvY2tldGNkbi5qcyc7XHJcbmltcG9ydCAnLi4vZ2xvYmFsL2NvdW50ZG93bi5qcyc7IiwidmFyICQgPSBqUXVlcnk7XG4kKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpe1xuICAgIGlmICgnQmVhY29uJyBpbiB3aW5kb3cpIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFNob3cgYmVhY29ucyBvbiBidXR0b24gXCJoZWxwXCIgY2xpY2tcbiAgICAgICAgICovXG4gICAgICAgIHZhciAkaGVscCA9ICQoJy53cHItaW5mb0FjdGlvbi0taGVscCcpO1xuICAgICAgICAkaGVscC5vbignY2xpY2snLCBmdW5jdGlvbihlKXtcbiAgICAgICAgICAgIHZhciBpZHMgPSAkKHRoaXMpLmRhdGEoJ2JlYWNvbi1pZCcpO1xuICAgICAgICAgICAgd3ByQ2FsbEJlYWNvbihpZHMpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9KTtcblxuICAgICAgICBmdW5jdGlvbiB3cHJDYWxsQmVhY29uKGFJRCl7XG4gICAgICAgICAgICBhSUQgPSBhSUQuc3BsaXQoJywnKTtcbiAgICAgICAgICAgIGlmICggYUlELmxlbmd0aCA9PT0gMCApIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIGFJRC5sZW5ndGggPiAxICkge1xuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuQmVhY29uKFwic3VnZ2VzdFwiLCBhSUQpO1xuXG4gICAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB3aW5kb3cuQmVhY29uKFwib3BlblwiKTtcbiAgICAgICAgICAgICAgICAgICAgfSwgMjAwKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuQmVhY29uKFwiYXJ0aWNsZVwiLCBhSUQudG9TdHJpbmcoKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsImZ1bmN0aW9uIGdldFRpbWVSZW1haW5pbmcoZW5kdGltZSl7XG4gICAgY29uc3Qgc3RhcnQgPSBEYXRlLm5vdygpO1xuICAgIGNvbnN0IHRvdGFsID0gKGVuZHRpbWUgKiAxMDAwKSAtIHN0YXJ0O1xuICAgIGNvbnN0IHNlY29uZHMgPSBNYXRoLmZsb29yKCAodG90YWwvMTAwMCkgJSA2MCApO1xuICAgIGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKCAodG90YWwvMTAwMC82MCkgJSA2MCApO1xuICAgIGNvbnN0IGhvdXJzID0gTWF0aC5mbG9vciggKHRvdGFsLygxMDAwKjYwKjYwKSkgJSAyNCApO1xuICAgIGNvbnN0IGRheXMgPSBNYXRoLmZsb29yKCB0b3RhbC8oMTAwMCo2MCo2MCoyNCkgKTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIHRvdGFsLFxuICAgICAgICBkYXlzLFxuICAgICAgICBob3VycyxcbiAgICAgICAgbWludXRlcyxcbiAgICAgICAgc2Vjb25kc1xuICAgIH07XG59XG5cbmZ1bmN0aW9uIGluaXRpYWxpemVDbG9jayhpZCwgZW5kdGltZSkge1xuICAgIGNvbnN0IGNsb2NrID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoaWQpO1xuXG4gICAgaWYgKGNsb2NrID09PSBudWxsKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBkYXlzU3BhbiA9IGNsb2NrLnF1ZXJ5U2VsZWN0b3IoJy5yb2NrZXQtY291bnRkb3duLWRheXMnKTtcbiAgICBjb25zdCBob3Vyc1NwYW4gPSBjbG9jay5xdWVyeVNlbGVjdG9yKCcucm9ja2V0LWNvdW50ZG93bi1ob3VycycpO1xuICAgIGNvbnN0IG1pbnV0ZXNTcGFuID0gY2xvY2sucXVlcnlTZWxlY3RvcignLnJvY2tldC1jb3VudGRvd24tbWludXRlcycpO1xuICAgIGNvbnN0IHNlY29uZHNTcGFuID0gY2xvY2sucXVlcnlTZWxlY3RvcignLnJvY2tldC1jb3VudGRvd24tc2Vjb25kcycpO1xuXG4gICAgZnVuY3Rpb24gdXBkYXRlQ2xvY2soKSB7XG4gICAgICAgIGNvbnN0IHQgPSBnZXRUaW1lUmVtYWluaW5nKGVuZHRpbWUpO1xuXG4gICAgICAgIGlmICh0LnRvdGFsIDwgMCkge1xuICAgICAgICAgICAgY2xlYXJJbnRlcnZhbCh0aW1laW50ZXJ2YWwpO1xuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBkYXlzU3Bhbi5pbm5lckhUTUwgPSB0LmRheXM7XG4gICAgICAgIGhvdXJzU3Bhbi5pbm5lckhUTUwgPSAoJzAnICsgdC5ob3Vycykuc2xpY2UoLTIpO1xuICAgICAgICBtaW51dGVzU3Bhbi5pbm5lckhUTUwgPSAoJzAnICsgdC5taW51dGVzKS5zbGljZSgtMik7XG4gICAgICAgIHNlY29uZHNTcGFuLmlubmVySFRNTCA9ICgnMCcgKyB0LnNlY29uZHMpLnNsaWNlKC0yKTtcbiAgICB9XG5cbiAgICB1cGRhdGVDbG9jaygpO1xuICAgIGNvbnN0IHRpbWVpbnRlcnZhbCA9IHNldEludGVydmFsKHVwZGF0ZUNsb2NrLCAxMDAwKTtcbn1cblxuZnVuY3Rpb24gcnVjc3NUaW1lcihpZCwgZW5kdGltZSkge1xuXHRjb25zdCB0aW1lciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKTtcblx0Y29uc3Qgbm90aWNlID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3JvY2tldC1ub3RpY2Utc2Fhcy1wcm9jZXNzaW5nJyk7XG5cdGNvbnN0IHN1Y2Nlc3MgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncm9ja2V0LW5vdGljZS1zYWFzLXN1Y2Nlc3MnKTtcblxuXHRpZiAodGltZXIgPT09IG51bGwpIHtcblx0XHRyZXR1cm47XG5cdH1cblxuXHRmdW5jdGlvbiB1cGRhdGVUaW1lcigpIHtcblx0XHRjb25zdCBzdGFydCA9IERhdGUubm93KCk7XG5cdFx0Y29uc3QgcmVtYWluaW5nID0gTWF0aC5mbG9vciggKCAoZW5kdGltZSAqIDEwMDApIC0gc3RhcnQgKSAvIDEwMDAgKTtcblxuXHRcdGlmIChyZW1haW5pbmcgPD0gMCkge1xuXHRcdFx0Y2xlYXJJbnRlcnZhbCh0aW1lckludGVydmFsKTtcblxuXHRcdFx0aWYgKG5vdGljZSAhPT0gbnVsbCkge1xuXHRcdFx0XHRub3RpY2UuY2xhc3NMaXN0LmFkZCgnaGlkZGVuJyk7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChzdWNjZXNzICE9PSBudWxsKSB7XG5cdFx0XHRcdHN1Y2Nlc3MuY2xhc3NMaXN0LnJlbW92ZSgnaGlkZGVuJyk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggcm9ja2V0X2FqYXhfZGF0YS5jcm9uX2Rpc2FibGVkICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGRhdGEgPSBuZXcgRm9ybURhdGEoKTtcblxuXHRcdFx0ZGF0YS5hcHBlbmQoICdhY3Rpb24nLCAncm9ja2V0X3NwYXduX2Nyb24nICk7XG5cdFx0XHRkYXRhLmFwcGVuZCggJ25vbmNlJywgcm9ja2V0X2FqYXhfZGF0YS5ub25jZSApO1xuXG5cdFx0XHRmZXRjaCggYWpheHVybCwge1xuXHRcdFx0XHRtZXRob2Q6ICdQT1NUJyxcblx0XHRcdFx0Y3JlZGVudGlhbHM6ICdzYW1lLW9yaWdpbicsXG5cdFx0XHRcdGJvZHk6IGRhdGFcblx0XHRcdH0gKTtcblxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRpbWVyLmlubmVySFRNTCA9IHJlbWFpbmluZztcblx0fVxuXG5cdHVwZGF0ZVRpbWVyKCk7XG5cdGNvbnN0IHRpbWVySW50ZXJ2YWwgPSBzZXRJbnRlcnZhbCggdXBkYXRlVGltZXIsIDEwMDApO1xufVxuXG5pZiAoIURhdGUubm93KSB7XG4gICAgRGF0ZS5ub3cgPSBmdW5jdGlvbiBub3coKSB7XG4gICAgICByZXR1cm4gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgfTtcbn1cblxuaWYgKHR5cGVvZiByb2NrZXRfYWpheF9kYXRhLnByb21vX2VuZCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpbml0aWFsaXplQ2xvY2soJ3JvY2tldC1wcm9tby1jb3VudGRvd24nLCByb2NrZXRfYWpheF9kYXRhLnByb21vX2VuZCk7XG59XG5cbmlmICh0eXBlb2Ygcm9ja2V0X2FqYXhfZGF0YS5saWNlbnNlX2V4cGlyYXRpb24gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaW5pdGlhbGl6ZUNsb2NrKCdyb2NrZXQtcmVuZXctY291bnRkb3duJywgcm9ja2V0X2FqYXhfZGF0YS5saWNlbnNlX2V4cGlyYXRpb24pO1xufVxuXG5pZiAodHlwZW9mIHJvY2tldF9hamF4X2RhdGEubm90aWNlX2VuZF90aW1lICE9PSAndW5kZWZpbmVkJykge1xuICAgIHJ1Y3NzVGltZXIoJ3JvY2tldC1ydWNzcy10aW1lcicsIHJvY2tldF9hamF4X2RhdGEubm90aWNlX2VuZF90aW1lKTtcbn0iLCJ2YXIgJCA9IGpRdWVyeTtcbiQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCl7XG5cblxuICAgIC8qKipcbiAgICAqIENoZWNrIHBhcmVudCAvIHNob3cgY2hpbGRyZW5cbiAgICAqKiovXG5cblx0ZnVuY3Rpb24gd3ByU2hvd0NoaWxkcmVuKGFFbGVtKXtcblx0XHR2YXIgcGFyZW50SWQsICRjaGlsZHJlbjtcblxuXHRcdGFFbGVtICAgICA9ICQoIGFFbGVtICk7XG5cdFx0cGFyZW50SWQgID0gYUVsZW0uYXR0cignaWQnKTtcblx0XHQkY2hpbGRyZW4gPSAkKCdbZGF0YS1wYXJlbnQ9XCInICsgcGFyZW50SWQgKyAnXCJdJyk7XG5cblx0XHQvLyBUZXN0IGNoZWNrIGZvciBzd2l0Y2hcblx0XHRpZihhRWxlbS5pcygnOmNoZWNrZWQnKSl7XG5cdFx0XHQkY2hpbGRyZW4uYWRkQ2xhc3MoJ3dwci1pc09wZW4nKTtcblxuXHRcdFx0JGNoaWxkcmVuLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggJCh0aGlzKS5maW5kKCdpbnB1dFt0eXBlPWNoZWNrYm94XScpLmlzKCc6Y2hlY2tlZCcpKSB7XG5cdFx0XHRcdFx0dmFyIGlkID0gJCh0aGlzKS5maW5kKCdpbnB1dFt0eXBlPWNoZWNrYm94XScpLmF0dHIoJ2lkJyk7XG5cblx0XHRcdFx0XHQkKCdbZGF0YS1wYXJlbnQ9XCInICsgaWQgKyAnXCJdJykuYWRkQ2xhc3MoJ3dwci1pc09wZW4nKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fVxuXHRcdGVsc2V7XG5cdFx0XHQkY2hpbGRyZW4ucmVtb3ZlQ2xhc3MoJ3dwci1pc09wZW4nKTtcblxuXHRcdFx0JGNoaWxkcmVuLmVhY2goZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBpZCA9ICQodGhpcykuZmluZCgnaW5wdXRbdHlwZT1jaGVja2JveF0nKS5hdHRyKCdpZCcpO1xuXG5cdFx0XHRcdCQoJ1tkYXRhLXBhcmVudD1cIicgKyBpZCArICdcIl0nKS5yZW1vdmVDbGFzcygnd3ByLWlzT3BlbicpO1xuXHRcdFx0fSk7XG5cdFx0fVxuXHR9XG5cbiAgICAvKipcbiAgICAgKiBUZWxsIGlmIHRoZSBnaXZlbiBjaGlsZCBmaWVsZCBoYXMgYW4gYWN0aXZlIHBhcmVudCBmaWVsZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSAgb2JqZWN0ICRmaWVsZCBBIGpRdWVyeSBvYmplY3Qgb2YgYSBcIi53cHItZmllbGRcIiBmaWVsZC5cbiAgICAgKiBAcmV0dXJuIGJvb2x8bnVsbFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHdwcklzUGFyZW50QWN0aXZlKCAkZmllbGQgKSB7XG4gICAgICAgIHZhciAkcGFyZW50O1xuXG4gICAgICAgIGlmICggISAkZmllbGQubGVuZ3RoICkge1xuICAgICAgICAgICAgLy8gwq9cXF8o44OEKV8vwq9cbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgJHBhcmVudCA9ICRmaWVsZC5kYXRhKCAncGFyZW50JyApO1xuXG4gICAgICAgIGlmICggdHlwZW9mICRwYXJlbnQgIT09ICdzdHJpbmcnICkge1xuICAgICAgICAgICAgLy8gVGhpcyBmaWVsZCBoYXMgbm8gcGFyZW50IGZpZWxkOiB0aGVuIHdlIGNhbiBkaXNwbGF5IGl0LlxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICAkcGFyZW50ID0gJHBhcmVudC5yZXBsYWNlKCAvXlxccyt8XFxzKyQvZywgJycgKTtcblxuICAgICAgICBpZiAoICcnID09PSAkcGFyZW50ICkge1xuICAgICAgICAgICAgLy8gVGhpcyBmaWVsZCBoYXMgbm8gcGFyZW50IGZpZWxkOiB0aGVuIHdlIGNhbiBkaXNwbGF5IGl0LlxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICAkcGFyZW50ID0gJCggJyMnICsgJHBhcmVudCApO1xuXG4gICAgICAgIGlmICggISAkcGFyZW50Lmxlbmd0aCApIHtcbiAgICAgICAgICAgIC8vIFRoaXMgZmllbGQncyBwYXJlbnQgaXMgbWlzc2luZzogbGV0J3MgY29uc2lkZXIgaXQncyBub3QgYWN0aXZlIHRoZW4uXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoICEgJHBhcmVudC5pcyggJzpjaGVja2VkJyApICYmICRwYXJlbnQuaXMoJ2lucHV0JykpIHtcbiAgICAgICAgICAgIC8vIFRoaXMgZmllbGQncyBwYXJlbnQgaXMgY2hlY2tib3ggYW5kIG5vdCBjaGVja2VkOiBkb24ndCBkaXNwbGF5IHRoZSBmaWVsZCB0aGVuLlxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cblx0XHRpZiAoICEkcGFyZW50Lmhhc0NsYXNzKCdyYWRpby1hY3RpdmUnKSAmJiAkcGFyZW50LmlzKCdidXR0b24nKSkge1xuXHRcdFx0Ly8gVGhpcyBmaWVsZCdzIHBhcmVudCBidXR0b24gYW5kIGlzIG5vdCBhY3RpdmU6IGRvbid0IGRpc3BsYXkgdGhlIGZpZWxkIHRoZW4uXG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuICAgICAgICAvLyBHbyByZWN1cnNpdmUgdG8gdGhlIGxhc3QgcGFyZW50LlxuICAgICAgICByZXR1cm4gd3BySXNQYXJlbnRBY3RpdmUoICRwYXJlbnQuY2xvc2VzdCggJy53cHItZmllbGQnICkgKTtcbiAgICB9XG5cblx0LyoqXG5cdCAqIE1hc2tzIHNlbnNpdGl2ZSBpbmZvcm1hdGlvbiBpbiBhbiBpbnB1dCBmaWVsZCBieSByZXBsYWNpbmcgYWxsIGJ1dCB0aGUgbGFzdCA0IGNoYXJhY3RlcnMgd2l0aCBhc3Rlcmlza3MuXG5cdCAqXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBpZF9zZWxlY3RvciAtIFRoZSBJRCBvZiB0aGUgaW5wdXQgZmllbGQgdG8gYmUgbWFza2VkLlxuXHQgKiBAcmV0dXJucyB7dm9pZH0gLSBNb2RpZmllcyB0aGUgaW5wdXQgZmllbGQgdmFsdWUgaW4tcGxhY2UuXG5cdCAqXG5cdCAqIEBleGFtcGxlXG5cdCAqIC8vIEhUTUw6IDxpbnB1dCB0eXBlPVwidGV4dFwiIGlkPVwiY3JlZGl0Q2FyZElucHV0XCIgdmFsdWU9XCIxMjM0NTY3ODkwMTIzNDU2XCI+XG5cdCAqIG1hc2tGaWVsZCgnY3JlZGl0Q2FyZElucHV0Jyk7XG5cdCAqIC8vIFJlc3VsdDogVXBkYXRlcyB0aGUgaW5wdXQgZmllbGQgdmFsdWUgdG8gJyoqKioqKioqKioqKjM0NTYnLlxuXHQgKi9cblx0ZnVuY3Rpb24gbWFza0ZpZWxkKHByb3h5X3NlbGVjdG9yLCBjb25jcmV0ZV9zZWxlY3Rvcikge1xuXHRcdHZhciBjb25jcmV0ZSA9IHtcblx0XHRcdCd2YWwnOiBjb25jcmV0ZV9zZWxlY3Rvci52YWwoKSxcblx0XHRcdCdsZW5ndGgnOiBjb25jcmV0ZV9zZWxlY3Rvci52YWwoKS5sZW5ndGhcblx0XHR9XG5cblx0XHRpZiAoY29uY3JldGUubGVuZ3RoID4gNCkge1xuXG5cdFx0XHR2YXIgaGlkZGVuUGFydCA9ICdcXHUyMDIyJy5yZXBlYXQoTWF0aC5tYXgoMCwgY29uY3JldGUubGVuZ3RoIC0gNCkpO1xuXHRcdFx0dmFyIHZpc2libGVQYXJ0ID0gY29uY3JldGUudmFsLnNsaWNlKC00KTtcblxuXHRcdFx0Ly8gQ29tYmluZSB0aGUgaGlkZGVuIGFuZCB2aXNpYmxlIHBhcnRzXG5cdFx0XHR2YXIgbWFza2VkVmFsdWUgPSBoaWRkZW5QYXJ0ICsgdmlzaWJsZVBhcnQ7XG5cblx0XHRcdHByb3h5X3NlbGVjdG9yLnZhbChtYXNrZWRWYWx1ZSk7XG5cdFx0fVxuXHRcdC8vIEVuc3VyZSBldmVudHMgYXJlIG5vdCBhZGRlZCBtb3JlIHRoYW4gb25jZVxuXHRcdGlmICghcHJveHlfc2VsZWN0b3IuZGF0YSgnZXZlbnRzQXR0YWNoZWQnKSkge1xuXHRcdFx0cHJveHlfc2VsZWN0b3Iub24oJ2lucHV0JywgaGFuZGxlSW5wdXQpO1xuXHRcdFx0cHJveHlfc2VsZWN0b3Iub24oJ2ZvY3VzJywgaGFuZGxlRm9jdXMpO1xuXHRcdFx0cHJveHlfc2VsZWN0b3IuZGF0YSgnZXZlbnRzQXR0YWNoZWQnLCB0cnVlKTtcblx0XHR9XG5cblx0XHQvKipcblx0XHQgKiBIYW5kbGUgdGhlIGlucHV0IGV2ZW50XG5cdFx0ICovXG5cdFx0ZnVuY3Rpb24gaGFuZGxlSW5wdXQoKSB7XG5cdFx0XHR2YXIgcHJveHlWYWx1ZSA9IHByb3h5X3NlbGVjdG9yLnZhbCgpO1xuXHRcdFx0aWYgKHByb3h5VmFsdWUuaW5kZXhPZignXFx1MjAyMicpID09PSAtMSkge1xuXHRcdFx0XHRjb25jcmV0ZV9zZWxlY3Rvci52YWwocHJveHlWYWx1ZSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0LyoqXG5cdFx0ICogSGFuZGxlIHRoZSBmb2N1cyBldmVudFxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIGhhbmRsZUZvY3VzKCkge1xuXHRcdFx0dmFyIGNvbmNyZXRlX3ZhbHVlID0gY29uY3JldGVfc2VsZWN0b3IudmFsKCk7XG5cdFx0XHRwcm94eV9zZWxlY3Rvci52YWwoY29uY3JldGVfdmFsdWUpO1xuXHRcdH1cblxuXHR9XG5cblx0XHQvLyBVcGRhdGUgdGhlIGNvbmNyZXRlIGZpZWxkIHdoZW4gdGhlIHByb3h5IGlzIHVwZGF0ZWQuXG5cblxuXHRtYXNrRmllbGQoJCgnI2Nsb3VkZmxhcmVfYXBpX2tleV9tYXNrJyksICQoJyNjbG91ZGZsYXJlX2FwaV9rZXknKSk7XG5cdG1hc2tGaWVsZCgkKCcjY2xvdWRmbGFyZV96b25lX2lkX21hc2snKSwgJCgnI2Nsb3VkZmxhcmVfem9uZV9pZCcpKTtcblxuXHQvLyBEaXNwbGF5L0hpZGUgY2hpbGRlcm4gZmllbGRzIG9uIGNoZWNrYm94IGNoYW5nZS5cbiAgICAkKCAnLndwci1pc1BhcmVudCBpbnB1dFt0eXBlPWNoZWNrYm94XScgKS5vbignY2hhbmdlJywgZnVuY3Rpb24oKSB7XG4gICAgICAgIHdwclNob3dDaGlsZHJlbigkKHRoaXMpKTtcbiAgICB9KTtcblxuICAgIC8vIE9uIHBhZ2UgbG9hZCwgZGlzcGxheSB0aGUgYWN0aXZlIGZpZWxkcy5cbiAgICAkKCAnLndwci1maWVsZC0tY2hpbGRyZW4nICkuZWFjaCggZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciAkZmllbGQgPSAkKCB0aGlzICk7XG5cbiAgICAgICAgaWYgKCB3cHJJc1BhcmVudEFjdGl2ZSggJGZpZWxkICkgKSB7XG4gICAgICAgICAgICAkZmllbGQuYWRkQ2xhc3MoICd3cHItaXNPcGVuJyApO1xuICAgICAgICB9XG4gICAgfSApO1xuXG5cblxuXG4gICAgLyoqKlxuICAgICogV2FybmluZyBmaWVsZHNcbiAgICAqKiovXG5cbiAgICB2YXIgJHdhcm5pbmdQYXJlbnQgPSAkKCcud3ByLWZpZWxkLS1wYXJlbnQnKTtcbiAgICB2YXIgJHdhcm5pbmdQYXJlbnRJbnB1dCA9ICQoJy53cHItZmllbGQtLXBhcmVudCBpbnB1dFt0eXBlPWNoZWNrYm94XScpO1xuXG4gICAgLy8gSWYgYWxyZWFkeSBjaGVja2VkXG4gICAgJHdhcm5pbmdQYXJlbnRJbnB1dC5lYWNoKGZ1bmN0aW9uKCl7XG4gICAgICAgIHdwclNob3dDaGlsZHJlbigkKHRoaXMpKTtcbiAgICB9KTtcblxuICAgICR3YXJuaW5nUGFyZW50Lm9uKCdjaGFuZ2UnLCBmdW5jdGlvbigpIHtcbiAgICAgICAgd3ByU2hvd1dhcm5pbmcoJCh0aGlzKSk7XG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiB3cHJTaG93V2FybmluZyhhRWxlbSl7XG4gICAgICAgIHZhciAkd2FybmluZ0ZpZWxkID0gYUVsZW0ubmV4dCgnLndwci1maWVsZFdhcm5pbmcnKSxcbiAgICAgICAgICAgICR0aGlzQ2hlY2tib3ggPSBhRWxlbS5maW5kKCdpbnB1dFt0eXBlPWNoZWNrYm94XScpLFxuICAgICAgICAgICAgJG5leHRXYXJuaW5nID0gYUVsZW0ucGFyZW50KCkubmV4dCgnLndwci13YXJuaW5nQ29udGFpbmVyJyksXG4gICAgICAgICAgICAkbmV4dEZpZWxkcyA9ICRuZXh0V2FybmluZy5maW5kKCcud3ByLWZpZWxkJyksXG4gICAgICAgICAgICBwYXJlbnRJZCA9IGFFbGVtLmZpbmQoJ2lucHV0W3R5cGU9Y2hlY2tib3hdJykuYXR0cignaWQnKSxcbiAgICAgICAgICAgICRjaGlsZHJlbiA9ICQoJ1tkYXRhLXBhcmVudD1cIicgKyBwYXJlbnRJZCArICdcIl0nKVxuICAgICAgICA7XG5cbiAgICAgICAgLy8gQ2hlY2sgd2FybmluZyBwYXJlbnRcbiAgICAgICAgaWYoJHRoaXNDaGVja2JveC5pcygnOmNoZWNrZWQnKSl7XG4gICAgICAgICAgICAkd2FybmluZ0ZpZWxkLmFkZENsYXNzKCd3cHItaXNPcGVuJyk7XG4gICAgICAgICAgICAkdGhpc0NoZWNrYm94LnByb3AoJ2NoZWNrZWQnLCBmYWxzZSk7XG4gICAgICAgICAgICBhRWxlbS50cmlnZ2VyKCdjaGFuZ2UnKTtcblxuXG4gICAgICAgICAgICB2YXIgJHdhcm5pbmdCdXR0b24gPSAkd2FybmluZ0ZpZWxkLmZpbmQoJy53cHItYnV0dG9uJyk7XG5cbiAgICAgICAgICAgIC8vIFZhbGlkYXRlIHRoZSB3YXJuaW5nXG4gICAgICAgICAgICAkd2FybmluZ0J1dHRvbi5vbignY2xpY2snLCBmdW5jdGlvbigpe1xuICAgICAgICAgICAgICAgICR0aGlzQ2hlY2tib3gucHJvcCgnY2hlY2tlZCcsIHRydWUpO1xuICAgICAgICAgICAgICAgICR3YXJuaW5nRmllbGQucmVtb3ZlQ2xhc3MoJ3dwci1pc09wZW4nKTtcbiAgICAgICAgICAgICAgICAkY2hpbGRyZW4uYWRkQ2xhc3MoJ3dwci1pc09wZW4nKTtcblxuICAgICAgICAgICAgICAgIC8vIElmIG5leHQgZWxlbSA9IGRpc2FibGVkXG4gICAgICAgICAgICAgICAgaWYoJG5leHRXYXJuaW5nLmxlbmd0aCA+IDApe1xuICAgICAgICAgICAgICAgICAgICAkbmV4dEZpZWxkcy5yZW1vdmVDbGFzcygnd3ByLWlzRGlzYWJsZWQnKTtcbiAgICAgICAgICAgICAgICAgICAgJG5leHRGaWVsZHMuZmluZCgnaW5wdXQnKS5wcm9wKCdkaXNhYmxlZCcsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNle1xuICAgICAgICAgICAgJG5leHRGaWVsZHMuYWRkQ2xhc3MoJ3dwci1pc0Rpc2FibGVkJyk7XG4gICAgICAgICAgICAkbmV4dEZpZWxkcy5maW5kKCdpbnB1dCcpLnByb3AoJ2Rpc2FibGVkJywgdHJ1ZSk7XG4gICAgICAgICAgICAkbmV4dEZpZWxkcy5maW5kKCdpbnB1dFt0eXBlPWNoZWNrYm94XScpLnByb3AoJ2NoZWNrZWQnLCBmYWxzZSk7XG4gICAgICAgICAgICAkY2hpbGRyZW4ucmVtb3ZlQ2xhc3MoJ3dwci1pc09wZW4nKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENOQU1FUyBhZGQvcmVtb3ZlIGxpbmVzXG4gICAgICovXG4gICAgJChkb2N1bWVudCkub24oJ2NsaWNrJywgJy53cHItbXVsdGlwbGUtY2xvc2UnLCBmdW5jdGlvbihlKSB7XG5cdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdCQodGhpcykucGFyZW50KCkuc2xpZGVVcCggJ3Nsb3cnICwgZnVuY3Rpb24oKXskKHRoaXMpLnJlbW92ZSgpOyB9ICk7XG5cdH0gKTtcblxuXHQkKCcud3ByLWJ1dHRvbi0tYWRkTXVsdGknKS5vbignY2xpY2snLCBmdW5jdGlvbihlKSB7XG5cdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAkKCQoJyN3cHItY25hbWUtbW9kZWwnKS5odG1sKCkpLmFwcGVuZFRvKCcjd3ByLWNuYW1lcy1saXN0Jyk7XG4gICAgfSk7XG5cblx0LyoqKlxuXHQgKiBXcHIgUmFkaW8gYnV0dG9uXG5cdCAqKiovXG5cdHZhciBkaXNhYmxlX3JhZGlvX3dhcm5pbmcgPSBmYWxzZTtcblxuXHQkKGRvY3VtZW50KS5vbignY2xpY2snLCAnLndwci1yYWRpby1idXR0b25zLWNvbnRhaW5lciBidXR0b24nLCBmdW5jdGlvbihlKSB7XG5cdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdGlmKCQodGhpcykuaGFzQ2xhc3MoJ3JhZGlvLWFjdGl2ZScpKXtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdFx0dmFyICRwYXJlbnQgPSAkKHRoaXMpLnBhcmVudHMoJy53cHItcmFkaW8tYnV0dG9ucycpO1xuXHRcdCRwYXJlbnQuZmluZCgnLndwci1yYWRpby1idXR0b25zLWNvbnRhaW5lciBidXR0b24nKS5yZW1vdmVDbGFzcygncmFkaW8tYWN0aXZlJyk7XG5cdFx0JHBhcmVudC5maW5kKCcud3ByLWV4dHJhLWZpZWxkcy1jb250YWluZXInKS5yZW1vdmVDbGFzcygnd3ByLWlzT3BlbicpO1xuXHRcdCRwYXJlbnQuZmluZCgnLndwci1maWVsZFdhcm5pbmcnKS5yZW1vdmVDbGFzcygnd3ByLWlzT3BlbicpO1xuXHRcdCQodGhpcykuYWRkQ2xhc3MoJ3JhZGlvLWFjdGl2ZScpO1xuXHRcdHdwclNob3dSYWRpb1dhcm5pbmcoJCh0aGlzKSk7XG5cblx0fSApO1xuXG5cblx0ZnVuY3Rpb24gd3ByU2hvd1JhZGlvV2FybmluZygkZWxtKXtcblx0XHRkaXNhYmxlX3JhZGlvX3dhcm5pbmcgPSBmYWxzZTtcblx0XHQkZWxtLnRyaWdnZXIoIFwiYmVmb3JlX3Nob3dfcmFkaW9fd2FybmluZ1wiLCBbICRlbG0gXSApO1xuXHRcdGlmICghJGVsbS5oYXNDbGFzcygnaGFzLXdhcm5pbmcnKSB8fCBkaXNhYmxlX3JhZGlvX3dhcm5pbmcpIHtcblx0XHRcdHdwclNob3dSYWRpb0J1dHRvbkNoaWxkcmVuKCRlbG0pO1xuXHRcdFx0JGVsbS50cmlnZ2VyKCBcInJhZGlvX2J1dHRvbl9zZWxlY3RlZFwiLCBbICRlbG0gXSApO1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0XHR2YXIgJHdhcm5pbmdGaWVsZCA9ICQoJ1tkYXRhLXBhcmVudD1cIicgKyAkZWxtLmF0dHIoJ2lkJykgKyAnXCJdLndwci1maWVsZFdhcm5pbmcnKTtcblx0XHQkd2FybmluZ0ZpZWxkLmFkZENsYXNzKCd3cHItaXNPcGVuJyk7XG5cdFx0dmFyICR3YXJuaW5nQnV0dG9uID0gJHdhcm5pbmdGaWVsZC5maW5kKCcud3ByLWJ1dHRvbicpO1xuXG5cdFx0Ly8gVmFsaWRhdGUgdGhlIHdhcm5pbmdcblx0XHQkd2FybmluZ0J1dHRvbi5vbignY2xpY2snLCBmdW5jdGlvbigpe1xuXHRcdFx0JHdhcm5pbmdGaWVsZC5yZW1vdmVDbGFzcygnd3ByLWlzT3BlbicpO1xuXHRcdFx0d3ByU2hvd1JhZGlvQnV0dG9uQ2hpbGRyZW4oJGVsbSk7XG5cdFx0XHQkZWxtLnRyaWdnZXIoIFwicmFkaW9fYnV0dG9uX3NlbGVjdGVkXCIsIFsgJGVsbSBdICk7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fSk7XG5cdH1cblxuXHRmdW5jdGlvbiB3cHJTaG93UmFkaW9CdXR0b25DaGlsZHJlbigkZWxtKSB7XG5cdFx0dmFyICRwYXJlbnQgPSAkZWxtLnBhcmVudHMoJy53cHItcmFkaW8tYnV0dG9ucycpO1xuXHRcdHZhciAkY2hpbGRyZW4gPSAkKCcud3ByLWV4dHJhLWZpZWxkcy1jb250YWluZXJbZGF0YS1wYXJlbnQ9XCInICsgJGVsbS5hdHRyKCdpZCcpICsgJ1wiXScpO1xuXHRcdCRjaGlsZHJlbi5hZGRDbGFzcygnd3ByLWlzT3BlbicpO1xuXHR9XG5cblx0LyoqKlxuXHQgKiBXcHIgT3B0aW1pemUgQ3NzIERlbGl2ZXJ5IEZpZWxkXG5cdCAqKiovXG5cdHZhciBydWNzc0FjdGl2ZSA9IHBhcnNlSW50KCQoJyNyZW1vdmVfdW51c2VkX2NzcycpLnZhbCgpKTtcblxuXHQkKCBcIiNvcHRpbWl6ZV9jc3NfZGVsaXZlcnlfbWV0aG9kIC53cHItcmFkaW8tYnV0dG9ucy1jb250YWluZXIgYnV0dG9uXCIgKVxuXHRcdC5vbiggXCJyYWRpb19idXR0b25fc2VsZWN0ZWRcIiwgZnVuY3Rpb24oIGV2ZW50LCAkZWxtICkge1xuXHRcdFx0dG9nZ2xlQWN0aXZlT3B0aW1pemVDc3NEZWxpdmVyeU1ldGhvZCgkZWxtKTtcblx0XHR9KTtcblxuXHQkKFwiI29wdGltaXplX2Nzc19kZWxpdmVyeVwiKS5vbihcImNoYW5nZVwiLCBmdW5jdGlvbigpe1xuXHRcdGlmKCAkKHRoaXMpLmlzKFwiOm5vdCg6Y2hlY2tlZClcIikgKXtcblx0XHRcdGRpc2FibGVPcHRpbWl6ZUNzc0RlbGl2ZXJ5KCk7XG5cdFx0fWVsc2V7XG5cdFx0XHR2YXIgZGVmYXVsdF9yYWRpb19idXR0b25faWQgPSAnIycrJCgnI29wdGltaXplX2Nzc19kZWxpdmVyeV9tZXRob2QnKS5kYXRhKCAnZGVmYXVsdCcgKTtcblx0XHRcdCQoZGVmYXVsdF9yYWRpb19idXR0b25faWQpLnRyaWdnZXIoJ2NsaWNrJyk7XG5cdFx0fVxuXHR9KTtcblxuXHRmdW5jdGlvbiB0b2dnbGVBY3RpdmVPcHRpbWl6ZUNzc0RlbGl2ZXJ5TWV0aG9kKCRlbG0pIHtcblx0XHR2YXIgb3B0aW1pemVfbWV0aG9kID0gJGVsbS5kYXRhKCd2YWx1ZScpO1xuXHRcdGlmKCdyZW1vdmVfdW51c2VkX2NzcycgPT09IG9wdGltaXplX21ldGhvZCl7XG5cdFx0XHQkKCcjcmVtb3ZlX3VudXNlZF9jc3MnKS52YWwoMSk7XG5cdFx0XHQkKCcjYXN5bmNfY3NzJykudmFsKDApO1xuXHRcdH1lbHNle1xuXHRcdFx0JCgnI3JlbW92ZV91bnVzZWRfY3NzJykudmFsKDApO1xuXHRcdFx0JCgnI2FzeW5jX2NzcycpLnZhbCgxKTtcblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc2FibGVPcHRpbWl6ZUNzc0RlbGl2ZXJ5KCkge1xuXHRcdCQoJyNyZW1vdmVfdW51c2VkX2NzcycpLnZhbCgwKTtcblx0XHQkKCcjYXN5bmNfY3NzJykudmFsKDApO1xuXHR9XG5cblx0JCggXCIjb3B0aW1pemVfY3NzX2RlbGl2ZXJ5X21ldGhvZCAud3ByLXJhZGlvLWJ1dHRvbnMtY29udGFpbmVyIGJ1dHRvblwiIClcblx0XHQub24oIFwiYmVmb3JlX3Nob3dfcmFkaW9fd2FybmluZ1wiLCBmdW5jdGlvbiggZXZlbnQsICRlbG0gKSB7XG5cdFx0XHRkaXNhYmxlX3JhZGlvX3dhcm5pbmcgPSAoJ3JlbW92ZV91bnVzZWRfY3NzJyA9PT0gJGVsbS5kYXRhKCd2YWx1ZScpICYmIDEgPT09IHJ1Y3NzQWN0aXZlKVxuXHRcdH0pO1xuXG5cdCQoIFwiLndwci1tdWx0aXBsZS1zZWxlY3QgLndwci1saXN0LWhlYWRlci1hcnJvd1wiICkuY2xpY2soZnVuY3Rpb24gKGUpIHtcblx0XHQkKGUudGFyZ2V0KS5jbG9zZXN0KCcud3ByLW11bHRpcGxlLXNlbGVjdCAud3ByLWxpc3QnKS50b2dnbGVDbGFzcygnb3BlbicpO1xuXHR9KTtcblxuXHQkKCcud3ByLW11bHRpcGxlLXNlbGVjdCAud3ByLWNoZWNrYm94JykuY2xpY2soZnVuY3Rpb24gKGUpIHtcblx0XHRjb25zdCBjaGVja2JveCA9ICQodGhpcykuZmluZCgnaW5wdXQnKTtcblx0XHRjb25zdCBpc19jaGVja2VkID0gY2hlY2tib3guYXR0cignY2hlY2tlZCcpICE9PSB1bmRlZmluZWQ7XG5cdFx0Y2hlY2tib3guYXR0cignY2hlY2tlZCcsIGlzX2NoZWNrZWQgPyBudWxsIDogJ2NoZWNrZWQnICk7XG5cdFx0Y29uc3Qgc3ViX2NoZWNrYm94ZXMgPSAkKGNoZWNrYm94KS5jbG9zZXN0KCcud3ByLWxpc3QnKS5maW5kKCcud3ByLWxpc3QtYm9keSBpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl0nKTtcblx0XHRpZihjaGVja2JveC5oYXNDbGFzcygnd3ByLW1haW4tY2hlY2tib3gnKSkge1xuXHRcdFx0JC5tYXAoc3ViX2NoZWNrYm94ZXMsIGNoZWNrYm94ID0+IHtcblx0XHRcdFx0JChjaGVja2JveCkuYXR0cignY2hlY2tlZCcsIGlzX2NoZWNrZWQgPyBudWxsIDogJ2NoZWNrZWQnICk7XG5cdFx0XHR9KTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0Y29uc3QgbWFpbl9jaGVja2JveCA9ICQoY2hlY2tib3gpLmNsb3Nlc3QoJy53cHItbGlzdCcpLmZpbmQoJy53cHItbWFpbi1jaGVja2JveCcpO1xuXG5cdFx0Y29uc3Qgc3ViX2NoZWNrZWQgPSAgJC5tYXAoc3ViX2NoZWNrYm94ZXMsIGNoZWNrYm94ID0+IHtcblx0XHRcdGlmKCQoY2hlY2tib3gpLmF0dHIoJ2NoZWNrZWQnKSA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdHJldHVybiA7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gY2hlY2tib3g7XG5cdFx0fSk7XG5cdFx0bWFpbl9jaGVja2JveC5hdHRyKCdjaGVja2VkJywgc3ViX2NoZWNrZWQubGVuZ3RoID09PSBzdWJfY2hlY2tib3hlcy5sZW5ndGggPyAnY2hlY2tlZCcgOiBudWxsICk7XG5cdH0pO1xuXG5cdGlmICggJCggJy53cHItbWFpbi1jaGVja2JveCcgKS5sZW5ndGggPiAwICkge1xuXHRcdCQoJy53cHItbWFpbi1jaGVja2JveCcpLmVhY2goKGNoZWNrYm94X2tleSwgY2hlY2tib3gpID0+IHtcblx0XHRcdGxldCBwYXJlbnRfbGlzdCA9ICQoY2hlY2tib3gpLnBhcmVudHMoJy53cHItbGlzdCcpO1xuXHRcdFx0bGV0IG5vdF9jaGVja2VkID0gcGFyZW50X2xpc3QuZmluZCggJy53cHItbGlzdC1ib2R5IGlucHV0W3R5cGU9Y2hlY2tib3hdOm5vdCg6Y2hlY2tlZCknICkubGVuZ3RoO1xuXHRcdFx0JChjaGVja2JveCkuYXR0cignY2hlY2tlZCcsIG5vdF9jaGVja2VkIDw9IDAgPyAnY2hlY2tlZCcgOiBudWxsICk7XG5cdFx0fSk7XG5cdH1cbn0pO1xuIiwidmFyICQgPSBqUXVlcnk7XG4kKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpe1xuXG5cblx0LyoqKlxuXHQqIERhc2hib2FyZCBub3RpY2Vcblx0KioqL1xuXG5cdHZhciAkbm90aWNlID0gJCgnLndwci1ub3RpY2UnKTtcblx0dmFyICRub3RpY2VDbG9zZSA9ICQoJyN3cHItY29uZ3JhdHVsYXRpb25zLW5vdGljZScpO1xuXG5cdCRub3RpY2VDbG9zZS5vbignY2xpY2snLCBmdW5jdGlvbigpIHtcblx0XHR3cHJDbG9zZURhc2hib2FyZE5vdGljZSgpO1xuXHRcdHJldHVybiBmYWxzZTtcblx0fSk7XG5cblx0ZnVuY3Rpb24gd3ByQ2xvc2VEYXNoYm9hcmROb3RpY2UoKXtcblx0XHR2YXIgdlRMID0gbmV3IFRpbWVsaW5lTGl0ZSgpXG5cdFx0ICAudG8oJG5vdGljZSwgMSwge2F1dG9BbHBoYTowLCB4OjQwLCBlYXNlOlBvd2VyNC5lYXNlT3V0fSlcblx0XHQgIC50bygkbm90aWNlLCAwLjYsIHtoZWlnaHQ6IDAsIG1hcmdpblRvcDowLCBlYXNlOlBvd2VyNC5lYXNlT3V0fSwgJz0tLjQnKVxuXHRcdCAgLnNldCgkbm90aWNlLCB7J2Rpc3BsYXknOidub25lJ30pXG5cdFx0O1xuXHR9XG5cblx0LyoqXG5cdCAqIFJvY2tldCBBbmFseXRpY3Mgbm90aWNlIGluZm8gY29sbGVjdFxuXHQgKi9cblx0JCggJy5yb2NrZXQtYW5hbHl0aWNzLWRhdGEtY29udGFpbmVyJyApLmhpZGUoKTtcblx0JCggJy5yb2NrZXQtcHJldmlldy1hbmFseXRpY3MtZGF0YScgKS5vbiggJ2NsaWNrJywgZnVuY3Rpb24oIGUgKSB7XG5cdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0JCh0aGlzKS5wYXJlbnQoKS5uZXh0KCAnLnJvY2tldC1hbmFseXRpY3MtZGF0YS1jb250YWluZXInICkudG9nZ2xlKCk7XG5cdH0gKTtcblxuXHQvKioqXG5cdCogSGlkZSAvIHNob3cgUm9ja2V0IGFkZG9uIHRhYnMuXG5cdCoqKi9cblxuXHQkKCAnLndwci10b2dnbGUtYnV0dG9uJyApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdHZhciAkYnV0dG9uICAgPSAkKCB0aGlzICk7XG5cdFx0dmFyICRjaGVja2JveCA9ICRidXR0b24uY2xvc2VzdCggJy53cHItZmllbGRzQ29udGFpbmVyLWZpZWxkc2V0JyApLmZpbmQoICcud3ByLXJhZGlvIDpjaGVja2JveCcgKTtcblx0XHR2YXIgJG1lbnVJdGVtID0gJCggJ1tocmVmPVwiJyArICRidXR0b24uYXR0ciggJ2hyZWYnICkgKyAnXCJdLndwci1tZW51SXRlbScgKTtcblxuXHRcdCRjaGVja2JveC5vbignY2hhbmdlJywgZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoICRjaGVja2JveC5pcyggJzpjaGVja2VkJyApICkge1xuXHRcdFx0XHQkbWVudUl0ZW0uY3NzKCAnZGlzcGxheScsICdibG9jaycgKTtcblx0XHRcdFx0JGJ1dHRvbi5jc3MoICdkaXNwbGF5JywgJ2lubGluZS1ibG9jaycgKTtcblx0XHRcdH0gZWxzZXtcblx0XHRcdFx0JG1lbnVJdGVtLmNzcyggJ2Rpc3BsYXknLCAnbm9uZScgKTtcblx0XHRcdFx0JGJ1dHRvbi5jc3MoICdkaXNwbGF5JywgJ25vbmUnICk7XG5cdFx0XHR9XG5cdFx0fSApLnRyaWdnZXIoICdjaGFuZ2UnICk7XG5cdH0gKTtcblxuXG5cblxuXG5cdC8qKipcblx0KiBTaG93IHBvcGluIGFuYWx5dGljc1xuXHQqKiovXG5cblx0dmFyICR3cHJBbmFseXRpY3NQb3BpbiA9ICQoJy53cHItUG9waW4tQW5hbHl0aWNzJyksXG5cdFx0JHdwclBvcGluT3ZlcmxheSA9ICQoJy53cHItUG9waW4tb3ZlcmxheScpLFxuXHRcdCR3cHJBbmFseXRpY3NDbG9zZVBvcGluID0gJCgnLndwci1Qb3Bpbi1BbmFseXRpY3MtY2xvc2UnKSxcblx0XHQkd3ByQW5hbHl0aWNzUG9waW5CdXR0b24gPSAkKCcud3ByLVBvcGluLUFuYWx5dGljcyAud3ByLWJ1dHRvbicpLFxuXHRcdCR3cHJBbmFseXRpY3NPcGVuUG9waW4gPSAkKCcud3ByLWpzLXBvcGluJylcblx0O1xuXG5cdCR3cHJBbmFseXRpY3NPcGVuUG9waW4ub24oJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHR3cHJPcGVuQW5hbHl0aWNzKCk7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9KTtcblxuXHQkd3ByQW5hbHl0aWNzQ2xvc2VQb3Bpbi5vbignY2xpY2snLCBmdW5jdGlvbihlKSB7XG5cdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdHdwckNsb3NlQW5hbHl0aWNzKCk7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9KTtcblxuXHQkd3ByQW5hbHl0aWNzUG9waW5CdXR0b24ub24oJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHR3cHJBY3RpdmF0ZUFuYWx5dGljcygpO1xuXHRcdHJldHVybiBmYWxzZTtcblx0fSk7XG5cblx0ZnVuY3Rpb24gd3ByT3BlbkFuYWx5dGljcygpe1xuXHRcdHZhciB2VEwgPSBuZXcgVGltZWxpbmVMaXRlKClcblx0XHQgIC5zZXQoJHdwckFuYWx5dGljc1BvcGluLCB7J2Rpc3BsYXknOidibG9jayd9KVxuXHRcdCAgLnNldCgkd3ByUG9waW5PdmVybGF5LCB7J2Rpc3BsYXknOidibG9jayd9KVxuXHRcdCAgLmZyb21Ubygkd3ByUG9waW5PdmVybGF5LCAwLjYsIHthdXRvQWxwaGE6MH0se2F1dG9BbHBoYToxLCBlYXNlOlBvd2VyNC5lYXNlT3V0fSlcblx0XHQgIC5mcm9tVG8oJHdwckFuYWx5dGljc1BvcGluLCAwLjYsIHthdXRvQWxwaGE6MCwgbWFyZ2luVG9wOiAtMjR9LCB7YXV0b0FscGhhOjEsIG1hcmdpblRvcDowLCBlYXNlOlBvd2VyNC5lYXNlT3V0fSwgJz0tLjUnKVxuXHRcdDtcblx0fVxuXG5cdGZ1bmN0aW9uIHdwckNsb3NlQW5hbHl0aWNzKCl7XG5cdFx0dmFyIHZUTCA9IG5ldyBUaW1lbGluZUxpdGUoKVxuXHRcdCAgLmZyb21Ubygkd3ByQW5hbHl0aWNzUG9waW4sIDAuNiwge2F1dG9BbHBoYToxLCBtYXJnaW5Ub3A6IDB9LCB7YXV0b0FscGhhOjAsIG1hcmdpblRvcDotMjQsIGVhc2U6UG93ZXI0LmVhc2VPdXR9KVxuXHRcdCAgLmZyb21Ubygkd3ByUG9waW5PdmVybGF5LCAwLjYsIHthdXRvQWxwaGE6MX0se2F1dG9BbHBoYTowLCBlYXNlOlBvd2VyNC5lYXNlT3V0fSwgJz0tLjUnKVxuXHRcdCAgLnNldCgkd3ByQW5hbHl0aWNzUG9waW4sIHsnZGlzcGxheSc6J25vbmUnfSlcblx0XHQgIC5zZXQoJHdwclBvcGluT3ZlcmxheSwgeydkaXNwbGF5Jzonbm9uZSd9KVxuXHRcdDtcblx0fVxuXG5cdGZ1bmN0aW9uIHdwckFjdGl2YXRlQW5hbHl0aWNzKCl7XG5cdFx0d3ByQ2xvc2VBbmFseXRpY3MoKTtcblx0XHQkKCcjYW5hbHl0aWNzX2VuYWJsZWQnKS5wcm9wKCdjaGVja2VkJywgdHJ1ZSk7XG5cdFx0JCgnI2FuYWx5dGljc19lbmFibGVkJykudHJpZ2dlcignY2hhbmdlJyk7XG5cdH1cblxuXHQvLyBEaXNwbGF5IENUQSB3aXRoaW4gdGhlIHBvcGluIGBXaGF0IGluZm8gd2lsbCB3ZSBjb2xsZWN0P2Bcblx0JCgnI2FuYWx5dGljc19lbmFibGVkJykub24oJ2NoYW5nZScsIGZ1bmN0aW9uICgpIHtcblx0XHQkKCcud3ByLXJvY2tldC1hbmFseXRpY3MtY3RhJykudG9nZ2xlQ2xhc3MoJ3dwci1pc0hpZGRlbicpO1xuXHR9KTtcblxuXHQvKioqXG5cdCogU2hvdyBwb3BpbiB1cGdyYWRlXG5cdCoqKi9cblxuXHR2YXIgJHdwclVwZ3JhZGVQb3BpbiA9ICQoJy53cHItUG9waW4tVXBncmFkZScpLFxuXHQkd3ByVXBncmFkZUNsb3NlUG9waW4gPSAkKCcud3ByLVBvcGluLVVwZ3JhZGUtY2xvc2UnKSxcblx0JHdwclVwZ3JhZGVPcGVuUG9waW4gPSAkKCcud3ByLXBvcGluLXVwZ3JhZGUtdG9nZ2xlJyk7XG5cblx0JHdwclVwZ3JhZGVPcGVuUG9waW4ub24oJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHR3cHJPcGVuVXBncmFkZVBvcGluKCk7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9KTtcblxuXHQkd3ByVXBncmFkZUNsb3NlUG9waW4ub24oJ2NsaWNrJywgZnVuY3Rpb24oKSB7XG5cdFx0d3ByQ2xvc2VVcGdyYWRlUG9waW4oKTtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0pO1xuXG5cdGZ1bmN0aW9uIHdwck9wZW5VcGdyYWRlUG9waW4oKXtcblx0XHR2YXIgdlRMID0gbmV3IFRpbWVsaW5lTGl0ZSgpO1xuXG5cdFx0dlRMLnNldCgkd3ByVXBncmFkZVBvcGluLCB7J2Rpc3BsYXknOidibG9jayd9KVxuXHRcdFx0LnNldCgkd3ByUG9waW5PdmVybGF5LCB7J2Rpc3BsYXknOidibG9jayd9KVxuXHRcdFx0LmZyb21Ubygkd3ByUG9waW5PdmVybGF5LCAwLjYsIHthdXRvQWxwaGE6MH0se2F1dG9BbHBoYToxLCBlYXNlOlBvd2VyNC5lYXNlT3V0fSlcblx0XHRcdC5mcm9tVG8oJHdwclVwZ3JhZGVQb3BpbiwgMC42LCB7YXV0b0FscGhhOjAsIG1hcmdpblRvcDogLTI0fSwge2F1dG9BbHBoYToxLCBtYXJnaW5Ub3A6MCwgZWFzZTpQb3dlcjQuZWFzZU91dH0sICc9LS41Jylcblx0XHQ7XG5cdH1cblxuXHRmdW5jdGlvbiB3cHJDbG9zZVVwZ3JhZGVQb3Bpbigpe1xuXHRcdHZhciB2VEwgPSBuZXcgVGltZWxpbmVMaXRlKCk7XG5cblx0XHR2VEwuZnJvbVRvKCR3cHJVcGdyYWRlUG9waW4sIDAuNiwge2F1dG9BbHBoYToxLCBtYXJnaW5Ub3A6IDB9LCB7YXV0b0FscGhhOjAsIG1hcmdpblRvcDotMjQsIGVhc2U6UG93ZXI0LmVhc2VPdXR9KVxuXHRcdFx0LmZyb21Ubygkd3ByUG9waW5PdmVybGF5LCAwLjYsIHthdXRvQWxwaGE6MX0se2F1dG9BbHBoYTowLCBlYXNlOlBvd2VyNC5lYXNlT3V0fSwgJz0tLjUnKVxuXHRcdFx0LnNldCgkd3ByVXBncmFkZVBvcGluLCB7J2Rpc3BsYXknOidub25lJ30pXG5cdFx0XHQuc2V0KCR3cHJQb3Bpbk92ZXJsYXksIHsnZGlzcGxheSc6J25vbmUnfSlcblx0XHQ7XG5cdH1cblxuXHQvKioqXG5cdCogU2lkZWJhciBvbi9vZmZcblx0KioqL1xuXHR2YXIgJHdwclNpZGViYXIgICAgPSAkKCAnLndwci1TaWRlYmFyJyApO1xuXHR2YXIgJHdwckJ1dHRvblRpcHMgPSAkKCcud3ByLWpzLXRpcHMnKTtcblxuXHQkd3ByQnV0dG9uVGlwcy5vbignY2hhbmdlJywgZnVuY3Rpb24oKSB7XG5cdFx0d3ByRGV0ZWN0VGlwcygkKHRoaXMpKTtcblx0fSk7XG5cblx0ZnVuY3Rpb24gd3ByRGV0ZWN0VGlwcyhhRWxlbSl7XG5cdFx0aWYoYUVsZW0uaXMoJzpjaGVja2VkJykpe1xuXHRcdFx0JHdwclNpZGViYXIuY3NzKCdkaXNwbGF5JywnYmxvY2snKTtcblx0XHRcdGxvY2FsU3RvcmFnZS5zZXRJdGVtKCAnd3ByLXNob3ctc2lkZWJhcicsICdvbicgKTtcblx0XHR9XG5cdFx0ZWxzZXtcblx0XHRcdCR3cHJTaWRlYmFyLmNzcygnZGlzcGxheScsJ25vbmUnKTtcblx0XHRcdGxvY2FsU3RvcmFnZS5zZXRJdGVtKCAnd3ByLXNob3ctc2lkZWJhcicsICdvZmYnICk7XG5cdFx0fVxuXHR9XG5cblxuXG5cdC8qKipcblx0KiBEZXRlY3QgQWRibG9ja1xuXHQqKiovXG5cblx0aWYoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ0xLZ09jQ1Jwd21BaicpKXtcblx0XHQkKCcud3ByLWFkYmxvY2snKS5jc3MoJ2Rpc3BsYXknLCAnbm9uZScpO1xuXHR9IGVsc2Uge1xuXHRcdCQoJy53cHItYWRibG9jaycpLmNzcygnZGlzcGxheScsICdibG9jaycpO1xuXHR9XG5cblx0dmFyICRhZGJsb2NrID0gJCgnLndwci1hZGJsb2NrJyk7XG5cdHZhciAkYWRibG9ja0Nsb3NlID0gJCgnLndwci1hZGJsb2NrLWNsb3NlJyk7XG5cblx0JGFkYmxvY2tDbG9zZS5vbignY2xpY2snLCBmdW5jdGlvbigpIHtcblx0XHR3cHJDbG9zZUFkYmxvY2tOb3RpY2UoKTtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0pO1xuXG5cdGZ1bmN0aW9uIHdwckNsb3NlQWRibG9ja05vdGljZSgpe1xuXHRcdHZhciB2VEwgPSBuZXcgVGltZWxpbmVMaXRlKClcblx0XHQgIC50bygkYWRibG9jaywgMSwge2F1dG9BbHBoYTowLCB4OjQwLCBlYXNlOlBvd2VyNC5lYXNlT3V0fSlcblx0XHQgIC50bygkYWRibG9jaywgMC40LCB7aGVpZ2h0OiAwLCBtYXJnaW5Ub3A6MCwgZWFzZTpQb3dlcjQuZWFzZU91dH0sICc9LS40Jylcblx0XHQgIC5zZXQoJGFkYmxvY2ssIHsnZGlzcGxheSc6J25vbmUnfSlcblx0XHQ7XG5cdH1cblxufSk7XG4iLCJkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCAnRE9NQ29udGVudExvYWRlZCcsIGZ1bmN0aW9uICgpIHtcblxuICAgIHZhciAkcGFnZU1hbmFnZXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFwiLndwci1Db250ZW50XCIpO1xuICAgIGlmKCRwYWdlTWFuYWdlcil7XG4gICAgICAgIG5ldyBQYWdlTWFuYWdlcigkcGFnZU1hbmFnZXIpO1xuICAgIH1cblxufSk7XG5cblxuLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSpcXFxuXHRcdENMQVNTIFBBR0VNQU5BR0VSXG5cXCotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG4vKipcbiAqIE1hbmFnZXMgdGhlIGRpc3BsYXkgb2YgcGFnZXMgLyBzZWN0aW9uIGZvciBXUCBSb2NrZXQgcGx1Z2luXG4gKlxuICogUHVibGljIG1ldGhvZCA6XG4gICAgIGRldGVjdElEIC0gRGV0ZWN0IElEIHdpdGggaGFzaFxuICAgICBnZXRCb2R5VG9wIC0gR2V0IGJvZHkgdG9wIHBvc2l0aW9uXG5cdCBjaGFuZ2UgLSBEaXNwbGF5cyB0aGUgY29ycmVzcG9uZGluZyBwYWdlXG4gKlxuICovXG5cbmZ1bmN0aW9uIFBhZ2VNYW5hZ2VyKGFFbGVtKSB7XG5cbiAgICB2YXIgcmVmVGhpcyA9IHRoaXM7XG5cbiAgICB0aGlzLiRib2R5ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLndwci1ib2R5Jyk7XG4gICAgdGhpcy4kbWVudUl0ZW1zID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLndwci1tZW51SXRlbScpO1xuICAgIHRoaXMuJHN1Ym1pdEJ1dHRvbiA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy53cHItQ29udGVudCA+IGZvcm0gPiAjd3ByLW9wdGlvbnMtc3VibWl0Jyk7XG4gICAgdGhpcy4kcGFnZXMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcud3ByLVBhZ2UnKTtcbiAgICB0aGlzLiRzaWRlYmFyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLndwci1TaWRlYmFyJyk7XG4gICAgdGhpcy4kY29udGVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy53cHItQ29udGVudCcpO1xuICAgIHRoaXMuJHRpcHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcud3ByLUNvbnRlbnQtdGlwcycpO1xuICAgIHRoaXMuJGxpbmtzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLndwci1ib2R5IGEnKTtcbiAgICB0aGlzLiRtZW51SXRlbSA9IG51bGw7XG4gICAgdGhpcy4kcGFnZSA9IG51bGw7XG4gICAgdGhpcy5wYWdlSWQgPSBudWxsO1xuICAgIHRoaXMuYm9keVRvcCA9IDA7XG4gICAgdGhpcy5idXR0b25UZXh0ID0gdGhpcy4kc3VibWl0QnV0dG9uLnZhbHVlO1xuXG4gICAgcmVmVGhpcy5nZXRCb2R5VG9wKCk7XG5cbiAgICAvLyBJZiB1cmwgcGFnZSBjaGFuZ2VcbiAgICB3aW5kb3cub25oYXNoY2hhbmdlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJlZlRoaXMuZGV0ZWN0SUQoKTtcbiAgICB9XG5cbiAgICAvLyBJZiBoYXNoIGFscmVhZHkgZXhpc3QgKGFmdGVyIHJlZnJlc2ggcGFnZSBmb3IgZXhhbXBsZSlcbiAgICBpZih3aW5kb3cubG9jYXRpb24uaGFzaCl7XG4gICAgICAgIHRoaXMuYm9keVRvcCA9IDA7XG4gICAgICAgIHRoaXMuZGV0ZWN0SUQoKTtcbiAgICB9XG4gICAgZWxzZXtcbiAgICAgICAgdmFyIHNlc3Npb24gPSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnd3ByLWhhc2gnKTtcbiAgICAgICAgdGhpcy5ib2R5VG9wID0gMDtcblxuICAgICAgICBpZihzZXNzaW9uKXtcbiAgICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5oYXNoID0gc2Vzc2lvbjtcbiAgICAgICAgICAgIHRoaXMuZGV0ZWN0SUQoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNle1xuICAgICAgICAgICAgdGhpcy4kbWVudUl0ZW1zWzBdLmNsYXNzTGlzdC5hZGQoJ2lzQWN0aXZlJyk7XG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSgnd3ByLWhhc2gnLCAnZGFzaGJvYXJkJyk7XG4gICAgICAgICAgICB3aW5kb3cubG9jYXRpb24uaGFzaCA9ICcjZGFzaGJvYXJkJztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIENsaWNrIGxpbmsgc2FtZSBoYXNoXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLiRsaW5rcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLiRsaW5rc1tpXS5vbmNsaWNrID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZWZUaGlzLmdldEJvZHlUb3AoKTtcbiAgICAgICAgICAgIHZhciBocmVmU3BsaXQgPSB0aGlzLmhyZWYuc3BsaXQoJyMnKVsxXTtcbiAgICAgICAgICAgIGlmKGhyZWZTcGxpdCA9PSByZWZUaGlzLnBhZ2VJZCAmJiBocmVmU3BsaXQgIT0gdW5kZWZpbmVkKXtcbiAgICAgICAgICAgICAgICByZWZUaGlzLmRldGVjdElEKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8vIENsaWNrIGxpbmtzIG5vdCBXUCByb2NrZXQgdG8gcmVzZXQgaGFzaFxuICAgIHZhciAkb3RoZXJsaW5rcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJyNhZG1pbm1lbnVtYWluIGEsICN3cGFkbWluYmFyIGEnKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8ICRvdGhlcmxpbmtzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICRvdGhlcmxpbmtzW2ldLm9uY2xpY2sgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKCd3cHItaGFzaCcsICcnKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbn1cblxuXG4vKlxuKiBQYWdlIGRldGVjdCBJRFxuKi9cblBhZ2VNYW5hZ2VyLnByb3RvdHlwZS5kZXRlY3RJRCA9IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucGFnZUlkID0gd2luZG93LmxvY2F0aW9uLmhhc2guc3BsaXQoJyMnKVsxXTtcbiAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSgnd3ByLWhhc2gnLCB0aGlzLnBhZ2VJZCk7XG5cbiAgICB0aGlzLiRwYWdlID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLndwci1QYWdlIycgKyB0aGlzLnBhZ2VJZCk7XG4gICAgdGhpcy4kbWVudUl0ZW0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnd3ByLW5hdi0nICsgdGhpcy5wYWdlSWQpO1xuXG4gICAgdGhpcy5jaGFuZ2UoKTtcbn1cblxuXG5cbi8qXG4qIEdldCBib2R5IHRvcCBwb3NpdGlvblxuKi9cblBhZ2VNYW5hZ2VyLnByb3RvdHlwZS5nZXRCb2R5VG9wID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGJvZHlQb3MgPSB0aGlzLiRib2R5LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIHRoaXMuYm9keVRvcCA9IGJvZHlQb3MudG9wICsgd2luZG93LnBhZ2VZT2Zmc2V0IC0gNDc7IC8vICN3cGFkbWluYmFyICsgcGFkZGluZy10b3AgLndwci13cmFwIC0gMSAtIDQ3XG59XG5cblxuXG4vKlxuKiBQYWdlIGNoYW5nZVxuKi9cblBhZ2VNYW5hZ2VyLnByb3RvdHlwZS5jaGFuZ2UgPSBmdW5jdGlvbigpIHtcblxuICAgIHZhciByZWZUaGlzID0gdGhpcztcbiAgICBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsVG9wID0gcmVmVGhpcy5ib2R5VG9wO1xuXG4gICAgLy8gSGlkZSBvdGhlciBwYWdlc1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy4kcGFnZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy4kcGFnZXNbaV0uc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICB9XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLiRtZW51SXRlbXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy4kbWVudUl0ZW1zW2ldLmNsYXNzTGlzdC5yZW1vdmUoJ2lzQWN0aXZlJyk7XG4gICAgfVxuXG4gICAgLy8gU2hvdyBjdXJyZW50IGRlZmF1bHQgcGFnZVxuICAgIHRoaXMuJHBhZ2Uuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XG4gICAgdGhpcy4kc3VibWl0QnV0dG9uLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuXG4gICAgaWYgKCBudWxsID09PSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSggJ3dwci1zaG93LXNpZGViYXInICkgKSB7XG4gICAgICAgIGxvY2FsU3RvcmFnZS5zZXRJdGVtKCAnd3ByLXNob3ctc2lkZWJhcicsICdvbicgKTtcbiAgICB9XG5cbiAgICBpZiAoICdvbicgPT09IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCd3cHItc2hvdy1zaWRlYmFyJykgKSB7XG4gICAgICAgIHRoaXMuJHNpZGViYXIuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7XG4gICAgfSBlbHNlIGlmICggJ29mZicgPT09IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCd3cHItc2hvdy1zaWRlYmFyJykgKSB7XG4gICAgICAgIHRoaXMuJHNpZGViYXIuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI3dwci1qcy10aXBzJykucmVtb3ZlQXR0cmlidXRlKCAnY2hlY2tlZCcgKTtcbiAgICB9XG5cbiAgICB0aGlzLiR0aXBzLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuICAgIHRoaXMuJG1lbnVJdGVtLmNsYXNzTGlzdC5hZGQoJ2lzQWN0aXZlJyk7XG4gICAgdGhpcy4kc3VibWl0QnV0dG9uLnZhbHVlID0gdGhpcy5idXR0b25UZXh0O1xuICAgIHRoaXMuJGNvbnRlbnQuY2xhc3NMaXN0LmFkZCgnaXNOb3RGdWxsJyk7XG5cblxuICAgIC8vIEV4Y2VwdGlvbiBmb3IgZGFzaGJvYXJkXG4gICAgaWYodGhpcy5wYWdlSWQgPT0gXCJkYXNoYm9hcmRcIil7XG4gICAgICAgIHRoaXMuJHNpZGViYXIuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgdGhpcy4kdGlwcy5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgICB0aGlzLiRzdWJtaXRCdXR0b24uc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgdGhpcy4kY29udGVudC5jbGFzc0xpc3QucmVtb3ZlKCdpc05vdEZ1bGwnKTtcbiAgICB9XG5cbiAgICAvLyBFeGNlcHRpb24gZm9yIGFkZG9uc1xuICAgIGlmKHRoaXMucGFnZUlkID09IFwiYWRkb25zXCIpe1xuICAgICAgICB0aGlzLiRzdWJtaXRCdXR0b24uc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICB9XG5cbiAgICAvLyBFeGNlcHRpb24gZm9yIGRhdGFiYXNlXG4gICAgaWYodGhpcy5wYWdlSWQgPT0gXCJkYXRhYmFzZVwiKXtcbiAgICAgICAgdGhpcy4kc3VibWl0QnV0dG9uLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgfVxuXG4gICAgLy8gRXhjZXB0aW9uIGZvciB0b29scyBhbmQgYWRkb25zXG4gICAgaWYodGhpcy5wYWdlSWQgPT0gXCJ0b29sc1wiIHx8IHRoaXMucGFnZUlkID09IFwiYWRkb25zXCIpe1xuICAgICAgICB0aGlzLiRzdWJtaXRCdXR0b24uc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICB9XG5cbiAgICBpZiAodGhpcy5wYWdlSWQgPT0gXCJpbWFnaWZ5XCIpIHtcbiAgICAgICAgdGhpcy4kc2lkZWJhci5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgICB0aGlzLiR0aXBzLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICAgIHRoaXMuJHN1Ym1pdEJ1dHRvbi5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnBhZ2VJZCA9PSBcInR1dG9yaWFsc1wiKSB7XG4gICAgICAgIHRoaXMuJHN1Ym1pdEJ1dHRvbi5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgIH1cbn07XG4iLCIvKmVzbGludC1lbnYgZXM2Ki9cbiggKCBkb2N1bWVudCwgd2luZG93ICkgPT4ge1xuXHQndXNlIHN0cmljdCc7XG5cblx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ0RPTUNvbnRlbnRMb2FkZWQnLCAoKSA9PiB7XG5cdFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCggJy53cHItcm9ja2V0Y2RuLW9wZW4nICkuZm9yRWFjaCggKCBlbCApID0+IHtcblx0XHRcdGVsLmFkZEV2ZW50TGlzdGVuZXIoICdjbGljaycsICggZSApID0+IHtcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0fSApO1xuXHRcdH0gKTtcblxuXHRcdG1heWJlT3Blbk1vZGFsKCk7XG5cblx0XHRNaWNyb01vZGFsLmluaXQoIHtcblx0XHRcdGRpc2FibGVTY3JvbGw6IHRydWVcblx0XHR9ICk7XG5cdH0gKTtcblxuXHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lciggJ2xvYWQnLCAoKSA9PiB7XG5cdFx0bGV0IG9wZW5DVEEgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCAnI3dwci1yb2NrZXRjZG4tb3Blbi1jdGEnICksXG5cdFx0XHRjbG9zZUNUQSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoICcjd3ByLXJvY2tldGNkbi1jbG9zZS1jdGEnICksXG5cdFx0XHRzbWFsbENUQSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoICcjd3ByLXJvY2tldGNkbi1jdGEtc21hbGwnICksXG5cdFx0XHRiaWdDVEEgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCAnI3dwci1yb2NrZXRjZG4tY3RhJyApO1xuXG5cdFx0aWYgKCBudWxsICE9PSBvcGVuQ1RBICYmIG51bGwgIT09IHNtYWxsQ1RBICYmIG51bGwgIT09IGJpZ0NUQSApIHtcblx0XHRcdG9wZW5DVEEuYWRkRXZlbnRMaXN0ZW5lciggJ2NsaWNrJywgKCBlICkgPT4ge1xuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdFx0c21hbGxDVEEuY2xhc3NMaXN0LmFkZCggJ3dwci1pc0hpZGRlbicgKTtcblx0XHRcdFx0YmlnQ1RBLmNsYXNzTGlzdC5yZW1vdmUoICd3cHItaXNIaWRkZW4nICk7XG5cblx0XHRcdFx0c2VuZEhUVFBSZXF1ZXN0KCBnZXRQb3N0RGF0YSggJ2JpZycgKSApO1xuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdGlmICggbnVsbCAhPT0gY2xvc2VDVEEgJiYgbnVsbCAhPT0gc21hbGxDVEEgJiYgbnVsbCAhPT0gYmlnQ1RBICkge1xuXHRcdFx0Y2xvc2VDVEEuYWRkRXZlbnRMaXN0ZW5lciggJ2NsaWNrJywgKCBlICkgPT4ge1xuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdFx0c21hbGxDVEEuY2xhc3NMaXN0LnJlbW92ZSggJ3dwci1pc0hpZGRlbicgKTtcblx0XHRcdFx0YmlnQ1RBLmNsYXNzTGlzdC5hZGQoICd3cHItaXNIaWRkZW4nICk7XG5cblx0XHRcdFx0c2VuZEhUVFBSZXF1ZXN0KCBnZXRQb3N0RGF0YSggJ3NtYWxsJyApICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2V0UG9zdERhdGEoIHN0YXR1cyApIHtcblx0XHRcdGxldCBwb3N0RGF0YSA9ICcnO1xuXG5cdFx0XHRwb3N0RGF0YSArPSAnYWN0aW9uPXRvZ2dsZV9yb2NrZXRjZG5fY3RhJztcblx0XHRcdHBvc3REYXRhICs9ICcmc3RhdHVzPScgKyBzdGF0dXM7XG5cdFx0XHRwb3N0RGF0YSArPSAnJm5vbmNlPScgKyByb2NrZXRfYWpheF9kYXRhLm5vbmNlO1xuXG5cdFx0XHRyZXR1cm4gcG9zdERhdGE7XG5cdFx0fVxuXHR9ICk7XG5cblx0d2luZG93Lm9ubWVzc2FnZSA9ICggZSApID0+IHtcblx0XHRjb25zdCBpZnJhbWVVUkwgPSByb2NrZXRfYWpheF9kYXRhLm9yaWdpbl91cmw7XG5cblx0XHRpZiAoIGUub3JpZ2luICE9PSBpZnJhbWVVUkwgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0c2V0Q0RORnJhbWVIZWlnaHQoIGUuZGF0YSApO1xuXHRcdGNsb3NlTW9kYWwoIGUuZGF0YSApO1xuXHRcdHRva2VuSGFuZGxlciggZS5kYXRhLCBpZnJhbWVVUkwgKTtcblx0XHRwcm9jZXNzU3RhdHVzKCBlLmRhdGEgKTtcblx0XHRlbmFibGVDRE4oIGUuZGF0YSwgaWZyYW1lVVJMICk7XG5cdFx0ZGlzYWJsZUNETiggZS5kYXRhLCBpZnJhbWVVUkwgKTtcblx0XHR2YWxpZGF0ZVRva2VuQW5kQ05BTUUoIGUuZGF0YSApO1xuXHR9O1xuXG5cdGZ1bmN0aW9uIG1heWJlT3Blbk1vZGFsKCkge1xuXHRcdGxldCBwb3N0RGF0YSA9ICcnO1xuXG5cdFx0cG9zdERhdGEgKz0gJ2FjdGlvbj1yb2NrZXRjZG5fcHJvY2Vzc19zdGF0dXMnO1xuXHRcdHBvc3REYXRhICs9ICcmbm9uY2U9JyArIHJvY2tldF9hamF4X2RhdGEubm9uY2U7XG5cblx0XHRjb25zdCByZXF1ZXN0ID0gc2VuZEhUVFBSZXF1ZXN0KCBwb3N0RGF0YSApO1xuXG5cdFx0cmVxdWVzdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSAoKSA9PiB7XG5cdFx0XHRpZiAoIHJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gWE1MSHR0cFJlcXVlc3QuRE9ORSAmJiAyMDAgPT09IHJlcXVlc3Quc3RhdHVzICkge1xuXHRcdFx0XHRsZXQgcmVzcG9uc2VUeHQgPSBKU09OLnBhcnNlKHJlcXVlc3QucmVzcG9uc2VUZXh0KTtcblxuXHRcdFx0XHRpZiAoIHRydWUgPT09IHJlc3BvbnNlVHh0LnN1Y2Nlc3MgKSB7XG5cdFx0XHRcdFx0TWljcm9Nb2RhbC5zaG93KCAnd3ByLXJvY2tldGNkbi1tb2RhbCcgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cdH1cblxuXHRmdW5jdGlvbiBjbG9zZU1vZGFsKCBkYXRhICkge1xuXHRcdGlmICggISBkYXRhLmhhc093blByb3BlcnR5KCAnY2RuRnJhbWVDbG9zZScgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRNaWNyb01vZGFsLmNsb3NlKCAnd3ByLXJvY2tldGNkbi1tb2RhbCcgKTtcblxuXHRcdGxldCBwYWdlcyA9IFsgJ2lmcmFtZS1wYXltZW50LXN1Y2Nlc3MnLCAnaWZyYW1lLXVuc3Vic2NyaWJlLXN1Y2Nlc3MnIF07XG5cblx0XHRpZiAoICEgZGF0YS5oYXNPd25Qcm9wZXJ0eSggJ2Nkbl9wYWdlX21lc3NhZ2UnICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBwYWdlcy5pbmRleE9mKCBkYXRhLmNkbl9wYWdlX21lc3NhZ2UgKSA9PT0gLTEgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0ZG9jdW1lbnQubG9jYXRpb24ucmVsb2FkKCk7XG5cdH1cblxuXHRmdW5jdGlvbiBwcm9jZXNzU3RhdHVzKCBkYXRhICkge1xuXHRcdGlmICggISBkYXRhLmhhc093blByb3BlcnR5KCAncm9ja2V0Y2RuX3Byb2Nlc3MnICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bGV0IHBvc3REYXRhID0gJyc7XG5cblx0XHRwb3N0RGF0YSArPSAnYWN0aW9uPXJvY2tldGNkbl9wcm9jZXNzX3NldCc7XG5cdFx0cG9zdERhdGEgKz0gJyZzdGF0dXM9JyArIGRhdGEucm9ja2V0Y2RuX3Byb2Nlc3M7XG5cdFx0cG9zdERhdGEgKz0gJyZub25jZT0nICsgcm9ja2V0X2FqYXhfZGF0YS5ub25jZTtcblxuXHRcdHNlbmRIVFRQUmVxdWVzdCggcG9zdERhdGEgKTtcblx0fVxuXG5cdGZ1bmN0aW9uIGVuYWJsZUNETiggZGF0YSwgaWZyYW1lVVJMICkge1xuXHRcdGxldCBpZnJhbWUgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCAnI3JvY2tldGNkbi1pZnJhbWUnICkuY29udGVudFdpbmRvdztcblxuXHRcdGlmICggISBkYXRhLmhhc093blByb3BlcnR5KCAncm9ja2V0Y2RuX3VybCcgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRsZXQgcG9zdERhdGEgPSAnJztcblxuXHRcdHBvc3REYXRhICs9ICdhY3Rpb249cm9ja2V0Y2RuX2VuYWJsZSc7XG5cdFx0cG9zdERhdGEgKz0gJyZjZG5fdXJsPScgKyBkYXRhLnJvY2tldGNkbl91cmw7XG5cdFx0cG9zdERhdGEgKz0gJyZub25jZT0nICsgcm9ja2V0X2FqYXhfZGF0YS5ub25jZTtcblxuXHRcdGNvbnN0IHJlcXVlc3QgPSBzZW5kSFRUUFJlcXVlc3QoIHBvc3REYXRhICk7XG5cblx0XHRyZXF1ZXN0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9ICgpID0+IHtcblx0XHRcdGlmICggcmVxdWVzdC5yZWFkeVN0YXRlID09PSBYTUxIdHRwUmVxdWVzdC5ET05FICYmIDIwMCA9PT0gcmVxdWVzdC5zdGF0dXMgKSB7XG5cdFx0XHRcdGxldCByZXNwb25zZVR4dCA9IEpTT04ucGFyc2UocmVxdWVzdC5yZXNwb25zZVRleHQpO1xuXHRcdFx0XHRpZnJhbWUucG9zdE1lc3NhZ2UoXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0J3N1Y2Nlc3MnOiByZXNwb25zZVR4dC5zdWNjZXNzLFxuXHRcdFx0XHRcdFx0J2RhdGEnOiByZXNwb25zZVR4dC5kYXRhLFxuXHRcdFx0XHRcdFx0J3JvY2tldGNkbic6IHRydWVcblx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdGlmcmFtZVVSTFxuXHRcdFx0XHQpO1xuXHRcdFx0fVxuXHRcdH07XG5cdH1cblxuXHRmdW5jdGlvbiBkaXNhYmxlQ0ROKCBkYXRhLCBpZnJhbWVVUkwgKSB7XG5cdFx0bGV0IGlmcmFtZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoICcjcm9ja2V0Y2RuLWlmcmFtZScgKS5jb250ZW50V2luZG93O1xuXG5cdFx0aWYgKCAhIGRhdGEuaGFzT3duUHJvcGVydHkoICdyb2NrZXRjZG5fZGlzYWJsZScgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRsZXQgcG9zdERhdGEgPSAnJztcblxuXHRcdHBvc3REYXRhICs9ICdhY3Rpb249cm9ja2V0Y2RuX2Rpc2FibGUnO1xuXHRcdHBvc3REYXRhICs9ICcmbm9uY2U9JyArIHJvY2tldF9hamF4X2RhdGEubm9uY2U7XG5cblx0XHRjb25zdCByZXF1ZXN0ID0gc2VuZEhUVFBSZXF1ZXN0KCBwb3N0RGF0YSApO1xuXG5cdFx0cmVxdWVzdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSAoKSA9PiB7XG5cdFx0XHRpZiAoIHJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gWE1MSHR0cFJlcXVlc3QuRE9ORSAmJiAyMDAgPT09IHJlcXVlc3Quc3RhdHVzICkge1xuXHRcdFx0XHRsZXQgcmVzcG9uc2VUeHQgPSBKU09OLnBhcnNlKHJlcXVlc3QucmVzcG9uc2VUZXh0KTtcblx0XHRcdFx0aWZyYW1lLnBvc3RNZXNzYWdlKFxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdCdzdWNjZXNzJzogcmVzcG9uc2VUeHQuc3VjY2Vzcyxcblx0XHRcdFx0XHRcdCdkYXRhJzogcmVzcG9uc2VUeHQuZGF0YSxcblx0XHRcdFx0XHRcdCdyb2NrZXRjZG4nOiB0cnVlXG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRpZnJhbWVVUkxcblx0XHRcdFx0KTtcblx0XHRcdH1cblx0XHR9O1xuXHR9XG5cblx0ZnVuY3Rpb24gc2VuZEhUVFBSZXF1ZXN0KCBwb3N0RGF0YSApIHtcblx0XHRjb25zdCBodHRwUmVxdWVzdCA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpO1xuXG5cdFx0aHR0cFJlcXVlc3Qub3BlbiggJ1BPU1QnLCBhamF4dXJsICk7XG5cdFx0aHR0cFJlcXVlc3Quc2V0UmVxdWVzdEhlYWRlciggJ0NvbnRlbnQtVHlwZScsICdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnICk7XG5cdFx0aHR0cFJlcXVlc3Quc2VuZCggcG9zdERhdGEgKTtcblxuXHRcdHJldHVybiBodHRwUmVxdWVzdDtcblx0fVxuXG5cdGZ1bmN0aW9uIHNldENETkZyYW1lSGVpZ2h0KCBkYXRhICkge1xuXHRcdGlmICggISBkYXRhLmhhc093blByb3BlcnR5KCAnY2RuRnJhbWVIZWlnaHQnICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoICdyb2NrZXRjZG4taWZyYW1lJyApLnN0eWxlLmhlaWdodCA9IGAkeyBkYXRhLmNkbkZyYW1lSGVpZ2h0IH1weGA7XG5cdH1cblxuXHRmdW5jdGlvbiB0b2tlbkhhbmRsZXIoIGRhdGEsIGlmcmFtZVVSTCApIHtcblx0XHRsZXQgaWZyYW1lID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvciggJyNyb2NrZXRjZG4taWZyYW1lJyApLmNvbnRlbnRXaW5kb3c7XG5cblx0XHRpZiAoICEgZGF0YS5oYXNPd25Qcm9wZXJ0eSggJ3JvY2tldGNkbl90b2tlbicgKSApIHtcblx0XHRcdGxldCBkYXRhID0ge3Byb2Nlc3M6XCJzdWJzY3JpYmVcIiwgbWVzc2FnZTpcInRva2VuX25vdF9yZWNlaXZlZFwifTtcblx0XHRcdGlmcmFtZS5wb3N0TWVzc2FnZShcblx0XHRcdFx0e1xuXHRcdFx0XHRcdCdzdWNjZXNzJzogZmFsc2UsXG5cdFx0XHRcdFx0J2RhdGEnOiBkYXRhLFxuXHRcdFx0XHRcdCdyb2NrZXRjZG4nOiB0cnVlXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGlmcmFtZVVSTFxuXHRcdFx0KTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRsZXQgcG9zdERhdGEgPSAnJztcblxuXHRcdHBvc3REYXRhICs9ICdhY3Rpb249c2F2ZV9yb2NrZXRjZG5fdG9rZW4nO1xuXHRcdHBvc3REYXRhICs9ICcmdmFsdWU9JyArIGRhdGEucm9ja2V0Y2RuX3Rva2VuO1xuXHRcdHBvc3REYXRhICs9ICcmbm9uY2U9JyArIHJvY2tldF9hamF4X2RhdGEubm9uY2U7XG5cblx0XHRjb25zdCByZXF1ZXN0ID0gc2VuZEhUVFBSZXF1ZXN0KCBwb3N0RGF0YSApO1xuXG5cdFx0cmVxdWVzdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSAoKSA9PiB7XG5cdFx0XHRpZiAoIHJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gWE1MSHR0cFJlcXVlc3QuRE9ORSAmJiAyMDAgPT09IHJlcXVlc3Quc3RhdHVzICkge1xuXHRcdFx0XHRsZXQgcmVzcG9uc2VUeHQgPSBKU09OLnBhcnNlKHJlcXVlc3QucmVzcG9uc2VUZXh0KTtcblx0XHRcdFx0aWZyYW1lLnBvc3RNZXNzYWdlKFxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdCdzdWNjZXNzJzogcmVzcG9uc2VUeHQuc3VjY2Vzcyxcblx0XHRcdFx0XHRcdCdkYXRhJzogcmVzcG9uc2VUeHQuZGF0YSxcblx0XHRcdFx0XHRcdCdyb2NrZXRjZG4nOiB0cnVlXG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRpZnJhbWVVUkxcblx0XHRcdFx0KTtcblx0XHRcdH1cblx0XHR9O1xuXHR9XG5cblx0ZnVuY3Rpb24gdmFsaWRhdGVUb2tlbkFuZENOQU1FKCBkYXRhICkge1xuXHRcdGlmICggISBkYXRhLmhhc093blByb3BlcnR5KCAncm9ja2V0Y2RuX3ZhbGlkYXRlX3Rva2VuJyApIHx8ICEgZGF0YS5oYXNPd25Qcm9wZXJ0eSggJ3JvY2tldGNkbl92YWxpZGF0ZV9jbmFtZScgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRsZXQgcG9zdERhdGEgPSAnJztcblxuXHRcdHBvc3REYXRhICs9ICdhY3Rpb249cm9ja2V0Y2RuX3ZhbGlkYXRlX3Rva2VuX2NuYW1lJztcblx0XHRwb3N0RGF0YSArPSAnJmNkbl91cmw9JyArIGRhdGEucm9ja2V0Y2RuX3ZhbGlkYXRlX2NuYW1lO1xuXHRcdHBvc3REYXRhICs9ICcmY2RuX3Rva2VuPScgKyBkYXRhLnJvY2tldGNkbl92YWxpZGF0ZV90b2tlbjtcblx0XHRwb3N0RGF0YSArPSAnJm5vbmNlPScgKyByb2NrZXRfYWpheF9kYXRhLm5vbmNlO1xuXG5cdFx0Y29uc3QgcmVxdWVzdCA9IHNlbmRIVFRQUmVxdWVzdCggcG9zdERhdGEgKTtcblx0fVxufSApKCBkb2N1bWVudCwgd2luZG93ICk7XG4iLCIvKiFcclxuICogVkVSU0lPTjogMS4xMi4xXHJcbiAqIERBVEU6IDIwMTQtMDYtMjZcclxuICogVVBEQVRFUyBBTkQgRE9DUyBBVDogaHR0cDovL3d3dy5ncmVlbnNvY2suY29tXHJcbiAqXHJcbiAqIEBsaWNlbnNlIENvcHlyaWdodCAoYykgMjAwOC0yMDE0LCBHcmVlblNvY2suIEFsbCByaWdodHMgcmVzZXJ2ZWQuXHJcbiAqIFRoaXMgd29yayBpcyBzdWJqZWN0IHRvIHRoZSB0ZXJtcyBhdCBodHRwOi8vd3d3LmdyZWVuc29jay5jb20vdGVybXNfb2ZfdXNlLmh0bWwgb3IgZm9yXHJcbiAqIENsdWIgR3JlZW5Tb2NrIG1lbWJlcnMsIHRoZSBzb2Z0d2FyZSBhZ3JlZW1lbnQgdGhhdCB3YXMgaXNzdWVkIHdpdGggeW91ciBtZW1iZXJzaGlwLlxyXG4gKiBcclxuICogQGF1dGhvcjogSmFjayBEb3lsZSwgamFja0BncmVlbnNvY2suY29tXHJcbiAqL1xyXG4od2luZG93Ll9nc1F1ZXVlfHwod2luZG93Ll9nc1F1ZXVlPVtdKSkucHVzaChmdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3dpbmRvdy5fZ3NEZWZpbmUoXCJUaW1lbGluZUxpdGVcIixbXCJjb3JlLkFuaW1hdGlvblwiLFwiY29yZS5TaW1wbGVUaW1lbGluZVwiLFwiVHdlZW5MaXRlXCJdLGZ1bmN0aW9uKHQsZSxpKXt2YXIgcz1mdW5jdGlvbih0KXtlLmNhbGwodGhpcyx0KSx0aGlzLl9sYWJlbHM9e30sdGhpcy5hdXRvUmVtb3ZlQ2hpbGRyZW49dGhpcy52YXJzLmF1dG9SZW1vdmVDaGlsZHJlbj09PSEwLHRoaXMuc21vb3RoQ2hpbGRUaW1pbmc9dGhpcy52YXJzLnNtb290aENoaWxkVGltaW5nPT09ITAsdGhpcy5fc29ydENoaWxkcmVuPSEwLHRoaXMuX29uVXBkYXRlPXRoaXMudmFycy5vblVwZGF0ZTt2YXIgaSxzLHI9dGhpcy52YXJzO2ZvcihzIGluIHIpaT1yW3NdLGEoaSkmJi0xIT09aS5qb2luKFwiXCIpLmluZGV4T2YoXCJ7c2VsZn1cIikmJihyW3NdPXRoaXMuX3N3YXBTZWxmSW5QYXJhbXMoaSkpO2Eoci50d2VlbnMpJiZ0aGlzLmFkZChyLnR3ZWVucywwLHIuYWxpZ24sci5zdGFnZ2VyKX0scj0xZS0xMCxuPWkuX2ludGVybmFscy5pc1NlbGVjdG9yLGE9aS5faW50ZXJuYWxzLmlzQXJyYXksbz1bXSxoPXdpbmRvdy5fZ3NEZWZpbmUuZ2xvYmFscyxsPWZ1bmN0aW9uKHQpe3ZhciBlLGk9e307Zm9yKGUgaW4gdClpW2VdPXRbZV07cmV0dXJuIGl9LF89ZnVuY3Rpb24odCxlLGkscyl7dC5fdGltZWxpbmUucGF1c2UodC5fc3RhcnRUaW1lKSxlJiZlLmFwcGx5KHN8fHQuX3RpbWVsaW5lLGl8fG8pfSx1PW8uc2xpY2UsZj1zLnByb3RvdHlwZT1uZXcgZTtyZXR1cm4gcy52ZXJzaW9uPVwiMS4xMi4xXCIsZi5jb25zdHJ1Y3Rvcj1zLGYua2lsbCgpLl9nYz0hMSxmLnRvPWZ1bmN0aW9uKHQsZSxzLHIpe3ZhciBuPXMucmVwZWF0JiZoLlR3ZWVuTWF4fHxpO3JldHVybiBlP3RoaXMuYWRkKG5ldyBuKHQsZSxzKSxyKTp0aGlzLnNldCh0LHMscil9LGYuZnJvbT1mdW5jdGlvbih0LGUscyxyKXtyZXR1cm4gdGhpcy5hZGQoKHMucmVwZWF0JiZoLlR3ZWVuTWF4fHxpKS5mcm9tKHQsZSxzKSxyKX0sZi5mcm9tVG89ZnVuY3Rpb24odCxlLHMscixuKXt2YXIgYT1yLnJlcGVhdCYmaC5Ud2Vlbk1heHx8aTtyZXR1cm4gZT90aGlzLmFkZChhLmZyb21Ubyh0LGUscyxyKSxuKTp0aGlzLnNldCh0LHIsbil9LGYuc3RhZ2dlclRvPWZ1bmN0aW9uKHQsZSxyLGEsbyxoLF8sZil7dmFyIHAsYz1uZXcgcyh7b25Db21wbGV0ZTpoLG9uQ29tcGxldGVQYXJhbXM6XyxvbkNvbXBsZXRlU2NvcGU6ZixzbW9vdGhDaGlsZFRpbWluZzp0aGlzLnNtb290aENoaWxkVGltaW5nfSk7Zm9yKFwic3RyaW5nXCI9PXR5cGVvZiB0JiYodD1pLnNlbGVjdG9yKHQpfHx0KSxuKHQpJiYodD11LmNhbGwodCwwKSksYT1hfHwwLHA9MDt0Lmxlbmd0aD5wO3ArKylyLnN0YXJ0QXQmJihyLnN0YXJ0QXQ9bChyLnN0YXJ0QXQpKSxjLnRvKHRbcF0sZSxsKHIpLHAqYSk7cmV0dXJuIHRoaXMuYWRkKGMsbyl9LGYuc3RhZ2dlckZyb209ZnVuY3Rpb24odCxlLGkscyxyLG4sYSxvKXtyZXR1cm4gaS5pbW1lZGlhdGVSZW5kZXI9MCE9aS5pbW1lZGlhdGVSZW5kZXIsaS5ydW5CYWNrd2FyZHM9ITAsdGhpcy5zdGFnZ2VyVG8odCxlLGkscyxyLG4sYSxvKX0sZi5zdGFnZ2VyRnJvbVRvPWZ1bmN0aW9uKHQsZSxpLHMscixuLGEsbyxoKXtyZXR1cm4gcy5zdGFydEF0PWkscy5pbW1lZGlhdGVSZW5kZXI9MCE9cy5pbW1lZGlhdGVSZW5kZXImJjAhPWkuaW1tZWRpYXRlUmVuZGVyLHRoaXMuc3RhZ2dlclRvKHQsZSxzLHIsbixhLG8saCl9LGYuY2FsbD1mdW5jdGlvbih0LGUscyxyKXtyZXR1cm4gdGhpcy5hZGQoaS5kZWxheWVkQ2FsbCgwLHQsZSxzKSxyKX0sZi5zZXQ9ZnVuY3Rpb24odCxlLHMpe3JldHVybiBzPXRoaXMuX3BhcnNlVGltZU9yTGFiZWwocywwLCEwKSxudWxsPT1lLmltbWVkaWF0ZVJlbmRlciYmKGUuaW1tZWRpYXRlUmVuZGVyPXM9PT10aGlzLl90aW1lJiYhdGhpcy5fcGF1c2VkKSx0aGlzLmFkZChuZXcgaSh0LDAsZSkscyl9LHMuZXhwb3J0Um9vdD1mdW5jdGlvbih0LGUpe3Q9dHx8e30sbnVsbD09dC5zbW9vdGhDaGlsZFRpbWluZyYmKHQuc21vb3RoQ2hpbGRUaW1pbmc9ITApO3ZhciByLG4sYT1uZXcgcyh0KSxvPWEuX3RpbWVsaW5lO2ZvcihudWxsPT1lJiYoZT0hMCksby5fcmVtb3ZlKGEsITApLGEuX3N0YXJ0VGltZT0wLGEuX3Jhd1ByZXZUaW1lPWEuX3RpbWU9YS5fdG90YWxUaW1lPW8uX3RpbWUscj1vLl9maXJzdDtyOyluPXIuX25leHQsZSYmciBpbnN0YW5jZW9mIGkmJnIudGFyZ2V0PT09ci52YXJzLm9uQ29tcGxldGV8fGEuYWRkKHIsci5fc3RhcnRUaW1lLXIuX2RlbGF5KSxyPW47cmV0dXJuIG8uYWRkKGEsMCksYX0sZi5hZGQ9ZnVuY3Rpb24ocixuLG8saCl7dmFyIGwsXyx1LGYscCxjO2lmKFwibnVtYmVyXCIhPXR5cGVvZiBuJiYobj10aGlzLl9wYXJzZVRpbWVPckxhYmVsKG4sMCwhMCxyKSksIShyIGluc3RhbmNlb2YgdCkpe2lmKHIgaW5zdGFuY2VvZiBBcnJheXx8ciYmci5wdXNoJiZhKHIpKXtmb3Iobz1vfHxcIm5vcm1hbFwiLGg9aHx8MCxsPW4sXz1yLmxlbmd0aCx1PTA7Xz51O3UrKylhKGY9clt1XSkmJihmPW5ldyBzKHt0d2VlbnM6Zn0pKSx0aGlzLmFkZChmLGwpLFwic3RyaW5nXCIhPXR5cGVvZiBmJiZcImZ1bmN0aW9uXCIhPXR5cGVvZiBmJiYoXCJzZXF1ZW5jZVwiPT09bz9sPWYuX3N0YXJ0VGltZStmLnRvdGFsRHVyYXRpb24oKS9mLl90aW1lU2NhbGU6XCJzdGFydFwiPT09byYmKGYuX3N0YXJ0VGltZS09Zi5kZWxheSgpKSksbCs9aDtyZXR1cm4gdGhpcy5fdW5jYWNoZSghMCl9aWYoXCJzdHJpbmdcIj09dHlwZW9mIHIpcmV0dXJuIHRoaXMuYWRkTGFiZWwocixuKTtpZihcImZ1bmN0aW9uXCIhPXR5cGVvZiByKXRocm93XCJDYW5ub3QgYWRkIFwiK3IrXCIgaW50byB0aGUgdGltZWxpbmU7IGl0IGlzIG5vdCBhIHR3ZWVuLCB0aW1lbGluZSwgZnVuY3Rpb24sIG9yIHN0cmluZy5cIjtyPWkuZGVsYXllZENhbGwoMCxyKX1pZihlLnByb3RvdHlwZS5hZGQuY2FsbCh0aGlzLHIsbiksKHRoaXMuX2djfHx0aGlzLl90aW1lPT09dGhpcy5fZHVyYXRpb24pJiYhdGhpcy5fcGF1c2VkJiZ0aGlzLl9kdXJhdGlvbjx0aGlzLmR1cmF0aW9uKCkpZm9yKHA9dGhpcyxjPXAucmF3VGltZSgpPnIuX3N0YXJ0VGltZTtwLl90aW1lbGluZTspYyYmcC5fdGltZWxpbmUuc21vb3RoQ2hpbGRUaW1pbmc/cC50b3RhbFRpbWUocC5fdG90YWxUaW1lLCEwKTpwLl9nYyYmcC5fZW5hYmxlZCghMCwhMSkscD1wLl90aW1lbGluZTtyZXR1cm4gdGhpc30sZi5yZW1vdmU9ZnVuY3Rpb24oZSl7aWYoZSBpbnN0YW5jZW9mIHQpcmV0dXJuIHRoaXMuX3JlbW92ZShlLCExKTtpZihlIGluc3RhbmNlb2YgQXJyYXl8fGUmJmUucHVzaCYmYShlKSl7Zm9yKHZhciBpPWUubGVuZ3RoOy0taT4tMTspdGhpcy5yZW1vdmUoZVtpXSk7cmV0dXJuIHRoaXN9cmV0dXJuXCJzdHJpbmdcIj09dHlwZW9mIGU/dGhpcy5yZW1vdmVMYWJlbChlKTp0aGlzLmtpbGwobnVsbCxlKX0sZi5fcmVtb3ZlPWZ1bmN0aW9uKHQsaSl7ZS5wcm90b3R5cGUuX3JlbW92ZS5jYWxsKHRoaXMsdCxpKTt2YXIgcz10aGlzLl9sYXN0O3JldHVybiBzP3RoaXMuX3RpbWU+cy5fc3RhcnRUaW1lK3MuX3RvdGFsRHVyYXRpb24vcy5fdGltZVNjYWxlJiYodGhpcy5fdGltZT10aGlzLmR1cmF0aW9uKCksdGhpcy5fdG90YWxUaW1lPXRoaXMuX3RvdGFsRHVyYXRpb24pOnRoaXMuX3RpbWU9dGhpcy5fdG90YWxUaW1lPXRoaXMuX2R1cmF0aW9uPXRoaXMuX3RvdGFsRHVyYXRpb249MCx0aGlzfSxmLmFwcGVuZD1mdW5jdGlvbih0LGUpe3JldHVybiB0aGlzLmFkZCh0LHRoaXMuX3BhcnNlVGltZU9yTGFiZWwobnVsbCxlLCEwLHQpKX0sZi5pbnNlcnQ9Zi5pbnNlcnRNdWx0aXBsZT1mdW5jdGlvbih0LGUsaSxzKXtyZXR1cm4gdGhpcy5hZGQodCxlfHwwLGkscyl9LGYuYXBwZW5kTXVsdGlwbGU9ZnVuY3Rpb24odCxlLGkscyl7cmV0dXJuIHRoaXMuYWRkKHQsdGhpcy5fcGFyc2VUaW1lT3JMYWJlbChudWxsLGUsITAsdCksaSxzKX0sZi5hZGRMYWJlbD1mdW5jdGlvbih0LGUpe3JldHVybiB0aGlzLl9sYWJlbHNbdF09dGhpcy5fcGFyc2VUaW1lT3JMYWJlbChlKSx0aGlzfSxmLmFkZFBhdXNlPWZ1bmN0aW9uKHQsZSxpLHMpe3JldHVybiB0aGlzLmNhbGwoXyxbXCJ7c2VsZn1cIixlLGksc10sdGhpcyx0KX0sZi5yZW1vdmVMYWJlbD1mdW5jdGlvbih0KXtyZXR1cm4gZGVsZXRlIHRoaXMuX2xhYmVsc1t0XSx0aGlzfSxmLmdldExhYmVsVGltZT1mdW5jdGlvbih0KXtyZXR1cm4gbnVsbCE9dGhpcy5fbGFiZWxzW3RdP3RoaXMuX2xhYmVsc1t0XTotMX0sZi5fcGFyc2VUaW1lT3JMYWJlbD1mdW5jdGlvbihlLGkscyxyKXt2YXIgbjtpZihyIGluc3RhbmNlb2YgdCYmci50aW1lbGluZT09PXRoaXMpdGhpcy5yZW1vdmUocik7ZWxzZSBpZihyJiYociBpbnN0YW5jZW9mIEFycmF5fHxyLnB1c2gmJmEocikpKWZvcihuPXIubGVuZ3RoOy0tbj4tMTspcltuXWluc3RhbmNlb2YgdCYmcltuXS50aW1lbGluZT09PXRoaXMmJnRoaXMucmVtb3ZlKHJbbl0pO2lmKFwic3RyaW5nXCI9PXR5cGVvZiBpKXJldHVybiB0aGlzLl9wYXJzZVRpbWVPckxhYmVsKGkscyYmXCJudW1iZXJcIj09dHlwZW9mIGUmJm51bGw9PXRoaXMuX2xhYmVsc1tpXT9lLXRoaXMuZHVyYXRpb24oKTowLHMpO2lmKGk9aXx8MCxcInN0cmluZ1wiIT10eXBlb2YgZXx8IWlzTmFOKGUpJiZudWxsPT10aGlzLl9sYWJlbHNbZV0pbnVsbD09ZSYmKGU9dGhpcy5kdXJhdGlvbigpKTtlbHNle2lmKG49ZS5pbmRleE9mKFwiPVwiKSwtMT09PW4pcmV0dXJuIG51bGw9PXRoaXMuX2xhYmVsc1tlXT9zP3RoaXMuX2xhYmVsc1tlXT10aGlzLmR1cmF0aW9uKCkraTppOnRoaXMuX2xhYmVsc1tlXStpO2k9cGFyc2VJbnQoZS5jaGFyQXQobi0xKStcIjFcIiwxMCkqTnVtYmVyKGUuc3Vic3RyKG4rMSkpLGU9bj4xP3RoaXMuX3BhcnNlVGltZU9yTGFiZWwoZS5zdWJzdHIoMCxuLTEpLDAscyk6dGhpcy5kdXJhdGlvbigpfXJldHVybiBOdW1iZXIoZSkraX0sZi5zZWVrPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHRoaXMudG90YWxUaW1lKFwibnVtYmVyXCI9PXR5cGVvZiB0P3Q6dGhpcy5fcGFyc2VUaW1lT3JMYWJlbCh0KSxlIT09ITEpfSxmLnN0b3A9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5wYXVzZWQoITApfSxmLmdvdG9BbmRQbGF5PWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHRoaXMucGxheSh0LGUpfSxmLmdvdG9BbmRTdG9wPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHRoaXMucGF1c2UodCxlKX0sZi5yZW5kZXI9ZnVuY3Rpb24odCxlLGkpe3RoaXMuX2djJiZ0aGlzLl9lbmFibGVkKCEwLCExKTt2YXIgcyxuLGEsaCxsLF89dGhpcy5fZGlydHk/dGhpcy50b3RhbER1cmF0aW9uKCk6dGhpcy5fdG90YWxEdXJhdGlvbix1PXRoaXMuX3RpbWUsZj10aGlzLl9zdGFydFRpbWUscD10aGlzLl90aW1lU2NhbGUsYz10aGlzLl9wYXVzZWQ7aWYodD49Xz8odGhpcy5fdG90YWxUaW1lPXRoaXMuX3RpbWU9Xyx0aGlzLl9yZXZlcnNlZHx8dGhpcy5faGFzUGF1c2VkQ2hpbGQoKXx8KG49ITAsaD1cIm9uQ29tcGxldGVcIiwwPT09dGhpcy5fZHVyYXRpb24mJigwPT09dHx8MD50aGlzLl9yYXdQcmV2VGltZXx8dGhpcy5fcmF3UHJldlRpbWU9PT1yKSYmdGhpcy5fcmF3UHJldlRpbWUhPT10JiZ0aGlzLl9maXJzdCYmKGw9ITAsdGhpcy5fcmF3UHJldlRpbWU+ciYmKGg9XCJvblJldmVyc2VDb21wbGV0ZVwiKSkpLHRoaXMuX3Jhd1ByZXZUaW1lPXRoaXMuX2R1cmF0aW9ufHwhZXx8dHx8dGhpcy5fcmF3UHJldlRpbWU9PT10P3Q6cix0PV8rMWUtNCk6MWUtNz50Pyh0aGlzLl90b3RhbFRpbWU9dGhpcy5fdGltZT0wLCgwIT09dXx8MD09PXRoaXMuX2R1cmF0aW9uJiZ0aGlzLl9yYXdQcmV2VGltZSE9PXImJih0aGlzLl9yYXdQcmV2VGltZT4wfHwwPnQmJnRoaXMuX3Jhd1ByZXZUaW1lPj0wKSkmJihoPVwib25SZXZlcnNlQ29tcGxldGVcIixuPXRoaXMuX3JldmVyc2VkKSwwPnQ/KHRoaXMuX2FjdGl2ZT0hMSwwPT09dGhpcy5fZHVyYXRpb24mJnRoaXMuX3Jhd1ByZXZUaW1lPj0wJiZ0aGlzLl9maXJzdCYmKGw9ITApLHRoaXMuX3Jhd1ByZXZUaW1lPXQpOih0aGlzLl9yYXdQcmV2VGltZT10aGlzLl9kdXJhdGlvbnx8IWV8fHR8fHRoaXMuX3Jhd1ByZXZUaW1lPT09dD90OnIsdD0wLHRoaXMuX2luaXR0ZWR8fChsPSEwKSkpOnRoaXMuX3RvdGFsVGltZT10aGlzLl90aW1lPXRoaXMuX3Jhd1ByZXZUaW1lPXQsdGhpcy5fdGltZSE9PXUmJnRoaXMuX2ZpcnN0fHxpfHxsKXtpZih0aGlzLl9pbml0dGVkfHwodGhpcy5faW5pdHRlZD0hMCksdGhpcy5fYWN0aXZlfHwhdGhpcy5fcGF1c2VkJiZ0aGlzLl90aW1lIT09dSYmdD4wJiYodGhpcy5fYWN0aXZlPSEwKSwwPT09dSYmdGhpcy52YXJzLm9uU3RhcnQmJjAhPT10aGlzLl90aW1lJiYoZXx8dGhpcy52YXJzLm9uU3RhcnQuYXBwbHkodGhpcy52YXJzLm9uU3RhcnRTY29wZXx8dGhpcyx0aGlzLnZhcnMub25TdGFydFBhcmFtc3x8bykpLHRoaXMuX3RpbWU+PXUpZm9yKHM9dGhpcy5fZmlyc3Q7cyYmKGE9cy5fbmV4dCwhdGhpcy5fcGF1c2VkfHxjKTspKHMuX2FjdGl2ZXx8cy5fc3RhcnRUaW1lPD10aGlzLl90aW1lJiYhcy5fcGF1c2VkJiYhcy5fZ2MpJiYocy5fcmV2ZXJzZWQ/cy5yZW5kZXIoKHMuX2RpcnR5P3MudG90YWxEdXJhdGlvbigpOnMuX3RvdGFsRHVyYXRpb24pLSh0LXMuX3N0YXJ0VGltZSkqcy5fdGltZVNjYWxlLGUsaSk6cy5yZW5kZXIoKHQtcy5fc3RhcnRUaW1lKSpzLl90aW1lU2NhbGUsZSxpKSkscz1hO2Vsc2UgZm9yKHM9dGhpcy5fbGFzdDtzJiYoYT1zLl9wcmV2LCF0aGlzLl9wYXVzZWR8fGMpOykocy5fYWN0aXZlfHx1Pj1zLl9zdGFydFRpbWUmJiFzLl9wYXVzZWQmJiFzLl9nYykmJihzLl9yZXZlcnNlZD9zLnJlbmRlcigocy5fZGlydHk/cy50b3RhbER1cmF0aW9uKCk6cy5fdG90YWxEdXJhdGlvbiktKHQtcy5fc3RhcnRUaW1lKSpzLl90aW1lU2NhbGUsZSxpKTpzLnJlbmRlcigodC1zLl9zdGFydFRpbWUpKnMuX3RpbWVTY2FsZSxlLGkpKSxzPWE7dGhpcy5fb25VcGRhdGUmJihlfHx0aGlzLl9vblVwZGF0ZS5hcHBseSh0aGlzLnZhcnMub25VcGRhdGVTY29wZXx8dGhpcyx0aGlzLnZhcnMub25VcGRhdGVQYXJhbXN8fG8pKSxoJiYodGhpcy5fZ2N8fChmPT09dGhpcy5fc3RhcnRUaW1lfHxwIT09dGhpcy5fdGltZVNjYWxlKSYmKDA9PT10aGlzLl90aW1lfHxfPj10aGlzLnRvdGFsRHVyYXRpb24oKSkmJihuJiYodGhpcy5fdGltZWxpbmUuYXV0b1JlbW92ZUNoaWxkcmVuJiZ0aGlzLl9lbmFibGVkKCExLCExKSx0aGlzLl9hY3RpdmU9ITEpLCFlJiZ0aGlzLnZhcnNbaF0mJnRoaXMudmFyc1toXS5hcHBseSh0aGlzLnZhcnNbaCtcIlNjb3BlXCJdfHx0aGlzLHRoaXMudmFyc1toK1wiUGFyYW1zXCJdfHxvKSkpfX0sZi5faGFzUGF1c2VkQ2hpbGQ9ZnVuY3Rpb24oKXtmb3IodmFyIHQ9dGhpcy5fZmlyc3Q7dDspe2lmKHQuX3BhdXNlZHx8dCBpbnN0YW5jZW9mIHMmJnQuX2hhc1BhdXNlZENoaWxkKCkpcmV0dXJuITA7dD10Ll9uZXh0fXJldHVybiExfSxmLmdldENoaWxkcmVuPWZ1bmN0aW9uKHQsZSxzLHIpe3I9cnx8LTk5OTk5OTk5OTk7Zm9yKHZhciBuPVtdLGE9dGhpcy5fZmlyc3Qsbz0wO2E7KXI+YS5fc3RhcnRUaW1lfHwoYSBpbnN0YW5jZW9mIGk/ZSE9PSExJiYobltvKytdPWEpOihzIT09ITEmJihuW28rK109YSksdCE9PSExJiYobj1uLmNvbmNhdChhLmdldENoaWxkcmVuKCEwLGUscykpLG89bi5sZW5ndGgpKSksYT1hLl9uZXh0O3JldHVybiBufSxmLmdldFR3ZWVuc09mPWZ1bmN0aW9uKHQsZSl7dmFyIHMscixuPXRoaXMuX2djLGE9W10sbz0wO2ZvcihuJiZ0aGlzLl9lbmFibGVkKCEwLCEwKSxzPWkuZ2V0VHdlZW5zT2YodCkscj1zLmxlbmd0aDstLXI+LTE7KShzW3JdLnRpbWVsaW5lPT09dGhpc3x8ZSYmdGhpcy5fY29udGFpbnMoc1tyXSkpJiYoYVtvKytdPXNbcl0pO3JldHVybiBuJiZ0aGlzLl9lbmFibGVkKCExLCEwKSxhfSxmLl9jb250YWlucz1mdW5jdGlvbih0KXtmb3IodmFyIGU9dC50aW1lbGluZTtlOyl7aWYoZT09PXRoaXMpcmV0dXJuITA7ZT1lLnRpbWVsaW5lfXJldHVybiExfSxmLnNoaWZ0Q2hpbGRyZW49ZnVuY3Rpb24odCxlLGkpe2k9aXx8MDtmb3IodmFyIHMscj10aGlzLl9maXJzdCxuPXRoaXMuX2xhYmVscztyOylyLl9zdGFydFRpbWU+PWkmJihyLl9zdGFydFRpbWUrPXQpLHI9ci5fbmV4dDtpZihlKWZvcihzIGluIG4pbltzXT49aSYmKG5bc10rPXQpO3JldHVybiB0aGlzLl91bmNhY2hlKCEwKX0sZi5fa2lsbD1mdW5jdGlvbih0LGUpe2lmKCF0JiYhZSlyZXR1cm4gdGhpcy5fZW5hYmxlZCghMSwhMSk7Zm9yKHZhciBpPWU/dGhpcy5nZXRUd2VlbnNPZihlKTp0aGlzLmdldENoaWxkcmVuKCEwLCEwLCExKSxzPWkubGVuZ3RoLHI9ITE7LS1zPi0xOylpW3NdLl9raWxsKHQsZSkmJihyPSEwKTtyZXR1cm4gcn0sZi5jbGVhcj1mdW5jdGlvbih0KXt2YXIgZT10aGlzLmdldENoaWxkcmVuKCExLCEwLCEwKSxpPWUubGVuZ3RoO2Zvcih0aGlzLl90aW1lPXRoaXMuX3RvdGFsVGltZT0wOy0taT4tMTspZVtpXS5fZW5hYmxlZCghMSwhMSk7cmV0dXJuIHQhPT0hMSYmKHRoaXMuX2xhYmVscz17fSksdGhpcy5fdW5jYWNoZSghMCl9LGYuaW52YWxpZGF0ZT1mdW5jdGlvbigpe2Zvcih2YXIgdD10aGlzLl9maXJzdDt0Oyl0LmludmFsaWRhdGUoKSx0PXQuX25leHQ7cmV0dXJuIHRoaXN9LGYuX2VuYWJsZWQ9ZnVuY3Rpb24odCxpKXtpZih0PT09dGhpcy5fZ2MpZm9yKHZhciBzPXRoaXMuX2ZpcnN0O3M7KXMuX2VuYWJsZWQodCwhMCkscz1zLl9uZXh0O3JldHVybiBlLnByb3RvdHlwZS5fZW5hYmxlZC5jYWxsKHRoaXMsdCxpKX0sZi5kdXJhdGlvbj1mdW5jdGlvbih0KXtyZXR1cm4gYXJndW1lbnRzLmxlbmd0aD8oMCE9PXRoaXMuZHVyYXRpb24oKSYmMCE9PXQmJnRoaXMudGltZVNjYWxlKHRoaXMuX2R1cmF0aW9uL3QpLHRoaXMpOih0aGlzLl9kaXJ0eSYmdGhpcy50b3RhbER1cmF0aW9uKCksdGhpcy5fZHVyYXRpb24pfSxmLnRvdGFsRHVyYXRpb249ZnVuY3Rpb24odCl7aWYoIWFyZ3VtZW50cy5sZW5ndGgpe2lmKHRoaXMuX2RpcnR5KXtmb3IodmFyIGUsaSxzPTAscj10aGlzLl9sYXN0LG49OTk5OTk5OTk5OTk5O3I7KWU9ci5fcHJldixyLl9kaXJ0eSYmci50b3RhbER1cmF0aW9uKCksci5fc3RhcnRUaW1lPm4mJnRoaXMuX3NvcnRDaGlsZHJlbiYmIXIuX3BhdXNlZD90aGlzLmFkZChyLHIuX3N0YXJ0VGltZS1yLl9kZWxheSk6bj1yLl9zdGFydFRpbWUsMD5yLl9zdGFydFRpbWUmJiFyLl9wYXVzZWQmJihzLT1yLl9zdGFydFRpbWUsdGhpcy5fdGltZWxpbmUuc21vb3RoQ2hpbGRUaW1pbmcmJih0aGlzLl9zdGFydFRpbWUrPXIuX3N0YXJ0VGltZS90aGlzLl90aW1lU2NhbGUpLHRoaXMuc2hpZnRDaGlsZHJlbigtci5fc3RhcnRUaW1lLCExLC05OTk5OTk5OTk5KSxuPTApLGk9ci5fc3RhcnRUaW1lK3IuX3RvdGFsRHVyYXRpb24vci5fdGltZVNjYWxlLGk+cyYmKHM9aSkscj1lO3RoaXMuX2R1cmF0aW9uPXRoaXMuX3RvdGFsRHVyYXRpb249cyx0aGlzLl9kaXJ0eT0hMX1yZXR1cm4gdGhpcy5fdG90YWxEdXJhdGlvbn1yZXR1cm4gMCE9PXRoaXMudG90YWxEdXJhdGlvbigpJiYwIT09dCYmdGhpcy50aW1lU2NhbGUodGhpcy5fdG90YWxEdXJhdGlvbi90KSx0aGlzfSxmLnVzZXNGcmFtZXM9ZnVuY3Rpb24oKXtmb3IodmFyIGU9dGhpcy5fdGltZWxpbmU7ZS5fdGltZWxpbmU7KWU9ZS5fdGltZWxpbmU7cmV0dXJuIGU9PT10Ll9yb290RnJhbWVzVGltZWxpbmV9LGYucmF3VGltZT1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9wYXVzZWQ/dGhpcy5fdG90YWxUaW1lOih0aGlzLl90aW1lbGluZS5yYXdUaW1lKCktdGhpcy5fc3RhcnRUaW1lKSp0aGlzLl90aW1lU2NhbGV9LHN9LCEwKX0pLHdpbmRvdy5fZ3NEZWZpbmUmJndpbmRvdy5fZ3NRdWV1ZS5wb3AoKSgpOyIsIi8qIVxyXG4gKiBWRVJTSU9OOiAxLjEyLjFcclxuICogREFURTogMjAxNC0wNi0yNlxyXG4gKiBVUERBVEVTIEFORCBET0NTIEFUOiBodHRwOi8vd3d3LmdyZWVuc29jay5jb21cclxuICpcclxuICogQGxpY2Vuc2UgQ29weXJpZ2h0IChjKSAyMDA4LTIwMTQsIEdyZWVuU29jay4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuICogVGhpcyB3b3JrIGlzIHN1YmplY3QgdG8gdGhlIHRlcm1zIGF0IGh0dHA6Ly93d3cuZ3JlZW5zb2NrLmNvbS90ZXJtc19vZl91c2UuaHRtbCBvciBmb3JcclxuICogQ2x1YiBHcmVlblNvY2sgbWVtYmVycywgdGhlIHNvZnR3YXJlIGFncmVlbWVudCB0aGF0IHdhcyBpc3N1ZWQgd2l0aCB5b3VyIG1lbWJlcnNoaXAuXHJcbiAqIFxyXG4gKiBAYXV0aG9yOiBKYWNrIERveWxlLCBqYWNrQGdyZWVuc29jay5jb21cclxuICovXHJcbihmdW5jdGlvbih0KXtcInVzZSBzdHJpY3RcIjt2YXIgZT10LkdyZWVuU29ja0dsb2JhbHN8fHQ7aWYoIWUuVHdlZW5MaXRlKXt2YXIgaSxzLG4scixhLG89ZnVuY3Rpb24odCl7dmFyIGkscz10LnNwbGl0KFwiLlwiKSxuPWU7Zm9yKGk9MDtzLmxlbmd0aD5pO2krKyluW3NbaV1dPW49bltzW2ldXXx8e307cmV0dXJuIG59LGw9byhcImNvbS5ncmVlbnNvY2tcIiksaD0xZS0xMCxfPVtdLnNsaWNlLHU9ZnVuY3Rpb24oKXt9LG09ZnVuY3Rpb24oKXt2YXIgdD1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLGU9dC5jYWxsKFtdKTtyZXR1cm4gZnVuY3Rpb24oaSl7cmV0dXJuIG51bGwhPWkmJihpIGluc3RhbmNlb2YgQXJyYXl8fFwib2JqZWN0XCI9PXR5cGVvZiBpJiYhIWkucHVzaCYmdC5jYWxsKGkpPT09ZSl9fSgpLGY9e30scD1mdW5jdGlvbihpLHMsbixyKXt0aGlzLnNjPWZbaV0/ZltpXS5zYzpbXSxmW2ldPXRoaXMsdGhpcy5nc0NsYXNzPW51bGwsdGhpcy5mdW5jPW47dmFyIGE9W107dGhpcy5jaGVjaz1mdW5jdGlvbihsKXtmb3IodmFyIGgsXyx1LG0sYz1zLmxlbmd0aCxkPWM7LS1jPi0xOykoaD1mW3NbY11dfHxuZXcgcChzW2NdLFtdKSkuZ3NDbGFzcz8oYVtjXT1oLmdzQ2xhc3MsZC0tKTpsJiZoLnNjLnB1c2godGhpcyk7aWYoMD09PWQmJm4pZm9yKF89KFwiY29tLmdyZWVuc29jay5cIitpKS5zcGxpdChcIi5cIiksdT1fLnBvcCgpLG09byhfLmpvaW4oXCIuXCIpKVt1XT10aGlzLmdzQ2xhc3M9bi5hcHBseShuLGEpLHImJihlW3VdPW0sXCJmdW5jdGlvblwiPT10eXBlb2YgZGVmaW5lJiZkZWZpbmUuYW1kP2RlZmluZSgodC5HcmVlblNvY2tBTURQYXRoP3QuR3JlZW5Tb2NrQU1EUGF0aCtcIi9cIjpcIlwiKStpLnNwbGl0KFwiLlwiKS5qb2luKFwiL1wiKSxbXSxmdW5jdGlvbigpe3JldHVybiBtfSk6XCJ1bmRlZmluZWRcIiE9dHlwZW9mIG1vZHVsZSYmbW9kdWxlLmV4cG9ydHMmJihtb2R1bGUuZXhwb3J0cz1tKSksYz0wO3RoaXMuc2MubGVuZ3RoPmM7YysrKXRoaXMuc2NbY10uY2hlY2soKX0sdGhpcy5jaGVjayghMCl9LGM9dC5fZ3NEZWZpbmU9ZnVuY3Rpb24odCxlLGkscyl7cmV0dXJuIG5ldyBwKHQsZSxpLHMpfSxkPWwuX2NsYXNzPWZ1bmN0aW9uKHQsZSxpKXtyZXR1cm4gZT1lfHxmdW5jdGlvbigpe30sYyh0LFtdLGZ1bmN0aW9uKCl7cmV0dXJuIGV9LGkpLGV9O2MuZ2xvYmFscz1lO3ZhciB2PVswLDAsMSwxXSxnPVtdLFQ9ZChcImVhc2luZy5FYXNlXCIsZnVuY3Rpb24odCxlLGkscyl7dGhpcy5fZnVuYz10LHRoaXMuX3R5cGU9aXx8MCx0aGlzLl9wb3dlcj1zfHwwLHRoaXMuX3BhcmFtcz1lP3YuY29uY2F0KGUpOnZ9LCEwKSx5PVQubWFwPXt9LHc9VC5yZWdpc3Rlcj1mdW5jdGlvbih0LGUsaSxzKXtmb3IodmFyIG4scixhLG8saD1lLnNwbGl0KFwiLFwiKSxfPWgubGVuZ3RoLHU9KGl8fFwiZWFzZUluLGVhc2VPdXQsZWFzZUluT3V0XCIpLnNwbGl0KFwiLFwiKTstLV8+LTE7KWZvcihyPWhbX10sbj1zP2QoXCJlYXNpbmcuXCIrcixudWxsLCEwKTpsLmVhc2luZ1tyXXx8e30sYT11Lmxlbmd0aDstLWE+LTE7KW89dVthXSx5W3IrXCIuXCIrb109eVtvK3JdPW5bb109dC5nZXRSYXRpbz90OnRbb118fG5ldyB0fTtmb3Iobj1ULnByb3RvdHlwZSxuLl9jYWxjRW5kPSExLG4uZ2V0UmF0aW89ZnVuY3Rpb24odCl7aWYodGhpcy5fZnVuYylyZXR1cm4gdGhpcy5fcGFyYW1zWzBdPXQsdGhpcy5fZnVuYy5hcHBseShudWxsLHRoaXMuX3BhcmFtcyk7dmFyIGU9dGhpcy5fdHlwZSxpPXRoaXMuX3Bvd2VyLHM9MT09PWU/MS10OjI9PT1lP3Q6LjU+dD8yKnQ6MiooMS10KTtyZXR1cm4gMT09PWk/cyo9czoyPT09aT9zKj1zKnM6Mz09PWk/cyo9cypzKnM6ND09PWkmJihzKj1zKnMqcypzKSwxPT09ZT8xLXM6Mj09PWU/czouNT50P3MvMjoxLXMvMn0saT1bXCJMaW5lYXJcIixcIlF1YWRcIixcIkN1YmljXCIsXCJRdWFydFwiLFwiUXVpbnQsU3Ryb25nXCJdLHM9aS5sZW5ndGg7LS1zPi0xOyluPWlbc10rXCIsUG93ZXJcIitzLHcobmV3IFQobnVsbCxudWxsLDEscyksbixcImVhc2VPdXRcIiwhMCksdyhuZXcgVChudWxsLG51bGwsMixzKSxuLFwiZWFzZUluXCIrKDA9PT1zP1wiLGVhc2VOb25lXCI6XCJcIikpLHcobmV3IFQobnVsbCxudWxsLDMscyksbixcImVhc2VJbk91dFwiKTt5LmxpbmVhcj1sLmVhc2luZy5MaW5lYXIuZWFzZUluLHkuc3dpbmc9bC5lYXNpbmcuUXVhZC5lYXNlSW5PdXQ7dmFyIFA9ZChcImV2ZW50cy5FdmVudERpc3BhdGNoZXJcIixmdW5jdGlvbih0KXt0aGlzLl9saXN0ZW5lcnM9e30sdGhpcy5fZXZlbnRUYXJnZXQ9dHx8dGhpc30pO249UC5wcm90b3R5cGUsbi5hZGRFdmVudExpc3RlbmVyPWZ1bmN0aW9uKHQsZSxpLHMsbil7bj1ufHwwO3ZhciBvLGwsaD10aGlzLl9saXN0ZW5lcnNbdF0sXz0wO2ZvcihudWxsPT1oJiYodGhpcy5fbGlzdGVuZXJzW3RdPWg9W10pLGw9aC5sZW5ndGg7LS1sPi0xOylvPWhbbF0sby5jPT09ZSYmby5zPT09aT9oLnNwbGljZShsLDEpOjA9PT1fJiZuPm8ucHImJihfPWwrMSk7aC5zcGxpY2UoXywwLHtjOmUsczppLHVwOnMscHI6bn0pLHRoaXMhPT1yfHxhfHxyLndha2UoKX0sbi5yZW1vdmVFdmVudExpc3RlbmVyPWZ1bmN0aW9uKHQsZSl7dmFyIGkscz10aGlzLl9saXN0ZW5lcnNbdF07aWYocylmb3IoaT1zLmxlbmd0aDstLWk+LTE7KWlmKHNbaV0uYz09PWUpcmV0dXJuIHMuc3BsaWNlKGksMSksdm9pZCAwfSxuLmRpc3BhdGNoRXZlbnQ9ZnVuY3Rpb24odCl7dmFyIGUsaSxzLG49dGhpcy5fbGlzdGVuZXJzW3RdO2lmKG4pZm9yKGU9bi5sZW5ndGgsaT10aGlzLl9ldmVudFRhcmdldDstLWU+LTE7KXM9bltlXSxzLnVwP3MuYy5jYWxsKHMuc3x8aSx7dHlwZTp0LHRhcmdldDppfSk6cy5jLmNhbGwocy5zfHxpKX07dmFyIGs9dC5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUsYj10LmNhbmNlbEFuaW1hdGlvbkZyYW1lLEE9RGF0ZS5ub3d8fGZ1bmN0aW9uKCl7cmV0dXJuKG5ldyBEYXRlKS5nZXRUaW1lKCl9LFM9QSgpO2ZvcihpPVtcIm1zXCIsXCJtb3pcIixcIndlYmtpdFwiLFwib1wiXSxzPWkubGVuZ3RoOy0tcz4tMSYmIWs7KWs9dFtpW3NdK1wiUmVxdWVzdEFuaW1hdGlvbkZyYW1lXCJdLGI9dFtpW3NdK1wiQ2FuY2VsQW5pbWF0aW9uRnJhbWVcIl18fHRbaVtzXStcIkNhbmNlbFJlcXVlc3RBbmltYXRpb25GcmFtZVwiXTtkKFwiVGlja2VyXCIsZnVuY3Rpb24odCxlKXt2YXIgaSxzLG4sbyxsLF89dGhpcyxtPUEoKSxmPWUhPT0hMSYmayxwPTUwMCxjPTMzLGQ9ZnVuY3Rpb24odCl7dmFyIGUscixhPUEoKS1TO2E+cCYmKG0rPWEtYyksUys9YSxfLnRpbWU9KFMtbSkvMWUzLGU9Xy50aW1lLWwsKCFpfHxlPjB8fHQ9PT0hMCkmJihfLmZyYW1lKyssbCs9ZSsoZT49bz8uMDA0Om8tZSkscj0hMCksdCE9PSEwJiYobj1zKGQpKSxyJiZfLmRpc3BhdGNoRXZlbnQoXCJ0aWNrXCIpfTtQLmNhbGwoXyksXy50aW1lPV8uZnJhbWU9MCxfLnRpY2s9ZnVuY3Rpb24oKXtkKCEwKX0sXy5sYWdTbW9vdGhpbmc9ZnVuY3Rpb24odCxlKXtwPXR8fDEvaCxjPU1hdGgubWluKGUscCwwKX0sXy5zbGVlcD1mdW5jdGlvbigpe251bGwhPW4mJihmJiZiP2Iobik6Y2xlYXJUaW1lb3V0KG4pLHM9dSxuPW51bGwsXz09PXImJihhPSExKSl9LF8ud2FrZT1mdW5jdGlvbigpe251bGwhPT1uP18uc2xlZXAoKTpfLmZyYW1lPjEwJiYoUz1BKCktcCs1KSxzPTA9PT1pP3U6ZiYmaz9rOmZ1bmN0aW9uKHQpe3JldHVybiBzZXRUaW1lb3V0KHQsMHwxZTMqKGwtXy50aW1lKSsxKX0sXz09PXImJihhPSEwKSxkKDIpfSxfLmZwcz1mdW5jdGlvbih0KXtyZXR1cm4gYXJndW1lbnRzLmxlbmd0aD8oaT10LG89MS8oaXx8NjApLGw9dGhpcy50aW1lK28sXy53YWtlKCksdm9pZCAwKTppfSxfLnVzZVJBRj1mdW5jdGlvbih0KXtyZXR1cm4gYXJndW1lbnRzLmxlbmd0aD8oXy5zbGVlcCgpLGY9dCxfLmZwcyhpKSx2b2lkIDApOmZ9LF8uZnBzKHQpLHNldFRpbWVvdXQoZnVuY3Rpb24oKXtmJiYoIW58fDU+Xy5mcmFtZSkmJl8udXNlUkFGKCExKX0sMTUwMCl9KSxuPWwuVGlja2VyLnByb3RvdHlwZT1uZXcgbC5ldmVudHMuRXZlbnREaXNwYXRjaGVyLG4uY29uc3RydWN0b3I9bC5UaWNrZXI7dmFyIHg9ZChcImNvcmUuQW5pbWF0aW9uXCIsZnVuY3Rpb24odCxlKXtpZih0aGlzLnZhcnM9ZT1lfHx7fSx0aGlzLl9kdXJhdGlvbj10aGlzLl90b3RhbER1cmF0aW9uPXR8fDAsdGhpcy5fZGVsYXk9TnVtYmVyKGUuZGVsYXkpfHwwLHRoaXMuX3RpbWVTY2FsZT0xLHRoaXMuX2FjdGl2ZT1lLmltbWVkaWF0ZVJlbmRlcj09PSEwLHRoaXMuZGF0YT1lLmRhdGEsdGhpcy5fcmV2ZXJzZWQ9ZS5yZXZlcnNlZD09PSEwLEIpe2F8fHIud2FrZSgpO3ZhciBpPXRoaXMudmFycy51c2VGcmFtZXM/UTpCO2kuYWRkKHRoaXMsaS5fdGltZSksdGhpcy52YXJzLnBhdXNlZCYmdGhpcy5wYXVzZWQoITApfX0pO3I9eC50aWNrZXI9bmV3IGwuVGlja2VyLG49eC5wcm90b3R5cGUsbi5fZGlydHk9bi5fZ2M9bi5faW5pdHRlZD1uLl9wYXVzZWQ9ITEsbi5fdG90YWxUaW1lPW4uX3RpbWU9MCxuLl9yYXdQcmV2VGltZT0tMSxuLl9uZXh0PW4uX2xhc3Q9bi5fb25VcGRhdGU9bi5fdGltZWxpbmU9bi50aW1lbGluZT1udWxsLG4uX3BhdXNlZD0hMTt2YXIgQz1mdW5jdGlvbigpe2EmJkEoKS1TPjJlMyYmci53YWtlKCksc2V0VGltZW91dChDLDJlMyl9O0MoKSxuLnBsYXk9ZnVuY3Rpb24odCxlKXtyZXR1cm4gbnVsbCE9dCYmdGhpcy5zZWVrKHQsZSksdGhpcy5yZXZlcnNlZCghMSkucGF1c2VkKCExKX0sbi5wYXVzZT1mdW5jdGlvbih0LGUpe3JldHVybiBudWxsIT10JiZ0aGlzLnNlZWsodCxlKSx0aGlzLnBhdXNlZCghMCl9LG4ucmVzdW1lPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIG51bGwhPXQmJnRoaXMuc2Vlayh0LGUpLHRoaXMucGF1c2VkKCExKX0sbi5zZWVrPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHRoaXMudG90YWxUaW1lKE51bWJlcih0KSxlIT09ITEpfSxuLnJlc3RhcnQ9ZnVuY3Rpb24odCxlKXtyZXR1cm4gdGhpcy5yZXZlcnNlZCghMSkucGF1c2VkKCExKS50b3RhbFRpbWUodD8tdGhpcy5fZGVsYXk6MCxlIT09ITEsITApfSxuLnJldmVyc2U9ZnVuY3Rpb24odCxlKXtyZXR1cm4gbnVsbCE9dCYmdGhpcy5zZWVrKHR8fHRoaXMudG90YWxEdXJhdGlvbigpLGUpLHRoaXMucmV2ZXJzZWQoITApLnBhdXNlZCghMSl9LG4ucmVuZGVyPWZ1bmN0aW9uKCl7fSxuLmludmFsaWRhdGU9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sbi5pc0FjdGl2ZT1mdW5jdGlvbigpe3ZhciB0LGU9dGhpcy5fdGltZWxpbmUsaT10aGlzLl9zdGFydFRpbWU7cmV0dXJuIWV8fCF0aGlzLl9nYyYmIXRoaXMuX3BhdXNlZCYmZS5pc0FjdGl2ZSgpJiYodD1lLnJhd1RpbWUoKSk+PWkmJmkrdGhpcy50b3RhbER1cmF0aW9uKCkvdGhpcy5fdGltZVNjYWxlPnR9LG4uX2VuYWJsZWQ9ZnVuY3Rpb24odCxlKXtyZXR1cm4gYXx8ci53YWtlKCksdGhpcy5fZ2M9IXQsdGhpcy5fYWN0aXZlPXRoaXMuaXNBY3RpdmUoKSxlIT09ITAmJih0JiYhdGhpcy50aW1lbGluZT90aGlzLl90aW1lbGluZS5hZGQodGhpcyx0aGlzLl9zdGFydFRpbWUtdGhpcy5fZGVsYXkpOiF0JiZ0aGlzLnRpbWVsaW5lJiZ0aGlzLl90aW1lbGluZS5fcmVtb3ZlKHRoaXMsITApKSwhMX0sbi5fa2lsbD1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9lbmFibGVkKCExLCExKX0sbi5raWxsPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHRoaXMuX2tpbGwodCxlKSx0aGlzfSxuLl91bmNhY2hlPWZ1bmN0aW9uKHQpe2Zvcih2YXIgZT10P3RoaXM6dGhpcy50aW1lbGluZTtlOyllLl9kaXJ0eT0hMCxlPWUudGltZWxpbmU7cmV0dXJuIHRoaXN9LG4uX3N3YXBTZWxmSW5QYXJhbXM9ZnVuY3Rpb24odCl7Zm9yKHZhciBlPXQubGVuZ3RoLGk9dC5jb25jYXQoKTstLWU+LTE7KVwie3NlbGZ9XCI9PT10W2VdJiYoaVtlXT10aGlzKTtyZXR1cm4gaX0sbi5ldmVudENhbGxiYWNrPWZ1bmN0aW9uKHQsZSxpLHMpe2lmKFwib25cIj09PSh0fHxcIlwiKS5zdWJzdHIoMCwyKSl7dmFyIG49dGhpcy52YXJzO2lmKDE9PT1hcmd1bWVudHMubGVuZ3RoKXJldHVybiBuW3RdO251bGw9PWU/ZGVsZXRlIG5bdF06KG5bdF09ZSxuW3QrXCJQYXJhbXNcIl09bShpKSYmLTEhPT1pLmpvaW4oXCJcIikuaW5kZXhPZihcIntzZWxmfVwiKT90aGlzLl9zd2FwU2VsZkluUGFyYW1zKGkpOmksblt0K1wiU2NvcGVcIl09cyksXCJvblVwZGF0ZVwiPT09dCYmKHRoaXMuX29uVXBkYXRlPWUpfXJldHVybiB0aGlzfSxuLmRlbGF5PWZ1bmN0aW9uKHQpe3JldHVybiBhcmd1bWVudHMubGVuZ3RoPyh0aGlzLl90aW1lbGluZS5zbW9vdGhDaGlsZFRpbWluZyYmdGhpcy5zdGFydFRpbWUodGhpcy5fc3RhcnRUaW1lK3QtdGhpcy5fZGVsYXkpLHRoaXMuX2RlbGF5PXQsdGhpcyk6dGhpcy5fZGVsYXl9LG4uZHVyYXRpb249ZnVuY3Rpb24odCl7cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGg/KHRoaXMuX2R1cmF0aW9uPXRoaXMuX3RvdGFsRHVyYXRpb249dCx0aGlzLl91bmNhY2hlKCEwKSx0aGlzLl90aW1lbGluZS5zbW9vdGhDaGlsZFRpbWluZyYmdGhpcy5fdGltZT4wJiZ0aGlzLl90aW1lPHRoaXMuX2R1cmF0aW9uJiYwIT09dCYmdGhpcy50b3RhbFRpbWUodGhpcy5fdG90YWxUaW1lKih0L3RoaXMuX2R1cmF0aW9uKSwhMCksdGhpcyk6KHRoaXMuX2RpcnR5PSExLHRoaXMuX2R1cmF0aW9uKX0sbi50b3RhbER1cmF0aW9uPWZ1bmN0aW9uKHQpe3JldHVybiB0aGlzLl9kaXJ0eT0hMSxhcmd1bWVudHMubGVuZ3RoP3RoaXMuZHVyYXRpb24odCk6dGhpcy5fdG90YWxEdXJhdGlvbn0sbi50aW1lPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGg/KHRoaXMuX2RpcnR5JiZ0aGlzLnRvdGFsRHVyYXRpb24oKSx0aGlzLnRvdGFsVGltZSh0PnRoaXMuX2R1cmF0aW9uP3RoaXMuX2R1cmF0aW9uOnQsZSkpOnRoaXMuX3RpbWV9LG4udG90YWxUaW1lPWZ1bmN0aW9uKHQsZSxpKXtpZihhfHxyLndha2UoKSwhYXJndW1lbnRzLmxlbmd0aClyZXR1cm4gdGhpcy5fdG90YWxUaW1lO2lmKHRoaXMuX3RpbWVsaW5lKXtpZigwPnQmJiFpJiYodCs9dGhpcy50b3RhbER1cmF0aW9uKCkpLHRoaXMuX3RpbWVsaW5lLnNtb290aENoaWxkVGltaW5nKXt0aGlzLl9kaXJ0eSYmdGhpcy50b3RhbER1cmF0aW9uKCk7dmFyIHM9dGhpcy5fdG90YWxEdXJhdGlvbixuPXRoaXMuX3RpbWVsaW5lO2lmKHQ+cyYmIWkmJih0PXMpLHRoaXMuX3N0YXJ0VGltZT0odGhpcy5fcGF1c2VkP3RoaXMuX3BhdXNlVGltZTpuLl90aW1lKS0odGhpcy5fcmV2ZXJzZWQ/cy10OnQpL3RoaXMuX3RpbWVTY2FsZSxuLl9kaXJ0eXx8dGhpcy5fdW5jYWNoZSghMSksbi5fdGltZWxpbmUpZm9yKDtuLl90aW1lbGluZTspbi5fdGltZWxpbmUuX3RpbWUhPT0obi5fc3RhcnRUaW1lK24uX3RvdGFsVGltZSkvbi5fdGltZVNjYWxlJiZuLnRvdGFsVGltZShuLl90b3RhbFRpbWUsITApLG49bi5fdGltZWxpbmV9dGhpcy5fZ2MmJnRoaXMuX2VuYWJsZWQoITAsITEpLCh0aGlzLl90b3RhbFRpbWUhPT10fHwwPT09dGhpcy5fZHVyYXRpb24pJiYodGhpcy5yZW5kZXIodCxlLCExKSx6Lmxlbmd0aCYmcSgpKX1yZXR1cm4gdGhpc30sbi5wcm9ncmVzcz1uLnRvdGFsUHJvZ3Jlc3M9ZnVuY3Rpb24odCxlKXtyZXR1cm4gYXJndW1lbnRzLmxlbmd0aD90aGlzLnRvdGFsVGltZSh0aGlzLmR1cmF0aW9uKCkqdCxlKTp0aGlzLl90aW1lL3RoaXMuZHVyYXRpb24oKX0sbi5zdGFydFRpbWU9ZnVuY3Rpb24odCl7cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGg/KHQhPT10aGlzLl9zdGFydFRpbWUmJih0aGlzLl9zdGFydFRpbWU9dCx0aGlzLnRpbWVsaW5lJiZ0aGlzLnRpbWVsaW5lLl9zb3J0Q2hpbGRyZW4mJnRoaXMudGltZWxpbmUuYWRkKHRoaXMsdC10aGlzLl9kZWxheSkpLHRoaXMpOnRoaXMuX3N0YXJ0VGltZX0sbi50aW1lU2NhbGU9ZnVuY3Rpb24odCl7aWYoIWFyZ3VtZW50cy5sZW5ndGgpcmV0dXJuIHRoaXMuX3RpbWVTY2FsZTtpZih0PXR8fGgsdGhpcy5fdGltZWxpbmUmJnRoaXMuX3RpbWVsaW5lLnNtb290aENoaWxkVGltaW5nKXt2YXIgZT10aGlzLl9wYXVzZVRpbWUsaT1lfHwwPT09ZT9lOnRoaXMuX3RpbWVsaW5lLnRvdGFsVGltZSgpO3RoaXMuX3N0YXJ0VGltZT1pLShpLXRoaXMuX3N0YXJ0VGltZSkqdGhpcy5fdGltZVNjYWxlL3R9cmV0dXJuIHRoaXMuX3RpbWVTY2FsZT10LHRoaXMuX3VuY2FjaGUoITEpfSxuLnJldmVyc2VkPWZ1bmN0aW9uKHQpe3JldHVybiBhcmd1bWVudHMubGVuZ3RoPyh0IT10aGlzLl9yZXZlcnNlZCYmKHRoaXMuX3JldmVyc2VkPXQsdGhpcy50b3RhbFRpbWUodGhpcy5fdGltZWxpbmUmJiF0aGlzLl90aW1lbGluZS5zbW9vdGhDaGlsZFRpbWluZz90aGlzLnRvdGFsRHVyYXRpb24oKS10aGlzLl90b3RhbFRpbWU6dGhpcy5fdG90YWxUaW1lLCEwKSksdGhpcyk6dGhpcy5fcmV2ZXJzZWR9LG4ucGF1c2VkPWZ1bmN0aW9uKHQpe2lmKCFhcmd1bWVudHMubGVuZ3RoKXJldHVybiB0aGlzLl9wYXVzZWQ7aWYodCE9dGhpcy5fcGF1c2VkJiZ0aGlzLl90aW1lbGluZSl7YXx8dHx8ci53YWtlKCk7dmFyIGU9dGhpcy5fdGltZWxpbmUsaT1lLnJhd1RpbWUoKSxzPWktdGhpcy5fcGF1c2VUaW1lOyF0JiZlLnNtb290aENoaWxkVGltaW5nJiYodGhpcy5fc3RhcnRUaW1lKz1zLHRoaXMuX3VuY2FjaGUoITEpKSx0aGlzLl9wYXVzZVRpbWU9dD9pOm51bGwsdGhpcy5fcGF1c2VkPXQsdGhpcy5fYWN0aXZlPXRoaXMuaXNBY3RpdmUoKSwhdCYmMCE9PXMmJnRoaXMuX2luaXR0ZWQmJnRoaXMuZHVyYXRpb24oKSYmdGhpcy5yZW5kZXIoZS5zbW9vdGhDaGlsZFRpbWluZz90aGlzLl90b3RhbFRpbWU6KGktdGhpcy5fc3RhcnRUaW1lKS90aGlzLl90aW1lU2NhbGUsITAsITApfXJldHVybiB0aGlzLl9nYyYmIXQmJnRoaXMuX2VuYWJsZWQoITAsITEpLHRoaXN9O3ZhciBSPWQoXCJjb3JlLlNpbXBsZVRpbWVsaW5lXCIsZnVuY3Rpb24odCl7eC5jYWxsKHRoaXMsMCx0KSx0aGlzLmF1dG9SZW1vdmVDaGlsZHJlbj10aGlzLnNtb290aENoaWxkVGltaW5nPSEwfSk7bj1SLnByb3RvdHlwZT1uZXcgeCxuLmNvbnN0cnVjdG9yPVIsbi5raWxsKCkuX2djPSExLG4uX2ZpcnN0PW4uX2xhc3Q9bnVsbCxuLl9zb3J0Q2hpbGRyZW49ITEsbi5hZGQ9bi5pbnNlcnQ9ZnVuY3Rpb24odCxlKXt2YXIgaSxzO2lmKHQuX3N0YXJ0VGltZT1OdW1iZXIoZXx8MCkrdC5fZGVsYXksdC5fcGF1c2VkJiZ0aGlzIT09dC5fdGltZWxpbmUmJih0Ll9wYXVzZVRpbWU9dC5fc3RhcnRUaW1lKyh0aGlzLnJhd1RpbWUoKS10Ll9zdGFydFRpbWUpL3QuX3RpbWVTY2FsZSksdC50aW1lbGluZSYmdC50aW1lbGluZS5fcmVtb3ZlKHQsITApLHQudGltZWxpbmU9dC5fdGltZWxpbmU9dGhpcyx0Ll9nYyYmdC5fZW5hYmxlZCghMCwhMCksaT10aGlzLl9sYXN0LHRoaXMuX3NvcnRDaGlsZHJlbilmb3Iocz10Ll9zdGFydFRpbWU7aSYmaS5fc3RhcnRUaW1lPnM7KWk9aS5fcHJldjtyZXR1cm4gaT8odC5fbmV4dD1pLl9uZXh0LGkuX25leHQ9dCk6KHQuX25leHQ9dGhpcy5fZmlyc3QsdGhpcy5fZmlyc3Q9dCksdC5fbmV4dD90Ll9uZXh0Ll9wcmV2PXQ6dGhpcy5fbGFzdD10LHQuX3ByZXY9aSx0aGlzLl90aW1lbGluZSYmdGhpcy5fdW5jYWNoZSghMCksdGhpc30sbi5fcmVtb3ZlPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHQudGltZWxpbmU9PT10aGlzJiYoZXx8dC5fZW5hYmxlZCghMSwhMCksdC50aW1lbGluZT1udWxsLHQuX3ByZXY/dC5fcHJldi5fbmV4dD10Ll9uZXh0OnRoaXMuX2ZpcnN0PT09dCYmKHRoaXMuX2ZpcnN0PXQuX25leHQpLHQuX25leHQ/dC5fbmV4dC5fcHJldj10Ll9wcmV2OnRoaXMuX2xhc3Q9PT10JiYodGhpcy5fbGFzdD10Ll9wcmV2KSx0aGlzLl90aW1lbGluZSYmdGhpcy5fdW5jYWNoZSghMCkpLHRoaXN9LG4ucmVuZGVyPWZ1bmN0aW9uKHQsZSxpKXt2YXIgcyxuPXRoaXMuX2ZpcnN0O2Zvcih0aGlzLl90b3RhbFRpbWU9dGhpcy5fdGltZT10aGlzLl9yYXdQcmV2VGltZT10O247KXM9bi5fbmV4dCwobi5fYWN0aXZlfHx0Pj1uLl9zdGFydFRpbWUmJiFuLl9wYXVzZWQpJiYobi5fcmV2ZXJzZWQ/bi5yZW5kZXIoKG4uX2RpcnR5P24udG90YWxEdXJhdGlvbigpOm4uX3RvdGFsRHVyYXRpb24pLSh0LW4uX3N0YXJ0VGltZSkqbi5fdGltZVNjYWxlLGUsaSk6bi5yZW5kZXIoKHQtbi5fc3RhcnRUaW1lKSpuLl90aW1lU2NhbGUsZSxpKSksbj1zfSxuLnJhd1RpbWU9ZnVuY3Rpb24oKXtyZXR1cm4gYXx8ci53YWtlKCksdGhpcy5fdG90YWxUaW1lfTt2YXIgRD1kKFwiVHdlZW5MaXRlXCIsZnVuY3Rpb24oZSxpLHMpe2lmKHguY2FsbCh0aGlzLGkscyksdGhpcy5yZW5kZXI9RC5wcm90b3R5cGUucmVuZGVyLG51bGw9PWUpdGhyb3dcIkNhbm5vdCB0d2VlbiBhIG51bGwgdGFyZ2V0LlwiO3RoaXMudGFyZ2V0PWU9XCJzdHJpbmdcIiE9dHlwZW9mIGU/ZTpELnNlbGVjdG9yKGUpfHxlO3ZhciBuLHIsYSxvPWUuanF1ZXJ5fHxlLmxlbmd0aCYmZSE9PXQmJmVbMF0mJihlWzBdPT09dHx8ZVswXS5ub2RlVHlwZSYmZVswXS5zdHlsZSYmIWUubm9kZVR5cGUpLGw9dGhpcy52YXJzLm92ZXJ3cml0ZTtpZih0aGlzLl9vdmVyd3JpdGU9bD1udWxsPT1sP0dbRC5kZWZhdWx0T3ZlcndyaXRlXTpcIm51bWJlclwiPT10eXBlb2YgbD9sPj4wOkdbbF0sKG98fGUgaW5zdGFuY2VvZiBBcnJheXx8ZS5wdXNoJiZtKGUpKSYmXCJudW1iZXJcIiE9dHlwZW9mIGVbMF0pZm9yKHRoaXMuX3RhcmdldHM9YT1fLmNhbGwoZSwwKSx0aGlzLl9wcm9wTG9va3VwPVtdLHRoaXMuX3NpYmxpbmdzPVtdLG49MDthLmxlbmd0aD5uO24rKylyPWFbbl0scj9cInN0cmluZ1wiIT10eXBlb2Ygcj9yLmxlbmd0aCYmciE9PXQmJnJbMF0mJihyWzBdPT09dHx8clswXS5ub2RlVHlwZSYmclswXS5zdHlsZSYmIXIubm9kZVR5cGUpPyhhLnNwbGljZShuLS0sMSksdGhpcy5fdGFyZ2V0cz1hPWEuY29uY2F0KF8uY2FsbChyLDApKSk6KHRoaXMuX3NpYmxpbmdzW25dPU0ocix0aGlzLCExKSwxPT09bCYmdGhpcy5fc2libGluZ3Nbbl0ubGVuZ3RoPjEmJiQocix0aGlzLG51bGwsMSx0aGlzLl9zaWJsaW5nc1tuXSkpOihyPWFbbi0tXT1ELnNlbGVjdG9yKHIpLFwic3RyaW5nXCI9PXR5cGVvZiByJiZhLnNwbGljZShuKzEsMSkpOmEuc3BsaWNlKG4tLSwxKTtlbHNlIHRoaXMuX3Byb3BMb29rdXA9e30sdGhpcy5fc2libGluZ3M9TShlLHRoaXMsITEpLDE9PT1sJiZ0aGlzLl9zaWJsaW5ncy5sZW5ndGg+MSYmJChlLHRoaXMsbnVsbCwxLHRoaXMuX3NpYmxpbmdzKTsodGhpcy52YXJzLmltbWVkaWF0ZVJlbmRlcnx8MD09PWkmJjA9PT10aGlzLl9kZWxheSYmdGhpcy52YXJzLmltbWVkaWF0ZVJlbmRlciE9PSExKSYmKHRoaXMuX3RpbWU9LWgsdGhpcy5yZW5kZXIoLXRoaXMuX2RlbGF5KSl9LCEwKSxJPWZ1bmN0aW9uKGUpe3JldHVybiBlLmxlbmd0aCYmZSE9PXQmJmVbMF0mJihlWzBdPT09dHx8ZVswXS5ub2RlVHlwZSYmZVswXS5zdHlsZSYmIWUubm9kZVR5cGUpfSxFPWZ1bmN0aW9uKHQsZSl7dmFyIGkscz17fTtmb3IoaSBpbiB0KWpbaV18fGkgaW4gZSYmXCJ0cmFuc2Zvcm1cIiE9PWkmJlwieFwiIT09aSYmXCJ5XCIhPT1pJiZcIndpZHRoXCIhPT1pJiZcImhlaWdodFwiIT09aSYmXCJjbGFzc05hbWVcIiE9PWkmJlwiYm9yZGVyXCIhPT1pfHwhKCFMW2ldfHxMW2ldJiZMW2ldLl9hdXRvQ1NTKXx8KHNbaV09dFtpXSxkZWxldGUgdFtpXSk7dC5jc3M9c307bj1ELnByb3RvdHlwZT1uZXcgeCxuLmNvbnN0cnVjdG9yPUQsbi5raWxsKCkuX2djPSExLG4ucmF0aW89MCxuLl9maXJzdFBUPW4uX3RhcmdldHM9bi5fb3ZlcndyaXR0ZW5Qcm9wcz1uLl9zdGFydEF0PW51bGwsbi5fbm90aWZ5UGx1Z2luc09mRW5hYmxlZD1uLl9sYXp5PSExLEQudmVyc2lvbj1cIjEuMTIuMVwiLEQuZGVmYXVsdEVhc2U9bi5fZWFzZT1uZXcgVChudWxsLG51bGwsMSwxKSxELmRlZmF1bHRPdmVyd3JpdGU9XCJhdXRvXCIsRC50aWNrZXI9cixELmF1dG9TbGVlcD0hMCxELmxhZ1Ntb290aGluZz1mdW5jdGlvbih0LGUpe3IubGFnU21vb3RoaW5nKHQsZSl9LEQuc2VsZWN0b3I9dC4kfHx0LmpRdWVyeXx8ZnVuY3Rpb24oZSl7cmV0dXJuIHQuJD8oRC5zZWxlY3Rvcj10LiQsdC4kKGUpKTp0LmRvY3VtZW50P3QuZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCIjXCI9PT1lLmNoYXJBdCgwKT9lLnN1YnN0cigxKTplKTplfTt2YXIgej1bXSxPPXt9LE49RC5faW50ZXJuYWxzPXtpc0FycmF5Om0saXNTZWxlY3RvcjpJLGxhenlUd2VlbnM6en0sTD1ELl9wbHVnaW5zPXt9LFU9Ti50d2Vlbkxvb2t1cD17fSxGPTAsaj1OLnJlc2VydmVkUHJvcHM9e2Vhc2U6MSxkZWxheToxLG92ZXJ3cml0ZToxLG9uQ29tcGxldGU6MSxvbkNvbXBsZXRlUGFyYW1zOjEsb25Db21wbGV0ZVNjb3BlOjEsdXNlRnJhbWVzOjEscnVuQmFja3dhcmRzOjEsc3RhcnRBdDoxLG9uVXBkYXRlOjEsb25VcGRhdGVQYXJhbXM6MSxvblVwZGF0ZVNjb3BlOjEsb25TdGFydDoxLG9uU3RhcnRQYXJhbXM6MSxvblN0YXJ0U2NvcGU6MSxvblJldmVyc2VDb21wbGV0ZToxLG9uUmV2ZXJzZUNvbXBsZXRlUGFyYW1zOjEsb25SZXZlcnNlQ29tcGxldGVTY29wZToxLG9uUmVwZWF0OjEsb25SZXBlYXRQYXJhbXM6MSxvblJlcGVhdFNjb3BlOjEsZWFzZVBhcmFtczoxLHlveW86MSxpbW1lZGlhdGVSZW5kZXI6MSxyZXBlYXQ6MSxyZXBlYXREZWxheToxLGRhdGE6MSxwYXVzZWQ6MSxyZXZlcnNlZDoxLGF1dG9DU1M6MSxsYXp5OjF9LEc9e25vbmU6MCxhbGw6MSxhdXRvOjIsY29uY3VycmVudDozLGFsbE9uU3RhcnQ6NCxwcmVleGlzdGluZzo1LFwidHJ1ZVwiOjEsXCJmYWxzZVwiOjB9LFE9eC5fcm9vdEZyYW1lc1RpbWVsaW5lPW5ldyBSLEI9eC5fcm9vdFRpbWVsaW5lPW5ldyBSLHE9ZnVuY3Rpb24oKXt2YXIgdD16Lmxlbmd0aDtmb3IoTz17fTstLXQ+LTE7KWk9elt0XSxpJiZpLl9sYXp5IT09ITEmJihpLnJlbmRlcihpLl9sYXp5LCExLCEwKSxpLl9sYXp5PSExKTt6Lmxlbmd0aD0wfTtCLl9zdGFydFRpbWU9ci50aW1lLFEuX3N0YXJ0VGltZT1yLmZyYW1lLEIuX2FjdGl2ZT1RLl9hY3RpdmU9ITAsc2V0VGltZW91dChxLDEpLHguX3VwZGF0ZVJvb3Q9RC5yZW5kZXI9ZnVuY3Rpb24oKXt2YXIgdCxlLGk7aWYoei5sZW5ndGgmJnEoKSxCLnJlbmRlcigoci50aW1lLUIuX3N0YXJ0VGltZSkqQi5fdGltZVNjYWxlLCExLCExKSxRLnJlbmRlcigoci5mcmFtZS1RLl9zdGFydFRpbWUpKlEuX3RpbWVTY2FsZSwhMSwhMSksei5sZW5ndGgmJnEoKSwhKHIuZnJhbWUlMTIwKSl7Zm9yKGkgaW4gVSl7Zm9yKGU9VVtpXS50d2VlbnMsdD1lLmxlbmd0aDstLXQ+LTE7KWVbdF0uX2djJiZlLnNwbGljZSh0LDEpOzA9PT1lLmxlbmd0aCYmZGVsZXRlIFVbaV19aWYoaT1CLl9maXJzdCwoIWl8fGkuX3BhdXNlZCkmJkQuYXV0b1NsZWVwJiYhUS5fZmlyc3QmJjE9PT1yLl9saXN0ZW5lcnMudGljay5sZW5ndGgpe2Zvcig7aSYmaS5fcGF1c2VkOylpPWkuX25leHQ7aXx8ci5zbGVlcCgpfX19LHIuYWRkRXZlbnRMaXN0ZW5lcihcInRpY2tcIix4Ll91cGRhdGVSb290KTt2YXIgTT1mdW5jdGlvbih0LGUsaSl7dmFyIHMsbixyPXQuX2dzVHdlZW5JRDtpZihVW3J8fCh0Ll9nc1R3ZWVuSUQ9cj1cInRcIitGKyspXXx8KFVbcl09e3RhcmdldDp0LHR3ZWVuczpbXX0pLGUmJihzPVVbcl0udHdlZW5zLHNbbj1zLmxlbmd0aF09ZSxpKSlmb3IoOy0tbj4tMTspc1tuXT09PWUmJnMuc3BsaWNlKG4sMSk7cmV0dXJuIFVbcl0udHdlZW5zfSwkPWZ1bmN0aW9uKHQsZSxpLHMsbil7dmFyIHIsYSxvLGw7aWYoMT09PXN8fHM+PTQpe2ZvcihsPW4ubGVuZ3RoLHI9MDtsPnI7cisrKWlmKChvPW5bcl0pIT09ZSlvLl9nY3x8by5fZW5hYmxlZCghMSwhMSkmJihhPSEwKTtlbHNlIGlmKDU9PT1zKWJyZWFrO3JldHVybiBhfXZhciBfLHU9ZS5fc3RhcnRUaW1lK2gsbT1bXSxmPTAscD0wPT09ZS5fZHVyYXRpb247Zm9yKHI9bi5sZW5ndGg7LS1yPi0xOykobz1uW3JdKT09PWV8fG8uX2djfHxvLl9wYXVzZWR8fChvLl90aW1lbGluZSE9PWUuX3RpbWVsaW5lPyhfPV98fEsoZSwwLHApLDA9PT1LKG8sXyxwKSYmKG1bZisrXT1vKSk6dT49by5fc3RhcnRUaW1lJiZvLl9zdGFydFRpbWUrby50b3RhbER1cmF0aW9uKCkvby5fdGltZVNjYWxlPnUmJigocHx8IW8uX2luaXR0ZWQpJiYyZS0xMD49dS1vLl9zdGFydFRpbWV8fChtW2YrK109bykpKTtmb3Iocj1mOy0tcj4tMTspbz1tW3JdLDI9PT1zJiZvLl9raWxsKGksdCkmJihhPSEwKSwoMiE9PXN8fCFvLl9maXJzdFBUJiZvLl9pbml0dGVkKSYmby5fZW5hYmxlZCghMSwhMSkmJihhPSEwKTtyZXR1cm4gYX0sSz1mdW5jdGlvbih0LGUsaSl7Zm9yKHZhciBzPXQuX3RpbWVsaW5lLG49cy5fdGltZVNjYWxlLHI9dC5fc3RhcnRUaW1lO3MuX3RpbWVsaW5lOyl7aWYocis9cy5fc3RhcnRUaW1lLG4qPXMuX3RpbWVTY2FsZSxzLl9wYXVzZWQpcmV0dXJuLTEwMDtzPXMuX3RpbWVsaW5lfXJldHVybiByLz1uLHI+ZT9yLWU6aSYmcj09PWV8fCF0Ll9pbml0dGVkJiYyKmg+ci1lP2g6KHIrPXQudG90YWxEdXJhdGlvbigpL3QuX3RpbWVTY2FsZS9uKT5lK2g/MDpyLWUtaH07bi5faW5pdD1mdW5jdGlvbigpe3ZhciB0LGUsaSxzLG4scj10aGlzLnZhcnMsYT10aGlzLl9vdmVyd3JpdHRlblByb3BzLG89dGhpcy5fZHVyYXRpb24sbD0hIXIuaW1tZWRpYXRlUmVuZGVyLGg9ci5lYXNlO2lmKHIuc3RhcnRBdCl7dGhpcy5fc3RhcnRBdCYmKHRoaXMuX3N0YXJ0QXQucmVuZGVyKC0xLCEwKSx0aGlzLl9zdGFydEF0LmtpbGwoKSksbj17fTtmb3IocyBpbiByLnN0YXJ0QXQpbltzXT1yLnN0YXJ0QXRbc107aWYobi5vdmVyd3JpdGU9ITEsbi5pbW1lZGlhdGVSZW5kZXI9ITAsbi5sYXp5PWwmJnIubGF6eSE9PSExLG4uc3RhcnRBdD1uLmRlbGF5PW51bGwsdGhpcy5fc3RhcnRBdD1ELnRvKHRoaXMudGFyZ2V0LDAsbiksbClpZih0aGlzLl90aW1lPjApdGhpcy5fc3RhcnRBdD1udWxsO2Vsc2UgaWYoMCE9PW8pcmV0dXJufWVsc2UgaWYoci5ydW5CYWNrd2FyZHMmJjAhPT1vKWlmKHRoaXMuX3N0YXJ0QXQpdGhpcy5fc3RhcnRBdC5yZW5kZXIoLTEsITApLHRoaXMuX3N0YXJ0QXQua2lsbCgpLHRoaXMuX3N0YXJ0QXQ9bnVsbDtlbHNle2k9e307Zm9yKHMgaW4gcilqW3NdJiZcImF1dG9DU1NcIiE9PXN8fChpW3NdPXJbc10pO2lmKGkub3ZlcndyaXRlPTAsaS5kYXRhPVwiaXNGcm9tU3RhcnRcIixpLmxhenk9bCYmci5sYXp5IT09ITEsaS5pbW1lZGlhdGVSZW5kZXI9bCx0aGlzLl9zdGFydEF0PUQudG8odGhpcy50YXJnZXQsMCxpKSxsKXtpZigwPT09dGhpcy5fdGltZSlyZXR1cm59ZWxzZSB0aGlzLl9zdGFydEF0Ll9pbml0KCksdGhpcy5fc3RhcnRBdC5fZW5hYmxlZCghMSl9aWYodGhpcy5fZWFzZT1oP2ggaW5zdGFuY2VvZiBUP3IuZWFzZVBhcmFtcyBpbnN0YW5jZW9mIEFycmF5P2guY29uZmlnLmFwcGx5KGgsci5lYXNlUGFyYW1zKTpoOlwiZnVuY3Rpb25cIj09dHlwZW9mIGg/bmV3IFQoaCxyLmVhc2VQYXJhbXMpOnlbaF18fEQuZGVmYXVsdEVhc2U6RC5kZWZhdWx0RWFzZSx0aGlzLl9lYXNlVHlwZT10aGlzLl9lYXNlLl90eXBlLHRoaXMuX2Vhc2VQb3dlcj10aGlzLl9lYXNlLl9wb3dlcix0aGlzLl9maXJzdFBUPW51bGwsdGhpcy5fdGFyZ2V0cylmb3IodD10aGlzLl90YXJnZXRzLmxlbmd0aDstLXQ+LTE7KXRoaXMuX2luaXRQcm9wcyh0aGlzLl90YXJnZXRzW3RdLHRoaXMuX3Byb3BMb29rdXBbdF09e30sdGhpcy5fc2libGluZ3NbdF0sYT9hW3RdOm51bGwpJiYoZT0hMCk7ZWxzZSBlPXRoaXMuX2luaXRQcm9wcyh0aGlzLnRhcmdldCx0aGlzLl9wcm9wTG9va3VwLHRoaXMuX3NpYmxpbmdzLGEpO2lmKGUmJkQuX29uUGx1Z2luRXZlbnQoXCJfb25Jbml0QWxsUHJvcHNcIix0aGlzKSxhJiYodGhpcy5fZmlyc3RQVHx8XCJmdW5jdGlvblwiIT10eXBlb2YgdGhpcy50YXJnZXQmJnRoaXMuX2VuYWJsZWQoITEsITEpKSxyLnJ1bkJhY2t3YXJkcylmb3IoaT10aGlzLl9maXJzdFBUO2k7KWkucys9aS5jLGkuYz0taS5jLGk9aS5fbmV4dDt0aGlzLl9vblVwZGF0ZT1yLm9uVXBkYXRlLHRoaXMuX2luaXR0ZWQ9ITB9LG4uX2luaXRQcm9wcz1mdW5jdGlvbihlLGkscyxuKXt2YXIgcixhLG8sbCxoLF87aWYobnVsbD09ZSlyZXR1cm4hMTtPW2UuX2dzVHdlZW5JRF0mJnEoKSx0aGlzLnZhcnMuY3NzfHxlLnN0eWxlJiZlIT09dCYmZS5ub2RlVHlwZSYmTC5jc3MmJnRoaXMudmFycy5hdXRvQ1NTIT09ITEmJkUodGhpcy52YXJzLGUpO2ZvcihyIGluIHRoaXMudmFycyl7aWYoXz10aGlzLnZhcnNbcl0saltyXSlfJiYoXyBpbnN0YW5jZW9mIEFycmF5fHxfLnB1c2gmJm0oXykpJiYtMSE9PV8uam9pbihcIlwiKS5pbmRleE9mKFwie3NlbGZ9XCIpJiYodGhpcy52YXJzW3JdPV89dGhpcy5fc3dhcFNlbGZJblBhcmFtcyhfLHRoaXMpKTtlbHNlIGlmKExbcl0mJihsPW5ldyBMW3JdKS5fb25Jbml0VHdlZW4oZSx0aGlzLnZhcnNbcl0sdGhpcykpe2Zvcih0aGlzLl9maXJzdFBUPWg9e19uZXh0OnRoaXMuX2ZpcnN0UFQsdDpsLHA6XCJzZXRSYXRpb1wiLHM6MCxjOjEsZjohMCxuOnIscGc6ITAscHI6bC5fcHJpb3JpdHl9LGE9bC5fb3ZlcndyaXRlUHJvcHMubGVuZ3RoOy0tYT4tMTspaVtsLl9vdmVyd3JpdGVQcm9wc1thXV09dGhpcy5fZmlyc3RQVDsobC5fcHJpb3JpdHl8fGwuX29uSW5pdEFsbFByb3BzKSYmKG89ITApLChsLl9vbkRpc2FibGV8fGwuX29uRW5hYmxlKSYmKHRoaXMuX25vdGlmeVBsdWdpbnNPZkVuYWJsZWQ9ITApfWVsc2UgdGhpcy5fZmlyc3RQVD1pW3JdPWg9e19uZXh0OnRoaXMuX2ZpcnN0UFQsdDplLHA6cixmOlwiZnVuY3Rpb25cIj09dHlwZW9mIGVbcl0sbjpyLHBnOiExLHByOjB9LGgucz1oLmY/ZVtyLmluZGV4T2YoXCJzZXRcIil8fFwiZnVuY3Rpb25cIiE9dHlwZW9mIGVbXCJnZXRcIityLnN1YnN0cigzKV0/cjpcImdldFwiK3Iuc3Vic3RyKDMpXSgpOnBhcnNlRmxvYXQoZVtyXSksaC5jPVwic3RyaW5nXCI9PXR5cGVvZiBfJiZcIj1cIj09PV8uY2hhckF0KDEpP3BhcnNlSW50KF8uY2hhckF0KDApK1wiMVwiLDEwKSpOdW1iZXIoXy5zdWJzdHIoMikpOk51bWJlcihfKS1oLnN8fDA7aCYmaC5fbmV4dCYmKGguX25leHQuX3ByZXY9aCl9cmV0dXJuIG4mJnRoaXMuX2tpbGwobixlKT90aGlzLl9pbml0UHJvcHMoZSxpLHMsbik6dGhpcy5fb3ZlcndyaXRlPjEmJnRoaXMuX2ZpcnN0UFQmJnMubGVuZ3RoPjEmJiQoZSx0aGlzLGksdGhpcy5fb3ZlcndyaXRlLHMpPyh0aGlzLl9raWxsKGksZSksdGhpcy5faW5pdFByb3BzKGUsaSxzLG4pKToodGhpcy5fZmlyc3RQVCYmKHRoaXMudmFycy5sYXp5IT09ITEmJnRoaXMuX2R1cmF0aW9ufHx0aGlzLnZhcnMubGF6eSYmIXRoaXMuX2R1cmF0aW9uKSYmKE9bZS5fZ3NUd2VlbklEXT0hMCksbyl9LG4ucmVuZGVyPWZ1bmN0aW9uKHQsZSxpKXt2YXIgcyxuLHIsYSxvPXRoaXMuX3RpbWUsbD10aGlzLl9kdXJhdGlvbixfPXRoaXMuX3Jhd1ByZXZUaW1lO2lmKHQ+PWwpdGhpcy5fdG90YWxUaW1lPXRoaXMuX3RpbWU9bCx0aGlzLnJhdGlvPXRoaXMuX2Vhc2UuX2NhbGNFbmQ/dGhpcy5fZWFzZS5nZXRSYXRpbygxKToxLHRoaXMuX3JldmVyc2VkfHwocz0hMCxuPVwib25Db21wbGV0ZVwiKSwwPT09bCYmKHRoaXMuX2luaXR0ZWR8fCF0aGlzLnZhcnMubGF6eXx8aSkmJih0aGlzLl9zdGFydFRpbWU9PT10aGlzLl90aW1lbGluZS5fZHVyYXRpb24mJih0PTApLCgwPT09dHx8MD5ffHxfPT09aCkmJl8hPT10JiYoaT0hMCxfPmgmJihuPVwib25SZXZlcnNlQ29tcGxldGVcIikpLHRoaXMuX3Jhd1ByZXZUaW1lPWE9IWV8fHR8fF89PT10P3Q6aCk7ZWxzZSBpZigxZS03PnQpdGhpcy5fdG90YWxUaW1lPXRoaXMuX3RpbWU9MCx0aGlzLnJhdGlvPXRoaXMuX2Vhc2UuX2NhbGNFbmQ/dGhpcy5fZWFzZS5nZXRSYXRpbygwKTowLCgwIT09b3x8MD09PWwmJl8+MCYmXyE9PWgpJiYobj1cIm9uUmV2ZXJzZUNvbXBsZXRlXCIscz10aGlzLl9yZXZlcnNlZCksMD50Pyh0aGlzLl9hY3RpdmU9ITEsMD09PWwmJih0aGlzLl9pbml0dGVkfHwhdGhpcy52YXJzLmxhenl8fGkpJiYoXz49MCYmKGk9ITApLHRoaXMuX3Jhd1ByZXZUaW1lPWE9IWV8fHR8fF89PT10P3Q6aCkpOnRoaXMuX2luaXR0ZWR8fChpPSEwKTtlbHNlIGlmKHRoaXMuX3RvdGFsVGltZT10aGlzLl90aW1lPXQsdGhpcy5fZWFzZVR5cGUpe3ZhciB1PXQvbCxtPXRoaXMuX2Vhc2VUeXBlLGY9dGhpcy5fZWFzZVBvd2VyOygxPT09bXx8Mz09PW0mJnU+PS41KSYmKHU9MS11KSwzPT09bSYmKHUqPTIpLDE9PT1mP3UqPXU6Mj09PWY/dSo9dSp1OjM9PT1mP3UqPXUqdSp1OjQ9PT1mJiYodSo9dSp1KnUqdSksdGhpcy5yYXRpbz0xPT09bT8xLXU6Mj09PW0/dTouNT50L2w/dS8yOjEtdS8yfWVsc2UgdGhpcy5yYXRpbz10aGlzLl9lYXNlLmdldFJhdGlvKHQvbCk7aWYodGhpcy5fdGltZSE9PW98fGkpe2lmKCF0aGlzLl9pbml0dGVkKXtpZih0aGlzLl9pbml0KCksIXRoaXMuX2luaXR0ZWR8fHRoaXMuX2djKXJldHVybjtpZighaSYmdGhpcy5fZmlyc3RQVCYmKHRoaXMudmFycy5sYXp5IT09ITEmJnRoaXMuX2R1cmF0aW9ufHx0aGlzLnZhcnMubGF6eSYmIXRoaXMuX2R1cmF0aW9uKSlyZXR1cm4gdGhpcy5fdGltZT10aGlzLl90b3RhbFRpbWU9byx0aGlzLl9yYXdQcmV2VGltZT1fLHoucHVzaCh0aGlzKSx0aGlzLl9sYXp5PXQsdm9pZCAwO3RoaXMuX3RpbWUmJiFzP3RoaXMucmF0aW89dGhpcy5fZWFzZS5nZXRSYXRpbyh0aGlzLl90aW1lL2wpOnMmJnRoaXMuX2Vhc2UuX2NhbGNFbmQmJih0aGlzLnJhdGlvPXRoaXMuX2Vhc2UuZ2V0UmF0aW8oMD09PXRoaXMuX3RpbWU/MDoxKSl9Zm9yKHRoaXMuX2xhenkhPT0hMSYmKHRoaXMuX2xhenk9ITEpLHRoaXMuX2FjdGl2ZXx8IXRoaXMuX3BhdXNlZCYmdGhpcy5fdGltZSE9PW8mJnQ+PTAmJih0aGlzLl9hY3RpdmU9ITApLDA9PT1vJiYodGhpcy5fc3RhcnRBdCYmKHQ+PTA/dGhpcy5fc3RhcnRBdC5yZW5kZXIodCxlLGkpOm58fChuPVwiX2R1bW15R1NcIikpLHRoaXMudmFycy5vblN0YXJ0JiYoMCE9PXRoaXMuX3RpbWV8fDA9PT1sKSYmKGV8fHRoaXMudmFycy5vblN0YXJ0LmFwcGx5KHRoaXMudmFycy5vblN0YXJ0U2NvcGV8fHRoaXMsdGhpcy52YXJzLm9uU3RhcnRQYXJhbXN8fGcpKSkscj10aGlzLl9maXJzdFBUO3I7KXIuZj9yLnRbci5wXShyLmMqdGhpcy5yYXRpbytyLnMpOnIudFtyLnBdPXIuYyp0aGlzLnJhdGlvK3IucyxyPXIuX25leHQ7dGhpcy5fb25VcGRhdGUmJigwPnQmJnRoaXMuX3N0YXJ0QXQmJnRoaXMuX3N0YXJ0VGltZSYmdGhpcy5fc3RhcnRBdC5yZW5kZXIodCxlLGkpLGV8fCh0aGlzLl90aW1lIT09b3x8cykmJnRoaXMuX29uVXBkYXRlLmFwcGx5KHRoaXMudmFycy5vblVwZGF0ZVNjb3BlfHx0aGlzLHRoaXMudmFycy5vblVwZGF0ZVBhcmFtc3x8ZykpLG4mJih0aGlzLl9nY3x8KDA+dCYmdGhpcy5fc3RhcnRBdCYmIXRoaXMuX29uVXBkYXRlJiZ0aGlzLl9zdGFydFRpbWUmJnRoaXMuX3N0YXJ0QXQucmVuZGVyKHQsZSxpKSxzJiYodGhpcy5fdGltZWxpbmUuYXV0b1JlbW92ZUNoaWxkcmVuJiZ0aGlzLl9lbmFibGVkKCExLCExKSx0aGlzLl9hY3RpdmU9ITEpLCFlJiZ0aGlzLnZhcnNbbl0mJnRoaXMudmFyc1tuXS5hcHBseSh0aGlzLnZhcnNbbitcIlNjb3BlXCJdfHx0aGlzLHRoaXMudmFyc1tuK1wiUGFyYW1zXCJdfHxnKSwwPT09bCYmdGhpcy5fcmF3UHJldlRpbWU9PT1oJiZhIT09aCYmKHRoaXMuX3Jhd1ByZXZUaW1lPTApKSl9fSxuLl9raWxsPWZ1bmN0aW9uKHQsZSl7aWYoXCJhbGxcIj09PXQmJih0PW51bGwpLG51bGw9PXQmJihudWxsPT1lfHxlPT09dGhpcy50YXJnZXQpKXJldHVybiB0aGlzLl9sYXp5PSExLHRoaXMuX2VuYWJsZWQoITEsITEpO2U9XCJzdHJpbmdcIiE9dHlwZW9mIGU/ZXx8dGhpcy5fdGFyZ2V0c3x8dGhpcy50YXJnZXQ6RC5zZWxlY3RvcihlKXx8ZTt2YXIgaSxzLG4scixhLG8sbCxoO2lmKChtKGUpfHxJKGUpKSYmXCJudW1iZXJcIiE9dHlwZW9mIGVbMF0pZm9yKGk9ZS5sZW5ndGg7LS1pPi0xOyl0aGlzLl9raWxsKHQsZVtpXSkmJihvPSEwKTtlbHNle2lmKHRoaXMuX3RhcmdldHMpe2ZvcihpPXRoaXMuX3RhcmdldHMubGVuZ3RoOy0taT4tMTspaWYoZT09PXRoaXMuX3RhcmdldHNbaV0pe2E9dGhpcy5fcHJvcExvb2t1cFtpXXx8e30sdGhpcy5fb3ZlcndyaXR0ZW5Qcm9wcz10aGlzLl9vdmVyd3JpdHRlblByb3BzfHxbXSxzPXRoaXMuX292ZXJ3cml0dGVuUHJvcHNbaV09dD90aGlzLl9vdmVyd3JpdHRlblByb3BzW2ldfHx7fTpcImFsbFwiO2JyZWFrfX1lbHNle2lmKGUhPT10aGlzLnRhcmdldClyZXR1cm4hMTthPXRoaXMuX3Byb3BMb29rdXAscz10aGlzLl9vdmVyd3JpdHRlblByb3BzPXQ/dGhpcy5fb3ZlcndyaXR0ZW5Qcm9wc3x8e306XCJhbGxcIn1pZihhKXtsPXR8fGEsaD10IT09cyYmXCJhbGxcIiE9PXMmJnQhPT1hJiYoXCJvYmplY3RcIiE9dHlwZW9mIHR8fCF0Ll90ZW1wS2lsbCk7Zm9yKG4gaW4gbCkocj1hW25dKSYmKHIucGcmJnIudC5fa2lsbChsKSYmKG89ITApLHIucGcmJjAhPT1yLnQuX292ZXJ3cml0ZVByb3BzLmxlbmd0aHx8KHIuX3ByZXY/ci5fcHJldi5fbmV4dD1yLl9uZXh0OnI9PT10aGlzLl9maXJzdFBUJiYodGhpcy5fZmlyc3RQVD1yLl9uZXh0KSxyLl9uZXh0JiYoci5fbmV4dC5fcHJldj1yLl9wcmV2KSxyLl9uZXh0PXIuX3ByZXY9bnVsbCksZGVsZXRlIGFbbl0pLGgmJihzW25dPTEpOyF0aGlzLl9maXJzdFBUJiZ0aGlzLl9pbml0dGVkJiZ0aGlzLl9lbmFibGVkKCExLCExKX19cmV0dXJuIG99LG4uaW52YWxpZGF0ZT1mdW5jdGlvbigpe3JldHVybiB0aGlzLl9ub3RpZnlQbHVnaW5zT2ZFbmFibGVkJiZELl9vblBsdWdpbkV2ZW50KFwiX29uRGlzYWJsZVwiLHRoaXMpLHRoaXMuX2ZpcnN0UFQ9bnVsbCx0aGlzLl9vdmVyd3JpdHRlblByb3BzPW51bGwsdGhpcy5fb25VcGRhdGU9bnVsbCx0aGlzLl9zdGFydEF0PW51bGwsdGhpcy5faW5pdHRlZD10aGlzLl9hY3RpdmU9dGhpcy5fbm90aWZ5UGx1Z2luc09mRW5hYmxlZD10aGlzLl9sYXp5PSExLHRoaXMuX3Byb3BMb29rdXA9dGhpcy5fdGFyZ2V0cz97fTpbXSx0aGlzfSxuLl9lbmFibGVkPWZ1bmN0aW9uKHQsZSl7aWYoYXx8ci53YWtlKCksdCYmdGhpcy5fZ2Mpe3ZhciBpLHM9dGhpcy5fdGFyZ2V0cztpZihzKWZvcihpPXMubGVuZ3RoOy0taT4tMTspdGhpcy5fc2libGluZ3NbaV09TShzW2ldLHRoaXMsITApO2Vsc2UgdGhpcy5fc2libGluZ3M9TSh0aGlzLnRhcmdldCx0aGlzLCEwKX1yZXR1cm4geC5wcm90b3R5cGUuX2VuYWJsZWQuY2FsbCh0aGlzLHQsZSksdGhpcy5fbm90aWZ5UGx1Z2luc09mRW5hYmxlZCYmdGhpcy5fZmlyc3RQVD9ELl9vblBsdWdpbkV2ZW50KHQ/XCJfb25FbmFibGVcIjpcIl9vbkRpc2FibGVcIix0aGlzKTohMX0sRC50bz1mdW5jdGlvbih0LGUsaSl7cmV0dXJuIG5ldyBEKHQsZSxpKX0sRC5mcm9tPWZ1bmN0aW9uKHQsZSxpKXtyZXR1cm4gaS5ydW5CYWNrd2FyZHM9ITAsaS5pbW1lZGlhdGVSZW5kZXI9MCE9aS5pbW1lZGlhdGVSZW5kZXIsbmV3IEQodCxlLGkpfSxELmZyb21Ubz1mdW5jdGlvbih0LGUsaSxzKXtyZXR1cm4gcy5zdGFydEF0PWkscy5pbW1lZGlhdGVSZW5kZXI9MCE9cy5pbW1lZGlhdGVSZW5kZXImJjAhPWkuaW1tZWRpYXRlUmVuZGVyLG5ldyBEKHQsZSxzKX0sRC5kZWxheWVkQ2FsbD1mdW5jdGlvbih0LGUsaSxzLG4pe3JldHVybiBuZXcgRChlLDAse2RlbGF5OnQsb25Db21wbGV0ZTplLG9uQ29tcGxldGVQYXJhbXM6aSxvbkNvbXBsZXRlU2NvcGU6cyxvblJldmVyc2VDb21wbGV0ZTplLG9uUmV2ZXJzZUNvbXBsZXRlUGFyYW1zOmksb25SZXZlcnNlQ29tcGxldGVTY29wZTpzLGltbWVkaWF0ZVJlbmRlcjohMSx1c2VGcmFtZXM6bixvdmVyd3JpdGU6MH0pfSxELnNldD1mdW5jdGlvbih0LGUpe3JldHVybiBuZXcgRCh0LDAsZSl9LEQuZ2V0VHdlZW5zT2Y9ZnVuY3Rpb24odCxlKXtpZihudWxsPT10KXJldHVybltdO3Q9XCJzdHJpbmdcIiE9dHlwZW9mIHQ/dDpELnNlbGVjdG9yKHQpfHx0O3ZhciBpLHMsbixyO2lmKChtKHQpfHxJKHQpKSYmXCJudW1iZXJcIiE9dHlwZW9mIHRbMF0pe2ZvcihpPXQubGVuZ3RoLHM9W107LS1pPi0xOylzPXMuY29uY2F0KEQuZ2V0VHdlZW5zT2YodFtpXSxlKSk7Zm9yKGk9cy5sZW5ndGg7LS1pPi0xOylmb3Iocj1zW2ldLG49aTstLW4+LTE7KXI9PT1zW25dJiZzLnNwbGljZShpLDEpfWVsc2UgZm9yKHM9TSh0KS5jb25jYXQoKSxpPXMubGVuZ3RoOy0taT4tMTspKHNbaV0uX2djfHxlJiYhc1tpXS5pc0FjdGl2ZSgpKSYmcy5zcGxpY2UoaSwxKTtyZXR1cm4gc30sRC5raWxsVHdlZW5zT2Y9RC5raWxsRGVsYXllZENhbGxzVG89ZnVuY3Rpb24odCxlLGkpe1wib2JqZWN0XCI9PXR5cGVvZiBlJiYoaT1lLGU9ITEpO2Zvcih2YXIgcz1ELmdldFR3ZWVuc09mKHQsZSksbj1zLmxlbmd0aDstLW4+LTE7KXNbbl0uX2tpbGwoaSx0KX07dmFyIEg9ZChcInBsdWdpbnMuVHdlZW5QbHVnaW5cIixmdW5jdGlvbih0LGUpe3RoaXMuX292ZXJ3cml0ZVByb3BzPSh0fHxcIlwiKS5zcGxpdChcIixcIiksdGhpcy5fcHJvcE5hbWU9dGhpcy5fb3ZlcndyaXRlUHJvcHNbMF0sdGhpcy5fcHJpb3JpdHk9ZXx8MCx0aGlzLl9zdXBlcj1ILnByb3RvdHlwZX0sITApO2lmKG49SC5wcm90b3R5cGUsSC52ZXJzaW9uPVwiMS4xMC4xXCIsSC5BUEk9MixuLl9maXJzdFBUPW51bGwsbi5fYWRkVHdlZW49ZnVuY3Rpb24odCxlLGkscyxuLHIpe3ZhciBhLG87cmV0dXJuIG51bGwhPXMmJihhPVwibnVtYmVyXCI9PXR5cGVvZiBzfHxcIj1cIiE9PXMuY2hhckF0KDEpP051bWJlcihzKS1pOnBhcnNlSW50KHMuY2hhckF0KDApK1wiMVwiLDEwKSpOdW1iZXIocy5zdWJzdHIoMikpKT8odGhpcy5fZmlyc3RQVD1vPXtfbmV4dDp0aGlzLl9maXJzdFBULHQ6dCxwOmUsczppLGM6YSxmOlwiZnVuY3Rpb25cIj09dHlwZW9mIHRbZV0sbjpufHxlLHI6cn0sby5fbmV4dCYmKG8uX25leHQuX3ByZXY9byksbyk6dm9pZCAwfSxuLnNldFJhdGlvPWZ1bmN0aW9uKHQpe2Zvcih2YXIgZSxpPXRoaXMuX2ZpcnN0UFQscz0xZS02O2k7KWU9aS5jKnQraS5zLGkucj9lPU1hdGgucm91bmQoZSk6cz5lJiZlPi1zJiYoZT0wKSxpLmY/aS50W2kucF0oZSk6aS50W2kucF09ZSxpPWkuX25leHR9LG4uX2tpbGw9ZnVuY3Rpb24odCl7dmFyIGUsaT10aGlzLl9vdmVyd3JpdGVQcm9wcyxzPXRoaXMuX2ZpcnN0UFQ7aWYobnVsbCE9dFt0aGlzLl9wcm9wTmFtZV0pdGhpcy5fb3ZlcndyaXRlUHJvcHM9W107ZWxzZSBmb3IoZT1pLmxlbmd0aDstLWU+LTE7KW51bGwhPXRbaVtlXV0mJmkuc3BsaWNlKGUsMSk7Zm9yKDtzOyludWxsIT10W3Mubl0mJihzLl9uZXh0JiYocy5fbmV4dC5fcHJldj1zLl9wcmV2KSxzLl9wcmV2PyhzLl9wcmV2Ll9uZXh0PXMuX25leHQscy5fcHJldj1udWxsKTp0aGlzLl9maXJzdFBUPT09cyYmKHRoaXMuX2ZpcnN0UFQ9cy5fbmV4dCkpLHM9cy5fbmV4dDtyZXR1cm4hMX0sbi5fcm91bmRQcm9wcz1mdW5jdGlvbih0LGUpe2Zvcih2YXIgaT10aGlzLl9maXJzdFBUO2k7KSh0W3RoaXMuX3Byb3BOYW1lXXx8bnVsbCE9aS5uJiZ0W2kubi5zcGxpdCh0aGlzLl9wcm9wTmFtZStcIl9cIikuam9pbihcIlwiKV0pJiYoaS5yPWUpLGk9aS5fbmV4dH0sRC5fb25QbHVnaW5FdmVudD1mdW5jdGlvbih0LGUpe3ZhciBpLHMsbixyLGEsbz1lLl9maXJzdFBUO2lmKFwiX29uSW5pdEFsbFByb3BzXCI9PT10KXtmb3IoO287KXtmb3IoYT1vLl9uZXh0LHM9bjtzJiZzLnByPm8ucHI7KXM9cy5fbmV4dDsoby5fcHJldj1zP3MuX3ByZXY6cik/by5fcHJldi5fbmV4dD1vOm49bywoby5fbmV4dD1zKT9zLl9wcmV2PW86cj1vLG89YX1vPWUuX2ZpcnN0UFQ9bn1mb3IoO287KW8ucGcmJlwiZnVuY3Rpb25cIj09dHlwZW9mIG8udFt0XSYmby50W3RdKCkmJihpPSEwKSxvPW8uX25leHQ7cmV0dXJuIGl9LEguYWN0aXZhdGU9ZnVuY3Rpb24odCl7Zm9yKHZhciBlPXQubGVuZ3RoOy0tZT4tMTspdFtlXS5BUEk9PT1ILkFQSSYmKExbKG5ldyB0W2VdKS5fcHJvcE5hbWVdPXRbZV0pO3JldHVybiEwfSxjLnBsdWdpbj1mdW5jdGlvbih0KXtpZighKHQmJnQucHJvcE5hbWUmJnQuaW5pdCYmdC5BUEkpKXRocm93XCJpbGxlZ2FsIHBsdWdpbiBkZWZpbml0aW9uLlwiO3ZhciBlLGk9dC5wcm9wTmFtZSxzPXQucHJpb3JpdHl8fDAsbj10Lm92ZXJ3cml0ZVByb3BzLHI9e2luaXQ6XCJfb25Jbml0VHdlZW5cIixzZXQ6XCJzZXRSYXRpb1wiLGtpbGw6XCJfa2lsbFwiLHJvdW5kOlwiX3JvdW5kUHJvcHNcIixpbml0QWxsOlwiX29uSW5pdEFsbFByb3BzXCJ9LGE9ZChcInBsdWdpbnMuXCIraS5jaGFyQXQoMCkudG9VcHBlckNhc2UoKStpLnN1YnN0cigxKStcIlBsdWdpblwiLGZ1bmN0aW9uKCl7SC5jYWxsKHRoaXMsaSxzKSx0aGlzLl9vdmVyd3JpdGVQcm9wcz1ufHxbXX0sdC5nbG9iYWw9PT0hMCksbz1hLnByb3RvdHlwZT1uZXcgSChpKTtvLmNvbnN0cnVjdG9yPWEsYS5BUEk9dC5BUEk7Zm9yKGUgaW4gcilcImZ1bmN0aW9uXCI9PXR5cGVvZiB0W2VdJiYob1tyW2VdXT10W2VdKTtyZXR1cm4gYS52ZXJzaW9uPXQudmVyc2lvbixILmFjdGl2YXRlKFthXSksYX0saT10Ll9nc1F1ZXVlKXtmb3Iocz0wO2kubGVuZ3RoPnM7cysrKWlbc10oKTtmb3IobiBpbiBmKWZbbl0uZnVuY3x8dC5jb25zb2xlLmxvZyhcIkdTQVAgZW5jb3VudGVyZWQgbWlzc2luZyBkZXBlbmRlbmN5OiBjb20uZ3JlZW5zb2NrLlwiK24pfWE9ITF9fSkod2luZG93KTsiLCIvKiFcclxuICogVkVSU0lPTjogYmV0YSAxLjkuM1xyXG4gKiBEQVRFOiAyMDEzLTA0LTAyXHJcbiAqIFVQREFURVMgQU5EIERPQ1MgQVQ6IGh0dHA6Ly93d3cuZ3JlZW5zb2NrLmNvbVxyXG4gKlxyXG4gKiBAbGljZW5zZSBDb3B5cmlnaHQgKGMpIDIwMDgtMjAxNCwgR3JlZW5Tb2NrLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxyXG4gKiBUaGlzIHdvcmsgaXMgc3ViamVjdCB0byB0aGUgdGVybXMgYXQgaHR0cDovL3d3dy5ncmVlbnNvY2suY29tL3Rlcm1zX29mX3VzZS5odG1sIG9yIGZvclxyXG4gKiBDbHViIEdyZWVuU29jayBtZW1iZXJzLCB0aGUgc29mdHdhcmUgYWdyZWVtZW50IHRoYXQgd2FzIGlzc3VlZCB3aXRoIHlvdXIgbWVtYmVyc2hpcC5cclxuICogXHJcbiAqIEBhdXRob3I6IEphY2sgRG95bGUsIGphY2tAZ3JlZW5zb2NrLmNvbVxyXG4gKiovXHJcbih3aW5kb3cuX2dzUXVldWV8fCh3aW5kb3cuX2dzUXVldWU9W10pKS5wdXNoKGZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7d2luZG93Ll9nc0RlZmluZShcImVhc2luZy5CYWNrXCIsW1wiZWFzaW5nLkVhc2VcIl0sZnVuY3Rpb24odCl7dmFyIGUsaSxzLHI9d2luZG93LkdyZWVuU29ja0dsb2JhbHN8fHdpbmRvdyxuPXIuY29tLmdyZWVuc29jayxhPTIqTWF0aC5QSSxvPU1hdGguUEkvMixoPW4uX2NsYXNzLGw9ZnVuY3Rpb24oZSxpKXt2YXIgcz1oKFwiZWFzaW5nLlwiK2UsZnVuY3Rpb24oKXt9LCEwKSxyPXMucHJvdG90eXBlPW5ldyB0O3JldHVybiByLmNvbnN0cnVjdG9yPXMsci5nZXRSYXRpbz1pLHN9LF89dC5yZWdpc3Rlcnx8ZnVuY3Rpb24oKXt9LHU9ZnVuY3Rpb24odCxlLGkscyl7dmFyIHI9aChcImVhc2luZy5cIit0LHtlYXNlT3V0Om5ldyBlLGVhc2VJbjpuZXcgaSxlYXNlSW5PdXQ6bmV3IHN9LCEwKTtyZXR1cm4gXyhyLHQpLHJ9LGM9ZnVuY3Rpb24odCxlLGkpe3RoaXMudD10LHRoaXMudj1lLGkmJih0aGlzLm5leHQ9aSxpLnByZXY9dGhpcyx0aGlzLmM9aS52LWUsdGhpcy5nYXA9aS50LXQpfSxmPWZ1bmN0aW9uKGUsaSl7dmFyIHM9aChcImVhc2luZy5cIitlLGZ1bmN0aW9uKHQpe3RoaXMuX3AxPXR8fDA9PT10P3Q6MS43MDE1OCx0aGlzLl9wMj0xLjUyNSp0aGlzLl9wMX0sITApLHI9cy5wcm90b3R5cGU9bmV3IHQ7cmV0dXJuIHIuY29uc3RydWN0b3I9cyxyLmdldFJhdGlvPWksci5jb25maWc9ZnVuY3Rpb24odCl7cmV0dXJuIG5ldyBzKHQpfSxzfSxwPXUoXCJCYWNrXCIsZihcIkJhY2tPdXRcIixmdW5jdGlvbih0KXtyZXR1cm4odC09MSkqdCooKHRoaXMuX3AxKzEpKnQrdGhpcy5fcDEpKzF9KSxmKFwiQmFja0luXCIsZnVuY3Rpb24odCl7cmV0dXJuIHQqdCooKHRoaXMuX3AxKzEpKnQtdGhpcy5fcDEpfSksZihcIkJhY2tJbk91dFwiLGZ1bmN0aW9uKHQpe3JldHVybiAxPih0Kj0yKT8uNSp0KnQqKCh0aGlzLl9wMisxKSp0LXRoaXMuX3AyKTouNSooKHQtPTIpKnQqKCh0aGlzLl9wMisxKSp0K3RoaXMuX3AyKSsyKX0pKSxtPWgoXCJlYXNpbmcuU2xvd01vXCIsZnVuY3Rpb24odCxlLGkpe2U9ZXx8MD09PWU/ZTouNyxudWxsPT10P3Q9Ljc6dD4xJiYodD0xKSx0aGlzLl9wPTEhPT10P2U6MCx0aGlzLl9wMT0oMS10KS8yLHRoaXMuX3AyPXQsdGhpcy5fcDM9dGhpcy5fcDErdGhpcy5fcDIsdGhpcy5fY2FsY0VuZD1pPT09ITB9LCEwKSxkPW0ucHJvdG90eXBlPW5ldyB0O3JldHVybiBkLmNvbnN0cnVjdG9yPW0sZC5nZXRSYXRpbz1mdW5jdGlvbih0KXt2YXIgZT10KyguNS10KSp0aGlzLl9wO3JldHVybiB0aGlzLl9wMT50P3RoaXMuX2NhbGNFbmQ/MS0odD0xLXQvdGhpcy5fcDEpKnQ6ZS0odD0xLXQvdGhpcy5fcDEpKnQqdCp0KmU6dD50aGlzLl9wMz90aGlzLl9jYWxjRW5kPzEtKHQ9KHQtdGhpcy5fcDMpL3RoaXMuX3AxKSp0OmUrKHQtZSkqKHQ9KHQtdGhpcy5fcDMpL3RoaXMuX3AxKSp0KnQqdDp0aGlzLl9jYWxjRW5kPzE6ZX0sbS5lYXNlPW5ldyBtKC43LC43KSxkLmNvbmZpZz1tLmNvbmZpZz1mdW5jdGlvbih0LGUsaSl7cmV0dXJuIG5ldyBtKHQsZSxpKX0sZT1oKFwiZWFzaW5nLlN0ZXBwZWRFYXNlXCIsZnVuY3Rpb24odCl7dD10fHwxLHRoaXMuX3AxPTEvdCx0aGlzLl9wMj10KzF9LCEwKSxkPWUucHJvdG90eXBlPW5ldyB0LGQuY29uc3RydWN0b3I9ZSxkLmdldFJhdGlvPWZ1bmN0aW9uKHQpe3JldHVybiAwPnQ/dD0wOnQ+PTEmJih0PS45OTk5OTk5OTkpLCh0aGlzLl9wMip0Pj4wKSp0aGlzLl9wMX0sZC5jb25maWc9ZS5jb25maWc9ZnVuY3Rpb24odCl7cmV0dXJuIG5ldyBlKHQpfSxpPWgoXCJlYXNpbmcuUm91Z2hFYXNlXCIsZnVuY3Rpb24oZSl7ZT1lfHx7fTtmb3IodmFyIGkscyxyLG4sYSxvLGg9ZS50YXBlcnx8XCJub25lXCIsbD1bXSxfPTAsdT0wfChlLnBvaW50c3x8MjApLGY9dSxwPWUucmFuZG9taXplIT09ITEsbT1lLmNsYW1wPT09ITAsZD1lLnRlbXBsYXRlIGluc3RhbmNlb2YgdD9lLnRlbXBsYXRlOm51bGwsZz1cIm51bWJlclwiPT10eXBlb2YgZS5zdHJlbmd0aD8uNCplLnN0cmVuZ3RoOi40Oy0tZj4tMTspaT1wP01hdGgucmFuZG9tKCk6MS91KmYscz1kP2QuZ2V0UmF0aW8oaSk6aSxcIm5vbmVcIj09PWg/cj1nOlwib3V0XCI9PT1oPyhuPTEtaSxyPW4qbipnKTpcImluXCI9PT1oP3I9aSppKmc6LjU+aT8obj0yKmkscj0uNSpuKm4qZyk6KG49MiooMS1pKSxyPS41Km4qbipnKSxwP3MrPU1hdGgucmFuZG9tKCkqci0uNSpyOmYlMj9zKz0uNSpyOnMtPS41KnIsbSYmKHM+MT9zPTE6MD5zJiYocz0wKSksbFtfKytdPXt4OmkseTpzfTtmb3IobC5zb3J0KGZ1bmN0aW9uKHQsZSl7cmV0dXJuIHQueC1lLnh9KSxvPW5ldyBjKDEsMSxudWxsKSxmPXU7LS1mPi0xOylhPWxbZl0sbz1uZXcgYyhhLngsYS55LG8pO3RoaXMuX3ByZXY9bmV3IGMoMCwwLDAhPT1vLnQ/bzpvLm5leHQpfSwhMCksZD1pLnByb3RvdHlwZT1uZXcgdCxkLmNvbnN0cnVjdG9yPWksZC5nZXRSYXRpbz1mdW5jdGlvbih0KXt2YXIgZT10aGlzLl9wcmV2O2lmKHQ+ZS50KXtmb3IoO2UubmV4dCYmdD49ZS50OyllPWUubmV4dDtlPWUucHJldn1lbHNlIGZvcig7ZS5wcmV2JiZlLnQ+PXQ7KWU9ZS5wcmV2O3JldHVybiB0aGlzLl9wcmV2PWUsZS52Kyh0LWUudCkvZS5nYXAqZS5jfSxkLmNvbmZpZz1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IGkodCl9LGkuZWFzZT1uZXcgaSx1KFwiQm91bmNlXCIsbChcIkJvdW5jZU91dFwiLGZ1bmN0aW9uKHQpe3JldHVybiAxLzIuNzU+dD83LjU2MjUqdCp0OjIvMi43NT50PzcuNTYyNSoodC09MS41LzIuNzUpKnQrLjc1OjIuNS8yLjc1PnQ/Ny41NjI1Kih0LT0yLjI1LzIuNzUpKnQrLjkzNzU6Ny41NjI1Kih0LT0yLjYyNS8yLjc1KSp0Ky45ODQzNzV9KSxsKFwiQm91bmNlSW5cIixmdW5jdGlvbih0KXtyZXR1cm4gMS8yLjc1Pih0PTEtdCk/MS03LjU2MjUqdCp0OjIvMi43NT50PzEtKDcuNTYyNSoodC09MS41LzIuNzUpKnQrLjc1KToyLjUvMi43NT50PzEtKDcuNTYyNSoodC09Mi4yNS8yLjc1KSp0Ky45Mzc1KToxLSg3LjU2MjUqKHQtPTIuNjI1LzIuNzUpKnQrLjk4NDM3NSl9KSxsKFwiQm91bmNlSW5PdXRcIixmdW5jdGlvbih0KXt2YXIgZT0uNT50O3JldHVybiB0PWU/MS0yKnQ6Mip0LTEsdD0xLzIuNzU+dD83LjU2MjUqdCp0OjIvMi43NT50PzcuNTYyNSoodC09MS41LzIuNzUpKnQrLjc1OjIuNS8yLjc1PnQ/Ny41NjI1Kih0LT0yLjI1LzIuNzUpKnQrLjkzNzU6Ny41NjI1Kih0LT0yLjYyNS8yLjc1KSp0Ky45ODQzNzUsZT8uNSooMS10KTouNSp0Ky41fSkpLHUoXCJDaXJjXCIsbChcIkNpcmNPdXRcIixmdW5jdGlvbih0KXtyZXR1cm4gTWF0aC5zcXJ0KDEtKHQtPTEpKnQpfSksbChcIkNpcmNJblwiLGZ1bmN0aW9uKHQpe3JldHVybi0oTWF0aC5zcXJ0KDEtdCp0KS0xKX0pLGwoXCJDaXJjSW5PdXRcIixmdW5jdGlvbih0KXtyZXR1cm4gMT4odCo9Mik/LS41KihNYXRoLnNxcnQoMS10KnQpLTEpOi41KihNYXRoLnNxcnQoMS0odC09MikqdCkrMSl9KSkscz1mdW5jdGlvbihlLGkscyl7dmFyIHI9aChcImVhc2luZy5cIitlLGZ1bmN0aW9uKHQsZSl7dGhpcy5fcDE9dHx8MSx0aGlzLl9wMj1lfHxzLHRoaXMuX3AzPXRoaXMuX3AyL2EqKE1hdGguYXNpbigxL3RoaXMuX3AxKXx8MCl9LCEwKSxuPXIucHJvdG90eXBlPW5ldyB0O3JldHVybiBuLmNvbnN0cnVjdG9yPXIsbi5nZXRSYXRpbz1pLG4uY29uZmlnPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIG5ldyByKHQsZSl9LHJ9LHUoXCJFbGFzdGljXCIscyhcIkVsYXN0aWNPdXRcIixmdW5jdGlvbih0KXtyZXR1cm4gdGhpcy5fcDEqTWF0aC5wb3coMiwtMTAqdCkqTWF0aC5zaW4oKHQtdGhpcy5fcDMpKmEvdGhpcy5fcDIpKzF9LC4zKSxzKFwiRWxhc3RpY0luXCIsZnVuY3Rpb24odCl7cmV0dXJuLSh0aGlzLl9wMSpNYXRoLnBvdygyLDEwKih0LT0xKSkqTWF0aC5zaW4oKHQtdGhpcy5fcDMpKmEvdGhpcy5fcDIpKX0sLjMpLHMoXCJFbGFzdGljSW5PdXRcIixmdW5jdGlvbih0KXtyZXR1cm4gMT4odCo9Mik/LS41KnRoaXMuX3AxKk1hdGgucG93KDIsMTAqKHQtPTEpKSpNYXRoLnNpbigodC10aGlzLl9wMykqYS90aGlzLl9wMik6LjUqdGhpcy5fcDEqTWF0aC5wb3coMiwtMTAqKHQtPTEpKSpNYXRoLnNpbigodC10aGlzLl9wMykqYS90aGlzLl9wMikrMX0sLjQ1KSksdShcIkV4cG9cIixsKFwiRXhwb091dFwiLGZ1bmN0aW9uKHQpe3JldHVybiAxLU1hdGgucG93KDIsLTEwKnQpfSksbChcIkV4cG9JblwiLGZ1bmN0aW9uKHQpe3JldHVybiBNYXRoLnBvdygyLDEwKih0LTEpKS0uMDAxfSksbChcIkV4cG9Jbk91dFwiLGZ1bmN0aW9uKHQpe3JldHVybiAxPih0Kj0yKT8uNSpNYXRoLnBvdygyLDEwKih0LTEpKTouNSooMi1NYXRoLnBvdygyLC0xMCoodC0xKSkpfSkpLHUoXCJTaW5lXCIsbChcIlNpbmVPdXRcIixmdW5jdGlvbih0KXtyZXR1cm4gTWF0aC5zaW4odCpvKX0pLGwoXCJTaW5lSW5cIixmdW5jdGlvbih0KXtyZXR1cm4tTWF0aC5jb3ModCpvKSsxfSksbChcIlNpbmVJbk91dFwiLGZ1bmN0aW9uKHQpe3JldHVybi0uNSooTWF0aC5jb3MoTWF0aC5QSSp0KS0xKX0pKSxoKFwiZWFzaW5nLkVhc2VMb29rdXBcIix7ZmluZDpmdW5jdGlvbihlKXtyZXR1cm4gdC5tYXBbZV19fSwhMCksXyhyLlNsb3dNbyxcIlNsb3dNb1wiLFwiZWFzZSxcIiksXyhpLFwiUm91Z2hFYXNlXCIsXCJlYXNlLFwiKSxfKGUsXCJTdGVwcGVkRWFzZVwiLFwiZWFzZSxcIikscH0sITApfSksd2luZG93Ll9nc0RlZmluZSYmd2luZG93Ll9nc1F1ZXVlLnBvcCgpKCk7IiwiLyohXHJcbiAqIFZFUlNJT046IDEuMTIuMVxyXG4gKiBEQVRFOiAyMDE0LTA2LTI2XHJcbiAqIFVQREFURVMgQU5EIERPQ1MgQVQ6IGh0dHA6Ly93d3cuZ3JlZW5zb2NrLmNvbVxyXG4gKlxyXG4gKiBAbGljZW5zZSBDb3B5cmlnaHQgKGMpIDIwMDgtMjAxNCwgR3JlZW5Tb2NrLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxyXG4gKiBUaGlzIHdvcmsgaXMgc3ViamVjdCB0byB0aGUgdGVybXMgYXQgaHR0cDovL3d3dy5ncmVlbnNvY2suY29tL3Rlcm1zX29mX3VzZS5odG1sIG9yIGZvclxyXG4gKiBDbHViIEdyZWVuU29jayBtZW1iZXJzLCB0aGUgc29mdHdhcmUgYWdyZWVtZW50IHRoYXQgd2FzIGlzc3VlZCB3aXRoIHlvdXIgbWVtYmVyc2hpcC5cclxuICogXHJcbiAqIEBhdXRob3I6IEphY2sgRG95bGUsIGphY2tAZ3JlZW5zb2NrLmNvbVxyXG4gKi9cclxuKHdpbmRvdy5fZ3NRdWV1ZXx8KHdpbmRvdy5fZ3NRdWV1ZT1bXSkpLnB1c2goZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt3aW5kb3cuX2dzRGVmaW5lKFwicGx1Z2lucy5DU1NQbHVnaW5cIixbXCJwbHVnaW5zLlR3ZWVuUGx1Z2luXCIsXCJUd2VlbkxpdGVcIl0sZnVuY3Rpb24odCxlKXt2YXIgaSxyLHMsbixhPWZ1bmN0aW9uKCl7dC5jYWxsKHRoaXMsXCJjc3NcIiksdGhpcy5fb3ZlcndyaXRlUHJvcHMubGVuZ3RoPTAsdGhpcy5zZXRSYXRpbz1hLnByb3RvdHlwZS5zZXRSYXRpb30sbz17fSxsPWEucHJvdG90eXBlPW5ldyB0KFwiY3NzXCIpO2wuY29uc3RydWN0b3I9YSxhLnZlcnNpb249XCIxLjEyLjFcIixhLkFQST0yLGEuZGVmYXVsdFRyYW5zZm9ybVBlcnNwZWN0aXZlPTAsYS5kZWZhdWx0U2tld1R5cGU9XCJjb21wZW5zYXRlZFwiLGw9XCJweFwiLGEuc3VmZml4TWFwPXt0b3A6bCxyaWdodDpsLGJvdHRvbTpsLGxlZnQ6bCx3aWR0aDpsLGhlaWdodDpsLGZvbnRTaXplOmwscGFkZGluZzpsLG1hcmdpbjpsLHBlcnNwZWN0aXZlOmwsbGluZUhlaWdodDpcIlwifTt2YXIgaCx1LGYsXyxwLGMsZD0vKD86XFxkfFxcLVxcZHxcXC5cXGR8XFwtXFwuXFxkKSsvZyxtPS8oPzpcXGR8XFwtXFxkfFxcLlxcZHxcXC1cXC5cXGR8XFwrPVxcZHxcXC09XFxkfFxcKz0uXFxkfFxcLT1cXC5cXGQpKy9nLGc9Lyg/OlxcKz18XFwtPXxcXC18XFxiKVtcXGRcXC1cXC5dK1thLXpBLVowLTldKig/OiV8XFxiKS9naSx2PS9bXlxcZFxcLVxcLl0vZyx5PS8oPzpcXGR8XFwtfFxcK3w9fCN8XFwuKSovZyxUPS9vcGFjaXR5ICo9ICooW14pXSopL2ksdz0vb3BhY2l0eTooW147XSopL2kseD0vYWxwaGFcXChvcGFjaXR5ICo9Lis/XFwpL2ksYj0vXihyZ2J8aHNsKS8sUD0vKFtBLVpdKS9nLFM9Ly0oW2Etel0pL2dpLEM9LyheKD86dXJsXFwoXFxcInx1cmxcXCgpKXwoPzooXFxcIlxcKSkkfFxcKSQpL2dpLFI9ZnVuY3Rpb24odCxlKXtyZXR1cm4gZS50b1VwcGVyQ2FzZSgpfSxrPS8oPzpMZWZ0fFJpZ2h0fFdpZHRoKS9pLEE9LyhNMTF8TTEyfE0yMXxNMjIpPVtcXGRcXC1cXC5lXSsvZ2ksTz0vcHJvZ2lkXFw6RFhJbWFnZVRyYW5zZm9ybVxcLk1pY3Jvc29mdFxcLk1hdHJpeFxcKC4rP1xcKS9pLEQ9LywoPz1bXlxcKV0qKD86XFwofCQpKS9naSxNPU1hdGguUEkvMTgwLEw9MTgwL01hdGguUEksTj17fSxYPWRvY3VtZW50LHo9WC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpLEk9WC5jcmVhdGVFbGVtZW50KFwiaW1nXCIpLEU9YS5faW50ZXJuYWxzPXtfc3BlY2lhbFByb3BzOm99LEY9bmF2aWdhdG9yLnVzZXJBZ2VudCxZPWZ1bmN0aW9uKCl7dmFyIHQsZT1GLmluZGV4T2YoXCJBbmRyb2lkXCIpLGk9WC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO3JldHVybiBmPS0xIT09Ri5pbmRleE9mKFwiU2FmYXJpXCIpJiYtMT09PUYuaW5kZXhPZihcIkNocm9tZVwiKSYmKC0xPT09ZXx8TnVtYmVyKEYuc3Vic3RyKGUrOCwxKSk+MykscD1mJiY2Pk51bWJlcihGLnN1YnN0cihGLmluZGV4T2YoXCJWZXJzaW9uL1wiKSs4LDEpKSxfPS0xIT09Ri5pbmRleE9mKFwiRmlyZWZveFwiKSwvTVNJRSAoWzAtOV17MSx9W1xcLjAtOV17MCx9KS8uZXhlYyhGKSYmKGM9cGFyc2VGbG9hdChSZWdFeHAuJDEpKSxpLmlubmVySFRNTD1cIjxhIHN0eWxlPSd0b3A6MXB4O29wYWNpdHk6LjU1Oyc+YTwvYT5cIix0PWkuZ2V0RWxlbWVudHNCeVRhZ05hbWUoXCJhXCIpWzBdLHQ/L14wLjU1Ly50ZXN0KHQuc3R5bGUub3BhY2l0eSk6ITF9KCksQj1mdW5jdGlvbih0KXtyZXR1cm4gVC50ZXN0KFwic3RyaW5nXCI9PXR5cGVvZiB0P3Q6KHQuY3VycmVudFN0eWxlP3QuY3VycmVudFN0eWxlLmZpbHRlcjp0LnN0eWxlLmZpbHRlcil8fFwiXCIpP3BhcnNlRmxvYXQoUmVnRXhwLiQxKS8xMDA6MX0sVT1mdW5jdGlvbih0KXt3aW5kb3cuY29uc29sZSYmY29uc29sZS5sb2codCl9LFc9XCJcIixqPVwiXCIsVj1mdW5jdGlvbih0LGUpe2U9ZXx8ejt2YXIgaSxyLHM9ZS5zdHlsZTtpZih2b2lkIDAhPT1zW3RdKXJldHVybiB0O2Zvcih0PXQuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkrdC5zdWJzdHIoMSksaT1bXCJPXCIsXCJNb3pcIixcIm1zXCIsXCJNc1wiLFwiV2Via2l0XCJdLHI9NTstLXI+LTEmJnZvaWQgMD09PXNbaVtyXSt0XTspO3JldHVybiByPj0wPyhqPTM9PT1yP1wibXNcIjppW3JdLFc9XCItXCIrai50b0xvd2VyQ2FzZSgpK1wiLVwiLGordCk6bnVsbH0sSD1YLmRlZmF1bHRWaWV3P1guZGVmYXVsdFZpZXcuZ2V0Q29tcHV0ZWRTdHlsZTpmdW5jdGlvbigpe30scT1hLmdldFN0eWxlPWZ1bmN0aW9uKHQsZSxpLHIscyl7dmFyIG47cmV0dXJuIFl8fFwib3BhY2l0eVwiIT09ZT8oIXImJnQuc3R5bGVbZV0/bj10LnN0eWxlW2VdOihpPWl8fEgodCkpP249aVtlXXx8aS5nZXRQcm9wZXJ0eVZhbHVlKGUpfHxpLmdldFByb3BlcnR5VmFsdWUoZS5yZXBsYWNlKFAsXCItJDFcIikudG9Mb3dlckNhc2UoKSk6dC5jdXJyZW50U3R5bGUmJihuPXQuY3VycmVudFN0eWxlW2VdKSxudWxsPT1zfHxuJiZcIm5vbmVcIiE9PW4mJlwiYXV0b1wiIT09biYmXCJhdXRvIGF1dG9cIiE9PW4/bjpzKTpCKHQpfSxRPUUuY29udmVydFRvUGl4ZWxzPWZ1bmN0aW9uKHQsaSxyLHMsbil7aWYoXCJweFwiPT09c3x8IXMpcmV0dXJuIHI7aWYoXCJhdXRvXCI9PT1zfHwhcilyZXR1cm4gMDt2YXIgbyxsLGgsdT1rLnRlc3QoaSksZj10LF89ei5zdHlsZSxwPTA+cjtpZihwJiYocj0tciksXCIlXCI9PT1zJiYtMSE9PWkuaW5kZXhPZihcImJvcmRlclwiKSlvPXIvMTAwKih1P3QuY2xpZW50V2lkdGg6dC5jbGllbnRIZWlnaHQpO2Vsc2V7aWYoXy5jc3NUZXh0PVwiYm9yZGVyOjAgc29saWQgcmVkO3Bvc2l0aW9uOlwiK3EodCxcInBvc2l0aW9uXCIpK1wiO2xpbmUtaGVpZ2h0OjA7XCIsXCIlXCIhPT1zJiZmLmFwcGVuZENoaWxkKV9bdT9cImJvcmRlckxlZnRXaWR0aFwiOlwiYm9yZGVyVG9wV2lkdGhcIl09citzO2Vsc2V7aWYoZj10LnBhcmVudE5vZGV8fFguYm9keSxsPWYuX2dzQ2FjaGUsaD1lLnRpY2tlci5mcmFtZSxsJiZ1JiZsLnRpbWU9PT1oKXJldHVybiBsLndpZHRoKnIvMTAwO19bdT9cIndpZHRoXCI6XCJoZWlnaHRcIl09citzfWYuYXBwZW5kQ2hpbGQoeiksbz1wYXJzZUZsb2F0KHpbdT9cIm9mZnNldFdpZHRoXCI6XCJvZmZzZXRIZWlnaHRcIl0pLGYucmVtb3ZlQ2hpbGQoeiksdSYmXCIlXCI9PT1zJiZhLmNhY2hlV2lkdGhzIT09ITEmJihsPWYuX2dzQ2FjaGU9Zi5fZ3NDYWNoZXx8e30sbC50aW1lPWgsbC53aWR0aD0xMDAqKG8vcikpLDAhPT1vfHxufHwobz1RKHQsaSxyLHMsITApKX1yZXR1cm4gcD8tbzpvfSxaPUUuY2FsY3VsYXRlT2Zmc2V0PWZ1bmN0aW9uKHQsZSxpKXtpZihcImFic29sdXRlXCIhPT1xKHQsXCJwb3NpdGlvblwiLGkpKXJldHVybiAwO3ZhciByPVwibGVmdFwiPT09ZT9cIkxlZnRcIjpcIlRvcFwiLHM9cSh0LFwibWFyZ2luXCIrcixpKTtyZXR1cm4gdFtcIm9mZnNldFwiK3JdLShRKHQsZSxwYXJzZUZsb2F0KHMpLHMucmVwbGFjZSh5LFwiXCIpKXx8MCl9LCQ9ZnVuY3Rpb24odCxlKXt2YXIgaSxyLHM9e307aWYoZT1lfHxIKHQsbnVsbCkpaWYoaT1lLmxlbmd0aClmb3IoOy0taT4tMTspc1tlW2ldLnJlcGxhY2UoUyxSKV09ZS5nZXRQcm9wZXJ0eVZhbHVlKGVbaV0pO2Vsc2UgZm9yKGkgaW4gZSlzW2ldPWVbaV07ZWxzZSBpZihlPXQuY3VycmVudFN0eWxlfHx0LnN0eWxlKWZvcihpIGluIGUpXCJzdHJpbmdcIj09dHlwZW9mIGkmJnZvaWQgMD09PXNbaV0mJihzW2kucmVwbGFjZShTLFIpXT1lW2ldKTtyZXR1cm4gWXx8KHMub3BhY2l0eT1CKHQpKSxyPVBlKHQsZSwhMSkscy5yb3RhdGlvbj1yLnJvdGF0aW9uLHMuc2tld1g9ci5za2V3WCxzLnNjYWxlWD1yLnNjYWxlWCxzLnNjYWxlWT1yLnNjYWxlWSxzLng9ci54LHMueT1yLnkseGUmJihzLno9ci56LHMucm90YXRpb25YPXIucm90YXRpb25YLHMucm90YXRpb25ZPXIucm90YXRpb25ZLHMuc2NhbGVaPXIuc2NhbGVaKSxzLmZpbHRlcnMmJmRlbGV0ZSBzLmZpbHRlcnMsc30sRz1mdW5jdGlvbih0LGUsaSxyLHMpe3ZhciBuLGEsbyxsPXt9LGg9dC5zdHlsZTtmb3IoYSBpbiBpKVwiY3NzVGV4dFwiIT09YSYmXCJsZW5ndGhcIiE9PWEmJmlzTmFOKGEpJiYoZVthXSE9PShuPWlbYV0pfHxzJiZzW2FdKSYmLTE9PT1hLmluZGV4T2YoXCJPcmlnaW5cIikmJihcIm51bWJlclwiPT10eXBlb2Ygbnx8XCJzdHJpbmdcIj09dHlwZW9mIG4pJiYobFthXT1cImF1dG9cIiE9PW58fFwibGVmdFwiIT09YSYmXCJ0b3BcIiE9PWE/XCJcIiE9PW4mJlwiYXV0b1wiIT09biYmXCJub25lXCIhPT1ufHxcInN0cmluZ1wiIT10eXBlb2YgZVthXXx8XCJcIj09PWVbYV0ucmVwbGFjZSh2LFwiXCIpP246MDpaKHQsYSksdm9pZCAwIT09aFthXSYmKG89bmV3IGZlKGgsYSxoW2FdLG8pKSk7aWYocilmb3IoYSBpbiByKVwiY2xhc3NOYW1lXCIhPT1hJiYobFthXT1yW2FdKTtyZXR1cm57ZGlmczpsLGZpcnN0TVBUOm99fSxLPXt3aWR0aDpbXCJMZWZ0XCIsXCJSaWdodFwiXSxoZWlnaHQ6W1wiVG9wXCIsXCJCb3R0b21cIl19LEo9W1wibWFyZ2luTGVmdFwiLFwibWFyZ2luUmlnaHRcIixcIm1hcmdpblRvcFwiLFwibWFyZ2luQm90dG9tXCJdLHRlPWZ1bmN0aW9uKHQsZSxpKXt2YXIgcj1wYXJzZUZsb2F0KFwid2lkdGhcIj09PWU/dC5vZmZzZXRXaWR0aDp0Lm9mZnNldEhlaWdodCkscz1LW2VdLG49cy5sZW5ndGg7Zm9yKGk9aXx8SCh0LG51bGwpOy0tbj4tMTspci09cGFyc2VGbG9hdChxKHQsXCJwYWRkaW5nXCIrc1tuXSxpLCEwKSl8fDAsci09cGFyc2VGbG9hdChxKHQsXCJib3JkZXJcIitzW25dK1wiV2lkdGhcIixpLCEwKSl8fDA7cmV0dXJuIHJ9LGVlPWZ1bmN0aW9uKHQsZSl7KG51bGw9PXR8fFwiXCI9PT10fHxcImF1dG9cIj09PXR8fFwiYXV0byBhdXRvXCI9PT10KSYmKHQ9XCIwIDBcIik7dmFyIGk9dC5zcGxpdChcIiBcIikscj0tMSE9PXQuaW5kZXhPZihcImxlZnRcIik/XCIwJVwiOi0xIT09dC5pbmRleE9mKFwicmlnaHRcIik/XCIxMDAlXCI6aVswXSxzPS0xIT09dC5pbmRleE9mKFwidG9wXCIpP1wiMCVcIjotMSE9PXQuaW5kZXhPZihcImJvdHRvbVwiKT9cIjEwMCVcIjppWzFdO3JldHVybiBudWxsPT1zP3M9XCIwXCI6XCJjZW50ZXJcIj09PXMmJihzPVwiNTAlXCIpLChcImNlbnRlclwiPT09cnx8aXNOYU4ocGFyc2VGbG9hdChyKSkmJi0xPT09KHIrXCJcIikuaW5kZXhPZihcIj1cIikpJiYocj1cIjUwJVwiKSxlJiYoZS5veHA9LTEhPT1yLmluZGV4T2YoXCIlXCIpLGUub3lwPS0xIT09cy5pbmRleE9mKFwiJVwiKSxlLm94cj1cIj1cIj09PXIuY2hhckF0KDEpLGUub3lyPVwiPVwiPT09cy5jaGFyQXQoMSksZS5veD1wYXJzZUZsb2F0KHIucmVwbGFjZSh2LFwiXCIpKSxlLm95PXBhcnNlRmxvYXQocy5yZXBsYWNlKHYsXCJcIikpKSxyK1wiIFwiK3MrKGkubGVuZ3RoPjI/XCIgXCIraVsyXTpcIlwiKX0saWU9ZnVuY3Rpb24odCxlKXtyZXR1cm5cInN0cmluZ1wiPT10eXBlb2YgdCYmXCI9XCI9PT10LmNoYXJBdCgxKT9wYXJzZUludCh0LmNoYXJBdCgwKStcIjFcIiwxMCkqcGFyc2VGbG9hdCh0LnN1YnN0cigyKSk6cGFyc2VGbG9hdCh0KS1wYXJzZUZsb2F0KGUpfSxyZT1mdW5jdGlvbih0LGUpe3JldHVybiBudWxsPT10P2U6XCJzdHJpbmdcIj09dHlwZW9mIHQmJlwiPVwiPT09dC5jaGFyQXQoMSk/cGFyc2VJbnQodC5jaGFyQXQoMCkrXCIxXCIsMTApKk51bWJlcih0LnN1YnN0cigyKSkrZTpwYXJzZUZsb2F0KHQpfSxzZT1mdW5jdGlvbih0LGUsaSxyKXt2YXIgcyxuLGEsbyxsPTFlLTY7cmV0dXJuIG51bGw9PXQ/bz1lOlwibnVtYmVyXCI9PXR5cGVvZiB0P289dDoocz0zNjAsbj10LnNwbGl0KFwiX1wiKSxhPU51bWJlcihuWzBdLnJlcGxhY2UodixcIlwiKSkqKC0xPT09dC5pbmRleE9mKFwicmFkXCIpPzE6TCktKFwiPVwiPT09dC5jaGFyQXQoMSk/MDplKSxuLmxlbmd0aCYmKHImJihyW2ldPWUrYSksLTEhPT10LmluZGV4T2YoXCJzaG9ydFwiKSYmKGElPXMsYSE9PWElKHMvMikmJihhPTA+YT9hK3M6YS1zKSksLTEhPT10LmluZGV4T2YoXCJfY3dcIikmJjA+YT9hPShhKzk5OTk5OTk5OTkqcyklcy0oMHxhL3MpKnM6LTEhPT10LmluZGV4T2YoXCJjY3dcIikmJmE+MCYmKGE9KGEtOTk5OTk5OTk5OSpzKSVzLSgwfGEvcykqcykpLG89ZSthKSxsPm8mJm8+LWwmJihvPTApLG99LG5lPXthcXVhOlswLDI1NSwyNTVdLGxpbWU6WzAsMjU1LDBdLHNpbHZlcjpbMTkyLDE5MiwxOTJdLGJsYWNrOlswLDAsMF0sbWFyb29uOlsxMjgsMCwwXSx0ZWFsOlswLDEyOCwxMjhdLGJsdWU6WzAsMCwyNTVdLG5hdnk6WzAsMCwxMjhdLHdoaXRlOlsyNTUsMjU1LDI1NV0sZnVjaHNpYTpbMjU1LDAsMjU1XSxvbGl2ZTpbMTI4LDEyOCwwXSx5ZWxsb3c6WzI1NSwyNTUsMF0sb3JhbmdlOlsyNTUsMTY1LDBdLGdyYXk6WzEyOCwxMjgsMTI4XSxwdXJwbGU6WzEyOCwwLDEyOF0sZ3JlZW46WzAsMTI4LDBdLHJlZDpbMjU1LDAsMF0scGluazpbMjU1LDE5MiwyMDNdLGN5YW46WzAsMjU1LDI1NV0sdHJhbnNwYXJlbnQ6WzI1NSwyNTUsMjU1LDBdfSxhZT1mdW5jdGlvbih0LGUsaSl7cmV0dXJuIHQ9MD50P3QrMTp0PjE/dC0xOnQsMHwyNTUqKDE+Nip0P2UrNiooaS1lKSp0Oi41PnQ/aToyPjMqdD9lKzYqKGktZSkqKDIvMy10KTplKSsuNX0sb2U9ZnVuY3Rpb24odCl7dmFyIGUsaSxyLHMsbixhO3JldHVybiB0JiZcIlwiIT09dD9cIm51bWJlclwiPT10eXBlb2YgdD9bdD4+MTYsMjU1JnQ+PjgsMjU1JnRdOihcIixcIj09PXQuY2hhckF0KHQubGVuZ3RoLTEpJiYodD10LnN1YnN0cigwLHQubGVuZ3RoLTEpKSxuZVt0XT9uZVt0XTpcIiNcIj09PXQuY2hhckF0KDApPyg0PT09dC5sZW5ndGgmJihlPXQuY2hhckF0KDEpLGk9dC5jaGFyQXQoMikscj10LmNoYXJBdCgzKSx0PVwiI1wiK2UrZStpK2krcityKSx0PXBhcnNlSW50KHQuc3Vic3RyKDEpLDE2KSxbdD4+MTYsMjU1JnQ+PjgsMjU1JnRdKTpcImhzbFwiPT09dC5zdWJzdHIoMCwzKT8odD10Lm1hdGNoKGQpLHM9TnVtYmVyKHRbMF0pJTM2MC8zNjAsbj1OdW1iZXIodFsxXSkvMTAwLGE9TnVtYmVyKHRbMl0pLzEwMCxpPS41Pj1hP2EqKG4rMSk6YStuLWEqbixlPTIqYS1pLHQubGVuZ3RoPjMmJih0WzNdPU51bWJlcih0WzNdKSksdFswXT1hZShzKzEvMyxlLGkpLHRbMV09YWUocyxlLGkpLHRbMl09YWUocy0xLzMsZSxpKSx0KToodD10Lm1hdGNoKGQpfHxuZS50cmFuc3BhcmVudCx0WzBdPU51bWJlcih0WzBdKSx0WzFdPU51bWJlcih0WzFdKSx0WzJdPU51bWJlcih0WzJdKSx0Lmxlbmd0aD4zJiYodFszXT1OdW1iZXIodFszXSkpLHQpKTpuZS5ibGFja30sbGU9XCIoPzpcXFxcYig/Oig/OnJnYnxyZ2JhfGhzbHxoc2xhKVxcXFwoLis/XFxcXCkpfFxcXFxCIy4rP1xcXFxiXCI7Zm9yKGwgaW4gbmUpbGUrPVwifFwiK2wrXCJcXFxcYlwiO2xlPVJlZ0V4cChsZStcIilcIixcImdpXCIpO3ZhciBoZT1mdW5jdGlvbih0LGUsaSxyKXtpZihudWxsPT10KXJldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gdH07dmFyIHMsbj1lPyh0Lm1hdGNoKGxlKXx8W1wiXCJdKVswXTpcIlwiLGE9dC5zcGxpdChuKS5qb2luKFwiXCIpLm1hdGNoKGcpfHxbXSxvPXQuc3Vic3RyKDAsdC5pbmRleE9mKGFbMF0pKSxsPVwiKVwiPT09dC5jaGFyQXQodC5sZW5ndGgtMSk/XCIpXCI6XCJcIixoPS0xIT09dC5pbmRleE9mKFwiIFwiKT9cIiBcIjpcIixcIix1PWEubGVuZ3RoLGY9dT4wP2FbMF0ucmVwbGFjZShkLFwiXCIpOlwiXCI7cmV0dXJuIHU/cz1lP2Z1bmN0aW9uKHQpe3ZhciBlLF8scCxjO2lmKFwibnVtYmVyXCI9PXR5cGVvZiB0KXQrPWY7ZWxzZSBpZihyJiZELnRlc3QodCkpe2ZvcihjPXQucmVwbGFjZShELFwifFwiKS5zcGxpdChcInxcIikscD0wO2MubGVuZ3RoPnA7cCsrKWNbcF09cyhjW3BdKTtyZXR1cm4gYy5qb2luKFwiLFwiKX1pZihlPSh0Lm1hdGNoKGxlKXx8W25dKVswXSxfPXQuc3BsaXQoZSkuam9pbihcIlwiKS5tYXRjaChnKXx8W10scD1fLmxlbmd0aCx1PnAtLSlmb3IoO3U+KytwOylfW3BdPWk/X1swfChwLTEpLzJdOmFbcF07cmV0dXJuIG8rXy5qb2luKGgpK2grZStsKygtMSE9PXQuaW5kZXhPZihcImluc2V0XCIpP1wiIGluc2V0XCI6XCJcIil9OmZ1bmN0aW9uKHQpe3ZhciBlLG4sXztpZihcIm51bWJlclwiPT10eXBlb2YgdCl0Kz1mO2Vsc2UgaWYociYmRC50ZXN0KHQpKXtmb3Iobj10LnJlcGxhY2UoRCxcInxcIikuc3BsaXQoXCJ8XCIpLF89MDtuLmxlbmd0aD5fO18rKyluW19dPXMobltfXSk7cmV0dXJuIG4uam9pbihcIixcIil9aWYoZT10Lm1hdGNoKGcpfHxbXSxfPWUubGVuZ3RoLHU+Xy0tKWZvcig7dT4rK187KWVbX109aT9lWzB8KF8tMSkvMl06YVtfXTtyZXR1cm4gbytlLmpvaW4oaCkrbH06ZnVuY3Rpb24odCl7cmV0dXJuIHR9fSx1ZT1mdW5jdGlvbih0KXtyZXR1cm4gdD10LnNwbGl0KFwiLFwiKSxmdW5jdGlvbihlLGkscixzLG4sYSxvKXt2YXIgbCxoPShpK1wiXCIpLnNwbGl0KFwiIFwiKTtmb3Iobz17fSxsPTA7ND5sO2wrKylvW3RbbF1dPWhbbF09aFtsXXx8aFsobC0xKS8yPj4wXTtyZXR1cm4gcy5wYXJzZShlLG8sbixhKX19LGZlPShFLl9zZXRQbHVnaW5SYXRpbz1mdW5jdGlvbih0KXt0aGlzLnBsdWdpbi5zZXRSYXRpbyh0KTtmb3IodmFyIGUsaSxyLHMsbj10aGlzLmRhdGEsYT1uLnByb3h5LG89bi5maXJzdE1QVCxsPTFlLTY7bzspZT1hW28udl0sby5yP2U9TWF0aC5yb3VuZChlKTpsPmUmJmU+LWwmJihlPTApLG8udFtvLnBdPWUsbz1vLl9uZXh0O2lmKG4uYXV0b1JvdGF0ZSYmKG4uYXV0b1JvdGF0ZS5yb3RhdGlvbj1hLnJvdGF0aW9uKSwxPT09dClmb3Iobz1uLmZpcnN0TVBUO287KXtpZihpPW8udCxpLnR5cGUpe2lmKDE9PT1pLnR5cGUpe2ZvcihzPWkueHMwK2kucytpLnhzMSxyPTE7aS5sPnI7cisrKXMrPWlbXCJ4blwiK3JdK2lbXCJ4c1wiKyhyKzEpXTtpLmU9c319ZWxzZSBpLmU9aS5zK2kueHMwO289by5fbmV4dH19LGZ1bmN0aW9uKHQsZSxpLHIscyl7dGhpcy50PXQsdGhpcy5wPWUsdGhpcy52PWksdGhpcy5yPXMsciYmKHIuX3ByZXY9dGhpcyx0aGlzLl9uZXh0PXIpfSksX2U9KEUuX3BhcnNlVG9Qcm94eT1mdW5jdGlvbih0LGUsaSxyLHMsbil7dmFyIGEsbyxsLGgsdSxmPXIsXz17fSxwPXt9LGM9aS5fdHJhbnNmb3JtLGQ9Tjtmb3IoaS5fdHJhbnNmb3JtPW51bGwsTj1lLHI9dT1pLnBhcnNlKHQsZSxyLHMpLE49ZCxuJiYoaS5fdHJhbnNmb3JtPWMsZiYmKGYuX3ByZXY9bnVsbCxmLl9wcmV2JiYoZi5fcHJldi5fbmV4dD1udWxsKSkpO3ImJnIhPT1mOyl7aWYoMT49ci50eXBlJiYobz1yLnAscFtvXT1yLnMrci5jLF9bb109ci5zLG58fChoPW5ldyBmZShyLFwic1wiLG8saCxyLnIpLHIuYz0wKSwxPT09ci50eXBlKSlmb3IoYT1yLmw7LS1hPjA7KWw9XCJ4blwiK2Esbz1yLnArXCJfXCIrbCxwW29dPXIuZGF0YVtsXSxfW29dPXJbbF0sbnx8KGg9bmV3IGZlKHIsbCxvLGgsci5yeHBbbF0pKTtyPXIuX25leHR9cmV0dXJue3Byb3h5Ol8sZW5kOnAsZmlyc3RNUFQ6aCxwdDp1fX0sRS5DU1NQcm9wVHdlZW49ZnVuY3Rpb24odCxlLHIscyxhLG8sbCxoLHUsZixfKXt0aGlzLnQ9dCx0aGlzLnA9ZSx0aGlzLnM9cix0aGlzLmM9cyx0aGlzLm49bHx8ZSx0IGluc3RhbmNlb2YgX2V8fG4ucHVzaCh0aGlzLm4pLHRoaXMucj1oLHRoaXMudHlwZT1vfHwwLHUmJih0aGlzLnByPXUsaT0hMCksdGhpcy5iPXZvaWQgMD09PWY/cjpmLHRoaXMuZT12b2lkIDA9PT1fP3IrczpfLGEmJih0aGlzLl9uZXh0PWEsYS5fcHJldj10aGlzKX0pLHBlPWEucGFyc2VDb21wbGV4PWZ1bmN0aW9uKHQsZSxpLHIscyxuLGEsbyxsLHUpe2k9aXx8bnx8XCJcIixhPW5ldyBfZSh0LGUsMCwwLGEsdT8yOjEsbnVsbCwhMSxvLGkscikscis9XCJcIjt2YXIgZixfLHAsYyxnLHYseSxULHcseCxQLFMsQz1pLnNwbGl0KFwiLCBcIikuam9pbihcIixcIikuc3BsaXQoXCIgXCIpLFI9ci5zcGxpdChcIiwgXCIpLmpvaW4oXCIsXCIpLnNwbGl0KFwiIFwiKSxrPUMubGVuZ3RoLEE9aCE9PSExO2ZvcigoLTEhPT1yLmluZGV4T2YoXCIsXCIpfHwtMSE9PWkuaW5kZXhPZihcIixcIikpJiYoQz1DLmpvaW4oXCIgXCIpLnJlcGxhY2UoRCxcIiwgXCIpLnNwbGl0KFwiIFwiKSxSPVIuam9pbihcIiBcIikucmVwbGFjZShELFwiLCBcIikuc3BsaXQoXCIgXCIpLGs9Qy5sZW5ndGgpLGshPT1SLmxlbmd0aCYmKEM9KG58fFwiXCIpLnNwbGl0KFwiIFwiKSxrPUMubGVuZ3RoKSxhLnBsdWdpbj1sLGEuc2V0UmF0aW89dSxmPTA7az5mO2YrKylpZihjPUNbZl0sZz1SW2ZdLFQ9cGFyc2VGbG9hdChjKSxUfHwwPT09VClhLmFwcGVuZFh0cmEoXCJcIixULGllKGcsVCksZy5yZXBsYWNlKG0sXCJcIiksQSYmLTEhPT1nLmluZGV4T2YoXCJweFwiKSwhMCk7ZWxzZSBpZihzJiYoXCIjXCI9PT1jLmNoYXJBdCgwKXx8bmVbY118fGIudGVzdChjKSkpUz1cIixcIj09PWcuY2hhckF0KGcubGVuZ3RoLTEpP1wiKSxcIjpcIilcIixjPW9lKGMpLGc9b2UoZyksdz1jLmxlbmd0aCtnLmxlbmd0aD42LHcmJiFZJiYwPT09Z1szXT8oYVtcInhzXCIrYS5sXSs9YS5sP1wiIHRyYW5zcGFyZW50XCI6XCJ0cmFuc3BhcmVudFwiLGEuZT1hLmUuc3BsaXQoUltmXSkuam9pbihcInRyYW5zcGFyZW50XCIpKTooWXx8KHc9ITEpLGEuYXBwZW5kWHRyYSh3P1wicmdiYShcIjpcInJnYihcIixjWzBdLGdbMF0tY1swXSxcIixcIiwhMCwhMCkuYXBwZW5kWHRyYShcIlwiLGNbMV0sZ1sxXS1jWzFdLFwiLFwiLCEwKS5hcHBlbmRYdHJhKFwiXCIsY1syXSxnWzJdLWNbMl0sdz9cIixcIjpTLCEwKSx3JiYoYz00PmMubGVuZ3RoPzE6Y1szXSxhLmFwcGVuZFh0cmEoXCJcIixjLCg0PmcubGVuZ3RoPzE6Z1szXSktYyxTLCExKSkpO2Vsc2UgaWYodj1jLm1hdGNoKGQpKXtpZih5PWcubWF0Y2gobSksIXl8fHkubGVuZ3RoIT09di5sZW5ndGgpcmV0dXJuIGE7Zm9yKHA9MCxfPTA7di5sZW5ndGg+XztfKyspUD12W19dLHg9Yy5pbmRleE9mKFAscCksYS5hcHBlbmRYdHJhKGMuc3Vic3RyKHAseC1wKSxOdW1iZXIoUCksaWUoeVtfXSxQKSxcIlwiLEEmJlwicHhcIj09PWMuc3Vic3RyKHgrUC5sZW5ndGgsMiksMD09PV8pLHA9eCtQLmxlbmd0aDthW1wieHNcIithLmxdKz1jLnN1YnN0cihwKX1lbHNlIGFbXCJ4c1wiK2EubF0rPWEubD9cIiBcIitjOmM7aWYoLTEhPT1yLmluZGV4T2YoXCI9XCIpJiZhLmRhdGEpe2ZvcihTPWEueHMwK2EuZGF0YS5zLGY9MTthLmw+ZjtmKyspUys9YVtcInhzXCIrZl0rYS5kYXRhW1wieG5cIitmXTthLmU9UythW1wieHNcIitmXX1yZXR1cm4gYS5sfHwoYS50eXBlPS0xLGEueHMwPWEuZSksYS54Zmlyc3R8fGF9LGNlPTk7Zm9yKGw9X2UucHJvdG90eXBlLGwubD1sLnByPTA7LS1jZT4wOylsW1wieG5cIitjZV09MCxsW1wieHNcIitjZV09XCJcIjtsLnhzMD1cIlwiLGwuX25leHQ9bC5fcHJldj1sLnhmaXJzdD1sLmRhdGE9bC5wbHVnaW49bC5zZXRSYXRpbz1sLnJ4cD1udWxsLGwuYXBwZW5kWHRyYT1mdW5jdGlvbih0LGUsaSxyLHMsbil7dmFyIGE9dGhpcyxvPWEubDtyZXR1cm4gYVtcInhzXCIrb10rPW4mJm8/XCIgXCIrdDp0fHxcIlwiLGl8fDA9PT1vfHxhLnBsdWdpbj8oYS5sKyssYS50eXBlPWEuc2V0UmF0aW8/MjoxLGFbXCJ4c1wiK2EubF09cnx8XCJcIixvPjA/KGEuZGF0YVtcInhuXCIrb109ZStpLGEucnhwW1wieG5cIitvXT1zLGFbXCJ4blwiK29dPWUsYS5wbHVnaW58fChhLnhmaXJzdD1uZXcgX2UoYSxcInhuXCIrbyxlLGksYS54Zmlyc3R8fGEsMCxhLm4scyxhLnByKSxhLnhmaXJzdC54czA9MCksYSk6KGEuZGF0YT17czplK2l9LGEucnhwPXt9LGEucz1lLGEuYz1pLGEucj1zLGEpKTooYVtcInhzXCIrb10rPWUrKHJ8fFwiXCIpLGEpfTt2YXIgZGU9ZnVuY3Rpb24odCxlKXtlPWV8fHt9LHRoaXMucD1lLnByZWZpeD9WKHQpfHx0OnQsb1t0XT1vW3RoaXMucF09dGhpcyx0aGlzLmZvcm1hdD1lLmZvcm1hdHRlcnx8aGUoZS5kZWZhdWx0VmFsdWUsZS5jb2xvcixlLmNvbGxhcHNpYmxlLGUubXVsdGkpLGUucGFyc2VyJiYodGhpcy5wYXJzZT1lLnBhcnNlciksdGhpcy5jbHJzPWUuY29sb3IsdGhpcy5tdWx0aT1lLm11bHRpLHRoaXMua2V5d29yZD1lLmtleXdvcmQsdGhpcy5kZmx0PWUuZGVmYXVsdFZhbHVlLHRoaXMucHI9ZS5wcmlvcml0eXx8MH0sbWU9RS5fcmVnaXN0ZXJDb21wbGV4U3BlY2lhbFByb3A9ZnVuY3Rpb24odCxlLGkpe1wib2JqZWN0XCIhPXR5cGVvZiBlJiYoZT17cGFyc2VyOml9KTt2YXIgcixzLG49dC5zcGxpdChcIixcIiksYT1lLmRlZmF1bHRWYWx1ZTtmb3IoaT1pfHxbYV0scj0wO24ubGVuZ3RoPnI7cisrKWUucHJlZml4PTA9PT1yJiZlLnByZWZpeCxlLmRlZmF1bHRWYWx1ZT1pW3JdfHxhLHM9bmV3IGRlKG5bcl0sZSl9LGdlPWZ1bmN0aW9uKHQpe2lmKCFvW3RdKXt2YXIgZT10LmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpK3Quc3Vic3RyKDEpK1wiUGx1Z2luXCI7bWUodCx7cGFyc2VyOmZ1bmN0aW9uKHQsaSxyLHMsbixhLGwpe3ZhciBoPSh3aW5kb3cuR3JlZW5Tb2NrR2xvYmFsc3x8d2luZG93KS5jb20uZ3JlZW5zb2NrLnBsdWdpbnNbZV07cmV0dXJuIGg/KGguX2Nzc1JlZ2lzdGVyKCksb1tyXS5wYXJzZSh0LGkscixzLG4sYSxsKSk6KFUoXCJFcnJvcjogXCIrZStcIiBqcyBmaWxlIG5vdCBsb2FkZWQuXCIpLG4pfX0pfX07bD1kZS5wcm90b3R5cGUsbC5wYXJzZUNvbXBsZXg9ZnVuY3Rpb24odCxlLGkscixzLG4pe3ZhciBhLG8sbCxoLHUsZixfPXRoaXMua2V5d29yZDtpZih0aGlzLm11bHRpJiYoRC50ZXN0KGkpfHxELnRlc3QoZSk/KG89ZS5yZXBsYWNlKEQsXCJ8XCIpLnNwbGl0KFwifFwiKSxsPWkucmVwbGFjZShELFwifFwiKS5zcGxpdChcInxcIikpOl8mJihvPVtlXSxsPVtpXSkpLGwpe2ZvcihoPWwubGVuZ3RoPm8ubGVuZ3RoP2wubGVuZ3RoOm8ubGVuZ3RoLGE9MDtoPmE7YSsrKWU9b1thXT1vW2FdfHx0aGlzLmRmbHQsaT1sW2FdPWxbYV18fHRoaXMuZGZsdCxfJiYodT1lLmluZGV4T2YoXyksZj1pLmluZGV4T2YoXyksdSE9PWYmJihpPS0xPT09Zj9sOm8saVthXSs9XCIgXCIrXykpO2U9by5qb2luKFwiLCBcIiksaT1sLmpvaW4oXCIsIFwiKX1yZXR1cm4gcGUodCx0aGlzLnAsZSxpLHRoaXMuY2xycyx0aGlzLmRmbHQscix0aGlzLnByLHMsbil9LGwucGFyc2U9ZnVuY3Rpb24odCxlLGkscixuLGEpe3JldHVybiB0aGlzLnBhcnNlQ29tcGxleCh0LnN0eWxlLHRoaXMuZm9ybWF0KHEodCx0aGlzLnAscywhMSx0aGlzLmRmbHQpKSx0aGlzLmZvcm1hdChlKSxuLGEpfSxhLnJlZ2lzdGVyU3BlY2lhbFByb3A9ZnVuY3Rpb24odCxlLGkpe21lKHQse3BhcnNlcjpmdW5jdGlvbih0LHIscyxuLGEsbyl7dmFyIGw9bmV3IF9lKHQscywwLDAsYSwyLHMsITEsaSk7cmV0dXJuIGwucGx1Z2luPW8sbC5zZXRSYXRpbz1lKHQscixuLl90d2VlbixzKSxsfSxwcmlvcml0eTppfSl9O3ZhciB2ZT1cInNjYWxlWCxzY2FsZVksc2NhbGVaLHgseSx6LHNrZXdYLHNrZXdZLHJvdGF0aW9uLHJvdGF0aW9uWCxyb3RhdGlvblkscGVyc3BlY3RpdmVcIi5zcGxpdChcIixcIikseWU9VihcInRyYW5zZm9ybVwiKSxUZT1XK1widHJhbnNmb3JtXCIsd2U9VihcInRyYW5zZm9ybU9yaWdpblwiKSx4ZT1udWxsIT09VihcInBlcnNwZWN0aXZlXCIpLGJlPUUuVHJhbnNmb3JtPWZ1bmN0aW9uKCl7dGhpcy5za2V3WT0wfSxQZT1FLmdldFRyYW5zZm9ybT1mdW5jdGlvbih0LGUsaSxyKXtpZih0Ll9nc1RyYW5zZm9ybSYmaSYmIXIpcmV0dXJuIHQuX2dzVHJhbnNmb3JtO3ZhciBzLG4sbyxsLGgsdSxmLF8scCxjLGQsbSxnLHY9aT90Ll9nc1RyYW5zZm9ybXx8bmV3IGJlOm5ldyBiZSx5PTA+di5zY2FsZVgsVD0yZS01LHc9MWU1LHg9MTc5Ljk5LGI9eCpNLFA9eGU/cGFyc2VGbG9hdChxKHQsd2UsZSwhMSxcIjAgMCAwXCIpLnNwbGl0KFwiIFwiKVsyXSl8fHYuek9yaWdpbnx8MDowO2Zvcih5ZT9zPXEodCxUZSxlLCEwKTp0LmN1cnJlbnRTdHlsZSYmKHM9dC5jdXJyZW50U3R5bGUuZmlsdGVyLm1hdGNoKEEpLHM9cyYmND09PXMubGVuZ3RoP1tzWzBdLnN1YnN0cig0KSxOdW1iZXIoc1syXS5zdWJzdHIoNCkpLE51bWJlcihzWzFdLnN1YnN0cig0KSksc1szXS5zdWJzdHIoNCksdi54fHwwLHYueXx8MF0uam9pbihcIixcIik6XCJcIiksbj0oc3x8XCJcIikubWF0Y2goLyg/OlxcLXxcXGIpW1xcZFxcLVxcLmVdK1xcYi9naSl8fFtdLG89bi5sZW5ndGg7LS1vPi0xOylsPU51bWJlcihuW29dKSxuW29dPShoPWwtKGx8PTApKT8oMHxoKncrKDA+aD8tLjU6LjUpKS93K2w6bDtpZigxNj09PW4ubGVuZ3RoKXt2YXIgUz1uWzhdLEM9bls5XSxSPW5bMTBdLGs9blsxMl0sTz1uWzEzXSxEPW5bMTRdO2lmKHYuek9yaWdpbiYmKEQ9LXYuek9yaWdpbixrPVMqRC1uWzEyXSxPPUMqRC1uWzEzXSxEPVIqRCt2LnpPcmlnaW4tblsxNF0pLCFpfHxyfHxudWxsPT12LnJvdGF0aW9uWCl7dmFyIE4sWCx6LEksRSxGLFksQj1uWzBdLFU9blsxXSxXPW5bMl0saj1uWzNdLFY9bls0XSxIPW5bNV0sUT1uWzZdLFo9bls3XSwkPW5bMTFdLEc9TWF0aC5hdGFuMihRLFIpLEs9LWI+R3x8Rz5iO3Yucm90YXRpb25YPUcqTCxHJiYoST1NYXRoLmNvcygtRyksRT1NYXRoLnNpbigtRyksTj1WKkkrUypFLFg9SCpJK0MqRSx6PVEqSStSKkUsUz1WKi1FK1MqSSxDPUgqLUUrQypJLFI9USotRStSKkksJD1aKi1FKyQqSSxWPU4sSD1YLFE9eiksRz1NYXRoLmF0YW4yKFMsQiksdi5yb3RhdGlvblk9RypMLEcmJihGPS1iPkd8fEc+YixJPU1hdGguY29zKC1HKSxFPU1hdGguc2luKC1HKSxOPUIqSS1TKkUsWD1VKkktQypFLHo9VypJLVIqRSxDPVUqRStDKkksUj1XKkUrUipJLCQ9aipFKyQqSSxCPU4sVT1YLFc9eiksRz1NYXRoLmF0YW4yKFUsSCksdi5yb3RhdGlvbj1HKkwsRyYmKFk9LWI+R3x8Rz5iLEk9TWF0aC5jb3MoLUcpLEU9TWF0aC5zaW4oLUcpLEI9QipJK1YqRSxYPVUqSStIKkUsSD1VKi1FK0gqSSxRPVcqLUUrUSpJLFU9WCksWSYmSz92LnJvdGF0aW9uPXYucm90YXRpb25YPTA6WSYmRj92LnJvdGF0aW9uPXYucm90YXRpb25ZPTA6RiYmSyYmKHYucm90YXRpb25ZPXYucm90YXRpb25YPTApLHYuc2NhbGVYPSgwfE1hdGguc3FydChCKkIrVSpVKSp3Ky41KS93LHYuc2NhbGVZPSgwfE1hdGguc3FydChIKkgrQypDKSp3Ky41KS93LHYuc2NhbGVaPSgwfE1hdGguc3FydChRKlErUipSKSp3Ky41KS93LHYuc2tld1g9MCx2LnBlcnNwZWN0aXZlPSQ/MS8oMD4kPy0kOiQpOjAsdi54PWssdi55PU8sdi56PUR9fWVsc2UgaWYoISh4ZSYmIXImJm4ubGVuZ3RoJiZ2Lng9PT1uWzRdJiZ2Lnk9PT1uWzVdJiYodi5yb3RhdGlvblh8fHYucm90YXRpb25ZKXx8dm9pZCAwIT09di54JiZcIm5vbmVcIj09PXEodCxcImRpc3BsYXlcIixlKSkpe3ZhciBKPW4ubGVuZ3RoPj02LHRlPUo/blswXToxLGVlPW5bMV18fDAsaWU9blsyXXx8MCxyZT1KP25bM106MTt2Lng9bls0XXx8MCx2Lnk9bls1XXx8MCx1PU1hdGguc3FydCh0ZSp0ZStlZSplZSksZj1NYXRoLnNxcnQocmUqcmUraWUqaWUpLF89dGV8fGVlP01hdGguYXRhbjIoZWUsdGUpKkw6di5yb3RhdGlvbnx8MCxwPWllfHxyZT9NYXRoLmF0YW4yKGllLHJlKSpMK186di5za2V3WHx8MCxjPXUtTWF0aC5hYnModi5zY2FsZVh8fDApLGQ9Zi1NYXRoLmFicyh2LnNjYWxlWXx8MCksTWF0aC5hYnMocCk+OTAmJjI3MD5NYXRoLmFicyhwKSYmKHk/KHUqPS0xLHArPTA+PV8/MTgwOi0xODAsXys9MD49Xz8xODA6LTE4MCk6KGYqPS0xLHArPTA+PXA/MTgwOi0xODApKSxtPShfLXYucm90YXRpb24pJTE4MCxnPShwLXYuc2tld1gpJTE4MCwodm9pZCAwPT09di5za2V3WHx8Yz5UfHwtVD5jfHxkPlR8fC1UPmR8fG0+LXgmJng+bSYmZmFsc2V8bSp3fHxnPi14JiZ4PmcmJmZhbHNlfGcqdykmJih2LnNjYWxlWD11LHYuc2NhbGVZPWYsdi5yb3RhdGlvbj1fLHYuc2tld1g9cCkseGUmJih2LnJvdGF0aW9uWD12LnJvdGF0aW9uWT12Lno9MCx2LnBlcnNwZWN0aXZlPXBhcnNlRmxvYXQoYS5kZWZhdWx0VHJhbnNmb3JtUGVyc3BlY3RpdmUpfHwwLHYuc2NhbGVaPTEpfXYuek9yaWdpbj1QO2ZvcihvIGluIHYpVD52W29dJiZ2W29dPi1UJiYodltvXT0wKTtyZXR1cm4gaSYmKHQuX2dzVHJhbnNmb3JtPXYpLHZ9LFNlPWZ1bmN0aW9uKHQpe3ZhciBlLGkscj10aGlzLmRhdGEscz0tci5yb3RhdGlvbipNLG49cytyLnNrZXdYKk0sYT0xZTUsbz0oMHxNYXRoLmNvcyhzKSpyLnNjYWxlWCphKS9hLGw9KDB8TWF0aC5zaW4ocykqci5zY2FsZVgqYSkvYSxoPSgwfE1hdGguc2luKG4pKi1yLnNjYWxlWSphKS9hLHU9KDB8TWF0aC5jb3Mobikqci5zY2FsZVkqYSkvYSxmPXRoaXMudC5zdHlsZSxfPXRoaXMudC5jdXJyZW50U3R5bGU7aWYoXyl7aT1sLGw9LWgsaD0taSxlPV8uZmlsdGVyLGYuZmlsdGVyPVwiXCI7dmFyIHAsZCxtPXRoaXMudC5vZmZzZXRXaWR0aCxnPXRoaXMudC5vZmZzZXRIZWlnaHQsdj1cImFic29sdXRlXCIhPT1fLnBvc2l0aW9uLHc9XCJwcm9naWQ6RFhJbWFnZVRyYW5zZm9ybS5NaWNyb3NvZnQuTWF0cml4KE0xMT1cIitvK1wiLCBNMTI9XCIrbCtcIiwgTTIxPVwiK2grXCIsIE0yMj1cIit1LHg9ci54LGI9ci55O2lmKG51bGwhPXIub3gmJihwPShyLm94cD8uMDEqbSpyLm94OnIub3gpLW0vMixkPShyLm95cD8uMDEqZypyLm95OnIub3kpLWcvMix4Kz1wLShwKm8rZCpsKSxiKz1kLShwKmgrZCp1KSksdj8ocD1tLzIsZD1nLzIsdys9XCIsIER4PVwiKyhwLShwKm8rZCpsKSt4KStcIiwgRHk9XCIrKGQtKHAqaCtkKnUpK2IpK1wiKVwiKTp3Kz1cIiwgc2l6aW5nTWV0aG9kPSdhdXRvIGV4cGFuZCcpXCIsZi5maWx0ZXI9LTEhPT1lLmluZGV4T2YoXCJEWEltYWdlVHJhbnNmb3JtLk1pY3Jvc29mdC5NYXRyaXgoXCIpP2UucmVwbGFjZShPLHcpOncrXCIgXCIrZSwoMD09PXR8fDE9PT10KSYmMT09PW8mJjA9PT1sJiYwPT09aCYmMT09PXUmJih2JiYtMT09PXcuaW5kZXhPZihcIkR4PTAsIER5PTBcIil8fFQudGVzdChlKSYmMTAwIT09cGFyc2VGbG9hdChSZWdFeHAuJDEpfHwtMT09PWUuaW5kZXhPZihcImdyYWRpZW50KFwiJiZlLmluZGV4T2YoXCJBbHBoYVwiKSkmJmYucmVtb3ZlQXR0cmlidXRlKFwiZmlsdGVyXCIpKSwhdil7dmFyIFAsUyxDLFI9OD5jPzE6LTE7Zm9yKHA9ci5pZU9mZnNldFh8fDAsZD1yLmllT2Zmc2V0WXx8MCxyLmllT2Zmc2V0WD1NYXRoLnJvdW5kKChtLSgoMD5vPy1vOm8pKm0rKDA+bD8tbDpsKSpnKSkvMit4KSxyLmllT2Zmc2V0WT1NYXRoLnJvdW5kKChnLSgoMD51Py11OnUpKmcrKDA+aD8taDpoKSptKSkvMitiKSxjZT0wOzQ+Y2U7Y2UrKylTPUpbY2VdLFA9X1tTXSxpPS0xIT09UC5pbmRleE9mKFwicHhcIik/cGFyc2VGbG9hdChQKTpRKHRoaXMudCxTLHBhcnNlRmxvYXQoUCksUC5yZXBsYWNlKHksXCJcIikpfHwwLEM9aSE9PXJbU10/Mj5jZT8tci5pZU9mZnNldFg6LXIuaWVPZmZzZXRZOjI+Y2U/cC1yLmllT2Zmc2V0WDpkLXIuaWVPZmZzZXRZLGZbU109KHJbU109TWF0aC5yb3VuZChpLUMqKDA9PT1jZXx8Mj09PWNlPzE6UikpKStcInB4XCJ9fX0sQ2U9RS5zZXQzRFRyYW5zZm9ybVJhdGlvPWZ1bmN0aW9uKHQpe3ZhciBlLGkscixzLG4sYSxvLGwsaCx1LGYscCxjLGQsbSxnLHYseSxULHcseCxiLFAsUz10aGlzLmRhdGEsQz10aGlzLnQuc3R5bGUsUj1TLnJvdGF0aW9uKk0saz1TLnNjYWxlWCxBPVMuc2NhbGVZLE89Uy5zY2FsZVosRD1TLnBlcnNwZWN0aXZlO2lmKCEoMSE9PXQmJjAhPT10fHxcImF1dG9cIiE9PVMuZm9yY2UzRHx8Uy5yb3RhdGlvbll8fFMucm90YXRpb25YfHwxIT09T3x8RHx8Uy56KSlyZXR1cm4gUmUuY2FsbCh0aGlzLHQpLHZvaWQgMDtpZihfKXt2YXIgTD0xZS00O0w+ayYmaz4tTCYmKGs9Tz0yZS01KSxMPkEmJkE+LUwmJihBPU89MmUtNSksIUR8fFMuenx8Uy5yb3RhdGlvblh8fFMucm90YXRpb25ZfHwoRD0wKX1pZihSfHxTLnNrZXdYKXk9TWF0aC5jb3MoUiksVD1NYXRoLnNpbihSKSxlPXksbj1ULFMuc2tld1gmJihSLT1TLnNrZXdYKk0seT1NYXRoLmNvcyhSKSxUPU1hdGguc2luKFIpLFwic2ltcGxlXCI9PT1TLnNrZXdUeXBlJiYodz1NYXRoLnRhbihTLnNrZXdYKk0pLHc9TWF0aC5zcXJ0KDErdyp3KSx5Kj13LFQqPXcpKSxpPS1ULGE9eTtlbHNle2lmKCEoUy5yb3RhdGlvbll8fFMucm90YXRpb25YfHwxIT09T3x8RCkpcmV0dXJuIENbeWVdPVwidHJhbnNsYXRlM2QoXCIrUy54K1wicHgsXCIrUy55K1wicHgsXCIrUy56K1wicHgpXCIrKDEhPT1rfHwxIT09QT9cIiBzY2FsZShcIitrK1wiLFwiK0ErXCIpXCI6XCJcIiksdm9pZCAwO2U9YT0xLGk9bj0wfWY9MSxyPXM9bz1sPWg9dT1wPWM9ZD0wLG09RD8tMS9EOjAsZz1TLnpPcmlnaW4sdj0xZTUsUj1TLnJvdGF0aW9uWSpNLFImJih5PU1hdGguY29zKFIpLFQ9TWF0aC5zaW4oUiksaD1mKi1ULGM9bSotVCxyPWUqVCxvPW4qVCxmKj15LG0qPXksZSo9eSxuKj15KSxSPVMucm90YXRpb25YKk0sUiYmKHk9TWF0aC5jb3MoUiksVD1NYXRoLnNpbihSKSx3PWkqeStyKlQseD1hKnkrbypULGI9dSp5K2YqVCxQPWQqeSttKlQscj1pKi1UK3IqeSxvPWEqLVQrbyp5LGY9dSotVCtmKnksbT1kKi1UK20qeSxpPXcsYT14LHU9YixkPVApLDEhPT1PJiYocio9TyxvKj1PLGYqPU8sbSo9TyksMSE9PUEmJihpKj1BLGEqPUEsdSo9QSxkKj1BKSwxIT09ayYmKGUqPWssbio9ayxoKj1rLGMqPWspLGcmJihwLT1nLHM9cipwLGw9bypwLHA9ZipwK2cpLHM9KHc9KHMrPVMueCktKHN8PTApKT8oMHx3KnYrKDA+dz8tLjU6LjUpKS92K3M6cyxsPSh3PShsKz1TLnkpLShsfD0wKSk/KDB8dyp2KygwPnc/LS41Oi41KSkvditsOmwscD0odz0ocCs9Uy56KS0ocHw9MCkpPygwfHcqdisoMD53Py0uNTouNSkpL3YrcDpwLENbeWVdPVwibWF0cml4M2QoXCIrWygwfGUqdikvdiwoMHxuKnYpL3YsKDB8aCp2KS92LCgwfGMqdikvdiwoMHxpKnYpL3YsKDB8YSp2KS92LCgwfHUqdikvdiwoMHxkKnYpL3YsKDB8cip2KS92LCgwfG8qdikvdiwoMHxmKnYpL3YsKDB8bSp2KS92LHMsbCxwLEQ/MSstcC9EOjFdLmpvaW4oXCIsXCIpK1wiKVwifSxSZT1FLnNldDJEVHJhbnNmb3JtUmF0aW89ZnVuY3Rpb24odCl7dmFyIGUsaSxyLHMsbixhPXRoaXMuZGF0YSxvPXRoaXMudCxsPW8uc3R5bGU7cmV0dXJuIGEucm90YXRpb25YfHxhLnJvdGF0aW9uWXx8YS56fHxhLmZvcmNlM0Q9PT0hMHx8XCJhdXRvXCI9PT1hLmZvcmNlM0QmJjEhPT10JiYwIT09dD8odGhpcy5zZXRSYXRpbz1DZSxDZS5jYWxsKHRoaXMsdCksdm9pZCAwKTooYS5yb3RhdGlvbnx8YS5za2V3WD8oZT1hLnJvdGF0aW9uKk0saT1lLWEuc2tld1gqTSxyPTFlNSxzPWEuc2NhbGVYKnIsbj1hLnNjYWxlWSpyLGxbeWVdPVwibWF0cml4KFwiKygwfE1hdGguY29zKGUpKnMpL3IrXCIsXCIrKDB8TWF0aC5zaW4oZSkqcykvcitcIixcIisoMHxNYXRoLnNpbihpKSotbikvcitcIixcIisoMHxNYXRoLmNvcyhpKSpuKS9yK1wiLFwiK2EueCtcIixcIithLnkrXCIpXCIpOmxbeWVdPVwibWF0cml4KFwiK2Euc2NhbGVYK1wiLDAsMCxcIithLnNjYWxlWStcIixcIithLngrXCIsXCIrYS55K1wiKVwiLHZvaWQgMCl9O21lKFwidHJhbnNmb3JtLHNjYWxlLHNjYWxlWCxzY2FsZVksc2NhbGVaLHgseSx6LHJvdGF0aW9uLHJvdGF0aW9uWCxyb3RhdGlvblkscm90YXRpb25aLHNrZXdYLHNrZXdZLHNob3J0Um90YXRpb24sc2hvcnRSb3RhdGlvblgsc2hvcnRSb3RhdGlvblksc2hvcnRSb3RhdGlvblosdHJhbnNmb3JtT3JpZ2luLHRyYW5zZm9ybVBlcnNwZWN0aXZlLGRpcmVjdGlvbmFsUm90YXRpb24scGFyc2VUcmFuc2Zvcm0sZm9yY2UzRCxza2V3VHlwZVwiLHtwYXJzZXI6ZnVuY3Rpb24odCxlLGkscixuLG8sbCl7aWYoci5fdHJhbnNmb3JtKXJldHVybiBuO3ZhciBoLHUsZixfLHAsYyxkLG09ci5fdHJhbnNmb3JtPVBlKHQscywhMCxsLnBhcnNlVHJhbnNmb3JtKSxnPXQuc3R5bGUsdj0xZS02LHk9dmUubGVuZ3RoLFQ9bCx3PXt9O2lmKFwic3RyaW5nXCI9PXR5cGVvZiBULnRyYW5zZm9ybSYmeWUpZj16LnN0eWxlLGZbeWVdPVQudHJhbnNmb3JtLGYuZGlzcGxheT1cImJsb2NrXCIsZi5wb3NpdGlvbj1cImFic29sdXRlXCIsWC5ib2R5LmFwcGVuZENoaWxkKHopLGg9UGUoeixudWxsLCExKSxYLmJvZHkucmVtb3ZlQ2hpbGQoeik7ZWxzZSBpZihcIm9iamVjdFwiPT10eXBlb2YgVCl7aWYoaD17c2NhbGVYOnJlKG51bGwhPVQuc2NhbGVYP1Quc2NhbGVYOlQuc2NhbGUsbS5zY2FsZVgpLHNjYWxlWTpyZShudWxsIT1ULnNjYWxlWT9ULnNjYWxlWTpULnNjYWxlLG0uc2NhbGVZKSxzY2FsZVo6cmUoVC5zY2FsZVosbS5zY2FsZVopLHg6cmUoVC54LG0ueCkseTpyZShULnksbS55KSx6OnJlKFQueixtLnopLHBlcnNwZWN0aXZlOnJlKFQudHJhbnNmb3JtUGVyc3BlY3RpdmUsbS5wZXJzcGVjdGl2ZSl9LGQ9VC5kaXJlY3Rpb25hbFJvdGF0aW9uLG51bGwhPWQpaWYoXCJvYmplY3RcIj09dHlwZW9mIGQpZm9yKGYgaW4gZClUW2ZdPWRbZl07ZWxzZSBULnJvdGF0aW9uPWQ7aC5yb3RhdGlvbj1zZShcInJvdGF0aW9uXCJpbiBUP1Qucm90YXRpb246XCJzaG9ydFJvdGF0aW9uXCJpbiBUP1Quc2hvcnRSb3RhdGlvbitcIl9zaG9ydFwiOlwicm90YXRpb25aXCJpbiBUP1Qucm90YXRpb25aOm0ucm90YXRpb24sbS5yb3RhdGlvbixcInJvdGF0aW9uXCIsdykseGUmJihoLnJvdGF0aW9uWD1zZShcInJvdGF0aW9uWFwiaW4gVD9ULnJvdGF0aW9uWDpcInNob3J0Um90YXRpb25YXCJpbiBUP1Quc2hvcnRSb3RhdGlvblgrXCJfc2hvcnRcIjptLnJvdGF0aW9uWHx8MCxtLnJvdGF0aW9uWCxcInJvdGF0aW9uWFwiLHcpLGgucm90YXRpb25ZPXNlKFwicm90YXRpb25ZXCJpbiBUP1Qucm90YXRpb25ZOlwic2hvcnRSb3RhdGlvbllcImluIFQ/VC5zaG9ydFJvdGF0aW9uWStcIl9zaG9ydFwiOm0ucm90YXRpb25ZfHwwLG0ucm90YXRpb25ZLFwicm90YXRpb25ZXCIsdykpLGguc2tld1g9bnVsbD09VC5za2V3WD9tLnNrZXdYOnNlKFQuc2tld1gsbS5za2V3WCksaC5za2V3WT1udWxsPT1ULnNrZXdZP20uc2tld1k6c2UoVC5za2V3WSxtLnNrZXdZKSwodT1oLnNrZXdZLW0uc2tld1kpJiYoaC5za2V3WCs9dSxoLnJvdGF0aW9uKz11KX1mb3IoeGUmJm51bGwhPVQuZm9yY2UzRCYmKG0uZm9yY2UzRD1ULmZvcmNlM0QsYz0hMCksbS5za2V3VHlwZT1ULnNrZXdUeXBlfHxtLnNrZXdUeXBlfHxhLmRlZmF1bHRTa2V3VHlwZSxwPW0uZm9yY2UzRHx8bS56fHxtLnJvdGF0aW9uWHx8bS5yb3RhdGlvbll8fGguenx8aC5yb3RhdGlvblh8fGgucm90YXRpb25ZfHxoLnBlcnNwZWN0aXZlLHB8fG51bGw9PVQuc2NhbGV8fChoLnNjYWxlWj0xKTstLXk+LTE7KWk9dmVbeV0sXz1oW2ldLW1baV0sKF8+dnx8LXY+X3x8bnVsbCE9TltpXSkmJihjPSEwLG49bmV3IF9lKG0saSxtW2ldLF8sbiksaSBpbiB3JiYobi5lPXdbaV0pLG4ueHMwPTAsbi5wbHVnaW49byxyLl9vdmVyd3JpdGVQcm9wcy5wdXNoKG4ubikpO3JldHVybiBfPVQudHJhbnNmb3JtT3JpZ2luLChffHx4ZSYmcCYmbS56T3JpZ2luKSYmKHllPyhjPSEwLGk9d2UsXz0oX3x8cSh0LGkscywhMSxcIjUwJSA1MCVcIikpK1wiXCIsbj1uZXcgX2UoZyxpLDAsMCxuLC0xLFwidHJhbnNmb3JtT3JpZ2luXCIpLG4uYj1nW2ldLG4ucGx1Z2luPW8seGU/KGY9bS56T3JpZ2luLF89Xy5zcGxpdChcIiBcIiksbS56T3JpZ2luPShfLmxlbmd0aD4yJiYoMD09PWZ8fFwiMHB4XCIhPT1fWzJdKT9wYXJzZUZsb2F0KF9bMl0pOmYpfHwwLG4ueHMwPW4uZT1fWzBdK1wiIFwiKyhfWzFdfHxcIjUwJVwiKStcIiAwcHhcIixuPW5ldyBfZShtLFwiek9yaWdpblwiLDAsMCxuLC0xLG4ubiksbi5iPWYsbi54czA9bi5lPW0uek9yaWdpbik6bi54czA9bi5lPV8pOmVlKF8rXCJcIixtKSksYyYmKHIuX3RyYW5zZm9ybVR5cGU9cHx8Mz09PXRoaXMuX3RyYW5zZm9ybVR5cGU/MzoyKSxufSxwcmVmaXg6ITB9KSxtZShcImJveFNoYWRvd1wiLHtkZWZhdWx0VmFsdWU6XCIwcHggMHB4IDBweCAwcHggIzk5OVwiLHByZWZpeDohMCxjb2xvcjohMCxtdWx0aTohMCxrZXl3b3JkOlwiaW5zZXRcIn0pLG1lKFwiYm9yZGVyUmFkaXVzXCIse2RlZmF1bHRWYWx1ZTpcIjBweFwiLHBhcnNlcjpmdW5jdGlvbih0LGUsaSxuLGEpe2U9dGhpcy5mb3JtYXQoZSk7dmFyIG8sbCxoLHUsZixfLHAsYyxkLG0sZyx2LHksVCx3LHgsYj1bXCJib3JkZXJUb3BMZWZ0UmFkaXVzXCIsXCJib3JkZXJUb3BSaWdodFJhZGl1c1wiLFwiYm9yZGVyQm90dG9tUmlnaHRSYWRpdXNcIixcImJvcmRlckJvdHRvbUxlZnRSYWRpdXNcIl0sUD10LnN0eWxlO2ZvcihkPXBhcnNlRmxvYXQodC5vZmZzZXRXaWR0aCksbT1wYXJzZUZsb2F0KHQub2Zmc2V0SGVpZ2h0KSxvPWUuc3BsaXQoXCIgXCIpLGw9MDtiLmxlbmd0aD5sO2wrKyl0aGlzLnAuaW5kZXhPZihcImJvcmRlclwiKSYmKGJbbF09VihiW2xdKSksZj11PXEodCxiW2xdLHMsITEsXCIwcHhcIiksLTEhPT1mLmluZGV4T2YoXCIgXCIpJiYodT1mLnNwbGl0KFwiIFwiKSxmPXVbMF0sdT11WzFdKSxfPWg9b1tsXSxwPXBhcnNlRmxvYXQoZiksdj1mLnN1YnN0cigocCtcIlwiKS5sZW5ndGgpLHk9XCI9XCI9PT1fLmNoYXJBdCgxKSx5PyhjPXBhcnNlSW50KF8uY2hhckF0KDApK1wiMVwiLDEwKSxfPV8uc3Vic3RyKDIpLGMqPXBhcnNlRmxvYXQoXyksZz1fLnN1YnN0cigoYytcIlwiKS5sZW5ndGgtKDA+Yz8xOjApKXx8XCJcIik6KGM9cGFyc2VGbG9hdChfKSxnPV8uc3Vic3RyKChjK1wiXCIpLmxlbmd0aCkpLFwiXCI9PT1nJiYoZz1yW2ldfHx2KSxnIT09diYmKFQ9USh0LFwiYm9yZGVyTGVmdFwiLHAsdiksdz1RKHQsXCJib3JkZXJUb3BcIixwLHYpLFwiJVwiPT09Zz8oZj0xMDAqKFQvZCkrXCIlXCIsdT0xMDAqKHcvbSkrXCIlXCIpOlwiZW1cIj09PWc/KHg9USh0LFwiYm9yZGVyTGVmdFwiLDEsXCJlbVwiKSxmPVQveCtcImVtXCIsdT13L3grXCJlbVwiKTooZj1UK1wicHhcIix1PXcrXCJweFwiKSx5JiYoXz1wYXJzZUZsb2F0KGYpK2MrZyxoPXBhcnNlRmxvYXQodSkrYytnKSksYT1wZShQLGJbbF0sZitcIiBcIit1LF8rXCIgXCIraCwhMSxcIjBweFwiLGEpO3JldHVybiBhfSxwcmVmaXg6ITAsZm9ybWF0dGVyOmhlKFwiMHB4IDBweCAwcHggMHB4XCIsITEsITApfSksbWUoXCJiYWNrZ3JvdW5kUG9zaXRpb25cIix7ZGVmYXVsdFZhbHVlOlwiMCAwXCIscGFyc2VyOmZ1bmN0aW9uKHQsZSxpLHIsbixhKXt2YXIgbyxsLGgsdSxmLF8scD1cImJhY2tncm91bmQtcG9zaXRpb25cIixkPXN8fEgodCxudWxsKSxtPXRoaXMuZm9ybWF0KChkP2M/ZC5nZXRQcm9wZXJ0eVZhbHVlKHArXCIteFwiKStcIiBcIitkLmdldFByb3BlcnR5VmFsdWUocCtcIi15XCIpOmQuZ2V0UHJvcGVydHlWYWx1ZShwKTp0LmN1cnJlbnRTdHlsZS5iYWNrZ3JvdW5kUG9zaXRpb25YK1wiIFwiK3QuY3VycmVudFN0eWxlLmJhY2tncm91bmRQb3NpdGlvblkpfHxcIjAgMFwiKSxnPXRoaXMuZm9ybWF0KGUpO2lmKC0xIT09bS5pbmRleE9mKFwiJVwiKSE9KC0xIT09Zy5pbmRleE9mKFwiJVwiKSkmJihfPXEodCxcImJhY2tncm91bmRJbWFnZVwiKS5yZXBsYWNlKEMsXCJcIiksXyYmXCJub25lXCIhPT1fKSl7Zm9yKG89bS5zcGxpdChcIiBcIiksbD1nLnNwbGl0KFwiIFwiKSxJLnNldEF0dHJpYnV0ZShcInNyY1wiLF8pLGg9MjstLWg+LTE7KW09b1toXSx1PS0xIT09bS5pbmRleE9mKFwiJVwiKSx1IT09KC0xIT09bFtoXS5pbmRleE9mKFwiJVwiKSkmJihmPTA9PT1oP3Qub2Zmc2V0V2lkdGgtSS53aWR0aDp0Lm9mZnNldEhlaWdodC1JLmhlaWdodCxvW2hdPXU/cGFyc2VGbG9hdChtKS8xMDAqZitcInB4XCI6MTAwKihwYXJzZUZsb2F0KG0pL2YpK1wiJVwiKTttPW8uam9pbihcIiBcIil9cmV0dXJuIHRoaXMucGFyc2VDb21wbGV4KHQuc3R5bGUsbSxnLG4sYSl9LGZvcm1hdHRlcjplZX0pLG1lKFwiYmFja2dyb3VuZFNpemVcIix7ZGVmYXVsdFZhbHVlOlwiMCAwXCIsZm9ybWF0dGVyOmVlfSksbWUoXCJwZXJzcGVjdGl2ZVwiLHtkZWZhdWx0VmFsdWU6XCIwcHhcIixwcmVmaXg6ITB9KSxtZShcInBlcnNwZWN0aXZlT3JpZ2luXCIse2RlZmF1bHRWYWx1ZTpcIjUwJSA1MCVcIixwcmVmaXg6ITB9KSxtZShcInRyYW5zZm9ybVN0eWxlXCIse3ByZWZpeDohMH0pLG1lKFwiYmFja2ZhY2VWaXNpYmlsaXR5XCIse3ByZWZpeDohMH0pLG1lKFwidXNlclNlbGVjdFwiLHtwcmVmaXg6ITB9KSxtZShcIm1hcmdpblwiLHtwYXJzZXI6dWUoXCJtYXJnaW5Ub3AsbWFyZ2luUmlnaHQsbWFyZ2luQm90dG9tLG1hcmdpbkxlZnRcIil9KSxtZShcInBhZGRpbmdcIix7cGFyc2VyOnVlKFwicGFkZGluZ1RvcCxwYWRkaW5nUmlnaHQscGFkZGluZ0JvdHRvbSxwYWRkaW5nTGVmdFwiKX0pLG1lKFwiY2xpcFwiLHtkZWZhdWx0VmFsdWU6XCJyZWN0KDBweCwwcHgsMHB4LDBweClcIixwYXJzZXI6ZnVuY3Rpb24odCxlLGkscixuLGEpe3ZhciBvLGwsaDtyZXR1cm4gOT5jPyhsPXQuY3VycmVudFN0eWxlLGg9OD5jP1wiIFwiOlwiLFwiLG89XCJyZWN0KFwiK2wuY2xpcFRvcCtoK2wuY2xpcFJpZ2h0K2grbC5jbGlwQm90dG9tK2grbC5jbGlwTGVmdCtcIilcIixlPXRoaXMuZm9ybWF0KGUpLnNwbGl0KFwiLFwiKS5qb2luKGgpKToobz10aGlzLmZvcm1hdChxKHQsdGhpcy5wLHMsITEsdGhpcy5kZmx0KSksZT10aGlzLmZvcm1hdChlKSksdGhpcy5wYXJzZUNvbXBsZXgodC5zdHlsZSxvLGUsbixhKX19KSxtZShcInRleHRTaGFkb3dcIix7ZGVmYXVsdFZhbHVlOlwiMHB4IDBweCAwcHggIzk5OVwiLGNvbG9yOiEwLG11bHRpOiEwfSksbWUoXCJhdXRvUm91bmQsc3RyaWN0VW5pdHNcIix7cGFyc2VyOmZ1bmN0aW9uKHQsZSxpLHIscyl7cmV0dXJuIHN9fSksbWUoXCJib3JkZXJcIix7ZGVmYXVsdFZhbHVlOlwiMHB4IHNvbGlkICMwMDBcIixwYXJzZXI6ZnVuY3Rpb24odCxlLGkscixuLGEpe3JldHVybiB0aGlzLnBhcnNlQ29tcGxleCh0LnN0eWxlLHRoaXMuZm9ybWF0KHEodCxcImJvcmRlclRvcFdpZHRoXCIscywhMSxcIjBweFwiKStcIiBcIitxKHQsXCJib3JkZXJUb3BTdHlsZVwiLHMsITEsXCJzb2xpZFwiKStcIiBcIitxKHQsXCJib3JkZXJUb3BDb2xvclwiLHMsITEsXCIjMDAwXCIpKSx0aGlzLmZvcm1hdChlKSxuLGEpfSxjb2xvcjohMCxmb3JtYXR0ZXI6ZnVuY3Rpb24odCl7dmFyIGU9dC5zcGxpdChcIiBcIik7cmV0dXJuIGVbMF0rXCIgXCIrKGVbMV18fFwic29saWRcIikrXCIgXCIrKHQubWF0Y2gobGUpfHxbXCIjMDAwXCJdKVswXX19KSxtZShcImJvcmRlcldpZHRoXCIse3BhcnNlcjp1ZShcImJvcmRlclRvcFdpZHRoLGJvcmRlclJpZ2h0V2lkdGgsYm9yZGVyQm90dG9tV2lkdGgsYm9yZGVyTGVmdFdpZHRoXCIpfSksbWUoXCJmbG9hdCxjc3NGbG9hdCxzdHlsZUZsb2F0XCIse3BhcnNlcjpmdW5jdGlvbih0LGUsaSxyLHMpe3ZhciBuPXQuc3R5bGUsYT1cImNzc0Zsb2F0XCJpbiBuP1wiY3NzRmxvYXRcIjpcInN0eWxlRmxvYXRcIjtyZXR1cm4gbmV3IF9lKG4sYSwwLDAscywtMSxpLCExLDAsblthXSxlKX19KTt2YXIga2U9ZnVuY3Rpb24odCl7dmFyIGUsaT10aGlzLnQscj1pLmZpbHRlcnx8cSh0aGlzLmRhdGEsXCJmaWx0ZXJcIikscz0wfHRoaXMucyt0aGlzLmMqdDsxMDA9PT1zJiYoLTE9PT1yLmluZGV4T2YoXCJhdHJpeChcIikmJi0xPT09ci5pbmRleE9mKFwicmFkaWVudChcIikmJi0xPT09ci5pbmRleE9mKFwib2FkZXIoXCIpPyhpLnJlbW92ZUF0dHJpYnV0ZShcImZpbHRlclwiKSxlPSFxKHRoaXMuZGF0YSxcImZpbHRlclwiKSk6KGkuZmlsdGVyPXIucmVwbGFjZSh4LFwiXCIpLGU9ITApKSxlfHwodGhpcy54bjEmJihpLmZpbHRlcj1yPXJ8fFwiYWxwaGEob3BhY2l0eT1cIitzK1wiKVwiKSwtMT09PXIuaW5kZXhPZihcInBhY2l0eVwiKT8wPT09cyYmdGhpcy54bjF8fChpLmZpbHRlcj1yK1wiIGFscGhhKG9wYWNpdHk9XCIrcytcIilcIik6aS5maWx0ZXI9ci5yZXBsYWNlKFQsXCJvcGFjaXR5PVwiK3MpKX07bWUoXCJvcGFjaXR5LGFscGhhLGF1dG9BbHBoYVwiLHtkZWZhdWx0VmFsdWU6XCIxXCIscGFyc2VyOmZ1bmN0aW9uKHQsZSxpLHIsbixhKXt2YXIgbz1wYXJzZUZsb2F0KHEodCxcIm9wYWNpdHlcIixzLCExLFwiMVwiKSksbD10LnN0eWxlLGg9XCJhdXRvQWxwaGFcIj09PWk7cmV0dXJuXCJzdHJpbmdcIj09dHlwZW9mIGUmJlwiPVwiPT09ZS5jaGFyQXQoMSkmJihlPShcIi1cIj09PWUuY2hhckF0KDApPy0xOjEpKnBhcnNlRmxvYXQoZS5zdWJzdHIoMikpK28pLGgmJjE9PT1vJiZcImhpZGRlblwiPT09cSh0LFwidmlzaWJpbGl0eVwiLHMpJiYwIT09ZSYmKG89MCksWT9uPW5ldyBfZShsLFwib3BhY2l0eVwiLG8sZS1vLG4pOihuPW5ldyBfZShsLFwib3BhY2l0eVwiLDEwMCpvLDEwMCooZS1vKSxuKSxuLnhuMT1oPzE6MCxsLnpvb209MSxuLnR5cGU9MixuLmI9XCJhbHBoYShvcGFjaXR5PVwiK24ucytcIilcIixuLmU9XCJhbHBoYShvcGFjaXR5PVwiKyhuLnMrbi5jKStcIilcIixuLmRhdGE9dCxuLnBsdWdpbj1hLG4uc2V0UmF0aW89a2UpLGgmJihuPW5ldyBfZShsLFwidmlzaWJpbGl0eVwiLDAsMCxuLC0xLG51bGwsITEsMCwwIT09bz9cImluaGVyaXRcIjpcImhpZGRlblwiLDA9PT1lP1wiaGlkZGVuXCI6XCJpbmhlcml0XCIpLG4ueHMwPVwiaW5oZXJpdFwiLHIuX292ZXJ3cml0ZVByb3BzLnB1c2gobi5uKSxyLl9vdmVyd3JpdGVQcm9wcy5wdXNoKGkpKSxufX0pO3ZhciBBZT1mdW5jdGlvbih0LGUpe2UmJih0LnJlbW92ZVByb3BlcnR5PyhcIm1zXCI9PT1lLnN1YnN0cigwLDIpJiYoZT1cIk1cIitlLnN1YnN0cigxKSksdC5yZW1vdmVQcm9wZXJ0eShlLnJlcGxhY2UoUCxcIi0kMVwiKS50b0xvd2VyQ2FzZSgpKSk6dC5yZW1vdmVBdHRyaWJ1dGUoZSkpfSxPZT1mdW5jdGlvbih0KXtpZih0aGlzLnQuX2dzQ2xhc3NQVD10aGlzLDE9PT10fHwwPT09dCl7dGhpcy50LnNldEF0dHJpYnV0ZShcImNsYXNzXCIsMD09PXQ/dGhpcy5iOnRoaXMuZSk7Zm9yKHZhciBlPXRoaXMuZGF0YSxpPXRoaXMudC5zdHlsZTtlOyllLnY/aVtlLnBdPWUudjpBZShpLGUucCksZT1lLl9uZXh0OzE9PT10JiZ0aGlzLnQuX2dzQ2xhc3NQVD09PXRoaXMmJih0aGlzLnQuX2dzQ2xhc3NQVD1udWxsKX1lbHNlIHRoaXMudC5nZXRBdHRyaWJ1dGUoXCJjbGFzc1wiKSE9PXRoaXMuZSYmdGhpcy50LnNldEF0dHJpYnV0ZShcImNsYXNzXCIsdGhpcy5lKX07bWUoXCJjbGFzc05hbWVcIix7cGFyc2VyOmZ1bmN0aW9uKHQsZSxyLG4sYSxvLGwpe3ZhciBoLHUsZixfLHAsYz10LmdldEF0dHJpYnV0ZShcImNsYXNzXCIpfHxcIlwiLGQ9dC5zdHlsZS5jc3NUZXh0O2lmKGE9bi5fY2xhc3NOYW1lUFQ9bmV3IF9lKHQsciwwLDAsYSwyKSxhLnNldFJhdGlvPU9lLGEucHI9LTExLGk9ITAsYS5iPWMsdT0kKHQscyksZj10Ll9nc0NsYXNzUFQpe2ZvcihfPXt9LHA9Zi5kYXRhO3A7KV9bcC5wXT0xLHA9cC5fbmV4dDtmLnNldFJhdGlvKDEpfXJldHVybiB0Ll9nc0NsYXNzUFQ9YSxhLmU9XCI9XCIhPT1lLmNoYXJBdCgxKT9lOmMucmVwbGFjZShSZWdFeHAoXCJcXFxccypcXFxcYlwiK2Uuc3Vic3RyKDIpK1wiXFxcXGJcIiksXCJcIikrKFwiK1wiPT09ZS5jaGFyQXQoMCk/XCIgXCIrZS5zdWJzdHIoMik6XCJcIiksbi5fdHdlZW4uX2R1cmF0aW9uJiYodC5zZXRBdHRyaWJ1dGUoXCJjbGFzc1wiLGEuZSksaD1HKHQsdSwkKHQpLGwsXyksdC5zZXRBdHRyaWJ1dGUoXCJjbGFzc1wiLGMpLGEuZGF0YT1oLmZpcnN0TVBULHQuc3R5bGUuY3NzVGV4dD1kLGE9YS54Zmlyc3Q9bi5wYXJzZSh0LGguZGlmcyxhLG8pKSxhfX0pO3ZhciBEZT1mdW5jdGlvbih0KXtpZigoMT09PXR8fDA9PT10KSYmdGhpcy5kYXRhLl90b3RhbFRpbWU9PT10aGlzLmRhdGEuX3RvdGFsRHVyYXRpb24mJlwiaXNGcm9tU3RhcnRcIiE9PXRoaXMuZGF0YS5kYXRhKXt2YXIgZSxpLHIscyxuPXRoaXMudC5zdHlsZSxhPW8udHJhbnNmb3JtLnBhcnNlO2lmKFwiYWxsXCI9PT10aGlzLmUpbi5jc3NUZXh0PVwiXCIscz0hMDtlbHNlIGZvcihlPXRoaXMuZS5zcGxpdChcIixcIikscj1lLmxlbmd0aDstLXI+LTE7KWk9ZVtyXSxvW2ldJiYob1tpXS5wYXJzZT09PWE/cz0hMDppPVwidHJhbnNmb3JtT3JpZ2luXCI9PT1pP3dlOm9baV0ucCksQWUobixpKTtzJiYoQWUobix5ZSksdGhpcy50Ll9nc1RyYW5zZm9ybSYmZGVsZXRlIHRoaXMudC5fZ3NUcmFuc2Zvcm0pfX07Zm9yKG1lKFwiY2xlYXJQcm9wc1wiLHtwYXJzZXI6ZnVuY3Rpb24odCxlLHIscyxuKXtyZXR1cm4gbj1uZXcgX2UodCxyLDAsMCxuLDIpLG4uc2V0UmF0aW89RGUsbi5lPWUsbi5wcj0tMTAsbi5kYXRhPXMuX3R3ZWVuLGk9ITAsbn19KSxsPVwiYmV6aWVyLHRocm93UHJvcHMscGh5c2ljc1Byb3BzLHBoeXNpY3MyRFwiLnNwbGl0KFwiLFwiKSxjZT1sLmxlbmd0aDtjZS0tOylnZShsW2NlXSk7bD1hLnByb3RvdHlwZSxsLl9maXJzdFBUPW51bGwsbC5fb25Jbml0VHdlZW49ZnVuY3Rpb24odCxlLG8pe2lmKCF0Lm5vZGVUeXBlKXJldHVybiExO3RoaXMuX3RhcmdldD10LHRoaXMuX3R3ZWVuPW8sdGhpcy5fdmFycz1lLGg9ZS5hdXRvUm91bmQsaT0hMSxyPWUuc3VmZml4TWFwfHxhLnN1ZmZpeE1hcCxzPUgodCxcIlwiKSxuPXRoaXMuX292ZXJ3cml0ZVByb3BzO3ZhciBsLF8sYyxkLG0sZyx2LHksVCx4PXQuc3R5bGU7aWYodSYmXCJcIj09PXguekluZGV4JiYobD1xKHQsXCJ6SW5kZXhcIixzKSwoXCJhdXRvXCI9PT1sfHxcIlwiPT09bCkmJnRoaXMuX2FkZExhenlTZXQoeCxcInpJbmRleFwiLDApKSxcInN0cmluZ1wiPT10eXBlb2YgZSYmKGQ9eC5jc3NUZXh0LGw9JCh0LHMpLHguY3NzVGV4dD1kK1wiO1wiK2UsbD1HKHQsbCwkKHQpKS5kaWZzLCFZJiZ3LnRlc3QoZSkmJihsLm9wYWNpdHk9cGFyc2VGbG9hdChSZWdFeHAuJDEpKSxlPWwseC5jc3NUZXh0PWQpLHRoaXMuX2ZpcnN0UFQ9Xz10aGlzLnBhcnNlKHQsZSxudWxsKSx0aGlzLl90cmFuc2Zvcm1UeXBlKXtmb3IoVD0zPT09dGhpcy5fdHJhbnNmb3JtVHlwZSx5ZT9mJiYodT0hMCxcIlwiPT09eC56SW5kZXgmJih2PXEodCxcInpJbmRleFwiLHMpLChcImF1dG9cIj09PXZ8fFwiXCI9PT12KSYmdGhpcy5fYWRkTGF6eVNldCh4LFwiekluZGV4XCIsMCkpLHAmJnRoaXMuX2FkZExhenlTZXQoeCxcIldlYmtpdEJhY2tmYWNlVmlzaWJpbGl0eVwiLHRoaXMuX3ZhcnMuV2Via2l0QmFja2ZhY2VWaXNpYmlsaXR5fHwoVD9cInZpc2libGVcIjpcImhpZGRlblwiKSkpOnguem9vbT0xLGM9XztjJiZjLl9uZXh0OyljPWMuX25leHQ7eT1uZXcgX2UodCxcInRyYW5zZm9ybVwiLDAsMCxudWxsLDIpLHRoaXMuX2xpbmtDU1NQKHksbnVsbCxjKSx5LnNldFJhdGlvPVQmJnhlP0NlOnllP1JlOlNlLHkuZGF0YT10aGlzLl90cmFuc2Zvcm18fFBlKHQscywhMCksbi5wb3AoKX1pZihpKXtmb3IoO187KXtmb3IoZz1fLl9uZXh0LGM9ZDtjJiZjLnByPl8ucHI7KWM9Yy5fbmV4dDsoXy5fcHJldj1jP2MuX3ByZXY6bSk/Xy5fcHJldi5fbmV4dD1fOmQ9XywoXy5fbmV4dD1jKT9jLl9wcmV2PV86bT1fLF89Z310aGlzLl9maXJzdFBUPWR9cmV0dXJuITB9LGwucGFyc2U9ZnVuY3Rpb24odCxlLGksbil7dmFyIGEsbCx1LGYsXyxwLGMsZCxtLGcsdj10LnN0eWxlO2ZvcihhIGluIGUpcD1lW2FdLGw9b1thXSxsP2k9bC5wYXJzZSh0LHAsYSx0aGlzLGksbixlKTooXz1xKHQsYSxzKStcIlwiLG09XCJzdHJpbmdcIj09dHlwZW9mIHAsXCJjb2xvclwiPT09YXx8XCJmaWxsXCI9PT1hfHxcInN0cm9rZVwiPT09YXx8LTEhPT1hLmluZGV4T2YoXCJDb2xvclwiKXx8bSYmYi50ZXN0KHApPyhtfHwocD1vZShwKSxwPShwLmxlbmd0aD4zP1wicmdiYShcIjpcInJnYihcIikrcC5qb2luKFwiLFwiKStcIilcIiksaT1wZSh2LGEsXyxwLCEwLFwidHJhbnNwYXJlbnRcIixpLDAsbikpOiFtfHwtMT09PXAuaW5kZXhPZihcIiBcIikmJi0xPT09cC5pbmRleE9mKFwiLFwiKT8odT1wYXJzZUZsb2F0KF8pLGM9dXx8MD09PXU/Xy5zdWJzdHIoKHUrXCJcIikubGVuZ3RoKTpcIlwiLChcIlwiPT09X3x8XCJhdXRvXCI9PT1fKSYmKFwid2lkdGhcIj09PWF8fFwiaGVpZ2h0XCI9PT1hPyh1PXRlKHQsYSxzKSxjPVwicHhcIik6XCJsZWZ0XCI9PT1hfHxcInRvcFwiPT09YT8odT1aKHQsYSxzKSxjPVwicHhcIik6KHU9XCJvcGFjaXR5XCIhPT1hPzA6MSxjPVwiXCIpKSxnPW0mJlwiPVwiPT09cC5jaGFyQXQoMSksZz8oZj1wYXJzZUludChwLmNoYXJBdCgwKStcIjFcIiwxMCkscD1wLnN1YnN0cigyKSxmKj1wYXJzZUZsb2F0KHApLGQ9cC5yZXBsYWNlKHksXCJcIikpOihmPXBhcnNlRmxvYXQocCksZD1tP3Auc3Vic3RyKChmK1wiXCIpLmxlbmd0aCl8fFwiXCI6XCJcIiksXCJcIj09PWQmJihkPWEgaW4gcj9yW2FdOmMpLHA9Znx8MD09PWY/KGc/Zit1OmYpK2Q6ZVthXSxjIT09ZCYmXCJcIiE9PWQmJihmfHwwPT09ZikmJnUmJih1PVEodCxhLHUsYyksXCIlXCI9PT1kPyh1Lz1RKHQsYSwxMDAsXCIlXCIpLzEwMCxlLnN0cmljdFVuaXRzIT09ITAmJihfPXUrXCIlXCIpKTpcImVtXCI9PT1kP3UvPVEodCxhLDEsXCJlbVwiKTpcInB4XCIhPT1kJiYoZj1RKHQsYSxmLGQpLGQ9XCJweFwiKSxnJiYoZnx8MD09PWYpJiYocD1mK3UrZCkpLGcmJihmKz11KSwhdSYmMCE9PXV8fCFmJiYwIT09Zj92b2lkIDAhPT12W2FdJiYocHx8XCJOYU5cIiE9cCtcIlwiJiZudWxsIT1wKT8oaT1uZXcgX2UodixhLGZ8fHV8fDAsMCxpLC0xLGEsITEsMCxfLHApLGkueHMwPVwibm9uZVwiIT09cHx8XCJkaXNwbGF5XCIhPT1hJiYtMT09PWEuaW5kZXhPZihcIlN0eWxlXCIpP3A6Xyk6VShcImludmFsaWQgXCIrYStcIiB0d2VlbiB2YWx1ZTogXCIrZVthXSk6KGk9bmV3IF9lKHYsYSx1LGYtdSxpLDAsYSxoIT09ITEmJihcInB4XCI9PT1kfHxcInpJbmRleFwiPT09YSksMCxfLHApLGkueHMwPWQpKTppPXBlKHYsYSxfLHAsITAsbnVsbCxpLDAsbikpLG4mJmkmJiFpLnBsdWdpbiYmKGkucGx1Z2luPW4pO3JldHVybiBpfSxsLnNldFJhdGlvPWZ1bmN0aW9uKHQpe3ZhciBlLGkscixzPXRoaXMuX2ZpcnN0UFQsbj0xZS02O2lmKDEhPT10fHx0aGlzLl90d2Vlbi5fdGltZSE9PXRoaXMuX3R3ZWVuLl9kdXJhdGlvbiYmMCE9PXRoaXMuX3R3ZWVuLl90aW1lKWlmKHR8fHRoaXMuX3R3ZWVuLl90aW1lIT09dGhpcy5fdHdlZW4uX2R1cmF0aW9uJiYwIT09dGhpcy5fdHdlZW4uX3RpbWV8fHRoaXMuX3R3ZWVuLl9yYXdQcmV2VGltZT09PS0xZS02KWZvcig7czspe2lmKGU9cy5jKnQrcy5zLHMucj9lPU1hdGgucm91bmQoZSk6bj5lJiZlPi1uJiYoZT0wKSxzLnR5cGUpaWYoMT09PXMudHlwZSlpZihyPXMubCwyPT09cilzLnRbcy5wXT1zLnhzMCtlK3MueHMxK3MueG4xK3MueHMyO2Vsc2UgaWYoMz09PXIpcy50W3MucF09cy54czArZStzLnhzMStzLnhuMStzLnhzMitzLnhuMitzLnhzMztlbHNlIGlmKDQ9PT1yKXMudFtzLnBdPXMueHMwK2Urcy54czErcy54bjErcy54czIrcy54bjIrcy54czMrcy54bjMrcy54czQ7ZWxzZSBpZig1PT09cilzLnRbcy5wXT1zLnhzMCtlK3MueHMxK3MueG4xK3MueHMyK3MueG4yK3MueHMzK3MueG4zK3MueHM0K3MueG40K3MueHM1O2Vsc2V7Zm9yKGk9cy54czArZStzLnhzMSxyPTE7cy5sPnI7cisrKWkrPXNbXCJ4blwiK3JdK3NbXCJ4c1wiKyhyKzEpXTtzLnRbcy5wXT1pfWVsc2UtMT09PXMudHlwZT9zLnRbcy5wXT1zLnhzMDpzLnNldFJhdGlvJiZzLnNldFJhdGlvKHQpO2Vsc2Ugcy50W3MucF09ZStzLnhzMDtzPXMuX25leHR9ZWxzZSBmb3IoO3M7KTIhPT1zLnR5cGU/cy50W3MucF09cy5iOnMuc2V0UmF0aW8odCkscz1zLl9uZXh0O2Vsc2UgZm9yKDtzOykyIT09cy50eXBlP3MudFtzLnBdPXMuZTpzLnNldFJhdGlvKHQpLHM9cy5fbmV4dH0sbC5fZW5hYmxlVHJhbnNmb3Jtcz1mdW5jdGlvbih0KXt0aGlzLl90cmFuc2Zvcm1UeXBlPXR8fDM9PT10aGlzLl90cmFuc2Zvcm1UeXBlPzM6Mix0aGlzLl90cmFuc2Zvcm09dGhpcy5fdHJhbnNmb3JtfHxQZSh0aGlzLl90YXJnZXQscywhMCl9O3ZhciBNZT1mdW5jdGlvbigpe3RoaXMudFt0aGlzLnBdPXRoaXMuZSx0aGlzLmRhdGEuX2xpbmtDU1NQKHRoaXMsdGhpcy5fbmV4dCxudWxsLCEwKX07bC5fYWRkTGF6eVNldD1mdW5jdGlvbih0LGUsaSl7dmFyIHI9dGhpcy5fZmlyc3RQVD1uZXcgX2UodCxlLDAsMCx0aGlzLl9maXJzdFBULDIpO3IuZT1pLHIuc2V0UmF0aW89TWUsci5kYXRhPXRoaXN9LGwuX2xpbmtDU1NQPWZ1bmN0aW9uKHQsZSxpLHIpe3JldHVybiB0JiYoZSYmKGUuX3ByZXY9dCksdC5fbmV4dCYmKHQuX25leHQuX3ByZXY9dC5fcHJldiksdC5fcHJldj90Ll9wcmV2Ll9uZXh0PXQuX25leHQ6dGhpcy5fZmlyc3RQVD09PXQmJih0aGlzLl9maXJzdFBUPXQuX25leHQscj0hMCksaT9pLl9uZXh0PXQ6cnx8bnVsbCE9PXRoaXMuX2ZpcnN0UFR8fCh0aGlzLl9maXJzdFBUPXQpLHQuX25leHQ9ZSx0Ll9wcmV2PWkpLHR9LGwuX2tpbGw9ZnVuY3Rpb24oZSl7dmFyIGkscixzLG49ZTtpZihlLmF1dG9BbHBoYXx8ZS5hbHBoYSl7bj17fTtmb3IociBpbiBlKW5bcl09ZVtyXTtuLm9wYWNpdHk9MSxuLmF1dG9BbHBoYSYmKG4udmlzaWJpbGl0eT0xKX1yZXR1cm4gZS5jbGFzc05hbWUmJihpPXRoaXMuX2NsYXNzTmFtZVBUKSYmKHM9aS54Zmlyc3QscyYmcy5fcHJldj90aGlzLl9saW5rQ1NTUChzLl9wcmV2LGkuX25leHQscy5fcHJldi5fcHJldik6cz09PXRoaXMuX2ZpcnN0UFQmJih0aGlzLl9maXJzdFBUPWkuX25leHQpLGkuX25leHQmJnRoaXMuX2xpbmtDU1NQKGkuX25leHQsaS5fbmV4dC5fbmV4dCxzLl9wcmV2KSx0aGlzLl9jbGFzc05hbWVQVD1udWxsKSx0LnByb3RvdHlwZS5fa2lsbC5jYWxsKHRoaXMsbil9O3ZhciBMZT1mdW5jdGlvbih0LGUsaSl7dmFyIHIscyxuLGE7aWYodC5zbGljZSlmb3Iocz10Lmxlbmd0aDstLXM+LTE7KUxlKHRbc10sZSxpKTtlbHNlIGZvcihyPXQuY2hpbGROb2RlcyxzPXIubGVuZ3RoOy0tcz4tMTspbj1yW3NdLGE9bi50eXBlLG4uc3R5bGUmJihlLnB1c2goJChuKSksaSYmaS5wdXNoKG4pKSwxIT09YSYmOSE9PWEmJjExIT09YXx8IW4uY2hpbGROb2Rlcy5sZW5ndGh8fExlKG4sZSxpKX07cmV0dXJuIGEuY2FzY2FkZVRvPWZ1bmN0aW9uKHQsaSxyKXt2YXIgcyxuLGEsbz1lLnRvKHQsaSxyKSxsPVtvXSxoPVtdLHU9W10sZj1bXSxfPWUuX2ludGVybmFscy5yZXNlcnZlZFByb3BzO2Zvcih0PW8uX3RhcmdldHN8fG8udGFyZ2V0LExlKHQsaCxmKSxvLnJlbmRlcihpLCEwKSxMZSh0LHUpLG8ucmVuZGVyKDAsITApLG8uX2VuYWJsZWQoITApLHM9Zi5sZW5ndGg7LS1zPi0xOylpZihuPUcoZltzXSxoW3NdLHVbc10pLG4uZmlyc3RNUFQpe249bi5kaWZzO1xyXG5mb3IoYSBpbiByKV9bYV0mJihuW2FdPXJbYV0pO2wucHVzaChlLnRvKGZbc10saSxuKSl9cmV0dXJuIGx9LHQuYWN0aXZhdGUoW2FdKSxhfSwhMCl9KSx3aW5kb3cuX2dzRGVmaW5lJiZ3aW5kb3cuX2dzUXVldWUucG9wKCkoKTsiLCIvKiFcclxuICogVkVSU0lPTjogMS43LjNcclxuICogREFURTogMjAxNC0wMS0xNFxyXG4gKiBVUERBVEVTIEFORCBET0NTIEFUOiBodHRwOi8vd3d3LmdyZWVuc29jay5jb21cclxuICpcclxuICogQGxpY2Vuc2UgQ29weXJpZ2h0IChjKSAyMDA4LTIwMTQsIEdyZWVuU29jay4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuICogVGhpcyB3b3JrIGlzIHN1YmplY3QgdG8gdGhlIHRlcm1zIGF0IGh0dHA6Ly93d3cuZ3JlZW5zb2NrLmNvbS90ZXJtc19vZl91c2UuaHRtbCBvciBmb3JcclxuICogQ2x1YiBHcmVlblNvY2sgbWVtYmVycywgdGhlIHNvZnR3YXJlIGFncmVlbWVudCB0aGF0IHdhcyBpc3N1ZWQgd2l0aCB5b3VyIG1lbWJlcnNoaXAuXHJcbiAqIFxyXG4gKiBAYXV0aG9yOiBKYWNrIERveWxlLCBqYWNrQGdyZWVuc29jay5jb21cclxuICoqL1xyXG4od2luZG93Ll9nc1F1ZXVlfHwod2luZG93Ll9nc1F1ZXVlPVtdKSkucHVzaChmdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3ZhciB0PWRvY3VtZW50LmRvY3VtZW50RWxlbWVudCxlPXdpbmRvdyxpPWZ1bmN0aW9uKGkscyl7dmFyIHI9XCJ4XCI9PT1zP1wiV2lkdGhcIjpcIkhlaWdodFwiLG49XCJzY3JvbGxcIityLGE9XCJjbGllbnRcIityLG89ZG9jdW1lbnQuYm9keTtyZXR1cm4gaT09PWV8fGk9PT10fHxpPT09bz9NYXRoLm1heCh0W25dLG9bbl0pLShlW1wiaW5uZXJcIityXXx8TWF0aC5tYXgodFthXSxvW2FdKSk6aVtuXS1pW1wib2Zmc2V0XCIrcl19LHM9d2luZG93Ll9nc0RlZmluZS5wbHVnaW4oe3Byb3BOYW1lOlwic2Nyb2xsVG9cIixBUEk6Mix2ZXJzaW9uOlwiMS43LjNcIixpbml0OmZ1bmN0aW9uKHQscyxyKXtyZXR1cm4gdGhpcy5fd2R3PXQ9PT1lLHRoaXMuX3RhcmdldD10LHRoaXMuX3R3ZWVuPXIsXCJvYmplY3RcIiE9dHlwZW9mIHMmJihzPXt5OnN9KSx0aGlzLl9hdXRvS2lsbD1zLmF1dG9LaWxsIT09ITEsdGhpcy54PXRoaXMueFByZXY9dGhpcy5nZXRYKCksdGhpcy55PXRoaXMueVByZXY9dGhpcy5nZXRZKCksbnVsbCE9cy54Pyh0aGlzLl9hZGRUd2Vlbih0aGlzLFwieFwiLHRoaXMueCxcIm1heFwiPT09cy54P2kodCxcInhcIik6cy54LFwic2Nyb2xsVG9feFwiLCEwKSx0aGlzLl9vdmVyd3JpdGVQcm9wcy5wdXNoKFwic2Nyb2xsVG9feFwiKSk6dGhpcy5za2lwWD0hMCxudWxsIT1zLnk/KHRoaXMuX2FkZFR3ZWVuKHRoaXMsXCJ5XCIsdGhpcy55LFwibWF4XCI9PT1zLnk/aSh0LFwieVwiKTpzLnksXCJzY3JvbGxUb195XCIsITApLHRoaXMuX292ZXJ3cml0ZVByb3BzLnB1c2goXCJzY3JvbGxUb195XCIpKTp0aGlzLnNraXBZPSEwLCEwfSxzZXQ6ZnVuY3Rpb24odCl7dGhpcy5fc3VwZXIuc2V0UmF0aW8uY2FsbCh0aGlzLHQpO3ZhciBzPXRoaXMuX3dkd3x8IXRoaXMuc2tpcFg/dGhpcy5nZXRYKCk6dGhpcy54UHJldixyPXRoaXMuX3dkd3x8IXRoaXMuc2tpcFk/dGhpcy5nZXRZKCk6dGhpcy55UHJldixuPXItdGhpcy55UHJldixhPXMtdGhpcy54UHJldjt0aGlzLl9hdXRvS2lsbCYmKCF0aGlzLnNraXBYJiYoYT43fHwtNz5hKSYmaSh0aGlzLl90YXJnZXQsXCJ4XCIpPnMmJih0aGlzLnNraXBYPSEwKSwhdGhpcy5za2lwWSYmKG4+N3x8LTc+bikmJmkodGhpcy5fdGFyZ2V0LFwieVwiKT5yJiYodGhpcy5za2lwWT0hMCksdGhpcy5za2lwWCYmdGhpcy5za2lwWSYmdGhpcy5fdHdlZW4ua2lsbCgpKSx0aGlzLl93ZHc/ZS5zY3JvbGxUbyh0aGlzLnNraXBYP3M6dGhpcy54LHRoaXMuc2tpcFk/cjp0aGlzLnkpOih0aGlzLnNraXBZfHwodGhpcy5fdGFyZ2V0LnNjcm9sbFRvcD10aGlzLnkpLHRoaXMuc2tpcFh8fCh0aGlzLl90YXJnZXQuc2Nyb2xsTGVmdD10aGlzLngpKSx0aGlzLnhQcmV2PXRoaXMueCx0aGlzLnlQcmV2PXRoaXMueX19KSxyPXMucHJvdG90eXBlO3MubWF4PWksci5nZXRYPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuX3dkdz9udWxsIT1lLnBhZ2VYT2Zmc2V0P2UucGFnZVhPZmZzZXQ6bnVsbCE9dC5zY3JvbGxMZWZ0P3Quc2Nyb2xsTGVmdDpkb2N1bWVudC5ib2R5LnNjcm9sbExlZnQ6dGhpcy5fdGFyZ2V0LnNjcm9sbExlZnR9LHIuZ2V0WT1mdW5jdGlvbigpe3JldHVybiB0aGlzLl93ZHc/bnVsbCE9ZS5wYWdlWU9mZnNldD9lLnBhZ2VZT2Zmc2V0Om51bGwhPXQuc2Nyb2xsVG9wP3Quc2Nyb2xsVG9wOmRvY3VtZW50LmJvZHkuc2Nyb2xsVG9wOnRoaXMuX3RhcmdldC5zY3JvbGxUb3B9LHIuX2tpbGw9ZnVuY3Rpb24odCl7cmV0dXJuIHQuc2Nyb2xsVG9feCYmKHRoaXMuc2tpcFg9ITApLHQuc2Nyb2xsVG9feSYmKHRoaXMuc2tpcFk9ITApLHRoaXMuX3N1cGVyLl9raWxsLmNhbGwodGhpcyx0KX19KSx3aW5kb3cuX2dzRGVmaW5lJiZ3aW5kb3cuX2dzUXVldWUucG9wKCkoKTsiXX0= diff --git a/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js.map b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js.map index c4d7204eb..0e4633308 100644 --- a/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js.map +++ b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js.map @@ -1 +1 @@ -{"version":3,"names":[],"mappings":"","sources":["wpr-admin.js"],"sourcesContent":["!function r(a,o,l){function h(e,t){if(!o[e]){if(!a[e]){var i=\"function\"==typeof require&&require;if(!t&&i)return i(e,!0);if(c)return c(e,!0);var n=new Error(\"Cannot find module '\"+e+\"'\");throw n.code=\"MODULE_NOT_FOUND\",n}var s=o[e]={exports:{}};a[e][0].call(s.exports,function(t){return h(a[e][1][t]||t)},s,s.exports,r,a,o,l)}return o[e].exports}for(var c=\"function\"==typeof require&&require,t=0;t form > #wpr-options-submit\"),this.$pages=document.querySelectorAll(\".wpr-Page\"),this.$sidebar=document.querySelector(\".wpr-Sidebar\"),this.$content=document.querySelector(\".wpr-Content\"),this.$tips=document.querySelector(\".wpr-Content-tips\"),this.$links=document.querySelectorAll(\".wpr-body a\"),this.$menuItem=null,this.$page=null,this.pageId=null,this.bodyTop=0,this.buttonText=this.$submitButton.value,i.getBodyTop(),window.onhashchange=function(){i.detectID()},window.location.hash?(this.bodyTop=0,this.detectID()):(e=localStorage.getItem(\"wpr-hash\"),this.bodyTop=0,e?(window.location.hash=e,this.detectID()):(this.$menuItems[0].classList.add(\"isActive\"),localStorage.setItem(\"wpr-hash\",\"dashboard\"),window.location.hash=\"#dashboard\"));for(var n=0;nl;l++)i.startAt&&(i.startAt=d(i.startAt)),h.to(t[l],e,d(i),l*n);return this.add(h,s)},t.staggerFrom=function(t,e,i,n,s,r,a,o){return i.immediateRender=0!=i.immediateRender,i.runBackwards=!0,this.staggerTo(t,e,i,n,s,r,a,o)},t.staggerFromTo=function(t,e,i,n,s,r,a,o,l){return n.startAt=i,n.immediateRender=0!=n.immediateRender&&0!=i.immediateRender,this.staggerTo(t,e,n,s,r,a,o,l)},t.call=function(t,e,i,n){return this.add(p.delayedCall(0,t,e,i),n)},t.set=function(t,e,i){return i=this._parseTimeOrLabel(i,0,!0),null==e.immediateRender&&(e.immediateRender=i===this._time&&!this._paused),this.add(new p(t,0,e),i)},f.exportRoot=function(t,e){null==(t=t||{}).smoothChildTiming&&(t.smoothChildTiming=!0);var i,n,s=new f(t),r=s._timeline;for(null==e&&(e=!0),r._remove(s,!0),s._startTime=0,s._rawPrevTime=s._time=s._totalTime=r._time,i=r._first;i;)n=i._next,e&&i instanceof p&&i.target===i.vars.onComplete||s.add(i,i._startTime-i._delay),i=n;return r.add(s,0),s},t.add=function(t,e,i,n){var s,r,a,o,l,h;if(\"number\"!=typeof e&&(e=this._parseTimeOrLabel(e,0,!0,t)),!(t instanceof c)){if(t instanceof Array||t&&t.push&&g(t)){for(i=i||\"normal\",n=n||0,s=e,r=t.length,a=0;at._startTime;l._timeline;)h&&l._timeline.smoothChildTiming?l.totalTime(l._totalTime,!0):l._gc&&l._enabled(!0,!1),l=l._timeline;return this},t.remove=function(t){if(t instanceof c)return this._remove(t,!1);if(t instanceof Array||t&&t.push&&g(t)){for(var e=t.length;-1<--e;)this.remove(t[e]);return this}return\"string\"==typeof t?this.removeLabel(t):this.kill(null,t)},t._remove=function(t,e){u.prototype._remove.call(this,t,e);var i=this._last;return i?this._time>i._startTime+i._totalDuration/i._timeScale&&(this._time=this.duration(),this._totalTime=this._totalDuration):this._time=this._totalTime=this._duration=this._totalDuration=0,this},t.append=function(t,e){return this.add(t,this._parseTimeOrLabel(null,e,!0,t))},t.insert=t.insertMultiple=function(t,e,i,n){return this.add(t,e||0,i,n)},t.appendMultiple=function(t,e,i,n){return this.add(t,this._parseTimeOrLabel(null,e,!0,t),i,n)},t.addLabel=function(t,e){return this._labels[t]=this._parseTimeOrLabel(e),this},t.addPause=function(t,e,i,n){return this.call(s,[\"{self}\",e,i,n],this,t)},t.removeLabel=function(t){return delete this._labels[t],this},t.getLabelTime=function(t){return null!=this._labels[t]?this._labels[t]:-1},t._parseTimeOrLabel=function(t,e,i,n){var s;if(n instanceof c&&n.timeline===this)this.remove(n);else if(n&&(n instanceof Array||n.push&&g(n)))for(s=n.length;-1<--s;)n[s]instanceof c&&n[s].timeline===this&&this.remove(n[s]);if(\"string\"==typeof e)return this._parseTimeOrLabel(e,i&&\"number\"==typeof t&&null==this._labels[e]?t-this.duration():0,i);if(e=e||0,\"string\"!=typeof t||!isNaN(t)&&null==this._labels[t])null==t&&(t=this.duration());else{if(-1===(s=t.indexOf(\"=\")))return null==this._labels[t]?i?this._labels[t]=this.duration()+e:e:this._labels[t]+e;e=parseInt(t.charAt(s-1)+\"1\",10)*Number(t.substr(s+1)),t=1_&&(a=\"onReverseComplete\"))),this._rawPrevTime=this._duration||!e||t||this._rawPrevTime===t?t:_,t=l+1e-4):t<1e-7?(((this._totalTime=this._time=0)!==h||0===this._duration&&this._rawPrevTime!==_&&(0=h)for(n=this._first;n&&(r=n._next,!this._paused||p);)(n._active||n._startTime<=this._time&&!n._paused&&!n._gc)&&(n._reversed?n.render((n._dirty?n.totalDuration():n._totalDuration)-(t-n._startTime)*n._timeScale,e,i):n.render((t-n._startTime)*n._timeScale,e,i)),n=r;else for(n=this._last;n&&(r=n._prev,!this._paused||p);)(n._active||h>=n._startTime&&!n._paused&&!n._gc)&&(n._reversed?n.render((n._dirty?n.totalDuration():n._totalDuration)-(t-n._startTime)*n._timeScale,e,i):n.render((t-n._startTime)*n._timeScale,e,i)),n=r;this._onUpdate&&(e||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||v)),a&&(this._gc||c!==this._startTime&&u===this._timeScale||!(0===this._time||l>=this.totalDuration())||(s&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[a]&&this.vars[a].apply(this.vars[a+\"Scope\"]||this,this.vars[a+\"Params\"]||v)))}},t._hasPausedChild=function(){for(var t=this._first;t;){if(t._paused||t instanceof f&&t._hasPausedChild())return!0;t=t._next}return!1},t.getChildren=function(t,e,i,n){n=n||-9999999999;for(var s=[],r=this._first,a=0;r;)n>r._startTime||(r instanceof p?!1!==e&&(s[a++]=r):(!1!==i&&(s[a++]=r),!1!==t&&(a=(s=s.concat(r.getChildren(!0,e,i))).length))),r=r._next;return s},t.getTweensOf=function(t,e){var i,n,s=this._gc,r=[],a=0;for(s&&this._enabled(!0,!0),n=(i=p.getTweensOf(t)).length;-1<--n;)(i[n].timeline===this||e&&this._contains(i[n]))&&(r[a++]=i[n]);return s&&this._enabled(!1,!0),r},t._contains=function(t){for(var e=t.timeline;e;){if(e===this)return!0;e=e.timeline}return!1},t.shiftChildren=function(t,e,i){i=i||0;for(var n,s=this._first,r=this._labels;s;)s._startTime>=i&&(s._startTime+=t),s=s._next;if(e)for(n in r)r[n]>=i&&(r[n]+=t);return this._uncache(!0)},t._kill=function(t,e){if(!t&&!e)return this._enabled(!1,!1);for(var i=e?this.getTweensOf(e):this.getChildren(!0,!0,!1),n=i.length,s=!1;-1<--n;)i[n]._kill(t,e)&&(s=!0);return s},t.clear=function(t){var e=this.getChildren(!1,!0,!0),i=e.length;for(this._time=this._totalTime=0;-1<--i;)e[i]._enabled(!1,!1);return!1!==t&&(this._labels={}),this._uncache(!0)},t.invalidate=function(){for(var t=this._first;t;)t.invalidate(),t=t._next;return this},t._enabled=function(t,e){if(t===this._gc)for(var i=this._first;i;)i._enabled(t,!0),i=i._next;return u.prototype._enabled.call(this,t,e)},t.duration=function(t){return arguments.length?(0!==this.duration()&&0!==t&&this.timeScale(this._duration/t),this):(this._dirty&&this.totalDuration(),this._duration)},t.totalDuration=function(t){if(arguments.length)return 0!==this.totalDuration()&&0!==t&&this.timeScale(this._totalDuration/t),this;if(this._dirty){for(var e,i,n=0,s=this._last,r=999999999999;s;)e=s._prev,s._dirty&&s.totalDuration(),s._startTime>r&&this._sortChildren&&!s._paused?this.add(s,s._startTime-s._delay):r=s._startTime,s._startTime<0&&!s._paused&&(n-=s._startTime,this._timeline.smoothChildTiming&&(this._startTime+=s._startTime/this._timeScale),this.shiftChildren(-s._startTime,!1,-9999999999),r=0),n<(i=s._startTime+s._totalDuration/s._timeScale)&&(n=i),s=e;this._duration=this._totalDuration=n,this._dirty=!1}return this._totalDuration},t.usesFrames=function(){for(var t=this._timeline;t._timeline;)t=t._timeline;return t===c._rootFramesTimeline},t.rawTime=function(){return this._paused?this._totalTime:(this._timeline.rawTime()-this._startTime)*this._timeScale},f},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],10:[function(t,W,e){\"use strict\";var Q=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&\"function\"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?\"symbol\":typeof t};!function(f){var e,i,d=f.GreenSockGlobals||f;if(!d.TweenLite){var _,m=function(t){for(var e=t.split(\".\"),i=d,n=0;e.length>n;n++)i[e[n]]=i=i[e[n]]||{};return i},u=m(\"com.greensock\"),g=1e-10,l=[].slice,n=function(){},c=(e=Object.prototype.toString,i=e.call([]),function(t){return null!=t&&(t instanceof Array||\"object\"==(void 0===t?\"undefined\":Q(t))&&!!t.push&&e.call(t)===i)}),v={},s=function o(l,h,c,u){this.sc=v[l]?v[l].sc:[],(v[l]=this).gsClass=null,this.func=c;var p=[];this.check=function(t){for(var e,i,n,s,r=h.length,a=r;-1<--r;)(e=v[h[r]]||new o(h[r],[])).gsClass?(p[r]=e.gsClass,a--):t&&e.sc.push(this);if(0===a&&c)for(n=(i=(\"com.greensock.\"+l).split(\".\")).pop(),s=m(i.join(\".\"))[n]=this.gsClass=c.apply(c,p),u&&(d[n]=s,\"function\"==typeof define&&define.amd?define((f.GreenSockAMDPath?f.GreenSockAMDPath+\"/\":\"\")+l.split(\".\").join(\"/\"),[],function(){return s}):void 0!==W&&W.exports&&(W.exports=s)),r=0;this.sc.length>r;r++)this.sc[r].check()},this.check(!0)},r=f._gsDefine=function(t,e,i,n){return new s(t,e,i,n)},p=u._class=function(t,e,i){return e=e||function(){},r(t,[],function(){return e},i),e};r.globals=d;var t,a=[0,0,1,1],w=[],y=p(\"easing.Ease\",function(t,e,i,n){this._func=t,this._type=i||0,this._power=n||0,this._params=e?a.concat(e):a},!0),x=y.map={},o=y.register=function(t,e,i,n){for(var s,r,a,o,l=e.split(\",\"),h=l.length,c=(i||\"easeIn,easeOut,easeInOut\").split(\",\");-1<--h;)for(r=l[h],s=n?p(\"easing.\"+r,null,!0):u.easing[r]||{},a=c.length;-1<--a;)o=c[a],x[r+\".\"+o]=x[o+r]=s[o]=t.getRatio?t:t[o]||new t};for((t=y.prototype)._calcEnd=!1,t.getRatio=function(t){if(this._func)return this._params[0]=t,this._func.apply(null,this._params);var e=this._type,i=this._power,n=1===e?1-t:2===e?t:t<.5?2*t:2*(1-t);return 1===i?n*=n:2===i?n*=n*n:3===i?n*=n*n*n:4===i&&(n*=n*n*n*n),1===e?1-n:2===e?n:t<.5?n/2:1-n/2},O=(h=[\"Linear\",\"Quad\",\"Cubic\",\"Quart\",\"Quint,Strong\"]).length;-1<--O;)t=h[O]+\",Power\"+O,o(new y(null,null,1,O),t,\"easeOut\",!0),o(new y(null,null,2,O),t,\"easeIn\"+(0===O?\",easeNone\":\"\")),o(new y(null,null,3,O),t,\"easeInOut\");x.linear=u.easing.Linear.easeIn,x.swing=u.easing.Quad.easeInOut;var b=p(\"events.EventDispatcher\",function(t){this._listeners={},this._eventTarget=t||this});(t=b.prototype).addEventListener=function(t,e,i,n,s){s=s||0;var r,a,o=this._listeners[t],l=0;for(null==o&&(this._listeners[t]=o=[]),a=o.length;-1<--a;)(r=o[a]).c===e&&r.s===i?o.splice(a,1):0===l&&s>r.pr&&(l=a+1);o.splice(l,0,{c:e,s:i,up:n,pr:s}),this!==A||_||A.wake()},t.removeEventListener=function(t,e){var i,n=this._listeners[t];if(n)for(i=n.length;-1<--i;)if(n[i].c===e)return void n.splice(i,1)},t.dispatchEvent=function(t){var e,i,n,s=this._listeners[t];if(s)for(e=s.length,i=this._eventTarget;-1<--e;)(n=s[e]).up?n.c.call(n.s||i,{type:t,target:i}):n.c.call(n.s||i)};for(var h,T=f.requestAnimationFrame,k=f.cancelAnimationFrame,P=Date.now||function(){return(new Date).getTime()},S=P(),O=(h=[\"ms\",\"moz\",\"webkit\",\"o\"]).length;-1<--O&&!T;)T=f[h[O]+\"RequestAnimationFrame\"],k=f[h[O]+\"CancelAnimationFrame\"]||f[h[O]+\"CancelRequestAnimationFrame\"];p(\"Ticker\",function(t,e){function s(t){var e,i,n=P()-S;p=i&&i+this.totalDuration()/this._timeScale>t},t._enabled=function(t,e){return _||A.wake(),this._gc=!t,this._active=this.isActive(),!0!==e&&(t&&!this.timeline?this._timeline.add(this,this._startTime-this._delay):!t&&this.timeline&&this._timeline._remove(this,!0)),!1},t._kill=function(){return this._enabled(!1,!1)},t.kill=function(t,e){return this._kill(t,e),this},t._uncache=function(t){for(var e=t?this:this.timeline;e;)e._dirty=!0,e=e.timeline;return this},t._swapSelfInParams=function(t){for(var e=t.length,i=t.concat();-1<--e;)\"{self}\"===t[e]&&(i[e]=this);return i},t.eventCallback=function(t,e,i,n){if(\"on\"===(t||\"\").substr(0,2)){var s=this.vars;if(1===arguments.length)return s[t];null==e?delete s[t]:(s[t]=e,s[t+\"Params\"]=c(i)&&-1!==i.join(\"\").indexOf(\"{self}\")?this._swapSelfInParams(i):i,s[t+\"Scope\"]=n),\"onUpdate\"===t&&(this._onUpdate=e)}return this},t.delay=function(t){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+t-this._delay),this._delay=t,this):this._delay},t.duration=function(t){return arguments.length?(this._duration=this._totalDuration=t,this._uncache(!0),this._timeline.smoothChildTiming&&0this._duration?this._duration:t,e)):this._time},t.totalTime=function(t,e,i){if(_||A.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(t<0&&!i&&(t+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var n=this._totalDuration,s=this._timeline;if(nn;)i=i._prev;return i?(t._next=i._next,i._next=t):(t._next=this._first,this._first=t),t._next?t._next._prev=t:this._last=t,t._prev=i,this._timeline&&this._uncache(!0),this},t._remove=function(t,e){return t.timeline===this&&(e||t._enabled(!1,!0),t.timeline=null,t._prev?t._prev._next=t._next:this._first===t&&(this._first=t._next),t._next?t._next._prev=t._prev:this._last===t&&(this._last=t._prev),this._timeline&&this._uncache(!0)),this},t.render=function(t,e,i){var n,s=this._first;for(this._totalTime=this._time=this._rawPrevTime=t;s;)n=s._next,(s._active||t>=s._startTime&&!s._paused)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=n},t.rawTime=function(){return _||A.wake(),this._totalTime};var R=p(\"TweenLite\",function(t,e,i){if(C.call(this,e,i),this.render=R.prototype.render,null==t)throw\"Cannot tween a null target.\";this.target=t=\"string\"==typeof t&&R.selector(t)||t;var n,s,r,a=t.jquery||t.length&&t!==f&&t[0]&&(t[0]===f||t[0].nodeType&&t[0].style&&!t.nodeType),o=this.vars.overwrite;if(this._overwrite=o=null==o?Y[R.defaultOverwrite]:\"number\"==typeof o?o>>0:Y[o],(a||t instanceof Array||t.push&&c(t))&&\"number\"!=typeof t[0])for(this._targets=r=l.call(t,0),this._propLookup=[],this._siblings=[],n=0;r.length>n;n++)(s=r[n])?\"string\"!=typeof s?s.length&&s!==f&&s[0]&&(s[0]===f||s[0].nodeType&&s[0].style&&!s.nodeType)?(r.splice(n--,1),this._targets=r=r.concat(l.call(s,0))):(this._siblings[n]=q(s,this,!1),1===o&&1=a._startTime&&a._startTime+a.totalDuration()/a._timeScale>h&&((p||!a._initted)&&h-a._startTime<=2e-10||(c[u++]=a)));for(f=u;-1<--f;)a=c[f],2===n&&a._kill(i,t)&&(r=!0),(2!==n||!a._firstPT&&a._initted)&&a._enabled(!1,!1)&&(r=!0);return r},H=function(t,e,i){for(var n=t._timeline,s=n._timeScale,r=t._startTime;n._timeline;){if(r+=n._startTime,s*=n._timeScale,n._paused)return-100;n=n._timeline}return e<(r/=s)?r-e:i&&r===e||!t._initted&&r-e<2*g?g:(r+=t.totalDuration()/t._timeScale/s)>e+g?0:r-e-g};t._init=function(){var t,e,i,n,s,r=this.vars,a=this._overwrittenProps,o=this._duration,l=!!r.immediateRender,h=r.ease;if(r.startAt){for(n in this._startAt&&(this._startAt.render(-1,!0),this._startAt.kill()),s={},r.startAt)s[n]=r.startAt[n];if(s.overwrite=!1,s.immediateRender=!0,s.lazy=l&&!1!==r.lazy,s.startAt=s.delay=null,this._startAt=R.to(this.target,0,s),l)if(0o.pr;)n=n._next;(o._prev=n?n._prev:r)?o._prev._next=o:s=o,(o._next=n)?n._prev=o:r=o,o=a}o=e._firstPT=s}for(;o;)o.pg&&\"function\"==typeof o.t[t]&&o.t[t]()&&(i=!0),o=o._next;return i},V.activate=function(t){for(var e=t.length;-1<--e;)t[e].API===V.API&&(X[(new t[e])._propName]=t[e]);return!0},r.plugin=function(t){if(!(t&&t.propName&&t.init&&t.API))throw\"illegal plugin definition.\";var e,i=t.propName,n=t.priority||0,s=t.overwriteProps,r={init:\"_onInitTween\",set:\"setRatio\",kill:\"_kill\",round:\"_roundProps\",initAll:\"_onInitAllProps\"},a=p(\"plugins.\"+i.charAt(0).toUpperCase()+i.substr(1)+\"Plugin\",function(){V.call(this,i,n),this._overwriteProps=s||[]},!0===t.global),o=a.prototype=new V(i);for(e in(o.constructor=a).API=t.API,r)\"function\"==typeof t[e]&&(o[r[e]]=t[e]);return a.version=t.version,V.activate([a]),a},h=f._gsQueue){for(O=0;h.length>O;O++)h[O]();for(t in v)v[t].func||f.console.log(\"GSAP encountered missing dependency: com.greensock.\"+t)}_=!1}}(window)},{}],11:[function(t,e,i){\"use strict\";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine(\"easing.Back\",[\"easing.Ease\"],function(m){function t(t,e){var i=c(\"easing.\"+t,function(){},!0),n=i.prototype=new m;return n.constructor=i,n.getRatio=e,i}function e(t,e,i,n){var s=c(\"easing.\"+t,{easeOut:new e,easeIn:new i,easeInOut:new n},!0);return u(s,t),s}function g(t,e,i){this.t=t,this.v=e,i&&(((this.next=i).prev=this).c=i.v-e,this.gap=i.t-t)}function i(t,e){var i=c(\"easing.\"+t,function(t){this._p1=t||0===t?t:1.70158,this._p2=1.525*this._p1},!0),n=i.prototype=new m;return n.constructor=i,n.getRatio=e,n.config=function(t){return new i(t)},i}var n,s,r,a=window.GreenSockGlobals||window,o=a.com.greensock,l=2*Math.PI,h=Math.PI/2,c=o._class,u=m.register||function(){},p=e(\"Back\",i(\"BackOut\",function(t){return--t*t*((this._p1+1)*t+this._p1)+1}),i(\"BackIn\",function(t){return t*t*((this._p1+1)*t-this._p1)}),i(\"BackInOut\",function(t){return(t*=2)<1?.5*t*t*((this._p2+1)*t-this._p2):.5*((t-=2)*t*((this._p2+1)*t+this._p2)+2)})),f=c(\"easing.SlowMo\",function(t,e,i){e=e||0===e?e:.7,null==t?t=.7:1t?this._calcEnd?1-(t=1-t/this._p1)*t:e-(t=1-t/this._p1)*t*t*t*e:t>this._p3?this._calcEnd?1-(t=(t-this._p3)/this._p1)*t:e+(t-e)*(t=(t-this._p3)/this._p1)*t*t*t:this._calcEnd?1:e},f.ease=new f(.7,.7),d.config=f.config=function(t,e,i){return new f(t,e,i)},(d=(n=c(\"easing.SteppedEase\",function(t){t=t||1,this._p1=1/t,this._p2=t+1},!0)).prototype=new m).constructor=n,d.getRatio=function(t){return t<0?t=0:1<=t&&(t=.999999999),(this._p2*t>>0)*this._p1},d.config=n.config=function(t){return new n(t)},(d=(s=c(\"easing.RoughEase\",function(t){for(var e,i,n,s,r,a,o=(t=t||{}).taper||\"none\",l=[],h=0,c=0|(t.points||20),u=c,p=!1!==t.randomize,f=!0===t.clamp,d=t.template instanceof m?t.template:null,_=\"number\"==typeof t.strength?.4*t.strength:.4;-1<--u;)e=p?Math.random():1/c*u,i=d?d.getRatio(e):e,n=\"none\"===o?_:\"out\"===o?(s=1-e)*s*_:\"in\"===o?e*e*_:.5*(s=e<.5?2*e:2*(1-e))*s*_,p?i+=Math.random()*n-.5*n:u%2?i+=.5*n:i-=.5*n,f&&(1e.t){for(;e.next&&t>=e.t;)e=e.next;e=e.prev}else for(;e.prev&&e.t>=t;)e=e.prev;return(this._prev=e).v+(t-e.t)/e.gap*e.c},d.config=function(t){return new s(t)},s.ease=new s,e(\"Bounce\",t(\"BounceOut\",function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}),t(\"BounceIn\",function(t){return 1/2.75>(t=1-t)?1-7.5625*t*t:t<2/2.75?1-(7.5625*(t-=1.5/2.75)*t+.75):t<2.5/2.75?1-(7.5625*(t-=2.25/2.75)*t+.9375):1-(7.5625*(t-=2.625/2.75)*t+.984375)}),t(\"BounceInOut\",function(t){var e=t<.5;return t=(t=e?1-2*t:2*t-1)<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375,e?.5*(1-t):.5*t+.5})),e(\"Circ\",t(\"CircOut\",function(t){return Math.sqrt(1- --t*t)}),t(\"CircIn\",function(t){return-(Math.sqrt(1-t*t)-1)}),t(\"CircInOut\",function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)})),e(\"Elastic\",(r=function(t,e,i){var n=c(\"easing.\"+t,function(t,e){this._p1=t||1,this._p2=e||i,this._p3=this._p2/l*(Math.asin(1/this._p1)||0)},!0),s=n.prototype=new m;return s.constructor=n,s.getRatio=e,s.config=function(t,e){return new n(t,e)},n})(\"ElasticOut\",function(t){return this._p1*Math.pow(2,-10*t)*Math.sin((t-this._p3)*l/this._p2)+1},.3),r(\"ElasticIn\",function(t){return-(this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*l/this._p2))},.3),r(\"ElasticInOut\",function(t){return(t*=2)<1?-.5*this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*l/this._p2):.5*this._p1*Math.pow(2,-10*--t)*Math.sin((t-this._p3)*l/this._p2)+1},.45)),e(\"Expo\",t(\"ExpoOut\",function(t){return 1-Math.pow(2,-10*t)}),t(\"ExpoIn\",function(t){return Math.pow(2,10*(t-1))-.001}),t(\"ExpoInOut\",function(t){return(t*=2)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*(t-1)))})),e(\"Sine\",t(\"SineOut\",function(t){return Math.sin(t*h)}),t(\"SineIn\",function(t){return 1-Math.cos(t*h)}),t(\"SineInOut\",function(t){return-.5*(Math.cos(Math.PI*t)-1)})),c(\"easing.EaseLookup\",{find:function(t){return m.map[t]}},!0),u(a.SlowMo,\"SlowMo\",\"ease,\"),u(s,\"RoughEase\",\"ease,\"),u(n,\"SteppedEase\",\"ease,\"),p},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],12:[function(t,e,i){\"use strict\";var Lt=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&\"function\"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?\"symbol\":typeof t};(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine(\"plugins.CSSPlugin\",[\"plugins.TweenPlugin\",\"TweenLite\"],function(r,p){function J(){r.call(this,\"css\"),this._overwriteProps.length=0,this.setRatio=J.prototype.setRatio}var d,T,k,f,_={},t=J.prototype=new r(\"css\");(t.constructor=J).version=\"1.12.1\",J.API=2,J.defaultTransformPerspective=0,J.defaultSkewType=\"compensated\",J.suffixMap={top:t=\"px\",right:t,bottom:t,left:t,width:t,height:t,fontSize:t,padding:t,margin:t,perspective:t,lineHeight:\"\"};function a(t,e){return e.toUpperCase()}function o(t){return E.test(\"string\"==typeof t?t:(t.currentStyle?t.currentStyle.filter:t.style.filter)||\"\")?parseFloat(RegExp.$1)/100:1}function m(t){window.console&&console.log(t)}function P(t,e){var i,n,s=(e=e||V).style;if(void 0!==s[t])return t;for(t=t.charAt(0).toUpperCase()+t.substr(1),i=[\"O\",\"Moz\",\"ms\",\"Ms\",\"Webkit\"],n=5;-1<--n&&void 0===s[i[n]+t];);return 0<=n?(G=\"-\"+(K=3===n?\"ms\":i[n]).toLowerCase()+\"-\",K+t):null}function g(t,e){var i,n,s={};if(e=e||nt(t,null))if(i=e.length)for(;-1<--i;)s[e[i].replace(Y,a)]=e.getPropertyValue(e[i]);else for(i in e)s[i]=e[i];else if(e=t.currentStyle||t.style)for(i in e)\"string\"==typeof i&&void 0===s[i]&&(s[i.replace(Y,a)]=e[i]);return Z||(s.opacity=o(t)),n=St(t,e,!1),s.rotation=n.rotation,s.skewX=n.skewX,s.scaleX=n.scaleX,s.scaleY=n.scaleY,s.x=n.x,s.y=n.y,kt&&(s.z=n.z,s.rotationX=n.rotationX,s.rotationY=n.rotationY,s.scaleZ=n.scaleZ),s.filters&&delete s.filters,s}function v(t,e,i,n,s){var r,a,o,l={},h=t.style;for(a in i)\"cssText\"!==a&&\"length\"!==a&&isNaN(a)&&(e[a]!==(r=i[a])||s&&s[a])&&-1===a.indexOf(\"Origin\")&&(\"number\"==typeof r||\"string\"==typeof r)&&(l[a]=\"auto\"!==r||\"left\"!==a&&\"top\"!==a?\"\"!==r&&\"auto\"!==r&&\"none\"!==r||\"string\"!=typeof e[a]||\"\"===e[a].replace(c,\"\")?r:0:at(t,a),void 0!==h[a]&&(o=new ft(h,a,h[a],o)));if(n)for(a in n)\"className\"!==a&&(l[a]=n[a]);return{difs:l,firstMPT:o}}function w(t,e){null!=t&&\"\"!==t&&\"auto\"!==t&&\"auto auto\"!==t||(t=\"0 0\");var i=t.split(\" \"),n=-1!==t.indexOf(\"left\")?\"0%\":-1!==t.indexOf(\"right\")?\"100%\":i[0],s=-1!==t.indexOf(\"top\")?\"0%\":-1!==t.indexOf(\"bottom\")?\"100%\":i[1];return null==s?s=\"0\":\"center\"===s&&(s=\"50%\"),(\"center\"===n||isNaN(parseFloat(n))&&-1===(n+\"\").indexOf(\"=\"))&&(n=\"50%\"),e&&(e.oxp=-1!==n.indexOf(\"%\"),e.oyp=-1!==s.indexOf(\"%\"),e.oxr=\"=\"===n.charAt(1),e.oyr=\"=\"===s.charAt(1),e.ox=parseFloat(n.replace(c,\"\")),e.oy=parseFloat(s.replace(c,\"\"))),n+\" \"+s+(2>16,255&t>>8,255&t]:(\",\"===t.charAt(t.length-1)&&(t=t.substr(0,t.length-1)),ht[t]?ht[t]:\"#\"===t.charAt(0)?(4===t.length&&(t=\"#\"+(e=t.charAt(1))+e+(i=t.charAt(2))+i+(n=t.charAt(3))+n),[(t=parseInt(t.substr(1),16))>>16,255&t>>8,255&t]):(\"hsl\"===t.substr(0,3)?(t=t.match(I),s=Number(t[0])%360/360,r=Number(t[1])/100,e=2*(a=Number(t[2])/100)-(i=a<=.5?a*(1+r):a+r-a*r),3a\",!!(e=n.getElementsByTagName(\"a\")[0])&&/^0.55/.test(e.style.opacity)),G=\"\",K=\"\",nt=H.defaultView?H.defaultView.getComputedStyle:function(){},st=J.getStyle=function(t,e,i,n,s){var r;return Z||\"opacity\"!==e?(!n&&t.style[e]?r=t.style[e]:(i=i||nt(t))?r=i[e]||i.getPropertyValue(e)||i.getPropertyValue(e.replace(u,\"-$1\").toLowerCase()):t.currentStyle&&(r=t.currentStyle[e]),null==s||r&&\"none\"!==r&&\"auto\"!==r&&\"auto auto\"!==r?r:s):o(t)},rt=s.convertToPixels=function(t,e,i,n,s){if(\"px\"===n||!n)return i;if(\"auto\"===n||!i)return 0;var r,a,o,l=$.test(e),h=t,c=V.style,u=i<0;if(u&&(i=-i),\"%\"===n&&-1!==e.indexOf(\"border\"))r=i/100*(l?t.clientWidth:t.clientHeight);else{if(c.cssText=\"border:0 solid red;position:\"+st(t,\"position\")+\";line-height:0;\",\"%\"!==n&&h.appendChild)c[l?\"borderLeftWidth\":\"borderTopWidth\"]=i+n;else{if(a=(h=t.parentNode||H.body)._gsCache,o=p.ticker.frame,a&&l&&a.time===o)return a.width*i/100;c[l?\"width\":\"height\"]=i+n}h.appendChild(V),r=parseFloat(V[l?\"offsetWidth\":\"offsetHeight\"]),h.removeChild(V),l&&\"%\"===n&&!1!==J.cacheWidths&&((a=h._gsCache=h._gsCache||{}).time=o,a.width=r/i*100),0!==r||s||(r=rt(t,e,i,n,!0))}return u?-r:r},at=s.calculateOffset=function(t,e,i){if(\"absolute\"!==st(t,\"position\",i))return 0;var n=\"left\"===e?\"Left\":\"Top\",s=st(t,\"margin\"+n,i);return t[\"offset\"+n]-(rt(t,e,parseFloat(s),s.replace(X,\"\"))||0)},ot={width:[\"Left\",\"Right\"],height:[\"Top\",\"Bottom\"]},lt=[\"marginLeft\",\"marginRight\",\"marginTop\",\"marginBottom\"],ht={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},ct=\"(?:\\\\b(?:(?:rgb|rgba|hsl|hsla)\\\\(.+?\\\\))|\\\\B#.+?\\\\b\";for(t in ht)ct+=\"|\"+t+\"\\\\b\";ct=RegExp(ct+\")\",\"gi\");function ut(t,e,r,a){if(null==t)return function(t){return t};var o,l=e?(t.match(ct)||[\"\"])[0]:\"\",h=t.split(l).join(\"\").match(L)||[],c=t.substr(0,t.indexOf(h[0])),u=\")\"===t.charAt(t.length-1)?\")\":\"\",p=-1!==t.indexOf(\" \")?\" \":\",\",f=h.length,d=0n;n++)s[n]=o(s[n]);return s.join(\",\")}if(e=(t.match(ct)||[l])[0],n=(i=t.split(e).join(\"\").match(L)||[]).length,f>n--)for(;f>++n;)i[n]=r?i[0|(n-1)/2]:h[n];return c+i.join(p)+p+e+u+(-1!==t.indexOf(\"inset\")?\" inset\":\"\")}:function(t){var e,i,n;if(\"number\"==typeof t)t+=d;else if(a&&q.test(t)){for(i=t.replace(q,\"|\").split(\"|\"),n=0;i.length>n;n++)i[n]=o(i[n]);return i.join(\",\")}if(n=(e=t.match(L)||[]).length,f>n--)for(;f>++n;)e[n]=r?e[0|(n-1)/2]:h[n];return c+e.join(p)+u}:function(t){return t}}function pt(h){return h=h.split(\",\"),function(t,e,i,n,s,r,a){var o,l=(e+\"\").split(\" \");for(a={},o=0;o<4;o++)a[h[o]]=l[o]=l[o]||l[(o-1)/2>>0];return n.parse(t,a,s,r)}}var ft=(s._setPluginRatio=function(t){this.plugin.setRatio(t);for(var e,i,n,s,r=this.data,a=r.proxy,o=r.firstMPT;o;)e=a[o.v],o.r?e=Math.round(e):e<1e-6&&-1e-6n;n++)s+=i[\"xn\"+n]+i[\"xs\"+(n+1)];i.e=s}}else i.e=i.s+i.xs0;o=o._next}},function(t,e,i,n,s){this.t=t,this.p=e,this.v=i,this.r=s,n&&((n._prev=this)._next=n)}),dt=(s._parseToProxy=function(t,e,i,n,s,r){var a,o,l,h,c,u=n,p={},f={},d=i._transform,_=U;for(i._transform=null,U=e,n=c=i.parse(t,e,n,s),U=_,r&&(i._transform=d,u&&(u._prev=null,u._prev&&(u._prev._next=null)));n&&n!==u;){if(n.type<=1&&(f[o=n.p]=n.s+n.c,p[o]=n.s,r||(h=new ft(n,\"s\",o,h,n.r),n.c=0),1===n.type))for(a=n.l;0<--a;)l=\"xn\"+a,f[o=n.p+\"_\"+l]=n.data[l],p[o]=n[l],r||(h=new ft(n,l,o,h,n.rxp[l]));n=n._next}return{proxy:p,end:f,firstMPT:h,pt:c}},s.CSSPropTween=function(t,e,i,n,s,r,a,o,l,h,c){this.t=t,this.p=e,this.s=i,this.c=n,this.n=a||e,t instanceof dt||f.push(this.n),this.r=o,this.type=r||0,l&&(this.pr=l,d=!0),this.b=void 0===h?i:h,this.e=void 0===c?i+n:c,s&&((this._next=s)._prev=this)}),_t=J.parseComplex=function(t,e,i,n,s,r,a,o,l,h){a=new dt(t,e,0,0,a,h?2:1,null,!1,o,i=i||r||\"\",n),n+=\"\";var c,u,p,f,d,_,m,g,v,w,y,x,b=i.split(\", \").join(\",\").split(\" \"),T=n.split(\", \").join(\",\").split(\" \"),k=b.length,P=!1!==C;for(-1===n.indexOf(\",\")&&-1===i.indexOf(\",\")||(b=b.join(\" \").replace(q,\", \").split(\" \"),T=T.join(\" \").replace(q,\", \").split(\" \"),k=b.length),k!==T.length&&(k=(b=(r||\"\").split(\" \")).length),a.plugin=l,a.setRatio=h,c=0;cu;u++)y=_[u],w=f.indexOf(y,p),a.appendXtra(f.substr(p,w-p),Number(y),S(m[u],y),\"\",P&&\"px\"===f.substr(w+y.length,2),0===u),p=w+y.length;a[\"xs\"+a.l]+=f.substr(p)}else a[\"xs\"+a.l]+=a.l?\" \"+f:f;if(-1!==n.indexOf(\"=\")&&a.data){for(x=a.xs0+a.data.s,c=1;a.l>c;c++)x+=a[\"xs\"+c]+a.data[\"xn\"+c];a.e=x+a[\"xs\"+c]}return a.l||(a.type=-1,a.xs0=a.e),a.xfirst||a},mt=9;for((t=dt.prototype).l=t.pr=0;0<--mt;)t[\"xn\"+mt]=0,t[\"xs\"+mt]=\"\";t.xs0=\"\",t._next=t._prev=t.xfirst=t.data=t.plugin=t.setRatio=t.rxp=null,t.appendXtra=function(t,e,i,n,s,r){var a=this,o=a.l;return a[\"xs\"+o]+=r&&o?\" \"+t:t||\"\",i||0===o||a.plugin?(a.l++,a.type=a.setRatio?2:1,a[\"xs\"+a.l]=n||\"\",0n;n++)e.prefix=0===n&&e.prefix,e.defaultValue=i[n]||r,new gt(s[n],e)};(t=gt.prototype).parseComplex=function(t,e,i,n,s,r){var a,o,l,h,c,u=this.keyword;if(this.multi&&(q.test(i)||q.test(e)?(o=e.replace(q,\"|\").split(\"|\"),l=i.replace(q,\"|\").split(\"|\")):u&&(o=[e],l=[i])),l){for(h=l.length>o.length?l.length:o.length,a=0;aH[a]&&H[a]>-W&&(H[a]=0);return i&&(t._gsTransform=H),H},Ot=s.set3DTransformRatio=function(t){var e,i,n,s,r,a,o,l,h,c,u,p,f,d,_,m,g,v,w,y,x,b,T,k=this.data,P=this.t.style,S=k.rotation*et,O=k.scaleX,C=k.scaleY,A=k.scaleZ,M=k.perspective;if(1!==t&&0!==t||\"auto\"!==k.force3D||k.rotationY||k.rotationX||1!==A||M||k.z){if(R&&(O<1e-4&&-1e-4b;b++)this.p.indexOf(\"border\")&&(g[b]=P(g[b])),-1!==(o=a=st(t,g[b],k,!1,\"0px\")).indexOf(\" \")&&(o=(a=o.split(\" \"))[0],a=a[1]),l=r=x[b],h=parseFloat(o),p=o.substr((h+\"\").length),\"\"===(u=(f=\"=\"===l.charAt(1))?(c=parseInt(l.charAt(0)+\"1\",10),l=l.substr(2),c*=parseFloat(l),l.substr((c+\"\").length-(c<0?1:0))||\"\"):(c=parseFloat(l),l.substr((c+\"\").length)))&&(u=T[i]||p),u!==p&&(d=rt(t,\"borderLeft\",h,p),_=rt(t,\"borderTop\",h,p),a=\"%\"===u?(o=d/w*100+\"%\",_/y*100+\"%\"):\"em\"===u?(o=d/(m=rt(t,\"borderLeft\",1,\"em\"))+\"em\",_/m+\"em\"):(o=d+\"px\",_+\"px\"),f&&(l=parseFloat(o)+c+u,r=parseFloat(a)+c+u)),s=_t(v,g[b],o+\" \"+a,l+\" \"+r,!1,\"0px\",s);return s},prefix:!0,formatter:ut(\"0px 0px 0px 0px\",!1,!0)}),vt(\"backgroundPosition\",{defaultValue:\"0 0\",parser:function(t,e,i,n,s,r){var a,o,l,h,c,u,p=\"background-position\",f=k||nt(t,null),d=this.format((f?D?f.getPropertyValue(p+\"-x\")+\" \"+f.getPropertyValue(p+\"-y\"):f.getPropertyValue(p):t.currentStyle.backgroundPositionX+\" \"+t.currentStyle.backgroundPositionY)||\"0 0\"),_=this.format(e);if(-1!==d.indexOf(\"%\")!=(-1!==_.indexOf(\"%\"))&&((u=st(t,\"backgroundImage\").replace(F,\"\"))&&\"none\"!==u)){for(a=d.split(\" \"),o=_.split(\" \"),W.setAttribute(\"src\",u),l=2;-1<--l;)(h=-1!==(d=a[l]).indexOf(\"%\"))!=(-1!==o[l].indexOf(\"%\"))&&(c=0===l?t.offsetWidth-W.width:t.offsetHeight-W.height,a[l]=h?parseFloat(d)/100*c+\"px\":parseFloat(d)/c*100+\"%\");d=a.join(\" \")}return this.parseComplex(t.style,d,_,s,r)},formatter:w}),vt(\"backgroundSize\",{defaultValue:\"0 0\",formatter:w}),vt(\"perspective\",{defaultValue:\"0px\",prefix:!0}),vt(\"perspectiveOrigin\",{defaultValue:\"50% 50%\",prefix:!0}),vt(\"transformStyle\",{prefix:!0}),vt(\"backfaceVisibility\",{prefix:!0}),vt(\"userSelect\",{prefix:!0}),vt(\"margin\",{parser:pt(\"marginTop,marginRight,marginBottom,marginLeft\")}),vt(\"padding\",{parser:pt(\"paddingTop,paddingRight,paddingBottom,paddingLeft\")}),vt(\"clip\",{defaultValue:\"rect(0px,0px,0px,0px)\",parser:function(t,e,i,n,s,r){var a,o,l;return e=D<9?(o=t.currentStyle,l=D<8?\" \":\",\",a=\"rect(\"+o.clipTop+l+o.clipRight+l+o.clipBottom+l+o.clipLeft+\")\",this.format(e).split(\",\").join(l)):(a=this.format(st(t,this.p,k,!1,this.dflt)),this.format(e)),this.parseComplex(t.style,a,e,s,r)}}),vt(\"textShadow\",{defaultValue:\"0px 0px 0px #999\",color:!0,multi:!0}),vt(\"autoRound,strictUnits\",{parser:function(t,e,i,n,s){return s}}),vt(\"border\",{defaultValue:\"0px solid #000\",parser:function(t,e,i,n,s,r){return this.parseComplex(t.style,this.format(st(t,\"borderTopWidth\",k,!1,\"0px\")+\" \"+st(t,\"borderTopStyle\",k,!1,\"solid\")+\" \"+st(t,\"borderTopColor\",k,!1,\"#000\")),this.format(e),s,r)},color:!0,formatter:function(t){var e=t.split(\" \");return e[0]+\" \"+(e[1]||\"solid\")+\" \"+(t.match(ct)||[\"#000\"])[0]}}),vt(\"borderWidth\",{parser:pt(\"borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth\")}),vt(\"float,cssFloat,styleFloat\",{parser:function(t,e,i,n,s){var r=t.style,a=\"cssFloat\"in r?\"cssFloat\":\"styleFloat\";return new dt(r,a,0,0,s,-1,i,!1,0,r[a],e)}});function At(t){var e,i=this.t,n=i.filter||st(this.data,\"filter\"),s=0|this.s+this.c*t;100==s&&(e=-1===n.indexOf(\"atrix(\")&&-1===n.indexOf(\"radient(\")&&-1===n.indexOf(\"oader(\")?(i.removeAttribute(\"filter\"),!st(this.data,\"filter\")):(i.filter=n.replace(h,\"\"),!0)),e||(this.xn1&&(i.filter=n=n||\"alpha(opacity=\"+s+\")\"),-1===n.indexOf(\"pacity\")?0==s&&this.xn1||(i.filter=n+\" alpha(opacity=\"+s+\")\"):i.filter=n.replace(E,\"opacity=\"+s))}vt(\"opacity,alpha,autoAlpha\",{defaultValue:\"1\",parser:function(t,e,i,n,s,r){var a=parseFloat(st(t,\"opacity\",k,!1,\"1\")),o=t.style,l=\"autoAlpha\"===i;return\"string\"==typeof e&&\"=\"===e.charAt(1)&&(e=(\"-\"===e.charAt(0)?-1:1)*parseFloat(e.substr(2))+a),l&&1===a&&\"hidden\"===st(t,\"visibility\",k)&&0!==e&&(a=0),Z?s=new dt(o,\"opacity\",a,e-a,s):((s=new dt(o,\"opacity\",100*a,100*(e-a),s)).xn1=l?1:0,o.zoom=1,s.type=2,s.b=\"alpha(opacity=\"+s.s+\")\",s.e=\"alpha(opacity=\"+(s.s+s.c)+\")\",s.data=t,s.plugin=r,s.setRatio=At),l&&((s=new dt(o,\"visibility\",0,0,s,-1,null,!1,0,0!==a?\"inherit\":\"hidden\",0===e?\"hidden\":\"inherit\")).xs0=\"inherit\",n._overwriteProps.push(s.n),n._overwriteProps.push(i)),s}});function Mt(t,e){e&&(t.removeProperty?(\"ms\"===e.substr(0,2)&&(e=\"M\"+e.substr(1)),t.removeProperty(e.replace(u,\"-$1\").toLowerCase())):t.removeAttribute(e))}function Rt(t){if(this.t._gsClassPT=this,1===t||0===t){this.t.setAttribute(\"class\",0===t?this.b:this.e);for(var e=this.data,i=this.t.style;e;)e.v?i[e.p]=e.v:Mt(i,e.p),e=e._next;1===t&&this.t._gsClassPT===this&&(this.t._gsClassPT=null)}else this.t.getAttribute(\"class\")!==this.e&&this.t.setAttribute(\"class\",this.e)}vt(\"className\",{parser:function(t,e,i,n,s,r,a){var o,l,h,c,u,p=t.getAttribute(\"class\")||\"\",f=t.style.cssText;if((s=n._classNamePT=new dt(t,i,0,0,s,2)).setRatio=Rt,s.pr=-11,d=!0,s.b=p,l=g(t,k),h=t._gsClassPT){for(c={},u=h.data;u;)c[u.p]=1,u=u._next;h.setRatio(1)}return(t._gsClassPT=s).e=\"=\"!==e.charAt(1)?e:p.replace(RegExp(\"\\\\s*\\\\b\"+e.substr(2)+\"\\\\b\"),\"\")+(\"+\"===e.charAt(0)?\" \"+e.substr(2):\"\"),n._tween._duration&&(t.setAttribute(\"class\",s.e),o=v(t,l,g(t),a,c),t.setAttribute(\"class\",p),s.data=o.firstMPT,t.style.cssText=f,s=s.xfirst=n.parse(t,o.difs,s,r)),s}});function Dt(t){if((1===t||0===t)&&this.data._totalTime===this.data._totalDuration&&\"isFromStart\"!==this.data.data){var e,i,n,s,r=this.t.style,a=_.transform.parse;if(\"all\"===this.e)s=!(r.cssText=\"\");else for(n=(e=this.e.split(\",\")).length;-1<--n;)i=e[n],_[i]&&(_[i].parse===a?s=!0:i=\"transformOrigin\"===i?Tt:_[i].p),Mt(r,i);s&&(Mt(r,xt),this.t._gsTransform&&delete this.t._gsTransform)}}for(vt(\"clearProps\",{parser:function(t,e,i,n,s){return(s=new dt(t,i,0,0,s,2)).setRatio=Dt,s.e=e,s.pr=-10,s.data=n._tween,d=!0,s}}),t=\"bezier,throwProps,physicsProps,physics2D\".split(\",\"),mt=t.length;mt--;)!function(t){var l;_[t]||(l=t.charAt(0).toUpperCase()+t.substr(1)+\"Plugin\",vt(t,{parser:function(t,e,i,n,s,r,a){var o=(window.GreenSockGlobals||window).com.greensock.plugins[l];return o?(o._cssRegister(),_[i].parse(t,e,i,n,s,r,a)):(m(\"Error: \"+l+\" js file not loaded.\"),s)}}))}(t[mt]);(t=J.prototype)._firstPT=null,t._onInitTween=function(t,e,i){if(!t.nodeType)return!1;this._target=t,this._tween=i,this._vars=e,C=e.autoRound,d=!1,T=e.suffixMap||J.suffixMap,k=nt(t,\"\"),f=this._overwriteProps;var n,s,r,a,o,l,h,c,u,p=t.style;if(b&&\"\"===p.zIndex&&(\"auto\"!==(n=st(t,\"zIndex\",k))&&\"\"!==n||this._addLazySet(p,\"zIndex\",0)),\"string\"==typeof e&&(a=p.cssText,n=g(t,k),p.cssText=a+\";\"+e,n=v(t,n,g(t)).difs,!Z&&z.test(e)&&(n.opacity=parseFloat(RegExp.$1)),e=n,p.cssText=a),this._firstPT=s=this.parse(t,e,null),this._transformType){for(u=3===this._transformType,xt?A&&(b=!0,\"\"===p.zIndex&&(\"auto\"!==(h=st(t,\"zIndex\",k))&&\"\"!==h||this._addLazySet(p,\"zIndex\",0)),M&&this._addLazySet(p,\"WebkitBackfaceVisibility\",this._vars.WebkitBackfaceVisibility||(u?\"visible\":\"hidden\"))):p.zoom=1,r=s;r&&r._next;)r=r._next;c=new dt(t,\"transform\",0,0,null,2),this._linkCSSP(c,null,r),c.setRatio=u&&kt?Ot:xt?Ct:wt,c.data=this._transform||St(t,k,!0),f.pop()}if(d){for(;s;){for(l=s._next,r=a;r&&r.pr>s.pr;)r=r._next;(s._prev=r?r._prev:o)?s._prev._next=s:a=s,(s._next=r)?r._prev=s:o=s,s=l}this._firstPT=a}return!0},t.parse=function(t,e,i,n){var s,r,a,o,l,h,c,u,p,f,d=t.style;for(s in e)h=e[s],(r=_[s])?i=r.parse(t,h,s,this,i,n,e):(l=st(t,s,k)+\"\",p=\"string\"==typeof h,\"color\"===s||\"fill\"===s||\"stroke\"===s||-1!==s.indexOf(\"Color\")||p&&N.test(h)?(p||(h=(3<(h=O(h)).length?\"rgba(\":\"rgb(\")+h.join(\",\")+\")\"),i=_t(d,s,l,h,!0,\"transparent\",i,0,n)):!p||-1===h.indexOf(\" \")&&-1===h.indexOf(\",\")?(c=(a=parseFloat(l))||0===a?l.substr((a+\"\").length):\"\",\"\"!==l&&\"auto\"!==l||(c=\"width\"===s||\"height\"===s?(a=function(t,e,i){var n=parseFloat(\"width\"===e?t.offsetWidth:t.offsetHeight),s=ot[e],r=s.length;for(i=i||nt(t,null);-1<--r;)n-=parseFloat(st(t,\"padding\"+s[r],i,!0))||0,n-=parseFloat(st(t,\"border\"+s[r]+\"Width\",i,!0))||0;return n}(t,s,k),\"px\"):\"left\"===s||\"top\"===s?(a=at(t,s,k),\"px\"):(a=\"opacity\"!==s?0:1,\"\")),\"\"===(u=(f=p&&\"=\"===h.charAt(1))?(o=parseInt(h.charAt(0)+\"1\",10),h=h.substr(2),o*=parseFloat(h),h.replace(X,\"\")):(o=parseFloat(h),p&&h.substr((o+\"\").length)||\"\"))&&(u=s in T?T[s]:c),h=o||0===o?(f?o+a:o)+u:e[s],c!==u&&\"\"!==u&&(o||0===o)&&a&&(a=rt(t,s,a,c),\"%\"===u?(a/=rt(t,s,100,\"%\")/100,!0!==e.strictUnits&&(l=a+\"%\")):\"em\"===u?a/=rt(t,s,1,\"em\"):\"px\"!==u&&(o=rt(t,s,o,u),u=\"px\"),f&&(o||0===o)&&(h=o+a+u)),f&&(o+=a),!a&&0!==a||!o&&0!==o?void 0!==d[s]&&(h||\"NaN\"!=h+\"\"&&null!=h)?(i=new dt(d,s,o||a||0,0,i,-1,s,!1,0,l,h)).xs0=\"none\"!==h||\"display\"!==s&&-1===s.indexOf(\"Style\")?h:l:m(\"invalid \"+s+\" tween value: \"+e[s]):(i=new dt(d,s,a,o-a,i,0,s,!1!==C&&(\"px\"===u||\"zIndex\"===s),0,l,h)).xs0=u):i=_t(d,s,l,h,!0,null,i,0,n)),n&&i&&!i.plugin&&(i.plugin=n);return i},t.setRatio=function(t){var e,i,n,s=this._firstPT;if(1!==t||this._tween._time!==this._tween._duration&&0!==this._tween._time)if(t||this._tween._time!==this._tween._duration&&0!==this._tween._time||-1e-6===this._tween._rawPrevTime)for(;s;){if(e=s.c*t+s.s,s.r?e=Math.round(e):e<1e-6&&-1e-6n;n++)i+=s[\"xn\"+n]+s[\"xs\"+(n+1)];s.t[s.p]=i}else-1===s.type?s.t[s.p]=s.xs0:s.setRatio&&s.setRatio(t);else s.t[s.p]=e+s.xs0;s=s._next}else for(;s;)2!==s.type?s.t[s.p]=s.b:s.setRatio(t),s=s._next;else for(;s;)2!==s.type?s.t[s.p]=s.e:s.setRatio(t),s=s._next},t._enableTransforms=function(t){this._transformType=t||3===this._transformType?3:2,this._transform=this._transform||St(this._target,k,!0)};function It(){this.t[this.p]=this.e,this.data._linkCSSP(this,this._next,null,!0)}t._addLazySet=function(t,e,i){var n=this._firstPT=new dt(t,e,0,0,this._firstPT,2);n.e=i,n.setRatio=It,n.data=this},t._linkCSSP=function(t,e,i,n){return t&&(e&&(e._prev=t),t._next&&(t._next._prev=t._prev),t._prev?t._prev._next=t._next:this._firstPT===t&&(this._firstPT=t._next,n=!0),i?i._next=t:n||null!==this._firstPT||(this._firstPT=t),t._next=e,t._prev=i),t},t._kill=function(t){var e,i,n,s=t;if(t.autoAlpha||t.alpha){for(i in s={},t)s[i]=t[i];s.opacity=1,s.autoAlpha&&(s.visibility=1)}return t.className&&(e=this._classNamePT)&&((n=e.xfirst)&&n._prev?this._linkCSSP(n._prev,e._next,n._prev._prev):n===this._firstPT&&(this._firstPT=e._next),e._next&&this._linkCSSP(e._next,e._next._next,n._prev),this._classNamePT=null),r.prototype._kill.call(this,s)};function jt(t,e,i){var n,s,r,a;if(t.slice)for(s=t.length;-1<--s;)jt(t[s],e,i);else for(s=(n=t.childNodes).length;-1<--s;)a=(r=n[s]).type,r.style&&(e.push(g(r)),i&&i.push(r)),1!==a&&9!==a&&11!==a||!r.childNodes.length||jt(r,e,i)}return J.cascadeTo=function(t,e,i){var n,s,r,a=p.to(t,e,i),o=[a],l=[],h=[],c=[],u=p._internals.reservedProps;for(t=a._targets||a.target,jt(t,l,c),a.render(e,!0),jt(t,h),a.render(0,!0),a._enabled(!0),n=c.length;-1<--n;)if((s=v(c[n],l[n],h[n])).firstMPT){for(r in s=s.difs,i)u[r]&&(s[r]=i[r]);o.push(p.to(c[n],e,s))}return o},r.activate([J]),J},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],13:[function(t,e,i){\"use strict\";var n=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&\"function\"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?\"symbol\":typeof t};(window._gsQueue||(window._gsQueue=[])).push(function(){function r(t,e){var i=\"x\"===e?\"Width\":\"Height\",n=\"scroll\"+i,s=\"client\"+i,r=document.body;return t===o||t===a||t===r?Math.max(a[n],r[n])-(o[\"inner\"+i]||Math.max(a[s],r[s])):t[n]-t[\"offset\"+i]}var a=document.documentElement,o=window,t=window._gsDefine.plugin({propName:\"scrollTo\",API:2,version:\"1.7.3\",init:function(t,e,i){return this._wdw=t===o,this._target=t,this._tween=i,\"object\"!=(void 0===e?\"undefined\":n(e))&&(e={y:e}),this._autoKill=!1!==e.autoKill,this.x=this.xPrev=this.getX(),this.y=this.yPrev=this.getY(),null!=e.x?(this._addTween(this,\"x\",this.x,\"max\"===e.x?r(t,\"x\"):e.x,\"scrollTo_x\",!0),this._overwriteProps.push(\"scrollTo_x\")):this.skipX=!0,null!=e.y?(this._addTween(this,\"y\",this.y,\"max\"===e.y?r(t,\"y\"):e.y,\"scrollTo_y\",!0),this._overwriteProps.push(\"scrollTo_y\")):this.skipY=!0,!0},set:function(t){this._super.setRatio.call(this,t);var e=this._wdw||!this.skipX?this.getX():this.xPrev,i=this._wdw||!this.skipY?this.getY():this.yPrev,n=i-this.yPrev,s=e-this.xPrev;this._autoKill&&(!this.skipX&&(7e&&(this.skipX=!0),!this.skipY&&(7i&&(this.skipY=!0),this.skipX&&this.skipY&&this._tween.kill()),this._wdw?o.scrollTo(this.skipX?e:this.x,this.skipY?i:this.y):(this.skipY||(this._target.scrollTop=this.y),this.skipX||(this._target.scrollLeft=this.x)),this.xPrev=this.x,this.yPrev=this.y}}),e=t.prototype;t.max=r,e.getX=function(){return this._wdw?null!=o.pageXOffset?o.pageXOffset:null!=a.scrollLeft?a.scrollLeft:document.body.scrollLeft:this._target.scrollLeft},e.getY=function(){return this._wdw?null!=o.pageYOffset?o.pageYOffset:null!=a.scrollTop?a.scrollTop:document.body.scrollTop:this._target.scrollTop},e._kill=function(t){return t.scrollTo_x&&(this.skipX=!0),t.scrollTo_y&&(this.skipY=!0),this._super._kill.call(this,t)}}),window._gsDefine&&window._gsQueue.pop()()},{}]},{},[2]);"],"file":"wpr-admin.js"} \ No newline at end of file +{"version":3,"names":[],"mappings":"","sources":["wpr-admin.js"],"sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i= 0) {\n return;\n }\n\n $.post(ajaxurl, {\n action: 'rocket_toggle_option',\n _ajax_nonce: rocket_ajax_data.nonce,\n option: {\n name: name,\n value: value\n }\n }, function (response) {});\n });\n /**\n * Save enable CPCSS for mobiles option.\n */\n\n $('#wpr-action-rocket_enable_mobile_cpcss').on('click', function (e) {\n e.preventDefault();\n $('#wpr-action-rocket_enable_mobile_cpcss').addClass('wpr-isLoading');\n $.post(ajaxurl, {\n action: 'rocket_enable_mobile_cpcss',\n _ajax_nonce: rocket_ajax_data.nonce\n }, function (response) {\n if (response.success) {\n // Hide Mobile CPCSS btn on success.\n $('#wpr-action-rocket_enable_mobile_cpcss').hide();\n $('.wpr-hide-on-click').hide();\n $('.wpr-show-on-click').show();\n $('#wpr-action-rocket_enable_mobile_cpcss').removeClass('wpr-isLoading');\n }\n });\n });\n /**\n * Save enable Google Fonts Optimization option.\n */\n\n $('#wpr-action-rocket_enable_google_fonts').on('click', function (e) {\n e.preventDefault();\n $('#wpr-action-rocket_enable_google_fonts').addClass('wpr-isLoading');\n $.post(ajaxurl, {\n action: 'rocket_enable_google_fonts',\n _ajax_nonce: rocket_ajax_data.nonce\n }, function (response) {\n if (response.success) {\n // Hide Mobile CPCSS btn on success.\n $('#wpr-action-rocket_enable_google_fonts').hide();\n $('.wpr-hide-on-click').hide();\n $('.wpr-show-on-click').show();\n $('#wpr-action-rocket_enable_google_fonts').removeClass('wpr-isLoading');\n $('#minify_google_fonts').val(1);\n }\n });\n });\n $('#rocket-dismiss-promotion').on('click', function (e) {\n e.preventDefault();\n $.post(ajaxurl, {\n action: 'rocket_dismiss_promo',\n nonce: rocket_ajax_data.nonce\n }, function (response) {\n if (response.success) {\n $('#rocket-promo-banner').hide('slow');\n }\n });\n });\n $('#rocket-dismiss-renewal').on('click', function (e) {\n e.preventDefault();\n $.post(ajaxurl, {\n action: 'rocket_dismiss_renewal',\n nonce: rocket_ajax_data.nonce\n }, function (response) {\n if (response.success) {\n $('#rocket-renewal-banner').hide('slow');\n }\n });\n });\n $('#wpr-update-exclusion-list').on('click', function (e) {\n e.preventDefault();\n $('#wpr-update-exclusion-msg').html('');\n $.ajax({\n url: rocket_ajax_data.rest_url,\n beforeSend: function (xhr) {\n xhr.setRequestHeader('X-WP-Nonce', rocket_ajax_data.rest_nonce);\n },\n method: \"PUT\",\n success: function (responses) {\n let exclusion_msg_container = $('#wpr-update-exclusion-msg');\n exclusion_msg_container.html('');\n\n if (undefined !== responses['success']) {\n exclusion_msg_container.append('
' + responses['message'] + '
');\n return;\n }\n\n Object.keys(responses).forEach(response_key => {\n exclusion_msg_container.append('' + response_key + ': ');\n exclusion_msg_container.append(responses[response_key]['message']);\n exclusion_msg_container.append('
');\n });\n }\n });\n });\n /**\n * Enable mobile cache option.\n */\n\n $('#wpr_enable_mobile_cache').on('click', function (e) {\n e.preventDefault();\n $('#wpr_enable_mobile_cache').addClass('wpr-isLoading');\n $.post(ajaxurl, {\n action: 'rocket_enable_mobile_cache',\n _ajax_nonce: rocket_ajax_data.nonce\n }, function (response) {\n if (response.success) {\n // Hide Mobile cache enable button on success.\n $('#wpr_enable_mobile_cache').hide();\n $('#wpr_mobile_cache_default').hide();\n $('#wpr_mobile_cache_response').show();\n $('#wpr_enable_mobile_cache').removeClass('wpr-isLoading'); // Set values of mobile cache and separate cache files for mobiles option to 1.\n\n $('#cache_mobile').val(1);\n $('#do_caching_mobile_files').val(1);\n }\n });\n });\n});\n\n},{}],2:[function(require,module,exports){\n\"use strict\";\n\nrequire(\"../lib/greensock/TweenLite.min.js\");\n\nrequire(\"../lib/greensock/TimelineLite.min.js\");\n\nrequire(\"../lib/greensock/easing/EasePack.min.js\");\n\nrequire(\"../lib/greensock/plugins/CSSPlugin.min.js\");\n\nrequire(\"../lib/greensock/plugins/ScrollToPlugin.min.js\");\n\nrequire(\"../global/pageManager.js\");\n\nrequire(\"../global/main.js\");\n\nrequire(\"../global/fields.js\");\n\nrequire(\"../global/beacon.js\");\n\nrequire(\"../global/ajax.js\");\n\nrequire(\"../global/rocketcdn.js\");\n\nrequire(\"../global/countdown.js\");\n\n},{\"../global/ajax.js\":1,\"../global/beacon.js\":3,\"../global/countdown.js\":4,\"../global/fields.js\":5,\"../global/main.js\":6,\"../global/pageManager.js\":7,\"../global/rocketcdn.js\":8,\"../lib/greensock/TimelineLite.min.js\":9,\"../lib/greensock/TweenLite.min.js\":10,\"../lib/greensock/easing/EasePack.min.js\":11,\"../lib/greensock/plugins/CSSPlugin.min.js\":12,\"../lib/greensock/plugins/ScrollToPlugin.min.js\":13}],3:[function(require,module,exports){\n\"use strict\";\n\nvar $ = jQuery;\n$(document).ready(function () {\n if ('Beacon' in window) {\n /**\n * Show beacons on button \"help\" click\n */\n var $help = $('.wpr-infoAction--help');\n $help.on('click', function (e) {\n var ids = $(this).data('beacon-id');\n wprCallBeacon(ids);\n return false;\n });\n\n function wprCallBeacon(aID) {\n aID = aID.split(',');\n\n if (aID.length === 0) {\n return;\n }\n\n if (aID.length > 1) {\n window.Beacon(\"suggest\", aID);\n setTimeout(function () {\n window.Beacon(\"open\");\n }, 200);\n } else {\n window.Beacon(\"article\", aID.toString());\n }\n }\n }\n});\n\n},{}],4:[function(require,module,exports){\n\"use strict\";\n\nfunction getTimeRemaining(endtime) {\n const start = Date.now();\n const total = endtime * 1000 - start;\n const seconds = Math.floor(total / 1000 % 60);\n const minutes = Math.floor(total / 1000 / 60 % 60);\n const hours = Math.floor(total / (1000 * 60 * 60) % 24);\n const days = Math.floor(total / (1000 * 60 * 60 * 24));\n return {\n total,\n days,\n hours,\n minutes,\n seconds\n };\n}\n\nfunction initializeClock(id, endtime) {\n const clock = document.getElementById(id);\n\n if (clock === null) {\n return;\n }\n\n const daysSpan = clock.querySelector('.rocket-countdown-days');\n const hoursSpan = clock.querySelector('.rocket-countdown-hours');\n const minutesSpan = clock.querySelector('.rocket-countdown-minutes');\n const secondsSpan = clock.querySelector('.rocket-countdown-seconds');\n\n function updateClock() {\n const t = getTimeRemaining(endtime);\n\n if (t.total < 0) {\n clearInterval(timeinterval);\n return;\n }\n\n daysSpan.innerHTML = t.days;\n hoursSpan.innerHTML = ('0' + t.hours).slice(-2);\n minutesSpan.innerHTML = ('0' + t.minutes).slice(-2);\n secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);\n }\n\n updateClock();\n const timeinterval = setInterval(updateClock, 1000);\n}\n\nfunction rucssTimer(id, endtime) {\n const timer = document.getElementById(id);\n const notice = document.getElementById('rocket-notice-rucss-processing');\n const success = document.getElementById('rocket-notice-rucss-success');\n\n if (timer === null) {\n return;\n }\n\n function updateTimer() {\n const start = Date.now();\n const remaining = Math.floor((endtime * 1000 - start) / 1000);\n\n if (remaining <= 0) {\n clearInterval(timerInterval);\n\n if (notice !== null) {\n notice.classList.add('hidden');\n }\n\n if (success !== null) {\n success.classList.remove('hidden');\n }\n\n if (rocket_ajax_data.cron_disabled) {\n return;\n }\n\n const data = new FormData();\n data.append('action', 'rocket_spawn_cron');\n data.append('nonce', rocket_ajax_data.nonce);\n fetch(ajaxurl, {\n method: 'POST',\n credentials: 'same-origin',\n body: data\n });\n return;\n }\n\n timer.innerHTML = remaining;\n }\n\n updateTimer();\n const timerInterval = setInterval(updateTimer, 1000);\n}\n\nif (!Date.now) {\n Date.now = function now() {\n return new Date().getTime();\n };\n}\n\nif (typeof rocket_ajax_data.promo_end !== 'undefined') {\n initializeClock('rocket-promo-countdown', rocket_ajax_data.promo_end);\n}\n\nif (typeof rocket_ajax_data.license_expiration !== 'undefined') {\n initializeClock('rocket-renew-countdown', rocket_ajax_data.license_expiration);\n}\n\nif (typeof rocket_ajax_data.notice_end_time !== 'undefined') {\n rucssTimer('rocket-rucss-timer', rocket_ajax_data.notice_end_time);\n}\n\n},{}],5:[function(require,module,exports){\n\"use strict\";\n\nvar $ = jQuery;\n$(document).ready(function () {\n /***\n * Check parent / show children\n ***/\n function wprShowChildren(aElem) {\n var parentId, $children;\n aElem = $(aElem);\n parentId = aElem.attr('id');\n $children = $('[data-parent=\"' + parentId + '\"]'); // Test check for switch\n\n if (aElem.is(':checked')) {\n $children.addClass('wpr-isOpen');\n $children.each(function () {\n if ($(this).find('input[type=checkbox]').is(':checked')) {\n var id = $(this).find('input[type=checkbox]').attr('id');\n $('[data-parent=\"' + id + '\"]').addClass('wpr-isOpen');\n }\n });\n } else {\n $children.removeClass('wpr-isOpen');\n $children.each(function () {\n var id = $(this).find('input[type=checkbox]').attr('id');\n $('[data-parent=\"' + id + '\"]').removeClass('wpr-isOpen');\n });\n }\n }\n /**\n * Tell if the given child field has an active parent field.\n *\n * @param object $field A jQuery object of a \".wpr-field\" field.\n * @return bool|null\n */\n\n\n function wprIsParentActive($field) {\n var $parent;\n\n if (!$field.length) {\n // ¯\\_(ツ)_/¯\n return null;\n }\n\n $parent = $field.data('parent');\n\n if (typeof $parent !== 'string') {\n // This field has no parent field: then we can display it.\n return true;\n }\n\n $parent = $parent.replace(/^\\s+|\\s+$/g, '');\n\n if ('' === $parent) {\n // This field has no parent field: then we can display it.\n return true;\n }\n\n $parent = $('#' + $parent);\n\n if (!$parent.length) {\n // This field's parent is missing: let's consider it's not active then.\n return false;\n }\n\n if (!$parent.is(':checked') && $parent.is('input')) {\n // This field's parent is checkbox and not checked: don't display the field then.\n return false;\n }\n\n if (!$parent.hasClass('radio-active') && $parent.is('button')) {\n // This field's parent button and is not active: don't display the field then.\n return false;\n } // Go recursive to the last parent.\n\n\n return wprIsParentActive($parent.closest('.wpr-field'));\n }\n /**\n * Masks sensitive information in an input field by replacing all but the last 4 characters with asterisks.\n *\n * @param {string} id_selector - The ID of the input field to be masked.\n * @returns {void} - Modifies the input field value in-place.\n *\n * @example\n * // HTML: \n * maskField('creditCardInput');\n * // Result: Updates the input field value to '************3456'.\n */\n\n\n function maskField(proxy_selector, concrete_selector) {\n var concrete = {\n 'val': concrete_selector.val(),\n 'length': concrete_selector.val().length\n };\n\n if (concrete.length > 4) {\n var hiddenPart = '\\u2022'.repeat(Math.max(0, concrete.length - 4));\n var visiblePart = concrete.val.slice(-4); // Combine the hidden and visible parts\n\n var maskedValue = hiddenPart + visiblePart;\n proxy_selector.val(maskedValue);\n } // Ensure events are not added more than once\n\n\n if (!proxy_selector.data('eventsAttached')) {\n proxy_selector.on('input', handleInput);\n proxy_selector.on('focus', handleFocus);\n proxy_selector.data('eventsAttached', true);\n }\n /**\n * Handle the input event\n */\n\n\n function handleInput() {\n var proxyValue = proxy_selector.val();\n\n if (proxyValue.indexOf('\\u2022') === -1) {\n concrete_selector.val(proxyValue);\n }\n }\n /**\n * Handle the focus event\n */\n\n\n function handleFocus() {\n var concrete_value = concrete_selector.val();\n proxy_selector.val(concrete_value);\n }\n } // Update the concrete field when the proxy is updated.\n\n\n maskField($('#cloudflare_api_key_mask'), $('#cloudflare_api_key'));\n maskField($('#cloudflare_zone_id_mask'), $('#cloudflare_zone_id')); // Display/Hide childern fields on checkbox change.\n\n $('.wpr-isParent input[type=checkbox]').on('change', function () {\n wprShowChildren($(this));\n }); // On page load, display the active fields.\n\n $('.wpr-field--children').each(function () {\n var $field = $(this);\n\n if (wprIsParentActive($field)) {\n $field.addClass('wpr-isOpen');\n }\n });\n /***\n * Warning fields\n ***/\n\n var $warningParent = $('.wpr-field--parent');\n var $warningParentInput = $('.wpr-field--parent input[type=checkbox]'); // If already checked\n\n $warningParentInput.each(function () {\n wprShowChildren($(this));\n });\n $warningParent.on('change', function () {\n wprShowWarning($(this));\n });\n\n function wprShowWarning(aElem) {\n var $warningField = aElem.next('.wpr-fieldWarning'),\n $thisCheckbox = aElem.find('input[type=checkbox]'),\n $nextWarning = aElem.parent().next('.wpr-warningContainer'),\n $nextFields = $nextWarning.find('.wpr-field'),\n parentId = aElem.find('input[type=checkbox]').attr('id'),\n $children = $('[data-parent=\"' + parentId + '\"]'); // Check warning parent\n\n if ($thisCheckbox.is(':checked')) {\n $warningField.addClass('wpr-isOpen');\n $thisCheckbox.prop('checked', false);\n aElem.trigger('change');\n var $warningButton = $warningField.find('.wpr-button'); // Validate the warning\n\n $warningButton.on('click', function () {\n $thisCheckbox.prop('checked', true);\n $warningField.removeClass('wpr-isOpen');\n $children.addClass('wpr-isOpen'); // If next elem = disabled\n\n if ($nextWarning.length > 0) {\n $nextFields.removeClass('wpr-isDisabled');\n $nextFields.find('input').prop('disabled', false);\n }\n\n return false;\n });\n } else {\n $nextFields.addClass('wpr-isDisabled');\n $nextFields.find('input').prop('disabled', true);\n $nextFields.find('input[type=checkbox]').prop('checked', false);\n $children.removeClass('wpr-isOpen');\n }\n }\n /**\n * CNAMES add/remove lines\n */\n\n\n $(document).on('click', '.wpr-multiple-close', function (e) {\n e.preventDefault();\n $(this).parent().slideUp('slow', function () {\n $(this).remove();\n });\n });\n $('.wpr-button--addMulti').on('click', function (e) {\n e.preventDefault();\n $($('#wpr-cname-model').html()).appendTo('#wpr-cnames-list');\n });\n /***\n * Wpr Radio button\n ***/\n\n var disable_radio_warning = false;\n $(document).on('click', '.wpr-radio-buttons-container button', function (e) {\n e.preventDefault();\n\n if ($(this).hasClass('radio-active')) {\n return false;\n }\n\n var $parent = $(this).parents('.wpr-radio-buttons');\n $parent.find('.wpr-radio-buttons-container button').removeClass('radio-active');\n $parent.find('.wpr-extra-fields-container').removeClass('wpr-isOpen');\n $parent.find('.wpr-fieldWarning').removeClass('wpr-isOpen');\n $(this).addClass('radio-active');\n wprShowRadioWarning($(this));\n });\n\n function wprShowRadioWarning($elm) {\n disable_radio_warning = false;\n $elm.trigger(\"before_show_radio_warning\", [$elm]);\n\n if (!$elm.hasClass('has-warning') || disable_radio_warning) {\n wprShowRadioButtonChildren($elm);\n $elm.trigger(\"radio_button_selected\", [$elm]);\n return false;\n }\n\n var $warningField = $('[data-parent=\"' + $elm.attr('id') + '\"].wpr-fieldWarning');\n $warningField.addClass('wpr-isOpen');\n var $warningButton = $warningField.find('.wpr-button'); // Validate the warning\n\n $warningButton.on('click', function () {\n $warningField.removeClass('wpr-isOpen');\n wprShowRadioButtonChildren($elm);\n $elm.trigger(\"radio_button_selected\", [$elm]);\n return false;\n });\n }\n\n function wprShowRadioButtonChildren($elm) {\n var $parent = $elm.parents('.wpr-radio-buttons');\n var $children = $('.wpr-extra-fields-container[data-parent=\"' + $elm.attr('id') + '\"]');\n $children.addClass('wpr-isOpen');\n }\n /***\n * Wpr Optimize Css Delivery Field\n ***/\n\n\n var rucssActive = parseInt($('#remove_unused_css').val());\n $(\"#optimize_css_delivery_method .wpr-radio-buttons-container button\").on(\"radio_button_selected\", function (event, $elm) {\n toggleActiveOptimizeCssDeliveryMethod($elm);\n });\n $(\"#optimize_css_delivery\").on(\"change\", function () {\n if ($(this).is(\":not(:checked)\")) {\n disableOptimizeCssDelivery();\n } else {\n var default_radio_button_id = '#' + $('#optimize_css_delivery_method').data('default');\n $(default_radio_button_id).trigger('click');\n }\n });\n\n function toggleActiveOptimizeCssDeliveryMethod($elm) {\n var optimize_method = $elm.data('value');\n\n if ('remove_unused_css' === optimize_method) {\n $('#remove_unused_css').val(1);\n $('#async_css').val(0);\n } else {\n $('#remove_unused_css').val(0);\n $('#async_css').val(1);\n }\n }\n\n function disableOptimizeCssDelivery() {\n $('#remove_unused_css').val(0);\n $('#async_css').val(0);\n }\n\n $(\"#optimize_css_delivery_method .wpr-radio-buttons-container button\").on(\"before_show_radio_warning\", function (event, $elm) {\n disable_radio_warning = 'remove_unused_css' === $elm.data('value') && 1 === rucssActive;\n });\n $(\".wpr-multiple-select .wpr-list-header-arrow\").click(function (e) {\n $(e.target).closest('.wpr-multiple-select .wpr-list').toggleClass('open');\n });\n $('.wpr-multiple-select .wpr-checkbox').click(function (e) {\n const checkbox = $(this).find('input');\n const is_checked = checkbox.attr('checked') !== undefined;\n checkbox.attr('checked', is_checked ? null : 'checked');\n const sub_checkboxes = $(checkbox).closest('.wpr-list').find('.wpr-list-body input[type=\"checkbox\"]');\n\n if (checkbox.hasClass('wpr-main-checkbox')) {\n $.map(sub_checkboxes, checkbox => {\n $(checkbox).attr('checked', is_checked ? null : 'checked');\n });\n return;\n }\n\n const main_checkbox = $(checkbox).closest('.wpr-list').find('.wpr-main-checkbox');\n const sub_checked = $.map(sub_checkboxes, checkbox => {\n if ($(checkbox).attr('checked') === undefined) {\n return;\n }\n\n return checkbox;\n });\n main_checkbox.attr('checked', sub_checked.length === sub_checkboxes.length ? 'checked' : null);\n });\n\n if ($('.wpr-main-checkbox').length > 0) {\n $('.wpr-main-checkbox').each((checkbox_key, checkbox) => {\n let parent_list = $(checkbox).parents('.wpr-list');\n let not_checked = parent_list.find('.wpr-list-body input[type=checkbox]:not(:checked)').length;\n $(checkbox).attr('checked', not_checked <= 0 ? 'checked' : null);\n });\n }\n});\n\n},{}],6:[function(require,module,exports){\n\"use strict\";\n\nvar $ = jQuery;\n$(document).ready(function () {\n /***\n * Dashboard notice\n ***/\n var $notice = $('.wpr-notice');\n var $noticeClose = $('#wpr-congratulations-notice');\n $noticeClose.on('click', function () {\n wprCloseDashboardNotice();\n return false;\n });\n\n function wprCloseDashboardNotice() {\n var vTL = new TimelineLite().to($notice, 1, {\n autoAlpha: 0,\n x: 40,\n ease: Power4.easeOut\n }).to($notice, 0.6, {\n height: 0,\n marginTop: 0,\n ease: Power4.easeOut\n }, '=-.4').set($notice, {\n 'display': 'none'\n });\n }\n /**\n * Rocket Analytics notice info collect\n */\n\n\n $('.rocket-analytics-data-container').hide();\n $('.rocket-preview-analytics-data').on('click', function (e) {\n e.preventDefault();\n $(this).parent().next('.rocket-analytics-data-container').toggle();\n });\n /***\n * Hide / show Rocket addon tabs.\n ***/\n\n $('.wpr-toggle-button').each(function () {\n var $button = $(this);\n var $checkbox = $button.closest('.wpr-fieldsContainer-fieldset').find('.wpr-radio :checkbox');\n var $menuItem = $('[href=\"' + $button.attr('href') + '\"].wpr-menuItem');\n $checkbox.on('change', function () {\n if ($checkbox.is(':checked')) {\n $menuItem.css('display', 'block');\n $button.css('display', 'inline-block');\n } else {\n $menuItem.css('display', 'none');\n $button.css('display', 'none');\n }\n }).trigger('change');\n });\n /***\n * Show popin analytics\n ***/\n\n var $wprAnalyticsPopin = $('.wpr-Popin-Analytics'),\n $wprPopinOverlay = $('.wpr-Popin-overlay'),\n $wprAnalyticsClosePopin = $('.wpr-Popin-Analytics-close'),\n $wprAnalyticsPopinButton = $('.wpr-Popin-Analytics .wpr-button'),\n $wprAnalyticsOpenPopin = $('.wpr-js-popin');\n $wprAnalyticsOpenPopin.on('click', function (e) {\n e.preventDefault();\n wprOpenAnalytics();\n return false;\n });\n $wprAnalyticsClosePopin.on('click', function (e) {\n e.preventDefault();\n wprCloseAnalytics();\n return false;\n });\n $wprAnalyticsPopinButton.on('click', function (e) {\n e.preventDefault();\n wprActivateAnalytics();\n return false;\n });\n\n function wprOpenAnalytics() {\n var vTL = new TimelineLite().set($wprAnalyticsPopin, {\n 'display': 'block'\n }).set($wprPopinOverlay, {\n 'display': 'block'\n }).fromTo($wprPopinOverlay, 0.6, {\n autoAlpha: 0\n }, {\n autoAlpha: 1,\n ease: Power4.easeOut\n }).fromTo($wprAnalyticsPopin, 0.6, {\n autoAlpha: 0,\n marginTop: -24\n }, {\n autoAlpha: 1,\n marginTop: 0,\n ease: Power4.easeOut\n }, '=-.5');\n }\n\n function wprCloseAnalytics() {\n var vTL = new TimelineLite().fromTo($wprAnalyticsPopin, 0.6, {\n autoAlpha: 1,\n marginTop: 0\n }, {\n autoAlpha: 0,\n marginTop: -24,\n ease: Power4.easeOut\n }).fromTo($wprPopinOverlay, 0.6, {\n autoAlpha: 1\n }, {\n autoAlpha: 0,\n ease: Power4.easeOut\n }, '=-.5').set($wprAnalyticsPopin, {\n 'display': 'none'\n }).set($wprPopinOverlay, {\n 'display': 'none'\n });\n }\n\n function wprActivateAnalytics() {\n wprCloseAnalytics();\n $('#analytics_enabled').prop('checked', true);\n $('#analytics_enabled').trigger('change');\n } // Display CTA within the popin `What info will we collect?`\n\n\n $('#analytics_enabled').on('change', function () {\n $('.wpr-rocket-analytics-cta').toggleClass('wpr-isHidden');\n });\n /***\n * Show popin upgrade\n ***/\n\n var $wprUpgradePopin = $('.wpr-Popin-Upgrade'),\n $wprUpgradeClosePopin = $('.wpr-Popin-Upgrade-close'),\n $wprUpgradeOpenPopin = $('.wpr-popin-upgrade-toggle');\n $wprUpgradeOpenPopin.on('click', function (e) {\n e.preventDefault();\n wprOpenUpgradePopin();\n return false;\n });\n $wprUpgradeClosePopin.on('click', function () {\n wprCloseUpgradePopin();\n return false;\n });\n\n function wprOpenUpgradePopin() {\n var vTL = new TimelineLite();\n vTL.set($wprUpgradePopin, {\n 'display': 'block'\n }).set($wprPopinOverlay, {\n 'display': 'block'\n }).fromTo($wprPopinOverlay, 0.6, {\n autoAlpha: 0\n }, {\n autoAlpha: 1,\n ease: Power4.easeOut\n }).fromTo($wprUpgradePopin, 0.6, {\n autoAlpha: 0,\n marginTop: -24\n }, {\n autoAlpha: 1,\n marginTop: 0,\n ease: Power4.easeOut\n }, '=-.5');\n }\n\n function wprCloseUpgradePopin() {\n var vTL = new TimelineLite();\n vTL.fromTo($wprUpgradePopin, 0.6, {\n autoAlpha: 1,\n marginTop: 0\n }, {\n autoAlpha: 0,\n marginTop: -24,\n ease: Power4.easeOut\n }).fromTo($wprPopinOverlay, 0.6, {\n autoAlpha: 1\n }, {\n autoAlpha: 0,\n ease: Power4.easeOut\n }, '=-.5').set($wprUpgradePopin, {\n 'display': 'none'\n }).set($wprPopinOverlay, {\n 'display': 'none'\n });\n }\n /***\n * Sidebar on/off\n ***/\n\n\n var $wprSidebar = $('.wpr-Sidebar');\n var $wprButtonTips = $('.wpr-js-tips');\n $wprButtonTips.on('change', function () {\n wprDetectTips($(this));\n });\n\n function wprDetectTips(aElem) {\n if (aElem.is(':checked')) {\n $wprSidebar.css('display', 'block');\n localStorage.setItem('wpr-show-sidebar', 'on');\n } else {\n $wprSidebar.css('display', 'none');\n localStorage.setItem('wpr-show-sidebar', 'off');\n }\n }\n /***\n * Detect Adblock\n ***/\n\n\n if (document.getElementById('LKgOcCRpwmAj')) {\n $('.wpr-adblock').css('display', 'none');\n } else {\n $('.wpr-adblock').css('display', 'block');\n }\n\n var $adblock = $('.wpr-adblock');\n var $adblockClose = $('.wpr-adblock-close');\n $adblockClose.on('click', function () {\n wprCloseAdblockNotice();\n return false;\n });\n\n function wprCloseAdblockNotice() {\n var vTL = new TimelineLite().to($adblock, 1, {\n autoAlpha: 0,\n x: 40,\n ease: Power4.easeOut\n }).to($adblock, 0.4, {\n height: 0,\n marginTop: 0,\n ease: Power4.easeOut\n }, '=-.4').set($adblock, {\n 'display': 'none'\n });\n }\n});\n\n},{}],7:[function(require,module,exports){\n\"use strict\";\n\ndocument.addEventListener('DOMContentLoaded', function () {\n var $pageManager = document.querySelector(\".wpr-Content\");\n\n if ($pageManager) {\n new PageManager($pageManager);\n }\n});\n/*-----------------------------------------------*\\\n\t\tCLASS PAGEMANAGER\n\\*-----------------------------------------------*/\n\n/**\n * Manages the display of pages / section for WP Rocket plugin\n *\n * Public method :\n detectID - Detect ID with hash\n getBodyTop - Get body top position\n\t change - Displays the corresponding page\n *\n */\n\nfunction PageManager(aElem) {\n var refThis = this;\n this.$body = document.querySelector('.wpr-body');\n this.$menuItems = document.querySelectorAll('.wpr-menuItem');\n this.$submitButton = document.querySelector('.wpr-Content > form > #wpr-options-submit');\n this.$pages = document.querySelectorAll('.wpr-Page');\n this.$sidebar = document.querySelector('.wpr-Sidebar');\n this.$content = document.querySelector('.wpr-Content');\n this.$tips = document.querySelector('.wpr-Content-tips');\n this.$links = document.querySelectorAll('.wpr-body a');\n this.$menuItem = null;\n this.$page = null;\n this.pageId = null;\n this.bodyTop = 0;\n this.buttonText = this.$submitButton.value;\n refThis.getBodyTop(); // If url page change\n\n window.onhashchange = function () {\n refThis.detectID();\n }; // If hash already exist (after refresh page for example)\n\n\n if (window.location.hash) {\n this.bodyTop = 0;\n this.detectID();\n } else {\n var session = localStorage.getItem('wpr-hash');\n this.bodyTop = 0;\n\n if (session) {\n window.location.hash = session;\n this.detectID();\n } else {\n this.$menuItems[0].classList.add('isActive');\n localStorage.setItem('wpr-hash', 'dashboard');\n window.location.hash = '#dashboard';\n }\n } // Click link same hash\n\n\n for (var i = 0; i < this.$links.length; i++) {\n this.$links[i].onclick = function () {\n refThis.getBodyTop();\n var hrefSplit = this.href.split('#')[1];\n\n if (hrefSplit == refThis.pageId && hrefSplit != undefined) {\n refThis.detectID();\n return false;\n }\n };\n } // Click links not WP rocket to reset hash\n\n\n var $otherlinks = document.querySelectorAll('#adminmenumain a, #wpadminbar a');\n\n for (var i = 0; i < $otherlinks.length; i++) {\n $otherlinks[i].onclick = function () {\n localStorage.setItem('wpr-hash', '');\n };\n }\n}\n/*\n* Page detect ID\n*/\n\n\nPageManager.prototype.detectID = function () {\n this.pageId = window.location.hash.split('#')[1];\n localStorage.setItem('wpr-hash', this.pageId);\n this.$page = document.querySelector('.wpr-Page#' + this.pageId);\n this.$menuItem = document.getElementById('wpr-nav-' + this.pageId);\n this.change();\n};\n/*\n* Get body top position\n*/\n\n\nPageManager.prototype.getBodyTop = function () {\n var bodyPos = this.$body.getBoundingClientRect();\n this.bodyTop = bodyPos.top + window.pageYOffset - 47; // #wpadminbar + padding-top .wpr-wrap - 1 - 47\n};\n/*\n* Page change\n*/\n\n\nPageManager.prototype.change = function () {\n var refThis = this;\n document.documentElement.scrollTop = refThis.bodyTop; // Hide other pages\n\n for (var i = 0; i < this.$pages.length; i++) {\n this.$pages[i].style.display = 'none';\n }\n\n for (var i = 0; i < this.$menuItems.length; i++) {\n this.$menuItems[i].classList.remove('isActive');\n } // Show current default page\n\n\n this.$page.style.display = 'block';\n this.$submitButton.style.display = 'block';\n\n if (null === localStorage.getItem('wpr-show-sidebar')) {\n localStorage.setItem('wpr-show-sidebar', 'on');\n }\n\n if ('on' === localStorage.getItem('wpr-show-sidebar')) {\n this.$sidebar.style.display = 'block';\n } else if ('off' === localStorage.getItem('wpr-show-sidebar')) {\n this.$sidebar.style.display = 'none';\n document.querySelector('#wpr-js-tips').removeAttribute('checked');\n }\n\n this.$tips.style.display = 'block';\n this.$menuItem.classList.add('isActive');\n this.$submitButton.value = this.buttonText;\n this.$content.classList.add('isNotFull'); // Exception for dashboard\n\n if (this.pageId == \"dashboard\") {\n this.$sidebar.style.display = 'none';\n this.$tips.style.display = 'none';\n this.$submitButton.style.display = 'none';\n this.$content.classList.remove('isNotFull');\n } // Exception for addons\n\n\n if (this.pageId == \"addons\") {\n this.$submitButton.style.display = 'none';\n } // Exception for database\n\n\n if (this.pageId == \"database\") {\n this.$submitButton.style.display = 'none';\n } // Exception for tools and addons\n\n\n if (this.pageId == \"tools\" || this.pageId == \"addons\") {\n this.$submitButton.style.display = 'none';\n }\n\n if (this.pageId == \"imagify\") {\n this.$sidebar.style.display = 'none';\n this.$tips.style.display = 'none';\n this.$submitButton.style.display = 'none';\n }\n\n if (this.pageId == \"tutorials\") {\n this.$submitButton.style.display = 'none';\n }\n};\n\n},{}],8:[function(require,module,exports){\n\"use strict\";\n\n/*eslint-env es6*/\n((document, window) => {\n 'use strict';\n\n document.addEventListener('DOMContentLoaded', () => {\n document.querySelectorAll('.wpr-rocketcdn-open').forEach(el => {\n el.addEventListener('click', e => {\n e.preventDefault();\n });\n });\n maybeOpenModal();\n MicroModal.init({\n disableScroll: true\n });\n });\n window.addEventListener('load', () => {\n let openCTA = document.querySelector('#wpr-rocketcdn-open-cta'),\n closeCTA = document.querySelector('#wpr-rocketcdn-close-cta'),\n smallCTA = document.querySelector('#wpr-rocketcdn-cta-small'),\n bigCTA = document.querySelector('#wpr-rocketcdn-cta');\n\n if (null !== openCTA && null !== smallCTA && null !== bigCTA) {\n openCTA.addEventListener('click', e => {\n e.preventDefault();\n smallCTA.classList.add('wpr-isHidden');\n bigCTA.classList.remove('wpr-isHidden');\n sendHTTPRequest(getPostData('big'));\n });\n }\n\n if (null !== closeCTA && null !== smallCTA && null !== bigCTA) {\n closeCTA.addEventListener('click', e => {\n e.preventDefault();\n smallCTA.classList.remove('wpr-isHidden');\n bigCTA.classList.add('wpr-isHidden');\n sendHTTPRequest(getPostData('small'));\n });\n }\n\n function getPostData(status) {\n let postData = '';\n postData += 'action=toggle_rocketcdn_cta';\n postData += '&status=' + status;\n postData += '&nonce=' + rocket_ajax_data.nonce;\n return postData;\n }\n });\n\n window.onmessage = e => {\n const iframeURL = rocket_ajax_data.origin_url;\n\n if (e.origin !== iframeURL) {\n return;\n }\n\n setCDNFrameHeight(e.data);\n closeModal(e.data);\n tokenHandler(e.data, iframeURL);\n processStatus(e.data);\n enableCDN(e.data, iframeURL);\n disableCDN(e.data, iframeURL);\n validateTokenAndCNAME(e.data);\n };\n\n function maybeOpenModal() {\n let postData = '';\n postData += 'action=rocketcdn_process_status';\n postData += '&nonce=' + rocket_ajax_data.nonce;\n const request = sendHTTPRequest(postData);\n\n request.onreadystatechange = () => {\n if (request.readyState === XMLHttpRequest.DONE && 200 === request.status) {\n let responseTxt = JSON.parse(request.responseText);\n\n if (true === responseTxt.success) {\n MicroModal.show('wpr-rocketcdn-modal');\n }\n }\n };\n }\n\n function closeModal(data) {\n if (!data.hasOwnProperty('cdnFrameClose')) {\n return;\n }\n\n MicroModal.close('wpr-rocketcdn-modal');\n let pages = ['iframe-payment-success', 'iframe-unsubscribe-success'];\n\n if (!data.hasOwnProperty('cdn_page_message')) {\n return;\n }\n\n if (pages.indexOf(data.cdn_page_message) === -1) {\n return;\n }\n\n document.location.reload();\n }\n\n function processStatus(data) {\n if (!data.hasOwnProperty('rocketcdn_process')) {\n return;\n }\n\n let postData = '';\n postData += 'action=rocketcdn_process_set';\n postData += '&status=' + data.rocketcdn_process;\n postData += '&nonce=' + rocket_ajax_data.nonce;\n sendHTTPRequest(postData);\n }\n\n function enableCDN(data, iframeURL) {\n let iframe = document.querySelector('#rocketcdn-iframe').contentWindow;\n\n if (!data.hasOwnProperty('rocketcdn_url')) {\n return;\n }\n\n let postData = '';\n postData += 'action=rocketcdn_enable';\n postData += '&cdn_url=' + data.rocketcdn_url;\n postData += '&nonce=' + rocket_ajax_data.nonce;\n const request = sendHTTPRequest(postData);\n\n request.onreadystatechange = () => {\n if (request.readyState === XMLHttpRequest.DONE && 200 === request.status) {\n let responseTxt = JSON.parse(request.responseText);\n iframe.postMessage({\n 'success': responseTxt.success,\n 'data': responseTxt.data,\n 'rocketcdn': true\n }, iframeURL);\n }\n };\n }\n\n function disableCDN(data, iframeURL) {\n let iframe = document.querySelector('#rocketcdn-iframe').contentWindow;\n\n if (!data.hasOwnProperty('rocketcdn_disable')) {\n return;\n }\n\n let postData = '';\n postData += 'action=rocketcdn_disable';\n postData += '&nonce=' + rocket_ajax_data.nonce;\n const request = sendHTTPRequest(postData);\n\n request.onreadystatechange = () => {\n if (request.readyState === XMLHttpRequest.DONE && 200 === request.status) {\n let responseTxt = JSON.parse(request.responseText);\n iframe.postMessage({\n 'success': responseTxt.success,\n 'data': responseTxt.data,\n 'rocketcdn': true\n }, iframeURL);\n }\n };\n }\n\n function sendHTTPRequest(postData) {\n const httpRequest = new XMLHttpRequest();\n httpRequest.open('POST', ajaxurl);\n httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n httpRequest.send(postData);\n return httpRequest;\n }\n\n function setCDNFrameHeight(data) {\n if (!data.hasOwnProperty('cdnFrameHeight')) {\n return;\n }\n\n document.getElementById('rocketcdn-iframe').style.height = `${data.cdnFrameHeight}px`;\n }\n\n function tokenHandler(data, iframeURL) {\n let iframe = document.querySelector('#rocketcdn-iframe').contentWindow;\n\n if (!data.hasOwnProperty('rocketcdn_token')) {\n let data = {\n process: \"subscribe\",\n message: \"token_not_received\"\n };\n iframe.postMessage({\n 'success': false,\n 'data': data,\n 'rocketcdn': true\n }, iframeURL);\n return;\n }\n\n let postData = '';\n postData += 'action=save_rocketcdn_token';\n postData += '&value=' + data.rocketcdn_token;\n postData += '&nonce=' + rocket_ajax_data.nonce;\n const request = sendHTTPRequest(postData);\n\n request.onreadystatechange = () => {\n if (request.readyState === XMLHttpRequest.DONE && 200 === request.status) {\n let responseTxt = JSON.parse(request.responseText);\n iframe.postMessage({\n 'success': responseTxt.success,\n 'data': responseTxt.data,\n 'rocketcdn': true\n }, iframeURL);\n }\n };\n }\n\n function validateTokenAndCNAME(data) {\n if (!data.hasOwnProperty('rocketcdn_validate_token') || !data.hasOwnProperty('rocketcdn_validate_cname')) {\n return;\n }\n\n let postData = '';\n postData += 'action=rocketcdn_validate_token_cname';\n postData += '&cdn_url=' + data.rocketcdn_validate_cname;\n postData += '&cdn_token=' + data.rocketcdn_validate_token;\n postData += '&nonce=' + rocket_ajax_data.nonce;\n const request = sendHTTPRequest(postData);\n }\n})(document, window);\n\n},{}],9:[function(require,module,exports){\n\"use strict\";\n\n/*!\r\n * VERSION: 1.12.1\r\n * DATE: 2014-06-26\r\n * UPDATES AND DOCS AT: http://www.greensock.com\r\n *\r\n * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.\r\n * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for\r\n * Club GreenSock members, the software agreement that was issued with your membership.\r\n * \r\n * @author: Jack Doyle, jack@greensock.com\r\n */\n(window._gsQueue || (window._gsQueue = [])).push(function () {\n \"use strict\";\n\n window._gsDefine(\"TimelineLite\", [\"core.Animation\", \"core.SimpleTimeline\", \"TweenLite\"], function (t, e, i) {\n var s = function (t) {\n e.call(this, t), this._labels = {}, this.autoRemoveChildren = this.vars.autoRemoveChildren === !0, this.smoothChildTiming = this.vars.smoothChildTiming === !0, this._sortChildren = !0, this._onUpdate = this.vars.onUpdate;\n var i,\n s,\n r = this.vars;\n\n for (s in r) i = r[s], a(i) && -1 !== i.join(\"\").indexOf(\"{self}\") && (r[s] = this._swapSelfInParams(i));\n\n a(r.tweens) && this.add(r.tweens, 0, r.align, r.stagger);\n },\n r = 1e-10,\n n = i._internals.isSelector,\n a = i._internals.isArray,\n o = [],\n h = window._gsDefine.globals,\n l = function (t) {\n var e,\n i = {};\n\n for (e in t) i[e] = t[e];\n\n return i;\n },\n _ = function (t, e, i, s) {\n t._timeline.pause(t._startTime), e && e.apply(s || t._timeline, i || o);\n },\n u = o.slice,\n f = s.prototype = new e();\n\n return s.version = \"1.12.1\", f.constructor = s, f.kill()._gc = !1, f.to = function (t, e, s, r) {\n var n = s.repeat && h.TweenMax || i;\n return e ? this.add(new n(t, e, s), r) : this.set(t, s, r);\n }, f.from = function (t, e, s, r) {\n return this.add((s.repeat && h.TweenMax || i).from(t, e, s), r);\n }, f.fromTo = function (t, e, s, r, n) {\n var a = r.repeat && h.TweenMax || i;\n return e ? this.add(a.fromTo(t, e, s, r), n) : this.set(t, r, n);\n }, f.staggerTo = function (t, e, r, a, o, h, _, f) {\n var p,\n c = new s({\n onComplete: h,\n onCompleteParams: _,\n onCompleteScope: f,\n smoothChildTiming: this.smoothChildTiming\n });\n\n for (\"string\" == typeof t && (t = i.selector(t) || t), n(t) && (t = u.call(t, 0)), a = a || 0, p = 0; t.length > p; p++) r.startAt && (r.startAt = l(r.startAt)), c.to(t[p], e, l(r), p * a);\n\n return this.add(c, o);\n }, f.staggerFrom = function (t, e, i, s, r, n, a, o) {\n return i.immediateRender = 0 != i.immediateRender, i.runBackwards = !0, this.staggerTo(t, e, i, s, r, n, a, o);\n }, f.staggerFromTo = function (t, e, i, s, r, n, a, o, h) {\n return s.startAt = i, s.immediateRender = 0 != s.immediateRender && 0 != i.immediateRender, this.staggerTo(t, e, s, r, n, a, o, h);\n }, f.call = function (t, e, s, r) {\n return this.add(i.delayedCall(0, t, e, s), r);\n }, f.set = function (t, e, s) {\n return s = this._parseTimeOrLabel(s, 0, !0), null == e.immediateRender && (e.immediateRender = s === this._time && !this._paused), this.add(new i(t, 0, e), s);\n }, s.exportRoot = function (t, e) {\n t = t || {}, null == t.smoothChildTiming && (t.smoothChildTiming = !0);\n var r,\n n,\n a = new s(t),\n o = a._timeline;\n\n for (null == e && (e = !0), o._remove(a, !0), a._startTime = 0, a._rawPrevTime = a._time = a._totalTime = o._time, r = o._first; r;) n = r._next, e && r instanceof i && r.target === r.vars.onComplete || a.add(r, r._startTime - r._delay), r = n;\n\n return o.add(a, 0), a;\n }, f.add = function (r, n, o, h) {\n var l, _, u, f, p, c;\n\n if (\"number\" != typeof n && (n = this._parseTimeOrLabel(n, 0, !0, r)), !(r instanceof t)) {\n if (r instanceof Array || r && r.push && a(r)) {\n for (o = o || \"normal\", h = h || 0, l = n, _ = r.length, u = 0; _ > u; u++) a(f = r[u]) && (f = new s({\n tweens: f\n })), this.add(f, l), \"string\" != typeof f && \"function\" != typeof f && (\"sequence\" === o ? l = f._startTime + f.totalDuration() / f._timeScale : \"start\" === o && (f._startTime -= f.delay())), l += h;\n\n return this._uncache(!0);\n }\n\n if (\"string\" == typeof r) return this.addLabel(r, n);\n if (\"function\" != typeof r) throw \"Cannot add \" + r + \" into the timeline; it is not a tween, timeline, function, or string.\";\n r = i.delayedCall(0, r);\n }\n\n if (e.prototype.add.call(this, r, n), (this._gc || this._time === this._duration) && !this._paused && this._duration < this.duration()) for (p = this, c = p.rawTime() > r._startTime; p._timeline;) c && p._timeline.smoothChildTiming ? p.totalTime(p._totalTime, !0) : p._gc && p._enabled(!0, !1), p = p._timeline;\n return this;\n }, f.remove = function (e) {\n if (e instanceof t) return this._remove(e, !1);\n\n if (e instanceof Array || e && e.push && a(e)) {\n for (var i = e.length; --i > -1;) this.remove(e[i]);\n\n return this;\n }\n\n return \"string\" == typeof e ? this.removeLabel(e) : this.kill(null, e);\n }, f._remove = function (t, i) {\n e.prototype._remove.call(this, t, i);\n\n var s = this._last;\n return s ? this._time > s._startTime + s._totalDuration / s._timeScale && (this._time = this.duration(), this._totalTime = this._totalDuration) : this._time = this._totalTime = this._duration = this._totalDuration = 0, this;\n }, f.append = function (t, e) {\n return this.add(t, this._parseTimeOrLabel(null, e, !0, t));\n }, f.insert = f.insertMultiple = function (t, e, i, s) {\n return this.add(t, e || 0, i, s);\n }, f.appendMultiple = function (t, e, i, s) {\n return this.add(t, this._parseTimeOrLabel(null, e, !0, t), i, s);\n }, f.addLabel = function (t, e) {\n return this._labels[t] = this._parseTimeOrLabel(e), this;\n }, f.addPause = function (t, e, i, s) {\n return this.call(_, [\"{self}\", e, i, s], this, t);\n }, f.removeLabel = function (t) {\n return delete this._labels[t], this;\n }, f.getLabelTime = function (t) {\n return null != this._labels[t] ? this._labels[t] : -1;\n }, f._parseTimeOrLabel = function (e, i, s, r) {\n var n;\n if (r instanceof t && r.timeline === this) this.remove(r);else if (r && (r instanceof Array || r.push && a(r))) for (n = r.length; --n > -1;) r[n] instanceof t && r[n].timeline === this && this.remove(r[n]);\n if (\"string\" == typeof i) return this._parseTimeOrLabel(i, s && \"number\" == typeof e && null == this._labels[i] ? e - this.duration() : 0, s);\n if (i = i || 0, \"string\" != typeof e || !isNaN(e) && null == this._labels[e]) null == e && (e = this.duration());else {\n if (n = e.indexOf(\"=\"), -1 === n) return null == this._labels[e] ? s ? this._labels[e] = this.duration() + i : i : this._labels[e] + i;\n i = parseInt(e.charAt(n - 1) + \"1\", 10) * Number(e.substr(n + 1)), e = n > 1 ? this._parseTimeOrLabel(e.substr(0, n - 1), 0, s) : this.duration();\n }\n return Number(e) + i;\n }, f.seek = function (t, e) {\n return this.totalTime(\"number\" == typeof t ? t : this._parseTimeOrLabel(t), e !== !1);\n }, f.stop = function () {\n return this.paused(!0);\n }, f.gotoAndPlay = function (t, e) {\n return this.play(t, e);\n }, f.gotoAndStop = function (t, e) {\n return this.pause(t, e);\n }, f.render = function (t, e, i) {\n this._gc && this._enabled(!0, !1);\n\n var s,\n n,\n a,\n h,\n l,\n _ = this._dirty ? this.totalDuration() : this._totalDuration,\n u = this._time,\n f = this._startTime,\n p = this._timeScale,\n c = this._paused;\n\n if (t >= _ ? (this._totalTime = this._time = _, this._reversed || this._hasPausedChild() || (n = !0, h = \"onComplete\", 0 === this._duration && (0 === t || 0 > this._rawPrevTime || this._rawPrevTime === r) && this._rawPrevTime !== t && this._first && (l = !0, this._rawPrevTime > r && (h = \"onReverseComplete\"))), this._rawPrevTime = this._duration || !e || t || this._rawPrevTime === t ? t : r, t = _ + 1e-4) : 1e-7 > t ? (this._totalTime = this._time = 0, (0 !== u || 0 === this._duration && this._rawPrevTime !== r && (this._rawPrevTime > 0 || 0 > t && this._rawPrevTime >= 0)) && (h = \"onReverseComplete\", n = this._reversed), 0 > t ? (this._active = !1, 0 === this._duration && this._rawPrevTime >= 0 && this._first && (l = !0), this._rawPrevTime = t) : (this._rawPrevTime = this._duration || !e || t || this._rawPrevTime === t ? t : r, t = 0, this._initted || (l = !0))) : this._totalTime = this._time = this._rawPrevTime = t, this._time !== u && this._first || i || l) {\n if (this._initted || (this._initted = !0), this._active || !this._paused && this._time !== u && t > 0 && (this._active = !0), 0 === u && this.vars.onStart && 0 !== this._time && (e || this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || o)), this._time >= u) for (s = this._first; s && (a = s._next, !this._paused || c);) (s._active || s._startTime <= this._time && !s._paused && !s._gc) && (s._reversed ? s.render((s._dirty ? s.totalDuration() : s._totalDuration) - (t - s._startTime) * s._timeScale, e, i) : s.render((t - s._startTime) * s._timeScale, e, i)), s = a;else for (s = this._last; s && (a = s._prev, !this._paused || c);) (s._active || u >= s._startTime && !s._paused && !s._gc) && (s._reversed ? s.render((s._dirty ? s.totalDuration() : s._totalDuration) - (t - s._startTime) * s._timeScale, e, i) : s.render((t - s._startTime) * s._timeScale, e, i)), s = a;\n this._onUpdate && (e || this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || o)), h && (this._gc || (f === this._startTime || p !== this._timeScale) && (0 === this._time || _ >= this.totalDuration()) && (n && (this._timeline.autoRemoveChildren && this._enabled(!1, !1), this._active = !1), !e && this.vars[h] && this.vars[h].apply(this.vars[h + \"Scope\"] || this, this.vars[h + \"Params\"] || o)));\n }\n }, f._hasPausedChild = function () {\n for (var t = this._first; t;) {\n if (t._paused || t instanceof s && t._hasPausedChild()) return !0;\n t = t._next;\n }\n\n return !1;\n }, f.getChildren = function (t, e, s, r) {\n r = r || -9999999999;\n\n for (var n = [], a = this._first, o = 0; a;) r > a._startTime || (a instanceof i ? e !== !1 && (n[o++] = a) : (s !== !1 && (n[o++] = a), t !== !1 && (n = n.concat(a.getChildren(!0, e, s)), o = n.length))), a = a._next;\n\n return n;\n }, f.getTweensOf = function (t, e) {\n var s,\n r,\n n = this._gc,\n a = [],\n o = 0;\n\n for (n && this._enabled(!0, !0), s = i.getTweensOf(t), r = s.length; --r > -1;) (s[r].timeline === this || e && this._contains(s[r])) && (a[o++] = s[r]);\n\n return n && this._enabled(!1, !0), a;\n }, f._contains = function (t) {\n for (var e = t.timeline; e;) {\n if (e === this) return !0;\n e = e.timeline;\n }\n\n return !1;\n }, f.shiftChildren = function (t, e, i) {\n i = i || 0;\n\n for (var s, r = this._first, n = this._labels; r;) r._startTime >= i && (r._startTime += t), r = r._next;\n\n if (e) for (s in n) n[s] >= i && (n[s] += t);\n return this._uncache(!0);\n }, f._kill = function (t, e) {\n if (!t && !e) return this._enabled(!1, !1);\n\n for (var i = e ? this.getTweensOf(e) : this.getChildren(!0, !0, !1), s = i.length, r = !1; --s > -1;) i[s]._kill(t, e) && (r = !0);\n\n return r;\n }, f.clear = function (t) {\n var e = this.getChildren(!1, !0, !0),\n i = e.length;\n\n for (this._time = this._totalTime = 0; --i > -1;) e[i]._enabled(!1, !1);\n\n return t !== !1 && (this._labels = {}), this._uncache(!0);\n }, f.invalidate = function () {\n for (var t = this._first; t;) t.invalidate(), t = t._next;\n\n return this;\n }, f._enabled = function (t, i) {\n if (t === this._gc) for (var s = this._first; s;) s._enabled(t, !0), s = s._next;\n return e.prototype._enabled.call(this, t, i);\n }, f.duration = function (t) {\n return arguments.length ? (0 !== this.duration() && 0 !== t && this.timeScale(this._duration / t), this) : (this._dirty && this.totalDuration(), this._duration);\n }, f.totalDuration = function (t) {\n if (!arguments.length) {\n if (this._dirty) {\n for (var e, i, s = 0, r = this._last, n = 999999999999; r;) e = r._prev, r._dirty && r.totalDuration(), r._startTime > n && this._sortChildren && !r._paused ? this.add(r, r._startTime - r._delay) : n = r._startTime, 0 > r._startTime && !r._paused && (s -= r._startTime, this._timeline.smoothChildTiming && (this._startTime += r._startTime / this._timeScale), this.shiftChildren(-r._startTime, !1, -9999999999), n = 0), i = r._startTime + r._totalDuration / r._timeScale, i > s && (s = i), r = e;\n\n this._duration = this._totalDuration = s, this._dirty = !1;\n }\n\n return this._totalDuration;\n }\n\n return 0 !== this.totalDuration() && 0 !== t && this.timeScale(this._totalDuration / t), this;\n }, f.usesFrames = function () {\n for (var e = this._timeline; e._timeline;) e = e._timeline;\n\n return e === t._rootFramesTimeline;\n }, f.rawTime = function () {\n return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale;\n }, s;\n }, !0);\n}), window._gsDefine && window._gsQueue.pop()();\n\n},{}],10:[function(require,module,exports){\n\"use strict\";\n\n/*!\r\n * VERSION: 1.12.1\r\n * DATE: 2014-06-26\r\n * UPDATES AND DOCS AT: http://www.greensock.com\r\n *\r\n * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.\r\n * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for\r\n * Club GreenSock members, the software agreement that was issued with your membership.\r\n * \r\n * @author: Jack Doyle, jack@greensock.com\r\n */\n(function (t) {\n \"use strict\";\n\n var e = t.GreenSockGlobals || t;\n\n if (!e.TweenLite) {\n var i,\n s,\n n,\n r,\n a,\n o = function (t) {\n var i,\n s = t.split(\".\"),\n n = e;\n\n for (i = 0; s.length > i; i++) n[s[i]] = n = n[s[i]] || {};\n\n return n;\n },\n l = o(\"com.greensock\"),\n h = 1e-10,\n _ = [].slice,\n u = function () {},\n m = function () {\n var t = Object.prototype.toString,\n e = t.call([]);\n return function (i) {\n return null != i && (i instanceof Array || \"object\" == typeof i && !!i.push && t.call(i) === e);\n };\n }(),\n f = {},\n p = function (i, s, n, r) {\n this.sc = f[i] ? f[i].sc : [], f[i] = this, this.gsClass = null, this.func = n;\n var a = [];\n this.check = function (l) {\n for (var h, _, u, m, c = s.length, d = c; --c > -1;) (h = f[s[c]] || new p(s[c], [])).gsClass ? (a[c] = h.gsClass, d--) : l && h.sc.push(this);\n\n if (0 === d && n) for (_ = (\"com.greensock.\" + i).split(\".\"), u = _.pop(), m = o(_.join(\".\"))[u] = this.gsClass = n.apply(n, a), r && (e[u] = m, \"function\" == typeof define && define.amd ? define((t.GreenSockAMDPath ? t.GreenSockAMDPath + \"/\" : \"\") + i.split(\".\").join(\"/\"), [], function () {\n return m;\n }) : \"undefined\" != typeof module && module.exports && (module.exports = m)), c = 0; this.sc.length > c; c++) this.sc[c].check();\n }, this.check(!0);\n },\n c = t._gsDefine = function (t, e, i, s) {\n return new p(t, e, i, s);\n },\n d = l._class = function (t, e, i) {\n return e = e || function () {}, c(t, [], function () {\n return e;\n }, i), e;\n };\n\n c.globals = e;\n\n var v = [0, 0, 1, 1],\n g = [],\n T = d(\"easing.Ease\", function (t, e, i, s) {\n this._func = t, this._type = i || 0, this._power = s || 0, this._params = e ? v.concat(e) : v;\n }, !0),\n y = T.map = {},\n w = T.register = function (t, e, i, s) {\n for (var n, r, a, o, h = e.split(\",\"), _ = h.length, u = (i || \"easeIn,easeOut,easeInOut\").split(\",\"); --_ > -1;) for (r = h[_], n = s ? d(\"easing.\" + r, null, !0) : l.easing[r] || {}, a = u.length; --a > -1;) o = u[a], y[r + \".\" + o] = y[o + r] = n[o] = t.getRatio ? t : t[o] || new t();\n };\n\n for (n = T.prototype, n._calcEnd = !1, n.getRatio = function (t) {\n if (this._func) return this._params[0] = t, this._func.apply(null, this._params);\n var e = this._type,\n i = this._power,\n s = 1 === e ? 1 - t : 2 === e ? t : .5 > t ? 2 * t : 2 * (1 - t);\n return 1 === i ? s *= s : 2 === i ? s *= s * s : 3 === i ? s *= s * s * s : 4 === i && (s *= s * s * s * s), 1 === e ? 1 - s : 2 === e ? s : .5 > t ? s / 2 : 1 - s / 2;\n }, i = [\"Linear\", \"Quad\", \"Cubic\", \"Quart\", \"Quint,Strong\"], s = i.length; --s > -1;) n = i[s] + \",Power\" + s, w(new T(null, null, 1, s), n, \"easeOut\", !0), w(new T(null, null, 2, s), n, \"easeIn\" + (0 === s ? \",easeNone\" : \"\")), w(new T(null, null, 3, s), n, \"easeInOut\");\n\n y.linear = l.easing.Linear.easeIn, y.swing = l.easing.Quad.easeInOut;\n var P = d(\"events.EventDispatcher\", function (t) {\n this._listeners = {}, this._eventTarget = t || this;\n });\n n = P.prototype, n.addEventListener = function (t, e, i, s, n) {\n n = n || 0;\n var o,\n l,\n h = this._listeners[t],\n _ = 0;\n\n for (null == h && (this._listeners[t] = h = []), l = h.length; --l > -1;) o = h[l], o.c === e && o.s === i ? h.splice(l, 1) : 0 === _ && n > o.pr && (_ = l + 1);\n\n h.splice(_, 0, {\n c: e,\n s: i,\n up: s,\n pr: n\n }), this !== r || a || r.wake();\n }, n.removeEventListener = function (t, e) {\n var i,\n s = this._listeners[t];\n if (s) for (i = s.length; --i > -1;) if (s[i].c === e) return s.splice(i, 1), void 0;\n }, n.dispatchEvent = function (t) {\n var e,\n i,\n s,\n n = this._listeners[t];\n if (n) for (e = n.length, i = this._eventTarget; --e > -1;) s = n[e], s.up ? s.c.call(s.s || i, {\n type: t,\n target: i\n }) : s.c.call(s.s || i);\n };\n\n var k = t.requestAnimationFrame,\n b = t.cancelAnimationFrame,\n A = Date.now || function () {\n return new Date().getTime();\n },\n S = A();\n\n for (i = [\"ms\", \"moz\", \"webkit\", \"o\"], s = i.length; --s > -1 && !k;) k = t[i[s] + \"RequestAnimationFrame\"], b = t[i[s] + \"CancelAnimationFrame\"] || t[i[s] + \"CancelRequestAnimationFrame\"];\n\n d(\"Ticker\", function (t, e) {\n var i,\n s,\n n,\n o,\n l,\n _ = this,\n m = A(),\n f = e !== !1 && k,\n p = 500,\n c = 33,\n d = function (t) {\n var e,\n r,\n a = A() - S;\n a > p && (m += a - c), S += a, _.time = (S - m) / 1e3, e = _.time - l, (!i || e > 0 || t === !0) && (_.frame++, l += e + (e >= o ? .004 : o - e), r = !0), t !== !0 && (n = s(d)), r && _.dispatchEvent(\"tick\");\n };\n\n P.call(_), _.time = _.frame = 0, _.tick = function () {\n d(!0);\n }, _.lagSmoothing = function (t, e) {\n p = t || 1 / h, c = Math.min(e, p, 0);\n }, _.sleep = function () {\n null != n && (f && b ? b(n) : clearTimeout(n), s = u, n = null, _ === r && (a = !1));\n }, _.wake = function () {\n null !== n ? _.sleep() : _.frame > 10 && (S = A() - p + 5), s = 0 === i ? u : f && k ? k : function (t) {\n return setTimeout(t, 0 | 1e3 * (l - _.time) + 1);\n }, _ === r && (a = !0), d(2);\n }, _.fps = function (t) {\n return arguments.length ? (i = t, o = 1 / (i || 60), l = this.time + o, _.wake(), void 0) : i;\n }, _.useRAF = function (t) {\n return arguments.length ? (_.sleep(), f = t, _.fps(i), void 0) : f;\n }, _.fps(t), setTimeout(function () {\n f && (!n || 5 > _.frame) && _.useRAF(!1);\n }, 1500);\n }), n = l.Ticker.prototype = new l.events.EventDispatcher(), n.constructor = l.Ticker;\n var x = d(\"core.Animation\", function (t, e) {\n if (this.vars = e = e || {}, this._duration = this._totalDuration = t || 0, this._delay = Number(e.delay) || 0, this._timeScale = 1, this._active = e.immediateRender === !0, this.data = e.data, this._reversed = e.reversed === !0, B) {\n a || r.wake();\n var i = this.vars.useFrames ? Q : B;\n i.add(this, i._time), this.vars.paused && this.paused(!0);\n }\n });\n r = x.ticker = new l.Ticker(), n = x.prototype, n._dirty = n._gc = n._initted = n._paused = !1, n._totalTime = n._time = 0, n._rawPrevTime = -1, n._next = n._last = n._onUpdate = n._timeline = n.timeline = null, n._paused = !1;\n\n var C = function () {\n a && A() - S > 2e3 && r.wake(), setTimeout(C, 2e3);\n };\n\n C(), n.play = function (t, e) {\n return null != t && this.seek(t, e), this.reversed(!1).paused(!1);\n }, n.pause = function (t, e) {\n return null != t && this.seek(t, e), this.paused(!0);\n }, n.resume = function (t, e) {\n return null != t && this.seek(t, e), this.paused(!1);\n }, n.seek = function (t, e) {\n return this.totalTime(Number(t), e !== !1);\n }, n.restart = function (t, e) {\n return this.reversed(!1).paused(!1).totalTime(t ? -this._delay : 0, e !== !1, !0);\n }, n.reverse = function (t, e) {\n return null != t && this.seek(t || this.totalDuration(), e), this.reversed(!0).paused(!1);\n }, n.render = function () {}, n.invalidate = function () {\n return this;\n }, n.isActive = function () {\n var t,\n e = this._timeline,\n i = this._startTime;\n return !e || !this._gc && !this._paused && e.isActive() && (t = e.rawTime()) >= i && i + this.totalDuration() / this._timeScale > t;\n }, n._enabled = function (t, e) {\n return a || r.wake(), this._gc = !t, this._active = this.isActive(), e !== !0 && (t && !this.timeline ? this._timeline.add(this, this._startTime - this._delay) : !t && this.timeline && this._timeline._remove(this, !0)), !1;\n }, n._kill = function () {\n return this._enabled(!1, !1);\n }, n.kill = function (t, e) {\n return this._kill(t, e), this;\n }, n._uncache = function (t) {\n for (var e = t ? this : this.timeline; e;) e._dirty = !0, e = e.timeline;\n\n return this;\n }, n._swapSelfInParams = function (t) {\n for (var e = t.length, i = t.concat(); --e > -1;) \"{self}\" === t[e] && (i[e] = this);\n\n return i;\n }, n.eventCallback = function (t, e, i, s) {\n if (\"on\" === (t || \"\").substr(0, 2)) {\n var n = this.vars;\n if (1 === arguments.length) return n[t];\n null == e ? delete n[t] : (n[t] = e, n[t + \"Params\"] = m(i) && -1 !== i.join(\"\").indexOf(\"{self}\") ? this._swapSelfInParams(i) : i, n[t + \"Scope\"] = s), \"onUpdate\" === t && (this._onUpdate = e);\n }\n\n return this;\n }, n.delay = function (t) {\n return arguments.length ? (this._timeline.smoothChildTiming && this.startTime(this._startTime + t - this._delay), this._delay = t, this) : this._delay;\n }, n.duration = function (t) {\n return arguments.length ? (this._duration = this._totalDuration = t, this._uncache(!0), this._timeline.smoothChildTiming && this._time > 0 && this._time < this._duration && 0 !== t && this.totalTime(this._totalTime * (t / this._duration), !0), this) : (this._dirty = !1, this._duration);\n }, n.totalDuration = function (t) {\n return this._dirty = !1, arguments.length ? this.duration(t) : this._totalDuration;\n }, n.time = function (t, e) {\n return arguments.length ? (this._dirty && this.totalDuration(), this.totalTime(t > this._duration ? this._duration : t, e)) : this._time;\n }, n.totalTime = function (t, e, i) {\n if (a || r.wake(), !arguments.length) return this._totalTime;\n\n if (this._timeline) {\n if (0 > t && !i && (t += this.totalDuration()), this._timeline.smoothChildTiming) {\n this._dirty && this.totalDuration();\n var s = this._totalDuration,\n n = this._timeline;\n if (t > s && !i && (t = s), this._startTime = (this._paused ? this._pauseTime : n._time) - (this._reversed ? s - t : t) / this._timeScale, n._dirty || this._uncache(!1), n._timeline) for (; n._timeline;) n._timeline._time !== (n._startTime + n._totalTime) / n._timeScale && n.totalTime(n._totalTime, !0), n = n._timeline;\n }\n\n this._gc && this._enabled(!0, !1), (this._totalTime !== t || 0 === this._duration) && (this.render(t, e, !1), z.length && q());\n }\n\n return this;\n }, n.progress = n.totalProgress = function (t, e) {\n return arguments.length ? this.totalTime(this.duration() * t, e) : this._time / this.duration();\n }, n.startTime = function (t) {\n return arguments.length ? (t !== this._startTime && (this._startTime = t, this.timeline && this.timeline._sortChildren && this.timeline.add(this, t - this._delay)), this) : this._startTime;\n }, n.timeScale = function (t) {\n if (!arguments.length) return this._timeScale;\n\n if (t = t || h, this._timeline && this._timeline.smoothChildTiming) {\n var e = this._pauseTime,\n i = e || 0 === e ? e : this._timeline.totalTime();\n this._startTime = i - (i - this._startTime) * this._timeScale / t;\n }\n\n return this._timeScale = t, this._uncache(!1);\n }, n.reversed = function (t) {\n return arguments.length ? (t != this._reversed && (this._reversed = t, this.totalTime(this._timeline && !this._timeline.smoothChildTiming ? this.totalDuration() - this._totalTime : this._totalTime, !0)), this) : this._reversed;\n }, n.paused = function (t) {\n if (!arguments.length) return this._paused;\n\n if (t != this._paused && this._timeline) {\n a || t || r.wake();\n var e = this._timeline,\n i = e.rawTime(),\n s = i - this._pauseTime;\n !t && e.smoothChildTiming && (this._startTime += s, this._uncache(!1)), this._pauseTime = t ? i : null, this._paused = t, this._active = this.isActive(), !t && 0 !== s && this._initted && this.duration() && this.render(e.smoothChildTiming ? this._totalTime : (i - this._startTime) / this._timeScale, !0, !0);\n }\n\n return this._gc && !t && this._enabled(!0, !1), this;\n };\n var R = d(\"core.SimpleTimeline\", function (t) {\n x.call(this, 0, t), this.autoRemoveChildren = this.smoothChildTiming = !0;\n });\n n = R.prototype = new x(), n.constructor = R, n.kill()._gc = !1, n._first = n._last = null, n._sortChildren = !1, n.add = n.insert = function (t, e) {\n var i, s;\n if (t._startTime = Number(e || 0) + t._delay, t._paused && this !== t._timeline && (t._pauseTime = t._startTime + (this.rawTime() - t._startTime) / t._timeScale), t.timeline && t.timeline._remove(t, !0), t.timeline = t._timeline = this, t._gc && t._enabled(!0, !0), i = this._last, this._sortChildren) for (s = t._startTime; i && i._startTime > s;) i = i._prev;\n return i ? (t._next = i._next, i._next = t) : (t._next = this._first, this._first = t), t._next ? t._next._prev = t : this._last = t, t._prev = i, this._timeline && this._uncache(!0), this;\n }, n._remove = function (t, e) {\n return t.timeline === this && (e || t._enabled(!1, !0), t.timeline = null, t._prev ? t._prev._next = t._next : this._first === t && (this._first = t._next), t._next ? t._next._prev = t._prev : this._last === t && (this._last = t._prev), this._timeline && this._uncache(!0)), this;\n }, n.render = function (t, e, i) {\n var s,\n n = this._first;\n\n for (this._totalTime = this._time = this._rawPrevTime = t; n;) s = n._next, (n._active || t >= n._startTime && !n._paused) && (n._reversed ? n.render((n._dirty ? n.totalDuration() : n._totalDuration) - (t - n._startTime) * n._timeScale, e, i) : n.render((t - n._startTime) * n._timeScale, e, i)), n = s;\n }, n.rawTime = function () {\n return a || r.wake(), this._totalTime;\n };\n\n var D = d(\"TweenLite\", function (e, i, s) {\n if (x.call(this, i, s), this.render = D.prototype.render, null == e) throw \"Cannot tween a null target.\";\n this.target = e = \"string\" != typeof e ? e : D.selector(e) || e;\n var n,\n r,\n a,\n o = e.jquery || e.length && e !== t && e[0] && (e[0] === t || e[0].nodeType && e[0].style && !e.nodeType),\n l = this.vars.overwrite;\n if (this._overwrite = l = null == l ? G[D.defaultOverwrite] : \"number\" == typeof l ? l >> 0 : G[l], (o || e instanceof Array || e.push && m(e)) && \"number\" != typeof e[0]) for (this._targets = a = _.call(e, 0), this._propLookup = [], this._siblings = [], n = 0; a.length > n; n++) r = a[n], r ? \"string\" != typeof r ? r.length && r !== t && r[0] && (r[0] === t || r[0].nodeType && r[0].style && !r.nodeType) ? (a.splice(n--, 1), this._targets = a = a.concat(_.call(r, 0))) : (this._siblings[n] = M(r, this, !1), 1 === l && this._siblings[n].length > 1 && $(r, this, null, 1, this._siblings[n])) : (r = a[n--] = D.selector(r), \"string\" == typeof r && a.splice(n + 1, 1)) : a.splice(n--, 1);else this._propLookup = {}, this._siblings = M(e, this, !1), 1 === l && this._siblings.length > 1 && $(e, this, null, 1, this._siblings);\n (this.vars.immediateRender || 0 === i && 0 === this._delay && this.vars.immediateRender !== !1) && (this._time = -h, this.render(-this._delay));\n }, !0),\n I = function (e) {\n return e.length && e !== t && e[0] && (e[0] === t || e[0].nodeType && e[0].style && !e.nodeType);\n },\n E = function (t, e) {\n var i,\n s = {};\n\n for (i in t) j[i] || i in e && \"transform\" !== i && \"x\" !== i && \"y\" !== i && \"width\" !== i && \"height\" !== i && \"className\" !== i && \"border\" !== i || !(!L[i] || L[i] && L[i]._autoCSS) || (s[i] = t[i], delete t[i]);\n\n t.css = s;\n };\n\n n = D.prototype = new x(), n.constructor = D, n.kill()._gc = !1, n.ratio = 0, n._firstPT = n._targets = n._overwrittenProps = n._startAt = null, n._notifyPluginsOfEnabled = n._lazy = !1, D.version = \"1.12.1\", D.defaultEase = n._ease = new T(null, null, 1, 1), D.defaultOverwrite = \"auto\", D.ticker = r, D.autoSleep = !0, D.lagSmoothing = function (t, e) {\n r.lagSmoothing(t, e);\n }, D.selector = t.$ || t.jQuery || function (e) {\n return t.$ ? (D.selector = t.$, t.$(e)) : t.document ? t.document.getElementById(\"#\" === e.charAt(0) ? e.substr(1) : e) : e;\n };\n\n var z = [],\n O = {},\n N = D._internals = {\n isArray: m,\n isSelector: I,\n lazyTweens: z\n },\n L = D._plugins = {},\n U = N.tweenLookup = {},\n F = 0,\n j = N.reservedProps = {\n ease: 1,\n delay: 1,\n overwrite: 1,\n onComplete: 1,\n onCompleteParams: 1,\n onCompleteScope: 1,\n useFrames: 1,\n runBackwards: 1,\n startAt: 1,\n onUpdate: 1,\n onUpdateParams: 1,\n onUpdateScope: 1,\n onStart: 1,\n onStartParams: 1,\n onStartScope: 1,\n onReverseComplete: 1,\n onReverseCompleteParams: 1,\n onReverseCompleteScope: 1,\n onRepeat: 1,\n onRepeatParams: 1,\n onRepeatScope: 1,\n easeParams: 1,\n yoyo: 1,\n immediateRender: 1,\n repeat: 1,\n repeatDelay: 1,\n data: 1,\n paused: 1,\n reversed: 1,\n autoCSS: 1,\n lazy: 1\n },\n G = {\n none: 0,\n all: 1,\n auto: 2,\n concurrent: 3,\n allOnStart: 4,\n preexisting: 5,\n \"true\": 1,\n \"false\": 0\n },\n Q = x._rootFramesTimeline = new R(),\n B = x._rootTimeline = new R(),\n q = function () {\n var t = z.length;\n\n for (O = {}; --t > -1;) i = z[t], i && i._lazy !== !1 && (i.render(i._lazy, !1, !0), i._lazy = !1);\n\n z.length = 0;\n };\n\n B._startTime = r.time, Q._startTime = r.frame, B._active = Q._active = !0, setTimeout(q, 1), x._updateRoot = D.render = function () {\n var t, e, i;\n\n if (z.length && q(), B.render((r.time - B._startTime) * B._timeScale, !1, !1), Q.render((r.frame - Q._startTime) * Q._timeScale, !1, !1), z.length && q(), !(r.frame % 120)) {\n for (i in U) {\n for (e = U[i].tweens, t = e.length; --t > -1;) e[t]._gc && e.splice(t, 1);\n\n 0 === e.length && delete U[i];\n }\n\n if (i = B._first, (!i || i._paused) && D.autoSleep && !Q._first && 1 === r._listeners.tick.length) {\n for (; i && i._paused;) i = i._next;\n\n i || r.sleep();\n }\n }\n }, r.addEventListener(\"tick\", x._updateRoot);\n\n var M = function (t, e, i) {\n var s,\n n,\n r = t._gsTweenID;\n if (U[r || (t._gsTweenID = r = \"t\" + F++)] || (U[r] = {\n target: t,\n tweens: []\n }), e && (s = U[r].tweens, s[n = s.length] = e, i)) for (; --n > -1;) s[n] === e && s.splice(n, 1);\n return U[r].tweens;\n },\n $ = function (t, e, i, s, n) {\n var r, a, o, l;\n\n if (1 === s || s >= 4) {\n for (l = n.length, r = 0; l > r; r++) if ((o = n[r]) !== e) o._gc || o._enabled(!1, !1) && (a = !0);else if (5 === s) break;\n\n return a;\n }\n\n var _,\n u = e._startTime + h,\n m = [],\n f = 0,\n p = 0 === e._duration;\n\n for (r = n.length; --r > -1;) (o = n[r]) === e || o._gc || o._paused || (o._timeline !== e._timeline ? (_ = _ || K(e, 0, p), 0 === K(o, _, p) && (m[f++] = o)) : u >= o._startTime && o._startTime + o.totalDuration() / o._timeScale > u && ((p || !o._initted) && 2e-10 >= u - o._startTime || (m[f++] = o)));\n\n for (r = f; --r > -1;) o = m[r], 2 === s && o._kill(i, t) && (a = !0), (2 !== s || !o._firstPT && o._initted) && o._enabled(!1, !1) && (a = !0);\n\n return a;\n },\n K = function (t, e, i) {\n for (var s = t._timeline, n = s._timeScale, r = t._startTime; s._timeline;) {\n if (r += s._startTime, n *= s._timeScale, s._paused) return -100;\n s = s._timeline;\n }\n\n return r /= n, r > e ? r - e : i && r === e || !t._initted && 2 * h > r - e ? h : (r += t.totalDuration() / t._timeScale / n) > e + h ? 0 : r - e - h;\n };\n\n n._init = function () {\n var t,\n e,\n i,\n s,\n n,\n r = this.vars,\n a = this._overwrittenProps,\n o = this._duration,\n l = !!r.immediateRender,\n h = r.ease;\n\n if (r.startAt) {\n this._startAt && (this._startAt.render(-1, !0), this._startAt.kill()), n = {};\n\n for (s in r.startAt) n[s] = r.startAt[s];\n\n if (n.overwrite = !1, n.immediateRender = !0, n.lazy = l && r.lazy !== !1, n.startAt = n.delay = null, this._startAt = D.to(this.target, 0, n), l) if (this._time > 0) this._startAt = null;else if (0 !== o) return;\n } else if (r.runBackwards && 0 !== o) if (this._startAt) this._startAt.render(-1, !0), this._startAt.kill(), this._startAt = null;else {\n i = {};\n\n for (s in r) j[s] && \"autoCSS\" !== s || (i[s] = r[s]);\n\n if (i.overwrite = 0, i.data = \"isFromStart\", i.lazy = l && r.lazy !== !1, i.immediateRender = l, this._startAt = D.to(this.target, 0, i), l) {\n if (0 === this._time) return;\n } else this._startAt._init(), this._startAt._enabled(!1);\n }\n\n if (this._ease = h ? h instanceof T ? r.easeParams instanceof Array ? h.config.apply(h, r.easeParams) : h : \"function\" == typeof h ? new T(h, r.easeParams) : y[h] || D.defaultEase : D.defaultEase, this._easeType = this._ease._type, this._easePower = this._ease._power, this._firstPT = null, this._targets) for (t = this._targets.length; --t > -1;) this._initProps(this._targets[t], this._propLookup[t] = {}, this._siblings[t], a ? a[t] : null) && (e = !0);else e = this._initProps(this.target, this._propLookup, this._siblings, a);\n if (e && D._onPluginEvent(\"_onInitAllProps\", this), a && (this._firstPT || \"function\" != typeof this.target && this._enabled(!1, !1)), r.runBackwards) for (i = this._firstPT; i;) i.s += i.c, i.c = -i.c, i = i._next;\n this._onUpdate = r.onUpdate, this._initted = !0;\n }, n._initProps = function (e, i, s, n) {\n var r, a, o, l, h, _;\n\n if (null == e) return !1;\n O[e._gsTweenID] && q(), this.vars.css || e.style && e !== t && e.nodeType && L.css && this.vars.autoCSS !== !1 && E(this.vars, e);\n\n for (r in this.vars) {\n if (_ = this.vars[r], j[r]) _ && (_ instanceof Array || _.push && m(_)) && -1 !== _.join(\"\").indexOf(\"{self}\") && (this.vars[r] = _ = this._swapSelfInParams(_, this));else if (L[r] && (l = new L[r]())._onInitTween(e, this.vars[r], this)) {\n for (this._firstPT = h = {\n _next: this._firstPT,\n t: l,\n p: \"setRatio\",\n s: 0,\n c: 1,\n f: !0,\n n: r,\n pg: !0,\n pr: l._priority\n }, a = l._overwriteProps.length; --a > -1;) i[l._overwriteProps[a]] = this._firstPT;\n\n (l._priority || l._onInitAllProps) && (o = !0), (l._onDisable || l._onEnable) && (this._notifyPluginsOfEnabled = !0);\n } else this._firstPT = i[r] = h = {\n _next: this._firstPT,\n t: e,\n p: r,\n f: \"function\" == typeof e[r],\n n: r,\n pg: !1,\n pr: 0\n }, h.s = h.f ? e[r.indexOf(\"set\") || \"function\" != typeof e[\"get\" + r.substr(3)] ? r : \"get\" + r.substr(3)]() : parseFloat(e[r]), h.c = \"string\" == typeof _ && \"=\" === _.charAt(1) ? parseInt(_.charAt(0) + \"1\", 10) * Number(_.substr(2)) : Number(_) - h.s || 0;\n h && h._next && (h._next._prev = h);\n }\n\n return n && this._kill(n, e) ? this._initProps(e, i, s, n) : this._overwrite > 1 && this._firstPT && s.length > 1 && $(e, this, i, this._overwrite, s) ? (this._kill(i, e), this._initProps(e, i, s, n)) : (this._firstPT && (this.vars.lazy !== !1 && this._duration || this.vars.lazy && !this._duration) && (O[e._gsTweenID] = !0), o);\n }, n.render = function (t, e, i) {\n var s,\n n,\n r,\n a,\n o = this._time,\n l = this._duration,\n _ = this._rawPrevTime;\n if (t >= l) this._totalTime = this._time = l, this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1, this._reversed || (s = !0, n = \"onComplete\"), 0 === l && (this._initted || !this.vars.lazy || i) && (this._startTime === this._timeline._duration && (t = 0), (0 === t || 0 > _ || _ === h) && _ !== t && (i = !0, _ > h && (n = \"onReverseComplete\")), this._rawPrevTime = a = !e || t || _ === t ? t : h);else if (1e-7 > t) this._totalTime = this._time = 0, this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0, (0 !== o || 0 === l && _ > 0 && _ !== h) && (n = \"onReverseComplete\", s = this._reversed), 0 > t ? (this._active = !1, 0 === l && (this._initted || !this.vars.lazy || i) && (_ >= 0 && (i = !0), this._rawPrevTime = a = !e || t || _ === t ? t : h)) : this._initted || (i = !0);else if (this._totalTime = this._time = t, this._easeType) {\n var u = t / l,\n m = this._easeType,\n f = this._easePower;\n (1 === m || 3 === m && u >= .5) && (u = 1 - u), 3 === m && (u *= 2), 1 === f ? u *= u : 2 === f ? u *= u * u : 3 === f ? u *= u * u * u : 4 === f && (u *= u * u * u * u), this.ratio = 1 === m ? 1 - u : 2 === m ? u : .5 > t / l ? u / 2 : 1 - u / 2;\n } else this.ratio = this._ease.getRatio(t / l);\n\n if (this._time !== o || i) {\n if (!this._initted) {\n if (this._init(), !this._initted || this._gc) return;\n if (!i && this._firstPT && (this.vars.lazy !== !1 && this._duration || this.vars.lazy && !this._duration)) return this._time = this._totalTime = o, this._rawPrevTime = _, z.push(this), this._lazy = t, void 0;\n this._time && !s ? this.ratio = this._ease.getRatio(this._time / l) : s && this._ease._calcEnd && (this.ratio = this._ease.getRatio(0 === this._time ? 0 : 1));\n }\n\n for (this._lazy !== !1 && (this._lazy = !1), this._active || !this._paused && this._time !== o && t >= 0 && (this._active = !0), 0 === o && (this._startAt && (t >= 0 ? this._startAt.render(t, e, i) : n || (n = \"_dummyGS\")), this.vars.onStart && (0 !== this._time || 0 === l) && (e || this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || g))), r = this._firstPT; r;) r.f ? r.t[r.p](r.c * this.ratio + r.s) : r.t[r.p] = r.c * this.ratio + r.s, r = r._next;\n\n this._onUpdate && (0 > t && this._startAt && this._startTime && this._startAt.render(t, e, i), e || (this._time !== o || s) && this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || g)), n && (this._gc || (0 > t && this._startAt && !this._onUpdate && this._startTime && this._startAt.render(t, e, i), s && (this._timeline.autoRemoveChildren && this._enabled(!1, !1), this._active = !1), !e && this.vars[n] && this.vars[n].apply(this.vars[n + \"Scope\"] || this, this.vars[n + \"Params\"] || g), 0 === l && this._rawPrevTime === h && a !== h && (this._rawPrevTime = 0)));\n }\n }, n._kill = function (t, e) {\n if (\"all\" === t && (t = null), null == t && (null == e || e === this.target)) return this._lazy = !1, this._enabled(!1, !1);\n e = \"string\" != typeof e ? e || this._targets || this.target : D.selector(e) || e;\n var i, s, n, r, a, o, l, h;\n if ((m(e) || I(e)) && \"number\" != typeof e[0]) for (i = e.length; --i > -1;) this._kill(t, e[i]) && (o = !0);else {\n if (this._targets) {\n for (i = this._targets.length; --i > -1;) if (e === this._targets[i]) {\n a = this._propLookup[i] || {}, this._overwrittenProps = this._overwrittenProps || [], s = this._overwrittenProps[i] = t ? this._overwrittenProps[i] || {} : \"all\";\n break;\n }\n } else {\n if (e !== this.target) return !1;\n a = this._propLookup, s = this._overwrittenProps = t ? this._overwrittenProps || {} : \"all\";\n }\n\n if (a) {\n l = t || a, h = t !== s && \"all\" !== s && t !== a && (\"object\" != typeof t || !t._tempKill);\n\n for (n in l) (r = a[n]) && (r.pg && r.t._kill(l) && (o = !0), r.pg && 0 !== r.t._overwriteProps.length || (r._prev ? r._prev._next = r._next : r === this._firstPT && (this._firstPT = r._next), r._next && (r._next._prev = r._prev), r._next = r._prev = null), delete a[n]), h && (s[n] = 1);\n\n !this._firstPT && this._initted && this._enabled(!1, !1);\n }\n }\n return o;\n }, n.invalidate = function () {\n return this._notifyPluginsOfEnabled && D._onPluginEvent(\"_onDisable\", this), this._firstPT = null, this._overwrittenProps = null, this._onUpdate = null, this._startAt = null, this._initted = this._active = this._notifyPluginsOfEnabled = this._lazy = !1, this._propLookup = this._targets ? {} : [], this;\n }, n._enabled = function (t, e) {\n if (a || r.wake(), t && this._gc) {\n var i,\n s = this._targets;\n if (s) for (i = s.length; --i > -1;) this._siblings[i] = M(s[i], this, !0);else this._siblings = M(this.target, this, !0);\n }\n\n return x.prototype._enabled.call(this, t, e), this._notifyPluginsOfEnabled && this._firstPT ? D._onPluginEvent(t ? \"_onEnable\" : \"_onDisable\", this) : !1;\n }, D.to = function (t, e, i) {\n return new D(t, e, i);\n }, D.from = function (t, e, i) {\n return i.runBackwards = !0, i.immediateRender = 0 != i.immediateRender, new D(t, e, i);\n }, D.fromTo = function (t, e, i, s) {\n return s.startAt = i, s.immediateRender = 0 != s.immediateRender && 0 != i.immediateRender, new D(t, e, s);\n }, D.delayedCall = function (t, e, i, s, n) {\n return new D(e, 0, {\n delay: t,\n onComplete: e,\n onCompleteParams: i,\n onCompleteScope: s,\n onReverseComplete: e,\n onReverseCompleteParams: i,\n onReverseCompleteScope: s,\n immediateRender: !1,\n useFrames: n,\n overwrite: 0\n });\n }, D.set = function (t, e) {\n return new D(t, 0, e);\n }, D.getTweensOf = function (t, e) {\n if (null == t) return [];\n t = \"string\" != typeof t ? t : D.selector(t) || t;\n var i, s, n, r;\n\n if ((m(t) || I(t)) && \"number\" != typeof t[0]) {\n for (i = t.length, s = []; --i > -1;) s = s.concat(D.getTweensOf(t[i], e));\n\n for (i = s.length; --i > -1;) for (r = s[i], n = i; --n > -1;) r === s[n] && s.splice(i, 1);\n } else for (s = M(t).concat(), i = s.length; --i > -1;) (s[i]._gc || e && !s[i].isActive()) && s.splice(i, 1);\n\n return s;\n }, D.killTweensOf = D.killDelayedCallsTo = function (t, e, i) {\n \"object\" == typeof e && (i = e, e = !1);\n\n for (var s = D.getTweensOf(t, e), n = s.length; --n > -1;) s[n]._kill(i, t);\n };\n var H = d(\"plugins.TweenPlugin\", function (t, e) {\n this._overwriteProps = (t || \"\").split(\",\"), this._propName = this._overwriteProps[0], this._priority = e || 0, this._super = H.prototype;\n }, !0);\n\n if (n = H.prototype, H.version = \"1.10.1\", H.API = 2, n._firstPT = null, n._addTween = function (t, e, i, s, n, r) {\n var a, o;\n return null != s && (a = \"number\" == typeof s || \"=\" !== s.charAt(1) ? Number(s) - i : parseInt(s.charAt(0) + \"1\", 10) * Number(s.substr(2))) ? (this._firstPT = o = {\n _next: this._firstPT,\n t: t,\n p: e,\n s: i,\n c: a,\n f: \"function\" == typeof t[e],\n n: n || e,\n r: r\n }, o._next && (o._next._prev = o), o) : void 0;\n }, n.setRatio = function (t) {\n for (var e, i = this._firstPT, s = 1e-6; i;) e = i.c * t + i.s, i.r ? e = Math.round(e) : s > e && e > -s && (e = 0), i.f ? i.t[i.p](e) : i.t[i.p] = e, i = i._next;\n }, n._kill = function (t) {\n var e,\n i = this._overwriteProps,\n s = this._firstPT;\n if (null != t[this._propName]) this._overwriteProps = [];else for (e = i.length; --e > -1;) null != t[i[e]] && i.splice(e, 1);\n\n for (; s;) null != t[s.n] && (s._next && (s._next._prev = s._prev), s._prev ? (s._prev._next = s._next, s._prev = null) : this._firstPT === s && (this._firstPT = s._next)), s = s._next;\n\n return !1;\n }, n._roundProps = function (t, e) {\n for (var i = this._firstPT; i;) (t[this._propName] || null != i.n && t[i.n.split(this._propName + \"_\").join(\"\")]) && (i.r = e), i = i._next;\n }, D._onPluginEvent = function (t, e) {\n var i,\n s,\n n,\n r,\n a,\n o = e._firstPT;\n\n if (\"_onInitAllProps\" === t) {\n for (; o;) {\n for (a = o._next, s = n; s && s.pr > o.pr;) s = s._next;\n\n (o._prev = s ? s._prev : r) ? o._prev._next = o : n = o, (o._next = s) ? s._prev = o : r = o, o = a;\n }\n\n o = e._firstPT = n;\n }\n\n for (; o;) o.pg && \"function\" == typeof o.t[t] && o.t[t]() && (i = !0), o = o._next;\n\n return i;\n }, H.activate = function (t) {\n for (var e = t.length; --e > -1;) t[e].API === H.API && (L[new t[e]()._propName] = t[e]);\n\n return !0;\n }, c.plugin = function (t) {\n if (!(t && t.propName && t.init && t.API)) throw \"illegal plugin definition.\";\n var e,\n i = t.propName,\n s = t.priority || 0,\n n = t.overwriteProps,\n r = {\n init: \"_onInitTween\",\n set: \"setRatio\",\n kill: \"_kill\",\n round: \"_roundProps\",\n initAll: \"_onInitAllProps\"\n },\n a = d(\"plugins.\" + i.charAt(0).toUpperCase() + i.substr(1) + \"Plugin\", function () {\n H.call(this, i, s), this._overwriteProps = n || [];\n }, t.global === !0),\n o = a.prototype = new H(i);\n o.constructor = a, a.API = t.API;\n\n for (e in r) \"function\" == typeof t[e] && (o[r[e]] = t[e]);\n\n return a.version = t.version, H.activate([a]), a;\n }, i = t._gsQueue) {\n for (s = 0; i.length > s; s++) i[s]();\n\n for (n in f) f[n].func || t.console.log(\"GSAP encountered missing dependency: com.greensock.\" + n);\n }\n\n a = !1;\n }\n})(window);\n\n},{}],11:[function(require,module,exports){\n\"use strict\";\n\n/*!\r\n * VERSION: beta 1.9.3\r\n * DATE: 2013-04-02\r\n * UPDATES AND DOCS AT: http://www.greensock.com\r\n *\r\n * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.\r\n * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for\r\n * Club GreenSock members, the software agreement that was issued with your membership.\r\n * \r\n * @author: Jack Doyle, jack@greensock.com\r\n **/\n(window._gsQueue || (window._gsQueue = [])).push(function () {\n \"use strict\";\n\n window._gsDefine(\"easing.Back\", [\"easing.Ease\"], function (t) {\n var e,\n i,\n s,\n r = window.GreenSockGlobals || window,\n n = r.com.greensock,\n a = 2 * Math.PI,\n o = Math.PI / 2,\n h = n._class,\n l = function (e, i) {\n var s = h(\"easing.\" + e, function () {}, !0),\n r = s.prototype = new t();\n return r.constructor = s, r.getRatio = i, s;\n },\n _ = t.register || function () {},\n u = function (t, e, i, s) {\n var r = h(\"easing.\" + t, {\n easeOut: new e(),\n easeIn: new i(),\n easeInOut: new s()\n }, !0);\n return _(r, t), r;\n },\n c = function (t, e, i) {\n this.t = t, this.v = e, i && (this.next = i, i.prev = this, this.c = i.v - e, this.gap = i.t - t);\n },\n f = function (e, i) {\n var s = h(\"easing.\" + e, function (t) {\n this._p1 = t || 0 === t ? t : 1.70158, this._p2 = 1.525 * this._p1;\n }, !0),\n r = s.prototype = new t();\n return r.constructor = s, r.getRatio = i, r.config = function (t) {\n return new s(t);\n }, s;\n },\n p = u(\"Back\", f(\"BackOut\", function (t) {\n return (t -= 1) * t * ((this._p1 + 1) * t + this._p1) + 1;\n }), f(\"BackIn\", function (t) {\n return t * t * ((this._p1 + 1) * t - this._p1);\n }), f(\"BackInOut\", function (t) {\n return 1 > (t *= 2) ? .5 * t * t * ((this._p2 + 1) * t - this._p2) : .5 * ((t -= 2) * t * ((this._p2 + 1) * t + this._p2) + 2);\n })),\n m = h(\"easing.SlowMo\", function (t, e, i) {\n e = e || 0 === e ? e : .7, null == t ? t = .7 : t > 1 && (t = 1), this._p = 1 !== t ? e : 0, this._p1 = (1 - t) / 2, this._p2 = t, this._p3 = this._p1 + this._p2, this._calcEnd = i === !0;\n }, !0),\n d = m.prototype = new t();\n\n return d.constructor = m, d.getRatio = function (t) {\n var e = t + (.5 - t) * this._p;\n return this._p1 > t ? this._calcEnd ? 1 - (t = 1 - t / this._p1) * t : e - (t = 1 - t / this._p1) * t * t * t * e : t > this._p3 ? this._calcEnd ? 1 - (t = (t - this._p3) / this._p1) * t : e + (t - e) * (t = (t - this._p3) / this._p1) * t * t * t : this._calcEnd ? 1 : e;\n }, m.ease = new m(.7, .7), d.config = m.config = function (t, e, i) {\n return new m(t, e, i);\n }, e = h(\"easing.SteppedEase\", function (t) {\n t = t || 1, this._p1 = 1 / t, this._p2 = t + 1;\n }, !0), d = e.prototype = new t(), d.constructor = e, d.getRatio = function (t) {\n return 0 > t ? t = 0 : t >= 1 && (t = .999999999), (this._p2 * t >> 0) * this._p1;\n }, d.config = e.config = function (t) {\n return new e(t);\n }, i = h(\"easing.RoughEase\", function (e) {\n e = e || {};\n\n for (var i, s, r, n, a, o, h = e.taper || \"none\", l = [], _ = 0, u = 0 | (e.points || 20), f = u, p = e.randomize !== !1, m = e.clamp === !0, d = e.template instanceof t ? e.template : null, g = \"number\" == typeof e.strength ? .4 * e.strength : .4; --f > -1;) i = p ? Math.random() : 1 / u * f, s = d ? d.getRatio(i) : i, \"none\" === h ? r = g : \"out\" === h ? (n = 1 - i, r = n * n * g) : \"in\" === h ? r = i * i * g : .5 > i ? (n = 2 * i, r = .5 * n * n * g) : (n = 2 * (1 - i), r = .5 * n * n * g), p ? s += Math.random() * r - .5 * r : f % 2 ? s += .5 * r : s -= .5 * r, m && (s > 1 ? s = 1 : 0 > s && (s = 0)), l[_++] = {\n x: i,\n y: s\n };\n\n for (l.sort(function (t, e) {\n return t.x - e.x;\n }), o = new c(1, 1, null), f = u; --f > -1;) a = l[f], o = new c(a.x, a.y, o);\n\n this._prev = new c(0, 0, 0 !== o.t ? o : o.next);\n }, !0), d = i.prototype = new t(), d.constructor = i, d.getRatio = function (t) {\n var e = this._prev;\n\n if (t > e.t) {\n for (; e.next && t >= e.t;) e = e.next;\n\n e = e.prev;\n } else for (; e.prev && e.t >= t;) e = e.prev;\n\n return this._prev = e, e.v + (t - e.t) / e.gap * e.c;\n }, d.config = function (t) {\n return new i(t);\n }, i.ease = new i(), u(\"Bounce\", l(\"BounceOut\", function (t) {\n return 1 / 2.75 > t ? 7.5625 * t * t : 2 / 2.75 > t ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : 2.5 / 2.75 > t ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;\n }), l(\"BounceIn\", function (t) {\n return 1 / 2.75 > (t = 1 - t) ? 1 - 7.5625 * t * t : 2 / 2.75 > t ? 1 - (7.5625 * (t -= 1.5 / 2.75) * t + .75) : 2.5 / 2.75 > t ? 1 - (7.5625 * (t -= 2.25 / 2.75) * t + .9375) : 1 - (7.5625 * (t -= 2.625 / 2.75) * t + .984375);\n }), l(\"BounceInOut\", function (t) {\n var e = .5 > t;\n return t = e ? 1 - 2 * t : 2 * t - 1, t = 1 / 2.75 > t ? 7.5625 * t * t : 2 / 2.75 > t ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 : 2.5 / 2.75 > t ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 : 7.5625 * (t -= 2.625 / 2.75) * t + .984375, e ? .5 * (1 - t) : .5 * t + .5;\n })), u(\"Circ\", l(\"CircOut\", function (t) {\n return Math.sqrt(1 - (t -= 1) * t);\n }), l(\"CircIn\", function (t) {\n return -(Math.sqrt(1 - t * t) - 1);\n }), l(\"CircInOut\", function (t) {\n return 1 > (t *= 2) ? -.5 * (Math.sqrt(1 - t * t) - 1) : .5 * (Math.sqrt(1 - (t -= 2) * t) + 1);\n })), s = function (e, i, s) {\n var r = h(\"easing.\" + e, function (t, e) {\n this._p1 = t || 1, this._p2 = e || s, this._p3 = this._p2 / a * (Math.asin(1 / this._p1) || 0);\n }, !0),\n n = r.prototype = new t();\n return n.constructor = r, n.getRatio = i, n.config = function (t, e) {\n return new r(t, e);\n }, r;\n }, u(\"Elastic\", s(\"ElasticOut\", function (t) {\n return this._p1 * Math.pow(2, -10 * t) * Math.sin((t - this._p3) * a / this._p2) + 1;\n }, .3), s(\"ElasticIn\", function (t) {\n return -(this._p1 * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - this._p3) * a / this._p2));\n }, .3), s(\"ElasticInOut\", function (t) {\n return 1 > (t *= 2) ? -.5 * this._p1 * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - this._p3) * a / this._p2) : .5 * this._p1 * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - this._p3) * a / this._p2) + 1;\n }, .45)), u(\"Expo\", l(\"ExpoOut\", function (t) {\n return 1 - Math.pow(2, -10 * t);\n }), l(\"ExpoIn\", function (t) {\n return Math.pow(2, 10 * (t - 1)) - .001;\n }), l(\"ExpoInOut\", function (t) {\n return 1 > (t *= 2) ? .5 * Math.pow(2, 10 * (t - 1)) : .5 * (2 - Math.pow(2, -10 * (t - 1)));\n })), u(\"Sine\", l(\"SineOut\", function (t) {\n return Math.sin(t * o);\n }), l(\"SineIn\", function (t) {\n return -Math.cos(t * o) + 1;\n }), l(\"SineInOut\", function (t) {\n return -.5 * (Math.cos(Math.PI * t) - 1);\n })), h(\"easing.EaseLookup\", {\n find: function (e) {\n return t.map[e];\n }\n }, !0), _(r.SlowMo, \"SlowMo\", \"ease,\"), _(i, \"RoughEase\", \"ease,\"), _(e, \"SteppedEase\", \"ease,\"), p;\n }, !0);\n}), window._gsDefine && window._gsQueue.pop()();\n\n},{}],12:[function(require,module,exports){\n\"use strict\";\n\n/*!\r\n * VERSION: 1.12.1\r\n * DATE: 2014-06-26\r\n * UPDATES AND DOCS AT: http://www.greensock.com\r\n *\r\n * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.\r\n * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for\r\n * Club GreenSock members, the software agreement that was issued with your membership.\r\n * \r\n * @author: Jack Doyle, jack@greensock.com\r\n */\n(window._gsQueue || (window._gsQueue = [])).push(function () {\n \"use strict\";\n\n window._gsDefine(\"plugins.CSSPlugin\", [\"plugins.TweenPlugin\", \"TweenLite\"], function (t, e) {\n var i,\n r,\n s,\n n,\n a = function () {\n t.call(this, \"css\"), this._overwriteProps.length = 0, this.setRatio = a.prototype.setRatio;\n },\n o = {},\n l = a.prototype = new t(\"css\");\n\n l.constructor = a, a.version = \"1.12.1\", a.API = 2, a.defaultTransformPerspective = 0, a.defaultSkewType = \"compensated\", l = \"px\", a.suffixMap = {\n top: l,\n right: l,\n bottom: l,\n left: l,\n width: l,\n height: l,\n fontSize: l,\n padding: l,\n margin: l,\n perspective: l,\n lineHeight: \"\"\n };\n\n var h,\n u,\n f,\n _,\n p,\n c,\n d = /(?:\\d|\\-\\d|\\.\\d|\\-\\.\\d)+/g,\n m = /(?:\\d|\\-\\d|\\.\\d|\\-\\.\\d|\\+=\\d|\\-=\\d|\\+=.\\d|\\-=\\.\\d)+/g,\n g = /(?:\\+=|\\-=|\\-|\\b)[\\d\\-\\.]+[a-zA-Z0-9]*(?:%|\\b)/gi,\n v = /[^\\d\\-\\.]/g,\n y = /(?:\\d|\\-|\\+|=|#|\\.)*/g,\n T = /opacity *= *([^)]*)/i,\n w = /opacity:([^;]*)/i,\n x = /alpha\\(opacity *=.+?\\)/i,\n b = /^(rgb|hsl)/,\n P = /([A-Z])/g,\n S = /-([a-z])/gi,\n C = /(^(?:url\\(\\\"|url\\())|(?:(\\\"\\))$|\\)$)/gi,\n R = function (t, e) {\n return e.toUpperCase();\n },\n k = /(?:Left|Right|Width)/i,\n A = /(M11|M12|M21|M22)=[\\d\\-\\.e]+/gi,\n O = /progid\\:DXImageTransform\\.Microsoft\\.Matrix\\(.+?\\)/i,\n D = /,(?=[^\\)]*(?:\\(|$))/gi,\n M = Math.PI / 180,\n L = 180 / Math.PI,\n N = {},\n X = document,\n z = X.createElement(\"div\"),\n I = X.createElement(\"img\"),\n E = a._internals = {\n _specialProps: o\n },\n F = navigator.userAgent,\n Y = function () {\n var t,\n e = F.indexOf(\"Android\"),\n i = X.createElement(\"div\");\n return f = -1 !== F.indexOf(\"Safari\") && -1 === F.indexOf(\"Chrome\") && (-1 === e || Number(F.substr(e + 8, 1)) > 3), p = f && 6 > Number(F.substr(F.indexOf(\"Version/\") + 8, 1)), _ = -1 !== F.indexOf(\"Firefox\"), /MSIE ([0-9]{1,}[\\.0-9]{0,})/.exec(F) && (c = parseFloat(RegExp.$1)), i.innerHTML = \"a\", t = i.getElementsByTagName(\"a\")[0], t ? /^0.55/.test(t.style.opacity) : !1;\n }(),\n B = function (t) {\n return T.test(\"string\" == typeof t ? t : (t.currentStyle ? t.currentStyle.filter : t.style.filter) || \"\") ? parseFloat(RegExp.$1) / 100 : 1;\n },\n U = function (t) {\n window.console && console.log(t);\n },\n W = \"\",\n j = \"\",\n V = function (t, e) {\n e = e || z;\n var i,\n r,\n s = e.style;\n if (void 0 !== s[t]) return t;\n\n for (t = t.charAt(0).toUpperCase() + t.substr(1), i = [\"O\", \"Moz\", \"ms\", \"Ms\", \"Webkit\"], r = 5; --r > -1 && void 0 === s[i[r] + t];);\n\n return r >= 0 ? (j = 3 === r ? \"ms\" : i[r], W = \"-\" + j.toLowerCase() + \"-\", j + t) : null;\n },\n H = X.defaultView ? X.defaultView.getComputedStyle : function () {},\n q = a.getStyle = function (t, e, i, r, s) {\n var n;\n return Y || \"opacity\" !== e ? (!r && t.style[e] ? n = t.style[e] : (i = i || H(t)) ? n = i[e] || i.getPropertyValue(e) || i.getPropertyValue(e.replace(P, \"-$1\").toLowerCase()) : t.currentStyle && (n = t.currentStyle[e]), null == s || n && \"none\" !== n && \"auto\" !== n && \"auto auto\" !== n ? n : s) : B(t);\n },\n Q = E.convertToPixels = function (t, i, r, s, n) {\n if (\"px\" === s || !s) return r;\n if (\"auto\" === s || !r) return 0;\n var o,\n l,\n h,\n u = k.test(i),\n f = t,\n _ = z.style,\n p = 0 > r;\n if (p && (r = -r), \"%\" === s && -1 !== i.indexOf(\"border\")) o = r / 100 * (u ? t.clientWidth : t.clientHeight);else {\n if (_.cssText = \"border:0 solid red;position:\" + q(t, \"position\") + \";line-height:0;\", \"%\" !== s && f.appendChild) _[u ? \"borderLeftWidth\" : \"borderTopWidth\"] = r + s;else {\n if (f = t.parentNode || X.body, l = f._gsCache, h = e.ticker.frame, l && u && l.time === h) return l.width * r / 100;\n _[u ? \"width\" : \"height\"] = r + s;\n }\n f.appendChild(z), o = parseFloat(z[u ? \"offsetWidth\" : \"offsetHeight\"]), f.removeChild(z), u && \"%\" === s && a.cacheWidths !== !1 && (l = f._gsCache = f._gsCache || {}, l.time = h, l.width = 100 * (o / r)), 0 !== o || n || (o = Q(t, i, r, s, !0));\n }\n return p ? -o : o;\n },\n Z = E.calculateOffset = function (t, e, i) {\n if (\"absolute\" !== q(t, \"position\", i)) return 0;\n var r = \"left\" === e ? \"Left\" : \"Top\",\n s = q(t, \"margin\" + r, i);\n return t[\"offset\" + r] - (Q(t, e, parseFloat(s), s.replace(y, \"\")) || 0);\n },\n $ = function (t, e) {\n var i,\n r,\n s = {};\n if (e = e || H(t, null)) {\n if (i = e.length) for (; --i > -1;) s[e[i].replace(S, R)] = e.getPropertyValue(e[i]);else for (i in e) s[i] = e[i];\n } else if (e = t.currentStyle || t.style) for (i in e) \"string\" == typeof i && void 0 === s[i] && (s[i.replace(S, R)] = e[i]);\n return Y || (s.opacity = B(t)), r = Pe(t, e, !1), s.rotation = r.rotation, s.skewX = r.skewX, s.scaleX = r.scaleX, s.scaleY = r.scaleY, s.x = r.x, s.y = r.y, xe && (s.z = r.z, s.rotationX = r.rotationX, s.rotationY = r.rotationY, s.scaleZ = r.scaleZ), s.filters && delete s.filters, s;\n },\n G = function (t, e, i, r, s) {\n var n,\n a,\n o,\n l = {},\n h = t.style;\n\n for (a in i) \"cssText\" !== a && \"length\" !== a && isNaN(a) && (e[a] !== (n = i[a]) || s && s[a]) && -1 === a.indexOf(\"Origin\") && (\"number\" == typeof n || \"string\" == typeof n) && (l[a] = \"auto\" !== n || \"left\" !== a && \"top\" !== a ? \"\" !== n && \"auto\" !== n && \"none\" !== n || \"string\" != typeof e[a] || \"\" === e[a].replace(v, \"\") ? n : 0 : Z(t, a), void 0 !== h[a] && (o = new fe(h, a, h[a], o)));\n\n if (r) for (a in r) \"className\" !== a && (l[a] = r[a]);\n return {\n difs: l,\n firstMPT: o\n };\n },\n K = {\n width: [\"Left\", \"Right\"],\n height: [\"Top\", \"Bottom\"]\n },\n J = [\"marginLeft\", \"marginRight\", \"marginTop\", \"marginBottom\"],\n te = function (t, e, i) {\n var r = parseFloat(\"width\" === e ? t.offsetWidth : t.offsetHeight),\n s = K[e],\n n = s.length;\n\n for (i = i || H(t, null); --n > -1;) r -= parseFloat(q(t, \"padding\" + s[n], i, !0)) || 0, r -= parseFloat(q(t, \"border\" + s[n] + \"Width\", i, !0)) || 0;\n\n return r;\n },\n ee = function (t, e) {\n (null == t || \"\" === t || \"auto\" === t || \"auto auto\" === t) && (t = \"0 0\");\n var i = t.split(\" \"),\n r = -1 !== t.indexOf(\"left\") ? \"0%\" : -1 !== t.indexOf(\"right\") ? \"100%\" : i[0],\n s = -1 !== t.indexOf(\"top\") ? \"0%\" : -1 !== t.indexOf(\"bottom\") ? \"100%\" : i[1];\n return null == s ? s = \"0\" : \"center\" === s && (s = \"50%\"), (\"center\" === r || isNaN(parseFloat(r)) && -1 === (r + \"\").indexOf(\"=\")) && (r = \"50%\"), e && (e.oxp = -1 !== r.indexOf(\"%\"), e.oyp = -1 !== s.indexOf(\"%\"), e.oxr = \"=\" === r.charAt(1), e.oyr = \"=\" === s.charAt(1), e.ox = parseFloat(r.replace(v, \"\")), e.oy = parseFloat(s.replace(v, \"\"))), r + \" \" + s + (i.length > 2 ? \" \" + i[2] : \"\");\n },\n ie = function (t, e) {\n return \"string\" == typeof t && \"=\" === t.charAt(1) ? parseInt(t.charAt(0) + \"1\", 10) * parseFloat(t.substr(2)) : parseFloat(t) - parseFloat(e);\n },\n re = function (t, e) {\n return null == t ? e : \"string\" == typeof t && \"=\" === t.charAt(1) ? parseInt(t.charAt(0) + \"1\", 10) * Number(t.substr(2)) + e : parseFloat(t);\n },\n se = function (t, e, i, r) {\n var s,\n n,\n a,\n o,\n l = 1e-6;\n return null == t ? o = e : \"number\" == typeof t ? o = t : (s = 360, n = t.split(\"_\"), a = Number(n[0].replace(v, \"\")) * (-1 === t.indexOf(\"rad\") ? 1 : L) - (\"=\" === t.charAt(1) ? 0 : e), n.length && (r && (r[i] = e + a), -1 !== t.indexOf(\"short\") && (a %= s, a !== a % (s / 2) && (a = 0 > a ? a + s : a - s)), -1 !== t.indexOf(\"_cw\") && 0 > a ? a = (a + 9999999999 * s) % s - (0 | a / s) * s : -1 !== t.indexOf(\"ccw\") && a > 0 && (a = (a - 9999999999 * s) % s - (0 | a / s) * s)), o = e + a), l > o && o > -l && (o = 0), o;\n },\n ne = {\n aqua: [0, 255, 255],\n lime: [0, 255, 0],\n silver: [192, 192, 192],\n black: [0, 0, 0],\n maroon: [128, 0, 0],\n teal: [0, 128, 128],\n blue: [0, 0, 255],\n navy: [0, 0, 128],\n white: [255, 255, 255],\n fuchsia: [255, 0, 255],\n olive: [128, 128, 0],\n yellow: [255, 255, 0],\n orange: [255, 165, 0],\n gray: [128, 128, 128],\n purple: [128, 0, 128],\n green: [0, 128, 0],\n red: [255, 0, 0],\n pink: [255, 192, 203],\n cyan: [0, 255, 255],\n transparent: [255, 255, 255, 0]\n },\n ae = function (t, e, i) {\n return t = 0 > t ? t + 1 : t > 1 ? t - 1 : t, 0 | 255 * (1 > 6 * t ? e + 6 * (i - e) * t : .5 > t ? i : 2 > 3 * t ? e + 6 * (i - e) * (2 / 3 - t) : e) + .5;\n },\n oe = function (t) {\n var e, i, r, s, n, a;\n return t && \"\" !== t ? \"number\" == typeof t ? [t >> 16, 255 & t >> 8, 255 & t] : (\",\" === t.charAt(t.length - 1) && (t = t.substr(0, t.length - 1)), ne[t] ? ne[t] : \"#\" === t.charAt(0) ? (4 === t.length && (e = t.charAt(1), i = t.charAt(2), r = t.charAt(3), t = \"#\" + e + e + i + i + r + r), t = parseInt(t.substr(1), 16), [t >> 16, 255 & t >> 8, 255 & t]) : \"hsl\" === t.substr(0, 3) ? (t = t.match(d), s = Number(t[0]) % 360 / 360, n = Number(t[1]) / 100, a = Number(t[2]) / 100, i = .5 >= a ? a * (n + 1) : a + n - a * n, e = 2 * a - i, t.length > 3 && (t[3] = Number(t[3])), t[0] = ae(s + 1 / 3, e, i), t[1] = ae(s, e, i), t[2] = ae(s - 1 / 3, e, i), t) : (t = t.match(d) || ne.transparent, t[0] = Number(t[0]), t[1] = Number(t[1]), t[2] = Number(t[2]), t.length > 3 && (t[3] = Number(t[3])), t)) : ne.black;\n },\n le = \"(?:\\\\b(?:(?:rgb|rgba|hsl|hsla)\\\\(.+?\\\\))|\\\\B#.+?\\\\b\";\n\n for (l in ne) le += \"|\" + l + \"\\\\b\";\n\n le = RegExp(le + \")\", \"gi\");\n\n var he = function (t, e, i, r) {\n if (null == t) return function (t) {\n return t;\n };\n var s,\n n = e ? (t.match(le) || [\"\"])[0] : \"\",\n a = t.split(n).join(\"\").match(g) || [],\n o = t.substr(0, t.indexOf(a[0])),\n l = \")\" === t.charAt(t.length - 1) ? \")\" : \"\",\n h = -1 !== t.indexOf(\" \") ? \" \" : \",\",\n u = a.length,\n f = u > 0 ? a[0].replace(d, \"\") : \"\";\n return u ? s = e ? function (t) {\n var e, _, p, c;\n\n if (\"number\" == typeof t) t += f;else if (r && D.test(t)) {\n for (c = t.replace(D, \"|\").split(\"|\"), p = 0; c.length > p; p++) c[p] = s(c[p]);\n\n return c.join(\",\");\n }\n if (e = (t.match(le) || [n])[0], _ = t.split(e).join(\"\").match(g) || [], p = _.length, u > p--) for (; u > ++p;) _[p] = i ? _[0 | (p - 1) / 2] : a[p];\n return o + _.join(h) + h + e + l + (-1 !== t.indexOf(\"inset\") ? \" inset\" : \"\");\n } : function (t) {\n var e, n, _;\n\n if (\"number\" == typeof t) t += f;else if (r && D.test(t)) {\n for (n = t.replace(D, \"|\").split(\"|\"), _ = 0; n.length > _; _++) n[_] = s(n[_]);\n\n return n.join(\",\");\n }\n if (e = t.match(g) || [], _ = e.length, u > _--) for (; u > ++_;) e[_] = i ? e[0 | (_ - 1) / 2] : a[_];\n return o + e.join(h) + l;\n } : function (t) {\n return t;\n };\n },\n ue = function (t) {\n return t = t.split(\",\"), function (e, i, r, s, n, a, o) {\n var l,\n h = (i + \"\").split(\" \");\n\n for (o = {}, l = 0; 4 > l; l++) o[t[l]] = h[l] = h[l] || h[(l - 1) / 2 >> 0];\n\n return s.parse(e, o, n, a);\n };\n },\n fe = (E._setPluginRatio = function (t) {\n this.plugin.setRatio(t);\n\n for (var e, i, r, s, n = this.data, a = n.proxy, o = n.firstMPT, l = 1e-6; o;) e = a[o.v], o.r ? e = Math.round(e) : l > e && e > -l && (e = 0), o.t[o.p] = e, o = o._next;\n\n if (n.autoRotate && (n.autoRotate.rotation = a.rotation), 1 === t) for (o = n.firstMPT; o;) {\n if (i = o.t, i.type) {\n if (1 === i.type) {\n for (s = i.xs0 + i.s + i.xs1, r = 1; i.l > r; r++) s += i[\"xn\" + r] + i[\"xs\" + (r + 1)];\n\n i.e = s;\n }\n } else i.e = i.s + i.xs0;\n\n o = o._next;\n }\n }, function (t, e, i, r, s) {\n this.t = t, this.p = e, this.v = i, this.r = s, r && (r._prev = this, this._next = r);\n }),\n _e = (E._parseToProxy = function (t, e, i, r, s, n) {\n var a,\n o,\n l,\n h,\n u,\n f = r,\n _ = {},\n p = {},\n c = i._transform,\n d = N;\n\n for (i._transform = null, N = e, r = u = i.parse(t, e, r, s), N = d, n && (i._transform = c, f && (f._prev = null, f._prev && (f._prev._next = null))); r && r !== f;) {\n if (1 >= r.type && (o = r.p, p[o] = r.s + r.c, _[o] = r.s, n || (h = new fe(r, \"s\", o, h, r.r), r.c = 0), 1 === r.type)) for (a = r.l; --a > 0;) l = \"xn\" + a, o = r.p + \"_\" + l, p[o] = r.data[l], _[o] = r[l], n || (h = new fe(r, l, o, h, r.rxp[l]));\n r = r._next;\n }\n\n return {\n proxy: _,\n end: p,\n firstMPT: h,\n pt: u\n };\n }, E.CSSPropTween = function (t, e, r, s, a, o, l, h, u, f, _) {\n this.t = t, this.p = e, this.s = r, this.c = s, this.n = l || e, t instanceof _e || n.push(this.n), this.r = h, this.type = o || 0, u && (this.pr = u, i = !0), this.b = void 0 === f ? r : f, this.e = void 0 === _ ? r + s : _, a && (this._next = a, a._prev = this);\n }),\n pe = a.parseComplex = function (t, e, i, r, s, n, a, o, l, u) {\n i = i || n || \"\", a = new _e(t, e, 0, 0, a, u ? 2 : 1, null, !1, o, i, r), r += \"\";\n\n var f,\n _,\n p,\n c,\n g,\n v,\n y,\n T,\n w,\n x,\n P,\n S,\n C = i.split(\", \").join(\",\").split(\" \"),\n R = r.split(\", \").join(\",\").split(\" \"),\n k = C.length,\n A = h !== !1;\n\n for ((-1 !== r.indexOf(\",\") || -1 !== i.indexOf(\",\")) && (C = C.join(\" \").replace(D, \", \").split(\" \"), R = R.join(\" \").replace(D, \", \").split(\" \"), k = C.length), k !== R.length && (C = (n || \"\").split(\" \"), k = C.length), a.plugin = l, a.setRatio = u, f = 0; k > f; f++) if (c = C[f], g = R[f], T = parseFloat(c), T || 0 === T) a.appendXtra(\"\", T, ie(g, T), g.replace(m, \"\"), A && -1 !== g.indexOf(\"px\"), !0);else if (s && (\"#\" === c.charAt(0) || ne[c] || b.test(c))) S = \",\" === g.charAt(g.length - 1) ? \"),\" : \")\", c = oe(c), g = oe(g), w = c.length + g.length > 6, w && !Y && 0 === g[3] ? (a[\"xs\" + a.l] += a.l ? \" transparent\" : \"transparent\", a.e = a.e.split(R[f]).join(\"transparent\")) : (Y || (w = !1), a.appendXtra(w ? \"rgba(\" : \"rgb(\", c[0], g[0] - c[0], \",\", !0, !0).appendXtra(\"\", c[1], g[1] - c[1], \",\", !0).appendXtra(\"\", c[2], g[2] - c[2], w ? \",\" : S, !0), w && (c = 4 > c.length ? 1 : c[3], a.appendXtra(\"\", c, (4 > g.length ? 1 : g[3]) - c, S, !1)));else if (v = c.match(d)) {\n if (y = g.match(m), !y || y.length !== v.length) return a;\n\n for (p = 0, _ = 0; v.length > _; _++) P = v[_], x = c.indexOf(P, p), a.appendXtra(c.substr(p, x - p), Number(P), ie(y[_], P), \"\", A && \"px\" === c.substr(x + P.length, 2), 0 === _), p = x + P.length;\n\n a[\"xs\" + a.l] += c.substr(p);\n } else a[\"xs\" + a.l] += a.l ? \" \" + c : c;\n\n if (-1 !== r.indexOf(\"=\") && a.data) {\n for (S = a.xs0 + a.data.s, f = 1; a.l > f; f++) S += a[\"xs\" + f] + a.data[\"xn\" + f];\n\n a.e = S + a[\"xs\" + f];\n }\n\n return a.l || (a.type = -1, a.xs0 = a.e), a.xfirst || a;\n },\n ce = 9;\n\n for (l = _e.prototype, l.l = l.pr = 0; --ce > 0;) l[\"xn\" + ce] = 0, l[\"xs\" + ce] = \"\";\n\n l.xs0 = \"\", l._next = l._prev = l.xfirst = l.data = l.plugin = l.setRatio = l.rxp = null, l.appendXtra = function (t, e, i, r, s, n) {\n var a = this,\n o = a.l;\n return a[\"xs\" + o] += n && o ? \" \" + t : t || \"\", i || 0 === o || a.plugin ? (a.l++, a.type = a.setRatio ? 2 : 1, a[\"xs\" + a.l] = r || \"\", o > 0 ? (a.data[\"xn\" + o] = e + i, a.rxp[\"xn\" + o] = s, a[\"xn\" + o] = e, a.plugin || (a.xfirst = new _e(a, \"xn\" + o, e, i, a.xfirst || a, 0, a.n, s, a.pr), a.xfirst.xs0 = 0), a) : (a.data = {\n s: e + i\n }, a.rxp = {}, a.s = e, a.c = i, a.r = s, a)) : (a[\"xs\" + o] += e + (r || \"\"), a);\n };\n\n var de = function (t, e) {\n e = e || {}, this.p = e.prefix ? V(t) || t : t, o[t] = o[this.p] = this, this.format = e.formatter || he(e.defaultValue, e.color, e.collapsible, e.multi), e.parser && (this.parse = e.parser), this.clrs = e.color, this.multi = e.multi, this.keyword = e.keyword, this.dflt = e.defaultValue, this.pr = e.priority || 0;\n },\n me = E._registerComplexSpecialProp = function (t, e, i) {\n \"object\" != typeof e && (e = {\n parser: i\n });\n var r,\n s,\n n = t.split(\",\"),\n a = e.defaultValue;\n\n for (i = i || [a], r = 0; n.length > r; r++) e.prefix = 0 === r && e.prefix, e.defaultValue = i[r] || a, s = new de(n[r], e);\n },\n ge = function (t) {\n if (!o[t]) {\n var e = t.charAt(0).toUpperCase() + t.substr(1) + \"Plugin\";\n me(t, {\n parser: function (t, i, r, s, n, a, l) {\n var h = (window.GreenSockGlobals || window).com.greensock.plugins[e];\n return h ? (h._cssRegister(), o[r].parse(t, i, r, s, n, a, l)) : (U(\"Error: \" + e + \" js file not loaded.\"), n);\n }\n });\n }\n };\n\n l = de.prototype, l.parseComplex = function (t, e, i, r, s, n) {\n var a,\n o,\n l,\n h,\n u,\n f,\n _ = this.keyword;\n\n if (this.multi && (D.test(i) || D.test(e) ? (o = e.replace(D, \"|\").split(\"|\"), l = i.replace(D, \"|\").split(\"|\")) : _ && (o = [e], l = [i])), l) {\n for (h = l.length > o.length ? l.length : o.length, a = 0; h > a; a++) e = o[a] = o[a] || this.dflt, i = l[a] = l[a] || this.dflt, _ && (u = e.indexOf(_), f = i.indexOf(_), u !== f && (i = -1 === f ? l : o, i[a] += \" \" + _));\n\n e = o.join(\", \"), i = l.join(\", \");\n }\n\n return pe(t, this.p, e, i, this.clrs, this.dflt, r, this.pr, s, n);\n }, l.parse = function (t, e, i, r, n, a) {\n return this.parseComplex(t.style, this.format(q(t, this.p, s, !1, this.dflt)), this.format(e), n, a);\n }, a.registerSpecialProp = function (t, e, i) {\n me(t, {\n parser: function (t, r, s, n, a, o) {\n var l = new _e(t, s, 0, 0, a, 2, s, !1, i);\n return l.plugin = o, l.setRatio = e(t, r, n._tween, s), l;\n },\n priority: i\n });\n };\n\n var ve = \"scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective\".split(\",\"),\n ye = V(\"transform\"),\n Te = W + \"transform\",\n we = V(\"transformOrigin\"),\n xe = null !== V(\"perspective\"),\n be = E.Transform = function () {\n this.skewY = 0;\n },\n Pe = E.getTransform = function (t, e, i, r) {\n if (t._gsTransform && i && !r) return t._gsTransform;\n\n var s,\n n,\n o,\n l,\n h,\n u,\n f,\n _,\n p,\n c,\n d,\n m,\n g,\n v = i ? t._gsTransform || new be() : new be(),\n y = 0 > v.scaleX,\n T = 2e-5,\n w = 1e5,\n x = 179.99,\n b = x * M,\n P = xe ? parseFloat(q(t, we, e, !1, \"0 0 0\").split(\" \")[2]) || v.zOrigin || 0 : 0;\n\n for (ye ? s = q(t, Te, e, !0) : t.currentStyle && (s = t.currentStyle.filter.match(A), s = s && 4 === s.length ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), v.x || 0, v.y || 0].join(\",\") : \"\"), n = (s || \"\").match(/(?:\\-|\\b)[\\d\\-\\.e]+\\b/gi) || [], o = n.length; --o > -1;) l = Number(n[o]), n[o] = (h = l - (l |= 0)) ? (0 | h * w + (0 > h ? -.5 : .5)) / w + l : l;\n\n if (16 === n.length) {\n var S = n[8],\n C = n[9],\n R = n[10],\n k = n[12],\n O = n[13],\n D = n[14];\n\n if (v.zOrigin && (D = -v.zOrigin, k = S * D - n[12], O = C * D - n[13], D = R * D + v.zOrigin - n[14]), !i || r || null == v.rotationX) {\n var N,\n X,\n z,\n I,\n E,\n F,\n Y,\n B = n[0],\n U = n[1],\n W = n[2],\n j = n[3],\n V = n[4],\n H = n[5],\n Q = n[6],\n Z = n[7],\n $ = n[11],\n G = Math.atan2(Q, R),\n K = -b > G || G > b;\n v.rotationX = G * L, G && (I = Math.cos(-G), E = Math.sin(-G), N = V * I + S * E, X = H * I + C * E, z = Q * I + R * E, S = V * -E + S * I, C = H * -E + C * I, R = Q * -E + R * I, $ = Z * -E + $ * I, V = N, H = X, Q = z), G = Math.atan2(S, B), v.rotationY = G * L, G && (F = -b > G || G > b, I = Math.cos(-G), E = Math.sin(-G), N = B * I - S * E, X = U * I - C * E, z = W * I - R * E, C = U * E + C * I, R = W * E + R * I, $ = j * E + $ * I, B = N, U = X, W = z), G = Math.atan2(U, H), v.rotation = G * L, G && (Y = -b > G || G > b, I = Math.cos(-G), E = Math.sin(-G), B = B * I + V * E, X = U * I + H * E, H = U * -E + H * I, Q = W * -E + Q * I, U = X), Y && K ? v.rotation = v.rotationX = 0 : Y && F ? v.rotation = v.rotationY = 0 : F && K && (v.rotationY = v.rotationX = 0), v.scaleX = (0 | Math.sqrt(B * B + U * U) * w + .5) / w, v.scaleY = (0 | Math.sqrt(H * H + C * C) * w + .5) / w, v.scaleZ = (0 | Math.sqrt(Q * Q + R * R) * w + .5) / w, v.skewX = 0, v.perspective = $ ? 1 / (0 > $ ? -$ : $) : 0, v.x = k, v.y = O, v.z = D;\n }\n } else if (!(xe && !r && n.length && v.x === n[4] && v.y === n[5] && (v.rotationX || v.rotationY) || void 0 !== v.x && \"none\" === q(t, \"display\", e))) {\n var J = n.length >= 6,\n te = J ? n[0] : 1,\n ee = n[1] || 0,\n ie = n[2] || 0,\n re = J ? n[3] : 1;\n v.x = n[4] || 0, v.y = n[5] || 0, u = Math.sqrt(te * te + ee * ee), f = Math.sqrt(re * re + ie * ie), _ = te || ee ? Math.atan2(ee, te) * L : v.rotation || 0, p = ie || re ? Math.atan2(ie, re) * L + _ : v.skewX || 0, c = u - Math.abs(v.scaleX || 0), d = f - Math.abs(v.scaleY || 0), Math.abs(p) > 90 && 270 > Math.abs(p) && (y ? (u *= -1, p += 0 >= _ ? 180 : -180, _ += 0 >= _ ? 180 : -180) : (f *= -1, p += 0 >= p ? 180 : -180)), m = (_ - v.rotation) % 180, g = (p - v.skewX) % 180, (void 0 === v.skewX || c > T || -T > c || d > T || -T > d || m > -x && x > m && false | m * w || g > -x && x > g && false | g * w) && (v.scaleX = u, v.scaleY = f, v.rotation = _, v.skewX = p), xe && (v.rotationX = v.rotationY = v.z = 0, v.perspective = parseFloat(a.defaultTransformPerspective) || 0, v.scaleZ = 1);\n }\n\n v.zOrigin = P;\n\n for (o in v) T > v[o] && v[o] > -T && (v[o] = 0);\n\n return i && (t._gsTransform = v), v;\n },\n Se = function (t) {\n var e,\n i,\n r = this.data,\n s = -r.rotation * M,\n n = s + r.skewX * M,\n a = 1e5,\n o = (0 | Math.cos(s) * r.scaleX * a) / a,\n l = (0 | Math.sin(s) * r.scaleX * a) / a,\n h = (0 | Math.sin(n) * -r.scaleY * a) / a,\n u = (0 | Math.cos(n) * r.scaleY * a) / a,\n f = this.t.style,\n _ = this.t.currentStyle;\n\n if (_) {\n i = l, l = -h, h = -i, e = _.filter, f.filter = \"\";\n var p,\n d,\n m = this.t.offsetWidth,\n g = this.t.offsetHeight,\n v = \"absolute\" !== _.position,\n w = \"progid:DXImageTransform.Microsoft.Matrix(M11=\" + o + \", M12=\" + l + \", M21=\" + h + \", M22=\" + u,\n x = r.x,\n b = r.y;\n\n if (null != r.ox && (p = (r.oxp ? .01 * m * r.ox : r.ox) - m / 2, d = (r.oyp ? .01 * g * r.oy : r.oy) - g / 2, x += p - (p * o + d * l), b += d - (p * h + d * u)), v ? (p = m / 2, d = g / 2, w += \", Dx=\" + (p - (p * o + d * l) + x) + \", Dy=\" + (d - (p * h + d * u) + b) + \")\") : w += \", sizingMethod='auto expand')\", f.filter = -1 !== e.indexOf(\"DXImageTransform.Microsoft.Matrix(\") ? e.replace(O, w) : w + \" \" + e, (0 === t || 1 === t) && 1 === o && 0 === l && 0 === h && 1 === u && (v && -1 === w.indexOf(\"Dx=0, Dy=0\") || T.test(e) && 100 !== parseFloat(RegExp.$1) || -1 === e.indexOf(\"gradient(\" && e.indexOf(\"Alpha\")) && f.removeAttribute(\"filter\")), !v) {\n var P,\n S,\n C,\n R = 8 > c ? 1 : -1;\n\n for (p = r.ieOffsetX || 0, d = r.ieOffsetY || 0, r.ieOffsetX = Math.round((m - ((0 > o ? -o : o) * m + (0 > l ? -l : l) * g)) / 2 + x), r.ieOffsetY = Math.round((g - ((0 > u ? -u : u) * g + (0 > h ? -h : h) * m)) / 2 + b), ce = 0; 4 > ce; ce++) S = J[ce], P = _[S], i = -1 !== P.indexOf(\"px\") ? parseFloat(P) : Q(this.t, S, parseFloat(P), P.replace(y, \"\")) || 0, C = i !== r[S] ? 2 > ce ? -r.ieOffsetX : -r.ieOffsetY : 2 > ce ? p - r.ieOffsetX : d - r.ieOffsetY, f[S] = (r[S] = Math.round(i - C * (0 === ce || 2 === ce ? 1 : R))) + \"px\";\n }\n }\n },\n Ce = E.set3DTransformRatio = function (t) {\n var e,\n i,\n r,\n s,\n n,\n a,\n o,\n l,\n h,\n u,\n f,\n p,\n c,\n d,\n m,\n g,\n v,\n y,\n T,\n w,\n x,\n b,\n P,\n S = this.data,\n C = this.t.style,\n R = S.rotation * M,\n k = S.scaleX,\n A = S.scaleY,\n O = S.scaleZ,\n D = S.perspective;\n if (!(1 !== t && 0 !== t || \"auto\" !== S.force3D || S.rotationY || S.rotationX || 1 !== O || D || S.z)) return Re.call(this, t), void 0;\n\n if (_) {\n var L = 1e-4;\n L > k && k > -L && (k = O = 2e-5), L > A && A > -L && (A = O = 2e-5), !D || S.z || S.rotationX || S.rotationY || (D = 0);\n }\n\n if (R || S.skewX) y = Math.cos(R), T = Math.sin(R), e = y, n = T, S.skewX && (R -= S.skewX * M, y = Math.cos(R), T = Math.sin(R), \"simple\" === S.skewType && (w = Math.tan(S.skewX * M), w = Math.sqrt(1 + w * w), y *= w, T *= w)), i = -T, a = y;else {\n if (!(S.rotationY || S.rotationX || 1 !== O || D)) return C[ye] = \"translate3d(\" + S.x + \"px,\" + S.y + \"px,\" + S.z + \"px)\" + (1 !== k || 1 !== A ? \" scale(\" + k + \",\" + A + \")\" : \"\"), void 0;\n e = a = 1, i = n = 0;\n }\n f = 1, r = s = o = l = h = u = p = c = d = 0, m = D ? -1 / D : 0, g = S.zOrigin, v = 1e5, R = S.rotationY * M, R && (y = Math.cos(R), T = Math.sin(R), h = f * -T, c = m * -T, r = e * T, o = n * T, f *= y, m *= y, e *= y, n *= y), R = S.rotationX * M, R && (y = Math.cos(R), T = Math.sin(R), w = i * y + r * T, x = a * y + o * T, b = u * y + f * T, P = d * y + m * T, r = i * -T + r * y, o = a * -T + o * y, f = u * -T + f * y, m = d * -T + m * y, i = w, a = x, u = b, d = P), 1 !== O && (r *= O, o *= O, f *= O, m *= O), 1 !== A && (i *= A, a *= A, u *= A, d *= A), 1 !== k && (e *= k, n *= k, h *= k, c *= k), g && (p -= g, s = r * p, l = o * p, p = f * p + g), s = (w = (s += S.x) - (s |= 0)) ? (0 | w * v + (0 > w ? -.5 : .5)) / v + s : s, l = (w = (l += S.y) - (l |= 0)) ? (0 | w * v + (0 > w ? -.5 : .5)) / v + l : l, p = (w = (p += S.z) - (p |= 0)) ? (0 | w * v + (0 > w ? -.5 : .5)) / v + p : p, C[ye] = \"matrix3d(\" + [(0 | e * v) / v, (0 | n * v) / v, (0 | h * v) / v, (0 | c * v) / v, (0 | i * v) / v, (0 | a * v) / v, (0 | u * v) / v, (0 | d * v) / v, (0 | r * v) / v, (0 | o * v) / v, (0 | f * v) / v, (0 | m * v) / v, s, l, p, D ? 1 + -p / D : 1].join(\",\") + \")\";\n },\n Re = E.set2DTransformRatio = function (t) {\n var e,\n i,\n r,\n s,\n n,\n a = this.data,\n o = this.t,\n l = o.style;\n return a.rotationX || a.rotationY || a.z || a.force3D === !0 || \"auto\" === a.force3D && 1 !== t && 0 !== t ? (this.setRatio = Ce, Ce.call(this, t), void 0) : (a.rotation || a.skewX ? (e = a.rotation * M, i = e - a.skewX * M, r = 1e5, s = a.scaleX * r, n = a.scaleY * r, l[ye] = \"matrix(\" + (0 | Math.cos(e) * s) / r + \",\" + (0 | Math.sin(e) * s) / r + \",\" + (0 | Math.sin(i) * -n) / r + \",\" + (0 | Math.cos(i) * n) / r + \",\" + a.x + \",\" + a.y + \")\") : l[ye] = \"matrix(\" + a.scaleX + \",0,0,\" + a.scaleY + \",\" + a.x + \",\" + a.y + \")\", void 0);\n };\n\n me(\"transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType\", {\n parser: function (t, e, i, r, n, o, l) {\n if (r._transform) return n;\n\n var h,\n u,\n f,\n _,\n p,\n c,\n d,\n m = r._transform = Pe(t, s, !0, l.parseTransform),\n g = t.style,\n v = 1e-6,\n y = ve.length,\n T = l,\n w = {};\n\n if (\"string\" == typeof T.transform && ye) f = z.style, f[ye] = T.transform, f.display = \"block\", f.position = \"absolute\", X.body.appendChild(z), h = Pe(z, null, !1), X.body.removeChild(z);else if (\"object\" == typeof T) {\n if (h = {\n scaleX: re(null != T.scaleX ? T.scaleX : T.scale, m.scaleX),\n scaleY: re(null != T.scaleY ? T.scaleY : T.scale, m.scaleY),\n scaleZ: re(T.scaleZ, m.scaleZ),\n x: re(T.x, m.x),\n y: re(T.y, m.y),\n z: re(T.z, m.z),\n perspective: re(T.transformPerspective, m.perspective)\n }, d = T.directionalRotation, null != d) if (\"object\" == typeof d) for (f in d) T[f] = d[f];else T.rotation = d;\n h.rotation = se(\"rotation\" in T ? T.rotation : \"shortRotation\" in T ? T.shortRotation + \"_short\" : \"rotationZ\" in T ? T.rotationZ : m.rotation, m.rotation, \"rotation\", w), xe && (h.rotationX = se(\"rotationX\" in T ? T.rotationX : \"shortRotationX\" in T ? T.shortRotationX + \"_short\" : m.rotationX || 0, m.rotationX, \"rotationX\", w), h.rotationY = se(\"rotationY\" in T ? T.rotationY : \"shortRotationY\" in T ? T.shortRotationY + \"_short\" : m.rotationY || 0, m.rotationY, \"rotationY\", w)), h.skewX = null == T.skewX ? m.skewX : se(T.skewX, m.skewX), h.skewY = null == T.skewY ? m.skewY : se(T.skewY, m.skewY), (u = h.skewY - m.skewY) && (h.skewX += u, h.rotation += u);\n }\n\n for (xe && null != T.force3D && (m.force3D = T.force3D, c = !0), m.skewType = T.skewType || m.skewType || a.defaultSkewType, p = m.force3D || m.z || m.rotationX || m.rotationY || h.z || h.rotationX || h.rotationY || h.perspective, p || null == T.scale || (h.scaleZ = 1); --y > -1;) i = ve[y], _ = h[i] - m[i], (_ > v || -v > _ || null != N[i]) && (c = !0, n = new _e(m, i, m[i], _, n), i in w && (n.e = w[i]), n.xs0 = 0, n.plugin = o, r._overwriteProps.push(n.n));\n\n return _ = T.transformOrigin, (_ || xe && p && m.zOrigin) && (ye ? (c = !0, i = we, _ = (_ || q(t, i, s, !1, \"50% 50%\")) + \"\", n = new _e(g, i, 0, 0, n, -1, \"transformOrigin\"), n.b = g[i], n.plugin = o, xe ? (f = m.zOrigin, _ = _.split(\" \"), m.zOrigin = (_.length > 2 && (0 === f || \"0px\" !== _[2]) ? parseFloat(_[2]) : f) || 0, n.xs0 = n.e = _[0] + \" \" + (_[1] || \"50%\") + \" 0px\", n = new _e(m, \"zOrigin\", 0, 0, n, -1, n.n), n.b = f, n.xs0 = n.e = m.zOrigin) : n.xs0 = n.e = _) : ee(_ + \"\", m)), c && (r._transformType = p || 3 === this._transformType ? 3 : 2), n;\n },\n prefix: !0\n }), me(\"boxShadow\", {\n defaultValue: \"0px 0px 0px 0px #999\",\n prefix: !0,\n color: !0,\n multi: !0,\n keyword: \"inset\"\n }), me(\"borderRadius\", {\n defaultValue: \"0px\",\n parser: function (t, e, i, n, a) {\n e = this.format(e);\n\n var o,\n l,\n h,\n u,\n f,\n _,\n p,\n c,\n d,\n m,\n g,\n v,\n y,\n T,\n w,\n x,\n b = [\"borderTopLeftRadius\", \"borderTopRightRadius\", \"borderBottomRightRadius\", \"borderBottomLeftRadius\"],\n P = t.style;\n\n for (d = parseFloat(t.offsetWidth), m = parseFloat(t.offsetHeight), o = e.split(\" \"), l = 0; b.length > l; l++) this.p.indexOf(\"border\") && (b[l] = V(b[l])), f = u = q(t, b[l], s, !1, \"0px\"), -1 !== f.indexOf(\" \") && (u = f.split(\" \"), f = u[0], u = u[1]), _ = h = o[l], p = parseFloat(f), v = f.substr((p + \"\").length), y = \"=\" === _.charAt(1), y ? (c = parseInt(_.charAt(0) + \"1\", 10), _ = _.substr(2), c *= parseFloat(_), g = _.substr((c + \"\").length - (0 > c ? 1 : 0)) || \"\") : (c = parseFloat(_), g = _.substr((c + \"\").length)), \"\" === g && (g = r[i] || v), g !== v && (T = Q(t, \"borderLeft\", p, v), w = Q(t, \"borderTop\", p, v), \"%\" === g ? (f = 100 * (T / d) + \"%\", u = 100 * (w / m) + \"%\") : \"em\" === g ? (x = Q(t, \"borderLeft\", 1, \"em\"), f = T / x + \"em\", u = w / x + \"em\") : (f = T + \"px\", u = w + \"px\"), y && (_ = parseFloat(f) + c + g, h = parseFloat(u) + c + g)), a = pe(P, b[l], f + \" \" + u, _ + \" \" + h, !1, \"0px\", a);\n\n return a;\n },\n prefix: !0,\n formatter: he(\"0px 0px 0px 0px\", !1, !0)\n }), me(\"backgroundPosition\", {\n defaultValue: \"0 0\",\n parser: function (t, e, i, r, n, a) {\n var o,\n l,\n h,\n u,\n f,\n _,\n p = \"background-position\",\n d = s || H(t, null),\n m = this.format((d ? c ? d.getPropertyValue(p + \"-x\") + \" \" + d.getPropertyValue(p + \"-y\") : d.getPropertyValue(p) : t.currentStyle.backgroundPositionX + \" \" + t.currentStyle.backgroundPositionY) || \"0 0\"),\n g = this.format(e);\n\n if (-1 !== m.indexOf(\"%\") != (-1 !== g.indexOf(\"%\")) && (_ = q(t, \"backgroundImage\").replace(C, \"\"), _ && \"none\" !== _)) {\n for (o = m.split(\" \"), l = g.split(\" \"), I.setAttribute(\"src\", _), h = 2; --h > -1;) m = o[h], u = -1 !== m.indexOf(\"%\"), u !== (-1 !== l[h].indexOf(\"%\")) && (f = 0 === h ? t.offsetWidth - I.width : t.offsetHeight - I.height, o[h] = u ? parseFloat(m) / 100 * f + \"px\" : 100 * (parseFloat(m) / f) + \"%\");\n\n m = o.join(\" \");\n }\n\n return this.parseComplex(t.style, m, g, n, a);\n },\n formatter: ee\n }), me(\"backgroundSize\", {\n defaultValue: \"0 0\",\n formatter: ee\n }), me(\"perspective\", {\n defaultValue: \"0px\",\n prefix: !0\n }), me(\"perspectiveOrigin\", {\n defaultValue: \"50% 50%\",\n prefix: !0\n }), me(\"transformStyle\", {\n prefix: !0\n }), me(\"backfaceVisibility\", {\n prefix: !0\n }), me(\"userSelect\", {\n prefix: !0\n }), me(\"margin\", {\n parser: ue(\"marginTop,marginRight,marginBottom,marginLeft\")\n }), me(\"padding\", {\n parser: ue(\"paddingTop,paddingRight,paddingBottom,paddingLeft\")\n }), me(\"clip\", {\n defaultValue: \"rect(0px,0px,0px,0px)\",\n parser: function (t, e, i, r, n, a) {\n var o, l, h;\n return 9 > c ? (l = t.currentStyle, h = 8 > c ? \" \" : \",\", o = \"rect(\" + l.clipTop + h + l.clipRight + h + l.clipBottom + h + l.clipLeft + \")\", e = this.format(e).split(\",\").join(h)) : (o = this.format(q(t, this.p, s, !1, this.dflt)), e = this.format(e)), this.parseComplex(t.style, o, e, n, a);\n }\n }), me(\"textShadow\", {\n defaultValue: \"0px 0px 0px #999\",\n color: !0,\n multi: !0\n }), me(\"autoRound,strictUnits\", {\n parser: function (t, e, i, r, s) {\n return s;\n }\n }), me(\"border\", {\n defaultValue: \"0px solid #000\",\n parser: function (t, e, i, r, n, a) {\n return this.parseComplex(t.style, this.format(q(t, \"borderTopWidth\", s, !1, \"0px\") + \" \" + q(t, \"borderTopStyle\", s, !1, \"solid\") + \" \" + q(t, \"borderTopColor\", s, !1, \"#000\")), this.format(e), n, a);\n },\n color: !0,\n formatter: function (t) {\n var e = t.split(\" \");\n return e[0] + \" \" + (e[1] || \"solid\") + \" \" + (t.match(le) || [\"#000\"])[0];\n }\n }), me(\"borderWidth\", {\n parser: ue(\"borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth\")\n }), me(\"float,cssFloat,styleFloat\", {\n parser: function (t, e, i, r, s) {\n var n = t.style,\n a = \"cssFloat\" in n ? \"cssFloat\" : \"styleFloat\";\n return new _e(n, a, 0, 0, s, -1, i, !1, 0, n[a], e);\n }\n });\n\n var ke = function (t) {\n var e,\n i = this.t,\n r = i.filter || q(this.data, \"filter\"),\n s = 0 | this.s + this.c * t;\n 100 === s && (-1 === r.indexOf(\"atrix(\") && -1 === r.indexOf(\"radient(\") && -1 === r.indexOf(\"oader(\") ? (i.removeAttribute(\"filter\"), e = !q(this.data, \"filter\")) : (i.filter = r.replace(x, \"\"), e = !0)), e || (this.xn1 && (i.filter = r = r || \"alpha(opacity=\" + s + \")\"), -1 === r.indexOf(\"pacity\") ? 0 === s && this.xn1 || (i.filter = r + \" alpha(opacity=\" + s + \")\") : i.filter = r.replace(T, \"opacity=\" + s));\n };\n\n me(\"opacity,alpha,autoAlpha\", {\n defaultValue: \"1\",\n parser: function (t, e, i, r, n, a) {\n var o = parseFloat(q(t, \"opacity\", s, !1, \"1\")),\n l = t.style,\n h = \"autoAlpha\" === i;\n return \"string\" == typeof e && \"=\" === e.charAt(1) && (e = (\"-\" === e.charAt(0) ? -1 : 1) * parseFloat(e.substr(2)) + o), h && 1 === o && \"hidden\" === q(t, \"visibility\", s) && 0 !== e && (o = 0), Y ? n = new _e(l, \"opacity\", o, e - o, n) : (n = new _e(l, \"opacity\", 100 * o, 100 * (e - o), n), n.xn1 = h ? 1 : 0, l.zoom = 1, n.type = 2, n.b = \"alpha(opacity=\" + n.s + \")\", n.e = \"alpha(opacity=\" + (n.s + n.c) + \")\", n.data = t, n.plugin = a, n.setRatio = ke), h && (n = new _e(l, \"visibility\", 0, 0, n, -1, null, !1, 0, 0 !== o ? \"inherit\" : \"hidden\", 0 === e ? \"hidden\" : \"inherit\"), n.xs0 = \"inherit\", r._overwriteProps.push(n.n), r._overwriteProps.push(i)), n;\n }\n });\n\n var Ae = function (t, e) {\n e && (t.removeProperty ? (\"ms\" === e.substr(0, 2) && (e = \"M\" + e.substr(1)), t.removeProperty(e.replace(P, \"-$1\").toLowerCase())) : t.removeAttribute(e));\n },\n Oe = function (t) {\n if (this.t._gsClassPT = this, 1 === t || 0 === t) {\n this.t.setAttribute(\"class\", 0 === t ? this.b : this.e);\n\n for (var e = this.data, i = this.t.style; e;) e.v ? i[e.p] = e.v : Ae(i, e.p), e = e._next;\n\n 1 === t && this.t._gsClassPT === this && (this.t._gsClassPT = null);\n } else this.t.getAttribute(\"class\") !== this.e && this.t.setAttribute(\"class\", this.e);\n };\n\n me(\"className\", {\n parser: function (t, e, r, n, a, o, l) {\n var h,\n u,\n f,\n _,\n p,\n c = t.getAttribute(\"class\") || \"\",\n d = t.style.cssText;\n\n if (a = n._classNamePT = new _e(t, r, 0, 0, a, 2), a.setRatio = Oe, a.pr = -11, i = !0, a.b = c, u = $(t, s), f = t._gsClassPT) {\n for (_ = {}, p = f.data; p;) _[p.p] = 1, p = p._next;\n\n f.setRatio(1);\n }\n\n return t._gsClassPT = a, a.e = \"=\" !== e.charAt(1) ? e : c.replace(RegExp(\"\\\\s*\\\\b\" + e.substr(2) + \"\\\\b\"), \"\") + (\"+\" === e.charAt(0) ? \" \" + e.substr(2) : \"\"), n._tween._duration && (t.setAttribute(\"class\", a.e), h = G(t, u, $(t), l, _), t.setAttribute(\"class\", c), a.data = h.firstMPT, t.style.cssText = d, a = a.xfirst = n.parse(t, h.difs, a, o)), a;\n }\n });\n\n var De = function (t) {\n if ((1 === t || 0 === t) && this.data._totalTime === this.data._totalDuration && \"isFromStart\" !== this.data.data) {\n var e,\n i,\n r,\n s,\n n = this.t.style,\n a = o.transform.parse;\n if (\"all\" === this.e) n.cssText = \"\", s = !0;else for (e = this.e.split(\",\"), r = e.length; --r > -1;) i = e[r], o[i] && (o[i].parse === a ? s = !0 : i = \"transformOrigin\" === i ? we : o[i].p), Ae(n, i);\n s && (Ae(n, ye), this.t._gsTransform && delete this.t._gsTransform);\n }\n };\n\n for (me(\"clearProps\", {\n parser: function (t, e, r, s, n) {\n return n = new _e(t, r, 0, 0, n, 2), n.setRatio = De, n.e = e, n.pr = -10, n.data = s._tween, i = !0, n;\n }\n }), l = \"bezier,throwProps,physicsProps,physics2D\".split(\",\"), ce = l.length; ce--;) ge(l[ce]);\n\n l = a.prototype, l._firstPT = null, l._onInitTween = function (t, e, o) {\n if (!t.nodeType) return !1;\n this._target = t, this._tween = o, this._vars = e, h = e.autoRound, i = !1, r = e.suffixMap || a.suffixMap, s = H(t, \"\"), n = this._overwriteProps;\n\n var l,\n _,\n c,\n d,\n m,\n g,\n v,\n y,\n T,\n x = t.style;\n\n if (u && \"\" === x.zIndex && (l = q(t, \"zIndex\", s), (\"auto\" === l || \"\" === l) && this._addLazySet(x, \"zIndex\", 0)), \"string\" == typeof e && (d = x.cssText, l = $(t, s), x.cssText = d + \";\" + e, l = G(t, l, $(t)).difs, !Y && w.test(e) && (l.opacity = parseFloat(RegExp.$1)), e = l, x.cssText = d), this._firstPT = _ = this.parse(t, e, null), this._transformType) {\n for (T = 3 === this._transformType, ye ? f && (u = !0, \"\" === x.zIndex && (v = q(t, \"zIndex\", s), (\"auto\" === v || \"\" === v) && this._addLazySet(x, \"zIndex\", 0)), p && this._addLazySet(x, \"WebkitBackfaceVisibility\", this._vars.WebkitBackfaceVisibility || (T ? \"visible\" : \"hidden\"))) : x.zoom = 1, c = _; c && c._next;) c = c._next;\n\n y = new _e(t, \"transform\", 0, 0, null, 2), this._linkCSSP(y, null, c), y.setRatio = T && xe ? Ce : ye ? Re : Se, y.data = this._transform || Pe(t, s, !0), n.pop();\n }\n\n if (i) {\n for (; _;) {\n for (g = _._next, c = d; c && c.pr > _.pr;) c = c._next;\n\n (_._prev = c ? c._prev : m) ? _._prev._next = _ : d = _, (_._next = c) ? c._prev = _ : m = _, _ = g;\n }\n\n this._firstPT = d;\n }\n\n return !0;\n }, l.parse = function (t, e, i, n) {\n var a,\n l,\n u,\n f,\n _,\n p,\n c,\n d,\n m,\n g,\n v = t.style;\n\n for (a in e) p = e[a], l = o[a], l ? i = l.parse(t, p, a, this, i, n, e) : (_ = q(t, a, s) + \"\", m = \"string\" == typeof p, \"color\" === a || \"fill\" === a || \"stroke\" === a || -1 !== a.indexOf(\"Color\") || m && b.test(p) ? (m || (p = oe(p), p = (p.length > 3 ? \"rgba(\" : \"rgb(\") + p.join(\",\") + \")\"), i = pe(v, a, _, p, !0, \"transparent\", i, 0, n)) : !m || -1 === p.indexOf(\" \") && -1 === p.indexOf(\",\") ? (u = parseFloat(_), c = u || 0 === u ? _.substr((u + \"\").length) : \"\", (\"\" === _ || \"auto\" === _) && (\"width\" === a || \"height\" === a ? (u = te(t, a, s), c = \"px\") : \"left\" === a || \"top\" === a ? (u = Z(t, a, s), c = \"px\") : (u = \"opacity\" !== a ? 0 : 1, c = \"\")), g = m && \"=\" === p.charAt(1), g ? (f = parseInt(p.charAt(0) + \"1\", 10), p = p.substr(2), f *= parseFloat(p), d = p.replace(y, \"\")) : (f = parseFloat(p), d = m ? p.substr((f + \"\").length) || \"\" : \"\"), \"\" === d && (d = a in r ? r[a] : c), p = f || 0 === f ? (g ? f + u : f) + d : e[a], c !== d && \"\" !== d && (f || 0 === f) && u && (u = Q(t, a, u, c), \"%\" === d ? (u /= Q(t, a, 100, \"%\") / 100, e.strictUnits !== !0 && (_ = u + \"%\")) : \"em\" === d ? u /= Q(t, a, 1, \"em\") : \"px\" !== d && (f = Q(t, a, f, d), d = \"px\"), g && (f || 0 === f) && (p = f + u + d)), g && (f += u), !u && 0 !== u || !f && 0 !== f ? void 0 !== v[a] && (p || \"NaN\" != p + \"\" && null != p) ? (i = new _e(v, a, f || u || 0, 0, i, -1, a, !1, 0, _, p), i.xs0 = \"none\" !== p || \"display\" !== a && -1 === a.indexOf(\"Style\") ? p : _) : U(\"invalid \" + a + \" tween value: \" + e[a]) : (i = new _e(v, a, u, f - u, i, 0, a, h !== !1 && (\"px\" === d || \"zIndex\" === a), 0, _, p), i.xs0 = d)) : i = pe(v, a, _, p, !0, null, i, 0, n)), n && i && !i.plugin && (i.plugin = n);\n\n return i;\n }, l.setRatio = function (t) {\n var e,\n i,\n r,\n s = this._firstPT,\n n = 1e-6;\n if (1 !== t || this._tween._time !== this._tween._duration && 0 !== this._tween._time) {\n if (t || this._tween._time !== this._tween._duration && 0 !== this._tween._time || this._tween._rawPrevTime === -1e-6) for (; s;) {\n if (e = s.c * t + s.s, s.r ? e = Math.round(e) : n > e && e > -n && (e = 0), s.type) {\n if (1 === s.type) {\n if (r = s.l, 2 === r) s.t[s.p] = s.xs0 + e + s.xs1 + s.xn1 + s.xs2;else if (3 === r) s.t[s.p] = s.xs0 + e + s.xs1 + s.xn1 + s.xs2 + s.xn2 + s.xs3;else if (4 === r) s.t[s.p] = s.xs0 + e + s.xs1 + s.xn1 + s.xs2 + s.xn2 + s.xs3 + s.xn3 + s.xs4;else if (5 === r) s.t[s.p] = s.xs0 + e + s.xs1 + s.xn1 + s.xs2 + s.xn2 + s.xs3 + s.xn3 + s.xs4 + s.xn4 + s.xs5;else {\n for (i = s.xs0 + e + s.xs1, r = 1; s.l > r; r++) i += s[\"xn\" + r] + s[\"xs\" + (r + 1)];\n\n s.t[s.p] = i;\n }\n } else -1 === s.type ? s.t[s.p] = s.xs0 : s.setRatio && s.setRatio(t);\n } else s.t[s.p] = e + s.xs0;\n s = s._next;\n } else for (; s;) 2 !== s.type ? s.t[s.p] = s.b : s.setRatio(t), s = s._next;\n } else for (; s;) 2 !== s.type ? s.t[s.p] = s.e : s.setRatio(t), s = s._next;\n }, l._enableTransforms = function (t) {\n this._transformType = t || 3 === this._transformType ? 3 : 2, this._transform = this._transform || Pe(this._target, s, !0);\n };\n\n var Me = function () {\n this.t[this.p] = this.e, this.data._linkCSSP(this, this._next, null, !0);\n };\n\n l._addLazySet = function (t, e, i) {\n var r = this._firstPT = new _e(t, e, 0, 0, this._firstPT, 2);\n r.e = i, r.setRatio = Me, r.data = this;\n }, l._linkCSSP = function (t, e, i, r) {\n return t && (e && (e._prev = t), t._next && (t._next._prev = t._prev), t._prev ? t._prev._next = t._next : this._firstPT === t && (this._firstPT = t._next, r = !0), i ? i._next = t : r || null !== this._firstPT || (this._firstPT = t), t._next = e, t._prev = i), t;\n }, l._kill = function (e) {\n var i,\n r,\n s,\n n = e;\n\n if (e.autoAlpha || e.alpha) {\n n = {};\n\n for (r in e) n[r] = e[r];\n\n n.opacity = 1, n.autoAlpha && (n.visibility = 1);\n }\n\n return e.className && (i = this._classNamePT) && (s = i.xfirst, s && s._prev ? this._linkCSSP(s._prev, i._next, s._prev._prev) : s === this._firstPT && (this._firstPT = i._next), i._next && this._linkCSSP(i._next, i._next._next, s._prev), this._classNamePT = null), t.prototype._kill.call(this, n);\n };\n\n var Le = function (t, e, i) {\n var r, s, n, a;\n if (t.slice) for (s = t.length; --s > -1;) Le(t[s], e, i);else for (r = t.childNodes, s = r.length; --s > -1;) n = r[s], a = n.type, n.style && (e.push($(n)), i && i.push(n)), 1 !== a && 9 !== a && 11 !== a || !n.childNodes.length || Le(n, e, i);\n };\n\n return a.cascadeTo = function (t, i, r) {\n var s,\n n,\n a,\n o = e.to(t, i, r),\n l = [o],\n h = [],\n u = [],\n f = [],\n _ = e._internals.reservedProps;\n\n for (t = o._targets || o.target, Le(t, h, f), o.render(i, !0), Le(t, u), o.render(0, !0), o._enabled(!0), s = f.length; --s > -1;) if (n = G(f[s], h[s], u[s]), n.firstMPT) {\n n = n.difs;\n\n for (a in r) _[a] && (n[a] = r[a]);\n\n l.push(e.to(f[s], i, n));\n }\n\n return l;\n }, t.activate([a]), a;\n }, !0);\n}), window._gsDefine && window._gsQueue.pop()();\n\n},{}],13:[function(require,module,exports){\n\"use strict\";\n\n/*!\r\n * VERSION: 1.7.3\r\n * DATE: 2014-01-14\r\n * UPDATES AND DOCS AT: http://www.greensock.com\r\n *\r\n * @license Copyright (c) 2008-2014, GreenSock. All rights reserved.\r\n * This work is subject to the terms at http://www.greensock.com/terms_of_use.html or for\r\n * Club GreenSock members, the software agreement that was issued with your membership.\r\n * \r\n * @author: Jack Doyle, jack@greensock.com\r\n **/\n(window._gsQueue || (window._gsQueue = [])).push(function () {\n \"use strict\";\n\n var t = document.documentElement,\n e = window,\n i = function (i, s) {\n var r = \"x\" === s ? \"Width\" : \"Height\",\n n = \"scroll\" + r,\n a = \"client\" + r,\n o = document.body;\n return i === e || i === t || i === o ? Math.max(t[n], o[n]) - (e[\"inner\" + r] || Math.max(t[a], o[a])) : i[n] - i[\"offset\" + r];\n },\n s = window._gsDefine.plugin({\n propName: \"scrollTo\",\n API: 2,\n version: \"1.7.3\",\n init: function (t, s, r) {\n return this._wdw = t === e, this._target = t, this._tween = r, \"object\" != typeof s && (s = {\n y: s\n }), this._autoKill = s.autoKill !== !1, this.x = this.xPrev = this.getX(), this.y = this.yPrev = this.getY(), null != s.x ? (this._addTween(this, \"x\", this.x, \"max\" === s.x ? i(t, \"x\") : s.x, \"scrollTo_x\", !0), this._overwriteProps.push(\"scrollTo_x\")) : this.skipX = !0, null != s.y ? (this._addTween(this, \"y\", this.y, \"max\" === s.y ? i(t, \"y\") : s.y, \"scrollTo_y\", !0), this._overwriteProps.push(\"scrollTo_y\")) : this.skipY = !0, !0;\n },\n set: function (t) {\n this._super.setRatio.call(this, t);\n\n var s = this._wdw || !this.skipX ? this.getX() : this.xPrev,\n r = this._wdw || !this.skipY ? this.getY() : this.yPrev,\n n = r - this.yPrev,\n a = s - this.xPrev;\n this._autoKill && (!this.skipX && (a > 7 || -7 > a) && i(this._target, \"x\") > s && (this.skipX = !0), !this.skipY && (n > 7 || -7 > n) && i(this._target, \"y\") > r && (this.skipY = !0), this.skipX && this.skipY && this._tween.kill()), this._wdw ? e.scrollTo(this.skipX ? s : this.x, this.skipY ? r : this.y) : (this.skipY || (this._target.scrollTop = this.y), this.skipX || (this._target.scrollLeft = this.x)), this.xPrev = this.x, this.yPrev = this.y;\n }\n }),\n r = s.prototype;\n\n s.max = i, r.getX = function () {\n return this._wdw ? null != e.pageXOffset ? e.pageXOffset : null != t.scrollLeft ? t.scrollLeft : document.body.scrollLeft : this._target.scrollLeft;\n }, r.getY = function () {\n return this._wdw ? null != e.pageYOffset ? e.pageYOffset : null != t.scrollTop ? t.scrollTop : document.body.scrollTop : this._target.scrollTop;\n }, r._kill = function (t) {\n return t.scrollTo_x && (this.skipX = !0), t.scrollTo_y && (this.skipY = !0), this._super._kill.call(this, t);\n };\n}), window._gsDefine && window._gsQueue.pop()();\n\n},{}]},{},[2])\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvanMvZ2xvYmFsL2FqYXguanMiLCJzcmMvanMvZ2xvYmFsL2FwcC5qcyIsInNyYy9qcy9nbG9iYWwvYmVhY29uLmpzIiwic3JjL2pzL2dsb2JhbC9jb3VudGRvd24uanMiLCJzcmMvanMvZ2xvYmFsL2ZpZWxkcy5qcyIsInNyYy9qcy9nbG9iYWwvbWFpbi5qcyIsInNyYy9qcy9nbG9iYWwvcGFnZU1hbmFnZXIuanMiLCJzcmMvanMvZ2xvYmFsL3JvY2tldGNkbi5qcyIsInNyYy9qcy9saWIvZ3JlZW5zb2NrL1RpbWVsaW5lTGl0ZS5taW4uanMiLCJzcmMvanMvbGliL2dyZWVuc29jay9Ud2VlbkxpdGUubWluLmpzIiwic3JjL2pzL2xpYi9ncmVlbnNvY2svZWFzaW5nL0Vhc2VQYWNrLm1pbi5qcyIsInNyYy9qcy9saWIvZ3JlZW5zb2NrL3BsdWdpbnMvQ1NTUGx1Z2luLm1pbi5qcyIsInNyYy9qcy9saWIvZ3JlZW5zb2NrL3BsdWdpbnMvU2Nyb2xsVG9QbHVnaW4ubWluLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7QUNBQSxJQUFJLENBQUMsR0FBRyxNQUFSO0FBQ0EsQ0FBQyxDQUFDLFFBQUQsQ0FBRCxDQUFZLEtBQVosQ0FBa0IsWUFBVTtBQUN4QjtBQUNKO0FBQ0E7QUFDSSxNQUFJLGFBQWEsR0FBRyxLQUFwQjtBQUNBLEVBQUEsQ0FBQyxDQUFDLDZCQUFELENBQUQsQ0FBaUMsRUFBakMsQ0FBb0MsT0FBcEMsRUFBNkMsVUFBUyxDQUFULEVBQVk7QUFDckQsUUFBRyxDQUFDLGFBQUosRUFBa0I7QUFDZCxVQUFJLE1BQU0sR0FBRyxDQUFDLENBQUMsSUFBRCxDQUFkO0FBQ0EsVUFBSSxPQUFPLEdBQUcsQ0FBQyxDQUFDLG1CQUFELENBQWY7QUFDQSxVQUFJLE1BQU0sR0FBRyxDQUFDLENBQUMsc0JBQUQsQ0FBZDtBQUVBLE1BQUEsQ0FBQyxDQUFDLGNBQUY7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Q0FBQyxDQUFDLFdBQVIsR0FBb0IsQ0FBQyxDQUFDLFdBQXRCLEdBQWtDLFFBQU0sQ0FBQyxDQUFDLFNBQVIsR0FBa0IsQ0FBQyxDQUFDLFNBQXBCLEdBQThCLFFBQVEsQ0FBQyxJQUFULENBQWMsU0FBeEYsR0FBa0csS0FBSyxPQUFMLENBQWEsU0FBdEg7QUFBZ0ksR0FBalQsRUFBa1QsQ0FBQyxDQUFDLEtBQUYsR0FBUSxVQUFTLENBQVQsRUFBVztBQUFDLFdBQU8sQ0FBQyxDQUFDLFVBQUYsS0FBZSxLQUFLLEtBQUwsR0FBVyxDQUFDLENBQTNCLEdBQThCLENBQUMsQ0FBQyxVQUFGLEtBQWUsS0FBSyxLQUFMLEdBQVcsQ0FBQyxDQUEzQixDQUE5QixFQUE0RCxLQUFLLE1BQUwsQ0FBWSxLQUFaLENBQWtCLElBQWxCLENBQXVCLElBQXZCLEVBQTRCLENBQTVCLENBQW5FO0FBQWtHLEdBQXhhO0FBQXlhLENBQXh6RCxHQUEwekQsTUFBTSxDQUFDLFNBQVAsSUFBa0IsTUFBTSxDQUFDLFFBQVAsQ0FBZ0IsR0FBaEIsSUFBNTBEIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24oKXtmdW5jdGlvbiByKGUsbix0KXtmdW5jdGlvbiBvKGksZil7aWYoIW5baV0pe2lmKCFlW2ldKXt2YXIgYz1cImZ1bmN0aW9uXCI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlO2lmKCFmJiZjKXJldHVybiBjKGksITApO2lmKHUpcmV0dXJuIHUoaSwhMCk7dmFyIGE9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitpK1wiJ1wiKTt0aHJvdyBhLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsYX12YXIgcD1uW2ldPXtleHBvcnRzOnt9fTtlW2ldWzBdLmNhbGwocC5leHBvcnRzLGZ1bmN0aW9uKHIpe3ZhciBuPWVbaV1bMV1bcl07cmV0dXJuIG8obnx8cil9LHAscC5leHBvcnRzLHIsZSxuLHQpfXJldHVybiBuW2ldLmV4cG9ydHN9Zm9yKHZhciB1PVwiZnVuY3Rpb25cIj09dHlwZW9mIHJlcXVpcmUmJnJlcXVpcmUsaT0wO2k8dC5sZW5ndGg7aSsrKW8odFtpXSk7cmV0dXJuIG99cmV0dXJuIHJ9KSgpIiwidmFyICQgPSBqUXVlcnk7XG4kKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpe1xuICAgIC8qKlxuICAgICAqIFJlZnJlc2ggTGljZW5zZSBkYXRhXG4gICAgICovXG4gICAgdmFyIF9pc1JlZnJlc2hpbmcgPSBmYWxzZTtcbiAgICAkKCcjd3ByLWFjdGlvbi1yZWZyZXNoX2FjY291bnQnKS5vbignY2xpY2snLCBmdW5jdGlvbihlKSB7XG4gICAgICAgIGlmKCFfaXNSZWZyZXNoaW5nKXtcbiAgICAgICAgICAgIHZhciBidXR0b24gPSAkKHRoaXMpO1xuICAgICAgICAgICAgdmFyIGFjY291bnQgPSAkKCcjd3ByLWFjY291bnQtZGF0YScpO1xuICAgICAgICAgICAgdmFyIGV4cGlyZSA9ICQoJyN3cHItZXhwaXJhdGlvbi1kYXRhJyk7XG5cbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgIF9pc1JlZnJlc2hpbmcgPSB0cnVlO1xuICAgICAgICAgICAgYnV0dG9uLnRyaWdnZXIoICdibHVyJyApO1xuICAgICAgICAgICAgYnV0dG9uLmFkZENsYXNzKCd3cHItaXNMb2FkaW5nJyk7XG4gICAgICAgICAgICBleHBpcmUucmVtb3ZlQ2xhc3MoJ3dwci1pc1ZhbGlkIHdwci1pc0ludmFsaWQnKTtcblxuICAgICAgICAgICAgJC5wb3N0KFxuICAgICAgICAgICAgICAgIGFqYXh1cmwsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBhY3Rpb246ICdyb2NrZXRfcmVmcmVzaF9jdXN0b21lcl9kYXRhJyxcbiAgICAgICAgICAgICAgICAgICAgX2FqYXhfbm9uY2U6IHJvY2tldF9hamF4X2RhdGEubm9uY2UsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbihyZXNwb25zZSkge1xuICAgICAgICAgICAgICAgICAgICBidXR0b24ucmVtb3ZlQ2xhc3MoJ3dwci1pc0xvYWRpbmcnKTtcbiAgICAgICAgICAgICAgICAgICAgYnV0dG9uLmFkZENsYXNzKCd3cHItaXNIaWRkZW4nKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIHRydWUgPT09IHJlc3BvbnNlLnN1Y2Nlc3MgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhY2NvdW50Lmh0bWwocmVzcG9uc2UuZGF0YS5saWNlbnNlX3R5cGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZXhwaXJlLmFkZENsYXNzKHJlc3BvbnNlLmRhdGEubGljZW5zZV9jbGFzcykuaHRtbChyZXNwb25zZS5kYXRhLmxpY2Vuc2VfZXhwaXJhdGlvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbi5yZW1vdmVDbGFzcygnd3ByLWljb24tcmVmcmVzaCB3cHItaXNIaWRkZW4nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b24uYWRkQ2xhc3MoJ3dwci1pY29uLWNoZWNrJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9LCAyNTApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2V7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbi5yZW1vdmVDbGFzcygnd3ByLWljb24tcmVmcmVzaCB3cHItaXNIaWRkZW4nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBidXR0b24uYWRkQ2xhc3MoJ3dwci1pY29uLWNsb3NlJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9LCAyNTApO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB2VEwgPSBuZXcgVGltZWxpbmVMaXRlKHtvbkNvbXBsZXRlOmZ1bmN0aW9uKCl7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgX2lzUmVmcmVzaGluZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgfX0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC5zZXQoYnV0dG9uLCB7Y3NzOntjbGFzc05hbWU6Jys9d3ByLWlzSGlkZGVuJ319KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAuc2V0KGJ1dHRvbiwge2Nzczp7Y2xhc3NOYW1lOictPXdwci1pY29uLWNoZWNrJ319LCAwLjI1KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAuc2V0KGJ1dHRvbiwge2Nzczp7Y2xhc3NOYW1lOictPXdwci1pY29uLWNsb3NlJ319KVxuICAgICAgICAgICAgICAgICAgICAgICAgICAuc2V0KGJ1dHRvbiwge2Nzczp7Y2xhc3NOYW1lOicrPXdwci1pY29uLXJlZnJlc2gnfX0sIDAuMjUpXG4gICAgICAgICAgICAgICAgICAgICAgICAgIC5zZXQoYnV0dG9uLCB7Y3NzOntjbGFzc05hbWU6Jy09d3ByLWlzSGlkZGVuJ319KVxuICAgICAgICAgICAgICAgICAgICAgICAgO1xuICAgICAgICAgICAgICAgICAgICB9LCAyMDAwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIFNhdmUgVG9nZ2xlIG9wdGlvbiB2YWx1ZXMgb24gY2hhbmdlXG4gICAgICovXG4gICAgJCgnLndwci1yYWRpbyBpbnB1dFt0eXBlPWNoZWNrYm94XScpLm9uKCdjaGFuZ2UnLCBmdW5jdGlvbihlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgdmFyIG5hbWUgID0gJCh0aGlzKS5hdHRyKCdpZCcpO1xuICAgICAgICB2YXIgdmFsdWUgPSAkKHRoaXMpLnByb3AoJ2NoZWNrZWQnKSA/IDEgOiAwO1xuXG5cdFx0dmFyIGV4Y2x1ZGVkID0gWyAnY2xvdWRmbGFyZV9hdXRvX3NldHRpbmdzJywgJ2Nsb3VkZmxhcmVfZGV2bW9kZScgXTtcblx0XHRpZiAoIGV4Y2x1ZGVkLmluZGV4T2YoIG5hbWUgKSA+PSAwICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuICAgICAgICAkLnBvc3QoXG4gICAgICAgICAgICBhamF4dXJsLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGFjdGlvbjogJ3JvY2tldF90b2dnbGVfb3B0aW9uJyxcbiAgICAgICAgICAgICAgICBfYWpheF9ub25jZTogcm9ja2V0X2FqYXhfZGF0YS5ub25jZSxcbiAgICAgICAgICAgICAgICBvcHRpb246IHtcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogbmFtZSxcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHZhbHVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uKHJlc3BvbnNlKSB7fVxuICAgICAgICApO1xuXHR9KTtcblxuXHQvKipcbiAgICAgKiBTYXZlIGVuYWJsZSBDUENTUyBmb3IgbW9iaWxlcyBvcHRpb24uXG4gICAgICovXG4gICAgJCgnI3dwci1hY3Rpb24tcm9ja2V0X2VuYWJsZV9tb2JpbGVfY3Bjc3MnKS5vbignY2xpY2snLCBmdW5jdGlvbihlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuXHRcdCQoJyN3cHItYWN0aW9uLXJvY2tldF9lbmFibGVfbW9iaWxlX2NwY3NzJykuYWRkQ2xhc3MoJ3dwci1pc0xvYWRpbmcnKTtcblxuICAgICAgICAkLnBvc3QoXG4gICAgICAgICAgICBhamF4dXJsLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGFjdGlvbjogJ3JvY2tldF9lbmFibGVfbW9iaWxlX2NwY3NzJyxcbiAgICAgICAgICAgICAgICBfYWpheF9ub25jZTogcm9ja2V0X2FqYXhfZGF0YS5ub25jZVxuICAgICAgICAgICAgfSxcblx0XHRcdGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG5cdFx0XHRcdGlmICggcmVzcG9uc2Uuc3VjY2VzcyApIHtcblx0XHRcdFx0XHQvLyBIaWRlIE1vYmlsZSBDUENTUyBidG4gb24gc3VjY2Vzcy5cblx0XHRcdFx0XHQkKCcjd3ByLWFjdGlvbi1yb2NrZXRfZW5hYmxlX21vYmlsZV9jcGNzcycpLmhpZGUoKTtcblx0XHRcdFx0XHQkKCcud3ByLWhpZGUtb24tY2xpY2snKS5oaWRlKCk7XG5cdFx0XHRcdFx0JCgnLndwci1zaG93LW9uLWNsaWNrJykuc2hvdygpO1xuXHRcdFx0XHRcdCQoJyN3cHItYWN0aW9uLXJvY2tldF9lbmFibGVfbW9iaWxlX2NwY3NzJykucmVtb3ZlQ2xhc3MoJ3dwci1pc0xvYWRpbmcnKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuICAgICAgICApO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogU2F2ZSBlbmFibGUgR29vZ2xlIEZvbnRzIE9wdGltaXphdGlvbiBvcHRpb24uXG4gICAgICovXG4gICAgJCgnI3dwci1hY3Rpb24tcm9ja2V0X2VuYWJsZV9nb29nbGVfZm9udHMnKS5vbignY2xpY2snLCBmdW5jdGlvbihlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuXHRcdCQoJyN3cHItYWN0aW9uLXJvY2tldF9lbmFibGVfZ29vZ2xlX2ZvbnRzJykuYWRkQ2xhc3MoJ3dwci1pc0xvYWRpbmcnKTtcblxuICAgICAgICAkLnBvc3QoXG4gICAgICAgICAgICBhamF4dXJsLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGFjdGlvbjogJ3JvY2tldF9lbmFibGVfZ29vZ2xlX2ZvbnRzJyxcbiAgICAgICAgICAgICAgICBfYWpheF9ub25jZTogcm9ja2V0X2FqYXhfZGF0YS5ub25jZVxuICAgICAgICAgICAgfSxcblx0XHRcdGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG5cdFx0XHRcdGlmICggcmVzcG9uc2Uuc3VjY2VzcyApIHtcblx0XHRcdFx0XHQvLyBIaWRlIE1vYmlsZSBDUENTUyBidG4gb24gc3VjY2Vzcy5cblx0XHRcdFx0XHQkKCcjd3ByLWFjdGlvbi1yb2NrZXRfZW5hYmxlX2dvb2dsZV9mb250cycpLmhpZGUoKTtcblx0XHRcdFx0XHQkKCcud3ByLWhpZGUtb24tY2xpY2snKS5oaWRlKCk7XG5cdFx0XHRcdFx0JCgnLndwci1zaG93LW9uLWNsaWNrJykuc2hvdygpO1xuICAgICAgICAgICAgICAgICAgICAkKCcjd3ByLWFjdGlvbi1yb2NrZXRfZW5hYmxlX2dvb2dsZV9mb250cycpLnJlbW92ZUNsYXNzKCd3cHItaXNMb2FkaW5nJyk7XG4gICAgICAgICAgICAgICAgICAgICQoJyNtaW5pZnlfZ29vZ2xlX2ZvbnRzJykudmFsKDEpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG4gICAgICAgICk7XG4gICAgfSk7XG5cbiAgICAkKCAnI3JvY2tldC1kaXNtaXNzLXByb21vdGlvbicgKS5vbiggJ2NsaWNrJywgZnVuY3Rpb24oIGUgKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICAkLnBvc3QoXG4gICAgICAgICAgICBhamF4dXJsLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGFjdGlvbjogJ3JvY2tldF9kaXNtaXNzX3Byb21vJyxcbiAgICAgICAgICAgICAgICBub25jZTogcm9ja2V0X2FqYXhfZGF0YS5ub25jZVxuICAgICAgICAgICAgfSxcblx0XHRcdGZ1bmN0aW9uKHJlc3BvbnNlKSB7XG5cdFx0XHRcdGlmICggcmVzcG9uc2Uuc3VjY2VzcyApIHtcblx0XHRcdFx0XHQkKCcjcm9ja2V0LXByb21vLWJhbm5lcicpLmhpZGUoICdzbG93JyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG4gICAgICAgICk7XG4gICAgfSApO1xuXG4gICAgJCggJyNyb2NrZXQtZGlzbWlzcy1yZW5ld2FsJyApLm9uKCAnY2xpY2snLCBmdW5jdGlvbiggZSApIHtcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICAgICQucG9zdChcbiAgICAgICAgICAgIGFqYXh1cmwsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgYWN0aW9uOiAncm9ja2V0X2Rpc21pc3NfcmVuZXdhbCcsXG4gICAgICAgICAgICAgICAgbm9uY2U6IHJvY2tldF9hamF4X2RhdGEubm9uY2VcbiAgICAgICAgICAgIH0sXG5cdFx0XHRmdW5jdGlvbihyZXNwb25zZSkge1xuXHRcdFx0XHRpZiAoIHJlc3BvbnNlLnN1Y2Nlc3MgKSB7XG5cdFx0XHRcdFx0JCgnI3JvY2tldC1yZW5ld2FsLWJhbm5lcicpLmhpZGUoICdzbG93JyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG4gICAgICAgICk7XG4gICAgfSApO1xuXHQkKCAnI3dwci11cGRhdGUtZXhjbHVzaW9uLWxpc3QnICkub24oICdjbGljaycsIGZ1bmN0aW9uKCBlICkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHQkKCcjd3ByLXVwZGF0ZS1leGNsdXNpb24tbXNnJykuaHRtbCgnJyk7XG5cdFx0JC5hamF4KHtcblx0XHRcdHVybDogcm9ja2V0X2FqYXhfZGF0YS5yZXN0X3VybCxcblx0XHRcdGJlZm9yZVNlbmQ6IGZ1bmN0aW9uICggeGhyICkge1xuXHRcdFx0XHR4aHIuc2V0UmVxdWVzdEhlYWRlciggJ1gtV1AtTm9uY2UnLCByb2NrZXRfYWpheF9kYXRhLnJlc3Rfbm9uY2UgKTtcblx0XHRcdH0sXG5cdFx0XHRtZXRob2Q6IFwiUFVUXCIsXG5cdFx0XHRzdWNjZXNzOiBmdW5jdGlvbihyZXNwb25zZXMpIHtcblx0XHRcdFx0bGV0IGV4Y2x1c2lvbl9tc2dfY29udGFpbmVyID0gJCgnI3dwci11cGRhdGUtZXhjbHVzaW9uLW1zZycpO1xuXHRcdFx0XHRleGNsdXNpb25fbXNnX2NvbnRhaW5lci5odG1sKCcnKTtcblx0XHRcdFx0aWYgKCB1bmRlZmluZWQgIT09IHJlc3BvbnNlc1snc3VjY2VzcyddICkge1xuXHRcdFx0XHRcdGV4Y2x1c2lvbl9tc2dfY29udGFpbmVyLmFwcGVuZCggJzxkaXYgY2xhc3M9XCJub3RpY2Ugbm90aWNlLWVycm9yXCI+JyArIHJlc3BvbnNlc1snbWVzc2FnZSddICsgJzwvZGl2PicgKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdFx0T2JqZWN0LmtleXMoIHJlc3BvbnNlcyApLmZvckVhY2goKCByZXNwb25zZV9rZXkgKSA9PiB7XG5cdFx0XHRcdFx0ZXhjbHVzaW9uX21zZ19jb250YWluZXIuYXBwZW5kKCAnPHN0cm9uZz4nICsgcmVzcG9uc2Vfa2V5ICsgJzogPC9zdHJvbmc+JyApO1xuXHRcdFx0XHRcdGV4Y2x1c2lvbl9tc2dfY29udGFpbmVyLmFwcGVuZCggcmVzcG9uc2VzW3Jlc3BvbnNlX2tleV1bJ21lc3NhZ2UnXSApO1xuXHRcdFx0XHRcdGV4Y2x1c2lvbl9tc2dfY29udGFpbmVyLmFwcGVuZCggJzxicj4nICk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9ICk7XG5cbiAgICAvKipcbiAgICAgKiBFbmFibGUgbW9iaWxlIGNhY2hlIG9wdGlvbi5cbiAgICAgKi9cbiAgICAkKCcjd3ByX2VuYWJsZV9tb2JpbGVfY2FjaGUnKS5vbignY2xpY2snLCBmdW5jdGlvbihlKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuXHRcdCQoJyN3cHJfZW5hYmxlX21vYmlsZV9jYWNoZScpLmFkZENsYXNzKCd3cHItaXNMb2FkaW5nJyk7XG5cbiAgICAgICAgJC5wb3N0KFxuICAgICAgICAgICAgYWpheHVybCxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhY3Rpb246ICdyb2NrZXRfZW5hYmxlX21vYmlsZV9jYWNoZScsXG4gICAgICAgICAgICAgICAgX2FqYXhfbm9uY2U6IHJvY2tldF9hamF4X2RhdGEubm9uY2VcbiAgICAgICAgICAgIH0sXG5cdFx0XHRmdW5jdGlvbihyZXNwb25zZSkge1xuXHRcdFx0XHRpZiAoIHJlc3BvbnNlLnN1Y2Nlc3MgKSB7XG5cdFx0XHRcdFx0Ly8gSGlkZSBNb2JpbGUgY2FjaGUgZW5hYmxlIGJ1dHRvbiBvbiBzdWNjZXNzLlxuXHRcdFx0XHRcdCQoJyN3cHJfZW5hYmxlX21vYmlsZV9jYWNoZScpLmhpZGUoKTtcblx0XHRcdFx0XHQkKCcjd3ByX21vYmlsZV9jYWNoZV9kZWZhdWx0JykuaGlkZSgpO1xuXHRcdFx0XHRcdCQoJyN3cHJfbW9iaWxlX2NhY2hlX3Jlc3BvbnNlJykuc2hvdygpO1xuICAgICAgICAgICAgICAgICAgICAkKCcjd3ByX2VuYWJsZV9tb2JpbGVfY2FjaGUnKS5yZW1vdmVDbGFzcygnd3ByLWlzTG9hZGluZycpO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFNldCB2YWx1ZXMgb2YgbW9iaWxlIGNhY2hlIGFuZCBzZXBhcmF0ZSBjYWNoZSBmaWxlcyBmb3IgbW9iaWxlcyBvcHRpb24gdG8gMS5cbiAgICAgICAgICAgICAgICAgICAgJCgnI2NhY2hlX21vYmlsZScpLnZhbCgxKTtcbiAgICAgICAgICAgICAgICAgICAgJCgnI2RvX2NhY2hpbmdfbW9iaWxlX2ZpbGVzJykudmFsKDEpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG4gICAgICAgICk7XG4gICAgfSk7XG59KTtcblxuIiwiLy8gQWRkIGdyZWVuc29jayBsaWIgZm9yIGFuaW1hdGlvbnNcclxuaW1wb3J0ICcuLi9saWIvZ3JlZW5zb2NrL1R3ZWVuTGl0ZS5taW4uanMnO1xyXG5pbXBvcnQgJy4uL2xpYi9ncmVlbnNvY2svVGltZWxpbmVMaXRlLm1pbi5qcyc7XHJcbmltcG9ydCAnLi4vbGliL2dyZWVuc29jay9lYXNpbmcvRWFzZVBhY2subWluLmpzJztcclxuaW1wb3J0ICcuLi9saWIvZ3JlZW5zb2NrL3BsdWdpbnMvQ1NTUGx1Z2luLm1pbi5qcyc7XHJcbmltcG9ydCAnLi4vbGliL2dyZWVuc29jay9wbHVnaW5zL1Njcm9sbFRvUGx1Z2luLm1pbi5qcyc7XHJcblxyXG4vLyBBZGQgc2NyaXB0c1xyXG5pbXBvcnQgJy4uL2dsb2JhbC9wYWdlTWFuYWdlci5qcyc7XHJcbmltcG9ydCAnLi4vZ2xvYmFsL21haW4uanMnO1xyXG5pbXBvcnQgJy4uL2dsb2JhbC9maWVsZHMuanMnO1xyXG5pbXBvcnQgJy4uL2dsb2JhbC9iZWFjb24uanMnO1xyXG5pbXBvcnQgJy4uL2dsb2JhbC9hamF4LmpzJztcclxuaW1wb3J0ICcuLi9nbG9iYWwvcm9ja2V0Y2RuLmpzJztcclxuaW1wb3J0ICcuLi9nbG9iYWwvY291bnRkb3duLmpzJzsiLCJ2YXIgJCA9IGpRdWVyeTtcbiQoZG9jdW1lbnQpLnJlYWR5KGZ1bmN0aW9uKCl7XG4gICAgaWYgKCdCZWFjb24nIGluIHdpbmRvdykge1xuICAgICAgICAvKipcbiAgICAgICAgICogU2hvdyBiZWFjb25zIG9uIGJ1dHRvbiBcImhlbHBcIiBjbGlja1xuICAgICAgICAgKi9cbiAgICAgICAgdmFyICRoZWxwID0gJCgnLndwci1pbmZvQWN0aW9uLS1oZWxwJyk7XG4gICAgICAgICRoZWxwLm9uKCdjbGljaycsIGZ1bmN0aW9uKGUpe1xuICAgICAgICAgICAgdmFyIGlkcyA9ICQodGhpcykuZGF0YSgnYmVhY29uLWlkJyk7XG4gICAgICAgICAgICB3cHJDYWxsQmVhY29uKGlkcyk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGZ1bmN0aW9uIHdwckNhbGxCZWFjb24oYUlEKXtcbiAgICAgICAgICAgIGFJRCA9IGFJRC5zcGxpdCgnLCcpO1xuICAgICAgICAgICAgaWYgKCBhSUQubGVuZ3RoID09PSAwICkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICggYUlELmxlbmd0aCA+IDEgKSB7XG4gICAgICAgICAgICAgICAgICAgIHdpbmRvdy5CZWFjb24oXCJzdWdnZXN0XCIsIGFJRCk7XG5cbiAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5CZWFjb24oXCJvcGVuXCIpO1xuICAgICAgICAgICAgICAgICAgICB9LCAyMDApO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHdpbmRvdy5CZWFjb24oXCJhcnRpY2xlXCIsIGFJRC50b1N0cmluZygpKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwiZnVuY3Rpb24gZ2V0VGltZVJlbWFpbmluZyhlbmR0aW1lKXtcbiAgICBjb25zdCBzdGFydCA9IERhdGUubm93KCk7XG4gICAgY29uc3QgdG90YWwgPSAoZW5kdGltZSAqIDEwMDApIC0gc3RhcnQ7XG4gICAgY29uc3Qgc2Vjb25kcyA9IE1hdGguZmxvb3IoICh0b3RhbC8xMDAwKSAlIDYwICk7XG4gICAgY29uc3QgbWludXRlcyA9IE1hdGguZmxvb3IoICh0b3RhbC8xMDAwLzYwKSAlIDYwICk7XG4gICAgY29uc3QgaG91cnMgPSBNYXRoLmZsb29yKCAodG90YWwvKDEwMDAqNjAqNjApKSAlIDI0ICk7XG4gICAgY29uc3QgZGF5cyA9IE1hdGguZmxvb3IoIHRvdGFsLygxMDAwKjYwKjYwKjI0KSApO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgdG90YWwsXG4gICAgICAgIGRheXMsXG4gICAgICAgIGhvdXJzLFxuICAgICAgICBtaW51dGVzLFxuICAgICAgICBzZWNvbmRzXG4gICAgfTtcbn1cblxuZnVuY3Rpb24gaW5pdGlhbGl6ZUNsb2NrKGlkLCBlbmR0aW1lKSB7XG4gICAgY29uc3QgY2xvY2sgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCk7XG5cbiAgICBpZiAoY2xvY2sgPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGRheXNTcGFuID0gY2xvY2sucXVlcnlTZWxlY3RvcignLnJvY2tldC1jb3VudGRvd24tZGF5cycpO1xuICAgIGNvbnN0IGhvdXJzU3BhbiA9IGNsb2NrLnF1ZXJ5U2VsZWN0b3IoJy5yb2NrZXQtY291bnRkb3duLWhvdXJzJyk7XG4gICAgY29uc3QgbWludXRlc1NwYW4gPSBjbG9jay5xdWVyeVNlbGVjdG9yKCcucm9ja2V0LWNvdW50ZG93bi1taW51dGVzJyk7XG4gICAgY29uc3Qgc2Vjb25kc1NwYW4gPSBjbG9jay5xdWVyeVNlbGVjdG9yKCcucm9ja2V0LWNvdW50ZG93bi1zZWNvbmRzJyk7XG5cbiAgICBmdW5jdGlvbiB1cGRhdGVDbG9jaygpIHtcbiAgICAgICAgY29uc3QgdCA9IGdldFRpbWVSZW1haW5pbmcoZW5kdGltZSk7XG5cbiAgICAgICAgaWYgKHQudG90YWwgPCAwKSB7XG4gICAgICAgICAgICBjbGVhckludGVydmFsKHRpbWVpbnRlcnZhbCk7XG5cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGRheXNTcGFuLmlubmVySFRNTCA9IHQuZGF5cztcbiAgICAgICAgaG91cnNTcGFuLmlubmVySFRNTCA9ICgnMCcgKyB0LmhvdXJzKS5zbGljZSgtMik7XG4gICAgICAgIG1pbnV0ZXNTcGFuLmlubmVySFRNTCA9ICgnMCcgKyB0Lm1pbnV0ZXMpLnNsaWNlKC0yKTtcbiAgICAgICAgc2Vjb25kc1NwYW4uaW5uZXJIVE1MID0gKCcwJyArIHQuc2Vjb25kcykuc2xpY2UoLTIpO1xuICAgIH1cblxuICAgIHVwZGF0ZUNsb2NrKCk7XG4gICAgY29uc3QgdGltZWludGVydmFsID0gc2V0SW50ZXJ2YWwodXBkYXRlQ2xvY2ssIDEwMDApO1xufVxuXG5mdW5jdGlvbiBydWNzc1RpbWVyKGlkLCBlbmR0aW1lKSB7XG5cdGNvbnN0IHRpbWVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoaWQpO1xuXHRjb25zdCBub3RpY2UgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncm9ja2V0LW5vdGljZS1ydWNzcy1wcm9jZXNzaW5nJyk7XG5cdGNvbnN0IHN1Y2Nlc3MgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncm9ja2V0LW5vdGljZS1ydWNzcy1zdWNjZXNzJyk7XG5cblx0aWYgKHRpbWVyID09PSBudWxsKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0ZnVuY3Rpb24gdXBkYXRlVGltZXIoKSB7XG5cdFx0Y29uc3Qgc3RhcnQgPSBEYXRlLm5vdygpO1xuXHRcdGNvbnN0IHJlbWFpbmluZyA9IE1hdGguZmxvb3IoICggKGVuZHRpbWUgKiAxMDAwKSAtIHN0YXJ0ICkgLyAxMDAwICk7XG5cblx0XHRpZiAocmVtYWluaW5nIDw9IDApIHtcblx0XHRcdGNsZWFySW50ZXJ2YWwodGltZXJJbnRlcnZhbCk7XG5cblx0XHRcdGlmIChub3RpY2UgIT09IG51bGwpIHtcblx0XHRcdFx0bm90aWNlLmNsYXNzTGlzdC5hZGQoJ2hpZGRlbicpO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoc3VjY2VzcyAhPT0gbnVsbCkge1xuXHRcdFx0XHRzdWNjZXNzLmNsYXNzTGlzdC5yZW1vdmUoJ2hpZGRlbicpO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHJvY2tldF9hamF4X2RhdGEuY3Jvbl9kaXNhYmxlZCApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBkYXRhID0gbmV3IEZvcm1EYXRhKCk7XG5cblx0XHRcdGRhdGEuYXBwZW5kKCAnYWN0aW9uJywgJ3JvY2tldF9zcGF3bl9jcm9uJyApO1xuXHRcdFx0ZGF0YS5hcHBlbmQoICdub25jZScsIHJvY2tldF9hamF4X2RhdGEubm9uY2UgKTtcblxuXHRcdFx0ZmV0Y2goIGFqYXh1cmwsIHtcblx0XHRcdFx0bWV0aG9kOiAnUE9TVCcsXG5cdFx0XHRcdGNyZWRlbnRpYWxzOiAnc2FtZS1vcmlnaW4nLFxuXHRcdFx0XHRib2R5OiBkYXRhXG5cdFx0XHR9ICk7XG5cblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aW1lci5pbm5lckhUTUwgPSByZW1haW5pbmc7XG5cdH1cblxuXHR1cGRhdGVUaW1lcigpO1xuXHRjb25zdCB0aW1lckludGVydmFsID0gc2V0SW50ZXJ2YWwoIHVwZGF0ZVRpbWVyLCAxMDAwKTtcbn1cblxuaWYgKCFEYXRlLm5vdykge1xuICAgIERhdGUubm93ID0gZnVuY3Rpb24gbm93KCkge1xuICAgICAgcmV0dXJuIG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgIH07XG59XG5cbmlmICh0eXBlb2Ygcm9ja2V0X2FqYXhfZGF0YS5wcm9tb19lbmQgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgaW5pdGlhbGl6ZUNsb2NrKCdyb2NrZXQtcHJvbW8tY291bnRkb3duJywgcm9ja2V0X2FqYXhfZGF0YS5wcm9tb19lbmQpO1xufVxuXG5pZiAodHlwZW9mIHJvY2tldF9hamF4X2RhdGEubGljZW5zZV9leHBpcmF0aW9uICE9PSAndW5kZWZpbmVkJykge1xuICAgIGluaXRpYWxpemVDbG9jaygncm9ja2V0LXJlbmV3LWNvdW50ZG93bicsIHJvY2tldF9hamF4X2RhdGEubGljZW5zZV9leHBpcmF0aW9uKTtcbn1cblxuaWYgKHR5cGVvZiByb2NrZXRfYWpheF9kYXRhLm5vdGljZV9lbmRfdGltZSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBydWNzc1RpbWVyKCdyb2NrZXQtcnVjc3MtdGltZXInLCByb2NrZXRfYWpheF9kYXRhLm5vdGljZV9lbmRfdGltZSk7XG59IiwidmFyICQgPSBqUXVlcnk7XG4kKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpe1xuXG5cbiAgICAvKioqXG4gICAgKiBDaGVjayBwYXJlbnQgLyBzaG93IGNoaWxkcmVuXG4gICAgKioqL1xuXG5cdGZ1bmN0aW9uIHdwclNob3dDaGlsZHJlbihhRWxlbSl7XG5cdFx0dmFyIHBhcmVudElkLCAkY2hpbGRyZW47XG5cblx0XHRhRWxlbSAgICAgPSAkKCBhRWxlbSApO1xuXHRcdHBhcmVudElkICA9IGFFbGVtLmF0dHIoJ2lkJyk7XG5cdFx0JGNoaWxkcmVuID0gJCgnW2RhdGEtcGFyZW50PVwiJyArIHBhcmVudElkICsgJ1wiXScpO1xuXG5cdFx0Ly8gVGVzdCBjaGVjayBmb3Igc3dpdGNoXG5cdFx0aWYoYUVsZW0uaXMoJzpjaGVja2VkJykpe1xuXHRcdFx0JGNoaWxkcmVuLmFkZENsYXNzKCd3cHItaXNPcGVuJyk7XG5cblx0XHRcdCRjaGlsZHJlbi5lYWNoKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoICQodGhpcykuZmluZCgnaW5wdXRbdHlwZT1jaGVja2JveF0nKS5pcygnOmNoZWNrZWQnKSkge1xuXHRcdFx0XHRcdHZhciBpZCA9ICQodGhpcykuZmluZCgnaW5wdXRbdHlwZT1jaGVja2JveF0nKS5hdHRyKCdpZCcpO1xuXG5cdFx0XHRcdFx0JCgnW2RhdGEtcGFyZW50PVwiJyArIGlkICsgJ1wiXScpLmFkZENsYXNzKCd3cHItaXNPcGVuJyk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH1cblx0XHRlbHNle1xuXHRcdFx0JGNoaWxkcmVuLnJlbW92ZUNsYXNzKCd3cHItaXNPcGVuJyk7XG5cblx0XHRcdCRjaGlsZHJlbi5lYWNoKGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgaWQgPSAkKHRoaXMpLmZpbmQoJ2lucHV0W3R5cGU9Y2hlY2tib3hdJykuYXR0cignaWQnKTtcblxuXHRcdFx0XHQkKCdbZGF0YS1wYXJlbnQ9XCInICsgaWQgKyAnXCJdJykucmVtb3ZlQ2xhc3MoJ3dwci1pc09wZW4nKTtcblx0XHRcdH0pO1xuXHRcdH1cblx0fVxuXG4gICAgLyoqXG4gICAgICogVGVsbCBpZiB0aGUgZ2l2ZW4gY2hpbGQgZmllbGQgaGFzIGFuIGFjdGl2ZSBwYXJlbnQgZmllbGQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gIG9iamVjdCAkZmllbGQgQSBqUXVlcnkgb2JqZWN0IG9mIGEgXCIud3ByLWZpZWxkXCIgZmllbGQuXG4gICAgICogQHJldHVybiBib29sfG51bGxcbiAgICAgKi9cbiAgICBmdW5jdGlvbiB3cHJJc1BhcmVudEFjdGl2ZSggJGZpZWxkICkge1xuICAgICAgICB2YXIgJHBhcmVudDtcblxuICAgICAgICBpZiAoICEgJGZpZWxkLmxlbmd0aCApIHtcbiAgICAgICAgICAgIC8vIMKvXFxfKOODhClfL8KvXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgICRwYXJlbnQgPSAkZmllbGQuZGF0YSggJ3BhcmVudCcgKTtcblxuICAgICAgICBpZiAoIHR5cGVvZiAkcGFyZW50ICE9PSAnc3RyaW5nJyApIHtcbiAgICAgICAgICAgIC8vIFRoaXMgZmllbGQgaGFzIG5vIHBhcmVudCBmaWVsZDogdGhlbiB3ZSBjYW4gZGlzcGxheSBpdC5cbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgJHBhcmVudCA9ICRwYXJlbnQucmVwbGFjZSggL15cXHMrfFxccyskL2csICcnICk7XG5cbiAgICAgICAgaWYgKCAnJyA9PT0gJHBhcmVudCApIHtcbiAgICAgICAgICAgIC8vIFRoaXMgZmllbGQgaGFzIG5vIHBhcmVudCBmaWVsZDogdGhlbiB3ZSBjYW4gZGlzcGxheSBpdC5cbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgJHBhcmVudCA9ICQoICcjJyArICRwYXJlbnQgKTtcblxuICAgICAgICBpZiAoICEgJHBhcmVudC5sZW5ndGggKSB7XG4gICAgICAgICAgICAvLyBUaGlzIGZpZWxkJ3MgcGFyZW50IGlzIG1pc3Npbmc6IGxldCdzIGNvbnNpZGVyIGl0J3Mgbm90IGFjdGl2ZSB0aGVuLlxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCAhICRwYXJlbnQuaXMoICc6Y2hlY2tlZCcgKSAmJiAkcGFyZW50LmlzKCdpbnB1dCcpKSB7XG4gICAgICAgICAgICAvLyBUaGlzIGZpZWxkJ3MgcGFyZW50IGlzIGNoZWNrYm94IGFuZCBub3QgY2hlY2tlZDogZG9uJ3QgZGlzcGxheSB0aGUgZmllbGQgdGhlbi5cbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG5cdFx0aWYgKCAhJHBhcmVudC5oYXNDbGFzcygncmFkaW8tYWN0aXZlJykgJiYgJHBhcmVudC5pcygnYnV0dG9uJykpIHtcblx0XHRcdC8vIFRoaXMgZmllbGQncyBwYXJlbnQgYnV0dG9uIGFuZCBpcyBub3QgYWN0aXZlOiBkb24ndCBkaXNwbGF5IHRoZSBmaWVsZCB0aGVuLlxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cbiAgICAgICAgLy8gR28gcmVjdXJzaXZlIHRvIHRoZSBsYXN0IHBhcmVudC5cbiAgICAgICAgcmV0dXJuIHdwcklzUGFyZW50QWN0aXZlKCAkcGFyZW50LmNsb3Nlc3QoICcud3ByLWZpZWxkJyApICk7XG4gICAgfVxuXG5cdC8qKlxuXHQgKiBNYXNrcyBzZW5zaXRpdmUgaW5mb3JtYXRpb24gaW4gYW4gaW5wdXQgZmllbGQgYnkgcmVwbGFjaW5nIGFsbCBidXQgdGhlIGxhc3QgNCBjaGFyYWN0ZXJzIHdpdGggYXN0ZXJpc2tzLlxuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gaWRfc2VsZWN0b3IgLSBUaGUgSUQgb2YgdGhlIGlucHV0IGZpZWxkIHRvIGJlIG1hc2tlZC5cblx0ICogQHJldHVybnMge3ZvaWR9IC0gTW9kaWZpZXMgdGhlIGlucHV0IGZpZWxkIHZhbHVlIGluLXBsYWNlLlxuXHQgKlxuXHQgKiBAZXhhbXBsZVxuXHQgKiAvLyBIVE1MOiA8aW5wdXQgdHlwZT1cInRleHRcIiBpZD1cImNyZWRpdENhcmRJbnB1dFwiIHZhbHVlPVwiMTIzNDU2Nzg5MDEyMzQ1NlwiPlxuXHQgKiBtYXNrRmllbGQoJ2NyZWRpdENhcmRJbnB1dCcpO1xuXHQgKiAvLyBSZXN1bHQ6IFVwZGF0ZXMgdGhlIGlucHV0IGZpZWxkIHZhbHVlIHRvICcqKioqKioqKioqKiozNDU2Jy5cblx0ICovXG5cdGZ1bmN0aW9uIG1hc2tGaWVsZChwcm94eV9zZWxlY3RvciwgY29uY3JldGVfc2VsZWN0b3IpIHtcblx0XHR2YXIgY29uY3JldGUgPSB7XG5cdFx0XHQndmFsJzogY29uY3JldGVfc2VsZWN0b3IudmFsKCksXG5cdFx0XHQnbGVuZ3RoJzogY29uY3JldGVfc2VsZWN0b3IudmFsKCkubGVuZ3RoXG5cdFx0fVxuXG5cdFx0aWYgKGNvbmNyZXRlLmxlbmd0aCA+IDQpIHtcblxuXHRcdFx0dmFyIGhpZGRlblBhcnQgPSAnXFx1MjAyMicucmVwZWF0KE1hdGgubWF4KDAsIGNvbmNyZXRlLmxlbmd0aCAtIDQpKTtcblx0XHRcdHZhciB2aXNpYmxlUGFydCA9IGNvbmNyZXRlLnZhbC5zbGljZSgtNCk7XG5cblx0XHRcdC8vIENvbWJpbmUgdGhlIGhpZGRlbiBhbmQgdmlzaWJsZSBwYXJ0c1xuXHRcdFx0dmFyIG1hc2tlZFZhbHVlID0gaGlkZGVuUGFydCArIHZpc2libGVQYXJ0O1xuXG5cdFx0XHRwcm94eV9zZWxlY3Rvci52YWwobWFza2VkVmFsdWUpO1xuXHRcdH1cblx0XHQvLyBFbnN1cmUgZXZlbnRzIGFyZSBub3QgYWRkZWQgbW9yZSB0aGFuIG9uY2Vcblx0XHRpZiAoIXByb3h5X3NlbGVjdG9yLmRhdGEoJ2V2ZW50c0F0dGFjaGVkJykpIHtcblx0XHRcdHByb3h5X3NlbGVjdG9yLm9uKCdpbnB1dCcsIGhhbmRsZUlucHV0KTtcblx0XHRcdHByb3h5X3NlbGVjdG9yLm9uKCdmb2N1cycsIGhhbmRsZUZvY3VzKTtcblx0XHRcdHByb3h5X3NlbGVjdG9yLmRhdGEoJ2V2ZW50c0F0dGFjaGVkJywgdHJ1ZSk7XG5cdFx0fVxuXG5cdFx0LyoqXG5cdFx0ICogSGFuZGxlIHRoZSBpbnB1dCBldmVudFxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIGhhbmRsZUlucHV0KCkge1xuXHRcdFx0dmFyIHByb3h5VmFsdWUgPSBwcm94eV9zZWxlY3Rvci52YWwoKTtcblx0XHRcdGlmIChwcm94eVZhbHVlLmluZGV4T2YoJ1xcdTIwMjInKSA9PT0gLTEpIHtcblx0XHRcdFx0Y29uY3JldGVfc2VsZWN0b3IudmFsKHByb3h5VmFsdWUpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8qKlxuXHRcdCAqIEhhbmRsZSB0aGUgZm9jdXMgZXZlbnRcblx0XHQgKi9cblx0XHRmdW5jdGlvbiBoYW5kbGVGb2N1cygpIHtcblx0XHRcdHZhciBjb25jcmV0ZV92YWx1ZSA9IGNvbmNyZXRlX3NlbGVjdG9yLnZhbCgpO1xuXHRcdFx0cHJveHlfc2VsZWN0b3IudmFsKGNvbmNyZXRlX3ZhbHVlKTtcblx0XHR9XG5cblx0fVxuXG5cdFx0Ly8gVXBkYXRlIHRoZSBjb25jcmV0ZSBmaWVsZCB3aGVuIHRoZSBwcm94eSBpcyB1cGRhdGVkLlxuXG5cblx0bWFza0ZpZWxkKCQoJyNjbG91ZGZsYXJlX2FwaV9rZXlfbWFzaycpLCAkKCcjY2xvdWRmbGFyZV9hcGlfa2V5JykpO1xuXHRtYXNrRmllbGQoJCgnI2Nsb3VkZmxhcmVfem9uZV9pZF9tYXNrJyksICQoJyNjbG91ZGZsYXJlX3pvbmVfaWQnKSk7XG5cblx0Ly8gRGlzcGxheS9IaWRlIGNoaWxkZXJuIGZpZWxkcyBvbiBjaGVja2JveCBjaGFuZ2UuXG4gICAgJCggJy53cHItaXNQYXJlbnQgaW5wdXRbdHlwZT1jaGVja2JveF0nICkub24oJ2NoYW5nZScsIGZ1bmN0aW9uKCkge1xuICAgICAgICB3cHJTaG93Q2hpbGRyZW4oJCh0aGlzKSk7XG4gICAgfSk7XG5cbiAgICAvLyBPbiBwYWdlIGxvYWQsIGRpc3BsYXkgdGhlIGFjdGl2ZSBmaWVsZHMuXG4gICAgJCggJy53cHItZmllbGQtLWNoaWxkcmVuJyApLmVhY2goIGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgJGZpZWxkID0gJCggdGhpcyApO1xuXG4gICAgICAgIGlmICggd3BySXNQYXJlbnRBY3RpdmUoICRmaWVsZCApICkge1xuICAgICAgICAgICAgJGZpZWxkLmFkZENsYXNzKCAnd3ByLWlzT3BlbicgKTtcbiAgICAgICAgfVxuICAgIH0gKTtcblxuXG5cblxuICAgIC8qKipcbiAgICAqIFdhcm5pbmcgZmllbGRzXG4gICAgKioqL1xuXG4gICAgdmFyICR3YXJuaW5nUGFyZW50ID0gJCgnLndwci1maWVsZC0tcGFyZW50Jyk7XG4gICAgdmFyICR3YXJuaW5nUGFyZW50SW5wdXQgPSAkKCcud3ByLWZpZWxkLS1wYXJlbnQgaW5wdXRbdHlwZT1jaGVja2JveF0nKTtcblxuICAgIC8vIElmIGFscmVhZHkgY2hlY2tlZFxuICAgICR3YXJuaW5nUGFyZW50SW5wdXQuZWFjaChmdW5jdGlvbigpe1xuICAgICAgICB3cHJTaG93Q2hpbGRyZW4oJCh0aGlzKSk7XG4gICAgfSk7XG5cbiAgICAkd2FybmluZ1BhcmVudC5vbignY2hhbmdlJywgZnVuY3Rpb24oKSB7XG4gICAgICAgIHdwclNob3dXYXJuaW5nKCQodGhpcykpO1xuICAgIH0pO1xuXG4gICAgZnVuY3Rpb24gd3ByU2hvd1dhcm5pbmcoYUVsZW0pe1xuICAgICAgICB2YXIgJHdhcm5pbmdGaWVsZCA9IGFFbGVtLm5leHQoJy53cHItZmllbGRXYXJuaW5nJyksXG4gICAgICAgICAgICAkdGhpc0NoZWNrYm94ID0gYUVsZW0uZmluZCgnaW5wdXRbdHlwZT1jaGVja2JveF0nKSxcbiAgICAgICAgICAgICRuZXh0V2FybmluZyA9IGFFbGVtLnBhcmVudCgpLm5leHQoJy53cHItd2FybmluZ0NvbnRhaW5lcicpLFxuICAgICAgICAgICAgJG5leHRGaWVsZHMgPSAkbmV4dFdhcm5pbmcuZmluZCgnLndwci1maWVsZCcpLFxuICAgICAgICAgICAgcGFyZW50SWQgPSBhRWxlbS5maW5kKCdpbnB1dFt0eXBlPWNoZWNrYm94XScpLmF0dHIoJ2lkJyksXG4gICAgICAgICAgICAkY2hpbGRyZW4gPSAkKCdbZGF0YS1wYXJlbnQ9XCInICsgcGFyZW50SWQgKyAnXCJdJylcbiAgICAgICAgO1xuXG4gICAgICAgIC8vIENoZWNrIHdhcm5pbmcgcGFyZW50XG4gICAgICAgIGlmKCR0aGlzQ2hlY2tib3guaXMoJzpjaGVja2VkJykpe1xuICAgICAgICAgICAgJHdhcm5pbmdGaWVsZC5hZGRDbGFzcygnd3ByLWlzT3BlbicpO1xuICAgICAgICAgICAgJHRoaXNDaGVja2JveC5wcm9wKCdjaGVja2VkJywgZmFsc2UpO1xuICAgICAgICAgICAgYUVsZW0udHJpZ2dlcignY2hhbmdlJyk7XG5cblxuICAgICAgICAgICAgdmFyICR3YXJuaW5nQnV0dG9uID0gJHdhcm5pbmdGaWVsZC5maW5kKCcud3ByLWJ1dHRvbicpO1xuXG4gICAgICAgICAgICAvLyBWYWxpZGF0ZSB0aGUgd2FybmluZ1xuICAgICAgICAgICAgJHdhcm5pbmdCdXR0b24ub24oJ2NsaWNrJywgZnVuY3Rpb24oKXtcbiAgICAgICAgICAgICAgICAkdGhpc0NoZWNrYm94LnByb3AoJ2NoZWNrZWQnLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAkd2FybmluZ0ZpZWxkLnJlbW92ZUNsYXNzKCd3cHItaXNPcGVuJyk7XG4gICAgICAgICAgICAgICAgJGNoaWxkcmVuLmFkZENsYXNzKCd3cHItaXNPcGVuJyk7XG5cbiAgICAgICAgICAgICAgICAvLyBJZiBuZXh0IGVsZW0gPSBkaXNhYmxlZFxuICAgICAgICAgICAgICAgIGlmKCRuZXh0V2FybmluZy5sZW5ndGggPiAwKXtcbiAgICAgICAgICAgICAgICAgICAgJG5leHRGaWVsZHMucmVtb3ZlQ2xhc3MoJ3dwci1pc0Rpc2FibGVkJyk7XG4gICAgICAgICAgICAgICAgICAgICRuZXh0RmllbGRzLmZpbmQoJ2lucHV0JykucHJvcCgnZGlzYWJsZWQnLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZXtcbiAgICAgICAgICAgICRuZXh0RmllbGRzLmFkZENsYXNzKCd3cHItaXNEaXNhYmxlZCcpO1xuICAgICAgICAgICAgJG5leHRGaWVsZHMuZmluZCgnaW5wdXQnKS5wcm9wKCdkaXNhYmxlZCcsIHRydWUpO1xuICAgICAgICAgICAgJG5leHRGaWVsZHMuZmluZCgnaW5wdXRbdHlwZT1jaGVja2JveF0nKS5wcm9wKCdjaGVja2VkJywgZmFsc2UpO1xuICAgICAgICAgICAgJGNoaWxkcmVuLnJlbW92ZUNsYXNzKCd3cHItaXNPcGVuJyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDTkFNRVMgYWRkL3JlbW92ZSBsaW5lc1xuICAgICAqL1xuICAgICQoZG9jdW1lbnQpLm9uKCdjbGljaycsICcud3ByLW11bHRpcGxlLWNsb3NlJywgZnVuY3Rpb24oZSkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHQkKHRoaXMpLnBhcmVudCgpLnNsaWRlVXAoICdzbG93JyAsIGZ1bmN0aW9uKCl7JCh0aGlzKS5yZW1vdmUoKTsgfSApO1xuXHR9ICk7XG5cblx0JCgnLndwci1idXR0b24tLWFkZE11bHRpJykub24oJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgJCgkKCcjd3ByLWNuYW1lLW1vZGVsJykuaHRtbCgpKS5hcHBlbmRUbygnI3dwci1jbmFtZXMtbGlzdCcpO1xuICAgIH0pO1xuXG5cdC8qKipcblx0ICogV3ByIFJhZGlvIGJ1dHRvblxuXHQgKioqL1xuXHR2YXIgZGlzYWJsZV9yYWRpb193YXJuaW5nID0gZmFsc2U7XG5cblx0JChkb2N1bWVudCkub24oJ2NsaWNrJywgJy53cHItcmFkaW8tYnV0dG9ucy1jb250YWluZXIgYnV0dG9uJywgZnVuY3Rpb24oZSkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRpZigkKHRoaXMpLmhhc0NsYXNzKCdyYWRpby1hY3RpdmUnKSl7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHRcdHZhciAkcGFyZW50ID0gJCh0aGlzKS5wYXJlbnRzKCcud3ByLXJhZGlvLWJ1dHRvbnMnKTtcblx0XHQkcGFyZW50LmZpbmQoJy53cHItcmFkaW8tYnV0dG9ucy1jb250YWluZXIgYnV0dG9uJykucmVtb3ZlQ2xhc3MoJ3JhZGlvLWFjdGl2ZScpO1xuXHRcdCRwYXJlbnQuZmluZCgnLndwci1leHRyYS1maWVsZHMtY29udGFpbmVyJykucmVtb3ZlQ2xhc3MoJ3dwci1pc09wZW4nKTtcblx0XHQkcGFyZW50LmZpbmQoJy53cHItZmllbGRXYXJuaW5nJykucmVtb3ZlQ2xhc3MoJ3dwci1pc09wZW4nKTtcblx0XHQkKHRoaXMpLmFkZENsYXNzKCdyYWRpby1hY3RpdmUnKTtcblx0XHR3cHJTaG93UmFkaW9XYXJuaW5nKCQodGhpcykpO1xuXG5cdH0gKTtcblxuXG5cdGZ1bmN0aW9uIHdwclNob3dSYWRpb1dhcm5pbmcoJGVsbSl7XG5cdFx0ZGlzYWJsZV9yYWRpb193YXJuaW5nID0gZmFsc2U7XG5cdFx0JGVsbS50cmlnZ2VyKCBcImJlZm9yZV9zaG93X3JhZGlvX3dhcm5pbmdcIiwgWyAkZWxtIF0gKTtcblx0XHRpZiAoISRlbG0uaGFzQ2xhc3MoJ2hhcy13YXJuaW5nJykgfHwgZGlzYWJsZV9yYWRpb193YXJuaW5nKSB7XG5cdFx0XHR3cHJTaG93UmFkaW9CdXR0b25DaGlsZHJlbigkZWxtKTtcblx0XHRcdCRlbG0udHJpZ2dlciggXCJyYWRpb19idXR0b25fc2VsZWN0ZWRcIiwgWyAkZWxtIF0gKTtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdFx0dmFyICR3YXJuaW5nRmllbGQgPSAkKCdbZGF0YS1wYXJlbnQ9XCInICsgJGVsbS5hdHRyKCdpZCcpICsgJ1wiXS53cHItZmllbGRXYXJuaW5nJyk7XG5cdFx0JHdhcm5pbmdGaWVsZC5hZGRDbGFzcygnd3ByLWlzT3BlbicpO1xuXHRcdHZhciAkd2FybmluZ0J1dHRvbiA9ICR3YXJuaW5nRmllbGQuZmluZCgnLndwci1idXR0b24nKTtcblxuXHRcdC8vIFZhbGlkYXRlIHRoZSB3YXJuaW5nXG5cdFx0JHdhcm5pbmdCdXR0b24ub24oJ2NsaWNrJywgZnVuY3Rpb24oKXtcblx0XHRcdCR3YXJuaW5nRmllbGQucmVtb3ZlQ2xhc3MoJ3dwci1pc09wZW4nKTtcblx0XHRcdHdwclNob3dSYWRpb0J1dHRvbkNoaWxkcmVuKCRlbG0pO1xuXHRcdFx0JGVsbS50cmlnZ2VyKCBcInJhZGlvX2J1dHRvbl9zZWxlY3RlZFwiLCBbICRlbG0gXSApO1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH0pO1xuXHR9XG5cblx0ZnVuY3Rpb24gd3ByU2hvd1JhZGlvQnV0dG9uQ2hpbGRyZW4oJGVsbSkge1xuXHRcdHZhciAkcGFyZW50ID0gJGVsbS5wYXJlbnRzKCcud3ByLXJhZGlvLWJ1dHRvbnMnKTtcblx0XHR2YXIgJGNoaWxkcmVuID0gJCgnLndwci1leHRyYS1maWVsZHMtY29udGFpbmVyW2RhdGEtcGFyZW50PVwiJyArICRlbG0uYXR0cignaWQnKSArICdcIl0nKTtcblx0XHQkY2hpbGRyZW4uYWRkQ2xhc3MoJ3dwci1pc09wZW4nKTtcblx0fVxuXG5cdC8qKipcblx0ICogV3ByIE9wdGltaXplIENzcyBEZWxpdmVyeSBGaWVsZFxuXHQgKioqL1xuXHR2YXIgcnVjc3NBY3RpdmUgPSBwYXJzZUludCgkKCcjcmVtb3ZlX3VudXNlZF9jc3MnKS52YWwoKSk7XG5cblx0JCggXCIjb3B0aW1pemVfY3NzX2RlbGl2ZXJ5X21ldGhvZCAud3ByLXJhZGlvLWJ1dHRvbnMtY29udGFpbmVyIGJ1dHRvblwiIClcblx0XHQub24oIFwicmFkaW9fYnV0dG9uX3NlbGVjdGVkXCIsIGZ1bmN0aW9uKCBldmVudCwgJGVsbSApIHtcblx0XHRcdHRvZ2dsZUFjdGl2ZU9wdGltaXplQ3NzRGVsaXZlcnlNZXRob2QoJGVsbSk7XG5cdFx0fSk7XG5cblx0JChcIiNvcHRpbWl6ZV9jc3NfZGVsaXZlcnlcIikub24oXCJjaGFuZ2VcIiwgZnVuY3Rpb24oKXtcblx0XHRpZiggJCh0aGlzKS5pcyhcIjpub3QoOmNoZWNrZWQpXCIpICl7XG5cdFx0XHRkaXNhYmxlT3B0aW1pemVDc3NEZWxpdmVyeSgpO1xuXHRcdH1lbHNle1xuXHRcdFx0dmFyIGRlZmF1bHRfcmFkaW9fYnV0dG9uX2lkID0gJyMnKyQoJyNvcHRpbWl6ZV9jc3NfZGVsaXZlcnlfbWV0aG9kJykuZGF0YSggJ2RlZmF1bHQnICk7XG5cdFx0XHQkKGRlZmF1bHRfcmFkaW9fYnV0dG9uX2lkKS50cmlnZ2VyKCdjbGljaycpO1xuXHRcdH1cblx0fSk7XG5cblx0ZnVuY3Rpb24gdG9nZ2xlQWN0aXZlT3B0aW1pemVDc3NEZWxpdmVyeU1ldGhvZCgkZWxtKSB7XG5cdFx0dmFyIG9wdGltaXplX21ldGhvZCA9ICRlbG0uZGF0YSgndmFsdWUnKTtcblx0XHRpZigncmVtb3ZlX3VudXNlZF9jc3MnID09PSBvcHRpbWl6ZV9tZXRob2Qpe1xuXHRcdFx0JCgnI3JlbW92ZV91bnVzZWRfY3NzJykudmFsKDEpO1xuXHRcdFx0JCgnI2FzeW5jX2NzcycpLnZhbCgwKTtcblx0XHR9ZWxzZXtcblx0XHRcdCQoJyNyZW1vdmVfdW51c2VkX2NzcycpLnZhbCgwKTtcblx0XHRcdCQoJyNhc3luY19jc3MnKS52YWwoMSk7XG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBkaXNhYmxlT3B0aW1pemVDc3NEZWxpdmVyeSgpIHtcblx0XHQkKCcjcmVtb3ZlX3VudXNlZF9jc3MnKS52YWwoMCk7XG5cdFx0JCgnI2FzeW5jX2NzcycpLnZhbCgwKTtcblx0fVxuXG5cdCQoIFwiI29wdGltaXplX2Nzc19kZWxpdmVyeV9tZXRob2QgLndwci1yYWRpby1idXR0b25zLWNvbnRhaW5lciBidXR0b25cIiApXG5cdFx0Lm9uKCBcImJlZm9yZV9zaG93X3JhZGlvX3dhcm5pbmdcIiwgZnVuY3Rpb24oIGV2ZW50LCAkZWxtICkge1xuXHRcdFx0ZGlzYWJsZV9yYWRpb193YXJuaW5nID0gKCdyZW1vdmVfdW51c2VkX2NzcycgPT09ICRlbG0uZGF0YSgndmFsdWUnKSAmJiAxID09PSBydWNzc0FjdGl2ZSlcblx0XHR9KTtcblxuXHQkKCBcIi53cHItbXVsdGlwbGUtc2VsZWN0IC53cHItbGlzdC1oZWFkZXItYXJyb3dcIiApLmNsaWNrKGZ1bmN0aW9uIChlKSB7XG5cdFx0JChlLnRhcmdldCkuY2xvc2VzdCgnLndwci1tdWx0aXBsZS1zZWxlY3QgLndwci1saXN0JykudG9nZ2xlQ2xhc3MoJ29wZW4nKTtcblx0fSk7XG5cblx0JCgnLndwci1tdWx0aXBsZS1zZWxlY3QgLndwci1jaGVja2JveCcpLmNsaWNrKGZ1bmN0aW9uIChlKSB7XG5cdFx0Y29uc3QgY2hlY2tib3ggPSAkKHRoaXMpLmZpbmQoJ2lucHV0Jyk7XG5cdFx0Y29uc3QgaXNfY2hlY2tlZCA9IGNoZWNrYm94LmF0dHIoJ2NoZWNrZWQnKSAhPT0gdW5kZWZpbmVkO1xuXHRcdGNoZWNrYm94LmF0dHIoJ2NoZWNrZWQnLCBpc19jaGVja2VkID8gbnVsbCA6ICdjaGVja2VkJyApO1xuXHRcdGNvbnN0IHN1Yl9jaGVja2JveGVzID0gJChjaGVja2JveCkuY2xvc2VzdCgnLndwci1saXN0JykuZmluZCgnLndwci1saXN0LWJvZHkgaW5wdXRbdHlwZT1cImNoZWNrYm94XCJdJyk7XG5cdFx0aWYoY2hlY2tib3guaGFzQ2xhc3MoJ3dwci1tYWluLWNoZWNrYm94JykpIHtcblx0XHRcdCQubWFwKHN1Yl9jaGVja2JveGVzLCBjaGVja2JveCA9PiB7XG5cdFx0XHRcdCQoY2hlY2tib3gpLmF0dHIoJ2NoZWNrZWQnLCBpc19jaGVja2VkID8gbnVsbCA6ICdjaGVja2VkJyApO1xuXHRcdFx0fSk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGNvbnN0IG1haW5fY2hlY2tib3ggPSAkKGNoZWNrYm94KS5jbG9zZXN0KCcud3ByLWxpc3QnKS5maW5kKCcud3ByLW1haW4tY2hlY2tib3gnKTtcblxuXHRcdGNvbnN0IHN1Yl9jaGVja2VkID0gICQubWFwKHN1Yl9jaGVja2JveGVzLCBjaGVja2JveCA9PiB7XG5cdFx0XHRpZigkKGNoZWNrYm94KS5hdHRyKCdjaGVja2VkJykgPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRyZXR1cm4gO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGNoZWNrYm94O1xuXHRcdH0pO1xuXHRcdG1haW5fY2hlY2tib3guYXR0cignY2hlY2tlZCcsIHN1Yl9jaGVja2VkLmxlbmd0aCA9PT0gc3ViX2NoZWNrYm94ZXMubGVuZ3RoID8gJ2NoZWNrZWQnIDogbnVsbCApO1xuXHR9KTtcblxuXHRpZiAoICQoICcud3ByLW1haW4tY2hlY2tib3gnICkubGVuZ3RoID4gMCApIHtcblx0XHQkKCcud3ByLW1haW4tY2hlY2tib3gnKS5lYWNoKChjaGVja2JveF9rZXksIGNoZWNrYm94KSA9PiB7XG5cdFx0XHRsZXQgcGFyZW50X2xpc3QgPSAkKGNoZWNrYm94KS5wYXJlbnRzKCcud3ByLWxpc3QnKTtcblx0XHRcdGxldCBub3RfY2hlY2tlZCA9IHBhcmVudF9saXN0LmZpbmQoICcud3ByLWxpc3QtYm9keSBpbnB1dFt0eXBlPWNoZWNrYm94XTpub3QoOmNoZWNrZWQpJyApLmxlbmd0aDtcblx0XHRcdCQoY2hlY2tib3gpLmF0dHIoJ2NoZWNrZWQnLCBub3RfY2hlY2tlZCA8PSAwID8gJ2NoZWNrZWQnIDogbnVsbCApO1xuXHRcdH0pO1xuXHR9XG59KTtcbiIsInZhciAkID0galF1ZXJ5O1xuJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKXtcblxuXG5cdC8qKipcblx0KiBEYXNoYm9hcmQgbm90aWNlXG5cdCoqKi9cblxuXHR2YXIgJG5vdGljZSA9ICQoJy53cHItbm90aWNlJyk7XG5cdHZhciAkbm90aWNlQ2xvc2UgPSAkKCcjd3ByLWNvbmdyYXR1bGF0aW9ucy1ub3RpY2UnKTtcblxuXHQkbm90aWNlQ2xvc2Uub24oJ2NsaWNrJywgZnVuY3Rpb24oKSB7XG5cdFx0d3ByQ2xvc2VEYXNoYm9hcmROb3RpY2UoKTtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0pO1xuXG5cdGZ1bmN0aW9uIHdwckNsb3NlRGFzaGJvYXJkTm90aWNlKCl7XG5cdFx0dmFyIHZUTCA9IG5ldyBUaW1lbGluZUxpdGUoKVxuXHRcdCAgLnRvKCRub3RpY2UsIDEsIHthdXRvQWxwaGE6MCwgeDo0MCwgZWFzZTpQb3dlcjQuZWFzZU91dH0pXG5cdFx0ICAudG8oJG5vdGljZSwgMC42LCB7aGVpZ2h0OiAwLCBtYXJnaW5Ub3A6MCwgZWFzZTpQb3dlcjQuZWFzZU91dH0sICc9LS40Jylcblx0XHQgIC5zZXQoJG5vdGljZSwgeydkaXNwbGF5Jzonbm9uZSd9KVxuXHRcdDtcblx0fVxuXG5cdC8qKlxuXHQgKiBSb2NrZXQgQW5hbHl0aWNzIG5vdGljZSBpbmZvIGNvbGxlY3Rcblx0ICovXG5cdCQoICcucm9ja2V0LWFuYWx5dGljcy1kYXRhLWNvbnRhaW5lcicgKS5oaWRlKCk7XG5cdCQoICcucm9ja2V0LXByZXZpZXctYW5hbHl0aWNzLWRhdGEnICkub24oICdjbGljaycsIGZ1bmN0aW9uKCBlICkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcblxuXHRcdCQodGhpcykucGFyZW50KCkubmV4dCggJy5yb2NrZXQtYW5hbHl0aWNzLWRhdGEtY29udGFpbmVyJyApLnRvZ2dsZSgpO1xuXHR9ICk7XG5cblx0LyoqKlxuXHQqIEhpZGUgLyBzaG93IFJvY2tldCBhZGRvbiB0YWJzLlxuXHQqKiovXG5cblx0JCggJy53cHItdG9nZ2xlLWJ1dHRvbicgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHR2YXIgJGJ1dHRvbiAgID0gJCggdGhpcyApO1xuXHRcdHZhciAkY2hlY2tib3ggPSAkYnV0dG9uLmNsb3Nlc3QoICcud3ByLWZpZWxkc0NvbnRhaW5lci1maWVsZHNldCcgKS5maW5kKCAnLndwci1yYWRpbyA6Y2hlY2tib3gnICk7XG5cdFx0dmFyICRtZW51SXRlbSA9ICQoICdbaHJlZj1cIicgKyAkYnV0dG9uLmF0dHIoICdocmVmJyApICsgJ1wiXS53cHItbWVudUl0ZW0nICk7XG5cblx0XHQkY2hlY2tib3gub24oJ2NoYW5nZScsIGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCAkY2hlY2tib3guaXMoICc6Y2hlY2tlZCcgKSApIHtcblx0XHRcdFx0JG1lbnVJdGVtLmNzcyggJ2Rpc3BsYXknLCAnYmxvY2snICk7XG5cdFx0XHRcdCRidXR0b24uY3NzKCAnZGlzcGxheScsICdpbmxpbmUtYmxvY2snICk7XG5cdFx0XHR9IGVsc2V7XG5cdFx0XHRcdCRtZW51SXRlbS5jc3MoICdkaXNwbGF5JywgJ25vbmUnICk7XG5cdFx0XHRcdCRidXR0b24uY3NzKCAnZGlzcGxheScsICdub25lJyApO1xuXHRcdFx0fVxuXHRcdH0gKS50cmlnZ2VyKCAnY2hhbmdlJyApO1xuXHR9ICk7XG5cblxuXG5cblxuXHQvKioqXG5cdCogU2hvdyBwb3BpbiBhbmFseXRpY3Ncblx0KioqL1xuXG5cdHZhciAkd3ByQW5hbHl0aWNzUG9waW4gPSAkKCcud3ByLVBvcGluLUFuYWx5dGljcycpLFxuXHRcdCR3cHJQb3Bpbk92ZXJsYXkgPSAkKCcud3ByLVBvcGluLW92ZXJsYXknKSxcblx0XHQkd3ByQW5hbHl0aWNzQ2xvc2VQb3BpbiA9ICQoJy53cHItUG9waW4tQW5hbHl0aWNzLWNsb3NlJyksXG5cdFx0JHdwckFuYWx5dGljc1BvcGluQnV0dG9uID0gJCgnLndwci1Qb3Bpbi1BbmFseXRpY3MgLndwci1idXR0b24nKSxcblx0XHQkd3ByQW5hbHl0aWNzT3BlblBvcGluID0gJCgnLndwci1qcy1wb3BpbicpXG5cdDtcblxuXHQkd3ByQW5hbHl0aWNzT3BlblBvcGluLm9uKCdjbGljaycsIGZ1bmN0aW9uKGUpIHtcblx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0d3ByT3BlbkFuYWx5dGljcygpO1xuXHRcdHJldHVybiBmYWxzZTtcblx0fSk7XG5cblx0JHdwckFuYWx5dGljc0Nsb3NlUG9waW4ub24oJ2NsaWNrJywgZnVuY3Rpb24oZSkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHR3cHJDbG9zZUFuYWx5dGljcygpO1xuXHRcdHJldHVybiBmYWxzZTtcblx0fSk7XG5cblx0JHdwckFuYWx5dGljc1BvcGluQnV0dG9uLm9uKCdjbGljaycsIGZ1bmN0aW9uKGUpIHtcblx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0d3ByQWN0aXZhdGVBbmFseXRpY3MoKTtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0pO1xuXG5cdGZ1bmN0aW9uIHdwck9wZW5BbmFseXRpY3MoKXtcblx0XHR2YXIgdlRMID0gbmV3IFRpbWVsaW5lTGl0ZSgpXG5cdFx0ICAuc2V0KCR3cHJBbmFseXRpY3NQb3BpbiwgeydkaXNwbGF5JzonYmxvY2snfSlcblx0XHQgIC5zZXQoJHdwclBvcGluT3ZlcmxheSwgeydkaXNwbGF5JzonYmxvY2snfSlcblx0XHQgIC5mcm9tVG8oJHdwclBvcGluT3ZlcmxheSwgMC42LCB7YXV0b0FscGhhOjB9LHthdXRvQWxwaGE6MSwgZWFzZTpQb3dlcjQuZWFzZU91dH0pXG5cdFx0ICAuZnJvbVRvKCR3cHJBbmFseXRpY3NQb3BpbiwgMC42LCB7YXV0b0FscGhhOjAsIG1hcmdpblRvcDogLTI0fSwge2F1dG9BbHBoYToxLCBtYXJnaW5Ub3A6MCwgZWFzZTpQb3dlcjQuZWFzZU91dH0sICc9LS41Jylcblx0XHQ7XG5cdH1cblxuXHRmdW5jdGlvbiB3cHJDbG9zZUFuYWx5dGljcygpe1xuXHRcdHZhciB2VEwgPSBuZXcgVGltZWxpbmVMaXRlKClcblx0XHQgIC5mcm9tVG8oJHdwckFuYWx5dGljc1BvcGluLCAwLjYsIHthdXRvQWxwaGE6MSwgbWFyZ2luVG9wOiAwfSwge2F1dG9BbHBoYTowLCBtYXJnaW5Ub3A6LTI0LCBlYXNlOlBvd2VyNC5lYXNlT3V0fSlcblx0XHQgIC5mcm9tVG8oJHdwclBvcGluT3ZlcmxheSwgMC42LCB7YXV0b0FscGhhOjF9LHthdXRvQWxwaGE6MCwgZWFzZTpQb3dlcjQuZWFzZU91dH0sICc9LS41Jylcblx0XHQgIC5zZXQoJHdwckFuYWx5dGljc1BvcGluLCB7J2Rpc3BsYXknOidub25lJ30pXG5cdFx0ICAuc2V0KCR3cHJQb3Bpbk92ZXJsYXksIHsnZGlzcGxheSc6J25vbmUnfSlcblx0XHQ7XG5cdH1cblxuXHRmdW5jdGlvbiB3cHJBY3RpdmF0ZUFuYWx5dGljcygpe1xuXHRcdHdwckNsb3NlQW5hbHl0aWNzKCk7XG5cdFx0JCgnI2FuYWx5dGljc19lbmFibGVkJykucHJvcCgnY2hlY2tlZCcsIHRydWUpO1xuXHRcdCQoJyNhbmFseXRpY3NfZW5hYmxlZCcpLnRyaWdnZXIoJ2NoYW5nZScpO1xuXHR9XG5cblx0Ly8gRGlzcGxheSBDVEEgd2l0aGluIHRoZSBwb3BpbiBgV2hhdCBpbmZvIHdpbGwgd2UgY29sbGVjdD9gXG5cdCQoJyNhbmFseXRpY3NfZW5hYmxlZCcpLm9uKCdjaGFuZ2UnLCBmdW5jdGlvbiAoKSB7XG5cdFx0JCgnLndwci1yb2NrZXQtYW5hbHl0aWNzLWN0YScpLnRvZ2dsZUNsYXNzKCd3cHItaXNIaWRkZW4nKTtcblx0fSk7XG5cblx0LyoqKlxuXHQqIFNob3cgcG9waW4gdXBncmFkZVxuXHQqKiovXG5cblx0dmFyICR3cHJVcGdyYWRlUG9waW4gPSAkKCcud3ByLVBvcGluLVVwZ3JhZGUnKSxcblx0JHdwclVwZ3JhZGVDbG9zZVBvcGluID0gJCgnLndwci1Qb3Bpbi1VcGdyYWRlLWNsb3NlJyksXG5cdCR3cHJVcGdyYWRlT3BlblBvcGluID0gJCgnLndwci1wb3Bpbi11cGdyYWRlLXRvZ2dsZScpO1xuXG5cdCR3cHJVcGdyYWRlT3BlblBvcGluLm9uKCdjbGljaycsIGZ1bmN0aW9uKGUpIHtcblx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0d3ByT3BlblVwZ3JhZGVQb3BpbigpO1xuXHRcdHJldHVybiBmYWxzZTtcblx0fSk7XG5cblx0JHdwclVwZ3JhZGVDbG9zZVBvcGluLm9uKCdjbGljaycsIGZ1bmN0aW9uKCkge1xuXHRcdHdwckNsb3NlVXBncmFkZVBvcGluKCk7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9KTtcblxuXHRmdW5jdGlvbiB3cHJPcGVuVXBncmFkZVBvcGluKCl7XG5cdFx0dmFyIHZUTCA9IG5ldyBUaW1lbGluZUxpdGUoKTtcblxuXHRcdHZUTC5zZXQoJHdwclVwZ3JhZGVQb3BpbiwgeydkaXNwbGF5JzonYmxvY2snfSlcblx0XHRcdC5zZXQoJHdwclBvcGluT3ZlcmxheSwgeydkaXNwbGF5JzonYmxvY2snfSlcblx0XHRcdC5mcm9tVG8oJHdwclBvcGluT3ZlcmxheSwgMC42LCB7YXV0b0FscGhhOjB9LHthdXRvQWxwaGE6MSwgZWFzZTpQb3dlcjQuZWFzZU91dH0pXG5cdFx0XHQuZnJvbVRvKCR3cHJVcGdyYWRlUG9waW4sIDAuNiwge2F1dG9BbHBoYTowLCBtYXJnaW5Ub3A6IC0yNH0sIHthdXRvQWxwaGE6MSwgbWFyZ2luVG9wOjAsIGVhc2U6UG93ZXI0LmVhc2VPdXR9LCAnPS0uNScpXG5cdFx0O1xuXHR9XG5cblx0ZnVuY3Rpb24gd3ByQ2xvc2VVcGdyYWRlUG9waW4oKXtcblx0XHR2YXIgdlRMID0gbmV3IFRpbWVsaW5lTGl0ZSgpO1xuXG5cdFx0dlRMLmZyb21Ubygkd3ByVXBncmFkZVBvcGluLCAwLjYsIHthdXRvQWxwaGE6MSwgbWFyZ2luVG9wOiAwfSwge2F1dG9BbHBoYTowLCBtYXJnaW5Ub3A6LTI0LCBlYXNlOlBvd2VyNC5lYXNlT3V0fSlcblx0XHRcdC5mcm9tVG8oJHdwclBvcGluT3ZlcmxheSwgMC42LCB7YXV0b0FscGhhOjF9LHthdXRvQWxwaGE6MCwgZWFzZTpQb3dlcjQuZWFzZU91dH0sICc9LS41Jylcblx0XHRcdC5zZXQoJHdwclVwZ3JhZGVQb3BpbiwgeydkaXNwbGF5Jzonbm9uZSd9KVxuXHRcdFx0LnNldCgkd3ByUG9waW5PdmVybGF5LCB7J2Rpc3BsYXknOidub25lJ30pXG5cdFx0O1xuXHR9XG5cblx0LyoqKlxuXHQqIFNpZGViYXIgb24vb2ZmXG5cdCoqKi9cblx0dmFyICR3cHJTaWRlYmFyICAgID0gJCggJy53cHItU2lkZWJhcicgKTtcblx0dmFyICR3cHJCdXR0b25UaXBzID0gJCgnLndwci1qcy10aXBzJyk7XG5cblx0JHdwckJ1dHRvblRpcHMub24oJ2NoYW5nZScsIGZ1bmN0aW9uKCkge1xuXHRcdHdwckRldGVjdFRpcHMoJCh0aGlzKSk7XG5cdH0pO1xuXG5cdGZ1bmN0aW9uIHdwckRldGVjdFRpcHMoYUVsZW0pe1xuXHRcdGlmKGFFbGVtLmlzKCc6Y2hlY2tlZCcpKXtcblx0XHRcdCR3cHJTaWRlYmFyLmNzcygnZGlzcGxheScsJ2Jsb2NrJyk7XG5cdFx0XHRsb2NhbFN0b3JhZ2Uuc2V0SXRlbSggJ3dwci1zaG93LXNpZGViYXInLCAnb24nICk7XG5cdFx0fVxuXHRcdGVsc2V7XG5cdFx0XHQkd3ByU2lkZWJhci5jc3MoJ2Rpc3BsYXknLCdub25lJyk7XG5cdFx0XHRsb2NhbFN0b3JhZ2Uuc2V0SXRlbSggJ3dwci1zaG93LXNpZGViYXInLCAnb2ZmJyApO1xuXHRcdH1cblx0fVxuXG5cblxuXHQvKioqXG5cdCogRGV0ZWN0IEFkYmxvY2tcblx0KioqL1xuXG5cdGlmKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdMS2dPY0NScHdtQWonKSl7XG5cdFx0JCgnLndwci1hZGJsb2NrJykuY3NzKCdkaXNwbGF5JywgJ25vbmUnKTtcblx0fSBlbHNlIHtcblx0XHQkKCcud3ByLWFkYmxvY2snKS5jc3MoJ2Rpc3BsYXknLCAnYmxvY2snKTtcblx0fVxuXG5cdHZhciAkYWRibG9jayA9ICQoJy53cHItYWRibG9jaycpO1xuXHR2YXIgJGFkYmxvY2tDbG9zZSA9ICQoJy53cHItYWRibG9jay1jbG9zZScpO1xuXG5cdCRhZGJsb2NrQ2xvc2Uub24oJ2NsaWNrJywgZnVuY3Rpb24oKSB7XG5cdFx0d3ByQ2xvc2VBZGJsb2NrTm90aWNlKCk7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9KTtcblxuXHRmdW5jdGlvbiB3cHJDbG9zZUFkYmxvY2tOb3RpY2UoKXtcblx0XHR2YXIgdlRMID0gbmV3IFRpbWVsaW5lTGl0ZSgpXG5cdFx0ICAudG8oJGFkYmxvY2ssIDEsIHthdXRvQWxwaGE6MCwgeDo0MCwgZWFzZTpQb3dlcjQuZWFzZU91dH0pXG5cdFx0ICAudG8oJGFkYmxvY2ssIDAuNCwge2hlaWdodDogMCwgbWFyZ2luVG9wOjAsIGVhc2U6UG93ZXI0LmVhc2VPdXR9LCAnPS0uNCcpXG5cdFx0ICAuc2V0KCRhZGJsb2NrLCB7J2Rpc3BsYXknOidub25lJ30pXG5cdFx0O1xuXHR9XG5cbn0pO1xuIiwiZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ0RPTUNvbnRlbnRMb2FkZWQnLCBmdW5jdGlvbiAoKSB7XG5cbiAgICB2YXIgJHBhZ2VNYW5hZ2VyID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcIi53cHItQ29udGVudFwiKTtcbiAgICBpZigkcGFnZU1hbmFnZXIpe1xuICAgICAgICBuZXcgUGFnZU1hbmFnZXIoJHBhZ2VNYW5hZ2VyKTtcbiAgICB9XG5cbn0pO1xuXG5cbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qXFxcblx0XHRDTEFTUyBQQUdFTUFOQUdFUlxuXFwqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuLyoqXG4gKiBNYW5hZ2VzIHRoZSBkaXNwbGF5IG9mIHBhZ2VzIC8gc2VjdGlvbiBmb3IgV1AgUm9ja2V0IHBsdWdpblxuICpcbiAqIFB1YmxpYyBtZXRob2QgOlxuICAgICBkZXRlY3RJRCAtIERldGVjdCBJRCB3aXRoIGhhc2hcbiAgICAgZ2V0Qm9keVRvcCAtIEdldCBib2R5IHRvcCBwb3NpdGlvblxuXHQgY2hhbmdlIC0gRGlzcGxheXMgdGhlIGNvcnJlc3BvbmRpbmcgcGFnZVxuICpcbiAqL1xuXG5mdW5jdGlvbiBQYWdlTWFuYWdlcihhRWxlbSkge1xuXG4gICAgdmFyIHJlZlRoaXMgPSB0aGlzO1xuXG4gICAgdGhpcy4kYm9keSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy53cHItYm9keScpO1xuICAgIHRoaXMuJG1lbnVJdGVtcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy53cHItbWVudUl0ZW0nKTtcbiAgICB0aGlzLiRzdWJtaXRCdXR0b24gPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcud3ByLUNvbnRlbnQgPiBmb3JtID4gI3dwci1vcHRpb25zLXN1Ym1pdCcpO1xuICAgIHRoaXMuJHBhZ2VzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLndwci1QYWdlJyk7XG4gICAgdGhpcy4kc2lkZWJhciA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy53cHItU2lkZWJhcicpO1xuICAgIHRoaXMuJGNvbnRlbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcud3ByLUNvbnRlbnQnKTtcbiAgICB0aGlzLiR0aXBzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLndwci1Db250ZW50LXRpcHMnKTtcbiAgICB0aGlzLiRsaW5rcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy53cHItYm9keSBhJyk7XG4gICAgdGhpcy4kbWVudUl0ZW0gPSBudWxsO1xuICAgIHRoaXMuJHBhZ2UgPSBudWxsO1xuICAgIHRoaXMucGFnZUlkID0gbnVsbDtcbiAgICB0aGlzLmJvZHlUb3AgPSAwO1xuICAgIHRoaXMuYnV0dG9uVGV4dCA9IHRoaXMuJHN1Ym1pdEJ1dHRvbi52YWx1ZTtcblxuICAgIHJlZlRoaXMuZ2V0Qm9keVRvcCgpO1xuXG4gICAgLy8gSWYgdXJsIHBhZ2UgY2hhbmdlXG4gICAgd2luZG93Lm9uaGFzaGNoYW5nZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZWZUaGlzLmRldGVjdElEKCk7XG4gICAgfVxuXG4gICAgLy8gSWYgaGFzaCBhbHJlYWR5IGV4aXN0IChhZnRlciByZWZyZXNoIHBhZ2UgZm9yIGV4YW1wbGUpXG4gICAgaWYod2luZG93LmxvY2F0aW9uLmhhc2gpe1xuICAgICAgICB0aGlzLmJvZHlUb3AgPSAwO1xuICAgICAgICB0aGlzLmRldGVjdElEKCk7XG4gICAgfVxuICAgIGVsc2V7XG4gICAgICAgIHZhciBzZXNzaW9uID0gbG9jYWxTdG9yYWdlLmdldEl0ZW0oJ3dwci1oYXNoJyk7XG4gICAgICAgIHRoaXMuYm9keVRvcCA9IDA7XG5cbiAgICAgICAgaWYoc2Vzc2lvbil7XG4gICAgICAgICAgICB3aW5kb3cubG9jYXRpb24uaGFzaCA9IHNlc3Npb247XG4gICAgICAgICAgICB0aGlzLmRldGVjdElEKCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZXtcbiAgICAgICAgICAgIHRoaXMuJG1lbnVJdGVtc1swXS5jbGFzc0xpc3QuYWRkKCdpc0FjdGl2ZScpO1xuICAgICAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oJ3dwci1oYXNoJywgJ2Rhc2hib2FyZCcpO1xuICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLmhhc2ggPSAnI2Rhc2hib2FyZCc7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDbGljayBsaW5rIHNhbWUgaGFzaFxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy4kbGlua3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy4kbGlua3NbaV0ub25jbGljayA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmVmVGhpcy5nZXRCb2R5VG9wKCk7XG4gICAgICAgICAgICB2YXIgaHJlZlNwbGl0ID0gdGhpcy5ocmVmLnNwbGl0KCcjJylbMV07XG4gICAgICAgICAgICBpZihocmVmU3BsaXQgPT0gcmVmVGhpcy5wYWdlSWQgJiYgaHJlZlNwbGl0ICE9IHVuZGVmaW5lZCl7XG4gICAgICAgICAgICAgICAgcmVmVGhpcy5kZXRlY3RJRCgpO1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBDbGljayBsaW5rcyBub3QgV1Agcm9ja2V0IHRvIHJlc2V0IGhhc2hcbiAgICB2YXIgJG90aGVybGlua3MgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcjYWRtaW5tZW51bWFpbiBhLCAjd3BhZG1pbmJhciBhJyk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAkb3RoZXJsaW5rcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAkb3RoZXJsaW5rc1tpXS5vbmNsaWNrID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSgnd3ByLWhhc2gnLCAnJyk7XG4gICAgICAgIH07XG4gICAgfVxuXG59XG5cblxuLypcbiogUGFnZSBkZXRlY3QgSURcbiovXG5QYWdlTWFuYWdlci5wcm90b3R5cGUuZGV0ZWN0SUQgPSBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnBhZ2VJZCA9IHdpbmRvdy5sb2NhdGlvbi5oYXNoLnNwbGl0KCcjJylbMV07XG4gICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oJ3dwci1oYXNoJywgdGhpcy5wYWdlSWQpO1xuXG4gICAgdGhpcy4kcGFnZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy53cHItUGFnZSMnICsgdGhpcy5wYWdlSWQpO1xuICAgIHRoaXMuJG1lbnVJdGVtID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3dwci1uYXYtJyArIHRoaXMucGFnZUlkKTtcblxuICAgIHRoaXMuY2hhbmdlKCk7XG59XG5cblxuXG4vKlxuKiBHZXQgYm9keSB0b3AgcG9zaXRpb25cbiovXG5QYWdlTWFuYWdlci5wcm90b3R5cGUuZ2V0Qm9keVRvcCA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBib2R5UG9zID0gdGhpcy4kYm9keS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICB0aGlzLmJvZHlUb3AgPSBib2R5UG9zLnRvcCArIHdpbmRvdy5wYWdlWU9mZnNldCAtIDQ3OyAvLyAjd3BhZG1pbmJhciArIHBhZGRpbmctdG9wIC53cHItd3JhcCAtIDEgLSA0N1xufVxuXG5cblxuLypcbiogUGFnZSBjaGFuZ2VcbiovXG5QYWdlTWFuYWdlci5wcm90b3R5cGUuY2hhbmdlID0gZnVuY3Rpb24oKSB7XG5cbiAgICB2YXIgcmVmVGhpcyA9IHRoaXM7XG4gICAgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcCA9IHJlZlRoaXMuYm9keVRvcDtcblxuICAgIC8vIEhpZGUgb3RoZXIgcGFnZXNcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuJHBhZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMuJHBhZ2VzW2ldLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgfVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy4kbWVudUl0ZW1zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMuJG1lbnVJdGVtc1tpXS5jbGFzc0xpc3QucmVtb3ZlKCdpc0FjdGl2ZScpO1xuICAgIH1cblxuICAgIC8vIFNob3cgY3VycmVudCBkZWZhdWx0IHBhZ2VcbiAgICB0aGlzLiRwYWdlLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuICAgIHRoaXMuJHN1Ym1pdEJ1dHRvbi5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblxuICAgIGlmICggbnVsbCA9PT0gbG9jYWxTdG9yYWdlLmdldEl0ZW0oICd3cHItc2hvdy1zaWRlYmFyJyApICkge1xuICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSggJ3dwci1zaG93LXNpZGViYXInLCAnb24nICk7XG4gICAgfVxuXG4gICAgaWYgKCAnb24nID09PSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnd3ByLXNob3ctc2lkZWJhcicpICkge1xuICAgICAgICB0aGlzLiRzaWRlYmFyLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuICAgIH0gZWxzZSBpZiAoICdvZmYnID09PSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnd3ByLXNob3ctc2lkZWJhcicpICkge1xuICAgICAgICB0aGlzLiRzaWRlYmFyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICAgIGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJyN3cHItanMtdGlwcycpLnJlbW92ZUF0dHJpYnV0ZSggJ2NoZWNrZWQnICk7XG4gICAgfVxuXG4gICAgdGhpcy4kdGlwcy5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcbiAgICB0aGlzLiRtZW51SXRlbS5jbGFzc0xpc3QuYWRkKCdpc0FjdGl2ZScpO1xuICAgIHRoaXMuJHN1Ym1pdEJ1dHRvbi52YWx1ZSA9IHRoaXMuYnV0dG9uVGV4dDtcbiAgICB0aGlzLiRjb250ZW50LmNsYXNzTGlzdC5hZGQoJ2lzTm90RnVsbCcpO1xuXG5cbiAgICAvLyBFeGNlcHRpb24gZm9yIGRhc2hib2FyZFxuICAgIGlmKHRoaXMucGFnZUlkID09IFwiZGFzaGJvYXJkXCIpe1xuICAgICAgICB0aGlzLiRzaWRlYmFyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICAgIHRoaXMuJHRpcHMuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgdGhpcy4kc3VibWl0QnV0dG9uLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICAgIHRoaXMuJGNvbnRlbnQuY2xhc3NMaXN0LnJlbW92ZSgnaXNOb3RGdWxsJyk7XG4gICAgfVxuXG4gICAgLy8gRXhjZXB0aW9uIGZvciBhZGRvbnNcbiAgICBpZih0aGlzLnBhZ2VJZCA9PSBcImFkZG9uc1wiKXtcbiAgICAgICAgdGhpcy4kc3VibWl0QnV0dG9uLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgfVxuXG4gICAgLy8gRXhjZXB0aW9uIGZvciBkYXRhYmFzZVxuICAgIGlmKHRoaXMucGFnZUlkID09IFwiZGF0YWJhc2VcIil7XG4gICAgICAgIHRoaXMuJHN1Ym1pdEJ1dHRvbi5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgIH1cblxuICAgIC8vIEV4Y2VwdGlvbiBmb3IgdG9vbHMgYW5kIGFkZG9uc1xuICAgIGlmKHRoaXMucGFnZUlkID09IFwidG9vbHNcIiB8fCB0aGlzLnBhZ2VJZCA9PSBcImFkZG9uc1wiKXtcbiAgICAgICAgdGhpcy4kc3VibWl0QnV0dG9uLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMucGFnZUlkID09IFwiaW1hZ2lmeVwiKSB7XG4gICAgICAgIHRoaXMuJHNpZGViYXIuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgdGhpcy4kdGlwcy5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgICB0aGlzLiRzdWJtaXRCdXR0b24uc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICB9XG5cbiAgICBpZiAodGhpcy5wYWdlSWQgPT0gXCJ0dXRvcmlhbHNcIikge1xuICAgICAgICB0aGlzLiRzdWJtaXRCdXR0b24uc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICB9XG59O1xuIiwiLyplc2xpbnQtZW52IGVzNiovXG4oICggZG9jdW1lbnQsIHdpbmRvdyApID0+IHtcblx0J3VzZSBzdHJpY3QnO1xuXG5cdGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoICdET01Db250ZW50TG9hZGVkJywgKCkgPT4ge1xuXHRcdGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoICcud3ByLXJvY2tldGNkbi1vcGVuJyApLmZvckVhY2goICggZWwgKSA9PiB7XG5cdFx0XHRlbC5hZGRFdmVudExpc3RlbmVyKCAnY2xpY2snLCAoIGUgKSA9PiB7XG5cdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdH0gKTtcblx0XHR9ICk7XG5cblx0XHRtYXliZU9wZW5Nb2RhbCgpO1xuXG5cdFx0TWljcm9Nb2RhbC5pbml0KCB7XG5cdFx0XHRkaXNhYmxlU2Nyb2xsOiB0cnVlXG5cdFx0fSApO1xuXHR9ICk7XG5cblx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoICdsb2FkJywgKCkgPT4ge1xuXHRcdGxldCBvcGVuQ1RBID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvciggJyN3cHItcm9ja2V0Y2RuLW9wZW4tY3RhJyApLFxuXHRcdFx0Y2xvc2VDVEEgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCAnI3dwci1yb2NrZXRjZG4tY2xvc2UtY3RhJyApLFxuXHRcdFx0c21hbGxDVEEgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCAnI3dwci1yb2NrZXRjZG4tY3RhLXNtYWxsJyApLFxuXHRcdFx0YmlnQ1RBID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvciggJyN3cHItcm9ja2V0Y2RuLWN0YScgKTtcblxuXHRcdGlmICggbnVsbCAhPT0gb3BlbkNUQSAmJiBudWxsICE9PSBzbWFsbENUQSAmJiBudWxsICE9PSBiaWdDVEEgKSB7XG5cdFx0XHRvcGVuQ1RBLmFkZEV2ZW50TGlzdGVuZXIoICdjbGljaycsICggZSApID0+IHtcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRcdHNtYWxsQ1RBLmNsYXNzTGlzdC5hZGQoICd3cHItaXNIaWRkZW4nICk7XG5cdFx0XHRcdGJpZ0NUQS5jbGFzc0xpc3QucmVtb3ZlKCAnd3ByLWlzSGlkZGVuJyApO1xuXG5cdFx0XHRcdHNlbmRIVFRQUmVxdWVzdCggZ2V0UG9zdERhdGEoICdiaWcnICkgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRpZiAoIG51bGwgIT09IGNsb3NlQ1RBICYmIG51bGwgIT09IHNtYWxsQ1RBICYmIG51bGwgIT09IGJpZ0NUQSApIHtcblx0XHRcdGNsb3NlQ1RBLmFkZEV2ZW50TGlzdGVuZXIoICdjbGljaycsICggZSApID0+IHtcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRcdHNtYWxsQ1RBLmNsYXNzTGlzdC5yZW1vdmUoICd3cHItaXNIaWRkZW4nICk7XG5cdFx0XHRcdGJpZ0NUQS5jbGFzc0xpc3QuYWRkKCAnd3ByLWlzSGlkZGVuJyApO1xuXG5cdFx0XHRcdHNlbmRIVFRQUmVxdWVzdCggZ2V0UG9zdERhdGEoICdzbWFsbCcgKSApO1xuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdldFBvc3REYXRhKCBzdGF0dXMgKSB7XG5cdFx0XHRsZXQgcG9zdERhdGEgPSAnJztcblxuXHRcdFx0cG9zdERhdGEgKz0gJ2FjdGlvbj10b2dnbGVfcm9ja2V0Y2RuX2N0YSc7XG5cdFx0XHRwb3N0RGF0YSArPSAnJnN0YXR1cz0nICsgc3RhdHVzO1xuXHRcdFx0cG9zdERhdGEgKz0gJyZub25jZT0nICsgcm9ja2V0X2FqYXhfZGF0YS5ub25jZTtcblxuXHRcdFx0cmV0dXJuIHBvc3REYXRhO1xuXHRcdH1cblx0fSApO1xuXG5cdHdpbmRvdy5vbm1lc3NhZ2UgPSAoIGUgKSA9PiB7XG5cdFx0Y29uc3QgaWZyYW1lVVJMID0gcm9ja2V0X2FqYXhfZGF0YS5vcmlnaW5fdXJsO1xuXG5cdFx0aWYgKCBlLm9yaWdpbiAhPT0gaWZyYW1lVVJMICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHNldENETkZyYW1lSGVpZ2h0KCBlLmRhdGEgKTtcblx0XHRjbG9zZU1vZGFsKCBlLmRhdGEgKTtcblx0XHR0b2tlbkhhbmRsZXIoIGUuZGF0YSwgaWZyYW1lVVJMICk7XG5cdFx0cHJvY2Vzc1N0YXR1cyggZS5kYXRhICk7XG5cdFx0ZW5hYmxlQ0ROKCBlLmRhdGEsIGlmcmFtZVVSTCApO1xuXHRcdGRpc2FibGVDRE4oIGUuZGF0YSwgaWZyYW1lVVJMICk7XG5cdFx0dmFsaWRhdGVUb2tlbkFuZENOQU1FKCBlLmRhdGEgKTtcblx0fTtcblxuXHRmdW5jdGlvbiBtYXliZU9wZW5Nb2RhbCgpIHtcblx0XHRsZXQgcG9zdERhdGEgPSAnJztcblxuXHRcdHBvc3REYXRhICs9ICdhY3Rpb249cm9ja2V0Y2RuX3Byb2Nlc3Nfc3RhdHVzJztcblx0XHRwb3N0RGF0YSArPSAnJm5vbmNlPScgKyByb2NrZXRfYWpheF9kYXRhLm5vbmNlO1xuXG5cdFx0Y29uc3QgcmVxdWVzdCA9IHNlbmRIVFRQUmVxdWVzdCggcG9zdERhdGEgKTtcblxuXHRcdHJlcXVlc3Qub25yZWFkeXN0YXRlY2hhbmdlID0gKCkgPT4ge1xuXHRcdFx0aWYgKCByZXF1ZXN0LnJlYWR5U3RhdGUgPT09IFhNTEh0dHBSZXF1ZXN0LkRPTkUgJiYgMjAwID09PSByZXF1ZXN0LnN0YXR1cyApIHtcblx0XHRcdFx0bGV0IHJlc3BvbnNlVHh0ID0gSlNPTi5wYXJzZShyZXF1ZXN0LnJlc3BvbnNlVGV4dCk7XG5cblx0XHRcdFx0aWYgKCB0cnVlID09PSByZXNwb25zZVR4dC5zdWNjZXNzICkge1xuXHRcdFx0XHRcdE1pY3JvTW9kYWwuc2hvdyggJ3dwci1yb2NrZXRjZG4tbW9kYWwnICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXHR9XG5cblx0ZnVuY3Rpb24gY2xvc2VNb2RhbCggZGF0YSApIHtcblx0XHRpZiAoICEgZGF0YS5oYXNPd25Qcm9wZXJ0eSggJ2NkbkZyYW1lQ2xvc2UnICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0TWljcm9Nb2RhbC5jbG9zZSggJ3dwci1yb2NrZXRjZG4tbW9kYWwnICk7XG5cblx0XHRsZXQgcGFnZXMgPSBbICdpZnJhbWUtcGF5bWVudC1zdWNjZXNzJywgJ2lmcmFtZS11bnN1YnNjcmliZS1zdWNjZXNzJyBdO1xuXG5cdFx0aWYgKCAhIGRhdGEuaGFzT3duUHJvcGVydHkoICdjZG5fcGFnZV9tZXNzYWdlJyApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggcGFnZXMuaW5kZXhPZiggZGF0YS5jZG5fcGFnZV9tZXNzYWdlICkgPT09IC0xICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGRvY3VtZW50LmxvY2F0aW9uLnJlbG9hZCgpO1xuXHR9XG5cblx0ZnVuY3Rpb24gcHJvY2Vzc1N0YXR1cyggZGF0YSApIHtcblx0XHRpZiAoICEgZGF0YS5oYXNPd25Qcm9wZXJ0eSggJ3JvY2tldGNkbl9wcm9jZXNzJyApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGxldCBwb3N0RGF0YSA9ICcnO1xuXG5cdFx0cG9zdERhdGEgKz0gJ2FjdGlvbj1yb2NrZXRjZG5fcHJvY2Vzc19zZXQnO1xuXHRcdHBvc3REYXRhICs9ICcmc3RhdHVzPScgKyBkYXRhLnJvY2tldGNkbl9wcm9jZXNzO1xuXHRcdHBvc3REYXRhICs9ICcmbm9uY2U9JyArIHJvY2tldF9hamF4X2RhdGEubm9uY2U7XG5cblx0XHRzZW5kSFRUUFJlcXVlc3QoIHBvc3REYXRhICk7XG5cdH1cblxuXHRmdW5jdGlvbiBlbmFibGVDRE4oIGRhdGEsIGlmcmFtZVVSTCApIHtcblx0XHRsZXQgaWZyYW1lID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvciggJyNyb2NrZXRjZG4taWZyYW1lJyApLmNvbnRlbnRXaW5kb3c7XG5cblx0XHRpZiAoICEgZGF0YS5oYXNPd25Qcm9wZXJ0eSggJ3JvY2tldGNkbl91cmwnICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bGV0IHBvc3REYXRhID0gJyc7XG5cblx0XHRwb3N0RGF0YSArPSAnYWN0aW9uPXJvY2tldGNkbl9lbmFibGUnO1xuXHRcdHBvc3REYXRhICs9ICcmY2RuX3VybD0nICsgZGF0YS5yb2NrZXRjZG5fdXJsO1xuXHRcdHBvc3REYXRhICs9ICcmbm9uY2U9JyArIHJvY2tldF9hamF4X2RhdGEubm9uY2U7XG5cblx0XHRjb25zdCByZXF1ZXN0ID0gc2VuZEhUVFBSZXF1ZXN0KCBwb3N0RGF0YSApO1xuXG5cdFx0cmVxdWVzdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSAoKSA9PiB7XG5cdFx0XHRpZiAoIHJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gWE1MSHR0cFJlcXVlc3QuRE9ORSAmJiAyMDAgPT09IHJlcXVlc3Quc3RhdHVzICkge1xuXHRcdFx0XHRsZXQgcmVzcG9uc2VUeHQgPSBKU09OLnBhcnNlKHJlcXVlc3QucmVzcG9uc2VUZXh0KTtcblx0XHRcdFx0aWZyYW1lLnBvc3RNZXNzYWdlKFxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdCdzdWNjZXNzJzogcmVzcG9uc2VUeHQuc3VjY2Vzcyxcblx0XHRcdFx0XHRcdCdkYXRhJzogcmVzcG9uc2VUeHQuZGF0YSxcblx0XHRcdFx0XHRcdCdyb2NrZXRjZG4nOiB0cnVlXG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRpZnJhbWVVUkxcblx0XHRcdFx0KTtcblx0XHRcdH1cblx0XHR9O1xuXHR9XG5cblx0ZnVuY3Rpb24gZGlzYWJsZUNETiggZGF0YSwgaWZyYW1lVVJMICkge1xuXHRcdGxldCBpZnJhbWUgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCAnI3JvY2tldGNkbi1pZnJhbWUnICkuY29udGVudFdpbmRvdztcblxuXHRcdGlmICggISBkYXRhLmhhc093blByb3BlcnR5KCAncm9ja2V0Y2RuX2Rpc2FibGUnICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bGV0IHBvc3REYXRhID0gJyc7XG5cblx0XHRwb3N0RGF0YSArPSAnYWN0aW9uPXJvY2tldGNkbl9kaXNhYmxlJztcblx0XHRwb3N0RGF0YSArPSAnJm5vbmNlPScgKyByb2NrZXRfYWpheF9kYXRhLm5vbmNlO1xuXG5cdFx0Y29uc3QgcmVxdWVzdCA9IHNlbmRIVFRQUmVxdWVzdCggcG9zdERhdGEgKTtcblxuXHRcdHJlcXVlc3Qub25yZWFkeXN0YXRlY2hhbmdlID0gKCkgPT4ge1xuXHRcdFx0aWYgKCByZXF1ZXN0LnJlYWR5U3RhdGUgPT09IFhNTEh0dHBSZXF1ZXN0LkRPTkUgJiYgMjAwID09PSByZXF1ZXN0LnN0YXR1cyApIHtcblx0XHRcdFx0bGV0IHJlc3BvbnNlVHh0ID0gSlNPTi5wYXJzZShyZXF1ZXN0LnJlc3BvbnNlVGV4dCk7XG5cdFx0XHRcdGlmcmFtZS5wb3N0TWVzc2FnZShcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHQnc3VjY2Vzcyc6IHJlc3BvbnNlVHh0LnN1Y2Nlc3MsXG5cdFx0XHRcdFx0XHQnZGF0YSc6IHJlc3BvbnNlVHh0LmRhdGEsXG5cdFx0XHRcdFx0XHQncm9ja2V0Y2RuJzogdHJ1ZVxuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0aWZyYW1lVVJMXG5cdFx0XHRcdCk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fVxuXG5cdGZ1bmN0aW9uIHNlbmRIVFRQUmVxdWVzdCggcG9zdERhdGEgKSB7XG5cdFx0Y29uc3QgaHR0cFJlcXVlc3QgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcblxuXHRcdGh0dHBSZXF1ZXN0Lm9wZW4oICdQT1NUJywgYWpheHVybCApO1xuXHRcdGh0dHBSZXF1ZXN0LnNldFJlcXVlc3RIZWFkZXIoICdDb250ZW50LVR5cGUnLCAnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJyApO1xuXHRcdGh0dHBSZXF1ZXN0LnNlbmQoIHBvc3REYXRhICk7XG5cblx0XHRyZXR1cm4gaHR0cFJlcXVlc3Q7XG5cdH1cblxuXHRmdW5jdGlvbiBzZXRDRE5GcmFtZUhlaWdodCggZGF0YSApIHtcblx0XHRpZiAoICEgZGF0YS5oYXNPd25Qcm9wZXJ0eSggJ2NkbkZyYW1lSGVpZ2h0JyApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAncm9ja2V0Y2RuLWlmcmFtZScgKS5zdHlsZS5oZWlnaHQgPSBgJHsgZGF0YS5jZG5GcmFtZUhlaWdodCB9cHhgO1xuXHR9XG5cblx0ZnVuY3Rpb24gdG9rZW5IYW5kbGVyKCBkYXRhLCBpZnJhbWVVUkwgKSB7XG5cdFx0bGV0IGlmcmFtZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoICcjcm9ja2V0Y2RuLWlmcmFtZScgKS5jb250ZW50V2luZG93O1xuXG5cdFx0aWYgKCAhIGRhdGEuaGFzT3duUHJvcGVydHkoICdyb2NrZXRjZG5fdG9rZW4nICkgKSB7XG5cdFx0XHRsZXQgZGF0YSA9IHtwcm9jZXNzOlwic3Vic2NyaWJlXCIsIG1lc3NhZ2U6XCJ0b2tlbl9ub3RfcmVjZWl2ZWRcIn07XG5cdFx0XHRpZnJhbWUucG9zdE1lc3NhZ2UoXG5cdFx0XHRcdHtcblx0XHRcdFx0XHQnc3VjY2Vzcyc6IGZhbHNlLFxuXHRcdFx0XHRcdCdkYXRhJzogZGF0YSxcblx0XHRcdFx0XHQncm9ja2V0Y2RuJzogdHJ1ZVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRpZnJhbWVVUkxcblx0XHRcdCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bGV0IHBvc3REYXRhID0gJyc7XG5cblx0XHRwb3N0RGF0YSArPSAnYWN0aW9uPXNhdmVfcm9ja2V0Y2RuX3Rva2VuJztcblx0XHRwb3N0RGF0YSArPSAnJnZhbHVlPScgKyBkYXRhLnJvY2tldGNkbl90b2tlbjtcblx0XHRwb3N0RGF0YSArPSAnJm5vbmNlPScgKyByb2NrZXRfYWpheF9kYXRhLm5vbmNlO1xuXG5cdFx0Y29uc3QgcmVxdWVzdCA9IHNlbmRIVFRQUmVxdWVzdCggcG9zdERhdGEgKTtcblxuXHRcdHJlcXVlc3Qub25yZWFkeXN0YXRlY2hhbmdlID0gKCkgPT4ge1xuXHRcdFx0aWYgKCByZXF1ZXN0LnJlYWR5U3RhdGUgPT09IFhNTEh0dHBSZXF1ZXN0LkRPTkUgJiYgMjAwID09PSByZXF1ZXN0LnN0YXR1cyApIHtcblx0XHRcdFx0bGV0IHJlc3BvbnNlVHh0ID0gSlNPTi5wYXJzZShyZXF1ZXN0LnJlc3BvbnNlVGV4dCk7XG5cdFx0XHRcdGlmcmFtZS5wb3N0TWVzc2FnZShcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHQnc3VjY2Vzcyc6IHJlc3BvbnNlVHh0LnN1Y2Nlc3MsXG5cdFx0XHRcdFx0XHQnZGF0YSc6IHJlc3BvbnNlVHh0LmRhdGEsXG5cdFx0XHRcdFx0XHQncm9ja2V0Y2RuJzogdHJ1ZVxuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0aWZyYW1lVVJMXG5cdFx0XHRcdCk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fVxuXG5cdGZ1bmN0aW9uIHZhbGlkYXRlVG9rZW5BbmRDTkFNRSggZGF0YSApIHtcblx0XHRpZiAoICEgZGF0YS5oYXNPd25Qcm9wZXJ0eSggJ3JvY2tldGNkbl92YWxpZGF0ZV90b2tlbicgKSB8fCAhIGRhdGEuaGFzT3duUHJvcGVydHkoICdyb2NrZXRjZG5fdmFsaWRhdGVfY25hbWUnICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bGV0IHBvc3REYXRhID0gJyc7XG5cblx0XHRwb3N0RGF0YSArPSAnYWN0aW9uPXJvY2tldGNkbl92YWxpZGF0ZV90b2tlbl9jbmFtZSc7XG5cdFx0cG9zdERhdGEgKz0gJyZjZG5fdXJsPScgKyBkYXRhLnJvY2tldGNkbl92YWxpZGF0ZV9jbmFtZTtcblx0XHRwb3N0RGF0YSArPSAnJmNkbl90b2tlbj0nICsgZGF0YS5yb2NrZXRjZG5fdmFsaWRhdGVfdG9rZW47XG5cdFx0cG9zdERhdGEgKz0gJyZub25jZT0nICsgcm9ja2V0X2FqYXhfZGF0YS5ub25jZTtcblxuXHRcdGNvbnN0IHJlcXVlc3QgPSBzZW5kSFRUUFJlcXVlc3QoIHBvc3REYXRhICk7XG5cdH1cbn0gKSggZG9jdW1lbnQsIHdpbmRvdyApO1xuIiwiLyohXHJcbiAqIFZFUlNJT046IDEuMTIuMVxyXG4gKiBEQVRFOiAyMDE0LTA2LTI2XHJcbiAqIFVQREFURVMgQU5EIERPQ1MgQVQ6IGh0dHA6Ly93d3cuZ3JlZW5zb2NrLmNvbVxyXG4gKlxyXG4gKiBAbGljZW5zZSBDb3B5cmlnaHQgKGMpIDIwMDgtMjAxNCwgR3JlZW5Tb2NrLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxyXG4gKiBUaGlzIHdvcmsgaXMgc3ViamVjdCB0byB0aGUgdGVybXMgYXQgaHR0cDovL3d3dy5ncmVlbnNvY2suY29tL3Rlcm1zX29mX3VzZS5odG1sIG9yIGZvclxyXG4gKiBDbHViIEdyZWVuU29jayBtZW1iZXJzLCB0aGUgc29mdHdhcmUgYWdyZWVtZW50IHRoYXQgd2FzIGlzc3VlZCB3aXRoIHlvdXIgbWVtYmVyc2hpcC5cclxuICogXHJcbiAqIEBhdXRob3I6IEphY2sgRG95bGUsIGphY2tAZ3JlZW5zb2NrLmNvbVxyXG4gKi9cclxuKHdpbmRvdy5fZ3NRdWV1ZXx8KHdpbmRvdy5fZ3NRdWV1ZT1bXSkpLnB1c2goZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt3aW5kb3cuX2dzRGVmaW5lKFwiVGltZWxpbmVMaXRlXCIsW1wiY29yZS5BbmltYXRpb25cIixcImNvcmUuU2ltcGxlVGltZWxpbmVcIixcIlR3ZWVuTGl0ZVwiXSxmdW5jdGlvbih0LGUsaSl7dmFyIHM9ZnVuY3Rpb24odCl7ZS5jYWxsKHRoaXMsdCksdGhpcy5fbGFiZWxzPXt9LHRoaXMuYXV0b1JlbW92ZUNoaWxkcmVuPXRoaXMudmFycy5hdXRvUmVtb3ZlQ2hpbGRyZW49PT0hMCx0aGlzLnNtb290aENoaWxkVGltaW5nPXRoaXMudmFycy5zbW9vdGhDaGlsZFRpbWluZz09PSEwLHRoaXMuX3NvcnRDaGlsZHJlbj0hMCx0aGlzLl9vblVwZGF0ZT10aGlzLnZhcnMub25VcGRhdGU7dmFyIGkscyxyPXRoaXMudmFycztmb3IocyBpbiByKWk9cltzXSxhKGkpJiYtMSE9PWkuam9pbihcIlwiKS5pbmRleE9mKFwie3NlbGZ9XCIpJiYocltzXT10aGlzLl9zd2FwU2VsZkluUGFyYW1zKGkpKTthKHIudHdlZW5zKSYmdGhpcy5hZGQoci50d2VlbnMsMCxyLmFsaWduLHIuc3RhZ2dlcil9LHI9MWUtMTAsbj1pLl9pbnRlcm5hbHMuaXNTZWxlY3RvcixhPWkuX2ludGVybmFscy5pc0FycmF5LG89W10saD13aW5kb3cuX2dzRGVmaW5lLmdsb2JhbHMsbD1mdW5jdGlvbih0KXt2YXIgZSxpPXt9O2ZvcihlIGluIHQpaVtlXT10W2VdO3JldHVybiBpfSxfPWZ1bmN0aW9uKHQsZSxpLHMpe3QuX3RpbWVsaW5lLnBhdXNlKHQuX3N0YXJ0VGltZSksZSYmZS5hcHBseShzfHx0Ll90aW1lbGluZSxpfHxvKX0sdT1vLnNsaWNlLGY9cy5wcm90b3R5cGU9bmV3IGU7cmV0dXJuIHMudmVyc2lvbj1cIjEuMTIuMVwiLGYuY29uc3RydWN0b3I9cyxmLmtpbGwoKS5fZ2M9ITEsZi50bz1mdW5jdGlvbih0LGUscyxyKXt2YXIgbj1zLnJlcGVhdCYmaC5Ud2Vlbk1heHx8aTtyZXR1cm4gZT90aGlzLmFkZChuZXcgbih0LGUscykscik6dGhpcy5zZXQodCxzLHIpfSxmLmZyb209ZnVuY3Rpb24odCxlLHMscil7cmV0dXJuIHRoaXMuYWRkKChzLnJlcGVhdCYmaC5Ud2Vlbk1heHx8aSkuZnJvbSh0LGUscykscil9LGYuZnJvbVRvPWZ1bmN0aW9uKHQsZSxzLHIsbil7dmFyIGE9ci5yZXBlYXQmJmguVHdlZW5NYXh8fGk7cmV0dXJuIGU/dGhpcy5hZGQoYS5mcm9tVG8odCxlLHMsciksbik6dGhpcy5zZXQodCxyLG4pfSxmLnN0YWdnZXJUbz1mdW5jdGlvbih0LGUscixhLG8saCxfLGYpe3ZhciBwLGM9bmV3IHMoe29uQ29tcGxldGU6aCxvbkNvbXBsZXRlUGFyYW1zOl8sb25Db21wbGV0ZVNjb3BlOmYsc21vb3RoQ2hpbGRUaW1pbmc6dGhpcy5zbW9vdGhDaGlsZFRpbWluZ30pO2ZvcihcInN0cmluZ1wiPT10eXBlb2YgdCYmKHQ9aS5zZWxlY3Rvcih0KXx8dCksbih0KSYmKHQ9dS5jYWxsKHQsMCkpLGE9YXx8MCxwPTA7dC5sZW5ndGg+cDtwKyspci5zdGFydEF0JiYoci5zdGFydEF0PWwoci5zdGFydEF0KSksYy50byh0W3BdLGUsbChyKSxwKmEpO3JldHVybiB0aGlzLmFkZChjLG8pfSxmLnN0YWdnZXJGcm9tPWZ1bmN0aW9uKHQsZSxpLHMscixuLGEsbyl7cmV0dXJuIGkuaW1tZWRpYXRlUmVuZGVyPTAhPWkuaW1tZWRpYXRlUmVuZGVyLGkucnVuQmFja3dhcmRzPSEwLHRoaXMuc3RhZ2dlclRvKHQsZSxpLHMscixuLGEsbyl9LGYuc3RhZ2dlckZyb21Ubz1mdW5jdGlvbih0LGUsaSxzLHIsbixhLG8saCl7cmV0dXJuIHMuc3RhcnRBdD1pLHMuaW1tZWRpYXRlUmVuZGVyPTAhPXMuaW1tZWRpYXRlUmVuZGVyJiYwIT1pLmltbWVkaWF0ZVJlbmRlcix0aGlzLnN0YWdnZXJUbyh0LGUscyxyLG4sYSxvLGgpfSxmLmNhbGw9ZnVuY3Rpb24odCxlLHMscil7cmV0dXJuIHRoaXMuYWRkKGkuZGVsYXllZENhbGwoMCx0LGUscykscil9LGYuc2V0PWZ1bmN0aW9uKHQsZSxzKXtyZXR1cm4gcz10aGlzLl9wYXJzZVRpbWVPckxhYmVsKHMsMCwhMCksbnVsbD09ZS5pbW1lZGlhdGVSZW5kZXImJihlLmltbWVkaWF0ZVJlbmRlcj1zPT09dGhpcy5fdGltZSYmIXRoaXMuX3BhdXNlZCksdGhpcy5hZGQobmV3IGkodCwwLGUpLHMpfSxzLmV4cG9ydFJvb3Q9ZnVuY3Rpb24odCxlKXt0PXR8fHt9LG51bGw9PXQuc21vb3RoQ2hpbGRUaW1pbmcmJih0LnNtb290aENoaWxkVGltaW5nPSEwKTt2YXIgcixuLGE9bmV3IHModCksbz1hLl90aW1lbGluZTtmb3IobnVsbD09ZSYmKGU9ITApLG8uX3JlbW92ZShhLCEwKSxhLl9zdGFydFRpbWU9MCxhLl9yYXdQcmV2VGltZT1hLl90aW1lPWEuX3RvdGFsVGltZT1vLl90aW1lLHI9by5fZmlyc3Q7cjspbj1yLl9uZXh0LGUmJnIgaW5zdGFuY2VvZiBpJiZyLnRhcmdldD09PXIudmFycy5vbkNvbXBsZXRlfHxhLmFkZChyLHIuX3N0YXJ0VGltZS1yLl9kZWxheSkscj1uO3JldHVybiBvLmFkZChhLDApLGF9LGYuYWRkPWZ1bmN0aW9uKHIsbixvLGgpe3ZhciBsLF8sdSxmLHAsYztpZihcIm51bWJlclwiIT10eXBlb2YgbiYmKG49dGhpcy5fcGFyc2VUaW1lT3JMYWJlbChuLDAsITAscikpLCEociBpbnN0YW5jZW9mIHQpKXtpZihyIGluc3RhbmNlb2YgQXJyYXl8fHImJnIucHVzaCYmYShyKSl7Zm9yKG89b3x8XCJub3JtYWxcIixoPWh8fDAsbD1uLF89ci5sZW5ndGgsdT0wO18+dTt1KyspYShmPXJbdV0pJiYoZj1uZXcgcyh7dHdlZW5zOmZ9KSksdGhpcy5hZGQoZixsKSxcInN0cmluZ1wiIT10eXBlb2YgZiYmXCJmdW5jdGlvblwiIT10eXBlb2YgZiYmKFwic2VxdWVuY2VcIj09PW8/bD1mLl9zdGFydFRpbWUrZi50b3RhbER1cmF0aW9uKCkvZi5fdGltZVNjYWxlOlwic3RhcnRcIj09PW8mJihmLl9zdGFydFRpbWUtPWYuZGVsYXkoKSkpLGwrPWg7cmV0dXJuIHRoaXMuX3VuY2FjaGUoITApfWlmKFwic3RyaW5nXCI9PXR5cGVvZiByKXJldHVybiB0aGlzLmFkZExhYmVsKHIsbik7aWYoXCJmdW5jdGlvblwiIT10eXBlb2Ygcil0aHJvd1wiQ2Fubm90IGFkZCBcIityK1wiIGludG8gdGhlIHRpbWVsaW5lOyBpdCBpcyBub3QgYSB0d2VlbiwgdGltZWxpbmUsIGZ1bmN0aW9uLCBvciBzdHJpbmcuXCI7cj1pLmRlbGF5ZWRDYWxsKDAscil9aWYoZS5wcm90b3R5cGUuYWRkLmNhbGwodGhpcyxyLG4pLCh0aGlzLl9nY3x8dGhpcy5fdGltZT09PXRoaXMuX2R1cmF0aW9uKSYmIXRoaXMuX3BhdXNlZCYmdGhpcy5fZHVyYXRpb248dGhpcy5kdXJhdGlvbigpKWZvcihwPXRoaXMsYz1wLnJhd1RpbWUoKT5yLl9zdGFydFRpbWU7cC5fdGltZWxpbmU7KWMmJnAuX3RpbWVsaW5lLnNtb290aENoaWxkVGltaW5nP3AudG90YWxUaW1lKHAuX3RvdGFsVGltZSwhMCk6cC5fZ2MmJnAuX2VuYWJsZWQoITAsITEpLHA9cC5fdGltZWxpbmU7cmV0dXJuIHRoaXN9LGYucmVtb3ZlPWZ1bmN0aW9uKGUpe2lmKGUgaW5zdGFuY2VvZiB0KXJldHVybiB0aGlzLl9yZW1vdmUoZSwhMSk7aWYoZSBpbnN0YW5jZW9mIEFycmF5fHxlJiZlLnB1c2gmJmEoZSkpe2Zvcih2YXIgaT1lLmxlbmd0aDstLWk+LTE7KXRoaXMucmVtb3ZlKGVbaV0pO3JldHVybiB0aGlzfXJldHVyblwic3RyaW5nXCI9PXR5cGVvZiBlP3RoaXMucmVtb3ZlTGFiZWwoZSk6dGhpcy5raWxsKG51bGwsZSl9LGYuX3JlbW92ZT1mdW5jdGlvbih0LGkpe2UucHJvdG90eXBlLl9yZW1vdmUuY2FsbCh0aGlzLHQsaSk7dmFyIHM9dGhpcy5fbGFzdDtyZXR1cm4gcz90aGlzLl90aW1lPnMuX3N0YXJ0VGltZStzLl90b3RhbER1cmF0aW9uL3MuX3RpbWVTY2FsZSYmKHRoaXMuX3RpbWU9dGhpcy5kdXJhdGlvbigpLHRoaXMuX3RvdGFsVGltZT10aGlzLl90b3RhbER1cmF0aW9uKTp0aGlzLl90aW1lPXRoaXMuX3RvdGFsVGltZT10aGlzLl9kdXJhdGlvbj10aGlzLl90b3RhbER1cmF0aW9uPTAsdGhpc30sZi5hcHBlbmQ9ZnVuY3Rpb24odCxlKXtyZXR1cm4gdGhpcy5hZGQodCx0aGlzLl9wYXJzZVRpbWVPckxhYmVsKG51bGwsZSwhMCx0KSl9LGYuaW5zZXJ0PWYuaW5zZXJ0TXVsdGlwbGU9ZnVuY3Rpb24odCxlLGkscyl7cmV0dXJuIHRoaXMuYWRkKHQsZXx8MCxpLHMpfSxmLmFwcGVuZE11bHRpcGxlPWZ1bmN0aW9uKHQsZSxpLHMpe3JldHVybiB0aGlzLmFkZCh0LHRoaXMuX3BhcnNlVGltZU9yTGFiZWwobnVsbCxlLCEwLHQpLGkscyl9LGYuYWRkTGFiZWw9ZnVuY3Rpb24odCxlKXtyZXR1cm4gdGhpcy5fbGFiZWxzW3RdPXRoaXMuX3BhcnNlVGltZU9yTGFiZWwoZSksdGhpc30sZi5hZGRQYXVzZT1mdW5jdGlvbih0LGUsaSxzKXtyZXR1cm4gdGhpcy5jYWxsKF8sW1wie3NlbGZ9XCIsZSxpLHNdLHRoaXMsdCl9LGYucmVtb3ZlTGFiZWw9ZnVuY3Rpb24odCl7cmV0dXJuIGRlbGV0ZSB0aGlzLl9sYWJlbHNbdF0sdGhpc30sZi5nZXRMYWJlbFRpbWU9ZnVuY3Rpb24odCl7cmV0dXJuIG51bGwhPXRoaXMuX2xhYmVsc1t0XT90aGlzLl9sYWJlbHNbdF06LTF9LGYuX3BhcnNlVGltZU9yTGFiZWw9ZnVuY3Rpb24oZSxpLHMscil7dmFyIG47aWYociBpbnN0YW5jZW9mIHQmJnIudGltZWxpbmU9PT10aGlzKXRoaXMucmVtb3ZlKHIpO2Vsc2UgaWYociYmKHIgaW5zdGFuY2VvZiBBcnJheXx8ci5wdXNoJiZhKHIpKSlmb3Iobj1yLmxlbmd0aDstLW4+LTE7KXJbbl1pbnN0YW5jZW9mIHQmJnJbbl0udGltZWxpbmU9PT10aGlzJiZ0aGlzLnJlbW92ZShyW25dKTtpZihcInN0cmluZ1wiPT10eXBlb2YgaSlyZXR1cm4gdGhpcy5fcGFyc2VUaW1lT3JMYWJlbChpLHMmJlwibnVtYmVyXCI9PXR5cGVvZiBlJiZudWxsPT10aGlzLl9sYWJlbHNbaV0/ZS10aGlzLmR1cmF0aW9uKCk6MCxzKTtpZihpPWl8fDAsXCJzdHJpbmdcIiE9dHlwZW9mIGV8fCFpc05hTihlKSYmbnVsbD09dGhpcy5fbGFiZWxzW2VdKW51bGw9PWUmJihlPXRoaXMuZHVyYXRpb24oKSk7ZWxzZXtpZihuPWUuaW5kZXhPZihcIj1cIiksLTE9PT1uKXJldHVybiBudWxsPT10aGlzLl9sYWJlbHNbZV0/cz90aGlzLl9sYWJlbHNbZV09dGhpcy5kdXJhdGlvbigpK2k6aTp0aGlzLl9sYWJlbHNbZV0raTtpPXBhcnNlSW50KGUuY2hhckF0KG4tMSkrXCIxXCIsMTApKk51bWJlcihlLnN1YnN0cihuKzEpKSxlPW4+MT90aGlzLl9wYXJzZVRpbWVPckxhYmVsKGUuc3Vic3RyKDAsbi0xKSwwLHMpOnRoaXMuZHVyYXRpb24oKX1yZXR1cm4gTnVtYmVyKGUpK2l9LGYuc2Vlaz1mdW5jdGlvbih0LGUpe3JldHVybiB0aGlzLnRvdGFsVGltZShcIm51bWJlclwiPT10eXBlb2YgdD90OnRoaXMuX3BhcnNlVGltZU9yTGFiZWwodCksZSE9PSExKX0sZi5zdG9wPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucGF1c2VkKCEwKX0sZi5nb3RvQW5kUGxheT1mdW5jdGlvbih0LGUpe3JldHVybiB0aGlzLnBsYXkodCxlKX0sZi5nb3RvQW5kU3RvcD1mdW5jdGlvbih0LGUpe3JldHVybiB0aGlzLnBhdXNlKHQsZSl9LGYucmVuZGVyPWZ1bmN0aW9uKHQsZSxpKXt0aGlzLl9nYyYmdGhpcy5fZW5hYmxlZCghMCwhMSk7dmFyIHMsbixhLGgsbCxfPXRoaXMuX2RpcnR5P3RoaXMudG90YWxEdXJhdGlvbigpOnRoaXMuX3RvdGFsRHVyYXRpb24sdT10aGlzLl90aW1lLGY9dGhpcy5fc3RhcnRUaW1lLHA9dGhpcy5fdGltZVNjYWxlLGM9dGhpcy5fcGF1c2VkO2lmKHQ+PV8/KHRoaXMuX3RvdGFsVGltZT10aGlzLl90aW1lPV8sdGhpcy5fcmV2ZXJzZWR8fHRoaXMuX2hhc1BhdXNlZENoaWxkKCl8fChuPSEwLGg9XCJvbkNvbXBsZXRlXCIsMD09PXRoaXMuX2R1cmF0aW9uJiYoMD09PXR8fDA+dGhpcy5fcmF3UHJldlRpbWV8fHRoaXMuX3Jhd1ByZXZUaW1lPT09cikmJnRoaXMuX3Jhd1ByZXZUaW1lIT09dCYmdGhpcy5fZmlyc3QmJihsPSEwLHRoaXMuX3Jhd1ByZXZUaW1lPnImJihoPVwib25SZXZlcnNlQ29tcGxldGVcIikpKSx0aGlzLl9yYXdQcmV2VGltZT10aGlzLl9kdXJhdGlvbnx8IWV8fHR8fHRoaXMuX3Jhd1ByZXZUaW1lPT09dD90OnIsdD1fKzFlLTQpOjFlLTc+dD8odGhpcy5fdG90YWxUaW1lPXRoaXMuX3RpbWU9MCwoMCE9PXV8fDA9PT10aGlzLl9kdXJhdGlvbiYmdGhpcy5fcmF3UHJldlRpbWUhPT1yJiYodGhpcy5fcmF3UHJldlRpbWU+MHx8MD50JiZ0aGlzLl9yYXdQcmV2VGltZT49MCkpJiYoaD1cIm9uUmV2ZXJzZUNvbXBsZXRlXCIsbj10aGlzLl9yZXZlcnNlZCksMD50Pyh0aGlzLl9hY3RpdmU9ITEsMD09PXRoaXMuX2R1cmF0aW9uJiZ0aGlzLl9yYXdQcmV2VGltZT49MCYmdGhpcy5fZmlyc3QmJihsPSEwKSx0aGlzLl9yYXdQcmV2VGltZT10KToodGhpcy5fcmF3UHJldlRpbWU9dGhpcy5fZHVyYXRpb258fCFlfHx0fHx0aGlzLl9yYXdQcmV2VGltZT09PXQ/dDpyLHQ9MCx0aGlzLl9pbml0dGVkfHwobD0hMCkpKTp0aGlzLl90b3RhbFRpbWU9dGhpcy5fdGltZT10aGlzLl9yYXdQcmV2VGltZT10LHRoaXMuX3RpbWUhPT11JiZ0aGlzLl9maXJzdHx8aXx8bCl7aWYodGhpcy5faW5pdHRlZHx8KHRoaXMuX2luaXR0ZWQ9ITApLHRoaXMuX2FjdGl2ZXx8IXRoaXMuX3BhdXNlZCYmdGhpcy5fdGltZSE9PXUmJnQ+MCYmKHRoaXMuX2FjdGl2ZT0hMCksMD09PXUmJnRoaXMudmFycy5vblN0YXJ0JiYwIT09dGhpcy5fdGltZSYmKGV8fHRoaXMudmFycy5vblN0YXJ0LmFwcGx5KHRoaXMudmFycy5vblN0YXJ0U2NvcGV8fHRoaXMsdGhpcy52YXJzLm9uU3RhcnRQYXJhbXN8fG8pKSx0aGlzLl90aW1lPj11KWZvcihzPXRoaXMuX2ZpcnN0O3MmJihhPXMuX25leHQsIXRoaXMuX3BhdXNlZHx8Yyk7KShzLl9hY3RpdmV8fHMuX3N0YXJ0VGltZTw9dGhpcy5fdGltZSYmIXMuX3BhdXNlZCYmIXMuX2djKSYmKHMuX3JldmVyc2VkP3MucmVuZGVyKChzLl9kaXJ0eT9zLnRvdGFsRHVyYXRpb24oKTpzLl90b3RhbER1cmF0aW9uKS0odC1zLl9zdGFydFRpbWUpKnMuX3RpbWVTY2FsZSxlLGkpOnMucmVuZGVyKCh0LXMuX3N0YXJ0VGltZSkqcy5fdGltZVNjYWxlLGUsaSkpLHM9YTtlbHNlIGZvcihzPXRoaXMuX2xhc3Q7cyYmKGE9cy5fcHJldiwhdGhpcy5fcGF1c2VkfHxjKTspKHMuX2FjdGl2ZXx8dT49cy5fc3RhcnRUaW1lJiYhcy5fcGF1c2VkJiYhcy5fZ2MpJiYocy5fcmV2ZXJzZWQ/cy5yZW5kZXIoKHMuX2RpcnR5P3MudG90YWxEdXJhdGlvbigpOnMuX3RvdGFsRHVyYXRpb24pLSh0LXMuX3N0YXJ0VGltZSkqcy5fdGltZVNjYWxlLGUsaSk6cy5yZW5kZXIoKHQtcy5fc3RhcnRUaW1lKSpzLl90aW1lU2NhbGUsZSxpKSkscz1hO3RoaXMuX29uVXBkYXRlJiYoZXx8dGhpcy5fb25VcGRhdGUuYXBwbHkodGhpcy52YXJzLm9uVXBkYXRlU2NvcGV8fHRoaXMsdGhpcy52YXJzLm9uVXBkYXRlUGFyYW1zfHxvKSksaCYmKHRoaXMuX2djfHwoZj09PXRoaXMuX3N0YXJ0VGltZXx8cCE9PXRoaXMuX3RpbWVTY2FsZSkmJigwPT09dGhpcy5fdGltZXx8Xz49dGhpcy50b3RhbER1cmF0aW9uKCkpJiYobiYmKHRoaXMuX3RpbWVsaW5lLmF1dG9SZW1vdmVDaGlsZHJlbiYmdGhpcy5fZW5hYmxlZCghMSwhMSksdGhpcy5fYWN0aXZlPSExKSwhZSYmdGhpcy52YXJzW2hdJiZ0aGlzLnZhcnNbaF0uYXBwbHkodGhpcy52YXJzW2grXCJTY29wZVwiXXx8dGhpcyx0aGlzLnZhcnNbaCtcIlBhcmFtc1wiXXx8bykpKX19LGYuX2hhc1BhdXNlZENoaWxkPWZ1bmN0aW9uKCl7Zm9yKHZhciB0PXRoaXMuX2ZpcnN0O3Q7KXtpZih0Ll9wYXVzZWR8fHQgaW5zdGFuY2VvZiBzJiZ0Ll9oYXNQYXVzZWRDaGlsZCgpKXJldHVybiEwO3Q9dC5fbmV4dH1yZXR1cm4hMX0sZi5nZXRDaGlsZHJlbj1mdW5jdGlvbih0LGUscyxyKXtyPXJ8fC05OTk5OTk5OTk5O2Zvcih2YXIgbj1bXSxhPXRoaXMuX2ZpcnN0LG89MDthOylyPmEuX3N0YXJ0VGltZXx8KGEgaW5zdGFuY2VvZiBpP2UhPT0hMSYmKG5bbysrXT1hKToocyE9PSExJiYobltvKytdPWEpLHQhPT0hMSYmKG49bi5jb25jYXQoYS5nZXRDaGlsZHJlbighMCxlLHMpKSxvPW4ubGVuZ3RoKSkpLGE9YS5fbmV4dDtyZXR1cm4gbn0sZi5nZXRUd2VlbnNPZj1mdW5jdGlvbih0LGUpe3ZhciBzLHIsbj10aGlzLl9nYyxhPVtdLG89MDtmb3IobiYmdGhpcy5fZW5hYmxlZCghMCwhMCkscz1pLmdldFR3ZWVuc09mKHQpLHI9cy5sZW5ndGg7LS1yPi0xOykoc1tyXS50aW1lbGluZT09PXRoaXN8fGUmJnRoaXMuX2NvbnRhaW5zKHNbcl0pKSYmKGFbbysrXT1zW3JdKTtyZXR1cm4gbiYmdGhpcy5fZW5hYmxlZCghMSwhMCksYX0sZi5fY29udGFpbnM9ZnVuY3Rpb24odCl7Zm9yKHZhciBlPXQudGltZWxpbmU7ZTspe2lmKGU9PT10aGlzKXJldHVybiEwO2U9ZS50aW1lbGluZX1yZXR1cm4hMX0sZi5zaGlmdENoaWxkcmVuPWZ1bmN0aW9uKHQsZSxpKXtpPWl8fDA7Zm9yKHZhciBzLHI9dGhpcy5fZmlyc3Qsbj10aGlzLl9sYWJlbHM7cjspci5fc3RhcnRUaW1lPj1pJiYoci5fc3RhcnRUaW1lKz10KSxyPXIuX25leHQ7aWYoZSlmb3IocyBpbiBuKW5bc10+PWkmJihuW3NdKz10KTtyZXR1cm4gdGhpcy5fdW5jYWNoZSghMCl9LGYuX2tpbGw9ZnVuY3Rpb24odCxlKXtpZighdCYmIWUpcmV0dXJuIHRoaXMuX2VuYWJsZWQoITEsITEpO2Zvcih2YXIgaT1lP3RoaXMuZ2V0VHdlZW5zT2YoZSk6dGhpcy5nZXRDaGlsZHJlbighMCwhMCwhMSkscz1pLmxlbmd0aCxyPSExOy0tcz4tMTspaVtzXS5fa2lsbCh0LGUpJiYocj0hMCk7cmV0dXJuIHJ9LGYuY2xlYXI9ZnVuY3Rpb24odCl7dmFyIGU9dGhpcy5nZXRDaGlsZHJlbighMSwhMCwhMCksaT1lLmxlbmd0aDtmb3IodGhpcy5fdGltZT10aGlzLl90b3RhbFRpbWU9MDstLWk+LTE7KWVbaV0uX2VuYWJsZWQoITEsITEpO3JldHVybiB0IT09ITEmJih0aGlzLl9sYWJlbHM9e30pLHRoaXMuX3VuY2FjaGUoITApfSxmLmludmFsaWRhdGU9ZnVuY3Rpb24oKXtmb3IodmFyIHQ9dGhpcy5fZmlyc3Q7dDspdC5pbnZhbGlkYXRlKCksdD10Ll9uZXh0O3JldHVybiB0aGlzfSxmLl9lbmFibGVkPWZ1bmN0aW9uKHQsaSl7aWYodD09PXRoaXMuX2djKWZvcih2YXIgcz10aGlzLl9maXJzdDtzOylzLl9lbmFibGVkKHQsITApLHM9cy5fbmV4dDtyZXR1cm4gZS5wcm90b3R5cGUuX2VuYWJsZWQuY2FsbCh0aGlzLHQsaSl9LGYuZHVyYXRpb249ZnVuY3Rpb24odCl7cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGg/KDAhPT10aGlzLmR1cmF0aW9uKCkmJjAhPT10JiZ0aGlzLnRpbWVTY2FsZSh0aGlzLl9kdXJhdGlvbi90KSx0aGlzKToodGhpcy5fZGlydHkmJnRoaXMudG90YWxEdXJhdGlvbigpLHRoaXMuX2R1cmF0aW9uKX0sZi50b3RhbER1cmF0aW9uPWZ1bmN0aW9uKHQpe2lmKCFhcmd1bWVudHMubGVuZ3RoKXtpZih0aGlzLl9kaXJ0eSl7Zm9yKHZhciBlLGkscz0wLHI9dGhpcy5fbGFzdCxuPTk5OTk5OTk5OTk5OTtyOyllPXIuX3ByZXYsci5fZGlydHkmJnIudG90YWxEdXJhdGlvbigpLHIuX3N0YXJ0VGltZT5uJiZ0aGlzLl9zb3J0Q2hpbGRyZW4mJiFyLl9wYXVzZWQ/dGhpcy5hZGQocixyLl9zdGFydFRpbWUtci5fZGVsYXkpOm49ci5fc3RhcnRUaW1lLDA+ci5fc3RhcnRUaW1lJiYhci5fcGF1c2VkJiYocy09ci5fc3RhcnRUaW1lLHRoaXMuX3RpbWVsaW5lLnNtb290aENoaWxkVGltaW5nJiYodGhpcy5fc3RhcnRUaW1lKz1yLl9zdGFydFRpbWUvdGhpcy5fdGltZVNjYWxlKSx0aGlzLnNoaWZ0Q2hpbGRyZW4oLXIuX3N0YXJ0VGltZSwhMSwtOTk5OTk5OTk5OSksbj0wKSxpPXIuX3N0YXJ0VGltZStyLl90b3RhbER1cmF0aW9uL3IuX3RpbWVTY2FsZSxpPnMmJihzPWkpLHI9ZTt0aGlzLl9kdXJhdGlvbj10aGlzLl90b3RhbER1cmF0aW9uPXMsdGhpcy5fZGlydHk9ITF9cmV0dXJuIHRoaXMuX3RvdGFsRHVyYXRpb259cmV0dXJuIDAhPT10aGlzLnRvdGFsRHVyYXRpb24oKSYmMCE9PXQmJnRoaXMudGltZVNjYWxlKHRoaXMuX3RvdGFsRHVyYXRpb24vdCksdGhpc30sZi51c2VzRnJhbWVzPWZ1bmN0aW9uKCl7Zm9yKHZhciBlPXRoaXMuX3RpbWVsaW5lO2UuX3RpbWVsaW5lOyllPWUuX3RpbWVsaW5lO3JldHVybiBlPT09dC5fcm9vdEZyYW1lc1RpbWVsaW5lfSxmLnJhd1RpbWU9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fcGF1c2VkP3RoaXMuX3RvdGFsVGltZToodGhpcy5fdGltZWxpbmUucmF3VGltZSgpLXRoaXMuX3N0YXJ0VGltZSkqdGhpcy5fdGltZVNjYWxlfSxzfSwhMCl9KSx3aW5kb3cuX2dzRGVmaW5lJiZ3aW5kb3cuX2dzUXVldWUucG9wKCkoKTsiLCIvKiFcclxuICogVkVSU0lPTjogMS4xMi4xXHJcbiAqIERBVEU6IDIwMTQtMDYtMjZcclxuICogVVBEQVRFUyBBTkQgRE9DUyBBVDogaHR0cDovL3d3dy5ncmVlbnNvY2suY29tXHJcbiAqXHJcbiAqIEBsaWNlbnNlIENvcHlyaWdodCAoYykgMjAwOC0yMDE0LCBHcmVlblNvY2suIEFsbCByaWdodHMgcmVzZXJ2ZWQuXHJcbiAqIFRoaXMgd29yayBpcyBzdWJqZWN0IHRvIHRoZSB0ZXJtcyBhdCBodHRwOi8vd3d3LmdyZWVuc29jay5jb20vdGVybXNfb2ZfdXNlLmh0bWwgb3IgZm9yXHJcbiAqIENsdWIgR3JlZW5Tb2NrIG1lbWJlcnMsIHRoZSBzb2Z0d2FyZSBhZ3JlZW1lbnQgdGhhdCB3YXMgaXNzdWVkIHdpdGggeW91ciBtZW1iZXJzaGlwLlxyXG4gKiBcclxuICogQGF1dGhvcjogSmFjayBEb3lsZSwgamFja0BncmVlbnNvY2suY29tXHJcbiAqL1xyXG4oZnVuY3Rpb24odCl7XCJ1c2Ugc3RyaWN0XCI7dmFyIGU9dC5HcmVlblNvY2tHbG9iYWxzfHx0O2lmKCFlLlR3ZWVuTGl0ZSl7dmFyIGkscyxuLHIsYSxvPWZ1bmN0aW9uKHQpe3ZhciBpLHM9dC5zcGxpdChcIi5cIiksbj1lO2ZvcihpPTA7cy5sZW5ndGg+aTtpKyspbltzW2ldXT1uPW5bc1tpXV18fHt9O3JldHVybiBufSxsPW8oXCJjb20uZ3JlZW5zb2NrXCIpLGg9MWUtMTAsXz1bXS5zbGljZSx1PWZ1bmN0aW9uKCl7fSxtPWZ1bmN0aW9uKCl7dmFyIHQ9T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZyxlPXQuY2FsbChbXSk7cmV0dXJuIGZ1bmN0aW9uKGkpe3JldHVybiBudWxsIT1pJiYoaSBpbnN0YW5jZW9mIEFycmF5fHxcIm9iamVjdFwiPT10eXBlb2YgaSYmISFpLnB1c2gmJnQuY2FsbChpKT09PWUpfX0oKSxmPXt9LHA9ZnVuY3Rpb24oaSxzLG4scil7dGhpcy5zYz1mW2ldP2ZbaV0uc2M6W10sZltpXT10aGlzLHRoaXMuZ3NDbGFzcz1udWxsLHRoaXMuZnVuYz1uO3ZhciBhPVtdO3RoaXMuY2hlY2s9ZnVuY3Rpb24obCl7Zm9yKHZhciBoLF8sdSxtLGM9cy5sZW5ndGgsZD1jOy0tYz4tMTspKGg9ZltzW2NdXXx8bmV3IHAoc1tjXSxbXSkpLmdzQ2xhc3M/KGFbY109aC5nc0NsYXNzLGQtLSk6bCYmaC5zYy5wdXNoKHRoaXMpO2lmKDA9PT1kJiZuKWZvcihfPShcImNvbS5ncmVlbnNvY2suXCIraSkuc3BsaXQoXCIuXCIpLHU9Xy5wb3AoKSxtPW8oXy5qb2luKFwiLlwiKSlbdV09dGhpcy5nc0NsYXNzPW4uYXBwbHkobixhKSxyJiYoZVt1XT1tLFwiZnVuY3Rpb25cIj09dHlwZW9mIGRlZmluZSYmZGVmaW5lLmFtZD9kZWZpbmUoKHQuR3JlZW5Tb2NrQU1EUGF0aD90LkdyZWVuU29ja0FNRFBhdGgrXCIvXCI6XCJcIikraS5zcGxpdChcIi5cIikuam9pbihcIi9cIiksW10sZnVuY3Rpb24oKXtyZXR1cm4gbX0pOlwidW5kZWZpbmVkXCIhPXR5cGVvZiBtb2R1bGUmJm1vZHVsZS5leHBvcnRzJiYobW9kdWxlLmV4cG9ydHM9bSkpLGM9MDt0aGlzLnNjLmxlbmd0aD5jO2MrKyl0aGlzLnNjW2NdLmNoZWNrKCl9LHRoaXMuY2hlY2soITApfSxjPXQuX2dzRGVmaW5lPWZ1bmN0aW9uKHQsZSxpLHMpe3JldHVybiBuZXcgcCh0LGUsaSxzKX0sZD1sLl9jbGFzcz1mdW5jdGlvbih0LGUsaSl7cmV0dXJuIGU9ZXx8ZnVuY3Rpb24oKXt9LGModCxbXSxmdW5jdGlvbigpe3JldHVybiBlfSxpKSxlfTtjLmdsb2JhbHM9ZTt2YXIgdj1bMCwwLDEsMV0sZz1bXSxUPWQoXCJlYXNpbmcuRWFzZVwiLGZ1bmN0aW9uKHQsZSxpLHMpe3RoaXMuX2Z1bmM9dCx0aGlzLl90eXBlPWl8fDAsdGhpcy5fcG93ZXI9c3x8MCx0aGlzLl9wYXJhbXM9ZT92LmNvbmNhdChlKTp2fSwhMCkseT1ULm1hcD17fSx3PVQucmVnaXN0ZXI9ZnVuY3Rpb24odCxlLGkscyl7Zm9yKHZhciBuLHIsYSxvLGg9ZS5zcGxpdChcIixcIiksXz1oLmxlbmd0aCx1PShpfHxcImVhc2VJbixlYXNlT3V0LGVhc2VJbk91dFwiKS5zcGxpdChcIixcIik7LS1fPi0xOylmb3Iocj1oW19dLG49cz9kKFwiZWFzaW5nLlwiK3IsbnVsbCwhMCk6bC5lYXNpbmdbcl18fHt9LGE9dS5sZW5ndGg7LS1hPi0xOylvPXVbYV0seVtyK1wiLlwiK29dPXlbbytyXT1uW29dPXQuZ2V0UmF0aW8/dDp0W29dfHxuZXcgdH07Zm9yKG49VC5wcm90b3R5cGUsbi5fY2FsY0VuZD0hMSxuLmdldFJhdGlvPWZ1bmN0aW9uKHQpe2lmKHRoaXMuX2Z1bmMpcmV0dXJuIHRoaXMuX3BhcmFtc1swXT10LHRoaXMuX2Z1bmMuYXBwbHkobnVsbCx0aGlzLl9wYXJhbXMpO3ZhciBlPXRoaXMuX3R5cGUsaT10aGlzLl9wb3dlcixzPTE9PT1lPzEtdDoyPT09ZT90Oi41PnQ/Mip0OjIqKDEtdCk7cmV0dXJuIDE9PT1pP3MqPXM6Mj09PWk/cyo9cypzOjM9PT1pP3MqPXMqcypzOjQ9PT1pJiYocyo9cypzKnMqcyksMT09PWU/MS1zOjI9PT1lP3M6LjU+dD9zLzI6MS1zLzJ9LGk9W1wiTGluZWFyXCIsXCJRdWFkXCIsXCJDdWJpY1wiLFwiUXVhcnRcIixcIlF1aW50LFN0cm9uZ1wiXSxzPWkubGVuZ3RoOy0tcz4tMTspbj1pW3NdK1wiLFBvd2VyXCIrcyx3KG5ldyBUKG51bGwsbnVsbCwxLHMpLG4sXCJlYXNlT3V0XCIsITApLHcobmV3IFQobnVsbCxudWxsLDIscyksbixcImVhc2VJblwiKygwPT09cz9cIixlYXNlTm9uZVwiOlwiXCIpKSx3KG5ldyBUKG51bGwsbnVsbCwzLHMpLG4sXCJlYXNlSW5PdXRcIik7eS5saW5lYXI9bC5lYXNpbmcuTGluZWFyLmVhc2VJbix5LnN3aW5nPWwuZWFzaW5nLlF1YWQuZWFzZUluT3V0O3ZhciBQPWQoXCJldmVudHMuRXZlbnREaXNwYXRjaGVyXCIsZnVuY3Rpb24odCl7dGhpcy5fbGlzdGVuZXJzPXt9LHRoaXMuX2V2ZW50VGFyZ2V0PXR8fHRoaXN9KTtuPVAucHJvdG90eXBlLG4uYWRkRXZlbnRMaXN0ZW5lcj1mdW5jdGlvbih0LGUsaSxzLG4pe249bnx8MDt2YXIgbyxsLGg9dGhpcy5fbGlzdGVuZXJzW3RdLF89MDtmb3IobnVsbD09aCYmKHRoaXMuX2xpc3RlbmVyc1t0XT1oPVtdKSxsPWgubGVuZ3RoOy0tbD4tMTspbz1oW2xdLG8uYz09PWUmJm8ucz09PWk/aC5zcGxpY2UobCwxKTowPT09XyYmbj5vLnByJiYoXz1sKzEpO2guc3BsaWNlKF8sMCx7YzplLHM6aSx1cDpzLHByOm59KSx0aGlzIT09cnx8YXx8ci53YWtlKCl9LG4ucmVtb3ZlRXZlbnRMaXN0ZW5lcj1mdW5jdGlvbih0LGUpe3ZhciBpLHM9dGhpcy5fbGlzdGVuZXJzW3RdO2lmKHMpZm9yKGk9cy5sZW5ndGg7LS1pPi0xOylpZihzW2ldLmM9PT1lKXJldHVybiBzLnNwbGljZShpLDEpLHZvaWQgMH0sbi5kaXNwYXRjaEV2ZW50PWZ1bmN0aW9uKHQpe3ZhciBlLGkscyxuPXRoaXMuX2xpc3RlbmVyc1t0XTtpZihuKWZvcihlPW4ubGVuZ3RoLGk9dGhpcy5fZXZlbnRUYXJnZXQ7LS1lPi0xOylzPW5bZV0scy51cD9zLmMuY2FsbChzLnN8fGkse3R5cGU6dCx0YXJnZXQ6aX0pOnMuYy5jYWxsKHMuc3x8aSl9O3ZhciBrPXQucmVxdWVzdEFuaW1hdGlvbkZyYW1lLGI9dC5jYW5jZWxBbmltYXRpb25GcmFtZSxBPURhdGUubm93fHxmdW5jdGlvbigpe3JldHVybihuZXcgRGF0ZSkuZ2V0VGltZSgpfSxTPUEoKTtmb3IoaT1bXCJtc1wiLFwibW96XCIsXCJ3ZWJraXRcIixcIm9cIl0scz1pLmxlbmd0aDstLXM+LTEmJiFrOylrPXRbaVtzXStcIlJlcXVlc3RBbmltYXRpb25GcmFtZVwiXSxiPXRbaVtzXStcIkNhbmNlbEFuaW1hdGlvbkZyYW1lXCJdfHx0W2lbc10rXCJDYW5jZWxSZXF1ZXN0QW5pbWF0aW9uRnJhbWVcIl07ZChcIlRpY2tlclwiLGZ1bmN0aW9uKHQsZSl7dmFyIGkscyxuLG8sbCxfPXRoaXMsbT1BKCksZj1lIT09ITEmJmsscD01MDAsYz0zMyxkPWZ1bmN0aW9uKHQpe3ZhciBlLHIsYT1BKCktUzthPnAmJihtKz1hLWMpLFMrPWEsXy50aW1lPShTLW0pLzFlMyxlPV8udGltZS1sLCghaXx8ZT4wfHx0PT09ITApJiYoXy5mcmFtZSsrLGwrPWUrKGU+PW8/LjAwNDpvLWUpLHI9ITApLHQhPT0hMCYmKG49cyhkKSksciYmXy5kaXNwYXRjaEV2ZW50KFwidGlja1wiKX07UC5jYWxsKF8pLF8udGltZT1fLmZyYW1lPTAsXy50aWNrPWZ1bmN0aW9uKCl7ZCghMCl9LF8ubGFnU21vb3RoaW5nPWZ1bmN0aW9uKHQsZSl7cD10fHwxL2gsYz1NYXRoLm1pbihlLHAsMCl9LF8uc2xlZXA9ZnVuY3Rpb24oKXtudWxsIT1uJiYoZiYmYj9iKG4pOmNsZWFyVGltZW91dChuKSxzPXUsbj1udWxsLF89PT1yJiYoYT0hMSkpfSxfLndha2U9ZnVuY3Rpb24oKXtudWxsIT09bj9fLnNsZWVwKCk6Xy5mcmFtZT4xMCYmKFM9QSgpLXArNSkscz0wPT09aT91OmYmJms/azpmdW5jdGlvbih0KXtyZXR1cm4gc2V0VGltZW91dCh0LDB8MWUzKihsLV8udGltZSkrMSl9LF89PT1yJiYoYT0hMCksZCgyKX0sXy5mcHM9ZnVuY3Rpb24odCl7cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGg/KGk9dCxvPTEvKGl8fDYwKSxsPXRoaXMudGltZStvLF8ud2FrZSgpLHZvaWQgMCk6aX0sXy51c2VSQUY9ZnVuY3Rpb24odCl7cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGg/KF8uc2xlZXAoKSxmPXQsXy5mcHMoaSksdm9pZCAwKTpmfSxfLmZwcyh0KSxzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7ZiYmKCFufHw1Pl8uZnJhbWUpJiZfLnVzZVJBRighMSl9LDE1MDApfSksbj1sLlRpY2tlci5wcm90b3R5cGU9bmV3IGwuZXZlbnRzLkV2ZW50RGlzcGF0Y2hlcixuLmNvbnN0cnVjdG9yPWwuVGlja2VyO3ZhciB4PWQoXCJjb3JlLkFuaW1hdGlvblwiLGZ1bmN0aW9uKHQsZSl7aWYodGhpcy52YXJzPWU9ZXx8e30sdGhpcy5fZHVyYXRpb249dGhpcy5fdG90YWxEdXJhdGlvbj10fHwwLHRoaXMuX2RlbGF5PU51bWJlcihlLmRlbGF5KXx8MCx0aGlzLl90aW1lU2NhbGU9MSx0aGlzLl9hY3RpdmU9ZS5pbW1lZGlhdGVSZW5kZXI9PT0hMCx0aGlzLmRhdGE9ZS5kYXRhLHRoaXMuX3JldmVyc2VkPWUucmV2ZXJzZWQ9PT0hMCxCKXthfHxyLndha2UoKTt2YXIgaT10aGlzLnZhcnMudXNlRnJhbWVzP1E6QjtpLmFkZCh0aGlzLGkuX3RpbWUpLHRoaXMudmFycy5wYXVzZWQmJnRoaXMucGF1c2VkKCEwKX19KTtyPXgudGlja2VyPW5ldyBsLlRpY2tlcixuPXgucHJvdG90eXBlLG4uX2RpcnR5PW4uX2djPW4uX2luaXR0ZWQ9bi5fcGF1c2VkPSExLG4uX3RvdGFsVGltZT1uLl90aW1lPTAsbi5fcmF3UHJldlRpbWU9LTEsbi5fbmV4dD1uLl9sYXN0PW4uX29uVXBkYXRlPW4uX3RpbWVsaW5lPW4udGltZWxpbmU9bnVsbCxuLl9wYXVzZWQ9ITE7dmFyIEM9ZnVuY3Rpb24oKXthJiZBKCktUz4yZTMmJnIud2FrZSgpLHNldFRpbWVvdXQoQywyZTMpfTtDKCksbi5wbGF5PWZ1bmN0aW9uKHQsZSl7cmV0dXJuIG51bGwhPXQmJnRoaXMuc2Vlayh0LGUpLHRoaXMucmV2ZXJzZWQoITEpLnBhdXNlZCghMSl9LG4ucGF1c2U9ZnVuY3Rpb24odCxlKXtyZXR1cm4gbnVsbCE9dCYmdGhpcy5zZWVrKHQsZSksdGhpcy5wYXVzZWQoITApfSxuLnJlc3VtZT1mdW5jdGlvbih0LGUpe3JldHVybiBudWxsIT10JiZ0aGlzLnNlZWsodCxlKSx0aGlzLnBhdXNlZCghMSl9LG4uc2Vlaz1mdW5jdGlvbih0LGUpe3JldHVybiB0aGlzLnRvdGFsVGltZShOdW1iZXIodCksZSE9PSExKX0sbi5yZXN0YXJ0PWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHRoaXMucmV2ZXJzZWQoITEpLnBhdXNlZCghMSkudG90YWxUaW1lKHQ/LXRoaXMuX2RlbGF5OjAsZSE9PSExLCEwKX0sbi5yZXZlcnNlPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIG51bGwhPXQmJnRoaXMuc2Vlayh0fHx0aGlzLnRvdGFsRHVyYXRpb24oKSxlKSx0aGlzLnJldmVyc2VkKCEwKS5wYXVzZWQoITEpfSxuLnJlbmRlcj1mdW5jdGlvbigpe30sbi5pbnZhbGlkYXRlPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LG4uaXNBY3RpdmU9ZnVuY3Rpb24oKXt2YXIgdCxlPXRoaXMuX3RpbWVsaW5lLGk9dGhpcy5fc3RhcnRUaW1lO3JldHVybiFlfHwhdGhpcy5fZ2MmJiF0aGlzLl9wYXVzZWQmJmUuaXNBY3RpdmUoKSYmKHQ9ZS5yYXdUaW1lKCkpPj1pJiZpK3RoaXMudG90YWxEdXJhdGlvbigpL3RoaXMuX3RpbWVTY2FsZT50fSxuLl9lbmFibGVkPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIGF8fHIud2FrZSgpLHRoaXMuX2djPSF0LHRoaXMuX2FjdGl2ZT10aGlzLmlzQWN0aXZlKCksZSE9PSEwJiYodCYmIXRoaXMudGltZWxpbmU/dGhpcy5fdGltZWxpbmUuYWRkKHRoaXMsdGhpcy5fc3RhcnRUaW1lLXRoaXMuX2RlbGF5KTohdCYmdGhpcy50aW1lbGluZSYmdGhpcy5fdGltZWxpbmUuX3JlbW92ZSh0aGlzLCEwKSksITF9LG4uX2tpbGw9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fZW5hYmxlZCghMSwhMSl9LG4ua2lsbD1mdW5jdGlvbih0LGUpe3JldHVybiB0aGlzLl9raWxsKHQsZSksdGhpc30sbi5fdW5jYWNoZT1mdW5jdGlvbih0KXtmb3IodmFyIGU9dD90aGlzOnRoaXMudGltZWxpbmU7ZTspZS5fZGlydHk9ITAsZT1lLnRpbWVsaW5lO3JldHVybiB0aGlzfSxuLl9zd2FwU2VsZkluUGFyYW1zPWZ1bmN0aW9uKHQpe2Zvcih2YXIgZT10Lmxlbmd0aCxpPXQuY29uY2F0KCk7LS1lPi0xOylcIntzZWxmfVwiPT09dFtlXSYmKGlbZV09dGhpcyk7cmV0dXJuIGl9LG4uZXZlbnRDYWxsYmFjaz1mdW5jdGlvbih0LGUsaSxzKXtpZihcIm9uXCI9PT0odHx8XCJcIikuc3Vic3RyKDAsMikpe3ZhciBuPXRoaXMudmFycztpZigxPT09YXJndW1lbnRzLmxlbmd0aClyZXR1cm4gblt0XTtudWxsPT1lP2RlbGV0ZSBuW3RdOihuW3RdPWUsblt0K1wiUGFyYW1zXCJdPW0oaSkmJi0xIT09aS5qb2luKFwiXCIpLmluZGV4T2YoXCJ7c2VsZn1cIik/dGhpcy5fc3dhcFNlbGZJblBhcmFtcyhpKTppLG5bdCtcIlNjb3BlXCJdPXMpLFwib25VcGRhdGVcIj09PXQmJih0aGlzLl9vblVwZGF0ZT1lKX1yZXR1cm4gdGhpc30sbi5kZWxheT1mdW5jdGlvbih0KXtyZXR1cm4gYXJndW1lbnRzLmxlbmd0aD8odGhpcy5fdGltZWxpbmUuc21vb3RoQ2hpbGRUaW1pbmcmJnRoaXMuc3RhcnRUaW1lKHRoaXMuX3N0YXJ0VGltZSt0LXRoaXMuX2RlbGF5KSx0aGlzLl9kZWxheT10LHRoaXMpOnRoaXMuX2RlbGF5fSxuLmR1cmF0aW9uPWZ1bmN0aW9uKHQpe3JldHVybiBhcmd1bWVudHMubGVuZ3RoPyh0aGlzLl9kdXJhdGlvbj10aGlzLl90b3RhbER1cmF0aW9uPXQsdGhpcy5fdW5jYWNoZSghMCksdGhpcy5fdGltZWxpbmUuc21vb3RoQ2hpbGRUaW1pbmcmJnRoaXMuX3RpbWU+MCYmdGhpcy5fdGltZTx0aGlzLl9kdXJhdGlvbiYmMCE9PXQmJnRoaXMudG90YWxUaW1lKHRoaXMuX3RvdGFsVGltZSoodC90aGlzLl9kdXJhdGlvbiksITApLHRoaXMpOih0aGlzLl9kaXJ0eT0hMSx0aGlzLl9kdXJhdGlvbil9LG4udG90YWxEdXJhdGlvbj1mdW5jdGlvbih0KXtyZXR1cm4gdGhpcy5fZGlydHk9ITEsYXJndW1lbnRzLmxlbmd0aD90aGlzLmR1cmF0aW9uKHQpOnRoaXMuX3RvdGFsRHVyYXRpb259LG4udGltZT1mdW5jdGlvbih0LGUpe3JldHVybiBhcmd1bWVudHMubGVuZ3RoPyh0aGlzLl9kaXJ0eSYmdGhpcy50b3RhbER1cmF0aW9uKCksdGhpcy50b3RhbFRpbWUodD50aGlzLl9kdXJhdGlvbj90aGlzLl9kdXJhdGlvbjp0LGUpKTp0aGlzLl90aW1lfSxuLnRvdGFsVGltZT1mdW5jdGlvbih0LGUsaSl7aWYoYXx8ci53YWtlKCksIWFyZ3VtZW50cy5sZW5ndGgpcmV0dXJuIHRoaXMuX3RvdGFsVGltZTtpZih0aGlzLl90aW1lbGluZSl7aWYoMD50JiYhaSYmKHQrPXRoaXMudG90YWxEdXJhdGlvbigpKSx0aGlzLl90aW1lbGluZS5zbW9vdGhDaGlsZFRpbWluZyl7dGhpcy5fZGlydHkmJnRoaXMudG90YWxEdXJhdGlvbigpO3ZhciBzPXRoaXMuX3RvdGFsRHVyYXRpb24sbj10aGlzLl90aW1lbGluZTtpZih0PnMmJiFpJiYodD1zKSx0aGlzLl9zdGFydFRpbWU9KHRoaXMuX3BhdXNlZD90aGlzLl9wYXVzZVRpbWU6bi5fdGltZSktKHRoaXMuX3JldmVyc2VkP3MtdDp0KS90aGlzLl90aW1lU2NhbGUsbi5fZGlydHl8fHRoaXMuX3VuY2FjaGUoITEpLG4uX3RpbWVsaW5lKWZvcig7bi5fdGltZWxpbmU7KW4uX3RpbWVsaW5lLl90aW1lIT09KG4uX3N0YXJ0VGltZStuLl90b3RhbFRpbWUpL24uX3RpbWVTY2FsZSYmbi50b3RhbFRpbWUobi5fdG90YWxUaW1lLCEwKSxuPW4uX3RpbWVsaW5lfXRoaXMuX2djJiZ0aGlzLl9lbmFibGVkKCEwLCExKSwodGhpcy5fdG90YWxUaW1lIT09dHx8MD09PXRoaXMuX2R1cmF0aW9uKSYmKHRoaXMucmVuZGVyKHQsZSwhMSksei5sZW5ndGgmJnEoKSl9cmV0dXJuIHRoaXN9LG4ucHJvZ3Jlc3M9bi50b3RhbFByb2dyZXNzPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGg/dGhpcy50b3RhbFRpbWUodGhpcy5kdXJhdGlvbigpKnQsZSk6dGhpcy5fdGltZS90aGlzLmR1cmF0aW9uKCl9LG4uc3RhcnRUaW1lPWZ1bmN0aW9uKHQpe3JldHVybiBhcmd1bWVudHMubGVuZ3RoPyh0IT09dGhpcy5fc3RhcnRUaW1lJiYodGhpcy5fc3RhcnRUaW1lPXQsdGhpcy50aW1lbGluZSYmdGhpcy50aW1lbGluZS5fc29ydENoaWxkcmVuJiZ0aGlzLnRpbWVsaW5lLmFkZCh0aGlzLHQtdGhpcy5fZGVsYXkpKSx0aGlzKTp0aGlzLl9zdGFydFRpbWV9LG4udGltZVNjYWxlPWZ1bmN0aW9uKHQpe2lmKCFhcmd1bWVudHMubGVuZ3RoKXJldHVybiB0aGlzLl90aW1lU2NhbGU7aWYodD10fHxoLHRoaXMuX3RpbWVsaW5lJiZ0aGlzLl90aW1lbGluZS5zbW9vdGhDaGlsZFRpbWluZyl7dmFyIGU9dGhpcy5fcGF1c2VUaW1lLGk9ZXx8MD09PWU/ZTp0aGlzLl90aW1lbGluZS50b3RhbFRpbWUoKTt0aGlzLl9zdGFydFRpbWU9aS0oaS10aGlzLl9zdGFydFRpbWUpKnRoaXMuX3RpbWVTY2FsZS90fXJldHVybiB0aGlzLl90aW1lU2NhbGU9dCx0aGlzLl91bmNhY2hlKCExKX0sbi5yZXZlcnNlZD1mdW5jdGlvbih0KXtyZXR1cm4gYXJndW1lbnRzLmxlbmd0aD8odCE9dGhpcy5fcmV2ZXJzZWQmJih0aGlzLl9yZXZlcnNlZD10LHRoaXMudG90YWxUaW1lKHRoaXMuX3RpbWVsaW5lJiYhdGhpcy5fdGltZWxpbmUuc21vb3RoQ2hpbGRUaW1pbmc/dGhpcy50b3RhbER1cmF0aW9uKCktdGhpcy5fdG90YWxUaW1lOnRoaXMuX3RvdGFsVGltZSwhMCkpLHRoaXMpOnRoaXMuX3JldmVyc2VkfSxuLnBhdXNlZD1mdW5jdGlvbih0KXtpZighYXJndW1lbnRzLmxlbmd0aClyZXR1cm4gdGhpcy5fcGF1c2VkO2lmKHQhPXRoaXMuX3BhdXNlZCYmdGhpcy5fdGltZWxpbmUpe2F8fHR8fHIud2FrZSgpO3ZhciBlPXRoaXMuX3RpbWVsaW5lLGk9ZS5yYXdUaW1lKCkscz1pLXRoaXMuX3BhdXNlVGltZTshdCYmZS5zbW9vdGhDaGlsZFRpbWluZyYmKHRoaXMuX3N0YXJ0VGltZSs9cyx0aGlzLl91bmNhY2hlKCExKSksdGhpcy5fcGF1c2VUaW1lPXQ/aTpudWxsLHRoaXMuX3BhdXNlZD10LHRoaXMuX2FjdGl2ZT10aGlzLmlzQWN0aXZlKCksIXQmJjAhPT1zJiZ0aGlzLl9pbml0dGVkJiZ0aGlzLmR1cmF0aW9uKCkmJnRoaXMucmVuZGVyKGUuc21vb3RoQ2hpbGRUaW1pbmc/dGhpcy5fdG90YWxUaW1lOihpLXRoaXMuX3N0YXJ0VGltZSkvdGhpcy5fdGltZVNjYWxlLCEwLCEwKX1yZXR1cm4gdGhpcy5fZ2MmJiF0JiZ0aGlzLl9lbmFibGVkKCEwLCExKSx0aGlzfTt2YXIgUj1kKFwiY29yZS5TaW1wbGVUaW1lbGluZVwiLGZ1bmN0aW9uKHQpe3guY2FsbCh0aGlzLDAsdCksdGhpcy5hdXRvUmVtb3ZlQ2hpbGRyZW49dGhpcy5zbW9vdGhDaGlsZFRpbWluZz0hMH0pO249Ui5wcm90b3R5cGU9bmV3IHgsbi5jb25zdHJ1Y3Rvcj1SLG4ua2lsbCgpLl9nYz0hMSxuLl9maXJzdD1uLl9sYXN0PW51bGwsbi5fc29ydENoaWxkcmVuPSExLG4uYWRkPW4uaW5zZXJ0PWZ1bmN0aW9uKHQsZSl7dmFyIGkscztpZih0Ll9zdGFydFRpbWU9TnVtYmVyKGV8fDApK3QuX2RlbGF5LHQuX3BhdXNlZCYmdGhpcyE9PXQuX3RpbWVsaW5lJiYodC5fcGF1c2VUaW1lPXQuX3N0YXJ0VGltZSsodGhpcy5yYXdUaW1lKCktdC5fc3RhcnRUaW1lKS90Ll90aW1lU2NhbGUpLHQudGltZWxpbmUmJnQudGltZWxpbmUuX3JlbW92ZSh0LCEwKSx0LnRpbWVsaW5lPXQuX3RpbWVsaW5lPXRoaXMsdC5fZ2MmJnQuX2VuYWJsZWQoITAsITApLGk9dGhpcy5fbGFzdCx0aGlzLl9zb3J0Q2hpbGRyZW4pZm9yKHM9dC5fc3RhcnRUaW1lO2kmJmkuX3N0YXJ0VGltZT5zOylpPWkuX3ByZXY7cmV0dXJuIGk/KHQuX25leHQ9aS5fbmV4dCxpLl9uZXh0PXQpOih0Ll9uZXh0PXRoaXMuX2ZpcnN0LHRoaXMuX2ZpcnN0PXQpLHQuX25leHQ/dC5fbmV4dC5fcHJldj10OnRoaXMuX2xhc3Q9dCx0Ll9wcmV2PWksdGhpcy5fdGltZWxpbmUmJnRoaXMuX3VuY2FjaGUoITApLHRoaXN9LG4uX3JlbW92ZT1mdW5jdGlvbih0LGUpe3JldHVybiB0LnRpbWVsaW5lPT09dGhpcyYmKGV8fHQuX2VuYWJsZWQoITEsITApLHQudGltZWxpbmU9bnVsbCx0Ll9wcmV2P3QuX3ByZXYuX25leHQ9dC5fbmV4dDp0aGlzLl9maXJzdD09PXQmJih0aGlzLl9maXJzdD10Ll9uZXh0KSx0Ll9uZXh0P3QuX25leHQuX3ByZXY9dC5fcHJldjp0aGlzLl9sYXN0PT09dCYmKHRoaXMuX2xhc3Q9dC5fcHJldiksdGhpcy5fdGltZWxpbmUmJnRoaXMuX3VuY2FjaGUoITApKSx0aGlzfSxuLnJlbmRlcj1mdW5jdGlvbih0LGUsaSl7dmFyIHMsbj10aGlzLl9maXJzdDtmb3IodGhpcy5fdG90YWxUaW1lPXRoaXMuX3RpbWU9dGhpcy5fcmF3UHJldlRpbWU9dDtuOylzPW4uX25leHQsKG4uX2FjdGl2ZXx8dD49bi5fc3RhcnRUaW1lJiYhbi5fcGF1c2VkKSYmKG4uX3JldmVyc2VkP24ucmVuZGVyKChuLl9kaXJ0eT9uLnRvdGFsRHVyYXRpb24oKTpuLl90b3RhbER1cmF0aW9uKS0odC1uLl9zdGFydFRpbWUpKm4uX3RpbWVTY2FsZSxlLGkpOm4ucmVuZGVyKCh0LW4uX3N0YXJ0VGltZSkqbi5fdGltZVNjYWxlLGUsaSkpLG49c30sbi5yYXdUaW1lPWZ1bmN0aW9uKCl7cmV0dXJuIGF8fHIud2FrZSgpLHRoaXMuX3RvdGFsVGltZX07dmFyIEQ9ZChcIlR3ZWVuTGl0ZVwiLGZ1bmN0aW9uKGUsaSxzKXtpZih4LmNhbGwodGhpcyxpLHMpLHRoaXMucmVuZGVyPUQucHJvdG90eXBlLnJlbmRlcixudWxsPT1lKXRocm93XCJDYW5ub3QgdHdlZW4gYSBudWxsIHRhcmdldC5cIjt0aGlzLnRhcmdldD1lPVwic3RyaW5nXCIhPXR5cGVvZiBlP2U6RC5zZWxlY3RvcihlKXx8ZTt2YXIgbixyLGEsbz1lLmpxdWVyeXx8ZS5sZW5ndGgmJmUhPT10JiZlWzBdJiYoZVswXT09PXR8fGVbMF0ubm9kZVR5cGUmJmVbMF0uc3R5bGUmJiFlLm5vZGVUeXBlKSxsPXRoaXMudmFycy5vdmVyd3JpdGU7aWYodGhpcy5fb3ZlcndyaXRlPWw9bnVsbD09bD9HW0QuZGVmYXVsdE92ZXJ3cml0ZV06XCJudW1iZXJcIj09dHlwZW9mIGw/bD4+MDpHW2xdLChvfHxlIGluc3RhbmNlb2YgQXJyYXl8fGUucHVzaCYmbShlKSkmJlwibnVtYmVyXCIhPXR5cGVvZiBlWzBdKWZvcih0aGlzLl90YXJnZXRzPWE9Xy5jYWxsKGUsMCksdGhpcy5fcHJvcExvb2t1cD1bXSx0aGlzLl9zaWJsaW5ncz1bXSxuPTA7YS5sZW5ndGg+bjtuKyspcj1hW25dLHI/XCJzdHJpbmdcIiE9dHlwZW9mIHI/ci5sZW5ndGgmJnIhPT10JiZyWzBdJiYoclswXT09PXR8fHJbMF0ubm9kZVR5cGUmJnJbMF0uc3R5bGUmJiFyLm5vZGVUeXBlKT8oYS5zcGxpY2Uobi0tLDEpLHRoaXMuX3RhcmdldHM9YT1hLmNvbmNhdChfLmNhbGwociwwKSkpOih0aGlzLl9zaWJsaW5nc1tuXT1NKHIsdGhpcywhMSksMT09PWwmJnRoaXMuX3NpYmxpbmdzW25dLmxlbmd0aD4xJiYkKHIsdGhpcyxudWxsLDEsdGhpcy5fc2libGluZ3Nbbl0pKToocj1hW24tLV09RC5zZWxlY3RvcihyKSxcInN0cmluZ1wiPT10eXBlb2YgciYmYS5zcGxpY2UobisxLDEpKTphLnNwbGljZShuLS0sMSk7ZWxzZSB0aGlzLl9wcm9wTG9va3VwPXt9LHRoaXMuX3NpYmxpbmdzPU0oZSx0aGlzLCExKSwxPT09bCYmdGhpcy5fc2libGluZ3MubGVuZ3RoPjEmJiQoZSx0aGlzLG51bGwsMSx0aGlzLl9zaWJsaW5ncyk7KHRoaXMudmFycy5pbW1lZGlhdGVSZW5kZXJ8fDA9PT1pJiYwPT09dGhpcy5fZGVsYXkmJnRoaXMudmFycy5pbW1lZGlhdGVSZW5kZXIhPT0hMSkmJih0aGlzLl90aW1lPS1oLHRoaXMucmVuZGVyKC10aGlzLl9kZWxheSkpfSwhMCksST1mdW5jdGlvbihlKXtyZXR1cm4gZS5sZW5ndGgmJmUhPT10JiZlWzBdJiYoZVswXT09PXR8fGVbMF0ubm9kZVR5cGUmJmVbMF0uc3R5bGUmJiFlLm5vZGVUeXBlKX0sRT1mdW5jdGlvbih0LGUpe3ZhciBpLHM9e307Zm9yKGkgaW4gdClqW2ldfHxpIGluIGUmJlwidHJhbnNmb3JtXCIhPT1pJiZcInhcIiE9PWkmJlwieVwiIT09aSYmXCJ3aWR0aFwiIT09aSYmXCJoZWlnaHRcIiE9PWkmJlwiY2xhc3NOYW1lXCIhPT1pJiZcImJvcmRlclwiIT09aXx8ISghTFtpXXx8TFtpXSYmTFtpXS5fYXV0b0NTUyl8fChzW2ldPXRbaV0sZGVsZXRlIHRbaV0pO3QuY3NzPXN9O249RC5wcm90b3R5cGU9bmV3IHgsbi5jb25zdHJ1Y3Rvcj1ELG4ua2lsbCgpLl9nYz0hMSxuLnJhdGlvPTAsbi5fZmlyc3RQVD1uLl90YXJnZXRzPW4uX292ZXJ3cml0dGVuUHJvcHM9bi5fc3RhcnRBdD1udWxsLG4uX25vdGlmeVBsdWdpbnNPZkVuYWJsZWQ9bi5fbGF6eT0hMSxELnZlcnNpb249XCIxLjEyLjFcIixELmRlZmF1bHRFYXNlPW4uX2Vhc2U9bmV3IFQobnVsbCxudWxsLDEsMSksRC5kZWZhdWx0T3ZlcndyaXRlPVwiYXV0b1wiLEQudGlja2VyPXIsRC5hdXRvU2xlZXA9ITAsRC5sYWdTbW9vdGhpbmc9ZnVuY3Rpb24odCxlKXtyLmxhZ1Ntb290aGluZyh0LGUpfSxELnNlbGVjdG9yPXQuJHx8dC5qUXVlcnl8fGZ1bmN0aW9uKGUpe3JldHVybiB0LiQ/KEQuc2VsZWN0b3I9dC4kLHQuJChlKSk6dC5kb2N1bWVudD90LmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwiI1wiPT09ZS5jaGFyQXQoMCk/ZS5zdWJzdHIoMSk6ZSk6ZX07dmFyIHo9W10sTz17fSxOPUQuX2ludGVybmFscz17aXNBcnJheTptLGlzU2VsZWN0b3I6SSxsYXp5VHdlZW5zOnp9LEw9RC5fcGx1Z2lucz17fSxVPU4udHdlZW5Mb29rdXA9e30sRj0wLGo9Ti5yZXNlcnZlZFByb3BzPXtlYXNlOjEsZGVsYXk6MSxvdmVyd3JpdGU6MSxvbkNvbXBsZXRlOjEsb25Db21wbGV0ZVBhcmFtczoxLG9uQ29tcGxldGVTY29wZToxLHVzZUZyYW1lczoxLHJ1bkJhY2t3YXJkczoxLHN0YXJ0QXQ6MSxvblVwZGF0ZToxLG9uVXBkYXRlUGFyYW1zOjEsb25VcGRhdGVTY29wZToxLG9uU3RhcnQ6MSxvblN0YXJ0UGFyYW1zOjEsb25TdGFydFNjb3BlOjEsb25SZXZlcnNlQ29tcGxldGU6MSxvblJldmVyc2VDb21wbGV0ZVBhcmFtczoxLG9uUmV2ZXJzZUNvbXBsZXRlU2NvcGU6MSxvblJlcGVhdDoxLG9uUmVwZWF0UGFyYW1zOjEsb25SZXBlYXRTY29wZToxLGVhc2VQYXJhbXM6MSx5b3lvOjEsaW1tZWRpYXRlUmVuZGVyOjEscmVwZWF0OjEscmVwZWF0RGVsYXk6MSxkYXRhOjEscGF1c2VkOjEscmV2ZXJzZWQ6MSxhdXRvQ1NTOjEsbGF6eToxfSxHPXtub25lOjAsYWxsOjEsYXV0bzoyLGNvbmN1cnJlbnQ6MyxhbGxPblN0YXJ0OjQscHJlZXhpc3Rpbmc6NSxcInRydWVcIjoxLFwiZmFsc2VcIjowfSxRPXguX3Jvb3RGcmFtZXNUaW1lbGluZT1uZXcgUixCPXguX3Jvb3RUaW1lbGluZT1uZXcgUixxPWZ1bmN0aW9uKCl7dmFyIHQ9ei5sZW5ndGg7Zm9yKE89e307LS10Pi0xOylpPXpbdF0saSYmaS5fbGF6eSE9PSExJiYoaS5yZW5kZXIoaS5fbGF6eSwhMSwhMCksaS5fbGF6eT0hMSk7ei5sZW5ndGg9MH07Qi5fc3RhcnRUaW1lPXIudGltZSxRLl9zdGFydFRpbWU9ci5mcmFtZSxCLl9hY3RpdmU9US5fYWN0aXZlPSEwLHNldFRpbWVvdXQocSwxKSx4Ll91cGRhdGVSb290PUQucmVuZGVyPWZ1bmN0aW9uKCl7dmFyIHQsZSxpO2lmKHoubGVuZ3RoJiZxKCksQi5yZW5kZXIoKHIudGltZS1CLl9zdGFydFRpbWUpKkIuX3RpbWVTY2FsZSwhMSwhMSksUS5yZW5kZXIoKHIuZnJhbWUtUS5fc3RhcnRUaW1lKSpRLl90aW1lU2NhbGUsITEsITEpLHoubGVuZ3RoJiZxKCksIShyLmZyYW1lJTEyMCkpe2ZvcihpIGluIFUpe2ZvcihlPVVbaV0udHdlZW5zLHQ9ZS5sZW5ndGg7LS10Pi0xOyllW3RdLl9nYyYmZS5zcGxpY2UodCwxKTswPT09ZS5sZW5ndGgmJmRlbGV0ZSBVW2ldfWlmKGk9Qi5fZmlyc3QsKCFpfHxpLl9wYXVzZWQpJiZELmF1dG9TbGVlcCYmIVEuX2ZpcnN0JiYxPT09ci5fbGlzdGVuZXJzLnRpY2subGVuZ3RoKXtmb3IoO2kmJmkuX3BhdXNlZDspaT1pLl9uZXh0O2l8fHIuc2xlZXAoKX19fSxyLmFkZEV2ZW50TGlzdGVuZXIoXCJ0aWNrXCIseC5fdXBkYXRlUm9vdCk7dmFyIE09ZnVuY3Rpb24odCxlLGkpe3ZhciBzLG4scj10Ll9nc1R3ZWVuSUQ7aWYoVVtyfHwodC5fZ3NUd2VlbklEPXI9XCJ0XCIrRisrKV18fChVW3JdPXt0YXJnZXQ6dCx0d2VlbnM6W119KSxlJiYocz1VW3JdLnR3ZWVucyxzW249cy5sZW5ndGhdPWUsaSkpZm9yKDstLW4+LTE7KXNbbl09PT1lJiZzLnNwbGljZShuLDEpO3JldHVybiBVW3JdLnR3ZWVuc30sJD1mdW5jdGlvbih0LGUsaSxzLG4pe3ZhciByLGEsbyxsO2lmKDE9PT1zfHxzPj00KXtmb3IobD1uLmxlbmd0aCxyPTA7bD5yO3IrKylpZigobz1uW3JdKSE9PWUpby5fZ2N8fG8uX2VuYWJsZWQoITEsITEpJiYoYT0hMCk7ZWxzZSBpZig1PT09cylicmVhaztyZXR1cm4gYX12YXIgXyx1PWUuX3N0YXJ0VGltZStoLG09W10sZj0wLHA9MD09PWUuX2R1cmF0aW9uO2ZvcihyPW4ubGVuZ3RoOy0tcj4tMTspKG89bltyXSk9PT1lfHxvLl9nY3x8by5fcGF1c2VkfHwoby5fdGltZWxpbmUhPT1lLl90aW1lbGluZT8oXz1ffHxLKGUsMCxwKSwwPT09SyhvLF8scCkmJihtW2YrK109bykpOnU+PW8uX3N0YXJ0VGltZSYmby5fc3RhcnRUaW1lK28udG90YWxEdXJhdGlvbigpL28uX3RpbWVTY2FsZT51JiYoKHB8fCFvLl9pbml0dGVkKSYmMmUtMTA+PXUtby5fc3RhcnRUaW1lfHwobVtmKytdPW8pKSk7Zm9yKHI9ZjstLXI+LTE7KW89bVtyXSwyPT09cyYmby5fa2lsbChpLHQpJiYoYT0hMCksKDIhPT1zfHwhby5fZmlyc3RQVCYmby5faW5pdHRlZCkmJm8uX2VuYWJsZWQoITEsITEpJiYoYT0hMCk7cmV0dXJuIGF9LEs9ZnVuY3Rpb24odCxlLGkpe2Zvcih2YXIgcz10Ll90aW1lbGluZSxuPXMuX3RpbWVTY2FsZSxyPXQuX3N0YXJ0VGltZTtzLl90aW1lbGluZTspe2lmKHIrPXMuX3N0YXJ0VGltZSxuKj1zLl90aW1lU2NhbGUscy5fcGF1c2VkKXJldHVybi0xMDA7cz1zLl90aW1lbGluZX1yZXR1cm4gci89bixyPmU/ci1lOmkmJnI9PT1lfHwhdC5faW5pdHRlZCYmMipoPnItZT9oOihyKz10LnRvdGFsRHVyYXRpb24oKS90Ll90aW1lU2NhbGUvbik+ZStoPzA6ci1lLWh9O24uX2luaXQ9ZnVuY3Rpb24oKXt2YXIgdCxlLGkscyxuLHI9dGhpcy52YXJzLGE9dGhpcy5fb3ZlcndyaXR0ZW5Qcm9wcyxvPXRoaXMuX2R1cmF0aW9uLGw9ISFyLmltbWVkaWF0ZVJlbmRlcixoPXIuZWFzZTtpZihyLnN0YXJ0QXQpe3RoaXMuX3N0YXJ0QXQmJih0aGlzLl9zdGFydEF0LnJlbmRlcigtMSwhMCksdGhpcy5fc3RhcnRBdC5raWxsKCkpLG49e307Zm9yKHMgaW4gci5zdGFydEF0KW5bc109ci5zdGFydEF0W3NdO2lmKG4ub3ZlcndyaXRlPSExLG4uaW1tZWRpYXRlUmVuZGVyPSEwLG4ubGF6eT1sJiZyLmxhenkhPT0hMSxuLnN0YXJ0QXQ9bi5kZWxheT1udWxsLHRoaXMuX3N0YXJ0QXQ9RC50byh0aGlzLnRhcmdldCwwLG4pLGwpaWYodGhpcy5fdGltZT4wKXRoaXMuX3N0YXJ0QXQ9bnVsbDtlbHNlIGlmKDAhPT1vKXJldHVybn1lbHNlIGlmKHIucnVuQmFja3dhcmRzJiYwIT09bylpZih0aGlzLl9zdGFydEF0KXRoaXMuX3N0YXJ0QXQucmVuZGVyKC0xLCEwKSx0aGlzLl9zdGFydEF0LmtpbGwoKSx0aGlzLl9zdGFydEF0PW51bGw7ZWxzZXtpPXt9O2ZvcihzIGluIHIpaltzXSYmXCJhdXRvQ1NTXCIhPT1zfHwoaVtzXT1yW3NdKTtpZihpLm92ZXJ3cml0ZT0wLGkuZGF0YT1cImlzRnJvbVN0YXJ0XCIsaS5sYXp5PWwmJnIubGF6eSE9PSExLGkuaW1tZWRpYXRlUmVuZGVyPWwsdGhpcy5fc3RhcnRBdD1ELnRvKHRoaXMudGFyZ2V0LDAsaSksbCl7aWYoMD09PXRoaXMuX3RpbWUpcmV0dXJufWVsc2UgdGhpcy5fc3RhcnRBdC5faW5pdCgpLHRoaXMuX3N0YXJ0QXQuX2VuYWJsZWQoITEpfWlmKHRoaXMuX2Vhc2U9aD9oIGluc3RhbmNlb2YgVD9yLmVhc2VQYXJhbXMgaW5zdGFuY2VvZiBBcnJheT9oLmNvbmZpZy5hcHBseShoLHIuZWFzZVBhcmFtcyk6aDpcImZ1bmN0aW9uXCI9PXR5cGVvZiBoP25ldyBUKGgsci5lYXNlUGFyYW1zKTp5W2hdfHxELmRlZmF1bHRFYXNlOkQuZGVmYXVsdEVhc2UsdGhpcy5fZWFzZVR5cGU9dGhpcy5fZWFzZS5fdHlwZSx0aGlzLl9lYXNlUG93ZXI9dGhpcy5fZWFzZS5fcG93ZXIsdGhpcy5fZmlyc3RQVD1udWxsLHRoaXMuX3RhcmdldHMpZm9yKHQ9dGhpcy5fdGFyZ2V0cy5sZW5ndGg7LS10Pi0xOyl0aGlzLl9pbml0UHJvcHModGhpcy5fdGFyZ2V0c1t0XSx0aGlzLl9wcm9wTG9va3VwW3RdPXt9LHRoaXMuX3NpYmxpbmdzW3RdLGE/YVt0XTpudWxsKSYmKGU9ITApO2Vsc2UgZT10aGlzLl9pbml0UHJvcHModGhpcy50YXJnZXQsdGhpcy5fcHJvcExvb2t1cCx0aGlzLl9zaWJsaW5ncyxhKTtpZihlJiZELl9vblBsdWdpbkV2ZW50KFwiX29uSW5pdEFsbFByb3BzXCIsdGhpcyksYSYmKHRoaXMuX2ZpcnN0UFR8fFwiZnVuY3Rpb25cIiE9dHlwZW9mIHRoaXMudGFyZ2V0JiZ0aGlzLl9lbmFibGVkKCExLCExKSksci5ydW5CYWNrd2FyZHMpZm9yKGk9dGhpcy5fZmlyc3RQVDtpOylpLnMrPWkuYyxpLmM9LWkuYyxpPWkuX25leHQ7dGhpcy5fb25VcGRhdGU9ci5vblVwZGF0ZSx0aGlzLl9pbml0dGVkPSEwfSxuLl9pbml0UHJvcHM9ZnVuY3Rpb24oZSxpLHMsbil7dmFyIHIsYSxvLGwsaCxfO2lmKG51bGw9PWUpcmV0dXJuITE7T1tlLl9nc1R3ZWVuSURdJiZxKCksdGhpcy52YXJzLmNzc3x8ZS5zdHlsZSYmZSE9PXQmJmUubm9kZVR5cGUmJkwuY3NzJiZ0aGlzLnZhcnMuYXV0b0NTUyE9PSExJiZFKHRoaXMudmFycyxlKTtmb3IociBpbiB0aGlzLnZhcnMpe2lmKF89dGhpcy52YXJzW3JdLGpbcl0pXyYmKF8gaW5zdGFuY2VvZiBBcnJheXx8Xy5wdXNoJiZtKF8pKSYmLTEhPT1fLmpvaW4oXCJcIikuaW5kZXhPZihcIntzZWxmfVwiKSYmKHRoaXMudmFyc1tyXT1fPXRoaXMuX3N3YXBTZWxmSW5QYXJhbXMoXyx0aGlzKSk7ZWxzZSBpZihMW3JdJiYobD1uZXcgTFtyXSkuX29uSW5pdFR3ZWVuKGUsdGhpcy52YXJzW3JdLHRoaXMpKXtmb3IodGhpcy5fZmlyc3RQVD1oPXtfbmV4dDp0aGlzLl9maXJzdFBULHQ6bCxwOlwic2V0UmF0aW9cIixzOjAsYzoxLGY6ITAsbjpyLHBnOiEwLHByOmwuX3ByaW9yaXR5fSxhPWwuX292ZXJ3cml0ZVByb3BzLmxlbmd0aDstLWE+LTE7KWlbbC5fb3ZlcndyaXRlUHJvcHNbYV1dPXRoaXMuX2ZpcnN0UFQ7KGwuX3ByaW9yaXR5fHxsLl9vbkluaXRBbGxQcm9wcykmJihvPSEwKSwobC5fb25EaXNhYmxlfHxsLl9vbkVuYWJsZSkmJih0aGlzLl9ub3RpZnlQbHVnaW5zT2ZFbmFibGVkPSEwKX1lbHNlIHRoaXMuX2ZpcnN0UFQ9aVtyXT1oPXtfbmV4dDp0aGlzLl9maXJzdFBULHQ6ZSxwOnIsZjpcImZ1bmN0aW9uXCI9PXR5cGVvZiBlW3JdLG46cixwZzohMSxwcjowfSxoLnM9aC5mP2Vbci5pbmRleE9mKFwic2V0XCIpfHxcImZ1bmN0aW9uXCIhPXR5cGVvZiBlW1wiZ2V0XCIrci5zdWJzdHIoMyldP3I6XCJnZXRcIityLnN1YnN0cigzKV0oKTpwYXJzZUZsb2F0KGVbcl0pLGguYz1cInN0cmluZ1wiPT10eXBlb2YgXyYmXCI9XCI9PT1fLmNoYXJBdCgxKT9wYXJzZUludChfLmNoYXJBdCgwKStcIjFcIiwxMCkqTnVtYmVyKF8uc3Vic3RyKDIpKTpOdW1iZXIoXyktaC5zfHwwO2gmJmguX25leHQmJihoLl9uZXh0Ll9wcmV2PWgpfXJldHVybiBuJiZ0aGlzLl9raWxsKG4sZSk/dGhpcy5faW5pdFByb3BzKGUsaSxzLG4pOnRoaXMuX292ZXJ3cml0ZT4xJiZ0aGlzLl9maXJzdFBUJiZzLmxlbmd0aD4xJiYkKGUsdGhpcyxpLHRoaXMuX292ZXJ3cml0ZSxzKT8odGhpcy5fa2lsbChpLGUpLHRoaXMuX2luaXRQcm9wcyhlLGkscyxuKSk6KHRoaXMuX2ZpcnN0UFQmJih0aGlzLnZhcnMubGF6eSE9PSExJiZ0aGlzLl9kdXJhdGlvbnx8dGhpcy52YXJzLmxhenkmJiF0aGlzLl9kdXJhdGlvbikmJihPW2UuX2dzVHdlZW5JRF09ITApLG8pfSxuLnJlbmRlcj1mdW5jdGlvbih0LGUsaSl7dmFyIHMsbixyLGEsbz10aGlzLl90aW1lLGw9dGhpcy5fZHVyYXRpb24sXz10aGlzLl9yYXdQcmV2VGltZTtpZih0Pj1sKXRoaXMuX3RvdGFsVGltZT10aGlzLl90aW1lPWwsdGhpcy5yYXRpbz10aGlzLl9lYXNlLl9jYWxjRW5kP3RoaXMuX2Vhc2UuZ2V0UmF0aW8oMSk6MSx0aGlzLl9yZXZlcnNlZHx8KHM9ITAsbj1cIm9uQ29tcGxldGVcIiksMD09PWwmJih0aGlzLl9pbml0dGVkfHwhdGhpcy52YXJzLmxhenl8fGkpJiYodGhpcy5fc3RhcnRUaW1lPT09dGhpcy5fdGltZWxpbmUuX2R1cmF0aW9uJiYodD0wKSwoMD09PXR8fDA+X3x8Xz09PWgpJiZfIT09dCYmKGk9ITAsXz5oJiYobj1cIm9uUmV2ZXJzZUNvbXBsZXRlXCIpKSx0aGlzLl9yYXdQcmV2VGltZT1hPSFlfHx0fHxfPT09dD90OmgpO2Vsc2UgaWYoMWUtNz50KXRoaXMuX3RvdGFsVGltZT10aGlzLl90aW1lPTAsdGhpcy5yYXRpbz10aGlzLl9lYXNlLl9jYWxjRW5kP3RoaXMuX2Vhc2UuZ2V0UmF0aW8oMCk6MCwoMCE9PW98fDA9PT1sJiZfPjAmJl8hPT1oKSYmKG49XCJvblJldmVyc2VDb21wbGV0ZVwiLHM9dGhpcy5fcmV2ZXJzZWQpLDA+dD8odGhpcy5fYWN0aXZlPSExLDA9PT1sJiYodGhpcy5faW5pdHRlZHx8IXRoaXMudmFycy5sYXp5fHxpKSYmKF8+PTAmJihpPSEwKSx0aGlzLl9yYXdQcmV2VGltZT1hPSFlfHx0fHxfPT09dD90OmgpKTp0aGlzLl9pbml0dGVkfHwoaT0hMCk7ZWxzZSBpZih0aGlzLl90b3RhbFRpbWU9dGhpcy5fdGltZT10LHRoaXMuX2Vhc2VUeXBlKXt2YXIgdT10L2wsbT10aGlzLl9lYXNlVHlwZSxmPXRoaXMuX2Vhc2VQb3dlcjsoMT09PW18fDM9PT1tJiZ1Pj0uNSkmJih1PTEtdSksMz09PW0mJih1Kj0yKSwxPT09Zj91Kj11OjI9PT1mP3UqPXUqdTozPT09Zj91Kj11KnUqdTo0PT09ZiYmKHUqPXUqdSp1KnUpLHRoaXMucmF0aW89MT09PW0/MS11OjI9PT1tP3U6LjU+dC9sP3UvMjoxLXUvMn1lbHNlIHRoaXMucmF0aW89dGhpcy5fZWFzZS5nZXRSYXRpbyh0L2wpO2lmKHRoaXMuX3RpbWUhPT1vfHxpKXtpZighdGhpcy5faW5pdHRlZCl7aWYodGhpcy5faW5pdCgpLCF0aGlzLl9pbml0dGVkfHx0aGlzLl9nYylyZXR1cm47aWYoIWkmJnRoaXMuX2ZpcnN0UFQmJih0aGlzLnZhcnMubGF6eSE9PSExJiZ0aGlzLl9kdXJhdGlvbnx8dGhpcy52YXJzLmxhenkmJiF0aGlzLl9kdXJhdGlvbikpcmV0dXJuIHRoaXMuX3RpbWU9dGhpcy5fdG90YWxUaW1lPW8sdGhpcy5fcmF3UHJldlRpbWU9Xyx6LnB1c2godGhpcyksdGhpcy5fbGF6eT10LHZvaWQgMDt0aGlzLl90aW1lJiYhcz90aGlzLnJhdGlvPXRoaXMuX2Vhc2UuZ2V0UmF0aW8odGhpcy5fdGltZS9sKTpzJiZ0aGlzLl9lYXNlLl9jYWxjRW5kJiYodGhpcy5yYXRpbz10aGlzLl9lYXNlLmdldFJhdGlvKDA9PT10aGlzLl90aW1lPzA6MSkpfWZvcih0aGlzLl9sYXp5IT09ITEmJih0aGlzLl9sYXp5PSExKSx0aGlzLl9hY3RpdmV8fCF0aGlzLl9wYXVzZWQmJnRoaXMuX3RpbWUhPT1vJiZ0Pj0wJiYodGhpcy5fYWN0aXZlPSEwKSwwPT09byYmKHRoaXMuX3N0YXJ0QXQmJih0Pj0wP3RoaXMuX3N0YXJ0QXQucmVuZGVyKHQsZSxpKTpufHwobj1cIl9kdW1teUdTXCIpKSx0aGlzLnZhcnMub25TdGFydCYmKDAhPT10aGlzLl90aW1lfHwwPT09bCkmJihlfHx0aGlzLnZhcnMub25TdGFydC5hcHBseSh0aGlzLnZhcnMub25TdGFydFNjb3BlfHx0aGlzLHRoaXMudmFycy5vblN0YXJ0UGFyYW1zfHxnKSkpLHI9dGhpcy5fZmlyc3RQVDtyOylyLmY/ci50W3IucF0oci5jKnRoaXMucmF0aW8rci5zKTpyLnRbci5wXT1yLmMqdGhpcy5yYXRpbytyLnMscj1yLl9uZXh0O3RoaXMuX29uVXBkYXRlJiYoMD50JiZ0aGlzLl9zdGFydEF0JiZ0aGlzLl9zdGFydFRpbWUmJnRoaXMuX3N0YXJ0QXQucmVuZGVyKHQsZSxpKSxlfHwodGhpcy5fdGltZSE9PW98fHMpJiZ0aGlzLl9vblVwZGF0ZS5hcHBseSh0aGlzLnZhcnMub25VcGRhdGVTY29wZXx8dGhpcyx0aGlzLnZhcnMub25VcGRhdGVQYXJhbXN8fGcpKSxuJiYodGhpcy5fZ2N8fCgwPnQmJnRoaXMuX3N0YXJ0QXQmJiF0aGlzLl9vblVwZGF0ZSYmdGhpcy5fc3RhcnRUaW1lJiZ0aGlzLl9zdGFydEF0LnJlbmRlcih0LGUsaSkscyYmKHRoaXMuX3RpbWVsaW5lLmF1dG9SZW1vdmVDaGlsZHJlbiYmdGhpcy5fZW5hYmxlZCghMSwhMSksdGhpcy5fYWN0aXZlPSExKSwhZSYmdGhpcy52YXJzW25dJiZ0aGlzLnZhcnNbbl0uYXBwbHkodGhpcy52YXJzW24rXCJTY29wZVwiXXx8dGhpcyx0aGlzLnZhcnNbbitcIlBhcmFtc1wiXXx8ZyksMD09PWwmJnRoaXMuX3Jhd1ByZXZUaW1lPT09aCYmYSE9PWgmJih0aGlzLl9yYXdQcmV2VGltZT0wKSkpfX0sbi5fa2lsbD1mdW5jdGlvbih0LGUpe2lmKFwiYWxsXCI9PT10JiYodD1udWxsKSxudWxsPT10JiYobnVsbD09ZXx8ZT09PXRoaXMudGFyZ2V0KSlyZXR1cm4gdGhpcy5fbGF6eT0hMSx0aGlzLl9lbmFibGVkKCExLCExKTtlPVwic3RyaW5nXCIhPXR5cGVvZiBlP2V8fHRoaXMuX3RhcmdldHN8fHRoaXMudGFyZ2V0OkQuc2VsZWN0b3IoZSl8fGU7dmFyIGkscyxuLHIsYSxvLGwsaDtpZigobShlKXx8SShlKSkmJlwibnVtYmVyXCIhPXR5cGVvZiBlWzBdKWZvcihpPWUubGVuZ3RoOy0taT4tMTspdGhpcy5fa2lsbCh0LGVbaV0pJiYobz0hMCk7ZWxzZXtpZih0aGlzLl90YXJnZXRzKXtmb3IoaT10aGlzLl90YXJnZXRzLmxlbmd0aDstLWk+LTE7KWlmKGU9PT10aGlzLl90YXJnZXRzW2ldKXthPXRoaXMuX3Byb3BMb29rdXBbaV18fHt9LHRoaXMuX292ZXJ3cml0dGVuUHJvcHM9dGhpcy5fb3ZlcndyaXR0ZW5Qcm9wc3x8W10scz10aGlzLl9vdmVyd3JpdHRlblByb3BzW2ldPXQ/dGhpcy5fb3ZlcndyaXR0ZW5Qcm9wc1tpXXx8e306XCJhbGxcIjticmVha319ZWxzZXtpZihlIT09dGhpcy50YXJnZXQpcmV0dXJuITE7YT10aGlzLl9wcm9wTG9va3VwLHM9dGhpcy5fb3ZlcndyaXR0ZW5Qcm9wcz10P3RoaXMuX292ZXJ3cml0dGVuUHJvcHN8fHt9OlwiYWxsXCJ9aWYoYSl7bD10fHxhLGg9dCE9PXMmJlwiYWxsXCIhPT1zJiZ0IT09YSYmKFwib2JqZWN0XCIhPXR5cGVvZiB0fHwhdC5fdGVtcEtpbGwpO2ZvcihuIGluIGwpKHI9YVtuXSkmJihyLnBnJiZyLnQuX2tpbGwobCkmJihvPSEwKSxyLnBnJiYwIT09ci50Ll9vdmVyd3JpdGVQcm9wcy5sZW5ndGh8fChyLl9wcmV2P3IuX3ByZXYuX25leHQ9ci5fbmV4dDpyPT09dGhpcy5fZmlyc3RQVCYmKHRoaXMuX2ZpcnN0UFQ9ci5fbmV4dCksci5fbmV4dCYmKHIuX25leHQuX3ByZXY9ci5fcHJldiksci5fbmV4dD1yLl9wcmV2PW51bGwpLGRlbGV0ZSBhW25dKSxoJiYoc1tuXT0xKTshdGhpcy5fZmlyc3RQVCYmdGhpcy5faW5pdHRlZCYmdGhpcy5fZW5hYmxlZCghMSwhMSl9fXJldHVybiBvfSxuLmludmFsaWRhdGU9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fbm90aWZ5UGx1Z2luc09mRW5hYmxlZCYmRC5fb25QbHVnaW5FdmVudChcIl9vbkRpc2FibGVcIix0aGlzKSx0aGlzLl9maXJzdFBUPW51bGwsdGhpcy5fb3ZlcndyaXR0ZW5Qcm9wcz1udWxsLHRoaXMuX29uVXBkYXRlPW51bGwsdGhpcy5fc3RhcnRBdD1udWxsLHRoaXMuX2luaXR0ZWQ9dGhpcy5fYWN0aXZlPXRoaXMuX25vdGlmeVBsdWdpbnNPZkVuYWJsZWQ9dGhpcy5fbGF6eT0hMSx0aGlzLl9wcm9wTG9va3VwPXRoaXMuX3RhcmdldHM/e306W10sdGhpc30sbi5fZW5hYmxlZD1mdW5jdGlvbih0LGUpe2lmKGF8fHIud2FrZSgpLHQmJnRoaXMuX2djKXt2YXIgaSxzPXRoaXMuX3RhcmdldHM7aWYocylmb3IoaT1zLmxlbmd0aDstLWk+LTE7KXRoaXMuX3NpYmxpbmdzW2ldPU0oc1tpXSx0aGlzLCEwKTtlbHNlIHRoaXMuX3NpYmxpbmdzPU0odGhpcy50YXJnZXQsdGhpcywhMCl9cmV0dXJuIHgucHJvdG90eXBlLl9lbmFibGVkLmNhbGwodGhpcyx0LGUpLHRoaXMuX25vdGlmeVBsdWdpbnNPZkVuYWJsZWQmJnRoaXMuX2ZpcnN0UFQ/RC5fb25QbHVnaW5FdmVudCh0P1wiX29uRW5hYmxlXCI6XCJfb25EaXNhYmxlXCIsdGhpcyk6ITF9LEQudG89ZnVuY3Rpb24odCxlLGkpe3JldHVybiBuZXcgRCh0LGUsaSl9LEQuZnJvbT1mdW5jdGlvbih0LGUsaSl7cmV0dXJuIGkucnVuQmFja3dhcmRzPSEwLGkuaW1tZWRpYXRlUmVuZGVyPTAhPWkuaW1tZWRpYXRlUmVuZGVyLG5ldyBEKHQsZSxpKX0sRC5mcm9tVG89ZnVuY3Rpb24odCxlLGkscyl7cmV0dXJuIHMuc3RhcnRBdD1pLHMuaW1tZWRpYXRlUmVuZGVyPTAhPXMuaW1tZWRpYXRlUmVuZGVyJiYwIT1pLmltbWVkaWF0ZVJlbmRlcixuZXcgRCh0LGUscyl9LEQuZGVsYXllZENhbGw9ZnVuY3Rpb24odCxlLGkscyxuKXtyZXR1cm4gbmV3IEQoZSwwLHtkZWxheTp0LG9uQ29tcGxldGU6ZSxvbkNvbXBsZXRlUGFyYW1zOmksb25Db21wbGV0ZVNjb3BlOnMsb25SZXZlcnNlQ29tcGxldGU6ZSxvblJldmVyc2VDb21wbGV0ZVBhcmFtczppLG9uUmV2ZXJzZUNvbXBsZXRlU2NvcGU6cyxpbW1lZGlhdGVSZW5kZXI6ITEsdXNlRnJhbWVzOm4sb3ZlcndyaXRlOjB9KX0sRC5zZXQ9ZnVuY3Rpb24odCxlKXtyZXR1cm4gbmV3IEQodCwwLGUpfSxELmdldFR3ZWVuc09mPWZ1bmN0aW9uKHQsZSl7aWYobnVsbD09dClyZXR1cm5bXTt0PVwic3RyaW5nXCIhPXR5cGVvZiB0P3Q6RC5zZWxlY3Rvcih0KXx8dDt2YXIgaSxzLG4scjtpZigobSh0KXx8SSh0KSkmJlwibnVtYmVyXCIhPXR5cGVvZiB0WzBdKXtmb3IoaT10Lmxlbmd0aCxzPVtdOy0taT4tMTspcz1zLmNvbmNhdChELmdldFR3ZWVuc09mKHRbaV0sZSkpO2ZvcihpPXMubGVuZ3RoOy0taT4tMTspZm9yKHI9c1tpXSxuPWk7LS1uPi0xOylyPT09c1tuXSYmcy5zcGxpY2UoaSwxKX1lbHNlIGZvcihzPU0odCkuY29uY2F0KCksaT1zLmxlbmd0aDstLWk+LTE7KShzW2ldLl9nY3x8ZSYmIXNbaV0uaXNBY3RpdmUoKSkmJnMuc3BsaWNlKGksMSk7cmV0dXJuIHN9LEQua2lsbFR3ZWVuc09mPUQua2lsbERlbGF5ZWRDYWxsc1RvPWZ1bmN0aW9uKHQsZSxpKXtcIm9iamVjdFwiPT10eXBlb2YgZSYmKGk9ZSxlPSExKTtmb3IodmFyIHM9RC5nZXRUd2VlbnNPZih0LGUpLG49cy5sZW5ndGg7LS1uPi0xOylzW25dLl9raWxsKGksdCl9O3ZhciBIPWQoXCJwbHVnaW5zLlR3ZWVuUGx1Z2luXCIsZnVuY3Rpb24odCxlKXt0aGlzLl9vdmVyd3JpdGVQcm9wcz0odHx8XCJcIikuc3BsaXQoXCIsXCIpLHRoaXMuX3Byb3BOYW1lPXRoaXMuX292ZXJ3cml0ZVByb3BzWzBdLHRoaXMuX3ByaW9yaXR5PWV8fDAsdGhpcy5fc3VwZXI9SC5wcm90b3R5cGV9LCEwKTtpZihuPUgucHJvdG90eXBlLEgudmVyc2lvbj1cIjEuMTAuMVwiLEguQVBJPTIsbi5fZmlyc3RQVD1udWxsLG4uX2FkZFR3ZWVuPWZ1bmN0aW9uKHQsZSxpLHMsbixyKXt2YXIgYSxvO3JldHVybiBudWxsIT1zJiYoYT1cIm51bWJlclwiPT10eXBlb2Ygc3x8XCI9XCIhPT1zLmNoYXJBdCgxKT9OdW1iZXIocyktaTpwYXJzZUludChzLmNoYXJBdCgwKStcIjFcIiwxMCkqTnVtYmVyKHMuc3Vic3RyKDIpKSk/KHRoaXMuX2ZpcnN0UFQ9bz17X25leHQ6dGhpcy5fZmlyc3RQVCx0OnQscDplLHM6aSxjOmEsZjpcImZ1bmN0aW9uXCI9PXR5cGVvZiB0W2VdLG46bnx8ZSxyOnJ9LG8uX25leHQmJihvLl9uZXh0Ll9wcmV2PW8pLG8pOnZvaWQgMH0sbi5zZXRSYXRpbz1mdW5jdGlvbih0KXtmb3IodmFyIGUsaT10aGlzLl9maXJzdFBULHM9MWUtNjtpOyllPWkuYyp0K2kucyxpLnI/ZT1NYXRoLnJvdW5kKGUpOnM+ZSYmZT4tcyYmKGU9MCksaS5mP2kudFtpLnBdKGUpOmkudFtpLnBdPWUsaT1pLl9uZXh0fSxuLl9raWxsPWZ1bmN0aW9uKHQpe3ZhciBlLGk9dGhpcy5fb3ZlcndyaXRlUHJvcHMscz10aGlzLl9maXJzdFBUO2lmKG51bGwhPXRbdGhpcy5fcHJvcE5hbWVdKXRoaXMuX292ZXJ3cml0ZVByb3BzPVtdO2Vsc2UgZm9yKGU9aS5sZW5ndGg7LS1lPi0xOyludWxsIT10W2lbZV1dJiZpLnNwbGljZShlLDEpO2Zvcig7czspbnVsbCE9dFtzLm5dJiYocy5fbmV4dCYmKHMuX25leHQuX3ByZXY9cy5fcHJldikscy5fcHJldj8ocy5fcHJldi5fbmV4dD1zLl9uZXh0LHMuX3ByZXY9bnVsbCk6dGhpcy5fZmlyc3RQVD09PXMmJih0aGlzLl9maXJzdFBUPXMuX25leHQpKSxzPXMuX25leHQ7cmV0dXJuITF9LG4uX3JvdW5kUHJvcHM9ZnVuY3Rpb24odCxlKXtmb3IodmFyIGk9dGhpcy5fZmlyc3RQVDtpOykodFt0aGlzLl9wcm9wTmFtZV18fG51bGwhPWkubiYmdFtpLm4uc3BsaXQodGhpcy5fcHJvcE5hbWUrXCJfXCIpLmpvaW4oXCJcIildKSYmKGkucj1lKSxpPWkuX25leHR9LEQuX29uUGx1Z2luRXZlbnQ9ZnVuY3Rpb24odCxlKXt2YXIgaSxzLG4scixhLG89ZS5fZmlyc3RQVDtpZihcIl9vbkluaXRBbGxQcm9wc1wiPT09dCl7Zm9yKDtvOyl7Zm9yKGE9by5fbmV4dCxzPW47cyYmcy5wcj5vLnByOylzPXMuX25leHQ7KG8uX3ByZXY9cz9zLl9wcmV2OnIpP28uX3ByZXYuX25leHQ9bzpuPW8sKG8uX25leHQ9cyk/cy5fcHJldj1vOnI9byxvPWF9bz1lLl9maXJzdFBUPW59Zm9yKDtvOylvLnBnJiZcImZ1bmN0aW9uXCI9PXR5cGVvZiBvLnRbdF0mJm8udFt0XSgpJiYoaT0hMCksbz1vLl9uZXh0O3JldHVybiBpfSxILmFjdGl2YXRlPWZ1bmN0aW9uKHQpe2Zvcih2YXIgZT10Lmxlbmd0aDstLWU+LTE7KXRbZV0uQVBJPT09SC5BUEkmJihMWyhuZXcgdFtlXSkuX3Byb3BOYW1lXT10W2VdKTtyZXR1cm4hMH0sYy5wbHVnaW49ZnVuY3Rpb24odCl7aWYoISh0JiZ0LnByb3BOYW1lJiZ0LmluaXQmJnQuQVBJKSl0aHJvd1wiaWxsZWdhbCBwbHVnaW4gZGVmaW5pdGlvbi5cIjt2YXIgZSxpPXQucHJvcE5hbWUscz10LnByaW9yaXR5fHwwLG49dC5vdmVyd3JpdGVQcm9wcyxyPXtpbml0OlwiX29uSW5pdFR3ZWVuXCIsc2V0Olwic2V0UmF0aW9cIixraWxsOlwiX2tpbGxcIixyb3VuZDpcIl9yb3VuZFByb3BzXCIsaW5pdEFsbDpcIl9vbkluaXRBbGxQcm9wc1wifSxhPWQoXCJwbHVnaW5zLlwiK2kuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkraS5zdWJzdHIoMSkrXCJQbHVnaW5cIixmdW5jdGlvbigpe0guY2FsbCh0aGlzLGkscyksdGhpcy5fb3ZlcndyaXRlUHJvcHM9bnx8W119LHQuZ2xvYmFsPT09ITApLG89YS5wcm90b3R5cGU9bmV3IEgoaSk7by5jb25zdHJ1Y3Rvcj1hLGEuQVBJPXQuQVBJO2ZvcihlIGluIHIpXCJmdW5jdGlvblwiPT10eXBlb2YgdFtlXSYmKG9bcltlXV09dFtlXSk7cmV0dXJuIGEudmVyc2lvbj10LnZlcnNpb24sSC5hY3RpdmF0ZShbYV0pLGF9LGk9dC5fZ3NRdWV1ZSl7Zm9yKHM9MDtpLmxlbmd0aD5zO3MrKylpW3NdKCk7Zm9yKG4gaW4gZilmW25dLmZ1bmN8fHQuY29uc29sZS5sb2coXCJHU0FQIGVuY291bnRlcmVkIG1pc3NpbmcgZGVwZW5kZW5jeTogY29tLmdyZWVuc29jay5cIituKX1hPSExfX0pKHdpbmRvdyk7IiwiLyohXHJcbiAqIFZFUlNJT046IGJldGEgMS45LjNcclxuICogREFURTogMjAxMy0wNC0wMlxyXG4gKiBVUERBVEVTIEFORCBET0NTIEFUOiBodHRwOi8vd3d3LmdyZWVuc29jay5jb21cclxuICpcclxuICogQGxpY2Vuc2UgQ29weXJpZ2h0IChjKSAyMDA4LTIwMTQsIEdyZWVuU29jay4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuICogVGhpcyB3b3JrIGlzIHN1YmplY3QgdG8gdGhlIHRlcm1zIGF0IGh0dHA6Ly93d3cuZ3JlZW5zb2NrLmNvbS90ZXJtc19vZl91c2UuaHRtbCBvciBmb3JcclxuICogQ2x1YiBHcmVlblNvY2sgbWVtYmVycywgdGhlIHNvZnR3YXJlIGFncmVlbWVudCB0aGF0IHdhcyBpc3N1ZWQgd2l0aCB5b3VyIG1lbWJlcnNoaXAuXHJcbiAqIFxyXG4gKiBAYXV0aG9yOiBKYWNrIERveWxlLCBqYWNrQGdyZWVuc29jay5jb21cclxuICoqL1xyXG4od2luZG93Ll9nc1F1ZXVlfHwod2luZG93Ll9nc1F1ZXVlPVtdKSkucHVzaChmdW5jdGlvbigpe1widXNlIHN0cmljdFwiO3dpbmRvdy5fZ3NEZWZpbmUoXCJlYXNpbmcuQmFja1wiLFtcImVhc2luZy5FYXNlXCJdLGZ1bmN0aW9uKHQpe3ZhciBlLGkscyxyPXdpbmRvdy5HcmVlblNvY2tHbG9iYWxzfHx3aW5kb3csbj1yLmNvbS5ncmVlbnNvY2ssYT0yKk1hdGguUEksbz1NYXRoLlBJLzIsaD1uLl9jbGFzcyxsPWZ1bmN0aW9uKGUsaSl7dmFyIHM9aChcImVhc2luZy5cIitlLGZ1bmN0aW9uKCl7fSwhMCkscj1zLnByb3RvdHlwZT1uZXcgdDtyZXR1cm4gci5jb25zdHJ1Y3Rvcj1zLHIuZ2V0UmF0aW89aSxzfSxfPXQucmVnaXN0ZXJ8fGZ1bmN0aW9uKCl7fSx1PWZ1bmN0aW9uKHQsZSxpLHMpe3ZhciByPWgoXCJlYXNpbmcuXCIrdCx7ZWFzZU91dDpuZXcgZSxlYXNlSW46bmV3IGksZWFzZUluT3V0Om5ldyBzfSwhMCk7cmV0dXJuIF8ocix0KSxyfSxjPWZ1bmN0aW9uKHQsZSxpKXt0aGlzLnQ9dCx0aGlzLnY9ZSxpJiYodGhpcy5uZXh0PWksaS5wcmV2PXRoaXMsdGhpcy5jPWkudi1lLHRoaXMuZ2FwPWkudC10KX0sZj1mdW5jdGlvbihlLGkpe3ZhciBzPWgoXCJlYXNpbmcuXCIrZSxmdW5jdGlvbih0KXt0aGlzLl9wMT10fHwwPT09dD90OjEuNzAxNTgsdGhpcy5fcDI9MS41MjUqdGhpcy5fcDF9LCEwKSxyPXMucHJvdG90eXBlPW5ldyB0O3JldHVybiByLmNvbnN0cnVjdG9yPXMsci5nZXRSYXRpbz1pLHIuY29uZmlnPWZ1bmN0aW9uKHQpe3JldHVybiBuZXcgcyh0KX0sc30scD11KFwiQmFja1wiLGYoXCJCYWNrT3V0XCIsZnVuY3Rpb24odCl7cmV0dXJuKHQtPTEpKnQqKCh0aGlzLl9wMSsxKSp0K3RoaXMuX3AxKSsxfSksZihcIkJhY2tJblwiLGZ1bmN0aW9uKHQpe3JldHVybiB0KnQqKCh0aGlzLl9wMSsxKSp0LXRoaXMuX3AxKX0pLGYoXCJCYWNrSW5PdXRcIixmdW5jdGlvbih0KXtyZXR1cm4gMT4odCo9Mik/LjUqdCp0KigodGhpcy5fcDIrMSkqdC10aGlzLl9wMik6LjUqKCh0LT0yKSp0KigodGhpcy5fcDIrMSkqdCt0aGlzLl9wMikrMil9KSksbT1oKFwiZWFzaW5nLlNsb3dNb1wiLGZ1bmN0aW9uKHQsZSxpKXtlPWV8fDA9PT1lP2U6LjcsbnVsbD09dD90PS43OnQ+MSYmKHQ9MSksdGhpcy5fcD0xIT09dD9lOjAsdGhpcy5fcDE9KDEtdCkvMix0aGlzLl9wMj10LHRoaXMuX3AzPXRoaXMuX3AxK3RoaXMuX3AyLHRoaXMuX2NhbGNFbmQ9aT09PSEwfSwhMCksZD1tLnByb3RvdHlwZT1uZXcgdDtyZXR1cm4gZC5jb25zdHJ1Y3Rvcj1tLGQuZ2V0UmF0aW89ZnVuY3Rpb24odCl7dmFyIGU9dCsoLjUtdCkqdGhpcy5fcDtyZXR1cm4gdGhpcy5fcDE+dD90aGlzLl9jYWxjRW5kPzEtKHQ9MS10L3RoaXMuX3AxKSp0OmUtKHQ9MS10L3RoaXMuX3AxKSp0KnQqdCplOnQ+dGhpcy5fcDM/dGhpcy5fY2FsY0VuZD8xLSh0PSh0LXRoaXMuX3AzKS90aGlzLl9wMSkqdDplKyh0LWUpKih0PSh0LXRoaXMuX3AzKS90aGlzLl9wMSkqdCp0KnQ6dGhpcy5fY2FsY0VuZD8xOmV9LG0uZWFzZT1uZXcgbSguNywuNyksZC5jb25maWc9bS5jb25maWc9ZnVuY3Rpb24odCxlLGkpe3JldHVybiBuZXcgbSh0LGUsaSl9LGU9aChcImVhc2luZy5TdGVwcGVkRWFzZVwiLGZ1bmN0aW9uKHQpe3Q9dHx8MSx0aGlzLl9wMT0xL3QsdGhpcy5fcDI9dCsxfSwhMCksZD1lLnByb3RvdHlwZT1uZXcgdCxkLmNvbnN0cnVjdG9yPWUsZC5nZXRSYXRpbz1mdW5jdGlvbih0KXtyZXR1cm4gMD50P3Q9MDp0Pj0xJiYodD0uOTk5OTk5OTk5KSwodGhpcy5fcDIqdD4+MCkqdGhpcy5fcDF9LGQuY29uZmlnPWUuY29uZmlnPWZ1bmN0aW9uKHQpe3JldHVybiBuZXcgZSh0KX0saT1oKFwiZWFzaW5nLlJvdWdoRWFzZVwiLGZ1bmN0aW9uKGUpe2U9ZXx8e307Zm9yKHZhciBpLHMscixuLGEsbyxoPWUudGFwZXJ8fFwibm9uZVwiLGw9W10sXz0wLHU9MHwoZS5wb2ludHN8fDIwKSxmPXUscD1lLnJhbmRvbWl6ZSE9PSExLG09ZS5jbGFtcD09PSEwLGQ9ZS50ZW1wbGF0ZSBpbnN0YW5jZW9mIHQ/ZS50ZW1wbGF0ZTpudWxsLGc9XCJudW1iZXJcIj09dHlwZW9mIGUuc3RyZW5ndGg/LjQqZS5zdHJlbmd0aDouNDstLWY+LTE7KWk9cD9NYXRoLnJhbmRvbSgpOjEvdSpmLHM9ZD9kLmdldFJhdGlvKGkpOmksXCJub25lXCI9PT1oP3I9ZzpcIm91dFwiPT09aD8obj0xLWkscj1uKm4qZyk6XCJpblwiPT09aD9yPWkqaSpnOi41Pmk/KG49MippLHI9LjUqbipuKmcpOihuPTIqKDEtaSkscj0uNSpuKm4qZykscD9zKz1NYXRoLnJhbmRvbSgpKnItLjUqcjpmJTI/cys9LjUqcjpzLT0uNSpyLG0mJihzPjE/cz0xOjA+cyYmKHM9MCkpLGxbXysrXT17eDppLHk6c307Zm9yKGwuc29ydChmdW5jdGlvbih0LGUpe3JldHVybiB0LngtZS54fSksbz1uZXcgYygxLDEsbnVsbCksZj11Oy0tZj4tMTspYT1sW2ZdLG89bmV3IGMoYS54LGEueSxvKTt0aGlzLl9wcmV2PW5ldyBjKDAsMCwwIT09by50P286by5uZXh0KX0sITApLGQ9aS5wcm90b3R5cGU9bmV3IHQsZC5jb25zdHJ1Y3Rvcj1pLGQuZ2V0UmF0aW89ZnVuY3Rpb24odCl7dmFyIGU9dGhpcy5fcHJldjtpZih0PmUudCl7Zm9yKDtlLm5leHQmJnQ+PWUudDspZT1lLm5leHQ7ZT1lLnByZXZ9ZWxzZSBmb3IoO2UucHJldiYmZS50Pj10OyllPWUucHJldjtyZXR1cm4gdGhpcy5fcHJldj1lLGUudisodC1lLnQpL2UuZ2FwKmUuY30sZC5jb25maWc9ZnVuY3Rpb24odCl7cmV0dXJuIG5ldyBpKHQpfSxpLmVhc2U9bmV3IGksdShcIkJvdW5jZVwiLGwoXCJCb3VuY2VPdXRcIixmdW5jdGlvbih0KXtyZXR1cm4gMS8yLjc1PnQ/Ny41NjI1KnQqdDoyLzIuNzU+dD83LjU2MjUqKHQtPTEuNS8yLjc1KSp0Ky43NToyLjUvMi43NT50PzcuNTYyNSoodC09Mi4yNS8yLjc1KSp0Ky45Mzc1OjcuNTYyNSoodC09Mi42MjUvMi43NSkqdCsuOTg0Mzc1fSksbChcIkJvdW5jZUluXCIsZnVuY3Rpb24odCl7cmV0dXJuIDEvMi43NT4odD0xLXQpPzEtNy41NjI1KnQqdDoyLzIuNzU+dD8xLSg3LjU2MjUqKHQtPTEuNS8yLjc1KSp0Ky43NSk6Mi41LzIuNzU+dD8xLSg3LjU2MjUqKHQtPTIuMjUvMi43NSkqdCsuOTM3NSk6MS0oNy41NjI1Kih0LT0yLjYyNS8yLjc1KSp0Ky45ODQzNzUpfSksbChcIkJvdW5jZUluT3V0XCIsZnVuY3Rpb24odCl7dmFyIGU9LjU+dDtyZXR1cm4gdD1lPzEtMip0OjIqdC0xLHQ9MS8yLjc1PnQ/Ny41NjI1KnQqdDoyLzIuNzU+dD83LjU2MjUqKHQtPTEuNS8yLjc1KSp0Ky43NToyLjUvMi43NT50PzcuNTYyNSoodC09Mi4yNS8yLjc1KSp0Ky45Mzc1OjcuNTYyNSoodC09Mi42MjUvMi43NSkqdCsuOTg0Mzc1LGU/LjUqKDEtdCk6LjUqdCsuNX0pKSx1KFwiQ2lyY1wiLGwoXCJDaXJjT3V0XCIsZnVuY3Rpb24odCl7cmV0dXJuIE1hdGguc3FydCgxLSh0LT0xKSp0KX0pLGwoXCJDaXJjSW5cIixmdW5jdGlvbih0KXtyZXR1cm4tKE1hdGguc3FydCgxLXQqdCktMSl9KSxsKFwiQ2lyY0luT3V0XCIsZnVuY3Rpb24odCl7cmV0dXJuIDE+KHQqPTIpPy0uNSooTWF0aC5zcXJ0KDEtdCp0KS0xKTouNSooTWF0aC5zcXJ0KDEtKHQtPTIpKnQpKzEpfSkpLHM9ZnVuY3Rpb24oZSxpLHMpe3ZhciByPWgoXCJlYXNpbmcuXCIrZSxmdW5jdGlvbih0LGUpe3RoaXMuX3AxPXR8fDEsdGhpcy5fcDI9ZXx8cyx0aGlzLl9wMz10aGlzLl9wMi9hKihNYXRoLmFzaW4oMS90aGlzLl9wMSl8fDApfSwhMCksbj1yLnByb3RvdHlwZT1uZXcgdDtyZXR1cm4gbi5jb25zdHJ1Y3Rvcj1yLG4uZ2V0UmF0aW89aSxuLmNvbmZpZz1mdW5jdGlvbih0LGUpe3JldHVybiBuZXcgcih0LGUpfSxyfSx1KFwiRWxhc3RpY1wiLHMoXCJFbGFzdGljT3V0XCIsZnVuY3Rpb24odCl7cmV0dXJuIHRoaXMuX3AxKk1hdGgucG93KDIsLTEwKnQpKk1hdGguc2luKCh0LXRoaXMuX3AzKSphL3RoaXMuX3AyKSsxfSwuMykscyhcIkVsYXN0aWNJblwiLGZ1bmN0aW9uKHQpe3JldHVybi0odGhpcy5fcDEqTWF0aC5wb3coMiwxMCoodC09MSkpKk1hdGguc2luKCh0LXRoaXMuX3AzKSphL3RoaXMuX3AyKSl9LC4zKSxzKFwiRWxhc3RpY0luT3V0XCIsZnVuY3Rpb24odCl7cmV0dXJuIDE+KHQqPTIpPy0uNSp0aGlzLl9wMSpNYXRoLnBvdygyLDEwKih0LT0xKSkqTWF0aC5zaW4oKHQtdGhpcy5fcDMpKmEvdGhpcy5fcDIpOi41KnRoaXMuX3AxKk1hdGgucG93KDIsLTEwKih0LT0xKSkqTWF0aC5zaW4oKHQtdGhpcy5fcDMpKmEvdGhpcy5fcDIpKzF9LC40NSkpLHUoXCJFeHBvXCIsbChcIkV4cG9PdXRcIixmdW5jdGlvbih0KXtyZXR1cm4gMS1NYXRoLnBvdygyLC0xMCp0KX0pLGwoXCJFeHBvSW5cIixmdW5jdGlvbih0KXtyZXR1cm4gTWF0aC5wb3coMiwxMCoodC0xKSktLjAwMX0pLGwoXCJFeHBvSW5PdXRcIixmdW5jdGlvbih0KXtyZXR1cm4gMT4odCo9Mik/LjUqTWF0aC5wb3coMiwxMCoodC0xKSk6LjUqKDItTWF0aC5wb3coMiwtMTAqKHQtMSkpKX0pKSx1KFwiU2luZVwiLGwoXCJTaW5lT3V0XCIsZnVuY3Rpb24odCl7cmV0dXJuIE1hdGguc2luKHQqbyl9KSxsKFwiU2luZUluXCIsZnVuY3Rpb24odCl7cmV0dXJuLU1hdGguY29zKHQqbykrMX0pLGwoXCJTaW5lSW5PdXRcIixmdW5jdGlvbih0KXtyZXR1cm4tLjUqKE1hdGguY29zKE1hdGguUEkqdCktMSl9KSksaChcImVhc2luZy5FYXNlTG9va3VwXCIse2ZpbmQ6ZnVuY3Rpb24oZSl7cmV0dXJuIHQubWFwW2VdfX0sITApLF8oci5TbG93TW8sXCJTbG93TW9cIixcImVhc2UsXCIpLF8oaSxcIlJvdWdoRWFzZVwiLFwiZWFzZSxcIiksXyhlLFwiU3RlcHBlZEVhc2VcIixcImVhc2UsXCIpLHB9LCEwKX0pLHdpbmRvdy5fZ3NEZWZpbmUmJndpbmRvdy5fZ3NRdWV1ZS5wb3AoKSgpOyIsIi8qIVxyXG4gKiBWRVJTSU9OOiAxLjEyLjFcclxuICogREFURTogMjAxNC0wNi0yNlxyXG4gKiBVUERBVEVTIEFORCBET0NTIEFUOiBodHRwOi8vd3d3LmdyZWVuc29jay5jb21cclxuICpcclxuICogQGxpY2Vuc2UgQ29weXJpZ2h0IChjKSAyMDA4LTIwMTQsIEdyZWVuU29jay4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cclxuICogVGhpcyB3b3JrIGlzIHN1YmplY3QgdG8gdGhlIHRlcm1zIGF0IGh0dHA6Ly93d3cuZ3JlZW5zb2NrLmNvbS90ZXJtc19vZl91c2UuaHRtbCBvciBmb3JcclxuICogQ2x1YiBHcmVlblNvY2sgbWVtYmVycywgdGhlIHNvZnR3YXJlIGFncmVlbWVudCB0aGF0IHdhcyBpc3N1ZWQgd2l0aCB5b3VyIG1lbWJlcnNoaXAuXHJcbiAqIFxyXG4gKiBAYXV0aG9yOiBKYWNrIERveWxlLCBqYWNrQGdyZWVuc29jay5jb21cclxuICovXHJcbih3aW5kb3cuX2dzUXVldWV8fCh3aW5kb3cuX2dzUXVldWU9W10pKS5wdXNoKGZ1bmN0aW9uKCl7XCJ1c2Ugc3RyaWN0XCI7d2luZG93Ll9nc0RlZmluZShcInBsdWdpbnMuQ1NTUGx1Z2luXCIsW1wicGx1Z2lucy5Ud2VlblBsdWdpblwiLFwiVHdlZW5MaXRlXCJdLGZ1bmN0aW9uKHQsZSl7dmFyIGkscixzLG4sYT1mdW5jdGlvbigpe3QuY2FsbCh0aGlzLFwiY3NzXCIpLHRoaXMuX292ZXJ3cml0ZVByb3BzLmxlbmd0aD0wLHRoaXMuc2V0UmF0aW89YS5wcm90b3R5cGUuc2V0UmF0aW99LG89e30sbD1hLnByb3RvdHlwZT1uZXcgdChcImNzc1wiKTtsLmNvbnN0cnVjdG9yPWEsYS52ZXJzaW9uPVwiMS4xMi4xXCIsYS5BUEk9MixhLmRlZmF1bHRUcmFuc2Zvcm1QZXJzcGVjdGl2ZT0wLGEuZGVmYXVsdFNrZXdUeXBlPVwiY29tcGVuc2F0ZWRcIixsPVwicHhcIixhLnN1ZmZpeE1hcD17dG9wOmwscmlnaHQ6bCxib3R0b206bCxsZWZ0Omwsd2lkdGg6bCxoZWlnaHQ6bCxmb250U2l6ZTpsLHBhZGRpbmc6bCxtYXJnaW46bCxwZXJzcGVjdGl2ZTpsLGxpbmVIZWlnaHQ6XCJcIn07dmFyIGgsdSxmLF8scCxjLGQ9Lyg/OlxcZHxcXC1cXGR8XFwuXFxkfFxcLVxcLlxcZCkrL2csbT0vKD86XFxkfFxcLVxcZHxcXC5cXGR8XFwtXFwuXFxkfFxcKz1cXGR8XFwtPVxcZHxcXCs9LlxcZHxcXC09XFwuXFxkKSsvZyxnPS8oPzpcXCs9fFxcLT18XFwtfFxcYilbXFxkXFwtXFwuXStbYS16QS1aMC05XSooPzolfFxcYikvZ2ksdj0vW15cXGRcXC1cXC5dL2cseT0vKD86XFxkfFxcLXxcXCt8PXwjfFxcLikqL2csVD0vb3BhY2l0eSAqPSAqKFteKV0qKS9pLHc9L29wYWNpdHk6KFteO10qKS9pLHg9L2FscGhhXFwob3BhY2l0eSAqPS4rP1xcKS9pLGI9L14ocmdifGhzbCkvLFA9LyhbQS1aXSkvZyxTPS8tKFthLXpdKS9naSxDPS8oXig/OnVybFxcKFxcXCJ8dXJsXFwoKSl8KD86KFxcXCJcXCkpJHxcXCkkKS9naSxSPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIGUudG9VcHBlckNhc2UoKX0saz0vKD86TGVmdHxSaWdodHxXaWR0aCkvaSxBPS8oTTExfE0xMnxNMjF8TTIyKT1bXFxkXFwtXFwuZV0rL2dpLE89L3Byb2dpZFxcOkRYSW1hZ2VUcmFuc2Zvcm1cXC5NaWNyb3NvZnRcXC5NYXRyaXhcXCguKz9cXCkvaSxEPS8sKD89W15cXCldKig/OlxcKHwkKSkvZ2ksTT1NYXRoLlBJLzE4MCxMPTE4MC9NYXRoLlBJLE49e30sWD1kb2N1bWVudCx6PVguY3JlYXRlRWxlbWVudChcImRpdlwiKSxJPVguY3JlYXRlRWxlbWVudChcImltZ1wiKSxFPWEuX2ludGVybmFscz17X3NwZWNpYWxQcm9wczpvfSxGPW5hdmlnYXRvci51c2VyQWdlbnQsWT1mdW5jdGlvbigpe3ZhciB0LGU9Ri5pbmRleE9mKFwiQW5kcm9pZFwiKSxpPVguY3JlYXRlRWxlbWVudChcImRpdlwiKTtyZXR1cm4gZj0tMSE9PUYuaW5kZXhPZihcIlNhZmFyaVwiKSYmLTE9PT1GLmluZGV4T2YoXCJDaHJvbWVcIikmJigtMT09PWV8fE51bWJlcihGLnN1YnN0cihlKzgsMSkpPjMpLHA9ZiYmNj5OdW1iZXIoRi5zdWJzdHIoRi5pbmRleE9mKFwiVmVyc2lvbi9cIikrOCwxKSksXz0tMSE9PUYuaW5kZXhPZihcIkZpcmVmb3hcIiksL01TSUUgKFswLTldezEsfVtcXC4wLTldezAsfSkvLmV4ZWMoRikmJihjPXBhcnNlRmxvYXQoUmVnRXhwLiQxKSksaS5pbm5lckhUTUw9XCI8YSBzdHlsZT0ndG9wOjFweDtvcGFjaXR5Oi41NTsnPmE8L2E+XCIsdD1pLmdldEVsZW1lbnRzQnlUYWdOYW1lKFwiYVwiKVswXSx0Py9eMC41NS8udGVzdCh0LnN0eWxlLm9wYWNpdHkpOiExfSgpLEI9ZnVuY3Rpb24odCl7cmV0dXJuIFQudGVzdChcInN0cmluZ1wiPT10eXBlb2YgdD90Oih0LmN1cnJlbnRTdHlsZT90LmN1cnJlbnRTdHlsZS5maWx0ZXI6dC5zdHlsZS5maWx0ZXIpfHxcIlwiKT9wYXJzZUZsb2F0KFJlZ0V4cC4kMSkvMTAwOjF9LFU9ZnVuY3Rpb24odCl7d2luZG93LmNvbnNvbGUmJmNvbnNvbGUubG9nKHQpfSxXPVwiXCIsaj1cIlwiLFY9ZnVuY3Rpb24odCxlKXtlPWV8fHo7dmFyIGkscixzPWUuc3R5bGU7aWYodm9pZCAwIT09c1t0XSlyZXR1cm4gdDtmb3IodD10LmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpK3Quc3Vic3RyKDEpLGk9W1wiT1wiLFwiTW96XCIsXCJtc1wiLFwiTXNcIixcIldlYmtpdFwiXSxyPTU7LS1yPi0xJiZ2b2lkIDA9PT1zW2lbcl0rdF07KTtyZXR1cm4gcj49MD8oaj0zPT09cj9cIm1zXCI6aVtyXSxXPVwiLVwiK2oudG9Mb3dlckNhc2UoKStcIi1cIixqK3QpOm51bGx9LEg9WC5kZWZhdWx0Vmlldz9YLmRlZmF1bHRWaWV3LmdldENvbXB1dGVkU3R5bGU6ZnVuY3Rpb24oKXt9LHE9YS5nZXRTdHlsZT1mdW5jdGlvbih0LGUsaSxyLHMpe3ZhciBuO3JldHVybiBZfHxcIm9wYWNpdHlcIiE9PWU/KCFyJiZ0LnN0eWxlW2VdP249dC5zdHlsZVtlXTooaT1pfHxIKHQpKT9uPWlbZV18fGkuZ2V0UHJvcGVydHlWYWx1ZShlKXx8aS5nZXRQcm9wZXJ0eVZhbHVlKGUucmVwbGFjZShQLFwiLSQxXCIpLnRvTG93ZXJDYXNlKCkpOnQuY3VycmVudFN0eWxlJiYobj10LmN1cnJlbnRTdHlsZVtlXSksbnVsbD09c3x8biYmXCJub25lXCIhPT1uJiZcImF1dG9cIiE9PW4mJlwiYXV0byBhdXRvXCIhPT1uP246cyk6Qih0KX0sUT1FLmNvbnZlcnRUb1BpeGVscz1mdW5jdGlvbih0LGkscixzLG4pe2lmKFwicHhcIj09PXN8fCFzKXJldHVybiByO2lmKFwiYXV0b1wiPT09c3x8IXIpcmV0dXJuIDA7dmFyIG8sbCxoLHU9ay50ZXN0KGkpLGY9dCxfPXouc3R5bGUscD0wPnI7aWYocCYmKHI9LXIpLFwiJVwiPT09cyYmLTEhPT1pLmluZGV4T2YoXCJib3JkZXJcIikpbz1yLzEwMCoodT90LmNsaWVudFdpZHRoOnQuY2xpZW50SGVpZ2h0KTtlbHNle2lmKF8uY3NzVGV4dD1cImJvcmRlcjowIHNvbGlkIHJlZDtwb3NpdGlvbjpcIitxKHQsXCJwb3NpdGlvblwiKStcIjtsaW5lLWhlaWdodDowO1wiLFwiJVwiIT09cyYmZi5hcHBlbmRDaGlsZClfW3U/XCJib3JkZXJMZWZ0V2lkdGhcIjpcImJvcmRlclRvcFdpZHRoXCJdPXIrcztlbHNle2lmKGY9dC5wYXJlbnROb2RlfHxYLmJvZHksbD1mLl9nc0NhY2hlLGg9ZS50aWNrZXIuZnJhbWUsbCYmdSYmbC50aW1lPT09aClyZXR1cm4gbC53aWR0aCpyLzEwMDtfW3U/XCJ3aWR0aFwiOlwiaGVpZ2h0XCJdPXIrc31mLmFwcGVuZENoaWxkKHopLG89cGFyc2VGbG9hdCh6W3U/XCJvZmZzZXRXaWR0aFwiOlwib2Zmc2V0SGVpZ2h0XCJdKSxmLnJlbW92ZUNoaWxkKHopLHUmJlwiJVwiPT09cyYmYS5jYWNoZVdpZHRocyE9PSExJiYobD1mLl9nc0NhY2hlPWYuX2dzQ2FjaGV8fHt9LGwudGltZT1oLGwud2lkdGg9MTAwKihvL3IpKSwwIT09b3x8bnx8KG89USh0LGkscixzLCEwKSl9cmV0dXJuIHA/LW86b30sWj1FLmNhbGN1bGF0ZU9mZnNldD1mdW5jdGlvbih0LGUsaSl7aWYoXCJhYnNvbHV0ZVwiIT09cSh0LFwicG9zaXRpb25cIixpKSlyZXR1cm4gMDt2YXIgcj1cImxlZnRcIj09PWU/XCJMZWZ0XCI6XCJUb3BcIixzPXEodCxcIm1hcmdpblwiK3IsaSk7cmV0dXJuIHRbXCJvZmZzZXRcIityXS0oUSh0LGUscGFyc2VGbG9hdChzKSxzLnJlcGxhY2UoeSxcIlwiKSl8fDApfSwkPWZ1bmN0aW9uKHQsZSl7dmFyIGkscixzPXt9O2lmKGU9ZXx8SCh0LG51bGwpKWlmKGk9ZS5sZW5ndGgpZm9yKDstLWk+LTE7KXNbZVtpXS5yZXBsYWNlKFMsUildPWUuZ2V0UHJvcGVydHlWYWx1ZShlW2ldKTtlbHNlIGZvcihpIGluIGUpc1tpXT1lW2ldO2Vsc2UgaWYoZT10LmN1cnJlbnRTdHlsZXx8dC5zdHlsZSlmb3IoaSBpbiBlKVwic3RyaW5nXCI9PXR5cGVvZiBpJiZ2b2lkIDA9PT1zW2ldJiYoc1tpLnJlcGxhY2UoUyxSKV09ZVtpXSk7cmV0dXJuIFl8fChzLm9wYWNpdHk9Qih0KSkscj1QZSh0LGUsITEpLHMucm90YXRpb249ci5yb3RhdGlvbixzLnNrZXdYPXIuc2tld1gscy5zY2FsZVg9ci5zY2FsZVgscy5zY2FsZVk9ci5zY2FsZVkscy54PXIueCxzLnk9ci55LHhlJiYocy56PXIueixzLnJvdGF0aW9uWD1yLnJvdGF0aW9uWCxzLnJvdGF0aW9uWT1yLnJvdGF0aW9uWSxzLnNjYWxlWj1yLnNjYWxlWikscy5maWx0ZXJzJiZkZWxldGUgcy5maWx0ZXJzLHN9LEc9ZnVuY3Rpb24odCxlLGkscixzKXt2YXIgbixhLG8sbD17fSxoPXQuc3R5bGU7Zm9yKGEgaW4gaSlcImNzc1RleHRcIiE9PWEmJlwibGVuZ3RoXCIhPT1hJiZpc05hTihhKSYmKGVbYV0hPT0obj1pW2FdKXx8cyYmc1thXSkmJi0xPT09YS5pbmRleE9mKFwiT3JpZ2luXCIpJiYoXCJudW1iZXJcIj09dHlwZW9mIG58fFwic3RyaW5nXCI9PXR5cGVvZiBuKSYmKGxbYV09XCJhdXRvXCIhPT1ufHxcImxlZnRcIiE9PWEmJlwidG9wXCIhPT1hP1wiXCIhPT1uJiZcImF1dG9cIiE9PW4mJlwibm9uZVwiIT09bnx8XCJzdHJpbmdcIiE9dHlwZW9mIGVbYV18fFwiXCI9PT1lW2FdLnJlcGxhY2UodixcIlwiKT9uOjA6Wih0LGEpLHZvaWQgMCE9PWhbYV0mJihvPW5ldyBmZShoLGEsaFthXSxvKSkpO2lmKHIpZm9yKGEgaW4gcilcImNsYXNzTmFtZVwiIT09YSYmKGxbYV09clthXSk7cmV0dXJue2RpZnM6bCxmaXJzdE1QVDpvfX0sSz17d2lkdGg6W1wiTGVmdFwiLFwiUmlnaHRcIl0saGVpZ2h0OltcIlRvcFwiLFwiQm90dG9tXCJdfSxKPVtcIm1hcmdpbkxlZnRcIixcIm1hcmdpblJpZ2h0XCIsXCJtYXJnaW5Ub3BcIixcIm1hcmdpbkJvdHRvbVwiXSx0ZT1mdW5jdGlvbih0LGUsaSl7dmFyIHI9cGFyc2VGbG9hdChcIndpZHRoXCI9PT1lP3Qub2Zmc2V0V2lkdGg6dC5vZmZzZXRIZWlnaHQpLHM9S1tlXSxuPXMubGVuZ3RoO2ZvcihpPWl8fEgodCxudWxsKTstLW4+LTE7KXItPXBhcnNlRmxvYXQocSh0LFwicGFkZGluZ1wiK3Nbbl0saSwhMCkpfHwwLHItPXBhcnNlRmxvYXQocSh0LFwiYm9yZGVyXCIrc1tuXStcIldpZHRoXCIsaSwhMCkpfHwwO3JldHVybiByfSxlZT1mdW5jdGlvbih0LGUpeyhudWxsPT10fHxcIlwiPT09dHx8XCJhdXRvXCI9PT10fHxcImF1dG8gYXV0b1wiPT09dCkmJih0PVwiMCAwXCIpO3ZhciBpPXQuc3BsaXQoXCIgXCIpLHI9LTEhPT10LmluZGV4T2YoXCJsZWZ0XCIpP1wiMCVcIjotMSE9PXQuaW5kZXhPZihcInJpZ2h0XCIpP1wiMTAwJVwiOmlbMF0scz0tMSE9PXQuaW5kZXhPZihcInRvcFwiKT9cIjAlXCI6LTEhPT10LmluZGV4T2YoXCJib3R0b21cIik/XCIxMDAlXCI6aVsxXTtyZXR1cm4gbnVsbD09cz9zPVwiMFwiOlwiY2VudGVyXCI9PT1zJiYocz1cIjUwJVwiKSwoXCJjZW50ZXJcIj09PXJ8fGlzTmFOKHBhcnNlRmxvYXQocikpJiYtMT09PShyK1wiXCIpLmluZGV4T2YoXCI9XCIpKSYmKHI9XCI1MCVcIiksZSYmKGUub3hwPS0xIT09ci5pbmRleE9mKFwiJVwiKSxlLm95cD0tMSE9PXMuaW5kZXhPZihcIiVcIiksZS5veHI9XCI9XCI9PT1yLmNoYXJBdCgxKSxlLm95cj1cIj1cIj09PXMuY2hhckF0KDEpLGUub3g9cGFyc2VGbG9hdChyLnJlcGxhY2UodixcIlwiKSksZS5veT1wYXJzZUZsb2F0KHMucmVwbGFjZSh2LFwiXCIpKSkscitcIiBcIitzKyhpLmxlbmd0aD4yP1wiIFwiK2lbMl06XCJcIil9LGllPWZ1bmN0aW9uKHQsZSl7cmV0dXJuXCJzdHJpbmdcIj09dHlwZW9mIHQmJlwiPVwiPT09dC5jaGFyQXQoMSk/cGFyc2VJbnQodC5jaGFyQXQoMCkrXCIxXCIsMTApKnBhcnNlRmxvYXQodC5zdWJzdHIoMikpOnBhcnNlRmxvYXQodCktcGFyc2VGbG9hdChlKX0scmU9ZnVuY3Rpb24odCxlKXtyZXR1cm4gbnVsbD09dD9lOlwic3RyaW5nXCI9PXR5cGVvZiB0JiZcIj1cIj09PXQuY2hhckF0KDEpP3BhcnNlSW50KHQuY2hhckF0KDApK1wiMVwiLDEwKSpOdW1iZXIodC5zdWJzdHIoMikpK2U6cGFyc2VGbG9hdCh0KX0sc2U9ZnVuY3Rpb24odCxlLGkscil7dmFyIHMsbixhLG8sbD0xZS02O3JldHVybiBudWxsPT10P289ZTpcIm51bWJlclwiPT10eXBlb2YgdD9vPXQ6KHM9MzYwLG49dC5zcGxpdChcIl9cIiksYT1OdW1iZXIoblswXS5yZXBsYWNlKHYsXCJcIikpKigtMT09PXQuaW5kZXhPZihcInJhZFwiKT8xOkwpLShcIj1cIj09PXQuY2hhckF0KDEpPzA6ZSksbi5sZW5ndGgmJihyJiYocltpXT1lK2EpLC0xIT09dC5pbmRleE9mKFwic2hvcnRcIikmJihhJT1zLGEhPT1hJShzLzIpJiYoYT0wPmE/YStzOmEtcykpLC0xIT09dC5pbmRleE9mKFwiX2N3XCIpJiYwPmE/YT0oYSs5OTk5OTk5OTk5KnMpJXMtKDB8YS9zKSpzOi0xIT09dC5pbmRleE9mKFwiY2N3XCIpJiZhPjAmJihhPShhLTk5OTk5OTk5OTkqcyklcy0oMHxhL3MpKnMpKSxvPWUrYSksbD5vJiZvPi1sJiYobz0wKSxvfSxuZT17YXF1YTpbMCwyNTUsMjU1XSxsaW1lOlswLDI1NSwwXSxzaWx2ZXI6WzE5MiwxOTIsMTkyXSxibGFjazpbMCwwLDBdLG1hcm9vbjpbMTI4LDAsMF0sdGVhbDpbMCwxMjgsMTI4XSxibHVlOlswLDAsMjU1XSxuYXZ5OlswLDAsMTI4XSx3aGl0ZTpbMjU1LDI1NSwyNTVdLGZ1Y2hzaWE6WzI1NSwwLDI1NV0sb2xpdmU6WzEyOCwxMjgsMF0seWVsbG93OlsyNTUsMjU1LDBdLG9yYW5nZTpbMjU1LDE2NSwwXSxncmF5OlsxMjgsMTI4LDEyOF0scHVycGxlOlsxMjgsMCwxMjhdLGdyZWVuOlswLDEyOCwwXSxyZWQ6WzI1NSwwLDBdLHBpbms6WzI1NSwxOTIsMjAzXSxjeWFuOlswLDI1NSwyNTVdLHRyYW5zcGFyZW50OlsyNTUsMjU1LDI1NSwwXX0sYWU9ZnVuY3Rpb24odCxlLGkpe3JldHVybiB0PTA+dD90KzE6dD4xP3QtMTp0LDB8MjU1KigxPjYqdD9lKzYqKGktZSkqdDouNT50P2k6Mj4zKnQ/ZSs2KihpLWUpKigyLzMtdCk6ZSkrLjV9LG9lPWZ1bmN0aW9uKHQpe3ZhciBlLGkscixzLG4sYTtyZXR1cm4gdCYmXCJcIiE9PXQ/XCJudW1iZXJcIj09dHlwZW9mIHQ/W3Q+PjE2LDI1NSZ0Pj44LDI1NSZ0XTooXCIsXCI9PT10LmNoYXJBdCh0Lmxlbmd0aC0xKSYmKHQ9dC5zdWJzdHIoMCx0Lmxlbmd0aC0xKSksbmVbdF0/bmVbdF06XCIjXCI9PT10LmNoYXJBdCgwKT8oND09PXQubGVuZ3RoJiYoZT10LmNoYXJBdCgxKSxpPXQuY2hhckF0KDIpLHI9dC5jaGFyQXQoMyksdD1cIiNcIitlK2UraStpK3IrciksdD1wYXJzZUludCh0LnN1YnN0cigxKSwxNiksW3Q+PjE2LDI1NSZ0Pj44LDI1NSZ0XSk6XCJoc2xcIj09PXQuc3Vic3RyKDAsMyk/KHQ9dC5tYXRjaChkKSxzPU51bWJlcih0WzBdKSUzNjAvMzYwLG49TnVtYmVyKHRbMV0pLzEwMCxhPU51bWJlcih0WzJdKS8xMDAsaT0uNT49YT9hKihuKzEpOmErbi1hKm4sZT0yKmEtaSx0Lmxlbmd0aD4zJiYodFszXT1OdW1iZXIodFszXSkpLHRbMF09YWUocysxLzMsZSxpKSx0WzFdPWFlKHMsZSxpKSx0WzJdPWFlKHMtMS8zLGUsaSksdCk6KHQ9dC5tYXRjaChkKXx8bmUudHJhbnNwYXJlbnQsdFswXT1OdW1iZXIodFswXSksdFsxXT1OdW1iZXIodFsxXSksdFsyXT1OdW1iZXIodFsyXSksdC5sZW5ndGg+MyYmKHRbM109TnVtYmVyKHRbM10pKSx0KSk6bmUuYmxhY2t9LGxlPVwiKD86XFxcXGIoPzooPzpyZ2J8cmdiYXxoc2x8aHNsYSlcXFxcKC4rP1xcXFwpKXxcXFxcQiMuKz9cXFxcYlwiO2ZvcihsIGluIG5lKWxlKz1cInxcIitsK1wiXFxcXGJcIjtsZT1SZWdFeHAobGUrXCIpXCIsXCJnaVwiKTt2YXIgaGU9ZnVuY3Rpb24odCxlLGkscil7aWYobnVsbD09dClyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIHR9O3ZhciBzLG49ZT8odC5tYXRjaChsZSl8fFtcIlwiXSlbMF06XCJcIixhPXQuc3BsaXQobikuam9pbihcIlwiKS5tYXRjaChnKXx8W10sbz10LnN1YnN0cigwLHQuaW5kZXhPZihhWzBdKSksbD1cIilcIj09PXQuY2hhckF0KHQubGVuZ3RoLTEpP1wiKVwiOlwiXCIsaD0tMSE9PXQuaW5kZXhPZihcIiBcIik/XCIgXCI6XCIsXCIsdT1hLmxlbmd0aCxmPXU+MD9hWzBdLnJlcGxhY2UoZCxcIlwiKTpcIlwiO3JldHVybiB1P3M9ZT9mdW5jdGlvbih0KXt2YXIgZSxfLHAsYztpZihcIm51bWJlclwiPT10eXBlb2YgdCl0Kz1mO2Vsc2UgaWYociYmRC50ZXN0KHQpKXtmb3IoYz10LnJlcGxhY2UoRCxcInxcIikuc3BsaXQoXCJ8XCIpLHA9MDtjLmxlbmd0aD5wO3ArKyljW3BdPXMoY1twXSk7cmV0dXJuIGMuam9pbihcIixcIil9aWYoZT0odC5tYXRjaChsZSl8fFtuXSlbMF0sXz10LnNwbGl0KGUpLmpvaW4oXCJcIikubWF0Y2goZyl8fFtdLHA9Xy5sZW5ndGgsdT5wLS0pZm9yKDt1PisrcDspX1twXT1pP19bMHwocC0xKS8yXTphW3BdO3JldHVybiBvK18uam9pbihoKStoK2UrbCsoLTEhPT10LmluZGV4T2YoXCJpbnNldFwiKT9cIiBpbnNldFwiOlwiXCIpfTpmdW5jdGlvbih0KXt2YXIgZSxuLF87aWYoXCJudW1iZXJcIj09dHlwZW9mIHQpdCs9ZjtlbHNlIGlmKHImJkQudGVzdCh0KSl7Zm9yKG49dC5yZXBsYWNlKEQsXCJ8XCIpLnNwbGl0KFwifFwiKSxfPTA7bi5sZW5ndGg+XztfKyspbltfXT1zKG5bX10pO3JldHVybiBuLmpvaW4oXCIsXCIpfWlmKGU9dC5tYXRjaChnKXx8W10sXz1lLmxlbmd0aCx1Pl8tLSlmb3IoO3U+KytfOyllW19dPWk/ZVswfChfLTEpLzJdOmFbX107cmV0dXJuIG8rZS5qb2luKGgpK2x9OmZ1bmN0aW9uKHQpe3JldHVybiB0fX0sdWU9ZnVuY3Rpb24odCl7cmV0dXJuIHQ9dC5zcGxpdChcIixcIiksZnVuY3Rpb24oZSxpLHIscyxuLGEsbyl7dmFyIGwsaD0oaStcIlwiKS5zcGxpdChcIiBcIik7Zm9yKG89e30sbD0wOzQ+bDtsKyspb1t0W2xdXT1oW2xdPWhbbF18fGhbKGwtMSkvMj4+MF07cmV0dXJuIHMucGFyc2UoZSxvLG4sYSl9fSxmZT0oRS5fc2V0UGx1Z2luUmF0aW89ZnVuY3Rpb24odCl7dGhpcy5wbHVnaW4uc2V0UmF0aW8odCk7Zm9yKHZhciBlLGkscixzLG49dGhpcy5kYXRhLGE9bi5wcm94eSxvPW4uZmlyc3RNUFQsbD0xZS02O287KWU9YVtvLnZdLG8ucj9lPU1hdGgucm91bmQoZSk6bD5lJiZlPi1sJiYoZT0wKSxvLnRbby5wXT1lLG89by5fbmV4dDtpZihuLmF1dG9Sb3RhdGUmJihuLmF1dG9Sb3RhdGUucm90YXRpb249YS5yb3RhdGlvbiksMT09PXQpZm9yKG89bi5maXJzdE1QVDtvOyl7aWYoaT1vLnQsaS50eXBlKXtpZigxPT09aS50eXBlKXtmb3Iocz1pLnhzMCtpLnMraS54czEscj0xO2kubD5yO3IrKylzKz1pW1wieG5cIityXStpW1wieHNcIisocisxKV07aS5lPXN9fWVsc2UgaS5lPWkucytpLnhzMDtvPW8uX25leHR9fSxmdW5jdGlvbih0LGUsaSxyLHMpe3RoaXMudD10LHRoaXMucD1lLHRoaXMudj1pLHRoaXMucj1zLHImJihyLl9wcmV2PXRoaXMsdGhpcy5fbmV4dD1yKX0pLF9lPShFLl9wYXJzZVRvUHJveHk9ZnVuY3Rpb24odCxlLGkscixzLG4pe3ZhciBhLG8sbCxoLHUsZj1yLF89e30scD17fSxjPWkuX3RyYW5zZm9ybSxkPU47Zm9yKGkuX3RyYW5zZm9ybT1udWxsLE49ZSxyPXU9aS5wYXJzZSh0LGUscixzKSxOPWQsbiYmKGkuX3RyYW5zZm9ybT1jLGYmJihmLl9wcmV2PW51bGwsZi5fcHJldiYmKGYuX3ByZXYuX25leHQ9bnVsbCkpKTtyJiZyIT09Zjspe2lmKDE+PXIudHlwZSYmKG89ci5wLHBbb109ci5zK3IuYyxfW29dPXIucyxufHwoaD1uZXcgZmUocixcInNcIixvLGgsci5yKSxyLmM9MCksMT09PXIudHlwZSkpZm9yKGE9ci5sOy0tYT4wOylsPVwieG5cIithLG89ci5wK1wiX1wiK2wscFtvXT1yLmRhdGFbbF0sX1tvXT1yW2xdLG58fChoPW5ldyBmZShyLGwsbyxoLHIucnhwW2xdKSk7cj1yLl9uZXh0fXJldHVybntwcm94eTpfLGVuZDpwLGZpcnN0TVBUOmgscHQ6dX19LEUuQ1NTUHJvcFR3ZWVuPWZ1bmN0aW9uKHQsZSxyLHMsYSxvLGwsaCx1LGYsXyl7dGhpcy50PXQsdGhpcy5wPWUsdGhpcy5zPXIsdGhpcy5jPXMsdGhpcy5uPWx8fGUsdCBpbnN0YW5jZW9mIF9lfHxuLnB1c2godGhpcy5uKSx0aGlzLnI9aCx0aGlzLnR5cGU9b3x8MCx1JiYodGhpcy5wcj11LGk9ITApLHRoaXMuYj12b2lkIDA9PT1mP3I6Zix0aGlzLmU9dm9pZCAwPT09Xz9yK3M6XyxhJiYodGhpcy5fbmV4dD1hLGEuX3ByZXY9dGhpcyl9KSxwZT1hLnBhcnNlQ29tcGxleD1mdW5jdGlvbih0LGUsaSxyLHMsbixhLG8sbCx1KXtpPWl8fG58fFwiXCIsYT1uZXcgX2UodCxlLDAsMCxhLHU/MjoxLG51bGwsITEsbyxpLHIpLHIrPVwiXCI7dmFyIGYsXyxwLGMsZyx2LHksVCx3LHgsUCxTLEM9aS5zcGxpdChcIiwgXCIpLmpvaW4oXCIsXCIpLnNwbGl0KFwiIFwiKSxSPXIuc3BsaXQoXCIsIFwiKS5qb2luKFwiLFwiKS5zcGxpdChcIiBcIiksaz1DLmxlbmd0aCxBPWghPT0hMTtmb3IoKC0xIT09ci5pbmRleE9mKFwiLFwiKXx8LTEhPT1pLmluZGV4T2YoXCIsXCIpKSYmKEM9Qy5qb2luKFwiIFwiKS5yZXBsYWNlKEQsXCIsIFwiKS5zcGxpdChcIiBcIiksUj1SLmpvaW4oXCIgXCIpLnJlcGxhY2UoRCxcIiwgXCIpLnNwbGl0KFwiIFwiKSxrPUMubGVuZ3RoKSxrIT09Ui5sZW5ndGgmJihDPShufHxcIlwiKS5zcGxpdChcIiBcIiksaz1DLmxlbmd0aCksYS5wbHVnaW49bCxhLnNldFJhdGlvPXUsZj0wO2s+ZjtmKyspaWYoYz1DW2ZdLGc9UltmXSxUPXBhcnNlRmxvYXQoYyksVHx8MD09PVQpYS5hcHBlbmRYdHJhKFwiXCIsVCxpZShnLFQpLGcucmVwbGFjZShtLFwiXCIpLEEmJi0xIT09Zy5pbmRleE9mKFwicHhcIiksITApO2Vsc2UgaWYocyYmKFwiI1wiPT09Yy5jaGFyQXQoMCl8fG5lW2NdfHxiLnRlc3QoYykpKVM9XCIsXCI9PT1nLmNoYXJBdChnLmxlbmd0aC0xKT9cIiksXCI6XCIpXCIsYz1vZShjKSxnPW9lKGcpLHc9Yy5sZW5ndGgrZy5sZW5ndGg+Nix3JiYhWSYmMD09PWdbM10/KGFbXCJ4c1wiK2EubF0rPWEubD9cIiB0cmFuc3BhcmVudFwiOlwidHJhbnNwYXJlbnRcIixhLmU9YS5lLnNwbGl0KFJbZl0pLmpvaW4oXCJ0cmFuc3BhcmVudFwiKSk6KFl8fCh3PSExKSxhLmFwcGVuZFh0cmEodz9cInJnYmEoXCI6XCJyZ2IoXCIsY1swXSxnWzBdLWNbMF0sXCIsXCIsITAsITApLmFwcGVuZFh0cmEoXCJcIixjWzFdLGdbMV0tY1sxXSxcIixcIiwhMCkuYXBwZW5kWHRyYShcIlwiLGNbMl0sZ1syXS1jWzJdLHc/XCIsXCI6UywhMCksdyYmKGM9ND5jLmxlbmd0aD8xOmNbM10sYS5hcHBlbmRYdHJhKFwiXCIsYywoND5nLmxlbmd0aD8xOmdbM10pLWMsUywhMSkpKTtlbHNlIGlmKHY9Yy5tYXRjaChkKSl7aWYoeT1nLm1hdGNoKG0pLCF5fHx5Lmxlbmd0aCE9PXYubGVuZ3RoKXJldHVybiBhO2ZvcihwPTAsXz0wO3YubGVuZ3RoPl87XysrKVA9dltfXSx4PWMuaW5kZXhPZihQLHApLGEuYXBwZW5kWHRyYShjLnN1YnN0cihwLHgtcCksTnVtYmVyKFApLGllKHlbX10sUCksXCJcIixBJiZcInB4XCI9PT1jLnN1YnN0cih4K1AubGVuZ3RoLDIpLDA9PT1fKSxwPXgrUC5sZW5ndGg7YVtcInhzXCIrYS5sXSs9Yy5zdWJzdHIocCl9ZWxzZSBhW1wieHNcIithLmxdKz1hLmw/XCIgXCIrYzpjO2lmKC0xIT09ci5pbmRleE9mKFwiPVwiKSYmYS5kYXRhKXtmb3IoUz1hLnhzMCthLmRhdGEucyxmPTE7YS5sPmY7ZisrKVMrPWFbXCJ4c1wiK2ZdK2EuZGF0YVtcInhuXCIrZl07YS5lPVMrYVtcInhzXCIrZl19cmV0dXJuIGEubHx8KGEudHlwZT0tMSxhLnhzMD1hLmUpLGEueGZpcnN0fHxhfSxjZT05O2ZvcihsPV9lLnByb3RvdHlwZSxsLmw9bC5wcj0wOy0tY2U+MDspbFtcInhuXCIrY2VdPTAsbFtcInhzXCIrY2VdPVwiXCI7bC54czA9XCJcIixsLl9uZXh0PWwuX3ByZXY9bC54Zmlyc3Q9bC5kYXRhPWwucGx1Z2luPWwuc2V0UmF0aW89bC5yeHA9bnVsbCxsLmFwcGVuZFh0cmE9ZnVuY3Rpb24odCxlLGkscixzLG4pe3ZhciBhPXRoaXMsbz1hLmw7cmV0dXJuIGFbXCJ4c1wiK29dKz1uJiZvP1wiIFwiK3Q6dHx8XCJcIixpfHwwPT09b3x8YS5wbHVnaW4/KGEubCsrLGEudHlwZT1hLnNldFJhdGlvPzI6MSxhW1wieHNcIithLmxdPXJ8fFwiXCIsbz4wPyhhLmRhdGFbXCJ4blwiK29dPWUraSxhLnJ4cFtcInhuXCIrb109cyxhW1wieG5cIitvXT1lLGEucGx1Z2lufHwoYS54Zmlyc3Q9bmV3IF9lKGEsXCJ4blwiK28sZSxpLGEueGZpcnN0fHxhLDAsYS5uLHMsYS5wciksYS54Zmlyc3QueHMwPTApLGEpOihhLmRhdGE9e3M6ZStpfSxhLnJ4cD17fSxhLnM9ZSxhLmM9aSxhLnI9cyxhKSk6KGFbXCJ4c1wiK29dKz1lKyhyfHxcIlwiKSxhKX07dmFyIGRlPWZ1bmN0aW9uKHQsZSl7ZT1lfHx7fSx0aGlzLnA9ZS5wcmVmaXg/Vih0KXx8dDp0LG9bdF09b1t0aGlzLnBdPXRoaXMsdGhpcy5mb3JtYXQ9ZS5mb3JtYXR0ZXJ8fGhlKGUuZGVmYXVsdFZhbHVlLGUuY29sb3IsZS5jb2xsYXBzaWJsZSxlLm11bHRpKSxlLnBhcnNlciYmKHRoaXMucGFyc2U9ZS5wYXJzZXIpLHRoaXMuY2xycz1lLmNvbG9yLHRoaXMubXVsdGk9ZS5tdWx0aSx0aGlzLmtleXdvcmQ9ZS5rZXl3b3JkLHRoaXMuZGZsdD1lLmRlZmF1bHRWYWx1ZSx0aGlzLnByPWUucHJpb3JpdHl8fDB9LG1lPUUuX3JlZ2lzdGVyQ29tcGxleFNwZWNpYWxQcm9wPWZ1bmN0aW9uKHQsZSxpKXtcIm9iamVjdFwiIT10eXBlb2YgZSYmKGU9e3BhcnNlcjppfSk7dmFyIHIscyxuPXQuc3BsaXQoXCIsXCIpLGE9ZS5kZWZhdWx0VmFsdWU7Zm9yKGk9aXx8W2FdLHI9MDtuLmxlbmd0aD5yO3IrKyllLnByZWZpeD0wPT09ciYmZS5wcmVmaXgsZS5kZWZhdWx0VmFsdWU9aVtyXXx8YSxzPW5ldyBkZShuW3JdLGUpfSxnZT1mdW5jdGlvbih0KXtpZighb1t0XSl7dmFyIGU9dC5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSt0LnN1YnN0cigxKStcIlBsdWdpblwiO21lKHQse3BhcnNlcjpmdW5jdGlvbih0LGkscixzLG4sYSxsKXt2YXIgaD0od2luZG93LkdyZWVuU29ja0dsb2JhbHN8fHdpbmRvdykuY29tLmdyZWVuc29jay5wbHVnaW5zW2VdO3JldHVybiBoPyhoLl9jc3NSZWdpc3RlcigpLG9bcl0ucGFyc2UodCxpLHIscyxuLGEsbCkpOihVKFwiRXJyb3I6IFwiK2UrXCIganMgZmlsZSBub3QgbG9hZGVkLlwiKSxuKX19KX19O2w9ZGUucHJvdG90eXBlLGwucGFyc2VDb21wbGV4PWZ1bmN0aW9uKHQsZSxpLHIscyxuKXt2YXIgYSxvLGwsaCx1LGYsXz10aGlzLmtleXdvcmQ7aWYodGhpcy5tdWx0aSYmKEQudGVzdChpKXx8RC50ZXN0KGUpPyhvPWUucmVwbGFjZShELFwifFwiKS5zcGxpdChcInxcIiksbD1pLnJlcGxhY2UoRCxcInxcIikuc3BsaXQoXCJ8XCIpKTpfJiYobz1bZV0sbD1baV0pKSxsKXtmb3IoaD1sLmxlbmd0aD5vLmxlbmd0aD9sLmxlbmd0aDpvLmxlbmd0aCxhPTA7aD5hO2ErKyllPW9bYV09b1thXXx8dGhpcy5kZmx0LGk9bFthXT1sW2FdfHx0aGlzLmRmbHQsXyYmKHU9ZS5pbmRleE9mKF8pLGY9aS5pbmRleE9mKF8pLHUhPT1mJiYoaT0tMT09PWY/bDpvLGlbYV0rPVwiIFwiK18pKTtlPW8uam9pbihcIiwgXCIpLGk9bC5qb2luKFwiLCBcIil9cmV0dXJuIHBlKHQsdGhpcy5wLGUsaSx0aGlzLmNscnMsdGhpcy5kZmx0LHIsdGhpcy5wcixzLG4pfSxsLnBhcnNlPWZ1bmN0aW9uKHQsZSxpLHIsbixhKXtyZXR1cm4gdGhpcy5wYXJzZUNvbXBsZXgodC5zdHlsZSx0aGlzLmZvcm1hdChxKHQsdGhpcy5wLHMsITEsdGhpcy5kZmx0KSksdGhpcy5mb3JtYXQoZSksbixhKX0sYS5yZWdpc3RlclNwZWNpYWxQcm9wPWZ1bmN0aW9uKHQsZSxpKXttZSh0LHtwYXJzZXI6ZnVuY3Rpb24odCxyLHMsbixhLG8pe3ZhciBsPW5ldyBfZSh0LHMsMCwwLGEsMixzLCExLGkpO3JldHVybiBsLnBsdWdpbj1vLGwuc2V0UmF0aW89ZSh0LHIsbi5fdHdlZW4scyksbH0scHJpb3JpdHk6aX0pfTt2YXIgdmU9XCJzY2FsZVgsc2NhbGVZLHNjYWxlWix4LHkseixza2V3WCxza2V3WSxyb3RhdGlvbixyb3RhdGlvblgscm90YXRpb25ZLHBlcnNwZWN0aXZlXCIuc3BsaXQoXCIsXCIpLHllPVYoXCJ0cmFuc2Zvcm1cIiksVGU9VytcInRyYW5zZm9ybVwiLHdlPVYoXCJ0cmFuc2Zvcm1PcmlnaW5cIikseGU9bnVsbCE9PVYoXCJwZXJzcGVjdGl2ZVwiKSxiZT1FLlRyYW5zZm9ybT1mdW5jdGlvbigpe3RoaXMuc2tld1k9MH0sUGU9RS5nZXRUcmFuc2Zvcm09ZnVuY3Rpb24odCxlLGkscil7aWYodC5fZ3NUcmFuc2Zvcm0mJmkmJiFyKXJldHVybiB0Ll9nc1RyYW5zZm9ybTt2YXIgcyxuLG8sbCxoLHUsZixfLHAsYyxkLG0sZyx2PWk/dC5fZ3NUcmFuc2Zvcm18fG5ldyBiZTpuZXcgYmUseT0wPnYuc2NhbGVYLFQ9MmUtNSx3PTFlNSx4PTE3OS45OSxiPXgqTSxQPXhlP3BhcnNlRmxvYXQocSh0LHdlLGUsITEsXCIwIDAgMFwiKS5zcGxpdChcIiBcIilbMl0pfHx2LnpPcmlnaW58fDA6MDtmb3IoeWU/cz1xKHQsVGUsZSwhMCk6dC5jdXJyZW50U3R5bGUmJihzPXQuY3VycmVudFN0eWxlLmZpbHRlci5tYXRjaChBKSxzPXMmJjQ9PT1zLmxlbmd0aD9bc1swXS5zdWJzdHIoNCksTnVtYmVyKHNbMl0uc3Vic3RyKDQpKSxOdW1iZXIoc1sxXS5zdWJzdHIoNCkpLHNbM10uc3Vic3RyKDQpLHYueHx8MCx2Lnl8fDBdLmpvaW4oXCIsXCIpOlwiXCIpLG49KHN8fFwiXCIpLm1hdGNoKC8oPzpcXC18XFxiKVtcXGRcXC1cXC5lXStcXGIvZ2kpfHxbXSxvPW4ubGVuZ3RoOy0tbz4tMTspbD1OdW1iZXIobltvXSksbltvXT0oaD1sLShsfD0wKSk/KDB8aCp3KygwPmg/LS41Oi41KSkvdytsOmw7aWYoMTY9PT1uLmxlbmd0aCl7dmFyIFM9bls4XSxDPW5bOV0sUj1uWzEwXSxrPW5bMTJdLE89blsxM10sRD1uWzE0XTtpZih2LnpPcmlnaW4mJihEPS12LnpPcmlnaW4saz1TKkQtblsxMl0sTz1DKkQtblsxM10sRD1SKkQrdi56T3JpZ2luLW5bMTRdKSwhaXx8cnx8bnVsbD09di5yb3RhdGlvblgpe3ZhciBOLFgseixJLEUsRixZLEI9blswXSxVPW5bMV0sVz1uWzJdLGo9blszXSxWPW5bNF0sSD1uWzVdLFE9bls2XSxaPW5bN10sJD1uWzExXSxHPU1hdGguYXRhbjIoUSxSKSxLPS1iPkd8fEc+Yjt2LnJvdGF0aW9uWD1HKkwsRyYmKEk9TWF0aC5jb3MoLUcpLEU9TWF0aC5zaW4oLUcpLE49VipJK1MqRSxYPUgqSStDKkUsej1RKkkrUipFLFM9ViotRStTKkksQz1IKi1FK0MqSSxSPVEqLUUrUipJLCQ9WiotRSskKkksVj1OLEg9WCxRPXopLEc9TWF0aC5hdGFuMihTLEIpLHYucm90YXRpb25ZPUcqTCxHJiYoRj0tYj5HfHxHPmIsST1NYXRoLmNvcygtRyksRT1NYXRoLnNpbigtRyksTj1CKkktUypFLFg9VSpJLUMqRSx6PVcqSS1SKkUsQz1VKkUrQypJLFI9VypFK1IqSSwkPWoqRSskKkksQj1OLFU9WCxXPXopLEc9TWF0aC5hdGFuMihVLEgpLHYucm90YXRpb249RypMLEcmJihZPS1iPkd8fEc+YixJPU1hdGguY29zKC1HKSxFPU1hdGguc2luKC1HKSxCPUIqSStWKkUsWD1VKkkrSCpFLEg9VSotRStIKkksUT1XKi1FK1EqSSxVPVgpLFkmJks/di5yb3RhdGlvbj12LnJvdGF0aW9uWD0wOlkmJkY/di5yb3RhdGlvbj12LnJvdGF0aW9uWT0wOkYmJksmJih2LnJvdGF0aW9uWT12LnJvdGF0aW9uWD0wKSx2LnNjYWxlWD0oMHxNYXRoLnNxcnQoQipCK1UqVSkqdysuNSkvdyx2LnNjYWxlWT0oMHxNYXRoLnNxcnQoSCpIK0MqQykqdysuNSkvdyx2LnNjYWxlWj0oMHxNYXRoLnNxcnQoUSpRK1IqUikqdysuNSkvdyx2LnNrZXdYPTAsdi5wZXJzcGVjdGl2ZT0kPzEvKDA+JD8tJDokKTowLHYueD1rLHYueT1PLHYuej1EfX1lbHNlIGlmKCEoeGUmJiFyJiZuLmxlbmd0aCYmdi54PT09bls0XSYmdi55PT09bls1XSYmKHYucm90YXRpb25YfHx2LnJvdGF0aW9uWSl8fHZvaWQgMCE9PXYueCYmXCJub25lXCI9PT1xKHQsXCJkaXNwbGF5XCIsZSkpKXt2YXIgSj1uLmxlbmd0aD49Nix0ZT1KP25bMF06MSxlZT1uWzFdfHwwLGllPW5bMl18fDAscmU9Sj9uWzNdOjE7di54PW5bNF18fDAsdi55PW5bNV18fDAsdT1NYXRoLnNxcnQodGUqdGUrZWUqZWUpLGY9TWF0aC5zcXJ0KHJlKnJlK2llKmllKSxfPXRlfHxlZT9NYXRoLmF0YW4yKGVlLHRlKSpMOnYucm90YXRpb258fDAscD1pZXx8cmU/TWF0aC5hdGFuMihpZSxyZSkqTCtfOnYuc2tld1h8fDAsYz11LU1hdGguYWJzKHYuc2NhbGVYfHwwKSxkPWYtTWF0aC5hYnModi5zY2FsZVl8fDApLE1hdGguYWJzKHApPjkwJiYyNzA+TWF0aC5hYnMocCkmJih5Pyh1Kj0tMSxwKz0wPj1fPzE4MDotMTgwLF8rPTA+PV8/MTgwOi0xODApOihmKj0tMSxwKz0wPj1wPzE4MDotMTgwKSksbT0oXy12LnJvdGF0aW9uKSUxODAsZz0ocC12LnNrZXdYKSUxODAsKHZvaWQgMD09PXYuc2tld1h8fGM+VHx8LVQ+Y3x8ZD5UfHwtVD5kfHxtPi14JiZ4Pm0mJmZhbHNlfG0qd3x8Zz4teCYmeD5nJiZmYWxzZXxnKncpJiYodi5zY2FsZVg9dSx2LnNjYWxlWT1mLHYucm90YXRpb249Xyx2LnNrZXdYPXApLHhlJiYodi5yb3RhdGlvblg9di5yb3RhdGlvblk9di56PTAsdi5wZXJzcGVjdGl2ZT1wYXJzZUZsb2F0KGEuZGVmYXVsdFRyYW5zZm9ybVBlcnNwZWN0aXZlKXx8MCx2LnNjYWxlWj0xKX12LnpPcmlnaW49UDtmb3IobyBpbiB2KVQ+dltvXSYmdltvXT4tVCYmKHZbb109MCk7cmV0dXJuIGkmJih0Ll9nc1RyYW5zZm9ybT12KSx2fSxTZT1mdW5jdGlvbih0KXt2YXIgZSxpLHI9dGhpcy5kYXRhLHM9LXIucm90YXRpb24qTSxuPXMrci5za2V3WCpNLGE9MWU1LG89KDB8TWF0aC5jb3Mocykqci5zY2FsZVgqYSkvYSxsPSgwfE1hdGguc2luKHMpKnIuc2NhbGVYKmEpL2EsaD0oMHxNYXRoLnNpbihuKSotci5zY2FsZVkqYSkvYSx1PSgwfE1hdGguY29zKG4pKnIuc2NhbGVZKmEpL2EsZj10aGlzLnQuc3R5bGUsXz10aGlzLnQuY3VycmVudFN0eWxlO2lmKF8pe2k9bCxsPS1oLGg9LWksZT1fLmZpbHRlcixmLmZpbHRlcj1cIlwiO3ZhciBwLGQsbT10aGlzLnQub2Zmc2V0V2lkdGgsZz10aGlzLnQub2Zmc2V0SGVpZ2h0LHY9XCJhYnNvbHV0ZVwiIT09Xy5wb3NpdGlvbix3PVwicHJvZ2lkOkRYSW1hZ2VUcmFuc2Zvcm0uTWljcm9zb2Z0Lk1hdHJpeChNMTE9XCIrbytcIiwgTTEyPVwiK2wrXCIsIE0yMT1cIitoK1wiLCBNMjI9XCIrdSx4PXIueCxiPXIueTtpZihudWxsIT1yLm94JiYocD0oci5veHA/LjAxKm0qci5veDpyLm94KS1tLzIsZD0oci5veXA/LjAxKmcqci5veTpyLm95KS1nLzIseCs9cC0ocCpvK2QqbCksYis9ZC0ocCpoK2QqdSkpLHY/KHA9bS8yLGQ9Zy8yLHcrPVwiLCBEeD1cIisocC0ocCpvK2QqbCkreCkrXCIsIER5PVwiKyhkLShwKmgrZCp1KStiKStcIilcIik6dys9XCIsIHNpemluZ01ldGhvZD0nYXV0byBleHBhbmQnKVwiLGYuZmlsdGVyPS0xIT09ZS5pbmRleE9mKFwiRFhJbWFnZVRyYW5zZm9ybS5NaWNyb3NvZnQuTWF0cml4KFwiKT9lLnJlcGxhY2UoTyx3KTp3K1wiIFwiK2UsKDA9PT10fHwxPT09dCkmJjE9PT1vJiYwPT09bCYmMD09PWgmJjE9PT11JiYodiYmLTE9PT13LmluZGV4T2YoXCJEeD0wLCBEeT0wXCIpfHxULnRlc3QoZSkmJjEwMCE9PXBhcnNlRmxvYXQoUmVnRXhwLiQxKXx8LTE9PT1lLmluZGV4T2YoXCJncmFkaWVudChcIiYmZS5pbmRleE9mKFwiQWxwaGFcIikpJiZmLnJlbW92ZUF0dHJpYnV0ZShcImZpbHRlclwiKSksIXYpe3ZhciBQLFMsQyxSPTg+Yz8xOi0xO2ZvcihwPXIuaWVPZmZzZXRYfHwwLGQ9ci5pZU9mZnNldFl8fDAsci5pZU9mZnNldFg9TWF0aC5yb3VuZCgobS0oKDA+bz8tbzpvKSptKygwPmw/LWw6bCkqZykpLzIreCksci5pZU9mZnNldFk9TWF0aC5yb3VuZCgoZy0oKDA+dT8tdTp1KSpnKygwPmg/LWg6aCkqbSkpLzIrYiksY2U9MDs0PmNlO2NlKyspUz1KW2NlXSxQPV9bU10saT0tMSE9PVAuaW5kZXhPZihcInB4XCIpP3BhcnNlRmxvYXQoUCk6USh0aGlzLnQsUyxwYXJzZUZsb2F0KFApLFAucmVwbGFjZSh5LFwiXCIpKXx8MCxDPWkhPT1yW1NdPzI+Y2U/LXIuaWVPZmZzZXRYOi1yLmllT2Zmc2V0WToyPmNlP3Atci5pZU9mZnNldFg6ZC1yLmllT2Zmc2V0WSxmW1NdPShyW1NdPU1hdGgucm91bmQoaS1DKigwPT09Y2V8fDI9PT1jZT8xOlIpKSkrXCJweFwifX19LENlPUUuc2V0M0RUcmFuc2Zvcm1SYXRpbz1mdW5jdGlvbih0KXt2YXIgZSxpLHIscyxuLGEsbyxsLGgsdSxmLHAsYyxkLG0sZyx2LHksVCx3LHgsYixQLFM9dGhpcy5kYXRhLEM9dGhpcy50LnN0eWxlLFI9Uy5yb3RhdGlvbipNLGs9Uy5zY2FsZVgsQT1TLnNjYWxlWSxPPVMuc2NhbGVaLEQ9Uy5wZXJzcGVjdGl2ZTtpZighKDEhPT10JiYwIT09dHx8XCJhdXRvXCIhPT1TLmZvcmNlM0R8fFMucm90YXRpb25ZfHxTLnJvdGF0aW9uWHx8MSE9PU98fER8fFMueikpcmV0dXJuIFJlLmNhbGwodGhpcyx0KSx2b2lkIDA7aWYoXyl7dmFyIEw9MWUtNDtMPmsmJms+LUwmJihrPU89MmUtNSksTD5BJiZBPi1MJiYoQT1PPTJlLTUpLCFEfHxTLnp8fFMucm90YXRpb25YfHxTLnJvdGF0aW9uWXx8KEQ9MCl9aWYoUnx8Uy5za2V3WCl5PU1hdGguY29zKFIpLFQ9TWF0aC5zaW4oUiksZT15LG49VCxTLnNrZXdYJiYoUi09Uy5za2V3WCpNLHk9TWF0aC5jb3MoUiksVD1NYXRoLnNpbihSKSxcInNpbXBsZVwiPT09Uy5za2V3VHlwZSYmKHc9TWF0aC50YW4oUy5za2V3WCpNKSx3PU1hdGguc3FydCgxK3cqdykseSo9dyxUKj13KSksaT0tVCxhPXk7ZWxzZXtpZighKFMucm90YXRpb25ZfHxTLnJvdGF0aW9uWHx8MSE9PU98fEQpKXJldHVybiBDW3llXT1cInRyYW5zbGF0ZTNkKFwiK1MueCtcInB4LFwiK1MueStcInB4LFwiK1MueitcInB4KVwiKygxIT09a3x8MSE9PUE/XCIgc2NhbGUoXCIraytcIixcIitBK1wiKVwiOlwiXCIpLHZvaWQgMDtlPWE9MSxpPW49MH1mPTEscj1zPW89bD1oPXU9cD1jPWQ9MCxtPUQ/LTEvRDowLGc9Uy56T3JpZ2luLHY9MWU1LFI9Uy5yb3RhdGlvblkqTSxSJiYoeT1NYXRoLmNvcyhSKSxUPU1hdGguc2luKFIpLGg9ZiotVCxjPW0qLVQscj1lKlQsbz1uKlQsZio9eSxtKj15LGUqPXksbio9eSksUj1TLnJvdGF0aW9uWCpNLFImJih5PU1hdGguY29zKFIpLFQ9TWF0aC5zaW4oUiksdz1pKnkrcipULHg9YSp5K28qVCxiPXUqeStmKlQsUD1kKnkrbSpULHI9aSotVCtyKnksbz1hKi1UK28qeSxmPXUqLVQrZip5LG09ZCotVCttKnksaT13LGE9eCx1PWIsZD1QKSwxIT09TyYmKHIqPU8sbyo9TyxmKj1PLG0qPU8pLDEhPT1BJiYoaSo9QSxhKj1BLHUqPUEsZCo9QSksMSE9PWsmJihlKj1rLG4qPWssaCo9ayxjKj1rKSxnJiYocC09ZyxzPXIqcCxsPW8qcCxwPWYqcCtnKSxzPSh3PShzKz1TLngpLShzfD0wKSk/KDB8dyp2KygwPnc/LS41Oi41KSkvditzOnMsbD0odz0obCs9Uy55KS0obHw9MCkpPygwfHcqdisoMD53Py0uNTouNSkpL3YrbDpsLHA9KHc9KHArPVMueiktKHB8PTApKT8oMHx3KnYrKDA+dz8tLjU6LjUpKS92K3A6cCxDW3llXT1cIm1hdHJpeDNkKFwiK1soMHxlKnYpL3YsKDB8bip2KS92LCgwfGgqdikvdiwoMHxjKnYpL3YsKDB8aSp2KS92LCgwfGEqdikvdiwoMHx1KnYpL3YsKDB8ZCp2KS92LCgwfHIqdikvdiwoMHxvKnYpL3YsKDB8Zip2KS92LCgwfG0qdikvdixzLGwscCxEPzErLXAvRDoxXS5qb2luKFwiLFwiKStcIilcIn0sUmU9RS5zZXQyRFRyYW5zZm9ybVJhdGlvPWZ1bmN0aW9uKHQpe3ZhciBlLGkscixzLG4sYT10aGlzLmRhdGEsbz10aGlzLnQsbD1vLnN0eWxlO3JldHVybiBhLnJvdGF0aW9uWHx8YS5yb3RhdGlvbll8fGEuenx8YS5mb3JjZTNEPT09ITB8fFwiYXV0b1wiPT09YS5mb3JjZTNEJiYxIT09dCYmMCE9PXQ/KHRoaXMuc2V0UmF0aW89Q2UsQ2UuY2FsbCh0aGlzLHQpLHZvaWQgMCk6KGEucm90YXRpb258fGEuc2tld1g/KGU9YS5yb3RhdGlvbipNLGk9ZS1hLnNrZXdYKk0scj0xZTUscz1hLnNjYWxlWCpyLG49YS5zY2FsZVkqcixsW3llXT1cIm1hdHJpeChcIisoMHxNYXRoLmNvcyhlKSpzKS9yK1wiLFwiKygwfE1hdGguc2luKGUpKnMpL3IrXCIsXCIrKDB8TWF0aC5zaW4oaSkqLW4pL3IrXCIsXCIrKDB8TWF0aC5jb3MoaSkqbikvcitcIixcIithLngrXCIsXCIrYS55K1wiKVwiKTpsW3llXT1cIm1hdHJpeChcIithLnNjYWxlWCtcIiwwLDAsXCIrYS5zY2FsZVkrXCIsXCIrYS54K1wiLFwiK2EueStcIilcIix2b2lkIDApfTttZShcInRyYW5zZm9ybSxzY2FsZSxzY2FsZVgsc2NhbGVZLHNjYWxlWix4LHkseixyb3RhdGlvbixyb3RhdGlvblgscm90YXRpb25ZLHJvdGF0aW9uWixza2V3WCxza2V3WSxzaG9ydFJvdGF0aW9uLHNob3J0Um90YXRpb25YLHNob3J0Um90YXRpb25ZLHNob3J0Um90YXRpb25aLHRyYW5zZm9ybU9yaWdpbix0cmFuc2Zvcm1QZXJzcGVjdGl2ZSxkaXJlY3Rpb25hbFJvdGF0aW9uLHBhcnNlVHJhbnNmb3JtLGZvcmNlM0Qsc2tld1R5cGVcIix7cGFyc2VyOmZ1bmN0aW9uKHQsZSxpLHIsbixvLGwpe2lmKHIuX3RyYW5zZm9ybSlyZXR1cm4gbjt2YXIgaCx1LGYsXyxwLGMsZCxtPXIuX3RyYW5zZm9ybT1QZSh0LHMsITAsbC5wYXJzZVRyYW5zZm9ybSksZz10LnN0eWxlLHY9MWUtNix5PXZlLmxlbmd0aCxUPWwsdz17fTtpZihcInN0cmluZ1wiPT10eXBlb2YgVC50cmFuc2Zvcm0mJnllKWY9ei5zdHlsZSxmW3llXT1ULnRyYW5zZm9ybSxmLmRpc3BsYXk9XCJibG9ja1wiLGYucG9zaXRpb249XCJhYnNvbHV0ZVwiLFguYm9keS5hcHBlbmRDaGlsZCh6KSxoPVBlKHosbnVsbCwhMSksWC5ib2R5LnJlbW92ZUNoaWxkKHopO2Vsc2UgaWYoXCJvYmplY3RcIj09dHlwZW9mIFQpe2lmKGg9e3NjYWxlWDpyZShudWxsIT1ULnNjYWxlWD9ULnNjYWxlWDpULnNjYWxlLG0uc2NhbGVYKSxzY2FsZVk6cmUobnVsbCE9VC5zY2FsZVk/VC5zY2FsZVk6VC5zY2FsZSxtLnNjYWxlWSksc2NhbGVaOnJlKFQuc2NhbGVaLG0uc2NhbGVaKSx4OnJlKFQueCxtLngpLHk6cmUoVC55LG0ueSksejpyZShULnosbS56KSxwZXJzcGVjdGl2ZTpyZShULnRyYW5zZm9ybVBlcnNwZWN0aXZlLG0ucGVyc3BlY3RpdmUpfSxkPVQuZGlyZWN0aW9uYWxSb3RhdGlvbixudWxsIT1kKWlmKFwib2JqZWN0XCI9PXR5cGVvZiBkKWZvcihmIGluIGQpVFtmXT1kW2ZdO2Vsc2UgVC5yb3RhdGlvbj1kO2gucm90YXRpb249c2UoXCJyb3RhdGlvblwiaW4gVD9ULnJvdGF0aW9uOlwic2hvcnRSb3RhdGlvblwiaW4gVD9ULnNob3J0Um90YXRpb24rXCJfc2hvcnRcIjpcInJvdGF0aW9uWlwiaW4gVD9ULnJvdGF0aW9uWjptLnJvdGF0aW9uLG0ucm90YXRpb24sXCJyb3RhdGlvblwiLHcpLHhlJiYoaC5yb3RhdGlvblg9c2UoXCJyb3RhdGlvblhcImluIFQ/VC5yb3RhdGlvblg6XCJzaG9ydFJvdGF0aW9uWFwiaW4gVD9ULnNob3J0Um90YXRpb25YK1wiX3Nob3J0XCI6bS5yb3RhdGlvblh8fDAsbS5yb3RhdGlvblgsXCJyb3RhdGlvblhcIix3KSxoLnJvdGF0aW9uWT1zZShcInJvdGF0aW9uWVwiaW4gVD9ULnJvdGF0aW9uWTpcInNob3J0Um90YXRpb25ZXCJpbiBUP1Quc2hvcnRSb3RhdGlvblkrXCJfc2hvcnRcIjptLnJvdGF0aW9uWXx8MCxtLnJvdGF0aW9uWSxcInJvdGF0aW9uWVwiLHcpKSxoLnNrZXdYPW51bGw9PVQuc2tld1g/bS5za2V3WDpzZShULnNrZXdYLG0uc2tld1gpLGguc2tld1k9bnVsbD09VC5za2V3WT9tLnNrZXdZOnNlKFQuc2tld1ksbS5za2V3WSksKHU9aC5za2V3WS1tLnNrZXdZKSYmKGguc2tld1grPXUsaC5yb3RhdGlvbis9dSl9Zm9yKHhlJiZudWxsIT1ULmZvcmNlM0QmJihtLmZvcmNlM0Q9VC5mb3JjZTNELGM9ITApLG0uc2tld1R5cGU9VC5za2V3VHlwZXx8bS5za2V3VHlwZXx8YS5kZWZhdWx0U2tld1R5cGUscD1tLmZvcmNlM0R8fG0uenx8bS5yb3RhdGlvblh8fG0ucm90YXRpb25ZfHxoLnp8fGgucm90YXRpb25YfHxoLnJvdGF0aW9uWXx8aC5wZXJzcGVjdGl2ZSxwfHxudWxsPT1ULnNjYWxlfHwoaC5zY2FsZVo9MSk7LS15Pi0xOylpPXZlW3ldLF89aFtpXS1tW2ldLChfPnZ8fC12Pl98fG51bGwhPU5baV0pJiYoYz0hMCxuPW5ldyBfZShtLGksbVtpXSxfLG4pLGkgaW4gdyYmKG4uZT13W2ldKSxuLnhzMD0wLG4ucGx1Z2luPW8sci5fb3ZlcndyaXRlUHJvcHMucHVzaChuLm4pKTtyZXR1cm4gXz1ULnRyYW5zZm9ybU9yaWdpbiwoX3x8eGUmJnAmJm0uek9yaWdpbikmJih5ZT8oYz0hMCxpPXdlLF89KF98fHEodCxpLHMsITEsXCI1MCUgNTAlXCIpKStcIlwiLG49bmV3IF9lKGcsaSwwLDAsbiwtMSxcInRyYW5zZm9ybU9yaWdpblwiKSxuLmI9Z1tpXSxuLnBsdWdpbj1vLHhlPyhmPW0uek9yaWdpbixfPV8uc3BsaXQoXCIgXCIpLG0uek9yaWdpbj0oXy5sZW5ndGg+MiYmKDA9PT1mfHxcIjBweFwiIT09X1syXSk/cGFyc2VGbG9hdChfWzJdKTpmKXx8MCxuLnhzMD1uLmU9X1swXStcIiBcIisoX1sxXXx8XCI1MCVcIikrXCIgMHB4XCIsbj1uZXcgX2UobSxcInpPcmlnaW5cIiwwLDAsbiwtMSxuLm4pLG4uYj1mLG4ueHMwPW4uZT1tLnpPcmlnaW4pOm4ueHMwPW4uZT1fKTplZShfK1wiXCIsbSkpLGMmJihyLl90cmFuc2Zvcm1UeXBlPXB8fDM9PT10aGlzLl90cmFuc2Zvcm1UeXBlPzM6Miksbn0scHJlZml4OiEwfSksbWUoXCJib3hTaGFkb3dcIix7ZGVmYXVsdFZhbHVlOlwiMHB4IDBweCAwcHggMHB4ICM5OTlcIixwcmVmaXg6ITAsY29sb3I6ITAsbXVsdGk6ITAsa2V5d29yZDpcImluc2V0XCJ9KSxtZShcImJvcmRlclJhZGl1c1wiLHtkZWZhdWx0VmFsdWU6XCIwcHhcIixwYXJzZXI6ZnVuY3Rpb24odCxlLGksbixhKXtlPXRoaXMuZm9ybWF0KGUpO3ZhciBvLGwsaCx1LGYsXyxwLGMsZCxtLGcsdix5LFQsdyx4LGI9W1wiYm9yZGVyVG9wTGVmdFJhZGl1c1wiLFwiYm9yZGVyVG9wUmlnaHRSYWRpdXNcIixcImJvcmRlckJvdHRvbVJpZ2h0UmFkaXVzXCIsXCJib3JkZXJCb3R0b21MZWZ0UmFkaXVzXCJdLFA9dC5zdHlsZTtmb3IoZD1wYXJzZUZsb2F0KHQub2Zmc2V0V2lkdGgpLG09cGFyc2VGbG9hdCh0Lm9mZnNldEhlaWdodCksbz1lLnNwbGl0KFwiIFwiKSxsPTA7Yi5sZW5ndGg+bDtsKyspdGhpcy5wLmluZGV4T2YoXCJib3JkZXJcIikmJihiW2xdPVYoYltsXSkpLGY9dT1xKHQsYltsXSxzLCExLFwiMHB4XCIpLC0xIT09Zi5pbmRleE9mKFwiIFwiKSYmKHU9Zi5zcGxpdChcIiBcIiksZj11WzBdLHU9dVsxXSksXz1oPW9bbF0scD1wYXJzZUZsb2F0KGYpLHY9Zi5zdWJzdHIoKHArXCJcIikubGVuZ3RoKSx5PVwiPVwiPT09Xy5jaGFyQXQoMSkseT8oYz1wYXJzZUludChfLmNoYXJBdCgwKStcIjFcIiwxMCksXz1fLnN1YnN0cigyKSxjKj1wYXJzZUZsb2F0KF8pLGc9Xy5zdWJzdHIoKGMrXCJcIikubGVuZ3RoLSgwPmM/MTowKSl8fFwiXCIpOihjPXBhcnNlRmxvYXQoXyksZz1fLnN1YnN0cigoYytcIlwiKS5sZW5ndGgpKSxcIlwiPT09ZyYmKGc9cltpXXx8diksZyE9PXYmJihUPVEodCxcImJvcmRlckxlZnRcIixwLHYpLHc9USh0LFwiYm9yZGVyVG9wXCIscCx2KSxcIiVcIj09PWc/KGY9MTAwKihUL2QpK1wiJVwiLHU9MTAwKih3L20pK1wiJVwiKTpcImVtXCI9PT1nPyh4PVEodCxcImJvcmRlckxlZnRcIiwxLFwiZW1cIiksZj1UL3grXCJlbVwiLHU9dy94K1wiZW1cIik6KGY9VCtcInB4XCIsdT13K1wicHhcIikseSYmKF89cGFyc2VGbG9hdChmKStjK2csaD1wYXJzZUZsb2F0KHUpK2MrZykpLGE9cGUoUCxiW2xdLGYrXCIgXCIrdSxfK1wiIFwiK2gsITEsXCIwcHhcIixhKTtyZXR1cm4gYX0scHJlZml4OiEwLGZvcm1hdHRlcjpoZShcIjBweCAwcHggMHB4IDBweFwiLCExLCEwKX0pLG1lKFwiYmFja2dyb3VuZFBvc2l0aW9uXCIse2RlZmF1bHRWYWx1ZTpcIjAgMFwiLHBhcnNlcjpmdW5jdGlvbih0LGUsaSxyLG4sYSl7dmFyIG8sbCxoLHUsZixfLHA9XCJiYWNrZ3JvdW5kLXBvc2l0aW9uXCIsZD1zfHxIKHQsbnVsbCksbT10aGlzLmZvcm1hdCgoZD9jP2QuZ2V0UHJvcGVydHlWYWx1ZShwK1wiLXhcIikrXCIgXCIrZC5nZXRQcm9wZXJ0eVZhbHVlKHArXCIteVwiKTpkLmdldFByb3BlcnR5VmFsdWUocCk6dC5jdXJyZW50U3R5bGUuYmFja2dyb3VuZFBvc2l0aW9uWCtcIiBcIit0LmN1cnJlbnRTdHlsZS5iYWNrZ3JvdW5kUG9zaXRpb25ZKXx8XCIwIDBcIiksZz10aGlzLmZvcm1hdChlKTtpZigtMSE9PW0uaW5kZXhPZihcIiVcIikhPSgtMSE9PWcuaW5kZXhPZihcIiVcIikpJiYoXz1xKHQsXCJiYWNrZ3JvdW5kSW1hZ2VcIikucmVwbGFjZShDLFwiXCIpLF8mJlwibm9uZVwiIT09Xykpe2ZvcihvPW0uc3BsaXQoXCIgXCIpLGw9Zy5zcGxpdChcIiBcIiksSS5zZXRBdHRyaWJ1dGUoXCJzcmNcIixfKSxoPTI7LS1oPi0xOyltPW9baF0sdT0tMSE9PW0uaW5kZXhPZihcIiVcIiksdSE9PSgtMSE9PWxbaF0uaW5kZXhPZihcIiVcIikpJiYoZj0wPT09aD90Lm9mZnNldFdpZHRoLUkud2lkdGg6dC5vZmZzZXRIZWlnaHQtSS5oZWlnaHQsb1toXT11P3BhcnNlRmxvYXQobSkvMTAwKmYrXCJweFwiOjEwMCoocGFyc2VGbG9hdChtKS9mKStcIiVcIik7bT1vLmpvaW4oXCIgXCIpfXJldHVybiB0aGlzLnBhcnNlQ29tcGxleCh0LnN0eWxlLG0sZyxuLGEpfSxmb3JtYXR0ZXI6ZWV9KSxtZShcImJhY2tncm91bmRTaXplXCIse2RlZmF1bHRWYWx1ZTpcIjAgMFwiLGZvcm1hdHRlcjplZX0pLG1lKFwicGVyc3BlY3RpdmVcIix7ZGVmYXVsdFZhbHVlOlwiMHB4XCIscHJlZml4OiEwfSksbWUoXCJwZXJzcGVjdGl2ZU9yaWdpblwiLHtkZWZhdWx0VmFsdWU6XCI1MCUgNTAlXCIscHJlZml4OiEwfSksbWUoXCJ0cmFuc2Zvcm1TdHlsZVwiLHtwcmVmaXg6ITB9KSxtZShcImJhY2tmYWNlVmlzaWJpbGl0eVwiLHtwcmVmaXg6ITB9KSxtZShcInVzZXJTZWxlY3RcIix7cHJlZml4OiEwfSksbWUoXCJtYXJnaW5cIix7cGFyc2VyOnVlKFwibWFyZ2luVG9wLG1hcmdpblJpZ2h0LG1hcmdpbkJvdHRvbSxtYXJnaW5MZWZ0XCIpfSksbWUoXCJwYWRkaW5nXCIse3BhcnNlcjp1ZShcInBhZGRpbmdUb3AscGFkZGluZ1JpZ2h0LHBhZGRpbmdCb3R0b20scGFkZGluZ0xlZnRcIil9KSxtZShcImNsaXBcIix7ZGVmYXVsdFZhbHVlOlwicmVjdCgwcHgsMHB4LDBweCwwcHgpXCIscGFyc2VyOmZ1bmN0aW9uKHQsZSxpLHIsbixhKXt2YXIgbyxsLGg7cmV0dXJuIDk+Yz8obD10LmN1cnJlbnRTdHlsZSxoPTg+Yz9cIiBcIjpcIixcIixvPVwicmVjdChcIitsLmNsaXBUb3AraCtsLmNsaXBSaWdodCtoK2wuY2xpcEJvdHRvbStoK2wuY2xpcExlZnQrXCIpXCIsZT10aGlzLmZvcm1hdChlKS5zcGxpdChcIixcIikuam9pbihoKSk6KG89dGhpcy5mb3JtYXQocSh0LHRoaXMucCxzLCExLHRoaXMuZGZsdCkpLGU9dGhpcy5mb3JtYXQoZSkpLHRoaXMucGFyc2VDb21wbGV4KHQuc3R5bGUsbyxlLG4sYSl9fSksbWUoXCJ0ZXh0U2hhZG93XCIse2RlZmF1bHRWYWx1ZTpcIjBweCAwcHggMHB4ICM5OTlcIixjb2xvcjohMCxtdWx0aTohMH0pLG1lKFwiYXV0b1JvdW5kLHN0cmljdFVuaXRzXCIse3BhcnNlcjpmdW5jdGlvbih0LGUsaSxyLHMpe3JldHVybiBzfX0pLG1lKFwiYm9yZGVyXCIse2RlZmF1bHRWYWx1ZTpcIjBweCBzb2xpZCAjMDAwXCIscGFyc2VyOmZ1bmN0aW9uKHQsZSxpLHIsbixhKXtyZXR1cm4gdGhpcy5wYXJzZUNvbXBsZXgodC5zdHlsZSx0aGlzLmZvcm1hdChxKHQsXCJib3JkZXJUb3BXaWR0aFwiLHMsITEsXCIwcHhcIikrXCIgXCIrcSh0LFwiYm9yZGVyVG9wU3R5bGVcIixzLCExLFwic29saWRcIikrXCIgXCIrcSh0LFwiYm9yZGVyVG9wQ29sb3JcIixzLCExLFwiIzAwMFwiKSksdGhpcy5mb3JtYXQoZSksbixhKX0sY29sb3I6ITAsZm9ybWF0dGVyOmZ1bmN0aW9uKHQpe3ZhciBlPXQuc3BsaXQoXCIgXCIpO3JldHVybiBlWzBdK1wiIFwiKyhlWzFdfHxcInNvbGlkXCIpK1wiIFwiKyh0Lm1hdGNoKGxlKXx8W1wiIzAwMFwiXSlbMF19fSksbWUoXCJib3JkZXJXaWR0aFwiLHtwYXJzZXI6dWUoXCJib3JkZXJUb3BXaWR0aCxib3JkZXJSaWdodFdpZHRoLGJvcmRlckJvdHRvbVdpZHRoLGJvcmRlckxlZnRXaWR0aFwiKX0pLG1lKFwiZmxvYXQsY3NzRmxvYXQsc3R5bGVGbG9hdFwiLHtwYXJzZXI6ZnVuY3Rpb24odCxlLGkscixzKXt2YXIgbj10LnN0eWxlLGE9XCJjc3NGbG9hdFwiaW4gbj9cImNzc0Zsb2F0XCI6XCJzdHlsZUZsb2F0XCI7cmV0dXJuIG5ldyBfZShuLGEsMCwwLHMsLTEsaSwhMSwwLG5bYV0sZSl9fSk7dmFyIGtlPWZ1bmN0aW9uKHQpe3ZhciBlLGk9dGhpcy50LHI9aS5maWx0ZXJ8fHEodGhpcy5kYXRhLFwiZmlsdGVyXCIpLHM9MHx0aGlzLnMrdGhpcy5jKnQ7MTAwPT09cyYmKC0xPT09ci5pbmRleE9mKFwiYXRyaXgoXCIpJiYtMT09PXIuaW5kZXhPZihcInJhZGllbnQoXCIpJiYtMT09PXIuaW5kZXhPZihcIm9hZGVyKFwiKT8oaS5yZW1vdmVBdHRyaWJ1dGUoXCJmaWx0ZXJcIiksZT0hcSh0aGlzLmRhdGEsXCJmaWx0ZXJcIikpOihpLmZpbHRlcj1yLnJlcGxhY2UoeCxcIlwiKSxlPSEwKSksZXx8KHRoaXMueG4xJiYoaS5maWx0ZXI9cj1yfHxcImFscGhhKG9wYWNpdHk9XCIrcytcIilcIiksLTE9PT1yLmluZGV4T2YoXCJwYWNpdHlcIik/MD09PXMmJnRoaXMueG4xfHwoaS5maWx0ZXI9citcIiBhbHBoYShvcGFjaXR5PVwiK3MrXCIpXCIpOmkuZmlsdGVyPXIucmVwbGFjZShULFwib3BhY2l0eT1cIitzKSl9O21lKFwib3BhY2l0eSxhbHBoYSxhdXRvQWxwaGFcIix7ZGVmYXVsdFZhbHVlOlwiMVwiLHBhcnNlcjpmdW5jdGlvbih0LGUsaSxyLG4sYSl7dmFyIG89cGFyc2VGbG9hdChxKHQsXCJvcGFjaXR5XCIscywhMSxcIjFcIikpLGw9dC5zdHlsZSxoPVwiYXV0b0FscGhhXCI9PT1pO3JldHVyblwic3RyaW5nXCI9PXR5cGVvZiBlJiZcIj1cIj09PWUuY2hhckF0KDEpJiYoZT0oXCItXCI9PT1lLmNoYXJBdCgwKT8tMToxKSpwYXJzZUZsb2F0KGUuc3Vic3RyKDIpKStvKSxoJiYxPT09byYmXCJoaWRkZW5cIj09PXEodCxcInZpc2liaWxpdHlcIixzKSYmMCE9PWUmJihvPTApLFk/bj1uZXcgX2UobCxcIm9wYWNpdHlcIixvLGUtbyxuKToobj1uZXcgX2UobCxcIm9wYWNpdHlcIiwxMDAqbywxMDAqKGUtbyksbiksbi54bjE9aD8xOjAsbC56b29tPTEsbi50eXBlPTIsbi5iPVwiYWxwaGEob3BhY2l0eT1cIituLnMrXCIpXCIsbi5lPVwiYWxwaGEob3BhY2l0eT1cIisobi5zK24uYykrXCIpXCIsbi5kYXRhPXQsbi5wbHVnaW49YSxuLnNldFJhdGlvPWtlKSxoJiYobj1uZXcgX2UobCxcInZpc2liaWxpdHlcIiwwLDAsbiwtMSxudWxsLCExLDAsMCE9PW8/XCJpbmhlcml0XCI6XCJoaWRkZW5cIiwwPT09ZT9cImhpZGRlblwiOlwiaW5oZXJpdFwiKSxuLnhzMD1cImluaGVyaXRcIixyLl9vdmVyd3JpdGVQcm9wcy5wdXNoKG4ubiksci5fb3ZlcndyaXRlUHJvcHMucHVzaChpKSksbn19KTt2YXIgQWU9ZnVuY3Rpb24odCxlKXtlJiYodC5yZW1vdmVQcm9wZXJ0eT8oXCJtc1wiPT09ZS5zdWJzdHIoMCwyKSYmKGU9XCJNXCIrZS5zdWJzdHIoMSkpLHQucmVtb3ZlUHJvcGVydHkoZS5yZXBsYWNlKFAsXCItJDFcIikudG9Mb3dlckNhc2UoKSkpOnQucmVtb3ZlQXR0cmlidXRlKGUpKX0sT2U9ZnVuY3Rpb24odCl7aWYodGhpcy50Ll9nc0NsYXNzUFQ9dGhpcywxPT09dHx8MD09PXQpe3RoaXMudC5zZXRBdHRyaWJ1dGUoXCJjbGFzc1wiLDA9PT10P3RoaXMuYjp0aGlzLmUpO2Zvcih2YXIgZT10aGlzLmRhdGEsaT10aGlzLnQuc3R5bGU7ZTspZS52P2lbZS5wXT1lLnY6QWUoaSxlLnApLGU9ZS5fbmV4dDsxPT09dCYmdGhpcy50Ll9nc0NsYXNzUFQ9PT10aGlzJiYodGhpcy50Ll9nc0NsYXNzUFQ9bnVsbCl9ZWxzZSB0aGlzLnQuZ2V0QXR0cmlidXRlKFwiY2xhc3NcIikhPT10aGlzLmUmJnRoaXMudC5zZXRBdHRyaWJ1dGUoXCJjbGFzc1wiLHRoaXMuZSl9O21lKFwiY2xhc3NOYW1lXCIse3BhcnNlcjpmdW5jdGlvbih0LGUscixuLGEsbyxsKXt2YXIgaCx1LGYsXyxwLGM9dC5nZXRBdHRyaWJ1dGUoXCJjbGFzc1wiKXx8XCJcIixkPXQuc3R5bGUuY3NzVGV4dDtpZihhPW4uX2NsYXNzTmFtZVBUPW5ldyBfZSh0LHIsMCwwLGEsMiksYS5zZXRSYXRpbz1PZSxhLnByPS0xMSxpPSEwLGEuYj1jLHU9JCh0LHMpLGY9dC5fZ3NDbGFzc1BUKXtmb3IoXz17fSxwPWYuZGF0YTtwOylfW3AucF09MSxwPXAuX25leHQ7Zi5zZXRSYXRpbygxKX1yZXR1cm4gdC5fZ3NDbGFzc1BUPWEsYS5lPVwiPVwiIT09ZS5jaGFyQXQoMSk/ZTpjLnJlcGxhY2UoUmVnRXhwKFwiXFxcXHMqXFxcXGJcIitlLnN1YnN0cigyKStcIlxcXFxiXCIpLFwiXCIpKyhcIitcIj09PWUuY2hhckF0KDApP1wiIFwiK2Uuc3Vic3RyKDIpOlwiXCIpLG4uX3R3ZWVuLl9kdXJhdGlvbiYmKHQuc2V0QXR0cmlidXRlKFwiY2xhc3NcIixhLmUpLGg9Ryh0LHUsJCh0KSxsLF8pLHQuc2V0QXR0cmlidXRlKFwiY2xhc3NcIixjKSxhLmRhdGE9aC5maXJzdE1QVCx0LnN0eWxlLmNzc1RleHQ9ZCxhPWEueGZpcnN0PW4ucGFyc2UodCxoLmRpZnMsYSxvKSksYX19KTt2YXIgRGU9ZnVuY3Rpb24odCl7aWYoKDE9PT10fHwwPT09dCkmJnRoaXMuZGF0YS5fdG90YWxUaW1lPT09dGhpcy5kYXRhLl90b3RhbER1cmF0aW9uJiZcImlzRnJvbVN0YXJ0XCIhPT10aGlzLmRhdGEuZGF0YSl7dmFyIGUsaSxyLHMsbj10aGlzLnQuc3R5bGUsYT1vLnRyYW5zZm9ybS5wYXJzZTtpZihcImFsbFwiPT09dGhpcy5lKW4uY3NzVGV4dD1cIlwiLHM9ITA7ZWxzZSBmb3IoZT10aGlzLmUuc3BsaXQoXCIsXCIpLHI9ZS5sZW5ndGg7LS1yPi0xOylpPWVbcl0sb1tpXSYmKG9baV0ucGFyc2U9PT1hP3M9ITA6aT1cInRyYW5zZm9ybU9yaWdpblwiPT09aT93ZTpvW2ldLnApLEFlKG4saSk7cyYmKEFlKG4seWUpLHRoaXMudC5fZ3NUcmFuc2Zvcm0mJmRlbGV0ZSB0aGlzLnQuX2dzVHJhbnNmb3JtKX19O2ZvcihtZShcImNsZWFyUHJvcHNcIix7cGFyc2VyOmZ1bmN0aW9uKHQsZSxyLHMsbil7cmV0dXJuIG49bmV3IF9lKHQsciwwLDAsbiwyKSxuLnNldFJhdGlvPURlLG4uZT1lLG4ucHI9LTEwLG4uZGF0YT1zLl90d2VlbixpPSEwLG59fSksbD1cImJlemllcix0aHJvd1Byb3BzLHBoeXNpY3NQcm9wcyxwaHlzaWNzMkRcIi5zcGxpdChcIixcIiksY2U9bC5sZW5ndGg7Y2UtLTspZ2UobFtjZV0pO2w9YS5wcm90b3R5cGUsbC5fZmlyc3RQVD1udWxsLGwuX29uSW5pdFR3ZWVuPWZ1bmN0aW9uKHQsZSxvKXtpZighdC5ub2RlVHlwZSlyZXR1cm4hMTt0aGlzLl90YXJnZXQ9dCx0aGlzLl90d2Vlbj1vLHRoaXMuX3ZhcnM9ZSxoPWUuYXV0b1JvdW5kLGk9ITEscj1lLnN1ZmZpeE1hcHx8YS5zdWZmaXhNYXAscz1IKHQsXCJcIiksbj10aGlzLl9vdmVyd3JpdGVQcm9wczt2YXIgbCxfLGMsZCxtLGcsdix5LFQseD10LnN0eWxlO2lmKHUmJlwiXCI9PT14LnpJbmRleCYmKGw9cSh0LFwiekluZGV4XCIscyksKFwiYXV0b1wiPT09bHx8XCJcIj09PWwpJiZ0aGlzLl9hZGRMYXp5U2V0KHgsXCJ6SW5kZXhcIiwwKSksXCJzdHJpbmdcIj09dHlwZW9mIGUmJihkPXguY3NzVGV4dCxsPSQodCxzKSx4LmNzc1RleHQ9ZCtcIjtcIitlLGw9Ryh0LGwsJCh0KSkuZGlmcywhWSYmdy50ZXN0KGUpJiYobC5vcGFjaXR5PXBhcnNlRmxvYXQoUmVnRXhwLiQxKSksZT1sLHguY3NzVGV4dD1kKSx0aGlzLl9maXJzdFBUPV89dGhpcy5wYXJzZSh0LGUsbnVsbCksdGhpcy5fdHJhbnNmb3JtVHlwZSl7Zm9yKFQ9Mz09PXRoaXMuX3RyYW5zZm9ybVR5cGUseWU/ZiYmKHU9ITAsXCJcIj09PXguekluZGV4JiYodj1xKHQsXCJ6SW5kZXhcIixzKSwoXCJhdXRvXCI9PT12fHxcIlwiPT09dikmJnRoaXMuX2FkZExhenlTZXQoeCxcInpJbmRleFwiLDApKSxwJiZ0aGlzLl9hZGRMYXp5U2V0KHgsXCJXZWJraXRCYWNrZmFjZVZpc2liaWxpdHlcIix0aGlzLl92YXJzLldlYmtpdEJhY2tmYWNlVmlzaWJpbGl0eXx8KFQ/XCJ2aXNpYmxlXCI6XCJoaWRkZW5cIikpKTp4Lnpvb209MSxjPV87YyYmYy5fbmV4dDspYz1jLl9uZXh0O3k9bmV3IF9lKHQsXCJ0cmFuc2Zvcm1cIiwwLDAsbnVsbCwyKSx0aGlzLl9saW5rQ1NTUCh5LG51bGwsYykseS5zZXRSYXRpbz1UJiZ4ZT9DZTp5ZT9SZTpTZSx5LmRhdGE9dGhpcy5fdHJhbnNmb3JtfHxQZSh0LHMsITApLG4ucG9wKCl9aWYoaSl7Zm9yKDtfOyl7Zm9yKGc9Xy5fbmV4dCxjPWQ7YyYmYy5wcj5fLnByOyljPWMuX25leHQ7KF8uX3ByZXY9Yz9jLl9wcmV2Om0pP18uX3ByZXYuX25leHQ9XzpkPV8sKF8uX25leHQ9Yyk/Yy5fcHJldj1fOm09XyxfPWd9dGhpcy5fZmlyc3RQVD1kfXJldHVybiEwfSxsLnBhcnNlPWZ1bmN0aW9uKHQsZSxpLG4pe3ZhciBhLGwsdSxmLF8scCxjLGQsbSxnLHY9dC5zdHlsZTtmb3IoYSBpbiBlKXA9ZVthXSxsPW9bYV0sbD9pPWwucGFyc2UodCxwLGEsdGhpcyxpLG4sZSk6KF89cSh0LGEscykrXCJcIixtPVwic3RyaW5nXCI9PXR5cGVvZiBwLFwiY29sb3JcIj09PWF8fFwiZmlsbFwiPT09YXx8XCJzdHJva2VcIj09PWF8fC0xIT09YS5pbmRleE9mKFwiQ29sb3JcIil8fG0mJmIudGVzdChwKT8obXx8KHA9b2UocCkscD0ocC5sZW5ndGg+Mz9cInJnYmEoXCI6XCJyZ2IoXCIpK3Auam9pbihcIixcIikrXCIpXCIpLGk9cGUodixhLF8scCwhMCxcInRyYW5zcGFyZW50XCIsaSwwLG4pKTohbXx8LTE9PT1wLmluZGV4T2YoXCIgXCIpJiYtMT09PXAuaW5kZXhPZihcIixcIik/KHU9cGFyc2VGbG9hdChfKSxjPXV8fDA9PT11P18uc3Vic3RyKCh1K1wiXCIpLmxlbmd0aCk6XCJcIiwoXCJcIj09PV98fFwiYXV0b1wiPT09XykmJihcIndpZHRoXCI9PT1hfHxcImhlaWdodFwiPT09YT8odT10ZSh0LGEscyksYz1cInB4XCIpOlwibGVmdFwiPT09YXx8XCJ0b3BcIj09PWE/KHU9Wih0LGEscyksYz1cInB4XCIpOih1PVwib3BhY2l0eVwiIT09YT8wOjEsYz1cIlwiKSksZz1tJiZcIj1cIj09PXAuY2hhckF0KDEpLGc/KGY9cGFyc2VJbnQocC5jaGFyQXQoMCkrXCIxXCIsMTApLHA9cC5zdWJzdHIoMiksZio9cGFyc2VGbG9hdChwKSxkPXAucmVwbGFjZSh5LFwiXCIpKTooZj1wYXJzZUZsb2F0KHApLGQ9bT9wLnN1YnN0cigoZitcIlwiKS5sZW5ndGgpfHxcIlwiOlwiXCIpLFwiXCI9PT1kJiYoZD1hIGluIHI/clthXTpjKSxwPWZ8fDA9PT1mPyhnP2YrdTpmKStkOmVbYV0sYyE9PWQmJlwiXCIhPT1kJiYoZnx8MD09PWYpJiZ1JiYodT1RKHQsYSx1LGMpLFwiJVwiPT09ZD8odS89USh0LGEsMTAwLFwiJVwiKS8xMDAsZS5zdHJpY3RVbml0cyE9PSEwJiYoXz11K1wiJVwiKSk6XCJlbVwiPT09ZD91Lz1RKHQsYSwxLFwiZW1cIik6XCJweFwiIT09ZCYmKGY9USh0LGEsZixkKSxkPVwicHhcIiksZyYmKGZ8fDA9PT1mKSYmKHA9Zit1K2QpKSxnJiYoZis9dSksIXUmJjAhPT11fHwhZiYmMCE9PWY/dm9pZCAwIT09dlthXSYmKHB8fFwiTmFOXCIhPXArXCJcIiYmbnVsbCE9cCk/KGk9bmV3IF9lKHYsYSxmfHx1fHwwLDAsaSwtMSxhLCExLDAsXyxwKSxpLnhzMD1cIm5vbmVcIiE9PXB8fFwiZGlzcGxheVwiIT09YSYmLTE9PT1hLmluZGV4T2YoXCJTdHlsZVwiKT9wOl8pOlUoXCJpbnZhbGlkIFwiK2ErXCIgdHdlZW4gdmFsdWU6IFwiK2VbYV0pOihpPW5ldyBfZSh2LGEsdSxmLXUsaSwwLGEsaCE9PSExJiYoXCJweFwiPT09ZHx8XCJ6SW5kZXhcIj09PWEpLDAsXyxwKSxpLnhzMD1kKSk6aT1wZSh2LGEsXyxwLCEwLG51bGwsaSwwLG4pKSxuJiZpJiYhaS5wbHVnaW4mJihpLnBsdWdpbj1uKTtyZXR1cm4gaX0sbC5zZXRSYXRpbz1mdW5jdGlvbih0KXt2YXIgZSxpLHIscz10aGlzLl9maXJzdFBULG49MWUtNjtpZigxIT09dHx8dGhpcy5fdHdlZW4uX3RpbWUhPT10aGlzLl90d2Vlbi5fZHVyYXRpb24mJjAhPT10aGlzLl90d2Vlbi5fdGltZSlpZih0fHx0aGlzLl90d2Vlbi5fdGltZSE9PXRoaXMuX3R3ZWVuLl9kdXJhdGlvbiYmMCE9PXRoaXMuX3R3ZWVuLl90aW1lfHx0aGlzLl90d2Vlbi5fcmF3UHJldlRpbWU9PT0tMWUtNilmb3IoO3M7KXtpZihlPXMuYyp0K3MucyxzLnI/ZT1NYXRoLnJvdW5kKGUpOm4+ZSYmZT4tbiYmKGU9MCkscy50eXBlKWlmKDE9PT1zLnR5cGUpaWYocj1zLmwsMj09PXIpcy50W3MucF09cy54czArZStzLnhzMStzLnhuMStzLnhzMjtlbHNlIGlmKDM9PT1yKXMudFtzLnBdPXMueHMwK2Urcy54czErcy54bjErcy54czIrcy54bjIrcy54czM7ZWxzZSBpZig0PT09cilzLnRbcy5wXT1zLnhzMCtlK3MueHMxK3MueG4xK3MueHMyK3MueG4yK3MueHMzK3MueG4zK3MueHM0O2Vsc2UgaWYoNT09PXIpcy50W3MucF09cy54czArZStzLnhzMStzLnhuMStzLnhzMitzLnhuMitzLnhzMytzLnhuMytzLnhzNCtzLnhuNCtzLnhzNTtlbHNle2ZvcihpPXMueHMwK2Urcy54czEscj0xO3MubD5yO3IrKylpKz1zW1wieG5cIityXStzW1wieHNcIisocisxKV07cy50W3MucF09aX1lbHNlLTE9PT1zLnR5cGU/cy50W3MucF09cy54czA6cy5zZXRSYXRpbyYmcy5zZXRSYXRpbyh0KTtlbHNlIHMudFtzLnBdPWUrcy54czA7cz1zLl9uZXh0fWVsc2UgZm9yKDtzOykyIT09cy50eXBlP3MudFtzLnBdPXMuYjpzLnNldFJhdGlvKHQpLHM9cy5fbmV4dDtlbHNlIGZvcig7czspMiE9PXMudHlwZT9zLnRbcy5wXT1zLmU6cy5zZXRSYXRpbyh0KSxzPXMuX25leHR9LGwuX2VuYWJsZVRyYW5zZm9ybXM9ZnVuY3Rpb24odCl7dGhpcy5fdHJhbnNmb3JtVHlwZT10fHwzPT09dGhpcy5fdHJhbnNmb3JtVHlwZT8zOjIsdGhpcy5fdHJhbnNmb3JtPXRoaXMuX3RyYW5zZm9ybXx8UGUodGhpcy5fdGFyZ2V0LHMsITApfTt2YXIgTWU9ZnVuY3Rpb24oKXt0aGlzLnRbdGhpcy5wXT10aGlzLmUsdGhpcy5kYXRhLl9saW5rQ1NTUCh0aGlzLHRoaXMuX25leHQsbnVsbCwhMCl9O2wuX2FkZExhenlTZXQ9ZnVuY3Rpb24odCxlLGkpe3ZhciByPXRoaXMuX2ZpcnN0UFQ9bmV3IF9lKHQsZSwwLDAsdGhpcy5fZmlyc3RQVCwyKTtyLmU9aSxyLnNldFJhdGlvPU1lLHIuZGF0YT10aGlzfSxsLl9saW5rQ1NTUD1mdW5jdGlvbih0LGUsaSxyKXtyZXR1cm4gdCYmKGUmJihlLl9wcmV2PXQpLHQuX25leHQmJih0Ll9uZXh0Ll9wcmV2PXQuX3ByZXYpLHQuX3ByZXY/dC5fcHJldi5fbmV4dD10Ll9uZXh0OnRoaXMuX2ZpcnN0UFQ9PT10JiYodGhpcy5fZmlyc3RQVD10Ll9uZXh0LHI9ITApLGk/aS5fbmV4dD10OnJ8fG51bGwhPT10aGlzLl9maXJzdFBUfHwodGhpcy5fZmlyc3RQVD10KSx0Ll9uZXh0PWUsdC5fcHJldj1pKSx0fSxsLl9raWxsPWZ1bmN0aW9uKGUpe3ZhciBpLHIscyxuPWU7aWYoZS5hdXRvQWxwaGF8fGUuYWxwaGEpe249e307Zm9yKHIgaW4gZSluW3JdPWVbcl07bi5vcGFjaXR5PTEsbi5hdXRvQWxwaGEmJihuLnZpc2liaWxpdHk9MSl9cmV0dXJuIGUuY2xhc3NOYW1lJiYoaT10aGlzLl9jbGFzc05hbWVQVCkmJihzPWkueGZpcnN0LHMmJnMuX3ByZXY/dGhpcy5fbGlua0NTU1Aocy5fcHJldixpLl9uZXh0LHMuX3ByZXYuX3ByZXYpOnM9PT10aGlzLl9maXJzdFBUJiYodGhpcy5fZmlyc3RQVD1pLl9uZXh0KSxpLl9uZXh0JiZ0aGlzLl9saW5rQ1NTUChpLl9uZXh0LGkuX25leHQuX25leHQscy5fcHJldiksdGhpcy5fY2xhc3NOYW1lUFQ9bnVsbCksdC5wcm90b3R5cGUuX2tpbGwuY2FsbCh0aGlzLG4pfTt2YXIgTGU9ZnVuY3Rpb24odCxlLGkpe3ZhciByLHMsbixhO2lmKHQuc2xpY2UpZm9yKHM9dC5sZW5ndGg7LS1zPi0xOylMZSh0W3NdLGUsaSk7ZWxzZSBmb3Iocj10LmNoaWxkTm9kZXMscz1yLmxlbmd0aDstLXM+LTE7KW49cltzXSxhPW4udHlwZSxuLnN0eWxlJiYoZS5wdXNoKCQobikpLGkmJmkucHVzaChuKSksMSE9PWEmJjkhPT1hJiYxMSE9PWF8fCFuLmNoaWxkTm9kZXMubGVuZ3RofHxMZShuLGUsaSl9O3JldHVybiBhLmNhc2NhZGVUbz1mdW5jdGlvbih0LGkscil7dmFyIHMsbixhLG89ZS50byh0LGksciksbD1bb10saD1bXSx1PVtdLGY9W10sXz1lLl9pbnRlcm5hbHMucmVzZXJ2ZWRQcm9wcztmb3IodD1vLl90YXJnZXRzfHxvLnRhcmdldCxMZSh0LGgsZiksby5yZW5kZXIoaSwhMCksTGUodCx1KSxvLnJlbmRlcigwLCEwKSxvLl9lbmFibGVkKCEwKSxzPWYubGVuZ3RoOy0tcz4tMTspaWYobj1HKGZbc10saFtzXSx1W3NdKSxuLmZpcnN0TVBUKXtuPW4uZGlmcztcclxuZm9yKGEgaW4gcilfW2FdJiYoblthXT1yW2FdKTtsLnB1c2goZS50byhmW3NdLGksbikpfXJldHVybiBsfSx0LmFjdGl2YXRlKFthXSksYX0sITApfSksd2luZG93Ll9nc0RlZmluZSYmd2luZG93Ll9nc1F1ZXVlLnBvcCgpKCk7IiwiLyohXHJcbiAqIFZFUlNJT046IDEuNy4zXHJcbiAqIERBVEU6IDIwMTQtMDEtMTRcclxuICogVVBEQVRFUyBBTkQgRE9DUyBBVDogaHR0cDovL3d3dy5ncmVlbnNvY2suY29tXHJcbiAqXHJcbiAqIEBsaWNlbnNlIENvcHlyaWdodCAoYykgMjAwOC0yMDE0LCBHcmVlblNvY2suIEFsbCByaWdodHMgcmVzZXJ2ZWQuXHJcbiAqIFRoaXMgd29yayBpcyBzdWJqZWN0IHRvIHRoZSB0ZXJtcyBhdCBodHRwOi8vd3d3LmdyZWVuc29jay5jb20vdGVybXNfb2ZfdXNlLmh0bWwgb3IgZm9yXHJcbiAqIENsdWIgR3JlZW5Tb2NrIG1lbWJlcnMsIHRoZSBzb2Z0d2FyZSBhZ3JlZW1lbnQgdGhhdCB3YXMgaXNzdWVkIHdpdGggeW91ciBtZW1iZXJzaGlwLlxyXG4gKiBcclxuICogQGF1dGhvcjogSmFjayBEb3lsZSwgamFja0BncmVlbnNvY2suY29tXHJcbiAqKi9cclxuKHdpbmRvdy5fZ3NRdWV1ZXx8KHdpbmRvdy5fZ3NRdWV1ZT1bXSkpLnB1c2goZnVuY3Rpb24oKXtcInVzZSBzdHJpY3RcIjt2YXIgdD1kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQsZT13aW5kb3csaT1mdW5jdGlvbihpLHMpe3ZhciByPVwieFwiPT09cz9cIldpZHRoXCI6XCJIZWlnaHRcIixuPVwic2Nyb2xsXCIrcixhPVwiY2xpZW50XCIrcixvPWRvY3VtZW50LmJvZHk7cmV0dXJuIGk9PT1lfHxpPT09dHx8aT09PW8/TWF0aC5tYXgodFtuXSxvW25dKS0oZVtcImlubmVyXCIrcl18fE1hdGgubWF4KHRbYV0sb1thXSkpOmlbbl0taVtcIm9mZnNldFwiK3JdfSxzPXdpbmRvdy5fZ3NEZWZpbmUucGx1Z2luKHtwcm9wTmFtZTpcInNjcm9sbFRvXCIsQVBJOjIsdmVyc2lvbjpcIjEuNy4zXCIsaW5pdDpmdW5jdGlvbih0LHMscil7cmV0dXJuIHRoaXMuX3dkdz10PT09ZSx0aGlzLl90YXJnZXQ9dCx0aGlzLl90d2Vlbj1yLFwib2JqZWN0XCIhPXR5cGVvZiBzJiYocz17eTpzfSksdGhpcy5fYXV0b0tpbGw9cy5hdXRvS2lsbCE9PSExLHRoaXMueD10aGlzLnhQcmV2PXRoaXMuZ2V0WCgpLHRoaXMueT10aGlzLnlQcmV2PXRoaXMuZ2V0WSgpLG51bGwhPXMueD8odGhpcy5fYWRkVHdlZW4odGhpcyxcInhcIix0aGlzLngsXCJtYXhcIj09PXMueD9pKHQsXCJ4XCIpOnMueCxcInNjcm9sbFRvX3hcIiwhMCksdGhpcy5fb3ZlcndyaXRlUHJvcHMucHVzaChcInNjcm9sbFRvX3hcIikpOnRoaXMuc2tpcFg9ITAsbnVsbCE9cy55Pyh0aGlzLl9hZGRUd2Vlbih0aGlzLFwieVwiLHRoaXMueSxcIm1heFwiPT09cy55P2kodCxcInlcIik6cy55LFwic2Nyb2xsVG9feVwiLCEwKSx0aGlzLl9vdmVyd3JpdGVQcm9wcy5wdXNoKFwic2Nyb2xsVG9feVwiKSk6dGhpcy5za2lwWT0hMCwhMH0sc2V0OmZ1bmN0aW9uKHQpe3RoaXMuX3N1cGVyLnNldFJhdGlvLmNhbGwodGhpcyx0KTt2YXIgcz10aGlzLl93ZHd8fCF0aGlzLnNraXBYP3RoaXMuZ2V0WCgpOnRoaXMueFByZXYscj10aGlzLl93ZHd8fCF0aGlzLnNraXBZP3RoaXMuZ2V0WSgpOnRoaXMueVByZXYsbj1yLXRoaXMueVByZXYsYT1zLXRoaXMueFByZXY7dGhpcy5fYXV0b0tpbGwmJighdGhpcy5za2lwWCYmKGE+N3x8LTc+YSkmJmkodGhpcy5fdGFyZ2V0LFwieFwiKT5zJiYodGhpcy5za2lwWD0hMCksIXRoaXMuc2tpcFkmJihuPjd8fC03Pm4pJiZpKHRoaXMuX3RhcmdldCxcInlcIik+ciYmKHRoaXMuc2tpcFk9ITApLHRoaXMuc2tpcFgmJnRoaXMuc2tpcFkmJnRoaXMuX3R3ZWVuLmtpbGwoKSksdGhpcy5fd2R3P2Uuc2Nyb2xsVG8odGhpcy5za2lwWD9zOnRoaXMueCx0aGlzLnNraXBZP3I6dGhpcy55KToodGhpcy5za2lwWXx8KHRoaXMuX3RhcmdldC5zY3JvbGxUb3A9dGhpcy55KSx0aGlzLnNraXBYfHwodGhpcy5fdGFyZ2V0LnNjcm9sbExlZnQ9dGhpcy54KSksdGhpcy54UHJldj10aGlzLngsdGhpcy55UHJldj10aGlzLnl9fSkscj1zLnByb3RvdHlwZTtzLm1heD1pLHIuZ2V0WD1mdW5jdGlvbigpe3JldHVybiB0aGlzLl93ZHc/bnVsbCE9ZS5wYWdlWE9mZnNldD9lLnBhZ2VYT2Zmc2V0Om51bGwhPXQuc2Nyb2xsTGVmdD90LnNjcm9sbExlZnQ6ZG9jdW1lbnQuYm9keS5zY3JvbGxMZWZ0OnRoaXMuX3RhcmdldC5zY3JvbGxMZWZ0fSxyLmdldFk9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5fd2R3P251bGwhPWUucGFnZVlPZmZzZXQ/ZS5wYWdlWU9mZnNldDpudWxsIT10LnNjcm9sbFRvcD90LnNjcm9sbFRvcDpkb2N1bWVudC5ib2R5LnNjcm9sbFRvcDp0aGlzLl90YXJnZXQuc2Nyb2xsVG9wfSxyLl9raWxsPWZ1bmN0aW9uKHQpe3JldHVybiB0LnNjcm9sbFRvX3gmJih0aGlzLnNraXBYPSEwKSx0LnNjcm9sbFRvX3kmJih0aGlzLnNraXBZPSEwKSx0aGlzLl9zdXBlci5fa2lsbC5jYWxsKHRoaXMsdCl9fSksd2luZG93Ll9nc0RlZmluZSYmd2luZG93Ll9nc1F1ZXVlLnBvcCgpKCk7Il19\n"],"file":"wpr-admin.js"} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js.min.map b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js.min.map new file mode 100644 index 000000000..03f37d96f --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.js.min.map @@ -0,0 +1 @@ +{"version":3,"names":[],"mappings":"","sources":["wpr-admin.js"],"sourcesContent":["!function s(n,r,a){function o(e,t){if(!r[e]){if(!n[e]){var i=\"function\"==typeof require&&require;if(!t&&i)return i(e,!0);if(l)return l(e,!0);throw(i=new Error(\"Cannot find module '\"+e+\"'\")).code=\"MODULE_NOT_FOUND\",i}i=r[e]={exports:{}},n[e][0].call(i.exports,function(t){return o(n[e][1][t]||t)},i,i.exports,s,n,r,a)}return r[e].exports}for(var l=\"function\"==typeof require&&require,t=0;t{i.append(\"\"+t+\": \"),i.append(e[t].message),i.append(\"
\")}):i.append('
'+e.message+\"
\")}})}),r(\"#wpr_enable_mobile_cache\").on(\"click\",function(t){t.preventDefault(),r(\"#wpr_enable_mobile_cache\").addClass(\"wpr-isLoading\"),r.post(ajaxurl,{action:\"rocket_enable_mobile_cache\",_ajax_nonce:rocket_ajax_data.nonce},function(t){t.success&&(r(\"#wpr_enable_mobile_cache\").hide(),r(\"#wpr_mobile_cache_default\").hide(),r(\"#wpr_mobile_cache_response\").show(),r(\"#wpr_enable_mobile_cache\").removeClass(\"wpr-isLoading\"),r(\"#cache_mobile\").val(1),r(\"#do_caching_mobile_files\").val(1))})})})},{}],2:[function(t,e,i){\"use strict\";t(\"../lib/greensock/TweenLite.min.js\"),t(\"../lib/greensock/TimelineLite.min.js\"),t(\"../lib/greensock/easing/EasePack.min.js\"),t(\"../lib/greensock/plugins/CSSPlugin.min.js\"),t(\"../lib/greensock/plugins/ScrollToPlugin.min.js\"),t(\"../global/pageManager.js\"),t(\"../global/main.js\"),t(\"../global/fields.js\"),t(\"../global/beacon.js\"),t(\"../global/ajax.js\"),t(\"../global/rocketcdn.js\"),t(\"../global/countdown.js\")},{\"../global/ajax.js\":1,\"../global/beacon.js\":3,\"../global/countdown.js\":4,\"../global/fields.js\":5,\"../global/main.js\":6,\"../global/pageManager.js\":7,\"../global/rocketcdn.js\":8,\"../lib/greensock/TimelineLite.min.js\":9,\"../lib/greensock/TweenLite.min.js\":10,\"../lib/greensock/easing/EasePack.min.js\":11,\"../lib/greensock/plugins/CSSPlugin.min.js\":12,\"../lib/greensock/plugins/ScrollToPlugin.min.js\":13}],3:[function(t,e,i){\"use strict\";var s=jQuery;s(document).ready(function(){\"Beacon\"in window&&s(\".wpr-infoAction--help\").on(\"click\",function(t){var e=s(this).data(\"beacon-id\");return 0!==(e=(e=e).split(\",\")).length&&(1{o(t).attr(\"checked\",i?null:\"checked\")});else{const r=o(e).closest(\".wpr-list\").find(\".wpr-main-checkbox\");var n=o.map(s,t=>{if(void 0!==o(t).attr(\"checked\"))return t});r.attr(\"checked\",n.length===s.length?\"checked\":null)}}),0{let i=o(e).parents(\".wpr-list\");var s=i.find(\".wpr-list-body input[type=checkbox]:not(:checked)\").length;o(e).attr(\"checked\",s<=0?\"checked\":null)})})},{}],6:[function(t,e,i){\"use strict\";var c=jQuery;c(document).ready(function(){var t=c(\".wpr-notice\");c(\"#wpr-congratulations-notice\").on(\"click\",function(){return(new TimelineLite).to(t,1,{autoAlpha:0,x:40,ease:Power4.easeOut}).to(t,.6,{height:0,marginTop:0,ease:Power4.easeOut},\"=-.4\").set(t,{display:\"none\"}),!1}),c(\".rocket-analytics-data-container\").hide(),c(\".rocket-preview-analytics-data\").on(\"click\",function(t){t.preventDefault(),c(this).parent().next(\".rocket-analytics-data-container\").toggle()}),c(\".wpr-toggle-button\").each(function(){var t=c(this),e=t.closest(\".wpr-fieldsContainer-fieldset\").find(\".wpr-radio :checkbox\"),i=c('[href=\"'+t.attr(\"href\")+'\"].wpr-menuItem');e.on(\"change\",function(){e.is(\":checked\")?(i.css(\"display\",\"block\"),t.css(\"display\",\"inline-block\")):(i.css(\"display\",\"none\"),t.css(\"display\",\"none\"))}).trigger(\"change\")});var e=c(\".wpr-Popin-Analytics\"),i=c(\".wpr-Popin-overlay\"),s=c(\".wpr-Popin-Analytics-close\"),n=c(\".wpr-Popin-Analytics .wpr-button\");function r(){(new TimelineLite).fromTo(e,.6,{autoAlpha:1,marginTop:0},{autoAlpha:0,marginTop:-24,ease:Power4.easeOut}).fromTo(i,.6,{autoAlpha:1},{autoAlpha:0,ease:Power4.easeOut},\"=-.5\").set(e,{display:\"none\"}).set(i,{display:\"none\"})}c(\".wpr-js-popin\").on(\"click\",function(t){return t.preventDefault(),(new TimelineLite).set(e,{display:\"block\"}).set(i,{display:\"block\"}).fromTo(i,.6,{autoAlpha:0},{autoAlpha:1,ease:Power4.easeOut}).fromTo(e,.6,{autoAlpha:0,marginTop:-24},{autoAlpha:1,marginTop:0,ease:Power4.easeOut},\"=-.5\"),!1}),s.on(\"click\",function(t){return t.preventDefault(),r(),!1}),n.on(\"click\",function(t){return t.preventDefault(),r(),c(\"#analytics_enabled\").prop(\"checked\",!0),c(\"#analytics_enabled\").trigger(\"change\"),!1}),c(\"#analytics_enabled\").on(\"change\",function(){c(\".wpr-rocket-analytics-cta\").toggleClass(\"wpr-isHidden\")});var a=c(\".wpr-Popin-Upgrade\"),n=c(\".wpr-Popin-Upgrade-close\");c(\".wpr-popin-upgrade-toggle\").on(\"click\",function(t){return t.preventDefault(),(new TimelineLite).set(a,{display:\"block\"}).set(i,{display:\"block\"}).fromTo(i,.6,{autoAlpha:0},{autoAlpha:1,ease:Power4.easeOut}).fromTo(a,.6,{autoAlpha:0,marginTop:-24},{autoAlpha:1,marginTop:0,ease:Power4.easeOut},\"=-.5\"),!1}),n.on(\"click\",function(){return(new TimelineLite).fromTo(a,.6,{autoAlpha:1,marginTop:0},{autoAlpha:0,marginTop:-24,ease:Power4.easeOut}).fromTo(i,.6,{autoAlpha:1},{autoAlpha:0,ease:Power4.easeOut},\"=-.5\").set(a,{display:\"none\"}).set(i,{display:\"none\"}),!1});var o=c(\".wpr-Sidebar\");c(\".wpr-js-tips\").on(\"change\",function(){c(this).is(\":checked\")?(o.css(\"display\",\"block\"),localStorage.setItem(\"wpr-show-sidebar\",\"on\")):(o.css(\"display\",\"none\"),localStorage.setItem(\"wpr-show-sidebar\",\"off\"))}),document.getElementById(\"LKgOcCRpwmAj\")?c(\".wpr-adblock\").css(\"display\",\"none\"):c(\".wpr-adblock\").css(\"display\",\"block\");var l=c(\".wpr-adblock\");c(\".wpr-adblock-close\").on(\"click\",function(){return(new TimelineLite).to(l,1,{autoAlpha:0,x:40,ease:Power4.easeOut}).to(l,.4,{height:0,marginTop:0,ease:Power4.easeOut},\"=-.4\").set(l,{display:\"none\"}),!1})})},{}],7:[function(t,e,i){\"use strict\";function s(t){var e,i=this;this.$body=document.querySelector(\".wpr-body\"),this.$menuItems=document.querySelectorAll(\".wpr-menuItem\"),this.$submitButton=document.querySelector(\".wpr-Content > form > #wpr-options-submit\"),this.$pages=document.querySelectorAll(\".wpr-Page\"),this.$sidebar=document.querySelector(\".wpr-Sidebar\"),this.$content=document.querySelector(\".wpr-Content\"),this.$tips=document.querySelector(\".wpr-Content-tips\"),this.$links=document.querySelectorAll(\".wpr-body a\"),this.$menuItem=null,this.$page=null,this.pageId=null,this.bodyTop=0,this.buttonText=this.$submitButton.value,i.getBodyTop(),window.onhashchange=function(){i.detectID()},window.location.hash?(this.bodyTop=0,this.detectID()):(e=localStorage.getItem(\"wpr-hash\"),this.bodyTop=0,e?(window.location.hash=e,this.detectID()):(this.$menuItems[0].classList.add(\"isActive\"),localStorage.setItem(\"wpr-hash\",\"dashboard\"),window.location.hash=\"#dashboard\"));for(var s=0;s{a.querySelectorAll(\".wpr-rocketcdn-open\").forEach(t=>{t.addEventListener(\"click\",t=>{t.preventDefault()})}),function(){var t=\"\";t+=\"action=rocketcdn_process_status\";const e=r(t+=\"&nonce=\"+rocket_ajax_data.nonce);e.onreadystatechange=()=>{e.readyState===XMLHttpRequest.DONE&&200===e.status&&!0===JSON.parse(e.responseText).success&&MicroModal.show(\"wpr-rocketcdn-modal\")}}(),MicroModal.init({disableScroll:!0})}),s.addEventListener(\"load\",()=>{let t=a.querySelector(\"#wpr-rocketcdn-open-cta\"),e=a.querySelector(\"#wpr-rocketcdn-close-cta\"),i=a.querySelector(\"#wpr-rocketcdn-cta-small\"),s=a.querySelector(\"#wpr-rocketcdn-cta\");function n(t){var e=\"\";return e+=\"action=toggle_rocketcdn_cta\",e+=\"&status=\"+t,e+=\"&nonce=\"+rocket_ajax_data.nonce}null!==t&&null!==i&&null!==s&&t.addEventListener(\"click\",t=>{t.preventDefault(),i.classList.add(\"wpr-isHidden\"),s.classList.remove(\"wpr-isHidden\"),r(n(\"big\"))}),null!==e&&null!==i&&null!==s&&e.addEventListener(\"click\",t=>{t.preventDefault(),i.classList.remove(\"wpr-isHidden\"),s.classList.add(\"wpr-isHidden\"),r(n(\"small\"))})}),s.onmessage=t=>{var e,i,s=rocket_ajax_data.origin_url;t.origin===s&&((e=t.data).hasOwnProperty(\"cdnFrameHeight\")&&(a.getElementById(\"rocketcdn-iframe\").style.height=\"\".concat(e.cdnFrameHeight,\"px\")),(i=t.data).hasOwnProperty(\"cdnFrameClose\")&&(MicroModal.close(\"wpr-rocketcdn-modal\"),i.hasOwnProperty(\"cdn_page_message\")&&-1!==[\"iframe-payment-success\",\"iframe-unsubscribe-success\"].indexOf(i.cdn_page_message)&&a.location.reload()),function(t,e){let i=a.querySelector(\"#rocketcdn-iframe\").contentWindow;if(t.hasOwnProperty(\"rocketcdn_token\")){var s=\"\";s+=\"action=save_rocketcdn_token\",s+=\"&value=\"+t.rocketcdn_token;const n=r(s+=\"&nonce=\"+rocket_ajax_data.nonce);n.onreadystatechange=()=>{var t;n.readyState===XMLHttpRequest.DONE&&200===n.status&&(t=JSON.parse(n.responseText),i.postMessage({success:t.success,data:t.data,rocketcdn:!0},e))}}else{s={process:\"subscribe\",message:\"token_not_received\"};i.postMessage({success:!1,data:s,rocketcdn:!0},e)}}(t.data,s),(e=t.data).hasOwnProperty(\"rocketcdn_process\")&&(i=\"\",i+=\"action=rocketcdn_process_set\",i+=\"&status=\"+e.rocketcdn_process,r(i+=\"&nonce=\"+rocket_ajax_data.nonce)),function(t,e){let i=a.querySelector(\"#rocketcdn-iframe\").contentWindow;if(t.hasOwnProperty(\"rocketcdn_url\")){var s=\"\";s+=\"action=rocketcdn_enable\",s+=\"&cdn_url=\"+t.rocketcdn_url;const n=r(s+=\"&nonce=\"+rocket_ajax_data.nonce);n.onreadystatechange=()=>{var t;n.readyState===XMLHttpRequest.DONE&&200===n.status&&(t=JSON.parse(n.responseText),i.postMessage({success:t.success,data:t.data,rocketcdn:!0},e))}}}(t.data,s),function(t,e){let i=a.querySelector(\"#rocketcdn-iframe\").contentWindow;if(t.hasOwnProperty(\"rocketcdn_disable\")){t=\"\";t+=\"action=rocketcdn_disable\";const s=r(t+=\"&nonce=\"+rocket_ajax_data.nonce);s.onreadystatechange=()=>{var t;s.readyState===XMLHttpRequest.DONE&&200===s.status&&(t=JSON.parse(s.responseText),i.postMessage({success:t.success,data:t.data,rocketcdn:!0},e))}}}(t.data,s),(s=t.data).hasOwnProperty(\"rocketcdn_validate_token\")&&s.hasOwnProperty(\"rocketcdn_validate_cname\")&&(t=\"\",t+=\"action=rocketcdn_validate_token_cname\",t+=\"&cdn_url=\"+s.rocketcdn_validate_cname,t+=\"&cdn_token=\"+s.rocketcdn_validate_token,r(t+=\"&nonce=\"+rocket_ajax_data.nonce)))}},{}],9:[function(t,e,i){\"use strict\";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine(\"TimelineLite\",[\"core.Animation\",\"core.SimpleTimeline\",\"TweenLite\"],function(h,u,p){function d(t){u.call(this,t),this._labels={},this.autoRemoveChildren=!0===this.vars.autoRemoveChildren,this.smoothChildTiming=!0===this.vars.smoothChildTiming,this._sortChildren=!0,this._onUpdate=this.vars.onUpdate;var e,i,s=this.vars;for(i in s)e=s[i],g(e)&&-1!==e.join(\"\").indexOf(\"{self}\")&&(s[i]=this._swapSelfInParams(e));g(s.tweens)&&this.add(s.tweens,0,s.align,s.stagger)}function _(t){var e,i={};for(e in t)i[e]=t[e];return i}function n(t,e,i,s){t._timeline.pause(t._startTime),e&&e.apply(s||t._timeline,i||v)}var f=1e-10,m=p._internals.isSelector,g=p._internals.isArray,v=[],a=window._gsDefine.globals,w=v.slice,t=d.prototype=new u;return d.version=\"1.12.1\",t.constructor=d,t.kill()._gc=!1,t.to=function(t,e,i,s){var n=i.repeat&&a.TweenMax||p;return e?this.add(new n(t,e,i),s):this.set(t,i,s)},t.from=function(t,e,i,s){return this.add((i.repeat&&a.TweenMax||p).from(t,e,i),s)},t.fromTo=function(t,e,i,s,n){var r=s.repeat&&a.TweenMax||p;return e?this.add(r.fromTo(t,e,i,s),n):this.set(t,s,n)},t.staggerTo=function(t,e,i,s,n,r,a,o){var l,c=new d({onComplete:r,onCompleteParams:a,onCompleteScope:o,smoothChildTiming:this.smoothChildTiming});for(\"string\"==typeof t&&(t=p.selector(t)||t),m(t)&&(t=w.call(t,0)),s=s||0,l=0;t.length>l;l++)i.startAt&&(i.startAt=_(i.startAt)),c.to(t[l],e,_(i),l*s);return this.add(c,n)},t.staggerFrom=function(t,e,i,s,n,r,a,o){return i.immediateRender=0!=i.immediateRender,i.runBackwards=!0,this.staggerTo(t,e,i,s,n,r,a,o)},t.staggerFromTo=function(t,e,i,s,n,r,a,o,l){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,this.staggerTo(t,e,s,n,r,a,o,l)},t.call=function(t,e,i,s){return this.add(p.delayedCall(0,t,e,i),s)},t.set=function(t,e,i){return i=this._parseTimeOrLabel(i,0,!0),null==e.immediateRender&&(e.immediateRender=i===this._time&&!this._paused),this.add(new p(t,0,e),i)},d.exportRoot=function(t,e){null==(t=t||{}).smoothChildTiming&&(t.smoothChildTiming=!0);var i,s,n=new d(t),t=n._timeline;for(null==e&&(e=!0),t._remove(n,!0),n._startTime=0,n._rawPrevTime=n._time=n._totalTime=t._time,i=t._first;i;)s=i._next,e&&i instanceof p&&i.target===i.vars.onComplete||n.add(i,i._startTime-i._delay),i=s;return t.add(n,0),n},t.add=function(t,e,i,s){var n,r,a,o,l,c;if(\"number\"!=typeof e&&(e=this._parseTimeOrLabel(e,0,!0,t)),!(t instanceof h)){if(t instanceof Array||t&&t.push&&g(t)){for(i=i||\"normal\",s=s||0,n=e,r=t.length,a=0;at._startTime;l._timeline;)c&&l._timeline.smoothChildTiming?l.totalTime(l._totalTime,!0):l._gc&&l._enabled(!0,!1),l=l._timeline;return this},t.remove=function(t){if(t instanceof h)return this._remove(t,!1);if(t instanceof Array||t&&t.push&&g(t)){for(var e=t.length;-1<--e;)this.remove(t[e]);return this}return\"string\"==typeof t?this.removeLabel(t):this.kill(null,t)},t._remove=function(t,e){u.prototype._remove.call(this,t,e);e=this._last;return e?this._time>e._startTime+e._totalDuration/e._timeScale&&(this._time=this.duration(),this._totalTime=this._totalDuration):this._time=this._totalTime=this._duration=this._totalDuration=0,this},t.append=function(t,e){return this.add(t,this._parseTimeOrLabel(null,e,!0,t))},t.insert=t.insertMultiple=function(t,e,i,s){return this.add(t,e||0,i,s)},t.appendMultiple=function(t,e,i,s){return this.add(t,this._parseTimeOrLabel(null,e,!0,t),i,s)},t.addLabel=function(t,e){return this._labels[t]=this._parseTimeOrLabel(e),this},t.addPause=function(t,e,i,s){return this.call(n,[\"{self}\",e,i,s],this,t)},t.removeLabel=function(t){return delete this._labels[t],this},t.getLabelTime=function(t){return null!=this._labels[t]?this._labels[t]:-1},t._parseTimeOrLabel=function(t,e,i,s){var n;if(s instanceof h&&s.timeline===this)this.remove(s);else if(s&&(s instanceof Array||s.push&&g(s)))for(n=s.length;-1<--n;)s[n]instanceof h&&s[n].timeline===this&&this.remove(s[n]);if(\"string\"==typeof e)return this._parseTimeOrLabel(e,i&&\"number\"==typeof t&&null==this._labels[e]?t-this.duration():0,i);if(e=e||0,\"string\"!=typeof t||!isNaN(t)&&null==this._labels[t])null==t&&(t=this.duration());else{if(-1===(n=t.indexOf(\"=\")))return null==this._labels[t]?i?this._labels[t]=this.duration()+e:e:this._labels[t]+e;e=parseInt(t.charAt(n-1)+\"1\",10)*Number(t.substr(n+1)),t=1f&&(a=\"onReverseComplete\"))),this._rawPrevTime=this._duration||!e||t||this._rawPrevTime===t?t:f,t=l+1e-4):t<1e-7?(((this._totalTime=this._time=0)!==c||0===this._duration&&this._rawPrevTime!==f&&(0=c)for(s=this._first;s&&(r=s._next,!this._paused||p);)(s._active||s._startTime<=this._time&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=r;else for(s=this._last;s&&(r=s._prev,!this._paused||p);)(s._active||c>=s._startTime&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=r;this._onUpdate&&(e||this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||v)),a&&(this._gc||h!==this._startTime&&u===this._timeScale||!(0===this._time||l>=this.totalDuration())||(n&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),!e&&this.vars[a]&&this.vars[a].apply(this.vars[a+\"Scope\"]||this,this.vars[a+\"Params\"]||v)))}},t._hasPausedChild=function(){for(var t=this._first;t;){if(t._paused||t instanceof d&&t._hasPausedChild())return!0;t=t._next}return!1},t.getChildren=function(t,e,i,s){s=s||-9999999999;for(var n=[],r=this._first,a=0;r;)s>r._startTime||(r instanceof p?!1!==e&&(n[a++]=r):(!1!==i&&(n[a++]=r),!1!==t&&(a=(n=n.concat(r.getChildren(!0,e,i))).length))),r=r._next;return n},t.getTweensOf=function(t,e){var i,s,n=this._gc,r=[],a=0;for(n&&this._enabled(!0,!0),s=(i=p.getTweensOf(t)).length;-1<--s;)(i[s].timeline===this||e&&this._contains(i[s]))&&(r[a++]=i[s]);return n&&this._enabled(!1,!0),r},t._contains=function(t){for(var e=t.timeline;e;){if(e===this)return!0;e=e.timeline}return!1},t.shiftChildren=function(t,e,i){i=i||0;for(var s,n=this._first,r=this._labels;n;)n._startTime>=i&&(n._startTime+=t),n=n._next;if(e)for(s in r)r[s]>=i&&(r[s]+=t);return this._uncache(!0)},t._kill=function(t,e){if(!t&&!e)return this._enabled(!1,!1);for(var i=e?this.getTweensOf(e):this.getChildren(!0,!0,!1),s=i.length,n=!1;-1<--s;)i[s]._kill(t,e)&&(n=!0);return n},t.clear=function(t){var e=this.getChildren(!1,!0,!0),i=e.length;for(this._time=this._totalTime=0;-1<--i;)e[i]._enabled(!1,!1);return!1!==t&&(this._labels={}),this._uncache(!0)},t.invalidate=function(){for(var t=this._first;t;)t.invalidate(),t=t._next;return this},t._enabled=function(t,e){if(t===this._gc)for(var i=this._first;i;)i._enabled(t,!0),i=i._next;return u.prototype._enabled.call(this,t,e)},t.duration=function(t){return arguments.length?(0!==this.duration()&&0!==t&&this.timeScale(this._duration/t),this):(this._dirty&&this.totalDuration(),this._duration)},t.totalDuration=function(t){if(arguments.length)return 0!==this.totalDuration()&&0!==t&&this.timeScale(this._totalDuration/t),this;if(this._dirty){for(var e,i,s=0,n=this._last,r=999999999999;n;)e=n._prev,n._dirty&&n.totalDuration(),n._startTime>r&&this._sortChildren&&!n._paused?this.add(n,n._startTime-n._delay):r=n._startTime,n._startTime<0&&!n._paused&&(s-=n._startTime,this._timeline.smoothChildTiming&&(this._startTime+=n._startTime/this._timeScale),this.shiftChildren(-n._startTime,!1,-9999999999),r=0),s<(i=n._startTime+n._totalDuration/n._timeScale)&&(s=i),n=e;this._duration=this._totalDuration=s,this._dirty=!1}return this._totalDuration},t.usesFrames=function(){for(var t=this._timeline;t._timeline;)t=t._timeline;return t===h._rootFramesTimeline},t.rawTime=function(){return this._paused?this._totalTime:(this._timeline.rawTime()-this._startTime)*this._timeScale},d},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],10:[function(t,Q,e){\"use strict\";!function(p){var e,i,d=p.GreenSockGlobals||p;if(!d.TweenLite){var _,f=function(t){for(var e=t.split(\".\"),i=d,s=0;e.length>s;s++)i[e[s]]=i=i[e[s]]||{};return i},u=f(\"com.greensock\"),m=1e-10,o=[].slice,g=function(){},h=(e=Object.prototype.toString,i=e.call([]),function(t){return null!=t&&(t instanceof Array||\"object\"==typeof t&&!!t.push&&e.call(t)===i)}),v={},w=function(o,l,c,h){this.sc=v[o]?v[o].sc:[],(v[o]=this).gsClass=null,this.func=c;var u=[];this.check=function(t){for(var e,i,s,n,r=l.length,a=r;-1<--r;)(e=v[l[r]]||new w(l[r],[])).gsClass?(u[r]=e.gsClass,a--):t&&e.sc.push(this);if(0===a&&c)for(s=(i=(\"com.greensock.\"+o).split(\".\")).pop(),n=f(i.join(\".\"))[s]=this.gsClass=c.apply(c,u),h&&(d[s]=n,\"function\"==typeof define&&define.amd?define((p.GreenSockAMDPath?p.GreenSockAMDPath+\"/\":\"\")+o.split(\".\").join(\"/\"),[],function(){return n}):void 0!==Q&&Q.exports&&(Q.exports=n)),r=0;this.sc.length>r;r++)this.sc[r].check()},this.check(!0)},s=p._gsDefine=function(t,e,i,s){return new w(t,e,i,s)},y=u._class=function(t,e,i){return e=e||function(){},s(t,[],function(){return e},i),e};s.globals=d;var t,n=[0,0,1,1],x=[],b=y(\"easing.Ease\",function(t,e,i,s){this._func=t,this._type=i||0,this._power=s||0,this._params=e?n.concat(e):n},!0),T=b.map={},r=b.register=function(t,e,i,s){for(var n,r,a,o,l=e.split(\",\"),c=l.length,h=(i||\"easeIn,easeOut,easeInOut\").split(\",\");-1<--c;)for(r=l[c],n=s?y(\"easing.\"+r,null,!0):u.easing[r]||{},a=h.length;-1<--a;)o=h[a],T[r+\".\"+o]=T[o+r]=n[o]=t.getRatio?t:t[o]||new t};for((t=b.prototype)._calcEnd=!1,t.getRatio=function(t){if(this._func)return this._params[0]=t,this._func.apply(null,this._params);var e=this._type,i=this._power,s=1===e?1-t:2===e?t:t<.5?2*t:2*(1-t);return 1===i?s*=s:2===i?s*=s*s:3===i?s*=s*s*s:4===i&&(s*=s*s*s*s),1===e?1-s:2===e?s:t<.5?s/2:1-s/2},l=(a=[\"Linear\",\"Quad\",\"Cubic\",\"Quart\",\"Quint,Strong\"]).length;-1<--l;)t=a[l]+\",Power\"+l,r(new b(null,null,1,l),t,\"easeOut\",!0),r(new b(null,null,2,l),t,\"easeIn\"+(0===l?\",easeNone\":\"\")),r(new b(null,null,3,l),t,\"easeInOut\");T.linear=u.easing.Linear.easeIn,T.swing=u.easing.Quad.easeInOut;var k=y(\"events.EventDispatcher\",function(t){this._listeners={},this._eventTarget=t||this});(t=k.prototype).addEventListener=function(t,e,i,s,n){n=n||0;var r,a,o=this._listeners[t],l=0;for(null==o&&(this._listeners[t]=o=[]),a=o.length;-1<--a;)(r=o[a]).c===e&&r.s===i?o.splice(a,1):0===l&&n>r.pr&&(l=a+1);o.splice(l,0,{c:e,s:i,up:s,pr:n}),this!==A||_||A.wake()},t.removeEventListener=function(t,e){var i,s=this._listeners[t];if(s)for(i=s.length;-1<--i;)if(s[i].c===e)return void s.splice(i,1)},t.dispatchEvent=function(t){var e,i,s,n=this._listeners[t];if(n)for(e=n.length,i=this._eventTarget;-1<--e;)(s=n[e]).up?s.c.call(s.s||i,{type:t,target:i}):s.c.call(s.s||i)};for(var a,P=p.requestAnimationFrame,S=p.cancelAnimationFrame,O=Date.now||function(){return(new Date).getTime()},C=O(),l=(a=[\"ms\",\"moz\",\"webkit\",\"o\"]).length;-1<--l&&!P;)P=p[a[l]+\"RequestAnimationFrame\"],S=p[a[l]+\"CancelAnimationFrame\"]||p[a[l]+\"CancelRequestAnimationFrame\"];y(\"Ticker\",function(t,e){var s,n,r,a,o,l=this,c=O(),i=!1!==e&&P,h=500,u=33,p=function(t){var e,i=O()-C;h=i&&i+this.totalDuration()/this._timeScale>t},t._enabled=function(t,e){return _||A.wake(),this._gc=!t,this._active=this.isActive(),!0!==e&&(t&&!this.timeline?this._timeline.add(this,this._startTime-this._delay):!t&&this.timeline&&this._timeline._remove(this,!0)),!1},t._kill=function(){return this._enabled(!1,!1)},t.kill=function(t,e){return this._kill(t,e),this},t._uncache=function(t){for(var e=t?this:this.timeline;e;)e._dirty=!0,e=e.timeline;return this},t._swapSelfInParams=function(t){for(var e=t.length,i=t.concat();-1<--e;)\"{self}\"===t[e]&&(i[e]=this);return i},t.eventCallback=function(t,e,i,s){if(\"on\"===(t||\"\").substr(0,2)){var n=this.vars;if(1===arguments.length)return n[t];null==e?delete n[t]:(n[t]=e,n[t+\"Params\"]=h(i)&&-1!==i.join(\"\").indexOf(\"{self}\")?this._swapSelfInParams(i):i,n[t+\"Scope\"]=s),\"onUpdate\"===t&&(this._onUpdate=e)}return this},t.delay=function(t){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+t-this._delay),this._delay=t,this):this._delay},t.duration=function(t){return arguments.length?(this._duration=this._totalDuration=t,this._uncache(!0),this._timeline.smoothChildTiming&&0this._duration?this._duration:t,e)):this._time},t.totalTime=function(t,e,i){if(_||A.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(t<0&&!i&&(t+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var s=this._totalDuration,n=this._timeline;if(ss;)i=i._prev;return i?(t._next=i._next,i._next=t):(t._next=this._first,this._first=t),t._next?t._next._prev=t:this._last=t,t._prev=i,this._timeline&&this._uncache(!0),this},t._remove=function(t,e){return t.timeline===this&&(e||t._enabled(!1,!0),t.timeline=null,t._prev?t._prev._next=t._next:this._first===t&&(this._first=t._next),t._next?t._next._prev=t._prev:this._last===t&&(this._last=t._prev),this._timeline&&this._uncache(!0)),this},t.render=function(t,e,i){var s,n=this._first;for(this._totalTime=this._time=this._rawPrevTime=t;n;)s=n._next,(n._active||t>=n._startTime&&!n._paused)&&(n._reversed?n.render((n._dirty?n.totalDuration():n._totalDuration)-(t-n._startTime)*n._timeScale,e,i):n.render((t-n._startTime)*n._timeScale,e,i)),n=s},t.rawTime=function(){return _||A.wake(),this._totalTime};var I=y(\"TweenLite\",function(t,e,i){if(c.call(this,e,i),this.render=I.prototype.render,null==t)throw\"Cannot tween a null target.\";this.target=t=\"string\"==typeof t&&I.selector(t)||t;var s,n,r,i=t.jquery||t.length&&t!==p&&t[0]&&(t[0]===p||t[0].nodeType&&t[0].style&&!t.nodeType),a=this.vars.overwrite;if(this._overwrite=a=null==a?F[I.defaultOverwrite]:\"number\"==typeof a?a>>0:F[a],(i||t instanceof Array||t.push&&h(t))&&\"number\"!=typeof t[0])for(this._targets=r=o.call(t,0),this._propLookup=[],this._siblings=[],s=0;r.length>s;s++)(n=r[s])?\"string\"!=typeof n?n.length&&n!==p&&n[0]&&(n[0]===p||n[0].nodeType&&n[0].style&&!n.nodeType)?(r.splice(s--,1),this._targets=r=r.concat(o.call(n,0))):(this._siblings[s]=H(n,this,!1),1===a&&1=a._startTime&&a._startTime+a.totalDuration()/a._timeScale>c&&((p||!a._initted)&&c-a._startTime<=2e-10||(h[u++]=a)));for(d=u;-1<--d;)a=h[d],2===s&&a._kill(i,t)&&(r=!0),(2!==s||!a._firstPT&&a._initted)&&a._enabled(!1,!1)&&(r=!0);return r},W=function(t,e,i){for(var s=t._timeline,n=s._timeScale,r=t._startTime;s._timeline;){if(r+=s._startTime,n*=s._timeScale,s._paused)return-100;s=s._timeline}return e<(r/=n)?r-e:i&&r===e||!t._initted&&r-e<2*m?m:(r+=t.totalDuration()/t._timeScale/n)>e+m?0:r-e-m};t._init=function(){var t,e,i,s,n,r=this.vars,a=this._overwrittenProps,o=this._duration,l=!!r.immediateRender,c=r.ease;if(r.startAt){for(s in this._startAt&&(this._startAt.render(-1,!0),this._startAt.kill()),n={},r.startAt)n[s]=r.startAt[s];if(n.overwrite=!1,n.immediateRender=!0,n.lazy=l&&!1!==r.lazy,n.startAt=n.delay=null,this._startAt=I.to(this.target,0,n),l)if(0o.pr;)s=s._next;(o._prev=s?s._prev:r)?o._prev._next=o:n=o,(o._next=s)?s._prev=o:r=o,o=a}o=e._firstPT=n}for(;o;)o.pg&&\"function\"==typeof o.t[t]&&o.t[t]()&&(i=!0),o=o._next;return i},V.activate=function(t){for(var e=t.length;-1<--e;)t[e].API===V.API&&(E[(new t[e])._propName]=t[e]);return!0},s.plugin=function(t){if(!(t&&t.propName&&t.init&&t.API))throw\"illegal plugin definition.\";var e,i=t.propName,s=t.priority||0,n=t.overwriteProps,r={init:\"_onInitTween\",set:\"setRatio\",kill:\"_kill\",round:\"_roundProps\",initAll:\"_onInitAllProps\"},a=y(\"plugins.\"+i.charAt(0).toUpperCase()+i.substr(1)+\"Plugin\",function(){V.call(this,i,s),this._overwriteProps=n||[]},!0===t.global),o=a.prototype=new V(i);for(e in(o.constructor=a).API=t.API,r)\"function\"==typeof t[e]&&(o[r[e]]=t[e]);return a.version=t.version,V.activate([a]),a},a=p._gsQueue){for(l=0;a.length>l;l++)a[l]();for(t in v)v[t].func||p.console.log(\"GSAP encountered missing dependency: com.greensock.\"+t)}_=!1}}(window)},{}],11:[function(t,e,i){\"use strict\";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine(\"easing.Back\",[\"easing.Ease\"],function(m){function t(t,e){var i=c(\"easing.\"+t,function(){},!0);return(t=i.prototype=new m).constructor=i,t.getRatio=e,i}function e(t,e,i,s){return s=c(\"easing.\"+t,{easeOut:new e,easeIn:new i,easeInOut:new s},!0),h(s,t),s}function g(t,e,i){this.t=t,this.v=e,i&&(((this.next=i).prev=this).c=i.v-e,this.gap=i.t-t)}function i(t,e){var i=c(\"easing.\"+t,function(t){this._p1=t||0===t?t:1.70158,this._p2=1.525*this._p1},!0);return(t=i.prototype=new m).constructor=i,t.getRatio=e,t.config=function(t){return new i(t)},i}var s,n,r=window.GreenSockGlobals||window,a=r.com.greensock,o=2*Math.PI,l=Math.PI/2,c=a._class,h=m.register||function(){},u=e(\"Back\",i(\"BackOut\",function(t){return--t*t*((this._p1+1)*t+this._p1)+1}),i(\"BackIn\",function(t){return t*t*((this._p1+1)*t-this._p1)}),i(\"BackInOut\",function(t){return(t*=2)<1?.5*t*t*((this._p2+1)*t-this._p2):.5*((t-=2)*t*((this._p2+1)*t+this._p2)+2)})),p=c(\"easing.SlowMo\",function(t,e,i){e=e||0===e?e:.7,null==t?t=.7:1t?this._calcEnd?1-(t=1-t/this._p1)*t:e-(t=1-t/this._p1)*t*t*t*e:t>this._p3?this._calcEnd?1-(t=(t-this._p3)/this._p1)*t:e+(t-e)*(t=(t-this._p3)/this._p1)*t*t*t:this._calcEnd?1:e},p.ease=new p(.7,.7),a.config=p.config=function(t,e,i){return new p(t,e,i)},(a=(s=c(\"easing.SteppedEase\",function(t){this._p1=1/(t=t||1),this._p2=t+1},!0)).prototype=new m).constructor=s,a.getRatio=function(t){return t<0?t=0:1<=t&&(t=.999999999),(this._p2*t>>0)*this._p1},a.config=s.config=function(t){return new s(t)},(a=(n=c(\"easing.RoughEase\",function(t){for(var e,i,s,n,r,a,o=(t=t||{}).taper||\"none\",l=[],c=0,h=0|(t.points||20),u=h,p=!1!==t.randomize,d=!0===t.clamp,_=t.template instanceof m?t.template:null,f=\"number\"==typeof t.strength?.4*t.strength:.4;-1<--u;)e=p?Math.random():1/h*u,i=_?_.getRatio(e):e,s=\"none\"===o?f:\"out\"===o?(n=1-e)*n*f:\"in\"===o?e*e*f:.5*(n=e<.5?2*e:2*(1-e))*n*f,p?i+=Math.random()*s-.5*s:u%2?i+=.5*s:i-=.5*s,d&&(1e.t){for(;e.next&&t>=e.t;)e=e.next;e=e.prev}else for(;e.prev&&e.t>=t;)e=e.prev;return(this._prev=e).v+(t-e.t)/e.gap*e.c},a.config=function(t){return new n(t)},n.ease=new n,e(\"Bounce\",t(\"BounceOut\",function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}),t(\"BounceIn\",function(t){return 1/2.75>(t=1-t)?1-7.5625*t*t:t<2/2.75?1-(7.5625*(t-=1.5/2.75)*t+.75):t<2.5/2.75?1-(7.5625*(t-=2.25/2.75)*t+.9375):1-(7.5625*(t-=2.625/2.75)*t+.984375)}),t(\"BounceInOut\",function(t){var e=t<.5;return t=(t=e?1-2*t:2*t-1)<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375,e?.5*(1-t):.5*t+.5})),e(\"Circ\",t(\"CircOut\",function(t){return Math.sqrt(1- --t*t)}),t(\"CircIn\",function(t){return-(Math.sqrt(1-t*t)-1)}),t(\"CircInOut\",function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)})),e(\"Elastic\",(a=function(t,e,i){var s=c(\"easing.\"+t,function(t,e){this._p1=t||1,this._p2=e||i,this._p3=this._p2/o*(Math.asin(1/this._p1)||0)},!0),t=s.prototype=new m;return t.constructor=s,t.getRatio=e,t.config=function(t,e){return new s(t,e)},s})(\"ElasticOut\",function(t){return this._p1*Math.pow(2,-10*t)*Math.sin((t-this._p3)*o/this._p2)+1},.3),a(\"ElasticIn\",function(t){return-(this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*o/this._p2))},.3),a(\"ElasticInOut\",function(t){return(t*=2)<1?-.5*this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*o/this._p2):.5*this._p1*Math.pow(2,-10*--t)*Math.sin((t-this._p3)*o/this._p2)+1},.45)),e(\"Expo\",t(\"ExpoOut\",function(t){return 1-Math.pow(2,-10*t)}),t(\"ExpoIn\",function(t){return Math.pow(2,10*(t-1))-.001}),t(\"ExpoInOut\",function(t){return(t*=2)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*(t-1)))})),e(\"Sine\",t(\"SineOut\",function(t){return Math.sin(t*l)}),t(\"SineIn\",function(t){return 1-Math.cos(t*l)}),t(\"SineInOut\",function(t){return-.5*(Math.cos(Math.PI*t)-1)})),c(\"easing.EaseLookup\",{find:function(t){return m.map[t]}},!0),h(r.SlowMo,\"SlowMo\",\"ease,\"),h(n,\"RoughEase\",\"ease,\"),h(s,\"SteppedEase\",\"ease,\"),u},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],12:[function(t,e,i){\"use strict\";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine(\"plugins.CSSPlugin\",[\"plugins.TweenPlugin\",\"TweenLite\"],function(r,p){function N(){r.call(this,\"css\"),this._overwriteProps.length=0,this.setRatio=N.prototype.setRatio}var d,x,b,u,_={},t=N.prototype=new r(\"css\");(t.constructor=N).version=\"1.12.1\",N.API=2,N.defaultTransformPerspective=0,N.defaultSkewType=\"compensated\",N.suffixMap={top:t=\"px\",right:t,bottom:t,left:t,width:t,height:t,fontSize:t,padding:t,margin:t,perspective:t,lineHeight:\"\"};function n(t,e){return e.toUpperCase()}function a(t){return L.test(\"string\"==typeof t?t:(t.currentStyle||t.style).filter||\"\")?parseFloat(RegExp.$1)/100:1}function f(t){window.console&&console.log(t)}function T(t,e){var i,s,n=(e=e||Z).style;if(void 0!==n[t])return t;for(t=t.charAt(0).toUpperCase()+t.substr(1),i=[\"O\",\"Moz\",\"ms\",\"Ms\",\"Webkit\"],s=5;-1<--s&&void 0===n[i[s]+t];);return 0<=s?(tt=\"-\"+(et=3===s?\"ms\":i[s]).toLowerCase()+\"-\",et+t):null}function m(t,e){var i,s={};if(e=e||it(t,null))if(i=e.length)for(;-1<--i;)s[e[i].replace(Y,n)]=e.getPropertyValue(e[i]);else for(i in e)s[i]=e[i];else if(e=t.currentStyle||t.style)for(i in e)\"string\"==typeof i&&void 0===s[i]&&(s[i.replace(Y,n)]=e[i]);return J||(s.opacity=a(t)),t=Pt(t,e,!1),s.rotation=t.rotation,s.skewX=t.skewX,s.scaleX=t.scaleX,s.scaleY=t.scaleY,s.x=t.x,s.y=t.y,Tt&&(s.z=t.z,s.rotationX=t.rotationX,s.rotationY=t.rotationY,s.scaleZ=t.scaleZ),s.filters&&delete s.filters,s}function g(t,e,i,s,n){var r,a,o,l={},c=t.style;for(a in i)\"cssText\"!==a&&\"length\"!==a&&isNaN(a)&&(e[a]!==(r=i[a])||n&&n[a])&&-1===a.indexOf(\"Origin\")&&(\"number\"==typeof r||\"string\"==typeof r)&&(l[a]=\"auto\"!==r||\"left\"!==a&&\"top\"!==a?\"\"!==r&&\"auto\"!==r&&\"none\"!==r||\"string\"!=typeof e[a]||\"\"===e[a].replace(D,\"\")?r:0:rt(t,a),void 0!==c[a]&&(o=new pt(c,a,c[a],o)));if(s)for(a in s)\"className\"!==a&&(l[a]=s[a]);return{difs:l,firstMPT:o}}function v(t,e){var i=(t=null==t||\"\"===t||\"auto\"===t||\"auto auto\"===t?\"0 0\":t).split(\" \"),s=-1!==t.indexOf(\"left\")?\"0%\":-1!==t.indexOf(\"right\")?\"100%\":i[0];return null==(t=-1!==t.indexOf(\"top\")?\"0%\":-1!==t.indexOf(\"bottom\")?\"100%\":i[1])?t=\"0\":\"center\"===t&&(t=\"50%\"),(\"center\"===s||isNaN(parseFloat(s))&&-1===(s+\"\").indexOf(\"=\"))&&(s=\"50%\"),e&&(e.oxp=-1!==s.indexOf(\"%\"),e.oyp=-1!==t.indexOf(\"%\"),e.oxr=\"=\"===s.charAt(1),e.oyr=\"=\"===t.charAt(1),e.ox=parseFloat(s.replace(D,\"\")),e.oy=parseFloat(t.replace(D,\"\"))),s+\" \"+t+(2>16,255&t>>8,255&t]:(\",\"===t.charAt(t.length-1)&&(t=t.substr(0,t.length-1)),lt[t]||(\"#\"===t.charAt(0)?(4===t.length&&(t=\"#\"+(e=t.charAt(1))+e+(i=t.charAt(2))+i+(r=t.charAt(3))+r),[(t=parseInt(t.substr(1),16))>>16,255&t>>8,255&t]):(\"hsl\"===t.substr(0,3)?(t=t.match(A),s=Number(t[0])%360/360,n=Number(t[1])/100,e=2*(r=Number(t[2])/100)-(i=r<=.5?r*(1+n):r+n-r*n),3a\",!!(i=i.getElementsByTagName(\"a\")[0])&&/^0.55/.test(i.style.opacity)),tt=\"\",et=\"\",it=Q.defaultView?Q.defaultView.getComputedStyle:function(){},st=N.getStyle=function(t,e,i,s,n){var r;return J||\"opacity\"!==e?(!s&&t.style[e]?r=t.style[e]:(i=i||it(t))?r=i[e]||i.getPropertyValue(e)||i.getPropertyValue(e.replace(z,\"-$1\").toLowerCase()):t.currentStyle&&(r=t.currentStyle[e]),null==n||r&&\"none\"!==r&&\"auto\"!==r&&\"auto auto\"!==r?r:n):a(t)},nt=s.convertToPixels=function(t,e,i,s,n){if(\"px\"===s||!s)return i;if(\"auto\"===s||!i)return 0;var r,a,o,l=$.test(e),c=t,h=Z.style,u=i<0;if(u&&(i=-i),\"%\"===s&&-1!==e.indexOf(\"border\"))r=i/100*(l?t.clientWidth:t.clientHeight);else{if(h.cssText=\"border:0 solid red;position:\"+st(t,\"position\")+\";line-height:0;\",\"%\"!==s&&c.appendChild)h[l?\"borderLeftWidth\":\"borderTopWidth\"]=i+s;else{if(a=(c=t.parentNode||Q.body)._gsCache,o=p.ticker.frame,a&&l&&a.time===o)return a.width*i/100;h[l?\"width\":\"height\"]=i+s}c.appendChild(Z),r=parseFloat(Z[l?\"offsetWidth\":\"offsetHeight\"]),c.removeChild(Z),l&&\"%\"===s&&!1!==N.cacheWidths&&((a=c._gsCache=c._gsCache||{}).time=o,a.width=r/i*100),0!==r||n||(r=nt(t,e,i,s,!0))}return u?-r:r},rt=s.calculateOffset=function(t,e,i){if(\"absolute\"!==st(t,\"position\",i))return 0;var s=\"left\"===e?\"Left\":\"Top\",i=st(t,\"margin\"+s,i);return t[\"offset\"+s]-(nt(t,e,parseFloat(i),i.replace(j,\"\"))||0)},at={width:[\"Left\",\"Right\"],height:[\"Top\",\"Bottom\"]},ot=[\"marginLeft\",\"marginRight\",\"marginTop\",\"marginBottom\"],lt={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},ct=\"(?:\\\\b(?:(?:rgb|rgba|hsl|hsla)\\\\(.+?\\\\))|\\\\B#.+?\\\\b\";for(t in lt)ct+=\"|\"+t+\"\\\\b\";function ht(t,e,r,a){if(null==t)return function(t){return t};var o,l=e?(t.match(ct)||[\"\"])[0]:\"\",c=t.split(l).join(\"\").match(I)||[],h=t.substr(0,t.indexOf(c[0])),u=\")\"===t.charAt(t.length-1)?\")\":\"\",p=-1!==t.indexOf(\" \")?\" \":\",\",d=c.length,_=0s;s++)n[s]=o(n[s]);return n.join(\",\")}if(e=(t.match(ct)||[l])[0],s=(i=t.split(e).join(\"\").match(I)||[]).length,d>s--)for(;d>++s;)i[s]=r?i[0|(s-1)/2]:c[s];return h+i.join(p)+p+e+u+(-1!==t.indexOf(\"inset\")?\" inset\":\"\")}:function(t){var e,i,s;if(\"number\"==typeof t)t+=_;else if(a&&H.test(t)){for(i=t.replace(H,\"|\").split(\"|\"),s=0;i.length>s;s++)i[s]=o(i[s]);return i.join(\",\")}if(s=(e=t.match(I)||[]).length,d>s--)for(;d>++s;)e[s]=r?e[0|(s-1)/2]:c[s];return h+e.join(p)+u}:function(t){return t}}function ut(c){return c=c.split(\",\"),function(t,e,i,s,n,r,a){var o,l=(e+\"\").split(\" \");for(a={},o=0;o<4;o++)a[c[o]]=l[o]=l[o]||l[(o-1)/2>>0];return s.parse(t,a,n,r)}}var ct=RegExp(ct+\")\",\"gi\"),pt=(s._setPluginRatio=function(t){this.plugin.setRatio(t);for(var e,i,s,n,r=this.data,a=r.proxy,o=r.firstMPT;o;)e=a[o.v],o.r?e=Math.round(e):e<1e-6&&-1e-6s;s++)n+=i[\"xn\"+s]+i[\"xs\"+(s+1)];i.e=n}}else i.e=i.s+i.xs0;o=o._next}},function(t,e,i,s,n){this.t=t,this.p=e,this.v=i,this.r=n,s&&((s._prev=this)._next=s)}),dt=(s._parseToProxy=function(t,e,i,s,n,r){var a,o,l,c,h=s,u={},p={},d=i._transform,_=V;for(i._transform=null,V=e,s=n=i.parse(t,e,s,n),V=_,r&&(i._transform=d,h&&(h._prev=null,h._prev&&(h._prev._next=null)));s&&s!==h;){if(s.type<=1&&(p[o=s.p]=s.s+s.c,u[o]=s.s,r||(c=new pt(s,\"s\",o,c,s.r),s.c=0),1===s.type))for(a=s.l;0<--a;)p[o=s.p+\"_\"+(l=\"xn\"+a)]=s.data[l],u[o]=s[l],r||(c=new pt(s,l,o,c,s.rxp[l]));s=s._next}return{proxy:u,end:p,firstMPT:c,pt:n}},s.CSSPropTween=function(t,e,i,s,n,r,a,o,l,c,h){this.t=t,this.p=e,this.s=i,this.c=s,this.n=a||e,t instanceof dt||u.push(this.n),this.r=o,this.type=r||0,l&&(this.pr=l,d=!0),this.b=void 0===c?i:c,this.e=void 0===h?i+s:h,n&&((this._next=n)._prev=this)}),_t=N.parseComplex=function(t,e,i,s,n,r,a,o,l,c){a=new dt(t,e,0,0,a,c?2:1,null,!1,o,i=i||r||\"\",s),s+=\"\";var h,u,p,d,_,f,m,g,v,w,y,x=i.split(\", \").join(\",\").split(\" \"),b=s.split(\", \").join(\",\").split(\" \"),T=x.length,k=!1!==O;for(-1===s.indexOf(\",\")&&-1===i.indexOf(\",\")||(x=x.join(\" \").replace(H,\", \").split(\" \"),b=b.join(\" \").replace(H,\", \").split(\" \"),T=x.length),T!==b.length&&(T=(x=(r||\"\").split(\" \")).length),a.plugin=l,a.setRatio=c,h=0;hu;u++)w=f[u],v=d.indexOf(w,p),a.appendXtra(d.substr(p,v-p),Number(w),P(m[u],w),\"\",k&&\"px\"===d.substr(v+w.length,2),0===u),p=v+w.length;a[\"xs\"+a.l]+=d.substr(p)}else a[\"xs\"+a.l]+=a.l?\" \"+d:d;if(-1!==s.indexOf(\"=\")&&a.data){for(y=a.xs0+a.data.s,h=1;a.l>h;h++)y+=a[\"xs\"+h]+a.data[\"xn\"+h];a.e=y+a[\"xs\"+h]}return a.l||(a.type=-1,a.xs0=a.e),a.xfirst||a},ft=9;for((t=dt.prototype).l=t.pr=0;0<--ft;)t[\"xn\"+ft]=0,t[\"xs\"+ft]=\"\";t.xs0=\"\",t._next=t._prev=t.xfirst=t.data=t.plugin=t.setRatio=t.rxp=null,t.appendXtra=function(t,e,i,s,n,r){var a=this,o=a.l;return a[\"xs\"+o]+=r&&o?\" \"+t:t||\"\",i||0===o||a.plugin?(a.l++,a.type=a.setRatio?2:1,a[\"xs\"+a.l]=s||\"\",0s;s++)e.prefix=0===s&&e.prefix,e.defaultValue=i[s]||r,new mt(n[s],e)};(t=mt.prototype).parseComplex=function(t,e,i,s,n,r){var a,o,l,c,h,u=this.keyword;if(this.multi&&(H.test(i)||H.test(e)?(o=e.replace(H,\"|\").split(\"|\"),l=i.replace(H,\"|\").split(\"|\")):u&&(o=[e],l=[i])),l){for(c=(l.length>o.length?l:o).length,a=0;aI[r]&&I[r]>-j&&(I[r]=0);return i&&(t._gsTransform=I),I},St=s.set3DTransformRatio=function(t){var e,i,s,n,r,a,o,l,c,h,u,p,d,_,f,m,g,v,w,y,x,b,T=this.data,k=this.t.style,P=T.rotation*U,S=T.scaleX,O=T.scaleY,C=T.scaleZ,A=T.perspective;if(1!==t&&0!==t||\"auto\"!==T.force3D||T.rotationY||T.rotationX||1!==C||A||T.z){if(M&&(S<1e-4&&-1e-4y;y++)this.p.indexOf(\"border\")&&(f[y]=T(f[y])),-1!==(o=a=st(t,f[y],b,!1,\"0px\")).indexOf(\" \")&&(o=(a=o.split(\" \"))[0],a=a[1]),l=r=w[y],d=parseFloat(o),_=o.substr((d+\"\").length),(h=\"\"===(h=(u=\"=\"===l.charAt(1))?(c=parseInt(l.charAt(0)+\"1\",10),l=l.substr(2),c*=parseFloat(l),l.substr((c+\"\").length-(c<0?1:0))||\"\"):(c=parseFloat(l),l.substr((c+\"\").length)))?x[i]||_:h)!==_&&(p=nt(t,\"borderLeft\",d,_),d=nt(t,\"borderTop\",d,_),a=\"%\"===h?(o=p/g*100+\"%\",d/v*100+\"%\"):\"em\"===h?(o=p/(_=nt(t,\"borderLeft\",1,\"em\"))+\"em\",d/_+\"em\"):(o=p+\"px\",d+\"px\"),u&&(l=parseFloat(o)+c+h,r=parseFloat(a)+c+h)),n=_t(m,f[y],o+\" \"+a,l+\" \"+r,!1,\"0px\",n);return n},prefix:!0,formatter:ht(\"0px 0px 0px 0px\",!1,!0)}),gt(\"backgroundPosition\",{defaultValue:\"0 0\",parser:function(t,e,i,s,n,r){var a,o,l,c,h,u,p=\"background-position\",d=b||it(t,null),_=this.format((d?C?d.getPropertyValue(p+\"-x\")+\" \"+d.getPropertyValue(p+\"-y\"):d.getPropertyValue(p):t.currentStyle.backgroundPositionX+\" \"+t.currentStyle.backgroundPositionY)||\"0 0\"),e=this.format(e);if(-1!==_.indexOf(\"%\")!=(-1!==e.indexOf(\"%\"))&&((u=st(t,\"backgroundImage\").replace(F,\"\"))&&\"none\"!==u)){for(a=_.split(\" \"),o=e.split(\" \"),G.setAttribute(\"src\",u),l=2;-1<--l;)(c=-1!==(_=a[l]).indexOf(\"%\"))!=(-1!==o[l].indexOf(\"%\"))&&(h=0===l?t.offsetWidth-G.width:t.offsetHeight-G.height,a[l]=c?parseFloat(_)/100*h+\"px\":parseFloat(_)/h*100+\"%\");_=a.join(\" \")}return this.parseComplex(t.style,_,e,n,r)},formatter:v}),gt(\"backgroundSize\",{defaultValue:\"0 0\",formatter:v}),gt(\"perspective\",{defaultValue:\"0px\",prefix:!0}),gt(\"perspectiveOrigin\",{defaultValue:\"50% 50%\",prefix:!0}),gt(\"transformStyle\",{prefix:!0}),gt(\"backfaceVisibility\",{prefix:!0}),gt(\"userSelect\",{prefix:!0}),gt(\"margin\",{parser:ut(\"marginTop,marginRight,marginBottom,marginLeft\")}),gt(\"padding\",{parser:ut(\"paddingTop,paddingRight,paddingBottom,paddingLeft\")}),gt(\"clip\",{defaultValue:\"rect(0px,0px,0px,0px)\",parser:function(t,e,i,s,n,r){var a,o;return e=C<9?(a=t.currentStyle,o=C<8?\" \":\",\",a=\"rect(\"+a.clipTop+o+a.clipRight+o+a.clipBottom+o+a.clipLeft+\")\",this.format(e).split(\",\").join(o)):(a=this.format(st(t,this.p,b,!1,this.dflt)),this.format(e)),this.parseComplex(t.style,a,e,n,r)}}),gt(\"textShadow\",{defaultValue:\"0px 0px 0px #999\",color:!0,multi:!0}),gt(\"autoRound,strictUnits\",{parser:function(t,e,i,s,n){return n}}),gt(\"border\",{defaultValue:\"0px solid #000\",parser:function(t,e,i,s,n,r){return this.parseComplex(t.style,this.format(st(t,\"borderTopWidth\",b,!1,\"0px\")+\" \"+st(t,\"borderTopStyle\",b,!1,\"solid\")+\" \"+st(t,\"borderTopColor\",b,!1,\"#000\")),this.format(e),n,r)},color:!0,formatter:function(t){var e=t.split(\" \");return e[0]+\" \"+(e[1]||\"solid\")+\" \"+(t.match(ct)||[\"#000\"])[0]}}),gt(\"borderWidth\",{parser:ut(\"borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth\")}),gt(\"float,cssFloat,styleFloat\",{parser:function(t,e,i,s,n){var r=t.style,t=\"cssFloat\"in r?\"cssFloat\":\"styleFloat\";return new dt(r,t,0,0,n,-1,i,!1,0,r[t],e)}});function Ct(t){var e,i=this.t,s=i.filter||st(this.data,\"filter\"),t=0|this.s+this.c*t;(e=100==t?-1===s.indexOf(\"atrix(\")&&-1===s.indexOf(\"radient(\")&&-1===s.indexOf(\"oader(\")?(i.removeAttribute(\"filter\"),!st(this.data,\"filter\")):(i.filter=s.replace(l,\"\"),!0):e)||(this.xn1&&(i.filter=s=s||\"alpha(opacity=\"+t+\")\"),-1===s.indexOf(\"pacity\")?0==t&&this.xn1||(i.filter=s+\" alpha(opacity=\"+t+\")\"):i.filter=s.replace(L,\"opacity=\"+t))}gt(\"opacity,alpha,autoAlpha\",{defaultValue:\"1\",parser:function(t,e,i,s,n,r){var a=parseFloat(st(t,\"opacity\",b,!1,\"1\")),o=t.style,l=\"autoAlpha\"===i;return\"string\"==typeof e&&\"=\"===e.charAt(1)&&(e=(\"-\"===e.charAt(0)?-1:1)*parseFloat(e.substr(2))+a),l&&1===a&&\"hidden\"===st(t,\"visibility\",b)&&0!==e&&(a=0),J?n=new dt(o,\"opacity\",a,e-a,n):((n=new dt(o,\"opacity\",100*a,100*(e-a),n)).xn1=l?1:0,o.zoom=1,n.type=2,n.b=\"alpha(opacity=\"+n.s+\")\",n.e=\"alpha(opacity=\"+(n.s+n.c)+\")\",n.data=t,n.plugin=r,n.setRatio=Ct),l&&((n=new dt(o,\"visibility\",0,0,n,-1,null,!1,0,0!==a?\"inherit\":\"hidden\",0===e?\"hidden\":\"inherit\")).xs0=\"inherit\",s._overwriteProps.push(n.n),s._overwriteProps.push(i)),n}});function At(t,e){e&&(t.removeProperty?(\"ms\"===e.substr(0,2)&&(e=\"M\"+e.substr(1)),t.removeProperty(e.replace(z,\"-$1\").toLowerCase())):t.removeAttribute(e))}function Mt(t){if(this.t._gsClassPT=this,1===t||0===t){this.t.setAttribute(\"class\",0===t?this.b:this.e);for(var e=this.data,i=this.t.style;e;)e.v?i[e.p]=e.v:At(i,e.p),e=e._next;1===t&&this.t._gsClassPT===this&&(this.t._gsClassPT=null)}else this.t.getAttribute(\"class\")!==this.e&&this.t.setAttribute(\"class\",this.e)}gt(\"className\",{parser:function(t,e,i,s,n,r,a){var o,l,c,h=t.getAttribute(\"class\")||\"\",u=t.style.cssText;if((n=s._classNamePT=new dt(t,i,0,0,n,2)).setRatio=Mt,n.pr=-11,d=!0,n.b=h,o=m(t,b),i=t._gsClassPT){for(l={},c=i.data;c;)l[c.p]=1,c=c._next;i.setRatio(1)}return(t._gsClassPT=n).e=\"=\"!==e.charAt(1)?e:h.replace(RegExp(\"\\\\s*\\\\b\"+e.substr(2)+\"\\\\b\"),\"\")+(\"+\"===e.charAt(0)?\" \"+e.substr(2):\"\"),s._tween._duration&&(t.setAttribute(\"class\",n.e),a=g(t,o,m(t),a,l),t.setAttribute(\"class\",h),n.data=a.firstMPT,t.style.cssText=u,n=n.xfirst=s.parse(t,a.difs,n,r)),n}});function Rt(t){if((1===t||0===t)&&this.data._totalTime===this.data._totalDuration&&\"isFromStart\"!==this.data.data){var e,i,s,n,r=this.t.style,a=_.transform.parse;if(\"all\"===this.e)n=!(r.cssText=\"\");else for(s=(e=this.e.split(\",\")).length;-1<--s;)i=e[s],_[i]&&(_[i].parse===a?n=!0:i=\"transformOrigin\"===i?bt:_[i].p),At(r,i);n&&(At(r,yt),this.t._gsTransform&&delete this.t._gsTransform)}}for(gt(\"clearProps\",{parser:function(t,e,i,s,n){return(n=new dt(t,i,0,0,n,2)).setRatio=Rt,n.e=e,n.pr=-10,n.data=s._tween,d=!0,n}}),t=\"bezier,throwProps,physicsProps,physics2D\".split(\",\"),ft=t.length;ft--;)!function(t){var l;_[t]||(l=t.charAt(0).toUpperCase()+t.substr(1)+\"Plugin\",gt(t,{parser:function(t,e,i,s,n,r,a){var o=(window.GreenSockGlobals||window).com.greensock.plugins[l];return o?(o._cssRegister(),_[i].parse(t,e,i,s,n,r,a)):(f(\"Error: \"+l+\" js file not loaded.\"),n)}}))}(t[ft]);(t=N.prototype)._firstPT=null,t._onInitTween=function(t,e,i){if(!t.nodeType)return!1;this._target=t,this._tween=i,this._vars=e,O=e.autoRound,d=!1,x=e.suffixMap||N.suffixMap,b=it(t,\"\"),u=this._overwriteProps;var s,n,r,a,o,l,i=t.style;if(c&&\"\"===i.zIndex&&(\"auto\"!==(l=st(t,\"zIndex\",b))&&\"\"!==l||this._addLazySet(i,\"zIndex\",0)),\"string\"==typeof e&&(r=i.cssText,l=m(t,b),i.cssText=r+\";\"+e,l=g(t,l,m(t)).difs,!J&&X.test(e)&&(l.opacity=parseFloat(RegExp.$1)),e=l,i.cssText=r),this._firstPT=s=this.parse(t,e,null),this._transformType){for(l=3===this._transformType,yt?h&&(c=!0,\"\"===i.zIndex&&(\"auto\"!==(e=st(t,\"zIndex\",b))&&\"\"!==e||this._addLazySet(i,\"zIndex\",0)),k&&this._addLazySet(i,\"WebkitBackfaceVisibility\",this._vars.WebkitBackfaceVisibility||(l?\"visible\":\"hidden\"))):i.zoom=1,n=s;n&&n._next;)n=n._next;i=new dt(t,\"transform\",0,0,null,2),this._linkCSSP(i,null,n),i.setRatio=l&&Tt?St:yt?Ot:vt,i.data=this._transform||Pt(t,b,!0),u.pop()}if(d){for(;s;){for(o=s._next,n=r;n&&n.pr>s.pr;)n=n._next;(s._prev=n?n._prev:a)?s._prev._next=s:r=s,(s._next=n)?n._prev=s:a=s,s=o}this._firstPT=r}return!0},t.parse=function(t,e,i,s){var n,r,a,o,l,c,h,u,p=t.style;for(n in e)l=e[n],u=_[n],u?i=u.parse(t,l,n,this,i,s,e):(o=st(t,n,b)+\"\",h=\"string\"==typeof l,\"color\"===n||\"fill\"===n||\"stroke\"===n||-1!==n.indexOf(\"Color\")||h&&E.test(l)?(h||(l=S(l),l=(3s;s++)i+=n[\"xn\"+s]+n[\"xs\"+(s+1)];n.t[n.p]=i}else-1===n.type?n.t[n.p]=n.xs0:n.setRatio&&n.setRatio(t);else n.t[n.p]=e+n.xs0;n=n._next}else for(;n;)2!==n.type?n.t[n.p]=n.b:n.setRatio(t),n=n._next;else for(;n;)2!==n.type?n.t[n.p]=n.e:n.setRatio(t),n=n._next},t._enableTransforms=function(t){this._transformType=t||3===this._transformType?3:2,this._transform=this._transform||Pt(this._target,b,!0)};function It(){this.t[this.p]=this.e,this.data._linkCSSP(this,this._next,null,!0)}t._addLazySet=function(t,e,i){e=this._firstPT=new dt(t,e,0,0,this._firstPT,2);e.e=i,e.setRatio=It,e.data=this},t._linkCSSP=function(t,e,i,s){return t&&(e&&(e._prev=t),t._next&&(t._next._prev=t._prev),t._prev?t._prev._next=t._next:this._firstPT===t&&(this._firstPT=t._next,s=!0),i?i._next=t:s||null!==this._firstPT||(this._firstPT=t),t._next=e,t._prev=i),t},t._kill=function(t){var e,i,s,n=t;if(t.autoAlpha||t.alpha){for(i in n={},t)n[i]=t[i];n.opacity=1,n.autoAlpha&&(n.visibility=1)}return t.className&&(e=this._classNamePT)&&((s=e.xfirst)&&s._prev?this._linkCSSP(s._prev,e._next,s._prev._prev):s===this._firstPT&&(this._firstPT=e._next),e._next&&this._linkCSSP(e._next,e._next._next,s._prev),this._classNamePT=null),r.prototype._kill.call(this,n)};function Dt(t,e,i){var s,n,r,a;if(t.slice)for(n=t.length;-1<--n;)Dt(t[n],e,i);else for(n=(s=t.childNodes).length;-1<--n;)a=(r=s[n]).type,r.style&&(e.push(m(r)),i&&i.push(r)),1!==a&&9!==a&&11!==a||!r.childNodes.length||Dt(r,e,i)}return N.cascadeTo=function(t,e,i){var s,n,r,a=p.to(t,e,i),o=[a],l=[],c=[],h=[],u=p._internals.reservedProps;for(t=a._targets||a.target,Dt(t,l,h),a.render(e,!0),Dt(t,c),a.render(0,!0),a._enabled(!0),s=h.length;-1<--s;)if((n=g(h[s],l[s],c[s])).firstMPT){for(r in n=n.difs,i)u[r]&&(n[r]=i[r]);o.push(p.to(h[s],e,n))}return o},r.activate([N]),N},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],13:[function(t,e,i){\"use strict\";(window._gsQueue||(window._gsQueue=[])).push(function(){function n(t,e){var i=\"x\"===e?\"Width\":\"Height\",s=\"scroll\"+i,n=\"client\"+i,e=document.body;return t===a||t===r||t===e?Math.max(r[s],e[s])-(a[\"inner\"+i]||Math.max(r[n],e[n])):t[s]-t[\"offset\"+i]}var r=document.documentElement,a=window,t=window._gsDefine.plugin({propName:\"scrollTo\",API:2,version:\"1.7.3\",init:function(t,e,i){return this._wdw=t===a,this._target=t,this._tween=i,this._autoKill=!1!==(e=\"object\"!=typeof e?{y:e}:e).autoKill,this.x=this.xPrev=this.getX(),this.y=this.yPrev=this.getY(),null!=e.x?(this._addTween(this,\"x\",this.x,\"max\"===e.x?n(t,\"x\"):e.x,\"scrollTo_x\",!0),this._overwriteProps.push(\"scrollTo_x\")):this.skipX=!0,null!=e.y?(this._addTween(this,\"y\",this.y,\"max\"===e.y?n(t,\"y\"):e.y,\"scrollTo_y\",!0),this._overwriteProps.push(\"scrollTo_y\")):this.skipY=!0,!0},set:function(t){this._super.setRatio.call(this,t);var e=this._wdw||!this.skipX?this.getX():this.xPrev,i=this._wdw||!this.skipY?this.getY():this.yPrev,s=i-this.yPrev,t=e-this.xPrev;this._autoKill&&(!this.skipX&&(7e&&(this.skipX=!0),!this.skipY&&(7i&&(this.skipY=!0),this.skipX&&this.skipY&&this._tween.kill()),this._wdw?a.scrollTo(this.skipX?e:this.x,this.skipY?i:this.y):(this.skipY||(this._target.scrollTop=this.y),this.skipX||(this._target.scrollLeft=this.x)),this.xPrev=this.x,this.yPrev=this.y}}),e=t.prototype;t.max=n,e.getX=function(){return this._wdw?null!=a.pageXOffset?a.pageXOffset:(null!=r.scrollLeft?r:document.body).scrollLeft:this._target.scrollLeft},e.getY=function(){return this._wdw?null!=a.pageYOffset?a.pageYOffset:(null!=r.scrollTop?r:document.body).scrollTop:this._target.scrollTop},e._kill=function(t){return t.scrollTo_x&&(this.skipX=!0),t.scrollTo_y&&(this.skipY=!0),this._super._kill.call(this,t)}}),window._gsDefine&&window._gsQueue.pop()()},{}]},{},[2]);"],"file":"wpr-admin.js"} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/wpr-admin.min.js b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.min.js new file mode 100644 index 000000000..6ea3a18e9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.min.js @@ -0,0 +1,2 @@ +!function s(n,r,a){function o(e,t){if(!r[e]){if(!n[e]){var i="function"==typeof require&&require;if(!t&&i)return i(e,!0);if(l)return l(e,!0);throw(t=new Error("Cannot find module '"+e+"'")).code="MODULE_NOT_FOUND",t}i=r[e]={exports:{}},n[e][0].call(i.exports,function(t){return o(n[e][1][t]||t)},i,i.exports,s,n,r,a)}return r[e].exports}for(var l="function"==typeof require&&require,t=0;t'+e.message+""):Object.keys(e).forEach(t=>{i.append(""+t+": "),i.append(e[t].message),i.append("
")})}})}),r("#wpr_enable_mobile_cache").on("click",function(t){t.preventDefault(),r("#wpr_enable_mobile_cache").addClass("wpr-isLoading"),r.post(ajaxurl,{action:"rocket_enable_mobile_cache",_ajax_nonce:rocket_ajax_data.nonce},function(t){t.success&&(r("#wpr_enable_mobile_cache").hide(),r("#wpr_mobile_cache_default").hide(),r("#wpr_mobile_cache_response").show(),r("#wpr_enable_mobile_cache").removeClass("wpr-isLoading"),r("#cache_mobile").val(1),r("#do_caching_mobile_files").val(1))})})})},{}],2:[function(t,e,i){"use strict";t("../lib/greensock/TweenLite.min.js"),t("../lib/greensock/TimelineLite.min.js"),t("../lib/greensock/easing/EasePack.min.js"),t("../lib/greensock/plugins/CSSPlugin.min.js"),t("../lib/greensock/plugins/ScrollToPlugin.min.js"),t("../global/pageManager.js"),t("../global/main.js"),t("../global/fields.js"),t("../global/beacon.js"),t("../global/ajax.js"),t("../global/rocketcdn.js"),t("../global/countdown.js")},{"../global/ajax.js":1,"../global/beacon.js":3,"../global/countdown.js":4,"../global/fields.js":5,"../global/main.js":6,"../global/pageManager.js":7,"../global/rocketcdn.js":8,"../lib/greensock/TimelineLite.min.js":9,"../lib/greensock/TweenLite.min.js":10,"../lib/greensock/easing/EasePack.min.js":11,"../lib/greensock/plugins/CSSPlugin.min.js":12,"../lib/greensock/plugins/ScrollToPlugin.min.js":13}],3:[function(t,e,i){"use strict";var s=jQuery;s(document).ready(function(){"Beacon"in window&&s(".wpr-infoAction--help").on("click",function(t){var e=s(this).data("beacon-id");return 0!==(e=(e=e).split(",")).length&&(1{o(t).attr("checked",i?null:"checked")}):(e=o(e).closest(".wpr-list").find(".wpr-main-checkbox"),s=o.map(n,t=>{if(void 0!==o(t).attr("checked"))return t}),e.attr("checked",s.length===n.length?"checked":null))}),0{var i=o(e).parents(".wpr-list").find(".wpr-list-body input[type=checkbox]:not(:checked)").length;o(e).attr("checked",i<=0?"checked":null)})})},{}],6:[function(t,e,i){"use strict";var c=jQuery;c(document).ready(function(){var t=c(".wpr-notice");c("#wpr-congratulations-notice").on("click",function(){return(new TimelineLite).to(t,1,{autoAlpha:0,x:40,ease:Power4.easeOut}).to(t,.6,{height:0,marginTop:0,ease:Power4.easeOut},"=-.4").set(t,{display:"none"}),!1}),c(".rocket-analytics-data-container").hide(),c(".rocket-preview-analytics-data").on("click",function(t){t.preventDefault(),c(this).parent().next(".rocket-analytics-data-container").toggle()}),c(".wpr-toggle-button").each(function(){var t=c(this),e=t.closest(".wpr-fieldsContainer-fieldset").find(".wpr-radio :checkbox"),i=c('[href="'+t.attr("href")+'"].wpr-menuItem');e.on("change",function(){e.is(":checked")?(i.css("display","block"),t.css("display","inline-block")):(i.css("display","none"),t.css("display","none"))}).trigger("change")});var e=c(".wpr-Popin-Analytics"),i=c(".wpr-Popin-overlay"),s=c(".wpr-Popin-Analytics-close"),n=c(".wpr-Popin-Analytics .wpr-button");function r(){(new TimelineLite).fromTo(e,.6,{autoAlpha:1,marginTop:0},{autoAlpha:0,marginTop:-24,ease:Power4.easeOut}).fromTo(i,.6,{autoAlpha:1},{autoAlpha:0,ease:Power4.easeOut},"=-.5").set(e,{display:"none"}).set(i,{display:"none"})}c(".wpr-js-popin").on("click",function(t){return t.preventDefault(),(new TimelineLite).set(e,{display:"block"}).set(i,{display:"block"}).fromTo(i,.6,{autoAlpha:0},{autoAlpha:1,ease:Power4.easeOut}).fromTo(e,.6,{autoAlpha:0,marginTop:-24},{autoAlpha:1,marginTop:0,ease:Power4.easeOut},"=-.5"),!1}),s.on("click",function(t){return t.preventDefault(),r(),!1}),n.on("click",function(t){return t.preventDefault(),r(),c("#analytics_enabled").prop("checked",!0),c("#analytics_enabled").trigger("change"),!1}),c("#analytics_enabled").on("change",function(){c(".wpr-rocket-analytics-cta").toggleClass("wpr-isHidden")});var a=c(".wpr-Popin-Upgrade"),s=c(".wpr-Popin-Upgrade-close");c(".wpr-popin-upgrade-toggle").on("click",function(t){return t.preventDefault(),(new TimelineLite).set(a,{display:"block"}).set(i,{display:"block"}).fromTo(i,.6,{autoAlpha:0},{autoAlpha:1,ease:Power4.easeOut}).fromTo(a,.6,{autoAlpha:0,marginTop:-24},{autoAlpha:1,marginTop:0,ease:Power4.easeOut},"=-.5"),!1}),s.on("click",function(){return(new TimelineLite).fromTo(a,.6,{autoAlpha:1,marginTop:0},{autoAlpha:0,marginTop:-24,ease:Power4.easeOut}).fromTo(i,.6,{autoAlpha:1},{autoAlpha:0,ease:Power4.easeOut},"=-.5").set(a,{display:"none"}).set(i,{display:"none"}),!1});var o=c(".wpr-Sidebar");c(".wpr-js-tips").on("change",function(){c(this).is(":checked")?(o.css("display","block"),localStorage.setItem("wpr-show-sidebar","on")):(o.css("display","none"),localStorage.setItem("wpr-show-sidebar","off"))}),document.getElementById("LKgOcCRpwmAj")?c(".wpr-adblock").css("display","none"):c(".wpr-adblock").css("display","block");var l=c(".wpr-adblock");c(".wpr-adblock-close").on("click",function(){return(new TimelineLite).to(l,1,{autoAlpha:0,x:40,ease:Power4.easeOut}).to(l,.4,{height:0,marginTop:0,ease:Power4.easeOut},"=-.4").set(l,{display:"none"}),!1})})},{}],7:[function(t,e,i){"use strict";function s(t){var e,i=this;this.$body=document.querySelector(".wpr-body"),this.$menuItems=document.querySelectorAll(".wpr-menuItem"),this.$submitButton=document.querySelector(".wpr-Content > form > #wpr-options-submit"),this.$pages=document.querySelectorAll(".wpr-Page"),this.$sidebar=document.querySelector(".wpr-Sidebar"),this.$content=document.querySelector(".wpr-Content"),this.$tips=document.querySelector(".wpr-Content-tips"),this.$links=document.querySelectorAll(".wpr-body a"),this.$menuItem=null,this.$page=null,this.pageId=null,this.bodyTop=0,this.buttonText=this.$submitButton.value,i.getBodyTop(),window.onhashchange=function(){i.detectID()},window.location.hash?(this.bodyTop=0,this.detectID()):(e=localStorage.getItem("wpr-hash"),this.bodyTop=0,e?(window.location.hash=e,this.detectID()):(this.$menuItems[0].classList.add("isActive"),localStorage.setItem("wpr-hash","dashboard"),window.location.hash="#dashboard"));for(var s=0;s{d.querySelectorAll(".wpr-rocketcdn-open").forEach(t=>{t.addEventListener("click",t=>{t.preventDefault()})});{var t="";const e=p((t+="action=rocketcdn_process_status")+"&nonce="+rocket_ajax_data.nonce);e.onreadystatechange=()=>{e.readyState===XMLHttpRequest.DONE&&200===e.status&&!0===JSON.parse(e.responseText).success&&MicroModal.show("wpr-rocketcdn-modal")}}MicroModal.init({disableScroll:!0})}),s.addEventListener("load",()=>{let t=d.querySelector("#wpr-rocketcdn-open-cta"),e=d.querySelector("#wpr-rocketcdn-close-cta"),i=d.querySelector("#wpr-rocketcdn-cta-small"),s=d.querySelector("#wpr-rocketcdn-cta");function n(t){var e="";return e+"action=toggle_rocketcdn_cta"+("&status="+t)+("&nonce="+rocket_ajax_data.nonce)}null!==t&&null!==i&&null!==s&&t.addEventListener("click",t=>{t.preventDefault(),i.classList.add("wpr-isHidden"),s.classList.remove("wpr-isHidden"),p(n("big"))}),null!==e&&null!==i&&null!==s&&e.addEventListener("click",t=>{t.preventDefault(),i.classList.remove("wpr-isHidden"),s.classList.add("wpr-isHidden"),p(n("small"))})}),s.onmessage=t=>{var i=rocket_ajax_data.origin_url;if(t.origin===i){(s=t.data).hasOwnProperty("cdnFrameHeight")&&(d.getElementById("rocketcdn-iframe").style.height=s.cdnFrameHeight+"px"),(s=t.data).hasOwnProperty("cdnFrameClose")&&(MicroModal.close("wpr-rocketcdn-modal"),s.hasOwnProperty("cdn_page_message"))&&-1!==["iframe-payment-success","iframe-unsubscribe-success"].indexOf(s.cdn_page_message)&&d.location.reload();{var s=t.data;var n=i;let e=d.querySelector("#rocketcdn-iframe").contentWindow;if(s.hasOwnProperty("rocketcdn_token")){var r="";const c=p(r+"action=save_rocketcdn_token"+("&value="+s.rocketcdn_token)+("&nonce="+rocket_ajax_data.nonce));c.onreadystatechange=()=>{var t;c.readyState===XMLHttpRequest.DONE&&200===c.status&&(t=JSON.parse(c.responseText),e.postMessage({success:t.success,data:t.data,rocketcdn:!0},n))}}else{r={process:"subscribe",message:"token_not_received"};e.postMessage({success:!1,data:r,rocketcdn:!0},n)}}(s=t.data).hasOwnProperty("rocketcdn_process")&&p(""+"action=rocketcdn_process_set"+("&status="+s.rocketcdn_process)+("&nonce="+rocket_ajax_data.nonce));{var s=t.data;var a=i;let e=d.querySelector("#rocketcdn-iframe").contentWindow;if(s.hasOwnProperty("rocketcdn_url")){var o="";const h=p(o+"action=rocketcdn_enable"+("&cdn_url="+s.rocketcdn_url)+("&nonce="+rocket_ajax_data.nonce));h.onreadystatechange=()=>{var t;h.readyState===XMLHttpRequest.DONE&&200===h.status&&(t=JSON.parse(h.responseText),e.postMessage({success:t.success,data:t.data,rocketcdn:!0},a))}}}{o=t.data;var l=i;let e=d.querySelector("#rocketcdn-iframe").contentWindow;if(o.hasOwnProperty("rocketcdn_disable")){o="";const u=p((o+="action=rocketcdn_disable")+("&nonce="+rocket_ajax_data.nonce));u.onreadystatechange=()=>{var t;u.readyState===XMLHttpRequest.DONE&&200===u.status&&(t=JSON.parse(u.responseText),e.postMessage({success:t.success,data:t.data,rocketcdn:!0},l))}}}(s=t.data).hasOwnProperty("rocketcdn_validate_token")&&s.hasOwnProperty("rocketcdn_validate_cname")&&p(""+"action=rocketcdn_validate_token_cname"+("&cdn_url="+s.rocketcdn_validate_cname)+("&cdn_token="+s.rocketcdn_validate_token)+("&nonce="+rocket_ajax_data.nonce))}}},{}],9:[function(t,e,i){"use strict";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine("TimelineLite",["core.Animation","core.SimpleTimeline","TweenLite"],function(h,u,p){function d(t){u.call(this,t),this._labels={},this.autoRemoveChildren=!0===this.vars.autoRemoveChildren,this.smoothChildTiming=!0===this.vars.smoothChildTiming,this._sortChildren=!0,this._onUpdate=this.vars.onUpdate;var e,i,s=this.vars;for(i in s)e=s[i],g(e)&&-1!==e.join("").indexOf("{self}")&&(s[i]=this._swapSelfInParams(e));g(s.tweens)&&this.add(s.tweens,0,s.align,s.stagger)}function _(t){var e,i={};for(e in t)i[e]=t[e];return i}function n(t,e,i,s){t._timeline.pause(t._startTime),e&&e.apply(s||t._timeline,i||v)}var f=1e-10,m=p._internals.isSelector,g=p._internals.isArray,v=[],a=window._gsDefine.globals,w=v.slice,t=d.prototype=new u;return d.version="1.12.1",t.constructor=d,t.kill()._gc=!1,t.to=function(t,e,i,s){var n=i.repeat&&a.TweenMax||p;return e?this.add(new n(t,e,i),s):this.set(t,i,s)},t.from=function(t,e,i,s){return this.add((i.repeat&&a.TweenMax||p).from(t,e,i),s)},t.fromTo=function(t,e,i,s,n){var r=s.repeat&&a.TweenMax||p;return e?this.add(r.fromTo(t,e,i,s),n):this.set(t,s,n)},t.staggerTo=function(t,e,i,s,n,r,a,o){var l,c=new d({onComplete:r,onCompleteParams:a,onCompleteScope:o,smoothChildTiming:this.smoothChildTiming});for("string"==typeof t&&(t=p.selector(t)||t),m(t)&&(t=w.call(t,0)),s=s||0,l=0;t.length>l;l++)i.startAt&&(i.startAt=_(i.startAt)),c.to(t[l],e,_(i),l*s);return this.add(c,n)},t.staggerFrom=function(t,e,i,s,n,r,a,o){return i.immediateRender=0!=i.immediateRender,i.runBackwards=!0,this.staggerTo(t,e,i,s,n,r,a,o)},t.staggerFromTo=function(t,e,i,s,n,r,a,o,l){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,this.staggerTo(t,e,s,n,r,a,o,l)},t.call=function(t,e,i,s){return this.add(p.delayedCall(0,t,e,i),s)},t.set=function(t,e,i){return i=this._parseTimeOrLabel(i,0,!0),null==e.immediateRender&&(e.immediateRender=i===this._time&&!this._paused),this.add(new p(t,0,e),i)},d.exportRoot=function(t,e){null==(t=t||{}).smoothChildTiming&&(t.smoothChildTiming=!0);var i,s,n=new d(t),t=n._timeline;for(null==e&&(e=!0),t._remove(n,!0),n._startTime=0,n._rawPrevTime=n._time=n._totalTime=t._time,i=t._first;i;)s=i._next,e&&i instanceof p&&i.target===i.vars.onComplete||n.add(i,i._startTime-i._delay),i=s;return t.add(n,0),n},t.add=function(t,e,i,s){var n,r,a,o,l,c;if("number"!=typeof e&&(e=this._parseTimeOrLabel(e,0,!0,t)),!(t instanceof h)){if(t instanceof Array||t&&t.push&&g(t)){for(i=i||"normal",s=s||0,n=e,r=t.length,a=0;at._startTime;l._timeline;)c&&l._timeline.smoothChildTiming?l.totalTime(l._totalTime,!0):l._gc&&l._enabled(!0,!1),l=l._timeline;return this},t.remove=function(t){if(t instanceof h)return this._remove(t,!1);if(t instanceof Array||t&&t.push&&g(t)){for(var e=t.length;-1<--e;)this.remove(t[e]);return this}return"string"==typeof t?this.removeLabel(t):this.kill(null,t)},t._remove=function(t,e){u.prototype._remove.call(this,t,e);t=this._last;return t?this._time>t._startTime+t._totalDuration/t._timeScale&&(this._time=this.duration(),this._totalTime=this._totalDuration):this._time=this._totalTime=this._duration=this._totalDuration=0,this},t.append=function(t,e){return this.add(t,this._parseTimeOrLabel(null,e,!0,t))},t.insert=t.insertMultiple=function(t,e,i,s){return this.add(t,e||0,i,s)},t.appendMultiple=function(t,e,i,s){return this.add(t,this._parseTimeOrLabel(null,e,!0,t),i,s)},t.addLabel=function(t,e){return this._labels[t]=this._parseTimeOrLabel(e),this},t.addPause=function(t,e,i,s){return this.call(n,["{self}",e,i,s],this,t)},t.removeLabel=function(t){return delete this._labels[t],this},t.getLabelTime=function(t){return null!=this._labels[t]?this._labels[t]:-1},t._parseTimeOrLabel=function(t,e,i,s){var n;if(s instanceof h&&s.timeline===this)this.remove(s);else if(s&&(s instanceof Array||s.push&&g(s)))for(n=s.length;-1<--n;)s[n]instanceof h&&s[n].timeline===this&&this.remove(s[n]);if("string"==typeof e)return this._parseTimeOrLabel(e,i&&"number"==typeof t&&null==this._labels[e]?t-this.duration():0,i);if(e=e||0,"string"!=typeof t||!isNaN(t)&&null==this._labels[t])null==t&&(t=this.duration());else{if(-1===(n=t.indexOf("=")))return null==this._labels[t]?i?this._labels[t]=this.duration()+e:e:this._labels[t]+e;e=parseInt(t.charAt(n-1)+"1",10)*Number(t.substr(n+1)),t=1f)&&(a="onReverseComplete")),this._rawPrevTime=this._duration||!e||t||this._rawPrevTime===t?t:f,t=l+1e-4):t<1e-7?(((this._totalTime=this._time=0)!==c||0===this._duration&&this._rawPrevTime!==f&&(0=c)for(s=this._first;s&&(r=s._next,!this._paused||p);)(s._active||s._startTime<=this._time&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=r;else for(s=this._last;s&&(r=s._prev,!this._paused||p);)(s._active||c>=s._startTime&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=r;this._onUpdate&&!e&&this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||v),!a||this._gc||h!==this._startTime&&u===this._timeScale||!(0===this._time||l>=this.totalDuration())||(n&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),e)||!this.vars[a]||this.vars[a].apply(this.vars[a+"Scope"]||this,this.vars[a+"Params"]||v)}},t._hasPausedChild=function(){for(var t=this._first;t;){if(t._paused||t instanceof d&&t._hasPausedChild())return!0;t=t._next}return!1},t.getChildren=function(t,e,i,s){s=s||-9999999999;for(var n=[],r=this._first,a=0;r;)s>r._startTime||(r instanceof p?!1!==e&&(n[a++]=r):(!1!==i&&(n[a++]=r),!1!==t&&(a=(n=n.concat(r.getChildren(!0,e,i))).length))),r=r._next;return n},t.getTweensOf=function(t,e){var i,s,n=this._gc,r=[],a=0;for(n&&this._enabled(!0,!0),s=(i=p.getTweensOf(t)).length;-1<--s;)(i[s].timeline===this||e&&this._contains(i[s]))&&(r[a++]=i[s]);return n&&this._enabled(!1,!0),r},t._contains=function(t){for(var e=t.timeline;e;){if(e===this)return!0;e=e.timeline}return!1},t.shiftChildren=function(t,e,i){i=i||0;for(var s,n=this._first,r=this._labels;n;)n._startTime>=i&&(n._startTime+=t),n=n._next;if(e)for(s in r)r[s]>=i&&(r[s]+=t);return this._uncache(!0)},t._kill=function(t,e){if(!t&&!e)return this._enabled(!1,!1);for(var i=e?this.getTweensOf(e):this.getChildren(!0,!0,!1),s=i.length,n=!1;-1<--s;)i[s]._kill(t,e)&&(n=!0);return n},t.clear=function(t){var e=this.getChildren(!1,!0,!0),i=e.length;for(this._time=this._totalTime=0;-1<--i;)e[i]._enabled(!1,!1);return!1!==t&&(this._labels={}),this._uncache(!0)},t.invalidate=function(){for(var t=this._first;t;)t.invalidate(),t=t._next;return this},t._enabled=function(t,e){if(t===this._gc)for(var i=this._first;i;)i._enabled(t,!0),i=i._next;return u.prototype._enabled.call(this,t,e)},t.duration=function(t){return arguments.length?(0!==this.duration()&&0!==t&&this.timeScale(this._duration/t),this):(this._dirty&&this.totalDuration(),this._duration)},t.totalDuration=function(t){if(arguments.length)return 0!==this.totalDuration()&&0!==t&&this.timeScale(this._totalDuration/t),this;if(this._dirty){for(var e,i,s=0,n=this._last,r=999999999999;n;)e=n._prev,n._dirty&&n.totalDuration(),n._startTime>r&&this._sortChildren&&!n._paused?this.add(n,n._startTime-n._delay):r=n._startTime,n._startTime<0&&!n._paused&&(s-=n._startTime,this._timeline.smoothChildTiming&&(this._startTime+=n._startTime/this._timeScale),this.shiftChildren(-n._startTime,!1,-9999999999),r=0),s<(i=n._startTime+n._totalDuration/n._timeScale)&&(s=i),n=e;this._duration=this._totalDuration=s,this._dirty=!1}return this._totalDuration},t.usesFrames=function(){for(var t=this._timeline;t._timeline;)t=t._timeline;return t===h._rootFramesTimeline},t.rawTime=function(){return this._paused?this._totalTime:(this._timeline.rawTime()-this._startTime)*this._timeScale},d},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],10:[function(X,p,E){"use strict";var e,z,_=window,d=_.GreenSockGlobals||_;if(!d.TweenLite){var f,N=function(t){for(var e=t.split("."),i=d,s=0;e.length>s;s++)i[e[s]]=i=i[e[s]]||{};return i},u=N("com.greensock"),m=1e-10,Y=[].slice,F=function(){},g=(e=Object.prototype.toString,z=e.call([]),function(t){return null!=t&&(t instanceof Array||"object"==typeof t&&!!t.push&&e.call(t)===z)}),v={},$=function(o,l,c,h){this.sc=v[o]?v[o].sc:[],(v[o]=this).gsClass=null,this.func=c;var u=[];this.check=function(t){for(var e,i,s,n,r=l.length,a=r;-1<--r;)(e=v[l[r]]||new $(l[r],[])).gsClass?(u[r]=e.gsClass,a--):t&&e.sc.push(this);if(0===a&&c)for(s=(i=("com.greensock."+o).split(".")).pop(),n=N(i.join("."))[s]=this.gsClass=c.apply(c,u),h&&(d[s]=n,"function"==typeof define&&define.amd?define((_.GreenSockAMDPath?_.GreenSockAMDPath+"/":"")+o.split(".").join("/"),[],function(){return n}):void 0!==p&&p.exports&&(p.exports=n)),r=0;this.sc.length>r;r++)this.sc[r].check()},this.check(!0)},s=_._gsDefine=function(t,e,i,s){return new $(t,e,i,s)},w=u._class=function(t,e,i){return e=e||function(){},s(t,[],function(){return e},i),e},B=(s.globals=d,[0,0,1,1]),y=[],h=w("easing.Ease",function(t,e,i,s){this._func=t,this._type=i||0,this._power=s||0,this._params=e?B.concat(e):B},!0),x=h.map={},t=h.register=function(t,e,i,s){for(var n,r,a,o,l=e.split(","),c=l.length,h=(i||"easeIn,easeOut,easeInOut").split(",");-1<--c;)for(r=l[c],n=s?w("easing."+r,null,!0):u.easing[r]||{},a=h.length;-1<--a;)o=h[a],x[r+"."+o]=x[o+r]=n[o]=t.getRatio?t:t[o]||new t},i=h.prototype;for(i._calcEnd=!1,i.getRatio=function(t){var e,i,s;return this._func?(this._params[0]=t,this._func.apply(null,this._params)):(s=1===(e=this._type)?1-t:2===e?t:t<.5?2*t:2*(1-t),1===(i=this._power)?s*=s:2===i?s*=s*s:3===i?s*=s*s*s:4===i&&(s*=s*s*s*s),1===e?1-s:2===e?s:t<.5?s/2:1-s/2)},r=(n=["Linear","Quad","Cubic","Quart","Quint,Strong"]).length;-1<--r;)i=n[r]+",Power"+r,t(new h(null,null,1,r),i,"easeOut",!0),t(new h(null,null,2,r),i,"easeIn"+(0===r?",easeNone":"")),t(new h(null,null,3,r),i,"easeInOut");x.linear=u.easing.Linear.easeIn,x.swing=u.easing.Quad.easeInOut;for(var n,q=w("events.EventDispatcher",function(t){this._listeners={},this._eventTarget=t||this}),b=((i=q.prototype).addEventListener=function(t,e,i,s,n){n=n||0;var r,a,o=this._listeners[t],l=0;for(null==o&&(this._listeners[t]=o=[]),a=o.length;-1<--a;)(r=o[a]).c===e&&r.s===i?o.splice(a,1):0===l&&n>r.pr&&(l=a+1);o.splice(l,0,{c:e,s:i,up:s,pr:n}),this!==S||f||S.wake()},i.removeEventListener=function(t,e){var i,s=this._listeners[t];if(s)for(i=s.length;-1<--i;)if(s[i].c===e)return void s.splice(i,1)},i.dispatchEvent=function(t){var e,i,s,n=this._listeners[t];if(n)for(e=n.length,i=this._eventTarget;-1<--e;)(s=n[e]).up?s.c.call(s.s||i,{type:t,target:i}):s.c.call(s.s||i)},_.requestAnimationFrame),T=_.cancelAnimationFrame,k=Date.now||function(){return(new Date).getTime()},P=k(),r=(n=["ms","moz","webkit","o"]).length;-1<--r&&!b;)b=_[n[r]+"RequestAnimationFrame"],T=_[n[r]+"CancelAnimationFrame"]||_[n[r]+"CancelRequestAnimationFrame"];w("Ticker",function(t,e){var s,n,r,a,o,l=this,c=k(),i=!1!==e&&b,h=500,u=33,p=function(t){var e,i=k()-P;h=e&&e+this.totalDuration()/this._timeScale>t},i._enabled=function(t,e){return f||S.wake(),this._gc=!t,this._active=this.isActive(),!0!==e&&(t&&!this.timeline?this._timeline.add(this,this._startTime-this._delay):!t&&this.timeline&&this._timeline._remove(this,!0)),!1},i._kill=function(){return this._enabled(!1,!1)},i.kill=function(t,e){return this._kill(t,e),this},i._uncache=function(t){for(var e=t?this:this.timeline;e;)e._dirty=!0,e=e.timeline;return this},i._swapSelfInParams=function(t){for(var e=t.length,i=t.concat();-1<--e;)"{self}"===t[e]&&(i[e]=this);return i},i.eventCallback=function(t,e,i,s){if("on"===(t||"").substr(0,2)){var n=this.vars;if(1===arguments.length)return n[t];null==e?delete n[t]:(n[t]=e,n[t+"Params"]=g(i)&&-1!==i.join("").indexOf("{self}")?this._swapSelfInParams(i):i,n[t+"Scope"]=s),"onUpdate"===t&&(this._onUpdate=e)}return this},i.delay=function(t){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+t-this._delay),this._delay=t,this):this._delay},i.duration=function(t){return arguments.length?(this._duration=this._totalDuration=t,this._uncache(!0),this._timeline.smoothChildTiming&&0this._duration?this._duration:t,e)):this._time},i.totalTime=function(t,e,i){if(f||S.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(t<0&&!i&&(t+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var s=this._totalDuration,n=this._timeline;if(ss;)i=i._prev;return i?(t._next=i._next,i._next=t):(t._next=this._first,this._first=t),t._next?t._next._prev=t:this._last=t,t._prev=i,this._timeline&&this._uncache(!0),this},i._remove=function(t,e){return t.timeline===this&&(e||t._enabled(!1,!0),t.timeline=null,t._prev?t._prev._next=t._next:this._first===t&&(this._first=t._next),t._next?t._next._prev=t._prev:this._last===t&&(this._last=t._prev),this._timeline)&&this._uncache(!0),this},i.render=function(t,e,i){var s,n=this._first;for(this._totalTime=this._time=this._rawPrevTime=t;n;)s=n._next,(n._active||t>=n._startTime&&!n._paused)&&(n._reversed?n.render((n._dirty?n.totalDuration():n._totalDuration)-(t-n._startTime)*n._timeScale,e,i):n.render((t-n._startTime)*n._timeScale,e,i)),n=s},i.rawTime=function(){return f||S.wake(),this._totalTime},w("TweenLite",function(t,e,i){if(o.call(this,e,i),this.render=O.prototype.render,null==t)throw"Cannot tween a null target.";this.target=t="string"==typeof t&&O.selector(t)||t;var s,n,r,i=t.jquery||t.length&&t!==_&&t[0]&&(t[0]===_||t[0].nodeType&&t[0].style&&!t.nodeType),a=this.vars.overwrite;if(this._overwrite=a=null==a?Q[O.defaultOverwrite]:"number"==typeof a?a>>0:Q[a],(i||t instanceof Array||t.push&&g(t))&&"number"!=typeof t[0])for(this._targets=r=Y.call(t,0),this._propLookup=[],this._siblings=[],s=0;r.length>s;s++)(n=r[s])?"string"!=typeof n?n.length&&n!==_&&n[0]&&(n[0]===_||n[0].nodeType&&n[0].style&&!n.nodeType)?(r.splice(s--,1),this._targets=r=r.concat(Y.call(n,0))):(this._siblings[s]=j(n,this,!1),1===a&&1=a._startTime&&a._startTime+a.totalDuration()/a._timeScale>c&&((p||!a._initted)&&c-a._startTime<=2e-10||(h[u++]=a)));for(d=u;-1<--d;)a=h[d],2===s&&a._kill(i,t)&&(r=!0),(2!==s||!a._firstPT&&a._initted)&&a._enabled(!1,!1)&&(r=!0)}return r},G=function(t,e,i){for(var s=t._timeline,n=s._timeScale,r=t._startTime;s._timeline;){if(r+=s._startTime,n*=s._timeScale,s._paused)return-100;s=s._timeline}return e<(r/=n)?r-e:i&&r===e||!t._initted&&r-e<2*m?m:(r+=t.totalDuration()/t._timeScale/n)>e+m?0:r-e-m},L=(i._init=function(){var t,e,i,s,n,r=this.vars,a=this._overwrittenProps,o=this._duration,l=!!r.immediateRender,c=r.ease;if(r.startAt){for(s in this._startAt&&(this._startAt.render(-1,!0),this._startAt.kill()),n={},r.startAt)n[s]=r.startAt[s];if(n.overwrite=!1,n.immediateRender=!0,n.lazy=l&&!1!==r.lazy,n.startAt=n.delay=null,this._startAt=O.to(this.target,0,n),l)if(0o.pr;)s=s._next;(o._prev=s?s._prev:r)?o._prev._next=o:n=o,(o._next=s)?s._prev=o:r=o,o=a}o=e._firstPT=n}for(;o;)o.pg&&"function"==typeof o.t[t]&&o.t[t]()&&(i=!0),o=o._next;return i},L.activate=function(t){for(var e=t.length;-1<--e;)t[e].API===L.API&&(R[(new t[e])._propName]=t[e]);return!0},s.plugin=function(t){if(!(t&&t.propName&&t.init&&t.API))throw"illegal plugin definition.";var e,i=t.propName,s=t.priority||0,n=t.overwriteProps,r={init:"_onInitTween",set:"setRatio",kill:"_kill",round:"_roundProps",initAll:"_onInitAllProps"},a=w("plugins."+i.charAt(0).toUpperCase()+i.substr(1)+"Plugin",function(){L.call(this,i,s),this._overwriteProps=n||[]},!0===t.global),o=a.prototype=new L(i);for(e in(o.constructor=a).API=t.API,r)"function"==typeof t[e]&&(o[r[e]]=t[e]);return a.version=t.version,L.activate([a]),a},n=_._gsQueue){for(r=0;n.length>r;r++)n[r]();for(i in v)v[i].func||_.console.log("GSAP encountered missing dependency: com.greensock."+i)}f=!1}},{}],11:[function(t,e,i){"use strict";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine("easing.Back",["easing.Ease"],function(m){function t(t,e){var i=(t=c("easing."+t,function(){},!0)).prototype=new m;return i.constructor=t,i.getRatio=e,t}function e(t,e,i,s){return e=c("easing."+t,{easeOut:new e,easeIn:new i,easeInOut:new s},!0),h(e,t),e}function g(t,e,i){this.t=t,this.v=e,i&&(((this.next=i).prev=this).c=i.v-e,this.gap=i.t-t)}function i(t,e){var i=c("easing."+t,function(t){this._p1=t||0===t?t:1.70158,this._p2=1.525*this._p1},!0);return(t=i.prototype=new m).constructor=i,t.getRatio=e,t.config=function(t){return new i(t)},i}var s,n,r=window.GreenSockGlobals||window,a=r.com.greensock,o=2*Math.PI,l=Math.PI/2,c=a._class,h=m.register||function(){},a=e("Back",i("BackOut",function(t){return--t*t*((this._p1+1)*t+this._p1)+1}),i("BackIn",function(t){return t*t*((this._p1+1)*t-this._p1)}),i("BackInOut",function(t){return(t*=2)<1?.5*t*t*((this._p2+1)*t-this._p2):.5*((t-=2)*t*((this._p2+1)*t+this._p2)+2)})),u=c("easing.SlowMo",function(t,e,i){e=e||0===e?e:.7,null==t?t=.7:1t?this._calcEnd?1-(t=1-t/this._p1)*t:e-(t=1-t/this._p1)*t*t*t*e:t>this._p3?this._calcEnd?1-(t=(t-this._p3)/this._p1)*t:e+(t-e)*(t=(t-this._p3)/this._p1)*t*t*t:this._calcEnd?1:e},u.ease=new u(.7,.7),p.config=u.config=function(t,e,i){return new u(t,e,i)},(p=(s=c("easing.SteppedEase",function(t){this._p1=1/(t=t||1),this._p2=t+1},!0)).prototype=new m).constructor=s,p.getRatio=function(t){return t<0?t=0:1<=t&&(t=.999999999),(this._p2*t>>0)*this._p1},p.config=s.config=function(t){return new s(t)},(p=(n=c("easing.RoughEase",function(t){for(var e,i,s,n,r,a,o=(t=t||{}).taper||"none",l=[],c=0,h=0|(t.points||20),u=h,p=!1!==t.randomize,d=!0===t.clamp,_=t.template instanceof m?t.template:null,f="number"==typeof t.strength?.4*t.strength:.4;-1<--u;)e=p?Math.random():1/h*u,i=_?_.getRatio(e):e,s="none"===o?f:"out"===o?(n=1-e)*n*f:"in"===o?e*e*f:.5*(n=e<.5?2*e:2*(1-e))*n*f,p?i+=Math.random()*s-.5*s:u%2?i+=.5*s:i-=.5*s,d&&(1e.t){for(;e.next&&t>=e.t;)e=e.next;e=e.prev}else for(;e.prev&&e.t>=t;)e=e.prev;return(this._prev=e).v+(t-e.t)/e.gap*e.c},p.config=function(t){return new n(t)},n.ease=new n,e("Bounce",t("BounceOut",function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}),t("BounceIn",function(t){return 1/2.75>(t=1-t)?1-7.5625*t*t:t<2/2.75?1-(7.5625*(t-=1.5/2.75)*t+.75):t<2.5/2.75?1-(7.5625*(t-=2.25/2.75)*t+.9375):1-(7.5625*(t-=2.625/2.75)*t+.984375)}),t("BounceInOut",function(t){var e=t<.5;return t=(t=e?1-2*t:2*t-1)<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375,e?.5*(1-t):.5*t+.5})),e("Circ",t("CircOut",function(t){return Math.sqrt(1- --t*t)}),t("CircIn",function(t){return-(Math.sqrt(1-t*t)-1)}),t("CircInOut",function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)})),e("Elastic",(p=function(t,e,i){var s=c("easing."+t,function(t,e){this._p1=t||1,this._p2=e||i,this._p3=this._p2/o*(Math.asin(1/this._p1)||0)},!0),t=s.prototype=new m;return t.constructor=s,t.getRatio=e,t.config=function(t,e){return new s(t,e)},s})("ElasticOut",function(t){return this._p1*Math.pow(2,-10*t)*Math.sin((t-this._p3)*o/this._p2)+1},.3),p("ElasticIn",function(t){return-(this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*o/this._p2))},.3),p("ElasticInOut",function(t){return(t*=2)<1?-.5*this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*o/this._p2):.5*this._p1*Math.pow(2,-10*--t)*Math.sin((t-this._p3)*o/this._p2)+1},.45)),e("Expo",t("ExpoOut",function(t){return 1-Math.pow(2,-10*t)}),t("ExpoIn",function(t){return Math.pow(2,10*(t-1))-.001}),t("ExpoInOut",function(t){return(t*=2)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*(t-1)))})),e("Sine",t("SineOut",function(t){return Math.sin(t*l)}),t("SineIn",function(t){return 1-Math.cos(t*l)}),t("SineInOut",function(t){return-.5*(Math.cos(Math.PI*t)-1)})),c("easing.EaseLookup",{find:function(t){return m.map[t]}},!0),h(r.SlowMo,"SlowMo","ease,"),h(n,"RoughEase","ease,"),h(s,"SteppedEase","ease,"),a},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],12:[function(t,e,i){"use strict";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine("plugins.CSSPlugin",["plugins.TweenPlugin","TweenLite"],function(r,p){function N(){r.call(this,"css"),this._overwriteProps.length=0,this.setRatio=N.prototype.setRatio}var d,x,b,u,_={},t=N.prototype=new r("css");(t.constructor=N).version="1.12.1",N.API=2,N.defaultTransformPerspective=0,N.defaultSkewType="compensated",N.suffixMap={top:t="px",right:t,bottom:t,left:t,width:t,height:t,fontSize:t,padding:t,margin:t,perspective:t,lineHeight:""};function a(t,e){return e.toUpperCase()}function o(t){return tt.test("string"==typeof t?t:(t.currentStyle||t.style).filter||"")?parseFloat(RegExp.$1)/100:1}function L(t){window.console&&console.log(t)}function T(t,e){var i,s,n=(e=e||O).style;if(void 0!==n[t])return t;for(t=t.charAt(0).toUpperCase()+t.substr(1),i=["O","Moz","ms","Ms","Webkit"],s=5;-1<--s&&void 0===n[i[s]+t];);return 0<=s?(ut="-"+(pt=3===s?"ms":i[s]).toLowerCase()+"-",pt+t):null}function f(t,e){var i,s={};if(e=e||m(t,null))if(i=e.length)for(;-1<--i;)s[e[i].replace(rt,a)]=e.getPropertyValue(e[i]);else for(i in e)s[i]=e[i];else if(e=t.currentStyle||t.style)for(i in e)"string"==typeof i&&void 0===s[i]&&(s[i.replace(rt,a)]=e[i]);return C||(s.opacity=o(t)),t=j(t,e,!1),s.rotation=t.rotation,s.skewX=t.skewX,s.scaleX=t.scaleX,s.scaleY=t.scaleY,s.x=t.x,s.y=t.y,q&&(s.z=t.z,s.rotationX=t.rotationX,s.rotationY=t.rotationY,s.scaleZ=t.scaleZ),s.filters&&delete s.filters,s}function X(t,e,i,s,n){var r,a,o,l={},c=t.style;for(a in i)"cssText"!==a&&"length"!==a&&isNaN(a)&&(e[a]!==(r=i[a])||n&&n[a])&&-1===a.indexOf("Origin")&&("number"==typeof r||"string"==typeof r)&&(l[a]="auto"!==r||"left"!==a&&"top"!==a?""!==r&&"auto"!==r&&"none"!==r||"string"!=typeof e[a]||""===e[a].replace(h,"")?r:0:dt(t,a),void 0!==c[a])&&(o=new vt(c,a,c[a],o));if(s)for(a in s)"className"!==a&&(l[a]=s[a]);return{difs:l,firstMPT:o}}function E(t,e){var i=(t=null!=t&&""!==t&&"auto"!==t&&"auto auto"!==t?t:"0 0").split(" "),s=-1!==t.indexOf("left")?"0%":-1!==t.indexOf("right")?"100%":i[0];return null==(t=-1!==t.indexOf("top")?"0%":-1!==t.indexOf("bottom")?"100%":i[1])?t="0":"center"===t&&(t="50%"),("center"===s||isNaN(parseFloat(s))&&-1===(s+"").indexOf("="))&&(s="50%"),e&&(e.oxp=-1!==s.indexOf("%"),e.oyp=-1!==t.indexOf("%"),e.oxr="="===s.charAt(1),e.oyr="="===t.charAt(1),e.ox=parseFloat(s.replace(h,"")),e.oy=parseFloat(t.replace(h,""))),s+" "+t+(2>16,255&t>>8,255&t]:(","===t.charAt(t.length-1)&&(t=t.substr(0,t.length-1)),M[t]||("#"===t.charAt(0)?(4===t.length&&(t="#"+(e=t.charAt(1))+e+(i=t.charAt(2))+i+(s=t.charAt(3))+s),[(t=parseInt(t.substr(1),16))>>16,255&t>>8,255&t]):("hsl"===t.substr(0,3)?(t=t.match(P),s=Number(t[0])%360/360,n=Number(t[1])/100,e=2*(r=Number(t[2])/100)-(i=r<=.5?r*(1+n):r+n-r*n),3a",!!(e=Z.getElementsByTagName("a")[0])&&/^0.55/.test(e.style.opacity)),ut="",pt="",m=y.defaultView?y.defaultView.getComputedStyle:function(){},$=N.getStyle=function(t,e,i,s,n){var r;return C||"opacity"!==e?(!s&&t.style[e]?r=t.style[e]:(i=i||m(t))?r=i[e]||i.getPropertyValue(e)||i.getPropertyValue(e.replace(nt,"-$1").toLowerCase()):t.currentStyle&&(r=t.currentStyle[e]),null==n||r&&"none"!==r&&"auto"!==r&&"auto auto"!==r?r:n):o(t)},A=i.convertToPixels=function(t,e,i,s,n){if("px"===s||!s)return i;if("auto"===s||!i)return 0;var r,a,o,l=ot.test(e),c=t,h=O.style,u=i<0;if(u&&(i=-i),"%"===s&&-1!==e.indexOf("border"))r=i/100*(l?t.clientWidth:t.clientHeight);else{if(h.cssText="border:0 solid red;position:"+$(t,"position")+";line-height:0;","%"!==s&&c.appendChild)h[l?"borderLeftWidth":"borderTopWidth"]=i+s;else{if(a=(c=t.parentNode||y.body)._gsCache,o=p.ticker.frame,a&&l&&a.time===o)return a.width*i/100;h[l?"width":"height"]=i+s}c.appendChild(O),r=parseFloat(O[l?"offsetWidth":"offsetHeight"]),c.removeChild(O),l&&"%"===s&&!1!==N.cacheWidths&&((a=c._gsCache=c._gsCache||{}).time=o,a.width=r/i*100),0!==r||n||(r=A(t,e,i,s,!0))}return u?-r:r},dt=i.calculateOffset=function(t,e,i){var s;return"absolute"!==$(t,"position",i)?0:(i=$(t,"margin"+(s="left"===e?"Left":"Top"),i),t["offset"+s]-(A(t,e,parseFloat(i),i.replace(J,""))||0))},_t={width:["Left","Right"],height:["Top","Bottom"]},ft=["marginLeft","marginRight","marginTop","marginBottom"],M={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},R="(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b";for(t in M)R+="|"+t+"\\b";function mt(t,e,r,a){var o,l,c,h,u,p,d,_;return null==t?function(t){return t}:(l=e?(t.match(R)||[""])[0]:"",c=t.split(l).join("").match(K)||[],h=t.substr(0,t.indexOf(c[0])),u=")"===t.charAt(t.length-1)?")":"",p=-1!==t.indexOf(" ")?" ":",",d=c.length,_=0s;s++)n[s]=o(n[s]);return n.join(",")}if(e=(t.match(R)||[l])[0],s=(i=t.split(e).join("").match(K)||[]).length,d>s--)for(;d>++s;)i[s]=r?i[0|(s-1)/2]:c[s];return h+i.join(p)+p+e+u+(-1!==t.indexOf("inset")?" inset":"")}:function(t){var e,i,s;if("number"==typeof t)t+=_;else if(a&&S.test(t)){for(i=t.replace(S,"|").split("|"),s=0;i.length>s;s++)i[s]=o(i[s]);return i.join(",")}if(s=(e=t.match(K)||[]).length,d>s--)for(;d>++s;)e[s]=r?e[0|(s-1)/2]:c[s];return h+e.join(p)+u}:function(t){return t})}function gt(c){return c=c.split(","),function(t,e,i,s,n,r,a){var o,l=(e+"").split(" ");for(a={},o=0;o<4;o++)a[c[o]]=l[o]=l[o]||l[(o-1)/2>>0];return s.parse(t,a,n,r)}}function vt(t,e,i,s,n){this.t=t,this.p=e,this.v=i,this.r=n,s&&((s._prev=this)._next=s)}var R=RegExp(R+")","gi"),I=(i._setPluginRatio=function(t){this.plugin.setRatio(t);for(var e,i,s,n,r=this.data,a=r.proxy,o=r.firstMPT;o;)e=a[o.v],o.r?e=Math.round(e):e<1e-6&&-1e-6s;s++)n+=i["xn"+s]+i["xs"+(s+1)];i.e=n}}else i.e=i.s+i.xs0;o=o._next}},i._parseToProxy=function(t,e,i,s,n,r){var a,o,l,c,h=s,u={},p={},d=i._transform,_=w;for(i._transform=null,w=e,s=t=i.parse(t,e,s,n),w=_,r&&(i._transform=d,h)&&(h._prev=null,h._prev)&&(h._prev._next=null);s&&s!==h;){if(s.type<=1&&(p[o=s.p]=s.s+s.c,u[o]=s.s,r||(c=new vt(s,"s",o,c,s.r),s.c=0),1===s.type))for(a=s.l;0<--a;)p[o=s.p+"_"+(l="xn"+a)]=s.data[l],u[o]=s[l],r||(c=new vt(s,l,o,c,s.rxp[l]));s=s._next}return{proxy:u,end:p,firstMPT:c,pt:t}},i.CSSPropTween=function(t,e,i,s,n,r,a,o,l,c,h){this.t=t,this.p=e,this.s=i,this.c=s,this.n=a||e,t instanceof I||u.push(this.n),this.r=o,this.type=r||0,l&&(this.pr=l,d=!0),this.b=void 0===c?i:c,this.e=void 0===h?i+s:h,n&&((this._next=n)._prev=this)}),wt=N.parseComplex=function(t,e,i,s,n,r,a,o,l,c){a=new I(t,e,0,0,a,c?2:1,null,!1,o,i=i||r||"",s),s+="";var h,u,p,d,_,f,m,g,v,w,y,x=i.split(", ").join(",").split(" "),b=s.split(", ").join(",").split(" "),T=x.length,k=!1!==U;for(-1===s.indexOf(",")&&-1===i.indexOf(",")||(x=x.join(" ").replace(S,", ").split(" "),b=b.join(" ").replace(S,", ").split(" "),T=x.length),T!==b.length&&(T=(x=(r||"").split(" ")).length),a.plugin=l,a.setRatio=c,h=0;hu;u++)w=f[u],v=d.indexOf(w,p),a.appendXtra(d.substr(p,v-p),Number(w),z(m[u],w),"",k&&"px"===d.substr(v+w.length,2),0===u),p=v+w.length;a["xs"+a.l]+=d.substr(p)}else a["xs"+a.l]+=a.l?" "+d:d;if(-1!==s.indexOf("=")&&a.data){for(y=a.xs0+a.data.s,h=1;a.l>h;h++)y+=a["xs"+h]+a.data["xn"+h];a.e=y+a["xs"+h]}return a.l||(a.type=-1,a.xs0=a.e),a.xfirst||a},D=9;for((t=I.prototype).l=t.pr=0;0<--D;)t["xn"+D]=0,t["xs"+D]="";t.xs0="",t._next=t._prev=t.xfirst=t.data=t.plugin=t.setRatio=t.rxp=null,t.appendXtra=function(t,e,i,s,n,r){var a=this,o=a.l;return a["xs"+o]+=r&&o?" "+t:t||"",i||0===o||a.plugin?(a.l++,a.type=a.setRatio?2:1,a["xs"+a.l]=s||"",0s;s++)e.prefix=0===s&&e.prefix,e.defaultValue=i[s]||r,new yt(n[s],e)},St=((t=yt.prototype).parseComplex=function(t,e,i,s,n,r){var a,o,l,c,h,u=this.keyword;if(this.multi&&(S.test(i)||S.test(e)?(o=e.replace(S,"|").split("|"),l=i.replace(S,"|").split("|")):u&&(o=[e],l=[i])),l){for(c=(l.length>o.length?l:o).length,a=0;aR[r]&&R[r]>-I&&(R[r]=0);return i&&(t._gsTransform=R),R},Mt=i.set3DTransformRatio=function(t){var e,i,s,n,r,a,o,l,c,h,u,p,d,_,f,m,g,v,w,y,x,b,T=this.data,k=this.t.style,P=T.rotation*Y,S=T.scaleX,O=T.scaleY,C=T.scaleZ,A=T.perspective;if(1!==t&&0!==t||"auto"!==T.force3D||T.rotationY||T.rotationX||1!==C||A||T.z){if(V&&(S<1e-4&&-1e-4s.pr;)n=n._next;(s._prev=n?n._prev:a)?s._prev._next=s:r=s,(s._next=n)?n._prev=s:a=s,s=o}this._firstPT=r}return!0},t.parse=function(t,e,i,s){var n,r,a,o,l,c,h,u,p=t.style;for(n in e)l=e[n],o=_[n],o?i=o.parse(t,l,n,this,i,s,e):(o=$(t,n,b)+"",h="string"==typeof l,"color"===n||"fill"===n||"stroke"===n||-1!==n.indexOf("Color")||h&&st.test(l)?(h||(l=H(l),l=(3s;s++)i+=n["xn"+s]+n["xs"+(s+1)];n.t[n.p]=i}else-1===n.type?n.t[n.p]=n.xs0:n.setRatio&&n.setRatio(t);else n.t[n.p]=e+n.xs0;n=n._next}else for(;n;)2!==n.type?n.t[n.p]=n.b:n.setRatio(t),n=n._next;else for(;n;)2!==n.type?n.t[n.p]=n.e:n.setRatio(t),n=n._next},t._enableTransforms=function(t){this._transformType=t||3===this._transformType?3:2,this._transform=this._transform||j(this._target,b,!0)};function It(){this.t[this.p]=this.e,this.data._linkCSSP(this,this._next,null,!0)}function Dt(t,e,i){var s,n,r,a;if(t.slice)for(n=t.length;-1<--n;)Dt(t[n],e,i);else for(n=(s=t.childNodes).length;-1<--n;)a=(r=s[n]).type,r.style&&(e.push(f(r)),i)&&i.push(r),1!==a&&9!==a&&11!==a||!r.childNodes.length||Dt(r,e,i)}t._addLazySet=function(t,e,i){t=this._firstPT=new I(t,e,0,0,this._firstPT,2);t.e=i,t.setRatio=It,t.data=this},t._linkCSSP=function(t,e,i,s){return t&&(e&&(e._prev=t),t._next&&(t._next._prev=t._prev),t._prev?t._prev._next=t._next:this._firstPT===t&&(this._firstPT=t._next,s=!0),i?i._next=t:s||null!==this._firstPT||(this._firstPT=t),t._next=e,t._prev=i),t},t._kill=function(t){var e,i,s,n=t;if(t.autoAlpha||t.alpha){for(i in n={},t)n[i]=t[i];n.opacity=1,n.autoAlpha&&(n.visibility=1)}return t.className&&(e=this._classNamePT)&&((s=e.xfirst)&&s._prev?this._linkCSSP(s._prev,e._next,s._prev._prev):s===this._firstPT&&(this._firstPT=e._next),e._next&&this._linkCSSP(e._next,e._next._next,s._prev),this._classNamePT=null),r.prototype._kill.call(this,n)};return N.cascadeTo=function(t,e,i){var s,n,r,a=p.to(t,e,i),o=[a],l=[],c=[],h=[],u=p._internals.reservedProps;for(t=a._targets||a.target,Dt(t,l,h),a.render(e,!0),Dt(t,c),a.render(0,!0),a._enabled(!0),s=h.length;-1<--s;)if((n=X(h[s],l[s],c[s])).firstMPT){for(r in n=n.difs,i)u[r]&&(n[r]=i[r]);o.push(p.to(h[s],e,n))}return o},r.activate([N]),N},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],13:[function(t,e,i){"use strict";(window._gsQueue||(window._gsQueue=[])).push(function(){function n(t,e){var i="scroll"+(e="x"===e?"Width":"Height"),s="client"+e,n=document.body;return t===a||t===r||t===n?Math.max(r[i],n[i])-(a["inner"+e]||Math.max(r[s],n[s])):t[i]-t["offset"+e]}var r=document.documentElement,a=window,t=window._gsDefine.plugin({propName:"scrollTo",API:2,version:"1.7.3",init:function(t,e,i){return this._wdw=t===a,this._target=t,this._tween=i,this._autoKill=!1!==(e="object"!=typeof e?{y:e}:e).autoKill,this.x=this.xPrev=this.getX(),this.y=this.yPrev=this.getY(),null!=e.x?(this._addTween(this,"x",this.x,"max"===e.x?n(t,"x"):e.x,"scrollTo_x",!0),this._overwriteProps.push("scrollTo_x")):this.skipX=!0,null!=e.y?(this._addTween(this,"y",this.y,"max"===e.y?n(t,"y"):e.y,"scrollTo_y",!0),this._overwriteProps.push("scrollTo_y")):this.skipY=!0,!0},set:function(t){this._super.setRatio.call(this,t);var t=this._wdw||!this.skipX?this.getX():this.xPrev,e=this._wdw||!this.skipY?this.getY():this.yPrev,i=e-this.yPrev,s=t-this.xPrev;this._autoKill&&(!this.skipX&&(7t&&(this.skipX=!0),!this.skipY&&(7e&&(this.skipY=!0),this.skipX)&&this.skipY&&this._tween.kill(),this._wdw?a.scrollTo(this.skipX?t:this.x,this.skipY?e:this.y):(this.skipY||(this._target.scrollTop=this.y),this.skipX||(this._target.scrollLeft=this.x)),this.xPrev=this.x,this.yPrev=this.y}}),e=t.prototype;t.max=n,e.getX=function(){return this._wdw?null!=a.pageXOffset?a.pageXOffset:(null!=r.scrollLeft?r:document.body).scrollLeft:this._target.scrollLeft},e.getY=function(){return this._wdw?null!=a.pageYOffset?a.pageYOffset:(null!=r.scrollTop?r:document.body).scrollTop:this._target.scrollTop},e._kill=function(t){return t.scrollTo_x&&(this.skipX=!0),t.scrollTo_y&&(this.skipY=!0),this._super._kill.call(this,t)}}),window._gsDefine&&window._gsQueue.pop()()},{}]},{},[2]); +//# sourceMappingURL=wpr-admin.min.js.map diff --git a/wp-content/plugins/wp-rocket/assets/js/wpr-admin.min.js.map b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.min.js.map new file mode 100644 index 000000000..4a1a83d9a --- /dev/null +++ b/wp-content/plugins/wp-rocket/assets/js/wpr-admin.min.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"mappings":"","sources":["wpr-admin.min.js"],"sourcesContent":["!function s(n,r,a){function o(e,t){if(!r[e]){if(!n[e]){var i=\"function\"==typeof require&&require;if(!t&&i)return i(e,!0);if(l)return l(e,!0);throw(t=new Error(\"Cannot find module '\"+e+\"'\")).code=\"MODULE_NOT_FOUND\",t}i=r[e]={exports:{}},n[e][0].call(i.exports,function(t){return o(n[e][1][t]||t)},i,i.exports,s,n,r,a)}return r[e].exports}for(var l=\"function\"==typeof require&&require,t=0;t'+e.message+\"\"):Object.keys(e).forEach(t=>{i.append(\"\"+t+\": \"),i.append(e[t].message),i.append(\"
\")})}})}),r(\"#wpr_enable_mobile_cache\").on(\"click\",function(t){t.preventDefault(),r(\"#wpr_enable_mobile_cache\").addClass(\"wpr-isLoading\"),r.post(ajaxurl,{action:\"rocket_enable_mobile_cache\",_ajax_nonce:rocket_ajax_data.nonce},function(t){t.success&&(r(\"#wpr_enable_mobile_cache\").hide(),r(\"#wpr_mobile_cache_default\").hide(),r(\"#wpr_mobile_cache_response\").show(),r(\"#wpr_enable_mobile_cache\").removeClass(\"wpr-isLoading\"),r(\"#cache_mobile\").val(1),r(\"#do_caching_mobile_files\").val(1))})})})},{}],2:[function(t,e,i){\"use strict\";t(\"../lib/greensock/TweenLite.min.js\"),t(\"../lib/greensock/TimelineLite.min.js\"),t(\"../lib/greensock/easing/EasePack.min.js\"),t(\"../lib/greensock/plugins/CSSPlugin.min.js\"),t(\"../lib/greensock/plugins/ScrollToPlugin.min.js\"),t(\"../global/pageManager.js\"),t(\"../global/main.js\"),t(\"../global/fields.js\"),t(\"../global/beacon.js\"),t(\"../global/ajax.js\"),t(\"../global/rocketcdn.js\"),t(\"../global/countdown.js\")},{\"../global/ajax.js\":1,\"../global/beacon.js\":3,\"../global/countdown.js\":4,\"../global/fields.js\":5,\"../global/main.js\":6,\"../global/pageManager.js\":7,\"../global/rocketcdn.js\":8,\"../lib/greensock/TimelineLite.min.js\":9,\"../lib/greensock/TweenLite.min.js\":10,\"../lib/greensock/easing/EasePack.min.js\":11,\"../lib/greensock/plugins/CSSPlugin.min.js\":12,\"../lib/greensock/plugins/ScrollToPlugin.min.js\":13}],3:[function(t,e,i){\"use strict\";var s=jQuery;s(document).ready(function(){\"Beacon\"in window&&s(\".wpr-infoAction--help\").on(\"click\",function(t){var e=s(this).data(\"beacon-id\");return 0!==(e=(e=e).split(\",\")).length&&(1{o(t).attr(\"checked\",i?null:\"checked\")}):(e=o(e).closest(\".wpr-list\").find(\".wpr-main-checkbox\"),s=o.map(n,t=>{if(void 0!==o(t).attr(\"checked\"))return t}),e.attr(\"checked\",s.length===n.length?\"checked\":null))}),0{var i=o(e).parents(\".wpr-list\").find(\".wpr-list-body input[type=checkbox]:not(:checked)\").length;o(e).attr(\"checked\",i<=0?\"checked\":null)})})},{}],6:[function(t,e,i){\"use strict\";var c=jQuery;c(document).ready(function(){var t=c(\".wpr-notice\");c(\"#wpr-congratulations-notice\").on(\"click\",function(){return(new TimelineLite).to(t,1,{autoAlpha:0,x:40,ease:Power4.easeOut}).to(t,.6,{height:0,marginTop:0,ease:Power4.easeOut},\"=-.4\").set(t,{display:\"none\"}),!1}),c(\".rocket-analytics-data-container\").hide(),c(\".rocket-preview-analytics-data\").on(\"click\",function(t){t.preventDefault(),c(this).parent().next(\".rocket-analytics-data-container\").toggle()}),c(\".wpr-toggle-button\").each(function(){var t=c(this),e=t.closest(\".wpr-fieldsContainer-fieldset\").find(\".wpr-radio :checkbox\"),i=c('[href=\"'+t.attr(\"href\")+'\"].wpr-menuItem');e.on(\"change\",function(){e.is(\":checked\")?(i.css(\"display\",\"block\"),t.css(\"display\",\"inline-block\")):(i.css(\"display\",\"none\"),t.css(\"display\",\"none\"))}).trigger(\"change\")});var e=c(\".wpr-Popin-Analytics\"),i=c(\".wpr-Popin-overlay\"),s=c(\".wpr-Popin-Analytics-close\"),n=c(\".wpr-Popin-Analytics .wpr-button\");function r(){(new TimelineLite).fromTo(e,.6,{autoAlpha:1,marginTop:0},{autoAlpha:0,marginTop:-24,ease:Power4.easeOut}).fromTo(i,.6,{autoAlpha:1},{autoAlpha:0,ease:Power4.easeOut},\"=-.5\").set(e,{display:\"none\"}).set(i,{display:\"none\"})}c(\".wpr-js-popin\").on(\"click\",function(t){return t.preventDefault(),(new TimelineLite).set(e,{display:\"block\"}).set(i,{display:\"block\"}).fromTo(i,.6,{autoAlpha:0},{autoAlpha:1,ease:Power4.easeOut}).fromTo(e,.6,{autoAlpha:0,marginTop:-24},{autoAlpha:1,marginTop:0,ease:Power4.easeOut},\"=-.5\"),!1}),s.on(\"click\",function(t){return t.preventDefault(),r(),!1}),n.on(\"click\",function(t){return t.preventDefault(),r(),c(\"#analytics_enabled\").prop(\"checked\",!0),c(\"#analytics_enabled\").trigger(\"change\"),!1}),c(\"#analytics_enabled\").on(\"change\",function(){c(\".wpr-rocket-analytics-cta\").toggleClass(\"wpr-isHidden\")});var a=c(\".wpr-Popin-Upgrade\"),s=c(\".wpr-Popin-Upgrade-close\");c(\".wpr-popin-upgrade-toggle\").on(\"click\",function(t){return t.preventDefault(),(new TimelineLite).set(a,{display:\"block\"}).set(i,{display:\"block\"}).fromTo(i,.6,{autoAlpha:0},{autoAlpha:1,ease:Power4.easeOut}).fromTo(a,.6,{autoAlpha:0,marginTop:-24},{autoAlpha:1,marginTop:0,ease:Power4.easeOut},\"=-.5\"),!1}),s.on(\"click\",function(){return(new TimelineLite).fromTo(a,.6,{autoAlpha:1,marginTop:0},{autoAlpha:0,marginTop:-24,ease:Power4.easeOut}).fromTo(i,.6,{autoAlpha:1},{autoAlpha:0,ease:Power4.easeOut},\"=-.5\").set(a,{display:\"none\"}).set(i,{display:\"none\"}),!1});var o=c(\".wpr-Sidebar\");c(\".wpr-js-tips\").on(\"change\",function(){c(this).is(\":checked\")?(o.css(\"display\",\"block\"),localStorage.setItem(\"wpr-show-sidebar\",\"on\")):(o.css(\"display\",\"none\"),localStorage.setItem(\"wpr-show-sidebar\",\"off\"))}),document.getElementById(\"LKgOcCRpwmAj\")?c(\".wpr-adblock\").css(\"display\",\"none\"):c(\".wpr-adblock\").css(\"display\",\"block\");var l=c(\".wpr-adblock\");c(\".wpr-adblock-close\").on(\"click\",function(){return(new TimelineLite).to(l,1,{autoAlpha:0,x:40,ease:Power4.easeOut}).to(l,.4,{height:0,marginTop:0,ease:Power4.easeOut},\"=-.4\").set(l,{display:\"none\"}),!1})})},{}],7:[function(t,e,i){\"use strict\";function s(t){var e,i=this;this.$body=document.querySelector(\".wpr-body\"),this.$menuItems=document.querySelectorAll(\".wpr-menuItem\"),this.$submitButton=document.querySelector(\".wpr-Content > form > #wpr-options-submit\"),this.$pages=document.querySelectorAll(\".wpr-Page\"),this.$sidebar=document.querySelector(\".wpr-Sidebar\"),this.$content=document.querySelector(\".wpr-Content\"),this.$tips=document.querySelector(\".wpr-Content-tips\"),this.$links=document.querySelectorAll(\".wpr-body a\"),this.$menuItem=null,this.$page=null,this.pageId=null,this.bodyTop=0,this.buttonText=this.$submitButton.value,i.getBodyTop(),window.onhashchange=function(){i.detectID()},window.location.hash?(this.bodyTop=0,this.detectID()):(e=localStorage.getItem(\"wpr-hash\"),this.bodyTop=0,e?(window.location.hash=e,this.detectID()):(this.$menuItems[0].classList.add(\"isActive\"),localStorage.setItem(\"wpr-hash\",\"dashboard\"),window.location.hash=\"#dashboard\"));for(var s=0;s{d.querySelectorAll(\".wpr-rocketcdn-open\").forEach(t=>{t.addEventListener(\"click\",t=>{t.preventDefault()})});{var t=\"\";const e=p((t+=\"action=rocketcdn_process_status\")+\"&nonce=\"+rocket_ajax_data.nonce);e.onreadystatechange=()=>{e.readyState===XMLHttpRequest.DONE&&200===e.status&&!0===JSON.parse(e.responseText).success&&MicroModal.show(\"wpr-rocketcdn-modal\")}}MicroModal.init({disableScroll:!0})}),s.addEventListener(\"load\",()=>{let t=d.querySelector(\"#wpr-rocketcdn-open-cta\"),e=d.querySelector(\"#wpr-rocketcdn-close-cta\"),i=d.querySelector(\"#wpr-rocketcdn-cta-small\"),s=d.querySelector(\"#wpr-rocketcdn-cta\");function n(t){var e=\"\";return e+\"action=toggle_rocketcdn_cta\"+(\"&status=\"+t)+(\"&nonce=\"+rocket_ajax_data.nonce)}null!==t&&null!==i&&null!==s&&t.addEventListener(\"click\",t=>{t.preventDefault(),i.classList.add(\"wpr-isHidden\"),s.classList.remove(\"wpr-isHidden\"),p(n(\"big\"))}),null!==e&&null!==i&&null!==s&&e.addEventListener(\"click\",t=>{t.preventDefault(),i.classList.remove(\"wpr-isHidden\"),s.classList.add(\"wpr-isHidden\"),p(n(\"small\"))})}),s.onmessage=t=>{var i=rocket_ajax_data.origin_url;if(t.origin===i){(s=t.data).hasOwnProperty(\"cdnFrameHeight\")&&(d.getElementById(\"rocketcdn-iframe\").style.height=s.cdnFrameHeight+\"px\"),(s=t.data).hasOwnProperty(\"cdnFrameClose\")&&(MicroModal.close(\"wpr-rocketcdn-modal\"),s.hasOwnProperty(\"cdn_page_message\"))&&-1!==[\"iframe-payment-success\",\"iframe-unsubscribe-success\"].indexOf(s.cdn_page_message)&&d.location.reload();{var s=t.data;var n=i;let e=d.querySelector(\"#rocketcdn-iframe\").contentWindow;if(s.hasOwnProperty(\"rocketcdn_token\")){var r=\"\";const c=p(r+\"action=save_rocketcdn_token\"+(\"&value=\"+s.rocketcdn_token)+(\"&nonce=\"+rocket_ajax_data.nonce));c.onreadystatechange=()=>{var t;c.readyState===XMLHttpRequest.DONE&&200===c.status&&(t=JSON.parse(c.responseText),e.postMessage({success:t.success,data:t.data,rocketcdn:!0},n))}}else{r={process:\"subscribe\",message:\"token_not_received\"};e.postMessage({success:!1,data:r,rocketcdn:!0},n)}}(s=t.data).hasOwnProperty(\"rocketcdn_process\")&&p(\"\"+\"action=rocketcdn_process_set\"+(\"&status=\"+s.rocketcdn_process)+(\"&nonce=\"+rocket_ajax_data.nonce));{var s=t.data;var a=i;let e=d.querySelector(\"#rocketcdn-iframe\").contentWindow;if(s.hasOwnProperty(\"rocketcdn_url\")){var o=\"\";const h=p(o+\"action=rocketcdn_enable\"+(\"&cdn_url=\"+s.rocketcdn_url)+(\"&nonce=\"+rocket_ajax_data.nonce));h.onreadystatechange=()=>{var t;h.readyState===XMLHttpRequest.DONE&&200===h.status&&(t=JSON.parse(h.responseText),e.postMessage({success:t.success,data:t.data,rocketcdn:!0},a))}}}{o=t.data;var l=i;let e=d.querySelector(\"#rocketcdn-iframe\").contentWindow;if(o.hasOwnProperty(\"rocketcdn_disable\")){o=\"\";const u=p((o+=\"action=rocketcdn_disable\")+(\"&nonce=\"+rocket_ajax_data.nonce));u.onreadystatechange=()=>{var t;u.readyState===XMLHttpRequest.DONE&&200===u.status&&(t=JSON.parse(u.responseText),e.postMessage({success:t.success,data:t.data,rocketcdn:!0},l))}}}(s=t.data).hasOwnProperty(\"rocketcdn_validate_token\")&&s.hasOwnProperty(\"rocketcdn_validate_cname\")&&p(\"\"+\"action=rocketcdn_validate_token_cname\"+(\"&cdn_url=\"+s.rocketcdn_validate_cname)+(\"&cdn_token=\"+s.rocketcdn_validate_token)+(\"&nonce=\"+rocket_ajax_data.nonce))}}},{}],9:[function(t,e,i){\"use strict\";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine(\"TimelineLite\",[\"core.Animation\",\"core.SimpleTimeline\",\"TweenLite\"],function(h,u,p){function d(t){u.call(this,t),this._labels={},this.autoRemoveChildren=!0===this.vars.autoRemoveChildren,this.smoothChildTiming=!0===this.vars.smoothChildTiming,this._sortChildren=!0,this._onUpdate=this.vars.onUpdate;var e,i,s=this.vars;for(i in s)e=s[i],g(e)&&-1!==e.join(\"\").indexOf(\"{self}\")&&(s[i]=this._swapSelfInParams(e));g(s.tweens)&&this.add(s.tweens,0,s.align,s.stagger)}function _(t){var e,i={};for(e in t)i[e]=t[e];return i}function n(t,e,i,s){t._timeline.pause(t._startTime),e&&e.apply(s||t._timeline,i||v)}var f=1e-10,m=p._internals.isSelector,g=p._internals.isArray,v=[],a=window._gsDefine.globals,w=v.slice,t=d.prototype=new u;return d.version=\"1.12.1\",t.constructor=d,t.kill()._gc=!1,t.to=function(t,e,i,s){var n=i.repeat&&a.TweenMax||p;return e?this.add(new n(t,e,i),s):this.set(t,i,s)},t.from=function(t,e,i,s){return this.add((i.repeat&&a.TweenMax||p).from(t,e,i),s)},t.fromTo=function(t,e,i,s,n){var r=s.repeat&&a.TweenMax||p;return e?this.add(r.fromTo(t,e,i,s),n):this.set(t,s,n)},t.staggerTo=function(t,e,i,s,n,r,a,o){var l,c=new d({onComplete:r,onCompleteParams:a,onCompleteScope:o,smoothChildTiming:this.smoothChildTiming});for(\"string\"==typeof t&&(t=p.selector(t)||t),m(t)&&(t=w.call(t,0)),s=s||0,l=0;t.length>l;l++)i.startAt&&(i.startAt=_(i.startAt)),c.to(t[l],e,_(i),l*s);return this.add(c,n)},t.staggerFrom=function(t,e,i,s,n,r,a,o){return i.immediateRender=0!=i.immediateRender,i.runBackwards=!0,this.staggerTo(t,e,i,s,n,r,a,o)},t.staggerFromTo=function(t,e,i,s,n,r,a,o,l){return s.startAt=i,s.immediateRender=0!=s.immediateRender&&0!=i.immediateRender,this.staggerTo(t,e,s,n,r,a,o,l)},t.call=function(t,e,i,s){return this.add(p.delayedCall(0,t,e,i),s)},t.set=function(t,e,i){return i=this._parseTimeOrLabel(i,0,!0),null==e.immediateRender&&(e.immediateRender=i===this._time&&!this._paused),this.add(new p(t,0,e),i)},d.exportRoot=function(t,e){null==(t=t||{}).smoothChildTiming&&(t.smoothChildTiming=!0);var i,s,n=new d(t),t=n._timeline;for(null==e&&(e=!0),t._remove(n,!0),n._startTime=0,n._rawPrevTime=n._time=n._totalTime=t._time,i=t._first;i;)s=i._next,e&&i instanceof p&&i.target===i.vars.onComplete||n.add(i,i._startTime-i._delay),i=s;return t.add(n,0),n},t.add=function(t,e,i,s){var n,r,a,o,l,c;if(\"number\"!=typeof e&&(e=this._parseTimeOrLabel(e,0,!0,t)),!(t instanceof h)){if(t instanceof Array||t&&t.push&&g(t)){for(i=i||\"normal\",s=s||0,n=e,r=t.length,a=0;at._startTime;l._timeline;)c&&l._timeline.smoothChildTiming?l.totalTime(l._totalTime,!0):l._gc&&l._enabled(!0,!1),l=l._timeline;return this},t.remove=function(t){if(t instanceof h)return this._remove(t,!1);if(t instanceof Array||t&&t.push&&g(t)){for(var e=t.length;-1<--e;)this.remove(t[e]);return this}return\"string\"==typeof t?this.removeLabel(t):this.kill(null,t)},t._remove=function(t,e){u.prototype._remove.call(this,t,e);t=this._last;return t?this._time>t._startTime+t._totalDuration/t._timeScale&&(this._time=this.duration(),this._totalTime=this._totalDuration):this._time=this._totalTime=this._duration=this._totalDuration=0,this},t.append=function(t,e){return this.add(t,this._parseTimeOrLabel(null,e,!0,t))},t.insert=t.insertMultiple=function(t,e,i,s){return this.add(t,e||0,i,s)},t.appendMultiple=function(t,e,i,s){return this.add(t,this._parseTimeOrLabel(null,e,!0,t),i,s)},t.addLabel=function(t,e){return this._labels[t]=this._parseTimeOrLabel(e),this},t.addPause=function(t,e,i,s){return this.call(n,[\"{self}\",e,i,s],this,t)},t.removeLabel=function(t){return delete this._labels[t],this},t.getLabelTime=function(t){return null!=this._labels[t]?this._labels[t]:-1},t._parseTimeOrLabel=function(t,e,i,s){var n;if(s instanceof h&&s.timeline===this)this.remove(s);else if(s&&(s instanceof Array||s.push&&g(s)))for(n=s.length;-1<--n;)s[n]instanceof h&&s[n].timeline===this&&this.remove(s[n]);if(\"string\"==typeof e)return this._parseTimeOrLabel(e,i&&\"number\"==typeof t&&null==this._labels[e]?t-this.duration():0,i);if(e=e||0,\"string\"!=typeof t||!isNaN(t)&&null==this._labels[t])null==t&&(t=this.duration());else{if(-1===(n=t.indexOf(\"=\")))return null==this._labels[t]?i?this._labels[t]=this.duration()+e:e:this._labels[t]+e;e=parseInt(t.charAt(n-1)+\"1\",10)*Number(t.substr(n+1)),t=1f)&&(a=\"onReverseComplete\")),this._rawPrevTime=this._duration||!e||t||this._rawPrevTime===t?t:f,t=l+1e-4):t<1e-7?(((this._totalTime=this._time=0)!==c||0===this._duration&&this._rawPrevTime!==f&&(0=c)for(s=this._first;s&&(r=s._next,!this._paused||p);)(s._active||s._startTime<=this._time&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=r;else for(s=this._last;s&&(r=s._prev,!this._paused||p);)(s._active||c>=s._startTime&&!s._paused&&!s._gc)&&(s._reversed?s.render((s._dirty?s.totalDuration():s._totalDuration)-(t-s._startTime)*s._timeScale,e,i):s.render((t-s._startTime)*s._timeScale,e,i)),s=r;this._onUpdate&&!e&&this._onUpdate.apply(this.vars.onUpdateScope||this,this.vars.onUpdateParams||v),!a||this._gc||h!==this._startTime&&u===this._timeScale||!(0===this._time||l>=this.totalDuration())||(n&&(this._timeline.autoRemoveChildren&&this._enabled(!1,!1),this._active=!1),e)||!this.vars[a]||this.vars[a].apply(this.vars[a+\"Scope\"]||this,this.vars[a+\"Params\"]||v)}},t._hasPausedChild=function(){for(var t=this._first;t;){if(t._paused||t instanceof d&&t._hasPausedChild())return!0;t=t._next}return!1},t.getChildren=function(t,e,i,s){s=s||-9999999999;for(var n=[],r=this._first,a=0;r;)s>r._startTime||(r instanceof p?!1!==e&&(n[a++]=r):(!1!==i&&(n[a++]=r),!1!==t&&(a=(n=n.concat(r.getChildren(!0,e,i))).length))),r=r._next;return n},t.getTweensOf=function(t,e){var i,s,n=this._gc,r=[],a=0;for(n&&this._enabled(!0,!0),s=(i=p.getTweensOf(t)).length;-1<--s;)(i[s].timeline===this||e&&this._contains(i[s]))&&(r[a++]=i[s]);return n&&this._enabled(!1,!0),r},t._contains=function(t){for(var e=t.timeline;e;){if(e===this)return!0;e=e.timeline}return!1},t.shiftChildren=function(t,e,i){i=i||0;for(var s,n=this._first,r=this._labels;n;)n._startTime>=i&&(n._startTime+=t),n=n._next;if(e)for(s in r)r[s]>=i&&(r[s]+=t);return this._uncache(!0)},t._kill=function(t,e){if(!t&&!e)return this._enabled(!1,!1);for(var i=e?this.getTweensOf(e):this.getChildren(!0,!0,!1),s=i.length,n=!1;-1<--s;)i[s]._kill(t,e)&&(n=!0);return n},t.clear=function(t){var e=this.getChildren(!1,!0,!0),i=e.length;for(this._time=this._totalTime=0;-1<--i;)e[i]._enabled(!1,!1);return!1!==t&&(this._labels={}),this._uncache(!0)},t.invalidate=function(){for(var t=this._first;t;)t.invalidate(),t=t._next;return this},t._enabled=function(t,e){if(t===this._gc)for(var i=this._first;i;)i._enabled(t,!0),i=i._next;return u.prototype._enabled.call(this,t,e)},t.duration=function(t){return arguments.length?(0!==this.duration()&&0!==t&&this.timeScale(this._duration/t),this):(this._dirty&&this.totalDuration(),this._duration)},t.totalDuration=function(t){if(arguments.length)return 0!==this.totalDuration()&&0!==t&&this.timeScale(this._totalDuration/t),this;if(this._dirty){for(var e,i,s=0,n=this._last,r=999999999999;n;)e=n._prev,n._dirty&&n.totalDuration(),n._startTime>r&&this._sortChildren&&!n._paused?this.add(n,n._startTime-n._delay):r=n._startTime,n._startTime<0&&!n._paused&&(s-=n._startTime,this._timeline.smoothChildTiming&&(this._startTime+=n._startTime/this._timeScale),this.shiftChildren(-n._startTime,!1,-9999999999),r=0),s<(i=n._startTime+n._totalDuration/n._timeScale)&&(s=i),n=e;this._duration=this._totalDuration=s,this._dirty=!1}return this._totalDuration},t.usesFrames=function(){for(var t=this._timeline;t._timeline;)t=t._timeline;return t===h._rootFramesTimeline},t.rawTime=function(){return this._paused?this._totalTime:(this._timeline.rawTime()-this._startTime)*this._timeScale},d},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],10:[function(X,p,E){\"use strict\";var e,z,_=window,d=_.GreenSockGlobals||_;if(!d.TweenLite){var f,N=function(t){for(var e=t.split(\".\"),i=d,s=0;e.length>s;s++)i[e[s]]=i=i[e[s]]||{};return i},u=N(\"com.greensock\"),m=1e-10,Y=[].slice,F=function(){},g=(e=Object.prototype.toString,z=e.call([]),function(t){return null!=t&&(t instanceof Array||\"object\"==typeof t&&!!t.push&&e.call(t)===z)}),v={},$=function(o,l,c,h){this.sc=v[o]?v[o].sc:[],(v[o]=this).gsClass=null,this.func=c;var u=[];this.check=function(t){for(var e,i,s,n,r=l.length,a=r;-1<--r;)(e=v[l[r]]||new $(l[r],[])).gsClass?(u[r]=e.gsClass,a--):t&&e.sc.push(this);if(0===a&&c)for(s=(i=(\"com.greensock.\"+o).split(\".\")).pop(),n=N(i.join(\".\"))[s]=this.gsClass=c.apply(c,u),h&&(d[s]=n,\"function\"==typeof define&&define.amd?define((_.GreenSockAMDPath?_.GreenSockAMDPath+\"/\":\"\")+o.split(\".\").join(\"/\"),[],function(){return n}):void 0!==p&&p.exports&&(p.exports=n)),r=0;this.sc.length>r;r++)this.sc[r].check()},this.check(!0)},s=_._gsDefine=function(t,e,i,s){return new $(t,e,i,s)},w=u._class=function(t,e,i){return e=e||function(){},s(t,[],function(){return e},i),e},B=(s.globals=d,[0,0,1,1]),y=[],h=w(\"easing.Ease\",function(t,e,i,s){this._func=t,this._type=i||0,this._power=s||0,this._params=e?B.concat(e):B},!0),x=h.map={},t=h.register=function(t,e,i,s){for(var n,r,a,o,l=e.split(\",\"),c=l.length,h=(i||\"easeIn,easeOut,easeInOut\").split(\",\");-1<--c;)for(r=l[c],n=s?w(\"easing.\"+r,null,!0):u.easing[r]||{},a=h.length;-1<--a;)o=h[a],x[r+\".\"+o]=x[o+r]=n[o]=t.getRatio?t:t[o]||new t},i=h.prototype;for(i._calcEnd=!1,i.getRatio=function(t){var e,i,s;return this._func?(this._params[0]=t,this._func.apply(null,this._params)):(s=1===(e=this._type)?1-t:2===e?t:t<.5?2*t:2*(1-t),1===(i=this._power)?s*=s:2===i?s*=s*s:3===i?s*=s*s*s:4===i&&(s*=s*s*s*s),1===e?1-s:2===e?s:t<.5?s/2:1-s/2)},r=(n=[\"Linear\",\"Quad\",\"Cubic\",\"Quart\",\"Quint,Strong\"]).length;-1<--r;)i=n[r]+\",Power\"+r,t(new h(null,null,1,r),i,\"easeOut\",!0),t(new h(null,null,2,r),i,\"easeIn\"+(0===r?\",easeNone\":\"\")),t(new h(null,null,3,r),i,\"easeInOut\");x.linear=u.easing.Linear.easeIn,x.swing=u.easing.Quad.easeInOut;for(var n,q=w(\"events.EventDispatcher\",function(t){this._listeners={},this._eventTarget=t||this}),b=((i=q.prototype).addEventListener=function(t,e,i,s,n){n=n||0;var r,a,o=this._listeners[t],l=0;for(null==o&&(this._listeners[t]=o=[]),a=o.length;-1<--a;)(r=o[a]).c===e&&r.s===i?o.splice(a,1):0===l&&n>r.pr&&(l=a+1);o.splice(l,0,{c:e,s:i,up:s,pr:n}),this!==S||f||S.wake()},i.removeEventListener=function(t,e){var i,s=this._listeners[t];if(s)for(i=s.length;-1<--i;)if(s[i].c===e)return void s.splice(i,1)},i.dispatchEvent=function(t){var e,i,s,n=this._listeners[t];if(n)for(e=n.length,i=this._eventTarget;-1<--e;)(s=n[e]).up?s.c.call(s.s||i,{type:t,target:i}):s.c.call(s.s||i)},_.requestAnimationFrame),T=_.cancelAnimationFrame,k=Date.now||function(){return(new Date).getTime()},P=k(),r=(n=[\"ms\",\"moz\",\"webkit\",\"o\"]).length;-1<--r&&!b;)b=_[n[r]+\"RequestAnimationFrame\"],T=_[n[r]+\"CancelAnimationFrame\"]||_[n[r]+\"CancelRequestAnimationFrame\"];w(\"Ticker\",function(t,e){var s,n,r,a,o,l=this,c=k(),i=!1!==e&&b,h=500,u=33,p=function(t){var e,i=k()-P;h=e&&e+this.totalDuration()/this._timeScale>t},i._enabled=function(t,e){return f||S.wake(),this._gc=!t,this._active=this.isActive(),!0!==e&&(t&&!this.timeline?this._timeline.add(this,this._startTime-this._delay):!t&&this.timeline&&this._timeline._remove(this,!0)),!1},i._kill=function(){return this._enabled(!1,!1)},i.kill=function(t,e){return this._kill(t,e),this},i._uncache=function(t){for(var e=t?this:this.timeline;e;)e._dirty=!0,e=e.timeline;return this},i._swapSelfInParams=function(t){for(var e=t.length,i=t.concat();-1<--e;)\"{self}\"===t[e]&&(i[e]=this);return i},i.eventCallback=function(t,e,i,s){if(\"on\"===(t||\"\").substr(0,2)){var n=this.vars;if(1===arguments.length)return n[t];null==e?delete n[t]:(n[t]=e,n[t+\"Params\"]=g(i)&&-1!==i.join(\"\").indexOf(\"{self}\")?this._swapSelfInParams(i):i,n[t+\"Scope\"]=s),\"onUpdate\"===t&&(this._onUpdate=e)}return this},i.delay=function(t){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+t-this._delay),this._delay=t,this):this._delay},i.duration=function(t){return arguments.length?(this._duration=this._totalDuration=t,this._uncache(!0),this._timeline.smoothChildTiming&&0this._duration?this._duration:t,e)):this._time},i.totalTime=function(t,e,i){if(f||S.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(t<0&&!i&&(t+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var s=this._totalDuration,n=this._timeline;if(ss;)i=i._prev;return i?(t._next=i._next,i._next=t):(t._next=this._first,this._first=t),t._next?t._next._prev=t:this._last=t,t._prev=i,this._timeline&&this._uncache(!0),this},i._remove=function(t,e){return t.timeline===this&&(e||t._enabled(!1,!0),t.timeline=null,t._prev?t._prev._next=t._next:this._first===t&&(this._first=t._next),t._next?t._next._prev=t._prev:this._last===t&&(this._last=t._prev),this._timeline)&&this._uncache(!0),this},i.render=function(t,e,i){var s,n=this._first;for(this._totalTime=this._time=this._rawPrevTime=t;n;)s=n._next,(n._active||t>=n._startTime&&!n._paused)&&(n._reversed?n.render((n._dirty?n.totalDuration():n._totalDuration)-(t-n._startTime)*n._timeScale,e,i):n.render((t-n._startTime)*n._timeScale,e,i)),n=s},i.rawTime=function(){return f||S.wake(),this._totalTime},w(\"TweenLite\",function(t,e,i){if(o.call(this,e,i),this.render=O.prototype.render,null==t)throw\"Cannot tween a null target.\";this.target=t=\"string\"==typeof t&&O.selector(t)||t;var s,n,r,i=t.jquery||t.length&&t!==_&&t[0]&&(t[0]===_||t[0].nodeType&&t[0].style&&!t.nodeType),a=this.vars.overwrite;if(this._overwrite=a=null==a?Q[O.defaultOverwrite]:\"number\"==typeof a?a>>0:Q[a],(i||t instanceof Array||t.push&&g(t))&&\"number\"!=typeof t[0])for(this._targets=r=Y.call(t,0),this._propLookup=[],this._siblings=[],s=0;r.length>s;s++)(n=r[s])?\"string\"!=typeof n?n.length&&n!==_&&n[0]&&(n[0]===_||n[0].nodeType&&n[0].style&&!n.nodeType)?(r.splice(s--,1),this._targets=r=r.concat(Y.call(n,0))):(this._siblings[s]=j(n,this,!1),1===a&&1=a._startTime&&a._startTime+a.totalDuration()/a._timeScale>c&&((p||!a._initted)&&c-a._startTime<=2e-10||(h[u++]=a)));for(d=u;-1<--d;)a=h[d],2===s&&a._kill(i,t)&&(r=!0),(2!==s||!a._firstPT&&a._initted)&&a._enabled(!1,!1)&&(r=!0)}return r},G=function(t,e,i){for(var s=t._timeline,n=s._timeScale,r=t._startTime;s._timeline;){if(r+=s._startTime,n*=s._timeScale,s._paused)return-100;s=s._timeline}return e<(r/=n)?r-e:i&&r===e||!t._initted&&r-e<2*m?m:(r+=t.totalDuration()/t._timeScale/n)>e+m?0:r-e-m},L=(i._init=function(){var t,e,i,s,n,r=this.vars,a=this._overwrittenProps,o=this._duration,l=!!r.immediateRender,c=r.ease;if(r.startAt){for(s in this._startAt&&(this._startAt.render(-1,!0),this._startAt.kill()),n={},r.startAt)n[s]=r.startAt[s];if(n.overwrite=!1,n.immediateRender=!0,n.lazy=l&&!1!==r.lazy,n.startAt=n.delay=null,this._startAt=O.to(this.target,0,n),l)if(0o.pr;)s=s._next;(o._prev=s?s._prev:r)?o._prev._next=o:n=o,(o._next=s)?s._prev=o:r=o,o=a}o=e._firstPT=n}for(;o;)o.pg&&\"function\"==typeof o.t[t]&&o.t[t]()&&(i=!0),o=o._next;return i},L.activate=function(t){for(var e=t.length;-1<--e;)t[e].API===L.API&&(R[(new t[e])._propName]=t[e]);return!0},s.plugin=function(t){if(!(t&&t.propName&&t.init&&t.API))throw\"illegal plugin definition.\";var e,i=t.propName,s=t.priority||0,n=t.overwriteProps,r={init:\"_onInitTween\",set:\"setRatio\",kill:\"_kill\",round:\"_roundProps\",initAll:\"_onInitAllProps\"},a=w(\"plugins.\"+i.charAt(0).toUpperCase()+i.substr(1)+\"Plugin\",function(){L.call(this,i,s),this._overwriteProps=n||[]},!0===t.global),o=a.prototype=new L(i);for(e in(o.constructor=a).API=t.API,r)\"function\"==typeof t[e]&&(o[r[e]]=t[e]);return a.version=t.version,L.activate([a]),a},n=_._gsQueue){for(r=0;n.length>r;r++)n[r]();for(i in v)v[i].func||_.console.log(\"GSAP encountered missing dependency: com.greensock.\"+i)}f=!1}},{}],11:[function(t,e,i){\"use strict\";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine(\"easing.Back\",[\"easing.Ease\"],function(m){function t(t,e){var i=(t=c(\"easing.\"+t,function(){},!0)).prototype=new m;return i.constructor=t,i.getRatio=e,t}function e(t,e,i,s){return e=c(\"easing.\"+t,{easeOut:new e,easeIn:new i,easeInOut:new s},!0),h(e,t),e}function g(t,e,i){this.t=t,this.v=e,i&&(((this.next=i).prev=this).c=i.v-e,this.gap=i.t-t)}function i(t,e){var i=c(\"easing.\"+t,function(t){this._p1=t||0===t?t:1.70158,this._p2=1.525*this._p1},!0);return(t=i.prototype=new m).constructor=i,t.getRatio=e,t.config=function(t){return new i(t)},i}var s,n,r=window.GreenSockGlobals||window,a=r.com.greensock,o=2*Math.PI,l=Math.PI/2,c=a._class,h=m.register||function(){},a=e(\"Back\",i(\"BackOut\",function(t){return--t*t*((this._p1+1)*t+this._p1)+1}),i(\"BackIn\",function(t){return t*t*((this._p1+1)*t-this._p1)}),i(\"BackInOut\",function(t){return(t*=2)<1?.5*t*t*((this._p2+1)*t-this._p2):.5*((t-=2)*t*((this._p2+1)*t+this._p2)+2)})),u=c(\"easing.SlowMo\",function(t,e,i){e=e||0===e?e:.7,null==t?t=.7:1t?this._calcEnd?1-(t=1-t/this._p1)*t:e-(t=1-t/this._p1)*t*t*t*e:t>this._p3?this._calcEnd?1-(t=(t-this._p3)/this._p1)*t:e+(t-e)*(t=(t-this._p3)/this._p1)*t*t*t:this._calcEnd?1:e},u.ease=new u(.7,.7),p.config=u.config=function(t,e,i){return new u(t,e,i)},(p=(s=c(\"easing.SteppedEase\",function(t){this._p1=1/(t=t||1),this._p2=t+1},!0)).prototype=new m).constructor=s,p.getRatio=function(t){return t<0?t=0:1<=t&&(t=.999999999),(this._p2*t>>0)*this._p1},p.config=s.config=function(t){return new s(t)},(p=(n=c(\"easing.RoughEase\",function(t){for(var e,i,s,n,r,a,o=(t=t||{}).taper||\"none\",l=[],c=0,h=0|(t.points||20),u=h,p=!1!==t.randomize,d=!0===t.clamp,_=t.template instanceof m?t.template:null,f=\"number\"==typeof t.strength?.4*t.strength:.4;-1<--u;)e=p?Math.random():1/h*u,i=_?_.getRatio(e):e,s=\"none\"===o?f:\"out\"===o?(n=1-e)*n*f:\"in\"===o?e*e*f:.5*(n=e<.5?2*e:2*(1-e))*n*f,p?i+=Math.random()*s-.5*s:u%2?i+=.5*s:i-=.5*s,d&&(1e.t){for(;e.next&&t>=e.t;)e=e.next;e=e.prev}else for(;e.prev&&e.t>=t;)e=e.prev;return(this._prev=e).v+(t-e.t)/e.gap*e.c},p.config=function(t){return new n(t)},n.ease=new n,e(\"Bounce\",t(\"BounceOut\",function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375}),t(\"BounceIn\",function(t){return 1/2.75>(t=1-t)?1-7.5625*t*t:t<2/2.75?1-(7.5625*(t-=1.5/2.75)*t+.75):t<2.5/2.75?1-(7.5625*(t-=2.25/2.75)*t+.9375):1-(7.5625*(t-=2.625/2.75)*t+.984375)}),t(\"BounceInOut\",function(t){var e=t<.5;return t=(t=e?1-2*t:2*t-1)<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375,e?.5*(1-t):.5*t+.5})),e(\"Circ\",t(\"CircOut\",function(t){return Math.sqrt(1- --t*t)}),t(\"CircIn\",function(t){return-(Math.sqrt(1-t*t)-1)}),t(\"CircInOut\",function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)})),e(\"Elastic\",(p=function(t,e,i){var s=c(\"easing.\"+t,function(t,e){this._p1=t||1,this._p2=e||i,this._p3=this._p2/o*(Math.asin(1/this._p1)||0)},!0),t=s.prototype=new m;return t.constructor=s,t.getRatio=e,t.config=function(t,e){return new s(t,e)},s})(\"ElasticOut\",function(t){return this._p1*Math.pow(2,-10*t)*Math.sin((t-this._p3)*o/this._p2)+1},.3),p(\"ElasticIn\",function(t){return-(this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*o/this._p2))},.3),p(\"ElasticInOut\",function(t){return(t*=2)<1?-.5*this._p1*Math.pow(2,10*--t)*Math.sin((t-this._p3)*o/this._p2):.5*this._p1*Math.pow(2,-10*--t)*Math.sin((t-this._p3)*o/this._p2)+1},.45)),e(\"Expo\",t(\"ExpoOut\",function(t){return 1-Math.pow(2,-10*t)}),t(\"ExpoIn\",function(t){return Math.pow(2,10*(t-1))-.001}),t(\"ExpoInOut\",function(t){return(t*=2)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*(t-1)))})),e(\"Sine\",t(\"SineOut\",function(t){return Math.sin(t*l)}),t(\"SineIn\",function(t){return 1-Math.cos(t*l)}),t(\"SineInOut\",function(t){return-.5*(Math.cos(Math.PI*t)-1)})),c(\"easing.EaseLookup\",{find:function(t){return m.map[t]}},!0),h(r.SlowMo,\"SlowMo\",\"ease,\"),h(n,\"RoughEase\",\"ease,\"),h(s,\"SteppedEase\",\"ease,\"),a},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],12:[function(t,e,i){\"use strict\";(window._gsQueue||(window._gsQueue=[])).push(function(){window._gsDefine(\"plugins.CSSPlugin\",[\"plugins.TweenPlugin\",\"TweenLite\"],function(r,p){function N(){r.call(this,\"css\"),this._overwriteProps.length=0,this.setRatio=N.prototype.setRatio}var d,x,b,u,_={},t=N.prototype=new r(\"css\");(t.constructor=N).version=\"1.12.1\",N.API=2,N.defaultTransformPerspective=0,N.defaultSkewType=\"compensated\",N.suffixMap={top:t=\"px\",right:t,bottom:t,left:t,width:t,height:t,fontSize:t,padding:t,margin:t,perspective:t,lineHeight:\"\"};function a(t,e){return e.toUpperCase()}function o(t){return tt.test(\"string\"==typeof t?t:(t.currentStyle||t.style).filter||\"\")?parseFloat(RegExp.$1)/100:1}function L(t){window.console&&console.log(t)}function T(t,e){var i,s,n=(e=e||O).style;if(void 0!==n[t])return t;for(t=t.charAt(0).toUpperCase()+t.substr(1),i=[\"O\",\"Moz\",\"ms\",\"Ms\",\"Webkit\"],s=5;-1<--s&&void 0===n[i[s]+t];);return 0<=s?(ut=\"-\"+(pt=3===s?\"ms\":i[s]).toLowerCase()+\"-\",pt+t):null}function f(t,e){var i,s={};if(e=e||m(t,null))if(i=e.length)for(;-1<--i;)s[e[i].replace(rt,a)]=e.getPropertyValue(e[i]);else for(i in e)s[i]=e[i];else if(e=t.currentStyle||t.style)for(i in e)\"string\"==typeof i&&void 0===s[i]&&(s[i.replace(rt,a)]=e[i]);return C||(s.opacity=o(t)),t=j(t,e,!1),s.rotation=t.rotation,s.skewX=t.skewX,s.scaleX=t.scaleX,s.scaleY=t.scaleY,s.x=t.x,s.y=t.y,q&&(s.z=t.z,s.rotationX=t.rotationX,s.rotationY=t.rotationY,s.scaleZ=t.scaleZ),s.filters&&delete s.filters,s}function X(t,e,i,s,n){var r,a,o,l={},c=t.style;for(a in i)\"cssText\"!==a&&\"length\"!==a&&isNaN(a)&&(e[a]!==(r=i[a])||n&&n[a])&&-1===a.indexOf(\"Origin\")&&(\"number\"==typeof r||\"string\"==typeof r)&&(l[a]=\"auto\"!==r||\"left\"!==a&&\"top\"!==a?\"\"!==r&&\"auto\"!==r&&\"none\"!==r||\"string\"!=typeof e[a]||\"\"===e[a].replace(h,\"\")?r:0:dt(t,a),void 0!==c[a])&&(o=new vt(c,a,c[a],o));if(s)for(a in s)\"className\"!==a&&(l[a]=s[a]);return{difs:l,firstMPT:o}}function E(t,e){var i=(t=null!=t&&\"\"!==t&&\"auto\"!==t&&\"auto auto\"!==t?t:\"0 0\").split(\" \"),s=-1!==t.indexOf(\"left\")?\"0%\":-1!==t.indexOf(\"right\")?\"100%\":i[0];return null==(t=-1!==t.indexOf(\"top\")?\"0%\":-1!==t.indexOf(\"bottom\")?\"100%\":i[1])?t=\"0\":\"center\"===t&&(t=\"50%\"),(\"center\"===s||isNaN(parseFloat(s))&&-1===(s+\"\").indexOf(\"=\"))&&(s=\"50%\"),e&&(e.oxp=-1!==s.indexOf(\"%\"),e.oyp=-1!==t.indexOf(\"%\"),e.oxr=\"=\"===s.charAt(1),e.oyr=\"=\"===t.charAt(1),e.ox=parseFloat(s.replace(h,\"\")),e.oy=parseFloat(t.replace(h,\"\"))),s+\" \"+t+(2>16,255&t>>8,255&t]:(\",\"===t.charAt(t.length-1)&&(t=t.substr(0,t.length-1)),M[t]||(\"#\"===t.charAt(0)?(4===t.length&&(t=\"#\"+(e=t.charAt(1))+e+(i=t.charAt(2))+i+(s=t.charAt(3))+s),[(t=parseInt(t.substr(1),16))>>16,255&t>>8,255&t]):(\"hsl\"===t.substr(0,3)?(t=t.match(P),s=Number(t[0])%360/360,n=Number(t[1])/100,e=2*(r=Number(t[2])/100)-(i=r<=.5?r*(1+n):r+n-r*n),3a\",!!(e=Z.getElementsByTagName(\"a\")[0])&&/^0.55/.test(e.style.opacity)),ut=\"\",pt=\"\",m=y.defaultView?y.defaultView.getComputedStyle:function(){},$=N.getStyle=function(t,e,i,s,n){var r;return C||\"opacity\"!==e?(!s&&t.style[e]?r=t.style[e]:(i=i||m(t))?r=i[e]||i.getPropertyValue(e)||i.getPropertyValue(e.replace(nt,\"-$1\").toLowerCase()):t.currentStyle&&(r=t.currentStyle[e]),null==n||r&&\"none\"!==r&&\"auto\"!==r&&\"auto auto\"!==r?r:n):o(t)},A=i.convertToPixels=function(t,e,i,s,n){if(\"px\"===s||!s)return i;if(\"auto\"===s||!i)return 0;var r,a,o,l=ot.test(e),c=t,h=O.style,u=i<0;if(u&&(i=-i),\"%\"===s&&-1!==e.indexOf(\"border\"))r=i/100*(l?t.clientWidth:t.clientHeight);else{if(h.cssText=\"border:0 solid red;position:\"+$(t,\"position\")+\";line-height:0;\",\"%\"!==s&&c.appendChild)h[l?\"borderLeftWidth\":\"borderTopWidth\"]=i+s;else{if(a=(c=t.parentNode||y.body)._gsCache,o=p.ticker.frame,a&&l&&a.time===o)return a.width*i/100;h[l?\"width\":\"height\"]=i+s}c.appendChild(O),r=parseFloat(O[l?\"offsetWidth\":\"offsetHeight\"]),c.removeChild(O),l&&\"%\"===s&&!1!==N.cacheWidths&&((a=c._gsCache=c._gsCache||{}).time=o,a.width=r/i*100),0!==r||n||(r=A(t,e,i,s,!0))}return u?-r:r},dt=i.calculateOffset=function(t,e,i){var s;return\"absolute\"!==$(t,\"position\",i)?0:(i=$(t,\"margin\"+(s=\"left\"===e?\"Left\":\"Top\"),i),t[\"offset\"+s]-(A(t,e,parseFloat(i),i.replace(J,\"\"))||0))},_t={width:[\"Left\",\"Right\"],height:[\"Top\",\"Bottom\"]},ft=[\"marginLeft\",\"marginRight\",\"marginTop\",\"marginBottom\"],M={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},R=\"(?:\\\\b(?:(?:rgb|rgba|hsl|hsla)\\\\(.+?\\\\))|\\\\B#.+?\\\\b\";for(t in M)R+=\"|\"+t+\"\\\\b\";function mt(t,e,r,a){var o,l,c,h,u,p,d,_;return null==t?function(t){return t}:(l=e?(t.match(R)||[\"\"])[0]:\"\",c=t.split(l).join(\"\").match(K)||[],h=t.substr(0,t.indexOf(c[0])),u=\")\"===t.charAt(t.length-1)?\")\":\"\",p=-1!==t.indexOf(\" \")?\" \":\",\",d=c.length,_=0s;s++)n[s]=o(n[s]);return n.join(\",\")}if(e=(t.match(R)||[l])[0],s=(i=t.split(e).join(\"\").match(K)||[]).length,d>s--)for(;d>++s;)i[s]=r?i[0|(s-1)/2]:c[s];return h+i.join(p)+p+e+u+(-1!==t.indexOf(\"inset\")?\" inset\":\"\")}:function(t){var e,i,s;if(\"number\"==typeof t)t+=_;else if(a&&S.test(t)){for(i=t.replace(S,\"|\").split(\"|\"),s=0;i.length>s;s++)i[s]=o(i[s]);return i.join(\",\")}if(s=(e=t.match(K)||[]).length,d>s--)for(;d>++s;)e[s]=r?e[0|(s-1)/2]:c[s];return h+e.join(p)+u}:function(t){return t})}function gt(c){return c=c.split(\",\"),function(t,e,i,s,n,r,a){var o,l=(e+\"\").split(\" \");for(a={},o=0;o<4;o++)a[c[o]]=l[o]=l[o]||l[(o-1)/2>>0];return s.parse(t,a,n,r)}}function vt(t,e,i,s,n){this.t=t,this.p=e,this.v=i,this.r=n,s&&((s._prev=this)._next=s)}var R=RegExp(R+\")\",\"gi\"),I=(i._setPluginRatio=function(t){this.plugin.setRatio(t);for(var e,i,s,n,r=this.data,a=r.proxy,o=r.firstMPT;o;)e=a[o.v],o.r?e=Math.round(e):e<1e-6&&-1e-6s;s++)n+=i[\"xn\"+s]+i[\"xs\"+(s+1)];i.e=n}}else i.e=i.s+i.xs0;o=o._next}},i._parseToProxy=function(t,e,i,s,n,r){var a,o,l,c,h=s,u={},p={},d=i._transform,_=w;for(i._transform=null,w=e,s=t=i.parse(t,e,s,n),w=_,r&&(i._transform=d,h)&&(h._prev=null,h._prev)&&(h._prev._next=null);s&&s!==h;){if(s.type<=1&&(p[o=s.p]=s.s+s.c,u[o]=s.s,r||(c=new vt(s,\"s\",o,c,s.r),s.c=0),1===s.type))for(a=s.l;0<--a;)p[o=s.p+\"_\"+(l=\"xn\"+a)]=s.data[l],u[o]=s[l],r||(c=new vt(s,l,o,c,s.rxp[l]));s=s._next}return{proxy:u,end:p,firstMPT:c,pt:t}},i.CSSPropTween=function(t,e,i,s,n,r,a,o,l,c,h){this.t=t,this.p=e,this.s=i,this.c=s,this.n=a||e,t instanceof I||u.push(this.n),this.r=o,this.type=r||0,l&&(this.pr=l,d=!0),this.b=void 0===c?i:c,this.e=void 0===h?i+s:h,n&&((this._next=n)._prev=this)}),wt=N.parseComplex=function(t,e,i,s,n,r,a,o,l,c){a=new I(t,e,0,0,a,c?2:1,null,!1,o,i=i||r||\"\",s),s+=\"\";var h,u,p,d,_,f,m,g,v,w,y,x=i.split(\", \").join(\",\").split(\" \"),b=s.split(\", \").join(\",\").split(\" \"),T=x.length,k=!1!==U;for(-1===s.indexOf(\",\")&&-1===i.indexOf(\",\")||(x=x.join(\" \").replace(S,\", \").split(\" \"),b=b.join(\" \").replace(S,\", \").split(\" \"),T=x.length),T!==b.length&&(T=(x=(r||\"\").split(\" \")).length),a.plugin=l,a.setRatio=c,h=0;hu;u++)w=f[u],v=d.indexOf(w,p),a.appendXtra(d.substr(p,v-p),Number(w),z(m[u],w),\"\",k&&\"px\"===d.substr(v+w.length,2),0===u),p=v+w.length;a[\"xs\"+a.l]+=d.substr(p)}else a[\"xs\"+a.l]+=a.l?\" \"+d:d;if(-1!==s.indexOf(\"=\")&&a.data){for(y=a.xs0+a.data.s,h=1;a.l>h;h++)y+=a[\"xs\"+h]+a.data[\"xn\"+h];a.e=y+a[\"xs\"+h]}return a.l||(a.type=-1,a.xs0=a.e),a.xfirst||a},D=9;for((t=I.prototype).l=t.pr=0;0<--D;)t[\"xn\"+D]=0,t[\"xs\"+D]=\"\";t.xs0=\"\",t._next=t._prev=t.xfirst=t.data=t.plugin=t.setRatio=t.rxp=null,t.appendXtra=function(t,e,i,s,n,r){var a=this,o=a.l;return a[\"xs\"+o]+=r&&o?\" \"+t:t||\"\",i||0===o||a.plugin?(a.l++,a.type=a.setRatio?2:1,a[\"xs\"+a.l]=s||\"\",0s;s++)e.prefix=0===s&&e.prefix,e.defaultValue=i[s]||r,new yt(n[s],e)},St=((t=yt.prototype).parseComplex=function(t,e,i,s,n,r){var a,o,l,c,h,u=this.keyword;if(this.multi&&(S.test(i)||S.test(e)?(o=e.replace(S,\"|\").split(\"|\"),l=i.replace(S,\"|\").split(\"|\")):u&&(o=[e],l=[i])),l){for(c=(l.length>o.length?l:o).length,a=0;aR[r]&&R[r]>-I&&(R[r]=0);return i&&(t._gsTransform=R),R},Mt=i.set3DTransformRatio=function(t){var e,i,s,n,r,a,o,l,c,h,u,p,d,_,f,m,g,v,w,y,x,b,T=this.data,k=this.t.style,P=T.rotation*Y,S=T.scaleX,O=T.scaleY,C=T.scaleZ,A=T.perspective;if(1!==t&&0!==t||\"auto\"!==T.force3D||T.rotationY||T.rotationX||1!==C||A||T.z){if(V&&(S<1e-4&&-1e-4s.pr;)n=n._next;(s._prev=n?n._prev:a)?s._prev._next=s:r=s,(s._next=n)?n._prev=s:a=s,s=o}this._firstPT=r}return!0},t.parse=function(t,e,i,s){var n,r,a,o,l,c,h,u,p=t.style;for(n in e)l=e[n],o=_[n],o?i=o.parse(t,l,n,this,i,s,e):(o=$(t,n,b)+\"\",h=\"string\"==typeof l,\"color\"===n||\"fill\"===n||\"stroke\"===n||-1!==n.indexOf(\"Color\")||h&&st.test(l)?(h||(l=H(l),l=(3s;s++)i+=n[\"xn\"+s]+n[\"xs\"+(s+1)];n.t[n.p]=i}else-1===n.type?n.t[n.p]=n.xs0:n.setRatio&&n.setRatio(t);else n.t[n.p]=e+n.xs0;n=n._next}else for(;n;)2!==n.type?n.t[n.p]=n.b:n.setRatio(t),n=n._next;else for(;n;)2!==n.type?n.t[n.p]=n.e:n.setRatio(t),n=n._next},t._enableTransforms=function(t){this._transformType=t||3===this._transformType?3:2,this._transform=this._transform||j(this._target,b,!0)};function It(){this.t[this.p]=this.e,this.data._linkCSSP(this,this._next,null,!0)}function Dt(t,e,i){var s,n,r,a;if(t.slice)for(n=t.length;-1<--n;)Dt(t[n],e,i);else for(n=(s=t.childNodes).length;-1<--n;)a=(r=s[n]).type,r.style&&(e.push(f(r)),i)&&i.push(r),1!==a&&9!==a&&11!==a||!r.childNodes.length||Dt(r,e,i)}t._addLazySet=function(t,e,i){t=this._firstPT=new I(t,e,0,0,this._firstPT,2);t.e=i,t.setRatio=It,t.data=this},t._linkCSSP=function(t,e,i,s){return t&&(e&&(e._prev=t),t._next&&(t._next._prev=t._prev),t._prev?t._prev._next=t._next:this._firstPT===t&&(this._firstPT=t._next,s=!0),i?i._next=t:s||null!==this._firstPT||(this._firstPT=t),t._next=e,t._prev=i),t},t._kill=function(t){var e,i,s,n=t;if(t.autoAlpha||t.alpha){for(i in n={},t)n[i]=t[i];n.opacity=1,n.autoAlpha&&(n.visibility=1)}return t.className&&(e=this._classNamePT)&&((s=e.xfirst)&&s._prev?this._linkCSSP(s._prev,e._next,s._prev._prev):s===this._firstPT&&(this._firstPT=e._next),e._next&&this._linkCSSP(e._next,e._next._next,s._prev),this._classNamePT=null),r.prototype._kill.call(this,n)};return N.cascadeTo=function(t,e,i){var s,n,r,a=p.to(t,e,i),o=[a],l=[],c=[],h=[],u=p._internals.reservedProps;for(t=a._targets||a.target,Dt(t,l,h),a.render(e,!0),Dt(t,c),a.render(0,!0),a._enabled(!0),s=h.length;-1<--s;)if((n=X(h[s],l[s],c[s])).firstMPT){for(r in n=n.difs,i)u[r]&&(n[r]=i[r]);o.push(p.to(h[s],e,n))}return o},r.activate([N]),N},!0)}),window._gsDefine&&window._gsQueue.pop()()},{}],13:[function(t,e,i){\"use strict\";(window._gsQueue||(window._gsQueue=[])).push(function(){function n(t,e){var i=\"scroll\"+(e=\"x\"===e?\"Width\":\"Height\"),s=\"client\"+e,n=document.body;return t===a||t===r||t===n?Math.max(r[i],n[i])-(a[\"inner\"+e]||Math.max(r[s],n[s])):t[i]-t[\"offset\"+e]}var r=document.documentElement,a=window,t=window._gsDefine.plugin({propName:\"scrollTo\",API:2,version:\"1.7.3\",init:function(t,e,i){return this._wdw=t===a,this._target=t,this._tween=i,this._autoKill=!1!==(e=\"object\"!=typeof e?{y:e}:e).autoKill,this.x=this.xPrev=this.getX(),this.y=this.yPrev=this.getY(),null!=e.x?(this._addTween(this,\"x\",this.x,\"max\"===e.x?n(t,\"x\"):e.x,\"scrollTo_x\",!0),this._overwriteProps.push(\"scrollTo_x\")):this.skipX=!0,null!=e.y?(this._addTween(this,\"y\",this.y,\"max\"===e.y?n(t,\"y\"):e.y,\"scrollTo_y\",!0),this._overwriteProps.push(\"scrollTo_y\")):this.skipY=!0,!0},set:function(t){this._super.setRatio.call(this,t);var t=this._wdw||!this.skipX?this.getX():this.xPrev,e=this._wdw||!this.skipY?this.getY():this.yPrev,i=e-this.yPrev,s=t-this.xPrev;this._autoKill&&(!this.skipX&&(7t&&(this.skipX=!0),!this.skipY&&(7e&&(this.skipY=!0),this.skipX)&&this.skipY&&this._tween.kill(),this._wdw?a.scrollTo(this.skipX?t:this.x,this.skipY?e:this.y):(this.skipY||(this._target.scrollTop=this.y),this.skipX||(this._target.scrollLeft=this.x)),this.xPrev=this.x,this.yPrev=this.y}}),e=t.prototype;t.max=n,e.getX=function(){return this._wdw?null!=a.pageXOffset?a.pageXOffset:(null!=r.scrollLeft?r:document.body).scrollLeft:this._target.scrollLeft},e.getY=function(){return this._wdw?null!=a.pageYOffset?a.pageYOffset:(null!=r.scrollTop?r:document.body).scrollTop:this._target.scrollTop},e._kill=function(t){return t.scrollTo_x&&(this.skipX=!0),t.scrollTo_y&&(this.skipY=!0),this._super._kill.call(this,t)}}),window._gsDefine&&window._gsQueue.pop()()},{}]},{},[2]);"],"file":"wpr-admin.min.js"} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/assets/js/wpr-cpcss.js b/wp-content/plugins/wp-rocket/assets/js/wpr-cpcss.js index 020b873a6..e98d65776 100644 --- a/wp-content/plugins/wp-rocket/assets/js/wpr-cpcss.js +++ b/wp-content/plugins/wp-rocket/assets/js/wpr-cpcss.js @@ -7,19 +7,23 @@ const rocketGenerateCPCSSbtn = document.getElementById( 'rocket-generate-po const rocketCPCSSGenerate = document.querySelectorAll( '.cpcss_generate' ); const rocketCPCSSReGenerate = document.querySelectorAll( '.cpcss_regenerate' ); -rocketDeleteCPCSSbtn.addEventListener( 'click', e => { - e.preventDefault(); - deleteCPCSS(); -} ); - -rocketGenerateCPCSSbtn.addEventListener( 'click', e => { - e.preventDefault(); - rocketGenerateCPCSSbtn.disabled = true; - checkCPCSSGeneration( null, false ); - if ( rocket_cpcss.wprMobileCpcssEnabled ) { - checkCPCSSGeneration( null, true ); - } -} ); +if ( null !== rocketDeleteCPCSSbtn ) { + rocketDeleteCPCSSbtn.addEventListener( 'click', e => { + e.preventDefault(); + deleteCPCSS(); + } ); +} + +if ( null !== rocketGenerateCPCSSbtn ) { + rocketGenerateCPCSSbtn.addEventListener( 'click', e => { + e.preventDefault(); + rocketGenerateCPCSSbtn.disabled = true; + checkCPCSSGeneration( null, false ); + if ( rocket_cpcss.wprMobileCpcssEnabled ) { + checkCPCSSGeneration( null, true ); + } + } ); +} const checkCPCSSGeneration = ( timeout = null, is_mobile = false ) => { const spinner = rocketGenerateCPCSSbtn.querySelector( '.spinner' ); @@ -85,7 +89,7 @@ const checkCPCSSGeneration = ( timeout = null, is_mobile = false ) => { }; xhttp.open( 'POST', rocket_cpcss.rest_url, true ); - xhttp.setRequestHeader( 'Content-Type', 'application/json;charset=UTF-8' ); + xhttp.setRequestHeader( 'Content-Type', 'application/json' ); xhttp.setRequestHeader( 'X-WP-Nonce', rocket_cpcss.rest_nonce ); xhttp.send( JSON.stringify( { timeout: timeout, is_mobile: is_mobile } ) ); } @@ -125,7 +129,7 @@ const deleteCPCSS = () => { }; xhttp.open( 'DELETE', rocket_cpcss.rest_url, true ); - xhttp.setRequestHeader( 'Content-Type', 'application/json;charset=UTF-8' ); + xhttp.setRequestHeader( 'Content-Type', 'application/json' ); xhttp.setRequestHeader( 'X-WP-Nonce', rocket_cpcss.rest_nonce ); xhttp.send(); } diff --git a/wp-content/plugins/wp-rocket/assets/js/wpr-modal.js b/wp-content/plugins/wp-rocket/assets/js/wpr-modal.js deleted file mode 100644 index a1d947e0c..000000000 --- a/wp-content/plugins/wp-rocket/assets/js/wpr-modal.js +++ /dev/null @@ -1,202 +0,0 @@ -var $ = jQuery; -$(document).ready(function(){ - - var $wprModal = $(".wpr-Modal"); - if($wprModal){ - new ModalWpr($wprModal); - } - - /** - * AJAX Safe mode action button - */ - $('#wpr-action-safe_mode').on('click', function(e) { - var button = $(this); - e.preventDefault(); - - $.post( - ajaxurl, - { - action: 'rocket_safe_mode', - nonce: rocket_ajax_data.nonce, - }, - function(response) { - if ( true === response.success ) { - button.hide(); - $('.show-if-safe-mode').show(); - } - } - ); - }); -}); - - -/*-----------------------------------------------*\ - CLASS ModalWpr -\*-----------------------------------------------*/ -/** - * Manages the display of deactivation modal box - * - * Public method : - open - Open the modal - close - Close the modal - change - Test if modal state change - * - */ - -function ModalWpr(aElem) { - - var refThis = this; - - this.elem = aElem; - this.overlay = $('.wpr-Modal-overlay'); - this.radio = $('input[name=reason]', aElem); - this.closer = $('.wpr-Modal-close, .wpr-Modal-cancel', aElem); - this.return = $('.wpr-Modal-return', aElem); - this.opener = $('.plugins [data-slug="wp-rocket"] .deactivate'); - this.question = $('.wpr-Modal-question', aElem); - this.button = $('.button-primary', aElem); - this.title = $('.wpr-Modal-header h2', aElem); - this.textFields = $('input[type=text], textarea',aElem); - this.hiddenReason = $('#wpr-reason', aElem); - this.hiddenDetails = $('#wpr-details', aElem); - this.titleText = this.title.text(); - - // Open - this.opener.click(function() { - refThis.open(); - return false; - }); - - // Close - this.closer.click(function() { - refThis.close(); - return false; - }); - - aElem.bind('keyup', function(){ - if(event.keyCode == 27){ // ECHAP - refThis.close(); - return false; - } - }); - - // Back - this.return.click(function() { - refThis.returnToQuestion(); - return false; - }); - - // Click on radio - this.radio.change(function(){ - refThis.change($(this)); - }); - - // Write text - this.textFields.keyup(function() { - refThis.hiddenDetails.val($(this).val()); - if(refThis.hiddenDetails.val() != ''){ - refThis.button.removeClass('wpr-isDisabled'); - refThis.button.removeAttr("disabled"); - } - else{ - refThis.button.addClass('wpr-isDisabled'); - refThis.button.attr("disabled", true); - } - }); -} - - -/* -* Change modal state -*/ -ModalWpr.prototype.change = function(aElem) { - - var id = aElem.attr('id'); - var refThis = this; - - // Reset values - this.hiddenReason.val(aElem.val()); - this.hiddenDetails.val(''); - this.textFields.val(''); - - $('.wpr-Modal-fieldHidden').removeClass('wpr-isOpen'); - $('.wpr-Modal-hidden').removeClass('wpr-isOpen'); - this.button.removeClass('wpr-isDisabled'); - this.button.removeAttr("disabled"); - - switch(id){ - case 'reason-temporary': - // Nothing to do - break; - - case 'reason-broke': - case 'reason-score': - case 'reason-loading': - case 'reason-complicated': - var $panel = $('#' + id + '-panel'); - refThis.question.removeClass('wpr-isOpen'); - refThis.return.addClass('wpr-isOpen'); - $panel.addClass('wpr-isOpen'); - - var titleText = $panel.find('h3').text(); - this.title.text(titleText); - break; - - case 'reason-host': - case 'reason-other': - var field = aElem.siblings('.wpr-Modal-fieldHidden'); - field.addClass('wpr-isOpen'); - field.find('input, textarea').focus(); - refThis.button.addClass('wpr-isDisabled'); - refThis.button.attr("disabled", true); - break; - } -}; - - - -/* -* Return to the question -*/ -ModalWpr.prototype.returnToQuestion = function() { - - $('.wpr-Modal-fieldHidden').removeClass('wpr-isOpen'); - $('.wpr-Modal-hidden').removeClass('wpr-isOpen'); - this.question.addClass('wpr-isOpen'); - this.return.removeClass('wpr-isOpen'); - this.title.text(this.titleText); - - // Reset values - this.hiddenReason.val(''); - this.hiddenDetails.val(''); - - this.radio.attr('checked', false); - this.button.addClass('wpr-isDisabled'); - this.button.attr("disabled", true); - -}; - - -/* -* Open modal -*/ -ModalWpr.prototype.open = function() { - - this.elem.css('display','block'); - this.overlay.css('display','block'); - - // Reset current tab wp-rocket - localStorage.setItem('wpr-hash', ''); -}; - - -/* -* Close modal -*/ -ModalWpr.prototype.close = function() { - - this.returnToQuestion(); - this.elem.css('display','none'); - this.overlay.css('display','none'); - -}; diff --git a/wp-content/plugins/wp-rocket/composer.json b/wp-content/plugins/wp-rocket/composer.json index 0e8b76830..a8df0ada8 100644 --- a/wp-content/plugins/wp-rocket/composer.json +++ b/wp-content/plugins/wp-rocket/composer.json @@ -21,52 +21,61 @@ "sort-packages": true, "preferred-install": { "wp-media/phpunit": "source" + }, + "process-timeout": 0, + "allow-plugins": { + "composer/installers": true, + "mnsami/composer-custom-directory-installer": true, + "dealerdirect/phpcodesniffer-composer-installer": true, + "phpstan/extension-installer": true } }, "support": { "issues": "https://github.com/wp-media/wp-rocket/issues", "source": "https://github.com/wp-media/wp-rocket" }, - "repositories":[ + "repositories": [ { "type": "composer", "url": "https://wpackagist.org" } ], "require": { - "php": ">=7.0", - "composer/installers": "~1.0", - "monolog/monolog": "^1.0", - "psr/container": "^1.0" + "php": ">=7.3", + "cloudflare/cf-ip-rewrite": "^1.0", + "composer/installers": "^1.0 || ^2.0" }, "require-dev": { - "php": "^7", + "php": "^7 || ^8", "brain/monkey": "^2.0", - "coenjacobs/mozart": "0.6.0-beta-3", + "coenjacobs/mozart": "^0.7", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", - "mikey179/vfsstream": "^1.6", - "mobiledetect/mobiledetectlib": "^2.8", + "league/container": "^4.2", + "mikey179/vfsstream": "1.6.11", "mnsami/composer-custom-directory-installer": "^2.0", + "mobiledetect/mobiledetectlib": "^2.8", "phpcompatibility/phpcompatibility-wp": "^2.0", - "phpstan/phpstan": "^0.12.3", - "phpunit/phpunit": "^7", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "^7.5 || ^8 || ^9", + "psr/container": "1.1.1", "roave/security-advisories": "dev-master", - "szepeviktor/phpstan-wordpress": "^0.5.0", - "woocommerce/woocommerce": "^3.9", - "wp-coding-standards/wpcs": "^2", + "szepeviktor/phpstan-wordpress": "^1.3", + "woocommerce/action-scheduler": "^3.4", + "wp-coding-standards/wpcs": "^3", "wp-media/background-processing": "^1.3", - "wp-media/cloudflare": "^1.0", - "wp-media/module-rocketcdn": "^1.0", - "wp-media/module-varnish": "^1.0", - "wp-media/rocket-lazyload-common": "^2", - "wp-media/phpunit": "^1.0", + "wp-media/monolog": "^0.0", + "wp-media/phpunit": "^3", + "wp-media/rocket-lazyload-common": "^3.0.11", "wp-media/wp-imagify-partner": "^1.0", "wpackagist-plugin/amp": "^1.1.4", "wpackagist-plugin/hummingbird-performance": "2.0.1", - "wpackagist-plugin/pdf-embedder": "^4.6", + "wpackagist-plugin/jetpack": "9.3.2", + "wpackagist-plugin/pdf-embedder": "4.6.*", "wpackagist-plugin/simple-custom-css": "^4.0.3", "wpackagist-plugin/spinupwp": "^1.1", - "wpackagist-plugin/wp-smushit": "^3.0" + "wpackagist-plugin/woocommerce": "^8", + "wpackagist-plugin/wp-smushit": "^3" }, "autoload": { "classmap": [ @@ -90,10 +99,8 @@ }, "extra": { "installer-paths": { - "vendor/{$vendor}/{$name}/": ["type:wordpress-plugin"], - "./inc/Addon/Cloudflare/": ["wp-media/cloudflare"], - "./inc/Addon/Varnish/": ["wp-media/module-varnish"], - "./inc/Engine/CDN/RocketCDN/": ["wp-media/module-rocketcdn"] + "./inc/Dependencies/ActionScheduler/": ["woocommerce/action-scheduler"], + "vendor/{$vendor}/{$name}/": ["type:wordpress-plugin"] }, "mozart": { "dep_namespace": "WP_Rocket\\Dependencies\\", @@ -104,16 +111,19 @@ "mobiledetect/mobiledetectlib", "wp-media/background-processing", "wp-media/rocket-lazyload-common", - "wp-media/wp-imagify-partner" + "wp-media/wp-imagify-partner", + "wp-media/monolog", + "league/container" ] } }, "scripts": { - "test-unit": "\"vendor/bin/phpunit\" --testsuite unit --colors=always --configuration tests/Unit/phpunit.xml.dist", - "test-integration": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --exclude-group AdminOnly,BeaverBuilder,Elementor,Hummingbird,WithSmush,WithWoo,WithAmp,WithAmpAndCloudflare,WithSCCSS,Cloudways,Dreampress,DoCloudflare,Multisite,WPEngine,SpinUpWP,WordPressCom,O2Switch,PDFEmbedder,PDFEmbedderPremium,PDFEmbedderSecure", + "test-unit": "\"vendor/bin/phpunit\" --testsuite unit --colors=always --configuration tests/Unit/phpunit.xml.dist --coverage-php tests/report/unit.cov", + "test-integration": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --exclude-group AdminOnly,BeaverBuilder,Elementor,Hummingbird,WithSmush,WithWoo,WithAmp,WithAmpAndCloudflare,WithSCCSS,Cloudways,Dreampress,Cloudflare,CloudflareAdmin,Multisite,WPEngine,SpinUpWP,WordPressCom,O2Switch,PDFEmbedder,PDFEmbedderPremium,PDFEmbedderSecure,Godaddy,LiteSpeed,RevolutionSlider,WordFence,ConvertPlug,Kinsta,Jetpack,RankMathSEO,AllInOneSeoPack,SEOPress,TheSEOFramework,OneCom,RocketLazyLoad,WPXCloud,TheEventsCalendar,Perfmatters,RapidLoad,ProIsp,TranslatePress,WPGeotargeting,Weglot,Pressidium --coverage-php tests/report/integration.cov", "test-integration-adminonly": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group AdminOnly", "test-integration-bb": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group BeaverBuilder", - "test-integration-cloudflare": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group DoCloudflare", + "test-integration-cloudflare": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Cloudflare", + "test-integration-cloudflareadmin": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group CloudflareAdmin", "test-integration-cloudways": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Cloudways", "test-integration-elementor": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Elementor", "test-integration-hummingbird": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Hummingbird", @@ -123,7 +133,7 @@ "test-integration-withampcloudflare": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group WithAmpAndCloudflare", "test-integration-withsccss": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group WithSCCSS", "test-integration-withwoo": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group WithWoo", - "test-integration-wpengine": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group WPEngine", + "test-integration-wpengine": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group WPEngine", "test-integration-spinupwp": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group SpinUpWP", "test-integration-wpcom": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group WordPressCom", "test-integration-pdfembedder": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group PDFEmbedder", @@ -131,11 +141,40 @@ "test-integration-pdfembeddersecure": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group PDFEmbedderSecure", "test-integration-o2switch": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group O2Switch", "test-integration-dreampress": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Dreampress", + "test-integration-godaddy": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Godaddy", + "test-integration-revolutionslider": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group RevolutionSlider", + "test-integration-litespeed": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group LiteSpeed", + "test-integration-wordfence": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group WordFence", + "test-integration-kinsta": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Kinsta", + "test-integration-convertplug": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group ConvertPlug", + "test-integration-onecom": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group OneCom", + "test-integration-jetpack": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Jetpack", + "test-integration-rank-math-seo": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group RankMathSEO", + "test-integration-all-in-seo-pack": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group AllInOneSeoPack", + "test-integration-seopress": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group SEOPress", + "test-integration-the-seo-framework": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group TheSEOFramework", + "test-integration-rocket-lazy-load": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group RocketLazyLoad", + "test-integration-the-events-calendar": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group TheEventsCalendar", + "test-integration-wpxcloud": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group WPXCloud", + "test-integration-perfmatters": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Perfmatters", + "test-integration-rapidload": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group RapidLoad", + "test-integration-proisp": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group ProIsp", + "test-integration-wp-geotargeting": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group WPGeotargeting", + "test-integration-translatepress": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group TranslatePress", + "test-integration-weglot": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Weglot", + "test-integration-pressidium": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist --group Pressidium", "run-tests": [ + "@run-tests-general", + "@run-tests-integration-specific" + ], + "run-tests-general": [ "@test-unit", - "@test-integration", + "@test-integration" + ], + "run-tests-integration-specific": [ "@test-integration-adminonly", "@test-integration-cloudflare", + "@test-integration-cloudflareadmin", "@test-integration-bb", "@test-integration-elementor", "@test-integration-hummingbird", @@ -149,13 +188,33 @@ "@test-integration-pdfembeddersecure", "@test-integration-multisite", "@test-integration-cloudways", - "@test-integration-wpengine", + "@test-integration-wpengine", "@test-integration-spinupwp", "@test-integration-wpcom", "@test-integration-o2switch", - "@test-integration-dreampress" + "@test-integration-dreampress", + "@test-integration-godaddy", + "@test-integration-revolutionslider", + "@test-integration-litespeed", + "@test-integration-wordfence", + "@test-integration-kinsta", + "@test-integration-convertplug", + "@test-integration-onecom", + "@test-integration-jetpack", + "@test-integration-rank-math-seo", + "@test-integration-all-in-seo-pack", + "@test-integration-seopress", + "@test-integration-the-events-calendar", + "@test-integration-wpxcloud", + "@test-integration-perfmatters", + "@test-integration-rapidload", + "@test-integration-proisp", + "@test-integration-wp-geotargeting", + "@test-integration-translatepress", + "@test-integration-weglot", + "@test-integration-pressidium" ], - "run-stan":"vendor/bin/phpstan analyze --memory-limit=2G --no-progress", + "run-stan": "vendor/bin/phpstan analyze --memory-limit=2G --no-progress", "install-codestandards": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", "phpcs": "phpcs --basepath=.", "phpcs-changed": "./bin/phpcs-changed.sh", @@ -167,6 +226,7 @@ "post-update-cmd": [ "\"vendor/bin/mozart\" compose", "composer dump-autoload" - ] + ], + "report-code-coverage": "\"vendor/bin/phpcov\" merge tests/report --clover tests/report/coverage.clover" } } diff --git a/wp-content/plugins/wp-rocket/composer.lock b/wp-content/plugins/wp-rocket/composer.lock deleted file mode 100644 index 19f0cfc41..000000000 --- a/wp-content/plugins/wp-rocket/composer.lock +++ /dev/null @@ -1,4625 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "3fef4597ef147dafa0d97cd4d5a3bdd9", - "packages": [ - { - "name": "composer/installers", - "version": "v1.7.0", - "source": { - "type": "git", - "url": "https://github.com/composer/installers.git", - "reference": "141b272484481432cda342727a427dc1e206bfa0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/141b272484481432cda342727a427dc1e206bfa0", - "reference": "141b272484481432cda342727a427dc1e206bfa0", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0" - }, - "replace": { - "roundcube/plugin-installer": "*", - "shama/baton": "*" - }, - "require-dev": { - "composer/composer": "1.0.*@dev", - "phpunit/phpunit": "^4.8.36" - }, - "type": "composer-plugin", - "extra": { - "class": "Composer\\Installers\\Plugin", - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Installers\\": "src/Composer/Installers" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kyle Robinson Young", - "email": "kyle@dontkry.com", - "homepage": "https://github.com/shama" - } - ], - "description": "A multi-framework Composer library installer", - "homepage": "https://composer.github.io/installers/", - "keywords": [ - "Craft", - "Dolibarr", - "Eliasis", - "Hurad", - "ImageCMS", - "Kanboard", - "Lan Management System", - "MODX Evo", - "Mautic", - "Maya", - "OXID", - "Plentymarkets", - "Porto", - "RadPHP", - "SMF", - "Thelia", - "Whmcs", - "WolfCMS", - "agl", - "aimeos", - "annotatecms", - "attogram", - "bitrix", - "cakephp", - "chef", - "cockpit", - "codeigniter", - "concrete5", - "croogo", - "dokuwiki", - "drupal", - "eZ Platform", - "elgg", - "expressionengine", - "fuelphp", - "grav", - "installer", - "itop", - "joomla", - "known", - "kohana", - "laravel", - "lavalite", - "lithium", - "magento", - "majima", - "mako", - "mediawiki", - "modulework", - "modx", - "moodle", - "osclass", - "phpbb", - "piwik", - "ppi", - "puppet", - "pxcms", - "reindex", - "roundcube", - "shopware", - "silverstripe", - "sydes", - "symfony", - "typo3", - "wordpress", - "yawik", - "zend", - "zikula" - ], - "time": "2019-08-12T15:00:31+00:00" - }, - { - "name": "monolog/monolog", - "version": "1.26.0", - "source": { - "type": "git", - "url": "https://github.com/Seldaek/monolog.git", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/2209ddd84e7ef1256b7af205d0717fb62cfc9c33", - "reference": "2209ddd84e7ef1256b7af205d0717fb62cfc9c33", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" - }, - "provide": { - "psr/log-implementation": "1.0.0" - }, - "require-dev": { - "aws/aws-sdk-php": "^2.4.9 || ^3.0", - "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", - "php-amqplib/php-amqplib": "~2.4", - "php-console/php-console": "^3.1.3", - "phpstan/phpstan": "^0.12.59", - "phpunit/phpunit": "~4.5", - "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^0.13", - "swiftmailer/swiftmailer": "^5.3|^6.0" - }, - "suggest": { - "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", - "doctrine/couchdb": "Allow sending log messages to a CouchDB server", - "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", - "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", - "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", - "php-console/php-console": "Allow sending log messages to Google Chrome", - "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "sentry/sentry": "Allow sending log messages to a Sentry server" - }, - "type": "library", - "autoload": { - "psr-4": { - "Monolog\\": "src/Monolog" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", - "keywords": [ - "log", - "logging", - "psr-3" - ], - "funding": [ - { - "url": "https://github.com/Seldaek", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", - "type": "tidelift" - } - ], - "time": "2020-12-14T12:56:38+00:00" - }, - { - "name": "psr/container", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "time": "2017-02-14T16:28:37+00:00" - }, - { - "name": "psr/log", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc", - "reference": "0f73288fd15629204f9d42b7055f72dacbe811fc", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2020-03-23T09:12:05+00:00" - } - ], - "packages-dev": [ - { - "name": "antecedent/patchwork", - "version": "2.1.12", - "source": { - "type": "git", - "url": "https://github.com/antecedent/patchwork.git", - "reference": "b98e046dd4c0acc34a0846604f06f6111654d9ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/antecedent/patchwork/zipball/b98e046dd4c0acc34a0846604f06f6111654d9ea", - "reference": "b98e046dd4c0acc34a0846604f06f6111654d9ea", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": ">=4" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ignas Rudaitis", - "email": "ignas.rudaitis@gmail.com" - } - ], - "description": "Method redefinition (monkey-patching) functionality for PHP.", - "homepage": "http://patchwork2.org/", - "keywords": [ - "aop", - "aspect", - "interception", - "monkeypatching", - "redefinition", - "runkit", - "testing" - ], - "time": "2019-12-22T17:52:09+00:00" - }, - { - "name": "automattic/jetpack-autoloader", - "version": "v1.3.2", - "source": { - "type": "git", - "url": "https://github.com/Automattic/jetpack-autoloader.git", - "reference": "301c2fbcf070d4f0147753447616b6e982bda09e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/301c2fbcf070d4f0147753447616b6e982bda09e", - "reference": "301c2fbcf070d4f0147753447616b6e982bda09e", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5" - }, - "type": "composer-plugin", - "extra": { - "class": "Automattic\\Jetpack\\Autoloader\\CustomAutoloaderPlugin" - }, - "autoload": { - "psr-4": { - "Automattic\\Jetpack\\Autoloader\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0-or-later" - ], - "description": "Creates a custom autoloader for a plugin or theme.", - "time": "2019-09-24T06:39:29+00:00" - }, - { - "name": "brain/monkey", - "version": "2.6.0", - "source": { - "type": "git", - "url": "https://github.com/Brain-WP/BrainMonkey.git", - "reference": "7042140000b4b18034c0c0010d86274a00f25442" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/7042140000b4b18034c0c0010d86274a00f25442", - "reference": "7042140000b4b18034c0c0010d86274a00f25442", - "shasum": "" - }, - "require": { - "antecedent/patchwork": "^2.0", - "mockery/mockery": ">=0.9 <2", - "php": ">=5.6.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || ^0.7", - "phpcompatibility/php-compatibility": "^9.3.0", - "phpunit/phpunit": "^5.7.9 || ^6.0 || ^7.0 || ^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-version/1": "1.x-dev", - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Brain\\Monkey\\": "src/" - }, - "files": [ - "inc/api.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Giuseppe Mazzapica", - "email": "giuseppe.mazzapica@gmail.com", - "homepage": "https://gmazzap.me", - "role": "Developer" - } - ], - "description": "Mocking utility for PHP functions and WordPress plugin API", - "keywords": [ - "Monkey Patching", - "interception", - "mock", - "mock functions", - "mockery", - "patchwork", - "redefinition", - "runkit", - "test", - "testing" - ], - "time": "2020-10-13T17:56:14+00:00" - }, - { - "name": "coenjacobs/mozart", - "version": "0.6.0-beta-3", - "source": { - "type": "git", - "url": "https://github.com/coenjacobs/mozart.git", - "reference": "965d698d76639587b26c878b22f4373c32f3d9ee" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/coenjacobs/mozart/zipball/965d698d76639587b26c878b22f4373c32f3d9ee", - "reference": "965d698d76639587b26c878b22f4373c32f3d9ee", - "shasum": "" - }, - "require": { - "league/flysystem": "^1.0", - "php": "^7.2", - "symfony/console": "^4|^5", - "symfony/finder": "^4|^5" - }, - "require-dev": { - "phpunit/phpunit": "^8.5", - "squizlabs/php_codesniffer": "^3.5" - }, - "bin": [ - "bin/mozart" - ], - "type": "library", - "autoload": { - "psr-4": { - "CoenJacobs\\Mozart\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Coen Jacobs", - "email": "coenjacobs@gmail.com" - } - ], - "description": "Composes all dependencies as a package inside a WordPress plugin", - "funding": [ - { - "url": "https://github.com/coenjacobs", - "type": "github" - } - ], - "time": "2020-06-02T06:54:01+00:00" - }, - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.7.1", - "source": { - "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "fe390591e0241955f22eb9ba327d137e501c771c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/fe390591e0241955f22eb9ba327d137e501c771c", - "reference": "fe390591e0241955f22eb9ba327d137e501c771c", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.0 || ^3.0 || ^4.0" - }, - "require-dev": { - "composer/composer": "*", - "phpcompatibility/php-compatibility": "^9.0", - "sensiolabs/security-checker": "^4.1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" - }, - "autoload": { - "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" - } - ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], - "time": "2020-12-07T18:04:37+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", - "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^8.0", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", - "phpstan/phpstan": "^0.12", - "phpstan/phpstan-phpunit": "^0.12", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2020-11-10T18:47:58+00:00" - }, - { - "name": "hamcrest/hamcrest-php", - "version": "v2.0.1", - "source": { - "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", - "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", - "shasum": "" - }, - "require": { - "php": "^5.3|^7.0|^8.0" - }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" - }, - "require-dev": { - "phpunit/php-file-iterator": "^1.4 || ^2.0", - "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1-dev" - } - }, - "autoload": { - "classmap": [ - "hamcrest" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "This is the PHP port of Hamcrest Matchers", - "keywords": [ - "test" - ], - "time": "2020-07-09T08:09:16+00:00" - }, - { - "name": "league/flysystem", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "9be3b16c877d477357c015cec057548cf9b2a14a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/9be3b16c877d477357c015cec057548cf9b2a14a", - "reference": "9be3b16c877d477357c015cec057548cf9b2a14a", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "league/mime-type-detection": "^1.3", - "php": "^7.2.5 || ^8.0" - }, - "conflict": { - "league/flysystem-sftp": "<1.0.6" - }, - "require-dev": { - "phpspec/prophecy": "^1.11.1", - "phpunit/phpunit": "^8.5.8" - }, - "suggest": { - "ext-fileinfo": "Required for MimeType", - "ext-ftp": "Allows you to use FTP server storage", - "ext-openssl": "Allows you to use FTPS server storage", - "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", - "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", - "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", - "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", - "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", - "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", - "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", - "league/flysystem-webdav": "Allows you to use WebDAV storage", - "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", - "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", - "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "psr-4": { - "League\\Flysystem\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frank de Jonge", - "email": "info@frenky.net" - } - ], - "description": "Filesystem abstraction: Many filesystems, one API.", - "keywords": [ - "Cloud Files", - "WebDAV", - "abstraction", - "aws", - "cloud", - "copy.com", - "dropbox", - "file systems", - "files", - "filesystem", - "filesystems", - "ftp", - "rackspace", - "remote", - "s3", - "sftp", - "storage" - ], - "funding": [ - { - "url": "https://offset.earth/frankdejonge", - "type": "other" - } - ], - "time": "2020-08-23T07:39:11+00:00" - }, - { - "name": "league/mime-type-detection", - "version": "1.5.1", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "353f66d7555d8a90781f6f5e7091932f9a4250aa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/353f66d7555d8a90781f6f5e7091932f9a4250aa", - "reference": "353f66d7555d8a90781f6f5e7091932f9a4250aa", - "shasum": "" - }, - "require": { - "ext-fileinfo": "*", - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.36", - "phpunit/phpunit": "^8.5.8" - }, - "type": "library", - "autoload": { - "psr-4": { - "League\\MimeTypeDetection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Frank de Jonge", - "email": "info@frankdejonge.nl" - } - ], - "description": "Mime-type detection for Flysystem", - "funding": [ - { - "url": "https://github.com/frankdejonge", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/league/flysystem", - "type": "tidelift" - } - ], - "time": "2020-10-18T11:50:25+00:00" - }, - { - "name": "maxmind-db/reader", - "version": "v1.6.0", - "source": { - "type": "git", - "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git", - "reference": "febd4920bf17c1da84cef58e56a8227dfb37fbe4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/febd4920bf17c1da84cef58e56a8227dfb37fbe4", - "reference": "febd4920bf17c1da84cef58e56a8227dfb37fbe4", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "conflict": { - "ext-maxminddb": "<1.6.0,>=2.0.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "2.*", - "php-coveralls/php-coveralls": "^2.1", - "phpunit/phpcov": "^3.0", - "phpunit/phpunit": "5.*", - "squizlabs/php_codesniffer": "3.*" - }, - "suggest": { - "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", - "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder", - "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups" - }, - "type": "library", - "autoload": { - "psr-4": { - "MaxMind\\Db\\": "src/MaxMind/Db" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Gregory J. Oschwald", - "email": "goschwald@maxmind.com", - "homepage": "https://www.maxmind.com/" - } - ], - "description": "MaxMind DB Reader API", - "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php", - "keywords": [ - "database", - "geoip", - "geoip2", - "geolocation", - "maxmind" - ], - "time": "2019-12-19T22:59:03+00:00" - }, - { - "name": "mikey179/vfsstream", - "version": "v1.6.8", - "source": { - "type": "git", - "url": "https://github.com/bovigo/vfsStream.git", - "reference": "231c73783ebb7dd9ec77916c10037eff5a2b6efe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/bovigo/vfsStream/zipball/231c73783ebb7dd9ec77916c10037eff5a2b6efe", - "reference": "231c73783ebb7dd9ec77916c10037eff5a2b6efe", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.5|^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, - "autoload": { - "psr-0": { - "org\\bovigo\\vfs\\": "src/main/php" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Frank Kleine", - "homepage": "http://frankkleine.de/", - "role": "Developer" - } - ], - "description": "Virtual file system to mock the real file system in unit tests.", - "homepage": "http://vfs.bovigo.org/", - "time": "2019-10-30T15:31:00+00:00" - }, - { - "name": "mnsami/composer-custom-directory-installer", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/mnsami/composer-custom-directory-installer.git", - "reference": "85f66323978d0b1cb0e6acc7f69b3e7b912f82d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mnsami/composer-custom-directory-installer/zipball/85f66323978d0b1cb0e6acc7f69b3e7b912f82d9", - "reference": "85f66323978d0b1cb0e6acc7f69b3e7b912f82d9", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3" - }, - "type": "composer-plugin", - "extra": { - "class": [ - "Composer\\CustomDirectoryInstaller\\LibraryPlugin", - "Composer\\CustomDirectoryInstaller\\PearPlugin", - "Composer\\CustomDirectoryInstaller\\PluginPlugin" - ], - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-0": { - "Composer\\CustomDirectoryInstaller": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mina Nabil Sami", - "email": "mina.nsami@gmail.com" - } - ], - "description": "A composer plugin, to help install packages of different types in custom paths.", - "keywords": [ - "composer", - "composer-installer", - "composer-plugin" - ], - "time": "2020-08-18T11:00:11+00:00" - }, - { - "name": "mobiledetect/mobiledetectlib", - "version": "2.8.34", - "source": { - "type": "git", - "url": "https://github.com/serbanghita/Mobile-Detect.git", - "reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/6f8113f57a508494ca36acbcfa2dc2d923c7ed5b", - "reference": "6f8113f57a508494ca36acbcfa2dc2d923c7ed5b", - "shasum": "" - }, - "require": { - "php": ">=5.0.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.8.35||~5.7" - }, - "type": "library", - "autoload": { - "classmap": [ - "Mobile_Detect.php" - ], - "psr-0": { - "Detection": "namespaced/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Serban Ghita", - "email": "serbanghita@gmail.com", - "homepage": "http://mobiledetect.net", - "role": "Developer" - } - ], - "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", - "homepage": "https://github.com/serbanghita/Mobile-Detect", - "keywords": [ - "detect mobile devices", - "mobile", - "mobile detect", - "mobile detector", - "php mobile detect" - ], - "time": "2019-09-18T18:44:20+00:00" - }, - { - "name": "mockery/mockery", - "version": "1.3.3", - "source": { - "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "60fa2f67f6e4d3634bb4a45ff3171fa52215800d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/60fa2f67f6e4d3634bb4a45ff3171fa52215800d", - "reference": "60fa2f67f6e4d3634bb4a45ff3171fa52215800d", - "shasum": "" - }, - "require": { - "hamcrest/hamcrest-php": "^2.0.1", - "lib-pcre": ">=7.0", - "php": ">=5.6.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.10|^6.5|^7.5|^8.5|^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "psr-0": { - "Mockery": "library/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" - }, - { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" - } - ], - "description": "Mockery is a simple yet flexible PHP mock object framework", - "homepage": "https://github.com/mockery/mockery", - "keywords": [ - "BDD", - "TDD", - "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" - ], - "time": "2020-08-11T18:10:21+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.10.2", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", - "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "replace": { - "myclabs/deep-copy": "self.version" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, - "files": [ - "src/DeepCopy/deep_copy.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2020-11-13T09:40:50+00:00" - }, - { - "name": "phar-io/manifest", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-phar": "*", - "phar-io/version": "^2.0", - "php": "^5.6 || ^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2018-07-08T19:23:20+00:00" - }, - { - "name": "phar-io/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "time": "2018-07-08T19:19:57+00:00" - }, - { - "name": "php-stubs/wordpress-stubs", - "version": "v5.6.0", - "source": { - "type": "git", - "url": "https://github.com/php-stubs/wordpress-stubs.git", - "reference": "ed446cce304cd49f13900274b3ed60d1b526297e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/ed446cce304cd49f13900274b3ed60d1b526297e", - "reference": "ed446cce304cd49f13900274b3ed60d1b526297e", - "shasum": "" - }, - "replace": { - "giacocorsiglia/wordpress-stubs": "*" - }, - "require-dev": { - "giacocorsiglia/stubs-generator": "^0.5.0", - "php": "~7.1" - }, - "suggest": { - "paragonie/sodium_compat": "Pure PHP implementation of libsodium", - "symfony/polyfill-php73": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "WordPress function and class declaration stubs for static analysis.", - "homepage": "https://github.com/php-stubs/wordpress-stubs", - "keywords": [ - "PHPStan", - "static analysis", - "wordpress" - ], - "time": "2020-12-09T00:38:16+00:00" - }, - { - "name": "phpcompatibility/php-compatibility", - "version": "9.3.5", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" - }, - "conflict": { - "squizlabs/php_codesniffer": "2.6.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "homepage": "https://github.com/wimg", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", - "role": "lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" - } - ], - "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", - "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", - "keywords": [ - "compatibility", - "phpcs", - "standards" - ], - "time": "2019-12-27T09:44:58+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-paragonie", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", - "reference": "b862bc32f7e860d0b164b199bd995e690b4b191c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b862bc32f7e860d0b164b199bd995e690b4b191c", - "reference": "b862bc32f7e860d0b164b199bd995e690b4b191c", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5", - "paragonie/random_compat": "dev-master", - "paragonie/sodium_compat": "dev-master" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "paragonie", - "phpcs", - "polyfill", - "standards" - ], - "time": "2019-11-04T15:17:54+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-wp", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", - "reference": "41bef18ba688af638b7310666db28e1ea9158b2f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f", - "reference": "41bef18ba688af638b7310666db28e1ea9158b2f", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0", - "phpcompatibility/phpcompatibility-paragonie": "^1.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "phpcs", - "standards", - "wordpress" - ], - "time": "2019-08-28T14:22:28+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2020-09-03T19:13:55+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2020-09-17T18:55:26+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "1.12.2", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "245710e971a030f42e08f4912863805570f23d39" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/245710e971a030f42e08f4912863805570f23d39", - "reference": "245710e971a030f42e08f4912863805570f23d39", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0", - "sebastian/recursion-context": "^3.0 || ^4.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0", - "phpunit/phpunit": "^8.0 || ^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2020-12-19T10:15:11+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "0.12.64", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "23eb1cb7ae125f45f1d0e48051bcf67a9a9b08aa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/23eb1cb7ae125f45f1d0e48051bcf67a9a9b08aa", - "reference": "23eb1cb7ae125f45f1d0e48051bcf67a9a9b08aa", - "shasum": "" - }, - "require": { - "php": "^7.1|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.12-dev" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://www.patreon.com/phpstan", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" - } - ], - "time": "2020-12-21T11:59:02+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "6.1.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": "^7.1", - "phpunit/php-file-iterator": "^2.0", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.1 || ^4.0", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "suggest": { - "ext-xdebug": "^2.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2018-10-31T16:06:48+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4b49fb70f067272b659ef0174ff9ca40fdaa6357", - "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "^8.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T08:25:21+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "2.1.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", - "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "^8.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T08:20:02+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "3.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "472b687829041c24b25f475e14c2f38a09edf1c2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/472b687829041c24b25f475e14c2f38a09edf1c2", - "reference": "472b687829041c24b25f475e14c2f38a09edf1c2", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "abandoned": true, - "time": "2020-11-30T08:38:46+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "7.5.20", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "9467db479d1b0487c99733bb1e7944d32deded2c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c", - "reference": "9467db479d1b0487c99733bb1e7944d32deded2c", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.1", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "myclabs/deep-copy": "^1.7", - "phar-io/manifest": "^1.0.2", - "phar-io/version": "^2.0", - "php": "^7.1", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^6.0.7", - "phpunit/php-file-iterator": "^2.0.1", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1", - "sebastian/comparator": "^3.0", - "sebastian/diff": "^3.0", - "sebastian/environment": "^4.0", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0", - "sebastian/version": "^2.0.1" - }, - "conflict": { - "phpunit/phpunit-mock-objects": "*" - }, - "require-dev": { - "ext-pdo": "*" - }, - "suggest": { - "ext-soap": "*", - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "7.5-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2020-01-08T08:45:45+00:00" - }, - { - "name": "roave/security-advisories", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "49da07b20a780d3fca9fe12e1db27975a2910c18" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/49da07b20a780d3fca9fe12e1db27975a2910c18", - "reference": "49da07b20a780d3fca9fe12e1db27975a2910c18", - "shasum": "" - }, - "conflict": { - "3f/pygmentize": "<1.2", - "adodb/adodb-php": "<5.20.12", - "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", - "amphp/artax": "<1.0.6|>=2,<2.0.6", - "amphp/http": "<1.0.1", - "amphp/http-client": ">=4,<4.4", - "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6", - "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99", - "aws/aws-sdk-php": ">=3,<3.2.1", - "bagisto/bagisto": "<0.1.5", - "barrelstrength/sprout-base-email": "<1.2.7", - "barrelstrength/sprout-forms": "<3.9", - "baserproject/basercms": ">=4,<=4.3.6|>=4.4,<4.4.1", - "bolt/bolt": "<3.7.1", - "brightlocal/phpwhois": "<=4.2.5", - "buddypress/buddypress": "<5.1.2", - "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "cakephp/cakephp": ">=1.3,<1.3.18|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=2.7,<2.7.6|>=3,<3.5.18|>=3.6,<3.6.15|>=3.7,<3.7.7", - "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", - "cartalyst/sentry": "<=2.1.6", - "centreon/centreon": "<18.10.8|>=19,<19.4.5", - "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "codeigniter/framework": "<=3.0.6", - "composer/composer": "<=1-alpha.11", - "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/core": ">=2,<3.5.39", - "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.6|= 4.10.0", - "contao/listing-bundle": ">=4,<4.4.8", - "datadog/dd-trace": ">=0.30,<0.30.2", - "david-garcia/phpwhois": "<=4.3.1", - "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1", - "doctrine/annotations": ">=1,<1.2.7", - "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", - "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2", - "doctrine/doctrine-bundle": "<1.5.2", - "doctrine/doctrine-module": "<=0.7.1", - "doctrine/mongodb-odm": ">=1,<1.0.2", - "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", - "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", - "dolibarr/dolibarr": "<11.0.4", - "dompdf/dompdf": ">=0.6,<0.6.2", - "drupal/core": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", - "drupal/drupal": ">=7,<7.74|>=8,<8.8.11|>=8.9,<8.9.9|>=9,<9.0.8", - "endroid/qr-code-bundle": "<3.4.2", - "enshrined/svg-sanitize": "<0.13.1", - "erusev/parsedown": "<1.7.2", - "ezsystems/demobundle": ">=5.4,<5.4.6.1", - "ezsystems/ez-support-tools": ">=2.2,<2.2.3", - "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1", - "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1", - "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4", - "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6", - "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1", - "ezsystems/ezplatform-kernel": ">=1,<1.0.2.1", - "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.2|>=6,<6.7.9.1|>=6.8,<6.13.6.3|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.7.1", - "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1", - "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1", - "ezyang/htmlpurifier": "<4.1.1", - "firebase/php-jwt": "<2", - "fooman/tcpdf": "<6.2.22", - "fossar/tcpdf-parser": "<6.2.22", - "friendsofsymfony/oauth2-php": "<1.3", - "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", - "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", - "fuel/core": "<1.8.1", - "getgrav/grav": "<1.7-beta.8", - "getkirby/cms": ">=3,<3.4.5", - "getkirby/panel": "<2.5.14", - "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", - "gree/jose": "<=2.2", - "gregwar/rst": "<1.0.3", - "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1", - "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10", - "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4", - "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29|>=5.5,<=5.5.44|>=6,<6.18.34|>=7,<7.23.2", - "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", - "illuminate/view": ">=7,<7.1.2", - "ivankristianto/phpwhois": "<=4.3", - "james-heinrich/getid3": "<1.9.9", - "joomla/session": "<1.3.1", - "jsmitty12/phpwhois": "<5.1", - "kazist/phpwhois": "<=4.2.6", - "kitodo/presentation": "<3.1.2", - "kreait/firebase-php": ">=3.2,<3.8.1", - "la-haute-societe/tcpdf": "<6.2.22", - "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.34|>=7,<7.23.2", - "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", - "league/commonmark": "<0.18.3", - "librenms/librenms": "<1.53", - "livewire/livewire": ">2.2.4,<2.2.6", - "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3", - "magento/magento1ce": "<1.9.4.3", - "magento/magento1ee": ">=1,<1.14.4.3", - "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2", - "marcwillmann/turn": "<0.3.3", - "mediawiki/core": ">=1.27,<1.27.6|>=1.29,<1.29.3|>=1.30,<1.30.2|>=1.31,<1.31.9|>=1.32,<1.32.6|>=1.32.99,<1.33.3|>=1.33.99,<1.34.3|>=1.34.99,<1.35", - "mittwald/typo3_forum": "<1.2.1", - "monolog/monolog": ">=1.8,<1.12", - "namshi/jose": "<2.2", - "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", - "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "nystudio107/craft-seomatic": "<3.3", - "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", - "october/backend": ">=1.0.319,<1.0.470", - "october/cms": "= 1.0.469|>=1.0.319,<1.0.469", - "october/october": ">=1.0.319,<1.0.466", - "october/rain": ">=1.0.319,<1.0.468", - "onelogin/php-saml": "<2.10.4", - "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5", - "openid/php-openid": "<2.3", - "openmage/magento-lts": "<19.4.8|>=20,<20.0.4", - "orchid/platform": ">=9,<9.4.4", - "oro/crm": ">=1.7,<1.7.4", - "oro/platform": ">=1.7,<1.7.4", - "padraic/humbug_get_contents": "<1.1.2", - "pagarme/pagarme-php": ">=0,<3", - "paragonie/random_compat": "<2", - "passbolt/passbolt_api": "<2.11", - "paypal/merchant-sdk-php": "<3.12", - "pear/archive_tar": "<1.4.11", - "personnummer/personnummer": "<3.0.2", - "phpfastcache/phpfastcache": ">=5,<5.0.13", - "phpmailer/phpmailer": "<6.1.6", - "phpmussel/phpmussel": ">=1,<1.6", - "phpmyadmin/phpmyadmin": "<4.9.6|>=5,<5.0.3", - "phpoffice/phpexcel": "<1.8.2", - "phpoffice/phpspreadsheet": "<1.8", - "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", - "phpwhois/phpwhois": "<=4.2.5", - "phpxmlrpc/extras": "<0.6.1", - "pimcore/pimcore": "<6.3", - "pocketmine/pocketmine-mp": "<3.15.4", - "prestashop/autoupgrade": ">=4,<4.10.1", - "prestashop/contactform": ">1.0.1,<4.3", - "prestashop/gamification": "<2.3.2", - "prestashop/productcomments": ">=4,<4.2", - "prestashop/ps_facetedsearch": "<3.4.1", - "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2", - "propel/propel": ">=2-alpha.1,<=2-alpha.7", - "propel/propel1": ">=1,<=1.7.1", - "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6", - "pusher/pusher-php-server": "<2.2.1", - "rainlab/debugbar-plugin": "<3.1", - "robrichards/xmlseclibs": "<3.0.4", - "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", - "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", - "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11", - "sensiolabs/connect": "<4.2.3", - "serluck/phpwhois": "<=4.2.6", - "shopware/core": "<=6.3.4", - "shopware/platform": "<=6.3.4", - "shopware/shopware": "<5.6.9", - "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1", - "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2", - "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4", - "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1", - "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<4.4.7|>=4.5,<4.5.4", - "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2|>=3.2,<3.2.4", - "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", - "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4", - "silverstripe/subsites": ">=2,<2.1.1", - "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", - "silverstripe/userforms": "<3", - "simple-updates/phpwhois": "<=1", - "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4", - "simplesamlphp/simplesamlphp": "<1.18.6", - "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", - "simplito/elliptic-php": "<1.0.6", - "slim/slim": "<2.6", - "smarty/smarty": "<3.1.33", - "socalnick/scn-social-auth": "<1.15.2", - "spoonity/tcpdf": "<6.2.22", - "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<0.29.2", - "stormpath/sdk": ">=0,<9.9.99", - "studio-42/elfinder": "<2.1.49", - "sulu/sulu": "<1.6.34|>=2,<2.0.10|>=2.1,<2.1.1", - "swiftmailer/swiftmailer": ">=4,<5.4.5", - "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", - "sylius/sylius": "<1.6.9|>=1.7,<1.7.9|>=1.8,<1.8.3", - "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99", - "symbiote/silverstripe-versionedfiles": "<=2.0.3", - "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", - "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", - "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/mime": ">=4.3,<4.3.8", - "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/polyfill": ">=1,<1.10", - "symfony/polyfill-php55": ">=1,<1.10", - "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/security-bundle": ">=2,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<2.8.37|>=3,<3.3.17|>=3.4,<3.4.7|>=4,<4.0.7", - "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7", - "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5", - "symfony/translation": ">=2,<2.0.17", - "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", - "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", - "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", - "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", - "t3g/svg-sanitizer": "<1.0.3", - "tecnickcom/tcpdf": "<6.2.22", - "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1-beta.1,<2.1.3", - "theonedemon/phpwhois": "<=4.2.5", - "titon/framework": ">=0,<9.9.99", - "truckersmp/phpwhois": "<=4.3.1", - "twig/twig": "<1.38|>=2,<2.7", - "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.38|>=9,<9.5.23|>=10,<10.4.10", - "typo3/cms-core": ">=8,<8.7.38|>=9,<9.5.23|>=10,<10.4.10", - "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", - "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", - "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", - "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", - "ua-parser/uap-php": "<3.8", - "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", - "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4", - "wallabag/tcpdf": "<6.2.22", - "willdurand/js-translation-bundle": "<2.1.1", - "yii2mod/yii2-cms": "<1.9.2", - "yiisoft/yii": ">=1.1.14,<1.1.15", - "yiisoft/yii2": "<2.0.38", - "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<2.0.15", - "yiisoft/yii2-elasticsearch": "<2.0.5", - "yiisoft/yii2-gii": "<2.0.4", - "yiisoft/yii2-jui": "<2.0.4", - "yiisoft/yii2-redis": "<2.0.8", - "yourls/yourls": "<1.7.4", - "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", - "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-db": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.10|>=2.3,<2.3.5", - "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", - "zendframework/zend-diactoros": ">=1,<1.8.4", - "zendframework/zend-feed": ">=1,<2.10.3", - "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-http": ">=1,<2.8.1", - "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", - "zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2", - "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4", - "zendframework/zend-validator": ">=2.3,<2.3.6", - "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": "<2.5.1", - "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": ">=2,<2.0.2", - "zendframework/zendxml": ">=1,<1.0.1", - "zetacomponents/mail": "<1.8.2", - "zf-commons/zfc-user": "<1.2.2", - "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", - "zfr/zfr-oauth2-server-module": "<0.1.2" - }, - "type": "metapackage", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "role": "maintainer" - }, - { - "name": "Ilya Tribusean", - "email": "slash3b@gmail.com", - "role": "maintainer" - } - ], - "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "funding": [ - { - "url": "https://github.com/Ocramius", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", - "type": "tidelift" - } - ], - "time": "2020-12-21T18:11:20+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", - "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "phpunit/phpunit": "^8.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T08:15:22+00:00" - }, - { - "name": "sebastian/comparator", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "1071dfcef776a57013124ff35e1fc41ccd294758" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1071dfcef776a57013124ff35e1fc41ccd294758", - "reference": "1071dfcef776a57013124ff35e1fc41ccd294758", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" - }, - "require-dev": { - "phpunit/phpunit": "^8.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T08:04:30+00:00" - }, - { - "name": "sebastian/diff", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211", - "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T07:59:04+00:00" - }, - { - "name": "sebastian/environment", - "version": "4.2.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", - "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.5" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T07:53:42+00:00" - }, - { - "name": "sebastian/exporter", - "version": "3.1.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/6b853149eab67d4da22291d36f5b0631c0fd856e", - "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e", - "shasum": "" - }, - "require": { - "php": ">=7.0", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T07:47:53+00:00" - }, - { - "name": "sebastian/global-state", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2017-04-27T15:39:26+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "3.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", - "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", - "shasum": "" - }, - "require": { - "php": ">=7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T07:40:27+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", - "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", - "shasum": "" - }, - "require": { - "php": ">=7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T07:37:18+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "3.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", - "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", - "shasum": "" - }, - "require": { - "php": ">=7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T07:34:24+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", - "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-11-30T07:30:19+00:00" - }, - { - "name": "sebastian/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.5.8", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9d583721a7157ee997f235f327de038e7ea6dac4", - "reference": "9d583721a7157ee997f235f327de038e7ea6dac4", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "bin": [ - "bin/phpcs", - "bin/phpcbf" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards" - ], - "time": "2020-10-23T02:01:07+00:00" - }, - { - "name": "symfony/console", - "version": "v5.2.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "47c02526c532fb381374dab26df05e7313978976" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/47c02526c532fb381374dab26df05e7313978976", - "reference": "47c02526c532fb381374dab26df05e7313978976", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.15", - "symfony/service-contracts": "^1.1|^2", - "symfony/string": "^5.1" - }, - "conflict": { - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Console Component", - "homepage": "https://symfony.com", - "keywords": [ - "cli", - "command line", - "console", - "terminal" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-12-18T08:03:05+00:00" - }, - { - "name": "symfony/finder", - "version": "v5.2.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/0b9231a5922fd7287ba5b411893c0ecd2733e5ba", - "reference": "0b9231a5922fd7287ba5b411893c0ecd2733e5ba", - "shasum": "" - }, - "require": { - "php": ">=7.2.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Finder Component", - "homepage": "https://symfony.com", - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-12-08T17:02:38+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.20.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f4ba089a5b6366e453971d3aad5fe8e897b37f41", - "reference": "f4ba089a5b6366e453971d3aad5fe8e897b37f41", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.20-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-23T14:02:19+00:00" - }, - { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.20.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", - "reference": "c7cf3f858ec7d70b89559d6e6eb1f7c2517d479c", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.20-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's grapheme_* functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-23T14:02:19+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.20.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "727d1096295d807c309fb01a851577302394c897" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/727d1096295d807c309fb01a851577302394c897", - "reference": "727d1096295d807c309fb01a851577302394c897", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.20-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-23T14:02:19+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.20.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "39d483bdf39be819deabf04ec872eb0b2410b531" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/39d483bdf39be819deabf04ec872eb0b2410b531", - "reference": "39d483bdf39be819deabf04ec872eb0b2410b531", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.20-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-23T14:02:19+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "v1.20.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/8ff431c517be11c78c48a39a66d37431e26a6bed", - "reference": "8ff431c517be11c78c48a39a66d37431e26a6bed", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.20-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-23T14:02:19+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.20.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/e70aa8b064c5b72d3df2abd5ab1e90464ad009de", - "reference": "e70aa8b064c5b72d3df2abd5ab1e90464ad009de", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.20-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-10-23T14:02:19+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v2.2.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", - "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/container": "^1.0" - }, - "suggest": { - "symfony/service-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.2-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-09-07T11:33:47+00:00" - }, - { - "name": "symfony/string", - "version": "v5.2.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", - "reference": "5bd67751d2e3f7d6f770c9154b8fbcb2aa05f7ed", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" - }, - "require-dev": { - "symfony/error-handler": "^4.4|^5.0", - "symfony/http-client": "^4.4|^5.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "files": [ - "Resources/functions.php" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony String component", - "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-12-05T07:33:16+00:00" - }, - { - "name": "szepeviktor/phpstan-wordpress", - "version": "v0.5.0", - "source": { - "type": "git", - "url": "https://github.com/szepeviktor/phpstan-wordpress.git", - "reference": "1946738cdec130df4727f780ac541f8c6fd746a2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/1946738cdec130df4727f780ac541f8c6fd746a2", - "reference": "1946738cdec130df4727f780ac541f8c6fd746a2", - "shasum": "" - }, - "require": { - "php": "~7.1", - "php-stubs/wordpress-stubs": "^4.7 || ^5.0", - "phpstan/phpstan": "^0.12.0", - "symfony/polyfill-php73": "^1.12.0" - }, - "require-dev": { - "composer/composer": "^1.8.6", - "consistence/coding-standard": "^3.8", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5", - "jakub-onderka/php-parallel-lint": "^1.0", - "phpstan/phpstan-strict-rules": "^0.12", - "slevomat/coding-standard": "^5.0.4" - }, - "type": "phpstan-extension", - "extra": { - "phpstan": { - "includes": [ - "extension.neon" - ] - } - }, - "autoload": { - "psr-4": { - "PHPStan\\WordPress\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "WordPress extensions for PHPStan", - "keywords": [ - "PHPStan", - "code analyse", - "code analysis", - "static analysis", - "wordpress" - ], - "time": "2019-12-05T22:19:53+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2020-07-12T23:59:07+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.9.1", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" - }, - "type": "library", - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2020-07-08T17:02:28+00:00" - }, - { - "name": "woocommerce/woocommerce", - "version": "3.9.3", - "source": { - "type": "git", - "url": "https://github.com/woocommerce/woocommerce.git", - "reference": "310a620134199758e071ad00690816a95ced2100" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce/zipball/310a620134199758e071ad00690816a95ced2100", - "reference": "310a620134199758e071ad00690816a95ced2100", - "shasum": "" - }, - "require": { - "automattic/jetpack-autoloader": "^1.2.0", - "composer/installers": "1.7.0", - "maxmind-db/reader": "1.6.0", - "php": ">=5.6|>=7.0", - "woocommerce/woocommerce-blocks": "2.5.14", - "woocommerce/woocommerce-rest-api": "1.0.7" - }, - "require-dev": { - "phpunit/phpunit": "7.5.18", - "woocommerce/woocommerce-sniffs": "0.0.9" - }, - "type": "wordpress-plugin", - "extra": { - "installer-paths": { - "packages/woocommerce-rest-api": [ - "woocommerce/woocommerce-rest-api" - ], - "packages/woocommerce-blocks": [ - "woocommerce/woocommerce-blocks" - ] - }, - "scripts-description": { - "test": "Run unit tests", - "phpcs": "Analyze code against the WordPress coding standards with PHP_CodeSniffer", - "phpcbf": "Fix coding standards warnings/errors automatically with PHP Code Beautifier" - } - }, - "autoload": { - "exclude-from-classmap": [ - "includes/legacy", - "includes/libraries" - ], - "psr-4": { - "Automattic\\WooCommerce\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0-or-later" - ], - "description": "An eCommerce toolkit that helps you sell anything. Beautifully.", - "homepage": "https://woocommerce.com/", - "time": "2020-03-04T09:08:17+00:00" - }, - { - "name": "woocommerce/woocommerce-blocks", - "version": "v2.5.14", - "source": { - "type": "git", - "url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git", - "reference": "0dd70617085d2e73f3adfb38df98a90df3514816" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/0dd70617085d2e73f3adfb38df98a90df3514816", - "reference": "0dd70617085d2e73f3adfb38df98a90df3514816", - "shasum": "" - }, - "require": { - "automattic/jetpack-autoloader": "1.3.2", - "composer/installers": "1.7.0" - }, - "require-dev": { - "phpunit/phpunit": "6.5.14", - "woocommerce/woocommerce-sniffs": "0.0.7" - }, - "type": "wordpress-plugin", - "extra": { - "scripts-description": { - "phpcs": "Analyze code against the WordPress coding standards with PHP_CodeSniffer", - "phpcbf": "Fix coding standards warnings/errors automatically with PHP Code Beautifier" - } - }, - "autoload": { - "psr-4": { - "Automattic\\WooCommerce\\Blocks\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0-or-later" - ], - "description": "WooCommerce blocks for the Gutenberg editor.", - "homepage": "https://woocommerce.com/", - "keywords": [ - "blocks", - "gutenberg", - "woocommerce" - ], - "time": "2020-03-03T13:25:56+00:00" - }, - { - "name": "woocommerce/woocommerce-rest-api", - "version": "1.0.7", - "source": { - "type": "git", - "url": "https://github.com/woocommerce/woocommerce-rest-api.git", - "reference": "49162ec26a25bd0c6efc0f3452b113cdfff0a823" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-rest-api/zipball/49162ec26a25bd0c6efc0f3452b113cdfff0a823", - "reference": "49162ec26a25bd0c6efc0f3452b113cdfff0a823", - "shasum": "" - }, - "require": { - "automattic/jetpack-autoloader": "^1.2.0" - }, - "require-dev": { - "phpunit/phpunit": "6.5.14", - "woocommerce/woocommerce-sniffs": "0.0.9" - }, - "type": "wordpress-plugin", - "autoload": { - "classmap": [ - "src/Controllers/Version1", - "src/Controllers/Version2", - "src/Controllers/Version3" - ], - "psr-4": { - "Automattic\\WooCommerce\\RestApi\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0-or-later" - ], - "description": "The WooCommerce core REST API.", - "homepage": "https://github.com/woocommerce/woocommerce-rest-api", - "abandoned": true, - "time": "2020-01-28T21:04:51+00:00" - }, - { - "name": "wp-coding-standards/wpcs", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "7da1894633f168fe244afc6de00d141f27517b62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62", - "reference": "7da1894633f168fe244afc6de00d141f27517b62", - "shasum": "" - }, - "require": { - "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.3.1" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", - "phpcompatibility/php-compatibility": "^9.0", - "phpcsstandards/phpcsdevtools": "^1.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Contributors", - "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", - "keywords": [ - "phpcs", - "standards", - "wordpress" - ], - "time": "2020-05-13T23:57:56+00:00" - }, - { - "name": "wp-media/background-processing", - "version": "v1.3.1", - "source": { - "type": "git", - "url": "https://github.com/wp-media/background-processing.git", - "reference": "20979ca3bc258bb97a526c2c4aff61254872bfea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-media/background-processing/zipball/20979ca3bc258bb97a526c2c4aff61254872bfea", - "reference": "20979ca3bc258bb97a526c2c4aff61254872bfea", - "shasum": "" - }, - "require-dev": { - "brain/monkey": "^2.0", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "php": "^5.6 || ^7", - "phpcompatibility/phpcompatibility-wp": "^2.0", - "phpunit/phpunit": "^5.7 || ^7", - "wp-coding-standards/wpcs": "^2", - "wp-media/phpunit": "^1.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "authors": [ - { - "name": "WP Media", - "email": "contact@wp-media.me", - "homepage": "https://wp-media.me" - } - ], - "description": "Async & Background Tasks Processing", - "homepage": "https://github.com/wp-media/background-processing", - "time": "2020-08-21T13:47:06+00:00" - }, - { - "name": "wp-media/cloudflare", - "version": "v1.0", - "source": { - "type": "git", - "url": "https://github.com/wp-media/module-cloudflare.git", - "reference": "2fa5d2c99e7696d71885bda1c14e49e3ff0d5e3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-media/module-cloudflare/zipball/2fa5d2c99e7696d71885bda1c14e49e3ff0d5e3e", - "reference": "2fa5d2c99e7696d71885bda1c14e49e3ff0d5e3e", - "shasum": "" - }, - "require-dev": { - "brain/monkey": "^2.0", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "php": "^5.6 || ^7", - "phpcompatibility/phpcompatibility-wp": "^2.0", - "phpunit/phpunit": "^5.7 || ^7", - "wp-coding-standards/wpcs": "^2", - "wp-media/event-manager": "^3.1", - "wp-media/options": "^3.0", - "wp-media/phpunit": "^1.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "WPMedia\\Cloudflare\\": "." - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "authors": [ - { - "name": "WP Media", - "email": "contact@wp-media.me", - "homepage": "https://wp-media.me" - } - ], - "description": "Cloudflare Addon", - "homepage": "https://github.com/wp-media/cloudflare", - "time": "2020-08-24T20:21:34+00:00" - }, - { - "name": "wp-media/module-rocketcdn", - "version": "v1.0.4", - "source": { - "type": "git", - "url": "https://github.com/wp-media/module-rocketcdn.git", - "reference": "da772209c2361243309b6ba11ea43bc516bdd5cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-media/module-rocketcdn/zipball/da772209c2361243309b6ba11ea43bc516bdd5cf", - "reference": "da772209c2361243309b6ba11ea43bc516bdd5cf", - "shasum": "" - }, - "require-dev": { - "brain/monkey": "^2.0", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "php": "^5.6 || ^7", - "phpcompatibility/phpcompatibility-wp": "^2.0", - "phpunit/phpunit": "^5.7 || ^7", - "roave/security-advisories": "dev-master", - "wp-coding-standards/wpcs": "^2", - "wp-media/event-manager": "^3.1", - "wp-media/module-container": "^2.4", - "wp-media/options": "^3.0", - "wp-media/phpunit": "^1.0", - "wp-media/phpunit-wp-rocket": "^1.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "WP_Rocket\\Engine\\CDN\\RocketCDN\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "authors": [ - { - "name": "WP Media", - "email": "contact@wp-media.me", - "homepage": "https://wp-media.me" - } - ], - "description": "Module for RocketCDN integration", - "homepage": "https://github.com/wp-media/module-rocketcdn", - "time": "2020-11-20T15:22:36+00:00" - }, - { - "name": "wp-media/module-varnish", - "version": "v1.0", - "source": { - "type": "git", - "url": "https://github.com/wp-media/module-varnish.git", - "reference": "698534076da4af54fe4a99f33cd0c947175d564c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-media/module-varnish/zipball/698534076da4af54fe4a99f33cd0c947175d564c", - "reference": "698534076da4af54fe4a99f33cd0c947175d564c", - "shasum": "" - }, - "require-dev": { - "brain/monkey": "^2.0", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "php": "^5.6 || ^7", - "phpcompatibility/phpcompatibility-wp": "^2.0", - "phpstan/phpstan": "^0.12.3", - "phpunit/phpunit": "^5.7 || ^7", - "roave/security-advisories": "dev-master", - "szepeviktor/phpstan-wordpress": "^0.6", - "wp-coding-standards/wpcs": "^2", - "wp-media/event-manager": "^3.1", - "wp-media/module-container": "^2.4", - "wp-media/options": "^3.0", - "wp-media/phpunit": "^1.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "WP_Rocket\\Addon\\Varnish\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "authors": [ - { - "name": "WP Media", - "email": "contact@wp-media.me", - "homepage": "https://wp-media.me" - } - ], - "description": "Varnish Addon for WP Rocket", - "homepage": "https://github.com/wp-media/module-varnish", - "time": "2020-09-01T14:11:34+00:00" - }, - { - "name": "wp-media/phpunit", - "version": "v1.1.6", - "source": { - "type": "git", - "url": "https://github.com/wp-media/phpunit.git", - "reference": "5ea013e3a573c4211512248971145496193d9535" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-media/phpunit/zipball/5ea013e3a573c4211512248971145496193d9535", - "reference": "5ea013e3a573c4211512248971145496193d9535", - "shasum": "" - }, - "require": { - "brain/monkey": "^2.0", - "mikey179/vfsstream": "^1.6", - "php": "^5.6 || ^7", - "phpunit/phpunit": "^5.7 || ^7" - }, - "bin": [ - "wpmedia-phpunit" - ], - "type": "library", - "autoload": { - "psr-4": { - "WPMedia\\PHPUnit\\": "." - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "authors": [ - { - "name": "WP Media", - "email": "contact@wp-media.me", - "homepage": "https://wp-media.me" - } - ], - "description": "PHPUnit extender for bootstrapping unit and WordPress integration test suites.", - "homepage": "https://github.com/wp-media/phpunit", - "time": "2020-04-08T10:44:10+00:00" - }, - { - "name": "wp-media/rocket-lazyload-common", - "version": "v2.5.13", - "source": { - "type": "git", - "url": "https://github.com/wp-media/rocket-lazyload-common.git", - "reference": "511aca1c16aafd61d0a21b1559c38308e948d37d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-media/rocket-lazyload-common/zipball/511aca1c16aafd61d0a21b1559c38308e948d37d", - "reference": "511aca1c16aafd61d0a21b1559c38308e948d37d", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "require-dev": { - "brain/monkey": "^2.0", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "php": "^5.6 || ^7", - "phpcompatibility/phpcompatibility-wp": "^2.0", - "phpunit/phpunit": "^5.7 || ^7", - "wp-coding-standards/wpcs": "^2.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "RocketLazyload\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0-or-later" - ], - "authors": [ - { - "name": "WP Media", - "email": "contact@wp-media.me" - } - ], - "description": "Common Code between WP Rocket and Lazyload by WP Rocket", - "time": "2020-11-02T15:54:11+00:00" - }, - { - "name": "wp-media/wp-imagify-partner", - "version": "v1.0", - "source": { - "type": "git", - "url": "https://github.com/wp-media/wp-imagify-partner.git", - "reference": "c3412007b268a2793432f7d4fed31d2639ee2982" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-media/wp-imagify-partner/zipball/c3412007b268a2793432f7d4fed31d2639ee2982", - "reference": "c3412007b268a2793432f7d4fed31d2639ee2982", - "shasum": "" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0+" - ], - "authors": [ - { - "name": "WP Media", - "email": "contact@wp-media.me", - "homepage": "https://wp-media.me" - } - ], - "description": "A php class allowing WordPress plugin developers to promote Imagify through their own plugin", - "homepage": "https://github.com/wp-media/wp-imagify-partner", - "keywords": [ - "Imagify", - "wordpress" - ], - "time": "2020-01-22T22:22:41+00:00" - }, - { - "name": "wpackagist-plugin/amp", - "version": "1.5.5", - "source": { - "type": "svn", - "url": "https://plugins.svn.wordpress.org/amp/", - "reference": "tags/1.5.5" - }, - "dist": { - "type": "zip", - "url": "https://downloads.wordpress.org/plugin/amp.1.5.5.zip" - }, - "require": { - "composer/installers": "~1.0" - }, - "type": "wordpress-plugin", - "homepage": "https://wordpress.org/plugins/amp/" - }, - { - "name": "wpackagist-plugin/hummingbird-performance", - "version": "2.0.1", - "source": { - "type": "svn", - "url": "https://plugins.svn.wordpress.org/hummingbird-performance/", - "reference": "tags/2.0.1" - }, - "dist": { - "type": "zip", - "url": "https://downloads.wordpress.org/plugin/hummingbird-performance.2.0.1.zip" - }, - "require": { - "composer/installers": "~1.0" - }, - "type": "wordpress-plugin", - "homepage": "https://wordpress.org/plugins/hummingbird-performance/" - }, - { - "name": "wpackagist-plugin/pdf-embedder", - "version": "4.6.1", - "source": { - "type": "svn", - "url": "https://plugins.svn.wordpress.org/pdf-embedder/", - "reference": "tags/4.6.1" - }, - "dist": { - "type": "zip", - "url": "https://downloads.wordpress.org/plugin/pdf-embedder.4.6.1.zip" - }, - "require": { - "composer/installers": "~1.0" - }, - "type": "wordpress-plugin", - "homepage": "https://wordpress.org/plugins/pdf-embedder/" - }, - { - "name": "wpackagist-plugin/simple-custom-css", - "version": "4.0.4", - "source": { - "type": "svn", - "url": "https://plugins.svn.wordpress.org/simple-custom-css/", - "reference": "trunk" - }, - "dist": { - "type": "zip", - "url": "https://downloads.wordpress.org/plugin/simple-custom-css.zip?timestamp=1591707703" - }, - "require": { - "composer/installers": "~1.0" - }, - "type": "wordpress-plugin", - "homepage": "https://wordpress.org/plugins/simple-custom-css/" - }, - { - "name": "wpackagist-plugin/spinupwp", - "version": "1.2", - "source": { - "type": "svn", - "url": "https://plugins.svn.wordpress.org/spinupwp/", - "reference": "tags/1.2" - }, - "dist": { - "type": "zip", - "url": "https://downloads.wordpress.org/plugin/spinupwp.1.2.zip" - }, - "require": { - "composer/installers": "~1.0" - }, - "type": "wordpress-plugin", - "homepage": "https://wordpress.org/plugins/spinupwp/" - }, - { - "name": "wpackagist-plugin/wp-smushit", - "version": "3.8.2", - "source": { - "type": "svn", - "url": "https://plugins.svn.wordpress.org/wp-smushit/", - "reference": "tags/3.8.2" - }, - "dist": { - "type": "zip", - "url": "https://downloads.wordpress.org/plugin/wp-smushit.3.8.2.zip" - }, - "require": { - "composer/installers": "~1.0" - }, - "type": "wordpress-plugin", - "homepage": "https://wordpress.org/plugins/wp-smushit/" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "coenjacobs/mozart": 10, - "roave/security-advisories": 20 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=7.0" - }, - "platform-dev": { - "php": "^7" - }, - "plugin-api-version": "1.1.0" -} diff --git a/wp-content/plugins/wp-rocket/contributors.txt b/wp-content/plugins/wp-rocket/contributors.txt index 66e7deaee..953c29629 100644 --- a/wp-content/plugins/wp-rocket/contributors.txt +++ b/wp-content/plugins/wp-rocket/contributors.txt @@ -1,22 +1,27 @@ This file contains a list of people who have made large contributions to WP Rocket. Developers: - Jonathan Buttigieg - Remy Perona - Arun Basil Lal - Cristina Soponar - Tonya Mork + Jonathan Buttigieg + Remy Perona Ahmed Saeed - Caspar Green - Vasilis Manthos Alfonso Catron + COQUARD Cyrille + Mike + Mostafa Hisham QA: Piotr Bąk + Mai Saad + Vasilis Manthos Previous contributors: Julio Potier Gregory Viguier David Acuna Caspar Hübinger - Thomas Geisen \ No newline at end of file + Thomas Geisen + Tonya Mork + Arun Basil Lal + Cristina Soponar + Caspar Green + Natalia Drause diff --git a/wp-content/plugins/wp-rocket/dynamic-lists-delayjs.json b/wp-content/plugins/wp-rocket/dynamic-lists-delayjs.json new file mode 100644 index 000000000..1a10c42b9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/dynamic-lists-delayjs.json @@ -0,0 +1 @@ +{"plugins":{"ffc21030-519a-4853-8cea-49f959e82731":{"id":"plugin:def67a2c1ddd6df2353e4772b6fd4e5b","title":"Additional Variation Images Gallery for WooCommerce","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/woo-variation-gallery\/assets\/js\/slick.min.js","\/woo-variation-gallery\/assets\/js\/frontend.min.js","\/wp-includes\/js\/underscore.min.js","variation_custom_fields"],"is_default":0,"condition":"woo-variation-gallery\/woo-variation-gallery.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"0e7dc253-acd0-4421-877f-a7101d848717":{"id":"plugin:4b82cc7379d46c6272f5d556bb264eec","title":"Advanced Ads","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/uploads\/(.*).js","advanced_ads_ready","advadsCfpQueue","adsbygoogle","adservice.google","\/advanced-ads(.*)","advads_items","advads_tracking_ads"],"is_default":0,"condition":"advanced-ads\/advanced-ads.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"a4d5c058-9120-47ee-977c-f30f83fb1a75":{"id":"plugin:a076fbb79772f497349a76ee74a7f708","title":"All-in-one Compliance for GDPR \/ CCPA Cookie Consent","type":"plugin","icon":"","exclusions":["iubenda_cs.js","var _iub"],"is_default":0,"condition":"iubenda-cookie-law-solution\/iubenda_cookie_solution.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"88457e92-0f24-458e-b7b5-bab59074ebef":{"title":"Amelia","condition":"ameliabooking\/ameliabooking.php","exclusions":["\/wp-content\/plugins\/ameliabooking\/(.*).js","var hasAmeliaEvent"],"icon_url":"","type":"plugin","id":"plugin:93ea6597c3cbd06e93a46b9f5368732d","is_default":0,"created_at":1714415106},"79a5082f-821a-4a4b-a0e3-caaf22cf3f75":{"id":"plugin:9bdceaa1bb89135730a3b2aa4db94c22","title":"AMO Team Showcase","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/amo-team-showcase\/public\/js\/wookmark.js","\/amo-team-showcase\/public\/js\/amo-team-showcase-public.js","\/wp-includes\/js\/imagesloaded.min.js","amoTeamVars"],"is_default":0,"condition":"amo-team-showcase\/amo-team-showcase.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"90c7fd90-3adf-4cb7-8a92-845bdbd95d27":{"title":"Anti-Spam by CleanTalk - Prevent console error","condition":"cleantalk-spam-protect\/cleantalk.php","exclusions":["ctPublicFunctions","ctPublic"],"icon_url":"","type":"plugin","id":"plugin:ed2ade77cd44e21b1703b093c002a903","is_default":0,"created_at":1699370420},"e054f840-700a-4549-bbba-485473a53f71":{"title":"AnWP Football Leagues - Calendar Widget","condition":"football-leagues-by-anwppro\/anwp-football-leagues.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/football-leagues-by-anwppro\/(.*)","\/football-leagues-by-anwppro-premium-premium\/(.*)","window.AnWPFLPro","window.AnWPFLTabulator","\/elementor\/assets\/lib\/flatpickr\/flatpickr.min.js"],"icon_url":"","type":"plugin","id":"plugin:e7581089f33fdf0a970d5c5deb16ff50","is_default":0,"created_at":1708535321},"1d058cae-4460-4354-bab3-a96445650bd8":{"id":"plugin:b739df50f3f5bf400075f17dca652517","title":"AnyWhere Elementor Pro","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/anywhere-elementor-pro\/build\/index.js"],"is_default":0,"condition":"anywhere-elementor-pro\/anywhere-elementor-pro.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"8a1614c7-55b1-4b6d-88e5-6e8ddc630dae":{"id":"plugin:46741e77eaf4d13a0c80be6b86379758","title":"Astra - Pro Addon","type":"plugin","icon":"","exclusions":["\/astra-addon\/astra-addon-(.*).js"],"is_default":0,"condition":"astra-addon\/astra-addon.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"37d96403-f9ea-4481-b2f8-374d7c93e61a":{"id":"plugin:ccd87807930a1856717fd276c336db9a","title":"Beaver Builder","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/uploads\/bb-plugin\/","\/bb-plugin\/js\/yui3.min.js","\/wp-includes\/js\/imagesloaded.min.js","\/bb-plugin\/js\/fl-slideshow.min.js"],"is_default":0,"condition":"beaver-builder-lite-version\/fl-builder.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"f83dbf3b-783e-4ef9-9b18-8a469ca7102d":{"title":"Bloom","condition":"bloom\/bloom.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/bloom\/"],"icon_url":"","type":"plugin","id":"plugin:e57cdfbc09f4e0f7445c279d9f580bdd","is_default":0,"created_at":1685189070},"135aadd2-cd4a-44ae-8dcf-801f3f2316c0":{"id":"plugin:055ef01accbad6378e3d1a4965600964","title":"Booked","type":"plugin","icon":"","exclusions":["\/booked\/","\/js\/jquery\/ui\/datepicker.min.js"],"is_default":0,"condition":"booked\/booked.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"ddfee9b0-e5a9-4d3f-8c21-b999cbb61c33":{"id":"plugin:492f9b0d55f3bf07c68e915ea1dfb72a","title":"Bookly","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/bookly-responsive-appointment-booking-tool\/frontend\/","window.bookly"],"is_default":0,"condition":"bookly-responsive-appointment-booking-tool\/main.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"7a013fd6-0881-4dbe-8e93-33edefe7f717":{"title":"Borlabs Cookie","condition":"borlabs-cookie\/borlabs-cookie.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","borlabsCookieConfig","borlabs-cookie.min.js","borlabsCookieContentBlocker","BorlabsCookieBox","allFbWidgets","\/borlabs-cookie\/assets\/javascript\/","borlabs-cookie-config"],"icon_url":"","type":"plugin","id":"plugin:e1ec2daca513de476bd3dae79366e9ab","is_default":0,"created_at":1702497952},"3999e680-4049-4494-945c-768cecc1a2c4":{"id":"plugin:43019d66af7b41e65bb602c01e10c6a0","title":"Brizy","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/brizy\/public\/editor-build\/(.*)-wp\/editor\/js\/group-(.*).js","\/brizy\/public\/editor-build\/(.*)-wp\/editor\/js\/preview.js","Brizy.emit"],"is_default":0,"condition":"brizy\/brizy.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"af4d9357-3def-42a1-86b7-419553444b4d":{"id":"plugin:5c317f9f244597d8f236ecb7d8e41752","title":"Carousel Upsells and Related Product for WooCommerce","type":"plugin","icon":"","exclusions":["\/carousel-upsells-and-related-product-for-woocommerce\/assets\/js\/glide.min.js","carusel_poduct_related"],"is_default":0,"condition":"carousel-upsells-and-related-product-for-woocommerce\/ffxf-woo-glide-related-and-upsells.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"1d866d90-5451-43ba-a4d1-75b64f9235e1":{"id":"plugin:0a3a29603ebac8fe0808f64f5c8edbb2","title":"clickskeks.at Cookiebanner","type":"plugin","icon":"","exclusions":["clickskeks"],"is_default":0,"condition":"clickskeks\/index.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"c09695cc-2387-4416-881a-c0b392188a26":{"title":"Complianz","condition":"complianz-gdpr\/complianz-gpdr.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","complianz"],"icon_url":"","type":"plugin","id":"plugin:a766f95208154cd69a3e15150a42f325","is_default":0,"created_at":1685188788},"bfb36984-e2a1-40ba-a8cd-f29b0b6f720f":{"title":"Complianz Premium","condition":"complianz-gdpr-premium\/complianz-gpdr-premium.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","complianz"],"icon_url":"","type":"plugin","id":"plugin:89d54385816dd2d5ae92cfda9d95bbfd","is_default":0,"created_at":1712163685},"b5e146fc-0b7c-4c6c-a631-8da246d3bd89":{"title":"Conerstone Builder - Fix mobile menu","condition":"cornerstone\/cornerstone.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/cornerstone\/assets\/js\/site\/cs-classic.(.*).js"],"icon_url":"","type":"plugin","id":"plugin:f8f8c81535b5e0073aa3c56b6dd3df5b","is_default":0,"created_at":1708614275},"368bc394-b74e-4b62-b359-cd967f78c6ea":{"title":"ConsentMagic Pro - Show popup without user interaction","condition":"consent-magic-pro\/consent-magic-pro.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/wp-content\/plugins\/consent-magic-pro\/js\/cs-public.min.js","\/wp-content\/plugins\/pixelyoursite-pro\/(.*)"],"icon_url":"","type":"plugin","id":"plugin:9e0701a214f49a057f17b00e39df2e7e","is_default":0,"created_at":1711026041},"7e551e3b-fbe4-4235-87a9-b476bc9e2020":{"id":"plugin:949b1b923d51d10a2fb67a2a39d166b3","title":"Content Egg","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/content-egg\/res\/js\/morrisjs\/morris.min.js","\/content-egg\/res\/js\/morrisjs\/raphael.min.js","Morris.Area"],"is_default":0,"condition":"content-egg\/content-egg.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"7fbca6c5-9239-4550-a755-6f041f867a57":{"title":"Cookie Notice & Compliance for GDPR \/ CCPA","condition":"cookie-notice\/cookie-notice.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/cookie-notice\/","var cnArgs"],"icon_url":"","type":"plugin","id":"plugin:213d0f883ae27aefb3a7937656bbd11e","is_default":0,"created_at":1681379736},"26722567-fe35-44b5-a5a7-fb0f3a38c3f2":{"id":"plugin:1d10ad30bbcf0fd4b26e9625a07abcfc","title":"Cookiebot CMP","type":"plugin","icon":"","exclusions":["consent.cookiebot.com"],"is_default":0,"condition":"cookiebot\/cookiebot.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"74110e36-89e5-440d-bec3-7133da3277c2":{"id":"plugin:edcf103293ceab711e999d419d038ca1","title":"Coupon Referral Program","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/coupon-referral-program\/","\/wp-includes\/js\/jquery\/ui\/draggable.min.js"],"is_default":0,"condition":"coupon-referral-program\/coupon-referral-program.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"408fa396-20f2-4b1f-820d-52882af281cc":{"title":"CozyStay Core - Fix background images","condition":"cozystay-core\/cozystay-core.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/cozystay-core\/assets\/scripts\/front\/parallax-bundle.min.js"],"icon_url":"","type":"plugin","id":"plugin:872b5eef05c1fc3b00cda07ee966938d","is_default":0,"created_at":1711999893},"ed63e02f-d6c5-481a-bcb9-aae15f72aa21":{"id":"plugin:c3e26264dcfd25802805b4fd1a2a449c","title":"Crisp - Live Chat and Chatbot","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","CRISP_RUNTIME_CONFIG","l.js"],"is_default":0,"condition":"crisp\/crisp.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"a8eb622b-279c-4f84-86e0-785e9497add7":{"id":"plugin:6e4bf949e12f0bebfefb48f6c316102a","title":"Custom Twitter Feeds pro","type":"plugin","icon":"","exclusions":["\/custom-twitter-feeds-pro\/js\/ctf-scripts.min.js"],"is_default":0,"condition":"custom-twitter-feeds-pro\/custom-twitter-feed.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"1624ef15-e25b-406d-bdf9-d4b78d7a59e7":{"title":"Customer Reviews for WooCommerce Plugin","condition":"customer-reviews-woocommerce\/ivole.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/customer-reviews-woocommerce\/js\/colcade.js"],"icon_url":"","type":"plugin","id":"plugin:1f893b343e72ce55e6c9013fbda172fa","is_default":0,"created_at":1704734788},"b0614843-afed-4377-9d8d-e869221be331":{"title":"Depicter Slider","condition":"depicter\/depicter.php","exclusions":["\/depicter\/"],"icon_url":"","type":"plugin","id":"plugin:77c42a041f1c40d128f4bb3714a6d20d","is_default":0,"created_at":1713878881},"396cc03a-8946-4ee8-ab15-7e48261df79a":{"title":"Divi - Carousel Module 2.0","condition":"dg-divi-carousel","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/wp-content\/plugins\/dg-divi-carousel\/"],"icon_url":"","type":"plugin","id":"plugin:fcd789b7d02699f89720aa5ff3627912","is_default":0,"created_at":1709126476},"c15fe3b3-0eaa-48f9-bf04-0e778b1f8c63":{"title":"Divi - Supreme","condition":"supreme-modules-for-divi\/supreme-modules-for-divi.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js",".dipi_preloader_wrapper_outer","\/Divi\/js\/scripts.min.js","\/Divi\/js\/custom.unified.js","\/js\/magnific-popup.js","var DIVI","\/supreme-modules-for-divi\/"],"icon_url":"","type":"plugin","id":"plugin:b5489ae4d8b949f536d6dd2e5b0c1a95","is_default":0,"created_at":1679738701},"dd31451b-989a-4517-b02a-e2c2e2023366":{"id":"plugin:5caed322df984bbfd3ecb506cf12b688","title":"Divi Den Pro","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/ddpro\/build\/freddie\/js\/freddieScriptPageTransition.js","\/ddpro\/build\/freddie\/js\/freddieScriptsHeaders.js","\/ddpro\/build\/freddie\/js\/freddieScriptsContents.js","\/ddpro\/build\/freddie\/js\/gsap\/gsap.min.js"],"is_default":0,"condition":"ddpro\/ddpro.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"2b006370-cc90-42c1-9656-a30fbfbc91c6":{"id":"plugin:402d9b241b04934dd30f32e7ba490e63","title":"Divi Mobile","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","divi-menu","dm_nav"],"is_default":0,"condition":"divi-mobile\/divi-mobile.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"666bbed9-7ce3-457c-ad6e-b5e056d05010":{"title":"Divi Overlays","condition":"divi-overlays\/divi-overlays.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js",".dipi_preloader_wrapper_outer","\/Divi\/js\/scripts.min.js","\/Divi\/js\/custom.unified.js","var DIVI","\/divi-overlays\/"],"icon_url":"","type":"plugin","id":"plugin:1c828c93d87298d2a27c76e13d0880ba","is_default":0,"created_at":1679738664},"42a404af-7792-44be-9baa-565dc3baf25d":{"title":"Divi Pixel","condition":"divi-pixel\/divi-pixel.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js",".dipi_preloader_wrapper_outer","\/divi-pixel\/dist\/public\/js\/hamburger.min.js"],"icon_url":"","type":"plugin","id":"plugin:dd2494945a487a6cc74d3ab1b2137ccb","is_default":0,"created_at":1686859169},"85f5c099-c481-4c38-bbb9-8b76113bdfd5":{"title":"Divi Supreme Pro","condition":"supreme-modules-pro-for-divi\/supreme-modules-pro-for-divi.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","elm.style.display","\/supreme-modules-pro-for-divi\/includes\/modules\/ImageCarousel\/frontend.min.js","\/supreme-modules-pro-for-divi\/public\/js\/swiper-bundle.min.js"],"icon_url":"","type":"plugin","id":"plugin:3d5f0ae7751702fd1bb490fcf991a334","is_default":0,"created_at":1695118162},"0b78d762-c7be-45de-9aae-0c5078ec0619":{"id":"plugin:b5fc0101608d0b0627268dc49e3e1f8f","title":"Divi Toolbox","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","jQuery('.preloader')","\/divi-toolbox\/assets\/js\/toolbox-scripts.js"],"is_default":0,"condition":"divi-toolbox\/divi-toolbox.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"31a34440-1383-40c4-8920-effcf99f2165":{"title":"Dracula Dark Mode","condition":"dracula-dark-mode-premium\/plugin.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/wp-content\/plugins\/dracula-dark-mode-premium\/assets\/js\/dark-mode.js","\/wp-content\/plugins\/dracula-dark-mode-premium\/assets\/js\/frontend.js","\/wp-includes\/js\/dist\/vendor\/react-dom.min.js","\/wp-includes\/js\/dist\/vendor\/react.min.js","\/wp-includes\/js\/dist\/api-fetch.min.js","\/wp-includes\/js\/dist\/hooks.min.js","\/wp-includes\/js\/dist\/i18n.min.js","draculaDarkMode"],"icon_url":"","type":"plugin","id":"plugin:5e8a5d8d3830136d84d0f3676f1bf5a5","is_default":0,"created_at":1704210236},"8baba0f8-4449-47d8-a87d-9b6a116e7684":{"title":"Dynamic Pricing & Discounts Lite for WooCommerce","condition":"woo-dynamic-pricing-discounts-lite\/dynamic-pricing-discounts-lite-for-woocommerce.php","exclusions":["\/woo-dynamic-pricing-discounts-lite\/assets\/OwlCarousel\/dist\/owl.carousel.min.js","\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js"],"icon_url":"","type":"plugin","id":"plugin:185062bf08db42515488e1853d1f4917","is_default":0,"created_at":1677857247},"0fa129f2-5869-4db7-9bf0-69e4b3549ee2":{"id":"plugin:27478327aa44075a86176fad95640d76","title":"Dynamic Product Gallery for WooCommerce","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/woocommerce-dynamic-gallery\/","a3revWCDynamicGallery"],"is_default":0,"condition":"woocommerce-dynamic-gallery\/wc_dynamic_gallery_woocommerce.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"9958c6be-2f67-4791-95c3-a7ad96d599c0":{"title":"Dynamic Product Gallery Premium for WooCommerce","condition":"woocommerce-dynamic-gallery-pro\/wc_dynamic_gallery_woocommerce.php","exclusions":["\/jquery-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?$","\/jquery-migrate(.*)(.min|.slim|.slim.min)?.js(\\?(.*))?$","\/woocommerce-dynamic-gallery-pro\/assets\/js\/mygallery\/jquery.a3-dgallery.js","settings_defaults_","a3revWCDynamicGallery"],"icon_url":"","type":"plugin","id":"plugin:11dc02a76019f00422f4ac85f47f5135","is_default":0,"created_at":1683208937},"ce26ed21-1be5-481f-80d4-31edfac6d890":{"title":"Dynamic.ooo - Dynamic Content for Elementor","condition":"dynamic-content-for-elementor\/dynamic-content-for-elementor.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","\/wp-includes\/js\/imagesloaded.min.js","ElementorProFrontendConfig","elementorFrontendConfig","\/dynamic-content-for-elementor\/assets\/","\/wp-includes\/js\/dist\/hooks.min.js","\/wp-includes\/js\/dist\/i18n.min.js"],"icon_url":"","type":"plugin","id":"plugin:d2bd5b348abe016bdc722acce7755062","is_default":0,"created_at":1683355024},"6a3161a6-1a6f-457a-a9ee-54b376981927":{"id":"plugin:ee1dec033c6481a77fe88de5bef1a02d","title":"Easy Table of Contents","type":"plugin","icon":"","exclusions":["\/easy-table-of-contents\/assets\/js\/front.min.js"],"is_default":0,"condition":"easy-table-of-contents\/easy-table-of-contents.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"25a534a0-2c1f-4cf4-9e19-7941bc032b3a":{"title":"Ecwid Ecommerce Shopping Cart","condition":"ecwid-shopping-cart\/ecwid-shopping-cart.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","app.ecwid.com\/script.js","\/ecwid-shopping-cart\/js\/frontend.js","\/ecwid-shopping-cart\/js\/static-page.js","ecwidParamswindow.ec","jQuery.mobile","xSearch","xCategoriesV2","xProductBrowser","Ecwid.init"],"icon_url":"","type":"plugin","id":"plugin:41c8f5f0ab00cb39654aedd783d194e0","is_default":0,"created_at":1704734846},"a0d681db-991a-4220-8f05-c54a4857aa42":{"title":"Element Pack Pro","condition":"bdthemes-element-pack\/bdthemes-element-pack.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/bdthemes-element-pack\/assets\/js\/modules\/ep-static-carousel.min.js","\/bdthemes-element-pack\/assets\/js\/modules\/ep-custom-carousel.min.js","\/bdthemes-element-pack\/assets\/js\/modules\/ep-slideshow.min.js","\/bdthemes-element-pack\/assets\/js\/modules\/ep-product-carousel.min.js","\/bdthemes-element-pack\/assets\/js\/modules\/ep-stacker.min.js","\/bdthemes-element-pack\/assets\/js\/bdt-uikit.min.js","\/bdthemes-element-pack\/assets\/js\/common\/helper.min.js","\/bdthemes-element-pack\/assets\/vendor\/js\/ScrollTrigger.min.js","\/bdthemes-element-pack\/assets\/vendor\/js\/gsap.min.js"],"icon_url":"","type":"plugin","id":"plugin:ced76c4da718a667537dc6c9d5e0244d","is_default":0,"created_at":1715791619},"40464325-5bae-4a20-bc97-553499e09a73":{"title":"Elementor","condition":"elementor\/elementor.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","\/wp-includes\/js\/imagesloaded.min.js","ElementorProFrontendConfig","elementorFrontendConfig","\/happy-elementor-addons-pro\/","\/header-footer-elementor\/inc\/js\/frontend.js","\/wp-includes\/js\/jquery\/ui\/core.min.js","\/wp-includes\/js\/dist\/api-fetch.min.js","\/wp-includes\/js\/dist\/hooks.min.js","\/wp-includes\/js\/dist\/i18n.min.js"],"icon_url":"","type":"plugin","id":"plugin:1d15783218a3137bec4ee8df5353e218","is_default":0,"created_at":1694425872},"ac86b64c-c80a-4053-894d-6caa8b4fdce8":{"title":"Elementor Loop Carrousel","condition":"elementor\/elementor.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-includes\/js\/jquery\/ui\/core.min.js","\/wp-includes\/js\/dist\/api-fetch.min.js","\/wp-includes\/js\/dist\/hooks.min.js","\/wp-includes\/js\/dist\/i18n.min.js"],"icon_url":"","type":"plugin","id":"plugin:0eb8d0bbd1c7ca05ac133ea634f676b7","is_default":0,"created_at":1694442056},"a8fc9fd1-f6d3-41eb-abe9-ef176de6d7e2":{"title":"Elementor - Lazy Load Background Images","condition":"elementor\/elementor.php","exclusions":["lazyloadRunObserver"],"icon_url":"","type":"plugin","id":"plugin:bf248cb2876558452a566c5dd89262b8","is_default":0,"created_at":1694453032},"1948aff5-7850-4979-91fa-0ce181484508":{"id":"plugin:de658ae6c2d05a5a4a947efecf5e0c16","title":"Elementor Custom Skin","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig","\/ele-custom-skin(.*)\/assets\/js\/"],"is_default":0,"condition":"ele-custom-skin\/ele-custom-skin.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"25708299-c596-4416-8ad8-740aee0f2752":{"title":"Elementor Pro","condition":"elementor-pro\/elementor-pro.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","\/wp-includes\/js\/imagesloaded.min.js","ElementorProFrontendConfig","elementorFrontendConfig","\/happy-elementor-addons-pro\/","\/header-footer-elementor\/inc\/js\/frontend.js"],"icon_url":"","type":"plugin","id":"plugin:030ad23e3851ed7adfa7b9b6c13cf5a6","is_default":0,"created_at":1679490021},"f34dd874-4b34-41e6-a31c-ece3c1efbffc":{"id":"plugin:305581ad4294a30eeb1247982f626005","title":"Elementor Pro - SmartMenus","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor-pro\/assets\/lib\/smartmenus\/jquery.smartmenus.min.js","\/elementor-pro\/assets\/js\/preloaded-elements-handlers.min.js"],"is_default":0,"condition":"elementor-pro\/elementor-pro.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"111cc8b2-0be9-438b-9aa3-7f1e301a5697":{"id":"plugin:5ae9f5d99224d5ebc7d0c0bbf5b99787","title":"Elementor Pro - User Cache","type":"plugin","icon":"","exclusions":["\/wp-includes\/js\/underscore.min.js","\/wp-includes\/js\/jquery\/ui\/core.min.js","\/wp-includes\/js\/backbone.min.js","elementorAdminBarConfig","elementorCommonConfig","elementorWebCliConfig","elementorDevToolsConfig"],"is_default":0,"condition":"elementor-pro\/elementor-pro.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"c1713bf8-e0c3-4cb5-8b3f-841b06aa87ed":{"title":"ElementsKit Lite - Megamenu","condition":"elementskit-lite\/elementskit-lite.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig","\/elementskit(.*)\/"],"icon_url":"","type":"plugin","id":"plugin:b91fed2fc4478dbb7067742c1ee4691b","is_default":0,"created_at":1683270249},"706ff35d-8e33-4b04-a986-346faff704e9":{"id":"plugin:417192424139d89fb2a5b1ee1f2b9613","title":"Essential Addons for Elementor","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig","\/essential-addons(-for)?-elementor(-lite)?\/.*(.min)?.js"],"is_default":0,"condition":"essential-addons-for-elementor-lite\/essential_adons_elementor.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"b38556dc-2bc4-430f-9c55-7191cf7773db":{"id":"plugin:057757d0593ad9d2dc58124f0077a5df","title":"Essential Addons for Elementor Pro","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig","\/essential-addons(-for)?-elementor(-lite)?\/.*(.min)?.js"],"is_default":0,"condition":"essential-addons-elementor\/essential_adons_elementor.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"719b988f-0d60-40c2-ba46-88f943119cb1":{"id":"plugin:c8e6c490f6438f566ade600c33531a85","title":"Essential Grid","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/essential-grid\/","lightboxOptions"],"is_default":0,"condition":"essential-grid\/essential-grid.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"47d3d2ab-160d-4b07-ac25-8250b9e6a951":{"id":"plugin:dafd19fa48a1fef890dc4348052fcb75","title":"EventON Lite","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/eventon-lite\/assets\/js\/(.*)"],"is_default":0,"condition":"eventon-lite\/eventon.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"219968d7-cf1f-4ee0-917a-db35dcc93a3e":{"id":"plugin:49ff465628fc3cb6d7f23ff81d9b8339","title":"FacetWP","type":"plugin","icon":"","exclusions":["\/facetwp\/assets\/js\/dist\/front.min.js","window.FWP_"],"is_default":0,"condition":"facetwp\/index.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"acce5701-5917-48d5-83ab-3e626aa420c5":{"id":"plugin:78a1c88a56fa957c802074b6418c6fac","title":"FacetWP - Flyout menu","type":"plugin","icon":"","exclusions":["\/facetwp-flyout\/assets\/js\/front.js"],"is_default":0,"condition":"facetwp-flyout\/facetwp-flyout.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"081461cf-dbd0-42f3-9557-10cdc16cf145":{"title":"FiboFilters Premium","condition":"fibofilters-pro\/fibofilters.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/fibofilters-pro\/build\/front-pro\/front.js"],"icon_url":"","type":"plugin","id":"plugin:d9f62725f1470d35c3f220645bc2e473","is_default":0,"created_at":1709923289},"f2a5b95f-1a22-46d2-8b72-42a53e46ae3f":{"id":"plugin:5d7555892a3a9968fde3fa3a335fc3d8","title":"FiboSearch - Ajax Search for WooCommerce","type":"plugin","icon":"","exclusions":["\/wp-includes\/js\/jquery\/jquery.js","\/wp-includes\/js\/jquery\/jquery-migrate.js","\/ajax-search-for-woocommerce-premium\/assets\/js\/search.js"],"is_default":0,"condition":"ajax-search-for-woocommerce\/ajax-search-for-woocommerce.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"7d1404e9-be76-449c-87aa-919557abe82d":{"id":"plugin:ad46179e8b0584abaf52056b846da227","title":"FlexBlock","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/flo-flex-builder\/dist\/flex-public.min.js","flexDebug"],"is_default":0,"condition":"flo-flex-builder\/flo-flex-builder.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"b9c6a2dc-b226-4e2c-b85e-29ee55b8f751":{"id":"plugin:567a2b15db30ef6bd4904e4317139aac","title":"Fluent Forms","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/fluentform\/public\/js\/(.*).js","\/fluentformpro\/public\/js\/(.*).js"],"is_default":0,"condition":"fluentform\/fluentform.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"10874f8a-2855-4e80-bc46-e484589b76a8":{"id":"plugin:e78c153103f698b2b34892332d6b3b62","title":"Flying Images","type":"plugin","icon":"","exclusions":["flyingImages"],"is_default":0,"condition":"nazy-load\/flying-images.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"53958499-dacd-41d6-93bc-1534fe7d9eda":{"id":"plugin:5a0e40a6c5783856893b803189de1404","title":"FooGallery Premium","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/plugins\/foobox-image-lightbox\/free\/js\/foobox.free.min.js","\/plugins\/foogallery-premium\/pro\/extensions\/default-templates\/shared\/js\/foogallery.min.js"],"is_default":0,"condition":"foogallery-premium\/foogallery.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"7870d704-2024-4622-838c-fad37d5c6753":{"id":"plugin:ebb5efb57b19ae60e734e456ca2df3f8","title":"Formidable Forms","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","frmSigs","\/formidable-signature\/js\/frm.signature.min.js"],"is_default":0,"condition":"formidable\/formidable.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"3f24f9b3-e59e-400f-a784-999f93f60fab":{"id":"plugin:0b08523445b8869a67ca40e777704692","title":"Forminator","type":"plugin","icon":"","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","forminatorFront","\/forminator\/build\/front\/front.multi.min.js","\/forminator\/assets\/js\/library\/jquery.validate.min.js","\/forminator\/assets\/forminator-ui\/js\/forminator-form.min.js","\/forminator\/assets\/forminator-ui\/js\/select2.full.min.js","\/wp-includes\/js\/jquery\/ui\/datepicker.min.js","\/wp-includes\/js\/dist\/vendor\/moment.min.js"],"is_default":0,"condition":"forminator\/forminator.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"3a600ded-3454-48fb-9811-46afa2ab3c05":{"id":"plugin:5759bf0d47ac3457485314b381a9b528","title":"GDPR Cookie Compliance","type":"plugin","icon":"","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/gdpr-cookie-compliance\/dist\/scripts\/main.js"],"is_default":0,"condition":"gdpr-cookie-compliance\/moove-gdpr.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"e21aaa5e-7354-471d-ab86-85f99f48830c":{"id":"plugin:ffb40036ab0583218561de7c28c6bd9b","title":"GDPR Cookie Consent","type":"plugin","icon":"","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/public\/js\/cookie-law-info-public.js","Cli_Data"],"is_default":0,"condition":"webtoffee-gdpr-cookie-consent\/cookie-law-info.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"c11ca4ea-1a23-49ee-9a6b-1e549de50ea2":{"id":"plugin:3877953c5ec1e66db92ad844ae8ebafc","title":"Getwid - Gutenberg Blocks","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/wp-includes\/js\/jquery\/ui\/tabs.min.js","\/wp-includes\/js\/jquery\/ui\/core.min.js"],"is_default":0,"condition":"getwid\/getwid.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"79b33eb9-bc92-4d8a-afd8-1c61e70bed8f":{"title":"GiveWP","condition":"give\/give.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/give\/assets\/dist\/js\/give.js","\/wp-includes\/js\/dist\/api-fetch.min.js","\/wp-includes\/js\/dist\/hooks.min.js","\/wp-includes\/js\/dist\/i18n.min.js"],"icon_url":"","type":"plugin","id":"plugin:0fb3af06fc5c710a670220b054c292c5","is_default":0,"created_at":1706652232},"3773bb33-b168-4f68-9963-512da24ac4da":{"title":"GoodLayers Core","condition":"goodlayers-core\/goodlayers-core.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/goodlayers-core\/plugins\/script.js","\/goodlayers-core\/include\/js\/page-builder.js"],"icon_url":"","type":"plugin","id":"plugin:5f124509a56ca2e0644246919ec70434","is_default":0,"created_at":1704734904},"2adabe9b-6e03-4a67-959f-492813d40f69":{"title":"Google Tag Manager for WooCommerce PRO","condition":"gtm-ecommerce-woo-pro\/gtm-ecommerce-woo-pro.php","exclusions":["\/gtm-ecommerce-woo-pro\/assets\/gtm-ecommerce-woo-pro.js"],"icon_url":"","type":"plugin","id":"plugin:e54fd4313007b6fedf8ab4df0e05277a","is_default":0,"created_at":1691218549},"7bf261ac-89d4-492f-8a3d-1c5809b9579a":{"title":"Gravity Forms","condition":"gravityforms\/gravityforms.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/gravityforms\/","gform","recaptcha","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/wp-includes\/js\/plupload\/plupload.min.js","\/wp-includes\/js\/plupload\/moxie.min.js"],"icon_url":"","type":"plugin","id":"plugin:7a1c1606d094f6bff83c0ee155908367","is_default":0,"created_at":1694457903},"fbaf4a19-f675-441a-b75c-7fd748a59827":{"title":"Gravity Forms Page Transitions","condition":"gp-page-transitions\/gp-page-transitions.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/plugins\/gp-page-transitions\/js\/"],"icon_url":"","type":"plugin","id":"plugin:53ef8d0ee1f9fdf0bbf87676e449eef5","is_default":0,"created_at":1713987341},"12340193-5c35-4b0d-b0bc-bea690cf1cae":{"id":"plugin:2f3112dd98c39aeb6bde618c9026a29f","title":"Green Forms","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","leform.min.js","leform_customjs_handlers","leform_ajax_url"],"is_default":0,"condition":"green-forms\/green-forms.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"4d20b427-47cf-4cdf-91c7-ff53602d3b2a":{"id":"plugin:0eb769dddc58f998e913345841b1d0b3","title":"GTM4WP","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","dataLayer"],"is_default":0,"condition":"duracelltomi-google-tag-manager\/duracelltomi-google-tag-manager-for-wordpress.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"a2b3c237-728c-49d6-882a-e3885444e9b4":{"id":"plugin:3b085ccda851ccf129d9506462f0cd65","title":"GTranslate","type":"plugin","icon":"","exclusions":["translate.google.com","googleTranslateElementInit"],"is_default":0,"condition":"gtranslate\/gtranslate.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"40cd9336-e73f-4a61-a7f6-27ec1ca6892c":{"id":"plugin:e1f17c1eac230219e6fec3ac07406a0d","title":"HBook","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/hbook\/","hb_booking_form_data","hb_max_date"],"is_default":0,"condition":"hbook\/hbook.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"192224c7-df72-4e3d-8f13-3206ac5b2e90":{"title":"Helper - OpenAI Chatbot for WordPress","condition":"\/helper\/index.php","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/helper\/js\/helper.min.js","mdpHelper"],"icon_url":"","type":"plugin","id":"plugin:07311d992a8a9d6af91e4766d2cb9ac9","is_default":0,"created_at":1691599768},"99cfbb2e-5678-42c2-928f-5cb09d7e43da":{"id":"plugin:269c5766fba124a838ac012a4b5a1a13","title":"HUSKY - Products Filter for WooCommerce","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/woocommerce-products-filter\/(.*)","woof"],"is_default":0,"condition":"woocommerce-products-filter\/index.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"3a964eac-4aeb-49a7-9fd6-4c31b2645dee":{"id":"plugin:d457acfec0f86aac6733f1446f4fc94f","title":"Instagram Feed Pro","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/instagram-feed-pro\/js\/sbi-scripts.min.js","sb_instagram_js_options"],"is_default":0,"condition":"instagram-feed-pro\/instagram-feed.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"8f9f4788-1b8d-468b-b291-1fcbd48618b9":{"id":"plugin:513b0c0ec8e12130af9b4bbbb17d7275","title":"Interactive Geo Maps","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/interactive-geo-maps-premium\/assets\/public\/map-service\/app.min.js","\/interactive-geo-maps\/assets\/public\/map-service\/app.js","iMapsData","cdn.amcharts.com\/lib\/"],"is_default":0,"condition":"interactive-geo-maps\/interactive-geo-maps.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"cf650ca3-afa0-4a13-9e4f-f7cca19abac6":{"title":"Ivory Search","condition":"add-search-to-menu\/add-search-to-menu.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/add-search-to-menu\/public\/js\/ivory-search.min.js"],"icon_url":"","type":"plugin","id":"plugin:7430e9d2c985ae0a3339a7b7e1acc318","is_default":0,"created_at":1677852711},"17a5dd54-1f5e-4d57-a56d-a8a970651954":{"id":"plugin:1c8a1e1ba89a601f88654f094139b469","title":"JetBlocks","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/jet-blocks\/assets\/js\/jet-blocks.min.js"],"is_default":0,"condition":"jet-blocks\/jet-blocks.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"b6f78c90-9823-459a-8dc1-1257e5f0d4e3":{"id":"plugin:dac9ec782180f33d0fcc7c4e0e569b9d","title":"JetBlog","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor-pro\/","\/elementor\/","\/jet-blog\/","ElementorProFrontendConfig","elementorFrontendConfig","hasJetBlogPlaylist"],"is_default":0,"condition":"jet-blog\/jet-blog.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"e17173d8-6ef8-4e27-ba0f-379c9aea7eda":{"id":"plugin:0fe8895d1da5247b73a5d0b482df4ac4","title":"JetElements","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig","\/jet-elements\/","hasJetBlogPlaylist","jetElements","\/wp-includes\/js\/jquery\/ui\/"],"is_default":0,"condition":"jet-elements\/jet-elements.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"cfd77501-9c9e-4f11-b994-0178a592fc08":{"title":"JetEngine","condition":"jet-engine\/jet-engine.php","exclusions":["\/jet-engine\/"],"icon_url":"","type":"plugin","id":"plugin:bc998e71546860c8c7f70c45a6c18972","is_default":0,"created_at":1686208296},"36fed829-a2d9-41b5-94f6-2c3b9f07a94e":{"id":"plugin:433a3173f2d06f7d02c7b91c06ed215d","title":"JetMenu","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor-pro\/","\/elementor\/","\/jet-blog\/assets\/js\/lib\/slick\/slick.min.js","\/jet-elements\/","\/jet-menu\/","elementorFrontendConfig","ElementorProFrontendConfig","hasJetBlogPlaylist","JetEngineSettings","jetMenuPublicSettings","\/jet-reviews\/assets\/js\/lib\/vue.min.js"],"is_default":0,"condition":"jet-menu\/jet-menu.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"580cfed7-f034-4e39-bc7a-cdd01923ce87":{"id":"plugin:51714cfdb43f231a1c93e7cffb1007ab","title":"JetPopup","type":"plugin","icon":"","exclusions":["\/jet-popup\/assets\/js\/lib\/anime-js\/anime.min.js","\/jet-popup\/assets\/js\/jet-popup-frontend.js","\/jet-woo-builder\/","var jetPopupData"],"is_default":0,"condition":"jet-popup\/jet-popup.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"d9cd2730-12e2-42d7-a082-6f0efcd466cc":{"id":"plugin:df3bc4b6a8a9f28a5ba24cb7496bbc72","title":"JetProductGallery","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/jet-woo-product-gallery\/assets\/lib\/swiper\/swiper.min.js","\/jet-woo-product-gallery\/assets\/js\/jet-woo-product-gallery.min.js"],"is_default":0,"condition":"jet-woo-product-gallery\/jet-woo-product-gallery.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"544aa37b-4d52-4182-99e8-abe23585da14":{"id":"plugin:5921fc95965ac7fccb7296957bd9abff","title":"JetReviews","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/jet-reviews\/assets\/js\/jet-reviews-frontend.js","\/jet-reviews\/assets\/js\/lib\/vue.min.js","jetReviewsWidget"],"is_default":0,"condition":"jet-reviews\/jet-reviews.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"963c7804-eede-4570-bd63-67066588b758":{"title":"JetSearch - Search results popup","condition":"jet-search\/jet-search.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/jet-search\/assets\/lib\/chosen\/chosen.jquery.min.js","\/jet-search\/assets\/js\/jet-search.js","\/jet-search\/assets\/lib\/jet-plugins\/jet-plugins.js"],"icon_url":"","type":"plugin","id":"plugin:13e8760379022187de982df2226a5be4","is_default":0,"created_at":1708541675},"a8460089-34b4-4f8f-8694-5d92fa48aa82":{"title":"JetSmartFilters","condition":"jet-smart-filters\/jet-smart-filters.php","exclusions":["jetOffcanvasInitialized"],"icon_url":"","type":"plugin","id":"plugin:0cd63a514de1f1acb88e2bde65c4bc8d","is_default":0,"created_at":1694447256},"fe3c4915-6f8b-49b7-aa9c-c97b264d9f12":{"id":"plugin:a346b60514ef52afeffc6e2ef2793da3","title":"JetSticky","type":"plugin","icon":"","exclusions":["\/jetsticky-for-elementor\/"],"is_default":0,"condition":"jetsticky-for-elementor\/jetsticky-for-elementor.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"853479dc-fff5-47cf-9a60-bf9b00f71fc4":{"title":"JetTabs for Elementor","condition":"jet-tabs\/jet-tabs.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/elementor\/","\/elementor-pro\/","\/wp-includes\/js\/imagesloaded.min.js","ElementorProFrontendConfig","elementorFrontendConfig","\/wp-content\/plugins\/jet-tabs\/assets\/js\/jet-tabs-frontend.min.js"],"icon_url":"","type":"plugin","id":"plugin:d887a6ffea25d759e8aecdb6b78917f7","is_default":0,"created_at":1697130971},"b7f89562-230c-4f63-8360-7aad6df31e02":{"id":"plugin:829272546b040d5aaeeeaf976b6cd4ec","title":"JetTricks","type":"plugin","icon":"","exclusions":["\/jet-tricks\/"],"is_default":0,"condition":"jet-tricks\/jet-tricks.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"90451e2a-553a-4496-9fa4-cffedbe69d43":{"id":"plugin:f44f3dbd09149f57db370e4132b057db","title":"JetWoo Widgets For Elementor","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig","\/jetwoo-widgets-for-elementor\/assets\/js\/jet-woo-widgets.js","\/jet-woo-builder\/assets\/js\/jet-woo-builder.min.js","\/jet-woo-builder\/assets\/js\/frontend.min.js","\/wp-includes\/js\/imagesloaded.min.js"],"is_default":0,"condition":"jet-woo-builder\/jet-woo-builder.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"944718c2-48c6-4f53-aaa2-460d07e033cc":{"id":"plugin:ed318a971f8a047bed5b02ad546a9c18","title":"JetWooBuilder","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-includes\/js\/dist\/hooks.min.js","\/wp-includes\/js\/dist\/i18n.min.js","\/elementor-pro\/","\/elementor\/","elementorFrontendConfig","ElementorProFrontendConfig","JetEngineSettings","\/jet-woo-builder\/","\/jet-woo-builder-custom-quantity-selectors-main\/assets\/js\/main.js"],"is_default":0,"condition":"jet-woo-builder\/jet-woo-builder.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"f5b62f59-1dae-4cdf-ac3f-f5e846fc9918":{"id":"plugin:9562e253cd4ac2b1e1f70e32cb4e32dc","title":"Layer Slider","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/LayerSlider\/assets\/static\/layerslider\/js\/layerslider.utils.js","\/LayerSlider\/assets\/static\/layerslider\/js\/layerslider.kreaturamedia.jquery.js","\/LayerSlider\/assets\/static\/layerslider\/js\/layerslider.transitions.js","initLayerSlider"],"is_default":0,"condition":"LayerSlider\/layerslider.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"e2be718d-83a2-4fa0-bc98-f0df52be3dc1":{"id":"plugin:1425e2735306796fe1539d9184a77e10","title":"LoftLoader Pro","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","loftloader.min.js"],"is_default":0,"condition":"loftloader-pro\/loftloader-pro.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"cfa18552-656e-453c-9e14-c07522dc6598":{"id":"plugin:0bf67b8ba84771e1a367fe24590ef09c","title":"MailUp for WordPress","type":"plugin","icon":"","exclusions":["\/mailup-email-and-newsletter-subscription-form\/public\/js\/mailup-public.js","mailup-js-extra"],"is_default":0,"condition":"mailup-email-and-newsletter-subscription-form\/mailup.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"c5330c66-ba7b-45b1-87e4-ce590ab005dd":{"id":"plugin:10d0de28911c5f66463b9c8783f8148a","title":"Maintenance","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/maintenance\/"],"is_default":0,"condition":"maintenance\/maintenance.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"267aef71-afa0-4848-b6f8-3e1ca15c3a23":{"id":"plugin:9460789bdfe77425c895f130991a4cb4","title":"Maps Marker Pro","type":"plugin","icon":"","exclusions":["\/maps-marker-pro\/js\/mapsmarkerpro.js","var mapsMarkerPro"],"is_default":0,"condition":"maps-marker-pro\/maps-marker-pro.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"b5a88b63-e906-49b3-8134-420139915ea6":{"title":"Master Popups","condition":"master-popups\/master-popups.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/plugins\/master-popups\/assets\/public\/js\/master-popups-libs.min.js"],"icon_url":"","type":"plugin","id":"plugin:8fd7bd2c8b0a33e62798573abd12be63","is_default":0,"created_at":1681305305},"4be41549-bf4d-4c49-8346-0f8a3b88fdba":{"id":"plugin:de888634cc4bd51576eed319d5a528fd","title":"Master Slider","type":"plugin","icon":"","exclusions":["masterslider"],"is_default":0,"condition":"master-slider\/master-slider.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"087bee18-7cd1-4c10-8acc-19e1b7c4f4cd":{"id":"plugin:b71309a89bf3c8b558b6fca5d6531919","title":"Max Mega Menu","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-includes\/js\/hoverIntent.min.js","\/megamenu\/js\/maxmegamenu.js","var megamenu"],"is_default":0,"condition":"megamenu\/megamenu.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"cf22f0b9-01f4-409e-8a93-ad6743095abd":{"id":"plugin:94a7bae84ef2816494be4af66c577bfc","title":"Meta Slider","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/ml-slider\/","var metaslider"],"is_default":0,"condition":"ml-slider\/ml-slider.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"bb2cbc0d-20da-415e-8218-c17f1db53579":{"title":"Monarch","condition":"monarch\/monarch.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","dt-place-monarch-icons"],"icon_url":"","type":"plugin","id":"plugin:b7335d6d6d5c5134ea10ac2d9b04226c","is_default":0,"created_at":1677853476},"a98d6a80-4610-4ede-bd33-c3e15bed0a95":{"id":"plugin:4f8651262425ef6d7c223c68a2ec2063","title":"Monster Insights","type":"plugin","icon":"","exclusions":["__gtagTracker","monsterinsights_frontend","\/google-analytics-for-wordpress\/assets\/js\/frontend-gtag.min.js"],"is_default":0,"condition":"google-analytics-for-wordpress\/googleanalytics.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"26e1a36e-7a03-449e-8ecc-e42c41ca291c":{"id":"plugin:f8fc66b302dec2327bdec0434a3b275b","title":"Motion.page","type":"plugin","icon":"","exclusions":["\/motionpage\/core\/includes\/assets\/js\/(.*)","\/motionpage\/core\/includes\/assets\/js\/gsap\/(.*)","\/motionpage\/assets\/js\/(.*)","\/motionpage\/assets\/js\/gsap\/(.*)"],"is_default":0,"condition":"motionpage\/motionpage.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"459fd663-7f80-45fd-8308-d3484981e161":{"title":"Ninja Forms","condition":"ninja-forms\/ninja-forms.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-includes\/js\/underscore.min.js","\/wp-includes\/js\/backbone.min.js","\/wp-includes\/js\/jquery\/ui\/core.min.js","\/ninja-forms\/assets\/js\/min\/front-end-deps.js","\/ninja-forms\/assets\/js\/min\/front-end.js","nf-"],"icon_url":"","type":"plugin","id":"plugin:1d3ae9c1a96d5062616968b81eef319d","is_default":0,"created_at":1703190792},"c97440dd-7592-40e7-8c98-dac20d39808f":{"id":"plugin:723a588dcd49285ea9f7404e2379b47f","title":"Ninja Tables","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/ninja-tables(.*)\/assets\/","\/ninja-tables(.*)\/public\/","\/wp-includes\/js\/dist\/vendor\/moment.min.js","ninja_table_instance_","ninja_filter_","ninja_table_ready_init_table_id"],"is_default":0,"condition":"ninja-tables\/ninja-tables.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"ebc01f06-8c35-47fa-9c63-8959c5cbd915":{"id":"plugin:f41a52ab1dd50a81cd3a5e341af0007c","title":"NotificationX","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/notificationx\/assets\/public\/js\/(.*).js","notificationXArr"],"is_default":0,"condition":"notificationx\/notificationx.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"3aaf4a1b-591a-48b7-8d60-e6d65c0f94c9":{"id":"plugin:be8fc72a8b8e8eb5958be13737cff47c","title":"Ocean Elementor Widgets","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig","\/ocean-elementor-widgets\/"],"is_default":0,"condition":"ocean-elementor-widgets\/ocean-elementor-widgets.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"f053a7d3-62b0-4312-b0ca-6ff63380eb0b":{"id":"plugin:1a14afe852fefe7b22ccad3893672a29","title":"One Click Accessibility","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/pojo-accessibility\/assets\/js\/app.min.js"],"is_default":0,"condition":"pojo-accessibility\/pojo-accessibility.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"61e11800-48a9-4354-8a4c-ac9a2b4b033a":{"id":"plugin:b9ed0fe6f2cdbd305691a6b857f4b3dc","title":"OoohBoi Steroids for Elementor","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig","\/ooohboi-steroids-for-elementor\/"],"is_default":0,"condition":"ooohboi-steroids-for-elementor\/ooohboi-steroids.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"560b78a2-f051-490b-9dc6-a602dece0d81":{"id":"plugin:f1ff18a3e04c4e0995fca9cabffe57a7","title":"Optimole","type":"plugin","icon":"","exclusions":["optimoleData"],"is_default":0,"condition":"optimole-wp\/optimole-wp.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"b0fda458-4bf2-41e9-a159-60d4bb6102a6":{"id":"plugin:48ec18bd3f59772d98f85dddab75e305","title":"OSM - OpenStreetMap","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/osm\/js\/OL\/","\/osm\/js\/osm-v3-plugin-lib.js","vectorM"],"is_default":0,"condition":"osm\/osm.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"3743ed67-e0d1-4243-bb1f-ee48a445dd10":{"id":"plugin:9eacf0b76484af0259cd788f4923f20c","title":"OxyExtras","type":"plugin","icon":"","exclusions":["vime","vime.esm.js"],"is_default":0,"condition":"oxyextras\/plugin.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"52a21e27-af5b-4476-8d6d-54c323fd1443":{"id":"plugin:e852555c4b4789d78a96d76f503b3262","title":"Oxygen Builder","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/component-framework\/vendor\/aos\/aos.js","AOS.init","oxygen_init_pro_menu","oxy-pro-menu-show-dropdown","oxy-shape-divider","oxygenVSBInitToggleJs"],"is_default":0,"condition":"oxygen\/functions.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"ebd282b9-e175-4b83-90a2-fe12389ccd11":{"id":"plugin:6f9419e58ec86c94e7698aaaaf9dc715","title":"PageLoader by Bonfire","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/pageloader-by-bonfire\/pageloader.js","bonfire-pageloader-overlay"],"is_default":0,"condition":"pageloader-by-bonfire\/pageloader-by-bonfire.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"0baf6353-aa70-41a9-a3bc-d89870a5839b":{"id":"plugin:3a4c4518eb0f60108ab4934fab27d335","title":"PDF Embedder","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/pdf-embedder\/js\/(.*).js"],"is_default":0,"condition":"pdf-embedder\/pdf_embedder.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"cba51ec1-87cc-44eb-b12b-d652e3446507":{"id":"plugin:4f90aca5957cccbf623e3bbc31afa204","title":"Perfect Brands for WooCommerce","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/perfect-woocommerce-brands\/assets\/lib\/slick\/slick.min.js","\/perfect-woocommerce-brands\/assets\/js\/functions-frontend.min.js"],"is_default":0,"condition":"perfect-woocommerce-brands\/perfect-woocommerce-brands.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"808e7a4e-025c-4fae-bf82-de3716e5eb0d":{"id":"plugin:84fe214646388d7c021dda25003ac165","title":"Photonic","type":"plugin","icon":"","exclusions":["\/photonic\/include\/js\/front-end\/module\/photonic-baguettebox.min.js"],"is_default":0,"condition":"photonic\/photonic.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"936aff7d-a8ac-4473-a7b5-4b1611b6c557":{"id":"plugin:6838be282f853f71be282783cb1c162b","title":"Pixel Caffein","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/pixel-caffeine\/build\/frontend.js","aepc_pixel"],"is_default":0,"condition":"pixel-caffeine\/pixel-caffeine.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"ab3a4ef5-2732-4b46-a7c3-17b4e9405cd1":{"id":"plugin:afe0eb7c64d4556a7111c56dd8c4d307","title":"Pixel Manager for WooCommerce","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/woocommerce-pixel-manager-pro\/js\/public\/","wpm"],"is_default":0,"condition":"woocommerce-pixel-manager-pro\/woocommerce-pixel-manager.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"2774f964-50b2-425e-8a30-0a02f421b7e4":{"id":"plugin:38d4b2986868f543639cd1ebc3e510aa","title":"Popup Builder","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/popup-builder\/public\/js\/(.*).js","\/popupbuilder-exit-intent\/public\/javascript\/ExitIntent.js","var sgpbPublicUrl","SGPB_POPUP_PARAMS"],"is_default":0,"condition":"popup-builder\/popup-builder.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"82dbb1e5-31f9-43d7-b522-52819aa49ba5":{"id":"plugin:786717922362642f34a7ff58e919bd95","title":"Popup Maker","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-includes\/js\/jquery\/ui\/core.min.js","\/pum\/pum-site-scripts.js","pum","\/plugins\/popup-maker\/assets\/js\/site.min.js"],"is_default":0,"condition":"popup-maker\/popup-maker.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"48e08305-1f1c-4ef4-9f13-24af1b155abc":{"id":"plugin:17831cbb64e469c7f66224c8c63d0a58","title":"PowerPack Addons for Elementor","type":"plugin","icon":"","exclusions":["\/powerpack-lite-for-elementor\/assets\/js\/min\/frontend.min.js"],"is_default":0,"condition":"powerpack-lite-for-elementor\/powerpack-lite-elementor.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"e037ae2f-e36b-4f1a-ada8-eb8fde6746f2":{"id":"plugin:80e1283ea1afead3ca904fad792643c5","title":"Preloader Plus","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/preloader-plus\/(.*)"],"is_default":0,"condition":"preloader-plus\/preloader-plus.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"90fed478-e89a-455c-8371-836bee58fb81":{"title":"Premium Addons for Elementor","condition":"premium-addons-for-elementor\/premium-addons-for-elementor.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/premium-addons-for-elementor\/assets\/frontend\/min-js\/premium-addons.min.js","\/premium-addons-for-elementor\/assets\/frontend\/min-js\/isotope.min.js","\/premium-addons-elementor\/pa-frontend-(.*).min.js","\/premium-addons-for-elementor\/assets\/frontend\/min-js\/slick.min.js","\/premium-addons-pro\/assets\/frontend\/min-js\/tooltipster.min.js","window.scopes_array","lottie.min.js","\/premium-addons-for-elementor\/assets\/frontend\/min-js\/premium-nav-menu.min.js"],"icon_url":"","type":"plugin","id":"plugin:debbfbbcbdf9ffb465bbc40008d99f02","is_default":0,"created_at":1693315214},"7e43c261-77be-48fc-b25a-8953a654ae85":{"id":"plugin:100a0382fcf3d1b6b22da928bce46ea8","title":"Presto Player","type":"plugin","icon":"","exclusions":["\/wp-includes\/js\/dist\/vendor\/regenerator-runtime.min.js","\/presto-player\/dist\/components\/web-components\/web-components.esm.js","\/presto-player\/src\/player\/player-static.js","var player","\/wp-includes\/js\/dist\/api-fetch.min.js","\/wp-includes\/js\/dist\/hooks.min.js","\/wp-includes\/js\/dist\/i18n.min.js"],"is_default":0,"condition":"presto-player\/presto-player.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"3d6f509f-d040-4279-9a2f-a4e6eae1e9df":{"id":"plugin:c0fce700121492b566517e68301db382","title":"Price Based on Country for WooCommerce Pro","type":"plugin","icon":"","exclusions":["\/woocommerce-product-price-based-on-countries\/assets\/js\/ajax-geolocation.min.js","\/woocommerce-price-based-country-pro-addon\/assets\/js\/currency-switcher.min.js","add-to-cart.min.js","cart-fragments.min.js"],"is_default":0,"condition":"woocommerce-price-based-country-pro-addon\/woocommerce-price-based-country-pro-addon.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"b970bc8a-bcbe-4d08-8ac0-a6853ab3f036":{"id":"plugin:f1ecfe258440b371124999ca3bfbfff3","title":"Prime Slider","type":"plugin","icon":"","exclusions":["\/plugins\/bdthemes-prime-slider-lite\/assets\/js\/bdt-uikit.min.js"],"is_default":0,"condition":"bdthemes-prime-slider-lite\/bdthemes-prime-slider.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"e5458963-f167-4b68-88e4-77dd39af2842":{"id":"plugin:29ea8f4dd72f5a5c5927917fb0665a05","title":"PRO Elements","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/pro-elements\/"],"is_default":0,"condition":"pro-elements\/pro-elements.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"b119ad72-f498-4576-bb71-9e6d8c37b68f":{"title":"Product Filter by WBW (for WooCommerce)","condition":"woo-product-filter\/woo-product-filter.php","exclusions":["\/jquery-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?$","\/jquery-migrate(.*)(.min|.slim|.slim.min)?.js(\\?(.*))?$","\/wp-content\/plugins\/woo-product-filter\/modules\/woofilters\/js\/frontend.woofilters.js","\/wp-includes\/js\/jquery\/ui\/mouse.min.js","\/wp-includes\/js\/jquery\/ui\/core.min.js","\/wp-includes\/js\/jquery\/ui\/slider.min.js"],"icon_url":"","type":"plugin","id":"plugin:e57ad91e0d94fab011353af544873743","is_default":0,"created_at":1685686062},"7b779aca-e497-4da3-8e51-fa12837d15ab":{"title":"Product Filters for WooCommerce","condition":"woocommerce-product-filters\/woocommerce-product-filters.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/woocommerce-product-filters\/","\/woocommerce\/assets\/js\/accounting\/accounting.min.js","\/wp-includes\/js\/jquery\/ui\/","wcpf-load-project","WCPFData"],"icon_url":"","type":"plugin","id":"plugin:719469f1c977f7109d3d6ee21ecd5a16","is_default":0,"created_at":1691235154},"2b2a51f2-bd47-4591-92d8-4a690bce5d99":{"id":"plugin:a898898b2b0ea2cd82e20a6d3a3aa47b","title":"Product Gallery Slider for WooCommerce","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/twist\/assets\/js\/slick.min.js","wpgs-public-js-after"],"is_default":0,"condition":"twist\/twist.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"062c5be3-e5ea-4958-9619-44e3410f237e":{"title":"Product Video Gallery for Woocommerce","condition":"product-video-gallery-slider-for-woocommerce\/product-video-gallery-slider-for-woocommerce.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/product-video-gallery-slider-for-woocommerce\/public\/js\/nickx.front.js"],"icon_url":"","type":"plugin","id":"plugin:bbc653a91f0635cd2edb0b741aa62b85","is_default":0,"created_at":1693512477},"34d225a4-688c-476b-846b-420774160d6b":{"id":"plugin:e0b123d324c6fc85b8682660c34f8829","title":"Rank Math SEO","type":"plugin","icon":"","exclusions":["local_ga_js"],"is_default":0,"condition":"seo-by-rank-math\/rank-math.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"02305ca0-2c2a-4eef-a802-b8a942771ecc":{"title":"Retainful","condition":"retainful-next-order-coupon-for-woocommerce\/retainful-next-order-coupon-for-woocommerce.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/retainful-next-order-coupon-for-woocommerce\/src\/premium\/assets\/js\/atc-popup.min.js","\/retainful-next-order-coupon-for-woocommerce\/src\/premium\/assets\/js\/exit-intent-popup.js","retainful.com","rnoc-add-to-cart-js-before","rnoc_redirect_coupon_popup"],"icon_url":"","type":"plugin","id":"plugin:f9fdee19ba6aed961d96d86e1521a761","is_default":0,"created_at":1679331508},"b4055250-5813-400f-b663-d390fee989e4":{"title":"Revolution Slider","condition":"revslider\/revslider.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/revslider\/public\/assets\/js\/","\/revslider\/sr6\/assets\/js\/","\/revslider-(.*)-addon\/","setREVStartSize","rev_slider_","revslider_","window.RS_MODULES","\/revslider\/public\/js\/libs\/tptools.js","\/revslider\/public\/js\/sr7.js","SR7"],"icon_url":"","type":"plugin","id":"plugin:d6a4d07d1b4022d886df52322dcd8a6f","is_default":0,"created_at":1714049967},"0b4e061a-b366-4d5a-a00e-bded4b107133":{"title":"Royal Elementor Addons","condition":"royal-elementor-addons\/wpr-addons.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/royal-elementor-addons\/assets\/js\/frontend.min.js","\/royal-elementor-addons\/assets\/js\/lib\/jarallax\/jarallax.min.js"],"icon_url":"","type":"plugin","id":"plugin:c4b464373716d7ac8e3cfb019aaa6102","is_default":0,"created_at":1688124503},"1b19ec89-171a-4f85-8c4b-b1bcfc6b1433":{"id":"plugin:5e3f85d8c82cc184b945415d1a862601","title":"Sassy Social Share","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/sassy-social-share\/public\/js\/sassy-social-share-public.js","heateorSssLoadEvent"],"is_default":0,"condition":"sassy-social-share\/sassy-social-share.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"f5899925-2ab7-43b6-abc4-51b76d664ca6":{"title":"Scrollsequence","condition":"scrollsequence-pro\/scrollsequence-pro.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/scrollsequence-pro\/public\/js\/gsap__premium_only.js","\/scrollsequence-pro\/public\/js\/gsap-scrolltrigger__premium_only.js","\/scrollsequence-pro\/public\/js\/ssq-lib__premium_only.js","scrollsequence-input-script"],"icon_url":"","type":"plugin","id":"plugin:3df51830b6b80668fc342c8dcea495cf","is_default":0,"created_at":1678111131},"043827fc-3df8-45d6-9cd2-14fbe962987a":{"id":"plugin:9d60b5d2de4d828b78c7b088024377d6","title":"ShiftNav Pro - Responsive Mobile Menu","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/shiftnav-pro\/assets\/js\/shiftnav(.*).js"],"is_default":0,"condition":"shiftnav-pro\/shiftnav.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"bcbaf240-e76f-4620-b7d5-4852c46d4be7":{"id":"plugin:56279bd768c8f27ad1972b6774738bcf","title":"ShiftNav \u2013 Responsive Mobile Menu","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/shiftnav-responsive-mobile-menu\/"],"is_default":0,"condition":"shiftnav-responsive-mobile-menu\/shiftnav-responsive-mobile-menu.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"bbe0543b-b5af-467b-a90d-e2975d892d8d":{"title":"Short Pixel Adaptive Image","condition":"shortpixel-adaptive-images\/short-pixel-ai.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/shortpixel-adaptive-images\/assets\/js\/ai(.*).min.js","spai_settings"],"icon_url":"","type":"plugin","id":"plugin:1bc7ac87d8ab2301a1b904919dc7a798","is_default":0,"created_at":1704734942},"543ab43a-6bd3-4948-a09e-3b95e7c9209d":{"title":"Showcase IDX","condition":"showcase-idx\/showcaseidx.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","SIDX","search.showcaseidx.com\/js\/app-(.*).js","cdn.shortpixel.ai"],"icon_url":"","type":"plugin","id":"plugin:ce4dea8ddc3caa8d00e95cec3202d32a","is_default":0,"created_at":1704734988},"a16bcab7-1169-46b9-a425-b091478d8312":{"id":"plugin:3ea7d9f75ad03620b0bce2517bd5b8d1","title":"Side Cart WooCommerce","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/plugins\/woocommerce\/assets\/js\/frontend\/cart-fragments.min.js","\/plugins\/woocommerce\/assets\/js\/frontend\/add-to-cart.min.js","\/plugins\/woocommerce\/assets\/js\/jquery-blockui\/jquery.blockUI.min.js","\/plugins\/woocommerce\/assets\/js\/js-cookie\/js.cookie.min.js"],"is_default":0,"condition":"side-cart-woocommerce\/xoo-wsc-main.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"521f748e-cf09-4019-bd28-b52daef5f16f":{"id":"plugin:7843983bf90dbae16c6e889382c71b23","title":"Simple Banner","type":"plugin","icon":"","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/simple-banner\/","simpleBannerScriptParams"],"is_default":0,"condition":"simple-banner\/simple-banner.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"76026e82-d9cf-482c-b480-55c57693a184":{"id":"plugin:b6825f971d35a5515d095564a2e40936","title":"Site Kit by Google","type":"plugin","icon":"","exclusions":["google-analytics.com\/analytics.js","ga\\( '","ga\\('","\/gtag\/js","gtag\\(","\/gtm.js"],"is_default":0,"condition":"google-site-kit\/google-site-kit.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"4f9be7dd-fa19-401c-a5a5-81654990f9c4":{"title":"SiteOrigin Widgets Bundle - Load images","condition":"so-widgets-bundle\/so-widgets-bundle.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/so-widgets-bundle\/js\/slider\/jquery.slider.min.js","\/so-widgets-bundle\/js\/jquery.cycle.min.js","\/so-widgets-bundle\/js\/jquery.cycle.swipe.min.js","\/so-widgets-bundle\/js\/sow.jquery.fittext.min.js","\/so-widgets-bundle\/js\/lib\/jquery.fitvids.min.js","\/siteorigin-panels\/js\/styling.min.js","siteorigin-panels-before-js","page_id"],"icon_url":"","type":"plugin","id":"plugin:3968480c93d7f92ed1cb78a54b47fc9f","is_default":0,"created_at":1716234178},"79c458d7-f7f7-4072-919d-ad337bde6ae3":{"title":"Slick Menu","condition":"slick-menu\/slick-menu.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/slick-menu\/"],"icon_url":"","type":"plugin","id":"plugin:5ce5dfecdc9d3292c69a1413bbd17d3c","is_default":0,"created_at":1704735027},"99cf4942-49ea-4687-b156-405ed1ce1cfa":{"title":"Slide Anything","condition":"slide-anything\/slide-anything.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/slide-anything\/owl-carousel\/owl.carousel.min.js","owl_goto.trigger"],"icon_url":"","type":"plugin","id":"plugin:fff874cc48b80940210228c975df395c","is_default":0,"created_at":1702907355},"dd0ea584-0c99-4c30-b46d-da35b94c9f0a":{"title":"Slider by Soliloquy","condition":"soliloquy-lite\/soliloquy-lite.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","soliloquy-min.js","soliloquy_slider"],"icon_url":"","type":"plugin","id":"plugin:ffb5f8cc0ea17886dbd05f601ca3eec0","is_default":0,"created_at":1704735068},"ecb2fffc-d289-4f68-ae94-71131f17deee":{"title":"Smart Slider 3","condition":"smart-slider-3\/smart-slider-3.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/smart-slider-3\/(.*).js","_N2"],"icon_url":"","type":"plugin","id":"plugin:2f373822dceb191c31c8ad2183d51869","is_default":0,"created_at":1704735119},"284ede43-bf80-419e-8414-46c26cb746f0":{"title":"Smart Slider 3 Pro","condition":"nextend-smart-slider3-pro\/nextend-smart-slider3-pro.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/SmartSlider3\/(.*).js","_N2"],"icon_url":"","type":"plugin","id":"plugin:720ec9fbbd8a52ce525959a68a5310b3","is_default":0,"created_at":1704735152},"be70034f-def5-4771-9b3f-662eb218da2a":{"title":"Spectra - Show Slider Images","condition":"ultimate-addons-for-gutenberg\/ultimate-addons-for-gutenberg.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/ultimate-addons-for-gutenberg\/assets\/js\/spectra-animations.min.js","\/ultimate-addons-for-gutenberg\/assets\/js\/post.min.js","\/ultimate-addons-for-gutenberg\/assets\/js\/aos.min.js","\/slick.min.js","\/imagesloaded.min.js","UAGBPostCarousel"],"icon_url":"","type":"plugin","id":"plugin:af16af31f83a874b9d0a9570d9c15ff7","is_default":0,"created_at":1706824485},"c3334c29-4160-42df-a1ce-f8aeeaee8668":{"title":"Super Socializer","condition":"super-socializer\/super_socializer.php","exclusions":["theChamp","\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js"],"icon_url":"","type":"plugin","id":"plugin:660defe26748470c3a47366cd4012579","is_default":0,"created_at":1677853633},"f18b4242-fe3f-4e2b-bfc9-ac2fb3939a90":{"title":"Superfly Menu","condition":"superfly-menu\/main.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate((.*?)(.min?)?).js","\/superfly-menu\/includes\/vendor\/looks_awesome\/icon_manager\/js\/md5.js","\/superfly-menu\/includes\/vendor\/looks_awesome\/icon_manager\/js\/util.js","\/superfly-menu\/js\/public.min.js","window.SFM_is_mobile","var SFM_skew_disabled","var SFM_template"],"icon_url":"","type":"plugin","id":"plugin:ccb15175093bc6c437b78797f0698a7b","is_default":0,"created_at":1684301673},"1a05c00a-8562-45bc-80e8-987a4574b1c9":{"title":"Symplr Ads","condition":"symplr-ads\/symplr-plugin.php","exclusions":["\/symplr-ads\/","cdns.symplr.de"],"icon_url":"","type":"plugin","id":"plugin:3b6d39e28a87e86c4659491e2368ff61","is_default":0,"created_at":1692199959},"858d2d7f-bdac-4d27-ba26-baa9ace96ba4":{"id":"plugin:7d93008296bb5c7c43d4cba185ed2632","title":"Tabby Responsive Tabs","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/tabby-responsive-tabs\/js\/tabby.js","RESPONSIVEUI"],"is_default":0,"condition":"tabby-responsive-tabs\/tabby-responsive-tabs.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"e44a5c93-bb77-4624-a121-d846905137ea":{"id":"plugin:2f563bbb7e92363ec3fb2989a1c7dffe","title":"The Plus Addons for Elementor","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/theplus-addons\/(.*)"],"is_default":0,"condition":"the-plus-addons-for-elementor-page-builder\/theplus_elementor_addon.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"2bbac961-b000-4802-ae97-d52472ec6750":{"title":"The Plus Addons for Elementor Premium","condition":"theplus_elementor_addon\/theplus_elementor_addon.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/wp-content\/plugins\/theplus_elementor_addon\/","\/elementor\/","\/elementor-pro\/","\/wp-includes\/js\/imagesloaded.min.js","ElementorProFrontendConfig","elementorFrontendConfig"],"icon_url":"","type":"plugin","id":"plugin:6e127deaaeefbe57ff945b1f9e274518","is_default":0,"created_at":1688143611},"666b45e8-749c-4140-bd17-e1cd589e03ee":{"id":"plugin:b9c418b47c986935a1151ab9b42f8971","title":"ThemeREX Addons","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/trx_addons\/js\/__scripts-full.js","\/trx_addons\/components\/cpt\/layouts\/shortcodes\/menu\/superfish.min.js"],"is_default":0,"condition":"trx_addons\/trx_addons.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"a750cada-eb58-4df4-9966-21c8a69332ba":{"id":"plugin:75af9efe22c5cc776636266feb55adf1","title":"Thrive Architect","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js"],"is_default":0,"condition":"thrive-visual-editor\/thrive-visual-editor.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"13714cde-680e-4ca4-8607-c35952d6a5f2":{"title":"Thrive Comments","condition":"thrive-comments\/thrive-comments.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/thrive-leads\/","window.TL_Const","var ml=","\/thrive-comments\/assets\/js\/","ThriveComments","\/wp-includes\/js\/underscore.min.js","\/wp-includes\/js\/backbone.min.js"],"icon_url":"","type":"plugin","id":"plugin:6a72d06ca2f6a888b0d9d5ea93af2edc","is_default":0,"created_at":1677852974},"aa7ca898-499f-4f04-b419-3de199996969":{"id":"plugin:b84d82c02cade64ade00712b9c5652aa","title":"Thrive Leads","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/thrive-leads\/","window.TL_Const","var ml=","\/thrive-comments\/assets\/js\/","ThriveComments","\/wp-includes\/js\/underscore.min.js","\/wp-includes\/js\/backbone.min.js"],"is_default":0,"condition":"thrive-leads\/thrive-leads.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"9eee297a-8241-4ef2-af97-46074bd0898c":{"id":"plugin:5bb61b0559b0a3fd578315b553451327","title":"Thrive Quiz Builder","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js"],"is_default":0,"condition":"thrive-quiz-builder\/thrive-quiz-builder.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"c2f3ec2a-5b09-4845-aa95-84841783fbfc":{"id":"plugin:a7f3e5206abff19ca7cf142260181738","title":"Thrive Ultimatum","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/thrive-ultimatum\/","var TVE_Ult_"],"is_default":0,"condition":"thrive-ultimatum\/thrive-ultimatum.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"d48b8d2f-e071-4a30-840a-306154a115a0":{"id":"plugin:f57be2014b6a489d053f8367fa6c0f9f","title":"Tidio Chat","type":"plugin","icon":"","exclusions":["document.tidioChatCode"],"is_default":0,"condition":"tidio-live-chat\/tidio-elements.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"cb6d33ed-7eb4-4ff9-9ad0-7fc54fbecf6f":{"id":"plugin:c9e0485ec256d4a6a8d92a98c18d76fc","title":"Toolset Blocks","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","toolsetCommonEs.fontToHead","toolsetCommonEs.styleToHead","\/toolset-blocks\/vendor\/toolset\/blocks\/public\/js\/frontend.js","\/toolset-blocks\/vendor\/toolset\/common-es\/public\/toolset-common-es-frontend.js","\/toolset-blocks\/public\/js\/views-frontend.js","\/wp-includes\/js\/underscore.min.js"],"is_default":0,"condition":"toolset-blocks\/wp-views.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"4bac6350-0925-49fb-904a-372f22fd6baf":{"id":"plugin:71beda322b37f7fc7d456822493cb972","title":"Top Bar Pro","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/plugins\/topbar-pro\/js\/tpbr_front.min.js","\/plugins\/topbar-pro\/js\/jquery.cookie.js"],"is_default":0,"condition":"topbar-pro\/topbar_pro.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"033486e7-0ddc-4915-a848-31504d00448e":{"title":"Twenty20 Image Before-After","condition":"twenty20\/ttwenty.php","exclusions":["\/twenty20\/assets\/js\/(.*).js","\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","twentytwenty-container"],"icon_url":"","type":"plugin","id":"plugin:23441bba9d3602bc932d697c7cb8aa1f","is_default":0,"created_at":1677858089},"bef2147e-2d0b-431d-ac29-5e8430c0d809":{"title":"Typing Effect","condition":"animated-typing-effect\/typingeffect.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/plugins\/animated-typing-effect\/assets\/js\/typed.js","\/plugins\/animated-typing-effect\/assets\/js\/typed.fe.js"],"icon_url":"","type":"plugin","id":"plugin:e4e1a3e63d09a28dcb20577efbcb5a48","is_default":0,"created_at":1711400446},"7675a34d-006e-4672-99d5-a81e1b8e47f9":{"id":"plugin:3d59cc34167a7f8123e66b627148e0b7","title":"UberMenu","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/ubermenu\/assets\/js\/ubermenu.min.js"],"is_default":0,"condition":"ubermenu\/ubermenu.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"8233178a-e7b3-43ce-b193-bd0d9c960933":{"id":"plugin:86424c46157c1c7e2e1571055813beee","title":"Ultimate Addons for Elementor","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/ultimate-elementor\/assets\/lib\/slick\/slick.min.js","\/ultimate-elementor\/assets\/min-js\/uael-frontend.min.js","\/ultimate-elementor\/assets\/lib\/isotope\/isotope.min.js","\/ultimate-elementor\/assets\/lib\/jquery-element-resize\/jquery_resize.min.js","\/ultimate-elementor\/assets\/lib\/fancybox\/jquery_fancybox.min.js","\/ultimate-elementor\/assets\/lib\/justifiedgallery\/justifiedgallery.min.js","\/elementor-pro\/assets\/js\/frontend.min.js","\/wp-includes\/js\/imagesloaded.min.js","\/js_composer\/assets\/js\/dist\/js_composer_front.min.js","\/elementor\/assets\/lib\/swiper\/swiper.min.js","\/nasa-core\/assets\/js\/min\/jquery.slick.min.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig"],"is_default":0,"condition":"ultimate-elementor\/ultimate-elementor.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"8bddf484-6c78-4147-a4e6-d3039904e5f6":{"title":"Ultimate Addons for Elementor - Mobile Menu","condition":"ultimate-elementor\/ultimate-elementor.php","exclusions":["\/jquery-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?$","\/jquery-migrate(.*)(.min|.slim|.slim.min)?.js(\\?(.*))?$","\/ultimate-elementor\/assets\/js\/uael-nav-menu.js","\/ultimate-elementor\/assets\/min-js\/uael-nav-menu.min.js"],"icon_url":"","type":"plugin","id":"plugin:70cfade3a7adbb54196f6acccc5a176f","is_default":0,"created_at":1694771327},"028504f7-b1cd-4318-8a6d-ce186197e89d":{"id":"plugin:0f0a91f0c454021a5ff9fc25c3ed419f","title":"Ultimate Addons for WPBakery Page Builder","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/Ultimate_VC_Addons\/assets\/"],"is_default":0,"condition":"Ultimate_VC_Addons\/Ultimate_VC_Addons.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"5754af3d-a6af-49eb-b731-bdd82f26dc4e":{"id":"plugin:34db8636812bad84c8aea037c2ddc8c2","title":"Ultimate Responsive Image Slider","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","sliderPro"],"is_default":0,"condition":"ultimate-responsive-image-slider\/ultimate-responsive-image-slider.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"78ae882d-ae31-4179-b677-8893814938c7":{"title":"Unlimited Elements for Elementor Premium - Slider","condition":"unlimited-elements-for-elementor-premium\/unlimited-elements-pro.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elementor\/","\/elementor-pro\/","ElementorProFrontendConfig","elementorFrontendConfig","\/unlimited-elements-for-elementor-premium\/","uc_"],"icon_url":"","type":"plugin","id":"plugin:17260bc347b8c29bee0010e9ec164184","is_default":0,"created_at":1683270377},"051cbfbb-7ad2-4f06-a493-3cf423a80904":{"id":"plugin:6717ef5673a956bc08ca4a5117065d53","title":"Variation Swatches for WooCommerce","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/jquery\/ui\/","\/woo-variation-swatches\/","\/woo-variation-swatches-pro\/","underscore.min.js"],"is_default":0,"condition":"woo-variation-swatches\/woo-variation-swatches.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"6879caba-7224-4eca-bcb2-370785b495ea":{"id":"plugin:57597b7683e01892932083413f085134","title":"Web Accessibility By accessiBe","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/accessibe\/","acsbJS"],"is_default":0,"condition":"accessibe\/accessiebe.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"bd6732fe-4c2b-40a1-9035-8464057e2da5":{"title":"WooCommerce - Cart Fragments","condition":"woocommerce\/woocommerce.php","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/woocommerce\/assets\/js\/frontend\/cart-fragments.min.js","\/woocommerce\/assets\/js\/js-cookie\/js.cookie.min.js"],"icon_url":"","type":"plugin","id":"plugin:201de694c6fc28c8d580a3b2ca484218","is_default":0,"created_at":1680937567},"d044900d-07e1-4533-9516-33106efcb259":{"title":"WooCommerce - Product description","condition":"woocommerce\/woocommerce.php","exclusions":["\/plugins\/woocommerce\/assets\/js\/frontend\/single-product.min.js","\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js"],"icon_url":"","type":"plugin","id":"plugin:a82644b4c9417ea3a240939a73344700","is_default":0,"created_at":1679309756},"bff953b1-2213-4666-8112-76a84a3cc207":{"title":"WooCommerce - Product Gallery","condition":"woocommerce\/woocommerce.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/woocommerce\/?(.*)\/assets\/js\/zoom\/jquery.zoom(.min)?.js","\/woocommerce\/?(.*)\/assets\/js\/photoswipe\/","\/woocommerce\/?(.*)\/assets\/js\/flexslider\/jquery.flexslider(.min)?.js","\/woocommerce\/?(.*)\/assets\/js\/frontend\/single-product(.min)?.js","wc_single_product_params"],"icon_url":"","type":"plugin","id":"plugin:7665868ff97c265628f376523a4f9ecc","is_default":0,"created_at":1686579689},"016e6ddf-c6e7-49ec-bd3f-2585d9e45895":{"title":"WooCommerce - Select2 library","condition":"woocommerce\/woocommerce.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/woocommerce\/assets\/js\/select2\/select2(.*).js"],"icon_url":"","type":"plugin","id":"plugin:4bca670bd5d55dd24b17fb0193b0891e","is_default":0,"created_at":1681459540},"b9b2c6d7-944f-4ae3-ae04-c9e2204b9dab":{"id":"plugin:9165c768e978d6ad3f696db8c78ccbb2","title":"WooCommerce Attribute Swatches","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/iconic-woo-attribute-swatches-premium\/assets\/frontend\/js\/main.min.js","\/iconic-woo-attribute-swatches-premium\/assets\/vendor\/flickity\/flickity.pkgd.min.js","iconic_was_vars"],"is_default":0,"condition":"iconic-woo-attribute-swatches-premium\/iconic-woo-attribute-swatches.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"4506c5e9-7349-44c9-9967-34370c83facb":{"title":"WooCommerce Bookings","condition":"woocommerce-bookings\/woocommerce-bookings.php","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/woocommerce-bookings\/dist\/frontend.js","\/wp-includes\/js\/dist\/date.min.js","\/wp-includes\/js\/dist\/vendor\/moment.min.js","\/wp-includes\/js\/jquery\/ui\/datepicker.min.js","\/wp-includes\/js\/underscore.min.js","\/woocommerce\/assets\/js\/jquery-blockui\/jquery.blockUI.min.js","\/wp-includes\/js\/dist\/hooks.min.js"],"icon_url":"","type":"plugin","id":"plugin:14dec6d289b9977fa3a74116feecebcc","is_default":0,"created_at":1693998405},"fec9cd04-c358-45da-a1a8-1668b964016b":{"id":"plugin:456f3b849ba3b6647246aca9d7cdaed5","title":"WooCommerce Product Reviews Pro","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","wc_product_reviews_pro","\/woocommerce-product-reviews-pro\/assets\/js\/frontend\/wc-product-reviews-pro-frontend.min.js","\/woocommerce\/assets\/js\/jquery-tiptip\/jquery.tipTip.min.js"],"is_default":0,"condition":"woocommerce-product-reviews-pro\/woocommerce-product-reviews-pro.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"551a9399-627f-4978-9bae-5cc8e0aefc82":{"id":"plugin:c8577e74eef3b082fb6403760d53f68c","title":"WooCommerce TM Extra Product Options","type":"plugin","icon":"","exclusions":["\/woocommerce-tm-extra-product-options\/assets\/js\/epo.min.js","\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-includes\/js\/jquery\/ui\/core.min.js","\/wp-includes\/js\/jquery\/ui\/mouse.min.js","\/wp-includes\/js\/jquery\/ui\/slider.min.js","\/wp-includes\/js\/underscore.min.js","\/wp-includes\/js\/wp-util.min.js","\/wp-includes\/js\/dist\/hooks.js","\/wp-includes\/js\/dist\/i18n.js"],"is_default":0,"condition":"woocommerce-tm-extra-product-options\/tm-woo-extra-product-options.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"3cac4650-6a52-448e-8e48-e99a772a59a2":{"id":"plugin:c6e6cab8c80fa3fe57d609f72d2d5c56","title":"WooLentor","type":"plugin","icon":"","exclusions":["\/woolementor\/assets\/third-party\/slick\/slick.min.js","\/woolentor-addons","woolentor_addons"],"is_default":0,"condition":"woolentor-addons\/woolentor_addons_elementor.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"21af073d-d2ec-4d46-bbda-2c69f87f3f98":{"title":"Woolentor - Fix product gallery","condition":"woolentor-addons\/woolentor_addons_elementor.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)",".woolentor-learg-img","\/woolentor-addons\/assets\/js\/slick.min.js","\/woolentor-addons-pro\/assets\/lib\/js\/tippy.min.js"],"icon_url":"","type":"plugin","id":"plugin:c5315e06dfc353cd57f85a60abe4e320","is_default":0,"created_at":1700061004},"67aeb4cb-1a00-4d10-a00c-34888b4c0dba":{"title":"WooThumbs for WooCommerce","condition":"woothumbs-premium\/woothumbs-premium.php","exclusions":["\/wp-includes\/js\/dist\/hooks.min.js","\/wp-includes\/js\/underscore.min.js","\/wp-includes\/js\/wp-embed.min.js","\/wp-includes\/js\/wp-util.min.js","\/woothumbs-premium\/(.*)"],"icon_url":"","type":"plugin","id":"plugin:b97b1d3f627769e1dd8305aa25af993c","is_default":0,"created_at":1679065404},"c7a14763-88d0-4344-a6af-e0a8dc5fa8d5":{"id":"plugin:31b9e812a025e5750a6ef0980ee7d2db","title":"WordPress Mega Menu \u2013 QuadMenu","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/quadmenu","#private-menu","#public-menu"],"is_default":0,"condition":"quadmenu\/quadmenu.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"f699fdbd-84a7-4f24-b729-3e4a4f83a4dd":{"id":"plugin:601f8fc7d10cad1c2ec2949c0d9b1651","title":"WP Armour","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/honeypot\/includes\/js\/wpa.js","\/wp-armour-extended\/includes\/js\/wpae.js","wpa_hidden_field","wpa_add_test"],"is_default":0,"condition":"wp-armour-extended\/wp-armour-extended.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"6a28aae5-ef91-43fc-8204-92e3a25642b4":{"id":"plugin:5728f3b9856dfe37a36ab15b0a637198","title":"WP Go Maps","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","maps.googleapis.com"],"is_default":0,"condition":"wp-google-maps\/wpGoogleMaps.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"c9b991d1-a653-404b-be85-e276b1814e7d":{"title":"WP Google Map Pro","condition":"wp-google-map-gold\/wp-google-map-gold.php","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","maps.google.com\/maps\/api\/js","\/wp-includes\/js\/masonry.min.js","\/wp-google-map-gold\/(.*)"],"icon_url":"","type":"plugin","id":"plugin:dc12a9b7b9c4c7ce3c532b6b377739f2","is_default":0,"created_at":1677858391},"1f8f9fbf-fbf0-4e3a-b77c-af0fa47e950d":{"id":"plugin:87f572f5f0ec143a8fceba77d0616197","title":"WP Google Maps Pro","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-google-maps(.*)","maps.googleapis.com","mgl_","wpgmza"],"is_default":0,"condition":"wp-google-maps-pro\/wp-google-maps-pro.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"41e4b98c-e63f-4800-a478-02592562322b":{"id":"plugin:3735ca768ede98b25795f4cb057ff4ed","title":"WP iCal Availability","type":"plugin","icon":"","exclusions":["\/wp-ical-availability\/js\/custom-select.js","\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-ical-availability\/"],"is_default":0,"condition":"wp-ical-availability\/wp-ical-availability.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"2b06c5b8-dc32-4bb0-8504-3a9f1c3a1ec0":{"title":"WP MapIt","condition":"wp-mapit\/wp_mapit.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-mapit\/wp_mapit\/js\/leaflet.js","\/wp-mapit\/wp_mapit\/js\/wp_mapit_multipin.js"],"icon_url":"","type":"plugin","id":"plugin:ba8d1c7f294a3f5b593556eb3b0bc7d9","is_default":0,"created_at":1679331261},"2039eafd-1c11-4e21-a61b-30857f291ae3":{"id":"plugin:927b8bf7806f2d287559b86a0b455a59","title":"WP Responsive Menu","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-responsive-menu\/(.*)"],"is_default":0,"condition":"wp-responsive-menu\/wp-responsive-menu.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"e06be942-cccd-4b2d-a268-06dc78f0b820":{"title":"WP Search with Algolia","condition":"wp-search-with-algolia\/algolia.php","exclusions":["\/wp-search-with-algolia\/js\/algoliasearch\/dist\/algoliasearch-lite.umd.js","\/wp-search-with-algolia\/js\/autocomplete-noconflict.js","\/wp-search-with-algolia\/js\/autocomplete.js\/dist\/autocomplete.min.js","var algolia"],"icon_url":"","type":"plugin","id":"plugin:43267e659d599fbb6b42c719b49bb7a7","is_default":0,"created_at":1677857180},"4fc2a7ae-b9e6-410e-93cf-e6d1962add6a":{"title":"WP Smart Preloader","condition":"wp-smart-preloader\/wp-preloader.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/wp-smart-preloader\/assets\/js\/wsp-main-script(.min)?.js"],"icon_url":"","type":"plugin","id":"plugin:4fb90fc73fc2b5d1e37ea2dadfd3cef3","is_default":0,"created_at":1711125833},"7ecf40ce-2bcd-412c-bb01-9e71fecf6be8":{"title":"WP Store Locator","condition":"wp-store-locator\/wp-store-locator.php","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-store-locator\/","\/wp-includes\/js\/underscore.min.js","maps.google.com"],"icon_url":"","type":"plugin","id":"plugin:d37bb5054a24471ca1675d9ab49d01b0","is_default":0,"created_at":1704735183},"7a1d19a2-3a48-40ab-8051-f642fc63ce2d":{"title":"WP Ultimate Post Grid","condition":"wp-ultimate-post-grid\/wp-ultimate-post-grid.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?$","\/wp-ultimate-post-grid\/dist\/public.js","\/wp-ultimate-post-grid-premium\/dist\/public-premium.js","wpupg_grid_args"],"icon_url":"","type":"plugin","id":"plugin:e24341fef49bd64b89682d583218c108","is_default":0,"created_at":1686597940},"76c86163-ddf3-4113-b620-de9d5058f505":{"title":"WPBakery Page Builder","condition":"js_composer\/js_composer.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/js_composer\/assets\/js\/dist\/js_composer_front.min.js"],"icon_url":"","type":"plugin","id":"plugin:517d7d24da9a7072ed389d0fb30374a0","is_default":0,"created_at":1704404852},"0b8ff2c0-c3cd-4ec1-b7f5-c7751de6101b":{"title":"WPBakery Page Builder - Carousel","condition":"js_composer\/js_composer.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/js_composer\/assets\/lib\/vc_carousel\/js\/vc_carousel.min.js"],"icon_url":"","type":"plugin","id":"plugin:76336ed3f04df091e669f89d908ef2ed","is_default":0,"created_at":1704405212},"4f5e5b98-c326-4b9f-9ada-3b257862132c":{"id":"plugin:1ec7138c950c355e7af60d49c81139fc","title":"wpDataTables","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wpdatatables\/","highcharts"],"is_default":0,"condition":"wpdatatables\/wpdatatables.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"18be1b8c-0bc4-4a01-abc6-a127aff380c6":{"id":"plugin:c62ca58ea081c1271de8dadfa7daac69","title":"WPForms","type":"plugin","icon":"","exclusions":["\/wpforms-offline-forms\/assets\/js\/wpforms-offline-forms.min.js","wpforms-offline-forms-js-extra","wpformsRecaptchaLoad"],"is_default":0,"condition":"wpforms\/wpforms.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"138b2894-25d2-47ce-b33d-cbf1256d8f45":{"title":"WPForms - Loader GIF","condition":"wpforms\/wpforms.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/wpforms-conversational-forms\/assets\/js\/conversational-forms.es5.min.js"],"icon_url":"","type":"plugin","id":"plugin:03dc6ae2848dd60e1d4f4f86015c22f0","is_default":0,"created_at":1715863299},"8a3cacb6-81bd-456a-a1cc-a4025f8e5234":{"id":"plugin:0992ac952c0a05bb35e18b1d5744d346","title":"WPForms Lite","type":"plugin","icon":"","exclusions":["wpformsRecaptchaLoad","\/wpforms-offline-forms\/assets\/js\/wpforms-offline-forms.min.js","wpforms-offline-forms-js-extra"],"is_default":0,"condition":"wpforms-lite\/wpforms.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"98bbd410-5b01-4244-a8eb-715765180328":{"title":"XL WooCommerce Sales Triggers","condition":"xl-woocommerce-sales-triggers\/xl-woocommerce-sales-triggers.php","exclusions":["\/xl-woocommerce-sales-triggers\/assets\/js\/wcst_combined.min.js","\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js"],"icon_url":"","type":"plugin","id":"plugin:ba9e526ddb0157e69757530c6b18b714","is_default":0,"created_at":1677856813},"bf9f9620-dd0e-4e6f-9a45-4eb78a148f42":{"id":"plugin:58663fc781232169e865f6fe7cf1afaa","title":"YITH WooCommerce Ajax Product Filter","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/yith-woocommerce-ajax-navigation\/assets\/js\/yith-wcan-shortcodes.min.js"],"is_default":0,"condition":"yith-woocommerce-ajax-navigation\/init.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"b053279d-e07c-438c-bb3e-3a1f4f5d7c5e":{"id":"plugin:68b637fd247e40c8e135e4771d739b07","title":"YITH WooCommerce AJAX Product Filter Premium","type":"plugin","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/yith-woocommerce-ajax-product-filter-premium\/assets\/js\/yith-wcan-shortcodes.min.js"],"is_default":0,"condition":"yith-woocommerce-ajax-product-filter-premium\/init.php","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"62056165-8bd9-4ff0-b21f-e4ed0ae45fae":{"title":"YITH WooCommerce Points and Rewards","condition":"yith-woocommerce-points-and-rewards-premium\/init.php","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/yith-woocommerce-points-and-rewards-premium\/assets\/js\/frontend.min.js","\/woo-variation-swatches-pro\/assets\/js\/add-to-cart-variation.min.js"],"icon_url":"","type":"plugin","id":"plugin:4acc87d4eb72c86cdea76d180b61a098","is_default":0,"created_at":1709917756},"d94dbbf3-bcab-4e47-9fbb-6b3a7cf92787":{"title":"Yotpo Social Reviews for Woocommerce","condition":"yotpo-social-reviews-for-woocommerce\/wc_yotpo.php","exclusions":["\/yotpo-social-reviews-for-woocommerce\/assets\/js\/headerScript.js"],"icon_url":"","type":"plugin","id":"plugin:45ab742b3fccbd04d7bc973c8582be87","is_default":0,"created_at":1680686421},"51dccf53-5cc7-4283-9ab1-01d34c6cce22":{"title":"Zoho SalesIQ","condition":"zoho-salesiq\/index.php","exclusions":["zoho.salesiq"],"icon_url":"","type":"plugin","id":"plugin:b96c3865575068aac82c973eb3e3c52a","is_default":0,"created_at":1713536671}},"themes":{"9aeea459-91d3-44b6-8a26-b883dca8b402":{"title":"Agensy - Load page without User Interaction","condition":"agensy","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/themes\/agensy\/js\/scripts.js","\/themes\/agensy\/js\/scripts-single.js","\/themes\/agensy\/js\/wow.min.js","\/themes\/agensy\/js\/TweenMax.min.js","\/themes\/agensy\/js\/swiper.min.js","\/plugins\/visualcomposer\/assets\/lib\/bower\/isotope\/dist\/isotope.pkgd.min.js","\/wp-includes\/js\/imagesloaded.min.js"],"icon_url":"","type":"theme","id":"theme:7ab7dfeb0db9c0c74c020be318c2e6d9","is_default":0,"created_at":1707317936},"9c623554-5834-4669-9e96-1b894c1939b2":{"id":"theme:0193ea55fce2ada93b262f2824008c0f","title":"Andaman","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/andaman\/assets\/js\/","\/wp-andaman-plugins\/shortcodes\/vc_extend\/"],"is_default":0,"condition":"andaman","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"7374c5a5-69f8-460f-b44f-dee884a824cd":{"id":"theme:24cbda63f1b898ade5562ab4ec6d97a5","title":"Artale","type":"theme","icon":"","exclusions":["\/artale-elementor\/assets\/js\/modulobox.js","\/artale-elementor\/assets\/js\/artale-elementor.js","\/artale\/js\/jquery-stellar.js","\/artale\/js\/core\/artale-plugins.js","\/artale\/js\/core\/artale-custom.js","var loader"],"is_default":0,"condition":"artale","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"23b01203-2a70-4394-9326-d59824def2d7":{"title":"Ashe Pro Premium","condition":"ashe-pro-premium","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/ashe-pro-premium\/"],"icon_url":"","type":"theme","id":"theme:4791da3cbbd1ed86253a087f0287aeb4","is_default":0,"created_at":1704912793},"03a9cc62-c167-447d-beb2-65c76c96b056":{"title":"Astra","condition":"astra","exclusions":["\/astra\/assets\/js\/minified\/frontend.min.js","replace\\(\/woocommerce-no-js\/,"],"icon_url":"","type":"theme","id":"theme:3cce5f3eaf76e098ba8e28f7bbba3f92","is_default":0,"created_at":1712608792},"2a2b54cb-8e1d-49d2-bfca-93eee231e470":{"id":"theme:72a8d63e59c10bdf512a62b862d143a7","title":"Astra - Carousel","type":"theme","icon":"","exclusions":["var astra","\/astra\/assets\/js\/minified\/style.min.js"],"is_default":0,"condition":"astra","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"7783361f-66fc-4d95-a054-4e9545bb5b48":{"title":"Auteur","condition":"g5plus-auteur","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/g5plus-auteur\/assets\/js\/core.min.js","\/g5plus-auteur\/assets\/vendors\/","\/auteur-framework\/libs\/smart-framework\/assets\/vendors\/perfect-scrollbar\/js\/perfect-scrollbar.jquery.min.js","\/wp-includes\/js\/imagesloaded.min.js"],"icon_url":"","type":"theme","id":"theme:6207fe478e269e7547bda70a46607a49","is_default":0,"created_at":1679737107},"4c618038-8fc7-4d48-8d41-a32da14e5c1e":{"title":"AutoTrader","condition":"autotrader","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/autotrader\/(.*).js"],"icon_url":"","type":"theme","id":"theme:046dfeee2b77390c53e0e7f93b6a3792","is_default":0,"created_at":1679736741},"18f04f23-35a0-4c45-8cb6-a91d57ca1790":{"id":"theme:835da12f43373029659f766920e81b47","title":"Avada - Animations & mobile-specific actions","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/uploads\/fusion-scripts\/(.*).js","window.off_canvas_","\/plugins\/fusion-builder\/","\/plugins\/fusion-core\/","\/Avada\/includes\/"],"is_default":0,"condition":"Avada","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"90135867-1b95-498b-80d6-f5dbf2f6b318":{"title":"Avada - FAQ shortcode","condition":"Avada","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/plugins\/fusion-core\/js\/min\/avada-faqs.js"],"icon_url":"","type":"theme","id":"theme:b084708c80d8582546e5430219aa4670","is_default":0,"created_at":1678277160},"d23b5bb1-1d7f-4109-bf69-b20a2be2d337":{"id":"theme:5e7a2248e1a53d9bb27b187deb541248","title":"Avada - Fusion carousel","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/includes\/lib\/assets\/min\/js\/library\/jquery.carouFredSel.js","\/includes\/lib\/assets\/min\/js\/general\/fusion-carousel.js","fusionCarouselVars"],"is_default":0,"condition":"Avada","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"98dfa8c1-e72a-4cef-a0b2-8f0c322490fc":{"id":"theme:f16fb109027f4994a7649a8b1663e6f7","title":"Avada - Fusion form","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/fusion-builder\/assets\/js\/min\/general\/fusion-form.js","\/fusion-builder\/assets\/js\/min\/general\/fusion-form-logics.js","\/includes\/lib\/assets\/min\/js\/library\/cssua.js","\/includes\/lib\/assets\/min\/js\/general\/fusion.js","\/includes\/lib\/assets\/min\/js\/library\/modernizr.js"],"is_default":0,"condition":"Avada","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"026801fa-af67-47ba-b966-347693f0585f":{"id":"theme:33f50696d353d8bd4eb59ff6e8f44c97","title":"Avada - Fusion grid gallery","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/fusion-builder\/assets\/js\/min\/general\/fusion-gallery.js","\/includes\/lib\/assets\/min\/js\/library\/imagesLoaded.js","\/includes\/lib\/assets\/min\/js\/library\/isotope.js","\/includes\/lib\/assets\/min\/js\/library\/packery.js","\/includes\/lib\/assets\/min\/js\/library\/lazysizes.js"],"is_default":0,"condition":"Avada","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"c8349314-15a3-481e-973b-e4d936e4420e":{"id":"theme:56fa9993a573540c83eda9c49fae5e3c","title":"Avada - Fusion slider","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/fusion-core\/js\/min\/avada-fusion-slider.js","\/Avada\/includes\/"],"is_default":0,"condition":"Avada","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"7a04bc85-0fec-4487-ae05-bb2e5d8d0420":{"title":"Avada - Load Portfolio on pageload","condition":"Avada","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/library\/packery.js","\/library\/isotope.js","\/library\/imagesLoaded.js","\/general\/fusion-lightbox.js","\/fusion-core\/js\/min\/avada-portfolio.js"],"icon_url":"","type":"theme","id":"theme:c3f0ed4d94499b68c77d95db37d1d399","is_default":0,"created_at":1696601814},"55bd510c-78aa-49d5-8304-8be2ee2ab0da":{"id":"theme:2189c1c769d65cfc2182e4822847071b","title":"Avada - Mobile menu","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/assets\/min\/js\/general\/avada-menu.js","\/includes\/lib\/assets\/min\/js\/library\/modernizr.js","\/includes\/lib\/assets\/min\/js\/library\/jquery.easing.js"],"is_default":0,"condition":"Avada","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"ddf00672-c35c-4b68-aeca-925e68bf12b2":{"id":"theme:97a185f08af70c39c7e221faab0f73eb","title":"Avada - OffCanvas","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/uploads\/fusion-scripts\/(.*).min.js","window.off_canvas_"],"is_default":0,"condition":"Avada","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"17544cc3-9d3a-4611-bc5d-44d04e2786fa":{"title":"Avada - Show the Portfolio grid on page load","condition":"Avada","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/includes\/lib\/assets\/min\/js\/library\/imagesLoaded.js","\/includes\/lib\/assets\/min\/js\/library\/isotope.js","\/includes\/lib\/assets\/min\/js\/library\/lazysizes.js","\/includes\/lib\/assets\/min\/js\/library\/modernizr.js","\/includes\/lib\/assets\/min\/js\/library\/packery.js","\/fusion-core\/js\/min\/avada-portfolio.js","avadaPortfolioVars"],"icon_url":"","type":"theme","id":"theme:9d1a9b0c2ca20fca764a82f197b962fd","is_default":0,"created_at":1696601823},"c6c3347c-14e0-4766-afa5-df33a47f5a5a":{"id":"theme:3ff44421b404c5efffa25e78e479e4ea","title":"Avada - Sticky menu","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/Avada\/assets\/min\/js\/general\/avada-menu.js"],"is_default":0,"condition":"Avada","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"232596c1-6a6a-4fe8-a5c3-a60fa74a9456":{"id":"theme:0d727d80bb132f17c737e55883fe4be0","title":"Avada - WooCommerce product gallery","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/assets\/min\/js\/general\/avada-woo-product-images.js","\/includes\/lib\/assets\/min\/js\/library\/jquery.flexslider.js"],"is_default":0,"condition":"Avada","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"95ece7e4-3b19-45e5-aa28-14f833c9afca":{"title":"Avesa","condition":"avesa","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/avesa\/js\/main.js","\/avesa\/js\/isotope.js","\/sw_core\/js\/slick.min.js","\/avesa\/js\/bootstrap-datetimepicker.min.js","\/avesa\/js\/bootstrap.min.js"],"icon_url":"","type":"theme","id":"theme:aad8bfcc594eec02e3b0d635198dee5e","is_default":0,"created_at":1679737993},"f2bfe477-4e45-4e52-a7d9-4d0ba3a92258":{"title":"Besa","condition":"besa","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/besa\/js\/"],"icon_url":"","type":"theme","id":"theme:c238e89523c46ca28b08e401f42f6ccc","is_default":0,"created_at":1679738204},"bd94908c-8138-4995-986b-47ec66494bdd":{"title":"BeTheme","condition":"betheme","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/betheme\/","mfn","\/wp-includes\/js\/jquery\/ui\/tabs.min.js","\/wp-includes\/js\/jquery\/ui\/core.min.js"],"icon_url":"","type":"theme","id":"theme:b99156eb9eeb357c0a70bd3bda6861cc","is_default":0,"created_at":1679738639},"190d2f1a-72a6-40ca-b08a-5c7ee7b0a6a5":{"title":"Bosa Online Education - Fixes animations and preloader","condition":"bosa-online-education","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/bosa\/assets\/js\/jquery.slicknav.min.js","\/bosa\/assets\/slick\/slick.min.js","\/bosa\/assets\/js\/navigation.js","\/bosa\/assets\/js\/custom.min.js","\/bosa\/assets\/js\/theia-sticky-sidebar.min.js"],"icon_url":"","type":"theme","id":"theme:5430bf7b83c83a3687b3b7b437e961b0","is_default":0,"created_at":1708371742},"6fb2b9d7-6ecc-4260-999c-938fbebdbf01":{"id":"theme:de8504b73ea228d0ea9bbce69752092e","title":"Bridge","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/bridge-creative\/bridge\/js\/","\/wp-includes\/js\/"],"is_default":0,"condition":"bridge","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"1dd63427-b4c9-4596-b952-ac711e3637f9":{"title":"Bridge - Load elements without user interaction","condition":"bridge","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/wp-content\/themes\/bridge\/js\/default.min.js","\/wp-content\/themes\/bridge\/js\/plugins.js","\/wp-content\/themes\/bridge\/js\/default_dynamic.js","\/wp-content\/themes\/bridge\/js\/jquery.touchSwipe.min.js"],"icon_url":"","type":"theme","id":"theme:ad9b810efd365ad9a27987d2912b94cd","is_default":0,"created_at":1710252260},"65698b6b-85dd-41ef-8fd7-718f1e983dba":{"title":"Car Dealer","condition":"cardealer","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-includes\/js\/jquery\/(.*)","\/cardealer\/js\/(.*)"],"icon_url":"","type":"theme","id":"theme:b1111424fff61af8d1e152dcdd6810f6","is_default":0,"created_at":1679737517},"3927d724-5a0a-402b-a838-858d30b54ea9":{"title":"Cardea - Show Page Content on Load","condition":"cardea-wp","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/themes\/cardea-wp\/js\/main.js","\/themes\/cardea-wp\/js\/jquery.sticky.js","\/themes\/cardea-wp\/js\/jquery.fitvids.js","\/themes\/cardea-wp\/js\/jquery.smartmenus.min.js"],"icon_url":"","type":"theme","id":"theme:d65d1a8303b0c7508278884520e4bec7","is_default":0,"created_at":1698677525},"087fb457-a09d-4140-84bd-c9bc1e8195b7":{"title":"CheerUp","condition":"cheerup","exclusions":["\/cheerup\/js\/jquery.sticky-sidebar.js","\/cheerup\/js\/object-fit-images.js","\/cheerup\/js\/jquery.fitvids.js","\/cheerup\/js\/jquery.mfp-lightbox.js","\/cheerup\/js\/ie-polyfills.js","\/cheerup\/js\/theme.js","\/wp-includes\/js\/imagesloaded.min.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/wp-includes\/js\/jquery\/jquery.min.js"],"icon_url":"","type":"theme","id":"theme:13bcf562f45afb245dc4f76fecfba6d6","is_default":0,"created_at":1696429398},"eb86aedb-91e6-480c-b76c-756ac1da41be":{"title":"Clover","condition":"clover-theme","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/clover-theme\/"],"icon_url":"","type":"theme","id":"theme:89372f3d9321ae09c94488592084da29","is_default":0,"created_at":1679738878},"6e90b649-5736-497f-9bc6-515900cfea8a":{"title":"Divi - Animations","condition":"Divi","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js",".dipi_preloader_wrapper_outer","\/Divi\/js\/scripts.min.js","\/Divi\/js\/custom.unified.js","\/js\/magnific-popup.js","var DIVI"],"icon_url":"","type":"theme","id":"theme:c0abf30dba4ff13db836d1b01685953a","is_default":0,"created_at":1679737389},"70916c43-4e02-4932-b6aa-91a1815bc755":{"title":"Divi - Background video","condition":"Divi","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate.min.js","\/Divi\/js\/custom.unified.js","\/js\/mediaelement\/(.*)","mejs"],"icon_url":"","type":"theme","id":"theme:c7edea41ae6716291e2d32a2ab429209","is_default":0,"created_at":1679738240},"08531785-9818-4e30-903e-564637a2ad7a":{"title":"Divi - Counter module","condition":"Divi","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js",".dipi_preloader_wrapper_outer","\/Divi\/js\/scripts.min.js","\/Divi\/js\/custom.unified.js","\/js\/magnific-popup.js","var DIVI","\/Divi\/includes\/builder\/feature\/dynamic-assets\/assets\/js\/easypiechart.js"],"icon_url":"","type":"theme","id":"theme:2c46b9f5a770f260c3f7115bb330b2d5","is_default":0,"created_at":1679736810},"b996762a-84ef-440d-a089-73a187936fbf":{"title":"Divi - Mobile menu","condition":"Divi","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate.min.js","\/Divi\/js\/scripts.min.js","\/Divi\/js\/custom.unified.js"],"icon_url":"","type":"theme","id":"theme:b9116994f4e4b9b9fa574440c00d2f0d","is_default":0,"created_at":1679738580},"ae096e1e-9c36-46ad-a3d1-c26ea507276b":{"title":"Divi - Sticky elements","condition":"Divi","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js",".dipi_preloader_wrapper_outer","\/Divi\/js\/scripts.min.js","\/Divi\/includes\/builder\/feature\/dynamic-assets\/assets\/js\/sticky-elements.js","var DIVI"],"icon_url":"","type":"theme","id":"theme:8b62db03c90245f3e690335b079b05dc","is_default":0,"created_at":1679737191},"349f31f0-dd10-41d3-b0a4-9c5df64879f8":{"title":"Divi - Sticky menu","condition":"Divi","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/js\/jquery\/jquery-migrate.min.js","\/Divi\/js\/scripts.min.js","\/Divi\/includes\/builder\/feature\/dynamic-assets\/assets\/js\/magnific-popup.js","jqueryParams","firstHeader"],"icon_url":"","type":"theme","id":"theme:b7b84aca0f0dc6a1ced31d38626c50ea","is_default":0,"created_at":1679738821},"59563458-5f04-4959-b3e2-53e49e169d67":{"title":"Divi - WooCommerce Single Product Images","condition":"Divi","exclusions":["\/Divi\/js\/scripts.min.js"],"icon_url":"","type":"theme","id":"theme:f9c5bdba8b39fc877b41dea00fa756f9","is_default":0,"created_at":1684342262},"6426539e-4e43-4fef-ab5a-3eb7b2a8b057":{"title":"Eikra","condition":"eikra","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate.min.js","\/eikra\/assets\/js\/","EikraObj"],"icon_url":"","type":"theme","id":"theme:55d2581ad975eb6325bc97fc3d3b0cb8","is_default":0,"created_at":1679738450},"59020bd6-069f-4f2d-afa2-fbdefa03211c":{"title":"Ekko","condition":"ekko","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/ekko\/"],"icon_url":"","type":"theme","id":"theme:2c06f4a1949f8ba4e77042a47674fd9e","is_default":0,"created_at":1679737803},"d82f5cdd-c5d3-4596-94dc-1e25aaff2083":{"title":"Elessi","condition":"elessi-theme","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/elessi-theme\/assets\/js\/min\/functions.min.js","\/elessi-theme\/assets\/js\/min\/main.min.js"],"icon_url":"","type":"theme","id":"theme:d5d2b7fda7b8a2b5b91d430f7602e230","is_default":0,"created_at":1679737773},"f0587c21-54d0-429d-8efe-18a93dacb18d":{"id":"theme:5fc04cc678cb54567aedb51027933002","title":"Enfold","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/dynamic_avia\/avia-footer-scripts-(.*).js","var avia_is_mobile"],"is_default":0,"condition":"enfold","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"c93ee1ee-3956-4278-9ee9-1a0968753e86":{"title":"Enfold - Fix hamburger menu","condition":"enfold","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/enfold\/js\/avia-snippet-hamburger-menu.js","\/enfold\/js\/avia.js","\/enfold\/js\/shortcodes.js","\/enfold\/js\/waypoints\/waypoints.js"],"icon_url":"","type":"theme","id":"theme:2b0c22c5169b94c2eabb125d18915246","is_default":0,"created_at":1715090218},"cc0550cb-918e-419d-b4f2-1809cf666dbb":{"id":"theme:eb759a03d0ca292c948f09d004a2963f","title":"Enfold - LayerSlider","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","layerslider"],"is_default":0,"condition":"enfold","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"ec883654-4f63-4fae-a3ef-923dcbc2426d":{"title":"Enfold - Shortcodes","condition":"enfold","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/enfold\/js\/avia(.min)?.js","\/enfold\/js\/shortcodes(.min)?.js","\/enfold\/config-templatebuilder\/avia-shortcodes\/","\/enfold\/js\/avia-compat(.min)?.js","\/enfold\/js\/waypoints\/waypoints.min.js","\/enfold\/js\/avia-snippet-(.*).js","\/enfold\/js\/avia-js(.min)?.js","\/enfold\/js\/aviapopup\/jquery.magnific-popup(.min)?.js"],"icon_url":"","type":"theme","id":"theme:072fc4077d7071791d774d6ddbf5dc2a","is_default":0,"created_at":1712954619},"fe3546f0-be3e-4173-8992-a7f6f203b82f":{"title":"Envision","condition":"envision","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/envision\/lib\/js\/app.min.js","var CloudFwOp"],"is_default":1,"icon_url":"","type":"theme","id":"theme:fc5f7d69b646ed95835badc0fc23bc11","created_at":1679737494},"d997b942-19de-4710-9c81-79d3c65cbd76":{"id":"theme:047f009f2a1f4cdf2088c46be47e385b","title":"Ewebot","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/gt3-themes-core\/","\/uploads\/gt3-assets\/js\/(.*)","\/wp-includes\/js\/imagesloaded.min.js"],"is_default":0,"condition":"ewebot","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"53d29aec-8ae4-4273-b748-f5bd52dfe177":{"title":"Farvis","condition":"farvis","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/farvis\/"],"icon_url":"","type":"theme","id":"theme:26bff2f3a6ff6347d35edf5c77a35687","is_default":0,"created_at":1679737972},"fb01246b-a5f8-4021-b514-c02cf55e80bd":{"title":"Flatsome","condition":"flatsome","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/flatsome\/assets\/js\/flatsome.js","\/flatsome\/assets\/libs\/packery.pkgd.min.js","\/flatsome\/assets\/js\/woocommerce.js"],"icon_url":"","type":"theme","id":"theme:26fb1cf80f074ca199d8a7e94c5fc796","is_default":0,"created_at":1679738732},"4d65dc12-9ce7-4171-94a7-9821fd95240e":{"id":"theme:28a6f8b3319c107a34603be0f01a4bcf","title":"Flatsome - Google map","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","maps.googleapis.com","google.maps.LatLng","\/wp-includes\/js\/hoverIntent.min.js"],"is_default":0,"condition":"flatsome","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"890e15b6-c66b-4a9e-9b7d-55417df94916":{"title":"Flatsome - Images","condition":"flatsome","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/flatsome\/inc\/integrations\/wp-rocket\/flatsome-wp-rocket.js","\/flatsome\/assets\/js\/flatsome.js","\/flatsome\/inc\/extensions\/flatsome-lazy-load\/flatsome-lazy-load.js"],"icon_url":"","type":"theme","id":"theme:f2d60aad9f2f5395e3e145cf8f8ab165","is_default":0,"created_at":1679737691},"cb54d070-8ee0-4c35-9fa9-b2bac73ccf39":{"title":"Frida","condition":"frida","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/frida\/"],"icon_url":"","type":"theme","id":"theme:109ddf56796a5133e12279f3daa5ff62","is_default":0,"created_at":1679738013},"435fe79f-47ba-422e-aca6-cea566f6b8a1":{"title":"Gardena Theme","condition":"gardena","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/gardena\/"],"icon_url":"","type":"theme","id":"theme:993e6f0fc44b9e55c0a565b84a449340","is_default":0,"created_at":1713905793},"9e78539a-03d9-442b-ab94-dd3b7a9658e4":{"id":"theme:80a330247d61d729fcd78dc01de6ed2f","title":"GeneratePress - Mobile menu","type":"theme","icon":"","exclusions":["\/generatepress\/assets\/js\/menu.min.js","generatepressMenu","\/gp-premium\/menu-plus\/functions\/js\/offside.min.js"],"is_default":0,"condition":"generatepress","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"02d47d01-56f5-4801-b319-cff1707dd59d":{"title":"Harmuny - Modern WordPress Blog Theme","condition":"harmuny","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/harmuny\/"],"icon_url":"","type":"theme","id":"theme:1ff9662c2a3e3221052cbe229feed18c","is_default":0,"created_at":1712153245},"6373bbb2-877c-4075-b6e4-7c58d686b25c":{"title":"HealthFirst - Prevent console errors","condition":"healthfirst","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/wp-includes\/js\/hoverIntent.min.js","\/wp-content\/plugins\/healthfirst-core\/assets\/js\/healthfirst-core.min.js","\/wp-content\/plugins\/healthfirst-core\/assets\/plugins\/modernizr\/modernizr.js","\/wp-content\/plugins\/healthfirst-core\/assets\/plugins\/perfect-scrollbar\/perfect-scrollbar.jquery.min.js","\/wp-content\/themes\/healthfirst\/assets\/js\/main.min.js","\/wp-content\/themes\/healthfirst\/assets\/plugins\/waitforimages\/jquery.waitforimages.js"],"icon_url":"","type":"theme","id":"theme:d244b3c692f8d023048207dbe9eb84da","is_default":0,"created_at":1699370973},"2c72e7e6-cb77-44e9-af87-d5c42ae6db52":{"title":"Honor - WPBakery fix","condition":"honor","exclusions":["\/honor\/js\/__scripts.js","HONOR_STORAGE","\/js_composer\/"],"icon_url":"","type":"theme","id":"theme:9f228373ff4d172655dbf5cb3b1bc23a","is_default":0,"created_at":1679736895},"9309d1d3-1035-4a2c-8ced-075bc3ff9957":{"title":"HotelMaster","condition":"hotelmaster","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/hotelmaster\/javascript\/gdlr-script.js","\/hotelmaster\/plugins\/dl-menu\/modernizr.custom.js","\/hotelmaster\/plugins\/dl-menu\/jquery.dlmenu.js","\/hotelmaster\/plugins\/superfish\/js\/superfish.js","\/hotelmaster\/plugins\/jquery.easing.js"],"icon_url":"","type":"theme","id":"theme:978eaddad3b1047e479407b6d92197aa","is_default":0,"created_at":1679738595},"4a09f745-cbb1-47c8-b50a-c8014d5d1335":{"id":"theme:e813a548bceac6765a1cdf2316f1a6ab","title":"HotelMaster - Blog","type":"theme","icon":"","exclusions":["\/wp-includes\/js\/masonry.min.js","\/gp-premium\/blog\/functions\/js\/scripts.min.js","\/wp-includes\/js\/imagesloaded.min.js"],"is_default":0,"condition":"hotelmaster","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"f2d8f704-ec68-4278-9ca2-885daa0c1ce5":{"id":"theme:398a264e302e42640553681e8759cd07","title":"HotelMaster - Masonry","type":"theme","icon":"","exclusions":["\/gp-premium\/menu-plus\/functions\/js\/offside.min.js","offSide"],"is_default":0,"condition":"hotelmaster","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"92b2e258-1f44-41c1-b1bd-f117f61ee49d":{"title":"Jannah Theme - Fix masonry grid","condition":"jannah","exclusions":["\/wp-includes\/js\/jquery\/jquery.min.js","\/wp-includes\/js\/masonry.min.js","\/wp-includes\/js\/jquery\/jquery.masonry.min.js","tie-"],"icon_url":"","type":"theme","id":"theme:35f7f183089309f52046377ca65e905a","is_default":0,"created_at":1699642920},"df52436c-53d6-461a-b81a-cd0b21680524":{"title":"JNews","condition":"jnews","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate.min.js","\/jnews\/assets\/js\/","jnews","jfla"],"icon_url":"","type":"theme","id":"theme:5d90e451984f9d894b1aabb0d00f30a2","is_default":0,"created_at":1679738860},"87ed69a2-3295-4fad-a82e-eeb02925a5dc":{"title":"Jobify","condition":"jobify","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/jobify\/js\/jobify.min.js","\/jobify\/js\/select2.full.min.js"],"icon_url":"","type":"theme","id":"theme:592006aa4562a6915e344e5e2a09e5ee","is_default":0,"created_at":1704735224},"28a0b1ea-8d2f-4931-a48a-166b8df8a773":{"title":"JOYN","condition":"joyn","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/swift-framework\/includes\/page-builder\/frontend-assets\/js\/lib\/modernizr-custom.js","\/swift-framework\/includes\/page-builder\/frontend-assets\/js\/spb-functions.min.js","\/swift-framework\/includes\/swift-slider\/assets\/js\/swift-slider.min.js","\/swift-framework\/public\/js\/lib\/imagesloaded.pkgd.min.js","\/joyn\/js\/owl.carousel.min.js","\/joyn\/js\/theme-scripts.js","\/joyn\/js\/functions.js"],"icon_url":"","type":"theme","id":"theme:c395470ad2d4d681836cd942bbb03120","is_default":0,"created_at":1679738527},"542be60a-2346-4740-9a41-8a580c4f013c":{"title":"Juno Toys","condition":"junotoys","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate.min.js","\/junotoys\/fw\/js\/core.init.js","\/junotoys\/fw\/js\/core.utils.js","\/junotoys\/fw\/js\/superfish.js","\/junotoys\/fw\/js\/swiper\/swiper.js","\/trx_utils\/shortcodes\/theme.shortcodes.js","\/wp-includes\/js\/jquery\/ui\/(.*)"],"icon_url":"","type":"theme","id":"theme:2acab38e8356d36355bb81d931e7fba4","is_default":0,"created_at":1679737788},"06167710-10c7-446e-a08b-ce676e444102":{"title":"Jupiter","condition":"jupiter","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/jupiter\/","\/wp-includes\/js\/underscore.min.js","WebFont.load"],"icon_url":"","type":"theme","id":"theme:89c5c30498c2989611f9044be006197c","is_default":0,"created_at":1679738430},"5d042e1f-7e62-4ec4-ba31-30d396004522":{"title":"JupiterX","condition":"jupiterx","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/jupiterx\/(.*).js","\/wp-includes\/js\/underscore.min.js","WebFont.load"],"icon_url":"","type":"theme","id":"theme:b06632962a4948d4944fd8d79ffbfceb","is_default":0,"created_at":1679737312},"c4b030ea-66a1-4729-85bf-a484e373a316":{"title":"Kadence","condition":"kadence","exclusions":["\/kadence\/assets\/js\/navigation.min.js","mobile_menu_breakpoint","kadenceConfig"],"icon_url":"","type":"theme","id":"theme:4b7907ee68218db279648da9bf7102d1","is_default":0,"created_at":1704735260},"20c605b4-3e3a-4bb0-a5e5-a08e2cb0f31f":{"title":"Kalium","condition":"kalium","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/kalium\/assets\/js\/main.min.js","mobile_menu_breakpoint","var _k"],"icon_url":"","type":"theme","id":"theme:1fcb99a1ab06e1e36635365ed3e59ce5","is_default":0,"created_at":1679737406},"e1e04a7d-635a-4e28-83d9-e345ce40e354":{"title":"Kava","condition":"kava","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/kava\/assets\/js\/theme-script.js"],"icon_url":"","type":"theme","id":"theme:359d67efbf530c998245225dd3245a88","is_default":0,"created_at":1679738609},"e833c36e-ee89-4924-b608-3f28327c2f85":{"title":"Lay","condition":"lay","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/backbone.min.js","\/wp-includes\/js\/underscore.min.js","\/lay\/","\/laytheme-carousel\/","window.laytheme"],"icon_url":"","type":"theme","id":"theme:7c718c6da874ea6e4b27c6d70bc4e7e8","is_default":0,"created_at":1679737453},"2df2ef47-a833-4711-ba54-48dc62586f37":{"id":"theme:85d9922ac61ed833fd047a67029df8e5","title":"LazaNews","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/jquery.custom.js"],"is_default":0,"condition":"lazanews","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"9443304a-34e9-4700-a03a-5f8f62f83ed1":{"title":"Listeo","condition":"listeo","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/listeo\/js\/"],"icon_url":"","type":"theme","id":"theme:db7da585545001f5ae614a2810f08f3a","is_default":0,"created_at":1679737244},"77afa73c-c4a8-42a8-aaee-43f6a761364e":{"title":"ListingPro","condition":"listingpro","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/listingpro\/assets\/lib\/jquerym.menu\/js\/jquery.mmenu.min.all.js","\/listingpro\/assets\/lib\/Magnific-Popup-master\/jquery.magnific-popup.min.js","\/listingpro\/assets\/js\/select2.full.min.js","\/listingpro\/assets\/js\/jquery.city-autocomplete.js","\/listingpro\/assets\/js\/chosen.jquery.min.js","\/listingpro\/assets\/lib\/bootstrap\/js\/bootstrap-slider.js","\/listingpro\/assets\/js\/jquery-ui.js","\/listingpro\/assets\/js\/mapbox.js","\/listingpro\/assets\/js\/main.js","\/listingpro\/assets\/js\/leaflet.markercluster.js","maps"],"icon_url":"","type":"theme","id":"theme:0b365e43dfc65d2b1b70fac6510c7c9c","is_default":0,"created_at":1679737938},"01b369b5-b578-4314-8e95-40b67a41d75a":{"title":"Master Study","condition":"masterstudy","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/masterstudy\/assets\/js\/custom.js","\/masterstudy\/assets\/vendors\/jquery.fancybox.min.js","\/masterstudy\/assets\/js\/select2.full.min.js"],"icon_url":"","type":"theme","id":"theme:0ee224c20e4ef7d546733d933db598f2","is_default":0,"created_at":1704735299},"6b000cc7-d33b-4109-9c39-6119a5d81cde":{"title":"Maya","condition":"maya","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/maya\/js\/jquery.mobilemenu.js","\/maya\/js\/jquery.custom.js","\/maya\/core\/includes\/js\/jquery.tipsy.js"],"icon_url":"","type":"theme","id":"theme:719fe28004fcdd81a820602924aa8074","is_default":0,"created_at":1679737916},"ef3c76d6-1041-473d-81ea-a5a6e8c86735":{"title":"MH Magazine","condition":"mh-magazine","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/mh-magazine\/"],"icon_url":"","type":"theme","id":"theme:2a0cd6efc2f46be69de61712729a2ec9","is_default":0,"created_at":1679737743},"9cbb2777-5524-43b8-af36-692b27452c0d":{"title":"Minimog","condition":"minimog","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/minimog\/"],"icon_url":"","type":"theme","id":"theme:61c0c235042359ee7d2a9035e79a7da2","is_default":0,"created_at":1679738135},"7eb81c74-8062-4a6c-bf66-b7c5bc160141":{"title":"Moozo Elementor","condition":"moozo-elementor","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/moozo-elementor\/assets\/js\/countdown.js","\/moozo-elementor\/assets\/vendor\/countdown\/countdown.min.js"],"icon_url":"","type":"theme","id":"theme:2ddb538c8e6b6c766fffd0d5c861fd82","is_default":0,"created_at":1679738623},"e90b7bfa-9ff6-4e1a-bf29-6207d55fdd39":{"title":"Motor","condition":"motor","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/motor\/js\/"],"icon_url":"","type":"theme","id":"theme:b33538179f5661a86cbe327a1793e199","is_default":0,"created_at":1683973354},"445e625a-f955-41fa-84de-65d9ea19be07":{"title":"My Listing","condition":"my-listing","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/my-listing\/assets\/","\/wp-includes\/js\/dist\/vendor\/moment.min.js","maps.googleapis.com","MyListing","_Explore_Settings"],"icon_url":"","type":"theme","id":"theme:afacb777229ddf5cabceacc64948057d","is_default":0,"created_at":1679737725},"00b8cd2d-2781-4fbb-ac5d-00750ba94ac9":{"title":"Neve - Mobile menu","condition":"neve","exclusions":["\/neve\/assets\/js\/build\/modern\/frontend.js"],"icon_url":"","type":"theme","id":"theme:5ae731cc06dd9284f8172675a6fe81ab","is_default":0,"created_at":1679738714},"483abc54-f1fc-47dc-bfc1-a269c7d1c849":{"title":"Newspaper - Images","condition":"Newspaper","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","tagdiv_theme.min.js","tdBlocksArray","\/wp-includes\/js\/underscore.min.js","\/td-cloud-library\/assets\/js\/","\/npm\/slick-carousel@1.8.1\/slick\/slick.min.js","tdb-gallery-wrap","tdBlocksArray","tdb_"],"icon_url":"","type":"theme","id":"theme:649ff22527bac2b1c8e0115cd3851d53","is_default":0,"created_at":1695805761},"50db8d14-d421-4237-be14-a6f7b5c11ec5":{"title":"Newspaper - Slider & YouTube","condition":"Newspaper","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","tagdiv_theme.min.js","tdBlocksArray","tdb_globals","td_youtube_list_ids","iosSlider","\/td-cloud-library\/assets\/js\/js_files_for_front.min.js","\/wp-includes\/js\/underscore.min.js","\/td-cloud-library\/assets\/js\/","\/npm\/slick-carousel@1.8.1\/slick\/slick.min.js","tdb-gallery-wrap","tdBlocksArray","tdb_"],"icon_url":"","type":"theme","id":"theme:7e2eeee57ae458c5959342eda6526bf1","is_default":0,"created_at":1695805747},"514f4c30-2b67-4648-960e-dfe1cc401ca5":{"title":"Niva","condition":"niva","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/niva\/js\/","\/sweetthemes-framework\/js\/","mt_typed"],"icon_url":"","type":"theme","id":"theme:c4838f73a344b829ed626635e210dcf4","is_default":0,"created_at":1679738256},"e67ee504-c3b1-455e-88ab-1fae8c830652":{"title":"OceanWP","condition":"oceanwp","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/oceanwp\/"],"icon_url":"","type":"theme","id":"theme:db37af4b7d12695d37d9256313a5f37a","is_default":0,"created_at":1679737552},"e44e240a-8765-4f4f-b67e-d54e4b727506":{"title":"OceanWP - Mobile menu","condition":"oceanwp","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/ocean-side-panel\/assets\/js\/side-panel.min.js","\/oceanwp\/assets\/js\/theme.vanilla.min.js"],"icon_url":"","type":"theme","id":"theme:9babbcd52b2ce558d299a06cd1130a11","is_default":0,"created_at":1679738463},"897b0100-958d-4a02-b6b2-1e753e9869f4":{"title":"PenNews","condition":"pennews","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/pennews\/js\/script.min.js","\/pennews\/js\/script.lib.min.js"],"icon_url":"","type":"theme","id":"theme:02811fa00bc1471bb5be0457ce0ee005","is_default":0,"created_at":1704735339},"edd3ba03-e0fd-4b6e-911b-60b29f3471bf":{"title":"Pharmacy Mentor","condition":"pharmacymentor","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/pharmacymentor\/"],"icon_url":"","type":"theme","id":"theme:3188aaf1ef2c39937450f2a14ebb1174","is_default":0,"created_at":1679738214},"725415ff-cc76-45cc-a131-3170e5aa30fc":{"title":"Porto","condition":"porto","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-includes\/js\/jquery\/ui\/","\/porto\/js\/theme.js","\/porto\/js\/theme.min.js"],"icon_url":"","type":"theme","id":"theme:8493f398f200c8dffe60d46439dd3360","is_default":0,"created_at":1679737758},"2c19bcec-f3ff-4873-bfd7-db6bc0f6433c":{"title":"Porto - Owl Carousel","condition":"porto","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/wp-includes\/js\/jquery\/ui\/","\/porto\/js\/theme(|.min).js","\/porto\/js\/libs\/owl.carousel(|.min).js","\/porto\/js\/theme-async(|.min).js","\/prettyPhoto\/jquery.prettyPhoto(|.min).js"],"icon_url":"","type":"theme","id":"theme:f34f5199fb7fca78852cd3fb7758f178","is_default":0,"created_at":1687527252},"5b11ec89-1cb2-4793-8b77-79e917e810a0":{"title":"Pro Theme - Fix menu and accordions","condition":"pro","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/pro\/cornerstone\/assets\/js\/site\/cs-classic.(.*).js"],"icon_url":"","type":"theme","id":"theme:8f30d70dd2d9a0386445aef8fdd534a9","is_default":0,"created_at":1708100602},"31347ccb-f69e-4cd3-bd47-b80ce14ac76e":{"title":"ProPhoto","condition":"prophoto7","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/prophoto7\/js\/bundle.front.js","\/wp-includes\/js\/underscore.min.js","PROPHOTO"],"icon_url":"","type":"theme","id":"theme:a5836a56c4472fade4dc6ebfe2281554","is_default":0,"created_at":1679737425},"a8208c04-865c-49aa-ab96-41e378d391c8":{"title":"Publisher","condition":"publisher","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/publisher\/js\/"],"icon_url":"","type":"theme","id":"theme:32c73be0cb175da278c8e2af0811b0d1","is_default":0,"created_at":1679738169},"a0d69f3d-1356-4a1d-a600-2f2f788b8a9a":{"title":"REHub","condition":"rehub-theme","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/rehub-theme\/js\/custom_floatpanel.js"],"icon_url":"","type":"theme","id":"theme:321af1febb74f488cf911380893739b2","is_default":0,"created_at":1679738502},"8b74bbe5-7f32-42df-908f-78c99a8cad82":{"title":"Rey","condition":"rey","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/rey\/scripts-(.*).js","\/rey-core\/assets\/js\/"],"icon_url":"","type":"theme","id":"theme:e46567cd0f3ec9b37e7230dc87eac367","is_default":0,"created_at":1679737011},"5c9115d3-bcbd-49d6-8feb-4880d2b82bfe":{"title":"Rife Free","condition":"rife-free","exclusions":["\/rife-free\/js\/script.min.js","\/rife-free\/js\/isotope.pkgd.min.js","\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","var reJS"],"icon_url":"","type":"theme","id":"theme:74a449954de79625eccc6750e87af8f6","is_default":0,"created_at":1679738107},"6542b2fd-1f91-4862-aa18-11eecc02faaf":{"title":"Roisin","condition":"roisin","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/themes\/roisin\/assets\/js\/main.min.js","\/plugins\/roisin-core\/assets\/js\/roisin-core.min.js","\/wp-includes\/js\/hoverIntent.min.js"],"icon_url":"","type":"theme","id":"theme:8f38fe58034772931110930b91cb6797","is_default":0,"created_at":1685964523},"5a192ad9-d150-4aa0-8efc-d68131cb7a37":{"title":"Sahifa - Mobile Menu","condition":"sahifa","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/themes\/sahifa\/js\/ilightbox.packed.js","\/translate_a\/element.js"],"icon_url":"","type":"theme","id":"theme:06ebe49f4c1e5b04cece831f8bb198a3","is_default":0,"created_at":1687540363},"7ae9d978-d63c-4a58-beb3-418bebb5b23c":{"title":"Salient","condition":"salient","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/salient\/","winW > bodyW"],"icon_url":"","type":"theme","id":"theme:b3e12d57ac23897be1bb2c673e3fc761","is_default":0,"created_at":1704735382},"35aaa6c5-4a37-4161-b504-fb3ebc4b1148":{"title":"Salient - Nectar slider","condition":"salient","exclusions":["\/salient-nectar-slider\/js\/nectar-slider.js","\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js"],"icon_url":"","type":"theme","id":"theme:d612db1dd8dc76faa6a36a9ebfd336dc","is_default":0,"created_at":1704735415},"84c95206-3e59-4eb3-a0c9-e2231a1c0a48":{"title":"SEO Lounge","condition":"seolounge","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?$","\/js_composer\/assets\/js\/dist\/js_composer_front.min.js","\/seolounge\/js\/radiantthemes-custom.js","\/seolounge\/js\/radiantthemes-core.min.js"],"icon_url":"","type":"theme","id":"theme:3d72b779d9c4ba6b51cc5b245b141433","is_default":0,"created_at":1691695809},"cd44aa56-088a-40dd-bf1e-f835efa68626":{"title":"Shoptimizer","condition":"shoptimizer","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/shoptimizer\/assets\/js\/lazyload-bg.js","\/shoptimizer\/assets\/js\/main.min.js"],"icon_url":"","type":"theme","id":"theme:6c32b43f4da639e5901574fac6b7d387","is_default":0,"created_at":1679737143},"d2c48a48-430a-4eea-bc05-99b66f1f6a7b":{"title":"SmartMag","condition":"smart-mag","exclusions":["\/smart-mag\/js\/lazyload.js"],"icon_url":"","type":"theme","id":"theme:23d6b7878bd0087addb067db3fa39864","is_default":0,"created_at":1679738490},"dd0d9133-ef17-4dac-b174-9f25d535838f":{"title":"Soledad","condition":"soledad","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/soledad\/js\/main.js","\/soledad\/js\/more-post.js","\/soledad\/js\/libs-script.min.js"],"icon_url":"","type":"theme","id":"theme:d3f78b26c2d11c99230171cc6378d06e","is_default":0,"created_at":1679737664},"3b85dd6e-9534-477e-9b15-940d0e155c8d":{"title":"Spacious - Mobile Menu","condition":"spacious","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/spacious\/js\/navigation.js"],"icon_url":"","type":"theme","id":"theme:d423c1f002b10b8682ee24d616b19c9c","is_default":0,"created_at":1703192854},"d657dc56-5c04-439a-8987-401f89a65bf9":{"title":"Stockholm","condition":"stockholm","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/stockholm\/js\/"],"icon_url":"","type":"theme","id":"theme:fcfff492e00727b63cf5dff9f59bc2a4","is_default":0,"created_at":1679738378},"121f9b1b-d3cd-4dde-915e-0b348abf6687":{"title":"Storefront","condition":"storefront","exclusions":["\/storefront\/assets\/js\/navigation.min.js"],"icon_url":"","type":"theme","id":"theme:f0dca7e4eaedf573d4664be249845942","is_default":0,"created_at":1679738793},"41cfc83f-ff02-4a35-a3b7-e92db213b224":{"title":"StreamTube","condition":"streamtube","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/streamtube\/","\/streamtube-core\/"],"icon_url":"","type":"theme","id":"theme:9772ccddd470688f6bc6aee86e34d29b","is_default":0,"created_at":1679331431},"c31366fe-9045-4767-a405-52a11e08b82e":{"title":"Sydney - Load elements on page load","condition":"sydney-pro-ii","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/wp-content\/themes\/sydney-pro-ii\/js\/scripts.js","\/wp-content\/themes\/sydney-pro-ii\/js\/functions.min.js","\/wp-content\/themes\/sydney-pro-ii\/js\/elementor.js","\/wp-content\/themes\/sydney-pro-ii\/js\/hero-slider.js","\/wp-content\/plugins\/sydney-toolbox\/js\/main.js"],"icon_url":"","type":"theme","id":"theme:1fb15693856451537e331adeaf2c7d6f","is_default":0,"created_at":1711977131},"aec0a548-4c6b-400a-80ed-19a49e0faef0":{"title":"The7","condition":"dt-the7","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/wp-includes\/js\/jquery\/jquery-migrate.min.js","loader-removed","\/Ultimate_VC_Addons\/assets\/min-js\/","\/dt-the7\/","\/js_composer\/"],"icon_url":"","type":"theme","id":"theme:7934c689fd20e30b6bfc69bb9d46cb63","is_default":0,"created_at":1679737892},"538354ff-d69f-40be-b0cc-df3790599dd2":{"title":"TheGem","condition":"thegem","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/thegem\/js\/","gemSettings","thegemSlideshow","tgpLazyItemsOptions"],"icon_url":"","type":"theme","id":"theme:153c54fe73897da838ce39152b1db5a8","is_default":0,"created_at":1679738477},"84d95a79-270c-4223-b459-bb49c6acfaf1":{"title":"Theme Electiman - Mobile Menu","condition":"electiman","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/themes\/electiman\/assets\/js\/navigation.js","\/themes\/electiman\/assets\/js\/theme-pluginjs.js","\/themes\/electiman\/assets\/js\/theme.js","\/themes\/electiman\/assets\/js\/slick.min.js","\/themes\/electiman\/venobox\/venobox.min.js","\/themes\/electiman\/assets\/js\/owl.carousel.min.js","\/wp-includes\/js\/imagesloaded.min.js"],"icon_url":"","type":"theme","id":"theme:a59c888391c869ed4f3417c02d71fe15","is_default":0,"created_at":1702923332},"3a59bf59-4fe5-4690-8ab7-33e6a976e2e3":{"title":"Thrive Theme Builder","condition":"thrive-theme","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/thrive-visual-editor\/editor\/js\/dist\/modules\/(.*).js","TVE_Event_Manager_Registered_Callbacks","ThriveGlobal","TCB_Front","TL_Front","TVE_Ult","thrive-","thrive_","tve_","tve-"],"icon_url":"","type":"theme","id":"theme:7492fc8f8a90ad7ef680d9c560da2b0f","is_default":0,"created_at":1710767440},"68f2de3b-e2b8-4edf-b82f-93fd7834c65f":{"title":"Total","condition":"Total","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/Total\/assets\/js\/total.min.js"],"icon_url":"","type":"theme","id":"theme:96b0141273eabab320119c467cdcaf17","is_default":0,"created_at":1679737571},"6dc1cb35-6b50-4da0-9834-dddf169edaa6":{"id":"theme:7c37c885d7fecf788f635734f99e8610","title":"Townhub","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/townhub-add-ons\/assets\/js\/(.*)","\/wp-includes\/js\/dist\/vendor\/react.js","\/wp-includes\/js\/dist\/vendor\/react-dom.js"],"is_default":0,"condition":"townhub","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"f484f86b-e316-4871-9322-dee3925349fe":{"title":"Travel Monster - Owl Carousel","condition":"travel-monster","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/wp-content\/plugins\/wp-travel-engine\/assets\/lib\/owl-carousel(.*)\/owl.carousel(|.min).js","var isRtl"],"icon_url":"","type":"theme","id":"theme:d3e8da87b3affd399205438fbc8a4f05","is_default":0,"created_at":1690822771},"3ec96c3f-a6bf-4748-9b7e-78864bd24add":{"title":"uDesign - Mobile Menu","condition":"u-design","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/wp-content\/themes\/u-design\/assets\/js\/theme.min.js","\/wp-content\/themes\/u-design\/framework\/assets\/js\/framework.min.js","\/wp-content\/themes\/u-design\/framework\/assets\/js\/framework-async.min.js"],"icon_url":"","type":"theme","id":"theme:31ce70b0a02f8720a86d993816676943","is_default":0,"created_at":1699292981},"cb523239-27cc-461e-973d-c984a83223ac":{"title":"uDesign - Show Page Content on Load","condition":"u-design","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/wp-content\/themes\/u-design\/assets\/js\/theme.min.js","\/wp-content\/themes\/u-design\/framework\/assets\/js\/framework.min.js"],"icon_url":"","type":"theme","id":"theme:c55edd40ad3f9321da577dad70bb130c","is_default":0,"created_at":1698778683},"14cb0a85-8bee-491e-99d7-5f20a07f4bdd":{"title":"Uncode","condition":"uncode","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/uncode\/library\/js\/init(.min)?.js","\/uncode\/library\/js\/plugins(.min)?.js","\/uncode\/library\/js\/app(.min)?.js","\/uncode\/library\/js\/woocommerce-uncode(.min)?.js","\/wp-includes\/js\/mediaelement\/mediaelement-and-player.min.js","initHeader","initBox","fixMenuHeight","initRow"],"icon_url":"","type":"theme","id":"theme:18ba19b98aefbb6c0fde6c6bf92e9cfc","is_default":0,"created_at":1679738154},"96aa49eb-6372-4b4c-b70d-f29dede8a8f2":{"title":"Utouch - Load menu on page load","condition":"utouch","exclusions":["\/wp-includes\/js\/jquery\/jquery-migrate.min.js","\/wp-includes\/js\/jquery\/jquery.min.js","\/utouch\/js\/main.js","\/utouch\/js\/swiper.jquery.min.js","\/utouch\/js\/fitvids.js","\/utouch\/js\/theme-plugins.js","\/utouch\/js\/crum-mega-menu.js"],"icon_url":"","type":"theme","id":"theme:18284bf26abf49a1d5d60b3fb34e4c2d","is_default":0,"created_at":1714156159},"a1fbf155-720a-4704-9794-d6749ad6df59":{"title":"Vivo theme - Fix blank page","condition":"vivo","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/vivo\/framework\/assets\/js\/bt_framework_misc.js"],"icon_url":"","type":"theme","id":"theme:a140e640fed504586e24e7c0df30376b","is_default":0,"created_at":1704308662},"88e96479-1aa2-4adc-8f07-20bc0368a63f":{"title":"Werkstatt","condition":"werkstatt","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/js\/underscore.min.js","\/werkstatt\/assets\/js\/vendor.min.js","\/werkstatt\/assets\/js\/fullscreen.min.js","\/werkstatt\/assets\/js\/app.min.js"],"icon_url":"","type":"theme","id":"theme:38faa29db5a07b8fef6aee9cc11cafec","is_default":0,"created_at":1679737639},"60c4110b-a960-4d44-b619-6d79514dbf75":{"title":"Woodmart","condition":"woodmart","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/wp-includes\/js\/imagesloaded.min.js","\/woodmart\/js\/scripts\/wc\/","\/woodmart\/js\/scripts\/global\/","\/woodmart\/js\/libs\/owl.carousel.min.js","\/woodmart\/js\/libs\/owl.carousel.js","\/woodmart\/js\/libs\/slick.js","\/woodmart\/js\/libs\/autocomplete.min.js"],"icon_url":"","type":"theme","id":"theme:06338f13cb89e5309ad2eb7e4d457be4","is_default":0,"created_at":1695633901},"a4547b5b-10ab-407c-969c-269fddec07b8":{"title":"Woodmart - Cart Fragments","condition":"woodmart","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>)","\/woocommerce\/assets\/js\/frontend\/cart-fragments.min.js","\/woocommerce\/assets\/js\/js-cookie\/js.cookie.min.js","\/woodmart\/js\/scripts\/wc\/updateCartFragmentsFix.js"],"icon_url":"","type":"theme","id":"theme:591f4f1b2e86b1e987cd8789df3ffce3","is_default":0,"created_at":1700584689},"97066e39-027a-4cd6-9152-7b6b53f365f5":{"title":"Woodmart - Mobile Menu","condition":"woodmart","exclusions":["\\\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\\?(.*))?( |'|\"|>|$)","\/themes\/woodmart\/js\/scripts\/menu\/mobileNavigation.min.js","\/themes\/woodmart\/js\/scripts\/global\/helpers.min.js"],"icon_url":"","type":"theme","id":"theme:d79a3941e2f12fb93ffc980ebeb1d7f4","is_default":0,"created_at":1711745013},"119ebd1c-6b46-4f07-8d6a-3498d9c8814f":{"title":"XStore","condition":"xstore","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/xstore\/js\/","\/et-core-plugin\/packages\/st-woo-swatches\/public\/js\/frontend.min.js"],"icon_url":"","type":"theme","id":"theme:3de9d9ba385200548f177d9c704ae92a","is_default":0,"created_at":1679738190},"9a7a548c-07a1-4dff-93fc-6e8230b67853":{"id":"theme:119d329456073aa10969d7cbd9760f28","title":"YOOtheme Pro","type":"theme","icon":"","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","uikit.min.js"],"is_default":0,"condition":"yootheme","created_at":1676435704,"updated_at":"2023-02-15T04:32:17.000000Z","icon_url":""},"f74c499e-b7d9-4590-8671-379f51f468c8":{"title":"Zeen","condition":"zeen","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","\/zeen\/assets\/js\/","\/js.cookie.min.js"],"icon_url":"","type":"theme","id":"theme:acb52844f996627788836366404a3245","is_default":0,"created_at":1679737859}},"scripts":{"dd0c5a5b-ec56-49f9-9aa4-89e1e3a6a28a":{"title":"Amazon Ads","exclusions":["amazon-adsystem.com"],"icon_url":"","type":"script","id":"script:b82a5936d8ea0745016caeb71629ae5d","is_default":0,"created_at":1681390276},"980edf32-c64b-4370-bf23-c62b079e71c3":{"title":"Google AdSense","exclusions":["adsbygoogle"],"icon_url":"","type":"script","id":"script:0206e6040c8ff64b8d6ee5fef2ce1c90","is_default":0,"created_at":1681377840},"2499bb90-0753-4b2b-9bd4-1525f94c7437":{"title":"Google Analytics","exclusions":["google-analytics.com\/analytics.js","ga\\( '","ga\\('"],"icon_url":"","type":"script","id":"script:d86cf69a8b82547a94ca3f6a307cf9a6","is_default":0,"created_at":1681388311},"6f460036-3106-4b8c-9951-d32de9b1258f":{"title":"Google Maps","exclusions":["maps.googleapis.com","maps.google.com"],"icon_url":"","type":"script","id":"script:4d60ab2c6d11d753267484006c23e54c","is_default":0,"created_at":1681390259},"ac2d5720-9418-468c-80a0-3874ee743c0f":{"title":"Google Optimize","exclusions":["a,s,y,n,c,h,i,d,e","googleoptimize.com\/optimize.js","async-hide"],"icon_url":"","type":"script","id":"script:031a0cece38c4739df67f910dcabf1bd","is_default":0,"created_at":1681390261},"122e6ebb-51fd-477f-97fb-559593f1a48b":{"title":"Google Recaptcha","exclusions":["recaptcha"],"icon_url":"","type":"script","id":"script:032cb16577cbf07bc7c02bac83bd936d","is_default":0,"created_at":1681390264},"219277ae-b2ac-4d42-913d-eaea40985295":{"title":"Google Tag Manager","exclusions":["\/gtag\/js","gtag\\(","\/gtm.js","async-hide"],"icon_url":"","type":"script","id":"script:1d3c65b2b03ef35e14df6b163ea3a1f6","is_default":0,"created_at":1681390266},"f632e3f4-20e6-471e-a78d-86afbea63586":{"title":"HubSpot","exclusions":["\/jquery-?[0-9.](.*)(.min|.slim|.slim.min)?.js","\/jquery-migrate(.min)?.js","js(.*).hsforms.net","hbspt.forms.create"],"icon_url":"","type":"script","id":"script:de4bd8ef4675ebb85a055955de76d0ee","is_default":0,"created_at":1713282413},"5d606add-ffb8-4a06-b295-5f722710fbfd":{"title":"Refari","exclusions":["widget.refari.co","refari"],"icon_url":"","type":"script","id":"script:a705e197b13b47e72a105c923e044358","is_default":0,"created_at":1683797056},"742ec14a-27a1-4789-b9c8-a9c3a3cf7042":{"title":"Reviews.io","exclusions":["\/carousel-inline-iframeless\/dist.js","carouselInlineWidget"],"icon_url":"","type":"script","id":"script:4df445c576f45889506ba175a4c39fdc","is_default":0,"created_at":1684389426},"05d3eb78-f574-49be-95e1-3f11714005d1":{"id":"script:ce7566d1d08cc094b74cf283cf9c56a5","title":"Stripe","type":"script","icon":"","exclusions":["js.stripe.com"],"is_default":0,"condition":"","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""},"0a37e528-8718-49f7-a26d-059aa29f867d":{"title":"Trustindex","exclusions":["cdn.trustindex.io\/loader.js","cdn.trustindex.io\/loader-cert.js"],"icon_url":"","type":"script","id":"script:1d38d6195597e8bb81966870f0a4f939","is_default":0,"created_at":1713359486},"ce9a3865-9efa-4e98-ae10-4f842a4ecc22":{"title":"Typeform","exclusions":["\/next\/embed.js"],"icon_url":"","type":"script","id":"script:cd3889ae3b96f891186ae270dbbcc9bb","is_default":0,"created_at":1709838856},"b56bf06c-2f8c-4757-b536-a689fb0e75f9":{"title":"Typekit","exclusions":["typekit"],"icon_url":"","type":"script","id":"script:7815e38b93e3b500a632681bd594bd61","is_default":0,"created_at":1681390268},"49c38c0a-43b9-4237-88cb-57ddd519f0ad":{"title":"Venatus Media","exclusions":["\/ad-manager.min.js","__vm_add"],"icon_url":"","type":"script","id":"script:abe11528732aed9a19a97e73b242faa5","is_default":0,"created_at":1681390272},"2c1d0998-8ab5-478c-8eb9-9e375b46363e":{"title":"Wistia","exclusions":["fast.wistia.com","\/assets\/external\/E-v1.js"],"icon_url":"","type":"script","id":"script:9a0111f8c3186c1cb3113587c660c041","is_default":0,"created_at":1711395219},"0627fe24-7e9d-400f-b064-d98bec2ba85e":{"id":"script:dbd1875130c71eb4b2ef768ad18d820c","title":"Yandex Ads","type":"script","icon":"","exclusions":["yandex.ru","window.yaContextCb"],"is_default":0,"condition":"","created_at":1676435704,"updated_at":"2023-02-15T04:32:16.000000Z","icon_url":""}}} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/dynamic-lists-incompatible-plugins.json b/wp-content/plugins/wp-rocket/dynamic-lists-incompatible-plugins.json new file mode 100644 index 000000000..8a8b1a42e --- /dev/null +++ b/wp-content/plugins/wp-rocket/dynamic-lists-incompatible-plugins.json @@ -0,0 +1 @@ +{"":[{"slug":"wp-super-cache","file":"wp-super-cache\/wp-cache.php"},{"slug":"enable-gzip-compression","file":"enable-gzip-compression\/enable-gzip-compression.php"},{"slug":"quick-cache","file":"quick-cache\/quick-cache.php"},{"slug":"leverage-browser-caching-ninjas","file":"leverage-browser-caching-ninjas\/leverage-browser-caching-ninja.php"},{"slug":"wp-performance-score-booster","file":"wp-performance-score-booster\/wp-performance-score-booster.php"},{"slug":"litespeed-cache","file":"litespeed-cache\/litespeed-cache.php"},{"slug":"remove-query-strings-from-static-resources","file":"remove-query-strings-from-static-resources\/remove-query-strings.php"},{"slug":"wp-http-compression","file":"wp-http-compression\/wp-http-compression.php"},{"slug":"query-strings-remover","file":"query-strings-remover\/query-strings-remover.php"},{"slug":"page-optimize","file":"page-optimize\/page-optimize.php"},{"slug":"speed-booster-pack","file":"speed-booster-pack\/speed-booster-pack.php"},{"slug":"swift-performance","file":"swift-performance\/performance.php"},{"slug":"gzip-ninja-speed-compression","file":"gzip-ninja-speed-compression\/gzip-ninja-speed.php"},{"slug":"super-static-cache","file":"super-static-cache\/super-static-cache.php"},{"slug":"lite-cache","file":"lite-cache\/plugin.php"},{"slug":"hyper-cache","file":"hyper-cache\/plugin.php"},{"slug":"wp-ffpc","file":"wp-ffpc\/wp-ffpc.php"},{"slug":"wp-fast-cache","file":"wp-fast-cache\/wp-fast-cache.php"},{"slug":"psn-pagespeed-ninja","file":"psn-pagespeed-ninja\/pagespeedninja.php"},{"slug":"swift-performance-lite","file":"swift-performance-lite\/performance.php"},{"slug":"force-gzip","file":"force-gzip\/force-gzip.php"},{"slug":"add-expires-headers","file":"add-expires-headers\/add-expires-headers.php"},{"slug":"hyper-cache-extended","file":"hyper-cache-extended\/plugin.php"},{"slug":"gator-cache","file":"gator-cache\/gator-cache.php"},{"slug":"flexicache","file":"flexicache\/wp-plugin.php"},{"slug":"wp-fastest-cache","file":"wp-fastest-cache\/wpFastestCache.php"},{"slug":"wordpress-gzip-compression","file":"wordpress-gzip-compression\/ezgz.php"},{"slug":"wp-optimize","file":"wp-optimize\/wp-optimize.php"},{"slug":"check-and-enable-gzip-compression","file":"check-and-enable-gzip-compression\/richards-toolbox.php"},{"slug":"far-future-expiry-header","file":"far-future-expiry-header\/far-future-expiration.php"},{"slug":"leverage-browser-caching","file":"leverage-browser-caching\/leverage-browser-caching.php"},{"slug":"wpcompressor","file":"wpcompressor\/wpcompressor.php"},{"slug":"combine-css","file":"combine-css\/combine-css.php"},{"slug":"w3-total-cache","file":"w3-total-cache\/w3-total-cache.php"},{"slug":"cache-enabler","file":"cache-enabler\/cache-enabler.php"}],"minify_css||minify_js":[{"slug":"merge-minify-refresh","file":"merge-minify-refresh\/merge-minify-refresh.php"},{"slug":"async-js-and-css","file":"async-js-and-css\/asyncJSandCSS.php"},{"slug":"wp-super-minify","file":"wp-super-minify\/wp-super-minify.php"},{"slug":"fast-velocity-minify","file":"fast-velocity-minify\/fvm.php"},{"slug":"dependency-minification","file":"dependency-minification\/dependency-minification.php"},{"slug":"bwp-minify","file":"bwp-minify\/bwp-minify.php"},{"slug":"minqueue","file":"minqueue\/plugin.php"},{"slug":"scripts-gzip","file":"scripts-gzip\/scripts_gzip.php"},{"slug":"wp-minify","file":"wp-minify\/wp-minify.php"}],"lazyload":[{"slug":"lazy-load","file":"lazy-load\/lazy-load.php"},{"slug":"bj-lazy-load","file":"bj-lazy-load\/bj-lazy-load.php"},{"slug":"jquery-image-lazy-loading","file":"jquery-image-lazy-loading\/jq_img_lazy_load.php"},{"slug":"crazy-lazy","file":"crazy-lazy\/crazy-lazy.php"},{"slug":"specify-image-dimensions","file":"specify-image-dimensions\/specify-image-dimensions.php"},{"slug":"advanced-lazy-load","file":"advanced-lazy-load\/advanced_lazyload.php"}],"minify_js":[{"slug":"wp-js","file":"wp-js\/wp-js.php"},{"slug":"scripts-to-footerphp","file":"scripts-to-footerphp\/scripts-to-footer.php"},{"slug":"combine-js","file":"combine-js\/combine-js.php"},{"slug":"footer-javascript","file":"footer-javascript\/footer-javascript.php"}],"control_heartbeat":[{"slug":"heartbeat-control","file":"heartbeat-control\/heartbeat-control.php"}],"lazyload_iframes":[{"slug":"lazy-load-for-videos","file":"lazy-load-for-videos\/codeispoetry.php"}]} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/dynamic-lists.json b/wp-content/plugins/wp-rocket/dynamic-lists.json new file mode 100644 index 000000000..915b50e54 --- /dev/null +++ b/wp-content/plugins/wp-rocket/dynamic-lists.json @@ -0,0 +1 @@ +{"rucss_inline_atts_exclusions":["rocket-lazyload-inline-css","divi-style-parent-inline-inline-css","gsf-custom-css","extra-style-inline-inline-css","woodmart-inline-css-inline-css","woodmart_shortcodes-custom-css","rs-plugin-settings-inline-css","divi-style-inline-inline-css","tcb-post-list-dynamic-style","n2-ss-","wpcf7-","siteorigin-panels-layouts-footer","xstore-inline-css-inline-css","assets.reviews.io","ezoicCSS","stk-"],"rucss_inline_content_exclusions":[".wp-container-",".wp-elements-","#wpv-expandable-",".custom-content-","#thb-",".et_pb_text_dap_","#gdlr-core-shape-divider","#ultib3-",".uvc-wrap-",".jet-listing-dynamic-post-",".vcex_",".wprm-advanced-list-",".adsslot_",".jnews_",".cp-info-bar.content-","#stockie-custom-","#ohio-custom-",".uid-","#wpfMainWrapper","#penci_","#penci-",".wpbs_s","#apcore_","#apress_","#zolo_",".extended-products-grid#style-",".preloader#style-preloader-",".thegem-heading-",".thegem-button-",".thegem-custom-",".thegem-popup-","#pattern-","#thegem-video-frame-","#thegem-",".qwery_inline_",".dcgd_submit_button",".irs-bar",".gallery-grid-",".cmplz-hidden","#sqbquizouter","#start_sqbquizouter",".flo-header--",".trx_addons_inline_",".wpp-cardview-compact",".e-loop-item-",".tiered-pricing-plain-text"],"defer_js_inline_exclusions":["DOMContentLoaded","document.write","window.lazyLoadOptions","N.N2_","rev_slider_wrapper","FB3D_CLIENT_LOCALE","ewww_webp_supported","anr_captcha_field_div","renderInvisibleReCaptcha","bookingInProgress"],"defer_js_external_exclusions":["gist.github.com","content.jwplatform.com","js.hsforms.net","www.uplaunch.com","google.com\/recaptcha","widget.reviews.co.uk","verify.authorize.net\/anetseal","lib\/admin\/assets\/lib\/webfont\/webfont.min.js","app.mailerlite.com","widget.reviews.io","simplybook.(.*)\/v2\/widget\/widget.js","\/wp-includes\/js\/dist\/i18n.min.js","\/wp-content\/plugins\/wpfront-notification-bar\/js\/wpfront-notification-bar(.*).js","\/wp-content\/plugins\/oxygen\/component-framework\/vendor\/aos\/aos.js","\/wp-content\/plugins\/ewww-image-optimizer\/includes\/check-webp(.min)?.js","static.mailerlite.com\/data\/(.*).js","cdn.voxpow.com\/static\/libs\/v1\/(.*).js","cdn.voxpow.com\/media\/trackers\/js\/(.*).js","use.typekit.net","www.idxhome.com","\/wp-includes\/js\/dist\/vendor\/lodash(.min)?.js","\/wp-includes\/js\/dist\/api-fetch(.min)?.js","\/wp-includes\/js\/dist\/i18n(.min)?.js","\/wp-includes\/js\/dist\/vendor\/wp-polyfill(.min)?.js","\/wp-includes\/js\/dist\/url(.min)?.js","\/wp-includes\/js\/dist\/hooks(.min)?.js","www.paypal.com\/sdk\/js","js-eu1.hsforms.net","yanovis.Voucher.js","\/carousel-upsells-and-related-product-for-woocommerce\/assets\/js\/glide.min.js","use.typekit.com","\/artale\/modules\/kirki\/assets\/webfont.js","\/api\/scripts\/lb_cs.js","js.hscta.net\/cta\/current.js","widget.refari.co","player.vdocipher.com","\/wp-content\/plugins\/wp-rocket\/assets\/js\/lcp-beacon(.min)?.js"],"delay_js_exclusions":["nowprocket","\/wp-includes\/js\/wp-embed.min.js","lazyLoadOptions","lazyLoadThumb","wp-rocket\/assets\/js\/lazyload\/(.*)","et_core_page_resource_fallback","window.\\$us === undefined","js-extra","fusionNavIsCollapsed","\/assets\/js\/smush-lazy-load","eio_lazy_vars","\\\/lazysizes(\\.min|-pre|-post)?\\.js","document\\.body\\.classList\\.remove\\(\"no-js\"\\)","document\\.documentElement\\.className\\.replace\\( 'no-js', 'js' \\)","et_animation_data","wpforms_settings","var nfForms","\/\/stats.wp.com","_stq.push","fluent_form_ff_form_instance_","cpLoadCSS","ninja_column_","var rbs_gallery_","var lepopup_","var billing_additional_field","var gtm4wp","var dataLayer_content","\/ewww-image-optimizer\/includes\/load[_-]webp(\\.min)?.js","\/ewww-image-optimizer\/includes\/check-webp(\\.min)?.js","ewww_webp_supported","\/dist\/js\/browser-redirect\/app.js","\/perfmatters\/js\/lazyload.min.js","lazyLoadInstance","scripts.mediavine.com\/tags\/","initCubePortfolio","simpli.fi","gforms_recaptcha_","\/jetpack-boost\/vendor\/automattic\/jetpack-lazy-images\/(.*)","jetpack-lazy-images-js-enabled","jetpack-boost-critical-css","wpformsRecaptchaCallback","booking-suedtirol-js","wpcp_css_disable_selection","\/gravityforms\/js\/conditional_logic.min.js","statcounter.com\/counter\/counter.js","var sc_project","\/jetpack\/jetpack_vendor\/automattic\/jetpack-lazy-images\/(.*)","\/themify-builder\/themify\/js\/modules\/fallback(\\.min)?.js","handlePixMessage","var corner_video","cdn.pixfuture.com\/hb_v2.js","cdn.pixfuture.com\/pbix.js","served-by.pixfuture.com\/www\/delivery\/ads.js","served-by.pixfuture.com\/www\/delivery\/headerbid_sticky_refresh.js","serv-vdo.pixfuture.com\/vpaid\/ads.js","wprRemoveCPCSS","window.jdgmSettings","\/photonic\/include\/js\/front-end\/nomodule\/photonic-baguettebox.min.js","\/photonic\/include\/ext\/baguettebox\/baguettebox.min.js","window.wsf_form_json_config","et_link_options_data","FuseboxPlayerAPIKey","js.hscta.net\/cta\/current.js","hbspt.cta.load","consent.cookiebot.com\/uc.js","\/woofilter-pro\/woofilterpro\/js\/ion.rangeSlider.min.js","barra.r7.com\/barra.js","rocket_css_lazyload_launch","#wpr-lazyload-bg","\/wp-content\/plugins\/wp-rocket\/assets\/js\/lcp-beacon(.min)?.js","rocket_lcp_data"],"js_minify_external":["html5.js","show_ads.js","histats.com\/js","ws.amazon.com\/widgets","\/ads\/","intensedebate.com","scripts.chitika.net\/","jotform.com\/","gist.github.com","forms.aweber.com","video.unrulymedia.com","stats.wp.com","stats.wordpress.com","widget.rafflecopter.com","widget-prime.rafflecopter.com","releases.flowplayer.org","c.ad6media.fr","cdn.stickyadstv.com","www.smava.de","contextual.media.net","app.getresponse.com","adserver.reklamstore.com","s0.wp.com","wprp.zemanta.com","files.bannersnack.com","smarticon.geotrust.com","js.gleam.io","ir-na.amazon-adsystem.com","web.ventunotech.com","verify.authorize.net","ads.themoneytizer.com","embed.finanzcheck.de","imagesrv.adition.com","js.juicyads.com","form.jotformeu.com","speakerdeck.com","content.jwplatform.com","ads.investingchannel.com","app.ecwid.com","www.industriejobs.de","s.gravatar.com","googlesyndication.com","a.optmstr.com","a.optmnstr.com","a.opmnstr.com","adthrive.com","mediavine.com","js.hsforms.net","googleadservices.com","f.convertkit.com","recaptcha\/api.js","mailmunch.co","apps.shareaholic.com","dsms0mj1bbhn4.cloudfront.net","nutrifox.com","code.tidio.co","www.uplaunch.com","widget.reviewability.com","embed-cdn.gettyimages.com\/widgets.js","app.mailerlite.com","ck.page","cdn.jsdelivr.net\/gh\/AmauriC\/","static.klaviyo.com\/onsite\/js\/klaviyo.js","a.omappapi.com\/app\/js\/api.min.js","static.zdassets.com","feedbackcompany.com\/widgets\/feedback-company-widget.min.js","widget.gleamjs.io","phonewagon.com","simplybook.asia\/v2\/widget\/widget.js","simplybook.it\/v2\/widget\/widget.js","simplybook.me\/v2\/widget\/widget.js","static.botsrv.com\/website\/js\/widget2.36cf1446.js","static.mailerlite.com\/data\/","cdn.voxpow.com","loader.knack.com","embed.lpcontent.net\/leadboxes\/current\/embed.js","cc.cdn.civiccomputing.com\/9\/cookieControl-9.x.min.js","cse.google.com\/cse.js","kit.fontawesome.com","cdn.jsdelivr.net\/npm\/mathjax@3\/es5\/tex-mml-chtml.js","static.leadpages.net\/leadbars\/current\/embed.js","booqable.com\/v2\/booqable.js","googleoptimize.com","cdna.hubpeople.com\/js\/widget_standalone_two_modes.js","s3.tradingview.com","www.vbt.io\/ext\/vbtforms.js","cdn.callrail.com","documentcloud.adobe.com\/view-sdk\/main.js","static.cleverpush.com","js.afterpay.com","cdn.enable.co.il\/licenses\/enable-","hcaptcha.com\/1\/api.js","voucher.getavo.it\/public\/js\/yanovis.Voucher.js","js-eu1.hsforms.net","statcounter.com\/counter\/counter.js","snapppt.com","use.typekit.com","secure.gravatar.com\/js\/gprofiles.js","cdn.jsdelivr.net\/npm\/hockeystack","widget.prod.faslet.net","ga.getresponse.com\/script\/ga.js","cognitoforms.com","usercentrics.eu","cdn.amcharts.com","umami","cdn.popt.in\/pixel.js","m2d.m2.ai","pubguru.net","trustindex.io","cdnjs.cloudflare.com\/ajax\/libs\/prism\/","podigee-podcast-player.js","tarteaucitron.io\/load.js","osm.klarnaservices.com\/lib.js","mein.clickskeks.at\/app.js","barra.r7.com\/barra.js","widget.refari.co","widget.reviews.co.uk","player.vdocipher.com","www.instagram.com\/embed.js","smartframe.io","challenges.cloudflare.com\/turnstile\/","script.roboassist.ai","cdn.hu-manity.co","daumcdn.net\/mapjsapi\/bundle\/postcode\/prod\/postcode.v2.js","consent.cookiebot.com\/uc.js"],"js_move_after_combine":["map_fusion_map_","ec:addProduct","ec:addImpression","clear_better_facebook_comments","vc-row-destroy-equal-heights-","dfd-icon-list-","SFM_template","WLTChangeState","wlt_star_","wlt_pop_distance_","smart_list_tip","gd-wgt-pagi-","data-rf-id=","tvc_po=","scrapeazon","startclock","it_logo_field_owl-box_","td_live_css_uid","wpvl_paramReplace","tdAjaxCount","mec_skin_","_wca","_taboola","fbq('trackCustom'","fbq('track'","data.token","sharrre","dfads_ajax_load_ads","tie_postviews","wmp_update","h5ab-print-article","gform_ajax_frame_","gform_post_render","mts_view_count","act_css_tooltip","window.SLB","wpt_view_count","var dateNow","gallery_product_",".flo-block-slideshow-","data='api-key=ct-","ip_common_function()","(\"style#gsf-custom-css\").append","a3revWCDynamicGallery_","#owl-carousel-instagram-","window.FlowFlowOpts","jQuery('.td_uid_","jQuery(\".slider-","#dfd-vcard-widget-","#sf-instagram-widget-",".woocommerce-tabs-","penci_megamenu__","vc_prepareHoverBox","wp-temp-form-div","_wswebinarsystem_already_","#views-extra-css\").text","fusetag.setTargeting","hit.uptrendsdata.com","callback:window.renderBadge","test_run_nf_conditional_logic","cb_nombre","$('.fl-node-","function($){google_maps_","$(\"#myCarousel","et_animation_data=","current_url=\"","CustomEvent.prototype=window.Event.prototype","electro-wc-product-gallery","woof_is_mobile","jQuery('.videonextup","wpp_params","us.templateDirectoryUri=",".fat-gallery-item",".ratingbox","user_rating.prototype.eraseCookie","test_run_nf_conditional","dpsp-networks-btns-wrapper","pa_woo_product_info","sharing_enabled_on_post_via_metabox","#product-search-field-","GOTMLS_login_offset","berocket_aapf_time_to_fix_products_style","window.vc_googleMapsPointer","sinceID_","#ut-background-video-ut-section","+window.comment_tab_width+","dfd-button-hover-in","wpseo-address-wrapper","platform.stumbleupon.com","#woo_pp_ec_button_mini_cart","#supercarousel","blockClass","tdbMenuItem","tdbSearchItem","best_seller_badge","jQuery('#product-top-bar","fb_desc-","FC_regenerate_captcha","wp_post_blocks_vars.listed_posts=[","captcha-hash","mapdata={",".ywpc-char-",").countdowntimer(","jQuery(\"#td_uid_","find('#td_uid_","variation_estimate_msg"],"js_excluded_inline":["document.write","google_ad","edToolbar","gtag","_gaq.push","_gaLt","GoogleAnalyticsObject","syntaxhighlighter","adsbygoogle","ci_cap_","_stq","nonce","post_id","LogHuman","idcomments_acct","ch_client","sc_online_t","_stq","bannersnack_embed","vtn_player_type","ven_video_key","ANS_customer_id","tdBlock","tdLocalCache","wpRestNonce","\"url\":","lazyLoadOptions","adthrive","loadCSS","google_tag_params","clicky_custom","clicky_site_ids","NSLPopupCenter","_paq","gtm","dataLayer","RecaptchaLoad","WPCOM_sharing_counts","jetpack_remote_comment","subscribe-field","contextly","_mmunch","gt_request_uri","doGTranslate","docTitle","bs_ajax_paginate_","bs_deferred_loading_","theChampRedirectionUrl","theChampFBCommentUrl","theChampTwitterRedirect","theChampRegRedirectionUrl","ESSB_CACHE_URL","oneall_social_login_providers_","betterads_screen_width","woocommerce_wishlist_add_to_wishlist_url","arf_conditional_logic","heateorSsHorSharingShortUrl","TL_Const","bimber_front_microshare","setAttribute(\"id\"","setAttribute( \"id\"","TribeEventsPro","peepsotimedata","wphc_data","hc_rand_id","RBL_ADD","AfsAnalyticsObject","_thriveCurrentPost","esc_login_url","fwduvpMainPlaylist","Bibblio.initRelatedContent","showUFC()","#iphorm-","#fancy-","ult-carousel-","theChampLJAuthUrl","f._fbq","Insticator","w2dc_js_objects","cherry_ajax","ad_block_","elementorFrontendConfig","zeen_","disqusIdentifier","currentAjaxUrl","geodir_event_call_calendar_","atatags-","hbspt.forms.create","function(c,h,i,m,p)","dataTable({","rankMath = {","_atrk_opts","quicklinkOptions","ct_checkjs_","WP_Statistics_http","penci_block_","omapi_localized","omapi_data","OptinMonsterApp","tminusnow","nfForms","galleries.gallery_","wcj_evt.prodID","advads_tracking_ads","advadsGATracking.postContext","woopack_config","ulp_content_id","wp-cumulus\/tagcloud.swf?r=","ctSetCookie('ct_checkjs'","woof_really_curr_tax","uLogin.customInit","i18n_no_matching_variations_text","alsp_map_markers_attrs","var inc_opt =","iworks_upprev","yith_wcevti_tickets","window.metrilo.ensure_cbuid","metrilo.event","wordpress_page_root","wcct_info","Springbot.product_id","pysWooProductData","dfd-heading","owl=$(\"#","penci_megamenu","fts_security","algoliaAutocomplete","avia_framework_globals","tabs.easyResponsiveTabs","searchlocationHeader","yithautocomplete","data-parallax-speed","currency_data=","cedexisData","function reenableButton","#wpnbio-show","e.Newsletter2GoTrackingObject","var categories_","\"+nRemaining+\"","cartsguru_cart_token","after_share_easyoptin","location_data.push","thirstyFunctions.isThirstyLink","styles: ' #custom-menu-","function svc_center_","#svc_carousel2_container_","advads.move","elementid","advads_has_ads","wpseo_map_init","mdf_current_page_url","tptn_tracker","dpsp_pin_button_data","searchwp_live_search_params","wpp_params","top.location,thispage","selection+pagelink","ic_window_resolution","PHP.wp_p_id","ShopifyBuy.UI.onReady(client)","orig_request_uri","gie.widgets.load","Adman.Flash","PHP.wp_p_id","window.broadstreetKeywords","var productId =","var flatsomeVars","wc_product_block_data","static.mailerlite.com","amzn_assoc","_bs_getParameterByName","_stq.push","h._remove","var FlowFlowOpts","var WCPFData =","var _beeketing","var _statcounter","var actions =","var current_url","var object_name","var the_ajax_script","var wc_cart_fragments_params","var woocommerce_params","var wpml_cookies","wc_add_to_cart_params","window.broadstreetKeywords","window.wc_ga_pro.available_gateways","xa.prototype","HOUZEZ_ajaxcalls_vars","w2dc_maps_objects","w2dc_controller_args_array","w2dc_map_markers_attrs","YT.Player","WPFC.data","function current_video_","var videodiv","var slider_wppasrotate","wppas_ga","var blockClass","tarteaucitron","pw_brand_product_list","tminusCountDown","pysWooSelectContentData","wpvq_ans89733","_isp_version","price_range_data","window.FeedbackCompanyWidgets","woocs_current_currency","woo_variation_swatches_options","woocommerce_price_slider_params","scriptParams","form-adv-pagination","borlabsCookiePrioritize","urls_wpwidgetpolylang","quickViewNonce","frontendscripts_params","nj-facebook-messenger","var fb_mess_position","init_particles_row_background_script","setREVStartSize","fl-node","PPAccordion","soliloquy_","wprevpublicjs_script_vars","DTGS_NONCE_FRONTEND","et_animation_data","archives-dropdown","loftloaderCache","SmartSliderSimple","var nectarLove","var incOpt","RocketBrowserCompatibilityChecker","RocketPreloadLinksConfig","placementVersionId","var useEdit","var DTGS_NONCE_FRONTEND","n2jQuery","et_core_api_spam_recaptcha","cnArgs","__CF$cv$params","trustbox_settings","aepro","cdn.jst.ai","w2dc_fields_in_categories","jetMenuPublicSettings","JetTricksSettings","aepc_pixel","avadaWooCommerceVars","var isb","fcaPcPost","csrf_token","icwp_wpsf_vars_lpantibot","wpvViewHead","ed_school_plugin","aps_comp_","guaven_woos","__lm_redirect_to","__wpdm_view_count","bookacti.booking_system","nfFrontEnd","view_quote_cart_link","__eae_decode_emails","divioverlays_ajaxurl","var _EPYT_","#ins-heading-","#ins-button-","tve_frontend_options","lb24.src","amazon_Login_accessToken","porto_infinite_scroll",".adace-loader-","adace_load_","tagGroupsAccordiontaggroupscloudaccordion","tagGroupsTabstaggroupscloudtabs","jrRelatedWidgets","UNCODE.initRow","amp_mobile_redirect_disabled","wpgdprcData","wpml_browser_redirect_params","swPreRegister","kboard_settings","ct_ultimate_gdpr_cookie","wcpv_registration_local","www.idxhome.com","arf_footer_cl_logic_call","reload_attached_coupons","var ftpp","forminatorFront","_EPYT_","edd_free_downloads_vars","edd_stripe_vars","var ASP","ecwidOriginalTitle","defaultCategoryId","translation-revision-date","google_conversion_id","hbspt","var marker_locations_","var AdmMyAjax","ifso_page_url","referrer_for_pageload","WoocommerceWidget\/woocommerceWidget.js","var ht_ctc_chat_var","spuvar","var wpilFrontend","urls_polylangREPLACETOID","e.setAttribute('unselectable',on);","try{Typekit.load","iMapsData","var wpforms_user_journey","rocket_lazyload_css_data","wcStoreApiNonceTimestamp","createNonceMiddleware","pbidHash","wcBlocksMiddlewareConfig"],"cache_ignored_parameters":["utm_source","utm_medium","utm_campaign","utm_expid","utm_term","utm_content","utm_id","utm_source_platform","utm_creative_format","utm_marketing_tactic","mtm_source","mtm_medium","mtm_campaign","mtm_keyword","mtm_cid","mtm_content","pk_source","pk_medium","pk_campaign","pk_keyword","pk_cid","pk_content","fb_action_ids","fb_action_types","fb_source","fbclid","campaignid","adgroupid","adid","gclid","age-verified","ao_noptimize","usqp","cn-reloaded","_ga","sscid","gclsrc","_gl","mc_cid","mc_eid","_bta_tid","_bta_c","trk_contact","trk_msg","trk_module","trk_sid","gdfms","gdftrk","gdffi","_ke","_kx","redirect_log_mongo_id","redirect_mongo_id","sb_referer_host","mkwid","pcrid","ef_id","s_kwcid","msclkid","dm_i","epik","pp","gbraid","wbraid","ssp_iabi","ssp_iaba","gad","vgo_ee","gad_source"],"preload_exclusions":["void\\(.*;","(.*)__trashed(.*)","\/jet-menu\/(.*)","\/jet-popup\/(.*)"],"exclude_js_files":["\/wp-includes\/js\/dist\/i18n.min.js","\/interactive-3d-flipbook-powered-physics-engine\/assets\/js\/html2canvas.min.js","\/interactive-3d-flipbook-powered-physics-engine\/assets\/js\/pdf.min.js","\/interactive-3d-flipbook-powered-physics-engine\/assets\/js\/three.min.js","\/interactive-3d-flipbook-powered-physics-engine\/assets\/js\/3d-flip-book.min.js","\/google-site-kit\/dist\/assets\/js\/(.*).js","\/wp-live-chat-support\/public\/js\/callus(.*).js","\/borlabs-cookie\/assets\/javascript\/(.*).js","\/wp-content\/plugins\/wp-rocket\/assets\/js\/lcp-beacon(.min)?.js","\/woocommerce-bookings\/dist\/frontend.js"],"staging_domains":[".wpengine.com",".wpenginepowered.com",".pantheonsite.io",".flywheelsites.com",".flywheelstaging.com",".kinsta.com",".kinsta.cloud",".cloudwaysapps.com",".azurewebsites.net",".wpserveur.net","-liquidwebsites.com",".myftpupload.com",".dream.press",".sg-host.com",".platformsh.site",".wpstage.net",".bigscoots-staging.com",".wpsc.site",".runcloud.link",".onrocket.site",".singlestaging.com",".myraidbox.de",".instawp.xyz",".instawp.co",".instawp.link",".instawp.app",".hstgr.cloud",".myhostpoint.ch",".wpcomstaging.com"],"exclude_js_template":["type=\"module\""]} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/3rd-party.php b/wp-content/plugins/wp-rocket/inc/3rd-party/3rd-party.php index fd8b99c22..79c88ae71 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/3rd-party.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/3rd-party.php @@ -14,26 +14,15 @@ require WP_ROCKET_3RD_PARTY_PATH . 'hosting/siteground.php'; } -if ( class_exists( 'WPaaS\Plugin' ) ) { - require WP_ROCKET_3RD_PARTY_PATH . 'hosting/godaddy.php'; -} - -if ( isset( $_SERVER['KINSTA_CACHE_ZONE'] ) ) { - require WP_ROCKET_3RD_PARTY_PATH . 'hosting/kinsta.php'; -} - if ( defined( 'PL_INSTANCE_REF' ) && class_exists( '\Presslabs\Cache\CacheHandler' ) && file_exists( WP_CONTENT_DIR . '/advanced-cache.php' ) ) { require WP_ROCKET_3RD_PARTY_PATH . 'hosting/presslabs.php'; } require WP_ROCKET_3RD_PARTY_PATH . 'hosting/pagely.php'; require WP_ROCKET_3RD_PARTY_PATH . 'hosting/nginx.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'hosting/pressidium.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'plugins/geotargetingwp.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/slider/meta-slider.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/slider/soliloquy.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'plugins/i18n/wpml.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/i18n/polylang.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/aelia-currencyswitcher.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/aelia-prices-by-country.php'; @@ -46,7 +35,6 @@ require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/jigoshop.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/wpshop.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/ecommerce/give.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'plugins/age-verify.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/autoptimize.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/envira-gallery.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/cookies/cookie-notice.php'; @@ -61,11 +49,6 @@ require WP_ROCKET_3RD_PARTY_PATH . 'plugins/disqus.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/custom-login.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/mobile/wp-appkit.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/seopress.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/rank-math-seo.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/yoast-seo.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/the-seo-framework.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/all-in-one-seo-pack.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/seo/premium-seo-pack.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/wp-rest-api.php'; require WP_ROCKET_3RD_PARTY_PATH . 'plugins/page-builder/thrive-visual-editor.php'; @@ -84,4 +67,3 @@ require WP_ROCKET_3RD_PARTY_PATH . 'plugins/nginx-helper.php'; require WP_ROCKET_3RD_PARTY_PATH . 'themes/studiopress.php'; -require WP_ROCKET_3RD_PARTY_PATH . 'themes/uncode.php'; diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/flywheel.php b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/flywheel.php index a8b67e70c..a56ffe77f 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/flywheel.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/flywheel.php @@ -69,7 +69,7 @@ function rocket_flywheel_remove_partial_purge_hooks() { // Remove rocket_clean_post() from core action hooks. array_map( - function( $hook ) { + function ( $hook ) { remove_action( $hook, 'rocket_clean_post' ); }, $clean_post_hooks diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/kinsta.php b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/kinsta.php deleted file mode 100644 index a131745a2..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/kinsta.php +++ /dev/null @@ -1,166 +0,0 @@ -kinsta_cache_purge ) ) { - $kinsta_cache->kinsta_cache_purge->purge_complete_caches(); - } - } - add_action( 'after_rocket_clean_domain', 'rocket_clean_kinsta_cache' ); - - /** - * Partially clear Kinsta cache when partially clearing WP Rocket cache - * - * @since 3.0 - * @author Remy Perona - * - * @param object $post Post object. - * @return void - */ - function rocket_clean_kinsta_post_cache( $post ) { - global $kinsta_cache; - $kinsta_cache->kinsta_cache_purge->initiate_purge( $post->ID, 'post' ); - } - add_action( 'after_rocket_clean_post', 'rocket_clean_kinsta_post_cache' ); - - /** - * Clears Kinsta cache for the homepage URL when using "Purge this URL" from the admin bar on the front end - * - * @since 3.0.4 - * @author Remy Perona - * - * @param string $root WP Rocket root cache path. - * @param string $lang Current language. - * @return void - */ - function rocket_clean_kinsta_cache_home( $root = '', $lang = '' ) { - $url = get_rocket_i18n_home_url( $lang ); - $url = trailingslashit( $url ) . 'kinsta-clear-cache/'; - - wp_remote_get( - $url, - [ - 'blocking' => false, - 'timeout' => 0.01, - ] - ); - } - add_action( 'after_rocket_clean_home', 'rocket_clean_kinsta_cache_home', 10, 2 ); - - /** - * Clears Kinsta cache for a specific URL when using "Purge this URL" from the admin bar on the front end - * - * @since 3.0.4 - * @author Remy Perona - * - * @param string $url URL to purge. - * @return void - */ - function rocket_clean_kinsta_cache_url( $url ) { - $url = trailingslashit( $url ) . 'kinsta-clear-cache/'; - - wp_remote_get( - $url, - [ - 'blocking' => false, - 'timeout' => 0.01, - ] - ); - } - add_action( 'after_rocket_clean_file', 'rocket_clean_kinsta_cache_url' ); - - /** - * Remove WP Rocket functions on WP core action hooks to prevent triggering a double cache clear. - * - * @since 3.0 - * @author Remy Perona - * - * @return void - */ - function rocket_remove_partial_purge_hooks() { - // WP core action hooks rocket_clean_post() gets hooked into. - $clean_post_hooks = [ - // Disables the refreshing of partial cache when content is edited. - 'wp_trash_post', - 'delete_post', - 'clean_post_cache', - 'wp_update_comment_count', - ]; - - // Remove rocket_clean_post() from core action hooks. - array_map( - function( $hook ) { - remove_action( $hook, 'rocket_clean_post' ); - }, - $clean_post_hooks - ); - - remove_filter( 'rocket_clean_files', 'rocket_clean_files_users' ); - } - add_action( 'wp_rocket_loaded', 'rocket_remove_partial_purge_hooks' ); - - if ( \Kinsta\CDN_Enabler::cdn_is_enabled() ) { - /** - * Add Kinsta CDN to WP Rocket CDN hosts list if enabled - * - * @since 3.0 - * @author Remy Perona - * - * @param Array $hosts Array of CDN hosts. - * @return Array Updated array of CDN hosts - */ - function rocket_add_kinsta_cdn_cname( $hosts ) { - if ( ! isset( $_SERVER['KINSTA_CDN_DOMAIN'] ) ) { - return $hosts; - } - - $hosts[] = sanitize_text_field( wp_unslash( $_SERVER['KINSTA_CDN_DOMAIN'] ) ); - - return $hosts; - } - add_filter( 'rocket_cdn_cnames', 'rocket_add_kinsta_cdn_cname', 1 ); - } -} else { - add_action( - 'admin_notices', - function() { - if ( ! current_user_can( 'manage_options' ) ) { - return; - } - - $screen = get_current_screen(); - - if ( 'settings_page_wprocket' !== $screen->id ) { - return; - } - - rocket_notice_html( - [ - 'status' => 'error', - 'dismissible' => '', - // translators: %1$s = opening link tag, %2$s = closing link tag. - 'message' => sprintf( __( 'Your installation seems to be missing core Kinsta files managing Cache clearing and CDN, which will prevent your Kinsta installation and WP Rocket from working correctly. Please get in touch with Kinsta support through your %1$sMyKinsta%2$s account to resolve this issue.', 'rocket' ), '', '' ), - ] - ); - } - ); -} diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/pagely.php b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/pagely.php index 128742373..da90eb4e8 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/pagely.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/pagely.php @@ -15,4 +15,4 @@ function rocket_clean_pagely() { $purger->purgeAll(); } } -add_action( 'after_rocket_clean_domain', 'rocket_clean_pagely' ); +add_action( 'rocket_after_clean_domain', 'rocket_clean_pagely' ); diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/pressidium.php b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/pressidium.php deleted file mode 100644 index f2342e936..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/pressidium.php +++ /dev/null @@ -1,61 +0,0 @@ -purgeAllCaches(); - } - add_action( 'after_rocket_clean_domain', 'rocket_clean_pressidium' ); -} diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/presslabs.php b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/presslabs.php index 1ac7bb1c1..a909ca95e 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/presslabs.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/presslabs.php @@ -11,7 +11,7 @@ add_action( 'after_rocket_clean_home', 'rocket_pl_clean_home', 10, 2 ); add_action( 'after_rocket_clean_file', 'rocket_pl_clean_post', 2 ); add_action( 'pl_pre_url_button_cache_refresh', 'rocket_clean_files' ); -add_action( 'wp_rocket_loaded', 'rocket_remove_partial_purge_hooks' ); +add_action( 'wp_rocket_loaded', 'rocket_pl_remove_partial_purge_hooks' ); /** * We clear the cache only on the post, homepage and listings when creating/updating/deleting posts. @@ -45,7 +45,7 @@ function rocket_pl_clean_post( $post = false, $permalink = false ) { * * @return void */ -function rocket_pl_clean_home( $root = false, $lang = false ) { +function rocket_pl_clean_home( $root = false, $lang = false ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed if ( ! $post || ! $permalink ) { return; } @@ -61,7 +61,7 @@ function rocket_pl_clean_home( $root = false, $lang = false ) { * * @return void */ -function rocket_remove_partial_purge_hooks() { +function rocket_pl_remove_partial_purge_hooks() { // WP core action hooks rocket_clean_post() gets hooked into. $clean_post_hooks = [ // Disables the refreshing of partial cache when content is edited. @@ -72,7 +72,7 @@ function rocket_remove_partial_purge_hooks() { ]; // Remove rocket_clean_post() from core action hooks. array_map( - function( $hook ) { + function ( $hook ) { remove_action( $hook, 'rocket_clean_post' ); }, $clean_post_hooks diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/siteground.php b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/siteground.php index b8150b274..6650ff8cf 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/siteground.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/hosting/siteground.php @@ -60,9 +60,30 @@ function rocket_clean_supercacher() { } } +/** + * Clean WP Rocket cache when cleaning SG cache + * + * @return void + */ +function rocket_sg_clear_cache() { + if ( empty( $_GET['_wpnonce'] ) ) { + return; + } + + if ( ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'sg-cachepress-purge' ) ) { + return; + } + + if ( ! current_user_can( 'rocket_purge_cache' ) ) { + return; + } + + rocket_clean_domain(); +} + if ( rocket_is_supercacher_active() ) { - add_action( 'admin_post_sg-cachepress-purge', 'rocket_clean_domain', 0 ); - add_action( 'after_rocket_clean_domain', 'rocket_clean_supercacher' ); + add_action( 'admin_post_sg-cachepress-purge', 'rocket_sg_clear_cache', 0 ); + add_action( 'rocket_after_clean_domain', 'rocket_clean_supercacher' ); add_filter( 'rocket_display_varnish_options_tab', '__return_false' ); // Prevent mandatory cookies on hosting with server cache. add_filter( 'rocket_cache_mandatory_cookies', '__return_empty_array', PHP_INT_MAX ); @@ -80,8 +101,8 @@ function rocket_clean_supercacher() { } if ( version_compare( rocket_get_sg_optimizer_version(), '5.0' ) < 0 ) { - add_action( 'wp_ajax_sg-cachepress-purge', 'rocket_clean_domain', 0 ); + add_action( 'wp_ajax_sg-cachepress-purge', 'rocket_sg_clear_cache', 0 ); } else { - add_action( 'wp_ajax_admin_bar_purge_cache', 'rocket_clean_domain', 0 ); + add_action( 'wp_ajax_admin_bar_purge_cache', 'rocket_sg_clear_cache', 0 ); } } diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/age-verify.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/age-verify.php deleted file mode 100644 index 2e7d7bbbd..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/age-verify.php +++ /dev/null @@ -1,59 +0,0 @@ -=' ) + && defined( 'WCML_VERSION' ) + && version_compare( WCML_VERSION, '4.12.6', '>=' ); +} + +if ( rocket_wcml_has_requirements() ) : + /** + * Use Cookie instead of WCSession + * + * @return string + */ + function rocket_wcml_use_cookie_storage() { + return 'cookie'; + } + add_filter( 'wcml_user_store_strategy', 'rocket_wcml_use_cookie_storage', 10, 2 ); + + add_filter( 'rocket_cache_dynamic_cookies', 'rocket_wcml_add_dynamic_cookies' ); + add_filter( 'rocket_cache_mandatory_cookies', 'rocket_wcml_add_mandatory_cookies' ); + add_action( 'updated_option', 'rocket_wcml_reset_settings', 10, 3 ); + + /** + * Reset WP Rocket settings on WCML deactivation. + */ + function rocket_wcml_deactivate() { + remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 64 ); + remove_filter( 'rocket_cache_dynamic_cookies', 'rocket_wcml_add_dynamic_cookies' ); + remove_filter( 'rocket_cache_mandatory_cookies', 'rocket_wcml_add_mandatory_cookies' ); + flush_rocket_htaccess(); + rocket_generate_config_file(); + } + add_action( 'deactivate_woocommerce-multilingual/wpml-woocommerce.php', 'rocket_wcml_deactivate', 11 ); + + add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 64 ); + endif; + +/** + * Add dynamic cookies for WCML. + * + * @param array $cookies Cookies. + * + * @return array + */ +function rocket_wcml_add_dynamic_cookies( $cookies ) { + $cookies[] = 'wcml_client_currency'; + $cookies[] = 'wcml_client_currency_language'; + $cookies[] = 'wcml_client_country'; + + return $cookies; +} + +/** + * Add mandatory cookies for WCML. + * + * @param array $cookies Cookies. + * + * @return array + */ +function rocket_wcml_add_mandatory_cookies( $cookies ) { + // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + if ( apply_filters( 'wcml_geolocation_is_used', false ) ) { + // phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $cookies[] = 'wcml_client_country'; + } + + return $cookies; +} + +/** + * Reset WP Rocket settings when a relevant WCML setting is changed. + * + * @param string $option Option name. + * @param mixed $old_data Old data. + * @param mixed $data New data. + */ +function rocket_wcml_reset_settings( $option, $old_data, $data ) { + $keys_to_check = [ + 'enable_multi_currency', + 'currency_mode', + 'default_currencies', + ]; + + $check_key = function ( $result, $key ) use ( $old_data, $data ) { + $has_value_changed = function ( $key ) use ( $old_data, $data ) { + $get_value = function ( $key, $data ) { + return isset( $data[ $key ] ) ? $data[ $key ] : null; + }; + + return $get_value( $key, $old_data ) !== $get_value( $key, $data ); + }; + + return $result || $has_value_changed( $key ); + }; + + if ( + '_wcml_settings' === $option + && array_reduce( $keys_to_check, $check_key, false ) + ) { + flush_rocket_htaccess(); + rocket_generate_config_file(); + } +} + +/** + * Reset WP Rocket settings on WCML activation. + */ +function rocket_wcml_activate() { + if ( rocket_wcml_has_requirements() ) { + add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 64 ); + add_filter( 'rocket_cache_dynamic_cookies', 'rocket_wcml_add_dynamic_cookies' ); + add_filter( 'rocket_cache_mandatory_cookies', 'rocket_wcml_add_mandatory_cookies' ); + flush_rocket_htaccess(); + rocket_generate_config_file(); + } +} +add_action( 'activate_woocommerce-multilingual/wpml-woocommerce.php', 'rocket_wcml_activate', 11 ); diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/envira-gallery.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/envira-gallery.php index 90cef29e8..ee6ee902a 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/envira-gallery.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/envira-gallery.php @@ -29,5 +29,3 @@ function rocket_deactivate_lazyload_on_envira_gallery_indexable_images( $images return $images; } add_filter( 'envira_gallery_indexable_images', 'rocket_deactivate_lazyload_on_envira_gallery_indexable_images', PHP_INT_MAX ); - - diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/i18n/polylang.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/i18n/polylang.php index 0df3902e1..a7297c0e0 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/i18n/polylang.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/i18n/polylang.php @@ -15,7 +15,7 @@ function rocket_force_clean_domain_on_polylang() { rocket_clean_cache_dir(); } } - add_action( 'after_rocket_clean_domain', 'rocket_force_clean_domain_on_polylang' ); + add_action( 'rocket_after_clean_domain', 'rocket_force_clean_domain_on_polylang' ); // Filter mandatory cookies and WP Rocket rewrite rules if Polylang module 'Detect browser language' is enabled. if ( function_exists( 'PLL' ) && PLL()->options['browser'] ) { diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/i18n/wpml.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/i18n/wpml.php deleted file mode 100644 index 6f3482bdf..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/i18n/wpml.php +++ /dev/null @@ -1,11 +0,0 @@ - 'sitemap_preload', - 'type' => 'checkbox', - 'label' => __( 'Jetpack XML Sitemaps', 'rocket' ), - 'label_for' => 'jetpack_xml_sitemap', - 'label_screen' => sprintf( __( 'Preload the sitemap from the Jetpack plugin', 'rocket' ), 'Jetpack' ), - 'default' => 0, - ]; - $options[] = [ - 'parent' => 'sitemap_preload', - 'type' => 'helper_description', - 'name' => 'jetpack_xml_sitemap_desc', - // translators: %s = plugin name, e.g. Yoast SEO. - 'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'Jetpack' ), - ]; - - return $options; - } - add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_preload_jetpack_option' ); - } // End if(). - - /** - * Support Jetpack's EU Cookie Law Widget. - * - * @see https://jetpack.com/support/extra-sidebar-widgets/eu-cookie-law-widget/ - * - * @since 2.10.1 - * @author Jeremy Herve - */ - if ( Jetpack::is_module_active( 'widgets' ) ) : - - /** - * Add the EU Cookie Law to the list of mandatory cookies before generating caching files. - * - * @since 2.10.1 - * @author Jeremy Herve - * - * @param array $cookies List of mandatory cookies. - */ - function rocket_add_jetpack_cookie_law_mandatory_cookie( $cookies ) { - $cookies['jetpack-eu-cookie-law'] = 'eucookielaw'; - - return $cookies; - } - add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_jetpack_cookie_law_mandatory_cookie' ); - - // Don't add the WP Rocket rewrite rules to avoid issues. - add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 76 ); - - /** - * Add Jetpack cookie when: - * - Jetpack is active. - * - Jetpack's Extra Sidebar Widgets module is active. - * - The widget is active. - * - the rocket_jetpack_eu_cookie_widget option is empty or not set. - * - * @since 2.10.1 - * @author Jeremy Herve - */ - function rocket_activate_jetpack_cookie_law() { - $rocket_jp_eu_cookie_widget = get_option( 'rocket_jetpack_eu_cookie_widget' ); - - if ( - is_active_widget( false, false, 'eu_cookie_law_widget' ) - && empty( $rocket_jp_eu_cookie_widget ) - ) { - add_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 76 ); - add_filter( 'rocket_cache_mandatory_cookies', 'rocket_add_jetpack_cookie_law_mandatory_cookie' ); - - // Update the WP Rocket rules on the .htaccess file. - flush_rocket_htaccess(); - - // Regenerate the config file. - rocket_generate_config_file(); - - // Set the option, so this is not triggered again. - update_option( 'rocket_jetpack_eu_cookie_widget', 1, true ); - } - } - add_action( 'admin_init', 'rocket_activate_jetpack_cookie_law' ); - - endif; // End if Widgets module is active check. - -endif; // End if Jetpack is active check. - -/** - * Remove cookies if Jetpack gets deactivated. - * - * @since 2.10.1 - * @author Jeremy Herve - */ -function rocket_remove_jetpack_cookie_law_mandatory_cookie() { - remove_filter( 'rocket_htaccess_mod_rewrite', '__return_false', 76 ); - remove_filter( 'rocket_cache_mandatory_cookies', '_rocket_add_eu_cookie_law_mandatory_cookie' ); - - // Update the WP Rocket rules on the .htaccess file. - flush_rocket_htaccess(); - - // Regenerate the config file. - rocket_generate_config_file(); - - // Delete our option. - delete_option( 'rocket_jetpack_eu_cookie_widget' ); -} -add_action( 'deactivate_jetpack/jetpack.php', 'rocket_remove_jetpack_cookie_law_mandatory_cookie', 11 ); diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/nginx-helper.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/nginx-helper.php index 3d2090b54..e6726a88f 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/nginx-helper.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/nginx-helper.php @@ -145,5 +145,14 @@ function rocket_clean_nginx_helper_cache() { do_action( 'rt_nginx_helper_purge_all' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals } - add_action( 'after_rocket_clean_domain', 'rocket_clean_nginx_helper_cache' ); + add_action( 'rocket_after_clean_domain', 'rocket_clean_nginx_helper_cache' ); + + /** + * Clean the NGINX cache after the Used CSS has been generated. + * + * @since 3.12.3 + */ + add_action( 'rocket_rucss_after_clearing_usedcss', 'rocket_clean_nginx_cache_url' ); + add_action( 'rocket_saas_complete_job_status', 'rocket_clean_nginx_helper_cache' ); + endif; diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/secupress.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/secupress.php index 65aa03b82..8d23417e1 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/secupress.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/secupress.php @@ -11,9 +11,15 @@ * @author Remy Perona * * @param array $urls URLs to exclude from cache. + * @param bool $show_safe_content show sensitive uris. * @return array Updated URLs to exclude */ -function rocket_exclude_secupress_move_login( $urls ) { +function rocket_exclude_secupress_move_login( $urls, $show_safe_content = true ) { + + if ( ! $show_safe_content ) { + return $urls; + } + if ( ! function_exists( 'secupress_move_login_get_slugs' ) ) { return $urls; } @@ -27,7 +33,7 @@ function rocket_exclude_secupress_move_login( $urls ) { return $urls; } -add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_secupress_move_login' ); +add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_secupress_move_login', 2, 2 ); /** * Add SecuPress move login pages to cache exclusion when activating the plugin @@ -49,7 +55,7 @@ function rocket_maybe_activate_secupress() { * @author Remy Perona */ function rocket_activate_secupress() { - add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_secupress_move_login' ); + add_filter( 'rocket_cache_reject_uri', 'rocket_exclude_secupress_move_login', 2, 2 ); // Update the WP Rocket rules on the .htaccess. flush_rocket_htaccess(); diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/sf-move-login.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/sf-move-login.php index a8b650b50..592f65d3a 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/sf-move-login.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/sf-move-login.php @@ -3,7 +3,7 @@ defined( 'ABSPATH' ) || exit; if ( defined( 'SFML_VERSION' ) ) : - add_filter( 'rocket_cache_reject_uri', 'rocket_add_sfml_exclude_pages' ); + add_filter( 'rocket_cache_reject_uri', 'rocket_add_sfml_exclude_pages', 2, 2 ); add_action( 'update_option_sfml', 'rocket_after_update_single_options', 10, 2 ); endif; @@ -14,9 +14,13 @@ * @since 2.6 * * @param array $urls An array of URLs to exclude from cache. + * @param bool $show_safe_content show sensitive uris. * @return array Updated array of URLs */ -function rocket_add_sfml_exclude_pages( $urls ) { +function rocket_add_sfml_exclude_pages( $urls, $show_safe_content = true ) { + if ( ! $show_safe_content ) { + return $urls; + } if ( ! function_exists( 'sfml_get_slugs' ) ) { if ( file_exists( SFML_PLUGIN_DIR . 'inc/utilities.php' ) ) { include SFML_PLUGIN_DIR . 'inc/utilities.php'; @@ -52,7 +56,7 @@ function rocket_add_sfml_exclude_pages( $urls ) { */ function rocket_activate_sfml() { if ( defined( 'SFML_VERSION' ) ) { - add_filter( 'rocket_cache_reject_uri', 'rocket_add_sfml_exclude_pages' ); + add_filter( 'rocket_cache_reject_uri', 'rocket_add_sfml_exclude_pages', 2, 2 ); // Update the WP Rocket rules on the .htaccess. flush_rocket_htaccess(); diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/wps-hide-login.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/wps-hide-login.php index 94b08e7e6..ecbdabebc 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/wps-hide-login.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/security/wps-hide-login.php @@ -4,7 +4,7 @@ if ( class_exists( 'WPS_Hide_Login' ) || defined( 'WPS_HIDE_LOGIN_VERSION' ) ) : add_action( 'update_option_whl_page', 'rocket_after_update_single_options', 10, 2 ); - add_filter( 'rocket_cache_reject_uri', 'rocket_exlude_wps_hide_login_page' ); + add_filter( 'rocket_cache_reject_uri', 'rocket_exlude_wps_hide_login_page', 2, 2 ); endif; /** @@ -16,9 +16,14 @@ * @since 2.6 * * @param array $urls An array of URLs to exclude from cache. + * @param bool $show_safe_content show sensitive uris. * @return array Updated array of URLs */ -function rocket_exlude_wps_hide_login_page( $urls ) { +function rocket_exlude_wps_hide_login_page( $urls, $show_safe_content = true ) { + if ( ! $show_safe_content ) { + return $urls; + } + if ( class_exists( 'WPS_Hide_Login' ) ) { $wps_hide_login = new WPS_Hide_Login(); $urls[] = rocket_clean_exclude_file( $wps_hide_login->new_login_url() ); @@ -35,7 +40,7 @@ function rocket_exlude_wps_hide_login_page( $urls ) { * @since 2.11 */ function rocket_activate_wps_hide_login() { - add_filter( 'rocket_cache_reject_uri', 'rocket_exlude_wps_hide_login_page' ); + add_filter( 'rocket_cache_reject_uri', 'rocket_exlude_wps_hide_login_page', 2, 2 ); // Update .htaccess file rules. flush_rocket_htaccess(); diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/all-in-one-seo-pack.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/all-in-one-seo-pack.php deleted file mode 100644 index 382ddccc1..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/all-in-one-seo-pack.php +++ /dev/null @@ -1,101 +0,0 @@ - 'checkbox', - 'container_class' => [ - 'wpr-field--children', - ], - 'label' => __( 'All in One SEO XML sitemap', 'rocket' ), - // translators: %s = Name of the plugin. - 'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'All in One SEO' ), - 'parent' => 'sitemap_preload', - 'section' => 'preload_section', - 'page' => 'preload', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ]; - - return $options; - } - add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_preload_all_in_one_seo_option' ); - } -endif; diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/rank-math-seo.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/rank-math-seo.php deleted file mode 100644 index a45c706a1..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/rank-math-seo.php +++ /dev/null @@ -1,91 +0,0 @@ - - */ - -defined( 'ABSPATH' ) || exit; - -// Ealry Bail!! -if ( ! defined( 'RANK_MATH_FILE' ) || ! \RankMath\Helper::is_module_active( 'sitemap' ) ) { - return; -} - -/** - * Add sitemap option to WP Rocket settings - * - * @since 3.2.3 - * - * @param array $options WP Rocket settings array. - * @return array Updated WP Rocket settings array - */ -function rank_math_rocket_sitemap_preload_option( $options ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals - $options['rank_math_xml_sitemap'] = [ - 'type' => 'checkbox', - 'container_class' => [ - 'wpr-field--children', - ], - 'label' => __( 'Rank Math XML sitemap', 'rocket' ), - // translators: %s = Name of the plugin. - 'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'Rank Math SEO' ), - 'parent' => 'sitemap_preload', - 'section' => 'preload_section', - 'page' => 'preload', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ]; - - return $options; -} -add_filter( 'rocket_sitemap_preload_options', 'rank_math_rocket_sitemap_preload_option' ); - -/** - * Add sitemap option to WP Rocket default options - * - * @since 3.2.3 - * - * @param array $options WP Rocket options array. - * @return array Updated WP Rocket options array - */ -function rank_math_rocket_add_sitemap_option( $options ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals - $options['rank_math_xml_sitemap'] = 0; - - return $options; -} -add_filter( 'rocket_first_install_options', 'rank_math_rocket_add_sitemap_option' ); - -/** - * Sanitize SEO sitemap option value - * - * @since 3.2.3 - * - * @param array $inputs WP Rocket inputs array. - * @return array Sanitized WP Rocket inputs array - */ -function rank_math_rocket_sitemap_option_sanitize( $inputs ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals - $inputs['rank_math_xml_sitemap'] = ! empty( $inputs['rank_math_xml_sitemap'] ) ? 1 : 0; - - return $inputs; -} -add_filter( 'rocket_inputs_sanitize', 'rank_math_rocket_sitemap_option_sanitize' ); - -/** - * Add SEO sitemap URL to the sitemaps to preload - * - * @since 3.2.3 - * - * @param array $sitemaps Sitemaps to preload. - * @return array Updated Sitemaps to preload - */ -function rank_math_rocket_sitemap( $sitemaps ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals - if ( get_rocket_option( 'rank_math_xml_sitemap', false ) ) { - $sitemaps[] = \RankMath\Sitemap\Router::get_base_url( 'sitemap_index.xml' ); - } - - return $sitemaps; -} -add_filter( 'rocket_sitemap_preload_list', 'rank_math_rocket_sitemap' ); diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/seopress.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/seopress.php deleted file mode 100644 index 5e4fcf687..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/seopress.php +++ /dev/null @@ -1,98 +0,0 @@ - 'checkbox', - 'container_class' => [ - 'wpr-field--children', - ], - 'label' => __( 'SEOPress XML sitemap', 'rocket' ), - // translators: %s = Name of the plugin. - 'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'SEOPress' ), - 'parent' => 'sitemap_preload', - 'section' => 'preload_section', - 'page' => 'preload', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ]; - - return $options; - } - add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_preload_seopress_option' ); - } -endif; diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/the-seo-framework.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/the-seo-framework.php deleted file mode 100644 index d158cdfa1..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/the-seo-framework.php +++ /dev/null @@ -1,153 +0,0 @@ -loaded ) ) { - return; - } - - /** - * 1. Performs option & other checks. - * 2. Checks for conflicting sitemap plugins that might prevent loading. - * - * These methods cache their output at runtime. - * - * @link https://github.com/wp-media/wp-rocket/issues/899 - */ - if ( $tsf->can_run_sitemap() ) { - rocket_add_tsf_sitemap_compat(); - } -} - -/** - * Adds compatibility for the sitemap functionality in The SEO Framework plugin. - * - * @since 3.2.1 - * @author Sybre Waaijer - */ -function rocket_add_tsf_sitemap_compat() { - add_filter( 'rocket_first_install_options', 'rocket_add_tsf_seo_sitemap_option' ); - add_filter( 'rocket_inputs_sanitize', 'rocket_tsf_seo_sitemap_option_sanitize' ); - add_filter( 'rocket_sitemap_preload_list', 'rocket_add_tsf_sitemap_to_preload' ); - add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_add_tsf_sitemap_to_preload_option' ); -} - -/** - * Adds a sitemap option in WP Rocket for The SEO Framework. - * - * @since 3.2.1 - * @author Sybre Waaijer - * @source ./yoast-seo.php (Remy Perona) - * - * @param array $options WP Rocket options array. - * @return array Updated WP Rocket options array - */ -function rocket_add_tsf_seo_sitemap_option( $options ) { - $options['tsf_xml_sitemap'] = 0; - - return $options; -} - -/** - * Sanitizes the added sitemap option for The SEO Framework. - * - * @since 3.2.1 - * @author Sybre Waaijer - * @source ./yoast-seo.php (Remy Perona) - * - * @param array $inputs WP Rocket inputs array. - * @return array Sanitized WP Rocket inputs array - */ -function rocket_tsf_seo_sitemap_option_sanitize( $inputs ) { - $inputs['tsf_xml_sitemap'] = ! empty( $inputs['tsf_xml_sitemap'] ) ? 1 : 0; - - return $inputs; -} - -/** - * Adds TSF sitemap URLs to preload. - * - * @since 3.2.1 - * @since TODO Added compatibility support for The SEO Framework v4.0+ - * @author Sybre Waaijer - * @source ./yoast-seo.php (Remy Perona) - * - * @param array $sitemaps Sitemaps to preload. - * @return array Updated Sitemaps to preload - */ -function rocket_add_tsf_sitemap_to_preload( $sitemaps ) { - - if ( get_rocket_option( 'tsf_xml_sitemap', false ) ) { - // The autoloader in TSF doesn't check for file_exists(). So, use version compare instead to prevent fatal errors. - if ( version_compare( THE_SEO_FRAMEWORK_VERSION, '4.0', '>=' ) ) { - // TSF 4.0+. Expect the class to exist indefinitely. - - $sitemap_bridge = The_SEO_Framework\Bridges\Sitemap::get_instance(); - - foreach ( $sitemap_bridge->get_sitemap_endpoint_list() as $id => $data ) { - // When the sitemap is good enough for a robots display, we determine it as valid for precaching. - // Non-robots display types are among the stylesheet endpoint, or the Yoast SEO-compatible endpoint. - // In other words, this enables support for ALL current and future public sitemap endpoints. - if ( ! empty( $data['robots'] ) ) { - $sitemaps[] = $sitemap_bridge->get_expected_sitemap_endpoint_url( $id ); - } - } - } else { - // Deprecated. TSF <4.0. - $sitemaps[] = the_seo_framework()->get_sitemap_xml_url(); - } - } - - return $sitemaps; -} - -/** - * Add The SEO Framework SEO option to WP Rocket settings - * - * @since 3.2.1 - * @author Sybre Waaijer - * @source ./yoast-seo.php (Remy Perona) - * - * @param array $options WP Rocket settings array. - * @return array Updated WP Rocket settings array - */ -function rocket_sitemap_add_tsf_sitemap_to_preload_option( $options ) { - $options['tsf_xml_sitemap'] = [ - 'type' => 'checkbox', - 'container_class' => [ - 'wpr-field--children', - ], - 'label' => __( 'The SEO Framework XML sitemap', 'rocket' ), - // translators: %s = Name of the plugin. - 'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'The SEO Framework' ), - 'parent' => 'sitemap_preload', - 'section' => 'preload_section', - 'page' => 'preload', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ]; - - return $options; -} diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/yoast-seo.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/yoast-seo.php deleted file mode 100644 index c5316d3a1..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/seo/yoast-seo.php +++ /dev/null @@ -1,99 +0,0 @@ -= 0 ) { - $yoast_seo = get_option( 'wpseo' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals - $yoast_seo_xml['enablexmlsitemap'] = isset( $yoast_seo['enable_xml_sitemap'] ) && $yoast_seo['enable_xml_sitemap']; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals - } - - /** - * Improvement with Yoast SEO: auto-detect the XML sitemaps for the preload option - * - * @since 2.8 - * @author Remy Perona - */ - if ( true === $yoast_seo_xml['enablexmlsitemap'] ) { - /** - * Add Yoast SEO sitemap option to WP Rocket default options - * - * @since 2.8 - * @author Remy Perona - * - * @param array $options WP Rocket options array. - * @return array Updated WP Rocket options array - */ - function rocket_add_yoast_seo_sitemap_option( $options ) { - $options['yoast_xml_sitemap'] = 0; - - return $options; - } - add_filter( 'rocket_first_install_options', 'rocket_add_yoast_seo_sitemap_option' ); - - /** - * Sanitize Yoast SEO sitemap option value - * - * @since 2.8 - * @author Remy Perona - * - * @param array $inputs WP Rocket inputs array. - * @return array Sanitized WP Rocket inputs array - */ - function rocket_yoast_seo_sitemap_option_sanitize( $inputs ) { - $inputs['yoast_xml_sitemap'] = ! empty( $inputs['yoast_xml_sitemap'] ) ? 1 : 0; - - return $inputs; - } - add_filter( 'rocket_inputs_sanitize', 'rocket_yoast_seo_sitemap_option_sanitize' ); - - /** - * Add Yoast SEO sitemap URL to the sitemaps to preload - * - * @since 2.8 - * @author Remy Perona - * - * @param array $sitemaps Sitemaps to preload. - * @return array Updated Sitemaps to preload - */ - function rocket_add_yoast_seo_sitemap( $sitemaps ) { - if ( get_rocket_option( 'yoast_xml_sitemap', false ) ) { - $sitemaps[] = WPSEO_Sitemaps_Router::get_base_url( 'sitemap_index.xml' ); - } - - return $sitemaps; - } - add_filter( 'rocket_sitemap_preload_list', 'rocket_add_yoast_seo_sitemap' ); - - /** - * Add Yoast SEO option to WP Rocket settings - * - * @since 2.8 - * @author Remy Perona - * - * @param array $options WP Rocket settings array. - * @return array Updated WP Rocket settings array - */ - function rocket_sitemap_preload_yoast_seo_option( $options ) { - $options['yoast_xml_sitemap'] = [ - 'type' => 'checkbox', - 'container_class' => [ - 'wpr-field--children', - ], - 'label' => __( 'Yoast SEO XML sitemap', 'rocket' ), - // translators: %s = Name of the plugin. - 'description' => sprintf( __( 'We automatically detected the sitemap generated by the %s plugin. You can check the option to preload it.', 'rocket' ), 'Yoast SEO' ), - 'parent' => 'sitemap_preload', - 'section' => 'preload_section', - 'page' => 'preload', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ]; - - return $options; - } - add_filter( 'rocket_sitemap_preload_options', 'rocket_sitemap_preload_yoast_seo_option' ); - } -endif; diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/varnish-http-purge.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/varnish-http-purge.php index e94e43ee8..50c750ba8 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/varnish-http-purge.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/varnish-http-purge.php @@ -23,7 +23,7 @@ function rocket_clear_cache_after_varnish_http_purge() { } endif; -add_action( 'after_rocket_clean_domain', 'rocket_clean_varnish_http_purge' ); +add_action( 'rocket_after_clean_domain', 'rocket_clean_varnish_http_purge' ); /** * Call the cache server to purge the cache with Varnish HTTP Purge. * diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/wp-rest-api.php b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/wp-rest-api.php index c1bef7da6..d5c7928cc 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/wp-rest-api.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/plugins/wp-rest-api.php @@ -41,7 +41,7 @@ function rocket_exclude_wp_rest_api( $uri ) { * - Single site: (/index\.php)?/wp\-json(/.*|$) * - Multisite: (/[^/]+)?(/index\.php)?/wp\-json(/.*|$) */ - $uri[] = $prefix . '/(' . $index . '/)?' . $suffix . '(/.*|$)'; + $uri[] = $prefix . '/(' . $index . '/)?(.*)' . $suffix . '(/.*|$)'; return $uri; } diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/themes/studiopress.php b/wp-content/plugins/wp-rocket/inc/3rd-party/themes/studiopress.php index b9dfb76d6..b01511020 100644 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/themes/studiopress.php +++ b/wp-content/plugins/wp-rocket/inc/3rd-party/themes/studiopress.php @@ -11,6 +11,10 @@ * @return void */ function rocket_clear_cache_after_studiopress_accelerator() { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + if ( isset( $GLOBALS['sp_accel_nginx_proxy_cache_purge'] ) && is_a( $GLOBALS['sp_accel_nginx_proxy_cache_purge'], 'SP_Accel_Nginx_Proxy_Cache_Purge' ) && isset( $_REQUEST['_wpnonce'] ) ) { $nonce = $_REQUEST['_wpnonce']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.NonceVerification.Recommended if ( wp_verify_nonce( $nonce, 'sp-accel-purge-url' ) && ! empty( $_REQUEST['cache-purge-url'] ) ) { @@ -29,7 +33,7 @@ function rocket_clear_cache_after_studiopress_accelerator() { } } -add_action( 'after_rocket_clean_domain', 'rocket_clean_studiopress_accelerator' ); +add_action( 'rocket_after_clean_domain', 'rocket_clean_studiopress_accelerator' ); /** * Call the cache server to purge the cache with StudioPress Accelerator. * diff --git a/wp-content/plugins/wp-rocket/inc/3rd-party/themes/uncode.php b/wp-content/plugins/wp-rocket/inc/3rd-party/themes/uncode.php deleted file mode 100644 index 05631618e..000000000 --- a/wp-content/plugins/wp-rocket/inc/3rd-party/themes/uncode.php +++ /dev/null @@ -1,64 +0,0 @@ -get( 'Name' ) ) || 'uncode' === strtolower( $current_theme->get( 'Template' ) ) ) { - /** - * Excludes Uncode init and ai-uncode JS files from minification/combine - * - * @since 3.1 - * @author Remy Perona - * - * @param array $excluded_js Array of JS filepaths to be excluded. - * @return array - */ - function rocket_exclude_js_uncode( $excluded_js ) { - $excluded_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/init.js' ); - $excluded_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/min/init.min.js' ); - $excluded_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/ai-uncode.js' ); - $excluded_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/min/ai-uncode.min.js' ); - - return $excluded_js; - } - add_filter( 'rocket_exclude_js', 'rocket_exclude_js_uncode' ); - - /** - * Excludes some Uncode inline scripts from combine JS - * - * @since 3.1 - * @author Remy Perona - * - * @param array $inline_js Array of patterns to match for exclusion. - * @return array - */ - function rocket_exclude_inline_js_uncode( $inline_js ) { - $inline_js[] = 'SiteParameters'; - $inline_js[] = 'script-'; - $inline_js[] = 'initBox'; - $inline_js[] = 'initHeader'; - $inline_js[] = 'fixMenuHeight'; - - return $inline_js; - } - add_filter( 'rocket_excluded_inline_js_content', 'rocket_exclude_inline_js_uncode' ); - - if ( version_compare( $current_theme->get( 'Version' ), '2.1', '<' ) ) { - /** - * Excludes Uncode JS files from defer JS - * - * @since 3.2.5 - * @author Remy Perona - * - * @param array $exclude_defer_js Array of JS filepaths to be excluded. - * @return array - */ - function rocket_exclude_defer_js_uncode( $exclude_defer_js ) { - $exclude_defer_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/init.js' ); - $exclude_defer_js[] = rocket_clean_exclude_file( get_template_directory_uri() . '/library/js/min/init.min.js' ); - return $exclude_defer_js; - } - add_filter( 'rocket_exclude_defer_js', 'rocket_exclude_defer_js_uncode' ); - } -} diff --git a/wp-content/plugins/wp-rocket/inc/API/bypass.php b/wp-content/plugins/wp-rocket/inc/API/bypass.php index 396459681..8f285c7ba 100644 --- a/wp-content/plugins/wp-rocket/inc/API/bypass.php +++ b/wp-content/plugins/wp-rocket/inc/API/bypass.php @@ -12,8 +12,6 @@ * @return bool True to indicate should bypass; false otherwise. */ function rocket_bypass() { - global $wp; - static $bypass = null; if ( rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ) { @@ -24,8 +22,7 @@ function rocket_bypass() { return $bypass; } - $url = wp_parse_url( add_query_arg( $wp->query_vars, home_url( $wp->request ) ) ); - $bypass = isset( $url['query'] ) && false !== strpos( $url['query'], 'nowprocket' ); + $bypass = isset( $_GET['nowprocket'] ) && 0 !== $_GET['nowprocket']; // phpcs:ignore WordPress.Security.NonceVerification return $bypass; } diff --git a/wp-content/plugins/wp-rocket/inc/API/preload.php b/wp-content/plugins/wp-rocket/inc/API/preload.php deleted file mode 100644 index b8dc371fc..000000000 --- a/wp-content/plugins/wp-rocket/inc/API/preload.php +++ /dev/null @@ -1,112 +0,0 @@ -preload( $urls ); -} - -/** - * Launches the sitemap preload (helper function for backward compatibility) - * - * @since 2.8 - * @author Remy Perona - * - * @return void - */ -function run_rocket_sitemap_preload() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals - if ( ! get_rocket_option( 'sitemap_preload' ) || ! get_rocket_option( 'manual_preload' ) ) { - return; - } - - /** - * Filters the sitemaps list to preload - * - * @since 2.8 - * - * @param array Array of sitemaps URL - */ - $sitemaps = apply_filters( 'rocket_sitemap_preload_list', get_rocket_option( 'sitemaps', false ) ); - $sitemaps = array_flip( array_flip( $sitemaps ) ); - - if ( ! $sitemaps ) { - return; - } - - $sitemap_preload = new Sitemap( new FullProcess() ); - - $sitemap_preload->run_preload( $sitemaps ); -} - -/** - * Launches the preload cache from the admin bar or the dashboard button - * - * @since 1.3.0 Compatibility with WPML - * @since 1.0 (delete in 1.1.6 and re-add in 1.1.9) - * @deprecated 3.2 - */ -function do_admin_post_rocket_preload_cache() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals - if ( empty( $_GET['_wpnonce'] ) ) { - wp_safe_redirect( wp_get_referer() ); - die(); - } - - if ( ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'preload' ) ) { - wp_nonce_ays( '' ); - } - - if ( ! current_user_can( 'rocket_preload_cache' ) ) { - wp_safe_redirect( wp_get_referer() ); - die(); - } - - $preload_process = new FullProcess(); - - if ( $preload_process->is_process_running() ) { - wp_safe_redirect( wp_get_referer() ); - die(); - } - - delete_transient( 'rocket_preload_errors' ); - - $lang = isset( $_GET['lang'] ) && 'all' !== $_GET['lang'] ? sanitize_key( $_GET['lang'] ) : ''; - run_rocket_bot( 'cache-preload', $lang ); - run_rocket_sitemap_preload(); - - if ( ! strpos( wp_get_referer(), 'wprocket' ) ) { - set_transient( 'rocket_preload_triggered', 1 ); - } - - wp_safe_redirect( wp_get_referer() ); - die(); -} -add_action( 'admin_post_nopriv_preload', 'do_admin_post_rocket_preload_cache' ); -add_action( 'admin_post_preload', 'do_admin_post_rocket_preload_cache' ); diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/API/Client.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/API/Client.php new file mode 100644 index 000000000..388cf8ccf --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/API/Client.php @@ -0,0 +1,226 @@ +auth = $auth; + $this->args = [ + 'sslverify' => true, + 'body' => [], + 'headers' => [], + ]; + } + /** + * Change client auth. + * + * @param AuthInterface $auth Client auth. + * + * @return void + */ + public function set_auth( AuthInterface $auth ) { + $this->auth = $auth; + } + + /** + * API call method for sending requests using GET. + * + * @param string $path Path of the endpoint. + * @param mixed[] $data Data to be sent along with the request. + * + * @return object + */ + public function get( $path, array $data = [] ) { + return $this->request( $path, 'get', $data ); + } + + /** + * API call method for sending requests using POST. + * + * @param string $path Path of the endpoint. + * @param array $data Data to be sent along with the request. + * + * @return object + */ + public function post( $path, array $data = [] ) { + return $this->request( $path, 'post', $data ); + } + + /** + * API call method for sending requests using DELETE. + * + * @param string $path Path of the endpoint. + * @param array $data Data to be sent along with the request. + * + * @return object + */ + public function delete( $path, array $data = [] ) { + return $this->request( $path, 'delete', $data ); + } + + /** + * API call method for sending requests using PATCH. + * + * @param string $path Path of the endpoint. + * @param array $data Data to be sent along with the request. + * + * @return object + */ + public function patch( $path, array $data = [] ) { + return $this->request( $path, 'patch', $data ); + } + + /** + * API call method for sending requests + * + * @param string $path Path of the endpoint. + * @param string $method Type of method that should be used. + * @param array $data Data to be sent along with the request. + * + * @return object|WP_Error + */ + protected function request( $path, $method = 'get', array $data = [] ) { + if ( '/ips' !== $path ) { + $valid = $this->auth->is_valid_credentials(); + + if ( is_wp_error( $valid ) ) { + return $valid; + } + + if ( ! $valid ) { + return new WP_Error( 'cloudflare_invalid_credentials', 'Cloudflare credentials are invalid.' ); + } + } + + $response = $this->do_remote_request( $path, $method, $data ); + + if ( is_wp_error( $response ) ) { + return $response; + } + + $content = wp_remote_retrieve_body( $response ); + + if ( empty( $content ) ) { + return new WP_Error( 'cloudflare_no_reply', __( 'Cloudflare did not provide any reply. Please try again later.', 'rocket' ) ); + } + + $content = json_decode( $content ); + + if ( ! is_object( $content ) ) { + return new WP_Error( 'cloudflare_content_error', __( 'Cloudflare unexpected response', 'rocket' ) ); + } + + if ( empty( $content->success ) ) { + return $this->set_request_error( $content ); + } + + if ( ! property_exists( $content, 'result' ) ) { + return new WP_Error( 'cloudflare_no_reply', __( 'Missing Cloudflare result.', 'rocket' ) ); + } + + return $content->result; + } + + /** + * Does the request remote request. + * + * @param string $path Path of the endpoint. + * @param string $method Type of method that should be used. + * @param array $data Data to be sent along with the request. + * + * @return array|WP_Error + */ + private function do_remote_request( string $path, string $method = 'GET', array $data = [] ) { + $this->args['method'] = strtoupper( $method ); + + $headers = [ + 'User-Agent' => 'wp-rocket/' . rocket_get_constant( 'WP_ROCKET_VERSION' ), + 'Content-Type' => 'application/json', + ]; + + if ( '/ips' !== $path ) { + $this->args['headers'] = array_merge( $headers, $this->auth->get_headers() ); + } + + $this->args['body'] = []; + + if ( ! empty( $data ) ) { + $this->args['body'] = wp_json_encode( $data ); + } + + $response = wp_remote_request( self::CLOUDFLARE_API . $path, $this->args ); + + return $response; + } + + /** + * Sets the WP_Error when request is not successful + * + * @param object $content Response object. + * + * @return WP_Error + */ + private function set_request_error( $content ) { + $errors = []; + + foreach ( $content->errors as $error ) { + if ( + 6003 === $error->code || 9103 === $error->code ) { + $msg = __( 'Incorrect Cloudflare email address or API key.', 'rocket' ); + + $msg .= ' ' . sprintf( + /* translators: %1$s = opening link; %2$s = closing link */ + __( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ), + // translators: Documentation exists in EN, FR; use localized URL if applicable. + '', + '' + ); + + return new WP_Error( 'cloudflare_incorrect_credentials', $msg ); + } + + if ( 7003 === $error->code ) { + $msg = __( 'Incorrect Cloudflare Zone ID.', 'rocket' ); + + $msg .= ' ' . sprintf( + /* translators: %1$s = opening link; %2$s = closing link */ + __( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ), + // translators: Documentation exists in EN, FR; use localized URL if applicable. + '', + '' + ); + + return new WP_Error( 'cloudflare_incorrect_zone_id', $msg ); + } + + $errors[] = $error->message; + } + + return new WP_Error( 'cloudflare_request_error', wp_sprintf_l( '%l ', $errors ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/API/Endpoints.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/API/Endpoints.php new file mode 100644 index 000000000..4287ab301 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/API/Endpoints.php @@ -0,0 +1,174 @@ +client = $client; + } + + /** + * Get zone data. + * + * @param string $zone_id Zone ID. + * + * @return object + */ + public function get_zones( string $zone_id ) { + return $this->client->get( "zones/{$zone_id}" ); + } + + /** + * Get the zone's page rules. + * + * @param string $zone_id Zone ID. + * @param string $status Rule status. + * + * @return object + */ + public function list_pagerules( string $zone_id, string $status ) { + return $this->client->get( "zones/{$zone_id}/pagerules?status={$status}" ); + } + + /** + * Purges the cache. + * + * @param string $zone_id Zone ID. + * + * @return object + */ + public function purge( string $zone_id ) { + return $this->client->post( "zones/{$zone_id}/purge_cache", [ 'purge_everything' => true ] ); + } + + /** + * Purges the given URLs. + * + * @param string $zone_id Zone ID. + * @param array $urls An array of URLs that should be removed from cache. + * + * @return object + */ + public function purge_files( string $zone_id, array $urls = [] ) { + return $this->client->post( "zones/{$zone_id}/purge_cache", [ 'files' => $urls ] ); + } + + /** + * Updates the zone's browser cache TTL setting + * + * @param string $zone_id Zone ID. + * @param string $value Cache TTL value. + * + * @return object + */ + public function update_browser_cache_ttl( string $zone_id, $value ) { + return $this->update_setting( $zone_id, 'browser_cache_ttl', $value ); + } + + /** + * Updates the zone's rocket loader setting. + * + * @param string $zone_id Zone ID. + * @param string $value Rocket Loader value. + * + * @return object + */ + public function update_rocket_loader( string $zone_id, $value ) { + return $this->update_setting( $zone_id, 'rocket_loader', $value ); + } + + /** + * Updates the zone's minify setting. + * + * @param string $zone_id Zone ID. + * @param string[] $value Minify value. + * + * @return object + */ + public function update_minify( string $zone_id, $value ) { + return $this->update_setting( $zone_id, 'minify', $value ); + } + + /** + * Updates the zone's cache level. + * + * @param string $zone_id Zone ID. + * @param string $value Cache level value. + * + * @return object + */ + public function change_cache_level( string $zone_id, $value ) { + return $this->update_setting( $zone_id, 'cache_level', $value ); + } + + /** + * Changes the zone's development mode. + * + * @param string $zone_id Zone ID. + * @param string $value Development mode value. + * + * @return object + */ + public function change_development_mode( string $zone_id, $value ) { + return $this->update_setting( $zone_id, 'development_mode', $value ); + } + + /** + * Updates the given setting. + * + * @param string $zone_id Zone ID. + * @param string $setting Name of the setting to change. + * @param mixed $value Setting value. + * + * @return object + */ + protected function update_setting( string $zone_id, $setting, $value ) { + return $this->client->patch( "zones/{$zone_id}/settings/{$setting}", [ 'value' => $value ] ); + } + + /** + * Gets all of the Cloudflare settings. + * + * @param string $zone_id Zone ID. + * + * @return object + */ + public function get_settings( string $zone_id ) { + return $this->client->get( "zones/{$zone_id}/settings" ); + } + + /** + * Gets Cloudflare's IPs. + * + * @return object + */ + public function get_ips() { + return $this->client->get( '/ips' ); + } + + /** + * Change client auth. + * + * @param AuthInterface $auth Client auth. + * + * @return void + */ + public function change_auth( AuthInterface $auth ) { + $this->client->set_auth( $auth ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/APIClient.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/APIClient.php deleted file mode 100644 index 244cad585..000000000 --- a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/APIClient.php +++ /dev/null @@ -1,394 +0,0 @@ -args = [ - 'timeout' => 30, // Increase from default of 5 to give extra time for the plugin to process story for exporting. - 'sslverify' => true, - 'body' => [], - ]; - $this->headers = [ - 'X-Auth-Email' => '', - 'X-Auth-Key' => '', - 'User-Agent' => $useragent, - 'Content-type' => 'application/json', - ]; - } - - /** - * Sets up the API credentials. - * - * @since 1.0 - * - * @param string $email The email associated with the Cloudflare account. - * @param string $api_key The API key for the associated Cloudflare account. - * @param string $zone_id The zone ID. - */ - public function set_api_credentials( $email, $api_key, $zone_id ) { - $this->email = $email; - $this->api_key = $api_key; - $this->zone_id = $zone_id; - - $this->headers['X-Auth-Email'] = $email; - $this->headers['X-Auth-Key'] = $api_key; - } - - /** - * Get zone data. - * - * @since 1.0 - * - * @return stdClass Cloudflare response packet. - */ - public function get_zones() { - return $this->get( "zones/{$this->zone_id}" ); - } - - /** - * Get the zone's page rules. - * - * @since 1.0 - * - * @return stdClass Cloudflare response packet. - */ - public function list_pagerules() { - return $this->get( "zones/{$this->zone_id}/pagerules?status=active" ); - } - - /** - * Purges the cache. - * - * @since 1.0 - * - * @return stdClass Cloudflare response packet. - */ - public function purge() { - return $this->delete( "zones/{$this->zone_id}/purge_cache", [ 'purge_everything' => true ] ); - } - - /** - * Purges the given URLs. - * - * @since 1.0 - * - * @param array|null $urls An array of URLs that should be removed from cache. - * - * @return stdClass Cloudflare response packet. - */ - public function purge_files( array $urls ) { - return $this->delete( "zones/{$this->zone_id}/purge_cache", [ 'files' => $urls ] ); - } - - /** - * Changes the zone's browser cache TTL setting. - * - * @since 1.0 - * - * @param string $value New setting's value. - * - * @return stdClass Cloudflare response packet. - */ - public function change_browser_cache_ttl( $value ) { - return $this->change_setting( 'browser_cache_ttl', $value ); - } - - /** - * Changes the zone's rocket loader setting. - * - * @since 1.0 - * - * @param string $value New setting's value. - * - * @return stdClass Cloudflare response packet. - */ - public function change_rocket_loader( $value ) { - return $this->change_setting( 'rocket_loader', $value ); - } - - /** - * Changes the zone's minify setting. - * - * @since 1.0 - * - * @param string $value New setting's value. - * - * @return stdClass Cloudflare response packet. - */ - public function change_minify( $value ) { - return $this->change_setting( 'minify', $value ); - } - - /** - * Changes the zone's cache level. - * - * @since 1.0 - * - * @param string $value New setting's value. - * - * @return stdClass Cloudflare response packet. - */ - public function change_cache_level( $value ) { - return $this->change_setting( 'cache_level', $value ); - } - - /** - * Changes the zone's development mode. - * - * @since 1.0 - * - * @param string $value New setting's value. - * - * @return stdClass Cloudflare response packet. - */ - public function change_development_mode( $value ) { - return $this->change_setting( 'development_mode', $value ); - } - - /** - * Changes the given setting. - * - * @since 1.0 - * - * @param string $setting Name of the setting to change. - * @param string $value New setting's value. - * - * @return stdClass Cloudflare response packet. - */ - protected function change_setting( $setting, $value ) { - return $this->patch( "zones/{$this->zone_id}/settings/{$setting}", [ 'value' => $value ] ); - } - - /** - * Gets all of the Cloudflare settings. - * - * @since 1.0 - * - * @return stdClass Cloudflare response packet. - */ - public function get_settings() { - return $this->get( "zones/{$this->zone_id}/settings" ); - } - - /** - * Gets Cloudflare's IPs. - * - * @since 1.0 - * - * @return stdClass Cloudflare response packet. - */ - public function get_ips() { - return $this->get( '/ips' ); - } - - /** - * API call method for sending requests using GET. - * - * @since 1.0 - * - * @param string $path Path of the endpoint. - * @param array $data Data to be sent along with the request. - * - * @return stdClass Cloudflare response packet. - */ - protected function get( $path, array $data = [] ) { - return $this->request( $path, $data, 'get' ); - } - - /** - * API call method for sending requests using DELETE. - * - * @since 1.0 - * - * @param string $path Path of the endpoint. - * @param array $data Data to be sent along with the request. - * - * @return stdClass Cloudflare response packet. - */ - protected function delete( $path, array $data = [] ) { - return $this->request( $path, $data, 'delete' ); - } - - /** - * API call method for sending requests using PATCH. - * - * @since 1.0 - * - * @param string $path Path of the endpoint. - * @param array $data Data to be sent along with the request. - * - * @return stdClass Cloudflare response packet. - */ - protected function patch( $path, array $data = [] ) { - return $this->request( $path, $data, 'patch' ); - } - - /** - * API call method for sending requests using GET, POST, PUT, DELETE OR PATCH. - * - * @since 1.0 - * - * @author James Bell - credit for original code adapted for version 1.0. - * @author WP Media - * - * @param string $path Path of the endpoint. - * @param array $data Data to be sent along with the request. - * @param string $method Type of method that should be used ('GET', 'DELETE', 'PATCH'). - * - * @return stdClass response object. - * @throws AuthenticationException When email or api key are not set. - * @throws UnauthorizedException When Cloudflare's API returns a 401 or 403. - */ - protected function request( $path, array $data = [], $method = 'get' ) { - if ( '/ips' !== $path && ! $this->is_authorized() ) { - throw new AuthenticationException( 'Authentication information must be provided.' ); - } - - $response = $this->do_remote_request( $path, $data, $method ); - - if ( is_wp_error( $response ) ) { - throw new Exception( $response->get_error_message() ); - } - - $data = wp_remote_retrieve_body( $response ); - - if ( empty( $data ) ) { - throw new Exception( __( 'Cloudflare did not provide any reply. Please try again later.', 'rocket' ) ); - } - - $data = json_decode( $data ); - - if ( empty( $data->success ) ) { - $errors = []; - foreach ( $data->errors as $error ) { - if ( 6003 === $error->code || 9103 === $error->code ) { - $msg = __( 'Incorrect Cloudflare email address or API key.', 'rocket' ); - - $msg .= ' ' . sprintf( - /* translators: %1$s = opening link; %2$s = closing link */ - __( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ), - // translators: Documentation exists in EN, FR; use localized URL if applicable. - '', - '' - ); - - throw new Exception( $msg ); - } - if ( 7003 === $error->code ) { - $msg = __( 'Incorrect Cloudflare Zone ID.', 'rocket' ); - - $msg .= ' ' . sprintf( - /* translators: %1$s = opening link; %2$s = closing link */ - __( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ), - // translators: Documentation exists in EN, FR; use localized URL if applicable. - '', - '' - ); - - throw new Exception( $msg ); - } - $errors[] = $error->message; - } - throw new Exception( wp_sprintf_l( '%l ', $errors ) ); - } - - return $data; - } - - /** - * Checks if the email and API key for the API credentials are set. - * - * @since 1.0 - * - * @return bool true if authorized; else false. - */ - private function is_authorized() { - return ( - isset( $this->email, $this->api_key ) - && - false !== filter_var( $this->email, FILTER_VALIDATE_EMAIL ) - ); - } - - /** - * Does the request remote cURL request. - * - * @since 1.0 - * - * @param string $path Path of the endpoint. - * @param array $data Data to be sent along with the request. - * @param string $method Type of method that should be used ('GET', 'DELETE', 'PATCH'). - * - * @return array curl response packet. - */ - private function do_remote_request( $path, array $data, $method ) { - $this->args['method'] = isset( $method ) ? strtoupper( $method ) : 'GET'; - - if ( '/ips' !== $path ) { - $this->args['headers'] = $this->headers; - } - - $this->args['body'] = []; - - if ( ! empty( $data ) ) { - $this->args['body'] = wp_json_encode( $data ); - } - - $response = wp_remote_request( self::CLOUDFLARE_API . $path, $this->args ); - - return $response; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Admin/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Admin/Subscriber.php new file mode 100644 index 000000000..caaafc3da --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Admin/Subscriber.php @@ -0,0 +1,131 @@ + [ + [ 'maybe_display_purge_notice' ], + [ 'maybe_display_update_settings_notice' ], + ], + 'rocket_input_sanitize' => [ 'sanitize_options', 20, 2 ], + ]; + } + + /** + * This notice is displayed after purging the CloudFlare cache. + * + * @return void + */ + public function maybe_display_purge_notice() { + if ( ! current_user_can( 'rocket_purge_cloudflare_cache' ) ) { + return; + } + + $user_id = get_current_user_id(); + $notice = get_transient( $user_id . '_cloudflare_purge_result' ); + + if ( ! $notice ) { + return; + } + + delete_transient( $user_id . '_cloudflare_purge_result' ); + + rocket_notice_html( + [ + 'status' => $notice['result'], + 'message' => $notice['message'], + ] + ); + } + + /** + * This notice is displayed after modifying the CloudFlare settings. + * + * @return void + */ + public function maybe_display_update_settings_notice() { + $screen = get_current_screen(); + + if ( ! current_user_can( 'rocket_manage_options' ) || 'settings_page_wprocket' !== $screen->id ) { + return; + } + + $user_id = get_current_user_id(); + $notices = get_transient( $user_id . '_cloudflare_update_settings' ); + + if ( ! $notices ) { + return; + } + + $errors = ''; + $success = ''; + $pre = ''; + delete_transient( $user_id . '_cloudflare_update_settings' ); + + if ( isset( $notices['pre'] ) ) { + $pre = $notices['pre']; + + unset( $notices['pre'] ); + } + + foreach ( $notices as $notice ) { + if ( 'error' === $notice['result'] ) { + $errors .= $notice['message'] . '
'; + } elseif ( 'success' === $notice['result'] ) { + $success .= $notice['message'] . '
'; + } + } + + if ( ! empty( $success ) ) { + rocket_notice_html( + [ + 'message' => $pre . $success, + ] + ); + } + + if ( ! empty( $errors ) ) { + rocket_notice_html( + [ + 'status' => 'error', + 'message' => $errors, + ] + ); + } + } + + /** + * Sanitize Cloudflare options + * + * @param array $input gtArray of sanitized values after being submitted by the form. + * @param Settings $settings Settings instance. + * + * @return array + */ + public function sanitize_options( $input, $settings ) { + $input['do_cloudflare'] = $settings->sanitize_checkbox( $input, 'do_cloudflare' ); + $input['cloudflare_devmode'] = $settings->sanitize_checkbox( $input, 'cloudflare_devmode' ); + $input['cloudflare_auto_settings'] = $settings->sanitize_checkbox( $input, 'cloudflare_auto_settings' ); + $input['cloudflare_protocol_rewrite'] = $settings->sanitize_checkbox( $input, 'cloudflare_protocol_rewrite' ); + + $input['cloudflare_email'] = isset( $input['cloudflare_email'] ) ? sanitize_email( $input['cloudflare_email'] ) : ''; + $input['cloudflare_zone_id'] = isset( $input['cloudflare_zone_id'] ) ? sanitize_text_field( $input['cloudflare_zone_id'] ) : ''; + + $input['cloudflare_api_key'] = isset( $input['cloudflare_api_key'] ) ? sanitize_text_field( $input['cloudflare_api_key'] ) : ''; + + if ( defined( 'WP_ROCKET_CF_API_KEY' ) ) { + $input['cloudflare_api_key'] = rocket_get_constant( 'WP_ROCKET_CF_API_KEY', '' ); + } + + return $input; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/APIKey.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/APIKey.php new file mode 100644 index 000000000..ef2485200 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/APIKey.php @@ -0,0 +1,71 @@ +email = $email; + $this->api_key = $api_key; + } + + /** + * Gets headers for Cloudflare API request + * + * @return array + */ + public function get_headers(): array { + return [ + 'X-Auth-Email' => $this->email, + 'X-Auth-Key' => $this->api_key, + ]; + } + + /** + * Checks if the credentials are set. + * + * @return bool|WP_Error true if authorized, false if not, WP_Error if either credential is empty. + */ + public function is_valid_credentials() { + if ( + empty( $this->email ) + || + empty( $this->api_key ) + ) { + return new WP_Error( + 'cloudflare_credentials_empty', + sprintf( + /* translators: %1$s = opening link; %2$s = closing link */ + __( 'Cloudflare email and/or API key are not set. Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ), + // translators: Documentation exists in EN, FR; use localized URL if applicable. + '', + '' + ) + ); + } + + return false !== filter_var( $this->email, FILTER_VALIDATE_EMAIL ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/APIKeyFactory.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/APIKeyFactory.php new file mode 100644 index 000000000..6333ac66f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/APIKeyFactory.php @@ -0,0 +1,44 @@ +options = $options; + } + + + /** + * Create a new authentication instance. + * + * @param array $data Data to inject into the client. + * @return AuthInterface + */ + public function create( array $data = [] ): AuthInterface { + + $cf_api_key = defined( 'WP_ROCKET_CF_API_KEY' ) ? rocket_get_constant( 'WP_ROCKET_CF_API_KEY', '' ) : $this->options->get( 'cloudflare_api_key', '' ); + + $email = key_exists( 'cloudflare_email', $data ) ? $data['cloudflare_email'] : $this->options->get( 'cloudflare_email', '' ); + $api_key = key_exists( 'cloudflare_api_key', $data ) ? $data['cloudflare_api_key'] : $cf_api_key; + + return new APIKey( $email, $api_key ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/AuthFactoryInterface.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/AuthFactoryInterface.php new file mode 100644 index 000000000..ccd5ef482 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Auth/AuthFactoryInterface.php @@ -0,0 +1,16 @@ +options = $options; - $this->cloudflare_api_error = null; - $this->api = $api; - // Update api_error with WP_Error if credentials are not valid. - // Update API with Cloudflare instance with correct auth data. - $this->get_cloudflare_instance(); + public function __construct( Options_Data $options, Endpoints $endpoints ) { + $this->endpoints = $endpoints; + $this->options = $options; } /** - * Get a Cloudflare\Api instance & the zone_id corresponding to the domain. - * - * @since 1.0 + * Check valid connection with Cloudflare * - * @return Object Cloudflare instance & zone_id if credentials are correct, WP_Error otherwise. + * @param string $zone_id Cloudflare zone ID. + * @return bool|mixed|WP_Error */ - public function get_cloudflare_instance() { - $cf_email = $this->options->get( 'cloudflare_email', null ); - $cf_api_key = defined( 'WP_ROCKET_CF_API_KEY' ) ? WP_ROCKET_CF_API_KEY : $this->options->get( 'cloudflare_api_key', null ); - $cf_zone_id = $this->options->get( 'cloudflare_zone_id', null ); - $is_api_keys_valid_cf = get_transient( 'rocket_cloudflare_is_api_keys_valid' ); - - if ( false === $is_api_keys_valid_cf ) { - $is_api_keys_valid_cf = $this->is_api_keys_valid( $cf_email, $cf_api_key, $cf_zone_id ); - set_transient( 'rocket_cloudflare_is_api_keys_valid', $is_api_keys_valid_cf, 2 * WEEK_IN_SECONDS ); - } + public function check_connection( string $zone_id = '' ) { + $is_valid = get_transient( 'rocket_cloudflare_is_api_keys_valid' ); + if ( false === $is_valid ) { - if ( is_wp_error( $is_api_keys_valid_cf ) ) { - // Sets Cloudflare API as WP_Error if credentials are not valid. - $this->cloudflare_api_error = $is_api_keys_valid_cf; + if ( '' === $zone_id ) { + $zone_id = $this->options->get( 'cloudflare_zone_id', '' ); + } + + $is_valid = $this->is_auth_valid( $zone_id ); - return; + set_transient( 'rocket_cloudflare_is_api_keys_valid', $is_valid, 2 * WEEK_IN_SECONDS ); } - // Sets Cloudflare Valid Credentials and User Agent. - $this->api->set_api_credentials( $cf_email, $cf_api_key, $cf_zone_id ); + return $is_valid; } /** * Validate Cloudflare input data. * - * @since 1.0 - * - * @param string $cf_email Cloudflare email. - * @param string $cf_api_key Cloudflare API key. - * @param string $cf_zone_id Cloudflare zone ID. + * @param string $zone_id Cloudflare zone ID. * - * @return stdClass true if credentials are ok, WP_Error otherwise. + * @return bool|WP_Error true if credentials are ok, WP_Error otherwise. */ - public function is_api_keys_valid( $cf_email, $cf_api_key, $cf_zone_id ) { - if ( empty( $cf_email ) || empty( $cf_api_key ) ) { - return new WP_Error( - 'cloudflare_credentials_empty', - sprintf( - /* translators: %1$s = opening link; %2$s = closing link */ - __( 'Cloudflare email and/or API key are not set. Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ), - // translators: Documentation exists in EN, FR; use localized URL if applicable. - '', - '' - ) - ); - } - - if ( empty( $cf_zone_id ) ) { + public function is_auth_valid( string $zone_id ) { + if ( empty( $zone_id ) ) { $msg = __( 'Missing Cloudflare Zone ID.', 'rocket' ); $msg .= ' ' . sprintf( @@ -118,313 +81,299 @@ public function is_api_keys_valid( $cf_email, $cf_api_key, $cf_zone_id ) { return new WP_Error( 'cloudflare_no_zone_id', $msg ); } - try { - $this->api->set_api_credentials( $cf_email, $cf_api_key, $cf_zone_id ); + $result = $this->endpoints->get_zones( $zone_id ); - $cf_zone = $this->api->get_zones(); - $zone_found = false; - $site_url = get_site_url(); + if ( is_wp_error( $result ) ) { + return $result; + } - if ( function_exists( 'domain_mapping_siteurl' ) ) { - $site_url = domain_mapping_siteurl( $site_url ); - } + $zone_found = false; + $site_url = get_site_url(); - if ( ! empty( $cf_zone->result ) ) { - $parsed_url = wp_parse_url( $site_url ); - if ( false !== strpos( strtolower( $parsed_url['host'] ), $cf_zone->result->name ) ) { - $zone_found = true; - } - } + if ( function_exists( 'domain_mapping_siteurl' ) ) { + $site_url = domain_mapping_siteurl( $site_url ); + } - if ( ! $zone_found ) { - $msg = __( 'It looks like your domain is not set up on Cloudflare.', 'rocket' ); + $parsed_url = wp_parse_url( $site_url ); - $msg .= ' ' . sprintf( - /* translators: %1$s = opening link; %2$s = closing link */ - __( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ), - // translators: Documentation exists in EN, FR; use localized URL if applicable. - '', - '' - ); + if ( property_exists( $result, 'name' ) && false !== strpos( strtolower( $parsed_url['host'] ), $result->name ) ) { + $zone_found = true; + } - return new WP_Error( 'cloudflare_wrong_zone_id', $msg ); - } + if ( ! $zone_found ) { + $msg = __( 'It looks like your domain is not set up on Cloudflare.', 'rocket' ); - $this->cloudflare_api_error = null; - return true; - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_invalid_auth', $e->getMessage() ); + $msg .= ' ' . sprintf( + /* translators: %1$s = opening link; %2$s = closing link */ + __( 'Read the %1$sdocumentation%2$s for further guidance.', 'rocket' ), + // translators: Documentation exists in EN, FR; use localized URL if applicable. + '', + '' + ); + + return new WP_Error( 'cloudflare_zone_not_found', $msg ); } + + return true; } /** * Checks if CF has the $action_value set as a Page Rule. * - * @since 1.0 - * - * @param string $action_value Cache_everything. + * @param string $action_value Action value. * - * @return mixed Object|bool true / false if $action_value was found or not, WP_Error otherwise. + * @return mixed true/false if $action_value was found or not, WP_Error otherwise. */ public function has_page_rule( $action_value ) { - if ( is_wp_error( $this->cloudflare_api_error ) ) { - return $this->cloudflare_api_error; + $result = $this->endpoints->list_pagerules( $this->options->get( 'cloudflare_zone_id', '' ), 'active' ); + + if ( is_wp_error( $result ) ) { + return $result; } - try { - $cf_page_rule = $this->api->list_pagerules(); - $cf_page_rule_arr = wp_json_encode( $cf_page_rule ); + $page_rule = wp_json_encode( $result ); - return preg_match( '/' . $action_value . '/', $cf_page_rule_arr ); - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_page_rule_failed', $e->getMessage() ); - } + return (bool) preg_match( '/' . $action_value . '/', $page_rule ); } /** * Purge Cloudflare cache. * - * @since 1.0 - * - * @return mixed Object|bool true if the purge is successful, WP_Error otherwise. + * @return mixed true if the purge is successful, WP_Error otherwise. */ public function purge_cloudflare() { - if ( is_wp_error( $this->cloudflare_api_error ) ) { - return $this->cloudflare_api_error; - } + $result = $this->endpoints->purge( $this->options->get( 'cloudflare_zone_id', '' ) ); - try { - $cf_purge = $this->api->purge(); - return true; - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_purge_failed', $e->getMessage() ); + if ( is_wp_error( $result ) ) { + return $result; } + + return true; } /** * Purge Cloudflare Cache by URL * - * @since 1.0 - * * @param WP_Post $post The post object. * @param array $purge_urls URLs cache files to remove. * @param string $lang The post language. * - * @return mixed Object|bool true if the purge is successful, WP_Error otherwise + * @return mixed true if the purge is successful, WP_Error otherwise */ - public function purge_by_url( $post, $purge_urls, $lang ) { - if ( is_wp_error( $this->cloudflare_api_error ) ) { - return $this->cloudflare_api_error; - } + public function purge_by_url( $post, $purge_urls, $lang ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed + $result = $this->endpoints->purge_files( $this->options->get( 'cloudflare_zone_id', '' ), $purge_urls ); - try { - $cf_purge = $this->api->purge_files( $purge_urls ); - return true; - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_purge_failed', $e->getMessage() ); + if ( is_wp_error( $result ) ) { + return $result; } + + return true; } /** * Set the Browser Cache TTL in Cloudflare. * - * @since 1.0 - * - * @param string $mode Value for Cloudflare browser cache TTL. + * @param string $value Value for Cloudflare browser cache TTL. * - * @return mixed Object|String Mode value if the update is successful, WP_Error otherwise. + * @return mixed Value if the update is successful, WP_Error otherwise. */ - public function set_browser_cache_ttl( $mode ) { - if ( is_wp_error( $this->cloudflare_api_error ) ) { - return $this->cloudflare_api_error; + public function set_browser_cache_ttl( $value ) { + $result = $this->endpoints->update_browser_cache_ttl( $this->options->get( 'cloudflare_zone_id', '' ), (int) $value ); + + if ( is_wp_error( $result ) ) { + return $result; } - try { - $cf_return = $this->api->change_browser_cache_ttl( (int) $mode ); - return $mode; - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_browser_cache', $e->getMessage() ); + return $this->convert_time( (int) $value ); + } + + /** + * Convert value in seconds to seconds/minutes/hours/days + * + * @param int $value Value in seconds. + * + * @return string + */ + private function convert_time( int $value ): string { + $base = new DateTimeImmutable( '@0' ); + $time = new DateTimeImmutable( "@$value" ); + $format = '%a ' . __( 'days', 'rocket' ); + + if ( 60 > $value ) { + $format = '%s ' . __( 'seconds', 'rocket' ); + } elseif ( 3600 > $value ) { + $format = '%i ' . __( 'minutes', 'rocket' ); + } elseif ( 86400 > $value ) { + $format = '%h ' . __( 'hours', 'rocket' ); } + + return $base->diff( $time )->format( $format ); } /** * Set the Cloudflare Rocket Loader. * - * @since 1.0 - * - * @param string $mode Value for Cloudflare Rocket Loader. + * @param string $value Value for Cloudflare Rocket Loader. * - * @return mixed Object|String Mode value if the update is successful, WP_Error otherwise. + * @return mixed Value if the update is successful, WP_Error otherwise. */ - public function set_rocket_loader( $mode ) { - if ( is_wp_error( $this->cloudflare_api_error ) ) { - return $this->cloudflare_api_error; - } + public function set_rocket_loader( $value ) { + $result = $this->endpoints->update_rocket_loader( $this->options->get( 'cloudflare_zone_id', '' ), $value ); - try { - $cf_return = $this->api->change_rocket_loader( $mode ); - return $mode; - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_rocket_loader', $e->getMessage() ); + if ( is_wp_error( $result ) ) { + return $result; } + + return $value; } /** * Set the Cloudflare Minification. * - * @since 1.0 - * - * @param string $mode Value for Cloudflare minification. + * @param string $value Value for Cloudflare minification. * - * @return mixed Object|String Mode value if the update is successful, WP_Error otherwise. + * @return mixed Value if the update is successful, WP_Error otherwise. */ - public function set_minify( $mode ) { - if ( is_wp_error( $this->cloudflare_api_error ) ) { - return $this->cloudflare_api_error; - } - + public function set_minify( $value ) { $cf_minify_settings = [ - 'css' => $mode, - 'html' => $mode, - 'js' => $mode, + 'css' => $value, + 'html' => $value, + 'js' => $value, ]; - try { - $cf_return = $this->api->change_minify( $cf_minify_settings ); - return $mode; - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_minification', $e->getMessage() ); + $result = $this->endpoints->update_minify( $this->options->get( 'cloudflare_zone_id', '' ), $cf_minify_settings ); + + if ( is_wp_error( $result ) ) { + return $result; } + + return $value; } /** * Set the Cloudflare Caching level. * - * @since 1.0 + * @param string $value Value for Cloudflare caching level. * - * @param string $mode Value for Cloudflare caching level. - * - * @return mixed Object|String Mode value if the update is successful, WP_Error otherwise. + * @return mixed Value if the update is successful, WP_Error otherwise. */ - public function set_cache_level( $mode ) { - if ( is_wp_error( $this->cloudflare_api_error ) ) { - return $this->cloudflare_api_error; - } + public function set_cache_level( $value ) { + $result = $this->endpoints->change_cache_level( $this->options->get( 'cloudflare_zone_id', '' ), $value ); - try { - $cf_return = $this->api->change_cache_level( $mode ); - return $mode; - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_cache_level', $e->getMessage() ); + if ( is_wp_error( $result ) ) { + return $result; } + + return $value; } /** * Set the Cloudflare Development mode. * - * @since 1.0 + * @param string $value Value for Cloudflare development mode. * - * @param string $mode Value for Cloudflare development mode. - * - * @return mixed Object|String Mode value if the update is successful, WP_Error otherwise. + * @return mixed Value if the update is successful, WP_Error otherwise. */ - public function set_devmode( $mode ) { - if ( is_wp_error( $this->cloudflare_api_error ) ) { - return $this->cloudflare_api_error; - } - - if ( 0 === (int) $mode ) { + public function set_devmode( $value ) { + if ( 0 === (int) $value ) { $value = 'off'; } else { $value = 'on'; } - try { - $cf_return = $this->api->change_development_mode( $value ); + $result = $this->endpoints->change_development_mode( $this->options->get( 'cloudflare_zone_id', '' ), $value ); - if ( 'on' === $value ) { + if ( is_wp_error( $result ) ) { + return $result; + } + + switch ( $value ) { + case 'on': wp_schedule_single_event( time() + 3 * HOUR_IN_SECONDS, 'rocket_cron_deactivate_cloudflare_devmode' ); - } + break; + case 'off': + $next_event = wp_next_scheduled( 'rocket_cron_deactivate_cloudflare_devmode' ); - return $value; - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_dev_mode', $e->getMessage() ); + if ( false !== $next_event ) { + wp_unschedule_event( $next_event, 'rocket_cron_deactivate_cloudflare_devmode' ); + } + break; } + + return $value; } /** * Get all the current Cloudflare settings for a given domain. * - * @since 1.0 - * - * @return mixed bool|Array Array of Cloudflare settings, false if any error connection to Cloudflare. + * @return array|WP_Error Array of Cloudflare settings, WP_Error if any error connection to Cloudflare. */ public function get_settings() { - if ( is_wp_error( $this->cloudflare_api_error ) ) { - return $this->cloudflare_api_error; - } + $cf_settings = $this->endpoints->get_settings( $this->options->get( 'cloudflare_zone_id', '' ) ); - try { - $cf_settings = $this->api->get_settings(); - - foreach ( $cf_settings->result as $cloudflare_option ) { - switch ( $cloudflare_option->id ) { - case 'browser_cache_ttl': - $browser_cache_ttl = $cloudflare_option->value; - break; - case 'cache_level': - $cache_level = $cloudflare_option->value; - break; - case 'rocket_loader': - $rocket_loader = $cloudflare_option->value; - break; - case 'minify': - $cf_minify = $cloudflare_option->value; - break; - } - } - $cf_minify_value = 'on'; + if ( is_wp_error( $cf_settings ) ) { + return $cf_settings; + } - if ( 'off' === $cf_minify->js || 'off' === $cf_minify->css || 'off' === $cf_minify->html ) { - $cf_minify_value = 'off'; + $browser_cache_ttl = 0; + $cache_level = ''; + $rocket_loader = ''; + $cf_minify = ''; + + foreach ( $cf_settings as $cloudflare_option ) { + switch ( $cloudflare_option->id ) { + case 'browser_cache_ttl': + $browser_cache_ttl = $cloudflare_option->value; + break; + case 'cache_level': + $cache_level = $cloudflare_option->value; + break; + case 'rocket_loader': + $rocket_loader = $cloudflare_option->value; + break; + case 'minify': + $cf_minify = $cloudflare_option->value; + break; } + } + $cf_minify_value = 'on'; + + if ( + 'off' === $cf_minify->js + || + 'off' === $cf_minify->css + || + 'off' === $cf_minify->html + ) { + $cf_minify_value = 'off'; + } - $cf_settings_array = [ - 'cache_level' => $cache_level, - 'minify' => $cf_minify_value, - 'rocket_loader' => $rocket_loader, - 'browser_cache_ttl' => $browser_cache_ttl, - ]; + $cf_settings_array = [ + 'cache_level' => $cache_level, + 'minify' => $cf_minify_value, + 'rocket_loader' => $rocket_loader, + 'browser_cache_ttl' => $browser_cache_ttl, + ]; - return $cf_settings_array; - } catch ( Exception $e ) { - return new WP_Error( 'cloudflare_current_settings', $e->getMessage() ); - } + return $cf_settings_array; } /** * Get Cloudflare IPs. No API validation needed, all exceptions returns the default CF IPs array. * - * @since 1.0 - * - * @return Object Result of API request if successful, default CF IPs otherwise. + * @return object Result of API request if successful, default CF IPs otherwise. */ public function get_cloudflare_ips() { $cf_ips = get_transient( 'rocket_cloudflare_ips' ); + if ( false !== $cf_ips ) { return $cf_ips; } - try { - $cf_ips = $this->api->get_ips(); + $cf_ips = $this->endpoints->get_ips(); - if ( empty( $cf_ips->success ) ) { - // Set default IPs from Cloudflare if call to Cloudflare /ips API does not contain a success. - // Prevents from making API calls on each page load. - $cf_ips = $this->get_default_ips(); - } - } catch ( Exception $e ) { - // Set default IPs from Cloudflare if call to Cloudflare /ips API fails. + if ( is_wp_error( $cf_ips ) ) { + // Set default IPs from Cloudflare if call to Cloudflare /ips API does not contain a success. // Prevents from making API calls on each page load. $cf_ips = $this->get_default_ips(); } @@ -437,19 +386,15 @@ public function get_cloudflare_ips() { /** * Get default Cloudflare IPs. * - * @since 1.0 - * - * @return stdClass Default Cloudflare connecting IPs. + * @return object Default Cloudflare connecting IPs. */ private function get_default_ips() { $cf_ips = (object) [ - 'result' => (object) [], - 'success' => true, - 'errors' => [], - 'messages' => [], + 'ipv4_cidrs' => [], + 'ipv6_cidrs' => [], ]; - $cf_ips->result->ipv4_cidrs = [ + $cf_ips->ipv4_cidrs = [ '173.245.48.0/20', '103.21.244.0/22', '103.22.200.0/22', @@ -462,11 +407,12 @@ private function get_default_ips() { '198.41.128.0/17', '162.158.0.0/15', '104.16.0.0/12', + '104.24.0.0/14', '172.64.0.0/13', '131.0.72.0/22', ]; - $cf_ips->result->ipv6_cidrs = [ + $cf_ips->ipv6_cidrs = [ '2400:cb00::/32', '2606:4700::/32', '2803:f800::/32', @@ -478,4 +424,48 @@ private function get_default_ips() { return $cf_ips; } + + /** + * Sets the Cloudflare IP Rewrite + * + * @return IpRewrite + */ + public static function set_ip_rewrite() { + static $instance = null; + + if ( is_null( $instance ) ) { + $instance = new IpRewrite(); + + return $instance; + } + + return $instance; + } + + /** + * Fixes Cloudflare Flexible SSL redirect loop + * + * @return void + */ + public static function fix_cf_flexible_ssl() { + $ip_rewrite = self::set_ip_rewrite(); + + if ( $ip_rewrite->isCloudFlare() ) { + // Fixes Flexible SSL. + if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) { + $_SERVER['HTTPS'] = 'on'; + } + } + } + + /** + * Change client auth. + * + * @param AuthInterface $auth Client auth. + * + * @return void + */ + public function change_auth( AuthInterface $auth ) { + $this->endpoints->change_auth( $auth ); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/ServiceProvider.php new file mode 100644 index 000000000..49354cd4a --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/ServiceProvider.php @@ -0,0 +1,68 @@ +provides, true ); + } + + /** + * Registers items with the container + */ + public function register(): void { + $options = $this->getContainer()->get( 'options' ); + + $this->getContainer()->add( 'cloudflare_auth_factory', APIKeyFactory::class )->addArgument( $options ); + + $this->getContainer()->add( 'cloudflare_client', Client::class ) + ->addArgument( $this->getContainer()->get( 'cloudflare_auth_factory' )->create() ); + $this->getContainer()->add( 'cloudflare_endpoints', Endpoints::class ) + ->addArgument( $this->getContainer()->get( 'cloudflare_client' ) ); + + $this->getContainer()->add( 'cloudflare', Cloudflare::class ) + ->addArgument( $options ) + ->addArgument( $this->getContainer()->get( 'cloudflare_endpoints' ) ); + $this->getContainer()->addShared( 'cloudflare_subscriber', CloudflareSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'cloudflare' ) ) + ->addArgument( $options ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ) + ->addArgument( $this->getContainer()->get( 'cloudflare_auth_factory' ) ) + ->addTag( 'cloudflare_subscriber' ); + $this->getContainer()->addShared( + 'cloudflare_admin_subscriber', + CloudflareAdminSubscriber::class + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Subscriber.php index f5e8f35b8..7c2f1a88b 100644 --- a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/Subscriber.php @@ -1,18 +1,14 @@ options = $options; - $this->options_api = $options_api; - $this->cloudflare = $cloudflare; + public function __construct( Cloudflare $cloudflare, Options_Data $options, Options $options_api, AuthFactoryInterface $auth_factory ) { + $this->options = $options; + $this->options_api = $options_api; + $this->cloudflare = $cloudflare; + $this->auth_factory = $auth_factory; } /** - * Gets the subscribed events. - * - * @since 1.0 + * Returns an array of events that this subscriber wants to listen to. * - * @return array subscribed events => callbacks. + * @return array */ public static function get_subscribed_events() { $slug = rocket_get_constant( 'WP_ROCKET_SLUG', 'wp_rocket_settings' ); @@ -61,24 +64,29 @@ public static function get_subscribed_events() { 'rocket_varnish_ip' => 'set_varnish_localhost', 'rocket_varnish_purge_request_host' => 'set_varnish_purge_request_host', 'rocket_cron_deactivate_cloudflare_devmode' => 'deactivate_devmode', - 'after_rocket_clean_domain' => 'auto_purge', + 'rocket_after_clean_domain' => 'auto_purge', 'after_rocket_clean_post' => [ 'auto_purge_by_url', 10, 3 ], 'admin_post_rocket_purge_cloudflare' => 'purge_cache', 'init' => [ 'set_real_ip', 1 ], - 'update_option_' . $slug => [ 'save_cloudflare_options', 10, 2 ], - 'pre_update_option_' . $slug => [ 'save_cloudflare_old_settings', 10, 2 ], - 'admin_notices' => [ - [ 'maybe_display_purge_notice' ], - [ 'maybe_print_update_settings_notice' ], + 'update_option_' . $slug => [ + [ 'save_cloudflare_options', 10, 2 ], + [ 'update_dev_mode', 11, 2 ], + ], + 'pre_update_option_' . $slug => [ + [ 'change_auth', 8, 2 ], + [ 'delete_connection_transient', 10, 2 ], + [ 'save_cloudflare_old_settings', 10, 2 ], + [ 'display_settings_notice', 11, 2 ], ], + 'rocket_buffer' => [ 'protocol_rewrite', PHP_INT_MAX ], + 'wp_calculate_image_srcset' => [ 'protocol_rewrite_srcset', PHP_INT_MAX ], + 'rocket_cdn_helper_addons' => 'add_cdn_helper_message', ]; } /** * Sets the Varnish IP to localhost if Cloudflare is active. * - * @since 1.0 - * * @param string|array $varnish_ip Varnish IP. * * @return array @@ -100,8 +108,6 @@ public function set_varnish_localhost( $varnish_ip ) { /** * Sets the Host header to the website domain if Cloudflare is active. * - * @since 1.0 - * * @param string $host the host header value. * * @return string @@ -117,40 +123,47 @@ public function set_varnish_purge_request_host( $host ) { /** * Checks if we should filter the value for the Varnish purge. * - * @since 1.0 - * * @return bool */ - private function should_filter_varnish() { - // This filter is documented in inc/classes/subscriber/Addons/Varnish/VarnishSubscriber.php. - if ( ! apply_filters( 'do_rocket_varnish_http_purge', false ) && ! $this->options->get( 'varnish_auto_purge', 0 ) ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals - return false; - } - - return true; + private function should_filter_varnish(): bool { + // This filter is documented in inc/Addon/Varnish.php. + return apply_filters( 'do_rocket_varnish_http_purge', false ) // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals + || + $this->options->get( 'varnish_auto_purge', 0 ); } - /** * Automatically set Cloudflare development mode value to off after 3 hours to reflect Cloudflare behaviour. * - * @since 1.0 + * @return void */ public function deactivate_devmode() { - $this->options->set( 'cloudflare_devmode', 'off' ); + $this->options->set( 'cloudflare_devmode', 0 ); $this->options_api->set( 'settings', $this->options->get_options() ); } /** * Purge Cloudflare cache automatically if Cache Everything is set as a Page Rule. * - * @since 1.0 + * @return void */ public function auto_purge() { if ( ! current_user_can( 'rocket_purge_cloudflare_cache' ) ) { return; } + $settings = $this->options_api->get( 'settings', [] ); + + $this->options->set_values( $settings ); + + $auth = $this->auth_factory->create( $settings ); + + $this->cloudflare->change_auth( $auth ); + + if ( is_wp_error( $this->cloudflare->check_connection( $this->options->get( 'cloudflare_zone_id', '' ) ) ) ) { + return; + } + $cf_cache_everything = $this->cloudflare->has_page_rule( 'cache_everything' ); if ( is_wp_error( $cf_cache_everything ) || ! $cf_cache_everything ) { @@ -164,17 +177,21 @@ public function auto_purge() { /** * Purge Cloudflare cache URLs automatically if Cache Everything is set as a Page Rule. * - * @since 1.0 - * * @param WP_Post $post The post object. * @param array $purge_urls URLs cache files to remove. * @param string $lang The post language. + * + * @return void */ public function auto_purge_by_url( $post, $purge_urls, $lang ) { if ( ! current_user_can( 'rocket_purge_cloudflare_cache' ) ) { return; } + if ( is_wp_error( $this->cloudflare->check_connection() ) ) { + return; + } + $cf_cache_everything = $this->cloudflare->has_page_rule( 'cache_everything' ); if ( is_wp_error( $cf_cache_everything ) || ! $cf_cache_everything ) { @@ -198,26 +215,54 @@ public function auto_purge_by_url( $post, $purge_urls, $lang ) { /** * Purge CloudFlare cache. * - * @since 1.0 + * @return void */ public function purge_cache_no_die() { if ( ! current_user_can( 'rocket_purge_cloudflare_cache' ) ) { return; } - // Purge CloudFlare. - $cf_purge = $this->cloudflare->purge_cloudflare(); + $connection = $this->cloudflare->check_connection(); - if ( is_wp_error( $cf_purge ) ) { + if ( is_wp_error( $connection ) ) { $cf_purge_result = [ 'result' => 'error', - // translators: %s = CloudFare API return message. - 'message' => sprintf( __( 'WP Rocket: %s', 'rocket' ), $cf_purge->get_error_message() ), + 'message' => sprintf( + // translators: %1$s = , %2$s = , %3$s = CloudFare API return message. + __( '%1$sWP Rocket:%2$s %3$s', 'rocket' ), + '', + '', + $connection->get_error_message() + ), ]; - } else { + + set_transient( get_current_user_id() . '_cloudflare_purge_result', $cf_purge_result ); + + return; + } + + // Purge CloudFlare. + $cf_purge = $this->cloudflare->purge_cloudflare(); + $cf_purge_result = [ + 'result' => 'success', + 'message' => sprintf( + // translators: %1$s = , %2$s = . + __( '%1$sWP Rocket:%2$s Cloudflare cache successfully purged.', 'rocket' ), + '', + '' + ), + ]; + + if ( is_wp_error( $cf_purge ) ) { $cf_purge_result = [ - 'result' => 'success', - 'message' => __( 'WP Rocket: Cloudflare cache successfully purged.', 'rocket' ), + 'result' => 'error', + 'message' => sprintf( + // translators: %1$s = , %2$s = , %3$s = CloudFare API return message. + __( '%1$sWP Rocket:%2$s %3$s', 'rocket' ), + '', + '', + $cf_purge->get_error_message() + ), ]; } @@ -227,7 +272,7 @@ public function purge_cache_no_die() { /** * Purge CloudFlare cache. * - * @since 1.0 + * @return void */ public function purge_cache() { if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'rocket_purge_cloudflare' ) ) { @@ -243,366 +288,449 @@ public function purge_cache() { /** * Set Real IP from CloudFlare. * - * @since 1.0 - * @source cloudflare.php - https://wordpress.org/plugins/cloudflare/ + * @return void */ public function set_real_ip() { - // only run this logic if the REMOTE_ADDR is populated, to avoid causing notices in CLI mode. - if ( ! isset( $_SERVER['HTTP_CF_CONNECTING_IP'], $_SERVER['REMOTE_ADDR'] ) ) { - return; - } - - $cf_ips_values = $this->cloudflare->get_cloudflare_ips(); - $cf_ip_ranges = $cf_ips_values->result->ipv6_cidrs; - $ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ); - $ipv6 = get_rocket_ipv6_full( $ip ); - if ( false === strpos( $ip, ':' ) ) { - // IPV4: Update the REMOTE_ADDR value if the current REMOTE_ADDR value is in the specified range. - $cf_ip_ranges = $cf_ips_values->result->ipv4_cidrs; - } - - foreach ( $cf_ip_ranges as $range ) { - if ( - ( strpos( $ip, ':' ) && rocket_ipv6_in_range( $ipv6, $range ) ) - || - ( false === strpos( $ip, ':' ) && rocket_ipv4_in_range( $ip, $range ) ) - ) { - $_SERVER['REMOTE_ADDR'] = sanitize_text_field( wp_unslash( $_SERVER['HTTP_CF_CONNECTING_IP'] ) ); - break; - } - } - } - - /** - * This notice is displayed after purging the CloudFlare cache. - * - * @since 1.0 - */ - public function maybe_display_purge_notice() { - if ( ! current_user_can( 'rocket_purge_cloudflare_cache' ) ) { - return; - } - - $user_id = get_current_user_id(); - $notice = get_transient( $user_id . '_cloudflare_purge_result' ); - if ( ! $notice ) { - return; - } - - delete_transient( $user_id . '_cloudflare_purge_result' ); - - rocket_notice_html( - [ - 'status' => $notice['result'], - 'message' => $notice['message'], - ] - ); - } - - /** - * This notice is displayed after modifying the CloudFlare settings. - * - * @since 1.0 - */ - public function maybe_print_update_settings_notice() { - $screen = get_current_screen(); - - if ( ! current_user_can( 'rocket_manage_options' ) || 'settings_page_wprocket' !== $screen->id ) { - return; - } - - $user_id = get_current_user_id(); - $notices = get_transient( $user_id . '_cloudflare_update_settings' ); - if ( ! $notices ) { - return; - } - - $errors = ''; - $success = ''; - delete_transient( $user_id . '_cloudflare_update_settings' ); - foreach ( $notices as $notice ) { - if ( 'error' === $notice['result'] ) { - $errors .= $notice['message'] . '
'; - } elseif ( 'success' === $notice['result'] ) { - $success .= $notice['message'] . '
'; - } - } - - if ( ! empty( $success ) ) { - rocket_notice_html( - [ - 'message' => $success, - ] - ); - } - - if ( ! empty( $errors ) ) { - rocket_notice_html( - [ - 'status' => 'error', - 'message' => $errors, - ] - ); - } - + Cloudflare::set_ip_rewrite(); } /** * Save Cloudflare dev mode admin option. * - * @since 3.5.2 - * @author Soponar Cristina + * @param string $value New value for Cloudflare dev mode. * - * @param string $devmode New value for Cloudflare dev mode. + * @return string[] */ - private function save_cloudflare_devmode( $devmode ) { - $cloudflare_dev_mode_return = $this->cloudflare->set_devmode( $devmode ); - if ( is_wp_error( $cloudflare_dev_mode_return ) ) { + private function save_cloudflare_devmode( $value ) { + $result = $this->cloudflare->set_devmode( $value ); + + if ( is_wp_error( $result ) ) { return [ 'result' => 'error', // translators: %s is the message returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare development mode error: %s', 'rocket' ), $cloudflare_dev_mode_return->get_error_message() ), + 'message' => sprintf( __( 'Cloudflare development mode error: %s', 'rocket' ), $result->get_error_message() ), ]; } + return [ 'result' => 'success', // translators: %s is the message returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare development mode %s', 'rocket' ), $cloudflare_dev_mode_return ), + 'message' => sprintf( __( 'Cloudflare development mode %s', 'rocket' ), $result ), ]; } /** * Save Cloudflare cache_level admin option. * - * @since 3.5.2 - * @author Soponar Cristina + * @param string $value New value for Cloudflare cache_level. * - * @param string $cache_level New value for Cloudflare cache_level. + * @return string[] */ - private function save_cache_level( $cache_level ) { + private function save_cache_level( $value ) { // Set Cache Level to Aggressive. - $cf_cache_level_return = $this->cloudflare->set_cache_level( $cache_level ); + $result = $this->cloudflare->set_cache_level( $value ); - if ( is_wp_error( $cf_cache_level_return ) ) { + if ( is_wp_error( $result ) ) { return [ 'result' => 'error', // translators: %s is the message returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare cache level error: %s', 'rocket' ), $cf_cache_level_return->get_error_message() ), + 'message' => sprintf( __( 'Cloudflare cache level error: %s', 'rocket' ), $result->get_error_message() ), ]; } - if ( 'aggressive' === $cf_cache_level_return ) { - $cf_cache_level_return = _x( 'Standard', 'Cloudflare caching level', 'rocket' ); + $level = $value; + + if ( 'aggressive' === $result ) { + $level = _x( 'standard', 'Cloudflare caching level', 'rocket' ); } return [ 'result' => 'success', // translators: %s is the caching level returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare cache level set to %s', 'rocket' ), $cf_cache_level_return ), + 'message' => sprintf( __( 'Cloudflare cache level set to %s', 'rocket' ), $level ), ]; } /** * Save Cloudflare minify admin option. * - * @since 3.5.2 - * @author Soponar Cristina + * @param string $value New value for Cloudflare minify. * - * @param string $minify New value for Cloudflare minify. + * @return string[] */ - private function save_minify( $minify ) { - $cf_minify_return = $this->cloudflare->set_minify( $minify ); + private function save_minify( $value ) { + $result = $this->cloudflare->set_minify( $value ); - if ( is_wp_error( $cf_minify_return ) ) { + if ( is_wp_error( $result ) ) { return [ 'result' => 'error', // translators: %s is the message returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare minification error: %s', 'rocket' ), $cf_minify_return->get_error_message() ), + 'message' => sprintf( __( 'Cloudflare minification error: %s', 'rocket' ), $result->get_error_message() ), ]; } + return [ 'result' => 'success', // translators: %s is the message returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare minification %s', 'rocket' ), $cf_minify_return ), + 'message' => sprintf( __( 'Cloudflare minification %s', 'rocket' ), $result ), ]; } /** * Save Cloudflare rocket loader admin option. * - * @since 3.5.2 - * @author Soponar Cristina + * @param string $value New value for Cloudflare rocket loader. * - * @param string $rocket_loader New value for Cloudflare rocket loader. + * @return string[] */ - private function save_rocket_loader( $rocket_loader ) { - $cf_rocket_loader_return = $this->cloudflare->set_rocket_loader( $rocket_loader ); + private function save_rocket_loader( $value ) { + $result = $this->cloudflare->set_rocket_loader( $value ); - if ( is_wp_error( $cf_rocket_loader_return ) ) { + if ( is_wp_error( $result ) ) { return [ 'result' => 'error', // translators: %s is the message returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare rocket loader error: %s', 'rocket' ), $cf_rocket_loader_return->get_error_message() ), + 'message' => sprintf( __( 'Cloudflare rocket loader error: %s', 'rocket' ), $result->get_error_message() ), ]; } + return [ 'result' => 'success', // translators: %s is the message returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare rocket loader %s', 'rocket' ), $cf_rocket_loader_return ), + 'message' => sprintf( __( 'Cloudflare rocket loader %s', 'rocket' ), $result ), ]; } /** * Save Cloudflare browser cache ttl admin option. * - * @since 3.5.2 - * @author Soponar Cristina + * @param int $value New value for Cloudflare browser cache ttl. * - * @param int $browser_cache_ttl New value for Cloudflare browser cache ttl. + * @return string[] */ - private function save_browser_cache_ttl( $browser_cache_ttl ) { - $cf_browser_cache_return = $this->cloudflare->set_browser_cache_ttl( $browser_cache_ttl ); + private function save_browser_cache_ttl( $value ) { + $result = $this->cloudflare->set_browser_cache_ttl( $value ); - if ( is_wp_error( $cf_browser_cache_return ) ) { + if ( is_wp_error( $result ) ) { return [ 'result' => 'error', // translators: %s is the message returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare browser cache error: %s', 'rocket' ), $cf_browser_cache_return->get_error_message() ), + 'message' => sprintf( __( 'Cloudflare browser cache error: %s', 'rocket' ), $result->get_error_message() ), ]; } + return [ 'result' => 'success', // translators: %s is the message returned by the CloudFlare API. - 'message' => '' . __( 'WP Rocket: ', 'rocket' ) . '' . sprintf( __( 'Cloudflare browser cache set to %s seconds', 'rocket' ), $cf_browser_cache_return ), + 'message' => sprintf( __( 'Cloudflare browser cache set to %s', 'rocket' ), $result ), ]; } /** * Save Cloudflare auto settings admin option. * - * @since 3.5.2 - * @author Soponar Cristina + * @param int $auto_settings New value for Cloudflare auto_settings. + * @param string $old_settings Cloudflare cloudflare_old_settings. * - * @param array $auto_settings New value for Cloudflare auto_settings. - * @param array $old_settings Cloudflare cloudflare_old_settings. + * @return array> */ private function save_cloudflare_auto_settings( $auto_settings, $old_settings ) { - $cf_old_settings = explode( ',', $old_settings ); - $cloudflare_update_result = []; + $cf_old_settings = explode( ',', $old_settings ); + + $result = []; // Set Cache Level to Aggressive. - $cf_cache_level = isset( $cf_old_settings[0] ) && 0 === $auto_settings ? 'basic' : 'aggressive'; - $cloudflare_update_result[] = $this->save_cache_level( $cf_cache_level ); + $cf_cache_level = isset( $cf_old_settings[0] ) && 0 === $auto_settings ? $cf_old_settings[0] : 'aggressive'; + $result[] = $this->save_cache_level( $cf_cache_level ); // Active Minification for HTML, CSS & JS. - $cf_minify = isset( $cf_old_settings[1] ) && 0 === $auto_settings ? $cf_old_settings[1] : 'on'; - $cloudflare_update_result[] = $this->save_minify( $cf_minify ); + $cf_minify = isset( $cf_old_settings[1] ) && 0 === $auto_settings ? $cf_old_settings[1] : 'on'; + $result[] = $this->save_minify( $cf_minify ); // Deactivate Rocket Loader to prevent conflicts. - $cf_rocket_loader = isset( $cf_old_settings[2] ) && 0 === $auto_settings ? $cf_old_settings[2] : 'off'; - $cloudflare_update_result[] = $this->save_rocket_loader( $cf_rocket_loader ); + $cf_rocket_loader = isset( $cf_old_settings[2] ) && 0 === $auto_settings ? $cf_old_settings[2] : 'off'; + $result[] = $this->save_rocket_loader( $cf_rocket_loader ); // Set Browser cache to 1 year. - $cf_browser_cache_ttl = isset( $cf_old_settings[3] ) && 0 === $auto_settings ? $cf_old_settings[3] : '31536000'; - $cloudflare_update_result[] = $this->save_browser_cache_ttl( $cf_browser_cache_ttl ); + $cf_browser_cache_ttl = isset( $cf_old_settings[3] ) && 0 === $auto_settings ? $cf_old_settings[3] : 31536000; + $result[] = $this->save_browser_cache_ttl( $cf_browser_cache_ttl ); - return $cloudflare_update_result; + return $result; } /** - * Save Cloudflare admin options. + * Update the development mode value on Cloudflare * - * @since 1.0 + * @param array $old_value An array of previous values for the settings. + * @param array $value An array of submitted values for the settings. + * + * @return void + */ + public function update_dev_mode( $old_value, $value ) { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + + if ( ! isset( $old_value['cloudflare_devmode'], $value['cloudflare_devmode'] ) ) { + return; + } + + if ( (int) $old_value['cloudflare_devmode'] === (int) $value['cloudflare_devmode'] ) { + return; + } + + $connection = $this->cloudflare->check_connection( $value['cloudflare_zone_id'] ); + + if ( is_wp_error( $connection ) ) { + return; + } + + $result = [ + 'pre' => sprintf( + '%1$sWP Rocket:%2$s', + '', + ' ' + ), + ]; + $update = get_transient( get_current_user_id() . '_cloudflare_update_settings' ); + + if ( false !== $update ) { + $result = $update; + } + + $result[] = $this->save_cloudflare_devmode( $value['cloudflare_devmode'] ); + + set_transient( get_current_user_id() . '_cloudflare_update_settings', $result ); + } + + /** + * Save Cloudflare admin options. * * @param array $old_value An array of previous values for the settings. * @param array $value An array of submitted values for the settings. + * + * @return void */ public function save_cloudflare_options( $old_value, $value ) { if ( ! current_user_can( 'rocket_manage_options' ) ) { return; } - $is_api_keys_valid_cloudflare = get_transient( 'rocket_cloudflare_is_api_keys_valid' ); - $submit_cloudflare_view = false; - if ( - ( isset( $old_value['cloudflare_email'], $value['cloudflare_email'] ) && $old_value['cloudflare_email'] !== $value['cloudflare_email'] ) - || - ( isset( $old_value['cloudflare_api_key'], $value['cloudflare_api_key'] ) && $old_value['cloudflare_api_key'] !== $value['cloudflare_api_key'] ) - || - ( isset( $old_value['cloudflare_zone_id'], $value['cloudflare_zone_id'] ) && $old_value['cloudflare_zone_id'] !== $value['cloudflare_zone_id'] ) - ) { - delete_transient( 'rocket_cloudflare_is_api_keys_valid' ); - $is_api_keys_valid_cloudflare = $this->cloudflare->is_api_keys_valid( $value['cloudflare_email'], $value['cloudflare_api_key'], $value['cloudflare_zone_id'], true ); - set_transient( 'rocket_cloudflare_is_api_keys_valid', $is_api_keys_valid_cloudflare, 2 * WEEK_IN_SECONDS ); - $submit_cloudflare_view = true; - } - - if ( ( isset( $old_value['cloudflare_devmode'], $value['cloudflare_devmode'] ) && (int) $old_value['cloudflare_devmode'] !== (int) $value['cloudflare_devmode'] ) || - ( isset( $old_value['cloudflare_auto_settings'], $value['cloudflare_auto_settings'] ) && (int) $old_value['cloudflare_auto_settings'] !== (int) $value['cloudflare_auto_settings'] ) ) { - $submit_cloudflare_view = true; - } - - // Revalidate Cloudflare credentials if transient is false. - if ( false === $is_api_keys_valid_cloudflare ) { - if ( isset( $value['cloudflare_email'], $value['cloudflare_api_key'], $value['cloudflare_zone_id'] ) ) { - $is_api_keys_valid_cloudflare = $this->cloudflare->is_api_keys_valid( $value['cloudflare_email'], $value['cloudflare_api_key'], $value['cloudflare_zone_id'] ); - } else { - $is_api_keys_valid_cloudflare = false; - } - set_transient( 'rocket_cloudflare_is_api_keys_valid', $is_api_keys_valid_cloudflare, 2 * WEEK_IN_SECONDS ); - } - - // If is submit CF view & CF Credentials are invalid, display error and bail out. - if ( is_wp_error( $is_api_keys_valid_cloudflare ) && $submit_cloudflare_view ) { - $cloudflare_error_message = $is_api_keys_valid_cloudflare->get_error_message(); - add_settings_error( 'general', 'cloudflare_api_key_invalid', __( 'WP Rocket: ', 'rocket' ) . '' . $cloudflare_error_message . '', 'error' ); - set_transient( get_current_user_id() . '_cloudflare_update_settings', [] ); + if ( ! isset( $old_value['cloudflare_auto_settings'], $value['cloudflare_auto_settings'] ) ) { + return; + } + + if ( (int) $old_value['cloudflare_auto_settings'] === (int) $value['cloudflare_auto_settings'] ) { return; } - // Update CloudFlare Development Mode. - $cloudflare_update_result = []; - if ( isset( $old_value['cloudflare_devmode'], $value['cloudflare_devmode'] ) && (int) $old_value['cloudflare_devmode'] !== (int) $value['cloudflare_devmode'] ) { - $cloudflare_update_result[] = $this->save_cloudflare_devmode( $value['cloudflare_devmode'] ); + $connection = $this->cloudflare->check_connection( $value['cloudflare_zone_id'] ); + + if ( is_wp_error( $connection ) ) { + return; } - // Update CloudFlare settings. - if ( isset( $old_value['cloudflare_auto_settings'], $value['cloudflare_auto_settings'] ) && (int) $old_value['cloudflare_auto_settings'] !== (int) $value['cloudflare_auto_settings'] ) { - $cloudflare_update_result = array_merge( $cloudflare_update_result, $this->save_cloudflare_auto_settings( $value['cloudflare_auto_settings'], $value['cloudflare_old_settings'] ) ); + $result = [ + 'pre' => sprintf( + // translators: %1$s = strong opening tag, %2$s = strong closing tag. + __( '%1$sWP Rocket:%2$s Optimal settings activated for Cloudflare:', 'rocket' ), + '', + '' + ) . '
', + ]; + + if ( 0 === (int) $value['cloudflare_auto_settings'] ) { + $result['pre'] = sprintf( + // translators: %1$s = strong opening tag, %2$s = strong closing tag. + __( '%1$sWP Rocket:%2$s Optimal settings deactivated for Cloudflare, reverted to previous settings:', 'rocket' ), + '', + '' + ) . '
'; } - set_transient( get_current_user_id() . '_cloudflare_update_settings', $cloudflare_update_result ); + $result = array_merge( $result, $this->save_cloudflare_auto_settings( $value['cloudflare_auto_settings'], $value['cloudflare_old_settings'] ) ); + + set_transient( get_current_user_id() . '_cloudflare_update_settings', $result ); } /** * Save Cloudflare old settings when the auto settings option is enabled. * - * @since 1.0 - * * @param array $value An array of previous values for the settings. * @param array $old_value An array of submitted values for the settings. * - * @return array settings with old settings. + * @return array */ public function save_cloudflare_old_settings( $value, $old_value ) { if ( ! current_user_can( 'rocket_manage_options' ) ) { return $value; } - // Save old CloudFlare settings. - if ( - isset( $value['cloudflare_auto_settings'], $old_value ['cloudflare_auto_settings'] ) - && - $value['cloudflare_auto_settings'] !== $old_value ['cloudflare_auto_settings'] - && - 1 === $value['cloudflare_auto_settings'] - ) { - $cf_settings = $this->cloudflare->get_settings(); - $value['cloudflare_old_settings'] = ! is_wp_error( $cf_settings ) - ? implode( ',', array_filter( $cf_settings ) ) - : ''; + if ( ! isset( $value['cloudflare_auto_settings'], $old_value ['cloudflare_auto_settings'] ) ) { + return $value; + } + + if ( $value['cloudflare_auto_settings'] === $old_value ['cloudflare_auto_settings'] ) { + return $value; + } + + if ( 0 === (int) $value['cloudflare_auto_settings'] ) { + return $value; + } + + $cloudflare_zone_id = key_exists( 'cloudflare_zone_id', $value ) ? $value['cloudflare_zone_id'] : ''; + + if ( is_wp_error( $this->cloudflare->check_connection( $cloudflare_zone_id ) ) ) { + return $value; + } + + $cf_settings = $this->cloudflare->get_settings(); + $value['cloudflare_old_settings'] = ! is_wp_error( $cf_settings ) + ? implode( ',', array_filter( $cf_settings ) ) + : ''; + + return $value; + } + + /** + * Change the authentification. + * + * @param array $value An array of previous values for the settings. + * @param array $old_value An array of submitted values for the settings. + * + * @return mixed + */ + public function change_auth( $value, $old_value ) { + $auth = $this->auth_factory->create( $value ); + $this->cloudflare->change_auth( $auth ); + return $value; + } + + /** + * Delete the transient CF connection status when API Key, Email or Zone ID is changed + * + * @param array $value An array of previous values for the settings. + * @param array $old_value An array of submitted values for the settings. + * + * @return array + */ + public function delete_connection_transient( $value, $old_value ) { + + $fields = [ + 'cloudflare_api_key', + 'cloudflare_email', + 'cloudflare_zone_id', + 'cloudflare_devmode', + 'cloudflare_auto_settings', + 'cloudflare_protocol_rewrite', + ]; + + $change = false; + + foreach ( $fields as $field ) { + $change |= ! isset( $old_value[ $field ], $value[ $field ] ) || $old_value[ $field ] !== $value[ $field ]; + } + + if ( ! $change ) { + return $value; + } + + delete_transient( get_current_user_id() . '_cloudflare_update_settings' ); + delete_transient( 'rocket_cloudflare_is_api_keys_valid' ); + + return $value; + } + + /** + * Display the error notice. + * + * @param array $value An array of previous values for the settings. + * @param array $old_value An array of submitted values for the settings. + * + * @return mixed + */ + public function display_settings_notice( $value, $old_value ) { + + if ( ! key_exists( 'cloudflare_zone_id', $value ) ) { + return $value; + } + + $connection = $this->cloudflare->check_connection( $value['cloudflare_zone_id'] ); + + if ( is_wp_error( $connection ) ) { + add_settings_error( 'general', 'cloudflare_api_key_invalid', __( 'WP Rocket: ', 'rocket' ) . '
' . $connection->get_error_message() . '', 'error' ); } return $value; } + + /** + * Remove HTTP protocol on script, link, img and form tags. + * + * @param string $buffer HTML content. + * + * @return string + */ + public function protocol_rewrite( $buffer ) { + if ( ! $this->can_protocol_rewrite() ) { + return $buffer; + } + + $return = preg_replace( "/(<(script|link|img|form)(?!.*?[\"']\bcanonical\b[\"'])([^>]*)(href|src|action)=[\"'])https?:\\/\\//i", '$1//', $buffer ); + + if ( $return ) { + $buffer = $return; + } + + return $buffer; + } + + /** + * Remove HTTP protocol on srcset attribute generated by WordPress + * + * @param array $sources an Array of images sources for srcset. + * + * @return array + */ + public function protocol_rewrite_srcset( $sources ) { + if ( ! $this->can_protocol_rewrite() ) { + return $sources; + } + + if ( empty( $sources ) ) { + return $sources; + } + + foreach ( $sources as $i => $source ) { + $sources[ $i ]['url'] = str_replace( [ 'http:', 'https:' ], '', $source['url'] ); + } + + return $sources; + } + + /** + * Can rewrite protocol + * + * @return bool + */ + private function can_protocol_rewrite(): bool { + return $this->options->get( 'do_cloudflare', 0 ) + && + ( + $this->options->get( 'cloudflare_protocol_rewrite', 0 ) + || + apply_filters( 'do_rocket_protocol_rewrite', false ) // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + ); + } + + /** + * Add the helper message on the CDN settings. + * + * @param string[] $addons Name from the addon that requires the helper message. + * @return string[] + */ + public function add_cdn_helper_message( array $addons ): array { + $addons[] = 'Cloudflare'; + return $addons; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/UnauthorizedException.php b/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/UnauthorizedException.php deleted file mode 100644 index a06570e19..000000000 --- a/wp-content/plugins/wp-rocket/inc/Addon/Cloudflare/UnauthorizedException.php +++ /dev/null @@ -1,7 +0,0 @@ -getContainer()->get( 'options' ); - - // Busting Factory. - $this->getContainer()->add( 'busting_factory', 'WP_Rocket\Addon\Busting\BustingFactory' ) - ->withArgument( rocket_get_constant( 'WP_ROCKET_CACHE_BUSTING_PATH' ) ) - ->withArgument( rocket_get_constant( 'WP_ROCKET_CACHE_BUSTING_URL' ) ); - - // Facebook Tracking Subscriber. - $this->getContainer()->share( 'facebook_tracking', 'WP_Rocket\Addon\FacebookTracking\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'busting_factory' ) ) - ->withArgument( $options ); - - // Google Tracking Subscriber. - $this->getContainer()->share( 'google_tracking', 'WP_Rocket\Addon\GoogleTracking\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'busting_factory' ) ) - ->withArgument( $options ); - - // Sucuri Addon. - $this->getContainer()->share( 'sucuri_subscriber', 'WP_Rocket\Subscriber\Third_Party\Plugins\Security\Sucuri_Subscriber' ) - ->withArgument( $options ); - - // Cloudflare Addon. - $this->addon_cloudflare( $options ); + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); } /** - * Adds Cloudflare Addon into the Container when the addon is enabled. - * - * @since 3.5 - * - * @param Options_Data $options Instance of options. + * Registers items with the container */ - protected function addon_cloudflare( Options_Data $options ) { - // If the addon is not enabled, delete the transient and bail out. Don't load the addon. - if ( ! (bool) $options->get( 'do_cloudflare', false ) ) { - delete_transient( 'rocket_cloudflare_is_api_keys_valid' ); - return; - } - - $this->provides[] = 'cloudflare_subscriber'; + public function register(): void { + $options = $this->getContainer()->get( 'options' ); - $this->getContainer()->add( 'cloudflare_api', 'WPMedia\Cloudflare\APIClient' ) - ->withArgument( rocket_get_constant( 'WP_ROCKET_VERSION' ) ); - $this->getContainer()->add( 'cloudflare', 'WPMedia\Cloudflare\Cloudflare' ) - ->withArgument( $options ) - ->withArgument( $this->getContainer()->get( 'cloudflare_api' ) ); - $this->getContainer()->share( 'cloudflare_subscriber', 'WPMedia\Cloudflare\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'cloudflare' ) ) - ->withArgument( $options ) - ->withArgument( $this->getContainer()->get( 'options_api' ) ); + // Sucuri Addon. + $this->getContainer()->addShared( 'sucuri_subscriber', SucuriSubscriber::class ) + ->addArgument( $options ) + ->addTag( 'common_subscriber' ); + + $this->getContainer()->addShared( 'webp_admin_subscriber', WebPAdminSubscriber::class ) + ->addArgument( $options ) + ->addArgument( $this->getContainer()->get( 'cdn_subscriber' ) ) + ->addArgument( $this->getContainer()->get( 'beacon' ) ) + ->addTag( 'common_subscriber' ); + + $this->getContainer()->addShared( 'webp_subscriber', WebPSubscriber::class ) + ->addArgument( $options ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ) + ->addArgument( $this->getContainer()->get( 'cdn_subscriber' ) ) + ->addTag( 'common_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/classes/subscriber/third-party/plugins/security/class-sucuri-subscriber.php b/wp-content/plugins/wp-rocket/inc/Addon/Sucuri/Subscriber.php similarity index 56% rename from wp-content/plugins/wp-rocket/inc/classes/subscriber/third-party/plugins/security/class-sucuri-subscriber.php rename to wp-content/plugins/wp-rocket/inc/Addon/Sucuri/Subscriber.php index 2a40270a6..8e0154d69 100644 --- a/wp-content/plugins/wp-rocket/inc/classes/subscriber/third-party/plugins/security/class-sucuri-subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Addon/Sucuri/Subscriber.php @@ -1,50 +1,37 @@ options = $options; } @@ -53,7 +40,7 @@ public function __construct( Options $options ) { */ public static function get_subscribed_events() { return [ - 'after_rocket_clean_domain' => 'maybe_clean_firewall_cache', + 'rocket_after_clean_domain' => 'maybe_clean_firewall_cache', 'after_rocket_clean_post' => 'maybe_clean_firewall_cache', 'after_rocket_clean_term' => 'maybe_clean_firewall_cache', 'after_rocket_clean_user' => 'maybe_clean_firewall_cache', @@ -61,19 +48,14 @@ public static function get_subscribed_events() { 'after_rocket_clean_files' => 'maybe_clean_firewall_cache', 'admin_post_rocket_purge_sucuri' => 'do_admin_post_rocket_purge_sucuri', 'admin_notices' => 'maybe_print_notice', + 'rocket_cdn_helper_addons' => 'add_cdn_helper_message', ]; } - /** ----------------------------------------------------------------------------------------- */ - /** HOOK CALLBACKS ========================================================================== */ - /** ----------------------------------------------------------------------------------------- */ - /** * Clear Sucuri firewall cache. * - * @since 3.2 - * @access public - * @author Grégory Viguier + * @since 3.2 */ public function maybe_clean_firewall_cache() { static $done = false; @@ -94,9 +76,7 @@ public function maybe_clean_firewall_cache() { /** * Ajax callback to empty Sucury cache. * - * @since 3.2 - * @access public - * @author Grégory Viguier + * @since 3.2 */ public function do_admin_post_rocket_purge_sucuri() { if ( empty( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'rocket_purge_sucuri' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash @@ -131,9 +111,7 @@ public function do_admin_post_rocket_purge_sucuri() { /** * Print an admin notice if the cache failed to be cleared. * - * @since 3.2 - * @access public - * @author Grégory Viguier + * @since 3.2 */ public function maybe_print_notice() { if ( ! current_user_can( 'rocket_purge_sucuri_cache' ) ) { @@ -144,6 +122,10 @@ public function maybe_print_notice() { return; } + if ( ! $this->options->get( 'sucury_waf_cache_sync', 0 ) ) { + return; + } + $user_id = get_current_user_id(); $notice = get_transient( $user_id . '_sucuri_purge_result' ); @@ -162,19 +144,14 @@ public function maybe_print_notice() { ); } - /** ----------------------------------------------------------------------------------------- */ - /** TOOLS =================================================================================== */ - /** ----------------------------------------------------------------------------------------- */ - /** - * Tell if a API key is well formatted. + * Tell if an API key is well formatted. + * + * @since 3.2.3 * - * @since 3.2.3 - * @access public - * @author Grégory Viguier + * @param string $api_key An API key. * - * @param string $api_key An API kay. - * @return array|bool An array with the keys 'k' and 's' (required by the API) if valid. False otherwise. + * @return array|false An array with the keys 'k' and 's' (required by the API) if valid. False otherwise. */ public static function is_api_key_valid( $api_key ) { if ( '' !== $api_key && preg_match( '@^(?[a-z0-9]{32})/(?[a-z0-9]{32})$@', $api_key, $matches ) ) { @@ -187,11 +164,9 @@ public static function is_api_key_valid( $api_key ) { /** * Clear Sucuri firewall cache. * - * @since 3.2 - * @access private - * @author Grégory Viguier + * @since 3.2 * - * @return bool|object True on success. A WP_Error object on failure. + * @return true|WP_Error True on success. A WP_Error object on failure. */ private function clean_firewall_cache() { $api_key = $this->get_api_key(); @@ -225,11 +200,9 @@ private function clean_firewall_cache() { /** * Get the API key. * - * @since 3.2 - * @access private - * @author Grégory Viguier + * @since 3.2 * - * @return array|object An array with the keys 'k' and 's', required by the API. A WP_Error object if no key or invalid key. + * @return array|WP_Error An array with the keys 'k' and 's', required by the API. A WP_Error object if no key or invalid key. */ private function get_api_key() { $api_key = trim( $this->options->get( 'sucury_waf_api_key', '' ) ); @@ -241,7 +214,8 @@ private function get_api_key() { 'sucuri firewall cache', ] ); - return new \WP_Error( 'no_sucuri_api_key', __( 'Sucuri firewall API key was not found.', 'rocket' ) ); + + return new WP_Error( 'no_sucuri_api_key', __( 'Sucuri firewall API key was not found.', 'rocket' ) ); } $matches = self::is_api_key_valid( $api_key ); @@ -253,7 +227,8 @@ private function get_api_key() { 'sucuri firewall cache', ] ); - return new \WP_Error( 'invalid_sucuri_api_key', __( 'Sucuri firewall API key is invalid.', 'rocket' ) ); + + return new WP_Error( 'invalid_sucuri_api_key', __( 'Sucuri firewall API key is invalid.', 'rocket' ) ); } return [ @@ -265,51 +240,37 @@ private function get_api_key() { /** * Request against the API. * - * @since 3.2 - * @access private - * @author Grégory Viguier + * @since 3.2 + * + * @param array $params Parameters to send. * - * @param array $params Parameters to send. - * @return array|object The response data on success. A WP_Error object on failure. + * @return array|WP_Error The response data on success. A WP_Error object on failure. */ private function request_api( $params = [] ) { $params['time'] = time(); $params = $this->build_query( $params ); $url = sprintf( static::API_URL, $params ); - try { - /** - * Filters the arguments for the Sucuri API request - * - * @since 3.3.4 - * @author Soponar Cristina - * - * @param array $args Arguments for the request. - */ - $args = apply_filters( - 'rocket_sucuri_api_request_args', - [ - 'timeout' => 5, - 'redirection' => 5, - 'httpversion' => '1.1', - 'blocking' => true, - /** This filter is documented in wp-includes/class-wp-http-streams.php */ - 'sslverify' => apply_filters( 'https_ssl_verify', true ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound - ] - ); + /** + * Filters the arguments for the Sucuri API request + * + * @since 3.3.4 + * + * @param array $args Arguments for the request. + */ + $args = apply_filters( + 'rocket_sucuri_api_request_args', + [ + 'timeout' => 5, + 'redirection' => 5, + 'httpversion' => '1.1', + 'blocking' => true, + // This filter is documented in wp-includes/class-wp-http-streams.php. + 'sslverify' => apply_filters( 'https_ssl_verify', true ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + ] + ); - $response = wp_remote_get( $url, $args ); - } catch ( \Exception $e ) { - Logger::error( - 'Error when contacting the API.', - [ - 'sucuri firewall cache', - 'url' => $url, - 'response' => $e->getMessage(), - ] - ); - return new \WP_Error( 'error_sucuri_api', __( 'Error when contacting Sucuri firewall API.', 'rocket' ) ); - } + $response = wp_remote_get( $url, $args ); if ( is_wp_error( $response ) ) { Logger::error( @@ -320,13 +281,14 @@ private function request_api( $params = [] ) { 'response' => $response->get_error_message(), ] ); - /* translators: %s is an error message. */ - return new \WP_Error( 'wp_error_sucuri_api', sprintf( __( 'Error when contacting Sucuri firewall API. Error message was: %s', 'rocket' ), $response->get_error_message() ) ); + + // translators: %s is an error message. + return new WP_Error( 'wp_error_sucuri_api', sprintf( __( 'Error when contacting Sucuri firewall API. Error message was: %s', 'rocket' ), $response->get_error_message() ) ); } $contents = wp_remote_retrieve_body( $response ); - if ( ! $contents ) { + if ( empty( $contents ) ) { Logger::error( 'Could not get a response from the API.', [ @@ -335,10 +297,11 @@ private function request_api( $params = [] ) { 'response' => $response, ] ); - return new \WP_Error( 'sucuri_api_no_response', __( 'Could not get a response from the Sucuri firewall API.', 'rocket' ) ); + + return new WP_Error( 'sucuri_api_no_response', __( 'Could not get a response from the Sucuri firewall API.', 'rocket' ) ); } - $data = @json_decode( $contents, true ); + $data = json_decode( $contents, true ); if ( ! $data || ! is_array( $data ) ) { Logger::error( @@ -349,7 +312,8 @@ private function request_api( $params = [] ) { 'response_body' => $contents, ] ); - return new \WP_Error( 'sucuri_api_invalid_response', __( 'Got an invalid response from the Sucuri firewall API.', 'rocket' ) ); + + return new WP_Error( 'sucuri_api_invalid_response', __( 'Got an invalid response from the Sucuri firewall API.', 'rocket' ) ); } if ( empty( $data['status'] ) ) { @@ -361,25 +325,45 @@ private function request_api( $params = [] ) { 'response_data' => $data, ] ); + if ( empty( $data['messages'] ) || ! is_array( $data['messages'] ) ) { - return new \WP_Error( 'sucuri_api_error_status', __( 'The Sucuri firewall API returned an unknown error.', 'rocket' ) ); + return new WP_Error( 'sucuri_api_error_status', __( 'The Sucuri firewall API returned an unknown error.', 'rocket' ) ); } - /* translators: %s is an error message. */ + + // translators: %s is an error message. $message = _n( 'The Sucuri firewall API returned the following error: %s', 'The Sucuri firewall API returned the following errors: %s', count( $data['messages'] ), 'rocket' ); $message = sprintf( $message, '
' . implode( '
', $data['messages'] ) ); - return new \WP_Error( 'sucuri_api_error_status', $message ); + + return new WP_Error( 'sucuri_api_error_status', $message ); } return $data; } /** - * An i18n-firendly alternative to the built-in PHP method `http_build_query()`. + * Add the helper message on the CDN settings. + * + * @param string[] $addons Name from the addon that requires the helper message. + * @return string[] + */ + public function add_cdn_helper_message( array $addons ): array { + + if ( ! $this->options->get( 'sucury_waf_cache_sync', false ) ) { + return $addons; + } + + $addons[] = 'Sucuri'; + return $addons; + } + + /** + * An i18n-friendly alternative to the built-in PHP method `http_build_query()`. + * + * @param array|object $params An array or object containing properties. * - * @param array|object $params An array or object containing properties. - * @return string A URL-encoded string. + * @return string An URL-encoded string. */ - private function build_query( $params ) { + private function build_query( $params ): string { if ( ! $params ) { return ''; } diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Varnish/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Addon/Varnish/ServiceProvider.php index ad5f2e202..1fb74154d 100644 --- a/wp-content/plugins/wp-rocket/inc/Addon/Varnish/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Addon/Varnish/ServiceProvider.php @@ -1,19 +1,14 @@ provides, true ); + } + + /** + * Registers items with the container * - * @since 3.3 + * @return void */ - public function register() { - $this->getContainer()->add( 'varnish', 'WP_Rocket\Addon\Varnish\Varnish' ); - $this->getContainer()->share( 'varnish_subscriber', 'WP_Rocket\Addon\Varnish\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'varnish' ) ) - ->withArgument( $this->getContainer()->get( 'options' ) ); + public function register(): void { + $this->getContainer()->add( 'varnish', Varnish::class ); + $this->getContainer()->addShared( 'varnish_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'varnish' ) ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addTag( 'common_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Varnish/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Addon/Varnish/Subscriber.php index 225b11ea0..6b1e9fa1d 100644 --- a/wp-content/plugins/wp-rocket/inc/Addon/Varnish/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Addon/Varnish/Subscriber.php @@ -40,9 +40,11 @@ public function __construct( Varnish $varnish, Options_Data $options ) { */ public static function get_subscribed_events() { return [ - 'before_rocket_clean_domain' => [ 'clean_domain', 10, 3 ], - 'before_rocket_clean_file' => [ 'clean_file' ], - 'before_rocket_clean_home' => [ 'clean_home', 10, 2 ], + 'before_rocket_clean_domain' => [ 'clean_domain', 10, 3 ], + 'before_rocket_clean_file' => [ 'clean_file' ], + 'rocket_rucss_after_clearing_usedcss' => [ 'clean_file' ], + 'before_rocket_clean_home' => [ 'clean_home', 10, 2 ], + 'rocket_saas_complete_job_status' => [ 'clean_file' ], ]; } diff --git a/wp-content/plugins/wp-rocket/inc/Addon/Varnish/composer.json b/wp-content/plugins/wp-rocket/inc/Addon/Varnish/composer.json index 2b70a94d1..e96f3d65b 100644 --- a/wp-content/plugins/wp-rocket/inc/Addon/Varnish/composer.json +++ b/wp-content/plugins/wp-rocket/inc/Addon/Varnish/composer.json @@ -19,25 +19,41 @@ "source": "https://github.com/wp-media/module-varnish" }, "require-dev": { - "php": "^5.6 || ^7", + "php": "^7 || ^8", "brain/monkey": "^2.0", + "coenjacobs/mozart": "^0.7", "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", + "league/container": "^3.3", "phpcompatibility/phpcompatibility-wp": "^2.0", "phpstan/phpstan": "^0.12.3", - "phpunit/phpunit": "^5.7 || ^7", + "phpunit/phpunit": "^7", + "psr/container": "1.0.0", "roave/security-advisories": "dev-master", - "szepeviktor/phpstan-wordpress": "^0.6", + "szepeviktor/phpstan-wordpress": "^0.7", "wp-coding-standards/wpcs": "^2", "wp-media/event-manager": "^3.1", - "wp-media/module-container": "^2.4", "wp-media/options": "^3.0", - "wp-media/phpunit": "^1.0" + "wp-media/phpunit": "1.1.6" }, "autoload": { "psr-4": { "WP_Rocket\\Addon\\Varnish\\": "." } }, "autoload-dev": { - "psr-4": { "WP_Rocket\\Tests\\": "Tests/" } + "psr-4": { + "WP_Rocket\\Tests\\": "Tests/", + "WP_Rocket\\Dependencies\\": "Dependencies/" + } + }, + "extra": { + "mozart": { + "dep_namespace": "WP_Rocket\\Dependencies\\", + "dep_directory": "/Dependencies/", + "classmap_directory": "/classes/dependencies/", + "classmap_prefix": "WP_Rocket_", + "packages": [ + "league/container" + ] + } }, "scripts": { "test-unit": "\"vendor/bin/wpmedia-phpunit\" unit path=Tests/Unit", @@ -47,8 +63,16 @@ "@test-integration" ], "install-codestandards": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", - "phpcs": "phpcs --basepath=.", - "phpcs-changed": "./bin/phpcs-changed.sh", - "phpcs:fix": "phpcbf" + "phpcs": "\"vendor/bin/phpcs\" .", + "phpcs:fix": "\"vendor/bin/phpcbf\" ", + "phpstan": "\"vendor/bin/phpstan\" analyse", + "post-install-cmd": [ + "\"vendor/bin/mozart\" compose", + "composer dump-autoload" + ], + "post-update-cmd": [ + "\"vendor/bin/mozart\" compose", + "composer dump-autoload" + ] } } diff --git a/wp-content/plugins/wp-rocket/inc/Addon/WebP/AbstractWebp.php b/wp-content/plugins/wp-rocket/inc/Addon/WebP/AbstractWebp.php new file mode 100644 index 000000000..98642a3e6 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/WebP/AbstractWebp.php @@ -0,0 +1,103 @@ +cdn_subscriber = $cdn_subscriber; + } + + /** + * Get a list of active plugins that convert and/or serve webp images. + * + * @since 3.12.6 + * + * @return array An array of Webp_Interface objects. + */ + protected function get_webp_plugins() { + /** + * Add Webp plugins. + * + * @since 3.4 + * + * @param array $webp_plugins An array of Webp_Interface objects. + */ + $webp_plugins = (array) apply_filters( 'rocket_webp_plugins', [] ); + + if ( ! $webp_plugins ) { + // Somebody probably messed up. + return []; + } + + foreach ( $webp_plugins as $plugin_key => $plugin ) { + if ( ! $plugin instanceof Webp_Interface ) { + unset( $webp_plugins[ $plugin_key ] ); + continue; + } + + if ( ! $this->is_plugin_active( $plugin->get_basename() ) ) { + unset( $webp_plugins[ $plugin_key ] ); + } + } + + return $webp_plugins; + } + + /** + * Tell if a plugin is active. + * + * @since 3.12.6 + * + * @param string $plugin_basename A plugin basename. + * @return bool + */ + protected function is_plugin_active( string $plugin_basename ): bool { + if ( doing_action( 'deactivate_' . $plugin_basename ) ) { + return false; + } + + if ( doing_action( 'activate_' . $plugin_basename ) ) { + return true; + } + + return rocket_is_plugin_active( $plugin_basename ); + } + + /** + * Tell if WP Rocket uses a CDN for images. + * + * @since 3.12.6 + * + * @return bool + */ + protected function is_using_cdn(): bool { + // Don't use `$this->options_data->get( 'cdn' )` here, we need an up-to-date value when the CDN option changes. + $use = get_rocket_option( 'cdn', 0 ) && $this->cdn_subscriber->get_cdn_hosts( [], [ 'all', 'images' ] ); + /** + * Filter whether WP Rocket is using a CDN for webp images. + * + * @since 3.4 + * + * @param bool $use True if WP Rocket is using a CDN for webp images. False otherwise. + */ + return (bool) apply_filters( 'rocket_webp_is_using_cdn', $use ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Addon/WebP/AdminSubscriber.php b/wp-content/plugins/wp-rocket/inc/Addon/WebP/AdminSubscriber.php new file mode 100644 index 000000000..4ebc71dc0 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/WebP/AdminSubscriber.php @@ -0,0 +1,214 @@ +options_data = $options_data; + $this->beacon = $beacon; + } + + /** + * {@inheritdoc} + */ + public static function get_subscribed_events() { + return [ + 'rocket_cache_webp_setting_field' => [ + [ 'maybe_disable_setting_field' ], + [ 'webp_section_description' ], + ], + ]; + } + + /** + * Modifies the WebP section description of WP Rocket settings. + * + * @since 3.4 + * + * @param array $cache_webp_field Section description. + * @return array + */ + public function webp_section_description( $cache_webp_field ) { + $webp_beacon = $this->beacon->get_suggest( 'webp' ); + $webp_plugins = $this->get_webp_plugins(); + $serving = []; + $serving_not_compatible = []; + $creating = []; + + if ( $webp_plugins ) { + $is_using_cdn = $this->is_using_cdn(); + + foreach ( $webp_plugins as $plugin ) { + if ( $plugin->is_serving_webp() ) { + if ( $is_using_cdn && ! $plugin->is_serving_webp_compatible_with_cdn() ) { + // Serving WebP using a method not compatible with CDN. + $serving_not_compatible[ $plugin->get_id() ] = $plugin->get_name(); + } else { + // Serving WebP when no CDN or with a method compatible with CDN. + $serving[ $plugin->get_id() ] = $plugin->get_name(); + } + } + if ( $plugin->is_converting_to_webp() ) { + // Generating WebP. + $creating[ $plugin->get_id() ] = $plugin->get_name(); + } + } + } + + if ( $serving ) { + // 5, 8. + $cache_webp_field['description'] = sprintf( + // Translators: %1$s = plugin name(s), %2$s = opening tag, %3$s = closing tag. + esc_html( _n( 'You are using %1$s to serve WebP images so you do not need to enable this option. %2$sMore info%3$s %4$s If you prefer to have WP Rocket serve WebP for you instead, please disable WebP display in %1$s.', 'You are using %1$s to serve WebP images so you do not need to enable this option. %2$sMore info%3$s %4$s If you prefer to have WP Rocket serve WebP for you instead, please disable WebP display in %1$s.', count( $serving ), 'rocket' ) ), + esc_html( wp_sprintf_l( '%l', $serving ) ), + '', + '', + '
' + ); + + return $cache_webp_field; + } + + /** This filter is documented in inc/classes/buffer/class-cache.php */ + if ( apply_filters( 'rocket_disable_webp_cache', false ) ) { + $cache_webp_field['description'] = esc_html__( 'WebP cache is disabled by filter.', 'rocket' ); + + return $cache_webp_field; + } + + if ( $serving_not_compatible ) { + if ( ! $this->options_data->get( 'cache_webp', 0 ) ) { + // 6. + $cache_webp_field['description'] = sprintf( + // Translators: %1$s = plugin name(s), %2$s = opening tag, %3$s = closing tag. + esc_html( _n( 'You are using %1$s to convert images to WebP. If you want WP Rocket to serve them for you, activate this option. %2$sMore info%3$s', 'You are using %1$s to convert images to WebP. If you want WP Rocket to serve them for you, activate this option. %2$sMore info%3$s', count( $serving_not_compatible ), 'rocket' ) ), + esc_html( wp_sprintf_l( '%l', $serving_not_compatible ) ), + '', + '' + ); + + return $cache_webp_field; + } + + // 7. + $cache_webp_field['description'] = sprintf( + // Translators: %1$s = plugin name(s), %2$s = opening tag, %3$s = closing tag. + esc_html( _n( 'You are using %1$s to convert images to WebP. WP Rocket will create separate cache files to serve your WebP images. %2$sMore info%3$s', 'You are using %1$s to convert images to WebP. WP Rocket will create separate cache files to serve your WebP images. %2$sMore info%3$s', count( $serving_not_compatible ), 'rocket' ) ), + esc_html( wp_sprintf_l( '%l', $serving_not_compatible ) ), + '', + '' + ); + + return $cache_webp_field; + } + + if ( $creating ) { + if ( ! $this->options_data->get( 'cache_webp', 0 ) ) { + // 3. + $cache_webp_field['description'] = sprintf( + // Translators: %1$s = plugin name(s), %2$s = opening tag, %3$s = closing tag. + esc_html( _n( 'You are using %1$s to convert images to WebP. If you want WP Rocket to serve them for you, activate this option. %2$sMore info%3$s', 'You are using %1$s to convert images to WebP. If you want WP Rocket to serve them for you, activate this option. %2$sMore info%3$s', count( $creating ), 'rocket' ) ), + esc_html( wp_sprintf_l( '%l', $creating ) ), + '', + '' + ); + + return $cache_webp_field; + } + + // 4. + $cache_webp_field['description'] = sprintf( + // Translators: %1$s = plugin name(s), %2$s = opening tag, %3$s = closing tag. + esc_html( _n( 'You are using %1$s to convert images to WebP. WP Rocket will create separate cache files to serve your WebP images. %2$sMore info%3$s', 'You are using %1$s to convert images to WebP. WP Rocket will create separate cache files to serve your WebP images. %2$sMore info%3$s', count( $creating ), 'rocket' ) ), + esc_html( wp_sprintf_l( '%l', $creating ) ), + '', + '' + ); + + return $cache_webp_field; + } + + if ( ! $this->options_data->get( 'cache_webp', 0 ) ) { + // 1. + if ( rocket_valid_key() && ! \Imagify_Partner::has_imagify_api_key() ) { + $imagify_link = ''; + } else { + // The Imagify page is not displayed. + $imagify_link = ''; + } + + $cache_webp_field['description'] = sprintf( + // Translators: %1$s = opening tag, %2$s = closing tag. + esc_html__( '%5$sWe have not detected any compatible WebP plugin!%6$s%4$s If you don’t already have WebP images on your site consider using %3$sImagify%2$s or another supported plugin. %1$sMore info%2$s %4$s If you are not using WebP do not enable this option.', 'rocket' ), + '', + '', + $imagify_link, + '
', + '', + '' + ); + return $cache_webp_field; + } + + // 2. + $cache_webp_field['description'] = esc_html__( 'WP Rocket will create separate cache files to serve your WebP images.', 'rocket' ); + + return $cache_webp_field; + } + + /** + * Disable 'cache_webp' setting field if another plugin serves WebP. + * + * @since 3.4 + * + * @param array $cache_webp_field Data to be added to the setting field. + * @return array + */ + public function maybe_disable_setting_field( $cache_webp_field ) { + /** This filter is documented in inc/classes/buffer/class-cache.php */ + if ( ! apply_filters( 'rocket_disable_webp_cache', false ) ) { + return $cache_webp_field; + } + + foreach ( [ 'input_attr', 'container_class' ] as $attr ) { + if ( ! isset( $cache_webp_field[ $attr ] ) || ! is_array( $cache_webp_field[ $attr ] ) ) { + $cache_webp_field[ $attr ] = []; + } + } + + $cache_webp_field['input_attr']['disabled'] = 1; + + return $cache_webp_field; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Addon/WebP/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Addon/WebP/Subscriber.php new file mode 100644 index 000000000..701af2065 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Addon/WebP/Subscriber.php @@ -0,0 +1,598 @@ +options_data = $options_data; + $this->options_api = $options_api; + + if ( ! isset( $server ) && ! empty( $_SERVER ) && is_array( $_SERVER ) ) { + $server = $_SERVER; + } + + $this->server = $server && is_array( $server ) ? $server : []; + } + + /** + * {@inheritdoc} + */ + public static function get_subscribed_events() { + return [ + 'rocket_buffer' => [ 'convert_to_webp', 16 ], + 'rocket_disable_webp_cache' => 'maybe_disable_webp_cache', + 'rocket_third_party_webp_change' => 'sync_webp_cache_with_third_party_plugins', + 'rocket_preload_before_preload_url' => 'add_accept_header', + 'rocket_lazyload_youtube_thumbnail_extension' => 'change_youtube_thumbnail', + ]; + } + + /** + * Converts images extension to WebP if the file exists. + * + * @since 3.4 + * + * @param string $html HTML content. + * @return string + */ + public function convert_to_webp( $html ) { + if ( ! $this->options_data->get( 'cache_webp', 0 ) ) { + return $html; + } + + /** This filter is documented in inc/classes/buffer/class-cache.php */ + if ( apply_filters( 'rocket_disable_webp_cache', false ) ) { + return $html; + } + + if ( ! $this->is_browser_webp_compatible() ) { + return $html; + } + + $extensions = $this->get_extensions(); + $attribute_names = $this->get_attribute_names(); + + if ( + empty( $extensions ) + || + empty( $attribute_names ) + ) { + return $html . ''; + } + + $extensions = implode( '|', $extensions ); + $attribute_names = implode( '|', $attribute_names ); + + if ( ! preg_match_all( '@["\'\s](?(?:data-(?:[a-z0-9_-]+-)?)?(?:' . $attribute_names . '))\s*=\s*["\']\s*(?(?:https?:/)?/[^"\']+\.(?:' . $extensions . ')[^"\']*?)\s*["\']@is', $html, $attributes, PREG_SET_ORDER ) ) { + return $html . ''; + } + + if ( ! isset( $this->filesystem ) ) { + $this->filesystem = \rocket_direct_filesystem(); + } + + $has_webp = false; + + foreach ( $attributes as $attribute ) { + if ( preg_match( '@srcset$@i', strtolower( $attribute['name'] ) ) ) { + // This is a srcset attribute, with probably multiple URLs. + $new_value = $this->srcset_to_webp( $attribute['value'], $extensions ); + } else { + // A single URL attibute. + $new_value = $this->url_to_webp( $attribute['value'], $extensions ); + } + + if ( ! $new_value ) { + // No webp here. + continue; + } + + // Replace in content. + $has_webp = true; + $new_attr = preg_replace( '@' . $attribute['name'] . '\s*=\s*["\'][^"\']+["\']@s', $attribute['name'] . '="' . $new_value . '"', $attribute[0] ); + $html = str_replace( $attribute[0], $new_attr, $html ); + } + + $has_webp = apply_filters_deprecated( 'rocket_page_has_webp_files', [ $has_webp, $html ], '3.12.6', 'rocket_page_has_webp_files' ); + + /** + * Tell if the page contains webp files. + * + * @since 3.4 + * + * @param bool $has_webp True if the page contains webp files. False otherwise. + * @param string $html The page’s html contents. + */ + + $has_webp = apply_filters( 'rocket_page_has_webp_files', $has_webp, $html ); + + if ( $has_webp ) { + return $html . ''; + } + + return $html . ''; + } + + /** + * Disable the WebP cache if a WebP plugin is in use. + * + * @since 3.4 + * + * @param bool $disable_webp_cache True to disable WebP cache. False otherwise (default). + * + * @return bool + */ + public function maybe_disable_webp_cache( $disable_webp_cache ): bool { + return $disable_webp_cache || ! empty( $this->get_plugins_serving_webp() ); + } + + /** + * When a 3rd party plugin enables or disables its webp feature, disable or enable WPR feature accordingly. + * + * @since 3.4 + */ + public function sync_webp_cache_with_third_party_plugins() { + if ( + $this->options_data->get( 'cache_webp', 0 ) + && + $this->get_plugins_serving_webp() + ) { + // Disable the cache webp option. + $this->options_data->set( 'cache_webp', 0 ); + $this->options_api->set( 'settings', $this->options_data->get_options() ); + } + + rocket_generate_config_file(); + } + + /** + * Add WebP to the HTTP_ACCEPT headers on preload request when the WebP option is active + * + * @param array $requests Requests to make. + * @return array + */ + public function add_accept_header( $requests ) { + if ( ! is_array( $requests ) || ! $this->options_data->get( 'cache_webp', 0 ) ) { + return $requests; + } + + return array_map( + function ( $request ) { + $request['headers']['headers']['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'; + $request['headers']['headers']['HTTP_ACCEPT'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'; + return $request; + }, + $requests + ); + } + + /** + * Checks if the browser is WebP compatible + * + * @since 3.12.6 + * + * @return bool + */ + private function is_browser_webp_compatible(): bool { + // Only to supporting browsers. + $http_accept = isset( $this->server['HTTP_ACCEPT'] ) ? $this->server['HTTP_ACCEPT'] : ''; + + if ( + empty( $http_accept ) + && + function_exists( 'apache_request_headers' ) + ) { + $headers = apache_request_headers(); + $http_accept = isset( $headers['Accept'] ) ? $headers['Accept'] : ''; + } + + if ( + ! empty( $http_accept ) + && + false !== strpos( $http_accept, 'webp' ) + ) { + return true; + } + + return $this->is_user_agent_compatible(); + } + + /** + * Check the User Agent if the Accept headers is missing the WebP info + * + * @since 3.12.6 + * + * @return bool + */ + private function is_user_agent_compatible(): bool { + $user_agent = isset( $this->server['HTTP_USER_AGENT'] ) ? $this->server['HTTP_USER_AGENT'] : ''; + + if ( empty( $user_agent ) ) { + return false; + } + + if ( preg_match( '#Firefox/(?[0-9]{2,})#i', $user_agent, $matches ) ) { + if ( 66 >= (int) $matches['version'] ) { + return false; + } + } + + if ( preg_match( '#(?:iPad|iPhone)(.*)Version/(?[0-9]{2,})#i', $user_agent, $matches ) ) { + if ( 14 > (int) $matches['version'] ) { + return false; + } + + return true; + } + + if ( preg_match( '#Version/(?[0-9]{2,})(?:.*)Safari#i', $user_agent, $matches ) ) { + if ( 16 > (int) $matches['version'] ) { + return false; + } + } + + return true; + } + + /** + * Get the list of file extensions that may have a webp version. + * + * @since 3.4 + * + * @return array + */ + private function get_extensions() { + $extensions = [ 'jpg', 'jpeg', 'jpe', 'png', 'gif' ]; + + /** + * Filter the list of file extensions that may have a webp version. + * + * @since 3.4 + * + * @param array $extensions An array of file extensions. + */ + $extensions = apply_filters( 'rocket_file_extensions_for_webp', $extensions ); + $extensions = array_filter( + (array) $extensions, + function ( $extension ) { + return $extension && is_string( $extension ); + } + ); + + return array_unique( $extensions ); + } + + /** + * Get the names of the HTML attributes where WP Rocket must search for image files. + * + * @since 3.4 + * + * @return array + */ + private function get_attribute_names() { + $attributes = [ 'href', 'src', 'srcset', 'data-large_image', 'data-thumb' ]; + + /** + * Filter the names of the HTML attributes where WP Rocket must search for image files. + * Don't prepend new names with `data-`, WPR will do it. For example if you want to add `data-foo-bar`, you only need to add `foo-bar` or `bar` to the list. + * + * @since 3.4 + * + * @param array $attributes An array of HTML attribute names. + */ + $attributes = apply_filters( 'rocket_attributes_for_webp', $attributes ); + $attributes = array_filter( + (array) $attributes, + function ( $attributes ) { + return $attributes && is_string( $attributes ); + } + ); + + return array_unique( $attributes ); + } + + /** + * Convert a URL to an absolute path. + * + * @since 3.4 + * + * @param string $url URL to convert. + * @return string|bool + */ + private function url_to_path( $url ) { + static $hosts, $site_host, $subdir_levels; + + $url_host = wp_parse_url( $url, PHP_URL_HOST ); + + // Relative path. + if ( null === $url_host ) { + if ( ! isset( $subdir_levels ) ) { + $subdir_levels = substr_count( preg_replace( '@^https?://@', '', site_url() ), '/' ); + } + + if ( $subdir_levels ) { + $url = ltrim( $url, '/' ); + $url = explode( '/', $url ); + array_splice( $url, 0, $subdir_levels ); + $url = implode( '/', $url ); + } + + $url = site_url( $url ); + } + + // CDN. + if ( ! isset( $hosts ) ) { + $hosts = $this->cdn_subscriber->get_cdn_hosts( [], [ 'all', 'images' ] ); + $hosts = array_flip( $hosts ); + } + + if ( isset( $hosts[ $url_host ] ) ) { + if ( ! isset( $site_host ) ) { + $site_host = wp_parse_url( site_url( '/' ), PHP_URL_HOST ); + } + if ( $site_host ) { + $url = preg_replace( '@^(https?://)' . $url_host . '/@', '$1' . $site_host . '/', $url ); + } + } + + // URL to path. + $url = preg_replace( '@^https?:@', '', $url ); + $paths = $this->get_url_to_path_associations(); + + if ( ! $paths ) { + // Uh? + return false; + } + + foreach ( $paths as $asso_url => $asso_path ) { + if ( 0 === strpos( $url, $asso_url ) ) { + $file = str_replace( $asso_url, $asso_path, $url ); + break; + } + } + + if ( empty( $file ) ) { + return false; + } + + /** This filter is documented in inc/functions/formatting.php. */ + return (string) apply_filters( 'rocket_url_to_path', $file, $url ); + } + + /** + * Add a webp extension to a URL. + * + * @since 3.4 + * + * @param string $url A URL (I see you're very surprised). + * @param string $extensions Allowed image extensions. + * @return string|bool The same URL with a webp extension if the file exists. False if the webp image doesn't exist. + */ + private function url_to_webp( $url, $extensions ) { + if ( ! preg_match( '@^(?.+\.(?' . $extensions . '))(?(?:\?.*)?)$@i', $url, $src_url ) ) { + // Probably something like "image.jpg.webp". + return false; + } + + $src_path = $this->url_to_path( $src_url['src'] ); + + if ( empty( $src_path ) ) { + return false; + } + + $src_path_webp = preg_replace( '@\.' . $src_url['extension'] . '$@', '.webp', $src_path ); + + if ( $this->filesystem->exists( $src_path_webp ) ) { + // File name: image.jpg => image.webp. + return preg_replace( '@\.' . $src_url['extension'] . '$@', '.webp', $src_url['src'] ) . $src_url['query']; + } + + if ( $this->filesystem->exists( $src_path . '.webp' ) ) { + // File name: image.jpg => image.jpg.webp. + return $src_url['src'] . '.webp' . $src_url['query']; + } + + return false; + } + + /** + * Add webp extension to URLs in a srcset attribute. + * + * @since 3.4 + * + * @param array|string $srcset_values Value of a srcset attribute. + * @param string $extensions Allowed image extensions. + * @return string|bool An array similar to $srcset_values, with webp extensions when the files exist. False if no images have webp versions. + */ + private function srcset_to_webp( $srcset_values, $extensions ) { + if ( ! $srcset_values ) { + return false; + } + + if ( ! is_array( $srcset_values ) ) { + $srcset_values = explode( ',', $srcset_values ); + } + + $has_webp = false; + + foreach ( $srcset_values as $i => $srcset_value ) { + $srcset_value = preg_split( '/\s+/', trim( $srcset_value ) ); + + if ( count( $srcset_value ) > 2 ) { + // Not a good idea to have space characters in file name. + $descriptor = array_pop( $srcset_value ); + $srcset_value = [ + 'url' => implode( ' ', $srcset_value ), + 'descriptor' => $descriptor, + ]; + } else { + $srcset_value = [ + 'url' => $srcset_value[0], + 'descriptor' => ! empty( $srcset_value[1] ) ? $srcset_value[1] : '1x', + ]; + } + + $url_webp = $this->url_to_webp( $srcset_value['url'], $extensions ); + + if ( ! $url_webp ) { + $srcset_values[ $i ] = implode( ' ', $srcset_value ); + continue; + } + + $srcset_values[ $i ] = $url_webp . ' ' . $srcset_value['descriptor']; + $has_webp = true; + } + + if ( ! $has_webp ) { + return false; + } + + return implode( ',', $srcset_values ); + } + + /** + * Get a list of URL/path associations. + * URLs are schema-less, starting by a double slash. + * + * @since 3.4 + * + * @return array A list of URLs as keys and paths as values. + */ + private function get_url_to_path_associations() { + static $list; + + if ( isset( $list ) ) { + return $list; + } + + $content_url = preg_replace( '@^https?:@', '', content_url( '/' ) ); + $content_dir = trailingslashit( rocket_get_constant( 'WP_CONTENT_DIR' ) ); + $list = [ $content_url => $content_dir ]; + + $upload = wp_upload_dir(); + $upload_dir = trailingslashit( $upload['basedir'] ); + + if ( strpos( $upload_dir, $content_dir ) === false ) { + $upload_url = preg_replace( '@^https?:@', '', trailingslashit( $upload['baseurl'] ) ); + $list[ $upload_url ] = $upload_dir; + } + + /** + * Filter the list of URL/path associations. + * The URLs with the most levels must come first. + * + * @since 3.4 + * + * @param array $list The list of URL/path associations. URLs are schema-less, starting by a double slash. + */ + $list = apply_filters( 'rocket_url_to_path_associations', $list ); + $list = array_filter( + $list, + function ( $path, $url ) { + return $path && $url && is_string( $path ) && is_string( $url ); + }, + ARRAY_FILTER_USE_BOTH + ); + + if ( $list ) { + $list = array_unique( $list ); + } + + return $list; + } + + /** + * Get a list of plugins that serve webp images on frontend. + * If the CDN is used, this won't list plugins that use a technique not compatible with CDN. + * + * @since 3.4 + * + * @return array The WebP plugin names. + */ + private function get_plugins_serving_webp() { + $webp_plugins = $this->get_webp_plugins(); + + if ( ! $webp_plugins ) { + // Somebody probably messed up. + return []; + } + + $checks = []; + $is_using_cdn = $this->is_using_cdn(); + + foreach ( $webp_plugins as $plugin ) { + if ( $is_using_cdn && $plugin->is_serving_webp_compatible_with_cdn() ) { + $checks[ $plugin->get_id() ] = $plugin->get_name(); + } elseif ( ! $is_using_cdn && $plugin->is_serving_webp() ) { + $checks[ $plugin->get_id() ] = $plugin->get_name(); + } + } + + return $checks; + } + + /** + * Change Youtube thumbnail extension. + * + * @param string $extension extension from the thumbnail. + * + * @return string + */ + public function change_youtube_thumbnail( $extension ) { + if ( ! $this->options_data->get( 'cache_webp', 0 ) ) { + return $extension; + } + return 'webp'; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/action-scheduler.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/action-scheduler.php new file mode 100644 index 000000000..b950a70b2 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/action-scheduler.php @@ -0,0 +1,65 @@ +. + * + * @package ActionScheduler + */ + +if ( ! function_exists( 'action_scheduler_register_3_dot_5_dot_4' ) && function_exists( 'add_action' ) ) { // WRCS: DEFINED_VERSION. + + if ( ! class_exists( 'ActionScheduler_Versions', false ) ) { + require_once __DIR__ . '/classes/ActionScheduler_Versions.php'; + add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 ); + } + + add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_5_dot_4', 0, 0 ); // WRCS: DEFINED_VERSION. + + /** + * Registers this version of Action Scheduler. + */ + function action_scheduler_register_3_dot_5_dot_4() { // WRCS: DEFINED_VERSION. + $versions = ActionScheduler_Versions::instance(); + $versions->register( '3.5.4', 'action_scheduler_initialize_3_dot_5_dot_4' ); // WRCS: DEFINED_VERSION. + } + + /** + * Initializes this version of Action Scheduler. + */ + function action_scheduler_initialize_3_dot_5_dot_4() { // WRCS: DEFINED_VERSION. + // A final safety check is required even here, because historic versions of Action Scheduler + // followed a different pattern (in some unusual cases, we could reach this point and the + // ActionScheduler class is already defined—so we need to guard against that). + if ( ! class_exists( 'ActionScheduler', false ) ) { + require_once __DIR__ . '/classes/abstracts/ActionScheduler.php'; + ActionScheduler::init( __FILE__ ); + } + } + + // Support usage in themes - load this version if no plugin has loaded a version yet. + if ( did_action( 'plugins_loaded' ) && ! doing_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler', false ) ) { + action_scheduler_initialize_3_dot_5_dot_4(); // WRCS: DEFINED_VERSION. + do_action( 'action_scheduler_pre_theme_init' ); + ActionScheduler_Versions::initialize_latest_version(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/changelog.txt b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/changelog.txt new file mode 100644 index 000000000..69aef1ff7 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/changelog.txt @@ -0,0 +1,81 @@ +*** Changelog *** + += 3.5.4 - 2023-01-17 = +* Add pre filters during action registration. +* Async scheduling. +* Calculate timeouts based on total actions. +* Correctly order the parameters for `ActionScheduler_ActionFactory`'s calls to `single_unique`. +* Fetch action in memory first before releasing claim to avoid deadlock. +* PHP 8.2: declare property to fix creation of dynamic property warning. +* PHP 8.2: fix "Using ${var} in strings is deprecated, use {$var} instead". +* Prevent `undefined variable` warning for `$num_pastdue_actions`. + += 3.5.3 - 2022-11-09 = +* Query actions with partial match. + += 3.5.2 - 2022-09-16 = +* Fix - erroneous 3.5.1 release. + += 3.5.1 - 2022-09-13 = +* Maintenance on A/S docs. +* fix: PHP 8.2 deprecated notice. + += 3.5.0 - 2022-08-25 = +* Add - The active view link within the "Tools > Scheduled Actions" screen is now clickable. +* Add - A warning when there are past-due actions. +* Enhancement - Added the ability to schedule unique actions via an atomic operation. +* Enhancement - Improvements to cache invalidation when processing batches (when running on WordPress 6.0+). +* Enhancement - If a recurring action is found to be consistently failing, it will stop being rescheduled. +* Enhancement - Adds a new "Past Due" view to the scheduled actions list table. + += 3.4.2 - 2022-06-08 = +* Fix - Change the include for better linting. +* Fix - update: Added Action scheduler completed action hook. + += 3.4.1 - 2022-05-24 = +* Fix - Change the include for better linting. +* Fix - Fix the documented return type. + += 3.4.0 - 2021-10-29 = +* Enhancement - Number of items per page can now be set for the Scheduled Actions view (props @ovidiul). #771 +* Fix - Do not lower the max_execution_time if it is already set to 0 (unlimited) (props @barryhughes). #755 +* Fix - Avoid triggering autoloaders during the version resolution process (props @olegabr). #731 & #776 +* Dev - ActionScheduler_wcSystemStatus PHPCS fixes (props @ovidiul). #761 +* Dev - ActionScheduler_DBLogger.php PHPCS fixes (props @ovidiul). #768 +* Dev - Fixed phpcs for ActionScheduler_Schedule_Deprecated (props @ovidiul). #762 +* Dev - Improve actions table indicies (props @glagonikas). #774 & #777 +* Dev - PHPCS fixes for ActionScheduler_DBStore.php (props @ovidiul). #769 & #778 +* Dev - PHPCS Fixes for ActionScheduler_Abstract_ListTable (props @ovidiul). #763 & #779 +* Dev - Adds new filter action_scheduler_claim_actions_order_by to allow tuning of the claim query (props @glagonikas). #773 +* Dev - PHPCS fixes for ActionScheduler_WpPostStore class (props @ovidiul). #780 + += 3.3.0 - 2021-09-15 = +* Enhancement - Adds as_has_scheduled_action() to provide a performant way to test for existing actions. #645 +* Fix - Improves compatibility with environments where NO_ZERO_DATE is enabled. #519 +* Fix - Adds safety checks to guard against errors when our database tables cannot be created. #645 +* Dev - Now supports queries that use multiple statuses. #649 +* Dev - Minimum requirements for WordPress and PHP bumped (to 5.2 and 5.6 respectively). #723 + += 3.2.1 - 2021-06-21 = +* Fix - Add extra safety/account for different versions of AS and different loading patterns. #714 +* Fix - Handle hidden columns (Tools → Scheduled Actions) | #600. + += 3.2.0 - 2021-06-03 = +* Fix - Add "no ordering" option to as_next_scheduled_action(). +* Fix - Add secondary scheduled date checks when claiming actions (DBStore) | #634. +* Fix - Add secondary scheduled date checks when claiming actions (wpPostStore) | #634. +* Fix - Adds a new index to the action table, reducing the potential for deadlocks (props: @glagonikas). +* Fix - Fix unit tests infrastructure and adapt tests to PHP 8. +* Fix - Identify in-use data store. +* Fix - Improve test_migration_is_scheduled. +* Fix - PHP notice on list table. +* Fix - Speed up clean up and batch selects. +* Fix - Update pending dependencies. +* Fix - [PHP 8.0] Only pass action arg values through to do_action_ref_array(). +* Fix - [PHP 8] Set the PHP version to 7.1 in composer.json for PHP 8 compatibility. +* Fix - add is_initialized() to docs. +* Fix - fix file permissions. +* Fix - fixes #664 by replacing __ with esc_html__. + += 3.1.6 - 2020-05-12 = +* Change log starts. diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_ActionClaim.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_ActionClaim.php new file mode 100644 index 000000000..8b5681620 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_ActionClaim.php @@ -0,0 +1,23 @@ +id = $id; + $this->action_ids = $action_ids; + } + + public function get_id() { + return $this->id; + } + + public function get_actions() { + return $this->action_ids; + } +} + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_ActionFactory.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_ActionFactory.php new file mode 100644 index 000000000..8e2e65018 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_ActionFactory.php @@ -0,0 +1,259 @@ +get_date() ); + } + break; + default: + $action_class = 'ActionScheduler_FinishedAction'; + break; + } + + $action_class = apply_filters( 'action_scheduler_stored_action_class', $action_class, $status, $hook, $args, $schedule, $group ); + + $action = new $action_class( $hook, $args, $schedule, $group ); + + /** + * Allow 3rd party code to change the instantiated action for a given hook, args, schedule and group. + * + * @param ActionScheduler_Action $action The instantiated action. + * @param string $hook The instantiated action's hook. + * @param array $args The instantiated action's args. + * @param ActionScheduler_Schedule $schedule The instantiated action's schedule. + * @param string $group The instantiated action's group. + */ + return apply_filters( 'action_scheduler_stored_action_instance', $action, $hook, $args, $schedule, $group ); + } + + /** + * Enqueue an action to run one time, as soon as possible (rather a specific scheduled time). + * + * This method creates a new action using the NullSchedule. In practice, this results in an action scheduled to + * execute "now". Therefore, it will generally run as soon as possible but is not prioritized ahead of other actions + * that are already past-due. + * + * @param string $hook The hook to trigger when this action runs. + * @param array $args Args to pass when the hook is triggered. + * @param string $group A group to put the action in. + * + * @return int The ID of the stored action. + */ + public function async( $hook, $args = array(), $group = '' ) { + return $this->async_unique( $hook, $args, $group, false ); + } + + /** + * Same as async, but also supports $unique param. + * + * @param string $hook The hook to trigger when this action runs. + * @param array $args Args to pass when the hook is triggered. + * @param string $group A group to put the action in. + * @param bool $unique Whether to ensure the action is unique. + * + * @return int The ID of the stored action. + */ + public function async_unique( $hook, $args = array(), $group = '', $unique = true ) { + $schedule = new ActionScheduler_NullSchedule(); + $action = new ActionScheduler_Action( $hook, $args, $schedule, $group ); + return $unique ? $this->store_unique_action( $action, $unique ) : $this->store( $action ); + } + + /** + * Create single action. + * + * @param string $hook The hook to trigger when this action runs. + * @param array $args Args to pass when the hook is triggered. + * @param int $when Unix timestamp when the action will run. + * @param string $group A group to put the action in. + * + * @return int The ID of the stored action. + */ + public function single( $hook, $args = array(), $when = null, $group = '' ) { + return $this->single_unique( $hook, $args, $when, $group, false ); + } + + /** + * Create single action only if there is no pending or running action with same name and params. + * + * @param string $hook The hook to trigger when this action runs. + * @param array $args Args to pass when the hook is triggered. + * @param int $when Unix timestamp when the action will run. + * @param string $group A group to put the action in. + * @param bool $unique Whether action scheduled should be unique. + * + * @return int The ID of the stored action. + */ + public function single_unique( $hook, $args = array(), $when = null, $group = '', $unique = true ) { + $date = as_get_datetime_object( $when ); + $schedule = new ActionScheduler_SimpleSchedule( $date ); + $action = new ActionScheduler_Action( $hook, $args, $schedule, $group ); + return $unique ? $this->store_unique_action( $action ) : $this->store( $action ); + } + + /** + * Create the first instance of an action recurring on a given interval. + * + * @param string $hook The hook to trigger when this action runs. + * @param array $args Args to pass when the hook is triggered. + * @param int $first Unix timestamp for the first run. + * @param int $interval Seconds between runs. + * @param string $group A group to put the action in. + * + * @return int The ID of the stored action. + */ + public function recurring( $hook, $args = array(), $first = null, $interval = null, $group = '' ) { + return $this->recurring_unique( $hook, $args, $first, $interval, $group, false ); + } + + /** + * Create the first instance of an action recurring on a given interval only if there is no pending or running action with same name and params. + * + * @param string $hook The hook to trigger when this action runs. + * @param array $args Args to pass when the hook is triggered. + * @param int $first Unix timestamp for the first run. + * @param int $interval Seconds between runs. + * @param string $group A group to put the action in. + * @param bool $unique Whether action scheduled should be unique. + * + * @return int The ID of the stored action. + */ + public function recurring_unique( $hook, $args = array(), $first = null, $interval = null, $group = '', $unique = true ) { + if ( empty( $interval ) ) { + return $this->single_unique( $hook, $args, $first, $group, $unique ); + } + $date = as_get_datetime_object( $first ); + $schedule = new ActionScheduler_IntervalSchedule( $date, $interval ); + $action = new ActionScheduler_Action( $hook, $args, $schedule, $group ); + return $unique ? $this->store_unique_action( $action ) : $this->store( $action ); + } + + /** + * Create the first instance of an action recurring on a Cron schedule. + * + * @param string $hook The hook to trigger when this action runs. + * @param array $args Args to pass when the hook is triggered. + * @param int $base_timestamp The first instance of the action will be scheduled + * to run at a time calculated after this timestamp matching the cron + * expression. This can be used to delay the first instance of the action. + * @param int $schedule A cron definition string. + * @param string $group A group to put the action in. + * + * @return int The ID of the stored action. + */ + public function cron( $hook, $args = array(), $base_timestamp = null, $schedule = null, $group = '' ) { + return $this->cron_unique( $hook, $args, $base_timestamp, $schedule, $group, false ); + } + + + /** + * Create the first instance of an action recurring on a Cron schedule only if there is no pending or running action with same name and params. + * + * @param string $hook The hook to trigger when this action runs. + * @param array $args Args to pass when the hook is triggered. + * @param int $base_timestamp The first instance of the action will be scheduled + * to run at a time calculated after this timestamp matching the cron + * expression. This can be used to delay the first instance of the action. + * @param int $schedule A cron definition string. + * @param string $group A group to put the action in. + * @param bool $unique Whether action scheduled should be unique. + * + * @return int The ID of the stored action. + **/ + public function cron_unique( $hook, $args = array(), $base_timestamp = null, $schedule = null, $group = '', $unique = true ) { + if ( empty( $schedule ) ) { + return $this->single_unique( $hook, $args, $base_timestamp, $group, $unique ); + } + $date = as_get_datetime_object( $base_timestamp ); + $cron = CronExpression::factory( $schedule ); + $schedule = new ActionScheduler_CronSchedule( $date, $cron ); + $action = new ActionScheduler_Action( $hook, $args, $schedule, $group ); + return $unique ? $this->store_unique_action( $action ) : $this->store( $action ); + } + + /** + * Create a successive instance of a recurring or cron action. + * + * Importantly, the action will be rescheduled to run based on the current date/time. + * That means when the action is scheduled to run in the past, the next scheduled date + * will be pushed forward. For example, if a recurring action set to run every hour + * was scheduled to run 5 seconds ago, it will be next scheduled for 1 hour in the + * future, which is 1 hour and 5 seconds from when it was last scheduled to run. + * + * Alternatively, if the action is scheduled to run in the future, and is run early, + * likely via manual intervention, then its schedule will change based on the time now. + * For example, if a recurring action set to run every day, and is run 12 hours early, + * it will run again in 24 hours, not 36 hours. + * + * This slippage is less of an issue with Cron actions, as the specific run time can + * be set for them to run, e.g. 1am each day. In those cases, and entire period would + * need to be missed before there was any change is scheduled, e.g. in the case of an + * action scheduled for 1am each day, the action would need to run an entire day late. + * + * @param ActionScheduler_Action $action The existing action. + * + * @return string The ID of the stored action + * @throws InvalidArgumentException If $action is not a recurring action. + */ + public function repeat( $action ) { + $schedule = $action->get_schedule(); + $next = $schedule->get_next( as_get_datetime_object() ); + + if ( is_null( $next ) || ! $schedule->is_recurring() ) { + throw new InvalidArgumentException( __( 'Invalid action - must be a recurring action.', 'action-scheduler' ) ); + } + + $schedule_class = get_class( $schedule ); + $new_schedule = new $schedule( $next, $schedule->get_recurrence(), $schedule->get_first_date() ); + $new_action = new ActionScheduler_Action( $action->get_hook(), $action->get_args(), $new_schedule, $action->get_group() ); + return $this->store( $new_action ); + } + + /** + * Save action to database. + * + * @param ActionScheduler_Action $action Action object to save. + * + * @return int The ID of the stored action + */ + protected function store( ActionScheduler_Action $action ) { + $store = ActionScheduler_Store::instance(); + return $store->save_action( $action ); + } + + /** + * Store action if it's unique. + * + * @param ActionScheduler_Action $action Action object to store. + * + * @return int ID of the created action. Will be 0 if action was not created. + */ + protected function store_unique_action( ActionScheduler_Action $action ) { + $store = ActionScheduler_Store::instance(); + return method_exists( $store, 'save_unique_action' ) ? + $store->save_unique_action( $action ) : $store->save_action( $action ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_AdminView.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_AdminView.php new file mode 100644 index 000000000..b747b0a1b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_AdminView.php @@ -0,0 +1,252 @@ +render(); + } + + /** + * Registers action-scheduler into WooCommerce > System status. + * + * @param array $tabs An associative array of tab key => label. + * @return array $tabs An associative array of tab key => label, including Action Scheduler's tabs + */ + public function register_system_status_tab( array $tabs ) { + $tabs['action-scheduler'] = __( 'Scheduled Actions', 'action-scheduler' ); + + return $tabs; + } + + /** + * Include Action Scheduler's administration under the Tools menu. + * + * A menu under the Tools menu is important for backward compatibility (as that's + * where it started), and also provides more convenient access than the WooCommerce + * System Status page, and for sites where WooCommerce isn't active. + */ + public function register_menu() { + $hook_suffix = add_submenu_page( + 'tools.php', + __( 'Scheduled Actions', 'action-scheduler' ), + __( 'Scheduled Actions', 'action-scheduler' ), + 'manage_options', + 'action-scheduler', + array( $this, 'render_admin_ui' ) + ); + add_action( 'load-' . $hook_suffix , array( $this, 'process_admin_ui' ) ); + } + + /** + * Triggers processing of any pending actions. + */ + public function process_admin_ui() { + $this->get_list_table(); + } + + /** + * Renders the Admin UI + */ + public function render_admin_ui() { + $table = $this->get_list_table(); + $table->display_page(); + } + + /** + * Get the admin UI object and process any requested actions. + * + * @return ActionScheduler_ListTable + */ + protected function get_list_table() { + if ( null === $this->list_table ) { + $this->list_table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() ); + $this->list_table->process_actions(); + } + + return $this->list_table; + } + + /** + * Action: admin_notices + * + * Maybe check past-due actions, and print notice. + * + * @uses $this->check_pastdue_actions() + */ + public function maybe_check_pastdue_actions() { + + # Filter to prevent checking actions (ex: inappropriate user). + if ( ! apply_filters( 'action_scheduler_check_pastdue_actions', current_user_can( 'manage_options' ) ) ) { + return; + } + + # Get last check transient. + $last_check = get_transient( 'action_scheduler_last_pastdue_actions_check' ); + + # If transient exists, we're within interval, so bail. + if ( ! empty( $last_check ) ) { + return; + } + + # Perform the check. + $this->check_pastdue_actions(); + } + + /** + * Check past-due actions, and print notice. + * + * @todo update $link_url to "Past-due" filter when released (see issue #510, PR #511) + */ + protected function check_pastdue_actions() { + + # Set thresholds. + $threshold_seconds = ( int ) apply_filters( 'action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS ); + $threshhold_min = ( int ) apply_filters( 'action_scheduler_pastdue_actions_min', 1 ); + + // Set fallback value for past-due actions count. + $num_pastdue_actions = 0; + + // Allow third-parties to preempt the default check logic. + $check = apply_filters( 'action_scheduler_pastdue_actions_check_pre', null ); + + // If no third-party preempted and there are no past-due actions, return early. + if ( ! is_null( $check ) ) { + return; + } + + # Scheduled actions query arguments. + $query_args = array( + 'date' => as_get_datetime_object( time() - $threshold_seconds ), + 'status' => ActionScheduler_Store::STATUS_PENDING, + 'per_page' => $threshhold_min, + ); + + # If no third-party preempted, run default check. + if ( is_null( $check ) ) { + $store = ActionScheduler_Store::instance(); + $num_pastdue_actions = ( int ) $store->query_actions( $query_args, 'count' ); + + # Check if past-due actions count is greater than or equal to threshold. + $check = ( $num_pastdue_actions >= $threshhold_min ); + $check = ( bool ) apply_filters( 'action_scheduler_pastdue_actions_check', $check, $num_pastdue_actions, $threshold_seconds, $threshhold_min ); + } + + # If check failed, set transient and abort. + if ( ! boolval( $check ) ) { + $interval = apply_filters( 'action_scheduler_pastdue_actions_check_interval', round( $threshold_seconds / 4 ), $threshold_seconds ); + set_transient( 'action_scheduler_last_pastdue_actions_check', time(), $interval ); + + return; + } + + $actions_url = add_query_arg( array( + 'page' => 'action-scheduler', + 'status' => 'past-due', + 'order' => 'asc', + ), admin_url( 'tools.php' ) ); + + # Print notice. + echo '

'; + printf( + _n( + // translators: 1) is the number of affected actions, 2) is a link to an admin screen. + 'Action Scheduler: %1$d past-due action found; something may be wrong. Read documentation »', + 'Action Scheduler: %1$d past-due actions found; something may be wrong. Read documentation »', + $num_pastdue_actions, + 'action-scheduler' + ), + $num_pastdue_actions, + esc_attr( esc_url( $actions_url ) ) + ); + echo '

'; + + # Facilitate third-parties to evaluate and print notices. + do_action( 'action_scheduler_pastdue_actions_extra_notices', $query_args ); + } + + /** + * Provide more information about the screen and its data in the help tab. + */ + public function add_help_tabs() { + $screen = get_current_screen(); + + if ( ! $screen || self::$screen_id != $screen->id ) { + return; + } + + $as_version = ActionScheduler_Versions::instance()->latest_version(); + $screen->add_help_tab( + array( + 'id' => 'action_scheduler_about', + 'title' => __( 'About', 'action-scheduler' ), + 'content' => + '

' . sprintf( __( 'About Action Scheduler %s', 'action-scheduler' ), $as_version ) . '

' . + '

' . + __( 'Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'action-scheduler' ) . + '

', + ) + ); + + $screen->add_help_tab( + array( + 'id' => 'action_scheduler_columns', + 'title' => __( 'Columns', 'action-scheduler' ), + 'content' => + '

' . __( 'Scheduled Action Columns', 'action-scheduler' ) . '

' . + '
    ' . + sprintf( '
  • %1$s: %2$s
  • ', __( 'Hook', 'action-scheduler' ), __( 'Name of the action hook that will be triggered.', 'action-scheduler' ) ) . + sprintf( '
  • %1$s: %2$s
  • ', __( 'Status', 'action-scheduler' ), __( 'Action statuses are Pending, Complete, Canceled, Failed', 'action-scheduler' ) ) . + sprintf( '
  • %1$s: %2$s
  • ', __( 'Arguments', 'action-scheduler' ), __( 'Optional data array passed to the action hook.', 'action-scheduler' ) ) . + sprintf( '
  • %1$s: %2$s
  • ', __( 'Group', 'action-scheduler' ), __( 'Optional action group.', 'action-scheduler' ) ) . + sprintf( '
  • %1$s: %2$s
  • ', __( 'Recurrence', 'action-scheduler' ), __( 'The action\'s schedule frequency.', 'action-scheduler' ) ) . + sprintf( '
  • %1$s: %2$s
  • ', __( 'Scheduled', 'action-scheduler' ), __( 'The date/time the action is/was scheduled to run.', 'action-scheduler' ) ) . + sprintf( '
  • %1$s: %2$s
  • ', __( 'Log', 'action-scheduler' ), __( 'Activity log for the action.', 'action-scheduler' ) ) . + '
', + ) + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php new file mode 100644 index 000000000..57706a24c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php @@ -0,0 +1,97 @@ +store = $store; + } + + /** + * Handle async requests + * + * Run a queue, and maybe dispatch another async request to run another queue + * if there are still pending actions after completing a queue in this request. + */ + protected function handle() { + do_action( 'action_scheduler_run_queue', 'Async Request' ); // run a queue in the same way as WP Cron, but declare the Async Request context + + $sleep_seconds = $this->get_sleep_seconds(); + + if ( $sleep_seconds ) { + sleep( $sleep_seconds ); + } + + $this->maybe_dispatch(); + } + + /** + * If the async request runner is needed and allowed to run, dispatch a request. + */ + public function maybe_dispatch() { + if ( ! $this->allow() ) { + return; + } + + $this->dispatch(); + ActionScheduler_QueueRunner::instance()->unhook_dispatch_async_request(); + } + + /** + * Only allow async requests when needed. + * + * Also allow 3rd party code to disable running actions via async requests. + */ + protected function allow() { + + if ( ! has_action( 'action_scheduler_run_queue' ) || ActionScheduler::runner()->has_maximum_concurrent_batches() || ! $this->store->has_pending_actions_due() ) { + $allow = false; + } else { + $allow = true; + } + + return apply_filters( 'action_scheduler_allow_async_request_runner', $allow ); + } + + /** + * Chaining async requests can crash MySQL. A brief sleep call in PHP prevents that. + */ + protected function get_sleep_seconds() { + return apply_filters( 'action_scheduler_async_request_sleep_seconds', 5, $this ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Compatibility.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Compatibility.php new file mode 100644 index 000000000..85e0ed9da --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Compatibility.php @@ -0,0 +1,109 @@ + $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) { + if ( false !== @ini_set( 'memory_limit', $filtered_limit ) ) { + return $filtered_limit; + } else { + return false; + } + } elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) { + if ( false !== @ini_set( 'memory_limit', $wp_max_limit ) ) { + return $wp_max_limit; + } else { + return false; + } + } + return false; + } + + /** + * Attempts to raise the PHP timeout for time intensive processes. + * + * Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available. + * + * @param int $limit The time limit in seconds. + */ + public static function raise_time_limit( $limit = 0 ) { + $limit = (int) $limit; + $max_execution_time = (int) ini_get( 'max_execution_time' ); + + /* + * If the max execution time is already unlimited (zero), or if it exceeds or is equal to the proposed + * limit, there is no reason for us to make further changes (we never want to lower it). + */ + if ( + 0 === $max_execution_time + || ( $max_execution_time >= $limit && $limit !== 0 ) + ) { + return; + } + + if ( function_exists( 'wc_set_time_limit' ) ) { + wc_set_time_limit( $limit ); + } elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved + @set_time_limit( $limit ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_DataController.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_DataController.php new file mode 100644 index 000000000..eb69847b5 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_DataController.php @@ -0,0 +1,187 @@ +=' ); + return $php_support && apply_filters( 'action_scheduler_migration_dependencies_met', true ); + } + + /** + * Get a flag indicating whether the migration is complete. + * + * @return bool Whether the flag has been set marking the migration as complete + */ + public static function is_migration_complete() { + return get_option( self::STATUS_FLAG ) === self::STATUS_COMPLETE; + } + + /** + * Mark the migration as complete. + */ + public static function mark_migration_complete() { + update_option( self::STATUS_FLAG, self::STATUS_COMPLETE ); + } + + /** + * Unmark migration when a plugin is de-activated. Will not work in case of silent activation, for example in an update. + * We do this to mitigate the bug of lost actions which happens if there was an AS 2.x to AS 3.x migration in the past, but that plugin is now + * deactivated and the site was running on AS 2.x again. + */ + public static function mark_migration_incomplete() { + delete_option( self::STATUS_FLAG ); + } + + /** + * Set the action store class name. + * + * @param string $class Classname of the store class. + * + * @return string + */ + public static function set_store_class( $class ) { + return self::DATASTORE_CLASS; + } + + /** + * Set the action logger class name. + * + * @param string $class Classname of the logger class. + * + * @return string + */ + public static function set_logger_class( $class ) { + return self::LOGGER_CLASS; + } + + /** + * Set the sleep time in seconds. + * + * @param integer $sleep_time The number of seconds to pause before resuming operation. + */ + public static function set_sleep_time( $sleep_time ) { + self::$sleep_time = (int) $sleep_time; + } + + /** + * Set the tick count required for freeing memory. + * + * @param integer $free_ticks The number of ticks to free memory on. + */ + public static function set_free_ticks( $free_ticks ) { + self::$free_ticks = (int) $free_ticks; + } + + /** + * Free memory if conditions are met. + * + * @param int $ticks Current tick count. + */ + public static function maybe_free_memory( $ticks ) { + if ( self::$free_ticks && 0 === $ticks % self::$free_ticks ) { + self::free_memory(); + } + } + + /** + * Reduce memory footprint by clearing the database query and object caches. + */ + public static function free_memory() { + if ( 0 < self::$sleep_time ) { + /* translators: %d: amount of time */ + \WP_CLI::warning( sprintf( _n( 'Stopped the insanity for %d second', 'Stopped the insanity for %d seconds', self::$sleep_time, 'action-scheduler' ), self::$sleep_time ) ); + sleep( self::$sleep_time ); + } + + \WP_CLI::warning( __( 'Attempting to reduce used memory...', 'action-scheduler' ) ); + + /** + * @var $wpdb \wpdb + * @var $wp_object_cache \WP_Object_Cache + */ + global $wpdb, $wp_object_cache; + + $wpdb->queries = array(); + + if ( ! is_a( $wp_object_cache, 'WP_Object_Cache' ) ) { + return; + } + + $wp_object_cache->group_ops = array(); + $wp_object_cache->stats = array(); + $wp_object_cache->memcache_debug = array(); + $wp_object_cache->cache = array(); + + if ( is_callable( array( $wp_object_cache, '__remoteset' ) ) ) { + call_user_func( array( $wp_object_cache, '__remoteset' ) ); // important + } + } + + /** + * Connect to table datastores if migration is complete. + * Otherwise, proceed with the migration if the dependencies have been met. + */ + public static function init() { + if ( self::is_migration_complete() ) { + add_filter( 'action_scheduler_store_class', array( 'ActionScheduler_DataController', 'set_store_class' ), 100 ); + add_filter( 'action_scheduler_logger_class', array( 'ActionScheduler_DataController', 'set_logger_class' ), 100 ); + add_action( 'deactivate_plugin', array( 'ActionScheduler_DataController', 'mark_migration_incomplete' ) ); + } elseif ( self::dependencies_met() ) { + Controller::init(); + } + + add_action( 'action_scheduler/progress_tick', array( 'ActionScheduler_DataController', 'maybe_free_memory' ) ); + } + + /** + * Singleton factory. + */ + public static function instance() { + if ( ! isset( self::$instance ) ) { + self::$instance = new static(); + } + + return self::$instance; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_DateTime.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_DateTime.php new file mode 100644 index 000000000..b142ca81c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_DateTime.php @@ -0,0 +1,79 @@ +format( 'U' ); + } + + /** + * Set the UTC offset. + * + * This represents a fixed offset instead of a timezone setting. + * + * @param $offset + */ + public function setUtcOffset( $offset ) { + $this->utcOffset = intval( $offset ); + } + + /** + * Returns the timezone offset. + * + * @return int + * @link http://php.net/manual/en/datetime.getoffset.php + */ + #[\ReturnTypeWillChange] + public function getOffset() { + return $this->utcOffset ? $this->utcOffset : parent::getOffset(); + } + + /** + * Set the TimeZone associated with the DateTime + * + * @param DateTimeZone $timezone + * + * @return static + * @link http://php.net/manual/en/datetime.settimezone.php + */ + #[\ReturnTypeWillChange] + public function setTimezone( $timezone ) { + $this->utcOffset = 0; + parent::setTimezone( $timezone ); + + return $this; + } + + /** + * Get the timestamp with the WordPress timezone offset added or subtracted. + * + * @since 3.0.0 + * @return int + */ + public function getOffsetTimestamp() { + return $this->getTimestamp() + $this->getOffset(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Exception.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Exception.php new file mode 100644 index 000000000..08e4faef8 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Exception.php @@ -0,0 +1,11 @@ +store = $store; + } + + public function attach( ActionScheduler_ActionClaim $claim ) { + $this->claim = $claim; + add_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) ); + add_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0, 1 ); + add_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0, 0 ); + add_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0, 0 ); + add_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0, 0 ); + } + + public function detach() { + $this->claim = NULL; + $this->untrack_action(); + remove_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) ); + remove_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0 ); + remove_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0 ); + remove_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0 ); + remove_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0 ); + } + + public function track_current_action( $action_id ) { + $this->action_id = $action_id; + } + + public function untrack_action() { + $this->action_id = 0; + } + + public function handle_unexpected_shutdown() { + if ( $error = error_get_last() ) { + if ( in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ) ) ) { + if ( !empty($this->action_id) ) { + $this->store->mark_failure( $this->action_id ); + do_action( 'action_scheduler_unexpected_shutdown', $this->action_id, $error ); + } + } + $this->store->release_claim( $this->claim ); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_InvalidActionException.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_InvalidActionException.php new file mode 100644 index 000000000..40b455993 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_InvalidActionException.php @@ -0,0 +1,47 @@ + label). + * + * @var array + */ + protected $columns = array(); + + /** + * Actions (name => label). + * + * @var array + */ + protected $row_actions = array(); + + /** + * The active data stores + * + * @var ActionScheduler_Store + */ + protected $store; + + /** + * A logger to use for getting action logs to display + * + * @var ActionScheduler_Logger + */ + protected $logger; + + /** + * A ActionScheduler_QueueRunner runner instance (or child class) + * + * @var ActionScheduler_QueueRunner + */ + protected $runner; + + /** + * Bulk actions. The key of the array is the method name of the implementation: + * + * bulk_(array $ids, string $sql_in). + * + * See the comments in the parent class for further details + * + * @var array + */ + protected $bulk_actions = array(); + + /** + * Flag variable to render our notifications, if any, once. + * + * @var bool + */ + protected static $did_notification = false; + + /** + * Array of seconds for common time periods, like week or month, alongside an internationalised string representation, i.e. "Day" or "Days" + * + * @var array + */ + private static $time_periods; + + /** + * Sets the current data store object into `store->action` and initialises the object. + * + * @param ActionScheduler_Store $store + * @param ActionScheduler_Logger $logger + * @param ActionScheduler_QueueRunner $runner + */ + public function __construct( ActionScheduler_Store $store, ActionScheduler_Logger $logger, ActionScheduler_QueueRunner $runner ) { + + $this->store = $store; + $this->logger = $logger; + $this->runner = $runner; + + $this->table_header = __( 'Scheduled Actions', 'action-scheduler' ); + + $this->bulk_actions = array( + 'delete' => __( 'Delete', 'action-scheduler' ), + ); + + $this->columns = array( + 'hook' => __( 'Hook', 'action-scheduler' ), + 'status' => __( 'Status', 'action-scheduler' ), + 'args' => __( 'Arguments', 'action-scheduler' ), + 'group' => __( 'Group', 'action-scheduler' ), + 'recurrence' => __( 'Recurrence', 'action-scheduler' ), + 'schedule' => __( 'Scheduled Date', 'action-scheduler' ), + 'log_entries' => __( 'Log', 'action-scheduler' ), + ); + + $this->sort_by = array( + 'schedule', + 'hook', + 'group', + ); + + $this->search_by = array( + 'hook', + 'args', + 'claim_id', + ); + + $request_status = $this->get_request_status(); + + if ( empty( $request_status ) ) { + $this->sort_by[] = 'status'; + } elseif ( in_array( $request_status, array( 'in-progress', 'failed' ) ) ) { + $this->columns += array( 'claim_id' => __( 'Claim ID', 'action-scheduler' ) ); + $this->sort_by[] = 'claim_id'; + } + + $this->row_actions = array( + 'hook' => array( + 'run' => array( + 'name' => __( 'Run', 'action-scheduler' ), + 'desc' => __( 'Process the action now as if it were run as part of a queue', 'action-scheduler' ), + ), + 'cancel' => array( + 'name' => __( 'Cancel', 'action-scheduler' ), + 'desc' => __( 'Cancel the action now to avoid it being run in future', 'action-scheduler' ), + 'class' => 'cancel trash', + ), + ), + ); + + self::$time_periods = array( + array( + 'seconds' => YEAR_IN_SECONDS, + /* translators: %s: amount of time */ + 'names' => _n_noop( '%s year', '%s years', 'action-scheduler' ), + ), + array( + 'seconds' => MONTH_IN_SECONDS, + /* translators: %s: amount of time */ + 'names' => _n_noop( '%s month', '%s months', 'action-scheduler' ), + ), + array( + 'seconds' => WEEK_IN_SECONDS, + /* translators: %s: amount of time */ + 'names' => _n_noop( '%s week', '%s weeks', 'action-scheduler' ), + ), + array( + 'seconds' => DAY_IN_SECONDS, + /* translators: %s: amount of time */ + 'names' => _n_noop( '%s day', '%s days', 'action-scheduler' ), + ), + array( + 'seconds' => HOUR_IN_SECONDS, + /* translators: %s: amount of time */ + 'names' => _n_noop( '%s hour', '%s hours', 'action-scheduler' ), + ), + array( + 'seconds' => MINUTE_IN_SECONDS, + /* translators: %s: amount of time */ + 'names' => _n_noop( '%s minute', '%s minutes', 'action-scheduler' ), + ), + array( + 'seconds' => 1, + /* translators: %s: amount of time */ + 'names' => _n_noop( '%s second', '%s seconds', 'action-scheduler' ), + ), + ); + + parent::__construct( + array( + 'singular' => 'action-scheduler', + 'plural' => 'action-scheduler', + 'ajax' => false, + ) + ); + + add_screen_option( + 'per_page', + array( + 'default' => $this->items_per_page, + ) + ); + + add_filter( 'set_screen_option_' . $this->get_per_page_option_name(), array( $this, 'set_items_per_page_option' ), 10, 3 ); + set_screen_options(); + } + + /** + * Handles setting the items_per_page option for this screen. + * + * @param mixed $status Default false (to skip saving the current option). + * @param string $option Screen option name. + * @param int $value Screen option value. + * @return int + */ + public function set_items_per_page_option( $status, $option, $value ) { + return $value; + } + /** + * Convert an interval of seconds into a two part human friendly string. + * + * The WordPress human_time_diff() function only calculates the time difference to one degree, meaning + * even if an action is 1 day and 11 hours away, it will display "1 day". This function goes one step + * further to display two degrees of accuracy. + * + * Inspired by the Crontrol::interval() function by Edward Dale: https://wordpress.org/plugins/wp-crontrol/ + * + * @param int $interval A interval in seconds. + * @param int $periods_to_include Depth of time periods to include, e.g. for an interval of 70, and $periods_to_include of 2, both minutes and seconds would be included. With a value of 1, only minutes would be included. + * @return string A human friendly string representation of the interval. + */ + private static function human_interval( $interval, $periods_to_include = 2 ) { + + if ( $interval <= 0 ) { + return __( 'Now!', 'action-scheduler' ); + } + + $output = ''; + + for ( $time_period_index = 0, $periods_included = 0, $seconds_remaining = $interval; $time_period_index < count( self::$time_periods ) && $seconds_remaining > 0 && $periods_included < $periods_to_include; $time_period_index++ ) { + + $periods_in_interval = floor( $seconds_remaining / self::$time_periods[ $time_period_index ]['seconds'] ); + + if ( $periods_in_interval > 0 ) { + if ( ! empty( $output ) ) { + $output .= ' '; + } + $output .= sprintf( _n( self::$time_periods[ $time_period_index ]['names'][0], self::$time_periods[ $time_period_index ]['names'][1], $periods_in_interval, 'action-scheduler' ), $periods_in_interval ); + $seconds_remaining -= $periods_in_interval * self::$time_periods[ $time_period_index ]['seconds']; + $periods_included++; + } + } + + return $output; + } + + /** + * Returns the recurrence of an action or 'Non-repeating'. The output is human readable. + * + * @param ActionScheduler_Action $action + * + * @return string + */ + protected function get_recurrence( $action ) { + $schedule = $action->get_schedule(); + if ( $schedule->is_recurring() ) { + $recurrence = $schedule->get_recurrence(); + + if ( is_numeric( $recurrence ) ) { + /* translators: %s: time interval */ + return sprintf( __( 'Every %s', 'action-scheduler' ), self::human_interval( $recurrence ) ); + } else { + return $recurrence; + } + } + + return __( 'Non-repeating', 'action-scheduler' ); + } + + /** + * Serializes the argument of an action to render it in a human friendly format. + * + * @param array $row The array representation of the current row of the table + * + * @return string + */ + public function column_args( array $row ) { + if ( empty( $row['args'] ) ) { + return apply_filters( 'action_scheduler_list_table_column_args', '', $row ); + } + + $row_html = '
    '; + foreach ( $row['args'] as $key => $value ) { + $row_html .= sprintf( '
  • %s => %s
  • ', esc_html( var_export( $key, true ) ), esc_html( var_export( $value, true ) ) ); + } + $row_html .= '
'; + + return apply_filters( 'action_scheduler_list_table_column_args', $row_html, $row ); + } + + /** + * Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal. + * + * @param array $row Action array. + * @return string + */ + public function column_log_entries( array $row ) { + + $log_entries_html = '
    '; + + $timezone = new DateTimezone( 'UTC' ); + + foreach ( $row['log_entries'] as $log_entry ) { + $log_entries_html .= $this->get_log_entry_html( $log_entry, $timezone ); + } + + $log_entries_html .= '
'; + + return $log_entries_html; + } + + /** + * Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal. + * + * @param ActionScheduler_LogEntry $log_entry + * @param DateTimezone $timezone + * @return string + */ + protected function get_log_entry_html( ActionScheduler_LogEntry $log_entry, DateTimezone $timezone ) { + $date = $log_entry->get_date(); + $date->setTimezone( $timezone ); + return sprintf( '
  • %s
    %s
  • ', esc_html( $date->format( 'Y-m-d H:i:s O' ) ), esc_html( $log_entry->get_message() ) ); + } + + /** + * Only display row actions for pending actions. + * + * @param array $row Row to render + * @param string $column_name Current row + * + * @return string + */ + protected function maybe_render_actions( $row, $column_name ) { + if ( 'pending' === strtolower( $row[ 'status_name' ] ) ) { + return parent::maybe_render_actions( $row, $column_name ); + } + + return ''; + } + + /** + * Renders admin notifications + * + * Notifications: + * 1. When the maximum number of tasks are being executed simultaneously. + * 2. Notifications when a task is manually executed. + * 3. Tables are missing. + */ + public function display_admin_notices() { + global $wpdb; + + if ( ( is_a( $this->store, 'ActionScheduler_HybridStore' ) || is_a( $this->store, 'ActionScheduler_DBStore' ) ) && apply_filters( 'action_scheduler_enable_recreate_data_store', true ) ) { + $table_list = array( + 'actionscheduler_actions', + 'actionscheduler_logs', + 'actionscheduler_groups', + 'actionscheduler_claims', + ); + + $found_tables = $wpdb->get_col( "SHOW TABLES LIKE '{$wpdb->prefix}actionscheduler%'" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + foreach ( $table_list as $table_name ) { + if ( ! in_array( $wpdb->prefix . $table_name, $found_tables ) ) { + $this->admin_notices[] = array( + 'class' => 'error', + 'message' => __( 'It appears one or more database tables were missing. Attempting to re-create the missing table(s).' , 'action-scheduler' ), + ); + $this->recreate_tables(); + parent::display_admin_notices(); + + return; + } + } + } + + if ( $this->runner->has_maximum_concurrent_batches() ) { + $claim_count = $this->store->get_claim_count(); + $this->admin_notices[] = array( + 'class' => 'updated', + 'message' => sprintf( + /* translators: %s: amount of claims */ + _n( + 'Maximum simultaneous queues already in progress (%s queue). No additional queues will begin processing until the current queues are complete.', + 'Maximum simultaneous queues already in progress (%s queues). No additional queues will begin processing until the current queues are complete.', + $claim_count, + 'action-scheduler' + ), + $claim_count + ), + ); + } elseif ( $this->store->has_pending_actions_due() ) { + + $async_request_lock_expiration = ActionScheduler::lock()->get_expiration( 'async-request-runner' ); + + // No lock set or lock expired + if ( false === $async_request_lock_expiration || $async_request_lock_expiration < time() ) { + $in_progress_url = add_query_arg( 'status', 'in-progress', remove_query_arg( 'status' ) ); + /* translators: %s: process URL */ + $async_request_message = sprintf( __( 'A new queue has begun processing. View actions in-progress »', 'action-scheduler' ), esc_url( $in_progress_url ) ); + } else { + /* translators: %d: seconds */ + $async_request_message = sprintf( __( 'The next queue will begin processing in approximately %d seconds.', 'action-scheduler' ), $async_request_lock_expiration - time() ); + } + + $this->admin_notices[] = array( + 'class' => 'notice notice-info', + 'message' => $async_request_message, + ); + } + + $notification = get_transient( 'action_scheduler_admin_notice' ); + + if ( is_array( $notification ) ) { + delete_transient( 'action_scheduler_admin_notice' ); + + $action = $this->store->fetch_action( $notification['action_id'] ); + $action_hook_html = '' . $action->get_hook() . ''; + if ( 1 == $notification['success'] ) { + $class = 'updated'; + switch ( $notification['row_action_type'] ) { + case 'run' : + /* translators: %s: action HTML */ + $action_message_html = sprintf( __( 'Successfully executed action: %s', 'action-scheduler' ), $action_hook_html ); + break; + case 'cancel' : + /* translators: %s: action HTML */ + $action_message_html = sprintf( __( 'Successfully canceled action: %s', 'action-scheduler' ), $action_hook_html ); + break; + default : + /* translators: %s: action HTML */ + $action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'action-scheduler' ), $action_hook_html ); + break; + } + } else { + $class = 'error'; + /* translators: 1: action HTML 2: action ID 3: error message */ + $action_message_html = sprintf( __( 'Could not process change for action: "%1$s" (ID: %2$d). Error: %3$s', 'action-scheduler' ), $action_hook_html, esc_html( $notification['action_id'] ), esc_html( $notification['error_message'] ) ); + } + + $action_message_html = apply_filters( 'action_scheduler_admin_notice_html', $action_message_html, $action, $notification ); + + $this->admin_notices[] = array( + 'class' => $class, + 'message' => $action_message_html, + ); + } + + parent::display_admin_notices(); + } + + /** + * Prints the scheduled date in a human friendly format. + * + * @param array $row The array representation of the current row of the table + * + * @return string + */ + public function column_schedule( $row ) { + return $this->get_schedule_display_string( $row['schedule'] ); + } + + /** + * Get the scheduled date in a human friendly format. + * + * @param ActionScheduler_Schedule $schedule + * @return string + */ + protected function get_schedule_display_string( ActionScheduler_Schedule $schedule ) { + + $schedule_display_string = ''; + + if ( is_a( $schedule, 'ActionScheduler_NullSchedule' ) ) { + return __( 'async', 'action-scheduler' ); + } + + if ( ! $schedule->get_date() ) { + return '0000-00-00 00:00:00'; + } + + $next_timestamp = $schedule->get_date()->getTimestamp(); + + $schedule_display_string .= $schedule->get_date()->format( 'Y-m-d H:i:s O' ); + $schedule_display_string .= '
    '; + + if ( gmdate( 'U' ) > $next_timestamp ) { + /* translators: %s: date interval */ + $schedule_display_string .= sprintf( __( ' (%s ago)', 'action-scheduler' ), self::human_interval( gmdate( 'U' ) - $next_timestamp ) ); + } else { + /* translators: %s: date interval */ + $schedule_display_string .= sprintf( __( ' (%s)', 'action-scheduler' ), self::human_interval( $next_timestamp - gmdate( 'U' ) ) ); + } + + return $schedule_display_string; + } + + /** + * Bulk delete + * + * Deletes actions based on their ID. This is the handler for the bulk delete. It assumes the data + * properly validated by the callee and it will delete the actions without any extra validation. + * + * @param array $ids + * @param string $ids_sql Inherited and unused + */ + protected function bulk_delete( array $ids, $ids_sql ) { + foreach ( $ids as $id ) { + $this->store->delete_action( $id ); + } + } + + /** + * Implements the logic behind running an action. ActionScheduler_Abstract_ListTable validates the request and their + * parameters are valid. + * + * @param int $action_id + */ + protected function row_action_cancel( $action_id ) { + $this->process_row_action( $action_id, 'cancel' ); + } + + /** + * Implements the logic behind running an action. ActionScheduler_Abstract_ListTable validates the request and their + * parameters are valid. + * + * @param int $action_id + */ + protected function row_action_run( $action_id ) { + $this->process_row_action( $action_id, 'run' ); + } + + /** + * Force the data store schema updates. + */ + protected function recreate_tables() { + if ( is_a( $this->store, 'ActionScheduler_HybridStore' ) ) { + $store = $this->store; + } else { + $store = new ActionScheduler_HybridStore(); + } + add_action( 'action_scheduler/created_table', array( $store, 'set_autoincrement' ), 10, 2 ); + + $store_schema = new ActionScheduler_StoreSchema(); + $logger_schema = new ActionScheduler_LoggerSchema(); + $store_schema->register_tables( true ); + $logger_schema->register_tables( true ); + + remove_action( 'action_scheduler/created_table', array( $store, 'set_autoincrement' ), 10 ); + } + /** + * Implements the logic behind processing an action once an action link is clicked on the list table. + * + * @param int $action_id + * @param string $row_action_type The type of action to perform on the action. + */ + protected function process_row_action( $action_id, $row_action_type ) { + try { + switch ( $row_action_type ) { + case 'run' : + $this->runner->process_action( $action_id, 'Admin List Table' ); + break; + case 'cancel' : + $this->store->cancel_action( $action_id ); + break; + } + $success = 1; + $error_message = ''; + } catch ( Exception $e ) { + $success = 0; + $error_message = $e->getMessage(); + } + + set_transient( 'action_scheduler_admin_notice', compact( 'action_id', 'success', 'error_message', 'row_action_type' ), 30 ); + } + + /** + * {@inheritDoc} + */ + public function prepare_items() { + $this->prepare_column_headers(); + + $per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page ); + + $query = array( + 'per_page' => $per_page, + 'offset' => $this->get_items_offset(), + 'status' => $this->get_request_status(), + 'orderby' => $this->get_request_orderby(), + 'order' => $this->get_request_order(), + 'search' => $this->get_request_search_query(), + ); + + /** + * Change query arguments to query for past-due actions. + * Past-due actions have the 'pending' status and are in the past. + * This is needed because registering 'past-due' as a status is overkill. + */ + if ( 'past-due' === $this->get_request_status() ) { + $query['status'] = ActionScheduler_Store::STATUS_PENDING; + $query['date'] = as_get_datetime_object(); + } + + $this->items = array(); + + $total_items = $this->store->query_actions( $query, 'count' ); + + $status_labels = $this->store->get_status_labels(); + + foreach ( $this->store->query_actions( $query ) as $action_id ) { + try { + $action = $this->store->fetch_action( $action_id ); + } catch ( Exception $e ) { + continue; + } + if ( is_a( $action, 'ActionScheduler_NullAction' ) ) { + continue; + } + $this->items[ $action_id ] = array( + 'ID' => $action_id, + 'hook' => $action->get_hook(), + 'status_name' => $this->store->get_status( $action_id ), + 'status' => $status_labels[ $this->store->get_status( $action_id ) ], + 'args' => $action->get_args(), + 'group' => $action->get_group(), + 'log_entries' => $this->logger->get_logs( $action_id ), + 'claim_id' => $this->store->get_claim_id( $action_id ), + 'recurrence' => $this->get_recurrence( $action ), + 'schedule' => $action->get_schedule(), + ); + } + + $this->set_pagination_args( array( + 'total_items' => $total_items, + 'per_page' => $per_page, + 'total_pages' => ceil( $total_items / $per_page ), + ) ); + } + + /** + * Prints the available statuses so the user can click to filter. + */ + protected function display_filter_by_status() { + $this->status_counts = $this->store->action_counts() + $this->store->extra_action_counts(); + parent::display_filter_by_status(); + } + + /** + * Get the text to display in the search box on the list table. + */ + protected function get_search_box_button_text() { + return __( 'Search hook, args and claim ID', 'action-scheduler' ); + } + + /** + * {@inheritDoc} + */ + protected function get_per_page_option_name() { + return str_replace( '-', '_', $this->screen->id ) . '_per_page'; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_LogEntry.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_LogEntry.php new file mode 100644 index 000000000..649636deb --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_LogEntry.php @@ -0,0 +1,67 @@ +comment_type + * to ActionScheduler_LogEntry::__construct(), goodness knows why, and the Follow-up Emails plugin + * hard-codes loading its own version of ActionScheduler_wpCommentLogger with that out-dated method, + * goodness knows why, so we need to guard against that here instead of using a DateTime type declaration + * for the constructor's 3rd param of $date and causing a fatal error with older versions of FUE. + */ + if ( null !== $date && ! is_a( $date, 'DateTime' ) ) { + _doing_it_wrong( __METHOD__, 'The third parameter must be a valid DateTime instance, or null.', '2.0.0' ); + $date = null; + } + + $this->action_id = $action_id; + $this->message = $message; + $this->date = $date ? $date : new Datetime; + } + + /** + * Returns the date when this log entry was created + * + * @return Datetime + */ + public function get_date() { + return $this->date; + } + + public function get_action_id() { + return $this->action_id; + } + + public function get_message() { + return $this->message; + } +} + diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_NullLogEntry.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_NullLogEntry.php new file mode 100644 index 000000000..6f8f218aa --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_NullLogEntry.php @@ -0,0 +1,11 @@ +maybe_dispatch_async_request() uses a lock to avoid + * calling ActionScheduler_QueueRunner->has_maximum_concurrent_batches() every time the 'shutdown', + * hook is triggered, because that method calls ActionScheduler_QueueRunner->store->get_claim_count() + * to find the current number of claims in the database. + * + * @param string $lock_type A string to identify different lock types. + * @bool True if lock value has changed, false if not or if set failed. + */ + public function set( $lock_type ) { + return update_option( $this->get_key( $lock_type ), time() + $this->get_duration( $lock_type ) ); + } + + /** + * If a lock is set, return the timestamp it was set to expiry. + * + * @param string $lock_type A string to identify different lock types. + * @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire. + */ + public function get_expiration( $lock_type ) { + return get_option( $this->get_key( $lock_type ) ); + } + + /** + * Get the key to use for storing the lock in the transient + * + * @param string $lock_type A string to identify different lock types. + * @return string + */ + protected function get_key( $lock_type ) { + return sprintf( 'action_scheduler_lock_%s', $lock_type ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_QueueCleaner.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_QueueCleaner.php new file mode 100644 index 000000000..49cd44bb2 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_QueueCleaner.php @@ -0,0 +1,158 @@ +store = $store ? $store : ActionScheduler_Store::instance(); + $this->batch_size = $batch_size; + } + + public function delete_old_actions() { + $lifespan = apply_filters( 'action_scheduler_retention_period', $this->month_in_seconds ); + $cutoff = as_get_datetime_object($lifespan.' seconds ago'); + + $statuses_to_purge = array( + ActionScheduler_Store::STATUS_COMPLETE, + ActionScheduler_Store::STATUS_CANCELED, + ); + + foreach ( $statuses_to_purge as $status ) { + $actions_to_delete = $this->store->query_actions( array( + 'status' => $status, + 'modified' => $cutoff, + 'modified_compare' => '<=', + 'per_page' => $this->get_batch_size(), + 'orderby' => 'none', + ) ); + + foreach ( $actions_to_delete as $action_id ) { + try { + $this->store->delete_action( $action_id ); + } catch ( Exception $e ) { + + /** + * Notify 3rd party code of exceptions when deleting a completed action older than the retention period + * + * This hook provides a way for 3rd party code to log or otherwise handle exceptions relating to their + * actions. + * + * @since 2.0.0 + * + * @param int $action_id The scheduled actions ID in the data store + * @param Exception $e The exception thrown when attempting to delete the action from the data store + * @param int $lifespan The retention period, in seconds, for old actions + * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch + */ + do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) ); + } + } + } + } + + /** + * Unclaim pending actions that have not been run within a given time limit. + * + * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed + * as a parameter is 10x the time limit used for queue processing. + * + * @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes). + */ + public function reset_timeouts( $time_limit = 300 ) { + $timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit ); + if ( $timeout < 0 ) { + return; + } + $cutoff = as_get_datetime_object($timeout.' seconds ago'); + $actions_to_reset = $this->store->query_actions( array( + 'status' => ActionScheduler_Store::STATUS_PENDING, + 'modified' => $cutoff, + 'modified_compare' => '<=', + 'claimed' => true, + 'per_page' => $this->get_batch_size(), + 'orderby' => 'none', + ) ); + + foreach ( $actions_to_reset as $action_id ) { + $this->store->unclaim_action( $action_id ); + do_action( 'action_scheduler_reset_action', $action_id ); + } + } + + /** + * Mark actions that have been running for more than a given time limit as failed, based on + * the assumption some uncatachable and unloggable fatal error occurred during processing. + * + * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed + * as a parameter is 10x the time limit used for queue processing. + * + * @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes). + */ + public function mark_failures( $time_limit = 300 ) { + $timeout = apply_filters( 'action_scheduler_failure_period', $time_limit ); + if ( $timeout < 0 ) { + return; + } + $cutoff = as_get_datetime_object($timeout.' seconds ago'); + $actions_to_reset = $this->store->query_actions( array( + 'status' => ActionScheduler_Store::STATUS_RUNNING, + 'modified' => $cutoff, + 'modified_compare' => '<=', + 'per_page' => $this->get_batch_size(), + 'orderby' => 'none', + ) ); + + foreach ( $actions_to_reset as $action_id ) { + $this->store->mark_failure( $action_id ); + do_action( 'action_scheduler_failed_action', $action_id, $timeout ); + } + } + + /** + * Do all of the cleaning actions. + * + * @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes). + * @author Jeremy Pry + */ + public function clean( $time_limit = 300 ) { + $this->delete_old_actions(); + $this->reset_timeouts( $time_limit ); + $this->mark_failures( $time_limit ); + } + + /** + * Get the batch size for cleaning the queue. + * + * @author Jeremy Pry + * @return int + */ + protected function get_batch_size() { + /** + * Filter the batch size when cleaning the queue. + * + * @param int $batch_size The number of actions to clean in one batch. + */ + return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_QueueRunner.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_QueueRunner.php new file mode 100644 index 000000000..b890dca13 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_QueueRunner.php @@ -0,0 +1,220 @@ +store ); + } + + $this->async_request = $async_request; + } + + /** + * @codeCoverageIgnore + */ + public function init() { + + add_filter( 'cron_schedules', array( self::instance(), 'add_wp_cron_schedule' ) ); + + // Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param + $next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK ); + if ( $next_timestamp ) { + wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK ); + } + + $cron_context = array( 'WP Cron' ); + + if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) { + $schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE ); + wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context ); + } + + add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) ); + $this->hook_dispatch_async_request(); + } + + /** + * Hook check for dispatching an async request. + */ + public function hook_dispatch_async_request() { + add_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) ); + } + + /** + * Unhook check for dispatching an async request. + */ + public function unhook_dispatch_async_request() { + remove_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) ); + } + + /** + * Check if we should dispatch an async request to process actions. + * + * This method is attached to 'shutdown', so is called frequently. To avoid slowing down + * the site, it mitigates the work performed in each request by: + * 1. checking if it's in the admin context and then + * 2. haven't run on the 'shutdown' hook within the lock time (60 seconds by default) + * 3. haven't exceeded the number of allowed batches. + * + * The order of these checks is important, because they run from a check on a value: + * 1. in memory - is_admin() maps to $GLOBALS or the WP_ADMIN constant + * 2. in memory - transients use autoloaded options by default + * 3. from a database query - has_maximum_concurrent_batches() run the query + * $this->store->get_claim_count() to find the current number of claims in the DB. + * + * If all of these conditions are met, then we request an async runner check whether it + * should dispatch a request to process pending actions. + */ + public function maybe_dispatch_async_request() { + if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) { + // Only start an async queue at most once every 60 seconds + ActionScheduler::lock()->set( 'async-request-runner' ); + $this->async_request->maybe_dispatch(); + } + } + + /** + * Process actions in the queue. Attached to self::WP_CRON_HOOK i.e. 'action_scheduler_run_queue' + * + * The $context param of this method defaults to 'WP Cron', because prior to Action Scheduler 3.0.0 + * that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context + * passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK, + * should set a context as the first parameter. For an example of this, refer to the code seen in + * @see ActionScheduler_AsyncRequest_QueueRunner::handle() + * + * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' + * Generally, this should be capitalised and not localised as it's a proper noun. + * @return int The number of actions processed. + */ + public function run( $context = 'WP Cron' ) { + ActionScheduler_Compatibility::raise_memory_limit(); + ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() ); + do_action( 'action_scheduler_before_process_queue' ); + $this->run_cleanup(); + + $this->processed_actions_count = 0; + if ( false === $this->has_maximum_concurrent_batches() ) { + $batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 ); + do { + $processed_actions_in_batch = $this->do_batch( $batch_size, $context ); + $this->processed_actions_count += $processed_actions_in_batch; + } while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $this->processed_actions_count ) ); // keep going until we run out of actions, time, or memory + } + + do_action( 'action_scheduler_after_process_queue' ); + return $this->processed_actions_count; + } + + /** + * Process a batch of actions pending in the queue. + * + * Actions are processed by claiming a set of pending actions then processing each one until either the batch + * size is completed, or memory or time limits are reached, defined by @see $this->batch_limits_exceeded(). + * + * @param int $size The maximum number of actions to process in the batch. + * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' + * Generally, this should be capitalised and not localised as it's a proper noun. + * @return int The number of actions processed. + */ + protected function do_batch( $size = 100, $context = '' ) { + $claim = $this->store->stake_claim($size); + $this->monitor->attach($claim); + $processed_actions = 0; + + foreach ( $claim->get_actions() as $action_id ) { + // bail if we lost the claim + if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ) ) ) { + break; + } + $this->process_action( $action_id, $context ); + $processed_actions++; + + if ( $this->batch_limits_exceeded( $processed_actions + $this->processed_actions_count ) ) { + break; + } + } + $this->store->release_claim($claim); + $this->monitor->detach(); + $this->clear_caches(); + return $processed_actions; + } + + /** + * Flush the cache if possible (intended for use after a batch of actions has been processed). + * + * This is useful because running large batches can eat up memory and because invalid data can accrue in the + * runtime cache, which may lead to unexpected results. + */ + protected function clear_caches() { + /* + * Calling wp_cache_flush_runtime() lets us clear the runtime cache without invalidating the external object + * cache, so we will always prefer this when it is available (but it was only introduced in WordPress 6.0). + */ + if ( function_exists( 'wp_cache_flush_runtime' ) ) { + wp_cache_flush_runtime(); + } elseif ( + ! wp_using_ext_object_cache() + /** + * When an external object cache is in use, and when wp_cache_flush_runtime() is not available, then + * normally the cache will not be flushed after processing a batch of actions (to avoid a performance + * penalty for other processes). + * + * This filter makes it possible to override this behavior and always flush the cache, even if an external + * object cache is in use. + * + * @since 1.0 + * + * @param bool $flush_cache If the cache should be flushed. + */ + || apply_filters( 'action_scheduler_queue_runner_flush_cache', false ) + ) { + wp_cache_flush(); + } + } + + public function add_wp_cron_schedule( $schedules ) { + $schedules['every_minute'] = array( + 'interval' => 60, // in seconds + 'display' => __( 'Every minute', 'action-scheduler' ), + ); + + return $schedules; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Versions.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Versions.php new file mode 100644 index 000000000..915c2e632 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_Versions.php @@ -0,0 +1,62 @@ +versions[$version_string]) ) { + return FALSE; + } + $this->versions[$version_string] = $initialization_callback; + return TRUE; + } + + public function get_versions() { + return $this->versions; + } + + public function latest_version() { + $keys = array_keys($this->versions); + if ( empty($keys) ) { + return false; + } + uasort( $keys, 'version_compare' ); + return end($keys); + } + + public function latest_version_callback() { + $latest = $this->latest_version(); + if ( empty($latest) || !isset($this->versions[$latest]) ) { + return '__return_null'; + } + return $this->versions[$latest]; + } + + /** + * @return ActionScheduler_Versions + * @codeCoverageIgnore + */ + public static function instance() { + if ( empty(self::$instance) ) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * @codeCoverageIgnore + */ + public static function initialize_latest_version() { + $self = self::instance(); + call_user_func($self->latest_version_callback()); + } +} + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_WPCommentCleaner.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_WPCommentCleaner.php new file mode 100644 index 000000000..1ba552c50 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_WPCommentCleaner.php @@ -0,0 +1,115 @@ + Status administration screen + add_action( 'load-tools_page_action-scheduler', array( __CLASS__, 'register_admin_notice' ) ); + add_action( 'load-woocommerce_page_wc-status', array( __CLASS__, 'register_admin_notice' ) ); + } + + /** + * Determines if there are log entries in the wp comments table. + * + * Uses the flag set on migration completion set by @see self::maybe_schedule_cleanup(). + * + * @return boolean Whether there are scheduled action comments in the comments table. + */ + public static function has_logs() { + return 'yes' === get_option( self::$has_logs_option_key ); + } + + /** + * Schedules the WP Post comment table cleanup to run in 6 months if it's not already scheduled. + * Attached to the migration complete hook 'action_scheduler/migration_complete'. + */ + public static function maybe_schedule_cleanup() { + if ( (bool) get_comments( array( 'type' => ActionScheduler_wpCommentLogger::TYPE, 'number' => 1, 'fields' => 'ids' ) ) ) { + update_option( self::$has_logs_option_key, 'yes' ); + + if ( ! as_next_scheduled_action( self::$cleanup_hook ) ) { + as_schedule_single_action( gmdate( 'U' ) + ( 6 * MONTH_IN_SECONDS ), self::$cleanup_hook ); + } + } + } + + /** + * Delete all action comments from the WP Comments table. + */ + public static function delete_all_action_comments() { + global $wpdb; + $wpdb->delete( $wpdb->comments, array( 'comment_type' => ActionScheduler_wpCommentLogger::TYPE, 'comment_agent' => ActionScheduler_wpCommentLogger::AGENT ) ); + delete_option( self::$has_logs_option_key ); + } + + /** + * Registers admin notices about the orphaned action logs. + */ + public static function register_admin_notice() { + add_action( 'admin_notices', array( __CLASS__, 'print_admin_notice' ) ); + } + + /** + * Prints details about the orphaned action logs and includes information on where to learn more. + */ + public static function print_admin_notice() { + $next_cleanup_message = ''; + $next_scheduled_cleanup_hook = as_next_scheduled_action( self::$cleanup_hook ); + + if ( $next_scheduled_cleanup_hook ) { + /* translators: %s: date interval */ + $next_cleanup_message = sprintf( __( 'This data will be deleted in %s.', 'action-scheduler' ), human_time_diff( gmdate( 'U' ), $next_scheduled_cleanup_hook ) ); + } + + $notice = sprintf( + /* translators: 1: next cleanup message 2: github issue URL */ + __( 'Action Scheduler has migrated data to custom tables; however, orphaned log entries exist in the WordPress Comments table. %1$s Learn more »', 'action-scheduler' ), + $next_cleanup_message, + 'https://github.com/woocommerce/action-scheduler/issues/368' + ); + + echo '

    ' . wp_kses_post( $notice ) . '

    '; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_wcSystemStatus.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_wcSystemStatus.php new file mode 100644 index 000000000..bca63e715 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/ActionScheduler_wcSystemStatus.php @@ -0,0 +1,166 @@ +store = $store; + } + + /** + * Display action data, including number of actions grouped by status and the oldest & newest action in each status. + * + * Helpful to identify issues, like a clogged queue. + */ + public function render() { + $action_counts = $this->store->action_counts(); + $status_labels = $this->store->get_status_labels(); + $oldest_and_newest = $this->get_oldest_and_newest( array_keys( $status_labels ) ); + + $this->get_template( $status_labels, $action_counts, $oldest_and_newest ); + } + + /** + * Get oldest and newest scheduled dates for a given set of statuses. + * + * @param array $status_keys Set of statuses to find oldest & newest action for. + * @return array + */ + protected function get_oldest_and_newest( $status_keys ) { + + $oldest_and_newest = array(); + + foreach ( $status_keys as $status ) { + $oldest_and_newest[ $status ] = array( + 'oldest' => '–', + 'newest' => '–', + ); + + if ( 'in-progress' === $status ) { + continue; + } + + $oldest_and_newest[ $status ]['oldest'] = $this->get_action_status_date( $status, 'oldest' ); + $oldest_and_newest[ $status ]['newest'] = $this->get_action_status_date( $status, 'newest' ); + } + + return $oldest_and_newest; + } + + /** + * Get oldest or newest scheduled date for a given status. + * + * @param string $status Action status label/name string. + * @param string $date_type Oldest or Newest. + * @return DateTime + */ + protected function get_action_status_date( $status, $date_type = 'oldest' ) { + + $order = 'oldest' === $date_type ? 'ASC' : 'DESC'; + + $action = $this->store->query_actions( + array( + 'claimed' => false, + 'status' => $status, + 'per_page' => 1, + 'order' => $order, + ) + ); + + if ( ! empty( $action ) ) { + $date_object = $this->store->get_date( $action[0] ); + $action_date = $date_object->format( 'Y-m-d H:i:s O' ); + } else { + $action_date = '–'; + } + + return $action_date; + } + + /** + * Get oldest or newest scheduled date for a given status. + * + * @param array $status_labels Set of statuses to find oldest & newest action for. + * @param array $action_counts Number of actions grouped by status. + * @param array $oldest_and_newest Date of the oldest and newest action with each status. + */ + protected function get_template( $status_labels, $action_counts, $oldest_and_newest ) { + $as_version = ActionScheduler_Versions::instance()->latest_version(); + $as_datastore = get_class( ActionScheduler_Store::instance() ); + ?> + + + + + + + + + + + + + + + + + + + + + + + + $count ) { + // WC uses the 3rd column for export, so we need to display more data in that (hidden when viewed as part of the table) and add an empty 2nd column. + printf( + '', + esc_html( $status_labels[ $status ] ), + esc_html( number_format_i18n( $count ) ), + esc_html( $oldest_and_newest[ $status ]['oldest'] ), + esc_html( $oldest_and_newest[ $status ]['newest'] ) + ); + } + ?> + +

     
    %1$s %2$s, Oldest: %3$s, Newest: %4$s%3$s%4$s
    + + run_cleanup(); + $this->add_hooks(); + + // Check to make sure there aren't too many concurrent processes running. + if ( $this->has_maximum_concurrent_batches() ) { + if ( $force ) { + WP_CLI::warning( __( 'There are too many concurrent batches, but the run is forced to continue.', 'action-scheduler' ) ); + } else { + WP_CLI::error( __( 'There are too many concurrent batches.', 'action-scheduler' ) ); + } + } + + // Stake a claim and store it. + $this->claim = $this->store->stake_claim( $batch_size, null, $hooks, $group ); + $this->monitor->attach( $this->claim ); + $this->actions = $this->claim->get_actions(); + + return count( $this->actions ); + } + + /** + * Add our hooks to the appropriate actions. + * + * @author Jeremy Pry + */ + protected function add_hooks() { + add_action( 'action_scheduler_before_execute', array( $this, 'before_execute' ) ); + add_action( 'action_scheduler_after_execute', array( $this, 'after_execute' ), 10, 2 ); + add_action( 'action_scheduler_failed_execution', array( $this, 'action_failed' ), 10, 2 ); + } + + /** + * Set up the WP CLI progress bar. + * + * @author Jeremy Pry + */ + protected function setup_progress_bar() { + $count = count( $this->actions ); + $this->progress_bar = new ProgressBar( + /* translators: %d: amount of actions */ + sprintf( _n( 'Running %d action', 'Running %d actions', $count, 'action-scheduler' ), number_format_i18n( $count ) ), + $count + ); + } + + /** + * Process actions in the queue. + * + * @author Jeremy Pry + * + * @param string $context Optional runner context. Default 'WP CLI'. + * + * @return int The number of actions processed. + */ + public function run( $context = 'WP CLI' ) { + do_action( 'action_scheduler_before_process_queue' ); + $this->setup_progress_bar(); + foreach ( $this->actions as $action_id ) { + // Error if we lost the claim. + if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $this->claim->get_id() ) ) ) { + WP_CLI::warning( __( 'The claim has been lost. Aborting current batch.', 'action-scheduler' ) ); + break; + } + + $this->process_action( $action_id, $context ); + $this->progress_bar->tick(); + } + + $completed = $this->progress_bar->current(); + $this->progress_bar->finish(); + $this->store->release_claim( $this->claim ); + do_action( 'action_scheduler_after_process_queue' ); + + return $completed; + } + + /** + * Handle WP CLI message when the action is starting. + * + * @author Jeremy Pry + * + * @param $action_id + */ + public function before_execute( $action_id ) { + /* translators: %s refers to the action ID */ + WP_CLI::log( sprintf( __( 'Started processing action %s', 'action-scheduler' ), $action_id ) ); + } + + /** + * Handle WP CLI message when the action has completed. + * + * @author Jeremy Pry + * + * @param int $action_id + * @param null|ActionScheduler_Action $action The instance of the action. Default to null for backward compatibility. + */ + public function after_execute( $action_id, $action = null ) { + // backward compatibility + if ( null === $action ) { + $action = $this->store->fetch_action( $action_id ); + } + /* translators: 1: action ID 2: hook name */ + WP_CLI::log( sprintf( __( 'Completed processing action %1$s with hook: %2$s', 'action-scheduler' ), $action_id, $action->get_hook() ) ); + } + + /** + * Handle WP CLI message when the action has failed. + * + * @author Jeremy Pry + * + * @param int $action_id + * @param Exception $exception + * @throws \WP_CLI\ExitException With failure message. + */ + public function action_failed( $action_id, $exception ) { + WP_CLI::error( + /* translators: 1: action ID 2: exception message */ + sprintf( __( 'Error processing action %1$s: %2$s', 'action-scheduler' ), $action_id, $exception->getMessage() ), + false + ); + } + + /** + * Sleep and help avoid hitting memory limit + * + * @param int $sleep_time Amount of seconds to sleep + * @deprecated 3.0.0 + */ + protected function stop_the_insanity( $sleep_time = 0 ) { + _deprecated_function( 'ActionScheduler_WPCLI_QueueRunner::stop_the_insanity', '3.0.0', 'ActionScheduler_DataController::free_memory' ); + + ActionScheduler_DataController::free_memory(); + } + + /** + * Maybe trigger the stop_the_insanity() method to free up memory. + */ + protected function maybe_stop_the_insanity() { + // The value returned by progress_bar->current() might be padded. Remove padding, and convert to int. + $current_iteration = intval( trim( $this->progress_bar->current() ) ); + if ( 0 === $current_iteration % 50 ) { + $this->stop_the_insanity(); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php new file mode 100644 index 000000000..70b052e58 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/ActionScheduler_WPCLI_Scheduler_command.php @@ -0,0 +1,188 @@ +init(); + $obj->register_tables( true ); + + WP_CLI::success( + sprintf( + /* translators: %s refers to the schema name*/ + __( 'Registered schema for %s', 'action-scheduler' ), + $classname + ) + ); + } + } + } + + /** + * Run the Action Scheduler + * + * ## OPTIONS + * + * [--batch-size=] + * : The maximum number of actions to run. Defaults to 100. + * + * [--batches=] + * : Limit execution to a number of batches. Defaults to 0, meaning batches will continue being executed until all actions are complete. + * + * [--cleanup-batch-size=] + * : The maximum number of actions to clean up. Defaults to the value of --batch-size. + * + * [--hooks=] + * : Only run actions with the specified hook. Omitting this option runs actions with any hook. Define multiple hooks as a comma separated string (without spaces), e.g. `--hooks=hook_one,hook_two,hook_three` + * + * [--group=] + * : Only run actions from the specified group. Omitting this option runs actions from all groups. + * + * [--free-memory-on=] + * : The number of actions to process between freeing memory. 0 disables freeing memory. Default 50. + * + * [--pause=] + * : The number of seconds to pause when freeing memory. Default no pause. + * + * [--force] + * : Whether to force execution despite the maximum number of concurrent processes being exceeded. + * + * @param array $args Positional arguments. + * @param array $assoc_args Keyed arguments. + * @throws \WP_CLI\ExitException When an error occurs. + * + * @subcommand run + */ + public function run( $args, $assoc_args ) { + // Handle passed arguments. + $batch = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'batch-size', 100 ) ); + $batches = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'batches', 0 ) ); + $clean = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'cleanup-batch-size', $batch ) ); + $hooks = explode( ',', WP_CLI\Utils\get_flag_value( $assoc_args, 'hooks', '' ) ); + $hooks = array_filter( array_map( 'trim', $hooks ) ); + $group = \WP_CLI\Utils\get_flag_value( $assoc_args, 'group', '' ); + $free_on = \WP_CLI\Utils\get_flag_value( $assoc_args, 'free-memory-on', 50 ); + $sleep = \WP_CLI\Utils\get_flag_value( $assoc_args, 'pause', 0 ); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false ); + + ActionScheduler_DataController::set_free_ticks( $free_on ); + ActionScheduler_DataController::set_sleep_time( $sleep ); + + $batches_completed = 0; + $actions_completed = 0; + $unlimited = $batches === 0; + + try { + // Custom queue cleaner instance. + $cleaner = new ActionScheduler_QueueCleaner( null, $clean ); + + // Get the queue runner instance + $runner = new ActionScheduler_WPCLI_QueueRunner( null, null, $cleaner ); + + // Determine how many tasks will be run in the first batch. + $total = $runner->setup( $batch, $hooks, $group, $force ); + + // Run actions for as long as possible. + while ( $total > 0 ) { + $this->print_total_actions( $total ); + $actions_completed += $runner->run(); + $batches_completed++; + + // Maybe set up tasks for the next batch. + $total = ( $unlimited || $batches_completed < $batches ) ? $runner->setup( $batch, $hooks, $group, $force ) : 0; + } + } catch ( Exception $e ) { + $this->print_error( $e ); + } + + $this->print_total_batches( $batches_completed ); + $this->print_success( $actions_completed ); + } + + /** + * Print WP CLI message about how many actions are about to be processed. + * + * @author Jeremy Pry + * + * @param int $total + */ + protected function print_total_actions( $total ) { + WP_CLI::log( + sprintf( + /* translators: %d refers to how many scheduled taks were found to run */ + _n( 'Found %d scheduled task', 'Found %d scheduled tasks', $total, 'action-scheduler' ), + number_format_i18n( $total ) + ) + ); + } + + /** + * Print WP CLI message about how many batches of actions were processed. + * + * @author Jeremy Pry + * + * @param int $batches_completed + */ + protected function print_total_batches( $batches_completed ) { + WP_CLI::log( + sprintf( + /* translators: %d refers to the total number of batches executed */ + _n( '%d batch executed.', '%d batches executed.', $batches_completed, 'action-scheduler' ), + number_format_i18n( $batches_completed ) + ) + ); + } + + /** + * Convert an exception into a WP CLI error. + * + * @author Jeremy Pry + * + * @param Exception $e The error object. + * + * @throws \WP_CLI\ExitException + */ + protected function print_error( Exception $e ) { + WP_CLI::error( + sprintf( + /* translators: %s refers to the exception error message */ + __( 'There was an error running the action scheduler: %s', 'action-scheduler' ), + $e->getMessage() + ) + ); + } + + /** + * Print a success message with the number of completed actions. + * + * @author Jeremy Pry + * + * @param int $actions_completed + */ + protected function print_success( $actions_completed ) { + WP_CLI::success( + sprintf( + /* translators: %d refers to the total number of taskes completed */ + _n( '%d scheduled task completed.', '%d scheduled tasks completed.', $actions_completed, 'action-scheduler' ), + number_format_i18n( $actions_completed ) + ) + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/Migration_Command.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/Migration_Command.php new file mode 100644 index 000000000..066697e4e --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/Migration_Command.php @@ -0,0 +1,148 @@ + 'Migrates actions to the DB tables store', + 'synopsis' => [ + [ + 'type' => 'assoc', + 'name' => 'batch-size', + 'optional' => true, + 'default' => 100, + 'description' => 'The number of actions to process in each batch', + ], + [ + 'type' => 'assoc', + 'name' => 'free-memory-on', + 'optional' => true, + 'default' => 50, + 'description' => 'The number of actions to process between freeing memory. 0 disables freeing memory', + ], + [ + 'type' => 'assoc', + 'name' => 'pause', + 'optional' => true, + 'default' => 0, + 'description' => 'The number of seconds to pause when freeing memory', + ], + [ + 'type' => 'flag', + 'name' => 'dry-run', + 'optional' => true, + 'description' => 'Reports on the actions that would have been migrated, but does not change any data', + ], + ], + ] ); + } + + /** + * Process the data migration. + * + * @param array $positional_args Required for WP CLI. Not used in migration. + * @param array $assoc_args Optional arguments. + * + * @return void + */ + public function migrate( $positional_args, $assoc_args ) { + $this->init_logging(); + + $config = $this->get_migration_config( $assoc_args ); + $runner = new Runner( $config ); + $runner->init_destination(); + + $batch_size = isset( $assoc_args[ 'batch-size' ] ) ? (int) $assoc_args[ 'batch-size' ] : 100; + $free_on = isset( $assoc_args[ 'free-memory-on' ] ) ? (int) $assoc_args[ 'free-memory-on' ] : 50; + $sleep = isset( $assoc_args[ 'pause' ] ) ? (int) $assoc_args[ 'pause' ] : 0; + \ActionScheduler_DataController::set_free_ticks( $free_on ); + \ActionScheduler_DataController::set_sleep_time( $sleep ); + + do { + $actions_processed = $runner->run( $batch_size ); + $this->total_processed += $actions_processed; + } while ( $actions_processed > 0 ); + + if ( ! $config->get_dry_run() ) { + // let the scheduler know that there's nothing left to do + $scheduler = new Scheduler(); + $scheduler->mark_complete(); + } + + WP_CLI::success( sprintf( '%s complete. %d actions processed.', $config->get_dry_run() ? 'Dry run' : 'Migration', $this->total_processed ) ); + } + + /** + * Build the config object used to create the Runner + * + * @param array $args Optional arguments. + * + * @return ActionScheduler\Migration\Config + */ + private function get_migration_config( $args ) { + $args = wp_parse_args( $args, [ + 'dry-run' => false, + ] ); + + $config = Controller::instance()->get_migration_config_object(); + $config->set_dry_run( ! empty( $args[ 'dry-run' ] ) ); + + return $config; + } + + /** + * Hook command line logging into migration actions. + */ + private function init_logging() { + add_action( 'action_scheduler/migrate_action_dry_run', function ( $action_id ) { + WP_CLI::debug( sprintf( 'Dry-run: migrated action %d', $action_id ) ); + }, 10, 1 ); + add_action( 'action_scheduler/no_action_to_migrate', function ( $action_id ) { + WP_CLI::debug( sprintf( 'No action found to migrate for ID %d', $action_id ) ); + }, 10, 1 ); + add_action( 'action_scheduler/migrate_action_failed', function ( $action_id ) { + WP_CLI::warning( sprintf( 'Failed migrating action with ID %d', $action_id ) ); + }, 10, 1 ); + add_action( 'action_scheduler/migrate_action_incomplete', function ( $source_id, $destination_id ) { + WP_CLI::warning( sprintf( 'Unable to remove source action with ID %d after migrating to new ID %d', $source_id, $destination_id ) ); + }, 10, 2 ); + add_action( 'action_scheduler/migrated_action', function ( $source_id, $destination_id ) { + WP_CLI::debug( sprintf( 'Migrated source action with ID %d to new store with ID %d', $source_id, $destination_id ) ); + }, 10, 2 ); + add_action( 'action_scheduler/migration_batch_starting', function ( $batch ) { + WP_CLI::debug( 'Beginning migration of batch: ' . print_r( $batch, true ) ); + }, 10, 1 ); + add_action( 'action_scheduler/migration_batch_complete', function ( $batch ) { + WP_CLI::log( sprintf( 'Completed migration of %d actions', count( $batch ) ) ); + }, 10, 1 ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/ProgressBar.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/ProgressBar.php new file mode 100644 index 000000000..c86c74e83 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/WP_CLI/ProgressBar.php @@ -0,0 +1,119 @@ +total_ticks = 0; + $this->message = $message; + $this->count = $count; + $this->interval = $interval; + } + + /** + * Increment the progress bar ticks. + */ + public function tick() { + if ( null === $this->progress_bar ) { + $this->setup_progress_bar(); + } + + $this->progress_bar->tick(); + $this->total_ticks++; + + do_action( 'action_scheduler/progress_tick', $this->total_ticks ); + } + + /** + * Get the progress bar tick count. + * + * @return int + */ + public function current() { + return $this->progress_bar ? $this->progress_bar->current() : 0; + } + + /** + * Finish the current progress bar. + */ + public function finish() { + if ( null !== $this->progress_bar ) { + $this->progress_bar->finish(); + } + + $this->progress_bar = null; + } + + /** + * Set the message used when creating the progress bar. + * + * @param string $message The message to be used when the next progress bar is created. + */ + public function set_message( $message ) { + $this->message = $message; + } + + /** + * Set the count for a new progress bar. + * + * @param integer $count The total number of ticks expected to complete. + */ + public function set_count( $count ) { + $this->count = $count; + $this->finish(); + } + + /** + * Set up the progress bar. + */ + protected function setup_progress_bar() { + $this->progress_bar = \WP_CLI\Utils\make_progress_bar( + $this->message, + $this->count, + $this->interval + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler.php new file mode 100644 index 000000000..e8873f11e --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler.php @@ -0,0 +1,304 @@ +init(); + $store->init(); + $logger->init(); + $runner->init(); + } + + if ( apply_filters( 'action_scheduler_load_deprecated_functions', true ) ) { + require_once( self::plugin_path( 'deprecated/functions.php' ) ); + } + + if ( defined( 'WP_CLI' ) && WP_CLI ) { + WP_CLI::add_command( 'action-scheduler', 'ActionScheduler_WPCLI_Scheduler_command' ); + if ( ! ActionScheduler_DataController::is_migration_complete() && Controller::instance()->allow_migration() ) { + $command = new Migration_Command(); + $command->register(); + } + } + + self::$data_store_initialized = true; + + /** + * Handle WP comment cleanup after migration. + */ + if ( is_a( $logger, 'ActionScheduler_DBLogger' ) && ActionScheduler_DataController::is_migration_complete() && ActionScheduler_WPCommentCleaner::has_logs() ) { + ActionScheduler_WPCommentCleaner::init(); + } + + add_action( 'action_scheduler/migration_complete', 'ActionScheduler_WPCommentCleaner::maybe_schedule_cleanup' ); + } + + /** + * Check whether the AS data store has been initialized. + * + * @param string $function_name The name of the function being called. Optional. Default `null`. + * @return bool + */ + public static function is_initialized( $function_name = null ) { + if ( ! self::$data_store_initialized && ! empty( $function_name ) ) { + $message = sprintf( __( '%s() was called before the Action Scheduler data store was initialized', 'action-scheduler' ), esc_attr( $function_name ) ); + error_log( $message, E_WARNING ); + } + + return self::$data_store_initialized; + } + + /** + * Determine if the class is one of our abstract classes. + * + * @since 3.0.0 + * + * @param string $class The class name. + * + * @return bool + */ + protected static function is_class_abstract( $class ) { + static $abstracts = array( + 'ActionScheduler' => true, + 'ActionScheduler_Abstract_ListTable' => true, + 'ActionScheduler_Abstract_QueueRunner' => true, + 'ActionScheduler_Abstract_Schedule' => true, + 'ActionScheduler_Abstract_RecurringSchedule' => true, + 'ActionScheduler_Lock' => true, + 'ActionScheduler_Logger' => true, + 'ActionScheduler_Abstract_Schema' => true, + 'ActionScheduler_Store' => true, + 'ActionScheduler_TimezoneHelper' => true, + ); + + return isset( $abstracts[ $class ] ) && $abstracts[ $class ]; + } + + /** + * Determine if the class is one of our migration classes. + * + * @since 3.0.0 + * + * @param string $class The class name. + * + * @return bool + */ + protected static function is_class_migration( $class ) { + static $migration_segments = array( + 'ActionMigrator' => true, + 'BatchFetcher' => true, + 'DBStoreMigrator' => true, + 'DryRun' => true, + 'LogMigrator' => true, + 'Config' => true, + 'Controller' => true, + 'Runner' => true, + 'Scheduler' => true, + ); + + $segments = explode( '_', $class ); + $segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class; + + return isset( $migration_segments[ $segment ] ) && $migration_segments[ $segment ]; + } + + /** + * Determine if the class is one of our WP CLI classes. + * + * @since 3.0.0 + * + * @param string $class The class name. + * + * @return bool + */ + protected static function is_class_cli( $class ) { + static $cli_segments = array( + 'QueueRunner' => true, + 'Command' => true, + 'ProgressBar' => true, + ); + + $segments = explode( '_', $class ); + $segment = isset( $segments[ 1 ] ) ? $segments[ 1 ] : $class; + + return isset( $cli_segments[ $segment ] ) && $cli_segments[ $segment ]; + } + + final public function __clone() { + trigger_error("Singleton. No cloning allowed!", E_USER_ERROR); + } + + final public function __wakeup() { + trigger_error("Singleton. No serialization allowed!", E_USER_ERROR); + } + + final private function __construct() {} + + /** Deprecated **/ + + public static function get_datetime_object( $when = null, $timezone = 'UTC' ) { + _deprecated_function( __METHOD__, '2.0', 'wcs_add_months()' ); + return as_get_datetime_object( $when, $timezone ); + } + + /** + * Issue deprecated warning if an Action Scheduler function is called in the shutdown hook. + * + * @param string $function_name The name of the function being called. + * @deprecated 3.1.6. + */ + public static function check_shutdown_hook( $function_name ) { + _deprecated_function( __FUNCTION__, '3.1.6' ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_ListTable.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_ListTable.php new file mode 100644 index 000000000..ccc997f2f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_ListTable.php @@ -0,0 +1,766 @@ + value pair. The + * key must much the table column name and the value is the label, which is + * automatically translated. + * + * @var array + */ + protected $columns = array(); + + /** + * Defines the row-actions. It expects an array where the key + * is the column name and the value is an array of actions. + * + * The array of actions are key => value, where key is the method name + * (with the prefix row_action_) and the value is the label + * and title. + * + * @var array + */ + protected $row_actions = array(); + + /** + * The Primary key of our table + * + * @var string + */ + protected $ID = 'ID'; + + /** + * Enables sorting, it expects an array + * of columns (the column names are the values) + * + * @var array + */ + protected $sort_by = array(); + + /** + * The default sort order + * + * @var string + */ + protected $filter_by = array(); + + /** + * The status name => count combinations for this table's items. Used to display status filters. + * + * @var array + */ + protected $status_counts = array(); + + /** + * Notices to display when loading the table. Array of arrays of form array( 'class' => {updated|error}, 'message' => 'This is the notice text display.' ). + * + * @var array + */ + protected $admin_notices = array(); + + /** + * Localised string displayed in the

    element above the able. + * + * @var string + */ + protected $table_header; + + /** + * Enables bulk actions. It must be an array where the key is the action name + * and the value is the label (which is translated automatically). It is important + * to notice that it will check that the method exists (`bulk_$name`) and will throw + * an exception if it does not exists. + * + * This class will automatically check if the current request has a bulk action, will do the + * validations and afterwards will execute the bulk method, with two arguments. The first argument + * is the array with primary keys, the second argument is a string with a list of the primary keys, + * escaped and ready to use (with `IN`). + * + * @var array + */ + protected $bulk_actions = array(); + + /** + * Makes translation easier, it basically just wraps + * `_x` with some default (the package name). + * + * @param string $text The new text to translate. + * @param string $context The context of the text. + * @return string|void The translated text. + * + * @deprecated 3.0.0 Use `_x()` instead. + */ + protected function translate( $text, $context = '' ) { + return $text; + } + + /** + * Reads `$this->bulk_actions` and returns an array that WP_List_Table understands. It + * also validates that the bulk method handler exists. It throws an exception because + * this is a library meant for developers and missing a bulk method is a development-time error. + * + * @return array + * + * @throws RuntimeException Throws RuntimeException when the bulk action does not have a callback method. + */ + protected function get_bulk_actions() { + $actions = array(); + + foreach ( $this->bulk_actions as $action => $label ) { + if ( ! is_callable( array( $this, 'bulk_' . $action ) ) ) { + throw new RuntimeException( "The bulk action $action does not have a callback method" ); + } + + $actions[ $action ] = $label; + } + + return $actions; + } + + /** + * Checks if the current request has a bulk action. If that is the case it will validate and will + * execute the bulk method handler. Regardless if the action is valid or not it will redirect to + * the previous page removing the current arguments that makes this request a bulk action. + */ + protected function process_bulk_action() { + global $wpdb; + // Detect when a bulk action is being triggered. + $action = $this->current_action(); + if ( ! $action ) { + return; + } + + check_admin_referer( 'bulk-' . $this->_args['plural'] ); + + $method = 'bulk_' . $action; + if ( array_key_exists( $action, $this->bulk_actions ) && is_callable( array( $this, $method ) ) && ! empty( $_GET['ID'] ) && is_array( $_GET['ID'] ) ) { + $ids_sql = '(' . implode( ',', array_fill( 0, count( $_GET['ID'] ), '%s' ) ) . ')'; + $id = array_map( 'absint', $_GET['ID'] ); + $this->$method( $id, $wpdb->prepare( $ids_sql, $id ) ); //phpcs:ignore WordPress.DB.PreparedSQL + } + + if ( isset( $_SERVER['REQUEST_URI'] ) ) { + wp_safe_redirect( + remove_query_arg( + array( '_wp_http_referer', '_wpnonce', 'ID', 'action', 'action2' ), + esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) + ) + ); + exit; + } + } + + /** + * Default code for deleting entries. + * validated already by process_bulk_action() + * + * @param array $ids ids of the items to delete. + * @param string $ids_sql the sql for the ids. + * @return void + */ + protected function bulk_delete( array $ids, $ids_sql ) { + $store = ActionScheduler::store(); + foreach ( $ids as $action_id ) { + $store->delete( $action_id ); + } + } + + /** + * Prepares the _column_headers property which is used by WP_Table_List at rendering. + * It merges the columns and the sortable columns. + */ + protected function prepare_column_headers() { + $this->_column_headers = array( + $this->get_columns(), + get_hidden_columns( $this->screen ), + $this->get_sortable_columns(), + ); + } + + /** + * Reads $this->sort_by and returns the columns name in a format that WP_Table_List + * expects + */ + public function get_sortable_columns() { + $sort_by = array(); + foreach ( $this->sort_by as $column ) { + $sort_by[ $column ] = array( $column, true ); + } + return $sort_by; + } + + /** + * Returns the columns names for rendering. It adds a checkbox for selecting everything + * as the first column + */ + public function get_columns() { + $columns = array_merge( + array( 'cb' => '' ), + $this->columns + ); + + return $columns; + } + + /** + * Get prepared LIMIT clause for items query + * + * @global wpdb $wpdb + * + * @return string Prepared LIMIT clause for items query. + */ + protected function get_items_query_limit() { + global $wpdb; + + $per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page ); + return $wpdb->prepare( 'LIMIT %d', $per_page ); + } + + /** + * Returns the number of items to offset/skip for this current view. + * + * @return int + */ + protected function get_items_offset() { + $per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page ); + $current_page = $this->get_pagenum(); + if ( 1 < $current_page ) { + $offset = $per_page * ( $current_page - 1 ); + } else { + $offset = 0; + } + + return $offset; + } + + /** + * Get prepared OFFSET clause for items query + * + * @global wpdb $wpdb + * + * @return string Prepared OFFSET clause for items query. + */ + protected function get_items_query_offset() { + global $wpdb; + + return $wpdb->prepare( 'OFFSET %d', $this->get_items_offset() ); + } + + /** + * Prepares the ORDER BY sql statement. It uses `$this->sort_by` to know which + * columns are sortable. This requests validates the orderby $_GET parameter is a valid + * column and sortable. It will also use order (ASC|DESC) using DESC by default. + */ + protected function get_items_query_order() { + if ( empty( $this->sort_by ) ) { + return ''; + } + + $orderby = esc_sql( $this->get_request_orderby() ); + $order = esc_sql( $this->get_request_order() ); + + return "ORDER BY {$orderby} {$order}"; + } + + /** + * Return the sortable column specified for this request to order the results by, if any. + * + * @return string + */ + protected function get_request_orderby() { + + $valid_sortable_columns = array_values( $this->sort_by ); + + if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns, true ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended + $orderby = sanitize_text_field( wp_unslash( $_GET['orderby'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended + } else { + $orderby = $valid_sortable_columns[0]; + } + + return $orderby; + } + + /** + * Return the sortable column order specified for this request. + * + * @return string + */ + protected function get_request_order() { + + if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( sanitize_text_field( wp_unslash( $_GET['order'] ) ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended + $order = 'DESC'; + } else { + $order = 'ASC'; + } + + return $order; + } + + /** + * Return the status filter for this request, if any. + * + * @return string + */ + protected function get_request_status() { + $status = ( ! empty( $_GET['status'] ) ) ? sanitize_text_field( wp_unslash( $_GET['status'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended + return $status; + } + + /** + * Return the search filter for this request, if any. + * + * @return string + */ + protected function get_request_search_query() { + $search_query = ( ! empty( $_GET['s'] ) ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended + return $search_query; + } + + /** + * Process and return the columns name. This is meant for using with SQL, this means it + * always includes the primary key. + * + * @return array + */ + protected function get_table_columns() { + $columns = array_keys( $this->columns ); + if ( ! in_array( $this->ID, $columns, true ) ) { + $columns[] = $this->ID; + } + + return $columns; + } + + /** + * Check if the current request is doing a "full text" search. If that is the case + * prepares the SQL to search texts using LIKE. + * + * If the current request does not have any search or if this list table does not support + * that feature it will return an empty string. + * + * @return string + */ + protected function get_items_query_search() { + global $wpdb; + + if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended + return ''; + } + + $search_string = sanitize_text_field( wp_unslash( $_GET['s'] ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended + + $filter = array(); + foreach ( $this->search_by as $column ) { + $wild = '%'; + $sql_like = $wild . $wpdb->esc_like( $search_string ) . $wild; + $filter[] = $wpdb->prepare( '`' . $column . '` LIKE %s', $sql_like ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.DB.PreparedSQL.NotPrepared + } + return implode( ' OR ', $filter ); + } + + /** + * Prepares the SQL to filter rows by the options defined at `$this->filter_by`. Before trusting + * any data sent by the user it validates that it is a valid option. + */ + protected function get_items_query_filters() { + global $wpdb; + + if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended + return ''; + } + + $filter = array(); + + foreach ( $this->filter_by as $column => $options ) { + if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended + continue; + } + + $filter[] = $wpdb->prepare( "`$column` = %s", sanitize_text_field( wp_unslash( $_GET['filter_by'][ $column ] ) ) ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.DB.PreparedSQL.InterpolatedNotPrepared + } + + return implode( ' AND ', $filter ); + + } + + /** + * Prepares the data to feed WP_Table_List. + * + * This has the core for selecting, sorting and filting data. To keep the code simple + * its logic is split among many methods (get_items_query_*). + * + * Beside populating the items this function will also count all the records that matches + * the filtering criteria and will do fill the pagination variables. + */ + public function prepare_items() { + global $wpdb; + + $this->process_bulk_action(); + + $this->process_row_actions(); + + if ( ! empty( $_REQUEST['_wp_http_referer'] && ! empty( $_SERVER['REQUEST_URI'] ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended + // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter + wp_safe_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) ); + exit; + } + + $this->prepare_column_headers(); + + $limit = $this->get_items_query_limit(); + $offset = $this->get_items_query_offset(); + $order = $this->get_items_query_order(); + $where = array_filter( + array( + $this->get_items_query_search(), + $this->get_items_query_filters(), + ) + ); + $columns = '`' . implode( '`, `', $this->get_table_columns() ) . '`'; + + if ( ! empty( $where ) ) { + $where = 'WHERE (' . implode( ') AND (', $where ) . ')'; + } else { + $where = ''; + } + + $sql = "SELECT $columns FROM {$this->table_name} {$where} {$order} {$limit} {$offset}"; + + $this->set_items( $wpdb->get_results( $sql, ARRAY_A ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + $query_count = "SELECT COUNT({$this->ID}) FROM {$this->table_name} {$where}"; + $total_items = $wpdb->get_var( $query_count ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $per_page = $this->get_items_per_page( $this->get_per_page_option_name(), $this->items_per_page ); + $this->set_pagination_args( + array( + 'total_items' => $total_items, + 'per_page' => $per_page, + 'total_pages' => ceil( $total_items / $per_page ), + ) + ); + } + + /** + * Display the table. + * + * @param string $which The name of the table. + */ + public function extra_tablenav( $which ) { + if ( ! $this->filter_by || 'top' !== $which ) { + return; + } + + echo '
    '; + + foreach ( $this->filter_by as $id => $options ) { + $default = ! empty( $_GET['filter_by'][ $id ] ) ? sanitize_text_field( wp_unslash( $_GET['filter_by'][ $id ] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( empty( $options[ $default ] ) ) { + $default = ''; + } + + echo ''; + } + + submit_button( esc_html__( 'Filter', 'action-scheduler' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) ); + echo '
    '; + } + + /** + * Set the data for displaying. It will attempt to unserialize (There is a chance that some columns + * are serialized). This can be override in child classes for futher data transformation. + * + * @param array $items Items array. + */ + protected function set_items( array $items ) { + $this->items = array(); + foreach ( $items as $item ) { + $this->items[ $item[ $this->ID ] ] = array_map( 'maybe_unserialize', $item ); + } + } + + /** + * Renders the checkbox for each row, this is the first column and it is named ID regardless + * of how the primary key is named (to keep the code simpler). The bulk actions will do the proper + * name transformation though using `$this->ID`. + * + * @param array $row The row to render. + */ + public function column_cb( $row ) { + return ''; + } + + /** + * Renders the row-actions. + * + * This method renders the action menu, it reads the definition from the $row_actions property, + * and it checks that the row action method exists before rendering it. + * + * @param array $row Row to be rendered. + * @param string $column_name Column name. + * @return string + */ + protected function maybe_render_actions( $row, $column_name ) { + if ( empty( $this->row_actions[ $column_name ] ) ) { + return; + } + + $row_id = $row[ $this->ID ]; + + $actions = '
    '; + $action_count = 0; + foreach ( $this->row_actions[ $column_name ] as $action_key => $action ) { + + $action_count++; + + if ( ! method_exists( $this, 'row_action_' . $action_key ) ) { + continue; + } + + $action_link = ! empty( $action['link'] ) ? $action['link'] : add_query_arg( + array( + 'row_action' => $action_key, + 'row_id' => $row_id, + 'nonce' => wp_create_nonce( $action_key . '::' . $row_id ), + ) + ); + $span_class = ! empty( $action['class'] ) ? $action['class'] : $action_key; + $separator = ( $action_count < count( $this->row_actions[ $column_name ] ) ) ? ' | ' : ''; + + $actions .= sprintf( '', esc_attr( $span_class ) ); + $actions .= sprintf( '%3$s', esc_url( $action_link ), esc_attr( $action['desc'] ), esc_html( $action['name'] ) ); + $actions .= sprintf( '%s', $separator ); + } + $actions .= '
    '; + return $actions; + } + + /** + * Process the bulk actions. + * + * @return void + */ + protected function process_row_actions() { + $parameters = array( 'row_action', 'row_id', 'nonce' ); + foreach ( $parameters as $parameter ) { + if ( empty( $_REQUEST[ $parameter ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return; + } + } + + $action = sanitize_text_field( wp_unslash( $_REQUEST['row_action'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated + $row_id = sanitize_text_field( wp_unslash( $_REQUEST['row_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated + $nonce = sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotValidated + $method = 'row_action_' . $action; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + + if ( wp_verify_nonce( $nonce, $action . '::' . $row_id ) && method_exists( $this, $method ) ) { + $this->$method( sanitize_text_field( wp_unslash( $row_id ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + } + + if ( isset( $_SERVER['REQUEST_URI'] ) ) { + wp_safe_redirect( + remove_query_arg( + array( 'row_id', 'row_action', 'nonce' ), + esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) + ) + ); + exit; + } + } + + /** + * Default column formatting, it will escape everythig for security. + * + * @param array $item The item array. + * @param string $column_name Column name to display. + * + * @return string + */ + public function column_default( $item, $column_name ) { + $column_html = esc_html( $item[ $column_name ] ); + $column_html .= $this->maybe_render_actions( $item, $column_name ); + return $column_html; + } + + /** + * Display the table heading and search query, if any + */ + protected function display_header() { + echo '

    ' . esc_attr( $this->table_header ) . '

    '; + if ( $this->get_request_search_query() ) { + /* translators: %s: search query */ + echo '' . esc_attr( sprintf( __( 'Search results for "%s"', 'action-scheduler' ), $this->get_request_search_query() ) ) . ''; + } + echo '
    '; + } + + /** + * Display the table heading and search query, if any + */ + protected function display_admin_notices() { + foreach ( $this->admin_notices as $notice ) { + echo '
    '; + echo '

    ' . wp_kses_post( $notice['message'] ) . '

    '; + echo '
    '; + } + } + + /** + * Prints the available statuses so the user can click to filter. + */ + protected function display_filter_by_status() { + + $status_list_items = array(); + $request_status = $this->get_request_status(); + + // Helper to set 'all' filter when not set on status counts passed in. + if ( ! isset( $this->status_counts['all'] ) ) { + $this->status_counts = array( 'all' => array_sum( $this->status_counts ) ) + $this->status_counts; + } + + foreach ( $this->status_counts as $status_name => $count ) { + + if ( 0 === $count ) { + continue; + } + + if ( $status_name === $request_status || ( empty( $request_status ) && 'all' === $status_name ) ) { + $status_list_item = '
  • %3$s (%4$d)
  • '; + } else { + $status_list_item = '
  • %3$s (%4$d)
  • '; + } + + $status_filter_url = ( 'all' === $status_name ) ? remove_query_arg( 'status' ) : add_query_arg( 'status', $status_name ); + $status_filter_url = remove_query_arg( array( 'paged', 's' ), $status_filter_url ); + $status_list_items[] = sprintf( $status_list_item, esc_attr( $status_name ), esc_url( $status_filter_url ), esc_html( ucfirst( $status_name ) ), absint( $count ) ); + } + + if ( $status_list_items ) { + echo '
      '; + echo implode( " | \n", $status_list_items ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + echo '
    '; + } + } + + /** + * Renders the table list, we override the original class to render the table inside a form + * and to render any needed HTML (like the search box). By doing so the callee of a function can simple + * forget about any extra HTML. + */ + protected function display_table() { + echo '
    '; + foreach ( $_GET as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( '_' === $key[0] || 'paged' === $key || 'ID' === $key ) { + continue; + } + echo ''; + } + if ( ! empty( $this->search_by ) ) { + echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + parent::display(); + echo '
    '; + } + + /** + * Process any pending actions. + */ + public function process_actions() { + $this->process_bulk_action(); + $this->process_row_actions(); + + if ( ! empty( $_REQUEST['_wp_http_referer'] ) && ! empty( $_SERVER['REQUEST_URI'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter + wp_safe_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) ); + exit; + } + } + + /** + * Render the list table page, including header, notices, status filters and table. + */ + public function display_page() { + $this->prepare_items(); + + echo '
    '; + $this->display_header(); + $this->display_admin_notices(); + $this->display_filter_by_status(); + $this->display_table(); + echo '
    '; + } + + /** + * Get the text to display in the search box on the list table. + */ + protected function get_search_box_placeholder() { + return esc_html__( 'Search', 'action-scheduler' ); + } + + /** + * Gets the screen per_page option name. + * + * @return string + */ + protected function get_per_page_option_name() { + return $this->package . '_items_per_page'; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php new file mode 100644 index 000000000..3440f0016 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php @@ -0,0 +1,303 @@ +created_time = microtime( true ); + + $this->store = $store ? $store : ActionScheduler_Store::instance(); + $this->monitor = $monitor ? $monitor : new ActionScheduler_FatalErrorMonitor( $this->store ); + $this->cleaner = $cleaner ? $cleaner : new ActionScheduler_QueueCleaner( $this->store ); + } + + /** + * Process an individual action. + * + * @param int $action_id The action ID to process. + * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' + * Generally, this should be capitalised and not localised as it's a proper noun. + */ + public function process_action( $action_id, $context = '' ) { + try { + $valid_action = false; + do_action( 'action_scheduler_before_execute', $action_id, $context ); + + if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) { + do_action( 'action_scheduler_execution_ignored', $action_id, $context ); + return; + } + + $valid_action = true; + do_action( 'action_scheduler_begin_execute', $action_id, $context ); + + $action = $this->store->fetch_action( $action_id ); + $this->store->log_execution( $action_id ); + $action->execute(); + do_action( 'action_scheduler_after_execute', $action_id, $action, $context ); + $this->store->mark_complete( $action_id ); + } catch ( Exception $e ) { + if ( $valid_action ) { + $this->store->mark_failure( $action_id ); + do_action( 'action_scheduler_failed_execution', $action_id, $e, $context ); + } else { + do_action( 'action_scheduler_failed_validation', $action_id, $e, $context ); + } + } + + if ( isset( $action ) && is_a( $action, 'ActionScheduler_Action' ) && $action->get_schedule()->is_recurring() ) { + $this->schedule_next_instance( $action, $action_id ); + } + } + + /** + * Schedule the next instance of the action if necessary. + * + * @param ActionScheduler_Action $action + * @param int $action_id + */ + protected function schedule_next_instance( ActionScheduler_Action $action, $action_id ) { + // If a recurring action has been consistently failing, we may wish to stop rescheduling it. + if ( + ActionScheduler_Store::STATUS_FAILED === $this->store->get_status( $action_id ) + && $this->recurring_action_is_consistently_failing( $action, $action_id ) + ) { + ActionScheduler_Logger::instance()->log( + $action_id, + __( 'This action appears to be consistently failing. A new instance will not be scheduled.', 'action-scheduler' ) + ); + + return; + } + + try { + ActionScheduler::factory()->repeat( $action ); + } catch ( Exception $e ) { + do_action( 'action_scheduler_failed_to_schedule_next_instance', $action_id, $e, $action ); + } + } + + /** + * Determine if the specified recurring action has been consistently failing. + * + * @param ActionScheduler_Action $action The recurring action to be rescheduled. + * @param int $action_id The ID of the recurring action. + * + * @return bool + */ + private function recurring_action_is_consistently_failing( ActionScheduler_Action $action, $action_id ) { + /** + * Controls the failure threshold for recurring actions. + * + * Before rescheduling a recurring action, we look at its status. If it failed, we then check if all of the most + * recent actions (upto the threshold set by this filter) sharing the same hook have also failed: if they have, + * that is considered consistent failure and a new instance of the action will not be scheduled. + * + * @param int $failure_threshold Number of actions of the same hook to examine for failure. Defaults to 5. + */ + $consistent_failure_threshold = (int) apply_filters( 'action_scheduler_recurring_action_failure_threshold', 5 ); + + // This query should find the earliest *failing* action (for the hook we are interested in) within our threshold. + $query_args = array( + 'hook' => $action->get_hook(), + 'status' => ActionScheduler_Store::STATUS_FAILED, + 'date' => date_create( 'now', timezone_open( 'UTC' ) )->format( 'Y-m-d H:i:s' ), + 'date_compare' => '<', + 'per_page' => 1, + 'offset' => $consistent_failure_threshold - 1 + ); + + $first_failing_action_id = $this->store->query_actions( $query_args ); + + // If we didn't retrieve an action ID, then there haven't been enough failures for us to worry about. + if ( empty( $first_failing_action_id ) ) { + return false; + } + + // Now let's fetch the first action (having the same hook) of *any status*ithin the same window. + unset( $query_args['status'] ); + $first_action_id_with_the_same_hook = $this->store->query_actions( $query_args ); + + // If the IDs match, then actions for this hook must be consistently failing. + return $first_action_id_with_the_same_hook === $first_failing_action_id; + } + + /** + * Run the queue cleaner. + * + * @author Jeremy Pry + */ + protected function run_cleanup() { + $this->cleaner->clean( 10 * $this->get_time_limit() ); + } + + /** + * Get the number of concurrent batches a runner allows. + * + * @return int + */ + public function get_allowed_concurrent_batches() { + return apply_filters( 'action_scheduler_queue_runner_concurrent_batches', 1 ); + } + + /** + * Check if the number of allowed concurrent batches is met or exceeded. + * + * @return bool + */ + public function has_maximum_concurrent_batches() { + return $this->store->get_claim_count() >= $this->get_allowed_concurrent_batches(); + } + + /** + * Get the maximum number of seconds a batch can run for. + * + * @return int The number of seconds. + */ + protected function get_time_limit() { + + $time_limit = 30; + + // Apply deprecated filter from deprecated get_maximum_execution_time() method + if ( has_filter( 'action_scheduler_maximum_execution_time' ) ) { + _deprecated_function( 'action_scheduler_maximum_execution_time', '2.1.1', 'action_scheduler_queue_runner_time_limit' ); + $time_limit = apply_filters( 'action_scheduler_maximum_execution_time', $time_limit ); + } + + return absint( apply_filters( 'action_scheduler_queue_runner_time_limit', $time_limit ) ); + } + + /** + * Get the number of seconds the process has been running. + * + * @return int The number of seconds. + */ + protected function get_execution_time() { + $execution_time = microtime( true ) - $this->created_time; + + // Get the CPU time if the hosting environment uses it rather than wall-clock time to calculate a process's execution time. + if ( function_exists( 'getrusage' ) && apply_filters( 'action_scheduler_use_cpu_execution_time', defined( 'PANTHEON_ENVIRONMENT' ) ) ) { + $resource_usages = getrusage(); + + if ( isset( $resource_usages['ru_stime.tv_usec'], $resource_usages['ru_stime.tv_usec'] ) ) { + $execution_time = $resource_usages['ru_stime.tv_sec'] + ( $resource_usages['ru_stime.tv_usec'] / 1000000 ); + } + } + + return $execution_time; + } + + /** + * Check if the host's max execution time is (likely) to be exceeded if processing more actions. + * + * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action + * @return bool + */ + protected function time_likely_to_be_exceeded( $processed_actions ) { + $execution_time = $this->get_execution_time(); + $max_execution_time = $this->get_time_limit(); + + // Safety against division by zero errors. + if ( 0 === $processed_actions ) { + return $execution_time >= $max_execution_time; + } + + $time_per_action = $execution_time / $processed_actions; + $estimated_time = $execution_time + ( $time_per_action * 3 ); + $likely_to_be_exceeded = $estimated_time > $max_execution_time; + + return apply_filters( 'action_scheduler_maximum_execution_time_likely_to_be_exceeded', $likely_to_be_exceeded, $this, $processed_actions, $execution_time, $max_execution_time ); + } + + /** + * Get memory limit + * + * Based on WP_Background_Process::get_memory_limit() + * + * @return int + */ + protected function get_memory_limit() { + if ( function_exists( 'ini_get' ) ) { + $memory_limit = ini_get( 'memory_limit' ); + } else { + $memory_limit = '128M'; // Sensible default, and minimum required by WooCommerce + } + + if ( ! $memory_limit || -1 === $memory_limit || '-1' === $memory_limit ) { + // Unlimited, set to 32GB. + $memory_limit = '32G'; + } + + return ActionScheduler_Compatibility::convert_hr_to_bytes( $memory_limit ); + } + + /** + * Memory exceeded + * + * Ensures the batch process never exceeds 90% of the maximum WordPress memory. + * + * Based on WP_Background_Process::memory_exceeded() + * + * @return bool + */ + protected function memory_exceeded() { + + $memory_limit = $this->get_memory_limit() * 0.90; + $current_memory = memory_get_usage( true ); + $memory_exceeded = $current_memory >= $memory_limit; + + return apply_filters( 'action_scheduler_memory_exceeded', $memory_exceeded, $this ); + } + + /** + * See if the batch limits have been exceeded, which is when memory usage is almost at + * the maximum limit, or the time to process more actions will exceed the max time limit. + * + * Based on WC_Background_Process::batch_limits_exceeded() + * + * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action + * @return bool + */ + protected function batch_limits_exceeded( $processed_actions ) { + return $this->memory_exceeded() || $this->time_likely_to_be_exceeded( $processed_actions ); + } + + /** + * Process actions in the queue. + * + * @author Jeremy Pry + * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' + * Generally, this should be capitalised and not localised as it's a proper noun. + * @return int The number of actions processed. + */ + abstract public function run( $context = '' ); +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php new file mode 100644 index 000000000..131d4757d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_RecurringSchedule.php @@ -0,0 +1,102 @@ +start - and logic to calculate the next run date after + * that - @see $this->calculate_next(). The $first_date property also keeps a record of when the very + * first instance of this chain of schedules ran. + * + * @var DateTime + */ + private $first_date = NULL; + + /** + * Timestamp equivalent of @see $this->first_date + * + * @var int + */ + protected $first_timestamp = NULL; + + /** + * The recurrance between each time an action is run using this schedule. + * Used to calculate the start date & time. Can be a number of seconds, in the + * case of ActionScheduler_IntervalSchedule, or a cron expression, as in the + * case of ActionScheduler_CronSchedule. Or something else. + * + * @var mixed + */ + protected $recurrence; + + /** + * @param DateTime $date The date & time to run the action. + * @param mixed $recurrence The data used to determine the schedule's recurrance. + * @param DateTime|null $first (Optional) The date & time the first instance of this interval schedule ran. Default null, meaning this is the first instance. + */ + public function __construct( DateTime $date, $recurrence, DateTime $first = null ) { + parent::__construct( $date ); + $this->first_date = empty( $first ) ? $date : $first; + $this->recurrence = $recurrence; + } + + /** + * @return bool + */ + public function is_recurring() { + return true; + } + + /** + * Get the date & time of the first schedule in this recurring series. + * + * @return DateTime|null + */ + public function get_first_date() { + return clone $this->first_date; + } + + /** + * @return string + */ + public function get_recurrence() { + return $this->recurrence; + } + + /** + * For PHP 5.2 compat, since DateTime objects can't be serialized + * @return array + */ + public function __sleep() { + $sleep_params = parent::__sleep(); + $this->first_timestamp = $this->first_date->getTimestamp(); + return array_merge( $sleep_params, array( + 'first_timestamp', + 'recurrence' + ) ); + } + + /** + * Unserialize recurring schedules serialized/stored prior to AS 3.0.0 + * + * Prior to Action Scheduler 3.0.0, schedules used different property names to refer + * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp + * was the same as ActionScheduler_SimpleSchedule::timestamp. This was addressed in + * Action Scheduler 3.0.0, where properties and property names were aligned for better + * inheritance. To maintain backward compatibility with scheduled serialized and stored + * prior to 3.0, we need to correctly map the old property names. + */ + public function __wakeup() { + parent::__wakeup(); + if ( $this->first_timestamp > 0 ) { + $this->first_date = as_get_datetime_object( $this->first_timestamp ); + } else { + $this->first_date = $this->get_date(); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php new file mode 100644 index 000000000..2631ef554 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_Schedule.php @@ -0,0 +1,83 @@ +scheduled_date + * + * @var int + */ + protected $scheduled_timestamp = NULL; + + /** + * @param DateTime $date The date & time to run the action. + */ + public function __construct( DateTime $date ) { + $this->scheduled_date = $date; + } + + /** + * Check if a schedule should recur. + * + * @return bool + */ + abstract public function is_recurring(); + + /** + * Calculate when the next instance of this schedule would run based on a given date & time. + * + * @param DateTime $after + * @return DateTime + */ + abstract protected function calculate_next( DateTime $after ); + + /** + * Get the next date & time when this schedule should run after a given date & time. + * + * @param DateTime $after + * @return DateTime|null + */ + public function get_next( DateTime $after ) { + $after = clone $after; + if ( $after > $this->scheduled_date ) { + $after = $this->calculate_next( $after ); + return $after; + } + return clone $this->scheduled_date; + } + + /** + * Get the date & time the schedule is set to run. + * + * @return DateTime|null + */ + public function get_date() { + return $this->scheduled_date; + } + + /** + * For PHP 5.2 compat, since DateTime objects can't be serialized + * @return array + */ + public function __sleep() { + $this->scheduled_timestamp = $this->scheduled_date->getTimestamp(); + return array( + 'scheduled_timestamp', + ); + } + + public function __wakeup() { + $this->scheduled_date = as_get_datetime_object( $this->scheduled_timestamp ); + unset( $this->scheduled_timestamp ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php new file mode 100644 index 000000000..2334fda10 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Abstract_Schema.php @@ -0,0 +1,172 @@ +tables as $table ) { + $wpdb->tables[] = $table; + $name = $this->get_full_table_name( $table ); + $wpdb->$table = $name; + } + + // create the tables + if ( $this->schema_update_required() || $force_update ) { + foreach ( $this->tables as $table ) { + /** + * Allow custom processing before updating a table schema. + * + * @param string $table Name of table being updated. + * @param string $db_version Existing version of the table being updated. + */ + do_action( 'action_scheduler_before_schema_update', $table, $this->db_version ); + $this->update_table( $table ); + } + $this->mark_schema_update_complete(); + } + } + + /** + * @param string $table The name of the table + * + * @return string The CREATE TABLE statement, suitable for passing to dbDelta + */ + abstract protected function get_table_definition( $table ); + + /** + * Determine if the database schema is out of date + * by comparing the integer found in $this->schema_version + * with the option set in the WordPress options table + * + * @return bool + */ + private function schema_update_required() { + $option_name = 'schema-' . static::class; + $this->db_version = get_option( $option_name, 0 ); + + // Check for schema option stored by the Action Scheduler Custom Tables plugin in case site has migrated from that plugin with an older schema + if ( 0 === $this->db_version ) { + + $plugin_option_name = 'schema-'; + + switch ( static::class ) { + case 'ActionScheduler_StoreSchema' : + $plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Store_Table_Maker'; + break; + case 'ActionScheduler_LoggerSchema' : + $plugin_option_name .= 'Action_Scheduler\Custom_Tables\DB_Logger_Table_Maker'; + break; + } + + $this->db_version = get_option( $plugin_option_name, 0 ); + + delete_option( $plugin_option_name ); + } + + return version_compare( $this->db_version, $this->schema_version, '<' ); + } + + /** + * Update the option in WordPress to indicate that + * our schema is now up to date + * + * @return void + */ + private function mark_schema_update_complete() { + $option_name = 'schema-' . static::class; + + // work around race conditions and ensure that our option updates + $value_to_save = (string) $this->schema_version . '.0.' . time(); + + update_option( $option_name, $value_to_save ); + } + + /** + * Update the schema for the given table + * + * @param string $table The name of the table to update + * + * @return void + */ + private function update_table( $table ) { + require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); + $definition = $this->get_table_definition( $table ); + if ( $definition ) { + $updated = dbDelta( $definition ); + foreach ( $updated as $updated_table => $update_description ) { + if ( strpos( $update_description, 'Created table' ) === 0 ) { + do_action( 'action_scheduler/created_table', $updated_table, $table ); + } + } + } + } + + /** + * @param string $table + * + * @return string The full name of the table, including the + * table prefix for the current blog + */ + protected function get_full_table_name( $table ) { + return $GLOBALS[ 'wpdb' ]->prefix . $table; + } + + /** + * Confirms that all of the tables registered by this schema class have been created. + * + * @return bool + */ + public function tables_exist() { + global $wpdb; + + $existing_tables = $wpdb->get_col( 'SHOW TABLES' ); + $expected_tables = array_map( + function ( $table_name ) use ( $wpdb ) { + return $wpdb->prefix . $table_name; + }, + $this->tables + ); + + return count( array_intersect( $existing_tables, $expected_tables ) ) === count( $expected_tables ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Lock.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Lock.php new file mode 100644 index 000000000..86e852851 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Lock.php @@ -0,0 +1,62 @@ +get_expiration( $lock_type ) >= time() ); + } + + /** + * Set a lock. + * + * @param string $lock_type A string to identify different lock types. + * @return bool + */ + abstract public function set( $lock_type ); + + /** + * If a lock is set, return the timestamp it was set to expiry. + * + * @param string $lock_type A string to identify different lock types. + * @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire. + */ + abstract public function get_expiration( $lock_type ); + + /** + * Get the amount of time to set for a given lock. 60 seconds by default. + * + * @param string $lock_type A string to identify different lock types. + * @return int + */ + protected function get_duration( $lock_type ) { + return apply_filters( 'action_scheduler_lock_duration', self::$lock_duration, $lock_type ); + } + + /** + * @return ActionScheduler_Lock + */ + public static function instance() { + if ( empty( self::$locker ) ) { + $class = apply_filters( 'action_scheduler_lock_class', 'ActionScheduler_OptionLock' ); + self::$locker = new $class(); + } + return self::$locker; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Logger.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Logger.php new file mode 100644 index 000000000..c3afd04b6 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Logger.php @@ -0,0 +1,176 @@ +hook_stored_action(); + add_action( 'action_scheduler_canceled_action', array( $this, 'log_canceled_action' ), 10, 1 ); + add_action( 'action_scheduler_begin_execute', array( $this, 'log_started_action' ), 10, 2 ); + add_action( 'action_scheduler_after_execute', array( $this, 'log_completed_action' ), 10, 3 ); + add_action( 'action_scheduler_failed_execution', array( $this, 'log_failed_action' ), 10, 3 ); + add_action( 'action_scheduler_failed_action', array( $this, 'log_timed_out_action' ), 10, 2 ); + add_action( 'action_scheduler_unexpected_shutdown', array( $this, 'log_unexpected_shutdown' ), 10, 2 ); + add_action( 'action_scheduler_reset_action', array( $this, 'log_reset_action' ), 10, 1 ); + add_action( 'action_scheduler_execution_ignored', array( $this, 'log_ignored_action' ), 10, 2 ); + add_action( 'action_scheduler_failed_fetch_action', array( $this, 'log_failed_fetch_action' ), 10, 2 ); + add_action( 'action_scheduler_failed_to_schedule_next_instance', array( $this, 'log_failed_schedule_next_instance' ), 10, 2 ); + add_action( 'action_scheduler_bulk_cancel_actions', array( $this, 'bulk_log_cancel_actions' ), 10, 1 ); + } + + public function hook_stored_action() { + add_action( 'action_scheduler_stored_action', array( $this, 'log_stored_action' ) ); + } + + public function unhook_stored_action() { + remove_action( 'action_scheduler_stored_action', array( $this, 'log_stored_action' ) ); + } + + public function log_stored_action( $action_id ) { + $this->log( $action_id, __( 'action created', 'action-scheduler' ) ); + } + + public function log_canceled_action( $action_id ) { + $this->log( $action_id, __( 'action canceled', 'action-scheduler' ) ); + } + + public function log_started_action( $action_id, $context = '' ) { + if ( ! empty( $context ) ) { + /* translators: %s: context */ + $message = sprintf( __( 'action started via %s', 'action-scheduler' ), $context ); + } else { + $message = __( 'action started', 'action-scheduler' ); + } + $this->log( $action_id, $message ); + } + + public function log_completed_action( $action_id, $action = NULL, $context = '' ) { + if ( ! empty( $context ) ) { + /* translators: %s: context */ + $message = sprintf( __( 'action complete via %s', 'action-scheduler' ), $context ); + } else { + $message = __( 'action complete', 'action-scheduler' ); + } + $this->log( $action_id, $message ); + } + + public function log_failed_action( $action_id, Exception $exception, $context = '' ) { + if ( ! empty( $context ) ) { + /* translators: 1: context 2: exception message */ + $message = sprintf( __( 'action failed via %1$s: %2$s', 'action-scheduler' ), $context, $exception->getMessage() ); + } else { + /* translators: %s: exception message */ + $message = sprintf( __( 'action failed: %s', 'action-scheduler' ), $exception->getMessage() ); + } + $this->log( $action_id, $message ); + } + + public function log_timed_out_action( $action_id, $timeout ) { + /* translators: %s: amount of time */ + $this->log( $action_id, sprintf( __( 'action marked as failed after %s seconds. Unknown error occurred. Check server, PHP and database error logs to diagnose cause.', 'action-scheduler' ), $timeout ) ); + } + + public function log_unexpected_shutdown( $action_id, $error ) { + if ( ! empty( $error ) ) { + /* translators: 1: error message 2: filename 3: line */ + $this->log( $action_id, sprintf( __( 'unexpected shutdown: PHP Fatal error %1$s in %2$s on line %3$s', 'action-scheduler' ), $error['message'], $error['file'], $error['line'] ) ); + } + } + + public function log_reset_action( $action_id ) { + $this->log( $action_id, __( 'action reset', 'action-scheduler' ) ); + } + + public function log_ignored_action( $action_id, $context = '' ) { + if ( ! empty( $context ) ) { + /* translators: %s: context */ + $message = sprintf( __( 'action ignored via %s', 'action-scheduler' ), $context ); + } else { + $message = __( 'action ignored', 'action-scheduler' ); + } + $this->log( $action_id, $message ); + } + + /** + * @param string $action_id + * @param Exception|NULL $exception The exception which occured when fetching the action. NULL by default for backward compatibility. + * + * @return ActionScheduler_LogEntry[] + */ + public function log_failed_fetch_action( $action_id, Exception $exception = NULL ) { + + if ( ! is_null( $exception ) ) { + /* translators: %s: exception message */ + $log_message = sprintf( __( 'There was a failure fetching this action: %s', 'action-scheduler' ), $exception->getMessage() ); + } else { + $log_message = __( 'There was a failure fetching this action', 'action-scheduler' ); + } + + $this->log( $action_id, $log_message ); + } + + public function log_failed_schedule_next_instance( $action_id, Exception $exception ) { + /* translators: %s: exception message */ + $this->log( $action_id, sprintf( __( 'There was a failure scheduling the next instance of this action: %s', 'action-scheduler' ), $exception->getMessage() ) ); + } + + /** + * Bulk add cancel action log entries. + * + * Implemented here for backward compatibility. Should be implemented in parent loggers + * for more performant bulk logging. + * + * @param array $action_ids List of action ID. + */ + public function bulk_log_cancel_actions( $action_ids ) { + if ( empty( $action_ids ) ) { + return; + } + + foreach ( $action_ids as $action_id ) { + $this->log_canceled_action( $action_id ); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Store.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Store.php new file mode 100644 index 000000000..a55529332 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_Store.php @@ -0,0 +1,450 @@ + null, + 'status' => self::STATUS_PENDING, + 'group' => '', + ) + ); + + // These params are fixed for this method. + $params['hook'] = $hook; + $params['orderby'] = 'date'; + $params['per_page'] = 1; + + if ( ! empty( $params['status'] ) ) { + if ( self::STATUS_PENDING === $params['status'] ) { + $params['order'] = 'ASC'; // Find the next action that matches. + } else { + $params['order'] = 'DESC'; // Find the most recent action that matches. + } + } + + $results = $this->query_actions( $params ); + + return empty( $results ) ? null : $results[0]; + } + + /** + * Query for action count or list of action IDs. + * + * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status. + * + * @param array $query { + * Query filtering options. + * + * @type string $hook The name of the actions. Optional. + * @type string|array $status The status or statuses of the actions. Optional. + * @type array $args The args array of the actions. Optional. + * @type DateTime $date The scheduled date of the action. Used in UTC timezone. Optional. + * @type string $date_compare Operator for selecting by $date param. Accepted values are '!=', '>', '>=', '<', '<=', '='. Defaults to '<='. + * @type DateTime $modified The last modified date of the action. Used in UTC timezone. Optional. + * @type string $modified_compare Operator for comparing $modified param. Accepted values are '!=', '>', '>=', '<', '<=', '='. Defaults to '<='. + * @type string $group The group the action belongs to. Optional. + * @type bool|int $claimed TRUE to find claimed actions, FALSE to find unclaimed actions, an int to find a specific claim ID. Optional. + * @type int $per_page Number of results to return. Defaults to 5. + * @type int $offset The query pagination offset. Defaults to 0. + * @type int $orderby Accepted values are 'hook', 'group', 'modified', 'date' or 'none'. Defaults to 'date'. + * @type string $order Accepted values are 'ASC' or 'DESC'. Defaults to 'ASC'. + * } + * @param string $query_type Whether to select or count the results. Default, select. + * + * @return string|array|null The IDs of actions matching the query. Null on failure. + */ + abstract public function query_actions( $query = array(), $query_type = 'select' ); + + /** + * Run query to get a single action ID. + * + * @since 3.3.0 + * + * @see ActionScheduler_Store::query_actions for $query arg usage but 'per_page' and 'offset' can't be used. + * + * @param array $query Query parameters. + * + * @return int|null + */ + public function query_action( $query ) { + $query['per_page'] = 1; + $query['offset'] = 0; + $results = $this->query_actions( $query ); + + if ( empty( $results ) ) { + return null; + } else { + return (int) $results[0]; + } + } + + /** + * Get a count of all actions in the store, grouped by status + * + * @return array + */ + abstract public function action_counts(); + + /** + * Get additional action counts. + * + * - add past-due actions + * + * @return array + */ + public function extra_action_counts() { + $extra_actions = array(); + + $pastdue_action_counts = ( int ) $this->query_actions( array( + 'status' => self::STATUS_PENDING, + 'date' => as_get_datetime_object(), + ), 'count' ); + + if ( $pastdue_action_counts ) { + $extra_actions['past-due'] = $pastdue_action_counts; + } + + /** + * Allows 3rd party code to add extra action counts (used in filters in the list table). + * + * @since 3.5.0 + * @param $extra_actions array Array with format action_count_identifier => action count. + */ + return apply_filters( 'action_scheduler_extra_action_counts', $extra_actions ); + } + + /** + * @param string $action_id + */ + abstract public function cancel_action( $action_id ); + + /** + * @param string $action_id + */ + abstract public function delete_action( $action_id ); + + /** + * @param string $action_id + * + * @return DateTime The date the action is schedule to run, or the date that it ran. + */ + abstract public function get_date( $action_id ); + + + /** + * @param int $max_actions + * @param DateTime $before_date Claim only actions schedule before the given date. Defaults to now. + * @param array $hooks Claim only actions with a hook or hooks. + * @param string $group Claim only actions in the given group. + * + * @return ActionScheduler_ActionClaim + */ + abstract public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ); + + /** + * @return int + */ + abstract public function get_claim_count(); + + /** + * @param ActionScheduler_ActionClaim $claim + */ + abstract public function release_claim( ActionScheduler_ActionClaim $claim ); + + /** + * @param string $action_id + */ + abstract public function unclaim_action( $action_id ); + + /** + * @param string $action_id + */ + abstract public function mark_failure( $action_id ); + + /** + * @param string $action_id + */ + abstract public function log_execution( $action_id ); + + /** + * @param string $action_id + */ + abstract public function mark_complete( $action_id ); + + /** + * @param string $action_id + * + * @return string + */ + abstract public function get_status( $action_id ); + + /** + * @param string $action_id + * @return mixed + */ + abstract public function get_claim_id( $action_id ); + + /** + * @param string $claim_id + * @return array + */ + abstract public function find_actions_by_claim_id( $claim_id ); + + /** + * @param string $comparison_operator + * @return string + */ + protected function validate_sql_comparator( $comparison_operator ) { + if ( in_array( $comparison_operator, array('!=', '>', '>=', '<', '<=', '=') ) ) { + return $comparison_operator; + } + return '='; + } + + /** + * Get the time MySQL formated date/time string for an action's (next) scheduled date. + * + * @param ActionScheduler_Action $action + * @param DateTime $scheduled_date (optional) + * @return string + */ + protected function get_scheduled_date_string( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) { + $next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date; + if ( ! $next ) { + $next = date_create(); + } + $next->setTimezone( new DateTimeZone( 'UTC' ) ); + + return $next->format( 'Y-m-d H:i:s' ); + } + + /** + * Get the time MySQL formated date/time string for an action's (next) scheduled date. + * + * @param ActionScheduler_Action $action + * @param DateTime $scheduled_date (optional) + * @return string + */ + protected function get_scheduled_date_string_local( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) { + $next = null === $scheduled_date ? $action->get_schedule()->get_date() : $scheduled_date; + if ( ! $next ) { + $next = date_create(); + } + + ActionScheduler_TimezoneHelper::set_local_timezone( $next ); + return $next->format( 'Y-m-d H:i:s' ); + } + + /** + * Validate that we could decode action arguments. + * + * @param mixed $args The decoded arguments. + * @param int $action_id The action ID. + * + * @throws ActionScheduler_InvalidActionException When the decoded arguments are invalid. + */ + protected function validate_args( $args, $action_id ) { + // Ensure we have an array of args. + if ( ! is_array( $args ) ) { + throw ActionScheduler_InvalidActionException::from_decoding_args( $action_id ); + } + + // Validate JSON decoding if possible. + if ( function_exists( 'json_last_error' ) && JSON_ERROR_NONE !== json_last_error() ) { + throw ActionScheduler_InvalidActionException::from_decoding_args( $action_id, $args ); + } + } + + /** + * Validate a ActionScheduler_Schedule object. + * + * @param mixed $schedule The unserialized ActionScheduler_Schedule object. + * @param int $action_id The action ID. + * + * @throws ActionScheduler_InvalidActionException When the schedule is invalid. + */ + protected function validate_schedule( $schedule, $action_id ) { + if ( empty( $schedule ) || ! is_a( $schedule, 'ActionScheduler_Schedule' ) ) { + throw ActionScheduler_InvalidActionException::from_schedule( $action_id, $schedule ); + } + } + + /** + * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4. + * + * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However, + * with custom tables, we use an indexed VARCHAR column instead. + * + * @param ActionScheduler_Action $action Action to be validated. + * @throws InvalidArgumentException When json encoded args is too long. + */ + protected function validate_action( ActionScheduler_Action $action ) { + if ( strlen( json_encode( $action->get_args() ) ) > static::$max_args_length ) { + throw new InvalidArgumentException( sprintf( __( 'ActionScheduler_Action::$args too long. To ensure the args column can be indexed, action args should not be more than %d characters when encoded as JSON.', 'action-scheduler' ), static::$max_args_length ) ); + } + } + + /** + * Cancel pending actions by hook. + * + * @since 3.0.0 + * + * @param string $hook Hook name. + * + * @return void + */ + public function cancel_actions_by_hook( $hook ) { + $action_ids = true; + while ( ! empty( $action_ids ) ) { + $action_ids = $this->query_actions( + array( + 'hook' => $hook, + 'status' => self::STATUS_PENDING, + 'per_page' => 1000, + 'orderby' => 'action_id', + ) + ); + + $this->bulk_cancel_actions( $action_ids ); + } + } + + /** + * Cancel pending actions by group. + * + * @since 3.0.0 + * + * @param string $group Group slug. + * + * @return void + */ + public function cancel_actions_by_group( $group ) { + $action_ids = true; + while ( ! empty( $action_ids ) ) { + $action_ids = $this->query_actions( + array( + 'group' => $group, + 'status' => self::STATUS_PENDING, + 'per_page' => 1000, + 'orderby' => 'action_id', + ) + ); + + $this->bulk_cancel_actions( $action_ids ); + } + } + + /** + * Cancel a set of action IDs. + * + * @since 3.0.0 + * + * @param array $action_ids List of action IDs. + * + * @return void + */ + private function bulk_cancel_actions( $action_ids ) { + foreach ( $action_ids as $action_id ) { + $this->cancel_action( $action_id ); + } + + do_action( 'action_scheduler_bulk_cancel_actions', $action_ids ); + } + + /** + * @return array + */ + public function get_status_labels() { + return array( + self::STATUS_COMPLETE => __( 'Complete', 'action-scheduler' ), + self::STATUS_PENDING => __( 'Pending', 'action-scheduler' ), + self::STATUS_RUNNING => __( 'In-progress', 'action-scheduler' ), + self::STATUS_FAILED => __( 'Failed', 'action-scheduler' ), + self::STATUS_CANCELED => __( 'Canceled', 'action-scheduler' ), + ); + } + + /** + * Check if there are any pending scheduled actions due to run. + * + * @param ActionScheduler_Action $action + * @param DateTime $scheduled_date (optional) + * @return string + */ + public function has_pending_actions_due() { + $pending_actions = $this->query_actions( array( + 'date' => as_get_datetime_object(), + 'status' => ActionScheduler_Store::STATUS_PENDING, + 'orderby' => 'none', + ) ); + + return ! empty( $pending_actions ); + } + + /** + * Callable initialization function optionally overridden in derived classes. + */ + public function init() {} + + /** + * Callable function to mark an action as migrated optionally overridden in derived classes. + */ + public function mark_migrated( $action_id ) {} + + /** + * @return ActionScheduler_Store + */ + public static function instance() { + if ( empty( self::$store ) ) { + $class = apply_filters( 'action_scheduler_store_class', self::DEFAULT_CLASS ); + self::$store = new $class(); + } + return self::$store; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_TimezoneHelper.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_TimezoneHelper.php new file mode 100644 index 000000000..fd0144941 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/abstracts/ActionScheduler_TimezoneHelper.php @@ -0,0 +1,152 @@ +format( 'U' ) ); + } + + if ( get_option( 'timezone_string' ) ) { + $date->setTimezone( new DateTimeZone( self::get_local_timezone_string() ) ); + } else { + $date->setUtcOffset( self::get_local_timezone_offset() ); + } + + return $date; + } + + /** + * Helper to retrieve the timezone string for a site until a WP core method exists + * (see https://core.trac.wordpress.org/ticket/24730). + * + * Adapted from wc_timezone_string() and https://secure.php.net/manual/en/function.timezone-name-from-abbr.php#89155. + * + * If no timezone string is set, and its not possible to match the UTC offset set for the site to a timezone + * string, then an empty string will be returned, and the UTC offset should be used to set a DateTime's + * timezone. + * + * @since 2.1.0 + * @return string PHP timezone string for the site or empty if no timezone string is available. + */ + protected static function get_local_timezone_string( $reset = false ) { + // If site timezone string exists, return it. + $timezone = get_option( 'timezone_string' ); + if ( $timezone ) { + return $timezone; + } + + // Get UTC offset, if it isn't set then return UTC. + $utc_offset = intval( get_option( 'gmt_offset', 0 ) ); + if ( 0 === $utc_offset ) { + return 'UTC'; + } + + // Adjust UTC offset from hours to seconds. + $utc_offset *= 3600; + + // Attempt to guess the timezone string from the UTC offset. + $timezone = timezone_name_from_abbr( '', $utc_offset ); + if ( $timezone ) { + return $timezone; + } + + // Last try, guess timezone string manually. + foreach ( timezone_abbreviations_list() as $abbr ) { + foreach ( $abbr as $city ) { + if ( (bool) date( 'I' ) === (bool) $city['dst'] && $city['timezone_id'] && intval( $city['offset'] ) === $utc_offset ) { + return $city['timezone_id']; + } + } + } + + // No timezone string + return ''; + } + + /** + * Get timezone offset in seconds. + * + * @since 2.1.0 + * @return float + */ + protected static function get_local_timezone_offset() { + $timezone = get_option( 'timezone_string' ); + + if ( $timezone ) { + $timezone_object = new DateTimeZone( $timezone ); + return $timezone_object->getOffset( new DateTime( 'now' ) ); + } else { + return floatval( get_option( 'gmt_offset', 0 ) ) * HOUR_IN_SECONDS; + } + } + + /** + * @deprecated 2.1.0 + */ + public static function get_local_timezone( $reset = FALSE ) { + _deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' ); + if ( $reset ) { + self::$local_timezone = NULL; + } + if ( !isset(self::$local_timezone) ) { + $tzstring = get_option('timezone_string'); + + if ( empty($tzstring) ) { + $gmt_offset = get_option('gmt_offset'); + if ( $gmt_offset == 0 ) { + $tzstring = 'UTC'; + } else { + $gmt_offset *= HOUR_IN_SECONDS; + $tzstring = timezone_name_from_abbr( '', $gmt_offset, 1 ); + + // If there's no timezone string, try again with no DST. + if ( false === $tzstring ) { + $tzstring = timezone_name_from_abbr( '', $gmt_offset, 0 ); + } + + // Try mapping to the first abbreviation we can find. + if ( false === $tzstring ) { + $is_dst = date( 'I' ); + foreach ( timezone_abbreviations_list() as $abbr ) { + foreach ( $abbr as $city ) { + if ( $city['dst'] == $is_dst && $city['offset'] == $gmt_offset ) { + // If there's no valid timezone ID, keep looking. + if ( null === $city['timezone_id'] ) { + continue; + } + + $tzstring = $city['timezone_id']; + break 2; + } + } + } + } + + // If we still have no valid string, then fall back to UTC. + if ( false === $tzstring ) { + $tzstring = 'UTC'; + } + } + } + + self::$local_timezone = new DateTimeZone($tzstring); + } + return self::$local_timezone; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_Action.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_Action.php new file mode 100644 index 000000000..f538f506b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_Action.php @@ -0,0 +1,96 @@ +set_hook($hook); + $this->set_schedule($schedule); + $this->set_args($args); + $this->set_group($group); + } + + /** + * Executes the action. + * + * If no callbacks are registered, an exception will be thrown and the action will not be + * fired. This is useful to help detect cases where the code responsible for setting up + * a scheduled action no longer exists. + * + * @throws Exception If no callbacks are registered for this action. + */ + public function execute() { + $hook = $this->get_hook(); + + if ( ! has_action( $hook ) ) { + throw new Exception( + sprintf( + /* translators: 1: action hook. */ + __( 'Scheduled action for %1$s will not be executed as no callbacks are registered.', 'action-scheduler' ), + $hook + ) + ); + } + + do_action_ref_array( $hook, array_values( $this->get_args() ) ); + } + + /** + * @param string $hook + */ + protected function set_hook( $hook ) { + $this->hook = $hook; + } + + public function get_hook() { + return $this->hook; + } + + protected function set_schedule( ActionScheduler_Schedule $schedule ) { + $this->schedule = $schedule; + } + + /** + * @return ActionScheduler_Schedule + */ + public function get_schedule() { + return $this->schedule; + } + + protected function set_args( array $args ) { + $this->args = $args; + } + + public function get_args() { + return $this->args; + } + + /** + * @param string $group + */ + protected function set_group( $group ) { + $this->group = $group; + } + + /** + * @return string + */ + public function get_group() { + return $this->group; + } + + /** + * @return bool If the action has been finished + */ + public function is_finished() { + return FALSE; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_CanceledAction.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_CanceledAction.php new file mode 100644 index 000000000..8bbc5d18d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_CanceledAction.php @@ -0,0 +1,23 @@ +set_schedule( new ActionScheduler_NullSchedule() ); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_FinishedAction.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_FinishedAction.php new file mode 100644 index 000000000..b23a56c66 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/actions/ActionScheduler_FinishedAction.php @@ -0,0 +1,16 @@ +set_schedule( new ActionScheduler_NullSchedule() ); + } + + public function execute() { + // don't execute + } +} + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_DBLogger.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_DBLogger.php new file mode 100644 index 000000000..37bfd0d44 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_DBLogger.php @@ -0,0 +1,154 @@ +format( 'Y-m-d H:i:s' ); + ActionScheduler_TimezoneHelper::set_local_timezone( $date ); + $date_local = $date->format( 'Y-m-d H:i:s' ); + + /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort + global $wpdb; + $wpdb->insert( + $wpdb->actionscheduler_logs, + array( + 'action_id' => $action_id, + 'message' => $message, + 'log_date_gmt' => $date_gmt, + 'log_date_local' => $date_local, + ), + array( '%d', '%s', '%s', '%s' ) + ); + + return $wpdb->insert_id; + } + + /** + * Retrieve an action log entry. + * + * @param int $entry_id Log entry ID. + * + * @return ActionScheduler_LogEntry + */ + public function get_entry( $entry_id ) { + /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort + global $wpdb; + $entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) ); + + return $this->create_entry_from_db_record( $entry ); + } + + /** + * Create an action log entry from a database record. + * + * @param object $record Log entry database record object. + * + * @return ActionScheduler_LogEntry + */ + private function create_entry_from_db_record( $record ) { + if ( empty( $record ) ) { + return new ActionScheduler_NullLogEntry(); + } + + if ( is_null( $record->log_date_gmt ) ) { + $date = as_get_datetime_object( ActionScheduler_StoreSchema::DEFAULT_DATE ); + } else { + $date = as_get_datetime_object( $record->log_date_gmt ); + } + + return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date ); + } + + /** + * Retrieve the an action's log entries from the database. + * + * @param int $action_id Action ID. + * + * @return ActionScheduler_LogEntry[] + */ + public function get_logs( $action_id ) { + /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort + global $wpdb; + + $records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) ); + + return array_map( array( $this, 'create_entry_from_db_record' ), $records ); + } + + /** + * Initialize the data store. + * + * @codeCoverageIgnore + */ + public function init() { + $table_maker = new ActionScheduler_LoggerSchema(); + $table_maker->init(); + $table_maker->register_tables(); + + parent::init(); + + add_action( 'action_scheduler_deleted_action', array( $this, 'clear_deleted_action_logs' ), 10, 1 ); + } + + /** + * Delete the action logs for an action. + * + * @param int $action_id Action ID. + */ + public function clear_deleted_action_logs( $action_id ) { + /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort + global $wpdb; + $wpdb->delete( $wpdb->actionscheduler_logs, array( 'action_id' => $action_id ), array( '%d' ) ); + } + + /** + * Bulk add cancel action log entries. + * + * @param array $action_ids List of action ID. + */ + public function bulk_log_cancel_actions( $action_ids ) { + if ( empty( $action_ids ) ) { + return; + } + + /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort + global $wpdb; + $date = as_get_datetime_object(); + $date_gmt = $date->format( 'Y-m-d H:i:s' ); + ActionScheduler_TimezoneHelper::set_local_timezone( $date ); + $date_local = $date->format( 'Y-m-d H:i:s' ); + $message = __( 'action canceled', 'action-scheduler' ); + $format = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')'; + $sql_query = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES "; + $value_rows = array(); + + foreach ( $action_ids as $action_id ) { + $value_rows[] = $wpdb->prepare( $format, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + $sql_query .= implode( ',', $value_rows ); + + $wpdb->query( $sql_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_DBStore.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_DBStore.php new file mode 100644 index 000000000..5009454f7 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_DBStore.php @@ -0,0 +1,1081 @@ +init(); + $table_maker->register_tables(); + } + + /** + * Save an action, checks if this is a unique action before actually saving. + * + * @param ActionScheduler_Action $action Action object. + * @param \DateTime $scheduled_date Optional schedule date. Default null. + * + * @return int Action ID. + * @throws RuntimeException Throws exception when saving the action fails. + */ + public function save_unique_action( ActionScheduler_Action $action, \DateTime $scheduled_date = null ) { + return $this->save_action_to_db( $action, $scheduled_date, true ); + } + + /** + * Save an action. Can save duplicate action as well, prefer using `save_unique_action` instead. + * + * @param ActionScheduler_Action $action Action object. + * @param \DateTime $scheduled_date Optional schedule date. Default null. + * + * @return int Action ID. + * @throws RuntimeException Throws exception when saving the action fails. + */ + public function save_action( ActionScheduler_Action $action, \DateTime $scheduled_date = null ) { + return $this->save_action_to_db( $action, $scheduled_date, false ); + } + + /** + * Save an action. + * + * @param ActionScheduler_Action $action Action object. + * @param ?DateTime $date Optional schedule date. Default null. + * @param bool $unique Whether the action should be unique. + * + * @return int Action ID. + * @throws RuntimeException Throws exception when saving the action fails. + */ + private function save_action_to_db( ActionScheduler_Action $action, DateTime $date = null, $unique = false ) { + global $wpdb; + + try { + $this->validate_action( $action ); + + $data = array( + 'hook' => $action->get_hook(), + 'status' => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ), + 'scheduled_date_gmt' => $this->get_scheduled_date_string( $action, $date ), + 'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ), + 'schedule' => serialize( $action->get_schedule() ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize + 'group_id' => $this->get_group_id( $action->get_group() ), + ); + + $args = wp_json_encode( $action->get_args() ); + if ( strlen( $args ) <= static::$max_index_length ) { + $data['args'] = $args; + } else { + $data['args'] = $this->hash_args( $args ); + $data['extended_args'] = $args; + } + + $insert_sql = $this->build_insert_sql( $data, $unique ); + + // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $insert_sql should be already prepared. + $wpdb->query( $insert_sql ); + $action_id = $wpdb->insert_id; + + if ( is_wp_error( $action_id ) ) { + throw new \RuntimeException( $action_id->get_error_message() ); + } elseif ( empty( $action_id ) ) { + if ( $unique ) { + return 0; + } + throw new \RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) ); + } + + do_action( 'action_scheduler_stored_action', $action_id ); + + return $action_id; + } catch ( \Exception $e ) { + /* translators: %s: error message */ + throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 ); + } + } + + /** + * Helper function to build insert query. + * + * @param array $data Row data for action. + * @param bool $unique Whether the action should be unique. + * + * @return string Insert query. + */ + private function build_insert_sql( array $data, $unique ) { + global $wpdb; + $columns = array_keys( $data ); + $values = array_values( $data ); + $placeholders = array_map( array( $this, 'get_placeholder_for_column' ), $columns ); + + $table_name = ! empty( $wpdb->actionscheduler_actions ) ? $wpdb->actionscheduler_actions : $wpdb->prefix . 'actionscheduler_actions'; + + $column_sql = '`' . implode( '`, `', $columns ) . '`'; + $placeholder_sql = implode( ', ', $placeholders ); + $where_clause = $this->build_where_clause_for_insert( $data, $table_name, $unique ); + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $column_sql and $where_clause are already prepared. $placeholder_sql is hardcoded. + $insert_query = $wpdb->prepare( + " +INSERT INTO $table_name ( $column_sql ) +SELECT $placeholder_sql FROM DUAL +WHERE ( $where_clause ) IS NULL", + $values + ); + // phpcs:enable + + return $insert_query; + } + + /** + * Helper method to build where clause for action insert statement. + * + * @param array $data Row data for action. + * @param string $table_name Action table name. + * @param bool $unique Where action should be unique. + * + * @return string Where clause to be used with insert. + */ + private function build_where_clause_for_insert( $data, $table_name, $unique ) { + global $wpdb; + + if ( ! $unique ) { + return 'SELECT NULL FROM DUAL'; + } + + $pending_statuses = array( + ActionScheduler_Store::STATUS_PENDING, + ActionScheduler_Store::STATUS_RUNNING, + ); + $pending_status_placeholders = implode( ', ', array_fill( 0, count( $pending_statuses ), '%s' ) ); + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $pending_status_placeholders is hardcoded. + $where_clause = $wpdb->prepare( + " +SELECT action_id FROM $table_name +WHERE status IN ( $pending_status_placeholders ) +AND hook = %s +AND `group_id` = %d +", + array_merge( + $pending_statuses, + array( + $data['hook'], + $data['group_id'], + ) + ) + ); + // phpcs:enable + + return "$where_clause" . ' LIMIT 1'; + } + + /** + * Helper method to get $wpdb->prepare placeholder for a given column name. + * + * @param string $column_name Name of column in actions table. + * + * @return string Placeholder to use for given column. + */ + private function get_placeholder_for_column( $column_name ) { + $string_columns = array( + 'hook', + 'status', + 'scheduled_date_gmt', + 'scheduled_date_local', + 'args', + 'schedule', + 'last_attempt_gmt', + 'last_attempt_local', + 'extended_args', + ); + + return in_array( $column_name, $string_columns ) ? '%s' : '%d'; + } + + /** + * Generate a hash from json_encoded $args using MD5 as this isn't for security. + * + * @param string $args JSON encoded action args. + * @return string + */ + protected function hash_args( $args ) { + return md5( $args ); + } + + /** + * Get action args query param value from action args. + * + * @param array $args Action args. + * @return string + */ + protected function get_args_for_query( $args ) { + $encoded = wp_json_encode( $args ); + if ( strlen( $encoded ) <= static::$max_index_length ) { + return $encoded; + } + return $this->hash_args( $encoded ); + } + /** + * Get a group's ID based on its name/slug. + * + * @param string $slug The string name of a group. + * @param bool $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group. + * + * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created. + */ + protected function get_group_id( $slug, $create_if_not_exists = true ) { + if ( empty( $slug ) ) { + return 0; + } + /** @var \wpdb $wpdb */ + global $wpdb; + $group_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug ) ); + if ( empty( $group_id ) && $create_if_not_exists ) { + $group_id = $this->create_group( $slug ); + } + + return $group_id; + } + + /** + * Create an action group. + * + * @param string $slug Group slug. + * + * @return int Group ID. + */ + protected function create_group( $slug ) { + /** @var \wpdb $wpdb */ + global $wpdb; + $wpdb->insert( $wpdb->actionscheduler_groups, array( 'slug' => $slug ) ); + + return (int) $wpdb->insert_id; + } + + /** + * Retrieve an action. + * + * @param int $action_id Action ID. + * + * @return ActionScheduler_Action + */ + public function fetch_action( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + $data = $wpdb->get_row( + $wpdb->prepare( + "SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d", + $action_id + ) + ); + + if ( empty( $data ) ) { + return $this->get_null_action(); + } + + if ( ! empty( $data->extended_args ) ) { + $data->args = $data->extended_args; + unset( $data->extended_args ); + } + + // Convert NULL dates to zero dates. + $date_fields = array( + 'scheduled_date_gmt', + 'scheduled_date_local', + 'last_attempt_gmt', + 'last_attempt_gmt', + ); + foreach ( $date_fields as $date_field ) { + if ( is_null( $data->$date_field ) ) { + $data->$date_field = ActionScheduler_StoreSchema::DEFAULT_DATE; + } + } + + try { + $action = $this->make_action_from_db_record( $data ); + } catch ( ActionScheduler_InvalidActionException $exception ) { + do_action( 'action_scheduler_failed_fetch_action', $action_id, $exception ); + return $this->get_null_action(); + } + + return $action; + } + + /** + * Create a null action. + * + * @return ActionScheduler_NullAction + */ + protected function get_null_action() { + return new ActionScheduler_NullAction(); + } + + /** + * Create an action from a database record. + * + * @param object $data Action database record. + * + * @return ActionScheduler_Action|ActionScheduler_CanceledAction|ActionScheduler_FinishedAction + */ + protected function make_action_from_db_record( $data ) { + + $hook = $data->hook; + $args = json_decode( $data->args, true ); + $schedule = unserialize( $data->schedule ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize + + $this->validate_args( $args, $data->action_id ); + $this->validate_schedule( $schedule, $data->action_id ); + + if ( empty( $schedule ) ) { + $schedule = new ActionScheduler_NullSchedule(); + } + $group = $data->group ? $data->group : ''; + + return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group ); + } + + /** + * Returns the SQL statement to query (or count) actions. + * + * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status. + * + * @param array $query Filtering options. + * @param string $select_or_count Whether the SQL should select and return the IDs or just the row count. + * + * @return string SQL statement already properly escaped. + * @throws InvalidArgumentException If the query is invalid. + */ + protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) { + + if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) { + throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) ); + } + + $query = wp_parse_args( $query, array( + 'hook' => '', + 'args' => null, + 'partial_args_matching' => 'off', // can be 'like' or 'json' + 'date' => null, + 'date_compare' => '<=', + 'modified' => null, + 'modified_compare' => '<=', + 'group' => '', + 'status' => '', + 'claimed' => null, + 'per_page' => 5, + 'offset' => 0, + 'orderby' => 'date', + 'order' => 'ASC', + ) ); + + /** @var \wpdb $wpdb */ + global $wpdb; + + $db_server_info = is_callable( array( $wpdb, 'db_server_info' ) ) ? $wpdb->db_server_info() : $wpdb->db_version(); + if ( false !== strpos( $db_server_info, 'MariaDB' ) ) { + $supports_json = version_compare( + PHP_VERSION_ID >= 80016 ? $wpdb->db_version() : preg_replace( '/[^0-9.].*/', '', str_replace( '5.5.5-', '', $db_server_info ) ), + '10.2', + '>=' + ); + } else { + $supports_json = version_compare( $wpdb->db_version(), '5.7', '>=' ); + } + + $sql = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id'; + $sql .= " FROM {$wpdb->actionscheduler_actions} a"; + $sql_params = array(); + + if ( ! empty( $query['group'] ) || 'group' === $query['orderby'] ) { + $sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id"; + } + + $sql .= " WHERE 1=1"; + + if ( ! empty( $query['group'] ) ) { + $sql .= " AND g.slug=%s"; + $sql_params[] = $query['group']; + } + + if ( ! empty( $query['hook'] ) ) { + $sql .= " AND a.hook=%s"; + $sql_params[] = $query['hook']; + } + + if ( ! is_null( $query['args'] ) ) { + switch ( $query['partial_args_matching'] ) { + case 'json': + if ( ! $supports_json ) { + throw new \RuntimeException( __( 'JSON partial matching not supported in your environment. Please check your MySQL/MariaDB version.', 'action-scheduler' ) ); + } + $supported_types = array( + 'integer' => '%d', + 'boolean' => '%s', + 'double' => '%f', + 'string' => '%s', + ); + foreach ( $query['args'] as $key => $value ) { + $value_type = gettype( $value ); + if ( 'boolean' === $value_type ) { + $value = $value ? 'true' : 'false'; + } + $placeholder = isset( $supported_types[ $value_type ] ) ? $supported_types[ $value_type ] : false; + if ( ! $placeholder ) { + throw new \RuntimeException( sprintf( + /* translators: %s: provided value type */ + __( 'The value type for the JSON partial matching is not supported. Must be either integer, boolean, double or string. %s type provided.', 'action-scheduler' ), + $value_type + ) ); + } + $sql .= ' AND JSON_EXTRACT(a.args, %s)='.$placeholder; + $sql_params[] = '$.'.$key; + $sql_params[] = $value; + } + break; + case 'like': + foreach ( $query['args'] as $key => $value ) { + $sql .= ' AND a.args LIKE %s'; + $json_partial = $wpdb->esc_like( trim( json_encode( array( $key => $value ) ), '{}' ) ); + $sql_params[] = "%{$json_partial}%"; + } + break; + case 'off': + $sql .= " AND a.args=%s"; + $sql_params[] = $this->get_args_for_query( $query['args'] ); + break; + default: + throw new \RuntimeException( __( 'Unknown partial args matching value.', 'action-scheduler' ) ); + } + } + + if ( $query['status'] ) { + $statuses = (array) $query['status']; + $placeholders = array_fill( 0, count( $statuses ), '%s' ); + $sql .= ' AND a.status IN (' . join( ', ', $placeholders ) . ')'; + $sql_params = array_merge( $sql_params, array_values( $statuses ) ); + } + + if ( $query['date'] instanceof \DateTime ) { + $date = clone $query['date']; + $date->setTimezone( new \DateTimeZone( 'UTC' ) ); + $date_string = $date->format( 'Y-m-d H:i:s' ); + $comparator = $this->validate_sql_comparator( $query['date_compare'] ); + $sql .= " AND a.scheduled_date_gmt $comparator %s"; + $sql_params[] = $date_string; + } + + if ( $query['modified'] instanceof \DateTime ) { + $modified = clone $query['modified']; + $modified->setTimezone( new \DateTimeZone( 'UTC' ) ); + $date_string = $modified->format( 'Y-m-d H:i:s' ); + $comparator = $this->validate_sql_comparator( $query['modified_compare'] ); + $sql .= " AND a.last_attempt_gmt $comparator %s"; + $sql_params[] = $date_string; + } + + if ( true === $query['claimed'] ) { + $sql .= ' AND a.claim_id != 0'; + } elseif ( false === $query['claimed'] ) { + $sql .= ' AND a.claim_id = 0'; + } elseif ( ! is_null( $query['claimed'] ) ) { + $sql .= ' AND a.claim_id = %d'; + $sql_params[] = $query['claimed']; + } + + if ( ! empty( $query['search'] ) ) { + $sql .= ' AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s'; + for ( $i = 0; $i < 3; $i++ ) { + $sql_params[] = sprintf( '%%%s%%', $query['search'] ); + } + + $search_claim_id = (int) $query['search']; + if ( $search_claim_id ) { + $sql .= ' OR a.claim_id = %d'; + $sql_params[] = $search_claim_id; + } + + $sql .= ')'; + } + + if ( 'select' === $select_or_count ) { + if ( 'ASC' === strtoupper( $query['order'] ) ) { + $order = 'ASC'; + } else { + $order = 'DESC'; + } + switch ( $query['orderby'] ) { + case 'hook': + $sql .= " ORDER BY a.hook $order"; + break; + case 'group': + $sql .= " ORDER BY g.slug $order"; + break; + case 'modified': + $sql .= " ORDER BY a.last_attempt_gmt $order"; + break; + case 'none': + break; + case 'action_id': + $sql .= " ORDER BY a.action_id $order"; + break; + case 'date': + default: + $sql .= " ORDER BY a.scheduled_date_gmt $order"; + break; + } + + if ( $query['per_page'] > 0 ) { + $sql .= ' LIMIT %d, %d'; + $sql_params[] = $query['offset']; + $sql_params[] = $query['per_page']; + } + } + + if ( ! empty( $sql_params ) ) { + $sql = $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + return $sql; + } + + /** + * Query for action count or list of action IDs. + * + * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status. + * + * @see ActionScheduler_Store::query_actions for $query arg usage. + * + * @param array $query Query filtering options. + * @param string $query_type Whether to select or count the results. Defaults to select. + * + * @return string|array|null The IDs of actions matching the query. Null on failure. + */ + public function query_actions( $query = array(), $query_type = 'select' ) { + /** @var wpdb $wpdb */ + global $wpdb; + + $sql = $this->get_query_actions_sql( $query, $query_type ); + + return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoSql, WordPress.DB.DirectDatabaseQuery.NoCaching + } + + /** + * Get a count of all actions in the store, grouped by status. + * + * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status. + */ + public function action_counts() { + global $wpdb; + + $sql = "SELECT a.status, count(a.status) as 'count'"; + $sql .= " FROM {$wpdb->actionscheduler_actions} a"; + $sql .= ' GROUP BY a.status'; + + $actions_count_by_status = array(); + $action_stati_and_labels = $this->get_status_labels(); + + foreach ( $wpdb->get_results( $sql ) as $action_data ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + // Ignore any actions with invalid status. + if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) { + $actions_count_by_status[ $action_data->status ] = $action_data->count; + } + } + + return $actions_count_by_status; + } + + /** + * Cancel an action. + * + * @param int $action_id Action ID. + * + * @return void + * @throws \InvalidArgumentException If the action update failed. + */ + public function cancel_action( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + + $updated = $wpdb->update( + $wpdb->actionscheduler_actions, + array( 'status' => self::STATUS_CANCELED ), + array( 'action_id' => $action_id ), + array( '%s' ), + array( '%d' ) + ); + if ( false === $updated ) { + /* translators: %s: action ID */ + throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); + } + do_action( 'action_scheduler_canceled_action', $action_id ); + } + + /** + * Cancel pending actions by hook. + * + * @since 3.0.0 + * + * @param string $hook Hook name. + * + * @return void + */ + public function cancel_actions_by_hook( $hook ) { + $this->bulk_cancel_actions( array( 'hook' => $hook ) ); + } + + /** + * Cancel pending actions by group. + * + * @param string $group Group slug. + * + * @return void + */ + public function cancel_actions_by_group( $group ) { + $this->bulk_cancel_actions( array( 'group' => $group ) ); + } + + /** + * Bulk cancel actions. + * + * @since 3.0.0 + * + * @param array $query_args Query parameters. + */ + protected function bulk_cancel_actions( $query_args ) { + /** @var \wpdb $wpdb */ + global $wpdb; + + if ( ! is_array( $query_args ) ) { + return; + } + + // Don't cancel actions that are already canceled. + if ( isset( $query_args['status'] ) && self::STATUS_CANCELED === $query_args['status'] ) { + return; + } + + $action_ids = true; + $query_args = wp_parse_args( + $query_args, + array( + 'per_page' => 1000, + 'status' => self::STATUS_PENDING, + 'orderby' => 'action_id', + ) + ); + + while ( $action_ids ) { + $action_ids = $this->query_actions( $query_args ); + if ( empty( $action_ids ) ) { + break; + } + + $format = array_fill( 0, count( $action_ids ), '%d' ); + $query_in = '(' . implode( ',', $format ) . ')'; + $parameters = $action_ids; + array_unshift( $parameters, self::STATUS_CANCELED ); + + $wpdb->query( + $wpdb->prepare( + "UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $parameters + ) + ); + + do_action( 'action_scheduler_bulk_cancel_actions', $action_ids ); + } + } + + /** + * Delete an action. + * + * @param int $action_id Action ID. + * @throws \InvalidArgumentException If the action deletion failed. + */ + public function delete_action( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + $deleted = $wpdb->delete( $wpdb->actionscheduler_actions, array( 'action_id' => $action_id ), array( '%d' ) ); + if ( empty( $deleted ) ) { + throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment + } + do_action( 'action_scheduler_deleted_action', $action_id ); + } + + /** + * Get the schedule date for an action. + * + * @param string $action_id Action ID. + * + * @return \DateTime The local date the action is scheduled to run, or the date that it ran. + */ + public function get_date( $action_id ) { + $date = $this->get_date_gmt( $action_id ); + ActionScheduler_TimezoneHelper::set_local_timezone( $date ); + return $date; + } + + /** + * Get the GMT schedule date for an action. + * + * @param int $action_id Action ID. + * + * @throws \InvalidArgumentException If action cannot be identified. + * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran. + */ + protected function get_date_gmt( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + $record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) ); + if ( empty( $record ) ) { + throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment + } + if ( self::STATUS_PENDING === $record->status ) { + return as_get_datetime_object( $record->scheduled_date_gmt ); + } else { + return as_get_datetime_object( $record->last_attempt_gmt ); + } + } + + /** + * Stake a claim on actions. + * + * @param int $max_actions Maximum number of action to include in claim. + * @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now. + * @param array $hooks Hooks to filter for. + * @param string $group Group to filter for. + * + * @return ActionScheduler_ActionClaim + */ + public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) { + $claim_id = $this->generate_claim_id(); + + $this->claim_before_date = $before_date; + $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group ); + $action_ids = $this->find_actions_by_claim_id( $claim_id ); + $this->claim_before_date = null; + + return new ActionScheduler_ActionClaim( $claim_id, $action_ids ); + } + + /** + * Generate a new action claim. + * + * @return int Claim ID. + */ + protected function generate_claim_id() { + /** @var \wpdb $wpdb */ + global $wpdb; + $now = as_get_datetime_object(); + $wpdb->insert( $wpdb->actionscheduler_claims, array( 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ) ); + + return $wpdb->insert_id; + } + + /** + * Mark actions claimed. + * + * @param string $claim_id Claim Id. + * @param int $limit Number of action to include in claim. + * @param \DateTime $before_date Should use UTC timezone. + * @param array $hooks Hooks to filter for. + * @param string $group Group to filter for. + * + * @return int The number of actions that were claimed. + * @throws \InvalidArgumentException Throws InvalidArgumentException if group doesn't exist. + * @throws \RuntimeException Throws RuntimeException if unable to claim action. + */ + protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) { + /** @var \wpdb $wpdb */ + global $wpdb; + + $now = as_get_datetime_object(); + $date = is_null( $before_date ) ? $now : clone $before_date; + + // can't use $wpdb->update() because of the <= condition. + $update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s"; + $params = array( + $claim_id, + $now->format( 'Y-m-d H:i:s' ), + current_time( 'mysql' ), + ); + + $where = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s'; + $params[] = $date->format( 'Y-m-d H:i:s' ); + $params[] = self::STATUS_PENDING; + + if ( ! empty( $hooks ) ) { + $placeholders = array_fill( 0, count( $hooks ), '%s' ); + $where .= ' AND hook IN (' . join( ', ', $placeholders ) . ')'; + $params = array_merge( $params, array_values( $hooks ) ); + } + + if ( ! empty( $group ) ) { + + $group_id = $this->get_group_id( $group, false ); + + // throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour. + if ( empty( $group_id ) ) { + /* translators: %s: group name */ + throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) ); + } + + $where .= ' AND group_id = %d'; + $params[] = $group_id; + } + + /** + * Sets the order-by clause used in the action claim query. + * + * @since 3.4.0 + * + * @param string $order_by_sql + */ + $order = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC' ); + $params[] = $limit; + + $sql = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders + $rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + if ( false === $rows_affected ) { + throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) ); + } + + return (int) $rows_affected; + } + + /** + * Get the number of active claims. + * + * @return int + */ + public function get_claim_count() { + global $wpdb; + + $sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)"; + $sql = $wpdb->prepare( $sql, array( self::STATUS_PENDING, self::STATUS_RUNNING ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + /** + * Return an action's claim ID, as stored in the claim_id column. + * + * @param string $action_id Action ID. + * @return mixed + */ + public function get_claim_id( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + + $sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d"; + $sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + /** + * Retrieve the action IDs of action in a claim. + * + * @param int $claim_id Claim ID. + * @return int[] + */ + public function find_actions_by_claim_id( $claim_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + + $action_ids = array(); + $before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object(); + $cut_off = $before_date->format( 'Y-m-d H:i:s' ); + + $sql = $wpdb->prepare( + "SELECT action_id, scheduled_date_gmt FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d", + $claim_id + ); + + // Verify that the scheduled date for each action is within the expected bounds (in some unusual + // cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify). + foreach ( $wpdb->get_results( $sql ) as $claimed_action ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + if ( $claimed_action->scheduled_date_gmt <= $cut_off ) { + $action_ids[] = absint( $claimed_action->action_id ); + } + } + + return $action_ids; + } + + /** + * Release actions from a claim and delete the claim. + * + * @param ActionScheduler_ActionClaim $claim Claim object. + */ + public function release_claim( ActionScheduler_ActionClaim $claim ) { + /** @var \wpdb $wpdb */ + global $wpdb; + /** + * Deadlock warning: This function modifies actions to release them from claims that have been processed. Earlier, we used to it in a atomic query, i.e. we would update all actions belonging to a particular claim_id with claim_id = 0. + * While this was functionally correct, it would cause deadlock, since this update query will hold a lock on the claim_id_.. index on the action table. + * This allowed the possibility of a race condition, where the claimer query is also running at the same time, then the claimer query will also try to acquire a lock on the claim_id_.. index, and in this case if claim release query has already progressed to the point of acquiring the lock, but have not updated yet, it would cause a deadlock. + * + * We resolve this by getting all the actions_id that we want to release claim from in a separate query, and then releasing the claim on each of them. This way, our lock is acquired on the action_id index instead of the claim_id index. Note that the lock on claim_id will still be acquired, but it will only when we actually make the update, rather than when we select the actions. + */ + $action_ids = $wpdb->get_col( $wpdb->prepare( "SELECT action_id FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d", $claim->get_id() ) ); + + $row_updates = 0; + if ( count( $action_ids ) > 0 ) { + $action_id_string = implode( ',', array_map( 'absint', $action_ids ) ); + $row_updates = $wpdb->query( "UPDATE {$wpdb->actionscheduler_actions} SET claim_id = 0 WHERE action_id IN ({$action_id_string})" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + $wpdb->delete( $wpdb->actionscheduler_claims, array( 'claim_id' => $claim->get_id() ), array( '%d' ) ); + + if ( $row_updates < count( $action_ids ) ) { + throw new RuntimeException( + sprintf( + __( 'Unable to release actions from claim id %d.', 'woocommerce' ), + $claim->get_id() + ) + ); + } + } + + /** + * Remove the claim from an action. + * + * @param int $action_id Action ID. + * + * @return void + */ + public function unclaim_action( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + $wpdb->update( + $wpdb->actionscheduler_actions, + array( 'claim_id' => 0 ), + array( 'action_id' => $action_id ), + array( '%s' ), + array( '%d' ) + ); + } + + /** + * Mark an action as failed. + * + * @param int $action_id Action ID. + * @throws \InvalidArgumentException Throw an exception if action was not updated. + */ + public function mark_failure( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + $updated = $wpdb->update( + $wpdb->actionscheduler_actions, + array( 'status' => self::STATUS_FAILED ), + array( 'action_id' => $action_id ), + array( '%s' ), + array( '%d' ) + ); + if ( empty( $updated ) ) { + throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment + } + } + + /** + * Add execution message to action log. + * + * @param int $action_id Action ID. + * + * @return void + */ + public function log_execution( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + + $sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d"; + $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + /** + * Mark an action as complete. + * + * @param int $action_id Action ID. + * + * @return void + * @throws \InvalidArgumentException Throw an exception if action was not updated. + */ + public function mark_complete( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + $updated = $wpdb->update( + $wpdb->actionscheduler_actions, + array( + 'status' => self::STATUS_COMPLETE, + 'last_attempt_gmt' => current_time( 'mysql', true ), + 'last_attempt_local' => current_time( 'mysql' ), + ), + array( 'action_id' => $action_id ), + array( '%s' ), + array( '%d' ) + ); + if ( empty( $updated ) ) { + throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment + } + + /** + * Fires after a scheduled action has been completed. + * + * @since 3.4.2 + * + * @param int $action_id Action ID. + */ + do_action( 'action_scheduler_completed_action', $action_id ); + } + + /** + * Get an action's status. + * + * @param int $action_id Action ID. + * + * @return string + * @throws \InvalidArgumentException Throw an exception if not status was found for action_id. + * @throws \RuntimeException Throw an exception if action status could not be retrieved. + */ + public function get_status( $action_id ) { + /** @var \wpdb $wpdb */ + global $wpdb; + $sql = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d"; + $sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $status = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + if ( null === $status ) { + throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) ); + } elseif ( empty( $status ) ) { + throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) ); + } else { + return $status; + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_HybridStore.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_HybridStore.php new file mode 100644 index 000000000..22d61a606 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_HybridStore.php @@ -0,0 +1,426 @@ +demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 ); + if ( empty( $config ) ) { + $config = Controller::instance()->get_migration_config_object(); + } + $this->primary_store = $config->get_destination_store(); + $this->secondary_store = $config->get_source_store(); + $this->migration_runner = new Runner( $config ); + } + + /** + * Initialize the table data store tables. + * + * @codeCoverageIgnore + */ + public function init() { + add_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10, 2 ); + $this->primary_store->init(); + $this->secondary_store->init(); + remove_action( 'action_scheduler/created_table', [ $this, 'set_autoincrement' ], 10 ); + } + + /** + * When the actions table is created, set its autoincrement + * value to be one higher than the posts table to ensure that + * there are no ID collisions. + * + * @param string $table_name + * @param string $table_suffix + * + * @return void + * @codeCoverageIgnore + */ + public function set_autoincrement( $table_name, $table_suffix ) { + if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) { + if ( empty( $this->demarkation_id ) ) { + $this->demarkation_id = $this->set_demarkation_id(); + } + /** @var \wpdb $wpdb */ + global $wpdb; + /** + * A default date of '0000-00-00 00:00:00' is invalid in MySQL 5.7 when configured with + * sql_mode including both STRICT_TRANS_TABLES and NO_ZERO_DATE. + */ + $default_date = new DateTime( 'tomorrow' ); + $null_action = new ActionScheduler_NullAction(); + $date_gmt = $this->get_scheduled_date_string( $null_action, $default_date ); + $date_local = $this->get_scheduled_date_string_local( $null_action, $default_date ); + + $row_count = $wpdb->insert( + $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE}, + [ + 'action_id' => $this->demarkation_id, + 'hook' => '', + 'status' => '', + 'scheduled_date_gmt' => $date_gmt, + 'scheduled_date_local' => $date_local, + 'last_attempt_gmt' => $date_gmt, + 'last_attempt_local' => $date_local, + ] + ); + if ( $row_count > 0 ) { + $wpdb->delete( + $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE}, + [ 'action_id' => $this->demarkation_id ] + ); + } + } + } + + /** + * Store the demarkation id in WP options. + * + * @param int $id The ID to set as the demarkation point between the two stores + * Leave null to use the next ID from the WP posts table. + * + * @return int The new ID. + * + * @codeCoverageIgnore + */ + private function set_demarkation_id( $id = null ) { + if ( empty( $id ) ) { + /** @var \wpdb $wpdb */ + global $wpdb; + $id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" ); + $id ++; + } + update_option( self::DEMARKATION_OPTION, $id ); + + return $id; + } + + /** + * Find the first matching action from the secondary store. + * If it exists, migrate it to the primary store immediately. + * After it migrates, the secondary store will logically contain + * the next matching action, so return the result thence. + * + * @param string $hook + * @param array $params + * + * @return string + */ + public function find_action( $hook, $params = [] ) { + $found_unmigrated_action = $this->secondary_store->find_action( $hook, $params ); + if ( ! empty( $found_unmigrated_action ) ) { + $this->migrate( [ $found_unmigrated_action ] ); + } + + return $this->primary_store->find_action( $hook, $params ); + } + + /** + * Find actions matching the query in the secondary source first. + * If any are found, migrate them immediately. Then the secondary + * store will contain the canonical results. + * + * @param array $query + * @param string $query_type Whether to select or count the results. Default, select. + * + * @return int[] + */ + public function query_actions( $query = [], $query_type = 'select' ) { + $found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' ); + if ( ! empty( $found_unmigrated_actions ) ) { + $this->migrate( $found_unmigrated_actions ); + } + + return $this->primary_store->query_actions( $query, $query_type ); + } + + /** + * Get a count of all actions in the store, grouped by status + * + * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status. + */ + public function action_counts() { + $unmigrated_actions_count = $this->secondary_store->action_counts(); + $migrated_actions_count = $this->primary_store->action_counts(); + $actions_count_by_status = array(); + + foreach ( $this->get_status_labels() as $status_key => $status_label ) { + + $count = 0; + + if ( isset( $unmigrated_actions_count[ $status_key ] ) ) { + $count += $unmigrated_actions_count[ $status_key ]; + } + + if ( isset( $migrated_actions_count[ $status_key ] ) ) { + $count += $migrated_actions_count[ $status_key ]; + } + + $actions_count_by_status[ $status_key ] = $count; + } + + $actions_count_by_status = array_filter( $actions_count_by_status ); + + return $actions_count_by_status; + } + + /** + * If any actions would have been claimed by the secondary store, + * migrate them immediately, then ask the primary store for the + * canonical claim. + * + * @param int $max_actions + * @param DateTime|null $before_date + * + * @return ActionScheduler_ActionClaim + */ + public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) { + $claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); + + $claimed_actions = $claim->get_actions(); + if ( ! empty( $claimed_actions ) ) { + $this->migrate( $claimed_actions ); + } + + $this->secondary_store->release_claim( $claim ); + + return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group ); + } + + /** + * Migrate a list of actions to the table data store. + * + * @param array $action_ids List of action IDs. + */ + private function migrate( $action_ids ) { + $this->migration_runner->migrate_actions( $action_ids ); + } + + /** + * Save an action to the primary store. + * + * @param ActionScheduler_Action $action Action object to be saved. + * @param DateTime $date Optional. Schedule date. Default null. + * + * @return int The action ID + */ + public function save_action( ActionScheduler_Action $action, DateTime $date = null ) { + return $this->primary_store->save_action( $action, $date ); + } + + /** + * Retrieve an existing action whether migrated or not. + * + * @param int $action_id Action ID. + */ + public function fetch_action( $action_id ) { + $store = $this->get_store_from_action_id( $action_id, true ); + if ( $store ) { + return $store->fetch_action( $action_id ); + } else { + return new ActionScheduler_NullAction(); + } + } + + /** + * Cancel an existing action whether migrated or not. + * + * @param int $action_id Action ID. + */ + public function cancel_action( $action_id ) { + $store = $this->get_store_from_action_id( $action_id ); + if ( $store ) { + $store->cancel_action( $action_id ); + } + } + + /** + * Delete an existing action whether migrated or not. + * + * @param int $action_id Action ID. + */ + public function delete_action( $action_id ) { + $store = $this->get_store_from_action_id( $action_id ); + if ( $store ) { + $store->delete_action( $action_id ); + } + } + + /** + * Get the schedule date an existing action whether migrated or not. + * + * @param int $action_id Action ID. + */ + public function get_date( $action_id ) { + $store = $this->get_store_from_action_id( $action_id ); + if ( $store ) { + return $store->get_date( $action_id ); + } else { + return null; + } + } + + /** + * Mark an existing action as failed whether migrated or not. + * + * @param int $action_id Action ID. + */ + public function mark_failure( $action_id ) { + $store = $this->get_store_from_action_id( $action_id ); + if ( $store ) { + $store->mark_failure( $action_id ); + } + } + + /** + * Log the execution of an existing action whether migrated or not. + * + * @param int $action_id Action ID. + */ + public function log_execution( $action_id ) { + $store = $this->get_store_from_action_id( $action_id ); + if ( $store ) { + $store->log_execution( $action_id ); + } + } + + /** + * Mark an existing action complete whether migrated or not. + * + * @param int $action_id Action ID. + */ + public function mark_complete( $action_id ) { + $store = $this->get_store_from_action_id( $action_id ); + if ( $store ) { + $store->mark_complete( $action_id ); + } + } + + /** + * Get an existing action status whether migrated or not. + * + * @param int $action_id Action ID. + */ + public function get_status( $action_id ) { + $store = $this->get_store_from_action_id( $action_id ); + if ( $store ) { + return $store->get_status( $action_id ); + } + return null; + } + + /** + * Return which store an action is stored in. + * + * @param int $action_id ID of the action. + * @param bool $primary_first Optional flag indicating search the primary store first. + * @return ActionScheduler_Store + */ + protected function get_store_from_action_id( $action_id, $primary_first = false ) { + if ( $primary_first ) { + $stores = [ + $this->primary_store, + $this->secondary_store, + ]; + } elseif ( $action_id < $this->demarkation_id ) { + $stores = [ + $this->secondary_store, + $this->primary_store, + ]; + } else { + $stores = [ + $this->primary_store, + ]; + } + + foreach ( $stores as $store ) { + $action = $store->fetch_action( $action_id ); + if ( ! is_a( $action, 'ActionScheduler_NullAction' ) ) { + return $store; + } + } + return null; + } + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * + * All claim-related functions should operate solely + * on the primary store. + * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * Get the claim count from the table data store. + */ + public function get_claim_count() { + return $this->primary_store->get_claim_count(); + } + + /** + * Retrieve the claim ID for an action from the table data store. + * + * @param int $action_id Action ID. + */ + public function get_claim_id( $action_id ) { + return $this->primary_store->get_claim_id( $action_id ); + } + + /** + * Release a claim in the table data store. + * + * @param ActionScheduler_ActionClaim $claim Claim object. + */ + public function release_claim( ActionScheduler_ActionClaim $claim ) { + $this->primary_store->release_claim( $claim ); + } + + /** + * Release claims on an action in the table data store. + * + * @param int $action_id Action ID. + */ + public function unclaim_action( $action_id ) { + $this->primary_store->unclaim_action( $action_id ); + } + + /** + * Retrieve a list of action IDs by claim. + * + * @param int $claim_id Claim ID. + */ + public function find_actions_by_claim_id( $claim_id ) { + return $this->primary_store->find_actions_by_claim_id( $claim_id ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php new file mode 100644 index 000000000..7215ddd94 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php @@ -0,0 +1,240 @@ +create_wp_comment( $action_id, $message, $date ); + return $comment_id; + } + + protected function create_wp_comment( $action_id, $message, DateTime $date ) { + + $comment_date_gmt = $date->format('Y-m-d H:i:s'); + ActionScheduler_TimezoneHelper::set_local_timezone( $date ); + $comment_data = array( + 'comment_post_ID' => $action_id, + 'comment_date' => $date->format('Y-m-d H:i:s'), + 'comment_date_gmt' => $comment_date_gmt, + 'comment_author' => self::AGENT, + 'comment_content' => $message, + 'comment_agent' => self::AGENT, + 'comment_type' => self::TYPE, + ); + return wp_insert_comment($comment_data); + } + + /** + * @param string $entry_id + * + * @return ActionScheduler_LogEntry + */ + public function get_entry( $entry_id ) { + $comment = $this->get_comment( $entry_id ); + if ( empty($comment) || $comment->comment_type != self::TYPE ) { + return new ActionScheduler_NullLogEntry(); + } + + $date = as_get_datetime_object( $comment->comment_date_gmt ); + ActionScheduler_TimezoneHelper::set_local_timezone( $date ); + return new ActionScheduler_LogEntry( $comment->comment_post_ID, $comment->comment_content, $date ); + } + + /** + * @param string $action_id + * + * @return ActionScheduler_LogEntry[] + */ + public function get_logs( $action_id ) { + $status = 'all'; + if ( get_post_status($action_id) == 'trash' ) { + $status = 'post-trashed'; + } + $comments = get_comments(array( + 'post_id' => $action_id, + 'orderby' => 'comment_date_gmt', + 'order' => 'ASC', + 'type' => self::TYPE, + 'status' => $status, + )); + $logs = array(); + foreach ( $comments as $c ) { + $entry = $this->get_entry( $c ); + if ( !empty($entry) ) { + $logs[] = $entry; + } + } + return $logs; + } + + protected function get_comment( $comment_id ) { + return get_comment( $comment_id ); + } + + + + /** + * @param WP_Comment_Query $query + */ + public function filter_comment_queries( $query ) { + foreach ( array('ID', 'parent', 'post_author', 'post_name', 'post_parent', 'type', 'post_type', 'post_id', 'post_ID') as $key ) { + if ( !empty($query->query_vars[$key]) ) { + return; // don't slow down queries that wouldn't include action_log comments anyway + } + } + $query->query_vars['action_log_filter'] = TRUE; + add_filter( 'comments_clauses', array( $this, 'filter_comment_query_clauses' ), 10, 2 ); + } + + /** + * @param array $clauses + * @param WP_Comment_Query $query + * + * @return array + */ + public function filter_comment_query_clauses( $clauses, $query ) { + if ( !empty($query->query_vars['action_log_filter']) ) { + $clauses['where'] .= $this->get_where_clause(); + } + return $clauses; + } + + /** + * Make sure Action Scheduler logs are excluded from comment feeds, which use WP_Query, not + * the WP_Comment_Query class handled by @see self::filter_comment_queries(). + * + * @param string $where + * @param WP_Query $query + * + * @return string + */ + public function filter_comment_feed( $where, $query ) { + if ( is_comment_feed() ) { + $where .= $this->get_where_clause(); + } + return $where; + } + + /** + * Return a SQL clause to exclude Action Scheduler comments. + * + * @return string + */ + protected function get_where_clause() { + global $wpdb; + return sprintf( " AND {$wpdb->comments}.comment_type != '%s'", self::TYPE ); + } + + /** + * Remove action log entries from wp_count_comments() + * + * @param array $stats + * @param int $post_id + * + * @return object + */ + public function filter_comment_count( $stats, $post_id ) { + global $wpdb; + + if ( 0 === $post_id ) { + $stats = $this->get_comment_count(); + } + + return $stats; + } + + /** + * Retrieve the comment counts from our cache, or the database if the cached version isn't set. + * + * @return object + */ + protected function get_comment_count() { + global $wpdb; + + $stats = get_transient( 'as_comment_count' ); + + if ( ! $stats ) { + $stats = array(); + + $count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type NOT IN('order_note','action_log') GROUP BY comment_approved", ARRAY_A ); + + $total = 0; + $stats = array(); + $approved = array( '0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed' ); + + foreach ( (array) $count as $row ) { + // Don't count post-trashed toward totals + if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) { + $total += $row['num_comments']; + } + if ( isset( $approved[ $row['comment_approved'] ] ) ) { + $stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments']; + } + } + + $stats['total_comments'] = $total; + $stats['all'] = $total; + + foreach ( $approved as $key ) { + if ( empty( $stats[ $key ] ) ) { + $stats[ $key ] = 0; + } + } + + $stats = (object) $stats; + set_transient( 'as_comment_count', $stats ); + } + + return $stats; + } + + /** + * Delete comment count cache whenever there is new comment or the status of a comment changes. Cache + * will be regenerated next time ActionScheduler_wpCommentLogger::filter_comment_count() is called. + */ + public function delete_comment_count_cache() { + delete_transient( 'as_comment_count' ); + } + + /** + * @codeCoverageIgnore + */ + public function init() { + add_action( 'action_scheduler_before_process_queue', array( $this, 'disable_comment_counting' ), 10, 0 ); + add_action( 'action_scheduler_after_process_queue', array( $this, 'enable_comment_counting' ), 10, 0 ); + + parent::init(); + + add_action( 'pre_get_comments', array( $this, 'filter_comment_queries' ), 10, 1 ); + add_action( 'wp_count_comments', array( $this, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs + add_action( 'comment_feed_where', array( $this, 'filter_comment_feed' ), 10, 2 ); + + // Delete comments count cache whenever there is a new comment or a comment status changes + add_action( 'wp_insert_comment', array( $this, 'delete_comment_count_cache' ) ); + add_action( 'wp_set_comment_status', array( $this, 'delete_comment_count_cache' ) ); + } + + public function disable_comment_counting() { + wp_defer_comment_counting(true); + } + public function enable_comment_counting() { + wp_defer_comment_counting(false); + } + +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore.php new file mode 100644 index 000000000..7883ca82b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore.php @@ -0,0 +1,1075 @@ +validate_action( $action ); + $post_array = $this->create_post_array( $action, $scheduled_date ); + $post_id = $this->save_post_array( $post_array ); + $this->save_post_schedule( $post_id, $action->get_schedule() ); + $this->save_action_group( $post_id, $action->get_group() ); + do_action( 'action_scheduler_stored_action', $post_id ); + return $post_id; + } catch ( Exception $e ) { + /* translators: %s: action error message */ + throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 ); + } + } + + /** + * Create post array. + * + * @param ActionScheduler_Action $action Scheduled Action. + * @param DateTime $scheduled_date Scheduled Date. + * + * @return array Returns an array of post data. + */ + protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = null ) { + $post = array( + 'post_type' => self::POST_TYPE, + 'post_title' => $action->get_hook(), + 'post_content' => wp_json_encode( $action->get_args() ), + 'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ), + 'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ), + 'post_date' => $this->get_scheduled_date_string_local( $action, $scheduled_date ), + ); + return $post; + } + + /** + * Save post array. + * + * @param array $post_array Post array. + * @return int Returns the post ID. + * @throws RuntimeException Throws an exception if the action could not be saved. + */ + protected function save_post_array( $post_array ) { + add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 ); + add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); + + $has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ); + + if ( $has_kses ) { + // Prevent KSES from corrupting JSON in post_content. + kses_remove_filters(); + } + + $post_id = wp_insert_post( $post_array ); + + if ( $has_kses ) { + kses_init_filters(); + } + + remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); + remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); + + if ( is_wp_error( $post_id ) || empty( $post_id ) ) { + throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) ); + } + return $post_id; + } + + /** + * Filter insert post data. + * + * @param array $postdata Post data to filter. + * + * @return array + */ + public function filter_insert_post_data( $postdata ) { + if ( self::POST_TYPE === $postdata['post_type'] ) { + $postdata['post_author'] = 0; + if ( 'future' === $postdata['post_status'] ) { + $postdata['post_status'] = 'publish'; + } + } + return $postdata; + } + + /** + * Create a (probably unique) post name for scheduled actions in a more performant manner than wp_unique_post_slug(). + * + * When an action's post status is transitioned to something other than 'draft', 'pending' or 'auto-draft, like 'publish' + * or 'failed' or 'trash', WordPress will find a unique slug (stored in post_name column) using the wp_unique_post_slug() + * function. This is done to ensure URL uniqueness. The approach taken by wp_unique_post_slug() is to iterate over existing + * post_name values that match, and append a number 1 greater than the largest. This makes sense when manually creating a + * post from the Edit Post screen. It becomes a bottleneck when automatically processing thousands of actions, with a + * database containing thousands of related post_name values. + * + * WordPress 5.1 introduces the 'pre_wp_unique_post_slug' filter for plugins to address this issue. + * + * We can short-circuit WordPress's wp_unique_post_slug() approach using the 'pre_wp_unique_post_slug' filter. This + * method is available to be used as a callback on that filter. It provides a more scalable approach to generating a + * post_name/slug that is probably unique. Because Action Scheduler never actually uses the post_name field, or an + * action's slug, being probably unique is good enough. + * + * For more backstory on this issue, see: + * - https://github.com/woocommerce/action-scheduler/issues/44 and + * - https://core.trac.wordpress.org/ticket/21112 + * + * @param string $override_slug Short-circuit return value. + * @param string $slug The desired slug (post_name). + * @param int $post_ID Post ID. + * @param string $post_status The post status. + * @param string $post_type Post type. + * @return string + */ + public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) { + if ( self::POST_TYPE === $post_type ) { + $override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false ); + } + return $override_slug; + } + + /** + * Save post schedule. + * + * @param int $post_id Post ID of the scheduled action. + * @param string $schedule Schedule to save. + * + * @return void + */ + protected function save_post_schedule( $post_id, $schedule ) { + update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule ); + } + + /** + * Save action group. + * + * @param int $post_id Post ID. + * @param string $group Group to save. + * @return void + */ + protected function save_action_group( $post_id, $group ) { + if ( empty( $group ) ) { + wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, false ); + } else { + wp_set_object_terms( $post_id, array( $group ), self::GROUP_TAXONOMY, false ); + } + } + + /** + * Fetch actions. + * + * @param int $action_id Action ID. + * @return object + */ + public function fetch_action( $action_id ) { + $post = $this->get_post( $action_id ); + if ( empty( $post ) || self::POST_TYPE !== $post->post_type ) { + return $this->get_null_action(); + } + + try { + $action = $this->make_action_from_post( $post ); + } catch ( ActionScheduler_InvalidActionException $exception ) { + do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception ); + return $this->get_null_action(); + } + + return $action; + } + + /** + * Get post. + * + * @param string $action_id - Action ID. + * @return WP_Post|null + */ + protected function get_post( $action_id ) { + if ( empty( $action_id ) ) { + return null; + } + return get_post( $action_id ); + } + + /** + * Get NULL action. + * + * @return ActionScheduler_NullAction + */ + protected function get_null_action() { + return new ActionScheduler_NullAction(); + } + + /** + * Make action from post. + * + * @param WP_Post $post Post object. + * @return WP_Post + */ + protected function make_action_from_post( $post ) { + $hook = $post->post_title; + + $args = json_decode( $post->post_content, true ); + $this->validate_args( $args, $post->ID ); + + $schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true ); + $this->validate_schedule( $schedule, $post->ID ); + + $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array( 'fields' => 'names' ) ); + $group = empty( $group ) ? '' : reset( $group ); + + return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group ); + } + + /** + * Get action status by post status. + * + * @param string $post_status Post status. + * + * @throws InvalidArgumentException Throw InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels(). + * @return string + */ + protected function get_action_status_by_post_status( $post_status ) { + + switch ( $post_status ) { + case 'publish': + $action_status = self::STATUS_COMPLETE; + break; + case 'trash': + $action_status = self::STATUS_CANCELED; + break; + default: + if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) { + throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) ); + } + $action_status = $post_status; + break; + } + + return $action_status; + } + + /** + * Get post status by action status. + * + * @param string $action_status Action status. + * + * @throws InvalidArgumentException Throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels(). + * @return string + */ + protected function get_post_status_by_action_status( $action_status ) { + + switch ( $action_status ) { + case self::STATUS_COMPLETE: + $post_status = 'publish'; + break; + case self::STATUS_CANCELED: + $post_status = 'trash'; + break; + default: + if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) { + throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) ); + } + $post_status = $action_status; + break; + } + + return $post_status; + } + + /** + * Returns the SQL statement to query (or count) actions. + * + * @param array $query - Filtering options. + * @param string $select_or_count - Whether the SQL should select and return the IDs or just the row count. + * + * @throws InvalidArgumentException - Throw InvalidArgumentException if $select_or_count not count or select. + * @return string SQL statement. The returned SQL is already properly escaped. + */ + protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) { + + if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) { + throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) ); + } + + $query = wp_parse_args( + $query, + array( + 'hook' => '', + 'args' => null, + 'date' => null, + 'date_compare' => '<=', + 'modified' => null, + 'modified_compare' => '<=', + 'group' => '', + 'status' => '', + 'claimed' => null, + 'per_page' => 5, + 'offset' => 0, + 'orderby' => 'date', + 'order' => 'ASC', + 'search' => '', + ) + ); + + /** + * Global wpdb object. + * + * @var wpdb $wpdb + */ + global $wpdb; + $sql = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID '; + $sql .= "FROM {$wpdb->posts} p"; + $sql_params = array(); + if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) { + $sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; + $sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; + $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; + } elseif ( ! empty( $query['group'] ) ) { + $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID"; + $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id"; + $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id"; + $sql .= ' AND t.slug=%s'; + $sql_params[] = $query['group']; + } + $sql .= ' WHERE post_type=%s'; + $sql_params[] = self::POST_TYPE; + if ( $query['hook'] ) { + $sql .= ' AND p.post_title=%s'; + $sql_params[] = $query['hook']; + } + if ( ! is_null( $query['args'] ) ) { + $sql .= ' AND p.post_content=%s'; + $sql_params[] = wp_json_encode( $query['args'] ); + } + + if ( $query['status'] ) { + $post_statuses = array_map( array( $this, 'get_post_status_by_action_status' ), (array) $query['status'] ); + $placeholders = array_fill( 0, count( $post_statuses ), '%s' ); + $sql .= ' AND p.post_status IN (' . join( ', ', $placeholders ) . ')'; + $sql_params = array_merge( $sql_params, array_values( $post_statuses ) ); + } + + if ( $query['date'] instanceof DateTime ) { + $date = clone $query['date']; + $date->setTimezone( new DateTimeZone( 'UTC' ) ); + $date_string = $date->format( 'Y-m-d H:i:s' ); + $comparator = $this->validate_sql_comparator( $query['date_compare'] ); + $sql .= " AND p.post_date_gmt $comparator %s"; + $sql_params[] = $date_string; + } + + if ( $query['modified'] instanceof DateTime ) { + $modified = clone $query['modified']; + $modified->setTimezone( new DateTimeZone( 'UTC' ) ); + $date_string = $modified->format( 'Y-m-d H:i:s' ); + $comparator = $this->validate_sql_comparator( $query['modified_compare'] ); + $sql .= " AND p.post_modified_gmt $comparator %s"; + $sql_params[] = $date_string; + } + + if ( true === $query['claimed'] ) { + $sql .= " AND p.post_password != ''"; + } elseif ( false === $query['claimed'] ) { + $sql .= " AND p.post_password = ''"; + } elseif ( ! is_null( $query['claimed'] ) ) { + $sql .= ' AND p.post_password = %s'; + $sql_params[] = $query['claimed']; + } + + if ( ! empty( $query['search'] ) ) { + $sql .= ' AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)'; + for ( $i = 0; $i < 3; $i++ ) { + $sql_params[] = sprintf( '%%%s%%', $query['search'] ); + } + } + + if ( 'select' === $select_or_count ) { + switch ( $query['orderby'] ) { + case 'hook': + $orderby = 'p.post_title'; + break; + case 'group': + $orderby = 't.name'; + break; + case 'status': + $orderby = 'p.post_status'; + break; + case 'modified': + $orderby = 'p.post_modified'; + break; + case 'claim_id': + $orderby = 'p.post_password'; + break; + case 'schedule': + case 'date': + default: + $orderby = 'p.post_date_gmt'; + break; + } + if ( 'ASC' === strtoupper( $query['order'] ) ) { + $order = 'ASC'; + } else { + $order = 'DESC'; + } + $sql .= " ORDER BY $orderby $order"; + if ( $query['per_page'] > 0 ) { + $sql .= ' LIMIT %d, %d'; + $sql_params[] = $query['offset']; + $sql_params[] = $query['per_page']; + } + } + + return $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + + /** + * Query for action count or list of action IDs. + * + * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status. + * + * @see ActionScheduler_Store::query_actions for $query arg usage. + * + * @param array $query Query filtering options. + * @param string $query_type Whether to select or count the results. Defaults to select. + * + * @return string|array|null The IDs of actions matching the query. Null on failure. + */ + public function query_actions( $query = array(), $query_type = 'select' ) { + /** + * Global $wpdb object. + * + * @var wpdb $wpdb + */ + global $wpdb; + + $sql = $this->get_query_actions_sql( $query, $query_type ); + + return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared + } + + /** + * Get a count of all actions in the store, grouped by status + * + * @return array + */ + public function action_counts() { + + $action_counts_by_status = array(); + $action_stati_and_labels = $this->get_status_labels(); + $posts_count_by_status = (array) wp_count_posts( self::POST_TYPE, 'readable' ); + + foreach ( $posts_count_by_status as $post_status_name => $count ) { + + try { + $action_status_name = $this->get_action_status_by_post_status( $post_status_name ); + } catch ( Exception $e ) { + // Ignore any post statuses that aren't for actions. + continue; + } + if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) { + $action_counts_by_status[ $action_status_name ] = $count; + } + } + + return $action_counts_by_status; + } + + /** + * Cancel action. + * + * @param int $action_id Action ID. + * + * @throws InvalidArgumentException If $action_id is not identified. + */ + public function cancel_action( $action_id ) { + $post = get_post( $action_id ); + if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) { + /* translators: %s is the action ID */ + throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); + } + do_action( 'action_scheduler_canceled_action', $action_id ); + add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); + wp_trash_post( $action_id ); + remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); + } + + /** + * Delete action. + * + * @param int $action_id Action ID. + * @return void + * @throws InvalidArgumentException If action is not identified. + */ + public function delete_action( $action_id ) { + $post = get_post( $action_id ); + if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) { + /* translators: %s is the action ID */ + throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); + } + do_action( 'action_scheduler_deleted_action', $action_id ); + + wp_delete_post( $action_id, true ); + } + + /** + * Get date for claim id. + * + * @param int $action_id Action ID. + * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran. + */ + public function get_date( $action_id ) { + $next = $this->get_date_gmt( $action_id ); + return ActionScheduler_TimezoneHelper::set_local_timezone( $next ); + } + + /** + * Get Date GMT. + * + * @param int $action_id Action ID. + * + * @throws InvalidArgumentException If $action_id is not identified. + * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran. + */ + public function get_date_gmt( $action_id ) { + $post = get_post( $action_id ); + if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) { + /* translators: %s is the action ID */ + throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); + } + if ( 'publish' === $post->post_status ) { + return as_get_datetime_object( $post->post_modified_gmt ); + } else { + return as_get_datetime_object( $post->post_date_gmt ); + } + } + + /** + * Stake claim. + * + * @param int $max_actions Maximum number of actions. + * @param DateTime $before_date Jobs must be schedule before this date. Defaults to now. + * @param array $hooks Claim only actions with a hook or hooks. + * @param string $group Claim only actions in the given group. + * + * @return ActionScheduler_ActionClaim + * @throws RuntimeException When there is an error staking a claim. + * @throws InvalidArgumentException When the given group is not valid. + */ + public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) { + $this->claim_before_date = $before_date; + $claim_id = $this->generate_claim_id(); + $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group ); + $action_ids = $this->find_actions_by_claim_id( $claim_id ); + $this->claim_before_date = null; + + return new ActionScheduler_ActionClaim( $claim_id, $action_ids ); + } + + /** + * Get claim count. + * + * @return int + */ + public function get_claim_count() { + global $wpdb; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching + return $wpdb->get_var( + $wpdb->prepare( + "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')", + array( self::POST_TYPE ) + ) + ); + } + + /** + * Generate claim id. + * + * @return string + */ + protected function generate_claim_id() { + $claim_id = md5( microtime( true ) . wp_rand( 0, 1000 ) ); + return substr( $claim_id, 0, 20 ); // to fit in db field with 20 char limit. + } + + /** + * Claim actions. + * + * @param string $claim_id Claim ID. + * @param int $limit Limit. + * @param DateTime $before_date Should use UTC timezone. + * @param array $hooks Claim only actions with a hook or hooks. + * @param string $group Claim only actions in the given group. + * + * @return int The number of actions that were claimed. + * @throws RuntimeException When there is a database error. + */ + protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) { + // Set up initial variables. + $date = null === $before_date ? as_get_datetime_object() : clone $before_date; + $limit_ids = ! empty( $group ); + $ids = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array(); + + // If limiting by IDs and no posts found, then return early since we have nothing to update. + if ( $limit_ids && 0 === count( $ids ) ) { + return 0; + } + + /** + * Global wpdb object. + * + * @var wpdb $wpdb + */ + global $wpdb; + + /* + * Build up custom query to update the affected posts. Parameters are built as a separate array + * to make it easier to identify where they are in the query. + * + * We can't use $wpdb->update() here because of the "ID IN ..." clause. + */ + $update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s"; + $params = array( + $claim_id, + current_time( 'mysql', true ), + current_time( 'mysql' ), + ); + + // Build initial WHERE clause. + $where = "WHERE post_type = %s AND post_status = %s AND post_password = ''"; + $params[] = self::POST_TYPE; + $params[] = ActionScheduler_Store::STATUS_PENDING; + + if ( ! empty( $hooks ) ) { + $placeholders = array_fill( 0, count( $hooks ), '%s' ); + $where .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')'; + $params = array_merge( $params, array_values( $hooks ) ); + } + + /* + * Add the IDs to the WHERE clause. IDs not escaped because they came directly from a prior DB query. + * + * If we're not limiting by IDs, then include the post_date_gmt clause. + */ + if ( $limit_ids ) { + $where .= ' AND ID IN (' . join( ',', $ids ) . ')'; + } else { + $where .= ' AND post_date_gmt <= %s'; + $params[] = $date->format( 'Y-m-d H:i:s' ); + } + + // Add the ORDER BY clause and,ms limit. + $order = 'ORDER BY menu_order ASC, post_date_gmt ASC, ID ASC LIMIT %d'; + $params[] = $limit; + + // Run the query and gather results. + $rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) ); // phpcs:ignore // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare + + if ( false === $rows_affected ) { + throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) ); + } + + return (int) $rows_affected; + } + + /** + * Get IDs of actions within a certain group and up to a certain date/time. + * + * @param string $group The group to use in finding actions. + * @param int $limit The number of actions to retrieve. + * @param DateTime $date DateTime object representing cutoff time for actions. Actions retrieved will be + * up to and including this DateTime. + * + * @return array IDs of actions in the appropriate group and before the appropriate time. + * @throws InvalidArgumentException When the group does not exist. + */ + protected function get_actions_by_group( $group, $limit, DateTime $date ) { + // Ensure the group exists before continuing. + if ( ! term_exists( $group, self::GROUP_TAXONOMY ) ) { + /* translators: %s is the group name */ + throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) ); + } + + // Set up a query for post IDs to use later. + $query = new WP_Query(); + $query_args = array( + 'fields' => 'ids', + 'post_type' => self::POST_TYPE, + 'post_status' => ActionScheduler_Store::STATUS_PENDING, + 'has_password' => false, + 'posts_per_page' => $limit * 3, + 'suppress_filters' => true, + 'no_found_rows' => true, + 'orderby' => array( + 'menu_order' => 'ASC', + 'date' => 'ASC', + 'ID' => 'ASC', + ), + 'date_query' => array( + 'column' => 'post_date_gmt', + 'before' => $date->format( 'Y-m-d H:i' ), + 'inclusive' => true, + ), + 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery + array( + 'taxonomy' => self::GROUP_TAXONOMY, + 'field' => 'slug', + 'terms' => $group, + 'include_children' => false, + ), + ), + ); + + return $query->query( $query_args ); + } + + /** + * Find actions by claim ID. + * + * @param string $claim_id Claim ID. + * @return array + */ + public function find_actions_by_claim_id( $claim_id ) { + /** + * Global wpdb object. + * + * @var wpdb $wpdb + */ + global $wpdb; + + $action_ids = array(); + $before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object(); + $cut_off = $before_date->format( 'Y-m-d H:i:s' ); + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + $results = $wpdb->get_results( + $wpdb->prepare( + "SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s", + array( + self::POST_TYPE, + $claim_id, + ) + ) + ); + + // Verify that the scheduled date for each action is within the expected bounds (in some unusual + // cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify). + foreach ( $results as $claimed_action ) { + if ( $claimed_action->post_date_gmt <= $cut_off ) { + $action_ids[] = absint( $claimed_action->ID ); + } + } + + return $action_ids; + } + + /** + * Release claim. + * + * @param ActionScheduler_ActionClaim $claim Claim object to release. + * @return void + * @throws RuntimeException When the claim is not unlocked. + */ + public function release_claim( ActionScheduler_ActionClaim $claim ) { + $action_ids = $this->find_actions_by_claim_id( $claim->get_id() ); + if ( empty( $action_ids ) ) { + return; // nothing to do. + } + $action_id_string = implode( ',', array_map( 'intval', $action_ids ) ); + /** + * Global wpdb object. + * + * @var wpdb $wpdb + */ + global $wpdb; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + $result = $wpdb->query( + $wpdb->prepare( + "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s", //phpcs:ignore + array( + $claim->get_id(), + ) + ) + ); + if ( false === $result ) { + /* translators: %s: claim ID */ + throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) ); + } + } + + /** + * Unclaim action. + * + * @param string $action_id Action ID. + * @throws RuntimeException When unable to unlock claim on action ID. + */ + public function unclaim_action( $action_id ) { + /** + * Global wpdb object. + * + * @var wpdb $wpdb + */ + global $wpdb; + + //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + $result = $wpdb->query( + $wpdb->prepare( + "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s", + $action_id, + self::POST_TYPE + ) + ); + if ( false === $result ) { + /* translators: %s: action ID */ + throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) ); + } + } + + /** + * Mark failure on action. + * + * @param int $action_id Action ID. + * + * @return void + * @throws RuntimeException When unable to mark failure on action ID. + */ + public function mark_failure( $action_id ) { + /** + * Global wpdb object. + * + * @var wpdb $wpdb + */ + global $wpdb; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + $result = $wpdb->query( + $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s", self::STATUS_FAILED, $action_id, self::POST_TYPE ) + ); + if ( false === $result ) { + /* translators: %s: action ID */ + throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) ); + } + } + + /** + * Return an action's claim ID, as stored in the post password column + * + * @param int $action_id Action ID. + * @return mixed + */ + public function get_claim_id( $action_id ) { + return $this->get_post_column( $action_id, 'post_password' ); + } + + /** + * Return an action's status, as stored in the post status column + * + * @param int $action_id Action ID. + * + * @return mixed + * @throws InvalidArgumentException When the action ID is invalid. + */ + public function get_status( $action_id ) { + $status = $this->get_post_column( $action_id, 'post_status' ); + + if ( null === $status ) { + throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) ); + } + + return $this->get_action_status_by_post_status( $status ); + } + + /** + * Get post column + * + * @param string $action_id Action ID. + * @param string $column_name Column Name. + * + * @return string|null + */ + private function get_post_column( $action_id, $column_name ) { + /** + * Global wpdb object. + * + * @var wpdb $wpdb + */ + global $wpdb; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + return $wpdb->get_var( + $wpdb->prepare( + "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", // phpcs:ignore + $action_id, + self::POST_TYPE + ) + ); + } + + /** + * Log Execution. + * + * @param string $action_id Action ID. + */ + public function log_execution( $action_id ) { + /** + * Global wpdb object. + * + * @var wpdb $wpdb + */ + global $wpdb; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + $wpdb->query( + $wpdb->prepare( + "UPDATE {$wpdb->posts} SET menu_order = menu_order+1, post_status=%s, post_modified_gmt = %s, post_modified = %s WHERE ID = %d AND post_type = %s", + self::STATUS_RUNNING, + current_time( 'mysql', true ), + current_time( 'mysql' ), + $action_id, + self::POST_TYPE + ) + ); + } + + /** + * Record that an action was completed. + * + * @param string $action_id ID of the completed action. + * + * @throws InvalidArgumentException When the action ID is invalid. + * @throws RuntimeException When there was an error executing the action. + */ + public function mark_complete( $action_id ) { + $post = get_post( $action_id ); + if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) { + /* translators: %s is the action ID */ + throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); + } + add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 ); + add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 ); + $result = wp_update_post( + array( + 'ID' => $action_id, + 'post_status' => 'publish', + ), + true + ); + remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 ); + remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 ); + if ( is_wp_error( $result ) ) { + throw new RuntimeException( $result->get_error_message() ); + } + + /** + * Fires after a scheduled action has been completed. + * + * @since 3.4.2 + * + * @param int $action_id Action ID. + */ + do_action( 'action_scheduler_completed_action', $action_id ); + } + + /** + * Mark action as migrated when there is an error deleting the action. + * + * @param int $action_id Action ID. + */ + public function mark_migrated( $action_id ) { + wp_update_post( + array( + 'ID' => $action_id, + 'post_status' => 'migrated', + ) + ); + } + + /** + * Determine whether the post store can be migrated. + * + * @param [type] $setting - Setting value. + * @return bool + */ + public function migration_dependencies_met( $setting ) { + global $wpdb; + + $dependencies_met = get_transient( self::DEPENDENCIES_MET ); + if ( empty( $dependencies_met ) ) { + $maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 ); + $found_action = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching + $wpdb->prepare( + "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1", + $maximum_args_length, + self::POST_TYPE + ) + ); + $dependencies_met = $found_action ? 'no' : 'yes'; + set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS ); + } + + return 'yes' === $dependencies_met ? $setting : false; + } + + /** + * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4. + * + * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However, + * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn + * developers of this impending requirement. + * + * @param ActionScheduler_Action $action Action object. + */ + protected function validate_action( ActionScheduler_Action $action ) { + try { + parent::validate_action( $action ); + } catch ( Exception $e ) { + /* translators: %s is the error message */ + $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() ); + _doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' ); + } + } + + /** + * (@codeCoverageIgnore) + */ + public function init() { + add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) ); + + $post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar(); + $post_type_registrar->register(); + + $post_status_registrar = new ActionScheduler_wpPostStore_PostStatusRegistrar(); + $post_status_registrar->register(); + + $taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar(); + $taxonomy_registrar->register(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php new file mode 100644 index 000000000..246bc347b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_PostStatusRegistrar.php @@ -0,0 +1,58 @@ +post_status_args(), $this->post_status_running_labels() ) ); + register_post_status( ActionScheduler_Store::STATUS_FAILED, array_merge( $this->post_status_args(), $this->post_status_failed_labels() ) ); + } + + /** + * Build the args array for the post type definition + * + * @return array + */ + protected function post_status_args() { + $args = array( + 'public' => false, + 'exclude_from_search' => false, + 'show_in_admin_all_list' => true, + 'show_in_admin_status_list' => true, + ); + + return apply_filters( 'action_scheduler_post_status_args', $args ); + } + + /** + * Build the args array for the post type definition + * + * @return array + */ + protected function post_status_failed_labels() { + $labels = array( + 'label' => _x( 'Failed', 'post', 'action-scheduler' ), + /* translators: %s: count */ + 'label_count' => _n_noop( 'Failed (%s)', 'Failed (%s)', 'action-scheduler' ), + ); + + return apply_filters( 'action_scheduler_post_status_failed_labels', $labels ); + } + + /** + * Build the args array for the post type definition + * + * @return array + */ + protected function post_status_running_labels() { + $labels = array( + 'label' => _x( 'In-Progress', 'post', 'action-scheduler' ), + /* translators: %s: count */ + 'label_count' => _n_noop( 'In-Progress (%s)', 'In-Progress (%s)', 'action-scheduler' ), + ); + + return apply_filters( 'action_scheduler_post_status_running_labels', $labels ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php new file mode 100644 index 000000000..8c63bd0f7 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_PostTypeRegistrar.php @@ -0,0 +1,50 @@ +post_type_args() ); + } + + /** + * Build the args array for the post type definition + * + * @return array + */ + protected function post_type_args() { + $args = array( + 'label' => __( 'Scheduled Actions', 'action-scheduler' ), + 'description' => __( 'Scheduled actions are hooks triggered on a cetain date and time.', 'action-scheduler' ), + 'public' => false, + 'map_meta_cap' => true, + 'hierarchical' => false, + 'supports' => array('title', 'editor','comments'), + 'rewrite' => false, + 'query_var' => false, + 'can_export' => true, + 'ep_mask' => EP_NONE, + 'labels' => array( + 'name' => __( 'Scheduled Actions', 'action-scheduler' ), + 'singular_name' => __( 'Scheduled Action', 'action-scheduler' ), + 'menu_name' => _x( 'Scheduled Actions', 'Admin menu name', 'action-scheduler' ), + 'add_new' => __( 'Add', 'action-scheduler' ), + 'add_new_item' => __( 'Add New Scheduled Action', 'action-scheduler' ), + 'edit' => __( 'Edit', 'action-scheduler' ), + 'edit_item' => __( 'Edit Scheduled Action', 'action-scheduler' ), + 'new_item' => __( 'New Scheduled Action', 'action-scheduler' ), + 'view' => __( 'View Action', 'action-scheduler' ), + 'view_item' => __( 'View Action', 'action-scheduler' ), + 'search_items' => __( 'Search Scheduled Actions', 'action-scheduler' ), + 'not_found' => __( 'No actions found', 'action-scheduler' ), + 'not_found_in_trash' => __( 'No actions found in trash', 'action-scheduler' ), + ), + ); + + $args = apply_filters('action_scheduler_post_type_args', $args); + return $args; + } +} + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php new file mode 100644 index 000000000..367401f7e --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/data-stores/ActionScheduler_wpPostStore_TaxonomyRegistrar.php @@ -0,0 +1,26 @@ +taxonomy_args() ); + } + + protected function taxonomy_args() { + $args = array( + 'label' => __( 'Action Group', 'action-scheduler' ), + 'public' => false, + 'hierarchical' => false, + 'show_admin_column' => true, + 'query_var' => false, + 'rewrite' => false, + ); + + $args = apply_filters( 'action_scheduler_taxonomy_args', $args ); + return $args; + } +} + \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/ActionMigrator.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/ActionMigrator.php new file mode 100644 index 000000000..c77d0832c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/ActionMigrator.php @@ -0,0 +1,109 @@ +source = $source_store; + $this->destination = $destination_store; + $this->log_migrator = $log_migrator; + } + + /** + * Migrate an action. + * + * @param int $source_action_id Action ID. + * + * @return int 0|new action ID + */ + public function migrate( $source_action_id ) { + try { + $action = $this->source->fetch_action( $source_action_id ); + $status = $this->source->get_status( $source_action_id ); + } catch ( \Exception $e ) { + $action = null; + $status = ''; + } + + if ( is_null( $action ) || empty( $status ) || ! $action->get_schedule()->get_date() ) { + // null action or empty status means the fetch operation failed or the action didn't exist + // null schedule means it's missing vital data + // delete it and move on + try { + $this->source->delete_action( $source_action_id ); + } catch ( \Exception $e ) { + // nothing to do, it didn't exist in the first place + } + do_action( 'action_scheduler/no_action_to_migrate', $source_action_id, $this->source, $this->destination ); + + return 0; + } + + try { + + // Make sure the last attempt date is set correctly for completed and failed actions + $last_attempt_date = ( $status !== \ActionScheduler_Store::STATUS_PENDING ) ? $this->source->get_date( $source_action_id ) : null; + + $destination_action_id = $this->destination->save_action( $action, null, $last_attempt_date ); + } catch ( \Exception $e ) { + do_action( 'action_scheduler/migrate_action_failed', $source_action_id, $this->source, $this->destination ); + + return 0; // could not save the action in the new store + } + + try { + switch ( $status ) { + case \ActionScheduler_Store::STATUS_FAILED : + $this->destination->mark_failure( $destination_action_id ); + break; + case \ActionScheduler_Store::STATUS_CANCELED : + $this->destination->cancel_action( $destination_action_id ); + break; + } + + $this->log_migrator->migrate( $source_action_id, $destination_action_id ); + $this->source->delete_action( $source_action_id ); + + $test_action = $this->source->fetch_action( $source_action_id ); + if ( ! is_a( $test_action, 'ActionScheduler_NullAction' ) ) { + throw new \RuntimeException( sprintf( __( 'Unable to remove source migrated action %s', 'action-scheduler' ), $source_action_id ) ); + } + do_action( 'action_scheduler/migrated_action', $source_action_id, $destination_action_id, $this->source, $this->destination ); + + return $destination_action_id; + } catch ( \Exception $e ) { + // could not delete from the old store + $this->source->mark_migrated( $source_action_id ); + do_action( 'action_scheduler/migrate_action_incomplete', $source_action_id, $destination_action_id, $this->source, $this->destination ); + do_action( 'action_scheduler/migrated_action', $source_action_id, $destination_action_id, $this->source, $this->destination ); + + return $destination_action_id; + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/ActionScheduler_DBStoreMigrator.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/ActionScheduler_DBStoreMigrator.php new file mode 100644 index 000000000..41c21da25 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/ActionScheduler_DBStoreMigrator.php @@ -0,0 +1,47 @@ + $this->get_scheduled_date_string( $action, $last_attempt_date ), + 'last_attempt_local' => $this->get_scheduled_date_string_local( $action, $last_attempt_date ), + ]; + + $wpdb->update( $wpdb->actionscheduler_actions, $data, array( 'action_id' => $action_id ), array( '%s', '%s' ), array( '%d' ) ); + } + + return $action_id; + } catch ( \Exception $e ) { + throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 ); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/BatchFetcher.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/BatchFetcher.php new file mode 100644 index 000000000..48728010f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/BatchFetcher.php @@ -0,0 +1,86 @@ +store = $source_store; + } + + /** + * Retrieve a list of actions. + * + * @param int $count The number of actions to retrieve + * + * @return int[] A list of action IDs + */ + public function fetch( $count = 10 ) { + foreach ( $this->get_query_strategies( $count ) as $query ) { + $action_ids = $this->store->query_actions( $query ); + if ( ! empty( $action_ids ) ) { + return $action_ids; + } + } + + return []; + } + + /** + * Generate a list of prioritized of action search parameters. + * + * @param int $count Number of actions to find. + * + * @return array + */ + private function get_query_strategies( $count ) { + $now = as_get_datetime_object(); + $args = [ + 'date' => $now, + 'per_page' => $count, + 'offset' => 0, + 'orderby' => 'date', + 'order' => 'ASC', + ]; + + $priorities = [ + Store::STATUS_PENDING, + Store::STATUS_FAILED, + Store::STATUS_CANCELED, + Store::STATUS_COMPLETE, + Store::STATUS_RUNNING, + '', // any other unanticipated status + ]; + + foreach ( $priorities as $status ) { + yield wp_parse_args( [ + 'status' => $status, + 'date_compare' => '<=', + ], $args ); + yield wp_parse_args( [ + 'status' => $status, + 'date_compare' => '>=', + ], $args ); + } + } +} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Config.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Config.php new file mode 100644 index 000000000..50f41ff49 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Config.php @@ -0,0 +1,168 @@ +source_store ) ) { + throw new \RuntimeException( __( 'Source store must be configured before running a migration', 'action-scheduler' ) ); + } + + return $this->source_store; + } + + /** + * Set the configured source store. + * + * @param ActionScheduler_Store $store Source store object. + */ + public function set_source_store( Store $store ) { + $this->source_store = $store; + } + + /** + * Get the configured source loger. + * + * @return ActionScheduler_Logger + */ + public function get_source_logger() { + if ( empty( $this->source_logger ) ) { + throw new \RuntimeException( __( 'Source logger must be configured before running a migration', 'action-scheduler' ) ); + } + + return $this->source_logger; + } + + /** + * Set the configured source logger. + * + * @param ActionScheduler_Logger $logger + */ + public function set_source_logger( Logger $logger ) { + $this->source_logger = $logger; + } + + /** + * Get the configured destination store. + * + * @return ActionScheduler_Store + */ + public function get_destination_store() { + if ( empty( $this->destination_store ) ) { + throw new \RuntimeException( __( 'Destination store must be configured before running a migration', 'action-scheduler' ) ); + } + + return $this->destination_store; + } + + /** + * Set the configured destination store. + * + * @param ActionScheduler_Store $store + */ + public function set_destination_store( Store $store ) { + $this->destination_store = $store; + } + + /** + * Get the configured destination logger. + * + * @return ActionScheduler_Logger + */ + public function get_destination_logger() { + if ( empty( $this->destination_logger ) ) { + throw new \RuntimeException( __( 'Destination logger must be configured before running a migration', 'action-scheduler' ) ); + } + + return $this->destination_logger; + } + + /** + * Set the configured destination logger. + * + * @param ActionScheduler_Logger $logger + */ + public function set_destination_logger( Logger $logger ) { + $this->destination_logger = $logger; + } + + /** + * Get flag indicating whether it's a dry run. + * + * @return bool + */ + public function get_dry_run() { + return $this->dry_run; + } + + /** + * Set flag indicating whether it's a dry run. + * + * @param bool $dry_run + */ + public function set_dry_run( $dry_run ) { + $this->dry_run = (bool) $dry_run; + } + + /** + * Get progress bar object. + * + * @return ActionScheduler\WPCLI\ProgressBar + */ + public function get_progress_bar() { + return $this->progress_bar; + } + + /** + * Set progress bar object. + * + * @param ActionScheduler\WPCLI\ProgressBar $progress_bar + */ + public function set_progress_bar( ProgressBar $progress_bar ) { + $this->progress_bar = $progress_bar; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Controller.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Controller.php new file mode 100644 index 000000000..b2b618d8f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Controller.php @@ -0,0 +1,226 @@ +migration_scheduler = $migration_scheduler; + $this->store_classname = ''; + } + + /** + * Set the action store class name. + * + * @param string $class Classname of the store class. + * + * @return string + */ + public function get_store_class( $class ) { + if ( \ActionScheduler_DataController::is_migration_complete() ) { + return \ActionScheduler_DataController::DATASTORE_CLASS; + } elseif ( \ActionScheduler_Store::DEFAULT_CLASS !== $class ) { + $this->store_classname = $class; + return $class; + } else { + return 'ActionScheduler_HybridStore'; + } + } + + /** + * Set the action logger class name. + * + * @param string $class Classname of the logger class. + * + * @return string + */ + public function get_logger_class( $class ) { + \ActionScheduler_Store::instance(); + + if ( $this->has_custom_datastore() ) { + $this->logger_classname = $class; + return $class; + } else { + return \ActionScheduler_DataController::LOGGER_CLASS; + } + } + + /** + * Get flag indicating whether a custom datastore is in use. + * + * @return bool + */ + public function has_custom_datastore() { + return (bool) $this->store_classname; + } + + /** + * Set up the background migration process. + * + * @return void + */ + public function schedule_migration() { + $logging_tables = new ActionScheduler_LoggerSchema(); + $store_tables = new ActionScheduler_StoreSchema(); + + /* + * In some unusual cases, the expected tables may not have been created. In such cases + * we do not schedule a migration as doing so will lead to fatal error conditions. + * + * In such cases the user will likely visit the Tools > Scheduled Actions screen to + * investigate, and will see appropriate messaging (this step also triggers an attempt + * to rebuild any missing tables). + * + * @see https://github.com/woocommerce/action-scheduler/issues/653 + */ + if ( + ActionScheduler_DataController::is_migration_complete() + || $this->migration_scheduler->is_migration_scheduled() + || ! $store_tables->tables_exist() + || ! $logging_tables->tables_exist() + ) { + return; + } + + $this->migration_scheduler->schedule_migration(); + } + + /** + * Get the default migration config object + * + * @return ActionScheduler\Migration\Config + */ + public function get_migration_config_object() { + static $config = null; + + if ( ! $config ) { + $source_store = $this->store_classname ? new $this->store_classname() : new \ActionScheduler_wpPostStore(); + $source_logger = $this->logger_classname ? new $this->logger_classname() : new \ActionScheduler_wpCommentLogger(); + + $config = new Config(); + $config->set_source_store( $source_store ); + $config->set_source_logger( $source_logger ); + $config->set_destination_store( new \ActionScheduler_DBStoreMigrator() ); + $config->set_destination_logger( new \ActionScheduler_DBLogger() ); + + if ( defined( 'WP_CLI' ) && WP_CLI ) { + $config->set_progress_bar( new ProgressBar( '', 0 ) ); + } + } + + return apply_filters( 'action_scheduler/migration_config', $config ); + } + + /** + * Hook dashboard migration notice. + */ + public function hook_admin_notices() { + if ( ! $this->allow_migration() || \ActionScheduler_DataController::is_migration_complete() ) { + return; + } + add_action( 'admin_notices', array( $this, 'display_migration_notice' ), 10, 0 ); + } + + /** + * Show a dashboard notice that migration is in progress. + */ + public function display_migration_notice() { + printf( '

    %s

    ', esc_html__( 'Action Scheduler migration in progress. The list of scheduled actions may be incomplete.', 'action-scheduler' ) ); + } + + /** + * Add store classes. Hook migration. + */ + private function hook() { + add_filter( 'action_scheduler_store_class', array( $this, 'get_store_class' ), 100, 1 ); + add_filter( 'action_scheduler_logger_class', array( $this, 'get_logger_class' ), 100, 1 ); + add_action( 'init', array( $this, 'maybe_hook_migration' ) ); + add_action( 'wp_loaded', array( $this, 'schedule_migration' ) ); + + // Action Scheduler may be displayed as a Tools screen or WooCommerce > Status administration screen + add_action( 'load-tools_page_action-scheduler', array( $this, 'hook_admin_notices' ), 10, 0 ); + add_action( 'load-woocommerce_page_wc-status', array( $this, 'hook_admin_notices' ), 10, 0 ); + } + + /** + * Possibly hook the migration scheduler action. + * + * @author Jeremy Pry + */ + public function maybe_hook_migration() { + if ( ! $this->allow_migration() || \ActionScheduler_DataController::is_migration_complete() ) { + return; + } + + $this->migration_scheduler->hook(); + } + + /** + * Allow datastores to enable migration to AS tables. + */ + public function allow_migration() { + if ( ! \ActionScheduler_DataController::dependencies_met() ) { + return false; + } + + if ( null === $this->migrate_custom_store ) { + $this->migrate_custom_store = apply_filters( 'action_scheduler_migrate_data_store', false ); + } + + return ( ! $this->has_custom_datastore() ) || $this->migrate_custom_store; + } + + /** + * Proceed with the migration if the dependencies have been met. + */ + public static function init() { + if ( \ActionScheduler_DataController::dependencies_met() ) { + self::instance()->hook(); + } + } + + /** + * Singleton factory. + */ + public static function instance() { + if ( ! isset( self::$instance ) ) { + self::$instance = new static( new Scheduler() ); + } + + return self::$instance; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/DryRun_ActionMigrator.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/DryRun_ActionMigrator.php new file mode 100644 index 000000000..ffc21c287 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/DryRun_ActionMigrator.php @@ -0,0 +1,28 @@ +source = $source_logger; + $this->destination = $destination_Logger; + } + + /** + * Migrate an action log. + * + * @param int $source_action_id Source logger object. + * @param int $destination_action_id Destination logger object. + */ + public function migrate( $source_action_id, $destination_action_id ) { + $logs = $this->source->get_logs( $source_action_id ); + foreach ( $logs as $log ) { + if ( $log->get_action_id() == $source_action_id ) { + $this->destination->log( $destination_action_id, $log->get_message(), $log->get_date() ); + } + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Runner.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Runner.php new file mode 100644 index 000000000..867c5de68 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Runner.php @@ -0,0 +1,136 @@ +source_store = $config->get_source_store(); + $this->destination_store = $config->get_destination_store(); + $this->source_logger = $config->get_source_logger(); + $this->destination_logger = $config->get_destination_logger(); + + $this->batch_fetcher = new BatchFetcher( $this->source_store ); + if ( $config->get_dry_run() ) { + $this->log_migrator = new DryRun_LogMigrator( $this->source_logger, $this->destination_logger ); + $this->action_migrator = new DryRun_ActionMigrator( $this->source_store, $this->destination_store, $this->log_migrator ); + } else { + $this->log_migrator = new LogMigrator( $this->source_logger, $this->destination_logger ); + $this->action_migrator = new ActionMigrator( $this->source_store, $this->destination_store, $this->log_migrator ); + } + + if ( defined( 'WP_CLI' ) && WP_CLI ) { + $this->progress_bar = $config->get_progress_bar(); + } + } + + /** + * Run migration batch. + * + * @param int $batch_size Optional batch size. Default 10. + * + * @return int Size of batch processed. + */ + public function run( $batch_size = 10 ) { + $batch = $this->batch_fetcher->fetch( $batch_size ); + $batch_size = count( $batch ); + + if ( ! $batch_size ) { + return 0; + } + + if ( $this->progress_bar ) { + /* translators: %d: amount of actions */ + $this->progress_bar->set_message( sprintf( _n( 'Migrating %d action', 'Migrating %d actions', $batch_size, 'action-scheduler' ), number_format_i18n( $batch_size ) ) ); + $this->progress_bar->set_count( $batch_size ); + } + + $this->migrate_actions( $batch ); + + return $batch_size; + } + + /** + * Migration a batch of actions. + * + * @param array $action_ids List of action IDs to migrate. + */ + public function migrate_actions( array $action_ids ) { + do_action( 'action_scheduler/migration_batch_starting', $action_ids ); + + \ActionScheduler::logger()->unhook_stored_action(); + $this->destination_logger->unhook_stored_action(); + + foreach ( $action_ids as $source_action_id ) { + $destination_action_id = $this->action_migrator->migrate( $source_action_id ); + if ( $destination_action_id ) { + $this->destination_logger->log( $destination_action_id, sprintf( + /* translators: 1: source action ID 2: source store class 3: destination action ID 4: destination store class */ + __( 'Migrated action with ID %1$d in %2$s to ID %3$d in %4$s', 'action-scheduler' ), + $source_action_id, + get_class( $this->source_store ), + $destination_action_id, + get_class( $this->destination_store ) + ) ); + } + + if ( $this->progress_bar ) { + $this->progress_bar->tick(); + } + } + + if ( $this->progress_bar ) { + $this->progress_bar->finish(); + } + + \ActionScheduler::logger()->hook_stored_action(); + + do_action( 'action_scheduler/migration_batch_complete', $action_ids ); + } + + /** + * Initialize destination store and logger. + */ + public function init_destination() { + $this->destination_store->init(); + $this->destination_logger->init(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Scheduler.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Scheduler.php new file mode 100644 index 000000000..dcbe2db5f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/migration/Scheduler.php @@ -0,0 +1,128 @@ +get_migration_runner(); + $count = $migration_runner->run( $this->get_batch_size() ); + + if ( $count === 0 ) { + $this->mark_complete(); + } else { + $this->schedule_migration( time() + $this->get_schedule_interval() ); + } + } + + /** + * Mark the migration complete. + */ + public function mark_complete() { + $this->unschedule_migration(); + + \ActionScheduler_DataController::mark_migration_complete(); + do_action( 'action_scheduler/migration_complete' ); + } + + /** + * Get a flag indicating whether the migration is scheduled. + * + * @return bool Whether there is a pending action in the store to handle the migration + */ + public function is_migration_scheduled() { + $next = as_next_scheduled_action( self::HOOK ); + + return ! empty( $next ); + } + + /** + * Schedule the migration. + * + * @param int $when Optional timestamp to run the next migration batch. Defaults to now. + * + * @return string The action ID + */ + public function schedule_migration( $when = 0 ) { + $next = as_next_scheduled_action( self::HOOK ); + + if ( ! empty( $next ) ) { + return $next; + } + + if ( empty( $when ) ) { + $when = time() + MINUTE_IN_SECONDS; + } + + return as_schedule_single_action( $when, self::HOOK, array(), self::GROUP ); + } + + /** + * Remove the scheduled migration action. + */ + public function unschedule_migration() { + as_unschedule_action( self::HOOK, null, self::GROUP ); + } + + /** + * Get migration batch schedule interval. + * + * @return int Seconds between migration runs. Defaults to 0 seconds to allow chaining migration via Async Runners. + */ + private function get_schedule_interval() { + return (int) apply_filters( 'action_scheduler/migration_interval', 0 ); + } + + /** + * Get migration batch size. + * + * @return int Number of actions to migrate in each batch. Defaults to 250. + */ + private function get_batch_size() { + return (int) apply_filters( 'action_scheduler/migration_batch_size', 250 ); + } + + /** + * Get migration runner object. + * + * @return Runner + */ + private function get_migration_runner() { + $config = Controller::instance()->get_migration_config_object(); + + return new Runner( $config ); + } + +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_CanceledSchedule.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_CanceledSchedule.php new file mode 100644 index 000000000..840e482c1 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_CanceledSchedule.php @@ -0,0 +1,57 @@ +__wakeup() for details. + **/ + private $timestamp = NULL; + + /** + * @param DateTime $after + * + * @return DateTime|null + */ + public function calculate_next( DateTime $after ) { + return null; + } + + /** + * Cancelled actions should never have a next schedule, even if get_next() + * is called with $after < $this->scheduled_date. + * + * @param DateTime $after + * @return DateTime|null + */ + public function get_next( DateTime $after ) { + return null; + } + + /** + * @return bool + */ + public function is_recurring() { + return false; + } + + /** + * Unserialize recurring schedules serialized/stored prior to AS 3.0.0 + * + * Prior to Action Scheduler 3.0.0, schedules used different property names to refer + * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp + * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 + * aligned properties and property names for better inheritance. To maintain backward + * compatibility with schedules serialized and stored prior to 3.0, we need to correctly + * map the old property names with matching visibility. + */ + public function __wakeup() { + if ( ! is_null( $this->timestamp ) ) { + $this->scheduled_timestamp = $this->timestamp; + unset( $this->timestamp ); + } + parent::__wakeup(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_CronSchedule.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_CronSchedule.php new file mode 100644 index 000000000..7859307ac --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_CronSchedule.php @@ -0,0 +1,102 @@ +__wakeup() for details. + **/ + private $start_timestamp = NULL; + + /** + * Deprecated property @see $this->__wakeup() for details. + **/ + private $cron = NULL; + + /** + * Wrapper for parent constructor to accept a cron expression string and map it to a CronExpression for this + * objects $recurrence property. + * + * @param DateTime $start The date & time to run the action at or after. If $start aligns with the CronSchedule passed via $recurrence, it will be used. If it does not align, the first matching date after it will be used. + * @param CronExpression|string $recurrence The CronExpression used to calculate the schedule's next instance. + * @param DateTime|null $first (Optional) The date & time the first instance of this interval schedule ran. Default null, meaning this is the first instance. + */ + public function __construct( DateTime $start, $recurrence, DateTime $first = null ) { + if ( ! is_a( $recurrence, 'CronExpression' ) ) { + $recurrence = CronExpression::factory( $recurrence ); + } + + // For backward compatibility, we need to make sure the date is set to the first matching cron date, not whatever date is passed in. Importantly, by passing true as the 3rd param, if $start matches the cron expression, then it will be used. This was previously handled in the now deprecated next() method. + $date = $recurrence->getNextRunDate( $start, 0, true ); + + // parent::__construct() will set this to $date by default, but that may be different to $start now. + $first = empty( $first ) ? $start : $first; + + parent::__construct( $date, $recurrence, $first ); + } + + /** + * Calculate when an instance of this schedule would start based on a given + * date & time using its the CronExpression. + * + * @param DateTime $after + * @return DateTime + */ + protected function calculate_next( DateTime $after ) { + return $this->recurrence->getNextRunDate( $after, 0, false ); + } + + /** + * @return string + */ + public function get_recurrence() { + return strval( $this->recurrence ); + } + + /** + * Serialize cron schedules with data required prior to AS 3.0.0 + * + * Prior to Action Scheduler 3.0.0, reccuring schedules used different property names to + * refer to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp + * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 + * aligned properties and property names for better inheritance. To guard against the + * possibility of infinite loops if downgrading to Action Scheduler < 3.0.0, we need to + * also store the data with the old property names so if it's unserialized in AS < 3.0, + * the schedule doesn't end up with a null recurrence. + * + * @return array + */ + public function __sleep() { + + $sleep_params = parent::__sleep(); + + $this->start_timestamp = $this->scheduled_timestamp; + $this->cron = $this->recurrence; + + return array_merge( $sleep_params, array( + 'start_timestamp', + 'cron' + ) ); + } + + /** + * Unserialize cron schedules serialized/stored prior to AS 3.0.0 + * + * For more background, @see ActionScheduler_Abstract_RecurringSchedule::__wakeup(). + */ + public function __wakeup() { + if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->start_timestamp ) ) { + $this->scheduled_timestamp = $this->start_timestamp; + unset( $this->start_timestamp ); + } + + if ( is_null( $this->recurrence ) && ! is_null( $this->cron ) ) { + $this->recurrence = $this->cron; + unset( $this->cron ); + } + parent::__wakeup(); + } +} + diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_IntervalSchedule.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_IntervalSchedule.php new file mode 100644 index 000000000..11a591e80 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_IntervalSchedule.php @@ -0,0 +1,81 @@ +__wakeup() for details. + **/ + private $start_timestamp = NULL; + + /** + * Deprecated property @see $this->__wakeup() for details. + **/ + private $interval_in_seconds = NULL; + + /** + * Calculate when this schedule should start after a given date & time using + * the number of seconds between recurrences. + * + * @param DateTime $after + * @return DateTime + */ + protected function calculate_next( DateTime $after ) { + $after->modify( '+' . (int) $this->get_recurrence() . ' seconds' ); + return $after; + } + + /** + * @return int + */ + public function interval_in_seconds() { + _deprecated_function( __METHOD__, '3.0.0', '(int)ActionScheduler_Abstract_RecurringSchedule::get_recurrence()' ); + return (int) $this->get_recurrence(); + } + + /** + * Serialize interval schedules with data required prior to AS 3.0.0 + * + * Prior to Action Scheduler 3.0.0, reccuring schedules used different property names to + * refer to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp + * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 + * aligned properties and property names for better inheritance. To guard against the + * possibility of infinite loops if downgrading to Action Scheduler < 3.0.0, we need to + * also store the data with the old property names so if it's unserialized in AS < 3.0, + * the schedule doesn't end up with a null/false/0 recurrence. + * + * @return array + */ + public function __sleep() { + + $sleep_params = parent::__sleep(); + + $this->start_timestamp = $this->scheduled_timestamp; + $this->interval_in_seconds = $this->recurrence; + + return array_merge( $sleep_params, array( + 'start_timestamp', + 'interval_in_seconds' + ) ); + } + + /** + * Unserialize interval schedules serialized/stored prior to AS 3.0.0 + * + * For more background, @see ActionScheduler_Abstract_RecurringSchedule::__wakeup(). + */ + public function __wakeup() { + if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->start_timestamp ) ) { + $this->scheduled_timestamp = $this->start_timestamp; + unset( $this->start_timestamp ); + } + + if ( is_null( $this->recurrence ) && ! is_null( $this->interval_in_seconds ) ) { + $this->recurrence = $this->interval_in_seconds; + unset( $this->interval_in_seconds ); + } + parent::__wakeup(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_NullSchedule.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_NullSchedule.php new file mode 100644 index 000000000..1b1afec02 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_NullSchedule.php @@ -0,0 +1,31 @@ +scheduled_date = null; + } + + /** + * This schedule has no scheduled DateTime, so we need to override the parent __sleep() + * @return array + */ + public function __sleep() { + return array(); + } + + public function __wakeup() { + $this->scheduled_date = null; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_Schedule.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_Schedule.php new file mode 100644 index 000000000..d61a9f7c9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schedules/ActionScheduler_Schedule.php @@ -0,0 +1,18 @@ +__wakeup() for details. + **/ + private $timestamp = NULL; + + /** + * @param DateTime $after + * + * @return DateTime|null + */ + public function calculate_next( DateTime $after ) { + return null; + } + + /** + * @return bool + */ + public function is_recurring() { + return false; + } + + /** + * Serialize schedule with data required prior to AS 3.0.0 + * + * Prior to Action Scheduler 3.0.0, schedules used different property names to refer + * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp + * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 + * aligned properties and property names for better inheritance. To guard against the + * scheduled date for single actions always being seen as "now" if downgrading to + * Action Scheduler < 3.0.0, we need to also store the data with the old property names + * so if it's unserialized in AS < 3.0, the schedule doesn't end up with a null recurrence. + * + * @return array + */ + public function __sleep() { + + $sleep_params = parent::__sleep(); + + $this->timestamp = $this->scheduled_timestamp; + + return array_merge( $sleep_params, array( + 'timestamp', + ) ); + } + + /** + * Unserialize recurring schedules serialized/stored prior to AS 3.0.0 + * + * Prior to Action Scheduler 3.0.0, schedules used different property names to refer + * to equivalent data. For example, ActionScheduler_IntervalSchedule::start_timestamp + * was the same as ActionScheduler_SimpleSchedule::timestamp. Action Scheduler 3.0.0 + * aligned properties and property names for better inheritance. To maintain backward + * compatibility with schedules serialized and stored prior to 3.0, we need to correctly + * map the old property names with matching visibility. + */ + public function __wakeup() { + + if ( is_null( $this->scheduled_timestamp ) && ! is_null( $this->timestamp ) ) { + $this->scheduled_timestamp = $this->timestamp; + unset( $this->timestamp ); + } + parent::__wakeup(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schema/ActionScheduler_LoggerSchema.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schema/ActionScheduler_LoggerSchema.php new file mode 100644 index 000000000..c52d37ce0 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schema/ActionScheduler_LoggerSchema.php @@ -0,0 +1,90 @@ +tables = [ + self::LOG_TABLE, + ]; + } + + /** + * Performs additional setup work required to support this schema. + */ + public function init() { + add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_3_0' ), 10, 2 ); + } + + protected function get_table_definition( $table ) { + global $wpdb; + $table_name = $wpdb->$table; + $charset_collate = $wpdb->get_charset_collate(); + switch ( $table ) { + + case self::LOG_TABLE: + + $default_date = ActionScheduler_StoreSchema::DEFAULT_DATE; + return "CREATE TABLE $table_name ( + log_id bigint(20) unsigned NOT NULL auto_increment, + action_id bigint(20) unsigned NOT NULL, + message text NOT NULL, + log_date_gmt datetime NULL default '{$default_date}', + log_date_local datetime NULL default '{$default_date}', + PRIMARY KEY (log_id), + KEY action_id (action_id), + KEY log_date_gmt (log_date_gmt) + ) $charset_collate"; + + default: + return ''; + } + } + + /** + * Update the logs table schema, allowing datetime fields to be NULL. + * + * This is needed because the NOT NULL constraint causes a conflict with some versions of MySQL + * configured with sql_mode=NO_ZERO_DATE, which can for instance lead to tables not being created. + * + * Most other schema updates happen via ActionScheduler_Abstract_Schema::update_table(), however + * that method relies on dbDelta() and this change is not possible when using that function. + * + * @param string $table Name of table being updated. + * @param string $db_version The existing schema version of the table. + */ + public function update_schema_3_0( $table, $db_version ) { + global $wpdb; + + if ( 'actionscheduler_logs' !== $table || version_compare( $db_version, '3', '>=' ) ) { + return; + } + + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $table_name = $wpdb->prefix . 'actionscheduler_logs'; + $table_list = $wpdb->get_col( "SHOW TABLES LIKE '{$table_name}'" ); + $default_date = ActionScheduler_StoreSchema::DEFAULT_DATE; + + if ( ! empty( $table_list ) ) { + $query = " + ALTER TABLE {$table_name} + MODIFY COLUMN log_date_gmt datetime NULL default '{$default_date}', + MODIFY COLUMN log_date_local datetime NULL default '{$default_date}' + "; + $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schema/ActionScheduler_StoreSchema.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schema/ActionScheduler_StoreSchema.php new file mode 100644 index 000000000..d52f27f6f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/classes/schema/ActionScheduler_StoreSchema.php @@ -0,0 +1,129 @@ +tables = [ + self::ACTIONS_TABLE, + self::CLAIMS_TABLE, + self::GROUPS_TABLE, + ]; + } + + /** + * Performs additional setup work required to support this schema. + */ + public function init() { + add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_5_0' ), 10, 2 ); + } + + protected function get_table_definition( $table ) { + global $wpdb; + $table_name = $wpdb->$table; + $charset_collate = $wpdb->get_charset_collate(); + $max_index_length = 191; // @see wp_get_db_schema() + $default_date = self::DEFAULT_DATE; + switch ( $table ) { + + case self::ACTIONS_TABLE: + + return "CREATE TABLE {$table_name} ( + action_id bigint(20) unsigned NOT NULL auto_increment, + hook varchar(191) NOT NULL, + status varchar(20) NOT NULL, + scheduled_date_gmt datetime NULL default '{$default_date}', + scheduled_date_local datetime NULL default '{$default_date}', + args varchar($max_index_length), + schedule longtext, + group_id bigint(20) unsigned NOT NULL default '0', + attempts int(11) NOT NULL default '0', + last_attempt_gmt datetime NULL default '{$default_date}', + last_attempt_local datetime NULL default '{$default_date}', + claim_id bigint(20) unsigned NOT NULL default '0', + extended_args varchar(8000) DEFAULT NULL, + PRIMARY KEY (action_id), + KEY hook (hook($max_index_length)), + KEY status (status), + KEY scheduled_date_gmt (scheduled_date_gmt), + KEY args (args($max_index_length)), + KEY group_id (group_id), + KEY last_attempt_gmt (last_attempt_gmt), + KEY `claim_id_status_scheduled_date_gmt` (`claim_id`, `status`, `scheduled_date_gmt`) + ) $charset_collate"; + + case self::CLAIMS_TABLE: + + return "CREATE TABLE {$table_name} ( + claim_id bigint(20) unsigned NOT NULL auto_increment, + date_created_gmt datetime NULL default '{$default_date}', + PRIMARY KEY (claim_id), + KEY date_created_gmt (date_created_gmt) + ) $charset_collate"; + + case self::GROUPS_TABLE: + + return "CREATE TABLE {$table_name} ( + group_id bigint(20) unsigned NOT NULL auto_increment, + slug varchar(255) NOT NULL, + PRIMARY KEY (group_id), + KEY slug (slug($max_index_length)) + ) $charset_collate"; + + default: + return ''; + } + } + + /** + * Update the actions table schema, allowing datetime fields to be NULL. + * + * This is needed because the NOT NULL constraint causes a conflict with some versions of MySQL + * configured with sql_mode=NO_ZERO_DATE, which can for instance lead to tables not being created. + * + * Most other schema updates happen via ActionScheduler_Abstract_Schema::update_table(), however + * that method relies on dbDelta() and this change is not possible when using that function. + * + * @param string $table Name of table being updated. + * @param string $db_version The existing schema version of the table. + */ + public function update_schema_5_0( $table, $db_version ) { + global $wpdb; + + if ( 'actionscheduler_actions' !== $table || version_compare( $db_version, '5', '>=' ) ) { + return; + } + + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared + $table_name = $wpdb->prefix . 'actionscheduler_actions'; + $table_list = $wpdb->get_col( "SHOW TABLES LIKE '{$table_name}'" ); + $default_date = self::DEFAULT_DATE; + + if ( ! empty( $table_list ) ) { + $query = " + ALTER TABLE {$table_name} + MODIFY COLUMN scheduled_date_gmt datetime NULL default '{$default_date}', + MODIFY COLUMN scheduled_date_local datetime NULL default '{$default_date}', + MODIFY COLUMN last_attempt_gmt datetime NULL default '{$default_date}', + MODIFY COLUMN last_attempt_local datetime NULL default '{$default_date}' + "; + $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + } + // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_Abstract_QueueRunner_Deprecated.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_Abstract_QueueRunner_Deprecated.php new file mode 100644 index 000000000..dac17aa42 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_Abstract_QueueRunner_Deprecated.php @@ -0,0 +1,27 @@ +get_date(); + $replacement_method = 'get_date()'; + } else { + $return_value = $this->get_next( $after ); + $replacement_method = 'get_next( $after )'; + } + + _deprecated_function( __METHOD__, '3.0.0', __CLASS__ . '::' . $replacement_method ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + + return $return_value; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_Store_Deprecated.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_Store_Deprecated.php new file mode 100644 index 000000000..002dc75b4 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/ActionScheduler_Store_Deprecated.php @@ -0,0 +1,49 @@ +mark_failure( $action_id ); + } + + /** + * Add base hooks + * + * @since 2.2.6 + */ + protected static function hook() { + _deprecated_function( __METHOD__, '3.0.0' ); + } + + /** + * Remove base hooks + * + * @since 2.2.6 + */ + protected static function unhook() { + _deprecated_function( __METHOD__, '3.0.0' ); + } + + /** + * Get the site's local time. + * + * @deprecated 2.1.0 + * @return DateTimeZone + */ + protected function get_local_timezone() { + _deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' ); + return ActionScheduler_TimezoneHelper::get_local_timezone(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/functions.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/functions.php new file mode 100644 index 000000000..f782c4b7f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/deprecated/functions.php @@ -0,0 +1,126 @@ + '' - the name of the action that will be triggered + * 'args' => NULL - the args array that will be passed with the action + * 'date' => NULL - the scheduled date of the action. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. + * 'date_compare' => '<=' - operator for testing "date". accepted values are '!=', '>', '>=', '<', '<=', '=' + * 'modified' => NULL - the date the action was last updated. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. + * 'modified_compare' => '<=' - operator for testing "modified". accepted values are '!=', '>', '>=', '<', '<=', '=' + * 'group' => '' - the group the action belongs to + * 'status' => '' - ActionScheduler_Store::STATUS_COMPLETE or ActionScheduler_Store::STATUS_PENDING + * 'claimed' => NULL - TRUE to find claimed actions, FALSE to find unclaimed actions, a string to find a specific claim ID + * 'per_page' => 5 - Number of results to return + * 'offset' => 0 + * 'orderby' => 'date' - accepted values are 'hook', 'group', 'modified', or 'date' + * 'order' => 'ASC' + * @param string $return_format OBJECT, ARRAY_A, or ids + * + * @deprecated 2.1.0 + * + * @return array + */ +function wc_get_scheduled_actions( $args = array(), $return_format = OBJECT ) { + _deprecated_function( __FUNCTION__, '2.1.0', 'as_get_scheduled_actions()' ); + return as_get_scheduled_actions( $args, $return_format ); +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/functions.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/functions.php new file mode 100644 index 000000000..09ef353d9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/functions.php @@ -0,0 +1,424 @@ +async_unique( $hook, $args, $group, $unique ); +} + +/** + * Schedule an action to run one time + * + * @param int $timestamp When the job will run. + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @param string $group The group to assign this job to. + * @param bool $unique Whether the action should be unique. + * + * @return int The action ID. + */ +function as_schedule_single_action( $timestamp, $hook, $args = array(), $group = '', $unique = false ) { + if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) { + return 0; + } + + /** + * Provides an opportunity to short-circuit the default process for enqueuing single + * actions. + * + * Returning a value other than null from the filter will short-circuit the normal + * process. The expectation in such a scenario is that callbacks will return an integer + * representing the scheduled action ID (scheduled using some alternative process) or else + * zero. + * + * @param int|null $pre_option The value to return instead of the option value. + * @param int $timestamp When the action will run. + * @param string $hook Action hook. + * @param array $args Action arguments. + * @param string $group Action group. + */ + $pre = apply_filters( 'pre_as_schedule_single_action', null, $timestamp, $hook, $args, $group ); + if ( null !== $pre ) { + return is_int( $pre ) ? $pre : 0; + } + + return ActionScheduler::factory()->single_unique( $hook, $args, $timestamp, $group, $unique ); +} + +/** + * Schedule a recurring action + * + * @param int $timestamp When the first instance of the job will run. + * @param int $interval_in_seconds How long to wait between runs. + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @param string $group The group to assign this job to. + * @param bool $unique Whether the action should be unique. + * + * @return int The action ID. + */ +function as_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook, $args = array(), $group = '', $unique = false ) { + if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) { + return 0; + } + + /** + * Provides an opportunity to short-circuit the default process for enqueuing recurring + * actions. + * + * Returning a value other than null from the filter will short-circuit the normal + * process. The expectation in such a scenario is that callbacks will return an integer + * representing the scheduled action ID (scheduled using some alternative process) or else + * zero. + * + * @param int|null $pre_option The value to return instead of the option value. + * @param int $timestamp When the action will run. + * @param int $interval_in_seconds How long to wait between runs. + * @param string $hook Action hook. + * @param array $args Action arguments. + * @param string $group Action group. + */ + $pre = apply_filters( 'pre_as_schedule_recurring_action', null, $timestamp, $interval_in_seconds, $hook, $args, $group ); + if ( null !== $pre ) { + return is_int( $pre ) ? $pre : 0; + } + + return ActionScheduler::factory()->recurring_unique( $hook, $args, $timestamp, $interval_in_seconds, $group, $unique ); +} + +/** + * Schedule an action that recurs on a cron-like schedule. + * + * @param int $timestamp The first instance of the action will be scheduled + * to run at a time calculated after this timestamp matching the cron + * expression. This can be used to delay the first instance of the action. + * @param string $schedule A cron-link schedule string. + * @see http://en.wikipedia.org/wiki/Cron + * * * * * * * + * ┬ ┬ ┬ ┬ ┬ ┬ + * | | | | | | + * | | | | | + year [optional] + * | | | | +----- day of week (0 - 7) (Sunday=0 or 7) + * | | | +---------- month (1 - 12) + * | | +--------------- day of month (1 - 31) + * | +-------------------- hour (0 - 23) + * +------------------------- min (0 - 59) + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @param string $group The group to assign this job to. + * @param bool $unique Whether the action should be unique. + * + * @return int The action ID. + */ +function as_schedule_cron_action( $timestamp, $schedule, $hook, $args = array(), $group = '', $unique = false ) { + if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) { + return 0; + } + + /** + * Provides an opportunity to short-circuit the default process for enqueuing cron + * actions. + * + * Returning a value other than null from the filter will short-circuit the normal + * process. The expectation in such a scenario is that callbacks will return an integer + * representing the scheduled action ID (scheduled using some alternative process) or else + * zero. + * + * @param int|null $pre_option The value to return instead of the option value. + * @param int $timestamp When the action will run. + * @param string $schedule Cron-like schedule string. + * @param string $hook Action hook. + * @param array $args Action arguments. + * @param string $group Action group. + */ + $pre = apply_filters( 'pre_as_schedule_cron_action', null, $timestamp, $schedule, $hook, $args, $group ); + if ( null !== $pre ) { + return is_int( $pre ) ? $pre : 0; + } + + return ActionScheduler::factory()->cron_unique( $hook, $args, $timestamp, $schedule, $group, $unique ); +} + +/** + * Cancel the next occurrence of a scheduled action. + * + * While only the next instance of a recurring or cron action is unscheduled by this method, that will also prevent + * all future instances of that recurring or cron action from being run. Recurring and cron actions are scheduled in + * a sequence instead of all being scheduled at once. Each successive occurrence of a recurring action is scheduled + * only after the former action is run. If the next instance is never run, because it's unscheduled by this function, + * then the following instance will never be scheduled (or exist), which is effectively the same as being unscheduled + * by this method also. + * + * @param string $hook The hook that the job will trigger. + * @param array $args Args that would have been passed to the job. + * @param string $group The group the job is assigned to. + * + * @return int|null The scheduled action ID if a scheduled action was found, or null if no matching action found. + */ +function as_unschedule_action( $hook, $args = array(), $group = '' ) { + if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) { + return 0; + } + $params = array( + 'hook' => $hook, + 'status' => ActionScheduler_Store::STATUS_PENDING, + 'orderby' => 'date', + 'order' => 'ASC', + 'group' => $group, + ); + if ( is_array( $args ) ) { + $params['args'] = $args; + } + + $action_id = ActionScheduler::store()->query_action( $params ); + + if ( $action_id ) { + try { + ActionScheduler::store()->cancel_action( $action_id ); + } catch ( Exception $exception ) { + ActionScheduler::logger()->log( + $action_id, + sprintf( + /* translators: %s is the name of the hook to be cancelled. */ + __( 'Caught exception while cancelling action: %s', 'action-scheduler' ), + esc_attr( $hook ) + ) + ); + + $action_id = null; + } + } + + return $action_id; +} + +/** + * Cancel all occurrences of a scheduled action. + * + * @param string $hook The hook that the job will trigger. + * @param array $args Args that would have been passed to the job. + * @param string $group The group the job is assigned to. + */ +function as_unschedule_all_actions( $hook, $args = array(), $group = '' ) { + if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) { + return; + } + if ( empty( $args ) ) { + if ( ! empty( $hook ) && empty( $group ) ) { + ActionScheduler_Store::instance()->cancel_actions_by_hook( $hook ); + return; + } + if ( ! empty( $group ) && empty( $hook ) ) { + ActionScheduler_Store::instance()->cancel_actions_by_group( $group ); + return; + } + } + do { + $unscheduled_action = as_unschedule_action( $hook, $args, $group ); + } while ( ! empty( $unscheduled_action ) ); +} + +/** + * Check if there is an existing action in the queue with a given hook, args and group combination. + * + * An action in the queue could be pending, in-progress or async. If the is pending for a time in + * future, its scheduled date will be returned as a timestamp. If it is currently being run, or an + * async action sitting in the queue waiting to be processed, in which case boolean true will be + * returned. Or there may be no async, in-progress or pending action for this hook, in which case, + * boolean false will be the return value. + * + * @param string $hook Name of the hook to search for. + * @param array $args Arguments of the action to be searched. + * @param string $group Group of the action to be searched. + * + * @return int|bool The timestamp for the next occurrence of a pending scheduled action, true for an async or in-progress action or false if there is no matching action. + */ +function as_next_scheduled_action( $hook, $args = null, $group = '' ) { + if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) { + return false; + } + + $params = array( + 'hook' => $hook, + 'orderby' => 'date', + 'order' => 'ASC', + 'group' => $group, + ); + + if ( is_array( $args ) ) { + $params['args'] = $args; + } + + $params['status'] = ActionScheduler_Store::STATUS_RUNNING; + $action_id = ActionScheduler::store()->query_action( $params ); + if ( $action_id ) { + return true; + } + + $params['status'] = ActionScheduler_Store::STATUS_PENDING; + $action_id = ActionScheduler::store()->query_action( $params ); + if ( null === $action_id ) { + return false; + } + + $action = ActionScheduler::store()->fetch_action( $action_id ); + $scheduled_date = $action->get_schedule()->get_date(); + if ( $scheduled_date ) { + return (int) $scheduled_date->format( 'U' ); + } elseif ( null === $scheduled_date ) { // pending async action with NullSchedule. + return true; + } + + return false; +} + +/** + * Check if there is a scheduled action in the queue but more efficiently than as_next_scheduled_action(). + * + * It's recommended to use this function when you need to know whether a specific action is currently scheduled + * (pending or in-progress). + * + * @since 3.3.0 + * + * @param string $hook The hook of the action. + * @param array $args Args that have been passed to the action. Null will matches any args. + * @param string $group The group the job is assigned to. + * + * @return bool True if a matching action is pending or in-progress, false otherwise. + */ +function as_has_scheduled_action( $hook, $args = null, $group = '' ) { + if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) { + return false; + } + + $query_args = array( + 'hook' => $hook, + 'status' => array( ActionScheduler_Store::STATUS_RUNNING, ActionScheduler_Store::STATUS_PENDING ), + 'group' => $group, + 'orderby' => 'none', + ); + + if ( null !== $args ) { + $query_args['args'] = $args; + } + + $action_id = ActionScheduler::store()->query_action( $query_args ); + + return null !== $action_id; +} + +/** + * Find scheduled actions + * + * @param array $args Possible arguments, with their default values. + * 'hook' => '' - the name of the action that will be triggered. + * 'args' => NULL - the args array that will be passed with the action. + * 'date' => NULL - the scheduled date of the action. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. + * 'date_compare' => '<=' - operator for testing "date". accepted values are '!=', '>', '>=', '<', '<=', '='. + * 'modified' => NULL - the date the action was last updated. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. + * 'modified_compare' => '<=' - operator for testing "modified". accepted values are '!=', '>', '>=', '<', '<=', '='. + * 'group' => '' - the group the action belongs to. + * 'status' => '' - ActionScheduler_Store::STATUS_COMPLETE or ActionScheduler_Store::STATUS_PENDING. + * 'claimed' => NULL - TRUE to find claimed actions, FALSE to find unclaimed actions, a string to find a specific claim ID. + * 'per_page' => 5 - Number of results to return. + * 'offset' => 0. + * 'orderby' => 'date' - accepted values are 'hook', 'group', 'modified', 'date' or 'none'. + * 'order' => 'ASC'. + * + * @param string $return_format OBJECT, ARRAY_A, or ids. + * + * @return array + */ +function as_get_scheduled_actions( $args = array(), $return_format = OBJECT ) { + if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) { + return array(); + } + $store = ActionScheduler::store(); + foreach ( array( 'date', 'modified' ) as $key ) { + if ( isset( $args[ $key ] ) ) { + $args[ $key ] = as_get_datetime_object( $args[ $key ] ); + } + } + $ids = $store->query_actions( $args ); + + if ( 'ids' === $return_format || 'int' === $return_format ) { + return $ids; + } + + $actions = array(); + foreach ( $ids as $action_id ) { + $actions[ $action_id ] = $store->fetch_action( $action_id ); + } + + if ( ARRAY_A == $return_format ) { + foreach ( $actions as $action_id => $action_object ) { + $actions[ $action_id ] = get_object_vars( $action_object ); + } + } + + return $actions; +} + +/** + * Helper function to create an instance of DateTime based on a given + * string and timezone. By default, will return the current date/time + * in the UTC timezone. + * + * Needed because new DateTime() called without an explicit timezone + * will create a date/time in PHP's timezone, but we need to have + * assurance that a date/time uses the right timezone (which we almost + * always want to be UTC), which means we need to always include the + * timezone when instantiating datetimes rather than leaving it up to + * the PHP default. + * + * @param mixed $date_string A date/time string. Valid formats are explained in http://php.net/manual/en/datetime.formats.php. + * @param string $timezone A timezone identifier, like UTC or Europe/Lisbon. The list of valid identifiers is available http://php.net/manual/en/timezones.php. + * + * @return ActionScheduler_DateTime + */ +function as_get_datetime_object( $date_string = null, $timezone = 'UTC' ) { + if ( is_object( $date_string ) && $date_string instanceof DateTime ) { + $date = new ActionScheduler_DateTime( $date_string->format( 'Y-m-d H:i:s' ), new DateTimeZone( $timezone ) ); + } elseif ( is_numeric( $date_string ) ) { + $date = new ActionScheduler_DateTime( '@' . $date_string, new DateTimeZone( $timezone ) ); + } else { + $date = new ActionScheduler_DateTime( null === $date_string ? 'now' : $date_string, new DateTimeZone( $timezone ) ); + } + return $date; +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/WP_Async_Request.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/WP_Async_Request.php new file mode 100644 index 000000000..ff5e29b30 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/WP_Async_Request.php @@ -0,0 +1,191 @@ +identifier = $this->prefix . '_' . $this->action; + + add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) ); + add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) ); + } + + /** + * Set data used during the request + * + * @param array $data Data. + * + * @return $this + */ + public function data( $data ) { + $this->data = $data; + + return $this; + } + + /** + * Dispatch the async request + * + * @return array|WP_Error + */ + public function dispatch() { + $url = add_query_arg( $this->get_query_args(), $this->get_query_url() ); + $args = $this->get_post_args(); + + return wp_remote_post( esc_url_raw( $url ), $args ); + } + + /** + * Get query args + * + * @return array + */ + protected function get_query_args() { + if ( property_exists( $this, 'query_args' ) ) { + return $this->query_args; + } + + $args = array( + 'action' => $this->identifier, + 'nonce' => wp_create_nonce( $this->identifier ), + ); + + /** + * Filters the post arguments used during an async request. + * + * @param array $url + */ + return apply_filters( $this->identifier . '_query_args', $args ); + } + + /** + * Get query URL + * + * @return string + */ + protected function get_query_url() { + if ( property_exists( $this, 'query_url' ) ) { + return $this->query_url; + } + + $url = admin_url( 'admin-ajax.php' ); + + /** + * Filters the post arguments used during an async request. + * + * @param string $url + */ + return apply_filters( $this->identifier . '_query_url', $url ); + } + + /** + * Get post args + * + * @return array + */ + protected function get_post_args() { + if ( property_exists( $this, 'post_args' ) ) { + return $this->post_args; + } + + $args = array( + 'timeout' => 0.01, + 'blocking' => false, + 'body' => $this->data, + 'cookies' => $_COOKIE, + 'sslverify' => apply_filters( 'https_local_ssl_verify', false ), + ); + + /** + * Filters the post arguments used during an async request. + * + * @param array $args + */ + return apply_filters( $this->identifier . '_post_args', $args ); + } + + /** + * Maybe handle + * + * Check for correct nonce and pass to handler. + */ + public function maybe_handle() { + // Don't lock up other requests while processing + session_write_close(); + + check_ajax_referer( $this->identifier, 'nonce' ); + + $this->handle(); + + wp_die(); + } + + /** + * Handle + * + * Override this method to perform any actions required + * during the async request. + */ + abstract protected function handle(); + + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression.php new file mode 100644 index 000000000..7f33c378f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression.php @@ -0,0 +1,318 @@ + + * @link http://en.wikipedia.org/wiki/Cron + */ +class CronExpression +{ + const MINUTE = 0; + const HOUR = 1; + const DAY = 2; + const MONTH = 3; + const WEEKDAY = 4; + const YEAR = 5; + + /** + * @var array CRON expression parts + */ + private $cronParts; + + /** + * @var CronExpression_FieldFactory CRON field factory + */ + private $fieldFactory; + + /** + * @var array Order in which to test of cron parts + */ + private static $order = array(self::YEAR, self::MONTH, self::DAY, self::WEEKDAY, self::HOUR, self::MINUTE); + + /** + * Factory method to create a new CronExpression. + * + * @param string $expression The CRON expression to create. There are + * several special predefined values which can be used to substitute the + * CRON expression: + * + * @yearly, @annually) - Run once a year, midnight, Jan. 1 - 0 0 1 1 * + * @monthly - Run once a month, midnight, first of month - 0 0 1 * * + * @weekly - Run once a week, midnight on Sun - 0 0 * * 0 + * @daily - Run once a day, midnight - 0 0 * * * + * @hourly - Run once an hour, first minute - 0 * * * * + * +*@param CronExpression_FieldFactory $fieldFactory (optional) Field factory to use + * + * @return CronExpression + */ + public static function factory($expression, CronExpression_FieldFactory $fieldFactory = null) + { + $mappings = array( + '@yearly' => '0 0 1 1 *', + '@annually' => '0 0 1 1 *', + '@monthly' => '0 0 1 * *', + '@weekly' => '0 0 * * 0', + '@daily' => '0 0 * * *', + '@hourly' => '0 * * * *' + ); + + if (isset($mappings[$expression])) { + $expression = $mappings[$expression]; + } + + return new self($expression, $fieldFactory ? $fieldFactory : new CronExpression_FieldFactory()); + } + + /** + * Parse a CRON expression + * + * @param string $expression CRON expression (e.g. '8 * * * *') + * @param CronExpression_FieldFactory $fieldFactory Factory to create cron fields + */ + public function __construct($expression, CronExpression_FieldFactory $fieldFactory) + { + $this->fieldFactory = $fieldFactory; + $this->setExpression($expression); + } + + /** + * Set or change the CRON expression + * + * @param string $value CRON expression (e.g. 8 * * * *) + * + * @return CronExpression + * @throws InvalidArgumentException if not a valid CRON expression + */ + public function setExpression($value) + { + $this->cronParts = preg_split('/\s/', $value, -1, PREG_SPLIT_NO_EMPTY); + if (count($this->cronParts) < 5) { + throw new InvalidArgumentException( + $value . ' is not a valid CRON expression' + ); + } + + foreach ($this->cronParts as $position => $part) { + $this->setPart($position, $part); + } + + return $this; + } + + /** + * Set part of the CRON expression + * + * @param int $position The position of the CRON expression to set + * @param string $value The value to set + * + * @return CronExpression + * @throws InvalidArgumentException if the value is not valid for the part + */ + public function setPart($position, $value) + { + if (!$this->fieldFactory->getField($position)->validate($value)) { + throw new InvalidArgumentException( + 'Invalid CRON field value ' . $value . ' as position ' . $position + ); + } + + $this->cronParts[$position] = $value; + + return $this; + } + + /** + * Get a next run date relative to the current date or a specific date + * + * @param string|DateTime $currentTime (optional) Relative calculation date + * @param int $nth (optional) Number of matches to skip before returning a + * matching next run date. 0, the default, will return the current + * date and time if the next run date falls on the current date and + * time. Setting this value to 1 will skip the first match and go to + * the second match. Setting this value to 2 will skip the first 2 + * matches and so on. + * @param bool $allowCurrentDate (optional) Set to TRUE to return the + * current date if it matches the cron expression + * + * @return DateTime + * @throws RuntimeException on too many iterations + */ + public function getNextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false) + { + return $this->getRunDate($currentTime, $nth, false, $allowCurrentDate); + } + + /** + * Get a previous run date relative to the current date or a specific date + * + * @param string|DateTime $currentTime (optional) Relative calculation date + * @param int $nth (optional) Number of matches to skip before returning + * @param bool $allowCurrentDate (optional) Set to TRUE to return the + * current date if it matches the cron expression + * + * @return DateTime + * @throws RuntimeException on too many iterations + * @see CronExpression::getNextRunDate + */ + public function getPreviousRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false) + { + return $this->getRunDate($currentTime, $nth, true, $allowCurrentDate); + } + + /** + * Get multiple run dates starting at the current date or a specific date + * + * @param int $total Set the total number of dates to calculate + * @param string|DateTime $currentTime (optional) Relative calculation date + * @param bool $invert (optional) Set to TRUE to retrieve previous dates + * @param bool $allowCurrentDate (optional) Set to TRUE to return the + * current date if it matches the cron expression + * + * @return array Returns an array of run dates + */ + public function getMultipleRunDates($total, $currentTime = 'now', $invert = false, $allowCurrentDate = false) + { + $matches = array(); + for ($i = 0; $i < max(0, $total); $i++) { + $matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate); + } + + return $matches; + } + + /** + * Get all or part of the CRON expression + * + * @param string $part (optional) Specify the part to retrieve or NULL to + * get the full cron schedule string. + * + * @return string|null Returns the CRON expression, a part of the + * CRON expression, or NULL if the part was specified but not found + */ + public function getExpression($part = null) + { + if (null === $part) { + return implode(' ', $this->cronParts); + } elseif (array_key_exists($part, $this->cronParts)) { + return $this->cronParts[$part]; + } + + return null; + } + + /** + * Helper method to output the full expression. + * + * @return string Full CRON expression + */ + public function __toString() + { + return $this->getExpression(); + } + + /** + * Determine if the cron is due to run based on the current date or a + * specific date. This method assumes that the current number of + * seconds are irrelevant, and should be called once per minute. + * + * @param string|DateTime $currentTime (optional) Relative calculation date + * + * @return bool Returns TRUE if the cron is due to run or FALSE if not + */ + public function isDue($currentTime = 'now') + { + if ('now' === $currentTime) { + $currentDate = date('Y-m-d H:i'); + $currentTime = strtotime($currentDate); + } elseif ($currentTime instanceof DateTime) { + $currentDate = $currentTime->format('Y-m-d H:i'); + $currentTime = strtotime($currentDate); + } else { + $currentTime = new DateTime($currentTime); + $currentTime->setTime($currentTime->format('H'), $currentTime->format('i'), 0); + $currentDate = $currentTime->format('Y-m-d H:i'); + $currentTime = (int)($currentTime->getTimestamp()); + } + + return $this->getNextRunDate($currentDate, 0, true)->getTimestamp() == $currentTime; + } + + /** + * Get the next or previous run date of the expression relative to a date + * + * @param string|DateTime $currentTime (optional) Relative calculation date + * @param int $nth (optional) Number of matches to skip before returning + * @param bool $invert (optional) Set to TRUE to go backwards in time + * @param bool $allowCurrentDate (optional) Set to TRUE to return the + * current date if it matches the cron expression + * + * @return DateTime + * @throws RuntimeException on too many iterations + */ + protected function getRunDate($currentTime = null, $nth = 0, $invert = false, $allowCurrentDate = false) + { + if ($currentTime instanceof DateTime) { + $currentDate = $currentTime; + } else { + $currentDate = new DateTime($currentTime ? $currentTime : 'now'); + $currentDate->setTimezone(new DateTimeZone(date_default_timezone_get())); + } + + $currentDate->setTime($currentDate->format('H'), $currentDate->format('i'), 0); + $nextRun = clone $currentDate; + $nth = (int) $nth; + + // Set a hard limit to bail on an impossible date + for ($i = 0; $i < 1000; $i++) { + + foreach (self::$order as $position) { + $part = $this->getExpression($position); + if (null === $part) { + continue; + } + + $satisfied = false; + // Get the field object used to validate this part + $field = $this->fieldFactory->getField($position); + // Check if this is singular or a list + if (strpos($part, ',') === false) { + $satisfied = $field->isSatisfiedBy($nextRun, $part); + } else { + foreach (array_map('trim', explode(',', $part)) as $listPart) { + if ($field->isSatisfiedBy($nextRun, $listPart)) { + $satisfied = true; + break; + } + } + } + + // If the field is not satisfied, then start over + if (!$satisfied) { + $field->increment($nextRun, $invert); + continue 2; + } + } + + // Skip this match if needed + if ((!$allowCurrentDate && $nextRun == $currentDate) || --$nth > -1) { + $this->fieldFactory->getField(0)->increment($nextRun, $invert); + continue; + } + + return $nextRun; + } + + // @codeCoverageIgnoreStart + throw new RuntimeException('Impossible CRON expression'); + // @codeCoverageIgnoreEnd + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_AbstractField.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_AbstractField.php new file mode 100644 index 000000000..f8d5c00ae --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_AbstractField.php @@ -0,0 +1,100 @@ + + */ +abstract class CronExpression_AbstractField implements CronExpression_FieldInterface +{ + /** + * Check to see if a field is satisfied by a value + * + * @param string $dateValue Date value to check + * @param string $value Value to test + * + * @return bool + */ + public function isSatisfied($dateValue, $value) + { + if ($this->isIncrementsOfRanges($value)) { + return $this->isInIncrementsOfRanges($dateValue, $value); + } elseif ($this->isRange($value)) { + return $this->isInRange($dateValue, $value); + } + + return $value == '*' || $dateValue == $value; + } + + /** + * Check if a value is a range + * + * @param string $value Value to test + * + * @return bool + */ + public function isRange($value) + { + return strpos($value, '-') !== false; + } + + /** + * Check if a value is an increments of ranges + * + * @param string $value Value to test + * + * @return bool + */ + public function isIncrementsOfRanges($value) + { + return strpos($value, '/') !== false; + } + + /** + * Test if a value is within a range + * + * @param string $dateValue Set date value + * @param string $value Value to test + * + * @return bool + */ + public function isInRange($dateValue, $value) + { + $parts = array_map('trim', explode('-', $value, 2)); + + return $dateValue >= $parts[0] && $dateValue <= $parts[1]; + } + + /** + * Test if a value is within an increments of ranges (offset[-to]/step size) + * + * @param string $dateValue Set date value + * @param string $value Value to test + * + * @return bool + */ + public function isInIncrementsOfRanges($dateValue, $value) + { + $parts = array_map('trim', explode('/', $value, 2)); + $stepSize = isset($parts[1]) ? $parts[1] : 0; + if ($parts[0] == '*' || $parts[0] === '0') { + return (int) $dateValue % $stepSize == 0; + } + + $range = explode('-', $parts[0], 2); + $offset = $range[0]; + $to = isset($range[1]) ? $range[1] : $dateValue; + // Ensure that the date value is within the range + if ($dateValue < $offset || $dateValue > $to) { + return false; + } + + for ($i = $offset; $i <= $to; $i+= $stepSize) { + if ($i == $dateValue) { + return true; + } + } + + return false; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_DayOfMonthField.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_DayOfMonthField.php new file mode 100644 index 000000000..40c1d6c6e --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_DayOfMonthField.php @@ -0,0 +1,110 @@ + + */ +class CronExpression_DayOfMonthField extends CronExpression_AbstractField +{ + /** + * Get the nearest day of the week for a given day in a month + * + * @param int $currentYear Current year + * @param int $currentMonth Current month + * @param int $targetDay Target day of the month + * + * @return DateTime Returns the nearest date + */ + private static function getNearestWeekday($currentYear, $currentMonth, $targetDay) + { + $tday = str_pad($targetDay, 2, '0', STR_PAD_LEFT); + $target = new DateTime("$currentYear-$currentMonth-$tday"); + $currentWeekday = (int) $target->format('N'); + + if ($currentWeekday < 6) { + return $target; + } + + $lastDayOfMonth = $target->format('t'); + + foreach (array(-1, 1, -2, 2) as $i) { + $adjusted = $targetDay + $i; + if ($adjusted > 0 && $adjusted <= $lastDayOfMonth) { + $target->setDate($currentYear, $currentMonth, $adjusted); + if ($target->format('N') < 6 && $target->format('m') == $currentMonth) { + return $target; + } + } + } + } + + /** + * {@inheritdoc} + */ + public function isSatisfiedBy(DateTime $date, $value) + { + // ? states that the field value is to be skipped + if ($value == '?') { + return true; + } + + $fieldValue = $date->format('d'); + + // Check to see if this is the last day of the month + if ($value == 'L') { + return $fieldValue == $date->format('t'); + } + + // Check to see if this is the nearest weekday to a particular value + if (strpos($value, 'W')) { + // Parse the target day + $targetDay = substr($value, 0, strpos($value, 'W')); + // Find out if the current day is the nearest day of the week + return $date->format('j') == self::getNearestWeekday( + $date->format('Y'), + $date->format('m'), + $targetDay + )->format('j'); + } + + return $this->isSatisfied($date->format('d'), $value); + } + + /** + * {@inheritdoc} + */ + public function increment(DateTime $date, $invert = false) + { + if ($invert) { + $date->modify('previous day'); + $date->setTime(23, 59); + } else { + $date->modify('next day'); + $date->setTime(0, 0); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function validate($value) + { + return (bool) preg_match('/[\*,\/\-\?LW0-9A-Za-z]+/', $value); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_DayOfWeekField.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_DayOfWeekField.php new file mode 100644 index 000000000..e9f68a7cd --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_DayOfWeekField.php @@ -0,0 +1,124 @@ + + */ +class CronExpression_DayOfWeekField extends CronExpression_AbstractField +{ + /** + * {@inheritdoc} + */ + public function isSatisfiedBy(DateTime $date, $value) + { + if ($value == '?') { + return true; + } + + // Convert text day of the week values to integers + $value = str_ireplace( + array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'), + range(0, 6), + $value + ); + + $currentYear = $date->format('Y'); + $currentMonth = $date->format('m'); + $lastDayOfMonth = $date->format('t'); + + // Find out if this is the last specific weekday of the month + if (strpos($value, 'L')) { + $weekday = str_replace('7', '0', substr($value, 0, strpos($value, 'L'))); + $tdate = clone $date; + $tdate->setDate($currentYear, $currentMonth, $lastDayOfMonth); + while ($tdate->format('w') != $weekday) { + $tdate->setDate($currentYear, $currentMonth, --$lastDayOfMonth); + } + + return $date->format('j') == $lastDayOfMonth; + } + + // Handle # hash tokens + if (strpos($value, '#')) { + list($weekday, $nth) = explode('#', $value); + // Validate the hash fields + if ($weekday < 1 || $weekday > 5) { + throw new InvalidArgumentException("Weekday must be a value between 1 and 5. {$weekday} given"); + } + if ($nth > 5) { + throw new InvalidArgumentException('There are never more than 5 of a given weekday in a month'); + } + // The current weekday must match the targeted weekday to proceed + if ($date->format('N') != $weekday) { + return false; + } + + $tdate = clone $date; + $tdate->setDate($currentYear, $currentMonth, 1); + $dayCount = 0; + $currentDay = 1; + while ($currentDay < $lastDayOfMonth + 1) { + if ($tdate->format('N') == $weekday) { + if (++$dayCount >= $nth) { + break; + } + } + $tdate->setDate($currentYear, $currentMonth, ++$currentDay); + } + + return $date->format('j') == $currentDay; + } + + // Handle day of the week values + if (strpos($value, '-')) { + $parts = explode('-', $value); + if ($parts[0] == '7') { + $parts[0] = '0'; + } elseif ($parts[1] == '0') { + $parts[1] = '7'; + } + $value = implode('-', $parts); + } + + // Test to see which Sunday to use -- 0 == 7 == Sunday + $format = in_array(7, str_split($value)) ? 'N' : 'w'; + $fieldValue = $date->format($format); + + return $this->isSatisfied($fieldValue, $value); + } + + /** + * {@inheritdoc} + */ + public function increment(DateTime $date, $invert = false) + { + if ($invert) { + $date->modify('-1 day'); + $date->setTime(23, 59, 0); + } else { + $date->modify('+1 day'); + $date->setTime(0, 0, 0); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function validate($value) + { + return (bool) preg_match('/[\*,\/\-0-9A-Z]+/', $value); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_FieldFactory.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_FieldFactory.php new file mode 100644 index 000000000..556ba1a3e --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_FieldFactory.php @@ -0,0 +1,55 @@ + + * @link http://en.wikipedia.org/wiki/Cron + */ +class CronExpression_FieldFactory +{ + /** + * @var array Cache of instantiated fields + */ + private $fields = array(); + + /** + * Get an instance of a field object for a cron expression position + * + * @param int $position CRON expression position value to retrieve + * + * @return CronExpression_FieldInterface + * @throws InvalidArgumentException if a position is not valid + */ + public function getField($position) + { + if (!isset($this->fields[$position])) { + switch ($position) { + case 0: + $this->fields[$position] = new CronExpression_MinutesField(); + break; + case 1: + $this->fields[$position] = new CronExpression_HoursField(); + break; + case 2: + $this->fields[$position] = new CronExpression_DayOfMonthField(); + break; + case 3: + $this->fields[$position] = new CronExpression_MonthField(); + break; + case 4: + $this->fields[$position] = new CronExpression_DayOfWeekField(); + break; + case 5: + $this->fields[$position] = new CronExpression_YearField(); + break; + default: + throw new InvalidArgumentException( + $position . ' is not a valid position' + ); + } + } + + return $this->fields[$position]; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_FieldInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_FieldInterface.php new file mode 100644 index 000000000..5d5109b70 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_FieldInterface.php @@ -0,0 +1,39 @@ + + */ +interface CronExpression_FieldInterface +{ + /** + * Check if the respective value of a DateTime field satisfies a CRON exp + * + * @param DateTime $date DateTime object to check + * @param string $value CRON expression to test against + * + * @return bool Returns TRUE if satisfied, FALSE otherwise + */ + public function isSatisfiedBy(DateTime $date, $value); + + /** + * When a CRON expression is not satisfied, this method is used to increment + * or decrement a DateTime object by the unit of the cron field + * + * @param DateTime $date DateTime object to change + * @param bool $invert (optional) Set to TRUE to decrement + * + * @return CronExpression_FieldInterface + */ + public function increment(DateTime $date, $invert = false); + + /** + * Validates a CRON expression for a given field + * + * @param string $value CRON expression value to validate + * + * @return bool Returns TRUE if valid, FALSE otherwise + */ + public function validate($value); +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_HoursField.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_HoursField.php new file mode 100644 index 000000000..088ca73c7 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_HoursField.php @@ -0,0 +1,47 @@ + + */ +class CronExpression_HoursField extends CronExpression_AbstractField +{ + /** + * {@inheritdoc} + */ + public function isSatisfiedBy(DateTime $date, $value) + { + return $this->isSatisfied($date->format('H'), $value); + } + + /** + * {@inheritdoc} + */ + public function increment(DateTime $date, $invert = false) + { + // Change timezone to UTC temporarily. This will + // allow us to go back or forwards and hour even + // if DST will be changed between the hours. + $timezone = $date->getTimezone(); + $date->setTimezone(new DateTimeZone('UTC')); + if ($invert) { + $date->modify('-1 hour'); + $date->setTime($date->format('H'), 59); + } else { + $date->modify('+1 hour'); + $date->setTime($date->format('H'), 0); + } + $date->setTimezone($timezone); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function validate($value) + { + return (bool) preg_match('/[\*,\/\-0-9]+/', $value); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_MinutesField.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_MinutesField.php new file mode 100644 index 000000000..436acf2f5 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_MinutesField.php @@ -0,0 +1,39 @@ + + */ +class CronExpression_MinutesField extends CronExpression_AbstractField +{ + /** + * {@inheritdoc} + */ + public function isSatisfiedBy(DateTime $date, $value) + { + return $this->isSatisfied($date->format('i'), $value); + } + + /** + * {@inheritdoc} + */ + public function increment(DateTime $date, $invert = false) + { + if ($invert) { + $date->modify('-1 minute'); + } else { + $date->modify('+1 minute'); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function validate($value) + { + return (bool) preg_match('/[\*,\/\-0-9]+/', $value); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_MonthField.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_MonthField.php new file mode 100644 index 000000000..d3deb129f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_MonthField.php @@ -0,0 +1,55 @@ + + */ +class CronExpression_MonthField extends CronExpression_AbstractField +{ + /** + * {@inheritdoc} + */ + public function isSatisfiedBy(DateTime $date, $value) + { + // Convert text month values to integers + $value = str_ireplace( + array( + 'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', + 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC' + ), + range(1, 12), + $value + ); + + return $this->isSatisfied($date->format('m'), $value); + } + + /** + * {@inheritdoc} + */ + public function increment(DateTime $date, $invert = false) + { + if ($invert) { + // $date->modify('last day of previous month'); // remove for php 5.2 compat + $date->modify('previous month'); + $date->modify($date->format('Y-m-t')); + $date->setTime(23, 59); + } else { + //$date->modify('first day of next month'); // remove for php 5.2 compat + $date->modify('next month'); + $date->modify($date->format('Y-m-01')); + $date->setTime(0, 0); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function validate($value) + { + return (bool) preg_match('/[\*,\/\-0-9A-Z]+/', $value); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_YearField.php b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_YearField.php new file mode 100644 index 000000000..f11562e45 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/lib/cron-expression/CronExpression_YearField.php @@ -0,0 +1,43 @@ + + */ +class CronExpression_YearField extends CronExpression_AbstractField +{ + /** + * {@inheritdoc} + */ + public function isSatisfiedBy(DateTime $date, $value) + { + return $this->isSatisfied($date->format('Y'), $value); + } + + /** + * {@inheritdoc} + */ + public function increment(DateTime $date, $invert = false) + { + if ($invert) { + $date->modify('-1 year'); + $date->setDate($date->format('Y'), 12, 31); + $date->setTime(23, 59, 0); + } else { + $date->modify('+1 year'); + $date->setDate($date->format('Y'), 1, 1); + $date->setTime(0, 0, 0); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function validate($value) + { + return (bool) preg_match('/[\*,\/\-0-9]+/', $value); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/license.txt b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/license.txt new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/license.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/readme.txt b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/readme.txt new file mode 100644 index 000000000..3518b1544 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/ActionScheduler/readme.txt @@ -0,0 +1,125 @@ +=== Action Scheduler === +Contributors: Automattic, wpmuguru, claudiosanches, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski, royho, barryhughes-1 +Tags: scheduler, cron +Requires at least: 5.2 +Tested up to: 6.0 +Stable tag: 3.5.4 +License: GPLv3 +Requires PHP: 5.6 + +Action Scheduler - Job Queue for WordPress + +== Description == + +Action Scheduler is a scalable, traceable job queue for background processing large sets of actions in WordPress. It's specially designed to be distributed in WordPress plugins. + +Action Scheduler works by triggering an action hook to run at some time in the future. Each hook can be scheduled with unique data, to allow callbacks to perform operations on that data. The hook can also be scheduled to run on one or more occassions. + +Think of it like an extension to `do_action()` which adds the ability to delay and repeat a hook. + +## Battle-Tested Background Processing + +Every month, Action Scheduler processes millions of payments for [Subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/), webhooks for [WooCommerce](https://wordpress.org/plugins/woocommerce/), as well as emails and other events for a range of other plugins. + +It's been seen on live sites processing queues in excess of 50,000 jobs and doing resource intensive operations, like processing payments and creating orders, at a sustained rate of over 10,000 / hour without negatively impacting normal site operations. + +This is all on infrastructure and WordPress sites outside the control of the plugin author. + +If your plugin needs background processing, especially of large sets of tasks, Action Scheduler can help. + +## Learn More + +To learn more about how to Action Scheduler works, and how to use it in your plugin, check out the docs on [ActionScheduler.org](https://actionscheduler.org). + +There you will find: + +* [Usage guide](https://actionscheduler.org/usage/): instructions on installing and using Action Scheduler +* [WP CLI guide](https://actionscheduler.org/wp-cli/): instructions on running Action Scheduler at scale via WP CLI +* [API Reference](https://actionscheduler.org/api/): complete reference guide for all API functions +* [Administration Guide](https://actionscheduler.org/admin/): guide to managing scheduled actions via the administration screen +* [Guide to Background Processing at Scale](https://actionscheduler.org/perf/): instructions for running Action Scheduler at scale via the default WP Cron queue runner + +## Credits + +Action Scheduler is developed and maintained by [Automattic](http://automattic.com/) with significant early development completed by [Flightless](https://flightless.us/). + +Collaboration is cool. We'd love to work with you to improve Action Scheduler. [Pull Requests](https://github.com/woocommerce/action-scheduler/pulls) welcome. + +== Changelog == + += 3.5.4 - 2023-01-17 = +* Add pre filters during action registration. +* Async scheduling. +* Calculate timeouts based on total actions. +* Correctly order the parameters for `ActionScheduler_ActionFactory`'s calls to `single_unique`. +* Fetch action in memory first before releasing claim to avoid deadlock. +* PHP 8.2: declare property to fix creation of dynamic property warning. +* PHP 8.2: fix "Using ${var} in strings is deprecated, use {$var} instead". +* Prevent `undefined variable` warning for `$num_pastdue_actions`. + += 3.5.3 - 2022-11-09 = +* Query actions with partial match. + += 3.5.2 - 2022-09-16 = +* Fix - erroneous 3.5.1 release. + += 3.5.1 - 2022-09-13 = +* Maintenance on A/S docs. +* fix: PHP 8.2 deprecated notice. + += 3.5.0 - 2022-08-25 = +* Add - The active view link within the "Tools > Scheduled Actions" screen is now clickable. +* Add - A warning when there are past-due actions. +* Enhancement - Added the ability to schedule unique actions via an atomic operation. +* Enhancement - Improvements to cache invalidation when processing batches (when running on WordPress 6.0+). +* Enhancement - If a recurring action is found to be consistently failing, it will stop being rescheduled. +* Enhancement - Adds a new "Past Due" view to the scheduled actions list table. + += 3.4.2 - 2022-06-08 = +* Fix - Change the include for better linting. +* Fix - update: Added Action scheduler completed action hook. + += 3.4.1 - 2022-05-24 = +* Fix - Change the include for better linting. +* Fix - Fix the documented return type. + += 3.4.0 - 2021-10-29 = +* Enhancement - Number of items per page can now be set for the Scheduled Actions view (props @ovidiul). #771 +* Fix - Do not lower the max_execution_time if it is already set to 0 (unlimited) (props @barryhughes). #755 +* Fix - Avoid triggering autoloaders during the version resolution process (props @olegabr). #731 & #776 +* Dev - ActionScheduler_wcSystemStatus PHPCS fixes (props @ovidiul). #761 +* Dev - ActionScheduler_DBLogger.php PHPCS fixes (props @ovidiul). #768 +* Dev - Fixed phpcs for ActionScheduler_Schedule_Deprecated (props @ovidiul). #762 +* Dev - Improve actions table indicies (props @glagonikas). #774 & #777 +* Dev - PHPCS fixes for ActionScheduler_DBStore.php (props @ovidiul). #769 & #778 +* Dev - PHPCS Fixes for ActionScheduler_Abstract_ListTable (props @ovidiul). #763 & #779 +* Dev - Adds new filter action_scheduler_claim_actions_order_by to allow tuning of the claim query (props @glagonikas). #773 +* Dev - PHPCS fixes for ActionScheduler_WpPostStore class (props @ovidiul). #780 + += 3.3.0 - 2021-09-15 = +* Enhancement - Adds as_has_scheduled_action() to provide a performant way to test for existing actions. #645 +* Fix - Improves compatibility with environments where NO_ZERO_DATE is enabled. #519 +* Fix - Adds safety checks to guard against errors when our database tables cannot be created. #645 +* Dev - Now supports queries that use multiple statuses. #649 +* Dev - Minimum requirements for WordPress and PHP bumped (to 5.2 and 5.6 respectively). #723 + += 3.2.1 - 2021-06-21 = +* Fix - Add extra safety/account for different versions of AS and different loading patterns. #714 +* Fix - Handle hidden columns (Tools → Scheduled Actions) | #600. + += 3.2.0 - 2021-06-03 = +* Fix - Add "no ordering" option to as_next_scheduled_action(). +* Fix - Add secondary scheduled date checks when claiming actions (DBStore) | #634. +* Fix - Add secondary scheduled date checks when claiming actions (wpPostStore) | #634. +* Fix - Adds a new index to the action table, reducing the potential for deadlocks (props: @glagonikas). +* Fix - Fix unit tests infrastructure and adapt tests to PHP 8. +* Fix - Identify in-use data store. +* Fix - Improve test_migration_is_scheduled. +* Fix - PHP notice on list table. +* Fix - Speed up clean up and batch selects. +* Fix - Update pending dependencies. +* Fix - [PHP 8.0] Only pass action arg values through to do_action_ref_array(). +* Fix - [PHP 8] Set the PHP version to 7.1 in composer.json for PHP 8 compatibility. +* Fix - add is_initialized() to docs. +* Fix - fix file permissions. +* Fix - fixes #664 by replacing __ with esc_html__. diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Base.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Base.php new file mode 100644 index 000000000..20fcdb52d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Base.php @@ -0,0 +1,344 @@ +{$key}; + } + + // Return null if not exists + return null; + } + + /** + * Converts the given object to an array. + * + * @since 1.0.0 + * + * @return array Array version of the given object. + */ + public function to_array() { + return get_object_vars( $this ); + } + + /** Protected *************************************************************/ + + /** + * Maybe append the prefix to string. + * + * @since 1.0.0 + * + * @param string $string + * @param string $sep + * @return string + */ + protected function apply_prefix( $string = '', $sep = '_' ) { + return ! empty( $this->prefix ) + ? "{$this->prefix}{$sep}{$string}" + : $string; + } + + /** + * Return the first letters of a string of words with a separator. + * + * Used primarily to guess at table aliases when none is manually set. + * + * Applies the following formatting to a string: + * - Trim whitespace + * - No accents + * - No trailing underscores + * + * @since 1.0.0 + * + * @param string $string + * @param string $sep + * @return string + */ + protected function first_letters( $string = '', $sep = '_' ) { + + // Set empty default return value + $retval = ''; + + // Bail if empty or not a string + if ( empty( $string ) || ! is_string( $string ) ) { + return $retval; + } + + // Trim spaces off the ends + $unspace = trim( $string ); + + // Only non-accented table names (avoid truncation) + $accents = remove_accents( $unspace ); + + // Only lowercase letters are allowed + $lower = strtolower( $accents ); + + // Explode into parts + $parts = explode( $sep, $lower ); + + // Loop through parts and concatenate the first letters together + foreach ( $parts as $part ) { + $retval .= substr( $part, 0, 1 ); + } + + // Return the result + return $retval; + } + + /** + * Sanitize a table name string. + * + * Used to make sure that a table name value meets MySQL expectations. + * + * Applies the following formatting to a string: + * - Trim whitespace + * - No accents + * - No special characters + * - No hyphens + * - No double underscores + * - No trailing underscores + * + * @since 1.0.0 + * + * @param string $name The name of the database table + * + * @return string Sanitized database table name + */ + protected function sanitize_table_name( $name = '' ) { + + // Bail if empty or not a string + if ( empty( $name ) || ! is_string( $name ) ) { + return false; + } + + // Trim spaces off the ends + $unspace = trim( $name ); + + // Only non-accented table names (avoid truncation) + $accents = remove_accents( $unspace ); + + // Only lowercase characters, hyphens, and dashes (avoid index corruption) + $lower = sanitize_key( $accents ); + + // Replace hyphens with single underscores + $under = str_replace( '-', '_', $lower ); + + // Single underscores only + $single = str_replace( '__', '_', $under ); + + // Remove trailing underscores + $clean = trim( $single, '_' ); + + // Bail if table name was garbaged + if ( empty( $clean ) ) { + return false; + } + + // Return the cleaned table name + return $clean; + } + + /** + * Set class variables from arguments. + * + * @since 1.0.0 + * @param array $args + */ + protected function set_vars( $args = array() ) { + + // Bail if empty or not an array + if ( empty( $args ) ) { + return; + } + + // Cast to an array + if ( ! is_array( $args ) ) { + $args = (array) $args; + } + + // Set all properties + foreach ( $args as $key => $value ) { + $this->{$key} = $value; + } + } + + /** + * Return the global database interface. + * + * See: https://core.trac.wordpress.org/ticket/31556 + * + * @since 1.0.0 + * + * @return \wpdb Database interface, or False if not set + */ + protected function get_db() { + + // Default database return value (might change) + $retval = false; + + // Look for a commonly used global database interface + if ( isset( $GLOBALS[ $this->db_global ] ) ) { + $retval = $GLOBALS[ $this->db_global ]; + } + + /* + * Developer note: + * + * It should be impossible for a database table to be interacted with + * before the primary database interface is setup. + * + * However, because applications are complicated, it is unsafe to assume + * anything, so this silently returns false instead of halting everything. + * + * If you are here because this method is returning false for you, that + * means the database table is being invoked too early in the lifecycle + * of the application. + * + * In WordPress, that means before the $wpdb global is created; in other + * environments, you will need to adjust accordingly. + */ + + // Return the database interface + return $retval; + } + + /** + * Check if an operation succeeded. + * + * @since 1.0.0 + * + * @param mixed $result + * @return bool + */ + protected function is_success( $result = false ) { + + // Bail if no row exists + if ( empty( $result ) ) { + $retval = false; + + // Bail if an error occurred + } elseif ( is_wp_error( $result ) ) { + $this->last_error = $result; + $retval = false; + + // No errors + } else { + $retval = true; + } + + // Return the result + return (bool) $retval; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Column.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Column.php new file mode 100644 index 000000000..97cedaa05 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Column.php @@ -0,0 +1,965 @@ +parse_args( $args ); + + // Maybe set variables from arguments + if ( ! empty( $r ) ) { + $this->set_vars( $r ); + } + } + + /** Argument Handlers *****************************************************/ + + /** + * Parse column arguments + * + * @since 1.0.0 + * @param array $args Default empty array. + * @return array + */ + private function parse_args( $args = array() ) { + + // Parse arguments + $r = wp_parse_args( $args, array( + + // Table + 'name' => '', + 'type' => '', + 'length' => '', + 'unsigned' => false, + 'zerofill' => false, + 'binary' => false, + 'allow_null' => false, + 'default' => '', + 'extra' => '', + 'encoding' => $this->get_db()->charset, + 'collation' => $this->get_db()->collate, + 'comment' => '', + + // Query + 'pattern' => false, + 'searchable' => false, + 'sortable' => false, + 'date_query' => false, + 'transition' => false, + 'in' => true, + 'not_in' => true, + + // Special + 'primary' => false, + 'created' => false, + 'modified' => false, + 'uuid' => false, + + // Cache + 'cache_key' => false, + + // Validation + 'validate' => '', + + // Capabilities + 'caps' => array(), + + // Backwards Compatibility + 'aliases' => array(), + + // Column Relationships + 'relationships' => array() + ) ); + + // Force some arguments for special column types + $r = $this->special_args( $r ); + + // Set the args before they are sanitized + $this->set_vars( $r ); + + // Return array + return $this->validate_args( $r ); + } + + /** + * Validate arguments after they are parsed. + * + * @since 1.0.0 + * @param array $args Default empty array. + * @return array + */ + private function validate_args( $args = array() ) { + + // Sanitization callbacks + $callbacks = array( + 'name' => 'sanitize_key', + 'type' => 'strtoupper', + 'length' => 'intval', + 'unsigned' => 'wp_validate_boolean', + 'zerofill' => 'wp_validate_boolean', + 'binary' => 'wp_validate_boolean', + 'allow_null' => 'wp_validate_boolean', + 'default' => array( $this, 'sanitize_default' ), + 'extra' => 'wp_kses_data', + 'encoding' => 'wp_kses_data', + 'collation' => 'wp_kses_data', + 'comment' => 'wp_kses_data', + + 'primary' => 'wp_validate_boolean', + 'created' => 'wp_validate_boolean', + 'modified' => 'wp_validate_boolean', + 'uuid' => 'wp_validate_boolean', + + 'searchable' => 'wp_validate_boolean', + 'sortable' => 'wp_validate_boolean', + 'date_query' => 'wp_validate_boolean', + 'transition' => 'wp_validate_boolean', + 'in' => 'wp_validate_boolean', + 'not_in' => 'wp_validate_boolean', + 'cache_key' => 'wp_validate_boolean', + + 'pattern' => array( $this, 'sanitize_pattern' ), + 'validate' => array( $this, 'sanitize_validation' ), + 'caps' => array( $this, 'sanitize_capabilities' ), + 'aliases' => array( $this, 'sanitize_aliases' ), + 'relationships' => array( $this, 'sanitize_relationships' ) + ); + + // Default args array + $r = array(); + + // Loop through and try to execute callbacks + foreach ( $args as $key => $value ) { + + // Callback is callable + if ( isset( $callbacks[ $key ] ) && is_callable( $callbacks[ $key ] ) ) { + $r[ $key ] = call_user_func( $callbacks[ $key ], $value ); + + // Callback is malformed so just let it through to avoid breakage + } else { + $r[ $key ] = $value; + } + } + + // Return sanitized arguments + return $r; + } + + /** + * Force column arguments for special column types + * + * @since 1.0.0 + * @param array $args Default empty array. + * @return array + */ + private function special_args( $args = array() ) { + + // Primary key columns are always used as cache keys + if ( ! empty( $args['primary'] ) ) { + $args['cache_key'] = true; + + // All UUID columns need to follow a very specific pattern + } elseif ( ! empty( $args['uuid'] ) ) { + $args['name'] = 'uuid'; + $args['type'] = 'varchar'; + $args['length'] = '100'; + $args['in'] = false; + $args['not_in'] = false; + $args['searchable'] = false; + $args['sortable'] = false; + } + + // Return args + return (array) $args; + } + + /** Public Helpers ********************************************************/ + + /** + * Return if a column type is numeric or not. + * + * @since 1.0.0 + * @return bool + */ + public function is_numeric() { + return $this->is_type( array( + 'tinyint', + 'int', + 'mediumint', + 'bigint' + ) ); + } + + /** Private Helpers *******************************************************/ + + /** + * Return if this column is of a certain type. + * + * @since 1.0.0 + * @param mixed $type Default empty string. The type to check. Also accepts an array. + * @return bool True if of type, False if not + */ + private function is_type( $type = '' ) { + + // If string, cast to array + if ( is_string( $type ) ) { + $type = (array) $type; + } + + // Make them lowercase + $types = array_map( 'strtolower', $type ); + + // Return if match or not + return (bool) in_array( strtolower( $this->type ), $types, true ); + } + + /** Private Sanitizers ****************************************************/ + + /** + * Sanitize capabilities array + * + * @since 1.0.0 + * @param array $caps Default empty array. + * @return array + */ + private function sanitize_capabilities( $caps = array() ) { + return wp_parse_args( $caps, array( + 'select' => 'exist', + 'insert' => 'exist', + 'update' => 'exist', + 'delete' => 'exist' + ) ); + } + + /** + * Sanitize aliases array using `sanitize_key()` + * + * @since 1.0.0 + * @param array $aliases Default empty array. + * @return array + */ + private function sanitize_aliases( $aliases = array() ) { + return array_map( 'sanitize_key', $aliases ); + } + + /** + * Sanitize relationships array + * + * @todo + * @since 1.0.0 + * @param array $relationships Default empty array. + * @return array + */ + private function sanitize_relationships( $relationships = array() ) { + return array_filter( $relationships ); + } + + /** + * Sanitize the default value + * + * @since 1.0.0 + * @param string $default + * @return string|null + */ + private function sanitize_default( $default = '' ) { + + // Null + if ( ( true === $this->allow_null ) && is_null( $default ) ) { + return null; + + // String + } elseif ( is_string( $default ) ) { + return wp_kses_data( $default ); + + // Integer + } elseif ( $this->is_numeric() ) { + return (int) $default; + } + + // @todo datetime, decimal, and other column types + + // Unknown, so return the default's default + return ''; + } + + /** + * Sanitize the pattern + * + * @since 1.0.0 + * @param string $pattern + * @return string + */ + private function sanitize_pattern( $pattern = '%s' ) { + + // Allowed patterns + $allowed_patterns = array( '%s', '%d', '%f' ); + + // Return pattern if allowed + if ( in_array( $pattern, $allowed_patterns, true ) ) { + return $pattern; + } + + // Fallback to digit or string + return $this->is_numeric() + ? '%d' + : '%s'; + } + + /** + * Sanitize the validation callback + * + * @since 1.0.0 + * @param string $callback Default empty string. A callable PHP function name or method + * @return string The most appropriate callback function for the value + */ + private function sanitize_validation( $callback = '' ) { + + // Return callback if it's callable + if ( is_callable( $callback ) ) { + return $callback; + } + + // UUID special column + if ( true === $this->uuid ) { + $callback = array( $this, 'validate_uuid' ); + + // Datetime fallback + } elseif ( $this->is_type( 'datetime' ) ) { + $callback = array( $this, 'validate_datetime' ); + + // Decimal fallback + } elseif ( $this->is_type( 'decimal' ) ) { + $callback = array( $this, 'validate_decimal' ); + + // Intval fallback + } elseif ( $this->is_numeric() ) { + $callback = 'intval'; + } + + // Return the callback + return $callback; + } + + /** Public Validators *****************************************************/ + + /** + * Fallback to validate a datetime value if no other is set. + * + * This assumes NO_ZERO_DATES is off or overridden. + * + * If MySQL drops support for zero dates, this method will need to be + * updated to support different default values based on the environment. + * + * @since 1.0.0 + * @param string $value Default ''. A datetime value that needs validating + * @return string A valid datetime value + */ + public function validate_datetime( $value = '' ) { + + // Handle "empty" values + if ( empty( $value ) || ( '0000-00-00 00:00:00' === $value ) ) { + $value = ! empty( $this->default ) + ? $this->default + : ''; + + // Convert to MySQL datetime format via gmdate() && strtotime + } elseif ( function_exists( 'gmdate' ) ) { + $value = gmdate( 'Y-m-d H:i:s', strtotime( $value ) ); + } + + // Return the validated value + return $value; + } + + /** + * Validate a decimal + * + * (Recommended decimal column length is '18,9'.) + * + * This is used to validate a mixed value before it is saved into a decimal + * column in a database table. + * + * Uses number_format() which does rounding to the last decimal if your + * value is longer than specified. + * + * @since 1.0.0 + * @param mixed $value Default empty string. The decimal value to validate + * @param int $decimals Default 9. The number of decimal points to accept + * @return float + */ + public function validate_decimal( $value = 0, $decimals = 9 ) { + + // Protect against non-numeric values + if ( ! is_numeric( $value ) ) { + $value = 0; + } + + // Protect against non-numeric decimals + if ( ! is_numeric( $decimals ) ) { + $decimals = 9; + } + + // Is the value negative? + $negative_exponent = ( $value < 0 ) + ? -1 + : 1; + + // Only numbers and period + $value = preg_replace( '/[^0-9\.]/', '', (string) $value ); + + // Format to number of decimals, and cast as float + $formatted = number_format( $value, $decimals, '.', '' ); + + // Adjust for negative values + $retval = $formatted * $negative_exponent; + + // Return + return $retval; + } + + /** + * Validate a UUID. + * + * This uses the v4 algorithm to generate a UUID that is used to uniquely + * and universally identify a given database row without any direct + * connection or correlation to the data in that row. + * + * From http://php.net/manual/en/function.uniqid.php#94959 + * + * @since 1.0.0 + * @param string $value The UUID value (empty on insert, string on update) + * @return string Generated UUID. + */ + public function validate_uuid( $value = '' ) { + + // Default URN UUID prefix + $prefix = 'urn:uuid:'; + + // Bail if not empty and correctly prefixed + // (UUIDs should _never_ change once they are set) + if ( ! empty( $value ) && ( 0 === strpos( $value, $prefix ) ) ) { + return $value; + } + + // Put the pieces together + $value = sprintf( "{$prefix}%04x%04x-%04x-%04x-%04x-%04x%04x%04x", + + // 32 bits for "time_low" + mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), + + // 16 bits for "time_mid" + mt_rand( 0, 0xffff ), + + // 16 bits for "time_hi_and_version", + // four most significant bits holds version number 4 + mt_rand( 0, 0x0fff ) | 0x4000, + + // 16 bits, 8 bits for "clk_seq_hi_res", + // 8 bits for "clk_seq_low", + // two most significant bits holds zero and one for variant DCE1.1 + mt_rand( 0, 0x3fff ) | 0x8000, + + // 48 bits for "node" + mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ) + ); + + // Return the new UUID + return $value; + } + + /** Table Helpers *********************************************************/ + + /** + * Return a string representation of what this column's properties look like + * in a MySQL. + * + * @todo + * @since 1.0.0 + * @return string + */ + public function get_create_string() { + + // Default return val + $retval = ''; + + // Bail if no name + if ( ! empty( $this->name ) ) { + $retval .= $this->name; + } + + // Type + if ( ! empty( $this->type ) ) { + $retval .= " {$this->type}"; + } + + // Length + if ( ! empty( $this->length ) ) { + $retval .= '(' . $this->length . ')'; + } + + // Unsigned + if ( ! empty( $this->unsigned ) ) { + $retval .= " unsigned"; + } + + // Zerofill + if ( ! empty( $this->zerofill ) ) { + // TBD + } + + // Binary + if ( ! empty( $this->binary ) ) { + // TBD + } + + // Allow null + if ( ! empty( $this->allow_null ) ) { + $retval .= " NOT NULL "; + } + + // Default + if ( ! empty( $this->default ) ) { + $retval .= " default '{$this->default}'"; + + // A literal false means no default value + } elseif ( false !== $this->default ) { + + // Numeric + if ( $this->is_numeric() ) { + $retval .= " default '0'"; + } elseif ( $this->is_type( 'datetime' ) ) { + $retval .= " default '0000-00-00 00:00:00'"; + } else { + $retval .= " default ''"; + } + } + + // Extra + if ( ! empty( $this->extra ) ) { + $retval .= " {$this->extra}"; + } + + // Encoding + if ( ! empty( $this->encoding ) ) { + + } else { + + } + + // Collation + if ( ! empty( $this->collation ) ) { + + } else { + + } + + // Return the create string + return $retval; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Compare.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Compare.php new file mode 100644 index 000000000..4091af038 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Compare.php @@ -0,0 +1,180 @@ +', + '>=', + '<', + '<=', + 'LIKE', + 'NOT LIKE', + 'IN', + 'NOT IN', + 'BETWEEN', + 'NOT BETWEEN', + 'EXISTS', + 'NOT EXISTS', + 'REGEXP', + 'NOT REGEXP', + 'RLIKE', + ); + + // IN and BETWEEN + const IN_BETWEEN_COMPARES = array( + 'IN', + 'NOT IN', + 'BETWEEN', + 'NOT BETWEEN' + ); + + /** + * Generate SQL WHERE clauses for a first-order query clause. + * + * "First-order" means that it's an array with a 'key' or 'value'. + * + * @since 1.0.0 + * + * @param array $clause Query clause (passed by reference). + * @param array $parent_query Parent query array. + * @param string $clause_key Optional. The array key used to name the clause in the original `$meta_query` + * parameters. If not provided, a key will be generated automatically. + * @return array { + * Array containing WHERE SQL clauses to append to a first-order query. + * + * @type string $where SQL fragment to append to the main WHERE clause. + * } + */ + public function get_sql_for_clause( &$clause, $parent_query, $clause_key = '' ) { + global $wpdb; + + // Default chunks + $sql_chunks = array( + 'where' => array(), + 'join' => array(), + ); + + // Maybe format compare clause + if ( isset( $clause['compare'] ) ) { + $clause['compare'] = strtoupper( $clause['compare'] ); + + // Or set compare clause based on value + } else { + $clause['compare'] = isset( $clause['value'] ) && is_array( $clause['value'] ) + ? 'IN' + : '='; + } + + // Fallback to equals + if ( ! in_array( $clause['compare'], self::ALL_COMPARES, true ) ) { + $clause['compare'] = '='; + } + + // Uppercase or equals + if ( isset( $clause['compare_key'] ) && ( 'LIKE' === strtoupper( $clause['compare_key'] ) ) ) { + $clause['compare_key'] = strtoupper( $clause['compare_key'] ); + } else { + $clause['compare_key'] = '='; + } + + // Get comparison from clause + $compare = $clause['compare']; + + /** Build the WHERE clause ********************************************/ + + // Column name and value. + if ( array_key_exists( 'key', $clause ) && array_key_exists( 'value', $clause ) ) { + $column = sanitize_key( $clause['key'] ); + $value = $clause['value']; + + // IN or BETWEEN + if ( in_array( $compare, self::IN_BETWEEN_COMPARES, true ) ) { + if ( ! is_array( $value ) ) { + $value = preg_split( '/[,\s]+/', $value ); + } + + // Anything else + } else { + $value = trim( $value ); + } + + // Format WHERE from compare value(s) + switch ( $compare ) { + case 'IN': + case 'NOT IN': + $compare_string = '(' . substr( str_repeat( ',%s', count( $value ) ), 1 ) . ')'; + $where = $wpdb->prepare( $compare_string, $value ); + break; + + case 'BETWEEN': + case 'NOT BETWEEN': + $value = array_slice( $value, 0, 2 ); + $where = $wpdb->prepare( '%s AND %s', $value ); + break; + + case 'LIKE': + case 'NOT LIKE': + $value = '%' . $wpdb->esc_like( $value ) . '%'; + $where = $wpdb->prepare( '%s', $value ); + break; + + // EXISTS with a value is interpreted as '='. + case 'EXISTS': + $compare = '='; + $where = $wpdb->prepare( '%s', $value ); + break; + + // 'value' is ignored for NOT EXISTS. + case 'NOT EXISTS': + $where = ''; + break; + + default: + $where = $wpdb->prepare( '%s', $value ); + break; + + } + + // Maybe add column, compare, & where to chunks + if ( ! empty( $where ) ) { + $sql_chunks['where'][] = "{$column} {$compare} {$where}"; + } + } + + /* + * Multiple WHERE clauses (for meta_key and meta_value) should + * be joined in parentheses. + */ + if ( 1 < count( $sql_chunks['where'] ) ) { + $sql_chunks['where'] = array( '( ' . implode( ' AND ', $sql_chunks['where'] ) . ' )' ); + } + + // Return + return $sql_chunks; + } +} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Date.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Date.php new file mode 100644 index 000000000..d67223e2c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Date.php @@ -0,0 +1,1317 @@ +', + '>=', + '<', + '<=', + 'IN', + 'NOT IN', + 'BETWEEN', + 'NOT BETWEEN' + ); + + /** + * Supported multi-value comparison types + * + * @since 1.1.0 + * @var array + */ + public $multi_value_keys = array( + 'IN', + 'NOT IN', + 'BETWEEN', + 'NOT BETWEEN' + ); + + /** + * Supported relation types + * + * @since 1.1.0 + * @var array + */ + public $relation_keys = array( + 'OR', + 'AND' + ); + + /** + * Constructor. + * + * Time-related parameters that normally require integer values ('year', 'month', 'week', 'dayofyear', 'day', + * 'dayofweek', 'dayofweek_iso', 'hour', 'minute', 'second') accept arrays of integers for some values of + * 'compare'. When 'compare' is 'IN' or 'NOT IN', arrays are accepted; when 'compare' is 'BETWEEN' or 'NOT + * BETWEEN', arrays of two valid values are required. See individual argument descriptions for accepted values. + * + * @since 1.0.0 + * + * @param array $date_query { + * Array of date query clauses. + * + * @type array ...$0 { + * @type string $column Optional. The column to query against. If undefined, inherits the value of + * 'date_created'. Accepts 'date_created', 'date_created_gmt', + * 'post_modified','post_modified_gmt', 'comment_date', 'comment_date_gmt'. + * Default 'date_created'. + * @type string $compare Optional. The comparison operator. Accepts '=', '!=', '>', '>=', '<', '<=', + * 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'. Default '='. + * @type string $relation Optional. The boolean relationship between the date queries. Accepts 'OR' or 'AND'. + * Default 'OR'. + * @type int|array $start_of_week Optional. Day that week starts on. Accepts numbers 0-6 + * (0 = Sunday, 1 is Monday). Default 0. + * @type array ...$0 { + * Optional. An array of first-order clause parameters, or another fully-formed date query. + * + * @type string|array $before { + * Optional. Date to retrieve posts before. Accepts `strtotime()`-compatible string, + * or array of 'year', 'month', 'day' values. + * + * @type string $year The four-digit year. Default empty. Accepts any four-digit year. + * @type string $month Optional when passing array.The month of the year. + * Default (string:empty)|(array:1). Accepts numbers 1-12. + * @type string $day Optional when passing array.The day of the month. + * Default (string:empty)|(array:1). Accepts numbers 1-31. + * } + * @type string|array $after { + * Optional. Date to retrieve posts after. Accepts `strtotime()`-compatible string, + * or array of 'year', 'month', 'day' values. + * + * @type string $year The four-digit year. Accepts any four-digit year. Default empty. + * @type string $month Optional when passing array. The month of the year. Accepts numbers 1-12. + * Default (string:empty)|(array:12). + * @type string $day Optional when passing array.The day of the month. Accepts numbers 1-31. + * Default (string:empty)|(array:last day of month). + * } + * @type string $column Optional. Used to add a clause comparing a column other than the + * column specified in the top-level `$column` parameter. Accepts + * 'date_created', 'date_created_gmt', 'post_modified', 'post_modified_gmt', + * 'comment_date', 'comment_date_gmt'. Default is the value of + * top-level `$column`. + * @type string $compare Optional. The comparison operator. Accepts '=', '!=', '>', '>=', + * '<', '<=', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'. 'IN', + * 'NOT IN', 'BETWEEN', and 'NOT BETWEEN'. Comparisons support + * arrays in some time-related parameters. Default '='. + * @type int|array $start_of_week Optional. Day that week starts on. Accepts numbers 0-6 + * (0 = Sunday, 1 is Monday). Default 0. + * @type bool $inclusive Optional. Include results from dates specified in 'before' or + * 'after'. Default false. + * @type int|array $year Optional. The four-digit year number. Accepts any four-digit year + * or an array of years if `$compare` supports it. Default empty. + * @type int|array $month Optional. The two-digit month number. Accepts numbers 1-12 or an + * array of valid numbers if `$compare` supports it. Default empty. + * @type int|array $week Optional. The week number of the year. Accepts numbers 0-53 or an + * array of valid numbers if `$compare` supports it. Default empty. + * @type int|array $dayofyear Optional. The day number of the year. Accepts numbers 1-366 or an + * array of valid numbers if `$compare` supports it. + * @type int|array $day Optional. The day of the month. Accepts numbers 1-31 or an array + * of valid numbers if `$compare` supports it. Default empty. + * @type int|array $dayofweek Optional. The day number of the week. Accepts numbers 1-7 (1 is + * Sunday) or an array of valid numbers if `$compare` supports it. + * Default empty. + * @type int|array $dayofweek_iso Optional. The day number of the week (ISO). Accepts numbers 1-7 + * (1 is Monday) or an array of valid numbers if `$compare` supports it. + * Default empty. + * @type int|array $hour Optional. The hour of the day. Accepts numbers 0-23 or an array + * of valid numbers if `$compare` supports it. Default empty. + * @type int|array $minute Optional. The minute of the hour. Accepts numbers 0-60 or an array + * of valid numbers if `$compare` supports it. Default empty. + * @type int|array $second Optional. The second of the minute. Accepts numbers 0-60 or an + * array of valid numbers if `$compare` supports it. Default empty. + * } + * } + * } + */ + public function __construct( $date_query = array() ) { + + // Bail if empty or not an array. + if ( empty( $date_query ) || ! is_array( $date_query ) ) { + return; + } + + // Set now, column, compare, relation, and start_of_week. + $this->now = $this->get_now( $date_query ); + $this->column = $this->get_column( $date_query ); + $this->compare = $this->get_compare( $date_query ); + $this->relation = $this->get_relation( $date_query ); + $this->start_of_week = $this->get_start_of_week( $date_query ); + + // Support for passing time-based keys in the top level of the array. + if ( ! isset( $date_query[0] ) ) { + $date_query = array( $date_query ); + } + + // Set the queries + $this->queries = $this->sanitize_query( $date_query ); + } + + /** + * Recursive-friendly query sanitizer. + * + * Ensures that each query-level clause has a 'relation' key, and that + * each first-order clause contains all the necessary keys from + * `$defaults`. + * + * @since 1.0.0 + * + * @param array $queries + * @param array $parent_query + * + * @return array Sanitized queries. + */ + public function sanitize_query( $queries = array(), $parent_query = array() ) { + + // Default return value. + $retval = array(); + + // Setup defaults. + $defaults = array( + 'now' => $this->get_now(), + 'column' => $this->get_column(), + 'compare' => $this->get_compare(), + 'relation' => $this->get_relation(), + 'start_of_week' => $this->get_start_of_week() + ); + + // Numeric keys should always have array values. + foreach ( $queries as $qkey => $qvalue ) { + if ( is_numeric( $qkey ) && ! is_array( $qvalue ) ) { + unset( $queries[ $qkey ] ); + } + } + + // Each query should have a value for each default key. + // Inherit from the parent when possible. + foreach ( $defaults as $dkey => $dvalue ) { + + // Skip if already set. + if ( isset( $queries[ $dkey ] ) ) { + continue; + } + + // Set the query. + if ( isset( $parent_query[ $dkey ] ) ) { + $queries[ $dkey ] = $parent_query[ $dkey ]; + } else { + $queries[ $dkey ] = $dvalue; + } + } + + // Validate the dates passed in the query. + if ( $this->is_first_order_clause( $queries ) ) { + $this->validate_date_values( $queries ); + } + + // Add queries to return array. + foreach ( $queries as $key => $q ) { + + // This is a first-order query. Trust the values and sanitize when building SQL. + if ( ! is_array( $q ) || in_array( $key, $this->time_keys, true ) ) { + $retval[ $key ] = $q; + + // Any array without a time key is another query, so we recurse. + } else { + $retval[] = $this->sanitize_query( $q, $queries ); + } + } + + // Return sanitized queries. + return $retval; + } + + /** + * Determine whether this is a first-order clause. + * + * Checks to see if the current clause has any time-related keys. + * If so, it's first-order. + * + * @since 1.0.0 + * + * @param array $query Query clause. + * + * @return bool True if this is a first-order clause. + */ + protected function is_first_order_clause( $query = array() ) { + $time_keys = array_intersect( $this->time_keys, array_keys( $query ) ); + + return ! empty( $time_keys ); + } + + /** + * Determines and validates what the current unix timestamp is. + * + * @since 1.1.0 + * + * @param array $query A date query or a date subquery. + * + * @return string The current unix timestamp. + */ + public function get_now( $query = array() ) { + + // Use now if passed + $retval = ! empty( $query['now'] ) && is_numeric( $query['now'] ) + ? absint( $query['now'] ) + : time(); + + return $retval; + } + + /** + * Determines and validates what comparison operator to use. + * + * @since 1.0.0 + * + * @param array $query A date query or a date subquery. + * + * @return string The comparison operator. + */ + public function get_column( $query = array() ) { + + // Use column if passed + $retval = ! empty( $query['column'] ) + ? esc_sql( $this->validate_column( $query['column'] ) ) + : $this->column; + + return $retval; + } + + /** + * Determines and validates what comparison operator to use. + * + * @since 1.0.0 + * + * @param array $query A date query or a date subquery. + * + * @return string The comparison operator. + */ + public function get_compare( $query = array() ) { + + // Compare must be in the allowed array + $retval = ! empty( $query['compare'] ) && in_array( $query['compare'], $this->comparison_keys, true ) + ? strtoupper( $query['compare'] ) + : $this->compare; + + return $retval; + } + + /** + * Determines and validates what relation to use. + * + * @since 1.0.0 + * + * @param array $query A date query or a date subquery. + * @return string The relation operator. + */ + public function get_relation( $query = array() ) { + + // Relation must be in the allowed array + $retval = ! empty( $query['relation'] ) && in_array( $query['relation'], $this->relation_keys, true ) + ? strtoupper( $query['relation'] ) + : $this->relation; + + return $retval; + } + + /** + * Determines and validates what start_of_week to use. + * + * @since 1.1.0 + * + * @param array $query A date query or a date subquery. + * + * @return string The comparison operator. + */ + public function get_start_of_week( $query = array() ) { + + // Use start of week if passed and valid + $retval = isset( $query['start_of_week'] ) && ( 6 >= (int) $query['start_of_week'] ) && ( 0 <= (int) $query['start_of_week'] ) + ? $query['start_of_week'] + : $this->start_of_week; + + return (int) $retval; + } + + /** + * Validates the given date_query values. + * + * Note that date queries with invalid date ranges are allowed to + * continue (though of course no items will be found for impossible dates). + * This method only generates debug notices for these cases. + * + * @since 1.0.0 + * + * @param array $date_query The date_query array. + * + * @return bool True if all values in the query are valid, false if one or more fail. + */ + public function validate_date_values( $date_query = array() ) { + + // Bail if empty. + if ( empty( $date_query ) ) { + return false; + } + + $valid = true; + + /* + * Validate 'before' and 'after' up front, then let the + * validation routine continue to be sure that all invalid + * values generate errors too. + */ + if ( array_key_exists( 'before', $date_query ) && is_array( $date_query['before'] ) ) { + $valid = $this->validate_date_values( $date_query['before'] ); + } + + if ( array_key_exists( 'after', $date_query ) && is_array( $date_query['after'] ) ) { + $valid = $this->validate_date_values( $date_query['after'] ); + } + + // Values are passthroughs. + if ( array_key_exists( 'value', $date_query ) ) { + $valid = true; + } + + // Array containing all min-max checks. + $min_max_checks = array(); + + // Days per year. + if ( array_key_exists( 'year', $date_query ) ) { + /* + * If a year exists in the date query, we can use it to get the days. + * If multiple years are provided (as in a BETWEEN), use the first one. + */ + if ( is_array( $date_query['year'] ) ) { + $_year = reset( $date_query['year'] ); + } else { + $_year = $date_query['year']; + } + + $max_days_of_year = gmdate( 'z', gmmktime( 0, 0, 0, 12, 31, $_year ) ) + 1; + + // Otherwise we use the max of 366 (leap-year) + } else { + $max_days_of_year = 366; + } + + // Days of year. + $min_max_checks['dayofyear'] = array( + 'min' => 1, + 'max' => $max_days_of_year, + ); + + // Days per week. + $min_max_checks['dayofweek'] = array( + 'min' => 1, + 'max' => 7, + ); + + // Days per week. + $min_max_checks['dayofweek_iso'] = array( + 'min' => 1, + 'max' => 7, + ); + + // Months per year. + $min_max_checks['month'] = array( + 'min' => 1, + 'max' => 12, + ); + + // Weeks per year. + if ( isset( $_year ) ) { + /* + * If we have a specific year, use it to calculate number of weeks. + * Note: the number of weeks in a year is the date in which Dec 28 appears. + */ + $week_count = gmdate( 'W', gmmktime( 0, 0, 0, 12, 28, $_year ) ); + + // Otherwise set the week-count to a maximum of 53. + } else { + $week_count = 53; + } + + // Weeks per year. + $min_max_checks['week'] = array( + 'min' => 1, + 'max' => $week_count, + ); + + // Days per month. + $min_max_checks['day'] = array( + 'min' => 1, + 'max' => 31, + ); + + // Hours per day. + $min_max_checks['hour'] = array( + 'min' => 0, + 'max' => 23, + ); + + // Minutes per hour. + $min_max_checks['minute'] = array( + 'min' => 0, + 'max' => 59, + ); + + // Seconds per minute. + $min_max_checks['second'] = array( + 'min' => 0, + 'max' => 59, + ); + + // Loop through min/max checks. + foreach ( $min_max_checks as $key => $check ) { + + // Skip if not in query. + if ( ! array_key_exists( $key, $date_query ) ) { + continue; + } + + // Check for invalid values. + foreach ( (array) $date_query[ $key ] as $_value ) { + $is_between = ( $_value >= $check['min'] ) && ( $_value <= $check['max'] ); + + if ( ! is_numeric( $_value ) || empty( $is_between ) ) { + $valid = false; + } + } + } + + // Bail if invalid query. + if ( false === $valid ) { + return $valid; + } + + // Check what kinds of dates are being queried for. + $day_exists = array_key_exists( 'day', $date_query ) && is_numeric( $date_query['day'] ); + $month_exists = array_key_exists( 'month', $date_query ) && is_numeric( $date_query['month'] ); + $year_exists = array_key_exists( 'year', $date_query ) && is_numeric( $date_query['year'] ); + + // Checking at least day & month. + if ( ! empty( $day_exists ) && ! empty( $month_exists ) ) { + + // Check for year query, or fallback to 2012 (for flexibility). + $year = ! empty( $year_exists ) + ? $date_query['year'] + : '2012'; + + // Parse the date to check. + $to_check = sprintf( '%s-%s-%s', $year, $date_query['month'], $date_query['day'] ); + + // Check the date. + if ( ! $this->checkdate( $date_query['month'], $date_query['day'], $year, $to_check ) ) { + $valid = false; + } + } + + // Return if valid or not + return $valid; + } + + /** + * Validates a column name parameter. + * + * @since 1.0.0 + * + * @param string $column The user-supplied column name. + * + * @return string A validated column name value. + */ + public function validate_column( $column = '' ) { + return preg_replace( '/[^a-zA-Z0-9_$\.]/', '', $column ); + } + + /** + * Generate WHERE clause to be appended to a main query. + * + * @since 1.0.0 + * + * @return string MySQL WHERE clauses. + */ + public function get_sql() { + $sql = $this->get_sql_clauses(); + + /** + * Filters the date query clauses. + * + * @since 1.0.0 + * + * @param string $sql Clauses of the date query. + * @param Date $this The Date query instance. + */ + return apply_filters( 'get_date_sql', $sql, $this ); + } + + /** + * Generate SQL clauses to be appended to a main query. + * + * Called by the public Date::get_sql(), this method is abstracted + * out to maintain parity with the other Query classes. + * + * @since 1.0.0 + * + * @return array { + * Array containing JOIN and WHERE SQL clauses to append to the main query. + * + * @type string $join SQL fragment to append to the main JOIN clause. + * @type string $where SQL fragment to append to the main WHERE clause. + * } + */ + protected function get_sql_clauses() { + $sql = $this->get_sql_for_query( $this->queries ); + + if ( ! empty( $sql['where'] ) ) { + $sql['where'] = ' AND ' . $sql['where']; + } + + return apply_filters( 'get_date_sql_clauses', $sql, $this ); + } + + /** + * Generate SQL clauses for a single query array. + * + * If nested subqueries are found, this method recurses the tree to + * produce the properly nested SQL. + * + * @since 1.0.0 + * + * @param array $query Query to parse. + * @param int $depth Optional. Number of tree levels deep we currently are. + * Used to calculate indentation. Default 0. + * @return array { + * Array containing JOIN and WHERE SQL clauses to append to a single query array. + * + * @type string $join SQL fragment to append to the main JOIN clause. + * @type string $where SQL fragment to append to the main WHERE clause. + * } + */ + protected function get_sql_for_query( $query = array(), $depth = 0 ) { + $sql_chunks = array( + 'join' => array(), + 'where' => array(), + ); + + $sql = array( + 'join' => '', + 'where' => '', + ); + + $indent = ''; + for ( $i = 0; $i < $depth; $i++ ) { + $indent .= ' '; + } + + foreach ( $query as $key => $clause ) { + + if ( 'relation' === $key ) { + $relation = $query['relation']; + + } elseif ( is_array( $clause ) ) { + + // This is a first-order clause. + if ( $this->is_first_order_clause( $clause ) ) { + + // Get clauses & where count + $clause_sql = $this->get_sql_for_clause( $clause, $query ); + $where_count = count( $clause_sql['where'] ); + + if ( 0 === $where_count ) { + $sql_chunks['where'][] = ''; + + } elseif ( 1 === $where_count ) { + $sql_chunks['where'][] = $clause_sql['where'][0]; + + } else { + $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )'; + } + + $sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] ); + + // This is a subquery, so we recurse. + } else { + $clause_sql = $this->get_sql_for_query( $clause, $depth + 1 ); + + $sql_chunks['where'][] = $clause_sql['where']; + $sql_chunks['join'][] = $clause_sql['join']; + } + } + } + + // Filter to remove empties. + $sql_chunks['join'] = array_filter( $sql_chunks['join'] ); + $sql_chunks['where'] = array_filter( $sql_chunks['where'] ); + + if ( empty( $relation ) ) { + $relation = 'AND'; + } + + // Filter duplicate JOIN clauses and combine into a single string. + if ( ! empty( $sql_chunks['join'] ) ) { + $sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) ); + } + + // Generate a single WHERE clause with proper brackets and indentation. + if ( ! empty( $sql_chunks['where'] ) ) { + $sql['where'] = '( ' . "\n " . $indent . implode( ' ' . "\n " . $indent . $relation . ' ' . "\n " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')'; + } + + // Filter and return + return apply_filters( 'get_date_sql_for_query', $sql, $query, $depth, $this ); + } + + /** + * Turns a first-order date query into SQL for a WHERE clause. + * + * @since 1.0.0 + * + * @param array $query Date query clause. + * @param array $parent_query Parent query of the current date query. + * + * @return array { + * Array containing JOIN and WHERE SQL clauses to append to the main query. + * + * @type string $join SQL fragment to append to the main JOIN clause. + * @type string $where SQL fragment to append to the main WHERE clause. + * } + */ + protected function get_sql_for_clause( $query = array(), $parent_query = array() ) { + + // The sub-parts of a $where part. + $where_parts = array(); + + // Get first-order clauses + $now = $this->get_now( $query ); + $column = $this->get_column( $query ); + $compare = $this->get_compare( $query ); + $start_of_week = $this->get_start_of_week( $query ); + $inclusive = ! empty( $query['inclusive'] ); + + // Assign greater-than and less-than values. + $lt = '<'; + $gt = '>'; + + if ( true === $inclusive ) { + $lt .= '='; + $gt .= '='; + } + + // Range queries. + if ( ! empty( $query['after'] ) ) { + $where_parts[] = $this->get_db()->prepare( "{$column} {$gt} %s", $this->build_mysql_datetime( $query['after'], ! $inclusive, $now ) ); + } + + if ( ! empty( $query['before'] ) ) { + $where_parts[] = $this->get_db()->prepare( "{$column} {$lt} %s", $this->build_mysql_datetime( $query['before'], $inclusive, $now ) ); + } + + // Specific value queries. + if ( isset( $query['year'] ) && $value = $this->build_numeric_value( $compare, $query['year'] ) ) { + $where_parts[] = "YEAR( {$column} ) {$compare} {$value}"; + } + + if ( isset( $query['month'] ) && $value = $this->build_numeric_value( $compare, $query['month'] ) ) { + $where_parts[] = "MONTH( {$column} ) {$compare} {$value}"; + } elseif ( isset( $query['monthnum'] ) && $value = $this->build_numeric_value( $compare, $query['monthnum'] ) ) { + $where_parts[] = "MONTH( {$column} ) {$compare} {$value}"; + } + + if ( isset( $query['week'] ) && false !== ( $value = $this->build_numeric_value( $compare, $query['week'] ) ) ) { + $where_parts[] = $this->build_mysql_week( $column, $start_of_week ) . " {$compare} {$value}"; + } elseif ( isset( $query['w'] ) && false !== ( $value = $this->build_numeric_value( $compare, $query['w'] ) ) ) { + $where_parts[] = $this->build_mysql_week( $column, $start_of_week ) . " {$compare} {$value}"; + } + + if ( isset( $query['dayofyear'] ) && $value = $this->build_numeric_value( $compare, $query['dayofyear'] ) ) { + $where_parts[] = "DAYOFYEAR( {$column} ) {$compare} {$value}"; + } + + if ( isset( $query['day'] ) && $value = $this->build_numeric_value( $compare, $query['day'] ) ) { + $where_parts[] = "DAYOFMONTH( {$column} ) {$compare} {$value}"; + } + + if ( isset( $query['dayofweek'] ) && $value = $this->build_numeric_value( $compare, $query['dayofweek'] ) ) { + $where_parts[] = "DAYOFWEEK( {$column} ) {$compare} {$value}"; + } + + if ( isset( $query['dayofweek_iso'] ) && $value = $this->build_numeric_value( $compare, $query['dayofweek_iso'] ) ) { + $where_parts[] = "WEEKDAY( {$column} ) + 1 {$compare} {$value}"; + } + + // Straight value compare + if ( isset( $query['value'] ) ) { + $value = $this->build_value( $compare, $query['value'] ); + $where_parts[] = "{$column} {$compare} $value"; + } + + // Hour/Minute/Second + if ( isset( $query['hour'] ) || isset( $query['minute'] ) || isset( $query['second'] ) ) { + + // Avoid notices. + foreach ( array( 'hour', 'minute', 'second' ) as $unit ) { + if ( ! isset( $query[ $unit ] ) ) { + $query[ $unit ] = null; + } + } + + $time_query = $this->build_time_query( $column, $compare, $query['hour'], $query['minute'], $query['second'] ); + + if ( ! empty( $time_query ) ) { + $where_parts[] = $time_query; + } + } + + /* + * Return an array of 'join' and 'where' for compatibility + * with other query classes. + */ + return array( + 'where' => $where_parts, + 'join' => array(), + ); + } + + /** + * Builds and validates a value string based on the comparison operator. + * + * @since 1.0.0 + * + * @param string $compare The compare operator to use + * @param string|array $value The value + * + * @return string|false|int The value to be used in SQL or false on error. + */ + public function build_numeric_value( $compare = '=', $value = null ) { + + // Bail if null value + if ( is_null( $value ) ) { + return false; + } + + switch ( $compare ) { + case 'IN': + case 'NOT IN': + $value = (array) $value; + + // Remove non-numeric values. + $value = array_filter( $value, 'is_numeric' ); + + if ( empty( $value ) ) { + return false; + } + + return '(' . implode( ',', array_map( 'intval', $value ) ) . ')'; + + case 'BETWEEN': + case 'NOT BETWEEN': + if ( ! is_array( $value ) || ( 2 !== count( $value ) ) ) { + $value = array( $value, $value ); + } else { + $value = array_values( $value ); + } + + // If either value is non-numeric, bail. + foreach ( $value as $v ) { + if ( ! is_numeric( $v ) ) { + return false; + } + } + + $value = array_map( 'intval', $value ); + + return $value[0] . ' AND ' . $value[1]; + + default: + if ( ! is_numeric( $value ) ) { + return false; + } + + return (int) $value; + } + } + + /** + * Builds and validates a value string based on the comparison operator. + * + * @since 1.0.0 + * + * @param string $compare The compare operator to use + * @param string|array $value The value + * + * @return string|false|int The value to be used in SQL or false on error. + */ + public function build_value( $compare = '=', $value = null ) { + + if ( in_array( $compare, $this->multi_value_keys, true ) ) { + if ( ! is_array( $value ) ) { + $value = preg_split( '/[,\s]+/', $value ); + } + } else { + $value = trim( $value ); + } + + switch ( $compare ) { + case 'IN': + case 'NOT IN': + $compare_string = '(' . substr( str_repeat( ',%s', count( $value ) ), 1 ) . ')'; + $where = $this->get_db()->prepare( $compare_string, $value ); + break; + + case 'BETWEEN': + case 'NOT BETWEEN': + $value = array_slice( $value, 0, 2 ); + $where = $this->get_db()->prepare( '%s AND %s', $value ); + break; + + case 'LIKE': + case 'NOT LIKE': + $value = '%' . $this->get_db()->esc_like( $value ) . '%'; + $where = $this->get_db()->prepare( '%s', $value ); + break; + + // EXISTS with a value is interpreted as '='. + case 'EXISTS': + $compare = '='; + $where = $this->get_db()->prepare( '%s', $value ); + break; + + // 'value' is ignored for NOT EXISTS. + case 'NOT EXISTS': + $where = ''; + break; + + default: + $where = $this->get_db()->prepare( '%s', $value ); + break; + } + + return $where; + } + + /** + * Builds a MySQL format date/time based on some query parameters. + * + * You can pass an array of values (year, month, etc.) with missing parameter values being defaulted to + * either the maximum or minimum values (controlled by the $default_to parameter). Alternatively you can + * pass a string that will be run through strtotime(). + * + * @since 1.0.0 + * + * @param string|array $datetime An array of parameters or a strtotime() string + * @param bool $default_to_max Whether to round up incomplete dates. Supported by values + * of $datetime that are arrays, or string values that are a + * subset of MySQL date format ('Y', 'Y-m', 'Y-m-d', 'Y-m-d H:i'). + * Default: false. + * @param string|int $now The current unix timestamp. + * + * @return string|false A MySQL format date/time or false on failure + */ + public function build_mysql_datetime( $datetime = '', $default_to_max = false, $now = 0 ) { + + // Datetime is string + if ( is_string( $datetime ) ) { + + // Define matches so linters don't complain + $matches = array(); + + /* + * Try to parse some common date formats, so we can detect + * the level of precision and support the 'inclusive' parameter. + */ + + // Y + if ( preg_match( '/^(\d{4})$/', $datetime, $matches ) ) { + $datetime = array( + 'year' => intval( $matches[1] ), + ); + + // Y-m + } elseif ( preg_match( '/^(\d{4})\-(\d{2})$/', $datetime, $matches ) ) { + $datetime = array( + 'year' => intval( $matches[1] ), + 'month' => intval( $matches[2] ), + ); + + // Y-m-d + } elseif ( preg_match( '/^(\d{4})\-(\d{2})\-(\d{2})$/', $datetime, $matches ) ) { + $datetime = array( + 'year' => intval( $matches[1] ), + 'month' => intval( $matches[2] ), + 'day' => intval( $matches[3] ), + ); + + // Y-m-d H:i + } elseif ( preg_match( '/^(\d{4})\-(\d{2})\-(\d{2}) (\d{2}):(\d{2})$/', $datetime, $matches ) ) { + $datetime = array( + 'year' => intval( $matches[1] ), + 'month' => intval( $matches[2] ), + 'day' => intval( $matches[3] ), + 'hour' => intval( $matches[4] ), + 'minute' => intval( $matches[5] ), + ); + + // Y-m-d H:i:s + } elseif ( preg_match( '/^(\d{4})\-(\d{2})\-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/', $datetime, $matches ) ) { + $datetime = array( + 'year' => intval( $matches[1] ), + 'month' => intval( $matches[2] ), + 'day' => intval( $matches[3] ), + 'hour' => intval( $matches[4] ), + 'minute' => intval( $matches[5] ), + 'second' => intval( $matches[6] ), + ); + } + } + + // No match; may be int or string + if ( ! is_array( $datetime ) ) { + + // Maybe format or use as-is + $datetime = ! is_int( $datetime ) + ? strtotime( $datetime, $now ) + : absint( $datetime ); + + // Return formatted + return gmdate( 'Y-m-d H:i:s', $datetime ); + } + + // Map to ints + $datetime = array_map( 'absint', $datetime ); + + // Year + if ( ! isset( $datetime['year'] ) ) { + $datetime['year'] = gmdate( 'Y', $now ); + } + + // Month + if ( ! isset( $datetime['month'] ) ) { + $datetime['month'] = ! empty( $default_to_max ) + ? 12 + : 1; + } + + // Day + if ( ! isset( $datetime['day'] ) ) { + $datetime['day'] = ! empty( $default_to_max ) + ? (int) gmdate( 't', gmmktime( 0, 0, 0, $datetime['month'], 1, $datetime['year'] ) ) + : 1; + } + + // Hour + if ( ! isset( $datetime['hour'] ) ) { + $datetime['hour'] = ! empty( $default_to_max ) + ? 23 + : 0; + } + + // Minute + if ( ! isset( $datetime['minute'] ) ) { + $datetime['minute'] = ! empty( $default_to_max ) + ? 59 + : 0; + } + + // Second + if ( ! isset( $datetime['second'] ) ) { + $datetime['second'] = ! empty( $default_to_max ) + ? 59 + : 0; + } + + // Combine and return + return sprintf( + '%04d-%02d-%02d %02d:%02d:%02d', + $datetime['year'], + $datetime['month'], + $datetime['day'], + $datetime['hour'], + $datetime['minute'], + $datetime['second'] + ); + } + + /** + * Return a MySQL expression for selecting the week number based on the + * day that the week starts. + * + * Uses the WordPress site option, if set. + * + * @since 1.0.0 + * + * @param string $column Database column. + * @param int $start_of_week Day that week starts on. 0 = Sunday. + * + * @return string SQL clause. + */ + public function build_mysql_week( $column = '', $start_of_week = 0 ) { + + // When does the week start? + switch ( $start_of_week ) { + + // Monday + case 1: + $retval = "WEEK( {$column}, 1 )"; + break; + + // Tuesday - Saturday + case 2: + case 3: + case 4: + case 5: + case 6: + $retval = "WEEK( DATE_SUB( {$column}, INTERVAL {$start_of_week} DAY ), 0 )"; + break; + + // Sunday + case 0: + default: + $retval = "WEEK( {$column}, 0 )"; + break; + } + + // Return SQL + return $retval; + } + + /** + * Builds a query string for comparing time values (hour, minute, second). + * + * If just hour, minute, or second is set than a normal comparison will be done. + * However if multiple values are passed, a pseudo-decimal time will be created + * in order to be able to accurately compare against. + * + * @since 1.0.0 + * + * @param string $column The column to query against. Needs to be pre-validated! + * @param string $compare The comparison operator. Needs to be pre-validated! + * @param int|null $hour Optional. An hour value (0-23). + * @param int|null $minute Optional. A minute value (0-59). + * @param int|null $second Optional. A second value (0-59). + * + * @return string|false A query part or false on failure. + */ + public function build_time_query( $column, $compare, $hour = null, $minute = null, $second = null ) { + + // Have to have at least one + if ( ! isset( $hour ) && ! isset( $minute ) && ! isset( $second ) ) { + return false; + } + + // Complex combined queries aren't supported for multi-value queries + if ( in_array( $compare, $this->multi_value_keys, true ) ) { + $retval = array(); + + // Hour + if ( isset( $hour ) && false !== ( $value = $this->build_numeric_value( $compare, $hour ) ) ) { + $retval[] = "HOUR( {$column} ) {$compare} {$value}"; + } + + // Minute + if ( isset( $minute ) && false !== ( $value = $this->build_numeric_value( $compare, $minute ) ) ) { + $retval[] = "MINUTE( {$column} ) {$compare} {$value}"; + } + + // Second + if ( isset( $second ) && false !== ( $value = $this->build_numeric_value( $compare, $second ) ) ) { + $retval[] = "SECOND( {$column} ) {$compare} {$value}"; + } + + return implode( ' AND ', $retval ); + } + + // Cases where just one unit is set + + // Hour + if ( isset( $hour ) && ! isset( $minute ) && ! isset( $second ) && false !== ( $value = $this->build_numeric_value( $compare, $hour ) ) ) { + return "HOUR( {$column} ) {$compare} {$value}"; + + // Minute + } elseif ( ! isset( $hour ) && isset( $minute ) && ! isset( $second ) && false !== ( $value = $this->build_numeric_value( $compare, $minute ) ) ) { + return "MINUTE( {$column} ) {$compare} {$value}"; + + // Second + } elseif ( ! isset( $hour ) && ! isset( $minute ) && isset( $second ) && false !== ( $value = $this->build_numeric_value( $compare, $second ) ) ) { + return "SECOND( {$column} ) {$compare} {$value}"; + } + + // Single units were already handled. Since hour & second isn't allowed, + // minute must to be set. + if ( ! isset( $minute ) ) { + return false; + } + + // Defaults + $format = $time = ''; + + // Hour + if ( null !== $hour ) { + $format .= '%H.'; + $time .= sprintf( '%02d', $hour ) . '.'; + } else { + $format .= '0.'; + $time .= '0.'; + } + + // Minute + $format .= '%i'; + $time .= sprintf( '%02d', $minute ); + + // Second + if ( isset( $second ) ) { + $format .= '%s'; + $time .= sprintf( '%02d', $second ); + } + + // Build the SQL + $query = "DATE_FORMAT( {$column}, %s ) {$compare} %f"; + + // Return the prepared SQL + return $this->get_db()->prepare( $query, $format, $time ); + } + + /** + * Test if the supplied date is valid for the Gregorian calendar. + * + * @since 1.0.0 + * + * @link https://www.php.net/manual/en/function.checkdate.php + * + * @param int $month Month number. + * @param int $day Day number. + * @param int $year Year number. + * @param string $source_date The date to filter. + * + * @return bool True if valid date, false if not valid date. + */ + public function checkdate( $month = 0, $day = 0, $year = 0, $source_date = '' ) { + + // Check the date + $retval = checkdate( $month, $day, $year ); + + /** + * Filters whether the given date is valid for the Gregorian calendar. + * + * @since 1.0.0 + * + * @param bool $checkdate Whether the given date is valid. + * @param string $source_date Date to check. + */ + return (bool) apply_filters( 'wp_checkdate', $retval, $source_date ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Meta.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Meta.php new file mode 100644 index 000000000..07aaa859b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Queries/Meta.php @@ -0,0 +1,29 @@ + '', + 'from' => '', + 'where' => array(), + 'groupby' => '', + 'orderby' => '', + 'limits' => '' + ); + + /** + * Request clauses. + * + * @since 1.0.0 + * @var array + */ + protected $request_clauses = array( + 'select' => '', + 'from' => '', + 'where' => '', + 'groupby' => '', + 'orderby' => '', + 'limits' => '' + ); + + /** + * Meta query container. + * + * @since 1.0.0 + * @var object|Queries\Meta + */ + protected $meta_query = false; + + /** + * Date query container. + * + * @since 1.0.0 + * @var object|Queries\Date + */ + protected $date_query = false; + + /** + * Compare query container. + * + * @since 1.0.0 + * @var object|Queries\Compare + */ + protected $compare_query = false; + + /** Query Variables *******************************************************/ + + /** + * Parsed query vars set by the application, possibly filtered and changed. + * + * This is specifically marked as public, to allow byref actions to change + * them from outside the class methods proper and inside filter functions. + * + * @since 1.0.0 + * @var array + */ + public $query_vars = array(); + + /** + * Original query vars set by the application. + * + * These are the original query variables before any filters are applied, + * and are the results of merging $query_var_defaults with $query_vars. + * + * @since 1.0.0 + * @var array + */ + protected $query_var_originals = array(); + + /** + * Default values for query vars. + * + * These are computed at runtime based on the registered columns for the + * database table this query relates to. + * + * @since 1.0.0 + * @var array + */ + protected $query_var_defaults = array(); + + /** + * This private variable temporarily holds onto a random string used as the + * default query var value. This is used internally when performing + * comparisons, and allows for querying by falsy values. + * + * @since 1.1.0 + * @var string + */ + protected $query_var_default_value = ''; + + /** Results ***************************************************************/ + + /** + * List of items located by the query. + * + * @since 1.0.0 + * @var array + */ + public $items = array(); + + /** + * The amount of found items for the current query. + * + * @since 1.0.0 + * @var int + */ + protected $found_items = 0; + + /** + * The number of pages. + * + * @since 1.0.0 + * @var int + */ + protected $max_num_pages = 0; + + /** + * SQL for database query. + * + * @since 1.0.0 + * @var string + */ + protected $request = ''; + + /** Methods ***************************************************************/ + + /** + * Sets up the item query, based on the query vars passed. + * + * @since 1.0.0 + * + * @param string|array $query { + * Optional. Array or query string of item query parameters. + * Default empty. + * + * @type string $fields Site fields to return. Accepts 'ids' (returns an array of item IDs) + * or empty (returns an array of complete item objects). Default empty. + * To do a date query against a field, append the field name with _query + * @type bool $count Whether to return a item count (true) or array of item objects. + * Default false. + * @type int $number Limit number of items to retrieve. Use 0 for no limit. + * Default 100. + * @type int $offset Number of items to offset the query. Used to build LIMIT clause. + * Default 0. + * @type bool $no_found_rows Whether to disable the `SQL_CALC_FOUND_ROWS` query. + * Default true. + * @type string|array $orderby Accepts false, an empty array, or 'none' to disable `ORDER BY` clause. + * Default '', to primary column ID. + * @type string $order How to order retrieved items. Accepts 'ASC', 'DESC'. + * Default 'DESC'. + * @type string $search Search term(s) to retrieve matching items for. + * Default empty. + * @type array $search_columns Array of column names to be searched. + * Default empty array. + * @type bool $update_item_cache Whether to prime the cache for found items. + * Default false. + * @type bool $update_meta_cache Whether to prime the meta cache for found items. + * Default false. + * } + */ + public function __construct( $query = array() ) { + + // Setup + $this->set_alias(); + $this->set_prefix(); + $this->set_columns(); + $this->set_item_shape(); + $this->set_query_var_defaults(); + + // Maybe execute a query if arguments were passed + if ( ! empty( $query ) ) { + $this->query( $query ); + } + } + + /** + * Queries the database and retrieves items or counts. + * + * This method is public to allow subclasses to perform JIT manipulation + * of the parameters passed into it. + * + * @since 1.0.0 + * + * @param string|array $query Array or URL query string of parameters. + * @param bool $use_cache Use DB cache or not. (custom parameter added by us!) + * @return array|int List of items, or number of items when 'count' is passed as a query var. + */ + public function query( $query = array(), bool $use_cache = true ) { + $this->parse_query( $query ); + + return $this->get_items( $use_cache ); + } + + /** Private Setters *******************************************************/ + + /** + * Set the time when items were last changed. + * + * We set this locally to avoid inconsistencies between method calls. + * + * @since 1.0.0 + */ + private function set_last_changed() { + $this->last_changed = microtime(); + } + + /** + * Set up the table alias if not already set in the class. + * + * This happens before prefixes are applied. + * + * @since 1.0.0 + */ + private function set_alias() { + if ( empty( $this->table_alias ) ) { + $this->table_alias = $this->first_letters( $this->table_name ); + } + } + + /** + * Prefix table names, cache groups, and other things. + * + * This is to avoid conflicts with other plugins or themes that might be + * doing their own things. + * + * @since 1.0.0 + */ + private function set_prefix() { + $this->table_name = $this->apply_prefix( $this->table_name ); + $this->table_alias = $this->apply_prefix( $this->table_alias ); + $this->cache_group = $this->apply_prefix( $this->cache_group, '-' ); + } + + /** + * Set columns objects. + * + * @since 1.0.0 + */ + private function set_columns() { + + // Bail if no table schema + if ( ! class_exists( $this->table_schema ) ) { + return; + } + + // Invoke a new table schema class + $schema = new $this->table_schema; + + // Maybe get the column objects + if ( ! empty( $schema->columns ) ) { + $this->columns = $schema->columns; + } + } + + /** + * Set the default item shape if none exists. + * + * @since 1.0.0 + */ + private function set_item_shape() { + if ( empty( $this->item_shape ) || ! class_exists( $this->item_shape ) ) { + $this->item_shape = __NAMESPACE__ . '\\Row'; + } + } + + /** + * Set default query vars based on columns. + * + * @since 1.0.0 + */ + private function set_query_var_defaults() { + + // Default query variable value + $this->query_var_default_value = function_exists( 'random_bytes' ) + ? $this->apply_prefix( bin2hex( random_bytes( 18 ) ) ) + : $this->apply_prefix( uniqid( '_', true ) ); + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Default query variables + $this->query_var_defaults = array( + 'fields' => '', + 'number' => 100, + 'offset' => '', + 'orderby' => $primary, + 'order' => 'DESC', + 'groupby' => '', + 'search' => '', + 'search_columns' => array(), + 'count' => false, + + // Disable SQL_CALC_FOUND_ROWS? + 'no_found_rows' => true, + + // Queries + 'meta_query' => null, // See Queries\Meta + 'date_query' => null, // See Queries\Date + 'compare_query' => null, // See Queries\Compare + + // Caching + 'update_item_cache' => true, + 'update_meta_cache' => true + ); + + // Bail if no columns + if ( empty( $this->columns ) ) { + return; + } + + // Direct column names + $names = wp_list_pluck( $this->columns, 'name' ); + foreach ( $names as $name ) { + $this->query_var_defaults[ $name ] = $this->query_var_default_value; + } + + // Possible ins + $possible_ins = $this->get_columns( array( 'in' => true ), 'and', 'name' ); + foreach ( $possible_ins as $in ) { + $key = "{$in}__in"; + $this->query_var_defaults[ $key ] = false; + } + + // Possible not ins + $possible_not_ins = $this->get_columns( array( 'not_in' => true ), 'and', 'name' ); + foreach ( $possible_not_ins as $in ) { + $key = "{$in}__not_in"; + $this->query_var_defaults[ $key ] = false; + } + + // Possible dates + $possible_dates = $this->get_columns( array( 'date_query' => true ), 'and', 'name' ); + foreach ( $possible_dates as $date ) { + $key = "{$date}_query"; + $this->query_var_defaults[ $key ] = false; + } + } + + /** + * Set the request clauses. + * + * @since 1.0.0 + * + * @param array $clauses + */ + private function set_request_clauses( $clauses = array() ) { + + // Found rows + $found_rows = empty( $this->query_vars['no_found_rows'] ) + ? 'SQL_CALC_FOUND_ROWS' + : ''; + + // Fields + $fields = ! empty( $clauses['fields'] ) + ? $clauses['fields'] + : ''; + + // Join + $join = ! empty( $clauses['join'] ) + ? $clauses['join'] + : ''; + + // Where + $where = ! empty( $clauses['where'] ) + ? "WHERE {$clauses['where']}" + : ''; + + // Group by + $groupby = ! empty( $clauses['groupby'] ) + ? "GROUP BY {$clauses['groupby']}" + : ''; + + // Order by + $orderby = ! empty( $clauses['orderby'] ) + ? "ORDER BY {$clauses['orderby']}" + : ''; + + // Limits + $limits = ! empty( $clauses['limits'] ) + ? $clauses['limits'] + : ''; + + // Select & From + $table = $this->get_table_name(); + $select = "SELECT {$found_rows} {$fields}"; + $from = "FROM {$table} {$this->table_alias} {$join}"; + + // Put query into clauses array + $this->request_clauses['select'] = $select; + $this->request_clauses['from'] = $from; + $this->request_clauses['where'] = $where; + $this->request_clauses['groupby'] = $groupby; + $this->request_clauses['orderby'] = $orderby; + $this->request_clauses['limits'] = $limits; + } + + /** + * Set the request. + * + * @since 1.0.0 + */ + private function set_request() { + $filtered = array_filter( $this->request_clauses ); + $clauses = array_map( 'trim', $filtered ); + $this->request = implode( ' ', $clauses ); + } + + /** + * Set items by mapping them through the single item callback. + * + * @since 1.0.0 + * @param array $item_ids + */ + private function set_items( $item_ids = array() ) { + + // Bail if counting, to avoid shaping items + if ( ! empty( $this->query_vars['count'] ) ) { + $this->items = $item_ids; + return; + } + + // Cast to integers + $item_ids = array_map( 'intval', $item_ids ); + + // Prime item caches + $this->prime_item_caches( $item_ids ); + + // Shape the items + $this->items = $this->shape_items( $item_ids ); + } + + /** + * Populates found_items and max_num_pages properties for the current query + * if the limit clause was used. + * + * @since 1.0.0 + * + * @param array $item_ids Optional array of item IDs + */ + private function set_found_items( $item_ids = array() ) { + + // Items were not found + if ( empty( $item_ids ) ) { + return; + } + + // Default to number of item IDs + $this->found_items = count( (array) $item_ids ); + + // Count query + if ( ! empty( $this->query_vars['count'] ) ) { + + // Not grouped + if ( is_numeric( $item_ids ) && empty( $this->query_vars['groupby'] ) ) { + $this->found_items = intval( $item_ids ); + } + + // Not a count query + } elseif ( is_array( $item_ids ) && ( ! empty( $this->query_vars['number'] ) && empty( $this->query_vars['no_found_rows'] ) ) ) { + + /** + * Filters the query used to retrieve found item count. + * + * @since 1.0.0 + * + * @param string $found_items_query SQL query. Default 'SELECT FOUND_ROWS()'. + * @param object $item_query The object instance. + */ + $found_items_query = (string) apply_filters_ref_array( $this->apply_prefix( "found_{$this->item_name_plural}_query" ), array( 'SELECT FOUND_ROWS()', &$this ) ); + + // Maybe query for found items + if ( ! empty( $found_items_query ) ) { + $this->found_items = (int) $this->get_db()->get_var( $found_items_query ); + } + } + } + + /** Public Setters ********************************************************/ + + /** + * Set a query var, to both defaults and request arrays. + * + * This method is used to expose the private query_vars array to hooks, + * allowing them to manipulate query vars just-in-time. + * + * @since 1.0.0 + * + * @param string $key + * @param string $value + */ + public function set_query_var( $key = '', $value = '' ) { + $this->query_var_defaults[ $key ] = $value; + $this->query_vars[ $key ] = $value; + } + + /** + * Check whether a query variable strictly equals the unique default + * starting value. + * + * @since 1.1.0 + * @param string $key + * @return bool + */ + public function is_query_var_default( $key = '' ) { + return (bool) ( $this->query_vars[ $key ] === $this->query_var_default_value ); + } + + /** Private Getters *******************************************************/ + + /** + * Pass-through method to return a new Meta object. + * + * @since 1.0.0 + * + * @param array $args See Queries\Meta + * + * @return Queries\Meta + */ + private function get_meta_query( $args = array() ) { + return new Queries\Meta( $args ); + } + + /** + * Pass-through method to return a new Compare object. + * + * @since 1.0.0 + * + * @param array $args See Queries\Compare + * + * @return Queries\Compare + */ + private function get_compare_query( $args = array() ) { + return new Queries\Compare( $args ); + } + + /** + * Pass-through method to return a new Queries\Date object. + * + * @since 1.0.0 + * + * @param array $args See Queries\Date + * + * @return Queries\Date + */ + private function get_date_query( $args = array() ) { + return new Queries\Date( $args ); + } + + /** + * Return the current time as a UTC timestamp. + * + * This is used by add_item() and update_item() + * + * @since 1.0.0 + * + * @return string + */ + private function get_current_time() { + return gmdate( "Y-m-d\TH:i:s\Z" ); + } + + /** + * Return the literal table name (with prefix) from the database interface. + * + * @since 1.0.0 + * + * @return string + */ + private function get_table_name() { + return $this->get_db()->{$this->table_name}; + } + + /** + * Return array of column names. + * + * @since 1.0.0 + * + * @return array + */ + private function get_column_names() { + return array_flip( $this->get_columns( array(), 'and', 'name' ) ); + } + + /** + * Return the primary database column name. + * + * @since 1.0.0 + * + * @return string Default "id", Primary column name if not empty + */ + private function get_primary_column_name() { + return $this->get_column_field( array( 'primary' => true ), 'name', 'id' ); + } + + /** + * Get a column from an array of arguments. + * + * @since 1.0.0 + * + * @param array $args Arguments to get a column by. + * @param string $field Field to get from a column. + * @param mixed $default Default to use if no field is set. + * @return mixed Column object, or false + */ + private function get_column_field( $args = array(), $field = '', $default = false ) { + + // Get the column + $column = $this->get_column_by( $args ); + + // Return field, or default + return isset( $column->{$field} ) + ? $column->{$field} + : $default; + } + + /** + * Get a column from an array of arguments. + * + * @since 1.0.0 + * + * @param array $args Arguments to get a column by. + * @return mixed Column object, or false + */ + private function get_column_by( $args = array() ) { + + // Filter columns + $filter = $this->get_columns( $args ); + + // Return column or false + return ! empty( $filter ) + ? reset( $filter ) + : false; + } + + /** + * Get columns from an array of arguments. + * + * @since 1.0.0 + * + * @param array $args Arguments to filter columns by. + * @param string $operator Optional. The logical operation to perform. + * @param string $field Optional. A field from the object to place + * instead of the entire object. Default false. + * @return array Array of column. + */ + private function get_columns( $args = array(), $operator = 'and', $field = false ) { + + // Filter columns + $filter = wp_filter_object_list( $this->columns, $args, $operator, $field ); + + // Return column or false + return ! empty( $filter ) + ? array_values( $filter ) + : array(); + } + + /** + * Get a single database row by any column and value, skipping cache. + * + * @since 1.0.0 + * + * @param string $column_name Name of database column + * @param string $column_value Value to query for + * @return object|false False if empty/error, Object if successful + */ + private function get_item_raw( $column_name = '', $column_value = '' ) { + + // Bail if no name or value + if ( empty( $column_name ) || empty( $column_value ) ) { + return false; + } + + // Bail if values aren't query'able + if ( ! is_string( $column_name ) || ! is_scalar( $column_value ) ) { + return false; + } + + // Get query parts + $table = $this->get_table_name(); + $pattern = $this->get_column_field( array( 'name' => $column_name ), 'pattern', '%s' ); + + // Query database + $query = "SELECT * FROM {$table} WHERE {$column_name} = {$pattern} LIMIT 1"; + $select = $this->get_db()->prepare( $query, $column_value ); + $result = $this->get_db()->get_row( $select ); + + // Bail on failure + if ( ! $this->is_success( $result ) ) { + return false; + } + + // Return row + return $result; + } + + /** + * Retrieves a list of items matching the query vars. + * + * @since 1.0.0 + * + * @param bool $use_cache Use DB cache or not. (custom parameter added by us!) + * + * @return array|int List of items, or number of items when 'count' is passed as a query var. + */ + private function get_items( bool $use_cache = true ) { + + /** + * Fires before object items are retrieved. + * + * @since 1.0.0 + * + * @param Query &$this Current instance of Query, passed by reference. + */ + do_action_ref_array( $this->apply_prefix( "pre_get_{$this->item_name_plural}" ), array( &$this ) ); + + // Never limit, never update item/meta caches when counting + if ( ! empty( $this->query_vars['count'] ) ) { + $this->query_vars['number'] = false; + $this->query_vars['no_found_rows'] = true; + $this->query_vars['update_item_cache'] = false; + $this->query_vars['update_meta_cache'] = false; + } + + // Check the cache + $cache_key = $this->get_cache_key(); + $cache_value = $use_cache ? $this->cache_get( $cache_key, $this->cache_group ) : false; + + // No cache value + if ( false === $cache_value ) { + $item_ids = $this->get_item_ids(); + + // Set the number of found items + $this->set_found_items( $item_ids ); + + if ( $use_cache ) { + // Format the cached value + $cache_value = array( + 'item_ids' => $item_ids, + 'found_items' => intval( $this->found_items ), + ); + + // Add value to the cache + $this->cache_add( $cache_key, $cache_value, $this->cache_group ); + } + + // Value exists in cache + } else { + $item_ids = $cache_value['item_ids']; + $this->found_items = intval( $cache_value['found_items'] ); + } + + // Pagination + if ( ! empty( $this->found_items ) && ! empty( $this->query_vars['number'] ) ) { + $this->max_num_pages = ceil( $this->found_items / $this->query_vars['number'] ); + } + + // Cast to int if not grouping counts + if ( ! empty( $this->query_vars['count'] ) && empty( $this->query_vars['groupby'] ) ) { + $item_ids = intval( $item_ids ); + } + + // Set items from IDs + $this->set_items( $item_ids ); + + // Return array of items + return $this->items; + } + + /** + * Used internally to get a list of item IDs matching the query vars. + * + * @since 1.0.0 + * + * @return int|array A single count of item IDs if a count query. An array + * of item IDs if a full query. + */ + private function get_item_ids() { + + // Setup primary column, and parse the where clause + $this->parse_where(); + + // Order & Order By + $order = $this->parse_order( $this->query_vars['order'] ); + $orderby = $this->get_order_by( $order ); + + // Limit & Offset + $limit = absint( $this->query_vars['number'] ); + $offset = absint( $this->query_vars['offset'] ); + + // Limits + if ( ! empty( $limit ) ) { + $limits = ! empty( $offset ) + ? "LIMIT {$offset}, {$limit}" + : "LIMIT {$limit}"; + } else { + $limits = ''; + } + + // Where & Join + $where = implode( ' AND ', $this->query_clauses['where'] ); + $join = implode( ', ', $this->query_clauses['join'] ); + + // Group by + $groupby = $this->parse_groupby( $this->query_vars['groupby'] ); + + // Fields + $fields = $this->parse_fields( $this->query_vars['fields'] ); + + // Setup the query array (compact() is too opaque here) + $query = array( + 'fields' => $fields, + 'join' => $join, + 'where' => $where, + 'orderby' => $orderby, + 'limits' => $limits, + 'groupby' => $groupby + ); + + /** + * Filters the item query clauses. + * + * @since 1.0.0 + * + * @param array $pieces A compacted array of item query clauses. + * @param Query &$this Current instance passed by reference. + */ + $clauses = (array) apply_filters_ref_array( $this->apply_prefix( "{$this->item_name_plural}_query_clauses" ), array( $query, &$this ) ); + + // Setup request + $this->set_request_clauses( $clauses ); + $this->set_request(); + + // Return count + if ( ! empty( $this->query_vars['count'] ) ) { + + // Get vars or results + $retval = empty( $this->query_vars['groupby'] ) + ? $this->get_db()->get_var( $this->request ) + : $this->get_db()->get_results( $this->request, ARRAY_A ); + + // Return vars or results + return $retval; + } + + // Get IDs + $item_ids = $this->get_db()->get_col( $this->request ); + + // Return parsed IDs + return wp_parse_id_list( $item_ids ); + } + + /** + * Get the ORDERBY clause. + * + * @since 1.0.0 + * + * @param string $order + * @return string + */ + private function get_order_by( $order = '' ) { + + // Default orderby primary column + $parsed = $this->parse_orderby(); + $orderby = "{$parsed} {$order}"; + + // Disable ORDER BY if counting, or: 'none', an empty array, or false. + if ( ! empty( $this->query_vars['count'] ) || in_array( $this->query_vars['orderby'], array( 'none', array(), false ), true ) ) { + $orderby = ''; + + // Ordering by something, so figure it out + } elseif ( ! empty( $this->query_vars['orderby'] ) ) { + + // Array of keys, or comma separated + $ordersby = is_array( $this->query_vars['orderby'] ) + ? $this->query_vars['orderby'] + : preg_split( '/[,\s]/', $this->query_vars['orderby'] ); + + $orderby_array = array(); + $possible_ins = $this->get_columns( array( 'in' => true ), 'and', 'name' ); + $sortables = $this->get_columns( array( 'sortable' => true ), 'and', 'name' ); + + // Loop through possible order by's + foreach ( $ordersby as $_key => $_value ) { + + // Skip if empty + if ( empty( $_value ) ) { + continue; + } + + // Key is numeric + if ( is_int( $_key ) ) { + $_orderby = $_value; + $_item = $order; + + // Key is string + } else { + $_orderby = $_key; + $_item = $_value; + } + + // Skip if not sortable + if ( ! in_array( $_value, $sortables, true ) ) { + continue; + } + + // Parse orderby + $parsed = $this->parse_orderby( $_orderby ); + + // Skip if empty + if ( empty( $parsed ) ) { + continue; + } + + // Set if __in + if ( in_array( $_orderby, $possible_ins, true ) ) { + $orderby_array[] = "{$parsed} {$order}"; + continue; + } + + // Append parsed orderby to array + $orderby_array[] = $parsed . ' ' . $this->parse_order( $_item ); + } + + // Only set if valid orderby + if ( ! empty( $orderby_array ) ) { + $orderby = implode( ', ', $orderby_array ); + } + } + + // Return parsed orderby + return $orderby; + } + + /** + * Used internally to generate an SQL string for searching across multiple + * columns. + * + * @since 1.0.0 + * + * @param string $string Search string. + * @param array $columns Columns to search. + * @return string Search SQL. + */ + private function get_search_sql( $string = '', $columns = array() ) { + + // Array or String + $like = ( false !== strpos( $string, '*' ) ) + ? '%' . implode( '%', array_map( array( $this->get_db(), 'esc_like' ), explode( '*', $string ) ) ) . '%' + : '%' . $this->get_db()->esc_like( $string ) . '%'; + + // Default array + $searches = array(); + + // Build search SQL + foreach ( $columns as $column ) { + $searches[] = $this->get_db()->prepare( "{$column} LIKE %s", $like ); + } + + // Return the clause + return '(' . implode( ' OR ', $searches ) . ')'; + } + + /** Private Parsers *******************************************************/ + + /** + * Parses arguments passed to the item query with default query parameters. + * + * @since 1.0.0 + * + * @see Query::__construct() + * + * @param string|array $query Array or string of Query arguments. + */ + private function parse_query( $query = array() ) { + + // Setup the query_vars_original var + $this->query_var_originals = wp_parse_args( $query ); + + // Setup the query_vars parsed var + $this->query_vars = wp_parse_args( + $this->query_var_originals, + $this->query_var_defaults + ); + + /** + * Fires after the item query vars have been parsed. + * + * @since 1.0.0 + * + * @param Query &$this The Query instance (passed by reference). + */ + do_action_ref_array( $this->apply_prefix( "parse_{$this->item_name_plural}_query" ), array( &$this ) ); + } + + /** + * Parse the where clauses for all known columns. + * + * @todo split this method into smaller parts + * + * @since 1.0.0 + */ + private function parse_where() { + + // Defaults + $where = $join = $searchable = $date_query = array(); + + // Loop through columns + foreach ( $this->columns as $column ) { + + // Maybe add name to searchable array + if ( true === $column->searchable ) { + $searchable[] = $column->name; + } + + // Literal column comparison + if ( ! $this->is_query_var_default( $column->name ) ) { + + // Array (unprepared) + if ( is_array( $this->query_vars[ $column->name ] ) ) { + $where_id = "'" . implode( "', '", $this->get_db()->_escape( $this->query_vars[ $column->name ] ) ) . "'"; + $statement = "{$this->table_alias}.{$column->name} IN ({$where_id})"; + + // Add to where array + $where[ $column->name ] = $statement; + + // Numeric/String/Float (prepared) + } else { + $pattern = $this->get_column_field( array( 'name' => $column->name ), 'pattern', '%s' ); + $where_id = $this->query_vars[ $column->name ]; + $statement = "{$this->table_alias}.{$column->name} = {$pattern}"; + + // Add to where array + $where[ $column->name ] = $this->get_db()->prepare( $statement, $where_id ); + } + } + + // __in + if ( true === $column->in ) { + $where_id = "{$column->name}__in"; + + // Parse item for an IN clause. + if ( isset( $this->query_vars[ $where_id ] ) && is_array( $this->query_vars[ $where_id ] ) ) { + + // Convert single item arrays to literal column comparisons + if ( 1 === count( $this->query_vars[ $where_id ] ) ) { + $column_value = reset( $this->query_vars[ $where_id ] ); + $statement = "{$this->table_alias}.{$column->name} = %s"; + + $where[ $column->name ] = $this->get_db()->prepare( $statement, $column_value ); + + // Implode + } else { + $where[ $where_id ] = "{$this->table_alias}.{$column->name} IN ( '" . implode( "', '", $this->get_db()->_escape( $this->query_vars[ $where_id ] ) ) . "' )"; + } + } + } + + // __not_in + if ( true === $column->not_in ) { + $where_id = "{$column->name}__not_in"; + + // Parse item for a NOT IN clause. + if ( isset( $this->query_vars[ $where_id ] ) && is_array( $this->query_vars[ $where_id ] ) ) { + + // Convert single item arrays to literal column comparisons + if ( 1 === count( $this->query_vars[ $where_id ] ) ) { + $column_value = reset( $this->query_vars[ $where_id ] ); + $statement = "{$this->table_alias}.{$column->name} != %s"; + + $where[ $column->name ] = $this->get_db()->prepare( $statement, $column_value ); + + // Implode + } else { + $where[ $where_id ] = "{$this->table_alias}.{$column->name} NOT IN ( '" . implode( "', '", $this->get_db()->_escape( $this->query_vars[ $where_id ] ) ) . "' )"; + } + } + } + + // date_query + if ( true === $column->date_query ) { + $where_id = "{$column->name}_query"; + $column_date = $this->query_vars[ $where_id ]; + + // Parse item + if ( ! empty( $column_date ) ) { + + // Default arguments + $defaults = array( + 'column' => "{$this->table_alias}.{$column->name}", + 'before' => $column_date, + 'inclusive' => true + ); + + // Default date query + if ( is_string( $column_date ) ) { + $date_query[] = $defaults; + + // Array query var + } elseif ( is_array( $column_date ) ) { + + // Auto-fill column if empty + if ( empty( $column_date['column'] ) ) { + $column_date['column'] = $defaults['column']; + } + + // Add clause to date query + $date_query[] = $column_date; + } + } + } + } + + // Maybe search if columns are searchable. + if ( ! empty( $searchable ) && strlen( $this->query_vars['search'] ) ) { + $search_columns = array(); + + // Intersect against known searchable columns + if ( ! empty( $this->query_vars['search_columns'] ) ) { + $search_columns = array_intersect( + $this->query_vars['search_columns'], + $searchable + ); + } + + // Default to all searchable columns + if ( empty( $search_columns ) ) { + $search_columns = $searchable; + } + + /** + * Filters the columns to search in a Query search. + * + * @since 1.0.0 + * + * @param array $search_columns Array of column names to be searched. + * @param string $search Text being searched. + * @param object $this The current Query instance. + */ + $search_columns = (array) apply_filters( $this->apply_prefix( "{$this->item_name_plural}_search_columns" ), $search_columns, $this->query_vars['search'], $this ); + + // Add search query clause + $where['search'] = $this->get_search_sql( $this->query_vars['search'], $search_columns ); + } + + /** Query Classes *****************************************************/ + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Get the meta table + $table = $this->get_meta_type(); + + // Set the " AND " regex pattern + $and = '/^\s*AND\s*/'; + + // Maybe perform a meta query. + $meta_query = $this->query_vars['meta_query']; + if ( ! empty( $meta_query ) && is_array( $meta_query ) ) { + $this->meta_query = $this->get_meta_query( $meta_query ); + $clauses = $this->meta_query->get_sql( $table, $this->table_alias, $primary, $this ); + + // Not all objects have meta, so make sure this one exists + if ( false !== $clauses ) { + + // Set join + if ( ! empty( $clauses['join'] ) ) { + $join['meta_query'] = $clauses['join']; + } + + // Set where + if ( ! empty( $clauses['where'] ) ) { + + // Remove " AND " from query query where clause + $where['meta_query'] = preg_replace( $and, '', $clauses['where'] ); + } + } + } + + // Maybe perform a compare query. + $compare_query = $this->query_vars['compare_query']; + if ( ! empty( $compare_query ) && is_array( $compare_query ) ) { + $this->compare_query = $this->get_compare_query( $compare_query ); + $clauses = $this->compare_query->get_sql( $table, $this->table_alias, $primary, $this ); + + // Not all objects can compare, so make sure this one exists + if ( false !== $clauses ) { + + // Set join + if ( ! empty( $clauses['join'] ) ) { + $join['compare_query'] = $clauses['join']; + } + + // Set where + if ( ! empty( $clauses['where'] ) ) { + + // Remove " AND " from query where clause. + $where['compare_query'] = preg_replace( $and, '', $clauses['where'] ); + } + } + } + + // Only do a date query with an array + $date_query = ! empty( $date_query ) + ? $date_query + : $this->query_vars['date_query']; + + // Maybe perform a date query + if ( ! empty( $date_query ) && is_array( $date_query ) ) { + $this->date_query = $this->get_date_query( $date_query ); + $clauses = $this->date_query->get_sql( $this->table_name, $this->table_alias, $primary, $this ); + + // Not all objects are dates, so make sure this one exists + if ( false !== $clauses ) { + + // Set join + if ( ! empty( $clauses['join'] ) ) { + $join['date_query'] = $clauses['join']; + } + + // Set where + if ( ! empty( $clauses['where'] ) ) { + + // Remove " AND " from query where clause. + $where['date_query'] = preg_replace( $and, '', $clauses['where'] ); + } + } + } + + // Set where and join clauses, removing possible empties + $this->query_clauses['where'] = array_filter( $where ); + $this->query_clauses['join'] = array_filter( $join ); + } + + /** + * Parse which fields to query for. + * + * @since 1.0.0 + * + * @param string $fields + * @param bool $alias + * @return string + */ + private function parse_fields( $fields = '', $alias = true ) { + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Default return value + $retval = ( true === $alias ) + ? "{$this->table_alias}.{$primary}" + : $primary; + + // No fields + if ( empty( $fields ) && ! empty( $this->query_vars['count'] ) ) { + + // Possible fields to group by + $groupby_names = $this->parse_groupby( $this->query_vars['groupby'], $alias ); + $groupby_names = ! empty( $groupby_names ) + ? "{$groupby_names}" + : ''; + + // Group by or total count + $retval = ! empty( $groupby_names ) + ? "{$groupby_names}, COUNT(*) as count" + : 'COUNT(*)'; + } + + // Return fields (or COUNT) + return $retval; + } + + /** + * Parses and sanitizes the 'groupby' keys passed into the item query. + * + * @since 1.0.0 + * + * @param string $groupby + * @param bool $alias + * @return string + */ + private function parse_groupby( $groupby = '', $alias = true ) { + + // Bail if empty + if ( empty( $groupby ) ) { + return ''; + } + + // Sanitize groupby columns + $groupby = (array) array_map( 'sanitize_key', (array) $groupby ); + + // Re'flip column names back around + $columns = array_flip( $this->get_column_names() ); + + // Get the intersection of allowed column names to groupby columns + $intersect = array_intersect( $groupby, $columns ); + + // Bail if invalid column + if ( empty( $intersect ) ) { + return ''; + } + + // Default return value + $retval = array(); + + // Maybe prepend table alias to key + foreach ( $intersect as $key ) { + $retval[] = ( true === $alias ) + ? "{$this->table_alias}.{$key}" + : $key; + } + + // Separate sanitized columns + return implode( ',', array_values( $retval ) ); + } + + /** + * Parses and sanitizes 'orderby' keys passed to the item query. + * + * @since 1.0.0 + * + * @param string $orderby Field for the items to be ordered by. + * @return string|false Value to used in the ORDER clause. False otherwise. + */ + private function parse_orderby( $orderby = '' ) { + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Default return value + $parsed = "{$this->table_alias}.{$primary}"; + + // Default to primary column + if ( empty( $orderby ) ) { + $orderby = $primary; + } + + // __in + if ( false !== strstr( $orderby, '__in' ) ) { + $column_name = str_replace( '__in', '', $orderby ); + $column = $this->get_column_by( array( 'name' => $column_name ) ); + $item_in = $column->is_numeric() + ? implode( ',', array_map( 'absint', $this->query_vars[ $orderby ] ) ) + : implode( ',', $this->query_vars[ $orderby ] ); + + $parsed = "FIELD( {$this->table_alias}.{$column->name}, {$item_in} )"; + + // Specific column + } else { + + // Orderby is a literal, sortable column name + $sortables = $this->get_columns( array( 'sortable' => true ), 'and', 'name' ); + if ( in_array( $orderby, $sortables, true ) ) { + $parsed = "{$this->table_alias}.{$orderby}"; + } + } + + // Return parsed value + return $parsed; + } + + /** + * Parses an 'order' query variable and cast it to 'ASC' or 'DESC' as + * necessary. + * + * @since 1.0.0 + * + * @param string $order The 'order' query variable. + * @return string The sanitized 'order' query variable. + */ + private function parse_order( $order = '' ) { + + // Bail if malformed + if ( empty( $order ) || ! is_string( $order ) ) { + return 'DESC'; + } + + // Ascending or Descending + return ( 'ASC' === strtoupper( $order ) ) + ? 'ASC' + : 'DESC'; + } + + /** Private Shapers *******************************************************/ + + /** + * Shape items into their most relevant objects. + * + * This will try to use item_shape, but will fallback to a private + * method for querying and caching items. + * + * If using the `fields` parameter, results will have unique shapes based on + * exactly what was requested. + * + * @since 1.0.0 + * + * @param array $items + * @return array + */ + private function shape_items( $items = array() ) { + + // Force to stdClass if querying for fields + if ( ! empty( $this->query_vars['fields'] ) ) { + $this->item_shape = 'stdClass'; + } + + // Default return value + $retval = array(); + + // Use foreach because it's faster than array_map() + if ( ! empty( $items ) ) { + foreach ( $items as $item ) { + $retval[] = $this->get_item( $item ); + } + } + + /** + * Filters the object query results. + * + * Looks like `edd_get_customers` + * + * @since 1.0.0 + * + * @param array $retval An array of items. + * @param object &$this Current instance of Query, passed by reference. + */ + $retval = (array) apply_filters_ref_array( $this->apply_prefix( "the_{$this->item_name_plural}" ), array( $retval, &$this ) ); + + // Return filtered results + return ! empty( $this->query_vars['fields'] ) + ? $this->get_item_fields( $retval ) + : $retval; + } + + /** + * Get specific item fields based on query_vars['fields']. + * + * @since 1.0.0 + * + * @param array $items + * @return array + */ + private function get_item_fields( $items = array() ) { + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Get the query var fields + $fields = $this->query_vars['fields']; + + // Strings need to be single columns + if ( is_string( $fields ) ) { + $field = sanitize_key( $fields ); + $items = ( 'ids' === $fields ) + ? wp_list_pluck( $items, $primary ) + : wp_list_pluck( $items, $field, $primary ); + + // Arrays could be anything + } elseif ( is_array( $fields ) ) { + $new_items = array(); + $fields = array_flip( $fields ); + + // Loop through items and pluck out the fields + foreach ( $items as $item_id => $item ) { + $new_items[ $item_id ] = (object) array_intersect_key( (array) $item, $fields ); + } + + // Set the items and unset the new items + $items = $new_items; + unset( $new_items ); + } + + // Return the item, possibly reduced + return $items; + } + + /** + * Shape an item ID from an object, array, or numeric value. + * + * @since 1.0.0 + * + * @param mixed $item + * @return int + */ + private function shape_item_id( $item = 0 ) { + + // Default return value + $retval = 0; + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Numeric item ID + if ( is_numeric( $item ) ) { + $retval = $item; + + // Object item + } elseif ( is_object( $item ) && isset( $item->{$primary} ) ) { + $retval = $item->{$primary}; + + // Array item + } elseif ( is_array( $item ) && isset( $item[ $primary ] ) ) { + $retval = $item[ $primary ]; + } + + // Return the item ID + return absint( $retval ); + } + + /** Queries ***************************************************************/ + + /** + * Get a single database row by the primary column ID, possibly from cache. + * + * Accepts an integer, object, or array, and attempts to get the ID from it, + * then attempts to retrieve that item fresh from the database or cache. + * + * @since 1.0.0 + * + * @param int|array|object $item_id The ID of the item + * @return object|false False if empty/error, Object if successful + */ + public function get_item( $item_id = 0 ) { + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if no item to get by + if ( empty( $item_id ) ) { + return false; + } + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Get item by ID + return $this->get_item_by( $primary, $item_id ); + } + + /** + * Get a single database row by any column and value, possibly from cache. + * + * Take care to only use this method on columns with unique values, + * preferably with a cache group for that column. See: get_item(). + * + * @since 1.0.0 + * + * @param string $column_name Name of database column + * @param int|string $column_value Value to query for + * @return object|false False if empty/error, Object if successful + */ + public function get_item_by( $column_name = '', $column_value = '' ) { + + // Default return value + $retval = false; + + // Bail if no key or value + if ( empty( $column_name ) || empty( $column_value ) ) { + return $retval; + } + + // Bail if name is not a string + if ( ! is_string( $column_name ) ) { + return $retval; + } + + // Bail if value is not scalar (null values also not allowed) + if ( ! is_scalar( $column_value ) ) { + return $retval; + } + + // Get all of the column names + $columns = $this->get_column_names(); + + // Bail if column does not exist + if ( ! isset( $columns[ $column_name ] ) ) { + return $retval; + } + + // Get all of the cache groups + $groups = $this->get_cache_groups(); + + // Check cache + if ( ! empty( $groups[ $column_name ] ) ) { + $retval = $this->cache_get( $column_value, $groups[ $column_name ] ); + } + + // Item not cached + if ( false === $retval ) { + + // Get item by column name & value (from database, not cache) + $retval = $this->get_item_raw( $column_name, $column_value ); + + // Bail on failure + if ( ! $this->is_success( $retval ) ) { + return false; + } + + // Update item cache(s) + $this->update_item_cache( $retval ); + } + + // Reduce the item + $retval = $this->reduce_item( 'select', $retval ); + + // Return result + return $this->shape_item( $retval ); + } + + /** + * Add an item to the database. + * + * @since 1.0.0 + * + * @param array $data + * @return bool + */ + public function add_item( $data = array() ) { + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // If data includes primary column, check if item already exists + if ( ! empty( $data[ $primary ] ) ) { + + // Shape the primary item ID + $item_id = $this->shape_item_id( $data[ $primary ] ); + + // Get item by ID (from database, not cache) + $item = $this->get_item_raw( $primary, $item_id ); + + // Bail if item already exists + if ( ! empty( $item ) ) { + return false; + } + + // Set data primary ID to newly shaped ID + $data[ $primary ] = $item_id; + } + + // Get default values for item (from columns) + $item = $this->default_item(); + + // Unset the primary key if not part of data array (auto-incremented) + if ( empty( $data[ $primary ] ) ) { + unset( $item[ $primary ] ); + } + + // Cut out non-keys for meta + $columns = $this->get_column_names(); + $data = array_merge( $item, $data ); + $meta = array_diff_key( $data, $columns ); + $save = array_intersect_key( $data, $columns ); + + // Bail if nothing to save + if ( empty( $save ) && empty( $meta ) ) { + return false; + } + + // Get the current time (maybe used by created/modified) + $time = $this->get_current_time(); + + // If date-created exists, but is empty or default, use the current time + $created = $this->get_column_by( array( 'created' => true ) ); + if ( ! empty( $created ) && ( empty( $save[ $created->name ] ) || ( $save[ $created->name ] === $created->default ) ) ) { + $save[ $created->name ] = $time; + } + + // If date-modified exists, but is empty or default, use the current time + $modified = $this->get_column_by( array( 'modified' => true ) ); + if ( ! empty( $modified ) && ( empty( $save[ $modified->name ] ) || ( $save[ $modified->name ] === $modified->default ) ) ) { + $save[ $modified->name ] = $time; + } + + // Try to add + $table = $this->get_table_name(); + $reduce = $this->reduce_item( 'insert', $save ); + $save = $this->validate_item( $reduce ); + $result = ! empty( $save ) + ? $this->get_db()->insert( $table, $save ) + : false; + + // Bail on failure + if ( ! $this->is_success( $result ) ) { + return false; + } + + // Get the new item ID + $item_id = $this->get_db()->insert_id; + + // Maybe save meta keys + if ( ! empty( $meta ) ) { + $this->save_extra_item_meta( $item_id, $meta ); + } + + // Update item cache(s) + $this->update_item_cache( $item_id ); + + // Transition item data + $this->transition_item( $save, array(), $item_id ); + + // Return result + return $item_id; + } + + /** + * Copy an item in the database to a new item. + * + * @since 1.1.0 + * + * @param int $item_id + * @param array $data + * @return bool + */ + public function copy_item( $item_id = 0, $data = array() ) { + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Get item by ID (from database, not cache) + $item = $this->get_item_raw( $primary, $item_id ); + + // Bail if item does not exist + if ( empty( $item ) ) { + return false; + } + + // Cast object to array + $save = (array) $item; + + // Maybe merge data with original item + if ( ! empty( $data ) && is_array( $data ) ) { + $save = array_merge( $save, $data ); + } + + // Unset the primary key + unset( $save[ $primary ] ); + + // Return result + return $this->add_item( $save ); + } + + /** + * Update an item in the database. + * + * @since 1.0.0 + * + * @param int $item_id + * @param array $data + * @return bool + */ + public function update_item( $item_id = 0, $data = array() ) { + + // Bail early if no data to update + if ( empty( $data ) ) { + return false; + } + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if no item ID + if ( empty( $item_id ) ) { + return false; + } + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Get item to update (from database, not cache) + $item = $this->get_item_raw( $primary, $item_id ); + + // Bail if item does not exist to update + if ( empty( $item ) ) { + return false; + } + + // Cast as an array for easier manipulation + $item = (array) $item; + + // Unset the primary key from item & data + unset( + $data[ $primary ], + $item[ $primary ] + ); + + // Slice data that has columns, and cut out non-keys for meta + $columns = $this->get_column_names(); + $data = array_diff_assoc( $data, $item ); + $meta = array_diff_key( $data, $columns ); + $save = array_intersect_key( $data, $columns ); + + // Maybe save meta keys + if ( ! empty( $meta ) ) { + $this->save_extra_item_meta( $item_id, $meta ); + } + + // Bail if nothing to save + if ( empty( $save ) ) { + return false; + } + + // If date-modified exists, use the current time + $modified = $this->get_column_by( array( 'modified' => true ) ); + if ( ! empty( $modified ) ) { + $save[ $modified->name ] = $this->get_current_time(); + } + + // Try to update + $table = $this->get_table_name(); + $reduce = $this->reduce_item( 'update', $save ); + $save = $this->validate_item( $reduce ); + $where = array( $primary => $item_id ); + $result = ! empty( $save ) + ? $this->get_db()->update( $table, $save, $where ) + : false; + + // Bail on failure + if ( ! $this->is_success( $result ) ) { + return false; + } + + // Update item cache(s) + $this->update_item_cache( $item_id ); + + // Transition item data + $this->transition_item( $save, $item, $item_id ); + + // Return result + return $result; + } + + /** + * Delete an item from the database. + * + * @since 1.0.0 + * + * @param int $item_id + * @return bool + */ + public function delete_item( $item_id = 0 ) { + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if no item ID + if ( empty( $item_id ) ) { + return false; + } + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Get item by ID (from database, not cache) + $item = $this->get_item_raw( $primary, $item_id ); + + // Bail if item does not exist to delete + if ( empty( $item ) ) { + return false; + } + + // Attempt to reduce this item + $item = $this->reduce_item( 'delete', $item ); + + // Bail if item was reduced to nothing + if ( empty( $item ) ) { + return false; + } + + // Try to delete + $table = $this->get_table_name(); + $where = array( $primary => $item_id ); + $result = $this->get_db()->delete( $table, $where ); + + // Bail on failure + if ( ! $this->is_success( $result ) ) { + return false; + } + + // Clean caches on successful delete + $this->delete_all_item_meta( $item_id ); + $this->clean_item_cache( $item ); + + // Return result + return $result; + } + + /** + * Filter an item before it is inserted of updated in the database. + * + * This method is public to allow subclasses to perform JIT manipulation + * of the parameters passed into it. + * + * @since 1.0.0 + * + * @param array $item + * @return array + */ + public function filter_item( $item = array() ) { + return (array) apply_filters_ref_array( $this->apply_prefix( "filter_{$this->item_name}_item" ), array( $item, &$this ) ); + } + + /** + * Shape an item from the database into the type of object it always wanted + * to be when it grew up. + * + * @since 1.0.0 + * + * @param mixed ID of item, or row from database + * @return mixed False on error, Object of single-object class type on success + */ + private function shape_item( $item = 0 ) { + + // Get the item from an ID + if ( is_numeric( $item ) ) { + $item = $this->get_item( $item ); + } + + // Return the item if it's already shaped + if ( $item instanceof $this->item_shape ) { + return $item; + } + + // Shape the item as needed + $item = ! empty( $this->item_shape ) + ? new $this->item_shape( $item ) + : (object) $item; + + // Return the item object + return $item; + } + + /** + * Validate an item before it is updated in or added to the database. + * + * @since 1.0.0 + * + * @param array $item + * @return array|false False on error, Array of validated values on success + */ + private function validate_item( $item = array() ) { + + // Bail if item is empty or not an array + if ( empty( $item ) || ! is_array( $item ) ) { + return $item; + } + + // Loop through item attributes + foreach ( $item as $key => $value ) { + + // Get the column + $column = $this->get_column_by( array( 'name' => $key ) ); + + // Null value is special for all item keys + if ( is_null( $value ) ) { + + // Bail if null is not allowed + if ( false === $column->allow_null ) { + return false; + } + + // Attempt to validate + } elseif ( ! empty( $column->validate ) && is_callable( $column->validate ) ) { + $validated = call_user_func( $column->validate, $value ); + + // Bail if error + if ( is_wp_error( $validated ) ) { + return false; + } + + // Update the value + $item[ $key ] = $validated; + + /** + * Fallback to using the raw value. + * + * Note: This may change at a later date, so do not rely on this. + * Please always validate all data. + */ + } else { + $item[ $key ] = $value; + } + } + + // Return the validated item + return $this->filter_item( $item ); + } + + /** + * Reduce an item down to the keys and values the current user has the + * appropriate capabilities to select|insert|update|delete. + * + * Note that internally, this method works with both arrays and objects of + * any type, and also resets the key values. It looks weird, but is + * currently by design to protect the integrity of the return value. + * + * @since 1.0.0 + * + * @param string $method select|insert|update|delete + * @param mixed $item Object|Array of keys/values to reduce + * + * @return mixed Object|Array without keys the current user does not have caps for + */ + private function reduce_item( $method = 'update', $item = array() ) { + + // Bail if item is empty + if ( empty( $item ) ) { + return $item; + } + + // Loop through item attributes + foreach ( $item as $key => $value ) { + + // Get capabilities for this column + $caps = $this->get_column_field( array( 'name' => $key ), 'caps' ); + + // Unset if not explicitly allowed + if ( empty( $caps[ $method ] ) || ! current_user_can( $caps[ $method ] ) ) { + if ( is_array( $item ) ) { + unset( $item[ $key ] ); + } elseif ( is_object( $item ) ) { + $item->{$key} = null; + } + + // Set if explicitly allowed + } elseif ( is_array( $item ) ) { + $item[ $key ] = $value; + } elseif ( is_object( $item ) ) { + $item->{$key} = $value; + } + } + + // Return the reduced item + return $item; + } + + /** + * Return an item comprised of all default values. + * + * This is used by `add_item()` to populate known default values, to ensure + * new item data is always what we expect it to be. + * + * @since 1.0.0 + * + * @return array + */ + private function default_item() { + + // Default return value + $retval = array(); + + // Get the column names and their defaults + $names = $this->get_columns( array(), 'and', 'name' ); + $defaults = $this->get_columns( array(), 'and', 'default' ); + + // Put together an item using default values + foreach ( $names as $key => $name ) { + $retval[ $name ] = $defaults[ $key ]; + } + + // Return + return $retval; + } + + /** + * Transition an item when adding or updating. + * + * This method takes the data being saved, looks for any columns that are + * known to transition between values, and fires actions on them. + * + * @since 1.0.0 + * + * @param array $new_data + * @param array $old_data + * @param int $item_id + * @return array + */ + private function transition_item( $new_data = array(), $old_data = array(), $item_id = 0 ) { + + // Look for transition columns + $columns = $this->get_columns( array( 'transition' => true ), 'and', 'name' ); + + // Bail if no columns to transition + if ( empty( $columns ) ) { + return; + } + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if no item ID + if ( empty( $item_id ) ) { + return; + } + + // If no old value(s), it's new + if ( empty( $old_data ) || ! is_array( $old_data ) ) { + $old_data = $new_data; + + // Set all old values to "new" + foreach ( $old_data as $key => $value ) { + $value = 'new'; + $old_data[ $key ] = $value; + } + } + + // Compare + $keys = array_flip( $columns ); + $new = array_intersect_key( $new_data, $keys ); + $old = array_intersect_key( $old_data, $keys ); + + // Get the difference + $diff = array_diff( $new, $old ); + + // Bail if nothing is changing + if ( empty( $diff ) ) { + return; + } + + // Do the actions + foreach ( $diff as $key => $value ) { + $old_value = $old_data[ $key ]; + $new_value = $new_data[ $key ]; + $key_action = $this->apply_prefix( "transition_{$this->item_name}_{$key}" ); + + /** + * Fires after an object value has transitioned. + * + * @since 1.0.0 + * + * @param mixed $old_value The value being transitioned FROM. + * @param mixed $new_value The value being transitioned TO. + * @param int $item_id The ID of the item that is transitioning. + */ + do_action( $key_action, $old_value, $new_value, $item_id ); + } + } + + /** Meta ******************************************************************/ + + /** + * Add meta data to an item. + * + * @since 1.0.0 + * + * @param int $item_id + * @param string $meta_key + * @param string $meta_value + * @param string $unique + * @return int|false The meta ID on success, false on failure. + */ + protected function add_item_meta( $item_id = 0, $meta_key = '', $meta_value = '', $unique = false ) { + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if no meta to add + if ( empty( $item_id ) || empty( $meta_key ) ) { + return false; + } + + // Bail if no meta table exists + if ( false === $this->get_meta_table_name() ) { + return false; + } + + // Get the meta type + $meta_type = $this->get_meta_type(); + + // Return results of adding meta data + return add_metadata( $meta_type, $item_id, $meta_key, $meta_value, $unique ); + } + + /** + * Get meta data for an item. + * + * @since 1.0.0 + * + * @param int $item_id + * @param string $meta_key + * @param bool $single + * @return mixed Single metadata value, or array of values + */ + protected function get_item_meta( $item_id = 0, $meta_key = '', $single = false ) { + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if no meta was returned + if ( empty( $item_id ) || empty( $meta_key ) ) { + return false; + } + + // Bail if no meta table exists + if ( false === $this->get_meta_table_name() ) { + return false; + } + + // Get the meta type + $meta_type = $this->get_meta_type(); + + // Return results of getting meta data + return get_metadata( $meta_type, $item_id, $meta_key, $single ); + } + + /** + * Update meta data for an item. + * + * @since 1.0.0 + * + * @param int $item_id + * @param string $meta_key + * @param string $meta_value + * @param string $prev_value + * @return bool True on successful update, false on failure. + */ + protected function update_item_meta( $item_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) { + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if no meta was returned + if ( empty( $item_id ) || empty( $meta_key ) ) { + return false; + } + + // Bail if no meta table exists + if ( false === $this->get_meta_table_name() ) { + return false; + } + + // Get the meta type + $meta_type = $this->get_meta_type(); + + // Return results of updating meta data + return update_metadata( $meta_type, $item_id, $meta_key, $meta_value, $prev_value ); + } + + /** + * Delete meta data for an item. + * + * @since 1.0.0 + * + * @param int $item_id + * @param string $meta_key + * @param string $meta_value + * @param string $delete_all + * @return bool True on successful delete, false on failure. + */ + protected function delete_item_meta( $item_id = 0, $meta_key = '', $meta_value = '', $delete_all = false ) { + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if no meta was returned + if ( empty( $item_id ) || empty( $meta_key ) ) { + return false; + } + + // Bail if no meta table exists + if ( false === $this->get_meta_table_name() ) { + return false; + } + + // Get the meta type + $meta_type = $this->get_meta_type(); + + // Return results of deleting meta data + return delete_metadata( $meta_type, $item_id, $meta_key, $meta_value, $delete_all ); + } + + /** + * Get registered meta data keys. + * + * @since 1.0.0 + * + * @param string $object_subtype The sub-type of meta keys + * + * @return array + */ + private function get_registered_meta_keys( $object_subtype = '' ) { + + // Get the object type + $object_type = $this->get_meta_type(); + + // Return the keys + return get_registered_meta_keys( $object_type, $object_subtype ); + } + + /** + * Maybe update meta values on item update/save. + * + * @since 1.0.0 + * + * @param array $meta + */ + private function save_extra_item_meta( $item_id = 0, $meta = array() ) { + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if there is no bulk meta to save + if ( empty( $item_id ) || empty( $meta ) ) { + return; + } + + // Bail if no meta table exists + if ( false === $this->get_meta_table_name() ) { + return; + } + + // Only save registered keys + $keys = $this->get_registered_meta_keys(); + $meta = array_intersect_key( $meta, $keys ); + + // Bail if no registered meta keys + if ( empty( $meta ) ) { + return; + } + + // Save or delete meta data + foreach ( $meta as $key => $value ) { + ! empty( $value ) + ? $this->update_item_meta( $item_id, $key, $value ) + : $this->delete_item_meta( $item_id, $key ); + } + } + + /** + * Delete all meta data for an item. + * + * @since 1.0.0 + * + * @param int $item_id + */ + private function delete_all_item_meta( $item_id = 0 ) { + + // Shape the item ID + $item_id = $this->shape_item_id( $item_id ); + + // Bail if no item ID + if ( empty( $item_id ) ) { + return; + } + + // Get the meta table name + $table = $this->get_meta_table_name(); + + // Bail if no meta table exists + if ( empty( $table ) ) { + return; + } + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Guess the item ID column for the meta table + $item_id_column = $this->apply_prefix( "{$this->item_name}_{$primary}" ); + + // Get meta IDs + $query = "SELECT meta_id FROM {$table} WHERE {$item_id_column} = %d"; + $prepared = $this->get_db()->prepare( $query, $item_id ); + $meta_ids = $this->get_db()->get_col( $prepared ); + + // Bail if no meta IDs to delete + if ( empty( $meta_ids ) ) { + return; + } + + // Get the meta type + $meta_type = $this->get_meta_type(); + + // Delete all meta data for this item ID + foreach ( $meta_ids as $mid ) { + delete_metadata_by_mid( $meta_type, $mid ); + } + } + + /** + * Get the meta table for this query. + * + * Forked from WordPress\_get_meta_table() so it can be more accurately + * predicted in a future iteration and default to returning false. + * + * @since 1.0.0 + * + * @return mixed Table name if exists, False if not + */ + private function get_meta_table_name() { + + // Get the meta-type + $type = $this->get_meta_type(); + + // Append "meta" to end of meta-type + $table_name = "{$type}meta"; + + // Variable'ize the database interface, to use inside empty() + $db = $this->get_db(); + + // If not empty, return table name + if ( ! empty( $db->{$table_name} ) ) { + return $db->{$table_name}; + } + + // Default return false + return false; + } + + /** + * Get the meta type for this query. + * + * This method exists to reduce some duplication for now. Future iterations + * will likely use Column::relationships to + * + * @since 1.1.0 + * + * @return string + */ + private function get_meta_type() { + return $this->apply_prefix( $this->item_name ); + } + + /** Cache *****************************************************************/ + + /** + * Get cache key from query_vars and query_var_defaults. + * + * @since 1.0.0 + * + * @return string + */ + private function get_cache_key( $group = '' ) { + + // Slice query vars + $slice = wp_array_slice_assoc( $this->query_vars, array_keys( $this->query_var_defaults ) ); + + // Unset `fields` so it does not effect the cache key + unset( $slice['fields'] ); + + // Setup key & last_changed + $key = md5( serialize( $slice ) ); + $last_changed = $this->get_last_changed_cache( $group ); + + // Concatenate and return cache key + return "get_{$this->item_name_plural}:{$key}:{$last_changed}"; + } + + /** + * Get the cache group, or fallback to the primary one. + * + * @since 1.0.0 + * + * @param string $group + * @return string + */ + private function get_cache_group( $group = '' ) { + + // Get the primary column + $primary = $this->get_primary_column_name(); + + // Default return value + $retval = $this->cache_group; + + // Only allow non-primary groups + if ( ! empty( $group ) && ( $group !== $primary ) ) { + $retval = $group; + } + + // Return the group + return $retval; + } + + /** + * Get array of which database columns have uniquely cached groups. + * + * @since 1.0.0 + * + * @return array + */ + private function get_cache_groups() { + + // Return value + $cache_groups = array(); + + // Get the cache groups + $groups = $this->get_columns( array( 'cache_key' => true ), 'and', 'name' ); + + if ( ! empty( $groups ) ) { + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Setup return values + foreach ( $groups as $name ) { + if ( $primary !== $name ) { + $cache_groups[ $name ] = "{$this->cache_group}-by-{$name}"; + } else { + $cache_groups[ $name ] = $this->cache_group; + } + } + } + + // Return cache groups array + return $cache_groups; + } + + /** + * Maybe prime item & item-meta caches by querying 1 time for all un-cached + * items. + * + * Accepts a single ID, or an array of IDs. + * + * The reason this accepts only IDs is because it gets called immediately + * after an item is inserted in the database, but before items have been + * "shaped" into proper objects, so object properties may not be set yet. + * + * @since 1.0.0 + * + * @param array $item_ids + * @param bool $force + * + * @return bool False if empty + */ + private function prime_item_caches( $item_ids = array(), $force = false ) { + + // Bail if no items to cache + if ( empty( $item_ids ) ) { + return false; + } + + // Accepts single values, so cast to array + $item_ids = (array) $item_ids; + + // Update item caches + if ( ! empty( $force ) || ! empty( $this->query_vars['update_item_cache'] ) ) { + + // Look for non-cached IDs + $ids = $this->get_non_cached_ids( $item_ids, $this->cache_group ); + + // Bail if IDs are cached + if ( empty( $ids ) ) { + return false; + } + + // Get query parts + $table = $this->get_table_name(); + $primary = $this->get_primary_column_name(); + + // Query database + $query = "SELECT * FROM {$table} WHERE {$primary} IN (%s)"; + $ids = implode( ',', array_map( 'absint', $ids ) ); + $prepare = sprintf( $query, $ids ); + $results = $this->get_db()->get_results( $prepare ); + + // Update item cache(s) + $this->update_item_cache( $results ); + } + + // Update meta data caches + if ( ! empty( $this->query_vars['update_meta_cache'] ) ) { + $singular = rtrim( $this->table_name, 's' ); // sic + update_meta_cache( $singular, $item_ids ); + } + } + + /** + * Update the cache for an item. Does not update item-meta cache. + * + * Accepts a single object, or an array of objects. + * + * The reason this does not accept ID's is because this gets called + * after an item is already updated in the database, so we want to avoid + * querying for it again. It's just safer this way. + * + * @since 1.0.0 + * + * @param array $items + */ + private function update_item_cache( $items = array() ) { + + // Maybe query for single item + if ( is_numeric( $items ) ) { + + // Get the primary column name + $primary = $this->get_primary_column_name(); + + // Get item by ID (from database, not cache) + $items = $this->get_item_raw( $primary, $items ); + } + + // Bail if no items to cache + if ( empty( $items ) ) { + return false; + } + + // Make sure items are an array (without casting objects to arrays) + if ( ! is_array( $items ) ) { + $items = array( $items ); + } + + // Get the cache groups + $groups = $this->get_cache_groups(); + + // Loop through all items and cache them + foreach ( $items as $item ) { + + // Skip if item is not an object + if ( ! is_object( $item ) ) { + continue; + } + + // Loop through groups and set cache + if ( ! empty( $groups ) ) { + foreach ( $groups as $key => $group ) { + $this->cache_set( $item->{$key}, $item, $group ); + } + } + } + + // Update last changed + $this->update_last_changed_cache(); + } + + /** + * Clean the cache for an item. Does not clean item-meta. + * + * Accepts a single object, or an array of objects. + * + * The reason this does not accept ID's is because this gets called + * after an item is already deleted from the database, so it cannot be + * queried and may not exist in the cache. It's just safer this way. + * + * @since 1.0.0 + * + * @param mixed $items Single object item, or Array of object items + * + * @return bool + */ + private function clean_item_cache( $items = array() ) { + + // Bail if no items to clean + if ( empty( $items ) ) { + return false; + } + + // Make sure items are an array + if ( ! is_array( $items ) ) { + $items = array( $items ); + } + + // Get the cache groups + $groups = $this->get_cache_groups(); + + // Loop through all items and clean them + foreach ( $items as $item ) { + + // Skip if item is not an object + if ( ! is_object( $item ) ) { + continue; + } + + // Loop through groups and delete cache + if ( ! empty( $groups ) ) { + foreach ( $groups as $key => $group ) { + $this->cache_delete( $item->{$key}, $group ); + } + } + } + + // Update last changed + $this->update_last_changed_cache(); + } + + /** + * Update the last_changed key for the cache group. + * + * @since 1.0.0 + * + * @return string The last time a cache group was changed. + */ + private function update_last_changed_cache( $group = '' ) { + + // Fallback to microtime + if ( empty( $this->last_changed ) ) { + $this->set_last_changed(); + } + + // Set the last changed time for this cache group + $this->cache_set( 'last_changed', $this->last_changed, $group ); + + // Return the last changed time + return $this->last_changed; + } + + /** + * Get the last_changed key for a cache group. + * + * @since 1.0.0 + * + * @param string $group Cache group. Defaults to $this->cache_group + * + * @return string The last time a cache group was changed. + */ + private function get_last_changed_cache( $group = '' ) { + + // Get the last changed cache value + $last_changed = $this->cache_get( 'last_changed', $group ); + + // Maybe update the last changed value + if ( false === $last_changed ) { + $last_changed = $this->update_last_changed_cache( $group ); + } + + // Return the last changed value for the cache group + return $last_changed; + } + + /** + * Get array of non-cached item IDs. + * + * @since 1.0.0 + * + * @param array $item_ids Array of item IDs + * @param string $group Cache group. Defaults to $this->cache_group + * + * @return array + */ + private function get_non_cached_ids( $item_ids = array(), $group = '' ) { + + // Default return value + $retval = array(); + + // Bail if no item IDs + if ( empty( $item_ids ) ) { + return $retval; + } + + // Loop through item IDs + foreach ( $item_ids as $id ) { + + // Shape the item ID + $id = $this->shape_item_id( $id ); + + // Add to return value if not cached + if ( false === $this->cache_get( $id, $group ) ) { + $retval[] = $id; + } + } + + // Return array of IDs + return $retval; + } + + /** + * Add a cache value for a key and group. + * + * @since 1.0.0 + * + * @param string $key Cache key. + * @param mixed $value Cache value. + * @param string $group Cache group. Defaults to $this->cache_group + * @param int $expire Expiration. + */ + private function cache_add( $key = '', $value = '', $group = '', $expire = 0 ) { + + // Bail if cache invalidation is suspended + if ( wp_suspend_cache_addition() ) { + return; + } + + // Bail if no cache key + if ( empty( $key ) ) { + return; + } + + // Get the cache group + $group = $this->get_cache_group( $group ); + + // Add to the cache + wp_cache_add( $key, $value, $group, $expire ); + } + + /** + * Get a cache value for a key and group. + * + * @since 1.0.0 + * + * @param string $key Cache key. + * @param string $group Cache group. Defaults to $this->cache_group + * @param bool $force + */ + private function cache_get( $key = '', $group = '', $force = false ) { + + // Bail if no cache key + if ( empty( $key ) ) { + return; + } + + // Get the cache group + $group = $this->get_cache_group( $group ); + + // Return from the cache + return wp_cache_get( $key, $group, $force ); + } + + /** + * Set a cache value for a key and group. + * + * @since 1.0.0 + * + * @param string $key Cache key. + * @param mixed $value Cache value. + * @param string $group Cache group. Defaults to $this->cache_group + * @param int $expire Expiration. + */ + private function cache_set( $key = '', $value = '', $group = '', $expire = 0 ) { + + // Bail if cache invalidation is suspended + if ( wp_suspend_cache_addition() ) { + return; + } + + // Bail if no cache key + if ( empty( $key ) ) { + return; + } + + // Get the cache group + $group = $this->get_cache_group( $group ); + + // Update the cache + wp_cache_set( $key, $value, $group, $expire ); + } + + /** + * Delete a cache key for a group. + * + * @since 1.0.0 + * + * @global bool $_wp_suspend_cache_invalidation + * + * @param string $key Cache key. + * @param string $group Cache group. Defaults to $this->cache_group + */ + private function cache_delete( $key = '', $group = '' ) { + global $_wp_suspend_cache_invalidation; + + // Bail if cache invalidation is suspended + if ( ! empty( $_wp_suspend_cache_invalidation ) ) { + return; + } + + // Bail if no cache key + if ( empty( $key ) ) { + return; + } + + // Get the cache group + $group = $this->get_cache_group( $group ); + + // Delete the cache + wp_cache_delete( $key, $group ); + } + + /** + * Fetch raw results directly from the database. + * + * @since 1.0.0 + * + * @param array $cols Columns for `SELECT`. + * @param array $where_cols Where clauses. Each key-value pair in the array + * represents a column and a comparison. + * @param int $limit Optional. LIMIT value. Default 25. + * @param null $offset Optional. OFFSET value. Default null. + * @param string $output Optional. Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants. + * Default OBJECT. + * With one of the first three, return an array of + * rows indexed from 0 by SQL result row number. + * Each row is an associative array (column => value, ...), + * a numerically indexed array (0 => value, ...), + * or an object. ( ->column = value ), respectively. + * With OBJECT_K, return an associative array of + * row objects keyed by the value of each row's + * first column's value. + * + * @return array|object|null Database query results. + */ + public function get_results( $cols = array(), $where_cols = array(), $limit = 25, $offset = null, $output = OBJECT ) { + + // Bail if no columns have been passed + if ( empty( $cols ) ) { + return null; + } + + // Fetch all the columns for the table being queried + $column_names = $this->get_column_names(); + + // Ensure valid column names have been passed for the `SELECT` clause + foreach ( $cols as $index => $column ) { + if ( ! array_key_exists( $column, $column_names ) ) { + unset( $cols[ $index ] ); + } + } + + // Columns to retrieve + $columns = implode( ',', $cols ); + + // Get the table name + $table = $this->get_table_name(); + + // Setup base query + $query = implode( ' ', array( + "SELECT", + $columns, + "FROM {$table} {$this->table_alias}", + "WHERE 1=1" + ) ); + + // Ensure valid columns have been passed for the `WHERE` clause + if ( ! empty( $where_cols ) ) { + + // Get keys from where columns + $columns = array_keys( $where_cols ); + + // Loop through columns and unset any invalid names + foreach ( $columns as $index => $column ) { + if ( ! array_key_exists( $column, $column_names ) ) { + unset( $where_cols[ $index ] ); + } + } + + // Parse WHERE clauses + foreach ( $where_cols as $column => $compare ) { + + // Basic WHERE clause + if ( ! is_array( $compare ) ) { + $pattern = $this->get_column_field( array( 'name' => $column ), 'pattern', '%s' ); + $statement = " AND {$this->table_alias}.{$column} = {$pattern} "; + $query .= $this->get_db()->prepare( $statement, $compare ); + + // More complex WHERE clause + } else { + $value = isset( $compare['value'] ) + ? $compare['value'] + : false; + + // Skip if a value was not provided + if ( false === $value ) { + continue; + } + + // Default compare clause to equals + $compare_clause = isset( $compare['compare_query'] ) + ? trim( strtoupper( $compare['compare_query'] ) ) + : '='; + + // Array (unprepared) + if ( is_array( $compare['value'] ) ) { + + // Default to IN if clause not specified + if ( ! in_array( $compare_clause, array( 'IN', 'NOT IN', 'BETWEEN' ), true ) ) { + $compare_clause = 'IN'; + } + + // Parse & escape for IN and NOT IN + if ( 'IN' === $compare_clause || 'NOT IN' === $compare_clause ) { + $value = "('" . implode( "','", $this->get_db()->_escape( $compare['value'] ) ) . "')"; + + // Parse & escape for BETWEEN + } elseif ( is_array( $value ) && 2 === count( $value ) && 'BETWEEN' === $compare_clause ) { + $_this = $this->get_db()->_escape( $value[0] ); + $_that = $this->get_db()->_escape( $value[1] ); + $value = " {$_this} AND {$_that} "; + } + } + + // Add WHERE clause + $query .= " AND {$this->table_alias}.{$column} {$compare_clause} {$value} "; + } + } + } + + // Maybe set an offset + if ( ! empty( $offset ) ) { + $values = explode( ',', $offset ); + $values = array_filter( $values, 'intval' ); + $offset = implode( ',', $values ); + $query .= " OFFSET {$offset} "; + } + + // Maybe set a limit + if ( ! empty( $limit ) && ( $limit > 0 ) ) { + $limit = intval( $limit ); + $query .= " LIMIT {$limit} "; + } + + // Execute query + $results = $this->get_db()->get_results( $query, $output ); + + // Return results + return $results; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Row.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Row.php new file mode 100644 index 000000000..1614d6bb0 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Row.php @@ -0,0 +1,65 @@ +init( $item ); + } + } + + /** + * Initialize class properties based on data array. + * + * @since 1.0.0 + * + * @param array $data + */ + private function init( $data = array() ) { + $this->set_vars( $data ); + } + + /** + * Determines whether the current row exists. + * + * @since 1.0.0 + * + * @return bool + */ + public function exists() { + return ! empty( $this->id ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Schema.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Schema.php new file mode 100644 index 000000000..a7ed3e36e --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Schema.php @@ -0,0 +1,88 @@ +columns ) || ! is_array( $this->columns ) ) { + return; + } + + // Juggle original columns array + $columns = $this->columns; + $this->columns = array(); + + // Loop through columns and create objects from them + foreach ( $columns as $column ) { + if ( is_array( $column ) ) { + $this->columns[] = new Column( $column ); + } elseif ( $column instanceof Column ) { + $this->columns[] = $column; + } + } + } + + /** + * Return the schema in string form. + * + * @since 1.0.0 + * + * @return string Calls get_create_string() on every column. + */ + protected function to_string() { + + // Default return value + $retval = ''; + + // Bail if no columns to convert + if ( empty( $this->columns ) ) { + return $retval; + } + + // Loop through columns... + foreach ( $this->columns as $column_info ) { + if ( method_exists( $column_info, 'get_create_string' ) ) { + $retval .= '\n' . $column_info->get_create_string() . ', '; + } + } + + // Return the string + return $retval; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Table.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Table.php new file mode 100644 index 000000000..e85054e06 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Database/Table.php @@ -0,0 +1,998 @@ + value array of versions => methods. + * + * @since 1.0.0 + * @var array + */ + protected $upgrades = array(); + + /** Methods ***************************************************************/ + + /** + * Hook into queries, admin screens, and more! + * + * @since 1.0.0 + */ + public function __construct() { + + // Setup the database table + $this->setup(); + + // Bail if setup failed + if ( empty( $this->name ) || empty( $this->db_version_key ) ) { + return; + } + + // Add the table to the database interface + $this->set_db_interface(); + + // Set the database schema + $this->set_schema(); + + // Add hooks + $this->add_hooks(); + + // Maybe force upgrade if testing + if ( $this->is_testing() ) { + $this->maybe_upgrade(); + } + } + + /** + * Compatibility for clone() method for PHP versions less than 7.0. + * + * See: https://github.com/sugarcalendar/core/issues/105 + * + * This shim will be removed at a later date. + * + * @since 2.0.20 + * + * @param string $function + * @param array $args + */ + public function __call( $function = '', $args = array() ) { + if ( 'clone' === $function ) { + call_user_func_array( array( $this, '_clone' ), $args ); + } + } + + /** Abstract **************************************************************/ + + /** + * Setup this database table. + * + * @since 1.0.0 + */ + protected abstract function set_schema(); + + /** Multisite *************************************************************/ + + /** + * Update table version & references. + * + * Hooked to the "switch_blog" action. + * + * @since 1.0.0 + * + * @param int $site_id The site being switched to + */ + public function switch_blog( $site_id = 0 ) { + + // Update DB version based on the current site + if ( ! $this->is_global() ) { + $this->db_version = get_blog_option( $site_id, $this->db_version_key, false ); + } + + // Update interface for switched site + $this->set_db_interface(); + } + + /** Public Helpers ********************************************************/ + + /** + * Maybe upgrade the database table. Handles creation & schema changes. + * + * Hooked to the `admin_init` action. + * + * @since 1.0.0 + */ + public function maybe_upgrade() { + + // Bail if not upgradeable + if ( ! $this->is_upgradeable() ) { + return; + } + + // Bail if upgrade not needed + if ( ! $this->needs_upgrade() ) { + return; + } + + // Upgrade + if ( $this->exists() ) { + $this->upgrade(); + + // Install + } else { + $this->install(); + } + } + + /** + * Return whether this table needs an upgrade. + * + * @since 1.0.0 + * + * @param mixed $version Database version to check if upgrade is needed + * + * @return bool True if table needs upgrading. False if not. + */ + public function needs_upgrade( $version = false ) { + + // Use the current table version if none was passed + if ( empty( $version ) ) { + $version = $this->version; + } + + // Get the current database version + $this->get_db_version(); + + // Is the database table up to date? + $is_current = version_compare( $this->db_version, $version, '>=' ); + + // Return false if current, true if out of date + return ( true === $is_current ) + ? false + : true; + } + + /** + * Return whether this table can be upgraded. + * + * @since 1.0.0 + * + * @return bool True if table can be upgraded. False if not. + */ + public function is_upgradeable() { + + // Bail if global and upgrading global tables is not allowed + if ( $this->is_global() && ! wp_should_upgrade_global_tables() ) { + return false; + } + + // Kinda weird, but assume it is + return true; + } + + /** + * Return the current table version from the database. + * + * This is public method for accessing a private variable so that it cannot + * be externally modified. + * + * @since 1.0.0 + * + * @return string + */ + public function get_version() { + $this->get_db_version(); + + return $this->db_version; + } + + /** + * Install a database table + * + * Creates the table and sets the version information if successful. + * + * @since 1.0.0 + */ + public function install() { + + // Try to create the table + $created = $this->create(); + + // Set the DB version if create was successful + if ( true === $created ) { + $this->set_db_version(); + } + } + + /** + * Uninstall a database table + * + * Drops the table and deletes the version information if successful and/or + * the table does not exist anymore. + * + * @since 1.0.0 + */ + public function uninstall() { + + // Try to drop the table + $dropped = $this->drop(); + + // Delete the DB version if drop was successful or table does not exist + if ( ( true === $dropped ) || ! $this->exists() ) { + $this->delete_db_version(); + } + } + + /** Public Management *****************************************************/ + + /** + * Check if table already exists. + * + * @since 1.0.0 + * + * @return bool + */ + public function exists() { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Query statement + $query = "SHOW TABLES LIKE %s"; + $like = $db->esc_like( $this->table_name ); + $prepared = $db->prepare( $query, $like ); + $result = $db->get_var( $prepared ); + + // Does the table exist? + return $this->is_success( $result ); + } + + /** + * Get columns from table. + * + * @since 1.2.0 + * + * @return array + */ + public function columns() { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Query statement + $query = "SHOW FULL COLUMNS FROM {$this->table_name}"; + $result = $db->get_results( $query ); + + // Return the results + return $this->is_success( $result ) + ? $result + : false; + } + + /** + * Create the table. + * + * @since 1.0.0 + * + * @return bool + */ + public function create() { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Query statement + $query = "CREATE TABLE {$this->table_name} ( {$this->schema} ) {$this->charset_collation}"; + $result = $db->query( $query ); + + // Was the table created? + return $this->is_success( $result ); + } + + /** + * Drop the database table. + * + * @since 1.0.0 + * + * @return bool + */ + public function drop() { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Query statement + $query = "DROP TABLE {$this->table_name}"; + $result = $db->query( $query ); + + // Did the table get dropped? + return $this->is_success( $result ); + } + + /** + * Truncate the database table. + * + * @since 1.0.0 + * + * @return bool + */ + public function truncate() { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Query statement + $query = "TRUNCATE TABLE {$this->table_name}"; + $result = $db->query( $query ); + + // Did the table get truncated? + return $this->is_success( $result ); + } + + /** + * Delete all items from the database table. + * + * @since 1.0.0 + * + * @return bool + */ + public function delete_all() { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Query statement + $query = "DELETE FROM {$this->table_name}"; + $result = $db->query( $query ); + + // Return the results + return $result; + } + + /** + * Clone this database table. + * + * Pair with copy(). + * + * @since 1.1.0 + * + * @param string $new_table_name The name of the new table, without prefix + * + * @return bool + */ + public function _clone( $new_table_name = '' ) { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Sanitize the new table name + $table_name = $this->sanitize_table_name( $new_table_name ); + + // Bail if new table name is invalid + if ( empty( $table_name ) ) { + return false; + } + + // Query statement + $table = $this->apply_prefix( $table_name ); + $query = "CREATE TABLE {$table} LIKE {$this->table_name}"; + $result = $db->query( $query ); + + // Did the table get cloned? + return $this->is_success( $result ); + } + + /** + * Copy the contents of this table to a new table. + * + * Pair with clone(). + * + * @since 1.1.0 + * + * @param string $new_table_name The name of the new table, without prefix + * + * @return bool + */ + public function copy( $new_table_name = '' ) { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Sanitize the new table name + $table_name = $this->sanitize_table_name( $new_table_name ); + + // Bail if new table name is invalid + if ( empty( $table_name ) ) { + return false; + } + + // Query statement + $table = $this->apply_prefix( $table_name ); + $query = "INSERT INTO {$table} SELECT * FROM {$this->table_name}"; + $result = $db->query( $query ); + + // Did the table get copied? + return $this->is_success( $result ); + } + + /** + * Count the number of items in the database table. + * + * @since 1.0.0 + * + * @return int + */ + public function count() { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return 0; + } + + // Query statement + $query = "SELECT COUNT(*) FROM {$this->table_name}"; + $result = $db->get_var( $query ); + + // Query success/fail + return intval( $result ); + } + + /** + * Check if column already exists. + * + * @since 1.0.0 + * + * @param string $name Value + * + * @return bool + */ + public function column_exists( $name = '' ) { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Query statement + $query = "SHOW COLUMNS FROM {$this->table_name} LIKE %s"; + $like = $db->esc_like( $name ); + $prepared = $db->prepare( $query, $like ); + $result = $db->query( $prepared ); + + // Does the column exist? + return $this->is_success( $result ); + } + + /** + * Check if index already exists. + * + * @since 1.0.0 + * + * @param string $name Value + * @param string $column Column name + * + * @return bool + */ + public function index_exists( $name = '', $column = 'Key_name' ) { + + // Get the database interface + $db = $this->get_db(); + + // Bail if no database interface is available + if ( empty( $db ) ) { + return false; + } + + // Limit $column to Key or Column name, until we can do better + if ( ! in_array( $column, array( 'Key_name', 'Column_name' ), true ) ) { + $column = 'Key_name'; + } + + // Query statement + $query = "SHOW INDEXES FROM {$this->table_name} WHERE {$column} LIKE %s"; + $like = $db->esc_like( $name ); + $prepared = $db->prepare( $query, $like ); + $result = $db->query( $prepared ); + + // Does the index exist? + return $this->is_success( $result ); + } + + /** Upgrades **************************************************************/ + + /** + * Upgrade this database table. + * + * @since 1.0.0 + * + * @return bool + */ + public function upgrade() { + + // Get pending upgrades + $upgrades = $this->get_pending_upgrades(); + + // Bail if no upgrades + if ( empty( $upgrades ) ) { + $this->set_db_version(); + + // Return, without failure + return true; + } + + // Default result + $result = false; + + // Try to do the upgrades + foreach ( $upgrades as $version => $callback ) { + + // Do the upgrade + $result = $this->upgrade_to( $version, $callback ); + + // Bail if an error occurs, to avoid skipping upgrades + if ( ! $this->is_success( $result ) ) { + return false; + } + } + + // Success/fail + return $this->is_success( $result ); + } + + /** + * Return array of upgrades that still need to run. + * + * @since 1.1.0 + * + * @return array Array of upgrade callbacks, keyed by their db version. + */ + public function get_pending_upgrades() { + + // Default return value + $upgrades = array(); + + // Bail if no upgrades, or no database version to compare to + if ( empty( $this->upgrades ) || empty( $this->db_version ) ) { + return $upgrades; + } + + // Loop through all upgrades, and pick out the ones that need doing + foreach ( $this->upgrades as $version => $callback ) { + if ( true === version_compare( $version, $this->db_version, '>' ) ) { + $upgrades[ $version ] = $callback; + } + } + + // Return + return $upgrades; + } + + /** + * Upgrade to a specific database version. + * + * @since 1.0.0 + * + * @param mixed $version Database version to check if upgrade is needed + * @param string $callback Callback function or class method to call + * + * @return bool + */ + public function upgrade_to( $version = '', $callback = '' ) { + + // Bail if no upgrade is needed + if ( ! $this->needs_upgrade( $version ) ) { + return false; + } + + // Allow self-named upgrade callbacks + if ( empty( $callback ) ) { + $callback = $version; + } + + // Is the callback... callable? + $callable = $this->get_callable( $callback ); + + // Bail if no callable upgrade was found + if ( empty( $callable ) ) { + return false; + } + + // Do the upgrade + $result = call_user_func( $callable ); + $success = $this->is_success( $result ); + + // Bail if upgrade failed + if ( true !== $success ) { + return false; + } + + // Set the database version to this successful version + $this->set_db_version( $version ); + + // Return success + return true; + } + + /** Private ***************************************************************/ + + /** + * Setup the necessary table variables. + * + * @since 1.0.0 + */ + private function setup() { + + // Bail if no database interface is available + if ( ! $this->get_db() ) { + return; + } + + // Sanitize the database table name + $this->name = $this->sanitize_table_name( $this->name ); + + // Bail if database table name was garbage + if ( false === $this->name ) { + return; + } + + // Separator + $glue = '_'; + + // Setup the prefixed name + $this->prefixed_name = $this->apply_prefix( $this->name, $glue ); + + // Maybe create database key + if ( empty( $this->db_version_key ) ) { + $this->db_version_key = implode( + $glue, + array( + sanitize_key( $this->db_global ), + $this->prefixed_name, + 'version' + ) + ); + } + } + + /** + * Set this table up in the database interface. + * + * This must be done directly because the database interface does not + * have a common mechanism for manipulating them safely. + * + * @since 1.0.0 + */ + private function set_db_interface() { + + // Get the database once, to avoid duplicate function calls + $db = $this->get_db(); + + // Bail if no database + if ( empty( $db ) ) { + return; + } + + // Set variables for global tables + if ( $this->is_global() ) { + $site_id = 0; + $tables = 'ms_global_tables'; + + // Set variables for per-site tables + } else { + $site_id = null; + $tables = 'tables'; + } + + // Set the table prefix and prefix the table name + $this->table_prefix = $db->get_blog_prefix( $site_id ); + + // Get the prefixed table name + $prefixed_table_name = "{$this->table_prefix}{$this->prefixed_name}"; + + // Set the database interface + $db->{$this->prefixed_name} = $this->table_name = $prefixed_table_name; + + // Create the array if it does not exist + if ( ! isset( $db->{$tables} ) ) { + $db->{$tables} = array(); + } + + // Add the table to the global table array + $db->{$tables}[] = $this->prefixed_name; + + // Charset + if ( ! empty( $db->charset ) ) { + $this->charset_collation = "DEFAULT CHARACTER SET {$db->charset}"; + } + + // Collation + if ( ! empty( $db->collate ) ) { + $this->charset_collation .= " COLLATE {$db->collate}"; + } + } + + /** + * Set the database version for the table. + * + * @since 1.0.0 + * + * @param mixed $version Database version to set when upgrading/creating + */ + private function set_db_version( $version = '' ) { + + // If no version is passed during an upgrade, use the current version + if ( empty( $version ) ) { + $version = $this->version; + } + + // Update the DB version + $this->is_global() + ? update_network_option( get_main_network_id(), $this->db_version_key, $version ) + : update_option( $this->db_version_key, $version ); + + // Set the DB version + $this->db_version = $version; + } + + /** + * Get the table version from the database. + * + * @since 1.0.0 + */ + private function get_db_version() { + $this->db_version = $this->is_global() + ? get_network_option( get_main_network_id(), $this->db_version_key, false ) + : get_option( $this->db_version_key, false ); + } + + /** + * Delete the table version from the database. + * + * @since 1.0.0 + */ + private function delete_db_version() { + $this->db_version = $this->is_global() + ? delete_network_option( get_main_network_id(), $this->db_version_key ) + : delete_option( $this->db_version_key ); + } + + /** + * Add class hooks to the parent application actions. + * + * @since 1.0.0 + */ + private function add_hooks() { + + // Add table to the global database object + add_action( 'switch_blog', array( $this, 'switch_blog' ) ); + add_action( 'admin_init', array( $this, 'maybe_upgrade' ) ); + } + + /** + * Check if the current request is from some kind of test. + * + * This is primarily used to skip 'admin_init' and force-install tables. + * + * @since 1.0.0 + * + * @return bool + */ + private function is_testing() { + return (bool) + + // Tests constant is being used + ( defined( 'WP_TESTS_DIR' ) && WP_TESTS_DIR ) + + || + + // Scaffolded (https://make.wordpress.org/cli/handbook/plugin-unit-tests/) + function_exists( '_manually_load_plugin' ); + } + + /** + * Check if table is global. + * + * @since 1.0.0 + * + * @return bool + */ + private function is_global() { + return ( true === $this->global ); + } + + /** + * Try to get a callable upgrade, with some magic to avoid needing to + * do this dance repeatedly inside subclasses. + * + * @since 1.0.0 + * + * @param string $callback + * + * @return mixed Callable string, or false if not callable + */ + private function get_callable( $callback = '' ) { + + // Default return value + $callable = $callback; + + // Look for global function + if ( ! is_callable( $callable ) ) { + + // Fallback to local class method + $callable = array( $this, $callback ); + if ( ! is_callable( $callable ) ) { + + // Fallback to class method prefixed with "__" + $callable = array( $this, "__{$callback}" ); + if ( ! is_callable( $callable ) ) { + $callable = false; + } + } + } + + // Return callable string, or false if not callable + return $callable; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ArgumentInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ArgumentInterface.php new file mode 100644 index 000000000..ec18821f1 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ArgumentInterface.php @@ -0,0 +1,13 @@ +getContainer(); + } catch (ContainerException $e) { + $container = ($this instanceof ReflectionContainer) ? $this : null; + } + + foreach ($arguments as &$arg) { + // if we have a literal, we don't want to do anything more with it + if ($arg instanceof LiteralArgumentInterface) { + $arg = $arg->getValue(); + continue; + } + + if ($arg instanceof ArgumentInterface) { + $argValue = $arg->getValue(); + } else { + $argValue = $arg; + } + + if (!is_string($argValue)) { + continue; + } + + // resolve the argument from the container, if it happens to be another + // argument wrapper, use that value + if ($container instanceof ContainerInterface && $container->has($argValue)) { + try { + $arg = $container->get($argValue); + + if ($arg instanceof ArgumentInterface) { + $arg = $arg->getValue(); + } + + continue; + } catch (NotFoundException $e) { + } + } + + // if we have a default value, we use that, no more resolution as + // we expect a default/optional argument value to be literal + if ($arg instanceof DefaultValueInterface) { + $arg = $arg->getDefaultValue(); + } + } + + return $arguments; + } + + public function reflectArguments(ReflectionFunctionAbstract $method, array $args = []): array + { + $params = $method->getParameters(); + $arguments = []; + + foreach ($params as $param) { + $name = $param->getName(); + + // if we've been given a value for the argument, treat as literal + if (array_key_exists($name, $args)) { + $arguments[] = new LiteralArgument($args[$name]); + continue; + } + + $type = $param->getType(); + + if ($type instanceof ReflectionNamedType) { + // in PHP 8, nullable arguments have "?" prefix + $typeHint = ltrim($type->getName(), '?'); + + if ($param->isDefaultValueAvailable()) { + $arguments[] = new DefaultValueArgument($typeHint, $param->getDefaultValue()); + continue; + } + + $arguments[] = new ResolvableArgument($typeHint); + continue; + } + + if ($param->isDefaultValueAvailable()) { + $arguments[] = new LiteralArgument($param->getDefaultValue()); + continue; + } + + throw new NotFoundException(sprintf( + 'Unable to resolve a value for parameter (%s) in the function/method (%s)', + $name, + $method->getName() + )); + } + + return $this->resolveArguments($arguments); + } + + abstract public function getContainer(): DefinitionContainerInterface; +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/DefaultValueArgument.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/DefaultValueArgument.php new file mode 100644 index 000000000..8c5b77188 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/DefaultValueArgument.php @@ -0,0 +1,24 @@ +defaultValue = $defaultValue; + parent::__construct($value); + } + + /** + * @return mixed|null + */ + public function getDefaultValue() + { + return $this->defaultValue; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/DefaultValueInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/DefaultValueInterface.php new file mode 100644 index 000000000..cbeb6b414 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/DefaultValueInterface.php @@ -0,0 +1,13 @@ +value = $value; + } else { + throw new InvalidArgumentException('Incorrect type for value.'); + } + } + + /** + * {@inheritdoc} + */ + public function getValue() + { + return $this->value; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/LiteralArgumentInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/LiteralArgumentInterface.php new file mode 100644 index 000000000..81c684457 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/LiteralArgumentInterface.php @@ -0,0 +1,9 @@ +value = $value; + } + + public function getValue(): string + { + return $this->value; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ResolvableArgumentInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ResolvableArgumentInterface.php new file mode 100644 index 000000000..24308977b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Argument/ResolvableArgumentInterface.php @@ -0,0 +1,10 @@ +definitions = $definitions ?? new DefinitionAggregate(); + $this->providers = $providers ?? new ServiceProviderAggregate(); + $this->inflectors = $inflectors ?? new InflectorAggregate(); + + if ($this->definitions instanceof ContainerAwareInterface) { + $this->definitions->setContainer($this); + } + + if ($this->providers instanceof ContainerAwareInterface) { + $this->providers->setContainer($this); + } + + if ($this->inflectors instanceof ContainerAwareInterface) { + $this->inflectors->setContainer($this); + } + } + + public function add(string $id, $concrete = null): DefinitionInterface + { + $concrete = $concrete ?? $id; + + if (true === $this->defaultToShared) { + return $this->addShared($id, $concrete); + } + + return $this->definitions->add($id, $concrete); + } + + public function addShared(string $id, $concrete = null): DefinitionInterface + { + $concrete = $concrete ?? $id; + return $this->definitions->addShared($id, $concrete); + } + + public function defaultToShared(bool $shared = true): ContainerInterface + { + $this->defaultToShared = $shared; + return $this; + } + + public function extend(string $id): DefinitionInterface + { + if ($this->providers->provides($id)) { + $this->providers->register($id); + } + + if ($this->definitions->has($id)) { + return $this->definitions->getDefinition($id); + } + + throw new NotFoundException(sprintf( + 'Unable to extend alias (%s) as it is not being managed as a definition', + $id + )); + } + + public function addServiceProvider(ServiceProviderInterface $provider): DefinitionContainerInterface + { + $this->providers->add($provider); + return $this; + } + + /** + * @template RequestedType + * + * @param class-string|string $id + * + * @return RequestedType|mixed + */ + public function get($id) + { + return $this->resolve($id); + } + + /** + * @template RequestedType + * + * @param class-string|string $id + * + * @return RequestedType|mixed + */ + public function getNew($id) + { + return $this->resolve($id, true); + } + + public function has($id): bool + { + if ($this->definitions->has($id)) { + return true; + } + + if ($this->definitions->hasTag($id)) { + return true; + } + + if ($this->providers->provides($id)) { + return true; + } + + foreach ($this->delegates as $delegate) { + if ($delegate->has($id)) { + return true; + } + } + + return false; + } + + public function inflector(string $type, callable $callback = null): InflectorInterface + { + return $this->inflectors->add($type, $callback); + } + + public function delegate(ContainerInterface $container): self + { + $this->delegates[] = $container; + + if ($container instanceof ContainerAwareInterface) { + $container->setContainer($this); + } + + return $this; + } + + protected function resolve($id, bool $new = false) + { + if ($this->definitions->has($id)) { + $resolved = (true === $new) ? $this->definitions->resolveNew($id) : $this->definitions->resolve($id); + return $this->inflectors->inflect($resolved); + } + + if ($this->definitions->hasTag($id)) { + $arrayOf = (true === $new) + ? $this->definitions->resolveTaggedNew($id) + : $this->definitions->resolveTagged($id); + + array_walk($arrayOf, function (&$resolved) { + $resolved = $this->inflectors->inflect($resolved); + }); + + return $arrayOf; + } + + if ($this->providers->provides($id)) { + $this->providers->register($id); + + if (!$this->definitions->has($id) && !$this->definitions->hasTag($id)) { + throw new ContainerException(sprintf('Service provider lied about providing (%s) service', $id)); + } + + return $this->resolve($id, $new); + } + + foreach ($this->delegates as $delegate) { + if ($delegate->has($id)) { + $resolved = $delegate->get($id); + return $this->inflectors->inflect($resolved); + } + } + + throw new NotFoundException(sprintf('Alias (%s) is not being managed by the container or delegates', $id)); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ContainerAwareInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ContainerAwareInterface.php new file mode 100644 index 000000000..416aa86c7 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ContainerAwareInterface.php @@ -0,0 +1,11 @@ +container = $container; + + if ($this instanceof ContainerAwareInterface) { + return $this; + } + + throw new BadMethodCallException(sprintf( + 'Attempt to use (%s) while not implementing (%s)', + ContainerAwareTrait::class, + ContainerAwareInterface::class + )); + } + + public function getContainer(): DefinitionContainerInterface + { + if ($this->container instanceof DefinitionContainerInterface) { + return $this->container; + } + + throw new ContainerException('No container implementation has been set.'); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/Definition.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/Definition.php new file mode 100644 index 000000000..06e2eaf3f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/Definition.php @@ -0,0 +1,238 @@ +alias = $id; + $this->concrete = $concrete; + } + + public function addTag(string $tag): DefinitionInterface + { + $this->tags[$tag] = true; + return $this; + } + + public function hasTag(string $tag): bool + { + return isset($this->tags[$tag]); + } + + public function setAlias(string $id): DefinitionInterface + { + $this->alias = $id; + return $this; + } + + public function getAlias(): string + { + return $this->alias; + } + + public function setShared(bool $shared = true): DefinitionInterface + { + $this->shared = $shared; + return $this; + } + + public function isShared(): bool + { + return $this->shared; + } + + public function getConcrete() + { + return $this->concrete; + } + + public function setConcrete($concrete): DefinitionInterface + { + $this->concrete = $concrete; + $this->resolved = null; + return $this; + } + + public function addArgument($arg): DefinitionInterface + { + $this->arguments[] = $arg; + return $this; + } + + public function addArguments(array $args): DefinitionInterface + { + foreach ($args as $arg) { + $this->addArgument($arg); + } + + return $this; + } + + public function addMethodCall(string $method, array $args = []): DefinitionInterface + { + $this->methods[] = [ + 'method' => $method, + 'arguments' => $args + ]; + + return $this; + } + + public function addMethodCalls(array $methods = []): DefinitionInterface + { + foreach ($methods as $method => $args) { + $this->addMethodCall($method, $args); + } + + return $this; + } + + public function resolve() + { + if (null !== $this->resolved && $this->isShared()) { + return $this->resolved; + } + + return $this->resolveNew(); + } + + public function resolveNew() + { + $concrete = $this->concrete; + + if (is_callable($concrete)) { + $concrete = $this->resolveCallable($concrete); + } + + if ($concrete instanceof LiteralArgumentInterface) { + $this->resolved = $concrete->getValue(); + return $concrete->getValue(); + } + + if ($concrete instanceof ArgumentInterface) { + $concrete = $concrete->getValue(); + } + + if (is_string($concrete) && class_exists($concrete)) { + $concrete = $this->resolveClass($concrete); + } + + if (is_object($concrete)) { + $concrete = $this->invokeMethods($concrete); + } + + try { + $container = $this->getContainer(); + } catch (ContainerException $e) { + $container = null; + } + + // stop recursive resolving + if (is_string($concrete) && in_array($concrete, $this->recursiveCheck)) { + $this->resolved = $concrete; + return $concrete; + } + + // if we still have a string, try to pull it from the container + // this allows for `alias -> alias -> ... -> concrete + if (is_string($concrete) && $container instanceof ContainerInterface && $container->has($concrete)) { + $this->recursiveCheck[] = $concrete; + $concrete = $container->get($concrete); + } + + $this->resolved = $concrete; + return $concrete; + } + + /** + * @param callable $concrete + * @return mixed + */ + protected function resolveCallable(callable $concrete) + { + $resolved = $this->resolveArguments($this->arguments); + return call_user_func_array($concrete, $resolved); + } + + protected function resolveClass(string $concrete): object + { + $resolved = $this->resolveArguments($this->arguments); + $reflection = new ReflectionClass($concrete); + return $reflection->newInstanceArgs($resolved); + } + + protected function invokeMethods(object $instance): object + { + foreach ($this->methods as $method) { + $args = $this->resolveArguments($method['arguments']); + $callable = [$instance, $method['method']]; + call_user_func_array($callable, $args); + } + + return $instance; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/DefinitionAggregate.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/DefinitionAggregate.php new file mode 100644 index 000000000..6a851e5fd --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/DefinitionAggregate.php @@ -0,0 +1,117 @@ +definitions = array_filter($definitions, static function ($definition) { + return ($definition instanceof DefinitionInterface); + }); + } + + public function add(string $id, $definition): DefinitionInterface + { + if (false === ($definition instanceof DefinitionInterface)) { + $definition = new Definition($id, $definition); + } + + $this->definitions[] = $definition->setAlias($id); + + return $definition; + } + + public function addShared(string $id, $definition): DefinitionInterface + { + $definition = $this->add($id, $definition); + return $definition->setShared(true); + } + + public function has(string $id): bool + { + foreach ($this->getIterator() as $definition) { + if ($id === $definition->getAlias()) { + return true; + } + } + + return false; + } + + public function hasTag(string $tag): bool + { + foreach ($this->getIterator() as $definition) { + if ($definition->hasTag($tag)) { + return true; + } + } + + return false; + } + + public function getDefinition(string $id): DefinitionInterface + { + foreach ($this->getIterator() as $definition) { + if ($id === $definition->getAlias()) { + return $definition->setContainer($this->getContainer()); + } + } + + throw new NotFoundException(sprintf('Alias (%s) is not being handled as a definition.', $id)); + } + + public function resolve(string $id) + { + return $this->getDefinition($id)->resolve(); + } + + public function resolveNew(string $id) + { + return $this->getDefinition($id)->resolveNew(); + } + + public function resolveTagged(string $tag): array + { + $arrayOf = []; + + foreach ($this->getIterator() as $definition) { + if ($definition->hasTag($tag)) { + $arrayOf[] = $definition->setContainer($this->getContainer())->resolve(); + } + } + + return $arrayOf; + } + + public function resolveTaggedNew(string $tag): array + { + $arrayOf = []; + + foreach ($this->getIterator() as $definition) { + if ($definition->hasTag($tag)) { + $arrayOf[] = $definition->setContainer($this->getContainer())->resolveNew(); + } + } + + return $arrayOf; + } + + public function getIterator(): Generator + { + yield from $this->definitions; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/DefinitionAggregateInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/DefinitionAggregateInterface.php new file mode 100644 index 000000000..5bf9de680 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Definition/DefinitionAggregateInterface.php @@ -0,0 +1,21 @@ +type = $type; + $this->callback = $callback; + } + + public function getType(): string + { + return $this->type; + } + + public function invokeMethod(string $name, array $args): InflectorInterface + { + $this->methods[$name] = $args; + return $this; + } + + public function invokeMethods(array $methods): InflectorInterface + { + foreach ($methods as $name => $args) { + $this->invokeMethod($name, $args); + } + + return $this; + } + + public function setProperty(string $property, $value): InflectorInterface + { + $this->properties[$property] = $this->resolveArguments([$value])[0]; + return $this; + } + + public function setProperties(array $properties): InflectorInterface + { + foreach ($properties as $property => $value) { + $this->setProperty($property, $value); + } + + return $this; + } + + public function inflect(object $object): void + { + $properties = $this->resolveArguments(array_values($this->properties)); + $properties = array_combine(array_keys($this->properties), $properties); + + // array_combine() can technically return false + foreach ($properties ?: [] as $property => $value) { + $object->{$property} = $value; + } + + foreach ($this->methods as $method => $args) { + $args = $this->resolveArguments($args); + $callable = [$object, $method]; + call_user_func_array($callable, $args); + } + + if ($this->callback !== null) { + call_user_func($this->callback, $object); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/InflectorAggregate.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/InflectorAggregate.php new file mode 100644 index 000000000..b26a3b9f9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/InflectorAggregate.php @@ -0,0 +1,44 @@ +inflectors[] = $inflector; + return $inflector; + } + + public function inflect($object) + { + foreach ($this->getIterator() as $inflector) { + $type = $inflector->getType(); + + if ($object instanceof $type) { + $inflector->setContainer($this->getContainer()); + $inflector->inflect($object); + } + } + + return $object; + } + + public function getIterator(): Generator + { + yield from $this->inflectors; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/InflectorAggregateInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/InflectorAggregateInterface.php new file mode 100644 index 000000000..a48df1f14 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/Inflector/InflectorAggregateInterface.php @@ -0,0 +1,14 @@ +cacheResolutions = $cacheResolutions; + } + + public function get($id, array $args = []) + { + if ($this->cacheResolutions === true && array_key_exists($id, $this->cache)) { + return $this->cache[$id]; + } + + if (!$this->has($id)) { + throw new NotFoundException( + sprintf('Alias (%s) is not an existing class and therefore cannot be resolved', $id) + ); + } + + $reflector = new ReflectionClass($id); + $construct = $reflector->getConstructor(); + + if ($construct && !$construct->isPublic()) { + throw new NotFoundException( + sprintf('Alias (%s) has a non-public constructor and therefore cannot be instantiated', $id) + ); + } + + $resolution = $construct === null + ? new $id() + : $reflector->newInstanceArgs($this->reflectArguments($construct, $args)) + ; + + if ($this->cacheResolutions === true) { + $this->cache[$id] = $resolution; + } + + return $resolution; + } + + public function has($id): bool + { + return class_exists($id); + } + + public function call(callable $callable, array $args = []) + { + if (is_string($callable) && strpos($callable, '::') !== false) { + $callable = explode('::', $callable); + } + + if (is_array($callable)) { + if (is_string($callable[0])) { + // if we have a definition container, try that first, otherwise, reflect + try { + $callable[0] = $this->getContainer()->get($callable[0]); + } catch (ContainerException $e) { + $callable[0] = $this->get($callable[0]); + } + } + + $reflection = new ReflectionMethod($callable[0], $callable[1]); + + if ($reflection->isStatic()) { + $callable[0] = null; + } + + return $reflection->invokeArgs($callable[0], $this->reflectArguments($reflection, $args)); + } + + if (is_object($callable)) { + $reflection = new ReflectionMethod($callable, '__invoke'); + return $reflection->invokeArgs($callable, $this->reflectArguments($reflection, $args)); + } + + $reflection = new ReflectionFunction(\Closure::fromCallable($callable)); + + return $reflection->invokeArgs($this->reflectArguments($reflection, $args)); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/AbstractServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/AbstractServiceProvider.php new file mode 100644 index 000000000..4b0e77cc2 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/AbstractServiceProvider.php @@ -0,0 +1,28 @@ +identifier ?? get_class($this); + } + + public function setIdentifier(string $id): ServiceProviderInterface + { + $this->identifier = $id; + return $this; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/BootableServiceProviderInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/BootableServiceProviderInterface.php similarity index 69% rename from wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/BootableServiceProviderInterface.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/BootableServiceProviderInterface.php index 33d9579d5..3f3553c0d 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/BootableServiceProviderInterface.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/BootableServiceProviderInterface.php @@ -1,6 +1,8 @@ providers, true)) { + return $this; + } + + $provider->setContainer($this->getContainer()); + + if ($provider instanceof BootableServiceProviderInterface) { + $provider->boot(); + } + + $this->providers[] = $provider; + return $this; + } + + public function provides(string $service): bool + { + foreach ($this->getIterator() as $provider) { + if ($provider->provides($service)) { + return true; + } + } + + return false; + } + + public function getIterator(): Generator + { + yield from $this->providers; + } + + public function register(string $service): void + { + if (false === $this->provides($service)) { + throw new ContainerException( + sprintf('(%s) is not provided by a service provider', $service) + ); + } + + foreach ($this->getIterator() as $provider) { + if (in_array($provider->getIdentifier(), $this->registered, true)) { + continue; + } + + if ($provider->provides($service)) { + $provider->register(); + $this->registered[] = $provider->getIdentifier(); + } + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/ServiceProviderAggregateInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/ServiceProviderAggregateInterface.php new file mode 100644 index 000000000..de7bc7438 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/League/Container/ServiceProvider/ServiceProviderAggregateInterface.php @@ -0,0 +1,15 @@ +setMaxImportSize($this->maxImportSize); $minifier->setImportExtensions($this->importExtensions); $importContent = $minifier->execute($source, $parents); @@ -307,7 +307,8 @@ public function execute($path = null, $parents = array()) */ $this->extractStrings(); $this->stripComments(); - $this->extractCalcs(); + $this->extractMath(); + $this->extractCustomProperties(); $css = $this->replace($css); $css = $this->stripWhitespace($css); @@ -678,19 +679,29 @@ protected function stripWhitespace($content) } /** - * Replace all `calc()` occurrences. + * Replace all occurrences of functions that may contain math, where + * whitespace around operators needs to be preserved (e.g. calc, clamp) */ - protected function extractCalcs() + protected function extractMath() { + $functions = array('calc', 'clamp', 'min', 'max'); + $pattern = '/\b('. implode('|', $functions) .')(\(.+?)(?=$|;|})/m'; + // PHP only supports $this inside anonymous functions since 5.4 $minifier = $this; - $callback = function ($match) use ($minifier) { - $length = strlen($match[1]); + $callback = function ($match) use ($minifier, $pattern, &$callback) { + $function = $match[1]; + $length = strlen($match[2]); $expr = ''; $opened = 0; + // the regular expression for extracting math has 1 significant problem: + // it can't determine the correct closing parenthesis... + // instead, it'll match a larger portion of code to where it's certain that + // the calc() musts have ended, and we'll figure out which is the correct + // closing parenthesis here, by counting how many have opened for ($i = 0; $i < $length; $i++) { - $char = $match[1][$i]; + $char = $match[2][$i]; $expr .= $char; if ($char === '(') { $opened++; @@ -698,18 +709,45 @@ protected function extractCalcs() break; } } - $rest = str_replace($expr, '', $match[1]); - $expr = trim(substr($expr, 1, -1)); + // now that we've figured out where the calc() starts and ends, extract it $count = count($minifier->extracted); - $placeholder = 'calc('.$count.')'; - $minifier->extracted[$placeholder] = 'calc('.$expr.')'; + $placeholder = 'math('.$count.')'; + $minifier->extracted[$placeholder] = $function.'('.trim(substr($expr, 1, -1)).')'; + + // and since we've captured more code than required, we may have some leftover + // calc() in here too - go recursive on the remaining but of code to go figure + // that out and extract what is needed + $rest = ""; + $pos = strpos($match[0], $function.$expr); + if ($pos !== false) { + $rest = substr_replace($match[0], '', $pos, strlen($function.$expr)); + } + $rest = preg_replace_callback($pattern, $callback, $rest); return $placeholder.$rest; }; - $this->registerPattern('/calc(\(.+?)(?=$|;|}|calc\()/', $callback); - $this->registerPattern('/calc(\(.+?)(?=$|;|}|calc\()/m', $callback); + $this->registerPattern($pattern, $callback); + } + + /** + * Replace custom properties, whose values may be used in scenarios where + * we wouldn't want them to be minified (e.g. inside calc) + */ + protected function extractCustomProperties() + { + // PHP only supports $this inside anonymous functions since 5.4 + $minifier = $this; + $this->registerPattern( + '/(?<=^|[;}{])\s*(--[^:;{}"\'\s]+)\s*:([^;{}]+)/m', + function ($match) use ($minifier) { + $placeholder = '--custom-'. count($minifier->extracted) . ':0'; + $minifier->extracted[$placeholder] = $match[1] .':'. trim($match[2]); + return $placeholder; + + } + ); } /** diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Minify/JS.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Minify/JS.php index 192506137..3fc9b4c94 100644 --- a/wp-content/plugins/wp-rocket/inc/Dependencies/Minify/JS.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Minify/JS.php @@ -124,7 +124,7 @@ class JS extends Minify */ public function __construct() { - call_user_func_array(array('parent', '__construct'), func_get_args()); + call_user_func_array(array('\\WP_Rocket\Dependencies\Minify\\Minify', '__construct'), func_get_args()); $dataDir = __DIR__.'/data/js/'; $options = FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES; @@ -198,15 +198,25 @@ protected function stripComments() // PHP only supports $this inside anonymous functions since 5.4 $minifier = $this; $callback = function ($match) use ($minifier) { - $count = count($minifier->extracted); - $placeholder = '/*'.$count.'*/'; - $minifier->extracted[$placeholder] = $match[0]; + if ( + substr($match[1], 0, 1) === '!' || + strpos($match[1], '@license') !== false || + strpos($match[1], '@preserve') !== false + ) { + // preserve multi-line comments that start with /*! + // or contain @license or @preserve annotations + $count = count($minifier->extracted); + $placeholder = '/*'.$count.'*/'; + $minifier->extracted[$placeholder] = $match[0]; + + return $placeholder; + } - return $placeholder; + return ''; }; + // multi-line comments - $this->registerPattern('/\n?\/\*(!|.*?@license|.*?@preserve).*?\*\/\n?/s', $callback); - $this->registerPattern('/\/\*.*?\*\//s', ''); + $this->registerPattern('/\n?\/\*(.*?)\*\/\n?/s', $callback); // single-line comments $this->registerPattern('/\/\/.*$/m', ''); @@ -254,7 +264,7 @@ protected function extractRegex() // of the RegExp methods (a `\` followed by a variable or value is // likely part of a division, not a regex) $keywords = array('do', 'in', 'new', 'else', 'throw', 'yield', 'delete', 'return', 'typeof'); - $before = '([=:,;\+\-\*\/\}\(\{\[&\|!]|^|'.implode('|', $keywords).')\s*'; + $before = '(^|[=:,;\+\-\*\/\}\(\{\[&\|!]|'.implode('|', $keywords).')\s*'; $propertiesAndMethods = array( // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#Properties_2 'constructor', diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Minify/Minify.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Minify/Minify.php index 2f175abcb..33d032cb9 100644 --- a/wp-content/plugins/wp-rocket/inc/Dependencies/Minify/Minify.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Minify/Minify.php @@ -105,7 +105,7 @@ public function add($data /* $data = null, ... */) * @param string|string[] $data * * @return static - * + * * @throws IOException */ public function addFile($data /* $data = null, ... */) @@ -243,6 +243,9 @@ protected function save($content, $path) /** * Register a pattern to execute against the source content. * + * If $replacement is a string, it must be plain text. Placeholders like $1 or \2 don't work. + * If you need that functionality, use a callback instead. + * * @param string $pattern PCRE pattern * @param string|callable $replacement Replacement value for matched pattern */ @@ -268,11 +271,13 @@ protected function registerPattern($pattern, $replacement = '') */ protected function replace($content) { - $processed = ''; + $contentLength = strlen($content); + $output = ''; + $processedOffset = 0; $positions = array_fill(0, count($this->patterns), -1); $matches = array(); - while ($content) { + while ($processedOffset < $contentLength) { // find first match for all patterns foreach ($this->patterns as $i => $pattern) { list($pattern, $replacement) = $pattern; @@ -285,12 +290,12 @@ protected function replace($content) // no need to re-run matches that are still in the part of the // content that hasn't been processed - if ($positions[$i] >= 0) { + if ($positions[$i] >= $processedOffset) { continue; } $match = null; - if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE)) { + if (preg_match($pattern, $content, $match, PREG_OFFSET_CAPTURE, $processedOffset)) { $matches[$i] = $match; // we'll store the match position as well; that way, we @@ -307,61 +312,52 @@ protected function replace($content) // no more matches to find: everything's been processed, break out if (!$matches) { - $processed .= $content; + // output the remaining content + $output .= substr($content, $processedOffset); break; } // see which of the patterns actually found the first thing (we'll // only want to execute that one, since we're unsure if what the // other found was not inside what the first found) - $discardLength = min($positions); - $firstPattern = array_search($discardLength, $positions); - $match = $matches[$firstPattern][0][0]; + $matchOffset = min($positions); + $firstPattern = array_search($matchOffset, $positions); + $match = $matches[$firstPattern]; // execute the pattern that matches earliest in the content string - list($pattern, $replacement) = $this->patterns[$firstPattern]; - $replacement = $this->replacePattern($pattern, $replacement, $content); - - // figure out which part of the string was unmatched; that's the - // part we'll execute the patterns on again next - $content = (string) substr($content, $discardLength); - $unmatched = (string) substr($content, strpos($content, $match) + strlen($match)); - - // move the replaced part to $processed and prepare $content to - // again match batch of patterns against - $processed .= substr($replacement, 0, strlen($replacement) - strlen($unmatched)); - $content = $unmatched; - - // first match has been replaced & that content is to be left alone, - // the next matches will start after this replacement, so we should - // fix their offsets - foreach ($positions as $i => $position) { - $positions[$i] -= $discardLength + strlen($match); - } + list(, $replacement) = $this->patterns[$firstPattern]; + + // add the part of the input between $processedOffset and the first match; + // that content wasn't matched by anything + $output .= substr($content, $processedOffset, $matchOffset - $processedOffset); + // add the replacement for the match + $output .= $this->executeReplacement($replacement, $match); + // advance $processedOffset past the match + $processedOffset = $matchOffset + strlen($match[0][0]); } - return $processed; + return $output; } /** - * This is where a pattern is matched against $content and the matches - * are replaced by their respective value. - * This function will be called plenty of times, where $content will always - * move up 1 character. + * If $replacement is a callback, execute it, passing in the match data. + * If it's a string, just pass it through. * - * @param string $pattern Pattern to match * @param string|callable $replacement Replacement value - * @param string $content Content to match pattern against + * @param array $match Match data, in PREG_OFFSET_CAPTURE form * * @return string */ - protected function replacePattern($pattern, $replacement, $content) + protected function executeReplacement($replacement, $match) { - if (is_callable($replacement)) { - return preg_replace_callback($pattern, $replacement, $content, 1, $count); - } else { - return preg_replace($pattern, $replacement, $content, 1, $count); + if (!is_callable($replacement)) { + return $replacement; } + // convert $match from the PREG_OFFSET_CAPTURE form to the form the callback expects + foreach ($match as &$matchItem) { + $matchItem = $matchItem[0]; + } + return $replacement($match); } /** @@ -472,7 +468,7 @@ protected function canImportFile($path) */ protected function openFileForWriting($path) { - if (($handler = @fopen($path, 'w')) === false) { + if ($path === '' || ($handler = @fopen($path, 'w')) === false) { throw new IOException('The file "'.$path.'" could not be opened for writing. Check if PHP has enough permissions.'); } @@ -490,7 +486,11 @@ protected function openFileForWriting($path) */ protected function writeToFile($handler, $content, $path = '') { - if (($result = @fwrite($handler, $content)) === false || ($result < strlen($content))) { + if ( + !is_resource($handler) || + ($result = @fwrite($handler, $content)) === false || + ($result < strlen($content)) + ) { throw new IOException('The file "'.$path.'" could not be written to. Check your disk space and file permissions.'); } } diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/ErrorHandler.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/ErrorHandler.php similarity index 96% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/ErrorHandler.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/ErrorHandler.php index 5121c2cd0..faa26b5fb 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/ErrorHandler.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/ErrorHandler.php @@ -1,7 +1,7 @@ * @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace Monolog; +namespace WP_Rocket\Dependencies\Monolog; -use Psr\Log\LoggerInterface; -use Psr\Log\LogLevel; -use Monolog\Handler\AbstractHandler; +use WP_Rocket\Dependencies\Psr\Log\LoggerInterface; +use WP_Rocket\Dependencies\Psr\Log\LogLevel; +use WP_Rocket\Dependencies\Monolog\Handler\AbstractHandler; /** - * Monolog error handler + * WP_Rocket\Dependencies\Monolog error handler * * A facility to enable logging of runtime errors, exceptions and fatal errors. * diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/FormatterInterface.php similarity index 85% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/FormatterInterface.php index b5de75111..e4a317639 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/FormatterInterface.php @@ -1,7 +1,7 @@ * @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Monolog\Formatter; +namespace WP_Rocket\Dependencies\Monolog\Formatter; /** * Interface for formatters diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/HtmlFormatter.php similarity index 93% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/HtmlFormatter.php index 9e8d2d018..b8c215843 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/HtmlFormatter.php @@ -1,6 +1,6 @@ * @@ -8,10 +8,10 @@ * file that was distributed with this source code. */ -namespace Monolog\Formatter; +namespace WP_Rocket\Dependencies\Monolog\Formatter; -use Monolog\Logger; -use Monolog\Utils; +use WP_Rocket\Dependencies\Monolog\Logger; +use WP_Rocket\Dependencies\Monolog\Utils; /** * Formats incoming records into an HTML table @@ -23,7 +23,7 @@ class HtmlFormatter extends NormalizerFormatter { /** - * Translates Monolog log levels to html color priorities. + * Translates WP_Rocket\Dependencies\Monolog log levels to html color priorities. */ protected $logLevels = array( Logger::DEBUG => '#cccccc', diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/LineFormatter.php similarity index 97% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/LineFormatter.php index acc1fd38f..60b8a72c1 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/LineFormatter.php @@ -1,7 +1,7 @@ * @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Monolog\Formatter; +namespace WP_Rocket\Dependencies\Monolog\Formatter; -use Monolog\Utils; +use WP_Rocket\Dependencies\Monolog\Utils; /** * Formats incoming records into a one-line string diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/NormalizerFormatter.php similarity index 86% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/NormalizerFormatter.php index 3a01f2cef..df64b2a17 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Formatter/NormalizerFormatter.php @@ -1,7 +1,7 @@ * @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Monolog\Formatter; +namespace WP_Rocket\Dependencies\Monolog\Formatter; use Exception; -use Monolog\Utils; +use WP_Rocket\Dependencies\Monolog\Utils; /** * Normalizes incoming records to remove objects/resources so it's easier to dump to various targets @@ -24,15 +24,18 @@ class NormalizerFormatter implements FormatterInterface const SIMPLE_DATE = "Y-m-d H:i:s"; protected $dateFormat; + protected $maxDepth; /** * @param string $dateFormat The format of the timestamp: one supported by DateTime::format + * @param int $maxDepth */ - public function __construct($dateFormat = null) + public function __construct($dateFormat = null, $maxDepth = 9) { $this->dateFormat = $dateFormat ?: static::SIMPLE_DATE; + $this->maxDepth = $maxDepth; if (!function_exists('json_encode')) { - throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter'); + throw new \RuntimeException('PHP\'s json extension is required to use WP_Rocket\Dependencies\Monolog\'s NormalizerFormatter'); } } @@ -56,10 +59,26 @@ public function formatBatch(array $records) return $records; } + /** + * @return int + */ + public function getMaxDepth() + { + return $this->maxDepth; + } + + /** + * @param int $maxDepth + */ + public function setMaxDepth($maxDepth) + { + $this->maxDepth = $maxDepth; + } + protected function normalize($data, $depth = 0) { - if ($depth > 9) { - return 'Over 9 levels deep, aborting normalization'; + if ($depth > $this->maxDepth) { + return 'Over '.$this->maxDepth.' levels deep, aborting normalization'; } if (null === $data || is_scalar($data)) { @@ -177,4 +196,4 @@ protected function toJson($data, $ignoreErrors = false) { return Utils::jsonEncode($data, null, $ignoreErrors); } -} +} \ No newline at end of file diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/AbstractHandler.php similarity index 92% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/AbstractHandler.php index cdd9f7d40..5e089b68c 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/AbstractHandler.php @@ -1,7 +1,7 @@ * @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler; +namespace WP_Rocket\Dependencies\Monolog\Handler; -use Monolog\Formatter\FormatterInterface; -use Monolog\Formatter\LineFormatter; -use Monolog\Logger; -use Monolog\ResettableInterface; +use WP_Rocket\Dependencies\Monolog\Formatter\FormatterInterface; +use WP_Rocket\Dependencies\Monolog\Formatter\LineFormatter; +use WP_Rocket\Dependencies\Monolog\Logger; +use WP_Rocket\Dependencies\Monolog\ResettableInterface; /** * Base Handler class providing the Handler structure diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/AbstractProcessingHandler.php similarity index 89% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/AbstractProcessingHandler.php index e1e89530a..e852d2703 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/AbstractProcessingHandler.php @@ -1,7 +1,7 @@ * @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler; +namespace WP_Rocket\Dependencies\Monolog\Handler; -use Monolog\ResettableInterface; +use WP_Rocket\Dependencies\Monolog\ResettableInterface; /** * Base Handler class providing the Handler structure diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/FormattableHandlerInterface.php similarity index 81% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/FormattableHandlerInterface.php index 3e2f1b28a..3d4cbec61 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/FormattableHandlerInterface.php @@ -1,7 +1,7 @@ * @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler; +namespace WP_Rocket\Dependencies\Monolog\Handler; -use Monolog\Formatter\FormatterInterface; +use WP_Rocket\Dependencies\Monolog\Formatter\FormatterInterface; /** * Interface to describe loggers that have a formatter diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/FormattableHandlerTrait.php similarity index 83% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/FormattableHandlerTrait.php index e9ec5e776..9f40d2590 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/FormattableHandlerTrait.php @@ -1,7 +1,7 @@ * @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler; +namespace WP_Rocket\Dependencies\Monolog\Handler; -use Monolog\Formatter\FormatterInterface; -use Monolog\Formatter\LineFormatter; +use WP_Rocket\Dependencies\Monolog\Formatter\FormatterInterface; +use WP_Rocket\Dependencies\Monolog\Formatter\LineFormatter; /** * Helper trait for implementing FormattableInterface diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/HandlerInterface.php similarity index 90% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/HandlerInterface.php index 8d5a4a095..20527d76e 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/HandlerInterface.php @@ -1,7 +1,7 @@ * @@ -9,12 +9,12 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler; +namespace WP_Rocket\Dependencies\Monolog\Handler; -use Monolog\Formatter\FormatterInterface; +use WP_Rocket\Dependencies\Monolog\Formatter\FormatterInterface; /** - * Interface that all Monolog Handlers must implement + * Interface that all WP_Rocket\Dependencies\Monolog Handlers must implement * * @author Jordi Boggiano */ diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/ProcessableHandlerInterface.php similarity index 83% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/ProcessableHandlerInterface.php index 66a3d83ae..12630d9eb 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/ProcessableHandlerInterface.php @@ -1,7 +1,7 @@ * @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler; +namespace WP_Rocket\Dependencies\Monolog\Handler; -use Monolog\Processor\ProcessorInterface; +use WP_Rocket\Dependencies\Monolog\Processor\ProcessorInterface; /** * Interface to describe loggers that have processors diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/ProcessableHandlerTrait.php similarity index 89% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/ProcessableHandlerTrait.php index 09f32a12c..b5223cb6a 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/ProcessableHandlerTrait.php @@ -1,7 +1,7 @@ * @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler; +namespace WP_Rocket\Dependencies\Monolog\Handler; -use Monolog\ResettableInterface; +use WP_Rocket\Dependencies\Monolog\ResettableInterface; /** * Helper trait for implementing ProcessableInterface diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/StreamHandler.php similarity index 89% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/StreamHandler.php index ad6960cb2..1b1ff9c07 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Handler/StreamHandler.php @@ -1,7 +1,7 @@ * @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Monolog\Handler; +namespace WP_Rocket\Dependencies\Monolog\Handler; -use Monolog\Logger; -use Monolog\Utils; +use WP_Rocket\Dependencies\Monolog\Logger; +use WP_Rocket\Dependencies\Monolog\Utils; /** * Stores to any stream resource @@ -23,6 +23,10 @@ */ class StreamHandler extends AbstractProcessingHandler { + /** @private 512KB */ + const CHUNK_SIZE = 524288; + + /** @var resource|null */ protected $stream; protected $url; private $errorMessage; @@ -45,6 +49,7 @@ public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $fi parent::__construct($level, $bubble); if (is_resource($stream)) { $this->stream = $stream; + $this->streamSetChunkSize(); } elseif (is_string($stream)) { $this->url = Utils::canonicalizePath($stream); } else { @@ -109,6 +114,7 @@ protected function write(array $record) throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url)); } + $this->streamSetChunkSize(); } if ($this->useLocking) { @@ -133,6 +139,15 @@ protected function streamWrite($stream, array $record) fwrite($stream, (string) $record['formatted']); } + protected function streamSetChunkSize() + { + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + return stream_set_chunk_size($this->stream, self::CHUNK_SIZE); + } + + return false; + } + private function customErrorHandler($code, $msg) { $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg); diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Logger.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Logger.php similarity index 97% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Logger.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Logger.php index b8b4f55b4..2903bc73f 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Logger.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Logger.php @@ -1,7 +1,7 @@ * @@ -9,16 +9,16 @@ * file that was distributed with this source code. */ -namespace Monolog; +namespace WP_Rocket\Dependencies\Monolog; -use Monolog\Handler\HandlerInterface; -use Monolog\Handler\StreamHandler; -use Psr\Log\LoggerInterface; -use Psr\Log\InvalidArgumentException; +use WP_Rocket\Dependencies\Monolog\Handler\HandlerInterface; +use WP_Rocket\Dependencies\Monolog\Handler\StreamHandler; +use WP_Rocket\Dependencies\Psr\Log\LoggerInterface; +use WP_Rocket\Dependencies\Psr\Log\InvalidArgumentException; use Exception; /** - * Monolog log channel + * WP_Rocket\Dependencies\Monolog log channel * * It contains a stack of Handlers and a stack of Processors, * and uses them to store records that are added to it. @@ -78,7 +78,7 @@ class Logger implements LoggerInterface, ResettableInterface const EMERGENCY = 600; /** - * Monolog API version + * WP_Rocket\Dependencies\Monolog API version * * This is only bumped when API breaks are done and should * follow the major version of the library @@ -321,7 +321,7 @@ public function addRecord($level, $message, array $context = array()) if ($this->microsecondTimestamps && PHP_VERSION_ID < 70100) { $ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone); } else { - $ts = new \DateTime(null, static::$timezone); + $ts = new \DateTime('now', static::$timezone); } $ts->setTimezone(static::$timezone); @@ -520,7 +520,7 @@ public static function getLevelName($level) } /** - * Converts PSR-3 levels to Monolog ones if necessary + * Converts PSR-3 levels to WP_Rocket\Dependencies\Monolog ones if necessary * * @param string|int $level Level number (monolog) or name (PSR-3) * @return int diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Processor/IntrospectionProcessor.php similarity index 92% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Processor/IntrospectionProcessor.php index 6ae192a23..d91d46218 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Processor/IntrospectionProcessor.php @@ -1,7 +1,7 @@ * @@ -9,9 +9,9 @@ * file that was distributed with this source code. */ -namespace Monolog\Processor; +namespace WP_Rocket\Dependencies\Monolog\Processor; -use Monolog\Logger; +use WP_Rocket\Dependencies\Monolog\Logger; /** * Injects line/file:class/function where the log message came from @@ -40,7 +40,7 @@ class IntrospectionProcessor implements ProcessorInterface public function __construct($level = Logger::DEBUG, array $skipClassesPartials = array(), $skipStackFramesCount = 0) { $this->level = Logger::toMonologLevel($level); - $this->skipClassesPartials = array_merge(array('Monolog\\'), $skipClassesPartials); + $this->skipClassesPartials = array_merge(array('WP_Rocket\Dependencies\Monolog\\'), $skipClassesPartials); $this->skipStackFramesCount = $skipStackFramesCount; } diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Processor/ProcessorInterface.php similarity index 64% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Processor/ProcessorInterface.php index 7e64d4dfa..597900c88 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Processor/ProcessorInterface.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Processor/ProcessorInterface.php @@ -1,7 +1,7 @@ * @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Monolog\Processor; +namespace WP_Rocket\Dependencies\Monolog\Processor; /** - * An optional interface to allow labelling Monolog processors. + * An optional interface to allow labelling WP_Rocket\Dependencies\Monolog processors. * * @author Nicolas Grekas */ diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Registry.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Registry.php similarity index 85% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Registry.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Registry.php index 159b751cd..806ee114a 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Registry.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Registry.php @@ -1,7 +1,7 @@ * @@ -9,27 +9,27 @@ * file that was distributed with this source code. */ -namespace Monolog; +namespace WP_Rocket\Dependencies\Monolog; use InvalidArgumentException; /** - * Monolog log registry + * WP_Rocket\Dependencies\Monolog log registry * * Allows to get `Logger` instances in the global scope * via static method calls on this class. * * - * $application = new Monolog\Logger('application'); - * $api = new Monolog\Logger('api'); + * $application = new WP_Rocket\Dependencies\Monolog\Logger('application'); + * $api = new WP_Rocket\Dependencies\Monolog\Logger('api'); * - * Monolog\Registry::addLogger($application); - * Monolog\Registry::addLogger($api); + * WP_Rocket\Dependencies\Monolog\Registry::addLogger($application); + * WP_Rocket\Dependencies\Monolog\Registry::addLogger($api); * * function testLogger() * { - * Monolog\Registry::api()->addError('Sent to $api Logger instance'); - * Monolog\Registry::application()->addError('Sent to $application Logger instance'); + * WP_Rocket\Dependencies\Monolog\Registry::api()->addError('Sent to $api Logger instance'); + * WP_Rocket\Dependencies\Monolog\Registry::application()->addError('Sent to $application Logger instance'); * } * * diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/ResettableInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/ResettableInterface.php similarity index 88% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/ResettableInterface.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/ResettableInterface.php index 635bc77dc..f91ee124b 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/ResettableInterface.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/ResettableInterface.php @@ -1,7 +1,7 @@ * @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Monolog; +namespace WP_Rocket\Dependencies\Monolog; /** * Handler or Processor implementing this interface will be reset when Logger::reset() is called. diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/SignalHandler.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/SignalHandler.php similarity index 93% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/SignalHandler.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/SignalHandler.php index d87018fed..8f62c7e99 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/SignalHandler.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/SignalHandler.php @@ -1,7 +1,7 @@ * @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace Monolog; +namespace WP_Rocket\Dependencies\Monolog; -use Psr\Log\LoggerInterface; -use Psr\Log\LogLevel; +use WP_Rocket\Dependencies\Psr\Log\LoggerInterface; +use WP_Rocket\Dependencies\Psr\Log\LogLevel; use ReflectionExtension; /** - * Monolog POSIX signal handler + * WP_Rocket\Dependencies\Monolog POSIX signal handler * * @author Robert Gust-Bardon */ diff --git a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Utils.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Utils.php similarity index 96% rename from wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Utils.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Utils.php index 7f1ba129e..2542e2ed1 100644 --- a/wp-content/plugins/wp-rocket/vendor/monolog/monolog/src/Monolog/Utils.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Monolog/Utils.php @@ -1,7 +1,7 @@ * @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Monolog; +namespace WP_Rocket\Dependencies\Monolog; class Utils { @@ -108,7 +108,7 @@ public static function handleJsonError($code, $data, $encodeFlags = null) if (is_string($data)) { self::detectAndCleanUtf8($data); } elseif (is_array($data)) { - array_walk_recursive($data, array('Monolog\Utils', 'detectAndCleanUtf8')); + array_walk_recursive($data, array('WP_Rocket\Dependencies\Monolog\Utils', 'detectAndCleanUtf8')); } else { self::throwEncodeError($code, $data); } diff --git a/wp-content/plugins/wp-rocket/vendor/psr/container/src/ContainerExceptionInterface.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Psr/Container/ContainerExceptionInterface.php similarity index 50% rename from wp-content/plugins/wp-rocket/vendor/psr/container/src/ContainerExceptionInterface.php rename to wp-content/plugins/wp-rocket/inc/Dependencies/Psr/Container/ContainerExceptionInterface.php index d35c6b4d8..98b4b6712 100644 --- a/wp-content/plugins/wp-rocket/vendor/psr/container/src/ContainerExceptionInterface.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Psr/Container/ContainerExceptionInterface.php @@ -1,9 +1,6 @@ value pairs. Cache keys that do not exist or are stale will have $default as value. + * + */ + public function getMultiple($keys, $default = null); + + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @param iterable $values A list of key => value pairs for a multiple-set operation. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + * + */ + public function setMultiple($values, $ttl = null); + + /** + * Deletes multiple cache items in a single operation. + * + * @param iterable $keys A list of string-based keys to be deleted. + * + * @return bool True if the items were successfully removed. False if there was an error. + * + */ + public function deleteMultiple($keys); + + /** + * Determines whether an item is present in the cache. + * + * NOTE: It is recommended that has() is only to be used for cache warming type purposes + * and not to be used within your live applications operations for get/set, as this method + * is subject to a race condition where your has() will return true and immediately after, + * another script can remove it making the state of your app out of date. + * + * @param string $key The cache item key. + * + * @return bool + * + */ + public function has($key); +} diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/Psr/SimpleCache/InvalidArgumentException.php b/wp-content/plugins/wp-rocket/inc/Dependencies/Psr/SimpleCache/InvalidArgumentException.php new file mode 100644 index 000000000..f42d29b75 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/Psr/SimpleCache/InvalidArgumentException.php @@ -0,0 +1,13 @@ +getLazyloadScript( $args ); + echo $this->getLazyloadScript( $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** @@ -31,7 +33,6 @@ public function insertLazyloadScript( $args = [] ) { public function getInlineLazyloadScript( $args = [] ) { $defaults = [ 'elements' => [ - 'img', 'iframe', ], 'threshold' => 300, @@ -42,13 +43,24 @@ public function getInlineLazyloadScript( $args = [] ) { 'container' => 1, 'thresholds' => 1, 'data_bg' => 1, + 'data_bg_hidpi' => 1, + 'data_bg_multi' => 1, + 'data_bg_multi_hidpi' => 1, + 'data_poster' => 1, + 'class_applied' => 1, 'class_error' => 1, + 'class_entered' => 1, + 'class_exited' => 1, 'cancel_on_exit' => 1, + 'unobserve_entered' => 1, 'unobserve_completed' => 1, 'callback_enter' => 1, 'callback_exit' => 1, 'callback_loading' => 1, + 'callback_cancel' => 1, + 'callback_loaded' => 1, 'callback_error' => 1, + 'callback_applied' => 1, 'callback_finish' => 1, 'use_native' => 1, ]; @@ -57,8 +69,13 @@ public function getInlineLazyloadScript( $args = [] ) { $script = ''; $args['options'] = array_intersect_key( $args['options'], $allowed_options ); + $script .= 'window.lazyLoadOptions = '; + + if ( isset( $args['elements']['background_image'] ) ) { + $script .= '['; + } - $script .= 'window.lazyLoadOptions = { + $script .= '{ elements_selector: "' . esc_attr( implode( ',', $args['elements'] ) ) . '", data_src: "lazy-src", data_srcset: "lazy-srcset", @@ -88,7 +105,19 @@ class_loaded: "lazyloaded", $script = rtrim( $script, ',' ); } - $script .= '};'; + if ( isset( $args['elements']['background_image'] ) ) { + $script .= '},{ + elements_selector: "' . esc_attr( $args['elements']['background_image'] ) . '", + data_src: "lazy-src", + data_srcset: "lazy-srcset", + data_sizes: "lazy-sizes", + class_loading: "lazyloading", + class_loaded: "lazyloaded", + threshold: ' . esc_attr( $args['threshold'] ) . ', + }];'; + } else { + $script .= '};'; + } $script .= ' window.addEventListener(\'LazyLoad::Initialized\', function (e) { @@ -101,12 +130,12 @@ class_loaded: "lazyloaded", var rocketlazy_count = 0; mutations.forEach(function(mutation) { - for (i = 0; i < mutation.addedNodes.length; i++) { + for (var i = 0; i < mutation.addedNodes.length; i++) { if (typeof mutation.addedNodes[i].getElementsByTagName !== \'function\') { continue; } - if (typeof mutation.addedNodes[i].getElementsByClassName !== \'function\') { + if (typeof mutation.addedNodes[i].getElementsByClassName !== \'function\') { continue; } @@ -155,16 +184,10 @@ public function getLazyloadScript( $args = [] ) { $defaults = [ 'base_url' => '', 'version' => '', - 'polyfill' => false, ]; - $args = wp_parse_args( $args, $defaults ); - $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min'; - $script = ''; - - if ( isset( $args['polyfill'] ) && $args['polyfill'] ) { - $script .= ''; - } + $args = wp_parse_args( $args, $defaults ); + $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min'; /** * Filters the script tag for the lazyload script @@ -173,9 +196,7 @@ public function getLazyloadScript( $args = [] ) { * * @param $script_tag HTML tag for the lazyload script. */ - $script .= apply_filters( 'rocket_lazyload_script_tag', '' ); - - return $script; + return apply_filters( 'rocket_lazyload_script_tag', '' ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript } /** @@ -185,7 +206,7 @@ public function getLazyloadScript( $args = [] ) { * @return void */ public function insertYoutubeThumbnailScript( $args = [] ) { - echo $this->getYoutubeThumbnailScript( $args ); + echo $this->getYoutubeThumbnailScript( $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** @@ -198,6 +219,8 @@ public function getYoutubeThumbnailScript( $args = [] ) { $defaults = [ 'resolution' => 'hqdefault', 'lazy_image' => false, + 'native' => true, + 'extension' => 'jpg', ]; $allowed_resolutions = [ @@ -228,13 +251,36 @@ public function getYoutubeThumbnailScript( $args = [] ) { $args = wp_parse_args( $args, $defaults ); - $image = ''; + $extension_uri = 'webp' === $args['extension'] ? 'vi_webp' : 'vi'; + + $image_url = 'https://i.ytimg.com/' . $extension_uri . '/ID/' . $args['resolution'] . '.' . $args['extension']; + + $image = ''; if ( isset( $args['lazy_image'] ) && $args['lazy_image'] ) { - $image = ''; + $attributes = 'alt="" width="' . $allowed_resolutions[ $args['resolution'] ]['width'] . '" height="' . $allowed_resolutions[ $args['resolution'] ]['height'] . '"'; + + $image = ''; + + if ( $args['native'] ) { + $image = ''; + } } - return ""; + /** + * Filters the patterns excluded from lazyload for youtube thumbnails. + * + * @param array $excluded_patterns Array of excluded patterns. + */ + $excluded_patterns = apply_filters( 'rocket_lazyload_exclude_youtube_thumbnail', [] ); + + if ( ! is_array( $excluded_patterns ) ) { + $excluded_patterns = []; + } + + $excluded_patterns = wp_json_encode( $excluded_patterns ); + + return ""; } /** @@ -244,7 +290,7 @@ public function getYoutubeThumbnailScript( $args = [] ) { * @return void */ public function insertYoutubeThumbnailCSS( $args = [] ) { - wp_register_style( 'rocket-lazyload', false ); + wp_register_style( 'rocket-lazyload', false ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion wp_enqueue_style( 'rocket-lazyload' ); wp_add_inline_style( 'rocket-lazyload', $this->getYoutubeThumbnailCSS( $args ) ); } @@ -263,10 +309,10 @@ public function getYoutubeThumbnailCSS( $args = [] ) { $args = wp_parse_args( $args, $defaults ); - $css = '.rll-youtube-player{position:relative;padding-bottom:56.23%;height:0;overflow:hidden;max-width:100%;}.rll-youtube-player iframe{position:absolute;top:0;left:0;width:100%;height:100%;z-index:100;background:0 0}.rll-youtube-player img{bottom:0;display:block;left:0;margin:auto;max-width:100%;width:100%;position:absolute;right:0;top:0;border:none;height:auto;cursor:pointer;-webkit-transition:.4s all;-moz-transition:.4s all;transition:.4s all}.rll-youtube-player img:hover{-webkit-filter:brightness(75%)}.rll-youtube-player .play{height:72px;width:72px;left:50%;top:50%;margin-left:-36px;margin-top:-36px;position:absolute;background:url(' . $args['base_url'] . 'img/youtube.png) no-repeat;cursor:pointer}'; + $css = '.rll-youtube-player{position:relative;padding-bottom:56.23%;height:0;overflow:hidden;max-width:100%;}.rll-youtube-player:focus-within{outline: 2px solid currentColor;outline-offset: 5px;}.rll-youtube-player iframe{position:absolute;top:0;left:0;width:100%;height:100%;z-index:100;background:0 0}.rll-youtube-player img{bottom:0;display:block;left:0;margin:auto;max-width:100%;width:100%;position:absolute;right:0;top:0;border:none;height:auto;-webkit-transition:.4s all;-moz-transition:.4s all;transition:.4s all}.rll-youtube-player img:hover{-webkit-filter:brightness(75%)}.rll-youtube-player .play{height:100%;width:100%;left:0;top:0;position:absolute;background:url(' . $args['base_url'] . 'img/youtube.png) no-repeat center;background-color: transparent !important;cursor:pointer;border:none;}'; if ( $args['responsive_embeds'] ) { - $css .= '.wp-has-aspect-ratio .rll-youtube-player{position:absolute;padding-bottom:0;width:100%;height:100%;top:0;bottom:0;left:0;right:0}'; + $css .= '.wp-embed-responsive .wp-has-aspect-ratio .rll-youtube-player{position:absolute;padding-bottom:0;width:100%;height:100%;top:0;bottom:0;left:0;right:0}'; } return $css; @@ -276,7 +322,7 @@ public function getYoutubeThumbnailCSS( $args = [] ) { * Inserts the CSS needed when Javascript is not enabled to keep the display correct */ public function insertNoJSCSS() { - echo $this->getNoJSCSS(); + echo $this->getNoJSCSS(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } /** diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/RocketLazyload/Iframe.php b/wp-content/plugins/wp-rocket/inc/Dependencies/RocketLazyload/Iframe.php index 202964a2b..d5143f396 100644 --- a/wp-content/plugins/wp-rocket/inc/Dependencies/RocketLazyload/Iframe.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/RocketLazyload/Iframe.php @@ -2,7 +2,7 @@ /** * Handles lazyloading of iframes * - * @package RocketLazyload + * @package WP_Rocket\Dependencies\RocketLazyload */ namespace WP_Rocket\Dependencies\RocketLazyload; @@ -106,6 +106,7 @@ private function getExcludedPatterns() { 'loading="eager"', 'data-skip-lazy', 'skip-lazy', + 'google_ads_iframe_', ] ); } @@ -163,6 +164,10 @@ private function replaceYoutubeThumbnail( $iframe ) { $youtube_url = $this->changeYoutubeUrlForYoutuDotBe( $iframe['src'] ); $youtube_url = $this->cleanYoutubeUrl( $iframe['src'] ); + + preg_match( '@\s*title\s*=\s*(\'|")(?.*)\1@iUs', $iframe['atts'], $atts ); + + $title = $atts['title'] ?? ''; /** * Filter the LazyLoad HTML output on Youtube iframes * @@ -170,7 +175,7 @@ private function replaceYoutubeThumbnail( $iframe ) { * * @param array $html Output that will be printed. */ - $youtube_lazyload = apply_filters( 'rocket_lazyload_youtube_html', '<div class="rll-youtube-player" data-src="' . esc_attr( $youtube_url ) . '" data-id="' . esc_attr( $youtube_id ) . '" data-query="' . esc_attr( $query ) . '"></div>' ); + $youtube_lazyload = apply_filters( 'rocket_lazyload_youtube_html', '<div class="rll-youtube-player" data-src="' . esc_attr( $youtube_url ) . '" data-id="' . esc_attr( $youtube_id ) . '" data-query="' . esc_attr( $query ) . '" data-alt="' . esc_attr( $title ) . '"></div>' ); $youtube_lazyload .= '<noscript>' . $iframe[0] . '</noscript>'; return $youtube_lazyload; diff --git a/wp-content/plugins/wp-rocket/inc/Dependencies/RocketLazyload/Image.php b/wp-content/plugins/wp-rocket/inc/Dependencies/RocketLazyload/Image.php index 6a95df402..9ff6061eb 100644 --- a/wp-content/plugins/wp-rocket/inc/Dependencies/RocketLazyload/Image.php +++ b/wp-content/plugins/wp-rocket/inc/Dependencies/RocketLazyload/Image.php @@ -1,8 +1,10 @@ <?php +declare(strict_types=1); + /** * Handles lazyloading of images * - * @package RocketLazyload + * @package WP_Rocket\Dependencies\RocketLazyload */ namespace WP_Rocket\Dependencies\RocketLazyload; @@ -17,12 +19,11 @@ class Image { * * @param string $html Original HTML. * @param string $buffer Content to parse. + * @param bool $use_native Use native lazyload. * @return string */ - public function lazyloadImages( $html, $buffer ) { - $clean_buffer = preg_replace( '/<script\b(?:[^>]*)>(?:.+)?<\/script>/Umsi', '', $html ); - $clean_buffer = preg_replace( '#<noscript>(?:.+)</noscript>#Umsi', '', $clean_buffer ); - if (! preg_match_all('#<img(?<atts>\s.+)\s?/?>#iUs', $clean_buffer, $images, PREG_SET_ORDER)) { + public function lazyloadImages( $html, $buffer, $use_native = true ) { + if ( ! preg_match_all( '#<img(?<atts>\s.+)\s?/?>#iUs', $buffer, $images, PREG_SET_ORDER ) ) { return $html; } @@ -35,9 +36,13 @@ public function lazyloadImages( $html, $buffer ) { continue; } - $image_lazyload = $this->replaceImage( $image ); - $image_lazyload .= $this->noscript( $image[0] ); - $html = str_replace( $image[0], $image_lazyload, $html ); + $image_lazyload = $this->replaceImage( $image, $use_native ); + + if ( ! $use_native ) { + $image_lazyload .= $this->noscript( $image[0] ); + } + + $html = str_replace( $image[0], $image_lazyload, $html ); unset( $image_lazyload ); } @@ -62,17 +67,34 @@ public function lazyloadBackgroundImages( $html, $buffer ) { continue; } - if ( ! preg_match( '#background-image\s*:\s*(?<attr>\s*url\s*\((?<url>[^)]+)\))\s*;?#is', $element['styles'], $url ) ) { + /** + * Regex to detect bg images inside CSS. + * + * @param string $regex regex to detect. + * @return string + */ + $regex = apply_filters( 'rocket_lazyload_bg_images_regex', 'background-image\s*:\s*(?<attr>\s*url\s*\((?<url>[^)]+)\))\s*;?' ); + + if ( @preg_match( "#$regex#is", '' ) === false ) {// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + $regex = 'background-image\s*:\s*(?<attr>\s*url\s*\((?<url>[^)]+)\))\s*;?'; + } + + if ( ! preg_match( "#$regex#is", $element['styles'], $url ) ) { continue; } + if ( preg_match( '#data:image#is', $url['url'], $img ) ) { + continue; + } $url['url'] = esc_url( trim( - strip_tags( + wp_strip_all_tags( html_entity_decode( - $url['url'], ENT_QUOTES|ENT_HTML5 + $url['url'], + ENT_QUOTES | ENT_HTML5 ) - ), '\'" ' + ), + '\'" ' ) ); @@ -99,7 +121,7 @@ public function lazyloadBackgroundImages( $html, $buffer ) { */ private function addLazyClass( $element ) { $class = $this->getClasses( $element ); - if ( empty( $class ) ) { + if ( empty( $class ) ) { return preg_replace( '#<(img|div|figure|section|li|span|a)([^>]*)>#is', '<\1 class="rocket-lazyload"\2>', $element ); } @@ -132,7 +154,7 @@ private function addLazyClass( $element ) { */ private function getAttributeQuotes( $attribute_value ) { $attribute_value = trim( $attribute_value ); - $first_char = $attribute_value[0]; + $first_char = $attribute_value[0]; if ( '"' === $first_char || "'" === $first_char ) { return $first_char; @@ -230,7 +252,7 @@ private function stringToArray( $string, $delimiter = ' ' ) { } $array = explode( $delimiter, $string ); - $array = array_map('trim', $array ); + $array = array_map( 'trim', $array ); // Remove empties. return array_filter( $array ); @@ -253,25 +275,40 @@ public function lazyloadPictures( $html, $buffer ) { foreach ( $pictures as $picture ) { if ( $this->isExcluded( $picture[0], $excluded ) ) { + if ( ! preg_match( '#<img(?<atts>\s.+)\s?/?>#iUs', $picture[0], $img ) ) { + continue; + } + + $img = $this->canLazyload( $img ); + + if ( ! $img ) { + continue; + } + + $nolazy_picture = str_replace( '<img', '<img data-no-lazy=""', $picture[0] ); + $html = str_replace( $picture[0], $nolazy_picture, $html ); + continue; } if ( preg_match_all( '#<source(?<atts>\s.+)>#iUs', $picture['sources'], $sources, PREG_SET_ORDER ) ) { - $sources = array_unique( $sources, SORT_REGULAR ); - $lazy_sources = 0; + $sources = array_unique( $sources, SORT_REGULAR ); + $lazy_picture = $picture[0]; foreach ( $sources as $source ) { $lazyload_srcset = preg_replace( '/([\s"\'])srcset/i', '\1data-lazy-srcset', $source[0] ); - $html = str_replace( $source[0], $lazyload_srcset, $html ); + $lazy_picture = str_replace( $source[0], $lazyload_srcset, $lazy_picture ); unset( $lazyload_srcset ); $lazy_sources++; } - } - if ( 0 === $lazy_sources ) { - continue; + if ( 0 === $lazy_sources ) { + continue; + } + + $html = str_replace( $picture[0], $lazy_picture, $html ); } if ( ! preg_match( '#<img(?<atts>\s.+)\s?/?>#iUs', $picture[0], $img ) ) { @@ -284,10 +321,10 @@ public function lazyloadPictures( $html, $buffer ) { continue; } - $img_lazy = $this->replaceImage( $img ); + $img_lazy = $this->replaceImage( $img, false ); $img_lazy .= $this->noscript( $img[0] ); - $safe_img = str_replace('/', '\/', preg_quote( $img[0], '#' )); - $html = preg_replace( '#<noscript[^>]*>.*' . $safe_img . '.*<\/noscript>(*SKIP)(*FAIL)|' . $safe_img . '#iU', $img_lazy, $html ); + $safe_img = str_replace( '/', '\/', preg_quote( $img[0], '#' ) ); + $html = preg_replace( '#<noscript[^>]*>.*' . $safe_img . '.*<\/noscript>(*SKIP)(*FAIL)|' . $safe_img . '#i', $img_lazy, $html ); unset( $img_lazy ); } @@ -321,13 +358,6 @@ private function canLazyload( $image ) { return false; } - // Don't apply LazyLoad on images from WP Retina x2. - if ( function_exists( 'wr2x_picture_rewrite' ) ) { - if ( wr2x_get_retina( trailingslashit( ABSPATH ) . wr2x_get_pathinfo_from_image_src( trim( $image['src'], '"' ) ) ) ) { - return false; - } - } - return $image; } @@ -340,7 +370,7 @@ private function canLazyload( $image ) { */ public function isExcluded( $string, $excluded_values ) { if ( ! is_array( $excluded_values ) ) { - (array) $excluded_values; + $excluded_values = (array) $excluded_values; } if ( empty( $excluded_values ) ) { @@ -366,7 +396,6 @@ public function getExcludedAttributes() { * Filters the attributes used to prevent lazylad from being applied * * @since 1.0 - * @author Remy Perona * * @param array $excluded_attributes An array of excluded attributes. */ @@ -394,6 +423,7 @@ public function getExcludedAttributes() { 'avia-bg-style-fixed', 'data-skip-lazy', 'skip-lazy', + 'image-compare__', ] ); } @@ -408,7 +438,6 @@ public function getExcludedSrc() { * Filters the src used to prevent lazylad from being applied * * @since 1.0 - * @author Remy Perona * * @param array $excluded_src An array of excluded src. */ @@ -426,26 +455,43 @@ public function getExcludedSrc() { * Replaces the original image by the lazyload one * * @param array $image Array of matches elements. + * @param bool $use_native Use native lazyload. + * * @return string */ - private function replaceImage( $image ) { - $width = 0; - $height = 0; - - if ( preg_match( '@[\s"\']width\s*=\s*(\'|")(?<width>.*)\1@iUs', $image['atts'], $atts ) ) { - $width = absint( $atts['width'] ); - } - - if ( preg_match( '@[\s"\']height\s*=\s*(\'|")(?<height>.*)\1@iUs', $image['atts'], $atts ) ) { - $height = absint( $atts['height'] ); + private function replaceImage( $image, $use_native = true ) { + if ( empty( $image ) ) { + return ''; } - $placeholder_atts = preg_replace( '@\ssrc\s*=\s*(\'|")(?<src>.*)\1@iUs', ' src="' . $this->getPlaceholder( $width, $height ) . '"', $image['atts'] ); + $native_pattern = '@\sloading\s*=\s*(\'|")(?:lazy|auto)\1@i'; + $image_lazyload = $image[0]; - $image_lazyload = str_replace( $image['atts'], $placeholder_atts . ' data-lazy-src="' . $image['src'] . '"', $image[0] ); + if ( $use_native ) { + if ( preg_match( $native_pattern, $image[0] ) ) { + return $image[0]; + } - if ( ! preg_match( '@\sloading\s*=\s*(\'|")(?:lazy|auto)\1@i', $image_lazyload ) && apply_filters( 'rocket_use_native_lazyload', false ) ) { $image_lazyload = str_replace( '<img', '<img loading="lazy"', $image_lazyload ); + } else { + $width = 0; + $height = 0; + + if ( preg_match( '@[\s"\']width\s*=\s*(\'|")(?<width>.*)\1@iUs', $image['atts'], $atts ) ) { + $width = absint( $atts['width'] ); + } + + if ( preg_match( '@[\s"\']height\s*=\s*(\'|")(?<height>.*)\1@iUs', $image['atts'], $atts ) ) { + $height = absint( $atts['height'] ); + } + + $placeholder_atts = preg_replace( '@\ssrc\s*=\s*(\'|")(?<src>.*)\1@iUs', ' src="' . $this->getPlaceholder( $width, $height ) . '"', $image['atts'] ); + + $image_lazyload = str_replace( $image['atts'], $placeholder_atts . ' data-lazy-src="' . $image['src'] . '"', $image_lazyload ); + + if ( preg_match( $native_pattern, $image_lazyload ) ) { + $image_lazyload = preg_replace( $native_pattern, '', $image_lazyload ); + } } /** @@ -492,6 +538,10 @@ public function lazyloadResponsiveAttributes( $html ) { public function convertSmilies( $text ) { global $wp_smiliessearch; + if ( empty( $text ) || ! is_string( $text ) ) { + return $text; + } + if ( ! get_option( 'use_smilies' ) || empty( $wp_smiliessearch ) ) { return $text; } @@ -563,7 +613,7 @@ private function translateSmiley( $matches ) { * @param string $img Filename for the smiley image. * @param string $site_url Site URL, as returned by site_url(). */ - $src_url = apply_filters( 'smilies_src', includes_url( "images/smilies/$img" ), $img, site_url() ); + $src_url = apply_filters( 'smilies_src', includes_url( "images/smilies/$img" ), $img, site_url() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound // Don't LazyLoad if process is stopped for these reasons. if ( is_feed() || is_preview() ) { @@ -577,7 +627,6 @@ private function translateSmiley( $matches ) { * Returns the placeholder for the src attribute * * @since 1.2 - * @author Remy Perona * * @param int $width Width of the placeholder image. Default 0. * @param int $height Height of the placeholder image. Default 0. diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Activation/Activation.php b/wp-content/plugins/wp-rocket/inc/Engine/Activation/Activation.php index b0b493017..c60153ef4 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Activation/Activation.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Activation/Activation.php @@ -2,8 +2,15 @@ namespace WP_Rocket\Engine\Activation; -use WP_Rocket\Engine\Container\Container; +use WP_Rocket\Admin\Options; +use WP_Rocket\Dependencies\League\Container\Container; +use WP_Rocket\ServiceProvider\Options as OptionsServiceProvider; +use WP_Rocket\Engine\Preload\Activation\ServiceProvider as PreloadActivationServiceProvider; +use WP_Rocket\Engine\License\ServiceProvider as LicenseServiceProvider; +use WP_Rocket\Logger\ServiceProvider as LoggerServiceProvider; +use WP_Rocket\Engine\Media\AboveTheFold\Activation\ServiceProvider as AboveTheFoldActivationServiceProvider; use WP_Rocket\ThirdParty\Hostings\HostResolver; +use WP_Rocket\ThirdParty\Hostings\ServiceProvider as HostingsServiceProvider; /** * Plugin activation controller @@ -20,6 +27,9 @@ class Activation { 'advanced_cache', 'capabilities_manager', 'wp_cache', + 'action_scheduler_check', + 'preload_activation', + 'atf_activation', ]; /** @@ -31,8 +41,16 @@ public static function activate_plugin() { $container = new Container(); $container->add( 'template_path', WP_ROCKET_PATH . 'views' ); - $container->addServiceProvider( 'WP_Rocket\Engine\Activation\ServiceProvider' ); - $container->addServiceProvider( 'WP_Rocket\ThirdParty\Hostings\ServiceProvider' ); + $options_api = new Options( 'wp_rocket_' ); + $container->add( 'options_api', $options_api ); + $container->addServiceProvider( new OptionsServiceProvider() ); + $container->addServiceProvider( new PreloadActivationServiceProvider() ); + $container->addServiceProvider( new ServiceProvider() ); + $container->addServiceProvider( new HostingsServiceProvider() ); + $container->addServiceProvider( new LicenseServiceProvider() ); + $container->addServiceProvider( new LoggerServiceProvider() ); + $container->get( 'logger' ); + $container->addServiceProvider( new AboveTheFoldActivationServiceProvider() ); $host_type = HostResolver::get_host_service(); @@ -56,10 +74,8 @@ public static function activate_plugin() { require WP_ROCKET_FUNCTIONS_PATH . 'formatting.php'; require WP_ROCKET_FUNCTIONS_PATH . 'i18n.php'; require WP_ROCKET_FUNCTIONS_PATH . 'htaccess.php'; - - if ( class_exists( 'WPaaS\Plugin' ) ) { - require WP_ROCKET_3RD_PARTY_PATH . 'hosting/godaddy.php'; - } + require WP_ROCKET_FUNCTIONS_PATH . 'api.php'; + require WP_ROCKET_FUNCTIONS_PATH . 'admin.php'; /** * WP Rocket activation. @@ -87,14 +103,9 @@ public static function activate_plugin() { ] ); - wp_remote_get( - home_url(), - [ - 'timeout' => 0.01, - 'blocking' => false, - 'user-agent' => 'WP Rocket/Homepage Preload', - 'sslverify' => apply_filters( 'https_local_ssl_verify', false ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound - ] - ); + /** + * Fires after WP Rocket is activated + */ + do_action( 'rocket_after_activation' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Activation/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Activation/ServiceProvider.php index 41dff9ea8..eda25745b 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Activation/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Activation/ServiceProvider.php @@ -1,22 +1,19 @@ <?php namespace WP_Rocket\Engine\Activation; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; -use WP_Rocket\Engine\Container\ServiceProvider\BootableServiceProviderInterface; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\BootableServiceProviderInterface; +use WP_Rocket\Engine\Cache\AdvancedCache; +use WP_Rocket\Engine\Cache\WPCache; +use WP_Rocket\Engine\Capabilities\Manager; +use WP_Rocket\Engine\HealthCheck\ActionSchedulerCheck; /** * Service Provider for the activation process. - * - * @since 3.6.3 */ class ServiceProvider extends AbstractServiceProvider implements BootableServiceProviderInterface { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -24,30 +21,43 @@ class ServiceProvider extends AbstractServiceProvider implements BootableService 'advanced_cache', 'capabilities_manager', 'wp_cache', + 'action_scheduler_check', ]; + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + /** * Executes this method when the service provider is registered * * @return void */ - public function boot() { + public function boot(): void { $this->getContainer() - ->inflector( 'WP_Rocket\Engine\Activation\ActivationInterface' ) + ->inflector( ActivationInterface::class ) ->invokeMethod( 'activate', [] ); } /** * Registers the option array in the container. */ - public function register() { + public function register(): void { $filesystem = rocket_direct_filesystem(); - $this->getContainer()->add( 'advanced_cache', 'WP_Rocket\Engine\Cache\AdvancedCache' ) - ->withArgument( $this->getContainer()->get( 'template_path' ) . '/cache/' ) - ->withArgument( $filesystem ); - $this->getContainer()->add( 'capabilities_manager', 'WP_Rocket\Engine\Capabilities\Manager' ); - $this->getContainer()->add( 'wp_cache', 'WP_Rocket\Engine\Cache\WPCache' ) - ->withArgument( $filesystem ); + $this->getContainer()->add( 'advanced_cache', AdvancedCache::class ) + ->addArgument( $this->getContainer()->get( 'template_path' ) . '/cache/' ) + ->addArgument( $filesystem ); + $this->getContainer()->add( 'capabilities_manager', Manager::class ); + $this->getContainer()->add( 'wp_cache', WPCache::class ) + ->addArgument( $filesystem ); + $this->getContainer()->add( 'action_scheduler_check', ActionSchedulerCheck::class ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/API/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/API/ServiceProvider.php new file mode 100644 index 000000000..a418cd752 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/API/ServiceProvider.php @@ -0,0 +1,36 @@ +<?php + +namespace WP_Rocket\Engine\Admin\API; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; + +class ServiceProvider extends AbstractServiceProvider { + /** + * Array of services provided by this service provider + * + * @var array + */ + protected $provides = [ + 'admin_api_subscriber', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers the option array in the container + * + * @return void + */ + public function register(): void { + $this->getContainer()->add( 'admin_api_subscriber', Subscriber::class ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/API/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/API/Subscriber.php new file mode 100644 index 000000000..ae21cb197 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/API/Subscriber.php @@ -0,0 +1,82 @@ +<?php + +namespace WP_Rocket\Engine\Admin\API; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + + const ROUTE_NAMESPACE = 'wp-rocket/v1'; + + /** + * Return an array of events that this subscriber wants to listen to. + * + * @return string[] + */ + public static function get_subscribed_events() { + return [ + 'rest_api_init' => 'register_route', + 'admin_enqueue_scripts' => [ 'enqueue_url', 999 ], + ]; + } + + + /** + * Enqueue the URL for option exporting. + * + * @return void + */ + public function enqueue_url() { + wp_localize_script( + 'wpr-admin-common', + 'rocket_option_export', + [ + 'rest_url_option_export' => wp_nonce_url( admin_url( 'admin-post.php?action=rocket_export' ), 'rocket_export' ), + ] + ); + } + + /** + * Register REST route. + * + * @return void + */ + public function register_route() { + register_rest_route( + self::ROUTE_NAMESPACE, + 'options/export', + [ + 'methods' => 'GET', + 'callback' => [ $this, 'export_options' ], + 'permission_callback' => [ $this, 'has_permissions' ], + ] + ); + } + + /** + * Export options. + * + * @return void + */ + public function export_options() { + list( $filename, $options ) = rocket_export_options(); + + nocache_headers(); + @header( 'Content-Type: application/json' ); //phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + @header( 'Content-Disposition: attachment; filename="' . $filename . '"' ); //phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + @header( 'Content-Transfer-Encoding: binary' ); //phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + @header( 'Content-Length: ' . strlen( $options ) ); //phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + @header( 'Connection: close' ); //phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + echo $options; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + exit(); + } + + /** + * Has permission to use the API route. + * + * @return bool + */ + public function has_permissions() { + return current_user_can( 'rocket_manage_options' ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/ActionSchedulerSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/ActionSchedulerSubscriber.php new file mode 100644 index 000000000..e85536173 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/ActionSchedulerSubscriber.php @@ -0,0 +1,39 @@ +<?php + +namespace WP_Rocket\Engine\Admin; + +use WP_Rocket\Event_Management\Subscriber_Interface; +use WP_Rocket\ThirdParty\ReturnTypesTrait; + +class ActionSchedulerSubscriber implements Subscriber_Interface { + + use ReturnTypesTrait; + + /** + * Return an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'action_scheduler_check_pastdue_actions' => 'return_false', + 'action_scheduler_extra_action_counts' => 'hide_pastdue_status_filter', + ]; + } + + /** + * Hide past-due from status filter in Action Scheduler tools page. + * + * @param array $extra_actions Array with format action_count_identifier => action count. + * + * @return array + */ + public function hide_pastdue_status_filter( array $extra_actions ) { + if ( ! isset( $extra_actions['past-due'] ) ) { + return $extra_actions; + } + + unset( $extra_actions['past-due'] ); + return $extra_actions; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/Beacon.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/Beacon.php index 9e8b38f71..bdfa3fe2e 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/Beacon.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/Beacon.php @@ -41,7 +41,7 @@ class Beacon extends Abstract_Render implements Subscriber_Interface { /** * Constructor * - * @since 3.2 + * @since 3.2 * * @param Options_Data $options Options instance. * @param string $template_path Absolute path to the views/settings. @@ -75,7 +75,11 @@ public static function get_subscribed_events() { * @return void */ public function insert_script() { - if ( ! current_user_can( 'rocket_manage_options' ) ) { + if ( + rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT' ) + || + ! current_user_can( 'rocket_manage_options' ) + ) { return; } @@ -93,6 +97,7 @@ public function insert_script() { 'identify' => wp_json_encode( $this->identify_data() ), 'session' => wp_json_encode( $this->support_data->get_support_data() ), 'prefill' => wp_json_encode( $this->prefill_data() ), + 'config' => wp_json_encode( $this->config_data() ), ]; echo $this->generate( 'beacon', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped @@ -178,6 +183,21 @@ private function prefill_data() { return $prefill_data; } + /** + * Returns config data to pass to Beacon + * + * @since 3.8.5 + * + * @return array + */ + private function config_data(): array { + return [ + 'display' => [ + 'position' => is_rtl() ? 'left' : 'right', + ], + ]; + } + /** * Returns the IDs for the HelpScout docs for the corresponding section and language. * @@ -207,9 +227,14 @@ public function get_suggest( $doc_id ) { 'title' => 'My Site Is Broken', ], [ - 'id' => '54205957e4b099def9b55df0', - 'url' => 'https://docs.wp-rocket.me/article/19-resolving-issues-with-file-optimization/?utm_source=wp_plugin&utm_medium=wp_rocket', - 'title' => 'Resolving Issues with File Optimization', + 'id' => '6001a83b2e764327f87bf189', + 'url' => 'https://docs.wp-rocket.me/article/1407-eliminate-render-blocking-resources/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'title' => 'Eliminate Render Blocking Resources', + ], + [ + 'id' => '54e6f7e5e4b034c37ea9095f', + 'url' => 'https://docs.wp-rocket.me/article/46-how-to-check-if-wp-rocket-is-caching-your-pages/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'title' => 'How to check if WP Rocket is caching your pages', ], ], 'fr' => [ @@ -229,9 +254,14 @@ public function get_suggest( $doc_id ) { 'title' => 'Mon site est cassé', ], [ - 'id' => '56967d73c69791436155e637', - 'url' => 'https://fr.docs.wp-rocket.me/article/241-problemes-minification/?utm_source=wp_plugin&utm_medium=wp_rocket', - 'title' => "Résoudre les problèmes avec l'optimisation des fichiers", + 'id' => '601d4b83ac2f834ec5385ca5', + 'url' => 'https://fr.docs.wp-rocket.me/article/1440-eliminez-les-ressources-qui-bloquent-le-rendu/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'title' => 'Éliminez les ressources qui bloquent le rendu', + ], + [ + 'id' => '568fe9ebc69791436155cd32', + 'url' => 'https://fr.docs.wp-rocket.me/article/180-verifier-cache/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'title' => 'Comment vérifier si WP Rocket met bien en cache vos pages', ], ], ], @@ -297,26 +327,22 @@ public function get_suggest( $doc_id ) { 'url' => 'https://fr.docs.wp-rocket.me/article/1015-nonces-delai-nettoyage-cache/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], - 'basic_section' => [ - 'en' => '55231415e4b0221aadf25676,588286b32c7d3a4a60b95b6c,58869c492c7d3a7846303a3d', - 'fr' => '569568269033603f7da30334,58e3be72dd8c8e5c57311c6e,59b7f049042863033a1cc5d0', - ], 'css_section' => [ - 'en' => '54205957e4b099def9b55df0,5419ec47e4b099def9b5565f,5578cfbbe4b027e1978e6bb1,5569b671e4b027e1978e3c51,5923772c2c7d3a074e8ab8b9', - 'fr' => '56967d73c69791436155e637,56967e80c69791436155e646,56957209c69791436155e0f6,5697d2dc9033603f7da31041593fec6d2c7d3a0747cddb93', + 'en' => '556ef48ce4b01a224b428691,6001a83b2e764327f87bf189,5569b671e4b027e1978e3c51,5d5214d10428631e94f94ae6', + 'fr' => '5697d2dc9033603f7da31041,5d5abcce0428634552d85c1c,5697d03bc69791436155ed69,601d4b83ac2f834ec5385ca5', ], 'js_section' => [ - 'en' => '54205957e4b099def9b55df0,5419ec47e4b099def9b5565f,5578cfbbe4b027e1978e6bb1,587904cf90336009736c678e,54b9509de4b07997ea3f27c7,59236dfb0428634b4a3358f9', - 'fr' => '56967d73c69791436155e637,56967e80c69791436155e646,56957209c69791436155e0f6,58a337c12c7d3a576d352cde,56967eebc69791436155e649,593fe9882c7d3a0747cddb77', + 'en' => '54b9509de4b07997ea3f27c7,59236dfb0428634b4a3358f9,5f359695042863444aa04e26,556ef48ce4b01a224b428691,6001a83b2e764327f87bf189', + 'fr' => '56967eebc69791436155e649,593fe9882c7d3a0747cddb77,5f523c46c9e77c0016384ba0,5697d03bc69791436155ed69,601d4b83ac2f834ec5385ca5', ], 'file_optimization' => [ 'en' => [ - 'id' => '54205957e4b099def9b55df0', - 'url' => 'https://docs.wp-rocket.me/article/19-resolving-issues-with-file-optimization/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'id' => '6001a83b2e764327f87bf189', + 'url' => 'https://docs.wp-rocket.me/article/1407-eliminate-render-blocking-resources/?utm_source=wp_plugin&utm_medium=wp_rocket', ], 'fr' => [ - 'id' => '56967d73c69791436155e637', - 'url' => 'https://fr.docs.wp-rocket.me/article/241-problemes-minification/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'id' => '601d4b83ac2f834ec5385ca5', + 'url' => 'https://fr.docs.wp-rocket.me/article/1440-eliminez-les-ressources-qui-bloquent-le-rendu/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], 'combine' => [ @@ -329,17 +355,45 @@ public function get_suggest( $doc_id ) { 'url' => 'https://fr.docs.wp-rocket.me/article/1018-configuration-http-2/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], + 'remove_unused_css' => [ + 'en' => [ + 'id' => '6076083ff8c0ef2d98df1f97', + 'url' => 'https://docs.wp-rocket.me/article/1529-remove-unused-css?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '60d499a705ff892e6bc2a89e', + 'url' => 'https://fr.docs.wp-rocket.me/article/1577-supprimer-les-ressources-css-inutilisees?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], 'exclude_inline_js' => [ 'en' => [ 'id' => '5b4879100428630abc0c0713', 'url' => 'https://docs.wp-rocket.me/article/1104-excluding-inline-js-from-combine/?utm_source=wp_plugin&utm_medium=wp_rocket', ], + 'fr' => [ + 'id' => '5b4dd9290428631d7a89023c', + 'url' => 'https://fr.docs.wp-rocket.me/article/1109-exclure-les-js-inline-de-la-combinaison?utm_source=wp_plugin&utm_medium=wp_rocket', + ], ], 'exclude_js' => [ 'en' => [ 'id' => '54b9509de4b07997ea3f27c7', 'url' => 'https://docs.wp-rocket.me/article/39-excluding-external-js-from-concatenation/?utm_source=wp_plugin&utm_medium=wp_rocket', ], + 'fr' => [ + 'id' => '56967eebc69791436155e649', + 'url' => 'https://fr.docs.wp-rocket.me/article/243-exclure-js-externe-minification?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], + 'exclude_css' => [ + 'en' => [ + 'id' => '5bf339b12c7d3a31944e2111', + 'url' => 'https://docs.wp-rocket.me/article/1131-resolving-issues-with-css-minify-combine?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '5bf3bece04286304a71c6d35', + 'url' => 'https://fr.docs.wp-rocket.me/article/1132-resoudre-problemes-minification-combinaison-css?utm_source=wp_plugin&utm_medium=wp_rocket', + ], ], 'defer_js' => [ 'en' => [ @@ -356,6 +410,16 @@ public function get_suggest( $doc_id ) { 'id' => '5f359695042863444aa04e26', 'url' => 'https://docs.wp-rocket.me/article/1349-delay-javascript-execution/?utm_source=wp_plugin&utm_medium=wp_rocket', ], + 'fr' => [ + 'id' => '60e5b05605ff892e6bc2e86c', + 'url' => 'https://fr.docs.wp-rocket.me/article/1626-reporter-l-execution-du-javascript?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], + 'delay_js_exclusions' => [ + 'en' => [ + 'id' => '', + 'url' => 'https://docs.wp-rocket.me/article/1560-delay-javascript-execution-compatibility-exclusions/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], ], 'async' => [ 'en' => [ @@ -378,14 +442,18 @@ public function get_suggest( $doc_id ) { ], ], 'webp' => [ + 'fr' => [ + 'id' => '5d7b495e04286364bc8f12ef', + 'url' => 'https://fr.docs.wp-rocket.me/article/1286-compatibilite-webp?utm_source=wp_plugin&utm_medium=wp_rocket', + ], 'en' => [ 'id' => '5d72919704286364bc8ed49d', - 'url' => 'https://docs.wp-rocket.me/article/1282-webp', + 'url' => 'https://docs.wp-rocket.me/article/1282-webp?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], 'lazyload_section' => [ - 'en' => '5c884cf80428633d2cf38314,54b85754e4b0512429883a86,5418c792e4b0e7b8127bed99,569ec4a69033603f7da32c93,5419e246e4b099def9b5561e,5a299b332c7d3a1a640cb402', - 'fr' => '56967a859033603f7da30858,56967952c69791436155e60a,56cb9c9d90336008e9e9e3dc,569676ea9033603f7da3083d,5a3a66f52c7d3a1943676524', + 'en' => '5c884cf80428633d2cf38314,54b85754e4b0512429883a86,5418c792e4b0e7b8127bed99,569ec4a69033603f7da32c93,5419e246e4b099def9b5561e', + 'fr' => '56967a859033603f7da30858,56967952c69791436155e60a,56cb9c9d90336008e9e9e3dc,569676ea9033603f7da3083d', ], 'sitemap_preload' => [ 'en' => '541780fde4b005ed2d11784c,5a71c8ab2c7d3a4a4198a9b3,55b282ede4b0b0593824f852', @@ -395,6 +463,16 @@ public function get_suggest( $doc_id ) { 'en' => '541780fde4b005ed2d11784c,55b282ede4b0b0593824f852,559113eae4b027e1978eba11', 'fr' => '5693d582c69791436155d645,569433d1c69791436155d99c', ], + 'preload_exclusions' => [ + 'en' => [ + 'id' => '6349682bde258f5018eb456d', + 'url' => 'https://docs.wp-rocket.me/article/1721-exclude-urls-from-being-preloaded?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '63496d5b8a552811521e52d2', + 'url' => 'https://fr.docs.wp-rocket.me/article/1722-exclure-url-du-prechargement?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], 'bot' => [ 'en' => [ 'id' => '541780fde4b005ed2d11784c', @@ -406,8 +484,14 @@ public function get_suggest( $doc_id ) { ], ], 'dns_prefetch' => [ - 'en' => '541780fde4b005ed2d11784c', - 'fr' => '5693d582c69791436155d645', + 'en' => [ + 'id' => '5e055a602c7d3a7e9ae5881c', + 'url' => 'https://docs.wp-rocket.me/article/1302-prefetch-dns-requests/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '5e1891892c7d3a7e9ae60983', + 'url' => 'https://fr.docs.wp-rocket.me/article/1303-prechargement-requetes-dns/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], ], 'fonts_preload' => [ 'en' => [ @@ -424,27 +508,19 @@ public function get_suggest( $doc_id ) { 'id' => '5f35939b042863444aa04df9', 'url' => 'https://docs.wp-rocket.me/article/1348-preload-links/?utm_source=wp_plugin&utm_medium=wp_rocket', ], - ], - 'never_cache' => [ - 'en' => '5519ab03e4b061031402119f,559110d0e4b027e1978eba09,56b55ba49033600da1c0b687,553ac7bfe4b0eb143c62af44,587920b5c697915403a0e1f4,5569b671e4b027e1978e3c51', - 'fr' => '56941c0cc69791436155d8ab,56943395c69791436155d99a,56cb9ba990336008e9e9e3d9,56942fc3c69791436155d987,5879230cc697915403a0e211,5697d2dc9033603f7da31041', - ], - 'always_purge_section' => [ - 'en' => '555c7e9ee4b027e1978e17a,55151406e4b0610314020a3f,5632858890336002f86d903e,5792c0c1903360293603896b', - 'fr' => '568f7df49033603f7da2ec72,5694194d9033603f7da2fb00,56951208c69791436155de2a,57a4a0c3c697910783242008', - ], - 'query_strings' => [ - 'en' => '590a83610428634b4a32d52c', - 'fr' => '597a04fd042863033a1b6da4', + 'fr' => [ + 'id' => '5f58527cc9e77c001603746c', + 'url' => 'https://fr.docs.wp-rocket.me/article/1358-precharger-les-liens/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], ], 'ecommerce' => [ 'en' => [ - 'id' => '555c619ce4b027e1978e1767', - 'url' => 'https://docs.wp-rocket.me/article/75-is-wp-rocket-compatible-with-e-commerce-plugins/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'id' => '548f492de4b034fd4862493e', + 'url' => 'https://docs.wp-rocket.me/article/27-using-wp-rocket-on-your-ecommerce-site/?utm_source=wp_plugin&utm_medium=wp_rocket', ], 'fr' => [ - 'id' => '568f8291c69791436155caea', - 'url' => 'https://fr.docs.wp-rocket.me/article/176-compatibilite-extensions-e-commerce/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'id' => '569431189033603f7da2fc13', + 'url' => 'https://fr.docs.wp-rocket.me/article/198-ecommerce?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], 'cache_query_strings' => [ @@ -467,33 +543,37 @@ public function get_suggest( $doc_id ) { 'url' => 'https://fr.docs.wp-rocket.me/article/196-exclure-pages-cache/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], - 'always_purge' => [ + 'exclude_cookie' => [ 'en' => [ - 'id' => '555c7e9ee4b027e1978e17a5', - 'url' => 'https://docs.wp-rocket.me/article/78-how-often-is-the-cache-updated/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'id' => '5fe5462df24ccf588e3fe804', + 'url' => 'https://docs.wp-rocket.me/article/1382-never-cache-cookies/?utm_source=wp_plugin&utm_medium=wp_rocket', ], - 'fr' => [ - 'id' => '568f7df49033603f7da2ec72', - 'url' => 'https://fr.docs.wp-rocket.me/article/171-intervalle-cache/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'exclude_user_agent' => [ + 'en' => [ + 'id' => '5ff728d3551e0c2853f3a245', + 'url' => 'https://docs.wp-rocket.me/article/1389-never-cache-user-agents/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], - 'cleanup' => [ - 'en' => '55dcaa28e4b01d7a6a9bd373,578cd762c6979160ca1441cd,5569d11ae4b01a224b427725', - 'fr' => '5697cebbc69791436155ed5e,58b6e7a0dd8c8e56bfa819f5,5697cd85c69791436155ed50', + 'always_purge' => [ + 'en' => [ + 'id' => '5ff72b4dfd168b77735328b7', + 'url' => 'https://docs.wp-rocket.me/article/1391-always-purge-url-s/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], ], - 'slow_admin' => [ + 'db_optimization' => [ 'en' => [ - 'id' => '55dcaa28e4b01d7a6a9bd373', - 'url' => 'https://docs.wp-rocket.me/article/121-wp-admin-area-is-slow/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'id' => '60259156b3ebfb109b58182d', + 'url' => 'https://docs.wp-rocket.me/article/1443-database-optimizations-are-not-working/?utm_source=wp_plugin&utm_medium=wp_rocket', ], 'fr' => [ - 'id' => '5697cebbc69791436155ed5e', - 'url' => 'https://fr.docs.wp-rocket.me/article/260-la-zone-d-administration-wp-est-lente/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'id' => '6040c5b90a2dae5b58fb5d29', + 'url' => 'https://fr.docs.wp-rocket.me/article/1486-les-optimisations-de-la-base-de-donnees-ne-fonctionne-pas/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], 'cdn_section' => [ - 'en' => '54c7fa3de4b0512429885b5c,54205619e4b0e7b8127bf849,54a6d578e4b047ebb774a687,56b2b4459033603f7da37acf,566f749f9033603f7da28459,5434667fe4b0310ce5ee867a', - 'fr' => '5696830b9033603f7da308ac,5696837e9033603f7da308ae,569685749033603f7da308c0,57a4961190336059d4edc9d8,5697d5f8c69791436155ed8e,569684d29033603f7da308b9', + 'en' => '5e4c84bd04286364bc958833,54c7fa3de4b0512429885b5c,54a6d578e4b047ebb774a687,56b2b4459033603f7da37acf,566f749f9033603f7da28459,5434667fe4b0310ce5ee867a', + 'fr' => '5f351e42042863444aa04652,5696830b9033603f7da308ac,569685749033603f7da308c0,57a4961190336059d4edc9d8,5697d5f8c69791436155ed8e,569684d29033603f7da308b9', ], 'cdn' => [ 'en' => [ @@ -511,8 +591,18 @@ public function get_suggest( $doc_id ) { 'url' => 'https://docs.wp-rocket.me/article/1307-rocketcdn/?utm_source=wp_plugin&utm_medium=wp_rocket', ], 'fr' => [ - 'id' => '5e5e36712c7d3a7e9ae89555', - 'url' => 'https://fr.docs.wp-rocket.me/article/1308-rocketcdn/?utm_source=wp_plugin&utm_medium=wp_rocket', + 'id' => '5f351e42042863444aa04652', + 'url' => 'https://fr.docs.wp-rocket.me/article/1343-comment-utiliser-rocketcdn/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], + 'rocketcdn_error' => [ + 'en' => [ + 'id' => '60ddc72d9e87cb3d01249270', + 'url' => 'https://docs.wp-rocket.me/article/1608-error-notices-during-the-rocketcdn-subscription-process/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '60df1cb200fd0d7c253fc044', + 'url' => 'https://fr.docs.wp-rocket.me/article/1620-messages-derreur-pendant-le-processus-dabonnement/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], 'exclude_cdn' => [ @@ -555,6 +645,16 @@ public function get_suggest( $doc_id ) { 'url' => 'https://fr.docs.wp-rocket.me/article/247-utiliser-wp-rocket-avec-cloudflare/?utm_source=wp_plugin&utm_medium=wp_rocket#add-on', ], ], + 'cloudflare_apo' => [ + 'en' => [ + 'id' => '602593e90a2dae5b58faee1e', + 'url' => 'https://docs.wp-rocket.me/article/1444-using-cloudflare-apo-with-wp-rocket?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '6486cb4147772865db893c7c', + 'url' => 'https://fr.docs.wp-rocket.me/article/1757-utiliser-cloudflare-apo-avec-wp-rocket?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], 'sucuri_credentials' => [ 'en' => [ 'id' => '5bce07be2c7d3a04dd5bf94d', @@ -585,22 +685,6 @@ public function get_suggest( $doc_id ) { 'url' => 'https://fr.docs.wp-rocket.me/article/1124-controler-api-wordpress-heartbeat/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], - 'google_tracking' => [ - 'en' => [ - 'id' => '5b4693220428630abc0bf97b', - 'url' => 'https://docs.wp-rocket.me/article/1103-google-tracking-add-on/?utm_source=wp_plugin&utm_medium=wp_rocket', - ], - ], - 'facebook_tracking' => [ - 'en' => [ - 'id' => '5bc904e7042863158cc79d57', - 'url' => 'https://docs.wp-rocket.me/article/1117-facebook-pixel-add-on/?utm_source=wp_plugin&utm_medium=wp_rocket', - ], - 'fr' => [ - 'id' => '5bcf3d35042863215a46bb7f', - 'url' => 'https://fr.docs.wp-rocket.me/article/1123-add-on-facebook-pixel/?utm_source=wp_plugin&utm_medium=wp_rocket', - ], - ], 'google_fonts' => [ 'en' => [ 'id' => '5e8687c22c7d3a7e9aea4c4a', @@ -611,11 +695,25 @@ public function get_suggest( $doc_id ) { 'url' => 'https://fr.docs.wp-rocket.me/article/1314-optimiser-les-google-fonts/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], + 'dynamic_lists' => [ + 'en' => [ + 'id' => '63234712b0f178684ee3b04a', + 'url' => 'https://docs.wp-rocket.me/article/1716-dynamic-exclusions-and-inclusions/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '6323604341e1a47267b8d0e3', + 'url' => 'https://fr.docs.wp-rocket.me/article/1717-inclusions-et-exclusions-dynamiques/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], 'image_dimensions' => [ 'en' => [ 'id' => '5fc70216de1bfa158fb54737', 'url' => 'https://docs.wp-rocket.me/article/1366-add-missing-image-dimensions/?utm_source=wp_plugin&utm_medium=wp_rocket', ], + 'fr' => [ + 'id' => '5fd20dcab6c6251cd1c35079', + 'url' => 'https://fr.docs.wp-rocket.me/article/1369-ajouter-les-dimensions-dimage-manquantes/?utm_source=wp_plugin&utm_medium=wp_rocket', + ], ], 'exclude_defer_js' => [ 'en' => [ @@ -624,11 +722,95 @@ public function get_suggest( $doc_id ) { ], ], 'exclude_lazyload' => [ + 'fr' => [ + 'id' => '56967952c69791436155e60a', + 'url' => 'https://fr.docs.wp-rocket.me/article/235-desactivez-le-lazyload-sur-des-images-specifiques?utm_source=wp_plugin&utm_medium=wp_rocket', + ], 'en' => [ 'id' => '5418c792e4b0e7b8127bed99', 'url' => 'https://docs.wp-rocket.me/article/15-disabling-lazy-load-on-specific-images/?utm_source=wp_plugin&utm_medium=wp_rocket', ], ], + 'invalid_exclusions' => [ + 'en' => [ + 'id' => '619e90a3d3efbe495c3b26b8', + 'url' => 'https://docs.wp-rocket.me/article/1657-invalid-patterns-of-exclusions', + ], + 'fr' => [ + 'id' => '61b21c1297682b790dad345a', + 'url' => 'https://fr.docs.wp-rocket.me/article/1659-motifs-exclusion-non-valables', + ], + ], + 'async_opti' => [ + 'en' => [ + 'id' => '622a725a2ce7ed0fb0914056', + 'url' => 'https://docs.wp-rocket.me/article/1688-asynchronous-optimizations?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '6231fc24c1688a6d26a75ee1', + 'url' => 'https://fr.docs.wp-rocket.me/article/1689-optimisations-asynchrones?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], + 'offline' => [ + 'en' => [ + 'id' => '60623465c44f5d025f4491de', + 'url' => 'https://docs.wp-rocket.me/article/1514-private-intranet-offline?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '6065cb184466ce6ddc5f05fb', + 'url' => 'https://fr.docs.wp-rocket.me/article/1521-utiliser-wp-rocket-sur-un-intranet-prive-ou-hors-ligne?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], + 'fallback_css' => [ + 'en' => [ + 'id' => '5ec5c4072c7d3a5ea54b7de7', + 'url' => 'https://docs.wp-rocket.me/article/1321-critical-css-issues-fouc#use-fallback-critical-css', + ], + 'fr' => [ + 'id' => '5edf8a5504286306f804e1dc', + 'url' => 'https://fr.docs.wp-rocket.me/article/1327-problemes-critical-css-fouc#critical-path-css-de-secours', + ], + ], + 'domain_change' => [ + 'en' => [ + 'id' => '577578b1903360258a10d8ba', + 'url' => 'https://docs.wp-rocket.me/article/705-changing-domains-migrating-sites-with-wp-rocket?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '57868414c697912dee72a98a', + 'url' => 'https://fr.docs.wp-rocket.me/article/837-changer-de-domaine-migrer-un-site-avec-wp-rocket?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], + 'rucss_firewall_ips' => [ + 'en' => [ + 'id' => '6076083ff8c0ef2d98df1f97', + 'url' => 'https://docs.wp-rocket.me/article/1529-remove-unused-css?utm_source=wp_plugin&utm_medium=wp_rocket#basic-requirements', + ], + 'fr' => [ + 'id' => '60d499a705ff892e6bc2a89e', + 'url' => 'https://fr.docs.wp-rocket.me/article/1577-supprimer-les-ressources-css-inutilisees?utm_source=wp_plugin&utm_medium=wp_rocket#basic-requirements', + ], + ], + 'optimize_critical_images' => [ + 'en' => [ + 'id' => '662c1a144c3ddc1d4e7a1d25', + 'url' => 'https://docs.wp-rocket.me/article/1816-optimize-critical-images?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '6634e9fe0cfcb4508af6b290', + 'url' => 'https://fr.docs.wp-rocket.me/article/1819-optimiser-images-essentielle?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], + 'remove_cache_tab' => [ + 'en' => [ + 'id' => '6633b5df1009cb439ac6a432', + 'url' => 'https://docs.wp-rocket.me/article/1817-removal-of-the-cache-tab?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + 'fr' => [ + 'id' => '6634e9b21009cb439ac6a6fb', + 'url' => 'https://fr.docs.wp-rocket.me/article/1818-suppression-onglet-cache?utm_source=wp_plugin&utm_medium=wp_rocket', + ], + ], ]; return isset( $suggest[ $doc_id ][ $this->get_user_locale() ] ) diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/ServiceProvider.php index 8cfd3a130..46b3ef9f9 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Beacon/ServiceProvider.php @@ -1,22 +1,14 @@ <?php namespace WP_Rocket\Engine\Admin\Beacon; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; /** * Service Provider for Beacon - * - * @since 3.3 - * @author Remy Perona */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -25,17 +17,26 @@ class ServiceProvider extends AbstractServiceProvider { ]; /** - * Registers the option array in the container + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. * - * @since 3.3 - * @author Remy Perona + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { - $this->getContainer()->add( 'beacon', 'WP_Rocket\Engine\Admin\Beacon\Beacon' ) - ->withArgument( $this->getContainer()->get( 'options' ) ) - ->withArgument( $this->getContainer()->get( 'template_path' ) . '/settings' ) - ->withArgument( $this->getContainer()->get( 'support_data' ) ); + public function register(): void { + $this->getContainer()->addShared( 'beacon', Beacon::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'template_path' ) . '/settings' ) + ->addArgument( $this->getContainer()->get( 'support_data' ) ) + ->addTag( 'admin_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/classes/admin/Database/class-optimization.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/Optimization.php similarity index 64% rename from wp-content/plugins/wp-rocket/inc/classes/admin/Database/class-optimization.php rename to wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/Optimization.php index c1bad4766..367ad7c7e 100644 --- a/wp-content/plugins/wp-rocket/inc/classes/admin/Database/class-optimization.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/Optimization.php @@ -1,21 +1,14 @@ <?php -namespace WP_Rocket\Admin\Database; - -defined( 'ABSPATH' ) || exit; +namespace WP_Rocket\Engine\Admin\Database; /** * Handles the database optimization process. - * - * @since 2.11 - * @author Remy Perona */ class Optimization { /** * Background process instance * - * @since 2.11 - * @var Optimization_Process $process Background Process instance. - * @access protected + * @var OptimizationProcess $process Background Process instance. */ protected $process; @@ -23,29 +16,24 @@ class Optimization { * Array of option name/label pairs. * * @var array - * @access private */ private $options; /** * Class constructor. * - * @since 2.11 - * @author Remy Perona - * - * @param Optimization_Process $process Background process instance. + * @param OptimizationProcess $process Background process instance. */ - public function __construct( Optimization_Process $process ) { + public function __construct( OptimizationProcess $process ) { $this->process = $process; $this->options = [ - 'database_revisions' => __( 'Revisions', 'rocket' ), - 'database_auto_drafts' => __( 'Auto Drafts', 'rocket' ), - 'database_trashed_posts' => __( 'Trashed Posts', 'rocket' ), - 'database_spam_comments' => __( 'Spam Comments', 'rocket' ), - 'database_trashed_comments' => __( 'Trashed Comments', 'rocket' ), - 'database_expired_transients' => __( 'Expired transients', 'rocket' ), - 'database_all_transients' => __( 'Transients', 'rocket' ), - 'database_optimize_tables' => __( 'Tables', 'rocket' ), + 'database_revisions' => __( 'Revisions', 'rocket' ), + 'database_auto_drafts' => __( 'Auto Drafts', 'rocket' ), + 'database_trashed_posts' => __( 'Trashed Posts', 'rocket' ), + 'database_spam_comments' => __( 'Spam Comments', 'rocket' ), + 'database_trashed_comments' => __( 'Trashed Comments', 'rocket' ), + 'database_all_transients' => __( 'Transients', 'rocket' ), + 'database_optimize_tables' => __( 'Tables', 'rocket' ), ]; } @@ -53,7 +41,6 @@ public function __construct( Optimization_Process $process ) { * Get Database options * * @since 3.0.4 - * @author Remy Perona * * @return array */ @@ -65,7 +52,6 @@ public function get_options() { * Performs the database optimization * * @since 2.11 - * @author Remy Perona * * @param array $options WP Rocket Database options. */ @@ -83,7 +69,6 @@ public function process_handler( $options ) { * Count the number of items concerned by the database cleanup * * @since 2.8 - * @author Remy Perona * * @param string $type Item type to count. * @return int Number of items for this type @@ -109,10 +94,6 @@ public function count_cleanup_items( $type ) { case 'database_trashed_comments': $count = $wpdb->get_var( "SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE (comment_approved = 'trash' OR comment_approved = 'post-trashed')" ); break; - case 'database_expired_transients': - $time = isset( $_SERVER['REQUEST_TIME'] ) ? (int) $_SERVER['REQUEST_TIME'] : time(); - $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(option_name) FROM $wpdb->options WHERE option_name LIKE %s AND option_value < %d", $wpdb->esc_like( '_transient_timeout' ) . '%', $time ) ); - break; case 'database_all_transients': $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(option_id) FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s", $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_site_transient_' ) . '%' ) ); break; diff --git a/wp-content/plugins/wp-rocket/inc/classes/admin/Database/class-optimization-process.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/OptimizationProcess.php similarity index 82% rename from wp-content/plugins/wp-rocket/inc/classes/admin/Database/class-optimization-process.php rename to wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/OptimizationProcess.php index 82cfc96a3..a901588a4 100644 --- a/wp-content/plugins/wp-rocket/inc/classes/admin/Database/class-optimization-process.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/OptimizationProcess.php @@ -1,28 +1,24 @@ <?php -namespace WP_Rocket\Admin\Database; +namespace WP_Rocket\Engine\Admin\Database; use WP_Rocket_WP_Background_Process; /** * Extends the background process class for the database optimization background process. * - * @since 2.11 - * - * @see WP_Background_Process + * @see WP_Rocket_WP_Background_Process */ -class Optimization_Process extends WP_Rocket_WP_Background_Process { +class OptimizationProcess extends WP_Rocket_WP_Background_Process { /** * Prefix * * @var string - * @access protected */ protected $prefix = 'rocket'; /** * Specific action identifier for sitemap preload. * - * @access protected * @var string Action identifier */ protected $action = 'database_optimization'; @@ -30,7 +26,6 @@ class Optimization_Process extends WP_Rocket_WP_Background_Process { /** * Count the number of optimized items. * - * @access protected * @var array $count An array of indexed number of optimized items. */ protected $count = []; @@ -38,14 +33,13 @@ class Optimization_Process extends WP_Rocket_WP_Background_Process { /** * Dispatch * - * @access public - * @return array|WP_Error + * @return void */ public function dispatch() { set_transient( 'rocket_database_optimization_process', 'running', HOUR_IN_SECONDS ); // Perform remote post. - return parent::dispatch(); + parent::dispatch(); } /** @@ -114,20 +108,6 @@ protected function task( $item ) { $this->count[ $item ] = $number; } break; - case 'database_expired_transients': - $time = isset( $_SERVER['REQUEST_TIME'] ) ? (int) $_SERVER['REQUEST_TIME'] : time(); - $query = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s AND option_value < %d", $wpdb->esc_like( '_transient_timeout' ) . '%', $time ) ); - - if ( $query ) { - $number = 0; - foreach ( $query as $transient ) { - $key = str_replace( '_transient_timeout_', '', $transient ); - $number += (int) delete_transient( $key ); - } - - $this->count[ $item ] = $number; - } - break; case 'database_all_transients': $query = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s", $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_site_transient_' ) . '%' ) ); if ( $query ) { @@ -168,5 +148,4 @@ protected function complete() { parent::complete(); } - } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/ServiceProvider.php new file mode 100644 index 000000000..3f949943d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/ServiceProvider.php @@ -0,0 +1,46 @@ +<?php +namespace WP_Rocket\Engine\Admin\Database; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; + +/** + * Service Provider for database optimization + */ +class ServiceProvider extends AbstractServiceProvider { + /** + * Array of services provided by this service provider + * + * @var array + */ + protected $provides = [ + 'db_optimization_process', + 'db_optimization', + 'db_optimization_subscriber', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers the option array in the container + * + * @return void + */ + public function register(): void { + $this->getContainer()->add( 'db_optimization_process', OptimizationProcess::class ); + $this->getContainer()->add( 'db_optimization', Optimization::class ) + ->addArgument( $this->getContainer()->get( 'db_optimization_process' ) ); + $this->getContainer()->addShared( 'db_optimization_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'db_optimization' ) ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addTag( 'common_subscriber' ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/classes/subscriber/admin/Database/class-optimization-subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/Subscriber.php similarity index 91% rename from wp-content/plugins/wp-rocket/inc/classes/subscriber/admin/Database/class-optimization-subscriber.php rename to wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/Subscriber.php index 5132fa732..1162e906d 100644 --- a/wp-content/plugins/wp-rocket/inc/classes/subscriber/admin/Database/class-optimization-subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Database/Subscriber.php @@ -1,26 +1,18 @@ <?php -namespace WP_Rocket\Subscriber\Admin\Database; +namespace WP_Rocket\Engine\Admin\Database; use WP_Rocket\Event_Management\Subscriber_Interface; -use WP_Rocket\Admin\Database\Optimization; use WP_Rocket\Admin\Options_Data; -defined( 'ABSPATH' ) || exit; - /** * Subscriber for the database optimization - * - * @since 3.3 - * @author Remy Perona */ -class Optimization_Subscriber implements Subscriber_Interface { +class Subscriber implements Subscriber_Interface { /** * Optimization process instance. * * @since 3.4 - * @access private - * @author Grégory Viguier * * @var Optimization */ @@ -30,8 +22,6 @@ class Optimization_Subscriber implements Subscriber_Interface { * WP Rocket Options instance. * * @since 3.4 - * @access private - * @author Grégory Viguier * * @var Options_Data */ @@ -51,8 +41,7 @@ public function __construct( Optimization $optimize, Options_Data $options ) { /** * Return an array of events that this subscriber wants to listen to. * - * @since 3.3 - * @author Remy Perona + * @since 3.3 * * @return array */ @@ -73,9 +62,7 @@ public static function get_subscribed_events() { * Add a new interval for the cron job. * This adds a weekly/monthly interval for database optimization. * - * @since 3.4 - * @access public - * @author Grégory Viguier + * @since 3.4 * * @param array $schedules An array of intervals used by cron jobs. * @return array Updated array of intervals. @@ -108,7 +95,6 @@ public function add_cron_schedule( $schedules ) { * If the task is not programmed, it is automatically triggered * * @since 2.8 - * @author Remy Perona * * @see process_handler() */ @@ -126,7 +112,6 @@ public function database_optimization_scheduled() { * Database Optimization cron callback * * @since 3.0.4 - * @author Remy Perona */ public function cron_optimize() { $items = array_filter( array_keys( $this->optimize->get_options() ), [ $this->options, 'get' ] ); @@ -142,7 +127,6 @@ public function cron_optimize() { * Launches the database optimization when the settings are saved with optimize button * * @since 2.8 - * @author Remy Perona * * @see process_handler() * @@ -186,7 +170,6 @@ public function save_optimize( $value ) { * This notice is displayed after launching the database optimization process * * @since 2.11 - * @author Remy Perona */ public function notice_process_running() { $screen = get_current_screen(); @@ -217,7 +200,6 @@ public function notice_process_running() { * This notice is displayed when the database optimization process is complete * * @since 2.11 - * @author Remy Perona */ public function notice_process_complete() { $screen = get_current_screen(); diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Deactivation/DeactivationIntent.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Deactivation/DeactivationIntent.php index 8e0fb1ccc..b8b1f35cc 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Deactivation/DeactivationIntent.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Deactivation/DeactivationIntent.php @@ -2,26 +2,11 @@ namespace WP_Rocket\Engine\Admin\Deactivation; +use WP_Rocket\Abstract_Render; use WP_Rocket\Admin\Options; use WP_Rocket\Admin\Options_Data; -use WP_Rocket\Event_Management\Subscriber_Interface; -use WP_Rocket\Interfaces\Render_Interface; - -/** - * Deactivation intent form on plugins page - * - * @since 3.0 - */ -class DeactivationIntent implements Subscriber_Interface { - /** - * Render Interface - * - * @since 3.0 - * - * @var Render_Interface - */ - private $render; +class DeactivationIntent extends Abstract_Render { /** * Options instance. * @@ -43,74 +28,85 @@ class DeactivationIntent implements Subscriber_Interface { * * @since 3.0 * - * @param Render_Interface $render Render interface. - * @param Options $options_api Options instance. - * @param Options_Data $options Options_Data instance. + * @param string $template Template path. + * @param Options $options_api Options instance. + * @param Options_Data $options Options_Data instance. */ - public function __construct( Render_Interface $render, Options $options_api, Options_Data $options ) { - $this->render = $render; + public function __construct( $template, Options $options_api, Options_Data $options ) { + parent::__construct( $template ); + $this->options_api = $options_api; $this->options = $options; } /** - * Return an array of events that this subscriber wants to listen to. + * Checks if the deactivation modal is snoozed * - * @since 3.0 + * @since 3.11.1 * - * @return array + * @return bool */ - public static function get_subscribed_events() { - return [ - 'admin_print_footer_scripts-plugins.php' => 'insert_mixpanel_tracking', - 'admin_footer' => 'insert_deactivation_intent_form', - 'wp_ajax_rocket_safe_mode' => 'activate_safe_mode', - ]; + private function is_snoozed(): bool { + if ( 1 === (int) get_option( 'wp_rocket_hide_deactivation_form', 0 ) ) { + return true; + } + + if ( false !== get_transient( 'rocket_hide_deactivation_form' ) ) { + return true; + } + + return false; } /** - * Inserts mixpanel tracking on plugins page to send deactivation data + * Inserts the deactivation intent form on plugins page * * @since 3.0 * * @return void */ - public function insert_mixpanel_tracking() { - ?> - <!-- start Mixpanel --><script type="text/javascript">(function(e,a){if(!a.__SV){var b=window;try{var c,l,i,j=b.location,g=j.hash;c=function(a,b){return(l=a.match(RegExp(b+"=([^&]*)")))?l[1]:null};g&&c(g,"state")&&(i=JSON.parse(decodeURIComponent(c(g,"state"))),"mpeditor"===i.action&&(b.sessionStorage.setItem("_mpcehash",g),history.replaceState(i.desiredHash||"",e.title,j.pathname+j.search)))}catch(m){}var k,h;window.mixpanel=a;a._i=[];a.init=function(b,c,f){function e(b,a){var c=a.split(".");2==c.length&&(b=b[c[0]],a=c[1]);b[a]=function(){b.push([a].concat(Array.prototype.slice.call(arguments, -0)))}}var d=a;"undefined"!==typeof f?d=a[f]=[]:f="mixpanel";d.people=d.people||[];d.toString=function(b){var a="mixpanel";"mixpanel"!==f&&(a+="."+f);b||(a+=" (stub)");return a};d.people.toString=function(){return d.toString(1)+".people (stub)"};k="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config reset people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" "); -for(h=0;h<k.length;h++)e(d,k[h]);a._i.push([b,c,f])};a.__SV=1.2;b=e.createElement("script");b.type="text/javascript";b.async=!0;b.src="undefined"!==typeof MIXPANEL_CUSTOM_LIB_URL?MIXPANEL_CUSTOM_LIB_URL:"file:"===e.location.protocol&&"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js".match(/^\/\//)?"https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js":"//cdn.mxpnl.com/libs/mixpanel-2-latest.min.js";c=e.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c)}})(document,window.mixpanel||[]); - -mixpanel.init("a36067b00a263cce0299cfd960e26ecf", { - 'ip':false, - property_blacklist: ['$initial_referrer', '$current_url', '$initial_referring_domain', '$referrer', '$referring_domain'] - } ); - - mixpanel.track_links( '#mixpanel-send-deactivation', 'Deactivation Intent', function(ele) { - return { - 'Reason': document.getElementById('wpr-reason').value, - 'Details': document.getElementById('wpr-details').value, - } - } ); - </script><!-- end Mixpanel --> - <?php + public function insert_deactivation_intent_form() { + if ( $this->is_snoozed() ) { + return; + } + + $data = [ + 'form_action' => admin_url( 'admin-post.php?action=rocket_deactivation' ), + ]; + + echo $this->generate( 'form', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view. } /** - * Inserts the deactivation intent form on plugins page + * Deactivate the plugin and set the snooze value * - * @since 3.0 + * @since 3.11.1 + * + * @param int $snooze Snooze value. * * @return void */ - public function insert_deactivation_intent_form() { - $current_screen = get_current_screen(); + public function deactivate_and_snooze( $snooze ) { + $this->set_snooze( $snooze ); + deactivate_plugins( 'wp-rocket/wp-rocket.php' ); + } - if ( 'plugins' !== $current_screen->id && 'plugins-network' !== $current_screen->id ) { + /** + * Sets the snooze value + * + * @since 3.11.1 + * + * @param int $snooze Snooze value. + * + * @return void + */ + private function set_snooze( int $snooze ) { + if ( 0 === $snooze ) { + add_option( 'wp_rocket_hide_deactivation_form', 1 ); return; } - $this->render->render_form(); + set_transient( 'rocket_hide_deactivation_form', 1, $snooze * DAY_IN_SECONDS ); } /** @@ -121,13 +117,6 @@ public function insert_deactivation_intent_form() { * @return void */ public function activate_safe_mode() { - check_ajax_referer( 'rocket-ajax', 'nonce' ); - - if ( ! current_user_can( 'rocket_manage_options' ) ) { - wp_send_json_error(); - return; - } - /** * Filters the array of options to reset when activating safe mode * @@ -138,24 +127,71 @@ public function activate_safe_mode() { $reset_options = apply_filters( 'rocket_safe_mode_reset_options', [ - 'embeds' => 0, - 'defer_all_js' => 0, - 'async_css' => 0, - 'lazyload' => 0, - 'lazyload_iframes' => 0, - 'lazyload_youtube' => 0, - 'minify_css' => 0, - 'minify_concatenate_css' => 0, - 'minify_js' => 0, - 'minify_concatenate_js' => 0, - 'minify_google_fonts' => 0, - 'cdn' => 0, + 'async_css' => 0, + 'lazyload' => 0, + 'lazyload_iframes' => 0, + 'lazyload_youtube' => 0, + 'minify_css' => 0, + 'minify_js' => 0, + 'minify_concatenate_js' => 0, + 'defer_all_js' => 0, + 'delay_js' => 0, + 'remove_unused_css' => 0, + 'minify_google_fonts' => 0, + 'cdn' => 0, ] ); $this->options->set_values( $reset_options ); $this->options_api->set( 'settings', $this->options->get_options() ); + } + + /** + * Add modal assets on the plugins page + * + * @since 3.11.1 + * + * @param string $hook The current admin page. + * + * @return void + */ + public function add_modal_assets( $hook ) { + if ( 'plugins.php' !== $hook ) { + return; + } + + if ( $this->is_snoozed() ) { + return; + } + + wp_enqueue_style( 'wpr-modal', rocket_get_constant( 'WP_ROCKET_ASSETS_CSS_URL' ) . 'wpr-modal.css', null, rocket_get_constant( 'WP_ROCKET_VERSION' ) ); + wp_enqueue_script( 'micromodal', rocket_get_constant( 'WP_ROCKET_ASSETS_JS_URL' ) . 'micromodal.min.js', null, '0.4.10', true ); + wp_add_inline_script( + 'micromodal', + 'window.addEventListener("DOMContentLoaded", (event) => { + document.getElementById("deactivate-wp-rocket").addEventListener("click", (event) => {event.preventDefault();});MicroModal.init(); + });' + ); + } + + /** + * Add data attribute to WP Rocket deactivation link for the modal + * + * @since 3.11.1 + * + * @param string[] $actions An array of plugin action links. + * + * @return array + */ + public function add_data_attribute( $actions ) { + if ( ! isset( $actions['deactivate'] ) ) { + return $actions; + } + + $deactivate_link = str_replace( '<a', '<a data-micromodal-trigger="wpr-deactivation-modal"', $actions['deactivate'] ); + + $actions['deactivate'] = $deactivate_link; - wp_send_json_success(); + return $actions; } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Deactivation/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Deactivation/Subscriber.php new file mode 100644 index 000000000..5122a89bb --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Deactivation/Subscriber.php @@ -0,0 +1,107 @@ +<?php + +namespace WP_Rocket\Engine\Admin\Deactivation; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + /** + * DeactivationIntent instance + * + * @var DeactivationIntent + */ + private $deactivation; + + /** + * Constructor + * + * @param DeactivationIntent $deactivation DeactivationIntent instance. + */ + public function __construct( DeactivationIntent $deactivation ) { + $this->deactivation = $deactivation; + } + + /** + * Return an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'admin_footer-plugins.php' => 'insert_deactivation_intent_form', + 'admin_enqueue_scripts' => 'add_modal_assets', + 'admin_post_rocket_deactivation' => 'safe_mode_or_deactivate', + 'plugin_action_links_wp-rocket/wp-rocket.php' => 'add_data_attribute', + ]; + } + + /** + * Inserts the deactivation intent form on plugins page + * + * @since 3.11.1 + * + * @return void + */ + public function insert_deactivation_intent_form() { + $this->deactivation->insert_deactivation_intent_form(); + } + + /** + * Add modal assets on the plugins page + * + * @since 3.11.1 + * + * @param string $hook The current admin page. + * + * @return void + */ + public function add_modal_assets( $hook ) { + $this->deactivation->add_modal_assets( $hook ); + } + + /** + * Apply safe mode or deactivate the plugin + * + * @since 3.11.1 + * + * @return void + */ + public function safe_mode_or_deactivate() { + check_admin_referer( 'rocket_deactivation', '_wpnonce' ); + + $referer = wp_get_referer(); + + if ( ! current_user_can( 'manage_options' ) ) { + wp_safe_redirect( $referer ); + exit; + } + + $mode = isset( $_POST['mode'] ) ? sanitize_key( $_POST['mode'] ) : ''; + + if ( 'safe_mode' === $mode ) { + $this->deactivation->activate_safe_mode(); + } elseif ( 'deactivate' === $mode ) { + $snooze = isset( $_POST['snooze'] ) ? absint( $_POST['snooze'] ) : 0; + + $this->deactivation->deactivate_and_snooze( $snooze ); + + $referer = add_query_arg( 'deactivate', '1', $referer ); + } + + wp_safe_redirect( $referer ); + exit; + } + + /** + * Add data attribute to WP Rocket deactivation link for the modal + * + * @since 3.11.1 + * + * @param string[] $actions An array of plugin action links. + * + * @return array + */ + public function add_data_attribute( $actions ): array { + return $this->deactivation->add_data_attribute( $actions ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/DomainChange/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/DomainChange/ServiceProvider.php new file mode 100644 index 000000000..7c93f13c9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/DomainChange/ServiceProvider.php @@ -0,0 +1,41 @@ +<?php + +namespace WP_Rocket\Engine\Admin\DomainChange; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Common\Ajax\AjaxHandler; + +class ServiceProvider extends AbstractServiceProvider { + /** + * Array of services provided by this service provider + * + * @var array + */ + protected $provides = [ + 'domain_change_subscriber', + 'ajax_handler', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container + * + * @return void + */ + public function register(): void { + $this->getContainer()->add( 'ajax_handler', AjaxHandler::class ); + $this->getContainer()->add( 'domain_change_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'ajax_handler' ) ) + ->addArgument( $this->getContainer()->get( 'beacon' ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/DomainChange/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/DomainChange/Subscriber.php new file mode 100644 index 000000000..3ecaee764 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/DomainChange/Subscriber.php @@ -0,0 +1,210 @@ +<?php + +namespace WP_Rocket\Engine\Admin\DomainChange; + +use WP_Rocket\Engine\Admin\Beacon\Beacon; +use WP_Rocket\Engine\Common\Ajax\AjaxHandler; +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + + /** + * Handle basic ajax operations. + * + * @var AjaxHandler + */ + protected $ajax_handler; + + /** + * Beacon instance + * + * @var Beacon + */ + protected $beacon; + + /** + * Name of the option saving the last base URL. + * + * @var string + */ + const LAST_BASE_URL_OPTION = 'wp_rocket_last_base_url'; + + /** + * Instantiate the class. + * + * @param AjaxHandler $ajax_handler Handle basic ajax operations. + * @param Beacon $beacon Beacon instance. + */ + public function __construct( AjaxHandler $ajax_handler, Beacon $beacon ) { + $this->ajax_handler = $ajax_handler; + $this->beacon = $beacon; + } + + /** + * Return an array of events that this subscriber wants to listen to. + * + * @return string[] + */ + public static function get_subscribed_events() { + + return [ + 'admin_init' => 'maybe_launch_domain_changed', + 'admin_notices' => 'maybe_display_domain_change_notice', + 'rocket_domain_changed' => 'maybe_clean_cache_domain_change', + 'rocket_notice_args' => 'add_regenerate_configuration_action', + 'admin_post_rocket_regenerate_configuration' => 'regenerate_configuration', + ]; + } + + /** + * Maybe launch the domain changed event. + * + * @return void + */ + public function maybe_launch_domain_changed() { + if ( wp_doing_ajax() ) { + return; + } + + $base_url = trailingslashit( get_option( 'home' ) ); + $base_url_encoded = base64_encode( $base_url ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode + $last_base_url_encoded = get_option( self::LAST_BASE_URL_OPTION ); + + if ( ! $last_base_url_encoded ) { + update_option( self::LAST_BASE_URL_OPTION, $base_url_encoded, true ); + return; + } + + if ( $base_url_encoded === $last_base_url_encoded ) { + return; + } + + update_option( self::LAST_BASE_URL_OPTION, $base_url_encoded, true ); + + $last_base_url = base64_decode( $last_base_url_encoded ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode + + set_transient( 'rocket_domain_changed', $last_base_url_encoded, 2 * rocket_get_constant( 'WEEK_IN_SECONDS', 604800 ) ); + + /** + * Fires when the domain of the website has been changed. + * + * @param string $current_url current URL from the website. + * @param string $old_url old URL from the website. + */ + do_action( 'rocket_detected_domain_changed', $base_url, $last_base_url ); + } + + /** + * Maybe clean cache on domain change. + * + * @return void + */ + public function maybe_clean_cache_domain_change() { + + $options = get_option( rocket_get_constant( 'WP_ROCKET_SLUG' ) ); + + if ( ! $options ) { + return; + } + + /** + * Fires after WP Rocket options that require a cache purge have changed + * + * @param array $value An array of submitted values for the settings. + */ + do_action( 'rocket_domain_options_changed', $options ); + } + + /** + * Maybe display a notice when domain change. + * + * @return void + */ + public function maybe_display_domain_change_notice() { + + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + + $notice = get_transient( 'rocket_domain_changed' ); + + if ( ! $notice || is_multisite() ) { + return; + } + + $beacon = $this->beacon->get_suggest( 'domain_change' ); + + $args = [ + 'status' => 'warning', + 'dismissible' => '', + 'dismiss_button' => false, + 'message' => sprintf( + // translators: %1$s = <strong>, %2$s = </strong>, %3$s = <a>, %4$s = </a>. + __( '%1$sWP Rocket:%2$s We detected that the website domain has changed. The configuration files must be regenerated for the page cache and all other optimizations to work as intended. %3$sLearn More%4$s', 'rocket' ), + '<strong>', + '</strong>', + '<a href="' . esc_url( $beacon['url'] ) . '" data-beacon-article="' . esc_attr( $beacon['id'] ) . '" target="_blank" rel="noopener noreferrer">', + '</a>' + ), + 'action' => 'regenerate_configuration', + ]; + + rocket_notice_html( $args ); + } + + /** + * Add mapping on notice. + * + * @param array $args Arguments from the notice. + * + * @return array + */ + public function add_regenerate_configuration_action( $args ) { + if ( ! key_exists( 'action', $args ) || 'regenerate_configuration' !== $args['action'] ) { + return $args; + } + + $params = [ + 'action' => 'rocket_regenerate_configuration', + ]; + + $args['action'] = '<a class="wp-core-ui button" href="' . add_query_arg( $params, wp_nonce_url( admin_url( 'admin-post.php' ), 'rocket_regenerate_configuration' ) ) . '">' . __( 'Regenerate WP Rocket configuration files now', 'rocket' ) . '</a>'; + + return $args; + } + + /** + * Regenerate configurations. + * + * @return void + */ + public function regenerate_configuration() { + if ( ! $this->ajax_handler->validate_referer( + 'rocket_regenerate_configuration', + 'rocket_manage_options' + ) ) { + return; + } + + $last_base_url_encoded = get_transient( 'rocket_domain_changed' ); + + if ( ! $last_base_url_encoded ) { + return; + } + + $last_base_url = base64_decode( $last_base_url_encoded ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode + $base_url = trailingslashit( get_option( 'home' ) ); + + /** + * Fires when the domain of the website has been changed and user clicked on notice. + * + * @param string $current_url current URL from the website. + * @param string $old_url old URL from the website. + */ + do_action( 'rocket_domain_changed', $base_url, $last_base_url ); + + delete_transient( 'rocket_domain_changed' ); + + $this->ajax_handler->redirect(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Metaboxes/PostEditOptionsSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Metaboxes/PostEditOptionsSubscriber.php new file mode 100644 index 000000000..ab096d8ba --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Metaboxes/PostEditOptionsSubscriber.php @@ -0,0 +1,205 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Admin\Metaboxes; + +use WP_Rocket\Abstract_Render; +use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Event_Management\Subscriber_Interface; + +class PostEditOptionsSubscriber extends Abstract_Render implements Subscriber_Interface { + /** + * Options instance + * + * @var Options_data + */ + private $options; + + /** + * Constructor + * + * @param Options_Data $options Options instance. + * @param string $template_path Path to the views. + */ + public function __construct( Options_Data $options, $template_path ) { + parent::__construct( $template_path ); + + $this->options = $options; + } + + /** + * Return an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'add_meta_boxes' => 'options_metabox', + 'save_post' => 'save_metabox_options', + ]; + } + + /** + * Add options metabox on post edit page + * + * @return void + */ + public function options_metabox() { + if ( ! rocket_can_display_options() ) { + return; + } + + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + + $cpts = get_post_types( + [ + 'public' => true, + ], + 'objects' + ); + + unset( $cpts['attachment'] ); + + /** + * Filters the post types to add the options metabox to + * + * @param array $cpts Array of post types. + */ + $cpts = apply_filters( 'rocket_metabox_options_post_types', $cpts ); + + foreach ( $cpts as $cpt => $cpt_object ) { + $label = $cpt_object->labels->singular_name; + add_meta_box( 'rocket_post_exclude', sprintf( __( 'WP Rocket Options', 'rocket' ), $label ), [ $this, 'display_metabox' ], $cpt, 'side', 'core' ); + } + } + + /** + * Displays checkboxes to de/activate some options + * + * @return void + */ + public function display_metabox() { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + + global $post, $pagenow; + + $excluded_url = false; + + if ( 'post-new.php' !== $pagenow ) { + $path = rocket_clean_exclude_file( get_permalink( $post->ID ) ); + + if ( in_array( $path, $this->options->get( 'cache_reject_uri', [] ), true ) ) { + $excluded_url = true; + } + } + + $original_fields = []; + + /** + * WP Rocket Metabox fields on post edit page. + * + * @param string[] $original_fields Metaboxes fields. + */ + $fields = apply_filters( 'rocket_meta_boxes_fields', $original_fields ); + + if ( ! is_array( $fields ) ) { + $fields = $original_fields; + } + + $fields_attributes = []; + + foreach ( $fields as $field => $label ) { + $disabled = disabled( ! $this->options->get( $field ), true, false ); + + $fields_attributes[ $field ]['id'] = $field; + $fields_attributes[ $field ]['label'] = $label; + // translators: %s is the name of the option. + $fields_attributes[ $field ]['title'] = $disabled ? ' title="' . esc_attr( sprintf( __( 'Activate first the %s option.', 'rocket' ), $label ) ) . '"' : ''; + $fields_attributes[ $field ]['class'] = $disabled ? ' class="rkt-disabled"' : ''; + $fields_attributes[ $field ]['checked'] = ! $disabled ? checked( ! get_post_meta( $post->ID, '_rocket_exclude_' . $field, true ), true, false ) : ''; + $fields_attributes[ $field ]['disabled'] = $disabled; + } + + echo $this->generate( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + 'post_edit_options', + [ + 'excluded_url' => $excluded_url, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + 'fields' => $fields_attributes, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + ] + ); + } + + /** + * Updates the options from the metabox. + * + * @return void + */ + public function save_metabox_options() { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + + if ( ! isset( $_POST['post_ID'], $_POST['rocket_post_exclude_hidden'] ) ) { + return; + } + + check_admin_referer( 'rocket_box_option', '_rocketnonce' ); + + // No cache field. + if ( isset( $_POST['post_status'] ) && 'publish' === $_POST['post_status'] ) { + $new_cache_reject_uri = $cache_reject_uri = $this->options->get( 'cache_reject_uri', [] ); // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found + $rejected_uris = array_flip( $cache_reject_uri ); + $path = rocket_clean_exclude_file( get_permalink( (int) $_POST['post_ID'] ) ); + + if ( isset( $_POST['rocket_post_nocache'] ) ) { + if ( ! isset( $rejected_uris[ $path ] ) ) { + array_push( $new_cache_reject_uri, $path ); + } + } elseif ( isset( $rejected_uris[ $path ] ) ) { + unset( $new_cache_reject_uri[ $rejected_uris[ $path ] ] ); + } + + if ( $new_cache_reject_uri !== $cache_reject_uri ) { + // Update the "Never cache the following pages" option. + update_rocket_option( 'cache_reject_uri', $new_cache_reject_uri ); + + // Update config file. + rocket_generate_config_file(); + } + } + + $original_fields = []; + + /** + * Metaboxes fields. + * + * @param string[] $original_fields Metaboxes fields. + */ + $fields = apply_filters( 'rocket_meta_boxes_fields', $original_fields ); + + if ( ! is_array( $fields ) ) { + $fields = $original_fields; + } + + $fields = array_keys( $fields ); + + foreach ( $fields as $field ) { + if ( ! isset( $_POST['rocket_post_exclude_hidden'][ $field ] ) ) { + continue; + } + + if ( isset( $_POST['rocket_post_exclude'][ $field ] ) ) { + delete_post_meta( (int) $_POST['post_ID'], '_rocket_exclude_' . $field ); + continue; + } + + if ( $this->options->get( $field ) ) { + update_post_meta( (int) $_POST['post_ID'], '_rocket_exclude_' . $field, true ); + } + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/ServiceProvider.php index 67164ca88..d5b845560 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Admin/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/ServiceProvider.php @@ -1,45 +1,61 @@ <?php namespace WP_Rocket\Engine\Admin; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Admin\Deactivation\{DeactivationIntent, Subscriber}; +use WP_Rocket\Engine\Admin\Metaboxes\PostEditOptionsSubscriber; +use WP_Rocket\ThirdParty\Plugins\Optimization\Hummingbird; /** * Service Provider for admin subscribers. - * - * @since 3.3 */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ protected $provides = [ - 'deactivation_intent_render', + 'deactivation_intent', 'deactivation_intent_subscriber', 'hummingbird_subscriber', + 'actionscheduler_admin_subscriber', + 'post_edit_options_subscriber', ]; /** - * Registers the option array in the container. + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * - * @since 3.3 + * @return void */ - public function register() { + public function register(): void { $options = $this->getContainer()->get( 'options' ); - $this->getContainer()->add( 'deactivation_intent_render', 'WP_Rocket\Admin\Deactivation\Render' ) - ->withArgument( $this->getContainer()->get( 'template_path' ) . '/deactivation-intent' ); - $this->getContainer()->share( 'deactivation_intent_subscriber', 'WP_Rocket\Engine\Admin\Deactivation\DeactivationIntent' ) - ->withArgument( $this->getContainer()->get( 'deactivation_intent_render' ) ) - ->withArgument( $this->getContainer()->get( 'options_api' ) ) - ->withArgument( $options ); - $this->getContainer()->share( 'hummingbird_subscriber', 'WP_Rocket\ThirdParty\Plugins\Optimization\Hummingbird' ) - ->withArgument( $options ); + $this->getContainer()->add( 'deactivation_intent', DeactivationIntent::class ) + ->addArgument( $this->getContainer()->get( 'template_path' ) . '/deactivation-intent' ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ) + ->addArgument( $options ); + $this->getContainer()->addShared( 'deactivation_intent_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'deactivation_intent' ) ) + ->addTag( 'admin_subscriber' ); + $this->getContainer()->addShared( 'hummingbird_subscriber', Hummingbird::class ) + ->addArgument( $options ) + ->addTag( 'admin_subscriber' ); + $this->getContainer()->addShared( 'actionscheduler_admin_subscriber', ActionSchedulerSubscriber::class ); + $this->getContainer()->addShared( 'post_edit_options_subscriber', PostEditOptionsSubscriber::class ) + ->addArgument( $options ) + ->addArgument( $this->getContainer()->get( 'template_path' ) . '/metaboxes' ) + ->addTag( 'admin_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Page.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Page.php index ab4b60839..a8dd03a27 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Page.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Page.php @@ -1,10 +1,14 @@ <?php namespace WP_Rocket\Engine\Admin\Settings; -use WP_Rocket\Admin\Database\Optimization; +use WP_Rocket\Engine\Admin\Database\Optimization; use WP_Rocket\Engine\Admin\Beacon\Beacon; use WP_Rocket\Engine\License\API\UserClient; +use WP_Rocket\Engine\Optimization\DelayJS\Admin\SiteList; use WP_Rocket\Interfaces\Render_Interface; +use WP_Rocket\Engine\Optimization\DelayJS\Admin\Settings as DelayJSSettings; +use WP_Rocket\Abstract_Render; +use WP_Rocket\Admin\Options_Data; /** * Registers the admin page and WP Rocket settings. @@ -12,7 +16,7 @@ * @since 3.5.5 Moves into the new architecture. * @since 3.0 */ -class Page { +class Page extends Abstract_Render { /** * Plugin slug. * @@ -54,7 +58,7 @@ class Page { * * @since 3.0 * - * @var Render_Interface + * @var Render */ private $render; @@ -83,6 +87,20 @@ class Page { */ private $user_client; + /** + * Delay JS Site List controller. + * + * @var SiteList + */ + protected $delayjs_sitelist; + + /** + * WP Rocket options instance + * + * @var Options_Data + */ + private $options; + /** * Creates an instance of the Page object. * @@ -94,8 +112,22 @@ class Page { * @param Beacon $beacon Beacon instance. * @param Optimization $optimize Database optimization instance. * @param UserClient $user_client User client instance. + * @param SiteList $delayjs_sitelist User client instance. + * @param string $template_path Path to views. + * @param Options_Data $options WP Rocket options instance. */ - public function __construct( array $args, Settings $settings, Render_Interface $render, Beacon $beacon, Optimization $optimize, UserClient $user_client ) { + public function __construct( + array $args, + Settings $settings, + Render_Interface $render, + Beacon $beacon, + Optimization $optimize, + UserClient $user_client, + SiteList $delayjs_sitelist, + $template_path, + Options_Data $options + ) { + parent::__construct( $template_path ); $args = array_merge( [ 'slug' => 'wprocket', @@ -105,14 +137,16 @@ public function __construct( array $args, Settings $settings, Render_Interface $ $args ); - $this->slug = $args['slug']; - $this->title = $args['title']; - $this->capability = $args['capability']; - $this->settings = $settings; - $this->render = $render; - $this->beacon = $beacon; - $this->optimize = $optimize; - $this->user_client = $user_client; + $this->slug = $args['slug']; + $this->title = $args['title']; + $this->capability = $args['capability']; + $this->settings = $settings; + $this->render = $render; + $this->beacon = $beacon; + $this->optimize = $optimize; + $this->user_client = $user_client; + $this->delayjs_sitelist = $delayjs_sitelist; + $this->options = $options; } /** @@ -166,7 +200,6 @@ public function render_page() { $rocket_valid_key = rocket_valid_key(); if ( $rocket_valid_key ) { $this->dashboard_section(); - $this->cache_section(); $this->assets_section(); $this->media_section(); $this->preload_section(); @@ -243,33 +276,17 @@ public function async_wistia_script( $tag, $handle ) { public function customer_data() { $user = $this->user_client->get_user_data(); $data = [ - 'license_type' => __( 'Unavailable', 'rocket' ), - 'license_expiration' => __( 'Unavailable', 'rocket' ), - 'license_class' => 'wpr-isInvalid', + 'license_type' => __( 'Unavailable', 'rocket' ), + 'license_expiration' => __( 'Unavailable', 'rocket' ), + 'license_class' => 'wpr-isInvalid', + 'is_from_one_dot_com' => false, ]; - if ( - false === $user - || - ! isset( $user->licence_account, $user->licence_expiration ) - ) { - return $data; - } + $data['license_type'] = rocket_get_license_type( $user ); - if ( - 1 <= $user->licence_account - && - $user->licence_account < 3 - ) { - $data['license_type'] = 'Single'; - } elseif ( -1 === (int) $user->licence_account ) { - $data['license_type'] = 'Infinite'; - } else { - $data['license_type'] = 'Plus'; - } - - $data['license_class'] = time() < $user->licence_expiration ? 'wpr-isValid' : 'wpr-isInvalid'; - $data['license_expiration'] = date_i18n( get_option( 'date_format' ), (int) $user->licence_expiration ); + $data['license_class'] = time() < $user->licence_expiration ? 'wpr-isValid' : 'wpr-isInvalid'; + $data['license_expiration'] = date_i18n( get_option( 'date_format' ), (int) $user->licence_expiration ); + $data['is_from_one_dot_com'] = (bool) $user->{'has_one-com_account'}; return $data; } @@ -292,10 +309,10 @@ public function toggle_option() { 'varnish_auto_purge' => 1, 'do_cloudflare' => 1, 'cloudflare_protocol_rewrite' => 1, - 'google_analytics_cache' => 1, - 'facebook_pixel_cache' => 1, 'sucury_waf_cache_sync' => 1, 'sucury_waf_api_key' => 1, + 'cache_webp' => 1, + 'cache_logged_user' => 1, ]; if ( ! isset( $_POST['option']['name'] ) || ! isset( $allowed[ $_POST['option']['name'] ] ) ) { @@ -428,137 +445,43 @@ private function dashboard_section() { } /** - * Registers Cache section. + * Registers CSS & Javascript section. * * @since 3.0 */ - private function cache_section() { - $mobile_cache_beacon = $this->beacon->get_suggest( 'mobile_cache' ); - $user_cache_beacon = $this->beacon->get_suggest( 'user_cache' ); - $nonce_beacon = $this->beacon->get_suggest( 'nonce' ); - $cache_life_beacon = $this->beacon->get_suggest( 'cache_lifespan' ); + private function assets_section() { + $combine_beacon = $this->beacon->get_suggest( 'combine' ); + $defer_js_beacon = $this->beacon->get_suggest( 'defer_js' ); + $async_beacon = $this->beacon->get_suggest( 'async' ); + $files_beacon = $this->beacon->get_suggest( 'file_optimization' ); + $inline_js_beacon = $this->beacon->get_suggest( 'exclude_inline_js' ); + $exclude_js_beacon = $this->beacon->get_suggest( 'exclude_js' ); + $exclude_css_beacon = $this->beacon->get_suggest( 'exclude_css' ); + $delay_js_beacon = $this->beacon->get_suggest( 'delay_js' ); + $delay_js_exclusions_beacon = $this->beacon->get_suggest( 'delay_js_exclusions' ); + $exclude_defer_js = $this->beacon->get_suggest( 'exclude_defer_js' ); + $rucss_beacon = $this->beacon->get_suggest( 'remove_unused_css' ); + $offline_beacon = $this->beacon->get_suggest( 'offline' ); + $fallback_css_beacon = $this->beacon->get_suggest( 'fallback_css' ); + + $disable_combine_js = $this->disable_combine_js(); + $disable_combine_css = $this->disable_combine_css(); + $disable_ocd = 'local' === wp_get_environment_type(); - $this->settings->add_page_section( - 'cache', + /** + * Filters the status of the RUCSS option. + * + * @param array $should_disable will return array with disable status and text. + */ + $rucss_status = apply_filters( + 'rocket_disable_rucss_setting', [ - 'title' => __( 'Cache', 'rocket' ), - 'menu_description' => __( 'Basic cache options', 'rocket' ), + 'disable' => false, + 'text' => '', ] ); - $this->settings->add_settings_sections( - [ - 'mobile_cache_section' => [ - 'title' => __( 'Mobile Cache', 'rocket' ), - 'type' => 'fields_container', - 'description' => __( 'Speed up your site for mobile visitors.', 'rocket' ), - 'help' => [ - 'url' => $mobile_cache_beacon['url'], - 'id' => $this->beacon->get_suggest( 'mobile_cache_section' ), - ], - 'helper' => rocket_is_mobile_plugin_active() ? __( 'We detected you use a plugin that requires a separate cache for mobile, and automatically enabled this option for compatibility.', 'rocket' ) : '', - 'page' => 'cache', - ], - 'user_cache_section' => [ - 'title' => __( 'User Cache', 'rocket' ), - 'type' => 'fields_container', - // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( '%1$sUser cache%2$s is great when you have user-specific or restricted content on your website.', 'rocket' ), '<a href="' . esc_url( $user_cache_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $user_cache_beacon['id'] ) . '" target="_blank">', '</a>' ), - 'help' => [ - 'url' => $user_cache_beacon['url'], - 'id' => $this->beacon->get_suggest( 'user_cache_section' ), - ], - 'page' => 'cache', - ], - 'cache_lifespan' => [ - 'title' => __( 'Cache Lifespan', 'rocket' ), - 'type' => 'fields_container', - // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( 'Cache files older than the specified lifespan will be deleted.<br>Enable %1$spreloading%2$s for the cache to be rebuilt automatically after lifespan expiration.', 'rocket' ), '<a href="#preload">', '</a>' ), - 'help' => [ - 'url' => $cache_life_beacon['url'], - 'id' => $this->beacon->get_suggest( 'cache_lifespan_section' ), - ], - 'page' => 'cache', - ], - ] - ); - - $this->settings->add_settings_fields( - [ - 'cache_logged_user' => [ - 'type' => 'checkbox', - 'label' => __( 'Enable caching for logged-in WordPress users', 'rocket' ), - 'section' => 'user_cache_section', - 'page' => 'cache', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ], - 'cache_mobile' => [ - 'type' => 'checkbox', - 'label' => __( 'Enable caching for mobile devices', 'rocket' ), - 'container_class' => [ - rocket_is_mobile_plugin_active() ? 'wpr-isDisabled' : '', - 'wpr-isParent', - ], - 'section' => 'mobile_cache_section', - 'page' => 'cache', - 'default' => 1, - 'sanitize_callback' => 'sanitize_checkbox', - 'input_attr' => [ - 'disabled' => rocket_is_mobile_plugin_active() ? 1 : 0, - ], - ], - 'do_caching_mobile_files' => [ - 'type' => 'checkbox', - 'label' => __( 'Separate cache files for mobile devices', 'rocket' ), - // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( 'Most modern themes are responsive and should work without a separate cache. Enable this only if you have a dedicated mobile theme or plugin. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $mobile_cache_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $mobile_cache_beacon['id'] ) . '" target="_blank">', '</a>' ), - 'container_class' => [ - rocket_is_mobile_plugin_active() ? 'wpr-isDisabled' : '', - 'wpr-field--children', - ], - 'parent' => 'cache_mobile', - 'section' => 'mobile_cache_section', - 'page' => 'cache', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - 'input_attr' => [ - 'disabled' => rocket_is_mobile_plugin_active() ? 1 : 0, - ], - ], - 'purge_cron_interval' => [ - 'type' => 'cache_lifespan', - 'label' => __( 'Specify time after which the global cache is cleared<br>(0 = unlimited )', 'rocket' ), - // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( 'Reduce lifespan to 10 hours or less if you notice issues that seem to appear periodically. %1$sWhy?%2$s', 'rocket' ), '<a href="' . esc_url( $nonce_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $nonce_beacon['id'] ) . '" target="_blank">', '</a>' ), - 'section' => 'cache_lifespan', - 'page' => 'cache', - 'default' => 10, - 'sanitize_callback' => 'sanitize_cache_lifespan', - 'choices' => [ - 'HOUR_IN_SECONDS' => __( 'Hours', 'rocket' ), - 'DAY_IN_SECONDS' => __( 'Days', 'rocket' ), - ], - ], - ] - ); - } - - /** - * Registers CSS & Javascript section. - * - * @since 3.0 - */ - private function assets_section() { - $combine_beacon = $this->beacon->get_suggest( 'combine' ); - $defer_js_beacon = $this->beacon->get_suggest( 'defer_js' ); - $async_beacon = $this->beacon->get_suggest( 'async' ); - $files_beacon = $this->beacon->get_suggest( 'file_optimization' ); - $inline_js_beacon = $this->beacon->get_suggest( 'exclude_inline_js' ); - $exclude_js_beacon = $this->beacon->get_suggest( 'exclude_js' ); - $delay_js_beacon = $this->beacon->get_suggest( 'delay_js' ); - $exclude_defer_js = $this->beacon->get_suggest( 'exclude_defer_js' ); + $invalid_license = get_option( 'wp_rocket_no_licence' ); $this->settings->add_page_section( 'file_optimization', @@ -568,6 +491,17 @@ private function assets_section() { ] ); + $css_section_helper = []; + + if ( rocket_maybe_disable_minify_css() ) { + // translators: %1$s = type of minification (HTML, CSS or JS), %2$s = “WP Rocket”. + $css_section_helper[] = sprintf( __( '%1$s Minification is currently activated in <strong>Autoptimize</strong>. If you want to use %2$s’s minification, disable this option in Autoptimize.', 'rocket' ), 'CSS', WP_ROCKET_PLUGIN_NAME ); + } + + if ( $rucss_status['disable'] ) { + $css_section_helper[] = $rucss_status['text']; + } + $this->settings->add_settings_sections( [ 'css' => [ @@ -577,8 +511,7 @@ private function assets_section() { 'url' => $files_beacon['url'], ], 'page' => 'file_optimization', - // translators: %1$s = type of minification (HTML, CSS or JS), %2$s = “WP Rocket”. - 'helper' => rocket_maybe_disable_minify_css() ? sprintf( __( '%1$s Minification is currently activated in <strong>Autoptimize</strong>. If you want to use %2$s’s minification, disable those options in Autoptimize.', 'rocket' ), 'CSS', WP_ROCKET_PLUGIN_NAME ) : '', + 'helper' => $css_section_helper, ], 'js' => [ 'title' => __( 'JavaScript Files', 'rocket' ), @@ -593,9 +526,26 @@ private function assets_section() { ] ); + $delay_js_list_helper = esc_html__( 'If you have problems after activating this option, copy and paste the default exclusions to quickly resolve issues:', 'rocket' ); + $delay_js_list_helper .= sprintf( '<br><pre><code>%1$s</code></pre><br>', implode( '<br>', DelayJSSettings::get_delay_js_default_exclusions() ) ); + $delay_js_list_helper .= sprintf( + // translators: %1$s = opening </a> tag, %2$s = closing </a> tag. + esc_html__( 'Also, please check our %1$sdocumentation%2$s for a list of compatibility exclusions.', 'rocket' ), + '<a href="' . esc_url( $delay_js_exclusions_beacon['url'] ) . '" target="_blank" rel="noopener">', + '</a>' + ); + + $delay_js_found_list_helper = esc_html__( 'Internal scripts are excluded by default to prevent issues. Remove them to take full advantage of this option.', 'rocket' ); + $delay_js_found_list_helper .= '<br>' . sprintf( + // translators: %1$s = opening </a> tag, %2$s = closing </a> tag. + esc_html__( 'If this causes trouble, restore the default exclusions, found %1$shere%2$s', 'rocket' ), + '<a href="' . esc_url( $delay_js_beacon['url'] ) . '" target="_blank" rel="noopener">', + '</a>' + ); + $this->settings->add_settings_fields( [ - 'minify_css' => [ + 'minify_css' => [ 'type' => 'checkbox', 'label' => __( 'Minify CSS files', 'rocket' ), 'description' => __( 'Minify CSS removes whitespace and comments to reduce the file size.', 'rocket' ), @@ -616,35 +566,13 @@ private function assets_section() { 'button_label' => __( 'Activate minify CSS', 'rocket' ), ], ], - 'minify_concatenate_css' => [ - 'type' => 'checkbox', - 'label' => __( 'Combine CSS files <em>(Enable Minify CSS files to select)</em>', 'rocket' ), - // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( 'Combine CSS merges all your files into 1, reducing HTTP requests. Not recommended if your site uses HTTP/2. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $combine_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $combine_beacon['id'] ) . '" target="_blank">', '</a>' ), - 'container_class' => [ - get_rocket_option( 'minify_css' ) ? '' : 'wpr-isDisabled', - 'wpr-field--parent', - ], - 'section' => 'css', - 'page' => 'file_optimization', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - 'input_attr' => [ - 'disabled' => get_rocket_option( 'minify_css' ) ? 0 : 1, - ], - 'warning' => [ - 'title' => __( 'This could break things!', 'rocket' ), - 'description' => __( 'If you notice any errors on your website after having activated this setting, just deactivate it again, and your site will be back to normal.', 'rocket' ), - 'button_label' => __( 'Activate combine CSS', 'rocket' ), - ], - ], - 'exclude_css' => [ + 'exclude_css' => [ 'type' => 'textarea', 'label' => __( 'Excluded CSS Files', 'rocket' ), - 'description' => __( 'Specify URLs of CSS files to be excluded from minification and concatenation (one per line).', 'rocket' ), + 'description' => __( 'Specify URLs of CSS files to be excluded from minification (one per line).', 'rocket' ), 'helper' => __( '<strong>Internal:</strong> The domain part of the URL will be stripped automatically. Use (.*).css wildcards to exclude all CSS files located at a specific path.', 'rocket' ) . '<br>' . // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - sprintf( __( '<strong>3rd Party:</strong> Use either the full URL path or only the domain name, to exclude external CSS. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $exclude_js_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $exclude_js_beacon['id'] ) . '" rel="noopener noreferrer" target="_blank">', '</a>' ), + sprintf( __( '<strong>3rd Party:</strong> Use either the full URL path or only the domain name, to exclude external CSS. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $exclude_css_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $exclude_css_beacon['id'] ) . '" rel="noopener noreferrer" target="_blank">', '</a>' ), 'container_class' => [ 'wpr-field--children', ], @@ -655,41 +583,99 @@ private function assets_section() { 'default' => [], 'sanitize_callback' => 'sanitize_textarea', ], - 'async_css' => [ + 'optimize_css_delivery' => [ 'type' => 'checkbox', 'label' => __( 'Optimize CSS delivery', 'rocket' ), 'container_class' => [ - is_plugin_active( 'wp-criticalcss/wp-criticalcss.php' ) ? 'wpr-isDisabled' : '', + $disable_ocd ? 'wpr-isDisabled' : '', 'wpr-isParent', ], - 'description' => is_plugin_active( 'wp-criticalcss/wp-criticalcss.php' ) ? - // translators: %1$s = plugin name. - sprintf( _x( 'Optimize CSS Delivery is currently handled by the %1$s plugin. If you want to use WP Rocket’s Optimize CSS Delivery option, disable the %1$s plugin.', 'WP Critical CSS compatibility', 'rocket' ), 'WP Critical CSS' ) : - // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - sprintf( __( 'Optimize CSS delivery eliminates render-blocking CSS on your website for faster perceived load time. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $async_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $async_beacon['id'] ) . '" target="_blank">', '</a>' ), + 'description' => $invalid_license ? __( 'Optimize CSS delivery eliminates render-blocking CSS on your website. Only one method can be selected. Remove Unused CSS is recommended for optimal performance, but limited only to the users with active license.', 'rocket' ) : __( 'Optimize CSS delivery eliminates render-blocking CSS on your website. Only one method can be selected. Remove Unused CSS is recommended for optimal performance.', 'rocket' ), 'section' => 'css', 'page' => 'file_optimization', 'default' => 0, 'sanitize_callback' => 'sanitize_checkbox', 'input_attr' => [ - 'disabled' => is_plugin_active( 'wp-criticalcss/wp-criticalcss.php' ) ? 1 : 0, + 'disabled' => $disable_ocd ? 1 : 0, ], + 'helper' => $disable_ocd ? sprintf( + // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. + __( 'Optimize CSS Delivery features are disabled on local environments. %1$sLearn more%2$s', 'rocket' ), + '<a href="' . esc_url( $offline_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $offline_beacon['id'] ) . '" target="_blank">', + '</a>' + ) : '', ], - 'critical_css' => [ - 'type' => 'textarea', - 'label' => __( 'Fallback critical CSS', 'rocket' ), - 'container_class' => [ + 'optimize_css_delivery_method' => [ + 'type' => 'radio_buttons', + 'label' => __( 'Optimize CSS delivery', 'rocket' ), + 'container_class' => [ 'wpr-field--children', + 'wpr-field--optimize-css-delivery', + ], + 'buttons_container_class' => '', + 'parent' => 'optimize_css_delivery', + 'section' => 'css', + 'page' => 'file_optimization', + 'default' => 'remove_unused_css', + 'sanitize_callback' => 'sanitize_checkbox', + 'options' => [ + 'remove_unused_css' => [ + 'label' => __( 'Remove Unused CSS', 'rocket' ), + 'disabled' => $invalid_license || $rucss_status['disable'] ? 'disabled' : false, + // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. + 'description' => sprintf( __( 'Removes unused CSS per page and helps to reduce page size and HTTP requests. Recommended for best performance. Test thoroughly! %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $rucss_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $rucss_beacon['id'] ) . '" target="_blank">', '</a>' ), + 'warning' => $invalid_license ? [] : [ + 'title' => __( 'This could break things!', 'rocket' ), + 'description' => __( 'If you notice any errors on your website after having activated this setting, just deactivate it again, and your site will be back to normal.', 'rocket' ), + 'button_label' => __( 'Activate Remove Unused CSS', 'rocket' ), + ], + 'sub_fields' => $invalid_license ? [] : [ + 'remove_unused_css_safelist' => + [ + 'type' => 'textarea', + 'label' => __( 'CSS safelist', 'rocket' ), + 'description' => __( 'Specify CSS filenames, IDs or classes that should not be removed (one per line).', 'rocket' ), + 'placeholder' => "/wp-content/plugins/some-plugin/(.*).css\n.css-class\n#css_id\ntag", + 'default' => [], + 'value' => [], + 'sanitize_callback' => 'sanitize_textarea', + 'parent' => '', + 'section' => 'css', + 'page' => 'file_optimization', + 'input_attr' => [ + 'disabled' => get_rocket_option( 'remove_unused_css' ) ? 0 : 1, + ], + ], + ], + ], + 'async_css' => [ + 'label' => __( 'Load CSS asynchronously', 'rocket' ), + 'description' => is_plugin_active( 'wp-criticalcss/wp-criticalcss.php' ) ? + // translators: %1$s = plugin name. + sprintf( _x( 'Load CSS asynchronously is currently handled by the %1$s plugin. If you want to use WP Rocket’s load CSS asynchronously option, disable the %1$s plugin.', 'WP Critical CSS compatibility', 'rocket' ), 'WP Critical CSS' ) : + // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. + sprintf( __( 'Generates critical path CSS and loads CSS asynchronously. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $async_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $async_beacon['id'] ) . '" target="_blank">', '</a>' ), + 'disabled' => is_plugin_active( 'wp-criticalcss/wp-criticalcss.php' ) ? 'disabled' : '', + 'sub_fields' => [ + 'critical_css' => + [ + 'type' => 'textarea', + 'label' => __( 'Fallback critical CSS', 'rocket' ), + // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. + 'helper' => sprintf( __( 'Provides a fallback if auto-generated critical path CSS is incomplete. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $fallback_css_beacon['url'] ) . '#fallback" data-beacon-article="' . esc_attr( $fallback_css_beacon['id'] ) . '" target="_blank">', '</a>' ), + 'sanitize_callback' => 'sanitize_textarea', + 'parent' => '', + 'section' => 'css', + 'page' => 'file_optimization', + 'placeholder' => '', + 'default' => [], + 'value' => [], + ], + ], + ], ], - // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'helper' => sprintf( __( 'Provides a fallback if auto-generated critical path CSS is incomplete. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $async_beacon['url'] ) . '#fallback" data-beacon-article="' . esc_attr( $async_beacon['id'] ) . '" target="_blank">', '</a>' ), - 'parent' => 'async_css', - 'section' => 'css', - 'page' => 'file_optimization', - 'default' => [], - 'sanitize_callback' => 'sanitize_textarea', ], - 'minify_js' => [ + 'minify_js' => [ 'type' => 'checkbox', 'label' => __( 'Minify JavaScript files', 'rocket' ), 'description' => __( 'Minify JavaScript removes whitespace and comments to reduce the file size.', 'rocket' ), @@ -710,21 +696,23 @@ private function assets_section() { 'button_label' => __( 'Activate minify JavaScript', 'rocket' ), ], ], - 'minify_concatenate_js' => [ + 'minify_concatenate_js' => [ 'type' => 'checkbox', 'label' => __( 'Combine JavaScript files <em>(Enable Minify JavaScript files to select)</em>', 'rocket' ), // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. 'description' => sprintf( __( 'Combine JavaScript files combines your site’s internal, 3rd party and inline JS reducing HTTP requests. Not recommended if your site uses HTTP/2. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $combine_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $combine_beacon['id'] ) . '" target="_blank">', '</a>' ), + 'helper' => get_rocket_option( 'delay_js' ) ? __( 'For compatibility and best results, this option is disabled when delay javascript execution is enabled.', 'rocket' ) : '', 'container_class' => [ - get_rocket_option( 'minify_js' ) ? '' : 'wpr-isDisabled', + $disable_combine_js ? 'wpr-isDisabled' : '', 'wpr-field--parent', + 'wpr-NoPaddingBottom', ], 'section' => 'js', 'page' => 'file_optimization', 'default' => 0, 'sanitize_callback' => 'sanitize_checkbox', 'input_attr' => [ - 'disabled' => get_rocket_option( 'minify_js' ) ? 0 : 1, + 'disabled' => $disable_combine_js ? 1 : 0, ], 'warning' => [ 'title' => __( 'This could break things!', 'rocket' ), @@ -732,7 +720,7 @@ private function assets_section() { 'button_label' => __( 'Activate combine JavaScript', 'rocket' ), ], ], - 'exclude_inline_js' => [ + 'exclude_inline_js' => [ 'type' => 'textarea', 'label' => __( 'Excluded Inline JavaScript', 'rocket' ), // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. @@ -750,7 +738,7 @@ private function assets_section() { 'disabled' => get_rocket_option( 'minify_concatenate_js' ) ? 0 : 1, ], ], - 'exclude_js' => [ + 'exclude_js' => [ 'type' => 'textarea', 'label' => __( 'Excluded JavaScript Files', 'rocket' ), 'description' => __( 'Specify URLs of JavaScript files to be excluded from minification and concatenation (one per line).', 'rocket' ), @@ -767,7 +755,7 @@ private function assets_section() { 'default' => [], 'sanitize_callback' => 'sanitize_textarea', ], - 'defer_all_js' => [ + 'defer_all_js' => [ 'container_class' => [ 'wpr-isParent', ], @@ -780,7 +768,7 @@ private function assets_section() { 'default' => 0, 'sanitize_callback' => 'sanitize_checkbox', ], - 'exclude_defer_js' => [ + 'exclude_defer_js' => [ 'container_class' => [ 'wpr-field--children', ], @@ -795,25 +783,45 @@ private function assets_section() { 'default' => [], 'sanitize_callback' => 'sanitize_textarea', ], - 'delay_js' => [ + 'delay_js' => apply_filters( + 'rocket_delay_js_settings_field', + [ + 'container_class' => [ + 'wpr-isParent', + 'wpr-Delayjs', + ], + 'type' => 'checkbox', + 'label' => __( 'Delay JavaScript execution', 'rocket' ), + // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. + 'description' => sprintf( __( 'Improves performance by delaying the loading of JavaScript files until user interaction (e.g. scroll, click). %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $delay_js_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $delay_js_beacon['id'] ) . '" target="_blank">', '</a>' ), + 'section' => 'js', + 'page' => 'file_optimization', + 'default' => 0, + 'sanitize_callback' => 'sanitize_checkbox', + ] + ), + 'delay_js_exclusions_selected' => [ + 'type' => 'categorized_multiselect', + 'label' => __( 'One-click exclusions', 'rocket' ), + 'description' => __( 'When using the Delay JavaScript Execution, you might experience delay loading elements located in the viewport that need to appear immediately - e.g. slider, header, menu.', 'rocket' ), + 'sub_description' => __( 'If you need instant visibility, click below on files that should NOT be delayed. This selection will help users interact with the elements straight away.', 'rocket' ), 'container_class' => [ - 'wpr-isParent', - 'wpr-Delayjs', + 'wpr-field--children', ], - 'type' => 'checkbox', - 'label' => __( 'Delay JavaScript execution', 'rocket' ), - // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( 'Improves performance by delaying the loading of JavaScript files until user interaction (e.g. scroll, click). %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $delay_js_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $delay_js_beacon['id'] ) . '" target="_blank">', '</a>' ), + 'parent' => 'delay_js', 'section' => 'js', 'page' => 'file_optimization', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', + 'default' => [], + 'sanitize_callback' => 'sanitize_textarea', + 'input_attr' => [ + 'disabled' => get_rocket_option( 'delay_js' ) ? 0 : 1, + ], + 'items' => $this->delayjs_sitelist->prepare_delayjs_ui_list(), ], - 'delay_js_scripts' => [ + 'delay_js_exclusions' => [ 'type' => 'textarea', - 'label' => __( 'Scripts to delay', 'rocket' ), - 'description' => __( 'Specify keywords that can identify inline or JavaScript files to be delayed (one per line).', 'rocket' ), - 'helper' => __( 'A curated list of scripts that are safe to delay is provided. They may not all apply to your website and it is safe to leave the list as-is unless you face issues.', 'rocket' ), + 'label' => __( 'Excluded JavaScript Files', 'rocket' ), + 'description' => __( 'Specify URLs or keywords that can identify inline or JavaScript files to be excluded from delaying execution (one per line).', 'rocket' ), 'container_class' => [ 'wpr-field--children', ], @@ -825,6 +833,8 @@ private function assets_section() { 'input_attr' => [ 'disabled' => get_rocket_option( 'delay_js' ) ? 0 : 1, ], + 'helper' => DelayJSSettings::exclusion_list_has_default() ? $delay_js_found_list_helper : $delay_js_list_helper, + 'placeholder' => '/wp-includes/js/jquery/jquery.min.js', ], ] ); @@ -838,20 +848,13 @@ private function assets_section() { private function media_section() { $lazyload_beacon = $this->beacon->get_suggest( 'lazyload' ); $exclude_lazyload = $this->beacon->get_suggest( 'exclude_lazyload' ); - $webp_beacon = $this->beacon->get_suggest( 'webp' ); $dimensions = $this->beacon->get_suggest( 'image_dimensions' ); - if ( rocket_valid_key() && ! \Imagify_Partner::has_imagify_api_key() ) { - $imagify_link = '<a href="#imagify">'; - } else { - $imagify_link = '<a href="https://wordpress.org/plugins/imagify/" target="_blank" rel="noopener noreferrer">'; - } - $this->settings->add_page_section( 'media', [ 'title' => __( 'Media', 'rocket' ), - 'menu_description' => __( 'LazyLoad, embeds, WebP', 'rocket' ), + 'menu_description' => __( 'LazyLoad, image dimensions', 'rocket' ), ] ); @@ -883,6 +886,15 @@ private function media_section() { $disable_iframes_lazyload = (array) apply_filters( 'rocket_maybe_disable_iframes_lazyload_helper', $disable_iframes_lazyload ); $disable_iframes_lazyload = $this->sanitize_and_format_list( $disable_iframes_lazyload ); + $disable_css_bg_img_lazyload = false; + + /** + * Lazyload Helper filter which disables WPR lazyload functionality for bg css. + * + * @param bool $disable_css_bg_img_lazyload Should the lazyload CSS be disabled. + */ + $disable_css_bg_img_lazyload = (bool) apply_filters( 'rocket_maybe_disable_css_bg_img_lazyload_helper', $disable_css_bg_img_lazyload ); + /** * Lazyload Helper filter which disables WPR lazyload functionality to replace YouTube iframe with preview image. * @@ -922,28 +934,7 @@ private function media_section() { 'type' => 'fields_container', // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. 'description' => sprintf( __( 'Add missing width and height attributes to images. Helps prevent layout shifts and improve the reading experience for your visitors. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $dimensions['url'] ) . '" data-beacon-article="' . esc_attr( $dimensions['id'] ) . '" target="_blank" rel="noopener noreferrer">', '</a>' ), - 'page' => 'media', - ], - 'embeds_section' => [ - 'title' => __( 'Embeds', 'rocket' ), - 'type' => 'fields_container', - 'description' => __( 'Prevents others from embedding content from your site, prevents you from embedding content from other (non-allowed) sites, and removes JavaScript requests related to WordPress embeds', 'rocket' ), - 'page' => 'media', - ], - 'webp_section' => [ - 'title' => __( 'WebP compatibility', 'rocket' ), - 'type' => 'fields_container', - 'description' => sprintf( - // translators: %1$s and %3$s = opening <a> tag, %2$s = closing </a> tag. - __( 'Enable this option if you would like WP Rocket to serve WebP images to compatible browsers. Please note that WP Rocket cannot create WebP images for you. To create WebP images we recommend %1$sImagify%2$s. %3$sMore info%2$s', 'rocket' ), - $imagify_link, - '</a>', - '<a href="' . esc_url( $webp_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $webp_beacon['id'] ) . '" target="_blank" rel="noopener noreferrer">' - ), - 'help' => [ - 'id' => $webp_beacon['id'], - 'url' => $webp_beacon['url'], - ], + 'help' => $dimensions, 'page' => 'media', ], ] @@ -956,11 +947,10 @@ private function media_section() { * * @param array $cache_webp_field Data to be added to the setting field. */ - $cache_webp_field = (array) apply_filters( 'rocket_cache_webp_setting_field', [] ); $this->settings->add_settings_fields( [ - 'lazyload' => [ + 'lazyload' => [ 'type' => 'checkbox', 'label' => __( 'Enable for images', 'rocket' ), 'section' => 'lazyload_section', @@ -976,7 +966,22 @@ private function media_section() { // translators: %1$s = “WP Rocket”, %2$s = a list of plugin names. 'description' => ! empty( $disable_images_lazyload ) ? sprintf( __( 'LazyLoad for images is currently activated in %2$s. If you want to use %1$s’s LazyLoad, disable this option in %2$s.', 'rocket' ), WP_ROCKET_PLUGIN_NAME, $disable_images_lazyload ) : '', ], - 'lazyload_iframes' => [ + 'lazyload_css_bg_img' => [ + 'container_class' => [ + $disable_css_bg_img_lazyload ? 'wpr-isDisabled' : '', + 'wpr-isParent', + ], + 'type' => 'checkbox', + 'label' => __( 'Enable for CSS background images', 'rocket' ), + 'section' => 'lazyload_section', + 'page' => 'media', + 'default' => 0, + 'sanitize_callback' => 'sanitize_checkbox', + 'input_attr' => [ + 'disabled' => $disable_css_bg_img_lazyload ? 1 : 0, + ], + ], + 'lazyload_iframes' => [ 'container_class' => [ ! empty( $disable_iframes_lazyload ) ? 'wpr-isDisabled' : '', 'wpr-isParent', @@ -991,7 +996,7 @@ private function media_section() { 'disabled' => ! empty( $disable_iframes_lazyload ) ? 1 : 0, ], ], - 'lazyload_youtube' => [ + 'lazyload_youtube' => [ 'container_class' => [ ! empty( $disable_youtube_lazyload ) ? 'wpr-isDisabled' : '', 'wpr-field--children', @@ -1009,20 +1014,20 @@ private function media_section() { 'disabled' => ! empty( $disable_youtube_lazyload ) ? 1 : 0, ], ], - 'exclude_lazyload' => [ + 'exclude_lazyload' => [ 'container_class' => [ 'wpr-Delayjs', ], 'type' => 'textarea', 'label' => __( 'Excluded images or iframes', 'rocket' ), // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( 'Specify keywords (e.g. image filename, CSS class, domain) from the image or iframe code to be excluded (one per line). %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $exclude_lazyload['url'] ) . '" data-beacon-article="' . esc_attr( $exclude_lazyload['id'] ) . '" target="_blank" rel="noopener noreferrer">', '</a>' ), + 'description' => sprintf( __( 'Specify keywords (e.g. image filename, CSS filename, CSS class, domain) from the image or iframe code to be excluded (one per line). %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $exclude_lazyload['url'] ) . '" data-beacon-article="' . esc_attr( $exclude_lazyload['id'] ) . '" target="_blank" rel="noopener noreferrer">', '</a>' ), 'section' => 'lazyload_section', 'page' => 'media', 'default' => [], - 'placeholder' => "example-image.jpg\nslider-image", + 'placeholder' => "example-image.jpg\nslider-image\nbackground-image-style.css", ], - 'image_dimensions' => [ + 'image_dimensions' => [ 'type' => 'checkbox', 'label' => __( 'Add missing image dimensions', 'rocket' ), 'section' => 'dimensions_section', @@ -1030,25 +1035,6 @@ private function media_section() { 'default' => 0, 'sanitize_callback' => 'sanitize_checkbox', ], - 'embeds' => [ - 'type' => 'checkbox', - 'label' => __( 'Disable WordPress embeds', 'rocket' ), - 'section' => 'embeds_section', - 'page' => 'media', - 'default' => 1, - 'sanitize_callback' => 'sanitize_checkbox', - ], - 'cache_webp' => array_merge( - $cache_webp_field, - [ - 'type' => 'checkbox', - 'label' => __( 'Enable WebP caching', 'rocket' ), - 'section' => 'webp_section', - 'page' => 'media', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ] - ), ] ); } @@ -1070,6 +1056,7 @@ private function preload_section() { $bot_beacon = $this->beacon->get_suggest( 'bot' ); $fonts_preload = $this->beacon->get_suggest( 'fonts_preload' ); $preload_links = $this->beacon->get_suggest( 'preload_links' ); + $exclusions = $this->beacon->get_suggest( 'preload_exclusions' ); $this->settings->add_settings_sections( [ @@ -1077,7 +1064,7 @@ private function preload_section() { 'title' => __( 'Preload Cache', 'rocket' ), 'type' => 'fields_container', // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( 'When you enable preloading WP Rocket will generate the cache starting with the links on your homepage followed by the sitemaps you specify. Preloading is automatically triggered when you add or update content and can also be manually triggered from the admin bar or from the %1$sWP Rocket Dashboard%2$s.', 'rocket' ), '<a href="#dashboard">', '</a>' ), + 'description' => __( 'When you enable preloading WP Rocket will automatically detect your sitemaps and save all URLs to the database. The plugin will make sure that your cache is always preloaded.', 'rocket' ), 'help' => [ 'id' => $this->beacon->get_suggest( 'sitemap_preload' ), 'url' => $bot_beacon['url'], @@ -1099,10 +1086,7 @@ private function preload_section() { 'title' => __( 'Prefetch DNS Requests', 'rocket' ), 'type' => 'fields_container', 'description' => __( 'DNS prefetching can make external files load faster, especially on mobile networks', 'rocket' ), - 'help' => [ - 'id' => $this->beacon->get_suggest( 'dns_prefetch' ), - 'url' => $bot_beacon['url'], - ], + 'help' => $this->beacon->get_suggest( 'dns_prefetch' ), 'page' => 'preload', ], 'preload_fonts_section' => [ @@ -1121,59 +1105,34 @@ private function preload_section() { $this->settings->add_settings_fields( [ - 'manual_preload' => [ + 'manual_preload' => [ 'type' => 'checkbox', 'label' => __( 'Activate Preloading', 'rocket' ), 'section' => 'preload_section', 'page' => 'preload', 'default' => 1, + 'sanitize_callback' => 'sanitize_checkbox', 'container_class' => [ 'wpr-isParent', ], - 'sanitize_callback' => 'sanitize_checkbox', ], - ] - ); - - // Add this separately to be able to filter it easily. - $this->settings->add_settings_fields( - apply_filters( - 'rocket_sitemap_preload_options', - [ - 'sitemap_preload' => [ - 'type' => 'checkbox', - 'label' => __( 'Activate sitemap-based cache preloading', 'rocket' ), - 'container_class' => [ - 'wpr-isParent', - 'wpr-field--children', - ], - 'parent' => 'manual_preload', - 'section' => 'preload_section', - 'page' => 'preload', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ], - ] - ) - ); - - $this->settings->add_settings_fields( - [ - 'sitemaps' => [ + 'preload_excluded_uri' => [ 'type' => 'textarea', - 'label' => __( 'Sitemaps for preloading', 'rocket' ), + 'label' => __( 'Exclude URLs', 'rocket' ), 'container_class' => [ 'wpr-field--children', ], - 'description' => __( 'Specify XML sitemap(s) to be used for preloading', 'rocket' ), - 'placeholder' => 'http://example.com/sitemap.xml', - 'parent' => 'sitemap_preload', + // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. + 'description' => sprintf( __( 'Specify URLs to be excluded from the preload feature (one per line). %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $exclusions['url'] ) . '" data-beacon-article="' . esc_attr( $exclusions['id'] ) . '" target="_blank">', '</a>' ), + 'placeholder' => '/author/(.*)', + 'helper' => 'Use (.*) wildcards to address multiple URLs under a given path.', + 'parent' => 'manual_preload', 'section' => 'preload_section', 'page' => 'preload', 'default' => [], 'sanitize_callback' => 'sanitize_textarea', ], - 'dns_prefetch' => [ + 'dns_prefetch' => [ 'type' => 'textarea', 'label' => __( 'URLs to prefetch', 'rocket' ), 'description' => __( 'Specify external hosts to be prefetched (no <code>http:</code>, one per line)', 'rocket' ), @@ -1183,7 +1142,7 @@ private function preload_section() { 'default' => [], 'sanitize_callback' => 'sanitize_textarea', ], - 'preload_fonts' => [ + 'preload_fonts' => [ 'type' => 'textarea', 'label' => __( 'Fonts to preload', 'rocket' ), 'description' => __( 'Specify urls of the font files to be preloaded (one per line). Fonts must be hosted on your own domain, or the domain you have specified on the CDN tab.', 'rocket' ), @@ -1194,7 +1153,7 @@ private function preload_section() { 'default' => [], 'sanitize_callback' => 'sanitize_textarea', ], - 'preload_links' => [ + 'preload_links' => [ 'type' => 'checkbox', 'label' => __( 'Enable link preloading', 'rocket' ), 'section' => 'preload_links_section', @@ -1222,7 +1181,11 @@ private function advanced_cache_section() { $ecommerce_beacon = $this->beacon->get_suggest( 'ecommerce' ); $cache_query_strings_beacon = $this->beacon->get_suggest( 'cache_query_strings' ); $never_cache_beacon = $this->beacon->get_suggest( 'exclude_cache' ); + $never_cache_cookie_beacon = $this->beacon->get_suggest( 'exclude_cookie' ); + $exclude_user_agent_beacon = $this->beacon->get_suggest( 'exclude_user_agent' ); $always_purge_beacon = $this->beacon->get_suggest( 'always_purge' ); + $cache_life_beacon = $this->beacon->get_suggest( 'cache_lifespan' ); + $nonce_beacon = $this->beacon->get_suggest( 'nonce' ); $ecommerce_plugin = ''; $reject_uri_desc = __( 'Sensitive pages like custom login/logout URLs should be excluded from cache.', 'rocket' ); @@ -1251,34 +1214,41 @@ private function advanced_cache_section() { $this->settings->add_settings_sections( [ + 'cache_lifespan' => [ + 'title' => __( 'Cache Lifespan', 'rocket' ), + 'type' => 'fields_container', + // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. + 'description' => sprintf( __( 'Cache files older than the specified lifespan will be deleted.<br>Enable %1$spreloading%2$s for the cache to be rebuilt automatically after lifespan expiration.', 'rocket' ), '<a href="#preload">', '</a>' ), + 'help' => [ + 'url' => $cache_life_beacon['url'], + 'id' => $this->beacon->get_suggest( 'cache_lifespan_section' ), + ], + 'page' => 'advanced_cache', + ], 'cache_reject_uri_section' => [ 'title' => __( 'Never Cache URL(s)', 'rocket' ), 'type' => 'fields_container', // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. 'description' => $reject_uri_desc, - 'help' => [ - 'id' => $this->beacon->get_suggest( 'never_cache' ), - 'url' => $never_cache_beacon['url'], - ], + 'help' => $never_cache_beacon, 'page' => 'advanced_cache', ], 'cache_reject_cookies_section' => [ 'title' => __( 'Never Cache Cookies', 'rocket' ), 'type' => 'fields_container', 'page' => 'advanced_cache', + 'help' => $never_cache_cookie_beacon, ], 'cache_reject_ua_section' => [ 'title' => __( 'Never Cache User Agent(s)', 'rocket' ), 'type' => 'fields_container', + 'help' => $exclude_user_agent_beacon, 'page' => 'advanced_cache', ], 'cache_purge_pages_section' => [ 'title' => __( 'Always Purge URL(s)', 'rocket' ), 'type' => 'fields_container', - 'help' => [ - 'id' => $this->beacon->get_suggest( 'always_purge_section' ), - 'url' => $always_purge_beacon['url'], - ], + 'help' => $always_purge_beacon, 'page' => 'advanced_cache', ], 'cache_query_strings_section' => [ @@ -1286,10 +1256,7 @@ private function advanced_cache_section() { 'type' => 'fields_container', // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. 'description' => sprintf( __( '%1$sCache for query strings%2$s enables you to force caching for specific GET parameters.', 'rocket' ), '<a href="' . esc_url( $cache_query_strings_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $cache_query_strings_beacon['id'] ) . '" target="_blank">', '</a>' ), - 'help' => [ - 'id' => $this->beacon->get_suggest( 'query_strings' ), - 'url' => $cache_query_strings_beacon['url'], - ], + 'help' => $cache_query_strings_beacon, 'page' => 'advanced_cache', ], ] @@ -1297,11 +1264,25 @@ private function advanced_cache_section() { $this->settings->add_settings_fields( [ + 'purge_cron_interval' => [ + 'type' => 'cache_lifespan', + 'label' => __( 'Specify time after which the global cache is cleared<br>(0 = unlimited )', 'rocket' ), + // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. + 'description' => sprintf( __( 'Reduce lifespan to 10 hours or less if you notice issues that seem to appear periodically. %1$sWhy?%2$s', 'rocket' ), '<a href="' . esc_url( $nonce_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $nonce_beacon['id'] ) . '" target="_blank">', '</a>' ), + 'section' => 'cache_lifespan', + 'page' => 'advanced_cache', + 'default' => 10, + 'sanitize_callback' => 'sanitize_cache_lifespan', + 'choices' => [ + 'HOUR_IN_SECONDS' => __( 'Hours', 'rocket' ), + 'DAY_IN_SECONDS' => __( 'Days', 'rocket' ), + ], + ], 'cache_reject_uri' => [ 'type' => 'textarea', 'description' => __( 'Specify URLs of pages or posts that should never be cached (one per line)', 'rocket' ), 'helper' => __( 'The domain part of the URL will be stripped automatically.<br>Use (.*) wildcards to address multiple URLs under a given path.', 'rocket' ), - 'placeholder' => '/members/(.*)', + 'placeholder' => '/example/(.*)', 'section' => 'cache_reject_uri_section', 'page' => 'advanced_cache', 'default' => [], @@ -1309,7 +1290,7 @@ private function advanced_cache_section() { ], 'cache_reject_cookies' => [ 'type' => 'textarea', - 'description' => __( 'Specify the IDs of cookies that, when set in the visitor\'s browser, should prevent a page from getting cached (one per line)', 'rocket' ), + 'description' => __( 'Specify full or partial IDs of cookies that, when set in the visitor\'s browser, should prevent a page from getting cached (one per line)', 'rocket' ), 'section' => 'cache_reject_cookies_section', 'page' => 'advanced_cache', 'default' => [], @@ -1366,18 +1347,13 @@ private function database_section() { ] ); - $database_beacon = $this->beacon->get_suggest( 'slow_admin' ); - $this->settings->add_settings_sections( [ 'post_cleanup_section' => [ 'title' => __( 'Post Cleanup', 'rocket' ), 'type' => 'fields_container', 'description' => __( 'Post revisions and drafts will be permanently deleted. Do not use this option if you need to retain revisions or drafts.', 'rocket' ), - 'help' => [ - 'id' => $this->beacon->get_suggest( 'cleanup' ), - 'url' => $database_beacon['url'], - ], + 'help' => $this->beacon->get_suggest( 'db_optimization' ), 'page' => 'database', ], 'comments_cleanup_section' => [ @@ -1399,7 +1375,7 @@ private function database_section() { 'page' => 'database', ], 'schedule_cleanup_section' => [ - 'title' => __( 'Automatic cleanup', 'rocket' ), + 'title' => __( 'Automatic Cleanup', 'rocket' ), 'type' => 'fields_container', 'page' => 'database', ], @@ -1458,16 +1434,6 @@ private function database_section() { 'default' => 0, 'sanitize_callback' => 'sanitize_checkbox', ], - 'database_expired_transients' => [ - 'type' => 'checkbox', - 'label' => __( 'Expired transients', 'rocket' ), - // translators: %s is the number of revisions found in the database. It's a formatted number, don't use %d. - 'description' => sprintf( _n( '%s expired transient in your database.', '%s expired transients in your database.', $total['database_expired_transients'], 'rocket' ), number_format_i18n( $total['database_expired_transients'] ) ), - 'section' => 'transients_cleanup_section', - 'page' => 'database', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ], 'database_all_transients' => [ 'type' => 'checkbox', 'label' => __( 'All transients', 'rocket' ), @@ -1573,27 +1539,31 @@ private function cdn_section() { ); $maybe_display_cdn_helper = ''; - $addons = []; - if ( get_rocket_option( 'do_cloudflare' ) ) { - $addons[] = 'Cloudflare'; - } + /** + * Filters the addons names requiring the helper message. + * + * @param array $addons Array of addons. + */ + $addons = apply_filters( 'rocket_cdn_helper_addons', [] ); - if ( get_rocket_option( 'sucury_waf_cache_sync' ) ) { - $addons[] = 'Sucuri'; + if ( ! is_array( $addons ) ) { + $addons = []; } + $addons = array_unique( $addons ); + if ( ! empty( $addons ) ) { - $maybe_display_cdn_helper = sprintf( - // translators: %1$s = opening em tag, %2$s = add-on name(s), %3$s = closing em tag. + $maybe_display_cdn_helper = wp_sprintf( + // translators: %1$s = opening em tag, %2$l = list of add-on name(s), %3$s = closing em tag. _n( - '%1$s%2$s Add-on%3$s is currently enabled. Configuration of the CDN settings is not required for %2$s to work on your site.', - '%1$s%2$s Add-ons%3$s are currently enabled. Configuration of the CDN settings is not required for %2$s to work on your site.', + '%1$s%2$l Add-on%3$s is currently enabled. Configuration of the CDN settings is not required for %2$l to work on your site.', + '%1$s%2$l Add-ons%3$s are currently enabled. Configuration of the CDN settings is not required for %2$l to work on your site.', count( $addons ), 'rocket' ), '<em>', - implode( ' and ', $addons ), + $addons, '</em>' ) . '<br>'; } @@ -1649,6 +1619,7 @@ private function cdn_section() { */ private function heartbeat_section() { $heartbeat_beacon = $this->beacon->get_suggest( 'heartbeat_settings' ); + $this->settings->add_page_section( 'heartbeat', [ @@ -1664,10 +1635,7 @@ private function heartbeat_section() { 'description' => __( 'Reducing or disabling the Heartbeat API’s activity can help save some of your server’s resources.', 'rocket' ), 'type' => 'fields_container', 'page' => 'heartbeat', - 'help' => [ - 'id' => $heartbeat_beacon['id'], - 'url' => $heartbeat_beacon['url'], - ], + 'help' => $heartbeat_beacon, ], 'heartbeat_settings' => [ 'title' => __( 'Reduce or disable Heartbeat activity', 'rocket' ), @@ -1730,6 +1698,9 @@ private function heartbeat_section() { * @since 3.0 */ private function addons_section() { + $webp_beacon = $this->beacon->get_suggest( 'webp' ); + $user_cache_beacon = $this->beacon->get_suggest( 'user_cache' ); + $this->settings->add_page_section( 'addons', [ @@ -1760,72 +1731,64 @@ private function addons_section() { ] ); - $ga_beacon = $this->beacon->get_suggest( 'google_tracking' ); - $this->settings->add_settings_fields( [ - 'google_analytics_cache' => [ + 'cache_logged_user' => [ 'type' => 'one_click_addon', - 'label' => __( 'Google Tracking', 'rocket' ), + 'label' => __( 'User Cache', 'rocket' ), 'logo' => [ - 'url' => WP_ROCKET_ASSETS_IMG_URL . 'logo-google-analytics.svg', - 'width' => 153, - 'height' => 111, + 'url' => WP_ROCKET_ASSETS_IMG_URL . 'icon-user-cache.svg', + 'width' => 152, + 'height' => 135, ], - 'title' => __( 'Improve browser caching for Google Analytics', 'rocket' ), + 'title' => __( 'If you need to create a dedicated set of cache files for each logged-in WordPress user, you must activate this add-on.', 'rocket' ), // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( 'WP Rocket will host these Google scripts locally on your server to help satisfy the PageSpeed recommendation for <em>Leverage browser caching</em>.<br>%1$sLearn more%2$s', 'rocket' ), '<a href="' . esc_url( $ga_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $ga_beacon['id'] ) . '" target="_blank">', '</a>' ), + 'description' => sprintf( __( 'User cache is great when you have user-specific or restricted content on your website.<br>%1$sLearn more%2$s', 'rocket' ), '<a href="' . esc_url( $user_cache_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $user_cache_beacon['id'] ) . '" target="_blank">', '</a>' ), 'section' => 'one_click', 'page' => 'addons', + 'settings_page' => 'user_cache', 'default' => 0, 'sanitize_callback' => 'sanitize_checkbox', ], ] ); - $fb_beacon = $this->beacon->get_suggest( 'facebook_tracking' ); + $default_cf_settings = [ + 'do_cloudflare' => [ + 'type' => 'rocket_addon', + 'label' => __( 'Cloudflare', 'rocket' ), + 'logo' => [ + 'url' => rocket_get_constant( 'WP_ROCKET_ASSETS_IMG_URL', '' ) . 'logo-cloudflare2.svg', + 'width' => 153, + 'height' => 51, + ], + 'title' => __( 'Integrate your Cloudflare account with this add-on.', 'rocket' ), + 'description' => __( 'Provide your account email, global API key, and domain to use options such as clearing the Cloudflare cache and enabling optimal settings with WP Rocket.', 'rocket' ), + 'helper' => sprintf( + // translators: %1$s = opening span tag, %2$s = closing span tag. + __( '%1$sPlanning on using Automatic Platform Optimization (APO)?%2$s Just activate the official Cloudflare plugin and configure it. WP Rocket will automatically enable compatibility.', 'rocket' ), + '<span class="wpr-helper-title">', + '</span>' + ), + 'section' => 'addons', + 'page' => 'addons', + 'settings_page' => 'cloudflare', + 'default' => 0, + 'sanitize_callback' => 'sanitize_checkbox', + ], + ]; - $this->settings->add_settings_fields( - [ - 'facebook_pixel_cache' => [ - 'type' => 'one_click_addon', - 'label' => __( 'Facebook Pixel', 'rocket' ), - 'logo' => [ - 'url' => WP_ROCKET_ASSETS_IMG_URL . 'logo-facebook.svg', - 'width' => 114, - 'height' => 114, - ], - 'title' => __( 'Improve browser caching for Facebook Pixel', 'rocket' ), - // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. - 'description' => sprintf( __( 'WP Rocket will host these Facebook Pixels locally on your server to help satisfy the PageSpeed recommendation for <em>Leverage browser caching</em>.<br>%1$sLearn more%2$s', 'rocket' ), '<a href="' . esc_url( $fb_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $fb_beacon['id'] ) . '" target="_blank">', '</a>' ), - 'section' => 'one_click', - 'page' => 'addons', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ], - ] - ); + /** + * Filters the Cloudflare Addon field values + * + * @since 3.14 + * + * @param array $cf_settings Array of values to populate the field. + */ + $cf_settings = (array) apply_filters( 'rocket_cloudflare_field_settings', $default_cf_settings ); + $cf_settings = wp_parse_args( $cf_settings, $default_cf_settings ); - $this->settings->add_settings_fields( - [ - 'do_cloudflare' => [ - 'type' => 'rocket_addon', - 'label' => __( 'Cloudflare', 'rocket' ), - 'logo' => [ - 'url' => WP_ROCKET_ASSETS_IMG_URL . 'logo-cloudflare2.svg', - 'width' => 153, - 'height' => 51, - ], - 'title' => __( 'Integrate your Cloudflare account with this add-on.', 'rocket' ), - 'description' => __( 'Provide your account email, global API key, and domain to use options such as clearing the Cloudflare cache and enabling optimal settings with WP Rocket.', 'rocket' ), - 'section' => 'addons', - 'page' => 'addons', - 'settings_page' => 'cloudflare', - 'default' => 0, - 'sanitize_callback' => 'sanitize_checkbox', - ], - ] - ); + $this->settings->add_settings_fields( $cf_settings ); /** * Allow to display the "Varnish" tab in the settings page @@ -1871,6 +1834,57 @@ private function addons_section() { ); } + $webp_beacon = $this->beacon->get_suggest( 'webp' ); + + if ( rocket_valid_key() && ! \Imagify_Partner::has_imagify_api_key() ) { + $imagify_link = '<a href="#imagify">'; + } else { + $imagify_link = '<a href="https://wordpress.org/plugins/imagify/" target="_blank" rel="noopener noreferrer">'; + } + + $this->settings->add_settings_fields( + [ + 'cache_webp' => + /** + * Add more content to the 'cache_webp' setting field. + * + * @since 3.10 moved to add-on section + * @since 3.4 + * + * @param array $cache_webp_field Data to be added to the setting field. + */ + apply_filters( + 'rocket_cache_webp_setting_field', + [ + 'type' => 'one_click_addon', + 'label' => __( 'WebP Compatibility', 'rocket' ), + 'logo' => [ + 'url' => WP_ROCKET_ASSETS_IMG_URL . 'logo-webp.svg', + 'width' => 152, + 'height' => 135, + ], + 'title' => __( 'Improve browser compatibility for WebP images.', 'rocket' ), + // translators: %1$s = opening <a> tag, %2$s = closing </a> tag. + 'description' => sprintf( + // translators: %1$s and %3$s = opening <a> tag, %2$s = closing </a> tag. + __( 'Enable this option if you would like WP Rocket to serve WebP images to compatible browsers. Please note that WP Rocket cannot create WebP images for you. To create WebP images we recommend %1$sImagify%2$s. %3$sMore info%2$s', 'rocket' ), + $imagify_link, + '</a>', + '<a href="' . esc_url( $webp_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $webp_beacon['id'] ) . '" target="_blank" rel="noopener noreferrer">' + ), + 'section' => 'one_click', + 'page' => 'addons', + 'settings_page' => 'webp', + 'default' => 0, + 'sanitize_callback' => 'sanitize_checkbox', + 'container_class' => [ + 'wpr-webp-addon', + ], + ] + ), + ] + ); + if ( defined( 'WP_ROCKET_SUCURI_API_KEY_HIDDEN' ) && WP_ROCKET_SUCURI_API_KEY_HIDDEN ) { // No need to display the dedicated tab if there is nothing to display on it. $description = __( 'Clear the Sucuri cache when WP Rocket’s cache is cleared.', 'rocket' ); @@ -1950,7 +1964,7 @@ private function cloudflare_section() { if ( ! defined( 'WP_ROCKET_CF_API_KEY_HIDDEN' ) || ! WP_ROCKET_CF_API_KEY_HIDDEN ) { $this->settings->add_settings_fields( [ - 'cloudflare_api_key' => [ + 'cloudflare_api_key_mask' => [ 'label' => _x( 'Global API key:', 'Cloudflare', 'rocket' ), 'description' => sprintf( '<a href="%1$s" target="_blank">%2$s</a>', esc_url( $beacon_cf_credentials_api['url'] ), _x( 'Find your API key', 'Cloudflare', 'rocket' ) ), 'default' => '', @@ -1972,7 +1986,7 @@ private function cloudflare_section() { 'section' => 'cloudflare_credentials', 'page' => 'cloudflare', ], - 'cloudflare_zone_id' => [ + 'cloudflare_zone_id_mask' => [ 'label' => _x( 'Zone ID', 'Cloudflare', 'rocket' ), 'default' => '', 'container_class' => [ @@ -2054,7 +2068,7 @@ private function sucuri_section() { $this->settings->add_settings_fields( [ 'sucury_waf_api_key' => [ - 'label' => _x( 'Firewall API key (for plugin), must be in format <code>{32 characters}/{32 characters}</code>:', 'Sucuri', 'rocket' ), + 'label' => _x( 'Firewall API key (for plugin), must be in format {32 characters}/{32 characters}:', 'Sucuri', 'rocket' ), 'description' => sprintf( '<a href="%1$s" target="_blank">%2$s</a>', 'https://kb.sucuri.net/firewall/Performance/clearing-cache', _x( 'Find your API key', 'Sucuri', 'rocket' ) ), 'default' => '', 'section' => 'sucuri_credentials', @@ -2070,6 +2084,30 @@ private function sucuri_section() { * @since 3.0 */ private function hidden_fields() { + + $hidden_fields = [ + 'consumer_key', + 'consumer_email', + 'secret_key', + 'license', + 'secret_cache_key', + 'minify_css_key', + 'minify_js_key', + 'version', + 'previous_version', + 'cloudflare_old_settings', + 'cache_ssl', + 'minify_google_fonts', + 'emoji', + 'remove_unused_css', + 'async_css', + 'cache_mobile', + 'do_caching_mobile_files', + 'minify_concatenate_css', + 'cloudflare_api_key', + 'cloudflare_zone_id', + ]; + $this->settings->add_hidden_settings_fields( /** * Filters the hidden settings fields @@ -2081,21 +2119,7 @@ private function hidden_fields() { */ apply_filters( 'rocket_hidden_settings_fields', - [ - 'consumer_key', - 'consumer_email', - 'secret_key', - 'license', - 'secret_cache_key', - 'minify_css_key', - 'minify_js_key', - 'version', - 'cloudflare_old_settings', - 'sitemap_preload_url_crawl', - 'cache_ssl', - 'minify_google_fonts', - 'emoji', - ] + $hidden_fields ) ); } @@ -2109,7 +2133,7 @@ private function hidden_fields() { * @param string $tag_name Name of the HTML tag that will wrap each element of the list. * @return array */ - private function sanitize_and_format_list( $list, $tag_name = 'strong' ) { + private function sanitize_and_format_list( $list, $tag_name = 'strong' ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.listFound if ( ! is_array( $list ) || empty( $list ) ) { return []; } @@ -2130,4 +2154,151 @@ private function sanitize_and_format_list( $list, $tag_name = 'strong' ) { return array_map( 'sprintf', array_fill( 0, count( $list ), $format ), $list ); } + + /** + * Checks if combine JS option should be disabled + * + * @since 3.9 + * + * @return bool + */ + private function disable_combine_js(): bool { + if ( (bool) get_rocket_option( 'delay_js', 0 ) ) { + return true; + } + + return ! (bool) get_rocket_option( 'minify_js', 0 ); + } + + /** + * Checks if combine CSS option should be disabled + * + * @since 3.11 + * + * @return bool + */ + private function disable_combine_css(): bool { + if ( (bool) get_rocket_option( 'remove_unused_css', 0 ) ) { + return true; + } + + return ! (bool) get_rocket_option( 'minify_css', 0 ); + } + + /** + * Render radio options sub fields. + * + * @since 3.10 + * + * @param array $sub_fields Array of fields to display. + */ + public function display_radio_options_sub_fields( $sub_fields ) { + $sub_fields = $this->settings->set_radio_buttons_sub_fields_value( $sub_fields ); + $this->render->render_fields( $sub_fields ); + } + + /** + * Render mobile cache option. + * + * @return void + */ + public function display_mobile_cache_option(): void { + if ( (bool) $this->options->get( 'cache_mobile', 0 ) ) { + return; + } + + $data = $this->beacon->get_suggest( 'mobile_cache' ); + echo $this->generate( 'settings/mobile-cache', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view. + } + + /** + * Callback method for the AJAX request to mobile cache. + * + * @return void + */ + public function enable_mobile_cache(): void { + check_ajax_referer( 'rocket-ajax', 'nonce', true ); + + if ( ! current_user_can( 'rocket_manage_options' ) ) { + wp_send_json_error(); + return; + } + + $this->options->set( 'cache_mobile', 1 ); + $this->options->set( 'do_caching_mobile_files', 1 ); + update_option( rocket_get_constant( 'WP_ROCKET_SLUG', 'wp_rocket_settings' ), $this->options->get_options() ); + + wp_send_json_success(); + } + + /** + * Enable Separate cache files option on upgrade. + * + * @return void + */ + public function enable_separate_cache_files_mobile(): void { + if ( ! (bool) $this->options->get( 'cache_mobile', 0 ) ) { + return; + } + + if ( (bool) $this->options->get( 'do_caching_mobile_files', 0 ) ) { + return; + } + + $this->options->set( 'do_caching_mobile_files', 1 ); + update_option( rocket_get_constant( 'WP_ROCKET_SLUG', 'wp_rocket_settings' ), $this->options->get_options() ); + } + + /** + * Display an update notice when the plugin is updated. + * + * @return void + */ + public function display_update_notice() { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + + if ( 'settings_page_wprocket' !== get_current_screen()->id ) { + return false; + } + + $boxes = get_user_meta( get_current_user_id(), 'rocket_boxes', true ); + + if ( in_array( 'rocket_update_notice', (array) $boxes, true ) ) { + return; + } + + $previous_version = $this->options->get( 'previous_version' ); + + // Bail-out for fresh install. + if ( empty( $previous_version ) ) { + return; + } + + // Bail-out if previous version is greater than 3.16. + if ( $previous_version > '3.16' ) { + return; + } + + $critical_images_beacon = $this->beacon->get_suggest( 'optimize_critical_images' ); + $remove_cache_tab = $this->beacon->get_suggest( 'remove_cache_tab' ); + + rocket_notice_html( + [ + 'status' => 'info', + 'dismissible' => '', + 'message' => sprintf( + // translators: %1$s: opening strong tag, %2$s: closing strong tag, %3$s: opening a tag, %4$s: option a tag, %5$s: opening a tag. + __( '%1$sWP Rocket:%2$s the plugin has been updated to the 3.16 version. Our brand new feature %3$sOptimize critical images%5$s is automatically activated now! Also, the Cache tab was removed but the existing features will remain working, %4$ssee more here%5$s.', 'rocket' ), + '<strong>', + '</strong>', + '<a href="' . esc_url( $critical_images_beacon['url'] ) . '" data-beacon-article="' . esc_attr( $critical_images_beacon['id'] ) . '" target="_blank" rel="noopener noreferrer">', + '<a href="' . esc_url( $remove_cache_tab['url'] ) . '" data-beacon-article="' . esc_attr( $remove_cache_tab['id'] ) . '" target="_blank" rel="noopener noreferrer">', + '</a>' + ), + 'dismiss_button' => 'rocket_update_notice', + ] + ); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Render.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Render.php index 6aaf664a2..7c335f655 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Render.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Render.php @@ -1,6 +1,7 @@ <?php namespace WP_Rocket\Engine\Admin\Settings; +use stdClass; use WP_Rocket\Abstract_Render; defined( 'ABSPATH' ) || exit; @@ -83,7 +84,7 @@ public function render_navigation() { ]; $navigation = array_map( - function( array $item ) use ( $default ) { + function ( array $item ) use ( $default ) { $item = wp_parse_args( $item, $default ); if ( ! empty( $item['class'] ) ) { @@ -129,7 +130,53 @@ public function render_form_sections() { * @since 3.2 */ public function render_imagify_section() { - echo $this->generate( 'page-sections/imagify' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view. + + require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; + + $plugin_data = get_transient( 'rocket_imagify_plugin_data' ); + + if ( ! $plugin_data ) { + + $query_args = [ + 'slug' => 'imagify', + 'fields' => [ + 'icons' => true, + 'active_installs' => true, + 'rating' => true, + 'ratings' => true, + 'short_description' => false, + 'sections' => false, + 'last_updated' => false, + 'added' => false, + 'tags' => false, + 'homepage' => false, + 'donate_link' => false, + 'screenshots' => false, + 'versions' => false, + 'banners' => false, + 'contributors' => false, + 'requires' => false, + 'tested' => false, + 'requires_php' => false, + 'support_url' => false, + 'upgrade_notice' => false, + 'business_model' => false, + 'repository_url' => false, + 'commercial_support_url' => false, + 'preview_link' => false, + ], + ]; + + $plugin_data = plugins_api( 'plugin_information', $query_args ); + + if ( is_wp_error( $plugin_data ) ) { + $plugin_data = []; + } + + set_transient( 'rocket_imagify_plugin_data', $plugin_data, WEEK_IN_SECONDS ); + } + + echo $this->generate( 'page-sections/imagify', $plugin_data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view. } /** @@ -197,59 +244,7 @@ public function render_settings_fields( $page, $section ) { if ( ! isset( $this->settings[ $page ]['sections'][ $section ]['fields'] ) ) { return; } - - foreach ( $this->settings[ $page ]['sections'][ $section ]['fields'] as $args ) { - $default = [ - 'type' => 'text', - 'label' => '', - 'description' => '', - 'class' => '', - 'container_class' => '', - 'default' => '', - 'helper' => '', - 'placeholder' => '', - 'parent' => '', - 'section' => '', - 'page' => '', - 'sanitize_callback' => 'sanitize_text_field', - 'input_attr' => '', - 'warning' => [], - ]; - - $args = wp_parse_args( $args, $default ); - - if ( ! empty( $args['input_attr'] ) ) { - $input_attr = ''; - - foreach ( $args['input_attr'] as $key => $value ) { - if ( 'disabled' === $key ) { - if ( 1 === $value ) { - $input_attr .= ' disabled'; - } - - continue; - } - - $input_attr .= ' ' . sanitize_key( $key ) . '="' . esc_attr( $value ) . '"'; - } - - $args['input_attr'] = $input_attr; - } - - if ( ! empty( $args['parent'] ) ) { - $args['parent'] = ' data-parent="' . esc_attr( $args['parent'] ) . '"'; - } - - if ( ! empty( $args['class'] ) ) { - $args['class'] = implode( ' ', array_map( 'sanitize_html_class', $args['class'] ) ); - } - - if ( ! empty( $args['container_class'] ) ) { - $args['container_class'] = implode( ' ', array_map( 'sanitize_html_class', $args['container_class'] ) ); - } - - call_user_func_array( [ $this, $args['type'] ], [ $args ] ); - } + $this->render_fields( $this->settings[ $page ]['sections'][ $section ]['fields'] ); } /** @@ -360,6 +355,18 @@ public function number( $args ) { echo $this->generate( 'fields/number', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view. } + /** + * Displays the multiselect field template. + * + * @param array $args Array of arguments to populate the template. + */ + public function categorized_multiselect( $args ) { + $args['items'] = empty( $args['items'] ) ? new stdClass() : $args['items']; + $args['selected'] = get_rocket_option( sanitize_key( $args['id'] ), [] ); + + echo $this->generate( 'fields/categorized_multiselect', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view. + } + /** * Displays the select field template. * @@ -473,4 +480,84 @@ public function render_import_form() { public function render_part( $part ) { echo $this->generate( 'partials/' . $part ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view. } + + /** + * Displays the radio_buttons field template. + * + * @since 3.10 + * + * @param array $args Array of arguments to populate the template. + */ + public function radio_buttons( $args ) { + echo $this->generate( 'fields/radio-buttons', $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Dynamic content is properly escaped in the view. + } + + /** + * Renders the fields. + * + * @since 3.10 + * + * @param array $fields fields to render. + * + * @return void + */ + public function render_fields( $fields ) { + + foreach ( $fields as $id => $args ) { + $default = [ + 'type' => 'text', + 'label' => '', + 'description' => '', + 'class' => '', + 'container_class' => '', + 'default' => '', + 'helper' => '', + 'placeholder' => '', + 'parent' => '', + 'section' => '', + 'page' => '', + 'sanitize_callback' => 'sanitize_text_field', + 'input_attr' => '', + 'warning' => [], + ]; + + $args = wp_parse_args( $args, $default ); + + if ( empty( $args['id'] ) ) { + $args['id'] = $id; + } + + if ( ! empty( $args['input_attr'] ) ) { + $input_attr = ''; + + foreach ( $args['input_attr'] as $key => $value ) { + if ( 'disabled' === $key ) { + if ( 1 === $value ) { + $input_attr .= ' disabled'; + } + + continue; + } + + $input_attr .= ' ' . sanitize_key( $key ) . '="' . esc_attr( $value ) . '"'; + } + + $args['input_attr'] = $input_attr; + } + + if ( ! empty( $args['parent'] ) ) { + $args['parent'] = ' data-parent="' . esc_attr( $args['parent'] ) . '"'; + } + + if ( ! empty( $args['class'] ) ) { + $args['class'] = implode( ' ', array_map( 'sanitize_html_class', $args['class'] ) ); + } + + if ( ! empty( $args['container_class'] ) ) { + $args['container_class'] = implode( ' ', array_map( 'sanitize_html_class', $args['container_class'] ) ); + } + + call_user_func_array( [ $this, $args['type'] ], [ $args ] ); + } + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/ServiceProvider.php index f4651d1e3..8f894722d 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/ServiceProvider.php @@ -1,22 +1,14 @@ <?php namespace WP_Rocket\Engine\Admin\Settings; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; /** * Service provider for the WP Rocket settings. - * - * @since 3.5.5 Moves into the new architecture. - * @since 3.3 */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -28,23 +20,38 @@ class ServiceProvider extends AbstractServiceProvider { ]; /** - * Registers the option array in the container. + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * - * @since 3.3 + * @return void */ - public function register() { - $this->getContainer()->add( 'settings', 'WP_Rocket\Engine\Admin\Settings\Settings' ) - ->withArgument( $this->getContainer()->get( 'options' ) ); - $this->getContainer()->add( 'settings_render', 'WP_Rocket\Engine\Admin\Settings\Render' ) - ->withArgument( $this->getContainer()->get( 'template_path' ) . '/settings' ); - $this->getContainer()->add( 'settings_page', 'WP_Rocket\Engine\Admin\Settings\Page' ) - ->withArgument( $this->getContainer()->get( 'settings_page_config' ) ) - ->withArgument( $this->getContainer()->get( 'settings' ) ) - ->withArgument( $this->getContainer()->get( 'settings_render' ) ) - ->withArgument( $this->getContainer()->get( 'beacon' ) ) - ->withArgument( $this->getContainer()->get( 'db_optimization' ) ) - ->withArgument( $this->getContainer()->get( 'user_client' ) ); - $this->getContainer()->share( 'settings_page_subscriber', 'WP_Rocket\Engine\Admin\Settings\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'settings_page' ) ); + public function register(): void { + $this->getContainer()->add( 'settings', Settings::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + $this->getContainer()->add( 'settings_render', Render::class ) + ->addArgument( $this->getContainer()->get( 'template_path' ) . '/settings' ); + $this->getContainer()->add( 'settings_page', Page::class ) + ->addArgument( $this->getContainer()->get( 'settings_page_config' ) ) + ->addArgument( $this->getContainer()->get( 'settings' ) ) + ->addArgument( $this->getContainer()->get( 'settings_render' ) ) + ->addArgument( $this->getContainer()->get( 'beacon' ) ) + ->addArgument( $this->getContainer()->get( 'db_optimization' ) ) + ->addArgument( $this->getContainer()->get( 'user_client' ) ) + ->addArgument( $this->getContainer()->get( 'delay_js_sitelist' ) ) + ->addArgument( $this->getContainer()->get( 'template_path' ) ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + $this->getContainer()->addShared( 'settings_page_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'settings_page' ) ) + ->addTag( 'admin_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Settings.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Settings.php index 396c1556b..225411bd9 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Settings.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Settings.php @@ -2,7 +2,7 @@ namespace WP_Rocket\Engine\Admin\Settings; use WP_Rocket\Admin\Options_Data; -use WP_Rocket\Subscriber\Third_Party\Plugins\Security\Sucuri_Subscriber; +use WP_Rocket\Addon\Sucuri\Subscriber as SucuriSubscriber; /** * Settings class. @@ -43,7 +43,7 @@ class Settings { * @since 3.6 * @see $this->sanitize_font() * - * @var string|bool + * @var array */ private $font_formats = [ 'otf', @@ -142,7 +142,14 @@ public function add_settings_fields( $settings_fields ) { $page = $args['page']; $section = $args['section']; unset( $args['page'], $args['section'] ); - + /** + * Filters the field before add to the settings + * + * @since 3.10 + * + * @param array $input Array of sanitized values after being submitted by the form. + */ + $args = apply_filters( 'rocket_before_add_field_to_settings', $args ); $this->settings[ $page ]['sections'][ $section ]['fields'][ $id ] = $args; } } @@ -216,16 +223,12 @@ public function sanitize_callback( $input ) { $input['minify_css'] = ! empty( $input['minify_css'] ) ? 1 : 0; $input['minify_js'] = ! empty( $input['minify_js'] ) ? 1 : 0; - $input['minify_concatenate_css'] = ! empty( $input['minify_concatenate_css'] ) ? 1 : 0; - $input['minify_concatenate_js'] = ! empty( $input['minify_concatenate_js'] ) ? 1 : 0; + $input['minify_concatenate_js'] = ! empty( $input['minify_concatenate_js'] ) ? 1 : 0; $input['defer_all_js'] = ! empty( $input['defer_all_js'] ) ? 1 : 0; $input['exclude_defer_js'] = ! empty( $input['exclude_defer_js'] ) ? rocket_sanitize_textarea_field( 'exclude_defer_js', $input['exclude_defer_js'] ) : []; - $input['delay_js'] = $this->sanitize_checkbox( $input, 'delay_js' ); - $input['delay_js_scripts'] = ! empty( $input['delay_js_scripts'] ) ? rocket_sanitize_textarea_field( 'delay_js_scripts', $input['delay_js_scripts'] ) : []; - $input['embeds'] = ! empty( $input['embeds'] ) ? 1 : 0; - $input['emoji'] = ! empty( $input['emoji'] ) ? 1 : 0; + $input['emoji'] = ! empty( $input['emoji'] ) ? 1 : 0; $input['lazyload'] = ! empty( $input['lazyload'] ) ? 1 : 0; $input['lazyload_iframes'] = ! empty( $input['lazyload_iframes'] ) ? 1 : 0; @@ -259,6 +262,7 @@ public function sanitize_callback( $input ) { // Option : Never cache the following pages. if ( ! empty( $input['cache_reject_uri'] ) ) { $input['cache_reject_uri'] = rocket_sanitize_textarea_field( 'cache_reject_uri', $input['cache_reject_uri'] ); + $input['cache_reject_uri'] = $this->check_global_exclusion( $input['cache_reject_uri'] ); } else { $input['cache_reject_uri'] = []; } @@ -312,15 +316,14 @@ public function sanitize_callback( $input ) { $input['critical_css'] = ! empty( $input['critical_css'] ) ? wp_strip_all_tags( str_replace( [ '<style>', '</style>' ], '', $input['critical_css'] ), [ "\'", '\"' ] ) : ''; // Database options. - $input['database_revisions'] = ! empty( $input['database_revisions'] ) ? 1 : 0; - $input['database_auto_drafts'] = ! empty( $input['database_auto_drafts'] ) ? 1 : 0; - $input['database_trashed_posts'] = ! empty( $input['database_trashed_posts'] ) ? 1 : 0; - $input['database_spam_comments'] = ! empty( $input['database_spam_comments'] ) ? 1 : 0; - $input['database_trashed_comments'] = ! empty( $input['database_trashed_comments'] ) ? 1 : 0; - $input['database_expired_transients'] = ! empty( $input['database_expired_transients'] ) ? 1 : 0; - $input['database_all_transients'] = ! empty( $input['database_all_transients'] ) ? 1 : 0; - $input['database_optimize_tables'] = ! empty( $input['database_optimize_tables'] ) ? 1 : 0; - $input['schedule_automatic_cleanup'] = ! empty( $input['schedule_automatic_cleanup'] ) ? 1 : 0; + $input['database_revisions'] = ! empty( $input['database_revisions'] ) ? 1 : 0; + $input['database_auto_drafts'] = ! empty( $input['database_auto_drafts'] ) ? 1 : 0; + $input['database_trashed_posts'] = ! empty( $input['database_trashed_posts'] ) ? 1 : 0; + $input['database_spam_comments'] = ! empty( $input['database_spam_comments'] ) ? 1 : 0; + $input['database_trashed_comments'] = ! empty( $input['database_trashed_comments'] ) ? 1 : 0; + $input['database_all_transients'] = ! empty( $input['database_all_transients'] ) ? 1 : 0; + $input['database_optimize_tables'] = ! empty( $input['database_optimize_tables'] ) ? 1 : 0; + $input['schedule_automatic_cleanup'] = ! empty( $input['schedule_automatic_cleanup'] ) ? 1 : 0; $cleanup_frequencies = [ 'daily' => 1, @@ -337,38 +340,9 @@ public function sanitize_callback( $input ) { // Options: Activate bot preload. $input['manual_preload'] = ! empty( $input['manual_preload'] ) ? 1 : 0; - // Option: activate sitemap preload. - $input['sitemap_preload'] = ! empty( $input['sitemap_preload'] ) ? 1 : 0; - - // Option : XML sitemaps URLs. - if ( ! empty( $input['sitemaps'] ) ) { - if ( ! is_array( $input['sitemaps'] ) ) { - $input['sitemaps'] = explode( "\n", $input['sitemaps'] ); - } - $input['sitemaps'] = array_map( 'trim', $input['sitemaps'] ); - $input['sitemaps'] = array_map( 'rocket_sanitize_xml', $input['sitemaps'] ); - $input['sitemaps'] = array_filter( $input['sitemaps'] ); - $input['sitemaps'] = array_unique( $input['sitemaps'] ); - } else { - $input['sitemaps'] = []; - } - // Option : fonts to preload. $input['preload_fonts'] = ! empty( $input['preload_fonts'] ) ? $this->sanitize_fonts( $input['preload_fonts'] ) : []; - // Options : CloudFlare. - $input['do_cloudflare'] = ! empty( $input['do_cloudflare'] ) ? 1 : 0; - $input['cloudflare_email'] = isset( $input['cloudflare_email'] ) ? sanitize_email( $input['cloudflare_email'] ) : ''; - $input['cloudflare_api_key'] = isset( $input['cloudflare_api_key'] ) ? sanitize_text_field( $input['cloudflare_api_key'] ) : ''; - $input['cloudflare_zone_id'] = isset( $input['cloudflare_zone_id'] ) ? sanitize_text_field( $input['cloudflare_zone_id'] ) : ''; - $input['cloudflare_devmode'] = isset( $input['cloudflare_devmode'] ) && is_numeric( $input['cloudflare_devmode'] ) ? (int) $input['cloudflare_devmode'] : 0; - $input['cloudflare_auto_settings'] = ( isset( $input['cloudflare_auto_settings'] ) && is_numeric( $input['cloudflare_auto_settings'] ) ) ? (int) $input['cloudflare_auto_settings'] : 0; - $input['cloudflare_protocol_rewrite'] = ! empty( $input['cloudflare_protocol_rewrite'] ) ? 1 : 0; - - if ( defined( 'WP_ROCKET_CF_API_KEY' ) ) { - $input['cloudflare_api_key'] = WP_ROCKET_CF_API_KEY; - } - // Options: Sucuri cache. And yeah, there's a typo, but now it's too late to fix ^^'. $input['sucury_waf_cache_sync'] = ! empty( $input['sucury_waf_cache_sync'] ) ? 1 : 0; @@ -380,7 +354,7 @@ public function sanitize_callback( $input ) { $input['sucury_waf_api_key'] = trim( $input['sucury_waf_api_key'] ); - if ( ! Sucuri_Subscriber::is_api_key_valid( $input['sucury_waf_api_key'] ) ) { + if ( ! SucuriSubscriber::is_api_key_valid( $input['sucury_waf_api_key'] ) ) { $input['sucury_waf_api_key'] = ''; if ( $input['sucury_waf_cache_sync'] && empty( $input['ignore'] ) ) { @@ -405,8 +379,7 @@ public function sanitize_callback( $input ) { // Option : CDN Cnames. if ( isset( $input['cdn_cnames'] ) ) { - $input['cdn_cnames'] = array_map( 'sanitize_text_field', $input['cdn_cnames'] ); - $input['cdn_cnames'] = array_filter( $input['cdn_cnames'] ); + $input['cdn_cnames'] = $this->sanitize_cdn_cnames( $input['cdn_cnames'] ); } else { $input['cdn_cnames'] = []; } @@ -463,7 +436,7 @@ public function sanitize_callback( $input ) { $notices = array_merge( (array) $wp_settings_errors, (array) get_transient( 'settings_errors' ) ); $notices = array_filter( $notices, - function( $error ) { + function ( $error ) { if ( ! $error || ! is_array( $error ) ) { return false; } @@ -499,7 +472,7 @@ function( $error ) { * @param string $key Array key to check. * @return int */ - public function sanitize_checkbox( $array, $key ) { + public function sanitize_checkbox( $array, $key ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.arrayFound return isset( $array[ $key ] ) && ! empty( $array[ $key ] ) ? 1 : 0; } @@ -547,7 +520,7 @@ private function sanitize_dns_prefetch( array $input ) { return array_unique( array_map( - function( $url ) { + function ( $url ) { return '//' . wp_parse_url( $url, PHP_URL_HOST ); }, $urls @@ -657,4 +630,72 @@ private function get_hosts() { return $this->hosts; } + + /** + * Sets radio buttons sub fields value from wp options. + * + * @since 3.10 + * + * @param array $sub_fields Array of fields to display.. + * @return array + */ + public function set_radio_buttons_sub_fields_value( $sub_fields ) { + + foreach ( $sub_fields as $id => &$args ) { + $args['id'] = $id; + $args['value'] = $this->options->get( $id, $args['default'] ); + $args = apply_filters( 'rocket_before_render_option_extra_field', $args ); + } + + return $sub_fields; + } + + /** + * Checks if the global exclusion pattern is used in the given field + * + * @since 3.10.3 + * + * @param array $field A field array value. + * + * @return array + */ + private function check_global_exclusion( $field ) { + if ( ! in_array( '/(.*)', $field, true ) ) { + return $field; + } + + add_settings_error( 'general', 'reject_uri_global_exclusion', __( 'Sorry! Adding /(.*) in Advanced Rules > Never Cache URL(s) was not saved because it disables caching and optimizations for every page on your site.', 'rocket' ) ); + + return array_diff_key( $field, array_flip( array_keys( $field, '/(.*)', true ) ) ); + } + + /** + * Sanitizes the CDN cnames values + * + * @param array $cnames Array of user submitted values for the cnames. + * + * @return array + */ + private function sanitize_cdn_cnames( array $cnames ) { + $cnames = array_map( + function ( $cname ) { + $cname = trim( $cname ); + + if ( empty( $cname ) ) { + return false; + } + + $cname_parts = get_rocket_parse_url( rocket_add_url_protocol( $cname ) ); + + if ( false === filter_var( $cname_parts['host'], FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME ) ) { + return false; + } + + return $cname_parts['scheme'] . '://' . $cname_parts['host'] . $cname_parts['path']; + }, + $cnames + ); + + return array_unique( array_filter( $cnames ) ); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Subscriber.php index 91a14ed01..0f6206b41 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Admin/Settings/Subscriber.php @@ -45,11 +45,34 @@ public static function get_subscribed_events() { [ 'add_imagify_page', 9 ], [ 'add_tutorials_page', 11 ], ], - 'admin_enqueue_scripts' => 'enqueue_rocket_scripts', + 'admin_enqueue_scripts' => [ + [ 'enqueue_rocket_scripts' ], + [ 'enqueue_url' ], + ], 'script_loader_tag' => [ 'async_wistia_script', 10, 2 ], + 'rocket_after_settings_radio_options' => [ 'display_radio_options_sub_fields', 11 ], + 'rocket_settings_tools_content' => 'display_mobile_cache_option', + 'wp_ajax_rocket_enable_mobile_cache' => 'enable_mobile_cache', + 'wp_rocket_upgrade' => [ 'enable_separate_cache_files_mobile', 9, 2 ], + 'admin_notices' => 'display_update_notice', ]; } + /** + * Enqueue the URL for option exporting. + * + * @return void + */ + public function enqueue_url() { + wp_localize_script( + 'wpr-admin-common', + 'rocket_option_export', + [ + 'rest_url_option_export' => rest_url( 'wp-rocket/v1/options/export/' ), + ] + ); + } + /** * Enqueues WP Rocket scripts on the settings page * @@ -161,7 +184,11 @@ public function add_menu_tools_page( $navigation ) { * @return array */ public function add_imagify_page( $navigation ) { - if ( Imagify_Partner::has_imagify_api_key() ) { + if ( + rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT' ) + || + Imagify_Partner::has_imagify_api_key() + ) { return $navigation; } @@ -191,4 +218,62 @@ public function add_tutorials_page( $navigation ) { return $navigation; } + + /** + * Displays the radio option sub fields + * + * @since 3.10 + * + * @param array $option_data array of option_id and sub_fields of the option. + * + * @return void + */ + public function display_radio_options_sub_fields( $option_data ) { + if ( empty( $option_data['sub_fields'] ) ) { + return; + } + $this->page->display_radio_options_sub_fields( $option_data['sub_fields'] ); + } + + /** + * Render mobile cache option. + * + * @return void + */ + public function display_mobile_cache_option(): void { + $this->page->display_mobile_cache_option(); + } + + /** + * Callback method for the AJAX request to mobile cache. + * + * @return void + */ + public function enable_mobile_cache(): void { + $this->page->enable_mobile_cache(); + } + + /** + * Enable Separate cache files for mobile devices on upgrade. + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * @return void + */ + public function enable_separate_cache_files_mobile( $new_version, $old_version ): void { + if ( version_compare( $old_version, '3.16', '>' ) ) { + return; + } + + $this->page->enable_separate_cache_files_mobile(); + } + + /** + * Display the update notice. + * + * @return void + */ + public function display_update_notice() { + $this->page->display_update_notice(); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/Admin/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/Admin/Subscriber.php new file mode 100644 index 000000000..281259b49 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/Admin/Subscriber.php @@ -0,0 +1,32 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\CDN\Admin; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + /** + * Returns an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'rocket_meta_boxes_fields' => [ 'add_meta_box', 9 ], + ]; + } + + /** + * Add the field to the WP Rocket metabox on the post edit page. + * + * @param string[] $fields Metaboxes fields. + * + * @return string[] + */ + public function add_meta_box( array $fields ) { + $fields['cdn'] = __( 'CDN', 'rocket' ); + + return $fields; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/CDN.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/CDN.php index add70f19f..a6245c594 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/CDN.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/CDN.php @@ -1,4 +1,6 @@ <?php +declare(strict_types=1); + namespace WP_Rocket\Engine\CDN; use WP_Rocket\Admin\Options_Data; @@ -41,14 +43,44 @@ public function __construct( Options_Data $options ) { * @return string */ public function rewrite( $html ) { - $pattern = '#[("\']\s*(?<url>(?:(?:https?:|)' . preg_quote( $this->get_base_url(), '#' ) . ')\/(?:(?:(?:' . $this->get_allowed_paths() . ')[^"\',)]+))|\/[^/](?:[^"\')\s>]+\.[[:alnum:]]+))\s*["\')]#i'; - return preg_replace_callback( - $pattern, - function( $matches ) { - return str_replace( $matches['url'], $this->rewrite_url( $matches['url'] ), $matches[0] ); - }, - $html - ); + $relative_path_pattern = ''; + + $buffer = $html; + + /** + * Filters the exclusion of CDN rewritting inside inline scripts + * + * @since 3.10.5 + * + * @param bool $enable True to exclude, false otherwise. + */ + if ( apply_filters( 'rocket_cdn_exclude_inline_scripts', true ) ) { + $buffer = $this->remove_inline_scripts( $html ); + } + + /** + * Filters the CDN rewriting of relative paths + * + * @since 3.10.5 + * + * @param bool $enable True to enable, false otherwise. + */ + if ( apply_filters( 'rocket_cdn_relative_paths', true ) ) { + $relative_path_pattern = '|\/[^/](?:[^"\')\s>]+\.[[:alnum:]]+)'; + } + + $pattern = '#[("\']\s*(?<url>(?:(?:https?:|)' . preg_quote( $this->get_base_url(), '#' ) . ')\/(?:(?:(?:' . $this->get_allowed_paths() . ')[^"\',)]+))' . $relative_path_pattern . ')\s*["\')]#i'; + + if ( ! preg_match_all( $pattern, $buffer, $matches, PREG_SET_ORDER ) ) { + return $html; + } + + foreach ( $matches as $match ) { + $cdn_url = str_replace( $match['url'], $this->rewrite_url( $match['url'] ), $match[0] ); + $html = str_replace( $match[0], $cdn_url, $html ); + } + + return $html; } /** @@ -60,7 +92,7 @@ function( $matches ) { * @return string */ public function rewrite_srcset( $html ) { - $pattern = '#\s+(?:data-lazy-|data-)?srcset\s*=\s*["\']\s*(?<sources>[^"\',\s]+\.[^"\',\s]+(?:\s+\d+[wx])?(?:\s*,\s*[^"\',\s]+\.[^"\',\s]+\s+\d+[wx])*)\s*["\']#i'; + $pattern = '#\s+(?:' . $this->get_srcset_attributes() . ')?srcset\s*=\s*["\']\s*(?<sources>[^"\',\s]+\.[^"\',\s]+(?:\s+\d+[wx])?(?:\s*,\s*[^"\',\s]+\.[^"\',\s]+(?:\s+\d+[wx])?)*)\s*["\']#i'; if ( ! preg_match_all( $pattern, $html, $srcsets, PREG_SET_ORDER ) ) { return $html; @@ -71,7 +103,8 @@ public function rewrite_srcset( $html ) { $cdn_srcset = $srcset['sources']; foreach ( $sources as $source ) { $url = preg_split( '#\s+#', trim( $source ) ); - $cdn_srcset = str_replace( $url[0], $this->rewrite_url( $url[0] ), $cdn_srcset ); + $cdn_source = str_replace( $url[0], $this->rewrite_url( $url[0] ), $source ); + $cdn_srcset = str_replace( $source, $cdn_source, $cdn_srcset ); } $cdn_srcsets = str_replace( $srcset['sources'], $cdn_srcset, $srcset[0] ); @@ -206,7 +239,6 @@ public function get_cdn_urls( $zones = [ 'all' ] ) { * Gets the base URL for the website * * @since 3.4 - * @author Remy Perona * * @return string */ @@ -218,7 +250,6 @@ private function get_base_url() { * Gets the allowed paths as a regex pattern for the CDN rewrite * * @since 3.4 - * @author Remy Perona * * @return string */ @@ -240,7 +271,6 @@ private function get_allowed_paths() { * Checks if the provided URL can be rewritten with the CDN URL * * @since 3.4 - * @author Remy Perona * * @param string $url URL to check. * @return boolean @@ -252,6 +282,7 @@ public function is_excluded( $url ) { 'php', 'html', 'htm', + 'cfm', ]; if ( in_array( pathinfo( $path, PATHINFO_EXTENSION ), $excluded_extensions, true ) ) { @@ -292,7 +323,6 @@ private function get_home_host() { * Gets the CDN zones for the provided URL * * @since 3.4 - * @author Remy Perona * * @param string $url URL to check. * @return array @@ -368,4 +398,58 @@ function ( $file ) use ( $delimiter ) { return implode( '|', $files ); } + + /** + * Get srcset attributes to rewrite to the CDN. + * + * @since 3.8.7 + * + * @return string A pipe-separated list of srcset attributes. + */ + private function get_srcset_attributes() { + /** + * Filter the srcset attributes. + * + * @since 3.8.7 + * + * @param array $srcset_attributes List of srcset attributes. + */ + $srcset_attributes = (array) apply_filters( + 'rocket_cdn_srcset_attributes', + [ + 'data-lazy-', + 'data-', + ] + ); + return implode( '|', $srcset_attributes ); + } + + /** + * Removes inline scripts from the HTML + * + * @since 3.10.5 + * + * @param string $html HTML content. + * + * @return string + */ + private function remove_inline_scripts( $html ): string { + if ( ! preg_match_all( '#<script(?:[^>]*)>(?<content>[\s\S]*?)</script>#msi', $html, $matches, PREG_SET_ORDER ) ) { + return $html; + } + + if ( empty( $matches ) ) { + return $html; + } + + foreach ( $matches as $inline_js ) { + if ( empty( $inline_js['content'] ) ) { + continue; + } + + $html = str_replace( $inline_js[0], '', $html ); + } + + return $html; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/APIClient.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/APIClient.php index f7b3b4dfc..526366cb5 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/APIClient.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/APIClient.php @@ -104,7 +104,7 @@ private function set_status_transient( $value, $duration ) { * * @since 3.5 * - * @return array + * @return array|WP_Error */ public function get_pricing_data() { $pricing = get_transient( 'rocketcdn_pricing' ); @@ -126,14 +126,18 @@ public function get_pricing_data() { private function get_remote_pricing_data() { $response = wp_remote_get( self::ROCKETCDN_API . 'pricing' ); + if ( is_wp_error( $response ) ) { + return $response; + } + if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { - return $this->get_wp_error(); + return $this->get_wp_error( __( 'We could not fetch the current price because RocketCDN API returned an unexpected error code.', 'rocket' ) ); } $data = wp_remote_retrieve_body( $response ); if ( empty( $data ) ) { - return $this->get_wp_error(); + return $this->get_wp_error( __( 'RocketCDN is not available at the moment. Please retry later.', 'rocket' ) ); } $data = json_decode( $data, true ); @@ -148,10 +152,12 @@ private function get_remote_pricing_data() { * * @since 3.5 * + * @param string $message Error message. + * * @return WP_Error */ - private function get_wp_error() { - return new WP_Error( 'rocketcdn_error', __( 'RocketCDN is not available at the moment. Please retry later', 'rocket' ) ); + private function get_wp_error( string $message ) { + return new WP_Error( 'rocketcdn_error', $message ); } /** @@ -193,6 +199,13 @@ public function purge_cache_request() { $args ); + if ( is_wp_error( $response ) ) { + return [ + 'status' => $status, + 'message' => $response->get_error_message(), + ]; + } + if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { return [ 'status' => $status, @@ -224,7 +237,7 @@ public function purge_cache_request() { 'message' => sprintf( // translators: %s = message returned by the API. __( 'RocketCDN cache purge failed: %s.', 'rocket' ), - $data->message + isset( $data->message ) ? $data->message : '' ), ]; } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/AdminPageSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/AdminPageSubscriber.php index bf07a4c84..eeba4355b 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/AdminPageSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/AdminPageSubscriber.php @@ -56,7 +56,6 @@ public function __construct( APIClient $api_client, Options_Data $options, Beaco public static function get_subscribed_events() { return [ 'rocket_dashboard_after_account_data' => 'display_rocketcdn_status', - 'rocket_after_cdn_sections' => 'display_manage_subscription', 'rocket_cdn_settings_fields' => 'rocketcdn_field', 'admin_post_rocket_purge_rocketcdn' => 'purge_cdn_cache', 'rocket_settings_page_footer' => 'add_subscription_modal', @@ -72,6 +71,15 @@ public static function get_subscribed_events() { * @return void */ public function display_rocketcdn_status() { + /** + * Filters the display of the RocketCDN status. + * + * @param bool $display_rocketcdn_status; true to display, false otherwise. + */ + if ( ! apply_filters( 'rocket_display_rocketcdn_status', true ) ) { + return; + } + if ( $this->is_white_label_account() ) { return; } @@ -163,35 +171,6 @@ public function rocketcdn_field( $fields ) { return $fields; } - /** - * Displays the button to open the subscription modal - * - * @since 3.5 - * - * @return void - */ - public function display_manage_subscription() { - if ( $this->is_white_label_account() ) { - return; - } - - if ( ! rocket_is_live_site() ) { - return; - } - - $subscription_data = $this->api_client->get_subscription_data(); - - if ( 'running' !== $subscription_data['subscription_status'] ) { - return; - } - - ?> - <p class="wpr-rocketcdn-subscription"> - <button class="wpr-rocketcdn-open" data-micromodal-trigger="wpr-rocketcdn-modal"><?php esc_html_e( 'Manage Subscription', 'rocket' ); ?></button> - </p> - <?php - } - /** * Purges the CDN cache and store the response in a transient. * diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/NoticesSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/NoticesSubscriber.php index f870fd04f..6dd623185 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/NoticesSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/NoticesSubscriber.php @@ -2,6 +2,7 @@ namespace WP_Rocket\Engine\CDN\RocketCDN; use WP_Rocket\Abstract_Render; +use WP_Rocket\Engine\Admin\Beacon\Beacon; use WP_Rocket\Event_Management\Subscriber_Interface; /** @@ -17,16 +18,25 @@ class NoticesSubscriber extends Abstract_Render implements Subscriber_Interface */ private $api_client; + /** + * Beacon instance + * + * @var Beacon + */ + private $beacon; + /** * Constructor * * @param APIClient $api_client RocketCDN API Client instance. + * @param Beacon $beacon Beacon instance. * @param string $template_path Path to the templates. */ - public function __construct( APIClient $api_client, $template_path ) { + public function __construct( APIClient $api_client, Beacon $beacon, $template_path ) { parent::__construct( $template_path ); $this->api_client = $api_client; + $this->beacon = $beacon; } /** @@ -53,6 +63,15 @@ public static function get_subscribed_events() { * @return void */ public function promote_rocketcdn_notice() { + /** + * Filters RocketCDN promotion notice. + * + * @param bool $promotion_notice; true to display, false otherwise. + */ + if ( ! apply_filters( 'rocket_promote_rocketcdn_notice', true ) ) { + return; + } + if ( $this->is_white_label_account() ) { return; } @@ -147,10 +166,14 @@ public function dismiss_notice() { check_ajax_referer( 'rocketcdn_dismiss_notice', 'nonce', true ); if ( ! current_user_can( 'rocket_manage_options' ) ) { + wp_send_json_error( 'no permissions' ); + return; } update_user_meta( get_current_user_id(), 'rocketcdn_dismiss_notice', true ); + + wp_send_json_success(); } /** @@ -161,6 +184,15 @@ public function dismiss_notice() { * @return void */ public function display_rocketcdn_cta() { + /** + * Filters the display of the RocketCDN cta banner. + * + * @param bool $display_cta_banner; true to display, false otherwise. + */ + if ( ! apply_filters( 'rocket_display_rocketcdn_cta', true ) ) { + return; + } + if ( $this->is_white_label_account() ) { return; } @@ -192,11 +224,21 @@ public function display_rocketcdn_cta() { ]; if ( is_wp_error( $pricing ) ) { + $beacon = $this->beacon->get_suggest( 'rocketcdn_error' ); + $more_info = sprintf( + // translators: %1$is = opening link tag, %2$s = closing link tag. + __( '%1$sMore Info%2$s', 'rocket' ), + '<a href="' . esc_url( $beacon['url'] ) . '" data-beacon-article="' . esc_attr( $beacon['id'] ) . '" rel="noopener noreferrer" target="_blank">', + '</a>' + ); + + $message = $pricing->get_error_message() . ' ' . $more_info; + $big_cta_data = [ 'container_class' => $cta_big_class, 'nopromo_variant' => $nopromo_variant, 'error' => true, - 'message' => $pricing->get_error_message(), + 'message' => $message, ]; } else { $current_price = number_format_i18n( $pricing['monthly_price'], 2 ); @@ -241,10 +283,14 @@ public function toggle_cta() { check_ajax_referer( 'rocket-ajax', 'nonce', true ); if ( ! current_user_can( 'rocket_manage_options' ) ) { + wp_send_json_error( 'no permissions' ); + return; } if ( ! isset( $_POST['status'] ) ) { + wp_send_json_error( 'missing status' ); + return; } @@ -253,6 +299,8 @@ public function toggle_cta() { } elseif ( 'small' === $_POST['status'] ) { update_user_meta( get_current_user_id(), 'rocket_rocketcdn_cta_hidden', true ); } + + wp_send_json_success(); } /** @@ -277,12 +325,26 @@ public function purge_cache_notice() { return; } + $message = $purge_response['message']; + + if ( 'error' === $purge_response['status'] ) { + $beacon = $this->beacon->get_suggest( 'rocketcdn_error' ); + $more_info = sprintf( + // translators: %1$is = opening link tag, %2$s = closing link tag. + __( '%1$sMore Info%2$s', 'rocket' ), + '<a href="' . esc_url( $beacon['url'] ) . '" data-beacon-article="' . esc_attr( $beacon['id'] ) . '" rel="noopener noreferrer" target="_blank">', + '</a>' + ); + + $message .= ' ' . $more_info; + } + delete_transient( 'rocketcdn_purge_cache_response' ); rocket_notice_html( [ 'status' => $purge_response['status'], - 'message' => $purge_response['message'], + 'message' => $message, ] ); } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/RESTSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/RESTSubscriber.php index 0fd4a1c8d..25b20d673 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/RESTSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/RESTSubscriber.php @@ -125,7 +125,7 @@ public function register_disable_route() { * * @param \WP_REST_Request $request the WP REST Request object. * - * @return string + * @return \WP_REST_Response|\WP_Error */ public function enable( \WP_REST_Request $request ) { $params = $request->get_body_params(); @@ -150,7 +150,7 @@ public function enable( \WP_REST_Request $request ) { * * @param \WP_REST_Request $request the WP Rest Request object. * - * @return string + * @return \WP_REST_Response|\WP_Error */ public function disable( \WP_REST_Request $request ) { $this->cdn_options->disable(); @@ -176,7 +176,7 @@ public function disable( \WP_REST_Request $request ) { * @return bool */ public function validate_email( $param ) { - return $param === $this->options->get( 'consumer_email' ); + return ! empty( $param ) && $param === $this->options->get( 'consumer_email' ); } /** @@ -189,6 +189,6 @@ public function validate_email( $param ) { * @return bool */ public function validate_key( $param ) { - return $param === $this->options->get( 'consumer_key' ); + return ! empty( $param ) && $param === $this->options->get( 'consumer_key' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/ServiceProvider.php index 10ec396c1..e4a63cb28 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/ServiceProvider.php @@ -1,20 +1,14 @@ <?php namespace WP_Rocket\Engine\CDN\RocketCDN; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; /** * Service provider for RocketCDN - * - * @since 3.5 */ class ServiceProvider extends AbstractServiceProvider { /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -28,37 +22,51 @@ class ServiceProvider extends AbstractServiceProvider { ]; /** - * Registers the RocketCDN classes in the container + * Check if the service provider provides a specific service. * - * @since 3.5 + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { + public function register(): void { $options = $this->getContainer()->get( 'options' ); // RocketCDN API Client. - $this->getContainer()->add( 'rocketcdn_api_client', 'WP_Rocket\Engine\CDN\RocketCDN\APIClient' ); + $this->getContainer()->add( 'rocketcdn_api_client', APIClient::class ); // RocketCDN CDN options manager. - $this->getContainer()->add( 'rocketcdn_options_manager', 'WP_Rocket\Engine\CDN\RocketCDN\CDNOptionsManager' ) - ->withArgument( $this->getContainer()->get( 'options_api' ) ) - ->withArgument( $options ); + $this->getContainer()->add( 'rocketcdn_options_manager', CDNOptionsManager::class ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ) + ->addArgument( $options ); // RocketCDN Data manager subscriber. - $this->getContainer()->share( 'rocketcdn_data_manager_subscriber', 'WP_Rocket\Engine\CDN\RocketCDN\DataManagerSubscriber' ) - ->withArgument( $this->getContainer()->get( 'rocketcdn_api_client' ) ) - ->withArgument( $this->getContainer()->get( 'rocketcdn_options_manager' ) ); + $this->getContainer()->addShared( 'rocketcdn_data_manager_subscriber', DataManagerSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'rocketcdn_api_client' ) ) + ->addArgument( $this->getContainer()->get( 'rocketcdn_options_manager' ) ) + ->addTag( 'admin_subscriber' ); // RocketCDN REST API Subscriber. - $this->getContainer()->share( 'rocketcdn_rest_subscriber', 'WP_Rocket\Engine\CDN\RocketCDN\RESTSubscriber' ) - ->withArgument( $this->getContainer()->get( 'rocketcdn_options_manager' ) ) - ->withArgument( $options ); + $this->getContainer()->addShared( 'rocketcdn_rest_subscriber', RESTSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'rocketcdn_options_manager' ) ) + ->addArgument( $options ) + ->addTag( 'common_subscriber' ); // RocketCDN Notices Subscriber. - $this->getContainer()->share( 'rocketcdn_notices_subscriber', 'WP_Rocket\Engine\CDN\RocketCDN\NoticesSubscriber' ) - ->withArgument( $this->getContainer()->get( 'rocketcdn_api_client' ) ) - ->withArgument( __DIR__ . '/views' ); + $this->getContainer()->addShared( 'rocketcdn_notices_subscriber', NoticesSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'rocketcdn_api_client' ) ) + ->addArgument( $this->getContainer()->get( 'beacon' ) ) + ->addArgument( __DIR__ . '/views' ) + ->addTag( 'admin_subscriber' ); // RocketCDN settings page subscriber. - $this->getContainer()->share( 'rocketcdn_admin_subscriber', 'WP_Rocket\Engine\CDN\RocketCDN\AdminPageSubscriber' ) - ->withArgument( $this->getContainer()->get( 'rocketcdn_api_client' ) ) - ->withArgument( $options ) - ->withArgument( $this->getContainer()->get( 'beacon' ) ) - ->withArgument( __DIR__ . '/views' ); + $this->getContainer()->addShared( 'rocketcdn_admin_subscriber', AdminPageSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'rocketcdn_api_client' ) ) + ->addArgument( $options ) + ->addArgument( $this->getContainer()->get( 'beacon' ) ) + ->addArgument( __DIR__ . '/views' ) + ->addTag( 'admin_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/composer.json b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/composer.json deleted file mode 100644 index 5c0ae5afc..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/composer.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "wp-media/module-rocketcdn", - "description": "Module for RocketCDN integration", - "homepage": "https://github.com/wp-media/module-rocketcdn", - "license": "GPL-2.0+", - "authors": [ - { - "name": "WP Media", - "email": "contact@wp-media.me", - "homepage": "https://wp-media.me" - } - ], - "type": "library", - "config": { - "sort-packages": true - }, - "support": { - "issues": "https://github.com/wp-media/module-rocketcdn/issues", - "source": "https://github.com/wp-media/module-rocketcdn" - }, - "require-dev": { - "php": "^5.6 || ^7", - "brain/monkey": "^2.0", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "phpcompatibility/phpcompatibility-wp": "^2.0", - "phpunit/phpunit": "^5.7 || ^7", - "roave/security-advisories": "dev-master", - "wp-coding-standards/wpcs": "^2", - "wp-media/event-manager": "^3.1", - "wp-media/options": "^3.0", - "wp-media/module-container": "^2.4", - "wp-media/phpunit": "^1.0", - "wp-media/phpunit-wp-rocket": "^1.0" - }, - "autoload": { - "psr-4": { "WP_Rocket\\Engine\\CDN\\RocketCDN\\": "." } - }, - "autoload-dev": { - "psr-4": { "WP_Rocket\\Tests\\": "Tests/" } - }, - "scripts": { - "test-unit": "\"vendor/bin/phpunit\" --testsuite unit --colors=always --configuration Tests/Unit/phpunit.xml.dist", - "test-integration": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration Tests/Integration/phpunit.xml.dist --exclude-group AdminOnly", - "test-integration-adminonly": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration Tests/Integration/phpunit.xml.dist --group AdminOnly", - "run-tests": [ - "@test-unit", - "@test-integration", - "@test-integration-adminonly" - ], - "install-codestandards": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", - "phpcs": "phpcs --basepath=.", - "phpcs-changed": "./bin/phpcs-changed.sh", - "phpcs:fix": "phpcbf" - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/views/cta-big.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/views/cta-big.php index 08f342a35..cb5b3608d 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/views/cta-big.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/RocketCDN/views/cta-big.php @@ -19,7 +19,7 @@ <div class="wpr-rocketcdn-cta <?php echo esc_attr( $data['container_class'] ); ?>" id="wpr-rocketcdn-cta"> <?php if ( ! empty( $data['promotion_campaign'] ) ) : ?> <div class="wpr-flex wpr-rocketcdn-promo"> - <h3 class="wpr-title1"><?php echo esc_html( $data['promotion_campaign'] ); ?></h3> + <h3 class="wpr-rocketcdn-promo-title"><?php echo esc_html( $data['promotion_campaign'] ); ?></h3> <p class="wpr-title2 wpr-rocketcdn-promo-date"> <?php printf( @@ -39,7 +39,7 @@ <li class="wpr-rocketcdn-feature wpr-rocketcdn-bandwidth"> <?php // translators: %1$s = opening strong tag, %2$s = closing strong tag. - printf( esc_html__( 'High performance Content Delivery Network (CDN) with %1$sunlimited bandwith%2$s', 'rocket' ), '<strong>', '</strong>' ); + printf( esc_html__( 'High performance Content Delivery Network (CDN) with %1$sunlimited bandwidth%2$s', 'rocket' ), '<strong>', '</strong>' ); ?> </li> <li class="wpr-rocketcdn-feature wpr-rocketcdn-configuration"> @@ -54,42 +54,40 @@ printf( esc_html__( 'WP Rocket integration: the CDN option is %1$sautomatically configured%2$s in our plugin', 'rocket' ), '<strong>', '</strong>' ); ?> </li> + <li class="wpr-rocketcdn-cta-footer"> + <a href="https://wp-rocket.me/rocketcdn/" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Learn more about RocketCDN', 'rocket' ); ?></a> + </li> + <?php if ( ! empty( $data['promotion_campaign'] ) ) : ?> + <li class="wpr-rocketcdn-cta-promo-footer"> + <?php + printf( + // translators: %1$s = discounted price, %2$s = regular price. + esc_html__( '*$%1$s/month for 12 months then $%2$s/month. You can cancel your subscription at any time.', 'rocket' ), + esc_html( str_replace( '*', '', $data['current_price'] ) ), + esc_html( $data['regular_price'] ) + ); + ?> + </li> + <?php endif; ?> </ul> <div class="wpr-rocketcdn-pricing"> <?php if ( ! empty( $data['error'] ) ) : ?> - <p><?php echo esc_html( $data['message'] ); ?></p> + <p><?php echo $data['message']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p> <?php else : ?> <?php if ( ! empty( $data['regular_price'] ) ) : ?> <h4 class="wpr-title2 wpr-rocketcdn-pricing-regular"><del>$<?php echo esc_html( $data['regular_price'] ); ?></del></h4> <?php endif; ?> <h4 class="wpr-rocketcdn-pricing-current"> - <?php - printf( - // translators: %s = price of RocketCDN subscription. - esc_html__( '%s / month', 'rocket' ), - '<span class="wpr-title1">$' . esc_html( $data['current_price'] ) . '</span>' - ); - ?> + <span class="wpr-rocketcdn-cta-currency-minor">$</span> + <span class="wpr-rocketcdn-cta-currency-major"><?php echo esc_html( substr( $data['current_price'], 0, strpos( $data['current_price'], '.' ) ) ); ?></span> + <span class="wpr-rocketcdn-cta-currency-minor"><?php echo esc_html( substr( $data['current_price'], strpos( $data['current_price'], '.' ) ) ); ?> + </span> </h4> + <p class="wpr-rocketcdn-cta-billing-detail"><?php esc_html_e( 'Billed monthly', 'rocket' ); ?></p> <button class="wpr-button wpr-rocketcdn-open" data-micromodal-trigger="wpr-rocketcdn-modal"><?php esc_html_e( 'Get Started', 'rocket' ); ?></button> <?php endif; ?> </div> </div> </section> - <div class="wpr-rocketcdn-cta-footer"> - <a href="https://go.wp-rocket.me/rocket-cdn" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Learn more about RocketCDN', 'rocket' ); ?></a> - </div> <button class="wpr-rocketcdn-cta-close<?php echo esc_attr( $data['nopromo_variant'] ); ?>" id="wpr-rocketcdn-close-cta"><span class="screen-reader-text"><?php esc_html_e( 'Reduce this banner', 'rocket' ); ?></span></button> - <?php if ( ! empty( $data['promotion_campaign'] ) ) : ?> - <p> - <?php - printf( - // translators: %1$s = discounted price, %2$s = regular price. - esc_html__( '* $%1$s/month for 12 months then $%2$s/month. You can cancel your subscription at any time.', 'rocket' ), - esc_html( str_replace( '*', '', $data['current_price'] ) ), - esc_html( $data['regular_price'] ) - ); - ?> - </p> -<?php endif; ?> </div> diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/ServiceProvider.php index 45fd0ba39..9bad58684 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/ServiceProvider.php @@ -1,40 +1,50 @@ <?php namespace WP_Rocket\Engine\CDN; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\CDN\Admin\Subscriber as AdminSubscriber; /** * Service provider for WP Rocket CDN - * - * @since 3.5.5 */ class ServiceProvider extends AbstractServiceProvider { /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ protected $provides = [ 'cdn', 'cdn_subscriber', + 'cdn_admin_subscriber', ]; /** - * Registers the services in the container + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { + public function register(): void { $options = $this->getContainer()->get( 'options' ); - $this->getContainer()->share( 'cdn', 'WP_Rocket\Engine\CDN\CDN' ) - ->withArgument( $options ); - $this->getContainer()->share( 'cdn_subscriber', 'WP_Rocket\Engine\CDN\Subscriber' ) - ->withArgument( $options ) - ->withArgument( $this->getContainer()->get( 'cdn' ) ); + $this->getContainer()->addShared( 'cdn', CDN::class ) + ->addArgument( $options ); + $this->getContainer()->addShared( 'cdn_subscriber', Subscriber::class ) + ->addArgument( $options ) + ->addArgument( $this->getContainer()->get( 'cdn' ) ) + ->addTag( 'common_subscriber' ); + $this->getContainer()->addShared( 'cdn_admin_subscriber', AdminSubscriber::class ) + ->addTag( 'admin_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CDN/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/CDN/Subscriber.php index ad96701c5..e8a45b532 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CDN/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CDN/Subscriber.php @@ -28,7 +28,7 @@ class Subscriber implements Subscriber_Interface { * Constructor * * @param Options_Data $options WP Rocket Options instance. - * @param CDN $cdn CDN instance. + * @param CDN $cdn CDN instance. */ public function __construct( Options_Data $options, CDN $cdn ) { $this->options = $options; @@ -49,12 +49,15 @@ public static function get_subscribed_events() { [ 'rewrite_srcset', 21 ], ], 'rocket_css_content' => 'rewrite_css_properties', + 'rocket_usedcss_content' => 'rewrite_css_properties', 'rocket_cdn_hosts' => [ 'get_cdn_hosts', 10, 2 ], 'rocket_dns_prefetch' => 'add_dns_prefetch_cdn', 'rocket_facebook_sdk_url' => 'add_cdn_url', 'rocket_css_url' => [ 'add_cdn_url', 10, 2 ], 'rocket_js_url' => [ 'add_cdn_url', 10, 2 ], 'rocket_asset_url' => [ 'maybe_replace_url', 10, 2 ], + 'wp_resource_hints' => [ 'add_preconnect_cdn', 10, 2 ], + 'rocket_font_url' => [ 'add_cdn_url', 10, 2 ], ]; } @@ -64,6 +67,7 @@ public static function get_subscribed_events() { * @since 3.4 * * @param string $html HTML content. + * * @return string */ public function rewrite( $html ) { @@ -80,6 +84,7 @@ public function rewrite( $html ) { * @since 3.4.0.4 * * @param string $html HTML content. + * * @return string */ public function rewrite_srcset( $html ) { @@ -96,6 +101,7 @@ public function rewrite_srcset( $html ) { * @since 3.4 * * @param string $content CSS content. + * * @return string */ public function rewrite_css_properties( $content ) { @@ -104,7 +110,7 @@ public function rewrite_css_properties( $content ) { * * @since 2.6 * - * @param bool true to apply CDN to properties, false otherwise + * @param bool $do_rewrite true to apply CDN to properties, false otherwise. */ $do_rewrite = apply_filters( 'do_rocket_cdn_css_properties', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals @@ -155,6 +161,7 @@ public function get_cdn_hosts( array $hosts = [], array $zones = [ 'all' ] ) { * @since 3.4 * * @param array $domains Domain names to DNS prefetch. + * * @return array */ public function add_dns_prefetch_cdn( $domains ) { @@ -176,8 +183,9 @@ public function add_dns_prefetch_cdn( $domains ) { * * @since 3.4 * - * @param string $url URL to rewrite. + * @param string $url URL to rewrite. * @param string $original_url Original URL for this URL. Optional. + * * @return string */ public function add_cdn_url( $url, $original_url = '' ) { @@ -195,8 +203,9 @@ public function add_cdn_url( $url, $original_url = '' ) { * * @since 3.5.3 * - * @param string $url URL of the asset. + * @param string $url URL of the asset. * @param array $zones Array of corresponding zones for the asset. + * * @return string */ public function maybe_replace_url( $url, array $zones = [ 'all' ] ) { @@ -241,6 +250,69 @@ public function maybe_replace_url( $url, array $zones = [ 'all' ] ) { return $url; } + /** + * Add a preconnect tag for the CDN. + * + * @since 3.8.3 + * + * @param array $urls The initial array of wp_resource_hint urls. + * @param string $relation_type The relation type for the hint: eg., 'preconnect', 'prerender', etc. + * + * @return array The filtered urls. + */ + public function add_preconnect_cdn( array $urls, string $relation_type ): array { + if ( + 'preconnect' !== $relation_type + || + rocket_bypass() + || + ! $this->is_allowed() + || + ! $this->is_cdn_enabled() + ) { + return $urls; + } + + $cdn_urls = $this->cdn->get_cdn_urls( [ 'all', 'images', 'css_and_js', 'css', 'js' ] ); + + if ( empty( $cdn_urls ) ) { + return $urls; + } + + foreach ( $cdn_urls as $url ) { + $url_parts = get_rocket_parse_url( $url ); + + if ( empty( $url_parts['scheme'] ) ) { + if ( preg_match( '/^(?![\/])(?=[^\.]+\/).+/i', $url ) ) { + continue; + } + + $url = '//' . $url; + $url_parts = get_rocket_parse_url( $url ); + } + + $domain = empty( $url_parts['scheme'] ) + ? '//' . $url_parts['host'] + : $url_parts['scheme'] . '://' . $url_parts['host']; + + // Note: As of 22 Feb, 2021 we cannot add more than one instance of a domain url + // on the wp_resource_hint() hook -- wp_resource_hint() will + // only actually print the first one. + // Ideally, we want both because CSS resources will use the crossorigin version, + // But JS resources will not. + // Jonathan has submitted a ticket to change this behavior: + // @see https://core.trac.wordpress.org/ticket/52465 + // Until then, we order these to prefer/print the non-crossorigin version. + $urls[] = [ 'href' => $domain ]; + $urls[] = [ + 'href' => $domain, + 'crossorigin' => 'anonymous', + ]; + } + + return $urls; + } + /** * Checks if CDN can be applied * diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Cache/AdminSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Cache/AdminSubscriber.php index ef02fdf83..697415134 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Cache/AdminSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Cache/AdminSubscriber.php @@ -2,6 +2,7 @@ namespace WP_Rocket\Engine\Cache; +use WP_Filesystem_Direct; use WP_Rocket\Event_Management\Event_Manager; use WP_Rocket\Event_Management\Event_Manager_Aware_Subscriber_Interface; @@ -32,15 +33,24 @@ class AdminSubscriber implements Event_Manager_Aware_Subscriber_Interface { */ private $wp_cache; + /** + * WordPress filesystem. + * + * @var WP_Filesystem_Direct + */ + private $filesystem; + /** * Instantiate the class * - * @param AdvancedCache $advanced_cache AdvancedCache instance. - * @param WPCache $wp_cache WPCache instance. + * @param AdvancedCache $advanced_cache AdvancedCache instance. + * @param WPCache $wp_cache WPCache instance. + * @param WP_Filesystem_Direct|null $filesystem WordPress filesystem. */ - public function __construct( AdvancedCache $advanced_cache, WPCache $wp_cache ) { + public function __construct( AdvancedCache $advanced_cache, WPCache $wp_cache, $filesystem = null ) { $this->advanced_cache = $advanced_cache; $this->wp_cache = $wp_cache; + $this->filesystem = ! empty( $filesystem ) ? $filesystem : rocket_direct_filesystem(); } /** @@ -50,18 +60,24 @@ public function __construct( AdvancedCache $advanced_cache, WPCache $wp_cache ) */ public static function get_subscribed_events() { $slug = rocket_get_constant( 'WP_ROCKET_SLUG' ); - return [ - 'admin_init' => [ + 'admin_init' => [ [ 'register_terms_row_action' ], [ 'maybe_set_wp_cache' ], ], - 'admin_notices' => [ + 'admin_notices' => [ [ 'notice_advanced_cache_permissions' ], [ 'notice_wp_config_permissions' ], ], - "update_option_{$slug}" => [ 'maybe_set_wp_cache', 12 ], - 'site_status_tests' => 'add_wp_cache_status_test', + "update_option_{$slug}" => [ 'maybe_set_wp_cache', 12 ], + 'site_status_tests' => 'add_wp_cache_status_test', + 'wp_rocket_upgrade' => [ 'on_update', 10, 2 ], + 'rocket_domain_changed' => [ + [ 'regenerate_configs' ], + [ 'delete_old_configs' ], + [ 'clear_cache', 10, 2 ], + ], + 'rocket_after_save_import' => 'maybe_regenerate_advanced_cache', ]; } @@ -165,4 +181,104 @@ public function notice_wp_config_permissions() { public function add_wp_cache_status_test( $tests ) { return $this->wp_cache->add_wp_cache_status_test( $tests ); } + + /** + * Regenerate configs. + * + * @return void + */ + public function regenerate_configs() { + rocket_generate_advanced_cache_file(); + flush_rocket_htaccess(); + rocket_generate_config_file(); + } + + /** + * Delete old config files. + * + * @return void + */ + public function delete_old_configs() { + $configs = []; + + if ( is_multisite() ) { + foreach ( get_sites( [ 'fields' => 'ids' ] ) as $site_id ) { + switch_to_blog( $site_id ); + $configs[] = $this->generate_config_path(); + restore_current_blog(); + } + } else { + $configs[] = $this->generate_config_path(); + } + + $contents = $this->filesystem->dirlist( WP_ROCKET_CONFIG_PATH ); + foreach ( $contents as $content ) { + $content = WP_ROCKET_CONFIG_PATH . $content['name']; + if ( ! preg_match( '#\.php$#', $content ) || ! $this->filesystem->is_file( $content ) || in_array( + $content, + $configs, + true + ) ) { + continue; + } + + if ( false === strpos( $this->filesystem->get_contents( $content ), '$rocket_cookie_hash' ) ) { + continue; + } + + $this->filesystem->delete( $content ); + } + } + + /** + * Generate the path to the config for the current website. + * + * @return string + */ + protected function generate_config_path() { + $file = get_rocket_parse_url( untrailingslashit( home_url() ) ); + $file['path'] = ( ! empty( $file['path'] ) ) ? str_replace( '/', '.', untrailingslashit( $file['path'] ) ) : ''; + return WP_ROCKET_CONFIG_PATH . strtolower( $file['host'] ) . $file['path'] . '.php'; + } + + /** + * Clear cache. + * + * @param string $current_url current URL from the website. + * @param string $old_url old URL from the website. + * + * @return void + */ + public function clear_cache( string $current_url, string $old_url ) { + rocket_clean_files( [ $old_url, $current_url ], null, false ); + } + + /** + * Regenerate the advanced cache file on update + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function on_update( $new_version, $old_version ) { + if ( version_compare( $old_version, '3.16', '>=' ) ) { + return; + } + rocket_generate_advanced_cache_file(); + } + + /** + * Regenerate config files after importing settings when do_caching_mobile_files is disabled and cach_mobile is enabled. + * + * @param boolean $regenerate_configs Returns whether to regenerate config. + * @return void + */ + public function maybe_regenerate_advanced_cache( bool $regenerate_configs ): void { + if ( ! $regenerate_configs ) { + return; + } + + $this->regenerate_configs(); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Cache/AdvancedCache.php b/wp-content/plugins/wp-rocket/inc/Engine/Cache/AdvancedCache.php index f74996f02..20ca2e9d5 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Cache/AdvancedCache.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Cache/AdvancedCache.php @@ -77,7 +77,7 @@ public function update_advanced_cache( $sites_number = 0 ) { * * @since 3.6.3 * - * @param bool True (default) to go ahead with advanced cache file generation; false to stop generation. + * @param bool $generate True (default) to go ahead with advanced cache file generation; false to stop generation. */ if ( ! (bool) apply_filters( 'rocket_generate_advanced_cache_file', true ) ) { return; diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Cache/Config/ConfigSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Cache/Config/ConfigSubscriber.php new file mode 100644 index 000000000..529b5bc56 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Cache/Config/ConfigSubscriber.php @@ -0,0 +1,108 @@ +<?php +namespace WP_Rocket\Engine\Cache\Config; + +use WP_Rocket\Event_Management\Subscriber_Interface; +use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Admin\Options; + +/** + * Subscriber for the Cache Config + */ +class ConfigSubscriber implements Subscriber_Interface { + + /** + * Options Data instance. + * + * @var Options_Data + */ + private $options; + + /** + * Options instance. + * + * @var Options + */ + private $options_api; + + /** + * Creates an instance of the Cache Config Subscriber. + * + * @param Options_Data $options WP Rocket options instance. + * @param Options $options_api Options instance. + */ + public function __construct( Options_Data $options, Options $options_api ) { + $this->options = $options; + $this->options_api = $options_api; + } + + /** + * Return an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'permalink_structure_changed' => 'regenerate_config_file', + 'pre_update_option_' . rocket_get_constant( 'WP_ROCKET_SLUG', 'wp_rocket_settings' ) => [ 'change_cache_reject_uri_with_permalink', 10, 2 ], + ]; + } + + /** + * Returns a matching user added patterns with permalink structure + * + * @param array $patterns user pattern. + * @return array + */ + private function match_pattern_with_permalink_structure( array $patterns ): array { + if ( empty( $patterns ) ) { + return $patterns; + } + + $patterns = array_map( + function ( $uri ) { + if ( false !== strpos( $uri, 'index.php' ) || '/' === $uri ) { + return $uri; + } + + return user_trailingslashit( $uri ); + }, + $patterns + ); + + return $patterns; + } + + /** + * Regenerate config file. + * + * @return void + */ + public function regenerate_config_file() { + $cache_reject_uri = $this->match_pattern_with_permalink_structure( $this->options->get( 'cache_reject_uri', [] ) ); + + $this->options->set( 'cache_reject_uri', $cache_reject_uri ); + $this->options_api->set( 'settings', $this->options->get_options() ); + + rocket_generate_config_file(); + } + + /** + * Modify cache_reject_uri values. + * + * @param mixed $value The new, unserialized option value. + * @param mixed $old_value The old option value. + * @return array + */ + public function change_cache_reject_uri_with_permalink( $value, $old_value ): array { + if ( ! isset( $old_value['cache_reject_uri'], $value['cache_reject_uri'] ) ) { + return $value; + } + + if ( $old_value['cache_reject_uri'] === $value['cache_reject_uri'] ) { + return $value; + } + + $value['cache_reject_uri'] = $this->match_pattern_with_permalink_structure( $value['cache_reject_uri'] ); + return $value; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Cache/Config/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Cache/Config/Subscriber.php new file mode 100644 index 000000000..3db9a0856 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Cache/Config/Subscriber.php @@ -0,0 +1,30 @@ +<?php +namespace WP_Rocket\Engine\Cache\Config; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +/** + * Subscriber for the Cache Config + */ +class Subscriber implements Subscriber_Interface { + + /** + * Return an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'permalink_structure_changed' => 'regenerate_config_file', + ]; + } + + /** + * Regenerate config file. + * + * @return void + */ + public function regenerate_config_file() { + rocket_generate_config_file(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Cache/Purge.php b/wp-content/plugins/wp-rocket/inc/Engine/Cache/Purge.php index 7b58afc97..c1eedf7dd 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Cache/Purge.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Cache/Purge.php @@ -2,6 +2,7 @@ namespace WP_Rocket\Engine\Cache; +use WP_Rocket\Engine\Preload\Database\Queries\Cache; use DirectoryIterator; use Exception; use WP_Term; @@ -19,12 +20,21 @@ class Purge { private $filesystem; /** - * Initialize the class + * Cache Query + * + * @var Cache + */ + protected $query; + + /** + * Initialize the class. * * @param WP_Filesystem_Direct $filesystem Filesystem instance. + * @param Cache $query Cache query instance. */ - public function __construct( $filesystem ) { + public function __construct( $filesystem, Cache $query ) { $this->filesystem = $filesystem; + $this->query = $query; } /** @@ -46,7 +56,11 @@ public function purge_dates_archives( $post ) { * @param boolean $pagination Purge also pagination. * @return void */ - private function purge_url( $url, $pagination = false ) { + public function purge_url( $url, $pagination = false ) { + if ( ! is_string( $url ) ) { + return; + } + global $wp_rewrite; $parsed_url = $this->parse_url( $url ); @@ -59,8 +73,14 @@ private function purge_url( $url, $pagination = false ) { } foreach ( $this->get_iterator( $path ) as $item ) { + if ( $item->isFile() ) { $this->filesystem->delete( $item->getPathname() ); + continue; + } + + if ( str_contains( $item->getPathname(), '#' ) ) { + $this->filesystem->delete( $item->getPathname(), true ); } } @@ -160,10 +180,16 @@ private function maybe_remove_dir( $dir ) { * @param WP_Post $post Post object. */ public function purge_post_terms_urls( WP_Post $post ) { - foreach ( $this->get_post_terms_urls( $post ) as $url ) { - $this->purge_url( $url ); + $urls = $this->get_post_terms_urls( $post ); + foreach ( $urls as $url ) { + $this->purge_url( $url, true ); } - + /** + * Action to preload urls after cleaning cache. + * + * @param array $urls urls to preload. + */ + do_action( 'rocket_after_clean_terms', $urls ); } /** @@ -178,9 +204,21 @@ public function purge_post_terms_urls( WP_Post $post ) { private function get_post_terms_urls( WP_Post $post ) { $urls = []; $taxonomies = get_object_taxonomies( get_post_type( $post->ID ), 'objects' ); + /** + * Filters the taxonomies excluded from post purge + * + * @since 3.9.1 + * + * @param array $excluded_taxonomies Array of excluded taxonomies names. + */ + $excluded_taxonomies = apply_filters( 'rocket_exclude_post_taxonomy', [] ); foreach ( $taxonomies as $taxonomy ) { - if ( ! $taxonomy->public || 'product_shipping_class' === $taxonomy->name ) { + if ( + ! $taxonomy->public + || + in_array( $taxonomy->name, $excluded_taxonomies, true ) + ) { continue; } @@ -211,6 +249,10 @@ private function get_post_terms_urls( WP_Post $post ) { } } } + + // Remove entries with empty values in array. + $urls = array_filter( $urls, 'is_string' ); + /** * Filter the list of taxonomies URLs * @@ -220,4 +262,52 @@ private function get_post_terms_urls( WP_Post $post ) { */ return apply_filters( 'rocket_post_terms_urls', $urls ); } + + /** + * Purge single cache file(s) added in the Never Cache URL(s). + * + * @param array $old_value An array of previous values for the settings. + * @param array $value An array of submitted values for the settings. + * @return void + */ + public function purge_cache_reject_uri_partially( array $old_value, array $value ): void { + // Bail out if cache_reject_uri key is not in the settings array. + if ( ! array_key_exists( 'cache_reject_uri', $old_value ) || ! array_key_exists( 'cache_reject_uri', $value ) ) { + return; + } + + // Get change in uris. + $diff = array_diff( $value['cache_reject_uri'], $old_value['cache_reject_uri'] ); + + // Bail out if values has not changed. + if ( empty( $diff ) ) { + return; + } + + $urls = []; + $wildcard = '(.*)'; + foreach ( $diff as $path ) { + // Check if string is a path or pattern. + if ( strpos( $path, $wildcard ) !== false ) { + $pattern = preg_replace( '#\(\.\*\).*#', '*', $path ); + $results = $this->query->query( + [ + 'search' => $pattern, + 'search_columns' => [ 'url' ], + 'status' => 'completed', + ] + ); + + foreach ( $results as $result ) { + $urls[] = $result->url; + } + + continue; + } + + // Get full url of never cache path. + $urls[] = home_url( $path ); + } + rocket_clean_files( array_unique( $urls ) ); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Cache/PurgeActionsSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Cache/PurgeActionsSubscriber.php index ba6374f30..bed2dcae1 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Cache/PurgeActionsSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Cache/PurgeActionsSubscriber.php @@ -1,8 +1,10 @@ <?php namespace WP_Rocket\Engine\Cache; +use WP_Post; use WP_Rocket\Event_Management\Subscriber_Interface; use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Logger\Logger; /** * Subscriber for the cache purge actions @@ -39,16 +41,24 @@ public function __construct( Options_Data $options, Purge $purge ) { * {@inheritdoc} */ public static function get_subscribed_events() { + $slug = rocket_get_constant( 'WP_ROCKET_SLUG' ); + return [ - 'profile_update' => 'purge_user_cache', - 'delete_user' => 'purge_user_cache', - 'create_term' => [ 'maybe_purge_cache_on_term_change', 10, 3 ], - 'edit_term' => [ 'maybe_purge_cache_on_term_change', 10, 3 ], - 'delete_term' => [ 'maybe_purge_cache_on_term_change', 10, 3 ], - 'after_rocket_clean_post' => [ + 'profile_update' => 'purge_user_cache', + 'delete_user' => 'purge_user_cache', + 'create_term' => [ 'maybe_purge_cache_on_term_change', 10, 3 ], + 'edit_term' => [ 'maybe_purge_cache_on_term_change', 10, 3 ], + 'delete_term' => [ 'maybe_purge_cache_on_term_change', 10, 3 ], + 'after_rocket_clean_post' => [ [ 'purge_dates_archives' ], [ 'purge_post_terms_urls' ], ], + 'rocket_saas_complete_job_status' => [ 'purge_url_cache', 100 ], + 'rocket_rucss_after_clearing_usedcss' => 'purge_url_cache', + 'rocket_after_save_dynamic_lists' => 'purge_cache_after_saving_dynamic_lists', + 'update_option_' . $slug => [ 'purge_cache_reject_uri_partially', 10, 2 ], + 'update_option_blog_public' => 'purge_cache', + 'wp_rocket_upgrade' => [ 'on_update', 10, 2 ], ]; } @@ -79,6 +89,10 @@ public function purge_user_cache( $user_id ) { * @return void */ public function maybe_purge_cache_on_term_change( $term_id, $tt_id, $taxonomy ) { + if ( rocket_is_importing() ) { + return; + } + if ( ! $this->is_taxonomy_public( $taxonomy ) ) { return; } @@ -137,4 +151,67 @@ private function should_purge_user_cache() { // This filter is documented in /inc/functions/files.php. return ! (bool) apply_filters( 'rocket_common_cache_logged_users', false ); } + + /** + * Purge cache after RUCSS + * + * @param string $url URL to be purged. + * + * @return void + */ + public function purge_url_cache( string $url ) { + // Flush cache for this url. + Logger::debug( 'RUCSS: Purge the cache for url: ' . $url ); + + $this->purge->purge_url( $url ); + } + + /** + * Clean the whole cache + * + * @return void + */ + public function purge_cache() { + rocket_clean_domain(); + } + + /** + * Purge single cache file(s) added in the Never Cache URL(s). + * + * @param array $old_value An array of previous values for the settings. + * @param array $value An array of submitted values for the settings. + * @return void + */ + public function purge_cache_reject_uri_partially( array $old_value, array $value ): void { + $this->purge->purge_cache_reject_uri_partially( $old_value, $value ); + } + + /** + * Purge cache after saving dynamic lists. + * + * @param bool $should_purge Should purge or not. + * + * @return void + */ + public function purge_cache_after_saving_dynamic_lists( $should_purge = true ) { + if ( ! $should_purge ) { + return; + } + $this->purge_cache(); + } + + /** + * Regenerate the advanced cache file on update + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function on_update( $new_version, $old_version ) { + if ( version_compare( $old_version, '3.15.3', '>=' ) ) { + return; + } + rocket_generate_advanced_cache_file(); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Cache/PurgeExpired/PurgeExpiredCache.php b/wp-content/plugins/wp-rocket/inc/Engine/Cache/PurgeExpired/PurgeExpiredCache.php index 0a5f649e0..7618bf4e9 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Cache/PurgeExpired/PurgeExpiredCache.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Cache/PurgeExpired/PurgeExpiredCache.php @@ -318,12 +318,12 @@ private function purge_dir( $dir_path, $file_age_limit ) { $dir_deleted = $this->purge_dir( $item->getPathname(), $file_age_limit ); $deleted = array_merge( $deleted, $dir_deleted ); - } elseif ( $item->isFile() && $item->getCTime() < $file_age_limit ) { + } elseif ( $item->isFile() && $item->getMTime() < $file_age_limit ) { $file_path = $item->getPathname(); /** * The file is older than our limit. - * This will also delete the file if `$item->getCTime()` fails. + * This will also delete the file if `$item->getMTime()` fails. */ if ( ! $this->filesystem->delete( $file_path ) ) { continue; @@ -401,5 +401,4 @@ public function update_lifespan_value( $old_lifespan, $old_lifespan_unit ) { update_option( 'wp_rocket_settings', $options ); } - } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Cache/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Cache/ServiceProvider.php index 50b60c08d..d561617e2 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Cache/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Cache/ServiceProvider.php @@ -1,21 +1,19 @@ <?php namespace WP_Rocket\Engine\Cache; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Cache\PurgeExpired\PurgeExpiredCache; +use WP_Rocket\Engine\Cache\PurgeExpired\Subscriber; +use WP_Rocket\Engine\Preload\Database\Queries\Cache as CacheQuery; +use WP_Rocket\Logger\Logger; +use WP_Rocket\Engine\Cache\Config\ConfigSubscriber; /** * Service Provider for cache subscribers - * - * @since 3.5.5 */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -27,34 +25,59 @@ class ServiceProvider extends AbstractServiceProvider { 'admin_cache_subscriber', 'expired_cache_purge', 'expired_cache_purge_subscriber', + 'preload_caches_query', + 'cache_config', ]; /** - * Registers the option array in the container + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { + public function register(): void { $filesystem = rocket_direct_filesystem(); - $this->getContainer()->add( 'advanced_cache', 'WP_Rocket\Engine\Cache\AdvancedCache' ) - ->withArgument( $this->getContainer()->get( 'template_path' ) . '/cache/' ) - ->withArgument( $filesystem ); - $this->getContainer()->add( 'wp_cache', 'WP_Rocket\Engine\Cache\WPCache' ) - ->withArgument( $filesystem ); - $this->getContainer()->add( 'purge', 'WP_Rocket\Engine\Cache\Purge' ) - ->withArgument( $filesystem ); - $this->getContainer()->share( 'purge_actions_subscriber', 'WP_Rocket\Engine\Cache\PurgeActionsSubscriber' ) - ->withArgument( $this->getContainer()->get( 'options' ) ) - ->withArgument( $this->getContainer()->get( 'purge' ) ); - $this->getContainer()->share( 'admin_cache_subscriber', 'WP_Rocket\Engine\Cache\AdminSubscriber' ) - ->withArgument( $this->getContainer()->get( 'advanced_cache' ) ) - ->withArgument( $this->getContainer()->get( 'wp_cache' ) ); + $this->getContainer()->add( 'preload_caches_query', CacheQuery::class ) + ->addArgument( new Logger() ); + $cache_query = $this->getContainer()->get( 'preload_caches_query' ); + + $this->getContainer()->add( 'advanced_cache', AdvancedCache::class ) + ->addArgument( $this->getContainer()->get( 'template_path' ) . '/cache/' ) + ->addArgument( $filesystem ); + $this->getContainer()->add( 'wp_cache', WPCache::class ) + ->addArgument( $filesystem ); + $this->getContainer()->add( 'purge', Purge::class ) + ->addArgument( $filesystem ) + ->addArgument( $cache_query ); + $this->getContainer()->addShared( 'purge_actions_subscriber', PurgeActionsSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'purge' ) ) + ->addTag( 'common_subscriber' ); + $this->getContainer()->addShared( 'admin_cache_subscriber', AdminSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'advanced_cache' ) ) + ->addArgument( $this->getContainer()->get( 'wp_cache' ) ) + ->addTag( 'admin_subscriber' ); - $this->getContainer()->add( 'expired_cache_purge', 'WP_Rocket\Engine\Cache\PurgeExpired\PurgeExpiredCache' ) - ->withArgument( rocket_get_constant( 'WP_ROCKET_CACHE_PATH' ) ); - $this->getContainer()->share( 'expired_cache_purge_subscriber', 'WP_Rocket\Engine\Cache\PurgeExpired\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'options' ) ) - ->withArgument( $this->getContainer()->get( 'expired_cache_purge' ) ); + $this->getContainer()->add( 'expired_cache_purge', PurgeExpiredCache::class ) + ->addArgument( rocket_get_constant( 'WP_ROCKET_CACHE_PATH' ) ); + $this->getContainer()->addShared( 'expired_cache_purge_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'expired_cache_purge' ) ) + ->addTag( 'common_subscriber' ); + $this->getContainer()->add( 'cache_config', ConfigSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ) + ->addTag( 'common_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Cache/WPCache.php b/wp-content/plugins/wp-rocket/inc/Engine/Cache/WPCache.php index d587293fc..8780386db 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Cache/WPCache.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Cache/WPCache.php @@ -118,17 +118,17 @@ public function maybe_set_wp_cache() { * @since 3.6.1 * * @param bool $value The value to set for WP_CACHE constant. - * @return void + * @return bool true on success, false otherwise. */ public function set_wp_cache_constant( $value ) { if ( ! $this->should_set_wp_cache_constant( $value ) ) { - return; + return false; } $config_file_path = $this->find_wpconfig_path(); if ( ! $config_file_path ) { - return; + return false; } $config_file_contents = $this->filesystem->get_contents( $config_file_path ); @@ -150,18 +150,18 @@ public function set_wp_cache_constant( $value ) { && $matches['value'] === $value ) { - return; + return false; } $constant = $this->get_wp_cache_content( $value ); if ( ! $wp_cache_found ) { - $config_file_contents = preg_replace( '/(<\?php)/i', "<?php\r\n{$constant}\r\n", $config_file_contents ); + $config_file_contents = preg_replace( '/(<\?php)/i', "<?php\r\n{$constant}\r\n", $config_file_contents, 1 ); } elseif ( ! empty( $matches['value'] ) && $matches['value'] !== $value ) { $config_file_contents = preg_replace( '/^\s*define\(\s*\'WP_CACHE\'\s*,\s*([^\s\)]*)\s*\).+/m', $constant, $config_file_contents ); } - $this->filesystem->put_contents( $config_file_path, $config_file_contents, rocket_get_filesystem_perms( 'file' ) ); + return $this->filesystem->put_contents( $config_file_path, $config_file_contents, rocket_get_filesystem_perms( 'file' ) ); } /** @@ -300,7 +300,7 @@ public function notice_wp_config_permissions() { * @return bool */ private function is_user_allowed() { - return current_user_can( 'rocket_manage_options' ) && rocket_valid_key(); + return ( rocket_get_constant( 'WP_CLI', false ) || current_user_can( 'rocket_manage_options' ) ) && rocket_valid_key(); } /** @@ -317,6 +317,7 @@ private function get_wp_cache_content( $value = 'true' ) { return "define( 'WP_CACHE', {$value} ); // Added by {$plugin_name}"; } + /** * Adds a Site Health check for the WP_CACHE constant value * @@ -326,6 +327,12 @@ private function get_wp_cache_content( $value = 'true' ) { * @return array */ public function add_wp_cache_status_test( $tests ) { + + // This filter is documented in inc/Engine/Cache/WPCache.php. + if ( ! (bool) apply_filters( 'rocket_set_wp_cache_constant', true ) ) { + return $tests; + } + $tests['direct']['wp_cache_status'] = [ 'label' => __( 'WP_CACHE value', 'rocket' ), 'test' => [ $this, 'check_wp_cache_value' ], diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Manager.php b/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Manager.php index b5d4d4709..f45c0bba0 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Manager.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Manager.php @@ -17,11 +17,11 @@ class Manager implements ActivationInterface, DeactivationInterface { 'rocket_purge_posts', 'rocket_purge_terms', 'rocket_purge_users', - 'rocket_purge_opcache', 'rocket_purge_cloudflare_cache', 'rocket_purge_sucuri_cache', 'rocket_preload_cache', 'rocket_regenerate_critical_css', + 'rocket_remove_unused_css', ]; /** @@ -140,6 +140,31 @@ public function add_group_to_ure( $groups ) { return $groups; } + /** + * Add WP Rocket as a cap group in Members + */ + public function add_cap_group_to_members() { + // @phpstan-ignore-next-line + \members_register_cap_group( + 'wp_rocket', + [ + 'label' => esc_html( 'WP Rocket' ), + 'priority' => 42, + 'caps' => $this->get_capabilities(), + ] + ); + } + + /** + * Add WP Rocket capabilities to Members + */ + public function add_caps_to_members() { + foreach ( $this->get_capabilities() as $cap ) { + // @phpstan-ignore-next-line + \members_register_cap( $cap, [ 'label' => $cap ] ); + } + } + /** * Adds WP Rocket capabilities on plugin upgrade * @@ -150,7 +175,7 @@ public function add_group_to_ure( $groups ) { * @return void */ public function add_capabilities_on_upgrade( $wp_rocket_version, $actual_version ) { - if ( version_compare( $actual_version, '3.4.0.1', '<' ) ) { + if ( version_compare( $actual_version, '3.9', '<' ) ) { $this->add_rocket_capabilities(); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/ServiceProvider.php index 848e2cb2a..a64ad84e8 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/ServiceProvider.php @@ -1,21 +1,14 @@ <?php namespace WP_Rocket\Engine\Capabilities; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; /** * Service Provider for capabilities - * - * @since 3.6.3 */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -25,13 +18,25 @@ class ServiceProvider extends AbstractServiceProvider { ]; /** - * Registers the option array in the container + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { - $this->getContainer()->add( 'capabilities_manager', 'WP_Rocket\Engine\Capabilities\Manager' ); - $this->getContainer()->share( 'capabilities_subscriber', 'WP_Rocket\Engine\Capabilities\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'capabilities_manager' ) ); + public function register(): void { + $this->getContainer()->add( 'capabilities_manager', Manager::class ); + $this->getContainer()->addShared( 'capabilities_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'capabilities_manager' ) ) + ->addTag( 'common_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Subscriber.php index 803f69f09..9fafab6de 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Capabilities/Subscriber.php @@ -39,6 +39,8 @@ public static function get_subscribed_events() { "option_page_capability_{$slug}" => 'required_capability', 'ure_built_in_wp_caps' => 'add_caps_to_ure', 'ure_capabilities_groups_tree' => 'add_group_to_ure', + 'members_register_cap_groups' => 'add_cap_group_to_members', + 'members_register_caps' => 'add_caps_to_members', 'wp_rocket_upgrade' => [ 'add_capabilities_on_upgrade', 12, 2 ], ]; } @@ -79,6 +81,21 @@ public function add_group_to_ure( $groups ) { return $this->capabilities->add_group_to_ure( $groups ); } + /** + * Add WP Rocket as a cap group in Members + */ + public function add_cap_group_to_members() { + $this->capabilities->add_cap_group_to_members(); + } + + /** + * Add WP Rocket capabilities to Members + */ + public function add_caps_to_members() { + $this->capabilities->add_caps_to_members(); + } + + /** * Adds WP Rocket capabilities on plugin upgrade * diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Ajax/AjaxHandler.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Ajax/AjaxHandler.php new file mode 100644 index 000000000..08c142d74 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Ajax/AjaxHandler.php @@ -0,0 +1,35 @@ +<?php + +namespace WP_Rocket\Engine\Common\Ajax; + +class AjaxHandler { + + /** + * Validate the referer before going further. + * + * @param string $action Action to validate. + * @param string $capacities User capacity to verify. + * @return bool + */ + public function validate_referer( string $action, string $capacities ) { + + check_admin_referer( $action ); + + if ( ! current_user_can( $capacities ) ) { + return false; + } + + return true; + } + + /** + * Redirect the page at the end of the logic. + * + * @param string $url URl to redirect to (by default referrer). + * @return void + */ + public function redirect( string $url = '' ) { + wp_safe_redirect( '' === $url ? wp_get_referer() : $url ); + rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ? wp_die() : exit; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Cache/CacheInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Cache/CacheInterface.php new file mode 100644 index 000000000..5daeb7b9d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Cache/CacheInterface.php @@ -0,0 +1,36 @@ +<?php + +namespace WP_Rocket\Engine\Common\Cache; + +interface CacheInterface extends \WP_Rocket\Dependencies\Psr\SimpleCache\CacheInterface { + + /** + * Generate the real URL. + * + * @param string $url original URL. + * @return string + */ + public function generate_url( string $url ): string; + + /** + * Is the root path available. + * + * @return bool + */ + public function is_accessible(): bool; + + /** + * Get root path from the cache. + * + * @return string + */ + public function get_root_path(): string; + + /** + * Generate a path from the URL. + * + * @param string $url URL to change to a path. + * @return string + */ + public function generate_path( string $url ): string; +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Cache/FilesystemCache.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Cache/FilesystemCache.php new file mode 100644 index 000000000..ee6fbc760 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Cache/FilesystemCache.php @@ -0,0 +1,236 @@ +<?php + +namespace WP_Rocket\Engine\Common\Cache; + +use WP_Rocket\Dependencies\Psr\SimpleCache\InvalidArgumentException; +use WP_Filesystem_Direct; + +class FilesystemCache implements CacheInterface { + + /** + * Root folder from the path. + * + * @var string + */ + protected $root_folder; + + /** + * WordPress filesystem. + * + * @var WP_Filesystem_Direct + */ + protected $filesystem; + + /** + * Class instantiation. + * + * @param string $root_folder Root folder from the path. + * @param WP_Filesystem_Direct|null $filesystem WordPress filesystem. + */ + public function __construct( string $root_folder, WP_Filesystem_Direct $filesystem = null ) { + $this->root_folder = $root_folder; + $this->filesystem = $filesystem ?: rocket_direct_filesystem(); + } + + + /** + * Fetches a value from the cache. + * + * @param string $key The unique key of this item in the cache. + * @param mixed $default Default value to return if the key does not exist. + * + * @return mixed The value of the item from the cache, or $default in case of cache miss. + */ + public function get( $key, $default = null ) { + $path = $this->generate_path( $key ); + + if ( ! $this->filesystem->exists( $path ) ) { + return $default; + } + + return $this->filesystem->get_contents( $path ); + } + + /** + * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. + * + * @param string $key The key of the item to store. + * @param mixed $value The value of the item to store, must be serializable. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + */ + public function set( $key, $value, $ttl = null ) { + $path = $this->generate_path( $key ); + $directory = dirname( $path ); + rocket_mkdir_p( $directory, $this->filesystem ); + return $this->filesystem->put_contents( $path, $value, rocket_get_filesystem_perms( 'file' ) ); + } + + /** + * Delete an item from the cache by its unique key. + * + * @param string $key The unique cache key of the item to delete. + * + * @return bool True if the item was successfully removed. False if there was an error. + */ + public function delete( $key ) { + $path = $this->generate_path( $key ); + if ( ! $this->filesystem->exists( $path ) ) { + return false; + } + if ( $this->filesystem->is_dir( $path ) ) { + rocket_rrmdir( $path, [], $this->filesystem ); + return true; + } + + return $this->filesystem->delete( $path ); + } + + /** + * Wipes clean the entire cache's keys. + * + * @return bool True on success and false on failure. + */ + public function clear() { + $root_path = $this->get_root_path(); + if ( ! $this->filesystem->exists( $root_path ) ) { + return false; + } + rocket_rrmdir( $root_path, [], $this->filesystem ); + return true; + } + + /** + * Obtains multiple cache items by their unique keys. + * + * @param iterable $keys A list of keys that can obtained in a single operation. + * @param mixed $default Default value to return for keys that do not exist. + * + * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value. + */ + public function getMultiple( $keys, $default = null ) { + $results = []; + foreach ( $keys as $key ) { + $results[ $key ] = $this->get( $key, $default ); + } + return $results; + } + + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @param iterable $values A list of key => value pairs for a multiple-set operation. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + */ + public function setMultiple( $values, $ttl = null ) { + $result = true; + foreach ( $values as $key => $value ) { + $result &= $this->set( $key, $value, $ttl ); + } + return (bool) $result; + } + + /** + * Deletes multiple cache items in a single operation. + * + * @param iterable $keys A list of string-based keys to be deleted. + * + * @return bool True if the items were successfully removed. False if there was an error. + */ + public function deleteMultiple( $keys ) { + $result = true; + foreach ( $keys as $key ) { + $result &= $this->delete( $key ); + } + return (bool) $result; + } + + /** + * Determines whether an item is present in the cache. + * + * NOTE: It is recommended that has() is only to be used for cache warming type purposes + * and not to be used within your live applications operations for get/set, as this method + * is subject to a race condition where your has() will return true and immediately after, + * another script can remove it making the state of your app out of date. + * + * @param string $key The cache item key. + * + * @return bool + */ + public function has( $key ) { + $path = $this->generate_path( $key ); + + return $this->filesystem->exists( $path ); + } + + /** + * Generate the real URL. + * + * @param string $url original URL. + * @return string + */ + public function generate_url( string $url ): string { + $path = $this->generate_path( $url ); + + $wp_content_dir = rocket_get_constant( 'WP_CONTENT_DIR' ); + + $wp_content_url = rocket_get_constant( 'WP_CONTENT_URL' ); + + $relative_path = str_replace( $wp_content_dir, '', $path ); + + $generated_url = $wp_content_url . $relative_path; + + return (string) apply_filters( 'rocket_css_url', $generated_url ); + } + + /** + * Generate a path from the URL. + * + * @param string $url URL to change to a path. + * @return string + */ + public function generate_path( string $url ): string { + $root_path = $this->get_root_path(); + $root_path = rtrim( $root_path, '/' ); + $parsed_url = get_rocket_parse_url( $url ); + $parsed_url_path = trim( $parsed_url['path'], '/' ); + + $home_url = home_url(); + $home_parsed_url = get_rocket_parse_url( $home_url ); + + $host = '' === $parsed_url['host'] || null === $parsed_url['host'] ? $home_parsed_url['host'] : $parsed_url['host']; + $parsed_url_host = '/' . $host; + + return $root_path . $parsed_url_host . '/' . $parsed_url_path; + } + + /** + * Is the root path available. + * + * @return bool + */ + public function is_accessible(): bool { + $root_path = $this->get_root_path(); + if ( ! $this->filesystem->exists( $root_path ) ) { + rocket_mkdir_p( $root_path, $this->filesystem ); + } + + return $this->filesystem->is_writable( $root_path ); + } + + /** + * Get root path from the cache. + * + * @return string + */ + public function get_root_path(): string { + return rtrim( _rocket_normalize_path( rocket_get_constant( 'WP_ROCKET_CACHE_ROOT_PATH' ) ) . $this->root_folder, '/' ) . '/'; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Clock/ClockInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Clock/ClockInterface.php new file mode 100644 index 000000000..487173258 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Clock/ClockInterface.php @@ -0,0 +1,27 @@ +<?php + +namespace WP_Rocket\Engine\Common\Clock; + +interface ClockInterface { + /** + * Retrieves the current time based on specified type. + * + * - The 'mysql' type will return the time in the format for MySQL DATETIME field. + * - The 'timestamp' or 'U' types will return the current timestamp or a sum of timestamp + * and timezone offset, depending on `$gmt`. + * - Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d'). + * + * If `$gmt` is a truthy value then both types will use GMT time, otherwise the + * output is adjusted with the GMT offset for the site. + * + * @since 1.0.0 + * @since 5.3.0 Now returns an integer if `$type` is 'U'. Previously a string was returned. + * + * @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp', 'U', + * or PHP date format string (e.g. 'Y-m-d'). + * @param int|bool $gmt Optional. Whether to use GMT timezone. Default false. + * + * @return int|string Integer if `$type` is 'timestamp' or 'U', string otherwise. + */ + public function current_time( string $type, $gmt = 0 ); +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Clock/WPRClock.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Clock/WPRClock.php new file mode 100644 index 000000000..59ca0b502 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Clock/WPRClock.php @@ -0,0 +1,35 @@ +<?php + +namespace WP_Rocket\Engine\Common\Clock; + +class WPRClock implements ClockInterface { + + /** + * Retrieves the current time based on specified type. + * + * - The 'mysql' type will return the time in the format for MySQL DATETIME field. + * - The 'timestamp' or 'U' types will return the current timestamp or a sum of timestamp + * and timezone offset, depending on `$gmt`. + * - Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d'). + * + * If `$gmt` is a truthy value then both types will use GMT time, otherwise the + * output is adjusted with the GMT offset for the site. + * + * @since 1.0.0 + * @since 5.3.0 Now returns an integer if `$type` is 'U'. Previously a string was returned. + * + * @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp', 'U', + * or PHP date format string (e.g. 'Y-m-d'). + * @param int|bool $gmt Optional. Whether to use GMT timezone. Default false. + * + * @return int|string Integer if `$type` is 'timestamp' or 'U', string otherwise. + */ + public function current_time( string $type, $gmt = 0 ) { + $current_time = current_time( $type, $gmt ); + $output = apply_filters( 'rocket_current_time', $current_time ); + if ( ( is_string( $current_time ) && strtotime( $current_time ) ) || ( is_int( $current_time ) && $current_time >= 0 ) ) { + return $output; + } + return $current_time; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Context/AbstractContext.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Context/AbstractContext.php new file mode 100644 index 000000000..36071808f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Context/AbstractContext.php @@ -0,0 +1,76 @@ +<?php + +namespace WP_Rocket\Engine\Common\Context; + +use WP_Rocket\Admin\Options_Data; + +abstract class AbstractContext implements ContextInterface { + + + /** + * WPR options. + * + * @var Options_Data + */ + protected $options; + + /** + * Instantiate the class. + * + * @param Options_Data $options WPR options. + */ + public function __construct( Options_Data $options ) { + $this->options = $options; + } + + /** + * Run common checks. + * + * @param array $args Arguments to configure the checks. + * + * @return bool + */ + public function run_common_checks( array $args = [] ): bool { + if ( key_exists( 'do_not_optimize', $args ) && (bool) rocket_get_constant( 'DONOTROCKETOPTIMIZE' ) !== (bool) $args['do_not_optimize'] ) { + return false; + } + + if ( key_exists( 'bypass', $args ) && rocket_bypass() !== (bool) $args['bypass'] ) { + return false; + } + + if ( key_exists( 'option', $args ) && is_string( $args['option'] ) && ! (bool) $this->options->get( $args['option'], 0 ) ) { + return false; + } + + if ( key_exists( 'password_protected', $args ) && $this->is_password_protected() !== (bool) $args['password_protected'] ) { + return false; + } + + if ( key_exists( 'post_excluded', $args ) && is_string( $args['post_excluded'] ) && is_rocket_post_excluded_option( $args['post_excluded'] ) ) { + return false; + } + + // Bailout if user is logged in. + if ( key_exists( 'logged_in', $args ) && is_user_logged_in() !== (bool) $args['logged_in'] ) { + return false; + } + + return true; + } + + /** + * Checks if on a single post and if it is password protected + * + * @since 3.11 + * + * @return bool + */ + private function is_password_protected(): bool { + if ( ! is_singular() ) { + return false; + } + + return post_password_required(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Context/ContextInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Context/ContextInterface.php new file mode 100644 index 000000000..efd42ae9a --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Context/ContextInterface.php @@ -0,0 +1,14 @@ +<?php + +namespace WP_Rocket\Engine\Common\Context; + +interface ContextInterface { + + /** + * Determine if the action is allowed. + * + * @param array $data Data to pass to the context. + * @return bool + */ + public function is_allowed( array $data = [] ): bool; +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Database/Queries/AbstractQuery.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Database/Queries/AbstractQuery.php new file mode 100644 index 000000000..f74d93b1d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Database/Queries/AbstractQuery.php @@ -0,0 +1,650 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Common\Database\Queries; + +use WP_Rocket\Dependencies\Database\Query; + +class AbstractQuery extends Query { + /** + * Table status. + * + * @var boolean + */ + public static $table_exists = false; + + /** + * Get row for specific url. + * + * @param string $url Page Url. + * @param bool $is_mobile if the request is for mobile page. + * + * @return false|mixed + */ + public function get_row( string $url, bool $is_mobile = false ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + $query = $this->query( + [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + ] + ); + + if ( empty( $query[0] ) ) { + return false; + } + + return $query[0]; + } + + /** + * Get single row by ID. + * + * @param int $row_id DB Row ID. + * + * @return array|false + */ + public function get_row_by_id( int $row_id ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + $query = $this->query( + [ + 'id' => $row_id, + ] + ); + + if ( empty( $query ) ) { + return false; + } + + return $query; + } + + /** + * Get all rows with the same url (desktop and mobile versions). + * + * @param string $url Page url. + * + * @return array|false + */ + public function get_rows_by_url( string $url ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + $query = $this->query( + [ + 'url' => untrailingslashit( $url ), + ] + ); + + if ( empty( $query ) ) { + return false; + } + + return $query; + } + + /** + * Fetch on submit jobs. + * + * @param int $count Number of jobs to fetch. + * @return array|int + */ + public function get_on_submit_jobs( int $count = 100 ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return []; + } + + $in_progress_count = $this->query( + [ + 'count' => true, + 'status' => [ 'in-progress' ], + ] + ); + $pending_count = $this->query( + [ + 'count' => true, + 'status' => [ 'pending' ], + ] + ); + + $processing_count = $in_progress_count + $pending_count; + + if ( 0 !== $count && $processing_count >= $count ) { + return []; + } + + $query_params = [ + 'status' => 'to-submit', + 'orderby' => 'modified', + 'order' => 'asc', + ]; + + if ( 0 !== $count ) { + $query_params['number'] = ( $count - $processing_count ); + } + + return $this->query( $query_params ); + } + + /** + * Create new DB row for specific url. + * + * @param string $url Current page url. + * @param string $job_id API job_id. + * @param string $queue_name API Queue name. + * @param bool $is_mobile if the request is for mobile page. + * + * @return bool + */ + public function create_new_job( string $url, string $job_id = '', string $queue_name = '', bool $is_mobile = false ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + $item = [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + 'job_id' => $job_id, + 'queue_name' => $queue_name, + 'status' => 'to-submit', + 'retries' => 0, + 'last_accessed' => current_time( 'mysql', true ), + ]; + + $result = $this->add_item( $item ); + + /** + * Fires after a new job has been added. + * + * @param mixed $is_success New job status: ID of inserted row if successfully added; false otherwise. + * @param string $timestamp Current timestamp. + */ + rocket_do_action_and_deprecated( + 'rocket_last_saas_job_added_time', + [ $result, current_time( 'mysql', true ) ], + '3.16', + 'rocket_last_rucss_job_added_time' + ); + + return $result; + } + + /** + * Get pending jobs. + * + * @param int $count Number of rows. + * + * @return array + */ + public function get_pending_jobs( int $count = 100 ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return []; + } + + $inprogress_count = $this->query( + [ + 'count' => true, + 'status' => 'in-progress', + ] + ); + + if ( $inprogress_count >= $count ) { + return []; + } + + return $this->query( + [ + 'number' => ( $count - $inprogress_count ), + 'status' => 'pending', + 'job_id__not_in' => [ + 'not_in' => '', + ], + 'orderby' => 'modified', + 'order' => 'asc', + ] + ); + } + + /** + * Increment retries number and change status back to pending. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $error_code error code. + * @param string $error_message error message. + * + * @return bool|int + */ + public function increment_retries( string $url, bool $is_mobile, string $error_code, string $error_message ) { + if ( ! $this->is_allowed() ) { + return false; + } + + $db = $this->get_db(); + + $prefixed_table_name = $db->prefix . $this->table_name; + + $old = $this->get_row( $url, $is_mobile ); + + $retries = 0; + $previous_message = ''; + + if ( $old ) { + $retries = $old->retries; + $previous_message = $old->error_message; + } + + $data = [ + 'retries' => $retries + 1, + 'status' => 'pending', + 'error_message' => $previous_message . ' - ' . current_time( 'mysql', true ) . " {$error_code}: {$error_message}", + ]; + + $where = [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + ]; + + return $db->update( $prefixed_table_name, $data, $where ); + } + + /** + * Update Job ID. + * + * @param int $id DB row ID. + * @param int $new_job_id new job id. + * + * @return bool + */ + public function update_job_id( $id, $new_job_id ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + $update_data['job_id'] = $new_job_id; + return $this->update_item( $id, $update_data ); + } + + /** + * Change the status to be in-progress. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @return bool|int + */ + public function make_status_inprogress( string $url, bool $is_mobile ) { + if ( ! $this->is_allowed() ) { + return false; + } + + $db = $this->get_db(); + + $prefixed_table_name = $db->prefix . $this->table_name; + $where = [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + ]; + + return $db->update( $prefixed_table_name, [ 'status' => 'in-progress' ], $where ); + } + + /** + * Reset the job and add new job_id pending. + * + * @param int $id DB row ID. + * @param string $job_id API job_id. + * + * @return bool + */ + public function reset_job( int $id, string $job_id = '' ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + return $this->update_item( + $id, + [ + 'job_id' => $job_id, + 'status' => 'to-submit', + 'error_code' => '', + 'error_message' => '', + 'retries' => 0, + 'modified' => current_time( 'mysql', true ), + 'submitted_at' => current_time( 'mysql', true ), + ] + ); + } + + /** + * Change the status to be failed. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $error_code error code. + * @param string $error_message error message. + * + * @return bool|int + */ + public function make_status_failed( string $url, bool $is_mobile, string $error_code, string $error_message ) { + if ( ! $this->is_allowed() ) { + return false; + } + + $db = $this->get_db(); + + $prefixed_table_name = $db->prefix . $this->table_name; + + $old = $this->get_row( $url, $is_mobile ); + + $previous_message = $old ? $old->error_message : ''; + + $data = [ + 'status' => 'failed', + 'error_code' => $error_code, + 'error_message' => $previous_message . ' - ' . current_time( 'mysql', true ) . " {$error_code}: {$error_message}", + ]; + + $where = [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + ]; + + return $db->update( $prefixed_table_name, $data, $where ); + } + + /** + * Update row last_accessed date to current date. + * + * @param int $id Used CSS id. + * + * @return bool + */ + public function update_last_accessed( int $id ): bool { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + return (bool) $this->update_item( + $id, + [ + 'last_accessed' => current_time( 'mysql', true ), + ] + ); + } + + /** + * Delete DB row by url. + * + * @param string $url Page url to be deleted. + * + * @return bool + */ + public function delete_by_url( string $url ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + $items = $this->get_rows_by_url( $url ); + + if ( ! $items ) { + return false; + } + + $deleted = true; + foreach ( $items as $item ) { + $deleted = $deleted && $this->delete_item( $item->id ); + } + + return $deleted; + } + + /** + * Get the count of not completed rows. + * + * @return int + */ + public function get_not_completed_count() { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return 0; + } + + return $this->query( + [ + 'count' => true, + 'status__in' => [ 'pending', 'in-progress' ], + ] + ); + } + + /** + * Get the count of completed rows. + * + * @return int + */ + public function get_completed_count() { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return 0; + } + + return $this->query( + [ + 'count' => true, + 'status' => 'completed', + ] + ); + } + + /** + * Get all failed rows. + * + * @param float $delay delay before the urls are deleted. + * @param string $unit unit from the delay. + * @return array|false + */ + public function get_failed_rows( float $delay = 3, string $unit = 'days' ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + $query = $this->query( + [ + 'status' => 'failed', + 'date_query' => [ + [ + 'column' => 'modified', + 'before' => "$delay $unit ago", + 'inclusive' => true, + ], + ], + ], + false + ); + + if ( empty( $query ) ) { + return false; + } + + return $query; + } + + /** + * Revert status to pending. + * + * @param integer $id Used CSS id. + * @return boolean + */ + public function revert_to_pending( int $id ): bool { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + return (bool) $this->update_item( + $id, + [ + 'error_code' => '', + 'error_message' => '', + 'retries' => 0, + 'status' => 'pending', + 'modified' => current_time( 'mysql', true ), + ] + ); + } + + /** + * Returns the current status of the table; true if it exists, false otherwise. + * + * @return boolean + */ + protected function table_exists(): bool { + if ( self::$table_exists ) { + return true; + } + + // Get the database interface. + $db = $this->get_db(); + + // Bail if no database interface is available. + if ( empty( $db ) ) { + return false; + } + + // Query statement. + $query = 'SHOW TABLES LIKE %s'; + $like = $db->esc_like( $db->{$this->table_name} ); + $prepared = $db->prepare( $query, $like ); + $result = $db->get_var( $prepared ); + + // Does the table exist? + $exists = $this->is_success( $result ); + + if ( $exists ) { + self::$table_exists = $exists; + } + + return $exists; + } + + /** + * Change the status to be pending. + * + * @param string $url DB row url. + * @param string $job_id API job_id. + * @param string $queue_name API Queue name. + * @param bool $is_mobile if the request is for mobile page. + * @return bool|int + */ + public function make_status_pending( string $url, string $job_id = '', string $queue_name = '', bool $is_mobile = false ) { + if ( ! $this->is_allowed() ) { + return false; + } + + $db = $this->get_db(); + + $prefixed_table_name = $db->prefix . $this->table_name; + $data = [ + 'job_id' => $job_id, + 'queue_name' => $queue_name, + 'status' => 'pending', + 'is_mobile' => $is_mobile, + 'submitted_at' => current_time( 'mysql', true ), + ]; + + $where = [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + ]; + + return $db->update( $prefixed_table_name, $data, $where ); + } + + /** + * Update the error message. + * + * @param string $url DB row url. + * @param boolean $is_mobile Is mobile from DB row. + * @param int $code Response code. + * @param string $message Response message. + * @param string $previous_message Previous saved message. + * + * @return bool|int + */ + public function update_message( string $url, bool $is_mobile, int $code, string $message, string $previous_message = '' ) { + if ( ! $this->is_allowed() ) { + return false; + } + + $db = $this->get_db(); + + $prefixed_table_name = $db->prefix . $this->table_name; + + $data = [ 'error_message' => $previous_message . ' - ' . current_time( 'mysql', true ) . " {$code}: {$message}" ]; + + $where = [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + ]; + + return $db->update( $prefixed_table_name, $data, $where ); + } + + /** + * Updates the next_retry_time field + * + * @param string $url DB row url. + * @param boolean $is_mobile Is mobile from DB row. + * @param string|int $next_retry_time timestamp or mysql format date. + * + * @return bool|int either it is saved or not. + */ + public function update_next_retry_time( string $url, bool $is_mobile, $next_retry_time ) { + if ( ! $this->is_allowed() ) { + return false; + } + + $db = $this->get_db(); + + $prefixed_table_name = $db->prefix . $this->table_name; + + if ( is_string( $next_retry_time ) && strtotime( $next_retry_time ) ) { + // If $next_retry_time is a valid date string, convert it to a timestamp. + $next_retry_time = strtotime( $next_retry_time ); + } elseif ( ! is_numeric( $next_retry_time ) ) { + // If it's not numeric and not a valid date string, return false. + return false; + } + + $data = [ 'next_retry_time' => gmdate( 'Y-m-d H:i:s', $next_retry_time ) ]; + + $where = [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + ]; + + return $db->update( $prefixed_table_name, $data, $where ); + } + + /** + * Check if db action can be processed. + * + * @return boolean + */ + private function is_allowed() { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + // Bail if no database interface is available. + if ( empty( $this->get_db() ) ) { + return false; + } + + return true; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Database/TableInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Database/TableInterface.php new file mode 100644 index 000000000..17715f8f8 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Database/TableInterface.php @@ -0,0 +1,40 @@ +<?php + +namespace WP_Rocket\Engine\Common\Database; + +interface TableInterface { + /** + * Delete all rows which were not accessed in the last month. + * + * @return bool|int + */ + public function delete_old_rows(); + + /** + * Get all rows which were not accessed in the last month. + * + * @return array + */ + public function get_old_rows(): array; + + /** + * Remove all completed rows. + * + * @return bool|int + */ + public function remove_all_completed_rows(); + + /** + * Returns name from table. + * + * @return string + */ + public function get_name(); + + /** + * Trigger recreation of cache table if not exist. + * + * @return void + */ + public function maybe_trigger_recreate_table(); +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Database/Tables/AbstractTable.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Database/Tables/AbstractTable.php new file mode 100644 index 000000000..f8fd6a688 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Database/Tables/AbstractTable.php @@ -0,0 +1,145 @@ +<?php + +namespace WP_Rocket\Engine\Common\Database\Tables; + +use WP_Rocket\Dependencies\Database\Table; +use WP_Rocket\Engine\Common\Database\TableInterface; + +class AbstractTable extends Table implements TableInterface { + + /** + * Table schema data. + * + * @var string + */ + protected $schema_data; + + /** + * Instantiate class. + */ + public function __construct() { + parent::__construct(); + add_action( 'admin_init', [ $this, 'maybe_trigger_recreate_table' ], 9 ); + add_action( 'init', [ $this, 'maybe_upgrade' ] ); + } + + /** + * Setup the database schema + * + * @return void + */ + protected function set_schema() { + if ( ! $this->schema_data ) { + return; + } + + $this->schema = $this->schema_data; + } + + /** + * Delete all rows which were not accessed in the last month. + * + * @return bool|int + */ + public function delete_old_rows() { + if ( ! $this->exists() ) { + return false; + } + // Get the database interface. + $db = $this->get_db(); + + // Bail if no database interface is available. + if ( empty( $db ) ) { + return false; + } + + /** + * Filters the old SaaS data deletion interval + * + * @param int $delete_interval Old Saas data deletion interval in months + */ + $delete_interval = (int) rocket_apply_filter_and_deprecated( + 'rocket_saas_delete_interval', + [ 1 ], + '3.16', + 'rocket_rucss_delete_interval' + ); + + if ( $delete_interval <= 0 ) { + return false; + } + + $prefixed_table_name = $this->apply_prefix( $this->table_name ); + $query = "DELETE FROM `$prefixed_table_name` WHERE `last_accessed` <= date_sub(now(), interval $delete_interval month)"; + $rows_affected = $db->query( $query ); + + return $rows_affected; + } + + /** + * Get all rows which were not accessed in the last month. + * + * @return array + */ + public function get_old_rows(): array { + if ( ! $this->exists() ) { + return false; + } + // Get the database interface. + $db = $this->get_db(); + + // Bail if no database interface is available. + if ( empty( $db ) ) { + return false; + } + + $prefixed_table_name = $this->apply_prefix( $this->table_name ); + $query = "SELECT * FROM `$prefixed_table_name` WHERE `last_accessed` <= date_sub(now(), interval 1 month)"; + $rows_affected = $db->get_results( $query ); + + return $rows_affected; + } + + /** + * Remove all completed rows. + * + * @return bool|int + */ + public function remove_all_completed_rows() { + if ( ! $this->exists() ) { + return false; + } + // Get the database interface. + $db = $this->get_db(); + + // Bail if no database interface is available. + if ( empty( $db ) ) { + return false; + } + + $prefixed_table_name = $this->apply_prefix( $this->table_name ); + return $db->query( "DELETE FROM `$prefixed_table_name` WHERE status IN ( 'failed', 'completed' )" ); + } + + /** + * Returns name from table. + * + * @return string + */ + public function get_name() { + return $this->apply_prefix( $this->table_name ); + } + + /** + * Trigger recreation of cache table if not exist. + * + * @return void + */ + public function maybe_trigger_recreate_table() { + if ( $this->exists() ) { + return; + } + + delete_option( $this->db_version_key ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/ExtractCSS/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/ExtractCSS/ServiceProvider.php new file mode 100644 index 000000000..0148a2f9c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/ExtractCSS/ServiceProvider.php @@ -0,0 +1,49 @@ +<?php + +namespace WP_Rocket\Engine\Common\ExtractCSS; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Common\Cache\FilesystemCache; + +/** + * Service provider. + */ +class ServiceProvider extends AbstractServiceProvider { + /** + * Array of services provided by this service provider + * + * @var array + */ + protected $provides = [ + 'lazyload_css_cache', + 'common_extractcss_subscriber', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container + * + * @return void + */ + public function register(): void { + /** + * Background CSS cache folder. + * + * @param string $root Background CSS cache folder. + */ + $root = apply_filters( 'rocket_lazyload_css_cache_root', 'background-css' ); + $this->getContainer()->add( 'lazyload_css_cache', FilesystemCache::class ) + ->addArgument( $root ); + $this->getContainer()->addShared( 'common_extractcss_subscriber', Subscriber::class ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/ExtractCSS/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/ExtractCSS/Subscriber.php new file mode 100644 index 000000000..85aa9af5b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/ExtractCSS/Subscriber.php @@ -0,0 +1,168 @@ +<?php +namespace WP_Rocket\Engine\Common\ExtractCSS; + +use WP_Rocket\Engine\Optimization\RegexTrait; +use WP_Rocket\Event_Management\Subscriber_Interface; +use WP_Rocket\Logger\LoggerAware; +use WP_Rocket\Logger\LoggerAwareInterface; + +class Subscriber implements Subscriber_Interface, LoggerAwareInterface { + use RegexTrait; + use LoggerAware; + + /** + * Returns an array of events that this subscriber wants to listen to. + * + * The array key is the event name. The value can be: + * + * * The method name + * * An array with the method name and priority + * * An array with the method name, priority and number of accepted arguments + * + * For instance: + * + * * array('hook_name' => 'method_name') + * * array('hook_name' => array('method_name', $priority)) + * * array('hook_name' => array('method_name', $priority, $accepted_args)) + * * array('hook_name' => array(array('method_name_1', $priority_1, $accepted_args_1)), array('method_name_2', $priority_2, $accepted_args_2))) + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'rocket_generate_lazyloaded_css' => [ + [ 'extract_css_files_from_html', 11 ], + [ 'extract_inline_css_from_html', 14 ], + ], + ]; + } + + /** + * Extract CSS files from the HTML. + * + * @param array $data Data sent. + * @return array + */ + public function extract_css_files_from_html( array $data ): array { + + if ( ! key_exists( 'html', $data ) ) { + $this->logger::notice( + 'Extract CSS files bailed out', + [ + 'type' => 'extract_css', + 'data' => $data, + ] + ); + return $data; + } + + if ( ! key_exists( 'css_files', $data ) ) { + $data['css_files'] = []; + } + + $css_links = []; + + $html = $this->hide_comments( $data['html'] ); + + $link_styles = $this->find( + '<link\s+([^>]+[\s"\'])?href\s*=\s*[\'"]\s*?(?<url>[^\'"]+(?:\?[^\'"]*)?)\s*?[\'"]([^>]+)?\/?>', + $html, + 'Uis' + ); + + foreach ( $link_styles as $style ) { + if ( + ( + ! (bool) preg_match( '/rel=[\'"]?stylesheet[\'"]?/is', $style[0] ) + && + ! ( (bool) preg_match( '/rel=[\'"]?preload[\'"]?/is', $style[0] ) && (bool) preg_match( '/as=[\'"]?style[\'"]?/is', $style[0] ) ) + ) + || + strstr( $style['url'], '//fonts.googleapis.com/css' ) + ) { + $this->logger::notice( + "Skipped URL: {$style['url']}", + [ + 'type' => 'extract_css', + 'data' => $style[0], + ] + ); + continue; + } + + $css_links [] = $style['url']; + $this->logger::notice( + "Extracted URL: {$style['url']}", + [ + 'type' => 'extract_css', + 'data' => $style[0], + ] + ); + } + + $data['css_files'] = array_merge( $data['css_files'], $css_links ); + + return $data; + } + + /** + * Extract inline CSS from the HTML. + * + * @param array $data Data sent. + * @return array + */ + public function extract_inline_css_from_html( array $data ): array { + if ( ! key_exists( 'html', $data ) ) { + $this->logger::notice( + 'Extract CSS inline bailed out', + [ + 'type' => 'extract_css', + 'data' => $data, + ] + ); + return $data; + } + + if ( ! key_exists( 'css_inline', $data ) ) { + $data['css_inline'] = []; + } + + $css_links = []; + + $html = $this->hide_comments( $data['html'] ); + + $inline_styles = $this->find( + '<style(?<atts>.*)>(?<content>.*)<\/style\s*>', + $html + ); + + foreach ( $inline_styles as $style ) { + + $content = trim( $style['content'] ); + + if ( empty( $content ) ) { + $this->logger::notice( + "Skipped Content: {$style['content']}", + [ + 'type' => 'extract_css', + 'data' => $style[0], + ] + ); + continue; + } + + $css_links [] = $content; + $this->logger::notice( + "Extracted Content: $content", + [ + 'type' => 'extract_css', + 'data' => $style[0], + ] + ); + } + + $data['css_inline'] = array_merge( $data['css_inline'], $css_links ); + + return $data; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/APIHandler/APIClient.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/APIHandler/APIClient.php new file mode 100644 index 000000000..47181d6e4 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/APIHandler/APIClient.php @@ -0,0 +1,144 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Common\JobManager\APIHandler; + +use WP_Rocket\Logger\LoggerAware; +use WP_Rocket\Logger\LoggerAwareInterface; + +class APIClient extends AbstractAPIClient implements LoggerAwareInterface { + use LoggerAware; + + /** + * SaaS main API path. + * + * @var string + */ + protected $request_path = 'rucss-job'; + + /** + * Array of Factories. + * + * @var array + */ + protected $factories; + + /** + * Calls Central SaaS API. + * + * @param string $url Page url. + * @param array $options Array with options sent to Saas API. + * + * @return array + */ + public function add_to_queue( string $url, array $options ): array { + $url = add_query_arg( + [ + 'nowprocket' => 1, + 'no_optimize' => 1, + ], + user_trailingslashit( $url ) + ); + + /** + * Filter the url that is sent to Saas when RUCSS and LCP/ATF is on. + * + * @param string $url contains the URL that is sent to Saas. + */ + $url = apply_filters( 'rocket_saas_api_queued_url', $url ); + + $args = [ + 'body' => [ + 'url' => $url, + 'config' => $options, + ], + 'timeout' => 5, + ]; + + $this->logger::debug( + 'Add to queue request arguments', + $args + ); + + $sent = $this->handle_post( $args ); + + if ( ! $sent ) { + $output = [ + 'code' => $this->response_code, + 'message' => $this->error_message, + ]; + + $this->logger::error( + 'Add to queue request failure', + $output + ); + return $output; + } + + $default = [ + 'code' => 400, + 'message' => 'No message. Defaulted in add_to_queue', + 'contents' => [ + 'jobId' => '0', + 'queueName' => '', + ], + ]; + $result = json_decode( $this->response_body, true ); + + $this->logger::debug( + $url . ' - Add to queue response body', + $result + ); + + if ( key_exists( 'code', $result ) && 401 === $result['code'] ) { + update_option( 'wp_rocket_no_licence', true ); + update_rocket_option( 'remove_unused_css', 0 ); + } + + return wp_parse_args( (array) $result, $default ); + } + + /** + * Get job status from RUCSS queue. + * + * @param string $job_id Job ID. + * @param string $queue_name Queue Name. + * @param bool $is_home Is home or not. + * + * @return array + */ + public function get_queue_job_status( $job_id, $queue_name, $is_home = false ) { + $args = [ + 'body' => [ + 'id' => $job_id, + 'force_queue' => $queue_name, + 'is_home' => $is_home, + ], + 'timeout' => 5, + ]; + + if ( ! $this->handle_get( $args ) ) { + return [ + 'code' => $this->response_code, + 'message' => $this->error_message, + ]; + } + + $default = [ + 'code' => 400, + 'status' => 'failed', + 'message' => 'No message. Defaulted in get_queue_job_status', + 'contents' => [ + 'success' => false, + 'shakedCSS' => '', + 'above_the_fold_result' => [ + 'lcp' => [], + 'images_above_fold' => [], + ], + ], + ]; + + $result = json_decode( $this->response_body, true ); + return (array) wp_parse_args( ( $result && $result['returnvalue'] ) ? (array) $result['returnvalue'] : [], $default ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/APIHandler/AbstractAPIClient.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/APIHandler/AbstractAPIClient.php new file mode 100644 index 000000000..1b8543f2f --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/APIHandler/AbstractAPIClient.php @@ -0,0 +1,144 @@ +<?php +declare( strict_types=1 ); + +namespace WP_Rocket\Engine\Common\JobManager\APIHandler; + +use WP_Error; +use WP_Rocket\Admin\Options_Data; + +abstract class AbstractAPIClient { + /** + * API URL. + */ + const API_URL = 'https://saas.wp-rocket.me/'; + + /** + * Part of request Url after the main API_URL. + * + * @var string + */ + protected $request_path; + + /** + * Response Code. + * + * @var int + */ + protected $response_code = 200; + + /** + * Error message. + * + * @var string + */ + protected $error_message = ''; + + /** + * Response Body. + * + * @var string + */ + protected $response_body; + + /** + * Plugin options instance. + * + * @var Options_Data + */ + protected $options; + + /** + * Instantiate the class. + * + * @param Options_Data $options Options instance. + */ + public function __construct( Options_Data $options ) { + $this->options = $options; + } + + /** + * Handle the request. + * + * @param array $args Passed arguments. + * @param string $type GET or POST. + * + * @return bool + */ + private function handle_request( array $args, string $type = 'post' ) { + $api_url = rocket_get_constant( 'WP_ROCKET_SAAS_API_URL', false ) + ? rocket_get_constant( 'WP_ROCKET_SAAS_API_URL', false ) + : self::API_URL; + + if ( empty( $args['body'] ) ) { + $args['body'] = []; + } + + $args['body']['credentials'] = [ + 'wpr_email' => $this->options->get( 'consumer_email', '' ), + 'wpr_key' => $this->options->get( 'consumer_key', '' ), + ]; + + $args['method'] = strtoupper( $type ); + $response = wp_remote_request( + $api_url . $this->request_path, + $args + ); + + return $this->check_response( $response ); + } + + /** + * Handle remote POST. + * + * @param array $args Array with options sent to Saas API. + * + * @return bool WP Remote request status. + */ + protected function handle_post( array $args ): bool { + return $this->handle_request( $args ); + } + + /** + * Handle remote GET. + * + * @param array $args Array with options sent to Saas API. + * + * @return bool WP Remote request status. + */ + protected function handle_get( array $args ): bool { + return $this->handle_request( $args, 'get' ); + } + + /** + * Handle SaaS request error. + * + * @param array|WP_Error $response WP Remote request. + * + * @return bool + */ + private function check_response( $response ): bool { + $this->response_code = is_array( $response ) + ? wp_remote_retrieve_response_code( $response ) + : $response->get_error_code(); + + if ( 200 !== $this->response_code ) { + $previous_errors = (int) get_transient( 'wp_rocket_rucss_errors_count' ); + set_transient( 'wp_rocket_rucss_errors_count', $previous_errors + 1, 5 * MINUTE_IN_SECONDS ); + + if ( empty( $response ) ) { + $this->error_message = 'API Client Error'; + return false; + } + + $this->error_message = is_array( $response ) + ? wp_remote_retrieve_response_message( $response ) + : $response->get_error_message(); + + return false; + } + delete_transient( 'wp_rocket_rucss_errors_count' ); + $this->response_body = wp_remote_retrieve_body( $response ); + + return true; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/AbstractFactory/SaasFactory.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/AbstractFactory/SaasFactory.php new file mode 100644 index 000000000..63bae6fab --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/AbstractFactory/SaasFactory.php @@ -0,0 +1,23 @@ +<?php +declare( strict_types=1 ); + +namespace WP_Rocket\Engine\Common\JobManager\AbstractFactory; + +use WP_Rocket\Engine\Common\JobManager\Managers\ManagerInterface; +use WP_Rocket\Engine\Common\Database\TableInterface; + +interface SaasFactory { + /** + * SaaS job manager. + * + * @return ManagerInterface + */ + public function manager(): ManagerInterface; + + /** + * Job table. + * + * @return TableInterface + */ + public function table(): TableInterface; +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Cron/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Cron/Subscriber.php new file mode 100644 index 000000000..8b2196924 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Cron/Subscriber.php @@ -0,0 +1,358 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Common\JobManager\Cron; + +use WP_Rocket\Event_Management\Subscriber_Interface; +use WP_Rocket\Engine\Common\Queue\RUCSSQueueRunner; +use WP_Rocket\Engine\Common\JobManager\JobProcessor; + +class Subscriber implements Subscriber_Interface { + /** + * JobProcessor instance + * + * @var JobProcessor + */ + private $job_processor; + + /** + * Array of Factories. + * + * @var array + */ + private $factories; + + /** + * Instantiate the class + * + * @param JobProcessor $job_processor JobProcessor instance. + * @param array $factories Array of factories. + */ + public function __construct( + JobProcessor $job_processor, + array $factories + ) { + $this->job_processor = $job_processor; + $this->factories = $factories; + } + + /** + * Return an array of events that this subscriber listens to. + * + * @return array + */ + public static function get_subscribed_events(): array { + return [ + 'rocket_saas_pending_jobs' => 'process_pending_jobs', + 'rocket_saas_on_submit_jobs' => 'process_on_submit_jobs', + 'rocket_saas_job_check_status' => [ 'check_job_status', 10, 3 ], + 'rocket_saas_clean_rows_time_event' => 'cron_clean_rows', + 'cron_schedules' => 'add_interval', + 'rocket_deactivation' => 'on_deactivation', + 'rocket_remove_saas_failed_jobs' => 'cron_remove_failed_jobs', + 'init' => [ + [ 'schedule_clean_not_commonly_used_rows' ], + [ 'schedule_pending_jobs' ], + [ 'initialize_rucss_queue_runner' ], + [ 'schedule_removing_failed_jobs' ], + [ 'schedule_on_submit_jobs' ], + ], + 'wp_rocket_upgrade' => [ 'unschedule_rucss_cron', 13, 2 ], + ]; + } + + /** + * Schedules cron to clean not commonly used rows. + * + * @since 3.9 + * + * @return void + */ + public function schedule_clean_not_commonly_used_rows() { + if ( ! $this->job_processor->is_allowed() ) { + return; + } + + if ( wp_next_scheduled( 'rocket_saas_clean_rows_time_event' ) ) { + return; + } + + wp_schedule_event( time(), 'weekly', 'rocket_saas_clean_rows_time_event' ); + } + + /** + * Initialize the queue runner for our SaaS. + * + * @return void + */ + public function initialize_rucss_queue_runner() { + if ( ! $this->job_processor->is_allowed() ) { + return; + } + + RUCSSQueueRunner::instance()->init(); + } + + /** + * Process pending jobs with Cron iteration. + * + * @return void + */ + public function process_pending_jobs() { + $this->job_processor->process_pending_jobs(); + } + + /** + * Process on submit jobs with Cron iteration. + * + * @return void + */ + public function process_on_submit_jobs() { + $this->job_processor->process_on_submit_jobs(); + } + + /** + * Cron callback for deleting old rows in both table databases. + * + * @since 3.9 + * + * @return void + */ + public function cron_clean_rows() { + if ( ! $this->is_deletion_enabled() ) { + return; + } + + foreach ( $this->factories as $factory ) { + if ( $factory->manager()->is_allowed() ) { + $factory->table()->delete_old_rows(); + } + } + } + + /** + * Cron callback for removing failed jobs. + * + * @return void + */ + public function cron_remove_failed_jobs() { + $this->job_processor->clear_failed_urls(); + } + + /** + * Handle job status by DB url and is_mobile. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $optimization_type The type of optimization request to send. + * + * @return void + */ + public function check_job_status( string $url, bool $is_mobile, string $optimization_type ) { + $this->job_processor->check_job_status( $url, $is_mobile, $optimization_type ); + } + + /** + * Adds new interval for SaaS pending jobs cron + * + * @since 3.11.3 + * + * @param array[] $schedules An array of non-default cron schedule arrays. + * + * @return array + */ + public function add_interval( $schedules ) { + if ( ! $this->job_processor->is_allowed() ) { + return $schedules; + } + + /** + * Filters the cron interval. + * + * @since 3.11 + * + * @param int $interval Interval in seconds. + */ + $interval = rocket_apply_filter_and_deprecated( + 'rocket_saas_pending_jobs_cron_interval', + [ 1 * rocket_get_constant( 'MINUTE_IN_SECONDS', 60 ) ], + '3.16', + 'rocket_rucss_pending_jobs_cron_interval' + ); + + $schedules['rocket_saas_pending_jobs'] = [ + 'interval' => $interval, + 'display' => esc_html__( 'WP Rocket process pending jobs', 'rocket' ), + ]; + + $default_interval = 3 * rocket_get_constant( 'DAY_IN_SECONDS', 86400 ); + /** + * Filters the cron interval for clearing failed jobs. + * + * @param int $interval Interval in seconds. + */ + $interval = rocket_apply_filter_and_deprecated( + 'rocket_remove_saas_failed_jobs_cron_interval', + [ $default_interval ], + '3.16', + 'rocket_remove_rucss_failed_jobs_cron_interval' + ); + $interval = (bool) $interval ? $interval : $default_interval; + + $schedules['rocket_remove_saas_failed_jobs'] = [ + 'interval' => $interval, + 'display' => esc_html__( 'WP Rocket clear failed jobs', 'rocket' ), + ]; + + /** + * Filters the cron interval for processing on submit jobs. + * + * @param int $interval Interval in seconds. + */ + $interval = (int) rocket_apply_filter_and_deprecated( + 'rocket_remove_saas_on_submit_jobs_cron_interval', + [ 1 * rocket_get_constant( 'MINUTE_IN_SECONDS', 60 ) ], + '3.16', + 'rocket_remove_rucss_on_submit_jobs_cron_interval' + ); + + $schedules['rocket_saas_on_submit_jobs'] = [ + 'interval' => $interval, + 'display' => esc_html__( 'WP Rocket process on submit jobs', 'rocket' ), + ]; + + return $schedules; + } + + /** + * Schedule on submit jobs. + * + * @return void + */ + public function schedule_on_submit_jobs() { + if ( + ! $this->job_processor->is_allowed() + && + wp_next_scheduled( 'rocket_saas_on_submit_jobs' ) + ) { + wp_clear_scheduled_hook( 'rocket_saas_on_submit_jobs' ); + + return; + } + + if ( ! $this->job_processor->is_allowed() ) { + return; + } + + if ( wp_next_scheduled( 'rocket_saas_on_submit_jobs' ) ) { + return; + } + + wp_schedule_event( time(), 'rocket_saas_on_submit_jobs', 'rocket_saas_on_submit_jobs' ); + } + + /** + * Schedules cron to get SaaS pendings jobs. + * + * @since 3.11.3 + * + * @return void + */ + public function schedule_pending_jobs() { + if ( + ! $this->job_processor->is_allowed() + && + wp_next_scheduled( 'rocket_saas_pending_jobs' ) + ) { + wp_clear_scheduled_hook( 'rocket_saas_pending_jobs' ); + + return; + } + + if ( ! $this->job_processor->is_allowed() ) { + return; + } + + if ( wp_next_scheduled( 'rocket_saas_pending_jobs' ) ) { + return; + } + + wp_schedule_event( time(), 'rocket_saas_pending_jobs', 'rocket_saas_pending_jobs' ); + } + + /** + * Schedules cron to remove failed jobs. + * + * @return void + */ + public function schedule_removing_failed_jobs() { + if ( + ! $this->job_processor->is_allowed() + && + wp_next_scheduled( 'rocket_remove_saas_failed_jobs' ) + ) { + wp_clear_scheduled_hook( 'rocket_remove_saas_failed_jobs' ); + + return; + } + + if ( ! $this->job_processor->is_allowed() ) { + return; + } + + if ( wp_next_scheduled( 'rocket_remove_saas_failed_jobs' ) ) { + return; + } + + wp_schedule_event( time(), 'rocket_remove_saas_failed_jobs', 'rocket_remove_saas_failed_jobs' ); + } + + /** + * Clear schedule of SaaS CRONs on deactivation. + * + * @return void + */ + public function on_deactivation() { + wp_clear_scheduled_hook( 'action_scheduler_run_queue_rucss', [ 'WP Cron' ] ); + } + + /** + * Checks if the SaaS deletion is enabled. + * + * @return bool + */ + protected function is_deletion_enabled(): bool { + /** + * Filters the enable SaaS job deletion value + * + * @param bool $delete_saas_jobs True to enable deletion, false otherwise. + */ + return (bool) rocket_apply_filter_and_deprecated( + 'rocket_saas_deletion_enabled', + [ true ], + '3.16', + 'rocket_rucss_deletion_enabled' + ); + } + + /** + * Unschedule old rucss crons. + * + * @since 3.16 + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function unschedule_rucss_cron( $new_version, $old_version ) { + if ( version_compare( $old_version, '3.16', '>=' ) ) { + return; + } + + wp_clear_scheduled_hook( 'rocket_rucss_on_submit_jobs' ); + wp_clear_scheduled_hook( 'rocket_rucss_pending_jobs' ); + wp_clear_scheduled_hook( 'rocket_remove_rucss_failed_jobs' ); + wp_clear_scheduled_hook( 'rocket_rucss_clean_rows_time_event' ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/JobProcessor.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/JobProcessor.php new file mode 100644 index 000000000..2694c9fe5 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/JobProcessor.php @@ -0,0 +1,652 @@ +<?php + +namespace WP_Rocket\Engine\Common\JobManager; + +use WP_Rocket\Logger\LoggerAware; +use WP_Rocket\Logger\LoggerAwareInterface; +use WP_Rocket\Engine\Common\Queue\QueueInterface; +use WP_Rocket\Engine\Common\JobManager\Strategy\Factory\StrategyFactory; +use WP_Rocket\Engine\Common\JobManager\APIHandler\APIClient; +use WP_Rocket\Engine\Common\Clock\WPRClock; +use WP_Rocket\Engine\Common\Utils; + +class JobProcessor implements LoggerAwareInterface { + use LoggerAware; + + /** + * Array of Factories. + * + * @var array + */ + private $factories; + + /** + * Queue instance. + * + * @var QueueInterface + */ + private $queue; + + /** + * Retry Strategy Factory + * + * @var StrategyFactory + */ + protected $strategy_factory; + + /** + * APIClient instance + * + * @var APIClient + */ + private $api; + + /** + * Clock instance. + * + * @var WPRClock + */ + protected $wpr_clock; + + /** + * Instantiate the class. + * + * @param array $factories Array of factories. + * @param QueueInterface $queue Queue instance. + * @param StrategyFactory $strategy_factory Strategy Factory. + * @param APIClient $api APIClient instance. + * @param WPRClock $clock Clock object instance. + */ + public function __construct( + array $factories, + QueueInterface $queue, + StrategyFactory $strategy_factory, + APIClient $api, + WPRClock $clock + ) { + $this->factories = $factories; + $this->queue = $queue; + $this->strategy_factory = $strategy_factory; + $this->api = $api; + $this->wpr_clock = $clock; + } + + /** + * Determine if action is allowed. + * + * @return boolean + */ + public function is_allowed(): bool { + if ( ! $this->factories ) { + return false; + } + + $is_allowed = []; + + foreach ( $this->factories as $factory ) { + $is_allowed[] = $factory->manager()->is_allowed(); + } + + return (bool) array_sum( $is_allowed ); + } + + /** + * Process pending jobs inside cron iteration. + * + * @return void + */ + public function process_pending_jobs() { + /** + * Fires at the start of the process pending jobs. + * + * @param string $current_time Current time. + */ + rocket_do_action_and_deprecated( + 'rocket_saas_process_pending_jobs_start', + [ $this->wpr_clock->current_time( 'mysql', true ) ], + '3.16', + 'rocket_rucss_process_pending_jobs_start' + ); + $this->logger::debug( 'RUCSS: Start processing pending jobs inside cron.' ); + + if ( ! $this->is_allowed() ) { + $this->logger::debug( 'Stop processing cron iteration for pending jobs.' ); + + return; + } + + $this->logger::debug( 'Start processing pending jobs inside cron.' ); + + // Get some items from the DB with status=pending & job_id isn't empty. + + /** + * Filters the pending jobs count. + * + * @since 3.11 + * + * @param int $rows Number of rows to grab with each CRON iteration. + */ + $rows = rocket_apply_filter_and_deprecated( + 'rocket_saas_pending_jobs_cron_rows_count', + [ 100 ], + '3.16', + 'rocket_rucss_pending_jobs_cron_rows_count' + ); + + $pending_jobs = $this->get_jobs( $rows, 'pending' ); + + if ( ! $pending_jobs ) { + return; + } + + foreach ( $pending_jobs as $row ) { + $current_time = $this->wpr_clock->current_time( 'timestamp', true ); + if ( $row->next_retry_time < $current_time ) { + $optimization_type = $this->get_optimization_type( $row ); + // Change status to in-progress. + $this->make_status_inprogress( $row->url, $row->is_mobile, $optimization_type ); + $this->queue->add_job_status_check_async( $row->url, $row->is_mobile, $optimization_type ); + } + } + + /** + * Fires at the end of the process pending jobs. + * + * @param string $current_time Current time. + */ + rocket_do_action_and_deprecated( + 'rocket_saas_process_pending_jobs_end', + [ $this->wpr_clock->current_time( 'mysql', true ) ], + '3.16', + 'rocket_rucss_process_pending_jobs_end' + ); + } + + /** + * Check job status by DB row ID. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $optimization_type The type of optimization request to send. + * + * @return void + */ + public function check_job_status( string $url, bool $is_mobile, string $optimization_type ) { + + $row_details = $this->get_single_job( $url, $is_mobile, $optimization_type ); + if ( ! $row_details ) { + $this->logger::debug( 'Url - ' . $url . ' not found for is_mobile - ' . (int) $is_mobile ); + // Nothing in DB, bailout. + return; + } + + // Send the request to get the job status from SaaS. + $job_details = $this->api->get_queue_job_status( $row_details->job_id, $row_details->queue_name, Utils::is_home( $row_details->url ) ); + + foreach ( $this->factories as $factory ) { + $factory->manager()->validate_and_fail( $job_details, $row_details, $optimization_type ); + } + + if ( + 200 !== (int) $job_details['code'] + ) { + $this->logger::debug( 'Job status failed for url: ' . $row_details->url, $job_details ); + $this->decide_strategy( $row_details, $job_details, $optimization_type ); + + return; + } + /** + * Unlock preload URL. + * + * @param string $url URL to unlock + */ + do_action( 'rocket_preload_unlock_url', $row_details->url ); + + foreach ( $this->factories as $factory ) { + $factory->manager()->process( $job_details, $row_details, $optimization_type ); + } + + /** + * Fires after successfully Processing the SaaS jobs. + * + * @param string $current_time Current time. + */ + rocket_do_action_and_deprecated( + 'rocket_saas_check_job_status_end', + [ $this->wpr_clock->current_time( 'mysql', true ) ], + '3.16', + 'rocket_rucss_check_job_status_end' + ); + + /** + * Fires after successfully processing the SaaS jobs. + * + * @param string $url Optimized Url. + * @param array $job_details Result of the request to get the job status from SaaS. + */ + rocket_do_action_and_deprecated( + 'rocket_saas_complete_job_status', + [ $row_details->url, $job_details ], + '3.16', + 'rocket_rucss_complete_job_status' + ); + } + + /** + * Process on submit jobs. + * + * @return void + */ + public function process_on_submit_jobs() { + $this->logger::debug( 'Start processing on submit jobs for adding jobs to queue.' ); + + /** + * Fires at the start of the process on submit jobs. + * + * @param string $current_time Current time. + */ + rocket_do_action_and_deprecated( + 'rocket_saas_process_on_submit_jobs_start', + [ $this->wpr_clock->current_time( 'mysql', true ) ], + '3.16', + 'rocket_rucss_process_on_submit_jobs_start' + ); + + if ( ! $this->is_allowed() ) { + $this->logger::debug( 'Stop processing cron iteration for to-submit jobs.' ); + + return; + } + + /** + * Pending rows cont. + * + * @param int $count Number of rows. + */ + $pending_job = rocket_apply_filter_and_deprecated( + 'rocket_saas_pending_jobs_cron_rows_count', + [ 100 ], + '3.16', + 'rocket_rucss_pending_jobs_cron_rows_count' + ); + + /** + * Maximum processing rows. + * + * @param int $max Max processing rows. + */ + $max_pending_rows = (int) rocket_apply_filter_and_deprecated( + 'rocket_saas_max_pending_jobs', + [ 3 * $pending_job, $pending_job ], + '3.16', + 'rocket_rucss_max_pending_jobs' + ); + + $rows = $this->get_jobs( $max_pending_rows, 'submit' ); + + if ( ! $rows ) { + return; + } + + foreach ( $rows as $row ) { + $optimization_type = $this->get_optimization_type( $row ); + $response = $this->send_api( $row->url, (bool) $row->is_mobile, $optimization_type ); + + if ( false === $response || ! isset( $response['contents'], $response['contents']['jobId'], $response['contents']['queueName'] ) ) { + + $this->make_status_failed( $row->url, $row->is_mobile, '', '', $optimization_type ); + continue; + } + + /** + * Lock preload URL. + * + * @param string $url URL to lock + */ + do_action( 'rocket_preload_lock_url', $row->url ); + + $this->make_status_pending( + $row->url, + $response['contents']['jobId'], + $response['contents']['queueName'], + (bool) $row->is_mobile, + $optimization_type + ); + } + + $this->logger::debug( 'End processing on submit jobs for adding jobs to queue.' ); + /** + * Fires at the end of the process pending jobs. + * + * @param string $current_time Current time. + */ + rocket_do_action_and_deprecated( + 'rocket_saas_process_on_submit_jobs_end', + [ $this->wpr_clock->current_time( 'mysql', true ) ], + '3.16', + 'rocket_rucss_process_on_submit_jobs_end' + ); + } + + /** + * Send the job to the API. + * + * @param string $url URL to work on. + * @param bool $is_mobile Is the page for mobile. + * @param string $optimization_type The type of optimization request to send. + * @return array|false + */ + protected function send_api( string $url, bool $is_mobile, string $optimization_type ) { + $config = [ + 'is_mobile' => $is_mobile, + 'is_home' => Utils::is_home( $url ), + ]; + + $config = $this->set_request_params( $config, $optimization_type ); + + $add_to_queue_response = $this->api->add_to_queue( $url, $config ); + + if ( 200 !== $add_to_queue_response['code'] ) { + $this->logger::error( + 'Error when contacting the SaaS API.', + [ + 'SaaS error', + 'url' => $url, + 'code' => $add_to_queue_response['code'], + 'message' => $add_to_queue_response['message'], + ] + ); + + return false; + } + + return $add_to_queue_response; + } + + /** + * Set request parameters + * + * @param array $config Array of request parameters. + * @param string $optimization_type The type of optimization applied for the current job. + * @return array + */ + public function set_request_params( array $config, string $optimization_type ): array { + list($updated_config, $optimization_list, $request_param) = [ [], [], [] ]; + + foreach ( $this->factories as $factory ) { + if ( $optimization_type === $factory->manager()->get_optimization_type() ) { + $config = array_merge( $config, $factory->manager()->set_request_param() ); + + return $config; + } + + $request_param = $factory->manager()->set_request_param(); + + $optimization_list = array_merge( $optimization_list, $request_param['optimization_list'] ); + $updated_config = array_merge( $request_param, $updated_config ); + } + + if ( ! $updated_config ) { + $updated_config['optimization_list'] = $optimization_list; + } + + return $updated_config; + } + + /** + * Clear failed urls. + * + * @return void + */ + public function clear_failed_urls(): void { + /** + * Delay before failed saas jobs are deleted. + * + * @param string $delay delay before failed saas jobs are deleted. + */ + $delay = (string) rocket_apply_filter_and_deprecated( + 'rocket_delay_remove_saas_failed_jobs', + [ '3 days' ], + '3.16', + 'rocket_delay_remove_rucss_failed_jobs' + ); + + if ( '' === $delay || '0' === $delay ) { + $delay = '3 days'; + } + $parts = explode( ' ', $delay ); + + $value = 3; + $unit = 'days'; + + if ( count( $parts ) === 2 && $parts[0] >= 0 ) { + $value = (float) $parts[0]; + $unit = $parts[1]; + } + + foreach ( $this->factories as $factory ) { + if ( $factory->manager()->is_allowed() ) { + $failed_urls = $factory->manager()->clear_failed_jobs( $value, $unit ); + + $hook = 'rocket_' . $factory->manager()->get_optimization_type() . '_after_clearing_failed_url'; + + /** + * Fires after clearing failed urls. + * + * @param array $urls Failed urls. + */ + do_action( $hook, $failed_urls ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals + } + } + } + + /** + * Change the status to be in-progress. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $optimization_type The type of optimization applied for the current job. + * @return void + */ + private function make_status_inprogress( string $url, bool $is_mobile, string $optimization_type ): void { + foreach ( $this->factories as $factory ) { + $factory->manager()->make_status_inprogress( $url, $is_mobile, $optimization_type ); + } + } + + /** + * Get single job. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $optimization_type The type of optimization applied for the current job. + * + * @return bool|object + */ + private function get_single_job( string $url, bool $is_mobile, string $optimization_type ) { + $job = []; + + foreach ( $this->factories as $factory ) { + if ( $optimization_type === $factory->manager()->get_optimization_type() ) { + return $factory->manager()->get_single_job( $url, $is_mobile ); + } + } + + $job = $this->factories[0]->manager()->get_single_job( $url, $is_mobile ); + + return ( ! $job ? [] : $job ); + } + + /** + * Decide jobs to get. + * + * @param integer $num_rows Number of rows to grab with each CRON iteration. + * @param string $type Type of job to get. + * @return array + */ + public function get_jobs( int $num_rows, string $type ): array { + $allowed_types = [ 'pending', 'submit' ]; + + if ( ! in_array( $type, $allowed_types, true ) ) { + return []; + } + + $rows = []; + + switch ( $type ) { + case 'pending': + foreach ( $this->factories as $factory ) { + $rows = array_merge( $rows, $factory->manager()->get_pending_jobs( $num_rows ) ); + } + break; + case 'submit': + foreach ( $this->factories as $factory ) { + $rows = array_merge( $rows, $factory->manager()->get_on_submit_jobs( $num_rows ) ); + } + break; + } + + if ( ! $rows ) { + return []; + } + + // Get distinct rows. + return $this->get_distinct( $rows ); + } + + /** + * Get rows common to jobs. + * + * @param array $rows Merged DB Rows of jobs. + * @return array + */ + private function get_common_jobs( array $rows ): array { + list($occurrences, $duplicates) = [ [], [] ]; + + foreach ( $rows as $row ) { + $key = $row->url . '|' . ( (bool) $row->is_mobile ?? 'null' ); + + if ( ! isset( $occurrences[ $key ] ) ) { + $occurrences[ $key ] = 1; + + continue; + } + + ++$occurrences[ $key ]; + + if ( 2 === $occurrences[ $key ] ) { + // Add new is_common property to the object and add object to duplicate. + $row->is_common = true; + $duplicates[] = $row; + } + } + + return $duplicates; + } + + /** + * Get distinct rows merged from both jobs. + * + * @param array $rows Merged DB Rows of jobs. + * @return array + */ + private function get_distinct( array $rows ): array { + // Get jobs common to both optimizations. + $common_rows = $this->get_common_jobs( $rows ); + + if ( ! $common_rows ) { + return $rows; + } + + $index = 0; + + foreach ( $rows as $row ) { + foreach ( $common_rows as $common_row ) { + if ( $row->url === $common_row->url && (bool) $row->is_mobile === (bool) $common_row->is_mobile ) { + // Remove the common row that is without the new is_common property. + unset( $rows[ $index ] ); + } + } + + ++$index; + } + + return array_merge( $rows, $common_rows ); + } + + /** + * Get the optimization type requested. + * + * @param object $row DB Row. + * @return string + */ + public function get_optimization_type( $row ): string { + $optimization_type = 'all'; + + if ( isset( $row->is_common ) ) { + return $optimization_type; + } + + foreach ( $this->factories as $factory ) { + $type = $factory->manager()->get_optimization_type_from_row( $row ); + + if ( is_string( $type ) ) { + $optimization_type = $type; + break; + } + } + + return $optimization_type; + } + + /** + * Decide with job strategy to apply based on the optimization type. + * + * @param object $row_details DB Row of job. + * @param array $job_details Job details from the API. + * @param string $optimization_type The type of optimization applied for the current job. + * @return void + */ + private function decide_strategy( $row_details, array $job_details, string $optimization_type ): void { + foreach ( $this->factories as $factory ) { + if ( $optimization_type === $factory->manager()->get_optimization_type() ) { + $this->strategy_factory->manage( $row_details, $job_details, $factory->manager() ); + break; + } + + $this->strategy_factory->manage( $row_details, $job_details, $factory->manager() ); + } + } + + /** + * Change the job status to be failed. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $error_code error code. + * @param string $error_message error message. + * @param string $optimization_type The type of optimization applied for the current job. + * @return void + */ + private function make_status_failed( string $url, bool $is_mobile, string $error_code, string $error_message, $optimization_type ): void { + foreach ( $this->factories as $factory ) { + $factory->manager()->make_status_failed( $url, $is_mobile, $error_code, $error_message, $optimization_type ); + } + } + + /** + * Change the job status to be pending. + * + * @param string $url Url from DB row. + * @param string $job_id API job_id. + * @param string $queue_name API Queue name. + * @param boolean $is_mobile if the request is for mobile page. + * @param string $optimization_type The type of optimization applied for the current job. + * @return void + */ + private function make_status_pending( string $url, string $job_id, string $queue_name, bool $is_mobile, string $optimization_type ): void { + foreach ( $this->factories as $factory ) { + $factory->manager()->make_status_pending( $url, $job_id, $queue_name, $is_mobile, $optimization_type ); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Managers/AbstractManager.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Managers/AbstractManager.php new file mode 100644 index 000000000..f22c0749a --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Managers/AbstractManager.php @@ -0,0 +1,223 @@ +<?php + +namespace WP_Rocket\Engine\Common\JobManager\Managers; + +trait AbstractManager { + + /** + * Determine if the action is allowed. + * + * @param string $optimization_type The type of optimization applied for the current job. + * + * @return boolean + */ + public function is_allowed( $optimization_type = '' ): bool { + if ( ! $this->context->is_allowed() ) { + return false; + } + + if ( ! $optimization_type ) { + return true; + } + + return in_array( $optimization_type, [ 'all', $this->optimization_type ], true ); + } + + /** + * Query object. + * + * @return object + */ + public function query() { + return $this->query; + } + + /** + * Return type of optimization. + * + * @return string + */ + public function get_optimization_type(): string { + return $this->optimization_type; + } + + /** + * Send the request to add url into the queue. + * + * @param string $url page URL. + * @param bool $is_mobile page is for mobile. + * + * @return void + */ + public function add_url_to_the_queue( string $url, bool $is_mobile ): void { + if ( ! $this->is_allowed() ) { + return; + } + + $row = $this->query->get_row( $url, (bool) $is_mobile ); + + if ( empty( $row ) ) { + $this->query->create_new_job( $url, '', '', $is_mobile ); + return; + } + $this->query->reset_job( (int) $row->id ); + } + + /** + * Clear failed jobs. + * + * @param float $delay delay before the urls are deleted. + * @param string $unit unit from the delay. + * @return array + */ + public function clear_failed_jobs( float $delay, string $unit ): array { + $rows = $this->query->get_failed_rows( $delay, $unit ); + + if ( empty( $rows ) ) { + return []; + } + + $failed_urls = []; + + foreach ( $rows as $row ) { + $failed_urls[] = $row->url; + + $id = (int) $row->id; + + if ( empty( $id ) ) { + continue; + } + + $this->add_url_to_the_queue( $row->url, (bool) $row->is_mobile ); + } + + return $failed_urls; + } + + /** + * Change the status to be in-progress. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $optimization_type The type of optimization applied for the current job. + * @return void + */ + public function make_status_inprogress( string $url, bool $is_mobile, string $optimization_type ): void { + if ( ! $this->is_allowed( $optimization_type ) ) { + return; + } + + $this->query->make_status_inprogress( $url, $is_mobile ); + } + + /** + * Get single job. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @return bool|object + */ + public function get_single_job( string $url, bool $is_mobile ) { + return $this->query->get_row( $url, $is_mobile ); + } + + /** + * Get on submit jobs based on enabled option. + * + * @param integer $num_rows Number of rows to grab with each CRON iteration. + * @return array|int + */ + public function get_on_submit_jobs( int $num_rows ): array { + return $this->query->get_on_submit_jobs( $num_rows ); + } + + /** + * Change the job status to be failed. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $error_code error code. + * @param string $error_message error message. + * @param string $optimization_type The type of optimization applied for the current job. + * @return void + */ + public function make_status_failed( string $url, bool $is_mobile, string $error_code, string $error_message, string $optimization_type = '' ): void { + if ( ! $this->is_allowed( $optimization_type ) ) { + return; + } + + $this->query->make_status_failed( $url, $is_mobile, $error_code, $error_message ); + } + + /** + * Change the job status to be pending. + * + * @param string $url Url from DB row. + * @param string $job_id API job_id. + * @param string $queue_name API Queue name. + * @param boolean $is_mobile if the request is for mobile page. + * @param string $optimization_type The type of optimization applied for the current job. + * @return void + */ + public function make_status_pending( string $url, string $job_id, string $queue_name, bool $is_mobile, string $optimization_type ): void { + if ( ! $this->is_allowed( $optimization_type ) ) { + return; + } + + $this->query->make_status_pending( $url, $job_id, $queue_name, $is_mobile ); + } + + /** + * Increment retries number and change status back to pending. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $error_code error code. + * @param string $error_message error message. + * + * @return void + */ + public function increment_retries( string $url, bool $is_mobile, string $error_code, string $error_message ): void { + if ( ! $this->is_allowed() ) { + return; + } + + $this->query->increment_retries( $url, $is_mobile, $error_code, $error_message ); + } + + /** + * Update the error message. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $error_code error code. + * @param string $error_message error message. + * @param string $previous_message Previous saved message. + * + * @return void + */ + public function update_message( string $url, bool $is_mobile, string $error_code, string $error_message, string $previous_message ): void { + if ( ! $this->is_allowed() ) { + return; + } + + $this->query->update_message( $url, $is_mobile, $error_code, $error_message, $previous_message ); + } + + /** + * Updates the next_retry_time field + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string|int $next_retry_time timestamp or mysql format date. + * + * @return void + */ + public function update_next_retry_time( string $url, bool $is_mobile, $next_retry_time ): void { + if ( ! $this->is_allowed() ) { + return; + } + + $this->query->update_next_retry_time( $url, $is_mobile, $next_retry_time ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Managers/ManagerInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Managers/ManagerInterface.php new file mode 100644 index 000000000..e989183cb --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Managers/ManagerInterface.php @@ -0,0 +1,49 @@ +<?php + +namespace WP_Rocket\Engine\Common\JobManager\Managers; + +interface ManagerInterface { + + /** + * Get pending jobs from db. + * + * @param integer $num_rows Number of rows to grab. + * @return array + */ + public function get_pending_jobs( int $num_rows ): array; + + /** + * Validate SaaS response and fail job. + * + * @param array $job_details Details related to the job.. + * @param object $row_details Details related to the row. + * @param string $optimization_type The type of optimization applied for the current job. + * @return void + */ + public function validate_and_fail( array $job_details, $row_details, string $optimization_type ): void; + + /** + * Process SaaS response. + * + * @param array $job_details Details related to the job.. + * @param object $row_details Details related to the row. + * @param string $optimization_type The type of optimization applied for the current job. + * @return void + */ + public function process( array $job_details, $row_details, string $optimization_type ): void; + + /** + * Set the request parameter to be sent to the SaaS + * + * @return array + */ + public function set_request_param(): array; + + /** + * Get the optimization type from the DB Row. + * + * @param object $row DB Row Object. + * @return boolean|string + */ + public function get_optimization_type_from_row( $row ); +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Queue/Queue.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Queue/Queue.php new file mode 100644 index 000000000..dc4bbbf43 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Queue/Queue.php @@ -0,0 +1,79 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Common\JobManager\Queue; + +use WP_Rocket\Engine\Common\Queue\AbstractASQueue; + +/** + * Queue + * + * A job queue using WordPress actions. + * + * @version 3.11.0 + */ +class Queue extends AbstractASQueue { + + /** + * Queue group. + * + * @var string + */ + protected $group = 'rocket-rucss'; + + /** + * Pending jobs cron hook. + * + * @var string + */ + private $pending_job_cron = 'rocket_saas_pending_jobs_cron'; + + /** + * Check if pending jobs cron is scheduled. + * + * @return bool + */ + public function is_pending_jobs_cron_scheduled() { + return $this->is_scheduled( $this->pending_job_cron ); + } + + /** + * Cancel pending jobs cron. + * + * @return void + */ + public function cancel_pending_jobs_cron() { + $this->cancel_all( $this->pending_job_cron ); + } + + /** + * Schedule pending jobs cron. + * + * @param int $interval Cron interval in seconds. + * + * @return string + */ + public function schedule_pending_jobs_cron( int $interval ) { + return $this->schedule_recurring( time(), $interval, $this->pending_job_cron ); + } + + /** + * Add Async job with DB row ID. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param string $optimization_type The type of optimization request to send. + * + * @return int + */ + public function add_job_status_check_async( string $url, bool $is_mobile, string $optimization_type ) { + return $this->add_async( + 'rocket_saas_job_check_status', + [ + $url, + $is_mobile, + $optimization_type, + ] + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/ServiceProvider.php new file mode 100644 index 000000000..e12ff10ba --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/ServiceProvider.php @@ -0,0 +1,91 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Common\JobManager; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Common\JobManager\Strategy\Context\RetryContext; +use WP_Rocket\Engine\Common\JobManager\Strategy\Factory\StrategyFactory; +use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\DefaultProcess; +use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\JobSetFail; +use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\ResetRetryProcess; +use WP_Rocket\Engine\Common\Clock\WPRClock; +use WP_Rocket\Engine\Common\JobManager\Queue\Queue; +use WP_Rocket\Engine\Common\JobManager\APIHandler\APIClient; +use WP_Rocket\Engine\Common\JobManager\Cron\Subscriber as CronSubscriber; + + +class ServiceProvider extends AbstractServiceProvider { + /** + * The provides array is a way to let the container + * know that a service is provided by this service + * provider. Every service that is registered via + * this service provider must have an alias added + * to this array or it will be ignored. + * + * @var array + */ + protected $provides = [ + 'wpr_clock', + 'retry_strategy_factory', + 'retry_strategy_context', + 'job_processor', + 'queue', + 'api_client', + 'cron_subscriber', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers the classes in the container + * + * @return void + */ + public function register(): void { + + $factories = [ + $this->getContainer()->get( 'rucss_factory' ), + ]; + + $this->getContainer()->add( 'wpr_clock', WPRClock::class ); + + $this->getContainer()->add( 'retry_strategy_context', RetryContext::class ); + + $this->getContainer()->add( 'retry_strategy_factory', StrategyFactory::class ) + ->addArgument( $this->getContainer()->get( 'wpr_clock' ) ); + + $this->getContainer()->add( 'queue', Queue::class ); + + $this->getContainer()->add( 'api_client', APIClient::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + + $this->getContainer()->addShared( 'job_processor', JobProcessor::class ) + ->addArguments( + [ + $factories, + $this->getContainer()->get( 'queue' ), + $this->getContainer()->get( 'retry_strategy_factory' ), + $this->getContainer()->get( 'api_client' ), + $this->getContainer()->get( 'wpr_clock' ), + ] + ); + + $this->getContainer()->addShared( 'cron_subscriber', CronSubscriber::class ) + ->addArguments( + [ + $this->getContainer()->get( 'job_processor' ), + $factories, + ] + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Context/RetryContext.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Context/RetryContext.php new file mode 100644 index 000000000..b7ef8e43d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Context/RetryContext.php @@ -0,0 +1,37 @@ +<?php + +namespace WP_Rocket\Engine\Common\JobManager\Strategy\Context; + +use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\StrategyInterface; + +class RetryContext { + /** + * Strategy Interface. + * + * @var StrategyInterface; + */ + protected $strategy; + + /** + * Set the strategy property + * + * @param StrategyInterface $strategy Strategy. + * + * @return void + */ + public function set_strategy( StrategyInterface $strategy ) { + $this->strategy = $strategy; + } + + /** + * Execute the strategy. + * + * @param object $row_details row from the database. + * @param array $job_details job details. + * + * @return void + */ + public function execute( $row_details, $job_details ): void { + $this->strategy->execute( $row_details, $job_details ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Factory/StrategyFactory.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Factory/StrategyFactory.php new file mode 100644 index 000000000..bc7875e6d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Factory/StrategyFactory.php @@ -0,0 +1,64 @@ +<?php + + +namespace WP_Rocket\Engine\Common\JobManager\Strategy\Factory; + +use WP_Rocket\Engine\Common\Clock\WPRClock; +use WP_Rocket\Engine\Common\JobManager\Strategy\Context\RetryContext; +use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\JobSetFail; +use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\ResetRetryProcess; +use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\DefaultProcess; +use WP_Rocket\Logger\LoggerAware; +use WP_Rocket\Logger\LoggerAwareInterface; +use WP_Rocket\Engine\Common\JobManager\Managers\ManagerInterface; + + +class StrategyFactory implements LoggerAwareInterface { + use LoggerAware; + + /** + * Clock instance. + * + * @var WPRClock + */ + protected $clock; + + /** + * Constructor. + * + * @param WPRClock $clock Clock instance. + */ + public function __construct( WPRClock $clock ) { + $this->clock = $clock; + } + /** + * Manage the whole process, to determine which strategy to adopt.. + * + * @param object $row_details DB Row of a job. + * @param array $job_details Job information from the API. + * @param ManagerInterface $manager Job Manager. + * + * @return void + */ + public function manage( $row_details, $job_details, ManagerInterface $manager ): void { + + switch ( $job_details['code'] ) { + case 408: + $strategy = new ResetRetryProcess( $manager ); + break; + case 500: + case 422: + case 404: + case 401: + $strategy = new JobSetFail( $manager ); + break; + default: + $strategy = new DefaultProcess( $manager, $this->clock ); + break; + } + + $context = new RetryContext(); + $context->set_strategy( $strategy ); + $context->execute( $row_details, $job_details ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/DefaultProcess.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/DefaultProcess.php new file mode 100644 index 000000000..43793483d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/DefaultProcess.php @@ -0,0 +1,123 @@ +<?php + +namespace WP_Rocket\Engine\Common\JobManager\Strategy\Strategies; + +use WP_Rocket\Engine\Common\Clock\WPRClock; +use WP_Rocket\Engine\Common\JobManager\Managers\ManagerInterface; + +/** + * Class managing the default error for retry process + */ +class DefaultProcess implements StrategyInterface { + + /** + * Job Manager. + * + * @var ManagerInterface + */ + private $manager; + + /** + * Clock Object. + * + * @var WPRClock + */ + protected $clock; + + /** + * Represents a timetable which shows how long to wait after for a new retry depending on how many retries have been made already. + * + * @var int[] + */ + private $time_table_retry = [ + 0 => 60, // 1 minutes + 1 => 120, // 2 minutes + 2 => 300, // 5 minutes + 3 => 600, // 10 minutes. + 4 => 1200, // 20 minutes. + 5 => 1500, // 25 minutes. + ]; + + /** + * Default value to wait before a retry. + * + * @var int + */ + private $default_waiting_retry = 1500; + + /** + * Strategy Constructor. + * + * @param ManagerInterface $manager Job Manager. + * @param WPRClock $clock Clock object. + */ + public function __construct( ManagerInterface $manager, WPRClock $clock ) { + $this->manager = $manager; + $this->clock = $clock; + + /** + * Filter the array containing the time needed to wait for each retry. + * + * @param array $time_table_entry contains the number of retry and how long we have to wait. + */ + $time_table_retry = rocket_apply_filter_and_deprecated( + 'rocket_saas_retry_table', + [ $this->time_table_retry ], + '3.16', + 'rocket_rucss_retry_table' + ); + + if ( is_array( $time_table_retry ) ) { + $this->time_table_retry = $time_table_retry; + } + } + + /** + * Execute the strategy process. + * + * @param object $row_details Row details of the job. + * @param array $job_details Job details from the API. + * + * @return void + */ + public function execute( object $row_details, array $job_details ): void { + + if ( $row_details->retries >= count( $this->time_table_retry ) ) { + /** + * Unlock preload URL. + * + * @param string $url URL to unlock + */ + do_action( 'rocket_preload_unlock_url', $row_details->url ); + + $this->manager->make_status_failed( $row_details->url, $row_details->is_mobile, $job_details['code'], $job_details['message'] ); + + return; + } + + $this->manager->increment_retries( $row_details->url, $row_details->is_mobile, $job_details['code'], $job_details['message'] ); + + $saas_retry_duration = $this->time_table_retry[ $row_details->retries ] ?? $this->default_waiting_retry; // Default to 30 minutes. + + /** + * Filter SaaS retry duration. + * + * @param int $duration Duration between each retry in seconds. + */ + $saas_retry_duration = (int) rocket_apply_filter_and_deprecated( + 'rocket_saas_retry_duration', + [ $saas_retry_duration ], + '3.16', + 'rocket_rucss_retry_duration' + ); + if ( $saas_retry_duration < 0 ) { + $saas_retry_duration = $this->default_waiting_retry; + } + + // update the `next_retry_time` column. + $next_retry_time = $this->clock->current_time( 'timestamp', true ) + $saas_retry_duration; + + $this->manager->update_message( $row_details->url, $row_details->is_mobile, $job_details['code'], $job_details['message'], $row_details->error_message ); + $this->manager->update_next_retry_time( $row_details->url, $row_details->is_mobile, $next_retry_time ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/JobSetFail.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/JobSetFail.php new file mode 100644 index 000000000..8aa5bc553 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/JobSetFail.php @@ -0,0 +1,45 @@ +<?php + +namespace WP_Rocket\Engine\Common\JobManager\Strategy\Strategies; + +use WP_Rocket\Engine\Common\JobManager\Managers\ManagerInterface; + +/** + * Class managing the retry process whenever a job isn't found in the SaaS. + */ +class JobSetFail implements StrategyInterface { + /** + * Job Manager. + * + * @var ManagerInterface + */ + private $manager; + + /** + * Strategy Constructor. + * + * @param ManagerInterface $manager Job Manager. + */ + public function __construct( ManagerInterface $manager ) { + $this->manager = $manager; + } + + /** + * Execute the strategy process. + * + * @param object $row_details Row details of the job. + * @param array $job_details Job details from the API. + * + * @return void + */ + public function execute( object $row_details, array $job_details ): void { + /** + * Unlock preload URL. + * + * @param string $url URL to unlock + */ + do_action( 'rocket_preload_unlock_url', $row_details->url ); + + $this->manager->make_status_failed( $row_details->url, $row_details->is_mobile, strval( $job_details['code'] ), $job_details['message'] ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/ResetRetryProcess.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/ResetRetryProcess.php new file mode 100644 index 000000000..73de51784 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/ResetRetryProcess.php @@ -0,0 +1,38 @@ +<?php + +namespace WP_Rocket\Engine\Common\JobManager\Strategy\Strategies; + +use WP_Rocket\Engine\Common\JobManager\Managers\ManagerInterface; + +/** + * Class managing the retry process whenever a job isn't found in the SaaS. + */ +class ResetRetryProcess implements StrategyInterface { + /** + * Job Manager. + * + * @var ManagerInterface + */ + private $manager; + + /** + * Strategy Constructor. + * + * @param ManagerInterface $manager Job Manager. + */ + public function __construct( ManagerInterface $manager ) { + $this->manager = $manager; + } + + /** + * Execute the strategy process. + * + * @param object $row_details Row details of the job. + * @param array $job_details Job details from the API. + * + * @return void + */ + public function execute( object $row_details, array $job_details ): void { + $this->manager->add_url_to_the_queue( $row_details->url, $row_details->is_mobile ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/StrategyInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/StrategyInterface.php new file mode 100644 index 000000000..601c1ca6c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/JobManager/Strategy/Strategies/StrategyInterface.php @@ -0,0 +1,15 @@ +<?php + +namespace WP_Rocket\Engine\Common\JobManager\Strategy\Strategies; + +interface StrategyInterface { + /** + * Execute the retry process of a RUCSS job. + * + * @param object $row_details DB Row of a job. + * @param array $job_details Job information from the API. + * + * @return mixed + */ + public function execute( object $row_details, array $job_details ); +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/AbstractASQueue.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/AbstractASQueue.php new file mode 100644 index 000000000..7c6705839 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/AbstractASQueue.php @@ -0,0 +1,253 @@ +<?php +declare( strict_types=1 ); + +namespace WP_Rocket\Engine\Common\Queue; + +use ActionScheduler_Store; +use Exception; +use WP_Rocket\Logger\Logger; + +abstract class AbstractASQueue implements QueueInterface { + + /** + * Queue shared Group. + * + * @var string + */ + protected $group = 'rocket'; + + /** + * Enqueue an action to run one time, as soon as possible + * + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @return int The action ID. + */ + public function add_async( $hook, $args = [] ) { + try { + if ( function_exists( 'as_enqueue_async_action' ) ) { + return as_enqueue_async_action( $hook, $args, $this->group ); + } + + return $this->schedule_single( time() + MINUTE_IN_SECONDS, $hook, $args ); + } catch ( Exception $exception ) { + Logger::error( $exception->getMessage(), [ 'Action Scheduler Queue' ] ); + + return 0; + } + } + + /** + * Schedule an action to run once at some time in the future + * + * @param int $timestamp When the job will run. + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @return int The action ID. + */ + public function schedule_single( $timestamp, $hook, $args = [] ) { + try { + return as_schedule_single_action( $timestamp, $hook, $args, $this->group ); + } catch ( Exception $exception ) { + Logger::error( $exception->getMessage(), [ 'Action Scheduler Queue' ] ); + + return 0; + } + } + + /** + * Schedule a recurring action + * + * @param int $timestamp When the first instance of the job will run. + * @param int $interval_in_seconds How long to wait between runs. + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @return int The action ID. + */ + public function schedule_recurring( $timestamp, $interval_in_seconds, $hook, $args = [] ) { + if ( $this->is_scheduled( $hook, $args ) ) { + // TODO: When v3.3.0 from Action Scheduler is commonly used use the array notation for status to reduce search queries to one. + $pending_actions = $this->search( + [ + 'hook' => $hook, + 'status' => ActionScheduler_Store::STATUS_PENDING, + ], + 'ids' + ); + + if ( 1 < count( $pending_actions ) ) { + $this->cancel_all( $hook, $args ); + return ''; + } + + $running_actions = $this->search( + [ + 'hook' => $hook, + 'status' => ActionScheduler_Store::STATUS_RUNNING, + ], + 'ids' + ); + + if ( 1 === count( $pending_actions ) + count( $running_actions ) ) { + return ''; + } + + $this->cancel_all( $hook, $args ); + } + + try { + return as_schedule_recurring_action( $timestamp, $interval_in_seconds, $hook, $args, $this->group ); + } catch ( Exception $exception ) { + Logger::error( $exception->getMessage(), [ 'Action Scheduler Queue' ] ); + + return 0; + } + } + + /** + * Checks if the hook is scheduled. + * + * @param string $hook The hook to check. + * @param array $args Passed arguments. + * + * @return bool + */ + public function is_scheduled( $hook, $args = [] ) { + if ( ! function_exists( 'as_has_scheduled_action' ) ) { + return ! is_null( $this->get_next( $hook, $args ) ); + } + + try { + return as_has_scheduled_action( $hook, $args, $this->group ); + } catch ( Exception $exception ) { + Logger::error( $exception->getMessage(), [ 'Action Scheduler Queue' ] ); + + return false; + } + } + + /** + * Schedule an action that recurs on a cron-like schedule. + * + * @param int $timestamp The schedule will start on or after this time. + * @param string $cron_schedule A cron-link schedule string. + * @see http://en.wikipedia.org/wiki/Cron + * * * * * * * + * ┬ ┬ ┬ ┬ ┬ ┬ + * | | | | | | + * | | | | | + year [optional] + * | | | | +----- day of week (0 - 7) (Sunday=0 or 7) + * | | | +---------- month (1 - 12) + * | | +--------------- day of month (1 - 31) + * | +-------------------- hour (0 - 23) + * +------------------------- min (0 - 59) + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @return int The action ID + */ + public function schedule_cron( $timestamp, $cron_schedule, $hook, $args = [] ) { + if ( $this->is_scheduled( $hook, $args ) ) { + return ''; + } + + try { + return as_schedule_cron_action( $timestamp, $cron_schedule, $hook, $args, $this->group ); + } catch ( Exception $exception ) { + Logger::error( $exception->getMessage(), [ 'Action Scheduler Queue' ] ); + + return 0; + } + } + + /** + * Dequeue the next scheduled instance of an action with a matching hook (and optionally matching args and group). + * + * Any recurring actions with a matching hook should also be cancelled, not just the next scheduled action. + * + * While technically only the next instance of a recurring or cron action is unscheduled by this method, that will also + * prevent all future instances of that recurring or cron action from being run. Recurring and cron actions are scheduled + * in a sequence instead of all being scheduled at once. Each successive occurrence of a recurring action is scheduled + * only after the former action is run. As the next instance is never run, because it's unscheduled by this function, + * then the following instance will never be scheduled (or exist), which is effectively the same as being unscheduled + * by this method also. + * + * @param string $hook The hook that the job will trigger. + * @param array $args Args that would have been passed to the job. + */ + public function cancel( $hook, $args = [] ) { + try { + as_unschedule_action( $hook, $args, $this->group ); + } catch ( Exception $exception ) { + Logger::error( $exception->getMessage(), [ 'Action Scheduler Queue' ] ); + } + } + + /** + * Dequeue all actions with a matching hook (and optionally matching args and group) so no matching actions are ever run. + * + * @param string $hook The hook that the job will trigger. + * @param array $args Args that would have been passed to the job. + */ + public function cancel_all( $hook, $args = [] ) { + try { + as_unschedule_all_actions( $hook, $args, $this->group ); + } catch ( Exception $exception ) { + Logger::error( $exception->getMessage(), [ 'Action Scheduler Queue' ] ); + } + } + + /** + * Get the date and time for the next scheduled occurence of an action with a given hook + * (an optionally that matches certain args and group), if any. + * + * @param string $hook The hook that the job will trigger. + * @param array $args Filter to a hook with matching args that will be passed to the job when it runs. + * @return int|null The date and time for the next occurrence, or null if there is no pending, scheduled action for the given hook. + */ + public function get_next( $hook, $args = null ) { + try { + $next_timestamp = as_next_scheduled_action( $hook, $args, $this->group ); + + if ( is_numeric( $next_timestamp ) ) { + return $next_timestamp; + } + + return null; + } catch ( Exception $exception ) { + Logger::error( $exception->getMessage(), [ 'Action Scheduler Queue' ] ); + + return null; + } + } + + /** + * Find scheduled actions + * + * @param array $args Possible arguments, with their default values: + * 'hook' => '' - the name of the action that will be triggered + * 'args' => null - the args array that will be passed with the action + * 'date' => null - the scheduled date of the action. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. + * 'date_compare' => '<=' - operator for testing "date". accepted values are '!=', '>', '>=', '<', '<=', '=' + * 'modified' => null - the date the action was last updated. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. + * 'modified_compare' => '<=' - operator for testing "modified". accepted values are '!=', '>', '>=', '<', '<=', '=' + * 'group' => '' - the group the action belongs to + * 'status' => '' - ActionScheduler_Store::STATUS_COMPLETE or ActionScheduler_Store::STATUS_PENDING + * 'claimed' => null - TRUE to find claimed actions, FALSE to find unclaimed actions, a string to find a specific claim ID + * 'per_page' => 5 - Number of results to return + * 'offset' => 0 + * 'orderby' => 'date' - accepted values are 'hook', 'group', 'modified', or 'date' + * 'order' => 'ASC'. + * + * @param string $return_format OBJECT, ARRAY_A, or ids. + * @return array + */ + public function search( $args = [], $return_format = OBJECT ) { + try { + return as_get_scheduled_actions( $args, $return_format ); + } catch ( Exception $exception ) { + Logger::error( $exception->getMessage(), [ 'Action Scheduler Queue' ] ); + + return []; + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/Cleaner.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/Cleaner.php new file mode 100644 index 000000000..eb48bb723 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/Cleaner.php @@ -0,0 +1,103 @@ +<?php +declare( strict_types=1 ); + +namespace WP_Rocket\Engine\Common\Queue; + +class Cleaner extends \ActionScheduler_QueueCleaner { + + /** + * The duration of clean Hour In seconds. + * + * @var int + */ + protected $hour_in_seconds = 60 * 60; + + /** + * Store instance. + * + * @var \ActionScheduler_Store + */ + private $store = null; + + /** + * Group name to be cleaned. + * + * @var string + */ + private $group; + + /** + * Cleaner constructor. + * + * @param \ActionScheduler_Store|null $store The store instance. + * @param int $batch_size The batch size. + * @param string $group Current queue group. + */ + public function __construct( \ActionScheduler_Store $store = null, $batch_size = 20, $group = '' ) { + parent::__construct( $store, $batch_size ); + $this->store = $store ? $store : \ActionScheduler_Store::instance(); + $this->group = $group; + } + + /** + * Overrides the base method of action scheduler to do the clean process for our actions only. + * + * @return void + */ + public function delete_old_actions() { + $lifespan = (int) apply_filters( 'action_scheduler_retention_period', $this->hour_in_seconds );// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + + /** + * Filters the retention period for our tasks only. + * + * @since 3.11.0.5 + * + * @param int $lifespan Lifespan in seconds. + * @param string $group The group name. + * + * @return int + */ + $lifespan = (int) apply_filters( 'rocket_action_scheduler_retention_period', $lifespan, $this->group ); + $cutoff = as_get_datetime_object( $lifespan . ' seconds ago' ); + + $statuses_to_purge = [ + \ActionScheduler_Store::STATUS_COMPLETE, + \ActionScheduler_Store::STATUS_CANCELED, + \ActionScheduler_Store::STATUS_FAILED, + ]; + foreach ( $statuses_to_purge as $status ) { + $actions_to_delete = $this->store->query_actions( + [ + 'status' => $status, + 'modified' => $cutoff, + 'modified_compare' => '<=', + 'per_page' => $this->get_batch_size(), + 'orderby' => 'none', + 'group' => $this->group, + ] + ); + + foreach ( $actions_to_delete as $action_id ) { + try { + $this->store->delete_action( $action_id ); + } catch ( \Exception $e ) { + + /** + * Notify 3rd party code of exceptions when deleting a completed action older than the retention period + * + * This hook provides a way for 3rd party code to log or otherwise handle exceptions relating to their + * actions. + * + * @since 2.0.0 + * + * @param int $action_id The scheduled actions ID in the data store + * @param \Exception $e The exception thrown when attempting to delete the action from the data store + * @param int $lifespan The retention period, in seconds, for old actions + * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch + */ + do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) );// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + } + } + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/QueueInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/QueueInterface.php new file mode 100644 index 000000000..d8f556ab7 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/QueueInterface.php @@ -0,0 +1,118 @@ +<?php +declare( strict_types=1 ); + +namespace WP_Rocket\Engine\Common\Queue; + +interface QueueInterface { + + /** + * Enqueue an action to run one time, as soon as possible + * + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @return string The action ID + */ + public function add_async( $hook, $args = [] ); + + /** + * Schedule an action to run once at some time in the future + * + * @param int $timestamp When the job will run. + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @return string The action ID + */ + public function schedule_single( $timestamp, $hook, $args = [] ); + + /** + * Schedule a recurring action + * + * @param int $timestamp When the first instance of the job will run. + * @param int $interval_in_seconds How long to wait between runs. + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @return string The action ID + */ + public function schedule_recurring( $timestamp, $interval_in_seconds, $hook, $args = [] ); + + /** + * Checks if the hook is scheduled. + * + * @param string $hook The hook to check. + * @param array $args Passed arguments. + * + * @return bool + */ + public function is_scheduled( $hook, $args = [] ); + + /** + * Schedule an action that recurs on a cron-like schedule. + * + * @param int $timestamp The schedule will start on or after this time. + * @param string $cron_schedule A cron-link schedule string. + * @see http://en.wikipedia.org/wiki/Cron + * * * * * * * + * ┬ ┬ ┬ ┬ ┬ ┬ + * | | | | | | + * | | | | | + year [optional] + * | | | | +----- day of week (0 - 7) (Sunday=0 or 7) + * | | | +---------- month (1 - 12) + * | | +--------------- day of month (1 - 31) + * | +-------------------- hour (0 - 23) + * +------------------------- min (0 - 59) + * @param string $hook The hook to trigger. + * @param array $args Arguments to pass when the hook triggers. + * @return string The action ID + */ + public function schedule_cron( $timestamp, $cron_schedule, $hook, $args = [] ); + + /** + * Dequeue the next scheduled instance of an action with a matching hook (and optionally matching args and group). + * + * Any recurring actions with a matching hook should also be cancelled, not just the next scheduled action. + * + * @param string $hook The hook that the job will trigger. + * @param array $args Args that would have been passed to the job. + */ + public function cancel( $hook, $args = [] ); + + /** + * Dequeue all actions with a matching hook (and optionally matching args and group) so no matching actions are ever run. + * + * @param string $hook The hook that the job will trigger. + * @param array $args Args that would have been passed to the job. + */ + public function cancel_all( $hook, $args = [] ); + + /** + * Get the date and time for the next scheduled occurence of an action with a given hook + * (an optionally that matches certain args and group), if any. + * + * @param string $hook The hook that the job will trigger. + * @param array $args Filter to a hook with matching args that will be passed to the job when it runs. + * @return int|null The date and time for the next occurrence, or null if there is no pending, scheduled action for the given hook + */ + public function get_next( $hook, $args = null ); + + /** + * Find scheduled actions. + * + * @param array $args Possible arguments, with their default values. + * 'hook' => '' - the name of the action that will be triggered. + * 'args' => null - the args array that will be passed with the action. + * 'date' => null - the scheduled date of the action. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. + * 'date_compare' => '<=' - operator for testing "date". accepted values are '!=', '>', '>=', '<', '<=', '='. + * 'modified' => null - the date the action was last updated. Expects a DateTime object, a unix timestamp, or a string that can parsed with strtotime(). Used in UTC timezone. + * 'modified_compare' => '<=' - operator for testing "modified". accepted values are '!=', '>', '>=', '<', '<=', '='. + * 'group' => '' - the group the action belongs to. + * 'status' => '' - ActionScheduler_Store::STATUS_COMPLETE or ActionScheduler_Store::STATUS_PENDING. + * 'claimed' => null - TRUE to find claimed actions, FALSE to find unclaimed actions, a string to find a specific claim ID. + * 'per_page' => 5 - Number of results to return. + * 'offset' => 0. + * 'orderby' => 'date' - accepted values are 'hook', 'group', 'modified', or 'date'. + * 'order' => 'ASC'. + * @param string $return_format OBJECT, ARRAY_A, or ids. + * @return array + */ + public function search( $args = [], $return_format = OBJECT ); +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/RUCSSQueueRunner.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/RUCSSQueueRunner.php new file mode 100644 index 000000000..9d7e7b9c9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Queue/RUCSSQueueRunner.php @@ -0,0 +1,280 @@ +<?php +declare( strict_types=1 ); + +namespace WP_Rocket\Engine\Common\Queue; + +use WP_Rocket\Logger\Logger; +use ActionScheduler_Abstract_QueueRunner; + +class RUCSSQueueRunner extends ActionScheduler_Abstract_QueueRunner { + + /** + * Cron hook name. + */ + const WP_CRON_HOOK = 'action_scheduler_run_queue_rucss'; + + /** + * Cron schedule interval. + */ + const WP_CRON_SCHEDULE = 'every_minute'; + + /** + * Async Request Queue Runner instance. + * We used the default one from AS. + * + * @var \ActionScheduler_AsyncRequest_QueueRunner Instance. + */ + protected $async_request; + + /** + * Current runner instance. + * + * @var RUCSSQueueRunner Instance. + */ + private static $runner = null; + + /** + * Current queue group. + * + * @var string + */ + private $group = 'rocket-rucss'; + + /** + * Get singleton instance. + * + * @return RUCSSQueueRunner Instance. + */ + public static function instance() { + if ( empty( self::$runner ) ) { + self::$runner = new RUCSSQueueRunner(); + } + return self::$runner; + } + + /** + * ActionScheduler_QueueRunner constructor. + * + * @param \ActionScheduler_Store|null $store Store Instance. + * @param \ActionScheduler_FatalErrorMonitor|null $monitor Fatal Error monitor instance. + * @param Cleaner|null $cleaner Cleaner instance. + * @param \ActionScheduler_AsyncRequest_QueueRunner|null $async_request Async Request Queue Runner instance. + */ + public function __construct( \ActionScheduler_Store $store = null, \ActionScheduler_FatalErrorMonitor $monitor = null, Cleaner $cleaner = null, \ActionScheduler_AsyncRequest_QueueRunner $async_request = null ) { + if ( is_null( $cleaner ) ) { + /** + * Filters the clean batch size. + * + * @since 3.11.0.5 + * + * @param int $batch_size Batch size. + * @param string $group The group name. + * + * @return int + */ + $batch_size = (int) apply_filters( 'rocket_action_scheduler_clean_batch_size', 100, $this->group ); + $cleaner = new Cleaner( $store, $batch_size, $this->group ); + } + + parent::__construct( $store, $monitor, $cleaner ); + + if ( is_null( $async_request ) ) { + $async_request = new \ActionScheduler_AsyncRequest_QueueRunner( $this->store ); + } + + $this->async_request = $async_request; + } + + /** + * Initialize the queue runner. + */ + public function init() { + + // phpcs:ignore WordPress.WP.CronInterval.CronSchedulesInterval + add_filter( 'cron_schedules', [ self::instance(), 'add_wp_cron_schedule' ] ); + + // Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param. + $next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK ); + if ( $next_timestamp ) { + wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK ); + } + + $cron_context = [ 'WP Cron' ]; + + if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) { + $schedule = apply_filters( 'rocket_action_scheduler_run_schedule', self::WP_CRON_SCHEDULE ); + wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context ); + } + + add_action( self::WP_CRON_HOOK, [ self::instance(), 'run' ] ); + $this->hook_dispatch_async_request(); + } + + /** + * Hook check for dispatching an async request. + */ + public function hook_dispatch_async_request() { + add_action( 'shutdown', [ $this, 'maybe_dispatch_async_request' ] ); + } + + /** + * Unhook check for dispatching an async request. + */ + public function unhook_dispatch_async_request() { + remove_action( 'shutdown', [ $this, 'maybe_dispatch_async_request' ] ); + } + + /** + * Check if we should dispatch an async request to process actions. + * + * This method is attached to 'shutdown', so is called frequently. To avoid slowing down + * the site, it mitigates the work performed in each request by: + * 1. checking if it's in the admin context and then + * 2. haven't run on the 'shutdown' hook within the lock time (60 seconds by default) + * 3. haven't exceeded the number of allowed batches. + * + * The order of these checks is important, because they run from a check on a value: + * 1. in memory - is_admin() maps to $GLOBALS or the WP_ADMIN constant + * 2. in memory - transients use autoloaded options by default + * 3. from a database query - has_maximum_concurrent_batches() run the query + * $this->store->get_claim_count() to find the current number of claims in the DB. + * + * If all of these conditions are met, then we request an async runner check whether it + * should dispatch a request to process pending actions. + */ + public function maybe_dispatch_async_request() { + if ( is_admin() && ! \ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) { + // Only start an async queue at most once every 60 seconds. + \ActionScheduler::lock()->set( 'async-request-runner' ); + $this->async_request->maybe_dispatch(); + } + } + + /** + * Process actions in the queue. Attached to self::WP_CRON_HOOK i.e. 'action_scheduler_run_queue' + * + * The $context param of this method defaults to 'WP Cron', because prior to Action Scheduler 3.0.0 + * that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context + * passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK, + * should set a context as the first parameter. For an example of this, refer to the code seen in + * + * @see ActionScheduler_AsyncRequest_QueueRunner::handle() + * + * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' + * Generally, this should be capitalised and not localised as it's a proper noun. + * + * @return void + */ + public function run( $context = 'WP Cron' ) { + \ActionScheduler_Compatibility::raise_memory_limit(); + \ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() ); + do_action( 'action_scheduler_before_process_queue' );// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + $this->run_cleanup(); + $processed_actions = 0; + if ( false === $this->has_maximum_concurrent_batches() ) { + $batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 );// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + do { + $processed_actions_in_batch = $this->do_batch( $batch_size, $context ); + $processed_actions += $processed_actions_in_batch; + } while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $processed_actions ) ); // keep going until we run out of actions, time, or memory. + } + + do_action( 'action_scheduler_after_process_queue' );// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + } + + /** + * Process a batch of actions pending in the queue. + * + * Actions are processed by claiming a set of pending actions then processing each one until either the batch + * size is completed, or memory or time limits are reached, defined by @see $this->batch_limits_exceeded(). + * + * @param int $size The maximum number of actions to process in the batch. + * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron' + * Generally, this should be capitalised and not localised as it's a proper noun. + * @return int The number of actions processed. + */ + protected function do_batch( $size = 100, $context = '' ) { + try { + $claim = $this->store->stake_claim( $size, null, [], $this->group ); + $this->monitor->attach( $claim ); + $processed_actions = 0; + + foreach ( $claim->get_actions() as $action_id ) { + // bail if we lost the claim. + if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ), true ) ) { + break; + } + $this->process_action( $action_id, $context ); + ++$processed_actions; + + if ( $this->batch_limits_exceeded( $processed_actions ) ) { + break; + } + } + $this->store->release_claim( $claim ); + $this->monitor->detach(); + $this->clear_caches(); + $this->reset_group(); + return $processed_actions; + } catch ( \Exception $exception ) { + Logger::debug( $exception->getMessage() ); + $this->reset_group(); + return 0; + } + } + + /** + * Reset group in store's claim filter. + * + * @return void + */ + private function reset_group() { + if ( ! method_exists( $this->store, 'set_claim_filter' ) ) { + return; + } + $this->store->set_claim_filter( 'group', '' ); + } + + /** + * Running large batches can eat up memory, as WP adds data to its object cache. + * + * If using a persistent object store, this has the side effect of flushing that + * as well, so this is disabled by default. To enable: + * + * add_filter( 'action_scheduler_queue_runner_flush_cache', '__return_true' ); + */ + protected function clear_caches() { + if ( ! wp_using_ext_object_cache() || apply_filters( 'action_scheduler_queue_runner_flush_cache', false ) ) {// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + wp_cache_flush(); + } + } + + /** + * Add the cron schedule. + * + * @param array $schedules Array of current schedules. + * + * @return array + */ + public function add_wp_cron_schedule( $schedules ) { + if ( isset( $schedules['every_minute'] ) ) { + return $schedules; + } + + $schedules['every_minute'] = [ + 'interval' => 60, // in seconds. + 'display' => __( 'Every minute', 'rocket' ), + ]; + + return $schedules; + } + + /** + * Get the number of concurrent batches a runner allows. + * + * @return int + */ + public function get_allowed_concurrent_batches() { + return 2; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Common/Utils.php b/wp-content/plugins/wp-rocket/inc/Engine/Common/Utils.php new file mode 100644 index 000000000..0992c8a9b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Common/Utils.php @@ -0,0 +1,31 @@ +<?php + +namespace WP_Rocket\Engine\Common; + +class Utils { + + /** + * Check if current page is the home page. + * + * @param string $url Current page url. + * + * @return bool + */ + public static function is_home( string $url ): bool { + /** + * Filters the home url. + * + * @since 3.11.4 + * + * @param string $home_url home url. + * @param string $url url of current page. + */ + $home_url = rocket_apply_filter_and_deprecated( + 'rocket_saas_is_home_url', + [ home_url(), $url ], + '3.16', + 'rocket_rucss_is_home_url' + ); + return untrailingslashit( $url ) === untrailingslashit( $home_url ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/ArgumentResolverInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/ArgumentResolverInterface.php deleted file mode 100644 index 4b1334060..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/ArgumentResolverInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Argument; - -use WP_Rocket\Engine\Container\ImmutableContainerAwareInterface; -use ReflectionFunctionAbstract; - -interface ArgumentResolverInterface extends ImmutableContainerAwareInterface -{ - /** - * Resolve an array of arguments to their concrete implementations. - * - * @param array $arguments - * @return array - */ - public function resolveArguments(array $arguments); - - /** - * Resolves the correct arguments to be passed to a method. - * - * @param \ReflectionFunctionAbstract $method - * @param array $args - * @return array - */ - public function reflectArguments(ReflectionFunctionAbstract $method, array $args = []); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/ArgumentResolverTrait.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/ArgumentResolverTrait.php deleted file mode 100644 index 3822da81e..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/ArgumentResolverTrait.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Argument; - -use WP_Rocket\Engine\Container\Exception\NotFoundException; -use WP_Rocket\Engine\Container\ReflectionContainer; -use ReflectionFunctionAbstract; -use ReflectionParameter; - -trait ArgumentResolverTrait -{ - /** - * {@inheritdoc} - */ - public function resolveArguments(array $arguments) - { - foreach ($arguments as &$arg) { - if ($arg instanceof RawArgumentInterface) { - $arg = $arg->getValue(); - continue; - } - - if (! is_string($arg)) { - continue; - } - - $container = $this->getContainer(); - - if (is_null($container) && $this instanceof ReflectionContainer) { - $container = $this; - } - - if (! is_null($container) && $container->has($arg)) { - $arg = $container->get($arg); - - if ($arg instanceof RawArgumentInterface) { - $arg = $arg->getValue(); - } - - continue; - } - } - - return $arguments; - } - - /** - * {@inheritdoc} - */ - public function reflectArguments(ReflectionFunctionAbstract $method, array $args = []) - { - $arguments = array_map(function (ReflectionParameter $param) use ($method, $args) { - $name = $param->getName(); - $class = $param->getClass(); - - if (array_key_exists($name, $args)) { - return $args[$name]; - } - - if (! is_null($class)) { - return $class->getName(); - } - - if ($param->isDefaultValueAvailable()) { - return $param->getDefaultValue(); - } - - throw new NotFoundException(sprintf( - 'Unable to resolve a value for parameter (%s) in the function/method (%s)', - $name, - $method->getName() - )); - }, $method->getParameters()); - - return $this->resolveArguments($arguments); - } - - /** - * @return \WP_Rocket\Engine\Container\ContainerInterface - */ - abstract public function getContainer(); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/RawArgument.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/RawArgument.php deleted file mode 100644 index 38da84932..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/RawArgument.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Argument; - -class RawArgument implements RawArgumentInterface -{ - /** - * @var mixed - */ - protected $value; - - /** - * {@inheritdoc} - */ - public function __construct($value) - { - $this->value = $value; - } - - /** - * {@inheritdoc} - */ - public function getValue() - { - return $this->value; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/RawArgumentInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/RawArgumentInterface.php deleted file mode 100644 index 6ca53ecb6..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Argument/RawArgumentInterface.php +++ /dev/null @@ -1,13 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Argument; - -interface RawArgumentInterface -{ - /** - * Return the value of the raw argument. - * - * @return mixed - */ - public function getValue(); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Container.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Container.php deleted file mode 100644 index ed954f56b..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Container.php +++ /dev/null @@ -1,305 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container; - -use Psr\Container\ContainerInterface as InteropContainerInterface; -use WP_Rocket\Engine\Container\Argument\RawArgumentInterface; -use WP_Rocket\Engine\Container\Definition\DefinitionFactory; -use WP_Rocket\Engine\Container\Definition\DefinitionFactoryInterface; -use WP_Rocket\Engine\Container\Definition\DefinitionInterface; -use WP_Rocket\Engine\Container\Exception\NotFoundException; -use WP_Rocket\Engine\Container\Inflector\InflectorAggregate; -use WP_Rocket\Engine\Container\Inflector\InflectorAggregateInterface; -use WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderAggregate; -use WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderAggregateInterface; - -class Container implements ContainerInterface -{ - /** - * @var \WP_Rocket\Engine\Container\Definition\DefinitionFactoryInterface - */ - protected $definitionFactory; - - /** - * @var \WP_Rocket\Engine\Container\Definition\DefinitionInterface[] - */ - protected $definitions = []; - - /** - * @var \WP_Rocket\Engine\Container\Definition\DefinitionInterface[] - */ - protected $sharedDefinitions = []; - - /** - * @var \WP_Rocket\Engine\Container\Inflector\InflectorAggregateInterface - */ - protected $inflectors; - - /** - * @var \WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderAggregateInterface - */ - protected $providers; - - /** - * @var array - */ - protected $shared = []; - - /** - * @var \Psr\Container\ContainerInterface[] - */ - protected $delegates = []; - - /** - * Constructor. - * - * @param \WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderAggregateInterface|null $providers - * @param \WP_Rocket\Engine\Container\Inflector\InflectorAggregateInterface|null $inflectors - * @param \WP_Rocket\Engine\Container\Definition\DefinitionFactoryInterface|null $definitionFactory - */ - public function __construct( - ServiceProviderAggregateInterface $providers = null, - InflectorAggregateInterface $inflectors = null, - DefinitionFactoryInterface $definitionFactory = null - ) { - // set required dependencies - $this->providers = (is_null($providers)) - ? (new ServiceProviderAggregate)->setContainer($this) - : $providers->setContainer($this); - - $this->inflectors = (is_null($inflectors)) - ? (new InflectorAggregate)->setContainer($this) - : $inflectors->setContainer($this); - - $this->definitionFactory = (is_null($definitionFactory)) - ? (new DefinitionFactory)->setContainer($this) - : $definitionFactory->setContainer($this); - } - - /** - * {@inheritdoc} - */ - public function get($alias, array $args = []) - { - try { - return $this->getFromThisContainer($alias, $args); - } catch (NotFoundException $exception) { - if ($this->providers->provides($alias)) { - $this->providers->register($alias); - - return $this->getFromThisContainer($alias, $args); - } - - $resolved = $this->getFromDelegate($alias, $args); - - return $this->inflectors->inflect($resolved); - } - } - - /** - * {@inheritdoc} - */ - public function has($alias) - { - if (array_key_exists($alias, $this->definitions) || $this->hasShared($alias)) { - return true; - } - - if ($this->providers->provides($alias)) { - return true; - } - - return $this->hasInDelegate($alias); - } - - /** - * Returns a boolean to determine if the container has a shared instance of an alias. - * - * @param string $alias - * @param boolean $resolved - * @return boolean - */ - public function hasShared($alias, $resolved = false) - { - $shared = ($resolved === false) ? array_merge($this->shared, $this->sharedDefinitions) : $this->shared; - - return (array_key_exists($alias, $shared)); - } - - /** - * {@inheritdoc} - */ - public function add($alias, $concrete = null, $share = false) - { - unset($this->shared[$alias]); - unset($this->definitions[$alias]); - unset($this->sharedDefinitions[$alias]); - - if (is_null($concrete)) { - $concrete = $alias; - } - - $definition = $this->definitionFactory->getDefinition($alias, $concrete); - - if ($definition instanceof DefinitionInterface) { - if ($share === false) { - $this->definitions[$alias] = $definition; - } else { - $this->sharedDefinitions[$alias] = $definition; - } - - return $definition; - } - - // dealing with a value that cannot build a definition - $this->shared[$alias] = $concrete; - } - - /** - * {@inheritdoc} - */ - public function share($alias, $concrete = null) - { - return $this->add($alias, $concrete, true); - } - - /** - * {@inheritdoc} - */ - public function addServiceProvider($provider) - { - $this->providers->add($provider); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function extend($alias) - { - if ($this->providers->provides($alias)) { - $this->providers->register($alias); - } - - if (array_key_exists($alias, $this->definitions)) { - return $this->definitions[$alias]; - } - - if (array_key_exists($alias, $this->sharedDefinitions)) { - return $this->sharedDefinitions[$alias]; - } - - throw new NotFoundException( - sprintf('Unable to extend alias (%s) as it is not being managed as a definition', $alias) - ); - } - - /** - * {@inheritdoc} - */ - public function inflector($type, callable $callback = null) - { - return $this->inflectors->add($type, $callback); - } - - /** - * {@inheritdoc} - */ - public function call(callable $callable, array $args = []) - { - return (new ReflectionContainer)->setContainer($this)->call($callable, $args); - } - - /** - * Delegate a backup container to be checked for services if it - * cannot be resolved via this container. - * - * @param \Psr\Container\ContainerInterface $container - * @return $this - */ - public function delegate(InteropContainerInterface $container) - { - $this->delegates[] = $container; - - if ($container instanceof ImmutableContainerAwareInterface) { - $container->setContainer($this); - } - - return $this; - } - - /** - * Returns true if service is registered in one of the delegated backup containers. - * - * @param string $alias - * @return boolean - */ - public function hasInDelegate($alias) - { - foreach ($this->delegates as $container) { - if ($container->has($alias)) { - return true; - } - } - - return false; - } - - /** - * Attempt to get a service from the stack of delegated backup containers. - * - * @param string $alias - * @param array $args - * @return mixed - */ - protected function getFromDelegate($alias, array $args = []) - { - foreach ($this->delegates as $container) { - if ($container->has($alias)) { - return $container->get($alias, $args); - } - - continue; - } - - throw new NotFoundException( - sprintf('Alias (%s) is not being managed by the container', $alias) - ); - - } - - /** - * Get a service that has been registered in this container. - * - * @param string $alias - * @param array $args - * @return mixed - */ - protected function getFromThisContainer($alias, array $args = []) - { - if ($this->hasShared($alias, true)) { - $shared = $this->inflectors->inflect($this->shared[$alias]); - if ($shared instanceof RawArgumentInterface) { - return $shared->getValue(); - } - return $shared; - } - - if (array_key_exists($alias, $this->sharedDefinitions)) { - $shared = $this->inflectors->inflect($this->sharedDefinitions[$alias]->build()); - $this->shared[$alias] = $shared; - return $shared; - } - - if (array_key_exists($alias, $this->definitions)) { - return $this->inflectors->inflect( - $this->definitions[$alias]->build($args) - ); - } - - throw new NotFoundException( - sprintf('Alias (%s) is not being managed by the container', $alias) - ); - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerAwareInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerAwareInterface.php deleted file mode 100644 index 74c78a3ff..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerAwareInterface.php +++ /dev/null @@ -1,20 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container; - -interface ContainerAwareInterface -{ - /** - * Set a container - * - * @param \WP_Rocket\Engine\Container\ContainerInterface $container - */ - public function setContainer(ContainerInterface $container); - - /** - * Get the container - * - * @return \WP_Rocket\Engine\Container\ContainerInterface - */ - public function getContainer(); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerAwareTrait.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerAwareTrait.php deleted file mode 100644 index 0cb76e021..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerAwareTrait.php +++ /dev/null @@ -1,34 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container; - -trait ContainerAwareTrait -{ - /** - * @var \WP_Rocket\Engine\Container\ContainerInterface - */ - protected $container; - - /** - * Set a container. - * - * @param \WP_Rocket\Engine\Container\ContainerInterface $container - * @return $this - */ - public function setContainer(ContainerInterface $container) - { - $this->container = $container; - - return $this; - } - - /** - * Get the container. - * - * @return \WP_Rocket\Engine\Container\ContainerInterface - */ - public function getContainer() - { - return $this->container; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerInterface.php deleted file mode 100644 index 19b95b9a4..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ContainerInterface.php +++ /dev/null @@ -1,59 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container; - -interface ContainerInterface extends ImmutableContainerInterface -{ - /** - * Add an item to the container. - * - * @param string $alias - * @param mixed|null $concrete - * @param boolean $share - * @return \WP_Rocket\Engine\Container\Definition\DefinitionInterface - */ - public function add($alias, $concrete = null, $share = false); - - /** - * Convenience method to add an item to the container as a shared item. - * - * @param string $alias - * @param mixed|null $concrete - * @return \WP_Rocket\Engine\Container\Definition\DefinitionInterface - */ - public function share($alias, $concrete = null); - - /** - * Add a service provider to the container. - * - * @param string|\WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderInterface $provider - * @return void - */ - public function addServiceProvider($provider); - - /** - * Returns a definition of an item to be extended. - * - * @param string $alias - * @return \WP_Rocket\Engine\Container\Definition\DefinitionInterface - */ - public function extend($alias); - - /** - * Allows for manipulation of specific types on resolution. - * - * @param string $type - * @param callable|null $callback - * @return \WP_Rocket\Engine\Container\Inflector\Inflector|void - */ - public function inflector($type, callable $callback = null); - - /** - * Invoke a callable via the container. - * - * @param callable $callable - * @param array $args - * @return mixed - */ - public function call(callable $callable, array $args = []); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/AbstractDefinition.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/AbstractDefinition.php deleted file mode 100644 index 2208b1cd7..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/AbstractDefinition.php +++ /dev/null @@ -1,62 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Definition; - -use WP_Rocket\Engine\Container\Argument\ArgumentResolverInterface; -use WP_Rocket\Engine\Container\Argument\ArgumentResolverTrait; -use WP_Rocket\Engine\Container\ImmutableContainerAwareTrait; - -abstract class AbstractDefinition implements ArgumentResolverInterface, DefinitionInterface -{ - use ArgumentResolverTrait; - use ImmutableContainerAwareTrait; - - /** - * @var string - */ - protected $alias; - - /** - * @var mixed - */ - protected $concrete; - - /** - * @var array - */ - protected $arguments = []; - - /** - * Constructor. - * - * @param string $alias - * @param mixed $concrete - */ - public function __construct($alias, $concrete) - { - $this->alias = $alias; - $this->concrete = $concrete; - } - - /** - * {@inheritdoc} - */ - public function withArgument($arg) - { - $this->arguments[] = $arg; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function withArguments(array $args) - { - foreach ($args as $arg) { - $this->withArgument($arg); - } - - return $this; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/CallableDefinition.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/CallableDefinition.php deleted file mode 100644 index 7d7c898d2..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/CallableDefinition.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Definition; - -class CallableDefinition extends AbstractDefinition -{ - /** - * {@inheritdoc} - */ - public function build(array $args = []) - { - $args = (empty($args)) ? $this->arguments : $args; - $resolved = $this->resolveArguments($args); - - if (is_array($this->concrete) && is_string($this->concrete[0])) { - $this->concrete[0] = ($this->getContainer()->has($this->concrete[0])) - ? $this->getContainer()->get($this->concrete[0]) - : $this->concrete[0]; - } - - return call_user_func_array($this->concrete, $resolved); - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/ClassDefinition.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/ClassDefinition.php deleted file mode 100644 index 3c2559b89..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/ClassDefinition.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Definition; - -use ReflectionClass; - -class ClassDefinition extends AbstractDefinition implements ClassDefinitionInterface -{ - /** - * @var array - */ - protected $methods = []; - - /** - * {@inheritdoc} - */ - public function withMethodCall($method, array $args = []) - { - $this->methods[] = [ - 'method' => $method, - 'arguments' => $args - ]; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function withMethodCalls(array $methods = []) - { - foreach ($methods as $method => $args) { - $this->withMethodCall($method, $args); - } - - return $this; - } - - /** - * {@inheritdoc} - */ - public function build(array $args = []) - { - $args = (empty($args)) ? $this->arguments : $args; - $resolved = $this->resolveArguments($args); - $reflection = new ReflectionClass($this->concrete); - $instance = $reflection->newInstanceArgs($resolved); - - return $this->invokeMethods($instance); - } - - /** - * Invoke methods on resolved instance. - * - * @param object $instance - * @return object - */ - protected function invokeMethods($instance) - { - foreach ($this->methods as $method) { - $args = $this->resolveArguments($method['arguments']); - call_user_func_array([$instance, $method['method']], $args); - } - - return $instance; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/ClassDefinitionInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/ClassDefinitionInterface.php deleted file mode 100644 index 8273daed0..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/ClassDefinitionInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Definition; - -interface ClassDefinitionInterface extends DefinitionInterface -{ - /** - * Add a method to be invoked - * - * @param string $method - * @param array $args - * @return $this - */ - public function withMethodCall($method, array $args = []); - - /** - * Add multiple methods to be invoked - * - * @param array $methods - * @return $this - */ - public function withMethodCalls(array $methods = []); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionFactory.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionFactory.php deleted file mode 100644 index 02e92c1e5..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionFactory.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Definition; - -use WP_Rocket\Engine\Container\ImmutableContainerAwareTrait; - -class DefinitionFactory implements DefinitionFactoryInterface -{ - use ImmutableContainerAwareTrait; - - /** - * {@inheritdoc} - */ - public function getDefinition($alias, $concrete) - { - if (is_callable($concrete)) { - return (new CallableDefinition($alias, $concrete))->setContainer($this->getContainer()); - } - - if (is_string($concrete) && class_exists($concrete)) { - return (new ClassDefinition($alias, $concrete))->setContainer($this->getContainer()); - } - - // if the item is not definable we just return the value to be stored - // in the container as an arbitrary value/instance - return $concrete; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionFactoryInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionFactoryInterface.php deleted file mode 100644 index a9bd63e87..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionFactoryInterface.php +++ /dev/null @@ -1,17 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Definition; - -use WP_Rocket\Engine\Container\ImmutableContainerAwareInterface; - -interface DefinitionFactoryInterface extends ImmutableContainerAwareInterface -{ - /** - * Return a definition based on type of concrete. - * - * @param string $alias - * @param mixed $concrete - * @return mixed - */ - public function getDefinition($alias, $concrete); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionInterface.php deleted file mode 100644 index c1a8a8c52..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Definition/DefinitionInterface.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Definition; - -interface DefinitionInterface -{ - /** - * Handle instantiation and manipulation of value and return. - * - * @param array $args - * @return mixed - */ - public function build(array $args = []); - - /** - * Add an argument to be injected. - * - * @param mixed $arg - * @return $this - */ - public function withArgument($arg); - - /** - * Add multiple arguments to be injected. - * - * @param array $args - * @return $this - */ - public function withArguments(array $args); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Exception/NotFoundException.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Exception/NotFoundException.php deleted file mode 100644 index 90d530277..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Exception/NotFoundException.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Exception; - -use Psr\Container\NotFoundExceptionInterface; -use InvalidArgumentException; - -class NotFoundException extends InvalidArgumentException implements NotFoundExceptionInterface -{ -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerAwareInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerAwareInterface.php deleted file mode 100644 index 45e6be233..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerAwareInterface.php +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container; - -use Psr\Container\ContainerInterface as InteropContainerInterface; - -interface ImmutableContainerAwareInterface -{ - /** - * Set a container - * - * @param \Psr\Container\ContainerInterface $container - */ - public function setContainer(InteropContainerInterface $container); - - /** - * Get the container - * - * @return \WP_Rocket\Engine\Container\ImmutableContainerInterface - */ - public function getContainer(); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerAwareTrait.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerAwareTrait.php deleted file mode 100644 index 2821d7884..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerAwareTrait.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container; - -use Psr\Container\ContainerInterface as InteropContainerInterface; - -trait ImmutableContainerAwareTrait -{ - /** - * @var \Psr\Container\ContainerInterface - */ - protected $container; - - /** - * Set a container. - * - * @param \Psr\Container\ContainerInterface $container - * @return $this - */ - public function setContainer(InteropContainerInterface $container) - { - $this->container = $container; - - return $this; - } - - /** - * Get the container. - * - * @return \WP_Rocket\Engine\Container\ImmutableContainerInterface - */ - public function getContainer() - { - return $this->container; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerInterface.php deleted file mode 100644 index 9dc936573..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ImmutableContainerInterface.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container; - -use Psr\Container\ContainerInterface as InteropContainerInterface; - -interface ImmutableContainerInterface extends InteropContainerInterface -{ - -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/Inflector.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/Inflector.php deleted file mode 100644 index 5c2d75aa3..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/Inflector.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Inflector; - -use WP_Rocket\Engine\Container\ImmutableContainerAwareTrait; -use WP_Rocket\Engine\Container\Argument\ArgumentResolverInterface; -use WP_Rocket\Engine\Container\Argument\ArgumentResolverTrait; - -class Inflector implements ArgumentResolverInterface -{ - use ArgumentResolverTrait; - use ImmutableContainerAwareTrait; - - /** - * @var array - */ - protected $methods = []; - - /** - * @var array - */ - protected $properties = []; - - /** - * Defines a method to be invoked on the subject object. - * - * @param string $name - * @param array $args - * @return $this - */ - public function invokeMethod($name, array $args) - { - $this->methods[$name] = $args; - - return $this; - } - - /** - * Defines multiple methods to be invoked on the subject object. - * - * @param array $methods - * @return $this - */ - public function invokeMethods(array $methods) - { - foreach ($methods as $name => $args) { - $this->invokeMethod($name, $args); - } - - return $this; - } - - /** - * Defines a property to be set on the subject object. - * - * @param string $property - * @param mixed $value - * @return $this - */ - public function setProperty($property, $value) - { - $this->properties[$property] = $value; - - return $this; - } - - /** - * Defines multiple properties to be set on the subject object. - * - * @param array $properties - * @return $this - */ - public function setProperties(array $properties) - { - foreach ($properties as $property => $value) { - $this->setProperty($property, $value); - } - - return $this; - } - - /** - * Apply inflections to an object. - * - * @param object $object - * @return void - */ - public function inflect($object) - { - $properties = $this->resolveArguments(array_values($this->properties)); - $properties = array_combine(array_keys($this->properties), $properties); - - foreach ($properties as $property => $value) { - $object->{$property} = $value; - } - - foreach ($this->methods as $method => $args) { - $args = $this->resolveArguments($args); - - call_user_func_array([$object, $method], $args); - } - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/InflectorAggregate.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/InflectorAggregate.php deleted file mode 100644 index d8d2abeee..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/InflectorAggregate.php +++ /dev/null @@ -1,53 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Inflector; - -use WP_Rocket\Engine\Container\ImmutableContainerAwareTrait; - -class InflectorAggregate implements InflectorAggregateInterface -{ - use ImmutableContainerAwareTrait; - - /** - * @var array - */ - protected $inflectors = []; - - /** - * {@inheritdoc} - */ - public function add($type, callable $callback = null) - { - if (is_null($callback)) { - $inflector = new Inflector; - $this->inflectors[$type] = $inflector; - - return $inflector; - } - - $this->inflectors[$type] = $callback; - } - - /** - * {@inheritdoc} - */ - public function inflect($object) - { - foreach ($this->inflectors as $type => $inflector) { - if (! $object instanceof $type) { - continue; - } - - if ($inflector instanceof Inflector) { - $inflector->setContainer($this->getContainer()); - $inflector->inflect($object); - continue; - } - - // must be dealing with a callable as the inflector - call_user_func_array($inflector, [$object]); - } - - return $object; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/InflectorAggregateInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/InflectorAggregateInterface.php deleted file mode 100644 index 2b5e30352..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/Inflector/InflectorAggregateInterface.php +++ /dev/null @@ -1,25 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\Inflector; - -use WP_Rocket\Engine\Container\ImmutableContainerAwareInterface; - -interface InflectorAggregateInterface extends ImmutableContainerAwareInterface -{ - /** - * Add an inflector to the aggregate. - * - * @param string $type - * @param callable $callback - * @return \WP_Rocket\Engine\Container\Inflector\Inflector - */ - public function add($type, callable $callback = null); - - /** - * Applies all inflectors to an object. - * - * @param object $object - * @return object - */ - public function inflect($object); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ReflectionContainer.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ReflectionContainer.php deleted file mode 100644 index d7604c451..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ReflectionContainer.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container; - -use WP_Rocket\Engine\Container\Argument\ArgumentResolverInterface; -use WP_Rocket\Engine\Container\Argument\ArgumentResolverTrait; -use WP_Rocket\Engine\Container\Exception\NotFoundException; -use ReflectionClass; -use ReflectionFunction; -use ReflectionMethod; - -class ReflectionContainer implements - ArgumentResolverInterface, - ImmutableContainerInterface -{ - use ArgumentResolverTrait; - use ImmutableContainerAwareTrait; - - /** - * {@inheritdoc} - */ - public function get($alias, array $args = []) - { - if (! $this->has($alias)) { - throw new NotFoundException( - sprintf('Alias (%s) is not an existing class and therefore cannot be resolved', $alias) - ); - } - - $reflector = new ReflectionClass($alias); - $construct = $reflector->getConstructor(); - - if ($construct === null) { - return new $alias; - } - - return $reflector->newInstanceArgs( - $this->reflectArguments($construct, $args) - ); - } - - /** - * {@inheritdoc} - */ - public function has($alias) - { - return class_exists($alias); - } - - /** - * Invoke a callable via the container. - * - * @param callable $callable - * @param array $args - * @return mixed - */ - public function call(callable $callable, array $args = []) - { - if (is_string($callable) && strpos($callable, '::') !== false) { - $callable = explode('::', $callable); - } - - if (is_array($callable)) { - if (is_string($callable[0])) { - $callable[0] = $this->getContainer()->get($callable[0]); - } - - $reflection = new ReflectionMethod($callable[0], $callable[1]); - - if ($reflection->isStatic()) { - $callable[0] = null; - } - - return $reflection->invokeArgs($callable[0], $this->reflectArguments($reflection, $args)); - } - - if (is_object($callable)) { - $reflection = new ReflectionMethod($callable, '__invoke'); - - return $reflection->invokeArgs($callable, $this->reflectArguments($reflection, $args)); - } - - $reflection = new ReflectionFunction($callable); - - return $reflection->invokeArgs($this->reflectArguments($reflection, $args)); - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/AbstractServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/AbstractServiceProvider.php deleted file mode 100644 index 6bd7fc51f..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/AbstractServiceProvider.php +++ /dev/null @@ -1,27 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\ServiceProvider; - -use WP_Rocket\Engine\Container\ContainerAwareTrait; - -abstract class AbstractServiceProvider implements ServiceProviderInterface -{ - use ContainerAwareTrait; - - /** - * @var array - */ - protected $provides = []; - - /** - * {@inheritdoc} - */ - public function provides($alias = null) - { - if (! is_null($alias)) { - return (in_array($alias, $this->provides)); - } - - return $this->provides; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/AbstractSignatureServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/AbstractSignatureServiceProvider.php deleted file mode 100644 index 84b54255e..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/AbstractSignatureServiceProvider.php +++ /dev/null @@ -1,31 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\ServiceProvider; - -abstract class AbstractSignatureServiceProvider - extends AbstractServiceProvider - implements SignatureServiceProviderInterface -{ - /** - * @var string - */ - protected $signature; - - /** - * {@inheritdoc} - */ - public function withSignature($signature) - { - $this->signature = $signature; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getSignature() - { - return (is_null($this->signature)) ? get_class($this) : $this->signature; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderAggregate.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderAggregate.php deleted file mode 100644 index 0f3670a10..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderAggregate.php +++ /dev/null @@ -1,88 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\ServiceProvider; - -use WP_Rocket\Engine\Container\ContainerAwareInterface; -use WP_Rocket\Engine\Container\ContainerAwareTrait; - -class ServiceProviderAggregate implements ServiceProviderAggregateInterface -{ - use ContainerAwareTrait; - - /** - * @var array - */ - protected $providers = []; - - /** - * @var array - */ - protected $registered = []; - - /** - * {@inheritdoc} - */ - public function add($provider) - { - if (is_string($provider) && class_exists($provider)) { - $provider = new $provider; - } - - if ($provider instanceof ContainerAwareInterface) { - $provider->setContainer($this->getContainer()); - } - - if ($provider instanceof BootableServiceProviderInterface) { - $provider->boot(); - } - - if ($provider instanceof ServiceProviderInterface) { - foreach ($provider->provides() as $service) { - $this->providers[$service] = $provider; - } - - return $this; - } - - throw new \InvalidArgumentException( - 'A service provider must be a fully qualified class name or instance ' . - 'of (\WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderInterface)' - ); - } - - /** - * {@inheritdoc} - */ - public function provides($service) - { - return array_key_exists($service, $this->providers); - } - - /** - * {@inheritdoc} - */ - public function register($service) - { - if (! array_key_exists($service, $this->providers)) { - throw new \InvalidArgumentException( - sprintf('(%s) is not provided by a service provider', $service) - ); - } - - $provider = $this->providers[$service]; - $signature = get_class($provider); - - if ($provider instanceof SignatureServiceProviderInterface) { - $signature = $provider->getSignature(); - } - - // ensure that the provider hasn't already been invoked by any other service request - if (in_array($signature, $this->registered)) { - return; - } - - $provider->register(); - - $this->registered[] = $signature; - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderAggregateInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderAggregateInterface.php deleted file mode 100644 index 41559ca9f..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderAggregateInterface.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\ServiceProvider; - -use WP_Rocket\Engine\Container\ContainerAwareInterface; - -interface ServiceProviderAggregateInterface extends ContainerAwareInterface -{ - /** - * Add a service provider to the aggregate. - * - * @param string|\WP_Rocket\Engine\Container\ServiceProvider\ServiceProviderInterface $provider - * @return $this - */ - public function add($provider); - - /** - * Determines whether a service is provided by the aggregate. - * - * @param string $service - * @return boolean - */ - public function provides($service); - - /** - * Invokes the register method of a provider that provides a specific service. - * - * @param string $service - * @return void - */ - public function register($service); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderInterface.php deleted file mode 100644 index d85d0ad04..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/ServiceProviderInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\ServiceProvider; - -use WP_Rocket\Engine\Container\ContainerAwareInterface; - -interface ServiceProviderInterface extends ContainerAwareInterface -{ - /** - * Returns a boolean if checking whether this provider provides a specific - * service or returns an array of provided services if no argument passed. - * - * @param string $service - * @return boolean|array - */ - public function provides($service = null); - - /** - * Use the register method to register items with the container via the - * protected $this->container property or the `getContainer` method - * from the ContainerAwareTrait. - * - * @return void - */ - public function register(); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/SignatureServiceProviderInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/SignatureServiceProviderInterface.php deleted file mode 100644 index 33a562881..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Container/ServiceProvider/SignatureServiceProviderInterface.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php - -namespace WP_Rocket\Engine\Container\ServiceProvider; - -interface SignatureServiceProviderInterface -{ - /** - * Set a custom signature for the service provider. This enables - * registering the same service provider multiple times. - * - * @param string $signature - * @return self - */ - public function withSignature($signature); - - /** - * The signature of the service provider uniquely identifies it, so - * that we can quickly determine if it has already been registered. - * Defaults to get_class($provider). - * - * @return string - */ - public function getSignature(); -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/APIClient.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/APIClient.php index 4c38f3038..ec285aa10 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/APIClient.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/APIClient.php @@ -20,7 +20,7 @@ class APIClient { * @param string $url The URL to send a CPCSS generation request for. * @param array $params Optional. Parameters needed to be sent in the body. Default: []. * @param string $item_type Optional. Type for this item if it's custom or specific type. Default: custom. - * @return array + * @return array|WP_Error */ public function send_generation_request( $url, $params = [], $item_type = 'custom' ) { $params['url'] = $url; @@ -230,7 +230,7 @@ private function get_response_data( $response ) { * * @return string response code. */ - private function get_response_code( $response ) { + private function get_response_code( $response ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found // Todo: we can return code based on the response status number, for example 404 not_found. return 'cpcss_generation_failed'; } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Admin.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Admin.php index 98fc7f828..15bb26502 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Admin.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Admin.php @@ -104,7 +104,7 @@ private function process_cpcss_pending_queue( array $cpcss_pending ) { ); // Increment this item's threshold count. - $cpcss_pending[ $cpcss_item['path'] ]['check']++; + ++$cpcss_pending[ $cpcss_item['path'] ]['check']; $this->cpcss_heartbeat_notices( $cpcss_generation, $cpcss_item ); @@ -129,8 +129,8 @@ private function process_cpcss_pending_queue( array $cpcss_pending ) { * * @since 3.6 * - * @param array|WP_Error $cpcss_generation CPCSS regeneration reply. - * @param array $cpcss_item Item processed. + * @param array|\WP_Error $cpcss_generation CPCSS regeneration reply. + * @param array $cpcss_item Item processed. */ private function cpcss_heartbeat_notices( $cpcss_generation, $cpcss_item ) { $mobile = isset( $cpcss_item['mobile'] ) ? $cpcss_item['mobile'] : 0; @@ -228,6 +228,10 @@ public function enqueue_admin_cpcss_heartbeat_script() { * @return void */ public function add_regenerate_menu_item( $wp_admin_bar ) { + if ( 'local' === wp_get_environment_type() ) { + return; + } + if ( ! current_user_can( 'rocket_regenerate_critical_css' ) ) { return; } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Post.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Post.php index 10c9d15f4..3c95c64f7 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Post.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Post.php @@ -59,6 +59,10 @@ public function __construct( Options_Data $options, Beacon $beacon, $critical_pa * @return void */ public function cpcss_section() { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + $data = [ 'disabled_description' => $this->get_disabled_description(), ]; @@ -74,6 +78,10 @@ public function cpcss_section() { * @return void */ public function cpcss_actions() { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + $data = [ 'disabled' => $this->is_enabled(), 'beacon' => $this->beacon->get_suggest( 'async' ), @@ -99,6 +107,10 @@ public function cpcss_actions() { public function enqueue_admin_edit_script( $page ) { global $post, $pagenow; + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + // Bailout if the page is not Post / Page. if ( ! in_array( $page, [ 'edit.php', 'post.php' ], true ) ) { return; @@ -166,6 +178,10 @@ private function get_disabled_data() { $this->disabled_data['option_excluded'] = 1; } + if ( ! is_post_type_viewable( get_post_type( $post ) ) ) { + $this->disabled_data['not_viewable'] = 1; + } + return $this->disabled_data; } @@ -196,12 +212,16 @@ private function get_disabled_description() { return ''; } + if ( isset( $disabled_data['not_viewable'] ) ) { + return __( 'This feature is not available for non-public post types.', 'rocket' ); + } + $notice = __( '%l to use this feature.', 'rocket' ); $list = [ // translators: %s = post type. 'not_published' => sprintf( __( 'Publish the %s', 'rocket' ), $post->post_type ), - 'option_disabled' => __( 'Enable Optimize CSS delivery in WP Rocket settings', 'rocket' ), - 'option_excluded' => __( 'Enable Optimize CSS delivery in the options above', 'rocket' ), + 'option_disabled' => __( 'Enable Load CSS asynchronously in WP Rocket settings', 'rocket' ), + 'option_excluded' => __( 'Enable Load CSS asynchronously in the options above', 'rocket' ), ]; return wp_sprintf_l( $notice, array_intersect_key( $list, $disabled_data ) ); diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Subscriber.php index a9a5139c9..129697f63 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/Admin/Subscriber.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\CriticalPath\Admin; @@ -59,6 +60,7 @@ public static function get_subscribed_events() { [ 'enqueue_admin_cpcss_heartbeat_script' ], ], 'rocket_admin_bar_items' => 'add_regenerate_menu_item', + 'rocket_meta_boxes_fields' => [ 'add_meta_box', 3 ], ]; } @@ -186,4 +188,17 @@ public function enqueue_admin_cpcss_heartbeat_script() { public function add_regenerate_menu_item( $wp_admin_bar ) { $this->admin->add_regenerate_menu_item( $wp_admin_bar ); } + + /** + * Add the field to the WP Rocket metabox on the post edit page. + * + * @param string[] $fields Metaboxes fields. + * + * @return string[] + */ + public function add_meta_box( array $fields ) { + $fields['async_css'] = __( 'Load CSS asynchronously', 'rocket' ); + + return $fields; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/CriticalCSS.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/CriticalCSS.php index 908a1f77e..17c4fb273 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/CriticalCSS.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/CriticalCSS.php @@ -6,6 +6,7 @@ use UnexpectedValueException; use WP_Filesystem_Direct; use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Optimization\ContentTrait; /** * Handles the critical CSS generation process. @@ -13,6 +14,8 @@ * @since 2.11 */ class CriticalCSS { + use ContentTrait; + /** * Background Process instance. * @@ -82,12 +85,14 @@ public function get_critical_css_path() { /** * Performs the critical CSS generation. * + * @since 3.13.2 Always clear all CPCSS files. * @since 3.6 Added the $version parameter. * @since 2.11 * * @param string $version Optional. Version of the CPCSS files to generate. Possible values: default, mobile, all. + * @param string $clean_version Optional: Version of the CPCSS files to clean. Possible values: default, mobile, all. */ - public function process_handler( $version = 'default' ) { + public function process_handler( $version = 'default', $clean_version = '' ) { /** * Filters the critical CSS generation process. * @@ -105,7 +110,11 @@ public function process_handler( $version = 'default' ) { return; } - $this->clean_critical_css( $version ); + if ( empty( $clean_version ) ) { + $clean_version = $version; + } + + $this->clean_critical_css( $clean_version ); $this->stop_generation(); @@ -195,121 +204,6 @@ private function get_critical_css_iterator() { } } - /** - * Gets all public post types. - * - * @since 2.11 - */ - private function get_public_post_types() { - global $wpdb; - - $post_types = get_post_types( - [ - 'public' => true, - 'publicly_queryable' => true, - ] - ); - - $post_types[] = 'page'; - - /** - * Filters the post types excluded from critical CSS generation. - * - * @since 2.11 - * - * @param array $excluded_post_types An array of post types names. - * - * @return array - */ - $excluded_post_types = (array) apply_filters( - 'rocket_cpcss_excluded_post_types', - [ - 'elementor_library', - 'oceanwp_library', - 'tbuilder_layout', - 'tbuilder_layout_part', - 'slider', - 'karma-slider', - 'tt-gallery', - 'xlwcty_thankyou', - 'fusion_template', - 'blocks', - 'jet-woo-builder', - 'fl-builder-template', - ] - ); - - $post_types = array_diff( $post_types, $excluded_post_types ); - $post_types = esc_sql( $post_types ); - $post_types = "'" . implode( "','", $post_types ) . "'"; - - return $wpdb->get_results( - "SELECT MAX(ID) as ID, post_type - FROM ( - SELECT ID, post_type - FROM $wpdb->posts - WHERE post_type IN ( $post_types ) - AND post_status = 'publish' - ORDER BY post_date DESC - ) AS posts - GROUP BY post_type" - ); - } - - /** - * Gets all public taxonomies. - * - * @since 2.11 - */ - private function get_public_taxonomies() { - global $wpdb; - - $taxonomies = get_taxonomies( - [ - 'public' => true, - 'publicly_queryable' => true, - ] - ); - - /** - * Filters the taxonomies excluded from critical CSS generation. - * - * @since 2.11 - * - * @param array $excluded_taxonomies An array of taxonomies names. - * - * @return array - */ - $excluded_taxonomies = (array) apply_filters( - 'rocket_cpcss_excluded_taxonomies', - [ - 'post_format', - 'product_shipping_class', - 'karma-slider-category', - 'truethemes-gallery-category', - 'coupon_campaign', - 'element_category', - 'mediamatic_wpfolder', - 'attachment_category', - ] - ); - - $taxonomies = array_diff( $taxonomies, $excluded_taxonomies ); - $taxonomies = esc_sql( $taxonomies ); - $taxonomies = "'" . implode( "','", $taxonomies ) . "'"; - - return $wpdb->get_results( - "SELECT MAX( term_id ) AS ID, taxonomy - FROM ( - SELECT term_id, taxonomy - FROM $wpdb->term_taxonomy - WHERE taxonomy IN ( $taxonomies ) - AND count > 0 - ) AS taxonomies - GROUP BY taxonomy" - ); - } - /** * Sets the items for which we generate critical CSS. * @@ -387,7 +281,7 @@ private function update_process_running_transient() { foreach ( $this->items as $item ) { if ( ! isset( $item['mobile'] ) ) { - $total ++; + ++$total; continue; } @@ -395,7 +289,7 @@ private function update_process_running_transient() { continue; } - $total ++; + ++$total; } $transient = [ diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/CriticalCSSSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/CriticalCSSSubscriber.php index d4bdc0dcb..52acd27ac 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/CriticalCSSSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/CriticalCSSSubscriber.php @@ -2,7 +2,10 @@ namespace WP_Rocket\Engine\CriticalPath; +use WP_Rocket\Admin\Options; use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\License\API\User; +use WP_Rocket\Engine\Optimization\RegexTrait; use WP_Rocket\Event_Management\Subscriber_Interface; use WP_Filesystem_Direct; @@ -12,6 +15,7 @@ * @since 3.3 */ class CriticalCSSSubscriber implements Subscriber_Interface { + use RegexTrait; /** * Instance of Critical CSS. @@ -27,6 +31,13 @@ class CriticalCSSSubscriber implements Subscriber_Interface { */ protected $options; + /** + * WordPress options. + * + * @var Options + */ + protected $options_api; + /** * Instance of the filesystem handler. * @@ -41,18 +52,29 @@ class CriticalCSSSubscriber implements Subscriber_Interface { */ private $cpcss_service; + /** + * User instance. + * + * @var User + */ + protected $user; + /** * Creates an instance of the Critical CSS Subscriber. * - * @param CriticalCSS $critical_css Critical CSS instance. + * @param CriticalCSS $critical_css Critical CSS instance. * @param ProcessorService $cpcss_service Has the logic for cpcss generation and deletion. - * @param Options_Data $options WP Rocket options. - * @param WP_Filesystem_Direct $filesystem Instance of the filesystem handler. + * @param Options_Data $options WP Rocket options. + * @param Options $options_api WordPress options. + * @param User $user User instance. + * @param WP_Filesystem_Direct $filesystem Instance of the filesystem handler. */ - public function __construct( CriticalCSS $critical_css, ProcessorService $cpcss_service, Options_Data $options, $filesystem ) { + public function __construct( CriticalCSS $critical_css, ProcessorService $cpcss_service, Options_Data $options, Options $options_api, User $user, $filesystem ) { $this->critical_css = $critical_css; $this->cpcss_service = $cpcss_service; $this->options = $options; + $this->options_api = $options_api; + $this->user = $user; $this->filesystem = $filesystem; } @@ -79,6 +101,7 @@ public static function get_subscribed_events() { [ 'critical_css_generation_running_notice' ], [ 'critical_css_generation_complete_notice' ], [ 'warning_critical_css_dir_permissions' ], + [ 'switch_to_rucss_notice', 9 ], ], 'wp_head' => [ 'insert_load_css', PHP_INT_MAX ], @@ -91,6 +114,9 @@ public static function get_subscribed_events() { 'switch_theme' => 'maybe_regenerate_cpcss', 'rocket_excluded_inline_js_content' => 'exclude_inline_js', 'before_delete_post' => 'delete_cpcss', + 'rocket_before_rollback' => [ 'stop_critical_css_generation', 9 ], + 'wp_rocket_upgrade' => [ 'stop_critical_css_generation', 9 ], + 'admin_post_switch_to_rucss' => 'switch_to_rucss', ]; // phpcs:enable WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned } @@ -138,6 +164,10 @@ public function notice_critical_css_generation_triggered() { return; } + if ( ! $this->options->get( 'async_css', 0 ) ) { + return; + } + if ( false === get_transient( 'rocket_critical_css_generation_triggered' ) ) { return; } @@ -300,10 +330,7 @@ public function stop_process_on_deactivation( $old_value, $value ) { && 0 === (int) $value['async_css'] ) { - $this->critical_css->stop_generation(); - - delete_transient( 'rocket_critical_css_generation_process_running' ); - delete_transient( 'rocket_critical_css_generation_process_complete' ); + $this->stop_critical_css_generation(); } } @@ -323,6 +350,10 @@ public function critical_css_generation_running_notice() { return; } + if ( ! $this->options->get( 'async_css', 0 ) ) { + return; + } + $transient = get_transient( 'rocket_critical_css_generation_process_running' ); if ( ! $transient ) { @@ -341,7 +372,7 @@ public function critical_css_generation_running_notice() { if ( $status_nonmobile && $status_mobile ) { $items_message .= '<li>' . $item['status']['nonmobile']['message'] . '</li>'; if ( $item['status']['nonmobile']['success'] ) { - $success_counter ++; + ++$success_counter; } } } @@ -392,6 +423,10 @@ public function critical_css_generation_complete_notice() { return; } + if ( ! $this->options->get( 'async_css', 0 ) ) { + return; + } + $transient = get_transient( 'rocket_critical_css_generation_process_complete' ); if ( ! $transient ) { return; @@ -416,7 +451,7 @@ public function critical_css_generation_complete_notice() { } $items_message .= '<li>' . $item['status']['nonmobile']['message'] . '</li>'; if ( $item['status']['nonmobile']['success'] ) { - $success_counter ++; + ++$success_counter; } } @@ -642,8 +677,12 @@ public function async_css( $buffer ) { '/(?=<link[^>]*\s(rel\s*=\s*[\'"]stylesheet["\']))<link[^>]*\shref\s*=\s*[\'"]([^\'"]+)[\'"](.*)>/iU' ); + // Remove comments from the buffer. + $clean_buffer = $this->hide_comments( $buffer ); + $clean_buffer = $this->hide_noscripts( $clean_buffer ); + // Get all css files with this regex. - preg_match_all( $css_pattern, $buffer, $tags_match ); + preg_match_all( $css_pattern, $clean_buffer, $tags_match ); if ( ! isset( $tags_match[0] ) ) { return $buffer; } @@ -659,8 +698,12 @@ public function async_css( $buffer ) { continue; } + if ( preg_match( '/media\s*=\s*[\'"]print[\'"]/i', $tags_match[0][ $i ] ) ) { + continue; + } + $preload = str_replace( 'stylesheet', 'preload', $tags_match[1][ $i ] ); - $onload = preg_replace( '~' . preg_quote( $tags_match[3][ $i ], '~' ) . '~iU', ' data-rocket-async="style" as="style" onload=""' . $tags_match[3][ $i ] . '>', $tags_match[3][ $i ] ); + $onload = preg_replace( '~' . preg_quote( $tags_match[3][ $i ], '~' ) . '~iU', ' data-rocket-async="style" as="style" onload="" onerror="this.removeAttribute(\'data-rocket-async\')" ' . $tags_match[3][ $i ] . '>', $tags_match[3][ $i ] ); $tag = str_replace( $tags_match[3][ $i ] . '>', $onload, $tag ); $tag = str_replace( $tags_match[1][ $i ], $preload, $tag ); $tag = str_replace( 'onload=""', 'onload="this.onload=null;this.rel=\'stylesheet\'"', $tag ); @@ -678,14 +721,19 @@ public function async_css( $buffer ) { /** * Regenerates the CPCSS when switching theme if the option is active. * - * @since 3.3 + * @since 3.3 */ public function maybe_regenerate_cpcss() { if ( ! $this->options->get( 'async_css' ) ) { return; } - $this->critical_css->process_handler(); + if ( ! $this->is_mobile_cpcss_active() ) { + $this->critical_css->process_handler( 'default', 'all' ); + return; + } + + $this->critical_css->process_handler( 'all' ); } /** @@ -725,4 +773,102 @@ private function should_async_css() { return ! is_rocket_post_excluded_option( 'async_css' ); } + + /** + * Stops the critical CSS generation. + * + * @since 3.10 + * + * @return void + */ + public function stop_critical_css_generation() { + + $this->critical_css->stop_generation(); + delete_transient( 'rocket_critical_css_generation_process_running' ); + delete_transient( 'rocket_critical_css_generation_process_complete' ); + } + + /** + * Display a notice to pass from CPCSS to RUCSS. + * + * @return void + */ + public function switch_to_rucss_notice() { + $boxes = get_user_meta( get_current_user_id(), 'rocket_boxes', true ); + + if ( in_array( __FUNCTION__, (array) $boxes, true ) ) { + return; + } + + if ( ! $this->options->get( 'async_css', 0 ) ) { + return; + } + + if ( $this->user->is_license_expired() ) { + return; + } + + $screen = get_current_screen(); + + if ( isset( $screen->id ) && 'settings_page_wprocket' !== $screen->id ) { + return; + } + + /** + * Filters the status of the RUCSS option. + * + * @param array $should_disable will return array with disable status and text. + */ + $rucss_status = apply_filters( + 'rocket_disable_rucss_setting', + [ + 'disable' => false, + 'text' => '', + ] + ); + + if ( is_array( $rucss_status ) && key_exists( 'disable', $rucss_status ) && $rucss_status['disable'] ) { + return; + } + + rocket_notice_html( + [ + 'status' => 'wpr-warning', + 'dismissible' => '', + 'dismiss_button' => __FUNCTION__, + 'message' => sprintf( + // translators: %1$ = opening bold tag, %2$ = closing bold tag. + __( 'We highly recommend the %1$supdated Remove Unused CSS%2$s for a better CSS optimization. Load CSS Asynchronously is always available as a back-up.', 'rocket' ), + '<b>', + '</b>' + ), + 'action' => 'switch_to_rucss', + 'dismiss_button_message' => __( 'Stay with the old option', 'rocket' ), + ] + ); + } + + /** + * Switch to RUCSS. + * + * @return void + */ + public function switch_to_rucss() { + check_admin_referer( 'rucss_switch' ); + + if ( ! current_user_can( 'rocket_manage_options' ) ) { + wp_safe_redirect( wp_get_referer() ); + rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ? wp_die() : exit; + return; // phpcs:ignore Squiz.PHP.NonExecutableCode.Unreachable + } + + $this->options->set( 'async_css', false ); + $this->options->set( 'remove_unused_css', true ); + $this->options_api->set( 'settings', $this->options->get_options() ); + + rocket_dismiss_box( 'switch_to_rucss_notice' ); + + wp_safe_redirect( wp_get_referer() ); + rocket_get_constant( 'WP_ROCKET_IS_TESTING', false ) ? wp_die() : exit; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/DataManager.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/DataManager.php index dd7ac5574..a53e098ba 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/DataManager.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/DataManager.php @@ -4,6 +4,7 @@ use WP_Error; use WP_Filesystem_Direct; +use WP_Rocket\Engine\Optimization\CSSTrait; /** * Class DataManager @@ -11,6 +12,7 @@ * @package WP_Rocket\Engine\CriticalPath */ class DataManager { + use CSSTrait; /** * Base critical CSS path for posts. @@ -63,10 +65,10 @@ public function save_cpcss( $path, $cpcss, $url, $is_mobile = false, $item_type $is_mobile ? // translators: %s = item URL. - __( 'Critical CSS for %1$s on mobile not generated. Error: The API returned an empty response.', 'rocket' ) + __( 'Critical CSS for %1$s on mobile not generated. Error: The destination folder could not be created.', 'rocket' ) : // translators: %s = item URL. - __( 'Critical CSS for %1$s not generated. Error: The API returned an empty response.', 'rocket' ), + __( 'Critical CSS for %1$s not generated. Error: The destination folder could not be created.', 'rocket' ), ( 'custom' === $item_type ) ? $url : $item_type ), [ @@ -77,6 +79,8 @@ public function save_cpcss( $path, $cpcss, $url, $is_mobile = false, $item_type } } + $cpcss = $this->apply_font_display_swap( $cpcss ); + return rocket_put_content( $this->critical_css_path . $path, wp_strip_all_tags( $cpcss, true ) diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/ProcessorService.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/ProcessorService.php index 2bdbb9276..fab7b7c5c 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/ProcessorService.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/ProcessorService.php @@ -81,7 +81,8 @@ public function process_generate( $item_url, $item_path, $additional_parameters private function send_generation_request( $item_url, $item_path, $is_mobile = false, $item_type = 'custom' ) { // call send generation request from APIClient for the first time. $params = [ - 'mobile' => (int) $is_mobile, + 'mobile' => (int) $is_mobile, + 'nofontface' => false, ]; $generated_job = $this->api_client->send_generation_request( $item_url, $params, $item_type ); @@ -162,6 +163,8 @@ private function check_cpcss_job_status( $job_id, $item_path, $item_url, $is_mob ) { return $this->on_job_success( $item_path, $item_url, $job_details->data->critical_path, $is_mobile, $item_type ); } + + return $this->on_job_error( $job_details, $item_url, $is_mobile, $item_type ); } /** @@ -334,5 +337,4 @@ private function process_timeout( $item_url, $is_mobile = false, $item_type = 'c ] ); } - } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTCSSSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTCSSSubscriber.php index 60bdd1c15..cd5ba9bb4 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTCSSSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTCSSSubscriber.php @@ -51,5 +51,4 @@ public function register_routes() { $this->rest_manager->register_generate_route(); $this->rest_manager->register_delete_route(); } - } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWP.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWP.php index 633426d6b..a5696c114 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWP.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWP.php @@ -176,7 +176,6 @@ public function generate( WP_REST_Request $request ) { return rest_ensure_response( $this->return_success( $generated ) ); - } /** @@ -318,5 +317,4 @@ protected function return_success( $data ) { 200 ); } - } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWPInterface.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWPInterface.php index c11c92eab..ce125ad40 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWPInterface.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWPInterface.php @@ -54,5 +54,4 @@ public function generate( WP_REST_Request $request ); * @return WP_REST_Response */ public function delete( WP_REST_Request $request ); - } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/ServiceProvider.php index 2410fd96f..0668fdc12 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/CriticalPath/ServiceProvider.php @@ -2,21 +2,15 @@ namespace WP_Rocket\Engine\CriticalPath; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\CriticalPath\Admin\{Admin, Post, Settings, Subscriber}; /** * Service provider for the Critical CSS classes - * - * @since 3.6 */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -36,66 +30,82 @@ class ServiceProvider extends AbstractServiceProvider { ]; /** - * Registers the subscribers in the container. + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * - * @since 3.6 + * @return void */ - public function register() { + public function register(): void { $filesystem = rocket_direct_filesystem(); $critical_css_path = rocket_get_constant( 'WP_ROCKET_CRITICAL_CSS_PATH' ); $options = $this->getContainer()->get( 'options' ); $beacon = $this->getContainer()->get( 'beacon' ); $template_path = $this->getContainer()->get( 'template_path' ) . '/cpcss'; - $this->getContainer()->share( 'cpcss_api_client', 'WP_Rocket\Engine\CriticalPath\APIClient' ); - $this->getContainer()->share( 'cpcss_data_manager', 'WP_Rocket\Engine\CriticalPath\DataManager' ) - ->withArgument( $critical_css_path ) - ->withArgument( $filesystem ); - $this->getContainer()->share( 'cpcss_service', 'WP_Rocket\Engine\CriticalPath\ProcessorService' ) - ->withArgument( $this->getContainer()->get( 'cpcss_data_manager' ) ) - ->withArgument( $this->getContainer()->get( 'cpcss_api_client' ) ); + $this->getContainer()->addShared( 'cpcss_api_client', APIClient::class ); + $this->getContainer()->addShared( 'cpcss_data_manager', DataManager::class ) + ->addArgument( $critical_css_path ) + ->addArgument( $filesystem ); + $this->getContainer()->addShared( 'cpcss_service', ProcessorService::class ) + ->addArgument( $this->getContainer()->get( 'cpcss_data_manager' ) ) + ->addArgument( $this->getContainer()->get( 'cpcss_api_client' ) ); $processor_service = $this->getContainer()->get( 'cpcss_service' ); // REST CPCSS START. - $this->getContainer()->share( 'rest_cpcss_wp_post', 'WP_Rocket\Engine\CriticalPath\RESTWPPost' ) - ->withArgument( $processor_service ) - ->withArgument( $options ); - $this->getContainer()->share( 'rest_cpcss_subscriber', 'WP_Rocket\Engine\CriticalPath\RESTCSSSubscriber' ) - ->withArgument( $this->getContainer()->get( 'rest_cpcss_wp_post' ) ); + $this->getContainer()->addShared( 'rest_cpcss_wp_post', RESTWPPost::class ) + ->addArgument( $processor_service ) + ->addArgument( $options ); + $this->getContainer()->addShared( 'rest_cpcss_subscriber', RESTCSSSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'rest_cpcss_wp_post' ) ) + ->addTag( 'common_subscriber' ); // REST CPCSS END. - $this->getContainer()->add( 'critical_css_generation', 'WP_Rocket\Engine\CriticalPath\CriticalCSSGeneration' ) - ->withArgument( $processor_service ); - $this->getContainer()->add( 'critical_css', 'WP_Rocket\Engine\CriticalPath\CriticalCSS' ) - ->withArgument( $this->getContainer()->get( 'critical_css_generation' ) ) - ->withArgument( $options ) - ->withArgument( $filesystem ); + $this->getContainer()->add( 'critical_css_generation', CriticalCSSGeneration::class ) + ->addArgument( $processor_service ); + $this->getContainer()->add( 'critical_css', CriticalCSS::class ) + ->addArgument( $this->getContainer()->get( 'critical_css_generation' ) ) + ->addArgument( $options ) + ->addArgument( $filesystem ); $critical_css = $this->getContainer()->get( 'critical_css' ); - $this->getContainer()->share( 'critical_css_subscriber', 'WP_Rocket\Engine\CriticalPath\CriticalCSSSubscriber' ) - ->withArgument( $critical_css ) - ->withArgument( $processor_service ) - ->withArgument( $options ) - ->withArgument( $filesystem ); + $this->getContainer()->addShared( 'critical_css_subscriber', CriticalCSSSubscriber::class ) + ->addArgument( $critical_css ) + ->addArgument( $processor_service ) + ->addArgument( $options ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ) + ->addArgument( $this->getContainer()->get( 'user' ) ) + ->addArgument( $filesystem ) + ->addTag( 'common_subscriber' ); - $this->getContainer()->add( 'cpcss_post', 'WP_Rocket\Engine\CriticalPath\Admin\Post' ) - ->withArgument( $options ) - ->withArgument( $beacon ) - ->withArgument( $critical_css_path ) - ->withArgument( $template_path ); - $this->getContainer()->add( 'cpcss_settings', 'WP_Rocket\Engine\CriticalPath\Admin\Settings' ) - ->withArgument( $options ) - ->withArgument( $beacon ) - ->withArgument( $critical_css ) - ->withArgument( $template_path ); - $this->getContainer()->add( 'cpcss_admin', 'WP_Rocket\Engine\CriticalPath\Admin\Admin' ) - ->withArgument( $options ) - ->withArgument( $processor_service ); - $this->getContainer()->share( 'critical_css_admin_subscriber', 'WP_Rocket\Engine\CriticalPath\Admin\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'cpcss_post' ) ) - ->withArgument( $this->getContainer()->get( 'cpcss_settings' ) ) - ->withArgument( $this->getContainer()->get( 'cpcss_admin' ) ); + $this->getContainer()->add( 'cpcss_post', Post::class ) + ->addArgument( $options ) + ->addArgument( $beacon ) + ->addArgument( $critical_css_path ) + ->addArgument( $template_path ); + $this->getContainer()->add( 'cpcss_settings', Settings::class ) + ->addArgument( $options ) + ->addArgument( $beacon ) + ->addArgument( $critical_css ) + ->addArgument( $template_path ); + $this->getContainer()->add( 'cpcss_admin', Admin::class ) + ->addArgument( $options ) + ->addArgument( $processor_service ); + $this->getContainer()->addShared( 'critical_css_admin_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'cpcss_post' ) ) + ->addArgument( $this->getContainer()->get( 'cpcss_settings' ) ) + ->addArgument( $this->getContainer()->get( 'cpcss_admin' ) ) + ->addTag( 'admin_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Deactivation/Deactivation.php b/wp-content/plugins/wp-rocket/inc/Engine/Deactivation/Deactivation.php index 0e9ff85c7..e93e9a238 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Deactivation/Deactivation.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Deactivation/Deactivation.php @@ -2,8 +2,13 @@ namespace WP_Rocket\Engine\Deactivation; -use WP_Rocket\Engine\Container\Container; +use WP_Rocket\Admin\Options; +use WP_Rocket\Dependencies\League\Container\Container; +use WP_Rocket\Engine\Admin\Beacon\ServiceProvider as BeaconServiceProvider; +use WP_Rocket\Engine\Support\ServiceProvider as SupportServiceProvider; +use WP_Rocket\ServiceProvider\Options as OptionsServiceProvider; use WP_Rocket\ThirdParty\Hostings\HostResolver; +use WP_Rocket\ThirdParty\Hostings\ServiceProvider as HostingsServiceProvider; class Deactivation { /** @@ -15,6 +20,7 @@ class Deactivation { 'advanced_cache', 'capabilities_manager', 'wp_cache', + 'cloudflare_plugin_subscriber', ]; /** @@ -27,9 +33,15 @@ public static function deactivate_plugin() { $container = new Container(); + $container->add( 'options_api', new Options( 'wp_rocket_' ) ); $container->add( 'template_path', WP_ROCKET_PATH . 'views' ); - $container->addServiceProvider( 'WP_Rocket\Engine\Deactivation\ServiceProvider' ); - $container->addServiceProvider( 'WP_Rocket\ThirdParty\Hostings\ServiceProvider' ); + + $container->addServiceProvider( new OptionsServiceProvider() ); + $container->addServiceProvider( new BeaconServiceProvider() ); + $container->addServiceProvider( new SupportServiceProvider() ); + + $container->addServiceProvider( new ServiceProvider() ); + $container->addServiceProvider( new HostingsServiceProvider() ); $host_type = HostResolver::get_host_service(); @@ -86,11 +98,14 @@ public static function deactivate_plugin() { // Delete transients. delete_transient( 'rocket_check_licence_30' ); delete_transient( 'rocket_check_licence_1' ); + delete_transient( 'rocket_rucss_as_tables_count' ); delete_site_transient( 'update_wprocket_response' ); + delete_site_transient( 'wp_rocket_update_data' ); + + // Delete user metadata. + rocket_renew_box( 'preload_notice' ); // Unschedule WP Cron events. - wp_clear_scheduled_hook( 'rocket_facebook_tracking_cache_update' ); - wp_clear_scheduled_hook( 'rocket_google_tracking_cache_update' ); wp_clear_scheduled_hook( 'rocket_cache_dir_size_check' ); /** diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Deactivation/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Deactivation/ServiceProvider.php index d50555989..0b201ecfd 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Deactivation/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Deactivation/ServiceProvider.php @@ -1,22 +1,17 @@ <?php namespace WP_Rocket\Engine\Deactivation; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; -use WP_Rocket\Engine\Container\ServiceProvider\BootableServiceProviderInterface; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\{AbstractServiceProvider, BootableServiceProviderInterface}; +use WP_Rocket\Engine\Cache\{AdvancedCache, WPCache}; +use WP_Rocket\Engine\Capabilities\Manager; +use WP_Rocket\ThirdParty\Plugins\CDN\{Cloudflare, CloudflareFacade}; /** * Service Provider for the activation process. - * - * @since 3.6.3 */ class ServiceProvider extends AbstractServiceProvider implements BootableServiceProviderInterface { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -24,30 +19,51 @@ class ServiceProvider extends AbstractServiceProvider implements BootableService 'advanced_cache', 'capabilities_manager', 'wp_cache', + 'cloudflare_plugin_subscriber', ]; + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + /** * Executes this method when the service provider is registered * * @return void */ - public function boot() { + public function boot(): void { $this->getContainer() - ->inflector( 'WP_Rocket\Engine\Deactivation\DeactivationInterface' ) + ->inflector( DeactivationInterface::class ) ->invokeMethod( 'deactivate', [] ); } /** * Registers the option array in the container. */ - public function register() { + public function register(): void { $filesystem = rocket_direct_filesystem(); - $this->getContainer()->add( 'advanced_cache', 'WP_Rocket\Engine\Cache\AdvancedCache' ) - ->withArgument( $this->getContainer()->get( 'template_path' ) . '/cache/' ) - ->withArgument( $filesystem ); - $this->getContainer()->add( 'capabilities_manager', 'WP_Rocket\Engine\Capabilities\Manager' ); - $this->getContainer()->add( 'wp_cache', 'WP_Rocket\Engine\Cache\WPCache' ) - ->withArgument( $filesystem ); + $this->getContainer()->add( 'cloudflare_plugin_facade', CloudflareFacade::class ); + $this->getContainer() + ->addShared( 'cloudflare_plugin_subscriber', Cloudflare::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ) + ->addArgument( $this->getContainer()->get( 'beacon' ) ) + ->addArgument( $this->getContainer()->get( 'cloudflare_plugin_facade' ) ) + ->addTag( 'common_subscriber' ); + + $this->getContainer()->add( 'advanced_cache', AdvancedCache::class ) + ->addArgument( $this->getContainer()->get( 'template_path' ) . '/cache/' ) + ->addArgument( $filesystem ); + $this->getContainer()->add( 'capabilities_manager', Manager::class ); + $this->getContainer()->add( 'wp_cache', WPCache::class ) + ->addArgument( $filesystem ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Debug/DebugSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Debug/DebugSubscriber.php new file mode 100644 index 000000000..98c029844 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Debug/DebugSubscriber.php @@ -0,0 +1,59 @@ +<?php + +namespace WP_Rocket\Engine\Debug; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +class DebugSubscriber implements Subscriber_Interface { + + /** + * Returns an array of events this listens to + * + * @return array + */ + public static function get_subscribed_events(): array { + return [ + 'wp_rocket_first_install' => 'on_first_install', + 'wp_rocket_upgrade' => [ 'on_upgrade', 10, 2 ], + ]; + } + + /** + * Adds the debug option on first install. + * + * @return void + */ + public function on_first_install(): void { + $this->add_debug_options(); + } + + /** + * Adds the debug option on upgrade. + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function on_upgrade( $new_version, $old_version ): void { + if ( version_compare( $old_version, '3.16', '>=' ) ) { + return; + } + + $this->add_debug_options(); + } + + /** + * Adds the debug option. + * + * @return boolean + */ + private function add_debug_options(): bool { + return add_option( + 'wp_rocket_debug', + [ + 'last_rucss_job_added' => '', + ] + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Debug/RUCSS/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Debug/RUCSS/Subscriber.php new file mode 100644 index 000000000..082f3f7d6 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Debug/RUCSS/Subscriber.php @@ -0,0 +1,134 @@ +<?php + +namespace WP_Rocket\Engine\Debug\RUCSS; + +use WP_Rocket\Admin\{Options, Options_Data}; +use WP_Rocket\Event_Management\Subscriber_Interface; +use WP_Rocket\Logger\Logger; + +class Subscriber implements Subscriber_Interface { + + /** + * Plugin options instance. + * + * @var Options_Data + */ + protected $options; + + /** + * Options instance. + * + * @var Options + */ + private $options_api; + + /** + * Instantiate the class + * + * @param Options_Data $options Options instance. + * @param Options $options_api Options instance. + */ + public function __construct( Options_Data $options, Options $options_api ) { + $this->options = $options; + $this->options_api = $options_api; + } + + /** + * Returns an array of events this listens to + * + * @return array + */ + public static function get_subscribed_events(): array { + return [ + 'rocket_last_saas_job_added_time' => [ 'log_last_added_job_time', 10, 2 ], + 'rocket_saas_process_pending_jobs_start' => [ 'log_process_pending_job_start_time', 10, 1 ], + 'rocket_saas_process_pending_jobs_end' => [ 'log_process_pending_job_end_time', 10, 1 ], + 'rocket_saas_check_job_status_end' => [ 'log_check_job_status_end', 10, 1 ], + 'rocket_saas_process_on_submit_jobs_start' => [ 'log_process_on_submit_start', 10, 1 ], + 'rocket_saas_process_on_submit_jobs_end' => [ 'log_process_on_submit_end', 10, 1 ], + ]; + } + + /** + * Saves the last time a new job was added to rucss table. + * + * @param mixed $is_success New job status: ID of inserted row if successfully added; false otherwise. + * @param string $timestamp Current timestamp. + * @return void + */ + public function log_last_added_job_time( $is_success, $timestamp ) { + if ( Logger::debug_enabled() ) { + if ( ! $is_success ) { + return; + } + + $this->options->set( 'last_rucss_job_added', $timestamp ); + $this->options_api->set( 'debug', $this->options->get_options() ); + } + } + + /** + * Saves the time when the process pending jobs started. + * + * @param string $timestamp Current timestamp. + * @return void + */ + public function log_process_pending_job_start_time( $timestamp ) { + if ( Logger::debug_enabled() ) { + $this->options->set( 'rucss_process_pending_jobs_start', $timestamp ); + $this->options_api->set( 'debug', $this->options->get_options() ); + } + } + + /** + * Saves the time when the process pending jobs ended. + * + * @param string $timestamp Current timestamp. + * @return void + */ + public function log_process_pending_job_end_time( $timestamp ) { + if ( Logger::debug_enabled() ) { + $this->options->set( 'rucss_process_pending_jobs_end', $timestamp ); + $this->options_api->set( 'debug', $this->options->get_options() ); + } + } + + /** + * Saves the time when the check job status ended. + * + * @param string $timestamp Current timestamp. + * @return void + */ + public function log_check_job_status_end( $timestamp ) { + if ( Logger::debug_enabled() ) { + $this->options->set( 'rucss_check_job_status_end', $timestamp ); + $this->options_api->set( 'debug', $this->options->get_options() ); + } + } + + /** + * Saves the time when the process on submit jobs started. + * + * @param string $timestamp Current timestamp. + * @return void + */ + public function log_process_on_submit_start( $timestamp ) { + if ( Logger::debug_enabled() ) { + $this->options->set( 'rucss_process_on_submit_jobs_start', $timestamp ); + $this->options_api->set( 'debug', $this->options->get_options() ); + } + } + + /** + * Saves the time when the process on submit jobs ended. + * + * @param string $timestamp Current timestamp. + * @return void + */ + public function log_process_on_submit_end( $timestamp ) { + if ( Logger::debug_enabled() ) { + $this->options->set( 'rucss_process_on_submit_jobs_end', $timestamp ); + $this->options_api->set( 'debug', $this->options->get_options() ); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Debug/Resolver.php b/wp-content/plugins/wp-rocket/inc/Engine/Debug/Resolver.php new file mode 100644 index 000000000..4b9aa7449 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Debug/Resolver.php @@ -0,0 +1,62 @@ +<?php + +namespace WP_Rocket\Engine\Debug; + +use WP_Rocket\Admin\Options_Data; + +/** + * Resolver. + */ +class Resolver { + + /** + * Array of WP Rocket Options. + * + * @var array + */ + private $options_services = [ + 'remove_unused_css' => [ + 'service' => 'rucss_debug_subscriber', + 'class' => 'WP_Rocket\Engine\Debug\RUCSS\Subscriber', + ], + ]; + + /** + * Debug options instance. + * + * @var Options_Data + */ + private $options; + + /** + * Instantiate the class. + * + * @param Options_Data $options Options instance. + */ + public function __construct( Options_Data $options ) { + $this->options = $options; + } + + /** + * Ships an array of available services. + * + * @return array Array of services. + */ + public function get_services(): array { + $set_services = []; + + if ( empty( $this->options_services ) ) { + return []; + } + + foreach ( $this->options_services as $option => $services ) { + if ( ! (bool) $this->options->get( $option, 0 ) ) { + continue; + } + + $set_services[] = $services; + } + + return $set_services; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Debug/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Debug/ServiceProvider.php new file mode 100644 index 000000000..a119eb5ca --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Debug/ServiceProvider.php @@ -0,0 +1,77 @@ +<?php +namespace WP_Rocket\Engine\Debug; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\{AbstractServiceProvider, BootableServiceProviderInterface}; +use WP_Rocket\Admin\Options_Data; + +/** + * Service provider for Debug + */ +class ServiceProvider extends AbstractServiceProvider implements BootableServiceProviderInterface { + /** + * Array of services provided by this service provider + * + * @var array + */ + protected $provides = [ + 'debug_subscriber', + 'options_debug', + ]; + + /** + * Array of available debug services. + * + * @var array + */ + protected $services = []; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Register the service in the provider array + * + * @return void + */ + public function boot(): void { + $this->services = $this->getContainer()->get( 'debug_resolver' )->get_services(); + + if ( empty( $this->services ) ) { + return; + } + + foreach ( $this->services as $service ) { + $this->provides[] = $service['service']; + } + } + + /** + * Registers items with the container + * + * @return void + */ + public function register(): void { + $this->container->add( 'debug_subscriber', DebugSubscriber::class ); + + if ( empty( $this->services ) ) { + return; + } + + $this->container->add( 'options_debug', Options_Data::class ) + ->addArgument( $this->container->get( 'options_api' )->get( 'debug', [] ) ); + + foreach ( $this->services as $service ) { + $this->getContainer()->add( $service['service'], $service['class'] ) + ->addArgument( $this->getContainer()->get( 'options_debug' ) ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/ActionSchedulerCheck.php b/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/ActionSchedulerCheck.php new file mode 100644 index 000000000..2281931a4 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/ActionSchedulerCheck.php @@ -0,0 +1,154 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\HealthCheck; + +use ActionScheduler_Versions; +use ActionScheduler; +use ActionScheduler_StoreSchema; +use ActionScheduler_LoggerSchema; +use WP_Rocket\Event_Management\Subscriber_Interface; +use WP_Rocket\Engine\Activation\ActivationInterface; + +class ActionSchedulerCheck implements Subscriber_Interface, ActivationInterface { + /** + * Array of events this subscriber listens to. + * + * @return array + */ + public static function get_subscribed_events(): array { + $slug = rocket_get_constant( 'WP_ROCKET_SLUG', 'wp_rocket_settings' ); + + return [ + 'update_option_' . $slug => [ 'check_on_update_options', 10, 2 ], + 'wp_rocket_update' => 'maybe_recreate_as_tables', + ]; + } + + /** + * Actions to perform on plugin activation + * + * @return void + */ + public function activate() { + // @phpstan-ignore-next-line + add_action( 'rocket_activation', [ $this, 'maybe_recreate_as_tables' ] ); + } + + /** + * Maybe recreate Action Scheduler tables if they are missing + * + * @return bool + */ + public function maybe_recreate_as_tables(): bool { + if ( ! $this->is_valid_action_scheduler_version() ) { + return false; + } + + if ( $this->is_valid_as_tables() ) { + return false; + } + + $store_schema = new ActionScheduler_StoreSchema(); + $logger_schema = new ActionScheduler_LoggerSchema(); + $store_schema->register_tables( true ); + $logger_schema->register_tables( true ); + + return true; + } + + /** + * Maybe recreate tables on preload or RUCSS activation + * + * @param mixed $old_value The old option value. + * @param mixed $value The new option value. + * + * @return bool + */ + public function check_on_update_options( $old_value, $value ): bool { + if ( ! isset( $old_value['remove_unused_css'], $value['remove_unused_css'], $old_value['manual_preload'], $value['manual_preload'] ) ) { + return false; + } + + if ( + $old_value['remove_unused_css'] === $value['remove_unused_css'] + && + $old_value['manual_preload'] === $value['manual_preload'] + ) { + return false; + } + + if ( + 0 === (int) $value['remove_unused_css'] + && + 0 === (int) $value['manual_preload'] + ) { + return false; + } + + if ( + ( + $old_value['remove_unused_css'] !== $value['remove_unused_css'] + && + 1 !== (int) $value['remove_unused_css'] + ) + || + ( + $old_value['manual_preload'] !== $value['manual_preload'] + && + 1 !== (int) $value['manual_preload'] + ) + ) { + return false; + } + + return $this->maybe_recreate_as_tables(); + } + + /** + * Check if Action Scheduler tables exists + * + * @return bool + */ + private function is_valid_as_tables(): bool { + $cached_count = get_transient( 'rocket_rucss_as_tables_count' ); + + if ( + false !== $cached_count + && + ! is_admin() + ) { // Stop caching in admin UI. + return 4 === (int) $cached_count; + } + + global $wpdb; + + $exp = "'^" . $wpdb->prefix . "actionscheduler_(logs|actions|groups|claims)$'"; + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching + $found_as_tables = $wpdb->get_col( + // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $wpdb->prepare( 'SHOW TABLES FROM `' . DB_NAME . '` WHERE `Tables_in_' . DB_NAME . '` LIKE %s AND `Tables_in_' . DB_NAME . '` REGEXP ' . $exp, '%actionscheduler%' ) + ); + + set_transient( 'rocket_rucss_as_tables_count', count( $found_as_tables ), rocket_get_constant( 'DAY_IN_SECONDS', 24 * 60 * 60 ) ); + + return 4 === count( $found_as_tables ); + } + + /** + * Validate if the currenlt loaded action scheduler's version is more than 3.0.0. + * Note: Latest_version method in ActionScheduler_Versions class will return false with first activation + * in case we don't have any other active plugin which loads Action Scheduler. + * Because with activation, our Action Scheduler still not initialized yet. + * + * @return bool + */ + private function is_valid_action_scheduler_version() { + if ( ! class_exists( 'ActionScheduler_Versions' ) || ! class_exists( 'ActionScheduler' ) ) { + return false; + } + + $version = ActionScheduler_Versions::instance()->latest_version(); + return ! $version || version_compare( $version, '3.0.0', '>=' ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/CacheDirSizeCheck.php b/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/CacheDirSizeCheck.php deleted file mode 100644 index db96d785c..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/CacheDirSizeCheck.php +++ /dev/null @@ -1,187 +0,0 @@ -<?php -namespace WP_Rocket\Engine\HealthCheck; - -use FilesystemIterator; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; -use UnexpectedValueException; -use WP_Rocket\Event_Management\Subscriber_Interface; - -/** - * Add a weekly event to check for the cache directories sizes - * and send a notification if it's bigger thant the defined maximum size - * - * @since 3.3.5 - */ -class CacheDirSizeCheck implements Subscriber_Interface { - /** - * Event name - */ - const CRON_NAME = 'rocket_cache_dir_size_check'; - - /** - * Maximum allowed size - */ - const MAX_SIZE = 10737418240; - - /** - * ROUTE endpoint to request - */ - const ROUTE = 'api/wp-rocket/cache-dir-check.php'; - - /** - * Absolute path to the minify directory - * - * @var string - */ - private $minify_path; - - /** - * Full URL to the API endpoint - * - * @var string - */ - private $api_endpoint; - - /** - * Instantiate the class - * - * @param string $minify_path Absolute path to the minify directory. - * @param string $rocket_url WP Rocket website URL. - */ - public function __construct( $minify_path, $rocket_url ) { - $this->minify_path = $minify_path . get_current_blog_id(); - $this->api_endpoint = $rocket_url . self::ROUTE; - } - - /** - * Return an array of events that this subscriber wants to listen to. - * - * @since 3.3.5 - * - * @return array - */ - public static function get_subscribed_events() { - return [ - 'cron_schedules' => 'add_schedule', - 'init' => 'schedule_cache_dir_size_check', - self::CRON_NAME => 'cache_dir_size_check', - 'wp_rocket_upgrade' => [ 'delete_option_after_upgrade', 11, 2 ], - ]; - } - - /** - * Adds the weekly interval if it doesn't already exist - * - * @since 3.3.5 - * - * @param array $schedules Array of intervals. - * @return array - */ - public function add_schedule( $schedules ) { - if ( isset( $schedules['weekly'] ) ) { - return $schedules; - } - - $schedules['weekly'] = [ - 'interval' => 604800, - 'display' => __( 'weekly', 'rocket' ), - ]; - - return $schedules; - } - - /** - * Schedules the cron event if not yet scheduled. - * - * @since 3.3.5 - * - * @return void - */ - public function schedule_cache_dir_size_check() { - if ( ! wp_next_scheduled( self::CRON_NAME ) ) { - wp_schedule_event( time(), 'weekly', self::CRON_NAME ); - } - } - - /** - * Checks the cache dir size when the event is triggered - * and send a notification if the directory size is above the defined maximum size - * - * @since 3.3.5 - * - * @return void - */ - public function cache_dir_size_check() { - if ( 1 === (int) get_option( self::CRON_NAME ) ) { - return; - } - - $checks = [ - 'min' => $this->minify_path, - ]; - - foreach ( $checks as $type => $path ) { - $size = $this->get_dir_size( $path ); - - if ( $size > self::MAX_SIZE ) { - $this->send_notification( $type ); - } - } - - update_option( self::CRON_NAME, 1 ); - } - - /** - * Deletes the check size option when updating the plugin - * - * @since 3.3.6 - * - * @param string $new_version Latest WP Rocket version. - * @param string $current_version Installed WP Rocket version. - */ - public function delete_option_after_upgrade( $new_version, $current_version ) { - if ( version_compare( $current_version, $new_version, '<' ) ) { - delete_option( self::CRON_NAME ); - } - } - - /** - * Gets the size of the provided directory - * - * @since 3.3.5 - * - * @param string $dir Absolute path to the directory. - * @return int - */ - private function get_dir_size( $dir ) { - $size = 0; - - try { - foreach ( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ) ) as $file ) { - $size += $file->getSize(); - } - - return $size; - } catch ( UnexpectedValueException $e ) { - return $size; - } - } - - /** - * Sends a notification to our endpoint with the type of directory - * - * @since 3.3.5 - * - * @param string $dir_type Type of directory. - * @return void - */ - private function send_notification( $dir_type ) { - wp_safe_remote_post( - $this->api_endpoint, - [ - 'body' => 'cache_dir_type=' . $dir_type, - ] - ); - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/ServiceProvider.php index 86e674bdf..276daf64a 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/HealthCheck/ServiceProvider.php @@ -1,42 +1,43 @@ <?php namespace WP_Rocket\Engine\HealthCheck; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; /** * Service Provider for health check subscribers - * - * @since 3.6 */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ protected $provides = [ 'health_check', - 'cache_dir_size_check', + 'action_scheduler_check', ]; /** - * Registers the option array in the container + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. * - * @since 3.6 - * @author Remy Perona + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { - $this->getContainer()->share( 'health_check', 'WP_Rocket\Engine\HealthCheck\HealthCheck' ) - ->withArgument( $this->getContainer()->get( 'options' ) ); - $this->getContainer()->share( 'cache_dir_size_check', 'WP_Rocket\Engine\HealthCheck\CacheDirSizeCheck' ) - ->withArgument( rocket_get_constant( 'WP_ROCKET_MINIFY_CACHE_PATH' ) ) - ->withArgument( rocket_get_constant( 'WP_ROCKET_WEB_MAIN' ) ); + public function register(): void { + $this->getContainer()->addShared( 'health_check', HealthCheck::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addTag( 'admin_subscriber' ); + $this->getContainer()->addShared( 'action_scheduler_check', ActionSchedulerCheck::class ) + ->addTag( 'common_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Heartbeat/HeartbeatSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Heartbeat/HeartbeatSubscriber.php index 33e2e5abd..5425084c1 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Heartbeat/HeartbeatSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Heartbeat/HeartbeatSubscriber.php @@ -61,6 +61,12 @@ public function maybe_disable() { } wp_deregister_script( 'heartbeat' ); + + /** + * Enqueue an empty heartbeat script to prevent query monitor error + * Added to the footer + */ + wp_enqueue_script( 'heartbeat', WP_ROCKET_ASSETS_JS_URL . 'heartbeat.js', null, WP_ROCKET_VERSION, true ); } /** @@ -125,7 +131,7 @@ private function get_current_context() { * * @since 3.2 * - * @param $context string Either 'site' (frontend), 'admin' (backend), or 'editor'. + * @param string $context string Either 'site' (frontend), 'admin' (backend), or 'editor'. */ $filtered_context = apply_filters( 'rocket_heartbeat_context', $context ); diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Heartbeat/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Heartbeat/ServiceProvider.php index d0c431708..58ae3a498 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Heartbeat/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Heartbeat/ServiceProvider.php @@ -1,21 +1,14 @@ <?php namespace WP_Rocket\Engine\Heartbeat; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; /** - * Service provider for Media module - * - * @since 3.7 + * Service provider for heartbeat module */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -24,16 +17,24 @@ class ServiceProvider extends AbstractServiceProvider { ]; /** - * Registers the services in the container + * Check if the service provider provides a specific service. * - * @since 3.6 + * @param string $id The id of the service. * - * @return void + * @return bool */ - public function register() { - $options = $this->getContainer()->get( 'options' ); + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } - $this->getContainer()->share( 'heartbeat_subscriber', 'WP_Rocket\Engine\Heartbeat\HeartbeatSubscriber' ) - ->withArgument( $this->getContainer()->get( 'options' ) ); + /** + * Registers items with the container + * + * @return void + */ + public function register(): void { + $this->getContainer()->addShared( 'heartbeat_subscriber', HeartbeatSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addTag( 'common_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/API/PricingClient.php b/wp-content/plugins/wp-rocket/inc/Engine/License/API/PricingClient.php index c827b56cf..045482293 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/API/PricingClient.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/API/PricingClient.php @@ -3,7 +3,7 @@ namespace WP_Rocket\Engine\License\API; class PricingClient { - const PRICING_ENDPOINT = 'https://wp-rocket.me/stat/1.0/wp-rocket/pricing.php'; + const PRICING_ENDPOINT = 'https://wp-rocket.me/stat/1.0/wp-rocket/pricing-2023.php'; /** * Gets pricing data from cache if it exists, else gets it from the pricing endpoint @@ -27,7 +27,7 @@ public function get_pricing_data() { return false; } - set_transient( 'wp_rocket_pricing', $data, 6 * HOUR_IN_SECONDS ); + set_transient( 'wp_rocket_pricing', $data, 12 * HOUR_IN_SECONDS ); return $data; } @@ -40,20 +40,51 @@ public function get_pricing_data() { * @return bool|object */ private function get_raw_pricing_data() { + if ( (bool) get_transient( 'wp_rocket_pricing_timeout_active' ) ) { + return false; + } + $response = wp_safe_remote_get( self::PRICING_ENDPOINT ); if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { + $this->set_timeout_transients(); + return false; } $body = wp_remote_retrieve_body( $response ); if ( empty( $body ) ) { + $this->set_timeout_transients(); + return false; } + delete_transient( 'wp_rocket_pricing_timeout' ); + delete_transient( 'wp_rocket_pricing_timeout_active' ); + return json_decode( $body ); } + + /** + * Set pricing timeout transients. + * + * @since 3.8.4 + * + * @return void + */ + private function set_timeout_transients() { + $timeout = (int) get_transient( 'wp_rocket_pricing_timeout' ); + $timeout = ( 0 === $timeout ) + ? 300 + : ( 2 * $timeout <= DAY_IN_SECONDS + ? 2 * $timeout : + DAY_IN_SECONDS + ); + + set_transient( 'wp_rocket_pricing_timeout', $timeout, WEEK_IN_SECONDS ); + set_transient( 'wp_rocket_pricing_timeout_active', true, $timeout ); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/API/User.php b/wp-content/plugins/wp-rocket/inc/Engine/License/API/User.php index 819025c6a..21ef304fb 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/API/User.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/API/User.php @@ -120,4 +120,17 @@ public function get_renewal_url() { return $this->user->renewal_url; } + + /** + * Checks if the user license has expired for more than 15 days + * + * @return boolean + */ + public function is_license_expired_grace_period() { + if ( $this->is_license_expired() && ( time() - $this->get_license_expiration() > 15 * 24 * 60 * 60 ) ) { + return true; + } + + return false; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/API/UserClient.php b/wp-content/plugins/wp-rocket/inc/Engine/License/API/UserClient.php index 06ad02f95..00d6f15fa 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/API/UserClient.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/API/UserClient.php @@ -33,11 +33,6 @@ public function __construct( Options_Data $options ) { * @return bool|object */ public function get_user_data() { - return (object) [ - 'licence_account' => '-1', - 'licence_expiration' => 1893456000, - ]; - $cached_data = get_transient( 'wp_rocket_customer_data' ); if ( false !== $cached_data ) { diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/Renewal.php b/wp-content/plugins/wp-rocket/inc/Engine/License/Renewal.php index 1070acbd7..a3dbc6e97 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/Renewal.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/Renewal.php @@ -1,8 +1,10 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\License; use WP_Rocket\Abstract_Render; +use WP_Rocket\Admin\Options_Data; use WP_Rocket\Engine\License\API\Pricing; use WP_Rocket\Engine\License\API\User; @@ -21,18 +23,27 @@ class Renewal extends Abstract_Render { */ private $user; + /** + * Options_Data instance + * + * @var Options_Data + */ + private $options; + /** * Instantiate the class * - * @param Pricing $pricing Pricing instance. - * @param User $user User instance. - * @param string $template_path Path to the views. + * @param Pricing $pricing Pricing instance. + * @param User $user User instance. + * @param Options_Data $options Options_Data instance. + * @param string $template_path Path to the views. */ - public function __construct( Pricing $pricing, User $user, $template_path ) { + public function __construct( Pricing $pricing, User $user, Options_Data $options, $template_path ) { parent::__construct( $template_path ); $this->pricing = $pricing; $this->user = $user; + $this->options = $options; } /** @@ -57,6 +68,29 @@ public function display_renewal_soon_banner() { $data = $this->get_banner_data(); $data['countdown'] = $this->get_countdown_data(); + $discount = esc_html( $this->get_discount_percent() . '%' ); + $price = esc_html( '$' . number_format_i18n( $this->get_price(), 2 ) ); + + $data['message'] = sprintf( + // translators: %1$s = <strong>, %2$s = price, %3$s = </strong>. + esc_html__( 'Renew before it is too late, you will only pay %1$s%2$s%3$s!', 'rocket' ), + '<strong>', + $price, + '</strong>' + ); + + if ( $this->get_discount_percent() ) { + $data['message'] = sprintf( + // translators: %1$s = <strong>, %2$s = discount, %3$s = </strong>,%4$s = <strong>, %5$s = price, %6$s=</strong>. + esc_html__( 'Renew with a %1$s%2$s discount%3$s before it is too late, you will only pay %4$s%5$s%6$s!', 'rocket' ), + '<strong>', + $discount, + '</strong>', + '<strong>', + $price, + '</strong>' + ); + } echo $this->generate( 'renewal-soon-banner', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } @@ -85,7 +119,88 @@ public function display_renewal_expired_banner() { return; } - echo $this->generate( 'renewal-expired-banner', $this->get_banner_data() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + $expiration = $this->user->get_license_expiration(); + $expired_since = ( time() - $expiration ) / DAY_IN_SECONDS; + + if ( + $this->user->is_auto_renew() + && + 4 > $expired_since + ) { + return; + } + + $ocd_enabled = $this->options->get( 'optimize_css_delivery', 0 ); + $renewal_url = $this->user->get_renewal_url(); + $price = esc_html( '$' . number_format_i18n( $this->get_price(), 2 ) ); + + $message = sprintf( + // translators: %1$s = <strong>, %2$s = </strong>, %3$s = price. + esc_html__( 'Renew your license for 1 year now at %1$s%3$s%2$s.', 'rocket' ), + '<strong>', + '</strong>', + $price + ); + + if ( + ( $this->is_grandfather() || $this->has_grandmother() ) + && + $expired_since < 15 + ) { + $message = sprintf( + // translators: %1$s = <strong>, %2$s = </strong>, %3$s = discount percentage, %4$s = price. + esc_html__( 'Renew your license for 1 year now and get %1$s%3$s OFF%2$s immediately: you will only pay %1$s%4$s%2$s!', 'rocket' ), + '<strong>', + '</strong>', + esc_html( $this->get_discount_percent() . '%' ), + $price + ); + } + + if ( $ocd_enabled ) { + if ( 15 > $expired_since ) { + // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped + echo $this->generate( + 'renewal-expired-banner-ocd', + [ + 'renewal_url' => $renewal_url, + 'message' => $message, + 'disabled_date' => date_i18n( get_option( 'date_format' ), $expiration + 15 * DAY_IN_SECONDS ), + ] + ); + // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped + } elseif ( 90 > $expired_since ) { + // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped + echo $this->generate( + 'renewal-expired-banner-ocd-disabled', + [ + 'renewal_url' => $renewal_url, + 'message' => $message, + ] + ); + // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped + } elseif ( 90 < $expired_since ) { + // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped + echo $this->generate( + 'renewal-expired-banner', + [ + 'renewal_url' => $renewal_url, + 'message' => $message, + ] + ); + // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped + } + } elseif ( ! $ocd_enabled ) { + // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped + echo $this->generate( + 'renewal-expired-banner', + [ + 'renewal_url' => $renewal_url, + 'message' => $message, + ] + ); + // phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped + } } /** @@ -96,10 +211,30 @@ public function display_renewal_expired_banner() { * @return array */ private function get_banner_data() { + $price = esc_html( '$' . number_format_i18n( $this->get_price(), 2 ) ); + + $message = sprintf( + // translators: %1$s = <strong>, %2$s = </strong>, %3$s = discount price. + esc_html__( 'Renew before it is too late, you will pay %1$s%3$s%2$s.', 'rocket' ), + '<strong>', + '</strong>', + $price + ); + + if ( $this->is_grandfather() ) { + $message = sprintf( + // translators: %1$s = <strong>, %2$s = discount percentage, %3$s = </strong>, %4$s = discount price. + esc_html__( 'Renew with a %1$s%2$s discount%3$s before it is too late, you will only pay %1$s%4$s%3$s!', 'rocket' ), + '<strong>', + esc_html( '$' . number_format_i18n( $this->get_discount_percent(), 2 ) ), + '</strong>', + $price + ); + } + return [ - 'discount_percent' => $this->get_discount_percent(), - 'discount_price' => number_format_i18n( $this->get_discount_price(), 2 ), - 'renewal_url' => $this->user->get_renewal_url(), + 'message' => $message, + 'renewal_url' => $this->user->get_renewal_url(), ]; } @@ -172,38 +307,67 @@ private function is_expired_soon() { } /** - * Gets the discount percentage corresponding to the current user status + * Gets the discount corresponding to the current user status * * @since 3.7.5 * * @return int */ private function get_discount_percent() { + $prices = $this->get_license_pricing_data(); + $renewals = $this->get_user_renewal_status(); - if ( false === $renewals ) { + if ( false === $renewals || ! isset( $prices->prices, $prices->prices->renewal ) ) { return 0; } - if ( $renewals['is_expired'] ) { - return isset( $renewals['discount_percent']->is_expired ) ? $renewals['discount_percent']->is_expired : 0; - } + $prices = $prices->prices; if ( $renewals['is_grandfather'] ) { - return isset( $renewals['discount_percent']->is_grandfather ) ? $renewals['discount_percent']->is_grandfather : 0; + return $renewals['discount_percent']->is_grandfather; + } + + return 0; + } + + /** + * Is user grandfathered + * + * @return bool + */ + private function is_grandfather(): bool { + $renewals = $this->get_user_renewal_status(); + + if ( ! is_array( $renewals ) ) { + return false; + } + + return key_exists( 'is_grandfather', $renewals ) && $renewals['is_grandfather']; + } + /** + * Is user grandmothered + * + * @return bool + */ + private function has_grandmother(): bool { + $renewals = $this->get_user_renewal_status(); + + if ( ! is_array( $renewals ) ) { + return false; } - return isset( $renewals['discount_percent']->not_grandfather ) ? $renewals['discount_percent']->not_grandfather : 0; + return key_exists( 'is_grandmother', $renewals ) && $renewals['is_grandmother']; } /** - * Gets the discount price corresponding to the current user status + * Gets the price corresponding to the current user status * * @since 3.7.5 * * @return int */ - private function get_discount_price() { + private function get_price() { $renewals = $this->get_user_renewal_status(); if ( false === $renewals ) { @@ -212,12 +376,17 @@ private function get_discount_price() { $license = $this->get_license_pricing_data(); - if ( $renewals['is_expired'] ) { - return isset( $license->prices->renewal->is_expired ) ? $license->prices->renewal->is_expired : 0; + if ( + $renewals['is_grandfather'] + && + ! $renewals['is_expired'] + ) { + return isset( $license->prices->renewal->is_grandfather ) ? $license->prices->renewal->is_grandfather : 0; } - if ( $renewals['is_grandfather'] ) { - return isset( $license->prices->renewal->is_grandfather ) ? $license->prices->renewal->is_grandfather : 0; + if ( $renewals['is_grandmother'] && + ! $renewals['is_expired'] ) { + return isset( $license->prices->renewal->is_grandmother ) ? $license->prices->renewal->is_grandmother : 0; } return isset( $license->prices->renewal->not_grandfather ) ? $license->prices->renewal->not_grandfather : 0; @@ -233,7 +402,7 @@ private function get_discount_price() { private function get_user_renewal_status() { $renewals = $this->pricing->get_renewals_data(); - if ( ! isset( $renewals->extra_days, $renewals->grandfather_date, $renewals->discount_percent ) ) { + if ( ! isset( $renewals->extra_days, $renewals->grandfather_date, $renewals->discount_percent, $renewals->grandmother_date ) ) { return false; } @@ -241,6 +410,7 @@ private function get_user_renewal_status() { 'discount_percent' => $renewals->discount_percent, 'is_expired' => time() > ( $this->user->get_license_expiration() + ( $renewals->extra_days * DAY_IN_SECONDS ) ), 'is_grandfather' => $renewals->grandfather_date > $this->user->get_creation_date(), + 'is_grandmother' => $renewals->grandmother_date > $this->user->get_creation_date(), ]; } @@ -310,4 +480,277 @@ private function get_countdown_data() { return $data; } + + /** + * Add license expiring warning to OCD label + * + * @param array $args Setting field arguments. + * + * @return array + */ + public function add_license_expire_warning( $args ): array { + if ( 'optimize_css_delivery' !== $args['id'] ) { + return $args; + } + + if ( ! $this->user->is_license_expired() ) { + return $args; + } + + $ocd = $this->options->get( 'optimize_css_delivery', 0 ); + $whitelabel = rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT', false ); + $expired_since = ( time() - $this->user->get_license_expiration() ) / DAY_IN_SECONDS; + $message = ' <span class="wpr-icon-important wpr-checkbox-warning">'; + + if ( + ( + $whitelabel + && + 15 > $expired_since + && + $ocd + ) + || + ( + ! $whitelabel + && + $this->user->is_auto_renew() + && + 4 > $expired_since + ) + || + ( + $whitelabel + && + $this->user->is_auto_renew() + && + 4 > $expired_since + && + ! $ocd + ) + ) { + return $args; + } elseif ( + ! $whitelabel + && + 15 > $expired_since + && + $ocd + ) { + $message .= sprintf( + // translators: %1$s = <a>, %2$s = </a>. + __( 'You need a valid license to continue using this feature. %1$sRenew now%2$s before losing access.', 'rocket' ), + '<a href="' . esc_url( $this->user->get_renewal_url() ) . '" target="_blank">', + '</a>' + ); + } elseif ( + ( + ! $whitelabel + && + 15 < $expired_since + ) + || + ( + ! $whitelabel + && + 15 > $expired_since + && + ! $ocd + ) + ) { + $message .= sprintf( + // translators: %1$s = <a>, %2$s = </a>. + __( 'You need an active license to enable this option. %1$sRenew now%2$s.', 'rocket' ), + '<a href="' . esc_url( $this->user->get_renewal_url() ) . '" target="_blank">', + '</a>' + ); + } elseif ( + ( + $whitelabel + && + 15 < $expired_since + ) + || + ( + $whitelabel + && + 15 > $expired_since + && + ! $ocd + ) + ) { + $doc = 'https://docs.wp-rocket.me/article/1711-what-happens-if-my-license-expires'; + $locale = current( array_slice( explode( '_', get_user_locale() ), 0, 1 ) ); + + if ( 'fr' === $locale ) { + $doc = 'https://fr.docs.wp-rocket.me/article/1712-que-se-passe-t-il-si-ma-licence-expire'; + } + + $message .= sprintf( + // translators: %1$s = <a>, %2$s = </a>. + __( 'You need an active license to enable this option. %1$sMore info%2$s.', 'rocket' ), + '<a href="' . $doc . '?utm_source=wp_plugin&utm_medium=wp_rocket" target="_blank">', + '</a>' + ); + } + + $message .= '</span>'; + + $args['label'] = $args['label'] . $message; + + return $args; + } + + /** + * Adds the notification bubble to WP Rocket menu item when expired + * + * @param string $menu_title Menu title. + * + * @return string + */ + public function add_expired_bubble( $menu_title ): string { + if ( rocket_get_constant( 'WP_ROCKET_WHITE_LABEL_ACCOUNT', false ) ) { + return $menu_title; + } + + if ( ! $this->user->is_license_expired() ) { + return $menu_title; + } + + if ( false !== get_transient( 'wpr_dashboard_seen_' . get_current_user_id() ) ) { + return $menu_title; + } + + $expired_since = ( time() - $this->user->get_license_expiration() ) / DAY_IN_SECONDS; + $auto_renew = $this->user->is_auto_renew(); + $ocd_enabled = $this->options->get( 'optimize_css_delivery', 0 ); + + if ( + $ocd_enabled + && + $auto_renew + && + 4 > $expired_since + ) { + return $menu_title; + } + + if ( + ! $auto_renew + && + ! $ocd_enabled + && + 4 < $expired_since + + ) { + return $menu_title; + } + + if ( + $auto_renew + && + ! $ocd_enabled + && + ( + 4 > $expired_since + || + 15 < $expired_since + ) + ) { + return $menu_title; + } + + return $menu_title . ' <span class="awaiting-mod">!</span>'; + } + + /** + * Sets the dashboard seen transient to hide the expired bubble + * + * @return void + */ + public function set_dashboard_seen_transient() { + if ( ! $this->user->is_license_expired() ) { + return; + } + + if ( ! $this->options->get( 'optimize_css_delivery', 0 ) ) { + return; + } + + $current_user = get_current_user_id(); + + if ( false !== get_transient( "wpr_dashboard_seen_{$current_user}" ) ) { + return; + } + + $expired_since = ( time() - $this->user->get_license_expiration() ) / DAY_IN_SECONDS; + + if ( 15 > $expired_since ) { + set_transient( "wpr_dashboard_seen_{$current_user}", 1, 15 * DAY_IN_SECONDS ); + } elseif ( 15 < $expired_since ) { + set_transient( "wpr_dashboard_seen_{$current_user}", 1, YEAR_IN_SECONDS ); + } + } + + /** + * Disable optimize CSS delivery setting + * + * @param array $args Array of setting field arguments. + * + * @return array + */ + public function maybe_disable_ocd( $args ) { + if ( 'optimize_css_delivery' !== $args['id'] ) { + return $args; + } + + if ( ! $this->user->is_license_expired() ) { + return $args; + } + + $expired_since = ( time() - $this->user->get_license_expiration() ) / DAY_IN_SECONDS; + + if ( + 15 > $expired_since + || + ( + $this->user->is_auto_renew() + && + 4 > $expired_since + ) + ) { + return $args; + } + + $args['value'] = 0; + + if ( + isset( $args['container_class'] ) + && + ! in_array( 'wpr-isDisabled', $args['container_class'], true ) + ) { + $args['container_class'][] = 'wpr-isDisabled'; + } + + $args['input_attr']['disabled'] = 1; + + return $args; + } + + /** + * Disables the RUCSS & Async CSS options if license is expired since more than 15 days + * + * @param mixed $value Current option value. + * + * @return mixed + */ + public function maybe_disable_option( $value ) { + $expired_since = ( time() - $this->user->get_license_expiration() ) / DAY_IN_SECONDS; + + if ( 15 > $expired_since ) { + return $value; + } + + return 0; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/License/ServiceProvider.php index 2d826f068..3505b3a95 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/ServiceProvider.php @@ -2,23 +2,16 @@ namespace WP_Rocket\Engine\License; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; -use WP_Rocket\Engine\License\API\PricingClient; -use WP_Rocket\Engine\License\API\Pricing; -use WP_Rocket\Engine\License\API\UserClient; -use WP_Rocket\Engine\License\API\User; -use WP_Rocket\Engine\License\Renewal; -use WP_Rocket\Engine\License\Subscriber; -use WP_Rocket\Engine\License\Upgrade; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\License\API\{PricingClient, Pricing, UserClient, User}; +use WP_Rocket\Engine\License\{Renewal, Upgrade, Subscriber}; /** * Service Provider for the License module - * - * @since 3.7.3 */ class ServiceProvider extends AbstractServiceProvider { /** - * Aliases the service provider provides + * Array of services provided by this service provider * * @var array */ @@ -32,31 +25,44 @@ class ServiceProvider extends AbstractServiceProvider { 'license_subscriber', ]; + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + /** * Registers items with the container * * @return void */ - public function register() { + public function register(): void { $views = __DIR__ . '/views'; $this->getContainer()->add( 'pricing_client', PricingClient::class ); $this->getContainer()->add( 'user_client', UserClient::class ) - ->withArgument( $this->getContainer()->get( 'options' ) ); - $this->getContainer()->share( 'pricing', Pricing::class ) - ->withArgument( $this->getContainer()->get( 'pricing_client' )->get_pricing_data() ); - $this->getContainer()->share( 'user', User::class ) - ->withArgument( $this->getContainer()->get( 'user_client' )->get_user_data() ); + ->addArgument( $this->getContainer()->get( 'options' ) ); + $this->getContainer()->addShared( 'pricing', Pricing::class ) + ->addArgument( $this->getContainer()->get( 'pricing_client' )->get_pricing_data() ); + $this->getContainer()->addShared( 'user', User::class ) + ->addArgument( $this->getContainer()->get( 'user_client' )->get_user_data() ); $this->getContainer()->add( 'upgrade', Upgrade::class ) - ->withArgument( $this->getContainer()->get( 'pricing' ) ) - ->withArgument( $this->getContainer()->get( 'user' ) ) - ->withArgument( $views ); + ->addArgument( $this->getContainer()->get( 'pricing' ) ) + ->addArgument( $this->getContainer()->get( 'user' ) ) + ->addArgument( $views ); $this->getContainer()->add( 'renewal', Renewal::class ) - ->withArgument( $this->getContainer()->get( 'pricing' ) ) - ->withArgument( $this->getContainer()->get( 'user' ) ) - ->withArgument( $views ); - $this->getContainer()->share( 'license_subscriber', Subscriber::class ) - ->withArgument( $this->getContainer()->get( 'upgrade' ) ) - ->withArgument( $this->getContainer()->get( 'renewal' ) ); + ->addArgument( $this->getContainer()->get( 'pricing' ) ) + ->addArgument( $this->getContainer()->get( 'user' ) ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $views ); + $this->getContainer()->addShared( 'license_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'upgrade' ) ) + ->addArgument( $this->getContainer()->get( 'renewal' ) ) + ->addTag( 'admin_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/License/Subscriber.php index 657097fd6..494b9e4f3 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/Subscriber.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\License; @@ -39,8 +40,14 @@ public static function get_subscribed_events() { return [ 'rocket_dashboard_license_info' => 'display_upgrade_section', 'rocket_settings_page_footer' => 'display_upgrade_popin', - 'rocket_menu_title' => 'add_notification_bubble', - 'admin_footer-settings_page_wprocket' => 'dismiss_notification_bubble', + 'rocket_menu_title' => [ + [ 'add_notification_bubble' ], + [ 'add_notification_bubble_expired' ], + ], + 'admin_footer-settings_page_wprocket' => [ + [ 'dismiss_notification_bubble' ], + [ 'set_dashboard_seen_transient' ], + ], 'rocket_before_dashboard_content' => [ [ 'display_promo_banner' ], [ 'display_renewal_soon_banner', 11 ], @@ -50,6 +57,12 @@ public static function get_subscribed_events() { 'wp_ajax_rocket_dismiss_renewal' => 'dismiss_renewal_banner', 'rocket_localize_admin_script' => 'add_localize_script_data', 'wp_rocket_upgrade' => [ 'clean_user_transient', 15, 2 ], + 'rocket_before_add_field_to_settings' => [ + [ 'maybe_disable_ocd', 11 ], + [ 'add_license_expire_warning' ], + ], + 'get_rocket_option_remove_unused_css' => [ 'maybe_disable_option', PHP_INT_MAX ], + 'get_rocket_option_async_css' => [ 'maybe_disable_option', PHP_INT_MAX ], ]; } @@ -184,4 +197,57 @@ public function display_renewal_expired_banner() { public function dismiss_renewal_banner() { $this->renewal->dismiss_renewal_expired_banner(); } + + /** + * Add license expiring warning to OCD label + * + * @param array $args Setting field arguments. + * + * @return array + */ + public function add_license_expire_warning( $args ): array { + return $this->renewal->add_license_expire_warning( $args ); + } + + /** + * Adds the notification bubble to WP Rocket menu item when expired + * + * @param string $menu_title Menu title. + * + * @return string + */ + public function add_notification_bubble_expired( $menu_title ) { + return $this->renewal->add_expired_bubble( $menu_title ); + } + + /** + * Sets the dashboard seen transient to hide the expired bubble + * + * @return void + */ + public function set_dashboard_seen_transient() { + $this->renewal->set_dashboard_seen_transient(); + } + + /** + * Disable optimize CSS delivery setting + * + * @param array $args Array of setting field arguments. + * + * @return array + */ + public function maybe_disable_ocd( $args ) { + return $this->renewal->maybe_disable_ocd( $args ); + } + + /** + * Disables the RUCSS & Async CSS options if license is expired + * + * @param mixed $value Current option value. + * + * @return mixed + */ + public function maybe_disable_option( $value ) { + return $this->renewal->maybe_disable_option( $value ); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/Upgrade.php b/wp-content/plugins/wp-rocket/inc/Engine/License/Upgrade.php index 4d854bf8c..4d811f5c5 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/Upgrade.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/Upgrade.php @@ -282,6 +282,10 @@ private function can_use_promo() { return false; } + if ( $this->is_new_user() ) { + return false; + } + return $this->pricing->is_promo_active(); } @@ -296,6 +300,15 @@ private function is_expired_soon() { return 30 * DAY_IN_SECONDS > $expiration_delay; } + /** + * Checks if the User license bought less than 14 days + * + * @return boolean + */ + private function is_new_user() { + return ( 14 * DAY_IN_SECONDS ) > time() - $this->user->get_creation_date(); + } + /** * Checks if the current license can upgrade * diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/views/promo-banner.php b/wp-content/plugins/wp-rocket/inc/Engine/License/views/promo-banner.php index 5fd0bda55..78c42b396 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/views/promo-banner.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/views/promo-banner.php @@ -33,5 +33,5 @@ </ul> <button class="rocket-promo-cta wpr-popin-upgrade-toggle"><?php esc_html_e( 'Upgrade now', 'rocket' ); ?></button> </div> - <button class="wpr-notice-close wpr-icon-close" id="rocket-dismiss-promotion"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'rocket' ); ?></span></button> + <button class="wpr-notice-close wpr-icon-close" id="rocket-dismiss-promotion"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice', 'rocket' ); ?></span></button> </div> diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner-ocd-disabled.php b/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner-ocd-disabled.php new file mode 100644 index 000000000..777030c6d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner-ocd-disabled.php @@ -0,0 +1,33 @@ +<?php +/** + * Renewal expired banner with OCD disabled. + * + * @since 3.11.5 + */ + +defined( 'ABSPATH' ) || exit; +?> +<section class="rocket-renewal-expired-banner" id="rocket-renewal-banner"> + <h3 class="rocket-expired-title"><?php esc_html_e( 'The Optimize CSS Delivery feature is disabled.', 'rocket' ); ?></h3> + <div class="rocket-renewal-expired-banner-container"> + <div class="rocket-expired-message"> + <p> + <?php esc_html_e( 'You can no longer use the Remove Unused CSS or Load CSS asynchronously options.', 'rocket' ); ?> + <br> + <?php + printf( + // translators: %1$s = <strong>, %2$s = </strong>. + esc_html__( 'You need an %1$sactive license%2$s to keep optimizing your CSS delivery, which addresses a PageSpeed Insights recommendation and improves your page performance.', 'rocket' ), + '<strong>', + '</strong>' + ); + ?> + </p> + <p><?php echo $data['message']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p> + </div> + <div class="rocket-expired-cta-container"> + <a href="<?php echo esc_url( $data['renewal_url'] ); ?>" class="rocket-renew-cta" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Renew now', 'rocket' ); ?></a> + </div> + </div> + <button class="wpr-notice-close wpr-icon-close" id="rocket-dismiss-renewal"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice', 'rocket' ); ?></span></button> +</section> diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner-ocd.php b/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner-ocd.php new file mode 100644 index 000000000..5aad300ed --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner-ocd.php @@ -0,0 +1,43 @@ +<?php +/** + * Renewal expired banner with OCD. + * + * @since 3.11.5 + */ + +defined( 'ABSPATH' ) || exit; +?> +<section class="rocket-renewal-expired-banner" id="rocket-renewal-banner"> + <h3 class="rocket-expired-title"><?php esc_html_e( 'You will soon lose access to some features.', 'rocket' ); ?></h3> + <div class="rocket-renewal-expired-banner-container"> + <div class="rocket-expired-message"> + <p> + <?php + printf( + // translators: %1$s = <strong>, %2$s = </strong>. + esc_html__( 'You need an %1$sactive license to continue optimizing your CSS delivery%2$s.', 'rocket' ), + '<strong>', + '</strong>' + ); + ?> + <br> + <?php esc_html_e( 'The Remove Unused CSS and Load CSS asynchronously features are great options to address the PageSpeed Insights recommendations and improve your website performance.', 'rocket' ); ?> + <br> + <?php + printf( + // translators: %1$s = <strong>, %2$s = </strong>, %3$s = date. + esc_html__( 'These features will be %1$sautomatically disabled on %3$s%2$s.', 'rocket' ), + '<strong>', + '</strong>', + esc_html( $data['disabled_date'] ) + ); + ?> + </p> + <p><?php echo $data['message']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p> + </div> + <div class="rocket-expired-cta-container"> + <a href="<?php echo esc_url( $data['renewal_url'] ); ?>" class="rocket-renew-cta" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Renew now', 'rocket' ); ?></a> + </div> + </div> + <button class="wpr-notice-close wpr-icon-close" id="rocket-dismiss-renewal"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice', 'rocket' ); ?></span></button> +</section> diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner.php b/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner.php index 8b186534e..c3572769d 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-expired-banner.php @@ -1,40 +1,31 @@ <?php /** - * Renewal soon banner. + * Renewal expired banner. * * @since 3.7.5 */ defined( 'ABSPATH' ) || exit; ?> -<div class="rocket-promo-banner" id="rocket-renewal-banner"> - <div class="rocket-expired-message"> - <h3 class="rocket-expired-title"><?php esc_html_e( 'Your WP Rocket license is expired!', 'rocket' ); ?></h3> - <p> - <?php - printf( - // translators: %1$s = <strong>, %2$s = </strong>. - esc_html__( 'Your website could be much faster if it could take advantage of our %1$snew features and enhancements.%2$s', 'rocket' ), - '<strong>', - '</strong>' - ); - ?> - </p> - <p> - <?php - printf( - // translators: %1$s = <strong>, %2$s = discount percentage, %3$s = </strong>, %4$s = discount price. - esc_html__( 'Renew your license for 1 year and get an immediate %1$s%2$s off%3$s on your renewal rate: you will only pay %1$s%4$s%3$s!', 'rocket' ), - '<strong>', - esc_html( $data['discount_percent'] . '%' ), - '</strong>', - esc_html( '$' . $data['discount_price'] ) - ); - ?> - </p> +<section class="rocket-renewal-expired-banner" id="rocket-renewal-banner"> + <h3 class="rocket-expired-title"><?php esc_html_e( 'Your WP Rocket license is expired!', 'rocket' ); ?></h3> + <div class="rocket-renewal-expired-banner-container"> + <div class="rocket-expired-message"> + <p> + <?php + printf( + // translators: %1$s = <strong>, %2$s = </strong>. + esc_html__( 'Your website could be much faster if it could take advantage of our %1$snew features and enhancements%2$s. 🚀', 'rocket' ), + '<strong>', + '</strong>' + ); + ?> + </p> + <p><?php echo $data['message']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p> + </div> + <div class="rocket-expired-cta-container"> + <a href="<?php echo esc_url( $data['renewal_url'] ); ?>" class="rocket-renew-cta" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Renew now', 'rocket' ); ?></a> + </div> </div> - <div class="rocket-expired-cta-container"> - <a href="<?php echo esc_url( $data['renewal_url'] ); ?>" class="rocket-renew-cta" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Renew now', 'rocket' ); ?></a> - </div> - <button class="wpr-notice-close wpr-icon-close" id="rocket-dismiss-renewal"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'rocket' ); ?></span></button> -</div> + <button class="wpr-notice-close wpr-icon-close" id="rocket-dismiss-renewal"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice', 'rocket' ); ?></span></button> +</section> diff --git a/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-soon-banner.php b/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-soon-banner.php index c9c544514..46bb3392d 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-soon-banner.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/License/views/renewal-soon-banner.php @@ -19,24 +19,13 @@ <?php printf( // translators: %1$s = <strong>, %2$s = </strong>. - esc_html__( 'Your %1$sWP Rocket license is about to expire.%2$s', 'rocket' ), + esc_html__( 'Your %1$sWP Rocket license is about to expire%2$s: you will soon lose access to product updates and support.', 'rocket' ), '<strong>', '</strong>' ); ?> </p> - <p> - <?php - printf( - // translators: %1$s = <strong>, %2$s = discount percentage, %3$s = </strong>, %4$s = discount price. - esc_html__( 'Renew with a %1$s%2$s discount%3$s before it is too late, you will only pay %1$s%4$s%3$s!', 'rocket' ), - '<strong>', - esc_html( $data['discount_percent'] . '%' ), - '</strong>', - esc_html( '$' . $data['discount_price'] ) - ); - ?> - </p> + <p><?php echo $data['message']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p> </div> <div class="rocket-renew-cta-container"> <a href="<?php echo esc_url( $data['renewal_url'] ); ?>" class="rocket-renew-cta" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Renew now', 'rocket' ); ?></a> diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/AJAX/Controller.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/AJAX/Controller.php new file mode 100644 index 000000000..7213182d8 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/AJAX/Controller.php @@ -0,0 +1,257 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\AJAX; + +use WP_Rocket\Engine\Media\AboveTheFold\Database\Queries\AboveTheFold as ATFQuery; +use WP_Rocket\Engine\Common\Context\ContextInterface; +use WP_Rocket\Engine\Optimization\UrlTrait; + +class Controller { + use UrlTrait; + + /** + * ATFQuery instance + * + * @var ATFQuery + */ + private $query; + + /** + * LCP Context. + * + * @var ContextInterface + */ + protected $context; + + /** + * Constructor + * + * @param ATFQuery $query ATFQuery instance. + * @param ContextInterface $context Context interface. + */ + public function __construct( ATFQuery $query, ContextInterface $context ) { + $this->query = $query; + $this->context = $context; + } + + /** + * Add LCP data to the database + * + * @return bool + */ + public function add_lcp_data() { + check_ajax_referer( 'rocket_lcp', 'rocket_lcp_nonce' ); + + if ( ! $this->context->is_allowed() ) { + wp_send_json_error( 'not allowed' ); + return; + } + + $url = isset( $_POST['url'] ) ? untrailingslashit( esc_url_raw( wp_unslash( $_POST['url'] ) ) ) : ''; + $is_mobile = isset( $_POST['is_mobile'] ) ? filter_var( wp_unslash( $_POST['is_mobile'] ), FILTER_VALIDATE_BOOLEAN ) : false; + $images = isset( $_POST['images'] ) ? json_decode( wp_unslash( $_POST['images'] ) ) : []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + $lcp = 'not found'; + $viewport = []; + + /** + * Filters the maximum number of ATF images being saved into the database. + * + * @param int $max_number Maximum number to allow. + * @param string $url Current page url. + * @param string[]|array $images Current list of ATF images. + */ + $max_atf_images_number = (int) apply_filters( 'rocket_atf_images_number', 20, $url, $images ); + if ( 0 >= $max_atf_images_number ) { + $max_atf_images_number = 1; + } + + $keys = [ 'bg_set', 'src' ]; + + foreach ( (array) $images as $image ) { + if ( isset( $image->type ) ) { + $image_object = $this->create_object( $image, $keys ); + + if ( 'lcp' === $image->label && null !== $image_object ) { + $lcp = $image_object; + } elseif ( 'above-the-fold' === $image->label && null !== $image_object ) { + if ( 0 === $max_atf_images_number ) { + continue; + } + + $viewport[] = $image_object; + + --$max_atf_images_number; + } + } + } + + $row = $this->query->get_row( $url, $is_mobile ); + + if ( ! empty( $row ) ) { + wp_send_json_error( 'item already in the database' ); + return; + } + + $status = isset( $_POST['status'] ) ? sanitize_text_field( wp_unslash( $_POST['status'] ) ) : ''; + list( $status_code, $status_message ) = $this->get_status_code_message( $status ); + + $item = [ + 'url' => $url, + 'is_mobile' => $is_mobile, + 'status' => $status_code, + 'error_message' => $status_message, + 'lcp' => ( is_array( $lcp ) || is_object( $lcp ) ) ? wp_json_encode( $lcp ) : $lcp, + 'viewport' => wp_json_encode( $viewport ), + 'last_accessed' => current_time( 'mysql', true ), + ]; + + $result = $this->query->add_item( $item ); + + if ( ! $result ) { + wp_send_json_error( 'error when adding the entry to the database' ); + return; + } + + wp_send_json_success( $item ); + } + + /** + * Get status code and message to be saved into the database + * + * @param string $status Current status code from $_POST. + * @return array + */ + private function get_status_code_message( $status ) { + $status_code = 'success' !== $status ? 'failed' : 'completed'; + $status_message = ''; + + switch ( $status ) { + case 'script_error': + $status_message = esc_html__( 'Script error', 'rocket' ); + break; + case 'timeout': + $status_message = esc_html__( 'Script timeout', 'rocket' ); + break; + } + + return [ + $status_code, + $status_message, + ]; + } + + /** + * Creates an object with the 'type' property and the first key that exists in the image object. + * + * @param object $image The image object. + * @param array $keys An array of keys in the order of their priority. + * + * @return object|null Returns an object with the 'type' property and the first key that exists in the image object. If none of the keys exist in the image object, it returns null. + */ + private function create_object( $image, $keys ) { + $object = new \stdClass(); + $object->type = $image->type ?? 'img'; + + switch ( $object->type ) { + case 'img-srcset': + // If the type is 'img-srcset', add all the required parameters to the object. + if ( isset( $image->src ) && ! empty( $image->src ) && is_string( $image->src ) ) { + $object->src = $this->sanitize_image_url( $image->src ); + } + $object->srcset = $image->srcset; + $object->sizes = $image->sizes; + break; + case 'picture': + if ( isset( $image->src ) && ! empty( $image->src ) && is_string( $image->src ) ) { + $object->src = $this->sanitize_image_url( $image->src ); + } + $object->sources = $image->sources; + break; + default: + // For other types, add the first non-empty key to the object. + foreach ( $keys as $key ) { + if ( isset( $image->$key ) && ! empty( $image->$key ) ) { + if ( is_array( $image->$key ) ) { + $sanitized_array = array_map( + function ( $item ) { + if ( ! empty( $item->src ) ) { + $item->src = $this->sanitize_image_url( $item->src ); + } + return $item; + }, + $image->$key + ); + + $object->$key = $sanitized_array; + + } else { + $object->$key = $this->sanitize_image_url( $image->$key ); + } + break; + } + } + break; + } + + // If none of the keys exist in the image object, return null. + if ( count( (array) $object ) <= 1 ) { + return null; + } + + // Returned objects must always have a src for front-end optimization. + // Except bg-img and bg-img-set for which we use bg_set only. + // To keep it simple and safe for now, we enforce src for all, pending a refactor. + if ( ! isset( $object->src ) ) { + $object->src = ''; + } + + return $object; + } + + /** + * Sanitize image url before saving them into database. + * + * @param string $url The image url. + * @return string + */ + private function sanitize_image_url( string $url ) { + $sanitize_url = esc_url_raw( $url ); + if ( $this->is_relative( $url ) && strpos( $url, '/' ) !== 0 ) { + $sanitize_url = esc_url_raw( '/' . $url ); + $sanitize_url = substr( $sanitize_url, 1 ); + } + + return $sanitize_url; + } + + /** + * Checks if there is existing LCP data for the current URL and device type. + * + * This method is called via AJAX. It checks if there is existing LCP data for the current URL and device type. + * If the data exists, it returns a JSON success response with true. If the data does not exist, it returns a JSON success response with false. + * If the context is not allowed, it returns a JSON error response with false. + * + * @return void + */ + public function check_lcp_data() { + check_ajax_referer( 'rocket_lcp', 'rocket_lcp_nonce' ); + + if ( ! $this->context->is_allowed() ) { + wp_send_json_error( false ); + return; + } + + $url = isset( $_POST['url'] ) ? untrailingslashit( esc_url_raw( wp_unslash( $_POST['url'] ) ) ) : ''; + $is_mobile = isset( $_POST['is_mobile'] ) ? filter_var( wp_unslash( $_POST['is_mobile'] ), FILTER_VALIDATE_BOOLEAN ) : false; + + $row = $this->query->get_row( $url, $is_mobile ); + + if ( ! empty( $row ) ) { + wp_send_json_success( 'data already exists' ); + return; + } + + wp_send_json_error( 'data does not exist' ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/AJAX/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/AJAX/Subscriber.php new file mode 100644 index 000000000..6a070c454 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/AJAX/Subscriber.php @@ -0,0 +1,56 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\AJAX; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + /** + * Controller instance + * + * @var Controller + */ + private $controller; + + /** + * Constructor + * + * @param Controller $controller Controller instance. + */ + public function __construct( Controller $controller ) { + $this->controller = $controller; + } + + /** + * Array of events this subscriber listens to + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'wp_ajax_rocket_lcp' => 'add_lcp_data', + 'wp_ajax_nopriv_rocket_lcp' => 'add_lcp_data', + 'wp_ajax_rocket_check_lcp' => 'check_lcp_data', + 'wp_ajax_nopriv_rocket_check_lcp' => 'check_lcp_data', + ]; + } + + /** + * Callback for data received from lcp script + * + * @return void + */ + public function add_lcp_data() { + $this->controller->add_lcp_data(); + } + + /** + * Callback for checking lcp data + * + * @return void + */ + public function check_lcp_data() { + $this->controller->check_lcp_data(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Activation/Activation.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Activation/Activation.php new file mode 100644 index 000000000..5075a5be2 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Activation/Activation.php @@ -0,0 +1,55 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Activation; + +use WP_Rocket\Engine\Activation\ActivationInterface; +use WP_Rocket\Engine\Media\AboveTheFold\WarmUp\Controller; +use WP_Rocket\Engine\Common\Context\ContextInterface; + +class Activation implements ActivationInterface { + /** + * WarmUp controller + * + * @var Controller + */ + private $controller; + + /** + * ATF context. + * + * @var ContextInterface + */ + private $context; + + /** + * Instantiate class. + * + * @param Controller $controller Controller instance. + * @param ContextInterface $context ATF Context. + */ + public function __construct( Controller $controller, ContextInterface $context ) { + $this->controller = $controller; + $this->context = $context; + } + + /** + * Add actions on activation. + */ + public function activate() { + add_action( 'rocket_after_activation', [ $this, 'warm_up' ] ); + } + + /** + * Start warm up. + * + * @return void + */ + public function warm_up() { + if ( ! $this->context->is_allowed() ) { + return; + } + + $this->controller->warm_up_home(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Activation/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Activation/ServiceProvider.php new file mode 100644 index 000000000..f768ba299 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Activation/ServiceProvider.php @@ -0,0 +1,75 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Activation; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Media\AboveTheFold\Context\Context; +use WP_Rocket\Engine\Media\AboveTheFold\WarmUp\{ + APIClient, + Controller as WarmUpController, + Queue +}; + +class ServiceProvider extends AbstractServiceProvider { + /** + * The provides array is a way to let the container + * know that a service is provided by this service + * provider. Every service that is registered via + * this service provider must have an alias added + * to this array or it will be ignored. + * + * @var array + */ + protected $provides = [ + 'atf_context', + 'warmup_apiclient', + 'warmup_controller', + 'atf_activation', + 'warmup_queue', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container + * + * @return void + */ + public function register(): void { + $this->getContainer()->add( 'atf_context', Context::class ); + + $this->getContainer()->add( 'warmup_apiclient', APIClient::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + + $this->getContainer()->add( 'warmup_queue', Queue::class ); + + $this->getContainer()->add( 'warmup_controller', WarmUpController::class ) + ->addArguments( + [ + $this->getContainer()->get( 'atf_context' ), + $this->getContainer()->get( 'options' ), + $this->getContainer()->get( 'warmup_apiclient' ), + $this->getContainer()->get( 'user' ), + $this->getContainer()->get( 'warmup_queue' ), + ] + ); + + $this->getContainer()->add( 'atf_activation', Activation::class ) + ->addArguments( + [ + $this->getContainer()->get( 'warmup_controller' ), + $this->getContainer()->get( 'atf_context' ), + ] + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Admin/Controller.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Admin/Controller.php new file mode 100644 index 000000000..a1ebd78e2 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Admin/Controller.php @@ -0,0 +1,168 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Admin; + +use WP_Rocket\Engine\Media\AboveTheFold\Context\Context; +use WP_Rocket\Engine\Media\AboveTheFold\Database\Tables\AboveTheFold as ATFTable; +use WP_Rocket\Engine\Media\AboveTheFold\Database\Queries\AboveTheFold as ATFQuery; + +class Controller { + /** + * ATF Table instance + * + * @var ATFTable + */ + private $table; + + /** + * ATF Query instance + * + * @var ATFQuery + */ + private $query; + + /** + * Context instance + * + * @var Context + */ + private $context; + + /** + * Constructor + * + * @param ATFTable $table Table instance. + * @param ATFQuery $query ATF Query instance. + * @param Context $context Context instance. + */ + public function __construct( ATFTable $table, ATFQuery $query, Context $context ) { + $this->table = $table; + $this->query = $query; + $this->context = $context; + } + + /** + * Truncate delete ATF DB table. + * + * @return void + */ + public function truncate_atf() { + if ( ! $this->context->is_allowed() ) { + return; + } + + $this->delete_rows(); + } + + /** + * Deletes the rows from the table + * + * @return void + */ + private function delete_rows() { + if ( 0 < $this->query->get_not_completed_count() ) { + $this->table->remove_all_completed_rows(); + return; + } + + $this->table->truncate_atf_table(); + + /** + * Fires after clearing lcp & atf data. + */ + do_action( 'rocket_after_clear_atf' ); + } + + /** + * Delete ATF row on update Post or delete post. + * + * @param int $post_id The post ID. + * + * @return void + */ + public function delete_post_atf( $post_id ) { + if ( ! $this->context->is_allowed() ) { + return; + } + + $url = get_permalink( $post_id ); + + if ( false === $url ) { + return; + } + + $this->query->delete_by_url( untrailingslashit( $url ) ); + } + + /** + * Deletes the ATF when updating a term + * + * @param int $term_id the term ID. + * + * @return void + */ + public function delete_term_atf( $term_id ) { + if ( ! $this->context->is_allowed() ) { + return; + } + + $url = get_term_link( (int) $term_id ); + + if ( is_wp_error( $url ) ) { + return; + } + + $this->query->delete_by_url( untrailingslashit( $url ) ); + } + + /** + * Deletes rows when triggering clean from admin + * + * @param array $clean An array containing the status and message. + * + * @return array + */ + public function truncate_atf_admin( $clean ) { + if ( ! $this->context->is_allowed() ) { + return $clean; + } + + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return [ + 'status' => 'die', + ]; + } + + $this->delete_rows(); + + return [ + 'status' => 'success', + 'message' => sprintf( + // translators: %1$s = plugin name. + __( '%1$s: Critical images cleared!', 'rocket' ), + '<strong>WP Rocket</strong>' + ), + ]; + } + + /** + * Cleans rows for the current URL. + * + * @return void + */ + public function clean_url() { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + wp_nonce_ays( '' ); + } + + $url = wp_get_referer(); + + if ( 0 !== strpos( $url, 'http' ) ) { + $parse_url = get_rocket_parse_url( untrailingslashit( home_url() ) ); + $url = $parse_url['scheme'] . '://' . $parse_url['host'] . $url; + } + + $this->query->delete_by_url( untrailingslashit( $url ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Admin/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Admin/Subscriber.php new file mode 100644 index 000000000..bc1ca32a9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Admin/Subscriber.php @@ -0,0 +1,96 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Admin; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + /** + * Admin controller instance + * + * @var Controller + */ + private $controller; + + /** + * Constructor + * + * @param Controller $controller ATF Admin controller instance. + */ + public function __construct( Controller $controller ) { + $this->controller = $controller; + } + + /** + * Array of events this subscriber listens to + * + * @return array + */ + public static function get_subscribed_events(): array { + return [ + 'switch_theme' => 'truncate_atf', + 'permalink_structure_changed' => 'truncate_atf', + 'rocket_domain_options_changed' => 'truncate_atf', + 'wp_trash_post' => 'delete_post_atf', + 'delete_post' => 'delete_post_atf', + 'clean_post_cache' => 'delete_post_atf', + 'wp_update_comment_count' => 'delete_post_atf', + 'edit_term' => 'delete_term_atf', + 'pre_delete_term' => 'delete_term_atf', + 'rocket_saas_clean_all' => 'truncate_atf_admin', + 'rocket_saas_clean_url' => 'clean_url', + ]; + } + + /** + * Truncate delete ATF DB table. + * + * @return void + */ + public function truncate_atf() { + $this->controller->truncate_atf(); + } + + /** + * Delete ATF row on update Post or delete post. + * + * @param int $post_id The post ID. + * + * @return void + */ + public function delete_post_atf( $post_id ) { + $this->controller->delete_post_atf( $post_id ); + } + + /** + * Delete ATF row on update or delete term. + * + * @param int $term_id the term ID. + * + * @return void + */ + public function delete_term_atf( $term_id ) { + $this->controller->delete_term_atf( $term_id ); + } + + /** + * Deletes rows when triggering clean from admin + * + * @param array $clean An array containing the status and message. + * + * @return array + */ + public function truncate_atf_admin( $clean ) { + return $this->controller->truncate_atf_admin( $clean ); + } + + /** + * Cleans rows for the current URL. + * + * @return void + */ + public function clean_url() { + $this->controller->clean_url(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Context/Context.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Context/Context.php new file mode 100644 index 000000000..edb3a385d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Context/Context.php @@ -0,0 +1,34 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Context; + +use WP_Rocket\Engine\Common\Context\ContextInterface; + +class Context implements ContextInterface { + /** + * Determine if the action is allowed. + * + * @param array $data Data to pass to the context. + * @return bool + */ + public function is_allowed( array $data = [] ): bool { + + if ( get_option( 'wp_rocket_no_licence' ) ) { + return false; + } + + /** + * Filters to manage above the fold optimization + * + * @param bool $allow True to allow, false otherwise. + */ + $is_atf_enabled = apply_filters( 'rocket_above_the_fold_optimization', true ); + + if ( ! is_bool( $is_atf_enabled ) ) { + return true; + } + + return $is_atf_enabled; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Cron/Controller.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Cron/Controller.php new file mode 100644 index 000000000..982b6567e --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Cron/Controller.php @@ -0,0 +1,65 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Cron; + +use WP_Rocket\Engine\Media\AboveTheFold\Database\Queries\AboveTheFold as ATFQuery; +use WP_Rocket\Engine\Optimization\RegexTrait; + + +/** + * The Controller class is responsible for scheduling, executing, and unscheduling the 'above the fold' cleanup. + * + * It uses the RegexTrait for regular expression related methods. + * It has private properties for ATFTable, ATFQuery, and Context instances. + */ +class Controller { + use RegexTrait; + + /** + * Instance of the ATFQuery class. + * + * @var ATFQuery + */ + private $query; + + + /** + * Constructor method. + * Initializes a new instance of the Controller class. + * + * @param ATFQuery $query An instance of the ATFQuery class. + */ + public function __construct( ATFQuery $query ) { + $this->query = $query; + } + + /** + * Schedules the 'above the fold' cleanup to run daily if it's not already scheduled. + */ + public function schedule_atf_cleanup() { + if ( ! wp_next_scheduled( 'rocket_atf_cleanup' ) ) { + wp_schedule_event( time(), 'daily', 'rocket_atf_cleanup' ); + } + } + + /** + * Executes the 'above the fold' cleanup. + * It gets the current date and subtracts the interval (default to 1 month) from it. + * Then it deletes the rows with 'failed' status or not accessed since the interval. + */ + public function atf_cleanup() { + // Delete the rows with failed status or not accessed. + $this->query->delete_old_rows(); + } + + /** + * Unschedules the 'above the fold' cleanup, preventing it from running at the previously scheduled time. + */ + public function unschedule_atf_cleanup() { + $timestamp = wp_next_scheduled( 'rocket_atf_cleanup' ); + if ( $timestamp ) { + wp_unschedule_event( $timestamp, 'rocket_atf_cleanup' ); + } + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Cron/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Cron/Subscriber.php new file mode 100644 index 000000000..5eea55118 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Cron/Subscriber.php @@ -0,0 +1,70 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Cron; + +use WP_Rocket\Event_Management\Subscriber_Interface; + + +/** + * The Subscriber class implements the Subscriber_Interface. + * It provides methods for scheduling, executing, and unscheduling the 'above the fold' cleanup. + */ +class Subscriber implements Subscriber_Interface { + /** + * Instance of the Controller class + * + * @var Controller + */ + private $controller; + + /** + * Constructor method. + * Initializes a new instance of the Subscriber class. + * + * @param Controller $controller An instance of the Controller class. + */ + public function __construct( Controller $controller ) { + $this->controller = $controller; + } + + /** + * Returns an array of events that this class subscribes to. + * + * @return array An associative array where the keys are the event names and the values are the method names to call when the event is triggered. + */ + public static function get_subscribed_events() { + return [ + 'rocket_atf_cleanup' => 'atf_cleanup', + 'init' => 'schedule_atf_cleanup', + 'rocket_deactivation' => 'unschedule_atf_cleanup', + ]; + } + + /** + * Executes the 'above the fold' cleanup. + * + * @return void + */ + public function atf_cleanup() { + $this->controller->atf_cleanup(); + } + + /** + * Schedules the 'above the fold' cleanup to run at a later time. + * + * @return void + */ + public function schedule_atf_cleanup() { + $this->controller->schedule_atf_cleanup(); + } + + /** + * Unschedules the 'above the fold' cleanup, preventing it from running at the previously scheduled time. + * + * @return void + */ + public function unschedule_atf_cleanup() { + $this->controller->unschedule_atf_cleanup(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Queries/AboveTheFold.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Queries/AboveTheFold.php new file mode 100644 index 000000000..74d539fa4 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Queries/AboveTheFold.php @@ -0,0 +1,140 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Database\Queries; + +use WP_Rocket\Engine\Common\Database\Queries\AbstractQuery; +use WP_Rocket\Engine\Media\AboveTheFold\Database\Schemas\AboveTheFold as AboveTheFoldSchema; +use WP_Rocket\Engine\Media\AboveTheFold\Database\Rows\AboveTheFold as AboveTheFoldRow; + +class AboveTheFold extends AbstractQuery { + + /** + * Name of the database table to query. + * + * @var string + */ + protected $table_name = 'wpr_above_the_fold'; + + /** + * String used to alias the database table in MySQL statement. + * + * Keep this short, but descriptive. I.E. "tr" for term relationships. + * + * This is used to avoid collisions with JOINs. + * + * @var string + */ + protected $table_alias = 'wpr_atf'; + + /** + * Name of class used to setup the database schema. + * + * @var string + */ + protected $table_schema = AboveTheFoldSchema::class; + + /** Item ******************************************************************/ + + /** + * Name for a single item. + * + * Use underscores between words. I.E. "term_relationship" + * + * This is used to automatically generate action hooks. + * + * @var string + */ + protected $item_name = 'above_the_fold'; + + /** + * Plural version for a group of items. + * + * Use underscores between words. I.E. "term_relationships" + * + * This is used to automatically generate action hooks. + * + * @var string + */ + protected $item_name_plural = 'above_the_fold'; + + /** + * Name of class used to turn IDs into first-class objects. + * + * This is used when looping through return values to guarantee their shape. + * + * @var mixed + */ + protected $item_shape = AboveTheFoldRow::class; + + /** + * Complete a job. + * + * @param string $url Url from DB row. + * @param boolean $is_mobile Is mobile from DB row. + * @param array $data LCP & Above the fold data. + * + * @return boolean|int + */ + public function make_job_completed( string $url, bool $is_mobile, array $data ) { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return false; + } + + // Get the database interface. + $db = $this->get_db(); + + // Bail if no database interface is available. + if ( empty( $db ) ) { + return false; + } + + $prefixed_table_name = $db->prefix . $this->table_name; + + $data = [ + 'status' => 'completed', + 'lcp' => $data['lcp'], + 'viewport' => $data['viewport'], + ]; + + $where = [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + ]; + + return $db->update( $prefixed_table_name, $data, $where ); + } + + /** + * Delete all rows which were not accessed in the last month. + * + * @return bool|int + */ + public function delete_old_rows() { + // Get the database interface. + $db = $this->get_db(); + + // Bail if no database interface is available. + if ( empty( $db ) ) { + return false; + } + + /** + * Filters the interval (in months) to determine when an Above The Fold (ATF) entry is considered 'old'. + * Old ATF entries are eligible for deletion. By default, an ATF entry is considered old if it hasn't been accessed in the last month. + * + * @param int $delete_interval The interval in months after which an ATF entry is considered old. Default is 1 month. + */ + $delete_interval = (int) apply_filters( 'rocket_atf_cleanup_interval', 1 ); + + if ( $delete_interval <= 0 ) { + return false; + } + + $prefixed_table_name = $db->prefix . $this->table_name; + $query = "DELETE FROM `$prefixed_table_name` WHERE status = 'failed' OR `last_accessed` <= date_sub(now(), interval $delete_interval month)"; + $rows_affected = $db->query( $query ); + + return $rows_affected; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Rows/AboveTheFold.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Rows/AboveTheFold.php new file mode 100644 index 000000000..3b4b6d708 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Rows/AboveTheFold.php @@ -0,0 +1,112 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Database\Rows; + +use WP_Rocket\Dependencies\Database\Row; + +class AboveTheFold extends Row { + /** + * Row ID + * + * @var int + */ + public $id; + + /** + * URL + * + * @var string + */ + public $url; + + /** + * LCP + * + * @var string + */ + public $lcp; + + /** + * Viewport + * + * @var string + */ + public $viewport; + + /** + * Is CSS for mobile + * + * @var bool + */ + public $is_mobile; + + /** + * Error message + * + * @var string + */ + public $error_message; + + /** + * Status + * + * @var string + */ + public $status; + + /** + * Last modified time + * + * @var int + */ + public $modified; + + /** + * Last accessed time + * + * @var int + */ + public $last_accessed; + + /** + * Constructor. + * + * @param mixed $item Object Row. + */ + public function __construct( $item ) { + parent::__construct( $item ); + + // Set the type of each column, and prepare. + $this->id = (int) $this->id; + $this->url = (string) $this->url; + $this->lcp = (string) $this->lcp; + $this->viewport = (string) $this->viewport; + $this->error_message = (string) $this->error_message; + $this->is_mobile = (bool) $this->is_mobile; + $this->status = (string) $this->status; + $this->modified = empty( $this->modified ) ? 0 : strtotime( (string) $this->modified ); + $this->last_accessed = empty( $this->last_accessed ) ? 0 : strtotime( (string) $this->last_accessed ); + } + + /** + * Checks if the object has a valid LCP (Largest Contentful Paint) value. + * + * @return bool Returns true if the object's status is 'completed' and the LCP value is not empty or 'not found', false otherwise. + */ + public function has_lcp() { + if ( 'completed' !== $this->status ) { + return false; + } + + if ( empty( $this->lcp ) ) { + return false; + } + + if ( 'not found' === $this->lcp ) { + return false; + } + + return true; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Schemas/AboveTheFold.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Schemas/AboveTheFold.php new file mode 100644 index 000000000..a62623002 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Schemas/AboveTheFold.php @@ -0,0 +1,111 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Database\Schemas; + +use WP_Rocket\Dependencies\Database\Schema; + +class AboveTheFold extends Schema { + + /** + * Array of database column objects + * + * @var array + */ + public $columns = [ + + // ID column. + [ + 'name' => 'id', + 'type' => 'bigint', + 'length' => '20', + 'unsigned' => true, + 'extra' => 'auto_increment', + 'primary' => true, + 'sortable' => true, + ], + + // URL column. + [ + 'name' => 'url', + 'type' => 'varchar', + 'length' => '2000', + 'default' => '', + 'cache_key' => true, + 'searchable' => true, + 'sortable' => true, + ], + + // LCP column. + [ + 'name' => 'lcp', + 'type' => 'longtext', + 'default' => '', + 'cache_key' => false, + 'searchable' => true, + 'sortable' => true, + ], + + // Viewport column. + [ + 'name' => 'viewport', + 'type' => 'longtext', + 'default' => '', + 'cache_key' => false, + 'searchable' => true, + 'sortable' => true, + ], + + // IS_MOBILE column. + [ + 'name' => 'is_mobile', + 'type' => 'tinyint', + 'length' => '1', + 'default' => 0, + 'cache_key' => true, + 'searchable' => true, + 'sortable' => true, + ], + + // error_message column. + [ + 'name' => 'error_message', + 'type' => 'longtext', + 'default' => null, + 'cache_key' => false, + 'searchable' => true, + 'sortable' => true, + ], + + // STATUS column. + [ + 'name' => 'status', + 'type' => 'varchar', + 'length' => '255', + 'default' => null, + 'cache_key' => true, + 'searchable' => true, + 'sortable' => false, + ], + + // MODIFIED column. + [ + 'name' => 'modified', + 'type' => 'timestamp', + 'default' => '0000-00-00 00:00:00', + 'created' => true, + 'date_query' => true, + 'sortable' => true, + ], + + // LAST_ACCESSED column. + [ + 'name' => 'last_accessed', + 'type' => 'timestamp', + 'default' => '0000-00-00 00:00:00', + 'created' => true, + 'date_query' => true, + 'sortable' => true, + ], + ]; +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Tables/AboveTheFold.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Tables/AboveTheFold.php new file mode 100644 index 000000000..01f40efa6 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Database/Tables/AboveTheFold.php @@ -0,0 +1,102 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Database\Tables; + +use WP_Rocket\Engine\Common\Database\Tables\AbstractTable; + +class AboveTheFold extends AbstractTable { + /** + * Table name + * + * @var string + */ + protected $name = 'wpr_above_the_fold'; + + /** + * Database version key (saved in _options or _sitemeta) + * + * @var string + */ + protected $db_version_key = 'wpr_above_the_fold_version'; + + /** + * Database version + * + * @var int + */ + protected $version = 20240313; + + /** + * Key => value array of versions => methods. + * + * @var array + */ + protected $upgrades = [ + 20240313 => 'delete_old_atf_implementation', + ]; + /** + * Table schema data. + * + * @var string + */ + protected $schema_data = " + id bigint(20) unsigned NOT NULL AUTO_INCREMENT, + url varchar(2000) NOT NULL default '', + is_mobile tinyint(1) NOT NULL default 0, + lcp longtext default '', + viewport longtext default '', + error_message longtext NULL default NULL, + status varchar(255) NOT NULL default '', + modified timestamp NOT NULL default '0000-00-00 00:00:00', + last_accessed timestamp NOT NULL default '0000-00-00 00:00:00', + PRIMARY KEY (id), + KEY url (url(150), is_mobile), + KEY modified (modified), + KEY last_accessed (last_accessed), + INDEX `status_index` (`status`(191))"; + + /** + * Truncate DB table. + * + * @return bool + */ + public function truncate_atf_table(): bool { + if ( ! $this->exists() ) { + return false; + } + + return $this->truncate(); + } + + /** + * This function is responsible for deleting old columns from the 'wpr_above_the_fold' table. + * The columns to be deleted are: 'error_code', 'retries', 'job_id', 'queue_name', 'submitted_at', 'next_retry_time'. + * + * @return bool Returns true if all specified columns are successfully deleted or do not exist, false otherwise. + */ + public function delete_old_atf_implementation() { + // An array of column names to be deleted. + $columns_to_delete = [ 'error_code', 'retries', 'job_id', 'queue_name', 'submitted_at', 'next_retry_time' ]; + + // A flag to indicate the success of the operation. It is initially set to true. + $is_successful = true; + + // Iterate over each column name in the array. + foreach ( $columns_to_delete as $column ) { + // Check if the column exists in the table. + if ( $this->column_exists( $column ) ) { + // If the column exists, attempt to delete it. + $query_result = $this->get_db()->query( "ALTER TABLE `{$this->table_name}` DROP COLUMN `{$column}`" ); + + // If the deletion query fails, set the success flag to false. + if ( false === $query_result ) { + $is_successful = false; + } + } + } + + // Return the success flag. If all deletion queries were successful (or the columns did not exist), this will be true. If any query failed, this will be false. + return $is_successful; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Frontend/Controller.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Frontend/Controller.php new file mode 100644 index 000000000..1259d2faa --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Frontend/Controller.php @@ -0,0 +1,553 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Frontend; + +use WP_Filesystem_Direct; +use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Media\AboveTheFold\Database\Queries\AboveTheFold as ATFQuery; +use WP_Rocket\Engine\Media\AboveTheFold\Context\Context; +use WP_Rocket\Engine\Optimization\RegexTrait; +use WP_Rocket\Engine\Optimization\UrlTrait; + +class Controller { + use RegexTrait; + use UrlTrait; + + /** + * Options instance + * + * @var Options_Data + */ + private $options; + + /** + * Queries instance + * + * @var ATFQuery + */ + private $query; + + /** + * Context instance. + * + * @var Context + */ + private $context; + + /** + * WordPress filesystem. + * + * @var WP_Filesystem_Direct + */ + protected $filesystem; + + /** + * Constructor + * + * @param Options_Data $options Options instance. + * @param ATFQuery $query Queries instance. + * @param Context $context Context instance. + * @param WP_Filesystem_Direct|null $filesystem WordPress filesystem. + */ + public function __construct( Options_Data $options, ATFQuery $query, Context $context, WP_Filesystem_Direct $filesystem = null ) { + $this->options = $options; + $this->query = $query; + $this->context = $context; + $this->filesystem = $filesystem ?: rocket_direct_filesystem(); + } + + /** + * Optimize the LCP image + * + * @param string $html HTML content. + * + * @return string + */ + public function lcp( $html ): string { + if ( ! $this->context->is_allowed() ) { + return $html; + } + + global $wp; + + $url = untrailingslashit( home_url( add_query_arg( [], $wp->request ) ) ); + $is_mobile = $this->is_mobile(); + $row = $this->query->get_row( $url, $is_mobile ); + + if ( empty( $row ) ) { + return $this->inject_beacon( $html, $url, $is_mobile ); + } + + if ( ! $row->has_lcp() ) { + return $html; + } + + return $this->preload_lcp( $html, $row ); + } + + /** + * Preload the LCP image + * + * @param string $html HTML content. + * @param object $row Corresponding DB row. + * + * @return string + */ + private function preload_lcp( $html, $row ) { + if ( rocket_bypass() ) { // Bail out if rocket_bypass() returns true. + return $html; + } + + if ( ! preg_match( '#</title\s*>#', $html, $matches ) ) { + return $html; + } + + $title = $matches[0]; + $preload = $title; + + $lcp = json_decode( $row->lcp ); + + $preload .= $this->preload_tag( $lcp ); + + $replace = preg_replace( '#' . $title . '#', $preload, $html, 1 ); + + if ( null === $replace ) { + return $html; + } + + $replace = $this->set_fetchpriority( $lcp, $replace ); + + return $replace; + } + + /** + * Builds the preload tag + * + * @param object $lcp LCP object. + * + * @return string + */ + private function preload_tag( $lcp ): string { + $tags = $this->generate_lcp_link_tag_with_sources( $lcp ); + return $tags['tags']; + } + + /** + * Alters the preload element tag (img|img-srcset) + * + * @param object $lcp LCP object. + * @param string $html HTML content. + * @return string + */ + private function set_fetchpriority( $lcp, string $html ): string { + $allowed_types = [ + 'img', + 'img-srcset', + 'picture', + ]; + + if ( empty( $lcp ) || empty( $lcp->type ) || ! in_array( $lcp->type, $allowed_types, true ) ) { + return $html; + } + + $html = $this->replace_html_comments( $html ); + $url = urldecode( preg_quote( $lcp->src, '/' ) ); + $pattern = '#<img(?:[^>]*?\s+)?src=["\']' . $url . '["\'](?:\s+[^>]*?)?>#'; + if ( wp_http_validate_url( $lcp->src ) && ! $this->is_external_file( $lcp->src ) ) { + $url = preg_quote( + wp_parse_url( $lcp->src, PHP_URL_PATH ), + '/' + ); + + $pattern = '#<img(?:[^>]*?\s+)?src\s*=\s*["\'](?:https?:)?(?:\/\/(?:[^\/]+)\/?)?\/?' . $url . '["\'](?:\s+[^>]*?)?>#i'; + } + + $html = preg_replace_callback( + $pattern, + function ( $matches ) { + // Check if the fetchpriority attribute already exists. + if ( preg_match( '/<img[^>]*\sfetchpriority(?:\s*=\s*["\'][^"\']*["\'])?[^>]*>/i', $matches[0] ) ) { + // If it exists, don't modify the tag. + return $matches[0]; + } + + // If it doesn't exist, add the fetchpriority attribute. + $replace = preg_replace( '/<img/', '<img fetchpriority="high"', $matches[0] ); + + if ( null === $replace ) { + return $matches[0]; + } + + return $replace; + }, + $html, + 1 + ); + + return $this->restore_html_comments( $html ); + } + + /** + * Add above the fold images to lazyload exclusions + * + * @param array $exclusions Array of excluded patterns. + * + * @return array + */ + public function add_exclusions( $exclusions ): array { + if ( ! $this->context->is_allowed() ) { + return $exclusions; + } + + list($atf, $lcp) = [ [], [] ]; + + global $wp; + + $url = untrailingslashit( home_url( add_query_arg( [], $wp->request ) ) ); + + $row = $this->query->get_row( $url, $this->is_mobile() ); + + if ( ! $row ) { + return $exclusions; + } + + if ( $row->lcp && 'not found' !== $row->lcp ) { + $lcp = $this->generate_lcp_link_tag_with_sources( json_decode( $row->lcp ) ); + $lcp = $lcp['sources']; + $lcp = $this->get_path_for_exclusion( $lcp ); + } + + if ( $row->viewport && 'not found' !== $row->viewport ) { + $atf = $this->get_atf_sources( json_decode( $row->viewport ) ); + $atf = $this->get_path_for_exclusion( $atf ); + } + + $exclusions = array_merge( $exclusions, $lcp, $atf ); + + // Remove lcp candidate from the atf array. + $exclusions = array_unique( $exclusions ); + + return $exclusions; + } + + /** + * Get only the url path to exclude. + * + * @param array $exclusions Array of exclusions. + * @return array + */ + private function get_path_for_exclusion( array $exclusions ): array { + $exclusions = array_map( + function ( $exclusion ) { + $exclusion = wp_parse_url( $exclusion ); + return ltrim( $exclusion['path'], '/' ); + }, + $exclusions + ); + + return $exclusions; + } + + /** + * Generate preload link tags with sources for LCP. + * + * @param object $lcp LCP Object. + * @return array + */ + private function generate_lcp_link_tag_with_sources( $lcp ): array { + $pairs = [ + 'tags' => '', + 'sources' => [], + ]; + + if ( ! $lcp && ! is_object( $lcp ) ) { + return $pairs; + } + + $tag = ''; + $start_tag = '<link rel="preload" as="image" '; + $end_tag = ' fetchpriority="high">'; + + $sources = []; + + switch ( $lcp->type ) { + case 'img': + $sources[] = $lcp->src; + $tag .= $start_tag . 'href="' . ( $this->is_relative( $lcp->src ) ? esc_attr( $lcp->src ) : esc_url( $lcp->src ) ) . '"' . $end_tag; + break; + case 'img-srcset': + $sources[] = $lcp->src; + $tag .= $start_tag . 'href="' . ( $this->is_relative( $lcp->src ) ? esc_attr( $lcp->src ) : esc_url( $lcp->src ) ) . '" imagesrcset="' . esc_attr( $lcp->srcset ) . '" imagesizes="' . esc_attr( $lcp->sizes ) . '"' . $end_tag; + break; + case 'bg-img-set': + foreach ( $lcp->bg_set as $set ) { + $sources[] = $set->src; + } + + $tag .= $start_tag . 'imagesrcset="' . esc_attr( implode( ',', $sources ) ) . '"' . $end_tag; + break; + case 'bg-img': + foreach ( $lcp->bg_set as $set ) { + $sources[] = $set->src; + + $tag .= $start_tag . 'href="' . ( $this->is_relative( $set->src ) ? esc_attr( $set->src ) : esc_url( $set->src ) ) . '"' . $end_tag; + } + break; + case 'picture': + $result = $this->generate_source_tags( $lcp, $start_tag, $end_tag ); + $sources = $result['sources']; + $tag .= $result['tag']; + break; + } + + $pairs['tags'] = $tag; + $pairs['sources'] = $sources; + + return $pairs; + } + + /** + * Get above the fold images sources. + * + * @param array $atfs Above the fold object. + * @return array + */ + private function get_atf_sources( array $atfs ): array { + if ( ! $atfs && ! is_array( $atfs ) ) { + return []; + } + + $sources = []; + + foreach ( $atfs as $atf ) { + switch ( $atf->type ) { + case 'img': + case 'img-srcset': + $sources[] = $atf->src; + break; + case 'bg-img-set': + case 'bg-img': + foreach ( $atf->bg_set as $set ) { + $sources[] = $set->src; + } + break; + case 'picture': + if ( ! empty( $atf->sources ) ) { + foreach ( $atf->sources as $source ) { + $sources[] = $source->srcset; + } + } + $sources[] = $atf->src; + break; + } + } + + return $sources; + } + + /** + * Determines if the page is mobile and separate cache for mobile files is enabled. + * + * @return bool + */ + private function is_mobile(): bool { + return $this->options->get( 'cache_mobile', 0 ) + && $this->options->get( 'do_caching_mobile_files', 0 ) + && wp_is_mobile(); + } + + /** + * The `inject_beacon` function is used to inject a JavaScript beacon into the HTML content. + * + * @param string $html The HTML content where the beacon will be injected. + * @param string $url The current URL. + * @param bool $is_mobile True for mobile device, false otherwise. + * + * @return string The modified HTML content with the beacon script injected just before the closing body tag. + */ + public function inject_beacon( $html, $url, $is_mobile ): string { + $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min'; + + if ( ! $this->filesystem->exists( rocket_get_constant( 'WP_ROCKET_ASSETS_JS_PATH' ) . 'lcp-beacon' . $min . '.js' ) ) { + return $html; + } + + $default_width_threshold = $is_mobile ? 393 : 1600; + $default_height_threshold = $is_mobile ? 830 : 700; + /** + * Filters the width threshold for the LCP beacon. + * + * @param int $width_threshold The width threshold. Default is 393 for mobile and 1920 for others. + * @param bool $is_mobile True if the current device is mobile, false otherwise. + * @param string $url The current URL. + * + * @return int The filtered width threshold. + */ + $width_threshold = apply_filters( 'rocket_lcp_width_threshold', $default_width_threshold, $is_mobile, $url ); + + /** + * Filters the height threshold for the LCP beacon. + * + * @param int $height_threshold The height threshold. Default is 830 for mobile and 1080 for others. + * @param bool $is_mobile True if the current device is mobile, false otherwise. + * @param string $url The current URL. + * + * @return int The filtered height threshold. + */ + $height_threshold = apply_filters( 'rocket_lcp_height_threshold', $default_height_threshold, $is_mobile, $url ); + + if ( ! is_int( $width_threshold ) ) { + $width_threshold = $default_width_threshold; + } + + if ( ! is_int( $height_threshold ) ) { + $height_threshold = $default_height_threshold; + } + + $default_delay = 500; + + /** + * Filters the delay before the LCP beacon is triggered. + * + * @param int $delay The delay in milliseconds. Default is 500. + */ + $delay = apply_filters( 'rocket_lcp_delay', $default_delay ); + + if ( ! is_int( $delay ) ) { + $delay = $default_delay; + } + + $data = [ + 'ajax_url' => admin_url( 'admin-ajax.php' ), + 'nonce' => wp_create_nonce( 'rocket_lcp' ), + 'url' => $url, + 'is_mobile' => $is_mobile, + 'elements' => $this->lcp_atf_elements(), + 'width_threshold' => $width_threshold, + 'height_threshold' => $height_threshold, + 'delay' => $delay, + 'debug' => rocket_get_constant( 'WP_ROCKET_DEBUG' ), + ]; + + $inline_script = '<script>var rocket_lcp_data = ' . wp_json_encode( $data ) . '</script>'; + + // Get the URL of the script. + $script_url = rocket_get_constant( 'WP_ROCKET_ASSETS_JS_URL' ) . 'lcp-beacon' . $min . '.js'; + + // Create the script tag. + $script_tag = "<script data-name=\"wpr-lcp-beacon\" src='{$script_url}' async></script>"; // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript + + // Append the script tag just before the closing body tag. + return str_replace( '</body>', $inline_script . $script_tag . '</body>', $html ); + } + + /** + * Generates the source tags for the given LCP object. + * + * This method is used to generate the source tags for the given LCP object. It iterates over the sources of the LCP object, + * and for each source, it generates a media query and adds the source to the sources array. It also constructs a tag string + * with the source and media query. If a previous max-width is found, it is used to update the media query. The method also + * handles the case where a max-width is found in the source's media attribute. + * + * @param object $lcp The LCP object containing the sources. + * @param string $start_tag The starting tag for each source. + * @param string $end_tag The ending tag for each source. + * + * @return array An associative array containing the sources array and the tag string. + */ + private function generate_source_tags( $lcp, $start_tag, $end_tag ) { + $prev_max_width = null; + $sources = []; + $tag = ''; + $prev_type = null; + + // Iterate over the sources in the LCP object. + foreach ( $lcp->sources as $i => $source ) { + // If the type of the previous source is not equal to the type of the current source, break the loop. + if ( ! empty( $source->type ) && $prev_type !== $source->type && null !== $prev_type ) { + break; + } + + $media = ! empty( $source->media ) ? $source->media : ''; + + // If a previous max-width is found, update the media query. + if ( null !== $prev_max_width && false === strpos( $media, 'min-width' ) ) { + $media = '(min-width: ' . ( $prev_max_width + 0.1 ) . 'px) and ' . $media; + } + + // Add the media attribute to the media string. + + $media = ! empty( $media ) ? ' media="' . $media . '"' : ''; + + $sources[] = $source->srcset; + // Get the sizes attribute of the source, if it exists. + $sizes = ! empty( $source->sizes ) ? ' imagesizes="' . $source->sizes . '"' : ''; + + // Determine whether to use 'href' or 'imagesrcset' based on the srcset attribute. + $link_attribute = ( substr_count( $source->srcset, ',' ) > 0 ) ? 'imagesrcset' : 'href'; + + // Append the source and media query to the tag string. + $tag .= $start_tag . $link_attribute . '="' . $source->srcset . '"' . ( $media ?? '' ) . $sizes . $end_tag; + + // If a max-width is found in the source's media attribute, update the previous max-width. + if ( preg_match( '/\(max-width: (\d+(\.\d+)?)px\)/', $source->media, $matches ) ) { + $prev_max_width = floatval( $matches[1] ); + } + + $prev_type = $source->type; + } + + // If a previous max-width is found, update the media query and add the LCP source to the sources array and the tag string. + if ( null !== $prev_max_width ) { + $media = ' media="(min-width: ' . ( $prev_max_width + 0.1 ) . 'px)"'; + $sources[] = $lcp->src; + $tag .= $start_tag . 'href="' . $lcp->src . '"' . $media . $end_tag; + } + + // Return an associative array containing the sources array and the tag string. + return [ + 'sources' => $sources, + 'tag' => $tag, + ]; + } + + /** + * Returns a comma-separated list of elements to be considered for the lcp/above-the-fold optimization. + * + * @return string + */ + private function lcp_atf_elements(): string { + $elements = [ + 'img', + 'video', + 'picture', + 'p', + 'main', + 'div', + 'li', + 'svg', + 'section', + 'header', + ]; + + $default_elements = $elements; + + /** + * Filters the array of elements + * + * @since 3.16 + * + * @param array $formats Array of elements + */ + $elements = apply_filters( 'rocket_atf_elements', $elements ); + + if ( ! is_array( $elements ) ) { + $elements = $default_elements; + } + + $elements = array_filter( $elements, 'is_string' ); + + return implode( ', ', $elements ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Frontend/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Frontend/Subscriber.php new file mode 100644 index 000000000..949ed7f8c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/Frontend/Subscriber.php @@ -0,0 +1,59 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\Frontend; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + /** + * Controller instance + * + * @var Controller + */ + private $controller; + + /** + * Constructor + * + * @param Controller $controller Controller instance. + */ + public function __construct( Controller $controller ) { + $this->controller = $controller; + } + + /** + * Array of events to listen to + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'rocket_buffer' => [ 'lcp', 17 ], + 'rocket_lazyload_excluded_src' => 'add_exclusions', + 'rocket_critical_image_saas_visit_buffer' => [ 'lcp', 17 ], + ]; + } + + /** + * Optimize the LCP image + * + * @param string $html HTML content. + * + * @return string + */ + public function lcp( $html ): string { + return $this->controller->lcp( $html ); + } + + /** + * Add above the fold images to lazyload exclusions + * + * @param array $exclusions Array of excluded patterns. + * + * @return array + */ + public function add_exclusions( $exclusions ): array { + return $this->controller->add_exclusions( $exclusions ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/ServiceProvider.php new file mode 100644 index 000000000..3227ece89 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/ServiceProvider.php @@ -0,0 +1,124 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Media\AboveTheFold\Admin\{Controller as AdminController, Subscriber as AdminSubscriber}; +use WP_Rocket\Engine\Media\AboveTheFold\AJAX\{Controller as AJAXController, Subscriber as AJAXSubscriber}; +use WP_Rocket\Engine\Media\AboveTheFold\Context\Context; +use WP_Rocket\Engine\Media\AboveTheFold\Database\Tables\AboveTheFold as ATFTable; +use WP_Rocket\Engine\Media\AboveTheFold\Database\Queries\AboveTheFold as ATFQuery; +use WP_Rocket\Engine\Media\AboveTheFold\Frontend\{Controller as FrontController, Subscriber as FrontSubscriber}; +use WP_Rocket\Engine\Media\AboveTheFold\Cron\{Controller as CronController, Subscriber as CronSubscriber}; +use WP_Rocket\Engine\Media\AboveTheFold\WarmUp\{ + APIClient, + Controller as WarmUpController, + Subscriber as WarmUpSubscriber, + Queue +}; + +class ServiceProvider extends AbstractServiceProvider { + /** + * The provides array is a way to let the container + * know that a service is provided by this service + * provider. Every service that is registered via + * this service provider must have an alias added + * to this array or it will be ignored. + * + * @var array + */ + protected $provides = [ + 'atf_table', + 'atf_query', + 'atf_context', + 'atf_controller', + 'atf_subscriber', + 'atf_admin_controller', + 'atf_admin_subscriber', + 'atf_cron_controller', + 'atf_cron_subscriber', + 'atf_ajax_controller', + 'atf_ajax_subscriber', + 'warmup_controller', + 'warmup_subscriber', + 'warmup_apiclient', + 'warmup_queue', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers the classes in the container + * + * @return void + */ + public function register(): void { + $this->getContainer()->addShared( 'atf_table', ATFTable::class ); + $this->getContainer()->add( 'atf_query', ATFQuery::class ); + $this->getContainer()->add( 'atf_context', Context::class ); + + $this->getContainer()->get( 'atf_table' ); + + $this->getContainer()->add( 'atf_controller', FrontController::class ) + ->addArguments( + [ + $this->getContainer()->get( 'options' ), + $this->getContainer()->get( 'atf_query' ), + $this->getContainer()->get( 'atf_context' ), + ] + ); + + $this->getContainer()->addShared( 'atf_subscriber', FrontSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'atf_controller' ) ); + $this->getContainer()->add( 'atf_admin_controller', AdminController::class ) + ->addArgument( $this->getContainer()->get( 'atf_table' ) ) + ->addArgument( $this->getContainer()->get( 'atf_query' ) ) + ->addArgument( $this->getContainer()->get( 'atf_context' ) ); + $this->getContainer()->addShared( 'atf_admin_subscriber', AdminSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'atf_admin_controller' ) ); + + $this->getContainer()->add( 'atf_cron_controller', CronController::class ) + ->addArgument( $this->getContainer()->get( 'atf_query' ) ); + $this->getContainer()->addShared( 'atf_cron_subscriber', CronSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'atf_cron_controller' ) ); + + $this->getContainer()->add( 'atf_ajax_controller', AJAXController::class ) + ->addArguments( + [ + $this->getContainer()->get( 'atf_query' ), + $this->getContainer()->get( 'atf_context' ), + ] + ); + + $this->getContainer()->addShared( 'atf_ajax_subscriber', AJAXSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'atf_ajax_controller' ) ); + + $this->getContainer()->add( 'warmup_apiclient', APIClient::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + + $this->getContainer()->add( 'warmup_queue', Queue::class ); + + $this->getContainer()->add( 'warmup_controller', WarmUpController::class ) + ->addArguments( + [ + $this->getContainer()->get( 'atf_context' ), + $this->getContainer()->get( 'options' ), + $this->getContainer()->get( 'warmup_apiclient' ), + $this->getContainer()->get( 'user' ), + $this->getContainer()->get( 'warmup_queue' ), + ] + ); + $this->getContainer()->addShared( 'warmup_subscriber', WarmUpSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'warmup_controller' ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/APIClient.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/APIClient.php new file mode 100644 index 000000000..22814b11b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/APIClient.php @@ -0,0 +1,37 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\WarmUp; + +use WP_Rocket\Engine\Common\JobManager\APIHandler\APIClient as BaseAPIClient; +use WP_Rocket\Engine\Common\Utils; + +class APIClient extends BaseAPIClient { + + /** + * Send the link to Above the fold SaaS. + * + * @param string $url Url to be sent. + * @param string $device Device type. + * + * @return array + */ + public function add_to_atf_queue( string $url, $device = 'desktop' ): array { + $is_home = Utils::is_home( $url ); + + $url = add_query_arg( + [ + 'wpr_imagedimensions' => 1, + ], + $url + ); + + $config = [ + 'optimization_list' => '', + 'is_home' => $is_home, + 'is_mobile' => 'mobile' === $device, + ]; + + return $this->add_to_queue( $url, $config ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Controller.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Controller.php new file mode 100644 index 000000000..8493cc1ea --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Controller.php @@ -0,0 +1,245 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\WarmUp; + +use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Common\Context\ContextInterface; +use WP_Rocket\Engine\Common\Utils; +use WP_Rocket\Engine\License\API\User; + +class Controller { + /** + * ATF context. + * + * @var ContextInterface + */ + protected $context; + + /** + * Plugin options instance. + * + * @var Options_Data + */ + protected $options; + + /** + * APIClient Instance. + * + * @var APIClient + */ + private $api_client; + + /** + * User instance + * + * @var User + */ + private $user; + + /** + * Queue instance. + * + * @var Queue + */ + private $queue; + + /** + * Constructor + * + * @param ContextInterface $context ATF Context. + * @param Options_Data $options Options instance. + * @param APIClient $api_client APIClient instance. + * @param User $user User instance. + * @param Queue $queue Queue instance. + */ + public function __construct( ContextInterface $context, Options_Data $options, APIClient $api_client, User $user, Queue $queue ) { + $this->context = $context; + $this->options = $options; + $this->api_client = $api_client; + $this->user = $user; + $this->queue = $queue; + } + + /** + * Send home URL for warm up. + * + * @return void + */ + public function warm_up_home(): void { + if ( (bool) $this->options->get( 'remove_unused_css', 0 ) ) { + return; + } + + if ( ! $this->context->is_allowed() ) { + return; + } + + $this->send_to_saas( home_url() ); + $this->queue->add_job_warmup(); + } + + /** + * Fetch links and send them to SaaS for warm up. + * + * @return void + */ + public function warm_up(): void { + if ( 'local' === wp_get_environment_type() ) { + return; + } + + if ( (bool) $this->options->get( 'remove_unused_css', 0 ) ) { + return; + } + + if ( ! $this->context->is_allowed() ) { + return; + } + + $links = $this->fetch_links(); + + foreach ( $links as $link ) { + $this->queue->add_job_warmup_url( $link ); + } + } + + /** + * Fetch links from homepage. + * + * @return array + */ + public function fetch_links(): array { + if ( $this->user->is_license_expired_grace_period() ) { + return []; + } + + $user_agent = 'WP Rocket/Pre-fetch Home Links Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1'; + + $home_url = home_url(); + $args = [ + 'user-agent' => $user_agent, + 'timeout' => 60, + ]; + + $response = wp_safe_remote_get( $home_url, $args ); + + if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { + return []; + } + + $html = wp_remote_retrieve_body( $response ); + + if ( ! preg_match_all( '/<a\s+(?:[^>]*?\s+)?href=(["\'])(.*?)\1/', $html, $matches ) ) { + return []; + } + + $links = $matches[2]; + + // Cater for relative urls. + $links = array_map( + function ( $link ) { + $link_path = wp_parse_url( $link ); + + // Return if absolute url. + if ( isset( $link_path['path'], $link_path['scheme'] ) ) { + return $link; + } + + // Transform to absolute url if relative. + if ( isset( $link_path['path'] ) ) { + return home_url( $link ); + } + + return $link; + }, + $links + ); + + $reject_uri_pattern = '/(?:.+/)?feed(?:/(?:.+/?)?)?$|/(?:.+/)?embed/|/wc-api/v(.*)|/(index.php/)?(.*)wp-json(/.*|$)'; + + // Filter links. + $links = array_filter( + $links, + function ( $link ) use ( $home_url, $reject_uri_pattern ) { + $link_host = wp_parse_url( $link ); + $site_host = wp_parse_url( $home_url ); + /** + * Check for valid link. + * Check that no external link. + * Check that it's not home. + */ + $is_valid_url = wp_http_validate_url( $link ); + $is_same_host = isset( $link_host['host'] ) ? $link_host['host'] === $site_host['host'] : false; + $is_not_home = ! Utils::is_home( $link ); + $is_not_excluded_uri = ! (bool) preg_match( '#' . $reject_uri_pattern . '#i', $link ); + + return $is_valid_url && $is_same_host && $is_not_home && $is_not_excluded_uri; + } + ); + + // Remove duplicate links. + $links = array_unique( $links ); + + $default_limit = 10; + + /** + * Filters the number of links to return from the homepage. + * + * @param int $links_limit number of links to return. + */ + $links_limit = apply_filters( 'rocket_atf_warmup_links_number', $default_limit ); + + if ( ! is_int( $links_limit ) || $links_limit < 1 ) { + $links_limit = $default_limit; + } + + $links = array_slice( $links, 0, $links_limit ); + + return $links; + } + + /** + * Send link to SaaS to do the warmup. + * + * @param string $url Url to send. + * + * @return void + */ + public function send_to_saas( string $url ) { + $this->api_client->add_to_atf_queue( $url ); + + if ( $this->is_mobile() ) { + $this->api_client->add_to_atf_queue( $url, 'mobile' ); + } + } + + /** + * Add wpr_imagedimensions to URL query. + * + * @param string $url URL to be sent. + * + * @return string + */ + public function add_wpr_imagedimensions_query_arg( string $url ): string { + if ( ! $this->context->is_allowed() ) { + return $url; + } + + return add_query_arg( + [ + 'wpr_imagedimensions' => 1, + ], + $url + ); + } + + /** + * Check if the current request is for mobile. + * + * @return bool + */ + private function is_mobile(): bool { + return $this->options->get( 'cache_mobile', 0 ) && $this->options->get( 'do_caching_mobile_files', 0 ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Queue.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Queue.php new file mode 100644 index 000000000..237a8a469 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Queue.php @@ -0,0 +1,35 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\WarmUp; + +use WP_Rocket\Engine\Common\Queue\AbstractASQueue; + +class Queue extends AbstractASQueue { + /** + * ATF queue group + * + * @var string + */ + protected $group = 'rocket-atf-warmup'; + + /** + * Add an async job to warm up home links + * + * @return int + */ + public function add_job_warmup(): int { + return $this->add_async( 'rocket_job_warmup' ); + } + + /** + * Add an async job to send URL to SaaS for warmup + * + * @param string $url URL to warm up. + * + * @return int + */ + public function add_job_warmup_url( string $url ): int { + return $this->add_async( 'rocket_job_warmup_url', [ $url ] ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Subscriber.php new file mode 100644 index 000000000..09651afd9 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/AboveTheFold/WarmUp/Subscriber.php @@ -0,0 +1,94 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\AboveTheFold\WarmUp; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + /** + * WarmUp controller instance + * + * @var Controller + */ + private $controller; + + /** + * Constructor + * + * @param Controller $controller ATF WarmUp controller instance. + */ + public function __construct( Controller $controller ) { + $this->controller = $controller; + } + + /** + * Array of events this subscriber listens to + * + * @return array + */ + public static function get_subscribed_events(): array { + return [ + 'wp_rocket_upgrade' => [ 'warm_up_on_update', 10, 2 ], + 'rocket_after_clear_atf' => 'warm_up_home', + 'rocket_saas_api_queued_url' => 'add_wpr_imagedimensions_query_arg', + 'rocket_job_warmup' => 'warm_up', + 'rocket_job_warmup_url' => 'send_to_saas', + ]; + } + + /** + * Send home to warmup and start async fetch links + * + * @return void + */ + public function warm_up_home(): void { + $this->controller->warm_up_home(); + } + + /** + * Fetch links for warmup and create async tasks + * + * @return void + */ + public function warm_up(): void { + $this->controller->warm_up(); + } + + /** + * Send url to SaaS for warmup + * + * @param string $url URL to be sent. + * + * @return void + */ + public function send_to_saas( string $url ): void { + $this->controller->send_to_saas( $url ); + } + + /** + * Process links fetched from homepage on update. + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function warm_up_on_update( $new_version, $old_version ) { + if ( version_compare( $old_version, '3.16', '>=' ) ) { + return; + } + $this->controller->warm_up(); + } + + /** + * Add image dimensions query parameter to URL. + * + * @param string $url URL to be sent. + * + * @return string + */ + public function add_wpr_imagedimensions_query_arg( string $url ): string { + return $this->controller->add_wpr_imagedimensions_query_arg( $url ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/AdminSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/AdminSubscriber.php index 1d027b39b..1e84d46b1 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/AdminSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/AdminSubscriber.php @@ -27,7 +27,7 @@ public function __construct( ImageDimensions $dimensions ) { * * @return array */ - public static function get_subscribed_events() : array { + public static function get_subscribed_events(): array { return [ 'rocket_first_install_options' => [ 'add_option', 14 ], 'rocket_input_sanitize' => [ 'sanitize_option', 10, 2 ], @@ -40,7 +40,7 @@ public static function get_subscribed_events() : array { * @param array $options WP Rocket options array. * @return array */ - public function add_option( array $options ) : array { + public function add_option( array $options ): array { return $this->dimensions->add_option( $options ); } @@ -53,7 +53,7 @@ public function add_option( array $options ) : array { * @param Settings $settings Settings class instance. * @return array */ - public function sanitize_option( array $input, Settings $settings ) : array { + public function sanitize_option( array $input, Settings $settings ): array { return $this->dimensions->sanitize_option_value( $input, $settings ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/ImageDimensions.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/ImageDimensions.php index c9f0021a5..77e383251 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/ImageDimensions.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/ImageDimensions.php @@ -1,13 +1,18 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\Media\ImageDimensions; +use SplFileInfo; use WP_Filesystem_Direct; use WP_Rocket\Admin\Options_Data; use WP_Rocket\Engine\Admin\Settings\Settings; +use WP_Rocket\Engine\Optimization\RegexTrait; use WP_Rocket\Logger\Logger; class ImageDimensions { + use RegexTrait; + /** * Options_Data instance * @@ -15,13 +20,6 @@ class ImageDimensions { */ private $options; - /** - * Cache local paths for images. - * - * @var array - */ - private $local_paths = []; - /** * Filesystem instance * @@ -53,7 +51,7 @@ public function __construct( Options_Data $options, $filesystem = null ) { * @param array $options WP Rocket options array. * @return array */ - public function add_option( array $options ) : array { + public function add_option( array $options ): array { $options['image_dimensions'] = 0; return $options; @@ -68,7 +66,7 @@ public function add_option( array $options ) : array { * @param Settings $settings Settings class instance. * @return array */ - public function sanitize_option_value( array $input, Settings $settings ) : array { + public function sanitize_option_value( array $input, Settings $settings ): array { $input['image_dimensions'] = $settings->sanitize_checkbox( $input, 'image_dimensions' ); return $input; @@ -83,25 +81,30 @@ public function sanitize_option_value( array $input, Settings $settings ) : arra */ public function specify_image_dimensions( $html ) { Logger::debug( 'Start Specify Image Dimensions.' ); + if ( ! $this->can_specify_dimensions_images() ) { Logger::debug( 'Specify Image Dimensions failed because option is not enabled from admin or by filter (rocket_specify_image_dimensions).' ); return $html; } - // Get all images without width or height attribute. - $images_regex = '<img(?:[^>](?!(height|width)=[\'\"](?:\S+)[\'\"]))*+>'; + // Get all images without width and height attributes. + $images_regex = '<img(?:[^>](?!height=[\'\"](?:\S+)[\'\"]))*+>|<img(?:[^>](?!width=[\'\"](?:\S+)[\'\"]))*+>'; /** * Filters Specify image dimensions inside picture tags also. * * @since 3.8 * - * @param bool Do or not, Default is True so it will skip all img tags that are inside picture tag. + * @param bool $skip_pictures Do or not. Default is True, so it will skip all img tags that are inside picture tag. */ if ( apply_filters( 'rocket_specify_dimension_skip_pictures', true ) ) { - $images_regex = '<\s*picture[^>]*>.*' . $images_regex . '.*<\s*\/\s*picture\s*>(*SKIP)(*FAIL)|' . $images_regex; + $images_regex = '<\s*picture[^>]*>.*<\s*\/\s*picture\s*>(*SKIP)(*FAIL)|' . $images_regex; } - preg_match_all( "/{$images_regex}/is", $html, $images_match ); + + $clean_html = $this->hide_scripts( $html ); + $clean_html = $this->hide_noscripts( $clean_html ); + + preg_match_all( "/{$images_regex}/Uis", $clean_html, $images_match ); if ( empty( $images_match ) ) { Logger::debug( 'Specify Image Dimensions failed because there is no image without dimensions on this page.' ); @@ -109,19 +112,19 @@ public function specify_image_dimensions( $html ) { } $replaces = []; + /** * Filters Page images passed to specify dimensions. * * @since 3.8 * - * @param array Page images. + * @param array $images Page images. */ $images = apply_filters( 'rocket_specify_dimension_images', $images_match[0] ); Logger::debug( 'Specify Image Dimensions found ( ' . count( $images ) . ' ).', $images ); foreach ( $images as $image ) { - $image_url = $this->can_specify_dimensions_one_image( $image ); if ( ! $image_url ) { @@ -138,8 +141,14 @@ public function specify_image_dimensions( $html ) { continue; } + $width_height = $this->set_dimensions( $image, $sizes ); + + if ( ! $width_height ) { + continue; + } + // Replace image with new attributes, we will replace all images at once after the loop for optimizations. - $replaces[ $image ] = $this->assign_width_height( $image, $sizes ); + $replaces[ $image ] = $this->assign_width_height( $image, $width_height ); } if ( empty( $replaces ) ) { @@ -160,13 +169,17 @@ public function specify_image_dimensions( $html ) { private function is_external_file( $url ) { $file = get_rocket_parse_url( $url ); + if ( ! empty( $file['query'] ) ) { + return true; + } + if ( empty( $file['path'] ) ) { return true; } - $wp_content = wp_parse_url( content_url() ); + $parsed_site_url = wp_parse_url( site_url() ); - if ( empty( $wp_content['host'] ) || empty( $wp_content['path'] ) ) { + if ( empty( $parsed_site_url['host'] ) ) { return true; } @@ -179,7 +192,7 @@ private function is_external_file( $url ) { * @param array $zones Zones to check available hosts. */ $hosts = (array) apply_filters( 'rocket_cdn_hosts', [], [ 'all' ] ); - $hosts[] = $wp_content['host']; + $hosts[] = $parsed_site_url['host']; $langs = get_rocket_i18n_uri(); // Get host for all langs. @@ -202,8 +215,7 @@ private function is_external_file( $url ) { // URL has domain and domain is part of the internal domains. if ( ! empty( $file['host'] ) ) { foreach ( $hosts as $host ) { - if ( false !== strpos( $url, $host ) ) { - $this->local_paths[ md5( $url ) ] = str_replace( $host, untrailingslashit( rocket_get_constant( 'ABSPATH' ) ), rocket_remove_url_protocol( $url ) ); + if ( false !== strpos( $file['host'], $host ) ) { return false; } } @@ -211,8 +223,7 @@ private function is_external_file( $url ) { return true; } - // URL has no domain and doesn't contain the WP_CONTENT path or wp-includes. - return ! preg_match( '#(' . $wp_content['path'] . '|wp-includes)#', $file['path'] ); + return false; } /** @@ -223,11 +234,18 @@ private function is_external_file( $url ) { * @return string Image absolute local path. */ private function get_local_path( $url ) { - if ( isset( $this->local_paths[ md5( $url ) ] ) ) { - return $this->local_paths[ md5( $url ) ]; + $url = $this->normalize_url( $url ); + + $path = rocket_url_to_path( $url ); + if ( $path ) { + return $path; } - return str_replace( content_url(), rocket_get_constant( 'WP_CONTENT_DIR' ), $url ); + $relative_url = ltrim( wp_make_link_relative( $url ), '/' ); + $ds = rocket_get_constant( 'DIRECTORY_SEPARATOR' ); + $base_path = isset( $_SERVER['DOCUMENT_ROOT'] ) ? ( sanitize_text_field( wp_unslash( $_SERVER['DOCUMENT_ROOT'] ) ) . $ds ) : ''; + + return $base_path . str_replace( '/', $ds, $relative_url ); } /** @@ -241,11 +259,64 @@ private function can_specify_dimensions_external_images() { * * @since 3.8 * - * @param bool Specify image dimensions for external images or not. + * @param bool $specify_dimensions_external Specify image dimensions for external images or not. */ return ini_get( 'allow_url_fopen' ) && apply_filters( 'rocket_specify_image_dimensions_for_distant', false ); } + /** + * Sets the width and height dimensions string + * + * @param string $image Image HTML element. + * @param array $sizes Array of data created by getimagesize(). + * + * @return string|false + */ + private function set_dimensions( string $image, array $sizes ) { + preg_match( '/<img.*\sheight=[\'\"]?(?<height>[^\'\"\s]+)[\'\"]?.*>/i', $image, $initial_height ); + preg_match( '/<img.*\swidth=[\'\"]?(?<width>[^\'\"\s]+)[\'\"]?.*>/i', $image, $initial_width ); + + if ( + empty( $initial_height['height'] ) + && + empty( $initial_width['width'] ) + ) { + return $sizes[3]; + } + + if ( ! empty( $initial_height['height'] ) ) { + if ( ! is_numeric( $initial_height['height'] ) ) { + Logger::debug( + 'Specify Image Dimensions failed because specified height is not numeric.', + [ 'image' => $image ] + ); + + return false; + } + + $ratio = $initial_height['height'] / $sizes[1]; + + return 'width="' . (int) round( $sizes[0] * $ratio ) . '" height="' . $initial_height['height'] . '"'; + } + + if ( ! empty( $initial_width['width'] ) ) { + if ( ! is_numeric( $initial_width['width'] ) ) { + Logger::debug( + 'Specify Image Dimensions failed because specified width is not numeric.', + [ 'image' => $image ] + ); + + return false; + } + + $ratio = $initial_width['width'] / $sizes[0]; + + return 'width="' . $initial_width['width'] . '" height="' . (int) round( $sizes[1] * $ratio ) . '"'; + } + + return false; + } + /** * Assign width and height attributes to the img tag. * @@ -254,9 +325,9 @@ private function can_specify_dimensions_external_images() { * * @return string IMG tag after adding attributes otherwise return the input img when error. */ - private function assign_width_height( string $image, $width_height ) { + private function assign_width_height( string $image, string $width_height ): string { // Remove old width and height attributes if found. - $changed_image = preg_replace( '/(height|width)=[\'"](?:\S+)*[\'"]/i', '', $image ); + $changed_image = preg_replace( '/\s(height|width)=(?:[\'"]?(?:[^\'\"\s]+)*[\'"]?)?/i', '', $image ); $changed_image = preg_replace( '/<\s*img/i', '<img ' . $width_height, $changed_image ); if ( null === $changed_image ) { @@ -274,12 +345,17 @@ private function assign_width_height( string $image, $width_height ) { * * @return bool If image exists or not. */ - private function image_exists( $image, $external = false ) { + private function image_exists( string $image, $external = false ): bool { + if ( ! $image ) { + return false; + } + if ( ! $external ) { return $this->filesystem->exists( $image ); } $file_headers = get_headers( $image ); + if ( ! $file_headers ) { return false; } @@ -292,13 +368,13 @@ private function image_exists( $image, $external = false ) { * * @return bool Can we or not. */ - private function can_specify_dimensions_images() { + private function can_specify_dimensions_images(): bool { /** * Filter images dimensions attributes process. * * @since 2.2 * - * @param bool Do the job or not. + * @param bool $specify_dimensions Do the job or not. */ return apply_filters( 'rocket_specify_image_dimensions', false ) || @@ -312,7 +388,7 @@ private function can_specify_dimensions_images() { * * @return false|string false if we can't specify for this image otherwise get img src attribute. */ - private function can_specify_dimensions_one_image( $image ) { + private function can_specify_dimensions_one_image( string $image ) { // Don't touch lazy-load file (no conflict with Photon (Jetpack)). if ( false !== strpos( $image, 'data-lazy-original' ) @@ -325,7 +401,6 @@ private function can_specify_dimensions_one_image( $image ) { } return $src_match['url']; - } /** @@ -333,10 +408,12 @@ private function can_specify_dimensions_one_image( $image ) { * * @param string $image_url Image url to get sizes for. * - * @return string|false Get image sizes otherwise false. + * @return array|false Get image sizes otherwise false. */ private function get_image_sizes( string $image_url ) { if ( $this->is_external_file( $image_url ) ) { + $image_url = $this->normalize_url( $image_url ); + if ( ! $this->can_specify_dimensions_external_images() ) { Logger::debug( 'Specify Image Dimensions failed because you/server disabled specifying dimensions for external images.', @@ -353,7 +430,7 @@ private function get_image_sizes( string $image_url ) { return false; } - $sizes = getimagesize( $image_url ); + $sizes = $this->getimagesize( $image_url ); if ( ! $sizes ) { Logger::debug( @@ -363,7 +440,7 @@ private function get_image_sizes( string $image_url ) { return false; } - return $sizes[3]; + return $sizes; } $local_path = $this->get_local_path( $image_url ); @@ -373,10 +450,11 @@ private function get_image_sizes( string $image_url ) { 'Specify Image Dimensions failed because internal image is not found.', [ 'image_url' => $image_url ] ); + return false; } - $sizes = getimagesize( $this->get_local_path( $image_url ) ); + $sizes = $this->getimagesize( $local_path ); if ( ! $sizes ) { Logger::debug( @@ -387,6 +465,127 @@ private function get_image_sizes( string $image_url ) { return false; } - return $sizes[3]; + return $sizes; + } + + /** + * Gets image sizes for the given file + * + * @param string $filename File we want to retrieve information about. + * + * @return array|false + */ + private function getimagesize( string $filename ) { + $file = new SplFileInfo( strtok( $filename, '?' ) ); + + if ( 'svg' === $file->getExtension() ) { + return $this->svg_getimagesize( $filename ); + } + + return getimagesize( $filename ); + } + + /** + * Gets image sizes for the given SVG file + * + * Uses the width/height attributes if present, or fallback to viewBox attribute + * + * @param string $filename File we want to retrieve information about. + * + * @return array|false + */ + private function svg_getimagesize( string $filename ) { + $svgfile = simplexml_load_file( rawurlencode( $filename ), 'SimpleXMLElement', rocket_get_constant( 'LIBXML_NOERROR', 32 ) | rocket_get_constant( 'LIBXML_NOWARNING', 64 ) ); + + if ( ! $svgfile ) { + return false; + } + + $width = $this->format_svg_value( (string) $svgfile->attributes()->width ); + $height = $this->format_svg_value( (string) $svgfile->attributes()->height ); + $size = []; + + if ( + ! empty( $width ) + && + ! empty( $height ) + ) { + $size[0] = $width; + $size[1] = $height; + $size[2] = 0; + $size[3] = 'width="' . absint( $width ) . '" height="' . absint( $height ) . '"'; + + return $size; + } + + $view_box = preg_split( '/[\s,]+/', (string) $svgfile->attributes()->viewBox ); + + if ( ! empty( $view_box ) ) { + if ( + ! empty( $view_box[2] ) + && + ! empty( $view_box[3] ) + ) { + $size[0] = $view_box[2]; + $size[1] = $view_box[3]; + $size[2] = 0; + $size[3] = 'width="' . absint( $size[0] ) . '" height="' . absint( $size[1] ) . '"'; + + return $size; + } + + return false; + } + + return false; + } + + /** + * Formats the SVG width/height value in case of unusual units + * + * @since 3.10.8 + * + * @param string $value The value of the SVG width/height attribute. + * + * @return string + */ + private function format_svg_value( string $value ): string { + // No unit, we can use the value directly. + if ( is_numeric( $value ) ) { + return $value; + } + + if ( empty( $value ) ) { + return $value; + } + + $px_pattern = '/([0-9]+)\s*px/i'; + + // If pixel unit, remove the unit and return the numeric value. + if ( preg_match( $px_pattern, $value ) ) { + return preg_replace( $px_pattern, '$1', $value ); + } + + // Return an empty string for other units. + return ''; + } + + /** + * Normalize relative url to full url. + * + * @param string $url Url to be normalized. + * + * @return string Normalized url. + */ + private function normalize_url( string $url ): string { + $url_host = wp_parse_url( $url, PHP_URL_HOST ); + + if ( empty( $url_host ) ) { + $relative_url = ltrim( wp_make_link_relative( $url ), '/' ); + $site_url_components = wp_parse_url( site_url( '/' ) ); + return $site_url_components['scheme'] . '://' . $site_url_components['host'] . '/' . $relative_url; + } + + return $url; } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/Subscriber.php index 40de9b38e..43503c2f6 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/ImageDimensions/Subscriber.php @@ -2,6 +2,7 @@ namespace WP_Rocket\Engine\Media\ImageDimensions; +use WP_Rocket\Buffer\Tests; use WP_Rocket\Event_Management\Subscriber_Interface; /** @@ -18,13 +19,22 @@ class Subscriber implements Subscriber_Interface { */ private $dimensions; + /** + * Buffer tests to run against current page, to decide if we can start the buffer or not. + * + * @var Tests + */ + private $buffer_tests; + /** * Subscriber constructor. * * @param ImageDimensions $dimensions Images dimensions class that handles all business logic. + * @param Tests $buffer_tests Buffer tests instance. */ - public function __construct( ImageDimensions $dimensions ) { - $this->dimensions = $dimensions; + public function __construct( ImageDimensions $dimensions, Tests $buffer_tests ) { + $this->dimensions = $dimensions; + $this->buffer_tests = $buffer_tests; } /** @@ -34,7 +44,9 @@ public function __construct( ImageDimensions $dimensions ) { */ public static function get_subscribed_events() { return [ - 'rocket_buffer' => [ 'specify_image_dimensions', 17 ], + 'rocket_buffer' => [ 'specify_image_dimensions', 17 ], + 'template_redirect' => [ 'start_image_dimensions_buffer', 3 ], + 'rocket_critical_image_saas_visit_buffer' => 'specify_image_dimensions', ]; } @@ -52,4 +64,38 @@ public function specify_image_dimensions( $buffer ) { return $this->dimensions->specify_image_dimensions( $buffer ); } + + /** + * Update images that have no width/height with real dimentions for the SaaS + * + * @param string $buffer Page HTML content. + * + * @return string Page HTML content after update. + */ + public function prepare_critical_image_saas_visit( $buffer ) { + if ( ! isset( $_GET['wpr_imagedimensions'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return $buffer; + } + + return apply_filters( 'rocket_critical_image_saas_visit_buffer', $buffer ); + } + + /** + * Start image dimensions buffer to add + * + * @return void + */ + public function start_image_dimensions_buffer() { + if ( empty( $_GET['wpr_imagedimensions'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return; + } + + if ( ! $this->buffer_tests->can_process_any_buffer() ) { + return; + } + + add_filter( 'rocket_specify_image_dimensions', '__return_true' ); + + ob_start( [ $this, 'prepare_critical_image_saas_visit' ] ); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/AdminSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/AdminSubscriber.php index a6b0da105..dbbe11de7 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/AdminSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/AdminSubscriber.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\Media\Lazyload; @@ -10,10 +11,11 @@ class AdminSubscriber implements Subscriber_Interface { * * @return array */ - public static function get_subscribed_events() : array { + public static function get_subscribed_events(): array { return [ 'rocket_first_install_options' => [ 'add_option', 15 ], 'rocket_input_sanitize' => 'sanitize_exclude_lazyload', + 'rocket_meta_boxes_fields' => [ 'add_meta_box', 7 ], ]; } @@ -25,7 +27,7 @@ public static function get_subscribed_events() : array { * @param array $options WP Rocket options array. * @return array */ - public function add_option( array $options ) : array { + public function add_option( array $options ): array { $options['exclude_lazyload'] = []; return $options; @@ -39,7 +41,7 @@ public function add_option( array $options ) : array { * @param array $input Input array. * @return array */ - public function sanitize_exclude_lazyload( array $input ) : array { + public function sanitize_exclude_lazyload( array $input ): array { if ( empty( $input['exclude_lazyload'] ) ) { $input['exclude_lazyload'] = []; } @@ -48,4 +50,18 @@ public function sanitize_exclude_lazyload( array $input ) : array { return $input; } + + /** + * Add the field to the WP Rocket metabox on the post edit page. + * + * @param string[] $fields Metaboxes fields. + * + * @return string[] + */ + public function add_meta_box( array $fields ) { + $fields['lazyload'] = __( 'LazyLoad for images', 'rocket' ); + $fields['lazyload_iframes'] = __( 'LazyLoad for iframes/videos', 'rocket' ); + + return $fields; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Admin/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Admin/ServiceProvider.php new file mode 100644 index 000000000..7b1209479 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Admin/ServiceProvider.php @@ -0,0 +1,41 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Admin; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; + +/** + * Service provider. + */ +class ServiceProvider extends AbstractServiceProvider { + /** + * Array of services provided by this service provider + * + * @var array + */ + protected $provides = [ + 'lazyload_css_admin_subscriber', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container + * + * @return void + */ + public function register(): void { + + $this->getContainer()->addShared( 'lazyload_css_admin_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'lazyload_css_cache' ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Admin/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Admin/Subscriber.php new file mode 100644 index 000000000..59f0acf4d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Admin/Subscriber.php @@ -0,0 +1,81 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Admin; + +use WP_Rocket\Engine\Common\Cache\CacheInterface; +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + + /** + * Cache instance. + * + * @var CacheInterface + */ + protected $cache; + + /** + * Instantiate class. + * + * @param CacheInterface $cache Cache instance. + */ + public function __construct( CacheInterface $cache ) { + $this->cache = $cache; + } + + /** + * Returns an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'rocket_meta_boxes_fields' => [ 'add_meta_box', 8 ], + 'admin_notices' => 'maybe_add_error_notice', + 'rocket_safe_mode_reset_options' => 'add_option_safemode', + ]; + } + + /** + * Add the field to the WP Rocket metabox on the post edit page. + * + * @param string[] $fields Metaboxes fields. + * + * @return string[] + */ + public function add_meta_box( array $fields ) { + $fields['lazyload_css_bg_img'] = __( 'LazyLoad CSS backgrounds', 'rocket' ); + return $fields; + } + + /** + * Maybe display the error notice. + * + * @return void + */ + public function maybe_add_error_notice() { + if ( ! current_user_can( 'rocket_manage_options' ) || $this->cache->is_accessible() ) { + return; + } + + rocket_notice_html( + [ + 'status' => 'error', + 'dismissible' => '', + 'message' => rocket_notice_writing_permissions( $this->cache->get_root_path() ), + ] + ); + } + + /** + * Add option to safe mode. + * + * @param string[] $options Safe mode options. + * @return string[] + */ + public function add_option_safemode( array $options ) { + $options['lazyload_css_bg_img'] = 0; + return $options; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Context/LazyloadCSSContext.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Context/LazyloadCSSContext.php new file mode 100644 index 000000000..54ddce831 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Context/LazyloadCSSContext.php @@ -0,0 +1,55 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Context; + +use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Common\Cache\CacheInterface; +use WP_Rocket\Engine\Common\Context\AbstractContext; +use WP_Rocket\Engine\Media\Lazyload\CanLazyloadTrait; + +class LazyloadCSSContext extends AbstractContext { + use CanLazyloadTrait; + + /** + * Cache instance. + * + * @var CacheInterface + */ + protected $cache; + + /** + * Instantiate the class. + * + * @param Options_Data $options WPR options. + * @param CacheInterface $cache Cache instance. + */ + public function __construct( Options_Data $options, CacheInterface $cache ) { + parent::__construct( $options ); + $this->cache = $cache; + } + + /** + * Determine if the action is allowed. + * + * @param array $data Data to pass to the context. + * @return bool + */ + public function is_allowed( array $data = [] ): bool { + $is_allowed = $this->run_common_checks( + [ + 'do_not_optimize' => false, + 'bypass' => false, + 'option' => 'lazyload_css_bg_img', + 'password_protected' => false, + 'post_excluded' => 'lazyload_css_bg_img', + 'logged_in' => false, + ] + ); + + if ( ! $is_allowed || ! $this->should_lazyload() ) { + return false; + } + + return $this->cache->is_accessible(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/LazyloadCSSContentFactory.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/LazyloadCSSContentFactory.php new file mode 100644 index 000000000..677cbd995 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/LazyloadCSSContentFactory.php @@ -0,0 +1,34 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Data; + +class LazyloadCSSContentFactory { + + /** + * Make LazyloadedContent instance. + * + * @param array $formatted_urls Formatted URls. + * @param string $content Content. + * @return LazyloadedContent + */ + public function make_lazyloaded_content( array $formatted_urls, string $content ): LazyloadedContent { + $lazyloaded_content = new LazyloadedContent(); + $lazyloaded_content->set_urls( $formatted_urls ); + $lazyloaded_content->set_content( $content ); + return $lazyloaded_content; + } + + /** + * Make ProtectedContent instance. + * + * @param array $protected_files Protected files. + * @param string $content Content. + * @return ProtectedContent + */ + public function make_protected_content( array $protected_files, string $content ): ProtectedContent { + $protected_content = new ProtectedContent(); + $protected_content->set_content( $content ); + $protected_content->set_protected_files_mapping( $protected_files ); + return $protected_content; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/LazyloadedContent.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/LazyloadedContent.php new file mode 100644 index 000000000..0dae0b7ad --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/LazyloadedContent.php @@ -0,0 +1,58 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Data; + +class LazyloadedContent { + + /** + * URls extracted from the content. + * + * @var array + */ + protected $urls = []; + + /** + * Lazyloaded content. + * + * @var string + */ + protected $content = ''; + + /** + * Get URls extracted from the content. + * + * @return array + */ + public function get_urls(): array { + return $this->urls; + } + + /** + * Set URls extracted from the content. + * + * @param array $urls URls extracted from the content. + * @return void + */ + public function set_urls( array $urls ): void { + $this->urls = $urls; + } + + /** + * Get lazyloaded content. + * + * @return string + */ + public function get_content(): string { + return $this->content; + } + + /** + * Set lazyloaded content. + * + * @param string $content Lazyloaded content. + * @return void + */ + public function set_content( string $content ): void { + $this->content = $content; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/ProtectedContent.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/ProtectedContent.php new file mode 100644 index 000000000..43342fd98 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Data/ProtectedContent.php @@ -0,0 +1,58 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Data; + +class ProtectedContent { + + /** + * Protected content. + * + * @var string + */ + protected $content = ''; + + /** + * Mapping between protected files and their placeholder. + * + * @var array + */ + protected $protected_files_mapping = []; + + /** + * Set protected content. + * + * @param string $content Protected content. + * @return void + */ + public function set_content( string $content ): void { + $this->content = $content; + } + + /** + * Get protected content. + * + * @return string + */ + public function get_content(): string { + return $this->content; + } + + /** + * Set mapping between protected files and their placeholder. + * + * @param array $protected_files_mapping Mapping between protected files and their placeholder. + * @return void + */ + public function set_protected_files_mapping( array $protected_files_mapping ): void { + $this->protected_files_mapping = $protected_files_mapping; + } + + /** + * Get mapping between protected files and their placeholder. + * + * @return array + */ + public function get_protected_files_mapping(): array { + return $this->protected_files_mapping; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/ContentFetcher.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/ContentFetcher.php new file mode 100644 index 000000000..fc0487885 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/ContentFetcher.php @@ -0,0 +1,68 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Front; + +use WP_Filesystem_Direct; +use WP_Rocket\Engine\Optimization\CSSTrait; + +class ContentFetcher { + + use CSSTrait; + + /** + * WordPress filesystem. + * + * @var WP_Filesystem_Direct + */ + protected $filesystem; + + /** + * Instance. + * + * @param WP_Filesystem_Direct $filesystem WordPress filesystem. + */ + public function __construct( WP_Filesystem_Direct $filesystem = null ) { + $this->filesystem = $filesystem ?: rocket_direct_filesystem(); + } + + /** + * Fetch content from the resource. + * + * @param string $path Path from the resource. + * @param string $destination Destination path. + * @return false|string + */ + public function fetch( string $path, string $destination ) { + $content = $this->fetch_content( $path ); + + if ( ! $content ) { + return false; + } + + $content = $this->move( $this->get_converter( $path, $destination ), $content, $path ); + + $this->set_cached_import( $path ); + + $content = $this->combine_imports( $content, $destination ); + + return $content; + } + + /** + * Fetch the content from the file. + * + * @param string $path Path to fetch. + * + * @return false|string + */ + protected function fetch_content( string $path ) { + if ( ! wp_http_validate_url( $path ) ) { + $file_extension = pathinfo( $path, PATHINFO_EXTENSION ); + + if ( strtolower( $file_extension ) !== 'php' ) { + return $this->filesystem->get_contents( $path ); + } + } + return wp_remote_retrieve_body( wp_remote_get( $path ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/Extractor.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/Extractor.php new file mode 100644 index 000000000..15c1ae8d8 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/Extractor.php @@ -0,0 +1,347 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Front; + +use WP_Rocket\Engine\Optimization\RegexTrait; +use WP_Rocket\Engine\Optimization\UrlTrait; + +class Extractor { + + use RegexTrait; + use UrlTrait; + + /** + * Comment mapping. + * + * @var array + */ + protected $comments_mapping = []; + + /** + * Extract background images from CSS. + * + * @param string $content CSS content. + * @param string $file_url File we are extracting css from. + * @return array + */ + public function extract( string $content, string $file_url = '' ): array { + + $this->comments_mapping = []; + + $comment_regex = '#/\*[^*]*\*+([^/][^*]*\*+)*/#'; + + $content = preg_replace_callback( + $comment_regex, + function ( $matches ) { + $id = '/*' . uniqid( 'bg_css_comment' ) . '*/'; + $this->comments_mapping[ $id ] = $matches[0]; + return $id; + }, + $content + ); + + $background_regex = '\s?{[^{}]*background\s*:(?<property>[^;}]*)[^}]*}'; + $background_image_regex = '(?:background-image)\s*:(?<property>[^;}]*)[^}]*}'; + + $content_reversed = strrev( $content ); + $format_content = $this->reformat_css( $content ); + + /** + * Lazyload background property regex. + * + * @param string $regex Lazyload background property regex. + */ + $background_regex = $this->apply_string_filter( 'lazyload_css_extract_bg_property_regex', $background_regex ); + + /** + * Lazyload background property regex. + * + * @param string $regex Lazyload background property regex. + */ + $background_image_regex = $this->apply_string_filter( 'lazyload_css_extract_bg_img_property_regex', $background_image_regex ); + + $background_matches = $this->find( $background_regex, $content, 'mi', PREG_OFFSET_CAPTURE ); + $background_image_matches = $this->find( $background_image_regex, $content, 'mi', PREG_OFFSET_CAPTURE ); + + $background_property_matches = $background_matches['property'] ?? []; + $background_image_property_matches = $background_image_matches['property'] ?? []; + + $matches = array_merge( $background_property_matches, $background_image_property_matches ); + + if ( empty( $matches ) ) { + return []; + } + + $results = []; + $arr_selector = []; + + foreach ( $matches as $match ) { + $original_offset = $match[1]; + $adjusted_offset = strlen( $content ) - $original_offset - strlen( $match[0] ); + + // Reverse the selector regex. + $reversed_selector_regex = '/dnuorgkcab[^{}]*{\s?(?<reversed_selector>(?:[ \-,:\w\.\(\)\n\r\$\|^>[*"\'=~\]#]|(?:\][^\]]+\[))+)/mi'; + + // Execute preg_match to find reversed selector. + preg_match( $reversed_selector_regex, $content_reversed, $reversed_selector_matches, PREG_OFFSET_CAPTURE, $adjusted_offset ); + + if ( empty( $reversed_selector_matches ) ) { + continue; + } + + // Extract reversed selector and reverse it back. + $reversed_selector = $reversed_selector_matches['reversed_selector'][0]; + $selector = trim( strrev( $reversed_selector ) ); + $property = trim( $match[0] ); + + $block_regex_selector = $selector; + $escaped_block_selector = preg_quote( $block_regex_selector, '/' ); + + preg_match_all( "/^\s*$escaped_block_selector\s*{(.*?)}/ms", $format_content, $block_matches ); + + $block_index = 0; + $default_index = 0; + + /** + * If block matches is empty then try to use the second regex pattern. + * The first pattern will match the selector literally but sometimes fails to match + * selector within an internal style, the second make sure we capture it. + * e.g. style>.selector_name within <style>.selector_name will not be capture + * with the first pattern. + */ + if ( empty( $block_matches[ $default_index ] ) ) { + preg_match_all( "/\s*$escaped_block_selector\s*{(.*?)}/ms", $format_content, $block_matches ); + } + + $urls = $this->extract_urls( $property, $file_url ); + + if ( in_array( $selector, $arr_selector, true ) ) { + $indexes = array_keys( $arr_selector, trim( $selector ), true ); + $block_index = count( $indexes ); + } + + $arr_selector[] = $selector; + + if ( empty( $block_matches ) ) { + continue; + } + + $block = trim( $block_matches[ $default_index ][ $default_index ] ); + + if ( ! empty( $block_matches[ $default_index ][ $block_index ] ) ) { + $block = trim( $block_matches[ $default_index ][ $block_index ] ); + } + + foreach ( $this->comments_mapping as $id => $comment ) { + $block = str_replace( $id, $comment, $block ); + } + + foreach ( $urls as $url ) { + $results[ $selector ][] = [ + 'selector' => $selector, + 'url' => $url['url'], + 'original' => $url['original'], + 'block' => $block, + ]; + } + } + + return $results; + } + + /** + * Extract URLS from a CSS property. + * + * @param string $content Content from the CSS property. + * @param string $file_url URL of the css file. + * @return array + */ + protected function extract_urls( string $content, string $file_url = '' ): array { + + /** + * Lazyload URL regex. + * + * @param string $regex Lazyload URL regex. + */ + $regex = $this->apply_string_filter( 'lazyload_css_extract_url_regex', '(?<tag>url\([\'"]?(?<url>[^\)]*)[\'"]?\))' ); + + $matches = $this->find( $regex, $content, 'mi' ); + + $output = []; + + /** + * Lazyload ignored URLs. + * + * @param string[] $urls Ignored URLs. + */ + $ignored_urls = (array) apply_filters( 'rocket_lazyload_css_ignored_urls', [] ); + + foreach ( $matches as $match ) { + + $url = $match['url'] ?: ''; + $url = str_replace( '"', '', $url ); + $url = str_replace( "'", '', $url ); + $url = trim( $url ); + $url = $this->make_url_complete( $url, $file_url ); + if ( ! key_exists( 'tag', $match ) || ! key_exists( 'url', $match ) || ! $url || $this->is_url_ignored( $url, $ignored_urls ) ) { + continue; + } + + if ( ! $this->is_url_external( $url ) && ! $this->is_relative( $url ) ) { + $url = $this->apply_string_filter( 'css_url', $url ); + } + + $original_url = trim( $match['tag'], ' ,' ); + $output[] = [ + 'url' => $url, + 'original' => $original_url, + ]; + } + + return $output; + } + + /** + * Reformat css most especially minified css to make sure each rule are on + * a separate line. + * + * @param string $css_content The css content to be formatted. + * + * @return string + */ + protected function reformat_css( string $css_content ): string { + $matches = $this->find( '(.*?\{.*?\})', $css_content, 's', PREG_PATTERN_ORDER ); + + $formatted_css = ''; + if ( empty( $matches ) ) { + return $css_content; + } + + foreach ( $matches[0] as $class_block ) { + $formatted_css .= $class_block . "\n"; + } + + return $formatted_css; + } + + /** + * Apply a string filter. + * + * @param string $name Name from the filter. + * @param string $value Value to pass to the filter that will be returned. + * @param array ...$args Additional values. + * @return string + */ + protected function apply_string_filter( string $name, string $value, ...$args ) { + $output = apply_filters( 'rocket_' . $name, $value, ...$args ); + + if ( ! is_string( $output ) ) { + return $value; + } + + return $output; + } + + /** + * Check if the URLs is ignored. + * + * @param string $url URL to check. + * @param array $ignored_urls List of ignored URLs. + * + * @return bool + */ + protected function is_url_ignored( string $url, array $ignored_urls ): bool { + foreach ( $ignored_urls as $ignored_url ) { + if ( strpos( $url, $ignored_url ) !== false ) { + return true; + } + } + return false; + } + + /** + * Complete the URL if necessary. + * + * @param string $url URL to complete. + * @param string $file_url URL of the CSS File. + * + * @return string + */ + protected function make_url_complete( string $url, string $file_url ): string { + $host = wp_parse_url( $url, PHP_URL_HOST ); + + if ( + $host + || + ( $this->is_relative( $url ) && ! empty( $file_url ) ) + ) { + return $this->transform_relative_to_absolute( $url, $file_url ); + } + + return rocket_get_home_url() . '/' . trim( $url, '/ ' ); + } + + + /** + * Transform a relative URL to an absolute URL based on the base URL. + * + * @param string $rel Relative URL to transform. + * @param string $base Base URL. + * + * @return string + */ + protected function transform_relative_to_absolute( string $rel, string $base = '' ): string { + if ( ! is_null( wp_parse_url( $rel, PHP_URL_SCHEME ) ) ) { + return $rel; + } + + if ( '#' === $rel[0] || '?' === $rel[0] ) { + return $base . $rel; + } + + $base_url_parts = wp_parse_url( $base ); + $path = ! empty( $base_url_parts['path'] ) ? $base_url_parts['path'] : '/'; + + $path = preg_replace( '#/[^/]*$#', '', $path ); + + if ( '/' === $rel[0] ) { + $path = ''; + } + + $abs = "$path/$rel"; + + $re = [ '#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#' ]; + + $dots_count = substr_count( $rel, '..' ); + + foreach ( range( 1, $dots_count ) as $n ) { + $abs_before = $abs; + $abs = preg_replace( $re, '/', $abs, -1, $n ); + + if ( $abs_before === $abs ) { + break; + } + } + + return trailingslashit( rocket_get_home_url() ) . ltrim( $abs, '/' ); + } + + + /** + * Check if the URL is external. + * + * @param string $url URL to check. + * + * @return bool + */ + protected function is_url_external( string $url ): bool { + $host = wp_parse_url( $url, PHP_URL_HOST ); + if ( ! $host ) { + return false; + } + + $home_host = wp_parse_url( rocket_get_home_url(), PHP_URL_HOST ); + + return $host !== $home_host; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/FileResolver.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/FileResolver.php new file mode 100644 index 000000000..3a021127a --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/FileResolver.php @@ -0,0 +1,23 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Front; + +class FileResolver { + + /** + * Resolves the name from the file from its URL. + * + * @param string $url URL from the file to resolve. + * @return string + */ + public function resolve( string $url ): string { + + $path = rocket_url_to_path( strtok( $url, '?' ) ); + + if ( ! $path ) { + return ''; + } + + return $path; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/MappingFormatter.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/MappingFormatter.php new file mode 100644 index 000000000..127eb8a32 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/MappingFormatter.php @@ -0,0 +1,126 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Front; + +class MappingFormatter { + + /** + * Format data for the Mapping file. + * + * @param array $data Data to format. + * @return array + */ + public function format( array $data ): array { + $formatted_urls = []; + + foreach ( $data as $datum ) { + $hash = $datum['hash']; + + $selector = $datum['selector']; + $selector = $this->remove_pseudo_classes( $selector ); + $url = $datum['url']; + + $placeholder = "--wpr-bg-$hash"; + $img_url = "url('$url')"; + $variable_placeholder = $datum['selector'] . '{' . $placeholder . ': ' . $img_url . ';}'; + $formatted_urls[] = [ + 'selector' => $selector, + 'style' => $variable_placeholder, + 'hash' => $hash, + 'url' => $url, + ]; + } + + return $formatted_urls; + } + + /** + * Get pseudo elements to remove. + * + * @return string[] + */ + private function get_pseudo_elements_to_remove() { + $original_pseudo_elements = [ + ':before', + ':after', + ':first-line', + ':first-letter', + ':active', + ':hover', + ':focus', + ':visited', + ':focus-within', + ':focus-visible', + ]; + + /** + * Pseudo elements to remove from lazyload CSS selector. + * + * @param string[] $original_pseudo_elements Pseudo elements to remove. + */ + $pseudo_elements_to_remove = apply_filters( 'rocket_lazyload_css_ignored_pseudo_elements', $original_pseudo_elements ); + + if ( ! is_array( $original_pseudo_elements ) ) { + $pseudo_elements_to_remove = $original_pseudo_elements; + } + + usort( + $pseudo_elements_to_remove, + static function ( $first, $second ) { + if ( strlen( $first ) === strlen( $second ) ) { + return 0; + } + return ( strlen( $first ) > strlen( $second ) ) ? -1 : 1; + } + ); + + return $pseudo_elements_to_remove; + } + + /** + * Remove pseudo classes from the selector while mapping on each selector. + * + * @param string $selector Selector to clean. + * @return string + */ + public function remove_pseudo_classes_for_selector( string $selector ): string { + $selector = preg_replace( '/::[\w-]+/', '', $selector ); + + $pseudo_elements_to_remove = $this->get_pseudo_elements_to_remove(); + foreach ( $pseudo_elements_to_remove as $element ) { + $selector = str_replace( $element, '', $selector ); + } + if ( in_array( substr( $selector, -1 ), [ '&', '~', '+', '>' ], true ) ) { + $selector .= '*'; + } + + if ( ! $selector ) { + return 'body'; + } + + return $selector; + } + + + /** + * Remove pseudo classes from the selector. + * + * @param string $selector Selector to clean. + * @return string + */ + protected function remove_pseudo_classes( string $selector ): string { + $selectors = explode( ',', $selector ); + + $selectors = array_map( [ $this, 'remove_pseudo_classes_for_selector' ], $selectors ); + + $selectors = array_unique( $selectors ); + + $selector = implode( ',', $selectors ); + + if ( ! $selector ) { + return 'body'; + } + + return (string) $selector; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/RuleFormatter.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/RuleFormatter.php new file mode 100644 index 000000000..59feb0229 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/RuleFormatter.php @@ -0,0 +1,71 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Front; + +class RuleFormatter { + + /** + * Format the CSS rule inside the CSS content. + * + * @param string $css CSS content. + * @param array $data Data to format. + * @return string + */ + public function format( string $css, array $data ): string { + if ( count( $data ) === 0 ) { + return $css; + } + + $block = ''; + $replaced_block = null; + + $blocks = []; + + foreach ( $data as $datum ) { + $added = false; + foreach ( $blocks as &$block ) { + if ( $block['block'] === $datum['block'] ) { + $block['items'] [] = $datum; + $added = true; + break; + } + } + + if ( $added ) { + continue; + } + + $blocks [] = [ + 'items' => [ + $datum, + ], + 'block' => $datum['block'], + ]; + } + + foreach ( $blocks as $block ) { + $replaced_block = null; + foreach ( $block['items'] as $datum ) { + if ( ! key_exists( 'selector', $datum ) || ! key_exists( 'original', $datum ) || ! key_exists( 'block', $datum ) || ! key_exists( 'hash', $datum ) ) { + return $css; + } + + $original_block = $datum['block']; + $replaced_block = $replaced_block ?: $datum['block']; + $url = $datum['original']; + + $hash = $datum['hash']; + + $placeholder = "--wpr-bg-$hash"; + $variable_placeholder = "var($placeholder)"; + + $replaced_block = str_replace( $url, $variable_placeholder, $replaced_block ); + + } + + $css = str_replace( $original_block, $replaced_block, $css ); + } + + return $css; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/TagGenerator.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/TagGenerator.php new file mode 100644 index 000000000..872b7bb06 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Front/TagGenerator.php @@ -0,0 +1,50 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS\Front; + +class TagGenerator { + + /** + * Generate tags from the mapping of lazyloaded images. + * + * @param array $mapping Lazyload images mapping. + * @param array $loaded Excluded images. + * @return string + */ + public function generate( array $mapping, array $loaded = [] ): string { + $mapping = array_filter( + $mapping, + function ( $mapping_item ) use ( $loaded ) { + foreach ( $loaded as $exclude_item ) { + if ( $exclude_item['style'] === $mapping_item['style'] ) { + return false; // Exclude matching elements. + } + } + return true; // Include non-matching elements. + } + ); + $mapping = array_values( $mapping ); + $loaded_content = ''; + foreach ( $loaded as $item ) { + $loaded_content .= $item['style']; + } + $loaded_tag = "<style id=\"wpr-lazyload-bg-container\"></style><style id=\"wpr-lazyload-bg-exclusion\">$loaded_content</style>"; + + $nostyle_content = ''; + foreach ( $mapping as $item ) { + $nostyle_content .= $item['style']; + } + $nostyle_tag = "<noscript> +<style id=\"wpr-lazyload-bg-nostyle\">$nostyle_content</style> +</noscript>"; + + $mapping_json = wp_json_encode( $mapping ); + $loaded_json = wp_json_encode( $loaded ); + + $script_content = "const rocket_pairs = $mapping_json; const rocket_excluded_pairs = $loaded_json;"; + + $script_tag = "<script type=\"application/javascript\">$script_content</script>"; + + return "$loaded_tag\n$nostyle_tag\n$script_tag"; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/ServiceProvider.php new file mode 100644 index 000000000..10f018994 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/ServiceProvider.php @@ -0,0 +1,79 @@ +<?php + +namespace WP_Rocket\Engine\Media\Lazyload\CSS; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Common\Cache\FilesystemCache; +use WP_Rocket\Engine\Media\Lazyload\CSS\Context\LazyloadCSSContext; +use WP_Rocket\Engine\Media\Lazyload\CSS\Data\LazyloadCSSContentFactory; +use WP_Rocket\Engine\Media\Lazyload\CSS\Front\{ContentFetcher, + Extractor, + FileResolver, + MappingFormatter, + RuleFormatter, + TagGenerator}; + + +/** + * Service provider. + */ +class ServiceProvider extends AbstractServiceProvider { + /** + * Array of services provided by this service provider + * + * @var array + */ + protected $provides = [ + 'lazyload_css_cache', + 'lazyload_css_subscriber', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container + * + * @return void + */ + public function register(): void { + $this->getContainer()->add( 'lazyload_css_cache', FilesystemCache::class ) + ->addArgument( apply_filters( 'rocket_lazyload_css_cache_root', 'background-css/' . get_current_blog_id() ) ); + + $cache = $this->getContainer()->get( 'lazyload_css_cache' ); + + $this->getContainer()->add( 'lazyload_css_context', LazyloadCSSContext::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $cache ); + + $this->getContainer()->add( 'lazyload_css_fetcher', ContentFetcher::class ); + + $this->getContainer()->add( 'lazyload_css_extractor', Extractor::class ); + $this->getContainer()->add( 'lazyload_css_file_resolver', FileResolver::class ); + $this->getContainer()->add( 'lazyload_css_json_formatter', MappingFormatter::class ); + $this->getContainer()->add( 'lazyload_css_rule_formatter', RuleFormatter::class ); + $this->getContainer()->add( 'lazyload_css_tag_generator', TagGenerator::class ); + + $this->getContainer()->add( 'lazyload_css_factory', LazyloadCSSContentFactory::class ); + + $this->getContainer()->addShared( 'lazyload_css_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'lazyload_css_extractor' ) ) + ->addArgument( $this->getContainer()->get( 'lazyload_css_rule_formatter' ) ) + ->addArgument( $this->getContainer()->get( 'lazyload_css_file_resolver' ) ) + ->addArgument( $cache ) + ->addArgument( $this->getContainer()->get( 'lazyload_css_json_formatter' ) ) + ->addArgument( $this->getContainer()->get( 'lazyload_css_tag_generator' ) ) + ->addArgument( $this->getContainer()->get( 'lazyload_css_fetcher' ) ) + ->addArgument( $this->getContainer()->get( 'lazyload_css_context' ) ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'lazyload_css_factory' ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Subscriber.php new file mode 100644 index 000000000..53d90ffe2 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CSS/Subscriber.php @@ -0,0 +1,723 @@ +<?php +namespace WP_Rocket\Engine\Media\Lazyload\CSS; + +use WP_Filesystem_Direct; +use WP_Post; +use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Common\Context\ContextInterface; +use WP_Rocket\Engine\Media\Lazyload\CSS\Data\LazyloadedContent; +use WP_Rocket\Engine\Media\Lazyload\CSS\Data\LazyloadCSSContentFactory; +use WP_Rocket\Engine\Media\Lazyload\CSS\Data\ProtectedContent; +use WP_Rocket\Engine\Media\Lazyload\CSS\Front\{ContentFetcher, + Extractor, + FileResolver, + MappingFormatter, + RuleFormatter, + TagGenerator}; +use WP_Rocket\Engine\Common\Cache\CacheInterface; +use WP_Rocket\Engine\Optimization\RegexTrait; +use WP_Rocket\Event_Management\Subscriber_Interface; +use WP_Rocket\Logger\LoggerAware; +use WP_Rocket\Logger\LoggerAwareInterface; + +class Subscriber implements Subscriber_Interface, LoggerAwareInterface { + use LoggerAware; + use RegexTrait; + + /** + * Extract background images from CSS. + * + * @var Extractor + */ + protected $extractor; + + /** + * Cache instance. + * + * @var CacheInterface + */ + protected $cache; + + /** + * Format the CSS rule inside the CSS content. + * + * @var RuleFormatter + */ + protected $rule_formatter; + + /** + * Resolves the name from the file from its URL. + * + * @var FileResolver + */ + protected $file_resolver; + + /** + * Format data for the Mapping file. + * + * @var MappingFormatter + */ + protected $mapping_formatter; + + /** + * Generate tags from the mapping of lazyloaded images. + * + * @var TagGenerator + */ + protected $tag_generator; + + /** + * Fetch content. + * + * @var ContentFetcher + */ + protected $fetcher; + + /** + * Context. + * + * @var ContextInterface + */ + protected $context; + + /** + * WPR Options. + * + * @var Options_Data + */ + protected $options; + + /** + * Make LazyloadedContent instance. + * + * @var LazyloadCSSContentFactory + */ + protected $lazyloaded_content_factory; + + /** + * WordPress filesystem. + * + * @var WP_Filesystem_Direct + */ + protected $filesystem; + + /** + * Instantiate class. + * + * @param Extractor $extractor Extract background images from CSS. + * @param RuleFormatter $rule_formatter Format the CSS rule inside the CSS content. + * @param FileResolver $file_resolver Resolves the name from the file from its URL. + * @param CacheInterface $cache Cache instance. + * @param MappingFormatter $mapping_formatter Format data for the Mapping file. + * @param TagGenerator $tag_generator Generate tags from the mapping of lazy loaded images. + * @param ContentFetcher $fetcher Fetch content. + * @param ContextInterface $context Context. + * @param Options_Data $options WPR Options. + * @param LazyloadCSSContentFactory $lazyloaded_content_factory Make LazyloadedContent instance. + * @param WP_Filesystem_Direct|null $filesystem WordPress filesystem. + */ + public function __construct( Extractor $extractor, RuleFormatter $rule_formatter, FileResolver $file_resolver, CacheInterface $cache, MappingFormatter $mapping_formatter, TagGenerator $tag_generator, ContentFetcher $fetcher, ContextInterface $context, Options_Data $options, LazyloadCSSContentFactory $lazyloaded_content_factory, WP_Filesystem_Direct $filesystem = null ) { + $this->extractor = $extractor; + $this->cache = $cache; + $this->rule_formatter = $rule_formatter; + $this->file_resolver = $file_resolver; + $this->mapping_formatter = $mapping_formatter; + $this->tag_generator = $tag_generator; + $this->context = $context; + $this->options = $options; + $this->fetcher = $fetcher; + $this->lazyloaded_content_factory = $lazyloaded_content_factory; + $this->filesystem = $filesystem ?: rocket_direct_filesystem(); + } + + /** + * Returns an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'rocket_generate_lazyloaded_css' => [ + [ 'create_lazy_css_files', 18 ], + [ 'create_lazy_inline_css', 21 ], + [ 'add_lazy_tag', 24 ], + ], + 'rocket_buffer' => [ 'maybe_replace_css_images', 1002 ], + 'rocket_after_clean_domain' => 'clear_generated_css', + 'wp_enqueue_scripts' => 'insert_lazyload_script', + 'rocket_css_image_lazyload_images_load' => [ 'exclude_rocket_lazyload_excluded_src', 10, 2 ], + 'rocket_lazyload_css_ignored_urls' => 'remove_svg_from_lazyload_css', + ]; + } + + /** + * Replace CSS images by the lazyloaded version. + * + * @param string $html page HTML. + * @return string + */ + public function maybe_replace_css_images( string $html ): string { + + if ( ! $this->context->is_allowed() ) { + return $html; + } + + $this->logger::debug( + 'Starting lazyload', + $this->generate_log_context( + [ + 'data' => $html, + ] + ) + ); + + /** + * Generate lazyload CSS for the page. + * + * @param array $data Data passed to generate the lazyload CSS. + */ + $output = apply_filters( + 'rocket_generate_lazyloaded_css', + [ + 'html' => $html, + ] + ); + + if ( ! is_array( $output ) || ! key_exists( 'html', $output ) ) { + $this->logger::debug( + 'Lazyload bailed out', + $this->generate_log_context( + [ + 'data' => $html, + ] + ) + ); + return $html; + } + + $this->logger::debug( + 'Ending lazyload', + $this->generate_log_context( + [ + 'data' => $html, + ] + ) + ); + + return $output['html']; + } + + /** + * Clear the lazyload CSS files. + * + * @return void + */ + public function clear_generated_css() { + $this->logger::debug( + 'Clear lazy CSS', + $this->generate_log_context() + ); + $this->cache->clear(); + } + + /** + * Insert the lazyload script. + * + * @return void + */ + public function insert_lazyload_script() { + if ( ! $this->context->is_allowed() ) { + return; + } + + /** + * Filters the threshold at which lazyload is triggered + * + * @since 1.2 + * + * @param int $threshold Threshold value. + */ + $threshold = (int) apply_filters( 'rocket_lazyload_threshold', 300 ); + + $script_path = rocket_get_constant( 'WP_ROCKET_ASSETS_JS_PATH' ) . 'lazyload-css.min.js'; + + if ( ! $this->filesystem->exists( $script_path ) ) { + return; + } + + $content = $this->filesystem->get_contents( $script_path ); + + if ( ! $content ) { + return; + } + + wp_register_script( 'rocket_lazyload_css', '', [], false, true ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NoExplicitVersion + wp_enqueue_script( 'rocket_lazyload_css' ); + wp_add_inline_script( 'rocket_lazyload_css', $content, 'after' ); + wp_localize_script( + 'rocket_lazyload_css', + 'rocket_lazyload_css_data', + [ + 'threshold' => $threshold, + ] + ); + } + + /** + * Create the lazyload file for CSS files. + * + * @param array $data Data sent. + * @return array + */ + public function create_lazy_css_files( array $data ): array { + if ( ! key_exists( 'html', $data ) || ! key_exists( 'css_files', $data ) ) { + $this->logger::debug( + 'Create lazy css files bailed out', + $this->generate_log_context( + [ + 'data' => $data, + ] + ) + ); + return $data; + } + + $html = $data['html']; + $html = $this->replace_html_comments( $html ); + $mapping = []; + + $css_files = array_unique( $data['css_files'] ); + + $protected_content = $this->protect_css_urls( $html, $css_files ); + + $html = $protected_content->get_content(); + $css_files_mapping = $protected_content->get_protected_files_mapping(); + + foreach ( $css_files as $url ) { + + if ( $this->is_excluded( $url ) ) { + $this->logger::debug( + "Excluded lazy css files $url", + $this->generate_log_context() + ); + continue; + } + + $url_key = $this->format_url( $url ); + if ( ! $this->cache->has( $url_key ) ) { + $this->logger::debug( + "Generate lazy css files $url", + $this->generate_log_context() + ); + + $file_mapping = $this->generate_css_file( $url ); + if ( empty( $file_mapping ) ) { + $this->logger::debug( + "Create lazy css files $url bailed out", + $this->generate_log_context() + ); + continue; + } + + $mapping = array_merge( $mapping, $file_mapping ); + + } else { + $this->logger::debug( + "Load lazy css files $url", + $this->generate_log_context() + ); + $mapping = array_merge( $mapping, $this->load_existing_mapping( $url ) ); + } + + $cached_url = $this->generate_asset_url( $url ); + + $html = str_replace( $css_files_mapping[ $url ], $cached_url, $html ); + } + + foreach ( $css_files_mapping as $url => $placeholder ) { + $html = str_replace( $placeholder, $url, $html ); + } + + $html = $this->restore_html_comments( $html ); + + $data['html'] = $html; + + if ( ! key_exists( 'lazyloaded_images', $data ) ) { + $data['lazyloaded_images'] = []; + } + + $data['lazyloaded_images'] = array_merge( $data['lazyloaded_images'], $mapping ); + $data['lazyloaded_images'] = array_unique( $data['lazyloaded_images'], SORT_REGULAR ); + + return $data; + } + + /** + * Add the lazy tag to the current HTML. + * + * @param array $data Data sent. + * @return array + */ + public function add_lazy_tag( array $data ): array { + + if ( ! key_exists( 'html', $data ) || ! key_exists( 'lazyloaded_images', $data ) ) { + $this->logger::debug( + 'Add lazy tag bailed out', + $this->generate_log_context( + [ + 'data' => $data, + ] + ) + ); + return $data; + } + + $lazyload_images = $data['lazyloaded_images']; + + /** + * Lazyload background CSS excluded urls. + * + * @param array $excluded Excluded URLs. + * @param array $urls List of Urls processed. + */ + $loaded = apply_filters( 'rocket_css_image_lazyload_images_load', [], $lazyload_images ); + + $tags = $this->tag_generator->generate( $lazyload_images, $loaded ); + $this->logger::debug( + 'Add lazy tag generated', + $this->generate_log_context( + [ + 'data' => $tags, + ] + ) + ); + $data['html'] = str_replace( '</head>', "$tags</head>", $data['html'] ); + + return $data; + } + + /** + * Generate lazy CSS for a file. + * + * @param string $url Url from the CSS. + * @return array + */ + protected function generate_css_file( string $url ) { + $path = $this->file_resolver->resolve( $url ); + + if ( ! $path ) { + $path = $url; + } + + $content = $this->fetcher->fetch( $path, $this->cache->generate_path( $url ) ); + + if ( ! $content ) { + return []; + } + + $output = $this->generate_content( $content, $this->cache->generate_url( $url ) ); + + if ( count( $output->get_urls() ) === 0 ) { + return []; + } + + if ( ! $this->cache->set( $this->format_url( $url ), $output->get_content() ) ) { + return []; + } + + $this->cache->set( $this->get_mapping_file_url( $url ), json_encode( $output->get_urls() ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode + + return $output->get_urls(); + } + + /** + * Generate lazy content for a certain content. + * + * @param string $content Content to generate lazy for. + * @param string $url URL of the file we are extracting content from. + * @return LazyloadedContent + */ + protected function generate_content( string $content, string $url = '' ): LazyloadedContent { + $urls = $this->extractor->extract( $content, $url ); + $formatted_urls = []; + foreach ( $urls as $url_tags ) { + $url_tags = $this->add_hashes( $url_tags ); + $content = $this->rule_formatter->format( $content, $url_tags ); + $formatted_urls = array_merge( $formatted_urls, $this->mapping_formatter->format( $url_tags ) ); + } + + return $this->lazyloaded_content_factory->make_lazyloaded_content( $formatted_urls, $content ); + } + + /** + * Load existing mapping for a URL. + * + * @param string $url Url we load mapping for. + * @return array + */ + protected function load_existing_mapping( string $url ) { + $content = $this->cache->get( $this->get_mapping_file_url( $url ) ); + $urls = json_decode( $content, true ); + if ( ! $urls ) { + return []; + } + return $urls; + } + + /** + * Create the lazyload file for inline CSS. + * + * @param array $data Data sent. + * @return array + */ + public function create_lazy_inline_css( array $data ): array { + + if ( ! key_exists( 'html', $data ) || ! key_exists( 'css_inline', $data ) ) { + $this->logger::debug( + 'Create lazy css inline bailed out', + $this->generate_log_context( + [ + 'data' => $data, + ] + ) + ); + return $data; + } + + $html = $data['html']; + + if ( ! key_exists( 'lazyloaded_images', $data ) ) { + $data['lazyloaded_images'] = []; + } + + foreach ( $data['css_inline'] as $content ) { + + $output = $this->generate_content( $content ); + + $html = str_replace( $content, $output->get_content(), $html ); + + $data['lazyloaded_images'] = array_merge( $data['lazyloaded_images'], $output->get_urls() ); + } + + $data['html'] = $html; + + return $data; + } + + /** + * Format a URL. + * + * @param string $url URL to format. + * @return string + */ + protected function format_url( string $url ): string { + return strtok( $url, '?' ); + } + + /** + * Check of the string is excluded. + * + * @param string $string String to check. + * @return bool + */ + protected function is_excluded( string $string ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.stringFound + + $values = [ + $string, + ]; + + $parsed_url_host = wp_parse_url( $string, PHP_URL_HOST ); + + if ( ! $parsed_url_host ) { + $values [] = rocket_get_home_url() . $string; + } + + /** + * Filters the src used to prevent lazy load from being applied. + * + * @param array $excluded_src An array of excluded src. + */ + $excluded_values = apply_filters( 'rocket_lazyload_excluded_src', [] ); + + if ( ! is_array( $excluded_values ) ) { + $excluded_values = (array) $excluded_values; + } + + if ( empty( $excluded_values ) ) { + return false; + } + + foreach ( $values as $value ) { + foreach ( $excluded_values as $excluded_value ) { + if ( strpos( $value, $excluded_value ) !== false ) { + return true; + } + } + } + + return false; + } + + /** + * Is the feature activated. + * + * @return bool + */ + protected function is_activated(): bool { + return (bool) $this->options->get( 'lazyload_css_bg_img', false ); + } + + /** + * Add lazyload_excluded_src to excluded filters. + * + * @param array $excluded Excluded URLs. + * @param array $urls List of Urls processed. + * @return mixed + */ + public function exclude_rocket_lazyload_excluded_src( $excluded, $urls ) { + + /** + * Filters the src used to prevent lazy load from being applied. + * + * @param array $excluded_src An array of excluded src. + */ + $excluded_values = apply_filters( 'rocket_lazyload_excluded_src', [] ); + + if ( ! is_array( $excluded_values ) ) { + $excluded_values = (array) $excluded_values; + } + + if ( empty( $excluded_values ) ) { + return $excluded; + } + + foreach ( $urls as $url ) { + foreach ( $excluded_values as $excluded_value ) { + if ( strpos( $url['selector'], $excluded_value ) !== false || strpos( $url['style'], $excluded_value ) !== false ) { + $excluded[] = $url; + break; + } + } + } + + return $excluded; + } + + /** + * Add hashes. + * + * @param array $tags Tags. + * @return array + */ + protected function add_hashes( array $tags ): array { + return array_map( + function ( $url_tag ) { + /** + * Lazyload CSS hash. + * + * @param string $hash Lazyload CSS hash. + * @param mixed $url_tag URL tag. + */ + $url_tag['hash'] = apply_filters( 'rocket_lazyload_css_hash', wp_generate_uuid4(), $url_tag ); + return $url_tag; + }, + $tags + ); + } + + /** + * Return mapping file URL. + * + * @param string $url Resource URL. + * @return string + */ + protected function get_mapping_file_url( string $url ): string { + return $this->format_url( $url ) . '.json'; + } + + /** + * Add timestamp to URL. + * + * @param string $url Asset Url. + * + * @return string + */ + protected function generate_asset_url( string $url ): string { + $parsed_query = wp_parse_url( $url, PHP_URL_QUERY ); + $queries = []; + + if ( $parsed_query ) { + parse_str( $parsed_query, $queries ); + } + + $queries['wpr_t'] = current_time( 'timestamp' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested + + $cached_url = $this->cache->generate_url( $this->format_url( $url ) ); + + $this->logger::debug( + "Generated url lazy css files $url", + $this->generate_log_context( + [ + 'data' => $cached_url, + ] + ) + ); + + return add_query_arg( $queries, $cached_url ); + } + + /** + * Generate the context for logs. + * + * @param array $data Data to pass to logs. + * @return array + */ + protected function generate_log_context( array $data = [] ): array { + return array_merge( + $data, + [ + 'type' => 'lazyload_css_bg_images', + ] + ); + } + + /** + * Protect URL inside the content. + * + * @param string $content Content to protect. + * @param array $css_files CSS files from the content. + * @return ProtectedContent + */ + protected function protect_css_urls( string $content, array $css_files ): ProtectedContent { + usort( + $css_files, + function ( $url1, $url2 ) { + return strlen( $url1 ) < strlen( $url2 ) ? 1 : -1; + } + ); + + $css_files_mapping = []; + + foreach ( $css_files as $url ) { + $placeholder = uniqid( 'url_bg_css_' ); + + $content = str_replace( $url, $placeholder, $content ); + + $css_files_mapping[ $url ] = $placeholder; + } + + return $this->lazyloaded_content_factory->make_protected_content( $css_files_mapping, $content ); + } + + /** + * Exclude SVG from lazy loaded images. + * + * @param array $urls URLs to exclude. + * @return array + */ + public function remove_svg_from_lazyload_css( array $urls ): array { + $urls[] = 'data:image/svg+xml'; + + return $urls; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CanLazyloadTrait.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CanLazyloadTrait.php new file mode 100644 index 000000000..6a30f1ec8 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/CanLazyloadTrait.php @@ -0,0 +1,61 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Media\Lazyload; + +trait CanLazyloadTrait { + /** + * Checks if lazyload should be applied + * + * @since 3.3 + * + * @return bool + */ + protected function should_lazyload() { + if ( + rocket_get_constant( 'REST_REQUEST', false ) + || + rocket_get_constant( 'DONOTLAZYLOAD', false ) + || + rocket_get_constant( 'DONOTROCKETOPTIMIZE', false ) + || + rocket_get_constant( 'DONOTCACHEPAGE', false ) + ) { + return false; + } + + if ( + is_admin() + || + is_feed() + || + is_preview() + ) { + return false; + } + + if ( + is_search() + && + // This filter is documented in inc/classes/Buffer/class-tests.php. + ! (bool) apply_filters( 'rocket_cache_search', false ) + ) { + return false; + } + + // Exclude Page Builders editors. + $excluded_parameters = [ + 'fl_builder', + 'et_fb', + 'ct_builder', + ]; + + foreach ( $excluded_parameters as $excluded ) { + if ( isset( $_GET[ $excluded ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return false; + } + } + + return true; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/Subscriber.php index c25290f4a..50ddd5919 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/Lazyload/Subscriber.php @@ -7,6 +7,7 @@ use WP_Rocket\Dependencies\RocketLazyload\Image; use WP_Rocket\Dependencies\RocketLazyload\Iframe; use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Optimization\RegexTrait; use WP_Rocket\Event_Management\Subscriber_Interface; /** @@ -15,7 +16,10 @@ * @since 3.3 */ class Subscriber implements Subscriber_Interface { - const SCRIPT_VERSION = '16.1'; + use RegexTrait; + use CanLazyloadTrait; + + const SCRIPT_VERSION = '17.8.3'; /** * Options_Data instance @@ -71,20 +75,21 @@ public function __construct( Options_Data $options, Assets $assets, Image $image */ public static function get_subscribed_events() { return [ - 'wp_footer' => [ + 'wp_footer' => [ [ 'insert_lazyload_script', PHP_INT_MAX ], [ 'insert_youtube_thumbnail_script', PHP_INT_MAX ], ], - 'wp_head' => [ 'insert_nojs_style', PHP_INT_MAX ], - 'wp_enqueue_scripts' => [ 'insert_youtube_thumbnail_style', PHP_INT_MAX ], - 'rocket_buffer' => [ 'lazyload', 18 ], - 'rocket_lazyload_html' => 'lazyload_responsive', - 'init' => 'lazyload_smilies', - 'wp' => 'deactivate_lazyload_on_specific_posts', - 'wp_lazy_loading_enabled' => 'maybe_disable_core_lazyload', - 'rocket_lazyload_excluded_attributes' => 'add_exclusions', - 'rocket_lazyload_excluded_src' => 'add_exclusions', - 'rocket_lazyload_iframe_excluded_patterns' => 'add_exclusions', + 'wp_head' => [ 'insert_nojs_style', PHP_INT_MAX ], + 'wp_enqueue_scripts' => [ 'insert_youtube_thumbnail_style', PHP_INT_MAX ], + 'rocket_buffer' => [ 'lazyload', 18 ], + 'rocket_lazyload_html' => 'lazyload_responsive', + 'init' => 'lazyload_smilies', + 'wp' => 'deactivate_lazyload_on_specific_posts', + 'wp_lazy_loading_enabled' => [ 'maybe_disable_core_lazyload', 10, 2 ], + 'rocket_lazyload_excluded_attributes' => 'add_exclusions', + 'rocket_lazyload_excluded_src' => 'add_exclusions', + 'rocket_lazyload_iframe_excluded_patterns' => 'add_exclusions', + 'rocket_lazyload_exclude_youtube_thumbnail' => 'add_exclusions', ]; } @@ -104,20 +109,9 @@ public function insert_lazyload_script() { return; } - /** - * Filters the use of the polyfill for intersectionObserver - * - * @since 3.3 - * @author Remy Perona - * - * @param bool $polyfill True to use the polyfill, false otherwise. - */ - $polyfill = (bool) apply_filters( 'rocket_lazyload_polyfill', false ); - $script_args = [ 'base_url' => rocket_get_constant( 'WP_ROCKET_ASSETS_JS_URL' ) . 'lazyload/', 'version' => self::SCRIPT_VERSION, - 'polyfill' => $polyfill, ]; $this->add_inline_script(); @@ -153,7 +147,6 @@ private function set_inline_script_args() { * Filters the threshold at which lazyload is triggered * * @since 1.2 - * @author Remy Perona * * @param int $threshold Threshold value. */ @@ -167,19 +160,19 @@ private function set_inline_script_args() { * Filters the use of native lazyload * * @since 3.4 - * @author Remy Perona * * @param bool $use_native True to use native lazyload, false otherwise. */ if ( (bool) apply_filters( 'rocket_use_native_lazyload', false ) ) { - $inline_args['options'] = [ - 'use_native' => 'true', - ]; - $inline_args['elements']['loading'] = '[loading=lazy]'; + $inline_args['options']['use_native'] = true; + $inline_args['elements']['loading'] = '[loading=lazy]'; } if ( $this->options->get( 'lazyload', 0 ) ) { - $inline_args['elements']['image'] = 'img[data-lazy-src]'; + if ( ! $this->is_native_images() ) { + $inline_args['elements']['image'] = 'img[data-lazy-src]'; + } + $inline_args['elements']['background_image'] = '.rocket-lazyload'; } @@ -191,7 +184,6 @@ private function set_inline_script_args() { * Filters the arguments array for the lazyload script options * * @since 3.3 - * @author Remy Perona * * @param array $inline_args Arguments used for the lazyload script options. */ @@ -233,7 +225,6 @@ public function insert_youtube_thumbnail_script() { * * @since 1.4.8 * @deprecated 3.3 - * @author Arun Basil Lal * * @param string $thumbnail_resolution The resolution of the thumbnail. Accepted values: default, mqdefault, hqdefault, sddefault, maxresdefault */ @@ -243,16 +234,29 @@ public function insert_youtube_thumbnail_script() { * Filters the resolution of the YouTube thumbnail * * @since 1.4.8 - * @author Arun Basil Lal * * @param string $thumbnail_resolution The resolution of the thumbnail. Accepted values: default, mqdefault, hqdefault, sddefault, maxresdefault */ $thumbnail_resolution = apply_filters( 'rocket_lazyload_youtube_thumbnail_resolution', $thumbnail_resolution ); + /** + * Extension from the thumbnail from Youtube video. + * + * @param string $extension extension from the thumbnail from Youtube video. + * @returns string + */ + $extension = apply_filters( 'rocket_lazyload_youtube_thumbnail_extension', 'jpg' ); + + if ( ! is_string( $extension ) || ! in_array( $extension, [ 'jpg', 'webp' ], true ) ) { + $extension = 'jpg'; + } + $this->assets->insertYoutubeThumbnailScript( [ 'resolution' => $thumbnail_resolution, 'lazy_image' => (bool) $this->options->get( 'lazyload' ), + 'native' => $this->is_native_images(), + 'extension' => $extension, ] ); } @@ -304,59 +308,6 @@ public function insert_youtube_thumbnail_style() { ); } - /** - * Checks if lazyload should be applied - * - * @since 3.3 - * - * @return bool - */ - private function should_lazyload() { - if ( - rocket_get_constant( 'REST_REQUEST', false ) - || - rocket_get_constant( 'DONOTLAZYLOAD', false ) - || - rocket_get_constant( 'DONOTROCKETOPTIMIZE', false ) - ) { - return false; - } - - if ( - is_admin() - || - is_feed() - || - is_preview() - ) { - return false; - } - - if ( - is_search() - && - // This filter is documented in inc/classes/Buffer/class-tests.php. - ! (bool) apply_filters( 'rocket_cache_search', false ) - ) { - return false; - } - - // Exclude Page Builders editors. - $excluded_parameters = [ - 'fl_builder', - 'et_fb', - 'ct_builder', - ]; - - foreach ( $excluded_parameters as $excluded ) { - if ( isset( $_GET[ $excluded ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended - return false; - } - } - - return true; - } - /** * Applies lazyload on the provided content * @@ -370,8 +321,8 @@ public function lazyload( $html ) { return $html; } - $buffer = $this->ignore_scripts( $html ); - $buffer = $this->ignore_noscripts( $buffer ); + $buffer = $this->hide_scripts( $html ); + $buffer = $this->hide_noscripts( $buffer ); if ( $this->can_lazyload_iframes() ) { $args = [ @@ -382,8 +333,14 @@ public function lazyload( $html ) { } if ( $this->can_lazyload_images() ) { - $html = $this->image->lazyloadPictures( $html, $buffer ); - $html = $this->image->lazyloadImages( $html, $buffer ); + if ( ! $this->is_native_images() ) { + $html = $this->image->lazyloadPictures( $html, $buffer ); + + $buffer = $this->hide_scripts( $html ); + $buffer = $this->hide_noscripts( $buffer ); + } + + $html = $this->image->lazyloadImages( $html, $buffer, $this->is_native_images() ); /** * Filters the application of lazyload on background images @@ -409,6 +366,10 @@ public function lazyload( $html ) { * @return string */ public function lazyload_responsive( $html ) { + if ( $this->is_native_images() ) { + return $html; + } + return $this->image->lazyloadResponsiveAttributes( $html ); } @@ -466,15 +427,25 @@ public function deactivate_lazyload_on_specific_posts() { * * @since 3.5 * - * @param bool $value Current value for the enabling variable. + * @param bool $value Current value for the enabling variable. + * @param string $tag_name The tag name. + * * @return bool */ - public function maybe_disable_core_lazyload( $value ) { - if ( false === $value ) { + public function maybe_disable_core_lazyload( $value, $tag_name ) { + if ( false === $value || rocket_bypass() ) { return $value; } - return ! (bool) $this->can_lazyload_images(); + if ( 'img' === $tag_name ) { + return ! (bool) $this->can_lazyload_images(); + } + + if ( 'iframe' === $tag_name ) { + return ! (bool) $this->can_lazyload_iframes(); + } + + return $value; } /** @@ -485,7 +456,11 @@ public function maybe_disable_core_lazyload( $value ) { * @param array $exclusions Array of excluded patterns. * @return array */ - public function add_exclusions( array $exclusions ) : array { + public function add_exclusions( $exclusions ): array { + if ( ! is_array( $exclusions ) ) { + $exclusions = []; + } + $exclude_lazyload = $this->options->get( 'exclude_lazyload', [] ); if ( empty( $exclude_lazyload ) ) { @@ -495,18 +470,6 @@ public function add_exclusions( array $exclusions ) : array { return array_unique( array_merge( $exclusions, $exclude_lazyload ) ); } - /** - * Remove inline scripts from the HTML to parse - * - * @since 3.3 - * - * @param string $html HTML content. - * @return string - */ - private function ignore_scripts( $html ) { - return preg_replace( '/<script\b(?:[^>]*)>(?:.+)?<\/script>/Umsi', '', $html ); - } - /** * Checks if we can lazyload images. * @@ -523,7 +486,6 @@ private function can_lazyload_images() { * Filters the lazyload application on images * * @since 2.0 - * @author Remy Perona * * @param bool $do_rocket_lazyload True to apply lazyload, false otherwise. */ @@ -546,7 +508,6 @@ private function can_lazyload_iframes() { * Filters the lazyload application on iframes * * @since 2.0 - * @author Remy Perona * * @param bool $do_rocket_lazyload_iframes True to apply lazyload, false otherwise. */ @@ -554,14 +515,20 @@ private function can_lazyload_iframes() { } /** - * Remove noscript tags from the HTML to parse + * Checks if native lazyload is enabled for images * - * @since 3.3 + * @since 3.10.2 * - * @param string $html HTML content. - * @return string + * @return bool */ - private function ignore_noscripts( $html ) { - return preg_replace( '#<noscript>(?:.+)</noscript>#Umsi', '', $html ); + private function is_native_images(): bool { + /** + * Filters the use of native lazyload for images + * + * @since 3.10.2 + * + * @param bool $use_native True to use native lazyload for images, false otherwise. + */ + return (bool) apply_filters( 'rocket_use_native_lazyload_images', false ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Media/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Media/ServiceProvider.php index 922fab433..306d9295e 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Media/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Media/ServiceProvider.php @@ -1,31 +1,38 @@ <?php namespace WP_Rocket\Engine\Media; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Buffer\Config; +use WP_Rocket\Buffer\Tests; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\RocketLazyload\{Assets, Iframe, Image}; +use WP_Rocket\Engine\Media\Emojis\EmojisSubscriber; +use WP_Rocket\Engine\Media\ImageDimensions\{ + AdminSubscriber as ImageDimensionsAdminSubscriber, + ImageDimensions, + Subscriber as ImageDimensionsSubscriber +}; +use WP_Rocket\Engine\Media\Lazyload\{ + AdminSubscriber as LazyloadAdminSubscriber, + Subscriber +}; /** * Service provider for Media module - * - * @since 3.6 */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ protected $provides = [ + 'config', + 'tests', 'lazyload_assets', 'lazyload_image', 'lazyload_iframe', 'lazyload_subscriber', 'lazyload_admin_subscriber', - 'embeds_subscriber', 'emojis_subscriber', 'image_dimensions', 'image_dimensions_subscriber', @@ -33,33 +40,51 @@ class ServiceProvider extends AbstractServiceProvider { ]; /** - * Registers the services in the container + * Check if the service provider provides a specific service. * - * @since 3.6 + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { + public function register(): void { $options = $this->getContainer()->get( 'options' ); - $this->getContainer()->add( 'lazyload_assets', 'WP_Rocket\Dependencies\RocketLazyload\Assets' ); - $this->getContainer()->add( 'lazyload_image', 'WP_Rocket\Dependencies\RocketLazyload\Image' ); - $this->getContainer()->add( 'lazyload_iframe', 'WP_Rocket\Dependencies\RocketLazyload\Iframe' ); - $this->getContainer()->share( 'lazyload_subscriber', 'WP_Rocket\Engine\Media\Lazyload\Subscriber' ) - ->withArgument( $options ) - ->withArgument( $this->getContainer()->get( 'lazyload_assets' ) ) - ->withArgument( $this->getContainer()->get( 'lazyload_image' ) ) - ->withArgument( $this->getContainer()->get( 'lazyload_iframe' ) ); - $this->getContainer()->share( 'lazyload_admin_subscriber', 'WP_Rocket\Engine\Media\Lazyload\AdminSubscriber' ); - $this->getContainer()->share( 'embeds_subscriber', 'WP_Rocket\Engine\Media\Embeds\EmbedsSubscriber' ) - ->withArgument( $options ); - $this->getContainer()->share( 'emojis_subscriber', 'WP_Rocket\Engine\Media\Emojis\EmojisSubscriber' ) - ->withArgument( $options ); - $this->getContainer()->add( 'image_dimensions', 'WP_Rocket\Engine\Media\ImageDimensions\ImageDimensions' ) - ->withArgument( $options ); - $this->getContainer()->share( 'image_dimensions_subscriber', 'WP_Rocket\Engine\Media\ImageDimensions\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'image_dimensions' ) ); - $this->getContainer()->share( 'image_dimensions_admin_subscriber', 'WP_Rocket\Engine\Media\ImageDimensions\AdminSubscriber' ) - ->withArgument( $this->getContainer()->get( 'image_dimensions' ) ); + $this->getContainer()->add( 'config', Config::class ) + ->addArgument( [ 'config_dir_path' => rocket_get_constant( 'WP_ROCKET_CONFIG_PATH' ) ] ); + $this->getContainer()->add( 'tests', Tests::class ) + ->addArgument( $this->getContainer()->get( 'config' ) ); + + $this->getContainer()->add( 'lazyload_assets', Assets::class ); + $this->getContainer()->add( 'lazyload_image', Image::class ); + $this->getContainer()->add( 'lazyload_iframe', Iframe::class ); + $this->getContainer()->addShared( 'lazyload_subscriber', Subscriber::class ) + ->addArgument( $options ) + ->addArgument( $this->getContainer()->get( 'lazyload_assets' ) ) + ->addArgument( $this->getContainer()->get( 'lazyload_image' ) ) + ->addArgument( $this->getContainer()->get( 'lazyload_iframe' ) ) + ->addTag( 'lazyload_subscriber' ); + $this->getContainer()->addShared( 'lazyload_admin_subscriber', LazyloadAdminSubscriber::class ) + ->addTag( 'admin_subscriber' ); + $this->getContainer()->addShared( 'emojis_subscriber', EmojisSubscriber::class ) + ->addArgument( $options ) + ->addTag( 'front_subscriber' ); + $this->getContainer()->add( 'image_dimensions', ImageDimensions::class ) + ->addArgument( $options ); + $this->getContainer()->addShared( 'image_dimensions_subscriber', ImageDimensionsSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'image_dimensions' ) ) + ->addArgument( $this->getContainer()->get( 'tests' ) ) + ->addTag( 'front_subscriber' ); + $this->getContainer()->addShared( 'image_dimensions_admin_subscriber', ImageDimensionsAdminSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'image_dimensions' ) ) + ->addTag( 'admin_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AbstractOptimization.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AbstractOptimization.php index d20d6c6ec..0975108c9 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AbstractOptimization.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AbstractOptimization.php @@ -10,6 +10,7 @@ * @author Remy Perona */ abstract class AbstractOptimization { + use RegexTrait; /** * Plugin options. @@ -93,7 +94,7 @@ protected function is_external_file( $url ) { $wp_content = wp_parse_url( content_url() ); - if ( empty( $wp_content['host'] ) || empty( $wp_content['path'] ) ) { + if ( empty( $wp_content['path'] ) ) { return true; } @@ -106,9 +107,13 @@ protected function is_external_file( $url ) { * @param array $hosts Allowed hosts. * @param array $zones Zones to check available hosts. */ - $hosts = (array) apply_filters( 'rocket_cdn_hosts', [], $this->get_zones() ); - $hosts[] = $wp_content['host']; - $langs = get_rocket_i18n_uri(); + $hosts = (array) apply_filters( 'rocket_cdn_hosts', [], $this->get_zones() ); + + if ( ! empty( $wp_content['host'] ) ) { + $hosts[] = $wp_content['host']; + } + + $langs = get_rocket_i18n_uri(); // Get host for all langs. foreach ( $langs as $lang ) { @@ -126,11 +131,11 @@ protected function is_external_file( $url ) { if ( empty( $hosts ) ) { return true; } - // URL has domain and domain is part of the internal domains. if ( ! empty( $file['host'] ) ) { foreach ( $hosts as $host ) { - if ( false !== strpos( $url, $host ) ) { + $check_url = strtok( $url, '?' ); + if ( false !== strpos( $check_url, $host ) ) { return false; } } @@ -138,6 +143,10 @@ protected function is_external_file( $url ) { return true; } + if ( empty( $file['host'] ) ) { + return false; + } + // URL has no domain and doesn't contain the WP_CONTENT path or wp-includes. return ! preg_match( '#(' . $wp_content['path'] . '|wp-includes)#', $file['path'] ); } @@ -214,4 +223,29 @@ protected function hide_comments( $html ) { return $html; } + + /** + * Get full minified url with ?ver query string. + * + * @param string $minified_path Path of minified file. + * @param string $minified_url Url of minified file. + * + * @return string + */ + protected function get_full_minified_url( $minified_path, $minified_url ) { + $file_mtime = rocket_direct_filesystem()->mtime( $minified_path ); + + $version = $file_mtime ? $file_mtime : md5( $minified_url . $this->minify_key ); + + return add_query_arg( 'ver', $version, $minified_url ); + } + + /** + * Gets the CDN zones. + * + * @since 3.1 + * + * @return array + */ + abstract public function get_zones(); } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AdminServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AdminServiceProvider.php index 171320da9..7217bd8c9 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AdminServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AdminServiceProvider.php @@ -1,21 +1,14 @@ <?php namespace WP_Rocket\Engine\Optimization; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; /** * Service provider for the WP Rocket optimizations - * - * @since 3.5.3 */ class AdminServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -23,22 +16,37 @@ class AdminServiceProvider extends AbstractServiceProvider { 'minify_css_admin_subscriber', 'google_fonts_settings', 'google_fonts_admin_subscriber', + 'minify_admin_subscriber', ]; /** - * Registers the option array in the container + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. * - * @since 3.5.3 + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { - $this->getContainer()->share( 'minify_css_admin_subscriber', 'WP_Rocket\Engine\Optimization\Minify\CSS\AdminSubscriber' ); + public function register(): void { + $this->getContainer()->addShared( 'minify_css_admin_subscriber', 'WP_Rocket\Engine\Optimization\Minify\CSS\AdminSubscriber' ) + ->addTag( 'admin_subscriber' ); $this->getContainer()->add( 'google_fonts_settings', 'WP_Rocket\Engine\Optimization\GoogleFonts\Admin\Settings' ) - ->withArgument( $this->getContainer()->get( 'options' ) ) - ->withArgument( $this->getContainer()->get( 'beacon' ) ) - ->withArgument( $this->getContainer()->get( 'template_path' ) ); - $this->getContainer()->share( 'google_fonts_admin_subscriber', 'WP_Rocket\Engine\Optimization\GoogleFonts\Admin\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'google_fonts_settings' ) ); + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'beacon' ) ) + ->addArgument( $this->getContainer()->get( 'template_path' ) ); + $this->getContainer()->addShared( 'google_fonts_admin_subscriber', 'WP_Rocket\Engine\Optimization\GoogleFonts\Admin\Subscriber' ) + ->addArgument( $this->getContainer()->get( 'google_fonts_settings' ) ) + ->addTag( 'admin_subscriber' ); + $this->getContainer()->addShared( 'minify_admin_subscriber', 'WP_Rocket\Engine\Optimization\Minify\AdminSubscriber' ) + ->addTag( 'admin_subscriber' ) + ->addArgument( $this->getContainer()->get( 'options' ) ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AssetsLocalCache.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AssetsLocalCache.php index b845bf88a..7cc170131 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AssetsLocalCache.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/AssetsLocalCache.php @@ -183,6 +183,5 @@ public function validate_integrity( $asset_matched ) { } return str_replace( $integrity_matches[0], '', $asset_matched[0] ); - } } diff --git a/wp-content/plugins/wp-rocket/inc/classes/Buffer/class-optimization.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Buffer/Optimization.php similarity index 76% rename from wp-content/plugins/wp-rocket/inc/classes/Buffer/class-optimization.php rename to wp-content/plugins/wp-rocket/inc/Engine/Optimization/Buffer/Optimization.php index 35dba2391..4eb9bf914 100644 --- a/wp-content/plugins/wp-rocket/inc/classes/Buffer/class-optimization.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Buffer/Optimization.php @@ -1,11 +1,15 @@ <?php -namespace WP_Rocket\Buffer; +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\Buffer; + +use WP_Rocket\Buffer\Abstract_Buffer; +use WP_Rocket\Buffer\Tests; /** * Handle page optimizations. * - * @since 3.3 - * @author Grégory Viguier + * @since 3.3 */ class Optimization extends Abstract_Buffer { @@ -14,8 +18,6 @@ class Optimization extends Abstract_Buffer { * * @var string * @since 3.3 - * @access protected - * @author Grégory Viguier */ protected $process_id = 'optimization process'; @@ -30,8 +32,6 @@ class Optimization extends Abstract_Buffer { * Constructor. * * @since 3.3 - * @access public - * @author Grégory Viguier * * @param Tests $tests Tests instance. */ @@ -49,8 +49,6 @@ public function __construct( Tests $tests ) { * Do preliminary tests and maybe launch the buffer process. * * @since 3.3 - * @access public - * @author Grégory Viguier */ public function maybe_init_process() { if ( ! $this->tests->can_init_process() ) { @@ -65,8 +63,6 @@ public function maybe_init_process() { * Maybe optimize the page content. * * @since 3.3 - * @access public - * @author Grégory Viguier * * @param string $buffer The buffer content. * @return string The buffered content. @@ -82,7 +78,7 @@ public function maybe_process_buffer( $buffer ) { */ do_action( 'rocket_before_maybe_process_buffer', $buffer ); - if ( ! $this->is_html( $buffer ) ) { + if ( ! $this->is_feed_uri() && ! $this->is_html( $buffer ) ) { return $buffer; } @@ -105,6 +101,24 @@ public function maybe_process_buffer( $buffer ) { $this->log( 'Page optimized.', [], 'info' ); + /** + * Fires after processing the buffer + * + * @since 3.12 + */ + do_action( 'rocket_after_process_buffer' ); + return $buffer; } + + /** + * Tell if the current url is a feed. + * + * @return bool + */ + public function is_feed_uri() { + global $wp_rewrite, $wp; + $feed_uri = '/(?:.+/)?' . $wp_rewrite->feed_base . '(?:/(?:.+/?)?)?$'; + return (bool) preg_match( '#^(' . $feed_uri . ')$#i', '/' . $wp->request ); + } } diff --git a/wp-content/plugins/wp-rocket/inc/classes/subscriber/Optimization/class-buffer-subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Buffer/Subscriber.php similarity index 75% rename from wp-content/plugins/wp-rocket/inc/classes/subscriber/Optimization/class-buffer-subscriber.php rename to wp-content/plugins/wp-rocket/inc/Engine/Optimization/Buffer/Subscriber.php index 2dbddcf7a..ae32bb989 100644 --- a/wp-content/plugins/wp-rocket/inc/classes/subscriber/Optimization/class-buffer-subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Buffer/Subscriber.php @@ -1,16 +1,16 @@ <?php -namespace WP_Rocket\Subscriber\Optimization; +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\Buffer; -use WP_Rocket\Buffer\Optimization; use WP_Rocket\Event_Management\Subscriber_Interface; /** * Event subscriber to buffer and process a page content. * - * @since 3.3 - * @author Grégory Viguier + * @since 3.3 */ -class Buffer_Subscriber implements Subscriber_Interface { +class Subscriber implements Subscriber_Interface { /** * Optimization instance * @@ -39,9 +39,7 @@ public static function get_subscribed_events() { /** * Start buffering the page content and apply optimizations if we can. * - * @since 3.3 - * @access public - * @author Grégory Viguier + * @since 3.3 */ public function start_content_process() { return $this->optimizer->maybe_init_process(); diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/CSSTrait.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/CSSTrait.php index 321e70b8a..58bbbf464 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/CSSTrait.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/CSSTrait.php @@ -1,4 +1,5 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\Optimization; @@ -6,6 +7,21 @@ use WP_Rocket\Dependencies\PathConverter\Converter; trait CSSTrait { + + /** + * Currently imported files. + * + * @var array + */ + private $imports = []; + + /** + * Found charset on CSS. + * + * @var null|string + */ + private $found_charset = null; + /** * Rewrites the paths inside the CSS file content * @@ -35,6 +51,12 @@ public function rewrite_paths( $source, $target, $content ) { */ $target = apply_filters( 'rocket_css_asset_target_path', $target ); + $content = $this->move( $this->get_converter( $source, $target ), $content, $source ); + + $this->set_cached_import( $source ); + + $content = $this->combine_imports( $content, $target ); + /** * Filters the content of a CSS file * @@ -44,7 +66,7 @@ public function rewrite_paths( $source, $target, $content ) { * @param string $source Source filepath. * @param string $target Target filepath. */ - return apply_filters( 'rocket_css_content', $this->move( $this->get_converter( $source, $target ), $content, $source ), $source, $target ); + return apply_filters( 'rocket_css_content', $content, $source, $target ); } /** @@ -148,6 +170,11 @@ protected function move( ConverterInterface $converter, $content, $source ) { $type = ( strpos( $match[0], '@import' ) === 0 ? 'import' : 'url' ); $url = $match['path']; + + if ( preg_match( '/^#/', $url ) ) { + continue; + } + if ( ! preg_match( '/^(data:|https?:|\\/)/', $url ) ) { // attempting to interpret GET-params makes no sense, so let's discard them for awhile. $params = strrchr( $url, '?' ); @@ -191,6 +218,150 @@ protected function move( ConverterInterface $converter, $content, $source ) { return str_replace( $search, $replace, $content ); } + /** + * Replace local imports with their contents recursively. + * + * @since 3.8.6 + * + * @param string $content CSS Content. + * @param string $target Target CSS file path. + * + * @return string + */ + protected function combine_imports( $content, $target ) { + $import_regexes = [ + // @import url(xxx) + '/ + # import statement + @import + + # whitespace + \s+ + + # open url() + url\( + + # (optional) open path enclosure + (?P<quotes>["\']?) + + # fetch path + (?P<path>.+?) + + # (optional) close path enclosure + (?P=quotes) + + # close url() + \) + + # (optional) trailing whitespace + \s* + + # (optional) media statement(s) + (?P<media>[^;]*) + + # (optional) trailing whitespace + \s* + + # (optional) closing semi-colon + ;? + + /ix', + + // @import 'xxx' + '/ + + # import statement + @import + + # whitespace + \s+ + + # open path enclosure + (?P<quotes>["\']) + + # fetch path + (?P<path>.+?) + + # close path enclosure + (?P=quotes) + + # (optional) trailing whitespace + \s* + + # (optional) media statement(s) + (?P<media>[^;]*) + + # (optional) trailing whitespace + \s* + + # (optional) closing semi-colon + ;? + + /ix', + ]; + + // find all relative imports in css. + $matches = []; + foreach ( $import_regexes as $import_regexe ) { + if ( preg_match_all( $import_regexe, $content, $regex_matches, PREG_SET_ORDER ) ) { + $matches = array_merge( $matches, $regex_matches ); + } + } + + if ( empty( $matches ) ) { + return $content; + } + + $search = []; + $replace = []; + + // loop the matches. + foreach ( $matches as $match ) { + /** + * Filter Skip import replacement for one file. + * + * @since 3.8.6 + * + * @param bool $skip_import Skipped or not (Default not skipped). + * @param string $file_path Matched import path. + * @param array $import_match Full import match. + */ + if ( apply_filters( 'rocket_skip_import_replacement', false, $match['path'], $match ) ) { + continue; + } + + list( $import_path, $import_content ) = $this->get_internal_file_contents( $match['path'], dirname( $target ) ); + + if ( empty( $import_content ) ) { + continue; + } + + if ( $this->check_cached_import( $import_path ) ) { + $search[] = $match[0]; + $replace[] = ''; + + continue; + } + + $this->set_cached_import( $import_path ); + + // check if this is only valid for certain media. + if ( ! empty( $match['media'] ) ) { + $import_content = '@media ' . $match['media'] . '{' . $import_content . '}'; + } + + // Use recursion to rewrite paths and combine imports again for imported content. + $import_content = $this->rewrite_paths( $import_path, $target, $import_content ); + + // add to replacement array. + $search[] = $match[0]; + $replace[] = $import_content; + } + + // replace the import statements. + return str_replace( $search, $replace, $content ); + } + /** * Applies font-display:swap to all font-family rules without a previously set font-display property. * @@ -204,17 +375,219 @@ private function apply_font_display_swap( $css_file_content ) { $css_file_content = (string) $css_file_content; return preg_replace_callback( - '/(?:@font-face)\s*{(?<value>[^}]+)}/', + '/(?:@font-face)\s*{(?<value>[^}]+)}/i', function ( $matches ) { - if ( false !== strpos( $matches['value'], 'font-display' ) ) { - return $matches[0]; - } + if ( preg_match( '/font-display:\s*(?<swap_value>\w*);?/i', $matches['value'], $attribute ) ) { + if ( 'swap' === strtolower( $attribute['swap_value'] ) ) { + return $matches[0]; + } - $swap = "font-display:swap;{$matches['value']}"; + $swap = str_replace( $attribute['swap_value'], 'swap', $attribute[0] ); - return str_replace( $matches['value'], $swap, $matches[0] ); + return preg_replace( '/font-display:\s*(?<swap_value>\w*);?/i', $swap, $matches[0] ); + } + + return str_replace( $matches['value'], "font-display:swap;{$matches['value']}", $matches[0] ); }, $css_file_content ); } + + /** + * Get internal file full path and contents. + * + * @since 3.8.6 + * + * @param string $file Internal file path (maybe external url or relative path). + * @param string $base_path Base path as reference for relative paths. + * + * @return array Array of two values ( full path, contents ) + */ + private function get_internal_file_contents( $file, $base_path ) { + if ( $this->is_external_path( $file ) && wp_http_validate_url( $file ) ) { + return [ $file, false ]; + } + + // Remove query strings. + $file = str_replace( '?' . wp_parse_url( $file, PHP_URL_QUERY ), '', $file ); + + // Check if this file is readable or it's relative path so we add base_path at it's start. + if ( ! rocket_direct_filesystem()->is_readable( $this->get_local_path( $file ) ) ) { + $ds = rocket_get_constant( 'DIRECTORY_SEPARATOR' ); + $file = $base_path . $ds . str_replace( '/', $ds, $file ); + }else { + $file = $this->get_local_path( $file ); + } + + $file_type = wp_check_filetype( $file, [ 'css' => 'text/css' ] ); + + if ( 'css' !== $file_type['ext'] ) { + return [ $file, null ]; + } + + $import_content = rocket_direct_filesystem()->get_contents( $file ); + + return [ $file, $import_content ]; + } + + /** + * Determines if the file is external. + * + * @since 3.8.6 + * + * @param string $url URL of the file. + * @return bool True if external, false otherwise. + */ + protected function is_external_path( $url ) { + $file = get_rocket_parse_url( $url ); + + if ( empty( $file['path'] ) ) { + return true; + } + + $parsed_site_url = wp_parse_url( site_url() ); + + if ( empty( $parsed_site_url['host'] ) ) { + return true; + } + + // This filter is documented in inc/Engine/Admin/Settings/Settings.php. + $hosts = (array) apply_filters( 'rocket_cdn_hosts', [], [ 'all' ] ); + $hosts[] = $parsed_site_url['host']; + $langs = get_rocket_i18n_uri(); + + // Get host for all langs. + foreach ( $langs as $lang ) { + $url_host = wp_parse_url( $lang, PHP_URL_HOST ); + + if ( ! isset( $url_host ) ) { + continue; + } + + $hosts[] = $url_host; + } + + $hosts = array_unique( $hosts ); + + if ( empty( $hosts ) ) { + return true; + } + + // URL has domain and domain is part of the internal domains. + if ( ! empty( $file['host'] ) ) { + foreach ( $hosts as $host ) { + if ( false !== strpos( $url, $host ) ) { + return false; + } + } + + return true; + } + + return false; + } + + /** + * Get local absolute path for image. + * + * @since 3.8.6 + * + * @param string $url Image url. + * + * @return string Image absolute local path. + */ + private function get_local_path( $url ) { + $url = $this->normalize_url( $url ); + + $path = rocket_url_to_path( $url ); + if ( $path ) { + return $path; + } + + $relative_url = ltrim( wp_make_link_relative( $url ), '/' ); + $ds = rocket_get_constant( 'DIRECTORY_SEPARATOR' ); + $base_path = isset( $_SERVER['DOCUMENT_ROOT'] ) ? ( sanitize_text_field( wp_unslash( $_SERVER['DOCUMENT_ROOT'] ) ) . $ds ) : ''; + + return $base_path . str_replace( '/', $ds, $relative_url ); + } + + /** + * Normalize relative url to full url. + * + * @since 3.8.6 + * + * @param string $url Url to be normalized. + * + * @return string Normalized url. + */ + private function normalize_url( $url ) { + $url_host = wp_parse_url( $url, PHP_URL_HOST ); + + if ( ! empty( $url_host ) ) { + return $url; + } + + $relative_url = ltrim( wp_make_link_relative( $url ), '/' ); + $site_url_components = wp_parse_url( site_url( '/' ) ); + + return $site_url_components['scheme'] . '://' . $site_url_components['host'] . '/' . $relative_url; + } + + /** + * Set cached import locally not to imported again. + * + * @param string $path Path to be cached. + */ + private function set_cached_import( string $path ) { + $real_path = rocket_realpath( $path ); + $this->imports[ md5( $real_path ) ] = $real_path; + } + + /** + * Check if path imported before. + * + * @param string $path Path to be checked. + * + * @return bool + */ + private function check_cached_import( string $path ): bool { + return isset( $this->imports[ md5( rocket_realpath( $path ) ) ] ); + } + + /** + * Move charset to top of CSS file OR remove all charsets for internal CSS. + * + * @param string $content CSS content. + * @param bool $keep_first_charset Keep first charset if true, otherwise remove all charsets. + * + * @return string + */ + public function handle_charsets( string $content, bool $keep_first_charset = true ): string { + $new_content = preg_replace_callback( '/@charset\s+["|\'](.*?)["|\'];?/i', [ $this, 'match_charsets' ], $content ); + + if ( ! $keep_first_charset ) { + return $new_content; + } + + if ( is_null( $this->found_charset ) ) { + return $content; + } + + return "@charset \"{$this->found_charset}\";" . $new_content; + } + + /** + * Match each charset on the CSS file. + * + * @param array $match Match array. + * + * @return string + */ + private function match_charsets( array $match ): string { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.matchFound + if ( is_null( $this->found_charset ) ) { + $this->found_charset = $match[1]; + } + + return ''; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/CacheDynamicResource.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/CacheDynamicResource.php index fdcbddbaa..f9ad20cd7 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/CacheDynamicResource.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/CacheDynamicResource.php @@ -153,7 +153,7 @@ public function replace_url( $src ) { * * @param string $filename filename for the cache file */ - $filename = apply_filters( 'rocket_dynamic_resource_cache_filename', preg_replace( '/\.php$/', '-' . $this->minify_key . '.' . $this->extension, $path ) ); + $filename = apply_filters( 'rocket_dynamic_resource_cache_filename', preg_replace( '/\.php$/', '.' . $this->extension, $path ) ); $filename = ltrim( rocket_realpath( rtrim( str_replace( [ ' ', '%20' ], '-', $filename ) ) ), '/' ); $filepath = $this->busting_path . $filename; diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/ContentTrait.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/ContentTrait.php new file mode 100644 index 000000000..94bc1c0eb --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/ContentTrait.php @@ -0,0 +1,124 @@ +<?php + +namespace WP_Rocket\Engine\Optimization; + +trait ContentTrait { + /** + * Gets all public post types. + * + * @since 3.9 moved into trait + * @since 2.11 + */ + private function get_public_post_types() { + global $wpdb; + + $post_types = get_post_types( + [ + 'public' => true, + 'publicly_queryable' => true, + ] + ); + + $post_types[] = 'page'; + + /** + * Filters the post types excluded from critical CSS generation. + * + * @since 2.11 + * + * @param array $excluded_post_types An array of post types names. + * + * @return array + */ + $excluded_post_types = (array) apply_filters( + 'rocket_cpcss_excluded_post_types', + [ + 'elementor_library', + 'oceanwp_library', + 'tbuilder_layout', + 'tbuilder_layout_part', + 'slider', + 'karma-slider', + 'tt-gallery', + 'xlwcty_thankyou', + 'fusion_template', + 'blocks', + 'jet-woo-builder', + 'fl-builder-template', + 'cms_block', + 'web-story', + ] + ); + + $post_types = array_diff( $post_types, $excluded_post_types ); + $post_types = esc_sql( $post_types ); + $post_types = "'" . implode( "','", $post_types ) . "'"; + + return $wpdb->get_results( + "SELECT MAX(ID) as ID, post_type + FROM ( + SELECT ID, post_type + FROM $wpdb->posts + WHERE post_type IN ( $post_types ) + AND post_status = 'publish' + ORDER BY post_date DESC + ) AS posts + GROUP BY post_type" + ); + } + + /** + * Gets all public taxonomies. + * + * @since 3.9 moved into trait + * @since 2.11 + */ + private function get_public_taxonomies() { + global $wpdb; + + $taxonomies = get_taxonomies( + [ + 'public' => true, + 'publicly_queryable' => true, + ] + ); + + /** + * Filters the taxonomies excluded from critical CSS generation. + * + * @since 2.11 + * + * @param array $excluded_taxonomies An array of taxonomies names. + * + * @return array + */ + $excluded_taxonomies = (array) apply_filters( + 'rocket_cpcss_excluded_taxonomies', + [ + 'post_format', + 'product_shipping_class', + 'karma-slider-category', + 'truethemes-gallery-category', + 'coupon_campaign', + 'element_category', + 'mediamatic_wpfolder', + 'attachment_category', + ] + ); + + $taxonomies = array_diff( $taxonomies, $excluded_taxonomies ); + $taxonomies = esc_sql( $taxonomies ); + $taxonomies = "'" . implode( "','", $taxonomies ) . "'"; + + return $wpdb->get_results( + "SELECT MAX( term_id ) AS ID, taxonomy + FROM ( + SELECT term_id, taxonomy + FROM $wpdb->term_taxonomy + WHERE taxonomy IN ( $taxonomies ) + AND count > 0 + ) AS taxonomies + GROUP BY taxonomy" + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/AdminSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/AdminSubscriber.php index 4712e2f81..c93ec492d 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/AdminSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/AdminSubscriber.php @@ -27,10 +27,11 @@ public function __construct( DeferJS $defer_js ) { * * @return array */ - public static function get_subscribed_events() : array { + public static function get_subscribed_events(): array { return [ 'rocket_first_install_options' => 'add_defer_js_option', 'wp_rocket_upgrade' => [ 'exclude_jquery_defer', 14, 2 ], + 'rocket_meta_boxes_fields' => [ 'add_meta_box', 5 ], ]; } @@ -42,7 +43,7 @@ public static function get_subscribed_events() : array { * @param array $options WP Rocket options array. * @return array */ - public function add_defer_js_option( array $options ) : array { + public function add_defer_js_option( array $options ): array { return $this->defer_js->add_option( $options ); } @@ -63,4 +64,17 @@ public function exclude_jquery_defer( $new_version, $old_version ) { $this->defer_js->exclude_jquery_upgrade(); } + + /** + * Add the field to the WP Rocket metabox on the post edit page. + * + * @param string[] $fields Metaboxes fields. + * + * @return string[] + */ + public function add_meta_box( array $fields ) { + $fields['defer_all_js'] = __( 'Load JavaScript deferred', 'rocket' ); + + return $fields; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/DeferJS.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/DeferJS.php index 8544f41d8..cb183b469 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/DeferJS.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/DeferJS.php @@ -4,6 +4,7 @@ namespace WP_Rocket\Engine\Optimization\DeferJS; use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Optimization\DynamicLists\DefaultLists\DataManager; class DeferJS { /** @@ -13,26 +14,22 @@ class DeferJS { */ private $options; - /** - * Array of inline exclusions list. + * DataManager instance * - * @var string[] + * @var DataManager */ - private $inline_exclusions = [ - 'DOMContentLoaded', - 'document.write', - 'window.lazyLoadOptions', - 'N.N2_', - ]; + private $data_manager; /** * Instantiate the class * * @param Options_Data $options Options instance. + * @param DataManager $data_manager DataManager instance. */ - public function __construct( Options_Data $options ) { - $this->options = $options; + public function __construct( Options_Data $options, DataManager $data_manager ) { + $this->options = $options; + $this->data_manager = $data_manager; } /** @@ -43,7 +40,7 @@ public function __construct( Options_Data $options ) { * @param array $options WP Rocket options array. * @return array */ - public function add_option( array $options ) : array { + public function add_option( array $options ): array { $options['exclude_defer_js'] = []; return $options; @@ -57,7 +54,7 @@ public function add_option( array $options ) : array { * @param string $html HTML content. * @return string */ - public function defer_js( string $html ) : string { + public function defer_js( string $html ): string { if ( ! $this->can_defer_js() ) { return $html; } @@ -72,6 +69,10 @@ public function defer_js( string $html ) : string { $exclude_defer_js = implode( '|', $this->get_excluded() ); + if ( ! @preg_replace( '#(' . $exclude_defer_js . ')#i', '', 'dummy-string' ) ) { // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged + return $html; + } + foreach ( $matches as $tag ) { if ( preg_match( '#(' . $exclude_defer_js . ')#i', $tag['url'] ) ) { continue; @@ -96,7 +97,7 @@ public function defer_js( string $html ) : string { * @param string $html HTML content. * @return string */ - public function defer_inline_js( string $html ) : string { + public function defer_inline_js( string $html ): string { if ( ! $this->can_defer_js() ) { return $html; } @@ -124,28 +125,17 @@ public function defer_inline_js( string $html ) : string { */ $jquery_patterns = apply_filters( 'rocket_defer_jquery_patterns', 'jQuery|\$\.\(|\$\(' ); - /** - * Filters the patterns used to find inline JS that should not be deferred - * - * @since 3.8 - * - * @param array $inline_exclusions_list Array of inline JS that should not be deferred. - */ - $inline_exclusions_list = apply_filters( 'rocket_defer_inline_exclusions', $this->inline_exclusions ); - - $inline_exclusions = ''; - if ( ! empty( $inline_exclusions_list ) ) { - foreach ( $inline_exclusions_list as $inline_exclusions_item ) { - $inline_exclusions .= preg_quote( $inline_exclusions_item, '#' ) . '|'; - } - $inline_exclusions = rtrim( $inline_exclusions, '|' ); - } + $inline_exclusions = $this->get_inline_exclusions_list_pattern(); foreach ( $matches as $inline_js ) { if ( empty( $inline_js['content'] ) ) { continue; } + if ( preg_match( '/(application\/ld\+json)/i', $inline_js[0] ) ) { + continue; + } + if ( empty( $inline_exclusions ) || preg_match( "/({$inline_exclusions})/msi", $inline_js['content'] ) ) { continue; } @@ -169,7 +159,7 @@ public function defer_inline_js( string $html ) : string { * @param string $content Inline JS content. * @return string */ - private function inline_js_wrapper( string $content ) : string { + private function inline_js_wrapper( string $content ): string { return "window.addEventListener('DOMContentLoaded', function() {" . $content . '});'; } @@ -180,7 +170,7 @@ private function inline_js_wrapper( string $content ) : string { * * @return boolean */ - private function can_defer_js() : bool { + private function can_defer_js(): bool { if ( rocket_get_constant( 'DONOTROCKETOPTIMIZE' ) ) { return false; } @@ -199,28 +189,12 @@ private function can_defer_js() : bool { * * @return array */ - public function get_excluded() : array { - $exclude_defer_js = [ - 'gist.github.com', - 'content.jwplatform.com', - 'js.hsforms.net', - 'www.uplaunch.com', - 'google.com/recaptcha', - 'widget.reviews.co.uk', - 'verify.authorize.net/anetseal', - 'lib/admin/assets/lib/webfont/webfont.min.js', - 'app.mailerlite.com', - 'widget.reviews.io', - 'simplybook.(.*)/v2/widget/widget.js', - '/wp-includes/js/dist/i18n.min.js', - '/wp-content/plugins/wpfront-notification-bar/js/wpfront-notification-bar(.*).js', - '/wp-content/plugins/oxygen/component-framework/vendor/aos/aos.js', - 'static.mailerlite.com/data/(.*).js', - 'cdn.voxpow.com/static/libs/v1/(.*).js', - 'cdn.voxpow.com/media/trackers/js/(.*).js', - ]; - - $exclude_defer_js = array_unique( array_merge( $exclude_defer_js, $this->options->get( 'exclude_defer_js', [] ) ) ); + public function get_excluded(): array { + if ( ! $this->can_defer_js() ) { + return []; + } + + $exclude_defer_js = array_unique( array_merge( $this->get_external_exclusions(), $this->options->get( 'exclude_defer_js', [] ) ) ); /** * Filter list of Deferred JavaScript files @@ -246,7 +220,7 @@ public function get_excluded() : array { * @param array $excluded_files Array of excluded files from combine JS. * @return array */ - public function exclude_jquery_combine( array $excluded_files ) : array { + public function exclude_jquery_combine( array $excluded_files ): array { if ( ! $this->can_defer_js() ) { return $excluded_files; } @@ -282,4 +256,60 @@ public function exclude_jquery_upgrade() { update_option( 'wp_rocket_settings', $options ); } + + /** + * Get exclusion list pattern. + * + * @return string + */ + private function get_inline_exclusions_list_pattern() { + $inline_exclusions_list = $this->get_inline_exclusions(); + + /** + * Filters the patterns used to find inline JS that should not be deferred + * + * @since 3.8 + * + * @param array $inline_exclusions_list Array of inline JS that should not be deferred. + */ + $additional_inline_exclusions_list = apply_filters( 'rocket_defer_inline_exclusions', [] ); + + $inline_exclusions = ''; + + // Check if filter return is string so convert it to array for backward compatibility. + if ( is_string( $additional_inline_exclusions_list ) ) { + $additional_inline_exclusions_list = explode( '|', $additional_inline_exclusions_list ); + } + + // Cast filter return to array. + $inline_exclusions_list = array_merge( $inline_exclusions_list, (array) $additional_inline_exclusions_list ); + + foreach ( $inline_exclusions_list as $inline_exclusions_item ) { + $inline_exclusions .= preg_quote( (string) $inline_exclusions_item, '#' ) . '|'; + } + + return rtrim( $inline_exclusions, '|' ); + } + + /** + * Get inline exclusions list + * + * @return array + */ + private function get_inline_exclusions(): array { + $lists = $this->data_manager->get_lists(); + + return isset( $lists->defer_js_inline_exclusions ) ? $lists->defer_js_inline_exclusions : []; + } + + /** + * Get external exclusions list + * + * @return array + */ + private function get_external_exclusions(): array { + $lists = $this->data_manager->get_lists(); + + return isset( $lists->defer_js_external_exclusions ) ? $lists->defer_js_external_exclusions : []; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/ServiceProvider.php index 9954530cd..ed3f102b9 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/ServiceProvider.php @@ -1,21 +1,14 @@ <?php namespace WP_Rocket\Engine\Optimization\DeferJS; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; /** * Service provider for the WP Rocket Defer JS - * - * @since 3.8 */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ @@ -26,16 +19,30 @@ class ServiceProvider extends AbstractServiceProvider { ]; /** - * Registers the option array in the container + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { - $this->getContainer()->add( 'defer_js', 'WP_Rocket\Engine\Optimization\DeferJS\DeferJS' ) - ->withArgument( $this->getContainer()->get( 'options' ) ); - $this->getContainer()->share( 'defer_js_admin_subscriber', 'WP_Rocket\Engine\Optimization\DeferJS\AdminSubscriber' ) - ->withArgument( $this->getContainer()->get( 'defer_js' ) ); - $this->getContainer()->share( 'defer_js_subscriber', 'WP_Rocket\Engine\Optimization\DeferJS\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'defer_js' ) ); + public function register(): void { + $this->getContainer()->add( 'defer_js', DeferJS::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'dynamic_lists_defaultlists_data_manager' ) ); + $this->getContainer()->addShared( 'defer_js_admin_subscriber', AdminSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'defer_js' ) ) + ->addTag( 'admin_subscriber' ); + $this->getContainer()->addShared( 'defer_js_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'defer_js' ) ) + ->addTag( 'front_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/Subscriber.php index 00bd87240..ab84f79ac 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DeferJS/Subscriber.php @@ -27,7 +27,7 @@ public function __construct( DeferJS $defer_js ) { * * @return array */ - public static function get_subscribed_events() : array { + public static function get_subscribed_events(): array { return [ 'rocket_buffer' => [ [ 'defer_js', 24 ], @@ -46,7 +46,7 @@ public static function get_subscribed_events() : array { * @param string $html HTML content. * @return string */ - public function defer_js( string $html ) : string { + public function defer_js( string $html ): string { return $this->defer_js->defer_js( $html ); } @@ -58,7 +58,7 @@ public function defer_js( string $html ) : string { * @param string $html HTML content. * @return string */ - public function defer_inline_js( string $html ) : string { + public function defer_inline_js( string $html ): string { return $this->defer_js->defer_inline_js( $html ); } @@ -70,7 +70,7 @@ public function defer_inline_js( string $html ) : string { * @param array $excluded_files Array of excluded files from combine JS. * @return array */ - public function exclude_jquery_combine( array $excluded_files ) : array { + public function exclude_jquery_combine( array $excluded_files ): array { return $this->defer_js->exclude_jquery_combine( $excluded_files ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/Settings.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/Settings.php index ff15a0e8f..eff89530d 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/Settings.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/Settings.php @@ -1,118 +1,52 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\Optimization\DelayJS\Admin; -use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Admin\Options; +use WP_Rocket\Engine\Admin\Settings\Settings as AdminSettings; class Settings { - /** - * Array of defaults scripts to delay - * - * @var array - */ - private $defaults = [ - 'getbutton.io', - '//a.omappapi.com/app/js/api.min.js', - 'feedbackcompany.com/includes/widgets/feedback-company-widget.min.js', - 'snap.licdn.com/li.lms-analytics/insight.min.js', - 'static.ads-twitter.com/uwt.js', - 'platform.twitter.com/widgets.js', - 'twq(', - '/sdk.js#xfbml', - 'static.leadpages.net/leadbars/current/embed.js', - 'translate.google.com/translate_a/element.js', - 'widget.manychat.com', - 'xfbml.customerchat.js', - 'static.hotjar.com/c/hotjar-', - 'smartsuppchat.com/loader.js', - 'grecaptcha.execute', - 'Tawk_API', - 'shareaholic', - 'sharethis', - 'simple-share-buttons-adder', - 'addtoany', - 'font-awesome', - 'wpdiscuz', - 'cookie-law-info', - 'pinit.js', - '/gtag/js', - 'gtag(', - '/gtm.js', - '/gtm-', - 'fbevents.js', - 'fbq(', - 'google-analytics.com/analytics.js', - 'ga( \'', - 'ga(\'', - 'adsbygoogle.js', - 'ShopifyBuy', - 'widget.trustpilot.com/bootstrap', - 'ft.sdk.min.js', - 'apps.elfsight.com/p/platform.js', - 'livechatinc.com/tracking.js', - 'LiveChatWidget', - '/busting/facebook-tracking/', - 'olark', - 'pixel-caffeine/build/frontend.js', - ]; /** - * Instance of options handler. + * Options instance. * - * @var Options_Data + * @var Options */ - private $options; + protected $options_api; /** - * Creates an instance of the class. + * Constructor. * - * @param Options_Data $options WP Rocket Options instance. + * @param Options $options_api Options instance. */ - public function __construct( Options_Data $options ) { - $this->options = $options; + public function __construct( Options $options_api ) { + $this->options_api = $options_api; } /** * Add the delay JS options to the WP Rocket options array * + * @since 3.9 Removed delay_js_scripts key, added delay_js_exclusions. * @since 3.7 * * @param array $options WP Rocket options array. * * @return array */ - public function add_options( $options ) { + public function add_options( $options ): array { $options = (array) $options; - $options['delay_js'] = 1; - $options['delay_js_scripts'] = $this->defaults; + $options['delay_js'] = 0; + $options['delay_js_exclusions'] = []; return $options; } /** - * Gets the data to populate the view for the restore defaults button - * - * @since 3.7 - * - * @return array - */ - public function get_button_data() { - return [ - 'type' => 'button', - 'action' => 'rocket_delay_js_restore_defaults', - 'attributes' => [ - 'label' => __( 'Restore Defaults', 'rocket' ), - 'attributes' => [ - 'class' => 'wpr-button wpr-button--icon wpr-button--purple wpr-icon-refresh', - ], - ], - ]; - } - - /** - * Sets the delay_js option to zero when updating to 3.7 + * Sets the delay_js_exclusions default value for users with delay JS enabled on upgrade * + * @since 3.9 Sets the delay_js_exclusions default value if delay_js is 1 * @since 3.7 * * @param string $old_version Previous plugin version. @@ -120,134 +54,148 @@ public function get_button_data() { * @return void */ public function set_option_on_update( $old_version ) { - if ( version_compare( $old_version, '3.7', '>' ) ) { + if ( version_compare( $old_version, '3.9', '>=' ) ) { return; } - $options = get_option( 'wp_rocket_settings', [] ); + $options = $this->options_api->get( 'settings', [] ); - $options['delay_js'] = 0; - $options['delay_js_scripts'] = $this->defaults; + $options['delay_js_exclusions'] = []; - update_option( 'wp_rocket_settings', $options ); + if ( + isset( $options['delay_js'] ) + && + 1 === (int) $options['delay_js'] + ) { + $options['minify_concatenate_js'] = 0; + } + + $this->options_api->set( 'settings', $options ); } /** - * Update delay_js options when updating to ver 3.7.4 + * Sanitizes delay JS options when saving the settings * - * @since 3.7.4 + * @since 3.9 * - * @param string $old_version Old plugin version. + * @param array $input Array of values submitted from the form. + * @param AdminSettings $settings Settings class instance. * - * @return void + * @return array */ - public function option_update_3_7_4( $old_version ) { - if ( version_compare( $old_version, '3.7.4', '>' ) ) { - return; - } - - $options = get_option( 'wp_rocket_settings', [] ); - $delay_js_scripts = array_flip( $options['delay_js_scripts'] ); - - if ( isset( $delay_js_scripts['adsbygoogle'] ) ) { - $delay_js_scripts['adsbygoogle.js'] = $delay_js_scripts['adsbygoogle']; - - unset( $delay_js_scripts['adsbygoogle'] ); - } - - $options['delay_js_scripts'] = array_values( array_flip( $delay_js_scripts ) ); - - update_option( 'wp_rocket_settings', $options ); + public function sanitize_options( $input, $settings ): array { + $input['delay_js'] = $settings->sanitize_checkbox( $input, 'delay_js' ); + $input['delay_js_exclusions'] = + ! empty( $input['delay_js_exclusions'] ) + ? + rocket_sanitize_textarea_field( 'delay_js_exclusions', $input['delay_js_exclusions'] ) + : + []; + + return $input; } /** - * Update delay_js options when updating to ver 3.7.2. + * Disable combine JS option when delay JS is enabled * - * @since 3.7.2 + * @since 3.9 * - * @param string $old_version Old plugin version. + * @param array $value The new, unserialized option value. + * @param array $old_value The old option value. * - * @return void + * @return array */ - public function option_update_3_7_2( $old_version ) { - if ( version_compare( $old_version, '3.7.2', '>' ) ) { - return; + public function maybe_disable_combine_js( $value, $old_value ): array { + if ( ! isset( $value['delay_js'], $value['minify_concatenate_js'] ) ) { + return $value; } - $options = get_option( 'wp_rocket_settings', [] ); - - $delay_js_scripts = array_flip( $options['delay_js_scripts'] ); - if ( - isset( $delay_js_scripts['fbq('] ) - && - ! isset( $delay_js_scripts['pixel-caffeine/build/frontend.js'] ) + 0 === $value['minify_concatenate_js'] + || + 0 === $value['delay_js'] ) { - $delay_js_scripts['pixel-caffeine/build/frontend.js'] = ''; + return $value; } - if ( isset( $delay_js_scripts['google.com/recaptcha/api.js'] ) ) { - unset( $delay_js_scripts['google.com/recaptcha/api.js'] ); - } - - if ( isset( $delay_js_scripts['widget.trustpilot.com'] ) ) { - $delay_js_scripts['widget.trustpilot.com/bootstrap'] = $delay_js_scripts['widget.trustpilot.com']; - - unset( $delay_js_scripts['widget.trustpilot.com'] ); + if ( + isset( $old_value['delay_js'], $old_value['minify_concatenate_js'] ) + && + $value['delay_js'] === $old_value['delay_js'] + && + 1 === $value['delay_js'] + && + 0 === $old_value['minify_concatenate_js'] + ) { + return $value; } - $options['delay_js_scripts'] = array_values( array_flip( $delay_js_scripts ) ); + $value['minify_concatenate_js'] = 0; - update_option( 'wp_rocket_settings', $options ); + return $value; } /** - * Restores the default list when updating from 3.7.6 (which removed anything ending in '.js' -- whoops!) + * Get default exclusion list. * - * @since 3.7.6.1 + * @since 3.9.1 * - * @param string $old_version Old plugin version. - * - * @return void + * @return string[] */ - public function option_update_3_7_6_1( $old_version ) { - if ( 0 !== version_compare( $old_version, '3.7.6' ) ) { - return; - } + public static function get_delay_js_default_exclusions(): array { - $options = get_option( 'wp_rocket_settings', [] ); + $exclusions = [ + '\/jquery(-migrate)?-?([0-9.]+)?(.min|.slim|.slim.min)?.js(\?(.*))?( |\'|"|>)', + 'js-(before|after)', + ]; - if ( ! isset( $options['delay_js_scripts'] ) || ! is_array( $options['delay_js_scripts'] ) ) { - $options['delay_js_scripts'] = $this->defaults; - } else { - $delay_js_scripts = array_flip( $options['delay_js_scripts'] ); + $wp_content = wp_parse_url( content_url( '/' ), PHP_URL_PATH ); + $wp_includes = wp_parse_url( includes_url( '/' ), PHP_URL_PATH ); + $pattern = '(?:placeholder)(.*)'; + $paths = []; - if ( isset( $delay_js_scripts['a.omappapi.com/app/js/api.min.js'] ) ) { - unset( $delay_js_scripts['a.omappapi.com/app/js/api.min.js'] ); - } + if ( ! $wp_content && ! $wp_includes ) { + return $exclusions; + } - if ( isset( $delay_js_scripts['/sdk.js'] ) ) { - unset( $delay_js_scripts['/sdk.js'] ); - } + if ( $wp_content ) { + $paths[] = $wp_content; + } - $options['delay_js_scripts'] = array_values( array_unique( array_merge( $this->defaults, array_flip( $delay_js_scripts ) ) ) ); + if ( $wp_includes ) { + $paths[] = $wp_includes; } - update_option( 'wp_rocket_settings', $options ); + $exclusions[] = str_replace( 'placeholder', implode( '|', $paths ), $pattern ); + + return $exclusions; } /** - * Restores the delay_js_scripts option to the default value + * Check if current exclusion list has the default list. * - * @since 3.7 + * @since 3.9.1 * - * @return bool|string + * @return bool */ - public function restore_defaults() { - if ( ! current_user_can( 'rocket_manage_options' ) ) { + public static function exclusion_list_has_default(): bool { + $current_list = get_rocket_option( 'delay_js_exclusions', [] ); + if ( empty( $current_list ) ) { + return false; + } + + $default_list = self::get_delay_js_default_exclusions(); + if ( count( $current_list ) < count( $default_list ) ) { return false; } - return implode( "\n", $this->defaults ); + $current_list = array_flip( $current_list ); + + foreach ( $default_list as $item ) { + if ( ! isset( $current_list[ $item ] ) ) { + return false; + } + } + return true; } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/SiteList.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/SiteList.php new file mode 100644 index 000000000..b7854146c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/SiteList.php @@ -0,0 +1,535 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DelayJS\Admin; + +use WP_Rocket\Admin\Options; +use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Optimization\DynamicLists\DelayJSLists\DataManager; +use WP_Rocket\Engine\Optimization\DynamicLists\DynamicLists; +use WP_Theme; + +class SiteList { + /** + * Delay JS data manager. + * + * @var DataManager + */ + protected $dynamic_lists; + + /** + * Options instance. + * + * @var Options_Data + */ + protected $options; + + /** + * Options API instance. + * + * @var Options + */ + private $options_api; + + /** + * SiteList Constructor. + * + * @param DynamicLists $dynamic_lists Dynamic Lists instance. + * @param Options_Data $options Options instance. + * @param Options $options_api Options API instance. + */ + public function __construct( DynamicLists $dynamic_lists, Options_Data $options, Options $options_api ) { + $this->dynamic_lists = $dynamic_lists; + $this->options = $options; + $this->options_api = $options_api; + } + + /** + * Check if plugin is in the list and return it if found. + * + * @param string $item_id Plugin ID like wp-rocket/wp-rocket.php. + * + * @return array + */ + private function get_plugin_in_list( string $item_id ) { + $list = $this->dynamic_lists->get_delayjs_list(); + return ! empty( $list->plugins->$item_id ) ? (array) $list->plugins->$item_id : []; + } + + /** + * Check if theme is in the list and return it if found. + * + * @param string $item_id Theme ID (directory name) like twentytwenty. + * + * @return array + */ + private function get_theme_in_list( string $item_id ) { + $list = $this->dynamic_lists->get_delayjs_list(); + return ! empty( $list->themes->$item_id ) ? (array) $list->themes->$item_id : []; + } + + /** + * Check if script is in the list and return it if found. + * + * @param string $item_id Script ID. + * + * @return array + */ + private function get_script_in_list( string $item_id ) { + $scripts = $this->get_scripts_from_list(); + return ! empty( $scripts[ $item_id ] ) ? (array) $scripts[ $item_id ] : []; + } + + /** + * Get all scripts from the list. + * + * @return array + */ + private function get_scripts_from_list() { + $list = $this->dynamic_lists->get_delayjs_list(); + return ! empty( $list->scripts ) ? (array) $list->scripts : []; + } + + /** + * Get all plugins from the list. + * + * @return array + */ + private function get_plugins_from_list() { + $list = $this->dynamic_lists->get_delayjs_list(); + return ! empty( $list->plugins ) ? (array) $list->plugins : []; + } + + /** + * Get all themes from the list. + * + * @return array + */ + private function get_themes_from_list() { + $list = $this->dynamic_lists->get_delayjs_list(); + return ! empty( $list->themes ) ? (array) $list->themes : []; + } + + /** + * Get list of exclusions from the API list. + * + * @param string $item_id Item ID to get exclusions for (plugin slug, theme slug, script ID). + * + * @return array + */ + public function get_delayjs_exclusions_by_id( string $item_id ) { + $item = $this->get_script_in_list( $item_id ); + if ( $item ) { + return $item['exclusions']; + } + + $item = $this->get_plugin_in_list( $item_id ); + if ( $item ) { + return $item['exclusions']; + } + + $item = $this->get_theme_in_list( $item_id ); + if ( $item ) { + return $item['exclusions']; + } + + return []; + } + + /** + * Get all exclusions (merged together) for a list of item IDs. + * + * @param array $items List of items. + * + * @return array + */ + public function get_delayjs_items_exclusions( array $items ) { + if ( empty( $items ) ) { + return []; + } + + $exclusions = []; + + foreach ( $items as $item ) { + $exclusions = array_merge( $exclusions, $this->get_delayjs_exclusions_by_id( $item ) ); + } + + return $exclusions; + } + + /** + * Get active theme ID. + * + * @return string + */ + public function get_active_theme() { + return $this->get_theme_name( wp_get_theme() ); + } + + /** + * Get active plugins (list of IDs). + * + * @return array + */ + public function get_active_plugins() { + $plugins = (array) get_option( 'active_plugins', [] ); + + if ( ! is_multisite() ) { + return $plugins; + } + + return array_merge( + $plugins, + array_keys( (array) get_site_option( 'active_sitewide_plugins', [] ) ) + ); + } + + /** + * Prepare the list of scripts, plugins and theme for the view. + * + * @return array|array[] + */ + public function prepare_delayjs_ui_list() { + $full_list = [ + 'scripts' => [ + 'title' => __( 'Analytics & Ads', 'rocket' ), + 'items' => [], + 'dashicon-class' => 'analytics', + ], + 'plugins' => [ + 'title' => __( 'Plugins', 'rocket' ), + 'items' => [], + 'dashicon-class' => 'admin-plugins', + ], + 'themes' => [ + 'title' => __( 'Themes', 'rocket' ), + 'items' => [], + 'dashicon-class' => 'admin-appearance', + ], + ]; + + // Scripts. + $scripts = $this->get_scripts_from_list(); + foreach ( $scripts as $script_key => $script ) { + $full_list['scripts']['items'][] = [ + 'id' => $script_key, + 'title' => $script->title, + 'icon' => $this->get_icon( $script ), + ]; + } + + $active_plugins = $this->get_active_plugins(); + foreach ( $this->get_plugins_from_list() as $plugin_key => $plugin ) { + if ( ! in_array( $plugin->condition, $active_plugins, true ) ) { + continue; + } + + $full_list['plugins']['items'][] = [ + 'id' => $plugin_key, + 'title' => $plugin->title, + 'icon' => $this->get_icon( $plugin ), + ]; + } + + $active_theme = $this->get_active_theme(); + foreach ( $this->get_themes_from_list() as $theme_key => $theme ) { + if ( $theme->condition !== $active_theme ) { + continue; + } + + $full_list['themes']['items'][] = [ + 'id' => $theme_key, + 'title' => $theme->title, + 'icon' => $this->get_icon( $theme ), + ]; + } + + return $full_list; + } + /** + * Fetch the icon. + * + * @param array $item item from the list. + * @return string + */ + private function get_icon( $item ) { + if ( empty( $item ) || empty( $item->icon_url ) ) { + return ''; + } + + return $item->icon_url; + } + + /** + * Sanitizes delay JS options when saving the settings + * + * @since 3.13 + * + * @param array $input Array of values submitted from the form. + * + * @return array + */ + public function sanitize_options( $input ): array { + if ( empty( $input['delay_js_exclusions_selected'] ) ) { + $input['delay_js_exclusions_selected'] = []; + $input['delay_js_exclusions_selected_exclusions'] = []; + + return $input; + } + + $input['delay_js_exclusions_selected_exclusions'] = $this->get_delayjs_items_exclusions( $input['delay_js_exclusions_selected'] ); + + return $input; + } + + /** + * Refresh exclusions option based on selected items option. + * + * @return void + */ + public function refresh_exclusions_option() { + $slug = rocket_get_constant( 'WP_ROCKET_SLUG', 'wp_rocket_settings' ); + $options = get_option( $slug, [] ); + if ( empty( $options ) ) { + return; + } + $options['delay_js_exclusions_selected_exclusions'] = $this->get_delayjs_items_exclusions( $options['delay_js_exclusions_selected'] ?? [] ); + update_option( $slug, $options ); + } + + /** + * Get plugin item ids from the list using plugin base. + * + * @param string $plugin_base Plugin basename. + * + * @return string[] + */ + private function get_plugin_item_ids( string $plugin_base ) { + $item_ids = []; + foreach ( $this->get_plugins_from_list() as $plugin_key => $plugin ) { + if ( $plugin_base !== $plugin->condition ) { + continue; + } + $item_ids[ $plugin_key ] = $plugin->is_default; + } + return $item_ids; + } + + /** + * Add plugin exclusions only if plugin is default is checked in backend. + * + * @param string $plugin_base Plugin basename. + * + * @return void + */ + public function add_default_plugin_exclusions( string $plugin_base ) { + $plugin_item_ids = $this->get_plugin_item_ids( $plugin_base ); + if ( empty( $plugin_item_ids ) ) { + return; + } + + $selected_items = $this->options->get( 'delay_js_exclusions_selected', [] ); + if ( empty( $selected_items ) ) { + return; + } + + $current_selected_items = $selected_items; + + foreach ( $plugin_item_ids as $plugin_item_id => $plugin_is_default ) { + if ( ! $plugin_is_default ) { + continue; + } + $selected_items[] = $plugin_item_id; + } + + if ( $current_selected_items === $selected_items ) { + return; + } + + $this->options->set( 'delay_js_exclusions_selected', $selected_items ); + $this->options->set( + 'delay_js_exclusions_selected_exclusions', + $this->get_delayjs_items_exclusions( $selected_items ) + ); + + $this->options_api->set( 'settings', $this->options->get_options() ); + } + + /** + * Remove plugin selections from settings. + * + * @param string $plugin_base Plugin basename. + * + * @return void + */ + public function remove_plugin_selection( $plugin_base ) { + $plugin_item_ids = $this->get_plugin_item_ids( $plugin_base ); + if ( empty( $plugin_item_ids ) ) { + return; + } + + $selected_items = $this->options->get( 'delay_js_exclusions_selected', [] ); + if ( empty( $selected_items ) ) { + return; + } + + $current_selected_items = $selected_items; + + foreach ( $plugin_item_ids as $plugin_item_id => $plugin_is_default ) { + $selected_item_key = array_search( $plugin_item_id, $selected_items, true ); + if ( false === $selected_item_key ) { + continue; + } + unset( $selected_items[ $selected_item_key ] ); + } + + if ( $current_selected_items === $selected_items ) { + return; + } + + $this->options->set( 'delay_js_exclusions_selected', $selected_items ); + $this->options->set( + 'delay_js_exclusions_selected_exclusions', + $this->get_delayjs_items_exclusions( $selected_items ) + ); + + $this->options_api->set( 'settings', $this->options->get_options() ); + } + + /** + * Get theme name from theme object. + * + * @param WP_Theme $theme Theme to get its name. + * + * @return string + */ + private function get_theme_name( WP_Theme $theme ) { + $parent = $theme->get_template(); + if ( ! empty( $parent ) ) { + return $parent; + } + + return $theme->get( 'Name' ); + } + + /** + * Get Theme item ids from the list using theme name. + * + * @param string $theme_name Theme name. + * + * @return string[] + */ + private function get_theme_item_ids( $theme_name ) { + $item_ids = []; + foreach ( $this->get_themes_from_list() as $theme_key => $theme ) { + if ( $theme_name !== $theme->condition ) { + continue; + } + + $item_ids[] = $theme_key; + } + return $item_ids; + } + + /** + * Replace the old theme with the new theme exclusions. + * + * @param WP_Theme $new_theme WP_Theme instance of the new theme. + * @param WP_Theme $old_theme WP_Theme instance of the old theme. + * + * @return void + */ + public function replace_theme_selection( $new_theme, $old_theme ) { + $new_theme_ids = $this->get_theme_item_ids( $this->get_theme_name( $new_theme ) ); + $old_theme_ids = $this->get_theme_item_ids( $this->get_theme_name( $old_theme ) ); + + if ( empty( $new_theme_ids ) && empty( $old_theme_ids ) ) { + return; + } + + $selected_items = $this->options->get( 'delay_js_exclusions_selected', [] ); + if ( empty( $selected_items ) ) { + return; + } + + $current_selected_items = $selected_items; + + if ( ! empty( $old_theme_ids ) ) { + foreach ( $old_theme_ids as $old_theme_id ) { + $selected_item_key = array_search( $old_theme_id, $selected_items, true ); + if ( false === $selected_item_key ) { + continue; + } + unset( $selected_items[ $selected_item_key ] ); + } + } + + if ( ! empty( $new_theme_ids ) ) { + $themes = $this->get_themes_from_list(); + foreach ( $new_theme_ids as $new_theme_id ) { + if ( ! $themes[ $new_theme_id ]->is_default ) { + continue; + } + $selected_items[] = $new_theme_id; + } + } + + if ( $current_selected_items === $selected_items ) { + return; + } + + $this->options->set( 'delay_js_exclusions_selected', $selected_items ); + $this->options->set( + 'delay_js_exclusions_selected_exclusions', + $this->get_delayjs_items_exclusions( $selected_items ) + ); + + $this->options_api->set( 'settings', $this->options->get_options() ); + } + + /** + * Get default items from the list with their exclusions. + * + * @return array + */ + public function get_default_exclusions() { + $items = []; + + $scripts = $this->get_scripts_from_list(); + foreach ( $scripts as $script_key => $script ) { + if ( ! $script->is_default ) { + continue; + } + + $items[ $script_key ] = $script->exclusions; + } + + $active_plugins = $this->get_active_plugins(); + foreach ( $this->get_plugins_from_list() as $plugin_key => $plugin ) { + if ( ! in_array( $plugin->condition, $active_plugins, true ) || ! $plugin->is_default ) { + continue; + } + + $items[ $plugin_key ] = $plugin->exclusions; + } + + $active_theme = $this->get_active_theme(); + foreach ( $this->get_themes_from_list() as $theme_key => $theme ) { + if ( $theme->condition !== $active_theme || ! $theme->is_default ) { + continue; + } + + $items[ $theme_key ] = $theme->exclusions; + } + + /** + * Filters the delay JS default exclusions list. + * Key is the plugin/theme/script unique ID and value is array of exclusions + * + * @since 3.13 + * + * @param array $items Array of default excluded items. + */ + return apply_filters( 'rocket_delay_js_default_exclusions', $items ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/Subscriber.php index e10672662..684fb4510 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Admin/Subscriber.php @@ -1,11 +1,13 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\Optimization\DelayJS\Admin; -use WP_Rocket\Abstract_Render; +use WP_Rocket\Engine\Admin\Settings\Settings as AdminSettings; use WP_Rocket\Event_Management\Subscriber_Interface; +use WP_Theme; -class Subscriber extends Abstract_Render implements Subscriber_Interface { +class Subscriber implements Subscriber_Interface { /** * Settings instance * @@ -14,15 +16,21 @@ class Subscriber extends Abstract_Render implements Subscriber_Interface { private $settings; /** - * Instantiate the class + * Site List instance. * - * @param Settings $settings Settings instance. - * @param string $template_path Template path. + * @var SiteList */ - public function __construct( Settings $settings, $template_path ) { - parent::__construct( $template_path ); + private $site_list; - $this->settings = $settings; + /** + * Instantiate the class + * + * @param Settings $settings Settings instance. + * @param SiteList $site_list DelayJS Site List instance. + */ + public function __construct( Settings $settings, SiteList $site_list ) { + $this->settings = $settings; + $this->site_list = $site_list; } /** @@ -32,123 +40,175 @@ public function __construct( Settings $settings, $template_path ) { */ public static function get_subscribed_events() { return [ - 'rocket_first_install_options' => 'add_options', - 'rocket_after_textarea_field_delay_js_scripts' => 'display_restore_defaults_button', - 'wp_rocket_upgrade' => [ - [ 'set_option_on_update', 13, 2 ], - [ 'option_update_3_7_2', 13, 2 ], - [ 'option_update_3_7_4', 13, 2 ], - [ 'option_update_3_7_6_1', 13, 2 ], + 'rocket_first_install_options' => [ + [ 'add_options' ], + [ 'add_default_exclusions_options' ], + ], + 'wp_rocket_upgrade' => [ 'set_option_on_update', 13, 2 ], + 'rocket_input_sanitize' => [ + [ 'sanitize_options', 13, 2 ], + [ 'sanitize_selected_exclusions', 14 ], ], - 'wp_ajax_rocket_restore_delay_js_defaults' => 'restore_defaults', - 'rocket_safe_mode_reset_options' => 'add_options', + 'pre_update_option_wp_rocket_settings' => [ 'maybe_disable_combine_js', 11, 2 ], + 'rocket_after_save_dynamic_lists' => 'refresh_exclusions_option', + 'activate_plugin' => 'add_plugin_exclusions', + 'deactivate_plugin' => 'remove_plugin_exclusions', + 'switch_theme' => [ 'handle_switch_theme_exclusions', 10, 3 ], + 'rocket_meta_boxes_fields' => [ 'add_meta_box', 6 ], ]; } /** * Add the delay JS options to the WP Rocket options array * - * @since 3.7 - * * @param array $options WP Rocket options array. * * @return array + * @since 3.7 */ - public function add_options( $options ) { + public function add_options( $options ): array { return $this->settings->add_options( $options ); } /** - * Displays the restore defaults button under the textarea field + * Add the delay JS exclusions options to the WP Rocket options array + * based on the default items in the list. * - * @since 3.7 + * @param array $options WP Rocket options array. * - * @return void + * @return array + * @since 3.13 */ - public function display_restore_defaults_button() { - $data = $this->settings->get_button_data(); - - $this->render_action_button( - $data['type'], - $data['action'], - $data['attributes'] - ); + public function add_default_exclusions_options( $options ): array { + $default_exclusions = $this->site_list->get_default_exclusions(); + + if ( empty( $default_exclusions ) ) { + $options['delay_js_exclusions_selected'] = []; + $options['delay_js_exclusions_selected_exclusions'] = []; + + return $options; + } + + $options['delay_js_exclusions_selected'] = array_keys( $default_exclusions ); + $options['delay_js_exclusions_selected_exclusions'] = array_merge( ...array_values( $default_exclusions ) ); + + return $options; } /** - * Sets the delay_js option to zero when updating to 3.7 - * - * @since 3.7 + * Sets the delay_js_exclusions default value for users with delay JS enabled on upgrade * * @param string $new_version New plugin version. * @param string $old_version Previous plugin version. * * @return void + * @since 3.7 + * + * @since 3.9 Sets the delay_js_exclusions default value if delay_js is 1 */ public function set_option_on_update( $new_version, $old_version ) { $this->settings->set_option_on_update( $old_version ); } /** - * Update the delay_js options when updating to 3.7.2. + * Sanitizes Delay JS options values when the settings form is submitted * - * @since 3.7.2 + * @param array $input Array of values submitted from the form. + * @param AdminSettings $settings Settings class instance. * - * @param string $new_version New plugin version. - * @param string $old_version Old plugin version. - * - * @return void + * @return array + * @since 3.9 */ - public function option_update_3_7_2( $new_version, $old_version ) { - $this->settings->option_update_3_7_2( $old_version ); + public function sanitize_options( $input, AdminSettings $settings ): array { + return $this->settings->sanitize_options( $input, $settings ); } /** - * Update the delay_js options when updating to 3.7.4 + * Sanitizes delay JS selected exclusions options when saving the settings. * - * @since 3.7.4 + * @since 3.13 * - * @param string $new_version New plugin version. - * @param string $old_version Old plugin version. + * @param array $input Array of values submitted from the form. * - * @return void + * @return array */ - public function option_update_3_7_4( $new_version, $old_version ) { - $this->settings->option_update_3_7_4( $old_version ); + public function sanitize_selected_exclusions( $input ) { + return $this->site_list->sanitize_options( $input ); } /** - * Restore the delay_js options to default when updating from 3.7.6. + * Disable combine JS option when delay JS is enabled * - * @since 3.7.6.1 + * @param array $value The new, unserialized option value. + * @param array $old_value The old option value. * - * @param string $new_version New plugin version. - * @param string $old_version Old plugin version. + * @return array + * @since 3.9 + */ + public function maybe_disable_combine_js( $value, $old_value ): array { + return $this->settings->maybe_disable_combine_js( $value, $old_value ); + } + + /** + * Refresh exclusions option when the dynamic list is updated weekly or manually. * * @return void */ - public function option_update_3_7_6_1( $new_version, $old_version ) { - $this->settings->option_update_3_7_6_1( $old_version ); + public function refresh_exclusions_option() { + $this->site_list->refresh_exclusions_option(); } /** - * AJAX callback to restore the default value for the delay JS scripts + * Remove plugin from exclusions list once deactivated. * - * @since 3.7 + * @param string $plugin Plugin basename. * * @return void */ - public function restore_defaults() { - check_ajax_referer( 'rocket-ajax', 'nonce', true ); - - $result = $this->settings->restore_defaults(); + public function remove_plugin_exclusions( string $plugin ) { + if ( plugin_basename( WP_ROCKET_FILE ) === $plugin ) { + return; + } + $this->site_list->remove_plugin_selection( $plugin ); + } - if ( false === $result ) { - wp_send_json_error(); + /** + * Handle switch theme exclusions, remove the old theme exclusions and add the new one. + * + * @param string $new_name Name of the new theme. + * @param WP_Theme $new_theme WP_Theme instance of the new theme. + * @param WP_Theme $old_theme WP_Theme instance of the old theme. + * + * @return void + */ + public function handle_switch_theme_exclusions( string $new_name, WP_Theme $new_theme, WP_Theme $old_theme ) { + $this->site_list->replace_theme_selection( $new_theme, $old_theme ); + } + /** + * Add plugin exclusions with plugin activation for default checked plugins. + * + * @param string $plugin Plugin basename. + * + * @return void + */ + public function add_plugin_exclusions( string $plugin ) { + if ( plugin_basename( WP_ROCKET_FILE ) === $plugin ) { return; } + $this->site_list->add_default_plugin_exclusions( $plugin ); + } + + /** + * Add the field to the WP Rocket metabox on the post edit page. + * + * @param string[] $fields Metaboxes fields. + * + * @return string[] + */ + public function add_meta_box( array $fields ) { + $fields['delay_js'] = __( 'Delay JavaScript execution', 'rocket' ); - wp_send_json_success( $result ); + return $fields; } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/HTML.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/HTML.php index 2645db0a8..7acd06bc0 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/HTML.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/HTML.php @@ -1,58 +1,126 @@ <?php +declare( strict_types=1 ); namespace WP_Rocket\Engine\Optimization\DelayJS; use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Optimization\DynamicLists\DefaultLists\DataManager; +use WP_Rocket\Engine\Optimization\RegexTrait; +use WP_Rocket\Logger\Logger; class HTML { + use RegexTrait; /** * Plugin options instance. * - * @since 3.7 - * * @var Options_Data */ protected $options; /** - * Allowed scripts regex. + * DataManager instance * - * @since 3.7 + * @var DataManager + */ + private $data_manager; + + /** + * Array of excluded patterns from delay JS + * + * @since 3.9 * - * @var string + * @var array */ - private $allowed_scripts = ''; + protected $excluded = []; /** - * Creates an instance of HTML. + * Allowed type attributes. * - * @since 3.7 + * @var array Array of allowed type attributes. + */ + private $allowed_types = [ + 'text/javascript', + 'module', + 'application/javascript', + 'application/ecmascript', + 'application/x-ecmascript', + 'application/x-javascript', + 'text/ecmascript', + 'text/javascript1.0', + 'text/javascript1.1', + 'text/javascript1.2', + 'text/javascript1.3', + 'text/javascript1.4', + 'text/javascript1.5', + 'text/jscript', + 'text/livescript', + 'text/x-ecmascript', + 'text/x-javascript', + ]; + + /** + * Logger instance. + * + * @var Logger + */ + protected $logger; + + /** + * Creates an instance of HTML. * * @param Options_Data $options Plugin options instance. + * @param DataManager $data_manager DataManager instance. + * @param Logger $logger Logger instance. */ - public function __construct( Options_Data $options ) { - $this->options = $options; + public function __construct( Options_Data $options, DataManager $data_manager, Logger $logger ) { + $this->options = $options; + $this->data_manager = $data_manager; + $this->logger = $logger; } /** * Adjust HTML to have delay js structure. * + * @since 3.9 Updated to use exclusions list instead of inclusions list. + * @since 3.7 + * * @param string $html Buffer html for the page. * * @return string */ - public function delay_js( $html ) { - + public function delay_js( $html ): string { if ( ! $this->is_allowed() ) { return $html; } - $this->allowed_scripts = $this->prepare_allowed_scripts_regex(); + $this->set_exclusions(); - if ( empty( $this->allowed_scripts ) ) { - return $html; - } + $this->excluded = array_merge( $this->excluded, $this->options->get( 'delay_js_exclusions', [] ) ); + $this->excluded = array_merge( $this->excluded, $this->options->get( 'delay_js_exclusions_selected_exclusions', [] ) ); + + /** + * Filters the delay JS exclusions array + * + * @since 3.9 + * + * @param array $excluded Array of excluded patterns. + */ + $this->excluded = (array) apply_filters( 'rocket_delay_js_exclusions', $this->excluded ); + $this->excluded = array_map( + function ( $value ) { + if ( ! is_string( $value ) ) { + $value = (string) $value; + } + + return str_replace( + [ '+', '?ver', '#' ], + [ '\+', '\?ver', '\#' ], + $value + ); + }, + $this->excluded + ); return $this->parse( $html ); } @@ -64,7 +132,8 @@ public function delay_js( $html ) { * * @return bool */ - public function is_allowed() { + public function is_allowed(): bool { + if ( rocket_bypass() ) { return false; } @@ -80,96 +149,156 @@ public function is_allowed() { return (bool) $this->options->get( 'delay_js', 0 ); } + /** + * Gets Javascript to redirect IE visitors to the uncached page + * + * @since 3.9 + * + * @return string + */ + public function get_ie_fallback(): string { + return 'if(navigator.userAgent.match(/MSIE|Internet Explorer/i)||navigator.userAgent.match(/Trident\/7\..*?rv:11/i)){var href=document.location.href;if(!href.match(/[?&]nowprocket/)){if(href.indexOf("?")==-1){if(href.indexOf("#")==-1){document.location.href=href+"?nowprocket=1"}else{document.location.href=href.replace("#","?nowprocket=1#")}}else{if(href.indexOf("#")==-1){document.location.href=href+"&nowprocket=1"}else{document.location.href=href.replace("#","&nowprocket=1#")}}}}'; + } + /** * Parse the html and add/remove attributes from specific scripts. * + * @since 3.7 + * * @param string $html Buffer html for the page. * * @return string */ - private function parse( $html ) { - $replaced_html = preg_replace_callback( '/<script\s*(?<attr>[^>]*)?>(?<content>.*)?<\/script>/Uims', [ $this, 'replace_scripts' ], $html ); + private function parse( $html ): string { + + if ( empty( $html ) ) { + return $html; + } + $result = $this->replace_xmp_tags( $html ); + $result = $this->replace_svg_tags( $result ); + + $replaced_html = preg_replace_callback( + '/<\s*script(?<attr>\s*[^>]*?)?>(?<content>.*?)?<\s*\/\s*script\s*>/ims', + [ + $this, + 'replace_scripts', + ], + $result + ); if ( empty( $replaced_html ) ) { return $html; } - return $replaced_html; + $replaced_html = $this->restore_xmp_tags( $replaced_html ); + return $this->restore_svg_tags( $replaced_html ); } /** - * Callback method for preg_replace_callback that is used to adjust attributes for specific scripts. + * Callback method for preg_replace_callback that is used to adjust attributes for scripts. + * + * @since 3.9 Use exclusions list & fake type attribute. + * @since 3.7 * * @param array $matches Matches array for scripts regex. * * @return string */ - public function replace_scripts( $matches ) { - if ( - empty( $this->allowed_scripts ) - || - ( - ! empty( $this->allowed_scripts ) - && - ! preg_match( '#(' . $this->allowed_scripts . ')#', $matches[0] ) - ) - ) { - return $matches[0]; - } - - $src = ''; - $matches['attr'] = trim( $matches['attr'] ); - - if ( ! empty( $matches['attr'] ) ) { - if ( preg_match( '/src=(["\'])(.*?)\1/', $matches['attr'], $src_matches ) ) { - $src = $src_matches[2]; - - // Remove the src attribute. - $matches['attr'] = str_replace( $src_matches[0], '', $matches['attr'] ); + public function replace_scripts( $matches ): string { + foreach ( $this->excluded as $pattern ) { + if ( preg_match( "#{$pattern}#i", $matches[0] ) ) { + $this->logger->debug( "DelayJS: Script {$matches[0]} excluded by $pattern" ); + return $matches[0]; } } - if ( empty( $src ) ) { - // Get the JS content. - if ( ! empty( $matches['content'] ) ) { - $src = 'data:text/javascript;base64,' . base64_encode( $matches['content'] );// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode - } + if ( empty( $matches['attr'] ) ) { + return '<script type="rocketlazyloadscript">' . $matches['content'] . '</script>'; } - if ( empty( $src ) ) { + $type_regex = '/type\s*=\s*(["\'])(?<type>.*)\1/i'; + preg_match( $type_regex . 'U', $matches['attr'], $type_matches ); + if ( + ! empty( $type_matches ) + && + ! empty( trim( $type_matches['type'] ) ) + && + ! in_array( trim( $type_matches['type'] ), $this->allowed_types, true ) + ) { return $matches[0]; } - return "<script data-rocketlazyloadscript='{$src}' {$matches['attr']}></script>"; + $matches['attr'] = preg_replace( $type_regex, 'data-rocket-type=$1$2$1', $matches['attr'] ); + // To remove type attribute without any value. + $matches['attr'] = preg_replace( '/(\s+type\s+)|(^type\s+)|(\s+type$)/i', '', $matches['attr'] ); + + // Checks if script has src attribute so then treat as external script and replace src with data-rocket-src. + $src_regex = '/src\s*=\s*(["\'])(.*)\1/i'; + $matches['attr'] = preg_replace( $src_regex, 'data-rocket-src=$1$2$1', $matches['attr'] ); + + return '<script type="rocketlazyloadscript" ' . trim( $matches['attr'] ) . '>' . $matches['content'] . '</script>'; } + /** - * Prepare allowed scripts to be used as regex. + * Move meta charset to head if not found to the top of page content. + * + * @since 3.9.4 + * + * @param string $html Html content. * * @return string */ - private function prepare_allowed_scripts_regex() { - $delay_js_scripts = $this->options->get( 'delay_js_scripts', [] ); + public function move_meta_charset_to_head( $html ): string { + $meta_pattern = "#<meta[^h]*(http-equiv[^=]*=[^\'\"]*[\'\" ]Content-Type[\'\"][ ]*[^>]*|)(charset[^=]*=[ ]*[\'\" ]*[^\'\"> ][^\'\">]+[^\'\"> ][\'\" ]*|charset[^=]*=*[^\'\"> ][^\'\">]+[^\'\"> ])([^>]*|)>(?=.*</head>)#Usmi"; - /** - * Filters JS files to included into delay JS. - * - * @since 3.7 - * - * @param array $delay_js_scripts List of allowed JS files. - */ - $delay_js_scripts = (array) apply_filters( 'rocket_delay_js_scripts', $delay_js_scripts ); + if ( ! preg_match( $meta_pattern, $html, $matches ) ) { + return $html; + } + + $replaced_html = preg_replace( "$meta_pattern", '', $html ); - if ( empty( $delay_js_scripts ) ) { - return ''; + if ( empty( $replaced_html ) ) { + return $html; + } + + if ( preg_match( '/<head\b/i', $replaced_html ) ) { + $replaced_html = preg_replace( '/(<head\b[^>]*?>)/i', "\${1}{$matches[0]}", $replaced_html, 1 ); + + if ( empty( $replaced_html ) ) { + return $html; + } + + return $replaced_html; } - foreach ( $delay_js_scripts as $i => $delay_js_script ) { - $delay_js_scripts[ $i ] = preg_quote( str_replace( '#', '\#', $delay_js_script ), '#' ); + if ( preg_match( '/<html\b/i', $replaced_html ) ) { + $replaced_html = preg_replace( '/(<html\b[^>]*?>)/i', "\${1}{$matches[0]}", $replaced_html, 1 ); + + if ( empty( $replaced_html ) ) { + return $html; + } + + return $replaced_html; } - return implode( '|', $delay_js_scripts ); + $replaced_html = preg_replace( '/(<\w+)/', "{$matches[0]}\${1}", $replaced_html, 1 ); + if ( empty( $replaced_html ) ) { + return $html; + } + + return $replaced_html; } + /** + * Get exclusions + * + * @return void + */ + private function set_exclusions() { + $lists = $this->data_manager->get_lists(); + + $this->excluded = isset( $lists->delay_js_exclusions ) ? $lists->delay_js_exclusions : []; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/ServiceProvider.php index a9d0039b4..7310faf8a 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/ServiceProvider.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/ServiceProvider.php @@ -1,39 +1,66 @@ <?php namespace WP_Rocket\Engine\Optimization\DelayJS; -use WP_Rocket\Engine\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Optimization\DelayJS\Admin\{ + Settings, + SiteList, + Subscriber as AdminSubscriber +}; +use WP_Rocket\Logger\Logger; /** * Service provider for the WP Rocket Delay JS - * - * @since 3.7 */ class ServiceProvider extends AbstractServiceProvider { - /** - * The provides array is a way to let the container - * know that a service is provided by this service - * provider. Every service that is registered via - * this service provider must have an alias added - * to this array or it will be ignored. + * Array of services provided by this service provider * * @var array */ protected $provides = [ 'delay_js_settings', 'delay_js_admin_subscriber', + 'delay_js_html', + 'delay_js_subscriber', + 'delay_js_sitelist', ]; /** - * Registers the option array in the container + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers items with the container * * @return void */ - public function register() { - $this->getContainer()->add( 'delay_js_settings', 'WP_Rocket\Engine\Optimization\DelayJS\Admin\Settings' ) - ->withArgument( $this->getContainer()->get( 'options' ) ); - $this->getContainer()->share( 'delay_js_admin_subscriber', 'WP_Rocket\Engine\Optimization\DelayJS\Admin\Subscriber' ) - ->withArgument( $this->getContainer()->get( 'delay_js_settings' ) ) - ->withArgument( $this->getContainer()->get( 'template_path' ) . '/settings' ); + public function register(): void { + $this->getContainer()->add( 'delay_js_sitelist', SiteList::class ) + ->addArgument( $this->getContainer()->get( 'dynamic_lists' ) ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ); + $this->getContainer()->add( 'delay_js_settings', Settings::class ) + ->addArgument( $this->getContainer()->get( 'options_api' ) ); + $this->getContainer()->addShared( 'delay_js_admin_subscriber', AdminSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'delay_js_settings' ) ) + ->addArgument( $this->getContainer()->get( 'delay_js_sitelist' ) ) + ->addTag( 'admin_subscriber' ); + $this->getContainer()->add( 'delay_js_html', HTML::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'dynamic_lists_defaultlists_data_manager' ) ) + ->addArgument( new Logger() ); + $this->getContainer()->addShared( 'delay_js_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'delay_js_html' ) ) + ->addArgument( rocket_direct_filesystem() ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addTag( 'front_subscriber' ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Subscriber.php index 6705d4767..d48f80bd5 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DelayJS/Subscriber.php @@ -1,7 +1,9 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\Optimization\DelayJS; +use WP_Rocket\Admin\Options_Data; use WP_Rocket\Event_Management\Subscriber_Interface; class Subscriber implements Subscriber_Interface { @@ -24,10 +26,18 @@ class Subscriber implements Subscriber_Interface { */ private $filesystem; + /** + * Options Data instance + * + * @var Options_Data + */ + private $options; + /** * Script enqueued status. * * @since 3.7 + * * @var bool */ private $is_enqueued = false; @@ -37,10 +47,12 @@ class Subscriber implements Subscriber_Interface { * * @param HTML $html HTML Instance. * @param \WP_Filesystem_Direct $filesystem The Filesystem object. + * @param Options_Data $options Options data instance. */ - public function __construct( HTML $html, $filesystem ) { + public function __construct( HTML $html, $filesystem, Options_Data $options ) { $this->html = $html; $this->filesystem = $filesystem; + $this->options = $options; } /** @@ -52,15 +64,18 @@ public function __construct( HTML $html, $filesystem ) { */ public static function get_subscribed_events() { return [ - 'rocket_buffer' => [ - [ 'delay_js', 21 ], + 'rocket_buffer' => [ + [ 'delay_js', 26 ], + [ 'add_delay_js_script', 26 ], ], - 'wp_enqueue_scripts' => 'add_delay_js_script', + 'pre_get_rocket_option_minify_concatenate_js' => 'maybe_disable_option', ]; } /** - * Using html buffer get scripts to be delayed and adjust their html. + * Modifies scripts HTML to apply delay JS attribute + * + * @since 3.7 * * @param string $buffer_html Html for the page. * @@ -71,60 +86,58 @@ public function delay_js( $buffer_html ) { } /** - * Adds the inline script to the footer when the option is enabled. + * Displays the inline script to the head when the option is enabled. * + * @since 3.9.4 Move meta charset to head. + * @since 3.9 Hooked on rocket_buffer, display the script right after <head> * @since 3.7 * - * @return void + * @param string $html HTML content. + * + * @return string */ - public function add_delay_js_script() { - if ( $this->is_enqueued ) { - return; - } + public function add_delay_js_script( $html ): string { if ( ! $this->html->is_allowed() ) { - return; + return $html; } - $js_assets_path = rocket_get_constant( 'WP_ROCKET_PATH' ) . 'assets/js/'; - - if ( ! wp_script_is( 'rocket-browser-checker' ) ) { - $checker_filename = rocket_get_constant( 'SCRIPT_DEBUG' ) ? 'browser-checker.js' : 'browser-checker.min.js'; - - // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NoExplicitVersion - wp_register_script( - 'rocket-browser-checker', - '', - [], - '', - true - ); - wp_enqueue_script( 'rocket-browser-checker' ); - wp_add_inline_script( - 'rocket-browser-checker', - $this->filesystem->get_contents( "{$js_assets_path}{$checker_filename}" ) - ); + $pattern = '/<head[^>]*>/i'; + + $lazyload_script = $this->filesystem->get_contents( rocket_get_constant( 'WP_ROCKET_PATH' ) . 'assets/js/lazyload-scripts.min.js' ); + + $replaced_html = $html; + + if ( false !== $lazyload_script ) { + $replaced_html = preg_replace( $pattern, "$0<script>{$lazyload_script}</script>", $replaced_html, 1 ); + + if ( empty( $replaced_html ) ) { + return $html; + } } - // Register handle with no src to add the inline script after. - // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.NoExplicitVersion - wp_register_script( - 'rocket-delay-js', - '', - [ - 'rocket-browser-checker', - ], - '', - true - ); - wp_enqueue_script( 'rocket-delay-js' ); + $replaced_html = preg_replace( $pattern, '$0<script>' . $this->html->get_ie_fallback() . '</script>', $replaced_html, 1 ); - $script_filename = rocket_get_constant( 'SCRIPT_DEBUG' ) ? 'lazyload-scripts.js' : 'lazyload-scripts.min.js'; + if ( empty( $replaced_html ) ) { + return $html; + } + + return $this->html->move_meta_charset_to_head( $replaced_html ); + } - wp_add_inline_script( - 'rocket-delay-js', - $this->filesystem->get_contents( "{$js_assets_path}{$script_filename}" ) - ); + /** + * Disables defer JS if delay JS is enabled + * + * @since 3.9 + * + * @param null $value Original value. Should be always null. + * + * @return null|false + */ + public function maybe_disable_option( $value ) { + if ( $this->html->is_allowed() ) { + return false; + } - $this->is_enqueued = true; + return $value; } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/AbstractAPIClient.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/AbstractAPIClient.php new file mode 100644 index 000000000..20bf63f02 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/AbstractAPIClient.php @@ -0,0 +1,140 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists; + +use WP_Error; +use WP_Rocket\Admin\Options_Data; + +abstract class AbstractAPIClient { + /** + * API URL. + */ + const API_URL = 'https://b.rucss.wp-rocket.me/api/'; + + /** + * Response Code. + * + * @var int + */ + private $response_code = 200; + + /** + * Error message. + * + * @var string + */ + private $error_message = ''; + + /** + * Response Body. + * + * @var string + */ + private $response_body = ''; + + /** + * Plugin options instance. + * + * @var Options_Data + */ + private $options; + + /** + * Instantiate the class. + * + * @param Options_Data $options Options instance. + */ + public function __construct( Options_Data $options ) { + $this->options = $options; + } + + /** + * Specify API endpoint path. + * + * @return string + */ + abstract protected function get_api_path(); + + /** + * Get exclusions list. + * + * @param string $hash Hash of lists content to compare. + * + * @return array + */ + public function get_exclusions_list( $hash ) { + $args = [ + 'body' => [ + 'hash' => $hash, + ], + 'timeout' => 5, + ]; + + if ( ! $this->handle_request( $args ) ) { + return [ + 'code' => $this->response_code, + 'message' => $this->error_message, + ]; + } + + return [ + 'code' => $this->response_code, + 'body' => $this->response_body, + ]; + } + + /** + * Handle the request. + * + * @param array $args Passed arguments. + * + * @return bool + */ + private function handle_request( array $args ) { + $api_url = rocket_get_constant( 'WP_ROCKET_EXCLUSIONS_API_URL', false ) + ? rocket_get_constant( 'WP_ROCKET_EXCLUSIONS_API_URL', false ) + : self::API_URL; + + if ( empty( $args['body'] ) ) { + $args['body'] = []; + } + + $args['body']['credentials'] = [ + 'wpr_email' => $this->options->get( 'consumer_email', '' ), + 'wpr_key' => $this->options->get( 'consumer_key', '' ), + ]; + + $response = wp_remote_get( + $api_url . $this->get_api_path(), + $args + ); + + return $this->check_response( $response ); + } + + /** + * Handle SaaS request error. + * + * @param array|WP_Error $response WP Remote request. + * + * @return bool + */ + private function check_response( $response ): bool { + $this->response_code = is_array( $response ) + ? wp_remote_retrieve_response_code( $response ) + : $response->get_error_code(); + + if ( 200 !== $this->response_code && 206 !== $this->response_code ) { + $this->error_message = is_array( $response ) + ? wp_remote_retrieve_response_message( $response ) + : $response->get_error_message(); + + return false; + } + + $this->response_body = wp_remote_retrieve_body( $response ); + + return true; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/AbstractDataManager.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/AbstractDataManager.php new file mode 100644 index 000000000..b40dc74b3 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/AbstractDataManager.php @@ -0,0 +1,160 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists; + +use WP_Filesystem_Direct; +use StdClass; + +abstract class AbstractDataManager { + /** + * Filesystem instance + * + * @var WP_Filesystem_Direct + */ + private $filesystem; + + /** + * Cache ttl. + * + * @var int + */ + protected $cache_duration = WEEK_IN_SECONDS; + + /** + * Instantiate the class + * + * @param WP_Filesystem_Direct $filesystem Filesystem instance. + */ + public function __construct( $filesystem = null ) { + $this->filesystem = is_null( $filesystem ) ? rocket_direct_filesystem() : $filesystem; + } + + /** + * Get cache transient name. + * + * @return string + */ + abstract protected function get_cache_transient_name(); + + /** + * Get lists json filename. + * + * @return string + */ + abstract protected function get_json_filename(); + + /** + * Gets the lists content + * + * @return object + */ + public function get_lists() { + $transient = get_transient( $this->get_cache_transient_name() ); + + if ( false !== $transient ) { + return $transient; + } + + $json = $this->get_lists_from_file(); + + $lists = json_decode( $json ); + + if ( empty( $lists ) ) { + return new StdClass(); + } + + $this->set_lists_cache( $lists ); + + return $lists; + } + + /** + * Returns the hash of the current JSON + * + * @return string + */ + public function get_lists_hash() { + return md5( $this->get_lists_from_file() ); + } + + /** + * Save dynamic lists on file & transient + * + * @param string $content Lists content. + * + * @return boolean + */ + public function save_dynamic_lists( string $content ) { + $result = $this->put_lists_to_file( $content ); + + $lists = json_decode( $content ); + + $this->set_lists_cache( $lists ); + + return $result; + } + + /** + * Gets the path to the dynamic lists JSON file + * + * @return string + */ + private function get_json_filepath(): string { + return rocket_get_constant( 'WP_ROCKET_CONFIG_PATH', '' ) . $this->get_json_filename() . '.json'; + } + + /** + * Gets lists JSON content from file + * + * @return string + */ + private function get_lists_from_file(): string { + $content = ''; + $lists_filepath = $this->get_json_filepath(); + + if ( $this->filesystem->exists( $lists_filepath ) ) { + $content = $this->filesystem->get_contents( $lists_filepath ); + } + + if ( ! empty( $content ) ) { + return $content; + } + + $fallback_filepath = rocket_get_constant( 'WP_ROCKET_PATH', '' ) . $this->get_json_filename() . '.json'; + + if ( $this->filesystem->exists( $fallback_filepath ) ) { + $content = $this->filesystem->get_contents( $fallback_filepath ); + } + + if ( ! empty( $content ) ) { + $this->put_lists_to_file( $content ); + + return $content; + } + + return $content; + } + + /** + * Write lists content to JSON file + * + * @param string $content JSON content. + * + * @return bool + */ + private function put_lists_to_file( string $content ): bool { + return $this->filesystem->put_contents( $this->get_json_filepath(), $content, rocket_get_filesystem_perms( 'file' ) ); + } + + /** + * Sets transient for lists content + * + * @param object $content Lists content. + * + * @return void + */ + private function set_lists_cache( $content ) { + set_transient( $this->get_cache_transient_name(), $content, $this->cache_duration ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DefaultLists/APIClient.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DefaultLists/APIClient.php new file mode 100644 index 000000000..e5cee0626 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DefaultLists/APIClient.php @@ -0,0 +1,18 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists\DefaultLists; + +use WP_Rocket\Engine\Optimization\DynamicLists\AbstractAPIClient; + +class APIClient extends AbstractAPIClient { + + /** + * Specify API endpoint path. + * + * @return string + */ + protected function get_api_path() { + return 'exclusions/list'; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DefaultLists/DataManager.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DefaultLists/DataManager.php new file mode 100644 index 000000000..24ea98e20 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DefaultLists/DataManager.php @@ -0,0 +1,27 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists\DefaultLists; + +use WP_Rocket\Engine\Optimization\DynamicLists\AbstractDataManager; + +class DataManager extends AbstractDataManager { + + /** + * Get cache transient name. + * + * @return string + */ + protected function get_cache_transient_name() { + return 'wpr_dynamic_lists'; + } + + /** + * Get lists json filename. + * + * @return string + */ + protected function get_json_filename() { + return 'dynamic-lists'; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DelayJSLists/APIClient.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DelayJSLists/APIClient.php new file mode 100644 index 000000000..f20a9229c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DelayJSLists/APIClient.php @@ -0,0 +1,18 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists\DelayJSLists; + +use WP_Rocket\Engine\Optimization\DynamicLists\AbstractAPIClient; + +class APIClient extends AbstractAPIClient { + + /** + * Specify API endpoint path. + * + * @return string + */ + protected function get_api_path() { + return 'delay-js-exclusions/list'; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DelayJSLists/DataManager.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DelayJSLists/DataManager.php new file mode 100644 index 000000000..4d21ed4d1 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DelayJSLists/DataManager.php @@ -0,0 +1,27 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists\DelayJSLists; + +use WP_Rocket\Engine\Optimization\DynamicLists\AbstractDataManager; + +class DataManager extends AbstractDataManager { + + /** + * Get cache transient name. + * + * @return string + */ + protected function get_cache_transient_name() { + return 'wpr_dynamic_lists_delayjs'; + } + + /** + * Get lists json filename. + * + * @return string + */ + protected function get_json_filename() { + return 'dynamic-lists-delayjs'; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DynamicLists.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DynamicLists.php new file mode 100644 index 000000000..352ab0748 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/DynamicLists.php @@ -0,0 +1,294 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists; + +use WP_Rocket\Abstract_Render; +use WP_Rocket\Engine\Admin\Beacon\Beacon; +use WP_Rocket\Engine\License\API\User; +use WP_REST_Response; +use WP_Error; + +class DynamicLists extends Abstract_Render { + + /** + * Providers array. + * Array of objects with keys: api_client and data_manager. + * + * @var array + */ + private $providers; + + /** + * User instance + * + * @var User + */ + private $user; + + /** + * Beacon instance + * + * @var Beacon + */ + private $beacon; + + /** + * Route Rest API namespace. + */ + const ROUTE_NAMESPACE = 'wp-rocket/v1'; + + /** + * Instantiate the class. + * + * @param array $providers Lists providers. + * @param User $user User instance. + * @param string $template_path Path to views. + * @param Beacon $beacon Beacon instance. + */ + public function __construct( array $providers, User $user, $template_path, Beacon $beacon ) { + parent::__construct( $template_path ); + + $this->providers = $providers; + $this->user = $user; + $this->beacon = $beacon; + } + + /** + * Registers the dynamic lists update route + * + * @return void + */ + public function register_rest_route() { + register_rest_route( + self::ROUTE_NAMESPACE, + 'dynamic_lists/update', + [ + 'methods' => 'PUT', + 'callback' => [ $this, 'rest_update_response' ], + 'permission_callback' => [ $this, 'check_permissions' ], + ] + ); + } + /** + * Checks user's permissions. This is a callback registered to REST route's "permission_callback" parameter. + * + * @return bool true if the user has permission; else false. + */ + public function check_permissions() { + return current_user_can( 'rocket_manage_options' ); + } + + /** + * Returns the update response + * + * @return WP_REST_Response|WP_Error + */ + public function rest_update_response() { + return rest_ensure_response( $this->update_lists_from_remote() ); + } + + /** + * Updates the lists from remote + * + * @return array + */ + public function update_lists_from_remote() { + if ( $this->user->is_license_expired() ) { + return [ + 'success' => false, + 'data' => '', + 'message' => __( 'You need an active license to get the latest version of the lists from our server.', 'rocket' ), + ]; + } + + $response = []; + $success = false; + $should_purge = false; + + foreach ( $this->providers as $provider ) { + $result = $provider->api_client->get_exclusions_list( $provider->data_manager->get_lists_hash() ); + + if ( empty( $result['code'] ) || empty( $result['body'] ) ) { + $response[ $provider->title ] = [ + 'success' => false, + 'data' => '', + 'message' => __( 'Could not get updated lists from server.', 'rocket' ), + ]; + continue; + } + + if ( 206 === $result['code'] ) { + $response[ $provider->title ] = [ + 'success' => true, + 'data' => '', + 'message' => __( 'Lists are up to date.', 'rocket' ), + ]; + continue; + } + + if ( ! $provider->data_manager->save_dynamic_lists( $result['body'] ) ) { + $response[ $provider->title ] = [ + 'success' => false, + 'data' => '', + 'message' => __( 'Could not update lists.', 'rocket' ), + ]; + continue; + } + + $success = true; + $response[ $provider->title ] = [ + 'success' => true, + 'data' => '', + 'message' => __( 'Lists are successfully updated.', 'rocket' ), + ]; + + $should_purge |= $provider->clear_cache ?? true; + } + + if ( $success ) { + /** + * Fires after saving all dynamic lists files. + * + * @since 3.12.1 + * + * @param bool $should_purge Should purge status based on the updated providers. + */ + do_action( 'rocket_after_save_dynamic_lists', $should_purge ); + } + + return $response; + } + + /** + * Schedule cron to update dynamic lists weekly. + * + * @return void + */ + public function schedule_lists_update() { + if ( ! wp_next_scheduled( 'rocket_update_dynamic_lists' ) ) { + wp_schedule_event( time(), 'weekly', 'rocket_update_dynamic_lists' ); + } + } + + /** + * Clear dynamic lists update event. + */ + public function clear_schedule_lists_update() { + wp_clear_scheduled_hook( 'rocket_update_dynamic_lists' ); + } + + /** + * Displays the dynamic lists update section on tools tab + * + * @return void + */ + public function display_update_lists_section() { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + + $data = [ + 'beacon' => $this->beacon->get_suggest( 'dynamic_lists' ), + ]; + + echo $this->generate( 'settings/dynamic-lists-update', $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + } + + /** + * Get the cached ignored parameters + * + * @return array + */ + public function get_cache_ignored_parameters(): array { + $lists = $this->providers['defaultlists']->data_manager->get_lists(); + + return isset( $lists->cache_ignored_parameters ) ? array_flip( $lists->cache_ignored_parameters ) : []; + } + + /** + * Get the JS minify excluded external paths + * + * @return array + */ + public function get_js_minify_excluded_external(): array { + $lists = $this->providers['defaultlists']->data_manager->get_lists(); + + return isset( $lists->js_minify_external ) ? $lists->js_minify_external : []; + } + + /** + * Get the patterns to move after the combine JS file + * + * @return array + */ + public function get_js_move_after_combine(): array { + $lists = $this->providers['defaultlists']->data_manager->get_lists(); + + return isset( $lists->js_move_after_combine ) ? $lists->js_move_after_combine : []; + } + + /** + * Get the inline JS excluded from combine JS + * + * @return array + */ + public function get_combine_js_excluded_inline(): array { + $lists = $this->providers['defaultlists']->data_manager->get_lists(); + + return isset( $lists->js_excluded_inline ) ? $lists->js_excluded_inline : []; + } + + /** + * Get the preload exclusions + * + * @return array + */ + public function get_preload_exclusions(): array { + $lists = $this->providers['defaultlists']->data_manager->get_lists(); + + return isset( $lists->preload_exclusions ) ? $lists->preload_exclusions : []; + } + + /** + * Get Delay JS dynamic list. + * + * @return array + */ + public function get_delayjs_list() { + return $this->providers['delayjslists']->data_manager->get_lists(); + } + + /** + * Get the JS minify excluded files + * + * @return array + */ + public function get_js_exclude_files(): array { + $lists = $this->providers['defaultlists']->data_manager->get_lists(); + + return isset( $lists->exclude_js_files ) ? $lists->exclude_js_files : []; + } + + /** + * Get the incompatible plugins list + * + * @return array + */ + public function get_incompatible_plugins() { + $lists = $this->providers['incompatible_plugins']->data_manager->get_plugins_list(); + + return isset( $lists ) ? $lists : []; + } + + /** + * Get the staging list + * + * @return array + */ + public function get_stagings(): array { + $lists = $this->providers['defaultlists']->data_manager->get_lists(); + + return isset( $lists->staging_domains ) ? $lists->staging_domains : []; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/IncompatiblePluginsLists/APIClient.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/IncompatiblePluginsLists/APIClient.php new file mode 100644 index 000000000..16bc6fe54 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/IncompatiblePluginsLists/APIClient.php @@ -0,0 +1,18 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists\IncompatiblePluginsLists; + +use WP_Rocket\Engine\Optimization\DynamicLists\AbstractAPIClient; + +class APIClient extends AbstractAPIClient { + + /** + * Specify API endpoint path. + * + * @return string + */ + protected function get_api_path() { + return 'incompatible-plugins/list'; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/IncompatiblePluginsLists/DataManager.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/IncompatiblePluginsLists/DataManager.php new file mode 100644 index 000000000..db5dad1d0 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/IncompatiblePluginsLists/DataManager.php @@ -0,0 +1,84 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists\IncompatiblePluginsLists; + +use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Engine\Optimization\DynamicLists\AbstractDataManager; + +class DataManager extends AbstractDataManager { + + /** + * Plugin options instance. + * + * @var Options_Data + */ + private $options; + + /** + * Instantiate the class. + * + * @param Options_Data $options Options instance. + */ + public function __construct( Options_Data $options ) { + parent::__construct(); + $this->options = $options; + } + /** + * Get cache transient name. + * + * @return string + */ + protected function get_cache_transient_name() { + return 'wpr_dynamic_lists_incompatible_plugins'; + } + + /** + * Get lists json filename. + * + * @return string + */ + protected function get_json_filename() { + return 'dynamic-lists-incompatible-plugins'; + } + + /** + * Gets the plugins list content + * + * @return array + */ + public function get_plugins_list() { + $lists = []; + $list_from_json = $this->get_lists(); + foreach ( $list_from_json as $conditions => $list ) { + if ( $this->meet_conditions( $conditions ) ) { + $list = array_column( $list, 'file', 'slug' ); + $lists = array_merge( $lists, $list ); + } + } + return $lists; + } + + /** + * Check if the condition is meet based on plugin option and condition string. + * If $conditions contain "||" split and treat it like or + * + * @param string $conditions condition. + * + * @return bool + */ + private function meet_conditions( $conditions = '' ) { + if ( empty( $conditions ) ) { + return true; + } + + $conditions = explode( '||', $conditions ); + + foreach ( $conditions as $condition ) { + if ( $this->options->get( trim( $condition ), false ) ) { + return true; + } + } + return false; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/ServiceProvider.php new file mode 100644 index 000000000..1b9fff093 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/ServiceProvider.php @@ -0,0 +1,98 @@ +<?php + +namespace WP_Rocket\Engine\Optimization\DynamicLists; + +use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider; +use WP_Rocket\Engine\Optimization\DynamicLists\DefaultLists\{ + APIClient as DefaultListsAPIClient, + DataManager as DefaultListsDataManager +}; +use WP_Rocket\Engine\Optimization\DynamicLists\DelayJSLists\{ + APIClient as DelayJSListsAPIClient, + DataManager as DelayJSListsDataManager +}; +use WP_Rocket\Engine\Optimization\DynamicLists\IncompatiblePluginsLists\{ + APIClient as IncompatiblePluginsListsAPIClient, + DataManager as IncompatiblePluginsListsDataManager +}; + +/** + * Service provider for the WP Rocket DynamicLists + */ +class ServiceProvider extends AbstractServiceProvider { + /** + * Array of services provided by this service provider + * + * @var array + */ + protected $provides = [ + 'dynamic_lists_defaultlists_data_manager', + 'dynamic_lists_defaultlists_api_client', + 'dynamic_lists_delayjslists_data_manager', + 'dynamic_lists_delayjslists_api_client', + 'dynamic_lists_incompatible_plugins_lists_data_manager', + 'dynamic_lists_incompatible_plugins_lists_api_client', + 'dynamic_lists', + 'dynamic_lists_subscriber', + ]; + + /** + * Check if the service provider provides a specific service. + * + * @param string $id The id of the service. + * + * @return bool + */ + public function provides( string $id ): bool { + return in_array( $id, $this->provides, true ); + } + + /** + * Registers the option array in the container + * + * @return void + */ + public function register(): void { + $this->getContainer()->add( 'dynamic_lists_defaultlists_data_manager', DefaultListsDataManager::class ); + $this->getContainer()->add( 'dynamic_lists_defaultlists_api_client', DefaultListsAPIClient::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + $this->getContainer()->add( 'dynamic_lists_delayjslists_data_manager', DelayJSListsDataManager::class ); + $this->getContainer()->add( 'dynamic_lists_delayjslists_api_client', DelayJSListsAPIClient::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + $this->getContainer()->add( 'dynamic_lists_incompatible_plugins_lists_data_manager', IncompatiblePluginsListsDataManager::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + $this->getContainer()->add( 'dynamic_lists_incompatible_plugins_lists_api_client', IncompatiblePluginsListsAPIClient::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + + $providers = [ + 'defaultlists' => + (object) [ + 'api_client' => $this->getContainer()->get( 'dynamic_lists_defaultlists_api_client' ), + 'data_manager' => $this->getContainer()->get( 'dynamic_lists_defaultlists_data_manager' ), + 'title' => __( 'Default Lists', 'rocket' ), + ], + 'delayjslists' => + (object) [ + 'api_client' => $this->getContainer()->get( 'dynamic_lists_delayjslists_api_client' ), + 'data_manager' => $this->getContainer()->get( 'dynamic_lists_delayjslists_data_manager' ), + 'title' => __( 'Delay JavaScript Execution Exclusion Lists', 'rocket' ), + ], + 'incompatible_plugins' => + (object) [ + 'api_client' => $this->getContainer()->get( 'dynamic_lists_incompatible_plugins_lists_api_client' ), + 'data_manager' => $this->getContainer()->get( 'dynamic_lists_incompatible_plugins_lists_data_manager' ), + 'title' => __( 'Incompatible plugins Lists', 'rocket' ), + 'clear_cache' => false, + ], + ]; + + $this->getContainer()->add( 'dynamic_lists', DynamicLists::class ) + ->addArgument( $providers ) + ->addArgument( $this->getContainer()->get( 'user' ) ) + ->addArgument( $this->getContainer()->get( 'template_path' ) ) + ->addArgument( $this->getContainer()->get( 'beacon' ) ); + + $this->getContainer()->addShared( 'dynamic_lists_subscriber', Subscriber::class ) + ->addArgument( $this->getContainer()->get( 'dynamic_lists' ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/Subscriber.php new file mode 100644 index 000000000..7b1f81525 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/DynamicLists/Subscriber.php @@ -0,0 +1,216 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\DynamicLists; + +use WP_Rocket\Event_Management\Subscriber_Interface; + +class Subscriber implements Subscriber_Interface { + /** + * DynamicLists instance + * + * @var DynamicLists + */ + private $dynamic_lists; + + /** + * Instantiate the class + * + * @param DynamicLists $dynamic_lists DynamicLists instance. + */ + public function __construct( DynamicLists $dynamic_lists ) { + $this->dynamic_lists = $dynamic_lists; + } + + /** + * Events this subscriber listens to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'rest_api_init' => 'register_rest_route', + 'rocket_localize_admin_script' => [ 'add_dynamic_lists_script', 11 ], + 'init' => 'schedule_lists_update', + 'rocket_update_dynamic_lists' => 'update_lists', + 'rocket_deactivation' => 'clear_schedule_lists_update', + 'rocket_settings_tools_content' => 'display_update_lists_section', + 'rocket_cache_ignored_parameters' => 'add_cache_ignored_parameters', + 'rocket_minify_excluded_external_js' => 'add_minify_excluded_external_js', + 'rocket_move_after_combine_js' => 'add_move_after_combine_js', + 'rocket_excluded_inline_js_content' => 'add_combine_js_excluded_inline', + 'rocket_preload_exclude_urls' => 'add_preload_exclusions', + 'rocket_exclude_js' => 'add_js_exclude_files', + 'rocket_plugins_to_deactivate' => 'add_incompatible_plugins_to_deactivate', + 'rocket_staging_list' => 'add_staging_exclusions', + ]; + } + + /** + * Registers the REST dynamic lists update route + * + * @return void + */ + public function register_rest_route() { + $this->dynamic_lists->register_rest_route(); + } + + /** + * Add REST data to our localize script data. + * + * @param array $data Localize script data. + * @return array + */ + public function add_dynamic_lists_script( $data ) { + $data['rest_url'] = rest_url( 'wp-rocket/v1/dynamic_lists/update/' ); + $data['rest_nonce'] = wp_create_nonce( 'wp_rest' ); + + return $data; + } + + /** + * Scheduling the dynamic lists update cron event. + */ + public function schedule_lists_update() { + $this->dynamic_lists->schedule_lists_update(); + } + + /** + * Clear the dynamic lists update cron event. + * + * @return void + */ + public function clear_schedule_lists_update() { + $this->dynamic_lists->clear_schedule_lists_update(); + } + + /** + * Update dynamic lists from API. + * + * * @return void + */ + public function update_lists() { + $this->dynamic_lists->update_lists_from_remote(); + } + + /** + * Displays the dynamic lists update section on tools tab + * + * @return void + */ + public function display_update_lists_section() { + $this->dynamic_lists->display_update_lists_section(); + } + + /** + * Add the cached ignored parameters to the array + * + * @param string $params Array of ignored parameters. + * + * @return array + */ + public function add_cache_ignored_parameters( $params = [] ): array { + if ( ! is_array( $params ) ) { + $params = (array) $params; + } + + return array_merge( $params, $this->dynamic_lists->get_cache_ignored_parameters() ); + } + + /** + * Add the excluded external JS patterns to the array + * + * @param string $excluded Array of excluded patterns. + * + * @return array + */ + public function add_minify_excluded_external_js( $excluded = [] ): array { + if ( ! is_array( $excluded ) ) { + $excluded = (array) $excluded; + } + + return array_merge( $excluded, $this->dynamic_lists->get_js_minify_excluded_external() ); + } + + /** + * Add the JS patterns to move after the combine JS file to the array + * + * @param string $excluded Array of patterns to move. + * + * @return array + */ + public function add_move_after_combine_js( $excluded = [] ): array { + if ( ! is_array( $excluded ) ) { + $excluded = (array) $excluded; + } + + return array_merge( $excluded, $this->dynamic_lists->get_js_move_after_combine() ); + } + + /** + * Add the excluded inline JS patterns to the array + * + * @param string $excluded Array of excluded patterns. + * + * @return array + */ + public function add_combine_js_excluded_inline( $excluded = [] ): array { + if ( ! is_array( $excluded ) ) { + $excluded = (array) $excluded; + } + + return array_merge( $excluded, $this->dynamic_lists->get_combine_js_excluded_inline() ); + } + + /** + * Add the preload exclusions to the array + * + * @param array $excluded Array of ignored URL regex. + * + * @return array + */ + public function add_preload_exclusions( $excluded = [] ): array { + if ( ! is_array( $excluded ) ) { + $excluded = (array) $excluded; + } + + return array_merge( $excluded, $this->dynamic_lists->get_preload_exclusions() ); + } + + /** + * Add the js files exclusions to the array + * + * @param array $js_files Array of files. + * + * @return array + */ + public function add_js_exclude_files( $js_files = [] ): array { + if ( ! is_array( $js_files ) ) { + $js_files = (array) $js_files; + } + + return array_merge( $js_files, $this->dynamic_lists->get_js_exclude_files() ); + } + + /** + * Add incompatible plugins to the array + * + * @param array $plugins Array of $plugins. + * + * @return array + */ + public function add_incompatible_plugins_to_deactivate( $plugins = [] ): array { + return array_merge( (array) $plugins, $this->dynamic_lists->get_incompatible_plugins() ); + } + + /** + * Add the staging exclusions to the array + * + * @param array $stagings Array of staging urls. + * + * @return array + */ + public function add_staging_exclusions( $stagings = [] ): array { + return array_merge( (array) $stagings, (array) $this->dynamic_lists->get_stagings() ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/AbstractGFOptimization.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/AbstractGFOptimization.php index ee79de6f0..bb945d1f8 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/AbstractGFOptimization.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/AbstractGFOptimization.php @@ -1,18 +1,14 @@ <?php - -declare( strict_types=1 ); +declare(strict_types=1); namespace WP_Rocket\Engine\Optimization\GoogleFonts; -use WP_Rocket\Engine\Optimization\AbstractOptimization; - /** * Abstract Optimization Parent Class for Google Fonts Optimizers. * * @since 3.8 */ -abstract class AbstractGFOptimization extends AbstractOptimization { - +abstract class AbstractGFOptimization { /** * Allowed display values. * @@ -28,6 +24,35 @@ abstract class AbstractGFOptimization extends AbstractOptimization { 'optional' => 1, ]; + /** + * Flag for whether google fonts have been detected (Default: true) + * + * @since 3.8.8 + * + * @var bool + */ + protected $has_google_fonts = true; + + /** + * Optimize Google Fonts + * + * @param string $html HTML content. + * + * @return string + */ + abstract public function optimize( $html ): string; + + /** + * Check whether the optimizer has found google fonts on the page. + * + * @since 3.8.8 + * + * @return bool Will default to true when extending classes have not set via the optimize() method. + */ + public function has_google_fonts() { + return $this->has_google_fonts; + } + /** * Returns font with display value. * @@ -46,11 +71,10 @@ protected function get_font_with_display( array $font ) { return $font[0]; } - $display = $this->get_font_display_value(); $parsed_font = wp_parse_args( $query ); $font_url = ! empty( $parsed_font['display'] ) - ? str_replace( "&display={$parsed_font['display']}", "&display={$display}", $font_url ) - : "{$font_url}&display={$display}"; + ? str_replace( "&display={$parsed_font['display']}", '&display=swap', $font_url ) + : "{$font_url}&display=swap"; return str_replace( $font['url'], esc_url( $font_url ), $font[0] ); } @@ -80,4 +104,20 @@ protected function get_font_display_value(): string { return isset( $this->display_values[ $display ] ) ? $display : 'swap'; } + + /** + * Returns the optimized markup for Google Fonts + * + * @since 3.9.1 + * + * @param string $url Google Fonts URL. + * + * @return string + */ + protected function get_optimized_markup( string $url ): string { + return sprintf( + '<link rel="preload" as="style" href="%1$s" /><link rel="stylesheet" href="%1$s" media="print" onload="this.media=\'all\'" /><noscript><link rel="stylesheet" href="%1$s" /></noscript>', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet + $url + ); + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/Combine.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/Combine.php index 6dda5e82a..1e96d636b 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/Combine.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/Combine.php @@ -1,7 +1,9 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\Optimization\GoogleFonts; +use WP_Rocket\Engine\Optimization\RegexTrait; use WP_Rocket\Logger\Logger; /** @@ -10,11 +12,12 @@ * @since 3.1 */ class Combine extends AbstractGFOptimization { + use RegexTrait; + /** * Found fonts * - * @since 3.1 - * @author Remy Perona + * @since 3.1 * * @var string */ @@ -23,8 +26,7 @@ class Combine extends AbstractGFOptimization { /** * Found subsets * - * @since 3.1 - * @author Remy Perona + * @since 3.1 * * @var string */ @@ -34,13 +36,12 @@ class Combine extends AbstractGFOptimization { * Combines multiple Google Fonts links into one * * @since 3.1 - * @author Remy Perona * * @param string $html HTML content. * * @return string */ - public function optimize( $html ) { + public function optimize( $html ): string { Logger::info( 'GOOGLE FONTS COMBINE PROCESS STARTED.', [ 'GF combine process' ] ); $html_nocomments = $this->hide_comments( $html ); @@ -49,9 +50,13 @@ public function optimize( $html ) { if ( ! $fonts ) { Logger::debug( 'No Google Fonts found.', [ 'GF combine process' ] ); + $this->has_google_fonts = false; + return $html; } + $this->has_google_fonts = true; + $num_fonts = count( $fonts ); Logger::debug( @@ -62,10 +67,6 @@ public function optimize( $html ) { ] ); - if ( 1 === $num_fonts ) { - return str_replace( $fonts[0][0], $this->get_font_with_display( $fonts[0] ), $html ); - } - $this->parse( $fonts ); if ( empty( $this->fonts ) ) { @@ -74,7 +75,7 @@ public function optimize( $html ) { return $html; } - $html = preg_replace( '@<\/title>@i', '$0' . $this->get_combine_tag(), $html, 1 ); + $html = preg_replace( '@<\/title>@i', '$0' . $this->get_optimized_markup( $this->get_combined_url() ), $html, 1 ); foreach ( $fonts as $font ) { $html = str_replace( $font[0], '', $html ); @@ -95,7 +96,6 @@ public function optimize( $html ) { * Parses found matches to extract fonts and subsets. * * @since 3.1 - * @author Remy Perona * * @param array $matches Found matches for the pattern. * @@ -132,20 +132,15 @@ private function parse( array $matches ) { } /** - * Returns the combined Google fonts link tag + * Returns the combined Google fonts URL * - * @since 3.3.5 Add support for the display parameter - * @since 3.1 - * @author Remy Perona + * @since 3.9.1 * * @return string */ - private function get_combine_tag() { + private function get_combined_url(): string { $display = $this->get_font_display_value(); - return sprintf( - '<link rel="stylesheet" href="%s" />', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet - esc_url( "https://fonts.googleapis.com/css?family={$this->fonts}{$this->subsets}&display={$display}" ) - ); + return esc_url( "https://fonts.googleapis.com/css?family={$this->fonts}{$this->subsets}&display={$display}" ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/CombineV2.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/CombineV2.php index a04e4e8ed..faec84ebc 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/CombineV2.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/CombineV2.php @@ -1,9 +1,9 @@ <?php - -declare( strict_types=1 ); +declare(strict_types=1); namespace WP_Rocket\Engine\Optimization\GoogleFonts; +use WP_Rocket\Engine\Optimization\RegexTrait; use WP_Rocket\Logger\Logger; /** @@ -12,21 +12,7 @@ * @since 3.8 */ class CombineV2 extends AbstractGFOptimization { - - /** - * Allowed display values. - * - * @since 3.8 - * - * @var array - */ - protected $display_values = [ - 'auto' => 1, - 'block' => 1, - 'swap' => 1, - 'fallback' => 1, - 'optional' => 1, - ]; + use RegexTrait; /** * Combines multiple Google Fonts (API v2) links into one @@ -37,7 +23,7 @@ class CombineV2 extends AbstractGFOptimization { * * @return string */ - public function optimize( string $html ): string { + public function optimize( $html ): string { Logger::info( 'GOOGLE FONTS COMBINE-V2 PROCESS STARTED.', [ 'GF combine process' ] ); $processed_tags = []; @@ -46,9 +32,14 @@ public function optimize( string $html ): string { if ( ! $font_tags ) { Logger::debug( 'No v2 Google Fonts found.', [ 'GF combine process' ] ); + + $this->has_google_fonts = false; + return $html; } + $this->has_google_fonts = true; + $num_tags = count( $font_tags ); Logger::debug( @@ -59,10 +50,6 @@ public function optimize( string $html ): string { ] ); - if ( 1 === $num_tags ) { - return str_replace( $font_tags[0][0], $this->get_font_with_display( $font_tags[0] ), $html ); - } - $families = []; foreach ( $font_tags as $tag ) { $parsed_families = $this->parse( $tag ); @@ -78,7 +65,7 @@ public function optimize( string $html ): string { } $families = array_unique( $families ); - $combined_tag = $this->get_combine_tag( $families ); + $combined_tag = $this->get_optimized_markup( $this->get_combined_url( $families ) ); $html = preg_replace( '@<\/title>@i', '$0' . $combined_tag, $html, 1 ); foreach ( $processed_tags as $font ) { @@ -100,16 +87,18 @@ public function optimize( string $html ): string { * Parses found matches to extract fonts and subsets. * * @since 3.8 + * * @param array $tag A Google Font v2 url. + * * @return array */ - protected function parse( array $tag ) { + private function parse( array $tag ): array { if ( false !== strpos( $tag['url'], 'text=' ) ) { Logger::debug( 'GOOGLEFONTS V2 COMBINE: ' . $tag['url'] . ' SKIPPED TO PRESERVE "text" ATTRIBUTE.' ); return []; } - $url_pattern = '#^(family=[A-Za-z0-9;:,=%&\+\@\.]+)$#'; + $url_pattern = '#(family=[A-Za-z0-9;:,=%&\+\@\.]+)$#'; $display_pattern = '#&display=(?:swap|auto|block|fallback|optional)#'; $decoded_url = html_entity_decode( $tag['url'] ); $query = wp_parse_url( $decoded_url, PHP_URL_QUERY ); @@ -132,28 +121,30 @@ protected function parse( array $tag ) { /** - * Returns the combined Google fonts link tag. + * Returns the combined Google fonts URL + * + * @since 3.9.1 * - * @since 3.8 * @param array $families Array with all Google V2 families. + * * @return string */ - protected function get_combine_tag( array $families ): string { + private function get_combined_url( array $families ): string { $display = $this->get_font_display_value(); - return sprintf( - '<link rel="stylesheet" href="%s" />', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet - esc_url( "https://fonts.googleapis.com/css2{$this->get_concatenated_families( $families )}&display={$display}" ) - ); + + return esc_url( "https://fonts.googleapis.com/css2{$this->get_concatenated_families( $families )}&display={$display}" ); } /** * Get a string of the concatenated font family queries. * * @since 3.8 + * * @param array $families Array with all Google V2 families. + * * @return string */ - protected function get_concatenated_families( array $families ): string { + private function get_concatenated_families( array $families ): string { $families_string = '?'; foreach ( $families as $family ) { $families_string .= $family . '&'; diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/Subscriber.php index f5111e0b3..78b79864b 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/GoogleFonts/Subscriber.php @@ -54,7 +54,7 @@ public function __construct( AbstractGFOptimization $combine, AbstractGFOptimiza public static function get_subscribed_events() { return [ 'wp_resource_hints' => [ 'preconnect', 10, 2 ], - 'rocket_buffer' => [ 'process', 18 ], + 'rocket_buffer' => [ 'process', 1001 ], ]; } @@ -101,7 +101,13 @@ public function process( $html ) { // Combine Google Font API V2. $html = $this->combine_v2->optimize( $html ); // Combine Google Font API V1. - return $this->combine->optimize( $html ); + $html = $this->combine->optimize( $html ); + + if ( ! $this->combine->has_google_fonts() && ! $this->combine_v2->has_google_fonts() ) { + $html = preg_replace( '/<link\s+(?:[^>]+[\s"\'])?href\s*=\s*[\'"]https:\/\/fonts\.gstatic\.com[\'"](?:[^>]+[\s"\'])?\s?\/?>/', '', $html ); + } + + return $html; } /** @@ -114,6 +120,10 @@ protected function is_allowed() { return false; } - return (bool) $this->options->get( 'minify_google_fonts', 0 ); + if ( ! $this->options->get( 'minify_google_fonts', 0 ) ) { + return false; + } + + return ! is_user_logged_in() || (bool) $this->options->get( 'cache_logged_user', 0 ); } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/AbstractMinifySubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/AbstractMinifySubscriber.php index 7aa0ef832..a6cd349a8 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/AbstractMinifySubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/AbstractMinifySubscriber.php @@ -128,6 +128,17 @@ public function i18n_multidomain_url( $url ) { return $url; } - return str_replace( $url_host, sanitize_text_field( $_SERVER['HTTP_HOST'] ), $url ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash + return preg_replace( '/' . preg_quote( $url_host, '/' ) . '/', sanitize_text_field( $_SERVER['HTTP_HOST'] ), $url, 1 ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash + } + + /** + * Returns an array of CDN zones for CSS files. + * + * @since 3.1 + * + * @return array + */ + public function get_zones() { + return []; } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/AdminSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/AdminSubscriber.php new file mode 100644 index 000000000..1c466e9cb --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/AdminSubscriber.php @@ -0,0 +1,68 @@ +<?php +declare(strict_types=1); + +namespace WP_Rocket\Engine\Optimization\Minify; + +use WP_Rocket\Admin\Options_Data; +use WP_Rocket\Event_Management\Subscriber_Interface; + +class AdminSubscriber implements Subscriber_Interface { + /** + * WP Rocket Options + * + * @var Options_Data + */ + private $options; + + /** + * Instantiate the class + * + * @param Options_Data $options WP Rocket Options Instance. + */ + public function __construct( Options_Data $options ) { + $this->options = $options; + } + + /** + * Return an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'switch_theme' => 'clean_minify_all', + 'rocket_meta_boxes_fields' => [ 'add_meta_box', 4 ], + ]; + } + + /** + * Delete all minified cache files + * + * @return void + */ + public function clean_minify_all() { + // Bail out if minify_js or minify_css is not enabled. + if ( + ! (bool) $this->options->get( 'minify_js', 0 ) + && + ! (bool) $this->options->get( 'minify_css', 0 ) + ) { + return; + } + + // Delete all minify cache files. + rocket_clean_minify(); + } + + /** + * Add the field to the WP Rocket metabox on the post edit page. + * + * @param string[] $fields Metaboxes fields. + * + * @return string[] + */ + public function add_meta_box( array $fields ) { + $fields['minify_js'] = __( 'Minify/combine JavaScript', 'rocket' ); + return $fields; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/AbstractCSSOptimization.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/AbstractCSSOptimization.php index 0aeed8bb9..7cc85986f 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/AbstractCSSOptimization.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/AbstractCSSOptimization.php @@ -126,8 +126,8 @@ protected function is_minify_excluded_file( array $tag ) { } $file = wp_parse_url( $tag['url'] ); - $file_path = isset( $file['path'] ) ? $file['path'] : null; - $host = isset( $file['host'] ) ? $file['host'] : null; + $file_path = isset( $file['path'] ) ? $file['path'] : ''; + $host = isset( $file['host'] ) ? $file['host'] : ''; // File extension is not css. if ( pathinfo( $file_path, PATHINFO_EXTENSION ) !== self::FILE_TYPE ) { @@ -151,5 +151,4 @@ protected function is_minify_excluded_file( array $tag ) { return false; } - } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/AdminSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/AdminSubscriber.php index eab9e52dd..8cfdb64be 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/AdminSubscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/AdminSubscriber.php @@ -1,14 +1,10 @@ <?php +declare(strict_types=1); namespace WP_Rocket\Engine\Optimization\Minify\CSS; use WP_Rocket\Event_Management\Subscriber_Interface; -/** - * Minify/Combine CSS Admin subscriber - * - * @since 3.5.4 - */ class AdminSubscriber implements Subscriber_Interface { /** * Return an array of events that this subscriber wants to listen to. @@ -23,6 +19,8 @@ public static function get_subscribed_events() { return [ "update_option_{$slug}" => [ 'clean_minify', 10, 2 ], "pre_update_option_{$slug}" => [ 'regenerate_minify_css_key', 10, 2 ], + 'wp_rocket_upgrade' => [ 'on_update', 16, 2 ], + 'rocket_meta_boxes_fields' => [ 'add_meta_box', 1 ], ]; } @@ -33,8 +31,10 @@ public static function get_subscribed_events() { * * @param array $old An array of previous settings. * @param array $new An array of submitted settings. + * + * @return void */ - public function clean_minify( $old, $new ) { + public function clean_minify( $old, $new ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.newFound if ( ! is_array( $old ) || ! is_array( $new ) ) { return; } @@ -56,7 +56,7 @@ public function clean_minify( $old, $new ) { * * @return array Updates 'minify_css_key' setting when regenerated; else, original submitted settings. */ - public function regenerate_minify_css_key( $new, $old ) { + public function regenerate_minify_css_key( $new, $old ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.newFound if ( ! is_array( $old ) || ! is_array( $new ) ) { return $new; } @@ -80,7 +80,7 @@ public function regenerate_minify_css_key( $new, $old ) { * * @return bool true when should regenerate; else false. */ - protected function maybe_minify_regenerate( array $new, array $old ) { + protected function maybe_minify_regenerate( array $new, array $old ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.newFound $settings_to_check = [ 'minify_css', 'exclude_css', @@ -113,13 +113,42 @@ protected function maybe_minify_regenerate( array $new, array $old ) { * * @return bool */ - protected function did_setting_change( $setting, array $new, array $old ) { + protected function did_setting_change( $setting, array $new, array $old ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.newFound return ( array_key_exists( $setting, $old ) && array_key_exists( $setting, $new ) && - $old[ $setting ] !== $new[ $setting ] + // phpcs:ignore Universal.Operators.StrictComparisons.LooseNotEqual + $old[ $setting ] != $new[ $setting ] ); } + + /** + * Clean cache on update. + * + * @param string $new_version new version from the plugin. + * @param string $old_version old version from the plugin. + * + * @return void + */ + public function on_update( $new_version, $old_version ) { + if ( version_compare( $old_version, '3.15', '>=' ) ) { + return; + } + rocket_clean_domain(); + } + + /** + * Add the field to the WP Rocket metabox on the post edit page. + * + * @param string[] $fields Metaboxes fields. + * + * @return string[] + */ + public function add_meta_box( array $fields ) { + $fields['minify_css'] = __( 'Minify CSS', 'rocket' ); + + return $fields; + } } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Combine.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Combine.php deleted file mode 100644 index 1febe881d..000000000 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Combine.php +++ /dev/null @@ -1,336 +0,0 @@ -<?php -namespace WP_Rocket\Engine\Optimization\Minify\CSS; - -use WP_Rocket\Dependencies\Minify\CSS as MinifyCSS; -use WP_Rocket\Engine\Optimization\CSSTrait; -use WP_Rocket\Engine\Optimization\Minify\ProcessorInterface; -use WP_Rocket\Logger\Logger; - -/** - * Minify & Combine CSS files - * - * @since 3.1 - */ -class Combine extends AbstractCSSOptimization implements ProcessorInterface { - use CSSTrait; - - /** - * Array of styles - * - * @var array - */ - private $styles = []; - - /** - * Combined CSS filename - * - * @var string - */ - private $filename; - - /** - * Minifies and combines all CSS files into one - * - * @since 3.1 - * - * @param string $html HTML content. - * @return string - */ - public function optimize( $html ) { - Logger::info( 'CSS COMBINE PROCESS STARTED.', [ 'css combine process' ] ); - - $html_nocomments = $this->hide_comments( $html ); - $styles = $this->find( '<link\s+([^>]+[\s"\'])?href\s*=\s*[\'"]\s*?(?<url>[^\'"]+\.css(?:\?[^\'"]*)?)\s*?[\'"]([^>]+)?\/?>', $html_nocomments ); - - if ( ! $styles ) { - Logger::debug( 'No `<link>` tags found.', [ 'css combine process' ] ); - return $html; - } - - Logger::debug( - 'Found ' . count( $styles ) . ' `<link>` tag(s).', - [ - 'css combine process', - 'tags' => $styles, - ] - ); - - $styles = $this->parse( $styles ); - - if ( empty( $styles ) ) { - Logger::debug( 'No `<link>` tags to optimize.', [ 'css combine process' ] ); - return $html; - } - - Logger::debug( - count( $styles ) . ' `<link>` tag(s) remaining.', - [ - 'css combine process', - 'tags' => $styles, - ] - ); - - if ( ! $this->combine() ) { - Logger::error( 'CSS combine process failed.', [ 'css combine process' ] ); - return $html; - } - - return $this->insert_combined_css( $html ); - } - - /** - * Parses all found styles tag to keep only the ones to combine - * - * @since 3.7 - * - * @param array $styles Array of matched styles. - * @return array - */ - private function parse( array $styles ) { - foreach ( $styles as $key => $style ) { - if ( $this->is_combine_excluded_media( $style[0] ) ) { - Logger::debug( - 'Style is excluded due to media attribute.', - [ - 'css combine process', - 'tag' => $style[0], - ] - ); - - continue; - } - - if ( $this->is_external_file( $style['url'] ) ) { - if ( $this->is_excluded_external( $style['url'] ) ) { - unset( $styles[ $key ] ); - - continue; - } - - $this->styles[ $style['url'] ] = [ - 'type' => 'external', - 'tag' => $style[0], - 'url' => rocket_add_url_protocol( strtok( $style['url'], '?' ) ), - ]; - - continue; - } - - if ( $this->is_minify_excluded_file( $style ) ) { - Logger::debug( - 'Style is excluded.', - [ - 'css combine process', - 'tag' => $style[0], - ] - ); - - unset( $styles[ $key ] ); - - continue; - } - - $this->styles[ $style['url'] ] = [ - 'type' => 'internal', - 'tag' => $style[0], - 'url' => strtok( $style['url'], '?' ), - ]; - } - - return $styles; - } - - /** - * Checks if the provided external URL is excluded from combine - * - * @since 3.7 - * - * @param array $url External URL to check. - * @return boolean - */ - private function is_excluded_external( $url ) { - foreach ( $this->get_excluded_externals() as $excluded ) { - if ( false !== strpos( $url, $excluded ) ) { - Logger::debug( - 'Style is external.', - [ - 'css combine process', - 'url' => $url, - ] - ); - return true; - } - } - - return false; - } - - /** - * Gets external URLs excluded from combine - * - * @since 3.7 - * - * @return array - */ - private function get_excluded_externals() { - /** - * Filters CSS external URLs to exclude from the combine process - * - * @since 3.7 - * - * @param array $pattern Patterns to match. - */ - $excluded_externals = (array) apply_filters( 'rocket_combine_css_excluded_external', [] ); - - return array_merge( $excluded_externals, $this->options->get( 'exclude_css', [] ) ); - } - - /** - * Combine the CSS content into one file and save it - * - * @since 3.1 - * - * @return bool True if successful, false otherwise - */ - protected function combine() { - if ( empty( $this->styles ) ) { - return false; - } - - $file_hash = implode( ',', array_column( $this->styles, 'url' ) ); - $this->filename = md5( $file_hash . $this->minify_key ) . '.css'; - - $combined_file = $this->minify_base_path . $this->filename; - - if ( rocket_direct_filesystem()->exists( $combined_file ) ) { - Logger::debug( - 'Combined CSS file already exists.', - [ - 'css combine process', - 'path' => $combined_file, - ] - ); - - return true; - } - - $combined_content = $this->get_content( $combined_file ); - $combined_content = $this->apply_font_display_swap( $combined_content ); - - if ( empty( $combined_content ) ) { - Logger::error( - 'No combined content.', - [ - 'css combine process', - 'path' => $combined_file, - ] - ); - return false; - } - - if ( ! $this->write_file( $combined_content, $combined_file ) ) { - Logger::error( - 'Combined CSS file could not be created.', - [ - 'css combine process', - 'path' => $combined_file, - ] - ); - return false; - } - - Logger::debug( - 'Combined CSS file successfully created.', - [ - 'css combine process', - 'path' => $combined_file, - ] - ); - - return true; - } - - /** - * Insert the combined CSS file and remove the original CSS tags - * - * The combined CSS file is added after the closing tag, and the replacement occurs only once. The original CSS tags are then removed from the HTML. - * - * @since 3.3.3 - * - * @param string $html HTML content. - * @return string - */ - protected function insert_combined_css( $html ) { - foreach ( $this->styles as $style ) { - $html = str_replace( $style['tag'], '', $html ); - } - - $minify_url = $this->get_minify_url( $this->filename ); - - Logger::info( - 'Combined CSS file successfully added.', - [ - 'css combine process', - 'url' => $minify_url, - ] - ); - - // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet - return preg_replace( '/<\/title>/i', '$0', $html, 1 ); - } - - /** - * Gathers the content from all styles to combine & minify it if needed - * - * @since 3.7 - * - * @param string $combined_file Absolute path to the combined file. - * @return string - */ - private function get_content( $combined_file ) { - $minifier = new MinifyCSS(); - - foreach ( $this->styles as $key => $style ) { - if ( 'internal' === $style['type'] ) { - $filepath = $this->get_file_path( $style['url'] ); - $file_content = $this->get_file_content( $filepath ); - $file_content = $this->rewrite_paths( $filepath, $combined_file, $file_content ); - } elseif ( 'external' === $style['type'] ) { - $file_content = $this->local_cache->get_content( $style['url'] ); - $file_content = $this->rewrite_paths( $style['url'], $combined_file, $file_content ); - } - - if ( empty( $file_content ) ) { - unset( $this->styles[ $key ] ); - - continue; - } - - $minifier->add( $file_content ); - } - - $content = $minifier->minify(); - - if ( empty( $content ) ) { - Logger::debug( 'No CSS content.', [ 'css combine process' ] ); - } - - return $content; - } - - /** - * Check if media query is valid to be excluded from combine or not. - * - * @since 3.8 - * - * @param string $tag Stylesheet HTML tag. - * @return bool Ture if it's excluded else false. - */ - private function is_combine_excluded_media( $tag ) { - return ( - false !== strpos( $tag, 'media=' ) - && - ! preg_match( '/media=["\'](?:\s*|[^"\']*?\b(?:\s*?,\s*?)?(all|screen)(?:\s*?,\s*?[^"\']*)?)["\']/i', $tag ) - ); - } -} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Minify.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Minify.php index 7a521f13c..69431919e 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Minify.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Minify.php @@ -135,10 +135,8 @@ private function replace_url( $url ) { $url = rocket_add_url_protocol( $url ); } - $unique_id = md5( $url . $this->minify_key ); - $filename = preg_replace( '/\.(css)$/', '-' . $unique_id . '.css', ltrim( rocket_realpath( $parsed_url['path'] ), '/' ) ); + $filename = ltrim( rocket_realpath( $parsed_url['path'] ), '/' ); $minified_file = rawurldecode( $this->minify_base_path . $filename ); - $minify_url = $this->get_minify_url( $filename, $url ); if ( rocket_direct_filesystem()->exists( $minified_file ) ) { Logger::debug( @@ -149,7 +147,7 @@ private function replace_url( $url ) { ] ); - return $minify_url; + return $this->get_full_minified_url( $minified_file, $this->get_minify_url( $filename, $url ) ); } $external_url = $this->is_external_file( $url ); @@ -199,7 +197,7 @@ private function replace_url( $url ) { return false; } - return $minify_url; + return $this->get_full_minified_url( $minified_file, $this->get_minify_url( $filename, $url ) ); } /** @@ -322,10 +320,10 @@ protected function minify( $file_path, $minified_file, $file_content ) { ] ); - return ''; + return ''; // phpcs:ignore Universal.CodeAnalysis.ConstructorDestructorReturn.ReturnValueFound } - return $minified_content; + return $minified_content; // phpcs:ignore Universal.CodeAnalysis.ConstructorDestructorReturn.ReturnValueFound } /** diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Subscriber.php index 34c77958e..d5418443b 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/CSS/Subscriber.php @@ -44,9 +44,7 @@ public function process( $html ) { $assets_local_cache = new AssetsLocalCache( rocket_get_constant( 'WP_ROCKET_MINIFY_CACHE_PATH' ), $this->filesystem ); - if ( $this->options->get( 'minify_css' ) && $this->options->get( 'minify_concatenate_css' ) ) { - $this->set_processor_type( new Combine( $this->options, $assets_local_cache ) ); - } elseif ( $this->options->get( 'minify_css' ) && ! $this->options->get( 'minify_concatenate_css' ) ) { + if ( $this->options->get( 'minify_css' ) ) { $this->set_processor_type( new Minify( $this->options, $assets_local_cache ) ); } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/AbstractJSOptimization.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/AbstractJSOptimization.php index ce09f1c79..e2ea2f21f 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/AbstractJSOptimization.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/AbstractJSOptimization.php @@ -47,8 +47,7 @@ public function __construct( Options_Data $options, AssetsLocalCache $local_cach * @return string A list of files to exclude, ready to be used in a regex pattern. */ protected function get_excluded_files() { - $excluded_files = $this->options->get( 'exclude_js', [] ); - $excluded_files[] = '/wp-includes/js/dist/i18n.min.js'; + $excluded_files = $this->options->get( 'exclude_js', [] ); /** * Filter JS files to exclude from minification/concatenation. @@ -154,91 +153,7 @@ protected function get_minify_url( $filename, $original_url = '' ) { * @return array */ protected function get_excluded_external_file_path() { - $defaults = [ - 'html5.js', - 'show_ads.js', - 'histats.com/js', - 'ws.amazon.com/widgets', - '/ads/', - 'intensedebate.com', - 'scripts.chitika.net/', - 'jotform.com/', - 'gist.github.com', - 'forms.aweber.com', - 'video.unrulymedia.com', - 'stats.wp.com', - 'stats.wordpress.com', - 'widget.rafflecopter.com', - 'widget-prime.rafflecopter.com', - 'releases.flowplayer.org', - 'c.ad6media.fr', - 'cdn.stickyadstv.com', - 'www.smava.de', - 'contextual.media.net', - 'app.getresponse.com', - 'adserver.reklamstore.com', - 's0.wp.com', - 'wprp.zemanta.com', - 'files.bannersnack.com', - 'smarticon.geotrust.com', - 'js.gleam.io', - 'ir-na.amazon-adsystem.com', - 'web.ventunotech.com', - 'verify.authorize.net', - 'ads.themoneytizer.com', - 'embed.finanzcheck.de', - 'imagesrv.adition.com', - 'js.juicyads.com', - 'form.jotformeu.com', - 'speakerdeck.com', - 'content.jwplatform.com', - 'ads.investingchannel.com', - 'app.ecwid.com', - 'www.industriejobs.de', - 's.gravatar.com', - 'googlesyndication.com', - 'a.optmstr.com', - 'a.optmnstr.com', - 'a.opmnstr.com', - 'adthrive.com', - 'mediavine.com', - 'js.hsforms.net', - 'googleadservices.com', - 'f.convertkit.com', - 'recaptcha/api.js', - 'mailmunch.co', - 'apps.shareaholic.com', - 'dsms0mj1bbhn4.cloudfront.net', - 'nutrifox.com', - 'code.tidio.co', - 'www.uplaunch.com', - 'widget.reviewability.com', - 'embed-cdn.gettyimages.com/widgets.js', - 'app.mailerlite.com', - 'ck.page', - 'cdn.jsdelivr.net/gh/AmauriC/', - 'static.klaviyo.com/onsite/js/klaviyo.js', - 'a.omappapi.com/app/js/api.min.js', - 'static.zdassets.com', - 'feedbackcompany.com/widgets/feedback-company-widget.min.js', - 'widget.gleamjs.io', - 'phonewagon.com', - 'simplybook.asia/v2/widget/widget.js', - 'simplybook.it/v2/widget/widget.js', - 'simplybook.me/v2/widget/widget.js', - 'static.botsrv.com/website/js/widget2.36cf1446.js', - 'static.mailerlite.com/data/', - 'cdn.voxpow.com', - 'loader.knack.com', - 'embed.lpcontent.net/leadboxes/current/embed.js', - 'cc.cdn.civiccomputing.com/9/cookieControl-9.x.min.js', - '/wp-content/plugins/interactive-3d-flipbook-powered-physics-engine/assets/js/html2canvas.min.js', - '/wp-content/plugins/interactive-3d-flipbook-powered-physics-engine/assets/js/pdf.min.js', - '/wp-content/plugins/interactive-3d-flipbook-powered-physics-engine/assets/js/three.min.js', - '/wp-content/plugins/interactive-3d-flipbook-powered-physics-engine/assets/js/3d-flip-book.min.js', - ]; - - $excluded_external = array_merge( $defaults, $this->options->get( 'exclude_js', [] ) ); + $excluded_external = $this->options->get( 'exclude_js', [] ); /** * Filters JS externals files to exclude from the combine process diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Combine.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Combine.php index 04160f7c8..c9a00dfbe 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Combine.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Combine.php @@ -161,7 +161,7 @@ public function optimize( $html ) { protected function parse( $scripts ) { $excluded_externals = implode( '|', $this->get_excluded_external_file_path() ); $scripts = array_map( - function( $script ) use ( $excluded_externals ) { + function ( $script ) use ( $excluded_externals ) { preg_match( '/]+[\s\'"])?src\s*=\s*[\'"]\s*?(?[^\'"]+\.js(?:\?[^\'"]*)?)\s*?[\'"]([^>]+)?\/?>/Umsi', $script[0], $matches ); if ( isset( $matches['url'] ) ) { @@ -350,7 +350,7 @@ protected function get_content() { */ protected function combine( $content ) { if ( empty( $content ) ) { - return false; + return false; // phpcs:ignore Universal.CodeAnalysis.ConstructorDestructorReturn.ReturnValueFound } $filename = md5( $content . $this->minify_key ) . '.js'; @@ -359,17 +359,17 @@ protected function combine( $content ) { $minified_content = $this->minify(); if ( ! $minified_content ) { - return false; + return false; // phpcs:ignore Universal.CodeAnalysis.ConstructorDestructorReturn.ReturnValueFound } $minify_filepath = $this->write_file( $minified_content, $minified_file ); if ( ! $minify_filepath ) { - return false; + return false; // phpcs:ignore Universal.CodeAnalysis.ConstructorDestructorReturn.ReturnValueFound } } - return $this->get_minify_url( $filename ); + return $this->get_minify_url( $filename ); // phpcs:ignore Universal.CodeAnalysis.ConstructorDestructorReturn.ReturnValueFound } /** @@ -409,280 +409,7 @@ protected function add_to_minify( $content ) { * @return array */ protected function get_excluded_inline_content() { - $defaults = [ - 'document.write', - 'google_ad', - 'edToolbar', - 'gtag', - '_gaq.push', - '_gaLt', - 'GoogleAnalyticsObject', - 'syntaxhighlighter', - 'adsbygoogle', - 'ci_cap_', - '_stq', - 'nonce', - 'post_id', - 'LogHuman', - 'idcomments_acct', - 'ch_client', - 'sc_online_t', - '_stq', - 'bannersnack_embed', - 'vtn_player_type', - 'ven_video_key', - 'ANS_customer_id', - 'tdBlock', - 'tdLocalCache', - 'wpRestNonce', - '"url":', - 'lazyLoadOptions', - 'adthrive', - 'loadCSS', - 'google_tag_params', - 'clicky_custom', - 'clicky_site_ids', - 'NSLPopupCenter', - '_paq', - 'gtm', - 'dataLayer', - 'RecaptchaLoad', - 'WPCOM_sharing_counts', - 'jetpack_remote_comment', - 'subscribe-field', - 'contextly', - '_mmunch', - 'gt_request_uri', - 'doGTranslate', - 'docTitle', - 'bs_ajax_paginate_', - 'bs_deferred_loading_', - 'theChampRedirectionUrl', - 'theChampFBCommentUrl', - 'theChampTwitterRedirect', - 'theChampRegRedirectionUrl', - 'ESSB_CACHE_URL', - 'oneall_social_login_providers_', - 'betterads_screen_width', - 'woocommerce_wishlist_add_to_wishlist_url', - 'arf_conditional_logic', - 'heateorSsHorSharingShortUrl', - 'TL_Const', - 'bimber_front_microshare', - 'setAttribute("id"', - 'setAttribute( "id"', - 'TribeEventsPro', - 'peepsotimedata', - 'wphc_data', - 'hc_rand_id', - 'RBL_ADD', - 'AfsAnalyticsObject', - '_thriveCurrentPost', - 'esc_login_url', - 'fwduvpMainPlaylist', - 'Bibblio.initRelatedContent', - 'showUFC()', - '#iphorm-', - '#fancy-', - 'ult-carousel-', - 'theChampLJAuthUrl', - 'f._fbq', - 'Insticator', - 'w2dc_js_objects', - 'cherry_ajax', - 'ad_block_', - 'elementorFrontendConfig', - 'zeen_', - 'disqusIdentifier', - 'currentAjaxUrl', - 'geodir_event_call_calendar_', - 'atatags-', - 'hbspt.forms.create', - 'function(c,h,i,m,p)', - 'dataTable({', - 'rankMath = {', - '_atrk_opts', - 'quicklinkOptions', - 'ct_checkjs_', - 'WP_Statistics_http', - 'penci_block_', - 'omapi_localized', - 'omapi_data', - 'OptinMonsterApp', - 'tminusnow', - 'nfForms', - 'galleries.gallery_', - 'wcj_evt.prodID', - 'advads_tracking_ads', - 'advadsGATracking.postContext', - 'woopack_config', - 'ulp_content_id', - 'wp-cumulus/tagcloud.swf?r=', - 'ctSetCookie(\'ct_checkjs\'', - 'woof_really_curr_tax', - 'uLogin.customInit', - 'i18n_no_matching_variations_text', - 'alsp_map_markers_attrs', - 'var inc_opt =', - 'iworks_upprev', - 'yith_wcevti_tickets', - 'window.metrilo.ensure_cbuid', - 'metrilo.event', - 'wordpress_page_root', - 'wcct_info', - 'Springbot.product_id', - 'pysWooProductData', - 'dfd-heading', - 'owl=$("#', - 'penci_megamenu', - 'fts_security', - 'algoliaAutocomplete', - 'avia_framework_globals', - 'tabs.easyResponsiveTabs', - 'searchlocationHeader', - 'yithautocomplete', - 'data-parallax-speed', - 'currency_data=', - 'cedexisData', - 'function reenableButton', - '#wpnbio-show', - 'e.Newsletter2GoTrackingObject', - 'var categories_', - '"+nRemaining+"', - 'cartsguru_cart_token', - 'after_share_easyoptin', - 'location_data.push', - 'thirstyFunctions.isThirstyLink', - 'styles: \' #custom-menu-', - 'function svc_center_', - '#svc_carousel2_container_', - 'advads.move', - 'elementid', - 'advads_has_ads', - 'wpseo_map_init', - 'mdf_current_page_url', - 'tptn_tracker', - 'dpsp_pin_button_data', - 'searchwp_live_search_params', - 'wpp_params', - 'top.location,thispage', - 'selection+pagelink', - 'ic_window_resolution', - 'PHP.wp_p_id', - 'ShopifyBuy.UI.onReady(client)', - 'orig_request_uri', - 'gie.widgets.load', - 'Adman.Flash', - 'PHP.wp_p_id', - 'window.broadstreetKeywords', - 'var productId =', - 'var flatsomeVars', - 'wc_product_block_data', - 'static.mailerlite.com', - 'amzn_assoc', - '_bs_getParameterByName', - '_stq.push', - 'h._remove', - 'var FlowFlowOpts', - 'var WCPFData =', - 'var _beeketing', - 'var _statcounter', - 'var actions =', - 'var current_url', - 'var object_name', - 'var the_ajax_script', - 'var wc_cart_fragments_params', - 'var woocommerce_params', - 'var wpml_cookies', - 'wc_add_to_cart_params', - 'window.broadstreetKeywords', - 'window.wc_ga_pro.available_gateways', - 'xa.prototype', - 'HOUZEZ_ajaxcalls_vars', - 'w2dc_maps_objects', - 'w2dc_controller_args_array', - 'w2dc_map_markers_attrs', - 'YT.Player', - 'WPFC.data', - 'function current_video_', - 'var videodiv', - 'var slider_wppasrotate', - 'wppas_ga', - 'var blockClass', - 'tarteaucitron', - 'pw_brand_product_list', - 'tminusCountDown', - 'pysWooSelectContentData', - 'wpvq_ans89733', - '_isp_version', - 'price_range_data', - 'window.FeedbackCompanyWidgets', - 'woocs_current_currency', - 'woo_variation_swatches_options', - 'woocommerce_price_slider_params', - 'scriptParams', - 'form-adv-pagination', - 'borlabsCookiePrioritize', - 'urls_wpwidgetpolylang', - 'quickViewNonce', - 'frontendscripts_params', - 'nj-facebook-messenger', - 'var fb_mess_position', - 'init_particles_row_background_script', - 'setREVStartSize', - 'fl-node', - 'PPAccordion', - 'soliloquy_', - 'wprevpublicjs_script_vars', - 'DTGS_NONCE_FRONTEND', - 'et_animation_data', - 'archives-dropdown', - 'loftloaderCache', - 'SmartSliderSimple', - 'var nectarLove', - 'var incOpt', - 'RocketBrowserCompatibilityChecker', - 'RocketPreloadLinksConfig', - 'placementVersionId', - 'var useEdit', - 'var DTGS_NONCE_FRONTEND', - 'n2jQuery', - 'et_core_api_spam_recaptcha', - 'cnArgs', - '__CF$cv$params', - 'trustbox_settings', - 'aepro', - 'cdn.jst.ai', - 'w2dc_fields_in_categories', - 'aepc_pixel', - 'avadaWooCommerceVars', - 'var isb', - 'fcaPcPost', - 'csrf_token', - 'icwp_wpsf_vars_lpantibot', - 'wpvViewHead', - 'ed_school_plugin', - 'aps_comp_', - 'guaven_woos', - '__lm_redirect_to', - '__wpdm_view_count', - 'bookacti.booking_system', - 'nfFrontEnd', - 'view_quote_cart_link', - '__eae_decode_emails', - 'divioverlays_ajaxurl', - 'var _EPYT_', - '#ins-heading-', - '#ins-button-', - 'tve_frontend_options', - 'lb24.src', - 'amazon_Login_accessToken', - 'porto_infinite_scroll', - '.adace-loader-', - 'adace_load_', - ]; - - $excluded_inline = array_merge( $defaults, $this->options->get( 'exclude_inline_js', [] ) ); + $excluded_inline = $this->options->get( 'exclude_inline_js', [] ); /** * Filters inline JS excluded from being combined @@ -702,115 +429,6 @@ protected function get_excluded_inline_content() { * @return array */ protected function get_move_after_inline_scripts() { - $move_after_scripts = [ - 'map_fusion_map_', - 'ec:addProduct', - 'ec:addImpression', - 'clear_better_facebook_comments', - 'vc-row-destroy-equal-heights-', - 'dfd-icon-list-', - 'SFM_template', - 'WLTChangeState', - 'wlt_star_', - 'wlt_pop_distance_', - 'smart_list_tip', - 'gd-wgt-pagi-', - 'data-rf-id=', - 'tvc_po=', - 'scrapeazon', - 'startclock', - 'it_logo_field_owl-box_', - 'td_live_css_uid', - 'wpvl_paramReplace', - 'tdAjaxCount', - 'mec_skin_', - '_wca', - '_taboola', - 'fbq(\'trackCustom\'', - 'fbq(\'track\'', - 'data.token', - 'sharrre', - 'dfads_ajax_load_ads', - 'tie_postviews', - 'wmp_update', - 'h5ab-print-article', - 'gform_ajax_frame_', - 'gform_post_render', - 'mts_view_count', - 'act_css_tooltip', - 'window.SLB', - 'wpt_view_count', - 'var dateNow', - 'gallery_product_', - '.flo-block-slideshow-', - 'data=\'api-key=ct-', - 'ip_common_function()', - '("style#gsf-custom-css").append', - 'a3revWCDynamicGallery_', - '#owl-carousel-instagram-', - 'window.FlowFlowOpts', - 'jQuery(\'.td_uid_', - 'jQuery(".slider-', - '#dfd-vcard-widget-', - '#sf-instagram-widget-', - '.woocommerce-tabs-', - 'penci_megamenu__', - 'vc_prepareHoverBox', - 'wp-temp-form-div', - '_wswebinarsystem_already_', - '#views-extra-css").text', - 'fusetag.setTargeting', - 'hit.uptrendsdata.com', - 'callback:window.renderBadge', - 'test_run_nf_conditional_logic', - 'cb_nombre', - '$(\'.fl-node-', - 'function($){google_maps_', - '$("#myCarousel', - 'et_animation_data=', - 'current_url="', - 'CustomEvent.prototype=window.Event.prototype', - 'electro-wc-product-gallery', - 'woof_is_mobile', - 'jQuery(\'.videonextup', - 'wpp_params', - 'us.templateDirectoryUri=', - '.fat-gallery-item', - '.ratingbox', - 'user_rating.prototype.eraseCookie', - 'test_run_nf_conditional', - 'dpsp-networks-btns-wrapper', - 'pa_woo_product_info', - 'sharing_enabled_on_post_via_metabox', - '#product-search-field-', - 'GOTMLS_login_offset', - 'berocket_aapf_time_to_fix_products_style', - 'window.vc_googleMapsPointer', - 'sinceID_', - '#ut-background-video-ut-section', - '+window.comment_tab_width+', - 'dfd-button-hover-in', - 'wpseo-address-wrapper', - 'platform.stumbleupon.com', - '#woo_pp_ec_button_mini_cart', - '#supercarousel', - 'blockClass', - 'tdbMenuItem', - 'tdbSearchItem', - 'best_seller_badge', - 'jQuery(\'#product-top-bar', - 'fb_desc-', - 'FC_regenerate_captcha', - 'wp_post_blocks_vars.listed_posts=[', - 'captcha-hash', - 'mapdata={', - '.ywpc-char-', - ').countdowntimer(', - 'jQuery("#td_uid_', - 'find(\'#td_uid_', - 'variation_estimate_msg', - ]; - /** * Filters inline JS to move after the combined JS file * @@ -818,7 +436,7 @@ protected function get_move_after_inline_scripts() { * * @param array $move_after_scripts Patterns to match. */ - return apply_filters( 'rocket_move_after_combine_js', $move_after_scripts ); + return apply_filters( 'rocket_move_after_combine_js', [] ); } /** @@ -871,7 +489,7 @@ private function is_delayed_script( $script_attributes ) { * @param string $url URL to check. * @return boolean */ - private function is_defer_excluded( string $url ) : bool { + private function is_defer_excluded( string $url ): bool { if ( ! empty( $this->excluded_defer_js ) && diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Minify.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Minify.php index ee80d0b41..91961cf9d 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Minify.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Minify.php @@ -183,12 +183,20 @@ protected function replace_url( $url ) { } // This filter is documented in /inc/classes/optimization/class-abstract-optimization.php. - $url = apply_filters( 'rocket_asset_url', $url, $this->get_zones() ); - $unique_id = md5( $url . $this->minify_key ); - $filename = preg_replace( '/\.js$/', '-' . $unique_id . '.js', ltrim( rocket_realpath( wp_parse_url( $url, PHP_URL_PATH ) ), '/' ) ); + $url = apply_filters( 'rocket_asset_url', $url, $this->get_zones() ); + $parsed_url = wp_parse_url( $url ); + + if ( empty( $parsed_url['path'] ) ) { + return false; + } + + if ( ! empty( $parsed_url['host'] ) ) { + $url = rocket_add_url_protocol( $url ); + } + + $filename = ltrim( rocket_realpath( $parsed_url['path'] ), '/' ); $minified_file = rawurldecode( $this->minify_base_path . $filename ); - $minified_url = $this->get_minify_url( $filename, $url ); if ( rocket_direct_filesystem()->exists( $minified_file ) ) { Logger::debug( @@ -198,11 +206,11 @@ protected function replace_url( $url ) { 'path' => $minified_file, ] ); - return $minified_url; + return $this->get_full_minified_url( $minified_file, $this->get_minify_url( $filename, $url ) ); } $is_external_url = $this->is_external_file( $url ); - $file_path = $is_external_url ? $this->local_cache->get_filepath( $url ) : $this->get_file_path( $url ); + $file_path = $is_external_url ? $this->local_cache->get_filepath( rocket_add_url_protocol( $url ) ) : $this->get_file_path( $url ); if ( ! $file_path ) { Logger::error( @@ -248,7 +256,7 @@ protected function replace_url( $url ) { return false; } - return $minified_url; + return $this->get_full_minified_url( $minified_file, $this->get_minify_url( $filename, $url ) ); } /** @@ -324,10 +332,10 @@ protected function minify( $file_content ) { $minified_content = $minifier->minify(); if ( empty( $minified_content ) ) { - return ''; + return ''; // phpcs:ignore Universal.CodeAnalysis.ConstructorDestructorReturn.ReturnValueFound } - return $minified_content; + return $minified_content; // phpcs:ignore Universal.CodeAnalysis.ConstructorDestructorReturn.ReturnValueFound } /** diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Subscriber.php index 41de014fb..314300814 100644 --- a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Subscriber.php +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/Minify/JS/Subscriber.php @@ -45,9 +45,10 @@ public function process( $html ) { } $assets_local_cache = new AssetsLocalCache( rocket_get_constant( 'WP_ROCKET_MINIFY_CACHE_PATH' ), $this->filesystem ); + $container = apply_filters( 'rocket_container', null ); if ( $this->options->get( 'minify_js' ) && $this->options->get( 'minify_concatenate_js' ) ) { - $this->set_processor_type( new Combine( $this->options, new MinifyJS(), $assets_local_cache, new DeferJS( $this->options ) ) ); + $this->set_processor_type( new Combine( $this->options, new MinifyJS(), $assets_local_cache, $container->get( 'defer_js' ) ) ); } elseif ( $this->options->get( 'minify_js' ) && ! $this->options->get( 'minify_concatenate_js' ) ) { $this->set_processor_type( new Minify( $this->options, $assets_local_cache ) ); } diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Database.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Database.php new file mode 100644 index 000000000..59af63527 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Database.php @@ -0,0 +1,105 @@ +rucss_usedcss_table = $rucss_usedcss_table; + } + + /** + * Drop RUCSS Database Tables. + * + * @return void + */ + public function drop_rucss_database_tables() { + // If the table exist, then drop the table. + if ( $this->rucss_usedcss_table->exists() ) { + $this->rucss_usedcss_table->uninstall(); + } + } + + /** + * Truncate RUCSS used_css DB table. + * + * @return bool + */ + public function truncate_used_css_table(): bool { + if ( ! $this->rucss_usedcss_table->exists() ) { + return false; + } + return $this->rucss_usedcss_table->truncate(); + } + + /** + * Delete old used css based on last accessed date. + * + * @return void + */ + public function delete_old_used_css() { + if ( ! $this->rucss_usedcss_table->exists() ) { + return; + } + + $this->rucss_usedcss_table->delete_old_rows(); + } + + /** + * Get old used css based on last accessed date. + * + * @return array + */ + public function get_old_used_css(): array { + if ( ! $this->rucss_usedcss_table->exists() ) { + return []; + } + return $this->rucss_usedcss_table->get_old_rows(); + } + + /** + * Remove all completed rows. + * + * @return bool|int + */ + public function remove_all_completed_rows() { + if ( ! $this->rucss_usedcss_table->exists() ) { + return false; + } + + return $this->rucss_usedcss_table->remove_all_completed_rows(); + } + + /** + * Remove the resources table & version stored in options table + * + * @since 3.12 + * + * @return bool + */ + public function drop_resources_table(): bool { + global $wpdb; + + $result = $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}wpr_rucss_resources" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange + + if ( false === $result ) { + return false; + } + + return delete_option( 'wpr_rucss_resources_version' ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/OptionSubscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/OptionSubscriber.php new file mode 100644 index 000000000..48c34d959 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/OptionSubscriber.php @@ -0,0 +1,78 @@ +settings = $settings; + } + + /** + * Return an array of events that this subscriber wants to listen to. + * + * @return array + */ + public static function get_subscribed_events() { + return [ + 'rocket_first_install_options' => 'add_options_first_time', + 'rocket_input_sanitize' => [ 'sanitize_options', 14, 2 ], + 'rocket_meta_boxes_fields' => [ 'add_meta_box', 2 ], + ]; + } + + /** + * Add the RUCSS options to the WP Rocket options array. + * + * @since 3.9 + * + * @param array $options WP Rocket options array. + * + * @return array + */ + public function add_options_first_time( $options ): array { + return $this->settings->add_options( $options ); + } + + /** + * Sanitizes RUCSS options values when the settings form is submitted + * + * @since 3.9 + * + * @param array $input Array of values submitted from the form. + * @param AdminSettings $settings Settings class instance. + * + * @return array + */ + public function sanitize_options( $input, AdminSettings $settings ): array { + return $this->settings->sanitize_options( $input, $settings ); + } + + /** + * Add the field to the WP Rocket metabox on the post edit page. + * + * @param string[] $fields Metaboxes fields. + * + * @return string[] + */ + public function add_meta_box( array $fields ) { + $fields['remove_unused_css'] = __( 'Remove Unused CSS', 'rocket' ); + + return $fields; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Settings.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Settings.php new file mode 100644 index 000000000..786dd7539 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Settings.php @@ -0,0 +1,288 @@ +options = $options; + $this->beacon = $beacon; + $this->used_css = $used_css; + } + + /** + * Add the RUCSS options to the WP Rocket options array + * + * @since 3.9 + * + * @param array $options WP Rocket options array. + * + * @return array + */ + public function add_options( $options ): array { + $options = (array) $options; + + $options['remove_unused_css'] = 0; + $options['remove_unused_css_safelist'] = []; + + return $options; + } + + /** + * Determines if Remove Unused CSS option is enabled. + * + * @since 3.9 + * + * @return boolean + */ + public function is_enabled(): bool { + + return (bool) $this->options->get( 'remove_unused_css', 0 ); + } + + /** + * Sanitizes RUCSS options values when the settings form is submitted + * + * @since 3.9 + * + * @param array $input Array of values submitted from the form. + * @param AdminSettings $settings Settings class instance. + * + * @return array + */ + public function sanitize_options( array $input, AdminSettings $settings ): array { + $input['remove_unused_css'] = $settings->sanitize_checkbox( $input, 'remove_unused_css' ); + $input['remove_unused_css_safelist'] = ! empty( $input['remove_unused_css_safelist'] ) ? rocket_sanitize_textarea_field( 'remove_unused_css_safelist', $input['remove_unused_css_safelist'] ) : []; + + return $input; + } + + /** + * Set optimize css delivery value + * + * @since 3.10 + * + * @param array $field_args Array of field to be added to settings page. + * + * @return array + */ + public function set_optimize_css_delivery_value( $field_args ): array { + if ( 'optimize_css_delivery' !== $field_args['id'] ) { + return $field_args; + } + + $async_css_value = (bool) $this->options->get( 'async_css', 0 ); + $remove_unused_css_value = (bool) $this->options->get( 'remove_unused_css', 0 ); + $field_args['value'] = ( $remove_unused_css_value || $async_css_value ); + + return $field_args; + } + + /** + * Set optimize css delivery method value + * + * @since 3.10 + * + * @param array $field_args Array of field to be added to settings page. + * + * @return array + */ + public function set_optimize_css_delivery_method_value( $field_args ): array { + if ( 'optimize_css_delivery_method' !== $field_args['id'] ) { + return $field_args; + } + + $value = ''; + + if ( (bool) $this->options->get( 'async_css', 0 ) ) { + $value = 'async_css'; + } + + if ( (bool) $this->options->get( 'remove_unused_css', 0 ) ) { + $value = 'remove_unused_css'; + } + + $field_args['value'] = $value; + + return $field_args; + } + + /** + * Checks if we can display the RUCSS notices + * + * @param bool $check_enabled check if RUCSS is enabled. + * + * @since 3.11 + * + * @return bool + */ + private function can_display_notice( $check_enabled = true ): bool { + $screen = get_current_screen(); + + if ( ! rocket_direct_filesystem()->is_writable( rocket_get_constant( 'WP_ROCKET_USED_CSS_PATH' ) ) ) { + return false; + } + + if ( + isset( $screen->id ) + && + 'settings_page_wprocket' !== $screen->id + ) { + return false; + } + + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return false; + } + + if ( $check_enabled && ! $this->is_enabled() ) { + return false; + } + + return true; + } + + /** + * Disables combine CSS if RUCSS is enabled when updating to 3.11 + * + * @since 3.11 + * + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function set_option_on_update( $old_version ) { + if ( version_compare( $old_version, '3.11', '>=' ) ) { + return; + } + + $options = get_option( 'wp_rocket_settings', [] ); + + if ( 'local' === wp_get_environment_type() ) { + $options['optimize_css_delivery'] = 0; + $options['remove_unused_css'] = 0; + $options['async_css'] = 0; + } + + update_option( 'wp_rocket_settings', $options ); + } + + /** + * Updates safelist items for new SaaS compatibility + * + * @since 3.11.0.2 + * + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function update_safelist_items( $old_version ) { + if ( version_compare( $old_version, '3.11.0.2', '>=' ) ) { + return; + } + + $options = get_option( 'wp_rocket_settings', [] ); + + if ( empty( $options['remove_unused_css_safelist'] ) ) { + return; + } + + foreach ( $options['remove_unused_css_safelist'] as $key => $value ) { + if ( str_contains( $value, '.css' ) ) { + continue; + } + + if ( str_starts_with( $value, '(' ) ) { + continue; + } + + $options['remove_unused_css_safelist'][ $key ] = '(.*)' . $value; + } + + update_option( 'wp_rocket_settings', $options ); + } + + /** + * Display a notice on table missing. + * + * @return void + */ + public function display_no_table_notice() { + + if ( ! $this->can_display_notice() ) { + return; + } + if ( $this->used_css->exists() ) { + return; + } + + // translators: %1$s = plugin name, %2$s = table name, %3$s = open tag, %4$s = closing tag. + $main_message = esc_html__( '%1$s: Could not create the %2$s table in the database which is necessary for the Remove Unused CSS feature to work. Please reach out to %3$sour support%4$s.', 'rocket' ); + + $message = sprintf( + // translators: %1$s = plugin name, %2$s = table name, %3$s = open tag, %4$s = closing tag. + $main_message, + 'WP Rocket', + $this->used_css->get_name(), + '', + '' + ); + + rocket_notice_html( + [ + 'status' => 'error', + 'dismissible' => '', + 'message' => $message, + 'id' => 'rocket-notice-rucss-missing-table', + ] + ); + } + + /** + * Get support URL. + * + * @return string + */ + protected function get_support_url() { + return rocket_get_external_url( + 'support', + [ + 'utm_source' => 'wp_plugin', + 'utm_medium' => 'wp_rocket', + ] + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Subscriber.php new file mode 100644 index 000000000..94e176128 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Admin/Subscriber.php @@ -0,0 +1,592 @@ +settings = $settings; + $this->database = $database; + $this->used_css = $used_css; + $this->queue = $queue; + } + + /** + * Return an array of events that this subscriber listens to. + * + * @return array + */ + public static function get_subscribed_events(): array { + $slug = rocket_get_constant( 'WP_ROCKET_SLUG', 'wp_rocket_settings' ); + + return [ + 'update_option_' . $slug => [ + [ 'clean_used_css_and_cache', 9, 2 ], + [ 'maybe_set_processing_transient', 50, 2 ], + [ 'maybe_unlock_preload', 9, 2 ], + [ 'maybe_delete_transient', 10, 2 ], + ], + 'switch_theme' => 'truncate_used_css', + 'permalink_structure_changed' => 'truncate_used_css', + 'rocket_domain_options_changed' => 'truncate_used_css', + 'wp_trash_post' => 'delete_used_css_on_update_or_delete', + 'delete_post' => 'delete_used_css_on_update_or_delete', + 'clean_post_cache' => 'delete_used_css_on_update_or_delete', + 'wp_update_comment_count' => 'delete_used_css_on_update_or_delete', + 'edit_term' => 'delete_term_used_css', + 'pre_delete_term' => 'delete_term_used_css', + 'admin_notices' => [ + [ 'display_no_table_notice' ], + [ 'notice_write_permissions' ], + ], + 'rocket_before_add_field_to_settings' => [ + [ 'set_optimize_css_delivery_value', 10, 1 ], + [ 'set_optimize_css_delivery_method_value', 10, 1 ], + ], + 'wp_rocket_upgrade' => [ + [ 'set_option_on_update', 14, 2 ], + [ 'update_safelist_items', 15, 2 ], + [ 'delete_used_css', 16, 2 ], + [ 'cancel_pending_jobs_as', 16, 2 ], + [ 'drop_resources_table', 18, 2 ], + ], + 'wp_ajax_rocket_spawn_cron' => 'spawn_cron', + 'rocket_deactivation' => 'cancel_queues', + 'admin_head-tools_page_action-scheduler' => 'delete_as_tables_transient_on_tools_page', + 'pre_get_rocket_option_remove_unused_css' => 'disable_russ_on_wrong_license', + 'rocket_before_rollback' => 'cancel_queues', + 'rocket_saas_clean_all' => [ 'truncate', 11 ], + 'rocket_saas_clean_url' => [ 'clean_url', 11 ], + ]; + } + + /** + * Delete used_css on Update Post or Delete post. + * + * @since 3.9 + * + * @param int $post_id The post ID. + * + * @return void + */ + public function delete_used_css_on_update_or_delete( $post_id ) { + if ( ! $this->settings->is_enabled() ) { + return; + } + + if ( ! $this->is_deletion_enabled() ) { + return; + } + + $url = get_permalink( $post_id ); + + if ( false === $url ) { + return; + } + + $this->used_css->delete_used_css( untrailingslashit( $url ) ); + } + + /** + * Maybe unlock all locked preload urls. + * + * @param array $old_value An array of submitted values for the settings. + * @param array $value An array of previous values for the settings. + * + * @return void + */ + public function maybe_unlock_preload( $old_value, $value ) { + if ( ! isset( $value['remove_unused_css'], $old_value['remove_unused_css'] ) ) { + return; + } + + if ( $value['remove_unused_css'] === $old_value['remove_unused_css'] ) { + return; + } + + if ( $value['remove_unused_css'] ) { + return; + } + + do_action( 'rocket_preload_unlock_all_urls' ); + } + + /** + * Deletes the used CSS when updating a term + * + * @since 3.10.2 + * + * @param int $term_id the term ID. + * + * @return void + */ + public function delete_term_used_css( $term_id ) { + if ( ! $this->settings->is_enabled() ) { + return; + } + + if ( ! $this->is_deletion_enabled() ) { + return; + } + + $url = get_term_link( (int) $term_id ); + + if ( is_wp_error( $url ) ) { + return; + } + + $this->used_css->delete_used_css( untrailingslashit( $url ) ); + } + + /** + * Truncate RUCSS used_css DB table. + * + * @since 3.9 + * + * @return void + */ + public function truncate_used_css() { + if ( ! $this->settings->is_enabled() ) { + return; + } + + if ( ! $this->is_deletion_enabled() ) { + return; + } + + $this->delete_used_css_rows(); + $this->set_notice_transient(); + } + + /** + * Deletes the used CSS from the table + * + * @since 3.11 + * + * @return void + */ + private function delete_used_css_rows() { + $this->used_css->delete_all_used_css(); + + if ( 0 < $this->used_css->get_not_completed_count() ) { + $this->database->remove_all_completed_rows(); + } else { + $this->database->truncate_used_css_table(); + } + + /** + * Fires after the used CSS has been cleaned in the database + * + * @since 3.11 + */ + do_action( 'rocket_after_clean_used_css' ); + } + + /** + * Truncate UsedCSS DB Table when `remove_unused_css_safelist` is changed. + * + * @since 3.9 + * + * @param array $old_value An array of submitted values for the settings. + * @param array $value An array of previous values for the settings. + * + * @return void + */ + public function clean_used_css_and_cache( $old_value, $value ) { + if ( ! isset( $value['remove_unused_css_safelist'], $old_value['remove_unused_css_safelist'] ) ) { + return; + } + + if ( $value['remove_unused_css_safelist'] === $old_value['remove_unused_css_safelist'] ) { + return; + } + + $this->delete_used_css_rows(); + + $this->set_notice_transient(); + } + + /** + * Deletes rows when triggering clean from admin + * + * @param array $clean An array containing the status and message. + * + * @return array + */ + public function truncate( $clean ) { + if ( ! $this->settings->is_enabled() ) { + return $clean; + } + + if ( ! current_user_can( 'rocket_remove_unused_css' ) ) { + return [ + 'status' => 'die', + ]; + } + + $this->delete_used_css_rows(); + + return [ + 'status' => 'success', + 'message' => sprintf( + // translators: %1$s = plugin name. + __( '%1$s: Used CSS cache cleared!', 'rocket' ), + 'WP Rocket' + ), + ]; + } + + /** + * Set optimize css delivery value + * + * @since 3.10 + * + * @param array $field_args Array of field to be added to settings page. + * + * @return array + */ + public function set_optimize_css_delivery_value( $field_args ): array { + return $this->settings->set_optimize_css_delivery_value( $field_args ); + } + + /** + * Set optimize css delivery method value + * + * @since 3.10 + * + * @param array $field_args Array of field to be added to settings page. + * + * @return array + */ + public function set_optimize_css_delivery_method_value( $field_args ): array { + return $this->settings->set_optimize_css_delivery_method_value( $field_args ); + } + + /** + * Clean UsedCSS for the current URL. + * + * @return void + */ + public function clean_url() { + if ( ! current_user_can( 'rocket_remove_unused_css' ) ) { + wp_nonce_ays( '' ); + } + + $url = wp_get_referer(); + + if ( 0 !== strpos( $url, 'http' ) ) { + $parse_url = get_rocket_parse_url( untrailingslashit( home_url() ) ); + $url = $parse_url['scheme'] . '://' . $parse_url['host'] . $url; + } + + $this->used_css->clear_url_usedcss( $url ); + } + + /** + * Disables combine CSS if RUCSS is enabled when updating to 3.11 + * + * @since 3.11 + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function set_option_on_update( $new_version, $old_version ) { + $this->settings->set_option_on_update( $old_version ); + + if ( version_compare( $old_version, '3.11', '>=' ) ) { + return; + } + + $this->database->truncate_used_css_table(); + rocket_clean_domain(); + $this->set_notice_transient(); + } + + /** + * Updates safelist items for new SaaS compatibility + * + * @since 3.11.0.2 + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function update_safelist_items( $new_version, $old_version ) { + $this->settings->update_safelist_items( $old_version ); + } + + /** + * Cancel pending jobs actions in Action Scheduler on update to 3.11.3 + * + * @since 3.11.3 + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function cancel_pending_jobs_as( $new_version, $old_version ) { + if ( version_compare( $old_version, '3.11.3', '>=' ) ) { + return; + } + + try { + $this->queue->cancel_pending_jobs_cron(); + } catch ( \InvalidArgumentException $e ) { + // nothing to do. + return; + } + } + + /** + * Sets the processing transient if RUCSS is enabled + * + * @since 3.11 + * + * @param mixed $old_value Option old value. + * @param mixed $value Option new value. + * + * @return void + */ + public function maybe_set_processing_transient( $old_value, $value ) { + if ( ! isset( $old_value['remove_unused_css'], $value['remove_unused_css'] ) ) { + return; + } + + if ( 0 === (int) $value['remove_unused_css'] ) { + return; + } + + if ( $old_value['remove_unused_css'] === $value['remove_unused_css'] ) { + return; + } + + $this->set_notice_transient(); + } + + /** + * Sets the transient for the processing notice + * + * @since 3.11 + * + * @return void + */ + private function set_notice_transient() { + set_transient( + 'rocket_saas_processing', + time() + 90, + 1.5 * MINUTE_IN_SECONDS + ); + + rocket_renew_box( 'saas_success_notice' ); + } + + /** + * Sends a request to run cron when switching to RUCSS completed notice + * + * @since 3.11 + * + * @return void + */ + public function spawn_cron() { + if ( rocket_get_constant( 'DISABLE_WP_CRON', false ) ) { + return;// Bailout and don't fire the CRON. + } + + check_ajax_referer( 'rocket-ajax', 'nonce' ); + + if ( ! current_user_can( 'rocket_manage_options' ) ) { + wp_send_json_error(); + return; + } + + spawn_cron(); + + wp_send_json_success(); + } + + /** + * Cancel queues and crons for RUCSS. + * + * @return void + */ + public function cancel_queues() { + // Will unhook check for dispatching an async request without RUCSS process running. + \ActionScheduler_QueueRunner::instance()->unhook_dispatch_async_request(); + + // Will unhook check for dispatching an async request when RUCSS process is already running. + RUCSSQueueRunner::instance()->unhook_dispatch_async_request(); + + $this->queue->cancel_pending_jobs_cron(); + + if ( ! wp_next_scheduled( 'rocket_saas_clean_rows_time_event' ) ) { + return; + } + + wp_clear_scheduled_hook( 'rocket_saas_clean_rows_time_event' ); + } + + /** + * Delete the transient for Action scheduler once admin visits the AS tools page. + * + * @return void + */ + public function delete_as_tables_transient_on_tools_page() { + delete_transient( 'rocket_rucss_as_tables_count' ); + } + + /** + * Deletes the used CSS on update to 3.11.4 for new storage method + * + * @since 3.11.4 + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function delete_used_css( $new_version, $old_version ) { + if ( version_compare( $old_version, '3.11.4', '>=' ) ) { + return; + } + + $this->database->truncate_used_css_table(); + } + + /** + * Disable RUCSS on wrong license. + * + * @return bool + */ + public function disable_russ_on_wrong_license() { + if ( false !== (bool) get_option( 'wp_rocket_no_licence' ) ) { + return false; + } + return null; + } + + /** + * Remove the resources table & version stored in options table on update to 3.12 + * + * @since 3.12 + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function drop_resources_table( $new_version, $old_version ) { + if ( version_compare( $old_version, '3.12', '>=' ) ) { + return; + } + + $this->database->drop_resources_table(); + } + + /** + * Displays a notice if the used CSS folder is not writable + * + * @since 3.11.4 + * + * @return void + */ + public function notice_write_permissions() { + $this->used_css->notice_write_permissions(); + } + + /** + * Display a notice on table missing. + * + * @return void + */ + public function display_no_table_notice() { + $this->settings->display_no_table_notice(); + } + + /** + * Maybe delete transient. + * + * @param mixed $old_value Option old value. + * @param mixed $value Option new value. + * + * @return void + */ + public function maybe_delete_transient( $old_value, $value ) { + if ( ! isset( $old_value['remove_unused_css'], $value['remove_unused_css'] ) ) { + return; + } + + if ( 1 === (int) $value['remove_unused_css'] ) { + return; + } + + if ( $old_value['remove_unused_css'] === $value['remove_unused_css'] ) { + return; + } + + delete_transient( 'wp_rocket_no_licence' ); + } + + /** + * Checks if the SaaS deletion is enabled. + * + * @return bool + */ + protected function is_deletion_enabled(): bool { + /** + * Filters the enable SaaS deletion value + * + * @param bool $delete_saas_jobs True to enable deletion, false otherwise. + */ + return (bool) rocket_apply_filter_and_deprecated( + 'rocket_saas_deletion_enabled', + [ true ], + '3.16', + 'rocket_rucss_deletion_enabled' + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSContext.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSContext.php new file mode 100644 index 000000000..dc3fba54e --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSContext.php @@ -0,0 +1,56 @@ +filesystem = $filesystem; + } + + + /** + * Check if the operation is allowed. + * + * @param array $data Data to provide to the context. + * @return bool + */ + public function is_allowed( array $data = [] ): bool { + $is_allowed = $this->run_common_checks( + [ + 'do_not_optimize' => false, + 'bypass' => false, + 'option' => 'remove_unused_css', + 'password_protected' => false, + 'post_excluded' => 'remove_unused_css', + 'logged_in' => false, + ] + ); + + if ( ! $is_allowed ) { + return false; + } + + return $this->filesystem->is_writable_folder(); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSContextSaas.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSContextSaas.php new file mode 100644 index 000000000..9e192731d --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSContextSaas.php @@ -0,0 +1,23 @@ +run_common_checks( [ 'option' => 'remove_unused_css' ] ); + + if ( ! $is_allowed ) { + return false; + } + + return true; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSOptimizeContext.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSOptimizeContext.php new file mode 100644 index 000000000..c2a8126cc --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Context/RUCSSOptimizeContext.php @@ -0,0 +1,39 @@ +run_common_checks( + [ + 'bypass' => false, + 'option' => 'remove_unused_css', + 'post_excluded' => 'remove_unused_css', + ] + ); + + if ( ! current_user_can( 'rocket_remove_unused_css' ) ) { + return false; + } + + if ( ! $is_allowed ) { + return false; + } + + if ( ! rocket_can_display_options() ) { + return false; + } + + return true; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Controller/Filesystem.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Controller/Filesystem.php new file mode 100644 index 000000000..2558a7079 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Controller/Filesystem.php @@ -0,0 +1,173 @@ +filesystem = is_null( $filesystem ) ? rocket_direct_filesystem() : $filesystem; + $this->path = $base_path . get_current_blog_id() . '/'; + } + + /** + * Get the file path for the used CSS file. + * + * @param string $hash Hash of the file contents. + * + * @return string Path for the used CSS file. + */ + private function get_usedcss_full_path( string $hash ) { + return $this->path . $this->hash_to_path( $hash ) . '.css' . ( function_exists( 'gzdecode' ) ? '.gz' : '' ); + } + + /** + * Gets the used CSS content corresponding to the provided hash + * + * @param string $hash Hash of the corresponding used CSS. + * + * @return string + */ + public function get_used_css( string $hash ): string { + $file = $this->get_usedcss_full_path( $hash ); + + if ( ! $this->filesystem->exists( $file ) ) { + return ''; + } + + $file_contents = $this->filesystem->get_contents( $file ); + $css = function_exists( 'gzdecode' ) ? gzdecode( $file_contents ) : $file_contents; + + if ( ! $css ) { + return ''; + } + + return $css; + } + + /** + * Writes the used CSS to the filesystem + * + * @param string $hash Hash to use for the filename. + * @param string $used_css Used CSS content. + * + * @return bool + */ + public function write_used_css( string $hash, string $used_css ): bool { + $file = $this->get_usedcss_full_path( $hash ); + + if ( ! rocket_mkdir_p( dirname( $file ) ) ) { + return false; + } + + // This filter is documented in inc/classes/Buffer/class-cache.php. + $css = function_exists( 'gzencode' ) ? gzencode( $used_css, apply_filters( 'rocket_gzencode_level_compression', 6 ) ) : $used_css; + + if ( ! $css ) { + return false; + } + + return $this->filesystem->put_contents( $file, $css, rocket_get_filesystem_perms( 'file' ) ); + } + + /** + * Deletes the used CSS files for the corresponding hash + * + * @since 3.11.4 + * + * @param string $hash md5 hash string. + * + * @return bool + */ + public function delete_used_css( string $hash ): bool { + $file = $this->get_usedcss_full_path( $hash ); + + return $this->filesystem->delete( $file, false, 'f' ); + } + + /** + * Deletes all the used CSS files + * + * @since 3.11.4 + * + * @return void + */ + public function delete_all_used_css() { + try { + $dir = new RecursiveDirectoryIterator( $this->path, \FilesystemIterator::SKIP_DOTS ); + + $items = new RecursiveIteratorIterator( $dir, RecursiveIteratorIterator::CHILD_FIRST ); + + foreach ( $items as $item ) { + $this->filesystem->delete( $item ); + } + } catch ( \Exception $e ) { + return; + } + } + + /** + * Checks if the used CSS storage folder is writable + * + * @since 3.11.4 + * + * @return bool + */ + public function is_writable_folder() { + if ( ! $this->filesystem->exists( $this->path ) ) { + rocket_mkdir_p( $this->path ); + } + + return $this->filesystem->is_writable( $this->path ); + } + + /** + * Converts hash to path with filtered number of levels + * + * @since 3.11.4 + * + * @param string $hash md5 hash string. + * + * @return string + */ + private function hash_to_path( string $hash ): string { + /** + * Filters the number of sub-folders level to create for used CSS storage + * + * @since 3.11.4 + * + * @param int $levels Number of levels. + */ + $levels = apply_filters( 'rocket_used_css_dir_level', 3 ); + + $base = substr( $hash, 0, $levels ); + $remain = substr( $hash, $levels ); + + $path_array = str_split( $base ); + $path_array[] = $remain; + + return implode( '/', $path_array ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Controller/UsedCSS.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Controller/UsedCSS.php new file mode 100644 index 000000000..03624c046 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Controller/UsedCSS.php @@ -0,0 +1,692 @@ +options = $options; + $this->used_css_query = $used_css_query; + $this->data_manager = $data_manager; + $this->filesystem = $filesystem; + $this->context = $context; + $this->manager = $manager; + } + + /** + * Check if RUCSS option is enabled. + * + * Used inside the CRON so post object isn't there. + * + * @return bool + */ + public function is_enabled() { + return (bool) $this->options->get( 'remove_unused_css', 0 ); + } + + /** + * Start treeshaking the current page. + * + * @param string $html Buffet HTML for current page. + * + * @return string + */ + public function treeshake( string $html ): string { + if ( ! $this->context->is_allowed() ) { + return $html; + } + + $clean_html = $this->hide_comments( $html ); + $clean_html = $this->hide_noscripts( $clean_html ); + $clean_html = $this->hide_scripts( $clean_html ); + + if ( ! $this->html_has_title_tag( $clean_html ) ) { + return $html; + } + + global $wp; + $url = untrailingslashit( home_url( add_query_arg( [], $wp->request ) ) ); + $is_mobile = $this->is_mobile(); + $used_css = $this->used_css_query->get_row( $url, $is_mobile ); + + if ( empty( $used_css ) ) { + $this->manager->add_url_to_the_queue( $url, $is_mobile ); + return $html; + } + + if ( 'completed' !== $used_css->status || empty( $used_css->hash ) ) { + return $html; + } + + $used_css_content = $this->filesystem->get_used_css( $used_css->hash ); + + if ( empty( $used_css_content ) ) { + $this->used_css_query->delete_by_url( $url ); + return $html; + } + + $html = $this->remove_used_css_from_html( $clean_html, $html ); + $html = $this->add_used_css_to_html( $html, $used_css_content ); + $html = $this->add_used_fonts_preload( $html, $used_css_content ); + $html = $this->remove_google_font_preconnect( $html ); + $this->used_css_query->update_last_accessed( (int) $used_css->id ); + + return $html; + } + + /** + * Delete used css based on URL. + * + * @param string $url The page URL. + * + * @return boolean + */ + public function delete_used_css( string $url ): bool { + $used_css_arr = $this->used_css_query->get_rows_by_url( $url ); + + if ( empty( $used_css_arr ) ) { + return false; + } + + $deleted = true; + + foreach ( $used_css_arr as $used_css ) { + if ( empty( $used_css->id ) ) { + continue; + } + + $deleted = $deleted && $this->used_css_query->delete_item( $used_css->id ); + + $count = $this->used_css_query->count_rows_by_hash( $used_css->hash ); + + if ( 0 === $count ) { + $this->filesystem->delete_used_css( $used_css->hash ); + } + } + + return $deleted; + } + + /** + * Deletes all the used CSS files + * + * @since 3.11.4 + * + * @return void + */ + public function delete_all_used_css() { + $this->filesystem->delete_all_used_css(); + } + + /** + * Alter HTML and remove all CSS which was processed from HTML page. + * + * @param string $clean_html Cleaned HTML after removing comments, noscripts and scripts. + * @param string $html HTML content. + * + * @return string HTML content. + */ + private function remove_used_css_from_html( string $clean_html, string $html ): string { + $this->set_inline_exclusions_lists(); + $html = $this->remove_external_styles_from_html( $clean_html, $html ); + return $this->remove_internal_styles_from_html( $clean_html, $html ); + } + + /** + * Remove external styles from the page's HTML. + * + * @param string $clean_html Cleaned HTML after removing comments, noscripts and scripts. + * @param string $html Actual page's HTML. + * + * @return string + */ + private function remove_external_styles_from_html( string $clean_html, string $html ) { + $link_styles = $this->find( + ']+[\s"\'])?href\s*=\s*[\'"]\s*?(?[^\'"]+(?:\?[^\'"]*)?)\s*?[\'"]([^>]+)?\/?>', + $clean_html, + 'Uis' + ); + + $preserve_google_font = apply_filters( 'rocket_rucss_preserve_google_font', false ); + + $external_exclusions = $this->validate_array_and_quote( + /** + * Filters the array of external exclusions. + * + * @since 3.11.4 + * + * @param array $external_exclusions Array of patterns used to match against the external style tag. + */ + (array) apply_filters( 'rocket_rucss_external_exclusions', $this->external_exclusions ) + ); + + foreach ( $link_styles as $style ) { + if ( + ( + ! (bool) preg_match( '/rel=[\'"]?stylesheet[\'"]?/is', $style[0] ) + && + ! ( (bool) preg_match( '/rel=[\'"]?preload[\'"]?/is', $style[0] ) && (bool) preg_match( '/as=[\'"]?style[\'"]?/is', $style[0] ) ) + ) + || + ( $preserve_google_font && strstr( $style['url'], '//fonts.googleapis.com/css' ) ) + ) { + continue; + } + + if ( ! empty( $external_exclusions ) && $this->find( implode( '|', $external_exclusions ), $style[0] ) ) { + continue; + } + + $html = str_replace( $style[0], '', $html ); + } + + return (string) $html; + } + + /** + * Remove internal styles from the page's HTML. + * + * @param string $clean_html Cleaned HTML after removing comments, noscripts and scripts. + * @param string $html Actual page's HTML. + * + * @return string + */ + private function remove_internal_styles_from_html( string $clean_html, string $html ) { + $inline_styles = $this->find( + '.*)>(?.*)<\/style\s*>', + $clean_html + ); + + $inline_atts_exclusions = $this->validate_array_and_quote( + /** + * Filters the array of inline CSS attributes patterns to preserve + * + * @since 3.11 + * + * @param array $inline_atts_exclusions Array of patterns used to match against the inline CSS attributes. + */ + (array) apply_filters( 'rocket_rucss_inline_atts_exclusions', $this->inline_atts_exclusions ) + ); + + $inline_content_exclusions = $this->validate_array_and_quote( + /** + * Filters the array of inline CSS content patterns to preserve + * + * @since 3.11 + * + * @param array $inline_atts_exclusions Array of patterns used to match against the inline CSS content. + */ + (array) apply_filters( 'rocket_rucss_inline_content_exclusions', $this->inline_content_exclusions ) + ); + + foreach ( $inline_styles as $style ) { + if ( ! empty( $inline_atts_exclusions ) && $this->find( implode( '|', $inline_atts_exclusions ), $style['atts'] ) ) { + continue; + } + + if ( ! empty( $inline_content_exclusions ) && $this->find( implode( '|', $inline_content_exclusions ), $style['content'] ) ) { + continue; + } + + /** + * Filters the status of preserving inline style tags. + * + * @since 3.11.4 + * + * @param bool $preserve_status Status of preserve. + * @param array $style Full match style tag. + */ + if ( apply_filters( 'rocket_rucss_preserve_inline_style_tags', true, $style ) ) { + $content = trim( $style['content'] ); + + if ( empty( $content ) ) { + continue; + } + + $empty_tag = str_replace( $style['content'], '', $style[0] ); + $html = str_replace( $style[0], $empty_tag, $html ); + + continue; + } + + $html = str_replace( $style[0], '', $html ); + } + + return $html; + } + + /** + * Alter HTML string and add the used CSS style in tag, + * + * @param string $html HTML content. + * @param string $used_css Used CSS content. + * + * @return string HTML content. + */ + private function add_used_css_to_html( string $html, string $used_css ): string { + $replace = preg_replace( + '##iU', + '' . $this->get_used_css_markup( $used_css ), + $html, + 1 + ); + + if ( null === $replace ) { + return $html; + } + + return $replace; + } + + /** + * Return Markup for used_css into the page. + * + * @param string $used_css Used CSS content. + * + * @return string + */ + private function get_used_css_markup( string $used_css ): string { + /** + * Filters Used CSS content before output. + * + * @since 3.9.0.2 + * + * @param string $used_css Used CSS content. + */ + $used_css = apply_filters( 'rocket_usedcss_content', $used_css ); + + $used_css = str_replace( '\\', '\\\\', $used_css );// Guard the backslashes before passing the content to preg_replace. + $used_css = $this->handle_charsets( $used_css, false ); + + return sprintf( + '', + $used_css + ); + } + + /** + * Determines if the page is mobile and separate cache for mobile files is enabled. + * + * @return boolean + */ + private function is_mobile(): bool { + return $this->options->get( 'cache_mobile', 0 ) + && $this->options->get( 'do_caching_mobile_files', 0 ) + && wp_is_mobile(); + } + + /** + * Clear specific url. + * + * @param string $url Page url. + * + * @return void + */ + public function clear_url_usedcss( string $url ) { + $this->delete_used_css( $url ); + + /** + * Fires after clearing usedcss for specific url. + * + * @since 3.11 + * + * @param string $url Current page URL. + */ + do_action( 'rocket_rucss_after_clearing_usedcss', $url ); + } + + /** + * Get the count of not completed rows. + * + * @return int + */ + public function get_not_completed_count() { + return $this->used_css_query->get_not_completed_count(); + } + + /** + * Add preload links for the fonts in the used CSS + * + * @param string $html HTML content. + * @param string $used_css Used CSS content. + * + * @return string + */ + private function add_used_fonts_preload( string $html, string $used_css ): string { + /** + * Filters the fonts preload from the used CSS + * + * @since 3.11 + * + * @param bool $enable True to enable, false to disable. + */ + if ( ! apply_filters( 'rocket_enable_rucss_fonts_preload', true ) ) { + return $html; + } + + if ( ! preg_match_all( '/@font-face\s*{\s*(?[^}]+)}/is', $used_css, $font_faces, PREG_SET_ORDER ) ) { + return $html; + } + + if ( empty( $font_faces ) ) { + return $html; + } + + /** + * Filters the list of fonts to exclude from preload + * + * @since 3.15.10 + * + * @param array $excluded_fonts_preload List of fonts to exclude from preload + */ + $exclude_fonts_preload = apply_filters( 'rocket_exclude_rucss_fonts_preload', [] ); + if ( ! is_array( $exclude_fonts_preload ) ) { + $exclude_fonts_preload = []; + } + + $urls = []; + + foreach ( $font_faces as $font_face ) { + if ( empty( $font_face['content'] ) ) { + continue; + } + + $font_url = $this->extract_first_font( $font_face['content'] ); + + /** + * Filters font URL with CDN hostname + * + * @since 3.11.4 + * + * @param string $url url to be rewritten. + */ + $font_url = apply_filters( 'rocket_font_url', $font_url ); + + if ( empty( $font_url ) ) { + continue; + } + + // Making sure the excluded fonts array isn't empty to avoid excluding all fonts. + if ( ! empty( $exclude_fonts_preload ) ) { + // Combine the array elements into a single string with | as a separator and returning a pattern. + $exclude_fonts_preload_pattern = implode( + '|', + array_map( + function ( $item ) { + return is_string( $item ) ? preg_quote( $item, '/' ) : ''; + }, + $exclude_fonts_preload + ) + ); + + // Check if the font URL matches any part of the exclude_fonts_preload array. + if ( ! empty( $exclude_fonts_preload_pattern ) && preg_match( '/' . $exclude_fonts_preload_pattern . '/i', $font_url ) ) { + continue; // Skip this iteration as the font URL is in the exclusion list. + } + } + + $urls[] = $font_url; + } + + if ( empty( $urls ) ) { + return $html; + } + + $urls = array_unique( $urls ); + + $replace = preg_replace( + '##iU', + '' . $this->preload_links( $urls ), + $html, + 1 + ); + + if ( null === $replace ) { + return $html; + } + + return $replace; + } + + /** + * Remove preconnect tag for google api. + * + * @param string $html html content. + * + * @return string + */ + protected function remove_google_font_preconnect( string $html ): string { + $clean_html = $this->hide_comments( $html ); + $clean_html = $this->hide_noscripts( $clean_html ); + $clean_html = $this->hide_scripts( $clean_html ); + $links = $this->find( + ']+[\s"\'])?rel\s*=\s*[\'"]((preconnect)|(dns-prefetch))[\'"]([^>]+)?\/?>', + $clean_html, + 'Uis' + ); + + foreach ( $links as $link ) { + if ( preg_match( '/href=[\'"](https:)?\/\/fonts.googleapis.com\/?[\'"]/', $link[0] ) ) { + $html = str_replace( $link[0], '', $html ); + } + } + + return $html; + } + + /** + * Extracts the first font URL from the font-face declaration + * + * Skips .eot fonts if it exists + * + * @since 3.11 + * + * @param string $font_face Font-face declaration content. + * + * @return string + */ + private function extract_first_font( string $font_face ): string { + if ( ! preg_match_all( '/src:\s*(?[^;}]*)/is', $font_face, $sources, PREG_SET_ORDER ) ) { + return ''; + } + + foreach ( $sources as $src ) { + if ( empty( $src['urls'] ) ) { + continue; + } + + $urls = explode( ',', $src['urls'] ); + + foreach ( $urls as $url ) { + if ( false !== strpos( $url, '.eot' ) ) { + continue; + } + + if ( ! preg_match( '/url\(\s*[\'"]?(?[^\'")]+)[\'"]?\)/is', $url, $matches ) ) { + continue; + } + + return trim( $matches['url'] ); + } + } + + return ''; + } + + /** + * Converts an array of URLs to preload link tags + * + * @param array $urls An array of URLs. + * + * @return string + */ + private function preload_links( array $urls ): string { + $links = ''; + + foreach ( $urls as $url ) { + $links .= ''; + } + + return $links; + } + + /** + * Set Rucss inline attr exclusions + * + * @return void + */ + private function set_inline_exclusions_lists() { + $wpr_dynamic_lists = $this->data_manager->get_lists(); + $this->inline_atts_exclusions = isset( $wpr_dynamic_lists->rucss_inline_atts_exclusions ) ? $wpr_dynamic_lists->rucss_inline_atts_exclusions : []; + $this->inline_content_exclusions = isset( $wpr_dynamic_lists->rucss_inline_content_exclusions ) ? $wpr_dynamic_lists->rucss_inline_content_exclusions : []; + } + + /** + * Displays a notice if the used CSS folder is not writable + * + * @since 3.11.4 + * + * @return void + */ + public function notice_write_permissions() { + if ( ! current_user_can( 'rocket_manage_options' ) ) { + return; + } + + if ( ! $this->is_enabled() ) { + return; + } + + if ( $this->filesystem->is_writable_folder() ) { + return; + } + + $message = rocket_notice_writing_permissions( trim( str_replace( rocket_get_constant( 'ABSPATH', '' ), '', rocket_get_constant( 'WP_ROCKET_USED_CSS_PATH', '' ) ), '/' ) ); + + rocket_notice_html( + [ + 'status' => 'error', + 'dismissible' => '', + 'message' => $message, + ] + ); + } + + /** + * Validate the items in array to be strings only and preg_quote them. + * + * @param array $items Array to be validated and quoted. + * + * @return array|string[] + */ + private function validate_array_and_quote( array $items ) { + $items_array = array_filter( $items, 'is_string' ); + + return array_map( + static function ( $item ) { + return preg_quote( $item, '/' ); + }, + $items_array + ); + } + + /** + * Check if database has at least one completed row. + * + * @return bool + */ + public function has_one_completed_row_at_least() { + return $this->used_css_query->get_completed_count() > 0; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Cron/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Cron/Subscriber.php new file mode 100644 index 000000000..82a3b6b58 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Cron/Subscriber.php @@ -0,0 +1,62 @@ +job_processor = $job_processor; + $this->used_css_query = $used_css_query; + } + + /** + * Return an array of events that this subscriber listens to. + * + * @return array + */ + public static function get_subscribed_events(): array { + return [ + 'rocket_rucss_job_check_status' => 'check_job_status', + ]; + } + + /** + * Handle old rucss job during upgrade from versions < 3.16. + * + * @param integer $row_id DB Row ID. + * @return void + */ + public function check_job_status( int $row_id ): void { + $row = $this->used_css_query->get_row_by_id( $row_id ); + + if ( ! $row ) { + return; + } + + $this->job_processor->check_job_status( $row->url, $row->is_mobile, 'rucss' ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Queries/UsedCSS.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Queries/UsedCSS.php new file mode 100644 index 000000000..89ed6188b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Queries/UsedCSS.php @@ -0,0 +1,128 @@ +table_exists() ) { + return false; + } + + // Get the database interface. + $db = $this->get_db(); + + // Bail if no database interface is available. + if ( empty( $db ) ) { + return false; + } + + $prefixed_table_name = $db->prefix . $this->table_name; + + $data = [ + 'hash' => $hash, + 'status' => 'completed', + ]; + + $where = [ + 'url' => untrailingslashit( $url ), + 'is_mobile' => $is_mobile, + ]; + + return $db->update( $prefixed_table_name, $data, $where ); + } + + /** + * Get number of rows with the same hash value. + * + * @param string $hash Hash. + * + * @return int + */ + public function count_rows_by_hash( string $hash ): int { + if ( ! self::$table_exists && ! $this->table_exists() ) { + return 0; + } + + return $this->query( + [ + 'hash' => $hash, + 'count' => true, + ] + ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Row/UsedCSS.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Row/UsedCSS.php new file mode 100644 index 000000000..69ef32cef --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Row/UsedCSS.php @@ -0,0 +1,148 @@ +id = (int) $this->id; + $this->url = (string) $this->url; + $this->css = (string) $this->css; + $this->hash = (string) $this->hash; + $this->error_code = (string) $this->error_code; + $this->error_message = (string) $this->error_message; + $this->retries = (int) $this->retries; + $this->is_mobile = (bool) $this->is_mobile; + $this->job_id = (string) $this->job_id; + $this->queue_name = (string) $this->queue_name; + $this->status = (string) $this->status; + $this->modified = empty( $this->modified ) ? 0 : strtotime( $this->modified ); + $this->last_accessed = empty( $this->last_accessed ) ? 0 : strtotime( $this->last_accessed ); + $this->submitted_at = empty( $this->submitted_at ) ? 0 : strtotime( $this->submitted_at ); + $this->next_retry_time = empty( $this->next_retry_time ) ? 0 : strtotime( $this->next_retry_time ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Schemas/UsedCSS.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Schemas/UsedCSS.php new file mode 100644 index 000000000..3adf0b002 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Schemas/UsedCSS.php @@ -0,0 +1,177 @@ + 'id', + 'type' => 'bigint', + 'length' => '20', + 'unsigned' => true, + 'extra' => 'auto_increment', + 'primary' => true, + 'sortable' => true, + ], + + // URL column. + [ + 'name' => 'url', + 'type' => 'varchar', + 'length' => '2000', + 'default' => '', + 'cache_key' => true, + 'searchable' => true, + 'sortable' => true, + ], + + // CSS column. + [ + 'name' => 'css', + 'type' => 'longtext', + 'default' => null, + 'cache_key' => false, + 'searchable' => true, + 'sortable' => true, + ], + + // Hash column. + [ + 'name' => 'hash', + 'type' => 'varchar', + 'length' => '32', + 'default' => '', + 'cache_key' => false, + 'searchable' => true, + 'sortable' => true, + ], + + // error_code column. + [ + 'name' => 'error_code', + 'type' => 'varchar', + 'length' => '32', + 'default' => null, + 'cache_key' => false, + 'searchable' => true, + 'sortable' => true, + ], + + // error_message column. + [ + 'name' => 'error_message', + 'type' => 'longtext', + 'default' => null, + 'cache_key' => false, + 'searchable' => true, + 'sortable' => true, + ], + + // RETRIES column. + [ + 'name' => 'retries', + 'type' => 'tinyint', + 'length' => '1', + 'default' => 1, + 'cache_key' => false, + 'searchable' => true, + 'sortable' => true, + ], + + // IS_MOBILE column. + [ + 'name' => 'is_mobile', + 'type' => 'tinyint', + 'length' => '1', + 'default' => 0, + 'cache_key' => true, + 'searchable' => true, + 'sortable' => true, + ], + + // JOB_ID column. + [ + 'name' => 'job_id', + 'type' => 'varchar', + 'length' => '255', + 'default' => null, + 'cache_key' => true, + 'searchable' => false, + 'sortable' => false, + ], + + // QUEUE_NAME column. + [ + 'name' => 'queue_name', + 'type' => 'varchar', + 'length' => '255', + 'default' => null, + 'cache_key' => true, + 'searchable' => false, + 'sortable' => false, + ], + + // STATUS column. + [ + 'name' => 'status', + 'type' => 'varchar', + 'length' => '255', + 'default' => null, + 'cache_key' => true, + 'searchable' => true, + 'sortable' => false, + ], + + // MODIFIED column. + [ + 'name' => 'modified', + 'type' => 'timestamp', + 'default' => '0000-00-00 00:00:00', + 'modified' => true, + 'date_query' => true, + 'sortable' => true, + ], + + // LAST_ACCESSED column. + [ + 'name' => 'last_accessed', + 'type' => 'timestamp', + 'default' => '0000-00-00 00:00:00', + 'date_query' => true, + 'sortable' => true, + ], + + // SUBMITTED_AT column. + [ + 'name' => 'submitted_at', + 'type' => 'timestamp', + 'default' => null, + 'created' => true, + 'date_query' => true, + 'sortable' => true, + ], + + // NEXT_RETRY_TIME column. + [ + 'name' => 'next_retry_time', + 'type' => 'timestamp', + 'default' => '0000-00-00 00:00:00', + 'created' => true, + 'date_query' => true, + 'sortable' => true, + ], + ]; +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Tables/UsedCSS.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Tables/UsedCSS.php new file mode 100644 index 000000000..6bf714a8b --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Database/Tables/UsedCSS.php @@ -0,0 +1,260 @@ + value array of versions => methods. + * + * @var array + */ + protected $upgrades = [ + 20220121 => 'add_async_rucss_columns', + 20220131 => 'make_status_column_index', + 20220513 => 'add_hash_column', + 20220920 => 'make_status_column_index_instead_queue_name', + 20221104 => 'add_error_columns', + 20231010 => 'add_submitted_at_column', + 20231031 => 'add_next_retry_time_column', + ]; + + /** + * Table schema data. + * + * @var string + */ + protected $schema_data = " + id bigint(20) unsigned NOT NULL AUTO_INCREMENT, + url varchar(2000) NOT NULL default '', + css longtext default NULL, + hash varchar(32) default '', + error_code varchar(32) NULL default NULL, + error_message longtext NULL default NULL, + unprocessedcss longtext NULL, + retries tinyint(1) NOT NULL default 1, + is_mobile tinyint(1) NOT NULL default 0, + job_id varchar(255) NOT NULL default '', + queue_name varchar(255) NOT NULL default '', + status varchar(255) NOT NULL default '', + modified timestamp NOT NULL default '0000-00-00 00:00:00', + last_accessed timestamp NOT NULL default '0000-00-00 00:00:00', + submitted_at timestamp NULL, + next_retry_time timestamp NOT NULL default '0000-00-00 00:00:00', + PRIMARY KEY (id), + KEY url (url(150), is_mobile), + KEY modified (modified), + KEY last_accessed (last_accessed), + INDEX `status_index` (`status`(191)), + INDEX `error_code_index` (`error_code`(32)), + KEY hash (hash)"; + + /** + * Add queue columns. + * + * @return bool + */ + protected function add_async_rucss_columns() { + $jobid_column_exists = $this->column_exists( 'job_id' ); + $queuename_column_exists = $this->column_exists( 'queue_name' ); + $status_column_exists = $this->column_exists( 'status' ); + + $created = true; + + if ( ! $jobid_column_exists ) { + $created &= $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN job_id VARCHAR(255) NULL default '' AFTER is_mobile " ); + } + if ( ! $queuename_column_exists ) { + $created &= $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN queue_name VARCHAR(255) NULL default '' AFTER job_id " ); + } + if ( ! $status_column_exists ) { + $created &= $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN status VARCHAR(255) NULL default '' AFTER queue_name " ); + } + + return $this->is_success( $created ); + } + + /** + * Make status column as index. + * + * @return bool + */ + protected function make_status_column_index() { + $queuename_column_exists = $this->column_exists( 'queue_name' ); + if ( ! $queuename_column_exists ) { + return $this->is_success( false ); + } + + if ( $this->index_exists( 'queue_name_index' ) ) { + return $this->is_success( true ); + } + + $index_added = $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD INDEX `queue_name_index` (`queue_name`) " ); + return $this->is_success( $index_added ); + } + + /** + * Add hash column and index + * + * @return bool + */ + protected function add_hash_column() { + $hash_column_exists = $this->column_exists( 'hash' ); + + $created = true; + + if ( ! $hash_column_exists ) { + $created &= $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD COLUMN hash VARCHAR(32) NULL default '' AFTER css, ADD KEY hash (hash) " ); + } + + return $this->is_success( $created ); + } + + /** + * Make status column as index. + * + * @return bool + */ + protected function make_status_column_index_instead_queue_name() { + $queuename_column_exists = $this->column_exists( 'status' ); + if ( ! $queuename_column_exists ) { + return $this->is_success( false ); + } + + if ( $this->index_exists( 'status_index' ) ) { + return $this->is_success( true ); + } + + if ( $this->index_exists( 'queue_name_index' ) ) { + if ( ! $this->get_db()->query( "ALTER TABLE {$this->table_name} DROP INDEX `queue_name_index`" ) ) { + return $this->is_success( false ); + } + } + + $index_added = $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD INDEX `status_index` (`status`(191)) " ); + + return $this->is_success( $index_added ); + } + + /** + * Add error columns + * + * @return bool + */ + protected function add_error_columns() { + return $this->add_error_message_column() && $this->add_error_code_column() && $this->make_error_code_column_index(); + } + + /** + * Add error_message column and index + * + * @return bool + */ + private function add_error_message_column() { + $error_message_column_exists = $this->column_exists( 'error_message' ); + + $created = true; + + if ( ! $error_message_column_exists ) { + $created &= $this->get_db()->query( "ALTER TABLE `{$this->table_name}` ADD COLUMN error_message longtext NULL default NULL AFTER hash" ); + } + + return $this->is_success( $created ); + } + + /** + * Add error_code column and index + * + * @return bool + */ + private function add_error_code_column() { + $error_code_column_exists = $this->column_exists( 'error_code' ); + + $created = true; + + if ( ! $error_code_column_exists ) { + $created &= $this->get_db()->query( "ALTER TABLE `{$this->table_name}` ADD COLUMN error_code VARCHAR(32) NULL default NULL AFTER hash" ); + } + + return $this->is_success( $created ); + } + + /** + * Make status column as index. + * + * @return bool + */ + private function make_error_code_column_index() { + $error_code_column_exists = $this->column_exists( 'error_code' ); + if ( ! $error_code_column_exists ) { + return $this->is_success( false ); + } + + if ( $this->index_exists( 'error_code_index' ) ) { + return $this->is_success( true ); + } + + $index_added = $this->get_db()->query( "ALTER TABLE {$this->table_name} ADD INDEX `error_code_index` (`error_code`) " ); + return $this->is_success( $index_added ); + } + + /** + * Adds the submitted_at column + * + * @return bool + */ + protected function add_submitted_at_column() { + $submitted_at_column_exists = $this->column_exists( 'submitted_at' ); + + $created = true; + + if ( ! $submitted_at_column_exists ) { + $created &= $this->get_db()->query( "ALTER TABLE `{$this->table_name}` ADD COLUMN submitted_at timestamp NULL AFTER last_accessed" ); + } + + return $this->is_success( $created ); + } + + /** + * Adds the next_retry_time column + * + * @return bool + */ + protected function add_next_retry_time_column() { + $next_retry_time_exists = $this->column_exists( 'next_retry_time' ); + + $created = true; + + if ( ! $next_retry_time_exists ) { + $created &= $this->get_db()->query( "ALTER TABLE `{$this->table_name}` ADD COLUMN next_retry_time timestamp NOT NULL default '0000-00-00 00:00:00' AFTER submitted_at" ); + } + + return $this->is_success( $created ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Frontend/Subscriber.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Frontend/Subscriber.php new file mode 100644 index 000000000..751b2f153 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Frontend/Subscriber.php @@ -0,0 +1,116 @@ +used_css = $used_css; + $this->context = $context; + } + + /** + * Return an array of events that this subscriber listens to. + * + * @return array + */ + public static function get_subscribed_events(): array { + return [ + 'rocket_buffer' => [ 'treeshake', 1000 ], + 'rocket_disable_preload_fonts' => 'maybe_disable_preload_fonts', + 'rocket_first_install_options' => 'on_install', + 'wp_rocket_upgrade' => [ 'on_update', 10, 2 ], + ]; + } + + /** + * Apply TreeShaked CSS to the current HTML page. + * + * @param string $html HTML content. + * + * @return string HTML content. + */ + public function treeshake( string $html ): string { + return $this->used_css->treeshake( $html ); + } + + /** + * Disables the preload fonts if RUCSS is enabled + * + * @since 3.9 + * + * @param bool $value Value for the disable preload fonts filter. + * + * @return bool + */ + public function maybe_disable_preload_fonts( $value ): bool { + if ( $this->context->is_allowed() ) { + return true; + } + + return $value; + } + + /** + * Add option on update. + * + * @param string $new_version New plugin version. + * @param string $old_version Previous plugin version. + * + * @return void + */ + public function on_update( $new_version, $old_version ) { + if ( version_compare( $old_version, '3.15', '>=' ) ) { + return; + } + + $default = 0; + + if ( get_transient( 'wp_rocket_no_licence' ) ) { + $default = get_transient( 'wp_rocket_no_licence' ); + delete_transient( 'wp_rocket_no_licence' ); + } + + update_option( 'wp_rocket_no_licence', $default ); + } + + /** + * Add option on installation. + * + * @param array $options WP Rocket options array. + * + * @return array + */ + public function on_install( $options ) { + + update_option( 'wp_rocket_no_licence', 0 ); + + return $options; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Jobs/Factory.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Jobs/Factory.php new file mode 100644 index 000000000..ccb4fd830 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Jobs/Factory.php @@ -0,0 +1,54 @@ +manager = $manager; + $this->table = $table; + } + + /** + * RUCSS job manager. + * + * @return ManagerInterface + */ + public function manager(): ManagerInterface { + return $this->manager; + } + + /** + * RUCSS Table. + * + * @return TableInterface + */ + public function table(): TableInterface { + return $this->table; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Jobs/Manager.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Jobs/Manager.php new file mode 100644 index 000000000..b31507dad --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/Jobs/Manager.php @@ -0,0 +1,222 @@ +query = $query; + $this->filesystem = $filesystem; + $this->context = $context; + $this->options = $options; + } + + /** + * Get pending jobs from db. + * + * @param integer $num_rows Number of rows to grab. + * @return array + */ + public function get_pending_jobs( int $num_rows ): array { + $this->logger::debug( "RUCSS: Start getting number of {$num_rows} pending jobs." ); + + $pending_jobs = $this->query->get_pending_jobs( $num_rows ); + + if ( ! $pending_jobs ) { + $this->logger::debug( 'RUCSS: No pending jobs are there.' ); + + return []; + } + + return $pending_jobs; + } + + /** + * Validate SaaS response and fail job. + * + * @param array $job_details Details related to the job.. + * @param object $row_details Details related to the row. + * @param string $optimization_type The type of optimization applied for the current job. + * + * @return void + */ + public function validate_and_fail( array $job_details, $row_details, string $optimization_type ): void { + if ( 'all' !== $optimization_type || $this->optimization_type !== $optimization_type ) { + return; + } + + /** + * Filters the rocket min rucss css result size. + * + * @since 3.13.3 + * + * @param int $min_rucss_size min size. + */ + $min_rucss_size = apply_filters( 'rocket_min_rucss_size', 150 ); + if ( ! is_numeric( $min_rucss_size ) ) { + $min_rucss_size = 150; + } + + if ( isset( $job_details['contents']['shakedCSS_size'] ) && intval( $job_details['contents']['shakedCSS_size'] ) < $min_rucss_size ) { + $message = 'RUCSS: shakedCSS size is less than ' . $min_rucss_size; + $this->logger::error( $message ); + $this->make_status_failed( $row_details->url, $row_details->is_mobile, '500', $message ); + + $this->can_process = false; + } + } + + /** + * Process SaaS response. + * + * @param array $job_details Details related to the job.. + * @param object $row_details Details related to the row. + * @param string $optimization_type The type of optimization applied for the current job. + * + * @return void + */ + public function process( array $job_details, $row_details, string $optimization_type ): void { + if ( ! $this->is_allowed( $optimization_type ) || ! $this->can_process ) { + return; + } + + $css = $this->apply_font_display_swap( $job_details['contents']['shakedCSS'] ); + + /** + * RUCSS hash. + * + * @param string $hash RUCSS hash. + * @param string $css RUCSS content. + * @param UsedCSSRow $row_details Job details. + */ + $hash = (string) apply_filters( 'rocket_rucss_hash', md5( $css ), $css, $row_details ); + + if ( ! $this->filesystem->write_used_css( $hash, $css ) ) { + $message = 'RUCSS: Could not write used CSS to the filesystem: ' . $row_details->url; + $this->logger::error( $message ); + $this->query->make_status_failed( $row_details->url, $row_details->is_mobile, '', $job_details['message'] ); + + return; + } + + // Everything is fine, save the usedcss into DB, change status to completed and reset queue_name and job_id. + $this->logger::debug( 'RUCSS: Save used CSS for url: ' . $row_details->url ); + $this->query->make_status_completed( $row_details->url, $row_details->is_mobile, $hash ); + } + + /** + * Set the request parameter to be sent to the SaaS + * + * @return array + */ + public function set_request_param(): array { + /** + * Filters the RUCSS safelist + * + * @since 3.11 + * + * @param array $safelist Array of safelist values. + */ + $safelist = apply_filters( 'rocket_rucss_safelist', $this->options->get( 'remove_unused_css_safelist', [] ) ); + + /** + * Filters the styles attributes to be skipped (blocked) by RUCSS. + * + * @since 3.14 + * + * @param array $skipped_attr Array of safelist values. + */ + $skipped_attr = apply_filters( 'rocket_rucss_skip_styles_with_attr', [] ); + $skipped_attr = ( is_array( $skipped_attr ) ) ? $skipped_attr : []; + + return [ + 'rucss_safelist' => $safelist, + 'skip_attr' => $skipped_attr, + 'optimization_list' => [ + 'rucss', + ], + ]; + } + + /** + * Get the optimization type from the DB Row. + * + * @param object $row DB Row Object. + * @return boolean|string + */ + public function get_optimization_type_from_row( $row ) { + if ( ! isset( $row->css ) ) { + return false; + } + + return $this->optimization_type; + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/ServiceProvider.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/ServiceProvider.php new file mode 100644 index 000000000..3e4bef6c3 --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RUCSS/ServiceProvider.php @@ -0,0 +1,131 @@ +provides, true ); + } + + /** + * Registers the option array in the container + * + * @return void + */ + public function register(): void { + + $this->getContainer()->addShared( 'rucss_usedcss_table', UsedCSSTable::class ); + $this->getContainer()->add( 'rucss_database', Database::class ) + ->addArgument( $this->getContainer()->get( 'rucss_usedcss_table' ) ); + + $this->getContainer()->add( 'rucss_settings', Settings::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'beacon' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_usedcss_table' ) ); + + $this->getContainer()->add( 'rucss_used_css_query', UsedCSSQuery::class ); + $this->getContainer()->add( 'rucss_queue', Queue::class ); + $this->getContainer()->add( 'rucss_filesystem', Filesystem::class ) + ->addArgument( rocket_get_constant( 'WP_ROCKET_USED_CSS_PATH' ) ) + ->addArgument( rocket_direct_filesystem() ); + + $this->getContainer()->add( 'rucss_context', RUCSSContext::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_filesystem' ) ); + + $this->getContainer()->add( 'rucss_optimize_context', RUCSSOptimizeContext::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + + $this->getContainer()->add( 'rucss_context_saas', RUCSSContextSaas::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ); + + $this->getContainer()->add( 'rucss_manager', Manager::class ) + ->addArguments( + [ + $this->getContainer()->get( 'rucss_used_css_query' ), + $this->getContainer()->get( 'rucss_filesystem' ), + $this->getContainer()->get( 'rucss_context_saas' ), + $this->getContainer()->get( 'options' ), + ] + ); + + $this->getContainer()->addShared( 'rucss_factory', Factory::class ) + ->addArguments( + [ + $this->getContainer()->get( 'rucss_manager' ), + $this->getContainer()->get( 'rucss_usedcss_table' ), + ] + ); + + $this->getContainer()->add( 'rucss_used_css_controller', UsedCSSController::class ) + ->addArgument( $this->getContainer()->get( 'options' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_used_css_query' ) ) + ->addArgument( $this->getContainer()->get( 'dynamic_lists_defaultlists_data_manager' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_filesystem' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_context' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_manager' ) ); + + $this->getContainer()->addShared( 'rucss_option_subscriber', OptionSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'rucss_settings' ) ); + $this->getContainer()->addShared( 'rucss_admin_subscriber', AdminSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'rucss_settings' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_database' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_used_css_controller' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_queue' ) ); + $this->getContainer()->addShared( 'rucss_frontend_subscriber', FrontendSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'rucss_used_css_controller' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_context' ) ); + + $this->getContainer()->addShared( 'rucss_cron_subscriber', CronSubscriber::class ) + ->addArgument( $this->getContainer()->get( 'job_processor' ) ) + ->addArgument( $this->getContainer()->get( 'rucss_used_css_query' ) ); + } +} diff --git a/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RegexTrait.php b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RegexTrait.php new file mode 100644 index 000000000..e117df96c --- /dev/null +++ b/wp-content/plugins/wp-rocket/inc/Engine/Optimization/RegexTrait.php @@ -0,0 +1,265 @@ +.*?#is', '', $html ); + + if ( null === $replace ) { + return $html; + } + + $replace = preg_replace( '//Uis', '', $replace ); + + if ( null === $replace ) { + return $html; + } + + return $replace; + } + + /** + * Hides scripts from the HTML to be parsed when removing CSS from it + * + * @since 3.10.2 + * + * @param string $html HTML content. + * + * @return string + */ + protected function hide_scripts( $html ) { + $replace = preg_replace( '#]*>.*?<\/script\s*>#mis', '', $html ); + + if ( null === $replace ) { + return $html; + } + + return $replace; + } + + /** + * Hides