From 01870398eb211fed5dcf91adbbf4215234ab9316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= Date: Thu, 27 Sep 2018 18:36:17 +0200 Subject: [PATCH] [Validator] add number constraints --- src/Symfony/Component/Validator/CHANGELOG.md | 4 + .../Validator/Constraints/Negative.php | 35 ++++++ .../Validator/Constraints/NegativeOrZero.php | 35 ++++++ .../Constraints/NumberConstraintTrait.php | 41 +++++++ .../Validator/Constraints/Positive.php | 35 ++++++ .../Validator/Constraints/PositiveOrZero.php | 35 ++++++ .../Resources/translations/validators.de.xlf | 16 +++ .../Resources/translations/validators.en.xlf | 16 +++ .../Resources/translations/validators.vi.xlf | 16 +++ ...idatorWithPositiveOrZeroConstraintTest.php | 111 +++++++++++++++++ ...hanValidatorWithPositiveConstraintTest.php | 114 ++++++++++++++++++ ...idatorWithNegativeOrZeroConstraintTest.php | 114 ++++++++++++++++++ ...hanValidatorWithNegativeConstraintTest.php | 114 ++++++++++++++++++ 13 files changed, 686 insertions(+) create mode 100644 src/Symfony/Component/Validator/Constraints/Negative.php create mode 100644 src/Symfony/Component/Validator/Constraints/NegativeOrZero.php create mode 100644 src/Symfony/Component/Validator/Constraints/NumberConstraintTrait.php create mode 100644 src/Symfony/Component/Validator/Constraints/Positive.php create mode 100644 src/Symfony/Component/Validator/Constraints/PositiveOrZero.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorWithPositiveConstraintTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorWithNegativeConstraintTest.php diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 3ba214dda764b..0a1aac70ed580 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -10,6 +10,10 @@ CHANGELOG * added `Json` constraint * added `Unique` constraint * added a new `normalizer` option to the string constraints and to the `NotBlank` constraint + * added `Positive` constraint + * added `PositiveOrZero` constraint + * added `Negative` constraint + * added `NegativeOrZero` constraint 4.2.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Negative.php b/src/Symfony/Component/Validator/Constraints/Negative.php new file mode 100644 index 0000000000000..7dc394a2579a8 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Negative.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Jan Schädlich + */ +class Negative extends LessThan +{ + use NumberConstraintTrait; + + public $message = 'This value should be negative.'; + + public function __construct($options = null) + { + parent::__construct($this->configureNumberConstraintOptions($options)); + } + + public function validatedBy(): string + { + return LessThanValidator::class; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/NegativeOrZero.php b/src/Symfony/Component/Validator/Constraints/NegativeOrZero.php new file mode 100644 index 0000000000000..3b2274ba6373a --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/NegativeOrZero.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Jan Schädlich + */ +class NegativeOrZero extends LessThanOrEqual +{ + use NumberConstraintTrait; + + public $message = 'This value should be either negative or zero.'; + + public function __construct($options = null) + { + parent::__construct($this->configureNumberConstraintOptions($options)); + } + + public function validatedBy(): string + { + return LessThanOrEqualValidator::class; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/NumberConstraintTrait.php b/src/Symfony/Component/Validator/Constraints/NumberConstraintTrait.php new file mode 100644 index 0000000000000..ff189cf3e8acb --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/NumberConstraintTrait.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Exception\ConstraintDefinitionException; + +/** + * @author Jan Schädlich + */ +trait NumberConstraintTrait +{ + private function configureNumberConstraintOptions($options): array + { + if (null === $options) { + $options = []; + } elseif (!\is_array($options)) { + $options = [$this->getDefaultOption() => $options]; + } + + if (isset($options['propertyPath'])) { + throw new ConstraintDefinitionException(sprintf('The "propertyPath" option of the "%s" constraint cannot be set.', \get_class($this))); + } + + if (isset($options['value'])) { + throw new ConstraintDefinitionException(sprintf('The "value" option of the "%s" constraint cannot be set.', \get_class($this))); + } + + $options['value'] = 0; + + return $options; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/Positive.php b/src/Symfony/Component/Validator/Constraints/Positive.php new file mode 100644 index 0000000000000..6efba4a9b2ede --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Positive.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Jan Schädlich + */ +class Positive extends GreaterThan +{ + use NumberConstraintTrait; + + public $message = 'This value should be positive.'; + + public function __construct($options = null) + { + parent::__construct($this->configureNumberConstraintOptions($options)); + } + + public function validatedBy(): string + { + return GreaterThanValidator::class; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/PositiveOrZero.php b/src/Symfony/Component/Validator/Constraints/PositiveOrZero.php new file mode 100644 index 0000000000000..2e525db4647ba --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/PositiveOrZero.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Jan Schädlich + */ +class PositiveOrZero extends GreaterThanOrEqual +{ + use NumberConstraintTrait; + + public $message = 'This value should be either positive or zero.'; + + public function __construct($options = null) + { + parent::__construct($this->configureNumberConstraintOptions($options)); + } + + public function validatedBy(): string + { + return GreaterThanOrEqualValidator::class; + } +} diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf index aab53e727b9e4..604df8017ddf8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf @@ -330,6 +330,22 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. Diese internationale Bankleitzahl (BIC) ist nicht mit der IBAN {{ iban }} assoziiert. + + This value should be positive. + Dieser Wert sollte positiv sein. + + + This value should be either positive or zero. + Dieser Wert sollte entweder positiv oder 0 sein. + + + This value should be negative. + Dieser Wert sollte negativ sein. + + + This value should be either negative or zero. + Dieser Wert sollte entweder negativ oder 0 sein. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index 465ad220d8790..481df7a0f6bc8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -334,6 +334,22 @@ This value should be valid JSON. This value should be valid JSON. + + This value should be positive. + This value should be positive. + + + This value should be either positive or zero. + This value should be either positive or zero. + + + This value should be negative. + This value should be negative. + + + This value should be either negative or zero. + This value should be either negative or zero. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf index 750a4d91e2c61..4713a161f2ad9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf @@ -278,6 +278,22 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. Giá trị không được phép giống như {{ compared_value_type }} {{ compared_value }}. + + This value should be positive. + Giá trị này có thể thực hiện được. + + + This value should be either positive or zero. + Giá trị này có thể thực hiện được hoặc bằng không. + + + This value should be negative. + Giá trị này nên bị từ chối. + + + This value should be either negative or zero. + Giá trị này nên bị từ chối hoặc bằng không. + diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest.php new file mode 100644 index 0000000000000..7ac3e57919ae6 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\PositiveOrZero; + +/** + * @author Jan Schädlich + */ +class GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest extends GreaterThanOrEqualValidatorTest +{ + protected function createConstraint(array $options = null) + { + return new PositiveOrZero(); + } + + /** + * {@inheritdoc} + */ + public function provideValidComparisons() + { + return [ + [0, 0], + [1, 0], + [2, 0], + [2.5, 0], + ['0', '0'], + ['333', '0'], + [null, 0], + ]; + } + + /** + * {@inheritdoc} + */ + public function provideInvalidComparisons() + { + return [ + [-1, '-1', 0, '0', 'integer'], + [-2, '-2', 0, '0', 'integer'], + [-2.5, '-2.5', 0, '0', 'integer'], + ]; + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "propertyPath" option of the "Symfony\Component\Validator\Constraints\PositiveOrZero" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfPropertyPath() + { + return new PositiveOrZero(['propertyPath' => 'field']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "value" option of the "Symfony\Component\Validator\Constraints\PositiveOrZero" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfValue() + { + return new PositiveOrZero(['value' => 0]); + } + + /** + * @dataProvider provideInvalidConstraintOptions + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires either the "value" or "propertyPath" option to be set. + */ + public function testThrowsConstraintExceptionIfNoValueOrPropertyPath($options) + { + $this->markTestSkipped('Value option always set for PositiveOrZero constraint'); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires only one of the "value" or "propertyPath" options to be set, not both. + */ + public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() + { + $this->markTestSkipped('Value option is set for PositiveOrZero constraint automatically'); + } + + public function testInvalidValuePath() + { + $this->markTestSkipped('PropertyPath option is not used in PositiveOrZero constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPath($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in PositiveOrZero constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPathOnArray($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorWithPositiveConstraintTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorWithPositiveConstraintTest.php new file mode 100644 index 0000000000000..7a33e1553058c --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorWithPositiveConstraintTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Positive; + +/** + * @author Jan Schädlich + */ +class GreaterThanValidatorWithPositiveConstraintTest extends GreaterThanValidatorTest +{ + protected function createConstraint(array $options = null) + { + return new Positive(); + } + + /** + * {@inheritdoc} + */ + public function provideValidComparisons() + { + return [ + [2, 0], + [2.5, 0], + ['333', '0'], + [null, 0], + ]; + } + + /** + * {@inheritdoc} + */ + public function provideInvalidComparisons() + { + return [ + [0, '0', 0, '0', 'integer'], + [-1, '-1', 0, '0', 'integer'], + [-2, '-2', 0, '0', 'integer'], + [-2.5, '-2.5', 0, '0', 'integer'], + ]; + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "propertyPath" option of the "Symfony\Component\Validator\Constraints\Positive" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfPropertyPath() + { + return new Positive(['propertyPath' => 'field']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "value" option of the "Symfony\Component\Validator\Constraints\Positive" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfValue() + { + return new Positive(['value' => 0]); + } + + /** + * @dataProvider provideInvalidConstraintOptions + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires either the "value" or "propertyPath" option to be set. + */ + public function testThrowsConstraintExceptionIfNoValueOrPropertyPath($options) + { + $this->markTestSkipped('Value option always set for Positive constraint.'); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires only one of the "value" or "propertyPath" options to be set, not both. + */ + public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() + { + $this->markTestSkipped('Value option is set for Positive constraint automatically'); + } + + public function testNoViolationOnNullObjectWithPropertyPath() + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } + + public function testInvalidValuePath() + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPath($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPathOnArray($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest.php new file mode 100644 index 0000000000000..fa7fa2ec23461 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\NegativeOrZero; + +/** + * @author Jan Schädlich + */ +class LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest extends LessThanOrEqualValidatorTest +{ + protected function createConstraint(array $options = null) + { + return new NegativeOrZero(); + } + + /** + * {@inheritdoc} + */ + public function provideValidComparisons() + { + return [ + [0, 0], + [-1, 0], + [-2, 0], + [-2.5, 0], + [null, 0], + ]; + } + + /** + * {@inheritdoc} + */ + public function provideInvalidComparisons() + { + return [ + [2, '2', 0, '0', 'integer'], + [2.5, '2.5', 0, '0', 'integer'], + [333, '333', 0, '0', 'integer'], + ]; + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "propertyPath" option of the "Symfony\Component\Validator\Constraints\NegativeOrZero" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfPropertyPath() + { + return new NegativeOrZero(['propertyPath' => 'field']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "value" option of the "Symfony\Component\Validator\Constraints\NegativeOrZero" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfValue() + { + return new NegativeOrZero(['value' => 0]); + } + + /** + * @dataProvider provideInvalidConstraintOptions + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires either the "value" or "propertyPath" option to be set. + */ + public function testThrowsConstraintExceptionIfNoValueOrPropertyPath($options) + { + $this->markTestSkipped('Value option always set for NegativeOrZero constraint'); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires only one of the "value" or "propertyPath" options to be set, not both. + */ + public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() + { + $this->markTestSkipped('Value option is set for NegativeOrZero constraint automatically'); + } + + public function testNoViolationOnNullObjectWithPropertyPath() + { + $this->markTestSkipped('PropertyPath option is not used in NegativeOrZero constraint'); + } + + public function testInvalidValuePath() + { + $this->markTestSkipped('PropertyPath option is not used in NegativeOrZero constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPath($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in NegativeOrZero constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPathOnArray($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in NegativeOrZero constraint'); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorWithNegativeConstraintTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorWithNegativeConstraintTest.php new file mode 100644 index 0000000000000..d3e2b7afb38ad --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorWithNegativeConstraintTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Negative; + +/** + * @author Jan Schädlich + */ +class LessThanValidatorWithNegativeConstraintTest extends LessThanValidatorTest +{ + protected function createConstraint(array $options = null) + { + return new Negative(); + } + + /** + * {@inheritdoc} + */ + public function provideValidComparisons() + { + return [ + [-1, 0], + [-2, 0], + [-2.5, 0], + [null, 0], + ]; + } + + /** + * {@inheritdoc} + */ + public function provideInvalidComparisons() + { + return [ + [0, '0', 0, '0', 'integer'], + [2, '2', 0, '0', 'integer'], + [2.5, '2.5', 0, '0', 'integer'], + [333, '333', 0, '0', 'integer'], + ]; + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "propertyPath" option of the "Symfony\Component\Validator\Constraints\Negative" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfPropertyPath() + { + return new Negative(['propertyPath' => 'field']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "value" option of the "Symfony\Component\Validator\Constraints\Negative" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfValue() + { + return new Negative(['value' => 0]); + } + + /** + * @dataProvider provideInvalidConstraintOptions + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires either the "value" or "propertyPath" option to be set. + */ + public function testThrowsConstraintExceptionIfNoValueOrPropertyPath($options) + { + $this->markTestSkipped('Value option always set for Negative constraint'); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires only one of the "value" or "propertyPath" options to be set, not both. + */ + public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() + { + $this->markTestSkipped('Value option is set for Negative constraint automatically'); + } + + public function testNoViolationOnNullObjectWithPropertyPath() + { + $this->markTestSkipped('PropertyPath option is not used in Negative constraint'); + } + + public function testInvalidValuePath() + { + $this->markTestSkipped('PropertyPath option is not used in Negative constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPath($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Negative constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPathOnArray($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } +} 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