From 7131d9e9bd99b145808e3975fa0945da67274026 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 27 Aug 2019 11:40:39 +0200 Subject: [PATCH] forward-compatibility with HttpKernel 5 --- .../CacheWarmer/TemplateFinder.php | 10 +++--- .../Command/TranslationDebugCommand.php | 13 ++++---- .../Command/TranslationUpdateCommand.php | 9 +++-- .../FrameworkExtension.php | 23 +++++++++++-- .../Resources/config/services.xml | 5 --- .../Resources/config/templating.xml | 1 - .../DependencyInjection/TwigExtension.php | 33 +++++++++++++------ .../TwigBundle/Resources/config/console.xml | 2 +- .../TwigBundle/Resources/config/twig.xml | 2 +- .../Bundle/TwigBundle/TemplateIterator.php | 8 ++--- 10 files changed, 65 insertions(+), 41 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php index f49e856c81aab..64633249e92d3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php @@ -34,9 +34,9 @@ class TemplateFinder implements TemplateFinderInterface private $templates; /** - * @param string $rootDir The directory where global templates can be stored + * @param string|null $rootDir The directory where global templates can be stored */ - public function __construct(KernelInterface $kernel, TemplateNameParserInterface $parser, string $rootDir) + public function __construct(KernelInterface $kernel, TemplateNameParserInterface $parser, string $rootDir = null) { $this->kernel = $kernel; $this->parser = $parser; @@ -60,7 +60,9 @@ public function findAllTemplates() $templates = array_merge($templates, $this->findTemplatesInBundle($bundle)); } - $templates = array_merge($templates, $this->findTemplatesInFolder($this->rootDir.'/views')); + if (null !== $this->rootDir) { + $templates = array_merge($templates, $this->findTemplatesInFolder($this->rootDir.'/views')); + } return $this->templates = $templates; } @@ -99,7 +101,7 @@ private function findTemplatesInBundle(BundleInterface $bundle): array $name = $bundle->getName(); $templates = array_unique(array_merge( $this->findTemplatesInFolder($bundle->getPath().'/Resources/views'), - $this->findTemplatesInFolder($this->rootDir.'/'.$name.'/views') + null !== $this->rootDir ? $this->findTemplatesInFolder($this->rootDir.'/'.$name.'/views') : [] )); foreach ($templates as $i => $template) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php index 85c1e52905758..029c12bb51572 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php @@ -132,11 +132,10 @@ protected function execute(InputInterface $input, OutputInterface $output) $domain = $input->getOption('domain'); /** @var KernelInterface $kernel */ $kernel = $this->getApplication()->getKernel(); - $rootDir = $kernel->getContainer()->getParameter('kernel.root_dir'); // Define Root Paths $transPaths = $this->transPaths; - if (is_dir($dir = $rootDir.'/Resources/translations')) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($dir = $kernel->getContainer()->getParameter('kernel.root_dir').'/Resources/translations')) { if ($dir !== $this->defaultTransPath) { $notice = sprintf('Storing translations in the "%s" directory is deprecated since Symfony 4.2, ', $dir); @trigger_error($notice.($this->defaultTransPath ? sprintf('use the "%s" directory instead.', $this->defaultTransPath) : 'configure and use "framework.translator.default_path" instead.'), E_USER_DEPRECATED); @@ -147,7 +146,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $transPaths[] = $this->defaultTransPath; } $viewsPaths = $this->viewsPaths; - if (is_dir($dir = $rootDir.'/Resources/views')) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($dir = $kernel->getContainer()->getParameter('kernel.root_dir').'/Resources/views')) { if ($dir !== $this->defaultViewsPath) { $notice = sprintf('Loading Twig templates from the "%s" directory is deprecated since Symfony 4.2, ', $dir); @trigger_error($notice.($this->defaultViewsPath ? sprintf('use the "%s" directory instead.', $this->defaultViewsPath) : 'configure and use "twig.default_path" instead.'), E_USER_DEPRECATED); @@ -168,7 +167,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($this->defaultTransPath) { $transPaths[] = $this->defaultTransPath; } - if (is_dir($dir = sprintf('%s/Resources/%s/translations', $rootDir, $bundle->getName()))) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($dir = sprintf('%s/Resources/%s/translations', $kernel->getContainer()->getParameter('kernel.root_dir'), $bundle->getName()))) { $transPaths[] = $dir; $notice = sprintf('Storing translations files for "%s" in the "%s" directory is deprecated since Symfony 4.2, ', $dir, $bundle->getName()); @trigger_error($notice.($this->defaultTransPath ? sprintf('use the "%s" directory instead.', $this->defaultTransPath) : 'configure and use "framework.translator.default_path" instead.'), E_USER_DEPRECATED); @@ -176,7 +175,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if ($this->defaultViewsPath) { $viewsPaths[] = $this->defaultViewsPath; } - if (is_dir($dir = sprintf('%s/Resources/%s/views', $rootDir, $bundle->getName()))) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($dir = sprintf('%s/Resources/%s/views', $kernel->getContainer()->getParameter('kernel.root_dir'), $bundle->getName()))) { $viewsPaths[] = $dir; $notice = sprintf('Loading Twig templates for "%s" from the "%s" directory is deprecated since Symfony 4.2, ', $bundle->getName(), $dir); @trigger_error($notice.($this->defaultViewsPath ? sprintf('use the "%s" directory instead.', $this->defaultViewsPath) : 'configure and use "twig.default_path" instead.'), E_USER_DEPRECATED); @@ -210,12 +209,12 @@ protected function execute(InputInterface $input, OutputInterface $output) $bundleDir = $bundle->getPath(); $transPaths[] = is_dir($bundleDir.'/Resources/translations') ? $bundleDir.'/Resources/translations' : $bundle->getPath().'/translations'; $viewsPaths[] = is_dir($bundleDir.'/Resources/views') ? $bundleDir.'/Resources/views' : $bundle->getPath().'/templates'; - if (is_dir($deprecatedPath = sprintf('%s/Resources/%s/translations', $rootDir, $bundle->getName()))) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($deprecatedPath = sprintf('%s/Resources/%s/translations', $kernel->getContainer()->getParameter('kernel.root_dir'), $bundle->getName()))) { $transPaths[] = $deprecatedPath; $notice = sprintf('Storing translations files for "%s" in the "%s" directory is deprecated since Symfony 4.2, ', $bundle->getName(), $deprecatedPath); @trigger_error($notice.($this->defaultTransPath ? sprintf('use the "%s" directory instead.', $this->defaultTransPath) : 'configure and use "framework.translator.default_path" instead.'), E_USER_DEPRECATED); } - if (is_dir($deprecatedPath = sprintf('%s/Resources/%s/views', $rootDir, $bundle->getName()))) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($deprecatedPath = sprintf('%s/Resources/%s/views', $kernel->getContainer()->getParameter('kernel.root_dir'), $bundle->getName()))) { $viewsPaths[] = $deprecatedPath; $notice = sprintf('Loading Twig templates for "%s" from the "%s" directory is deprecated since Symfony 4.2, ', $bundle->getName(), $deprecatedPath); @trigger_error($notice.($this->defaultViewsPath ? sprintf('use the "%s" directory instead.', $this->defaultViewsPath) : 'configure and use "twig.default_path" instead.'), E_USER_DEPRECATED); diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index cc704ab5e4dfe..b1fa1553100c8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -123,11 +123,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int } /** @var KernelInterface $kernel */ $kernel = $this->getApplication()->getKernel(); - $rootDir = $kernel->getContainer()->getParameter('kernel.root_dir'); // Define Root Paths $transPaths = $this->transPaths; - if (is_dir($dir = $rootDir.'/Resources/translations')) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($dir = $kernel->getContainer()->getParameter('kernel.root_dir').'/Resources/translations')) { if ($dir !== $this->defaultTransPath) { $notice = sprintf('Storing translations in the "%s" directory is deprecated since Symfony 4.2, ', $dir); @trigger_error($notice.($this->defaultTransPath ? sprintf('use the "%s" directory instead.', $this->defaultTransPath) : 'configure and use "framework.translator.default_path" instead.'), E_USER_DEPRECATED); @@ -138,7 +137,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $transPaths[] = $this->defaultTransPath; } $viewsPaths = $this->viewsPaths; - if (is_dir($dir = $rootDir.'/Resources/views')) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($dir = $kernel->getContainer()->getParameter('kernel.root_dir').'/Resources/views')) { if ($dir !== $this->defaultViewsPath) { $notice = sprintf('Storing templates in the "%s" directory is deprecated since Symfony 4.2, ', $dir); @trigger_error($notice.($this->defaultViewsPath ? sprintf('use the "%s" directory instead.', $this->defaultViewsPath) : 'configure and use "twig.default_path" instead.'), E_USER_DEPRECATED); @@ -160,7 +159,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($this->defaultTransPath) { $transPaths[] = $this->defaultTransPath; } - if (is_dir($dir = sprintf('%s/Resources/%s/translations', $rootDir, $foundBundle->getName()))) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($dir = sprintf('%s/Resources/%s/translations', $kernel->getContainer()->getParameter('kernel.root_dir'), $foundBundle->getName()))) { $transPaths[] = $dir; $notice = sprintf('Storing translations files for "%s" in the "%s" directory is deprecated since Symfony 4.2, ', $foundBundle->getName(), $dir); @trigger_error($notice.($this->defaultTransPath ? sprintf('use the "%s" directory instead.', $this->defaultTransPath) : 'configure and use "framework.translator.default_path" instead.'), E_USER_DEPRECATED); @@ -168,7 +167,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($this->defaultViewsPath) { $viewsPaths[] = $this->defaultViewsPath; } - if (is_dir($dir = sprintf('%s/Resources/%s/views', $rootDir, $foundBundle->getName()))) { + if ($kernel->getContainer()->hasParameter('kernel.root_dir') && is_dir($dir = sprintf('%s/Resources/%s/views', $kernel->getContainer()->getParameter('kernel.root_dir'), $foundBundle->getName()))) { $viewsPaths[] = $dir; $notice = sprintf('Storing templates for "%s" in the "%s" directory is deprecated since Symfony 4.2, ', $foundBundle->getName(), $dir); @trigger_error($notice.($this->defaultViewsPath ? sprintf('use the "%s" directory instead.', $this->defaultViewsPath) : 'configure and use "twig.default_path" instead.'), E_USER_DEPRECATED); diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 5e302f0e37165..b5998ed22d0ea 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -70,6 +70,7 @@ use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\Lock\Factory; use Symfony\Component\Lock\Lock; use Symfony\Component\Lock\LockFactory; @@ -183,6 +184,15 @@ public function load(array $configs, ContainerBuilder $container) } } + if (Kernel::MAJOR_VERSION < 5) { + $container->getDefinition('file_locator') + ->addArgument('%kernel.root_dir%/Resources') + ->addArgument([ + '%kernel.root_dir%', + ]) + ->addArgument(false); + } + // Load Cache configuration first as it is used by other components $loader->load('cache.xml'); @@ -960,6 +970,14 @@ private function registerTemplatingConfiguration(array $config, ContainerBuilder ->addMethodCall('setLogger', [$logger]); } + if (Kernel::MAJOR_VERSION < 5) { + $container->getDefinition('templating.finder') + ->addArgument('%kernel.root_dir%/Resources'); + } else { + $container->getDefinition('templating.finder') + ->addArgument(null); + } + if (!empty($config['loaders'])) { $loaders = array_map(function ($loader) { return new Reference($loader); }, $config['loaders']); @@ -1150,14 +1168,13 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder $dirs[] = $transPaths[] = \dirname(\dirname($r->getFileName())).'/Resources/translations'; } $defaultDir = $container->getParameterBag()->resolveValue($config['default_path']); - $rootDir = $container->getParameter('kernel.root_dir'); foreach ($container->getParameter('kernel.bundles_metadata') as $name => $bundle) { if ($container->fileExists($dir = $bundle['path'].'/Resources/translations') || $container->fileExists($dir = $bundle['path'].'/translations')) { $dirs[] = $dir; } else { $nonExistingDirs[] = $dir; } - if ($container->fileExists($dir = $rootDir.sprintf('/Resources/%s/translations', $name))) { + if ($container->hasParameter('kernel.root_dir') && $container->fileExists($dir = $container->getParameter('kernel.root_dir').sprintf('/Resources/%s/translations', $name))) { @trigger_error(sprintf('Translations directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultDir), E_USER_DEPRECATED); $dirs[] = $dir; } else { @@ -1187,7 +1204,7 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder $nonExistingDirs[] = $defaultDir; } - if ($container->fileExists($dir = $rootDir.'/Resources/translations')) { + if ($container->hasParameter('kernel.root_dir') && $container->fileExists($dir = $container->getParameter('kernel.root_dir').'/Resources/translations')) { if ($dir !== $defaultDir) { @trigger_error(sprintf('Translations directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultDir), E_USER_DEPRECATED); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml index e8a11ad2428e5..a937dc9ac0045 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml @@ -87,11 +87,6 @@ - %kernel.root_dir%/Resources - - %kernel.root_dir% - - false diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml index b6b70be999de8..dd926d2f42e4e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/templating.xml @@ -32,7 +32,6 @@ - %kernel.root_dir%/Resources The "%service_id%" service is deprecated since Symfony 4.3 and will be removed in 5.0. diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index 7f3233ad4325d..a1dedfc5db994 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -19,6 +19,7 @@ use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\Mailer\Mailer; use Symfony\Component\Translation\Translator; use Twig\Extension\ExtensionInterface; @@ -48,6 +49,10 @@ public function load(array $configs, ContainerBuilder $container) if (class_exists(Application::class)) { $loader->load('console.xml'); + + if (Kernel::MAJOR_VERSION < 5) { + $container->getDefinition('twig.command.debug')->replaceArgument(5, '%kernel.root_dir%'); + } } if (class_exists(Mailer::class)) { @@ -108,6 +113,10 @@ public function load(array $configs, ContainerBuilder $container) $container->getDefinition('twig.cache_warmer')->replaceArgument(2, $config['paths']); $container->getDefinition('twig.template_iterator')->replaceArgument(2, $config['paths']); + if (Kernel::MAJOR_VERSION < 5) { + $container->getDefinition('twig.template_iterator')->replaceArgument(1, '%kernel.root_dir%'); + } + foreach ($this->getBundleTemplatePaths($container, $config) as $name => $paths) { $namespace = $this->normalizeBundleName($name); foreach ($paths as $path) { @@ -120,14 +129,16 @@ public function load(array $configs, ContainerBuilder $container) } } - if (file_exists($dir = $container->getParameter('kernel.root_dir').'/Resources/views')) { - if ($dir !== $defaultTwigPath) { - @trigger_error(sprintf('Loading Twig templates from the "%s" directory is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultTwigPath), E_USER_DEPRECATED); - } + if ($container->hasParameter('kernel.root_dir')) { + if (file_exists($dir = $container->getParameter('kernel.root_dir').'/Resources/views')) { + if ($dir !== $defaultTwigPath) { + @trigger_error(sprintf('Loading Twig templates from the "%s" directory is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultTwigPath), E_USER_DEPRECATED); + } - $twigFilesystemLoaderDefinition->addMethodCall('addPath', [$dir]); + $twigFilesystemLoaderDefinition->addMethodCall('addPath', [$dir]); + } + $container->addResource(new FileExistenceResource($dir)); } - $container->addResource(new FileExistenceResource($dir)); if (file_exists($defaultTwigPath)) { $twigFilesystemLoaderDefinition->addMethodCall('addPath', [$defaultTwigPath]); @@ -176,12 +187,14 @@ private function getBundleTemplatePaths(ContainerBuilder $container, array $conf foreach ($container->getParameter('kernel.bundles_metadata') as $name => $bundle) { $defaultOverrideBundlePath = $container->getParameterBag()->resolveValue($config['default_path']).'/bundles/'.$name; - if (file_exists($dir = $container->getParameter('kernel.root_dir').'/Resources/'.$name.'/views')) { - @trigger_error(sprintf('Loading Twig templates for "%s" from the "%s" directory is deprecated since Symfony 4.2, use "%s" instead.', $name, $dir, $defaultOverrideBundlePath), E_USER_DEPRECATED); + if ($container->hasParameter('kernel.root_dir')) { + if (file_exists($dir = $container->getParameter('kernel.root_dir').'/Resources/'.$name.'/views')) { + @trigger_error(sprintf('Loading Twig templates for "%s" from the "%s" directory is deprecated since Symfony 4.2, use "%s" instead.', $name, $dir, $defaultOverrideBundlePath), E_USER_DEPRECATED); - $bundleHierarchy[$name][] = $dir; + $bundleHierarchy[$name][] = $dir; + } + $container->addResource(new FileExistenceResource($dir)); } - $container->addResource(new FileExistenceResource($dir)); if (file_exists($defaultOverrideBundlePath)) { $bundleHierarchy[$name][] = $defaultOverrideBundlePath; diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/console.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/console.xml index 28306e19c5f89..667ffaa2cba44 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/console.xml @@ -13,7 +13,7 @@ %kernel.bundles_metadata% %twig.default_path% - %kernel.root_dir% + diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 52723177a1fbf..e7e728504a5ab 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -41,7 +41,7 @@ - %kernel.root_dir% + %twig.default_path% diff --git a/src/Symfony/Bundle/TwigBundle/TemplateIterator.php b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php index 2f33a9ed310fb..bce25efe10626 100644 --- a/src/Symfony/Bundle/TwigBundle/TemplateIterator.php +++ b/src/Symfony/Bundle/TwigBundle/TemplateIterator.php @@ -30,11 +30,11 @@ class TemplateIterator implements \IteratorAggregate private $defaultPath; /** - * @param string $rootDir The directory where global templates can be stored + * @param string|null $rootDir The directory where global templates can be stored * @param array $paths Additional Twig paths to warm * @param string|null $defaultPath The directory where global templates can be stored */ - public function __construct(KernelInterface $kernel, string $rootDir, array $paths = [], string $defaultPath = null) + public function __construct(KernelInterface $kernel, ?string $rootDir, array $paths = [], string $defaultPath = null) { $this->kernel = $kernel; $this->rootDir = $rootDir; @@ -51,7 +51,7 @@ public function getIterator() return $this->templates; } - $templates = $this->findTemplatesInDirectory($this->rootDir.'/Resources/views'); + $templates = null !== $this->rootDir ? $this->findTemplatesInDirectory($this->rootDir.'/Resources/views') : []; if (null !== $this->defaultPath) { $templates = array_merge( @@ -70,7 +70,7 @@ public function getIterator() $templates = array_merge( $templates, $this->findTemplatesInDirectory($bundleTemplatesDir, $name), - $this->findTemplatesInDirectory($this->rootDir.'/Resources/'.$bundle->getName().'/views', $name) + null !== $this->rootDir ? $this->findTemplatesInDirectory($this->rootDir.'/Resources/'.$bundle->getName().'/views', $name) : [] ); if (null !== $this->defaultPath) { $templates = array_merge( pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy