Merge branch '6.3'

* 6.3:
  Prepare release
  Ignore error
  Use SplObjectStorage::offsetSet() instead of deprecated SplObjectStorage::attach()
  Suppress warning
  Update tools
  Prepare release
  Use SplObjectStorage::offsetSet() instead of deprecated SplObjectStorage::attach()
  Suppress warning
  Prepare release
  Test with more versions
  Do not cache Composer dependencies
  Suppress warning
  Do not use implicitly nullable parameters and prepare release
  Do not use implicitly nullable parameters and prepare release
This commit is contained in:
Sebastian Bergmann 2025-09-22 07:36:56 +02:00
commit 5c10a78583
No known key found for this signature in database
GPG Key ID: 4AA394086372C20A
73 changed files with 1918 additions and 570 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="php-cs-fixer" version="^3.71" installed="3.72.0" location="./tools/php-cs-fixer" copy="true"/>
<phar name="composer" version="^2.8" installed="2.8.6" location="./tools/composer" copy="true"/>
<phar name="php-cs-fixer" version="^3.71" installed="3.87.2" location="./tools/php-cs-fixer" copy="true"/>
<phar name="composer" version="^2.8" installed="2.8.12" location="./tools/composer" copy="true"/>
<phar name="infection" version="^0.29" installed="0.29.14" location="./tools/infection" copy="true"/>
</phive>

View File

