From d6855831223719cd4c6d7257fb140c0e6b6229b8 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 26 Apr 2024 17:01:03 -0400 Subject: [PATCH 1/8] fix(Finder): ExcludeDirectoryFilterIterator relative to "root" if `/` Fixes #28158 Fixes #47431 Related: #26396 Related: #9158 Related: #28410 --- .../ExcludeDirectoryFilterIterator.php | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php index 39797c82cab28..d8866546bf260 100644 --- a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -26,6 +26,7 @@ class ExcludeDirectoryFilterIterator extends \FilterIterator implements \Recursi private $isRecursive; private $excludedDirs = []; private $excludedPattern; + private $excludedPatternAbsolute; /** * @param \Iterator $iterator The Iterator to filter @@ -36,9 +37,16 @@ public function __construct(\Iterator $iterator, array $directories) $this->iterator = $iterator; $this->isRecursive = $iterator instanceof \RecursiveIterator; $patterns = []; + $patternsAbsolute = []; foreach ($directories as $directory) { $directory = rtrim($directory, '/'); - if (!$this->isRecursive || str_contains($directory, '/')) { + $slashPos = strpos($directory, '/'); + if (false !== $slashPos && \strlen($directory) - 1 !== $slashPos) { + if (0 === $slashPos) { + $directory = substr($directory, 1); + } + $patternsAbsolute[] = preg_quote($directory, '#'); + } elseif (!$this->isRecursive || str_contains($directory, '/')) { $patterns[] = preg_quote($directory, '#'); } else { $this->excludedDirs[$directory] = true; @@ -48,6 +56,10 @@ public function __construct(\Iterator $iterator, array $directories) $this->excludedPattern = '#(?:^|/)(?:'.implode('|', $patterns).')(?:/|$)#'; } + if ($patternsAbsolute) { + $this->excludedPatternAbsolute = '#^('.implode('|', $patternsAbsolute).')$#'; + } + parent::__construct($iterator); } @@ -63,11 +75,15 @@ public function accept() return false; } - if ($this->excludedPattern) { + if ($this->excludedPattern || $this->excludedPatternAbsolute) { $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath(); $path = str_replace('\\', '/', $path); - - return !preg_match($this->excludedPattern, $path); + } + if ($this->excludedPattern && preg_match($this->excludedPattern, $path)) { + return false; + } + if ($this->excludedPatternAbsolute && preg_match($this->excludedPatternAbsolute, $path)) { + return false; } return true; From ca2ca8b7594657b4823c0270edce33d4ecf87c81 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 29 Apr 2024 10:49:58 -0400 Subject: [PATCH 2/8] Spacing Co-authored-by: Oskar Stark --- .../Finder/Iterator/ExcludeDirectoryFilterIterator.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php index d8866546bf260..ee0a709a46cbc 100644 --- a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -79,9 +79,11 @@ public function accept() $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath(); $path = str_replace('\\', '/', $path); } + if ($this->excludedPattern && preg_match($this->excludedPattern, $path)) { return false; } + if ($this->excludedPatternAbsolute && preg_match($this->excludedPatternAbsolute, $path)) { return false; } From 70e0ac420e151c1d86fa3a227c060fd77c024a60 Mon Sep 17 00:00:00 2001 From: Josh Richards Date: Wed, 8 May 2024 16:38:15 -0400 Subject: [PATCH 3/8] Add tests for Finder exclude root absolute Signed-off-by: Josh Richards --- .../ExcludeDirectoryFilterIteratorTest.php | 25 +++++++++++++++++++ .../Tests/Iterator/RealIteratorTestCase.php | 1 + 2 files changed, 26 insertions(+) diff --git a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php index 9b5ed98ad5a72..a63000cd03a0b 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php @@ -63,6 +63,7 @@ public static function getAcceptData() 'foo/bar.tmp', 'test.php', 'toto', + 'toto/foo', 'toto/.git', 'foo bar', 'qux', @@ -96,12 +97,36 @@ public static function getAcceptData() 'qux_10_2.php', 'qux_12_0.php', 'qux_2_0.php', + ]; + + $foo_absolute_root = [ + '.bar', + '.foo', + '.foo/.bar', + '.foo/bar', + '.git', + 'test.py', + 'test.php', + 'toto', + 'toto/foo', + 'toto/.git', + 'foo bar', + 'qux', + 'qux/baz_100_1.py', + 'qux/baz_1_2.py', + 'qux_0_1.php', + 'qux_1000_1.php', + 'qux_1002_0.php', + 'qux_10_2.php', + 'qux_12_0.php', + 'qux_2_0.php', ]; return [ [['foo'], self::toAbsolute($foo)], [['fo'], self::toAbsolute($fo)], [['toto/'], self::toAbsolute($toto)], + [['/foo'], self::toAbsolute($foo_absolute_root)], ]; } } diff --git a/src/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php b/src/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php index 8b727f4cee411..cdc80467be840 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php @@ -31,6 +31,7 @@ public static function setUpBeforeClass(): void 'foo/bar.tmp', 'test.php', 'toto/', + 'toto/foo/', 'toto/.git/', 'foo bar', 'qux_0_1.php', From 9f70375a3fa143332bacec3744ed50fd10a987da Mon Sep 17 00:00:00 2001 From: Josh Richards Date: Wed, 8 May 2024 16:40:25 -0400 Subject: [PATCH 4/8] coding standards update Signed-off-by: Josh Richards --- .../Finder/Iterator/ExcludeDirectoryFilterIterator.php | 2 +- .../Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php index ee0a709a46cbc..0b40692263be1 100644 --- a/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -79,7 +79,7 @@ public function accept() $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath(); $path = str_replace('\\', '/', $path); } - + if ($this->excludedPattern && preg_match($this->excludedPattern, $path)) { return false; } diff --git a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php index a63000cd03a0b..099482d2063b4 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php @@ -97,7 +97,7 @@ public static function getAcceptData() 'qux_10_2.php', 'qux_12_0.php', 'qux_2_0.php', - ]; + ]; $foo_absolute_root = [ '.bar', From 6912c9a94f9ff36240f0981c3e92d48758b75c89 Mon Sep 17 00:00:00 2001 From: Josh Richards Date: Wed, 8 May 2024 16:46:32 -0400 Subject: [PATCH 5/8] add test for absolute underneath a subfolder Signed-off-by: Josh Richards --- .../ExcludeDirectoryFilterIteratorTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php index 099482d2063b4..6edfc6c6b9f00 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php @@ -120,6 +120,30 @@ public static function getAcceptData() 'qux_10_2.php', 'qux_12_0.php', 'qux_2_0.php', + ]; + + $foo_toto_subdir_absolute_root = [ + '.bar', + '.foo', + '.foo/.bar', + '.foo/bar', + '.git', + 'test.py', + 'test.php', + 'foo', + 'foo/bar.tmp', + 'toto', + 'toto/.git', + 'foo bar', + 'qux', + 'qux/baz_100_1.py', + 'qux/baz_1_2.py', + 'qux_0_1.php', + 'qux_1000_1.php', + 'qux_1002_0.php', + 'qux_10_2.php', + 'qux_12_0.php', + 'qux_2_0.php', ]; return [ @@ -127,6 +151,7 @@ public static function getAcceptData() [['fo'], self::toAbsolute($fo)], [['toto/'], self::toAbsolute($toto)], [['/foo'], self::toAbsolute($foo_absolute_root)], + [['/toto/foo'], self::toAbsolute($foo_toto_subdir_absolute_root)], ]; } } From 5b49aa61603f890bb0969ee51af6cdd7ee37a48d Mon Sep 17 00:00:00 2001 From: Josh Richards Date: Wed, 8 May 2024 17:14:53 -0400 Subject: [PATCH 6/8] additional test adjustments Signed-off-by: Josh Richards --- .../Component/Finder/Tests/FinderTest.php | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index 183a09cff190a..c99b323784073 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -25,13 +25,13 @@ public function testDirectories() { $finder = $this->buildFinder(); $this->assertSame($finder, $finder->directories()); - $this->assertIterator($this->toAbsolute(['foo', 'qux', 'toto']), $finder->in(self::$tmpDir)->getIterator()); + $this->assertIterator($this->toAbsolute(['foo', 'qux', 'toto', 'toto/foo']), $finder->in(self::$tmpDir)->getIterator()); $finder = $this->buildFinder(); $finder->directories(); $finder->files(); $finder->directories(); - $this->assertIterator($this->toAbsolute(['foo', 'qux', 'toto']), $finder->in(self::$tmpDir)->getIterator()); + $this->assertIterator($this->toAbsolute(['foo', 'qux', 'toto', 'toto/foo']), $finder->in(self::$tmpDir)->getIterator()); } public function testFiles() @@ -162,7 +162,8 @@ public function testDepth() $this->assertIterator($this->toAbsolute([ 'foo/bar.tmp', 'qux/baz_100_1.py', - 'qux/baz_1_2.py', + 'qux/baz_1_2.py', + 'toto/foo', ]), $finder->in(self::$tmpDir)->getIterator()); $finder = $this->buildFinder(); @@ -178,6 +179,7 @@ public function testDepthWithArrayParam() 'foo/bar.tmp', 'qux/baz_100_1.py', 'qux/baz_1_2.py', + 'toto/foo', ]), $finder->in(self::$tmpDir)->getIterator()); } @@ -237,6 +239,7 @@ public function testNotName() 'foo/bar.tmp', 'test.py', 'toto', + 'toto/foo', 'foo bar', 'qux', 'qux/baz_100_1.py', @@ -250,6 +253,7 @@ public function testNotName() 'foo', 'foo/bar.tmp', 'toto', + 'toto/foo', 'foo bar', 'qux', ]), $finder->in(self::$tmpDir)->getIterator()); @@ -276,6 +280,7 @@ public function testNotNameWithArrayParam() 'foo', 'foo/bar.tmp', 'toto', + 'toto/foo', 'foo bar', 'qux', ]), $finder->in(self::$tmpDir)->getIterator()); @@ -340,6 +345,25 @@ public function testExclude() 'qux_10_2.php', 'qux_12_0.php', 'qux_2_0.php', + ]), $finder->in(self::$tmpDir)->getIterator()); + + $finder = $this->buildFinder(); + $this->assertSame($finder, $finder->exclude('/foo')); + $this->assertIterator($this->toAbsolute([ + 'test.php', + 'test.py', + 'toto', + 'toto/foo', + 'foo bar', + 'qux', + 'qux/baz_100_1.py', + 'qux/baz_1_2.py', + 'qux_0_1.php', + 'qux_1000_1.php', + 'qux_1002_0.php', + 'qux_10_2.php', + 'qux_12_0.php', + 'qux_2_0.php', ]), $finder->in(self::$tmpDir)->getIterator()); } @@ -355,6 +379,7 @@ public function testIgnoreVCS() 'test.py', 'toto', 'toto/.git', + 'toto/foo', '.bar', '.foo', '.foo/.bar', @@ -380,6 +405,7 @@ public function testIgnoreVCS() 'test.php', 'test.py', 'toto', + 'toto/foo', 'toto/.git', '.bar', '.foo', @@ -405,6 +431,7 @@ public function testIgnoreVCS() 'test.php', 'test.py', 'toto', + 'toto/foo', '.bar', '.foo', '.foo/.bar', @@ -468,6 +495,7 @@ public function testIgnoreVCSCanBeDisabledAfterFirstIteration() 'test.php', 'test.py', 'toto', + 'toto/foo', '.bar', '.foo', '.foo/.bar', @@ -492,6 +520,7 @@ public function testIgnoreVCSCanBeDisabledAfterFirstIteration() 'test.php', 'test.py', 'toto', + 'toto/foo', 'toto/.git', '.bar', '.foo', @@ -517,6 +546,7 @@ public function testIgnoreDotFiles() 'test.py', 'toto', 'toto/.git', + 'toto/foo', 'foo bar', 'qux', 'qux/baz_100_1.py', @@ -542,6 +572,7 @@ public function testIgnoreDotFiles() 'test.php', 'test.py', 'toto', + 'toto/foo', 'toto/.git', 'foo bar', 'qux', @@ -563,6 +594,7 @@ public function testIgnoreDotFiles() 'test.php', 'test.py', 'toto', + 'toto/foo', 'foo bar', 'qux', 'qux/baz_100_1.py', @@ -596,6 +628,7 @@ public function testIgnoreDotFilesCanBeDisabledAfterFirstIteration() 'test.php', 'test.py', 'toto', + 'toto/foo', 'foo bar', ]), $finder->getIterator()); @@ -615,6 +648,7 @@ public function testIgnoreDotFilesCanBeDisabledAfterFirstIteration() 'test.php', 'test.py', 'toto', + 'toto/foo', '.bar', '.foo', '.foo/.bar', @@ -643,6 +677,7 @@ public function testSortByName() 'test.php', 'test.py', 'toto', + 'toto/foo', ]), $finder->in(self::$tmpDir)->getIterator()); } @@ -654,6 +689,7 @@ public function testSortByType() 'foo', 'qux', 'toto', + 'toto/foo', 'foo bar', 'foo/bar.tmp', 'qux/baz_100_1.py', @@ -677,6 +713,7 @@ public function testSortByAccessedTime() 'foo/bar.tmp', 'test.php', 'toto', + 'toto/foo', 'test.py', 'foo', 'foo bar', @@ -698,6 +735,7 @@ public function testSortByChangedTime() $this->assertSame($finder, $finder->sortByChangedTime()); $this->assertIterator($this->toAbsolute([ 'toto', + 'toto/foo', 'test.py', 'test.php', 'foo/bar.tmp', @@ -723,6 +761,7 @@ public function testSortByModifiedTime() 'foo/bar.tmp', 'test.php', 'toto', + 'toto/foo', 'test.py', 'foo', 'foo bar', @@ -744,6 +783,7 @@ public function testReverseSorting() $this->assertSame($finder, $finder->sortByName()); $this->assertSame($finder, $finder->reverseSorting()); $this->assertOrderedIteratorInForeach($this->toAbsolute([ + 'toto/foo', 'toto', 'test.py', 'test.php', @@ -782,6 +822,7 @@ public function testSortByNameNatural() 'test.php', 'test.py', 'toto', + 'toto/foo', ]), $finder->in(self::$tmpDir)->getIterator()); $finder = $this->buildFinder(); @@ -802,6 +843,7 @@ public function testSortByNameNatural() 'test.php', 'test.py', 'toto', + 'toto/foo', ]), $finder->in(self::$tmpDir)->getIterator()); } @@ -825,6 +867,7 @@ public function testSort() 'test.php', 'test.py', 'toto', + 'toto/foo', ]), $finder->in(self::$tmpDir)->getIterator()); } @@ -882,6 +925,7 @@ public function testFollowLinks() 'test.php', 'test.py', 'toto', + 'toto/foo', 'foo bar', 'qux', 'qux/baz_100_1.py', @@ -972,7 +1016,7 @@ public function testGetIterator() $dirs[] = (string) $dir; } - $expected = $this->toAbsolute(['foo', 'qux', 'toto']); + $expected = $this->toAbsolute(['foo', 'qux', 'toto', 'toto/foo']); sort($dirs); sort($expected); @@ -980,7 +1024,7 @@ public function testGetIterator() $this->assertEquals($expected, $dirs, 'implements the \IteratorAggregate interface'); $finder = $this->buildFinder(); - $this->assertEquals(3, iterator_count($finder->directories()->in(self::$tmpDir)), 'implements the \IteratorAggregate interface'); + $this->assertEquals(4, iterator_count($finder->directories()->in(self::$tmpDir)), 'implements the \IteratorAggregate interface'); $finder = $this->buildFinder(); $a = iterator_to_array($finder->directories()->in(self::$tmpDir)); @@ -999,7 +1043,7 @@ public function testRelativePath() $paths[] = $file->getRelativePath(); } - $ref = ['', '', '', '', '', '', '', '', '', '', '', 'foo', 'qux', 'qux', '']; + $ref = ['', '', '', '', '', '', '', '', '', '', '', 'foo', 'qux', 'qux', '', 'toto']; sort($ref); sort($paths); @@ -1020,6 +1064,7 @@ public function testRelativePathname() $ref = [ 'test.php', 'toto', + 'toto/foo', 'test.py', 'foo', 'foo'.\DIRECTORY_SEPARATOR.'bar.tmp', @@ -1056,6 +1101,7 @@ public function testGetFilenameWithoutExtension() 'toto', 'test', 'foo', + 'foo', 'bar', 'foo bar', 'qux', @@ -1085,7 +1131,7 @@ public function testAppendWithAFinder() $finder = $finder->append($finder1); - $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'qux', 'toto']), $finder->getIterator()); + $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'qux', 'toto', 'toto/foo']), $finder->getIterator()); } public function testAppendWithAnArray() From 5b4734971ccad69e3ca96d126f9331669fb749a8 Mon Sep 17 00:00:00 2001 From: Josh Richards Date: Wed, 8 May 2024 17:19:05 -0400 Subject: [PATCH 7/8] add test for sub-root subdir Signed-off-by: Josh Richards --- .../Component/Finder/Tests/FinderTest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index c99b323784073..1292f33d533eb 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -365,6 +365,26 @@ public function testExclude() 'qux_12_0.php', 'qux_2_0.php', ]), $finder->in(self::$tmpDir)->getIterator()); + + $finder = $this->buildFinder(); + $this->assertSame($finder, $finder->exclude('/toto/foo')); + $this->assertIterator($this->toAbsolute([ + 'foo', + 'foo/bar.tmp', + 'test.php', + 'test.py', + 'toto', + 'foo bar', + 'qux', + 'qux/baz_100_1.py', + 'qux/baz_1_2.py', + 'qux_0_1.php', + 'qux_1000_1.php', + 'qux_1002_0.php', + 'qux_10_2.php', + 'qux_12_0.php', + 'qux_2_0.php', + ]), $finder->in(self::$tmpDir)->getIterator()); } public function testIgnoreVCS() From 992c48f8d986c7cf82e9f57350d8f64f958fb06c Mon Sep 17 00:00:00 2001 From: Josh Richards Date: Sun, 26 May 2024 17:36:42 -0400 Subject: [PATCH 8/8] fixup: exclude non-root absolute paths since not supported with this solution at the moment Signed-off-by: Josh Richards --- .../Component/Finder/Tests/FinderTest.php | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index 1292f33d533eb..f81f796480ad1 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -366,25 +366,26 @@ public function testExclude() 'qux_2_0.php', ]), $finder->in(self::$tmpDir)->getIterator()); - $finder = $this->buildFinder(); - $this->assertSame($finder, $finder->exclude('/toto/foo')); - $this->assertIterator($this->toAbsolute([ - 'foo', - 'foo/bar.tmp', - 'test.php', - 'test.py', - 'toto', - 'foo bar', - 'qux', - 'qux/baz_100_1.py', - 'qux/baz_1_2.py', - 'qux_0_1.php', - 'qux_1000_1.php', - 'qux_1002_0.php', - 'qux_10_2.php', - 'qux_12_0.php', - 'qux_2_0.php', - ]), $finder->in(self::$tmpDir)->getIterator()); + /* absolute folders lower than the "root" are not currently supported */ + //$finder = $this->buildFinder(); + //$this->assertSame($finder, $finder->exclude('/toto/foo')); + //$this->assertIterator($this->toAbsolute([ + // 'foo', + // 'foo/bar.tmp', + // 'test.php', + // 'test.py', + // 'toto', + // 'foo bar', + // 'qux', + // 'qux/baz_100_1.py', + // 'qux/baz_1_2.py', + // 'qux_0_1.php', + // 'qux_1000_1.php', + // 'qux_1002_0.php', + // 'qux_10_2.php', + // 'qux_12_0.php', + // 'qux_2_0.php', + //]), $finder->in(self::$tmpDir)->getIterator()); } public function testIgnoreVCS() 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