@ -8,205 +8,4 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
* This component is no longer supported on PHP 8.2
## [6.3.0] - 2024-12-05
### Added
* Optional constructor argument to control maximum string length
### Deprecated
* Optional argument for `shortenedRecursiveExport()` and `shortenedExport()` to control maximum string length
## [6.2.0] - 2024-12-05
### Added
* [#67](https://github.com/sebastianbergmann/exporter/issues/67): Optional argument for `shortenedRecursiveExport()` and `shortenedExport()` to control maximum string length
### Changed
* [#69](https://github.com/sebastianbergmann/exporter/pull/69): Do not initialize lazy objects during export
## [6.1.3] - 2024-07-03
### Changed
* [#66](https://github.com/sebastianbergmann/exporter/pull/66): Avoid using the Reflection API for some classes
* This project now uses PHPStan instead of Psalm for static analysis
## [6.1.2] - 2024-06-18
### Changed
* [#64](https://github.com/sebastianbergmann/exporter/pull/64): Improve performance of `Exporter::exportString()`
* [#65](https://github.com/sebastianbergmann/exporter/pull/65): Prevent unnecessary calls to `str_repeat()`
### Fixed
* [#62](https://github.com/sebastianbergmann/exporter/issues/62): Do not limit export of arrays by default (to restore BC with versions prior to 6.1.0)
## [6.1.1] - 2024-06-18
### Fixed
* [#61](https://github.com/sebastianbergmann/exporter/issues/61): `count(): Recursion detected` warning triggered
## [6.1.0] - 2024-06-18
### Added
* [#59](https://github.com/sebastianbergmann/exporter/pull/59): Option to limit export of (large) arrays (to speed up PHPUnit)
### Changed
* [#60](https://github.com/sebastianbergmann/exporter/pull/60): Take shortcut when exporting a string
## [6.0.3] - 2024-06-17
### Fixed
* Fixed code coverage metadata
## [6.0.2] - 2024-06-17 [YANKED]
### Changed
* [#58](https://github.com/sebastianbergmann/exporter/pull/58): Remove unnecessary `sprintf()` in hot path
## [6.0.1] - 2024-03-02
### Changed
* Do not use implicitly nullable parameters
## [6.0.0] - 2024-02-02
### Removed
* This component is no longer supported on PHP 8.1
## [5.1.2] - 2024-03-02
### Changed
* Do not use implicitly nullable parameters
## [5.1.1] - 2023-09-24
### Changed
* [#52](https://github.com/sebastianbergmann/exporter/pull/52): Optimize export of large arrays and object graphs
## [5.1.0] - 2023-09-18
### Changed
* [#51](https://github.com/sebastianbergmann/exporter/pull/51): Export arrays using short array syntax
## [5.0.1] - 2023-09-08
### Fixed
* [#49](https://github.com/sebastianbergmann/exporter/issues/49): `Exporter::toArray()` changes `SplObjectStorage` index
## [5.0.0] - 2023-02-03
### Changed
* [#42](https://github.com/sebastianbergmann/exporter/pull/42): Improve export of enumerations
### Removed
* This component is no longer supported on PHP 7.3, PHP 7.4 and PHP 8.0
## [4.0.5] - 2022-09-14
### Fixed
* [#47](https://github.com/sebastianbergmann/exporter/pull/47): Fix `float` export precision
## [4.0.4] - 2021-11-11
### Changed
* [#37](https://github.com/sebastianbergmann/exporter/pull/37): Improve export of closed resources
## [4.0.3] - 2020-09-28
### Changed
* Changed PHP version constraint in `composer.json` from `^7.3 || ^8.0` to `>=7.3`
## [4.0.2] - 2020-06-26
### Added
* This component is now supported on PHP 8
## [4.0.1] - 2020-06-15
### Changed
* Tests etc. are now ignored for archive exports
## [4.0.0] - 2020-02-07
### Removed
* This component is no longer supported on PHP 7.0, PHP 7.1, and PHP 7.2
## [3.1.5] - 2022-09-14
### Fixed
* [#47](https://github.com/sebastianbergmann/exporter/pull/47): Fix `float` export precision
## [3.1.4] - 2021-11-11
### Changed
* [#38](https://github.com/sebastianbergmann/exporter/pull/38): Improve export of closed resources
## [3.1.3] - 2020-11-30
### Changed
* Changed PHP version constraint in `composer.json` from `^7.0` to `>=7.0`
## [3.1.2] - 2019-09-14
### Fixed
* [#29](https://github.com/sebastianbergmann/exporter/pull/29): Second parameter for `str_repeat()` must be an integer
### Removed
* Remove HHVM-specific code that is no longer needed
[7.0.0]: https://github.com/sebastianbergmann/exporter/compare/6.3...7.0.0
[6.3.0]: https://github.com/sebastianbergmann/exporter/compare/6.2.0...6.3.0
[6.2.0]: https://github.com/sebastianbergmann/exporter/compare/6.1.3...6.2.0
[6.1.3]: https://github.com/sebastianbergmann/exporter/compare/6.1.2...6.1.3
[6.1.2]: https://github.com/sebastianbergmann/exporter/compare/6.1.1...6.1.2
[6.1.1]: https://github.com/sebastianbergmann/exporter/compare/6.1.0...6.1.1
[6.1.0]: https://github.com/sebastianbergmann/exporter/compare/6.0.3...6.1.0
[6.0.3]: https://github.com/sebastianbergmann/exporter/compare/fe0dca49a60d34440e2f086951952dd13aa9a5d2...6.0.3
[6.0.2]: https://github.com/sebastianbergmann/exporter/compare/6.0.1...fe0dca49a60d34440e2f086951952dd13aa9a5d2
[6.0.1]: https://github.com/sebastianbergmann/exporter/compare/6.0.0...6.0.1
[6.0.0]: https://github.com/sebastianbergmann/exporter/compare/5.1...6.0.0
[5.1.2]: https://github.com/sebastianbergmann/exporter/compare/5.1.1...5.1.2
[5.1.1]: https://github.com/sebastianbergmann/exporter/compare/5.1.0...5.1.1
[5.1.0]: https://github.com/sebastianbergmann/exporter/compare/5.0.1...5.1.0
[5.0.1]: https://github.com/sebastianbergmann/exporter/compare/5.0.0...5.0.1
[5.0.0]: https://github.com/sebastianbergmann/exporter/compare/4.0.5...5.0.0
[4.0.5]: https://github.com/sebastianbergmann/exporter/compare/4.0.4...4.0.5
[4.0.4]: https://github.com/sebastianbergmann/exporter/compare/4.0.3...4.0.4
[4.0.3]: https://github.com/sebastianbergmann/exporter/compare/4.0.2...4.0.3
[4.0.2]: https://github.com/sebastianbergmann/exporter/compare/4.0.1...4.0.2
[4.0.1]: https://github.com/sebastianbergmann/exporter/compare/4.0.0...4.0.1
[4.0.0]: https://github.com/sebastianbergmann/exporter/compare/3.1.2...4.0.0
[3.1.5]: https://github.com/sebastianbergmann/exporter/compare/3.1.4...3.1.5
[3.1.4]: https://github.com/sebastianbergmann/exporter/compare/3.1.3...3.1.4
[3.1.3]: https://github.com/sebastianbergmann/exporter/compare/3.1.2...3.1.3
[3.1.2]: https://github.com/sebastianbergmann/exporter/compare/3.1.1...3.1.2

View File

@ -356,7 +356,7 @@ final readonly class Exporter
ini_set('precision', $precisionBackup);
if ((string) (int) $value === $valueAsString) {
if ((string) @(int) $value === $valueAsString) {
return $valueAsString . '.0';
}
@ -405,6 +405,7 @@ final readonly class Exporter
. ' ' .
$this->recursiveExport($k, $indentation)
. ' => ' .
/** @phpstan-ignore offsetAccess.invalidOffset */
$this->recursiveExport($value[$k], $indentation + 1, $processed)
. ",\n";
}

View File

@ -67,7 +67,7 @@ final class ExporterTest extends TestCase
$obj->self = $obj;
$storage = new SplObjectStorage;
$storage->attach($obj2);
$storage->offsetSet($obj2);
$resource = fopen('php://memory', 'r');

View File

@ -1,10 +1,10 @@
{
"require-dev": {
"phpstan/phpstan": "^2.1.8",
"phpstan/phpstan": "^2.1.28",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan-strict-rules": "^2.0.3",
"phpstan/phpstan-strict-rules": "^2.0.6",
"tomasvotruba/type-coverage": "^2.0.2",
"ergebnis/phpstan-rules": "^2.8.0"
"ergebnis/phpstan-rules": "^2.12.0"
},
"config": {
"allow-plugins": {

View File

@ -4,39 +4,40 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "7c032feec49c9dbbdaa0d52198cabb4c",
"content-hash": "82891e636eae6e96ecd26fa1ee317643",
"packages": [],
"packages-dev": [
{
"name": "ergebnis/phpstan-rules",
"version": "2.8.0",
"version": "2.12.0",
"source": {
"type": "git",
"url": "https://github.com/ergebnis/phpstan-rules.git",
"reference": "30e790621fbad05573ef9cd355279fff5122e080"
"reference": "c4e0121a937b3b551f800a86e7d78794da2783ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ergebnis/phpstan-rules/zipball/30e790621fbad05573ef9cd355279fff5122e080",
"reference": "30e790621fbad05573ef9cd355279fff5122e080",
"url": "https://api.github.com/repos/ergebnis/phpstan-rules/zipball/c4e0121a937b3b551f800a86e7d78794da2783ea",
"reference": "c4e0121a937b3b551f800a86e7d78794da2783ea",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"phpstan/phpstan": "^2.0.0"
"php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"phpstan/phpstan": "^2.1.8"
},
"require-dev": {
"codeception/codeception": "^4.0.0 || ^5.0.0",
"doctrine/orm": "^2.20.0 || ^3.3.0",
"ergebnis/composer-normalize": "^2.45.0",
"ergebnis/composer-normalize": "^2.47.0",
"ergebnis/license": "^2.6.0",
"ergebnis/php-cs-fixer-config": "^6.43.0",
"ergebnis/phpunit-slow-test-detector": "^2.18.0",
"nette/di": "^3.1.10",
"ergebnis/php-cs-fixer-config": "^6.54.0",
"ergebnis/phpunit-slow-test-detector": "^2.20.0",
"fakerphp/faker": "^1.24.1",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan-deprecation-rules": "^2.0.1",
"phpstan/phpstan-phpunit": "^2.0.4",
"phpstan/phpstan-strict-rules": "^2.0.3",
"phpstan/phpstan-deprecation-rules": "^2.0.3",
"phpstan/phpstan-phpunit": "^2.0.7",
"phpstan/phpstan-strict-rules": "^2.0.6",
"phpunit/phpunit": "^9.6.21",
"psr/container": "^2.0.2",
"symfony/finder": "^5.4.45",
@ -77,33 +78,33 @@
"security": "https://github.com/ergebnis/phpstan-rules/blob/main/.github/SECURITY.md",
"source": "https://github.com/ergebnis/phpstan-rules"
},
"time": "2025-02-18T11:20:05+00:00"
"time": "2025-09-07T13:31:33+00:00"
},
{
"name": "nette/utils",
"version": "v4.0.5",
"version": "v4.0.8",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96"
"reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/736c567e257dbe0fcf6ce81b4d6dbe05c6899f96",
"reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96",
"url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede",
"reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede",
"shasum": ""
},
"require": {
"php": "8.0 - 8.4"
"php": "8.0 - 8.5"
},
"conflict": {
"nette/finder": "<3",
"nette/schema": "<1.2.2"
},
"require-dev": {
"jetbrains/phpstorm-attributes": "dev-master",
"jetbrains/phpstorm-attributes": "^1.2",
"nette/tester": "^2.5",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.9"
},
"suggest": {
@ -121,6 +122,9 @@
}
},
"autoload": {
"psr-4": {
"Nette\\": "src"
},
"classmap": [
"src/"
]
@ -161,9 +165,9 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.0.5"
"source": "https://github.com/nette/utils/tree/v4.0.8"
},
"time": "2024-08-07T15:39:19+00:00"
"time": "2025-08-06T21:43:34+00:00"
},
{
"name": "phpstan/extension-installer",
@ -215,16 +219,16 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.8",
"version": "2.1.28",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f"
"reference": "578fa296a166605d97b94091f724f1257185d278"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/f9adff3b87c03b12cc7e46a30a524648e497758f",
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/578fa296a166605d97b94091f724f1257185d278",
"reference": "578fa296a166605d97b94091f724f1257185d278",
"shasum": ""
},
"require": {
@ -269,20 +273,20 @@
"type": "github"
}
],
"time": "2025-03-09T09:30:48+00:00"
"time": "2025-09-19T08:58:49+00:00"
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "2.0.3",
"version": "2.0.6",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba"
"reference": "f9f77efa9de31992a832ff77ea52eb42d675b094"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/8b88b5f818bfa301e0c99154ab622dace071c3ba",
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/f9f77efa9de31992a832ff77ea52eb42d675b094",
"reference": "f9f77efa9de31992a832ff77ea52eb42d675b094",
"shasum": ""
},
"require": {
@ -315,9 +319,9 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.3"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.6"
},
"time": "2025-01-21T10:52:14+00:00"
"time": "2025-07-21T12:19:29+00:00"
},
{
"name": "tomasvotruba/type-coverage",

View File

@ -14,10 +14,7 @@ if (PHP_VERSION_ID < 50600) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
throw new RuntimeException($err);
}
require_once __DIR__ . '/composer/autoload_real.php';

View File

@ -26,6 +26,12 @@ use Composer\Semver\VersionParser;
*/
class InstalledVersions
{
/**
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
* @internal
*/
private static $selfDir = null;
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
@ -322,6 +328,18 @@ class InstalledVersions
self::$installedIsLocalDir = false;
}
/**
* @return string
*/
private static function getSelfDir()
{
if (self::$selfDir === null) {
self::$selfDir = strtr(__DIR__, '\\', '/');
}
return self::$selfDir;
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
@ -336,7 +354,7 @@ class InstalledVersions
$copiedLocalDir = false;
if (self::$canGetVendors) {
$selfDir = strtr(__DIR__, '\\', '/');
$selfDir = self::getSelfDir();
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
$vendorDir = strtr($vendorDir, '\\', '/');
if (isset(self::$installedByVendor[$vendorDir])) {

View File

@ -23,6 +23,7 @@ return array(
'Nette\\NotImplementedException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\NotSupportedException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\OutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\ShouldNotHappenException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\SmartObject' => $vendorDir . '/nette/utils/src/SmartObject.php',
'Nette\\StaticClass' => $vendorDir . '/nette/utils/src/StaticClass.php',
'Nette\\UnexpectedValueException' => $vendorDir . '/nette/utils/src/exceptions.php',

View File

@ -9,5 +9,6 @@ return array(
'TomasVotruba\\TypeCoverage\\' => array($vendorDir . '/tomasvotruba/type-coverage/src'),
'PHPStan\\ExtensionInstaller\\' => array($vendorDir . '/phpstan/extension-installer/src'),
'PHPStan\\' => array($vendorDir . '/phpstan/phpstan-strict-rules/src'),
'Nette\\' => array($vendorDir . '/nette/utils/src'),
'Ergebnis\\PHPStan\\Rules\\' => array($vendorDir . '/ergebnis/phpstan-rules/src'),
);

View File

@ -20,6 +20,10 @@ class ComposerStaticInitf9e7218f71d5874b5632927df4f72bd7
'PHPStan\\ExtensionInstaller\\' => 27,
'PHPStan\\' => 8,
),
'N' =>
array (
'Nette\\' => 6,
),
'E' =>
array (
'Ergebnis\\PHPStan\\Rules\\' => 23,
@ -39,6 +43,10 @@ class ComposerStaticInitf9e7218f71d5874b5632927df4f72bd7
array (
0 => __DIR__ . '/..' . '/phpstan/phpstan-strict-rules/src',
),
'Nette\\' =>
array (
0 => __DIR__ . '/..' . '/nette/utils/src',
),
'Ergebnis\\PHPStan\\Rules\\' =>
array (
0 => __DIR__ . '/..' . '/ergebnis/phpstan-rules/src',
@ -63,6 +71,7 @@ class ComposerStaticInitf9e7218f71d5874b5632927df4f72bd7
'Nette\\NotImplementedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\NotSupportedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\OutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\ShouldNotHappenException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\SmartObject' => __DIR__ . '/..' . '/nette/utils/src/SmartObject.php',
'Nette\\StaticClass' => __DIR__ . '/..' . '/nette/utils/src/StaticClass.php',
'Nette\\UnexpectedValueException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',

View File

@ -2,41 +2,42 @@
"packages": [
{
"name": "ergebnis/phpstan-rules",
"version": "2.8.0",
"version_normalized": "2.8.0.0",
"version": "2.12.0",
"version_normalized": "2.12.0.0",
"source": {
"type": "git",
"url": "https://github.com/ergebnis/phpstan-rules.git",
"reference": "30e790621fbad05573ef9cd355279fff5122e080"
"reference": "c4e0121a937b3b551f800a86e7d78794da2783ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ergebnis/phpstan-rules/zipball/30e790621fbad05573ef9cd355279fff5122e080",
"reference": "30e790621fbad05573ef9cd355279fff5122e080",
"url": "https://api.github.com/repos/ergebnis/phpstan-rules/zipball/c4e0121a937b3b551f800a86e7d78794da2783ea",
"reference": "c4e0121a937b3b551f800a86e7d78794da2783ea",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"phpstan/phpstan": "^2.0.0"
"php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"phpstan/phpstan": "^2.1.8"
},
"require-dev": {
"codeception/codeception": "^4.0.0 || ^5.0.0",
"doctrine/orm": "^2.20.0 || ^3.3.0",
"ergebnis/composer-normalize": "^2.45.0",
"ergebnis/composer-normalize": "^2.47.0",
"ergebnis/license": "^2.6.0",
"ergebnis/php-cs-fixer-config": "^6.43.0",
"ergebnis/phpunit-slow-test-detector": "^2.18.0",
"nette/di": "^3.1.10",
"ergebnis/php-cs-fixer-config": "^6.54.0",
"ergebnis/phpunit-slow-test-detector": "^2.20.0",
"fakerphp/faker": "^1.24.1",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan-deprecation-rules": "^2.0.1",
"phpstan/phpstan-phpunit": "^2.0.4",
"phpstan/phpstan-strict-rules": "^2.0.3",
"phpstan/phpstan-deprecation-rules": "^2.0.3",
"phpstan/phpstan-phpunit": "^2.0.7",
"phpstan/phpstan-strict-rules": "^2.0.6",
"phpunit/phpunit": "^9.6.21",
"psr/container": "^2.0.2",
"symfony/finder": "^5.4.45",
"symfony/process": "^5.4.47"
},
"time": "2025-02-18T11:20:05+00:00",
"time": "2025-09-07T13:31:33+00:00",
"type": "phpstan-extension",
"extra": {
"phpstan": {
@ -77,30 +78,30 @@
},
{
"name": "nette/utils",
"version": "v4.0.5",
"version_normalized": "4.0.5.0",
"version": "v4.0.8",
"version_normalized": "4.0.8.0",
"source": {
"type": "git",
"url": "https://github.com/nette/utils.git",
"reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96"
"reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/utils/zipball/736c567e257dbe0fcf6ce81b4d6dbe05c6899f96",
"reference": "736c567e257dbe0fcf6ce81b4d6dbe05c6899f96",
"url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede",
"reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede",
"shasum": ""
},
"require": {
"php": "8.0 - 8.4"
"php": "8.0 - 8.5"
},
"conflict": {
"nette/finder": "<3",
"nette/schema": "<1.2.2"
},
"require-dev": {
"jetbrains/phpstorm-attributes": "dev-master",
"jetbrains/phpstorm-attributes": "^1.2",
"nette/tester": "^2.5",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-nette": "^2.0@stable",
"tracy/tracy": "^2.9"
},
"suggest": {
@ -111,7 +112,7 @@
"ext-mbstring": "to use Strings::lower() etc...",
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
},
"time": "2024-08-07T15:39:19+00:00",
"time": "2025-08-06T21:43:34+00:00",
"type": "library",
"extra": {
"branch-alias": {
@ -120,6 +121,9 @@
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Nette\\": "src"
},
"classmap": [
"src/"
]
@ -160,7 +164,7 @@
],
"support": {
"issues": "https://github.com/nette/utils/issues",
"source": "https://github.com/nette/utils/tree/v4.0.5"
"source": "https://github.com/nette/utils/tree/v4.0.8"
},
"install-path": "../nette/utils"
},
@ -217,17 +221,17 @@
},
{
"name": "phpstan/phpstan",
"version": "2.1.8",
"version_normalized": "2.1.8.0",
"version": "2.1.28",
"version_normalized": "2.1.28.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f"
"reference": "578fa296a166605d97b94091f724f1257185d278"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/f9adff3b87c03b12cc7e46a30a524648e497758f",
"reference": "f9adff3b87c03b12cc7e46a30a524648e497758f",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/578fa296a166605d97b94091f724f1257185d278",
"reference": "578fa296a166605d97b94091f724f1257185d278",
"shasum": ""
},
"require": {
@ -236,7 +240,7 @@
"conflict": {
"phpstan/phpstan-shim": "*"
},
"time": "2025-03-09T09:30:48+00:00",
"time": "2025-09-19T08:58:49+00:00",
"bin": [
"phpstan",
"phpstan.phar"
@ -278,17 +282,17 @@
},
{
"name": "phpstan/phpstan-strict-rules",
"version": "2.0.3",
"version_normalized": "2.0.3.0",
"version": "2.0.6",
"version_normalized": "2.0.6.0",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan-strict-rules.git",
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba"
"reference": "f9f77efa9de31992a832ff77ea52eb42d675b094"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/8b88b5f818bfa301e0c99154ab622dace071c3ba",
"reference": "8b88b5f818bfa301e0c99154ab622dace071c3ba",
"url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/f9f77efa9de31992a832ff77ea52eb42d675b094",
"reference": "f9f77efa9de31992a832ff77ea52eb42d675b094",
"shasum": ""
},
"require": {
@ -301,7 +305,7 @@
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^9.6"
},
"time": "2025-01-21T10:52:14+00:00",
"time": "2025-07-21T12:19:29+00:00",
"type": "phpstan-extension",
"extra": {
"phpstan": {
@ -323,7 +327,7 @@
"description": "Extra strict and opinionated rules for PHPStan",
"support": {
"issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.3"
"source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.6"
},
"install-path": "../phpstan/phpstan-strict-rules"
},

View File

@ -1,9 +1,9 @@
<?php return array(
'root' => array(
'name' => '__root__',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => '0ef7d66753a1282b23890c2d9a8c775607e8e07f',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -11,27 +11,27 @@
),
'versions' => array(
'__root__' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'pretty_version' => 'dev-main',
'version' => 'dev-main',
'reference' => '0ef7d66753a1282b23890c2d9a8c775607e8e07f',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
'ergebnis/phpstan-rules' => array(
'pretty_version' => '2.8.0',
'version' => '2.8.0.0',
'reference' => '30e790621fbad05573ef9cd355279fff5122e080',
'pretty_version' => '2.12.0',
'version' => '2.12.0.0',
'reference' => 'c4e0121a937b3b551f800a86e7d78794da2783ea',
'type' => 'phpstan-extension',
'install_path' => __DIR__ . '/../ergebnis/phpstan-rules',
'aliases' => array(),
'dev_requirement' => true,
),
'nette/utils' => array(
'pretty_version' => 'v4.0.5',
'version' => '4.0.5.0',
'reference' => '736c567e257dbe0fcf6ce81b4d6dbe05c6899f96',
'pretty_version' => 'v4.0.8',
'version' => '4.0.8.0',
'reference' => 'c930ca4e3cf4f17dcfb03037703679d2396d2ede',
'type' => 'library',
'install_path' => __DIR__ . '/../nette/utils',
'aliases' => array(),
@ -47,18 +47,18 @@
'dev_requirement' => true,
),
'phpstan/phpstan' => array(
'pretty_version' => '2.1.8',
'version' => '2.1.8.0',
'reference' => 'f9adff3b87c03b12cc7e46a30a524648e497758f',
'pretty_version' => '2.1.28',
'version' => '2.1.28.0',
'reference' => '578fa296a166605d97b94091f724f1257185d278',
'type' => 'library',
'install_path' => __DIR__ . '/../phpstan/phpstan',
'aliases' => array(),
'dev_requirement' => true,
),
'phpstan/phpstan-strict-rules' => array(
'pretty_version' => '2.0.3',
'version' => '2.0.3.0',
'reference' => '8b88b5f818bfa301e0c99154ab622dace071c3ba',
'pretty_version' => '2.0.6',
'version' => '2.0.6.0',
'reference' => 'f9f77efa9de31992a832ff77ea52eb42d675b094',
'type' => 'phpstan-extension',
'install_path' => __DIR__ . '/../phpstan/phpstan-strict-rules',
'aliases' => array(),

View File

@ -6,7 +6,87 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## Unreleased
For a full diff see [`2.8.0...main`][2.8.0...main].
For a full diff see [`2.12.0...main`][2.12.0...main].
## [`2.12.0`][2.12.0]
For a full diff see [`2.11.0...2.12.0`][2.11.0...2.12.0].
### Added
- Added support for PHP 8.5 ([#977]), by [@localheinz]
## [`2.11.0`][2.11.0]
For a full diff see [`2.10.5...2.11.0`][2.10.5...2.11.0].
### Changed
- Allowed installation on PHP 8.5 ([#972]), by [@localheinz]
## [`2.10.5`][2.10.5]
For a full diff see [`2.10.4...2.10.5`][2.10.4...2.10.5].
### Fixed
- Adjusted `Methods\NoNamedArgumentRule` to handle calls to constructors of variable class names ([#957]), by [@localheinz]
- Adjusted `Methods\NoNamedArgumentRule` to describe known calls only ([#958]), by [@localheinz]
## [`2.10.4`][2.10.4]
For a full diff see [`2.10.3...2.10.4`][2.10.3...2.10.4].
### Fixed
- Adjusted `Methods\NoNamedArgumentRule` to handle static calls on variable expressions ([#947]), by [@localheinz]
- Adjusted `Methods\NoNamedArgumentRule` to handle calls on invokables ([#948]), by [@localheinz]
- Adjusted `Methods\NoNamedArgumentRule` to handle calls on callables assigned to properties ([#949]), by [@localheinz]
- Adjusted `Methods\NoNamedArgumentRule` to handle all other calls with generic error message ([#951]), by [@localheinz]
## [`2.10.3`][2.10.3]
For a full diff see [`2.10.2...2.10.3`][2.10.2...2.10.3].
### Fixed
- Adjusted `Methods\InvokeParentHookMethodRule` to ignore comments ([#944]), by [@localheinz]
## [`2.10.2`][2.10.2]
For a full diff see [`2.10.1...2.10.2`][2.10.1...2.10.2].
### Fixed
- Renamed error identifier for `Methods\InvokeParentHookMethodRule` ([#943]), by [@localheinz]
## [`2.10.1`][2.10.1]
For a full diff see [`2.10.0...2.10.1`][2.10.0...2.10.1].
### Fixed
- Fixed schema for configuration of `Methods\InvokeParentHookMethodRule` ([#940]), by [@localheinz]
## [`2.10.0`][2.10.0]
For a full diff see [`2.9.0...2.10.0`][2.9.0...2.10.0].
### Added
- Added `Methods\InvokeParentHookMethodRule`, which reports an error when a hook method that overrides a hook method in a parent class does not invoke the overridden hook method in the expected order ([#939]), by [@localheinz]
## [`2.9.0`][2.9.0]
For a full diff see [`2.8.0...2.9.0`][2.8.0...2.9.0].
### Added
- Added `CallLikes\NoNamedArgumentRule`, which reports an error when an anonymous function, a function, or a method is invoked using a named argument ([#914]), by [@localheinz]
### Changed
- Required `phpstan/phpstan:^2.1.8` ([#938]), by [@localheinz]
## [`2.8.0`][2.8.0]
@ -14,7 +94,7 @@ For a full diff see [`2.7.0...2.8.0`][2.7.0...2.8.0].
### Added
- Added `allRules` parameter to allow disabling and enabling all rules ([#913]), by [@localheinz]
- Added `allRules` parameter to allow disabling and enabling all rules ([#913]), by [@localheinz]
- Added `Expressions\NoAssignByReferenceRule`, which reports an error when a variable is assigned by reference ([#914]), by [@localheinz]
## [`2.7.0`][2.7.0]
@ -499,6 +579,15 @@ For a full diff see [`362c7ea...0.1.0`][362c7ea...0.1.0].
[2.6.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.6.1
[2.7.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.7.0
[2.8.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.8.0
[2.9.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.9.0
[2.10.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.0
[2.10.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.1
[2.10.2]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.2
[2.10.3]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.3
[2.10.4]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.4
[2.10.5]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.5
[2.11.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.11.0
[2.12.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.12.0
[362c7ea...0.1.0]: https://github.com/ergebnis/phpstan-rules/compare/362c7ea...0.1.0
[0.1.0...0.2.0]: https://github.com/ergebnis/phpstan-rules/compare/0.1.0...0.2.0
@ -540,7 +629,16 @@ For a full diff see [`362c7ea...0.1.0`][362c7ea...0.1.0].
[2.6.0...2.6.1]: https://github.com/ergebnis/phpstan-rules/compare/2.6.0...2.6.1
[2.6.1...2.7.0]: https://github.com/ergebnis/phpstan-rules/compare/2.6.1...2.7.0
[2.7.0...2.8.0]: https://github.com/ergebnis/phpstan-rules/compare/2.7.0...2.8.0
[2.8.0...main]: https://github.com/ergebnis/phpstan-rules/compare/2.8.0...main
[2.8.0...2.9.0]: https://github.com/ergebnis/phpstan-rules/compare/2.8.0...2.9.0
[2.9.0...2.10.0]: https://github.com/ergebnis/phpstan-rules/compare/2.9.0...2.10.0
[2.10.0...2.10.1]: https://github.com/ergebnis/phpstan-rules/compare/2.10.0...2.10.1
[2.10.1...2.10.2]: https://github.com/ergebnis/phpstan-rules/compare/2.10.1...2.10.2
[2.10.2...2.10.3]: https://github.com/ergebnis/phpstan-rules/compare/2.10.2...2.10.3
[2.10.3...2.10.4]: https://github.com/ergebnis/phpstan-rules/compare/2.10.3...2.10.4
[2.10.4...2.10.5]: https://github.com/ergebnis/phpstan-rules/compare/2.10.4...2.10.5
[2.10.5...2.11.0]: https://github.com/ergebnis/phpstan-rules/compare/2.10.5...2.11.0
[2.11.0...2.12.0]: https://github.com/ergebnis/phpstan-rules/compare/2.11.0...2.12.0
[2.12.0...main]: https://github.com/ergebnis/phpstan-rules/compare/2.12.0...main
[#1]: https://github.com/ergebnis/phpstan-rules/pull/1
[#4]: https://github.com/ergebnis/phpstan-rules/pull/4
@ -625,6 +723,19 @@ For a full diff see [`362c7ea...0.1.0`][362c7ea...0.1.0].
[#912]: https://github.com/ergebnis/phpstan-rules/pull/912
[#913]: https://github.com/ergebnis/phpstan-rules/pull/913
[#914]: https://github.com/ergebnis/phpstan-rules/pull/914
[#938]: https://github.com/ergebnis/phpstan-rules/pull/938
[#939]: https://github.com/ergebnis/phpstan-rules/pull/939
[#940]: https://github.com/ergebnis/phpstan-rules/pull/940
[#943]: https://github.com/ergebnis/phpstan-rules/pull/943
[#944]: https://github.com/ergebnis/phpstan-rules/pull/944
[#947]: https://github.com/ergebnis/phpstan-rules/pull/947
[#948]: https://github.com/ergebnis/phpstan-rules/pull/948
[#949]: https://github.com/ergebnis/phpstan-rules/pull/949
[#951]: https://github.com/ergebnis/phpstan-rules/pull/951
[#957]: https://github.com/ergebnis/phpstan-rules/pull/957
[#958]: https://github.com/ergebnis/phpstan-rules/pull/958
[#972]: https://github.com/ergebnis/phpstan-rules/pull/972
[#977]: https://github.com/ergebnis/phpstan-rules/pull/977
[@cosmastech]: https://github.com/cosmastech
[@enumag]: https://github.com/enumag

View File

@ -44,6 +44,7 @@ includes:
This package provides the following rules for use with [`phpstan/phpstan`](https://github.com/phpstan/phpstan):
- [`Ergebnis\PHPStan\Rules\CallLikes\NoNamedArgumentRule`](https://github.com/ergebnis/phpstan-rules#calllikesnonamedargumentrule)
- [`Ergebnis\PHPStan\Rules\Classes\FinalRule`](https://github.com/ergebnis/phpstan-rules#classesfinalrule)
- [`Ergebnis\PHPStan\Rules\Classes\NoExtendsRule`](https://github.com/ergebnis/phpstan-rules#classesnoextendsrule)
- [`Ergebnis\PHPStan\Rules\Classes\PHPUnit\Framework\TestCaseWithSuffixRule`](https://github.com/ergebnis/phpstan-rules#classesphpunitframeworktestcasewithsuffixrule)
@ -63,6 +64,7 @@ This package provides the following rules for use with [`phpstan/phpstan`](https
- [`Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullDefaultValueRule`](https://github.com/ergebnis/phpstan-rules#functionsnoparameterwithnulldefaultvaluerule)
- [`Ergebnis\PHPStan\Rules\Functions\NoReturnByReferenceRule`](https://github.com/ergebnis/phpstan-rules#functionsnoreturnbyreferencerule)
- [`Ergebnis\PHPStan\Rules\Methods\FinalInAbstractClassRule`](https://github.com/ergebnis/phpstan-rules#methodsfinalinabstractclassrule)
- [`Ergebnis\PHPStan\Rules\Methods\InvokeParentHookMethodRule`](https://github.com/ergebnis/phpstan-rules#methodsinvokeparenthookmethodrule)
- [`Ergebnis\PHPStan\Rules\Methods\NoConstructorParameterWithDefaultValueRule`](https://github.com/ergebnis/phpstan-rules#methodsnoconstructorparameterwithdefaultvaluerule)
- [`Ergebnis\PHPStan\Rules\Methods\NoNullableReturnTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#methodsnonullablereturntypedeclarationrule)
- [`Ergebnis\PHPStan\Rules\Methods\NoParameterPassedByReferenceRule`](https://github.com/ergebnis/phpstan-rules#methodsnoparameterpassedbyreferencerule)
@ -73,6 +75,24 @@ This package provides the following rules for use with [`phpstan/phpstan`](https
- [`Ergebnis\PHPStan\Rules\Methods\PrivateInFinalClassRule`](https://github.com/ergebnis/phpstan-rules#methodsprivateinfinalclassrule)
- [`Ergebnis\PHPStan\Rules\Statements\NoSwitchRule`](https://github.com/ergebnis/phpstan-rules#statementsnoswitchrule)
### CallLikes
#### `CallLikes\NoNamedArgumentRule`
This rule reports an error when an anonymous function, a function, or a method is invoked using a [named argument](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments).
##### Disabling the rule
You can set the `enabled` parameter to `false` to disable this rule.
```neon
parameters:
ergebnis:
noNamedArgument:
enabled: false
```
### Classes
#### `Classes\FinalRule`
@ -131,7 +151,7 @@ This rule reports an error when a class extends another class.
By default, this rule allows the following classes to be extended:
- [`PHPUnit\Framework\TestCase`](https://github.com/sebastianbergmann/phpunit/blob/7.5.2/src/Framework/TestCase.php)
- [`PHPUnit\Framework\TestCase`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php)
##### Disabling the rule
@ -266,21 +286,6 @@ parameters:
enabled: false
```
#### `Expressions\NoEvalRule`
This rule reports an error when the language construct [`eval()`](https://www.php.net/eval) is used.
##### Disabling the rule
You can set the `enabled` parameter to `false` to disable this rule.
```neon
parameters:
ergebnis:
noEval:
enabled: false
```
#### `Expressions\NoErrorSuppressionRule`
This rule reports an error when [`@`](https://www.php.net/manual/en/language.operators.errorcontrol.php) is used to suppress errors.
@ -296,6 +301,21 @@ parameters:
enabled: false
```
#### `Expressions\NoEvalRule`
This rule reports an error when the language construct [`eval()`](https://www.php.net/eval) is used.
##### Disabling the rule
You can set the `enabled` parameter to `false` to disable this rule.
```neon
parameters:
ergebnis:
noEval:
enabled: false
```
#### `Expressions\NoIssetRule`
This rule reports an error when the language construct [`isset()`](https://www.php.net/isset) is used.
@ -409,7 +429,7 @@ parameters:
#### `Methods\FinalInAbstractClassRule`
This rule reports an error when a concrete `public` or `protected `method in an `abstract` class is not `final`.
This rule reports an error when a concrete `public` or `protected` method in an `abstract` class is not `final`.
:bulb: This rule ignores
@ -427,6 +447,63 @@ parameters:
enabled: false
```
#### `Methods\InvokeParentHookMethodRule`
This rule reports an error when a hook method that overrides a hook method in a parent class does not invoke the overridden hook method in the expected order.
##### Defaults
By default, this rule requires the following hook methods to be invoked before doing something in the overriding method:
- [`Codeception\PHPUnit\TestCase::_setUp()`](https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L11-L13)
- [`Codeception\PHPUnit\TestCase::_setUpBeforeClass()`](https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L25-L27)
- [`Codeception\Test\Unit::_before()`](https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L63-L65)
- [`Codeception\Test\Unit::_setUp()`](https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L34-L58)
- [`PHPUnit\Framework\TestCase::assertPreConditions()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2073-L2075)
- [`PHPUnit\Framework\TestCase::setUp()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2063-L2065)
- [`PHPUnit\Framework\TestCase::setUpBeforeClass()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2055-L2057)
By default, this rule requires the following hook methods to be invoked after doing something in the overriding method:
- [`Codeception\PHPUnit\TestCase::_tearDown()`](https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L18-L20)
- [`Codeception\PHPUnit\TestCase::_tearDownAfterClass()`](https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L32-L34)
- [`Codeception\Test\Unit::_after()`](https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L75-L77)
- [`Codeception\Test\Unit::_tearDown()`](https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L67-L70)
- [`PHPUnit\Framework\TestCase::assertPostConditions()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2083-L2085)
- [`PHPUnit\Framework\TestCase::tearDown()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2091-L2093)
- [`PHPUnit\Framework\TestCase::tearDownAfterClass()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2098-L2100)
##### Disabling the rule
You can set the `enabled` parameter to `false` to disable this rule.
```neon
parameters:
ergebnis:
invokeParentHookMethod:
enabled: false
```
##### Configuring methods to invoke the parent method in the right order:
You can set the `hookMethods` parameter to a list of hook methods:
```neon
parameters:
ergebnis:
invokeParentHookMethod:
hookMethods:
- className: "Example\Test\Functional\AbstractCest"
methodName: "_before"
hasContent: "yes"
invocation: "first"
```
- `className`: name of the class that declares the hook method
- `methodName`: name of the hook method
- `hasContent`: one of `"yes"`, `"no"`, `"maybe"`
- `invocation`: one of `"any"` (needs to be invoked), `"first"` (needs to be invoked before all other statements in the overriding hook method, `"last"` (needs to be invoked after all other statements in the overriding hook method)
#### `Methods\NoConstructorParameterWithDefaultValueRule`
This rule reports an error when a constructor declared in
@ -658,7 +735,7 @@ The maintainers of this project ask contributors to follow the [code of conduct]
The maintainers of this project provide limited support.
You can support the maintenance of this project by [sponsoring @localheinz](https://github.com/sponsors/localheinz) or [requesting an invoice for services related to this project](mailto:am@localheinz.com?subject=ergebnis/phpstan-rules:%20Requesting%20invoice%20for%20services).
You can support the maintenance of this project by [sponsoring @ergebnis](https://github.com/sponsors/ergebnis).
## PHP Version Support Policy

View File

@ -21,21 +21,22 @@
"security": "https://github.com/ergebnis/phpstan-rules/blob/main/.github/SECURITY.md"
},
"require": {
"php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"ext-mbstring": "*",
"phpstan/phpstan": "^2.0.0"
"phpstan/phpstan": "^2.1.8"
},
"require-dev": {
"codeception/codeception": "^4.0.0 || ^5.0.0",
"doctrine/orm": "^2.20.0 || ^3.3.0",
"ergebnis/composer-normalize": "^2.45.0",
"ergebnis/composer-normalize": "^2.47.0",
"ergebnis/license": "^2.6.0",
"ergebnis/php-cs-fixer-config": "^6.43.0",
"ergebnis/phpunit-slow-test-detector": "^2.18.0",
"nette/di": "^3.1.10",
"ergebnis/php-cs-fixer-config": "^6.54.0",
"ergebnis/phpunit-slow-test-detector": "^2.20.0",
"fakerphp/faker": "^1.24.1",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan-deprecation-rules": "^2.0.1",
"phpstan/phpstan-phpunit": "^2.0.4",
"phpstan/phpstan-strict-rules": "^2.0.3",
"phpstan/phpstan-deprecation-rules": "^2.0.3",
"phpstan/phpstan-phpunit": "^2.0.7",
"phpstan/phpstan-strict-rules": "^2.0.6",
"phpunit/phpunit": "^9.6.21",
"psr/container": "^2.0.2",
"symfony/finder": "^5.4.45",

View File

@ -1,4 +1,6 @@
conditionalTags:
Ergebnis\PHPStan\Rules\CallLikes\NoNamedArgumentRule:
phpstan.rules.rule: %ergebnis.noNamedArgument.enabled%
Ergebnis\PHPStan\Rules\Classes\FinalRule:
phpstan.rules.rule: %ergebnis.final.enabled%
Ergebnis\PHPStan\Rules\Classes\NoExtendsRule:
@ -35,6 +37,8 @@ conditionalTags:
phpstan.rules.rule: %ergebnis.noReturnByReference.enabled%
Ergebnis\PHPStan\Rules\Methods\FinalInAbstractClassRule:
phpstan.rules.rule: %ergebnis.finalInAbstractClass.enabled%
Ergebnis\PHPStan\Rules\Methods\InvokeParentHookMethodRule:
phpstan.rules.rule: %ergebnis.invokeParentHookMethod.enabled%
Ergebnis\PHPStan\Rules\Methods\NoConstructorParameterWithDefaultValueRule:
phpstan.rules.rule: %ergebnis.noConstructorParameterWithDefaultValue.enabled%
Ergebnis\PHPStan\Rules\Methods\NoNullableReturnTypeDeclarationRule:
@ -65,6 +69,9 @@ parameters:
enabled: %ergebnis.allRules%
finalInAbstractClass:
enabled: %ergebnis.allRules%
invokeParentHookMethod:
enabled: %ergebnis.allRules%
hookMethods: []
noAssignByReference:
enabled: %ergebnis.allRules%
noCompact:
@ -80,6 +87,8 @@ parameters:
enabled: %ergebnis.allRules%
noIsset:
enabled: %ergebnis.allRules%
noNamedArgument:
enabled: %ergebnis.allRules%
noNullableReturnTypeDeclaration:
enabled: %ergebnis.allRules%
noParameterPassedByReference:
@ -116,6 +125,15 @@ parametersSchema:
finalInAbstractClass: structure([
enabled: bool(),
])
invokeParentHookMethod: structure([
enabled: bool(),
hookMethods: listOf(structure([
className: string(),
hasContent: anyOf("no", "yes"),
invocation: anyOf("any", "first", "last"),
methodName: string(),
]))
])
noAssignByReference: structure([
enabled: bool(),
])
@ -138,6 +156,9 @@ parametersSchema:
noIsset: structure([
enabled: bool(),
])
noNamedArgument: structure([
enabled: bool(),
])
noNullableReturnTypeDeclaration: structure([
enabled: bool(),
])
@ -173,6 +194,9 @@ services:
-
class: Ergebnis\PHPStan\Rules\Analyzer
-
class: Ergebnis\PHPStan\Rules\CallLikes\NoNamedArgumentRule
-
class: Ergebnis\PHPStan\Rules\Classes\FinalRule
arguments:
@ -232,6 +256,11 @@ services:
-
class: Ergebnis\PHPStan\Rules\Methods\FinalInAbstractClassRule
-
class: Ergebnis\PHPStan\Rules\Methods\InvokeParentHookMethodRule
arguments:
hookMethods: %ergebnis.invokeParentHookMethod.hookMethods%
-
class: Ergebnis\PHPStan\Rules\Methods\NoConstructorParameterWithDefaultValueRule

View File

@ -0,0 +1,175 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/
namespace Ergebnis\PHPStan\Rules\CallLikes;
use Ergebnis\PHPStan\Rules\ErrorIdentifier;
use PhpParser\Node;
use PHPStan\Analyser;
use PHPStan\Rules;
use PHPStan\ShouldNotHappenException;
/**
* @implements Rules\Rule<Node\Expr\CallLike>
*/
final class NoNamedArgumentRule implements Rules\Rule
{
public function getNodeType(): string
{
return Node\Expr\CallLike::class;
}
public function processNode(
Node $node,
Analyser\Scope $scope
): array {
if (0 === \count($node->getArgs())) {
return [];
}
/** @var list<Node\Arg> $namedArguments */
$namedArguments = \array_values(\array_filter($node->getArgs(), static function (Node\Arg $argument): bool {
if (!$argument->name instanceof Node\Identifier) {
return false;
}
return true;
}));
if (0 === \count($namedArguments)) {
return [];
}
$callLike = self::describeCallLike(
$node,
$scope,
);
return \array_map(static function (Node\Arg $namedArgument) use ($callLike): Rules\RuleError {
/** @var Node\Identifier $argumentName */
$argumentName = $namedArgument->name;
$message = \sprintf(
'%s is invoked with named argument for parameter $%s.',
$callLike,
$argumentName->toString(),
);
return Rules\RuleErrorBuilder::message($message)
->identifier(ErrorIdentifier::noNamedArgument()->toString())
->build();
}, $namedArguments);
}
private static function describeCallLike(
Node\Expr\CallLike $node,
Analyser\Scope $scope
): string {
if ($node instanceof Node\Expr\FuncCall) {
$functionName = $node->name;
if ($functionName instanceof Node\Expr\PropertyFetch) {
return \sprintf(
'Callable referenced by property $%s',
$functionName->name,
);
}
if ($functionName instanceof Node\Expr\Variable) {
return \sprintf(
'Callable referenced by $%s',
$functionName->name,
);
}
if ($functionName instanceof Node\Name) {
return \sprintf(
'Function %s()',
$functionName->name,
);
}
}
if ($node instanceof Node\Expr\MethodCall) {
$methodName = $node->name;
if ($methodName instanceof Node\Identifier) {
$objectType = $scope->getType($node->var);
$methodReflection = $scope->getMethodReflection(
$objectType,
$methodName->name,
);
if (null === $methodReflection) {
throw new ShouldNotHappenException();
}
$declaringClass = $methodReflection->getDeclaringClass();
if ($declaringClass->isAnonymous()) {
return \sprintf(
'Method %s() of anonymous class',
$methodName->toString(),
);
}
return \sprintf(
'Method %s::%s()',
$declaringClass->getName(),
$methodName->toString(),
);
}
return 'Method';
}
if ($node instanceof Node\Expr\StaticCall) {
$methodName = $node->name;
if ($methodName instanceof Node\Identifier) {
$className = $node->class;
if ($className instanceof Node\Name) {
return \sprintf(
'Method %s::%s()',
$className->toString(),
$methodName->toString(),
);
}
return \sprintf(
'Method %s()',
$methodName->toString(),
);
}
return 'Method';
}
if ($node instanceof Node\Expr\New_) {
$className = $node->class;
if ($className instanceof Node\Name) {
return \sprintf(
'Constructor of %s',
$className->toString(),
);
}
return 'Constructor';
}
return 'Callable';
}
}

View File

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/
namespace Ergebnis\PHPStan\Rules;
/**
* @internal
*/
final class ClassName
{
private string $value;
/**
* @param class-string $value
*/
private function __construct(string $value)
{
$this->value = $value;
}
/**
* @param class-string $value
*/
public static function fromString(string $value): self
{
return new self($value);
}
/**
* @return class-string
*/
public function toString(): string
{
return $this->value;
}
public function equals(self $other): bool
{
return $this->value === $other->value;
}
}

View File

@ -93,11 +93,11 @@ final class FinalRule implements Rules\Rule
return [];
}
if ($this->hasWhitelistedAnnotation($node)) {
if (self::hasWhitelistedAnnotation($node)) {
return [];
}
if ($this->hasWhitelistedAttribute($node)) {
if (self::hasWhitelistedAttribute($node)) {
return [];
}
@ -124,7 +124,7 @@ final class FinalRule implements Rules\Rule
* @see https://github.com/SpacePossum
* @see https://github.com/Slamdunk
*/
private function hasWhitelistedAnnotation(Node\Stmt\Class_ $node): bool
private static function hasWhitelistedAnnotation(Node\Stmt\Class_ $node): bool
{
$docComment = $node->getDocComment();
@ -147,7 +147,7 @@ final class FinalRule implements Rules\Rule
return false;
}
private function hasWhitelistedAttribute(Node\Stmt\Class_ $node): bool
private static function hasWhitelistedAttribute(Node\Stmt\Class_ $node): bool
{
foreach ($node->attrGroups as $attributeGroup) {
foreach ($attributeGroup->attrs as $attribute) {

View File

@ -17,6 +17,7 @@ use Ergebnis\PHPStan\Rules\ErrorIdentifier;
use PhpParser\Node;
use PHPStan\Analyser;
use PHPStan\Rules;
use PHPUnit\Framework;
/**
* @implements Rules\Rule<Node\Stmt\Class_>
@ -27,7 +28,7 @@ final class NoExtendsRule implements Rules\Rule
* @var list<class-string>
*/
private static array $defaultClassesAllowedToBeExtended = [
'PHPUnit\\Framework\\TestCase',
Framework\TestCase::class,
];
/**

View File

@ -65,7 +65,7 @@ final class TestCaseWithSuffixRule implements Rules\Rule
$extendedPhpunitTestCaseClassName = '';
foreach (self::$phpunitTestCaseClassNames as $phpunitTestCaseClassName) {
if ($classReflection->isSubclassOf($phpunitTestCaseClassName)) {
if ($classReflection->isSubclassOfClass($this->reflectionProvider->getClass($phpunitTestCaseClassName))) {
$extendedPhpunitTestCaseClassName = $phpunitTestCaseClassName;
break;

View File

@ -14,7 +14,7 @@ declare(strict_types=1);
namespace Ergebnis\PHPStan\Rules;
/**
* @internale
* @internal
*/
final class ErrorIdentifier
{
@ -40,6 +40,11 @@ final class ErrorIdentifier
return new self('finalInAbstractClass');
}
public static function invokeParentHookMethod(): self
{
return new self('invokeParentHookMethod');
}
public static function noCompact(): self
{
return new self('noCompact');
@ -75,6 +80,11 @@ final class ErrorIdentifier
return new self('noIsset');
}
public static function noNamedArgument(): self
{
return new self('noNamedArgument');
}
public static function noParameterPassedByReference(): self
{
return new self('noParameterPassedByReference');

View File

@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/
namespace Ergebnis\PHPStan\Rules;
/**
* @internal
*/
final class HasContent
{
private string $value;
private function __construct(string $value)
{
$this->value = $value;
}
/**
* @throws \InvalidArgumentException
*/
public static function fromString(string $value): self
{
$values = [
'maybe',
'no',
'yes',
];
if (!\in_array($value, $values, true)) {
throw new \InvalidArgumentException(\sprintf(
'Value needs to be one of "%s", got "%s" instead.',
\implode('", "', $values),
$value,
));
}
return new self($value);
}
public static function maybe(): self
{
return new self('maybe');
}
public static function no(): self
{
return new self('no');
}
public static function yes(): self
{
return new self('yes');
}
public function toString(): string
{
return $this->value;
}
public function equals(self $other): bool
{
return $this->value === $other->value;
}
}

View File

@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/
namespace Ergebnis\PHPStan\Rules;
/**
* @internal
*/
final class HookMethod
{
private ClassName $className;
private MethodName $methodName;
private Invocation $invocation;
private HasContent $hasContent;
private function __construct(
ClassName $className,
MethodName $methodName,
Invocation $invocation,
HasContent $hasContent
) {
$this->className = $className;
$this->methodName = $methodName;
$this->invocation = $invocation;
$this->hasContent = $hasContent;
}
public static function create(
ClassName $className,
MethodName $methodName,
Invocation $invocation,
HasContent $hasContent
): self {
return new self(
$className,
$methodName,
$invocation,
$hasContent,
);
}
public function className(): ClassName
{
return $this->className;
}
public function methodName(): MethodName
{
return $this->methodName;
}
public function invocation(): Invocation
{
return $this->invocation;
}
public function hasContent(): HasContent
{
return $this->hasContent;
}
}

View File

@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/
namespace Ergebnis\PHPStan\Rules;
/**
* @internal
*/
final class Invocation
{
private string $value;
/**
* @param non-empty-string $value
*/
private function __construct(string $value)
{
$this->value = $value;
}
/**
* @throws \InvalidArgumentException
*/
public static function fromString(string $value): self
{
$values = [
'any',
'first',
'last',
'never',
];
if (!\in_array($value, $values, true)) {
throw new \InvalidArgumentException(\sprintf(
'Value needs to be one of "%s", got "%s" instead.',
\implode('", "', $values),
$value,
));
}
return new self($value);
}
public static function any(): self
{
return new self('any');
}
public static function first(): self
{
return new self('first');
}
public static function last(): self
{
return new self('last');
}
public static function never(): self
{
return new self('never');
}
/**
* @return non-empty-string
*/
public function toString(): string
{
return $this->value;
}
public function equals(self $other): bool
{
return $this->value === $other->value;
}
}

View File

@ -0,0 +1,51 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/
namespace Ergebnis\PHPStan\Rules;
/**
* @internal
*/
final class MethodName
{
private string $value;
/**
* @param non-empty-string $value
*/
private function __construct(string $value)
{
$this->value = $value;
}
/**
* @param non-empty-string $value
*/
public static function fromString(string $value): self
{
return new self($value);
}
/**
* @return non-empty-string
*/
public function toString(): string
{
return $this->value;
}
public function equals(self $other): bool
{
return $this->value === $other->value;
}
}

View File

@ -13,6 +13,7 @@ declare(strict_types=1);
namespace Ergebnis\PHPStan\Rules\Methods;
use Doctrine\ORM;
use Ergebnis\PHPStan\Rules\ErrorIdentifier;
use PhpParser\Node;
use PHPStan\Analyser;
@ -27,10 +28,10 @@ use PHPStan\Rules;
final class FinalInAbstractClassRule implements Rules\Rule
{
private const DOCTRINE_ATTRIBUTE_NAMES = [
'Doctrine\\ORM\\Mapping\\Embeddable',
'Doctrine\\ORM\\Mapping\\Entity',
ORM\Mapping\Embeddable::class,
ORM\Mapping\Entity::class,
];
private const DOCTRINE_TAG_NAMES = [
private const DOCTRINE_ANNOTATION_NAMES = [
'@ORM\\Mapping\\Embeddable',
'@ORM\\Embeddable',
'@Embeddable',
@ -111,7 +112,7 @@ final class FinalInAbstractClassRule implements Rules\Rule
continue;
}
if (\in_array($child->name, self::DOCTRINE_TAG_NAMES, true)) {
if (\in_array($child->name, self::DOCTRINE_ANNOTATION_NAMES, true)) {
return true;
}
}

View File

@ -0,0 +1,436 @@
<?php
declare(strict_types=1);
/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/
namespace Ergebnis\PHPStan\Rules\Methods;
use Codeception\PHPUnit;
use Codeception\Test;
use Ergebnis\PHPStan\Rules\ClassName;
use Ergebnis\PHPStan\Rules\ErrorIdentifier;
use Ergebnis\PHPStan\Rules\HasContent;
use Ergebnis\PHPStan\Rules\HookMethod;
use Ergebnis\PHPStan\Rules\Invocation;
use Ergebnis\PHPStan\Rules\MethodName;
use PhpParser\Node;
use PHPStan\Analyser;
use PHPStan\Reflection;
use PHPStan\Rules;
use PHPStan\ShouldNotHappenException;
use PHPUnit\Framework;
/**
* @implements Rules\Rule<Node\Stmt\ClassMethod>
*/
final class InvokeParentHookMethodRule implements Rules\Rule
{
private Reflection\ReflectionProvider $reflectionProvider;
/**
* @var list<HookMethod>
*/
private array $hookMethods;
/**
* @param array<class-string, array<string, string>> $hookMethods
*/
public function __construct(
Reflection\ReflectionProvider $reflectionProvider,
array $hookMethods = []
) {
$this->reflectionProvider = $reflectionProvider;
$this->hookMethods = self::sort(
$reflectionProvider,
...self::filter(
$reflectionProvider,
...\array_merge(
self::defaultHookMethods(),
\array_map(static function (array $hookMethod): HookMethod {
return HookMethod::create(
ClassName::fromString($hookMethod['className']),
MethodName::fromString($hookMethod['methodName']),
Invocation::fromString($hookMethod['invocation']),
HasContent::fromString($hookMethod['hasContent']),
);
}, $hookMethods),
),
),
);
}
public function getNodeType(): string
{
return Node\Stmt\ClassMethod::class;
}
public function processNode(
Node $node,
Analyser\Scope $scope
): array {
$classReflection = $scope->getClassReflection();
if (null === $classReflection) {
return [];
}
$parentClassReflection = $classReflection->getParentClass();
if (null === $parentClassReflection) {
return [];
}
$methodName = $node->name->toString();
$hookMethod = $this->findMatchingHookMethod(
$scope,
$parentClassReflection,
$classReflection,
$methodName,
);
if (!$hookMethod instanceof HookMethod) {
return [];
}
$statements = $node->getStmts();
if (!\is_array($statements)) {
throw new ShouldNotHappenException();
}
$parentHookMethodInvocation = self::findParentHookMethodInvocation(
\array_values($statements),
$hookMethod,
);
if ($parentHookMethodInvocation->equals(Invocation::never())) {
if ($hookMethod->hasContent()->equals(HasContent::no())) {
return [];
}
$message = \sprintf(
'Method %s::%s() does not invoke parent::%s().',
$classReflection->getName(),
$methodName,
$hookMethod->methodName()->toString(),
);
return [
Rules\RuleErrorBuilder::message($message)
->identifier(ErrorIdentifier::invokeParentHookMethod()->toString())
->build(),
];
}
if ($parentHookMethodInvocation->equals($hookMethod->invocation())) {
return [];
}
if ($hookMethod->invocation()->equals(Invocation::first())) {
$message = \sprintf(
'Method %s::%s() does not invoke parent::%s() before all other statements.',
$classReflection->getName(),
$methodName,
$hookMethod->methodName()->toString(),
);
return [
Rules\RuleErrorBuilder::message($message)
->identifier(ErrorIdentifier::invokeParentHookMethod()->toString())
->build(),
];
}
if ($hookMethod->invocation()->equals(Invocation::last())) {
$message = \sprintf(
'Method %s::%s() does not invoke parent::%s() after all other statements.',
$classReflection->getName(),
$methodName,
$hookMethod->methodName()->toString(),
);
return [
Rules\RuleErrorBuilder::message($message)
->identifier(ErrorIdentifier::invokeParentHookMethod()->toString())
->build(),
];
}
throw new ShouldNotHappenException();
}
private function findMatchingHookMethod(
Analyser\Scope $scope,
Reflection\ClassReflection $parentClassReflection,
Reflection\ClassReflection $classReflection,
string $methodName
): ?HookMethod {
foreach ($this->hookMethods as $hookMethod) {
if (!$classReflection->isSubclassOfClass($this->reflectionProvider->getClass($hookMethod->className()->toString()))) {
continue;
}
if (\mb_strtolower($hookMethod->methodName()->toString()) !== \mb_strtolower($methodName)) {
continue;
}
$parentMethodReflection = $parentClassReflection->getMethod(
$methodName,
$scope,
);
$declaringClassReflection = $parentMethodReflection->getDeclaringClass();
if (\mb_strtolower($hookMethod->className()->toString()) !== \mb_strtolower($declaringClassReflection->getName())) {
return HookMethod::create(
ClassName::fromString($declaringClassReflection->getName()),
MethodName::fromString($methodName),
$hookMethod->invocation(),
HasContent::maybe(),
);
}
return $hookMethod;
}
return null;
}
/**
* @param list<Node\Stmt> $statements
*/
private static function findParentHookMethodInvocation(
array $statements,
HookMethod $hookMethod
): Invocation {
$statementsWithOperations = \array_filter($statements, static function (Node $statement): bool {
if ($statement instanceof Node\Stmt\Nop) {
return false;
}
return true;
});
$statementCount = \count($statementsWithOperations);
foreach ($statementsWithOperations as $index => $statement) {
if (!$statement instanceof Node\Stmt\Expression) {
continue;
}
if (!$statement->expr instanceof Node\Expr\StaticCall) {
continue;
}
if (!$statement->expr->class instanceof Node\Name) {
continue;
}
$className = (string) $statement->expr->class;
if (\mb_strtolower($className) !== 'parent') {
continue;
}
if (!$statement->expr->name instanceof Node\Identifier) {
continue;
}
if (\mb_strtolower($statement->expr->name->toString()) === \mb_strtolower($hookMethod->methodName()->toString())) {
if (1 === $statementCount) {
return $hookMethod->invocation();
}
if (0 === $index) {
return Invocation::first();
}
if ($statementCount - 1 === $index) {
return Invocation::last();
}
return Invocation::any();
}
}
return Invocation::never();
}
/**
* @return list<HookMethod>
*/
private static function filter(
Reflection\ReflectionProvider $reflectionProvider,
HookMethod ...$hookMethods
): array {
return \array_values(\array_filter($hookMethods, static function (HookMethod $hookMethod) use ($reflectionProvider): bool {
return $reflectionProvider->hasClass($hookMethod->className()->toString());
}));
}
/**
* @return list<HookMethod>
*/
private static function sort(
Reflection\ReflectionProvider $reflectionProvider,
HookMethod ...$hookMethods
): array {
\usort($hookMethods, static function (HookMethod $a, HookMethod $b) use ($reflectionProvider): int {
if (\mb_strtolower($a->className()->toString()) === \mb_strtolower($b->className()->toString())) {
return 0;
}
if ($reflectionProvider->getClass($a->className()->toString())->isSubclassOfClass($reflectionProvider->getClass($b->className()->toString()))) {
return -1;
}
return 1;
});
return $hookMethods;
}
/**
* @return list<HookMethod>
*/
private static function defaultHookMethods(): array
{
return [
/**
* @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2083-L2085
*/
HookMethod::create(
ClassName::fromString(Framework\TestCase::class),
MethodName::fromString('assertPostConditions'),
Invocation::last(),
HasContent::no(),
),
/**
* @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2073-L2075
*/
HookMethod::create(
ClassName::fromString(Framework\TestCase::class),
MethodName::fromString('assertPreConditions'),
Invocation::first(),
HasContent::no(),
),
/**
* @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2063-L2065
*/
HookMethod::create(
ClassName::fromString(Framework\TestCase::class),
MethodName::fromString('setUp'),
Invocation::first(),
HasContent::no(),
),
/**
* @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2055-L2057
*/
HookMethod::create(
ClassName::fromString(Framework\TestCase::class),
MethodName::fromString('setUpBeforeClass'),
Invocation::first(),
HasContent::no(),
),
/**
* @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2091-L2093
*/
HookMethod::create(
ClassName::fromString(Framework\TestCase::class),
MethodName::fromString('tearDown'),
Invocation::last(),
HasContent::no(),
),
/**
* @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2098-L2100
*/
HookMethod::create(
ClassName::fromString(Framework\TestCase::class),
MethodName::fromString('tearDownAfterClass'),
Invocation::last(),
HasContent::no(),
),
/**
* @see https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L11-L13
*/
HookMethod::create(
ClassName::fromString(PHPUnit\TestCase::class),
MethodName::fromString('_setUp'),
Invocation::first(),
HasContent::no(),
),
/**
* @see https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L25-L27
*/
HookMethod::create(
ClassName::fromString(PHPUnit\TestCase::class),
MethodName::fromString('_setUpBeforeClass'),
Invocation::first(),
HasContent::no(),
),
/**
* @see https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L18-L20
*/
HookMethod::create(
ClassName::fromString(PHPUnit\TestCase::class),
MethodName::fromString('_tearDown'),
Invocation::last(),
HasContent::no(),
),
/**
* @see https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L32-L34
*/
HookMethod::create(
ClassName::fromString(PHPUnit\TestCase::class),
MethodName::fromString('_tearDownAfterClass'),
Invocation::last(),
HasContent::no(),
),
/**
* @see https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L75-L77
*/
HookMethod::create(
ClassName::fromString(Test\Unit::class),
MethodName::fromString('_after'),
Invocation::last(),
HasContent::no(),
),
/**
* @see https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L63-L65
*/
HookMethod::create(
ClassName::fromString(Test\Unit::class),
MethodName::fromString('_before'),
Invocation::first(),
HasContent::no(),
),
/**
* @see https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L34-L58
*/
HookMethod::create(
ClassName::fromString(Test\Unit::class),
MethodName::fromString('_setUp'),
Invocation::first(),
HasContent::yes(),
),
/**
* @see https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L67-L70
*/
HookMethod::create(
ClassName::fromString(Test\Unit::class),
MethodName::fromString('_tearDown'),
Invocation::last(),
HasContent::yes(),
),
];
}
}

View File

@ -15,13 +15,13 @@
}
],
"require": {
"php": "8.0 - 8.4"
"php": "8.0 - 8.5"
},
"require-dev": {
"nette/tester": "^2.5",
"tracy/tracy": "^2.9",
"phpstan/phpstan": "^1.0",
"jetbrains/phpstorm-attributes": "dev-master"
"phpstan/phpstan-nette": "^2.0@stable",
"jetbrains/phpstorm-attributes": "^1.2"
},
"conflict": {
"nette/finder": "<3",
@ -36,7 +36,10 @@
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
},
"autoload": {
"classmap": ["src/"]
"classmap": ["src/"],
"psr-4": {
"Nette\\": "src"
}
},
"minimum-stability": "dev",
"scripts": {

View File

@ -41,7 +41,7 @@ The recommended way to install is via Composer:
composer require nette/utils
```
Nette Utils 4.0 is compatible with PHP 8.0 to 8.4.
Nette Utils 4.0 is compatible with PHP 8.0 to 8.5.
 <!---->

View File

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function count, is_array, is_scalar, sprintf;
/**
@ -59,7 +60,7 @@ class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \Iterator
/**
* Replaces or appends a item.
* Replaces or appends an item.
* @param array-key $key
* @param T $value
*/
@ -74,7 +75,7 @@ class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \Iterator
/**
* Returns a item.
* Returns an item.
* @param array-key $key
* @return T
*/
@ -86,7 +87,7 @@ class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \Iterator
/**
* Determines whether a item exists.
* Determines whether an item exists.
* @param array-key $key
*/
public function offsetExists($key): bool

View File

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function array_slice, array_splice, count, is_int;
/**
@ -63,7 +64,7 @@ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
/**
* Replaces or appends a item.
* Replaces or appends an item.
* @param int|null $index
* @param T $value
* @throws Nette\OutOfRangeException
@ -83,7 +84,7 @@ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
/**
* Returns a item.
* Returns an item.
* @param int $index
* @return T
* @throws Nette\OutOfRangeException
@ -99,7 +100,7 @@ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
/**
* Determines whether a item exists.
* Determines whether an item exists.
* @param int $index
*/
public function offsetExists($index): bool
@ -124,7 +125,7 @@ class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate
/**
* Prepends a item.
* Prepends an item.
* @param T $value
*/
public function prepend(mixed $value): void

View File

@ -11,7 +11,8 @@ namespace Nette\Utils;
use JetBrains\PhpStorm\Language;
use Nette;
use function is_array, is_int, is_object, count;
use function array_combine, array_intersect_key, array_is_list, array_key_exists, array_key_first, array_key_last, array_keys, array_reverse, array_search, array_slice, array_walk_recursive, count, func_num_args, in_array, is_array, is_int, is_object, key, preg_split, range;
use const PHP_VERSION_ID, PREG_GREP_INVERT, PREG_SPLIT_DELIM_CAPTURE, PREG_SPLIT_NO_EMPTY;
/**
@ -265,7 +266,7 @@ class Arrays
$res = [];
$cb = $preserveKeys
? function ($v, $k) use (&$res): void { $res[$k] = $v; }
: function ($v) use (&$res): void { $res[] = $v; };
: function ($v) use (&$res): void { $res[] = $v; };
array_walk_recursive($array, $cb);
return $res;
}
@ -277,7 +278,8 @@ class Arrays
*/
public static function isList(mixed $value): bool
{
return is_array($value) && (PHP_VERSION_ID < 80100
return is_array($value) && (
PHP_VERSION_ID < 80100
? !$value || array_keys($value) === range(0, count($value) - 1)
: array_is_list($value)
);

View File

@ -10,7 +10,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function is_array, is_object, is_string;
use function explode, func_get_args, ini_get, is_array, is_callable, is_object, is_string, preg_replace, restore_error_handler, set_error_handler, sprintf, str_contains, str_ends_with;
/**

View File

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function array_merge, checkdate, implode, is_numeric, is_string, preg_replace_callback, sprintf, time, trim;
/**
@ -45,7 +46,7 @@ class DateTime extends \DateTime implements \JsonSerializable
public static function from(string|int|\DateTimeInterface|null $time): static
{
if ($time instanceof \DateTimeInterface) {
return new static($time->format('Y-m-d H:i:s.u'), $time->getTimezone());
return static::createFromInterface($time);
} elseif (is_numeric($time)) {
if ($time <= self::YEAR) {
@ -76,12 +77,9 @@ class DateTime extends \DateTime implements \JsonSerializable
$s = sprintf('%04d-%02d-%02d %02d:%02d:%02.5F', $year, $month, $day, $hour, $minute, $second);
if (
!checkdate($month, $day, $year)
|| $hour < 0
|| $hour > 23
|| $minute < 0
|| $minute > 59
|| $second < 0
|| $second >= 60
|| $hour < 0 || $hour > 23
|| $minute < 0 || $minute > 59
|| $second < 0 || $second >= 60
) {
throw new Nette\InvalidArgumentException("Invalid date '$s'");
}
@ -91,26 +89,97 @@ class DateTime extends \DateTime implements \JsonSerializable
/**
* Returns new DateTime object formatted according to the specified format.
* Returns a new DateTime object formatted according to the specified format.
*/
public static function createFromFormat(
string $format,
string $time,
string $datetime,
string|\DateTimeZone|null $timezone = null,
): static|false
{
if ($timezone === null) {
$timezone = new \DateTimeZone(date_default_timezone_get());
} elseif (is_string($timezone)) {
if (is_string($timezone)) {
$timezone = new \DateTimeZone($timezone);
}
$date = parent::createFromFormat($format, $time, $timezone);
$date = parent::createFromFormat($format, $datetime, $timezone);
return $date ? static::from($date) : false;
}
public function __construct(string $datetime = 'now', ?\DateTimeZone $timezone = null)
{
$this->apply($datetime, $timezone, true);
}
public function modify(string $modifier): static
{
$this->apply($modifier);
return $this;
}
public function setDate(int $year, int $month, int $day): static
{
if (!checkdate($month, $day, $year)) {
trigger_error(sprintf(self::class . ': The date %04d-%02d-%02d is not valid.', $year, $month, $day), E_USER_WARNING);
}
return parent::setDate($year, $month, $day);
}
public function setTime(int $hour, int $minute, int $second = 0, int $microsecond = 0): static
{
if (
$hour < 0 || $hour > 23
|| $minute < 0 || $minute > 59
|| $second < 0 || $second >= 60
|| $microsecond < 0 || $microsecond >= 1_000_000
) {
trigger_error(sprintf(self::class . ': The time %02d:%02d:%08.5F is not valid.', $hour, $minute, $second + $microsecond / 1_000_000), E_USER_WARNING);
}
return parent::setTime($hour, $minute, $second, $microsecond);
}
/**
* Converts a relative time string (e.g. '10 minut') to seconds.
*/
public static function relativeToSeconds(string $relativeTime): int
{
return (new self('@0 ' . $relativeTime))
->getTimestamp();
}
private function apply(string $datetime, $timezone = null, bool $ctr = false): void
{
$relPart = '';
$absPart = preg_replace_callback(
'/[+-]?\s*\d+\s+((microsecond|millisecond|[mµu]sec)s?|[mµ]s|sec(ond)?s?|min(ute)?s?|hours?)(\s+ago)?\b/iu',
function ($m) use (&$relPart) {
$relPart .= $m[0] . ' ';
return '';
},
$datetime,
);
if ($ctr) {
parent::__construct($absPart, $timezone);
$this->handleErrors($datetime);
} elseif (trim($absPart)) {
parent::modify($absPart) && $this->handleErrors($datetime);
}
if ($relPart) {
$timezone ??= $this->getTimezone();
$this->setTimezone(new \DateTimeZone('UTC'));
parent::modify($relPart) && $this->handleErrors($datetime);
$this->setTimezone($timezone);
}
}
/**
* Returns JSON representation in ISO 8601 (used by JavaScript).
*/
@ -137,4 +206,14 @@ class DateTime extends \DateTime implements \JsonSerializable
$dolly = clone $this;
return $modify ? $dolly->modify($modify) : $dolly;
}
private function handleErrors(string $value): void
{
$errors = self::getLastErrors();
$errors = array_merge($errors['errors'] ?? [], $errors['warnings'] ?? []);
if ($errors) {
trigger_error(self::class . ': ' . implode(', ', $errors) . " '$value'", E_USER_WARNING);
}
}
}

View File

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use const DIRECTORY_SEPARATOR;
/**

View File

@ -10,6 +10,8 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function array_pop, chmod, decoct, dirname, end, fclose, file_exists, file_get_contents, file_put_contents, fopen, implode, is_dir, is_file, is_link, mkdir, preg_match, preg_split, realpath, rename, rmdir, rtrim, sprintf, str_replace, stream_copy_to_stream, stream_is_local, strtr;
use const DIRECTORY_SEPARATOR;
/**
@ -271,7 +273,7 @@ final class FileSystem
*/
public static function isAbsolute(string $path): bool
{
return (bool) preg_match('#([a-z]:)?[/\\\\]|[a-z][a-z0-9+.-]*://#Ai', $path);
return (bool) preg_match('#([a-z]:)?[/\\\]|[a-z][a-z0-9+.-]*://#Ai', $path);
}
@ -280,7 +282,7 @@ final class FileSystem
*/
public static function normalizePath(string $path): string
{
$parts = $path === '' ? [] : preg_split('~[/\\\\]+~', $path);
$parts = $path === '' ? [] : preg_split('~[/\\\]+~', $path);
$res = [];
foreach ($parts as $part) {
if ($part === '..' && $res && end($res) !== '..' && end($res) !== '') {
@ -305,6 +307,19 @@ final class FileSystem
}
/**
* Resolves a path against a base path. If the path is absolute, returns it directly, if it's relative, joins it with the base path.
*/
public static function resolvePath(string $basePath, string $path): string
{
return match (true) {
self::isAbsolute($path) => self::platformSlashes($path),
$path === '' => self::platformSlashes($basePath),
default => self::joinPaths($basePath, $path),
};
}
/**
* Converts backslashes to slashes.
*/

View File

@ -10,6 +10,8 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function array_merge, count, func_get_args, func_num_args, glob, implode, is_array, is_dir, iterator_to_array, preg_match, preg_quote, preg_replace, preg_split, rtrim, spl_object_id, sprintf, str_ends_with, str_starts_with, strnatcmp, strpbrk, strrpos, strtolower, strtr, substr, usort;
use const GLOB_NOESCAPE, GLOB_NOSORT, GLOB_ONLYDIR;
/**
@ -299,7 +301,7 @@ class Finder implements \IteratorAggregate
$operator = $operator ?: '=';
}
$date = DateTime::from($date)->format('U');
$date = DateTime::from($date)->getTimestamp();
return $this->filter(fn(FileInfo $file): bool => !$file->isFile() || Helpers::compare($file->getMTime(), $operator, $date));
}
@ -505,6 +507,6 @@ class Finder implements \IteratorAggregate
'\-' => '-',
],
);
return '#' . $anchor . $pattern . '$#D' . (defined('PHP_WINDOWS_VERSION_BUILD') ? 'i' : '');
return '#' . $anchor . $pattern . '$#D' . (Helpers::IsWindows ? 'i' : '');
}
}

View File

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function abs, is_finite, is_nan, max, round;
/**

View File

@ -10,16 +10,21 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function array_unique, ini_get, levenshtein, max, min, ob_end_clean, ob_get_clean, ob_start, preg_replace, strlen;
use const PHP_OS_FAMILY;
class Helpers
{
public const IsWindows = PHP_OS_FAMILY === 'Windows';
/**
* Executes a callback and returns the captured output as a string.
*/
public static function capture(callable $func): string
{
ob_start(function () {});
ob_start(fn() => '');
try {
$func();
return ob_get_clean();

View File

@ -11,7 +11,8 @@ namespace Nette\Utils;
use Nette;
use Nette\HtmlStringable;
use function is_array, is_float, is_object, is_string;
use function array_merge, array_splice, count, explode, func_num_args, html_entity_decode, htmlspecialchars, http_build_query, implode, is_array, is_bool, is_float, is_object, is_string, json_encode, max, number_format, rtrim, str_contains, str_repeat, str_replace, strip_tags, strncmp, strpbrk, substr;
use const ENT_HTML5, ENT_NOQUOTES, ENT_QUOTES;
/**

View File

@ -10,6 +10,8 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function is_array, is_int, is_string;
use const IMG_BMP, IMG_FLIP_BOTH, IMG_FLIP_HORIZONTAL, IMG_FLIP_VERTICAL, IMG_GIF, IMG_JPG, IMG_PNG, IMG_WEBP, PATHINFO_EXTENSION;
/**
@ -718,42 +720,27 @@ class Image
*/
private function output(int $type, ?int $quality, ?string $file = null): void
{
switch ($type) {
case ImageType::JPEG:
$quality = $quality === null ? 85 : max(0, min(100, $quality));
$success = @imagejpeg($this->image, $file, $quality); // @ is escalated to exception
break;
[$defQuality, $min, $max] = match ($type) {
ImageType::JPEG => [85, 0, 100],
ImageType::PNG => [9, 0, 9],
ImageType::GIF => [null, null, null],
ImageType::WEBP => [80, 0, 100],
ImageType::AVIF => [30, 0, 100],
ImageType::BMP => [null, null, null],
default => throw new Nette\InvalidArgumentException("Unsupported image type '$type'."),
};
case ImageType::PNG:
$quality = $quality === null ? 9 : max(0, min(9, $quality));
$success = @imagepng($this->image, $file, $quality); // @ is escalated to exception
break;
case ImageType::GIF:
$success = @imagegif($this->image, $file); // @ is escalated to exception
break;
case ImageType::WEBP:
$quality = $quality === null ? 80 : max(0, min(100, $quality));
$success = @imagewebp($this->image, $file, $quality); // @ is escalated to exception
break;
case ImageType::AVIF:
$quality = $quality === null ? 30 : max(0, min(100, $quality));
$success = @imageavif($this->image, $file, $quality); // @ is escalated to exception
break;
case ImageType::BMP:
$success = @imagebmp($this->image, $file); // @ is escalated to exception
break;
default:
throw new Nette\InvalidArgumentException("Unsupported image type '$type'.");
$args = [$this->image, $file];
if ($defQuality !== null) {
$args[] = $quality === null ? $defQuality : max($min, min($max, $quality));
}
if (!$success) {
throw new ImageException(Helpers::getLastError() ?: 'Unknown error');
}
Callback::invokeSafe('image' . self::Formats[$type], $args, function (string $message) use ($file): void {
if ($file !== null) {
@unlink($file);
}
throw new ImageException($message);
});
}
@ -786,7 +773,7 @@ class Image
public function __clone()
{
ob_start(function () {});
ob_start(fn() => '');
imagepng($this->image, null, 0);
$this->setImageResource(imagecreatefromstring(ob_get_clean()));
}
@ -809,7 +796,7 @@ class Image
/**
* Prevents serialization.
*/
public function __sleep(): array
public function __serialize(): array
{
throw new Nette\NotSupportedException('You cannot serialize or unserialize ' . self::class . ' instances.');
}

View File

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function hexdec, ltrim, max, min, round, strlen;
/**

View File

@ -9,6 +9,8 @@ declare(strict_types=1);
namespace Nette\Utils;
use const IMAGETYPE_BMP, IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_WEBP;
/**
* Type of image file.

View File

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function is_array;
/**
@ -233,6 +234,7 @@ final class Iterables
$iterable instanceof \Iterator => $iterable,
$iterable instanceof \IteratorAggregate => self::toIterator($iterable->getIterator()),
is_array($iterable) => new \ArrayIterator($iterable),
default => throw new Nette\ShouldNotHappenException,
};
}
}

View File

@ -10,6 +10,8 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function defined, is_int, json_decode, json_encode, json_last_error, json_last_error_msg;
use const JSON_BIGINT_AS_STRING, JSON_FORCE_OBJECT, JSON_HEX_AMP, JSON_HEX_APOS, JSON_HEX_QUOT, JSON_HEX_TAG, JSON_OBJECT_AS_ARRAY, JSON_PRESERVE_ZERO_FRACTION, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_UNESCAPED_UNICODE;
/**

View File

@ -11,6 +11,8 @@ namespace Nette\Utils;
use Nette;
use Nette\MemberAccessException;
use function array_filter, array_merge, array_pop, array_unique, get_class_methods, get_parent_class, implode, is_a, levenshtein, method_exists, preg_match_all, preg_replace, strlen, ucfirst;
use const PREG_SET_ORDER, SORT_REGULAR;
/**

View File

@ -11,6 +11,8 @@ namespace Nette\Utils;
use Nette;
use Random\Randomizer;
use function strlen;
use const PHP_VERSION_ID;
/**

View File

@ -10,6 +10,8 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function constant, current, defined, end, explode, file_get_contents, implode, ltrim, next, ord, strrchr, strtolower, substr;
use const PHP_VERSION_ID, T_AS, T_CLASS, T_COMMENT, T_CURLY_OPEN, T_DOC_COMMENT, T_DOLLAR_OPEN_CURLY_BRACES, T_ENUM, T_INTERFACE, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAMESPACE, T_NS_SEPARATOR, T_STRING, T_TRAIT, T_USE, T_WHITESPACE, TOKEN_PARSE;
/**
@ -19,21 +21,20 @@ final class Reflection
{
use Nette\StaticClass;
/** @deprecated use Nette\Utils\Validator::isBuiltinType() */
/** @deprecated use Nette\Utils\Validators::isBuiltinType() */
public static function isBuiltinType(string $type): bool
{
return Validators::isBuiltinType($type);
}
/** @deprecated use Nette\Utils\Validator::isClassKeyword() */
/** @deprecated use Nette\Utils\Validators::isClassKeyword() */
public static function isClassKeyword(string $name): bool
{
return Validators::isClassKeyword($name);
}
/** @deprecated use native ReflectionParameter::getDefaultValue() */
public static function getParameterDefaultValue(\ReflectionParameter $param): mixed
{
if ($param->isDefaultValueConstant()) {
@ -240,9 +241,7 @@ final class Reflection
case T_CLASS:
case T_INTERFACE:
case T_TRAIT:
case PHP_VERSION_ID < 80100
? T_CLASS
: T_ENUM:
case PHP_VERSION_ID < 80100 ? T_CLASS : T_ENUM:
if ($name = self::fetch($tokens, T_STRING)) {
$class = $namespace . $name;
$classLevel = $level + 1;

View File

@ -9,6 +9,8 @@ declare(strict_types=1);
namespace Nette\Utils;
use function explode, is_string, str_contains;
/**
* ReflectionMethod preserving the original class name.

View File

@ -11,7 +11,8 @@ namespace Nette\Utils;
use JetBrains\PhpStorm\Language;
use Nette;
use function is_array, is_object, strlen;
use function array_keys, array_map, array_shift, array_values, bin2hex, class_exists, defined, extension_loaded, function_exists, htmlspecialchars, htmlspecialchars_decode, iconv, iconv_strlen, iconv_substr, implode, in_array, is_array, is_callable, is_int, is_object, is_string, key, max, mb_convert_case, mb_strlen, mb_strtolower, mb_strtoupper, mb_substr, pack, preg_last_error, preg_last_error_msg, preg_quote, preg_replace, str_contains, str_ends_with, str_repeat, str_replace, str_starts_with, strlen, strpos, strrev, strrpos, strtolower, strtoupper, strtr, substr, trim, unpack, utf8_decode;
use const ENT_IGNORE, ENT_NOQUOTES, ICONV_IMPL, MB_CASE_TITLE, PHP_EOL, PREG_OFFSET_CAPTURE, PREG_PATTERN_ORDER, PREG_SET_ORDER, PREG_SPLIT_DELIM_CAPTURE, PREG_SPLIT_NO_EMPTY, PREG_SPLIT_OFFSET_CAPTURE, PREG_UNMATCHED_AS_NULL;
/**
@ -21,14 +22,14 @@ class Strings
{
use Nette\StaticClass;
public const TrimCharacters = " \t\n\r\0\x0B\u{A0}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{200B}";
public const TrimCharacters = " \t\n\r\0\x0B\u{A0}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{200B}\u{2028}\u{3000}";
/** @deprecated use Strings::TrimCharacters */
public const TRIM_CHARACTERS = self::TrimCharacters;
/**
* @deprecated use Nette\Utils\Validator::isUnicode()
* @deprecated use Nette\Utils\Validators::isUnicode()
*/
public static function checkEncoding(string $s): bool
{
@ -547,7 +548,6 @@ class Strings
return $utf8 && $captureOffset
? self::bytesToChars($subject, [$m])[0]
: $m;
}

View File

@ -10,6 +10,8 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function array_map, array_search, array_splice, count, explode, implode, is_a, is_string, strcasecmp, strtolower, substr, trim;
use const PHP_VERSION_ID;
/**
@ -260,8 +262,8 @@ final class Type
$subtypes,
fn($subtype) => Validators::isBuiltinType($type)
? strcasecmp($type, $subtype) === 0
: is_a($subtype, $type, allow_string: true)
)
: is_a($subtype, $type, allow_string: true),
),
);
}
}

View File

@ -10,6 +10,7 @@ declare(strict_types=1);
namespace Nette\Utils;
use Nette;
use function array_key_exists, class_exists, explode, gettype, interface_exists, is_callable, is_float, is_int, is_iterable, is_numeric, is_object, is_string, preg_match, str_ends_with, str_replace, str_starts_with, strlen, strtolower, substr, trait_exists, var_export;
/**

View File

@ -11,7 +11,7 @@ namespace Nette\Utils;
/**
* The exception that is thrown when an image error occurs.
* An error occurred while working with the image.
*/
class ImageException extends \Exception
{
@ -19,7 +19,7 @@ class ImageException extends \Exception
/**
* The exception that indicates invalid image file.
* The image file is invalid or in an unsupported format.
*/
class UnknownImageFileException extends ImageException
{
@ -27,7 +27,7 @@ class UnknownImageFileException extends ImageException
/**
* The exception that indicates error of JSON encoding/decoding.
* JSON encoding or decoding failed.
*/
class JsonException extends \JsonException
{
@ -35,7 +35,7 @@ class JsonException extends \JsonException
/**
* The exception that indicates error of the last Regexp execution.
* Regular expression pattern or execution failed.
*/
class RegexpException extends \Exception
{
@ -43,7 +43,7 @@ class RegexpException extends \Exception
/**
* The exception that indicates assertion error.
* Type validation failed. The value doesn't match the expected type constraints.
*/
class AssertionException extends \Exception
{

View File

@ -11,8 +11,7 @@ namespace Nette;
/**
* The exception that is thrown when the value of an argument is
* outside the allowable range of values as defined by the invoked method.
* The value is outside the allowed range.
*/
class ArgumentOutOfRangeException extends \InvalidArgumentException
{
@ -20,8 +19,7 @@ class ArgumentOutOfRangeException extends \InvalidArgumentException
/**
* The exception that is thrown when a method call is invalid for the object's
* current state, method has been invoked at an illegal or inappropriate time.
* The object is in a state that does not allow the requested operation.
*/
class InvalidStateException extends \RuntimeException
{
@ -29,7 +27,7 @@ class InvalidStateException extends \RuntimeException
/**
* The exception that is thrown when a requested method or operation is not implemented.
* The requested feature is not implemented.
*/
class NotImplementedException extends \LogicException
{
@ -37,8 +35,7 @@ class NotImplementedException extends \LogicException
/**
* The exception that is thrown when an invoked method is not supported. For scenarios where
* it is sometimes possible to perform the requested operation, see InvalidStateException.
* The requested operation is not supported.
*/
class NotSupportedException extends \LogicException
{
@ -46,7 +43,7 @@ class NotSupportedException extends \LogicException
/**
* The exception that is thrown when a requested method or operation is deprecated.
* The requested feature is deprecated and no longer available.
*/
class DeprecatedException extends NotSupportedException
{
@ -54,7 +51,7 @@ class DeprecatedException extends NotSupportedException
/**
* The exception that is thrown when accessing a class member (property or method) fails.
* Cannot access the requested class property or method.
*/
class MemberAccessException extends \Error
{
@ -62,7 +59,7 @@ class MemberAccessException extends \Error
/**
* The exception that is thrown when an I/O error occurs.
* Failed to read from or write to a file or stream.
*/
class IOException extends \RuntimeException
{
@ -70,7 +67,7 @@ class IOException extends \RuntimeException
/**
* The exception that is thrown when accessing a file that does not exist on disk.
* The requested file does not exist.
*/
class FileNotFoundException extends IOException
{
@ -78,7 +75,7 @@ class FileNotFoundException extends IOException
/**
* The exception that is thrown when part of a file or directory cannot be found.
* The requested directory does not exist.
*/
class DirectoryNotFoundException extends IOException
{
@ -86,7 +83,7 @@ class DirectoryNotFoundException extends IOException
/**
* The exception that is thrown when an argument does not match with the expected value.
* The provided argument has invalid type or format.
*/
class InvalidArgumentException extends \InvalidArgumentException
{
@ -94,7 +91,7 @@ class InvalidArgumentException extends \InvalidArgumentException
/**
* The exception that is thrown when an illegal index was requested.
* The requested array or collection index does not exist.
*/
class OutOfRangeException extends \OutOfRangeException
{
@ -102,8 +99,16 @@ class OutOfRangeException extends \OutOfRangeException
/**
* The exception that is thrown when a value (typically returned by function) does not match with the expected value.
* The returned value has unexpected type or format.
*/
class UnexpectedValueException extends \UnexpectedValueException
{
}
/**
* Houston, we have a problem.
*/
class ShouldNotHappenException extends \LogicException
{
}

View File

@ -21,8 +21,8 @@ final class GeneratedConfig
0 => 'rules.neon',
),
),
'version' => '2.8.0',
'phpstanVersionConstraint' => '>=2.0.0.0-dev, <3.0.0.0-dev',
'version' => '2.12.0',
'phpstanVersionConstraint' => '>=2.1.8.0-dev, <3.0.0.0-dev',
),
'phpstan/phpstan-strict-rules' =>
array (
@ -35,7 +35,7 @@ final class GeneratedConfig
0 => 'rules.neon',
),
),
'version' => '2.0.3',
'version' => '2.0.6',
'phpstanVersionConstraint' => '>=2.0.4.0-dev, <3.0.0.0-dev',
),
'tomasvotruba/type-coverage' =>
@ -58,7 +58,7 @@ final class GeneratedConfig
);
/** @var string|null */
public const PHPSTAN_VERSION_CONSTRAINT = '>=2.0.4.0-dev, <3.0.0.0-dev';
public const PHPSTAN_VERSION_CONSTRAINT = '>=2.1.8.0-dev, <3.0.0.0-dev';
private function __construct()
{

View File

@ -1,6 +1,7 @@
MIT License
Copyright (c) 2016 Ondřej Mirtes
Copyright (c) 2025 PHPStan s.r.o.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -6,30 +6,29 @@
[PHPStan](https://phpstan.org/) focuses on finding bugs in your code. But in PHP there's a lot of leeway in how stuff can be written. This repository contains additional rules that revolve around strictly and strongly typed code with no loose casting for those who want additional safety in extremely defensive programming:
* Require booleans in `if`, `elseif`, ternary operator, after `!`, and on both sides of `&&` and `||`.
* Require numeric operands or arrays in `+` and numeric operands in `-`/`*`/`/`/`**`/`%`.
* Require numeric operand in `$var++`, `$var--`, `++$var`and `--$var`.
* These functions contain a `$strict` parameter for better type safety, it must be set to `true`:
* `in_array` (3rd parameter)
* `array_search` (3rd parameter)
* `array_keys` (3rd parameter; only if the 2nd parameter `$search_value` is provided)
* `base64_decode` (2nd parameter)
* Variables assigned in `while` loop condition and `for` loop initial assignment cannot be used after the loop.
* Variables set in foreach that's always looped thanks to non-empty arrays cannot be used after the loop.
* Types in `switch` condition and `case` value must match. PHP compares them loosely by default and that can lead to unexpected results.
* Check that statically declared methods are called statically.
* Disallow `empty()` - it's a very loose comparison (see [manual](https://php.net/empty)), it's recommended to use more strict one.
* Disallow short ternary operator (`?:`) - implies weak comparison, it's recommended to use null coalesce operator (`??`) or ternary operator with strict condition.
* Disallow variable variables (`$$foo`, `$this->$method()` etc.)
* Disallow overwriting variables with foreach key and value variables
* Always true `instanceof`, type-checking `is_*` functions and strict comparisons `===`/`!==`. These checks can be turned off by setting `checkAlwaysTrueInstanceof`/`checkAlwaysTrueCheckTypeFunctionCall`/`checkAlwaysTrueStrictComparison` to false.
* Correct case for referenced and called function names.
* Correct case for inherited and implemented method names.
* Contravariance for parameter types and covariance for return types in inherited methods (also known as Liskov substitution principle - LSP)
* Check LSP even for static methods
* Require calling parent constructor
* Disallow usage of backtick operator (`` $ls = `ls -la` ``)
* Closure should use `$this` directly instead of using `$this` variable indirectly
| Configuration Parameters | Rule Description |
|:---------------------------------------|:--------------------------------------------------------------------------------------------------------|
| `booleansInConditions` | Require booleans in `if`, `elseif`, ternary operator, after `!`, and on both sides of `&&` and `\|\|`. |
| `booleansInLoopConditions` | Require booleans in `while` and `do while` loop conditions. |
| `numericOperandsInArithmeticOperators` | Require numeric operand in `+$var`, `-$var`, `$var++`, `$var--`, `++$var` and `--$var`. |
| `numericOperandsInArithmeticOperators` | Require numeric operand in `$var++`, `$var--`, `++$var`and `--$var`. |
| `strictFunctionCalls` | These functions contain a `$strict` parameter for better type safety, it must be set to `true`:<br>* `in_array` (3rd parameter)<br>* `array_search` (3rd parameter)<br>* `array_keys` (3rd parameter; only if the 2nd parameter `$search_value` is provided)<br>* `base64_decode` (2nd parameter). |
| `overwriteVariablesWithLoop` | Variables assigned in `while` loop condition and `for` loop initial assignment cannot be used after the loop. |
| `overwriteVariablesWithLoop` | Variables set in foreach that's always looped thanks to non-empty arrays cannot be used after the loop. |
| `switchConditionsMatchingType` | Types in `switch` condition and `case` value must match. PHP compares them loosely by default and that can lead to unexpected results. |
| `dynamicCallOnStaticMethod` | Check that statically declared methods are called statically. |
| `disallowedEmpty` | Disallow `empty()` - it's a very loose comparison (see [manual](https://php.net/empty)), it's recommended to use more strict one. |
| `disallowedShortTernary` | Disallow short ternary operator (`?:`) - implies weak comparison, it's recommended to use null coalesce operator (`??`) or ternary operator with strict condition. |
| `noVariableVariables` | Disallow variable variables (`$$foo`, `$this->$method()` etc.). |
| `overwriteVariablesWithLoop` | Disallow overwriting variables with foreach key and value variables. |
| `checkAlwaysTrueInstanceof`, `checkAlwaysTrueCheckTypeFunctionCall`, `checkAlwaysTrueStrictComparison` | Always true `instanceof`, type-checking `is_*` functions and strict comparisons `===`/`!==`. These checks can be turned off by setting `checkAlwaysTrueInstanceof`, `checkAlwaysTrueCheckTypeFunctionCall` and `checkAlwaysTrueStrictComparison` to false. |
| | Correct case for referenced and called function names. |
| `matchingInheritedMethodNames` | Correct case for inherited and implemented method names. |
| | Contravariance for parameter types and covariance for return types in inherited methods (also known as Liskov substitution principle - LSP).|
| | Check LSP even for static methods. |
| `requireParentConstructorCall` | Require calling parent constructor. |
| `disallowedBacktick` | Disallow usage of backtick operator (`` $ls = `ls -la` ``). |
| `closureUsesThis` | Closure should use `$this` directly instead of using `$this` variable indirectly. |
Additional rules are coming in subsequent releases!
@ -64,6 +63,7 @@ parameters:
strictRules:
disallowedLooseComparison: false
booleansInConditions: false
booleansInLoopConditions: false
uselessCast: false
requireParentConstructorCall: false
disallowedBacktick: false
@ -82,7 +82,7 @@ parameters:
illegalConstructorMethodCall: false
```
Aside from introducing new custom rules, phpstan-strict-rules also [change the default values of some configuration parameters](https://github.com/phpstan/phpstan-strict-rules/blob/1.6.x/rules.neon#L1) that are present in PHPStan itself. These parameters are [documented on phpstan.org](https://phpstan.org/config-reference#stricter-analysis).
Aside from introducing new custom rules, phpstan-strict-rules also [change the default values of some configuration parameters](./rules.neon#L1) that are present in PHPStan itself. These parameters are [documented on phpstan.org](https://phpstan.org/config-reference#stricter-analysis).
## Enabling rules one-by-one
@ -105,4 +105,4 @@ parameters:
booleansInConditions: true
```
Even with `strictRules.allRules` set to `false`, part of this package is still in effect. That's because phpstan-strict-rules also [change the default values of some configuration parameters](https://github.com/phpstan/phpstan-strict-rules/blob/1.6.x/rules.neon#L1) that are present in PHPStan itself. These parameters are [documented on phpstan.org](https://phpstan.org/config-reference#stricter-analysis).
Even with `strictRules.allRules` set to `false`, part of this package is still in effect. That's because phpstan-strict-rules also [change the default values of some configuration parameters](./rules.neon#L1) that are present in PHPStan itself. These parameters are [documented on phpstan.org](https://phpstan.org/config-reference#stricter-analysis).

View File

@ -15,6 +15,7 @@ parameters:
allRules: true
disallowedLooseComparison: %strictRules.allRules%
booleansInConditions: %strictRules.allRules%
booleansInLoopConditions: [%strictRules.allRules%, %featureToggles.bleedingEdge%]
uselessCast: %strictRules.allRules%
requireParentConstructorCall: %strictRules.allRules%
disallowedBacktick: %strictRules.allRules%
@ -37,6 +38,7 @@ parametersSchema:
allRules: anyOf(bool(), arrayOf(bool())),
disallowedLooseComparison: anyOf(bool(), arrayOf(bool())),
booleansInConditions: anyOf(bool(), arrayOf(bool()))
booleansInLoopConditions: anyOf(bool(), arrayOf(bool()))
uselessCast: anyOf(bool(), arrayOf(bool()))
requireParentConstructorCall: anyOf(bool(), arrayOf(bool()))
disallowedBacktick: anyOf(bool(), arrayOf(bool()))
@ -64,12 +66,16 @@ conditionalTags:
phpstan.rules.rule: %strictRules.booleansInConditions%
PHPStan\Rules\BooleansInConditions\BooleanInBooleanOrRule:
phpstan.rules.rule: %strictRules.booleansInConditions%
PHPStan\Rules\BooleansInConditions\BooleanInDoWhileConditionRule:
phpstan.rules.rule: %strictRules.booleansInLoopConditions%
PHPStan\Rules\BooleansInConditions\BooleanInElseIfConditionRule:
phpstan.rules.rule: %strictRules.booleansInConditions%
PHPStan\Rules\BooleansInConditions\BooleanInIfConditionRule:
phpstan.rules.rule: %strictRules.booleansInConditions%
PHPStan\Rules\BooleansInConditions\BooleanInTernaryOperatorRule:
phpstan.rules.rule: %strictRules.booleansInConditions%
PHPStan\Rules\BooleansInConditions\BooleanInWhileConditionRule:
phpstan.rules.rule: %strictRules.booleansInLoopConditions%
PHPStan\Rules\Cast\UselessCastRule:
phpstan.rules.rule: %strictRules.uselessCast%
PHPStan\Rules\Classes\RequireParentConstructCallRule:
@ -100,6 +106,10 @@ conditionalTags:
phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators%
PHPStan\Rules\Operators\OperandInArithmeticPreIncrementRule:
phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators%
PHPStan\Rules\Operators\OperandInArithmeticUnaryMinusRule:
phpstan.rules.rule: [%strictRules.numericOperandsInArithmeticOperators%, %featureToggles.bleedingEdge%]
PHPStan\Rules\Operators\OperandInArithmeticUnaryPlusRule:
phpstan.rules.rule: [%strictRules.numericOperandsInArithmeticOperators%, %featureToggles.bleedingEdge%]
PHPStan\Rules\Operators\OperandsInArithmeticAdditionRule:
phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators%
PHPStan\Rules\Operators\OperandsInArithmeticDivisionRule:
@ -163,6 +173,9 @@ services:
-
class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanOrRule
-
class: PHPStan\Rules\BooleansInConditions\BooleanInDoWhileConditionRule
-
class: PHPStan\Rules\BooleansInConditions\BooleanInElseIfConditionRule
@ -172,6 +185,9 @@ services:
-
class: PHPStan\Rules\BooleansInConditions\BooleanInTernaryOperatorRule
-
class: PHPStan\Rules\BooleansInConditions\BooleanInWhileConditionRule
-
class: PHPStan\Rules\Cast\UselessCastRule
arguments:
@ -230,6 +246,12 @@ services:
-
class: PHPStan\Rules\Operators\OperandInArithmeticPreIncrementRule
-
class: PHPStan\Rules\Operators\OperandInArithmeticUnaryMinusRule
-
class: PHPStan\Rules\Operators\OperandInArithmeticUnaryPlusRule
-
class: PHPStan\Rules\Operators\OperandsInArithmeticAdditionRule

View File

@ -0,0 +1,46 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\BooleansInConditions;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\VerbosityLevel;
use function sprintf;
/**
* @implements Rule<Node\Stmt\Do_>
*/
class BooleanInDoWhileConditionRule implements Rule
{
private BooleanRuleHelper $helper;
public function __construct(BooleanRuleHelper $helper)
{
$this->helper = $helper;
}
public function getNodeType(): string
{
return Node\Stmt\Do_::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->helper->passesAsBoolean($scope, $node->cond)) {
return [];
}
$conditionExpressionType = $scope->getType($node->cond);
return [
RuleErrorBuilder::message(sprintf(
'Only booleans are allowed in a do-while condition, %s given.',
$conditionExpressionType->describe(VerbosityLevel::typeOnly()),
))->identifier('doWhile.condNotBoolean')->build(),
];
}
}

View File

@ -0,0 +1,46 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\BooleansInConditions;
use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\VerbosityLevel;
use function sprintf;
/**
* @implements Rule<Node\Stmt\While_>
*/
class BooleanInWhileConditionRule implements Rule
{
private BooleanRuleHelper $helper;
public function __construct(BooleanRuleHelper $helper)
{
$this->helper = $helper;
}
public function getNodeType(): string
{
return Node\Stmt\While_::class;
}
public function processNode(Node $node, Scope $scope): array
{
if ($this->helper->passesAsBoolean($scope, $node->cond)) {
return [];
}
$conditionExpressionType = $scope->getType($node->cond);
return [
RuleErrorBuilder::message(sprintf(
'Only booleans are allowed in a while condition, %s given.',
$conditionExpressionType->describe(VerbosityLevel::typeOnly()),
))->identifier('while.condNotBoolean')->build(),
];
}
}

View File

@ -55,12 +55,12 @@ class UselessCastRule implements Rule
return $ruleErrorBuilder;
}
$expressionTypeWithoutPhpDoc = $scope->getNativeType($node->expr);
if ($castType->isSuperTypeOf($expressionTypeWithoutPhpDoc)->yes()) {
if (!$this->treatPhpDocTypesAsCertainTip) {
return $ruleErrorBuilder;
}
if (!$this->treatPhpDocTypesAsCertainTip) {
$expressionTypeWithoutPhpDoc = $scope->getNativeType($node->expr);
if ($castType->isSuperTypeOf($expressionTypeWithoutPhpDoc)->yes()) {
return $ruleErrorBuilder;
}

View File

@ -0,0 +1,47 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Operators;
use PhpParser\Node;
use PhpParser\Node\Expr\UnaryMinus;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\VerbosityLevel;
use function sprintf;
/**
* @phpstan-implements Rule<UnaryMinus>
*/
class OperandInArithmeticUnaryMinusRule implements Rule
{
private OperatorRuleHelper $helper;
public function __construct(OperatorRuleHelper $helper)
{
$this->helper = $helper;
}
public function getNodeType(): string
{
return UnaryMinus::class;
}
public function processNode(Node $node, Scope $scope): array
{
$messages = [];
if (!$this->helper->isValidForArithmeticOperation($scope, $node->expr)) {
$varType = $scope->getType($node->expr);
$messages[] = RuleErrorBuilder::message(sprintf(
'Only numeric types are allowed in unary -, %s given.',
$varType->describe(VerbosityLevel::typeOnly()),
))->identifier('unaryMinus.nonNumeric')->build();
}
return $messages;
}
}

View File

@ -0,0 +1,47 @@
<?php declare(strict_types = 1);
namespace PHPStan\Rules\Operators;
use PhpParser\Node;
use PhpParser\Node\Expr\UnaryPlus;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\VerbosityLevel;
use function sprintf;
/**
* @phpstan-implements Rule<UnaryPlus>
*/
class OperandInArithmeticUnaryPlusRule implements Rule
{
private OperatorRuleHelper $helper;
public function __construct(OperatorRuleHelper $helper)
{
$this->helper = $helper;
}
public function getNodeType(): string
{
return UnaryPlus::class;
}
public function processNode(Node $node, Scope $scope): array
{
$messages = [];
if (!$this->helper->isValidForArithmeticOperation($scope, $node->expr)) {
$varType = $scope->getType($node->expr);
$messages[] = RuleErrorBuilder::message(sprintf(
'Only numeric types are allowed in unary +, %s given.',
$varType->describe(VerbosityLevel::typeOnly()),
))->identifier('unaryPlus.nonNumeric')->build();
}
return $messages;
}
}

View File

@ -71,8 +71,7 @@ class VariablePropertyFetchRule implements Rule
ClassReflection $classReflection
): bool
{
return $classReflection->getName() === SimpleXMLElement::class
|| $classReflection->isSubclassOf(SimpleXMLElement::class);
return $classReflection->is(SimpleXMLElement::class);
}
private function isUniversalObjectCrate(
@ -84,10 +83,7 @@ class VariablePropertyFetchRule implements Rule
continue;
}
if (
$classReflection->getName() === $className
|| $classReflection->isSubclassOf($className)
) {
if ($classReflection->is($className)) {
return true;
}
}

View File

@ -24,11 +24,29 @@ can be checked before you run the actual line.
## Sponsors
Want your logo here? [Learn more »](https://phpstan.org/sponsor)
### Gold Sponsors
<a href="https://ma.tt/"><img src="website/src/images/sponsor/matt.png" alt="Matt Mullenweg" width="290" height="64"></a>
<a href="https://mojam.co/"><img src="website/src/images/sponsor/mojam.png" alt="Mojam" width="290" height="64"></a>
<br><br>
### Silver Sponsors
<a href="https://www.startupjobs.cz/startup/shipmonk"><img src="website/src/images/sponsor/shipmonk.jpg" alt="ShipMonk" width="290" height="64"></a>
<a href="https://www.shopware.com/en/"><img src="website/src/images/sponsor/shopware.png" alt="Shopware" width="284" height="64"></a>
<br><br>
### Bronze Sponsors
<a href="https://coders.thecodingmachine.com/phpstan"><img src="website/src/images/sponsor/tcm.png" alt="TheCodingMachine" width="247" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://packagist.com/?utm_source=phpstan&utm_medium=readme&utm_campaign=sponsorlogo"><img src="website/src/images/sponsor/packagist.png" alt="Private Packagist" width="283" height="64"></a>
<br>
<a href="https://www.cdn77.com/"><img src="website/src/images/sponsor/cdn77.png" alt="CDN77" width="283" height="64"></a>
<a href="https://www.cdn77.com/"><img src="website/src/images/sponsor/cdn77.png" alt="CDN77" width="290" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://blackfire.io/docs/introduction?utm_source=phpstan&utm_medium=github_readme&utm_campaign=logo"><img src="website/src/images/sponsor/blackfire.png" alt="Blackfire.io" width="254" height="64"></a>
<br>
@ -36,23 +54,23 @@ can be checked before you run the actual line.
&nbsp;&nbsp;&nbsp;
<a href="https://www.fame.fi/"><img src="website/src/images/sponsor/fame.png" alt="Fame Helsinki" width="283" height="64"></a>
<br>
<a href="https://www.startupjobs.cz/startup/shipmonk"><img src="website/src/images/sponsor/shipmonk.jpg" alt="ShipMonk" width="290" height="64"></a>
<a href="https://werkenbijbelsimpel.nl/en/about-us/"><img src="website/src/images/sponsor/belsimpel.png" alt="Belsimpel" width="284" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://togetter.com/"><img src="website/src/images/sponsor/togetter.png" alt="Togetter" width="283" height="64"></a>
<br>
<a href="https://join.rightcapital.com/?utm_source=phpstan&utm_medium=github&utm_campaign=sponsorship"><img src="website/src/images/sponsor/rightcapital.png" alt="RightCapital" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://www.contentkingapp.com/?ref=php-developer&utm_source=phpstan&utm_medium=referral&utm_campaign=sponsorship"><img src="website/src/images/sponsor/contentking.png" alt="ContentKing" width="283" height="64"></a>
<a href="https://www.shoptet.cz/"><img src="website/src/images/sponsor/shoptet.png" alt="Shoptet" width="283" height="64"></a>
<br>
<a href="https://zol.fr?utm_source=phpstan"><img src="website/src/images/sponsor/zol.png" alt="ZOL" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://www.edgenext.com/"><img src="website/src/images/sponsor/edgenext.png" alt="EdgeNext" width="283" height="64"></a>
<br>
<a href="https://www.shopware.com/en/"><img src="website/src/images/sponsor/shopware.png" alt="Shopware" width="284" height="64"></a>
<a href="https://route4me.com/"><img src="website/src/images/sponsor/route4me.png" alt="Route4Me: Route Optimizer and Route Planner Software" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://craftcms.com/"><img src="website/src/images/sponsor/craftcms.png" alt="Craft CMS" width="283" height="64"></a>
<br>
<a href="https://www.worksome.com/"><img src="website/src/images/sponsor/worksome.png" alt="Worksome" width="283" height="64"></a>
<a href="https://jobs.ticketswap.com/"><img src="website/src/images/sponsor/ticketswap.png" alt="TicketSwap" width="269" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://www.campoint.net/"><img src="website/src/images/sponsor/campoint.png" alt="campoint AG" width="283" height="64"></a>
<br>
@ -60,18 +78,10 @@ can be checked before you run the actual line.
&nbsp;&nbsp;&nbsp;
<a href="https://inviqa.com/"><img src="website/src/images/sponsor/inviqa.png" alt="Inviqa" width="254" height="65"></a>
<br>
<a href="https://www.shoptet.cz/"><img src="website/src/images/sponsor/shoptet.png" alt="Shoptet" width="283" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://route4me.com/"><img src="website/src/images/sponsor/route4me.png" alt="Route4Me: Route Optimizer and Route Planner Software" width="283" height="64"></a>
<br>
<a href="https://werkenbijbelsimpel.nl/en/about-us/"><img src="website/src/images/sponsor/belsimpel.png" alt="Belsimpel" width="284" height="64"></a>
&nbsp;&nbsp;&nbsp;
<a href="https://jobs.ticketswap.com/"><img src="website/src/images/sponsor/ticketswap.png" alt="TicketSwap" width="269" height="64"></a>
[**You can now sponsor my open-source work on PHPStan through GitHub Sponsors.**](https://github.com/sponsors/ondrejmirtes)
Does GitHub already have your 💳? Do you use PHPStan to find 🐛 before they reach production? [Send a couple of 💸 a month my way too.](https://github.com/sponsors/ondrejmirtes) Thank you!
[**You can sponsor my open-source work on PHPStan through GitHub Sponsors and also directly.**](https://phpstan.org/sponsor)
One-time donations [through Revolut.me](https://revolut.me/ondrejmirtes) are also accepted. To request an invoice, [contact me](mailto:ondrej@mirtes.cz) through e-mail.

View File

@ -92,6 +92,16 @@ final class PharAutoloader
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php81/Php81.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php81/bootstrap.php';
}
if (
PHP_VERSION_ID < 80300
&& empty ($GLOBALS['__composer_autoload_files']['662a729f963d39afe703c9d9b7ab4a8c'])
&& !class_exists(\Symfony\Polyfill\Php83\Php83::class, false)
) {
$GLOBALS['__composer_autoload_files']['662a729f963d39afe703c9d9b7ab4a8c'] = true;
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php83/Php83.php';
require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php83/bootstrap.php';
}
}
$filename = str_replace('\\', DIRECTORY_SEPARATOR, $class);

View File

@ -1,16 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmfNX6IACgkQUcZzBf/C
5cAOGBAAibd5PkpJtT3HD4whLS7MsTSOcHoGoHNaqCqZWWk/sQPg8IqQUTCW/F4u
e1BUQ3yTSs15XhoBh5vMzZ+LEzIdoXSwGyHSdBLVdYHVsg0HD8yUfuNiKy7ycJh0
jfcckztoLWPxZCpaxbv2RQ4e7l73rw5fGYwtLiKUvuh4vmtXNHK/gn25cJtKbEn+
Gocbe9LZfoB0IPWrb/JtES8SPqs307K8v1ATj7xEFK0EtFUmie36qlFOvJZstEJ4
Ro7HWaHJJFMqeX8sABanUp42lbiEJcZEoVBnWl5UeJ5aA5NnqB8t1m95ByCn4wQp
EMg4xiKOowtowfRByQngOd2jiNH/QuNZPNwNg4/3moJuKP/7MbAzI31FkPCoIonq
gz34IhW0S0pNIWEwIHJOtRKkOio5AjS7JTlU+XWhYfEYVPat1WHBKnpv8pfK+Xoe
qkkKjHhiZJD0zyf/d3LG8U+r7Q06/hJrhSghGOMcnh66qPLjl9k9MK1vAHbae9Y9
j7SDTIZfjflFFF0iHypaU9IEUio/3tTJngE+gB6IhVhMaqySm97W3ot225hKbM1d
VS4PqlOEPgOmPt3444VqaNJUoC2zJkGUhFKTyRm9aN+/8R6foKJ4GG4DICLmDr0R
wXDbAthyzPpZ84kN2p6EgVkSFsomQgwU93VSvB69KvbNkkOfZ9I=
=mtzY
iQIzBAABCgAdFiEEynwsejDI6OEnSoR2UcZzBf/C5cAFAmjNGyEACgkQUcZzBf/C
5cCyExAAmDcbTOVhPlAYAuH9Jdegk4x19Ax4BzQqkIV021xVGsNysyg0aIPtqCUH
XpXZI0oA8plPhIctiobpyYqg4Ou2T/Y5PxxFVLhiD12AxDEa+Iy765BNeZCRRj3W
VQQyDo1gj4y9N1Tmj4CihbIXNcxhXM8OMirekDPvEQmofYrp5bgXvwbyhmFsKwq/
ToGURtUFZg8GB68FnR3SviRJgxg1z/iKA0keIYFg78tJtAgzS7eBNWBwpfWMHs8b
2Sy87IJG0JVeq7x44ktLi5pUfi5sFwqF7cpFLnnBhFcaM+Z81KpwpfVmuvhArBsy
Jw0iGsi2LilzPCyTETmv6YMMrzmyhsAmibVzEHUpGtoI+Qq2QiXfu1hhVG7nS+Bx
VtUPeXu+XlXaXnFE/xm06mootkjs6NAaREKFrH/kCnH9mT5d5eRqb1KrO/hViAUC
tGflHeuYY2BnDthpy3orOmmO+qEdTxu6M24G6ANL4RRbcad0+IC/R6+UCYy+XZlc
QHgO2UGJw6tEvqZqhBoLpd9PEljyOdEmiCBlq4sXUnXiZvGplQzM4l0tqaaAK7AT
+gsuo73rR6JcRMPagsOZ4WGae/s7wolq8uTclNSzM+EGTfgk6zI/1H1dFBtDGAdA
q6bTMydHKDrTDPscsNDYPJ2OLq1tRE+LX6pojuOGadmetq5k000=
=PLj2
-----END PGP SIGNATURE-----

Binary file not shown.

View File

@ -352,34 +352,33 @@ spl_autoload_register(
Phar::mapPhar('phive.phar');
$rc = (new Factory(new Cli\Request($_SERVER['argv']), new StaticPhiveVersion('0.15.3')))->getRunner()->run();
$rc = (new Factory(new Cli\Request($_SERVER['argv']), new StaticPhiveVersion('0.16.0')))->getRunner()->run();
exit($rc);
__HALT_COMPILER(); ?>
nX=
phive.phar+vendor/phar-io/filesystem/src/Directory.phpñå«Çfæï<>æ´4vendor/phar-io/filesystem/src/DirectoryException.phpùå«Çf<C387>=v”"´+vendor/phar-io/filesystem/src/Exception.phpfå«Çf^Å$é´&vendor/phar-io/filesystem/src/File.phpfå«ÇfüCæ+r´*vendor/phar-io/filesystem/src/Filename.php å«Çf¦VsŠ)´3vendor/phar-io/filesystem/src/FilenameException.phpmå«Çfbfo‰ý´2vendor/phar-io/filesystem/src/LastModifiedDate.phpçå«ÇfTö•…[´(vendor/phar-io/executor/src/Executor.phpå«Çf£#½j~´1vendor/phar-io/executor/src/ExecutorException.php€å«Çfg—</n´.vendor/phar-io/executor/src/ExecutorResult.phpôå«Çf/0SH´)vendor/phar-io/gnupg/src/ErrorStrings.phpuIå«ÇfçÒ»¤&vendor/phar-io/gnupg/src/Exception.phpaå«ÇfY<19>¤$vendor/phar-io/gnupg/src/Factory.php7å«Çfêjþh¤"vendor/phar-io/gnupg/src/GnuPG.php=$å«Çfó KGE ¤Dvendor/phar-io/version/src/constraints/AbstractVersionConstraint.php¯å«ÇfnoSMy´Dvendor/phar-io/version/src/constraints/AndVersionConstraintGroup.php×å«ÇfÒ/j-Ò´?vendor/phar-io/version/src/constraints/AnyVersionConstraint.php@å«ÇfLÊ[ ´Avendor/phar-io/version/src/constraints/ExactVersionConstraint.phpÈå«Çf†:B Œ´Pvendor/phar-io/version/src/constraints/GreaterThanOrEqualToVersionConstraint.php„å«Çf·ÈÉ^¼´Cvendor/phar-io/version/src/constraints/OrVersionConstraintGroup.phpÿå«ÇfÕ¿‘ר´Qvendor/phar-io/version/src/constraints/SpecificMajorAndMinorVersionConstraint.php¼å«ÇfÓLÌK´Ivendor/phar-io/version/src/constraints/SpecificMajorVersionConstraint.phpúå«Çf¢ ý´<vendor/phar-io/version/src/constraints/VersionConstraint.phpíå«Çf0ø¦õW´3vendor/phar-io/version/src/exceptions/Exception.php¨å«ÇfóÑG´Jvendor/phar-io/version/src/exceptions/InvalidPreReleaseSuffixException.php<68>å«Çfu¹»þü´Avendor/phar-io/version/src/exceptions/InvalidVersionException.php•å«Çfs|—Ê´Bvendor/phar-io/version/src/exceptions/NoBuildMetaDataException.php‡å«Çfp’°¨—´Evendor/phar-io/version/src/exceptions/NoPreReleaseSuffixException.phpŠå«ÇfrXbpÔ´Ovendor/phar-io/version/src/exceptions/UnsupportedVersionConstraintException.phpÓå«Çf%Gd´,vendor/phar-io/version/src/BuildMetaData.phpÏå«Çf|ºâúH´/vendor/phar-io/version/src/PreReleaseSuffix.php^å«Çfv.œo ´&vendor/phar-io/version/src/Version.php+å«Çf;frë¶´6vendor/phar-io/version/src/VersionConstraintParser.phpÿå«Çf<P6´5vendor/phar-io/version/src/VersionConstraintValue.php&
å«ÇfgP>13´,vendor/phar-io/version/src/VersionNumber.php¡å«ÇfkJ}Ór´6vendor/phar-io/manifest/src/ManifestDocumentMapper.php€å«Çf¤q³»¤.vendor/phar-io/manifest/src/ManifestLoader.php å«Çfq̤2vendor/phar-io/manifest/src/ManifestSerializer.php‡å«ÇfM÷Û‚¯¤Evendor/phar-io/manifest/src/exceptions/ElementCollectionException.phpå«Çf0_Uj¤4vendor/phar-io/manifest/src/exceptions/Exception.phpÈå«ÇfŽPŒ¤Jvendor/phar-io/manifest/src/exceptions/InvalidApplicationNameException.php1å«ÇfFMüV†¤@vendor/phar-io/manifest/src/exceptions/InvalidEmailException.phpå«Çf+·ˤ>vendor/phar-io/manifest/src/exceptions/InvalidUrlException.phpå«Çf/ÙY<0E>¤Dvendor/phar-io/manifest/src/exceptions/ManifestDocumentException.php÷å«Çf'à‡ o¤Kvendor/phar-io/manifest/src/exceptions/ManifestDocumentLoadingException.phpûå«Çf!˜„Õ£¤Jvendor/phar-io/manifest/src/exceptions/ManifestDocumentMapperException.phpýå«Çf0`'€i¤Cvendor/phar-io/manifest/src/exceptions/ManifestElementException.phpöå«Çf%#mߤBvendor/phar-io/manifest/src/exceptions/ManifestLoaderException.phpØå«ÇfÒ4oô¤Bvendor/phar-io/manifest/src/exceptions/NoEmailAddressException.phpå«Çf4œq:¤2vendor/phar-io/manifest/src/values/Application.phpøå«Çf5fæÒ=¤6vendor/phar-io/manifest/src/values/ApplicationName.phpœå«Çf¥¤-vendor/phar-io/manifest/src/values/Author.phpå«Çfõ<L¹¤7vendor/phar-io/manifest/src/values/AuthorCollection.phpå«Çfßã¤?vendor/phar-io/manifest/src/values/AuthorCollectionIterator.php…å«Çfè]î=Œ¤7vendor/phar-io/manifest/src/values/BundledComponent.phpHå«Çf—µZ ¤Avendor/phar-io/manifest/src/values/BundledComponentCollection.php¢å«ÇfëÇé–$¤Ivendor/phar-io/manifest/src/values/BundledComponentCollectionIterator.phpýå«Çfó:"漤;vendor/phar-io/manifest/src/values/CopyrightInformation.php\å«ÇfŒ“û¤,vendor/phar-io/manifest/src/values/Email.php<68>å«ÇfÕS|à¤0vendor/phar-io/manifest/src/values/Extension.phpå«ÇfüZ7'¤.vendor/phar-io/manifest/src/values/Library.phpðå«Çf2×çÙ¤.vendor/phar-io/manifest/src/values/License.phpüå«Çf<C387>Ý<10>/vendor/phar-io/manifest/src/values/Manifest.php-
å«ÇfÆ÷ág¤>vendor/phar-io/manifest/src/values/PhpExtensionRequirement.phpªå«ÇfwÛ(¹ì¤<vendor/phar-io/manifest/src/values/PhpVersionRequirement.php$å«Çf<C387>Á"ë&¤2vendor/phar-io/manifest/src/values/Requirement.php¨å«Çf 1šq¤¤<vendor/phar-io/manifest/src/values/RequirementCollection.php\å«ÇfäX?ñ¤Dvendor/phar-io/manifest/src/values/RequirementCollectionIterator.phpÁå«Çfíü ¤+vendor/phar-io/manifest/src/values/Type.php£å«ÇfÉ<”2¤*vendor/phar-io/manifest/src/values/Url.php«å«ÇfÝ#lÍ£¤1vendor/phar-io/manifest/src/xml/AuthorElement.phpÚå«Çfn¸þÞ2¤;vendor/phar-io/manifest/src/xml/AuthorElementCollection.phpSå«ÇfS(æ7ä¤2vendor/phar-io/manifest/src/xml/BundlesElement.phpzå«Çff‘‰}¤4vendor/phar-io/manifest/src/xml/ComponentElement.php†å«Çf`$Sg¤>vendor/phar-io/manifest/src/xml/ComponentElementCollection.php\å«ÇfT ¤3vendor/phar-io/manifest/src/xml/ContainsElement.php‰å«Çf“aÇÉΤ4vendor/phar-io/manifest/src/xml/CopyrightElement.php å«Çf}Ït)T¤5vendor/phar-io/manifest/src/xml/ElementCollection.phpËå«Çf±ç ²L¤.vendor/phar-io/manifest/src/xml/ExtElement.phpå«ÇfKÁüãë¤8vendor/phar-io/manifest/src/xml/ExtElementCollection.phpJå«ÇfQ¬ï¤4vendor/phar-io/manifest/src/xml/ExtensionElement.phpŠå«Çfaôzõj¤2vendor/phar-io/manifest/src/xml/LicenseElement.php|å«Çf\t²TX¤4vendor/phar-io/manifest/src/xml/ManifestDocument.php å«Çf9ÑS¤3vendor/phar-io/manifest/src/xml/ManifestElement.phpnå«Çf¹ªpû¤.vendor/phar-io/manifest/src/xml/PhpElement.phpå«Çf©wO¤3vendor/phar-io/manifest/src/xml/RequiresElement.phpKå«Çf^<00>¹Ü—¤)src/commands/composer/ComposerContext.php«å«Çf¨x‡•´)src/commands/composer/ComposerCommand.phpéå«ÇfÍš`^²¤/src/commands/composer/ComposerCommandConfig.phpå«Çfë Ť)src/commands/composer/ComposerService.php å«Çf,üœ±ý¤'src/commands/default/DefaultCommand.php,å«Çfʱé¬e¤-src/commands/default/DefaultCommandConfig.php<68>å«Çft@Õk™¤src/commands/help/help.mdú
å«Çf$4w´!src/commands/help/HelpCommand.phpæå«ÇfáJ<>Dˆ¤6src/commands/install/InstallCommandConfigException.phpÎå«Çf2µ„=´'src/commands/install/InstallContext.phpNå«Çfð|SÁ´-src/commands/install/InstallCommandConfig.php{å«Çf<C387>¥k¤'src/commands/install/InstallCommand.phpÖ
å«Çfˆù;â¤!src/commands/list/ListCommand.phpÇå«ÇfD|Óó»¤'src/commands/migrate/MigrateContext.phpå«ÇfPX'¬e´'src/commands/migrate/MigrateCommand.phpå«Çféî Î"¤-src/commands/migrate/MigrateCommandConfig.phptå«Çft†ÎW¤1src/commands/outdated/OutdatedConfigException.phpžå«Çfè-4ú´)src/commands/outdated/OutdatedContext.php4å«Çf§#><3E>´(src/commands/outdated/OutdatedConfig.php9å«ÇfÙ ¼ý ¤)src/commands/outdated/OutdatedCommand.phpQå«ÇfPKæä5¤#src/commands/purge/PurgeContext.php¨å«Çff«ûP´#src/commands/purge/PurgeCommand.phpså«ÇfÐ(Ò¤%src/commands/remove/RemoveContext.phpå«ÇfQ'²Ý´%src/commands/remove/RemoveCommand.php å«Çf0±ª+src/commands/remove/RemoveCommandConfig.phpå«ÇfÖ—•/@¤#src/commands/reset/ResetContext.php¨å«ÇfëE<C3AB>Å´#src/commands/reset/ResetCommand.php0å«Çfr#˜\<5C>¤)src/commands/reset/ResetCommandConfig.phpå«ÇfŸI¸óŤ-src/commands/selfupdate/SelfupdateCommand.phpïå«ÇfûgY¨U¤!src/commands/skel/SkelContext.php2å«ÇfX¢_MÍ´'src/commands/skel/SkelCommandConfig.phpå«Çf·!ƒE¤!src/commands/skel/SkelCommand.phph å«Çf™VÁü¯¤%src/commands/status/StatusContext.php±å«ÇftÀ&Ø´%src/commands/status/StatusCommand.phpô å«ÇfðêÃçò¤+src/commands/status/StatusCommandConfig.phpI
å«Çf<Uæ°<C3A6>¤Csrc/commands/update-repository-list/UpdateRepositoryListCommand.php¶å«Çf8H÷j¤%src/commands/update/UpdateContext.php„å«Çfzßfò´%src/commands/update/UpdateCommand.phpå«Çf»«ökô¤+src/commands/update/UpdateCommandConfig.php å«Çf±@ù$Œ¤'src/commands/version/VersionCommand.php å«ÇfO<00> å´src/commands/CommandLocator.phpq
å«Çf¤†X)src/services/checksum/ChecksumService.php8å«Çf 2w¡´+src/services/key/gpg/GnupgKeyDownloader.phpt
å«ÇfÒóÝ´)src/services/key/gpg/GnupgKeyImporter.phpøå«Çf £~´(src/services/key/gpg/PublicKeyReader.phpˆå«Çf5ËâW¤"src/services/key/KeyDownloader.php¨å«Çf­}.e´ src/services/key/KeyImporter.php«å«Çf÷j´$src/services/key/KeyImportResult.phpaå«Çf<C387>ÌAGõ¤src/services/key/KeyService.php å«Çf«ƒÂU¤src/services/key/PublicKey.php<68>å«Çfr:F?¤&src/services/key/TrustedCollection.phpÏå«Çf”ža~ ¤(src/services/migration/FileMigration.phpîå«Çfÿt ;Y´0src/services/migration/HomePhiveXmlMigration.php>å«Çfë?ê²´0src/services/migration/InternalFileMigration.phpYå«ÇfmòæÅ@´$src/services/migration/Migration.phpøå«ÇfÎX'mY´3src/services/migration/ProjectPhiveXmlMigration.php¢å«Çf;´,src/services/migration/UserFileMigration.phpÒå«Çf`ç¦p´0src/services/migration/HomePharsXmlMigration.phplå«Çf·]]&¤+src/services/migration/MigrationFactory.php´å«Çf»+src/services/migration/MigrationService.phpüå«Çf<00>H4¤$src/services/phar/PharDownloader.phpVå«Çfx^éë´#src/services/phar/PharInstaller.phpÏ å«Çf 5ÛJÔ´*src/services/phar/PharInstallerFactory.php†å«Çf³²ž ´*src/services/phar/PharInstallerLocator.php-å«Çf•ÝV¿´!src/services/phar/PharService.phpõå«ÇfÆí´%src/services/phar/ReleaseSelector.phpü å«Çfmÿ´*src/services/phar/UnixoidPharInstaller.php7å«Çf´n0Þ±´*src/services/phar/WindowsPharInstaller.phpÃå«ÇfÉñGŸ´$src/services/phar/InstallService.phpv å«Çf©êд*src/services/phar/CompatibilityService.phpö å«Çfð>­~^¤$src/services/phar/RemovalService.phpuå«ÇfÔ%¤<src/services/resolver/strategy/AbstractResolvingStrategy.php å«Çf+×–ÿ ´>src/services/resolver/strategy/LocalFirstResolvingStrategy.php]å«ÇfqM;Bî´?src/services/resolver/strategy/RemoteFirstResolvingStrategy.php^å«ÇfrÀÁÙ´4src/services/resolver/strategy/ResolvingStrategy.php¾å«Çf-W$Ÿ–´7src/services/resolver/AbstractRequestedPharResolver.php0å«Çf82äQ´+src/services/resolver/DirectUrlResolver.phpÝå«Çf7Ük­´-src/services/resolver/GitlabAliasResolver.phpGå«Çf¤èvãµ´,src/services/resolver/LocalAliasResolver.phpå«ÇfïÁ_«Ÿ´-src/services/resolver/PharIoAliasResolver.php” å«ÇfIÓD×X´/src/services/resolver/RequestedPharResolver.php4å«ÇfWÅR/´6src/services/resolver/RequestedPharResolverFactory.php4å«Çf.”?Lî´6src/services/resolver/RequestedPharResolverService.phpWå«ÇfÞzËÄN´=src/services/resolver/RequestedPharResolverServiceBuilder.phpòå«Çf+‡ó&´-src/services/resolver/GithubAliasResolver.phpt å«Çf@ËZt¤6src/services/signature/gpg/GnupgVerificationResult.phpƒå«ÇfkL¤5src/services/signature/gpg/GnupgSignatureVerifier.php8å«ÇfÊe '8¤,src/services/signature/SignatureVerifier.phpâå«Çf>PÏú´-src/services/signature/VerificationResult.php4å«ÇfJ·´src/shared/cli/input/Input.php¶å«Çf()D÷U´%src/shared/cli/input/ConsoleInput.php<68>å«ÇfÃK„﨤'src/shared/cli/output/ConsoleOutput.php<68>
å«ÇfyìT:|´&src/shared/cli/output/ConsoleTable.phpÍå«Çfrd#;´ src/shared/cli/output/Output.phpÚå«Çf^ï÷ùJ´'src/shared/cli/output/OutputFactory.phpµå«Çf[Q¹@´.src/shared/cli/output/ColoredConsoleOutput.php[å«Çf;Õb¤'src/shared/cli/output/OutputLocator.phpgå«Çf° A®¤src/shared/cli/Command.php“å«ÇfǯG´*src/shared/cli/CommandLocatorException.phpÁå«Çf&øtä´*src/shared/cli/CommandOptionsException.phpëå«Çf<¸Í@´src/shared/cli/Context.phpzå«ÇfšŒ4nN´#src/shared/cli/ContextException.phpáå«Çf/ÖUð´#src/shared/cli/RequestException.phpå«ÇfGMÝꪴ"src/shared/cli/RunnerException.php·å«Çfm;g¨´src/shared/cli/error.txtRå«ÇfÏçý'´!src/shared/cli/CommandLocator.phpæå«Çf7™ýo6¤!src/shared/cli/GeneralContext.phpB å«Çf´˜¤src/shared/cli/Options.php<68>å«ÇfÕ¯ÍÑ6¤src/shared/cli/Request.phpå«ÇfuË7N¤src/shared/cli/Runner.phpVå«ÇfE src/shared/config/AuthConfig.phpòå«Çf,d¥ä´#src/shared/config/AuthXmlConfig.php å«ÇfS»à¦´.src/shared/config/AuthXmlConfigFileLocator.phpxå«Çff6®Ã´)src/shared/config/CompositeAuthConfig.phpåå«Çfù1zø¢´*src/shared/config/GlobalPhiveXmlConfig.php@å«Çf_²fK[´)src/shared/config/LocalPhiveXmlConfig.phpÅå«ÇfäºqÎÙ´/src/shared/config/PhiveXmlConfigFileLocator.php)å«ÇfWQwÅ´+src/shared/config/EnvironmentAuthConfig.phpÀå«Çf¶Voݤ$src/shared/config/PhiveXmlConfig.phpÏ#å«Çfh} src/shared/config/Config.phpàå«ÇfªÛÕ5¤&src/shared/download/FileDownloader.phpj å«ÇfFcz€¹¤-src/shared/environment/EnvironmentLocator.php²å«Çf…þŸ·´-src/shared/environment/WindowsEnvironment.phpíå«Çf<C387>“… |´-src/shared/environment/UnixoidEnvironment.php
å«Çf°RsˆÁ¤&src/shared/environment/Environment.php=å«Çf'f)Ф'src/shared/exceptions/AuthException.php”å«Çf Z
´)src/shared/exceptions/ConfigException.phpå«Çf í.<2E>´-src/shared/exceptions/CurlConfigException.phpšå«ÇfÓ?c­´'src/shared/exceptions/CurlException.php”å«Çf α®ÿ´1src/shared/exceptions/DownloadFailedException.phpžå«ÇfË«)$´.src/shared/exceptions/EnvironmentException.phpå«Çf¬‰bb´(src/shared/exceptions/ErrorException.phpšå«Çf ¸W´#src/shared/exceptions/Exception.phpŽå«Çf
É<½õ´+src/shared/exceptions/ExecutorException.phpÜå«Çf.»´1src/shared/exceptions/FeatureMissingException.phpËå«Çfƒ<11>Ö´2src/shared/exceptions/FileNotWritableException.phpŸå«Çfðg )´&src/shared/exceptions/GitException.php“å«Çf
å‚=ˆ´5src/shared/exceptions/GnupgKeyDownloaderException.php¢å«ÇfåÂm8´%src/shared/exceptions/IOException.phpå«Çf
½Ë¸Ë´5src/shared/exceptions/InstallationFailedException.php¢å«Çfuä´.src/shared/exceptions/InvalidHashException.phpå«Çf`o­´-src/shared/exceptions/InvalidXmlException.phpšå«ÇfÄÖ}´5src/shared/exceptions/LinkCreationFailedException.php¢å«ÇfH@!g´,src/shared/exceptions/MigrationException.php™å«Çf š´3src/shared/exceptions/MigrationsFailedException.phpå«Çftshg´3src/shared/exceptions/NoGPGBinaryFoundException.php å«ÇfŸ G?´+src/shared/exceptions/NotFoundException.php˜å«ÇfÿA´)´'src/shared/exceptions/PharException.php”å«Çf
2eh×´0src/shared/exceptions/PharInstallerException.php<68>å«Çf„BÙâ´/src/shared/exceptions/PharRegistryException.phpœå«ÇfðQz-´,src/shared/exceptions/PublicKeyException.php™å«ÇfÖîÐL´*src/shared/exceptions/ReleaseException.php—å«Çf |³<>´*src/shared/exceptions/ResolveException.php—å«Çf —Dbì´.src/shared/exceptions/SourcesListException.phpÇå«Çf)z”/´?src/shared/exceptions/UnsupportedVersionConstraintException.php¬å«Çf’éR´5src/shared/exceptions/VerificationFailedException.php¢å«ÇfVõ…&´ src/shared/executor/Executor.phpå«ÇfZ'&¯/´&src/shared/executor/ExecutorResult.php"å«ÇfËú8û¤ src/shared/hash/sha/Sha1Hash.phpLå«Çfݾ¿|†´"src/shared/hash/sha/Sha256Hash.phpRå«Çfâ$ò¢U´"src/shared/hash/sha/Sha384Hash.phpRå«Çfâ-Gõù´"src/shared/hash/sha/Sha512Hash.phpSå«Çfã§Cc•´src/shared/hash/BaseHash.phpNå«Çf´<00>«qQ´src/shared/hash/Hash.phpå«ÇfB.šð ´6src/shared/http/authentication/BasicAuthentication.phpºå«Çf«B-ý´7src/shared/http/authentication/BearerAuthentication.phpÚå«Çf/±Ý'I´6src/shared/http/authentication/TokenAuthentication.phpØå«Çf/Eû´ src/shared/http/CacheBackend.phpLå«ÇfSº4´src/shared/http/Curl.phpu
å«ÇflBi³´!src/shared/http/HttpException.phpŽå«ÇffdÞ_´'src/shared/http/HttpProgressHandler.phpºå«Çf™ YÃ_´)src/shared/http/HttpResponseException.phpœå«ÇfA´"src/shared/http/Authentication.phpëå«Çfš×瞤src/shared/http/CurlConfig.phpGå«ÇfÌð‹ ¤%src/shared/http/CurlConfigBuilder.phpå«Çf ·‡•½¤src/shared/http/ETag.php2å«ÇfPxp²r¤+src/shared/http/FileStorageCacheBackend.php±å«Çf¿9[i¤(src/shared/http/HttpProgressRenderer.phpÎ
å«Çf®&src/shared/http/HttpProgressUpdate.phpÃå«Çf'mKdĤ'src/shared/http/LocalSslCertificate.phpáå«Çfö£Û¥›¤src/shared/http/RateLimit.php(å«Çf·îè—$¤"src/shared/http/CurlHttpClient.phpçå«Çf{¦÷¤src/shared/http/HttpClient.phpùå«Çf1K Òe¤ src/shared/http/HttpResponse.php¾å«Çf|¼‹¤&src/shared/http/RetryingHttpClient.phpÚå«Çfp+³Š@¤*src/shared/http/RingdownCurlHttpClient.php å«Çfn% ri¤+src/shared/phar/ConfiguredPharException.phpÜå«Çf/4@ý´"src/shared/phar/PharIdentifier.php™å«Çfl€çI´src/shared/phar/PharUrl.phpÃå«Çf]¡\÷´src/shared/phar/Release.phpå«Çf8ÎEüÈ´%src/shared/phar/ReleaseCollection.phpHå«Çf¥cG´!src/shared/phar/InstalledPhar.php?å«Çf)7¤src/shared/phar/PharAlias.phpvå«ÇfmÆy•¤&src/shared/phar/UnsupportedRelease.phpå«ÇfÁ¼- ¤"src/shared/phar/ConfiguredPhar.php3 å«ÇføoØä¤src/shared/phar/Phar.phpåå«Çfá¬=@j¤!src/shared/phar/RequestedPhar.phpÂ
å«Çfè0¤$src/shared/phar/SupportedRelease.phpþå«ÇfOùÛ1¤src/shared/phar/UsedPhar.phpvå«ÇfÊ<éú÷¤*src/shared/repository/SourceRepository.phpÔå«Çf*ŽdÉд*src/shared/repository/GitlabRepository.phpI
å«ÇfÞ 2tœ¤)src/shared/repository/LocalRepository.phpçå«Çf imù¤*src/shared/repository/PharIoRepository.php(
å«Çf{ûÚ¤'src/shared/repository/UrlRepository.phpå«ÇfV$tã¤*src/shared/repository/GithubRepository.php
å«Çf×R'!r¤,src/shared/sources/SourcesListFileLoader.php¡å«Çf9™>K´1src/shared/sources/LocalSourcesListFileLoader.phpCå«Çf¨nÁCÒ¤2src/shared/sources/RemoteSourcesListFileLoader.phpå«Çf¸sSD¤src/shared/sources/Source.php\å«Çf õ[ ¤"src/shared/sources/SourcesList.php<68> å«Çf!dN¿¤+src/shared/version/GitAwarePhiveVersion.php³å«Çf%ƒäBÇ´#src/shared/version/PhiveVersion.phpÇå«Çf€ÁL++´)src/shared/version/StaticPhiveVersion.phpaå«Çf`VÓkØ´src/shared/ComposerAlias.php^å«ÇfI¹<>«Ž´&src/shared/FileDownloaderException.php˜å«Çfü¦f´src/shared/Git.phpVå«ÇfË5<¦Ó´src/shared/JsonData.phpMå«Çfîè®› ´%src/shared/TargetDirectoryLocator.phpþå«ÇfyH>Of´src/shared/Url.phpm
å«ÇfªÐ Äôsrc/shared/PharRegistry.php~&å«Çfc¬” ë¤src/shared/XmlFile.phpm å«Çf8ñºjž¤src/shared/GnuPG.phpXå«Çf0µ¯¤$src/GithubAliasResolverException.php<68>å«ÇfÆðQ¸´src/PhiveContext.php¾å«ÇfÉ4±ìk´src/autoload.php™Så«Çf1 "w|”´src/Factory.php´Få«ÇfÛ
(í¤conf/auth.skeleton.xmldå«ÇfR´&µÙ´ conf/auth.xsd†å«Çf†‡ü:%´conf/pgp-keyservers.phpYå«ÇfJ+<2B>§p´conf/pharBat.template%å«Çf'çÍÌî´conf/phive.skeleton.xmlŒå«ÇfRï<>¼º´­WmoÛF þî_Ávî$e¶åtëœ:sÚ"M<>¤ÁŠ¡)Œ³DY‡HwÚå$hó߇;½X¶d7ÅêOD>$RO¼Êâ B ¦ÐÕ¤x@sºÏPà ½ãž`)êŒ1SçòúOðý&L<>{½ aZÃ[®0 ©îáK¯àÀëS`Å|{;S|Å¡Ÿ1Š<31> Ó,_$<€(q)`>¤Ð¤ò€ÜÒÛš{ðÅÚ_Ÿb®‡'(t®ð\×áÝÂòxÛÐÜ…YÖ<x¨ò,LàŠÝ €HÉb¢lêûšXp#W¨¢DÞŽ™úÿæ¨MŽÚþû¯“—¿½ð—HÄÅr¨0aÄW84Z&9•·¸fqöS Ó<1E>'‡“ñѼĩ8UrÒ°”@rw¹F¥ýç㣣ñK)U(E‰àwRºDº,¼`_Iwݰ~Xýõ¦U·šDKÃ[Á"Óìs·I°elÖ€Ù´« }´L™fŒø'œî!âw¨!
phive.phar+vendor/phar-io/filesystem/src/Directory.phpñ9?øgæï<>æ´4vendor/phar-io/filesystem/src/DirectoryException.phpù9?øg<C3B8>=v”"´+vendor/phar-io/filesystem/src/Exception.phpf9?øg^Å$é´&vendor/phar-io/filesystem/src/File.phpf9?øgüCæ+r´*vendor/phar-io/filesystem/src/Filename.php 9?øg¦VsŠ)´3vendor/phar-io/filesystem/src/FilenameException.phpm9?øgbfo‰ý´2vendor/phar-io/filesystem/src/LastModifiedDate.phpç9?øgTö•…[´(vendor/phar-io/executor/src/Executor.php9?øg£#½j~´1vendor/phar-io/executor/src/ExecutorException.php€9?øgg—</n´.vendor/phar-io/executor/src/ExecutorResult.phpô9?øg/0SH´)vendor/phar-io/gnupg/src/ErrorStrings.phpuI9?øgçÒ»¤&vendor/phar-io/gnupg/src/Exception.phpa9?øgY<19>¤$vendor/phar-io/gnupg/src/Factory.php79?øgêjþh¤"vendor/phar-io/gnupg/src/GnuPG.php=$9?øgó KGE ¤Dvendor/phar-io/version/src/constraints/AbstractVersionConstraint.php¯9?øgnoSMy´Dvendor/phar-io/version/src/constraints/AndVersionConstraintGroup.php×9?øgÒ/j-Ò´?vendor/phar-io/version/src/constraints/AnyVersionConstraint.php@9?øgLÊ[ ´Avendor/phar-io/version/src/constraints/ExactVersionConstraint.phpÈ9?øg†:B Œ´Pvendor/phar-io/version/src/constraints/GreaterThanOrEqualToVersionConstraint.php„9?øg·ÈÉ^¼´Cvendor/phar-io/version/src/constraints/OrVersionConstraintGroup.phpÿ9?øgÕ¿‘ר´Qvendor/phar-io/version/src/constraints/SpecificMajorAndMinorVersionConstraint.php¼9?øgÓLÌK´Ivendor/phar-io/version/src/constraints/SpecificMajorVersionConstraint.phpú9?øg¢ ý´<vendor/phar-io/version/src/constraints/VersionConstraint.phpí9?øg0ø¦õW´3vendor/phar-io/version/src/exceptions/Exception.php¨9?øgóÑG´Jvendor/phar-io/version/src/exceptions/InvalidPreReleaseSuffixException.php<68>9?øgu¹»þü´Avendor/phar-io/version/src/exceptions/InvalidVersionException.php•9?øgs|—Ê´Bvendor/phar-io/version/src/exceptions/NoBuildMetaDataException.php‡9?øgp’°¨—´Evendor/phar-io/version/src/exceptions/NoPreReleaseSuffixException.phpŠ9?øgrXbpÔ´Ovendor/phar-io/version/src/exceptions/UnsupportedVersionConstraintException.phpÓ9?øg%Gd´,vendor/phar-io/version/src/BuildMetaData.phpÏ9?øg|ºâúH´/vendor/phar-io/version/src/PreReleaseSuffix.php^9?øgv.œo ´&vendor/phar-io/version/src/Version.php+9?øg;frë¶´6vendor/phar-io/version/src/VersionConstraintParser.phpÿ9?øg<P6´5vendor/phar-io/version/src/VersionConstraintValue.php&
9?øggP>13´,vendor/phar-io/version/src/VersionNumber.php¡9?øgkJ}Ór´6vendor/phar-io/manifest/src/ManifestDocumentMapper.php€9?øg¤q³»¤.vendor/phar-io/manifest/src/ManifestLoader.php 9?øgq̤2vendor/phar-io/manifest/src/ManifestSerializer.php‡9?øgM÷Û‚¯¤Evendor/phar-io/manifest/src/exceptions/ElementCollectionException.php9?øg0_Uj¤4vendor/phar-io/manifest/src/exceptions/Exception.phpÈ9?øgŽPŒ¤Jvendor/phar-io/manifest/src/exceptions/InvalidApplicationNameException.php19?øgFMüV†¤@vendor/phar-io/manifest/src/exceptions/InvalidEmailException.php9?øg+·ˤ>vendor/phar-io/manifest/src/exceptions/InvalidUrlException.php9?øg/ÙY<0E>¤Dvendor/phar-io/manifest/src/exceptions/ManifestDocumentException.php÷9?øg'à‡ o¤Kvendor/phar-io/manifest/src/exceptions/ManifestDocumentLoadingException.phpû9?øg!˜„Õ£¤Jvendor/phar-io/manifest/src/exceptions/ManifestDocumentMapperException.phpý9?øg0`'€i¤Cvendor/phar-io/manifest/src/exceptions/ManifestElementException.phpö9?øg%#mߤBvendor/phar-io/manifest/src/exceptions/ManifestLoaderException.phpØ9?øgÒ4oô¤Bvendor/phar-io/manifest/src/exceptions/NoEmailAddressException.php9?øg4œq:¤2vendor/phar-io/manifest/src/values/Application.phpø9?øg5fæÒ=¤6vendor/phar-io/manifest/src/values/ApplicationName.phpœ9?øg¥¤-vendor/phar-io/manifest/src/values/Author.php9?øgõ<L¹¤7vendor/phar-io/manifest/src/values/AuthorCollection.php9?øgßã¤?vendor/phar-io/manifest/src/values/AuthorCollectionIterator.php…9?øgè]î=Œ¤7vendor/phar-io/manifest/src/values/BundledComponent.phpH9?øg—µZ ¤Avendor/phar-io/manifest/src/values/BundledComponentCollection.php¢9?øgëÇé–$¤Ivendor/phar-io/manifest/src/values/BundledComponentCollectionIterator.phpý9?øgó:"漤;vendor/phar-io/manifest/src/values/CopyrightInformation.php\9?øgŒ“û¤,vendor/phar-io/manifest/src/values/Email.php<68>9?øgÕS|à¤0vendor/phar-io/manifest/src/values/Extension.php9?øgüZ7'¤.vendor/phar-io/manifest/src/values/Library.phpð9?øg2×çÙ¤.vendor/phar-io/manifest/src/values/License.phpü9?øg<C3B8>Ý<10>/vendor/phar-io/manifest/src/values/Manifest.php-
9?øgÆ÷ág¤>vendor/phar-io/manifest/src/values/PhpExtensionRequirement.phpª9?øgwÛ(¹ì¤<vendor/phar-io/manifest/src/values/PhpVersionRequirement.php$9?øg<C3B8>Á"ë&¤2vendor/phar-io/manifest/src/values/Requirement.php¨9?øg 1šq¤¤<vendor/phar-io/manifest/src/values/RequirementCollection.php\9?øgäX?ñ¤Dvendor/phar-io/manifest/src/values/RequirementCollectionIterator.phpÁ9?øgíü ¤+vendor/phar-io/manifest/src/values/Type.php£9?øgÉ<”2¤*vendor/phar-io/manifest/src/values/Url.php«9?øgÝ#lÍ£¤1vendor/phar-io/manifest/src/xml/AuthorElement.phpÚ9?øgn¸þÞ2¤;vendor/phar-io/manifest/src/xml/AuthorElementCollection.phpS9?øgS(æ7ä¤2vendor/phar-io/manifest/src/xml/BundlesElement.phpz9?øgf‘‰}¤4vendor/phar-io/manifest/src/xml/ComponentElement.php†9?øg`$Sg¤>vendor/phar-io/manifest/src/xml/ComponentElementCollection.php\9?øgT ¤3vendor/phar-io/manifest/src/xml/ContainsElement.php‰9?øg“aÇÉΤ4vendor/phar-io/manifest/src/xml/CopyrightElement.php 9?øg}Ït)T¤5vendor/phar-io/manifest/src/xml/ElementCollection.phpË9?øg±ç ²L¤.vendor/phar-io/manifest/src/xml/ExtElement.php9?øgKÁüãë¤8vendor/phar-io/manifest/src/xml/ExtElementCollection.phpJ9?øgQ¬ï¤4vendor/phar-io/manifest/src/xml/ExtensionElement.phpŠ9?øgaôzõj¤2vendor/phar-io/manifest/src/xml/LicenseElement.php|9?øg\t²TX¤4vendor/phar-io/manifest/src/xml/ManifestDocument.php 9?øg9ÑS¤3vendor/phar-io/manifest/src/xml/ManifestElement.phpn9?øg¹ªpû¤.vendor/phar-io/manifest/src/xml/PhpElement.php9?øg©wO¤3vendor/phar-io/manifest/src/xml/RequiresElement.phpK9?øg^<00>¹Ü—¤)src/commands/composer/ComposerContext.php«9?øg¨x‡•´)src/commands/composer/ComposerCommand.phpé9?øgÍš`^²¤/src/commands/composer/ComposerCommandConfig.php9?øgë Ť)src/commands/composer/ComposerService.php 9?øg,üœ±ý¤'src/commands/default/DefaultCommand.php,9?øgʱé¬e¤-src/commands/default/DefaultCommandConfig.php<68>9?øgt@Õk™¤src/commands/help/help.mdú
9?øg$4w´!src/commands/help/HelpCommand.phpæ9?øgáJ<>Dˆ¤6src/commands/install/InstallCommandConfigException.phpÎ9?øg2µ„=´'src/commands/install/InstallContext.phpN9?øgð|SÁ´-src/commands/install/InstallCommandConfig.php{9?øg<C3B8>¥k¤'src/commands/install/InstallCommand.phpÖ
9?øgˆù;â¤!src/commands/list/ListCommand.phpÇ9?øgD|Óó»¤'src/commands/migrate/MigrateContext.php9?øgPX'¬e´'src/commands/migrate/MigrateCommand.php9?øgéî Î"¤-src/commands/migrate/MigrateCommandConfig.phpt9?øgt†ÎW¤1src/commands/outdated/OutdatedConfigException.phpž9?øgè-4ú´)src/commands/outdated/OutdatedContext.php49?øg§#><3E>´(src/commands/outdated/OutdatedConfig.php99?øgÙ ¼ý ¤)src/commands/outdated/OutdatedCommand.phpQ9?øgPKæä5¤#src/commands/purge/PurgeContext.php¨9?øgf«ûP´#src/commands/purge/PurgeCommand.phps9?øgÐ(Ò¤%src/commands/remove/RemoveContext.php9?øgQ'²Ý´%src/commands/remove/RemoveCommand.php 9?øg0±ª+src/commands/remove/RemoveCommandConfig.php9?øgÖ—•/@¤#src/commands/reset/ResetContext.php¨9?øgëE<C3AB>Å´#src/commands/reset/ResetCommand.php09?øgr#˜\<5C>¤)src/commands/reset/ResetCommandConfig.php9?øgŸI¸óŤ-src/commands/selfupdate/SelfupdateCommand.phpï9?øgûgY¨U¤!src/commands/skel/SkelContext.php29?øgX¢_MÍ´'src/commands/skel/SkelCommandConfig.php9?øg·!ƒE¤!src/commands/skel/SkelCommand.phph 9?øg™VÁü¯¤%src/commands/status/StatusContext.php±9?øgtÀ&Ø´%src/commands/status/StatusCommand.phpô 9?øgðêÃçò¤+src/commands/status/StatusCommandConfig.phpI
9?øg<Uæ°<C3A6>¤Csrc/commands/update-repository-list/UpdateRepositoryListCommand.php¶9?øg8H÷j¤%src/commands/update/UpdateContext.php„9?øgzßfò´%src/commands/update/UpdateCommand.php9?øg»«ökô¤+src/commands/update/UpdateCommandConfig.php 9?øg±@ù$Œ¤'src/commands/version/VersionCommand.php 9?øgO<00> å´src/commands/CommandLocator.phpq
9?øg¤†X)src/services/checksum/ChecksumService.php89?øg 2w¡´+src/services/key/gpg/GnupgKeyDownloader.phpt
9?øgÒóÝ´)src/services/key/gpg/GnupgKeyImporter.phpø9?øg £~´(src/services/key/gpg/PublicKeyReader.phpˆ9?øg5ËâW¤"src/services/key/KeyDownloader.php¨9?øg­}.e´ src/services/key/KeyImporter.php«9?øg÷j´$src/services/key/KeyImportResult.phpa9?øg<C3B8>ÌAGõ¤src/services/key/KeyService.php 9?øg«ƒÂU¤src/services/key/PublicKey.php<68>9?øgr:F?¤&src/services/key/TrustedCollection.phpÏ9?øg”ža~ ¤(src/services/migration/FileMigration.phpî9?øgÿt ;Y´0src/services/migration/HomePhiveXmlMigration.php>9?øgë?ê²´0src/services/migration/InternalFileMigration.phpY9?øgmòæÅ@´$src/services/migration/Migration.phpø9?øgÎX'mY´3src/services/migration/ProjectPhiveXmlMigration.php¢9?øg;´,src/services/migration/UserFileMigration.phpÒ9?øg`ç¦p´0src/services/migration/HomePharsXmlMigration.phpl9?øg·]]&¤+src/services/migration/MigrationFactory.php´9?øg»+src/services/migration/MigrationService.phpü9?øg<00>H4¤$src/services/phar/PharDownloader.phpV9?øgx^éë´#src/services/phar/PharInstaller.phpÏ 9?øg 5ÛJÔ´*src/services/phar/PharInstallerFactory.php†9?øg³²ž ´*src/services/phar/PharInstallerLocator.php-9?øg•ÝV¿´!src/services/phar/PharService.phpõ9?øgÆí´%src/services/phar/ReleaseSelector.phpü 9?øgmÿ´*src/services/phar/UnixoidPharInstaller.php79?øg´n0Þ±´*src/services/phar/WindowsPharInstaller.phpÃ9?øgÉñGŸ´$src/services/phar/InstallService.phpv 9?øg©êд*src/services/phar/CompatibilityService.phpö 9?øgð>­~^¤$src/services/phar/RemovalService.phpu9?øgÔ%¤<src/services/resolver/strategy/AbstractResolvingStrategy.php 9?øg+×–ÿ ´>src/services/resolver/strategy/LocalFirstResolvingStrategy.php]9?øgqM;Bî´?src/services/resolver/strategy/RemoteFirstResolvingStrategy.php^9?øgrÀÁÙ´4src/services/resolver/strategy/ResolvingStrategy.php¾9?øg-W$Ÿ–´7src/services/resolver/AbstractRequestedPharResolver.php09?øg82äQ´+src/services/resolver/DirectUrlResolver.phpÝ9?øg7Ük­´-src/services/resolver/GitlabAliasResolver.phpG9?øg¤èvãµ´,src/services/resolver/LocalAliasResolver.php9?øgïÁ_«Ÿ´-src/services/resolver/PharIoAliasResolver.php” 9?øgIÓD×X´/src/services/resolver/RequestedPharResolver.php49?øgWÅR/´6src/services/resolver/RequestedPharResolverFactory.php49?øg.”?Lî´6src/services/resolver/RequestedPharResolverService.phpW9?øgÞzËÄN´=src/services/resolver/RequestedPharResolverServiceBuilder.phpò9?øg+‡ó&´-src/services/resolver/GithubAliasResolver.phpt 9?øg@ËZt¤6src/services/signature/gpg/GnupgVerificationResult.phpƒ9?øgkL¤5src/services/signature/gpg/GnupgSignatureVerifier.php89?øgÊe '8¤,src/services/signature/SignatureVerifier.phpâ9?øg>PÏú´-src/services/signature/VerificationResult.php49?øgJ·´src/shared/cli/input/Input.php¶9?øg()D÷U´%src/shared/cli/input/ConsoleInput.php<68>9?øgÃK„﨤'src/shared/cli/output/ConsoleOutput.php<68>
9?øgyìT:|´&src/shared/cli/output/ConsoleTable.phpÍ9?øgrd#;´ src/shared/cli/output/Output.phpÚ9?øg^ï÷ùJ´'src/shared/cli/output/OutputFactory.phpµ9?øg[Q¹@´.src/shared/cli/output/ColoredConsoleOutput.php[9?øg;Õb¤'src/shared/cli/output/OutputLocator.phpg9?øg° A®¤src/shared/cli/Command.php“9?øgǯG´*src/shared/cli/CommandLocatorException.phpÁ9?øg&øtä´*src/shared/cli/CommandOptionsException.phpë9?øg<¸Í@´src/shared/cli/Context.phpz9?øgšŒ4nN´#src/shared/cli/ContextException.phpá9?øg/ÖUð´#src/shared/cli/RequestException.php9?øgGMÝꪴ"src/shared/cli/RunnerException.php·9?øgm;g¨´src/shared/cli/error.txtR9?øgÏçý'´!src/shared/cli/CommandLocator.phpæ9?øg7™ýo6¤!src/shared/cli/GeneralContext.phpB 9?øg´˜¤src/shared/cli/Options.php<68>9?øgÕ¯ÍÑ6¤src/shared/cli/Request.php9?øguË7N¤src/shared/cli/Runner.phpV9?øgE src/shared/config/AuthConfig.phpò9?øg,d¥ä´#src/shared/config/AuthXmlConfig.php 9?øgS»à¦´.src/shared/config/AuthXmlConfigFileLocator.phpx9?øgf6®Ã´)src/shared/config/CompositeAuthConfig.phpå9?øgù1zø¢´*src/shared/config/GlobalPhiveXmlConfig.php@9?øg_²fK[´)src/shared/config/LocalPhiveXmlConfig.phpÅ9?øgäºqÎÙ´/src/shared/config/PhiveXmlConfigFileLocator.php)9?øgWQwÅ´+src/shared/config/EnvironmentAuthConfig.phpÀ9?øg¶Voݤ$src/shared/config/PhiveXmlConfig.phpÏ#9?øgh} src/shared/config/Config.phpà9?øgªÛÕ5¤&src/shared/download/FileDownloader.phpj 9?øgFcz€¹¤-src/shared/environment/EnvironmentLocator.php²9?øg…þŸ·´-src/shared/environment/WindowsEnvironment.phpí9?øg<C3B8>“… |´-src/shared/environment/UnixoidEnvironment.php
9?øg°RsˆÁ¤&src/shared/environment/Environment.php=9?øg'f)Ф'src/shared/exceptions/AuthException.php”9?øg Z
´)src/shared/exceptions/ConfigException.php9?øg í.<2E>´-src/shared/exceptions/CurlConfigException.phpš9?øgÓ?c­´'src/shared/exceptions/CurlException.php”9?øg α®ÿ´1src/shared/exceptions/DownloadFailedException.phpž9?øgË«)$´.src/shared/exceptions/EnvironmentException.php9?øg¬‰bb´(src/shared/exceptions/ErrorException.phpš9?øg ¸W´#src/shared/exceptions/Exception.phpŽ9?øg
É<½õ´+src/shared/exceptions/ExecutorException.phpÜ9?øg.»´1src/shared/exceptions/FeatureMissingException.phpË9?øgƒ<11>Ö´2src/shared/exceptions/FileNotWritableException.phpŸ9?øgðg )´&src/shared/exceptions/GitException.php“9?øg
å‚=ˆ´5src/shared/exceptions/GnupgKeyDownloaderException.php¢9?øgåÂm8´%src/shared/exceptions/IOException.php9?øg
½Ë¸Ë´5src/shared/exceptions/InstallationFailedException.php¢9?øguä´.src/shared/exceptions/InvalidHashException.php9?øg`o­´-src/shared/exceptions/InvalidXmlException.phpš9?øgÄÖ}´5src/shared/exceptions/LinkCreationFailedException.php¢9?øgH@!g´,src/shared/exceptions/MigrationException.php™9?øg š´3src/shared/exceptions/MigrationsFailedException.php9?øgtshg´3src/shared/exceptions/NoGPGBinaryFoundException.php 9?øgŸ G?´+src/shared/exceptions/NotFoundException.php˜9?øgÿA´)´'src/shared/exceptions/PharException.php”9?øg
2eh×´0src/shared/exceptions/PharInstallerException.php<68>9?øg„BÙâ´/src/shared/exceptions/PharRegistryException.phpœ9?øgðQz-´,src/shared/exceptions/PublicKeyException.php™9?øgÖîÐL´*src/shared/exceptions/ReleaseException.php—9?øg |³<>´*src/shared/exceptions/ResolveException.php—9?øg —Dbì´.src/shared/exceptions/SourcesListException.phpÇ9?øg)z”/´?src/shared/exceptions/UnsupportedVersionConstraintException.php¬9?øg’éR´5src/shared/exceptions/VerificationFailedException.php¢9?øgVõ…&´ src/shared/executor/Executor.php9?øgZ'&¯/´&src/shared/executor/ExecutorResult.php"9?øgËú8û¤ src/shared/hash/sha/Sha1Hash.phpL9?øgݾ¿|†´"src/shared/hash/sha/Sha256Hash.phpR9?øgâ$ò¢U´"src/shared/hash/sha/Sha384Hash.phpR9?øgâ-Gõù´"src/shared/hash/sha/Sha512Hash.phpS9?øgã§Cc•´src/shared/hash/BaseHash.phpN9?øg´<00>«qQ´src/shared/hash/Hash.php9?øgB.šð ´6src/shared/http/authentication/BasicAuthentication.phpº9?øg«B-ý´7src/shared/http/authentication/BearerAuthentication.phpÚ9?øg/±Ý'I´6src/shared/http/authentication/TokenAuthentication.phpØ9?øg/Eû´ src/shared/http/CacheBackend.phpL9?øgSº4´src/shared/http/Curl.phpu
9?øglBi³´!src/shared/http/HttpException.phpŽ9?øgfdÞ_´'src/shared/http/HttpProgressHandler.phpº9?øg™ YÃ_´)src/shared/http/HttpResponseException.phpœ9?øgA´"src/shared/http/Authentication.phpë9?øgš×瞤src/shared/http/CurlConfig.phpG9?øgÌð‹ ¤%src/shared/http/CurlConfigBuilder.php9?øg ·‡•½¤src/shared/http/ETag.php29?øgPxp²r¤+src/shared/http/FileStorageCacheBackend.php±9?øg¿9[i¤(src/shared/http/HttpProgressRenderer.phpú
9?øgÀ¼F¶¤&src/shared/http/HttpProgressUpdate.phpÃ9?øg'mKdĤ'src/shared/http/LocalSslCertificate.phpá9?øgö£Û¥›¤src/shared/http/RateLimit.php(9?øg·îè—$¤src/shared/http/HttpClient.phpù9?øg1K Òe¤ src/shared/http/HttpResponse.php¾9?øg|¼‹¤&src/shared/http/RetryingHttpClient.phpÚ9?øgp+³Š@¤*src/shared/http/RingdownCurlHttpClient.phpn 9?øg„ ÞëT¤"src/shared/http/CurlHttpClient.php©9?øgC<0E>DU¤+src/shared/phar/ConfiguredPharException.phpÜ9?øg/4@ý´"src/shared/phar/PharIdentifier.php™9?øgl€çI´src/shared/phar/Release.php9?øg8ÎEüÈ´%src/shared/phar/ReleaseCollection.phpH9?øg¥cG´!src/shared/phar/InstalledPhar.php?9?øg)7¤src/shared/phar/PharAlias.phpv9?øgmÆy•¤&src/shared/phar/UnsupportedRelease.php9?øgÁ¼- ¤"src/shared/phar/ConfiguredPhar.php3 9?øgøoØä¤src/shared/phar/Phar.phpå9?øgá¬=@j¤!src/shared/phar/RequestedPhar.phpÂ
9?øgè0¤$src/shared/phar/SupportedRelease.phpþ9?øgOùÛ1¤src/shared/phar/UsedPhar.phpv9?øgÊ<éú÷¤src/shared/phar/PharUrl.phpÑ9?øgbæ,g¤*src/shared/repository/SourceRepository.phpÔ9?øg*ŽdÉд*src/shared/repository/GitlabRepository.phpI
9?øgÞ 2tœ¤)src/shared/repository/LocalRepository.phpç9?øg imù¤*src/shared/repository/PharIoRepository.php(
9?øg{ûÚ¤'src/shared/repository/UrlRepository.php9?øgV$tã¤*src/shared/repository/GithubRepository.php­
9?øgõåÈùÛ¤,src/shared/sources/SourcesListFileLoader.php¡9?øg9™>K´1src/shared/sources/LocalSourcesListFileLoader.phpC9?øg¨nÁCÒ¤2src/shared/sources/RemoteSourcesListFileLoader.php9?øg¸sSD¤src/shared/sources/Source.php\9?øg õ[ ¤"src/shared/sources/SourcesList.php<68> 9?øg!dN¿¤+src/shared/version/GitAwarePhiveVersion.php³9?øg%ƒäBÇ´#src/shared/version/PhiveVersion.phpÇ9?øg€ÁL++´)src/shared/version/StaticPhiveVersion.phpa9?øg`VÓkØ´src/shared/ComposerAlias.php^9?øgI¹<>«Ž´&src/shared/FileDownloaderException.php˜9?øgü¦f´src/shared/Git.phpV9?øgË5<¦Ó´src/shared/JsonData.phpM9?øgîè®› ´%src/shared/TargetDirectoryLocator.phpþ9?øgyH>Of´src/shared/PharRegistry.php~&9?øgc¬” ë¤src/shared/XmlFile.phpm 9?øg8ñºjž¤src/shared/GnuPG.phpX9?øg0µ¯¤src/shared/Url.php/ 9?øg ÿ¾³Ð¤$src/GithubAliasResolverException.php<68>9?øgÆðQ¸´src/PhiveContext.php¾9?øgÉ4±ìk´src/autoload.php™S9?øg1 "w|”´src/Factory.php´F9?øgÛ
(í¤conf/auth.skeleton.xmld9?øgR´&µÙ´ conf/auth.xsd†9?øg†‡ü:%´conf/pharBat.template%9?øg'çÍÌî´conf/phive.skeleton.xmlŒ9?øgRï<>¼º´conf/pgp-keyservers.phpG9?øgAf­WmoÛF þî_Ávî$e¶åtëœ:sÚ"M<>¤ÁŠ¡)Œ³DY‡HwÚå$hó߇;½X¶d7ÅêOD>$RO¼Êâ B ¦ÐÕ¤x@sºÏPà ½ãž`)êŒ1SçòúOðý&L<>{½ aZÃ[®0 ©îáK¯àÀëS`Å|{;S|Å¡Ÿ1Š<31> Ó,_$<€(q)`>¤Ð¤ò€ÜÒÛš{ðÅÚ_Ÿb®‡'(t®ð\×áÝÂòxÛÐÜ…YÖ<x¨ò,LàŠÝ €HÉb¢lêûšXp#W¨¢DÞŽ™úÿæ¨MŽÚþû¯“—¿½ð—HÄÅr¨0aÄW84Z&9•·¸fqöS Ó<1E>'‡“ñѼĩ8UrÒ°”@rw¹F¥ýç㣣ñK)U(E‰àwRºDº,¼`_Iwݰ~Xýõ¦U·šDKÃ[Á"Óìs·I°elÖ€Ù´« }´L™fŒø'œî!âw¨!
>rÊ[ †-ÝçzråÚK^<5E>"ÅÓârεïx0Çw`Z¸oUPù“lx“lùl—¦IÍf Ðu®¯<C2AE><C2AF>1<14>½í@»ŒI6ɨ ñ.KdˆîÀM S(L.ÊÉ6‰×<>1ÓÐ13†'¶QÍW©ìMÄEWš@H1L±<>« S<1E>k `6³Q?ÈŸ·!KX¾R!˜ù<CB9C>zBZ†L)v?×1<C397>È­ŠjÔißWÀDcw<63>%ˆ<] <19>”qQæ®Í{dYh9ö׆3d.¨¯aI×qËÇV¿ö;<3B>îºË´X)¶B¥Y¢!ÏL.Å;é­“ËXø'Š¥m®[fW1¿4“š$`xØN6‡¤ 9ca 5h€39^7ÊB!»i?zèuÑj¡?<3F> œïÀ¨ys«­½ö?…”+<mþæT<t¯¼ãš´ëMa!eÒèL<C3A8>,ˆÑ%•ã ¹U—Ñ#žà¼ÄkÖÛ£^¯)VF¾ja=» 03YíUæbƒ<62>q¸ è§2D˜Áxòâ…7…•äᮽ÷7Kxø—¡È:5õ…ì&nm&÷Iå^ÒÔ5»ÖîuzS¨e]÷ Hl†ºNGÖpo;hp;=ÌOgŠ Š\çT!£ò­(·ÓÓgú)DŒ'ŽœÍ– v¶ƒO§ßY¤NÇŽÁØ1ªð¸‰jñïš¡ÊP¥#?Ãx2™xðÄHªme¿AœÊ°£%Û:¹~¡ 0*îõ™RRÕ\@¿…ÿ}}ûaýúVŸÚ¸Õ¨ýaŸ.1OÂú0i¯¼éÆ¡µ)ßþ *š¤ÃÞž_ž<5F>^½¿ügþáìâÍå«÷—Fá
Ô½ò3}Ú™ÉZí— ÿ•Á¬Ã sº÷¦ð®üÛMEõôqiÔ°{3Y<>eìF¸½X·œâ7åqÛl ÷{º«<C2BA>%&‚Û:åzû+àú£âÄ vlœj‰éùmeô#×µµGš_B»><3E>¬ÀoŒVañõk}H¶7¶5¢(¨ù­·Í£å£–{"y¦Ë<C2A6> œ€k’€­ÕÄ”éo
A—lœ•Ù†W÷ÙZ!¶º×MÙz‰ÖÛw­b%ÿcÃQqqˆŠšàð,¬ê·u8•¸?N4Ëê Ò·ôñ¡÷mÍ= Â0€áý~Å<>:ú±Õâ :ŽÄËAir§4ˆÿ]
@ -938,39 +937,30 @@ b
+-HÞ»‚<15>ri=r?²¸ Ÿ£"xÈ<78>ïÜK©È Š
xY<15>Ë<E2809C>I‚¬øÁ~Þgxö6$<aÊ *Údªþ7ÚÐãÚ -^~h&%Ž×ƒ(R½‡2)ŽqN#T]£z%^ä†öâ¿#€~§WKdØ6 “…LÎz‰BК¢§Tó Ú„©ÑjÇuæòÂ…x×£>”T0á«c½!Y_0<5F>i/>>ýzzš vUAîÞ°ª…Ë~Hÿ9Ì"C?¶Âëø™ ´
6É9L<EFBFBD>3 x=ƒøË~÷Þ0C?Ê´Iãp¦7œ“Ü:/ábã$ila†ÆÓŽpŨQðD}ˆÐ °‡Tu
=³yr÷áL9Û¶6ù§(sÑÆsMY»í¼1Ú>ë9Iå¢ímn@{Ãàä¸]Ù¸<C399>ô†L˜ÆIy¦ú”ÑXpÞ¤3~Âd,­ÊÌAY>¥Hó<E2809A>ø©<>Ç´o©î†k+tïÖ2¶*9sX:<3A>6í^Ù÷Î;#½[´Ï;ÙÑ?àqÒÝáÛ§Öf¯I6Co´©6ÁVœ¾<Â`<60>­·ûí.´'í.lŸÅJ' œ@»×†“r/V<>æhb‡Tn0Ûí§<C3AD>®é¨7«þûÁÖÀ‡Wá»—ÙØ~¢¿ÅVÛnã6}×W̃ I<>gÓl[ÄM6mí¶A}[À ¥QD”&‰!å4{ùŒý<C592>~S¿¤ .¶.vš>U6Dž™sæÂ¡NÒ¹†Ác‰'vnŸ4šøU8õ&{ìÁ}Î d\ pš‘•ÁMÎWxàA‰¸Pú‰øCn!HBxCá\0ù5pÊHâÙ¢y?HqÁ.˜±œI¸Â NM³p¦s<C2A6>J t@`2…DIK|QXE¦&üYØ!+„€dÍîÐ'( —™¢%³\É´@fVK»_¯/.»»t®ÊÀlÎ,<2)7¦ðÈmÖoTA B¢Ò&ä‰'Ù<12>f ÂMÎèZ},32õ¼Â8¤4îîoç7oÞÎo¯¹ºŸY!' 2¡õÖd±\ Í+ݽ=£‰KõW-Í5K§ž—f \Y«oH=s2EB¾Ô—(mwÿŠÉT Ág`²·g+Fp!øÇß « ë¢t[šøŠY„*—§^×ಠч-”â2NfàÐU@> °špÕh‡|¿¶ÓÅBðd““ù¼Ì>‰ ZÁÔêÃ:^÷Œ\q÷gÕÄ›{€R%@
¬v¿nç6 \F\
ÂX)ž àüUyÚÊö²ŒKnrLƒ<4C><U<û³Gâ›Ü¾>ë7/ãƒN™Å Ý1ÕŒŠò?<©jºaåõæþìí埋é[õ(…béÿ„AqÃa»î!´ÉVÐ-<2D>­õí·E|-3Ô®·ÆÆ<C386>ZÅØŸ1sWv]†átã¦*f»Â®ÓTy*Ë»ÉEÃ~ƒ” ´A8íÆT]¼Äq#¡}^˜¾^½#´ƒ³¥ldq©…+z >üýí¯/cóÆ&îgÆß¥ã±ß1x¦ñ:Šºt;œÑ–­ÒûÚÆç9£ '?ÜiW Ö² <07>ö¯½;tÝ·;²hn1A¾r's€ÿÕm·{Èçz¹ƒÞ¼µ{|РÍð©ÇûfªmÒÀ¥…Ö’#(_“¥ Ošk¢7~8Ìbxuxüãë¾á3L&ðþ|Û‰éܹAã&<26>qG!ïÏý݃©Ëzt\S¾û¯”GÇk¾w;øj'k3‡m »rÚ;0™PÌÂ(íq[JG Fª<>åíW~²}3˜ÀÑÁëÖÐt6ëX ¾<1F>«g¸ö<18>ûe¨3Ø'<27>ÝÆYLJøàGÝïªõ]öÕû­T[oÚ0~ϯ8} ˆú: ˜ZišÐhÞ&!ãœk®mŸÀØÔÿ>9$%Ü<C3B3>/ßÍ'|r¹ƒ¥„-Ϥ$ÏxíÐïâ~ÔmGІ—\yÈ”FPœ ›Á$WK¼<4B> D<Z·&µÈZ2†Ïd´0¿<30>ØÃ@<40>ÁѼÞߦxß<78>)Î…g% <a<>_Œ\îÐ:<3A>¤ ­aRó-ùJð«%à!+´ù®ÐZI4A™ÌÒ«`eMœFá
=³yr÷áL9Û¶6ù§(sÑÆsMY»í¼1Ú>ë9Iå¢ímn@{Ãàä¸]Ù¸<C399>ô†L˜ÆIy¦ú”ÑXpÞ¤3~Âd,­ÊÌAY>¥Hó<E2809A>ø©<>Ç´o©î†k+tïÖ2¶*9sX:<3A>6í^Ù÷Î;#½[´Ï;ÙÑ?àqÒÝáÛ§Öf¯I6Co´©6ÁVœ¾<Â`<60>­·ûí.´'í.lŸÅJ' œ@»×†“r/V<>æhb‡Tn0Ûí§<C3AD>®é¨7«þûÁÖÀ‡Wá»—ÙØ~¢¿ÅVÛrÛ6}çWìƒ4$=´å8NÛ±L5±ãÔž4­ÇvžšŽ"—&¦€Y€rÝ$ŸÑÿè7õK:àEâErݧòAg÷œ½<ý^çRL# Œ%žØ¹}ÔhâáÔìy°w97<39>q<EFBFBD>À hFT×9_á<5F>%â\éGâ÷¹… á I„3ÁäoHÖÀ)#‰¯ÍûAгnqÁŒåLÂ%Hpjš…×:ר´@&SH”´Ä…UdjÂwŠÀæY!$kv‡<Ai¸Ì-™åJF 2ƒ°âøPÚýxu~ñÓí…sUfsfá<66>H¹©¸0…ns°.x£
J•6!O<Éh4K®sFWêS™©çÆ!¥±p{w3¿~óv~sõÃåÝ´ÜÈ
™8I<EFBFBD> ¥¨·&‹åi^éîíM\Ú¬¿ji®Y:õ¼D0càÒZ}MêžÐ˜”)ð¥¸Di»û—L¦ >{“½=x½bç‚ú¹°º°.J·¥‰¯˜E©ryêu > }ØB©!.ãd]äý« W<>vˆÁ÷k;],O69™ÏËìSØ L­>¬ãuÏÈwVm@¼ °(UÄ`©Àj÷ëvncÙÀeÄ¥ <<3C>•âé<C3A2>± Î_•§­lÏ Ë¸ä&Ç4ØÉSų?{ n±É]àûá“~ó²1>ê”Y ÚS-Á¨(ÿÓª¦VžAPoîÏîÑ^ü®1±˜¾UR(–Þò?0!Žc8l×Á=„¶ Ù
º%pí»• ¾ý¶ˆ¯d¦zp¿Qázklà—±ùÕ<C3B9>Z)%¿ãÝdáþŒ™Û²ƒ° Û¬‡átˆ¦f{4#]§´òT¶Â&o<>Òk¤¥ Âi7A5!áÀK7ÚÃòÌT÷è<E2809A>ÛΖ²‘Å¥®Abðáï?ÿú26_\¦'îgÆ/ÓñØï<ѤÅM ;ÎhËVéýmãóŒQГî´«á²c<07>ö¯}>tÝ·;{´hn0A¾rS<Àÿ¿ê¶Û=KäS½ÜAoÞÚ=>hÐæ ª¯Í ¸IFXKŽ |M
"”6<i®”ÞQÕÀaËÃãï^}ûMŸa2<61>gÛ&¦s?<07>{˜…p>|8ówb]Ö£ãšòý¥<:^ó½ßÁW;Y9lÝ•ÓÞÀdB1 £´[Æm)-<18>«B7eùyôÍ`G¯Z‡¦³Y<1F>õÇLàû¸z†k<E280A0>ø±_†:ó‡}ÒØmœEp|<18>~Ôý[ß{_½­T[oÚ0~ϯ8} ˆú: ˜ZišÐhÞ&!ãœk®mŸÀØÔÿ>9$%Ü<C3B3>/ßÍ'|r¹ƒ¥„-Ϥ$ÏxíÐïâ~ÔmGІ—\yÈ”FPœ ›Á$WK¼<4B> D<Z·&µÈZ2†Ïd´0¿<30>ØÃ@<40>ÁѼÞߦxß<78>)Î…g% <a<>_Œ\îÐ:<3A>¤ ­aRó-ùJð«%à!+´ù®ÐZI4A™ÌÒ«`eMœFá
Wå{ßžÇß§ã@Uã\0¬„‡Tù<54>¦°Rœ‡ðÞ$¤MëÈÝȈWôNH„I.èÙþ,éGQáƒ/#ƒ2<C692>-LÚ<4C>"©…÷ðÄì&d„Þ'.Œð7è¶Û0Z
„t gŽÔ2 n
Òýh¦ Àð·Cɘ~±+s žP¢Zbz wâ.A{4\á\1×Jnû˜Í¤5ž©<C5BE>Ü
YC¸NI²ã¿:ª-î!W¡¸ª0¬p[î Òð¾†U<E280A0>{˜¦ZÀì¶·®}Ô„ÛêN°&nlö¶ Þ›&7¥…ÍÛñêÈ éVü±mhB.È4²Ÿc7¢j+Ò©úƒ<C3BA>6TzŠö°žÓükFÿ£ªèñn•çM'îZËu÷g OÑð9ÊKî¨nu$+ÊL[Ñ$U´ŽŽáp½æ<7ô¶Ti7™Öþ°v<C2B0>«tá®×ã³³æ®O¸ÿ”¡ü8ý'nßý[ô•“[kÛ@…ßõ+æÁI¸1}<7D>ãÔ­IH ”€óÖ3^<5E>­¥Òî2;²1%ÿ½¬.¾(vCõ¦Õ™9ß™ÑÞ~q¹ƒŒT<C592>ÖJ²sä'Ÿ“q4J#Há5×Vº в€]ÁK®7tA­˜Y·c½Îb•ÀW6ß
4¿‰ÅÃ-²¡é²{¿ÎènsZ¢<17>©"†[ßL]îȺ‚‚Ðd ¬ÖËJ,ûÖðÁ2HN°ªŠÔÞ=¨ ­ÈxmVK\Aè 6š¶uÝóÓìþûü>´ªƒIŽ<>ißxQ[-9HïmÅŠ@Ù¬‹<Š –ä*‚—ùÉþ¬'2Ž¢ÊsÝ}±&Y„<64>{ß·¬…z‡^˜°¬ËJ\d(Ø“HéBëq©½‡g«°˜ûbF,z¥
ÁŸ`”¦0Ý ‡®Ú¬z8v¬7A4È­<C2AD>e<1C>Ê™ÚÔý¡ÒYFÞy=4,µ®ZZH®”Ä-ÂÞsØA ¯Ð&i¹Ã3Óÿt×ÉarŒÛ)&;4µoçy×$<24>­GœÜt€&&©ØôÑ>jÙÇùGçsÛ<73>[»K³O~\U¬¯~<7E>`ŒÒ´é<C2B4>ÂÔ!cyfÚ­àtÅ{ðÿ˜é l¬ÎÞïî1Lº8N»l®ÃGi‡ï¯Õ Ë~ÁoÑ_…Oo1Åïû)Þ!@4´×B(mšªHQ%r©„¼f`GõÚgUùî•—?I<>ß<zþ½÷Æ£/±Š˜“u&QG4±Õ™>G«OÝa1èèá±bÁ<1D>Ñ$EXà®â]h×!>'^VŠŽíâkò„oÎø?”T02ÉÓ¤ÜÝ/ç4îã<C3AE>J#ÊÆã'5”0Ý`«H!:ÊB?‡ ^<>†$[Ã!A+¢qvïžÕŽ-y!°_„TåàûˆŽŒVLëöÝíôúæ×ÃMFµÅ´2еÌY6^4Çšµæòšd 6Ìw•…75I4pW™4 ¿Û<C2BF> ‹¢Âw£ôÈ5MëºQSº<·ÎˆàÞ(ÝrÍŠ¿ z=LV&<26>½flžÅÄ+£„ —…Ãâ¼0Qmس_Š<>œx*´óˆMéØbÑx÷†ÙÌ«<>l» Ôo#¼zöO¸l°ÝmÉ|.ò&?Œ[B;¸Ú÷;<3B>ìÁYò¦ÙLhOÚ¶È·—Ó]–¤íÞ;ÝÏmþ×d‰´Iþ¿€çH÷»Tçhñß!²<±Vì÷ËÜy&Æøx>©<>æ¿ÉØãzßãÍ>_ŠÅXmoÛ8þî_1»ðBRàØé¶Ÿœ:I7ë"Ò^à$ÀiÎ`¨±E”"u$娨ö¿HÉz¡lßõ®ÀùSBÎë3Ãá#¾¿Ì’ b¤œ( µQŒš…Ùf¨'o¢óÞè¤<>0 KƘ†Œ(r w [ã°NâZf[ÅV‰<56><E280B0>FðA „?8_Q ï‰xõ²ûãÅîñ…hÈÌQÁ{½[¸Ê’ eÆÑ
1P)Œb/¹J—?J&AX札¼[iÎ(
<EFBFBD>ÀÄRª”2ŽD#¬¾:½ÛÙõôóýÔšr‰™„x% _Ã+3 ›¼–¹¢TÆ»”G=ARÔ¡w Q3ùÅ!rÞëåÚÆ%¨õ D)²]0aPi¤æ|ßîWÜjoƒÊ\øÂ¸É¸ŒÑ[ebá¬xËéËBÅQxë™ÂÕ"%†&Þ†Îfé¯e$—¯¨¼ £Xê-åtÉ”.£þ“|`)ÎÒ47ä…[`('ZÃu®ø<C2AE>1Ù5g( °4㘢0«õF''pµ&Êé\K±d+‹¼ÝÊ[ƒÐ§nù¼×V°¦î”\)Ôú†ˆ˜£êhfí}ßÄ£â•\q_Läœ><3E>ndhH'.WªŽ¤"oYÊÌ •† <=ûªƒnöuDYþ­˱XP)´Q95¡°¿<06>N·ø{PíïÃÍjвVØùXzÕn/*ëg}{€N/Š2Aõ4ýŸûÒžG+Ý©–ïÀÆU`…Â÷
ÔBÿ®L¢äkÑ|Ó ÅÌJ—£½À&HâÐv‡m‡\ºâ»jÃĵC4vÖæ¨3i'Q ê¤l'o¯´ÓìžÆ®F“gö™Ð†Ša´‰ÓX~fŽ&WâoË1m<31>ç®èŸÐ ²Â•´r6ªð6HçøÏµÙ™ü˜®Ðü¿ õëôB¢Lh-u1;Ž¿B<C2BF>sc]ë˜ã%L'ï…¿°}ñŒ(Âò¦êÓäx;Ÿ»¢ÏÄR†}š }ÜdH ÆÊWQ.)¤ÈÖ{<12> Q˜hìþn”&±]ÆX#RôÜ
ÍM¹ÕÊ•-!¬•.&ðîì¬9KxœÕp~?Ô«€‹¬³˜ [V¾¶f_)S7×À‡¥I ŽŠÊx—pcxós+W\3å¦(œe-bv aI½UJ
ã`à®ð°Pðð ÓMXè=½yŽT¡b¥<>½Eyê'.ÚôׄçøìƹµÜ8…HÃÃdÇ'šƒ„¥XÔ<LÎ&´4ÌÜF·½
G“É‚©!«ÀO­=4lcØiT«2ä­ÍšS…ÁèáßO£ËùîF? ‡'QÄÔ08YÔâÍ<C3A2>|Rð´<0F>ÒÒÓïÏQäpuQ;ûKVÊíxEÍÿºón kÉâ=7¼;ÚL0Ó86§Dᯙ [MÖÒÑhþ…-º`µ­ój7:t¡è^bONbAwØχ i,ñÞßLãä9+~ ·È[Õu<C395>žúeR^i~ÙKý'[Ç`¶<ý,ž~²CÃfc6aÝ[ì~"µ±_(õè­&o¹Ó<C2B9>¼mè¢o%%ü^ókT†-u#qg¹3|ZGßþ
ÍqûNÄ7íÏwüsÔ¯1že?v©TkÀñ»woÇ<6F>"4Øïä¢ü<C2A2>…±9Ú~;i³Cº<43>´c»Å^nEëí¡ûöÜ JÁt.áf$ŽkëºVl:€ÿ–'ú©E©þ)<ö]eFmýÄ|
WŽ— Òb@í¹„ÐN§*rèc(«?UJª…L˜¨<CB9C>Eoûü§êOk2<6B>ëÇùítq»¸ëéüaöqvýáaÁ_0:<3A>ûû[ õa<C3B5>ŽéÈæÏ¡^Qž*ü°#è2(bý„Z“†‘= ¾&öÕD…°Ä£q6,BÙ¥_¿ˆ/âWî5¸‡%ξ"ßBŠDhØÊ\<5C>û”cöÂáœ<14>˜ Ò>,Þ„ˆ! ¬Q±å¶™¹–Žº½+ƒJ@€«?Ì0…p)U±#(ÂRÉ,!ÕãÑȆ5LÈf3Ô8Š%Õ#Jpc¡f˜˜”G.0ÛSdE˜ƒý€¶ŠÛit´Ïæ•î([7ì#!º~~ó‡oߪ׭zsO¿Ÿ<C2BF> àíÙ»gËaóîœ,™Î¥Ý|hÚØ<C39A>óË1šÕWkõOF”ƹ7AÝ?ÿQ]Ê'¶0x»/¨†—Kü·:%úM;îX‡¾Ÿ\µ«VÉ×"ljÞ<E280B0>lÇPSÙæ|µñ1…±<E280A6>¨<EFBFBD>Û Ì1%L0±*þÑhçÏ +Rš4³ÚïŽâVòžSÃ*<2A>Am>Šà=¼=Ô9çÇè±-a•q»|Åè>@ÎKž? RÃå©Ù :¨apÕ8­û¬9¼£nÅ¿÷þ<>ÍKA ÅïûW¼ƒ‡¶”ŠW­Ÿ¥RA¤øq$<24>ÍvÓ™!“m)âÿ.»ZO^<&yù½¼L/³Ï¨ÙRSqöfûÌåüdxV<1D>*Œð쥠À<E28098>LjH ^¶<©Ð+f)ïUÖÞ0pC\kdÜŠï¬V0%<25>|µ:Ô“š/ÆxâŠXpËŠi94®²ÏœràNŠ5\Ц²j-iù1¼M
ÁŸ`”¦0Ý ‡®Ú¬z8v¬7A4È­<C2AD>e<1C>Ê™ÚÔý¡ÒYFÞy=4,µ®ZZH®”Ä-ÂÞsØA ¯Ð&i¹Ã3Óÿt×ÉarŒÛ)&;4µoçy×$<24>­GœÜt€&&©ØôÑ>jÙÇùGçsÛ<73>[»K³O~\U¬¯~<7E>`ŒÒ´é<C2B4>ÂÔ!cyfÚ­àtÅ{ðÿ˜é l¬ÎÞïî1Lº8N»l®ÃGi‡ï¯Õ Ë~ÁoÑ_…Oo1Åïû)Þ!@4´×B(mšªHQ%r©„¼f`GõÚgUùî•—?I<>ß<zþ½÷Æ£/±Š˜“u&QG4±Õ™>G«OÝa1èèá±bÁ<1D>Ñ$EXà®â]h×!>'^VŠŽíâkò„oÎø?”T02ÉÓ¤ÜÝ/ç4îã<C3AE>J#ÊÆã'5”0Ý`«H!:ÊB?‡ ^<>†$[Ã!A+¢qvïžÕŽ-y!°_„TåàûˆŽŒVLëöÝíôúæ×ÃMFµÅ´2еÌY6^4Çšµæòšd 6Ìw•…75I4pW™4 ¿Û<C2BF> ‹¢Âw£ôÈ5MëºQSº<·ÎˆàÞ(ÝrÍŠ¿ z=LV&<26>½flžÅÄ+£„ —…Ãâ¼0Qmس_Š<>œx*´óˆMéØbÑx÷†ÙÌ«<>l» Ôo#¼zöO¸l°ÝmÉ|.ò&?Œ[B;¸Ú÷;<3B>ìÁYò¦ÙLhOÚ¶È·—Ó]–¤íÞ;ÝÏmþ×d‰´Iþ¿€çH÷»Tçhñß!²<±Vì÷ËÜy&Æøx>©<>æ¿ÉØãzßãÍ>_Š<7F>ÍKA ÅïûW¼ƒ‡¶”ŠW­Ÿ¥RA¤øq$<24>ÍvÓ™!“m)âÿ.»ZO^<&yù½¼L/³Ï¨ÙRSqöfûÌåüdxV<1D>*Œð쥠À<E28098>LjH ^¶<©Ð+f)ïUÖÞ0pC\kdÜŠï¬V0%<25>|µ:Ô“š/ÆxâŠXpËŠi94®²ÏœràNŠ5\Ц²j-iù1¼M
óŒ¦ î×½Sq Cb“tC&)Ž‘Sal…wýÞýÝlþð4ïP}0ódØQA-åÛkìÄ<¬ _R«ŽáR}ˆ|\EÚpÉäKOz—^û<>œU•DcmºÁÂ,Ïp4|T<00>ÛU‡¦<E280A1>®» k¶ÁµƸœ?ÓGl´Æ9bÂð´g<rÉ)þÅ3ÕÿÃ|V_µTÑNÛ@|÷W I”•x*1¤  <20>*„€ÇJèr^ǧ:w§»uRÔòïÕ9vâ8<C3A2>TH½·œggfg÷2¼´™EB2Ž:ž<>ü¯|ü¥{<1E>ô"ôðœ)<29>åa…c˜™šÓq„qmì«SÓŒÑ]|sšp• ý“{ …Ó4šÔ¿<C394>ºèã‰&³·T<C2B7>ÃÐ×#Y26§„Ð ¤ÑìÔ¤`ã|%xc8#¤EžC®Ô:W´'(<28>7¬ŒîÃæ$<a®hQÖ}¿»ß?<3F>g±‰òK-J°Pœ<50>CóÞN¤IêO"-fä­<C3A4>„‡L¸;ó£Lä<Šd.¼Ç-³}$oMðò;€“^£¹pzHµuj.˜pè*ø•I^ϣͥy Ÿ1Ûk“P«‹<ÿ3~Û
Äbºý(˜¾«™Úqõ—ªÎ“\I¤…!Z¼¼H£=»Br'˜\¹ê×mnôÕÇe鬴¸Tïãr­¿¬¾v«ôÂ9 Ó\4 ·ƒk<C692>k?å]ÜL­,Õ'®ÃjK¯Ü-A<>xÂÍÛî<C39B>*¤$ï;ݯ˜“7zrÄ…Ó[n‡8;=ÝCzoøÆ:ùwÖ8Žqvzö!ï”ø¶Ââ0Ô}¼ûøÂ`ïÑmÏñ­±¬Ö|6Þ“c„ÕØ˜\½¸-õLø°p{#*9âåεŗ5=Œ8sf±ù¸Ç¿$Ù U<>˜×6Êý_ÛP):užµÙæÒ‡SêBÓb·tçèÞ,y­#Oš¡4ê4<C3AA>ºë-®ZÚÝþÇT:`Woµý&ÞŸÁªhï Ölÿu†Ö-½;—þ3ÃY+|vB[ÿ4oÑ_½•QoÛ6Çßõ)îÁ«¥Ôn¶lI‡8v“ÉZ,À• Y.V´…ÀHgMi$×(òÝʲËYN0ìa|1Dýîîÿ?ž©we^B†)#MU¢¶%ÊáOÎÀ:?³à âœJXR†@%”D((0Ëé#¾± &Ü¢Ü
ºÊØ©w#üÆÿpCÇÛ‡ýó› G=˜ã‘ЬPÀ<50>ÜoÜy‰EÉPƒ@xiÁ• •*„l
þ^P9²b ÒCuM3š"—”/ ±&м%C")n긩ïzÁÜÓ©jc*'
6DBFå®f°¡*¥ÍË¢)BZd{Ëç'k”%If9~ñ¹îÈÀ²*©uñTWÉËÁÑ^)(WË<57>e¥ŒH *±¥|5QªtE®€®K†käJ±ûÍ(}$J«áR<C3A1>ÐÁn¡„!|ª½.†#èºhê%n¸˜Žƒ8‰¼y8ýà%³(üãc·w€¯^'á<6Ø·§X7 Ï5± ›Äñ,‰¼xÞ8ñ¢(ŒLôÊ@#ïîñ«A„3/ºý0Hbÿ½7fÙŸ/ r>Ÿî•µRþòÖã0LÞß“ÈûçÆsƒ¼4<C2BC>܇q„ñÄîMäŸÜ­rWf¹ixïÉØ |oÜ­/«þ=?;ƒÛG"€r¥gÌ<îΚ|<7C>EyÌr’ÖÛÿ&¹Ò™g(ô3Â<>ÇQ.£ŸÃJ•U;¸¨·€²z`4ý>íIRª¨Re ž)¿ÑÛ«ü:ÍÜëÕÑÇþhÿ
†f[Ž ]2 íq„ì4ì<34>½ ýúé´•If/ƒN%XÞy1YA˜s]Û‰P…¾ƒZŸm³^U%øÍŠXlí®®Ùí5ëZÎW¨þo‰+T/*lÆä q¦ïY¾ÎU^d=øo¢•ØOÏÚxýÚ0Ñ6²<1B>þè[£æÉn»©AJTšƒ­Õx_S,kCtŽDÐ%اûyÓšáW¯€J‰ÊÈ××ß/ôOì<>V¨ôƒí|qŽ´¹?ÚªÐçËÂnz5_»«odˆð¯
¥‚%¡ <C2B0>ôw}2”ÃHL žI}¾¦§•ÞèÒ¡šþöÙÎQ럣Ã$œî½1Q‡ÃÏE±<45>Ô Þ“õ7­V[o*7~çWL<57>ˆØ<CB86> Q_ÎC$”Ð&RJ"HÚ‡$BÆ;ËZ5¶<35>í…ƒ"þ{åÝeÙ*Õ/ ã¹}3ßÌúúFE
¤œhôŒÕŒÚ…Ý)4ƒ_ý~ëò¼çð1Ì€"Ú‚ á9b¼hA¢1j§Ù*²àQFZ üƉøµ5pM´ÀÛåá÷E€Ã.ÌqIŒeDÀ=ƨáÚ·*R(D@¥°š-c+µÉþ.5Ø!Œ9šGwÚœQ<06>‰Pê5±LŠ.(ŽÄ ln»Ç‡ñd:Ÿ8W 0 [b `&<26>l™<6C>À:ðFÆš"PY£Q„"<GD?È÷¤"ýV+6NS ã×Ùãd1~z}¼›¾,f“ùÓã_“ÅýÓü¥_кΣš`4Êda,¨Dk²[¬Q¯°ñÆD,´•*cQ•Â,Vh©ÔAåÒ(Í„ Séä'EåÄéÏ"Î÷1gïO±U±í·Z”c`ÆÄ*<2A>[1Ž5¿·V<C2B7>9Ca<43>­Ç5
k  ýl\žŸÃí†èâÍùer¥4ۋЦ‰¸ß*¸ c)B¶ª$âªAšlMY0””“ŠÖt5É7ÀÞ>2/9£Ç.IuL­W•¡èóÎíRËrñ³Ú¸Óvôë ScQUH=Žà+
©k§pì.÷ÍVh½WÍ¡kÞ…É YA-qD̹•ôk†FI7jÇ|5ÚXCPü‰ôoM”BíuVh;ÝÌeâÌÿ2‡Iðÿ'á¼~™EÖê<<3C>¢µÛ bí5ÚH]hÌîtZíH붆ëB¬yo¸B{ŸÉ<¿Ð2}0NfLs'” <09>ÀËÀeŒÌ½ä1| ÚLÉTãKohÐÎ2R?¨£u71í7Y¦ôé ·šY|¡ô²•áu^ôÎÕÇJ·ÇRëþ=3à<33>ß½ìÝ/ÀrÇê]%×j-JÃÐ~f<>Ø{åvÖ|”˜£çl̇…àå
½!3ó˜R4Æó«­’î`Ô¯iíK=Pb]']Rù¢…66hªýDk©<6B>ÅŸá<C5B8><18><EFBFBD>0ŽÁœWrLHö'CVèù~¥§û¦k\Ë ¾
²!Œ“%/²êh¾?Ö¹T, ²ù¬à°‘–[¸…b¯3•°f ìò bMÌíüÁ6ŽT±ºè4Go.ü©y®Ìa¦s„WÙîÿ,Áû…ƒ¶2uÁ[nöQãE©GfÜÆ-|·½S<C2BD>ý£ÞÝMçÅ~÷?ŒF#¿dT<64>Pò2ð²,Y}ªa<C2AA>ôÏyx7<78>óKŽë+¸ci!d"íêó[a<>oÂogæ[q54ÀuçôCª¦^cx3Åk tû%-Æ—,;iÿ5íòfUùÖæ^îÉÝ@½#‰ò÷4®Êü»P~Ü•6z#ù,¤³Õ¸hÒ€oI9Rµ·Ä0ë„^p¦:påþl¾w>N­”|Ã<>Ún å-vàôW÷SÃo$
¡
/䯆øxßúm<>AOA …ïó+Þ<11><>àP”`4!†D½˜ÙÙ®Ó8ÌL¦]<5D>ÿ»ÙUäⱯ¯}ý:½Î>£&<6C>ha§¯zÈ$³ñÙČΠÎñìYÐp ° Û¢H Öžw44è‹”…ß¼bàÎpS"á6ØøNES["Í«c=¬éêOTYQ¶÷ÔRÁTŽÂ<ûL)ꌰ±†KQ W­¦"¿<>w©@=¡iC€ûKïÜ<C3AF>E!plRÙZå/<2F>Y!ì˜öýÜêa±||Zv«z0õV±·šå'jìY=´ƒ—ÔGp©>"<22>L´[laímyHþ#c\°"X¤Øð[[¨îÚËG¹;ô¡kÁæ$ñ6ÚRTÁIü4<00>Û*°ë> ŠÇ´ ã‰ùÏñRf¸œ˜/ó =<3D>KKCA …÷ó+β-Eqkë³T,ˆêR<C3AA>éÜÜNp:3$¹-Eüïr¯Ö]'9ù2¿«±¢¡<C2A2>¼ÐHM8؇<C398>*éÍÕxæ.'¼EV´œ¬¨^ ¥Å:ò<>.Å¢Ô“ð.FaŒÉ„Çäó'‰)æ^2ÝoÏùEC·SlhëÕØg<SG¹ž ÷5V*5Q/„Ï BÉ&¼í¬ˆþ><15>EBÛ¥„ðïÞ«ÊJàÜÙ{ã’§¨‰¼LÇaîeµX¾nýªÌ¢7½¢aýõ¢ëáµt¡4gäK—ýž´ú@XG/«ò>|dæg#iÿIðå vÛÄm—C¼nL8ïFãkèÍÜ·ûµSßOÛ@ ~Ï_áIL$YiÄW
tU•XWQà…"t½8ÍiÉÝÉç´ ‰ÿ}º4ý1¨[ýÙþüÙwrfs )ÊB†ŽII~äg®{u$ †›\9ÈT<C388> XA &ƒq®Ø <46>}&5ÏBA<>4Â÷Bè_HìàD<C3A0>ÆóÙú¿<C3BA>âi &8Ž•Ðp‰œ¸µáÜæ<16>¤ÑLjV±!×¼0œ#dUQ€ÜT÷èBIÔAéÌP)XÝ[ p …Ë:îjØŒ&ŸªnŒsÁ°RåVµ0…¥âØ7ïLEAštÝrhQ¢³B"ŒsAC3­éAå<R;†qïær8ºøùx1¼Œz?<06>Ú™UZzZ M¥ù•Í
Î=õ×fÂùc)Xæ¯Î’Òœ­¬ “;$§Œ^;A á\í¾¥ð‰Q§üY•¶À5¯ÜÃ5«L!ÁïÀV³BÉm½9²Ç<C2B2>D‰aô ¼ZzÞ`ýsàõôÚ@wÓKxàU<:nRÃèõV¨³É±m6<LÂvÝOÓ‡/íÝwœ¶¶ÅZpPãÑE<C391>`“GeÖ/|êvák´C¸¸ï<C2B8> »Íºeô²MJÈéÝ<C3A9>¬<>$q¼ÆpÎ9™¥ƒ[í*k 1¦ÍDú~=H(̓'‰Ö Û%ï‰ÞD{Ý›ãÿþè~qG×ñ£©þ_U§É{e§I]ømW;öÌìÃTê‰<C3AA>Æådž6·/<ìªHAö—„d_ö®aÑŒ)#SÂg·<67>{´Ÿr³fžÊzì;+­wî%øu<>AkA …ïó+ÞÑ6&¡×®›º ) êS!ÌÎj=¢ã™AÒÆ˜Òÿ^Ɖ“KrŸôÞÓês<C3AA>…ä…fjÂÁìXI?}˜wîrá°À¯ÈŠ<13>Õ¡Œ¸üH'âºÔ£ð.faŽ/ _“ÏHL±òiÝŸû<C3BB>®ØRïÕØg|§‰+=Ö5V*5Qáó€P² ÷“ÑgÁoE`0N)!¼¨7:q ¬Îc½7.y‰šÈ+áépÚûq{}³ÙÞ´S§`½áàë“ 8°EX ¯e@e8G¾tÙïI«„»èå¶ü>}¤snÒ—Ñ=‰rÉçÚ9ÇÙHƶõ“ž<ýuP§>qÀ8åЃu;ÕZÄh˜Í?¢/%uîMrGö|¾<>¯Jï°¿§˜y×¹î?}Ao1…ïû+Þ!@4¨×)¥*RUEMnUƒw`­ÛÏP•ÿ^y—%iÓvož÷ü=¿ÙɇXE”l ÷Š5ú]OÓô}x¬lÂÖ:†Mˆ$аÅ}e|] q,B<‰ÝUŠžéc.žñÑ‘ÿÁ¢ ϳMw¾.ùvˆÞPRKŸ¹fÁ$uƒY¬"‡è8A¾„ ^Ånj Î<E28099>Ÿ@+ƶvæ’žÝÎö‰aý6ÈžÔ?DtL‰q°|lî}Y.î¾>ÜeTSL+R)¡´©Íâ4—O¡Ã0¡ì*<2A>
¥‚%¡ <C2B0>ôw}2”ÃHL žI}¾¦§•ÞèÒ¡šþöÙÎQ럣Ã$œî½1Q‡ÃÏE±<45>Ô Þ“õ7­VÝoâ8Ï_1»¢KRA«}¹‡Rh9Ê^+õhíÝC[!“LˆuÆöÚ,ªøßOÎIH'<27>_ZÆóùßL|}## úŒ(tµQÔ7s³•¨ûß½žsyîÀ9¼DTCHÕ ‰2 BxŽè/H4FBn]F\߃¡â¿3ÂÿAe4\Åñvÿ¾<70>.ˆ6”p¸Ç\ë\p+#‰B2´Š@x¾àFÑEl„ÒYÀB<>˜èVQ¹F <jE ¼Äîña4žÌÆÖUR˜ˆ<E280B0> ÑP<>ÆÂ6ÔD`lñZÄÊGðE<C3B0>—|ép²B-‰<>ðõ ÞDzŽk«Éµ<C389>Ñëôq<=½>ÞM^æÓñìéñ¯ñüþiöÒ+iÝMfóá<C3B3>`8ÌdaÌ}[¥Èv¾BµÄÆÑÐÔn|óº,àz¾D3Wè Ô.µT”0•Žù(­8ýY®ó}ÄèûSldlzŽã3¢5L)_bÃG±b÷ÆÈ£È Еd¸Bn4”¤ŸÀåù9Ü®‰*ßœ_&WRÑ51-?÷œª<C593> 2<¤ËCƒD\7H“=Py åÑ]…Z°5Ї·<E280A1>ÌDÆ Fý=€óyÒDûÆ-•UÑ)ç<>%ÚÉSËrñ2lìiYúu©1ô÷`ÔR<>ý}ñ5…ÔµUÈ ¶—»æhÜWÅ <>ñ YB ±˜w•ôkŠZ
;jû|šXñ<(þBÿoE¤Då¶—hÚ<68>ÌeâÌ;™C„$øÿ“°^OfµºH£lm7_Bk…&A³;žV+ÚØ­,ÑÜg2×+µLåÆi¥Óì …BâGàfÅeŒ,¼1< ZTÉtÀ—î@£™f¤~<7E>{ëNbÚk²LéÓl5øÀCáf+Ãm¿¨­ÅÇ»Ç8úÆþ{¦Á=Óž½êÝ+•e<E280A2>QÛZ®u,*ÃÐ|f<>عÕvø¨,™¢1{ÏÙ˜— Á-ºªg±ï£Ö®W´NºÜ¨w µ«Hvàc;i“*-´°)@öc¥„Úƒ?ÅŸ1j ƒ+8ÓrLHö'jMèz^­§»*X•ªáK?¥_*`L„ù!b4£QPs%ÖøÊÉšPF¬LÎz ùTség¹Ôã™H‰ pÜ@F·=°¢!ØRdꘙ øƒ®-ScyÑ.åRŠÞÜÍcK¢>…ù¢(ê½Ê>(Ÿ•ò¾P­ÑÔF9x+Ì>àmQùHµ]ã¥Ç€{¬?cTۻɬ<×ÉÛÂëüg“ápèUŒêƒ”<7Ü,ËFrkXãLä¾ÌàY‰ÃÕÜѸ0RžvõáÙîE(Öë×3ýµ¼oʵçøëì@ýôØo ]Z)'YvÔþ4íŠfÕùÖöß@½=‰ŠG 4îßâcS}1V>IŒä[“ÎVãBH¾%p¤jo‰a2Ö ½àÚT¶áÊþYÿÖþ8º!òµyle6À[îÀñ®o«†!^ ”B•žÝ§†8¼sþÅXíoÛ6ÿî¿â6x<36>8vºö“S'é<1<>ö œ<18>fC<>-¢4©”ccíÿþ€”¬ÊöÖ­ÀôÉæ½ÿîx<òíeš¤#åDa¨<61>bÔÌÍ6E=z<15>w'8<>û„iX0ŽÀ4¤D<19> ¸ûpc™n[&BÁ;%~áD|Fe4¼%JàÕóî?Æ‹Üá3цט¡·z·p•&)Ê”£e"b RÅž3#•. ¾—
L°È8ZZ·ÜœQ<1A>‰…T+b˜=H9<12>°føâän¦ãÉÇ»‰Uå3 1ðB4ÄLç¶0†f06x-3E¨Œw!:¬P§„"Ü&DMå'‡Èy§“ië— Ö2¥Èv΄A¥šó}ÔϸÕ<1E>ÊLøÌ¸I¹ŒÑ[ebî´xË«ç¹6Š£ðÖS…ËùŠšx<04>*&ÌÂ_5ÊH._Py£ØÊ[Êè‚)]xý+1xÏV8]­2Cž¹†r¢5Œ3ů<C385>IÇœ¡0ÀV)Ç
£¡¶úg`prWk¢œÌXŠ[Zä-)UlM B—ºåóNSÀªºUr©Pëk"bŽª%™6龊Å["™â>È8ÿ2¹'mÏÐ<C38F>_.U-NE Þ°3×HbTFðøäZ ÚÑW¥Ù3g´JÇ|N¥ÐFeÔ„ŽÁ~5 <20>lþ»WÒ÷áæÕkhËõ¼/¬jGŠüÙ¯k7ÐéEž&(¿QÝþ¹ÏíY´Ü­¬/Ð2P: |-AÍåOàÊ$J¾äÅ7ÙPL-wAì6A‡¶:l9ôàÒ%ße¢¡Ó6C<36>JÛ‰Z`8WGE9y´BO½zjT<6A>&K-ìS¡ Ãh/§±ü(Í M¦Ä/2ÞæcÚnÏ]Ò? Ae™Knåt”îm<C3AE>Îð<C38E> µÙ©ü˜.ÑüW<C3BC>z…uz¡ Q&´šÚ˜Ç_¡Î¸±¦uÌ𠦌÷Ÿë>ˆxJY<>Ââ¤êÒäx ;»¤OÅB†]šô€ ]ܤH Æ¿ÊQ,)¤ÈÖ{ Q˜hè~×R“؆.c¬Ékn‰æº 5be +¡‹¼9;«÷’gœ_Õj à<ê‡4&ÆV<E280A0>/<2F>ÞWðTÅÕóa©AÒ€#‡¢TÁ%œÁ^}ßÌåÅT¤™É±„.gÛ‰°C=UŠ" †AÏáa.à'á¦5š0—{|õÈB9ezö&å±8o{Ð]žá“kçVsmKä,5 £Ý<V3HX°EõÍätBC2<43>ÌÚå•<1A>FL Y~hͦa Ãv£J]! ×huV3U ~;<3B>.g»ý4ìŸDÝ zPÁàxQGÎWð‡‚Ç}xš~Š"‡«óòØÞØŸ²o7WTó_»ß a-Y¼ç„w[ fjÛæôè;Wša£È2ÍÿRóÎŽFac\°ÒÖxI<78><0E>b(ڇأãèAÐnvÁÓ!E ¼wƒƒ¯¦¶óœ¿„Ã[YuµšúaTi~Ú ùGÇ`º8ý(ž~° BýzaÖaÝìn"µ±7”ªõ<C3B5>· ´;oú„èI ¿Ó|ŒÊ°£®%î4·z<7A>cMê=ãèë_¢9®ß±øJ¢ýñî÷†Zò5ÆÓôÜ.„* èC0|óæõ°„Zû<>|ƒ—ï2“ 06F[oG<­WHÛƒzlµØÃ-/Ý£uSóÐáá@ü#c
㢠…-·R!¡IèÕYKˆ¶§f}ÕWÕŽ²ÉÞàþz(w{ÞµzÁ´ÆˆFÖIWøèJ°üÓI×<6F>¡ð¯ÆÚc7Cûµõó‡Ð¢An<41>6rÔvm-=‡.¶€²ò¥¤*&¹<> u1ß<31>þ<57>'5Áøav3™ßÝÝÌo'“Ù|<™ÝOßOÇïî'ü ƒ¸»»ZmwH•|æ¸ÚYÿêåÐVº]¹¯Pk²Ä0²û—ľû¨<vtªín{™èCÙ¥?‰OâGèïU¸§1Î>#ßÂ
‰Ð°•™weöÈäœäÏ4˜ Ò>vÌ_µˆ! ¬Q±Å¶¹îš½ÍŸ³
@€+ßOqáBªœ"(ÂBÉØZëV?!M_ã T<>Q„š~bV<rŽÙš"KÂD?èí´‘ÜKäïÒÆß¿<C39F>º¶¶ÛG\>t€~‡» |ùR¾ÏUÄ<þ|vÖƒ×gožìžµ;}1«íPÚõ‡ºŽÝ>¿B`‡Ëj8(ÿ¤DiœyäÐ ú·òR<†ÁƒØÝy l^.ðŸbh¥è'í¦ßÊõýãa3k%u•:>ªˆvÕ0^ﯻƒÅvÔÀQƒ3\&˜4šà©6)â†å!<21>jO·á<C2B7>^íWG~*yÂaéH¯R^*ŠŒóc¾Maq3}yë>p½(@xê}ƒH—'f<>h=‡ÁUm·îÓæðŽÚÿÚù?m<>AOA …ïó+Þ<11><>àP”`4!†D½˜ÙÙ®Ó8ÌL¦]<5D>ÿ»ÙUäⱯ¯}ý:½Î>£&<6C>ha§¯zÈ$³ñÙČΠÎñìYÐp ° Û¢H Öžw44è‹”…ß¼bàÎpS"á6ØøNES["Í«c=¬éêOTYQ¶÷ÔRÁTŽÂ<ûL)ꌰ±†KQ W­¦"¿<>w©@=¡iC€ûKïÜ<C3AF>E!plRÙZå/<2F>Y!ì˜öýÜêa±||Zv«z0õV±·šå'jìY=´ƒ—ÔGp©>"<22>L´[laímyHþ#c\°"X¤Øð[[¨îÚËG¹;ô¡kÁæ$ñ6ÚRTÁIü4<00>Û*°ë> ŠÇ´ ã‰ùÏñRf¸œ˜/ó =<3D>KKCA …÷ó+β-Eqkë³T,ˆêR<C3AA>éÜÜNp:3$¹-Eüïr¯Ö]'9ù2¿«±¢¡<C2A2>¼ÐHM8؇<C398>*éÍÕxæ.'¼EV´œ¬¨^ ¥Å:ò<>.Å¢Ô“ð.FaŒÉ„Çäó'‰)æ^2ÝoÏùEC·SlhëÕØg<SG¹ž ÷5V*5Q/„Ï BÉ&¼í¬ˆþ><15>EBÛ¥„ðïÞ«ÊJàÜÙ{ã’§¨‰¼LÇaîeµX¾nýªÌ¢7½¢aýõ¢ëáµt¡4gäK—ýž´ú@XG/«ò>|dæg#iÿIðå vÛÄm—C¼nL8ïFãkèÍÜ·ûu<>AkA …ïó+ÞÑ6&¡×®›º ) êS!ÌÎj=¢ã™AÒÆ˜Òÿ^Ɖ“KrŸôÞÓês<C3AA>…ä…fjÂÁìXI?}˜wîrá°À¯ÈŠ<13>Õ¡Œ¸üH'âºÔ£ð.faŽ/ _“ÏHL±òiÝŸû<C3BB>®ØRïÕØg|§‰+=Ö5V*5Qáó€P² ÷“ÑgÁoE`0N)!¼¨7:q ¬Îc½7.y‰šÈ+áépÚûq{}³ÙÞ´S§`½áàë“ 8°EX ¯e@e8G¾tÙïI«„»èå¶ü>}¤snÒ—Ñ=‰rÉçÚ9ÇÙHƶõ“ž<ýuP§>qÀ8åЃu;ÕZÄh˜Í?¢/%uîMrGö|¾<>¯Jï°¿§˜y×¹î?}Ao1…ïû+Þ!@4¨×)¥*RUEMnUƒw`­ÛÏP•ÿ^y—%iÓvož÷ü=¿ÙɇXE”l ÷Š5ú]OÓô}x¬lÂÖ:†Mˆ$аÅ}e|] q,B<‰ÝUŠžéc.žñÑ‘ÿÁ¢ ϳMw¾.ùvˆÞPRKŸ¹fÁ$uƒY¬"‡è8A¾„ ^Ånj Î<E28099>Ÿ@+ƶvæ’žÝÎö‰aý6ÈžÔ?DtL‰q°|lî}Y.î¾>ÜeTSL+R)¡´©Íâ4—O¡Ã0¡ì*<2A>
O{N ã¾"Y†§f#㢨S~—79&Ô^ÇÍl.B§¥²<C2A5>iG¬ÒÆq{ìÄùn'¼#=<3D>,©õÆQJøÆM£EpŽÛ$»<>Ž÷ì5½`‡oøYÀh0Àì@Ò<>VëÜ)+Qì!û®¤U¦X­ÇE+ÖgÍK=*ËÞ™p¹Ð¿Á!Øò”¿«¼Äw·pµÆôâ7®ç¿ãíõú7°^_ñ„µÞÿ/pÇÚm$c_mö-Þóñ÷öϨçâ…TÁŽÚ0½ç+æ°@tQ¯…ÝÒ¢]iµZ‰ª§•<C2A7>qbÕØgBÕþ{e“„“Ö—$ö{oæ½±2ûê
9J-<ˆ½¼æ“Czø<œf“Q#øY(‚­ÒŠÀ Ï`·ðV¨Þg ëN^í
<EFBFBD>Â7o¾ka~£g™ðç›úû>ÇÇ1¬p#ˆ•0ðKô0£zcî
@ -995,7 +985,10 @@ ma
ÅóìxÒ‡8?Œ·KyÊdWaòÕým:éyû¶Ø·ã¦g-ØIÓ;œï5ÝUؾÓ神_³ÿmQËnÛ0¼ë+æàƒm¸1zõ#qÄh€¢à&—¶0hj-¥Iawe×(òïõ°S ºˆšÎÎŒwUY!'ë ÓP”<50>Õ­ž+’åÇÑ<Ž3Œñ½t½ó O¥;ÒM††q«3»¢T íŸ8>{~«`a8Ðj×ßät;Á†vFÔ™€/Tc!=°ªÊŠbå)aBƒ²ÛÕYº…ëÈа¯½‡½lOlï,!¸°<C2B8>|0êb˜ òd„pttjî}}¼ø¶yHRM0-<2D>âd¹“vå89-¡)¼Äš-ÁƼ<C386>9<E2809A>žJÃ<4A>ñgÓÈ<Ëj¹@kçis¥Csœ¿<C593>½¡ϳÌz#g¡<Q@”B. 3˜ŽÇX #™ Å<>_ÉHTìŽF ƒZLA2ÏZ´Þyg±¯ƒM5`»µ1ˆrmuØÒÓJa<4A>òL.hç
ƒc{¸NR RkWÌ0s¿ü
ßõÚâŠ`´fZ»Pb‰P{ß<>G]¾Æ´a
:½5Ûš»šéö¿/<š_´éï}¸m}ay­' _³¾Ó?ÆŠIk—v;|ún™és£6ͺ®!:¡ÿö÷[_³UPMKA ½Ï¯x­ˆâÕÖ¯–Š‚ˆ´™Îf<C38E>à83&YKÿ»ìjE<6A>/yy™ž×XÑPH^h¤&ìɶ•ôôx<qGûûxˆ¬h9XQ½JûÈïtè00æ¥n…Ÿ£aƸ”L˜%Ÿ_HL1õéb½Ã‡ <0A>`Ek¯Æ>ãš:Lu7¸¨±R©‰z"|nJ6áugEô'ðª,Ú.%„ßôž<C3B4>8PVç¶È«7.ù5WÂ;ÓfÐÝÞÌw«Eo5³è ¯hX¿³¨Á†-ÂúòZ: „Pš]å#—ý+iõ<69>p½Ü”Çá#ç8IÛ/VƒlIµ([->Ôn<C394>8 írè¯Ã3Ùu¶]Ò[GjÔô®£ŽOð#—”h𚸭VÛnÛF}×H”…ÉKd9v\·IP†ÝöÅ1Œ9·^ï²;K©D/ÂqwçrΙ١ÎÞy<>ŒSMŽcñN¥þÉWËìÇÑt09à¿åJ°Pš¡9»Àm®V|:@mqeÊ©eî§#\:Ãø É<³ó3r†/æÝú4ãó÷<'ñŠ >rÉgÒm\yÁ¶Ð A&Cj<43>wj^zë¤Mø³uð9cQj<51>t“=Xk•²†2 ë^È+kšI+ÅëÚï×OW××!TMÌçä±&A¦¤ÉÅÖÊçð<C3A7>¼ØÒ¥ŒÔfåÉÀÐ KA)ã6'÷É~©¥\& ™¡Ì9GÕt[ʹx×l¶î°eÍ—OfEZeíòúï”àÒkÛþNƒT“~Q^ÓüŽ +Ê[WA½š_ØxÁ}ÍaçìŸLNNp±"‡ÏbÍOä)p …S+òŒáŸíÁtÐì—s­Ò-•§§Ôñ®L}¼‰Q;<3B>ÚáÇç],Ì“imðµ?ò’ý×…“ÕÿU²xÎñÞ
:½5Ûš»šéö¿/<š_´éï}¸m}ay­' _³¾Ó?ÆŠIk—v;|ún™és£6ͺ®!:¡ÿö÷[_³½SMoÛ0 ½ûWp@‡Ú^£;.MÛ,HÐ]ôëÒ…"Ó±0[(:i1ô¿<72>u]ÑÃ0l™|$ù¨ãS[HQ0tLJò?Yt½£¨$q1\çÊA¦
åÀ
b0LsµÄN5b`ì©EÎÊú¤¾Bÿ@bÇ4žÍ7ÿ<37>OZp…sáX çX!Á±ÛÎlnÑØ=„NAͤærMÁ!«Š䶺GJ¢vJg†JÁÊèØ…CX*\ÕqãÁpr5ô©êÆ8 +á Un] SX)Î<>}óÎT$¤I7-'<27>%:+$Â446³z"Ý ¨œGjÇ0í_Ÿ<5F>'£ï£ñÅpÒÿ6ìÖάÒÒÓi*Í/lVpî©¿4.JÁ2áp”ælmm˜Ü"9eôæÛ Yçj÷ <>Œ:uàϪ´¨yí§¨Ye
~¶šJîê-<2D>=n"J £/à§¥ Ö?~ž~6ÐÛöø)¶OÈ£Æá®êè0jý9ª¨»M¹ë=<LÂNµïféý§Îþ;N[»Ú-8¨ñè¢n°Í£2둇[/|èõàs´Ç¿î¡qßÝCo—uÇèy—”<E28094>+Òû!kXIâx <0A>áŒs2+7ÚUÖbL<1B>~[H(ÍÃG‰ÖϹ JÞÒ ‰ö24Çÿ¨CûnyK—÷§á+ZDÿRŒßªÎ·Êο~EºwS¨…<03>«÷i6w2<˜ªHAöWŽ„d˜ž÷/aÙ¨•)á£Ûç½NµÙ2Oa£úÞÆE•{~UPMKA ½Ï¯x­ˆâÕÖ¯–Š‚ˆ´™Îf<C38E>à83&YKÿ»ìjE<6A>/yy™ž×XÑPH^h¤&ìɶ•ôôx<qGûûxˆ¬h9XQ½JûÈïtè00æ¥n…Ÿ£aƸ”L˜%Ÿ_HL1õéb½Ã‡ <0A>`Ek¯Æ>ãš:Lu7¸¨±R©‰z"|nJ6áugEô'ðª,Ú.%„ßôž<C3B4>8PVç¶È«7.ù5WÂ;ÓfÐÝÞÌw«Eo5³è ¯hX¿³¨Á†-ÂúòZ: „Pš]å#—ý+iõ<69>p½Ü”Çá#ç8IÛ/VƒlIµ([->Ôn<C394>8 írè¯Ã3Ùu¶]Ò[GjÔô®£ŽOð#—”h𚸭VÛnÛF}×H”…ÉKd9v\·IP†ÝöÅ1Œ9·^ï²;K©D/ÂqwçrΙ١ÎÞy<>ŒSMŽcñN¥þÉWËìÇÑt09à¿åJ°Pš¡9»Àm®V|:@mqeÊ©eî§#\:Ãø É<³ó3r†/æÝú4ãó÷<'ñŠ >rÉgÒm\yÁ¶Ð A&Cj<43>wj^zë¤Mø³uð9cQj<51>t“=Xk•²†2 ë^È+kšI+ÅëÚï×OW××!TMÌçä±&A¦¤ÉÅÖÊçð<C3A7>¼ØÒ¥ŒÔfåÉÀÐ KA)ã6'÷É~©¥\& ™¡Ì9GÕt[ʹx×l¶î°eÍ—OfEZeíòúï”àÒkÛþNƒT“~Q^ÓüŽ +Ê[WA½š_ØxÁ}ÍaçìŸLNNp±"‡ÏbÍOä)p …S+òŒáŸíÁtÐì—s­Ò-•§§Ôñ®L}¼‰Q;<3B>ÚáÇç],Ì“imðµ?ò’ý×…“ÕÿU²xÎñÞ
C·»½Cëveµæ&Ö×ÆÄ ×Ƕñhº5U®ßfYÆçKö—ZÄ£ñ9ɽwÊ,ƒïÆyaSš#> _»ÞÎâH0dã]µ+Wxü¦F»ÏpÕÔ¼Eßv@Ü„xˆ<-Ÿæèq‡E­1RòÌ+ý…!w¯‡@ê6™`Í¥Ùx]A-<2D>uáŽÕ±ÐaR¯Š<>ö0vøùœ+<2B>㾨Z=³®à-æ 2 7WÞ«àiÙÜKvζ¥è
KëQ8ûbÃõm1<6D>"‡™¡LÉ­†ENîw§ÑØ”ZïÛE- ùÒq0ë,öL¶En+@"ì%z|ˆ´®wû„mNnBÍÚÅCÔTpzl\vhwŒK§ƒí±Z næL¼M`ü6ÁÛ¢Ó @ÔkOŸ¦ÕnU@Œzò½.;¶wü`7{¾Iðf”à!:%I£Ñ©¨eô˜À»G¯Â>,¯±ƒûØÀlÚ>³æ—Ðo9­´iøyéa,cŒ”LäQ
¿ß Øþ°TñdR¶­·1º95>§,{©ÖÔŒ”Ea<45>ç¬eq=µÍ¨HÝXdvm´¥Œæšqûñò.Åì+ëk7©_§VŸZ<C5B8>VœM9¤¶Ô
@ -1007,10 +1000,11 @@ N+
Œ¢ã}¹–‚Ÿ|®V¡[rŠÏxšÄ¤ó«ã[Ö×!¸mó{Àác• ÒÃwr÷ûþ*Ѧ^/>;yºÖ1¹†*íAK‰G®Â-(Ü]b㤪گL[d<‡ø]ýñÉ«¹ø\½?fnIV¨Mœ$ÀtŒ÷Ô2à—È þô>qƒô¢ù¦?к`¤?æº0R MÀ4Ñä=«_þmUâè,r8;5-è<>YšÆ¾-ËÒm Óª?—¨ÀÔ¸š±ã¤÷Tãýc ö½øne|•w=âoæ§zÀu1¼A=NUÿƒîIÀ¿ß·j««ä?å®´óäÔåÃif,RiÕ©ËçC^=±ö”7uÔ¡“U»ä\˜¦Ö§®øëŸEÜ€Û³×»üÙ$µ<17>UmoÛ6þ®_q(RH2âxI¢ˆcÏM𢶬ˆ“bÀ6Œt6‰Ñ$Ë£ìCþû@‰²%Û‰£/<12>wϽ=w:ÿÕp9fYLÈY¹·4Hƒã´õ:tàŽ <E2809A>À0ë@Oàs<Š Ô¸ÔfiÅ”;H²>Y…p!™ú­#8gVáè±>å8<„1>2r)øŠZ8§Z02Ü 6½"0•C¦•³â±pÚRpøE[paRH ÙÊ»×–"CEBM´<4D>1'´:#Â\ࢴûíúòêf|å¡ÊÄgŒ TùÂÂqp>yÒ…Í2<>×)÷"ÅfH†eß8³×úï²"ý(*ÈÇ¥2ïÈX¡Ü¤_J?ÿñû•Ä*W<>ƒáw´$´ªßý(Ê$#
×·h4 §íÄÌTæã2¢ÆÝ@¯Ó<C2AF>ÑœYøs&¿øÄ:½Rn¬˜3‡pð³÷£J\<J­£}xÈ´"gÌ%5Bmþ9ðUéà ¸þúi7úÝ-<> å-þ(<28>æ>ˤuÛ<¦gÌ.µ”Xa5b± ­¤ýµò<C2B5>íÒ êÖ$q¯g|ëÎ gö¯ïëàÍ[zóOüøp#®îpŠî“Œ’´;d4vV¨i¦¡¸þ™h<>´q$U8)0Z¥q£óV©[]]¨¥_wy«$Ý!Ëó¤uç_¦qaŒ¶óP¯m­€ôŠŒwÚz/<2F>ÒI3Ú
Å…1Kây¥§/àxï÷V¾ˆSXù,F(ÿÝXLs…ÅM¸½_ñ¶ÅA[ÒàÝÓš]aÕºG­éu:•bFŽ[½ ¸Vs&Eî½_ýÌÐxJ<07>öl7笌õ¶¤gà¯ÛÉ/Έok-ô3¿Ù`JË;6½a3Lb¯§Ý¡p8K~i¢ÿÉTŸƒ5ìfK½RÜ´òŠß™,ð%«¹WˆcH áª)\š­éÊüŸ!&κÇñÙVKC»Êáì¸"Á*ŒFlm¨“Ó{ÁNN?¼îÝÇ÷{áÞ}|ÿZ¸Ó㓽p§Ç'ÏÃ5ø\Ò´4ÚÅÔdµeïÕ+§âß<C3A2>gÀ[ò{µlKÚþyì`ukvŸg÷½•ûÈM5ÒÃÛ7¯cùʦEõ¦˜@ÒÆí­ÕµÁËF;Ê]µ<>°kù½´pV8ûV(A|Ä(W yŠþ<07>RÁnÛ0 ½û+Þ¡;HZìº6i×¢Ã
EÑ,; (™‰…)-ÿ>ÈqS'i<>"ßã#}qª€´ULy6Zžd(?çÙY/Cß*13`"b<E2809A>Ÿá¡2K:ÍÐ n|X³™W\øÄŽpm•ûI,Š]M_Þ§%<25>úÓTE1Êá Õĸˆ/‰«PòÁRÚ;a3­Åsl?{†T„Ym-ôN=¡­Ñä"Á¸™ç…ã]ÁŠ„¥¡UÓ÷õîæö~|›¨cR)ÁJE”&nµ¨ÄÊHI棯Y´/_,ŸeN-(¥ •â;ÿ£ÙÈyi«bÄ„í#<1F>x^Ã,‚¥9‰7\<5C>Ú¯ Îz=\-ÃÕÖþž°M©Ø,•Nj¶çÙ_b£™OºðæÞÁTÚ»(\kñ|Ú"Zžzj<7A>Ƭv:íOO;h~™ôÒ06ú}l3[É6Y´®Rœ¤À°5rPÝuïFOÅMöæ8sGj.¯×<C2AF>ô\Sò½N¸û,>¢m»ñÖÒ«3'·œÉ­Ž±yÑ.4…™!ï8<0E><>§`’šÝ+÷«ñÍ×Þ¨ƒÑœdÂ6/#z®•<C2AE>±âPdÇ>©²Ì÷j)qg¡²µuŒj™Þ™bNR÷jAyÑÿ¿æïıÙã¿õ¿ƒîþ8Gˆb/S¼¹ö·o³É6Ù­VßoÛF ~÷_Á$íK§I³lI1A²í% ­[ÏwÚgOú¿§Ží(+ô^¬;ù}$O>{_•”kt³8•ËBêŠxþc2MOFp¿•Ša©4<C2A9>b¨Ð Ø%Ü•jC§#h,®lU;µ*â<<3C>Kg>h4_È Ã:CY¿?-è<…Ê<><45>òäàŒûƒª¬ÈVš! ) ·FœÊ¼XÇ]ÀŸ­) ^kÈwуµV9&PfiÝEY“B¥ ™`£hÛøýz{uýéá:@5ĤD<C2A4>-2ŠÛXTÀVI ȳõ.'ÈmÑSžŽ ®‰+Ì îJt·ös£Èl4òò2yˆ Ê,Ð9¬g‡Çì3×<C3AE>ceÍç[³A­Šn{ýwNUp´í~g£Q®~QRúìž*ËJ¬«A­+Mk2ÂðÐpØ{÷Ï`zr­ù ·ð¢rjƒB0þ³{1µç>Ó*¦²XäÖ°8ŸK¼Ãhœ.DXã ãä¼Çyk2k ¾#¯Hî©)¨ïé/O,T ⃌Ýþ6y<07>Û•ÕšZ¬½L\‡ s0´}i'³gãPåæi~er¾"¹Ô
9N&çÈâ”Yß<>óÒ:¼„øˆ|ãz‡Ž©ˆ@†1qõ¾\aÉ®Fûk¼ikÞeßu@ÜB<F«EÈ9zÚcÑh 9JHæ•þ<31>lj4m2…-+MFt je¬ 3Ö`AŸ“*ȈZ*r؃±ÛÀOJª ¡jõ…t b!#@è2%] «v.É9kÈzÖ5¬¬@åìÚ† ]1_ ‡;COG"ìÆU‰îw§¡+°ñZÚ<>Y­ ŠwÌz“ç"w@fŽžšÂ6!=Ǿl £ÌÙ-“[vk´Åbá<62>ŽžŽB…¥·—G R˜¼Mámóù¢Ó@(
w@·íœ»v×À$^WžGö8µþº;ÊñM
o£Sä<J!:eµŠžRç)y5ácõi {¿Lé?lû·°ÀDëÐ8%np×¹™0DÐÔ&<26>£‰<Óû¨Àó‡<C3B3>˜Ê° ÉÉ.Cnƒ¥î/œÉ9E<Hµ¡fØW•uBEw'ÅÍõ“îf>…è“…¾G0Ów7—÷Qò ¯<C2A0>İN<C2B0>><3E> <20>8»r¤<72> ¨¬„yG­ë0½ž© ŠßO®‡oŠÕ×è;Êó­ä¦Óð ¾ñ8´OóQãÐÔP"—Ôތ͟¥‰áÝä%Ìÿã—NÊ!ݽAÙãâH¼3Ïtúïð×Ñ¿M<C2BF>QKBA…ß÷WœGIzM+K” Áƒwç¶Cëî²;Wè¿Ç½eô83ß™3gf÷Ùg8¶<38>
EÑ,; (™‰…)-ÿ>ÈqS'i<>"ßã#}qª€´ULy6Zžd(?çÙY/Cß*13`"b<E2809A>Ÿá¡2K:ÍÐ n|X³™W\øÄŽpm•ûI,Š]M_Þ§%<25>úÓTE1Êá Õĸˆ/‰«PòÁRÚ;a3­Åsl?{†T„Ym-ôN=¡­Ñä"Á¸™ç…ã]ÁŠ„¥¡UÓ÷õîæö~|›¨cR)ÁJE”&nµ¨ÄÊHI棯Y´/_,ŸeN-(¥ •â;ÿ£ÙÈyi«bÄ„í#<1F>x^Ã,‚¥9‰7\<5C>Ú¯ Îz=\-ÃÕÖþž°M©Ø,•Nj¶çÙ_b£™OºðæÞÁTÚ»(\kñ|Ú"Zžzj<7A>Ƭv:íOO;h~™ôÒ06ú}l3[É6Y´®Rœ¤À°5rPÝuïFOÅMöæ8sGj.¯×<C2AF>ô\Sò½N¸û,>¢m»ñÖÒ«3'·œÉ­Ž±yÑ.4…™!ï8<0E><>§`’šÝ+÷«ñÍ×Þ¨ƒÑœdÂ6/#z®•<C2AE>±âPdÇ>©²Ì÷j)qg¡²µuŒj™Þ™bNR÷jAyÑÿ¿æïıÙã¿õ¿ƒîþ8Gˆb/S¼¹ö·o³É6Ù­Vßoã6 ~Ï_Áìw/MÓk¯ëÖC´Û^zEÁÈL¬<4C>"y"•Ìîd;?ëî0ìôK&)~ßG2>ÿP%ä¤ zJY¼Vò"UI<ù~0î<30>Nzp¿ša® <0A>f(Ñ ¸9L ½¢ÓÔ×®¬¼^©À•· ÚÏä…á½¥ËÙfšÓE<06>4C<16>n)<29>‡sÞ\EI®4 mÊYñzÄyn/üÑy<C391>`Œµ½=Z­È2<C388>¶sç—(ÚÙ JCÈ+MëÚï—»ëûǪ&
¬‘!×ÜÜE9¬µ <»à<15>ò¨gqI\¢"˜èïܧš8æeU¼´}Aï±s˜±øæ°uÿ<75><kg?ÝÙ<1A>·Û¿•Ñ¥Ó¶ý÷zÊ 3ü¤¥³*kq¾½, -É
Ãc<EFBFBD>aïÝß=€ÑÉ \®ÐÃÏìì(±Å¥×+‚þíq¯93£ÕÊËrÅ%é6Fí4h¯ˆ«y^lbÁ¤1×_º#/H¨Ž?Vôg Ê#éÁú~;8ƒÖíÚCM¬½L|&`iýÚ6ŒwÆQåúirtËðbAre4r:^ ?Š×v}·Îsç UéøÚuŠž)O }²â«}ºâ­Fû«¿j4o³o+ mB<%˜sò¼‡¢æJLæ<4C>ú>m<1E>©ËdkÖ†¬˜
ôÂ:{¬ŽœtNVô\“爬[G|RPè©+ªÑŸÉT fhýLG_<47>à¢éKòÞYr<59>M 'Pz·t±AÅA+æ«Èqfh舄ƒ]¿,Ðÿæ ´Û`Ì¡}Ÿõ¢OÑlcq`²¹U™I8y®…­7]|6oš¨ÍóS¼IžÇo˜ÞÇBÜÙ6å—žCÚL—tç˜Áð}ï0™L 9<>¸“®¬Xi
lÚìÒmÂìÇ}J®T,3À²4ZÕóvä”<C3A4> Y<á²®Äκ5Ý@8Ƶ¦<>ßeðn:EVIÉ)ëEòœ<C3B2>ø@ƒ7Ñ+Lkøÿp_ãùtMkå˜hkºÀnj¬ƒ( Ô©ÀÚD 0}8Iún+ ¶,h¹y„ÔY…Y8¼À<O;ª±ÊÒy¡¼—i=³í8Ê ¹w<C2B9>»µ5éíÕC2x³«ÞêÖnžZ~jBZr¶*f \09”Nâ(Bcª8XSÞÁÔ<C381>øßŽ®Ç¯µÑèÒóµäF£øypf<>;âX>õÿ-€¶‚¹ fh×ßUÚÃÙðu˜ÿ†/;l°C¸{<7B>²‡Å“owp6Ÿ_zÿM<>QKBA…ß÷WœGIzM+K” Áƒwç¶Cëî²;Wè¿Ç½eô83ß™3gf÷Ùg8¶<38>
ª±ú¦çÌõöz85“Á/^* ©ÈT©ÁÖË‘¯ zbò¹È»W ì%2Å.Z1£y¾¿ÔWŽïÆØñžª
E<q˳zi̳ϜràE›¢Ù·šJý5\¥õŒ¦ öϽ£ƒXŽ•!±Iå@*)Ž‘Se…O½n³^,ŸwËnUL=)NTá¤þx±ÃIÔC»ð5µÅ2lr—ÈéÀ5“el=•uzí?25F¢riºÁ®—Õ<E28094>T]IàM"ÇŸ´Ñv'"$rƒáÍÍÔ|™omPÁjA ½ïWè°×8^z<><7A>ÔIHhÀ”€{è¡`ƳڎèìÌ imLÉ¿—Ùf·µN3zOïéiõ9¹5Zo§¢LVwzJ(·ŸÊeQÍ
˜Á7G yH†b¯Ž¸( g<Ætbú馶„{Þ„_È*°2þ‹ïæ°Å½%à vȰ¡±N.aL3L¨ÁÆ LûN#Ë»ásdP‡ÐtÞƒÝ3Û“Å šÈ­QŠaÉ£ᱟۼ<>}Ý>e©>˜:£p45É_/¬áHê@sx‰[ë!rUÓ¢$c^<5E>á—ø£¿È²(:[Ïäq{ŶæeQXoD`­ñÛ^X6$š hjd 6yl1¨ÀeÂï šÍ`}0 ƒv^+‰é`áªùgÚ÷»½' Ml> ìv6Qî¬NG<4E>q¨|·Éu•Ïp}7@p{®<> o—|4õ´¼9<C2BC>q¦Ê¨x<'LG<W¿·>¯÷¸°Öü?ÂÄ©&¹©ªä /(VŒ)
@ -1043,8 +1037,7 @@ I
Ħz@+)H;©sÃsôÒè.XEèÕ¾oÃσÑdRUÄ|<7C>–è “n]2XJ_€ä<>)Y“5”O"<22>srÁ]<5D><4?ª‰ô¢¨t©<>Éí(ý4¼ŽîÓËI:¹G×½6`0ߎÓÑíh°å¥¡k@f\¥´JéQ:ïZaz´ÊdÔZ•.­öµ9£ÓŒÄó UD¡ó)1þ{4<>»Ù T2»äY9'í<07>lØÑ"¡Ð9¸qFA<7F>ð;8étàb<C3A0> a¾z&zCÆe/ÚGV<ž-²£l­ÞÐ<C39E> ‹Œó&}ÈWG6_°YºW;¯qu¹rª¤ØÎ!M+Ÿ>¹“šVxƒGÞž3.¡_Ù„Ö݆Ïþ®UŽ.x.© ïOßu_öJRÓ <0C>Ì!n©'pÐï·]´ÛZx*Ú iù*óvÞ rœtÛâÇI²eö´ßÙA㻸¦œüGG×rAºâÓè˜r <72>‡*+HíM0> OÙ‰+­5ŽêZ™éh¯Åý­‰v˜´Ÿ‘ã2N>4­lé0ùõŽîÿJtW• ¹Öž~-Õ m=wø\>R‡9ã,Œï¯¶õ¼º&UCãæp4{'„Ì¥¨oÉ7ôA—J%`jŒÚõzŽt¿Ýð&ž&Äõíu_)˜:8| UÛ*•¡Ú·_<1C>ÝuÏ̵3Ê•£Þ^ôiïoC!¼¿‡¬?_´õî0*ìͺV8¿<38>ZOÑuR[oÚ0~ϯ8“* (Ýë(F©V©Z+@Ú¥é<C2A5>qNˆUc[¶C+ýí“CHsióäŸïvŽ/¯T¢ BʉFßXͨ]Ú½B3øô½^Ûƒ6,f f<1C>PD[<5B>1<$lçd©öš­ > `¬ÂWNÄ3jkàh<E28099>£Õéÿ<Âaæ¸"Æ2"নáÒœ
#•(”Š£k"" RXÍV©•Úä7RƒMâ”s …ºë挢0LÄRoˆeRt@q$aËp—áîn'Óïó©£ÊÙ„XØ3G-Œ`ÇlÖ…72Õ<14>Êè¹ç ²A£ExHˆ¾•a6¾ç¥¦(Ý0Žó½±¸ ¯™Fj¥Þ÷Ë &œpÞ+çÔô=<3D>rb ,ˆ^£-Pw+5üózí6Œ¶DÃDŠ˜­<CB9C>WVšm‰E8£Y¹ïU3±ŸþHU®ëàÜ_Sг7ëÙMºâŒBœ
êʰ\R)ŒÕ)µ~®œûëÔÕ,t
ÑJ<EFBFBD><EFBFBD>À}gn9ÝáíT„Á[þZc•Þ5Ö3× Ù‚¹וÅ˜ŽØ6Œl¢å΀[êDn6DD9bú—bvj´fêõëÞ»ã\£­= ?øÅOi:,¿‘£;Lˆ9žý͈ZAy¦YzElâÒ6Ñk´ut¾÷Ь#x¼xÁ`×·³édq?ûµœOƳñâ~// 4®—biâ·^Ãñã¸ûûéõéñO/ Ãð)xe­ÎÑJC¸¨tŸFjwoýJó¡ê1ÇUÞOí‡ÔÏL¬K³íiÂxÔ`-1]}OÙ°Ûª©š©3¼·ïw]|˜i!%7 ôÁ;xÿ<01>V[o"7~Ÿ_q*¡Î€hhU©j!,ÙF‰ˆµ4$U<1B>Œç<C592>±ÖØ^ûUùï•çÆ0l.-/Ìø|þÎÕŸç|frrÉ,&ެà”ÒÞ þПD£A¸Ï…ƒµ<C692>Â<>a@¯a-žEP .µÙ[ñ”­BøU2õ -98gVáŪ~?ËðøS0G<30>Î]½parƒÚH @`*®Y±ò¤­«^k ”#¬½”Àï-„Zk»a$´‚‘ÈÂVà®Øw{syõÛò*P‰QÎvÌA&\é 3Ø Ê<>BòN{˸Îê”Gbt†q„EÎì<C38E>þ»¨È$м óEúÇÃÕÝŸéÝõå<C3B5>¿üüÓ¤0®½â!,`Ö²}ú ÷)~Ž\Ǽbƒ—Î2×^Qg-'2éÊ ™¥Ÿ=Ú}Çl˜u˜z+;ë!W£»~Ù¯.z‡¶4ܨ-“"ûhŸü]}áh°´V%¹—{G¸)Ëd".™sð`%üŒ¸Ø2[„£žBqò±bˡ筘DïBæÚQåä=pÃ(¯ Æ¯¤ààˆ‘à‡¬…{°2©¶÷ÊÿþVZ×Á‡ŸEò¶®[RÁ†<10>¸ßL§°fÒá¤Øðü†Ã9ù<E28098>^űÛ0 ®ô=<3D>Náû¯ùm¦i1«Ösj<z+ú-G=®7F+Tä`
½p"¾ûPŒÔÃÝmR 'piFå¼Å"—¤µÿ¯Øñ7?Âlq|ºÑ[Q¾O«Æwìuƒ½ÍÖãÇxhqE×=mIŒñ°ÍÓ‡Ù1my„1Ä£ø<C2A3>:^õKúãzàNšUEÅ\ }•ó{“±)Õ TOHóªrï`;œ£×)ŒòwЕçìuªZ]ý|J¨p×X“Z“ÊMPÿõ²]_0Ë6.)f"Ax ‰ \·¼Š5$…Ü&5¤<QíÓÑŠŽK­°Lú0ˆÏ‡th`ÚÈDÓ¸!ij¶NÀ âoã0s³¸§N B˜-8+¹ÏNî<4E>:î!Äñ0°O/¥7ª…Ÿ=“.)*ÓóV¾(D­xBöt.GƒA¹oEhõìôŒÕ¤¹•ùXªÑ´u¥ÞÒÃV¬Ó¸Ã<C2B8>ÕBU.2îvr«wE}_ºÜøw%÷0¿¿_,¡æ„ð½Î£-aÖÖ´ç£Âvsi$´­»ãR§^”ßæ*¯…÷(ç#l=Oÿ'ÏûC[aw·À™Rš`…e<04>4OfáGÝþçè_ÕZ_o9÷§à <Øuû°8 ©Ý¤iŠ]ì5W\¶{¤A ÏÐáÆÒ¬¤IjÜö»iFc»múpFÑÚEù#%öÕë"+ Å$'MÔ½Ú(ç/ã³Ñìd'ð{F%¬hŽ@%D(à+ø<>Ñ|>CqÉ­ ëLA”Äp!œ°ÿ P^Áð|Yÿ~žâb7¸$RQÂà,QÀ+YœY<>¼ÈQa)$œ)A—¥âBV¾ãT†°*ófwM<77>Ó™D lÅņ(ÊÙŠ‰Dx øhÖýý×Ë«ë+ÍÊ(¦2¢àHH©´{a
ÑJ<EFBFBD><EFBFBD>À}gn9ÝáíT„Á[þZc•Þ5Ö3× Ù‚¹וÅ˜ŽØ6Œl¢å΀[êDn6DD9bú—bvj´fêõëÞ»ã\£­= ?øÅOi:,¿‘£;Lˆ9žý͈ZAy¦YzElâÒ6Ñk´ut¾÷Ь#x¼xÁ`×·³édq?ûµœOƳñâ~// 4®—biâ·^Ãñã¸ûûéõéñO/ Ãð)xe­ÎÑJC¸¨tŸFjwoýJó¡ê1ÇUÞOí‡ÔÏL¬K³íiÂxÔ`-1]}OÙ°Ûª©š©3¼·ïw]|˜i!%7 ôÁ;xÿÕZ_o9÷§à <Øuû°8 ©Ý¤iŠ]ì5W\¶{¤A ÏÐáÆÒ¬¤IjÜö»iFc»múpFÑÚEù#%öÕë"+ Å$'MÔ½Ú(ç/ã³Ñìd'ð{F%¬hŽ@%D(à+ø<>Ñ|>CqÉ­ ëLA”Äp!œ°ÿ P^Áð|Yÿ~žâb7¸$RQÂà,QÀ+YœY<>¼ÈQa)$œ)A—¥âBV¾ãT†°*ófwM<77>Ó™D lÅņ(ÊÙŠ‰Dx øhÖýý×Ë«ë+ÍÊ(¦2¢àHH©´{a
<EFBFBD>Te ´ò—"AHxZ«<1²AY<41>áCFįü“±ÈÙhTJ-KôÎ@„ Ûû’Ñ?K<ó§lÃÓΘæ~<7E>ê^ëŒLÉÎ<e÷†cgX2µ²£oÿñþ*Ç 2Õü¾æiµ{%ë;šãÍV*Ü|zK&Š‹í^‚«Ï z¿!Jýuל6™7ÿ
I9«ÿ=<1B>œHi¦ÿ‰k}[øï`vrçD@#Ž>=Sú@ÂQáhã/û÷&×¥K+µ-—9MZ»Þës<C3AB>J”‰ŠjGŸí—‰#‰¿u\‰¬?GÚ¦ » Ì›ÕÕ††Ä[<] “¥À«ÏT*½øÛÏ?Çg]vÞ
͵£º&ýV‰¤©¶n¤ÿ²ëâScoW襢ÌÄN-·ÝX4ËíÊ3_ ífõÀÜW}ºH…•gFcM?1˜.$ª UEa4ÖN3žØùéb<C3A9>êšl0ŠYú`ÝÊ[]¹Z»¿n” l}Óœ'Æ0škÇNÓ!V‘™±Í>£hÂñn2òò"³ÓÓ ¢V½´’¿žŒã}{wÕÐ ?žÀXfäåÀ9<C380>¢@^f4O£†Oìx.]A-VFä ]3¢J<C2A2>ï([£0<C2A3>Ån0þ²&;È" µ+cŸOW»U+2vX˜ÀÛÑYóe÷é¤i­´Í5µ®Èµ¯@U
@ -1064,7 +1057,10 @@ H
ÕÿΘÁ<CB9C>¨+H ×8DVÿV|-MQšÍ¨'ºÐkõŸÁÿµËnÛ0E÷úŠYˆ<6C>nëGÝ&Ž M ¸Ý0hj,Ib8!4ù÷zÙqƒvÓp§á<C2A7>¹ç5ùd ÊT†ŽIIÞraÑM?tÇÁ¨@~$ÊÁ^¥Ê<>Ä`ö°JTŽÃ­±©8ae>“Fø
}@bAç»æ{á¬kÜ ÇJhxÀ &®)ÌmbÑØ½„Ž@ͤvrµá½!àaŸ¥)ÈÖÝ«S%Q;¥÷†Ž‚•Ñ}°)
<EFBFBD>+<•}_oOë…UãD0œ„ƒH¹Ê #8)N€}xg2ÒDMäQ Å<11>a•z4r#ã ÈœçÒÒ;ƒÍu>.‹µî^¥¸.ãqs§%*ÆA Sá,u¶Z¯`ÔëÁ<Xg6ö¦¾lIå:eu¼Ö¶#ÿ<>ˆwŠêíR%Ï Û­4Ú1eÃÚ¯2è_ŒlftkB:~CƒYÕ0m¹®´$þú¥ Puô`NÈiD¢xÞÔa}5z]­!.ÿ^Cç€Å%_õáÍòéçjùðýÛbzÃ+¨ÁL¸v»õü©A.#fµ]éó*Â5× ÿ¶`ɤû±
öžˆ<EFBFBD>scù¿6<EFBFBD>#©}Ñ:¢s"Æ>´g„ïú5ÅÙþÂ÷_IËŒÏï_£ÆÈHd(¼Œò&ÎYÙ˜¿¿E<>MOB1E÷ýw „@\ƒ
öžˆ<EFBFBD>scù¿6<EFBFBD>#©}Ñ:¢s"Æ>´g„ïú5ÅÙþÂ÷_IËŒÏï_£ÆÈHd(¼Œò&ÎYÙ˜¿¿<01>Vmo"7þί˜“PwA4´:©jC8r<38>)j)I>T×ïÀZglÇá*ÿ½ò¾À²H®ùÖóø™™Ç3_ŒLj A.™ÅØ‘œf´5è†?w­]xH…ƒ…<C692>Â<>a@/`Š5žµ C\i³µb™ļŸ­Bø]2õ-9¸`Váå¼ü>KðSîqÎ ¦`Œ-\¸ráÒ¤µ‘€ÀT\+²bîI[W8¼Ñ(EXx)<29>ï¼´•Cj¡íŠÐªF"sk<>lßÝíÕõ÷×<C3B7>*KŒRF°aár_˜ÀFP
wÚ[ŽÀuR¦Üo)¶BgG˜¤ÌÞê2E­wwz)øõ7Ž&ødk\+G0Of=^OÿžMo®>þöë/¹qáP`Ö²íì+ngøM8r5óœ9 žkË\{Eµµ”ÈÌæ^ÈdöìÑnkfìÙ·²¶ò7ºî×}u´Ô´¹áV­Ég»ô+TTË¿<C38B>éFH¼ß:ÂUö3O¦Å%s­„[ýn.×Ìfá¨e<,+ÖŒÚÞŠAë]ÈT;*œ¼n¥´\ÐöboÕž´->{a1#KкäçRppÄHð½tÂ=Z—ÄùÿÎ9̵.ÉÛRü¸€õ :ï÷£|aÁ¤ÃA¶áå ‡c"ó<>^Å¡ÛPQ.÷=á§×üîÎfYÁ[ÏiçÑ[ÑkÊ CP^ÊÞ!a_ž:•øÚ\¯ŒV¨(ØÚ¡Cü”•óãô.N:ƒ=87£rÞb&A\Ùÿ%r<ÅFO0A57z+òïaQt5{Y^Á^å ëÑSÊ« «wzcÔ«òt`tHAžà¢~Ô ¯Z©Õ¨©n³rO+éûìãÎyÙD<C399>Ú)|1WBOrîao2îŽàÕi\œÈ;ØöwÃiÊ £ôtùÝq*enz¨u|´ý>àÊÐ6~ýÔNë¹DzÅMÞ]ÇbÿžX"•Ww .nvÖ¸^¤£Ñnš•¶<E280A2>Ô<EFBFBD>Ó †É<a­\\Ü
G„rQ D, Άc\Bò««zŸTæR+Ì%Ù7Î˾…îîã]Iö U/dAôCºts ¦J³Bg9÷Ycj—q÷ Šz<C5A0>µ×|B¼¡>{&]œ)ÓöV-¹J<A¤€mv\¿ÛÍ÷uá2 ­ìж±š4ײ0Ö}4Õ¸ÜÒ9‡µIíàöï
2S9EQý)µz“é{ì)G*¹…ñÃÃäJN/^pÞm “êx9¶žËnèTÜ+<2B>v8°v¯rTä|€-ëéÿäù<C3A4>bHp-Làqzœ)¥ æ˜GPK³Q û8ÊãE<>MOB1E÷ýw „@\ƒ
Tcˆ¸41óúæÙÆÒ6<C392>y|ÄøßÍCÁåLÎ<4C>“;ÓÛì2j¶<6A>
÷D·ú®ÇÌr}ÕŸ˜ñÀ`€Wç<05> /ÈT©ÁÚù<1D> NÄ"åcñNѳ}ÌKdÜŠŸ\T0¥yV<79>çQÍ7Cl¸"QO<11>ÜrÁTÎYv™SÜ<> Xæ¨ÅW­¦"ÂûT ŽÑ´!À^ì¼å( T¶¤>Å!r`ÆÎóþ”{Z-ÏewêTL)ö$¨½üº¸ÆÞ«ƒvå%µÅ2lªÏ•Ç&Ò–%“e¬•Uz;}dbL+ŒåÁrîÔcl <xum5žä…%… >(ÇZþcø2ßæMoA †ïû+|@JR¥-\*q!Mf½»#&žÁö$<24>ªþw4ìJQ)õÍžÇ~çµ§oc¡Dë ãP”<50>Õ_º(³7£Iq~RÀ |kœ@å<ˆ†B·<>ÛàYqÇ®n†vWLAßÈ*05Lx¹êò³çc¸Ã•u†à#&d˜JW¸ŒMÄ=f •`)»UÒÀr|´÷`{õL{gÁQxmÔCôhaãpÛö}¾Y\¹»Î£ZcÚ…­(<28>ìµ°„­Ó4<E280BA>Ø"ØPvÏ 2k”h,Âmcø&,Û<>LŠ"Éqi¹ðnù ÙøE Å{<7B>…õFd¿ÅCð^J<E28098>c
˜VÞY¨Ùl ÿ$Ç(ß<>OûËQ ¯BÌ<42>£ X…à<0F>951uï0Í`Є5&-òXüSÃXQåŠë´FR>?8¯ét^£~md8j³®uépÔ
@ -1101,7 +1097,8 @@ D7
öµT޳Ê{ãnz=S¡í
Ý;ÎXô±óhô¼É#êKÖmSêJ;ÏÑÝ_5ën¡kþ`ˆ³\¿bPX*Iy<49>Òqv¼/uñœ
KþSÐÎ`i<>µô<E28098>9@'
<06>#«°&Îb‰e)ƒÎí´-9Ó†8rXÓ?àÚn~ÀO ?=ï«ÕhfÖ¯f[ŒM:Îdq=ô«'Îÿ o„—xÆ€Ðý=ŽG+¶èé4<C3A9>6ø~û©(x<07>T=oÛ0Ýý+î5<C3AE>t)„ÐdjÓ!)ÐõL<C3B5>%"")ß‘‘òïÊ2âXrát#îßÇÁÛÞ5â‰mðZ^-WR ´¾ÒòÏó÷òv½¸é¹`S£Ñ»ÆsѳuŒm¡T×uËîû2P¥®W«+õ÷×ϧ*6èÐLJ@î·<>š¨å.Ac·K)"P…ñr ÷Œ\(ÕÖ@K¤XËQ1ŸÏ Ö !„ÈGAáÁ¡À×6Ø?¿µøÑ84w ½9éœr;舵L~/sÂí^°(ƒë¥:áW³Cybj¨ŽzçÂ<C3A7>2_ˆ1ݤˆ#ƒ!,ÑG KßZÔ2{Œd}5±?s¿¥HŒZî¥a§žÇ»¼ØKxZ`î•ÿe"_9cbØÆÐ¿€'1Ò? |eSl3,£Ž]~^aÖ0Ñ/6ÀŸd§vÑ'‡úš„Zn€­6‡E ¤ Á1¼àôýÎcK[!ÇÉœŽÂÍéc,ëž0üëÅ;³±/È(àâ*J-)-ÊSˆæRPPPPÏN­,ÖË/HÍ+H/ÐË/JW×Aˆ§•¥é•&•æ•”ê%ççÂä@Js3KôRSJÕ¹b­¹sHMÎÈWÈOKã*È(PPRVðp ŠwóôqõsôuUVVRPÕâ<00>SÁNÛ@½ç+¦–|KìVªz¨BP
<06>#«°&Îb‰e)ƒÎí´-9Ó†8rXÓ?àÚn~ÀO ?=ï«ÕhfÖ¯f[ŒM:Îdq=ô«'Îÿ o„—xÆ€Ðý=ŽG+¶èé4<C3A9>6ø~û©(x<07>T=oÛ0Ýý+î5<C3AE>t)„ÐdjÓ!)ÐõL<C3B5>%"")ß‘‘òïÊ2âXrát#îßÇÁÛÞ5â‰mðZ^-WR ´¾ÒòÏó÷òv½¸é¹`S£Ñ»ÆsѳuŒm¡T×uËîû2P¥®W«+õ÷×ϧ*6èÐLJ@î·<>š¨å.Ac·K)"P…ñr ÷Œ\(ÕÖ@K¤XËQ1ŸÏ Ö !„ÈGAáÁ¡À×6Ø?¿µøÑ84w ½9éœr;舵L~/sÂí^°(ƒë¥:áW³Cybj¨ŽzçÂ<C3A7>2_ˆ1ݤˆ#ƒ!,ÑG KßZÔ2{Œd}5±?s¿¥HŒZî¥a§žÇ»¼ØKxZ`î•ÿe"_9cbØÆÐ¿€'1Ò? |eSl3,£Ž]~^aÖ0Ñ/6ÀŸd§vÑ'‡úš„Zn€­6‡E ¤ Á1¼àôýÎcK[!ÇÉœŽÂÍéc,ëž0üëÅ;sHMÎÈWÈOKã*È(PPRVðp ŠwóôqõsôuUVVRPÕâ<00>SÁNÛ@½ç+¦–|KìVªz¨BP
¢ƒB@âRilOâ-ëkwœàK¿½Ú $@AªOöÍÌ{oÞŒ<C39E> ²N±9о$Ÿ#8ž ÆŸF£ÀõÅì.ƒ“y~6;¿]L—³y7?³Ël9Ïálv™ lY++¥ ¶èE•¨uk2dQ¨¢êÇwÙâf6ÏãØ@ŸN—YF£É`ÜÖjCðØh㎢Z¤ußÓ´­Ñ&ŠÓðMvS=Ëwú>{Døñß<C3B1>*Za§eøTå„-9@­áúbºp€¦Ç V•Åu<>å d#¨Œ2khH*eàOšNÉ~Ì=wP¢<50>²F³&<26>š`ËöÁWVÊR)lû!<14>P,•Ü4d*ª@œ¨ò¶JjP ömÇ%•ZCÍ EÏc#H'òJ2œf×Y~šå'÷p5ͧçÙU/?°e¶
+j=SöÐs†¨òì´r~ulàÍ*†æ…:Õ´º÷…F¨:¯¤çÎÂŽõÁ<C3B5>©š»u †å¥ôC;M¸!àNB·§hŠXUtBCp^ mÉ à•ÆB [¥õ~^A ŒÔšª—nz`Ð{ÙÖmg”D‡3øõ5ùö¾³ÿéš÷¡sÀ6€+¸-ñvYÒ½G#”dÄ¢+ÐÑp?õÙ#ÔŽƒáhàvq -+#>a€¦i~³?µs»<®•Ô]Qkù7•ZjÙ)ÌJn
eЇÿ¿:«'éï$]¥Â¬ÿ¾·ìM…G²¡PáG½¶v¼;êÉà/ÅT\U_˜]IHѬr*A<13><>Ø<EFBFBD>ß]ð0 <12>häHÖZö“Š&+nt‰0²¤3z7>œ¶Á0×:<3A>£ßGBMB
eЇÿ¿:«'éï$]¥Â¬ÿ¾·ìM…G²¡PáG½¶v¼;êÉà/³±/È(àâ*J-)-ÊSˆæRPPPPÏN­,ÖË/HÍ+H/ÐË/JW×Aˆ§•¥é•&•æ•”ê%ççªëpÅZs
40¾½ƒ&¡6cÓ®ßk`<60>ƒåï.—Þ^v¾ðnc°àÕ÷h¥??žßˆ0 Ï2rÝ›ÆDCÊGBMB

Binary file not shown.