From 44e6f355108de29baa3274bb28e212c27054cd61 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 4 Jan 2018 20:39:14 +0000 Subject: [PATCH 0001/2459] Bumped versions to 5.7 (#22636) --- composer.json | 2 +- src/Illuminate/Auth/composer.json | 16 ++++++++-------- src/Illuminate/Broadcasting/composer.json | 10 +++++----- src/Illuminate/Bus/composer.json | 8 ++++---- src/Illuminate/Cache/composer.json | 12 ++++++------ src/Illuminate/Config/composer.json | 6 +++--- src/Illuminate/Console/composer.json | 6 +++--- src/Illuminate/Container/composer.json | 4 ++-- src/Illuminate/Contracts/composer.json | 2 +- src/Illuminate/Cookie/composer.json | 6 +++--- src/Illuminate/Database/composer.json | 16 ++++++++-------- src/Illuminate/Encryption/composer.json | 6 +++--- src/Illuminate/Events/composer.json | 8 ++++---- src/Illuminate/Filesystem/composer.json | 6 +++--- src/Illuminate/Foundation/Application.php | 2 +- src/Illuminate/Hashing/composer.json | 6 +++--- src/Illuminate/Http/composer.json | 6 +++--- src/Illuminate/Log/composer.json | 6 +++--- src/Illuminate/Mail/composer.json | 8 ++++---- src/Illuminate/Notifications/composer.json | 20 ++++++++++---------- src/Illuminate/Pagination/composer.json | 6 +++--- src/Illuminate/Pipeline/composer.json | 6 +++--- src/Illuminate/Queue/composer.json | 16 ++++++++-------- src/Illuminate/Redis/composer.json | 6 +++--- src/Illuminate/Routing/composer.json | 16 ++++++++-------- src/Illuminate/Session/composer.json | 10 +++++----- src/Illuminate/Support/composer.json | 4 ++-- src/Illuminate/Translation/composer.json | 8 ++++---- src/Illuminate/Validation/composer.json | 12 ++++++------ src/Illuminate/View/composer.json | 12 ++++++------ tests/Console/ConsoleApplicationTest.php | 2 +- tests/Support/SupportTestingMailFakeTest.php | 4 ++-- 32 files changed, 129 insertions(+), 129 deletions(-) diff --git a/composer.json b/composer.json index fefa41592b7a..ec63f850cf53 100644 --- a/composer.json +++ b/composer.json @@ -101,7 +101,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { diff --git a/src/Illuminate/Auth/composer.json b/src/Illuminate/Auth/composer.json index 896c871a3919..ae98c7dc3fe3 100644 --- a/src/Illuminate/Auth/composer.json +++ b/src/Illuminate/Auth/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/http": "5.6.*", - "illuminate/queue": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/contracts": "5.7.*", + "illuminate/http": "5.7.*", + "illuminate/queue": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -27,13 +27,13 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { - "illuminate/console": "Required to use the auth:clear-resets command (5.6.*).", - "illuminate/queue": "Required to fire login / logout events (5.6.*).", - "illuminate/session": "Required to use the session based guard (5.6.*)." + "illuminate/console": "Required to use the auth:clear-resets command (5.7.*).", + "illuminate/queue": "Required to fire login / logout events (5.7.*).", + "illuminate/session": "Required to use the session based guard (5.7.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index 02069ac250fd..eb9c90b0b455 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -16,10 +16,10 @@ "require": { "php": "^7.1.3", "psr/log": "~1.0", - "illuminate/bus": "5.6.*", - "illuminate/contracts": "5.6.*", - "illuminate/queue": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/bus": "5.7.*", + "illuminate/contracts": "5.7.*", + "illuminate/queue": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { diff --git a/src/Illuminate/Bus/composer.json b/src/Illuminate/Bus/composer.json index 4939a99d921b..da911fda43e5 100644 --- a/src/Illuminate/Bus/composer.json +++ b/src/Illuminate/Bus/composer.json @@ -15,9 +15,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/pipeline": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/contracts": "5.7.*", + "illuminate/pipeline": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index 48b7e1bb7a73..a461242ce37f 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -25,13 +25,13 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { - "illuminate/database": "Required to use the database cache driver (5.6.*).", - "illuminate/filesystem": "Required to use the file cache driver (5.6.*).", - "illuminate/redis": "Required to use the redis cache driver (5.6.*)." + "illuminate/database": "Required to use the database cache driver (5.7.*).", + "illuminate/filesystem": "Required to use the file cache driver (5.7.*).", + "illuminate/redis": "Required to use the redis cache driver (5.7.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Config/composer.json b/src/Illuminate/Config/composer.json index f79f6f5665bb..1dbdd4be8209 100755 --- a/src/Illuminate/Config/composer.json +++ b/src/Illuminate/Config/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index 38346eb94bcd..eb96fc5ef05a 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*", "symfony/console": "~4.0" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { diff --git a/src/Illuminate/Container/composer.json b/src/Illuminate/Container/composer.json index b8c4aafc738a..fc52c13cb810 100755 --- a/src/Illuminate/Container/composer.json +++ b/src/Illuminate/Container/composer.json @@ -15,7 +15,7 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", + "illuminate/contracts": "5.7.*", "psr/container": "~1.0" }, "autoload": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Contracts/composer.json b/src/Illuminate/Contracts/composer.json index bd00fd61626e..7a7dbcf2eaeb 100644 --- a/src/Illuminate/Contracts/composer.json +++ b/src/Illuminate/Contracts/composer.json @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index d46dd119be06..b9f58b7afd0c 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*", "symfony/http-foundation": "~4.0", "symfony/http-kernel": "~4.0" }, @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index 652ac174ac5b..1b22c7aa6e9d 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -16,9 +16,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.6.*", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/container": "5.7.*", + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -27,16 +27,16 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.6).", "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", - "illuminate/console": "Required to use the database commands (5.6.*).", - "illuminate/events": "Required to use the observers with Eloquent (5.6.*).", - "illuminate/filesystem": "Required to use the migrations (5.6.*).", - "illuminate/pagination": "Required to paginate the result set (5.6.*)." + "illuminate/console": "Required to use the database commands (5.7.*).", + "illuminate/events": "Required to use the observers with Eloquent (5.7.*).", + "illuminate/filesystem": "Required to use the migrations (5.7.*).", + "illuminate/pagination": "Required to paginate the result set (5.7.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Encryption/composer.json b/src/Illuminate/Encryption/composer.json index 73486ababaf9..09eb4c74a271 100644 --- a/src/Illuminate/Encryption/composer.json +++ b/src/Illuminate/Encryption/composer.json @@ -17,8 +17,8 @@ "php": "^7.1.3", "ext-mbstring": "*", "ext-openssl": "*", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Events/composer.json b/src/Illuminate/Events/composer.json index ceca48505b3f..cba2e0fe27c9 100755 --- a/src/Illuminate/Events/composer.json +++ b/src/Illuminate/Events/composer.json @@ -15,9 +15,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.6.*", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/container": "5.7.*", + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index f9e205f4ab73..9e8d04c84e6c 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*", "symfony/finder": "~4.0" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index e1200161c009..373163ee0e64 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.6-dev'; + const VERSION = '5.7-dev'; /** * The base path for the Laravel installation. diff --git a/src/Illuminate/Hashing/composer.json b/src/Illuminate/Hashing/composer.json index f7dae2f4408a..ed9e20e8c07c 100755 --- a/src/Illuminate/Hashing/composer.json +++ b/src/Illuminate/Hashing/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 846a0305912c..cf67c4f72b4b 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/session": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/session": "5.7.*", + "illuminate/support": "5.7.*", "symfony/http-foundation": "~4.0", "symfony/http-kernel": "~4.0" }, @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Log/composer.json b/src/Illuminate/Log/composer.json index 15f56f0182a3..52da69281966 100755 --- a/src/Illuminate/Log/composer.json +++ b/src/Illuminate/Log/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*", "monolog/monolog": "~1.11" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index d3e23db4e2a4..69cc217d2dbd 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -16,9 +16,9 @@ "require": { "php": "^7.1.3", "erusev/parsedown": "~1.6", - "illuminate/container": "5.6.*", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/container": "5.7.*", + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*", "psr/log": "~1.0", "swiftmailer/swiftmailer": "~6.0", "tijsverkoyen/css-to-inline-styles": "dev-master" @@ -30,7 +30,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { diff --git a/src/Illuminate/Notifications/composer.json b/src/Illuminate/Notifications/composer.json index c1715cb2027e..81ab7af08e93 100644 --- a/src/Illuminate/Notifications/composer.json +++ b/src/Illuminate/Notifications/composer.json @@ -15,14 +15,14 @@ ], "require": { "php": "^7.1.3", - "illuminate/broadcasting": "5.6.*", - "illuminate/bus": "5.6.*", - "illuminate/container": "5.6.*", - "illuminate/contracts": "5.6.*", - "illuminate/filesystem": "5.6.*", - "illuminate/mail": "5.6.*", - "illuminate/queue": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/broadcasting": "5.7.*", + "illuminate/bus": "5.7.*", + "illuminate/container": "5.7.*", + "illuminate/contracts": "5.7.*", + "illuminate/filesystem": "5.7.*", + "illuminate/mail": "5.7.*", + "illuminate/queue": "5.7.*", + "illuminate/support": "5.7.*", "ramsey/uuid": "~3.0" }, "autoload": { @@ -32,12 +32,12 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { "guzzlehttp/guzzle": "Required to use the Slack transport (~6.0)", - "illuminate/database": "Required to use the database transport (5.6.*).", + "illuminate/database": "Required to use the database transport (5.7.*).", "nexmo/client": "Required to use the Nexmo transport (~1.0)." }, "config": { diff --git a/src/Illuminate/Pagination/composer.json b/src/Illuminate/Pagination/composer.json index 433829cb730f..9e4d73729746 100755 --- a/src/Illuminate/Pagination/composer.json +++ b/src/Illuminate/Pagination/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Pipeline/composer.json b/src/Illuminate/Pipeline/composer.json index 7e08e581ae2d..f3225d4a8b1b 100644 --- a/src/Illuminate/Pipeline/composer.json +++ b/src/Illuminate/Pipeline/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index 7a33abda3aa4..0e596cf52c77 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -15,12 +15,12 @@ ], "require": { "php": "^7.1.3", - "illuminate/console": "5.6.*", - "illuminate/container": "5.6.*", - "illuminate/contracts": "5.6.*", - "illuminate/database": "5.6.*", - "illuminate/filesystem": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/console": "5.7.*", + "illuminate/container": "5.7.*", + "illuminate/contracts": "5.7.*", + "illuminate/database": "5.7.*", + "illuminate/filesystem": "5.7.*", + "illuminate/support": "5.7.*", "symfony/debug": "~4.0", "symfony/process": "~4.0" }, @@ -31,14 +31,14 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { "ext-pcntl": "Required to use all features of the queue worker.", "ext-posix": "Required to use all features of the queue worker.", "aws/aws-sdk-php": "Required to use the SQS queue driver (~3.0).", - "illuminate/redis": "Required to use the Redis queue driver (5.6.*).", + "illuminate/redis": "Required to use the Redis queue driver (5.7.*).", "pda/pheanstalk": "Required to use the Beanstalk queue driver (~3.0)." }, "config": { diff --git a/src/Illuminate/Redis/composer.json b/src/Illuminate/Redis/composer.json index ee8bae7d5d23..0557d58b4cc3 100755 --- a/src/Illuminate/Redis/composer.json +++ b/src/Illuminate/Redis/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*", "predis/predis": "~1.0" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 56bf9d3e4067..1e6a554d67db 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -15,12 +15,12 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.6.*", - "illuminate/contracts": "5.6.*", - "illuminate/http": "5.6.*", - "illuminate/pipeline": "5.6.*", - "illuminate/session": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/container": "5.7.*", + "illuminate/contracts": "5.7.*", + "illuminate/http": "5.7.*", + "illuminate/pipeline": "5.7.*", + "illuminate/session": "5.7.*", + "illuminate/support": "5.7.*", "symfony/debug": "~4.0", "symfony/http-foundation": "~4.0", "symfony/http-kernel": "~4.0", @@ -33,11 +33,11 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { - "illuminate/console": "Required to use the make commands (5.6.*).", + "illuminate/console": "Required to use the make commands (5.7.*).", "symfony/psr-http-message-bridge": "Required to psr7 bridging features (~1.0)." }, "config": { diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index c1750f76e9a3..559125796d0e 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -15,9 +15,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/filesystem": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/contracts": "5.7.*", + "illuminate/filesystem": "5.7.*", + "illuminate/support": "5.7.*", "symfony/finder": "~4.0", "symfony/http-foundation": "~4.0" }, @@ -28,11 +28,11 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { - "illuminate/console": "Required to use the session:table command (5.6.*)." + "illuminate/console": "Required to use the session:table command (5.7.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 55a23230da08..7bff4b9def51 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -17,7 +17,7 @@ "php": "^7.1.3", "ext-mbstring": "*", "doctrine/inflector": "~1.1", - "illuminate/contracts": "5.6.*", + "illuminate/contracts": "5.7.*", "nesbot/carbon": "^1.20" }, "replace": { @@ -33,7 +33,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { diff --git a/src/Illuminate/Translation/composer.json b/src/Illuminate/Translation/composer.json index 4b01b280a826..d8784d7cceeb 100755 --- a/src/Illuminate/Translation/composer.json +++ b/src/Illuminate/Translation/composer.json @@ -15,9 +15,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.6.*", - "illuminate/filesystem": "5.6.*", - "illuminate/support": "5.6.*" + "illuminate/contracts": "5.7.*", + "illuminate/filesystem": "5.7.*", + "illuminate/support": "5.7.*" }, "autoload": { "psr-4": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index cfb90e1fbc55..8c36b8ac224b 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.6.*", - "illuminate/contracts": "5.6.*", - "illuminate/support": "5.6.*", - "illuminate/translation": "5.6.*", + "illuminate/container": "5.7.*", + "illuminate/contracts": "5.7.*", + "illuminate/support": "5.7.*", + "illuminate/translation": "5.7.*", "symfony/http-foundation": "~4.0" }, "autoload": { @@ -28,11 +28,11 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "suggest": { - "illuminate/database": "Required to use the database presence verifier (5.6.*)." + "illuminate/database": "Required to use the database presence verifier (5.7.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/View/composer.json b/src/Illuminate/View/composer.json index c82d2e0ead6c..40585a4a002c 100644 --- a/src/Illuminate/View/composer.json +++ b/src/Illuminate/View/composer.json @@ -15,11 +15,11 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.6.*", - "illuminate/contracts": "5.6.*", - "illuminate/events": "5.6.*", - "illuminate/filesystem": "5.6.*", - "illuminate/support": "5.6.*", + "illuminate/container": "5.7.*", + "illuminate/contracts": "5.7.*", + "illuminate/events": "5.7.*", + "illuminate/filesystem": "5.7.*", + "illuminate/support": "5.7.*", "symfony/debug": "~4.0" }, "autoload": { @@ -29,7 +29,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.6-dev" + "dev-master": "5.7-dev" } }, "config": { diff --git a/tests/Console/ConsoleApplicationTest.php b/tests/Console/ConsoleApplicationTest.php index 76b658339267..06aaddf02be4 100755 --- a/tests/Console/ConsoleApplicationTest.php +++ b/tests/Console/ConsoleApplicationTest.php @@ -47,7 +47,7 @@ public function testResolveAddsCommandViaApplicationResolution() protected function getMockConsole(array $methods) { - $app = m::mock('Illuminate\Contracts\Foundation\Application', ['version' => '5.6']); + $app = m::mock('Illuminate\Contracts\Foundation\Application', ['version' => '5.7']); $events = m::mock('Illuminate\Contracts\Events\Dispatcher', ['dispatch' => null]); $console = $this->getMockBuilder('Illuminate\Console\Application')->setMethods($methods)->setConstructorArgs([ diff --git a/tests/Support/SupportTestingMailFakeTest.php b/tests/Support/SupportTestingMailFakeTest.php index 8a2a7ead675c..87d13f5f2831 100644 --- a/tests/Support/SupportTestingMailFakeTest.php +++ b/tests/Support/SupportTestingMailFakeTest.php @@ -111,7 +111,7 @@ class MailableStub extends Mailable { public $framework = 'Laravel'; - protected $version = '5.6'; + protected $version = '5.7'; /** * Build the message. @@ -129,7 +129,7 @@ class QueueableMailableStub extends Mailable implements ShouldQueue { public $framework = 'Laravel'; - protected $version = '5.6'; + protected $version = '5.7'; /** * Build the message. From 6d513998b949f4d1b9e0d0b29c71020d6b62a2de Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 6 Jan 2018 10:07:43 -0600 Subject: [PATCH 0002/2459] update dep --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ec63f850cf53..8e0e0c2c8b04 100644 --- a/composer.json +++ b/composer.json @@ -75,7 +75,7 @@ "doctrine/dbal": "~2.6", "filp/whoops": "^2.1.4", "mockery/mockery": "~1.0", - "orchestra/testbench-core": "3.6.*", + "orchestra/testbench-core": "3.7.*", "pda/pheanstalk": "~3.0", "phpunit/phpunit": "~6.0", "predis/predis": "^1.1.1", From 127a83d8d2b1f3842b685982ac531936ef3030c4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 9 Feb 2018 14:06:15 -0600 Subject: [PATCH 0003/2459] Apply fixes from StyleCI (#23102) --- src/Illuminate/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 8a87729dc871..bf2d7165f7b2 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -350,7 +350,7 @@ protected function getInputSource() * @param \Illuminate\Http\Request|null $to * @return static */ - public static function createFrom(Request $from, $to = null) + public static function createFrom(self $from, $to = null) { $request = $to ?: new static; From b345650272e258d4ab99f57b0db6d0fcc7868ed8 Mon Sep 17 00:00:00 2001 From: Jack97 Date: Wed, 14 Feb 2018 02:44:33 +0000 Subject: [PATCH 0004/2459] Add absolute controller namespacing on route groups (#23113) --- src/Illuminate/Routing/RouteGroup.php | 2 +- tests/Routing/RoutingRouteTest.php | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/RouteGroup.php b/src/Illuminate/Routing/RouteGroup.php index ba33beeb93a7..4041f1f79b01 100644 --- a/src/Illuminate/Routing/RouteGroup.php +++ b/src/Illuminate/Routing/RouteGroup.php @@ -40,7 +40,7 @@ public static function merge($new, $old) protected static function formatNamespace($new, $old) { if (isset($new['namespace'])) { - return isset($old['namespace']) + return isset($old['namespace']) && strpos($new['namespace'], '\\') !== 0 ? trim($old['namespace'], '\\').'\\'.trim($new['namespace'], '\\') : trim($new['namespace'], '\\'); } diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index 7167089ee5d0..866c7b08c56f 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -882,6 +882,25 @@ public function testRouteGrouping() $this->assertEquals('foo', $routes[0]->getPrefix()); } + public function testRouteGroupingOutsideOfInheritedNamespace() + { + $router = $this->getRouter(); + + $router->group(['namespace' => 'App\Http\Controllers'], function ($router) { + $router->group(['namespace' => '\Foo\Bar'], function ($router) { + $router->get('users', 'UsersController@index'); + }); + }); + + $routes = $router->getRoutes(); + $routes = $routes->getRoutes(); + + $this->assertEquals( + 'Foo\Bar\UsersController@index', + $routes[0]->getAction()['uses'] + ); + } + public function testCurrentRouteUses() { $router = $this->getRouter(); From a60770e7e13e448293005167e6fec152123d37bc Mon Sep 17 00:00:00 2001 From: Laurence Ioannou Date: Sun, 18 Feb 2018 01:52:05 +1100 Subject: [PATCH 0005/2459] Update Factory.php (#23200) --- src/Illuminate/Contracts/Cookie/Factory.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Contracts/Cookie/Factory.php b/src/Illuminate/Contracts/Cookie/Factory.php index 0cf83ea7f08a..1cdd71bf0ce2 100644 --- a/src/Illuminate/Contracts/Cookie/Factory.php +++ b/src/Illuminate/Contracts/Cookie/Factory.php @@ -12,13 +12,13 @@ interface Factory * @param int $minutes * @param string $path * @param string $domain - * @param bool $secure + * @param bool|null $secure * @param bool $httpOnly * @param bool $raw * @param string|null $sameSite * @return \Symfony\Component\HttpFoundation\Cookie */ - public function make($name, $value, $minutes = 0, $path = null, $domain = null, $secure = false, $httpOnly = true, $raw = false, $sameSite = null); + public function make($name, $value, $minutes = 0, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null); /** * Create a cookie that lasts "forever" (five years). @@ -27,13 +27,13 @@ public function make($name, $value, $minutes = 0, $path = null, $domain = null, * @param string $value * @param string $path * @param string $domain - * @param bool $secure + * @param bool|null $secure * @param bool $httpOnly * @param bool $raw * @param string|null $sameSite * @return \Symfony\Component\HttpFoundation\Cookie */ - public function forever($name, $value, $path = null, $domain = null, $secure = false, $httpOnly = true, $raw = false, $sameSite = null); + public function forever($name, $value, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null); /** * Expire the given cookie. From 6d41a3f42a68ddaee1657eec7ff58d826ce02b5a Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Sat, 17 Feb 2018 18:52:11 -0500 Subject: [PATCH 0006/2459] Allow specifying a default when asking for a route parameter from the request (#23201) --- src/Illuminate/Http/Request.php | 6 +++--- tests/Http/HttpRequestTest.php | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index bf2d7165f7b2..ce09918d8aa0 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -487,10 +487,10 @@ public function user($guard = null) * Get the route handling the request. * * @param string|null $param - * + * @param mixed $default * @return \Illuminate\Routing\Route|object|string */ - public function route($param = null) + public function route($param = null, $default = null) { $route = call_user_func($this->getRouteResolver()); @@ -498,7 +498,7 @@ public function route($param = null) return $route; } - return $route->parameter($param); + return $route->parameter($param, $default); } /** diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index 7e59352bb881..97c395b0460b 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -187,6 +187,23 @@ public function testRouteIsMethod() $this->assertFalse($request->routeIs('foo.foo')); } + public function testRouteMethod() + { + $request = Request::create('/foo/bar', 'GET'); + + $request->setRouteResolver(function () use ($request) { + $route = new Route('GET', '/foo/{required}/{optional?}', []); + $route->bind($request); + + return $route; + }); + + $this->assertEquals('bar', $request->route('required')); + $this->assertEquals('bar', $request->route('required', 'default')); + $this->assertNull($request->route('optional')); + $this->assertEquals('default', $request->route('optional', 'default')); + } + public function testAjaxMethod() { $request = Request::create('/', 'GET'); From f3f4b0a478d35d65bbbfb528b086dad4062f84a7 Mon Sep 17 00:00:00 2001 From: Abdelrahman Omran Date: Mon, 19 Feb 2018 16:29:42 +0200 Subject: [PATCH 0007/2459] Pass basic authentication field parameter to the auth.basic middleware (Ref #23216) (#23220) --- src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php b/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php index 71f8be87813f..4c9e68786584 100644 --- a/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php +++ b/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php @@ -31,10 +31,11 @@ public function __construct(AuthFactory $auth) * @param \Illuminate\Http\Request $request * @param \Closure $next * @param string|null $guard + * @param string|null $field * @return mixed */ - public function handle($request, Closure $next, $guard = null) + public function handle($request, Closure $next, $guard = null, $field = null) { - return $this->auth->guard($guard)->basic() ?: $next($request); + return $this->auth->guard($guard)->basic($field) ?: $next($request); } } From 8129d194cb68c2b46c24aa9c3409557d0ab14540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kr=C3=BCss?= Date: Tue, 20 Feb 2018 05:40:48 -0800 Subject: [PATCH 0008/2459] =?UTF-8?q?don=E2=80=99t=20call=20Redis=20client?= =?UTF-8?q?=20directly=20(#23225)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Redis/Connections/PhpRedisConnection.php | 26 +++++++++---------- .../Redis/Limiters/ConcurrencyLimiter.php | 9 ++++--- .../Redis/Limiters/DurationLimiter.php | 6 ++--- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index 252532fac8fe..15955629f283 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -29,7 +29,7 @@ public function __construct($client) */ public function get($key) { - $result = $this->client->get($key); + $result = $this->command('get', [$key]); return $result !== false ? $result : null; } @@ -44,7 +44,7 @@ public function mget(array $keys) { return array_map(function ($value) { return $value !== false ? $value : null; - }, $this->client->mget($keys)); + }, $this->command('mget', $keys)); } /** @@ -90,7 +90,7 @@ public function set($key, $value, $expireResolution = null, $expireTTL = null, $ */ public function setnx($key, $value) { - return (int) $this->client->setnx($key, $value); + return (int) $this->command('setnx', [$key, $value]); } /** @@ -139,7 +139,7 @@ public function hmset($key, ...$dictionary) */ public function hsetnx($hash, $key, $value) { - return (int) $this->client->hsetnx($hash, $key, $value); + return (int) $this->command('hsetnx', [$hash, $key, $value]); } /** @@ -240,10 +240,10 @@ public function zrevrangebyscore($key, $min, $max, $options = []) */ public function zinterstore($output, $keys, $options = []) { - return $this->zInter($output, $keys, + return $this->command('zInter', [$output, $keys, $options['weights'] ?? null, - $options['aggregate'] ?? 'sum' - ); + $options['aggregate'] ?? 'sum', + ]); } /** @@ -256,10 +256,10 @@ public function zinterstore($output, $keys, $options = []) */ public function zunionstore($output, $keys, $options = []) { - return $this->zUnion($output, $keys, + return $this->command('zUnion', [$output, $keys, $options['weights'] ?? null, - $options['aggregate'] ?? 'sum' - ); + $options['aggregate'] ?? 'sum', + ]); } /** @@ -317,7 +317,7 @@ public function evalsha($script, $numkeys, ...$arguments) */ public function eval($script, $numberOfKeys, ...$arguments) { - return $this->client->eval($script, $arguments, $numberOfKeys); + return $this->command('eval', [$script, $arguments, $numberOfKeys]); } /** @@ -404,8 +404,6 @@ private function applyPrefix($key) */ public function __call($method, $parameters) { - $method = strtolower($method); - - return parent::__call($method, $parameters); + return parent::__call(strtolower($method), $parameters); } } diff --git a/src/Illuminate/Redis/Limiters/ConcurrencyLimiter.php b/src/Illuminate/Redis/Limiters/ConcurrencyLimiter.php index c6db2e20a71c..c6f03d8cc0ab 100644 --- a/src/Illuminate/Redis/Limiters/ConcurrencyLimiter.php +++ b/src/Illuminate/Redis/Limiters/ConcurrencyLimiter.php @@ -91,9 +91,10 @@ protected function acquire() return $this->name.$i; }, range(1, $this->maxLocks)); - return $this->redis->eval($this->luaScript(), count($slots), - ...array_merge($slots, [$this->name, $this->releaseAfter]) - ); + return $this->redis->command('eval', array_merge( + [$this->luaScript(), count($slots)], + array_merge($slots, [$this->name, $this->releaseAfter]) + )); } /** @@ -125,6 +126,6 @@ protected function luaScript() */ protected function release($key) { - $this->redis->del($key); + $this->redis->command('del', [$key]); } } diff --git a/src/Illuminate/Redis/Limiters/DurationLimiter.php b/src/Illuminate/Redis/Limiters/DurationLimiter.php index 0cd0ab2615c5..0cd555217145 100644 --- a/src/Illuminate/Redis/Limiters/DurationLimiter.php +++ b/src/Illuminate/Redis/Limiters/DurationLimiter.php @@ -99,9 +99,9 @@ public function block($timeout, $callback = null) */ public function acquire() { - $results = $this->redis->eval($this->luaScript(), 1, - $this->name, microtime(true), time(), $this->decay, $this->maxLocks - ); + $results = $this->redis->command('eval', [ + $this->luaScript(), 1, $this->name, microtime(true), time(), $this->decay, $this->maxLocks, + ]); $this->decaysAt = $results[1]; From 4215fd36f269f3b6d27fd453c7503cbde9806621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kru=CC=88ss?= Date: Tue, 20 Feb 2018 16:36:08 -0800 Subject: [PATCH 0009/2459] set Redis connection names --- .../Redis/Connections/Connection.php | 28 +++++++++++++++++++ src/Illuminate/Redis/RedisManager.php | 5 +++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Redis/Connections/Connection.php b/src/Illuminate/Redis/Connections/Connection.php index c5b524a04afe..f68a6857e39d 100644 --- a/src/Illuminate/Redis/Connections/Connection.php +++ b/src/Illuminate/Redis/Connections/Connection.php @@ -18,6 +18,13 @@ abstract class Connection */ protected $client; + /** + * The Redis connection name. + * + * @var string + */ + protected $name; + /** * Subscribe to a set of given channels for messages. * @@ -96,6 +103,27 @@ public function command($method, array $parameters = []) return $this->client->{$method}(...$parameters); } + /** + * Get the connection name. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Set the connections name. + * + * @param string $name + * @return void + */ + public function setName($name) + { + $this->name = $name; + } + /** * Pass other method calls down to the underlying client. * diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index 3217916d8bb5..cc1645d1d040 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -58,7 +58,10 @@ public function connection($name = null) return $this->connections[$name]; } - return $this->connections[$name] = $this->resolve($name); + $this->connections[$name] = $this->resolve($name); + $this->connections[$name]->setName($name); + + return $this->connections[$name]; } /** From b000f2896ac19088cc9e07b33c61016066aacc7c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 21 Feb 2018 07:52:59 -0600 Subject: [PATCH 0010/2459] formatting --- src/Illuminate/Redis/Connections/Connection.php | 8 +++++--- src/Illuminate/Redis/RedisManager.php | 5 +---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Redis/Connections/Connection.php b/src/Illuminate/Redis/Connections/Connection.php index f68a6857e39d..33916e19a0b6 100644 --- a/src/Illuminate/Redis/Connections/Connection.php +++ b/src/Illuminate/Redis/Connections/Connection.php @@ -21,7 +21,7 @@ abstract class Connection /** * The Redis connection name. * - * @var string + * @var string|null */ protected $name; @@ -106,7 +106,7 @@ public function command($method, array $parameters = []) /** * Get the connection name. * - * @return string + * @return string|null */ public function getName() { @@ -117,11 +117,13 @@ public function getName() * Set the connections name. * * @param string $name - * @return void + * @return $this */ public function setName($name) { $this->name = $name; + + return $this; } /** diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index cc1645d1d040..7552ff1f5837 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -58,10 +58,7 @@ public function connection($name = null) return $this->connections[$name]; } - $this->connections[$name] = $this->resolve($name); - $this->connections[$name]->setName($name); - - return $this->connections[$name]; + return $this->connections[$name] = $this->resolve($name)->setName($name); } /** From e7fa0b047b401666a50940c722bba762176a556f Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 22 Feb 2018 21:10:55 +0000 Subject: [PATCH 0011/2459] Apply fixes from StyleCI (#23265) --- src/Illuminate/Database/Eloquent/Model.php | 2 +- tests/Support/SupportCollectionTest.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 2b9af0037a6f..80c59cbd4b72 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -231,7 +231,7 @@ public function fill(array $attributes) $this->setAttribute($key, $value); } elseif ($totallyGuarded) { throw new MassAssignmentException(sprintf( - "Add [%s] to fillable property to allow mass assignment on [%s].", + 'Add [%s] to fillable property to allow mass assignment on [%s].', $key, get_class($this) )); } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index c0cf9afeec6b..1936cbe05016 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -633,10 +633,11 @@ public function testDiffUsingWithCollection() { $c = new Collection(['en_GB', 'fr', 'HR']); // demonstrate that diffKeys wont support case insensitivity - $this->assertEquals(['en_GB', 'fr', 'HR'], $c->diff(new Collection(['en_gb' , 'hr']))->values()->toArray()); + $this->assertEquals(['en_GB', 'fr', 'HR'], $c->diff(new Collection(['en_gb', 'hr']))->values()->toArray()); // allow for case insensitive difference - $this->assertEquals(['fr'], $c->diffUsing(new Collection(['en_gb' , 'hr']), 'strcasecmp')->values()->toArray()); + $this->assertEquals(['fr'], $c->diffUsing(new Collection(['en_gb', 'hr']), 'strcasecmp')->values()->toArray()); } + public function testDiffUsingWithNull() { $c = new Collection(['en_GB', 'fr', 'HR']); From e5763e16cb9170140d2c26697e34bda57b56e62d Mon Sep 17 00:00:00 2001 From: tjallingt Date: Thu, 1 Mar 2018 23:32:06 +0100 Subject: [PATCH 0012/2459] Add getNextRunDate timezone argument (#23350) CronExpression getNextRunDate supports a timezone argument to output the datetime in the specified timezone --- src/Illuminate/Console/Scheduling/Event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 89f9c99408fe..49b14af33364 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -668,7 +668,7 @@ public function nextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = { return Carbon::instance(CronExpression::factory( $this->getExpression() - )->getNextRunDate($currentTime, $nth, $allowCurrentDate)); + )->getNextRunDate($currentTime, $nth, $allowCurrentDate, $this->timezone)); } /** From fe1cbdf3b51ce1235b8c91f5e603f1e9306e4f6f Mon Sep 17 00:00:00 2001 From: Vincent Klaiber Date: Fri, 9 Mar 2018 20:14:12 +0100 Subject: [PATCH 0013/2459] Add optimize and optimize:clear commands --- .../Console/OptimizeClearCommand.php | 37 +++++++++++++++++++ .../Foundation/Console/OptimizeCommand.php | 37 +++++++++++++++++++ .../Providers/ArtisanServiceProvider.php | 28 ++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 src/Illuminate/Foundation/Console/OptimizeClearCommand.php create mode 100644 src/Illuminate/Foundation/Console/OptimizeCommand.php diff --git a/src/Illuminate/Foundation/Console/OptimizeClearCommand.php b/src/Illuminate/Foundation/Console/OptimizeClearCommand.php new file mode 100644 index 000000000000..8e205160c7cc --- /dev/null +++ b/src/Illuminate/Foundation/Console/OptimizeClearCommand.php @@ -0,0 +1,37 @@ +call('cache:clear'); + $this->call('route:clear'); + $this->call('view:clear'); + $this->call('clear-compiled'); + + $this->info('Config, routes and view cache cleared successfully!'); + } +} diff --git a/src/Illuminate/Foundation/Console/OptimizeCommand.php b/src/Illuminate/Foundation/Console/OptimizeCommand.php new file mode 100644 index 000000000000..5d537bf97c27 --- /dev/null +++ b/src/Illuminate/Foundation/Console/OptimizeCommand.php @@ -0,0 +1,37 @@ +call('cache:clear'); + $this->call('config:cache'); + $this->call('route:clear'); + $this->call('route:cache'); + + $this->info('Config and routes cached successfully!'); + } +} diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index 6fe0655a9848..f1c095a62598 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -16,6 +16,7 @@ use Illuminate\Foundation\Console\JobMakeCommand; use Illuminate\Database\Console\Seeds\SeedCommand; use Illuminate\Foundation\Console\MailMakeCommand; +use Illuminate\Foundation\Console\OptimizeCommand; use Illuminate\Foundation\Console\RuleMakeCommand; use Illuminate\Foundation\Console\TestMakeCommand; use Illuminate\Foundation\Console\EventMakeCommand; @@ -43,6 +44,7 @@ use Illuminate\Foundation\Console\ClearCompiledCommand; use Illuminate\Foundation\Console\EventGenerateCommand; use Illuminate\Foundation\Console\ExceptionMakeCommand; +use Illuminate\Foundation\Console\OptimizeClearCommand; use Illuminate\Foundation\Console\VendorPublishCommand; use Illuminate\Console\Scheduling\ScheduleFinishCommand; use Illuminate\Database\Console\Seeds\SeederMakeCommand; @@ -99,6 +101,8 @@ class ArtisanServiceProvider extends ServiceProvider 'MigrateReset' => 'command.migrate.reset', 'MigrateRollback' => 'command.migrate.rollback', 'MigrateStatus' => 'command.migrate.status', + 'Optimize' => 'command.optimize', + 'OptimizeClear' => 'command.optimize.clear', 'PackageDiscover' => 'command.package.discover', 'Preset' => 'command.preset', 'QueueFailed' => 'command.queue.failed', @@ -587,6 +591,30 @@ protected function registerNotificationMakeCommand() }); } + /** + * Register the command. + * + * @return void + */ + protected function registerOptimizeCommand() + { + $this->app->singleton('command.optimize', function ($app) { + return new OptimizeCommand; + }); + } + + /** + * Register the command. + * + * @return void + */ + protected function registerOptimizeClearCommand() + { + $this->app->singleton('command.optimize.clear', function ($app) { + return new OptimizeClearCommand; + }); + } + /** * Register the command. * From c2a6f174a3cabb8eead53614010c383f5aa3daad Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 9 Mar 2018 15:26:32 -0600 Subject: [PATCH 0014/2459] formatting --- src/Illuminate/Foundation/Console/OptimizeClearCommand.php | 6 +++--- src/Illuminate/Foundation/Console/OptimizeCommand.php | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Foundation/Console/OptimizeClearCommand.php b/src/Illuminate/Foundation/Console/OptimizeClearCommand.php index 8e205160c7cc..0fc7d961df83 100644 --- a/src/Illuminate/Foundation/Console/OptimizeClearCommand.php +++ b/src/Illuminate/Foundation/Console/OptimizeClearCommand.php @@ -18,7 +18,7 @@ class OptimizeClearCommand extends Command * * @var string */ - protected $description = 'Clear all caches (routes, config, views, compiled class)'; + protected $description = 'Remove the cached bootstrap files'; /** * Execute the console command. @@ -27,11 +27,11 @@ class OptimizeClearCommand extends Command */ public function handle() { + $this->call('view:clear'); $this->call('cache:clear'); $this->call('route:clear'); - $this->call('view:clear'); $this->call('clear-compiled'); - $this->info('Config, routes and view cache cleared successfully!'); + $this->info('Caches cleared successfully!'); } } diff --git a/src/Illuminate/Foundation/Console/OptimizeCommand.php b/src/Illuminate/Foundation/Console/OptimizeCommand.php index 5d537bf97c27..af5d731ea8da 100644 --- a/src/Illuminate/Foundation/Console/OptimizeCommand.php +++ b/src/Illuminate/Foundation/Console/OptimizeCommand.php @@ -18,7 +18,7 @@ class OptimizeCommand extends Command * * @var string */ - protected $description = 'Optimize everything (cache routes, config)'; + protected $description = 'Cache the framework bootstrap files'; /** * Execute the console command. @@ -27,11 +27,9 @@ class OptimizeCommand extends Command */ public function handle() { - $this->call('cache:clear'); $this->call('config:cache'); - $this->call('route:clear'); $this->call('route:cache'); - $this->info('Config and routes cached successfully!'); + $this->info('Files cached successfully!'); } } From 94bba2d0edc3b59216f49ef5739ae7b83653032d Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 10 Mar 2018 14:41:50 +0000 Subject: [PATCH 0015/2459] Fixed recommended version --- src/Illuminate/Support/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index e2862f9cbc8e..74010bab57df 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -37,7 +37,7 @@ } }, "suggest": { - "illuminate/filesystem": "Required to use the composer class (5.6.*).", + "illuminate/filesystem": "Required to use the composer class (5.7.*).", "symfony/process": "Required to use the composer class (~4.0).", "symfony/var-dumper": "Required to use the dd function (~4.0)." }, From 1d088833cca7262d28011b0a7277413f9a8a1200 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 10 Mar 2018 15:46:11 +0000 Subject: [PATCH 0016/2459] Bumped versions (#23481) --- composer.json | 50 +++++++++++----------- src/Illuminate/Broadcasting/composer.json | 2 +- src/Illuminate/Console/composer.json | 4 +- src/Illuminate/Container/composer.json | 2 +- src/Illuminate/Contracts/composer.json | 4 +- src/Illuminate/Cookie/composer.json | 4 +- src/Illuminate/Filesystem/composer.json | 2 +- src/Illuminate/Http/composer.json | 4 +- src/Illuminate/Log/composer.json | 2 +- src/Illuminate/Mail/composer.json | 6 +-- src/Illuminate/Notifications/composer.json | 2 +- src/Illuminate/Queue/composer.json | 4 +- src/Illuminate/Redis/composer.json | 2 +- src/Illuminate/Routing/composer.json | 8 ++-- src/Illuminate/Session/composer.json | 4 +- src/Illuminate/Support/composer.json | 6 +-- src/Illuminate/Validation/composer.json | 2 +- src/Illuminate/View/composer.json | 2 +- 18 files changed, 55 insertions(+), 55 deletions(-) diff --git a/composer.json b/composer.json index 84811ed4c6c8..a79f84b51891 100644 --- a/composer.json +++ b/composer.json @@ -18,26 +18,26 @@ "php": "^7.1.3", "ext-mbstring": "*", "ext-openssl": "*", - "doctrine/inflector": "~1.1", - "dragonmantank/cron-expression": "~2.0", - "erusev/parsedown": "~1.7", - "league/flysystem": "~1.0", - "monolog/monolog": "~1.12", + "doctrine/inflector": "^1.1", + "dragonmantank/cron-expression": "^2.0", + "erusev/parsedown": "^1.7", + "league/flysystem": "^1.0", + "monolog/monolog": "^1.12", "nesbot/carbon": "^1.24.1", - "psr/container": "~1.0", + "psr/container": "^1.0", "psr/simple-cache": "^1.0", "ramsey/uuid": "^3.7", - "swiftmailer/swiftmailer": "~6.0", - "symfony/console": "~4.0", - "symfony/debug": "~4.0", - "symfony/finder": "~4.0", - "symfony/http-foundation": "~4.0", - "symfony/http-kernel": "~4.0", - "symfony/process": "~4.0", - "symfony/routing": "~4.0", - "symfony/var-dumper": "~4.0", + "swiftmailer/swiftmailer": "^6.0", + "symfony/console": "^4.1", + "symfony/debug": "^4.1", + "symfony/finder": "^4.1", + "symfony/http-foundation": "^4.1", + "symfony/http-kernel": "^4.1", + "symfony/process": "^4.1", + "symfony/routing": "^4.1", + "symfony/var-dumper": "^4.1", "tijsverkoyen/css-to-inline-styles": "^2.2.1", - "vlucas/phpdotenv": "~2.2" + "vlucas/phpdotenv": "^2.2" }, "replace": { "illuminate/auth": "self.version", @@ -73,17 +73,17 @@ "tightenco/collect": "<5.5.33" }, "require-dev": { - "aws/aws-sdk-php": "~3.0", - "doctrine/dbal": "~2.6", + "aws/aws-sdk-php": "^3.0", + "doctrine/dbal": "^2.6", "filp/whoops": "^2.1.4", - "mockery/mockery": "~1.0", + "mockery/mockery": "^1.0", "moontoast/math": "^1.1", "orchestra/testbench-core": "3.7.*", - "pda/pheanstalk": "~3.0", - "phpunit/phpunit": "~7.0", + "pda/pheanstalk": "^3.0", + "phpunit/phpunit": "^7.0", "predis/predis": "^1.1.1", - "symfony/css-selector": "~4.0", - "symfony/dom-crawler": "~4.0" + "symfony/css-selector": "^4.1", + "symfony/dom-crawler": "^4.1" }, "autoload": { "files": [ @@ -123,8 +123,8 @@ "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~3.0).", - "symfony/css-selector": "Required to use some of the crawler integration testing tools (~4.0).", - "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (~4.0).", + "symfony/css-selector": "Required to use some of the crawler integration testing tools (^4.1).", + "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (^4.1).", "symfony/psr-http-message-bridge": "Required to psr7 bridging features (~1.0)." }, "config": { diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index eb9c90b0b455..dbd60b447828 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -15,7 +15,7 @@ ], "require": { "php": "^7.1.3", - "psr/log": "~1.0", + "psr/log": "^1.0", "illuminate/bus": "5.7.*", "illuminate/contracts": "5.7.*", "illuminate/queue": "5.7.*", diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index eb96fc5ef05a..95547e5ae952 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -17,7 +17,7 @@ "php": "^7.1.3", "illuminate/contracts": "5.7.*", "illuminate/support": "5.7.*", - "symfony/console": "~4.0" + "symfony/console": "^4.1" }, "autoload": { "psr-4": { @@ -32,7 +32,7 @@ "suggest": { "dragonmantank/cron-expression": "Required to use scheduling component (~2.0).", "guzzlehttp/guzzle": "Required to use the ping methods on schedules (~6.0).", - "symfony/process": "Required to use scheduling component (~4.0)." + "symfony/process": "Required to use scheduling component (^4.1)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Container/composer.json b/src/Illuminate/Container/composer.json index fc52c13cb810..3dd083c8c696 100755 --- a/src/Illuminate/Container/composer.json +++ b/src/Illuminate/Container/composer.json @@ -16,7 +16,7 @@ "require": { "php": "^7.1.3", "illuminate/contracts": "5.7.*", - "psr/container": "~1.0" + "psr/container": "^1.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Contracts/composer.json b/src/Illuminate/Contracts/composer.json index 7a7dbcf2eaeb..62c351eb518e 100644 --- a/src/Illuminate/Contracts/composer.json +++ b/src/Illuminate/Contracts/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "psr/container": "~1.0", - "psr/simple-cache": "~1.0" + "psr/container": "^1.0", + "psr/simple-cache": "^1.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index b9f58b7afd0c..014b7d21daea 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -17,8 +17,8 @@ "php": "^7.1.3", "illuminate/contracts": "5.7.*", "illuminate/support": "5.7.*", - "symfony/http-foundation": "~4.0", - "symfony/http-kernel": "~4.0" + "symfony/http-foundation": "^4.1", + "symfony/http-kernel": "^4.1" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index 5e98a8de610c..066b9a030f5a 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -17,7 +17,7 @@ "php": "^7.1.3", "illuminate/contracts": "5.7.*", "illuminate/support": "5.7.*", - "symfony/finder": "~4.0" + "symfony/finder": "^4.1" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index cf67c4f72b4b..69eb15562d04 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -17,8 +17,8 @@ "php": "^7.1.3", "illuminate/session": "5.7.*", "illuminate/support": "5.7.*", - "symfony/http-foundation": "~4.0", - "symfony/http-kernel": "~4.0" + "symfony/http-foundation": "^4.1", + "symfony/http-kernel": "^4.1" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Log/composer.json b/src/Illuminate/Log/composer.json index 52da69281966..f0af69bd44de 100755 --- a/src/Illuminate/Log/composer.json +++ b/src/Illuminate/Log/composer.json @@ -17,7 +17,7 @@ "php": "^7.1.3", "illuminate/contracts": "5.7.*", "illuminate/support": "5.7.*", - "monolog/monolog": "~1.11" + "monolog/monolog": "^1.11" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 64aa3e98f46c..334a7d0046b1 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -15,12 +15,12 @@ ], "require": { "php": "^7.1.3", - "erusev/parsedown": "~1.7", + "erusev/parsedown": "^1.7", "illuminate/container": "5.7.*", "illuminate/contracts": "5.7.*", "illuminate/support": "5.7.*", - "psr/log": "~1.0", - "swiftmailer/swiftmailer": "~6.0", + "psr/log": "^1.0", + "swiftmailer/swiftmailer": "^6.0", "tijsverkoyen/css-to-inline-styles": "^2.2.1" }, "autoload": { diff --git a/src/Illuminate/Notifications/composer.json b/src/Illuminate/Notifications/composer.json index 81ab7af08e93..49faf68b129d 100644 --- a/src/Illuminate/Notifications/composer.json +++ b/src/Illuminate/Notifications/composer.json @@ -23,7 +23,7 @@ "illuminate/mail": "5.7.*", "illuminate/queue": "5.7.*", "illuminate/support": "5.7.*", - "ramsey/uuid": "~3.0" + "ramsey/uuid": "^3.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index 0e596cf52c77..83a64785590f 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -21,8 +21,8 @@ "illuminate/database": "5.7.*", "illuminate/filesystem": "5.7.*", "illuminate/support": "5.7.*", - "symfony/debug": "~4.0", - "symfony/process": "~4.0" + "symfony/debug": "^4.1", + "symfony/process": "^4.1" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Redis/composer.json b/src/Illuminate/Redis/composer.json index 0557d58b4cc3..72f8b3b717ab 100755 --- a/src/Illuminate/Redis/composer.json +++ b/src/Illuminate/Redis/composer.json @@ -17,7 +17,7 @@ "php": "^7.1.3", "illuminate/contracts": "5.7.*", "illuminate/support": "5.7.*", - "predis/predis": "~1.0" + "predis/predis": "^1.0" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 1e6a554d67db..17179f7a8a6a 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -21,10 +21,10 @@ "illuminate/pipeline": "5.7.*", "illuminate/session": "5.7.*", "illuminate/support": "5.7.*", - "symfony/debug": "~4.0", - "symfony/http-foundation": "~4.0", - "symfony/http-kernel": "~4.0", - "symfony/routing": "~4.0" + "symfony/debug": "^4.1", + "symfony/http-foundation": "^4.1", + "symfony/http-kernel": "^4.1", + "symfony/routing": "^4.1" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index 559125796d0e..7e912c120d9e 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -18,8 +18,8 @@ "illuminate/contracts": "5.7.*", "illuminate/filesystem": "5.7.*", "illuminate/support": "5.7.*", - "symfony/finder": "~4.0", - "symfony/http-foundation": "~4.0" + "symfony/finder": "^4.1", + "symfony/http-foundation": "^4.1" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 74010bab57df..08b2a85bc14b 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -16,7 +16,7 @@ "require": { "php": "^7.1.3", "ext-mbstring": "*", - "doctrine/inflector": "~1.1", + "doctrine/inflector": "^1.1", "illuminate/contracts": "5.7.*", "nesbot/carbon": "^1.24.1" }, @@ -38,8 +38,8 @@ }, "suggest": { "illuminate/filesystem": "Required to use the composer class (5.7.*).", - "symfony/process": "Required to use the composer class (~4.0).", - "symfony/var-dumper": "Required to use the dd function (~4.0)." + "symfony/process": "Required to use the composer class (^4.1).", + "symfony/var-dumper": "Required to use the dd function (^4.1)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index 8c36b8ac224b..4a9da5f2541c 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -19,7 +19,7 @@ "illuminate/contracts": "5.7.*", "illuminate/support": "5.7.*", "illuminate/translation": "5.7.*", - "symfony/http-foundation": "~4.0" + "symfony/http-foundation": "^4.1" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/View/composer.json b/src/Illuminate/View/composer.json index 40585a4a002c..44ecebcca307 100644 --- a/src/Illuminate/View/composer.json +++ b/src/Illuminate/View/composer.json @@ -20,7 +20,7 @@ "illuminate/events": "5.7.*", "illuminate/filesystem": "5.7.*", "illuminate/support": "5.7.*", - "symfony/debug": "~4.0" + "symfony/debug": "^4.1" }, "autoload": { "psr-4": { From f26ee35a0bba37bcb03f59e0f5dd2d40e4885846 Mon Sep 17 00:00:00 2001 From: Vincent Klaiber Date: Sat, 10 Mar 2018 16:49:19 +0100 Subject: [PATCH 0017/2459] [5.7] Add config:clear to optimize command (#23473) * Add config:clear to optimize command https://github.com/laravel/framework/pull/23468#discussion_r173591716 * Update OptimizeClearCommand.php --- src/Illuminate/Foundation/Console/OptimizeClearCommand.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Foundation/Console/OptimizeClearCommand.php b/src/Illuminate/Foundation/Console/OptimizeClearCommand.php index 0fc7d961df83..0bd92dfee368 100644 --- a/src/Illuminate/Foundation/Console/OptimizeClearCommand.php +++ b/src/Illuminate/Foundation/Console/OptimizeClearCommand.php @@ -30,6 +30,7 @@ public function handle() $this->call('view:clear'); $this->call('cache:clear'); $this->call('route:clear'); + $this->call('config:clear'); $this->call('clear-compiled'); $this->info('Caches cleared successfully!'); From c6241441b93113d6c87b83d4e71f7a1d82b2fddc Mon Sep 17 00:00:00 2001 From: Vincent Klaiber Date: Sat, 10 Mar 2018 17:40:19 +0100 Subject: [PATCH 0018/2459] Update suggestion constraints --- composer.json | 28 +++++++++++----------- src/Illuminate/Broadcasting/composer.json | 2 +- src/Illuminate/Console/composer.json | 4 ++-- src/Illuminate/Database/composer.json | 4 ++-- src/Illuminate/Filesystem/composer.json | 8 +++---- src/Illuminate/Mail/composer.json | 4 ++-- src/Illuminate/Notifications/composer.json | 4 ++-- src/Illuminate/Queue/composer.json | 4 ++-- src/Illuminate/Routing/composer.json | 2 +- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/composer.json b/composer.json index a79f84b51891..87d0e20b5837 100644 --- a/composer.json +++ b/composer.json @@ -110,22 +110,22 @@ "suggest": { "ext-pcntl": "Required to use all features of the queue worker.", "ext-posix": "Required to use all features of the queue worker.", - "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).", - "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.6).", - "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", - "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~6.0).", - "laravel/tinker": "Required to use the tinker console command (~1.0).", - "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", - "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", - "league/flysystem-cached-adapter": "Required to use Flysystem caching (~1.0).", - "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (~1.0).", - "nexmo/client": "Required to use the Nexmo transport (~1.0).", - "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", - "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~3.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (^3.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).", + "fzaninotto/faker": "Required to use the eloquent factory builder (^1.4).", + "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (^6.0).", + "laravel/tinker": "Required to use the tinker console command (^1.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", + "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (^1.0).", + "league/flysystem-cached-adapter": "Required to use Flysystem caching (^1.0).", + "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", + "nexmo/client": "Required to use the Nexmo transport (^1.0).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^3.0).", + "predis/predis": "Required to use the redis cache and queue drivers (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^3.0).", "symfony/css-selector": "Required to use some of the crawler integration testing tools (^4.1).", "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (^4.1).", - "symfony/psr-http-message-bridge": "Required to psr7 bridging features (~1.0)." + "symfony/psr-http-message-bridge": "Required to psr7 bridging features (^1.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index dbd60b447828..5e7e5a289d31 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -32,7 +32,7 @@ } }, "suggest": { - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~3.0)." + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^3.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index 95547e5ae952..91ce9743a2ff 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -30,8 +30,8 @@ } }, "suggest": { - "dragonmantank/cron-expression": "Required to use scheduling component (~2.0).", - "guzzlehttp/guzzle": "Required to use the ping methods on schedules (~6.0).", + "dragonmantank/cron-expression": "Required to use scheduling component (^2.0).", + "guzzlehttp/guzzle": "Required to use the ping methods on schedules (^6.0).", "symfony/process": "Required to use scheduling component (^4.1)." }, "config": { diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index 1b22c7aa6e9d..81ef3b478e9a 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -31,8 +31,8 @@ } }, "suggest": { - "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.6).", - "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).", + "fzaninotto/faker": "Required to use the eloquent factory builder (^1.4).", "illuminate/console": "Required to use the database commands (5.7.*).", "illuminate/events": "Required to use the observers with Eloquent (5.7.*).", "illuminate/filesystem": "Required to use the migrations (5.7.*).", diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index 066b9a030f5a..541d330d765a 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -30,10 +30,10 @@ } }, "suggest": { - "league/flysystem": "Required to use the Flysystem local and FTP drivers (~1.0).", - "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", - "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", - "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (~1.0)." + "league/flysystem": "Required to use the Flysystem local and FTP drivers (^1.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", + "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (^1.0).", + "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index 334a7d0046b1..d07f51359de5 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -34,8 +34,8 @@ } }, "suggest": { - "aws/aws-sdk-php": "Required to use the SES mail driver (~3.0).", - "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers (~6.0)." + "aws/aws-sdk-php": "Required to use the SES mail driver (^3.0).", + "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers (^6.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Notifications/composer.json b/src/Illuminate/Notifications/composer.json index 49faf68b129d..e2981644e267 100644 --- a/src/Illuminate/Notifications/composer.json +++ b/src/Illuminate/Notifications/composer.json @@ -36,9 +36,9 @@ } }, "suggest": { - "guzzlehttp/guzzle": "Required to use the Slack transport (~6.0)", + "guzzlehttp/guzzle": "Required to use the Slack transport (^6.0)", "illuminate/database": "Required to use the database transport (5.7.*).", - "nexmo/client": "Required to use the Nexmo transport (~1.0)." + "nexmo/client": "Required to use the Nexmo transport (^1.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index 83a64785590f..ff3376da1332 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -37,9 +37,9 @@ "suggest": { "ext-pcntl": "Required to use all features of the queue worker.", "ext-posix": "Required to use all features of the queue worker.", - "aws/aws-sdk-php": "Required to use the SQS queue driver (~3.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver (^3.0).", "illuminate/redis": "Required to use the Redis queue driver (5.7.*).", - "pda/pheanstalk": "Required to use the Beanstalk queue driver (~3.0)." + "pda/pheanstalk": "Required to use the Beanstalk queue driver (^3.0)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 17179f7a8a6a..e438d41989fb 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -38,7 +38,7 @@ }, "suggest": { "illuminate/console": "Required to use the make commands (5.7.*).", - "symfony/psr-http-message-bridge": "Required to psr7 bridging features (~1.0)." + "symfony/psr-http-message-bridge": "Required to psr7 bridging features (^1.0)." }, "config": { "sort-packages": true From cae41f6ff7ec6897519d055758223608ad117509 Mon Sep 17 00:00:00 2001 From: Michael Dyrynda Date: Mon, 12 Mar 2018 23:57:42 +1030 Subject: [PATCH 0019/2459] [5.7] Make MessageBag constructor behaviour consistent with `add` (#23485) * Make MessageBag constructor behaviour consistent with `add` Addresses laravel/ideas#56 and the (long-closed) #13196. This change in constructor behaviour aims to bring consistency with the public `add` method on the MessageBag class, which would prevent duplicate values in any given MessageBag's key. * update test to show consistency of behaviour --- src/Illuminate/Support/MessageBag.php | 5 +++-- tests/Support/SupportMessageBagTest.php | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/MessageBag.php b/src/Illuminate/Support/MessageBag.php index da2c31e29dbe..41672fe7640c 100755 --- a/src/Illuminate/Support/MessageBag.php +++ b/src/Illuminate/Support/MessageBag.php @@ -34,8 +34,9 @@ class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, Me public function __construct(array $messages = []) { foreach ($messages as $key => $value) { - $this->messages[$key] = $value instanceof Arrayable - ? $value->toArray() : (array) $value; + $value = $value instanceof Arrayable ? $value->toArray() : (array) $value; + + $this->messages[$key] = array_unique($value); } } diff --git a/tests/Support/SupportMessageBagTest.php b/tests/Support/SupportMessageBagTest.php index 1d77c5b37c55..c487345f359c 100755 --- a/tests/Support/SupportMessageBagTest.php +++ b/tests/Support/SupportMessageBagTest.php @@ -298,4 +298,19 @@ public function testGetFormat() $container->setFormat(':message'); $this->assertEquals(':message', $container->getFormat()); } + + public function testConstructorUniquenessConsistency() + { + $messageBag = new MessageBag(['messages' => ['first', 'second', 'third', 'third']]); + $messages = $messageBag->getMessages(); + $this->assertEquals(['first', 'second', 'third'], $messages['messages']); + + $messageBag = new MessageBag; + $messageBag->add('messages', 'first'); + $messageBag->add('messages', 'second'); + $messageBag->add('messages', 'third'); + $messageBag->add('messages', 'third'); + $messages = $messageBag->getMessages(); + $this->assertEquals(['first', 'second', 'third'], $messages['messages']); + } } From 2115cf6274f4da1681311700b12416d637517340 Mon Sep 17 00:00:00 2001 From: Mehdi Esmaeili Date: Tue, 13 Mar 2018 23:58:19 +0330 Subject: [PATCH 0020/2459] Add cursor to ConnectionInterface (#23525) --- src/Illuminate/Database/ConnectionInterface.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/ConnectionInterface.php b/src/Illuminate/Database/ConnectionInterface.php index 9262d6fdfe3e..56127e1c7a5e 100755 --- a/src/Illuminate/Database/ConnectionInterface.php +++ b/src/Illuminate/Database/ConnectionInterface.php @@ -27,18 +27,30 @@ public function raw($value); * * @param string $query * @param array $bindings + * @param bool $useReadPdo * @return mixed */ - public function selectOne($query, $bindings = []); + public function selectOne($query, $bindings = [], $useReadPdo = true); /** * Run a select statement against the database. * * @param string $query * @param array $bindings + * @param bool $useReadPdo * @return array */ - public function select($query, $bindings = []); + public function select($query, $bindings = [], $useReadPdo = true); + + /** + * Run a select statement against the database and returns a generator. + * + * @param string $query + * @param array $bindings + * @param bool $useReadPdo + * @return \Generator + */ + public function cursor($query, $bindings = [], $useReadPdo = true); /** * Run an insert statement against the database. From 7c6ae9ad189febef82e41279937004caa1bd7411 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 13 Mar 2018 16:07:40 -0500 Subject: [PATCH 0021/2459] easier customization of redirect --- .../Auth/AuthenticationException.php | 21 +++++++++++++++++- .../Auth/Middleware/Authenticate.php | 22 +++++++++++++++---- .../Foundation/Exceptions/Handler.php | 2 +- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Auth/AuthenticationException.php b/src/Illuminate/Auth/AuthenticationException.php index 3445b23a0eb5..ef7dbee632c0 100644 --- a/src/Illuminate/Auth/AuthenticationException.php +++ b/src/Illuminate/Auth/AuthenticationException.php @@ -13,18 +13,27 @@ class AuthenticationException extends Exception */ protected $guards; + /** + * The path the user should be redirected to. + * + * @var string + */ + protected $redirectTo; + /** * Create a new authentication exception. * * @param string $message * @param array $guards + * @param string|null $redirectTo * @return void */ - public function __construct($message = 'Unauthenticated.', array $guards = []) + public function __construct($message = 'Unauthenticated.', array $guards = [], $redirectTo = null) { parent::__construct($message); $this->guards = $guards; + $this->redirectTo = $redirectTo; } /** @@ -36,4 +45,14 @@ public function guards() { return $this->guards; } + + /** + * Get the path the user should be redirected to. + * + * @return string + */ + public function redirectTo() + { + return $this->redirectTo; + } } diff --git a/src/Illuminate/Auth/Middleware/Authenticate.php b/src/Illuminate/Auth/Middleware/Authenticate.php index 21ea4b228a2b..88c6462b80c9 100644 --- a/src/Illuminate/Auth/Middleware/Authenticate.php +++ b/src/Illuminate/Auth/Middleware/Authenticate.php @@ -38,7 +38,7 @@ public function __construct(Auth $auth) */ public function handle($request, Closure $next, ...$guards) { - $this->authenticate($guards); + $this->authenticate($request, $guards); return $next($request); } @@ -46,15 +46,16 @@ public function handle($request, Closure $next, ...$guards) /** * Determine if the user is logged in to any of the given guards. * + * @param \Illuminate\Http\Request $request * @param array $guards * @return void * * @throws \Illuminate\Auth\AuthenticationException */ - protected function authenticate(array $guards) + protected function authenticate($request, array $guards) { if (empty($guards)) { - return $this->auth->authenticate(); + $guards = [null]; } foreach ($guards as $guard) { @@ -63,6 +64,19 @@ protected function authenticate(array $guards) } } - throw new AuthenticationException('Unauthenticated.', $guards); + throw new AuthenticationException( + 'Unauthenticated.', $guards, $this->redirectTo($request) + ); + } + + /** + * Get the path the user should be redirected to. + * + * @param \Illuminate\Http\Request $request + * @return string + */ + protected function redirectTo($request) + { + // } } diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index d853e0cc39b8..a594d757053e 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -218,7 +218,7 @@ protected function unauthenticated($request, AuthenticationException $exception) { return $request->expectsJson() ? response()->json(['message' => $exception->getMessage()], 401) - : redirect()->guest(route('login')); + : redirect()->guest($exception->redirectTo() ?? route('login')); } /** From fff247557a6d371f59d3e7c7f3c50baa3371adf2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 13 Mar 2018 16:08:48 -0500 Subject: [PATCH 0022/2459] fix wording --- src/Illuminate/Auth/Middleware/Authenticate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Middleware/Authenticate.php b/src/Illuminate/Auth/Middleware/Authenticate.php index 88c6462b80c9..98b9bc67e182 100644 --- a/src/Illuminate/Auth/Middleware/Authenticate.php +++ b/src/Illuminate/Auth/Middleware/Authenticate.php @@ -70,7 +70,7 @@ protected function authenticate($request, array $guards) } /** - * Get the path the user should be redirected to. + * Get the path the user should be redirected to when they are not authenticated. * * @param \Illuminate\Http\Request $request * @return string From 1fa9459a82fadc5958b0ae1b6b549ed32c0867f8 Mon Sep 17 00:00:00 2001 From: Titas Gailius Date: Wed, 14 Mar 2018 10:55:04 +0200 Subject: [PATCH 0023/2459] Add ArrayAccess "dot notation" support in Request object --- src/Illuminate/Http/Request.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index ce09918d8aa0..533c6116c2d5 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -600,8 +600,8 @@ public function toArray() */ public function offsetExists($offset) { - return array_key_exists( - $offset, $this->all() + $this->route()->parameters() + return Arr::has( + $this->all() + $this->route()->parameters(), $offset ); } @@ -658,10 +658,8 @@ public function __isset($key) */ public function __get($key) { - if (array_key_exists($key, $this->all())) { - return data_get($this->all(), $key); - } - - return $this->route($key); + return Arr::get($this->all(), $key, function () use ($key) { + return $this->route($key); + }); } } From 4e0754d3b9d869c0fd23574ee725c67ac834b2dd Mon Sep 17 00:00:00 2001 From: Titas Gailius Date: Wed, 14 Mar 2018 11:08:31 +0200 Subject: [PATCH 0024/2459] Add ArrayAccess test for Request object --- tests/Http/HttpRequestTest.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index 97c395b0460b..2ea78b66f956 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -325,6 +325,34 @@ public function testInputMethod() $this->assertInstanceOf('Symfony\Component\HttpFoundation\File\UploadedFile', $request['file']); } + public function testArrayAccess() + { + $request = Request::create('/', 'GET', ['name' => null, 'foo' => ['bar' => null, 'baz' => '']]); + $request->setRouteResolver(function () use ($request) { + $route = new Route('GET', '/foo/bar/{id}/{name}', []); + $route->bind($request); + $route->setParameter('id', 'foo'); + $route->setParameter('name', 'Taylor'); + + return $route; + }); + + $this->assertFalse(isset($request['non-existant'])); + $this->assertNull($request['non-existant']); + + $this->assertTrue(isset($request['name'])); + $this->assertEquals(null, $request['name']); + $this->assertNotEquals('Taylor', $request['name']); + + $this->assertTrue(isset($request['foo.bar'])); + $this->assertEquals(null, $request['foo.bar']); + $this->assertTrue(isset($request['foo.baz'])); + $this->assertEquals('', $request['foo.baz']); + + $this->assertTrue(isset($request['id'])); + $this->assertEquals('foo', $request['id']); + } + public function testAllMethod() { $request = Request::create('/', 'GET', ['name' => 'Taylor', 'age' => null]); From 59927d6a28bf1fc384cda4b7820ca4ca0156beba Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 14 Mar 2018 07:16:34 -0500 Subject: [PATCH 0025/2459] formatting --- tests/Http/HttpRequestTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index 2ea78b66f956..f66cb8ca2f6d 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -328,6 +328,7 @@ public function testInputMethod() public function testArrayAccess() { $request = Request::create('/', 'GET', ['name' => null, 'foo' => ['bar' => null, 'baz' => '']]); + $request->setRouteResolver(function () use ($request) { $route = new Route('GET', '/foo/bar/{id}/{name}', []); $route->bind($request); @@ -342,6 +343,7 @@ public function testArrayAccess() $this->assertTrue(isset($request['name'])); $this->assertEquals(null, $request['name']); + $this->assertNotEquals('Taylor', $request['name']); $this->assertTrue(isset($request['foo.bar'])); From ec5764c94ef567fe19644d137e3ce689dd47cdb4 Mon Sep 17 00:00:00 2001 From: Andrew Date: Wed, 14 Mar 2018 07:31:28 -0500 Subject: [PATCH 0026/2459] remove Blade defaults (#23532) current Blade functionality allows the user to define a default value if the first value is not set. `{{ $name or 'Andrew' }}` This feature was added in an early version of Laravel to be a shorthand for `isset($name) ? $name : 'Andrew'` PHP7 has introduced the null coalesce operator (`??`) which performs this exact functionality. `$name ?? 'Andrew'` While the 'or' feature was good when it was needed, it could produce unexpected results when the characters 'or' appeared anywhere in the Blade expression. This was solved with extensive regex, but was still somewhat error prone. Now that Laravel requires PHP 7.1, we can utilize the null coalesce operator and remove the 'or' feature. User upgrade process will be a find and replace, and the number of characters will be identical. ``` {{ $name or 'Andrew' }} {{ $name ?? 'Andrew' }} ``` --- .../View/Compilers/Concerns/CompilesEchos.php | 17 +++--------- tests/View/Blade/BladeEchoTest.php | 26 ------------------- 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesEchos.php b/src/Illuminate/View/Compilers/Concerns/CompilesEchos.php index 018f90b8911e..86f352e21d1e 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesEchos.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesEchos.php @@ -46,7 +46,7 @@ protected function compileRawEchos($value) $callback = function ($matches) { $whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3]; - return $matches[1] ? substr($matches[0], 1) : "compileEchoDefaults($matches[2])}; ?>{$whitespace}"; + return $matches[1] ? substr($matches[0], 1) : "{$whitespace}"; }; return preg_replace_callback($pattern, $callback, $value); @@ -65,7 +65,7 @@ protected function compileRegularEchos($value) $callback = function ($matches) { $whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3]; - $wrapped = sprintf($this->echoFormat, $this->compileEchoDefaults($matches[2])); + $wrapped = sprintf($this->echoFormat, $matches[2]); return $matches[1] ? substr($matches[0], 1) : "{$whitespace}"; }; @@ -86,20 +86,9 @@ protected function compileEscapedEchos($value) $callback = function ($matches) { $whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3]; - return $matches[1] ? $matches[0] : "compileEchoDefaults($matches[2])}); ?>{$whitespace}"; + return $matches[1] ? $matches[0] : "{$whitespace}"; }; return preg_replace_callback($pattern, $callback, $value); } - - /** - * Compile the default values for the echo statement. - * - * @param string $value - * @return string - */ - public function compileEchoDefaults($value) - { - return preg_replace('/^(?=\$)(.+?)(?:\s+or\s+)(.+?)$/si', 'isset($1) ? $1 : $2', $value); - } } diff --git a/tests/View/Blade/BladeEchoTest.php b/tests/View/Blade/BladeEchoTest.php index 3ee43b8c2f27..dc5b3a615d2e 100644 --- a/tests/View/Blade/BladeEchoTest.php +++ b/tests/View/Blade/BladeEchoTest.php @@ -11,8 +11,6 @@ public function testEchosAreCompiled() $this->assertEquals('', $this->compiler->compileString('{!! $name !!}')); - $this->assertEquals('', - $this->compiler->compileString('{!! $name or \'foo\' !!}')); $this->assertEquals('', $this->compiler->compileString('{{{$name}}}')); $this->assertEquals('', $this->compiler->compileString('{{$name}}')); @@ -25,30 +23,6 @@ public function testEchosAreCompiled() $this->assertEquals("\n\n", $this->compiler->compileString("{{ \$name }}\n")); $this->assertEquals("\r\n\r\n", $this->compiler->compileString("{{ \$name }}\r\n")); - $this->assertEquals('', - $this->compiler->compileString('{{ $name or "foo" }}')); - $this->assertEquals('name) ? $user->name : "foo"); ?>', - $this->compiler->compileString('{{ $user->name or "foo" }}')); - $this->assertEquals('', - $this->compiler->compileString('{{$name or "foo"}}')); - $this->assertEquals('', $this->compiler->compileString('{{ - $name or "foo" - }}')); - - $this->assertEquals('', - $this->compiler->compileString('{{ $name or \'foo\' }}')); - $this->assertEquals('', - $this->compiler->compileString('{{$name or \'foo\'}}')); - $this->assertEquals('', $this->compiler->compileString('{{ - $name or \'foo\' - }}')); - - $this->assertEquals('', $this->compiler->compileString('{{ $age or 90 }}')); - $this->assertEquals('', $this->compiler->compileString('{{$age or 90}}')); - $this->assertEquals('', $this->compiler->compileString('{{ - $age or 90 - }}')); - $this->assertEquals('', $this->compiler->compileString('{{ "Hello world or foo" }}')); $this->assertEquals('', From 4ac043bfadc09dd04af23d4553a13336eaba7aed Mon Sep 17 00:00:00 2001 From: Marcus Frolander Date: Fri, 16 Mar 2018 17:06:47 +0100 Subject: [PATCH 0027/2459] Add connection parameter to job scheduling (#23576) Currently, jobs scheduled via console scheduling can not specify a connection to dispatch that job onto. They can specify a queue. This PR adds an optional connection parameter to the end of the job function. --- src/Illuminate/Console/Scheduling/Schedule.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Schedule.php b/src/Illuminate/Console/Scheduling/Schedule.php index be99741fcf0f..746456fc6a04 100644 --- a/src/Illuminate/Console/Scheduling/Schedule.php +++ b/src/Illuminate/Console/Scheduling/Schedule.php @@ -90,13 +90,13 @@ public function command($command, array $parameters = []) * @param string|null $queue * @return \Illuminate\Console\Scheduling\CallbackEvent */ - public function job($job, $queue = null) + public function job($job, $queue = null, $connection = null) { - return $this->call(function () use ($job, $queue) { + return $this->call(function () use ($job, $queue, $connection) { $job = is_string($job) ? resolve($job) : $job; if ($job instanceof ShouldQueue) { - dispatch($job)->onQueue($queue); + dispatch($job)->onConnection($connection)->onQueue($queue); } else { dispatch_now($job); } From 17f93cb07cd021347f068037957d3f055cf0f785 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 17 Mar 2018 11:13:29 +0000 Subject: [PATCH 0028/2459] Fixed phpdoc of the schedule class --- src/Illuminate/Console/Scheduling/Schedule.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Scheduling/Schedule.php b/src/Illuminate/Console/Scheduling/Schedule.php index 746456fc6a04..06718b1850ee 100644 --- a/src/Illuminate/Console/Scheduling/Schedule.php +++ b/src/Illuminate/Console/Scheduling/Schedule.php @@ -53,7 +53,7 @@ public function __construct() * Add a new callback event to the schedule. * * @param string|callable $callback - * @param array $parameters + * @param array $parameters * @return \Illuminate\Console\Scheduling\CallbackEvent */ public function call($callback, array $parameters = []) @@ -88,6 +88,7 @@ public function command($command, array $parameters = []) * * @param object|string $job * @param string|null $queue + * @param string|null $connection * @return \Illuminate\Console\Scheduling\CallbackEvent */ public function job($job, $queue = null, $connection = null) From ecacc09cf42823835c517b3c7d3c14934cd197a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kru=CC=88ss?= Date: Sun, 18 Mar 2018 08:54:57 -0700 Subject: [PATCH 0029/2459] =?UTF-8?q?add=20Redis=20=E2=80=9CQueryExecuted?= =?UTF-8?q?=E2=80=9D=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Testing/Concerns/InteractsWithRedis.php | 4 +- .../Redis/Connections/Connection.php | 76 ++++++++++++++++++- src/Illuminate/Redis/Events/QueryExecuted.php | 59 ++++++++++++++ src/Illuminate/Redis/RedisManager.php | 34 ++++++++- src/Illuminate/Redis/RedisServiceProvider.php | 2 +- tests/Redis/RedisConnectionTest.php | 27 ++++++- 6 files changed, 196 insertions(+), 6 deletions(-) create mode 100644 src/Illuminate/Redis/Events/QueryExecuted.php diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithRedis.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithRedis.php index 4a18aec289ae..10dac7191215 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithRedis.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithRedis.php @@ -3,6 +3,7 @@ namespace Illuminate\Foundation\Testing\Concerns; use Illuminate\Redis\RedisManager; +use Illuminate\Foundation\Application; trait InteractsWithRedis { @@ -27,6 +28,7 @@ trait InteractsWithRedis */ public function setUpRedis() { + $app = $this->app ?? new Application; $host = getenv('REDIS_HOST') ?: '127.0.0.1'; $port = getenv('REDIS_PORT') ?: 6379; @@ -37,7 +39,7 @@ public function setUpRedis() } foreach ($this->redisDriverProvider() as $driver) { - $this->redis[$driver[0]] = new RedisManager($driver[0], [ + $this->redis[$driver[0]] = new RedisManager($app, $driver[0], [ 'cluster' => false, 'default' => [ 'host' => $host, diff --git a/src/Illuminate/Redis/Connections/Connection.php b/src/Illuminate/Redis/Connections/Connection.php index 33916e19a0b6..47b998557220 100644 --- a/src/Illuminate/Redis/Connections/Connection.php +++ b/src/Illuminate/Redis/Connections/Connection.php @@ -3,6 +3,8 @@ namespace Illuminate\Redis\Connections; use Closure; +use Illuminate\Redis\Events\QueryExecuted; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Redis\Limiters\DurationLimiterBuilder; use Illuminate\Redis\Limiters\ConcurrencyLimiterBuilder; @@ -18,6 +20,13 @@ abstract class Connection */ protected $client; + /** + * The event dispatcher instance. + * + * @var \Illuminate\Contracts\Events\Dispatcher + */ + protected $events; + /** * The Redis connection name. * @@ -100,7 +109,41 @@ public function psubscribe($channels, Closure $callback) */ public function command($method, array $parameters = []) { - return $this->client->{$method}(...$parameters); + $start = microtime(true); + $result = $this->client->{$method}(...$parameters); + $time = round((microtime(true) - $start) * 1000, 2); + + if (isset($this->events)) { + $this->event(new QueryExecuted($method, $parameters, $time, $this)); + } + + return $result; + } + + /** + * Fire the given event if possible. + * + * @param mixed $event + * @return void + */ + protected function event($event) + { + if (isset($this->events)) { + $this->events->dispatch($event); + } + } + + /** + * Register a Redis query listener with the connection. + * + * @param \Closure $callback + * @return void + */ + public function listen(Closure $callback) + { + if (isset($this->events)) { + $this->events->listen(QueryExecuted::class, $callback); + } } /** @@ -126,6 +169,37 @@ public function setName($name) return $this; } + /** + * Get the event dispatcher used by the connection. + * + * @return \Illuminate\Contracts\Events\Dispatcher + */ + public function getEventDispatcher() + { + return $this->events; + } + + /** + * Set the event dispatcher instance on the connection. + * + * @param \Illuminate\Contracts\Events\Dispatcher $events + * @return void + */ + public function setEventDispatcher(Dispatcher $events) + { + $this->events = $events; + } + + /** + * Unset the event dispatcher instance on the connection. + * + * @return void + */ + public function unsetEventDispatcher() + { + $this->events = null; + } + /** * Pass other method calls down to the underlying client. * diff --git a/src/Illuminate/Redis/Events/QueryExecuted.php b/src/Illuminate/Redis/Events/QueryExecuted.php new file mode 100644 index 000000000000..7bdc59435b66 --- /dev/null +++ b/src/Illuminate/Redis/Events/QueryExecuted.php @@ -0,0 +1,59 @@ +time = $time; + $this->command = $command; + $this->parameters = $parameters; + $this->connection = $connection; + $this->connectionName = $connection->getName(); + } +} diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index a3ced3696179..2db368973113 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -4,12 +4,20 @@ use InvalidArgumentException; use Illuminate\Contracts\Redis\Factory; +use Illuminate\Redis\Connections\Connection; /** * @mixin \Illuminate\Redis\Connections\Connection */ class RedisManager implements Factory { + /** + * The application instance. + * + * @var \Illuminate\Foundation\Application + */ + protected $app; + /** * The name of the default driver. * @@ -34,12 +42,14 @@ class RedisManager implements Factory /** * Create a new Redis manager instance. * + * @param \Illuminate\Foundation\Application $app * @param string $driver * @param array $config * @return void */ - public function __construct($driver, array $config) + public function __construct($app, $driver, array $config) { + $this->app = $app; $this->driver = $driver; $this->config = $config; } @@ -58,7 +68,9 @@ public function connection($name = null) return $this->connections[$name]; } - return $this->connections[$name] = $this->resolve($name)->setName($name); + return $this->connections[$name] = $this->configure( + $this->resolve($name), $name + ); } /** @@ -101,6 +113,24 @@ protected function resolveCluster($name) ); } + /** + * Get the connector instance for the current driver. + * + * @param \Illuminate\Redis\Connections\Connection $connection + * @param string $name + * @return \Illuminate\Redis\Connections\Connection + */ + protected function configure(Connection $connection, $name) + { + $connection->setName($name); + + if ($this->app->bound('events')) { + $connection->setEventDispatcher($this->app['events']); + } + + return $connection; + } + /** * Get the connector instance for the current driver. * diff --git a/src/Illuminate/Redis/RedisServiceProvider.php b/src/Illuminate/Redis/RedisServiceProvider.php index 20d78e603592..eb2cd6a97474 100755 --- a/src/Illuminate/Redis/RedisServiceProvider.php +++ b/src/Illuminate/Redis/RedisServiceProvider.php @@ -24,7 +24,7 @@ public function register() $this->app->singleton('redis', function ($app) { $config = $app->make('config')->get('database.redis'); - return new RedisManager(Arr::pull($config, 'client', 'predis'), $config); + return new RedisManager($app, Arr::pull($config, 'client', 'predis'), $config); }); $this->app->bind('redis.connection', function ($app) { diff --git a/tests/Redis/RedisConnectionTest.php b/tests/Redis/RedisConnectionTest.php index 9226787abc98..00bbcfdee2e2 100644 --- a/tests/Redis/RedisConnectionTest.php +++ b/tests/Redis/RedisConnectionTest.php @@ -2,8 +2,10 @@ namespace Illuminate\Tests\Redis; +use Mockery as m; use PHPUnit\Framework\TestCase; use Illuminate\Redis\RedisManager; +use Illuminate\Foundation\Application; use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis; class RedisConnectionTest extends TestCase @@ -573,6 +575,29 @@ public function it_runs_raw_command() } } + /** + * @test + */ + public function it_dispatches_query_event() + { + foreach ($this->connections() as $redis) { + $redis->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher')); + + $events->shouldReceive('dispatch')->once()->with(m::on(function ($event) { + $this->assertEquals('get', $event->command); + $this->assertEquals(['foobar'], $event->parameters); + $this->assertEquals('default', $event->connectionName); + $this->assertInstanceOf('\Illuminate\Redis\Connections\Connection', $event->connection); + + return true; + })); + + $redis->get('foobar'); + + $redis->unsetEventDispatcher(); + } + } + public function connections() { $connections = [ @@ -584,7 +609,7 @@ public function connections() $host = getenv('REDIS_HOST') ?: '127.0.0.1'; $port = getenv('REDIS_PORT') ?: 6379; - $prefixedPhpredis = new RedisManager('phpredis', [ + $prefixedPhpredis = new RedisManager(new Application, 'phpredis', [ 'cluster' => false, 'default' => [ 'host' => $host, From 75b3ec65c2a56b7cc243db84fe33f7d3d0a34289 Mon Sep 17 00:00:00 2001 From: Victor Isadov Date: Mon, 19 Mar 2018 19:17:19 +0300 Subject: [PATCH 0030/2459] Using full Yes / No in migrate:status command (#23616) --- src/Illuminate/Database/Console/Migrations/StatusCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Console/Migrations/StatusCommand.php b/src/Illuminate/Database/Console/Migrations/StatusCommand.php index 93ed51a7e019..53168a1019f5 100644 --- a/src/Illuminate/Database/Console/Migrations/StatusCommand.php +++ b/src/Illuminate/Database/Console/Migrations/StatusCommand.php @@ -80,8 +80,8 @@ protected function getStatusFor(array $ran, array $batches) $migrationName = $this->migrator->getMigrationName($migration); return in_array($migrationName, $ran) - ? ['Y', $migrationName, $batches[$migrationName]] - : ['N', $migrationName]; + ? ['Yes', $migrationName, $batches[$migrationName]] + : ['No', $migrationName]; }); } From dc642c83da7b4112714ce4c9ab33483b5799c657 Mon Sep 17 00:00:00 2001 From: AaronJan Date: Tue, 20 Mar 2018 00:21:00 +0800 Subject: [PATCH 0031/2459] fix phpdoc (#23609) --- src/Illuminate/Queue/Queue.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index b9b8461cb309..bf50317b1fa0 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -98,8 +98,8 @@ protected function createPayload($job, $data = '') /** * Create a payload array from the given job and data. * - * @param string $job - * @param mixed $data + * @param mixed $job + * @param mixed $data * @return array */ protected function createPayloadArray($job, $data = '') From eda7add72e5cd550367dbd864431fc640f3bd8c7 Mon Sep 17 00:00:00 2001 From: Gary Green Date: Tue, 20 Mar 2018 01:46:12 +0000 Subject: [PATCH 0032/2459] Update various blade array_ calls to use fully qualified Arr helper (#23619) * Update various blade array_ calls to use fully qualified Arr helper * Fix tests --- src/Illuminate/View/Compilers/BladeCompiler.php | 6 +++--- .../View/Compilers/Concerns/CompilesIncludes.php | 8 ++++---- .../View/Compilers/Concerns/CompilesLayouts.php | 2 +- tests/View/Blade/BladeCustomTest.php | 8 ++++---- tests/View/Blade/BladeExtendsTest.php | 8 ++++---- tests/View/Blade/BladeIncludeFirstTest.php | 4 ++-- tests/View/Blade/BladeIncludeIfTest.php | 4 ++-- tests/View/Blade/BladeIncludeTest.php | 4 ++-- tests/View/Blade/BladeIncludeWhenTest.php | 4 ++-- tests/View/Blade/BladeVerbatimTest.php | 2 +- tests/View/fixtures/section-exception.php | 2 +- 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index f53bf1fc013b..b78727cb31ba 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -433,7 +433,7 @@ public function check($name, ...$parameters) */ public function component($path, $alias = null) { - $alias = $alias ?: array_last(explode('.', $path)); + $alias = $alias ?: Arr::last(explode('.', $path)); $this->directive($alias, function ($expression) use ($path) { return $expression @@ -455,12 +455,12 @@ public function component($path, $alias = null) */ public function include($path, $alias = null) { - $alias = $alias ?: array_last(explode('.', $path)); + $alias = $alias ?: Arr::last(explode('.', $path)); $this->directive($alias, function ($expression) use ($path) { $expression = $this->stripParentheses($expression) ?: '[]'; - return "make('{$path}', {$expression}, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; + return "make('{$path}', {$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; }); } diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesIncludes.php b/src/Illuminate/View/Compilers/Concerns/CompilesIncludes.php index 417d4ef66801..0a310cebdbd1 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesIncludes.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesIncludes.php @@ -25,7 +25,7 @@ protected function compileInclude($expression) { $expression = $this->stripParentheses($expression); - return "make({$expression}, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; + return "make({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; } /** @@ -38,7 +38,7 @@ protected function compileIncludeIf($expression) { $expression = $this->stripParentheses($expression); - return "exists({$expression})) echo \$__env->make({$expression}, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; + return "exists({$expression})) echo \$__env->make({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; } /** @@ -51,7 +51,7 @@ protected function compileIncludeWhen($expression) { $expression = $this->stripParentheses($expression); - return "renderWhen($expression, array_except(get_defined_vars(), array('__data', '__path'))); ?>"; + return "renderWhen($expression, \Illuminate\Support\Arr::except(get_defined_vars(), array('__data', '__path'))); ?>"; } /** @@ -64,6 +64,6 @@ protected function compileIncludeFirst($expression) { $expression = $this->stripParentheses($expression); - return "first({$expression}, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; + return "first({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; } } diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesLayouts.php b/src/Illuminate/View/Compilers/Concerns/CompilesLayouts.php index 329a7055d06f..67429c7f4fa9 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesLayouts.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesLayouts.php @@ -23,7 +23,7 @@ protected function compileExtends($expression) { $expression = $this->stripParentheses($expression); - $echo = "make({$expression}, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; + $echo = "make({$expression}, \Illuminate\Support\Arr::except(get_defined_vars(), array('__data', '__path')))->render(); ?>"; $this->footer[] = $echo; diff --git a/tests/View/Blade/BladeCustomTest.php b/tests/View/Blade/BladeCustomTest.php index c68fd5d759bf..859f4fb76947 100644 --- a/tests/View/Blade/BladeCustomTest.php +++ b/tests/View/Blade/BladeCustomTest.php @@ -140,7 +140,7 @@ public function testCustomIncludes() $this->compiler->include('app.includes.input', 'input'); $string = '@input'; - $expected = 'make(\'app.includes.input\', [], array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; + $expected = 'make(\'app.includes.input\', [], \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); } @@ -149,7 +149,7 @@ public function testCustomIncludesWithData() $this->compiler->include('app.includes.input', 'input'); $string = '@input([\'type\' => \'email\'])'; - $expected = 'make(\'app.includes.input\', [\'type\' => \'email\'], array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; + $expected = 'make(\'app.includes.input\', [\'type\' => \'email\'], \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); } @@ -158,7 +158,7 @@ public function testCustomIncludesDefaultAlias() $this->compiler->include('app.includes.input'); $string = '@input'; - $expected = 'make(\'app.includes.input\', [], array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; + $expected = 'make(\'app.includes.input\', [], \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); } @@ -167,7 +167,7 @@ public function testCustomIncludesWithExistingDirective() $this->compiler->include('app.includes.foreach'); $string = '@foreach'; - $expected = 'make(\'app.includes.foreach\', [], array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; + $expected = 'make(\'app.includes.foreach\', [], \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); } } diff --git a/tests/View/Blade/BladeExtendsTest.php b/tests/View/Blade/BladeExtendsTest.php index f6131b93212c..efee088f425a 100644 --- a/tests/View/Blade/BladeExtendsTest.php +++ b/tests/View/Blade/BladeExtendsTest.php @@ -8,11 +8,11 @@ public function testExtendsAreCompiled() { $string = '@extends(\'foo\') test'; - $expected = 'test'.PHP_EOL.'make(\'foo\', array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; + $expected = 'test'.PHP_EOL.'make(\'foo\', \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); $string = '@extends(name(foo))'.PHP_EOL.'test'; - $expected = 'test'.PHP_EOL.'make(name(foo), array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; + $expected = 'test'.PHP_EOL.'make(name(foo), \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); } @@ -20,12 +20,12 @@ public function testSequentialCompileStringCalls() { $string = '@extends(\'foo\') test'; - $expected = 'test'.PHP_EOL.'make(\'foo\', array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; + $expected = 'test'.PHP_EOL.'make(\'foo\', \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); // use the same compiler instance to compile another template with @extends directive $string = '@extends(name(foo))'.PHP_EOL.'test'; - $expected = 'test'.PHP_EOL.'make(name(foo), array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; + $expected = 'test'.PHP_EOL.'make(name(foo), \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>'; $this->assertEquals($expected, $this->compiler->compileString($string)); } } diff --git a/tests/View/Blade/BladeIncludeFirstTest.php b/tests/View/Blade/BladeIncludeFirstTest.php index f8917fbd9022..76ad61c1ef28 100644 --- a/tests/View/Blade/BladeIncludeFirstTest.php +++ b/tests/View/Blade/BladeIncludeFirstTest.php @@ -6,7 +6,7 @@ class BladeIncludeFirstTest extends AbstractBladeTestCase { public function testIncludeFirstsAreCompiled() { - $this->assertEquals('first(["one", "two"], array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@includeFirst(["one", "two"])')); - $this->assertEquals('first(["one", "two"], ["foo" => "bar"], array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@includeFirst(["one", "two"], ["foo" => "bar"])')); + $this->assertEquals('first(["one", "two"], \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@includeFirst(["one", "two"])')); + $this->assertEquals('first(["one", "two"], ["foo" => "bar"], \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@includeFirst(["one", "two"], ["foo" => "bar"])')); } } diff --git a/tests/View/Blade/BladeIncludeIfTest.php b/tests/View/Blade/BladeIncludeIfTest.php index cff64f832842..45630aaaf55e 100644 --- a/tests/View/Blade/BladeIncludeIfTest.php +++ b/tests/View/Blade/BladeIncludeIfTest.php @@ -6,7 +6,7 @@ class BladeIncludeIfTest extends AbstractBladeTestCase { public function testIncludeIfsAreCompiled() { - $this->assertEquals('exists(\'foo\')) echo $__env->make(\'foo\', array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@includeIf(\'foo\')')); - $this->assertEquals('exists(name(foo))) echo $__env->make(name(foo), array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@includeIf(name(foo))')); + $this->assertEquals('exists(\'foo\')) echo $__env->make(\'foo\', \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@includeIf(\'foo\')')); + $this->assertEquals('exists(name(foo))) echo $__env->make(name(foo), \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@includeIf(name(foo))')); } } diff --git a/tests/View/Blade/BladeIncludeTest.php b/tests/View/Blade/BladeIncludeTest.php index 093032117629..e723b5d0c7d6 100644 --- a/tests/View/Blade/BladeIncludeTest.php +++ b/tests/View/Blade/BladeIncludeTest.php @@ -6,7 +6,7 @@ class BladeIncludeTest extends AbstractBladeTestCase { public function testIncludesAreCompiled() { - $this->assertEquals('make(\'foo\', array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@include(\'foo\')')); - $this->assertEquals('make(name(foo), array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@include(name(foo))')); + $this->assertEquals('make(\'foo\', \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@include(\'foo\')')); + $this->assertEquals('make(name(foo), \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?>', $this->compiler->compileString('@include(name(foo))')); } } diff --git a/tests/View/Blade/BladeIncludeWhenTest.php b/tests/View/Blade/BladeIncludeWhenTest.php index b7cf6f171cb3..4b7a4e47385c 100644 --- a/tests/View/Blade/BladeIncludeWhenTest.php +++ b/tests/View/Blade/BladeIncludeWhenTest.php @@ -6,7 +6,7 @@ class BladeIncludeWhenTest extends AbstractBladeTestCase { public function testIncludeWhensAreCompiled() { - $this->assertEquals('renderWhen(true, \'foo\', ["foo" => "bar"], array_except(get_defined_vars(), array(\'__data\', \'__path\'))); ?>', $this->compiler->compileString('@includeWhen(true, \'foo\', ["foo" => "bar"])')); - $this->assertEquals('renderWhen(true, \'foo\', array_except(get_defined_vars(), array(\'__data\', \'__path\'))); ?>', $this->compiler->compileString('@includeWhen(true, \'foo\')')); + $this->assertEquals('renderWhen(true, \'foo\', ["foo" => "bar"], \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\'))); ?>', $this->compiler->compileString('@includeWhen(true, \'foo\', ["foo" => "bar"])')); + $this->assertEquals('renderWhen(true, \'foo\', \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\'))); ?>', $this->compiler->compileString('@includeWhen(true, \'foo\')')); } } diff --git a/tests/View/Blade/BladeVerbatimTest.php b/tests/View/Blade/BladeVerbatimTest.php index 849714c87ab0..d1101c93988f 100644 --- a/tests/View/Blade/BladeVerbatimTest.php +++ b/tests/View/Blade/BladeVerbatimTest.php @@ -70,7 +70,7 @@ public function testMultilineTemplatesWithRawBlocksAreRenderedInTheRightOrder() -make("users", array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?> +make("users", \Illuminate\Support\Arr::except(get_defined_vars(), array(\'__data\', \'__path\')))->render(); ?> {{ $fourth }} @include("test") diff --git a/tests/View/fixtures/section-exception.php b/tests/View/fixtures/section-exception.php index 13a8c901cc46..e073d1228e78 100644 --- a/tests/View/fixtures/section-exception.php +++ b/tests/View/fixtures/section-exception.php @@ -1,4 +1,4 @@ -make('layout', array_except(get_defined_vars(), ['__data', '__path']))->render(); ?> +make('layout', \Illuminate\Support\Arr::except(get_defined_vars(), ['__data', '__path']))->render(); ?> startSection('content'); ?> stopSection(); ?> From b38b67acf02171a6aeb2bea306fe01dabefe5063 Mon Sep 17 00:00:00 2001 From: Sije Harkema Date: Tue, 20 Mar 2018 16:36:07 +0100 Subject: [PATCH 0033/2459] [5.7] Make Filesystem contract in line with Flysystem (#23629) * Be in line with Flysystem contract * Be in line with Flysystem --- src/Illuminate/Contracts/Filesystem/Filesystem.php | 2 +- src/Illuminate/Filesystem/FilesystemAdapter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Contracts/Filesystem/Filesystem.php b/src/Illuminate/Contracts/Filesystem/Filesystem.php index 69a189c125b8..8ada2003b56d 100644 --- a/src/Illuminate/Contracts/Filesystem/Filesystem.php +++ b/src/Illuminate/Contracts/Filesystem/Filesystem.php @@ -59,7 +59,7 @@ public function getVisibility($path); * * @param string $path * @param string $visibility - * @return void + * @return bool */ public function setVisibility($path, $visibility); diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index 679d269708ce..e9abcc7519d3 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -240,7 +240,7 @@ public function getVisibility($path) * * @param string $path * @param string $visibility - * @return void + * @return bool */ public function setVisibility($path, $visibility) { From d7d4cc892f61ff1a0ca8364f768ee54967d3214c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kru=CC=88ss?= Date: Tue, 20 Mar 2018 16:42:13 -0700 Subject: [PATCH 0034/2459] allow Redis events to be disabled --- src/Illuminate/Redis/RedisManager.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index 2db368973113..06f0bddfc3e4 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -39,6 +39,13 @@ class RedisManager implements Factory */ protected $connections; + /** + * Whether or not event dispatcher is set on connections. + * + * @var bool + */ + protected $events = true; + /** * Create a new Redis manager instance. * @@ -124,7 +131,7 @@ protected function configure(Connection $connection, $name) { $connection->setName($name); - if ($this->app->bound('events')) { + if ($this->events && $this->app->bound('events')) { $connection->setEventDispatcher($this->app['events']); } @@ -156,6 +163,16 @@ public function connections() return $this->connections; } + /** + * Disable setting event dispatcher on connections. + * + * @return array + */ + public function disableEvents() + { + return $this->events = false; + } + /** * Pass methods onto the default Redis connection. * From 585fb2c322975a11acd4394653928802773e5c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kr=C3=BCss?= Date: Tue, 20 Mar 2018 16:45:10 -0700 Subject: [PATCH 0035/2459] update comment --- src/Illuminate/Redis/RedisManager.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index 06f0bddfc3e4..24df6ceb230f 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -40,7 +40,7 @@ class RedisManager implements Factory protected $connections; /** - * Whether or not event dispatcher is set on connections. + * Indicates whether event dispatcher is set on connections. * * @var bool */ @@ -164,6 +164,16 @@ public function connections() } /** + * Enable setting event dispatcher on connections. + * + * @return array + */ + public function enableEvents() + { + return $this->events = true; + } + + /** * Disable setting event dispatcher on connections. * * @return array From 47db16381f3a575c811318f25039e392709267eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kr=C3=BCss?= Date: Tue, 20 Mar 2018 16:51:06 -0700 Subject: [PATCH 0036/2459] fix styling --- src/Illuminate/Redis/RedisManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index 24df6ceb230f..d2f90736aa39 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -173,7 +173,7 @@ public function enableEvents() return $this->events = true; } - /** + /** * Disable setting event dispatcher on connections. * * @return array From ba0f3729a17978f6d263a28592c247232170816b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kr=C3=BCss?= Date: Tue, 20 Mar 2018 16:52:51 -0700 Subject: [PATCH 0037/2459] spaces --- src/Illuminate/Redis/RedisManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index d2f90736aa39..4516fe91ad9c 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -172,7 +172,7 @@ public function enableEvents() { return $this->events = true; } - + /** * Disable setting event dispatcher on connections. * From ab83fb9ebbfb0d8d7afb09ddf0daac82c8c13c80 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 21 Mar 2018 01:12:22 +0200 Subject: [PATCH 0038/2459] [5.7] Allow to disable `CREATED_AT`. (cherry picked from commit 273b7fc) --- src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php b/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php index ce3e0801dee6..a9077058f584 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php @@ -42,7 +42,7 @@ protected function updateTimestamps() $this->setUpdatedAt($time); } - if (! $this->exists && ! $this->isDirty(static::CREATED_AT)) { + if (! $this->exists && ! is_null(static::CREATED_AT) && ! $this->isDirty(static::CREATED_AT)) { $this->setCreatedAt($time); } } From 0ab2566d510933b46408d563c9d82b7321efeb0b Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 21 Mar 2018 21:15:37 +0200 Subject: [PATCH 0039/2459] [5.7] add unit tests for CREATED_AT and UPDATED_AT disabling. (cherry picked from commit e856976) --- tests/Database/DatabaseEloquentTimestamps.php | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 tests/Database/DatabaseEloquentTimestamps.php diff --git a/tests/Database/DatabaseEloquentTimestamps.php b/tests/Database/DatabaseEloquentTimestamps.php new file mode 100644 index 000000000000..c2b817964e2a --- /dev/null +++ b/tests/Database/DatabaseEloquentTimestamps.php @@ -0,0 +1,152 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->bootEloquent(); + $db->setAsGlobal(); + + $this->createSchema(); + } + + /** + * Setup the database schema. + * + * @return void + */ + public function createSchema() + { + $this->schema()->create('users', function ($table) { + $table->increments('id'); + $table->string('email')->unique(); + $table->timestamps(); + }); + + $this->schema()->create('users_created_at', function ($table) { + $table->increments('id'); + $table->string('email')->unique(); + $table->string('created_at'); + }); + + $this->schema()->create('users_updated_at', function ($table) { + $table->increments('id'); + $table->string('email')->unique(); + $table->string('updated_at'); + }); + } + + /** + * Tear down the database schema. + * + * @return void + */ + public function tearDown() + { + $this->schema()->drop('users'); + $this->schema()->drop('users_created_at'); + $this->schema()->drop('users_updated_at'); + } + + /** + * Tests... + */ + public function testUserWithCreatedAtAndUpdatedAt() + { + $now = Carbon::now(); + $user = UserWithCreatedAndUpdated::create([ + 'email' => 'test@test.com', + ]); + + $this->assertEquals($now->toDateTimeString(), $user->created_at->toDateTimeString()); + $this->assertEquals($now->toDateTimeString(), $user->updated_at->toDateTimeString()); + } + + + public function testUserWithCreatedAt() + { + $now = Carbon::now(); + $user = UserWithCreated::create([ + 'email' => 'test@test.com', + ]); + + $this->assertEquals($now->toDateTimeString(), $user->created_at->toDateTimeString()); + } + + public function testUserWithUpdatedAt() + { + $now = Carbon::now(); + $user = UserWithUpdated::create([ + 'email' => 'test@test.com', + ]); + + $this->assertEquals($now->toDateTimeString(), $user->updated_at->toDateTimeString()); + } + + /** + * Get a database connection instance. + * + * @return Connection + */ + protected function connection() + { + return Eloquent::getConnectionResolver()->connection(); + } + + /** + * Get a schema builder instance. + * + * @return Schema\Builder + */ + protected function schema() + { + return $this->connection()->getSchemaBuilder(); + } +} + +/** + * Eloquent Models... + */ +class UserWithCreatedAndUpdated extends Eloquent +{ + protected $table = 'users'; + + protected $guarded = []; +} + +class UserWithCreated extends Eloquent +{ + public const UPDATED_AT = null; + + protected $table = 'users_created_at'; + + protected $guarded = []; + + protected $dateFormat = 'U'; +} + +class UserWithUpdated extends Eloquent +{ + public const CREATED_AT = null; + + protected $table = 'users_updated_at'; + + protected $guarded = []; + + protected $dateFormat = 'U'; +} From 603ae0f6f4fbe505f1723beb53ee8d79c539018a Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 21 Mar 2018 14:44:28 -0700 Subject: [PATCH 0040/2459] formatting --- src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php b/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php index a9077058f584..8e3d488edd2d 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php @@ -42,7 +42,8 @@ protected function updateTimestamps() $this->setUpdatedAt($time); } - if (! $this->exists && ! is_null(static::CREATED_AT) && ! $this->isDirty(static::CREATED_AT)) { + if (! $this->exists && ! is_null(static::CREATED_AT) && + ! $this->isDirty(static::CREATED_AT)) { $this->setCreatedAt($time); } } From 74cf20355da753b3b9baf15ab2a1ad49d6d21e52 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 21 Mar 2018 14:44:53 -0700 Subject: [PATCH 0041/2459] Apply fixes from StyleCI (#23649) --- tests/Database/DatabaseEloquentTimestamps.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/Database/DatabaseEloquentTimestamps.php b/tests/Database/DatabaseEloquentTimestamps.php index c2b817964e2a..927639a223f4 100644 --- a/tests/Database/DatabaseEloquentTimestamps.php +++ b/tests/Database/DatabaseEloquentTimestamps.php @@ -2,11 +2,11 @@ namespace Illuminate\Tests\Database; -use Illuminate\Database\Capsule\Manager as DB; -use Illuminate\Database\Connection; -use Illuminate\Database\Eloquent\Model as Eloquent; use Illuminate\Support\Carbon; use PHPUnit\Framework\TestCase; +use Illuminate\Database\Connection; +use Illuminate\Database\Capsule\Manager as DB; +use Illuminate\Database\Eloquent\Model as Eloquent; class DatabaseEloquentTimestamps extends TestCase { @@ -77,7 +77,6 @@ public function testUserWithCreatedAtAndUpdatedAt() $this->assertEquals($now->toDateTimeString(), $user->updated_at->toDateTimeString()); } - public function testUserWithCreatedAt() { $now = Carbon::now(); From b14cfc9966572cf7b61e05a433947895cfddef2a Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 26 Mar 2018 08:38:51 -0500 Subject: [PATCH 0042/2459] formatting --- .../Redis/Connections/Connection.php | 22 ++++++++++--------- ...{QueryExecuted.php => CommandExecuted.php} | 6 ++--- src/Illuminate/Redis/RedisManager.php | 18 +++++++-------- 3 files changed, 24 insertions(+), 22 deletions(-) rename src/Illuminate/Redis/Events/{QueryExecuted.php => CommandExecuted.php} (89%) diff --git a/src/Illuminate/Redis/Connections/Connection.php b/src/Illuminate/Redis/Connections/Connection.php index 47b998557220..e09c2033e026 100644 --- a/src/Illuminate/Redis/Connections/Connection.php +++ b/src/Illuminate/Redis/Connections/Connection.php @@ -3,8 +3,8 @@ namespace Illuminate\Redis\Connections; use Closure; -use Illuminate\Redis\Events\QueryExecuted; use Illuminate\Contracts\Events\Dispatcher; +use Illuminate\Redis\Events\CommandExecuted; use Illuminate\Redis\Limiters\DurationLimiterBuilder; use Illuminate\Redis\Limiters\ConcurrencyLimiterBuilder; @@ -21,18 +21,18 @@ abstract class Connection protected $client; /** - * The event dispatcher instance. + * The Redis connection name. * - * @var \Illuminate\Contracts\Events\Dispatcher + * @var string|null */ - protected $events; + protected $name; /** - * The Redis connection name. + * The event dispatcher instance. * - * @var string|null + * @var \Illuminate\Contracts\Events\Dispatcher */ - protected $name; + protected $events; /** * Subscribe to a set of given channels for messages. @@ -110,11 +110,13 @@ public function psubscribe($channels, Closure $callback) public function command($method, array $parameters = []) { $start = microtime(true); + $result = $this->client->{$method}(...$parameters); + $time = round((microtime(true) - $start) * 1000, 2); if (isset($this->events)) { - $this->event(new QueryExecuted($method, $parameters, $time, $this)); + $this->event(new CommandExecuted($method, $parameters, $time, $this)); } return $result; @@ -134,7 +136,7 @@ protected function event($event) } /** - * Register a Redis query listener with the connection. + * Register a Redis command listener with the connection. * * @param \Closure $callback * @return void @@ -142,7 +144,7 @@ protected function event($event) public function listen(Closure $callback) { if (isset($this->events)) { - $this->events->listen(QueryExecuted::class, $callback); + $this->events->listen(CommandExecuted::class, $callback); } } diff --git a/src/Illuminate/Redis/Events/QueryExecuted.php b/src/Illuminate/Redis/Events/CommandExecuted.php similarity index 89% rename from src/Illuminate/Redis/Events/QueryExecuted.php rename to src/Illuminate/Redis/Events/CommandExecuted.php index 7bdc59435b66..fa65719af02a 100644 --- a/src/Illuminate/Redis/Events/QueryExecuted.php +++ b/src/Illuminate/Redis/Events/CommandExecuted.php @@ -2,7 +2,7 @@ namespace Illuminate\Redis\Events; -class QueryExecuted +class CommandExecuted { /** * The Redis command that was executed. @@ -12,14 +12,14 @@ class QueryExecuted public $command; /** - * The array of query parameters. + * The array of command parameters. * * @var array */ public $parameters; /** - * The number of milliseconds it took to execute the query. + * The number of milliseconds it took to execute the command. * * @var float */ diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index 4516fe91ad9c..969c4dbe3cce 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -44,7 +44,7 @@ class RedisManager implements Factory * * @var bool */ - protected $events = true; + protected $events = false; /** * Create a new Redis manager instance. @@ -121,7 +121,7 @@ protected function resolveCluster($name) } /** - * Get the connector instance for the current driver. + * Configure the given connection to prepare it for commands. * * @param \Illuminate\Redis\Connections\Connection $connection * @param string $name @@ -132,7 +132,7 @@ protected function configure(Connection $connection, $name) $connection->setName($name); if ($this->events && $this->app->bound('events')) { - $connection->setEventDispatcher($this->app['events']); + $connection->setEventDispatcher($this->app->make('events')); } return $connection; @@ -164,23 +164,23 @@ public function connections() } /** - * Enable setting event dispatcher on connections. + * Enable the firing of Redis command events. * - * @return array + * @return void */ public function enableEvents() { - return $this->events = true; + $this->events = true; } /** - * Disable setting event dispatcher on connections. + * Disable the firing of Redis command events. * - * @return array + * @return void */ public function disableEvents() { - return $this->events = false; + $this->events = false; } /** From 63d70a8b65163d4ac9ba6fd859a7d39fb36ee0d8 Mon Sep 17 00:00:00 2001 From: Mohamed Nagy Date: Tue, 27 Mar 2018 14:45:11 +0200 Subject: [PATCH 0043/2459] checking if exception is HttpExceptionInterface (#23712) --- src/Illuminate/Foundation/Exceptions/Handler.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Exceptions/Handler.php b/src/Illuminate/Foundation/Exceptions/Handler.php index 9a9970482e8c..0d80b6117a3a 100644 --- a/src/Illuminate/Foundation/Exceptions/Handler.php +++ b/src/Illuminate/Foundation/Exceptions/Handler.php @@ -27,6 +27,7 @@ use Symfony\Component\Console\Application as ConsoleApplication; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\Debug\ExceptionHandler as SymfonyExceptionHandler; use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract; @@ -476,6 +477,6 @@ public function renderForConsole($output, Exception $e) */ protected function isHttpException(Exception $e) { - return $e instanceof HttpException; + return $e instanceof HttpExceptionInterface; } } From 0a56560863125853873997013b43f6ab1eeb5c2c Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Tue, 27 Mar 2018 14:46:54 +0200 Subject: [PATCH 0044/2459] Improve nested rules in validated data (#23708) --- .../Foundation/Http/FormRequest.php | 3 ++- .../Providers/FoundationServiceProvider.php | 3 ++- .../Validation/ValidatesRequests.php | 3 ++- src/Illuminate/Validation/Validator.php | 14 +++++++---- .../Foundation/FoundationFormRequestTest.php | 24 +++++++++++++++++++ tests/Validation/ValidationValidatorTest.php | 15 ++++++++++++ 6 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 0e26083620a0..386e6c2b3508 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation\Http; +use Illuminate\Support\Str; use Illuminate\Http\Request; use Illuminate\Routing\Redirector; use Illuminate\Contracts\Container\Container; @@ -175,7 +176,7 @@ public function validated() $rules = $this->container->call([$this, 'rules']); return $this->only(collect($rules)->keys()->map(function ($rule) { - return explode('.', $rule)[0]; + return Str::contains($rule, '*') ? explode('.', $rule)[0] : $rule; })->unique()->toArray()); } diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index b20efaa1b6c8..d66f442dea1a 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation\Providers; +use Illuminate\Support\Str; use Illuminate\Http\Request; use Illuminate\Support\Facades\URL; use Illuminate\Support\AggregateServiceProvider; @@ -41,7 +42,7 @@ public function registerRequestValidation() validator()->validate($this->all(), $rules, ...$params); return $this->only(collect($rules)->keys()->map(function ($rule) { - return explode('.', $rule)[0]; + return Str::contains($rule, '*') ? explode('.', $rule)[0] : $rule; })->unique()->toArray()); }); } diff --git a/src/Illuminate/Foundation/Validation/ValidatesRequests.php b/src/Illuminate/Foundation/Validation/ValidatesRequests.php index 05d95918d8e9..cb947274de47 100644 --- a/src/Illuminate/Foundation/Validation/ValidatesRequests.php +++ b/src/Illuminate/Foundation/Validation/ValidatesRequests.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation\Validation; +use Illuminate\Support\Str; use Illuminate\Http\Request; use Illuminate\Contracts\Validation\Factory; use Illuminate\Validation\ValidationException; @@ -57,7 +58,7 @@ public function validate(Request $request, array $rules, protected function extractInputFromRules(Request $request, array $rules) { return $request->only(collect($rules)->keys()->map(function ($rule) { - return explode('.', $rule)[0]; + return Str::contains($rule, '*') ? explode('.', $rule)[0] : $rule; })->unique()->toArray()); } diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 3f7fb98ba428..b0d20eb47eef 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -306,11 +306,17 @@ public function validate() throw new ValidationException($this); } - $data = collect($this->getData()); + $results = []; - return $data->only(collect($this->getRules())->keys()->map(function ($rule) { - return explode('.', $rule)[0]; - })->unique())->toArray(); + $rules = collect($this->getRules())->keys()->map(function ($rule) { + return Str::contains($rule, '*') ? explode('.', $rule)[0] : $rule; + })->unique(); + + foreach ($rules as $rule) { + Arr::set($results, $rule, data_get($this->getData(), $rule)); + } + + return $results; } /** diff --git a/tests/Foundation/FoundationFormRequestTest.php b/tests/Foundation/FoundationFormRequestTest.php index 44585084c515..34577e2a9366 100644 --- a/tests/Foundation/FoundationFormRequestTest.php +++ b/tests/Foundation/FoundationFormRequestTest.php @@ -34,6 +34,17 @@ public function test_validated_method_returns_the_validated_data() $this->assertEquals(['name' => 'specified'], $request->validated()); } + public function test_validated_method_returns_the_validated_data_nested_rules() + { + $payload = ['nested' => ['foo' => 'bar', 'baz' => ''], 'array' => [1, 2]]; + + $request = $this->createRequest($payload, FoundationTestFormRequestNestedStub::class); + + $request->validateResolved(); + + $this->assertEquals(['nested' => ['foo' => 'bar'], 'array' => [1, 2]], $request->validated()); + } + /** * @expectedException \Illuminate\Validation\ValidationException */ @@ -174,6 +185,19 @@ public function authorize() } } +class FoundationTestFormRequestNestedStub extends FormRequest +{ + public function rules() + { + return ['nested.foo' => 'required', 'array.*' => 'integer']; + } + + public function authorize() + { + return true; + } +} + class FoundationTestFormRequestForbiddenStub extends FormRequest { public function rules() diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index bc89a7a6743a..d7e793825a11 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -3902,6 +3902,21 @@ public function testValidateReturnsValidatedData() $this->assertEquals(['first' => 'john', 'preferred' => 'john'], $data); } + public function testValidateReturnsValidatedDataNestedRules() + { + $post = ['nested' => ['foo' => 'bar', 'baz' => ''], 'array' => [1, 2]]; + + $rules = ['nested.foo' => 'required', 'array.*' => 'integer']; + + $v = new Validator($this->getIlluminateArrayTranslator(), $post, $rules); + $v->sometimes('type', 'required', function () { + return false; + }); + $data = $v->validate(); + + $this->assertEquals(['nested' => ['foo' => 'bar'], 'array' => [1, 2]], $data); + } + protected function getTranslator() { return m::mock('Illuminate\Contracts\Translation\Translator'); From 62ce097e686f63499fabc039dbf8b87e75066847 Mon Sep 17 00:00:00 2001 From: Samson Endale <4sam21@gmail.com> Date: Wed, 28 Mar 2018 16:39:50 +0300 Subject: [PATCH 0045/2459] [5.7] Moved the soft delete column name to the arg to make it consistent (#23718) * moved the soft delete column name to the arg to make it consistent * added missing docblock * added missing docblock 2 * added missing docblock --- src/Illuminate/Database/Schema/Blueprint.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 0580438a3962..7cda3387c923 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -380,21 +380,23 @@ public function dropTimestampsTz() /** * Indicate that the soft delete column should be dropped. * + * @param string $column * @return void */ - public function dropSoftDeletes() + public function dropSoftDeletes($column = 'deleted_at') { - $this->dropColumn('deleted_at'); + $this->dropColumn($column); } /** * Indicate that the soft delete column should be dropped. * + * @param string $column * @return void */ - public function dropSoftDeletesTz() + public function dropSoftDeletesTz($column = 'deleted_at') { - $this->dropSoftDeletes(); + $this->dropSoftDeletes($column); } /** @@ -972,12 +974,13 @@ public function softDeletes($column = 'deleted_at', $precision = 0) /** * Add a "deleted at" timestampTz for the table. * + * @param string $column * @param int $precision * @return \Illuminate\Support\Fluent */ - public function softDeletesTz($precision = 0) + public function softDeletesTz($column = 'deleted_at', $precision = 0) { - return $this->timestampTz('deleted_at', $precision)->nullable(); + return $this->timestampTz($column, $precision)->nullable(); } /** From 59f970b2b440338e48e0d41df7fa5fede08d2efc Mon Sep 17 00:00:00 2001 From: RachidLaasri Date: Thu, 29 Mar 2018 14:35:15 +0100 Subject: [PATCH 0046/2459] Add noContent response type --- src/Illuminate/Contracts/Routing/ResponseFactory.php | 9 +++++++++ src/Illuminate/Routing/ResponseFactory.php | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Illuminate/Contracts/Routing/ResponseFactory.php b/src/Illuminate/Contracts/Routing/ResponseFactory.php index 1d28e2e87d9c..2cdc1fb66a54 100644 --- a/src/Illuminate/Contracts/Routing/ResponseFactory.php +++ b/src/Illuminate/Contracts/Routing/ResponseFactory.php @@ -13,6 +13,15 @@ interface ResponseFactory * @return \Illuminate\Http\Response */ public function make($content = '', $status = 200, array $headers = []); + + /** + * Return an empty response. + * + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Response + */ + public function noContent($status = 204, array $headers = []); /** * Return a new view response from the application. diff --git a/src/Illuminate/Routing/ResponseFactory.php b/src/Illuminate/Routing/ResponseFactory.php index 309cc79cd74d..ea4f4512af40 100644 --- a/src/Illuminate/Routing/ResponseFactory.php +++ b/src/Illuminate/Routing/ResponseFactory.php @@ -55,6 +55,18 @@ public function make($content = '', $status = 200, array $headers = []) return new Response($content, $status, $headers); } + /** + * Return an empty response. + * + * @param int $status + * @param array $headers + * @return \Illuminate\Http\Response + */ + public function noContent($status = 204, array $headers = []) + { + return $this->make('', $status, $headers); + } + /** * Return a new view response from the application. * From cc76568b37cd8e72099162e12eed8d9611041a46 Mon Sep 17 00:00:00 2001 From: Rachid Laasri Date: Thu, 29 Mar 2018 14:40:13 +0100 Subject: [PATCH 0047/2459] Update ResponseFactory.php --- src/Illuminate/Contracts/Routing/ResponseFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Contracts/Routing/ResponseFactory.php b/src/Illuminate/Contracts/Routing/ResponseFactory.php index 2cdc1fb66a54..fcd5c2ba0a35 100644 --- a/src/Illuminate/Contracts/Routing/ResponseFactory.php +++ b/src/Illuminate/Contracts/Routing/ResponseFactory.php @@ -13,7 +13,7 @@ interface ResponseFactory * @return \Illuminate\Http\Response */ public function make($content = '', $status = 200, array $headers = []); - + /** * Return an empty response. * From 0129f633cf57a618cfead91a6bf8589123ee703a Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 30 Mar 2018 08:18:48 -0500 Subject: [PATCH 0048/2459] formatting --- .../Contracts/Routing/ResponseFactory.php | 14 +++++++------- src/Illuminate/Routing/ResponseFactory.php | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Contracts/Routing/ResponseFactory.php b/src/Illuminate/Contracts/Routing/ResponseFactory.php index fcd5c2ba0a35..9079ace15973 100644 --- a/src/Illuminate/Contracts/Routing/ResponseFactory.php +++ b/src/Illuminate/Contracts/Routing/ResponseFactory.php @@ -5,7 +5,7 @@ interface ResponseFactory { /** - * Return a new response from the application. + * Create a new response instance. * * @param string $content * @param int $status @@ -15,7 +15,7 @@ interface ResponseFactory public function make($content = '', $status = 200, array $headers = []); /** - * Return an empty response. + * Create a new "no content" response. * * @param int $status * @param array $headers @@ -24,7 +24,7 @@ public function make($content = '', $status = 200, array $headers = []); public function noContent($status = 204, array $headers = []); /** - * Return a new view response from the application. + * Create a new response for a given view. * * @param string $view * @param array $data @@ -35,7 +35,7 @@ public function noContent($status = 204, array $headers = []); public function view($view, $data = [], $status = 200, array $headers = []); /** - * Return a new JSON response from the application. + * Create a new JSON response instance. * * @param string|array $data * @param int $status @@ -46,7 +46,7 @@ public function view($view, $data = [], $status = 200, array $headers = []); public function json($data = [], $status = 200, array $headers = [], $options = 0); /** - * Return a new JSONP response from the application. + * Create a new JSONP response instance. * * @param string $callback * @param string|array $data @@ -58,7 +58,7 @@ public function json($data = [], $status = 200, array $headers = [], $options = public function jsonp($callback, $data = [], $status = 200, array $headers = [], $options = 0); /** - * Return a new streamed response from the application. + * Create a new streamed response instance. * * @param \Closure $callback * @param int $status @@ -68,7 +68,7 @@ public function jsonp($callback, $data = [], $status = 200, array $headers = [], public function stream($callback, $status = 200, array $headers = []); /** - * Return a new streamed response as a file download from the application. + * Create a new streamed response instance as a file download. * * @param \Closure $callback * @param string|null $name diff --git a/src/Illuminate/Routing/ResponseFactory.php b/src/Illuminate/Routing/ResponseFactory.php index ea4f4512af40..58e04faa07fb 100644 --- a/src/Illuminate/Routing/ResponseFactory.php +++ b/src/Illuminate/Routing/ResponseFactory.php @@ -43,7 +43,7 @@ public function __construct(ViewFactory $view, Redirector $redirector) } /** - * Return a new response from the application. + * Create a new response instance. * * @param string $content * @param int $status @@ -56,7 +56,7 @@ public function make($content = '', $status = 200, array $headers = []) } /** - * Return an empty response. + * Create a new "no content" response. * * @param int $status * @param array $headers @@ -68,7 +68,7 @@ public function noContent($status = 204, array $headers = []) } /** - * Return a new view response from the application. + * Create a new response for a given view. * * @param string $view * @param array $data @@ -82,7 +82,7 @@ public function view($view, $data = [], $status = 200, array $headers = []) } /** - * Return a new JSON response from the application. + * Create a new JSON response instance. * * @param mixed $data * @param int $status @@ -96,7 +96,7 @@ public function json($data = [], $status = 200, array $headers = [], $options = } /** - * Return a new JSONP response from the application. + * Create a new JSONP response instance. * * @param string $callback * @param mixed $data @@ -111,7 +111,7 @@ public function jsonp($callback, $data = [], $status = 200, array $headers = [], } /** - * Return a new streamed response from the application. + * Create a new streamed response instance. * * @param \Closure $callback * @param int $status @@ -124,7 +124,7 @@ public function stream($callback, $status = 200, array $headers = []) } /** - * Return a new streamed response as a file download from the application. + * Create a new streamed response instance as a file download. * * @param \Closure $callback * @param string|null $name From fbd0332e3746316996f9bfa85a58b28160d4b08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kru=CC=88ss?= Date: Sat, 31 Mar 2018 09:05:32 -0700 Subject: [PATCH 0049/2459] match Predis method signature for BLPOP and BRPOP PhpRedis returns an empty array, but Predis returns `null` when there is no result --- .../Redis/Connections/PhpRedisConnection.php | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index 15955629f283..a07365dd3208 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -155,6 +155,34 @@ public function lrem($key, $count, $value) return $this->command('lrem', [$key, $value, $count]); } + /** + * Removes and returns the first element of the list stored at key. + * It is the blocking version of LPOP. + * + * @param dynamic $arguments + * @return array|null + */ + public function blpop(...$arguments) + { + $result = $this->command('blpop', $arguments); + + return empty($result) ? null : $result; + } + + /** + * Removes and returns the last element of the list stored at key. + * It is the blocking version of RPOP. + * + * @param dynamic $arguments + * @return array|null + */ + public function brpop(...$arguments) + { + $result = $this->command('brpop', $arguments); + + return empty($result) ? null : $result; + } + /** * Removes and returns a random element from the set value at key. * From 5eb50837b6994956b54d6482c0c5a5b7134f3b8e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 2 Apr 2018 08:01:11 -0500 Subject: [PATCH 0050/2459] formatting --- src/Illuminate/Redis/Connections/PhpRedisConnection.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index a07365dd3208..5b088fbb1571 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -157,7 +157,6 @@ public function lrem($key, $count, $value) /** * Removes and returns the first element of the list stored at key. - * It is the blocking version of LPOP. * * @param dynamic $arguments * @return array|null @@ -171,7 +170,6 @@ public function blpop(...$arguments) /** * Removes and returns the last element of the list stored at key. - * It is the blocking version of RPOP. * * @param dynamic $arguments * @return array|null From b488c0f6d66b267dcf426c5254fd422eed2af919 Mon Sep 17 00:00:00 2001 From: Tom Lankhorst Date: Tue, 3 Apr 2018 16:12:32 +0200 Subject: [PATCH 0051/2459] [5.7] Expose readStream and writeStream to allow cross-filesystem actions (#23755) * Expose WriteStream and ReadStream * Added test, clean * Removed additional Stream interfaces --- .../Filesystem/FileExistsException.php | 10 +++++ .../Contracts/Filesystem/Filesystem.php | 23 ++++++++++ .../Filesystem/FilesystemAdapter.php | 30 ++++++++++++- tests/Filesystem/FilesystemAdapterTest.php | 45 +++++++++++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/Illuminate/Contracts/Filesystem/FileExistsException.php diff --git a/src/Illuminate/Contracts/Filesystem/FileExistsException.php b/src/Illuminate/Contracts/Filesystem/FileExistsException.php new file mode 100644 index 000000000000..9027892faa00 --- /dev/null +++ b/src/Illuminate/Contracts/Filesystem/FileExistsException.php @@ -0,0 +1,10 @@ +setCallback(function () use ($path) { - $stream = $this->driver->readStream($path); + $stream = $this->readStream($path); fpassthru($stream); fclose($stream); }); @@ -390,6 +392,32 @@ public function url($path) } } + /** + * {@inheritdoc} + */ + public function readStream($path) + { + try { + $resource = $this->driver->readStream($path); + + return $resource ? $resource : null; + } catch (FileNotFoundException $e) { + throw new ContractFileNotFoundException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + */ + public function writeStream($path, $resource, array $options = []) + { + try { + return $this->driver->writeStream($path, $resource, $options); + } catch (FileExistsException $e) { + throw new ContractFileExistsException($e->getMessage(), $e->getCode(), $e); + } + } + /** * Get the URL for the file at the given path. * diff --git a/tests/Filesystem/FilesystemAdapterTest.php b/tests/Filesystem/FilesystemAdapterTest.php index e5d795d156fe..2a53fee53720 100644 --- a/tests/Filesystem/FilesystemAdapterTest.php +++ b/tests/Filesystem/FilesystemAdapterTest.php @@ -7,6 +7,7 @@ use League\Flysystem\Adapter\Local; use Illuminate\Filesystem\FilesystemAdapter; use Symfony\Component\HttpFoundation\StreamedResponse; +use Illuminate\Contracts\Filesystem\FileExistsException; use Illuminate\Contracts\Filesystem\FileNotFoundException; class FilesystemAdapterTest extends TestCase @@ -145,4 +146,48 @@ public function testMove() $this->assertFileExists($this->tempDir.'/foo/foo2.txt'); $this->assertEquals($data, file_get_contents($this->tempDir.'/foo/foo2.txt')); } + + public function testStream() + { + $this->filesystem->write('file.txt', $original_content = 'Hello World'); + $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $readStream = $filesystemAdapter->readStream('file.txt'); + $filesystemAdapter->writeStream('copy.txt', $readStream); + $this->assertEquals($original_content, $filesystemAdapter->get('copy.txt')); + } + + public function testStreamBetweenFilesystems() + { + $secondFilesystem = new Filesystem(new Local($this->tempDir.'/second')); + $this->filesystem->write('file.txt', $original_content = 'Hello World'); + $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $secondFilesystemAdapter = new FilesystemAdapter($secondFilesystem); + $readStream = $filesystemAdapter->readStream('file.txt'); + $secondFilesystemAdapter->writeStream('copy.txt', $readStream); + $this->assertEquals($original_content, $secondFilesystemAdapter->get('copy.txt')); + } + + public function testStreamToExistingFileThrows() + { + $this->expectException(FileExistsException::class); + $this->filesystem->write('file.txt', 'Hello World'); + $this->filesystem->write('existing.txt', 'Dear Kate'); + $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $readStream = $filesystemAdapter->readStream('file.txt'); + $filesystemAdapter->writeStream('existing.txt', $readStream); + } + + public function testReadStreamNonExistentFileThrows() + { + $this->expectException(FileNotFoundException::class); + $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter->readStream('nonexistent.txt'); + } + + public function testStreamInvalidResourceThrows() + { + $this->expectException(\InvalidArgumentException::class); + $filesystemAdapter = new FilesystemAdapter($this->filesystem); + $filesystemAdapter->writeStream('file.txt', 'foo bar'); + } } From 8124f9b8fafb6bd5e7c834c789709c01fedd39f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kr=C3=BCss?= Date: Tue, 10 Apr 2018 12:06:48 -0700 Subject: [PATCH 0052/2459] Add PR template (#23846) * add simple PR template * update copy --- .github/PULL_REQUEST_TEMPLATE.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000000..406bf9f52e44 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ + From c562b63b7fdd7ba438b0c0be1bfe6a891b432d80 Mon Sep 17 00:00:00 2001 From: Miguel Piedrafita Date: Wed, 11 Apr 2018 14:43:02 +0200 Subject: [PATCH 0053/2459] Add oxford comma (#23849) --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 406bf9f52e44..84e668053eeb 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,5 @@ From 1eb1314da8956808e20acfe2bf731199577ac934 Mon Sep 17 00:00:00 2001 From: Duilio Palacios Date: Fri, 13 Apr 2018 13:55:43 +0100 Subject: [PATCH 0054/2459] Add view data method to the TestResponse class (#23873) --- src/Illuminate/Foundation/Testing/TestResponse.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Illuminate/Foundation/Testing/TestResponse.php b/src/Illuminate/Foundation/Testing/TestResponse.php index 51cf2e21399d..6532d627b255 100644 --- a/src/Illuminate/Foundation/Testing/TestResponse.php +++ b/src/Illuminate/Foundation/Testing/TestResponse.php @@ -663,6 +663,19 @@ public function assertViewHasAll(array $bindings) return $this; } + /** + * Get a piece of data from the original view. + * + * @param string $key + * @return mixed + */ + public function viewData($key) + { + $this->ensureResponseHasView(); + + return $this->original->$key; + } + /** * Assert that the response view is missing a piece of bound data. * From 9d0d6f8a9409f9d28765c8e2396369d30b32051e Mon Sep 17 00:00:00 2001 From: Abdulrahman Date: Mon, 16 Apr 2018 18:50:50 +0300 Subject: [PATCH 0055/2459] enable pusher set_logger --- .../Broadcasters/PusherBroadcaster.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 856024f373d8..8c4d81550f8c 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -7,11 +7,15 @@ use Illuminate\Support\Str; use Illuminate\Broadcasting\BroadcastException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Illuminate\Container\Container; +use Illuminate\Config\Repository as ConfigRepository; class PusherBroadcaster extends Broadcaster { /** - * The Pusher SDK instance. + * The Pusher SDK instance. * * @var \Pusher\Pusher */ @@ -26,6 +30,19 @@ class PusherBroadcaster extends Broadcaster public function __construct(Pusher $pusher) { $this->pusher = $pusher; + + $this->pusher->set_logger(new class() { + public function log($message) + { + $app = Container::getInstance(); + $config = $app->make(ConfigRepository::class); + + if ($config->get('app.debug')) { + return $app->make(LoggerInterface::class) + ->log(LogLevel::INFO, $message); + } + } + }); } /** From 890b614bfced6668cd32f97b19ec23bb71692a6c Mon Sep 17 00:00:00 2001 From: Thorben Grahlmann Date: Tue, 17 Apr 2018 14:29:48 +0200 Subject: [PATCH 0056/2459] fixed collection min returns null with given key --- src/Illuminate/Support/Collection.php | 8 ++++---- tests/Support/SupportCollectionTest.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 154b64099c38..3ab68650541c 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -1081,11 +1081,11 @@ public function min($callback = null) { $callback = $this->valueRetriever($callback); - return $this->filter(function ($value) { + return $this->map(function ($value) use ($callback) { + return $callback($value); + })->filter(function ($value) { return ! is_null($value); - })->reduce(function ($result, $item) use ($callback) { - $value = $callback($item); - + })->reduce(function ($result, $value) { return is_null($result) || $value < $result ? $value : $result; }); } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 9313606a7c83..6b3b2dd821c3 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2054,7 +2054,7 @@ public function testGettingMinItemsFromCollection() $this->assertEquals(10, $c->min('foo')); $this->assertEquals(10, $c->min->foo); - $c = new Collection([['foo' => 10], ['foo' => 20]]); + $c = new Collection([['foo' => 10], ['foo' => 20], ['foo' => null]]); $this->assertEquals(10, $c->min('foo')); $this->assertEquals(10, $c->min->foo); From d86ee3915045ea656ab1f39612299dbe6fb64a5e Mon Sep 17 00:00:00 2001 From: Thorben Grahlmann Date: Tue, 17 Apr 2018 14:52:59 +0200 Subject: [PATCH 0057/2459] fixed test --- tests/Support/SupportCollectionTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 6b3b2dd821c3..0dd8ccabcb59 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2053,10 +2053,12 @@ public function testGettingMinItemsFromCollection() })); $this->assertEquals(10, $c->min('foo')); $this->assertEquals(10, $c->min->foo); + + $c = new Collection([['foo' => 10], ['foo' => 20]]); + $this->assertEquals(10, $c->min('foo')); $c = new Collection([['foo' => 10], ['foo' => 20], ['foo' => null]]); $this->assertEquals(10, $c->min('foo')); - $this->assertEquals(10, $c->min->foo); $c = new Collection([1, 2, 3, 4, 5]); $this->assertEquals(1, $c->min()); From b41c9e1153e8bcb39718bae76d8d8384e59a94ce Mon Sep 17 00:00:00 2001 From: Thorben Grahlmann Date: Tue, 17 Apr 2018 14:56:27 +0200 Subject: [PATCH 0058/2459] add second assertEquals --- tests/Support/SupportCollectionTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 0dd8ccabcb59..08973007a1b8 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2056,9 +2056,11 @@ public function testGettingMinItemsFromCollection() $c = new Collection([['foo' => 10], ['foo' => 20]]); $this->assertEquals(10, $c->min('foo')); + $this->assertEquals(10, $c->min->foo); $c = new Collection([['foo' => 10], ['foo' => 20], ['foo' => null]]); $this->assertEquals(10, $c->min('foo')); + $this->assertEquals(10, $c->min->foo); $c = new Collection([1, 2, 3, 4, 5]); $this->assertEquals(1, $c->min()); From 44b5c1f039f57af52db5fc4358d6c80bdd134182 Mon Sep 17 00:00:00 2001 From: Thorben Grahlmann Date: Tue, 17 Apr 2018 14:57:39 +0200 Subject: [PATCH 0059/2459] fix for style ci --- tests/Support/SupportCollectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 08973007a1b8..3601dca9c062 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2053,7 +2053,7 @@ public function testGettingMinItemsFromCollection() })); $this->assertEquals(10, $c->min('foo')); $this->assertEquals(10, $c->min->foo); - + $c = new Collection([['foo' => 10], ['foo' => 20]]); $this->assertEquals(10, $c->min('foo')); $this->assertEquals(10, $c->min->foo); From 1360f3b1188800149707b2f0998dc4104dd62998 Mon Sep 17 00:00:00 2001 From: TheDramatist Date: Wed, 25 Apr 2018 20:33:05 +0600 Subject: [PATCH 0060/2459] Added '\Throwable' to PHPDoc with '@throws'. (#23960) --- src/Illuminate/View/View.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/View/View.php b/src/Illuminate/View/View.php index be51cdc11c59..c171278295d7 100755 --- a/src/Illuminate/View/View.php +++ b/src/Illuminate/View/View.php @@ -159,6 +159,8 @@ protected function gatherData() * Get the sections of the rendered view. * * @return string + * + * @throws \Throwable */ public function renderSections() { @@ -377,7 +379,7 @@ public function __isset($key) * Remove a piece of bound data from the view. * * @param string $key - * @return bool + * @return void */ public function __unset($key) { @@ -408,6 +410,8 @@ public function __call($method, $parameters) * Get the string contents of the view. * * @return string + * + * @throws \Throwable */ public function __toString() { From 91aefbe8b265954379537dcb946e3450e8f52832 Mon Sep 17 00:00:00 2001 From: Paul Redmond Date: Wed, 25 Apr 2018 07:49:40 -0700 Subject: [PATCH 0061/2459] Add a named route for POST password/reset (#23958) The reset.stub is using the GET named route (password.request) for the POST password/reset request (changed in #17718). Incorrectly using a named route from another route is confusing and could lead to unexpected results. --- .../Auth/Console/stubs/make/views/auth/passwords/reset.stub | 2 +- src/Illuminate/Routing/Router.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub index 292f30241f75..4a125494ca98 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub @@ -8,7 +8,7 @@
{{ __('Reset Password') }}
-
+ @csrf diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 6ee8073b8903..9b9774a0687b 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -1135,7 +1135,7 @@ public function auth() $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request'); $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email'); $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset'); - $this->post('password/reset', 'Auth\ResetPasswordController@reset'); + $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update'); } /** From 4861b82bd1395fdcddd2fab1ae728c05ba2aba55 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 25 Apr 2018 13:26:38 -0500 Subject: [PATCH 0062/2459] Apply fixes from StyleCI (#24008) --- .../Foundation/Providers/FoundationServiceProvider.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index 7d2c5d6ce55b..b12c1799aed7 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -2,7 +2,6 @@ namespace Illuminate\Foundation\Providers; -use Illuminate\Support\Str; use Illuminate\Http\Request; use Illuminate\Support\Facades\URL; use Illuminate\Support\AggregateServiceProvider; From 6f49781eedb41a94d470028584dcbd73dc0994fa Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Wed, 25 Apr 2018 20:26:45 +0200 Subject: [PATCH 0063/2459] Use custom CREATED_AT column for latest() and oldest() (#24004) --- src/Illuminate/Database/Eloquent/Builder.php | 34 ++++++++++ .../Database/DatabaseEloquentBuilderTest.php | 64 +++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 1de309145bfa..5ec834efda27 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -248,6 +248,40 @@ public function orWhere($column, $operator = null, $value = null) return $this->where($column, $operator, $value, 'or'); } + /** + * Add an "order by" clause for a timestamp to the query. + * + * @param string $column + * @return $this + */ + public function latest($column = null) + { + if (is_null($column)) { + $column = $this->model->getCreatedAtColumn() ?? 'created_at'; + } + + $this->query->latest($column); + + return $this; + } + + /** + * Add an "order by" clause for a timestamp to the query. + * + * @param string $column + * @return $this + */ + public function oldest($column = null) + { + if (is_null($column)) { + $column = $this->model->getCreatedAtColumn() ?? 'created_at'; + } + + $this->query->oldest($column); + + return $this; + } + /** * Create a collection of models from plain arrays. * diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 9011fadbd4f6..93f69b01e8c4 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -969,6 +969,70 @@ public function testWhereKeyNotMethodWithCollection() $builder->whereKeyNot($collection); } + public function testLatestWithoutColumnWithCreatedAt() + { + $model = $this->getMockModel(); + $model->shouldReceive('getCreatedAtColumn')->andReturn('foo'); + $builder = $this->getBuilder()->setModel($model); + + $builder->getQuery()->shouldReceive('latest')->once()->with('foo'); + + $builder->latest(); + } + + public function testLatestWithoutColumnWithoutCreatedAt() + { + $model = $this->getMockModel(); + $model->shouldReceive('getCreatedAtColumn')->andReturn(null); + $builder = $this->getBuilder()->setModel($model); + + $builder->getQuery()->shouldReceive('latest')->once()->with('created_at'); + + $builder->latest(); + } + + public function testLatestWithColumn() + { + $model = $this->getMockModel(); + $builder = $this->getBuilder()->setModel($model); + + $builder->getQuery()->shouldReceive('latest')->once()->with('foo'); + + $builder->latest('foo'); + } + + public function testOldestWithoutColumnWithCreatedAt() + { + $model = $this->getMockModel(); + $model->shouldReceive('getCreatedAtColumn')->andReturn('foo'); + $builder = $this->getBuilder()->setModel($model); + + $builder->getQuery()->shouldReceive('oldest')->once()->with('foo'); + + $builder->oldest(); + } + + public function testOldestWithoutColumnWithoutCreatedAt() + { + $model = $this->getMockModel(); + $model->shouldReceive('getCreatedAtColumn')->andReturn(null); + $builder = $this->getBuilder()->setModel($model); + + $builder->getQuery()->shouldReceive('oldest')->once()->with('created_at'); + + $builder->oldest(); + } + + public function testOldestWithColumn() + { + $model = $this->getMockModel(); + $builder = $this->getBuilder()->setModel($model); + + $builder->getQuery()->shouldReceive('oldest')->once()->with('foo'); + + $builder->oldest('foo'); + } + protected function mockConnectionForModel($model, $database) { $grammarClass = 'Illuminate\Database\Query\Grammars\\'.$database.'Grammar'; From 3f793789fb9c1effdd450932bbe075a251ed12a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=81nis=20Elmeris?= Date: Sun, 29 Apr 2018 22:13:14 +0300 Subject: [PATCH 0064/2459] [5.7] Throw on trying to drop foreign keys in SQLite (#24052) * Throw on trying to drop foreign keys in SQLite * Throw on trying to drop foreign keys in SQLite --- src/Illuminate/Database/Schema/Blueprint.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index ee376dbb7fda..f49e84003300 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -128,11 +128,18 @@ public function toSql(Connection $connection, Grammar $grammar) */ protected function ensureCommandsAreValid(Connection $connection) { - if ($connection instanceof SQLiteConnection && - $this->commandsNamed(['dropColumn', 'renameColumn'])->count() > 1) { - throw new BadMethodCallException( - "SQLite doesn't support multiple calls to dropColumn / renameColumn in a single modification." - ); + if ($connection instanceof SQLiteConnection) { + if ($this->commandsNamed(['dropColumn', 'renameColumn'])->count() > 1) { + throw new BadMethodCallException( + "SQLite doesn't support multiple calls to dropColumn / renameColumn in a single modification." + ); + } + + if ($this->commandsNamed(['dropForeign'])->count() > 0) { + throw new BadMethodCallException( + "SQLite doesn't support dropping foreign keys (you would need to re-create the table)." + ); + } } } From ba6535590535a089473a78509d6814cf185682ca Mon Sep 17 00:00:00 2001 From: Carlos Ramos Date: Mon, 30 Apr 2018 16:55:49 -0600 Subject: [PATCH 0065/2459] Build http queries with RFC3986 --- src/Illuminate/Http/Request.php | 4 ++-- src/Illuminate/Pagination/AbstractPaginator.php | 2 +- src/Illuminate/Redis/Connectors/PhpRedisConnector.php | 2 +- src/Illuminate/Routing/RouteUrlGenerator.php | 5 ++++- src/Illuminate/Routing/UrlGenerator.php | 5 ++++- tests/Http/HttpRequestTest.php | 3 +++ tests/Pagination/LengthAwarePaginatorTest.php | 9 +++++++++ 7 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 533c6116c2d5..524d0f20ed73 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -124,8 +124,8 @@ public function fullUrlWithQuery(array $query) $question = $this->getBaseUrl().$this->getPathInfo() == '/' ? '/?' : '?'; return count($this->query()) > 0 - ? $this->url().$question.http_build_query(array_merge($this->query(), $query)) - : $this->fullUrl().$question.http_build_query($query); + ? $this->url().$question.http_build_query(array_merge($this->query(), $query), null, '&', PHP_QUERY_RFC3986) + : $this->fullUrl().$question.http_build_query($query, null, '&', PHP_QUERY_RFC3986); } /** diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index 8bdeee33e33e..7a1da177bc33 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -156,7 +156,7 @@ public function url($page) return $this->path .(Str::contains($this->path, '?') ? '&' : '?') - .http_build_query($parameters, '', '&') + .http_build_query($parameters, null, '&', PHP_QUERY_RFC3986) .$this->buildFragment(); } diff --git a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php index 78f3e7180015..edae03e9f74c 100644 --- a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php +++ b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php @@ -51,7 +51,7 @@ protected function buildClusterConnectionString(array $server) { return $server['host'].':'.$server['port'].'?'.http_build_query(Arr::only($server, [ 'database', 'password', 'prefix', 'read_timeout', - ])); + ]), null, '&', PHP_QUERY_RFC3986); } /** diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index b5a4c1cbf1ec..3de8ab7df3bc 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -255,7 +255,10 @@ protected function getRouteQueryString(array $parameters) } $query = http_build_query( - $keyed = $this->getStringParameters($parameters) + $keyed = $this->getStringParameters($parameters), + null, + '&', + PHP_QUERY_RFC3986 ); // Lastly, if there are still parameters remaining, we will fetch the numeric diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 7c7a417ed20e..ccb362485f91 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -340,7 +340,10 @@ public function temporarySignedRoute($name, $expiration, $parameters = []) public function hasValidSignature(Request $request) { $original = rtrim($request->url().'?'.http_build_query( - Arr::except($request->query(), 'signature') + Arr::except($request->query(), 'signature'), + null, + '&', + PHP_QUERY_RFC3986 ), '?'); $expires = Arr::get($request->query(), 'expires'); diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index e37b298b64b1..84bb7d6db747 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -141,6 +141,9 @@ public function testFullUrlMethod() $request = Request::create('http://foo.com/foo/bar/?name=taylor', 'GET'); $this->assertEquals('http://foo.com/foo/bar?name=graham', $request->fullUrlWithQuery(['name' => 'graham'])); + + $request = Request::create('https://foo.com', 'GET'); + $this->assertEquals('https://foo.com?key=value%20with%20spaces', $request->fullUrlWithQuery(['key' => 'value with spaces'])); } public function testIsMethod() diff --git a/tests/Pagination/LengthAwarePaginatorTest.php b/tests/Pagination/LengthAwarePaginatorTest.php index 3fcd658d70d1..611df2c65004 100644 --- a/tests/Pagination/LengthAwarePaginatorTest.php +++ b/tests/Pagination/LengthAwarePaginatorTest.php @@ -83,4 +83,13 @@ public function testLengthAwarePaginatorCanGenerateUrlsWithoutTrailingSlashes() $this->assertEquals('http://website.com/test?foo=1', $this->p->url($this->p->currentPage() - 2)); } + + public function testLengthAwarePaginatorCorrectlyGenerateUrlsWithQueryAndSpaces() + { + $this->p->setPath('http://website.com?key=value%20with%20spaces'); + $this->p->setPageName('foo'); + + $this->assertEquals('http://website.com?key=value%20with%20spaces&foo=2', + $this->p->url($this->p->currentPage())); + } } From 0d3055de465ace9d4d9133f0979c6d06fcdf1a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kr=C3=BCss?= Date: Mon, 30 Apr 2018 16:53:34 -0700 Subject: [PATCH 0066/2459] fix test --- tests/Http/HttpRequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index 84bb7d6db747..c1e70abc7e6e 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -143,7 +143,7 @@ public function testFullUrlMethod() $this->assertEquals('http://foo.com/foo/bar?name=graham', $request->fullUrlWithQuery(['name' => 'graham'])); $request = Request::create('https://foo.com', 'GET'); - $this->assertEquals('https://foo.com?key=value%20with%20spaces', $request->fullUrlWithQuery(['key' => 'value with spaces'])); + $this->assertEquals('https://foo.com/?key=value%20with%20spaces', $request->fullUrlWithQuery(['key' => 'value with spaces'])); } public function testIsMethod() From 69dd3b89d45d0b6aa42c99ef4b56485b43f8b107 Mon Sep 17 00:00:00 2001 From: ThorbenG <26707299+ThorbenG@users.noreply.github.com> Date: Wed, 2 May 2018 16:48:41 +0200 Subject: [PATCH 0067/2459] [5.7] Collection avg() should ignore null (#24081) * filter out null in avg method * styleci fix --- src/Illuminate/Support/Collection.php | 12 ++++++++++-- tests/Support/SupportCollectionTest.php | 7 +++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index d89737e62d22..387b35b453e4 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -122,8 +122,16 @@ public function all() */ public function avg($callback = null) { - if ($count = $this->count()) { - return $this->sum($callback) / $count; + $callback = $this->valueRetriever($callback); + + $items = $this->map(function ($value) use ($callback) { + return $callback($value); + })->filter(function ($value) { + return ! is_null($value); + }); + + if ($count = $items->count()) { + return $items->sum() / $count; } } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 3601dca9c062..e503a3de0be7 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2098,6 +2098,13 @@ public function testGettingAvgItemsFromCollection() $this->assertEquals(15, $c->avg('foo')); $this->assertEquals(15, $c->avg->foo); + $c = new Collection([(object) ['foo' => 10], (object) ['foo' => 20], (object) ['foo' => null]]); + $this->assertEquals(15, $c->avg(function ($item) { + return $item->foo; + })); + $this->assertEquals(15, $c->avg('foo')); + $this->assertEquals(15, $c->avg->foo); + $c = new Collection([['foo' => 10], ['foo' => 20]]); $this->assertEquals(15, $c->avg('foo')); $this->assertEquals(15, $c->avg->foo); From 274dd487005e785a04ddca7c1469464433d4ba38 Mon Sep 17 00:00:00 2001 From: ThorbenG <26707299+ThorbenG@users.noreply.github.com> Date: Wed, 2 May 2018 16:56:53 +0200 Subject: [PATCH 0068/2459] filter out null in median method (#24082) --- src/Illuminate/Support/Collection.php | 10 ++++++---- tests/Support/SupportCollectionTest.php | 11 +++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 387b35b453e4..7f6eefc4aa24 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -154,15 +154,17 @@ public function average($callback = null) */ public function median($key = null) { - $count = $this->count(); + $values = (isset($key) ? $this->pluck($key) : $this) + ->filter(function ($item) { + return ! is_null($item); + })->sort()->values(); + + $count = $values->count(); if ($count == 0) { return; } - $values = (isset($key) ? $this->pluck($key) : $this) - ->sort()->values(); - $middle = (int) ($count / 2); if ($count % 2) { diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index e503a3de0be7..50b1516bdb6d 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2258,6 +2258,17 @@ public function testMedianValueByKey() $this->assertEquals(2, $collection->median('foo')); } + public function testMedianOnCollectionWithNull() + { + $collection = new Collection([ + (object) ['foo' => 1], + (object) ['foo' => 2], + (object) ['foo' => 4], + (object) ['foo' => null], + ]); + $this->assertEquals(2, $collection->median('foo')); + } + public function testEvenMedianCollection() { $collection = new Collection([ From d81e8c53d2c02df5b0b07bfed70304d1c3748d50 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 2 May 2018 18:13:39 +0200 Subject: [PATCH 0069/2459] [5.7] Pass route to custom URL formatters (#24049) * Pass route to custom URL formatters * Create a separate test --- src/Illuminate/Routing/RouteUrlGenerator.php | 3 ++- src/Illuminate/Routing/UrlGenerator.php | 7 ++++--- tests/Routing/RoutingUrlGeneratorTest.php | 22 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index b5a4c1cbf1ec..a3e91b1ec51a 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -83,7 +83,8 @@ public function to($route, $parameters = [], $absolute = false) // will need to throw the exception to let the developers know one was not given. $uri = $this->addQueryString($this->url->format( $root = $this->replaceRootParameters($route, $domain, $parameters), - $this->replaceRouteParameters($route->uri(), $parameters) + $this->replaceRouteParameters($route->uri(), $parameters), + $route ), $parameters); if (preg_match('/\{.*?\}/', $uri)) { diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 7c7a417ed20e..a4b1a305d3c6 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -485,18 +485,19 @@ public function formatRoot($scheme, $root = null) * * @param string $root * @param string $path + * @param \Illuminate\Routing\Route|null $route * @return string */ - public function format($root, $path) + public function format($root, $path, $route = null) { $path = '/'.trim($path, '/'); if ($this->formatHostUsing) { - $root = call_user_func($this->formatHostUsing, $root); + $root = call_user_func($this->formatHostUsing, $root, $route); } if ($this->formatPathUsing) { - $path = call_user_func($this->formatPathUsing, $path); + $path = call_user_func($this->formatPathUsing, $path, $route); } return trim($root.$path, '/'); diff --git a/tests/Routing/RoutingUrlGeneratorTest.php b/tests/Routing/RoutingUrlGeneratorTest.php index 766cade3a69b..cc574e142488 100755 --- a/tests/Routing/RoutingUrlGeneratorTest.php +++ b/tests/Routing/RoutingUrlGeneratorTest.php @@ -67,6 +67,28 @@ public function testBasicGenerationWithFormatting() $this->assertEquals('/something/named-route', $url->route('plain', [], false)); } + public function testUrlFormattersShouldReceiveTargetRoute() + { + $url = new UrlGenerator( + $routes = new RouteCollection, + $request = Request::create('http://abc.com/') + ); + + $namedRoute = new Route(['GET'], '/bar', ['as' => 'plain', 'root' => 'bar.com', 'path' => 'foo']); + $routes->add($namedRoute); + + $url->formatHostUsing(function ($root, $route) { + return $route ? 'http://'.$route->getAction('root') : $root; + }); + + $url->formatPathUsing(function ($path, $route) { + return $route ? '/'.$route->getAction('path') : $path; + }); + + $this->assertEquals('http://abc.com/foo/bar', $url->to('foo/bar')); + $this->assertEquals('http://bar.com/foo', $url->route('plain')); + } + public function testBasicRouteGeneration() { $url = new UrlGenerator( From 4a27f5aeacba5913d3fe8e0cb5637c8180081d45 Mon Sep 17 00:00:00 2001 From: Tobias van Beek Date: Thu, 3 May 2018 11:12:30 +0200 Subject: [PATCH 0070/2459] Fix a unsuspected result from the split function in the Collection class See: https://github.com/laravel/framework/issues/22090 --- src/Illuminate/Support/Collection.php | 20 ++++++++++++-- tests/Support/SupportCollectionTest.php | 36 +++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 7f6eefc4aa24..c2cd18b85692 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -1396,9 +1396,25 @@ public function split($numberOfGroups) return new static; } - $groupSize = ceil($this->count() / $numberOfGroups); + $groups = new static(); - return $this->chunk($groupSize); + $groupSize = floor($this->count() / $numberOfGroups); + + $remain = $this->count() % $numberOfGroups; + + $start = 0; + for ($i = 0; $i < $numberOfGroups; $i++) { + $size = $groupSize; + if ($i < $remain) { + $size++; + } + if ($size) { + $groups->push(new static(array_slice($this->items, $start, $size))); + $start += $size; + } + } + + return $groups; } /** diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 50b1516bdb6d..079fea8b9a5f 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2407,6 +2407,42 @@ public function testSplitCollectionWithCountLessThenDivisor() ); } + public function testSplitCollectionIntoThreeWithCountOfFour() + { + $collection = new Collection(['a', 'b', 'c', 'd']); + + $this->assertEquals( + [['a', 'b'], ['c'], ['d']], + $collection->split(3)->map(function (Collection $chunk) { + return $chunk->values()->toArray(); + })->toArray() + ); + } + + public function testSplitCollectionIntoThreeWithCountOfFive() + { + $collection = new Collection(['a', 'b', 'c', 'd', 'e']); + + $this->assertEquals( + [['a', 'b'], ['c', 'd'], ['e']], + $collection->split(3)->map(function (Collection $chunk) { + return $chunk->values()->toArray(); + })->toArray() + ); + } + + public function testSplitCollectionIntoSixWithCountOfTen() + { + $collection = new Collection(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']); + + $this->assertEquals( + [['a', 'b'], ['c', 'd'], ['e', 'f'], ['g', 'h'], ['i'], ['j']], + $collection->split(6)->map(function (Collection $chunk) { + return $chunk->values()->toArray(); + })->toArray() + ); + } + public function testSplitEmptyCollection() { $collection = new Collection; From 76553b0b5f9a4d7bccca1fc3dab7788c30632cb4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 3 May 2018 08:47:30 -0500 Subject: [PATCH 0071/2459] formatting. test --- src/Illuminate/Support/Collection.php | 6 +++++- tests/Support/SupportCollectionTest.php | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index c2cd18b85692..389602971966 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -1396,20 +1396,24 @@ public function split($numberOfGroups) return new static; } - $groups = new static(); + $groups = new static; $groupSize = floor($this->count() / $numberOfGroups); $remain = $this->count() % $numberOfGroups; $start = 0; + for ($i = 0; $i < $numberOfGroups; $i++) { $size = $groupSize; + if ($i < $remain) { $size++; } + if ($size) { $groups->push(new static(array_slice($this->items, $start, $size))); + $start += $size; } } diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 079fea8b9a5f..6c60e200431f 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -2381,6 +2381,15 @@ public function testSplitCollectionWithADivisableCount() return $chunk->values()->toArray(); })->toArray() ); + + $collection = new Collection([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + + $this->assertEquals( + [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]], + $collection->split(2)->map(function (Collection $chunk) { + return $chunk->values()->toArray(); + })->toArray() + ); } public function testSplitCollectionWithAnUndivisableCount() From 7c3525393ea0a1eb79321d05e744551839d5a74b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 3 May 2018 10:34:38 -0500 Subject: [PATCH 0072/2459] dry code --- src/Illuminate/Http/Request.php | 4 ++-- src/Illuminate/Pagination/AbstractPaginator.php | 3 ++- src/Illuminate/Redis/Connectors/PhpRedisConnector.php | 4 ++-- src/Illuminate/Routing/RouteUrlGenerator.php | 7 ++----- src/Illuminate/Routing/UrlGenerator.php | 7 ++----- src/Illuminate/Support/Arr.php | 11 +++++++++++ 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index f47493d8095e..1b2e15cecdcd 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -124,8 +124,8 @@ public function fullUrlWithQuery(array $query) $question = $this->getBaseUrl().$this->getPathInfo() == '/' ? '/?' : '?'; return count($this->query()) > 0 - ? $this->url().$question.http_build_query(array_merge($this->query(), $query), null, '&', PHP_QUERY_RFC3986) - : $this->fullUrl().$question.http_build_query($query, null, '&', PHP_QUERY_RFC3986); + ? $this->url().$question.Arr::query(array_merge($this->query(), $query)) + : $this->fullUrl().$question.Arr::query($query); } /** diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index 7a1da177bc33..57f50738106a 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -3,6 +3,7 @@ namespace Illuminate\Pagination; use Closure; +use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Support\Collection; use Illuminate\Contracts\Support\Htmlable; @@ -156,7 +157,7 @@ public function url($page) return $this->path .(Str::contains($this->path, '?') ? '&' : '?') - .http_build_query($parameters, null, '&', PHP_QUERY_RFC3986) + .Arr::query($parameters) .$this->buildFragment(); } diff --git a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php index edae03e9f74c..0841fca205ec 100644 --- a/src/Illuminate/Redis/Connectors/PhpRedisConnector.php +++ b/src/Illuminate/Redis/Connectors/PhpRedisConnector.php @@ -49,9 +49,9 @@ public function connectToCluster(array $config, array $clusterOptions, array $op */ protected function buildClusterConnectionString(array $server) { - return $server['host'].':'.$server['port'].'?'.http_build_query(Arr::only($server, [ + return $server['host'].':'.$server['port'].'?'.Arr::query(Arr::only($server, [ 'database', 'password', 'prefix', 'read_timeout', - ]), null, '&', PHP_QUERY_RFC3986); + ])); } /** diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index f12fa3bc84f2..a3525012d15a 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -261,11 +261,8 @@ protected function getRouteQueryString(array $parameters) return ''; } - $query = http_build_query( - $keyed = $this->getStringParameters($parameters), - null, - '&', - PHP_QUERY_RFC3986 + $query = Arr::query( + $keyed = $this->getStringParameters($parameters) ); // Lastly, if there are still parameters remaining, we will fetch the numeric diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 94b6013b4910..d87feccc995d 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -339,11 +339,8 @@ public function temporarySignedRoute($name, $expiration, $parameters = []) */ public function hasValidSignature(Request $request) { - $original = rtrim($request->url().'?'.http_build_query( - Arr::except($request->query(), 'signature'), - null, - '&', - PHP_QUERY_RFC3986 + $original = rtrim($request->url().'?'.Arr::query( + Arr::except($request->query(), 'signature') ), '?'); $expires = Arr::get($request->query(), 'expires'); diff --git a/src/Illuminate/Support/Arr.php b/src/Illuminate/Support/Arr.php index 616c030c5fe3..85d04b67fb01 100755 --- a/src/Illuminate/Support/Arr.php +++ b/src/Illuminate/Support/Arr.php @@ -594,6 +594,17 @@ public static function sortRecursive($array) return $array; } + /** + * Convert the array into a query string. + * + * @param array $array + * @return string + */ + public static function query($array) + { + return http_build_query($array, null, '&', PHP_QUERY_RFC3986); + } + /** * Filter the array using the given callback. * From e7481b13a0c98ce4987eb4b0d3370d2bb8226f8c Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 3 May 2018 18:55:17 +0200 Subject: [PATCH 0073/2459] [5.7] Move Carbon macro methods (#23938) * Use Carbon 1.26 * Update Carbon macro exception messages in unit tests --- composer.json | 2 +- src/Illuminate/Support/Carbon.php | 41 +---------------------------- tests/Support/SupportCarbonTest.php | 4 +-- 3 files changed, 4 insertions(+), 43 deletions(-) diff --git a/composer.json b/composer.json index 6d04153da17f..2930dce167e1 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "erusev/parsedown": "^1.7", "league/flysystem": "^1.0.8", "monolog/monolog": "^1.12", - "nesbot/carbon": "1.25.*", + "nesbot/carbon": "^1.26.3", "psr/container": "^1.0", "psr/simple-cache": "^1.0", "ramsey/uuid": "^3.7", diff --git a/src/Illuminate/Support/Carbon.php b/src/Illuminate/Support/Carbon.php index db1bdbef0121..d7f537f2a8db 100644 --- a/src/Illuminate/Support/Carbon.php +++ b/src/Illuminate/Support/Carbon.php @@ -2,47 +2,8 @@ namespace Illuminate\Support; -use JsonSerializable; use Carbon\Carbon as BaseCarbon; -use Illuminate\Support\Traits\Macroable; -class Carbon extends BaseCarbon implements JsonSerializable +class Carbon extends BaseCarbon { - use Macroable; - - /** - * The custom Carbon JSON serializer. - * - * @var callable|null - */ - protected static $serializer; - - /** - * Prepare the object for JSON serialization. - * - * @return array|string - */ - public function jsonSerialize() - { - if (static::$serializer) { - return call_user_func(static::$serializer, $this); - } - - $carbon = $this; - - return call_user_func(function () use ($carbon) { - return get_object_vars($carbon); - }); - } - - /** - * JSON serialize all Carbon instances using the given callback. - * - * @param callable $callback - * @return void - */ - public static function serializeUsing($callback) - { - static::$serializer = $callback; - } } diff --git a/tests/Support/SupportCarbonTest.php b/tests/Support/SupportCarbonTest.php index 186e7baf8a0c..d37420424e9d 100644 --- a/tests/Support/SupportCarbonTest.php +++ b/tests/Support/SupportCarbonTest.php @@ -58,7 +58,7 @@ public function testCarbonIsMacroableWhenCalledStatically() /** * @expectedException \BadMethodCallException - * @expectedExceptionMessage Method Illuminate\Support\Carbon::nonExistingStaticMacro does not exist. + * @expectedExceptionMessage nonExistingStaticMacro does not exist. */ public function testCarbonRaisesExceptionWhenStaticMacroIsNotFound() { @@ -67,7 +67,7 @@ public function testCarbonRaisesExceptionWhenStaticMacroIsNotFound() /** * @expectedException \BadMethodCallException - * @expectedExceptionMessage Method Illuminate\Support\Carbon::nonExistingMacro does not exist. + * @expectedExceptionMessage nonExistingMacro does not exist. */ public function testCarbonRaisesExceptionWhenMacroIsNotFound() { From 1e53e32302edd1ccdd06eacbcbf6e955616d7a02 Mon Sep 17 00:00:00 2001 From: DavidNineRoc <1033404553@qq.com> Date: Thu, 10 May 2018 11:12:05 +0800 Subject: [PATCH 0074/2459] Author: Roc <1033404553@qq.com> Date: Thu, 10 May 2018 03:15:47 +0000 * fixed InteractsWithPivotTable::caseKey return value type --- .../Concerns/InteractsWithPivotTable.php | 31 +++- ...ntBelongsToManySyncReturnValueTypeTest.php | 135 ++++++++++++++++++ 2 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index 83da64e83da7..26d8622a0be9 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -492,14 +492,17 @@ protected function castKeys(array $keys) } /** - * Cast the given key to an integer if it is numeric. + * Cast the given key to convert to primary key type. * * @param mixed $key * @return mixed */ protected function castKey($key) { - return is_numeric($key) ? (int) $key : (string) $key; + return $this->getTypeSwapValue( + $this->related->getKeyType(), + $key + ); } /** @@ -514,4 +517,28 @@ protected function castAttributes($attributes) ? $this->newPivot()->fill($attributes)->getAttributes() : $attributes; } + + /** + * Converts a given value to a given type value. + * + * @param string $type + * @param mixed $value + * @return mixed + */ + protected function getTypeSwapValue($type, $value) + { + switch (strtolower($type)) { + case 'int': + case 'integer': + return (int) $value; + case 'real': + case 'float': + case 'double': + return (float) $value; + case 'string': + return (string) $value; + default: + return $value; + } + } } diff --git a/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php b/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php new file mode 100644 index 000000000000..be12fc20dbbd --- /dev/null +++ b/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php @@ -0,0 +1,135 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->bootEloquent(); + $db->setAsGlobal(); + + $this->createSchema(); + } + + /** + * Setup the database schema. + * + * @return void + */ + public function createSchema() + { + $this->schema()->create('users', function ($table) { + $table->increments('id'); + $table->string('email')->unique(); + }); + + $this->schema()->create('articles', function ($table) { + $table->string('id'); + $table->string('title'); + + $table->primary('id'); + }); + + $this->schema()->create('article_user', function ($table) { + $table->string('article_id'); + $table->foreign('article_id')->references('id')->on('articles'); + $table->integer('user_id')->unsigned(); + $table->foreign('user_id')->references('id')->on('users'); + }); + } + + /** + * Tear down the database schema. + * + * @return void + */ + public function tearDown() + { + $this->schema()->drop('users'); + $this->schema()->drop('articles'); + $this->schema()->drop('article_user'); + } + + /** + * Helpers... + */ + protected function seedData() + { + BelongsToManySyncTestTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); + BelongsToManySyncTestTestArticle::insert([ + ['id' => '7b7306ae-5a02-46fa-a84c-9538f45c7dd4', 'title' => 'uuid title'], + ['id' => (string)(PHP_INT_MAX+1), 'title' => 'Another title'], + ['id' => '1', 'title' => 'Another title'] + ]); + } + + public function testSyncReturnValueType() + { + $this->seedData(); + + + $user = BelongsToManySyncTestTestUser::query()->first(); + $articleIDs = BelongsToManySyncTestTestArticle::all()->pluck('id')->toArray(); + + $changes = $user->articles()->sync($articleIDs); + + collect($changes['attached'])->map(function ($id) { + $this->assertTrue(gettype($id) === (new BelongsToManySyncTestTestArticle)->getKeyType()); + }); + } + + /** + * Get a database connection instance. + * + * @return Connection + */ + protected function connection() + { + return Eloquent::getConnectionResolver()->connection(); + } + + /** + * Get a schema builder instance. + * + * @return Schema\Builder + */ + protected function schema() + { + return $this->connection()->getSchemaBuilder(); + } +} + +class BelongsToManySyncTestTestUser extends Eloquent +{ + protected $table = 'users'; + protected $fillable = ['id', 'email']; + public $timestamps = false; + + public function articles() + { + return $this->belongsToMany(BelongsToManySyncTestTestArticle::class, 'article_user', 'user_id', 'article_id'); + } +} + + +class BelongsToManySyncTestTestArticle extends Eloquent +{ + protected $table = 'articles'; + protected $keyType = 'string'; + public $incrementing = false; + public $timestamps = false; + protected $fillable = ['id', 'title']; +} From 1d7eb4c39e428949c82179169e5aa689211ed34f Mon Sep 17 00:00:00 2001 From: Jad Haboush Date: Thu, 10 May 2018 18:18:09 +0100 Subject: [PATCH 0075/2459] Fix hashing classes not verifying algorithm Add additional check on hashing algorithm when checking a hashed value. An exception is thrown if algorithm does not match the one intended in the hasher. --- src/Illuminate/Hashing/ArgonHasher.php | 7 +++++++ src/Illuminate/Hashing/BcryptHasher.php | 7 +++++++ tests/Hashing/HasherTest.php | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php index e0c7f83e7bc3..fbdc3b38f59a 100644 --- a/src/Illuminate/Hashing/ArgonHasher.php +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -2,6 +2,7 @@ namespace Illuminate\Hashing; +use Exception; use RuntimeException; use Illuminate\Contracts\Hashing\Hasher as HasherContract; @@ -81,6 +82,8 @@ public function make($value, array $options = []) * @param string $hashedValue * @param array $options * @return bool + * + * @throws Exception */ public function check($value, $hashedValue, array $options = []) { @@ -88,6 +91,10 @@ public function check($value, $hashedValue, array $options = []) return false; } + if ($this->info($hashedValue)['algo'] !== PASSWORD_ARGON2I) { + throw new Exception('Hashing algorithm mismatch.'); + } + return password_verify($value, $hashedValue); } diff --git a/src/Illuminate/Hashing/BcryptHasher.php b/src/Illuminate/Hashing/BcryptHasher.php index d0fadfbda7b8..445b54458b9b 100755 --- a/src/Illuminate/Hashing/BcryptHasher.php +++ b/src/Illuminate/Hashing/BcryptHasher.php @@ -2,6 +2,7 @@ namespace Illuminate\Hashing; +use Exception; use RuntimeException; use Illuminate\Contracts\Hashing\Hasher as HasherContract; @@ -65,6 +66,8 @@ public function make($value, array $options = []) * @param string $hashedValue * @param array $options * @return bool + * + * @throws Exception */ public function check($value, $hashedValue, array $options = []) { @@ -72,6 +75,10 @@ public function check($value, $hashedValue, array $options = []) return false; } + if ($this->info($hashedValue)['algo'] !== PASSWORD_BCRYPT) { + throw new Exception('Hashing algorithm mismatch.'); + } + return password_verify($value, $hashedValue); } diff --git a/tests/Hashing/HasherTest.php b/tests/Hashing/HasherTest.php index 1d008a3e0c14..506cfb21fe9d 100755 --- a/tests/Hashing/HasherTest.php +++ b/tests/Hashing/HasherTest.php @@ -29,4 +29,26 @@ public function testBasicArgonHashing() $this->assertFalse($hasher->needsRehash($value)); $this->assertTrue($hasher->needsRehash($value, ['threads' => 1])); } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Hashing algorithm mismatch. + */ + public function testBasicBcryptVerification() + { + $argonHasher = new \Illuminate\Hashing\ArgonHasher; + $argonHashed = $argonHasher->make('password'); + (new \Illuminate\Hashing\BcryptHasher)->check('password', $argonHashed); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Hashing algorithm mismatch. + */ + public function testBasicVerification() + { + $bcryptHasher = new \Illuminate\Hashing\BcryptHasher; + $bcryptHashed = $bcryptHasher->make('password'); + (new \Illuminate\Hashing\ArgonHasher)->check('password', $bcryptHashed); + } } From c50a94e412e4fa95a854b6768d2a09f306e6868e Mon Sep 17 00:00:00 2001 From: Jad Haboush Date: Thu, 10 May 2018 21:01:49 +0100 Subject: [PATCH 0076/2459] Fix hashing classes not verifying algorithm Modified test on password info to check algoName instead. --- src/Illuminate/Hashing/ArgonHasher.php | 2 +- src/Illuminate/Hashing/BcryptHasher.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php index fbdc3b38f59a..47a65875bbeb 100644 --- a/src/Illuminate/Hashing/ArgonHasher.php +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -91,7 +91,7 @@ public function check($value, $hashedValue, array $options = []) return false; } - if ($this->info($hashedValue)['algo'] !== PASSWORD_ARGON2I) { + if ($this->info($hashedValue)['algoName'] !== 'argon2i') { throw new Exception('Hashing algorithm mismatch.'); } diff --git a/src/Illuminate/Hashing/BcryptHasher.php b/src/Illuminate/Hashing/BcryptHasher.php index 445b54458b9b..9c14eadad796 100755 --- a/src/Illuminate/Hashing/BcryptHasher.php +++ b/src/Illuminate/Hashing/BcryptHasher.php @@ -75,7 +75,7 @@ public function check($value, $hashedValue, array $options = []) return false; } - if ($this->info($hashedValue)['algo'] !== PASSWORD_BCRYPT) { + if ($this->info($hashedValue)['algoName'] !== 'bcrypt') { throw new Exception('Hashing algorithm mismatch.'); } From e9ee6ea22acf14e8de1240ca8e22623cc849e3af Mon Sep 17 00:00:00 2001 From: Jad Haboush Date: Thu, 10 May 2018 21:34:58 +0100 Subject: [PATCH 0077/2459] Fix hashing classes not verifying algorithm Now skipping `ArgonHasher` test on platforms where PHP isn't built with Argon support --- tests/Hashing/HasherTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/Hashing/HasherTest.php b/tests/Hashing/HasherTest.php index 506cfb21fe9d..0274701f2bc9 100755 --- a/tests/Hashing/HasherTest.php +++ b/tests/Hashing/HasherTest.php @@ -36,6 +36,10 @@ public function testBasicArgonHashing() */ public function testBasicBcryptVerification() { + if (! defined('PASSWORD_ARGON2I')) { + $this->markTestSkipped('PHP not compiled with argon2 hashing support.'); + } + $argonHasher = new \Illuminate\Hashing\ArgonHasher; $argonHashed = $argonHasher->make('password'); (new \Illuminate\Hashing\BcryptHasher)->check('password', $argonHashed); @@ -45,7 +49,7 @@ public function testBasicBcryptVerification() * @expectedException \Exception * @expectedExceptionMessage Hashing algorithm mismatch. */ - public function testBasicVerification() + public function testBasicArgonVerification() { $bcryptHasher = new \Illuminate\Hashing\BcryptHasher; $bcryptHashed = $bcryptHasher->make('password'); From 637014503c5147117f1f1c0ab81cfca049bf35b6 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 11 May 2018 08:04:00 -0500 Subject: [PATCH 0078/2459] formatting --- src/Illuminate/Hashing/ArgonHasher.php | 2 +- src/Illuminate/Hashing/BcryptHasher.php | 2 +- tests/Hashing/HasherTest.php | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php index 47a65875bbeb..86f775d2208e 100644 --- a/src/Illuminate/Hashing/ArgonHasher.php +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -92,7 +92,7 @@ public function check($value, $hashedValue, array $options = []) } if ($this->info($hashedValue)['algoName'] !== 'argon2i') { - throw new Exception('Hashing algorithm mismatch.'); + throw new Exception('This password does not use the Argon algorithm.'); } return password_verify($value, $hashedValue); diff --git a/src/Illuminate/Hashing/BcryptHasher.php b/src/Illuminate/Hashing/BcryptHasher.php index 9c14eadad796..1c886814d11f 100755 --- a/src/Illuminate/Hashing/BcryptHasher.php +++ b/src/Illuminate/Hashing/BcryptHasher.php @@ -76,7 +76,7 @@ public function check($value, $hashedValue, array $options = []) } if ($this->info($hashedValue)['algoName'] !== 'bcrypt') { - throw new Exception('Hashing algorithm mismatch.'); + throw new Exception('This password does not use the Bcrypt algorithm.'); } return password_verify($value, $hashedValue); diff --git a/tests/Hashing/HasherTest.php b/tests/Hashing/HasherTest.php index 0274701f2bc9..14e173634c4b 100755 --- a/tests/Hashing/HasherTest.php +++ b/tests/Hashing/HasherTest.php @@ -32,7 +32,6 @@ public function testBasicArgonHashing() /** * @expectedException \Exception - * @expectedExceptionMessage Hashing algorithm mismatch. */ public function testBasicBcryptVerification() { @@ -47,7 +46,6 @@ public function testBasicBcryptVerification() /** * @expectedException \Exception - * @expectedExceptionMessage Hashing algorithm mismatch. */ public function testBasicArgonVerification() { From 52a6e51d672ed65574733cc8be8652ebd2efad99 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 11 May 2018 08:04:35 -0500 Subject: [PATCH 0079/2459] Apply fixes from StyleCI (#24181) --- ...tabaseEloquentBelongsToManySyncReturnValueTypeTest.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php b/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php index be12fc20dbbd..e64b48cf5acf 100644 --- a/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php @@ -71,8 +71,8 @@ protected function seedData() BelongsToManySyncTestTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); BelongsToManySyncTestTestArticle::insert([ ['id' => '7b7306ae-5a02-46fa-a84c-9538f45c7dd4', 'title' => 'uuid title'], - ['id' => (string)(PHP_INT_MAX+1), 'title' => 'Another title'], - ['id' => '1', 'title' => 'Another title'] + ['id' => (string) (PHP_INT_MAX + 1), 'title' => 'Another title'], + ['id' => '1', 'title' => 'Another title'], ]); } @@ -80,14 +80,13 @@ public function testSyncReturnValueType() { $this->seedData(); - $user = BelongsToManySyncTestTestUser::query()->first(); $articleIDs = BelongsToManySyncTestTestArticle::all()->pluck('id')->toArray(); $changes = $user->articles()->sync($articleIDs); collect($changes['attached'])->map(function ($id) { - $this->assertTrue(gettype($id) === (new BelongsToManySyncTestTestArticle)->getKeyType()); + $this->assertTrue(gettype($id) === (new BelongsToManySyncTestTestArticle)->getKeyType()); }); } @@ -124,7 +123,6 @@ public function articles() } } - class BelongsToManySyncTestTestArticle extends Eloquent { protected $table = 'articles'; From 7dcff71f14b28fc2f69693ee63d9870e4e440659 Mon Sep 17 00:00:00 2001 From: Anton Komarev Date: Sat, 12 May 2018 02:39:23 +0300 Subject: [PATCH 0080/2459] Fix return types and DocBlocks code styling (#24183) --- src/Illuminate/Hashing/ArgonHasher.php | 7 ++++--- src/Illuminate/Hashing/BcryptHasher.php | 5 ++--- src/Illuminate/Hashing/HashManager.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php index 86f775d2208e..7049134b5a6c 100644 --- a/src/Illuminate/Hashing/ArgonHasher.php +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -2,7 +2,6 @@ namespace Illuminate\Hashing; -use Exception; use RuntimeException; use Illuminate\Contracts\Hashing\Hasher as HasherContract; @@ -59,6 +58,8 @@ public function info($hashedValue) * @param string $value * @param array $options * @return string + * + * @throws \RuntimeException */ public function make($value, array $options = []) { @@ -83,7 +84,7 @@ public function make($value, array $options = []) * @param array $options * @return bool * - * @throws Exception + * @throws \RuntimeException */ public function check($value, $hashedValue, array $options = []) { @@ -92,7 +93,7 @@ public function check($value, $hashedValue, array $options = []) } if ($this->info($hashedValue)['algoName'] !== 'argon2i') { - throw new Exception('This password does not use the Argon algorithm.'); + throw new RuntimeException('This password does not use the Argon algorithm.'); } return password_verify($value, $hashedValue); diff --git a/src/Illuminate/Hashing/BcryptHasher.php b/src/Illuminate/Hashing/BcryptHasher.php index 1c886814d11f..b5161a6423d2 100755 --- a/src/Illuminate/Hashing/BcryptHasher.php +++ b/src/Illuminate/Hashing/BcryptHasher.php @@ -2,7 +2,6 @@ namespace Illuminate\Hashing; -use Exception; use RuntimeException; use Illuminate\Contracts\Hashing\Hasher as HasherContract; @@ -67,7 +66,7 @@ public function make($value, array $options = []) * @param array $options * @return bool * - * @throws Exception + * @throws \RuntimeException */ public function check($value, $hashedValue, array $options = []) { @@ -76,7 +75,7 @@ public function check($value, $hashedValue, array $options = []) } if ($this->info($hashedValue)['algoName'] !== 'bcrypt') { - throw new Exception('This password does not use the Bcrypt algorithm.'); + throw new RuntimeException('This password does not use the Bcrypt algorithm.'); } return password_verify($value, $hashedValue); diff --git a/src/Illuminate/Hashing/HashManager.php b/src/Illuminate/Hashing/HashManager.php index 0d9ca759280a..9b96617cb670 100644 --- a/src/Illuminate/Hashing/HashManager.php +++ b/src/Illuminate/Hashing/HashManager.php @@ -10,7 +10,7 @@ class HashManager extends Manager implements Hasher /** * Create an instance of the Bcrypt hash Driver. * - * @return BcryptHasher + * @return \Illuminate\Hashing\BcryptHasher */ public function createBcryptDriver() { @@ -20,7 +20,7 @@ public function createBcryptDriver() /** * Create an instance of the Argon2 hash Driver. * - * @return ArgonHasher + * @return \Illuminate\Hashing\ArgonHasher */ public function createArgonDriver() { From f29b3cd37626c03354dbd1871d0d94073cbe6e1d Mon Sep 17 00:00:00 2001 From: Justin Seliga Date: Thu, 17 May 2018 09:35:52 -0400 Subject: [PATCH 0081/2459] Align Mailable dynamic parameter case to View (camel). (#24232) --- src/Illuminate/Mail/Mailable.php | 2 +- tests/Mail/MailMailableTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 81506b177999..3c2e2d08cf5e 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -776,7 +776,7 @@ public function withSwiftMessage($callback) public function __call($method, $parameters) { if (Str::startsWith($method, 'with')) { - return $this->with(Str::snake(substr($method, 4)), $parameters[0]); + return $this->with(Str::camel(substr($method, 4)), $parameters[0]); } throw new BadMethodCallException(sprintf( diff --git a/tests/Mail/MailMailableTest.php b/tests/Mail/MailMailableTest.php index 6120eed584c5..4ce9eb710919 100644 --- a/tests/Mail/MailMailableTest.php +++ b/tests/Mail/MailMailableTest.php @@ -109,7 +109,7 @@ public function testMailableBuildsViewData() $expected = [ 'first_name' => 'Taylor', - 'last_name' => 'Otwell', + 'lastName' => 'Otwell', 'framework' => 'Laravel', ]; From 75d239b354ea8c12a22bfb180e809e0c171b6bfb Mon Sep 17 00:00:00 2001 From: Ed Preston Date: Wed, 23 May 2018 23:22:11 +1000 Subject: [PATCH 0082/2459] update doc block (#24291) make returns `\Illuminate\Validation\Validator` --- src/Illuminate/Support/Facades/Validator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Validator.php b/src/Illuminate/Support/Facades/Validator.php index 1579c2660b6b..4f1bf5c38712 100755 --- a/src/Illuminate/Support/Facades/Validator.php +++ b/src/Illuminate/Support/Facades/Validator.php @@ -3,7 +3,7 @@ namespace Illuminate\Support\Facades; /** - * @method static \Illuminate\Contracts\Validation\Validator make(array $data, array $rules, array $messages = [], array $customAttributes = []) + * @method static \Illuminate\Validation\Validator make(array $data, array $rules, array $messages = [], array $customAttributes = []) * @method static void extend(string $rule, \Closure | string $extension, string $message = null) * @method static void extendImplicit(string $rule, \Closure | string $extension, string $message = null) * @method static void replacer(string $rule, \Closure | string $replacer) From dd59b17a93fdfc8594c9237b11f55f8df55b0242 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 23 May 2018 16:00:13 +0200 Subject: [PATCH 0083/2459] remove unneeded tests --- tests/Database/DatabaseEloquentIntegrationTest.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index fbcb4c15eb3d..836252182123 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -1151,7 +1151,6 @@ public function testTimestampsUsingDefaultDateFormat() 'created_at' => '2017-11-14 08:23:19', ]); - $this->assertEquals('2017-11-14 08:23:19.000000', $this->getRawDateTimeString($model->getAttribute('created_at'))); $this->assertEquals('2017-11-14 08:23:19', $model->fromDateTime($model->getAttribute('created_at'))); } @@ -1164,8 +1163,6 @@ public function testTimestampsUsingDefaultSqlServerDateFormat() 'updated_at' => '2017-11-14 08:23:19.734', ]); - $this->assertEquals('2017-11-14 08:23:19.000000', $this->getRawDateTimeString($model->getAttribute('created_at'))); - $this->assertEquals('2017-11-14 08:23:19.734000', $this->getRawDateTimeString($model->getAttribute('updated_at'))); $this->assertEquals('2017-11-14 08:23:19.000', $model->fromDateTime($model->getAttribute('created_at'))); $this->assertEquals('2017-11-14 08:23:19.734', $model->fromDateTime($model->getAttribute('updated_at'))); } @@ -1180,8 +1177,6 @@ public function testTimestampsUsingCustomDateFormat() 'updated_at' => '2017-11-14 08:23:19.7348', ]); - $this->assertEquals('2017-11-14 08:23:19.000000', $this->getRawDateTimeString($model->getAttribute('created_at'))); - $this->assertEquals('2017-11-14 08:23:19.734800', $this->getRawDateTimeString($model->getAttribute('updated_at'))); // Note: when storing databases would truncate the value to the given precision $this->assertEquals('2017-11-14 08:23:19.000000', $model->fromDateTime($model->getAttribute('created_at'))); $this->assertEquals('2017-11-14 08:23:19.734800', $model->fromDateTime($model->getAttribute('updated_at'))); @@ -1195,7 +1190,6 @@ public function testTimestampsUsingOldSqlServerDateFormat() 'created_at' => '2017-11-14 08:23:19.000', ]); - $this->assertEquals('2017-11-14 08:23:19.000000', $this->getRawDateTimeString($model->getAttribute('created_at'))); $this->assertEquals('2017-11-14 08:23:19.000', $model->fromDateTime($model->getAttribute('created_at'))); } @@ -1236,11 +1230,6 @@ protected function schema($connection = 'default') { return $this->connection($connection)->getSchemaBuilder(); } - - protected function getRawDateTimeString($object) - { - return (new ReflectionObject($object))->getProperty('date')->getValue($object); - } } /** From 0bf5f8ec0c519ccb558c3280b5ce09f4f3f7486e Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 23 May 2018 16:14:51 +0200 Subject: [PATCH 0084/2459] Apply fixes from StyleCI (#24292) --- tests/Database/DatabaseEloquentIntegrationTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index 836252182123..56d817a4c6e4 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -3,7 +3,6 @@ namespace Illuminate\Tests\Database; use Exception; -use ReflectionObject; use PHPUnit\Framework\TestCase; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\SoftDeletes; From 5bd6c713a8b0c7716236c2d0485d4f20927a4866 Mon Sep 17 00:00:00 2001 From: Ed Preston Date: Thu, 24 May 2018 23:07:44 +1000 Subject: [PATCH 0085/2459] reset doc block (#24300) Request to revert #24291 as discussed on that pull request. --- src/Illuminate/Support/Facades/Validator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Validator.php b/src/Illuminate/Support/Facades/Validator.php index 4f1bf5c38712..1579c2660b6b 100755 --- a/src/Illuminate/Support/Facades/Validator.php +++ b/src/Illuminate/Support/Facades/Validator.php @@ -3,7 +3,7 @@ namespace Illuminate\Support\Facades; /** - * @method static \Illuminate\Validation\Validator make(array $data, array $rules, array $messages = [], array $customAttributes = []) + * @method static \Illuminate\Contracts\Validation\Validator make(array $data, array $rules, array $messages = [], array $customAttributes = []) * @method static void extend(string $rule, \Closure | string $extension, string $message = null) * @method static void extendImplicit(string $rule, \Closure | string $extension, string $message = null) * @method static void replacer(string $rule, \Closure | string $replacer) From 5f87d93b1697d66e9e82f4a681f3e0317ac7e30f Mon Sep 17 00:00:00 2001 From: Rob Taylor Date: Fri, 25 May 2018 10:17:58 +0100 Subject: [PATCH 0086/2459] Add support for Gate::define() callback to be the name of an invokable class --- src/Illuminate/Auth/Access/Gate.php | 12 +++++++++--- tests/Auth/AuthAccessGateTest.php | 26 +++++++++++++++++--------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index dfc72cf02ac7..7fd1490bf933 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -108,7 +108,7 @@ public function define($ability, $callback) { if (is_callable($callback)) { $this->abilities[$ability] = $callback; - } elseif (is_string($callback) && Str::contains($callback, '@')) { + } elseif (is_string($callback)) { $this->abilities[$ability] = $this->buildAbilityCallback($ability, $callback); } else { throw new InvalidArgumentException("Callback must be a callable or a 'Class@method' string."); @@ -151,7 +151,11 @@ public function resource($name, $class, array $abilities = null) protected function buildAbilityCallback($ability, $callback) { return function () use ($ability, $callback) { - list($class, $method) = Str::parseCallback($callback); + if (Str::contains($callback, '@')) { + list($class, $method) = Str::parseCallback($callback); + } else { + $class = $callback; + } $policy = $this->resolvePolicy($class); @@ -167,7 +171,9 @@ protected function buildAbilityCallback($ability, $callback) return $result; } - return $policy->{$method}(...func_get_args()); + return isset($method) ? + $policy->{$method}(...func_get_args()) + : $policy(...func_get_args()); }; } diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index 30a8a9aa85e5..4a935606742a 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -11,15 +11,6 @@ class GateTest extends TestCase { - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Callback must be a callable or a 'Class@method' - */ - public function test_gate_throws_exception_on_invalid_callback_type() - { - $this->getBasicGate()->define('foo', 'foo'); - } - public function test_basic_closures_can_be_defined() { $gate = $this->getBasicGate(); @@ -171,6 +162,15 @@ public function test_classes_can_be_defined_as_callbacks_using_at_notation() $this->assertTrue($gate->check('foo')); } + public function test_invokable_classes_can_be_defined() + { + $gate = $this->getBasicGate(); + + $gate->define('foo', '\Illuminate\Tests\Auth\AccessGateTestInvokableClass'); + + $this->assertTrue($gate->check('foo')); + } + public function test_policy_classes_can_be_defined_to_handle_checks_for_given_type() { $gate = $this->getBasicGate(); @@ -383,6 +383,14 @@ public function foo() } } +class AccessGateTestInvokableClass +{ + public function __invoke() + { + return true; + } +} + interface AccessGateTestDummyInterface { // From 65107b0bfdaabd8728aa75e65ede5530a851d0fd Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 25 May 2018 09:31:25 -0500 Subject: [PATCH 0087/2459] formatting --- src/Illuminate/Auth/Access/Gate.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 5f8c5fb7faf5..d301c42b403a 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -152,7 +152,7 @@ protected function buildAbilityCallback($ability, $callback) { return function () use ($ability, $callback) { if (Str::contains($callback, '@')) { - list($class, $method) = Str::parseCallback($callback); + [$class, $method] = Str::parseCallback($callback); } else { $class = $callback; } @@ -171,9 +171,9 @@ protected function buildAbilityCallback($ability, $callback) return $result; } - return isset($method) ? - $policy->{$method}(...func_get_args()) - : $policy(...func_get_args()); + return isset($method) + ? $policy->{$method}(...func_get_args()) + : $policy(...func_get_args()); }; } From 51d5f2f5452f5ebedd6445f8b7a7321e8e903ef8 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sat, 2 Jun 2018 17:30:48 +0300 Subject: [PATCH 0088/2459] Allow use `formatScheme` method in `UrlGenerator` without parameter. (#24419) - in the Laravel Framework we already have the case, when we need call the urlGenerator in `RouteUrlGenerator`. --- src/Illuminate/Routing/RouteUrlGenerator.php | 2 +- src/Illuminate/Routing/UrlGenerator.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Routing/RouteUrlGenerator.php b/src/Illuminate/Routing/RouteUrlGenerator.php index 61f590ec7e4b..4a82b4f5cdba 100644 --- a/src/Illuminate/Routing/RouteUrlGenerator.php +++ b/src/Illuminate/Routing/RouteUrlGenerator.php @@ -149,7 +149,7 @@ protected function getRouteScheme($route) return 'https://'; } - return $this->url->formatScheme(null); + return $this->url->formatScheme(); } /** diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index d87feccc995d..5bddc9e81545 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -282,7 +282,7 @@ protected function removeIndex($root) * @param bool|null $secure * @return string */ - public function formatScheme($secure) + public function formatScheme($secure = null) { if (! is_null($secure)) { return $secure ? 'https://' : 'http://'; From 520fb03d1fe8f019c79a4f49744ae36ab44bed51 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Sat, 2 Jun 2018 16:34:47 +0200 Subject: [PATCH 0089/2459] Use assertCount(). (#24411) --- .../Database/DatabaseEloquentHasManyTest.php | 4 +-- .../DatabaseEloquentIntegrationTest.php | 30 +++++++++---------- ...EloquentIntegrationWithTablePrefixTest.php | 2 +- ...entPolymorphicRelationsIntegrationTest.php | 12 ++++---- .../DatabaseMySqlSchemaGrammarTest.php | 2 +- .../Database/EloquentDeleteTest.php | 4 +-- .../Database/EloquentUpdateTest.php | 4 +-- tests/Support/SupportViewErrorBagTest.php | 6 ++-- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/tests/Database/DatabaseEloquentHasManyTest.php b/tests/Database/DatabaseEloquentHasManyTest.php index 038fe47b0c4b..05efea776a40 100755 --- a/tests/Database/DatabaseEloquentHasManyTest.php +++ b/tests/Database/DatabaseEloquentHasManyTest.php @@ -231,10 +231,10 @@ public function testModelsAreProperlyMatchedToParents() $models = $relation->match([$model1, $model2, $model3], new Collection([$result1, $result2, $result3]), 'foo'); $this->assertEquals(1, $models[0]->foo[0]->foreign_key); - $this->assertEquals(1, count($models[0]->foo)); + $this->assertCount(1, $models[0]->foo); $this->assertEquals(2, $models[1]->foo[0]->foreign_key); $this->assertEquals(2, $models[1]->foo[1]->foreign_key); - $this->assertEquals(2, count($models[1]->foo)); + $this->assertCount(2, $models[1]->foo); $this->assertNull($models[2]->foo); } diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index 56d817a4c6e4..3641f82b5be6 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -158,11 +158,11 @@ public function testBasicModelRetrieval() $collection = EloquentTestUser::find([]); $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $collection); - $this->assertEquals(0, $collection->count()); + $this->assertCount(0, $collection); $collection = EloquentTestUser::find([1, 2, 3]); $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $collection); - $this->assertEquals(2, $collection->count()); + $this->assertCount(2, $collection); $models = EloquentTestUser::where('id', 1)->cursor(); foreach ($models as $model) { @@ -187,7 +187,7 @@ public function testBasicModelCollectionRetrieval() $models = EloquentTestUser::oldest('id')->get(); - $this->assertEquals(2, $models->count()); + $this->assertCount(2, $models); $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $models); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestUser', $models[0]); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestUser', $models[1]); @@ -206,7 +206,7 @@ public function testPaginatedModelCollectionRetrieval() }); $models = EloquentTestUser::oldest('id')->paginate(2); - $this->assertEquals(2, $models->count()); + $this->assertCount(2, $models); $this->assertInstanceOf('Illuminate\Pagination\LengthAwarePaginator', $models); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestUser', $models[0]); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestUser', $models[1]); @@ -218,7 +218,7 @@ public function testPaginatedModelCollectionRetrieval() }); $models = EloquentTestUser::oldest('id')->paginate(2); - $this->assertEquals(1, $models->count()); + $this->assertCount(1, $models); $this->assertInstanceOf('Illuminate\Pagination\LengthAwarePaginator', $models); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestUser', $models[0]); $this->assertEquals('foo@gmail.com', $models[0]->email); @@ -231,7 +231,7 @@ public function testPaginatedModelCollectionRetrievalWhenNoElements() }); $models = EloquentTestUser::oldest('id')->paginate(2); - $this->assertEquals(0, $models->count()); + $this->assertCount(0, $models); $this->assertInstanceOf('Illuminate\Pagination\LengthAwarePaginator', $models); Paginator::currentPageResolver(function () { @@ -239,14 +239,14 @@ public function testPaginatedModelCollectionRetrievalWhenNoElements() }); $models = EloquentTestUser::oldest('id')->paginate(2); - $this->assertEquals(0, $models->count()); + $this->assertCount(0, $models); } public function testPaginatedModelCollectionRetrievalWhenNoElementsAndDefaultPerPage() { $models = EloquentTestUser::oldest('id')->paginate(); - $this->assertEquals(0, $models->count()); + $this->assertCount(0, $models); $this->assertInstanceOf('Illuminate\Pagination\LengthAwarePaginator', $models); } @@ -459,7 +459,7 @@ public function testOneToManyRelationship() $post2 = $user->posts()->where('name', 'Second Post')->first(); $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $posts); - $this->assertEquals(2, $posts->count()); + $this->assertCount(2, $posts); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestPost', $posts[0]); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestPost', $posts[1]); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestPost', $post2); @@ -484,7 +484,7 @@ public function testBasicModelHydration() $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestUser', $models[0]); $this->assertEquals('abigailotwell@gmail.com', $models[0]->email); $this->assertEquals('second_connection', $models[0]->getConnectionName()); - $this->assertEquals(1, $models->count()); + $this->assertCount(1, $models); } public function testHasOnSelfReferencingBelongsToManyRelationship() @@ -744,8 +744,8 @@ public function testBasicMorphManyRelationship() $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestPhoto', $user->photos[0]); $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $post->photos); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestPhoto', $post->photos[0]); - $this->assertEquals(2, $user->photos->count()); - $this->assertEquals(2, $post->photos->count()); + $this->assertCount(2, $user->photos); + $this->assertCount(2, $post->photos); $this->assertEquals('Avatar 1', $user->photos[0]->name); $this->assertEquals('Avatar 2', $user->photos[1]->name); $this->assertEquals('Hero 1', $post->photos[0]->name); @@ -754,7 +754,7 @@ public function testBasicMorphManyRelationship() $photos = EloquentTestPhoto::orderBy('name')->get(); $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $photos); - $this->assertEquals(4, $photos->count()); + $this->assertCount(4, $photos); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestUser', $photos[0]->imageable); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestPost', $photos[2]->imageable); $this->assertEquals('taylorotwell@gmail.com', $photos[1]->imageable->email); @@ -779,8 +779,8 @@ public function testMorphMapIsUsedForCreatingAndFetchingThroughRelation() $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestPhoto', $user->photos[0]); $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $post->photos); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestPhoto', $post->photos[0]); - $this->assertEquals(2, $user->photos->count()); - $this->assertEquals(2, $post->photos->count()); + $this->assertCount(2, $user->photos); + $this->assertCount(2, $post->photos); $this->assertEquals('Avatar 1', $user->photos[0]->name); $this->assertEquals('Avatar 2', $user->photos[1]->name); $this->assertEquals('Hero 1', $post->photos[0]->name); diff --git a/tests/Database/DatabaseEloquentIntegrationWithTablePrefixTest.php b/tests/Database/DatabaseEloquentIntegrationWithTablePrefixTest.php index 8dd97969054c..6a5388e924c6 100644 --- a/tests/Database/DatabaseEloquentIntegrationWithTablePrefixTest.php +++ b/tests/Database/DatabaseEloquentIntegrationWithTablePrefixTest.php @@ -87,7 +87,7 @@ public function testBasicModelHydration() $this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $models); $this->assertInstanceOf('Illuminate\Tests\Database\EloquentTestUser', $models[0]); $this->assertEquals('abigailotwell@gmail.com', $models[0]->email); - $this->assertEquals(1, $models->count()); + $this->assertCount(1, $models); } /** diff --git a/tests/Database/DatabaseEloquentPolymorphicRelationsIntegrationTest.php b/tests/Database/DatabaseEloquentPolymorphicRelationsIntegrationTest.php index c61a7da99cfd..b71af961a3df 100644 --- a/tests/Database/DatabaseEloquentPolymorphicRelationsIntegrationTest.php +++ b/tests/Database/DatabaseEloquentPolymorphicRelationsIntegrationTest.php @@ -81,12 +81,12 @@ public function testCreation() $post->tags()->attach($tag2->id); $image->tags()->attach($tag->id); - $this->assertEquals(2, $post->tags->count()); - $this->assertEquals(1, $image->tags->count()); - $this->assertEquals(1, $tag->posts->count()); - $this->assertEquals(1, $tag->images->count()); - $this->assertEquals(1, $tag2->posts->count()); - $this->assertEquals(0, $tag2->images->count()); + $this->assertCount(2, $post->tags); + $this->assertCount(1, $image->tags); + $this->assertCount(1, $tag->posts); + $this->assertCount(1, $tag->images); + $this->assertCount(1, $tag2->posts); + $this->assertCount(0, $tag2->images); } public function testEagerLoading() diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index c949fb442201..341f94468ceb 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -930,7 +930,7 @@ public function testAddingComment() $blueprint->string('foo')->comment("Escape ' when using words like it's"); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertEquals(1, count($statements)); + $this->assertCount(1, $statements); $this->assertEquals("alter table `users` add `foo` varchar(255) not null comment 'Escape \\' when using words like it\\'s'", $statements[0]); } diff --git a/tests/Integration/Database/EloquentDeleteTest.php b/tests/Integration/Database/EloquentDeleteTest.php index fddcf8c2ae11..95c7c5fb2776 100644 --- a/tests/Integration/Database/EloquentDeleteTest.php +++ b/tests/Integration/Database/EloquentDeleteTest.php @@ -58,10 +58,10 @@ public function testOnlyDeleteWhatGiven() } Post::latest('id')->limit(1)->delete(); - $this->assertEquals(9, Post::all()->count()); + $this->assertCount(9, Post::all()); Post::join('comments', 'comments.post_id', '=', 'posts.id')->where('posts.id', '>', 1)->orderBy('posts.id')->limit(1)->delete(); - $this->assertEquals(8, Post::all()->count()); + $this->assertCount(8, Post::all()); } public function testForceDeletedEventIsFired() diff --git a/tests/Integration/Database/EloquentUpdateTest.php b/tests/Integration/Database/EloquentUpdateTest.php index dcb0c56c7c60..baf1712d20dc 100644 --- a/tests/Integration/Database/EloquentUpdateTest.php +++ b/tests/Integration/Database/EloquentUpdateTest.php @@ -53,7 +53,7 @@ public function testBasicUpdate() TestUpdateModel1::where('title', 'Ms.')->delete(); - $this->assertEquals(0, TestUpdateModel1::all()->count()); + $this->assertCount(0, TestUpdateModel1::all()); } public function testUpdateWithLimitsAndOrders() @@ -105,7 +105,7 @@ public function testSoftDeleteWithJoins() ->where('test_model1.title', '=', 'Mr.'); })->delete(); - $this->assertEquals(0, TestUpdateModel2::all()->count()); + $this->assertCount(0, TestUpdateModel2::all()); } } diff --git a/tests/Support/SupportViewErrorBagTest.php b/tests/Support/SupportViewErrorBagTest.php index 9558ed7e501d..9dbacd08c1db 100755 --- a/tests/Support/SupportViewErrorBagTest.php +++ b/tests/Support/SupportViewErrorBagTest.php @@ -80,20 +80,20 @@ public function testCount() { $viewErrorBag = new ViewErrorBag(); $viewErrorBag->put('default', new MessageBag(['message', 'second'])); - $this->assertEquals(2, $viewErrorBag->count()); + $this->assertCount(2, $viewErrorBag); } public function testCountWithNoMessagesInMessageBag() { $viewErrorBag = new ViewErrorBag(); $viewErrorBag->put('default', new MessageBag()); - $this->assertEquals(0, $viewErrorBag->count()); + $this->assertCount(0, $viewErrorBag); } public function testCountWithNoMessageBags() { $viewErrorBag = new ViewErrorBag(); - $this->assertEquals(0, $viewErrorBag->count()); + $this->assertCount(0, $viewErrorBag); } public function testDynamicCallToDefaultMessageBag() From 21da25ad65e465f49127b19c480d5e593eb59a88 Mon Sep 17 00:00:00 2001 From: Nguyen Xuan Quynh Date: Mon, 4 Jun 2018 20:50:27 +0700 Subject: [PATCH 0090/2459] Unnecessary to check EventDispatcher on Logger constructor (#24441) --- src/Illuminate/Log/Logger.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Illuminate/Log/Logger.php b/src/Illuminate/Log/Logger.php index e2010846c85b..76df3b0f3f88 100755 --- a/src/Illuminate/Log/Logger.php +++ b/src/Illuminate/Log/Logger.php @@ -36,10 +36,7 @@ class Logger implements LoggerInterface public function __construct(LoggerInterface $logger, Dispatcher $dispatcher = null) { $this->logger = $logger; - - if (isset($dispatcher)) { - $this->dispatcher = $dispatcher; - } + $this->dispatcher = $dispatcher; } /** From 52481d4fb32d995f375afa19a5590b99b58498fa Mon Sep 17 00:00:00 2001 From: Samuel Ryan Date: Mon, 4 Jun 2018 14:54:57 +0100 Subject: [PATCH 0091/2459] Default Route::redirect to a 302 instead of a 301 (#24434) --- src/Illuminate/Routing/Router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 156656eda225..246f64f313dd 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -236,7 +236,7 @@ public function fallback($action) * @param int $status * @return \Illuminate\Routing\Route */ - public function redirect($uri, $destination, $status = 301) + public function redirect($uri, $destination, $status = 302) { return $this->any($uri, '\Illuminate\Routing\RedirectController') ->defaults('destination', $destination) From b63701a2b9508c14b9074882231b804204e4d941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Gonz=C3=A1lez?= Date: Mon, 4 Jun 2018 08:56:55 -0500 Subject: [PATCH 0092/2459] Standardize the console commands help output (#24432) Remove the period at the end of the options and arguments of console commands that have it. Now all commands use the same format. --- src/Illuminate/Cache/Console/ClearCommand.php | 4 ++-- .../Database/Console/Migrations/FreshCommand.php | 12 ++++++------ .../Database/Console/Migrations/InstallCommand.php | 2 +- .../Database/Console/Migrations/MigrateCommand.php | 14 +++++++------- .../Console/Migrations/MigrateMakeCommand.php | 10 +++++----- .../Database/Console/Migrations/RefreshCommand.php | 14 +++++++------- .../Database/Console/Migrations/ResetCommand.php | 10 +++++----- .../Console/Migrations/RollbackCommand.php | 12 ++++++------ .../Database/Console/Migrations/StatusCommand.php | 6 +++--- .../Database/Console/Seeds/SeedCommand.php | 2 +- .../Foundation/Console/AppNameCommand.php | 2 +- .../Foundation/Console/ConsoleMakeCommand.php | 4 ++-- src/Illuminate/Foundation/Console/DownCommand.php | 6 +++--- .../Foundation/Console/ExceptionMakeCommand.php | 4 ++-- .../Foundation/Console/JobMakeCommand.php | 2 +- .../Foundation/Console/ListenerMakeCommand.php | 4 ++-- .../Foundation/Console/MailMakeCommand.php | 4 ++-- .../Foundation/Console/ModelMakeCommand.php | 8 ++++---- .../Foundation/Console/NotificationMakeCommand.php | 4 ++-- .../Foundation/Console/PolicyMakeCommand.php | 2 +- .../Foundation/Console/ResourceMakeCommand.php | 2 +- .../Foundation/Console/RouteListCommand.php | 10 +++++----- src/Illuminate/Foundation/Console/ServeCommand.php | 4 ++-- .../Foundation/Console/VendorPublishCommand.php | 8 ++++---- .../Queue/Console/ForgetFailedCommand.php | 2 +- src/Illuminate/Queue/Console/RetryCommand.php | 2 +- .../Routing/Console/ControllerMakeCommand.php | 8 ++++---- 27 files changed, 81 insertions(+), 81 deletions(-) diff --git a/src/Illuminate/Cache/Console/ClearCommand.php b/src/Illuminate/Cache/Console/ClearCommand.php index 34f2a4d878aa..ccf8957f67f7 100755 --- a/src/Illuminate/Cache/Console/ClearCommand.php +++ b/src/Illuminate/Cache/Console/ClearCommand.php @@ -123,7 +123,7 @@ protected function tags() protected function getArguments() { return [ - ['store', InputArgument::OPTIONAL, 'The name of the store you would like to clear.'], + ['store', InputArgument::OPTIONAL, 'The name of the store you would like to clear'], ]; } @@ -135,7 +135,7 @@ protected function getArguments() protected function getOptions() { return [ - ['tags', null, InputOption::VALUE_OPTIONAL, 'The cache tags you would like to clear.', null], + ['tags', null, InputOption::VALUE_OPTIONAL, 'The cache tags you would like to clear', null], ]; } } diff --git a/src/Illuminate/Database/Console/Migrations/FreshCommand.php b/src/Illuminate/Database/Console/Migrations/FreshCommand.php index 39dec79128bf..235d5e88b461 100644 --- a/src/Illuminate/Database/Console/Migrations/FreshCommand.php +++ b/src/Illuminate/Database/Console/Migrations/FreshCommand.php @@ -98,17 +98,17 @@ protected function runSeeder($database) protected function getOptions() { return [ - ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'], + ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], - ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'], + ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], - ['path', null, InputOption::VALUE_OPTIONAL, 'The path to the migrations files to be executed.'], + ['path', null, InputOption::VALUE_OPTIONAL, 'The path to the migrations files to be executed'], - ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths.'], + ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], - ['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run.'], + ['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run'], - ['seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder.'], + ['seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder'], ]; } } diff --git a/src/Illuminate/Database/Console/Migrations/InstallCommand.php b/src/Illuminate/Database/Console/Migrations/InstallCommand.php index d9200240bea4..354d7a1c167e 100755 --- a/src/Illuminate/Database/Console/Migrations/InstallCommand.php +++ b/src/Illuminate/Database/Console/Migrations/InstallCommand.php @@ -64,7 +64,7 @@ public function handle() protected function getOptions() { return [ - ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'], + ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], ]; } } diff --git a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php index dbeaed418b12..5c7a8045d659 100755 --- a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php +++ b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php @@ -14,13 +14,13 @@ class MigrateCommand extends BaseCommand * * @var string */ - protected $signature = 'migrate {--database= : The database connection to use.} - {--force : Force the operation to run when in production.} - {--path= : The path to the migrations files to be executed.} - {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths.} - {--pretend : Dump the SQL queries that would be run.} - {--seed : Indicates if the seed task should be re-run.} - {--step : Force the migrations to be run so they can be rolled back individually.}'; + protected $signature = 'migrate {--database= : The database connection to use} + {--force : Force the operation to run when in production} + {--path= : The path to the migrations files to be executed} + {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths} + {--pretend : Dump the SQL queries that would be run} + {--seed : Indicates if the seed task should be re-run} + {--step : Force the migrations to be run so they can be rolled back individually}'; /** * The console command description. diff --git a/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php b/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php index aafd973f17f1..e0bfc079e4a0 100644 --- a/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php +++ b/src/Illuminate/Database/Console/Migrations/MigrateMakeCommand.php @@ -13,11 +13,11 @@ class MigrateMakeCommand extends BaseCommand * * @var string */ - protected $signature = 'make:migration {name : The name of the migration.} - {--create= : The table to be created.} - {--table= : The table to migrate.} - {--path= : The location where the migration file should be created.} - {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths.}'; + protected $signature = 'make:migration {name : The name of the migration} + {--create= : The table to be created} + {--table= : The table to migrate} + {--path= : The location where the migration file should be created} + {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}'; /** * The console command description. diff --git a/src/Illuminate/Database/Console/Migrations/RefreshCommand.php b/src/Illuminate/Database/Console/Migrations/RefreshCommand.php index 866b2133f092..64e892fc3db2 100755 --- a/src/Illuminate/Database/Console/Migrations/RefreshCommand.php +++ b/src/Illuminate/Database/Console/Migrations/RefreshCommand.php @@ -138,19 +138,19 @@ protected function runSeeder($database) protected function getOptions() { return [ - ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'], + ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], - ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'], + ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], - ['path', null, InputOption::VALUE_OPTIONAL, 'The path to the migrations files to be executed.'], + ['path', null, InputOption::VALUE_OPTIONAL, 'The path to the migrations files to be executed'], - ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths.'], + ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], - ['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run.'], + ['seed', null, InputOption::VALUE_NONE, 'Indicates if the seed task should be re-run'], - ['seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder.'], + ['seeder', null, InputOption::VALUE_OPTIONAL, 'The class name of the root seeder'], - ['step', null, InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted & re-run.'], + ['step', null, InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted & re-run'], ]; } } diff --git a/src/Illuminate/Database/Console/Migrations/ResetCommand.php b/src/Illuminate/Database/Console/Migrations/ResetCommand.php index c887ac494e7b..e883402a2e74 100755 --- a/src/Illuminate/Database/Console/Migrations/ResetCommand.php +++ b/src/Illuminate/Database/Console/Migrations/ResetCommand.php @@ -84,15 +84,15 @@ public function handle() protected function getOptions() { return [ - ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'], + ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], - ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'], + ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], - ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed.'], + ['path', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'The path(s) to the migrations files to be executed'], - ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths.'], + ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], - ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'], + ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run'], ]; } } diff --git a/src/Illuminate/Database/Console/Migrations/RollbackCommand.php b/src/Illuminate/Database/Console/Migrations/RollbackCommand.php index eac23263ce9d..8005149dff5f 100755 --- a/src/Illuminate/Database/Console/Migrations/RollbackCommand.php +++ b/src/Illuminate/Database/Console/Migrations/RollbackCommand.php @@ -80,17 +80,17 @@ public function handle() protected function getOptions() { return [ - ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'], + ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], - ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'], + ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], - ['path', null, InputOption::VALUE_OPTIONAL, 'The path to the migrations files to be executed.'], + ['path', null, InputOption::VALUE_OPTIONAL, 'The path to the migrations files to be executed'], - ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths.'], + ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], - ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run.'], + ['pretend', null, InputOption::VALUE_NONE, 'Dump the SQL queries that would be run'], - ['step', null, InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted.'], + ['step', null, InputOption::VALUE_OPTIONAL, 'The number of migrations to be reverted'], ]; } } diff --git a/src/Illuminate/Database/Console/Migrations/StatusCommand.php b/src/Illuminate/Database/Console/Migrations/StatusCommand.php index 53168a1019f5..520f6c7f4401 100644 --- a/src/Illuminate/Database/Console/Migrations/StatusCommand.php +++ b/src/Illuminate/Database/Console/Migrations/StatusCommand.php @@ -103,11 +103,11 @@ protected function getAllMigrationFiles() protected function getOptions() { return [ - ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use.'], + ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to use'], - ['path', null, InputOption::VALUE_OPTIONAL, 'The path to the migrations files to use.'], + ['path', null, InputOption::VALUE_OPTIONAL, 'The path to the migrations files to use'], - ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths.'], + ['realpath', null, InputOption::VALUE_NONE, 'Indicate any provided migration file paths are pre-resolved absolute paths'], ]; } } diff --git a/src/Illuminate/Database/Console/Seeds/SeedCommand.php b/src/Illuminate/Database/Console/Seeds/SeedCommand.php index 248987320b96..b719312a6db5 100644 --- a/src/Illuminate/Database/Console/Seeds/SeedCommand.php +++ b/src/Illuminate/Database/Console/Seeds/SeedCommand.php @@ -100,7 +100,7 @@ protected function getOptions() ['database', null, InputOption::VALUE_OPTIONAL, 'The database connection to seed'], - ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production.'], + ['force', null, InputOption::VALUE_NONE, 'Force the operation to run when in production'], ]; } } diff --git a/src/Illuminate/Foundation/Console/AppNameCommand.php b/src/Illuminate/Foundation/Console/AppNameCommand.php index e92b7a8f3719..4ed13ec3fb48 100644 --- a/src/Illuminate/Foundation/Console/AppNameCommand.php +++ b/src/Illuminate/Foundation/Console/AppNameCommand.php @@ -290,7 +290,7 @@ protected function getConfigPath($name) protected function getArguments() { return [ - ['name', InputArgument::REQUIRED, 'The desired namespace.'], + ['name', InputArgument::REQUIRED, 'The desired namespace'], ]; } } diff --git a/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php b/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php index a9b164b97a85..54183e90f143 100644 --- a/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ConsoleMakeCommand.php @@ -72,7 +72,7 @@ protected function getDefaultNamespace($rootNamespace) protected function getArguments() { return [ - ['name', InputArgument::REQUIRED, 'The name of the command.'], + ['name', InputArgument::REQUIRED, 'The name of the command'], ]; } @@ -84,7 +84,7 @@ protected function getArguments() protected function getOptions() { return [ - ['command', null, InputOption::VALUE_OPTIONAL, 'The terminal command that should be assigned.', 'command:name'], + ['command', null, InputOption::VALUE_OPTIONAL, 'The terminal command that should be assigned', 'command:name'], ]; } } diff --git a/src/Illuminate/Foundation/Console/DownCommand.php b/src/Illuminate/Foundation/Console/DownCommand.php index 4382ccc2e1d5..ff1e5943b959 100644 --- a/src/Illuminate/Foundation/Console/DownCommand.php +++ b/src/Illuminate/Foundation/Console/DownCommand.php @@ -14,9 +14,9 @@ class DownCommand extends Command * * @var string */ - protected $signature = 'down {--message= : The message for the maintenance mode. } - {--retry= : The number of seconds after which the request may be retried.} - {--allow=* : IP or networks allowed to access the application while in maintenance mode.}'; + protected $signature = 'down {--message= : The message for the maintenance mode} + {--retry= : The number of seconds after which the request may be retried} + {--allow=* : IP or networks allowed to access the application while in maintenance mode}'; /** * The console command description. diff --git a/src/Illuminate/Foundation/Console/ExceptionMakeCommand.php b/src/Illuminate/Foundation/Console/ExceptionMakeCommand.php index d81476db01ac..2bc0e6c32ea0 100644 --- a/src/Illuminate/Foundation/Console/ExceptionMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ExceptionMakeCommand.php @@ -76,9 +76,9 @@ protected function getDefaultNamespace($rootNamespace) protected function getOptions() { return [ - ['render', null, InputOption::VALUE_NONE, 'Create the exception with an empty render method.'], + ['render', null, InputOption::VALUE_NONE, 'Create the exception with an empty render method'], - ['report', null, InputOption::VALUE_NONE, 'Create the exception with an empty report method.'], + ['report', null, InputOption::VALUE_NONE, 'Create the exception with an empty report method'], ]; } } diff --git a/src/Illuminate/Foundation/Console/JobMakeCommand.php b/src/Illuminate/Foundation/Console/JobMakeCommand.php index af0067207b74..60d942eb0f27 100644 --- a/src/Illuminate/Foundation/Console/JobMakeCommand.php +++ b/src/Illuminate/Foundation/Console/JobMakeCommand.php @@ -59,7 +59,7 @@ protected function getDefaultNamespace($rootNamespace) protected function getOptions() { return [ - ['sync', null, InputOption::VALUE_NONE, 'Indicates that job should be synchronous.'], + ['sync', null, InputOption::VALUE_NONE, 'Indicates that job should be synchronous'], ]; } } diff --git a/src/Illuminate/Foundation/Console/ListenerMakeCommand.php b/src/Illuminate/Foundation/Console/ListenerMakeCommand.php index ce3e25ef059f..c13bfbb92c71 100644 --- a/src/Illuminate/Foundation/Console/ListenerMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ListenerMakeCommand.php @@ -104,9 +104,9 @@ protected function getDefaultNamespace($rootNamespace) protected function getOptions() { return [ - ['event', 'e', InputOption::VALUE_OPTIONAL, 'The event class being listened for.'], + ['event', 'e', InputOption::VALUE_OPTIONAL, 'The event class being listened for'], - ['queued', null, InputOption::VALUE_NONE, 'Indicates the event listener should be queued.'], + ['queued', null, InputOption::VALUE_NONE, 'Indicates the event listener should be queued'], ]; } } diff --git a/src/Illuminate/Foundation/Console/MailMakeCommand.php b/src/Illuminate/Foundation/Console/MailMakeCommand.php index 6b97fa987c32..d401a9ec45be 100644 --- a/src/Illuminate/Foundation/Console/MailMakeCommand.php +++ b/src/Illuminate/Foundation/Console/MailMakeCommand.php @@ -108,9 +108,9 @@ protected function getDefaultNamespace($rootNamespace) protected function getOptions() { return [ - ['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the mailable already exists.'], + ['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the mailable already exists'], - ['markdown', 'm', InputOption::VALUE_OPTIONAL, 'Create a new Markdown template for the mailable.'], + ['markdown', 'm', InputOption::VALUE_OPTIONAL, 'Create a new Markdown template for the mailable'], ]; } } diff --git a/src/Illuminate/Foundation/Console/ModelMakeCommand.php b/src/Illuminate/Foundation/Console/ModelMakeCommand.php index 071b52883fd9..d5ffbb617da0 100644 --- a/src/Illuminate/Foundation/Console/ModelMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ModelMakeCommand.php @@ -146,13 +146,13 @@ protected function getOptions() ['factory', 'f', InputOption::VALUE_NONE, 'Create a new factory for the model'], - ['force', null, InputOption::VALUE_NONE, 'Create the class even if the model already exists.'], + ['force', null, InputOption::VALUE_NONE, 'Create the class even if the model already exists'], - ['migration', 'm', InputOption::VALUE_NONE, 'Create a new migration file for the model.'], + ['migration', 'm', InputOption::VALUE_NONE, 'Create a new migration file for the model'], - ['pivot', 'p', InputOption::VALUE_NONE, 'Indicates if the generated model should be a custom intermediate table model.'], + ['pivot', 'p', InputOption::VALUE_NONE, 'Indicates if the generated model should be a custom intermediate table model'], - ['resource', 'r', InputOption::VALUE_NONE, 'Indicates if the generated controller should be a resource controller.'], + ['resource', 'r', InputOption::VALUE_NONE, 'Indicates if the generated controller should be a resource controller'], ]; } } diff --git a/src/Illuminate/Foundation/Console/NotificationMakeCommand.php b/src/Illuminate/Foundation/Console/NotificationMakeCommand.php index 43c62678bc38..40e9d849f3ad 100644 --- a/src/Illuminate/Foundation/Console/NotificationMakeCommand.php +++ b/src/Illuminate/Foundation/Console/NotificationMakeCommand.php @@ -108,9 +108,9 @@ protected function getDefaultNamespace($rootNamespace) protected function getOptions() { return [ - ['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the notification already exists.'], + ['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the notification already exists'], - ['markdown', 'm', InputOption::VALUE_OPTIONAL, 'Create a new Markdown template for the notification.'], + ['markdown', 'm', InputOption::VALUE_OPTIONAL, 'Create a new Markdown template for the notification'], ]; } } diff --git a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php index c360d0f39df7..9124de71d65f 100644 --- a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php +++ b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php @@ -136,7 +136,7 @@ protected function getDefaultNamespace($rootNamespace) protected function getOptions() { return [ - ['model', 'm', InputOption::VALUE_OPTIONAL, 'The model that the policy applies to.'], + ['model', 'm', InputOption::VALUE_OPTIONAL, 'The model that the policy applies to'], ]; } } diff --git a/src/Illuminate/Foundation/Console/ResourceMakeCommand.php b/src/Illuminate/Foundation/Console/ResourceMakeCommand.php index fd74a8ec74bf..4419e737ea2e 100644 --- a/src/Illuminate/Foundation/Console/ResourceMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ResourceMakeCommand.php @@ -85,7 +85,7 @@ protected function getDefaultNamespace($rootNamespace) protected function getOptions() { return [ - ['collection', 'c', InputOption::VALUE_NONE, 'Create a resource collection.'], + ['collection', 'c', InputOption::VALUE_NONE, 'Create a resource collection'], ]; } } diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index e5e963ce0381..12af805e61d6 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -178,15 +178,15 @@ protected function filterRoute(array $route) protected function getOptions() { return [ - ['method', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by method.'], + ['method', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by method'], - ['name', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by name.'], + ['name', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by name'], - ['path', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by path.'], + ['path', null, InputOption::VALUE_OPTIONAL, 'Filter the routes by path'], - ['reverse', 'r', InputOption::VALUE_NONE, 'Reverse the ordering of the routes.'], + ['reverse', 'r', InputOption::VALUE_NONE, 'Reverse the ordering of the routes'], - ['sort', null, InputOption::VALUE_OPTIONAL, 'The column (host, method, uri, name, action, middleware) to sort by.', 'uri'], + ['sort', null, InputOption::VALUE_OPTIONAL, 'The column (host, method, uri, name, action, middleware) to sort by', 'uri'], ]; } } diff --git a/src/Illuminate/Foundation/Console/ServeCommand.php b/src/Illuminate/Foundation/Console/ServeCommand.php index c81e9c0f8c16..376f53b23e04 100644 --- a/src/Illuminate/Foundation/Console/ServeCommand.php +++ b/src/Illuminate/Foundation/Console/ServeCommand.php @@ -84,9 +84,9 @@ protected function port() protected function getOptions() { return [ - ['host', null, InputOption::VALUE_OPTIONAL, 'The host address to serve the application on.', '127.0.0.1'], + ['host', null, InputOption::VALUE_OPTIONAL, 'The host address to serve the application on', '127.0.0.1'], - ['port', null, InputOption::VALUE_OPTIONAL, 'The port to serve the application on.', 8000], + ['port', null, InputOption::VALUE_OPTIONAL, 'The port to serve the application on', 8000], ]; } } diff --git a/src/Illuminate/Foundation/Console/VendorPublishCommand.php b/src/Illuminate/Foundation/Console/VendorPublishCommand.php index 686f26b70a0b..03a80bfeea2a 100644 --- a/src/Illuminate/Foundation/Console/VendorPublishCommand.php +++ b/src/Illuminate/Foundation/Console/VendorPublishCommand.php @@ -38,10 +38,10 @@ class VendorPublishCommand extends Command * * @var string */ - protected $signature = 'vendor:publish {--force : Overwrite any existing files.} - {--all : Publish assets for all service providers without prompt.} - {--provider= : The service provider that has assets you want to publish.} - {--tag=* : One or many tags that have assets you want to publish.}'; + protected $signature = 'vendor:publish {--force : Overwrite any existing files} + {--all : Publish assets for all service providers without prompt} + {--provider= : The service provider that has assets you want to publish} + {--tag=* : One or many tags that have assets you want to publish}'; /** * The console command description. diff --git a/src/Illuminate/Queue/Console/ForgetFailedCommand.php b/src/Illuminate/Queue/Console/ForgetFailedCommand.php index dc04d948ab5b..b8eecb96dfcd 100644 --- a/src/Illuminate/Queue/Console/ForgetFailedCommand.php +++ b/src/Illuminate/Queue/Console/ForgetFailedCommand.php @@ -11,7 +11,7 @@ class ForgetFailedCommand extends Command * * @var string */ - protected $signature = 'queue:forget {id : The ID of the failed job.}'; + protected $signature = 'queue:forget {id : The ID of the failed job}'; /** * The console command description. diff --git a/src/Illuminate/Queue/Console/RetryCommand.php b/src/Illuminate/Queue/Console/RetryCommand.php index 5ea49d53d385..96fb9e389201 100644 --- a/src/Illuminate/Queue/Console/RetryCommand.php +++ b/src/Illuminate/Queue/Console/RetryCommand.php @@ -12,7 +12,7 @@ class RetryCommand extends Command * * @var string */ - protected $signature = 'queue:retry {id* : The ID of the failed job or "all" to retry all jobs.}'; + protected $signature = 'queue:retry {id* : The ID of the failed job or "all" to retry all jobs}'; /** * The console command description. diff --git a/src/Illuminate/Routing/Console/ControllerMakeCommand.php b/src/Illuminate/Routing/Console/ControllerMakeCommand.php index 664bc15f2d36..5336849410f5 100755 --- a/src/Illuminate/Routing/Console/ControllerMakeCommand.php +++ b/src/Illuminate/Routing/Console/ControllerMakeCommand.php @@ -172,13 +172,13 @@ protected function parseModel($model) protected function getOptions() { return [ - ['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a resource controller for the given model.'], + ['model', 'm', InputOption::VALUE_OPTIONAL, 'Generate a resource controller for the given model'], - ['resource', 'r', InputOption::VALUE_NONE, 'Generate a resource controller class.'], + ['resource', 'r', InputOption::VALUE_NONE, 'Generate a resource controller class'], - ['parent', 'p', InputOption::VALUE_OPTIONAL, 'Generate a nested resource controller class.'], + ['parent', 'p', InputOption::VALUE_OPTIONAL, 'Generate a nested resource controller class'], - ['api', null, InputOption::VALUE_NONE, 'Exclude the create and edit methods from the controller.'], + ['api', null, InputOption::VALUE_NONE, 'Exclude the create and edit methods from the controller'], ]; } } From 5673a197d91b1a40563dff59c0e7dcc4c74003a5 Mon Sep 17 00:00:00 2001 From: Derek MacDonald Date: Wed, 21 Mar 2018 21:30:03 -0400 Subject: [PATCH 0093/2459] Mailables can hook into LocaleUpdated Allow mailables to translate timestamps, money currency, etc. in Mailable body content by adding LocaleUpdated event listeners. --- src/Illuminate/Mail/Mailable.php | 5 +-- src/Illuminate/Support/Traits/Localizable.php | 19 ++++++----- .../Mail/Fixtures/timestamp.blade.php | 1 + .../Mail/SendingMailWithLocaleTest.php | 34 +++++++++++++++++++ 4 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 tests/Integration/Mail/Fixtures/timestamp.blade.php diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 6848e29137c4..d998b0a7de3f 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -12,7 +12,6 @@ use Illuminate\Support\Traits\Localizable; use Illuminate\Contracts\Support\Renderable; use Illuminate\Contracts\Queue\Factory as Queue; -use Illuminate\Contracts\Translation\Translator; use Illuminate\Contracts\Mail\Mailer as MailerContract; use Illuminate\Contracts\Mail\Mailable as MailableContract; use Illuminate\Contracts\Filesystem\Factory as FilesystemFactory; @@ -134,9 +133,7 @@ class Mailable implements MailableContract, Renderable */ public function send(MailerContract $mailer) { - $translator = Container::getInstance()->make(Translator::class); - - $this->withLocale($this->locale, $translator, function () use ($mailer) { + $this->withLocale($this->locale, function () use ($mailer) { Container::getInstance()->call([$this, 'build']); $mailer->send($this->buildView(), $this->buildViewData(), function ($message) { diff --git a/src/Illuminate/Support/Traits/Localizable.php b/src/Illuminate/Support/Traits/Localizable.php index b26996200244..0381415200eb 100644 --- a/src/Illuminate/Support/Traits/Localizable.php +++ b/src/Illuminate/Support/Traits/Localizable.php @@ -2,30 +2,33 @@ namespace Illuminate\Support\Traits; +use Illuminate\Container\Container; + trait Localizable { /** * Run the callback with the given locale. * - * @param string $locale - * @param \Illuminate\Contracts\Translation\Translator $translator - * @param \Closure $callback + * @param string $locale + * @param \Closure $callback * @return bool */ - public function withLocale($locale, $translator, $callback) + public function withLocale($locale, $callback) { - if (! $locale || ! $translator) { + if (! $locale) { return $callback(); } - $original = $translator->getLocale(); + $app = Container::getInstance(); + + $original = $app->getLocale(); try { - $translator->setLocale($locale); + $app->setLocale($locale); return $callback(); } finally { - $translator->setLocale($original); + $app->setLocale($original); } } } diff --git a/tests/Integration/Mail/Fixtures/timestamp.blade.php b/tests/Integration/Mail/Fixtures/timestamp.blade.php new file mode 100644 index 000000000000..774e558b2f98 --- /dev/null +++ b/tests/Integration/Mail/Fixtures/timestamp.blade.php @@ -0,0 +1 @@ +{{__('nom')}} {{ Illuminate\Support\Carbon::tomorrow()->diffForHumans() }} diff --git a/tests/Integration/Mail/SendingMailWithLocaleTest.php b/tests/Integration/Mail/SendingMailWithLocaleTest.php index c58e30c6f218..fc98034677b0 100644 --- a/tests/Integration/Mail/SendingMailWithLocaleTest.php +++ b/tests/Integration/Mail/SendingMailWithLocaleTest.php @@ -4,9 +4,12 @@ use Mockery; use Illuminate\Mail\Mailable; +use Illuminate\Support\Carbon; use Orchestra\Testbench\TestCase; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\View; +use Illuminate\Support\Facades\Event; +use Illuminate\Foundation\Events\LocaleUpdated; /** * @group integration @@ -35,6 +38,7 @@ protected function getEnvironmentSetUp($app) '*' => [ 'en' => ['nom' => 'name'], 'ar' => ['nom' => 'esm'], + 'es' => ['nom' => 'nombre'], ], ], ]); @@ -63,6 +67,23 @@ public function test_mail_is_sent_with_selected_locale() ); } + public function test_mail_is_sent_with_locale_updated_listeners_called() + { + Carbon::setTestNow(Carbon::parse('2018-04-01')); + + Event::listen(LocaleUpdated::class, function ($event) { + Carbon::setLocale($event->locale); + }); + + Mail::to('test@mail.com')->locale('es')->send(new TimestampTestMail); + + $this->assertContains('nombre dentro de 1 día', + app('swift.transport')->messages()[0]->getBody() + ); + + $this->assertEquals('en', Carbon::getLocale()); + } + public function test_locale_is_set_back_to_default_after_mail_sent() { Mail::to('test@mail.com')->locale('ar')->send(new TestMail()); @@ -92,3 +113,16 @@ public function build() return $this->view('view'); } } + +class TimestampTestMail extends Mailable +{ + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this->view('timestamp'); + } +} From 05c001e3c1293fe984eaeb6bed3fd8e6eed1c750 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 5 Jun 2018 15:42:55 +0300 Subject: [PATCH 0094/2459] Return `$this` from setters within the `Connection` class. (#24449) - this PR is unified the setters within the `Connection` class. - in `setDatabaseName` method `return` PhpDoc Match to the real value. --- src/Illuminate/Database/Connection.php | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Connection.php b/src/Illuminate/Database/Connection.php index 4b416c393ca1..0de81560da2f 100755 --- a/src/Illuminate/Database/Connection.php +++ b/src/Illuminate/Database/Connection.php @@ -1026,11 +1026,13 @@ public function getQueryGrammar() * Set the query grammar used by the connection. * * @param \Illuminate\Database\Query\Grammars\Grammar $grammar - * @return void + * @return $this */ public function setQueryGrammar(Query\Grammars\Grammar $grammar) { $this->queryGrammar = $grammar; + + return $this; } /** @@ -1047,11 +1049,13 @@ public function getSchemaGrammar() * Set the schema grammar used by the connection. * * @param \Illuminate\Database\Schema\Grammars\Grammar $grammar - * @return void + * @return $this */ public function setSchemaGrammar(Schema\Grammars\Grammar $grammar) { $this->schemaGrammar = $grammar; + + return $this; } /** @@ -1068,11 +1072,13 @@ public function getPostProcessor() * Set the query post processor used by the connection. * * @param \Illuminate\Database\Query\Processors\Processor $processor - * @return void + * @return $this */ public function setPostProcessor(Processor $processor) { $this->postProcessor = $processor; + + return $this; } /** @@ -1089,11 +1095,13 @@ public function getEventDispatcher() * Set the event dispatcher instance on the connection. * * @param \Illuminate\Contracts\Events\Dispatcher $events - * @return void + * @return $this */ public function setEventDispatcher(Dispatcher $events) { $this->events = $events; + + return $this; } /** @@ -1180,11 +1188,13 @@ public function getDatabaseName() * Set the name of the connected database. * * @param string $database - * @return string + * @return $this */ public function setDatabaseName($database) { $this->database = $database; + + return $this; } /** @@ -1201,13 +1211,15 @@ public function getTablePrefix() * Set the table prefix in use by the connection. * * @param string $prefix - * @return void + * @return $this */ public function setTablePrefix($prefix) { $this->tablePrefix = $prefix; $this->getQueryGrammar()->setTablePrefix($prefix); + + return $this; } /** From 98421e50d004dbe045000680b502016ea0e18bed Mon Sep 17 00:00:00 2001 From: Oleksii Bilotserkivskyi Date: Mon, 4 Jun 2018 18:20:18 +0300 Subject: [PATCH 0095/2459] Database migration - add schema column definition meta class --- src/Illuminate/Database/Schema/Blueprint.php | 114 +++++++++--------- .../Database/Schema/ColumnDefinition.php | 25 ++++ 2 files changed, 82 insertions(+), 57 deletions(-) create mode 100644 src/Illuminate/Database/Schema/ColumnDefinition.php diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 3d5c11b2d790..52e929d9c25d 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -24,7 +24,7 @@ class Blueprint /** * The columns that should be added to the table. * - * @var \Illuminate\Support\Fluent[] + * @var \Illuminate\Database\Schema\ColumnDefinition[] */ protected $columns = []; @@ -520,7 +520,7 @@ public function foreign($columns, $name = null) * Create a new auto-incrementing integer (4-byte) column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function increments($column) { @@ -531,7 +531,7 @@ public function increments($column) * Create a new auto-incrementing tiny integer (1-byte) column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function tinyIncrements($column) { @@ -542,7 +542,7 @@ public function tinyIncrements($column) * Create a new auto-incrementing small integer (2-byte) column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function smallIncrements($column) { @@ -553,7 +553,7 @@ public function smallIncrements($column) * Create a new auto-incrementing medium integer (3-byte) column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function mediumIncrements($column) { @@ -564,7 +564,7 @@ public function mediumIncrements($column) * Create a new auto-incrementing big integer (8-byte) column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function bigIncrements($column) { @@ -576,7 +576,7 @@ public function bigIncrements($column) * * @param string $column * @param int $length - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function char($column, $length = null) { @@ -590,7 +590,7 @@ public function char($column, $length = null) * * @param string $column * @param int $length - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function string($column, $length = null) { @@ -603,7 +603,7 @@ public function string($column, $length = null) * Create a new text column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function text($column) { @@ -614,7 +614,7 @@ public function text($column) * Create a new medium text column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function mediumText($column) { @@ -625,7 +625,7 @@ public function mediumText($column) * Create a new long text column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function longText($column) { @@ -638,7 +638,7 @@ public function longText($column) * @param string $column * @param bool $autoIncrement * @param bool $unsigned - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function integer($column, $autoIncrement = false, $unsigned = false) { @@ -651,7 +651,7 @@ public function integer($column, $autoIncrement = false, $unsigned = false) * @param string $column * @param bool $autoIncrement * @param bool $unsigned - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function tinyInteger($column, $autoIncrement = false, $unsigned = false) { @@ -664,7 +664,7 @@ public function tinyInteger($column, $autoIncrement = false, $unsigned = false) * @param string $column * @param bool $autoIncrement * @param bool $unsigned - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function smallInteger($column, $autoIncrement = false, $unsigned = false) { @@ -677,7 +677,7 @@ public function smallInteger($column, $autoIncrement = false, $unsigned = false) * @param string $column * @param bool $autoIncrement * @param bool $unsigned - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function mediumInteger($column, $autoIncrement = false, $unsigned = false) { @@ -690,7 +690,7 @@ public function mediumInteger($column, $autoIncrement = false, $unsigned = false * @param string $column * @param bool $autoIncrement * @param bool $unsigned - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function bigInteger($column, $autoIncrement = false, $unsigned = false) { @@ -702,7 +702,7 @@ public function bigInteger($column, $autoIncrement = false, $unsigned = false) * * @param string $column * @param bool $autoIncrement - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedInteger($column, $autoIncrement = false) { @@ -714,7 +714,7 @@ public function unsignedInteger($column, $autoIncrement = false) * * @param string $column * @param bool $autoIncrement - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedTinyInteger($column, $autoIncrement = false) { @@ -726,7 +726,7 @@ public function unsignedTinyInteger($column, $autoIncrement = false) * * @param string $column * @param bool $autoIncrement - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedSmallInteger($column, $autoIncrement = false) { @@ -738,7 +738,7 @@ public function unsignedSmallInteger($column, $autoIncrement = false) * * @param string $column * @param bool $autoIncrement - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedMediumInteger($column, $autoIncrement = false) { @@ -750,7 +750,7 @@ public function unsignedMediumInteger($column, $autoIncrement = false) * * @param string $column * @param bool $autoIncrement - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedBigInteger($column, $autoIncrement = false) { @@ -763,7 +763,7 @@ public function unsignedBigInteger($column, $autoIncrement = false) * @param string $column * @param int $total * @param int $places - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function float($column, $total = 8, $places = 2) { @@ -776,7 +776,7 @@ public function float($column, $total = 8, $places = 2) * @param string $column * @param int|null $total * @param int|null $places - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function double($column, $total = null, $places = null) { @@ -789,7 +789,7 @@ public function double($column, $total = null, $places = null) * @param string $column * @param int $total * @param int $places - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function decimal($column, $total = 8, $places = 2) { @@ -802,7 +802,7 @@ public function decimal($column, $total = 8, $places = 2) * @param string $column * @param int $total * @param int $places - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function unsignedDecimal($column, $total = 8, $places = 2) { @@ -815,7 +815,7 @@ public function unsignedDecimal($column, $total = 8, $places = 2) * Create a new boolean column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function boolean($column) { @@ -827,7 +827,7 @@ public function boolean($column) * * @param string $column * @param array $allowed - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function enum($column, array $allowed) { @@ -838,7 +838,7 @@ public function enum($column, array $allowed) * Create a new json column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function json($column) { @@ -849,7 +849,7 @@ public function json($column) * Create a new jsonb column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function jsonb($column) { @@ -860,7 +860,7 @@ public function jsonb($column) * Create a new date column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function date($column) { @@ -872,7 +872,7 @@ public function date($column) * * @param string $column * @param int $precision - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function dateTime($column, $precision = 0) { @@ -884,7 +884,7 @@ public function dateTime($column, $precision = 0) * * @param string $column * @param int $precision - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function dateTimeTz($column, $precision = 0) { @@ -896,7 +896,7 @@ public function dateTimeTz($column, $precision = 0) * * @param string $column * @param int $precision - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function time($column, $precision = 0) { @@ -908,7 +908,7 @@ public function time($column, $precision = 0) * * @param string $column * @param int $precision - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function timeTz($column, $precision = 0) { @@ -920,7 +920,7 @@ public function timeTz($column, $precision = 0) * * @param string $column * @param int $precision - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function timestamp($column, $precision = 0) { @@ -932,7 +932,7 @@ public function timestamp($column, $precision = 0) * * @param string $column * @param int $precision - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function timestampTz($column, $precision = 0) { @@ -983,7 +983,7 @@ public function timestampsTz($precision = 0) * * @param string $column * @param int $precision - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function softDeletes($column = 'deleted_at', $precision = 0) { @@ -995,7 +995,7 @@ public function softDeletes($column = 'deleted_at', $precision = 0) * * @param string $column * @param int $precision - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function softDeletesTz($column = 'deleted_at', $precision = 0) { @@ -1006,7 +1006,7 @@ public function softDeletesTz($column = 'deleted_at', $precision = 0) * Create a new year column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function year($column) { @@ -1017,7 +1017,7 @@ public function year($column) * Create a new binary column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function binary($column) { @@ -1028,7 +1028,7 @@ public function binary($column) * Create a new uuid column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function uuid($column) { @@ -1039,7 +1039,7 @@ public function uuid($column) * Create a new IP address column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function ipAddress($column) { @@ -1050,7 +1050,7 @@ public function ipAddress($column) * Create a new MAC address column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function macAddress($column) { @@ -1061,7 +1061,7 @@ public function macAddress($column) * Create a new geometry column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function geometry($column) { @@ -1073,7 +1073,7 @@ public function geometry($column) * * @param string $column * @param null|int $srid - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function point($column, $srid = null) { @@ -1084,7 +1084,7 @@ public function point($column, $srid = null) * Create a new linestring column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function lineString($column) { @@ -1095,7 +1095,7 @@ public function lineString($column) * Create a new polygon column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function polygon($column) { @@ -1106,7 +1106,7 @@ public function polygon($column) * Create a new geometrycollection column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function geometryCollection($column) { @@ -1117,7 +1117,7 @@ public function geometryCollection($column) * Create a new multipoint column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function multiPoint($column) { @@ -1128,7 +1128,7 @@ public function multiPoint($column) * Create a new multilinestring column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function multiLineString($column) { @@ -1139,7 +1139,7 @@ public function multiLineString($column) * Create a new multipolygon column on the table. * * @param string $column - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function multiPolygon($column) { @@ -1181,7 +1181,7 @@ public function nullableMorphs($name, $indexName = null) /** * Adds the `remember_token` column to the table. * - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function rememberToken() { @@ -1253,11 +1253,11 @@ protected function createIndexName($type, array $columns) * @param string $type * @param string $name * @param array $parameters - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Database\Schema\ColumnDefinition */ public function addColumn($type, $name, array $parameters = []) { - $this->columns[] = $column = new Fluent( + $this->columns[] = $column = new ColumnDefinition( array_merge(compact('type', 'name'), $parameters) ); @@ -1318,7 +1318,7 @@ public function getTable() /** * Get the columns on the blueprint. * - * @return \Illuminate\Support\Fluent[] + * @return \Illuminate\Database\Schema\ColumnDefinition[] */ public function getColumns() { @@ -1338,7 +1338,7 @@ public function getCommands() /** * Get the columns on the blueprint that should be added. * - * @return \Illuminate\Support\Fluent[] + * @return \Illuminate\Database\Schema\ColumnDefinition[] */ public function getAddedColumns() { @@ -1350,7 +1350,7 @@ public function getAddedColumns() /** * Get the columns on the blueprint that should be changed. * - * @return \Illuminate\Support\Fluent[] + * @return \Illuminate\Database\Schema\ColumnDefinition[] */ public function getChangedColumns() { diff --git a/src/Illuminate/Database/Schema/ColumnDefinition.php b/src/Illuminate/Database/Schema/ColumnDefinition.php new file mode 100644 index 000000000000..43e4ea11cd18 --- /dev/null +++ b/src/Illuminate/Database/Schema/ColumnDefinition.php @@ -0,0 +1,25 @@ + Date: Tue, 5 Jun 2018 14:20:34 -0500 Subject: [PATCH 0096/2459] initial commit of trait based instance initializers proof of concept --- src/Illuminate/Database/Eloquent/Model.php | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 443f09e8b545..af5d8cc4cd11 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -117,6 +117,13 @@ abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializab */ protected static $booted = []; + /** + * The array of trait initializers that will be called on each new instance + * + * @var array + */ + protected static $traitInitializers = []; + /** * The array of global scopes on the model. * @@ -148,6 +155,8 @@ public function __construct(array $attributes = []) { $this->bootIfNotBooted(); + $this->initializeTraits(); + $this->syncOriginal(); $this->fill($attributes); @@ -190,10 +199,24 @@ protected static function bootTraits() { $class = static::class; + static::$traitInitializers[$class] = []; + foreach (class_uses_recursive($class) as $trait) { if (method_exists($class, $method = 'boot'.class_basename($trait))) { forward_static_call([$class, $method]); } + if (method_exists($class, $method = 'initialize'.class_basename($trait))) { + static::$traitInitializers[$class][] = $method; + } + } + } + + protected function initializeTraits() + { + $class = static::class; + + foreach (static::$traitInitializers[$class] as $method) { + $this->{$method}(); } } From a2f3c4aee6e85263404439c2fbf02178b8f38cce Mon Sep 17 00:00:00 2001 From: Ralph Schindler Date: Tue, 5 Jun 2018 14:20:57 -0500 Subject: [PATCH 0097/2459] trait initializer tests --- tests/Database/DatabaseEloquentModelTest.php | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 436999653d74..cec7a0895d6b 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -1367,6 +1367,12 @@ public function testModelIsBootedOnUnserialize() $this->assertTrue(EloquentModelBootingTestStub::isBooted()); } + public function testModelsTraitIsInitialized() + { + $model = new EloquentModelStubWithTrait; + $this->assertTrue($model->fooBarIsInitialized); + } + public function testAppendingOfAttributes() { $model = new EloquentModelAppendsStub; @@ -1853,6 +1859,21 @@ public function scopeFramework(Builder $builder, $framework, $version) } } +trait FooBarTrait +{ + public $fooBarIsInitialized = false; + + public function initializeFooBarTrait() + { + $this->fooBarIsInitialized = true; + } +} + +class EloquentModelStubWithTrait extends EloquentModelStub +{ + use FooBarTrait; +} + class EloquentModelCamelStub extends EloquentModelStub { public static $snakeAttributes = false; From d28cbf2f04a7a174a00cd06f2138f27e58b0e540 Mon Sep 17 00:00:00 2001 From: Ralph Schindler Date: Tue, 5 Jun 2018 15:27:22 -0500 Subject: [PATCH 0098/2459] style fixes --- src/Illuminate/Database/Eloquent/Model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index af5d8cc4cd11..c16dda7883d3 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -118,7 +118,7 @@ abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializab protected static $booted = []; /** - * The array of trait initializers that will be called on each new instance + * The array of trait initializers that will be called on each new instance. * * @var array */ From ea3b5e5300be3824cee30dfa9608d27d8432addf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=89=E6=98=8E?= Date: Wed, 6 Jun 2018 21:18:16 +0800 Subject: [PATCH 0099/2459] Add exit status to WorkStopping event. (#24476) --- src/Illuminate/Queue/Events/WorkerStopping.php | 18 +++++++++++++++++- src/Illuminate/Queue/Worker.php | 4 ++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Queue/Events/WorkerStopping.php b/src/Illuminate/Queue/Events/WorkerStopping.php index 6c51209cf539..6d49bb2092ac 100644 --- a/src/Illuminate/Queue/Events/WorkerStopping.php +++ b/src/Illuminate/Queue/Events/WorkerStopping.php @@ -4,5 +4,21 @@ class WorkerStopping { - // + /** + * The exit status. + * + * @var int + */ + public $status; + + /** + * Create a new event instance. + * + * @param int $status + * @return void + */ + public function __construct($status = 0) + { + $this->status = $status; + } } diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 13699cca9d83..3d3ab0508a12 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -552,7 +552,7 @@ public function memoryExceeded($memoryLimit) */ public function stop($status = 0) { - $this->events->dispatch(new Events\WorkerStopping); + $this->events->dispatch(new Events\WorkerStopping($status)); exit($status); } @@ -565,7 +565,7 @@ public function stop($status = 0) */ public function kill($status = 0) { - $this->events->dispatch(new Events\WorkerStopping); + $this->events->dispatch(new Events\WorkerStopping($status)); if (extension_loaded('posix')) { posix_kill(getmypid(), SIGKILL); From 0cab06b58765a70dcb7af1e4758e538190b375ee Mon Sep 17 00:00:00 2001 From: Ralph Schindler Date: Wed, 6 Jun 2018 13:30:36 -0500 Subject: [PATCH 0100/2459] added docblock and removed extraneous variable declaration --- src/Illuminate/Database/Eloquent/Model.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index c16dda7883d3..adea21e3a968 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -211,11 +211,14 @@ protected static function bootTraits() } } + /** + * Initialize any initializable traits on the model. + * + * @return void + */ protected function initializeTraits() { - $class = static::class; - - foreach (static::$traitInitializers[$class] as $method) { + foreach (static::$traitInitializers[static::class] as $method) { $this->{$method}(); } } From 1e9b90daaad14802f0f26bcb014659fe0a0fe982 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Thu, 7 Jun 2018 02:58:06 +0200 Subject: [PATCH 0101/2459] No need to return anything for void functions. (#24489) --- src/Illuminate/Log/LogManager.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index ad0f8dd76842..1ec2d9f11ab9 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -476,7 +476,7 @@ public function extend($driver, Closure $callback) */ public function emergency($message, array $context = []) { - return $this->driver()->emergency($message, $context); + $this->driver()->emergency($message, $context); } /** @@ -492,7 +492,7 @@ public function emergency($message, array $context = []) */ public function alert($message, array $context = []) { - return $this->driver()->alert($message, $context); + $this->driver()->alert($message, $context); } /** @@ -507,7 +507,7 @@ public function alert($message, array $context = []) */ public function critical($message, array $context = []) { - return $this->driver()->critical($message, $context); + $this->driver()->critical($message, $context); } /** @@ -521,7 +521,7 @@ public function critical($message, array $context = []) */ public function error($message, array $context = []) { - return $this->driver()->error($message, $context); + $this->driver()->error($message, $context); } /** @@ -537,7 +537,7 @@ public function error($message, array $context = []) */ public function warning($message, array $context = []) { - return $this->driver()->warning($message, $context); + $this->driver()->warning($message, $context); } /** @@ -550,7 +550,7 @@ public function warning($message, array $context = []) */ public function notice($message, array $context = []) { - return $this->driver()->notice($message, $context); + $this->driver()->notice($message, $context); } /** @@ -565,7 +565,7 @@ public function notice($message, array $context = []) */ public function info($message, array $context = []) { - return $this->driver()->info($message, $context); + $this->driver()->info($message, $context); } /** @@ -578,7 +578,7 @@ public function info($message, array $context = []) */ public function debug($message, array $context = []) { - return $this->driver()->debug($message, $context); + $this->driver()->debug($message, $context); } /** @@ -592,7 +592,7 @@ public function debug($message, array $context = []) */ public function log($level, $message, array $context = []) { - return $this->driver()->log($level, $message, $context); + $this->driver()->log($level, $message, $context); } /** From f4146818f8033a3408027350e35673741fcf6cb5 Mon Sep 17 00:00:00 2001 From: Oleksii Bilotserkivskyi Date: Fri, 8 Jun 2018 16:38:47 +0300 Subject: [PATCH 0102/2459] [5.7] Logger facade: write to channel(s) - add methods docblock (#24515) --- src/Illuminate/Support/Facades/Log.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/Support/Facades/Log.php b/src/Illuminate/Support/Facades/Log.php index 9250e875b44f..13324709892f 100755 --- a/src/Illuminate/Support/Facades/Log.php +++ b/src/Illuminate/Support/Facades/Log.php @@ -15,6 +15,9 @@ * @method static void debug(string $message, array $context = []) * @method static void log($level, string $message, array $context = []) * + * @method static self channel(string $channel) + * @method static self stack(array $channels) + * * @see \Illuminate\Log\Logger */ class Log extends Facade From e2faaccc78b904bb0f0ec3258ee328be87458b28 Mon Sep 17 00:00:00 2001 From: Pavlo Zhukov Date: Sat, 9 Jun 2018 17:53:34 +0300 Subject: [PATCH 0103/2459] Add missed 'static' in return type list (#24526) --- src/Illuminate/Database/Eloquent/Builder.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 4ba88cb10ded..c089f3824ec1 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -346,7 +346,7 @@ public function findMany($ids, $columns = ['*']) * * @param mixed $id * @param array $columns - * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection + * @return \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|static * * @throws \Illuminate\Database\Eloquent\ModelNotFoundException */ @@ -372,7 +372,7 @@ public function findOrFail($id, $columns = ['*']) * * @param mixed $id * @param array $columns - * @return \Illuminate\Database\Eloquent\Model + * @return \Illuminate\Database\Eloquent\Model|static */ public function findOrNew($id, $columns = ['*']) { @@ -388,7 +388,7 @@ public function findOrNew($id, $columns = ['*']) * * @param array $attributes * @param array $values - * @return \Illuminate\Database\Eloquent\Model + * @return \Illuminate\Database\Eloquent\Model|static */ public function firstOrNew(array $attributes, array $values = []) { @@ -404,7 +404,7 @@ public function firstOrNew(array $attributes, array $values = []) * * @param array $attributes * @param array $values - * @return \Illuminate\Database\Eloquent\Model + * @return \Illuminate\Database\Eloquent\Model|static */ public function firstOrCreate(array $attributes, array $values = []) { @@ -422,7 +422,7 @@ public function firstOrCreate(array $attributes, array $values = []) * * @param array $attributes * @param array $values - * @return \Illuminate\Database\Eloquent\Model + * @return \Illuminate\Database\Eloquent\Model|static */ public function updateOrCreate(array $attributes, array $values = []) { @@ -507,7 +507,7 @@ public function get($columns = ['*']) * Get the hydrated models without eager loading. * * @param array $columns - * @return \Illuminate\Database\Eloquent\Model[] + * @return \Illuminate\Database\Eloquent\Model[]|static[] */ public function getModels($columns = ['*']) { @@ -1093,7 +1093,7 @@ public function without($relations) * Create a new instance of the model being queried. * * @param array $attributes - * @return \Illuminate\Database\Eloquent\Model + * @return \Illuminate\Database\Eloquent\Model|static */ public function newModelInstance($attributes = []) { @@ -1236,7 +1236,7 @@ public function setEagerLoads(array $eagerLoad) /** * Get the model instance being queried. * - * @return \Illuminate\Database\Eloquent\Model + * @return \Illuminate\Database\Eloquent\Model|static */ public function getModel() { From ecd5485de20ca6cbbecaf94997fe6646085dabc5 Mon Sep 17 00:00:00 2001 From: George Hanson Date: Mon, 11 Jun 2018 19:10:46 +0100 Subject: [PATCH 0104/2459] [5.7] - Update contract docblock (#24554) Reopen of PR #24552 into master --- src/Illuminate/View/ViewFinderInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/View/ViewFinderInterface.php b/src/Illuminate/View/ViewFinderInterface.php index 49d609ea039a..7b8a849e09e6 100755 --- a/src/Illuminate/View/ViewFinderInterface.php +++ b/src/Illuminate/View/ViewFinderInterface.php @@ -50,7 +50,7 @@ public function prependNamespace($namespace, $hints); * * @param string $namespace * @param string|array $hints - * @return $this + * @return void */ public function replaceNamespace($namespace, $hints); From b3008d4193586a6bbaa772596d27a8f267b7394e Mon Sep 17 00:00:00 2001 From: George Hanson Date: Tue, 12 Jun 2018 15:27:49 +0100 Subject: [PATCH 0105/2459] Correct DocBlock (#24565) Correct the DocBlock return type to match the function calls --- src/Illuminate/Filesystem/FilesystemAdapter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index 50da3dd87934..756efe240960 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -255,7 +255,7 @@ public function setVisibility($path, $visibility) * @param string $path * @param string $data * @param string $separator - * @return int + * @return bool */ public function prepend($path, $data, $separator = PHP_EOL) { @@ -272,7 +272,7 @@ public function prepend($path, $data, $separator = PHP_EOL) * @param string $path * @param string $data * @param string $separator - * @return int + * @return bool */ public function append($path, $data, $separator = PHP_EOL) { From fb63eb4e681b1c528122fbeb8199821e9a4885d9 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 12 Jun 2018 09:32:38 -0500 Subject: [PATCH 0106/2459] formatting' --- src/Illuminate/Database/Schema/ColumnDefinition.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Schema/ColumnDefinition.php b/src/Illuminate/Database/Schema/ColumnDefinition.php index 43e4ea11cd18..9b6db32ccb94 100644 --- a/src/Illuminate/Database/Schema/ColumnDefinition.php +++ b/src/Illuminate/Database/Schema/ColumnDefinition.php @@ -10,15 +10,15 @@ * @method ColumnDefinition autoIncrement() Set INTEGER columns as auto-increment (primary key) * @method ColumnDefinition charset(string $charset) Specify a character set for the column (MySQL) * @method ColumnDefinition collation(string $collation) Specify a collation for the column (MySQL/SQL Server) - * @method ColumnDefinition comment(string $comment) Add a comment to a column (MySQL) + * @method ColumnDefinition comment(string $comment) Add a comment to the column (MySQL) * @method ColumnDefinition default(string $value) Specify a "default" value for the column * @method ColumnDefinition first(string $column) Place the column "first" in the table (MySQL) - * @method ColumnDefinition nullable($value = true) Allows (by default) NULL values to be inserted into the column + * @method ColumnDefinition nullable($value = true) Allow NULL values to be inserted into the column * @method ColumnDefinition storedAs($expression) Create a stored generated column (MySQL) - * @method ColumnDefinition unsigned() Set INTEGER columns as UNSIGNED (MySQL) - * @method ColumnDefinition useCurrent() Set TIMESTAMP columns to use CURRENT_TIMESTAMP as default value - * @method ColumnDefinition virtualAs(string $expression) Create a virtual generated column (MySQL) * @method ColumnDefinition unique() Add a unique index + * @method ColumnDefinition unsigned() Set the INTEGER column as UNSIGNED (MySQL) + * @method ColumnDefinition useCurrent() Set the TIMESTAMP column to use CURRENT_TIMESTAMP as default value + * @method ColumnDefinition virtualAs(string $expression) Create a virtual generated column (MySQL) */ class ColumnDefinition extends Fluent { From 7e1c5e8ae5c85ae5aaec6b2b100c986448e14827 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 12 Jun 2018 14:06:31 -0500 Subject: [PATCH 0107/2459] initial pass of allowing guests via type hints --- src/Illuminate/Auth/Access/Gate.php | 80 ++++++++++++++++++++++++++++- tests/Auth/AuthAccessGateTest.php | 18 +++++++ 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index d301c42b403a..ca0df13ada81 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -2,6 +2,9 @@ namespace Illuminate\Auth\Access; +use Exception; +use ReflectionClass; +use ReflectionFunction; use Illuminate\Support\Arr; use Illuminate\Support\Str; use InvalidArgumentException; @@ -302,7 +305,8 @@ public function authorize($ability, $arguments = []) */ protected function raw($ability, $arguments = []) { - if (! $user = $this->resolveUser()) { + if (! ($user = $this->resolveUser()) && + ! $this->allowsGuests($ability, Arr::wrap($arguments))) { return false; } @@ -329,6 +333,80 @@ protected function raw($ability, $arguments = []) return $result; } + /** + * Determine if the given ability allows guests. + * + * @param string $ability + * @param array $arguments + * @return bool + */ + protected function allowsGuests($ability, $arguments) + { + if (isset($arguments[0]) && + ! is_null($policy = $this->getPolicyFor($arguments[0]))) { + return $this->policyAllowsGuests($policy, $ability, $arguments); + } + + if (isset($this->abilities[$ability])) { + return $this->abilityAllowsGuests($ability, $arguments); + } + + return false; + } + + /** + * Determine if the given policy method allows guests. + * + * @param string $policy + * @param string $ability + * @param array $arguments + * @return bool + */ + protected function policyAllowsGuests($policy, $ability, $arguments) + { + try { + $reflection = new ReflectionClass($policy); + + $method = $reflection->getMethod($this->formatAbilityToMethod($ability)); + } catch (Exception $e) { + return false; + } + + if ($method) { + $parameters = $method->getParameters(); + + return isset($parameters[0]) && $this->parameterAllowsGuests($parameters[0]); + } + + return false; + } + + /** + * Determine if the ability allows guests. + * + * @param string $ability + * @param array $arguments + * @return bool + */ + protected function abilityAllowsGuests($ability, $arguments) + { + $parameters = (new ReflectionFunction($this->abilities[$ability]))->getParameters(); + + return isset($parameters[0]) && $this->parameterAllowsGuests($parameters[0]); + } + + /** + * Determine if the given parameter allows guests. + * + * @param \ReflectionParameter $parameter + * @return bool + */ + protected function parameterAllowsGuests($parameter) + { + return ($parameter->getClass() && $parameter->allowsNull()) || + ($parameter->isDefaultValueAvailable() && is_null($parameter->getDefaultValue())); + } + /** * Resolve and call the appropriate authorization callback. * diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index e0b5506e0eb5..e69490ae0ed6 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -26,6 +26,24 @@ public function test_basic_closures_can_be_defined() $this->assertFalse($gate->check('bar')); } + public function test_closures_can_allow_guest_users() + { + $gate = new Gate(new Container, function () { + return null; + }); + + $gate->define('foo', function (?StdClass $user) { + return true; + }); + + $gate->define('bar', function (StdClass $user) { + return false; + }); + + $this->assertTrue($gate->check('foo')); + $this->assertFalse($gate->check('bar')); + } + public function test_resource_gates_can_be_defined() { $gate = $this->getBasicGate(); From 6197db7f3cfc8086d6beb486800b0d107cb9e2ce Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 12 Jun 2018 14:26:41 -0500 Subject: [PATCH 0108/2459] check optional status on policies --- src/Illuminate/Auth/Access/Gate.php | 43 ++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index ca0df13ada81..d73d472c939d 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -363,11 +363,25 @@ protected function allowsGuests($ability, $arguments) * @return bool */ protected function policyAllowsGuests($policy, $ability, $arguments) + { + return $this->methodAllowsGuests( + $policy, $this->formatAbilityToMethod($ability) + ); + } + + /** + * Determine if the given class method allows guests. + * + * @param string $class + * @param string $method + * @return bool + */ + protected function methodAllowsGuests($class, $method) { try { - $reflection = new ReflectionClass($policy); + $reflection = new ReflectionClass($class); - $method = $reflection->getMethod($this->formatAbilityToMethod($ability)); + $method = $reflection->getMethod($method); } catch (Exception $e) { return false; } @@ -390,7 +404,19 @@ protected function policyAllowsGuests($policy, $ability, $arguments) */ protected function abilityAllowsGuests($ability, $arguments) { - $parameters = (new ReflectionFunction($this->abilities[$ability]))->getParameters(); + return $this->callbackAllowsGuests($this->abilities[$ability]); + } + + /** + * Determine if the callback allows guests. + * + * @param callable $callback + * @param array $arguments + * @return bool + */ + protected function callbackAllowsGuests($callback) + { + $parameters = (new ReflectionFunction($callback))->getParameters(); return isset($parameters[0]) && $this->parameterAllowsGuests($parameters[0]); } @@ -435,6 +461,10 @@ protected function callBeforeCallbacks($user, $ability, array $arguments) $arguments = array_merge([$user, $ability], [$arguments]); foreach ($this->beforeCallbacks as $before) { + if (is_null($user) && ! $this->callbackAllowsGuests($before)) { + continue; + } + if (! is_null($result = $before(...$arguments))) { return $result; } @@ -455,6 +485,10 @@ protected function callAfterCallbacks($user, $ability, array $arguments, $result $arguments = array_merge([$user, $ability, $result], [$arguments]); foreach ($this->afterCallbacks as $after) { + if (is_null($user) && ! $this->callbackAllowsGuests($after)) { + continue; + } + $after(...$arguments); } } @@ -578,7 +612,8 @@ protected function resolvePolicyCallback($user, $ability, array $arguments, $pol */ protected function callPolicyBefore($policy, $user, $ability, $arguments) { - if (method_exists($policy, 'before')) { + if (method_exists($policy, 'before') && + (! is_null($user) || $this->methodAllowsGuests($policy, 'before'))) { return $policy->before($user, $ability, ...$arguments); } } From 4bb9c194ec39429f63f6aa4f6e4de505fa720b82 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 12 Jun 2018 14:43:49 -0500 Subject: [PATCH 0109/2459] tests --- tests/Auth/AuthAccessGateTest.php | 121 ++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index e69490ae0ed6..870e9cf0db64 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -44,6 +44,91 @@ public function test_closures_can_allow_guest_users() $this->assertFalse($gate->check('bar')); } + public function test_policies_can_allow_guests() + { + unset($_SERVER['__laravel.testBefore']); + + $gate = new Gate(new Container, function () { + return null; + }); + + $gate->policy(AccessGateTestDummy::class, AccessGateTestPolicyThatAllowsGuests::class); + + $this->assertTrue($gate->check('edit', new AccessGateTestDummy)); + $this->assertFalse($gate->check('update', new AccessGateTestDummy)); + $this->assertTrue($_SERVER['__laravel.testBefore']); + + $gate = $this->getBasicGate(); + + $gate->policy(AccessGateTestDummy::class, AccessGateTestPolicyThatAllowsGuests::class); + + $this->assertTrue($gate->check('edit', new AccessGateTestDummy)); + $this->assertTrue($gate->check('update', new AccessGateTestDummy)); + + unset($_SERVER['__laravel.testBefore']); + } + + public function test_policy_before_not_called_with_guests_if_it_doesnt_allow_them() + { + $_SERVER['__laravel.testBefore'] = false; + + $gate = new Gate(new Container, function () { + return null; + }); + + $gate->policy(AccessGateTestDummy::class, AccessGateTestPolicyWithNonGuestBefore::class); + + $this->assertTrue($gate->check('edit', new AccessGateTestDummy)); + $this->assertFalse($gate->check('update', new AccessGateTestDummy)); + $this->assertFalse($_SERVER['__laravel.testBefore']); + + unset($_SERVER['__laravel.testBefore']); + } + + public function test_before_and_after_callbacks_can_allow_guests() + { + $_SERVER['__laravel.gateBefore'] = false; + $_SERVER['__laravel.gateBefore2'] = false; + $_SERVER['__laravel.gateAfter'] = false; + $_SERVER['__laravel.gateAfter2'] = false; + + $gate = new Gate(new Container, function () { + return null; + }); + + $gate->before(function (?StdClass $user) { + $_SERVER['__laravel.gateBefore'] = true; + }); + + $gate->after(function (?StdClass $user) { + $_SERVER['__laravel.gateAfter'] = true; + }); + + $gate->before(function (StdClass $user) { + $_SERVER['__laravel.gateBefore2'] = true; + }); + + $gate->after(function (StdClass $user) { + $_SERVER['__laravel.gateAfter2'] = true; + }); + + $gate->define('foo', function ($user = null) { + return true; + }); + + $this->assertTrue($gate->check('foo')); + + $this->assertTrue($_SERVER['__laravel.gateBefore']); + $this->assertFalse($_SERVER['__laravel.gateBefore2']); + $this->assertTrue($_SERVER['__laravel.gateAfter']); + $this->assertFalse($_SERVER['__laravel.gateAfter2']); + + unset($_SERVER['__laravel.gateBefore']); + unset($_SERVER['__laravel.gateBefore2']); + unset($_SERVER['__laravel.gateAfter']); + unset($_SERVER['__laravel.gateAfter2']); + } + public function test_resource_gates_can_be_defined() { $gate = $this->getBasicGate(); @@ -541,3 +626,39 @@ public function update($user, AccessGateTestDummy $dummy) return true; } } + +class AccessGateTestPolicyThatAllowsGuests +{ + public function before(?StdClass $user) + { + $_SERVER['__laravel.testBefore'] = true; + } + + public function edit(?StdClass $user, AccessGateTestDummy $dummy) + { + return true; + } + + public function update($user, AccessGateTestDummy $dummy) + { + return true; + } +} + +class AccessGateTestPolicyWithNonGuestBefore +{ + public function before(StdClass $user) + { + $_SERVER['__laravel.testBefore'] = true; + } + + public function edit(?StdClass $user, AccessGateTestDummy $dummy) + { + return true; + } + + public function update($user, AccessGateTestDummy $dummy) + { + return true; + } +} From 37c933a9211f2f7b6a81960e08d710cec2b69af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Nabia=C5=82ek?= Date: Thu, 14 Jun 2018 16:14:10 +0200 Subject: [PATCH 0110/2459] Make array values to work as expected for retrieveByCredentials method (#24586) --- src/Illuminate/Auth/DatabaseUserProvider.php | 2 +- src/Illuminate/Auth/EloquentUserProvider.php | 2 +- tests/Auth/AuthDatabaseUserProviderTest.php | 3 ++- tests/Auth/AuthEloquentUserProviderTest.php | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Auth/DatabaseUserProvider.php b/src/Illuminate/Auth/DatabaseUserProvider.php index d69cfc626ca6..415c9b7f79a9 100755 --- a/src/Illuminate/Auth/DatabaseUserProvider.php +++ b/src/Illuminate/Auth/DatabaseUserProvider.php @@ -111,7 +111,7 @@ public function retrieveByCredentials(array $credentials) foreach ($credentials as $key => $value) { if (! Str::contains($key, 'password')) { - $query->where($key, $value); + is_array($value) ? $query->whereIn($key, $value) : $query->where($key, $value); } } diff --git a/src/Illuminate/Auth/EloquentUserProvider.php b/src/Illuminate/Auth/EloquentUserProvider.php index 1630ebe91c0a..7ac823ffa839 100755 --- a/src/Illuminate/Auth/EloquentUserProvider.php +++ b/src/Illuminate/Auth/EloquentUserProvider.php @@ -114,7 +114,7 @@ public function retrieveByCredentials(array $credentials) foreach ($credentials as $key => $value) { if (! Str::contains($key, 'password')) { - $query->where($key, $value); + is_array($value) ? $query->whereIn($key, $value) : $query->where($key, $value); } } diff --git a/tests/Auth/AuthDatabaseUserProviderTest.php b/tests/Auth/AuthDatabaseUserProviderTest.php index ac90136f7f52..f5f4f75a1798 100755 --- a/tests/Auth/AuthDatabaseUserProviderTest.php +++ b/tests/Auth/AuthDatabaseUserProviderTest.php @@ -87,10 +87,11 @@ public function testRetrieveByCredentialsReturnsUserWhenUserIsFound() $conn = m::mock('Illuminate\Database\Connection'); $conn->shouldReceive('table')->once()->with('foo')->andReturn($conn); $conn->shouldReceive('where')->once()->with('username', 'dayle'); + $conn->shouldReceive('whereIn')->once()->with('group', ['one', 'two']); $conn->shouldReceive('first')->once()->andReturn(['id' => 1, 'name' => 'taylor']); $hasher = m::mock('Illuminate\Contracts\Hashing\Hasher'); $provider = new DatabaseUserProvider($conn, $hasher, 'foo'); - $user = $provider->retrieveByCredentials(['username' => 'dayle', 'password' => 'foo']); + $user = $provider->retrieveByCredentials(['username' => 'dayle', 'password' => 'foo', 'group' => ['one', 'two']]); $this->assertInstanceOf('Illuminate\Auth\GenericUser', $user); $this->assertEquals(1, $user->getAuthIdentifier()); diff --git a/tests/Auth/AuthEloquentUserProviderTest.php b/tests/Auth/AuthEloquentUserProviderTest.php index 17013dcc800c..f5dab1acbab0 100755 --- a/tests/Auth/AuthEloquentUserProviderTest.php +++ b/tests/Auth/AuthEloquentUserProviderTest.php @@ -78,9 +78,10 @@ public function testRetrieveByCredentialsReturnsUser() $mock = m::mock('stdClass'); $mock->shouldReceive('newQuery')->once()->andReturn($mock); $mock->shouldReceive('where')->once()->with('username', 'dayle'); + $mock->shouldReceive('whereIn')->once()->with('group', ['one', 'two']); $mock->shouldReceive('first')->once()->andReturn('bar'); $provider->expects($this->once())->method('createModel')->will($this->returnValue($mock)); - $user = $provider->retrieveByCredentials(['username' => 'dayle', 'password' => 'foo']); + $user = $provider->retrieveByCredentials(['username' => 'dayle', 'password' => 'foo', 'group' => ['one', 'two']]); $this->assertEquals('bar', $user); } From 8b0fdccce9884f0bc822ad50727fada403a23848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Nabia=C5=82ek?= Date: Fri, 15 Jun 2018 15:21:13 +0200 Subject: [PATCH 0111/2459] Don't use deprecated method (#24602) --- src/Illuminate/Http/UploadedFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Http/UploadedFile.php b/src/Illuminate/Http/UploadedFile.php index 8ed7e7f98750..eee493546885 100644 --- a/src/Illuminate/Http/UploadedFile.php +++ b/src/Illuminate/Http/UploadedFile.php @@ -99,7 +99,7 @@ public static function createFromBase(SymfonyUploadedFile $file, $test = false) $file->getPathname(), $file->getClientOriginalName(), $file->getClientMimeType(), - $file->getClientSize(), + $file->getSize(), $file->getError(), $test ); From 104f6b016d3b957edb4bc8d90aca717961daba54 Mon Sep 17 00:00:00 2001 From: Gaurav Makhecha Date: Fri, 15 Jun 2018 21:15:53 +0530 Subject: [PATCH 0112/2459] Remove unnecessary else conditional (#24612) --- src/Illuminate/Database/Migrations/Migrator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index 11e42b80c689..06fa9a9bbf41 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -219,9 +219,9 @@ protected function getMigrationsForRollback(array $options) { if (($steps = $options['step'] ?? 0) > 0) { return $this->repository->getMigrations($steps); - } else { - return $this->repository->getLast(); } + + return $this->repository->getLast(); } /** From 8b289e9dd00ae34394f76e3615ecd8a30d7be8dd Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 15 Jun 2018 10:46:20 -0500 Subject: [PATCH 0113/2459] Apply fixes from StyleCI (#24613) --- src/Illuminate/Database/Migrations/Migrator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index 06fa9a9bbf41..b1327a39ffec 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -220,7 +220,7 @@ protected function getMigrationsForRollback(array $options) if (($steps = $options['step'] ?? 0) > 0) { return $this->repository->getMigrations($steps); } - + return $this->repository->getLast(); } From 02591e21d6307d9ff34d406cf1857df13c15586c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 20 Jun 2018 09:27:45 -0500 Subject: [PATCH 0114/2459] Apply fixes from StyleCI (#24642) --- tests/Database/DatabaseEloquentIntegrationTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index e2832f34d919..45e3d349b590 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -3,7 +3,6 @@ namespace Illuminate\Tests\Database; use Exception; -use ReflectionObject; use Illuminate\Support\Carbon; use PHPUnit\Framework\TestCase; use Illuminate\Database\Eloquent\Model; From 35c68c20922936bf1f1ae07473b1f6730a04f72c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 22 Jun 2018 10:25:08 -0500 Subject: [PATCH 0115/2459] [5.7] Email Verification (Framework) (#24655) This PR adds optional email verification to the typical "make:auth" setup. To utilize this, the end-user must only do "make:auth" and then add implements MustVerifyEmail to their User model. Everything should be automatic from there. This uses temporary signed URLs to avoid creating another "token" table, etc. Corresponding application skeleton PR will be incoming to add necessary controller, as well as middleware registration. --- .../Auth/Console/AuthMakeCommand.php | 1 + .../Console/stubs/make/views/auth/verify.stub | 24 ++++++ .../SendEmailVerificationNotification.php | 22 ++++++ .../Auth/Middleware/EnsureEmailIsVerified.php | 28 +++++++ src/Illuminate/Auth/MustVerifyEmail.php | 38 ++++++++++ .../Auth/Notifications/VerifyEmail.php | 76 +++++++++++++++++++ .../Contracts/Auth/MustVerifyEmail.php | 27 +++++++ src/Illuminate/Foundation/Auth/User.php | 3 +- .../Foundation/Auth/VerifiesEmails.php | 51 +++++++++++++ src/Illuminate/Routing/Router.php | 20 ++++- src/Illuminate/Support/Facades/Auth.php | 5 +- 11 files changed, 291 insertions(+), 4 deletions(-) create mode 100644 src/Illuminate/Auth/Console/stubs/make/views/auth/verify.stub create mode 100644 src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php create mode 100644 src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php create mode 100644 src/Illuminate/Auth/MustVerifyEmail.php create mode 100644 src/Illuminate/Auth/Notifications/VerifyEmail.php create mode 100644 src/Illuminate/Contracts/Auth/MustVerifyEmail.php create mode 100644 src/Illuminate/Foundation/Auth/VerifiesEmails.php diff --git a/src/Illuminate/Auth/Console/AuthMakeCommand.php b/src/Illuminate/Auth/Console/AuthMakeCommand.php index 52041fa3e17d..cfe959774755 100644 --- a/src/Illuminate/Auth/Console/AuthMakeCommand.php +++ b/src/Illuminate/Auth/Console/AuthMakeCommand.php @@ -33,6 +33,7 @@ class AuthMakeCommand extends Command protected $views = [ 'auth/login.stub' => 'auth/login.blade.php', 'auth/register.stub' => 'auth/register.blade.php', + 'auth/verify.stub' => 'auth/verify.blade.php', 'auth/passwords/email.stub' => 'auth/passwords/email.blade.php', 'auth/passwords/reset.stub' => 'auth/passwords/reset.blade.php', 'layouts/app.stub' => 'layouts/app.blade.php', diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/verify.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/verify.stub new file mode 100644 index 000000000000..75ed8115efa0 --- /dev/null +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/verify.stub @@ -0,0 +1,24 @@ +@extends('layouts.app') + +@section('content') +
+
+
+
+
Verify Your Email Address
+ +
+ @if (session('resent')) + + @endif + + Before proceeding, please check your email for a verification link. + If you did not receive the email, click here to request another. +
+
+
+
+
+@endsection diff --git a/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php b/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php new file mode 100644 index 000000000000..c7b19c851547 --- /dev/null +++ b/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php @@ -0,0 +1,22 @@ +user instanceof MustVerifyEmail) { + $event->user->sendEmailVerificationNotification(); + } + } +} diff --git a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php new file mode 100644 index 000000000000..f9ee4babce57 --- /dev/null +++ b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php @@ -0,0 +1,28 @@ +user() || + ($request->user() instanceof MustVerifyEmail && + ! $request->user()->hasVerifiedEmail())) { + return Redirect::route('verification.notice'); + } + + return $next($request); + } +} diff --git a/src/Illuminate/Auth/MustVerifyEmail.php b/src/Illuminate/Auth/MustVerifyEmail.php new file mode 100644 index 000000000000..b2e4f53232a8 --- /dev/null +++ b/src/Illuminate/Auth/MustVerifyEmail.php @@ -0,0 +1,38 @@ +email_verified_at); + } + + /** + * Mark the given user's email as verified. + * + * @return void + */ + public function markEmailAsVerified() + { + $this->forceFill(['email_verified_at' => new DateTime])->save(); + } + + /** + * Send the email verification notification. + * + * @return void + */ + public function sendEmailVerificationNotification() + { + $this->notify(new Notifications\VerifyEmail); + } +} diff --git a/src/Illuminate/Auth/Notifications/VerifyEmail.php b/src/Illuminate/Auth/Notifications/VerifyEmail.php new file mode 100644 index 000000000000..f8f316260e98 --- /dev/null +++ b/src/Illuminate/Auth/Notifications/VerifyEmail.php @@ -0,0 +1,76 @@ +subject(Lang::getFromJson('Verify Email Address')) + ->line(Lang::getFromJson('Please click the button below to verify your email address.')) + ->action( + Lang::getFromJson('Verify Email Address'), + $this->verificationUrl($notifiable) + ) + ->line(Lang::getFromJson('If you did not create an account, no further action is required.')); + } + + /** + * Get the verification URL for the given notifiable. + * + * @param mixed $notifiable + * @return string + */ + protected function verificationUrl($notifiable) + { + return URL::temporarySignedRoute( + 'verification.verify', Carbon::now()->addMinutes(60), ['id' => $notifiable->getKey()] + ); + } + + /** + * Set a callback that should be used when building the notification mail message. + * + * @param \Closure $callback + * @return void + */ + public static function toMailUsing($callback) + { + static::$toMailCallback = $callback; + } +} diff --git a/src/Illuminate/Contracts/Auth/MustVerifyEmail.php b/src/Illuminate/Contracts/Auth/MustVerifyEmail.php new file mode 100644 index 000000000000..355217097375 --- /dev/null +++ b/src/Illuminate/Contracts/Auth/MustVerifyEmail.php @@ -0,0 +1,27 @@ +user()->hasVerifiedEmail() + ? redirect($this->redirectPath()) + : view('auth.verify'); + } + + /** + * Mark the authenticated user's email address as verified. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function verify(Request $request) + { + if ($request->route('id') == $request->user()->getKey()) { + $request->user()->markEmailAsVerified(); + } + + return redirect($this->redirectPath()); + } + + /** + * Resend the email verification notification. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + */ + public function resend(Request $request) + { + $request->user()->sendEmailVerificationNotification(); + + return back()->with('resent', true); + } +} diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 246f64f313dd..97fe7b9ad582 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -1124,9 +1124,10 @@ public function currentRouteUses($action) /** * Register the typical authentication routes for an application. * + * @param array $options * @return void */ - public function auth() + public function auth(array $options = []) { // Authentication Routes... $this->get('login', 'Auth\LoginController@showLoginForm')->name('login'); @@ -1142,6 +1143,23 @@ public function auth() $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email'); $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset'); $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update'); + + // Email Verification Routes... + if ($options['verify'] ?? false) { + $this->emailVerification(); + } + } + + /** + * Register the typical email verification routes for an application. + * + * @return void + */ + public function emailVerification() + { + $this->get('email/verify', 'Auth\VerificationController@show')->name('verification.notice'); + $this->get('email/verify/{id}', 'Auth\VerificationController@verify')->name('verification.verify'); + $this->get('email/resend', 'Auth\VerificationController@resend')->name('verification.resend'); } /** diff --git a/src/Illuminate/Support/Facades/Auth.php b/src/Illuminate/Support/Facades/Auth.php index 1d8cee633854..d794a0b6583f 100755 --- a/src/Illuminate/Support/Facades/Auth.php +++ b/src/Illuminate/Support/Facades/Auth.php @@ -44,10 +44,11 @@ protected static function getFacadeAccessor() /** * Register the typical authentication routes for an application. * + * @param array $options * @return void */ - public static function routes() + public static function routes(array $options = []) { - static::$app->make('router')->auth(); + static::$app->make('router')->auth($options); } } From 9353bf4c09f3f60bb30ea1dce4fbfd056bd6f5a2 Mon Sep 17 00:00:00 2001 From: webmake Date: Mon, 25 Jun 2018 16:42:42 +0300 Subject: [PATCH 0116/2459] Fix not existing method on Dispatcher contract (#24677) Fix for https://github.com/laravel/framework/issues/24666 --- .../Foundation/Testing/Concerns/MocksApplicationServices.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php b/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php index e0c48029fc64..1ad4be4d8ed0 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php +++ b/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php @@ -98,7 +98,7 @@ protected function withoutEvents() { $mock = Mockery::mock(EventsDispatcherContract::class)->shouldIgnoreMissing(); - $mock->shouldReceive('fire', 'dispatch')->andReturnUsing(function ($called) { + $mock->shouldReceive('dispatch')->andReturnUsing(function ($called) { $this->firedEvents[] = $called; }); From e227c3762b1b2216e3b98ab507a61d23450e1248 Mon Sep 17 00:00:00 2001 From: Dmitry Bubyakin Date: Mon, 25 Jun 2018 16:42:56 +0300 Subject: [PATCH 0117/2459] Add test for overwriting keys (#24676) --- tests/Support/SupportCollectionTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 6c60e200431f..bbd30bc604a7 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -1586,6 +1586,25 @@ public function testNth() $this->assertEquals(['d'], $data->nth(4, 3)->all()); } + public function testMapWithKeysOverwritingKeys() + { + $data = new Collection([ + ['id' => 1, 'name' => 'A'], + ['id' => 2, 'name' => 'B'], + ['id' => 1, 'name' => 'C'], + ]); + $data = $data->mapWithKeys(function ($item) { + return [$item['id'] => $item['name']]; + }); + $this->assertSame( + [ + 1 => 'C', + 2 => 'B', + ], + $data->all() + ); + } + public function testTransform() { $data = new Collection(['first' => 'taylor', 'last' => 'otwell']); From 29deb0c92fa8f8e38f4dd21d418af15d438826a1 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Mon, 2 Jul 2018 16:31:56 +0200 Subject: [PATCH 0118/2459] [5.7] No need to import DateTime (#24716) --- src/Illuminate/Auth/MustVerifyEmail.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Auth/MustVerifyEmail.php b/src/Illuminate/Auth/MustVerifyEmail.php index b2e4f53232a8..d20418880863 100644 --- a/src/Illuminate/Auth/MustVerifyEmail.php +++ b/src/Illuminate/Auth/MustVerifyEmail.php @@ -2,8 +2,6 @@ namespace Illuminate\Auth; -use DateTime; - trait MustVerifyEmail { /** @@ -23,7 +21,7 @@ public function hasVerifiedEmail() */ public function markEmailAsVerified() { - $this->forceFill(['email_verified_at' => new DateTime])->save(); + $this->forceFill(['email_verified_at' => $this->freshTimestamp()])->save(); } /** From bcca1fce433cea16e7c2282d965a73c759ffe60a Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 2 Jul 2018 09:58:54 -0500 Subject: [PATCH 0119/2459] fix conflicts --- tests/Redis/RedisConnectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Redis/RedisConnectionTest.php b/tests/Redis/RedisConnectionTest.php index 80f95e00af3f..6d6c010388fa 100644 --- a/tests/Redis/RedisConnectionTest.php +++ b/tests/Redis/RedisConnectionTest.php @@ -635,7 +635,7 @@ public function connections() ], ]); - $persistentPhpRedis = new RedisManager('phpredis', [ + $persistentPhpRedis = new RedisManager(new Application, 'phpredis', [ 'cluster' => false, 'default' => [ 'host' => $host, From 3ff7040663b81d8f01939edd2cb67d3214ec91b8 Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Mon, 2 Jul 2018 22:06:02 +0200 Subject: [PATCH 0120/2459] Make httpOnly CSRF cookie optional --- .../Http/Middleware/VerifyCsrfToken.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php index a33e20952f2e..ad4e86c66f3f 100644 --- a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php +++ b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php @@ -34,6 +34,13 @@ class VerifyCsrfToken */ protected $except = []; + /** + * If you're client-side scripts need the XSRF-TOKEN cookie, enable this setting. + * + * @var bool + */ + protected $addHttpCookie = false; + /** * Create a new middleware instance. * @@ -64,7 +71,13 @@ public function handle($request, Closure $next) $this->inExceptArray($request) || $this->tokensMatch($request) ) { - return $this->addCookieToResponse($request, $next($request)); + $response = $next($request); + + if ($this->addHttpCookie) { + $this->addCookieToResponse($request, $response); + } + + return $response; } throw new TokenMismatchException; From a4e7311cf5c9730898129fe6b102faa170a0ea76 Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Mon, 2 Jul 2018 22:15:28 +0200 Subject: [PATCH 0121/2459] Update VerifyCsrfToken.php --- src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php index ad4e86c66f3f..499b83440491 100644 --- a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php +++ b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php @@ -35,7 +35,7 @@ class VerifyCsrfToken protected $except = []; /** - * If you're client-side scripts need the XSRF-TOKEN cookie, enable this setting. + * If your client-side scripts need the XSRF-TOKEN cookie, enable this setting. * * @var bool */ From 669ad7180773cb45dcc59b7629e70f583409fa6c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 3 Jul 2018 09:33:25 -0500 Subject: [PATCH 0122/2459] fixes --- composer.json | 3 ++- .../Http/Middleware/VerifyCsrfToken.php | 16 +++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 2930dce167e1..92a10e5a9774 100644 --- a/composer.json +++ b/composer.json @@ -84,7 +84,8 @@ "phpunit/phpunit": "^7.0", "predis/predis": "^1.1.1", "symfony/css-selector": "^4.1", - "symfony/dom-crawler": "^4.1" + "symfony/dom-crawler": "^4.1", + "true/punycode": "^2.1" }, "autoload": { "files": [ diff --git a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php index 499b83440491..9213ebc40fce 100644 --- a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php +++ b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php @@ -35,11 +35,11 @@ class VerifyCsrfToken protected $except = []; /** - * If your client-side scripts need the XSRF-TOKEN cookie, enable this setting. + * Indicates whether the XSRF-TOKEN cookie should be set on the response. * * @var bool */ - protected $addHttpCookie = false; + protected $addHttpCookie = true; /** * Create a new middleware instance. @@ -71,13 +71,11 @@ public function handle($request, Closure $next) $this->inExceptArray($request) || $this->tokensMatch($request) ) { - $response = $next($request); - - if ($this->addHttpCookie) { - $this->addCookieToResponse($request, $response); - } - - return $response; + return tap($next($request), function ($response) { + if ($this->addHttpCookie) { + $this->addCookieToResponse($request, $response); + } + }); } throw new TokenMismatchException; From 2b3902a77f9f8193ab7ee157530e97d1b96cfa05 Mon Sep 17 00:00:00 2001 From: Sebastian De Deyne Date: Wed, 4 Jul 2018 03:27:37 +0200 Subject: [PATCH 0123/2459] Allow tuple notation for actions (#24738) --- src/Illuminate/Routing/UrlGenerator.php | 8 ++++++-- tests/Routing/RoutingUrlGeneratorTest.php | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 901d41276b17..f446fb959341 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -392,7 +392,7 @@ protected function toRoute($route, $parameters, $absolute) /** * Get the URL to a controller action. * - * @param string $action + * @param string|array $action * @param mixed $parameters * @param bool $absolute * @return string @@ -411,11 +411,15 @@ public function action($action, $parameters = [], $absolute = true) /** * Format the given controller action. * - * @param string $action + * @param string|array $action * @return string */ protected function formatAction($action) { + if (is_array($action)) { + $action = implode('@', $action); + } + if ($this->rootNamespace && ! (strpos($action, '\\') === 0)) { return $this->rootNamespace.'\\'.$action; } else { diff --git a/tests/Routing/RoutingUrlGeneratorTest.php b/tests/Routing/RoutingUrlGeneratorTest.php index e9c8e9fa8900..ec340c98694e 100755 --- a/tests/Routing/RoutingUrlGeneratorTest.php +++ b/tests/Routing/RoutingUrlGeneratorTest.php @@ -244,6 +244,7 @@ public function testBasicRouteGeneration() $this->assertEquals('/foo/bar/taylor/breeze/otwell?fly=wall', $url->route('bar', ['taylor', 'otwell', 'fly' => 'wall'], false)); $this->assertEquals('https://www.foo.com/foo/baz', $url->route('baz')); $this->assertEquals('http://www.foo.com/foo/bam', $url->action('foo@bar')); + $this->assertEquals('http://www.foo.com/foo/bam', $url->action(['foo', 'bar'])); $this->assertEquals('http://www.foo.com/foo/invoke', $url->action('InvokableActionStub')); $this->assertEquals('http://www.foo.com/foo/bar/taylor/breeze/otwell?wall&woz', $url->route('bar', ['wall', 'woz', 'boom' => 'otwell', 'baz' => 'taylor'])); $this->assertEquals('http://www.foo.com/foo/bar/taylor/breeze/otwell?wall&woz', $url->route('bar', ['taylor', 'otwell', 'wall', 'woz'])); From 37a16a117124e25ab70915f68ad2c80bc36b7d50 Mon Sep 17 00:00:00 2001 From: Refael Iliaguyev Date: Fri, 6 Jul 2018 17:52:31 +0300 Subject: [PATCH 0124/2459] missing use (#24761) --- src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php index 9213ebc40fce..a727b8a9829a 100644 --- a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php +++ b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php @@ -71,7 +71,7 @@ public function handle($request, Closure $next) $this->inExceptArray($request) || $this->tokensMatch($request) ) { - return tap($next($request), function ($response) { + return tap($next($request), function ($response) use ($request) { if ($this->addHttpCookie) { $this->addCookieToResponse($request, $response); } From 6fd187b72b6866aed832f281c1ac7d42572d2730 Mon Sep 17 00:00:00 2001 From: Sebastian De Deyne Date: Fri, 6 Jul 2018 16:58:20 +0200 Subject: [PATCH 0125/2459] [5.7] Use functional mail button class names (#24736) * Use functional mail button class names * Backwards compat --- .../Mail/resources/views/html/button.blade.php | 2 +- .../Mail/resources/views/html/themes/default.css | 9 ++++++--- .../Notifications/resources/views/email.blade.php | 6 ++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Mail/resources/views/html/button.blade.php b/src/Illuminate/Mail/resources/views/html/button.blade.php index bf35c79183ab..9d14d9b1619b 100644 --- a/src/Illuminate/Mail/resources/views/html/button.blade.php +++ b/src/Illuminate/Mail/resources/views/html/button.blade.php @@ -7,7 +7,7 @@
- {{ $slot }} + {{ $slot }}
diff --git a/src/Illuminate/Mail/resources/views/html/themes/default.css b/src/Illuminate/Mail/resources/views/html/themes/default.css index b78b27daa47a..aa4afb266084 100644 --- a/src/Illuminate/Mail/resources/views/html/themes/default.css +++ b/src/Illuminate/Mail/resources/views/html/themes/default.css @@ -218,7 +218,8 @@ img { -webkit-text-size-adjust: none; } -.button-blue { +.button-blue, +.button-primary { background-color: #3097D1; border-top: 10px solid #3097D1; border-right: 18px solid #3097D1; @@ -226,7 +227,8 @@ img { border-left: 18px solid #3097D1; } -.button-green { +.button-green, +.button-success { background-color: #2ab27b; border-top: 10px solid #2ab27b; border-right: 18px solid #2ab27b; @@ -234,7 +236,8 @@ img { border-left: 18px solid #2ab27b; } -.button-red { +.button-red, +.button-error { background-color: #bf5329; border-top: 10px solid #bf5329; border-right: 18px solid #bf5329; diff --git a/src/Illuminate/Notifications/resources/views/email.blade.php b/src/Illuminate/Notifications/resources/views/email.blade.php index fe38895320d1..8e4ddbad8c5f 100644 --- a/src/Illuminate/Notifications/resources/views/email.blade.php +++ b/src/Illuminate/Notifications/resources/views/email.blade.php @@ -21,13 +21,11 @@ @component('mail::button', ['url' => $actionUrl, 'color' => $color]) From b32618e3e1794c224760db746c8982e79cf80a29 Mon Sep 17 00:00:00 2001 From: Sebastian De Deyne Date: Tue, 10 Jul 2018 15:33:47 +0200 Subject: [PATCH 0126/2459] Collection::where with a single parameter (#24737) --- src/Illuminate/Support/Collection.php | 10 ++++++++-- tests/Support/SupportCollectionTest.php | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index a3e8c4d4eb4e..e2246a4cfed3 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -524,7 +524,7 @@ public function unless($value, callable $callback, callable $default = null) * @param mixed $value * @return static */ - public function where($key, $operator, $value = null) + public function where($key, $operator = null, $value = null) { return $this->filter($this->operatorForWhere(...func_get_args())); } @@ -537,8 +537,14 @@ public function where($key, $operator, $value = null) * @param mixed $value * @return \Closure */ - protected function operatorForWhere($key, $operator, $value = null) + protected function operatorForWhere($key, $operator = null, $value = null) { + if (func_num_args() === 1) { + $value = true; + + $operator = '='; + } + if (func_num_args() === 2) { $value = $operator; diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index bbd30bc604a7..19ce77a22bca 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -483,6 +483,12 @@ public function testWhere() [['v' => 'hello']], $c->where('v', new \Illuminate\Support\HtmlString('hello'))->values()->all() ); + + $c = new Collection([['v' => 1], ['v' => 2], ['v' => null]]); + $this->assertEquals( + [['v' => 1], ['v' => 2]], + $c->where('v')->values()->all() + ); } public function testWhereStrict() From e3ef9e01c73272a2114a53a5ebd472d7a9ab5edc Mon Sep 17 00:00:00 2001 From: Grummfy Date: Wed, 13 Jun 2018 12:24:42 +0200 Subject: [PATCH 0127/2459] fix laravel/framework#22804 + adding some unit test --- src/Illuminate/Mail/Mailable.php | 24 +++++-- tests/Mail/MailMailableDataTest.php | 4 +- tests/Mail/MailableQueuedTest.php | 107 ++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 tests/Mail/MailableQueuedTest.php diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index d998b0a7de3f..36f351a6fba1 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -118,6 +118,13 @@ class Mailable implements MailableContract, Renderable */ public $rawAttachments = []; + /** + * The attachments coming from storage disk + * + * @var array + */ + public $diskAttachments = []; + /** * The callbacks for the message. * @@ -345,6 +352,15 @@ protected function buildAttachments($message) ); } + foreach ($this->diskAttachments as $attachment) { + $storage = Container::getInstance()->make(FilesystemFactory::class)->disk($attachment['disk']); + + return $message->attachData( + $storage->get($attachment['path']), $attachment['name'] ?? basename($attachment['path']), + array_merge(['mime' => $storage->mimeType($attachment['path'])], $attachment['options']) + ); + } + return $this; } @@ -725,12 +741,10 @@ public function attachFromStorage($path, $name = null, array $options = []) */ public function attachFromStorageDisk($disk, $path, $name = null, array $options = []) { - $storage = Container::getInstance()->make(FilesystemFactory::class)->disk($disk); + $name = $name ?? basename($path); + $this->diskAttachments[] = compact('disk', 'path', 'name', 'options'); - return $this->attachData( - $storage->get($path), $name ?? basename($path), - array_merge(['mime' => $storage->mimeType($path)], $options) - ); + return $this; } /** diff --git a/tests/Mail/MailMailableDataTest.php b/tests/Mail/MailMailableDataTest.php index 0aa0aa21e3b9..df4da579ee50 100644 --- a/tests/Mail/MailMailableDataTest.php +++ b/tests/Mail/MailMailableDataTest.php @@ -11,13 +11,13 @@ public function testMailableDataIsNotLost() { $testData = ['first_name' => 'James']; - $mailable = new MailableStub; + $mailable = new MailableQueableStub; $mailable->build(function ($m) use ($testData) { $m->view('view', $testData); }); $this->assertSame($testData, $mailable->buildViewData()); - $mailable = new MailableStub; + $mailable = new MailableQueableStub; $mailable->build(function ($m) use ($testData) { $m->view('view', $testData) ->text('text-view'); diff --git a/tests/Mail/MailableQueuedTest.php b/tests/Mail/MailableQueuedTest.php new file mode 100644 index 000000000000..e13cb2142e14 --- /dev/null +++ b/tests/Mail/MailableQueuedTest.php @@ -0,0 +1,107 @@ +getMockBuilder('Illuminate\Mail\Mailer') + ->setConstructorArgs($this->getMocks()) + ->setMethods(['createMessage', 'to']) + ->getMock(); + $mailer->setQueue($queueFake); + $mailable = new MailableQueableStub(); + $queueFake->assertNothingPushed(); + $mailer->send($mailable); + $queueFake->assertPushedOn(null, SendQueuedMailable::class); + } + + public function testQueuedMailableWithAttachmentSent() + { + $queueFake = new QueueFake(new Application); + $mailer = $this->getMockBuilder('Illuminate\Mail\Mailer') + ->setConstructorArgs($this->getMocks()) + ->setMethods(['createMessage']) + ->getMock(); + $mailer->setQueue($queueFake); + $mailable = new MailableQueableStub(); + $attachmentOption = ['mime' => 'image/jpeg', 'as' => 'bar.jpg']; + $mailable->attach('foo.jpg', $attachmentOption); + $this->assertTrue(is_array($mailable->attachments)); + $this->assertCount(1, $mailable->attachments); + $this->assertEquals($mailable->attachments[0]['options'], $attachmentOption); + $queueFake->assertNothingPushed(); + $mailer->send($mailable); + $queueFake->assertPushedOn(null, SendQueuedMailable::class); + } + + public function testQueuedMailableWithAttachmentFromDiskSent() + { + $app = new Application; + $container = Container::getInstance(); + $disk = $this->getMockBuilder(Filesystem::class) + ->getMock(); + $filesystemFactory = $this->getMockBuilder(FilesystemManager::class) + ->setConstructorArgs([$app]) + ->getMock(); + $container->singleton('filesystem', function () use ($filesystemFactory) { + return $filesystemFactory; + }); + $queueFake = new QueueFake($app); + $mailer = $this->getMockBuilder('Illuminate\Mail\Mailer') + ->setConstructorArgs($this->getMocks()) + ->setMethods(['createMessage']) + ->getMock(); + $mailer->setQueue($queueFake); + $mailable = new MailableQueableStub(); + $attachmentOption = ['mime' => 'image/jpeg', 'as' => 'bar.jpg']; + + $mailable->attachFromStorage('/', 'foo.jpg', $attachmentOption); + + $this->assertTrue(is_array($mailable->diskAttachments)); + $this->assertCount(1, $mailable->diskAttachments); + $this->assertEquals($mailable->diskAttachments[0]['options'], $attachmentOption); + + $queueFake->assertNothingPushed(); + $mailer->send($mailable); + $queueFake->assertPushedOn(null, SendQueuedMailable::class); + } + + protected function getMocks() + { + return [m::mock('Illuminate\Contracts\View\Factory'), m::mock('Swift_Mailer')]; + } +} + +class MailableQueableStub extends Mailable implements ShouldQueue +{ + use Queueable; + + public function build(): self + { + $this + ->subject('lorem ipsum') + ->html('foo bar baz') + ->to('foo@example.tld'); + return $this; + } +} From c244abe51891602b061d51460b74af442da1f8cc Mon Sep 17 00:00:00 2001 From: Grummfy Date: Wed, 11 Jul 2018 14:50:22 +0200 Subject: [PATCH 0128/2459] fix from styleci --- src/Illuminate/Mail/Mailable.php | 24 ++-- tests/Mail/MailMailableDataTest.php | 4 +- tests/Mail/MailableQueuedTest.php | 167 ++++++++++++++-------------- 3 files changed, 98 insertions(+), 97 deletions(-) diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 36f351a6fba1..1c232f681826 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -118,11 +118,11 @@ class Mailable implements MailableContract, Renderable */ public $rawAttachments = []; - /** - * The attachments coming from storage disk - * - * @var array - */ + /** + * The attachments coming from storage disk. + * + * @var array + */ public $diskAttachments = []; /** @@ -353,12 +353,12 @@ protected function buildAttachments($message) } foreach ($this->diskAttachments as $attachment) { - $storage = Container::getInstance()->make(FilesystemFactory::class)->disk($attachment['disk']); + $storage = Container::getInstance()->make(FilesystemFactory::class)->disk($attachment['disk']); - return $message->attachData( - $storage->get($attachment['path']), $attachment['name'] ?? basename($attachment['path']), - array_merge(['mime' => $storage->mimeType($attachment['path'])], $attachment['options']) - ); + return $message->attachData( + $storage->get($attachment['path']), $attachment['name'] ?? basename($attachment['path']), + array_merge(['mime' => $storage->mimeType($attachment['path'])], $attachment['options']) + ); } return $this; @@ -741,8 +741,8 @@ public function attachFromStorage($path, $name = null, array $options = []) */ public function attachFromStorageDisk($disk, $path, $name = null, array $options = []) { - $name = $name ?? basename($path); - $this->diskAttachments[] = compact('disk', 'path', 'name', 'options'); + $name = $name ?? basename($path); + $this->diskAttachments[] = compact('disk', 'path', 'name', 'options'); return $this; } diff --git a/tests/Mail/MailMailableDataTest.php b/tests/Mail/MailMailableDataTest.php index df4da579ee50..0aa0aa21e3b9 100644 --- a/tests/Mail/MailMailableDataTest.php +++ b/tests/Mail/MailMailableDataTest.php @@ -11,13 +11,13 @@ public function testMailableDataIsNotLost() { $testData = ['first_name' => 'James']; - $mailable = new MailableQueableStub; + $mailable = new MailableStub; $mailable->build(function ($m) use ($testData) { $m->view('view', $testData); }); $this->assertSame($testData, $mailable->buildViewData()); - $mailable = new MailableQueableStub; + $mailable = new MailableStub; $mailable->build(function ($m) use ($testData) { $m->view('view', $testData) ->text('text-view'); diff --git a/tests/Mail/MailableQueuedTest.php b/tests/Mail/MailableQueuedTest.php index e13cb2142e14..19198f2f3aae 100644 --- a/tests/Mail/MailableQueuedTest.php +++ b/tests/Mail/MailableQueuedTest.php @@ -2,106 +2,107 @@ namespace Illuminate\Tests\Mail; +use Mockery as m; +use Illuminate\Bus\Queueable; +use Illuminate\Mail\Mailable; +use PHPUnit\Framework\TestCase; use Illuminate\Container\Container; use Illuminate\Filesystem\Filesystem; -use Illuminate\Filesystem\FilesystemManager; +use Illuminate\Foundation\Application; use Illuminate\Mail\SendQueuedMailable; -use Illuminate\Support\Testing\Fakes\QueueFake; -use Mockery as m; -use Illuminate\Mail\Mailable; -use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Foundation\Application; -use PHPUnit\Framework\TestCase; +use Illuminate\Filesystem\FilesystemManager; +use Illuminate\Support\Testing\Fakes\QueueFake; class MailableQueuedTest extends TestCase { - public function tearDown() - { - m::close(); - } + public function tearDown() + { + m::close(); + } - public function testQueuedMailableSent() - { - $queueFake = new QueueFake(new Application); - $mailer = $this->getMockBuilder('Illuminate\Mail\Mailer') - ->setConstructorArgs($this->getMocks()) - ->setMethods(['createMessage', 'to']) - ->getMock(); - $mailer->setQueue($queueFake); - $mailable = new MailableQueableStub(); - $queueFake->assertNothingPushed(); - $mailer->send($mailable); - $queueFake->assertPushedOn(null, SendQueuedMailable::class); - } + public function testQueuedMailableSent() + { + $queueFake = new QueueFake(new Application); + $mailer = $this->getMockBuilder('Illuminate\Mail\Mailer') + ->setConstructorArgs($this->getMocks()) + ->setMethods(['createMessage', 'to']) + ->getMock(); + $mailer->setQueue($queueFake); + $mailable = new MailableQueableStub(); + $queueFake->assertNothingPushed(); + $mailer->send($mailable); + $queueFake->assertPushedOn(null, SendQueuedMailable::class); + } - public function testQueuedMailableWithAttachmentSent() - { - $queueFake = new QueueFake(new Application); - $mailer = $this->getMockBuilder('Illuminate\Mail\Mailer') - ->setConstructorArgs($this->getMocks()) - ->setMethods(['createMessage']) - ->getMock(); - $mailer->setQueue($queueFake); - $mailable = new MailableQueableStub(); - $attachmentOption = ['mime' => 'image/jpeg', 'as' => 'bar.jpg']; - $mailable->attach('foo.jpg', $attachmentOption); - $this->assertTrue(is_array($mailable->attachments)); - $this->assertCount(1, $mailable->attachments); - $this->assertEquals($mailable->attachments[0]['options'], $attachmentOption); - $queueFake->assertNothingPushed(); - $mailer->send($mailable); - $queueFake->assertPushedOn(null, SendQueuedMailable::class); - } + public function testQueuedMailableWithAttachmentSent() + { + $queueFake = new QueueFake(new Application); + $mailer = $this->getMockBuilder('Illuminate\Mail\Mailer') + ->setConstructorArgs($this->getMocks()) + ->setMethods(['createMessage']) + ->getMock(); + $mailer->setQueue($queueFake); + $mailable = new MailableQueableStub(); + $attachmentOption = ['mime' => 'image/jpeg', 'as' => 'bar.jpg']; + $mailable->attach('foo.jpg', $attachmentOption); + $this->assertTrue(is_array($mailable->attachments)); + $this->assertCount(1, $mailable->attachments); + $this->assertEquals($mailable->attachments[0]['options'], $attachmentOption); + $queueFake->assertNothingPushed(); + $mailer->send($mailable); + $queueFake->assertPushedOn(null, SendQueuedMailable::class); + } - public function testQueuedMailableWithAttachmentFromDiskSent() - { - $app = new Application; - $container = Container::getInstance(); - $disk = $this->getMockBuilder(Filesystem::class) - ->getMock(); - $filesystemFactory = $this->getMockBuilder(FilesystemManager::class) - ->setConstructorArgs([$app]) - ->getMock(); - $container->singleton('filesystem', function () use ($filesystemFactory) { - return $filesystemFactory; - }); - $queueFake = new QueueFake($app); - $mailer = $this->getMockBuilder('Illuminate\Mail\Mailer') - ->setConstructorArgs($this->getMocks()) - ->setMethods(['createMessage']) - ->getMock(); - $mailer->setQueue($queueFake); - $mailable = new MailableQueableStub(); - $attachmentOption = ['mime' => 'image/jpeg', 'as' => 'bar.jpg']; + public function testQueuedMailableWithAttachmentFromDiskSent() + { + $app = new Application; + $container = Container::getInstance(); + $disk = $this->getMockBuilder(Filesystem::class) + ->getMock(); + $filesystemFactory = $this->getMockBuilder(FilesystemManager::class) + ->setConstructorArgs([$app]) + ->getMock(); + $container->singleton('filesystem', function () use ($filesystemFactory) { + return $filesystemFactory; + }); + $queueFake = new QueueFake($app); + $mailer = $this->getMockBuilder('Illuminate\Mail\Mailer') + ->setConstructorArgs($this->getMocks()) + ->setMethods(['createMessage']) + ->getMock(); + $mailer->setQueue($queueFake); + $mailable = new MailableQueableStub(); + $attachmentOption = ['mime' => 'image/jpeg', 'as' => 'bar.jpg']; - $mailable->attachFromStorage('/', 'foo.jpg', $attachmentOption); + $mailable->attachFromStorage('/', 'foo.jpg', $attachmentOption); - $this->assertTrue(is_array($mailable->diskAttachments)); - $this->assertCount(1, $mailable->diskAttachments); - $this->assertEquals($mailable->diskAttachments[0]['options'], $attachmentOption); + $this->assertTrue(is_array($mailable->diskAttachments)); + $this->assertCount(1, $mailable->diskAttachments); + $this->assertEquals($mailable->diskAttachments[0]['options'], $attachmentOption); - $queueFake->assertNothingPushed(); - $mailer->send($mailable); - $queueFake->assertPushedOn(null, SendQueuedMailable::class); - } + $queueFake->assertNothingPushed(); + $mailer->send($mailable); + $queueFake->assertPushedOn(null, SendQueuedMailable::class); + } - protected function getMocks() - { - return [m::mock('Illuminate\Contracts\View\Factory'), m::mock('Swift_Mailer')]; - } + protected function getMocks() + { + return [m::mock('Illuminate\Contracts\View\Factory'), m::mock('Swift_Mailer')]; + } } class MailableQueableStub extends Mailable implements ShouldQueue { - use Queueable; + use Queueable; + + public function build(): self + { + $this + ->subject('lorem ipsum') + ->html('foo bar baz') + ->to('foo@example.tld'); - public function build(): self - { - $this - ->subject('lorem ipsum') - ->html('foo bar baz') - ->to('foo@example.tld'); - return $this; - } + return $this; + } } From 18dc89b3434367946d7e62e5d684dbbae49d0431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Nabia=C5=82ek?= Date: Wed, 11 Jul 2018 17:48:10 +0200 Subject: [PATCH 0129/2459] Display messages during running migrator --- .../Console/Migrations/MigrateCommand.php | 9 +---- .../Console/Migrations/ResetCommand.php | 9 +---- .../Console/Migrations/RollbackCommand.php | 9 +---- .../Database/Migrations/Migrator.php | 37 +++++++++++-------- .../DatabaseMigrationMigrateCommandTest.php | 9 +++-- .../DatabaseMigrationResetCommandTest.php | 4 +- .../DatabaseMigrationRollbackCommandTest.php | 8 ++-- .../DatabaseMigratorIntegrationTest.php | 6 +++ 8 files changed, 41 insertions(+), 50 deletions(-) diff --git a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php index 5c7a8045d659..fea29888a5be 100755 --- a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php +++ b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php @@ -65,18 +65,11 @@ public function handle() // Next, we will check to see if a path option has been defined. If it has // we will use the path relative to the root of this installation folder // so that migrations may be run for any path within the applications. - $this->migrator->run($this->getMigrationPaths(), [ + $this->migrator->setOutput($this->output)->run($this->getMigrationPaths(), [ 'pretend' => $this->option('pretend'), 'step' => $this->option('step'), ]); - // Once the migrator has run we will grab the note output and send it out to - // the console screen, since the migrator itself functions without having - // any instances of the OutputInterface contract passed into the class. - foreach ($this->migrator->getNotes() as $note) { - $this->output->writeln($note); - } - // Finally, if the "seed" option has been given, we will re-run the database // seed task to re-populate the database, which is convenient when adding // a migration and a seed at the same time, as it is only this command. diff --git a/src/Illuminate/Database/Console/Migrations/ResetCommand.php b/src/Illuminate/Database/Console/Migrations/ResetCommand.php index e883402a2e74..28803806a33f 100755 --- a/src/Illuminate/Database/Console/Migrations/ResetCommand.php +++ b/src/Illuminate/Database/Console/Migrations/ResetCommand.php @@ -64,16 +64,9 @@ public function handle() return $this->comment('Migration table not found.'); } - $this->migrator->reset( + $this->migrator->setOutput($this->output)->reset( $this->getMigrationPaths(), $this->option('pretend') ); - - // Once the migrator has run we will grab the note output and send it out to - // the console screen, since the migrator itself functions without having - // any instances of the OutputInterface contract passed into the class. - foreach ($this->migrator->getNotes() as $note) { - $this->output->writeln($note); - } } /** diff --git a/src/Illuminate/Database/Console/Migrations/RollbackCommand.php b/src/Illuminate/Database/Console/Migrations/RollbackCommand.php index 8005149dff5f..457bcb1dbe36 100755 --- a/src/Illuminate/Database/Console/Migrations/RollbackCommand.php +++ b/src/Illuminate/Database/Console/Migrations/RollbackCommand.php @@ -57,19 +57,12 @@ public function handle() $this->migrator->setConnection($this->option('database')); - $this->migrator->rollback( + $this->migrator->setOutput($this->output)->rollback( $this->getMigrationPaths(), [ 'pretend' => $this->option('pretend'), 'step' => (int) $this->option('step'), ] ); - - // Once the migrator has run we will grab the note output and send it out to - // the console screen, since the migrator itself functions without having - // any instances of the OutputInterface contract passed into the class. - foreach ($this->migrator->getNotes() as $note) { - $this->output->writeln($note); - } } /** diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index a6af769e1e33..edeee670aeb1 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -2,6 +2,7 @@ namespace Illuminate\Database\Migrations; +use Illuminate\Console\OutputStyle; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Support\Collection; @@ -39,18 +40,18 @@ class Migrator protected $connection; /** - * The notes for the current operation. + * The paths to all of the migration files. * * @var array */ - protected $notes = []; + protected $paths = []; /** - * The paths to all of the migration files. + * The output interface implementation. * - * @var array + * @var \Illuminate\Console\OutputStyle */ - protected $paths = []; + protected $output; /** * Create a new migrator instance. @@ -69,6 +70,20 @@ public function __construct(MigrationRepositoryInterface $repository, $this->repository = $repository; } + /** + * Set output. + * + * @param \Illuminate\Console\OutputStyle $output + * + * @return $this + */ + public function setOutput(OutputStyle $output) + { + $this->output = $output; + + return $this; + } + /** * Run the pending migrations at a given path. * @@ -573,16 +588,6 @@ public function getFilesystem() */ protected function note($message) { - $this->notes[] = $message; - } - - /** - * Get the notes for the last operation. - * - * @return array - */ - public function getNotes() - { - return $this->notes; + $this->output->writeln($message); } } diff --git a/tests/Database/DatabaseMigrationMigrateCommandTest.php b/tests/Database/DatabaseMigrationMigrateCommandTest.php index bffadc3d7382..26bb65a23771 100755 --- a/tests/Database/DatabaseMigrationMigrateCommandTest.php +++ b/tests/Database/DatabaseMigrationMigrateCommandTest.php @@ -22,6 +22,7 @@ public function testBasicMigrationsCallMigratorWithProperArguments() $command->setLaravel($app); $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with(null); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('run')->once()->with([__DIR__.DIRECTORY_SEPARATOR.'migrations'], ['pretend' => false, 'step' => false]); $migrator->shouldReceive('getNotes')->andReturn([]); $migrator->shouldReceive('repositoryExists')->once()->andReturn(true); @@ -38,8 +39,8 @@ public function testMigrationRepositoryCreatedWhenNecessary() $command->setLaravel($app); $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with(null); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('run')->once()->with([__DIR__.DIRECTORY_SEPARATOR.'migrations'], ['pretend' => false, 'step' => false]); - $migrator->shouldReceive('getNotes')->andReturn([]); $migrator->shouldReceive('repositoryExists')->once()->andReturn(false); $command->expects($this->once())->method('call')->with($this->equalTo('migrate:install'), $this->equalTo(['--database' => null])); @@ -54,8 +55,8 @@ public function testTheCommandMayBePretended() $command->setLaravel($app); $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with(null); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('run')->once()->with([__DIR__.DIRECTORY_SEPARATOR.'migrations'], ['pretend' => true, 'step' => false]); - $migrator->shouldReceive('getNotes')->andReturn([]); $migrator->shouldReceive('repositoryExists')->once()->andReturn(true); $this->runCommand($command, ['--pretend' => true]); @@ -69,8 +70,8 @@ public function testTheDatabaseMayBeSet() $command->setLaravel($app); $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with('foo'); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('run')->once()->with([__DIR__.DIRECTORY_SEPARATOR.'migrations'], ['pretend' => false, 'step' => false]); - $migrator->shouldReceive('getNotes')->andReturn([]); $migrator->shouldReceive('repositoryExists')->once()->andReturn(true); $this->runCommand($command, ['--database' => 'foo']); @@ -84,8 +85,8 @@ public function testStepMayBeSet() $command->setLaravel($app); $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with(null); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('run')->once()->with([__DIR__.DIRECTORY_SEPARATOR.'migrations'], ['pretend' => false, 'step' => true]); - $migrator->shouldReceive('getNotes')->andReturn([]); $migrator->shouldReceive('repositoryExists')->once()->andReturn(true); $this->runCommand($command, ['--step' => true]); diff --git a/tests/Database/DatabaseMigrationResetCommandTest.php b/tests/Database/DatabaseMigrationResetCommandTest.php index 353010c30f95..6bc9bd77be82 100755 --- a/tests/Database/DatabaseMigrationResetCommandTest.php +++ b/tests/Database/DatabaseMigrationResetCommandTest.php @@ -23,8 +23,8 @@ public function testResetCommandCallsMigratorWithProperArguments() $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with(null); $migrator->shouldReceive('repositoryExists')->once()->andReturn(true); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('reset')->once()->with([__DIR__.'/migrations'], false); - $migrator->shouldReceive('getNotes')->andReturn([]); $this->runCommand($command); } @@ -38,8 +38,8 @@ public function testResetCommandCanBePretended() $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with('foo'); $migrator->shouldReceive('repositoryExists')->once()->andReturn(true); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('reset')->once()->with([__DIR__.'/migrations'], true); - $migrator->shouldReceive('getNotes')->andReturn([]); $this->runCommand($command, ['--pretend' => true, '--database' => 'foo']); } diff --git a/tests/Database/DatabaseMigrationRollbackCommandTest.php b/tests/Database/DatabaseMigrationRollbackCommandTest.php index 919f9b918a22..3751581892de 100755 --- a/tests/Database/DatabaseMigrationRollbackCommandTest.php +++ b/tests/Database/DatabaseMigrationRollbackCommandTest.php @@ -22,8 +22,8 @@ public function testRollbackCommandCallsMigratorWithProperArguments() $command->setLaravel($app); $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with(null); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('rollback')->once()->with([__DIR__.'/migrations'], ['pretend' => false, 'step' => 0]); - $migrator->shouldReceive('getNotes')->andReturn([]); $this->runCommand($command); } @@ -36,8 +36,8 @@ public function testRollbackCommandCallsMigratorWithStepOption() $command->setLaravel($app); $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with(null); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('rollback')->once()->with([__DIR__.'/migrations'], ['pretend' => false, 'step' => 2]); - $migrator->shouldReceive('getNotes')->andReturn([]); $this->runCommand($command, ['--step' => 2]); } @@ -50,8 +50,8 @@ public function testRollbackCommandCanBePretended() $command->setLaravel($app); $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with('foo'); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('rollback')->once()->with([__DIR__.'/migrations'], true); - $migrator->shouldReceive('getNotes')->andReturn([]); $this->runCommand($command, ['--pretend' => true, '--database' => 'foo']); } @@ -64,8 +64,8 @@ public function testRollbackCommandCanBePretendedWithStepOption() $command->setLaravel($app); $migrator->shouldReceive('paths')->once()->andReturn([]); $migrator->shouldReceive('setConnection')->once()->with('foo'); + $migrator->shouldReceive('setOutput')->once()->andReturn($migrator); $migrator->shouldReceive('rollback')->once()->with([__DIR__.'/migrations'], ['pretend' => true, 'step' => 2]); - $migrator->shouldReceive('getNotes')->andReturn([]); $this->runCommand($command, ['--pretend' => true, '--database' => 'foo', '--step' => 2]); } diff --git a/tests/Database/DatabaseMigratorIntegrationTest.php b/tests/Database/DatabaseMigratorIntegrationTest.php index 5f48d9e5f247..ad3a4ea2ac33 100644 --- a/tests/Database/DatabaseMigratorIntegrationTest.php +++ b/tests/Database/DatabaseMigratorIntegrationTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Database; use Illuminate\Support\Str; +use Mockery; use PHPUnit\Framework\TestCase; use Illuminate\Filesystem\Filesystem; use Illuminate\Database\Migrations\Migrator; @@ -39,6 +40,11 @@ public function setUp() new Filesystem ); + $output = Mockery::mock('\Illuminate\Console\OutputStyle'); + $output->shouldReceive('writeln'); + + $this->migrator->setOutput($output); + if (! $repository->repositoryExists()) { $repository->createRepository(); } From 7bf5189a5d41775b620e97ddfb13601c5f5d2856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Nabia=C5=82ek?= Date: Wed, 11 Jul 2018 17:58:23 +0200 Subject: [PATCH 0130/2459] Apply StyleCI patch --- src/Illuminate/Database/Migrations/Migrator.php | 2 +- tests/Database/DatabaseMigratorIntegrationTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index edeee670aeb1..9472824b9406 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -2,10 +2,10 @@ namespace Illuminate\Database\Migrations; -use Illuminate\Console\OutputStyle; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Support\Collection; +use Illuminate\Console\OutputStyle; use Illuminate\Filesystem\Filesystem; use Illuminate\Database\ConnectionResolverInterface as Resolver; diff --git a/tests/Database/DatabaseMigratorIntegrationTest.php b/tests/Database/DatabaseMigratorIntegrationTest.php index ad3a4ea2ac33..d13da9d25aa8 100644 --- a/tests/Database/DatabaseMigratorIntegrationTest.php +++ b/tests/Database/DatabaseMigratorIntegrationTest.php @@ -2,8 +2,8 @@ namespace Illuminate\Tests\Database; -use Illuminate\Support\Str; use Mockery; +use Illuminate\Support\Str; use PHPUnit\Framework\TestCase; use Illuminate\Filesystem\Filesystem; use Illuminate\Database\Migrations\Migrator; From 04a46ab05319533fc072be2d163fc5ebf9c3b7ee Mon Sep 17 00:00:00 2001 From: Jarek Tkaczyk Date: Thu, 12 Jul 2018 21:53:46 +0800 Subject: [PATCH 0131/2459] [5.7] tiny cleanup in Cache ns (#24819) * don't return anything for void * cleanup Lock abstract & its implementations --- src/Illuminate/Cache/Lock.php | 10 +++++++++- src/Illuminate/Cache/MemcachedLock.php | 4 +--- src/Illuminate/Cache/RedisLock.php | 4 +--- src/Illuminate/Cache/Repository.php | 4 +++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index e81bee6e08eb..3ed94b392924 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -3,9 +3,10 @@ namespace Illuminate\Cache; use Illuminate\Support\InteractsWithTime; +use Illuminate\Contracts\Cache\Lock as LockContract; use Illuminate\Contracts\Cache\LockTimeoutException; -abstract class Lock +abstract class Lock implements LockContract { use InteractsWithTime; @@ -43,6 +44,13 @@ public function __construct($name, $seconds) */ abstract public function acquire(); + /** + * Release the lock. + * + * @return void + */ + abstract public function release(); + /** * Attempt to acquire the lock. * diff --git a/src/Illuminate/Cache/MemcachedLock.php b/src/Illuminate/Cache/MemcachedLock.php index 1b0627cc0664..c0db841d7973 100644 --- a/src/Illuminate/Cache/MemcachedLock.php +++ b/src/Illuminate/Cache/MemcachedLock.php @@ -2,9 +2,7 @@ namespace Illuminate\Cache; -use Illuminate\Contracts\Cache\Lock as LockContract; - -class MemcachedLock extends Lock implements LockContract +class MemcachedLock extends Lock { /** * The Memcached instance. diff --git a/src/Illuminate/Cache/RedisLock.php b/src/Illuminate/Cache/RedisLock.php index c15569fe8a3b..6ce5afe59427 100644 --- a/src/Illuminate/Cache/RedisLock.php +++ b/src/Illuminate/Cache/RedisLock.php @@ -2,9 +2,7 @@ namespace Illuminate\Cache; -use Illuminate\Contracts\Cache\Lock as LockContract; - -class RedisLock extends Lock implements LockContract +class RedisLock extends Lock { /** * The Redis factory implementation. diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index de06b9ca9c54..67c5e481469a 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -188,7 +188,9 @@ public function pull($key, $default = null) public function put($key, $value, $minutes = null) { if (is_array($key)) { - return $this->putMany($key, $value); + $this->putMany($key, $value); + + return; } if (! is_null($minutes = $this->getMinutes($minutes))) { From ee437b1ef09fe55809811cf4e5563bd35bcb9d94 Mon Sep 17 00:00:00 2001 From: Abdulrahman Date: Fri, 13 Jul 2018 00:10:51 +0300 Subject: [PATCH 0132/2459] logging for pusher >= 3.0.0 --- .../Broadcasters/PusherBroadcaster.php | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index ee2b1b5af9b8..f20ffca5a8df 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -8,9 +8,7 @@ use Illuminate\Broadcasting\BroadcastException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Psr\Log\LoggerInterface; -use Psr\Log\LogLevel; use Illuminate\Container\Container; -use Illuminate\Config\Repository as ConfigRepository; class PusherBroadcaster extends Broadcaster { @@ -31,18 +29,14 @@ public function __construct(Pusher $pusher) { $this->pusher = $pusher; - $this->pusher->set_logger(new class() { - public function log($message) - { - $app = Container::getInstance(); - $config = $app->make(ConfigRepository::class); - - if ($config->get('app.debug')) { - return $app->make(LoggerInterface::class) - ->log(LogLevel::INFO, $message); - } - } - }); + $container = Container::getInstance(); + + if (version_compare($this->pusher::$VERSION, '3.0.0', '>=') && + $container->make('config')->get('app.debug')) { + $this->pusher->setLogger( + $container->make(LoggerInterface::class) + ); + } } /** From b343c4fd40e4c8466e205ee3347a893a0dcdb1c2 Mon Sep 17 00:00:00 2001 From: Dwight Watson Date: Fri, 13 Jul 2018 23:16:06 +1000 Subject: [PATCH 0133/2459] Remove aria-label on form tags (#24839) --- src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub | 2 +- .../Auth/Console/stubs/make/views/auth/passwords/email.stub | 2 +- .../Auth/Console/stubs/make/views/auth/passwords/reset.stub | 2 +- src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub index 474be66e4c74..47e3f53068ad 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub @@ -8,7 +8,7 @@
{{ __('Login') }}
- + @csrf
diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub index 12e808345211..ccbee595c03a 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub @@ -14,7 +14,7 @@
@endif - + @csrf
diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub index fca94d414901..bf27f4c85688 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub @@ -8,7 +8,7 @@
{{ __('Reset Password') }}
- + @csrf diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub index f9dd66293f8a..ad95f2cfd98c 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub @@ -8,7 +8,7 @@
{{ __('Register') }}
- + @csrf
From 6b9a00dbf0e6f094a7b68798f3a55804d2a16964 Mon Sep 17 00:00:00 2001 From: Abdulrahman Date: Fri, 13 Jul 2018 17:38:56 +0300 Subject: [PATCH 0134/2459] move to BroadcastManager --- src/Illuminate/Broadcasting/BroadcastManager.php | 15 +++++++++++---- .../Broadcasters/PusherBroadcaster.php | 13 +------------ 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index 0ac9055f8301..8d8ae88dc46d 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -212,10 +212,17 @@ protected function callCustomCreator(array $config) */ protected function createPusherDriver(array $config) { - return new PusherBroadcaster( - new Pusher($config['key'], $config['secret'], - $config['app_id'], $config['options'] ?? []) - ); + $pusher = new Pusher($config['key'], $config['secret'], + $config['app_id'], $config['options'] ?? []); + + if (version_compare($pusher::$VERSION, '3.0.0', '>=') && + $this->app->make('config')->get('app.debug')) { + $pusher->setLogger( + $this->app->make(LoggerInterface::class) + ); + } + + return new PusherBroadcaster($pusher); } /** diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index f20ffca5a8df..afb922a9bdc0 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -7,13 +7,11 @@ use Illuminate\Support\Str; use Illuminate\Broadcasting\BroadcastException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; -use Psr\Log\LoggerInterface; -use Illuminate\Container\Container; class PusherBroadcaster extends Broadcaster { /** - * The Pusher SDK instance. + * The Pusher SDK instance. * * @var \Pusher\Pusher */ @@ -28,15 +26,6 @@ class PusherBroadcaster extends Broadcaster public function __construct(Pusher $pusher) { $this->pusher = $pusher; - - $container = Container::getInstance(); - - if (version_compare($this->pusher::$VERSION, '3.0.0', '>=') && - $container->make('config')->get('app.debug')) { - $this->pusher->setLogger( - $container->make(LoggerInterface::class) - ); - } } /** From 9fd8c9843240d1861613c26b67c9fcf9402cac54 Mon Sep 17 00:00:00 2001 From: Abdulrahman Date: Sat, 14 Jul 2018 22:14:26 +0300 Subject: [PATCH 0135/2459] snince it's always >= 3.0.0 --- src/Illuminate/Broadcasting/BroadcastManager.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index 8d8ae88dc46d..b5d4837e2ccd 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -215,8 +215,7 @@ protected function createPusherDriver(array $config) $pusher = new Pusher($config['key'], $config['secret'], $config['app_id'], $config['options'] ?? []); - if (version_compare($pusher::$VERSION, '3.0.0', '>=') && - $this->app->make('config')->get('app.debug')) { + if ($this->app->make('config')->get('app.debug')) { $pusher->setLogger( $this->app->make(LoggerInterface::class) ); From 01d2a27d7f029e8728c9af4ae9dab2f1afe72066 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Sun, 15 Jul 2018 16:16:51 +0200 Subject: [PATCH 0136/2459] Make MailFake implement MailQueue interface (#24849) --- .../Support/Testing/Fakes/MailFake.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Testing/Fakes/MailFake.php b/src/Illuminate/Support/Testing/Fakes/MailFake.php index 48392d1d1b9d..12235bc91f1b 100644 --- a/src/Illuminate/Support/Testing/Fakes/MailFake.php +++ b/src/Illuminate/Support/Testing/Fakes/MailFake.php @@ -4,10 +4,11 @@ use Illuminate\Contracts\Mail\Mailer; use Illuminate\Contracts\Mail\Mailable; +use Illuminate\Contracts\Mail\MailQueue; use PHPUnit\Framework\Assert as PHPUnit; use Illuminate\Contracts\Queue\ShouldQueue; -class MailFake implements Mailer +class MailFake implements Mailer, MailQueue { /** * All of the mailables that have been sent. @@ -304,6 +305,19 @@ public function queue($view, $queue = null) $this->queuedMailables[] = $view; } + /** + * Queue a new e-mail message for sending after (n) seconds. + * + * @param \DateTimeInterface|\DateInterval|int $delay + * @param string|array|\Illuminate\Contracts\Mail\Mailable $view + * @param string $queue + * @return mixed + */ + public function later($delay, $view, $queue = null) + { + $this->queue($view, $queue); + } + /** * Get the array of failed recipients. * From 2ae5872a24a71094521c06b4f682e053f9ec8fe6 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 15 Jul 2018 09:22:51 -0500 Subject: [PATCH 0137/2459] use local configuration options --- src/Illuminate/Broadcasting/BroadcastManager.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index b5d4837e2ccd..864b32010507 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -212,13 +212,13 @@ protected function callCustomCreator(array $config) */ protected function createPusherDriver(array $config) { - $pusher = new Pusher($config['key'], $config['secret'], - $config['app_id'], $config['options'] ?? []); + $pusher = new Pusher( + $config['key'], $config['secret'], + $config['app_id'], $config['options'] ?? [] + ); - if ($this->app->make('config')->get('app.debug')) { - $pusher->setLogger( - $this->app->make(LoggerInterface::class) - ); + if ($config['log'] ?? false) { + $pusher->setLogger($this->app->make(LoggerInterface::class)); } return new PusherBroadcaster($pusher); From db147997b7ca1f937366e0f5e80d419b31470eac Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 15 Jul 2018 09:36:43 -0500 Subject: [PATCH 0138/2459] formatting --- .../Console/Migrations/MigrateCommand.php | 9 +++--- .../Database/Migrations/Migrator.php | 29 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php index fea29888a5be..79d48146e265 100755 --- a/src/Illuminate/Database/Console/Migrations/MigrateCommand.php +++ b/src/Illuminate/Database/Console/Migrations/MigrateCommand.php @@ -65,10 +65,11 @@ public function handle() // Next, we will check to see if a path option has been defined. If it has // we will use the path relative to the root of this installation folder // so that migrations may be run for any path within the applications. - $this->migrator->setOutput($this->output)->run($this->getMigrationPaths(), [ - 'pretend' => $this->option('pretend'), - 'step' => $this->option('step'), - ]); + $this->migrator->setOutput($this->output) + ->run($this->getMigrationPaths(), [ + 'pretend' => $this->option('pretend'), + 'step' => $this->option('step'), + ]); // Finally, if the "seed" option has been given, we will re-run the database // seed task to re-populate the database, which is convenient when adding diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index 9472824b9406..8908b921a57e 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -70,20 +70,6 @@ public function __construct(MigrationRepositoryInterface $repository, $this->repository = $repository; } - /** - * Set output. - * - * @param \Illuminate\Console\OutputStyle $output - * - * @return $this - */ - public function setOutput(OutputStyle $output) - { - $this->output = $output; - - return $this; - } - /** * Run the pending migrations at a given path. * @@ -581,7 +567,20 @@ public function getFilesystem() } /** - * Raise a note event for the migrator. + * Set the output implementation that should be used by the console. + * + * @param \Illuminate\Console\OutputStyle $output + * @return $this + */ + public function setOutput(OutputStyle $output) + { + $this->output = $output; + + return $this; + } + + /** + * Write a note to the conosle's output. * * @param string $message * @return void From a43562b6a139887b421d1d3f3fdfc110c9a8df2b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 15 Jul 2018 09:55:22 -0500 Subject: [PATCH 0139/2459] add joiningTableSegment to Model --- .../Eloquent/Concerns/HasRelationships.php | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index e4b69bc9429d..313c21121ca0 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -425,7 +425,7 @@ public function belongsToMany($related, $table = null, $foreignPivotKey = null, // models using underscores in alphabetical order. The two model names // are transformed to snake case from their default CamelCase also. if (is_null($table)) { - $table = $this->joiningTable($related); + $table = $this->joiningTable($related, $instance); } return $this->newBelongsToMany( @@ -563,24 +563,36 @@ protected function guessBelongsToManyRelation() * Get the joining table name for a many-to-many relation. * * @param string $related + * @param \Illuminate\Database\Eloquent\Model|null $instance * @return string */ - public function joiningTable($related) + public function joiningTable($related, $instance = null) { // The joining table name, by convention, is simply the snake cased models // sorted alphabetically and concatenated with an underscore, so we can // just sort the models and join them together to get the table name. - $models = [ - Str::snake(class_basename($related)), - Str::snake(class_basename($this)), + $segments = [ + $instance ? $instance->joiningTableSegment() + : Str::snake(class_basename($related)), + $this->joiningTableSegment(), ]; // Now that we have the model names in an array we can just sort them and // use the implode function to join them together with an underscores, // which is typically used by convention within the database system. - sort($models); + sort($segments); - return strtolower(implode('_', $models)); + return strtolower(implode('_', $segments)); + } + + /** + * Get this model's half of the intermediate table name for belongsToMany relationships. + * + * @return string + */ + public function joiningTableSegment() + { + return Str::snake(class_basename($this)); } /** From 5bafdb9cad9ff74a7d81b36c1bfbf87c406b2512 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 15 Jul 2018 10:01:12 -0500 Subject: [PATCH 0140/2459] formatting and cleaning --- src/Illuminate/Mail/Mailable.php | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 1c232f681826..2390681baa3e 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -119,7 +119,7 @@ class Mailable implements MailableContract, Renderable public $rawAttachments = []; /** - * The attachments coming from storage disk. + * The attachments from a storage disk. * * @var array */ @@ -352,16 +352,30 @@ protected function buildAttachments($message) ); } + $this->buildDiskAttachments($message); + + return $this; + } + + /** + * Add all of the disk attachments to the message. + * + * @param \Illuminate\Mail\Message $message + * @return void + */ + protected function buildDiskAttachments($message) + { foreach ($this->diskAttachments as $attachment) { - $storage = Container::getInstance()->make(FilesystemFactory::class)->disk($attachment['disk']); + $storage = Container::getInstance()->make( + FilesystemFactory::class + )->disk($attachment['disk']); return $message->attachData( - $storage->get($attachment['path']), $attachment['name'] ?? basename($attachment['path']), + $storage->get($attachment['path']), + $attachment['name'] ?? basename($attachment['path']), array_merge(['mime' => $storage->mimeType($attachment['path'])], $attachment['options']) ); } - - return $this; } /** @@ -741,8 +755,12 @@ public function attachFromStorage($path, $name = null, array $options = []) */ public function attachFromStorageDisk($disk, $path, $name = null, array $options = []) { - $name = $name ?? basename($path); - $this->diskAttachments[] = compact('disk', 'path', 'name', 'options'); + $this->diskAttachments[] = [ + 'disk' => $disk, + 'path' => $path, + 'name' => $name ?? basename($path), + 'options' => $options, + ]; return $this; } From 499485ee99e76bafa740753df5d8f29f1ea0e49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Tue, 17 Jul 2018 15:01:06 +0200 Subject: [PATCH 0141/2459] [5.7] Dont try to display message if Output is not set (#24873) * Dont try to display message if Output is not set * StyleCI * Add namespace --- .../Database/Migrations/Migrator.php | 4 +- tests/Integration/Migration/MigratorTest.php | 45 +++++++++++++++++++ ...2014_10_12_000000_create_members_table.php | 37 +++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 tests/Integration/Migration/MigratorTest.php create mode 100644 tests/Integration/Migration/fixtures/2014_10_12_000000_create_members_table.php diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index 8908b921a57e..66cda4499dbb 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -587,6 +587,8 @@ public function setOutput(OutputStyle $output) */ protected function note($message) { - $this->output->writeln($message); + if ($this->output) { + $this->output->writeln($message); + } } } diff --git a/tests/Integration/Migration/MigratorTest.php b/tests/Integration/Migration/MigratorTest.php new file mode 100644 index 000000000000..0f418486d905 --- /dev/null +++ b/tests/Integration/Migration/MigratorTest.php @@ -0,0 +1,45 @@ +set('app.debug', 'true'); + + $app['config']->set('database.default', 'testbench'); + $app['config']->set('database.connections.testbench', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + } + + /** + * @test + */ + public function dont_display_output_when_output_object_is_not_available() + { + $migrator = $this->app->make('migrator'); + + $migrator->getRepository()->createRepository(); + + $migrator->run([__DIR__.'/fixtures']); + + $this->assertTrue($this->tableExists('members')); + } + + private function tableExists($table): bool + { + try { + $this->app->make('db')->select("SELECT COUNT(*) FROM $table"); + } catch (\PDOException $e) { + return false; + } + + return true; + } +} diff --git a/tests/Integration/Migration/fixtures/2014_10_12_000000_create_members_table.php b/tests/Integration/Migration/fixtures/2014_10_12_000000_create_members_table.php new file mode 100644 index 000000000000..422f36d17e69 --- /dev/null +++ b/tests/Integration/Migration/fixtures/2014_10_12_000000_create_members_table.php @@ -0,0 +1,37 @@ +increments('id'); + $table->string('name'); + $table->string('email')->unique(); + $table->string('password'); + $table->rememberToken(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('members'); + } +} From 7c3f0f73fe9b40ca8af33207c4e28bbb67719c3e Mon Sep 17 00:00:00 2001 From: Domenico Rizzo Date: Tue, 17 Jul 2018 15:40:46 +0200 Subject: [PATCH 0142/2459] Guard system management for channels (PusherBroadcaster only) --- .../Broadcasting/Broadcasters/Broadcaster.php | 24 +++++++++++++++++-- .../Broadcasters/PusherBroadcaster.php | 19 +++++++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index 18a8fefbdd8e..158ce14af873 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -21,6 +21,13 @@ abstract class Broadcaster implements BroadcasterContract */ protected $channels = []; + /** + * The registered channel options. + * + * @var array + */ + protected $channelsOptions = []; + /** * The binding registrar instance. * @@ -35,10 +42,12 @@ abstract class Broadcaster implements BroadcasterContract * @param callable|string $callback * @return $this */ - public function channel($channel, $callback) + public function channel($channel, $callback, array $options = []) { $this->channels[$channel] = $callback; + $this->channelsOptions[$channel] = $options; + return $this; } @@ -52,6 +61,17 @@ public function channel($channel, $callback) */ protected function verifyUserCanAccessChannel($request, $channel) { + $options = []; + + foreach ($this->channelsOptions as $pattern => $opts) { + if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { + continue; + } + + $options = $opts; + } + + foreach ($this->channels as $pattern => $callback) { if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { continue; @@ -61,7 +81,7 @@ protected function verifyUserCanAccessChannel($request, $channel) $handler = $this->normalizeChannelHandlerToCallable($callback); - if ($result = $handler($request->user(), ...$parameters)) { + if ($result = $handler($request->user($options['guard'] ?? null), ...$parameters)) { return $this->validAuthenticationResponse($request, $result); } } diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 856024f373d8..964d8ebd2bec 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -37,15 +37,24 @@ public function __construct(Pusher $pusher) */ public function auth($request) { + $channelName = Str::startsWith($request->channel_name, 'private-') + ? Str::replaceFirst('private-', '', $request->channel_name) + : Str::replaceFirst('presence-', '', $request->channel_name); + + $options = []; + foreach ($this->channelsOptions as $pattern => $opts) { + if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channelName)) { + continue; + } + + $options = $opts; + } + if (Str::startsWith($request->channel_name, ['private-', 'presence-']) && - ! $request->user()) { + ! $request->user($options['guard'] ?? null)) { throw new AccessDeniedHttpException; } - $channelName = Str::startsWith($request->channel_name, 'private-') - ? Str::replaceFirst('private-', '', $request->channel_name) - : Str::replaceFirst('presence-', '', $request->channel_name); - return parent::verifyUserCanAccessChannel( $request, $channelName ); From 585d934fe2883af9ea5bd002427a30b5633764d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Sun, 22 Jul 2018 03:51:25 +0200 Subject: [PATCH 0143/2459] Add options parameter to validAuthenticationResponse in Broadcast contract --- src/Illuminate/Contracts/Broadcasting/Broadcaster.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Contracts/Broadcasting/Broadcaster.php b/src/Illuminate/Contracts/Broadcasting/Broadcaster.php index 1034e4406823..d351ce8cc0d7 100644 --- a/src/Illuminate/Contracts/Broadcasting/Broadcaster.php +++ b/src/Illuminate/Contracts/Broadcasting/Broadcaster.php @@ -19,7 +19,7 @@ public function auth($request); * @param mixed $result * @return mixed */ - public function validAuthenticationResponse($request, $result); + public function validAuthenticationResponse($request, $result, $options); /** * Broadcast the given event. From 16ed752928a59e0b3003ab54675fcb3096b23d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Sun, 22 Jul 2018 03:53:54 +0200 Subject: [PATCH 0144/2459] Remove options retrieving from Broadcaster --- .../Broadcasting/Broadcasters/Broadcaster.php | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index 158ce14af873..eaa86b23016e 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -59,19 +59,8 @@ public function channel($channel, $callback, array $options = []) * @return mixed * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException */ - protected function verifyUserCanAccessChannel($request, $channel) + protected function verifyUserCanAccessChannel($request, $channel, $options = []) { - $options = []; - - foreach ($this->channelsOptions as $pattern => $opts) { - if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { - continue; - } - - $options = $opts; - } - - foreach ($this->channels as $pattern => $callback) { if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { continue; @@ -82,7 +71,7 @@ protected function verifyUserCanAccessChannel($request, $channel) $handler = $this->normalizeChannelHandlerToCallable($callback); if ($result = $handler($request->user($options['guard'] ?? null), ...$parameters)) { - return $this->validAuthenticationResponse($request, $result); + return $this->validAuthenticationResponse($request, $result, $options); } } From 796eb9315b2a1eaee830873ebdd4950b757fcdb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Sun, 22 Jul 2018 03:54:45 +0200 Subject: [PATCH 0145/2459] Add options to RedisBroadcaster --- .../Broadcasters/RedisBroadcaster.php | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index ccda0e65faf5..c12961675f6d 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -45,17 +45,26 @@ public function __construct(Redis $redis, $connection = null) */ public function auth($request) { + $channelName = Str::startsWith($request->channel_name, 'private-') + ? Str::replaceFirst('private-', '', $request->channel_name) + : Str::replaceFirst('presence-', '', $request->channel_name); + + $options = []; + foreach ($this->channelsOptions as $pattern => $opts) { + if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channelName)) { + continue; + } + + $options = $opts; + } + if (Str::startsWith($request->channel_name, ['private-', 'presence-']) && - ! $request->user()) { + ! $request->user($options['guard'] ?? null)) { throw new AccessDeniedHttpException; } - $channelName = Str::startsWith($request->channel_name, 'private-') - ? Str::replaceFirst('private-', '', $request->channel_name) - : Str::replaceFirst('presence-', '', $request->channel_name); - return parent::verifyUserCanAccessChannel( - $request, $channelName + $request, $channelName, $options ); } @@ -66,14 +75,14 @@ public function auth($request) * @param mixed $result * @return mixed */ - public function validAuthenticationResponse($request, $result) + public function validAuthenticationResponse($request, $result, $options = []) { if (is_bool($result)) { return json_encode($result); } return json_encode(['channel_data' => [ - 'user_id' => $request->user()->getAuthIdentifier(), + 'user_id' => $request->user($options['guard'] ?? null)->getAuthIdentifier(), 'user_info' => $result, ]]); } From 4d9e85fc4f320fce3c7c386368e00405efb46d3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Sun, 22 Jul 2018 04:00:14 +0200 Subject: [PATCH 0146/2459] Add missing call to guard for Pusher --- .../Broadcasting/Broadcasters/PusherBroadcaster.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index d7bdaff741db..bae2cc4d41b1 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -67,7 +67,7 @@ public function auth($request) * @param mixed $result * @return mixed */ - public function validAuthenticationResponse($request, $result) + public function validAuthenticationResponse($request, $result, $options = []) { if (Str::startsWith($request->channel_name, 'private')) { return $this->decodePusherResponse( @@ -79,7 +79,7 @@ public function validAuthenticationResponse($request, $result) $request, $this->pusher->presence_auth( $request->channel_name, $request->socket_id, - $request->user()->getAuthIdentifier(), $result + $request->user($options['guard'] ?? null)->getAuthIdentifier(), $result ) ); } From ce8fe3d219c045e13c3309e03c624320bb82f07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Sun, 22 Jul 2018 04:01:08 +0200 Subject: [PATCH 0147/2459] Make Null and Log broadcasters validate Broadcaster contract --- src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php | 2 +- src/Illuminate/Broadcasting/Broadcasters/NullBroadcaster.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php index 50877dc976fe..a4af6c12bf59 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php @@ -35,7 +35,7 @@ public function auth($request) /** * {@inheritdoc} */ - public function validAuthenticationResponse($request, $result) + public function validAuthenticationResponse($request, $result, $options = []) { // } diff --git a/src/Illuminate/Broadcasting/Broadcasters/NullBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/NullBroadcaster.php index 6205c90c12da..9fc99ec39857 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/NullBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/NullBroadcaster.php @@ -15,7 +15,7 @@ public function auth($request) /** * {@inheritdoc} */ - public function validAuthenticationResponse($request, $result) + public function validAuthenticationResponse($request, $result, $options = []) { // } From eeb39cbe744a781b8f3ed9c36cef6204bdaaed39 Mon Sep 17 00:00:00 2001 From: Mathieu TUDISCO Date: Sun, 22 Jul 2018 16:35:46 +0200 Subject: [PATCH 0148/2459] [5.7] Change Log FacadeAccessor to 'log'. (#24921) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change Log FacadeAccessor to 'log'. * Typo 🤦‍♂️ --- src/Illuminate/Support/Facades/Log.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Support/Facades/Log.php b/src/Illuminate/Support/Facades/Log.php index 103cf589856e..589e0e193549 100755 --- a/src/Illuminate/Support/Facades/Log.php +++ b/src/Illuminate/Support/Facades/Log.php @@ -2,8 +2,6 @@ namespace Illuminate\Support\Facades; -use Psr\Log\LoggerInterface; - /** * @method static void emergency(string $message, array $context = []) * @method static void alert(string $message, array $context = []) @@ -31,6 +29,6 @@ class Log extends Facade */ protected static function getFacadeAccessor() { - return LoggerInterface::class; + return 'log'; } } From a57504a6875a863614488fb5562c203fd43196a9 Mon Sep 17 00:00:00 2001 From: Willy Rizzo Date: Sun, 22 Jul 2018 19:08:24 +0200 Subject: [PATCH 0149/2459] Added retrieveOptionsForChannel($channel) and retrieveUser to Broadcaster --- .../Broadcasting/Broadcasters/Broadcaster.php | 43 +++++++++++++++++-- .../Broadcasters/LogBroadcaster.php | 2 +- .../Broadcasters/NullBroadcaster.php | 2 +- .../Broadcasters/PusherBroadcaster.php | 6 +-- .../Broadcasters/RedisBroadcaster.php | 4 +- .../Contracts/Broadcasting/Broadcaster.php | 2 +- 6 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index eaa86b23016e..d710be0b7391 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -59,7 +59,7 @@ public function channel($channel, $callback, array $options = []) * @return mixed * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException */ - protected function verifyUserCanAccessChannel($request, $channel, $options = []) + protected function verifyUserCanAccessChannel($request, $channel) { foreach ($this->channels as $pattern => $callback) { if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { @@ -70,8 +70,8 @@ protected function verifyUserCanAccessChannel($request, $channel, $options = []) $handler = $this->normalizeChannelHandlerToCallable($callback); - if ($result = $handler($request->user($options['guard'] ?? null), ...$parameters)) { - return $this->validAuthenticationResponse($request, $result, $options); + if ($result = $handler($this->retrieveUser($request, $channel), ...$parameters)) { + return $this->validAuthenticationResponse($request, $result); } } @@ -265,4 +265,41 @@ protected function normalizeChannelHandlerToCallable($callback) ->join(...$args); }; } + + /** + * Retrieve options for a certain channel + * + * @param string $channel + * @return array + */ + protected function retrieveOptionsForChannel($channel) + { + $channelName = Str::startsWith($channel, 'private-') + ? Str::replaceFirst('private-', '', $channel) + : Str::replaceFirst('presence-', '', $channel); + + foreach ($this->channelsOptions as $pattern => $opts) { + if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channelName)) { + continue; + } + + return $opts; + } + + return []; + } + + /** + * Retrieve current user + * + * @param \Illuminate\Http\Request $request + * @param string $channel + * @return mixed + */ + protected function retrieveUser($request, $channel) + { + $options = $this->retrieveOptionsForChannel($channel); + + return $request->user($options['guard'] ?? null); + } } diff --git a/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php index a4af6c12bf59..50877dc976fe 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/LogBroadcaster.php @@ -35,7 +35,7 @@ public function auth($request) /** * {@inheritdoc} */ - public function validAuthenticationResponse($request, $result, $options = []) + public function validAuthenticationResponse($request, $result) { // } diff --git a/src/Illuminate/Broadcasting/Broadcasters/NullBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/NullBroadcaster.php index 9fc99ec39857..6205c90c12da 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/NullBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/NullBroadcaster.php @@ -15,7 +15,7 @@ public function auth($request) /** * {@inheritdoc} */ - public function validAuthenticationResponse($request, $result, $options = []) + public function validAuthenticationResponse($request, $result) { // } diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index bae2cc4d41b1..44719e336ec1 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -51,7 +51,7 @@ public function auth($request) } if (Str::startsWith($request->channel_name, ['private-', 'presence-']) && - ! $request->user($options['guard'] ?? null)) { + ! $this->retrieveUser($request, $request->channel_name)) { throw new AccessDeniedHttpException; } @@ -67,7 +67,7 @@ public function auth($request) * @param mixed $result * @return mixed */ - public function validAuthenticationResponse($request, $result, $options = []) + public function validAuthenticationResponse($request, $result) { if (Str::startsWith($request->channel_name, 'private')) { return $this->decodePusherResponse( @@ -79,7 +79,7 @@ public function validAuthenticationResponse($request, $result, $options = []) $request, $this->pusher->presence_auth( $request->channel_name, $request->socket_id, - $request->user($options['guard'] ?? null)->getAuthIdentifier(), $result + $this->retrieveUser($request, $request->channel_name)->getAuthIdentifier(), $result ) ); } diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index c12961675f6d..b9c36d778a00 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -59,7 +59,7 @@ public function auth($request) } if (Str::startsWith($request->channel_name, ['private-', 'presence-']) && - ! $request->user($options['guard'] ?? null)) { + ! $this->retrieveUser($request, $request->channel_name)) { throw new AccessDeniedHttpException; } @@ -82,7 +82,7 @@ public function validAuthenticationResponse($request, $result, $options = []) } return json_encode(['channel_data' => [ - 'user_id' => $request->user($options['guard'] ?? null)->getAuthIdentifier(), + 'user_id' => $this->retrieveUser($request, $request->channel_name)->getAuthIdentifier(), 'user_info' => $result, ]]); } diff --git a/src/Illuminate/Contracts/Broadcasting/Broadcaster.php b/src/Illuminate/Contracts/Broadcasting/Broadcaster.php index d351ce8cc0d7..1034e4406823 100644 --- a/src/Illuminate/Contracts/Broadcasting/Broadcaster.php +++ b/src/Illuminate/Contracts/Broadcasting/Broadcaster.php @@ -19,7 +19,7 @@ public function auth($request); * @param mixed $result * @return mixed */ - public function validAuthenticationResponse($request, $result, $options); + public function validAuthenticationResponse($request, $result); /** * Broadcast the given event. From b58519ea8dad18aee716a608476b5c66e975668d Mon Sep 17 00:00:00 2001 From: Willy Rizzo Date: Sun, 22 Jul 2018 19:12:38 +0200 Subject: [PATCH 0150/2459] removed options in validAuthenticationResponse of RedisBroadcaster --- src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index b9c36d778a00..0b4f94fdc061 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -75,7 +75,7 @@ public function auth($request) * @param mixed $result * @return mixed */ - public function validAuthenticationResponse($request, $result, $options = []) + public function validAuthenticationResponse($request, $result) { if (is_bool($result)) { return json_encode($result); From 1dcc31f3083287c75073af3631ae793b29bcaa77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Mon, 23 Jul 2018 02:40:23 +0200 Subject: [PATCH 0151/2459] Add multi guards support + refactoring --- .../Broadcasting/Broadcasters/Broadcaster.php | 39 ++++++++------ .../Broadcasters/PusherBroadcaster.php | 54 +++++++++++++------ .../Broadcasters/RedisBroadcaster.php | 52 +++++++++++++----- 3 files changed, 101 insertions(+), 44 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index d710be0b7391..78c402e9b671 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -5,6 +5,7 @@ use Exception; use ReflectionClass; use ReflectionFunction; +use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Container\Container; use Illuminate\Contracts\Routing\UrlRoutable; @@ -40,9 +41,10 @@ abstract class Broadcaster implements BroadcasterContract * * @param string $channel * @param callable|string $callback + * @param array $options * @return $this */ - public function channel($channel, $callback, array $options = []) + public function channel($channel, $callback, $options = []) { $this->channels[$channel] = $callback; @@ -59,7 +61,7 @@ public function channel($channel, $callback, array $options = []) * @return mixed * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException */ - protected function verifyUserCanAccessChannel($request, $channel) + protected function verifyUserCanAccessChannel($request, $channel, $options = []) { foreach ($this->channels as $pattern => $callback) { if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { @@ -70,7 +72,7 @@ protected function verifyUserCanAccessChannel($request, $channel) $handler = $this->normalizeChannelHandlerToCallable($callback); - if ($result = $handler($this->retrieveUser($request, $channel), ...$parameters)) { + if ($result = $handler($this->retrieveUser($request, $options['guards'] ?? null), ...$parameters)) { return $this->validAuthenticationResponse($request, $result); } } @@ -269,17 +271,13 @@ protected function normalizeChannelHandlerToCallable($callback) /** * Retrieve options for a certain channel * - * @param string $channel + * @param string $channel * @return array */ - protected function retrieveOptionsForChannel($channel) + protected function retrieveChannelOptions($channel) { - $channelName = Str::startsWith($channel, 'private-') - ? Str::replaceFirst('private-', '', $channel) - : Str::replaceFirst('presence-', '', $channel); - foreach ($this->channelsOptions as $pattern => $opts) { - if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channelName)) { + if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { continue; } @@ -290,16 +288,27 @@ protected function retrieveOptionsForChannel($channel) } /** - * Retrieve current user + * Retrieve user by checking in provided guards * * @param \Illuminate\Http\Request $request - * @param string $channel + * @param array $guards + * * @return mixed */ - protected function retrieveUser($request, $channel) + protected function retrieveUser($request, $guards = null) { - $options = $this->retrieveOptionsForChannel($channel); + if (is_null($guards)) { + return $request->user(); + } + + $guards = Arr::wrap($guards); + + foreach ($guards as $guard) { + if ($user = $request->user($guard)) { + return $user; + } + } - return $request->user($options['guard'] ?? null); + return null; } } diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 44719e336ec1..8d5a4db42085 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -37,26 +37,17 @@ public function __construct(Pusher $pusher) */ public function auth($request) { - $channelName = Str::startsWith($request->channel_name, 'private-') - ? Str::replaceFirst('private-', '', $request->channel_name) - : Str::replaceFirst('presence-', '', $request->channel_name); + $channelName = $this->normalizeChannelName($request->channel_name); - $options = []; - foreach ($this->channelsOptions as $pattern => $opts) { - if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channelName)) { - continue; - } + $options = $this->retrieveChannelOptions($channelName); - $options = $opts; - } - - if (Str::startsWith($request->channel_name, ['private-', 'presence-']) && - ! $this->retrieveUser($request, $request->channel_name)) { + if ($this->isGuardedChannel($request->channel_name) && + ! $this->retrieveUser($request, $options['guards'] ?? null)) { throw new AccessDeniedHttpException; } return parent::verifyUserCanAccessChannel( - $request, $channelName + $request, $channelName, $options ); } @@ -75,11 +66,15 @@ public function validAuthenticationResponse($request, $result) ); } + $options = $this->retrieveChannelOptions( + $this->normalizeChannelName($request->channel_name) + ); + return $this->decodePusherResponse( $request, $this->pusher->presence_auth( $request->channel_name, $request->socket_id, - $this->retrieveUser($request, $request->channel_name)->getAuthIdentifier(), $result + $this->retrieveUser($request, $options['guards'] ?? null)->getAuthIdentifier(), $result ) ); } @@ -136,4 +131,33 @@ public function getPusher() { return $this->pusher; } + + /** + * Return true if channel is protected by authentication + * + * @param string $channel + * + * @return bool + */ + public function isGuardedChannel($channel) + { + return Str::startsWith($channel, ['private-', 'presence-']); + } + + /** + * Remove prefix from channel name + * + * @param string $channel + * + * @return string + */ + public function normalizeChannelName($channel) + { + if ($this->isGuardedChannel($channel)) { + return Str::startsWith($channel, 'private-') + ? Str::replaceFirst('private-', '', $channel) + : Str::replaceFirst('presence-', '', $channel); + } + return $channel; + } } diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index 0b4f94fdc061..059e8e99fbb1 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -45,21 +45,12 @@ public function __construct(Redis $redis, $connection = null) */ public function auth($request) { - $channelName = Str::startsWith($request->channel_name, 'private-') - ? Str::replaceFirst('private-', '', $request->channel_name) - : Str::replaceFirst('presence-', '', $request->channel_name); + $channelName = $this->normalizeChannelName($request->channel_name); - $options = []; - foreach ($this->channelsOptions as $pattern => $opts) { - if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channelName)) { - continue; - } + $options = $this->retrieveChannelOptions($channelName); - $options = $opts; - } - - if (Str::startsWith($request->channel_name, ['private-', 'presence-']) && - ! $this->retrieveUser($request, $request->channel_name)) { + if ($this->isGuardedChannel($request->channel_name) && + ! $this->retrieveUser($request, $options['guards'] ?? null)) { throw new AccessDeniedHttpException; } @@ -81,8 +72,12 @@ public function validAuthenticationResponse($request, $result) return json_encode($result); } + $options = $this->retrieveChannelOptions( + $this->normalizeChannelName($request->channel_name) + ); + return json_encode(['channel_data' => [ - 'user_id' => $this->retrieveUser($request, $request->channel_name)->getAuthIdentifier(), + 'user_id' => $this->retrieveUser($request, $options['guards'] ?? null)->getAuthIdentifier(), 'user_info' => $result, ]]); } @@ -109,4 +104,33 @@ public function broadcast(array $channels, $event, array $payload = []) $connection->publish($channel, $payload); } } + + /** + * Return true if channel is protected by authentication + * + * @param string $channel + * + * @return bool + */ + public function isGuardedChannel($channel) + { + return Str::startsWith($channel, ['private-', 'presence-']); + } + + /** + * Remove prefix from channel name + * + * @param string $channel + * + * @return string + */ + public function normalizeChannelName($channel) + { + if ($this->isGuardedChannel($channel)) { + return Str::startsWith($channel, 'private-') + ? Str::replaceFirst('private-', '', $channel) + : Str::replaceFirst('presence-', '', $channel); + } + return $channel; + } } From 31ed2856586850d5b2aa98e12af1e3c7a4e87a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Mon, 23 Jul 2018 03:07:12 +0200 Subject: [PATCH 0152/2459] Fix phpDoc + format --- src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php | 3 ++- src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php | 2 -- src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index 78c402e9b671..a261b63c986a 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -58,6 +58,7 @@ public function channel($channel, $callback, $options = []) * * @param \Illuminate\Http\Request $request * @param string $channel + * @param array $options * @return mixed * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException */ @@ -271,7 +272,7 @@ protected function normalizeChannelHandlerToCallable($callback) /** * Retrieve options for a certain channel * - * @param string $channel + * @param string $channel * @return array */ protected function retrieveChannelOptions($channel) diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 8d5a4db42085..b1996a74cc07 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -136,7 +136,6 @@ public function getPusher() * Return true if channel is protected by authentication * * @param string $channel - * * @return bool */ public function isGuardedChannel($channel) @@ -148,7 +147,6 @@ public function isGuardedChannel($channel) * Remove prefix from channel name * * @param string $channel - * * @return string */ public function normalizeChannelName($channel) diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index 059e8e99fbb1..738be026c176 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -109,7 +109,6 @@ public function broadcast(array $channels, $event, array $payload = []) * Return true if channel is protected by authentication * * @param string $channel - * * @return bool */ public function isGuardedChannel($channel) @@ -121,7 +120,6 @@ public function isGuardedChannel($channel) * Remove prefix from channel name * * @param string $channel - * * @return string */ public function normalizeChannelName($channel) From ffa5803a9dd72ca431cf4711cf636f3ba20f57db Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 23 Jul 2018 01:31:22 +0200 Subject: [PATCH 0153/2459] Support special float values on PostgreSQL --- .../Eloquent/Concerns/HasAttributes.php | 22 +++++++++++++++++- tests/Database/DatabaseEloquentModelTest.php | 23 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 5067a5b52d84..454021a8df6c 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -478,7 +478,7 @@ protected function castAttribute($key, $value) case 'real': case 'float': case 'double': - return (float) $value; + return $this->fromFloat($value); case 'string': return (string) $value; case 'bool': @@ -692,6 +692,26 @@ public function fromJson($value, $asObject = false) return json_decode($value, ! $asObject); } + /** + * Cast the given float value. + * + * @param mixed $value + * @return mixed + */ + public function fromFloat($value) + { + switch ($value) { + case 'Infinity': + return INF; + case '-Infinity': + return -INF; + case 'NaN': + return NAN; + default: + return (float) $value; + } + } + /** * Return a timestamp as DateTime object with time set to 00:00:00. * diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 45da52a15e05..78d4f3279a2e 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -1613,6 +1613,29 @@ public function testModelAttributeCastingFailsOnUnencodableData() $model->getAttributes(); } + public function testModelAttributeCastingWithSpecialFloatValues() + { + $model = new EloquentModelCastingStub; + + $model->floatAttribute = 'Infinity'; + $this->assertEquals(INF, $model->floatAttribute); + + $model->floatAttribute = INF; + $this->assertEquals(INF, $model->floatAttribute); + + $model->floatAttribute = '-Infinity'; + $this->assertEquals(-INF, $model->floatAttribute); + + $model->floatAttribute = -INF; + $this->assertEquals(-INF, $model->floatAttribute); + + $model->floatAttribute = 'NaN'; + $this->assertNan($model->floatAttribute); + + $model->floatAttribute = NAN; + $this->assertNan($model->floatAttribute); + } + public function testUpdatingNonExistentModelFails() { $model = new EloquentModelStub; From fe63381355f094e4b99b1791d6ee8c142149875b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Thu, 26 Jul 2018 02:33:52 +0200 Subject: [PATCH 0154/2459] Add retrieving user by channel using options --- .../Broadcasting/Broadcasters/Broadcaster.php | 13 +++++++------ .../Broadcasting/Broadcasters/PusherBroadcaster.php | 12 ++++-------- .../Broadcasting/Broadcasters/RedisBroadcaster.php | 12 ++++-------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index a261b63c986a..824737ec10de 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -58,11 +58,10 @@ public function channel($channel, $callback, $options = []) * * @param \Illuminate\Http\Request $request * @param string $channel - * @param array $options * @return mixed * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException */ - protected function verifyUserCanAccessChannel($request, $channel, $options = []) + protected function verifyUserCanAccessChannel($request, $channel) { foreach ($this->channels as $pattern => $callback) { if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { @@ -73,7 +72,7 @@ protected function verifyUserCanAccessChannel($request, $channel, $options = []) $handler = $this->normalizeChannelHandlerToCallable($callback); - if ($result = $handler($this->retrieveUser($request, $options['guards'] ?? null), ...$parameters)) { + if ($result = $handler($this->retrieveUser($request, $channel), ...$parameters)) { return $this->validAuthenticationResponse($request, $result); } } @@ -292,12 +291,14 @@ protected function retrieveChannelOptions($channel) * Retrieve user by checking in provided guards * * @param \Illuminate\Http\Request $request - * @param array $guards - * * @return mixed */ - protected function retrieveUser($request, $guards = null) + protected function retrieveUser($request, $channel) { + $options = $this->retrieveChannelOptions($channel); + + $guards = $options['guards'] ?? null; + if (is_null($guards)) { return $request->user(); } diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index b1996a74cc07..784786381e8b 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -39,15 +39,13 @@ public function auth($request) { $channelName = $this->normalizeChannelName($request->channel_name); - $options = $this->retrieveChannelOptions($channelName); - if ($this->isGuardedChannel($request->channel_name) && - ! $this->retrieveUser($request, $options['guards'] ?? null)) { + ! $this->retrieveUser($request, $channelName)) { throw new AccessDeniedHttpException; } return parent::verifyUserCanAccessChannel( - $request, $channelName, $options + $request, $channelName ); } @@ -66,15 +64,13 @@ public function validAuthenticationResponse($request, $result) ); } - $options = $this->retrieveChannelOptions( - $this->normalizeChannelName($request->channel_name) - ); + $channelName = $this->normalizeChannelName($request->channel_name); return $this->decodePusherResponse( $request, $this->pusher->presence_auth( $request->channel_name, $request->socket_id, - $this->retrieveUser($request, $options['guards'] ?? null)->getAuthIdentifier(), $result + $this->retrieveUser($request, $channelName)->getAuthIdentifier(), $result ) ); } diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index 738be026c176..3efe6196f7d3 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -47,15 +47,13 @@ public function auth($request) { $channelName = $this->normalizeChannelName($request->channel_name); - $options = $this->retrieveChannelOptions($channelName); - if ($this->isGuardedChannel($request->channel_name) && - ! $this->retrieveUser($request, $options['guards'] ?? null)) { + ! $this->retrieveUser($request, $channelName)) { throw new AccessDeniedHttpException; } return parent::verifyUserCanAccessChannel( - $request, $channelName, $options + $request, $channelName ); } @@ -72,12 +70,10 @@ public function validAuthenticationResponse($request, $result) return json_encode($result); } - $options = $this->retrieveChannelOptions( - $this->normalizeChannelName($request->channel_name) - ); + $channelName = $this->normalizeChannelName($request->channel_name); return json_encode(['channel_data' => [ - 'user_id' => $this->retrieveUser($request, $options['guards'] ?? null)->getAuthIdentifier(), + 'user_id' => $this->retrieveUser($request, $channelName)->getAuthIdentifier(), 'user_info' => $result, ]]); } From b4695e8cb05bd5ce0f0c1e481ae7e40f3f6e8c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Wed, 25 Jul 2018 21:17:14 +0200 Subject: [PATCH 0155/2459] Add tests for Abstract, Redis and Pusher Broadcasters --- tests/Broadcasting/BroadcasterTest.php | 140 ++++++++++ tests/Broadcasting/PusherBroadcasterTest.php | 253 +++++++++++++++++++ tests/Broadcasting/RedisBroadcasterTest.php | 241 ++++++++++++++++++ 3 files changed, 634 insertions(+) create mode 100644 tests/Broadcasting/PusherBroadcasterTest.php create mode 100644 tests/Broadcasting/RedisBroadcasterTest.php diff --git a/tests/Broadcasting/BroadcasterTest.php b/tests/Broadcasting/BroadcasterTest.php index 090741763d2c..9f292bbc02d5 100644 --- a/tests/Broadcasting/BroadcasterTest.php +++ b/tests/Broadcasting/BroadcasterTest.php @@ -94,6 +94,131 @@ public function testNotFoundThrowsHttpException() }; $broadcaster->extractAuthParameters('asd.{model}', 'asd.1', $callback); } + + public function testCanRegisterChannelsWithoutOptions() + { + $broadcaster = new FakeBroadcaster; + + $broadcaster->channel('somechannel', function () {}); + } + + public function testCanRegisterChannelsWithOptions() + { + $broadcaster = new FakeBroadcaster; + + $options = [ 'a' => [ 'b', 'c' ] ]; + $broadcaster->channel('somechannel', function () {}, $options); + + $this->assertEquals( + $options, + $broadcaster->retrieveChannelOptions('somechannel') + ); + } + + public function testRetrieveUserWithoutGuard() + { + $broadcaster = new FakeBroadcaster; + + $broadcaster->channel('somechannel', function () {}); + + $request = m::mock(\Illuminate\Http\Request::class); + $request->shouldReceive('user') + ->once() + ->withNoArgs() + ->andReturn(new DummyUser); + + $this->assertInstanceOf( + DummyUser::class, + $broadcaster->retrieveUser($request, 'somechannel') + ); + } + + public function testRetrieveUserWithOneGuardUsingAStringForSpecifyingGuard() + { + $broadcaster = new FakeBroadcaster; + + $broadcaster->channel('somechannel', function () {}, ['guards' => 'myguard']); + + $request = m::mock(\Illuminate\Http\Request::class); + $request->shouldReceive('user') + ->once() + ->with('myguard') + ->andReturn(new DummyUser); + + $this->assertInstanceOf( + DummyUser::class, + $broadcaster->retrieveUser($request, 'somechannel') + ); + } + + public function testRetrieveUserWithMultipleGuardsAndRespectGuardsOrder() + { + $broadcaster = new FakeBroadcaster; + + $broadcaster->channel('somechannel', function () {}, ['guards' => ['myguard1', 'myguard2']]); + $broadcaster->channel('someotherchannel', function () {}, ['guards' => ['myguard2', 'myguard1']]); + + + $request = m::mock(\Illuminate\Http\Request::class); + $request->shouldReceive('user') + ->once() + ->with('myguard1') + ->andReturn(null); + $request->shouldReceive('user') + ->twice() + ->with('myguard2') + ->andReturn(new DummyUser) + ->ordered('user'); + + $this->assertInstanceOf( + DummyUser::class, + $broadcaster->retrieveUser($request, 'somechannel') + ); + + $this->assertInstanceOf( + DummyUser::class, + $broadcaster->retrieveUser($request, 'someotherchannel') + ); + } + + public function testRetrieveUserDontUseDefaultGuardWhenOneGuardSpecified() + { + $broadcaster = new FakeBroadcaster; + + $broadcaster->channel('somechannel', function () {}, ['guards' => 'myguard']); + + $request = m::mock(\Illuminate\Http\Request::class); + $request->shouldReceive('user') + ->once() + ->with('myguard') + ->andReturn(null); + $request->shouldNotReceive('user') + ->withNoArgs(); + + $broadcaster->retrieveUser($request, 'somechannel'); + } + + public function testRetrieveUserDontUseDefaultGuardWhenMultipleGuardsSpecified() + { + $broadcaster = new FakeBroadcaster; + + $broadcaster->channel('somechannel', function () {}, ['guards' => ['myguard1', 'myguard2']]); + + + $request = m::mock(\Illuminate\Http\Request::class); + $request->shouldReceive('user') + ->once() + ->with('myguard1') + ->andReturn(null); + $request->shouldReceive('user') + ->once() + ->with('myguard2') + ->andReturn(null); + $request->shouldNotReceive('user') + ->withNoArgs(); + + $broadcaster->retrieveUser($request, 'somechannel'); + } } class FakeBroadcaster extends Broadcaster @@ -114,6 +239,16 @@ public function extractAuthParameters($pattern, $channel, $callback) { return parent::extractAuthParameters($pattern, $channel, $callback); } + + public function retrieveChannelOptions($channel) + { + return parent::retrieveChannelOptions($channel); + } + + public function retrieveUser($request, $channel) + { + return parent::retrieveUser($request, $channel); + } } class BroadcasterTestEloquentModelStub extends Model @@ -163,3 +298,8 @@ public function join($user, BroadcasterTestEloquentModelStub $model, $nonModel) // } } + +class DummyUser +{ + +} diff --git a/tests/Broadcasting/PusherBroadcasterTest.php b/tests/Broadcasting/PusherBroadcasterTest.php new file mode 100644 index 000000000000..96f9295c0c99 --- /dev/null +++ b/tests/Broadcasting/PusherBroadcasterTest.php @@ -0,0 +1,253 @@ +pusher = m::mock('Pusher\Pusher'); + $this->broadcaster = m::mock(PusherBroadcaster::class, [$this->pusher])->makePartial(); + } + + /** + * @dataProvider channelsProvider + */ + public function testChannelNameNormalization($requestChannelName, $normalizedName) + { + $this->assertEquals( + $normalizedName, + $this->broadcaster->normalizeChannelName($requestChannelName) + ); + } + + /** + * @dataProvider channelsProvider + */ + public function testIsGuardedChannel($requestChannelName, $_, $guarded) + { + $this->assertEquals( + $guarded, + $this->broadcaster->isGuardedChannel($requestChannelName) + ); + } + + public function testAuthCallValidAuthenticationResponseWithPrivateChannelWhenCallbackReturnTrue() + { + $this->broadcaster->channel('test', function() { + return true; + }); + + $this->broadcaster->shouldReceive('validAuthenticationResponse') + ->once(); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('private-test') + ); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenCallbackReturnFalse() + { + $this->broadcaster->channel('test', function() { + return false; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('private-test') + ); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenRequestUserNotFound() + { + $this->broadcaster->channel('test', function() { + return true; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithoutUserForChannel('private-test') + ); + } + + public function testAuthCallValidAuthenticationResponseWithPresenceChannelWhenCallbackReturnAnArray() + { + $returnData = [1, 2, 3, 4]; + $this->broadcaster->channel('test', function() use ($returnData) { + return $returnData; + }); + + $this->broadcaster->shouldReceive('validAuthenticationResponse') + ->once(); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('presence-test') + ); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenCallbackReturnNull() + { + $this->broadcaster->channel('test', function() { + return; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('presence-test') + ); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenRequestUserNotFound() + { + $this->broadcaster->channel('test', function() { + return [1, 2, 3, 4]; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithoutUserForChannel('presence-test') + ); + } + + public function testValidAuthenticationResponseCallPusherSocketAuthMethodWithPrivateChannel() + { + $request = $this->getMockRequestWithUserForChannel('private-test'); + + $data = [ + 'auth' => 'abcd:efgh' + ]; + + $this->pusher->shouldReceive('socket_auth') + ->once() + ->andReturn(json_encode($data)); + + $this->assertEquals( + $data, + $this->broadcaster->validAuthenticationResponse($request, true) + ); + } + + public function testValidAuthenticationResponseCallPusherPresenceAuthMethodWithPresenceChannel() + { + $request = $this->getMockRequestWithUserForChannel('presence-test'); + + $data = [ + 'auth' => 'abcd:efgh', + 'channel_data' => [ + 'user_id' => 42, + 'user_info' => [1, 2, 3, 4], + ], + ]; + + $this->pusher->shouldReceive('presence_auth') + ->once() + ->andReturn(json_encode($data)); + + $this->assertEquals( + $data, + $this->broadcaster->validAuthenticationResponse($request, true) + ); + } + + public function channelsProvider() + { + $prefixesInfos = [ + ['prefix' => 'private-', 'guarded' => true], + ['prefix' => 'presence-', 'guarded' => true], + ['prefix' => '', 'guarded' => false], + ]; + + $channels = [ + 'test', + 'test-channel', + 'test-private-channel', + 'test-presence-channel', + 'abcd.efgh', + 'abcd.efgh.ijkl', + 'test.{param}', + 'test-{param}', + '{a}.{b}', + '{a}-{b}', + '{a}-{b}.{c}', + ]; + + $tests = []; + foreach ($prefixesInfos as $prefixInfos) { + foreach ($channels as $channel) { + $tests[] = [ + $prefixInfos['prefix'] . $channel, + $channel, + $prefixInfos['guarded'], + ]; + } + } + + $tests[] = ['private-private-test' , 'private-test', true]; + $tests[] = ['private-presence-test' , 'presence-test', true]; + $tests[] = ['presence-private-test' , 'private-test', true]; + $tests[] = ['presence-presence-test' , 'presence-test', true]; + $tests[] = ['public-test' , 'public-test', false]; + + return $tests; + } + + /** + * @param string $channel + * @return \Illuminate\Http\Request + */ + protected function getMockRequestWithUserForChannel($channel) + { + $request = m::mock(\Illuminate\Http\Request::class); + $request->channel_name = $channel; + $request->socket_id = 'abcd.1234'; + + $request->shouldReceive('input') + ->with('callback', false) + ->andReturn(false); + + $user = m::mock('User'); + $user->shouldReceive('getAuthIdentifier') + ->andReturn(42); + + $request->shouldReceive('user') + ->andReturn($user); + + return $request; + } + + /** + * @param string $channel + * @return \Illuminate\Http\Request + */ + protected function getMockRequestWithoutUserForChannel($channel) + { + $request = m::mock(\Illuminate\Http\Request::class); + $request->channel_name = $channel; + + $request->shouldReceive('user') + ->andReturn(null); + + return $request; + } +} diff --git a/tests/Broadcasting/RedisBroadcasterTest.php b/tests/Broadcasting/RedisBroadcasterTest.php new file mode 100644 index 000000000000..daf6c72d225e --- /dev/null +++ b/tests/Broadcasting/RedisBroadcasterTest.php @@ -0,0 +1,241 @@ +broadcaster = m::mock(RedisBroadcaster::class)->makePartial(); + } + + public function tearDown() + { + m::close(); + } + + /** + * @dataProvider channelsProvider + */ + public function testChannelNameNormalization($requestChannelName, $normalizedName) + { + $this->assertEquals( + $normalizedName, + $this->broadcaster->normalizeChannelName($requestChannelName) + ); + } + + /** + * @dataProvider channelsProvider + */ + public function testIsGuardedChannel($requestChannelName, $_, $guarded) + { + $this->assertEquals( + $guarded, + $this->broadcaster->isGuardedChannel($requestChannelName) + ); + } + + public function testAuthCallValidAuthenticationResponseWithPrivateChannelWhenCallbackReturnTrue() + { + $this->broadcaster->channel('test', function() { + return true; + }); + + $this->broadcaster->shouldReceive('validAuthenticationResponse') + ->once(); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('private-test') + ); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenCallbackReturnFalse() + { + $this->broadcaster->channel('test', function() { + return false; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('private-test') + ); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAuthThrowAccessDeniedHttpExceptionWithPrivateChannelWhenRequestUserNotFound() + { + $this->broadcaster->channel('test', function() { + return true; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithoutUserForChannel('private-test') + ); + } + + public function testAuthCallValidAuthenticationResponseWithPresenceChannelWhenCallbackReturnAnArray() + { + $returnData = [1, 2, 3, 4]; + $this->broadcaster->channel('test', function() use ($returnData) { + return $returnData; + }); + + $this->broadcaster->shouldReceive('validAuthenticationResponse') + ->once(); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('presence-test') + ); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenCallbackReturnNull() + { + $this->broadcaster->channel('test', function() { + return; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithUserForChannel('presence-test') + ); + } + + /** + * @expectedException \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + */ + public function testAuthThrowAccessDeniedHttpExceptionWithPresenceChannelWhenRequestUserNotFound() + { + $this->broadcaster->channel('test', function() { + return [1, 2, 3, 4]; + }); + + $this->broadcaster->auth( + $this->getMockRequestWithoutUserForChannel('presence-test') + ); + } + + public function testValidAuthenticationResponseWithPrivateChannel() + { + $request = $this->getMockRequestWithUserForChannel('private-test'); + + $this->assertEquals( + json_encode(true), + $this->broadcaster->validAuthenticationResponse($request, true) + ); + } + + public function testValidAuthenticationResponseWithPresenceChannel() + { + $request = $this->getMockRequestWithUserForChannel('presence-test'); + + $this->assertEquals( + json_encode([ + 'channel_data' => [ + 'user_id' => 42, + 'user_info' => [ + 'a' => 'b', + 'c' => 'd', + ], + ], + ]), + $this->broadcaster->validAuthenticationResponse($request, [ + 'a' => 'b', + 'c' => 'd' + ]) + ); + } + + public function channelsProvider() + { + $prefixesInfos = [ + ['prefix' => 'private-', 'guarded' => true], + ['prefix' => 'presence-', 'guarded' => true], + ['prefix' => '', 'guarded' => false], + ]; + + $channels = [ + 'test', + 'test-channel', + 'test-private-channel', + 'test-presence-channel', + 'abcd.efgh', + 'abcd.efgh.ijkl', + 'test.{param}', + 'test-{param}', + '{a}.{b}', + '{a}-{b}', + '{a}-{b}.{c}', + ]; + + $tests = []; + foreach ($prefixesInfos as $prefixInfos) { + foreach ($channels as $channel) { + $tests[] = [ + $prefixInfos['prefix'] . $channel, + $channel, + $prefixInfos['guarded'], + ]; + } + } + + $tests[] = ['private-private-test' , 'private-test', true]; + $tests[] = ['private-presence-test' , 'presence-test', true]; + $tests[] = ['presence-private-test' , 'private-test', true]; + $tests[] = ['presence-presence-test' , 'presence-test', true]; + $tests[] = ['public-test' , 'public-test', false]; + + return $tests; + } + + /** + * @param string $channel + * @return \Illuminate\Http\Request + */ + protected function getMockRequestWithUserForChannel($channel) + { + $request = m::mock(\Illuminate\Http\Request::class); + $request->channel_name = $channel; + + $user = m::mock('User'); + $user->shouldReceive('getAuthIdentifier') + ->andReturn(42); + + $request->shouldReceive('user') + ->andReturn($user); + + return $request; + } + + /** + * @param string $channel + * @return \Illuminate\Http\Request + */ + protected function getMockRequestWithoutUserForChannel($channel) + { + $request = m::mock(\Illuminate\Http\Request::class); + $request->channel_name = $channel; + + $request->shouldReceive('user') + ->andReturn(null); + + return $request; + } +} From e43370a8ac0033174b9be93f0a5fc993c10d1da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Thu, 26 Jul 2018 03:01:25 +0200 Subject: [PATCH 0156/2459] Fix phpDoc --- src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index 824737ec10de..b98ae1785208 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -41,7 +41,7 @@ abstract class Broadcaster implements BroadcasterContract * * @param string $channel * @param callable|string $callback - * @param array $options + * @param array $options * @return $this */ public function channel($channel, $callback, $options = []) @@ -288,9 +288,10 @@ protected function retrieveChannelOptions($channel) } /** - * Retrieve user by checking in provided guards + * Retrieve request user using optional guards * * @param \Illuminate\Http\Request $request + * @param string $channel * @return mixed */ protected function retrieveUser($request, $channel) From fc682fc9ddabe88ad1585b0469fb6261656b168b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Thu, 26 Jul 2018 03:33:05 +0200 Subject: [PATCH 0157/2459] Add channelNameMatchPattern --- .../Broadcasting/Broadcasters/Broadcaster.php | 16 ++++++++-- tests/Broadcasting/BroadcasterTest.php | 31 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index b98ae1785208..7b7ce411284e 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -64,7 +64,7 @@ public function channel($channel, $callback, $options = []) protected function verifyUserCanAccessChannel($request, $channel) { foreach ($this->channels as $pattern => $callback) { - if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { + if (! $this->channelNameMatchPattern($channel, $pattern)) { continue; } @@ -277,7 +277,7 @@ protected function normalizeChannelHandlerToCallable($callback) protected function retrieveChannelOptions($channel) { foreach ($this->channelsOptions as $pattern => $opts) { - if (! Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel)) { + if (! $this->channelNameMatchPattern($channel, $pattern)) { continue; } @@ -314,4 +314,16 @@ protected function retrieveUser($request, $channel) return null; } + + /** + * Check if channel name from request match a pattern from registered channels + * + * @param string $channel + * @param string $pattern + * @return bool + */ + protected function channelNameMatchPattern($channel, $pattern) + { + return Str::is(preg_replace('/\{(.*?)\}/', '*', $pattern), $channel); + } } diff --git a/tests/Broadcasting/BroadcasterTest.php b/tests/Broadcasting/BroadcasterTest.php index 9f292bbc02d5..4ebee43fc190 100644 --- a/tests/Broadcasting/BroadcasterTest.php +++ b/tests/Broadcasting/BroadcasterTest.php @@ -219,6 +219,32 @@ public function testRetrieveUserDontUseDefaultGuardWhenMultipleGuardsSpecified() $broadcaster->retrieveUser($request, 'somechannel'); } + + /** + * @dataProvider channelNameMatchPatternProvider + */ + public function testChannelNameMatchPattern($channel, $pattern, $shouldMatch) + { + $broadcaster = new FakeBroadcaster; + + $this->assertEquals($shouldMatch, $broadcaster->channelNameMatchPattern($channel, $pattern)); + } + + public function channelNameMatchPatternProvider() { + return [ + ['something', 'something', true], + ['something.23', 'something.{id}', true], + ['something.23.test', 'something.{id}.test', true], + ['something.23.test.42', 'something.{id}.test.{id2}', true], + ['something-23:test-42', 'something-{id}:test-{id2}', true], + ['something..test.42', 'something.{id}.test.{id2}', true], + ['23:string:test', '{id}:string:{text}', true], + ['something.23', 'something', false], + ['something.23.test.42', 'something.test.{id}', false], + ['something-23-test-42', 'something-{id}-test', false], + ['23:test', '{id}:test:abcd', false], + ]; + } } class FakeBroadcaster extends Broadcaster @@ -249,6 +275,11 @@ public function retrieveUser($request, $channel) { return parent::retrieveUser($request, $channel); } + + public function channelNameMatchPattern($channel, $pattern) + { + return parent::channelNameMatchPattern($channel, $pattern); + } } class BroadcasterTestEloquentModelStub extends Model From a4df21f8f866797653cbccd63ec27304a48fa305 Mon Sep 17 00:00:00 2001 From: Nguyen Xuan Quynh Date: Thu, 26 Jul 2018 22:28:48 +0700 Subject: [PATCH 0158/2459] correct segmentProvider in HttpRequestTest (#24971) --- tests/Http/HttpRequestTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index 8f6927546831..564c35edafdd 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -79,9 +79,9 @@ public function segmentProvider() { return [ ['', 1, 'default'], - ['foo/bar//baz', '1', 'foo'], - ['foo/bar//baz', '2', 'bar'], - ['foo/bar//baz', '3', 'baz'], + ['foo/bar//baz', 1, 'foo'], + ['foo/bar//baz', 2, 'bar'], + ['foo/bar//baz', 3, 'baz'], ]; } From e70fd77ec5563385c587037da38af0fd9eb3c169 Mon Sep 17 00:00:00 2001 From: Robin van der Vleuten Date: Thu, 26 Jul 2018 17:34:49 +0200 Subject: [PATCH 0159/2459] Made auth trait response handlers consistent (#24963) --- src/Illuminate/Foundation/Auth/ResetsPasswords.php | 5 +++-- src/Illuminate/Foundation/Auth/SendsPasswordResetEmails.php | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Auth/ResetsPasswords.php b/src/Illuminate/Foundation/Auth/ResetsPasswords.php index d8bea843b143..a8a8a1e9a844 100644 --- a/src/Illuminate/Foundation/Auth/ResetsPasswords.php +++ b/src/Illuminate/Foundation/Auth/ResetsPasswords.php @@ -52,7 +52,7 @@ public function reset(Request $request) // the application's home authenticated view. If there is an error we can // redirect them back to where they came from with their error message. return $response == Password::PASSWORD_RESET - ? $this->sendResetResponse($response) + ? $this->sendResetResponse($request, $response) : $this->sendResetFailedResponse($request, $response); } @@ -116,10 +116,11 @@ protected function resetPassword($user, $password) /** * Get the response for a successful password reset. * + * @param \Illuminate\Http\Request $request * @param string $response * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse */ - protected function sendResetResponse($response) + protected function sendResetResponse(Request $request, $response) { return redirect($this->redirectPath()) ->with('status', trans($response)); diff --git a/src/Illuminate/Foundation/Auth/SendsPasswordResetEmails.php b/src/Illuminate/Foundation/Auth/SendsPasswordResetEmails.php index fd946ca95d1a..02378c15dc60 100644 --- a/src/Illuminate/Foundation/Auth/SendsPasswordResetEmails.php +++ b/src/Illuminate/Foundation/Auth/SendsPasswordResetEmails.php @@ -35,7 +35,7 @@ public function sendResetLinkEmail(Request $request) ); return $response == Password::RESET_LINK_SENT - ? $this->sendResetLinkResponse($response) + ? $this->sendResetLinkResponse($request, $response) : $this->sendResetLinkFailedResponse($request, $response); } @@ -53,10 +53,11 @@ protected function validateEmail(Request $request) /** * Get the response for a successful password reset link. * + * @param \Illuminate\Http\Request $request * @param string $response * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse */ - protected function sendResetLinkResponse($response) + protected function sendResetLinkResponse(Request $request, $response) { return back()->with('status', trans($response)); } From 30ebb1b80521efca6c65b3921bfd725d6c628b6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Thu, 26 Jul 2018 21:11:57 +0200 Subject: [PATCH 0160/2459] Add trait UsePusherChannelsNames --- .../Broadcasters/PusherBroadcaster.php | 29 ++------------- .../Broadcasters/RedisBroadcaster.php | 30 ++-------------- .../Broadcasters/UsePusherChannelsNames.php | 35 +++++++++++++++++++ 3 files changed, 39 insertions(+), 55 deletions(-) create mode 100644 src/Illuminate/Broadcasting/Broadcasters/UsePusherChannelsNames.php diff --git a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php index 784786381e8b..efdbd6eb1d02 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php @@ -10,6 +10,8 @@ class PusherBroadcaster extends Broadcaster { + use UsePusherChannelsNames; + /** * The Pusher SDK instance. * @@ -127,31 +129,4 @@ public function getPusher() { return $this->pusher; } - - /** - * Return true if channel is protected by authentication - * - * @param string $channel - * @return bool - */ - public function isGuardedChannel($channel) - { - return Str::startsWith($channel, ['private-', 'presence-']); - } - - /** - * Remove prefix from channel name - * - * @param string $channel - * @return string - */ - public function normalizeChannelName($channel) - { - if ($this->isGuardedChannel($channel)) { - return Str::startsWith($channel, 'private-') - ? Str::replaceFirst('private-', '', $channel) - : Str::replaceFirst('presence-', '', $channel); - } - return $channel; - } } diff --git a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php index 3efe6196f7d3..8d64a6a8c2d3 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/RedisBroadcaster.php @@ -3,12 +3,13 @@ namespace Illuminate\Broadcasting\Broadcasters; use Illuminate\Support\Arr; -use Illuminate\Support\Str; use Illuminate\Contracts\Redis\Factory as Redis; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class RedisBroadcaster extends Broadcaster { + use UsePusherChannelsNames; + /** * The Redis instance. * @@ -100,31 +101,4 @@ public function broadcast(array $channels, $event, array $payload = []) $connection->publish($channel, $payload); } } - - /** - * Return true if channel is protected by authentication - * - * @param string $channel - * @return bool - */ - public function isGuardedChannel($channel) - { - return Str::startsWith($channel, ['private-', 'presence-']); - } - - /** - * Remove prefix from channel name - * - * @param string $channel - * @return string - */ - public function normalizeChannelName($channel) - { - if ($this->isGuardedChannel($channel)) { - return Str::startsWith($channel, 'private-') - ? Str::replaceFirst('private-', '', $channel) - : Str::replaceFirst('presence-', '', $channel); - } - return $channel; - } } diff --git a/src/Illuminate/Broadcasting/Broadcasters/UsePusherChannelsNames.php b/src/Illuminate/Broadcasting/Broadcasters/UsePusherChannelsNames.php new file mode 100644 index 000000000000..b37c04ef2d58 --- /dev/null +++ b/src/Illuminate/Broadcasting/Broadcasters/UsePusherChannelsNames.php @@ -0,0 +1,35 @@ +isGuardedChannel($channel)) { + return Str::startsWith($channel, 'private-') + ? Str::replaceFirst('private-', '', $channel) + : Str::replaceFirst('presence-', '', $channel); + } + return $channel; + } +} From cdcb9e28205e1bd9104a79335619652772533f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Thu, 26 Jul 2018 21:18:57 +0200 Subject: [PATCH 0161/2459] Add a test class for trait UsePusherChannelsNames --- tests/Broadcasting/PusherBroadcasterTest.php | 64 ---------- tests/Broadcasting/RedisBroadcasterTest.php | 64 ---------- .../UsePusherChannelsNamesTest.php | 109 ++++++++++++++++++ 3 files changed, 109 insertions(+), 128 deletions(-) create mode 100644 tests/Broadcasting/UsePusherChannelsNamesTest.php diff --git a/tests/Broadcasting/PusherBroadcasterTest.php b/tests/Broadcasting/PusherBroadcasterTest.php index 96f9295c0c99..2f3020dee699 100644 --- a/tests/Broadcasting/PusherBroadcasterTest.php +++ b/tests/Broadcasting/PusherBroadcasterTest.php @@ -23,28 +23,6 @@ public function setUp() $this->broadcaster = m::mock(PusherBroadcaster::class, [$this->pusher])->makePartial(); } - /** - * @dataProvider channelsProvider - */ - public function testChannelNameNormalization($requestChannelName, $normalizedName) - { - $this->assertEquals( - $normalizedName, - $this->broadcaster->normalizeChannelName($requestChannelName) - ); - } - - /** - * @dataProvider channelsProvider - */ - public function testIsGuardedChannel($requestChannelName, $_, $guarded) - { - $this->assertEquals( - $guarded, - $this->broadcaster->isGuardedChannel($requestChannelName) - ); - } - public function testAuthCallValidAuthenticationResponseWithPrivateChannelWhenCallbackReturnTrue() { $this->broadcaster->channel('test', function() { @@ -170,48 +148,6 @@ public function testValidAuthenticationResponseCallPusherPresenceAuthMethodWithP ); } - public function channelsProvider() - { - $prefixesInfos = [ - ['prefix' => 'private-', 'guarded' => true], - ['prefix' => 'presence-', 'guarded' => true], - ['prefix' => '', 'guarded' => false], - ]; - - $channels = [ - 'test', - 'test-channel', - 'test-private-channel', - 'test-presence-channel', - 'abcd.efgh', - 'abcd.efgh.ijkl', - 'test.{param}', - 'test-{param}', - '{a}.{b}', - '{a}-{b}', - '{a}-{b}.{c}', - ]; - - $tests = []; - foreach ($prefixesInfos as $prefixInfos) { - foreach ($channels as $channel) { - $tests[] = [ - $prefixInfos['prefix'] . $channel, - $channel, - $prefixInfos['guarded'], - ]; - } - } - - $tests[] = ['private-private-test' , 'private-test', true]; - $tests[] = ['private-presence-test' , 'presence-test', true]; - $tests[] = ['presence-private-test' , 'private-test', true]; - $tests[] = ['presence-presence-test' , 'presence-test', true]; - $tests[] = ['public-test' , 'public-test', false]; - - return $tests; - } - /** * @param string $channel * @return \Illuminate\Http\Request diff --git a/tests/Broadcasting/RedisBroadcasterTest.php b/tests/Broadcasting/RedisBroadcasterTest.php index daf6c72d225e..80c1e79107d9 100644 --- a/tests/Broadcasting/RedisBroadcasterTest.php +++ b/tests/Broadcasting/RedisBroadcasterTest.php @@ -25,28 +25,6 @@ public function tearDown() m::close(); } - /** - * @dataProvider channelsProvider - */ - public function testChannelNameNormalization($requestChannelName, $normalizedName) - { - $this->assertEquals( - $normalizedName, - $this->broadcaster->normalizeChannelName($requestChannelName) - ); - } - - /** - * @dataProvider channelsProvider - */ - public function testIsGuardedChannel($requestChannelName, $_, $guarded) - { - $this->assertEquals( - $guarded, - $this->broadcaster->isGuardedChannel($requestChannelName) - ); - } - public function testAuthCallValidAuthenticationResponseWithPrivateChannelWhenCallbackReturnTrue() { $this->broadcaster->channel('test', function() { @@ -163,48 +141,6 @@ public function testValidAuthenticationResponseWithPresenceChannel() ); } - public function channelsProvider() - { - $prefixesInfos = [ - ['prefix' => 'private-', 'guarded' => true], - ['prefix' => 'presence-', 'guarded' => true], - ['prefix' => '', 'guarded' => false], - ]; - - $channels = [ - 'test', - 'test-channel', - 'test-private-channel', - 'test-presence-channel', - 'abcd.efgh', - 'abcd.efgh.ijkl', - 'test.{param}', - 'test-{param}', - '{a}.{b}', - '{a}-{b}', - '{a}-{b}.{c}', - ]; - - $tests = []; - foreach ($prefixesInfos as $prefixInfos) { - foreach ($channels as $channel) { - $tests[] = [ - $prefixInfos['prefix'] . $channel, - $channel, - $prefixInfos['guarded'], - ]; - } - } - - $tests[] = ['private-private-test' , 'private-test', true]; - $tests[] = ['private-presence-test' , 'presence-test', true]; - $tests[] = ['presence-private-test' , 'private-test', true]; - $tests[] = ['presence-presence-test' , 'presence-test', true]; - $tests[] = ['public-test' , 'public-test', false]; - - return $tests; - } - /** * @param string $channel * @return \Illuminate\Http\Request diff --git a/tests/Broadcasting/UsePusherChannelsNamesTest.php b/tests/Broadcasting/UsePusherChannelsNamesTest.php new file mode 100644 index 000000000000..777e99c8d034 --- /dev/null +++ b/tests/Broadcasting/UsePusherChannelsNamesTest.php @@ -0,0 +1,109 @@ +broadcaster = new FakeBroadcasterUsingPusherChannelsNames(); + } + + public function tearDown() + { + m::close(); + } + + /** + * @dataProvider channelsProvider + */ + public function testChannelNameNormalization($requestChannelName, $normalizedName) + { + $this->assertEquals( + $normalizedName, + $this->broadcaster->normalizeChannelName($requestChannelName) + ); + } + + /** + * @dataProvider channelsProvider + */ + public function testIsGuardedChannel($requestChannelName, $_, $guarded) + { + $this->assertEquals( + $guarded, + $this->broadcaster->isGuardedChannel($requestChannelName) + ); + } + + public function channelsProvider() + { + $prefixesInfos = [ + ['prefix' => 'private-', 'guarded' => true], + ['prefix' => 'presence-', 'guarded' => true], + ['prefix' => '', 'guarded' => false], + ]; + + $channels = [ + 'test', + 'test-channel', + 'test-private-channel', + 'test-presence-channel', + 'abcd.efgh', + 'abcd.efgh.ijkl', + 'test.{param}', + 'test-{param}', + '{a}.{b}', + '{a}-{b}', + '{a}-{b}.{c}', + ]; + + $tests = []; + foreach ($prefixesInfos as $prefixInfos) { + foreach ($channels as $channel) { + $tests[] = [ + $prefixInfos['prefix'] . $channel, + $channel, + $prefixInfos['guarded'], + ]; + } + } + + $tests[] = ['private-private-test' , 'private-test', true]; + $tests[] = ['private-presence-test' , 'presence-test', true]; + $tests[] = ['presence-private-test' , 'private-test', true]; + $tests[] = ['presence-presence-test' , 'presence-test', true]; + $tests[] = ['public-test' , 'public-test', false]; + + return $tests; + } +} + +class FakeBroadcasterUsingPusherChannelsNames extends Broadcaster +{ + use UsePusherChannelsNames; + + public function auth($request) + { + } + + public function validAuthenticationResponse($request, $result) + { + } + + public function broadcast(array $channels, $event, array $payload = []) + { + } +} From 304de5fc046c16eb08ab1415cc7755981ac1f3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Thu, 26 Jul 2018 21:28:40 +0200 Subject: [PATCH 0162/2459] Add tests for method retrieveChannelsOptions --- tests/Broadcasting/BroadcasterTest.php | 48 ++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/Broadcasting/BroadcasterTest.php b/tests/Broadcasting/BroadcasterTest.php index 4ebee43fc190..6e3759cd4fdf 100644 --- a/tests/Broadcasting/BroadcasterTest.php +++ b/tests/Broadcasting/BroadcasterTest.php @@ -108,6 +108,14 @@ public function testCanRegisterChannelsWithOptions() $options = [ 'a' => [ 'b', 'c' ] ]; $broadcaster->channel('somechannel', function () {}, $options); + } + + public function testCanRetrieveChannelsOptions() + { + $broadcaster = new FakeBroadcaster; + + $options = [ 'a' => [ 'b', 'c' ] ]; + $broadcaster->channel('somechannel', function () {}, $options); $this->assertEquals( $options, @@ -115,6 +123,46 @@ public function testCanRegisterChannelsWithOptions() ); } + public function testCanRetrieveChannelsOptionsUsingAChannelNameContainingArgs() + { + $broadcaster = new FakeBroadcaster; + + $options = [ 'a' => [ 'b', 'c' ] ]; + $broadcaster->channel('somechannel.{id}.test.{text}', function () {}, $options); + + $this->assertEquals( + $options, + $broadcaster->retrieveChannelOptions('somechannel.23.test.mytext') + ); + } + + public function testCanRetrieveChannelsOptionsWhenMultipleChannelsAreRegistered() + { + $broadcaster = new FakeBroadcaster; + + $options = [ 'a' => [ 'b', 'c' ] ]; + $broadcaster->channel('somechannel', function () {}); + $broadcaster->channel('someotherchannel', function () {}, $options); + + $this->assertEquals( + $options, + $broadcaster->retrieveChannelOptions('someotherchannel') + ); + } + + public function testDontRetrieveChannelsOptionsWhenChannelDoesntExists() + { + $broadcaster = new FakeBroadcaster; + + $options = [ 'a' => [ 'b', 'c' ] ]; + $broadcaster->channel('somechannel', function () {}, $options); + + $this->assertEquals( + [], + $broadcaster->retrieveChannelOptions('someotherchannel') + ); + } + public function testRetrieveUserWithoutGuard() { $broadcaster = new FakeBroadcaster; From fa9359c8fed0211ddff970ee99a61e75bcd4fca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Lefe=CC=80vre?= Date: Thu, 26 Jul 2018 21:33:20 +0200 Subject: [PATCH 0163/2459] Add a setup method in BroadcasterTest --- tests/Broadcasting/BroadcasterTest.php | 114 ++++++++++--------------- 1 file changed, 46 insertions(+), 68 deletions(-) diff --git a/tests/Broadcasting/BroadcasterTest.php b/tests/Broadcasting/BroadcasterTest.php index 6e3759cd4fdf..d1140355f76c 100644 --- a/tests/Broadcasting/BroadcasterTest.php +++ b/tests/Broadcasting/BroadcasterTest.php @@ -11,6 +11,18 @@ class BroadcasterTest extends TestCase { + /** + * @var \Illuminate\Tests\Broadcasting\FakeBroadcaster + */ + public $broadcaster; + + public function setUp() + { + parent::setUp(); + + $this->broadcaster = new FakeBroadcaster; + } + public function tearDown() { m::close(); @@ -18,26 +30,24 @@ public function tearDown() public function testExtractingParametersWhileCheckingForUserAccess() { - $broadcaster = new FakeBroadcaster; - $callback = function ($user, BroadcasterTestEloquentModelStub $model, $nonModel) { }; - $parameters = $broadcaster->extractAuthParameters('asd.{model}.{nonModel}', 'asd.1.something', $callback); + $parameters = $this->broadcaster->extractAuthParameters('asd.{model}.{nonModel}', 'asd.1.something', $callback); $this->assertEquals(['model.1.instance', 'something'], $parameters); $callback = function ($user, BroadcasterTestEloquentModelStub $model, BroadcasterTestEloquentModelStub $model2, $something) { }; - $parameters = $broadcaster->extractAuthParameters('asd.{model}.{model2}.{nonModel}', 'asd.1.uid.something', $callback); + $parameters = $this->broadcaster->extractAuthParameters('asd.{model}.{model2}.{nonModel}', 'asd.1.uid.something', $callback); $this->assertEquals(['model.1.instance', 'model.uid.instance', 'something'], $parameters); $callback = function ($user) { }; - $parameters = $broadcaster->extractAuthParameters('asd', 'asd', $callback); + $parameters = $this->broadcaster->extractAuthParameters('asd', 'asd', $callback); $this->assertEquals([], $parameters); $callback = function ($user, $something) { }; - $parameters = $broadcaster->extractAuthParameters('asd', 'asd', $callback); + $parameters = $this->broadcaster->extractAuthParameters('asd', 'asd', $callback); $this->assertEquals([], $parameters); /* @@ -52,16 +62,14 @@ public function testExtractingParametersWhileCheckingForUserAccess() $container->instance(BindingRegistrar::class, $binder); $callback = function ($user, $model) { }; - $parameters = $broadcaster->extractAuthParameters('something.{model}', 'something.1', $callback); + $parameters = $this->broadcaster->extractAuthParameters('something.{model}', 'something.1', $callback); $this->assertEquals(['bound'], $parameters); Container::setInstance(new Container); } public function testCanUseChannelClasses() { - $broadcaster = new FakeBroadcaster; - - $parameters = $broadcaster->extractAuthParameters('asd.{model}.{nonModel}', 'asd.1.something', DummyBroadcastingChannel::class); + $parameters = $this->broadcaster->extractAuthParameters('asd.{model}.{nonModel}', 'asd.1.something', DummyBroadcastingChannel::class); $this->assertEquals(['model.1.instance', 'something'], $parameters); } @@ -70,18 +78,14 @@ public function testCanUseChannelClasses() */ public function testUnknownChannelAuthHandlerTypeThrowsException() { - $broadcaster = new FakeBroadcaster; - - $broadcaster->extractAuthParameters('asd.{model}.{nonModel}', 'asd.1.something', 123); + $this->broadcaster->extractAuthParameters('asd.{model}.{nonModel}', 'asd.1.something', 123); } public function testCanRegisterChannelsAsClasses() { - $broadcaster = new FakeBroadcaster; - - $broadcaster->channel('something', function () { + $this->broadcaster->channel('something', function () { }); - $broadcaster->channel('somethingelse', DummyBroadcastingChannel::class); + $this->broadcaster->channel('somethingelse', DummyBroadcastingChannel::class); } /** @@ -89,85 +93,70 @@ public function testCanRegisterChannelsAsClasses() */ public function testNotFoundThrowsHttpException() { - $broadcaster = new FakeBroadcaster; $callback = function ($user, BroadcasterTestEloquentModelNotFoundStub $model) { }; - $broadcaster->extractAuthParameters('asd.{model}', 'asd.1', $callback); + $this->broadcaster->extractAuthParameters('asd.{model}', 'asd.1', $callback); } public function testCanRegisterChannelsWithoutOptions() { - $broadcaster = new FakeBroadcaster; - - $broadcaster->channel('somechannel', function () {}); + $this->broadcaster->channel('somechannel', function () {}); } public function testCanRegisterChannelsWithOptions() { - $broadcaster = new FakeBroadcaster; - $options = [ 'a' => [ 'b', 'c' ] ]; - $broadcaster->channel('somechannel', function () {}, $options); + $this->broadcaster->channel('somechannel', function () {}, $options); } public function testCanRetrieveChannelsOptions() { - $broadcaster = new FakeBroadcaster; - $options = [ 'a' => [ 'b', 'c' ] ]; - $broadcaster->channel('somechannel', function () {}, $options); + $this->broadcaster->channel('somechannel', function () {}, $options); $this->assertEquals( $options, - $broadcaster->retrieveChannelOptions('somechannel') + $this->broadcaster->retrieveChannelOptions('somechannel') ); } public function testCanRetrieveChannelsOptionsUsingAChannelNameContainingArgs() { - $broadcaster = new FakeBroadcaster; - $options = [ 'a' => [ 'b', 'c' ] ]; - $broadcaster->channel('somechannel.{id}.test.{text}', function () {}, $options); + $this->broadcaster->channel('somechannel.{id}.test.{text}', function () {}, $options); $this->assertEquals( $options, - $broadcaster->retrieveChannelOptions('somechannel.23.test.mytext') + $this->broadcaster->retrieveChannelOptions('somechannel.23.test.mytext') ); } public function testCanRetrieveChannelsOptionsWhenMultipleChannelsAreRegistered() { - $broadcaster = new FakeBroadcaster; - $options = [ 'a' => [ 'b', 'c' ] ]; - $broadcaster->channel('somechannel', function () {}); - $broadcaster->channel('someotherchannel', function () {}, $options); + $this->broadcaster->channel('somechannel', function () {}); + $this->broadcaster->channel('someotherchannel', function () {}, $options); $this->assertEquals( $options, - $broadcaster->retrieveChannelOptions('someotherchannel') + $this->broadcaster->retrieveChannelOptions('someotherchannel') ); } public function testDontRetrieveChannelsOptionsWhenChannelDoesntExists() { - $broadcaster = new FakeBroadcaster; - $options = [ 'a' => [ 'b', 'c' ] ]; - $broadcaster->channel('somechannel', function () {}, $options); + $this->broadcaster->channel('somechannel', function () {}, $options); $this->assertEquals( [], - $broadcaster->retrieveChannelOptions('someotherchannel') + $this->broadcaster->retrieveChannelOptions('someotherchannel') ); } public function testRetrieveUserWithoutGuard() { - $broadcaster = new FakeBroadcaster; - - $broadcaster->channel('somechannel', function () {}); + $this->broadcaster->channel('somechannel', function () {}); $request = m::mock(\Illuminate\Http\Request::class); $request->shouldReceive('user') @@ -177,15 +166,13 @@ public function testRetrieveUserWithoutGuard() $this->assertInstanceOf( DummyUser::class, - $broadcaster->retrieveUser($request, 'somechannel') + $this->broadcaster->retrieveUser($request, 'somechannel') ); } public function testRetrieveUserWithOneGuardUsingAStringForSpecifyingGuard() { - $broadcaster = new FakeBroadcaster; - - $broadcaster->channel('somechannel', function () {}, ['guards' => 'myguard']); + $this->broadcaster->channel('somechannel', function () {}, ['guards' => 'myguard']); $request = m::mock(\Illuminate\Http\Request::class); $request->shouldReceive('user') @@ -195,16 +182,14 @@ public function testRetrieveUserWithOneGuardUsingAStringForSpecifyingGuard() $this->assertInstanceOf( DummyUser::class, - $broadcaster->retrieveUser($request, 'somechannel') + $this->broadcaster->retrieveUser($request, 'somechannel') ); } public function testRetrieveUserWithMultipleGuardsAndRespectGuardsOrder() { - $broadcaster = new FakeBroadcaster; - - $broadcaster->channel('somechannel', function () {}, ['guards' => ['myguard1', 'myguard2']]); - $broadcaster->channel('someotherchannel', function () {}, ['guards' => ['myguard2', 'myguard1']]); + $this->broadcaster->channel('somechannel', function () {}, ['guards' => ['myguard1', 'myguard2']]); + $this->broadcaster->channel('someotherchannel', function () {}, ['guards' => ['myguard2', 'myguard1']]); $request = m::mock(\Illuminate\Http\Request::class); @@ -220,20 +205,18 @@ public function testRetrieveUserWithMultipleGuardsAndRespectGuardsOrder() $this->assertInstanceOf( DummyUser::class, - $broadcaster->retrieveUser($request, 'somechannel') + $this->broadcaster->retrieveUser($request, 'somechannel') ); $this->assertInstanceOf( DummyUser::class, - $broadcaster->retrieveUser($request, 'someotherchannel') + $this->broadcaster->retrieveUser($request, 'someotherchannel') ); } public function testRetrieveUserDontUseDefaultGuardWhenOneGuardSpecified() { - $broadcaster = new FakeBroadcaster; - - $broadcaster->channel('somechannel', function () {}, ['guards' => 'myguard']); + $this->broadcaster->channel('somechannel', function () {}, ['guards' => 'myguard']); $request = m::mock(\Illuminate\Http\Request::class); $request->shouldReceive('user') @@ -243,15 +226,12 @@ public function testRetrieveUserDontUseDefaultGuardWhenOneGuardSpecified() $request->shouldNotReceive('user') ->withNoArgs(); - $broadcaster->retrieveUser($request, 'somechannel'); + $this->broadcaster->retrieveUser($request, 'somechannel'); } public function testRetrieveUserDontUseDefaultGuardWhenMultipleGuardsSpecified() { - $broadcaster = new FakeBroadcaster; - - $broadcaster->channel('somechannel', function () {}, ['guards' => ['myguard1', 'myguard2']]); - + $this->broadcaster->channel('somechannel', function () {}, ['guards' => ['myguard1', 'myguard2']]); $request = m::mock(\Illuminate\Http\Request::class); $request->shouldReceive('user') @@ -265,7 +245,7 @@ public function testRetrieveUserDontUseDefaultGuardWhenMultipleGuardsSpecified() $request->shouldNotReceive('user') ->withNoArgs(); - $broadcaster->retrieveUser($request, 'somechannel'); + $this->broadcaster->retrieveUser($request, 'somechannel'); } /** @@ -273,9 +253,7 @@ public function testRetrieveUserDontUseDefaultGuardWhenMultipleGuardsSpecified() */ public function testChannelNameMatchPattern($channel, $pattern, $shouldMatch) { - $broadcaster = new FakeBroadcaster; - - $this->assertEquals($shouldMatch, $broadcaster->channelNameMatchPattern($channel, $pattern)); + $this->assertEquals($shouldMatch, $this->broadcaster->channelNameMatchPattern($channel, $pattern)); } public function channelNameMatchPatternProvider() { From a5d690b12509bc1146c6980b6b9d88b75d7e75ad Mon Sep 17 00:00:00 2001 From: Matt McDonald Date: Sat, 28 Jul 2018 10:55:35 +0100 Subject: [PATCH 0164/2459] Allow setting full Mailgun API URL --- src/Illuminate/Mail/Transport/MailgunTransport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Mail/Transport/MailgunTransport.php b/src/Illuminate/Mail/Transport/MailgunTransport.php index bac829327e7f..2cc182be700e 100644 --- a/src/Illuminate/Mail/Transport/MailgunTransport.php +++ b/src/Illuminate/Mail/Transport/MailgunTransport.php @@ -161,7 +161,7 @@ public function getDomain() */ public function setDomain($domain) { - $this->url = 'https://api.mailgun.net/v3/'.$domain.'/messages.mime'; + $this->url = $domain.'/messages.mime'; return $this->domain = $domain; } From 8544966587e77838f542f7ab0c405371c996b7b0 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 28 Jul 2018 10:17:11 -0500 Subject: [PATCH 0165/2459] make non breaking --- src/Illuminate/Mail/Transport/MailgunTransport.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Mail/Transport/MailgunTransport.php b/src/Illuminate/Mail/Transport/MailgunTransport.php index 2cc182be700e..a27086766a8d 100644 --- a/src/Illuminate/Mail/Transport/MailgunTransport.php +++ b/src/Illuminate/Mail/Transport/MailgunTransport.php @@ -2,6 +2,7 @@ namespace Illuminate\Mail\Transport; +use Illuminate\Support\Str; use Swift_Mime_SimpleMessage; use GuzzleHttp\ClientInterface; @@ -161,7 +162,11 @@ public function getDomain() */ public function setDomain($domain) { - $this->url = $domain.'/messages.mime'; + $url = ! Str::startsWith($domain, ['http://', 'https://']) + ? 'https://api.mailgun.net/v3/'.$domain + : $domain; + + $this->url = $url.'/messages.mime'; return $this->domain = $domain; } From 51c6c8604fb1c0f5a13585cf991a872bf2f242bb Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Sun, 29 Jul 2018 17:20:12 +0200 Subject: [PATCH 0166/2459] Use proper assertions. (#25004) --- tests/Filesystem/FilesystemAdapterTest.php | 2 +- .../Database/EloquentCollectionLoadMissingTest.php | 4 ++-- tests/Integration/Routing/UrlSigningTest.php | 10 +++++----- tests/Mail/MailableQueuedTest.php | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/Filesystem/FilesystemAdapterTest.php b/tests/Filesystem/FilesystemAdapterTest.php index c837ad5a3e6d..91d6b63bb2ad 100644 --- a/tests/Filesystem/FilesystemAdapterTest.php +++ b/tests/Filesystem/FilesystemAdapterTest.php @@ -107,7 +107,7 @@ public function testDelete() file_put_contents($this->tempDir.'/file.txt', 'Hello World'); $filesystemAdapter = new FilesystemAdapter($this->filesystem); $this->assertTrue($filesystemAdapter->delete('file.txt')); - $this->assertFalse(file_exists($this->tempDir.'/file.txt')); + $this->assertFileNotExists($this->tempDir.'/file.txt'); } public function testDeleteReturnsFalseWhenFileNotFound() diff --git a/tests/Integration/Database/EloquentCollectionLoadMissingTest.php b/tests/Integration/Database/EloquentCollectionLoadMissingTest.php index b04d832bd01b..1989a4eac513 100644 --- a/tests/Integration/Database/EloquentCollectionLoadMissingTest.php +++ b/tests/Integration/Database/EloquentCollectionLoadMissingTest.php @@ -57,7 +57,7 @@ public function testLoadMissing() $this->assertCount(2, \DB::getQueryLog()); $this->assertTrue($posts[0]->comments[0]->relationLoaded('parent')); $this->assertTrue($posts[0]->comments[1]->parent->relationLoaded('revisions')); - $this->assertFalse(array_key_exists('id', $posts[0]->comments[1]->parent->revisions[0]->getAttributes())); + $this->assertArrayNotHasKey('id', $posts[0]->comments[1]->parent->revisions[0]->getAttributes()); } public function testLoadMissingWithClosure() @@ -72,7 +72,7 @@ public function testLoadMissingWithClosure() $this->assertCount(1, \DB::getQueryLog()); $this->assertTrue($posts[0]->comments[0]->relationLoaded('parent')); - $this->assertFalse(array_key_exists('post_id', $posts[0]->comments[1]->parent->getAttributes())); + $this->assertArrayNotHasKey('post_id', $posts[0]->comments[1]->parent->getAttributes()); } } diff --git a/tests/Integration/Routing/UrlSigningTest.php b/tests/Integration/Routing/UrlSigningTest.php index d2e099aabc2d..7a04eed2edc7 100644 --- a/tests/Integration/Routing/UrlSigningTest.php +++ b/tests/Integration/Routing/UrlSigningTest.php @@ -21,7 +21,7 @@ public function test_signing_url() return $request->hasValidSignature() ? 'valid' : 'invalid'; })->name('foo'); - $this->assertTrue(is_string($url = URL::signedRoute('foo', ['id' => 1]))); + $this->assertInternalType('string', $url = URL::signedRoute('foo', ['id' => 1])); $this->assertEquals('valid', $this->get($url)->original); } @@ -32,7 +32,7 @@ public function test_temporary_signed_urls() })->name('foo'); Carbon::setTestNow(Carbon::create(2018, 1, 1)); - $this->assertTrue(is_string($url = URL::temporarySignedRoute('foo', now()->addMinutes(5), ['id' => 1]))); + $this->assertInternalType('string', $url = URL::temporarySignedRoute('foo', now()->addMinutes(5), ['id' => 1])); $this->assertEquals('valid', $this->get($url)->original); Carbon::setTestNow(Carbon::create(2018, 1, 1)->addMinutes(10)); @@ -55,7 +55,7 @@ public function test_signed_middleware() })->name('foo')->middleware(ValidateSignature::class); Carbon::setTestNow(Carbon::create(2018, 1, 1)); - $this->assertTrue(is_string($url = URL::temporarySignedRoute('foo', now()->addMinutes(5), ['id' => 1]))); + $this->assertInternalType('string', $url = URL::temporarySignedRoute('foo', now()->addMinutes(5), ['id' => 1])); $this->assertEquals('valid', $this->get($url)->original); } @@ -66,7 +66,7 @@ public function test_signed_middleware_with_invalid_url() })->name('foo')->middleware(ValidateSignature::class); Carbon::setTestNow(Carbon::create(2018, 1, 1)); - $this->assertTrue(is_string($url = URL::temporarySignedRoute('foo', now()->addMinutes(5), ['id' => 1]))); + $this->assertInternalType('string', $url = URL::temporarySignedRoute('foo', now()->addMinutes(5), ['id' => 1])); Carbon::setTestNow(Carbon::create(2018, 1, 1)->addMinutes(10)); $response = $this->get($url); @@ -82,7 +82,7 @@ public function test_signed_middleware_with_routable_parameter() return $request->hasValidSignature() ? $routable : 'invalid'; })->name('foo'); - $this->assertTrue(is_string($url = URL::signedRoute('foo', $model))); + $this->assertInternalType('string', $url = URL::signedRoute('foo', $model)); $this->assertEquals('routable', $this->get($url)->original); } } diff --git a/tests/Mail/MailableQueuedTest.php b/tests/Mail/MailableQueuedTest.php index 19198f2f3aae..02ddb31af80a 100644 --- a/tests/Mail/MailableQueuedTest.php +++ b/tests/Mail/MailableQueuedTest.php @@ -46,7 +46,7 @@ public function testQueuedMailableWithAttachmentSent() $mailable = new MailableQueableStub(); $attachmentOption = ['mime' => 'image/jpeg', 'as' => 'bar.jpg']; $mailable->attach('foo.jpg', $attachmentOption); - $this->assertTrue(is_array($mailable->attachments)); + $this->assertInternalType('array', $mailable->attachments); $this->assertCount(1, $mailable->attachments); $this->assertEquals($mailable->attachments[0]['options'], $attachmentOption); $queueFake->assertNothingPushed(); @@ -77,7 +77,7 @@ public function testQueuedMailableWithAttachmentFromDiskSent() $mailable->attachFromStorage('/', 'foo.jpg', $attachmentOption); - $this->assertTrue(is_array($mailable->diskAttachments)); + $this->assertInternalType('array', $mailable->diskAttachments); $this->assertCount(1, $mailable->diskAttachments); $this->assertEquals($mailable->diskAttachments[0]['options'], $attachmentOption); From 54beb9532f1a345523f40f4dc2b29442e4c3d12b Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Mon, 30 Jul 2018 01:28:12 +0200 Subject: [PATCH 0167/2459] Assertions (#25008) --- tests/Http/HttpRequestTest.php | 4 ++-- tests/Integration/Queue/JobChainingTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Http/HttpRequestTest.php b/tests/Http/HttpRequestTest.php index 564c35edafdd..19eb2d3ac370 100644 --- a/tests/Http/HttpRequestTest.php +++ b/tests/Http/HttpRequestTest.php @@ -371,12 +371,12 @@ public function testArrayAccess() $this->assertNull($request['non-existant']); $this->assertTrue(isset($request['name'])); - $this->assertEquals(null, $request['name']); + $this->assertNull($request['name']); $this->assertNotEquals('Taylor', $request['name']); $this->assertTrue(isset($request['foo.bar'])); - $this->assertEquals(null, $request['foo.bar']); + $this->assertNull($request['foo.bar']); $this->assertTrue(isset($request['foo.baz'])); $this->assertEquals('', $request['foo.baz']); diff --git a/tests/Integration/Queue/JobChainingTest.php b/tests/Integration/Queue/JobChainingTest.php index 4d2c369e061d..b8b034dec9ca 100644 --- a/tests/Integration/Queue/JobChainingTest.php +++ b/tests/Integration/Queue/JobChainingTest.php @@ -174,8 +174,8 @@ public function test_chain_jobs_use_default_config() $this->assertEquals('another_queue', JobChainingTestSecondJob::$usedQueue); $this->assertEquals('sync2', JobChainingTestSecondJob::$usedConnection); - $this->assertEquals(null, JobChainingTestThirdJob::$usedQueue); - $this->assertEquals(null, JobChainingTestThirdJob::$usedConnection); + $this->assertNull(JobChainingTestThirdJob::$usedQueue); + $this->assertNull(JobChainingTestThirdJob::$usedConnection); } } From 252080689239aad063e48f4b70559f20b081b96d Mon Sep 17 00:00:00 2001 From: Dylan Lamers <36036362+Dylan-DutchAndBold@users.noreply.github.com> Date: Mon, 30 Jul 2018 12:40:18 +0200 Subject: [PATCH 0168/2459] Sync changes before firing updated event 1. Logic: Since the updated events suggests the model is now saved (which it is). We should be using the `->wasChanged` function instead of the `->isDirty` functions within this function. 2. Unwanted behaviour: In my case I now check if a value is dirty and then save another. But it will create an infinite loop when you save the model, because the dirty values are still there when you update again. Instead of just that second new value. --- src/Illuminate/Database/Eloquent/Model.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 85a698158aef..138bc96892a1 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -691,10 +691,10 @@ protected function performUpdate(Builder $query) if (count($dirty) > 0) { $this->setKeysForSaveQuery($query)->update($dirty); - - $this->fireModelEvent('updated', false); - + $this->syncChanges(); + + $this->fireModelEvent('updated', false); } return true; From 896212e97e1738bcc153627e9151177b4c3ffdcc Mon Sep 17 00:00:00 2001 From: Dylan Lamers <36036362+Dylan-DutchAndBold@users.noreply.github.com> Date: Mon, 30 Jul 2018 12:47:22 +0200 Subject: [PATCH 0169/2459] Removed blank lines for StyleCI approval --- src/Illuminate/Database/Eloquent/Model.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 138bc96892a1..90eb41c8ffe5 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -691,9 +691,7 @@ protected function performUpdate(Builder $query) if (count($dirty) > 0) { $this->setKeysForSaveQuery($query)->update($dirty); - $this->syncChanges(); - $this->fireModelEvent('updated', false); } From 819dbe33b899e174ff70192479f1beaa86ab6707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kr=C3=BCss?= Date: Mon, 30 Jul 2018 08:37:36 -0500 Subject: [PATCH 0170/2459] add API endpoint to MailgunTransport (#25010) --- .../Mail/Transport/MailgunTransport.php | 19 +++++++++---------- src/Illuminate/Mail/TransportManager.php | 4 +++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Mail/Transport/MailgunTransport.php b/src/Illuminate/Mail/Transport/MailgunTransport.php index a27086766a8d..946ce1066bf2 100644 --- a/src/Illuminate/Mail/Transport/MailgunTransport.php +++ b/src/Illuminate/Mail/Transport/MailgunTransport.php @@ -23,7 +23,7 @@ class MailgunTransport extends Transport protected $key; /** - * The Mailgun domain. + * The Mailgun email domain. * * @var string */ @@ -34,7 +34,7 @@ class MailgunTransport extends Transport * * @var string */ - protected $url; + protected $endpoint; /** * Create a new Mailgun transport instance. @@ -44,10 +44,12 @@ class MailgunTransport extends Transport * @param string $domain * @return void */ - public function __construct(ClientInterface $client, $key, $domain) + public function __construct(ClientInterface $client, $key, $domain, $endpoint = null) { $this->key = $key; $this->client = $client; + $this->endpoint = $endpoint ?? 'api.mailgun.net'; + $this->setDomain($domain); } @@ -62,7 +64,10 @@ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = nul $message->setBcc([]); - $this->client->post($this->url, $this->payload($message, $to)); + $this->client->post( + "https://{$this->endpoint}/v3/{$this->domain}/messages.mime", + $this->payload($message, $to) + ); $this->sendPerformed($message); @@ -162,12 +167,6 @@ public function getDomain() */ public function setDomain($domain) { - $url = ! Str::startsWith($domain, ['http://', 'https://']) - ? 'https://api.mailgun.net/v3/'.$domain - : $domain; - - $this->url = $url.'/messages.mime'; - return $this->domain = $domain; } } diff --git a/src/Illuminate/Mail/TransportManager.php b/src/Illuminate/Mail/TransportManager.php index 532264a42a72..bab48943d2db 100644 --- a/src/Illuminate/Mail/TransportManager.php +++ b/src/Illuminate/Mail/TransportManager.php @@ -118,7 +118,9 @@ protected function createMailgunDriver() return new MailgunTransport( $this->guzzle($config), - $config['secret'], $config['domain'] + $config['secret'], + $config['domain'], + $config['endpoint'] ?? null ); } From dc767d2d7cecd621d4c12b9eac901c17560cecd0 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 30 Jul 2018 08:49:43 -0500 Subject: [PATCH 0171/2459] Apply fixes from StyleCI (#25017) --- src/Illuminate/Mail/Transport/MailgunTransport.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Mail/Transport/MailgunTransport.php b/src/Illuminate/Mail/Transport/MailgunTransport.php index 946ce1066bf2..599b4ef6ddea 100644 --- a/src/Illuminate/Mail/Transport/MailgunTransport.php +++ b/src/Illuminate/Mail/Transport/MailgunTransport.php @@ -2,7 +2,6 @@ namespace Illuminate\Mail\Transport; -use Illuminate\Support\Str; use Swift_Mime_SimpleMessage; use GuzzleHttp\ClientInterface; From 83fdcd2edfb545090d00fcd0cd6397ac6ef5dee3 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 30 Jul 2018 08:54:29 -0500 Subject: [PATCH 0172/2459] formatting --- .../Eloquent/Concerns/HasAttributes.php | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 454021a8df6c..0d217b760f0b 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -681,19 +681,7 @@ protected function asJson($value) } /** - * Decode the given JSON back into an array or object. - * - * @param string $value - * @param bool $asObject - * @return mixed - */ - public function fromJson($value, $asObject = false) - { - return json_decode($value, ! $asObject); - } - - /** - * Cast the given float value. + * Decode the given float. * * @param mixed $value * @return mixed @@ -712,6 +700,18 @@ public function fromFloat($value) } } + /** + * Decode the given JSON back into an array or object. + * + * @param string $value + * @param bool $asObject + * @return mixed + */ + public function fromJson($value, $asObject = false) + { + return json_decode($value, ! $asObject); + } + /** * Return a timestamp as DateTime object with time set to 00:00:00. * From 5222a966be392c3a8d0c3087df623897ea5daa5c Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Mon, 30 Jul 2018 09:55:08 -0400 Subject: [PATCH 0173/2459] Allow Gate::after() callbacks to provide a result (#24935) --- src/Illuminate/Auth/Access/Gate.php | 16 ++++----- tests/Auth/AuthAccessGateTest.php | 52 ++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index d73d472c939d..3f8c450a4ac7 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -326,11 +326,9 @@ protected function raw($ability, $arguments = []) // After calling the authorization callback, we will call the "after" callbacks // that are registered with the Gate, which allows a developer to do logging // if that is required for this application. Then we'll return the result. - $this->callAfterCallbacks( + return $this->callAfterCallbacks( $user, $ability, $arguments, $result ); - - return $result; } /** @@ -482,15 +480,17 @@ protected function callBeforeCallbacks($user, $ability, array $arguments) */ protected function callAfterCallbacks($user, $ability, array $arguments, $result) { - $arguments = array_merge([$user, $ability, $result], [$arguments]); - foreach ($this->afterCallbacks as $after) { if (is_null($user) && ! $this->callbackAllowsGuests($after)) { continue; } - $after(...$arguments); + $afterResult = $after($user, $ability, $result, $arguments); + + $result = $result ?? $afterResult; } + + return $result; } /** @@ -514,7 +514,7 @@ protected function resolveAuthCallback($user, $ability, array $arguments) } return function () { - return false; + return null; }; } @@ -597,7 +597,7 @@ protected function resolvePolicyCallback($user, $ability, array $arguments, $pol return is_callable([$policy, $ability]) ? $policy->{$ability}($user, ...$arguments) - : false; + : null; }; } diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index 441034a32304..110cfbeb537c 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -194,6 +194,7 @@ public function test_after_callbacks_are_called_with_result() $gate->define('foo', function ($user) { return true; }); + $gate->define('bar', function ($user) { return false; }); @@ -201,8 +202,10 @@ public function test_after_callbacks_are_called_with_result() $gate->after(function ($user, $ability, $result) { if ($ability == 'foo') { $this->assertTrue($result, 'After callback on `foo` should receive true as result'); + } elseif ($ability == 'bar') { + $this->assertFalse($result, 'After callback on `bar` should receive false as result'); } else { - $this->assertFalse($result, 'After callback on `bar` or `missing` should receive false as result'); + $this->assertNull($result, 'After callback on `missing` should receive null as result'); } }); @@ -211,6 +214,53 @@ public function test_after_callbacks_are_called_with_result() $this->assertFalse($gate->check('missing')); } + public function test_after_callbacks_can_allow_if_null() + { + $gate = $this->getBasicGate(); + + $gate->after(function ($user, $ability, $result) { + return true; + }); + + $this->assertTrue($gate->allows('null')); + } + + public function test_after_callbacks_do_not_override_previous_result() + { + $gate = $this->getBasicGate(); + + $gate->define('deny', function ($user) { + return false; + }); + + $gate->define('allow', function ($user) { + return true; + }); + + $gate->after(function ($user, $ability, $result) { + return ! $result; + }); + + $this->assertTrue($gate->allows('allow')); + $this->assertTrue($gate->denies('deny')); + } + + public function test_after_callbacks_do_not_override_each_other() + { + $gate = $this->getBasicGate(); + + $gate->after(function ($user, $ability, $result) { + return $ability == 'allow' ? true : false; + }); + + $gate->after(function ($user, $ability, $result) { + return ! $result; + }); + + $this->assertTrue($gate->allows('allow')); + $this->assertTrue($gate->denies('deny')); + } + public function test_current_user_that_is_on_gate_always_injected_into_closure_callbacks() { $gate = $this->getBasicGate(); From e99e447bc8870d1826733cc681112dcb1b4d95d0 Mon Sep 17 00:00:00 2001 From: QWp6t Date: Tue, 31 Jul 2018 05:49:14 -0700 Subject: [PATCH 0174/2459] Remove unused $options in Application::register() (#25028) --- src/Illuminate/Contracts/Foundation/Application.php | 3 +-- src/Illuminate/Foundation/Application.php | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Contracts/Foundation/Application.php b/src/Illuminate/Contracts/Foundation/Application.php index 810f929b4e64..e2e03cf6bb57 100644 --- a/src/Illuminate/Contracts/Foundation/Application.php +++ b/src/Illuminate/Contracts/Foundation/Application.php @@ -59,11 +59,10 @@ public function registerConfiguredProviders(); * Register a service provider with the application. * * @param \Illuminate\Support\ServiceProvider|string $provider - * @param array $options * @param bool $force * @return \Illuminate\Support\ServiceProvider */ - public function register($provider, $options = [], $force = false); + public function register($provider, $force = false); /** * Register a deferred provider and service. diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 955c4ab5a42c..9ae3b668bb94 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -552,11 +552,10 @@ public function registerConfiguredProviders() * Register a service provider with the application. * * @param \Illuminate\Support\ServiceProvider|string $provider - * @param array $options * @param bool $force * @return \Illuminate\Support\ServiceProvider */ - public function register($provider, $options = [], $force = false) + public function register($provider, $force = false) { if (($registered = $this->getProvider($provider)) && ! $force) { return $registered; From 2ee2bb537ee10f398e9c4f4ffbc12b057a93a3d2 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Tue, 31 Jul 2018 14:50:24 +0200 Subject: [PATCH 0175/2459] Add tests for Arr::query(). (#25024) --- tests/Support/SupportArrTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/Support/SupportArrTest.php b/tests/Support/SupportArrTest.php index 59f0cc4c404c..620307a9af97 100644 --- a/tests/Support/SupportArrTest.php +++ b/tests/Support/SupportArrTest.php @@ -419,6 +419,16 @@ public function testPull() $this->assertEquals(['emails' => ['joe@example.com' => 'Joe', 'jane@localhost' => 'Jane']], $array); } + public function testQuery() + { + $this->assertSame('', Arr::query([])); + $this->assertSame('foo=bar', Arr::query(['foo' => 'bar'])); + $this->assertSame('foo=bar&bar=baz', Arr::query(['foo' => 'bar', 'bar' => 'baz'])); + $this->assertSame('foo=bar&bar=1', Arr::query(['foo' => 'bar', 'bar' => true])); + $this->assertSame('foo=bar', Arr::query(['foo' => 'bar', 'bar' => null])); + $this->assertSame('foo=bar&bar=', Arr::query(['foo' => 'bar', 'bar' => ''])); + } + public function testRandom() { $random = Arr::random(['foo', 'bar', 'baz']); From 6ddb11400b95ca178a82c19e5fba5b2909c0db9f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 31 Jul 2018 07:54:02 -0500 Subject: [PATCH 0176/2459] formatting --- src/Illuminate/Database/Eloquent/Model.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 800efe54b46e..a5adb894c270 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -722,7 +722,9 @@ protected function performUpdate(Builder $query) if (count($dirty) > 0) { $this->setKeysForSaveQuery($query)->update($dirty); + $this->syncChanges(); + $this->fireModelEvent('updated', false); } From 5e33a96cd5fe9f5bea953a3e07ec827d5f19a9a3 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Tue, 31 Jul 2018 20:37:08 +0200 Subject: [PATCH 0177/2459] Add Builder::whereJsonLength() --- src/Illuminate/Database/Query/Builder.php | 43 ++++++++++ .../Database/Query/Grammars/Grammar.php | 56 +++++++++++++ .../Database/Query/Grammars/MySqlGrammar.php | 15 ++++ .../Query/Grammars/PostgresGrammar.php | 15 ++++ .../Query/Grammars/SqlServerGrammar.php | 32 ++++---- tests/Database/DatabaseQueryBuilderTest.php | 78 +++++++++++++++++++ 6 files changed, 223 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 5420f4c65dd5..8620ea5bea55 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1492,6 +1492,49 @@ public function orWhereJsonDoesntContain($column, $value) return $this->whereJsonDoesntContain($column, $value, 'or'); } + /** + * Add a "where JSON length" clause to the query. + * + * @param string $column + * @param mixed $operator + * @param mixed $value + * @param string $boolean + * @return $this + */ + public function whereJsonLength($column, $operator, $value = null, $boolean = 'and') + { + $type = 'JsonLength'; + + list($value, $operator) = $this->prepareValueAndOperator( + $value, $operator, func_num_args() === 2 + ); + + $this->wheres[] = compact('type', 'column', 'operator', 'value', 'boolean'); + + if (! $value instanceof Expression) { + $this->addBinding($value); + } + + return $this; + } + + /** + * Add a "or where JSON length" clause to the query. + * + * @param string $column + * @param mixed $operator + * @param mixed $value + * @return $this + */ + public function orWhereJsonLength($column, $operator, $value = null) + { + list($value, $operator) = $this->prepareValueAndOperator( + $value, $operator, func_num_args() === 2 + ); + + return $this->whereJsonLength($column, $operator, $value, 'or'); + } + /** * Handles dynamic "where" clauses to the query. * diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index b9e002b2b9b2..4820f320c0a5 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -535,6 +535,34 @@ public function prepareBindingForJsonContains($binding) return json_encode($binding); } + /** + * Compile a "where JSON length" clause. + * + * @param \Illuminate\Database\Query\Builder $query + * @param array $where + * @return string + */ + protected function whereJsonLength(Builder $query, $where) + { + return $this->compileJsonLength( + $where['column'], $where['operator'], $this->parameter($where['value']) + ); + } + + /** + * Compile a "JSON length" statement into SQL. + * + * @param string $column + * @param string $operator + * @param string $value + * @return string + * @throws \RuntimeException + */ + protected function compileJsonLength($column, $operator, $value) + { + throw new RuntimeException('This database engine does not support JSON length operations.'); + } + /** * Compile the "group by" portions of the query. * @@ -930,6 +958,34 @@ protected function wrapJsonSelector($value) throw new RuntimeException('This database engine does not support JSON operations.'); } + /** + * Split the given JSON selector into the field and the optional path and wrap them separately. + * + * @param string $column + * @return array + */ + protected function wrapJsonFieldAndPath($column) + { + $parts = explode('->', $column, 2); + + $field = $this->wrap($parts[0]); + + $path = count($parts) > 1 ? ', '.$this->wrapJsonPath($parts[1]) : ''; + + return [$field, $path]; + } + + /** + * Wrap the given JSON path. + * + * @param string $value + * @return string + */ + protected function wrapJsonPath($value) + { + return '\'$."'.str_replace('->', '"."', $value).'"\''; + } + /** * Determine if the given string is a JSON selector. * diff --git a/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php index 38ac9cb3b43e..fce9a08519eb 100755 --- a/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php @@ -63,6 +63,21 @@ protected function compileJsonContains($column, $value) return 'json_contains('.$this->wrap($column).', '.$value.')'; } + /** + * Compile a "JSON length" statement into SQL. + * + * @param string $column + * @param string $operator + * @param string $value + * @return string + */ + protected function compileJsonLength($column, $operator, $value) + { + list($field, $path) = $this->wrapJsonFieldAndPath($column); + + return 'json_length('.$field.$path.') '.$operator.' '.$value; + } + /** * Compile a single union statement. * diff --git a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php index b41299a5d038..2a2f3bfb2b18 100755 --- a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php @@ -77,6 +77,21 @@ protected function compileJsonContains($column, $value) return '('.$column.')::jsonb @> '.$value; } + /** + * Compile a "JSON length" statement into SQL. + * + * @param string $column + * @param string $operator + * @param string $value + * @return string + */ + protected function compileJsonLength($column, $operator, $value) + { + $column = str_replace('->>', '->', $this->wrap($column)); + + return 'json_array_length(('.$column.')::json) '.$operator.' '.$value; + } + /** * Compile the lock into SQL. * diff --git a/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php index bb4809d67291..0583c4ae4719 100755 --- a/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SqlServerGrammar.php @@ -112,11 +112,7 @@ protected function whereDate(Builder $query, $where) */ protected function compileJsonContains($column, $value) { - $parts = explode('->', $column, 2); - - $field = $this->wrap($parts[0]); - - $path = count($parts) > 1 ? ', '.$this->wrapJsonPath($parts[1]) : ''; + list($field, $path) = $this->wrapJsonFieldAndPath($column); return $value.' in (select [value] from openjson('.$field.$path.'))'; } @@ -132,6 +128,21 @@ public function prepareBindingForJsonContains($binding) return is_bool($binding) ? json_encode($binding) : $binding; } + /** + * Compile a "JSON length" statement into SQL. + * + * @param string $column + * @param string $operator + * @param string $value + * @return string + */ + protected function compileJsonLength($column, $operator, $value) + { + list($field, $path) = $this->wrapJsonFieldAndPath($column); + + return '(select count(*) from openjson('.$field.$path.')) '.$operator.' '.$value; + } + /** * Create a full ANSI offset clause for the query. * @@ -458,17 +469,6 @@ protected function wrapJsonSelector($value) return 'json_value('.$field.', '.$this->wrapJsonPath($parts[0]).')'; } - /** - * Wrap the given JSON path. - * - * @param string $value - * @return string - */ - protected function wrapJsonPath($value) - { - return '\'$."'.str_replace('->', '"."', $value).'"\''; - } - /** * Wrap a table in keyword identifiers. * diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 3b74507ad8a8..d612dc470ea9 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2758,6 +2758,84 @@ public function testWhereJsonDoesntContainSqlServer() $this->assertEquals([1], $builder->getBindings()); } + public function testWhereJsonLengthMySql() + { + $builder = $this->getMySqlBuilder(); + $builder->select('*')->from('users')->whereJsonLength('options', 0); + $this->assertEquals('select * from `users` where json_length(`options`) = ?', $builder->toSql()); + $this->assertEquals([0], $builder->getBindings()); + + $builder = $this->getMySqlBuilder(); + $builder->select('*')->from('users')->whereJsonLength('users.options->languages', '>', 0); + $this->assertEquals('select * from `users` where json_length(`users`.`options`, \'$."languages"\') > ?', $builder->toSql()); + $this->assertEquals([0], $builder->getBindings()); + + $builder = $this->getMySqlBuilder(); + $builder->select('*')->from('users')->where('id', '=', 1)->orWhereJsonLength('options->languages', new Raw('0')); + $this->assertEquals('select * from `users` where `id` = ? or json_length(`options`, \'$."languages"\') = 0', $builder->toSql()); + $this->assertEquals([1], $builder->getBindings()); + + $builder = $this->getMySqlBuilder(); + $builder->select('*')->from('users')->where('id', '=', 1)->orWhereJsonLength('options->languages', '>', new Raw('0')); + $this->assertEquals('select * from `users` where `id` = ? or json_length(`options`, \'$."languages"\') > 0', $builder->toSql()); + $this->assertEquals([1], $builder->getBindings()); + } + + public function testWhereJsonLengthPostgres() + { + $builder = $this->getPostgresBuilder(); + $builder->select('*')->from('users')->whereJsonLength('options', 0); + $this->assertEquals('select * from "users" where json_array_length(("options")::json) = ?', $builder->toSql()); + $this->assertEquals([0], $builder->getBindings()); + + $builder = $this->getPostgresBuilder(); + $builder->select('*')->from('users')->whereJsonLength('users.options->languages', '>', 0); + $this->assertEquals('select * from "users" where json_array_length(("users"."options"->\'languages\')::json) > ?', $builder->toSql()); + $this->assertEquals([0], $builder->getBindings()); + + $builder = $this->getPostgresBuilder(); + $builder->select('*')->from('users')->where('id', '=', 1)->orWhereJsonLength('options->languages', new Raw('0')); + $this->assertEquals('select * from "users" where "id" = ? or json_array_length(("options"->\'languages\')::json) = 0', $builder->toSql()); + $this->assertEquals([1], $builder->getBindings()); + + $builder = $this->getPostgresBuilder(); + $builder->select('*')->from('users')->where('id', '=', 1)->orWhereJsonLength('options->languages', '>', new Raw('0')); + $this->assertEquals('select * from "users" where "id" = ? or json_array_length(("options"->\'languages\')::json) > 0', $builder->toSql()); + $this->assertEquals([1], $builder->getBindings()); + } + + /** + * @expectedException \RuntimeException + */ + public function testWhereJsonLengthSqlite() + { + $builder = $this->getSQLiteBuilder(); + $builder->select('*')->from('users')->whereJsonLength('options', 0)->toSql(); + } + + public function testWhereJsonLengthSqlServer() + { + $builder = $this->getSqlServerBuilder(); + $builder->select('*')->from('users')->whereJsonLength('options', 0); + $this->assertEquals('select * from [users] where (select count(*) from openjson([options])) = ?', $builder->toSql()); + $this->assertEquals([0], $builder->getBindings()); + + $builder = $this->getSqlServerBuilder(); + $builder->select('*')->from('users')->whereJsonLength('users.options->languages', '>', 0); + $this->assertEquals('select * from [users] where (select count(*) from openjson([users].[options], \'$."languages"\')) > ?', $builder->toSql()); + $this->assertEquals([0], $builder->getBindings()); + + $builder = $this->getSqlServerBuilder(); + $builder->select('*')->from('users')->where('id', '=', 1)->orWhereJsonLength('options->languages', new Raw('0')); + $this->assertEquals('select * from [users] where [id] = ? or (select count(*) from openjson([options], \'$."languages"\')) = 0', $builder->toSql()); + $this->assertEquals([1], $builder->getBindings()); + + $builder = $this->getSqlServerBuilder(); + $builder->select('*')->from('users')->where('id', '=', 1)->orWhereJsonLength('options->languages', '>', new Raw('0')); + $this->assertEquals('select * from [users] where [id] = ? or (select count(*) from openjson([options], \'$."languages"\')) > 0', $builder->toSql()); + $this->assertEquals([1], $builder->getBindings()); + } + public function testFromSub() { $builder = $this->getBuilder(); From 57adf12bd3cc3bf89f3cfcea25ca690ecffb8311 Mon Sep 17 00:00:00 2001 From: Nguyen Xuan Quynh Date: Wed, 1 Aug 2018 20:20:56 +0700 Subject: [PATCH 0178/2459] fix RedirectResponse session param document (#25042) --- src/Illuminate/Http/RedirectResponse.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Http/RedirectResponse.php b/src/Illuminate/Http/RedirectResponse.php index 67e9cddc434a..fc177f8dfb45 100755 --- a/src/Illuminate/Http/RedirectResponse.php +++ b/src/Illuminate/Http/RedirectResponse.php @@ -26,7 +26,7 @@ class RedirectResponse extends BaseRedirectResponse protected $request; /** - * The session store implementation. + * The session store instance. * * @var \Illuminate\Session\Store */ @@ -192,7 +192,7 @@ public function setRequest(Request $request) } /** - * Get the session store implementation. + * Get the session store instance. * * @return \Illuminate\Session\Store|null */ @@ -202,7 +202,7 @@ public function getSession() } /** - * Set the session store implementation. + * Set the session store instance. * * @param \Illuminate\Session\Store $session * @return void From 54703971c1528c9c24a97fd7f7e6899fe2a57ef0 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Fri, 3 Aug 2018 14:20:23 -0500 Subject: [PATCH 0179/2459] [5.8] Bumped Laravel version to 5.8 (#25057) * Bumped laravel version to 5.8 * Bumped orchestra/testbench-core to 3.8 --- composer.json | 4 ++-- src/Illuminate/Auth/composer.json | 16 ++++++++-------- src/Illuminate/Broadcasting/composer.json | 10 +++++----- src/Illuminate/Bus/composer.json | 8 ++++---- src/Illuminate/Cache/composer.json | 12 ++++++------ src/Illuminate/Config/composer.json | 6 +++--- src/Illuminate/Console/composer.json | 6 +++--- src/Illuminate/Container/composer.json | 4 ++-- src/Illuminate/Contracts/composer.json | 2 +- src/Illuminate/Cookie/composer.json | 6 +++--- src/Illuminate/Database/composer.json | 16 ++++++++-------- src/Illuminate/Encryption/composer.json | 6 +++--- src/Illuminate/Events/composer.json | 8 ++++---- src/Illuminate/Filesystem/composer.json | 6 +++--- src/Illuminate/Foundation/Application.php | 2 +- src/Illuminate/Hashing/composer.json | 6 +++--- src/Illuminate/Http/composer.json | 6 +++--- src/Illuminate/Log/composer.json | 6 +++--- src/Illuminate/Mail/composer.json | 8 ++++---- src/Illuminate/Notifications/composer.json | 20 ++++++++++---------- src/Illuminate/Pagination/composer.json | 6 +++--- src/Illuminate/Pipeline/composer.json | 6 +++--- src/Illuminate/Queue/composer.json | 16 ++++++++-------- src/Illuminate/Redis/composer.json | 6 +++--- src/Illuminate/Routing/composer.json | 16 ++++++++-------- src/Illuminate/Session/composer.json | 10 +++++----- src/Illuminate/Support/composer.json | 6 +++--- src/Illuminate/Translation/composer.json | 8 ++++---- src/Illuminate/Validation/composer.json | 12 ++++++------ src/Illuminate/View/composer.json | 12 ++++++------ tests/Console/ConsoleApplicationTest.php | 2 +- tests/Support/SupportTestingMailFakeTest.php | 4 ++-- 32 files changed, 131 insertions(+), 131 deletions(-) diff --git a/composer.json b/composer.json index 92a10e5a9774..df1aacbd3801 100644 --- a/composer.json +++ b/composer.json @@ -79,7 +79,7 @@ "league/flysystem-cached-adapter": "^1.0", "mockery/mockery": "^1.0", "moontoast/math": "^1.1", - "orchestra/testbench-core": "3.7.*", + "orchestra/testbench-core": "3.8.*", "pda/pheanstalk": "^3.0", "phpunit/phpunit": "^7.0", "predis/predis": "^1.1.1", @@ -106,7 +106,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { diff --git a/src/Illuminate/Auth/composer.json b/src/Illuminate/Auth/composer.json index ae98c7dc3fe3..f9eaf684fbd2 100644 --- a/src/Illuminate/Auth/composer.json +++ b/src/Illuminate/Auth/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/http": "5.7.*", - "illuminate/queue": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/contracts": "5.8.*", + "illuminate/http": "5.8.*", + "illuminate/queue": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -27,13 +27,13 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { - "illuminate/console": "Required to use the auth:clear-resets command (5.7.*).", - "illuminate/queue": "Required to fire login / logout events (5.7.*).", - "illuminate/session": "Required to use the session based guard (5.7.*)." + "illuminate/console": "Required to use the auth:clear-resets command (5.8.*).", + "illuminate/queue": "Required to fire login / logout events (5.8.*).", + "illuminate/session": "Required to use the session based guard (5.8.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Broadcasting/composer.json b/src/Illuminate/Broadcasting/composer.json index 5e7e5a289d31..c9b3a6df555c 100644 --- a/src/Illuminate/Broadcasting/composer.json +++ b/src/Illuminate/Broadcasting/composer.json @@ -16,10 +16,10 @@ "require": { "php": "^7.1.3", "psr/log": "^1.0", - "illuminate/bus": "5.7.*", - "illuminate/contracts": "5.7.*", - "illuminate/queue": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/bus": "5.8.*", + "illuminate/contracts": "5.8.*", + "illuminate/queue": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -28,7 +28,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { diff --git a/src/Illuminate/Bus/composer.json b/src/Illuminate/Bus/composer.json index da911fda43e5..d2662466468e 100644 --- a/src/Illuminate/Bus/composer.json +++ b/src/Illuminate/Bus/composer.json @@ -15,9 +15,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/pipeline": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/contracts": "5.8.*", + "illuminate/pipeline": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Cache/composer.json b/src/Illuminate/Cache/composer.json index a461242ce37f..974782f0abc0 100755 --- a/src/Illuminate/Cache/composer.json +++ b/src/Illuminate/Cache/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -25,13 +25,13 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { - "illuminate/database": "Required to use the database cache driver (5.7.*).", - "illuminate/filesystem": "Required to use the file cache driver (5.7.*).", - "illuminate/redis": "Required to use the redis cache driver (5.7.*)." + "illuminate/database": "Required to use the database cache driver (5.8.*).", + "illuminate/filesystem": "Required to use the file cache driver (5.8.*).", + "illuminate/redis": "Required to use the redis cache driver (5.8.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Config/composer.json b/src/Illuminate/Config/composer.json index 1dbdd4be8209..661104034940 100755 --- a/src/Illuminate/Config/composer.json +++ b/src/Illuminate/Config/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index 91ce9743a2ff..078c8ed507ad 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*", "symfony/console": "^4.1" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { diff --git a/src/Illuminate/Container/composer.json b/src/Illuminate/Container/composer.json index 3dd083c8c696..1d72999dd8c1 100755 --- a/src/Illuminate/Container/composer.json +++ b/src/Illuminate/Container/composer.json @@ -15,7 +15,7 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", + "illuminate/contracts": "5.8.*", "psr/container": "^1.0" }, "autoload": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Contracts/composer.json b/src/Illuminate/Contracts/composer.json index 62c351eb518e..dcb098b1c524 100644 --- a/src/Illuminate/Contracts/composer.json +++ b/src/Illuminate/Contracts/composer.json @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index 014b7d21daea..185fe15b09a2 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*", "symfony/http-foundation": "^4.1", "symfony/http-kernel": "^4.1" }, @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Database/composer.json b/src/Illuminate/Database/composer.json index 81ef3b478e9a..86a997bc79ff 100644 --- a/src/Illuminate/Database/composer.json +++ b/src/Illuminate/Database/composer.json @@ -16,9 +16,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.7.*", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/container": "5.8.*", + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -27,16 +27,16 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).", "fzaninotto/faker": "Required to use the eloquent factory builder (^1.4).", - "illuminate/console": "Required to use the database commands (5.7.*).", - "illuminate/events": "Required to use the observers with Eloquent (5.7.*).", - "illuminate/filesystem": "Required to use the migrations (5.7.*).", - "illuminate/pagination": "Required to paginate the result set (5.7.*)." + "illuminate/console": "Required to use the database commands (5.8.*).", + "illuminate/events": "Required to use the observers with Eloquent (5.8.*).", + "illuminate/filesystem": "Required to use the migrations (5.8.*).", + "illuminate/pagination": "Required to paginate the result set (5.8.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Encryption/composer.json b/src/Illuminate/Encryption/composer.json index 09eb4c74a271..44893130854b 100644 --- a/src/Illuminate/Encryption/composer.json +++ b/src/Illuminate/Encryption/composer.json @@ -17,8 +17,8 @@ "php": "^7.1.3", "ext-mbstring": "*", "ext-openssl": "*", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Events/composer.json b/src/Illuminate/Events/composer.json index cba2e0fe27c9..d75f2c1eae4e 100755 --- a/src/Illuminate/Events/composer.json +++ b/src/Illuminate/Events/composer.json @@ -15,9 +15,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.7.*", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/container": "5.8.*", + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index 4157c814a464..98826965342c 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*", "symfony/finder": "^4.1" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 9ae3b668bb94..72ccb1a5f8ef 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.7-dev'; + const VERSION = '5.8-dev'; /** * The base path for the Laravel installation. diff --git a/src/Illuminate/Hashing/composer.json b/src/Illuminate/Hashing/composer.json index ed9e20e8c07c..4da36baadb09 100755 --- a/src/Illuminate/Hashing/composer.json +++ b/src/Illuminate/Hashing/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index 69eb15562d04..7ca7e05e0824 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/session": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/session": "5.8.*", + "illuminate/support": "5.8.*", "symfony/http-foundation": "^4.1", "symfony/http-kernel": "^4.1" }, @@ -27,7 +27,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Log/composer.json b/src/Illuminate/Log/composer.json index f0af69bd44de..3e3b22184b48 100755 --- a/src/Illuminate/Log/composer.json +++ b/src/Illuminate/Log/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*", "monolog/monolog": "^1.11" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Mail/composer.json b/src/Illuminate/Mail/composer.json index d07f51359de5..76b4f4502d8b 100755 --- a/src/Illuminate/Mail/composer.json +++ b/src/Illuminate/Mail/composer.json @@ -16,9 +16,9 @@ "require": { "php": "^7.1.3", "erusev/parsedown": "^1.7", - "illuminate/container": "5.7.*", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/container": "5.8.*", + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*", "psr/log": "^1.0", "swiftmailer/swiftmailer": "^6.0", "tijsverkoyen/css-to-inline-styles": "^2.2.1" @@ -30,7 +30,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { diff --git a/src/Illuminate/Notifications/composer.json b/src/Illuminate/Notifications/composer.json index e893261429ae..e87ee0d74b13 100644 --- a/src/Illuminate/Notifications/composer.json +++ b/src/Illuminate/Notifications/composer.json @@ -15,14 +15,14 @@ ], "require": { "php": "^7.1.3", - "illuminate/broadcasting": "5.7.*", - "illuminate/bus": "5.7.*", - "illuminate/container": "5.7.*", - "illuminate/contracts": "5.7.*", - "illuminate/filesystem": "5.7.*", - "illuminate/mail": "5.7.*", - "illuminate/queue": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/broadcasting": "5.8.*", + "illuminate/bus": "5.8.*", + "illuminate/container": "5.8.*", + "illuminate/contracts": "5.8.*", + "illuminate/filesystem": "5.8.*", + "illuminate/mail": "5.8.*", + "illuminate/queue": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -31,12 +31,12 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { "guzzlehttp/guzzle": "Required to use the Slack transport (^6.0)", - "illuminate/database": "Required to use the database transport (5.7.*).", + "illuminate/database": "Required to use the database transport (5.8.*).", "nexmo/client": "Required to use the Nexmo transport (^1.0)." }, "config": { diff --git a/src/Illuminate/Pagination/composer.json b/src/Illuminate/Pagination/composer.json index 9e4d73729746..0f17cd2dc614 100755 --- a/src/Illuminate/Pagination/composer.json +++ b/src/Illuminate/Pagination/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Pipeline/composer.json b/src/Illuminate/Pipeline/composer.json index f3225d4a8b1b..65d3085e841a 100644 --- a/src/Illuminate/Pipeline/composer.json +++ b/src/Illuminate/Pipeline/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index ff3376da1332..0414cb74b698 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -15,12 +15,12 @@ ], "require": { "php": "^7.1.3", - "illuminate/console": "5.7.*", - "illuminate/container": "5.7.*", - "illuminate/contracts": "5.7.*", - "illuminate/database": "5.7.*", - "illuminate/filesystem": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/console": "5.8.*", + "illuminate/container": "5.8.*", + "illuminate/contracts": "5.8.*", + "illuminate/database": "5.8.*", + "illuminate/filesystem": "5.8.*", + "illuminate/support": "5.8.*", "symfony/debug": "^4.1", "symfony/process": "^4.1" }, @@ -31,14 +31,14 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { "ext-pcntl": "Required to use all features of the queue worker.", "ext-posix": "Required to use all features of the queue worker.", "aws/aws-sdk-php": "Required to use the SQS queue driver (^3.0).", - "illuminate/redis": "Required to use the Redis queue driver (5.7.*).", + "illuminate/redis": "Required to use the Redis queue driver (5.8.*).", "pda/pheanstalk": "Required to use the Beanstalk queue driver (^3.0)." }, "config": { diff --git a/src/Illuminate/Redis/composer.json b/src/Illuminate/Redis/composer.json index 72f8b3b717ab..a1ab184f91ee 100755 --- a/src/Illuminate/Redis/composer.json +++ b/src/Illuminate/Redis/composer.json @@ -15,8 +15,8 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*", "predis/predis": "^1.0" }, "autoload": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index e438d41989fb..f6fe4e92f715 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -15,12 +15,12 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.7.*", - "illuminate/contracts": "5.7.*", - "illuminate/http": "5.7.*", - "illuminate/pipeline": "5.7.*", - "illuminate/session": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/container": "5.8.*", + "illuminate/contracts": "5.8.*", + "illuminate/http": "5.8.*", + "illuminate/pipeline": "5.8.*", + "illuminate/session": "5.8.*", + "illuminate/support": "5.8.*", "symfony/debug": "^4.1", "symfony/http-foundation": "^4.1", "symfony/http-kernel": "^4.1", @@ -33,11 +33,11 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { - "illuminate/console": "Required to use the make commands (5.7.*).", + "illuminate/console": "Required to use the make commands (5.8.*).", "symfony/psr-http-message-bridge": "Required to psr7 bridging features (^1.0)." }, "config": { diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index 7e912c120d9e..439532b17b83 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -15,9 +15,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/filesystem": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/contracts": "5.8.*", + "illuminate/filesystem": "5.8.*", + "illuminate/support": "5.8.*", "symfony/finder": "^4.1", "symfony/http-foundation": "^4.1" }, @@ -28,11 +28,11 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { - "illuminate/console": "Required to use the session:table command (5.7.*)." + "illuminate/console": "Required to use the session:table command (5.8.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index e36143dbd94d..722ac685ca66 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -17,7 +17,7 @@ "php": "^7.1.3", "ext-mbstring": "*", "doctrine/inflector": "^1.1", - "illuminate/contracts": "5.7.*", + "illuminate/contracts": "5.8.*", "nesbot/carbon": "^1.24.1" }, "conflict": { @@ -33,11 +33,11 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { - "illuminate/filesystem": "Required to use the composer class (5.7.*).", + "illuminate/filesystem": "Required to use the composer class (5.8.*).", "ramsey/uuid": "Required to use Str::uuid() (^3.7).", "symfony/process": "Required to use the composer class (^4.1).", "symfony/var-dumper": "Required to use the dd function (^4.1)." diff --git a/src/Illuminate/Translation/composer.json b/src/Illuminate/Translation/composer.json index d8784d7cceeb..f00bc286925a 100755 --- a/src/Illuminate/Translation/composer.json +++ b/src/Illuminate/Translation/composer.json @@ -15,9 +15,9 @@ ], "require": { "php": "^7.1.3", - "illuminate/contracts": "5.7.*", - "illuminate/filesystem": "5.7.*", - "illuminate/support": "5.7.*" + "illuminate/contracts": "5.8.*", + "illuminate/filesystem": "5.8.*", + "illuminate/support": "5.8.*" }, "autoload": { "psr-4": { @@ -26,7 +26,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index 4a9da5f2541c..0e8a9c3da200 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -15,10 +15,10 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.7.*", - "illuminate/contracts": "5.7.*", - "illuminate/support": "5.7.*", - "illuminate/translation": "5.7.*", + "illuminate/container": "5.8.*", + "illuminate/contracts": "5.8.*", + "illuminate/support": "5.8.*", + "illuminate/translation": "5.8.*", "symfony/http-foundation": "^4.1" }, "autoload": { @@ -28,11 +28,11 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "suggest": { - "illuminate/database": "Required to use the database presence verifier (5.7.*)." + "illuminate/database": "Required to use the database presence verifier (5.8.*)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/View/composer.json b/src/Illuminate/View/composer.json index 44ecebcca307..a079ebd45d24 100644 --- a/src/Illuminate/View/composer.json +++ b/src/Illuminate/View/composer.json @@ -15,11 +15,11 @@ ], "require": { "php": "^7.1.3", - "illuminate/container": "5.7.*", - "illuminate/contracts": "5.7.*", - "illuminate/events": "5.7.*", - "illuminate/filesystem": "5.7.*", - "illuminate/support": "5.7.*", + "illuminate/container": "5.8.*", + "illuminate/contracts": "5.8.*", + "illuminate/events": "5.8.*", + "illuminate/filesystem": "5.8.*", + "illuminate/support": "5.8.*", "symfony/debug": "^4.1" }, "autoload": { @@ -29,7 +29,7 @@ }, "extra": { "branch-alias": { - "dev-master": "5.7-dev" + "dev-master": "5.8-dev" } }, "config": { diff --git a/tests/Console/ConsoleApplicationTest.php b/tests/Console/ConsoleApplicationTest.php index 06442e9dbdf9..402640799934 100755 --- a/tests/Console/ConsoleApplicationTest.php +++ b/tests/Console/ConsoleApplicationTest.php @@ -47,7 +47,7 @@ public function testResolveAddsCommandViaApplicationResolution() protected function getMockConsole(array $methods) { - $app = m::mock('Illuminate\Contracts\Foundation\Application', ['version' => '5.7']); + $app = m::mock('Illuminate\Contracts\Foundation\Application', ['version' => '5.8']); $events = m::mock('Illuminate\Contracts\Events\Dispatcher', ['dispatch' => null]); return $this->getMockBuilder('Illuminate\Console\Application')->setMethods($methods)->setConstructorArgs([ diff --git a/tests/Support/SupportTestingMailFakeTest.php b/tests/Support/SupportTestingMailFakeTest.php index c78ebbcef440..c75c50ec01c7 100644 --- a/tests/Support/SupportTestingMailFakeTest.php +++ b/tests/Support/SupportTestingMailFakeTest.php @@ -123,7 +123,7 @@ class MailableStub extends Mailable { public $framework = 'Laravel'; - protected $version = '5.7'; + protected $version = '5.8'; /** * Build the message. @@ -141,7 +141,7 @@ class QueueableMailableStub extends Mailable implements ShouldQueue { public $framework = 'Laravel'; - protected $version = '5.7'; + protected $version = '5.8'; /** * Build the message. From bbe08b01fea3b4f3f9d2979ea10e1150efbe7c20 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 4 Aug 2018 08:50:23 -1000 Subject: [PATCH 0180/2459] argon2id support --- src/Illuminate/Hashing/Argon2idHasher.php | 16 ++++++++++++++++ src/Illuminate/Hashing/ArgonHasher.php | 14 ++++++++++++-- src/Illuminate/Hashing/HashManager.php | 10 ++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 src/Illuminate/Hashing/Argon2idHasher.php diff --git a/src/Illuminate/Hashing/Argon2idHasher.php b/src/Illuminate/Hashing/Argon2idHasher.php new file mode 100644 index 000000000000..39adb6600b6b --- /dev/null +++ b/src/Illuminate/Hashing/Argon2idHasher.php @@ -0,0 +1,16 @@ +algorithm(), [ 'memory_cost' => $this->memory($options), 'time_cost' => $this->time($options), 'threads' => $this->threads($options), @@ -65,6 +65,16 @@ public function make($value, array $options = []) return $hash; } + /** + * Get the algorithm that should be used for hashing. + * + * @return string + */ + protected function algorithm() + { + return PASSWORD_ARGON2I; + } + /** * Check the given plain value against a hash. * @@ -91,7 +101,7 @@ public function check($value, $hashedValue, array $options = []) */ public function needsRehash($hashedValue, array $options = []) { - return password_needs_rehash($hashedValue, PASSWORD_ARGON2I, [ + return password_needs_rehash($hashedValue, $this->algorithm(), [ 'memory_cost' => $this->memory($options), 'time_cost' => $this->time($options), 'threads' => $this->threads($options), diff --git a/src/Illuminate/Hashing/HashManager.php b/src/Illuminate/Hashing/HashManager.php index 9b96617cb670..a7aac950abbc 100644 --- a/src/Illuminate/Hashing/HashManager.php +++ b/src/Illuminate/Hashing/HashManager.php @@ -27,6 +27,16 @@ public function createArgonDriver() return new ArgonHasher($this->app['config']['hashing.argon'] ?? []); } + /** + * Create an instance of the Argon2id hash Driver. + * + * @return \Illuminate\Hashing\Argon2idHasher + */ + public function createArgon2idDriver() + { + return new Argon2idHasher($this->app['config']['hashing.argon'] ?? []); + } + /** * Get information about the given hashed value. * From 20b8f9cc7ba2171a2fe35802f1d232af08edaf27 Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Sat, 4 Aug 2018 15:34:14 +0800 Subject: [PATCH 0181/2459] [5.7] Allow custom monolog driver to be able to use channel name parser (fallback to environment) and parse string level into monolog constant. Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Log/LogManager.php | 52 +------------------ src/Illuminate/Log/LoggerConfiguration.php | 59 ++++++++++++++++++++++ 2 files changed, 61 insertions(+), 50 deletions(-) create mode 100644 src/Illuminate/Log/LoggerConfiguration.php diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 964f5310c05b..9d94f2d399ed 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -18,6 +18,8 @@ class LogManager implements LoggerInterface { + use LoggerConfiguration; + /** * The application instance. * @@ -39,22 +41,6 @@ class LogManager implements LoggerInterface */ protected $customCreators = []; - /** - * The Log levels. - * - * @var array - */ - protected $levels = [ - 'debug' => Monolog::DEBUG, - 'info' => Monolog::INFO, - 'notice' => Monolog::NOTICE, - 'warning' => Monolog::WARNING, - 'error' => Monolog::ERROR, - 'critical' => Monolog::CRITICAL, - 'alert' => Monolog::ALERT, - 'emergency' => Monolog::EMERGENCY, - ]; - /** * Create a new Log manager instance. * @@ -388,40 +374,6 @@ protected function formatter() }); } - /** - * Extract the log channel from the given configuration. - * - * @param array $config - * @return string - */ - protected function parseChannel(array $config) - { - if (! isset($config['name'])) { - return $this->app->bound('env') ? $this->app->environment() : 'production'; - } - - return $config['name']; - } - - /** - * Parse the string level into a Monolog constant. - * - * @param array $config - * @return int - * - * @throws \InvalidArgumentException - */ - protected function level(array $config) - { - $level = $config['level'] ?? 'debug'; - - if (isset($this->levels[$level])) { - return $this->levels[$level]; - } - - throw new InvalidArgumentException('Invalid log level.'); - } - /** * Get the log connection configuration. * diff --git a/src/Illuminate/Log/LoggerConfiguration.php b/src/Illuminate/Log/LoggerConfiguration.php new file mode 100644 index 000000000000..0bfc1514dc61 --- /dev/null +++ b/src/Illuminate/Log/LoggerConfiguration.php @@ -0,0 +1,59 @@ + Monolog::DEBUG, + 'info' => Monolog::INFO, + 'notice' => Monolog::NOTICE, + 'warning' => Monolog::WARNING, + 'error' => Monolog::ERROR, + 'critical' => Monolog::CRITICAL, + 'alert' => Monolog::ALERT, + 'emergency' => Monolog::EMERGENCY, + ]; + + /** + * Parse the string level into a Monolog constant. + * + * @param array $config + * @return int + * + * @throws \InvalidArgumentException + */ + protected function level(array $config) + { + $level = $config['level'] ?? 'debug'; + + if (isset($this->levels[$level])) { + return $this->levels[$level]; + } + + throw new InvalidArgumentException('Invalid log level.'); + } + + /** + * Extract the log channel from the given configuration. + * + * @param array $config + * @return string + */ + protected function parseChannel(array $config) + { + if (! isset($config['name'])) { + return $this->app->bound('env') ? $this->app->environment() : 'production'; + } + + return $config['name']; + } +} From bb57655967f31b426b968a46ca738d6a245e873d Mon Sep 17 00:00:00 2001 From: Mior Muhammad Zaki Date: Sun, 5 Aug 2018 09:26:36 +0800 Subject: [PATCH 0182/2459] Add getFallbackChannelName method. Signed-off-by: Mior Muhammad Zaki --- src/Illuminate/Log/LogManager.php | 10 ++++++++++ src/Illuminate/Log/LoggerConfiguration.php | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 9d94f2d399ed..66e3eb65c328 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -374,6 +374,16 @@ protected function formatter() }); } + /** + * Get fallback log channel name. + * + * @return string + */ + protected function getFallbackChannelName() + { + return $this->app->bound('env') ? $this->app->environment() : 'production'; + } + /** * Get the log connection configuration. * diff --git a/src/Illuminate/Log/LoggerConfiguration.php b/src/Illuminate/Log/LoggerConfiguration.php index 0bfc1514dc61..da1deaa4e0e7 100644 --- a/src/Illuminate/Log/LoggerConfiguration.php +++ b/src/Illuminate/Log/LoggerConfiguration.php @@ -51,9 +51,16 @@ protected function level(array $config) protected function parseChannel(array $config) { if (! isset($config['name'])) { - return $this->app->bound('env') ? $this->app->environment() : 'production'; + return $this->getFallbackChannelName(); } return $config['name']; } + + /** + * Get fallback log channel name. + * + * @return string + */ + abstract protected function getFallbackChannelName(); } From eaacd5201725536b2645a1a6e5dd25cc93af4b5d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 4 Aug 2018 20:55:59 -1000 Subject: [PATCH 0183/2459] change file --- tests/Validation/ValidationValidatorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index b03c15cf7e5b..46d4c0fecc4d 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -2247,7 +2247,7 @@ public function testValidateImageDimensions() public function testValidatePhpMimetypes() { $trans = $this->getIlluminateArrayTranslator(); - $uploadedFile = [__FILE__, '', null, null, null, true]; + $uploadedFile = [__DIR__.'/ValidationRuleTest.php', '', null, null, null, true]; $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['guessExtension', 'getClientOriginalExtension'])->setConstructorArgs($uploadedFile)->getMock(); $file->expects($this->any())->method('guessExtension')->will($this->returnValue('rtf')); From 1d45b187a16bc7fb39df932a704147eb01a710a9 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Sun, 5 Aug 2018 03:29:19 +0200 Subject: [PATCH 0184/2459] Fix Argon2id check method and add tests --- src/Illuminate/Hashing/Argon2IdHasher.php | 39 +++++++++++++++++++++++ src/Illuminate/Hashing/Argon2idHasher.php | 16 ---------- src/Illuminate/Hashing/ArgonHasher.php | 4 +-- src/Illuminate/Hashing/HashManager.php | 6 ++-- tests/Hashing/HasherTest.php | 37 ++++++++++++++++++--- 5 files changed, 76 insertions(+), 26 deletions(-) create mode 100644 src/Illuminate/Hashing/Argon2IdHasher.php delete mode 100644 src/Illuminate/Hashing/Argon2idHasher.php diff --git a/src/Illuminate/Hashing/Argon2IdHasher.php b/src/Illuminate/Hashing/Argon2IdHasher.php new file mode 100644 index 000000000000..657f5842ff47 --- /dev/null +++ b/src/Illuminate/Hashing/Argon2IdHasher.php @@ -0,0 +1,39 @@ +info($hashedValue)['algoName'] !== 'argon2id') { + throw new RuntimeException('This password does not use the Argon2id algorithm.'); + } + + if (strlen($hashedValue) === 0) { + return false; + } + + return password_verify($value, $hashedValue); + } +} diff --git a/src/Illuminate/Hashing/Argon2idHasher.php b/src/Illuminate/Hashing/Argon2idHasher.php deleted file mode 100644 index 39adb6600b6b..000000000000 --- a/src/Illuminate/Hashing/Argon2idHasher.php +++ /dev/null @@ -1,16 +0,0 @@ -info($hashedValue)['algoName'] !== 'argon2i') { - throw new RuntimeException('This password does not use the Argon algorithm.'); + throw new RuntimeException('This password does not use the Argon2i algorithm.'); } return parent::check($value, $hashedValue, $options); diff --git a/src/Illuminate/Hashing/HashManager.php b/src/Illuminate/Hashing/HashManager.php index a7aac950abbc..4dbae34ca9f8 100644 --- a/src/Illuminate/Hashing/HashManager.php +++ b/src/Illuminate/Hashing/HashManager.php @@ -18,7 +18,7 @@ public function createBcryptDriver() } /** - * Create an instance of the Argon2 hash Driver. + * Create an instance of the Argon2i hash Driver. * * @return \Illuminate\Hashing\ArgonHasher */ @@ -30,11 +30,11 @@ public function createArgonDriver() /** * Create an instance of the Argon2id hash Driver. * - * @return \Illuminate\Hashing\Argon2idHasher + * @return \Illuminate\Hashing\Argon2IdHasher */ public function createArgon2idDriver() { - return new Argon2idHasher($this->app['config']['hashing.argon'] ?? []); + return new Argon2IdHasher($this->app['config']['hashing.argon'] ?? []); } /** diff --git a/tests/Hashing/HasherTest.php b/tests/Hashing/HasherTest.php index 884cb1c2380a..64751b4d60f1 100755 --- a/tests/Hashing/HasherTest.php +++ b/tests/Hashing/HasherTest.php @@ -14,12 +14,13 @@ public function testBasicBcryptHashing() $this->assertTrue($hasher->check('password', $value)); $this->assertFalse($hasher->needsRehash($value)); $this->assertTrue($hasher->needsRehash($value, ['rounds' => 1])); + $this->assertSame('bcrypt', password_get_info($value)['algoName']); } - public function testBasicArgonHashing() + public function testBasicArgon2iHashing() { if (! defined('PASSWORD_ARGON2I')) { - $this->markTestSkipped('PHP not compiled with argon2 hashing support.'); + $this->markTestSkipped('PHP not compiled with Argon2i hashing support.'); } $hasher = new \Illuminate\Hashing\ArgonHasher; @@ -28,6 +29,22 @@ public function testBasicArgonHashing() $this->assertTrue($hasher->check('password', $value)); $this->assertFalse($hasher->needsRehash($value)); $this->assertTrue($hasher->needsRehash($value, ['threads' => 1])); + $this->assertSame('argon2i', password_get_info($value)['algoName']); + } + + public function testBasicArgon2idHashing() + { + if (! defined('PASSWORD_ARGON2ID')) { + $this->markTestSkipped('PHP not compiled with Argon2id hashing support.'); + } + + $hasher = new \Illuminate\Hashing\Argon2IdHasher; + $value = $hasher->make('password'); + $this->assertNotSame('password', $value); + $this->assertTrue($hasher->check('password', $value)); + $this->assertFalse($hasher->needsRehash($value)); + $this->assertTrue($hasher->needsRehash($value, ['threads' => 1])); + $this->assertSame('argon2id', password_get_info($value)['algoName']); } /** @@ -36,7 +53,7 @@ public function testBasicArgonHashing() public function testBasicBcryptVerification() { if (! defined('PASSWORD_ARGON2I')) { - $this->markTestSkipped('PHP not compiled with argon2 hashing support.'); + $this->markTestSkipped('PHP not compiled with Argon2i hashing support.'); } $argonHasher = new \Illuminate\Hashing\ArgonHasher; @@ -45,12 +62,22 @@ public function testBasicBcryptVerification() } /** - * @expectedException \Exception + * @expectedException \RuntimeException */ - public function testBasicArgonVerification() + public function testBasicArgon2iVerification() { $bcryptHasher = new \Illuminate\Hashing\BcryptHasher; $bcryptHashed = $bcryptHasher->make('password'); (new \Illuminate\Hashing\ArgonHasher)->check('password', $bcryptHashed); } + + /** + * @expectedException \RuntimeException + */ + public function testBasicArgon2idVerification() + { + $bcryptHasher = new \Illuminate\Hashing\BcryptHasher; + $bcryptHashed = $bcryptHasher->make('password'); + (new \Illuminate\Hashing\Argon2IdHasher)->check('password', $bcryptHashed); + } } From 7e0e431b454130325856197cc841c4d6ad97aff0 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 5 Aug 2018 08:22:32 -1000 Subject: [PATCH 0185/2459] formatting --- src/Illuminate/Hashing/Argon2IdHasher.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Hashing/Argon2IdHasher.php b/src/Illuminate/Hashing/Argon2IdHasher.php index 657f5842ff47..f3da9f74cb0d 100644 --- a/src/Illuminate/Hashing/Argon2IdHasher.php +++ b/src/Illuminate/Hashing/Argon2IdHasher.php @@ -6,16 +6,6 @@ class Argon2IdHasher extends ArgonHasher { - /** - * Get the algorithm that should be used for hashing. - * - * @return int - */ - protected function algorithm() - { - return PASSWORD_ARGON2ID; - } - /** * Check the given plain value against a hash. * @@ -36,4 +26,14 @@ public function check($value, $hashedValue, array $options = []) return password_verify($value, $hashedValue); } + + /** + * Get the algorithm that should be used for hashing. + * + * @return int + */ + protected function algorithm() + { + return PASSWORD_ARGON2ID; + } } From df7810aa2d7ae1d4b02fb80622eacf10b410554a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Till=20Kr=C3=BCss?= Date: Sun, 5 Aug 2018 11:24:38 -0700 Subject: [PATCH 0186/2459] [5.7] Remove dd() helper (#25087) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * use Symfony’s dd() helper * satisfy StyleCI --- src/Illuminate/Support/Collection.php | 4 +-- src/Illuminate/Support/Debug/Dumper.php | 26 ------------------ src/Illuminate/Support/Debug/HtmlDumper.php | 29 --------------------- src/Illuminate/Support/helpers.php | 18 ------------- 4 files changed, 2 insertions(+), 75 deletions(-) delete mode 100644 src/Illuminate/Support/Debug/Dumper.php delete mode 100644 src/Illuminate/Support/Debug/HtmlDumper.php diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 50dc627d32c5..c3b2fbd93a79 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -11,9 +11,9 @@ use CachingIterator; use JsonSerializable; use IteratorAggregate; -use Illuminate\Support\Debug\Dumper; use Illuminate\Support\Traits\Macroable; use Illuminate\Contracts\Support\Jsonable; +use Symfony\Component\VarDumper\VarDumper; use Illuminate\Contracts\Support\Arrayable; /** @@ -320,7 +320,7 @@ public function dump() (new static(func_get_args())) ->push($this) ->each(function ($item) { - (new Dumper)->dump($item); + VarDumper::dump($item); }); return $this; diff --git a/src/Illuminate/Support/Debug/Dumper.php b/src/Illuminate/Support/Debug/Dumper.php deleted file mode 100644 index 7442343f8097..000000000000 --- a/src/Illuminate/Support/Debug/Dumper.php +++ /dev/null @@ -1,26 +0,0 @@ -dump((new VarCloner)->cloneVar($value)); - } else { - var_dump($value); - } - } -} diff --git a/src/Illuminate/Support/Debug/HtmlDumper.php b/src/Illuminate/Support/Debug/HtmlDumper.php deleted file mode 100644 index 5825ac8dba7c..000000000000 --- a/src/Illuminate/Support/Debug/HtmlDumper.php +++ /dev/null @@ -1,29 +0,0 @@ - 'background-color:#fff; color:#222; line-height:1.2em; font-weight:normal; font:12px Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:100000', - 'num' => 'color:#a71d5d', - 'const' => 'color:#795da3', - 'str' => 'color:#df5000', - 'cchr' => 'color:#222', - 'note' => 'color:#a71d5d', - 'ref' => 'color:#a0a0a0', - 'public' => 'color:#795da3', - 'protected' => 'color:#795da3', - 'private' => 'color:#795da3', - 'meta' => 'color:#b729d9', - 'key' => 'color:#df5000', - 'index' => 'color:#a71d5d', - ]; -} diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 0fb3e75f84b4..6f28c148946e 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -4,7 +4,6 @@ use Illuminate\Support\Str; use Illuminate\Support\Optional; use Illuminate\Support\Collection; -use Illuminate\Support\Debug\Dumper; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\HigherOrderTapProxy; @@ -544,23 +543,6 @@ function data_set(&$target, $key, $value, $overwrite = true) } } -if (! function_exists('dd')) { - /** - * Dump the passed variables and end the script. - * - * @param mixed $args - * @return void - */ - function dd(...$args) - { - foreach ($args as $x) { - (new Dumper)->dump($x); - } - - die(1); - } -} - if (! function_exists('e')) { /** * Escape HTML special characters in a string. From 6cd81219122828b371ebdb216d17dbd6832a34b6 Mon Sep 17 00:00:00 2001 From: Derek MacDonald Date: Fri, 20 Jul 2018 23:58:50 -0400 Subject: [PATCH 0187/2459] Notifications can choose locale Queued notifications can run in a locale other than the application default. --- .../Notifications/ChannelManager.php | 24 ++- src/Illuminate/Notifications/Notification.php | 20 ++ .../Notifications/NotificationSender.php | 28 ++- .../Support/Facades/Notification.php | 1 + .../Testing/Fakes/NotificationFake.php | 21 ++ .../Notifications/Fixtures/greeting.blade.php | 1 + ...otificationsViaAnonymousNotifiableTest.php | 8 +- .../SendingNotificationsWithLocaleTest.php | 202 ++++++++++++++++++ 8 files changed, 295 insertions(+), 10 deletions(-) create mode 100644 tests/Integration/Notifications/Fixtures/greeting.blade.php create mode 100644 tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php diff --git a/src/Illuminate/Notifications/ChannelManager.php b/src/Illuminate/Notifications/ChannelManager.php index eb8c4f29d007..d8a8de735163 100644 --- a/src/Illuminate/Notifications/ChannelManager.php +++ b/src/Illuminate/Notifications/ChannelManager.php @@ -21,6 +21,13 @@ class ChannelManager extends Manager implements DispatcherContract, FactoryContr */ protected $defaultChannel = 'mail'; + /** + * Locale used when sending notifications. + * + * @var string|null + */ + protected $locale; + /** * Send the given notification to the given notifiable entities. * @@ -31,7 +38,7 @@ class ChannelManager extends Manager implements DispatcherContract, FactoryContr public function send($notifiables, $notification) { return (new NotificationSender( - $this, $this->app->make(Bus::class), $this->app->make(Dispatcher::class)) + $this, $this->app->make(Bus::class), $this->app->make(Dispatcher::class), $this->locale) )->send($notifiables, $notification); } @@ -46,7 +53,7 @@ public function send($notifiables, $notification) public function sendNow($notifiables, $notification, array $channels = null) { return (new NotificationSender( - $this, $this->app->make(Bus::class), $this->app->make(Dispatcher::class)) + $this, $this->app->make(Bus::class), $this->app->make(Dispatcher::class), $this->locale) )->sendNow($notifiables, $notification, $channels); } @@ -168,4 +175,17 @@ public function deliverVia($channel) { $this->defaultChannel = $channel; } + + /** + * Set the locale of notifications. + * + * @param string $locale + * @return $this + */ + public function locale($locale) + { + $this->locale = $locale; + + return $this; + } } diff --git a/src/Illuminate/Notifications/Notification.php b/src/Illuminate/Notifications/Notification.php index 9b258b7dc1f6..64f68e4c43bf 100644 --- a/src/Illuminate/Notifications/Notification.php +++ b/src/Illuminate/Notifications/Notification.php @@ -15,6 +15,13 @@ class Notification */ public $id; + /** + * Locale used when sending the notification. + * + * @var string|null + */ + public $locale; + /** * Get the channels the event should broadcast on. * @@ -24,4 +31,17 @@ public function broadcastOn() { return []; } + + /** + * Set the locale to send this notification in. + * + * @param string $locale + * @return $this + */ + public function locale($locale) + { + $this->locale = $locale; + + return $this; + } } diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index c9731fab77a4..cca14ae62cb3 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -5,11 +5,14 @@ use Illuminate\Support\Str; use Illuminate\Support\Collection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Traits\Localizable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Database\Eloquent\Collection as ModelCollection; class NotificationSender { + use Localizable; + /** * The notification manager instance. * @@ -31,19 +34,28 @@ class NotificationSender */ protected $events; + /** + * Locale used when sending notifications. + * + * @var string|null + */ + protected $locale; + /** * Create a new notification sender instance. * * @param \Illuminate\Notifications\ChannelManager $manager * @param \Illuminate\Contracts\Bus\Dispatcher $bus * @param \Illuminate\Contracts\Events\Dispatcher $events + * @param string|null $locale * @return void */ - public function __construct($manager, $bus, $events) + public function __construct($manager, $bus, $events, $locale = null) { $this->bus = $bus; $this->events = $events; $this->manager = $manager; + $this->locale = $locale; } /** @@ -83,11 +95,13 @@ public function sendNow($notifiables, $notification, array $channels = null) continue; } - $notificationId = Str::uuid()->toString(); + $this->withLocale($notification->locale ?? $this->locale, function () use ($viaChannels, $notifiable, $original) { + $notificationId = Str::uuid()->toString(); - foreach ((array) $viaChannels as $channel) { - $this->sendToNotifiable($notifiable, $notificationId, clone $original, $channel); - } + foreach ((array) $viaChannels as $channel) { + $this->sendToNotifiable($notifiable, $notificationId, clone $original, $channel); + } + }); } } @@ -153,6 +167,10 @@ protected function queueNotification($notifiables, $notification) $notification->id = $notificationId; + if (! is_null($this->locale)) { + $notification->locale = $this->locale; + } + $this->bus->dispatch( (new SendQueuedNotifications($notifiable, $notification, [$channel])) ->onConnection($notification->connection) diff --git a/src/Illuminate/Support/Facades/Notification.php b/src/Illuminate/Support/Facades/Notification.php index d13ec82ae30e..425520d852e3 100644 --- a/src/Illuminate/Support/Facades/Notification.php +++ b/src/Illuminate/Support/Facades/Notification.php @@ -10,6 +10,7 @@ * @method static void send(\Illuminate\Support\Collection|array|mixed $notifiables, $notification) * @method static void sendNow(\Illuminate\Support\Collection|array|mixed $notifiables, $notification) * @method static mixed channel(string|null $name = null) + * @method static \Illuminate\Notifications\ChannelManager locale(string|null $locale) * * @see \Illuminate\Notifications\ChannelManager */ diff --git a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php index 8093a4fb7968..72b6ab9bab38 100644 --- a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php +++ b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php @@ -17,6 +17,13 @@ class NotificationFake implements NotificationFactory, NotificationDispatcher */ protected $notifications = []; + /** + * Locale used when sending notifications. + * + * @var string|null + */ + public $locale; + /** * Assert if a notification was sent based on a truth-test callback. * @@ -203,6 +210,7 @@ public function sendNow($notifiables, $notification) 'notification' => $notification, 'channels' => $notification->via($notifiable), 'notifiable' => $notifiable, + 'locale' => $notification->locale ?? $this->locale, ]; } } @@ -217,4 +225,17 @@ public function channel($name = null) { // } + + /** + * Set the locale of notifications. + * + * @param string $locale + * @return $this + */ + public function locale($locale) + { + $this->locale = $locale; + + return $this; + } } diff --git a/tests/Integration/Notifications/Fixtures/greeting.blade.php b/tests/Integration/Notifications/Fixtures/greeting.blade.php new file mode 100644 index 000000000000..1eceadd36906 --- /dev/null +++ b/tests/Integration/Notifications/Fixtures/greeting.blade.php @@ -0,0 +1 @@ +{{ __('hi') }} diff --git a/tests/Integration/Notifications/SendingNotificationsViaAnonymousNotifiableTest.php b/tests/Integration/Notifications/SendingNotificationsViaAnonymousNotifiableTest.php index 153d60dd6c1f..ab9235ea756b 100644 --- a/tests/Integration/Notifications/SendingNotificationsViaAnonymousNotifiableTest.php +++ b/tests/Integration/Notifications/SendingNotificationsViaAnonymousNotifiableTest.php @@ -46,14 +46,16 @@ public function test_faking() ->route('testchannel', 'enzo') ->route('anothertestchannel', 'enzo@deepblue.com'); - NotificationFacade::send( + NotificationFacade::locale('it')->send( $notifiable, new TestMailNotificationForAnonymousNotifiable() ); NotificationFacade::assertSentTo(new AnonymousNotifiable(), TestMailNotificationForAnonymousNotifiable::class, - function ($notification, $channels, $notifiable) { - return $notifiable->routes['testchannel'] == 'enzo' && $notifiable->routes['anothertestchannel'] == 'enzo@deepblue.com'; + function ($notification, $channels, $notifiable, $locale) { + return $notifiable->routes['testchannel'] === 'enzo' && + $notifiable->routes['anothertestchannel'] === 'enzo@deepblue.com' && + $locale === 'it'; } ); } diff --git a/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php b/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php new file mode 100644 index 000000000000..741249e51717 --- /dev/null +++ b/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php @@ -0,0 +1,202 @@ +set('app.debug', 'true'); + + $app['config']->set('mail.driver', 'array'); + + $app['config']->set('app.locale', 'en'); + + $app['config']->set('database.default', 'testbench'); + + $app['config']->set('database.connections.testbench', [ + 'driver' => 'sqlite', + 'database' => ':memory:', + 'prefix' => '', + ]); + + View::addLocation(__DIR__.'/Fixtures'); + + app('translator')->setLoaded([ + '*' => [ + '*' => [ + 'en' => ['hi' => 'hello'], + 'fr' => ['hi' => 'bonjour'], + ], + ], + ]); + } + + public function setUp() + { + parent::setUp(); + + Schema::create('users', function ($table) { + $table->increments('id'); + $table->string('email'); + $table->string('name')->nullable(); + }); + } + + public function test_mail_is_sent_with_default_locale() + { + $user = NotifiableLocalizedUser::forceCreate([ + 'email' => 'taylor@laravel.com', + 'name' => 'Taylor Otwell', + ]); + + NotificationFacade::send($user, new GreetingMailNotification); + + $this->assertContains('hello', + app('swift.transport')->messages()[0]->getBody() + ); + } + + public function test_mail_is_sent_with_facade_selected_locale() + { + $user = NotifiableLocalizedUser::forceCreate([ + 'email' => 'taylor@laravel.com', + 'name' => 'Taylor Otwell', + ]); + + NotificationFacade::locale('fr')->send($user, new GreetingMailNotification); + + $this->assertContains('bonjour', + app('swift.transport')->messages()[0]->getBody() + ); + } + + public function test_mail_is_sent_with_notification_selected_locale() + { + $users = [ + NotifiableLocalizedUser::forceCreate([ + 'email' => 'taylor@laravel.com', + 'name' => 'Taylor Otwell', + ]), + NotifiableLocalizedUser::forceCreate([ + 'email' => 'mohamed@laravel.com', + 'name' => 'Mohamed Said', + ]), + ]; + + NotificationFacade::send($users, (new GreetingMailNotification())->locale('fr')); + + $this->assertContains('bonjour', + app('swift.transport')->messages()[0]->getBody() + ); + + $this->assertContains('bonjour', + app('swift.transport')->messages()[1]->getBody() + ); + } + + public function test_mailable_is_sent_with_selected_locale() + { + $user = NotifiableLocalizedUser::forceCreate([ + 'email' => 'taylor@laravel.com', + 'name' => 'Taylor Otwell', + ]); + + NotificationFacade::locale('fr')->send($user, new GreetingMailNotificationWithMailable); + + $this->assertContains('bonjour', + app('swift.transport')->messages()[0]->getBody() + ); + } + + public function test_mail_is_sent_with_locale_updated_listeners_called() + { + Carbon::setTestNow(Carbon::parse('2018-07-25')); + + Event::listen(LocaleUpdated::class, function ($event) { + Carbon::setLocale($event->locale); + }); + + $user = NotifiableLocalizedUser::forceCreate([ + 'email' => 'taylor@laravel.com', + 'name' => 'Taylor Otwell', + ]); + + $user->notify((new GreetingMailNotification())->locale('fr')); + + $this->assertContains('bonjour', + app('swift.transport')->messages()[0]->getBody() + ); + + $this->assertContains('dans 1 jour', + app('swift.transport')->messages()[0]->getBody() + ); + + $this->assertTrue($this->app->isLocale('en')); + + $this->assertSame('en', Carbon::getLocale()); + } +} + +class NotifiableLocalizedUser extends Model +{ + use Notifiable; + + public $table = 'users'; + public $timestamps = false; +} + +class GreetingMailNotification extends Notification +{ + public function via($notifiable) + { + return [MailChannel::class]; + } + + public function toMail($notifiable) + { + return (new MailMessage) + ->greeting(__('hi')) + ->line(Carbon::tomorrow()->diffForHumans()); + } +} + +class GreetingMailNotificationWithMailable extends Notification +{ + public function via($notifiable) + { + return [MailChannel::class]; + } + + public function toMail($notifiable) + { + return new GreetingMailable; + } +} + +class GreetingMailable extends Mailable +{ + public function build() + { + return $this->view('greeting'); + } +} From a09b0e377ff1cf2b68a0c9bb87e8dfba21f34c51 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 5 Aug 2018 17:25:51 -1000 Subject: [PATCH 0188/2459] use 301 redirect --- src/Illuminate/Routing/Router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 24c6b8c7e0ef..c83473e44c84 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -236,7 +236,7 @@ public function fallback($action) * @param int $status * @return \Illuminate\Routing\Route */ - public function redirect($uri, $destination, $status = 302) + public function redirect($uri, $destination, $status = 301) { return $this->any($uri, '\Illuminate\Routing\RedirectController') ->defaults('destination', $destination) From 4910bdc7df9b72b55f19989716801545fbee9319 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 6 Aug 2018 17:46:28 +0200 Subject: [PATCH 0189/2459] allow to customize amount of links on each side --- .../Pagination/AbstractPaginator.php | 41 +++++++++++++++++++ .../Pagination/LengthAwarePaginator.php | 2 +- src/Illuminate/Pagination/UrlWindow.php | 10 ++--- tests/Pagination/UrlWindowTest.php | 19 +++++++++ 4 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index ac4ae13424b7..472025a61dcd 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -41,6 +41,13 @@ abstract class AbstractPaginator implements Htmlable */ protected $path = '/'; + /** + * The number of links to display on each side of current page link. + * + * @var int + */ + protected $onEachSide = 3; + /** * The query parameters to add to all URLs. * @@ -342,6 +349,40 @@ public function setPageName($name) return $this; } + /** + * Set the number of links to display on each side of current page link + * + * @param int $amount + * @return this + */ + public function linksOnEachSide($amount) + { + return $this->setOnEachSide($amount); + } + + /** + * Get the number of links to display on each side of current page link + * + * @return int + */ + public function getOnEachSide() + { + return $this->onEachSide; + } + + /** + * Set the number of links to display on each side of current page link + * + * @param int $amount + * @return $this + */ + public function setOnEachSide($amount) + { + $this->onEachSide = $amount; + + return $this; + } + /** * Set the base path to assign to all URLs. * diff --git a/src/Illuminate/Pagination/LengthAwarePaginator.php b/src/Illuminate/Pagination/LengthAwarePaginator.php index 5a7094eafba6..bb49f8cc705f 100644 --- a/src/Illuminate/Pagination/LengthAwarePaginator.php +++ b/src/Illuminate/Pagination/LengthAwarePaginator.php @@ -100,7 +100,7 @@ public function render($view = null, $data = []) */ protected function elements() { - $window = UrlWindow::make($this); + $window = UrlWindow::make($this, $this->onEachSide); return array_filter([ $window['first'], diff --git a/src/Illuminate/Pagination/UrlWindow.php b/src/Illuminate/Pagination/UrlWindow.php index 6ec0b0c9d3eb..314047697651 100644 --- a/src/Illuminate/Pagination/UrlWindow.php +++ b/src/Illuminate/Pagination/UrlWindow.php @@ -28,22 +28,22 @@ public function __construct(PaginatorContract $paginator) * Create a new URL window instance. * * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator - * @param int $onEachSide * @return array */ - public static function make(PaginatorContract $paginator, $onEachSide = 3) + public static function make(PaginatorContract $paginator) { - return (new static($paginator))->get($onEachSide); + return (new static($paginator))->get(); } /** * Get the window of URLs to be shown. * - * @param int $onEachSide * @return array */ - public function get($onEachSide = 3) + public function get() { + $onEachSide = $this->paginator->getOnEachSide(); + if ($this->paginator->lastPage() < ($onEachSide * 2) + 6) { return $this->getSmallSlider(); } diff --git a/tests/Pagination/UrlWindowTest.php b/tests/Pagination/UrlWindowTest.php index 3aedd72cf69a..0cb7319d7b2b 100644 --- a/tests/Pagination/UrlWindowTest.php +++ b/tests/Pagination/UrlWindowTest.php @@ -49,4 +49,23 @@ public function testPresenterCanGetAUrlRangeForAWindowOfLinks() $this->assertEquals(['first' => [1 => '/?page=1', 2 => '/?page=2'], 'slider' => null, 'last' => $last], $window->get()); } + + public function testCustomUrlRangeForAWindowOfLinks() + { + $array = []; + for ($i = 1; $i <= 13; $i++) { + $array[$i] = 'item'.$i; + } + + $p = new LengthAwarePaginator($array, count($array), 1, 8); + $p->linksOnEachSide(1); + $window = new UrlWindow($p); + + $slider = []; + for ($i = 7; $i <= 9; $i++) { + $slider[$i] = '/?page='.$i; + } + + $this->assertEquals(['first' => [1 => '/?page=1', 2 => '/?page=2'], 'slider' => $slider, 'last' => [12 => '/?page=12', 13 => '/?page=13']], $window->get()); + } } From 755e6428d3e32b37809bcc97f2bd307d4e15f239 Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 6 Aug 2018 18:11:32 +0200 Subject: [PATCH 0190/2459] style --- src/Illuminate/Pagination/AbstractPaginator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index 472025a61dcd..d81a50b2b028 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -350,7 +350,7 @@ public function setPageName($name) } /** - * Set the number of links to display on each side of current page link + * Set the number of links to display on each side of current page link. * * @param int $amount * @return this @@ -361,7 +361,7 @@ public function linksOnEachSide($amount) } /** - * Get the number of links to display on each side of current page link + * Get the number of links to display on each side of current page link. * * @return int */ @@ -371,7 +371,7 @@ public function getOnEachSide() } /** - * Set the number of links to display on each side of current page link + * Set the number of links to display on each side of current page link. * * @param int $amount * @return $this From 30ed900ebbdd8840a64c390b94fda8c9288d22ad Mon Sep 17 00:00:00 2001 From: Michal Date: Mon, 6 Aug 2018 18:37:06 +0200 Subject: [PATCH 0191/2459] fix --- src/Illuminate/Pagination/LengthAwarePaginator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Pagination/LengthAwarePaginator.php b/src/Illuminate/Pagination/LengthAwarePaginator.php index bb49f8cc705f..5a7094eafba6 100644 --- a/src/Illuminate/Pagination/LengthAwarePaginator.php +++ b/src/Illuminate/Pagination/LengthAwarePaginator.php @@ -100,7 +100,7 @@ public function render($view = null, $data = []) */ protected function elements() { - $window = UrlWindow::make($this, $this->onEachSide); + $window = UrlWindow::make($this); return array_filter([ $window['first'], From aabc4d62a8d7b37a38acfe68b8b0d6b49ed55065 Mon Sep 17 00:00:00 2001 From: Jeff Puckett Date: Mon, 6 Aug 2018 18:16:13 +0000 Subject: [PATCH 0192/2459] fix #24914 die with unsuccessful return code (#25111) --- .../Foundation/Bootstrap/LoadEnvironmentVariables.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php b/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php index 599c474c174b..6eeb73504ac8 100644 --- a/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php +++ b/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php @@ -29,7 +29,8 @@ public function bootstrap(Application $app) } catch (InvalidPathException $e) { // } catch (InvalidFileException $e) { - die('The environment file is invalid: '.$e->getMessage()); + echo 'The environment file is invalid: '.$e->getMessage(); + die(1); } } From 55afaaa248d2e7092f99963762150f397fbbaba3 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Mon, 6 Aug 2018 14:23:48 -0400 Subject: [PATCH 0193/2459] Allow guests in authorize middleware (#25109) --- src/Illuminate/Auth/Middleware/Authorize.php | 14 +------------- tests/Auth/AuthorizeMiddlewareTest.php | 10 +--------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/Illuminate/Auth/Middleware/Authorize.php b/src/Illuminate/Auth/Middleware/Authorize.php index 0993b3b4cd36..331edc120b41 100644 --- a/src/Illuminate/Auth/Middleware/Authorize.php +++ b/src/Illuminate/Auth/Middleware/Authorize.php @@ -5,17 +5,9 @@ use Closure; use Illuminate\Database\Eloquent\Model; use Illuminate\Contracts\Auth\Access\Gate; -use Illuminate\Contracts\Auth\Factory as Auth; class Authorize { - /** - * The authentication factory instance. - * - * @var \Illuminate\Contracts\Auth\Factory - */ - protected $auth; - /** * The gate instance. * @@ -26,13 +18,11 @@ class Authorize /** * Create a new middleware instance. * - * @param \Illuminate\Contracts\Auth\Factory $auth * @param \Illuminate\Contracts\Auth\Access\Gate $gate * @return void */ - public function __construct(Auth $auth, Gate $gate) + public function __construct(Gate $gate) { - $this->auth = $auth; $this->gate = $gate; } @@ -50,8 +40,6 @@ public function __construct(Auth $auth, Gate $gate) */ public function handle($request, Closure $next, $ability, ...$models) { - $this->auth->authenticate(); - $this->gate->authorize($ability, $this->getGateArguments($request, $models)); return $next($request); diff --git a/tests/Auth/AuthorizeMiddlewareTest.php b/tests/Auth/AuthorizeMiddlewareTest.php index ef1094d657da..4a5986d4ab52 100644 --- a/tests/Auth/AuthorizeMiddlewareTest.php +++ b/tests/Auth/AuthorizeMiddlewareTest.php @@ -12,7 +12,6 @@ use Illuminate\Container\Container; use Illuminate\Auth\Middleware\Authorize; use Illuminate\Contracts\Routing\Registrar; -use Illuminate\Contracts\Auth\Factory as Auth; use Illuminate\Routing\Middleware\SubstituteBindings; use Illuminate\Contracts\Auth\Access\Gate as GateContract; @@ -34,13 +33,6 @@ public function setUp() Container::setInstance($this->container = new Container); - $this->container->singleton(Auth::class, function () { - $auth = m::mock(Auth::class); - $auth->shouldReceive('authenticate')->once()->andReturn(null); - - return $auth; - }); - $this->container->singleton(GateContract::class, function () { return new Gate($this->container, function () { return $this->user; @@ -208,7 +200,7 @@ public function testModelInstanceAsParameter() $nextParam = $param; }; - (new Authorize($this->container->make(Auth::class), $this->gate())) + (new Authorize($this->gate())) ->handle($request, $next, 'success', $instance); } From 08f8456711b378168b5e4a671f5230a2f5440961 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 6 Aug 2018 08:29:46 -1000 Subject: [PATCH 0194/2459] formatting --- .../Pagination/AbstractPaginator.php | 61 ++++++------------- src/Illuminate/Pagination/UrlWindow.php | 2 +- tests/Pagination/UrlWindowTest.php | 2 +- 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index d81a50b2b028..6cef61d7e51e 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -41,13 +41,6 @@ abstract class AbstractPaginator implements Htmlable */ protected $path = '/'; - /** - * The number of links to display on each side of current page link. - * - * @var int - */ - protected $onEachSide = 3; - /** * The query parameters to add to all URLs. * @@ -69,6 +62,13 @@ abstract class AbstractPaginator implements Htmlable */ protected $pageName = 'page'; + /** + * The number of links to display on each side of current page link. + * + * @var int + */ + public $onEachSide = 3; + /** * The current path resolver callback. * @@ -349,40 +349,6 @@ public function setPageName($name) return $this; } - /** - * Set the number of links to display on each side of current page link. - * - * @param int $amount - * @return this - */ - public function linksOnEachSide($amount) - { - return $this->setOnEachSide($amount); - } - - /** - * Get the number of links to display on each side of current page link. - * - * @return int - */ - public function getOnEachSide() - { - return $this->onEachSide; - } - - /** - * Set the number of links to display on each side of current page link. - * - * @param int $amount - * @return $this - */ - public function setOnEachSide($amount) - { - $this->onEachSide = $amount; - - return $this; - } - /** * Set the base path to assign to all URLs. * @@ -407,6 +373,19 @@ public function setPath($path) return $this; } + /** + * Set the number of links to display on each side of current page link. + * + * @param int $count + * @return this + */ + public function onEachSide($count) + { + $this->onEachSide = $count; + + return $this; + } + /** * Resolve the current request path or return the default value. * diff --git a/src/Illuminate/Pagination/UrlWindow.php b/src/Illuminate/Pagination/UrlWindow.php index 314047697651..0fd3aa8230b4 100644 --- a/src/Illuminate/Pagination/UrlWindow.php +++ b/src/Illuminate/Pagination/UrlWindow.php @@ -42,7 +42,7 @@ public static function make(PaginatorContract $paginator) */ public function get() { - $onEachSide = $this->paginator->getOnEachSide(); + $onEachSide = $this->paginator->onEachSide; if ($this->paginator->lastPage() < ($onEachSide * 2) + 6) { return $this->getSmallSlider(); diff --git a/tests/Pagination/UrlWindowTest.php b/tests/Pagination/UrlWindowTest.php index 0cb7319d7b2b..a598728c86ef 100644 --- a/tests/Pagination/UrlWindowTest.php +++ b/tests/Pagination/UrlWindowTest.php @@ -58,7 +58,7 @@ public function testCustomUrlRangeForAWindowOfLinks() } $p = new LengthAwarePaginator($array, count($array), 1, 8); - $p->linksOnEachSide(1); + $p->onEachSide(1); $window = new UrlWindow($p); $slider = []; From a0b4d25c1b795cd81cacda1a1407ecc191151c4c Mon Sep 17 00:00:00 2001 From: Alfonso Bribiesca Date: Mon, 6 Aug 2018 13:30:49 -0500 Subject: [PATCH 0195/2459] Add absolute parameter to signed routes (#25107) --- src/Illuminate/Routing/UrlGenerator.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index f446fb959341..98446c8d4f62 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -301,9 +301,10 @@ public function formatScheme($secure = null) * @param string $name * @param array $parameters * @param \DateTimeInterface|int $expiration + * @param bool $absolute * @return string */ - public function signedRoute($name, $parameters = [], $expiration = null) + public function signedRoute($name, $parameters = [], $expiration = null, $absolute = true) { $parameters = $this->formatParameters($parameters); @@ -317,7 +318,7 @@ public function signedRoute($name, $parameters = [], $expiration = null) return $this->route($name, $parameters + [ 'signature' => hash_hmac('sha256', $this->route($name, $parameters), $key), - ]); + ], $absolute); } /** @@ -326,11 +327,12 @@ public function signedRoute($name, $parameters = [], $expiration = null) * @param string $name * @param \DateTimeInterface|int $expiration * @param array $parameters + * @param bool $absolute * @return string */ - public function temporarySignedRoute($name, $expiration, $parameters = []) + public function temporarySignedRoute($name, $expiration, $parameters = [], $absolute = true) { - return $this->signedRoute($name, $parameters, $expiration); + return $this->signedRoute($name, $parameters, $expiration, $absolute); } /** From 8b7ec89969955cd38ee028da0e144f9deb550267 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 6 Aug 2018 08:46:10 -1000 Subject: [PATCH 0196/2459] formatting --- src/Illuminate/Log/LogManager.php | 2 +- src/Illuminate/Log/LoggerConfiguration.php | 66 ---------------------- 2 files changed, 1 insertion(+), 67 deletions(-) delete mode 100644 src/Illuminate/Log/LoggerConfiguration.php diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 66e3eb65c328..d49c4bac9aaf 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -18,7 +18,7 @@ class LogManager implements LoggerInterface { - use LoggerConfiguration; + use ParsesLogConfiguration; /** * The application instance. diff --git a/src/Illuminate/Log/LoggerConfiguration.php b/src/Illuminate/Log/LoggerConfiguration.php deleted file mode 100644 index da1deaa4e0e7..000000000000 --- a/src/Illuminate/Log/LoggerConfiguration.php +++ /dev/null @@ -1,66 +0,0 @@ - Monolog::DEBUG, - 'info' => Monolog::INFO, - 'notice' => Monolog::NOTICE, - 'warning' => Monolog::WARNING, - 'error' => Monolog::ERROR, - 'critical' => Monolog::CRITICAL, - 'alert' => Monolog::ALERT, - 'emergency' => Monolog::EMERGENCY, - ]; - - /** - * Parse the string level into a Monolog constant. - * - * @param array $config - * @return int - * - * @throws \InvalidArgumentException - */ - protected function level(array $config) - { - $level = $config['level'] ?? 'debug'; - - if (isset($this->levels[$level])) { - return $this->levels[$level]; - } - - throw new InvalidArgumentException('Invalid log level.'); - } - - /** - * Extract the log channel from the given configuration. - * - * @param array $config - * @return string - */ - protected function parseChannel(array $config) - { - if (! isset($config['name'])) { - return $this->getFallbackChannelName(); - } - - return $config['name']; - } - - /** - * Get fallback log channel name. - * - * @return string - */ - abstract protected function getFallbackChannelName(); -} From b49f6381114116d6153558815bca2dc9e1e78d24 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 6 Aug 2018 08:46:16 -1000 Subject: [PATCH 0197/2459] formatting --- src/Illuminate/Log/ParsesLogConfiguration.php | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 src/Illuminate/Log/ParsesLogConfiguration.php diff --git a/src/Illuminate/Log/ParsesLogConfiguration.php b/src/Illuminate/Log/ParsesLogConfiguration.php new file mode 100644 index 000000000000..ebcb21d060ef --- /dev/null +++ b/src/Illuminate/Log/ParsesLogConfiguration.php @@ -0,0 +1,66 @@ + Monolog::DEBUG, + 'info' => Monolog::INFO, + 'notice' => Monolog::NOTICE, + 'warning' => Monolog::WARNING, + 'error' => Monolog::ERROR, + 'critical' => Monolog::CRITICAL, + 'alert' => Monolog::ALERT, + 'emergency' => Monolog::EMERGENCY, + ]; + + /** + * Get fallback log channel name. + * + * @return string + */ + abstract protected function getFallbackChannelName(); + + /** + * Parse the string level into a Monolog constant. + * + * @param array $config + * @return int + * + * @throws \InvalidArgumentException + */ + protected function level(array $config) + { + $level = $config['level'] ?? 'debug'; + + if (isset($this->levels[$level])) { + return $this->levels[$level]; + } + + throw new InvalidArgumentException('Invalid log level.'); + } + + /** + * Extract the log channel from the given configuration. + * + * @param array $config + * @return string + */ + protected function parseChannel(array $config) + { + if (! isset($config['name'])) { + return $this->getFallbackChannelName(); + } + + return $config['name']; + } +} From 2104d867fd5a14753a01bec2603da0044fefa17e Mon Sep 17 00:00:00 2001 From: Zak Nesler <7189795+zaknesler@users.noreply.github.com> Date: Mon, 6 Aug 2018 15:58:35 -0400 Subject: [PATCH 0198/2459] Flatten preset asset directories (#25112) --- src/Illuminate/Foundation/Console/Presets/Bootstrap.php | 4 ++-- src/Illuminate/Foundation/Console/Presets/None.php | 8 ++++---- src/Illuminate/Foundation/Console/Presets/Preset.php | 2 +- src/Illuminate/Foundation/Console/Presets/React.php | 6 +++--- src/Illuminate/Foundation/Console/Presets/Vue.php | 6 +++--- .../Foundation/Console/Presets/react-stubs/webpack.mix.js | 4 ++-- .../Foundation/Console/Presets/vue-stubs/webpack.mix.js | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Foundation/Console/Presets/Bootstrap.php b/src/Illuminate/Foundation/Console/Presets/Bootstrap.php index 93c561828a52..248e2f29d446 100644 --- a/src/Illuminate/Foundation/Console/Presets/Bootstrap.php +++ b/src/Illuminate/Foundation/Console/Presets/Bootstrap.php @@ -38,7 +38,7 @@ protected static function updatePackageArray(array $packages) */ protected static function updateSass() { - copy(__DIR__.'/bootstrap-stubs/_variables.scss', resource_path('assets/sass/_variables.scss')); - copy(__DIR__.'/bootstrap-stubs/app.scss', resource_path('assets/sass/app.scss')); + copy(__DIR__.'/bootstrap-stubs/_variables.scss', resource_path('sass/_variables.scss')); + copy(__DIR__.'/bootstrap-stubs/app.scss', resource_path('sass/app.scss')); } } diff --git a/src/Illuminate/Foundation/Console/Presets/None.php b/src/Illuminate/Foundation/Console/Presets/None.php index 77d7f5b7ffc3..901471aa709f 100644 --- a/src/Illuminate/Foundation/Console/Presets/None.php +++ b/src/Illuminate/Foundation/Console/Presets/None.php @@ -17,8 +17,8 @@ public static function install() static::updateBootstrapping(); tap(new Filesystem, function ($filesystem) { - $filesystem->deleteDirectory(resource_path('assets/js/components')); - $filesystem->delete(resource_path('assets/sass/_variables.scss')); + $filesystem->deleteDirectory(resource_path('js/components')); + $filesystem->delete(resource_path('sass/_variables.scss')); $filesystem->deleteDirectory(base_path('node_modules')); $filesystem->deleteDirectory(public_path('css')); $filesystem->deleteDirectory(public_path('js')); @@ -53,7 +53,7 @@ protected static function updatePackageArray(array $packages) */ protected static function updateBootstrapping() { - file_put_contents(resource_path('assets/sass/app.scss'), ''.PHP_EOL); - copy(__DIR__.'/none-stubs/app.js', resource_path('assets/js/app.js')); + file_put_contents(resource_path('sass/app.scss'), ''.PHP_EOL); + copy(__DIR__.'/none-stubs/app.js', resource_path('js/app.js')); } } diff --git a/src/Illuminate/Foundation/Console/Presets/Preset.php b/src/Illuminate/Foundation/Console/Presets/Preset.php index e837cffe0cbb..99af6b6f4571 100644 --- a/src/Illuminate/Foundation/Console/Presets/Preset.php +++ b/src/Illuminate/Foundation/Console/Presets/Preset.php @@ -15,7 +15,7 @@ protected static function ensureComponentDirectoryExists() { $filesystem = new Filesystem; - if (! $filesystem->isDirectory($directory = resource_path('assets/js/components'))) { + if (! $filesystem->isDirectory($directory = resource_path('js/components'))) { $filesystem->makeDirectory($directory, 0755, true); } } diff --git a/src/Illuminate/Foundation/Console/Presets/React.php b/src/Illuminate/Foundation/Console/Presets/React.php index 347de5fa1580..e7f3b3b61e24 100644 --- a/src/Illuminate/Foundation/Console/Presets/React.php +++ b/src/Illuminate/Foundation/Console/Presets/React.php @@ -55,12 +55,12 @@ protected static function updateWebpackConfiguration() protected static function updateComponent() { (new Filesystem)->delete( - resource_path('assets/js/components/ExampleComponent.vue') + resource_path('js/components/ExampleComponent.vue') ); copy( __DIR__.'/react-stubs/Example.js', - resource_path('assets/js/components/Example.js') + resource_path('js/components/Example.js') ); } @@ -71,6 +71,6 @@ protected static function updateComponent() */ protected static function updateBootstrapping() { - copy(__DIR__.'/react-stubs/app.js', resource_path('assets/js/app.js')); + copy(__DIR__.'/react-stubs/app.js', resource_path('js/app.js')); } } diff --git a/src/Illuminate/Foundation/Console/Presets/Vue.php b/src/Illuminate/Foundation/Console/Presets/Vue.php index 5a85dafdd671..2b3aaf61c61a 100644 --- a/src/Illuminate/Foundation/Console/Presets/Vue.php +++ b/src/Illuminate/Foundation/Console/Presets/Vue.php @@ -55,12 +55,12 @@ protected static function updateWebpackConfiguration() protected static function updateComponent() { (new Filesystem)->delete( - resource_path('assets/js/components/Example.js') + resource_path('js/components/Example.js') ); copy( __DIR__.'/vue-stubs/ExampleComponent.vue', - resource_path('assets/js/components/ExampleComponent.vue') + resource_path('js/components/ExampleComponent.vue') ); } @@ -71,6 +71,6 @@ protected static function updateComponent() */ protected static function updateBootstrapping() { - copy(__DIR__.'/vue-stubs/app.js', resource_path('assets/js/app.js')); + copy(__DIR__.'/vue-stubs/app.js', resource_path('js/app.js')); } } diff --git a/src/Illuminate/Foundation/Console/Presets/react-stubs/webpack.mix.js b/src/Illuminate/Foundation/Console/Presets/react-stubs/webpack.mix.js index 291598ad9476..4e045882c037 100644 --- a/src/Illuminate/Foundation/Console/Presets/react-stubs/webpack.mix.js +++ b/src/Illuminate/Foundation/Console/Presets/react-stubs/webpack.mix.js @@ -11,5 +11,5 @@ let mix = require('laravel-mix'); | */ -mix.react('resources/assets/js/app.js', 'public/js') - .sass('resources/assets/sass/app.scss', 'public/css'); +mix.react('resources/js/app.js', 'public/js') + .sass('resources/sass/app.scss', 'public/css'); diff --git a/src/Illuminate/Foundation/Console/Presets/vue-stubs/webpack.mix.js b/src/Illuminate/Foundation/Console/Presets/vue-stubs/webpack.mix.js index 72fdbb16d60b..20141cdbc6a2 100644 --- a/src/Illuminate/Foundation/Console/Presets/vue-stubs/webpack.mix.js +++ b/src/Illuminate/Foundation/Console/Presets/vue-stubs/webpack.mix.js @@ -11,5 +11,5 @@ let mix = require('laravel-mix'); | */ -mix.js('resources/assets/js/app.js', 'public/js') - .sass('resources/assets/sass/app.scss', 'public/css'); +mix.js('resources/js/app.js', 'public/js') + .sass('resources/sass/app.scss', 'public/css'); From 157a15080b95b26b2ccb0677dceab4964e25f18d Mon Sep 17 00:00:00 2001 From: Marco Deleu Date: Mon, 6 Aug 2018 22:51:14 +0200 Subject: [PATCH 0199/2459] Allow daemon to stop when there is no more jobs in the queue --- src/Illuminate/Queue/Worker.php | 7 ++-- src/Illuminate/Queue/WorkerOptions.php | 11 +++++- tests/Queue/QueueWorkerTest.php | 48 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 3d3ab0508a12..771035fa7a29 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -123,7 +123,7 @@ public function daemon($connectionName, $queue, WorkerOptions $options) // Finally, we will check to see if we have exceeded our memory limits or if // the queue should restart based on other indications. If so, we'll stop // this worker and let whatever is "monitoring" it restart the process. - $this->stopIfNecessary($options, $lastRestart); + $this->stopIfNecessary($options, $lastRestart, $job); } } @@ -195,16 +195,17 @@ protected function pauseWorker(WorkerOptions $options, $lastRestart) * @param \Illuminate\Queue\WorkerOptions $options * @param int $lastRestart */ - protected function stopIfNecessary(WorkerOptions $options, $lastRestart) + protected function stopIfNecessary(WorkerOptions $options, $lastRestart, $job = null) { if ($this->shouldQuit) { $this->kill(); } - if ($this->memoryExceeded($options->memory)) { $this->stop(12); } elseif ($this->queueShouldRestart($lastRestart)) { $this->stop(); + } elseif ($options->stopOnEmptyQueue && is_null($job)) { + $this->stop(); } } diff --git a/src/Illuminate/Queue/WorkerOptions.php b/src/Illuminate/Queue/WorkerOptions.php index 3549f4414c8f..22f2a0298206 100644 --- a/src/Illuminate/Queue/WorkerOptions.php +++ b/src/Illuminate/Queue/WorkerOptions.php @@ -46,6 +46,14 @@ class WorkerOptions */ public $force; + /** + * Indicates if the worker should stop when queue is empty. + * + * @var bool + */ + public $stopOnEmptyQueue; + + /** * Create a new worker options instance. * @@ -57,7 +65,7 @@ class WorkerOptions * @param bool $force * @return void */ - public function __construct($delay = 0, $memory = 128, $timeout = 60, $sleep = 3, $maxTries = 0, $force = false) + public function __construct($delay = 0, $memory = 128, $timeout = 60, $sleep = 3, $maxTries = 0, $force = false, $stopOnEmptyQueue = false) { $this->delay = $delay; $this->sleep = $sleep; @@ -65,5 +73,6 @@ public function __construct($delay = 0, $memory = 128, $timeout = 60, $sleep = 3 $this->memory = $memory; $this->timeout = $timeout; $this->maxTries = $maxTries; + $this->stopOnEmptyQueue = $stopOnEmptyQueue; } } diff --git a/tests/Queue/QueueWorkerTest.php b/tests/Queue/QueueWorkerTest.php index e0bd890edd67..b27294cd1f7c 100755 --- a/tests/Queue/QueueWorkerTest.php +++ b/tests/Queue/QueueWorkerTest.php @@ -46,6 +46,32 @@ public function test_job_can_be_fired() $this->events->shouldHaveReceived('dispatch')->with(Mockery::type(JobProcessed::class))->once(); } + public function test_worker_can_work_until_queue_is_empty() + { + $workerOptions = new WorkerOptions; + $workerOptions->stopOnEmptyQueue = true; + + $worker = $this->getWorker('default', ['queue' => [ + $firstJob = new WorkerFakeJob, + $secondJob = new WorkerFakeJob, + ]]); + + $this->expectException(LoopBreakerException::class); + + $worker->daemon('default', 'queue', $workerOptions); + + $this->assertTrue($firstJob->fired); + + $this->assertTrue($secondJob->fired); + + $this->assertSame(0, $worker->stoppedWithStatus); + + $this->events->shouldHaveReceived('dispatch')->with(Mockery::type(JobProcessing::class))->twice(); + + $this->events->shouldHaveReceived('dispatch')->with(Mockery::type(JobProcessed::class))->twice(); + } + + public function test_job_can_be_fired_based_on_priority() { $worker = $this->getWorker('default', [ @@ -262,6 +288,18 @@ public function sleep($seconds) { $this->sleptFor = $seconds; } + + public function stop($status = 0) + { + $this->stoppedWithStatus = $status; + + throw new LoopBreakerException; + } + + public function daemonShouldRun(WorkerOptions $options, $connectionName, $queue) + { + return true; + } } class WorkerFakeManager extends \Illuminate\Queue\QueueManager @@ -403,4 +441,14 @@ public function setConnectionName($name) { $this->connectionName = $name; } + + public function timeout() + { + return time() + 60; + } +} + +class LoopBreakerException extends RuntimeException +{ } + From 5c743784aa5d14e24a3c7a2fa24aef278b76d34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Tue, 7 Aug 2018 10:52:08 +0200 Subject: [PATCH 0200/2459] Style --- tests/Queue/QueueWorkerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Queue/QueueWorkerTest.php b/tests/Queue/QueueWorkerTest.php index b27294cd1f7c..5c282b3954a1 100755 --- a/tests/Queue/QueueWorkerTest.php +++ b/tests/Queue/QueueWorkerTest.php @@ -451,4 +451,3 @@ public function timeout() class LoopBreakerException extends RuntimeException { } - From 32e74fb70405e03570e65886b6ca8c17ebd5b208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Tue, 7 Aug 2018 10:52:27 +0200 Subject: [PATCH 0201/2459] Style --- src/Illuminate/Queue/WorkerOptions.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Queue/WorkerOptions.php b/src/Illuminate/Queue/WorkerOptions.php index 22f2a0298206..40a6b1de4478 100644 --- a/src/Illuminate/Queue/WorkerOptions.php +++ b/src/Illuminate/Queue/WorkerOptions.php @@ -53,7 +53,6 @@ class WorkerOptions */ public $stopOnEmptyQueue; - /** * Create a new worker options instance. * From 3c3385675543e7f7dce75514b8869399d6b4395e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Tue, 7 Aug 2018 10:53:07 +0200 Subject: [PATCH 0202/2459] Update QueueWorkerTest.php --- tests/Queue/QueueWorkerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Queue/QueueWorkerTest.php b/tests/Queue/QueueWorkerTest.php index 5c282b3954a1..a1b850acaec3 100755 --- a/tests/Queue/QueueWorkerTest.php +++ b/tests/Queue/QueueWorkerTest.php @@ -71,7 +71,6 @@ public function test_worker_can_work_until_queue_is_empty() $this->events->shouldHaveReceived('dispatch')->with(Mockery::type(JobProcessed::class))->twice(); } - public function test_job_can_be_fired_based_on_priority() { $worker = $this->getWorker('default', [ From 9513f789cf1c114b45840540ba10c34efd508a71 Mon Sep 17 00:00:00 2001 From: Deleu Date: Tue, 7 Aug 2018 07:49:49 -0400 Subject: [PATCH 0203/2459] Add docblock --- src/Illuminate/Queue/Worker.php | 1 + src/Illuminate/Queue/WorkerOptions.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 771035fa7a29..3f2fd7d917de 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -194,6 +194,7 @@ protected function pauseWorker(WorkerOptions $options, $lastRestart) * * @param \Illuminate\Queue\WorkerOptions $options * @param int $lastRestart + * @param mixed $job */ protected function stopIfNecessary(WorkerOptions $options, $lastRestart, $job = null) { diff --git a/src/Illuminate/Queue/WorkerOptions.php b/src/Illuminate/Queue/WorkerOptions.php index 40a6b1de4478..9138ee114d99 100644 --- a/src/Illuminate/Queue/WorkerOptions.php +++ b/src/Illuminate/Queue/WorkerOptions.php @@ -62,6 +62,7 @@ class WorkerOptions * @param int $sleep * @param int $maxTries * @param bool $force + * @param bool $stopOnEmptyQueue * @return void */ public function __construct($delay = 0, $memory = 128, $timeout = 60, $sleep = 3, $maxTries = 0, $force = false, $stopOnEmptyQueue = false) From 8af60026af486834e77f93b0789c8747788ff7fb Mon Sep 17 00:00:00 2001 From: TSURU Date: Tue, 7 Aug 2018 21:04:28 +0900 Subject: [PATCH 0204/2459] Fixed nested rules in validated data --- .../Foundation/Http/FormRequest.php | 7 ++--- .../Validation/ValidatesRequests.php | 12 +++----- src/Illuminate/Validation/Validator.php | 15 ++++++---- .../Foundation/FoundationFormRequestTest.php | 30 +++++++++++++++++-- tests/Validation/ValidationValidatorTest.php | 21 +++++++++---- 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 386e6c2b3508..528d32f339c0 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -2,7 +2,6 @@ namespace Illuminate\Foundation\Http; -use Illuminate\Support\Str; use Illuminate\Http\Request; use Illuminate\Routing\Redirector; use Illuminate\Contracts\Container\Container; @@ -173,11 +172,9 @@ protected function failedAuthorization() */ public function validated() { - $rules = $this->container->call([$this, 'rules']); + $rules = $this->getValidatorInstance()->getRules(); - return $this->only(collect($rules)->keys()->map(function ($rule) { - return Str::contains($rule, '*') ? explode('.', $rule)[0] : $rule; - })->unique()->toArray()); + return $this->only(array_keys($rules)); } /** diff --git a/src/Illuminate/Foundation/Validation/ValidatesRequests.php b/src/Illuminate/Foundation/Validation/ValidatesRequests.php index cb947274de47..6b24030aee88 100644 --- a/src/Illuminate/Foundation/Validation/ValidatesRequests.php +++ b/src/Illuminate/Foundation/Validation/ValidatesRequests.php @@ -2,7 +2,6 @@ namespace Illuminate\Foundation\Validation; -use Illuminate\Support\Str; use Illuminate\Http\Request; use Illuminate\Contracts\Validation\Factory; use Illuminate\Validation\ValidationException; @@ -41,11 +40,10 @@ public function validateWith($validator, Request $request = null) public function validate(Request $request, array $rules, array $messages = [], array $customAttributes = []) { - $this->getValidationFactory() - ->make($request->all(), $rules, $messages, $customAttributes) - ->validate(); + $validator = $this->getValidationFactory()->make($request->all(), $rules, $messages, $customAttributes); + $validator->validate(); - return $this->extractInputFromRules($request, $rules); + return $this->extractInputFromRules($request, $validator->getRules()); } /** @@ -57,9 +55,7 @@ public function validate(Request $request, array $rules, */ protected function extractInputFromRules(Request $request, array $rules) { - return $request->only(collect($rules)->keys()->map(function ($rule) { - return Str::contains($rule, '*') ? explode('.', $rule)[0] : $rule; - })->unique()->toArray()); + return $request->only(array_keys($rules)); } /** diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index db8b2d6358ae..7ee71ce8d8c7 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -308,12 +308,17 @@ public function validate() $results = []; - $rules = collect($this->getRules())->keys()->map(function ($rule) { - return Str::contains($rule, '*') ? explode('.', $rule)[0] : $rule; - })->unique(); + $keys = array_keys($this->getRules()); + $input = $this->getData(); - foreach ($rules as $rule) { - Arr::set($results, $rule, data_get($this->getData(), $rule)); + $placeholder = new \stdClass(); + + foreach ($keys as $key) { + $value = data_get($input, $key, $placeholder); + + if ($value !== $placeholder) { + Arr::set($results, $key, $value); + } } return $results; diff --git a/tests/Foundation/FoundationFormRequestTest.php b/tests/Foundation/FoundationFormRequestTest.php index 67304cbb0c1c..5c11b4d6ee9c 100644 --- a/tests/Foundation/FoundationFormRequestTest.php +++ b/tests/Foundation/FoundationFormRequestTest.php @@ -36,13 +36,24 @@ public function test_validated_method_returns_the_validated_data() public function test_validated_method_returns_the_validated_data_nested_rules() { - $payload = ['nested' => ['foo' => 'bar', 'baz' => ''], 'array' => [1, 2]]; + $payload = ['nested' => ['foo' => 'bar', 'with' => 'extras']]; $request = $this->createRequest($payload, FoundationTestFormRequestNestedStub::class); $request->validateResolved(); - $this->assertEquals(['nested' => ['foo' => 'bar'], 'array' => [1, 2]], $request->validated()); + $this->assertEquals(['nested' => ['foo' => 'bar']], $request->validated()); + } + + public function test_validated_method_returns_the_validated_data_nested_array_rules() + { + $payload = ['nested' => [['bar' => 'baz', 'with' => 'extras'], ['bar' => 'baz2', 'with' => 'extras']]]; + + $request = $this->createRequest($payload, FoundationTestFormRequestNestedArrayStub::class); + + $request->validateResolved(); + + $this->assertEquals(['nested' => [['bar' => 'baz'], ['bar' => 'baz2']]], $request->validated()); } /** @@ -189,7 +200,20 @@ class FoundationTestFormRequestNestedStub extends FormRequest { public function rules() { - return ['nested.foo' => 'required', 'array.*' => 'integer']; + return ['nested.foo' => 'required']; + } + + public function authorize() + { + return true; + } +} + +class FoundationTestFormRequestNestedArrayStub extends FormRequest +{ + public function rules() + { + return ['nested.*.bar' => 'required']; } public function authorize() diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 46d4c0fecc4d..171c96d4587a 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -4007,17 +4007,28 @@ public function testValidateReturnsValidatedData() public function testValidateReturnsValidatedDataNestedRules() { - $post = ['nested' => ['foo' => 'bar', 'baz' => ''], 'array' => [1, 2]]; + $post = ['nested' => ['foo' => 'bar', 'with' => 'extras', 'type' => 'admin']]; - $rules = ['nested.foo' => 'required', 'array.*' => 'integer']; + $v = new Validator($this->getIlluminateArrayTranslator(), $post, ['nested.foo' => 'required']); + $v->sometimes('nested.type', 'required', function () { + return false; + }); + $data = $v->validate(); - $v = new Validator($this->getIlluminateArrayTranslator(), $post, $rules); - $v->sometimes('type', 'required', function () { + $this->assertEquals(['nested' => ['foo' => 'bar']], $data); + } + + public function testValidateReturnsValidatedDataNestedArrayRules() + { + $post = ['nested' => [['bar' => 'baz', 'with' => 'extras', 'type' => 'admin'], ['bar' => 'baz2', 'with' => 'extras', 'type' => 'admin']]]; + + $v = new Validator($this->getIlluminateArrayTranslator(), $post, ['nested.*.bar' => 'required']); + $v->sometimes('nested.*.type', 'required', function () { return false; }); $data = $v->validate(); - $this->assertEquals(['nested' => ['foo' => 'bar'], 'array' => [1, 2]], $data); + $this->assertEquals(['nested' => [['bar' => 'baz'], ['bar' => 'baz2']]], $data); } protected function getTranslator() From 13e6f2cb1138ac70836c943abd9a82106a0ba5e6 Mon Sep 17 00:00:00 2001 From: TSURU Date: Tue, 7 Aug 2018 22:19:20 +0900 Subject: [PATCH 0205/2459] Revert test --- .../Foundation/FoundationFormRequestTest.php | 26 ++++++++++++++++++- tests/Validation/ValidationValidatorTest.php | 15 +++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/tests/Foundation/FoundationFormRequestTest.php b/tests/Foundation/FoundationFormRequestTest.php index 5c11b4d6ee9c..8bc0505479ea 100644 --- a/tests/Foundation/FoundationFormRequestTest.php +++ b/tests/Foundation/FoundationFormRequestTest.php @@ -36,12 +36,23 @@ public function test_validated_method_returns_the_validated_data() public function test_validated_method_returns_the_validated_data_nested_rules() { - $payload = ['nested' => ['foo' => 'bar', 'with' => 'extras']]; + $payload = ['nested' => ['foo' => 'bar', 'baz' => ''], 'array' => [1, 2]]; $request = $this->createRequest($payload, FoundationTestFormRequestNestedStub::class); $request->validateResolved(); + $this->assertEquals(['nested' => ['foo' => 'bar'], 'array' => [1, 2]], $request->validated()); + } + + public function test_validated_method_returns_the_validated_data_nested_child_rules() + { + $payload = ['nested' => ['foo' => 'bar', 'with' => 'extras']]; + + $request = $this->createRequest($payload, FoundationTestFormRequestNestedChildStub::class); + + $request->validateResolved(); + $this->assertEquals(['nested' => ['foo' => 'bar']], $request->validated()); } @@ -197,6 +208,19 @@ public function authorize() } class FoundationTestFormRequestNestedStub extends FormRequest +{ + public function rules() + { + return ['nested.foo' => 'required', 'array.*' => 'integer']; + } + + public function authorize() + { + return true; + } +} + +class FoundationTestFormRequestNestedChildStub extends FormRequest { public function rules() { diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 171c96d4587a..98b7fee0c04d 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -4006,6 +4006,21 @@ public function testValidateReturnsValidatedData() } public function testValidateReturnsValidatedDataNestedRules() + { + $post = ['nested' => ['foo' => 'bar', 'baz' => ''], 'array' => [1, 2]]; + + $rules = ['nested.foo' => 'required', 'array.*' => 'integer']; + + $v = new Validator($this->getIlluminateArrayTranslator(), $post, $rules); + $v->sometimes('type', 'required', function () { + return false; + }); + $data = $v->validate(); + + $this->assertEquals(['nested' => ['foo' => 'bar'], 'array' => [1, 2]], $data); + } + + public function testValidateReturnsValidatedDataNestedChildRules() { $post = ['nested' => ['foo' => 'bar', 'with' => 'extras', 'type' => 'admin']]; From 595a848c3bf1e0aecb533dbd7b46e352dd4ef0da Mon Sep 17 00:00:00 2001 From: TSURU Date: Tue, 7 Aug 2018 23:25:31 +0900 Subject: [PATCH 0206/2459] Add Contracts --- src/Illuminate/Contracts/Validation/Validator.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Illuminate/Contracts/Validation/Validator.php b/src/Illuminate/Contracts/Validation/Validator.php index 3815921c963e..5128101ad0a4 100644 --- a/src/Illuminate/Contracts/Validation/Validator.php +++ b/src/Illuminate/Contracts/Validation/Validator.php @@ -44,4 +44,18 @@ public function after($callback); * @return \Illuminate\Support\MessageBag */ public function errors(); + + /** + * Run the validator's rules against its data. + * + * @return array + */ + public function validate(); + + /** + * Get the validation rules. Array keys must be attribute. + * + * @return array + */ + public function getRules(); } From b360a12e4400f48b51fe4af1418c375e3b5f92ab Mon Sep 17 00:00:00 2001 From: Nguyen Xuan Quynh Date: Wed, 8 Aug 2018 12:33:11 +0700 Subject: [PATCH 0207/2459] fix console getDefaultInputDefinition() docblock (#25134) --- src/Illuminate/Console/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index e836f71c0170..d57236582b19 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -259,7 +259,7 @@ public function resolveCommands($commands) } /** - * Get the default input definitions for the applications. + * Get the default input definition for the application. * * This is used to add the --env option to every available command. * From 7f043c774af55cec7abda3d0590e65666bfa2934 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Wed, 8 Aug 2018 01:37:48 -0400 Subject: [PATCH 0208/2459] [5.7] Remove preflight guest check by the gate (#25108) * Remove preflight guest check * Add tests for before/after guest callbacks --- src/Illuminate/Auth/Access/Gate.php | 114 +++++++++++++--------------- tests/Auth/AuthAccessGateTest.php | 26 +++++++ 2 files changed, 79 insertions(+), 61 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 3f8c450a4ac7..2131e3c7c3e9 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -305,13 +305,10 @@ public function authorize($ability, $arguments = []) */ protected function raw($ability, $arguments = []) { - if (! ($user = $this->resolveUser()) && - ! $this->allowsGuests($ability, Arr::wrap($arguments))) { - return false; - } - $arguments = Arr::wrap($arguments); + $user = $this->resolveUser(); + // First we will call the "before" callbacks for the Gate. If any of these give // back a non-null response, we will immediately return that result in order // to let the developers override all checks for some authorization cases. @@ -332,39 +329,24 @@ protected function raw($ability, $arguments = []) } /** - * Determine if the given ability allows guests. + * Determine whether the callback/method can be called with the given user. * - * @param string $ability - * @param array $arguments + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user + * @param \Closure|string $class + * @param string|null $method * @return bool */ - protected function allowsGuests($ability, $arguments) + protected function canBeCalledWithUser($user, $class, $method = null) { - if (isset($arguments[0]) && - ! is_null($policy = $this->getPolicyFor($arguments[0]))) { - return $this->policyAllowsGuests($policy, $ability, $arguments); + if (! is_null($user)) { + return true; } - if (isset($this->abilities[$ability])) { - return $this->abilityAllowsGuests($ability, $arguments); + if (! is_null($method)) { + return $this->methodAllowsGuests($class, $method); } - return false; - } - - /** - * Determine if the given policy method allows guests. - * - * @param string $policy - * @param string $ability - * @param array $arguments - * @return bool - */ - protected function policyAllowsGuests($policy, $ability, $arguments) - { - return $this->methodAllowsGuests( - $policy, $this->formatAbilityToMethod($ability) - ); + return $this->callbackAllowsGuests($class); } /** @@ -393,18 +375,6 @@ protected function methodAllowsGuests($class, $method) return false; } - /** - * Determine if the ability allows guests. - * - * @param string $ability - * @param array $arguments - * @return bool - */ - protected function abilityAllowsGuests($ability, $arguments) - { - return $this->callbackAllowsGuests($this->abilities[$ability]); - } - /** * Determine if the callback allows guests. * @@ -434,7 +404,7 @@ protected function parameterAllowsGuests($parameter) /** * Resolve and call the appropriate authorization callback. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param string $ability * @param array $arguments * @return bool @@ -449,7 +419,7 @@ protected function callAuthCallback($user, $ability, array $arguments) /** * Call all of the before callbacks and return if a result is given. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param string $ability * @param array $arguments * @return bool|null @@ -459,7 +429,7 @@ protected function callBeforeCallbacks($user, $ability, array $arguments) $arguments = array_merge([$user, $ability], [$arguments]); foreach ($this->beforeCallbacks as $before) { - if (is_null($user) && ! $this->callbackAllowsGuests($before)) { + if (! $this->canBeCalledWithUser($user, $before)) { continue; } @@ -481,7 +451,7 @@ protected function callBeforeCallbacks($user, $ability, array $arguments) protected function callAfterCallbacks($user, $ability, array $arguments, $result) { foreach ($this->afterCallbacks as $after) { - if (is_null($user) && ! $this->callbackAllowsGuests($after)) { + if (! $this->canBeCalledWithUser($user, $after)) { continue; } @@ -496,7 +466,7 @@ protected function callAfterCallbacks($user, $ability, array $arguments, $result /** * Resolve the callable for the given ability and arguments. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param string $ability * @param array $arguments * @return callable @@ -509,7 +479,8 @@ protected function resolveAuthCallback($user, $ability, array $arguments) return $callback; } - if (isset($this->abilities[$ability])) { + if (isset($this->abilities[$ability]) && + $this->canBeCalledWithUser($user, $this->abilities[$ability])) { return $this->abilities[$ability]; } @@ -586,18 +557,9 @@ protected function resolvePolicyCallback($user, $ability, array $arguments, $pol return $result; } - $ability = $this->formatAbilityToMethod($ability); - - // If this first argument is a string, that means they are passing a class name - // to the policy. We will remove the first argument from this argument array - // because this policy already knows what type of models it can authorize. - if (isset($arguments[0]) && is_string($arguments[0])) { - array_shift($arguments); - } + $method = $this->formatAbilityToMethod($ability); - return is_callable([$policy, $ability]) - ? $policy->{$ability}($user, ...$arguments) - : null; + return $this->callPolicyMethod($policy, $method, $user, $arguments); }; } @@ -612,12 +574,42 @@ protected function resolvePolicyCallback($user, $ability, array $arguments, $pol */ protected function callPolicyBefore($policy, $user, $ability, $arguments) { - if (method_exists($policy, 'before') && - (! is_null($user) || $this->methodAllowsGuests($policy, 'before'))) { + if (! method_exists($policy, 'before')) { + return null; + } + + if ($this->canBeCalledWithUser($user, $policy, 'before')) { return $policy->before($user, $ability, ...$arguments); } } + /** + * Call the appropriate method on the given policy. + * + * @param mixed $policy + * @param string $method + * @param \Illuminate\Contracts\Auth\Authenticatable|null $user + * @param array $arguments + * @return mixed + */ + protected function callPolicyMethod($policy, $method, $user, array $arguments) + { + // If this first argument is a string, that means they are passing a class name + // to the policy. We will remove the first argument from this argument array + // because this policy already knows what type of models it can authorize. + if (isset($arguments[0]) && is_string($arguments[0])) { + array_shift($arguments); + } + + if (! is_callable([$policy, $method])) { + return null; + } + + if ($this->canBeCalledWithUser($user, $policy, $method)) { + return $policy->{$method}($user, ...$arguments); + } + } + /** * Format the policy ability into a method name. * diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index 110cfbeb537c..b2ba324a52a0 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -26,6 +26,32 @@ public function test_basic_closures_can_be_defined() $this->assertFalse($gate->check('bar')); } + public function test_before_can_allow_guests() + { + $gate = new Gate(new Container, function () { + return null; + }); + + $gate->before(function (?StdClass $user) { + return true; + }); + + $this->assertTrue($gate->check('anything')); + } + + public function test_after_can_allow_guests() + { + $gate = new Gate(new Container, function () { + return null; + }); + + $gate->after(function (?StdClass $user) { + return true; + }); + + $this->assertTrue($gate->check('anything')); + } + public function test_closures_can_allow_guest_users() { $gate = new Gate(new Container, function () { From 941c8c7be2ad4441cdba12053c15f5dc46980707 Mon Sep 17 00:00:00 2001 From: TSURU Date: Wed, 8 Aug 2018 14:50:03 +0900 Subject: [PATCH 0209/2459] Using Validator::validate() --- src/Illuminate/Contracts/Validation/Validator.php | 7 ------- src/Illuminate/Foundation/Http/FormRequest.php | 4 +--- src/Illuminate/Foundation/Validation/ValidatesRequests.php | 7 ++----- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/Illuminate/Contracts/Validation/Validator.php b/src/Illuminate/Contracts/Validation/Validator.php index 5128101ad0a4..56d6fbc9b8f6 100644 --- a/src/Illuminate/Contracts/Validation/Validator.php +++ b/src/Illuminate/Contracts/Validation/Validator.php @@ -51,11 +51,4 @@ public function errors(); * @return array */ public function validate(); - - /** - * Get the validation rules. Array keys must be attribute. - * - * @return array - */ - public function getRules(); } diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 528d32f339c0..f1d617f02848 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -172,9 +172,7 @@ protected function failedAuthorization() */ public function validated() { - $rules = $this->getValidatorInstance()->getRules(); - - return $this->only(array_keys($rules)); + return $this->getValidatorInstance()->validate(); } /** diff --git a/src/Illuminate/Foundation/Validation/ValidatesRequests.php b/src/Illuminate/Foundation/Validation/ValidatesRequests.php index 6b24030aee88..99c7f361b05c 100644 --- a/src/Illuminate/Foundation/Validation/ValidatesRequests.php +++ b/src/Illuminate/Foundation/Validation/ValidatesRequests.php @@ -23,9 +23,7 @@ public function validateWith($validator, Request $request = null) $validator = $this->getValidationFactory()->make($request->all(), $validator); } - $validator->validate(); - - return $this->extractInputFromRules($request, $validator->getRules()); + return $validator->validate(); } /** @@ -41,9 +39,8 @@ public function validate(Request $request, array $rules, array $messages = [], array $customAttributes = []) { $validator = $this->getValidationFactory()->make($request->all(), $rules, $messages, $customAttributes); - $validator->validate(); - return $this->extractInputFromRules($request, $validator->getRules()); + return $validator->validate(); } /** From 7b181010f10cf8363047d6fd7fdfed7733ea5b70 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Wed, 8 Aug 2018 14:52:32 -0400 Subject: [PATCH 0210/2459] Make the Gate's "raw" method public (#25143) --- src/Illuminate/Auth/Access/Gate.php | 2 +- src/Illuminate/Contracts/Auth/Access/Gate.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 2131e3c7c3e9..684478d74f5c 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -303,7 +303,7 @@ public function authorize($ability, $arguments = []) * @param array|mixed $arguments * @return mixed */ - protected function raw($ability, $arguments = []) + public function raw($ability, $arguments = []) { $arguments = Arr::wrap($arguments); diff --git a/src/Illuminate/Contracts/Auth/Access/Gate.php b/src/Illuminate/Contracts/Auth/Access/Gate.php index 2021b573e6c1..779ad46deb82 100644 --- a/src/Illuminate/Contracts/Auth/Access/Gate.php +++ b/src/Illuminate/Contracts/Auth/Access/Gate.php @@ -93,6 +93,15 @@ public function any($abilities, $arguments = []); */ public function authorize($ability, $arguments = []); + /** + * Get the raw result from the authorization callback. + * + * @param string $ability + * @param array|mixed $arguments + * @return mixed + */ + public function raw($ability, $arguments = []); + /** * Get a policy instance for a given class. * From 8c015cd2a29ed5e32411bf64547635e3be1176e8 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Thu, 9 Aug 2018 01:59:40 -0400 Subject: [PATCH 0211/2459] Add Route::permanentRedirect() method to the router (#25155) * Make Route::redirect() default to 302 * Add permanentRedirect() method to the router --- src/Illuminate/Routing/Router.php | 14 +++++++++++++- tests/Routing/RoutingRouteTest.php | 28 +++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index c83473e44c84..2d6825b8dab8 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -236,13 +236,25 @@ public function fallback($action) * @param int $status * @return \Illuminate\Routing\Route */ - public function redirect($uri, $destination, $status = 301) + public function redirect($uri, $destination, $status = 302) { return $this->any($uri, '\Illuminate\Routing\RedirectController') ->defaults('destination', $destination) ->defaults('status', $status); } + /** + * Create a permanent redirect from one URI to another. + * + * @param string $uri + * @param string $destination + * @return \Illuminate\Routing\Route + */ + public function permanentRedirect($uri, $destination) + { + return $this->redirect($uri, $destination, 301); + } + /** * Register a new route that returns a view. * diff --git a/tests/Routing/RoutingRouteTest.php b/tests/Routing/RoutingRouteTest.php index 65e99a9a41b6..6bc0d8743065 100644 --- a/tests/Routing/RoutingRouteTest.php +++ b/tests/Routing/RoutingRouteTest.php @@ -1484,13 +1484,39 @@ public function testRouteRedirect() $router->get('contact_us', function () { throw new \Exception('Route should not be reachable.'); }); - $router->redirect('contact_us', 'contact', 302); + $router->redirect('contact_us', 'contact'); $response = $router->dispatch(Request::create('contact_us', 'GET')); $this->assertTrue($response->isRedirect('contact')); $this->assertEquals(302, $response->getStatusCode()); } + public function testRouteRedirectWithCustomStatus() + { + $router = $this->getRouter(); + $router->get('contact_us', function () { + throw new \Exception('Route should not be reachable.'); + }); + $router->redirect('contact_us', 'contact', 301); + + $response = $router->dispatch(Request::create('contact_us', 'GET')); + $this->assertTrue($response->isRedirect('contact')); + $this->assertEquals(301, $response->getStatusCode()); + } + + public function testRoutePermanentRedirect() + { + $router = $this->getRouter(); + $router->get('contact_us', function () { + throw new \Exception('Route should not be reachable.'); + }); + $router->permanentRedirect('contact_us', 'contact'); + + $response = $router->dispatch(Request::create('contact_us', 'GET')); + $this->assertTrue($response->isRedirect('contact')); + $this->assertEquals(301, $response->getStatusCode()); + } + protected function getRouter() { $container = new Container; From f614da48c38dbfed29705a01fc7e953b5bee9a3f Mon Sep 17 00:00:00 2001 From: Nguyen Xuan Quynh Date: Thu, 9 Aug 2018 13:00:00 +0700 Subject: [PATCH 0212/2459] Add missed throws dockblock of FilesystemAdapter (#25153) --- src/Illuminate/Filesystem/FilesystemAdapter.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Filesystem/FilesystemAdapter.php b/src/Illuminate/Filesystem/FilesystemAdapter.php index 6a66b8f07a99..64f45b5c721c 100644 --- a/src/Illuminate/Filesystem/FilesystemAdapter.php +++ b/src/Illuminate/Filesystem/FilesystemAdapter.php @@ -370,6 +370,8 @@ public function lastModified($path) * * @param string $path * @return string + * + * @throws \RuntimeException */ public function url($path) { @@ -489,6 +491,8 @@ protected function getLocalUrl($path) * @param \DateTimeInterface $expiration * @param array $options * @return string + * + * @throws \RuntimeException */ public function temporaryUrl($path, $expiration, array $options = []) { From fe290321349916223a800bf2f300d818d94d537a Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Thu, 9 Aug 2018 08:00:50 +0200 Subject: [PATCH 0213/2459] Modify MSSQL driver order (#25150) --- .../Connectors/SqlServerConnector.php | 10 +++-- tests/Database/DatabaseConnectorTest.php | 37 ++++++++++++++++--- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Database/Connectors/SqlServerConnector.php b/src/Illuminate/Database/Connectors/SqlServerConnector.php index 87525d121b66..6cfc33fb6396 100755 --- a/src/Illuminate/Database/Connectors/SqlServerConnector.php +++ b/src/Illuminate/Database/Connectors/SqlServerConnector.php @@ -43,13 +43,15 @@ protected function getDsn(array $config) // First we will create the basic DSN setup as well as the port if it is in // in the configuration options. This will give us the basic DSN we will // need to establish the PDO connections and return them back for use. - if (in_array('dblib', $this->getAvailableDrivers())) { - return $this->getDblibDsn($config); - } elseif ($this->prefersOdbc($config)) { + if ($this->prefersOdbc($config)) { return $this->getOdbcDsn($config); } - return $this->getSqlSrvDsn($config); + if (in_array('sqlsrv', $this->getAvailableDrivers())) { + return $this->getSqlSrvDsn($config); + } else { + return $this->getDblibDsn($config); + } } /** diff --git a/tests/Database/DatabaseConnectorTest.php b/tests/Database/DatabaseConnectorTest.php index 0e9e1c3ce249..c33619510f68 100755 --- a/tests/Database/DatabaseConnectorTest.php +++ b/tests/Database/DatabaseConnectorTest.php @@ -161,23 +161,48 @@ public function testSqlServerConnectCallsCreateConnectionWithOptionalArguments() $this->assertSame($result, $connection); } + public function testSqlServerConnectCallsCreateConnectionWithPreferredODBC() + { + if (! in_array('odbc', PDO::getAvailableDrivers())) { + $this->markTestSkipped('PHP was compiled without PDO ODBC support.'); + } + + $config = ['odbc' => true, 'odbc_datasource_name' => 'server=localhost;database=test;']; + $dsn = $this->getDsn($config); + $connector = $this->getMockBuilder('Illuminate\Database\Connectors\SqlServerConnector')->setMethods(['createConnection', 'getOptions'])->getMock(); + $connection = m::mock('stdClass'); + $connector->expects($this->once())->method('getOptions')->with($this->equalTo($config))->will($this->returnValue(['options'])); + $connector->expects($this->once())->method('createConnection')->with($this->equalTo($dsn), $this->equalTo($config), $this->equalTo(['options']))->will($this->returnValue($connection)); + $result = $connector->connect($config); + + $this->assertSame($result, $connection); + } + protected function getDsn(array $config) { extract($config, EXTR_SKIP); - if (in_array('dblib', PDO::getAvailableDrivers())) { - $port = isset($config['port']) ? ':'.$port : ''; - $appname = isset($config['appname']) ? ';appname='.$config['appname'] : ''; - $charset = isset($config['charset']) ? ';charset='.$config['charset'] : ''; + $availableDrivers = PDO::getAvailableDrivers(); - return "dblib:host={$host}{$port};dbname={$database}{$charset}{$appname}"; - } else { + if (in_array('odbc', $availableDrivers) && + ($config['odbc'] ?? null) === true) { + return isset($config['odbc_datasource_name']) + ? 'odbc:'.$config['odbc_datasource_name'] : ''; + } + + if (in_array('sqlsrv', $availableDrivers)) { $port = isset($config['port']) ? ','.$port : ''; $appname = isset($config['appname']) ? ';APP='.$config['appname'] : ''; $readonly = isset($config['readonly']) ? ';ApplicationIntent=ReadOnly' : ''; $pooling = (isset($config['pooling']) && $config['pooling'] == false) ? ';ConnectionPooling=0' : ''; return "sqlsrv:Server={$host}{$port};Database={$database}{$readonly}{$pooling}{$appname}"; + } else { + $port = isset($config['port']) ? ':'.$port : ''; + $appname = isset($config['appname']) ? ';appname='.$config['appname'] : ''; + $charset = isset($config['charset']) ? ';charset='.$config['charset'] : ''; + + return "dblib:host={$host}{$port};dbname={$database}{$charset}{$appname}"; } } } From 525f780709026979e08ba5cfe0da91a6853075d8 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Wed, 8 Aug 2018 23:24:35 -0400 Subject: [PATCH 0214/2459] Create ForwardsCalls trait --- .../Support/Traits/ForwardsCalls.php | 35 +++++++ tests/Support/ForwardsCallsTest.php | 93 +++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 src/Illuminate/Support/Traits/ForwardsCalls.php create mode 100644 tests/Support/ForwardsCallsTest.php diff --git a/src/Illuminate/Support/Traits/ForwardsCalls.php b/src/Illuminate/Support/Traits/ForwardsCalls.php new file mode 100644 index 000000000000..5c264b52c8bd --- /dev/null +++ b/src/Illuminate/Support/Traits/ForwardsCalls.php @@ -0,0 +1,35 @@ +{$method}(...$parameters); + } catch (Error | BadMethodCallException $e) { + $pattern = '~^Call to undefined method (?P[^:]+)::(?P[a-zA-Z]+)\(\)$~'; + + if (! preg_match($pattern, $e->getMessage(), $matches)) { + throw $e; + } + + if ($matches['class'] != get_class($object) || $matches['method'] != $method) { + throw $e; + } + + $this->throwBadMethodCallException($method); + } + } + + protected function throwBadMethodCallException($method) + { + throw new BadMethodCallException(sprintf( + 'Call to undefined method %s::%s()', static::class, $method + )); + } +} diff --git a/tests/Support/ForwardsCallsTest.php b/tests/Support/ForwardsCallsTest.php new file mode 100644 index 000000000000..d32144e470a5 --- /dev/null +++ b/tests/Support/ForwardsCallsTest.php @@ -0,0 +1,93 @@ +forwardedTwo('foo', 'bar'); + + $this->assertEquals(['foo', 'bar'], $results); + } + + public function testNestedForwardCalls() + { + $results = (new ForwardsCallsOne)->forwardedBase('foo', 'bar'); + + $this->assertEquals(['foo', 'bar'], $results); + } + + /** + * @expectedException \BadMethodCallException + * @expectedExceptionMessage Call to undefined method Illuminate\Tests\Support\ForwardsCallsOne::missingMethod() + */ + public function testMissingForwardedCallThrowsCorrectError() + { + (new ForwardsCallsOne)->missingMethod('foo', 'bar'); + } + + /** + * @expectedException \Error + * @expectedExceptionMessage Call to undefined method Illuminate\Tests\Support\ForwardsCallsBase::missingMethod() + */ + public function testNonForwardedErrorIsNotTamperedWith() + { + (new ForwardsCallsOne)->baseError('foo', 'bar'); + } + + /** + * @expectedException \BadMethodCallException + * @expectedExceptionMessage Call to undefined method Illuminate\Tests\Support\ForwardsCallsOne::test() + */ + public function testThrowBadMethodCallException() + { + (new ForwardsCallsOne)->throwTestException('test'); + } +} + +class ForwardsCallsOne +{ + use ForwardsCalls; + + public function __call($method, $parameters) + { + return $this->forwardCallTo(new ForwardsCallsTwo, $method, $parameters); + } + + public function throwTestException($method) + { + $this->throwBadMethodCallException($method); + } +} + +class ForwardsCallsTwo +{ + use ForwardsCalls; + + public function __call($method, $parameters) + { + return $this->forwardCallTo(new ForwardsCallsBase, $method, $parameters); + } + + public function forwardedTwo(...$parameters) + { + return $parameters; + } +} + +class ForwardsCallsBase +{ + public function forwardedBase(...$parameters) + { + return $parameters; + } + + public function baseError() + { + return $this->missingMethod(); + } +} From 97733713699f4de69dd2bf46d8cfb11de7f34a30 Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Thu, 9 Aug 2018 10:03:03 -0400 Subject: [PATCH 0215/2459] Forward calls via the ForwardsCalls trait --- src/Illuminate/Database/Eloquent/Builder.php | 9 ++++----- src/Illuminate/Database/Eloquent/Model.php | 6 ++++-- src/Illuminate/Database/Eloquent/Relations/Relation.php | 5 +++-- src/Illuminate/Database/Query/Builder.php | 8 +++----- .../Support/Providers/RouteServiceProvider.php | 7 +++++-- src/Illuminate/Http/RedirectResponse.php | 8 +++----- src/Illuminate/Http/Resources/DelegatesToResource.php | 5 ++++- src/Illuminate/Mail/Mailable.php | 8 +++----- src/Illuminate/Mail/Message.php | 7 ++++--- src/Illuminate/Pagination/AbstractPaginator.php | 5 ++++- tests/Http/HttpRedirectResponseTest.php | 2 +- tests/Http/HttpResponseTest.php | 2 +- 12 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index ec95b91d8f77..2a4b009099fc 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -8,6 +8,7 @@ use Illuminate\Support\Str; use Illuminate\Pagination\Paginator; use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Support\Traits\ForwardsCalls; use Illuminate\Database\Concerns\BuildsQueries; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Query\Builder as QueryBuilder; @@ -17,7 +18,7 @@ */ class Builder { - use BuildsQueries, Concerns\QueriesRelationships; + use BuildsQueries, Concerns\QueriesRelationships, ForwardsCalls; /** * The base query builder instance. @@ -1317,7 +1318,7 @@ public function __call($method, $parameters) return $this->toBase()->{$method}(...$parameters); } - $this->query->{$method}(...$parameters); + $this->forwardCallTo($this->query, $method, $parameters); return $this; } @@ -1340,9 +1341,7 @@ public static function __callStatic($method, $parameters) } if (! isset(static::$macros[$method])) { - throw new BadMethodCallException(sprintf( - 'Method %s::%s does not exist.', static::class, $method - )); + $this->throwBadMethodCallException($method); } if (static::$macros[$method] instanceof Closure) { diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index a5adb894c270..26359ecc0f97 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -9,6 +9,7 @@ use Illuminate\Support\Str; use Illuminate\Contracts\Support\Jsonable; use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Support\Traits\ForwardsCalls; use Illuminate\Contracts\Routing\UrlRoutable; use Illuminate\Contracts\Queue\QueueableEntity; use Illuminate\Database\Eloquent\Relations\Pivot; @@ -24,7 +25,8 @@ abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializab Concerns\HasRelationships, Concerns\HasTimestamps, Concerns\HidesAttributes, - Concerns\GuardsAttributes; + Concerns\GuardsAttributes, + ForwardsCalls; /** * The connection name for the model. @@ -1598,7 +1600,7 @@ public function __call($method, $parameters) return $this->$method(...$parameters); } - return $this->newQuery()->$method(...$parameters); + return $this->forwardCallTo($this->newQuery(), $method, $parameters); } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index ae6ddbf4a5b2..8a6beb0c6d4b 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -9,13 +9,14 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Query\Expression; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Support\Traits\ForwardsCalls; /** * @mixin \Illuminate\Database\Eloquent\Builder */ abstract class Relation { - use Macroable { + use ForwardsCalls, Macroable { __call as macroCall; } @@ -366,7 +367,7 @@ public function __call($method, $parameters) return $this->macroCall($method, $parameters); } - $result = $this->query->{$method}(...$parameters); + $result = $this->forwardCallTo($this->query, $method, $parameters); if ($result === $this->query) { return $this; diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 3ec55a5ff3fa..446a0eca5159 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -4,7 +4,6 @@ use Closure; use RuntimeException; -use BadMethodCallException; use Illuminate\Support\Arr; use Illuminate\Support\Str; use InvalidArgumentException; @@ -13,6 +12,7 @@ use Illuminate\Support\Traits\Macroable; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\ConnectionInterface; +use Illuminate\Support\Traits\ForwardsCalls; use Illuminate\Database\Concerns\BuildsQueries; use Illuminate\Database\Query\Grammars\Grammar; use Illuminate\Database\Query\Processors\Processor; @@ -20,7 +20,7 @@ class Builder { - use BuildsQueries, Macroable { + use BuildsQueries, ForwardsCalls, Macroable { __call as macroCall; } @@ -2813,8 +2813,6 @@ public function __call($method, $parameters) return $this->dynamicWhere($method, $parameters); } - throw new BadMethodCallException(sprintf( - 'Method %s::%s does not exist.', static::class, $method - )); + $this->throwBadMethodCallException($method); } } diff --git a/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php index c753447b11f7..5034869461dd 100644 --- a/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php @@ -4,6 +4,7 @@ use Illuminate\Routing\Router; use Illuminate\Support\ServiceProvider; +use Illuminate\Support\Traits\ForwardsCalls; use Illuminate\Contracts\Routing\UrlGenerator; /** @@ -11,6 +12,8 @@ */ class RouteServiceProvider extends ServiceProvider { + use ForwardsCalls; + /** * The controller namespace for the application. * @@ -94,8 +97,8 @@ public function register() */ public function __call($method, $parameters) { - return call_user_func_array( - [$this->app->make(Router::class), $method], $parameters + return $this->forwardCallTo( + $this->app->make(Router::class), $method, $parameters ); } } diff --git a/src/Illuminate/Http/RedirectResponse.php b/src/Illuminate/Http/RedirectResponse.php index fc177f8dfb45..9453b58182f5 100755 --- a/src/Illuminate/Http/RedirectResponse.php +++ b/src/Illuminate/Http/RedirectResponse.php @@ -2,11 +2,11 @@ namespace Illuminate\Http; -use BadMethodCallException; use Illuminate\Support\Str; use Illuminate\Support\MessageBag; use Illuminate\Support\ViewErrorBag; use Illuminate\Support\Traits\Macroable; +use Illuminate\Support\Traits\ForwardsCalls; use Illuminate\Session\Store as SessionStore; use Illuminate\Contracts\Support\MessageProvider; use Symfony\Component\HttpFoundation\File\UploadedFile as SymfonyUploadedFile; @@ -14,7 +14,7 @@ class RedirectResponse extends BaseRedirectResponse { - use ResponseTrait, Macroable { + use ForwardsCalls, ResponseTrait, Macroable { Macroable::__call as macroCall; } @@ -231,8 +231,6 @@ public function __call($method, $parameters) return $this->with(Str::snake(substr($method, 4)), $parameters[0]); } - throw new BadMethodCallException(sprintf( - 'Method %s::%s does not exist.', static::class, $method - )); + $this->throwBadMethodCallException($method); } } diff --git a/src/Illuminate/Http/Resources/DelegatesToResource.php b/src/Illuminate/Http/Resources/DelegatesToResource.php index 6f642c4988a0..d11f27fed6ec 100644 --- a/src/Illuminate/Http/Resources/DelegatesToResource.php +++ b/src/Illuminate/Http/Resources/DelegatesToResource.php @@ -3,9 +3,12 @@ namespace Illuminate\Http\Resources; use Exception; +use Illuminate\Support\Traits\ForwardsCalls; trait DelegatesToResource { + use ForwardsCalls; + /** * Get the value of the resource's route key. * @@ -125,6 +128,6 @@ public function __get($key) */ public function __call($method, $parameters) { - return $this->resource->{$method}(...$parameters); + return $this->forwardCallTo($this->resource, $method, $parameters); } } diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index 1e5421bb12da..c15cbb9b652b 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -4,13 +4,13 @@ use ReflectionClass; use ReflectionProperty; -use BadMethodCallException; use Illuminate\Support\Str; use Illuminate\Support\Collection; use Illuminate\Support\HtmlString; use Illuminate\Container\Container; use Illuminate\Support\Traits\Localizable; use Illuminate\Contracts\Support\Renderable; +use Illuminate\Support\Traits\ForwardsCalls; use Illuminate\Contracts\Queue\Factory as Queue; use Illuminate\Contracts\Mail\Mailer as MailerContract; use Illuminate\Contracts\Mail\Mailable as MailableContract; @@ -18,7 +18,7 @@ class Mailable implements MailableContract, Renderable { - use Localizable; + use ForwardsCalls, Localizable; /** * The locale of the message. @@ -808,8 +808,6 @@ public function __call($method, $parameters) return $this->with(Str::camel(substr($method, 4)), $parameters[0]); } - throw new BadMethodCallException(sprintf( - 'Method %s::%s does not exist.', static::class, $method - )); + $this->throwBadMethodCallException($method); } } diff --git a/src/Illuminate/Mail/Message.php b/src/Illuminate/Mail/Message.php index 69324fc8fc23..94c9dce2201f 100755 --- a/src/Illuminate/Mail/Message.php +++ b/src/Illuminate/Mail/Message.php @@ -4,12 +4,15 @@ use Swift_Image; use Swift_Attachment; +use Illuminate\Support\Traits\ForwardsCalls; /** * @mixin \Swift_Message */ class Message { + use ForwardsCalls; + /** * The Swift Message instance. * @@ -321,8 +324,6 @@ public function getSwiftMessage() */ public function __call($method, $parameters) { - $callable = [$this->swift, $method]; - - return call_user_func_array($callable, $parameters); + return $this->forwardCallTo($this->swift, $method, $parameters); } } diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index 6cef61d7e51e..6d541f481431 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -7,12 +7,15 @@ use Illuminate\Support\Str; use Illuminate\Support\Collection; use Illuminate\Contracts\Support\Htmlable; +use Illuminate\Support\Traits\ForwardsCalls; /** * @mixin \Illuminate\Support\Collection */ abstract class AbstractPaginator implements Htmlable { + use ForwardsCalls; + /** * All of the items being paginated. * @@ -620,7 +623,7 @@ public function toHtml() */ public function __call($method, $parameters) { - return $this->getCollection()->$method(...$parameters); + return $this->forwardCallTo($this->getCollection(), $method, $parameters); } /** diff --git a/tests/Http/HttpRedirectResponseTest.php b/tests/Http/HttpRedirectResponseTest.php index b8dab27be17c..f4ca3860f4f6 100755 --- a/tests/Http/HttpRedirectResponseTest.php +++ b/tests/Http/HttpRedirectResponseTest.php @@ -121,7 +121,7 @@ public function testMagicCall() /** * @expectedException \BadMethodCallException - * @expectedExceptionMessage Method Illuminate\Http\RedirectResponse::doesNotExist does not exist. + * @expectedExceptionMessage Call to undefined method Illuminate\Http\RedirectResponse::doesNotExist() */ public function testMagicCallException() { diff --git a/tests/Http/HttpResponseTest.php b/tests/Http/HttpResponseTest.php index 82bb5bce9cf9..b2b07cfe1f74 100755 --- a/tests/Http/HttpResponseTest.php +++ b/tests/Http/HttpResponseTest.php @@ -189,7 +189,7 @@ public function testMagicCall() /** * @expectedException \BadMethodCallException - * @expectedExceptionMessage Method Illuminate\Http\RedirectResponse::doesNotExist does not exist. + * @expectedExceptionMessage Call to undefined method Illuminate\Http\RedirectResponse::doesNotExist() */ public function testMagicCallException() { From 49db8de9d9f0b73d5e1d96ebd1115a9e8d374e05 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Thu, 9 Aug 2018 21:24:43 +0200 Subject: [PATCH 0216/2459] Call the proper validator interface method (#25158) --- src/Illuminate/Validation/ValidatesWhenResolvedTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php b/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php index 598ef666a8ad..e4de332fa430 100644 --- a/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php +++ b/src/Illuminate/Validation/ValidatesWhenResolvedTrait.php @@ -22,7 +22,7 @@ public function validateResolved() $instance = $this->getValidatorInstance(); - if (! $instance->passes()) { + if ($instance->fails()) { $this->failedValidation($instance); } } From d4d74b221f268ecea5764a1c38e185e7379631a9 Mon Sep 17 00:00:00 2001 From: Eugene <37518271+Eugene-Melbourne@users.noreply.github.com> Date: Sat, 11 Aug 2018 05:43:50 +1000 Subject: [PATCH 0217/2459] [5.7] making addFailure public (#25088) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Making addFailure function - public and setting up defaults for the last parameter. This gives users an option to use existing functionality to generate and add new error message. The existing functionality takes care of translation and ":attribute" naming. It also simplifies the use of \resources\lang\en\validation.php file as a single source of truth for an error messages. * test cases around Making addFailure function creating test cases * formatting changed formatting to satisfy styleci.io * comment changes * removed class reflection removed all of those tests that are reflecting into the class to make sure it's public 😬 * removing return type declaration removing return type declaration from test case --- src/Illuminate/Validation/Validator.php | 6 ++- tests/Validation/ValidationAddFailureTest.php | 41 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 tests/Validation/ValidationAddFailureTest.php diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index db8b2d6358ae..ba99ca5672a6 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -584,8 +584,12 @@ protected function shouldStopValidating($attribute) * @param array $parameters * @return void */ - protected function addFailure($attribute, $rule, $parameters) + public function addFailure($attribute, $rule, $parameters = []) { + if (! $this->messages) { + $this->passes(); + } + $this->messages->add($attribute, $this->makeReplacements( $this->getMessage($attribute, $rule), $attribute, $rule, $parameters )); diff --git a/tests/Validation/ValidationAddFailureTest.php b/tests/Validation/ValidationAddFailureTest.php new file mode 100644 index 000000000000..c7d2605f9d17 --- /dev/null +++ b/tests/Validation/ValidationAddFailureTest.php @@ -0,0 +1,41 @@ +getIlluminateArrayTranslator(); + $validator = new Validator($trans, ['foo' => ['bar' => ['baz' => '']]], ['foo.bar.baz' => 'sometimes|required']); + + return $validator; + } + + public function testAddFailureExists() + { + $validator = $this->makeValidator(); + $method_name = 'addFailure'; + $this->assertTrue(method_exists($validator, $method_name)); + $this->assertTrue(is_callable([$validator, $method_name])); + } + + public function testAddFailureIsFunctional() + { + $attribute = 'Eugene'; + $validator = $this->makeValidator(); + $validator->addFailure($attribute, 'not_in'); + $messages = json_decode($validator->messages()); + $this->assertSame($messages->{'foo.bar.baz'}[0], 'validation.required', 'initial data in messages is lost'); + $this->assertSame($messages->{$attribute}[0], 'validation.not_in', 'new data in messages was not added'); + } +} From aaa08d688e549a593673692a0b65c7b5010cecfc Mon Sep 17 00:00:00 2001 From: TSURU Date: Sat, 11 Aug 2018 12:03:28 +0900 Subject: [PATCH 0218/2459] Remove ValidatesRequests::extractInputFromRules() --- .../Foundation/Validation/ValidatesRequests.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Illuminate/Foundation/Validation/ValidatesRequests.php b/src/Illuminate/Foundation/Validation/ValidatesRequests.php index 99c7f361b05c..cf5d75ad1ab4 100644 --- a/src/Illuminate/Foundation/Validation/ValidatesRequests.php +++ b/src/Illuminate/Foundation/Validation/ValidatesRequests.php @@ -43,18 +43,6 @@ public function validate(Request $request, array $rules, return $validator->validate(); } - /** - * Get the request input based on the given validation rules. - * - * @param \Illuminate\Http\Request $request - * @param array $rules - * @return array - */ - protected function extractInputFromRules(Request $request, array $rules) - { - return $request->only(array_keys($rules)); - } - /** * Validate the given request with the given rules. * From 996cca520649ec199087aacb40ac4aa8b3c74004 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 11 Aug 2018 16:12:51 -1000 Subject: [PATCH 0219/2459] formatting --- .../Support/Traits/ForwardsCalls.php | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Traits/ForwardsCalls.php b/src/Illuminate/Support/Traits/ForwardsCalls.php index 5c264b52c8bd..ac605d45160d 100644 --- a/src/Illuminate/Support/Traits/ForwardsCalls.php +++ b/src/Illuminate/Support/Traits/ForwardsCalls.php @@ -7,6 +7,16 @@ trait ForwardsCalls { + /** + * Forward a method call to the given object. + * + * @param mixed $object + * @param string $method + * @param array $parameters + * @return mixed + * + * @throws \BadMethodCallException + */ protected function forwardCallTo($object, $method, $parameters) { try { @@ -18,7 +28,8 @@ protected function forwardCallTo($object, $method, $parameters) throw $e; } - if ($matches['class'] != get_class($object) || $matches['method'] != $method) { + if ($matches['class'] != get_class($object) || + $matches['method'] != $method) { throw $e; } @@ -26,6 +37,14 @@ protected function forwardCallTo($object, $method, $parameters) } } + /** + * Create a bad method call exception for the given method. + * + * @param string $method + * @return void + * + * @throws \BadMethodCallException + */ protected function throwBadMethodCallException($method) { throw new BadMethodCallException(sprintf( From 083ad15c5ebcc8cad99f13a38b3a456dca4578e7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 11 Aug 2018 22:37:45 -1000 Subject: [PATCH 0220/2459] formatting --- src/Illuminate/Notifications/ChannelManager.php | 4 ++-- src/Illuminate/Notifications/Notification.php | 2 +- src/Illuminate/Notifications/NotificationSender.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Notifications/ChannelManager.php b/src/Illuminate/Notifications/ChannelManager.php index d8a8de735163..693767d318a7 100644 --- a/src/Illuminate/Notifications/ChannelManager.php +++ b/src/Illuminate/Notifications/ChannelManager.php @@ -1,4 +1,4 @@ - Date: Sat, 11 Aug 2018 23:03:46 -1000 Subject: [PATCH 0221/2459] remove garbage --- src/Illuminate/Notifications/ChannelManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Notifications/ChannelManager.php b/src/Illuminate/Notifications/ChannelManager.php index 693767d318a7..97d10c4125ee 100644 --- a/src/Illuminate/Notifications/ChannelManager.php +++ b/src/Illuminate/Notifications/ChannelManager.php @@ -1,4 +1,4 @@ -Local used Date: Tue, 14 Aug 2018 08:56:32 -0400 Subject: [PATCH 0222/2459] Support methods with underscores and numbers in the ForwardsCalls trait (#25208) --- src/Illuminate/Support/Traits/ForwardsCalls.php | 2 +- tests/Support/ForwardsCallsTest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Traits/ForwardsCalls.php b/src/Illuminate/Support/Traits/ForwardsCalls.php index ac605d45160d..bea7910cc477 100644 --- a/src/Illuminate/Support/Traits/ForwardsCalls.php +++ b/src/Illuminate/Support/Traits/ForwardsCalls.php @@ -22,7 +22,7 @@ protected function forwardCallTo($object, $method, $parameters) try { return $object->{$method}(...$parameters); } catch (Error | BadMethodCallException $e) { - $pattern = '~^Call to undefined method (?P[^:]+)::(?P[a-zA-Z]+)\(\)$~'; + $pattern = '~^Call to undefined method (?P[^:]+)::(?P[^\(]+)\(\)$~'; if (! preg_match($pattern, $e->getMessage(), $matches)) { throw $e; diff --git a/tests/Support/ForwardsCallsTest.php b/tests/Support/ForwardsCallsTest.php index d32144e470a5..1b4098fb152a 100644 --- a/tests/Support/ForwardsCallsTest.php +++ b/tests/Support/ForwardsCallsTest.php @@ -30,6 +30,15 @@ public function testMissingForwardedCallThrowsCorrectError() (new ForwardsCallsOne)->missingMethod('foo', 'bar'); } + /** + * @expectedException \BadMethodCallException + * @expectedExceptionMessage Call to undefined method Illuminate\Tests\Support\ForwardsCallsOne::this1_shouldWork_too() + */ + public function testMissingAlphanumericForwardedCallThrowsCorrectError() + { + (new ForwardsCallsOne)->this1_shouldWork_too('foo', 'bar'); + } + /** * @expectedException \Error * @expectedExceptionMessage Call to undefined method Illuminate\Tests\Support\ForwardsCallsBase::missingMethod() From 889b698c490bc9644178d87b65a28e0602bf071b Mon Sep 17 00:00:00 2001 From: Joseph Silber Date: Tue, 14 Aug 2018 08:56:48 -0400 Subject: [PATCH 0223/2459] Convert throwBadMethodCallException to a static method (#25207) --- src/Illuminate/Database/Eloquent/Builder.php | 2 +- src/Illuminate/Database/Query/Builder.php | 2 +- src/Illuminate/Http/RedirectResponse.php | 2 +- src/Illuminate/Mail/Mailable.php | 2 +- src/Illuminate/Support/Traits/ForwardsCalls.php | 6 +++--- tests/Database/DatabaseEloquentBuilderTest.php | 9 +++++++++ tests/Support/ForwardsCallsTest.php | 2 +- 7 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 2a4b009099fc..9798aac3f273 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -1341,7 +1341,7 @@ public static function __callStatic($method, $parameters) } if (! isset(static::$macros[$method])) { - $this->throwBadMethodCallException($method); + static::throwBadMethodCallException($method); } if (static::$macros[$method] instanceof Closure) { diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 446a0eca5159..452ddf6d5a7c 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2813,6 +2813,6 @@ public function __call($method, $parameters) return $this->dynamicWhere($method, $parameters); } - $this->throwBadMethodCallException($method); + static::throwBadMethodCallException($method); } } diff --git a/src/Illuminate/Http/RedirectResponse.php b/src/Illuminate/Http/RedirectResponse.php index 9453b58182f5..1fcfe9478d3e 100755 --- a/src/Illuminate/Http/RedirectResponse.php +++ b/src/Illuminate/Http/RedirectResponse.php @@ -231,6 +231,6 @@ public function __call($method, $parameters) return $this->with(Str::snake(substr($method, 4)), $parameters[0]); } - $this->throwBadMethodCallException($method); + static::throwBadMethodCallException($method); } } diff --git a/src/Illuminate/Mail/Mailable.php b/src/Illuminate/Mail/Mailable.php index c15cbb9b652b..fc9863a74c6b 100644 --- a/src/Illuminate/Mail/Mailable.php +++ b/src/Illuminate/Mail/Mailable.php @@ -808,6 +808,6 @@ public function __call($method, $parameters) return $this->with(Str::camel(substr($method, 4)), $parameters[0]); } - $this->throwBadMethodCallException($method); + static::throwBadMethodCallException($method); } } diff --git a/src/Illuminate/Support/Traits/ForwardsCalls.php b/src/Illuminate/Support/Traits/ForwardsCalls.php index bea7910cc477..3d0f122f3114 100644 --- a/src/Illuminate/Support/Traits/ForwardsCalls.php +++ b/src/Illuminate/Support/Traits/ForwardsCalls.php @@ -33,19 +33,19 @@ protected function forwardCallTo($object, $method, $parameters) throw $e; } - $this->throwBadMethodCallException($method); + static::throwBadMethodCallException($method); } } /** - * Create a bad method call exception for the given method. + * Throw a bad method call exception for the given method. * * @param string $method * @return void * * @throws \BadMethodCallException */ - protected function throwBadMethodCallException($method) + protected static function throwBadMethodCallException($method) { throw new BadMethodCallException(sprintf( 'Call to undefined method %s::%s()', static::class, $method diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index d21b14939f87..990ee6f5f01f 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -408,6 +408,15 @@ public function testGlobalMacrosAreCalledOnBuilder() $this->assertEquals($builder->bam(), $builder->getQuery()); } + /** + * @expectedException \BadMethodCallException + * @expectedExceptionMessage Call to undefined method Illuminate\Database\Eloquent\Builder::missingMacro() + */ + public function testMissingStaticMacrosThrowsProperException() + { + Builder::missingMacro(); + } + public function testGetModelsProperlyHydratesModels() { $builder = m::mock('Illuminate\Database\Eloquent\Builder[get]', [$this->getMockQueryBuilder()]); diff --git a/tests/Support/ForwardsCallsTest.php b/tests/Support/ForwardsCallsTest.php index 1b4098fb152a..fda4894f27df 100644 --- a/tests/Support/ForwardsCallsTest.php +++ b/tests/Support/ForwardsCallsTest.php @@ -69,7 +69,7 @@ public function __call($method, $parameters) public function throwTestException($method) { - $this->throwBadMethodCallException($method); + static::throwBadMethodCallException($method); } } From a3749b1318b917dbbd7415a89e76b2f16077de6e Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Wed, 15 Aug 2018 17:48:05 +0200 Subject: [PATCH 0224/2459] Respect the queue when scheduling a job (if it was already set on the job) --- .../Console/Scheduling/Schedule.php | 2 + .../Integration/Console/JobSchedulingTest.php | 123 ++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 tests/Integration/Console/JobSchedulingTest.php diff --git a/src/Illuminate/Console/Scheduling/Schedule.php b/src/Illuminate/Console/Scheduling/Schedule.php index 06718b1850ee..b819f0ea2ccd 100644 --- a/src/Illuminate/Console/Scheduling/Schedule.php +++ b/src/Illuminate/Console/Scheduling/Schedule.php @@ -97,6 +97,8 @@ public function job($job, $queue = null, $connection = null) $job = is_string($job) ? resolve($job) : $job; if ($job instanceof ShouldQueue) { + $queue = $queue ?? $job->queue; + $connection = $connection ?? $job->connection; dispatch($job)->onConnection($connection)->onQueue($queue); } else { dispatch_now($job); diff --git a/tests/Integration/Console/JobSchedulingTest.php b/tests/Integration/Console/JobSchedulingTest.php new file mode 100644 index 000000000000..582f73309370 --- /dev/null +++ b/tests/Integration/Console/JobSchedulingTest.php @@ -0,0 +1,123 @@ +app->make(Schedule::class); + + // all job names were set to an empty string so that the registered shutdown function in CallbackEvent does nothing + // that function would in this test environment fire after everything was run, including the tearDown method + // (which flushes the entire container) which would then result in a ReflectionException when the container would try + // to resolve the config service (which is needed in order to resolve the cache store for the mutex that is being cleared) + $scheduler->job(JobWithDefaultQueue::class)->name('')->everyMinute(); + $scheduler->job(JobWithDefaultQueueTwo::class, 'another-queue')->name('')->everyMinute(); + $scheduler->job(JobWithoutDefaultQueue::class)->name('')->everyMinute(); + + $events = $scheduler->events(); + foreach ($events as $event) { + $event->run($this->app); + } + + Queue::assertPushedOn('test-queue', JobWithDefaultQueue::class); + Queue::assertPushedOn('another-queue', JobWithDefaultQueueTwo::class); + Queue::assertPushedOn(null, JobWithoutDefaultQueue::class); + $this->assertTrue(Queue::pushed(JobWithDefaultQueueTwo::class, function ($job, $pushedQueue) { + return $pushedQueue === 'test-queue-two'; + })->isEmpty()); + } + + public function testJobQueuingRespectsJobConnection() + { + Queue::fake(); + + /** @var Schedule $scheduler */ + $scheduler = $this->app->make(Schedule::class); + + // all job names were set to an empty string so that the registered shutdown function in CallbackEvent does nothing + // that function would in this test environment fire after everything was run, including the tearDown method + // (which flushes the entire container) which would then result in a ReflectionException when the container would try + // to resolve the config service (which is needed in order to resolve the cache store for the mutex that is being cleared) + $scheduler->job(JobWithDefaultConnection::class)->name('')->everyMinute(); + $scheduler->job(JobWithDefaultConnection::class, null, 'foo')->name('')->everyMinute(); + $scheduler->job(JobWithoutDefaultConnection::class)->name('')->everyMinute(); + $scheduler->job(JobWithoutDefaultConnection::class, null, 'bar')->name('')->everyMinute(); + + $events = $scheduler->events(); + foreach ($events as $event) { + $event->run($this->app); + } + + $this->assertSame(1, Queue::pushed(JobWithDefaultConnection::class, function (JobWithDefaultConnection $job, $pushedQueue) { + return $job->connection === 'test-connection'; + })->count()); + + $this->assertSame(1, Queue::pushed(JobWithDefaultConnection::class, function (JobWithDefaultConnection $job, $pushedQueue) { + return $job->connection === 'foo'; + })->count()); + + $this->assertSame(0, Queue::pushed(JobWithDefaultConnection::class, function (JobWithDefaultConnection $job, $pushedQueue) { + return $job->connection === null; + })->count()); + + $this->assertSame(1, Queue::pushed(JobWithoutDefaultConnection::class, function (JobWithoutDefaultConnection $job, $pushedQueue) { + return $job->connection === null; + })->count()); + + $this->assertSame(1, Queue::pushed(JobWithoutDefaultConnection::class, function (JobWithoutDefaultConnection $job, $pushedQueue) { + return $job->connection === 'bar'; + })->count()); + } +} + +class JobWithDefaultQueue implements ShouldQueue +{ + use Queueable, InteractsWithQueue; + + public function __construct() + { + $this->onQueue('test-queue'); + } +} + +class JobWithDefaultQueueTwo implements ShouldQueue +{ + use Queueable, InteractsWithQueue; + + public function __construct() + { + $this->onQueue('test-queue-two'); + } +} + +class JobWithoutDefaultQueue implements ShouldQueue +{ + use Queueable, InteractsWithQueue; +} + +class JobWithDefaultConnection implements ShouldQueue +{ + use Queueable, InteractsWithQueue; + + public function __construct() + { + $this->onConnection('test-connection'); + } +} + +class JobWithoutDefaultConnection implements ShouldQueue +{ + use Queueable, InteractsWithQueue; +} From 3c6a78d61bdcf669ea94bee92c6494055daa6d44 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Thu, 16 Aug 2018 16:54:32 +0200 Subject: [PATCH 0225/2459] switch to classes --- src/Illuminate/Database/Query/Grammars/MySqlGrammar.php | 3 ++- src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php index 38ac9cb3b43e..c3d118bd5558 100755 --- a/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php @@ -3,6 +3,7 @@ namespace Illuminate\Database\Query\Grammars; use Illuminate\Support\Arr; +use Illuminate\Support\Str; use Illuminate\Database\Query\Builder; use Illuminate\Database\Query\JsonExpression; @@ -301,7 +302,7 @@ protected function wrapValue($value) */ protected function wrapJsonSelector($value) { - $delimiter = str_contains($value, '->>') + $delimiter = Str::contains($value, '->>') ? '->>' : '->'; diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index a83869b2f433..c68710fa2007 100755 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -3,6 +3,7 @@ namespace Illuminate\Database\Schema\Grammars; use RuntimeException; +use Illuminate\Support\Arr; use Illuminate\Support\Fluent; use Doctrine\DBAL\Schema\Index; use Illuminate\Database\Connection; @@ -332,7 +333,7 @@ public function compileRenameIndex(Blueprint $blueprint, Fluent $command, Connec $indexes = $schemaManager->listTableIndexes($this->getTablePrefix().$blueprint->getTable()); - $index = array_get($indexes, $command->from); + $index = Arr::get($indexes, $command->from); if (! $index) { throw new RuntimeException("Index [{$command->from}] does not exist."); From 0aa8de80118e401413fae3616f547935bdf15b4d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 16 Aug 2018 16:45:25 -0500 Subject: [PATCH 0226/2459] formatting --- src/Illuminate/Console/Scheduling/Schedule.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Schedule.php b/src/Illuminate/Console/Scheduling/Schedule.php index b819f0ea2ccd..3855f1775ce7 100644 --- a/src/Illuminate/Console/Scheduling/Schedule.php +++ b/src/Illuminate/Console/Scheduling/Schedule.php @@ -97,9 +97,9 @@ public function job($job, $queue = null, $connection = null) $job = is_string($job) ? resolve($job) : $job; if ($job instanceof ShouldQueue) { - $queue = $queue ?? $job->queue; - $connection = $connection ?? $job->connection; - dispatch($job)->onConnection($connection)->onQueue($queue); + dispatch($job) + ->onConnection($connection ?? $job->connection) + ->onQueue($queue ?? $job->queue); } else { dispatch_now($job); } From ad670c8423a5fdfc929644f63db1b7ca39a8ba59 Mon Sep 17 00:00:00 2001 From: DCzajkowski Date: Sat, 18 Aug 2018 14:17:56 +0200 Subject: [PATCH 0227/2459] Inform user when a `cache:clear` command fails --- src/Illuminate/Cache/Console/ClearCommand.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/Console/ClearCommand.php b/src/Illuminate/Cache/Console/ClearCommand.php index 34f2a4d878aa..e95517cdf189 100755 --- a/src/Illuminate/Cache/Console/ClearCommand.php +++ b/src/Illuminate/Cache/Console/ClearCommand.php @@ -64,7 +64,9 @@ public function handle() 'cache:clearing', [$this->argument('store'), $this->tags()] ); - $this->cache()->flush(); + if (! $this->cache()->flush()) { + return $this->error('Failed to clear cache. Make sure you have appropriate rights.'); + } $this->flushFacades(); From 2efb893a6b890bbc11ec6a9296219d856fb0cd87 Mon Sep 17 00:00:00 2001 From: Dariusz Czajkowski Date: Sat, 18 Aug 2018 14:58:48 +0200 Subject: [PATCH 0228/2459] Adhere to current tests --- src/Illuminate/Cache/Console/ClearCommand.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Cache/Console/ClearCommand.php b/src/Illuminate/Cache/Console/ClearCommand.php index e95517cdf189..a3e9e5901029 100755 --- a/src/Illuminate/Cache/Console/ClearCommand.php +++ b/src/Illuminate/Cache/Console/ClearCommand.php @@ -64,12 +64,14 @@ public function handle() 'cache:clearing', [$this->argument('store'), $this->tags()] ); - if (! $this->cache()->flush()) { - return $this->error('Failed to clear cache. Make sure you have appropriate rights.'); - } + $successful = $this->cache()->flush(); $this->flushFacades(); + if (! $successful) { + return $this->error('Failed to clear cache. Make sure you have appropriate rights.'); + } + $this->laravel['events']->fire( 'cache:cleared', [$this->argument('store'), $this->tags()] ); From 0afeb78bef5523ca57e2de881712f07fd5137881 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sat, 18 Aug 2018 17:45:41 -0500 Subject: [PATCH 0229/2459] formatting --- src/Illuminate/Cache/Console/ClearCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/Console/ClearCommand.php b/src/Illuminate/Cache/Console/ClearCommand.php index 99a64b8fa1f6..c70f459a2587 100755 --- a/src/Illuminate/Cache/Console/ClearCommand.php +++ b/src/Illuminate/Cache/Console/ClearCommand.php @@ -69,7 +69,7 @@ public function handle() $this->flushFacades(); if (! $successful) { - return $this->error('Failed to clear cache. Make sure you have appropriate rights.'); + return $this->error('Failed to clear cache. Make sure you have the appropriate permissions.'); } $this->laravel['events']->fire( From 435d0e9c2a3a542117e654ea5eda375afae0a6ee Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Sun, 19 Aug 2018 00:48:07 +0200 Subject: [PATCH 0230/2459] [5.7] Fix float casting (#25251) * Fix float casting * Improve float casting tests --- .../Database/Eloquent/Concerns/HasAttributes.php | 2 +- tests/Database/DatabaseEloquentModelTest.php | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 0d217b760f0b..b61321af509e 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -688,7 +688,7 @@ protected function asJson($value) */ public function fromFloat($value) { - switch ($value) { + switch ((string) $value) { case 'Infinity': return INF; case '-Infinity': diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 78d4f3279a2e..1bd28a05ecea 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -1617,17 +1617,20 @@ public function testModelAttributeCastingWithSpecialFloatValues() { $model = new EloquentModelCastingStub; + $model->floatAttribute = 0; + $this->assertSame(0.0, $model->floatAttribute); + $model->floatAttribute = 'Infinity'; - $this->assertEquals(INF, $model->floatAttribute); + $this->assertSame(INF, $model->floatAttribute); $model->floatAttribute = INF; - $this->assertEquals(INF, $model->floatAttribute); + $this->assertSame(INF, $model->floatAttribute); $model->floatAttribute = '-Infinity'; - $this->assertEquals(-INF, $model->floatAttribute); + $this->assertSame(-INF, $model->floatAttribute); $model->floatAttribute = -INF; - $this->assertEquals(-INF, $model->floatAttribute); + $this->assertSame(-INF, $model->floatAttribute); $model->floatAttribute = 'NaN'; $this->assertNan($model->floatAttribute); From 69cddedae349956c5f38455e861e3fc490d89a07 Mon Sep 17 00:00:00 2001 From: Propaganistas Date: Sun, 19 Aug 2018 11:03:41 +0200 Subject: [PATCH 0231/2459] Add guard to authentication events --- src/Illuminate/Auth/Events/Attempting.php | 11 ++++++++++- src/Illuminate/Auth/Events/Authenticated.php | 11 ++++++++++- src/Illuminate/Auth/Events/Failed.php | 11 ++++++++++- src/Illuminate/Auth/Events/Login.php | 11 ++++++++++- src/Illuminate/Auth/Events/Logout.php | 11 ++++++++++- src/Illuminate/Auth/SessionGuard.php | 16 +++++++++++----- 6 files changed, 61 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Auth/Events/Attempting.php b/src/Illuminate/Auth/Events/Attempting.php index 8353021fd70b..67d6b53ca716 100644 --- a/src/Illuminate/Auth/Events/Attempting.php +++ b/src/Illuminate/Auth/Events/Attempting.php @@ -18,16 +18,25 @@ class Attempting */ public $remember; + /** + * The guard this attempt is made to. + * + * @var string + */ + public $guard; + /** * Create a new event instance. * * @param array $credentials * @param bool $remember + * @param string $guard * @return void */ - public function __construct($credentials, $remember) + public function __construct($credentials, $remember, $guard) { $this->remember = $remember; $this->credentials = $credentials; + $this->guard = $guard; } } diff --git a/src/Illuminate/Auth/Events/Authenticated.php b/src/Illuminate/Auth/Events/Authenticated.php index f33c198d3f19..9cd8a59e55da 100644 --- a/src/Illuminate/Auth/Events/Authenticated.php +++ b/src/Illuminate/Auth/Events/Authenticated.php @@ -15,14 +15,23 @@ class Authenticated */ public $user; + /** + * The guard the user is authenticating to. + * + * @var string + */ + public $guard; + /** * Create a new event instance. * * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string $guard * @return void */ - public function __construct($user) + public function __construct($user, $guard) { $this->user = $user; + $this->guard = $guard; } } diff --git a/src/Illuminate/Auth/Events/Failed.php b/src/Illuminate/Auth/Events/Failed.php index 31e999c9edb7..cd740e79141f 100644 --- a/src/Illuminate/Auth/Events/Failed.php +++ b/src/Illuminate/Auth/Events/Failed.php @@ -18,16 +18,25 @@ class Failed */ public $credentials; + /** + * The guard the user failed to authenticated to. + * + * @var string + */ + public $guard; + /** * Create a new event instance. * * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param array $credentials + * @param string $guard * @return void */ - public function __construct($user, $credentials) + public function __construct($user, $credentials, $guard) { $this->user = $user; $this->credentials = $credentials; + $this->guard = $guard; } } diff --git a/src/Illuminate/Auth/Events/Login.php b/src/Illuminate/Auth/Events/Login.php index 881674593c94..818a261b8aac 100644 --- a/src/Illuminate/Auth/Events/Login.php +++ b/src/Illuminate/Auth/Events/Login.php @@ -22,16 +22,25 @@ class Login */ public $remember; + /** + * The guard the user authenticated to. + * + * @var string + */ + public $guard; + /** * Create a new event instance. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param bool $remember + * @param string $guard * @return void */ - public function __construct($user, $remember) + public function __construct($user, $remember, $guard) { $this->user = $user; $this->remember = $remember; + $this->guard = $guard; } } diff --git a/src/Illuminate/Auth/Events/Logout.php b/src/Illuminate/Auth/Events/Logout.php index ea788e715f4a..70ecb1de1d5e 100644 --- a/src/Illuminate/Auth/Events/Logout.php +++ b/src/Illuminate/Auth/Events/Logout.php @@ -15,14 +15,23 @@ class Logout */ public $user; + /** + * The guard to which the user was authenticated. + * + * @var string + */ + public $guard; + /** * Create a new event instance. * * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string $guard * @return void */ - public function __construct($user) + public function __construct($user, $guard) { $this->user = $user; + $this->guard = $guard; } } diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 10a82cafeea5..ccfa005dd04d 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -493,7 +493,7 @@ public function logout() } if (isset($this->events)) { - $this->events->dispatch(new Events\Logout($user)); + $this->events->dispatch(new Events\Logout($user, $this->name)); } // Once we have fired the logout event we will clear the users out of memory @@ -576,7 +576,7 @@ protected function fireAttemptEvent(array $credentials, $remember = false) { if (isset($this->events)) { $this->events->dispatch(new Events\Attempting( - $credentials, $remember + $credentials, $remember, $this->name )); } } @@ -591,7 +591,9 @@ protected function fireAttemptEvent(array $credentials, $remember = false) protected function fireLoginEvent($user, $remember = false) { if (isset($this->events)) { - $this->events->dispatch(new Events\Login($user, $remember)); + $this->events->dispatch(new Events\Login( + $user, $remember, $this->name + )); } } @@ -604,7 +606,9 @@ protected function fireLoginEvent($user, $remember = false) protected function fireAuthenticatedEvent($user) { if (isset($this->events)) { - $this->events->dispatch(new Events\Authenticated($user)); + $this->events->dispatch(new Events\Authenticated( + $user, $this->name + )); } } @@ -618,7 +622,9 @@ protected function fireAuthenticatedEvent($user) protected function fireFailedEvent($user, array $credentials) { if (isset($this->events)) { - $this->events->dispatch(new Events\Failed($user, $credentials)); + $this->events->dispatch(new Events\Failed( + $user, $credentials, $this->name + )); } } From 76da4655629262f6ae0f87ae01f8c212d3fd4295 Mon Sep 17 00:00:00 2001 From: Propaganistas Date: Sun, 19 Aug 2018 18:12:50 +0200 Subject: [PATCH 0232/2459] Pass whole Guard instance --- src/Illuminate/Auth/Events/Attempting.php | 4 ++-- src/Illuminate/Auth/Events/Authenticated.php | 4 ++-- src/Illuminate/Auth/Events/Failed.php | 4 ++-- src/Illuminate/Auth/Events/Login.php | 4 ++-- src/Illuminate/Auth/Events/Logout.php | 4 ++-- src/Illuminate/Auth/SessionGuard.php | 24 ++++++++++++++------ 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Auth/Events/Attempting.php b/src/Illuminate/Auth/Events/Attempting.php index 67d6b53ca716..97f8a7628d48 100644 --- a/src/Illuminate/Auth/Events/Attempting.php +++ b/src/Illuminate/Auth/Events/Attempting.php @@ -21,7 +21,7 @@ class Attempting /** * The guard this attempt is made to. * - * @var string + * @var \Illuminate\Contracts\Auth\StatefulGuard */ public $guard; @@ -30,7 +30,7 @@ class Attempting * * @param array $credentials * @param bool $remember - * @param string $guard + * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @return void */ public function __construct($credentials, $remember, $guard) diff --git a/src/Illuminate/Auth/Events/Authenticated.php b/src/Illuminate/Auth/Events/Authenticated.php index 9cd8a59e55da..e2994a486b42 100644 --- a/src/Illuminate/Auth/Events/Authenticated.php +++ b/src/Illuminate/Auth/Events/Authenticated.php @@ -18,7 +18,7 @@ class Authenticated /** * The guard the user is authenticating to. * - * @var string + * @var \Illuminate\Contracts\Auth\StatefulGuard */ public $guard; @@ -26,7 +26,7 @@ class Authenticated * Create a new event instance. * * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param string $guard + * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @return void */ public function __construct($user, $guard) diff --git a/src/Illuminate/Auth/Events/Failed.php b/src/Illuminate/Auth/Events/Failed.php index cd740e79141f..8cd6b172d39c 100644 --- a/src/Illuminate/Auth/Events/Failed.php +++ b/src/Illuminate/Auth/Events/Failed.php @@ -21,7 +21,7 @@ class Failed /** * The guard the user failed to authenticated to. * - * @var string + * @var \Illuminate\Contracts\Auth\StatefulGuard */ public $guard; @@ -30,7 +30,7 @@ class Failed * * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param array $credentials - * @param string $guard + * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @return void */ public function __construct($user, $credentials, $guard) diff --git a/src/Illuminate/Auth/Events/Login.php b/src/Illuminate/Auth/Events/Login.php index 818a261b8aac..cad0c88020c1 100644 --- a/src/Illuminate/Auth/Events/Login.php +++ b/src/Illuminate/Auth/Events/Login.php @@ -25,7 +25,7 @@ class Login /** * The guard the user authenticated to. * - * @var string + * @var \Illuminate\Contracts\Auth\StatefulGuard */ public $guard; @@ -34,7 +34,7 @@ class Login * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param bool $remember - * @param string $guard + * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @return void */ public function __construct($user, $remember, $guard) diff --git a/src/Illuminate/Auth/Events/Logout.php b/src/Illuminate/Auth/Events/Logout.php index 70ecb1de1d5e..62c9b078c01d 100644 --- a/src/Illuminate/Auth/Events/Logout.php +++ b/src/Illuminate/Auth/Events/Logout.php @@ -18,7 +18,7 @@ class Logout /** * The guard to which the user was authenticated. * - * @var string + * @var \Illuminate\Contracts\Auth\StatefulGuard */ public $guard; @@ -26,7 +26,7 @@ class Logout * Create a new event instance. * * @param \Illuminate\Contracts\Auth\Authenticatable $user - * @param string $guard + * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @return void */ public function __construct($user, $guard) diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index ccfa005dd04d..842d49efd864 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -493,7 +493,7 @@ public function logout() } if (isset($this->events)) { - $this->events->dispatch(new Events\Logout($user, $this->name)); + $this->events->dispatch(new Events\Logout($user, $this)); } // Once we have fired the logout event we will clear the users out of memory @@ -576,7 +576,7 @@ protected function fireAttemptEvent(array $credentials, $remember = false) { if (isset($this->events)) { $this->events->dispatch(new Events\Attempting( - $credentials, $remember, $this->name + $credentials, $remember, $this )); } } @@ -592,7 +592,7 @@ protected function fireLoginEvent($user, $remember = false) { if (isset($this->events)) { $this->events->dispatch(new Events\Login( - $user, $remember, $this->name + $user, $remember, $this )); } } @@ -607,7 +607,7 @@ protected function fireAuthenticatedEvent($user) { if (isset($this->events)) { $this->events->dispatch(new Events\Authenticated( - $user, $this->name + $user, $this )); } } @@ -623,7 +623,7 @@ protected function fireFailedEvent($user, array $credentials) { if (isset($this->events)) { $this->events->dispatch(new Events\Failed( - $user, $credentials, $this->name + $user, $credentials, $this )); } } @@ -645,7 +645,7 @@ public function getLastAttempted() */ public function getName() { - return 'login_'.$this->name.'_'.sha1(static::class); + return 'login_'.$this->getGuardName().'_'.sha1(static::class); } /** @@ -655,7 +655,17 @@ public function getName() */ public function getRecallerName() { - return 'remember_'.$this->name.'_'.sha1(static::class); + return 'remember_'.$this->getGuardName().'_'.sha1(static::class); + } + + /** + * Get the name of the guard, corresponding to name in authentication configuration. + * + * @return string + */ + public function getGuardName() + { + return $this->name; } /** From a07658c6e6e06fac8079a3d2be5ed4b19748d6cb Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Mon, 20 Aug 2018 09:14:43 +0200 Subject: [PATCH 0233/2459] mocking console output while testing to help making assertions --- src/Illuminate/Console/Command.php | 3 +- .../Testing/Concerns/InteractsWithConsole.php | 27 ++- .../Foundation/Testing/PendingCommand.php | 162 ++++++++++++++++++ 3 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 src/Illuminate/Foundation/Testing/PendingCommand.php diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index 497b0ca32813..ef11fc70bf00 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -163,7 +163,8 @@ protected function specifyParameters() public function run(InputInterface $input, OutputInterface $output) { return parent::run( - $this->input = $input, $this->output = new OutputStyle($input, $output) + $this->input = $input, + $this->output = $this->laravel->make(OutputStyle::class, ['input' => $input, 'output' => $output]) ); } diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index ba078b3149fe..511e235931b5 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -3,9 +3,24 @@ namespace Illuminate\Foundation\Testing\Concerns; use Illuminate\Contracts\Console\Kernel; +use Illuminate\Foundation\Testing\PendingCommand; trait InteractsWithConsole { + /** + * The list of expected questions with their answers. + * + * @var array + */ + public $expectedQuestions = []; + + /** + * The list of expected outputs. + * + * @var array + */ + public $expectedOutput = []; + /** * Call artisan command and return code. * @@ -15,6 +30,16 @@ trait InteractsWithConsole */ public function artisan($command, $parameters = []) { - return $this->app[Kernel::class]->call($command, $parameters); + $this->beforeApplicationDestroyed(function () { + if (count($this->expectedQuestions)) { + $this->fail('Question "'.array_first($this->expectedQuestions)[0].'" was never asked!'); + } + + if (count($this->expectedOutput)) { + $this->fail('Output "'.array_first($this->expectedOutput).'" was never printed!'); + } + }); + + return new PendingCommand($this, $this->app, $command, $parameters); } } diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php new file mode 100644 index 000000000000..71d41bc6bcc0 --- /dev/null +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -0,0 +1,162 @@ +test = $test; + $this->app = $app; + $this->command = $command; + $this->parameters = $parameters; + } + + /** + * Specify a question that should be asked when the command runs. + * + * @param string $question + * @param string $answer + * @return $this + */ + public function expectsQuestion($question, $answer) + { + $this->test->expectedQuestions[] = [$question, $answer]; + + return $this; + } + + /** + * Specify an output that should be printed when the command runs. + * + * @param string $output + * @return $this + */ + public function expectsOutput($output) + { + $this->test->expectedOutput[] = $output; + + return $this; + } + + /** + * Mock the application's console output. + * + * @return void + */ + private function mockTheConsoleOutput() + { + $mock = Mockery::mock(OutputStyle::class.'[askQuestion]', [ + (new ArrayInput($this->parameters)), $this->createABufferedOutputMock() + ]); + + foreach ($this->test->expectedQuestions as $i => $question) { + $mock->shouldReceive('askQuestion') + ->once() + ->ordered() + ->with(Mockery::on(function ($argument) use ($question) { + return $argument->getQuestion() == $question[0]; + })) + ->andReturnUsing(function () use ($question, $i) { + unset($this->test->expectedQuestions[$i]); + + return $question[1]; + }); + } + + $this->app->bind(OutputStyle::class, function () use ($mock) { + return $mock; + }); + } + + /** + * Create a mock for the buffered output. + * + * @return \Mockery\MockInterface + */ + private function createABufferedOutputMock() + { + $mock = Mockery::mock(BufferedOutput::class.'[doWrite]') + ->shouldAllowMockingProtectedMethods() + ->shouldIgnoreMissing(); + + foreach ($this->test->expectedOutput as $i => $output) { + $mock->shouldReceive('doWrite') + ->once() + ->ordered() + ->with($output, Mockery::any()) + ->andReturnUsing(function () use ($i) { + unset($this->test->expectedOutput[$i]); + }); + } + + return $mock; + } + + /** + * Handle the object's destruction. + * + * @return void + */ + public function __destruct() + { + $this->mockTheConsoleOutput(); + + try { + $this->app[Kernel::class]->call($this->command, $this->parameters); + } catch (NoMatchingExpectationException $e) { + if ($e->getMethodName() == 'askQuestion') { + $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked!'); + } + } catch (BadMethodCallException $e) { + if (str_contains($e->getMessage(), 'askQuestion')) { + $this->test->fail('An an expected question was asked while running the command.'); + } + } + } +} From dad6df49974afc27db923822e5128285d44349b5 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Mon, 20 Aug 2018 09:55:04 +0200 Subject: [PATCH 0234/2459] fix style and tests --- src/Illuminate/Console/Command.php | 2 +- .../Testing/Concerns/InteractsWithConsole.php | 4 +-- .../Foundation/Testing/PendingCommand.php | 36 ++++++++++++++++--- tests/Database/SeedCommandTest.php | 9 ++++- .../Console/ConsoleApplicationTest.php | 8 ++--- 5 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index ef11fc70bf00..2556eaa2719a 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -163,7 +163,7 @@ protected function specifyParameters() public function run(InputInterface $input, OutputInterface $output) { return parent::run( - $this->input = $input, + $this->input = $input, $this->output = $this->laravel->make(OutputStyle::class, ['input' => $input, 'output' => $output]) ); } diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index 511e235931b5..209fa1898895 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -9,14 +9,14 @@ trait InteractsWithConsole { /** * The list of expected questions with their answers. - * + * * @var array */ public $expectedQuestions = []; /** * The list of expected outputs. - * + * * @var array */ public $expectedOutput = []; diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index 71d41bc6bcc0..f9d7ca63811c 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -5,6 +5,7 @@ use Mockery; use Illuminate\Console\OutputStyle; use Illuminate\Contracts\Console\Kernel; +use PHPUnit\Framework\TestCase as PHPUnit; use Mockery\Exception\BadMethodCallException; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\BufferedOutput; @@ -40,16 +41,23 @@ class PendingCommand */ private $parameters; + /** + * The expected exit code. + * + * @var int + */ + private $expectedExitCode; + /** * Create a new pending console command run. * - * @param \Illuminate\Foundation\Testing\TestCase $test + * @param \PHPUnit\Framework\TestCase $test * @param \Illuminate\Foundation\Application $app * @param string $command * @param array $parameters * @return void */ - public function __construct(TestCase $test, $app, $command, $parameters) + public function __construct(PHPUnit $test, $app, $command, $parameters) { $this->test = $test; $this->app = $app; @@ -84,6 +92,19 @@ public function expectsOutput($output) return $this; } + /** + * Assert that the response has the given status code. + * + * @param int $status + * @return $this + */ + public function assertStatus($status) + { + $this->expectedExitCode = $status; + + return $this; + } + /** * Mock the application's console output. * @@ -92,7 +113,7 @@ public function expectsOutput($output) private function mockTheConsoleOutput() { $mock = Mockery::mock(OutputStyle::class.'[askQuestion]', [ - (new ArrayInput($this->parameters)), $this->createABufferedOutputMock() + (new ArrayInput($this->parameters)), $this->createABufferedOutputMock(), ]); foreach ($this->test->expectedQuestions as $i => $question) { @@ -148,7 +169,7 @@ public function __destruct() $this->mockTheConsoleOutput(); try { - $this->app[Kernel::class]->call($this->command, $this->parameters); + $exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters); } catch (NoMatchingExpectationException $e) { if ($e->getMethodName() == 'askQuestion') { $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked!'); @@ -158,5 +179,12 @@ public function __destruct() $this->test->fail('An an expected question was asked while running the command.'); } } + + if ($this->expectedExitCode != null) { + $this->test->assertTrue( + $exitCode == $this->expectedExitCode, + "Expected status code {$this->expectedExitCode} but received {$exitCode}." + ); + } } } diff --git a/tests/Database/SeedCommandTest.php b/tests/Database/SeedCommandTest.php index 5f215b7eae2c..ab21bf66f167 100644 --- a/tests/Database/SeedCommandTest.php +++ b/tests/Database/SeedCommandTest.php @@ -5,6 +5,7 @@ use Mockery; use Illuminate\Database\Seeder; use PHPUnit\Framework\TestCase; +use Illuminate\Console\OutputStyle; use Illuminate\Container\Container; use Illuminate\Database\Console\Seeds\SeedCommand; use Illuminate\Database\ConnectionResolverInterface; @@ -13,6 +14,9 @@ class SeedCommandTest extends TestCase { public function testHandle() { + $input = new \Symfony\Component\Console\Input\ArrayInput(['--force' => true, '--database' => 'sqlite']); + $output = new \Symfony\Component\Console\Output\NullOutput; + $seeder = Mockery::mock(Seeder::class); $seeder->shouldReceive('setContainer')->once()->andReturnSelf(); $seeder->shouldReceive('setCommand')->once()->andReturnSelf(); @@ -25,12 +29,15 @@ public function testHandle() $container->shouldReceive('call'); $container->shouldReceive('environment')->once()->andReturn('testing'); $container->shouldReceive('make')->with('DatabaseSeeder')->andReturn($seeder); + $container->shouldReceive('make')->with('Illuminate\Console\OutputStyle', Mockery::any())->andReturn( + new OutputStyle($input, $output) + ); $command = new SeedCommand($resolver); $command->setLaravel($container); // call run to set up IO, then fire manually. - $command->run(new \Symfony\Component\Console\Input\ArrayInput(['--force' => true, '--database' => 'sqlite']), new \Symfony\Component\Console\Output\NullOutput); + $command->run($input, $output); $command->handle(); $container->shouldHaveReceived('call')->with([$command, 'handle']); diff --git a/tests/Integration/Console/ConsoleApplicationTest.php b/tests/Integration/Console/ConsoleApplicationTest.php index cbe5413c2f97..51f2522d6954 100644 --- a/tests/Integration/Console/ConsoleApplicationTest.php +++ b/tests/Integration/Console/ConsoleApplicationTest.php @@ -19,18 +19,14 @@ public function test_artisan_call_using_command_name() { $exitCode = $this->artisan('foo:bar', [ 'id' => 1, - ]); - - $this->assertEquals($exitCode, 0); + ])->assertStatus(0); } public function test_artisan_call_using_command_class() { $exitCode = $this->artisan(FooCommandStub::class, [ 'id' => 1, - ]); - - $this->assertEquals($exitCode, 0); + ])->assertStatus(0); } /* From c0a5d9ceac18e41fdbe22a5106435a13dce72450 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Mon, 20 Aug 2018 09:56:52 +0200 Subject: [PATCH 0235/2459] fix style --- .../Foundation/Testing/Concerns/InteractsWithConsole.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index 209fa1898895..604a83e5ac9f 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -2,7 +2,6 @@ namespace Illuminate\Foundation\Testing\Concerns; -use Illuminate\Contracts\Console\Kernel; use Illuminate\Foundation\Testing\PendingCommand; trait InteractsWithConsole From fdd2ca968f78af530b328adf0aeab9cef5a3a989 Mon Sep 17 00:00:00 2001 From: Sjors Ottjes Date: Mon, 20 Aug 2018 15:27:11 +0200 Subject: [PATCH 0236/2459] add tests for the way JsonResource handles numeric keys (#25269) --- tests/Integration/Http/ResourceTest.php | 57 +++++++++++++++++++++---- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/tests/Integration/Http/ResourceTest.php b/tests/Integration/Http/ResourceTest.php index 7a9923becdfa..639c0988db79 100644 --- a/tests/Integration/Http/ResourceTest.php +++ b/tests/Integration/Http/ResourceTest.php @@ -708,21 +708,60 @@ public function work() public function test_the_resource_can_be_an_array() { - Route::get('/', function () { - return new JsonResource([ + $this->assertJsonResourceResponse([ + 'user@example.com' => 'John', + 'admin@example.com' => 'Hank', + ], [ + 'data' => [ 'user@example.com' => 'John', 'admin@example.com' => 'Hank', - ]); + ], + ]); + } + + public function test_it_strips_numeric_keys() + { + $this->assertJsonResourceResponse([ + 0 => 'John', + 1 => 'Hank', + ], ['data' => ['John', 'Hank']]); + + $this->assertJsonResourceResponse([ + 0 => 'John', + 1 => 'Hank', + 3 => 'Bill', + ], ['data' => ['John', 'Hank', 'Bill']]); + + $this->assertJsonResourceResponse([ + 5 => 'John', + 6 => 'Hank', + ], ['data' => ['John', 'Hank']]); + } + + public function test_it_strips_all_keys_if_any_of_them_are_numeric() + { + $this->assertJsonResourceResponse([ + '5' => 'John', + '6' => 'Hank', + 'a' => 'Bill', + ], ['data' => ['John', 'Hank', 'Bill']]); + + $this->assertJsonResourceResponse([ + 5 => 'John', + 6 => 'Hank', + 'a' => 'Bill', + ], ['data' => ['John', 'Hank', 'Bill']]); + } + + private function assertJsonResourceResponse($data, $expectedJson) + { + Route::get('/', function () use ($data) { + return new JsonResource($data); }); $this->withoutExceptionHandling() ->get('/', ['Accept' => 'application/json']) ->assertStatus(200) - ->assertJson([ - 'data' => [ - 'user@example.com' => 'John', - 'admin@example.com' => 'Hank', - ], - ]); + ->assertExactJson($expectedJson); } } From f5d8c0a673aa9fc6cd94aa4858a0027fe550a22e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 20 Aug 2018 08:34:02 -0500 Subject: [PATCH 0237/2459] adjust argument order --- src/Illuminate/Auth/Events/Attempting.php | 20 ++++++++-------- src/Illuminate/Auth/Events/Authenticated.php | 16 ++++++------- src/Illuminate/Auth/Events/Failed.php | 20 ++++++++-------- src/Illuminate/Auth/Events/Login.php | 20 ++++++++-------- src/Illuminate/Auth/Events/Logout.php | 16 ++++++------- src/Illuminate/Auth/SessionGuard.php | 24 ++++++-------------- 6 files changed, 53 insertions(+), 63 deletions(-) diff --git a/src/Illuminate/Auth/Events/Attempting.php b/src/Illuminate/Auth/Events/Attempting.php index 97f8a7628d48..c7c8437db964 100644 --- a/src/Illuminate/Auth/Events/Attempting.php +++ b/src/Illuminate/Auth/Events/Attempting.php @@ -4,6 +4,13 @@ class Attempting { + /** + * The authentication guard implementation. + * + * @var \Illuminate\Contracts\Auth\StatefulGuard + */ + public $guard; + /** * The credentials for the user. * @@ -18,25 +25,18 @@ class Attempting */ public $remember; - /** - * The guard this attempt is made to. - * - * @var \Illuminate\Contracts\Auth\StatefulGuard - */ - public $guard; - /** * Create a new event instance. * + * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @param array $credentials * @param bool $remember - * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @return void */ - public function __construct($credentials, $remember, $guard) + public function __construct($guard, $credentials, $remember) { + $this->guard = $guard; $this->remember = $remember; $this->credentials = $credentials; - $this->guard = $guard; } } diff --git a/src/Illuminate/Auth/Events/Authenticated.php b/src/Illuminate/Auth/Events/Authenticated.php index e2994a486b42..a674ec8fcd6d 100644 --- a/src/Illuminate/Auth/Events/Authenticated.php +++ b/src/Illuminate/Auth/Events/Authenticated.php @@ -9,27 +9,27 @@ class Authenticated use SerializesModels; /** - * The authenticated user. + * The authentication guard implementation. * - * @var \Illuminate\Contracts\Auth\Authenticatable + * @var \Illuminate\Contracts\Auth\StatefulGuard */ - public $user; + public $guard; /** - * The guard the user is authenticating to. + * The authenticated user. * - * @var \Illuminate\Contracts\Auth\StatefulGuard + * @var \Illuminate\Contracts\Auth\Authenticatable */ - public $guard; + public $user; /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param \Illuminate\Contracts\Auth\StatefulGuard $guard + * @param \Illuminate\Contracts\Auth\Authenticatable $user * @return void */ - public function __construct($user, $guard) + public function __construct($guard, $user) { $this->user = $user; $this->guard = $guard; diff --git a/src/Illuminate/Auth/Events/Failed.php b/src/Illuminate/Auth/Events/Failed.php index 8cd6b172d39c..8341d4691b44 100644 --- a/src/Illuminate/Auth/Events/Failed.php +++ b/src/Illuminate/Auth/Events/Failed.php @@ -4,6 +4,13 @@ class Failed { + /** + * The authentication guard implementation. + * + * @var \Illuminate\Contracts\Auth\StatefulGuard + */ + public $guard; + /** * The user the attempter was trying to authenticate as. * @@ -18,25 +25,18 @@ class Failed */ public $credentials; - /** - * The guard the user failed to authenticated to. - * - * @var \Illuminate\Contracts\Auth\StatefulGuard - */ - public $guard; - /** * Create a new event instance. * + * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param array $credentials - * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @return void */ - public function __construct($user, $credentials, $guard) + public function __construct($guard, $user, $credentials) { $this->user = $user; - $this->credentials = $credentials; $this->guard = $guard; + $this->credentials = $credentials; } } diff --git a/src/Illuminate/Auth/Events/Login.php b/src/Illuminate/Auth/Events/Login.php index cad0c88020c1..ab587f08d244 100644 --- a/src/Illuminate/Auth/Events/Login.php +++ b/src/Illuminate/Auth/Events/Login.php @@ -8,6 +8,13 @@ class Login { use SerializesModels; + /** + * The authentication guard implementation. + * + * @var \Illuminate\Contracts\Auth\StatefulGuard + */ + public $guard; + /** * The authenticated user. * @@ -22,25 +29,18 @@ class Login */ public $remember; - /** - * The guard the user authenticated to. - * - * @var \Illuminate\Contracts\Auth\StatefulGuard - */ - public $guard; - /** * Create a new event instance. * + * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param bool $remember - * @param \Illuminate\Contracts\Auth\StatefulGuard $guard * @return void */ - public function __construct($user, $remember, $guard) + public function __construct($guard, $user, $remember) { $this->user = $user; - $this->remember = $remember; $this->guard = $guard; + $this->remember = $remember; } } diff --git a/src/Illuminate/Auth/Events/Logout.php b/src/Illuminate/Auth/Events/Logout.php index 62c9b078c01d..5e8f77ddee34 100644 --- a/src/Illuminate/Auth/Events/Logout.php +++ b/src/Illuminate/Auth/Events/Logout.php @@ -9,27 +9,27 @@ class Logout use SerializesModels; /** - * The authenticated user. + * The authenticationg guard implementation. * - * @var \Illuminate\Contracts\Auth\Authenticatable + * @var \Illuminate\Contracts\Auth\StatefulGuard */ - public $user; + public $guard; /** - * The guard to which the user was authenticated. + * The authenticated user. * - * @var \Illuminate\Contracts\Auth\StatefulGuard + * @var \Illuminate\Contracts\Auth\Authenticatable */ - public $guard; + public $user; /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param \Illuminate\Contracts\Auth\StatefulGuard $guard + * @param \Illuminate\Contracts\Auth\Authenticatable $user * @return void */ - public function __construct($user, $guard) + public function __construct($guard, $user) { $this->user = $user; $this->guard = $guard; diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 842d49efd864..f4fdc0ec91d4 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -493,7 +493,7 @@ public function logout() } if (isset($this->events)) { - $this->events->dispatch(new Events\Logout($user, $this)); + $this->events->dispatch(new Events\Logout($this, $user)); } // Once we have fired the logout event we will clear the users out of memory @@ -576,7 +576,7 @@ protected function fireAttemptEvent(array $credentials, $remember = false) { if (isset($this->events)) { $this->events->dispatch(new Events\Attempting( - $credentials, $remember, $this + $this, $credentials, $remember )); } } @@ -592,7 +592,7 @@ protected function fireLoginEvent($user, $remember = false) { if (isset($this->events)) { $this->events->dispatch(new Events\Login( - $user, $remember, $this + $this, $user, $remember )); } } @@ -607,7 +607,7 @@ protected function fireAuthenticatedEvent($user) { if (isset($this->events)) { $this->events->dispatch(new Events\Authenticated( - $user, $this + $this, $user )); } } @@ -623,7 +623,7 @@ protected function fireFailedEvent($user, array $credentials) { if (isset($this->events)) { $this->events->dispatch(new Events\Failed( - $user, $credentials, $this + $this, $user, $credentials )); } } @@ -645,7 +645,7 @@ public function getLastAttempted() */ public function getName() { - return 'login_'.$this->getGuardName().'_'.sha1(static::class); + return 'login_'.$this->name.'_'.sha1(static::class); } /** @@ -655,17 +655,7 @@ public function getName() */ public function getRecallerName() { - return 'remember_'.$this->getGuardName().'_'.sha1(static::class); - } - - /** - * Get the name of the guard, corresponding to name in authentication configuration. - * - * @return string - */ - public function getGuardName() - { - return $this->name; + return 'remember_'.$this->name.'_'.sha1(static::class); } /** From ad34b8d4eb0d1c76d55ed3173a33f6fa32ead1d4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 20 Aug 2018 08:46:18 -0500 Subject: [PATCH 0238/2459] formatting --- src/Illuminate/Contracts/Validation/Validator.php | 14 +++++++------- .../Foundation/Validation/ValidatesRequests.php | 6 +++--- src/Illuminate/Validation/Validator.php | 11 ++++------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Contracts/Validation/Validator.php b/src/Illuminate/Contracts/Validation/Validator.php index 56d6fbc9b8f6..b69942b5f013 100644 --- a/src/Illuminate/Contracts/Validation/Validator.php +++ b/src/Illuminate/Contracts/Validation/Validator.php @@ -6,6 +6,13 @@ interface Validator extends MessageProvider { + /** + * Run the validator's rules against its data. + * + * @return array + */ + public function validate(); + /** * Determine if the data fails the validation rules. * @@ -44,11 +51,4 @@ public function after($callback); * @return \Illuminate\Support\MessageBag */ public function errors(); - - /** - * Run the validator's rules against its data. - * - * @return array - */ - public function validate(); } diff --git a/src/Illuminate/Foundation/Validation/ValidatesRequests.php b/src/Illuminate/Foundation/Validation/ValidatesRequests.php index cf5d75ad1ab4..1446c0b256a6 100644 --- a/src/Illuminate/Foundation/Validation/ValidatesRequests.php +++ b/src/Illuminate/Foundation/Validation/ValidatesRequests.php @@ -38,9 +38,9 @@ public function validateWith($validator, Request $request = null) public function validate(Request $request, array $rules, array $messages = [], array $customAttributes = []) { - $validator = $this->getValidationFactory()->make($request->all(), $rules, $messages, $customAttributes); - - return $validator->validate(); + return $this->getValidationFactory()->make( + $request->all(), $rules, $messages, $customAttributes + )->validate(); } /** diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 96ec026066b6..415118a0bc3b 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -308,15 +308,12 @@ public function validate() $results = []; - $keys = array_keys($this->getRules()); - $input = $this->getData(); + $missingValue = Str::random(10); - $placeholder = new \stdClass(); + foreach (array_keys($this->getRules()) as $key) { + $value = data_get($this->getData(), $key, $missingValue); - foreach ($keys as $key) { - $value = data_get($input, $key, $placeholder); - - if ($value !== $placeholder) { + if ($value !== $missingValue) { Arr::set($results, $key, $value); } } From 4ea0cb79c370f3d8e06005ce2b6bd0220b7ab240 Mon Sep 17 00:00:00 2001 From: Sjors Ottjes Date: Thu, 23 Aug 2018 14:44:28 +0200 Subject: [PATCH 0239/2459] Update InteractsWithDatabase.php (#25304) --- .../Foundation/Testing/Concerns/InteractsWithDatabase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithDatabase.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithDatabase.php index 7c30907ed4ce..b12e960e6829 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithDatabase.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithDatabase.php @@ -84,7 +84,7 @@ protected function getConnection($connection = null) */ public function seed($class = 'DatabaseSeeder') { - $this->artisan('db:seed', ['--class' => $class]); + $this->artisan('db:seed', ['--class' => $class, '--no-interaction' => true]); return $this; } From b298de2cf10a9828162d502a1f6b92089aadee18 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 24 Aug 2018 08:57:05 -0500 Subject: [PATCH 0240/2459] wip --- .../Database/Eloquent/Concerns/HasEvents.php | 2 +- tests/Database/DatabaseEloquentModelTest.php | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php b/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php index 2f6def1ecbf2..720266d0f754 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php @@ -148,7 +148,7 @@ protected function fireModelEvent($event, $halt = true) // First, we will get the proper method to call on the event dispatcher, and then we // will attempt to fire a custom, object based event for the given event. If that // returns a result we can return that result, or we'll call the string events. - $method = $halt ? 'until' : 'fire'; + $method = $halt ? 'until' : 'dispatch'; $result = $this->filterModelEventResults( $this->fireCustomModelEvent($event, $method) diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 1bd28a05ecea..81fd970cf033 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -236,8 +236,8 @@ public function testUpdateProcess() $model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher')); $events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($model), $model)->andReturn(true); $events->shouldReceive('until')->once()->with('eloquent.updating: '.get_class($model), $model)->andReturn(true); - $events->shouldReceive('fire')->once()->with('eloquent.updated: '.get_class($model), $model)->andReturn(true); - $events->shouldReceive('fire')->once()->with('eloquent.saved: '.get_class($model), $model)->andReturn(true); + $events->shouldReceive('dispatch')->once()->with('eloquent.updated: '.get_class($model), $model)->andReturn(true); + $events->shouldReceive('dispatch')->once()->with('eloquent.saved: '.get_class($model), $model)->andReturn(true); $model->id = 1; $model->foo = 'bar'; @@ -257,7 +257,7 @@ public function testUpdateProcessDoesntOverrideTimestamps() $model->expects($this->once())->method('newModelQuery')->will($this->returnValue($query)); $model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher')); $events->shouldReceive('until'); - $events->shouldReceive('fire'); + $events->shouldReceive('dispatch'); $model->id = 1; $model->syncOriginal(); @@ -334,8 +334,8 @@ public function testUpdateUsesOldPrimaryKey() $model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher')); $events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($model), $model)->andReturn(true); $events->shouldReceive('until')->once()->with('eloquent.updating: '.get_class($model), $model)->andReturn(true); - $events->shouldReceive('fire')->once()->with('eloquent.updated: '.get_class($model), $model)->andReturn(true); - $events->shouldReceive('fire')->once()->with('eloquent.saved: '.get_class($model), $model)->andReturn(true); + $events->shouldReceive('dispatch')->once()->with('eloquent.updated: '.get_class($model), $model)->andReturn(true); + $events->shouldReceive('dispatch')->once()->with('eloquent.saved: '.get_class($model), $model)->andReturn(true); $model->id = 1; $model->syncOriginal(); @@ -466,8 +466,8 @@ public function testInsertProcess() $model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher')); $events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($model), $model)->andReturn(true); $events->shouldReceive('until')->once()->with('eloquent.creating: '.get_class($model), $model)->andReturn(true); - $events->shouldReceive('fire')->once()->with('eloquent.created: '.get_class($model), $model); - $events->shouldReceive('fire')->once()->with('eloquent.saved: '.get_class($model), $model); + $events->shouldReceive('dispatch')->once()->with('eloquent.created: '.get_class($model), $model); + $events->shouldReceive('dispatch')->once()->with('eloquent.saved: '.get_class($model), $model); $model->name = 'taylor'; $model->exists = false; @@ -486,8 +486,8 @@ public function testInsertProcess() $model->setEventDispatcher($events = m::mock('Illuminate\Contracts\Events\Dispatcher')); $events->shouldReceive('until')->once()->with('eloquent.saving: '.get_class($model), $model)->andReturn(true); $events->shouldReceive('until')->once()->with('eloquent.creating: '.get_class($model), $model)->andReturn(true); - $events->shouldReceive('fire')->once()->with('eloquent.created: '.get_class($model), $model); - $events->shouldReceive('fire')->once()->with('eloquent.saved: '.get_class($model), $model); + $events->shouldReceive('dispatch')->once()->with('eloquent.created: '.get_class($model), $model); + $events->shouldReceive('dispatch')->once()->with('eloquent.saved: '.get_class($model), $model); $model->name = 'taylor'; $model->exists = false; From 37e46951c400775a3ac3560318527473e6118f23 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 24 Aug 2018 09:07:56 -0500 Subject: [PATCH 0241/2459] formatting --- src/Illuminate/Console/Command.php | 7 +++-- .../Testing/Concerns/InteractsWithConsole.php | 12 ++++---- .../Foundation/Testing/PendingCommand.php | 29 ++++++++++--------- .../Console/ConsoleApplicationTest.php | 12 ++------ 4 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index 2556eaa2719a..112850c5dace 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -162,9 +162,12 @@ protected function specifyParameters() */ public function run(InputInterface $input, OutputInterface $output) { + $this->output = $this->laravel->make( + OutputStyle::class, ['input' => $input, 'output' => $output] + ); + return parent::run( - $this->input = $input, - $this->output = $this->laravel->make(OutputStyle::class, ['input' => $input, 'output' => $output]) + $this->input = $input, $this->output ); } diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index 604a83e5ac9f..05887d3b3600 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -7,18 +7,18 @@ trait InteractsWithConsole { /** - * The list of expected questions with their answers. + * All of the expected output lines. * * @var array */ - public $expectedQuestions = []; + public $expectedOutput = []; /** - * The list of expected outputs. + * All of the expected questions. * * @var array */ - public $expectedOutput = []; + public $expectedQuestions = []; /** * Call artisan command and return code. @@ -31,11 +31,11 @@ public function artisan($command, $parameters = []) { $this->beforeApplicationDestroyed(function () { if (count($this->expectedQuestions)) { - $this->fail('Question "'.array_first($this->expectedQuestions)[0].'" was never asked!'); + $this->fail('Question "'.array_first($this->expectedQuestions)[0].'" was not asked.'); } if (count($this->expectedOutput)) { - $this->fail('Output "'.array_first($this->expectedOutput).'" was never printed!'); + $this->fail('Output "'.array_first($this->expectedOutput).'" was not printed.'); } }); diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index f9d7ca63811c..cd07f1bd1e22 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -3,11 +3,12 @@ namespace Illuminate\Foundation\Testing; use Mockery; +use Illuminate\Support\Str; use Illuminate\Console\OutputStyle; use Illuminate\Contracts\Console\Kernel; -use PHPUnit\Framework\TestCase as PHPUnit; use Mockery\Exception\BadMethodCallException; use Symfony\Component\Console\Input\ArrayInput; +use PHPUnit\Framework\TestCase as PHPUnitTestCase; use Symfony\Component\Console\Output\BufferedOutput; use Mockery\Exception\NoMatchingExpectationException; @@ -25,28 +26,28 @@ class PendingCommand * * @var \Illuminate\Foundation\Application */ - private $app; + protected $app; /** * The command to run. * * @var string */ - private $command; + protected $command; /** * The parameters to pass to the command. * * @var array */ - private $parameters; + protected $parameters; /** * The expected exit code. * * @var int */ - private $expectedExitCode; + protected $expectedExitCode; /** * Create a new pending console command run. @@ -57,10 +58,10 @@ class PendingCommand * @param array $parameters * @return void */ - public function __construct(PHPUnit $test, $app, $command, $parameters) + public function __construct(PHPUnitTestCase $test, $app, $command, $parameters) { - $this->test = $test; $this->app = $app; + $this->test = $test; $this->command = $command; $this->parameters = $parameters; } @@ -80,7 +81,7 @@ public function expectsQuestion($question, $answer) } /** - * Specify an output that should be printed when the command runs. + * Specify output that should be printed when the command runs. * * @param string $output * @return $this @@ -98,7 +99,7 @@ public function expectsOutput($output) * @param int $status * @return $this */ - public function assertStatus($status) + public function expectsExitCode($status) { $this->expectedExitCode = $status; @@ -110,7 +111,7 @@ public function assertStatus($status) * * @return void */ - private function mockTheConsoleOutput() + protected function mockConsoleOutput() { $mock = Mockery::mock(OutputStyle::class.'[askQuestion]', [ (new ArrayInput($this->parameters)), $this->createABufferedOutputMock(), @@ -166,17 +167,17 @@ private function createABufferedOutputMock() */ public function __destruct() { - $this->mockTheConsoleOutput(); + $this->mockConsoleOutput(); try { $exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters); } catch (NoMatchingExpectationException $e) { if ($e->getMethodName() == 'askQuestion') { - $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked!'); + $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked.'); } } catch (BadMethodCallException $e) { - if (str_contains($e->getMessage(), 'askQuestion')) { - $this->test->fail('An an expected question was asked while running the command.'); + if (Str::contains($e->getMessage(), 'askQuestion')) { + $this->test->fail('An expected question was asked while running the command.'); } } diff --git a/tests/Integration/Console/ConsoleApplicationTest.php b/tests/Integration/Console/ConsoleApplicationTest.php index 51f2522d6954..43b6e37dc853 100644 --- a/tests/Integration/Console/ConsoleApplicationTest.php +++ b/tests/Integration/Console/ConsoleApplicationTest.php @@ -19,23 +19,15 @@ public function test_artisan_call_using_command_name() { $exitCode = $this->artisan('foo:bar', [ 'id' => 1, - ])->assertStatus(0); + ])->expectsExitCode(0); } public function test_artisan_call_using_command_class() { $exitCode = $this->artisan(FooCommandStub::class, [ 'id' => 1, - ])->assertStatus(0); + ])->expectsExitCode(0); } - - /* - * @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException - */ - // public function test_artisan_call_invalid_command_name() - // { - // $this->artisan('foo:bars'); - // } } class FooCommandStub extends Command From e1718b5cfeb1d33e3644fab164be2e0001032578 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 24 Aug 2018 09:09:54 -0500 Subject: [PATCH 0242/2459] formatting --- src/Illuminate/Foundation/Testing/PendingCommand.php | 8 ++++---- tests/Integration/Console/ConsoleApplicationTest.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index cd07f1bd1e22..15caa84fde36 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -94,14 +94,14 @@ public function expectsOutput($output) } /** - * Assert that the response has the given status code. + * Assert that the command has the given exit code. * - * @param int $status + * @param int $exitCode * @return $this */ - public function expectsExitCode($status) + public function assertExitCode($exitCode) { - $this->expectedExitCode = $status; + $this->expectedExitCode = $exitCode; return $this; } diff --git a/tests/Integration/Console/ConsoleApplicationTest.php b/tests/Integration/Console/ConsoleApplicationTest.php index 43b6e37dc853..47cbce569ec6 100644 --- a/tests/Integration/Console/ConsoleApplicationTest.php +++ b/tests/Integration/Console/ConsoleApplicationTest.php @@ -19,14 +19,14 @@ public function test_artisan_call_using_command_name() { $exitCode = $this->artisan('foo:bar', [ 'id' => 1, - ])->expectsExitCode(0); + ])->assertExitCode(0); } public function test_artisan_call_using_command_class() { $exitCode = $this->artisan(FooCommandStub::class, [ 'id' => 1, - ])->expectsExitCode(0); + ])->assertExitCode(0); } } From ccb9d6c311bdfa8d22e32131f3e5474d588415ac Mon Sep 17 00:00:00 2001 From: KyleKatarn Date: Fri, 24 Aug 2018 18:29:50 +0200 Subject: [PATCH 0243/2459] Upgrade Carbon to version 2 and allow custom date handling --- composer.json | 2 +- src/Illuminate/Console/Scheduling/Event.php | 3 +- .../Console/Scheduling/ScheduleRunCommand.php | 4 +- .../Eloquent/Concerns/HasAttributes.php | 14 +- .../Eloquent/Concerns/HasTimestamps.php | 4 +- .../Exceptions/MaintenanceModeException.php | 5 +- .../Foundation/Testing/TestCase.php | 6 +- src/Illuminate/Foundation/helpers.php | 6 +- .../Failed/DatabaseFailedJobProvider.php | 4 +- .../Session/Middleware/StartSession.php | 5 +- src/Illuminate/Support/Facades/Date.php | 178 ++++++++++++++++++ src/Illuminate/Support/InteractsWithTime.php | 2 +- src/Illuminate/Support/composer.json | 2 +- .../Concerns/ValidatesAttributes.php | 3 +- .../Mail/SendingMailWithLocaleTest.php | 2 +- .../SendingNotificationsWithLocaleTest.php | 2 +- tests/Support/DateFacadeTest.php | 107 +++++++++++ tests/Support/fixtures/CustomDateClass.php | 21 +++ 18 files changed, 343 insertions(+), 27 deletions(-) create mode 100644 src/Illuminate/Support/Facades/Date.php create mode 100644 tests/Support/DateFacadeTest.php create mode 100644 tests/Support/fixtures/CustomDateClass.php diff --git a/composer.json b/composer.json index df1aacbd3801..31264c8ad93e 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "erusev/parsedown": "^1.7", "league/flysystem": "^1.0.8", "monolog/monolog": "^1.12", - "nesbot/carbon": "^1.26.3", + "nesbot/carbon": "^1.26.3 || ^2.0", "psr/container": "^1.0", "psr/simple-cache": "^1.0", "ramsey/uuid": "^3.7", diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 0adb9bf3d6db..9aa85ddf934c 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -7,6 +7,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Carbon; use GuzzleHttp\Client as HttpClient; +use Illuminate\Support\Facades\Date; use Illuminate\Contracts\Mail\Mailer; use Symfony\Component\Process\Process; use Illuminate\Support\Traits\Macroable; @@ -691,7 +692,7 @@ public function getSummaryForDisplay() */ public function nextRunDate($currentTime = 'now', $nth = 0, $allowCurrentDate = false) { - return Carbon::instance(CronExpression::factory( + return Date::instance(CronExpression::factory( $this->getExpression() )->getNextRunDate($currentTime, $nth, $allowCurrentDate, $this->timezone)); } diff --git a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php index 21695438aa2a..1340141cc429 100644 --- a/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php +++ b/src/Illuminate/Console/Scheduling/ScheduleRunCommand.php @@ -2,8 +2,8 @@ namespace Illuminate\Console\Scheduling; -use Illuminate\Support\Carbon; use Illuminate\Console\Command; +use Illuminate\Support\Facades\Date; class ScheduleRunCommand extends Command { @@ -52,7 +52,7 @@ public function __construct(Schedule $schedule) { $this->schedule = $schedule; - $this->startedAt = Carbon::now(); + $this->startedAt = Date::now(); parent::__construct(); } diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index b61321af509e..bded35bcba8f 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -4,9 +4,11 @@ use LogicException; use DateTimeInterface; +use Carbon\CarbonInterface; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Date; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Collection as BaseCollection; @@ -734,15 +736,15 @@ protected function asDateTime($value) // If this value is already a Carbon instance, we shall just return it as is. // This prevents us having to re-instantiate a Carbon instance when we know // it already is one, which wouldn't be fulfilled by the DateTime check. - if ($value instanceof Carbon) { - return $value; + if ($value instanceof Carbon || $value instanceof CarbonInterface) { + return Date::instance($value); } // If the value is already a DateTime instance, we will just skip the rest of // these checks since they will be a waste of time, and hinder performance // when checking the field. We will just return the DateTime right away. if ($value instanceof DateTimeInterface) { - return new Carbon( + return Date::parse( $value->format('Y-m-d H:i:s.u'), $value->getTimezone() ); } @@ -751,20 +753,20 @@ protected function asDateTime($value) // and format a Carbon object from this timestamp. This allows flexibility // when defining your date fields as they might be UNIX timestamps here. if (is_numeric($value)) { - return Carbon::createFromTimestamp($value); + return Date::createFromTimestamp($value); } // If the value is in simply year, month, day format, we will instantiate the // Carbon instances from that format. Again, this provides for simple date // fields on the database, while still supporting Carbonized conversion. if ($this->isStandardDateFormat($value)) { - return Carbon::createFromFormat('Y-m-d', $value)->startOfDay(); + return Date::instance(Carbon::createFromFormat('Y-m-d', $value)->startOfDay()); } // Finally, we will just assume this date is in the format used by default on // the database connection and use that format to create the Carbon object // that is returned back out to the developers after we convert it here. - return Carbon::createFromFormat( + return Date::createFromFormat( str_replace('.v', '.u', $this->getDateFormat()), $value ); } diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php b/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php index 8e3d488edd2d..6c44a73d6de3 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasTimestamps.php @@ -2,7 +2,7 @@ namespace Illuminate\Database\Eloquent\Concerns; -use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Date; trait HasTimestamps { @@ -81,7 +81,7 @@ public function setUpdatedAt($value) */ public function freshTimestamp() { - return new Carbon; + return Date::now(); } /** diff --git a/src/Illuminate/Foundation/Http/Exceptions/MaintenanceModeException.php b/src/Illuminate/Foundation/Http/Exceptions/MaintenanceModeException.php index 6d5a2ab71f27..d9df3452165e 100644 --- a/src/Illuminate/Foundation/Http/Exceptions/MaintenanceModeException.php +++ b/src/Illuminate/Foundation/Http/Exceptions/MaintenanceModeException.php @@ -4,6 +4,7 @@ use Exception; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Date; use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; class MaintenanceModeException extends ServiceUnavailableHttpException @@ -43,12 +44,12 @@ public function __construct($time, $retryAfter = null, $message = null, Exceptio { parent::__construct($retryAfter, $message, $previous, $code); - $this->wentDownAt = Carbon::createFromTimestamp($time); + $this->wentDownAt = Date::createFromTimestamp($time); if ($retryAfter) { $this->retryAfter = $retryAfter; - $this->willBeAvailableAt = Carbon::createFromTimestamp($time)->addSeconds($this->retryAfter); + $this->willBeAvailableAt = Date::instance(Carbon::createFromTimestamp($time)->addRealSeconds($this->retryAfter)); } } } diff --git a/src/Illuminate/Foundation/Testing/TestCase.php b/src/Illuminate/Foundation/Testing/TestCase.php index 1e9d33e2077c..fe23954d17a4 100644 --- a/src/Illuminate/Foundation/Testing/TestCase.php +++ b/src/Illuminate/Foundation/Testing/TestCase.php @@ -3,7 +3,8 @@ namespace Illuminate\Foundation\Testing; use Mockery; -use Illuminate\Support\Carbon; +use Carbon\Carbon; +use Carbon\CarbonImmutable; use Illuminate\Support\Facades\Facade; use Illuminate\Database\Eloquent\Model; use Illuminate\Console\Application as Artisan; @@ -165,6 +166,9 @@ protected function tearDown() if (class_exists(Carbon::class)) { Carbon::setTestNow(); } + if (class_exists(CarbonImmutable::class)) { + CarbonImmutable::setTestNow(); + } $this->afterApplicationCreatedCallbacks = []; $this->beforeApplicationDestroyedCallbacks = []; diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index a462a0ea1e98..a1e298ba7bbe 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -1,9 +1,9 @@ manager->getSessionConfig(); - return $config['expire_on_close'] ? 0 : Carbon::now()->addMinutes($config['lifetime']); + return $config['expire_on_close'] ? 0 : Date::instance(Carbon::now()->addRealMinutes($config['lifetime'])); } /** diff --git a/src/Illuminate/Support/Facades/Date.php b/src/Illuminate/Support/Facades/Date.php new file mode 100644 index 000000000000..aea29024a98e --- /dev/null +++ b/src/Illuminate/Support/Facades/Date.php @@ -0,0 +1,178 @@ +format('Y-m-d H:i:s.u'), $date->getTimezone()); + } + } + + if (static::$interceptor) { + return call_user_func(static::$interceptor, $date); + } + + return $date; + } +} diff --git a/src/Illuminate/Support/InteractsWithTime.php b/src/Illuminate/Support/InteractsWithTime.php index 19ed3f242a62..2b617c392a5a 100644 --- a/src/Illuminate/Support/InteractsWithTime.php +++ b/src/Illuminate/Support/InteractsWithTime.php @@ -34,7 +34,7 @@ protected function availableAt($delay = 0) return $delay instanceof DateTimeInterface ? $delay->getTimestamp() - : Carbon::now()->addSeconds($delay)->getTimestamp(); + : Carbon::now()->addRealSeconds($delay)->getTimestamp(); } /** diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 722ac685ca66..12d80d9b47f8 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -18,7 +18,7 @@ "ext-mbstring": "*", "doctrine/inflector": "^1.1", "illuminate/contracts": "5.8.*", - "nesbot/carbon": "^1.24.1" + "nesbot/carbon": "^1.26.3 || ^2.0" }, "conflict": { "tightenco/collect": "<5.5.33" diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index b32f9876b714..90ea30652e73 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -12,6 +12,7 @@ use Illuminate\Support\Str; use InvalidArgumentException; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Date; use Illuminate\Validation\Rules\Exists; use Illuminate\Validation\Rules\Unique; use Illuminate\Validation\ValidationData; @@ -240,7 +241,7 @@ protected function getDateTime($value) { try { if ($this->isTestingRelativeDateTime($value)) { - return new Carbon($value); + return Date::parse($value); } return new DateTime($value); diff --git a/tests/Integration/Mail/SendingMailWithLocaleTest.php b/tests/Integration/Mail/SendingMailWithLocaleTest.php index fc98034677b0..06553a4e29ae 100644 --- a/tests/Integration/Mail/SendingMailWithLocaleTest.php +++ b/tests/Integration/Mail/SendingMailWithLocaleTest.php @@ -77,7 +77,7 @@ public function test_mail_is_sent_with_locale_updated_listeners_called() Mail::to('test@mail.com')->locale('es')->send(new TimestampTestMail); - $this->assertContains('nombre dentro de 1 día', + $this->assertRegExp('/nombre (en|dentro de) (un|1) día/', app('swift.transport')->messages()[0]->getBody() ); diff --git a/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php b/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php index 741249e51717..878b0f0093a7 100644 --- a/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php +++ b/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php @@ -147,7 +147,7 @@ public function test_mail_is_sent_with_locale_updated_listeners_called() app('swift.transport')->messages()[0]->getBody() ); - $this->assertContains('dans 1 jour', + $this->assertRegExp('/dans (1|un) jour/', app('swift.transport')->messages()[0]->getBody() ); diff --git a/tests/Support/DateFacadeTest.php b/tests/Support/DateFacadeTest.php new file mode 100644 index 000000000000..0352ff6f9661 --- /dev/null +++ b/tests/Support/DateFacadeTest.php @@ -0,0 +1,107 @@ +getTimestamp()) + ) + ); + } + + public function testIntercept() + { + $start = Carbon::now()->getTimestamp(); + $this->assertSame(Carbon::class, get_class(Date::now())); + $this->assertBetweenStartAndNow($start, Date::now()->getTimestamp()); + Date::intercept(function (Carbon $date) { + return new DateTime($date->format('Y-m-d H:i:s.u'), $date->getTimezone()); + }); + $start = Carbon::now()->getTimestamp(); + $this->assertSame(DateTime::class, get_class(Date::now())); + $this->assertBetweenStartAndNow($start, Date::now()->getTimestamp()); + } + + public function testUse() + { + $start = Carbon::now()->getTimestamp(); + $this->assertSame(Carbon::class, get_class(Date::now())); + $this->assertBetweenStartAndNow($start, Date::now()->getTimestamp()); + Date::use(DateTime::class); + $start = Carbon::now()->getTimestamp(); + $this->assertSame(DateTime::class, get_class(Date::now())); + $this->assertBetweenStartAndNow($start, Date::now()->getTimestamp()); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Date class must implement a public static instance(DateTimeInterface $date) method or implements DateTimeInterface. + */ + public function testUseWrongClass() + { + Date::use(Date::class); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Date class must implement a public static instance(DateTimeInterface $date) method or implements DateTimeInterface. + */ + public function testUseWrongString() + { + Date::use('not-a-class'); + } + + public function testCarbonImmutable() + { + if (! class_exists(CarbonImmutable::class)) { + $this->markTestSkipped('Test for Carbon 2 only'); + } + + Date::use(CarbonImmutable::class); + $this->assertSame(CarbonImmutable::class, get_class(Date::now())); + Date::use(Carbon::class); + $this->assertSame(Carbon::class, get_class(Date::now())); + Date::intercept(function (Carbon $date) { + return $date->toImmutable(); + }); + $this->assertSame(CarbonImmutable::class, get_class(Date::now())); + Date::intercept(function ($date) { + return $date; + }); + $this->assertSame(Carbon::class, get_class(Date::now())); + + Date::swap(new Factory([ + 'locale' => 'fr', + ])); + $this->assertSame('fr', Date::now()->locale); + Date::swap(null); + $this->assertSame('en', Date::now()->locale); + include_once __DIR__.'/fixtures/CustomDateClass.php'; + Date::use(\CustomDateClass::class); + $this->assertInstanceOf(\CustomDateClass::class, Date::now()); + $this->assertInstanceOf(Carbon::class, Date::now()->getOriginal()); + Date::use(Carbon::class); + } +} diff --git a/tests/Support/fixtures/CustomDateClass.php b/tests/Support/fixtures/CustomDateClass.php new file mode 100644 index 000000000000..7b806c6052ce --- /dev/null +++ b/tests/Support/fixtures/CustomDateClass.php @@ -0,0 +1,21 @@ +original = $original; + } + + public static function instance($original) + { + return new static($original); + } + + public function getOriginal() + { + return $this->original; + } +} From 4b2fe70758961cd4f8709be79c8104219b5db89d Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Sat, 25 Aug 2018 08:53:39 +0200 Subject: [PATCH 0244/2459] fix docblock --- .../Foundation/Testing/Concerns/InteractsWithConsole.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index 05887d3b3600..32488e1facc8 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -25,7 +25,7 @@ trait InteractsWithConsole * * @param string $command * @param array $parameters - * @return int + * @return \Illuminate\Foundation\Testing\PendingCommand */ public function artisan($command, $parameters = []) { From 491fb3787b08b4a9381459397a514fe7f3220dfa Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Sat, 25 Aug 2018 09:10:00 +0200 Subject: [PATCH 0245/2459] remove unneded failure message --- src/Illuminate/Foundation/Testing/PendingCommand.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index 15caa84fde36..db5e7511f1cf 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -175,10 +175,6 @@ public function __destruct() if ($e->getMethodName() == 'askQuestion') { $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked.'); } - } catch (BadMethodCallException $e) { - if (Str::contains($e->getMessage(), 'askQuestion')) { - $this->test->fail('An expected question was asked while running the command.'); - } } if ($this->expectedExitCode != null) { From 8a221bf15334cdc864632f751736cc08d95e1cbb Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Sat, 25 Aug 2018 09:02:27 +0200 Subject: [PATCH 0246/2459] Apply fixes from StyleCI (#25329) --- src/Illuminate/Foundation/Testing/PendingCommand.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index db5e7511f1cf..dd54e6f9780e 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -3,10 +3,8 @@ namespace Illuminate\Foundation\Testing; use Mockery; -use Illuminate\Support\Str; use Illuminate\Console\OutputStyle; use Illuminate\Contracts\Console\Kernel; -use Mockery\Exception\BadMethodCallException; use Symfony\Component\Console\Input\ArrayInput; use PHPUnit\Framework\TestCase as PHPUnitTestCase; use Symfony\Component\Console\Output\BufferedOutput; From 9efb55d24963d5e825ff93495545c6424f13b281 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Sat, 25 Aug 2018 15:38:32 +0200 Subject: [PATCH 0247/2459] Test Coverage - Encryption Provider (#25325) --- .../Integration/Encryption/EncryptionTest.php | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/Integration/Encryption/EncryptionTest.php diff --git a/tests/Integration/Encryption/EncryptionTest.php b/tests/Integration/Encryption/EncryptionTest.php new file mode 100644 index 000000000000..73daecf23a6e --- /dev/null +++ b/tests/Integration/Encryption/EncryptionTest.php @@ -0,0 +1,41 @@ +set('app.key', 'base64:IUHRqAQ99pZ0A1MPjbuv1D6ff3jxv0GIvS2qIW4JNU4='); + } + + protected function getPackageProviders($app) + { + return [EncryptionServiceProvider::class]; + } + + /** + * @test + */ + public function encryption_provider_bind() + { + self::assertInstanceOf(Encrypter::class, $this->app->make('encrypter')); + } + + /** + * @test + */ + public function encryption_will_not_be_instantiable_when_missing_app_key() + { + $this->expectException(RuntimeException::class); + + $this->app['config']->set('app.key', null); + + $this->app->make('encrypter'); + } +} From 94b2670c9910b90893ba39cadd649b7ac13ec09d Mon Sep 17 00:00:00 2001 From: Michael Burton Date: Sun, 26 Aug 2018 02:11:06 +0100 Subject: [PATCH 0248/2459] Add Nelson Mandela to Inspirational Quotes (#25334) --- src/Illuminate/Foundation/Inspiring.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Foundation/Inspiring.php b/src/Illuminate/Foundation/Inspiring.php index ef5836530343..cc7c7b42d32b 100644 --- a/src/Illuminate/Foundation/Inspiring.php +++ b/src/Illuminate/Foundation/Inspiring.php @@ -31,6 +31,7 @@ public static function quote() 'It is quality rather than quantity that matters. - Lucius Annaeus Seneca', 'Genius is one percent inspiration and ninety-nine percent perspiration. - Thomas Edison', 'Computer science is no more about computers than astronomy is about telescopes. - Edsger Dijkstra', + 'It always seems impossible until it is done. - Nelson Mandela', ])->random(); } } From 7d6e204ce2ba62303936fa19ec72fafbebd0a2f0 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Sun, 26 Aug 2018 15:38:58 +0200 Subject: [PATCH 0249/2459] Fix some docblocks and return in the Mailer class. (#25344) --- src/Illuminate/Mail/Mailer.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index d610f47af11d..ee0482aa5254 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -157,7 +157,7 @@ public function bcc($users) */ public function html($html, $callback) { - return $this->send(['html' => new HtmlString($html)], [], $callback); + $this->send(['html' => new HtmlString($html)], [], $callback); } /** @@ -169,7 +169,7 @@ public function html($html, $callback) */ public function raw($text, $callback) { - return $this->send(['raw' => $text], [], $callback); + $this->send(['raw' => $text], [], $callback); } /** @@ -182,7 +182,7 @@ public function raw($text, $callback) */ public function plain($view, array $data, $callback) { - return $this->send(['text' => $view], $data, $callback); + $this->send(['text' => $view], $data, $callback); } /** @@ -456,7 +456,7 @@ protected function createMessage() * Send a Swift Message instance. * * @param \Swift_Message $message - * @return void + * @return int|null */ protected function sendSwiftMessage($message) { From 41eae4924f00abee4a280fa8b645d163065d8559 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 26 Aug 2018 08:39:16 -0500 Subject: [PATCH 0250/2459] Revert "Fix some docblocks and return in the Mailer class. (#25344)" (#25345) This reverts commit 7d6e204ce2ba62303936fa19ec72fafbebd0a2f0. --- src/Illuminate/Mail/Mailer.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index ee0482aa5254..d610f47af11d 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -157,7 +157,7 @@ public function bcc($users) */ public function html($html, $callback) { - $this->send(['html' => new HtmlString($html)], [], $callback); + return $this->send(['html' => new HtmlString($html)], [], $callback); } /** @@ -169,7 +169,7 @@ public function html($html, $callback) */ public function raw($text, $callback) { - $this->send(['raw' => $text], [], $callback); + return $this->send(['raw' => $text], [], $callback); } /** @@ -182,7 +182,7 @@ public function raw($text, $callback) */ public function plain($view, array $data, $callback) { - $this->send(['text' => $view], $data, $callback); + return $this->send(['text' => $view], $data, $callback); } /** @@ -456,7 +456,7 @@ protected function createMessage() * Send a Swift Message instance. * * @param \Swift_Message $message - * @return int|null + * @return void */ protected function sendSwiftMessage($message) { From df5bd55848aaf19e6d6932ad46b9d4f0ea79d9c2 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Sun, 26 Aug 2018 15:40:00 +0200 Subject: [PATCH 0251/2459] [5.7] Add cc() method to the Mailer. (#25343) * Add cc method to the Mailer. * Update Mailer.php --- src/Illuminate/Mail/Mailer.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index d610f47af11d..2bf798a8288a 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -137,6 +137,17 @@ public function to($users) return (new PendingMail($this))->to($users); } + /** + * Begin the process of mailing a mailable class instance. + * + * @param mixed $users + * @return \Illuminate\Mail\PendingMail + */ + public function cc($users) + { + return (new PendingMail($this))->cc($users); + } + /** * Begin the process of mailing a mailable class instance. * From 32870c47ab0fa1a046dc912beecfaf2f082f47b2 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Sun, 26 Aug 2018 15:40:29 +0200 Subject: [PATCH 0252/2459] Let a command handles programmatically its hidden/visible state. (#25342) --- src/Illuminate/Console/Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Command.php b/src/Illuminate/Console/Command.php index 112850c5dace..8701ff95e2c8 100755 --- a/src/Illuminate/Console/Command.php +++ b/src/Illuminate/Console/Command.php @@ -109,7 +109,7 @@ public function __construct() // the command we'll set the arguments and the options on this command. $this->setDescription($this->description); - $this->setHidden($this->hidden); + $this->setHidden($this->isHidden()); if (! isset($this->signature)) { $this->specifyParameters(); From 2459f43f9b69382fd7a13c29ba00caf7fcf8bebd Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Sun, 26 Aug 2018 15:40:46 +0200 Subject: [PATCH 0253/2459] Let the rule handles Arraybale values set. (#25341) --- src/Illuminate/Validation/Rule.php | 10 +++++----- tests/Validation/ValidationInRuleTest.php | 5 +++++ tests/Validation/fixtures/Values.php | 13 +++++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 tests/Validation/fixtures/Values.php diff --git a/src/Illuminate/Validation/Rule.php b/src/Illuminate/Validation/Rule.php index bd54bb568f33..87e41df6b5ca 100644 --- a/src/Illuminate/Validation/Rule.php +++ b/src/Illuminate/Validation/Rule.php @@ -2,8 +2,8 @@ namespace Illuminate\Validation; -use Illuminate\Support\Collection; use Illuminate\Support\Traits\Macroable; +use Illuminate\Contracts\Support\Arrayable; class Rule { @@ -35,12 +35,12 @@ public static function exists($table, $column = 'NULL') /** * Get an in constraint builder instance. * - * @param array|string|\Illuminate\Support\Collection $values + * @param \Illuminate\Contracts\Support\Arrayable|array|string $values * @return \Illuminate\Validation\Rules\In */ public static function in($values) { - if ($values instanceof Collection) { + if ($values instanceof Arrayable) { $values = $values->toArray(); } @@ -50,12 +50,12 @@ public static function in($values) /** * Get a not_in constraint builder instance. * - * @param array|string|\Illuminate\Support\Collection $values + * @param \Illuminate\Contracts\Support\Arrayable|array|string $values * @return \Illuminate\Validation\Rules\NotIn */ public static function notIn($values) { - if ($values instanceof Collection) { + if ($values instanceof Arrayable) { $values = $values->toArray(); } diff --git a/tests/Validation/ValidationInRuleTest.php b/tests/Validation/ValidationInRuleTest.php index 9b08fda53f20..d28fdc452f0c 100644 --- a/tests/Validation/ValidationInRuleTest.php +++ b/tests/Validation/ValidationInRuleTest.php @@ -5,6 +5,7 @@ use Illuminate\Validation\Rule; use PHPUnit\Framework\TestCase; use Illuminate\Validation\Rules\In; +use Illuminate\Tests\Validation\fixtures\Values; class ValidationInRuleTest extends TestCase { @@ -30,6 +31,10 @@ public function testItCorrectlyFormatsAStringVersionOfTheRule() $this->assertEquals('in:"1","2","3","4"', (string) $rule); + $rule = Rule::in(new Values); + + $this->assertEquals('in:"1","2","3","4"', (string) $rule); + $rule = Rule::in('1', '2', '3', '4'); $this->assertEquals('in:"1","2","3","4"', (string) $rule); diff --git a/tests/Validation/fixtures/Values.php b/tests/Validation/fixtures/Values.php new file mode 100644 index 000000000000..5563f59aa0c4 --- /dev/null +++ b/tests/Validation/fixtures/Values.php @@ -0,0 +1,13 @@ + Date: Sun, 26 Aug 2018 09:51:44 -0400 Subject: [PATCH 0254/2459] [5.7] Support "geometry" type in Postgres schema grammar (#25323) * [5.7] Support "geometry" type in Postgres schema grammar * Fix issues that StyleCI identified --- .../Database/Schema/Grammars/PostgresGrammar.php | 5 ++--- tests/Database/DatabasePostgresSchemaGrammarTest.php | 9 ++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index c69ee0f8f982..49902a627bea 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -2,7 +2,6 @@ namespace Illuminate\Database\Schema\Grammars; -use RuntimeException; use Illuminate\Support\Fluent; use Illuminate\Database\Schema\Blueprint; @@ -725,11 +724,11 @@ protected function typeMacAddress(Fluent $column) * Create the column definition for a spatial Geometry type. * * @param \Illuminate\Support\Fluent $column - * @throws \RuntimeException + * @return string */ protected function typeGeometry(Fluent $column) { - throw new RuntimeException('The database driver in use does not support the Geometry spatial column type.'); + return $this->formatPostGisType('geometry'); } /** diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 8a4d4bb516e4..14c54443586a 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -702,15 +702,14 @@ public function testCompileForeign() $this->assertEquals('alter table "users" add constraint "users_parent_id_foreign" foreign key ("parent_id") references "parents" ("id") on delete cascade deferrable initially deferred', $statements[0]); } - /** - * @expectedException \RuntimeException - * @expectedExceptionMessage The database driver in use does not support the Geometry spatial column type. - */ public function testAddingGeometry() { $blueprint = new Blueprint('geo'); $blueprint->geometry('coordinates'); - $blueprint->toSql($this->getConnection(), $this->getGrammar()); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertEquals('alter table "geo" add column "coordinates" geography(geometry, 4326) not null', $statements[0]); } public function testAddingPoint() From f149fbd0fede21fc3a8c0347d1ab9ee858727bb4 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 27 Aug 2018 00:07:52 +0200 Subject: [PATCH 0255/2459] Support whereJsonLength() on SQLite --- .../Database/Query/Grammars/SQLiteGrammar.php | 15 +++++++++++++ tests/Database/DatabaseQueryBuilderTest.php | 22 +++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php index e28313b77764..1220009e1fc9 100755 --- a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php @@ -143,6 +143,21 @@ protected function dateBasedWhere($type, Builder $query, $where) return "strftime('{$type}', {$this->wrap($where['column'])}) {$where['operator']} cast({$value} as text)"; } + /** + * Compile a "JSON length" statement into SQL. + * + * @param string $column + * @param string $operator + * @param string $value + * @return string + */ + protected function compileJsonLength($column, $operator, $value) + { + list($field, $path) = $this->wrapJsonFieldAndPath($column); + + return 'json_array_length('.$field.$path.') '.$operator.' '.$value; + } + /** * Compile an insert statement into SQL. * diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 6251712c8db9..d1ee2db3184e 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2837,13 +2837,27 @@ public function testWhereJsonLengthPostgres() $this->assertEquals([1], $builder->getBindings()); } - /** - * @expectedException \RuntimeException - */ public function testWhereJsonLengthSqlite() { $builder = $this->getSQLiteBuilder(); - $builder->select('*')->from('users')->whereJsonLength('options', 0)->toSql(); + $builder->select('*')->from('users')->whereJsonLength('options', 0); + $this->assertEquals('select * from "users" where json_array_length("options") = ?', $builder->toSql()); + $this->assertEquals([0], $builder->getBindings()); + + $builder = $this->getSQLiteBuilder(); + $builder->select('*')->from('users')->whereJsonLength('users.options->languages', '>', 0); + $this->assertEquals('select * from "users" where json_array_length("users"."options", \'$."languages"\') > ?', $builder->toSql()); + $this->assertEquals([0], $builder->getBindings()); + + $builder = $this->getSQLiteBuilder(); + $builder->select('*')->from('users')->where('id', '=', 1)->orWhereJsonLength('options->languages', new Raw('0')); + $this->assertEquals('select * from "users" where "id" = ? or json_array_length("options", \'$."languages"\') = 0', $builder->toSql()); + $this->assertEquals([1], $builder->getBindings()); + + $builder = $this->getSQLiteBuilder(); + $builder->select('*')->from('users')->where('id', '=', 1)->orWhereJsonLength('options->languages', '>', new Raw('0')); + $this->assertEquals('select * from "users" where "id" = ? or json_array_length("options", \'$."languages"\') > 0', $builder->toSql()); + $this->assertEquals([1], $builder->getBindings()); } public function testWhereJsonLengthSqlServer() From 92f284017320e0792fe2726b90f4b786770d387e Mon Sep 17 00:00:00 2001 From: Yohanan Baruchel Date: Tue, 28 Aug 2018 07:57:25 +0300 Subject: [PATCH 0256/2459] Remove the getClientSize() argument on UploadedFile constructor --- src/Illuminate/Http/UploadedFile.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Http/UploadedFile.php b/src/Illuminate/Http/UploadedFile.php index f6cb27572c67..61b7c1252f18 100644 --- a/src/Illuminate/Http/UploadedFile.php +++ b/src/Illuminate/Http/UploadedFile.php @@ -116,7 +116,6 @@ public static function createFromBase(SymfonyUploadedFile $file, $test = false) $file->getPathname(), $file->getClientOriginalName(), $file->getClientMimeType(), - $file->getClientSize(), $file->getError(), $test ); From b3079f35c0470e4615a2aa3abd9a50fff412c3c5 Mon Sep 17 00:00:00 2001 From: KyleKatarn Date: Tue, 28 Aug 2018 15:42:54 +0200 Subject: [PATCH 0257/2459] Simplify facade to use swap method only --- src/Illuminate/Support/Facades/Date.php | 75 +++++++------------------ tests/Support/DateFacadeTest.php | 42 ++++---------- 2 files changed, 31 insertions(+), 86 deletions(-) diff --git a/src/Illuminate/Support/Facades/Date.php b/src/Illuminate/Support/Facades/Date.php index aea29024a98e..4586b5d6b7f6 100644 --- a/src/Illuminate/Support/Facades/Date.php +++ b/src/Illuminate/Support/Facades/Date.php @@ -2,9 +2,7 @@ namespace Illuminate\Support\Facades; -use DateTimeInterface; use ReflectionException; -use InvalidArgumentException; use Illuminate\Support\Carbon; /** @@ -85,20 +83,6 @@ */ class Date extends Facade { - /** - * Date instance class name. - * - * @var string - */ - protected static $className = Carbon::class; - - /** - * Date interceptor. - * - * @var callable - */ - protected static $interceptor; - /** * Get the registered name of the component. * @@ -111,32 +95,6 @@ protected static function getFacadeAccessor() return 'date'; } - /** - * Change the class to use for date instances. - * - * @param string $className - */ - public static function use(string $className) - { - if (! (class_exists($className) && (in_array(DateTimeInterface::class, class_implements($className)) || method_exists($className, 'instance')))) { - throw new InvalidArgumentException( - 'Date class must implement a public static instance(DateTimeInterface $date) method or implements DateTimeInterface.' - ); - } - - static::$className = $className; - } - - /** - * Set an interceptor for each date (Carbon instance). - * - * @param callable $interceptor - */ - public static function intercept(callable $interceptor) - { - static::$interceptor = $interceptor; - } - /** * Handle dynamic, static calls to the object. * @@ -149,30 +107,35 @@ public static function intercept(callable $interceptor) */ public static function __callStatic($method, $args) { + $root = null; + try { - if (static::getFacadeRoot()) { - return parent::__callStatic($method, $args); - } + $root = static::getFacadeRoot(); } catch (ReflectionException $exception) { // continue } - if (method_exists(static::$className, $method)) { - $date = static::$className::$method(...$args); - } else { + if (! $root) { + Date::swap($root = Carbon::class); + } + + if (is_callable($root)) { + return $root(Carbon::$method(...$args)); + } + + if (is_string($root)) { + if (method_exists($root, $method)) { + return $root::$method(...$args); + } /** @var Carbon $date */ $date = Carbon::$method(...$args); - if (method_exists(static::$className, 'instance')) { - $date = static::$className::instance($date); - } else { - $date = new static::$className($date->format('Y-m-d H:i:s.u'), $date->getTimezone()); + if (method_exists($root, 'instance')) { + return $root::instance($date); } - } - if (static::$interceptor) { - return call_user_func(static::$interceptor, $date); + return new $root($date->format('Y-m-d H:i:s.u'), $date->getTimezone()); } - return $date; + return parent::__callStatic($method, $args); } } diff --git a/tests/Support/DateFacadeTest.php b/tests/Support/DateFacadeTest.php index 0352ff6f9661..70566cb19c50 100644 --- a/tests/Support/DateFacadeTest.php +++ b/tests/Support/DateFacadeTest.php @@ -14,8 +14,8 @@ class DateFacadeTest extends TestCase protected function tearDown() { parent::tearDown(); - Date::use(Carbon::class); - Date::intercept(function ($date) { + Date::swap(Carbon::class); + Date::swap(function ($date) { return $date; }); } @@ -31,12 +31,12 @@ protected static function assertBetweenStartAndNow($start, $actual) ); } - public function testIntercept() + public function testSwapClosure() { $start = Carbon::now()->getTimestamp(); $this->assertSame(Carbon::class, get_class(Date::now())); $this->assertBetweenStartAndNow($start, Date::now()->getTimestamp()); - Date::intercept(function (Carbon $date) { + Date::swap(function (Carbon $date) { return new DateTime($date->format('Y-m-d H:i:s.u'), $date->getTimezone()); }); $start = Carbon::now()->getTimestamp(); @@ -44,50 +44,32 @@ public function testIntercept() $this->assertBetweenStartAndNow($start, Date::now()->getTimestamp()); } - public function testUse() + public function testSwapClassName() { $start = Carbon::now()->getTimestamp(); $this->assertSame(Carbon::class, get_class(Date::now())); $this->assertBetweenStartAndNow($start, Date::now()->getTimestamp()); - Date::use(DateTime::class); + Date::swap(DateTime::class); $start = Carbon::now()->getTimestamp(); $this->assertSame(DateTime::class, get_class(Date::now())); $this->assertBetweenStartAndNow($start, Date::now()->getTimestamp()); } - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Date class must implement a public static instance(DateTimeInterface $date) method or implements DateTimeInterface. - */ - public function testUseWrongClass() - { - Date::use(Date::class); - } - - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Date class must implement a public static instance(DateTimeInterface $date) method or implements DateTimeInterface. - */ - public function testUseWrongString() - { - Date::use('not-a-class'); - } - public function testCarbonImmutable() { if (! class_exists(CarbonImmutable::class)) { $this->markTestSkipped('Test for Carbon 2 only'); } - Date::use(CarbonImmutable::class); + Date::swap(CarbonImmutable::class); $this->assertSame(CarbonImmutable::class, get_class(Date::now())); - Date::use(Carbon::class); + Date::swap(Carbon::class); $this->assertSame(Carbon::class, get_class(Date::now())); - Date::intercept(function (Carbon $date) { + Date::swap(function (Carbon $date) { return $date->toImmutable(); }); $this->assertSame(CarbonImmutable::class, get_class(Date::now())); - Date::intercept(function ($date) { + Date::swap(function ($date) { return $date; }); $this->assertSame(Carbon::class, get_class(Date::now())); @@ -99,9 +81,9 @@ public function testCarbonImmutable() Date::swap(null); $this->assertSame('en', Date::now()->locale); include_once __DIR__.'/fixtures/CustomDateClass.php'; - Date::use(\CustomDateClass::class); + Date::swap(\CustomDateClass::class); $this->assertInstanceOf(\CustomDateClass::class, Date::now()); $this->assertInstanceOf(Carbon::class, Date::now()->getOriginal()); - Date::use(Carbon::class); + Date::swap(Carbon::class); } } From d4cb93bb9e2bf0b9ee030341c988145ecf0b0526 Mon Sep 17 00:00:00 2001 From: Dwight Watson Date: Wed, 29 Aug 2018 00:29:37 +1000 Subject: [PATCH 0258/2459] [5.7] Support and format Carbon instances for date queries (#25315) * Support and format Carbon instances for date queries * Support DateTime instead of Carbon * Use DateTimeInterface instead of DateTime * Update docblocks --- src/Illuminate/Database/Query/Builder.php | 41 ++++++++++++++----- .../Integration/Database/QueryBuilderTest.php | 5 +++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 44d82001e080..70d6ae61ad91 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -4,6 +4,7 @@ use Closure; use RuntimeException; +use DateTimeInterface; use Illuminate\Support\Arr; use Illuminate\Support\Str; use InvalidArgumentException; @@ -1060,7 +1061,7 @@ public function orWhereNotNull($column) * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @param string $boolean * @return \Illuminate\Database\Query\Builder|static */ @@ -1070,6 +1071,10 @@ public function whereDate($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + if ($value instanceof DateTimeInterface) { + $value = $value->format('Y-m-d'); + } + return $this->addDateBasedWhere('Date', $column, $operator, $value, $boolean); } @@ -1078,7 +1083,7 @@ public function whereDate($column, $operator, $value = null, $boolean = 'and') * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @return \Illuminate\Database\Query\Builder|static */ public function orWhereDate($column, $operator, $value = null) @@ -1095,7 +1100,7 @@ public function orWhereDate($column, $operator, $value = null) * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @param string $boolean * @return \Illuminate\Database\Query\Builder|static */ @@ -1105,6 +1110,10 @@ public function whereTime($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + if ($value instanceof DateTimeInterface) { + $value = $value->format('H:i:s'); + } + return $this->addDateBasedWhere('Time', $column, $operator, $value, $boolean); } @@ -1113,7 +1122,7 @@ public function whereTime($column, $operator, $value = null, $boolean = 'and') * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @return \Illuminate\Database\Query\Builder|static */ public function orWhereTime($column, $operator, $value = null) @@ -1130,7 +1139,7 @@ public function orWhereTime($column, $operator, $value = null) * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @param string $boolean * @return \Illuminate\Database\Query\Builder|static */ @@ -1140,6 +1149,10 @@ public function whereDay($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + if ($value instanceof DateTimeInterface) { + $value = $value->format('d'); + } + return $this->addDateBasedWhere('Day', $column, $operator, $value, $boolean); } @@ -1148,7 +1161,7 @@ public function whereDay($column, $operator, $value = null, $boolean = 'and') * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @return \Illuminate\Database\Query\Builder|static */ public function orWhereDay($column, $operator, $value = null) @@ -1165,7 +1178,7 @@ public function orWhereDay($column, $operator, $value = null) * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @param string $boolean * @return \Illuminate\Database\Query\Builder|static */ @@ -1175,6 +1188,10 @@ public function whereMonth($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + if ($value instanceof DateTimeInterface) { + $value = $value->format('m'); + } + return $this->addDateBasedWhere('Month', $column, $operator, $value, $boolean); } @@ -1183,7 +1200,7 @@ public function whereMonth($column, $operator, $value = null, $boolean = 'and') * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @return \Illuminate\Database\Query\Builder|static */ public function orWhereMonth($column, $operator, $value = null) @@ -1200,7 +1217,7 @@ public function orWhereMonth($column, $operator, $value = null) * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @param string $boolean * @return \Illuminate\Database\Query\Builder|static */ @@ -1210,6 +1227,10 @@ public function whereYear($column, $operator, $value = null, $boolean = 'and') $value, $operator, func_num_args() === 2 ); + if ($value instanceof DateTimeInterface) { + $value = $value->format('Y'); + } + return $this->addDateBasedWhere('Year', $column, $operator, $value, $boolean); } @@ -1218,7 +1239,7 @@ public function whereYear($column, $operator, $value = null, $boolean = 'and') * * @param string $column * @param string $operator - * @param mixed $value + * @param \DateTimeInterface|string|int $value * @return \Illuminate\Database\Query\Builder|static */ public function orWhereYear($column, $operator, $value = null) diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index 3c917d7f78c2..314220b3a6f7 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -29,26 +29,31 @@ public function setUp() public function testWhereDate() { $this->assertSame(1, DB::table('posts')->whereDate('created_at', '2018-01-02')->count()); + $this->assertSame(1, DB::table('posts')->whereDate('created_at', new Carbon('2018-01-02'))->count()); } public function testWhereDay() { $this->assertSame(1, DB::table('posts')->whereDay('created_at', '02')->count()); + $this->assertSame(1, DB::table('posts')->whereDay('created_at', new Carbon('2018-01-02'))->count()); } public function testWhereMonth() { $this->assertSame(1, DB::table('posts')->whereMonth('created_at', '01')->count()); + $this->assertSame(1, DB::table('posts')->whereMonth('created_at', new Carbon('2018-01-02'))->count()); } public function testWhereYear() { $this->assertSame(1, DB::table('posts')->whereYear('created_at', '2018')->count()); $this->assertSame(1, DB::table('posts')->whereYear('created_at', 2018)->count()); + $this->assertSame(1, DB::table('posts')->whereYear('created_at', new Carbon('2018-01-02'))->count()); } public function testWhereTime() { $this->assertSame(1, DB::table('posts')->whereTime('created_at', '03:04:05')->count()); + $this->assertSame(1, DB::table('posts')->whereTime('created_at', new Carbon('2018-01-02 03:04:05'))->count()); } } From 0788f39f29247f6506bf8cec539c8a94a7d8c8a8 Mon Sep 17 00:00:00 2001 From: Peter Lightbody Date: Tue, 28 Aug 2018 15:30:33 +0100 Subject: [PATCH 0259/2459] [5.7] Adds route resources option (#25281) * Adds route resources option * Route Resources tests --- src/Illuminate/Routing/Router.php | 10 +- tests/Routing/RouteRegistrarTest.php | 131 +++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 2d6825b8dab8..c3077b1035a4 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -287,12 +287,13 @@ public function match($methods, $uri, $action = null) * Register an array of resource controllers. * * @param array $resources + * @param array $options * @return void */ - public function resources(array $resources) + public function resources(array $resources, array $options = []) { foreach ($resources as $name => $controller) { - $this->resource($name, $controller); + $this->resource($name, $controller, $options); } } @@ -321,12 +322,13 @@ public function resource($name, $controller, array $options = []) * Register an array of API resource controllers. * * @param array $resources + * @param array $options * @return void */ - public function apiResources(array $resources) + public function apiResources(array $resources, array $options = []) { foreach ($resources as $name => $controller) { - $this->apiResource($name, $controller); + $this->apiResource($name, $controller, $options); } } diff --git a/tests/Routing/RouteRegistrarTest.php b/tests/Routing/RouteRegistrarTest.php index db16053994a4..1e94ffa6aa05 100644 --- a/tests/Routing/RouteRegistrarTest.php +++ b/tests/Routing/RouteRegistrarTest.php @@ -230,6 +230,71 @@ public function testCanRegisterResource() $this->seeMiddleware('resource-middleware'); } + public function testCanRegisterResourcesWithExceptOption() + { + $this->router->resources([ + 'resource-one' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubOne::class, + 'resource-two' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubTwo::class, + 'resource-three' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubThree::class, + ], ['except' => ['create', 'show']]); + + $this->assertCount(15, $this->router->getRoutes()); + + foreach (['one', 'two', 'three'] as $resource) { + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy')); + + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show')); + } + } + + public function testCanRegisterResourcesWithOnlyOption() + { + $this->router->resources([ + 'resource-one' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubOne::class, + 'resource-two' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubTwo::class, + 'resource-three' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubThree::class, + ], ['only' => ['create', 'show']]); + + $this->assertCount(6, $this->router->getRoutes()); + + foreach (['one', 'two', 'three'] as $resource) { + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show')); + + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy')); + } + } + + public function testCanRegisterResourcesWithoutOption() + { + $this->router->resources([ + 'resource-one' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubOne::class, + 'resource-two' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubTwo::class, + 'resource-three' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubThree::class, + ]); + + $this->assertCount(21, $this->router->getRoutes()); + + foreach (['one', 'two', 'three'] as $resource) { + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy')); + } + } + public function testCanAccessRegisteredResourceRoutesAsRouteCollection() { $resource = $this->router->middleware('resource-middleware') @@ -270,6 +335,72 @@ public function testCanExcludeMethodsOnRegisteredResource() $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.destroy')); } + public function testCanRegisterApiResourcesWithExceptOption() + { + $this->router->apiResources([ + 'resource-one' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubOne::class, + 'resource-two' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubTwo::class, + 'resource-three' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubThree::class, + ], ['except' => ['create', 'show']]); + + $this->assertCount(12, $this->router->getRoutes()); + + foreach (['one', 'two', 'three'] as $resource) { + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy')); + + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit')); + } + } + + public function testCanRegisterApiResourcesWithOnlyOption() + { + $this->router->apiResources([ + 'resource-one' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubOne::class, + 'resource-two' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubTwo::class, + 'resource-three' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubThree::class, + ], ['only' => ['index', 'show']]); + + $this->assertCount(6, $this->router->getRoutes()); + + foreach (['one', 'two', 'three'] as $resource) { + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show')); + + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit')); + } + } + + public function testCanRegisterApiResourcesWithoutOption() + { + $this->router->apiResources([ + 'resource-one' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubOne::class, + 'resource-two' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubTwo::class, + 'resource-three' => \Illuminate\Tests\Routing\RouteRegistrarControllerStubThree::class, + ]); + + $this->assertCount(15, $this->router->getRoutes()); + + foreach (['one', 'two', 'three'] as $resource) { + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update')); + $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy')); + + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create')); + $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit')); + } + } + public function testUserCanRegisterApiResource() { $this->router->apiResource('users', \Illuminate\Tests\Routing\RouteRegistrarControllerStub::class); From 1d566d0dece7f0d2e640bc257845b19ad398ed53 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Wed, 29 Aug 2018 12:50:44 +0200 Subject: [PATCH 0260/2459] Fix param docblock. (#25364) --- src/Illuminate/Support/Optional.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Optional.php b/src/Illuminate/Support/Optional.php index b25aa997b74e..5e0b7d9cb040 100644 --- a/src/Illuminate/Support/Optional.php +++ b/src/Illuminate/Support/Optional.php @@ -45,7 +45,7 @@ public function __get($key) /** * Dynamically check a property exists on the underlying object. * - * @param $name + * @param mixed $name * @return bool */ public function __isset($name) From c88acdf0880a551f3ee2a99900efbb458afef135 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Wed, 29 Aug 2018 12:50:58 +0200 Subject: [PATCH 0261/2459] Fix Builder PHPDoc (#25367) --- src/Illuminate/Database/Query/Builder.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 70d6ae61ad91..a25a54111942 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1061,7 +1061,7 @@ public function orWhereNotNull($column) * * @param string $column * @param string $operator - * @param \DateTimeInterface|string|int $value + * @param \DateTimeInterface|string $value * @param string $boolean * @return \Illuminate\Database\Query\Builder|static */ @@ -1083,7 +1083,7 @@ public function whereDate($column, $operator, $value = null, $boolean = 'and') * * @param string $column * @param string $operator - * @param \DateTimeInterface|string|int $value + * @param \DateTimeInterface|string $value * @return \Illuminate\Database\Query\Builder|static */ public function orWhereDate($column, $operator, $value = null) @@ -1100,7 +1100,7 @@ public function orWhereDate($column, $operator, $value = null) * * @param string $column * @param string $operator - * @param \DateTimeInterface|string|int $value + * @param \DateTimeInterface|string $value * @param string $boolean * @return \Illuminate\Database\Query\Builder|static */ @@ -1122,7 +1122,7 @@ public function whereTime($column, $operator, $value = null, $boolean = 'and') * * @param string $column * @param string $operator - * @param \DateTimeInterface|string|int $value + * @param \DateTimeInterface|string $value * @return \Illuminate\Database\Query\Builder|static */ public function orWhereTime($column, $operator, $value = null) @@ -1139,7 +1139,7 @@ public function orWhereTime($column, $operator, $value = null) * * @param string $column * @param string $operator - * @param \DateTimeInterface|string|int $value + * @param \DateTimeInterface|string $value * @param string $boolean * @return \Illuminate\Database\Query\Builder|static */ @@ -1161,7 +1161,7 @@ public function whereDay($column, $operator, $value = null, $boolean = 'and') * * @param string $column * @param string $operator - * @param \DateTimeInterface|string|int $value + * @param \DateTimeInterface|string $value * @return \Illuminate\Database\Query\Builder|static */ public function orWhereDay($column, $operator, $value = null) @@ -1178,7 +1178,7 @@ public function orWhereDay($column, $operator, $value = null) * * @param string $column * @param string $operator - * @param \DateTimeInterface|string|int $value + * @param \DateTimeInterface|string $value * @param string $boolean * @return \Illuminate\Database\Query\Builder|static */ @@ -1200,7 +1200,7 @@ public function whereMonth($column, $operator, $value = null, $boolean = 'and') * * @param string $column * @param string $operator - * @param \DateTimeInterface|string|int $value + * @param \DateTimeInterface|string $value * @return \Illuminate\Database\Query\Builder|static */ public function orWhereMonth($column, $operator, $value = null) From 44fd3aed28857cb31481da813e9d38c919e19c7b Mon Sep 17 00:00:00 2001 From: georgexsh Date: Thu, 30 Aug 2018 20:47:17 +0800 Subject: [PATCH 0262/2459] Queue worker stopped by SIGTERM should quit peacefully (#25369) worker shouln't send SIGKILL to itself in this case, when a worker killed with SIGKILL, process supervisor would think it is a "unclean exit", and act differently. --- src/Illuminate/Queue/Worker.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 1983723ec5f9..abbd97df55b6 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -198,10 +198,8 @@ protected function pauseWorker(WorkerOptions $options, $lastRestart) protected function stopIfNecessary(WorkerOptions $options, $lastRestart) { if ($this->shouldQuit) { - $this->kill(); - } - - if ($this->memoryExceeded($options->memory)) { + $this->stop(); + } elseif ($this->memoryExceeded($options->memory)) { $this->stop(12); } elseif ($this->queueShouldRestart($lastRestart)) { $this->stop(); From de296ad631a9ef4b2377c2dabd3e9587ab85fa1c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 31 Aug 2018 10:16:43 +0200 Subject: [PATCH 0263/2459] prefix slash in callable actions urls --- src/Illuminate/Routing/UrlGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index 98446c8d4f62..68c564ab7ac4 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -419,7 +419,7 @@ public function action($action, $parameters = [], $absolute = true) protected function formatAction($action) { if (is_array($action)) { - $action = implode('@', $action); + $action = '\\'.implode('@', $action); } if ($this->rootNamespace && ! (strpos($action, '\\') === 0)) { From 2265a8c9a110679c041da2f9bbe407e732e49071 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 31 Aug 2018 13:55:16 +0200 Subject: [PATCH 0264/2459] add new error pages --- .../Foundation/Exceptions/views/403.blade.php | 11 + .../Foundation/Exceptions/views/404.blade.php | 6 + .../Foundation/Exceptions/views/419.blade.php | 12 +- .../Foundation/Exceptions/views/429.blade.php | 10 +- .../Foundation/Exceptions/views/500.blade.php | 8 +- .../Foundation/Exceptions/views/503.blade.php | 8 +- .../Exceptions/views/layout.blade.php | 530 ++++++++++++++++-- .../Exceptions/views/legacy-layout.blade.php | 57 ++ 8 files changed, 581 insertions(+), 61 deletions(-) create mode 100644 src/Illuminate/Foundation/Exceptions/views/403.blade.php create mode 100644 src/Illuminate/Foundation/Exceptions/views/legacy-layout.blade.php diff --git a/src/Illuminate/Foundation/Exceptions/views/403.blade.php b/src/Illuminate/Foundation/Exceptions/views/403.blade.php new file mode 100644 index 000000000000..b1d0e379972b --- /dev/null +++ b/src/Illuminate/Foundation/Exceptions/views/403.blade.php @@ -0,0 +1,11 @@ +@extends('errors::layout') + +@section('code', '403') +@section('title', 'Unauthorized') + +@section('image') +
+
+@endsection + +@section('message', 'Sorry, you may not access this page.') diff --git a/src/Illuminate/Foundation/Exceptions/views/404.blade.php b/src/Illuminate/Foundation/Exceptions/views/404.blade.php index ff4eb30fb9d6..72030c74e073 100644 --- a/src/Illuminate/Foundation/Exceptions/views/404.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/404.blade.php @@ -1,5 +1,11 @@ @extends('errors::layout') +@section('code', '404') @section('title', 'Page Not Found') +@section('image') +
+
+@endsection + @section('message', 'Sorry, the page you are looking for could not be found.') diff --git a/src/Illuminate/Foundation/Exceptions/views/419.blade.php b/src/Illuminate/Foundation/Exceptions/views/419.blade.php index 84258cc946e4..9412232228fb 100644 --- a/src/Illuminate/Foundation/Exceptions/views/419.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/419.blade.php @@ -1,9 +1,11 @@ @extends('errors::layout') +@section('code', '419') @section('title', 'Page Expired') -@section('message') - The page has expired due to inactivity. -

- Please refresh and try again. -@stop +@section('image') +
+
+@endsection + +@section('message', 'Sorry, your session has expired. Please refresh and try again.') diff --git a/src/Illuminate/Foundation/Exceptions/views/429.blade.php b/src/Illuminate/Foundation/Exceptions/views/429.blade.php index fc1930fd1c3b..0c1f4864a473 100644 --- a/src/Illuminate/Foundation/Exceptions/views/429.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/429.blade.php @@ -1,5 +1,11 @@ @extends('errors::layout') -@section('title', 'Error') +@section('code', '429') +@section('title', 'Too Many Requests') -@section('message', 'Too many requests.') +@section('image') +
+
+@endsection + +@section('message', 'Sorry, you are making too many requests to our servers.') diff --git a/src/Illuminate/Foundation/Exceptions/views/500.blade.php b/src/Illuminate/Foundation/Exceptions/views/500.blade.php index 333e98801a3e..23915e9dd3b7 100644 --- a/src/Illuminate/Foundation/Exceptions/views/500.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/500.blade.php @@ -1,5 +1,11 @@ @extends('errors::layout') +@section('code', '500') @section('title', 'Error') -@section('message', 'Whoops, looks like something went wrong.') +@section('image') +
+
+@endsection + +@section('message', 'Whoops, something went wrong on our servers.') diff --git a/src/Illuminate/Foundation/Exceptions/views/503.blade.php b/src/Illuminate/Foundation/Exceptions/views/503.blade.php index 7d7d211fe126..dc19c1d9ba05 100644 --- a/src/Illuminate/Foundation/Exceptions/views/503.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/503.blade.php @@ -1,5 +1,11 @@ @extends('errors::layout') +@section('code', '503') @section('title', 'Service Unavailable') -@section('message', 'Be right back.') +@section('image') +
+
+@endsection + +@section('message', 'Sorry, we are doing some maintenance. Please check back soon.') diff --git a/src/Illuminate/Foundation/Exceptions/views/layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/layout.blade.php index 50616e93a5d0..6fb9455b927a 100644 --- a/src/Illuminate/Foundation/Exceptions/views/layout.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/layout.blade.php @@ -1,57 +1,483 @@ - + - - - - - - @yield('title') - - - - - - - - -
-
-
- @yield('message') -
-
+ } + + .font-sans { + font-family: Nunito, sans-serif; + } + + .font-light { + font-weight: 300; + } + + .font-bold { + font-weight: 700; + } + + .font-black { + font-weight: 900; + } + + .h-1 { + height: .25rem; + } + + .leading-normal { + line-height: 1.5; + } + + .m-8 { + margin: 2rem; + } + + .my-3 { + margin-top: .75rem; + margin-bottom: .75rem; + } + + .mb-8 { + margin-bottom: 2rem; + } + + .max-w-sm { + max-width: 30rem; + } + + .min-h-screen { + min-height: 100vh; + } + + .py-3 { + padding-top: .75rem; + padding-bottom: .75rem; + } + + .px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; + } + + .pb-full { + padding-bottom: 100%; + } + + .absolute { + position: absolute; + } + + .relative { + position: relative; + } + + .pin { + top: 0; + right: 0; + bottom: 0; + left: 0; + } + + .text-black { + color: #22292f; + } + + .text-grey-darkest { + color: #3d4852; + } + + .text-grey-darker { + color: #606f7b; + } + + .text-2xl { + font-size: 1.5rem; + } + + .text-5xl { + font-size: 3rem; + } + + .uppercase { + text-transform: uppercase; + } + + .antialiased { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + .tracking-wide { + letter-spacing: .05em; + } + + .w-16 { + width: 4rem; + } + + .w-full { + width: 100%; + } + + @media (min-width: 768px) { + .md\:bg-left { + background-position: left; + } + + .md\:bg-right { + background-position: right; + } + + .md\:flex { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + + .md\:my-6 { + margin-top: 1.5rem; + margin-bottom: 1.5rem; + } + + .md\:min-h-screen { + min-height: 100vh; + } + + .md\:pb-0 { + padding-bottom: 0; + } + + .md\:text-3xl { + font-size: 1.875rem; + } + + .md\:text-15xl { + font-size: 9rem; + } + + .md\:w-1\/2 { + width: 50%; + } + } + + @media (min-width: 992px) { + .lg\:bg-center { + background-position: center; + } + } + + + +
+
+
+
+ @yield('code', 'Oh no') +
+ +
+ +

+ @yield('message') +

+ +
- +
+ +
+ @yield('image') +
+
+ diff --git a/src/Illuminate/Foundation/Exceptions/views/legacy-layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/legacy-layout.blade.php new file mode 100644 index 000000000000..50616e93a5d0 --- /dev/null +++ b/src/Illuminate/Foundation/Exceptions/views/legacy-layout.blade.php @@ -0,0 +1,57 @@ + + + + + + + + @yield('title') + + + + + + + + +
+
+
+ @yield('message') +
+
+
+ + From 9abd319d0d9e7e5d0997578c2ce88410d5f52db1 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 31 Aug 2018 13:56:12 +0200 Subject: [PATCH 0265/2459] rename --- .../Foundation/Exceptions/views/403.blade.php | 2 +- .../Foundation/Exceptions/views/404.blade.php | 2 +- .../Foundation/Exceptions/views/419.blade.php | 2 +- .../Foundation/Exceptions/views/429.blade.php | 2 +- .../Foundation/Exceptions/views/500.blade.php | 2 +- .../Foundation/Exceptions/views/503.blade.php | 2 +- .../views/illustrated-layout.blade.php | 483 ++++++++++++++++ .../Exceptions/views/layout.blade.php | 530 ++---------------- .../Exceptions/views/legacy-layout.blade.php | 57 -- 9 files changed, 541 insertions(+), 541 deletions(-) create mode 100644 src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php delete mode 100644 src/Illuminate/Foundation/Exceptions/views/legacy-layout.blade.php diff --git a/src/Illuminate/Foundation/Exceptions/views/403.blade.php b/src/Illuminate/Foundation/Exceptions/views/403.blade.php index b1d0e379972b..84c65ebe0da3 100644 --- a/src/Illuminate/Foundation/Exceptions/views/403.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/403.blade.php @@ -1,4 +1,4 @@ -@extends('errors::layout') +@extends('errors::illustrated-layout') @section('code', '403') @section('title', 'Unauthorized') diff --git a/src/Illuminate/Foundation/Exceptions/views/404.blade.php b/src/Illuminate/Foundation/Exceptions/views/404.blade.php index 72030c74e073..44bddf405709 100644 --- a/src/Illuminate/Foundation/Exceptions/views/404.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/404.blade.php @@ -1,4 +1,4 @@ -@extends('errors::layout') +@extends('errors::illustrated-layout') @section('code', '404') @section('title', 'Page Not Found') diff --git a/src/Illuminate/Foundation/Exceptions/views/419.blade.php b/src/Illuminate/Foundation/Exceptions/views/419.blade.php index 9412232228fb..788ed14343a2 100644 --- a/src/Illuminate/Foundation/Exceptions/views/419.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/419.blade.php @@ -1,4 +1,4 @@ -@extends('errors::layout') +@extends('errors::illustrated-layout') @section('code', '419') @section('title', 'Page Expired') diff --git a/src/Illuminate/Foundation/Exceptions/views/429.blade.php b/src/Illuminate/Foundation/Exceptions/views/429.blade.php index 0c1f4864a473..52449c8f11b4 100644 --- a/src/Illuminate/Foundation/Exceptions/views/429.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/429.blade.php @@ -1,4 +1,4 @@ -@extends('errors::layout') +@extends('errors::illustrated-layout') @section('code', '429') @section('title', 'Too Many Requests') diff --git a/src/Illuminate/Foundation/Exceptions/views/500.blade.php b/src/Illuminate/Foundation/Exceptions/views/500.blade.php index 23915e9dd3b7..adf147e33321 100644 --- a/src/Illuminate/Foundation/Exceptions/views/500.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/500.blade.php @@ -1,4 +1,4 @@ -@extends('errors::layout') +@extends('errors::illustrated-layout') @section('code', '500') @section('title', 'Error') diff --git a/src/Illuminate/Foundation/Exceptions/views/503.blade.php b/src/Illuminate/Foundation/Exceptions/views/503.blade.php index dc19c1d9ba05..a7bd157ba6be 100644 --- a/src/Illuminate/Foundation/Exceptions/views/503.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/503.blade.php @@ -1,4 +1,4 @@ -@extends('errors::layout') +@extends('errors::illustrated-layout') @section('code', '503') @section('title', 'Service Unavailable') diff --git a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php new file mode 100644 index 000000000000..6fb9455b927a --- /dev/null +++ b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php @@ -0,0 +1,483 @@ + + + + @yield('title') + + + + + + + + + + + +
+
+
+
+ @yield('code', 'Oh no') +
+ +
+ +

+ @yield('message') +

+ + +
+
+ +
+ @yield('image') +
+
+ + diff --git a/src/Illuminate/Foundation/Exceptions/views/layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/layout.blade.php index 6fb9455b927a..50616e93a5d0 100644 --- a/src/Illuminate/Foundation/Exceptions/views/layout.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/layout.blade.php @@ -1,483 +1,57 @@ - + - - @yield('title') - - - - - - - - - - - -
-
-
-
- @yield('code', 'Oh no') -
- -
- -

- @yield('message') -

- - + } + + .position-ref { + position: relative; + } + + .content { + text-align: center; + } + + .title { + font-size: 36px; + padding: 20px; + } + + + +
+
+
+ @yield('message') +
+
-
- -
- @yield('image') -
-
- + diff --git a/src/Illuminate/Foundation/Exceptions/views/legacy-layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/legacy-layout.blade.php deleted file mode 100644 index 50616e93a5d0..000000000000 --- a/src/Illuminate/Foundation/Exceptions/views/legacy-layout.blade.php +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - @yield('title') - - - - - - - - -
-
-
- @yield('message') -
-
-
- - From 7248f29b01030041e22558343eb3fd414f710e78 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 31 Aug 2018 13:56:34 +0200 Subject: [PATCH 0266/2459] wip --- src/Illuminate/Foundation/Exceptions/views/403.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Exceptions/views/403.blade.php b/src/Illuminate/Foundation/Exceptions/views/403.blade.php index 84c65ebe0da3..055bd5a94a63 100644 --- a/src/Illuminate/Foundation/Exceptions/views/403.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/403.blade.php @@ -8,4 +8,4 @@
@endsection -@section('message', 'Sorry, you may not access this page.') +@section('message', 'Sorry, you are not authorized to access this page.') From fee9658f508af07e3fe2f36baa664aa96dd31bae Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 31 Aug 2018 14:05:57 +0200 Subject: [PATCH 0267/2459] wip --- .../Exceptions/views/illustrated-layout.blade.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php index 6fb9455b927a..1d87781f0d92 100644 --- a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php @@ -469,9 +469,11 @@ @yield('message')

- + + +
From 0bdcce2ffd8a294bdea103cceb79cd0b7505ae93 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Fri, 31 Aug 2018 19:05:14 +0200 Subject: [PATCH 0268/2459] Fix return docblock. --- src/Illuminate/Pagination/AbstractPaginator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Pagination/AbstractPaginator.php b/src/Illuminate/Pagination/AbstractPaginator.php index 6d541f481431..165100682e01 100644 --- a/src/Illuminate/Pagination/AbstractPaginator.php +++ b/src/Illuminate/Pagination/AbstractPaginator.php @@ -380,7 +380,7 @@ public function setPath($path) * Set the number of links to display on each side of current page link. * * @param int $count - * @return this + * @return $this */ public function onEachSide($count) { From e8c9723bbef9ae6a9f9ef07aee0fb93ea8610671 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Fri, 31 Aug 2018 20:58:53 +0200 Subject: [PATCH 0269/2459] [5.7] Always use FQN in docblocks. (#25394) * Always use FQN in docblocks. * Fix style. --- src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php | 2 +- src/Illuminate/Contracts/Mail/Mailer.php | 4 +--- .../Testing/Concerns/InteractsWithExceptionHandling.php | 2 +- src/Illuminate/Mail/Mailer.php | 6 +++--- src/Illuminate/Mail/SendQueuedMailable.php | 2 +- src/Illuminate/Routing/SortedMiddleware.php | 2 +- src/Illuminate/Validation/Factory.php | 2 +- 7 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php index 18a8fefbdd8e..b98d66a7ed2a 100644 --- a/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php +++ b/src/Illuminate/Broadcasting/Broadcasters/Broadcaster.php @@ -24,7 +24,7 @@ abstract class Broadcaster implements BroadcasterContract /** * The binding registrar instance. * - * @var BindingRegistrar + * @var \Illuminate\Contracts\Routing\BindingRegistrar */ protected $bindingRegistrar; diff --git a/src/Illuminate/Contracts/Mail/Mailer.php b/src/Illuminate/Contracts/Mail/Mailer.php index 008a65ba580c..5e68c32b92a8 100644 --- a/src/Illuminate/Contracts/Mail/Mailer.php +++ b/src/Illuminate/Contracts/Mail/Mailer.php @@ -2,8 +2,6 @@ namespace Illuminate\Contracts\Mail; -use Illuminate\Contracts\Mail\Mailable as MailableContract; - interface Mailer { /** @@ -34,7 +32,7 @@ public function raw($text, $callback); /** * Send a new message using a view. * - * @param string|array|MailableContract $view + * @param string|array|\Illuminate\Contracts\Mail\Mailable $view * @param array $data * @param \Closure|string $callback * @return void diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php index 6967a58c088f..efa13f3fcecd 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithExceptionHandling.php @@ -13,7 +13,7 @@ trait InteractsWithExceptionHandling /** * The original exception handler. * - * @var ExceptionHandler|null + * @var \Illuminate\Contracts\Debug\ExceptionHandler|null */ protected $originalExceptionHandler; diff --git a/src/Illuminate/Mail/Mailer.php b/src/Illuminate/Mail/Mailer.php index 2bf798a8288a..9e0e469a35bd 100755 --- a/src/Illuminate/Mail/Mailer.php +++ b/src/Illuminate/Mail/Mailer.php @@ -218,7 +218,7 @@ public function render($view, array $data = []) /** * Send a new message using a view. * - * @param string|array|MailableContract $view + * @param string|array|\Illuminate\Contracts\Mail\Mailable $view * @param array $data * @param \Closure|string $callback * @return void @@ -368,7 +368,7 @@ protected function setGlobalToAndRemoveCcAndBcc($message) /** * Queue a new e-mail message for sending. * - * @param string|array|MailableContract $view + * @param string|array|\Illuminate\Contracts\Mail\Mailable $view * @param string|null $queue * @return mixed */ @@ -411,7 +411,7 @@ public function queueOn($queue, $view) * Queue a new e-mail message for sending after (n) seconds. * * @param \DateTimeInterface|\DateInterval|int $delay - * @param string|array|MailableContract $view + * @param string|array|\Illuminate\Contracts\Mail\Mailable $view * @param string|null $queue * @return mixed */ diff --git a/src/Illuminate/Mail/SendQueuedMailable.php b/src/Illuminate/Mail/SendQueuedMailable.php index 0ed9bdeb8c2e..e9e256d104a4 100644 --- a/src/Illuminate/Mail/SendQueuedMailable.php +++ b/src/Illuminate/Mail/SendQueuedMailable.php @@ -10,7 +10,7 @@ class SendQueuedMailable /** * The mailable message instance. * - * @var Mailable + * @var \Illuminate\Mail\Mailable */ public $mailable; diff --git a/src/Illuminate/Routing/SortedMiddleware.php b/src/Illuminate/Routing/SortedMiddleware.php index ad09456770a1..6af28d57ff9b 100644 --- a/src/Illuminate/Routing/SortedMiddleware.php +++ b/src/Illuminate/Routing/SortedMiddleware.php @@ -10,7 +10,7 @@ class SortedMiddleware extends Collection * Create a new Sorted Middleware container. * * @param array $priorityMap - * @param array|Collection $middlewares + * @param array|\Illuminate\Support\Collection $middlewares * @return void */ public function __construct(array $priorityMap, $middlewares) diff --git a/src/Illuminate/Validation/Factory.php b/src/Illuminate/Validation/Factory.php index fd496942c6e4..3660af0cda48 100755 --- a/src/Illuminate/Validation/Factory.php +++ b/src/Illuminate/Validation/Factory.php @@ -69,7 +69,7 @@ class Factory implements FactoryContract /** * The Validator resolver instance. * - * @var Closure + * @var \Closure */ protected $resolver; From 9d8452da5511c72592d14a1d59abda34506d104b Mon Sep 17 00:00:00 2001 From: Patrick Brouwers Date: Sat, 1 Sep 2018 10:56:45 +0200 Subject: [PATCH 0270/2459] Translate error messsages (#25395) --- src/Illuminate/Foundation/Exceptions/views/403.blade.php | 4 ++-- src/Illuminate/Foundation/Exceptions/views/404.blade.php | 4 ++-- src/Illuminate/Foundation/Exceptions/views/419.blade.php | 4 ++-- src/Illuminate/Foundation/Exceptions/views/429.blade.php | 4 ++-- src/Illuminate/Foundation/Exceptions/views/500.blade.php | 4 ++-- src/Illuminate/Foundation/Exceptions/views/503.blade.php | 4 ++-- .../Foundation/Exceptions/views/illustrated-layout.blade.php | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Foundation/Exceptions/views/403.blade.php b/src/Illuminate/Foundation/Exceptions/views/403.blade.php index 055bd5a94a63..07754cc61df1 100644 --- a/src/Illuminate/Foundation/Exceptions/views/403.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/403.blade.php @@ -1,11 +1,11 @@ @extends('errors::illustrated-layout') @section('code', '403') -@section('title', 'Unauthorized') +@section('title', __('Unauthorized')) @section('image')
@endsection -@section('message', 'Sorry, you are not authorized to access this page.') +@section('message', __('Sorry, you are not authorized to access this page.')) diff --git a/src/Illuminate/Foundation/Exceptions/views/404.blade.php b/src/Illuminate/Foundation/Exceptions/views/404.blade.php index 44bddf405709..0398a98e0057 100644 --- a/src/Illuminate/Foundation/Exceptions/views/404.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/404.blade.php @@ -1,11 +1,11 @@ @extends('errors::illustrated-layout') @section('code', '404') -@section('title', 'Page Not Found') +@section('title', __('Page Not Found')) @section('image')
@endsection -@section('message', 'Sorry, the page you are looking for could not be found.') +@section('message', __('Sorry, the page you are looking for could not be found.')) diff --git a/src/Illuminate/Foundation/Exceptions/views/419.blade.php b/src/Illuminate/Foundation/Exceptions/views/419.blade.php index 788ed14343a2..1671bffb49df 100644 --- a/src/Illuminate/Foundation/Exceptions/views/419.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/419.blade.php @@ -1,11 +1,11 @@ @extends('errors::illustrated-layout') @section('code', '419') -@section('title', 'Page Expired') +@section('title', __('Page Expired')) @section('image')
@endsection -@section('message', 'Sorry, your session has expired. Please refresh and try again.') +@section('message', __('Sorry, your session has expired. Please refresh and try again.')) diff --git a/src/Illuminate/Foundation/Exceptions/views/429.blade.php b/src/Illuminate/Foundation/Exceptions/views/429.blade.php index 52449c8f11b4..a9f3caa53a81 100644 --- a/src/Illuminate/Foundation/Exceptions/views/429.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/429.blade.php @@ -1,11 +1,11 @@ @extends('errors::illustrated-layout') @section('code', '429') -@section('title', 'Too Many Requests') +@section('title', __('Too Many Requests')) @section('image')
@endsection -@section('message', 'Sorry, you are making too many requests to our servers.') +@section('message', __('Sorry, you are making too many requests to our servers.')) diff --git a/src/Illuminate/Foundation/Exceptions/views/500.blade.php b/src/Illuminate/Foundation/Exceptions/views/500.blade.php index adf147e33321..8c5e2d5d6891 100644 --- a/src/Illuminate/Foundation/Exceptions/views/500.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/500.blade.php @@ -1,11 +1,11 @@ @extends('errors::illustrated-layout') @section('code', '500') -@section('title', 'Error') +@section('title', __('Error')) @section('image')
@endsection -@section('message', 'Whoops, something went wrong on our servers.') +@section('message', __('Whoops, something went wrong on our servers.')) diff --git a/src/Illuminate/Foundation/Exceptions/views/503.blade.php b/src/Illuminate/Foundation/Exceptions/views/503.blade.php index a7bd157ba6be..72b057ea0f73 100644 --- a/src/Illuminate/Foundation/Exceptions/views/503.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/503.blade.php @@ -1,11 +1,11 @@ @extends('errors::illustrated-layout') @section('code', '503') -@section('title', 'Service Unavailable') +@section('title', __('Service Unavailable')) @section('image')
@endsection -@section('message', 'Sorry, we are doing some maintenance. Please check back soon.') +@section('message', __('Sorry, we are doing some maintenance. Please check back soon.')) diff --git a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php index 1d87781f0d92..0f5450f6e7c8 100644 --- a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php @@ -460,7 +460,7 @@
- @yield('code', 'Oh no') + @yield('code', __('Oh no'))
@@ -471,7 +471,7 @@
From c074c11bf172e44c5dd2e7acf753f7c1da8efca1 Mon Sep 17 00:00:00 2001 From: Sebastian De Deyne Date: Mon, 3 Sep 2018 15:53:20 +0200 Subject: [PATCH 0271/2459] Use 4 spaces in views (#25418) --- .../views/illustrated-layout.blade.php | 880 +++++++++--------- 1 file changed, 440 insertions(+), 440 deletions(-) diff --git a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php index 0f5450f6e7c8..299416e5493b 100644 --- a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php @@ -1,485 +1,485 @@ - - @yield('title') - - - - - - - - - - - -
-
-
-
- @yield('code', __('Oh no')) -
-
+ html { + -webkit-box-sizing: border-box; + box-sizing: border-box; + font-family: sans-serif; + } -

- @yield('message') -

+ *, + *::before, + *::after { + -webkit-box-sizing: inherit; + box-sizing: inherit; + } - - - -
-
+ p { + margin: 0; + } + + button { + background: transparent; + padding: 0; + } + + button:focus { + outline: 1px dotted; + outline: 5px auto -webkit-focus-ring-color; + } + + *, + *::before, + *::after { + border-width: 0; + border-style: solid; + border-color: #dae1e7; + } + + button, + [type="button"], + [type="reset"], + [type="submit"] { + border-radius: 0; + } + + button, + input { + font-family: inherit; + } + + input::-webkit-input-placeholder { + color: inherit; + opacity: .5; + } + + input:-ms-input-placeholder { + color: inherit; + opacity: .5; + } + + input::-ms-input-placeholder { + color: inherit; + opacity: .5; + } + + input::placeholder { + color: inherit; + opacity: .5; + } + + button, + [role=button] { + cursor: pointer; + } + + .bg-transparent { + background-color: transparent; + } + + .bg-white { + background-color: #fff; + } + + .bg-teal-light { + background-color: #64d5ca; + } + + .bg-blue-dark { + background-color: #2779bd; + } + + .bg-indigo-light { + background-color: #7886d7; + } + + .bg-purple-light { + background-color: #a779e9; + } + + .bg-no-repeat { + background-repeat: no-repeat; + } + + .bg-cover { + background-size: cover; + } + + .border-grey-light { + border-color: #dae1e7; + } + + .hover\:border-grey:hover { + border-color: #b8c2cc; + } + + .rounded-lg { + border-radius: .5rem; + } + + .border-2 { + border-width: 2px; + } + + .hidden { + display: none; + } + + .flex { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + + .items-center { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + } + + .justify-center { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + } + + .font-sans { + font-family: Nunito, sans-serif; + } + + .font-light { + font-weight: 300; + } + + .font-bold { + font-weight: 700; + } + + .font-black { + font-weight: 900; + } + + .h-1 { + height: .25rem; + } + + .leading-normal { + line-height: 1.5; + } + + .m-8 { + margin: 2rem; + } + + .my-3 { + margin-top: .75rem; + margin-bottom: .75rem; + } + + .mb-8 { + margin-bottom: 2rem; + } + + .max-w-sm { + max-width: 30rem; + } + + .min-h-screen { + min-height: 100vh; + } + + .py-3 { + padding-top: .75rem; + padding-bottom: .75rem; + } + + .px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; + } -
- @yield('image') -
-
- + .pb-full { + padding-bottom: 100%; + } + + .absolute { + position: absolute; + } + + .relative { + position: relative; + } + + .pin { + top: 0; + right: 0; + bottom: 0; + left: 0; + } + + .text-black { + color: #22292f; + } + + .text-grey-darkest { + color: #3d4852; + } + + .text-grey-darker { + color: #606f7b; + } + + .text-2xl { + font-size: 1.5rem; + } + + .text-5xl { + font-size: 3rem; + } + + .uppercase { + text-transform: uppercase; + } + + .antialiased { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + .tracking-wide { + letter-spacing: .05em; + } + + .w-16 { + width: 4rem; + } + + .w-full { + width: 100%; + } + + @media (min-width: 768px) { + .md\:bg-left { + background-position: left; + } + + .md\:bg-right { + background-position: right; + } + + .md\:flex { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + } + + .md\:my-6 { + margin-top: 1.5rem; + margin-bottom: 1.5rem; + } + + .md\:min-h-screen { + min-height: 100vh; + } + + .md\:pb-0 { + padding-bottom: 0; + } + + .md\:text-3xl { + font-size: 1.875rem; + } + + .md\:text-15xl { + font-size: 9rem; + } + + .md\:w-1\/2 { + width: 50%; + } + } + + @media (min-width: 992px) { + .lg\:bg-center { + background-position: center; + } + } + + + +
+
+
+
+ @yield('code', __('Oh no')) +
+ +
+ +

+ @yield('message') +

+ + + + +
+
+ +
+ @yield('image') +
+
+ From 40ccbc3497198333d3c75c51729d94bb32c77d0d Mon Sep 17 00:00:00 2001 From: Sebastian De Deyne Date: Mon, 3 Sep 2018 15:54:40 +0200 Subject: [PATCH 0272/2459] Pass authorization by default (#25417) --- src/Illuminate/Foundation/Http/FormRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index f1d617f02848..53a4ec83bd5a 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -150,7 +150,7 @@ protected function passesAuthorization() return $this->container->call([$this, 'authorize']); } - return false; + return true; } /** From b3fe47783d2a0bd6557c1744c3d711cd73c7198c Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Tue, 4 Sep 2018 15:08:26 +0200 Subject: [PATCH 0273/2459] Show maintenance message on error page (#25431) --- src/Illuminate/Foundation/Exceptions/views/503.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Exceptions/views/503.blade.php b/src/Illuminate/Foundation/Exceptions/views/503.blade.php index 72b057ea0f73..8272e0e98ef0 100644 --- a/src/Illuminate/Foundation/Exceptions/views/503.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/503.blade.php @@ -8,4 +8,4 @@
@endsection -@section('message', __('Sorry, we are doing some maintenance. Please check back soon.')) +@section('message', __($exception->getMessage() ?: 'Sorry, we are doing some maintenance. Please check back soon.')) From 3285460ea0200ef66ed50c0fbe5d148a11839aa1 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Tue, 4 Sep 2018 15:10:26 +0200 Subject: [PATCH 0274/2459] Fix dropAllTables() and dropAllViews() on SQLite (#25427) --- .../Schema/Grammars/SQLiteGrammar.php | 10 +++++ .../Database/Schema/SQLiteBuilder.php | 4 ++ .../Database/SchemaBuilderTest.php | 39 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 tests/Integration/Database/SchemaBuilderTest.php diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index c68710fa2007..dac7c8911702 100755 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -242,6 +242,16 @@ public function compileDropAllViews() return "delete from sqlite_master where type in ('view')"; } + /** + * Compile the SQL needed to rebuild the database. + * + * @return string + */ + public function compileRebuild() + { + return 'vacuum'; + } + /** * Compile a drop column command. * diff --git a/src/Illuminate/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index 0f13dd2eee66..78b6b9c78d2e 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -20,6 +20,8 @@ public function dropAllTables() $this->connection->select($this->grammar->compileDropAllTables()); $this->connection->select($this->grammar->compileDisableWriteableSchema()); + + $this->connection->select($this->grammar->compileRebuild()); } /** @@ -34,6 +36,8 @@ public function dropAllViews() $this->connection->select($this->grammar->compileDropAllViews()); $this->connection->select($this->grammar->compileDisableWriteableSchema()); + + $this->connection->select($this->grammar->compileRebuild()); } /** diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php new file mode 100644 index 000000000000..f63deade31cd --- /dev/null +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -0,0 +1,39 @@ +increments('id'); + }); + + Schema::dropAllTables(); + + Schema::create('table', function ($table) { + $table->increments('id'); + }); + + $this->assertTrue(true); + } + + public function test_drop_all_views() + { + DB::statement('create view "view"("id") as select 1'); + + Schema::dropAllViews(); + + DB::statement('create view "view"("id") as select 1'); + + $this->assertTrue(true); + } +} From df38587ea34a0a508244825da785ea8c47efad9d Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 4 Sep 2018 15:27:54 +0200 Subject: [PATCH 0275/2459] update changelog git push original 5.7 --- CHANGELOG-5.5.md | 940 ----------------------------------------------- CHANGELOG-5.6.md | 636 -------------------------------- CHANGELOG-5.7.md | 5 + 3 files changed, 5 insertions(+), 1576 deletions(-) delete mode 100644 CHANGELOG-5.5.md delete mode 100644 CHANGELOG-5.6.md create mode 100644 CHANGELOG-5.7.md diff --git a/CHANGELOG-5.5.md b/CHANGELOG-5.5.md deleted file mode 100644 index 1b7eb87871c5..000000000000 --- a/CHANGELOG-5.5.md +++ /dev/null @@ -1,940 +0,0 @@ -# Release Notes for 5.5.x - -## v5.5.40 (2018-03-30) - -### Changed -- Only set id on `NotificationFake` if no id is set ([#23474](https://github.com/laravel/framework/pull/23474)) -- Removed attribute filling from pivot models ([#23554](https://github.com/laravel/framework/pull/23554)) - -### Fixed -- Fixed to not mistakenly release mutex ([#23607](https://github.com/laravel/framework/pull/23607)) -- Revert breaking changes in `ManagesLoops` ([#23681](https://github.com/laravel/framework/pull/23681)) - -### Security -- Check `iv` length in `Encrypter::validPayload()` ([28e53f2](https://github.com/laravel/framework/commit/28e53f23a76206fb130e9a54eb95aa3f010e79c9)) - - -## v5.5.39 (2018-03-09) - -### Fixed -- Fix for Carbon 1.24.1 ([b3a5608](https://github.com/laravel/framework/commit/b3a5608ff60a3679d51536a65bb525bdc2390fbc), [72286b3](https://github.com/laravel/framework/commit/72286b302e9bf6a29dd5f0e20f4e7c6dbce78a5d)) - - -## v5.5.38 (2018-03-09) - -### Fixed -- Fix for Carbon 1.24.0 ([#23459](https://github.com/laravel/framework/pull/23459)) -- Fixed `--force` flag on `GeneratorCommand` ([#23427](https://github.com/laravel/framework/pull/23427)) - - -## v5.5.37 (2018-03-07) - -### Changed -- Added `v-pre` to dropdown link in `app.stub` ([987c19f](https://github.com/laravel/framework/commit/987c19fc252a4883ec05e1691b98e7e9e0c74be8)) - -### Fixed -- `Queue::bulk()` fake now properly pushes expected jobs ([#23389](https://github.com/laravel/framework/pull/23389)) -- Set up loop variable correctly on all `Traversable` objects ([#23388](https://github.com/laravel/framework/pull/23388)) -- Fixed `SQLiteGrammar::whereTime()` formatting ([#23408](https://github.com/laravel/framework/pull/23408)) - - -## v5.5.36 (2018-03-01) - -### Changed -- Upgrade Parsedown to 1.7.0 ([14adb99](https://github.com/laravel/framework/commit/14adb9958729ea778767b9269df485e399fd6178)) - -### Fixed -- Fixed `PostgresGrammar::whereTime()` casting ([#23318](https://github.com/laravel/framework/pull/23318)) - - -## v5.5.35 (2018-02-22) - -### Fixed -- Fixed an issue with `orWhere*()` arguments ([3368494](https://github.com/laravel/framework/commit/3368494889130585bc6bbf22d8842881f8f4399c)) -- Fixed `tightenco/collect` version ([#23152](https://github.com/laravel/framework/pull/23152), [#23159](https://github.com/laravel/framework/pull/23159)) - - -## v5.5.34 (2018-02-06) - -### Changed -- Use path helpers in console commands ([#22971](https://github.com/laravel/framework/pull/22971)) -- Remove unnecessary `escapeshellarg()` call ([#23025](https://github.com/laravel/framework/pull/23025)) -- Use original attribute values in pivot where clauses ([#23031](https://github.com/laravel/framework/pull/23031), [#23035](https://github.com/laravel/framework/pull/23035)) - - -## v5.5.33 (2018-01-30) - -### Added -- Added `doesntExist()` method to query builder ([#22836](https://github.com/laravel/framework/pull/22836), [9d2a7ca](https://github.com/laravel/framework/commit/9d2a7ca049e71d39e453ba8c34addb657b71b237)) -- Added `assertHeaderMissing()` assertion ([#22849](https://github.com/laravel/framework/pull/22849), [#22866](https://github.com/laravel/framework/pull/22866)) -- Added support for higher order unique ([#22851](https://github.com/laravel/framework/pull/22851)) -- Added boolean toggle to `withTrashed()` ([#22888](https://github.com/laravel/framework/pull/22888)) - -### Changed -- Support Mix HMR with different host/port ([#22826](https://github.com/laravel/framework/pull/22826), [24897d6](https://github.com/laravel/framework/commit/24897d6afbfed70a7383561f31c01bc48927cbda)) -- Make route filtering by method case-insensitive ([#22856](https://github.com/laravel/framework/pull/22856)) -- Added missing PostgreSQL operator for array overlap ([#22903](https://github.com/laravel/framework/pull/22903)) - - -## v5.5.32 (2018-01-18) - -### Fixed -- Reverted `Collection::get()` changes [#22554](https://github.com/laravel/framework/pull/22554) ([6197e56](https://github.com/laravel/framework/commit/6197e563fab8511ce8bf9a006444fee26f015d3a), [af36f26](https://github.com/laravel/framework/commit/af36f26dad805a8d866555c979e92a9e0e1fa8ea)) - - -## v5.5.31 (2018-01-16) - -### Fixed -- Reverted [#22804](https://github.com/laravel/framework/pull/22804) ([d8a8368](https://github.com/laravel/framework/commit/d8a8368e15e73de50b91b903f6b933c7d05b0e28), [f34926c](https://github.com/laravel/framework/commit/f34926c52ba282ff67f4be3e9afc8d0ddc885c3f)) - - -## v5.5.30 (2018-01-16) - -### Changed -- Accept collection of keys on `Collection::only()` ([#22804](https://github.com/laravel/framework/pull/22804)) - -### Fixed -- Reverted [#22649](https://github.com/laravel/framework/pull/22649) ([#22815](https://github.com/laravel/framework/pull/22815)) -- Send status code `500` when using `Collection::dd()` ([#22803](https://github.com/laravel/framework/pull/22803)) - - -## v5.5.29 (2018-01-15) - -### Added -- Added `Model::qualifyColumn()` method ([#22577](https://github.com/laravel/framework/pull/22577)) -- Added support for the `author_*` fields to `SlackAttachment` ([#22610](https://github.com/laravel/framework/pull/22610)) -- Added `UrlGenerator::getDefaultParameters()` method ([#22572](https://github.com/laravel/framework/pull/22572)) -- Added option to double encode escaped strings ([61f8477](https://github.com/laravel/framework/commit/61f8477fab55a258f39a3d598f67f7cc0ffd6aca)) -- Added `BladeCompiler::doubleEncode()` method ([1cc96a1](https://github.com/laravel/framework/commit/1cc96a120955bc0d901f59dff7be1b99133fc7a1)) -- Added support for nested keys to `TestResponse::assertJsonCount()` ([#22740](https://github.com/laravel/framework/pull/22740)) -- Added `s3://` to protocol to URL validation ([#22752](https://github.com/laravel/framework/pull/22752)) -- Added option to disable wrapping migrations in transaction ([#22757](https://github.com/laravel/framework/pull/22757)) - -### Changed -- Use `Arr::get()` in `Collection::get()` ([#22554](https://github.com/laravel/framework/pull/22554)) -- Pass entire config to `FtpAdapter` ([#22539](https://github.com/laravel/framework/pull/22539)) -- Support extending Eloquent relationships ([#22617](https://github.com/laravel/framework/pull/22617)) -- Improved handling of `VerifyCsrfToken::$except` values ([#22619](https://github.com/laravel/framework/pull/22619), [#22661](https://github.com/laravel/framework/pull/22661)) -- Support multiple levels in `Collection::groupBy()` ([#22630](https://github.com/laravel/framework/pull/22630)) -- Clear user instance in `RequestGuard::setRequest()` ([#22649](https://github.com/laravel/framework/pull/22649)) -- Allow StudlyCase and snake_case migration names ([#22648](https://github.com/laravel/framework/pull/22648)) -- Set `null` as default value for `optional()` helper ([#22699](https://github.com/laravel/framework/pull/22699)) -- Make sure `getRememberToken()` returns a string ([#22724](https://github.com/laravel/framework/pull/22724)) -- Updated Vue preset version ([#22732](https://github.com/laravel/framework/pull/22732)) -- Accept `Arrayable` items in `Collection::find()` ([#22787](https://github.com/laravel/framework/pull/22787)) - -### Fixed -- Close database connection when using `RefreshDatabase` trait ([#22569](https://github.com/laravel/framework/pull/22569)) -- Send status code `500` when using `dd()` ([#22581](https://github.com/laravel/framework/pull/22581)) -- Fixed parameter usage in `RedirectController` ([#22657](https://github.com/laravel/framework/pull/22657)) -- Added `__set_state()` method to `Support/Carbon` ([#22689](https://github.com/laravel/framework/pull/22689)) -- Do not continue checking `APP_ENV` if environment file path being set successfully with `--env` option ([#22753](https://github.com/laravel/framework/pull/22753)) -- Fixed missing table prefix in `SQLiteGrammar::compileDropColumn()` ([#22745](https://github.com/laravel/framework/pull/22745), [c13322c](https://github.com/laravel/framework/commit/c13322c54a20de1417d7bf53e348a601c526bf54)) -- Fixed prefixing in `SQLiteGrammar::compileColumnListing()` ([#22781](https://github.com/laravel/framework/pull/22781)) - - -## v5.5.28 (2017-12-26) - -### Added -- Added `AnonymousNotifiable::notifyNow()` method ([#22530](https://github.com/laravel/framework/pull/22530)) -- Added `EventFake::assertDispatchedTimes()` method ([#22528](https://github.com/laravel/framework/pull/22528)) - -### Changed -- Check for `--no-interaction` flag on command calls ([#22515](https://github.com/laravel/framework/pull/22515), [ba5e31d](https://github.com/laravel/framework/commit/ba5e31dde341884b3bf03178d1a529abd55e7886)) - -### Fixed -- Fix Validator not handling properly inline messages for `size` rules ([#22518](https://github.com/laravel/framework/pull/22518), [690d9fc](https://github.com/laravel/framework/commit/690d9fcc380252806cd19c164af843ccb3e801d9)) - - -## v5.5.27 (2017-12-20) - -### Added -- Allow `HtmlString` as line in `MailMessage` ([#22473](https://github.com/laravel/framework/pull/22473)) -- Allow chaining of the `Request::merge()` calls ([#22479](https://github.com/laravel/framework/pull/22479)) - -### Changed -- Reverted performance improvements of `Model::getTable()` ([#22478](https://github.com/laravel/framework/pull/22478)) - - -## v5.5.26 (2017-12-18) - -### Added -- Support passing collections to `Collection::except()` ([#22399](https://github.com/laravel/framework/pull/22399)) -- Made `Command` class macroable ([#22426](https://github.com/laravel/framework/pull/22426), [#22434](https://github.com/laravel/framework/pull/22434)) -- Added `ProcessUtils` class for command argument escaping ([#22448](https://github.com/laravel/framework/pull/22448)) -- Added array support to `Optional` helper class ([#22417](https://github.com/laravel/framework/pull/22417)) - -### Changed -- Added "cattle" as an uncountable word ([#22415](https://github.com/laravel/framework/pull/22415)) -- Added `Dispatcher` contract on `NotificationFake` and return fake object from `Notification::fake()` ([#22396](https://github.com/laravel/framework/pull/22396)) -- Only add value as query binding if it isn't an `Expression` ([#22451](https://github.com/laravel/framework/pull/22451)) - -### Fixed -- Fixed database queue transactions wrapped in closures ([#22394](https://github.com/laravel/framework/pull/22394)) -- Fixed an issue with multiple `dont-discover` packages ([#22443](https://github.com/laravel/framework/pull/22443)) -- Fixed incorrect description type in `Console/Parser` ([#22449](https://github.com/laravel/framework/pull/22449)) - - -## v5.5.25 (2017-12-11) - -### Added -- Added support for Flysystem caching ([#22310](https://github.com/laravel/framework/pull/22310), [0657496](https://github.com/laravel/framework/commit/06574964c677c4205668def84ede22e3ca5eee9c)) -- Added support for `year` data type ([#22377](https://github.com/laravel/framework/pull/22377)) -- Added support for setting Whoops debug editor ([#22350](https://github.com/laravel/framework/pull/22350), [c6e3a73](https://github.com/laravel/framework/commit/c6e3a73d28ca91a3119a6eb51ef14dd332a64719)) - -### Changed -- Use `Model::newQueryWithoutRelationships()` in `Collection::load()` ([#22363](https://github.com/laravel/framework/pull/22363)) -- Respect `schema` config in `PostgresBuilder` ([#22365](https://github.com/laravel/framework/pull/22365), [de561cb](https://github.com/laravel/framework/commit/de561cb0c3de5d793a2bf93c5353dcec00c9544b)) - -### Fixed -- Fixed SQS queue driver for PHP 7.2 ([#22374](https://github.com/laravel/framework/pull/22374)) - - -## v5.5.24 (2017-12-06) - -### Added -- Added `WithFaker` testing trait ([#22280](https://github.com/laravel/framework/pull/22280), [4841089](https://github.com/laravel/framework/commit/4841089645e1772e64b501a4f69478b2ee7f4550), [5c72698](https://github.com/laravel/framework/commit/5c726986ae1ecb926ae9d77e28848bb38d020041)) - -### Changed -- Made `Relation::$morphMap` public ([e44596f](https://github.com/laravel/framework/commit/e44596f65667962af69fd9cd9e63beb927fecaa1)) -- Trim return value of `ValidatesAttributes::shouldBlockPhpUpload()` ([90a8faf](https://github.com/laravel/framework/commit/90a8fafd6b70d8f059e86010de996c5db6da4c37)) - -### Fixed -- Fixed an issue with queueable notifications ([#22275](https://github.com/laravel/framework/pull/22275)) -- Fixed `NullSessionDriver` upstream issues ([#22314](https://github.com/laravel/framework/pull/22314)) -- Move `payload` to the end of the insert array of a job ([#22334](https://github.com/laravel/framework/pull/22334)) - - -## v5.5.23 (2017-12-04) - -### Added -- Added a `Collection::firstWhere()` method ([#22261](https://github.com/laravel/framework/pull/22261), [#22264](https://github.com/laravel/framework/pull/22264)) -- Added several accessors to `BelongsToMany` ([f09ea98](https://github.com/laravel/framework/commit/f09ea98bc814c708215896dad702d715923f3bc3), [cbe8123](https://github.com/laravel/framework/commit/cbe8123a479e81779cd85251eb4a5cf861e93ea3), [3bcf9d1](https://github.com/laravel/framework/commit/3bcf9d1d67ca3f288270e910898c77334322128a)) - -### Changed -- Pass test value to `Collection::when()` callbacks ([#22224](https://github.com/laravel/framework/pull/22224)) -- Support worker sleep time of less than 1s ([#22246](https://github.com/laravel/framework/pull/22246), [#22255](https://github.com/laravel/framework/pull/22255)) -- Detect persistent connection resets ([#22277](https://github.com/laravel/framework/pull/22277)) -- Support chaining seeders ([#22288](https://github.com/laravel/framework/pull/22288)) - -### Fixed -- Fixed negative comparison to objects in `Collection::where()` ([#22256](https://github.com/laravel/framework/pull/22256)) -- Fixed comparing strings with objects that can be casted to string in `Collection::where()` ([#22295](https://github.com/laravel/framework/pull/22295)) -- Fixed integer validation using `distinct:ignore_case` ([#22235](https://github.com/laravel/framework/pull/22235)) -- Fixes building nested JSON accessors in `MySqlGrammar` ([#22254](https://github.com/laravel/framework/pull/22254)) -- Remove `SELECT` bindings from MySQL delete statements ([#22285](https://github.com/laravel/framework/pull/22285)) - - -## v5.5.22 (2017-11-27) - -### Added -- Added `response()` and `download()` methods to file system ([#22089](https://github.com/laravel/framework/pull/22089)) -- Added complete temporary table support ([#22110](https://github.com/laravel/framework/pull/22110)) -- Added `Mode::newQueryForRestoration()` method ([#22119](https://github.com/laravel/framework/pull/22119)) -- Added precision support for date/time columns ([#22122](https://github.com/laravel/framework/pull/22122)) -- Added detection for MySQL Galera deadlocks ([#22214](https://github.com/laravel/framework/pull/22214)) - -### Changed -- Updated depreciated `MailFake::queue()` method signature ([#22072](https://github.com/laravel/framework/pull/22072)) -- Use `MEDIUMTEXT` instead of `TEXT` for database cache values (MySQL only) ([#22091](https://github.com/laravel/framework/pull/22091)) -- Include the name of the scheduled job in the output email subject ([#22098](https://github.com/laravel/framework/pull/22098)) -- Support `Dblib` version config for SQL Server ([#22102](https://github.com/laravel/framework/pull/22102)) -- Set `Model::$exists` to `false` when force-deleting a model using `SoftDeletes` ([#22100](https://github.com/laravel/framework/pull/22100)) -- Support empty strings in `HasAttributes::fromDateTime()` ([#22108](https://github.com/laravel/framework/pull/22108)) -- Return condition from `throw_*` helpers ([#22149](https://github.com/laravel/framework/pull/22149)) -- Make `Collection::where()` independent of error reporting ([#22172](https://github.com/laravel/framework/pull/22172)) -- Show more meaningful message when json translation file contains errors ([#22165](https://github.com/laravel/framework/pull/22165), [cf29b88](https://github.com/laravel/framework/commit/cf29b884006a4ce4d84a115b531143337a875211)) -- Improve `Model::getTable()` performance ([#22222](https://github.com/laravel/framework/pull/22222)) -- Use transaction in migrations using SQL Server ([#22187](https://github.com/laravel/framework/pull/22187)) - -### Fixed -- Fixed `HasManyThrough` relation with custom intermediate and local keys when used in `whereHas()` ([#22071](https://github.com/laravel/framework/pull/22071), [3788cbd](https://github.com/laravel/framework/commit/3788cbd3e606caa4a6e4137f92709c85e52b2cf3)) -- Fixed SQL Server handling of `DATETIME` columns ([#22052](https://github.com/laravel/framework/pull/22052)) -- Return default value from `old()` when session isn't available ([#22082](https://github.com/laravel/framework/pull/22082)) -- Refactor `Arr::flatten()` to prevent performance issue ([#22103](https://github.com/laravel/framework/pull/22103)) -- Wrap MySQL JSON keys in double quotes when updating JSON columns ([#22118](https://github.com/laravel/framework/pull/22118)) -- Fixed custom URLs with prefix (`root`) for AWS storage ([#22130](https://github.com/laravel/framework/pull/22130)) -- Prevent authentication if `password` is the only specified field ([#22167](https://github.com/laravel/framework/pull/22167)) - -### Removed -- Removed `between` operator from basic where clauses ([#22182](https://github.com/laravel/framework/pull/22182)) - - -## v5.5.21 (2017-11-14) - -### Added -- Add support for `MultiSubnetFailover` parameter to SqlServer ([#22022](https://github.com/laravel/framework/pull/22022)) -- Support custom URLs for S3 ([#22037](https://github.com/laravel/framework/pull/22037)) -- Added `MakesHttpRequests::withMiddleware()` method ([#22060](https://github.com/laravel/framework/pull/22060)) - -### Changed -- Display controller name in `BadMethodCallException` ([#22005](https://github.com/laravel/framework/pull/22005)) -- Unify `Collection::dd()` and `Collection::dump()` output ([#22036](https://github.com/laravel/framework/pull/22036)) -- Support event generation from multiple service providers ([#22063](https://github.com/laravel/framework/pull/22063)) - - -## v5.5.20 (2017-11-07) - -### Added -- Added `TestResponse::assertJsonMissingExact()` ([#21881](https://github.com/laravel/framework/pull/21881)) -- Added `assertValidationErrors()` and `assertJsonCount()` to `TestResponse` ([#21917](https://github.com/laravel/framework/pull/21917)) -- Added `allOnQueue()` and `allOnConnection()` for job chaining ([#21765](https://github.com/laravel/framework/pull/21765)) -- Support variadic arguments on fluent `Route::middleware()` ([#21930](https://github.com/laravel/framework/pull/21930)) -- Added precision to `Blueprint::time()` ([#21936](https://github.com/laravel/framework/pull/21936)) -- Added `Router::apiResources()` method ([#21956](https://github.com/laravel/framework/pull/21956)) -- Support graceful handling of `SIGTERM` in queue workers ([#21964](https://github.com/laravel/framework/pull/21964)) - -### Changed -- Added "kin" as an uncountable word ([#21843](https://github.com/laravel/framework/pull/21843)) -- Improved geo spatial support ([#21919](https://github.com/laravel/framework/pull/21919)) -- Include job name in the `MaxAttemptsExcededException` ([#21941](https://github.com/laravel/framework/pull/21941), [#21943](https://github.com/laravel/framework/pull/21943)) -- Support rendering multiple `@verbatim` and `@php` blocks ([#21900](https://github.com/laravel/framework/pull/21900)) -- Moved `InteractsWithRedis` to `Illuminate\Foundation\Testing` ([#21967](https://github.com/laravel/framework/pull/21967)) -- Don't bind macro when it is not a `Closure` ([#21980](https://github.com/laravel/framework/pull/21980)) -- Check for `before()` method on policies classes ([#21989](https://github.com/laravel/framework/pull/21989)) -- Detect lost pgbouncer connections ([#21988](https://github.com/laravel/framework/pull/21988)) - -### Fixed -- Fixed `BroadcastController` namespace issue ([#21844](https://github.com/laravel/framework/pull/21844)) -- Fixed eager loading `HasManyThrough` relations with custom intermediate and local key ([#21902](https://github.com/laravel/framework/pull/21902)) -- Use table aliases when calling self-referencing `HasManyThrough` relation ([#21883](https://github.com/laravel/framework/pull/21883)) -- Fixed Vue component file name in React present ([#21945](https://github.com/laravel/framework/pull/21945)) -- Reverted changes to `BadMethodException` in [#20196](https://github.com/laravel/framework/pull/20196) ([#21929](https://github.com/laravel/framework/pull/21929)) - - -## v5.5.19 (2017-10-25) - -### Added -- Added `MakesHttpRequests::followingRedirects()` method ([#21771](https://github.com/laravel/framework/pull/21771)) -- Added `MakesHttpRequests::from()` method ([#21788](https://github.com/laravel/framework/pull/21788)) -- Added `notifyNow()` method to notifiables ([#21795](https://github.com/laravel/framework/pull/21795)) -- Added `TestResponse::assertCookieExpired()` method ([#21793](https://github.com/laravel/framework/pull/21793)) -- Added `TestResponse::assertCookieMissing()` method ([#21803](https://github.com/laravel/framework/pull/21803)) - -### Changed -- Allow the distinct validation rule to optionally ignore case ([#21757](https://github.com/laravel/framework/pull/21757)) - -### Fixed -- Excluding `spatial_ref_sys` table from `migrate:fresh` ([#21778](https://github.com/laravel/framework/pull/21778)) -- Fixed issue with `SessionGuard` setting the logged in user after firing the `Authenticated` event ([#21790](https://github.com/laravel/framework/pull/21790)) -- Fixed issue with `Model::refresh()` when model has a global scope ([#21815](https://github.com/laravel/framework/pull/21815)) -- Fixed scheduling a non-queuable job ([#21820](https://github.com/laravel/framework/pull/21820)) - - -## v5.5.18 (2017-10-19) - -### Added -- Made `Redirector` macroable ([#21714](https://github.com/laravel/framework/pull/21714)) - -### Changed -- Prevent reloading default relationships while lazy eager-loading ([#21710](https://github.com/laravel/framework/pull/21710)) -- Don't reload pivot relationship on refresh ([#21713](https://github.com/laravel/framework/pull/21713)) -- Unify Vue.js preset ([#21711](https://github.com/laravel/framework/pull/21711), [#21724](https://github.com/laravel/framework/pull/21724)) -- Revert multibyte functions in `Str` ([#21722](https://github.com/laravel/framework/pull/21722)) -- Remove hardcoded fields in DatabaseUserProvider ([#21749](https://github.com/laravel/framework/pull/21749)) - -### Fixed -- Don't recreate the SQLite database file in `refreshDatabaseFile()` ([#21720](https://github.com/laravel/framework/pull/21720)) - - -## v5.5.17 (2017-10-17) - -### Fixed -- Allow `@json` options to be `0` ([#21692](https://github.com/laravel/framework/pull/21692)) -- Fixed "invalid argument" error in `ServiceProvider::loadViewsFrom()` ([#21705](https://github.com/laravel/framework/pull/21705)) - - -## v5.5.16 (2017-10-16) - -_No changes._ - - -## v5.5.15 (2017-10-16) - -### Added -- Added missing PostgreSQL network address operators ([#21518](https://github.com/laravel/framework/pull/21518)) -- Added raw and same-site parameters to `cookie()` helper ([#21551](https://github.com/laravel/framework/pull/21551)) -- Added option to create pivot model to `make:model` command ([#21549](https://github.com/laravel/framework/pull/21549)) -- Added support for a `failed()` method to mailables and notifications ([#21585](https://github.com/laravel/framework/pull/21585)) -- Added `__toString` on `ViewErrorBag` ([#21605](https://github.com/laravel/framework/pull/21605)) -- Support higher order call of `keyBy()` ([#21606](https://github.com/laravel/framework/pull/21606)) -- Generate `@else*` directives for `Blade::if()` ([#21611](https://github.com/laravel/framework/pull/21611)) -- Made `Response` and `JsonResponse` macroable ([#21669](https://github.com/laravel/framework/pull/21669)) - -### Changed -- Escape HTML characters in `@json` directive ([#21574](https://github.com/laravel/framework/pull/21574)) -- Only accept strings in `Session::flash()` ([#21576](https://github.com/laravel/framework/pull/21576)) -- Use message from `AuthenticationException` in `Handler::unauthenticated()` ([#21575](https://github.com/laravel/framework/pull/21575)) -- Don't use global scope while touching parent timestamp ([#21604](https://github.com/laravel/framework/pull/21604)) -- Accept multiple middleware when defining middleware fluently ([#21621](https://github.com/laravel/framework/pull/21621)) -- Bind `true` as `1` while preparing an SQL statement ([#21623](https://github.com/laravel/framework/pull/21623)) -- Ensure config load order across multiple installations ([#21634](https://github.com/laravel/framework/pull/21634)) -- Pass previous exception to `AccessDeniedHttpException` and `HttpException` ([#21645](https://github.com/laravel/framework/pull/21645)) -- Unify Bootstrap preset ([#21686](https://github.com/laravel/framework/pull/21686), [#21685](https://github.com/laravel/framework/pull/21685)) - -### Fixed -- Reset table cell margins in mail theme ([#21647](https://github.com/laravel/framework/pull/21647)) -- Check for vendor views for each paths given in `config/view.php` ([#21636](https://github.com/laravel/framework/pull/21636)) -- Prevent negative offsets when paginating collection ([#21658](https://github.com/laravel/framework/pull/21658)) -- Flush all listeners of custom Eloquent events ([#21688](https://github.com/laravel/framework/pull/21688)) - - -## v5.5.14 (2017-10-03) - -### Added -- Allow testing anonymous notifiables ([#21379](https://github.com/laravel/framework/pull/21379)) -- Add relation and model attributes on `RelationNotFoundException` ([#21426](https://github.com/laravel/framework/pull/21426)) -- Allow passing a callback to `with()` ([#21445](https://github.com/laravel/framework/pull/21445)) -- Added `PotentiallyMissing` interface to `MissingValue` class ([be7dccc](https://github.com/laravel/framework/commit/be7dccca9f9249c928108d957fe70e78d370d26e)) -- Accept `$queue` name on `Schedule::job()` ([#21473](https://github.com/laravel/framework/pull/21473)) -- Added callback and default parameter `whenLoaded()` method ([#21490](https://github.com/laravel/framework/pull/21490)) -- Allow marking notifications as unread ([#21497](https://github.com/laravel/framework/pull/21497)) -- Added `Collection::mapToDictionary()` method ([#21505](https://github.com/laravel/framework/pull/21505)) -- Added `make:exception` command ([#21483](https://github.com/laravel/framework/pull/21483)) - -### Changed -- Reset RefreshDatabaseState after DatabaseMigrations rolls back ([#21325](https://github.com/laravel/framework/pull/21325)) -- Make sure page resolver returns an integer ([#21378](https://github.com/laravel/framework/pull/21378)) -- Allow single error messages in `ValidationException::withMessages()` ([#21400](https://github.com/laravel/framework/pull/21400)) -- Revert `Collection::sortBy()` behaviour to 5.4 ([#21382](https://github.com/laravel/framework/pull/21382)) -- Use fill instead of forceFill while storing pivot attributes ([#21403](https://github.com/laravel/framework/pull/21403)) -- Alphabetize `vendor:publish` options ([#21412](https://github.com/laravel/framework/pull/21412)) -- Extract `AnonymousResourceCollection` into class to allow serialization ([#21456](https://github.com/laravel/framework/pull/21456)) -- Extract some methods from `Resource` into `ConditionallyLoadsAttributes` trait ([28d945e](https://github.com/laravel/framework/commit/28d945e557736598c10c492c2918d5697b70570d), [1f37ccc](https://github.com/laravel/framework/commit/1f37ccc06485410fa0866c012b083a042c4cc73e)) - -### Fixed -- Ensure user is logged in before expecting user instance ([#21377](https://github.com/laravel/framework/pull/21377)) -- Remove leading slash from class while resolving controllers ([#21407](https://github.com/laravel/framework/pull/21407)) -- Make sure SQL for virtual columns is added after the unsigned modifier ([#21441](https://github.com/laravel/framework/pull/21441)) -- Fixed `Collection::contains()` when the found value is `null` ([#21442](https://github.com/laravel/framework/pull/21442)) -- Fixed merge issue in `Relation::morphMap()` ([#21458](https://github.com/laravel/framework/pull/21458)) -- Clear count query select bindings in `Relation::getRelationExistenceCountQuery()` ([#21468](https://github.com/laravel/framework/pull/21468)) -- Fixed user model type hints policy stub ([#21499](https://github.com/laravel/framework/pull/21499)) - - -## v5.5.13 (2017-09-24) - -### Added -- Added optional config option for whoops blacklist ([#21336](https://github.com/laravel/framework/pull/21336), [a83ebc1](https://github.com/laravel/framework/commit/a83ebc15e768fab3955013bf5797fa090ee693d7)) -- Added `Collection::pad()` method ([#21342](https://github.com/laravel/framework/pull/21342)) - -### Changed -- Made `$callback` parameter of `Arr::sort()` optional ([#21337](https://github.com/laravel/framework/pull/21337)) -- Support setting custom `REMOTE_ADDR` in `MakesHttpRequests` ([#21351](https://github.com/laravel/framework/pull/21351)) -- Changed visibility of `$output` to public on console events ([#21356](https://github.com/laravel/framework/pull/21356)) - -### Fixed -- Don't compare remember token in user providers if it's `null` (srsly for real this time, pinky promise) ([#21328](https://github.com/laravel/framework/pull/21328), [#21368](https://github.com/laravel/framework/pull/21368)) - - -## v5.5.12 (2017-09-22) - -### Added -- Added "software" as an uncountable word ([#21324](https://github.com/laravel/framework/pull/21324)) - -### Fixed -- Don't compare remember token if it's `null` ([#21328](https://github.com/laravel/framework/pull/21328)) - - -## v5.5.11 (2017-09-21) - -### Fixed -- Fixed bug in `EloquentUserProvider` introduced in [#21320](https://github.com/laravel/framework/pull/21320) ([#21323](https://github.com/laravel/framework/pull/21323)) - - -## v5.5.10 (2017-09-21) - -### Added -- Added `Route::respondWithRoute($name)` method ([#21299](https://github.com/laravel/framework/pull/21299), [66c5e46](https://github.com/laravel/framework/commit/66c5e462dbdb9d0c9d23114da3a3dc1b6e9fa0a1)) -- Added `$strict` parameter to `TestResponse::assertJson()` ([#21301](https://github.com/laravel/framework/pull/21301)) - -### Changed -- Added "firmware" as an uncountable word ([#21306](https://github.com/laravel/framework/pull/21306)) -- Allow `MorphTo::associate()` accept `null` ([#21318](https://github.com/laravel/framework/pull/21318)) -- Changed `__()` signature to match `Translation::trans()` ([10c013c](https://github.com/laravel/framework/commit/10c013c564b7e518640e42e97d9178f9e05ec7d9)) - -### Fixed -- Add missing `driver` parameter to doctrine connection ([#21297](https://github.com/laravel/framework/pull/21297)) - -### Security -- Perform constant-time token comparison in `DatabaseUserProvider` ([#21320](https://github.com/laravel/framework/pull/21320)) - - -## v5.5.9 (2017-09-20) - -### Changed -- Perform stable sort in `Collection::sortBy()` (2nd attempt) ([#21270](https://github.com/laravel/framework/pull/21270)) -- Return empty string if database session key is expired ([#21277](https://github.com/laravel/framework/pull/21277)) - -### Fixed -- Fixed setting `Model::UPDATED_AT` in `SoftDeletes` ([#21286](https://github.com/laravel/framework/pull/21286)) -- Apply custom pivot model attribute casting on arrays ([#21275](https://github.com/laravel/framework/pull/21275)) - - -## v5.5.8 (2017-09-20) - -### Fixed -- Fixed issue with routes sorting ([#21261](https://github.com/laravel/framework/pull/21261)) - - -## v5.5.7 (2017-09-19) - -### Fixed -- Fix `CacheClearCommand` binding ([#21256](https://github.com/laravel/framework/pull/21256)) - - -## v5.5.6 (2017-09-19) - -### Changed -- Clear real-time facades when running `cache:clear` ([#21250](https://github.com/laravel/framework/pull/21250), [1856601](https://github.com/laravel/framework/commit/185660178ad213140411ca27550cdaf44c650002)) - -### Fixed -- Reverted stable sort support in `Collection::sortBy()` ([#21255](https://github.com/laravel/framework/pull/21255)) - - -## v5.5.5 (2017-09-19) - -### Added -- Added `:input` placeholder in validation error messages ([#21175](https://github.com/laravel/framework/pull/21175)) -- Added `@includeFirst` Blade directive ([#21172](https://github.com/laravel/framework/pull/21172)) -- Allow setting column styles for tables in Artisan commands ([#21169](https://github.com/laravel/framework/pull/21169)) -- Added `ValidatesRequests::extractInputFromRules()` method ([#21192](https://github.com/laravel/framework/pull/21192)) -- Added `-m` shortcut to `make:factory` ([#21219](https://github.com/laravel/framework/pull/21219)) -- Added ability to set a fallback (catch-all) route ([#21234](https://github.com/laravel/framework/pull/21234)) - -### Changed -- Support `null` on `Model::UPDATED_AT` ([#21178](https://github.com/laravel/framework/pull/21178)) -- Render views from config while building error views ([#21145](https://github.com/laravel/framework/pull/21145)) -- Use multibyte functions in some `Str` methods ([#21207](https://github.com/laravel/framework/pull/21207)) -- Perform stable sort in `Collection::sortBy()` ([#21214](https://github.com/laravel/framework/pull/21214)) - -### Fixed -- Ignore `SELECT` bindings in `prepareBindingsForUpdate()` ([#21173](https://github.com/laravel/framework/pull/21173)) -- Fixed `remember` check in `AuthenticatesUsers::attemptLogin()` ([#21221](https://github.com/laravel/framework/pull/21221)) -- Added "hardware" as an uncountable word ([#21236](https://github.com/laravel/framework/pull/21236)) - - -## v5.5.4 (2017-09-13) - -### Added -- Added `Blueprint::spatialIndex()` method ([#21070](https://github.com/laravel/framework/pull/21070)) -- Added support for SQL Server's `TransactionIsolation` DSN key ([#21069](https://github.com/laravel/framework/pull/21069)) -- Added `ManagesFrequencies::everyFifteenMinutes()` method ([#21092](https://github.com/laravel/framework/pull/21092)) -- Added `Mailable::hasReplyTo()` method ([#21093](https://github.com/laravel/framework/pull/21093)) -- Added `MailMessage::template()` method ([#21154](https://github.com/laravel/framework/pull/21154)) -- Added support for Rackspace to `Storage::url()` ([#21157](https://github.com/laravel/framework/pull/21157)) -- Added support to use sub-queries as a where condition on a join clause ([#21008](https://github.com/laravel/framework/pull/21008)) - -### Changed -- Return `null` from `Route::getAction()` if `$key` is not found ([#21083](https://github.com/laravel/framework/pull/21083)) -- Restore non-static signature of `Router::prepareResponse()` ([#21114](https://github.com/laravel/framework/pull/21114), [e1a1265](https://github.com/laravel/framework/commit/e1a1265b6cd19c1597faafd4af409b913298c782)) -- Removed `Model` type hint from `Model::isNot()` ([4d8f0a1](https://github.com/laravel/framework/commit/4d8f0a1a72fe9ea915570df2ef58cbafd43ec96a)) -- Prefer `Jsonable` over `Arrayable` in `JsonResponse::setData()` ([#21136](https://github.com/laravel/framework/pull/21136)) -- Reset `cc` and `bcc` in `Mailer::setGlobalTo()` ([#21137](https://github.com/laravel/framework/pull/21137)) -- Avoid trace `args` in JSON exceptions ([#21149](https://github.com/laravel/framework/pull/21149)) - -### Fixed -- Fixed `@json` directive parameter logic ([2a25ee7](https://github.com/laravel/framework/commit/2a25ee7f2f2d5e2cbc1397cc24abbb2838a9b439)) -- Fixed a problem with `withoutExceptionHandling()` when called more than once ([#21086](https://github.com/laravel/framework/pull/21086)) -- Added a `compileForeign()` method to `PostgresGrammar` ([#21038](https://github.com/laravel/framework/pull/21038)) -- Reset the index after a `MissingValue` while resolving resource ([#21127](https://github.com/laravel/framework/pull/21127)) -- Fixed `getQualifiedParentKey()` on `BelongsToMany` relationships ([#21128](https://github.com/laravel/framework/pull/21128)) -- Fixed parameters on `Route::view()` when using `where()` ([#21113](https://github.com/laravel/framework/pull/21113)) -- Show real directory name in the exception message thrown by `PackageManifest` ([#21099](https://github.com/laravel/framework/pull/21099)) -- Fixed undefined offset error when refreshing a database collection ([#21159](https://github.com/laravel/framework/pull/21159)) - - -## v5.5.3 (2017-09-07) - -### Added -- Added `$action` parameter to `Route::getAction()` for simpler access ([#20975](https://github.com/laravel/framework/pull/20975)) -- Added `@json` blade directive ([#21004](https://github.com/laravel/framework/pull/21004)) -- Added `rescue()` helper ([#21010](https://github.com/laravel/framework/pull/21010), [74ecb34](https://github.com/laravel/framework/commit/74ecb34e1af89969f139e2d1d0f22694704a30d1), [c4d1c47](https://github.com/laravel/framework/commit/c4d1c471d2a9d080362b8bed70be35cd84e2cdef)) -- Support commas in `In` and `NotIn` parameters ([#21012](https://github.com/laravel/framework/pull/21012), [3c3c5e4](https://github.com/laravel/framework/commit/3c3c5e4402ed14ad86823aeec0f67b2da04629a0)) -- Added `RedisManager::connections()` method ([#21014](https://github.com/laravel/framework/pull/21014), [1deaaa9](https://github.com/laravel/framework/commit/1deaaa9dc08e1f194558df745d17e468d35d9eae)) -- Added exception class to JSON exceptions ([#21043](https://github.com/laravel/framework/pull/21043)) -- Added `Gate::policies()` method ([#21036](https://github.com/laravel/framework/pull/21036)) -- Added geo spatial blueprint methods ([#21056](https://github.com/laravel/framework/pull/21056)) - -### Changed -- Fixed migrations not being run in batch order ([#20986](https://github.com/laravel/framework/pull/20986)) -- Flush application resources on teardown ([#21022](https://github.com/laravel/framework/pull/21022)) -- Catch errors while building exception context ([#21047](https://github.com/laravel/framework/pull/21047)) -- Return `$this` from `Validator::setCustomMessages()` ([#21046](https://github.com/laravel/framework/pull/21046)) - -### Fixed -- Make `Request::validate()` return the value of parent key ([#20974](https://github.com/laravel/framework/pull/20974)) -- Fixed date comparison validators failing when a format is specified ([#20940](https://github.com/laravel/framework/pull/20940)) -- Fixed login throttling failing when `decayMinutes` is more than `1` ([#20997](https://github.com/laravel/framework/pull/20997)) -- Only use reflection on classes in `Kernel::load()` ([#20998](https://github.com/laravel/framework/pull/20998)) -- Specify lower case `column_name` in `MySqlGrammar::compileColumnListing()` ([#21037](https://github.com/laravel/framework/pull/21037)) -- Fixed eager loading problem with `BelongsToMany` ([#21044](https://github.com/laravel/framework/pull/21044)) - -### Removed -- Remove unnecessary `lcfirst()` call in `authorizeResource()` ([#21017](https://github.com/laravel/framework/pull/21017)) -- Removed `$listensFor` from listener stubs ([#21039](https://github.com/laravel/framework/pull/21039)) - - -## v5.5.2 (2017-09-04) - -### Added -- Added `mov` extension and `MimeType::search()` method ([#20917](https://github.com/laravel/framework/pull/20917)) -- Added support for `dont-discover` in packages ([#20921](https://github.com/laravel/framework/pull/20921), [4a6f1f2](https://github.com/laravel/framework/commit/4a6f1f2613f2ca5a1ef3792b019a769d6a269cda)) -- Added `retrieved` model event ([#20852](https://github.com/laravel/framework/pull/20852), [84291a6](https://github.com/laravel/framework/commit/84291a63d86bd97339f9d3970913c20035b733b9)) -- Added `HasOneOrMany::setForeignAttributesForCreate()` method ([#20871](https://github.com/laravel/framework/pull/20871)) -- Made `Route` macroable ([#20970](https://github.com/laravel/framework/pull/20970)) - -### Changed -- Load deferred providers before commands ([366c50e](https://github.com/laravel/framework/commit/366c50ec161f296df99961ecc71229b5b097ad49)) -- Don't pass cache instance to Schedule anymore ([#20916](https://github.com/laravel/framework/pull/20916), [#20933](https://github.com/laravel/framework/pull/20933)) -- Simplified `mix` require ([#20929](https://github.com/laravel/framework/pull/20929)) -- Return `null` if resource attribute contains relation with a null value ([#20969](https://github.com/laravel/framework/pull/20969)) - -### Fixed -- Prevent `ErrorException` in `Collection::operatorForWhere()` method ([#20913](https://github.com/laravel/framework/pull/20913)) -- Create default console input/output in `Application::run()` ([#20922](https://github.com/laravel/framework/pull/20922), [7647399](https://github.com/laravel/framework/commit/7647399b54c42b12cd66b76da046e73d15bcbff1)) -- Ignore abstract classes in `Kernel::load()` ([#20931](https://github.com/laravel/framework/pull/20931)) -- Fixed `listener-queued-duck.stub` filename ([#20937](https://github.com/laravel/framework/pull/20937)) -- Fixed faking notification sending while using AnonymousNotifiable ([#20965](https://github.com/laravel/framework/pull/20965)) -- Fixed `eachSpread()` and `mapSpread()` with nested collections ([#20962](https://github.com/laravel/framework/pull/20962)) -- Fixed generating names for classes beginning with slash ([#20961](https://github.com/laravel/framework/pull/20961)) - - -## v5.5.1 (2017-09-01) - -### Added -- Added getter methods on `MimeType` ([#20826](https://github.com/laravel/framework/pull/20826)) - -### Changed -- Moved console commands auto discovery to `Kernel::bootstrap()` ([#20863](https://github.com/laravel/framework/pull/20863)) -- Use classes instead of helper functions ([#20879](https://github.com/laravel/framework/pull/20879), [#20880](https://github.com/laravel/framework/pull/20880)) -- Changed `Resource::$collects` visibility to `public` ([#20885](https://github.com/laravel/framework/pull/20885)) - -### Fixed -- Fixed `choice()` on non-tty terminals ([#20840](https://github.com/laravel/framework/pull/20840)) -- Fixed Macroable calls on `Optional` ([#20845](https://github.com/laravel/framework/pull/20845), [#20898](https://github.com/laravel/framework/pull/20898)) -- Fixed `dropAllTables()` when using `PDO::FETCH_ASSOC` mode ([#20859](https://github.com/laravel/framework/pull/20859)) -- Pass model name to `ModelNotFoundException::setModel()` ([#20896](https://github.com/laravel/framework/pull/20896), [891f90e](https://github.com/laravel/framework/commit/891f90ea48056979add7319c5642501c8678bc9c)) -- Fixed `Basic` authentication ([#20905](https://github.com/laravel/framework/pull/20905)) -- Fixed `DelegatesToResource::offsetExists()` ([#20887](https://github.com/laravel/framework/pull/20887)) - -### Removed -- Removed redundant methods from `MorphOneOrMany` ([#20837](https://github.com/laravel/framework/pull/20837)) - - -## v5.5.0 (2017-08-30) - -### General -- ⚠️ Require PHP 7+ ([06907a0](https://github.com/laravel/framework/pull/17048/commits/06907a055e3d28c219f6b6ab97902f0be3e8a4ef), [39809ce](https://github.com/laravel/framework/pull/17048/commits/39809cea81a5564d196c16a87cbc25de88dd3d1c)) -- ⚠️ Removed deprecated `ServiceProvider::compile()` method ([10da428](https://github.com/laravel/framework/pull/17048/commits/10da428eb344191608474f1c12ee7edb0290e80a)) -- ⚠️ Removed deprecated `Str::quickRandom()` method ([2ef257a](https://github.com/laravel/framework/pull/17048/commits/2ef257a4197b7e6efeb0d6ac4a3958f82b7fed39)) -- Removed `build` scripts ([7c16b15](https://github.com/laravel/framework/pull/17048/commits/7c16b154ede10ff9a37756e32d7dddf317524634)) -- Upgraded to Symfony 3.3 components ([4db7031](https://github.com/laravel/framework/commit/4db70311b1b3813359b250d3f5a58743fa436453), [67a5367](https://github.com/laravel/framework/commit/67a536758d1636935ab5502bb6faedd73b30810f)) -- Throw `RuntimeException` when app key is missing ([#19145](https://github.com/laravel/framework/pull/19145), [8adbaa7](https://github.com/laravel/framework/commit/8adbaa714d37bb7214f29b12c52354900a1c6dc5)) - -### Artisan Console -- Added interactive prompt to `vendor:publish` ([#18230](https://github.com/laravel/framework/pull/18230)) -- Added `migrate:fresh` command ([f6511d4](https://github.com/laravel/framework/commit/f6511d477f73b3033ef2336257f4cac5f20594a0), [#20090](https://github.com/laravel/framework/pull/20090)) -- Added `make:factory` command and added `--factory` to `make:model` ([a6ffd8b](https://github.com/laravel/framework/commit/a6ffd8bfa896844fee4b4c83cc6aed9d0c33fd9d), [#19985](https://github.com/laravel/framework/pull/19985)) -- Added `make:rule` command ([76853fd](https://github.com/laravel/framework/commit/76853fd192f8f378ad9b781d64e3e40a9511f737)) -- ⚠️ Added `runningInConsole()` method `Application` contract ([#18658](https://github.com/laravel/framework/pull/18658)) -- Support default value(s) on command arguments ([#18572](https://github.com/laravel/framework/pull/18572)) -- Improved CLI detection for phpdbg ([#18781](https://github.com/laravel/framework/pull/18781)) -- ⚠️ Always return array from `RetryCommand::getJobIds()` ([#19232](https://github.com/laravel/framework/pull/19232)) -- Support passing absolute paths to `make::listener` ([#19660](https://github.com/laravel/framework/pull/19660)) -- ⚠️ Use `handle()` method instead of `fire()` ([#19827](https://github.com/laravel/framework/pull/19827), [#19839](https://github.com/laravel/framework/pull/19839), [#20024](https://github.com/laravel/framework/pull/20024)) -- Try to guess the `--create` option when generation migrations ([#20032](https://github.com/laravel/framework/pull/20032)) -- Generate `make:policy` with real user model namespace ([#20047](https://github.com/laravel/framework/pull/20047)) -- Added `Kernel::load()` to auto register a directory of commands ([2e7ddca](https://github.com/laravel/framework/commit/2e7ddca682214ea5ffd21aadc93d33b7a2805e94), [d607b9c](https://github.com/laravel/framework/commit/d607b9c670d9c7f7c749cda0a12a1dc6f55da6e4)) -- ⚠️ Removed `array` type hint from `Command::table()` ([#20120](https://github.com/laravel/framework/pull/20120)) -- Support loading multiple paths in `Kernel::load()` ([#20251](https://github.com/laravel/framework/pull/20251), [#20595](https://github.com/laravel/framework/pull/20595)) -- Added `CommandStarting` and `CommandFinished` events ([#20298](https://github.com/laravel/framework/pull/20298)) -- Show error message if a reverted migration is not found ([#20499](https://github.com/laravel/framework/pull/20499), [a895b1e](https://github.com/laravel/framework/commit/a895b1eb0e50683c4583c24bb17b3f8d9e8127ab)) -- Set correct namespace in model factories when using the `app:name` command ([#20766](https://github.com/laravel/framework/pull/20766)) -- ⚠️ Switched the `-f` shortcut from `--force` to `--factory` on `make:model` command ([#20800](https://github.com/laravel/framework/pull/20800)) - -### Assets -- Added frontend preset commands ([463b769](https://github.com/laravel/framework/commit/463b769270d462468e1b1dcc51a7a1144e003157), _too many follow-up commits_) - -### Authentication -- ⚠️ Support default user providers and pass user provider to `RequestGuard` ([#18856](https://github.com/laravel/framework/pull/18856)) -- Made the user provider parameter on `RequestGuard` optional ([d7f0b26](https://github.com/laravel/framework/commit/d7f0b2603ce0a0a568f84a8861c351a2c00d5613)) -- Use `setRememberToken()` in `ResetsPasswords` ([#19189](https://github.com/laravel/framework/pull/19189)) -- Added a `PasswordReset` event ([#19188](https://github.com/laravel/framework/pull/19188)) -- ⚠️ Support multiword models in `authorizeResource()` ([#19821](https://github.com/laravel/framework/pull/19821)) -- Added support for no user provider in `CreatesUserProviders` ([4feb847](https://github.com/laravel/framework/commit/4feb8477bab424da4ff9f34cba7afaed875db42d)) - -### Authorization -- Support multiple values in `Gate::has()` ([#18758](https://github.com/laravel/framework/pull/18758)) -- ⚠️ Prevent policies from being too greedy ([#19120](https://github.com/laravel/framework/pull/19120)) -- ⚠️ Added `abilities()` method to `Gate` contract ([#19173](https://github.com/laravel/framework/pull/19173)) -- ⚠️ Implement `iterable` on `Gate::check()` and `Gate::any()` ([#20084](https://github.com/laravel/framework/pull/20084)) - -### Blade Templates -- Added `Blade::if()` method ([71dfe0f](https://github.com/laravel/framework/commit/71dfe0f0824412f106b80df8dedd7708e66dfb00), [2905364](https://github.com/laravel/framework/commit/2905364f7c9f14b42a7283e56313b38d256ce09d), [#20025](https://github.com/laravel/framework/pull/20025)) -- Added `@switch`, `@case`, `@break` and `@default` directives ([#19758](https://github.com/laravel/framework/pull/19758)) -- ⚠️ Prevent Blade from parsing PHP code inside `@php` blocks ([#20065](https://github.com/laravel/framework/pull/20065)) - -### Broadcasting -- ⚠️ Use `AccessDeniedHttpException` instead if `HttpException` ([#19611](https://github.com/laravel/framework/pull/19611)) -- ⚠️ Upgraded to Pusher SDK v3 ([#20016](https://github.com/laravel/framework/pull/20016)) - -### Cache -- ⚠️ PSR-16 compliance ([#20194](https://github.com/laravel/framework/pull/20194)) -- Don't encrypt database cache values ([f0c72ec](https://github.com/laravel/framework/commit/f0c72ec9bcbdecb7e6267f7ec8f7ecbf8169a388)) -- Added support cache locks ([4e6b2e4](https://github.com/laravel/framework/commit/4e6b2e4ecbbec5a4b265f4d5a57ad1399227cf12), [045e6f2](https://github.com/laravel/framework/commit/045e6f25a860763942c928c4e6d8857d59741486), [#19669](https://github.com/laravel/framework/pull/19669)) -- Accept `DatetimeInterface` and `DateInterval` in cache repository ([#20034](https://github.com/laravel/framework/pull/20034)) -- Added `getStore()` method to cache `Repository` interface ([#20338](https://github.com/laravel/framework/pull/20338)) -- ⚠️ Made `RateLimiter` less aggressive ([#20759](https://github.com/laravel/framework/pull/20759)) - -### Collections -- Support multiple values in `Collection::has()` ([#18758](https://github.com/laravel/framework/pull/18758)) -- Added `Collection::mapInto()` method ([2642ac7](https://github.com/laravel/framework/commit/2642ac73cc5718a8aebe3d009b143b0fa43be085)) -- Added `Collection::dd()` method ([f5fafad](https://github.com/laravel/framework/commit/f5fafad80dbb08353824483f5b849031693cc477)) -- Added `Collection::dump()` method ([#19755](https://github.com/laravel/framework/pull/19755)) -- Added `wrap()` and `unwrap()` methods ([#20055](https://github.com/laravel/framework/pull/20055), [#20068](https://github.com/laravel/framework/pull/20068)) -- Added keys to `partition()`, `eachSpread()` and `mapSpread` callback ([#20783](https://github.com/laravel/framework/pull/20783), [#20723](https://github.com/laravel/framework/pull/20723)) - -### Configuration -- Added `Config::getMany()` method ([#19770](https://github.com/laravel/framework/pull/19770)) - -### Controllers -- ⚠️ Added `ControllerDispatcher` ([#20031](https://github.com/laravel/framework/pull/20031)) -- ⚠️ Removed `Controller::missingMethod()` ([bf5d221](https://github.com/laravel/framework/commit/bf5d221037d9857a74020f2623839e282035a420)) - -### Database -- ⚠️ Added `dropAllTables()` to schema builder ([#18484](https://github.com/laravel/framework/pull/18484), [d910bc8](https://github.com/laravel/framework/commit/d910bc8039f3cec2d906797818984e825601a3f5), [#19644](https://github.com/laravel/framework/pull/19644), [#19645](https://github.com/laravel/framework/pull/19645), [#20239](https://github.com/laravel/framework/pull/20239), [#20536](https://github.com/laravel/framework/pull/20536)) -- Added precision to `dateTime` and `timestamp` column types ([#18847](https://github.com/laravel/framework/pull/18847), [f85f6db](https://github.com/laravel/framework/commit/f85f6db7c00a43ae45d963d089458477cf3e44b3), [#18962](https://github.com/laravel/framework/pull/18962), [#20464](https://github.com/laravel/framework/pull/20464)) -- Pass page number to `chunk()` callback ([#19316](https://github.com/laravel/framework/pull/19316)) -- Improve memory usage in `chunk()` and `chunkById()` ([#19345](https://github.com/laravel/framework/pull/19345), [#19369](https://github.com/laravel/framework/pull/19369), [#19368](https://github.com/laravel/framework/pull/19368)) -- Fixed `compileColumnListing()` when using PostgreSQL with multiple schemas ([#19553](https://github.com/laravel/framework/pull/19553)) -- Allow the seeder to call multiple commands at once ([#19912](https://github.com/laravel/framework/pull/19912)) -- Added pgpool message to `DetectsLostConnections` ([#20418](https://github.com/laravel/framework/pull/20418)) -- Prevent race conditions on replicated databases ([#20445](https://github.com/laravel/framework/pull/20445), [0ec1522](https://github.com/laravel/framework/commit/0ec1522a74f4ef7b6a01d617a482ae3f46c81a70), [3824a36](https://github.com/laravel/framework/commit/3824a366b0cd8a081bef26d3b4509c5db2fe7aae)) -- ⚠️ Support sticky database connections ([#20746](https://github.com/laravel/framework/pull/20746)) - -### Eloquent ORM -- Added API resources ([#20710](https://github.com/laravel/framework/pull/20710), _too many follow-up commits_) -- ⚠️ Indicate soft deleted models as existing ([#17613](https://github.com/laravel/framework/pull/17613)) -- ⚠️ Added `$localKey` parameter to `HasRelationships::belongsToMany()` and `BelongsToMany` ([#17903](https://github.com/laravel/framework/pull/17903), [7c7c3bc](https://github.com/laravel/framework/commit/7c7c3bc4be3052afe0889fe323230dfd92f81000)) -- ⚠️ Added `$parentKey` parameter to `belongsToMany()`, `BelongsToMany` and `MorphToMany` ([#17915](https://github.com/laravel/framework/pull/17915), [#18380](https://github.com/laravel/framework/pull/18380)) -- ⚠️ Renamed `$parent` property to `$pivotParent` in `Pivot` class ([#17933](https://github.com/laravel/framework/pull/17933), [#18150](https://github.com/laravel/framework/pull/18150)) -- ⚠️ Don't add `_count` suffix to column name when using `withCount()` with an alias ([#17871](https://github.com/laravel/framework/pull/17871)) -- ⚠️ Renamed `$events` to `$dispatchesEvents` ([#17961](https://github.com/laravel/framework/pull/17961), [b6472bf](https://github.com/laravel/framework/commit/b6472bf6fec1af6e76604aaf3f7fed665440ac66), [3dbe12f](https://github.com/laravel/framework/commit/3dbe12f16f470e3bca868576d517d57876bc50af)) -- ⚠️ Only return query builder when the result is null for `callScope()` ([#18845](https://github.com/laravel/framework/pull/18845)) -- Allow setting a factory's attribute to a factory instance ([#18879](https://github.com/laravel/framework/pull/18879)) -- Support `null` comparison in `Model::is()` ([#18511](https://github.com/laravel/framework/pull/18511)) -- Added `getDirty()` checks for date and castable attributes ([#18400](https://github.com/laravel/framework/pull/18400), [e180e20](https://github.com/laravel/framework/commit/e180e20aa479525b34f77b9cf348148d329a4d2c)) -- Show method name in invalid relationship `LogicException` ([#18749](https://github.com/laravel/framework/pull/18749)) -- Add support for additional values in `firstOrCreate()` and `firstOrNew()` ([#18878](https://github.com/laravel/framework/pull/18878)) -- Added a second local key to `HasManyThrough` ([#19114](https://github.com/laravel/framework/pull/19114)) -- Respect casts declaration on custom pivot models ([#19335](https://github.com/laravel/framework/pull/19335)) -- Support creating relations without attributes ([#19506](https://github.com/laravel/framework/pull/19506)) -- Added `Model::only()` method ([#19459](https://github.com/laravel/framework/pull/19459)) -- ⚠️ Support model serialization on non default connection ([#19521](https://github.com/laravel/framework/pull/19521), [dd45f70](https://github.com/laravel/framework/commit/dd45f70519b72aa57bc21cec4e89886917990fa9)) -- ⚠️ Support updating nullable dates ([#19672](https://github.com/laravel/framework/pull/19672)) -- ⚠️ Make pivot model instantiable ([#20179](https://github.com/laravel/framework/pull/20179)) -- Simplified `BelongsToMany::allRelatedIds()` logic ([#20189](https://github.com/laravel/framework/pull/20189)) -- Added `Relation::get()` method ([#20052](https://github.com/laravel/framework/pull/20052)) -- Added `hasChanges()`, `wasChanged()`, `getChanges()` and `syncChanges()` ([#20129](https://github.com/laravel/framework/pull/20129), [#20130](https://github.com/laravel/framework/pull/20130)) -- Better exception message when calling non existing methods on models ([#20196](https://github.com/laravel/framework/pull/20196), [91c1f03](https://github.com/laravel/framework/commit/91c1f03be2835f5b15998ead9f47f37d5397c0cc)) -- Added support for connections on model factories ([#20191](https://github.com/laravel/framework/pull/20191)) -- Check for real primary key in `Pivot` methods ([8d82618](https://github.com/laravel/framework/commit/8d826189bb2db1c177d8605eb9218daa973acb6a)) -- Default `$attributes` on `BelongsToMany::create()` to empty array ([973bff4](https://github.com/laravel/framework/commit/973bff4527a433fa039fd937ecfe048ed2325a5f)) -- Add ability to set a custom pivot accessor ([#20411](https://github.com/laravel/framework/pull/20411)) -- ⚠️ Call `setConnection()` in `Model::save()` ([#20466](https://github.com/laravel/framework/pull/20466)) -- ⚠️ Touch parent timestamp only if the model is dirty ([#20489](https://github.com/laravel/framework/pull/20489)) -- Added `Model::loadMissing()` method ([#20630](https://github.com/laravel/framework/pull/20630), [4166c12](https://github.com/laravel/framework/commit/4166c12492ce7b1112911299caf4cdb17efc9364)) -- Added `Model::whereKeyNot()` method ([#20817](https://github.com/laravel/framework/pull/20817)) - -### Encryption -- Use `openssl_cipher_iv_length()` in `Encrypter` ([#18684](https://github.com/laravel/framework/pull/18684)) -- Added `Encrypter::generateKey()` method ([6623996](https://github.com/laravel/framework/commit/6623996212b3d59aa31a374b70311f03fd158075)) -- Use `json_last_error()` in `Encrypter` ([#20099](https://github.com/laravel/framework/pull/20099)) - -### Errors & Logging -- Added default 404, 419 and 500 error pages ([#18483](https://github.com/laravel/framework/pull/18483), [4d8c2c1](https://github.com/laravel/framework/commit/4d8c2c1f53979a669a59793b4ec61c8e60ed5b29)) -- ⚠️ Always show custom 500 error page for all exception types when not in debug mode ([#18481](https://github.com/laravel/framework/pull/18481), [3cb7b0f](https://github.com/laravel/framework/commit/3cb7b0f4304274f209ed0f776ef70ccd4f9fe5dd)) -- ⚠️ Show 419 error page on `TokenMismatchException` ([#18728](https://github.com/laravel/framework/pull/18728)) -- Support `render()` method on exceptions ([ed51160](https://github.com/laravel/framework/commit/ed51160b97d8c4cf16526a0f8ba57ce7cb131b53), [c8a9413](https://github.com/laravel/framework/commit/c8a9413e2dc3bf00c206742e2bc76a88134cba84)) -- Support `report()` method on exceptions ([e77f6f7](https://github.com/laravel/framework/commit/e77f6f76049050fd4abced63ffa768432d8974f2)) -- ⚠️ Send exceptions as JSON in debug mode if the request wants JSON ([5225389](https://github.com/laravel/framework/commit/5225389dfdf03d656b862bba59cebf1820e0e8f4), [#18732](https://github.com/laravel/framework/pull/18732), [4fe6091](https://github.com/laravel/framework/commit/4fe6091e9fc94817a70c47a6a1c2098d5a1805f8), [9ab58fd](https://github.com/laravel/framework/commit/9ab58fd1a0543b1c728124db7f70738b04dcf362), [#19333](https://github.com/laravel/framework/pull/19333)) -- ⚠️ Moved exceptions from `$dontReport` into `$internalDontReport` ([841b36c](https://github.com/laravel/framework/commit/841b36cc005ee5c400f1276175db9e2692d1e167)) -- Added `Handler::context()` method, that by default adds some default context to logs ([23b7d6b](https://github.com/laravel/framework/commit/23b7d6b45c675bcd93e9f1fb9cd33e71779142c6)) -- ⚠️ Don't set formatter on `ErrorLogHandler` ([a044f17](https://github.com/laravel/framework/commit/a044f17897eeda3ab909ea47eeba3804dabdf9ad)) -- Use whoops for errors ([b697272](https://github.com/laravel/framework/commit/b69727243305e0ffa4a68819450716f26396c5e6), [f6b67d4](https://github.com/laravel/framework/commit/f6b67d4e49e6c4de765f4b29b3c36c5d4ff84471), [#19471](https://github.com/laravel/framework/pull/19471), [#20412](https://github.com/laravel/framework/pull/20412)) -- Changed how exceptions are logged ([#19698](https://github.com/laravel/framework/pull/19698), [f1971c2](https://github.com/laravel/framework/commit/f1971c2242e4882440162fe504126a1475f7f2b4)) -- ⚠️ Return `HttpException` with code `413` from `PostTooLargeException` ([#19773](https://github.com/laravel/framework/pull/19773)) -- Support custom logger channel names ([#20133](https://github.com/laravel/framework/pull/20133)) -- ⚠️ Unify exception formatting ([#20173](https://github.com/laravel/framework/pull/20173), [#20067](https://github.com/laravel/framework/pull/20067), [#20167](https://github.com/laravel/framework/pull/20167), _too many follow-up commits, sorry_) -- Added default `Handler::unauthenticated()` method ([11b0de0](https://github.com/laravel/framework/commit/11b0de0485632d5712f7fb59071a4acbc4af2bdc)) - -### Events -- ⚠️ Removed calling queue method on handlers ([0360cb1](https://github.com/laravel/framework/commit/0360cb1c6b71ec89d406517b19d1508511e98fb5), [ec96979](https://github.com/laravel/framework/commit/ec969797878f2c731034455af2397110732d14c4), [d9be4bf](https://github.com/laravel/framework/commit/d9be4bfe0367a8e07eed4931bdabf135292abb1b)) -- Allow faking only specific events ([#19429](https://github.com/laravel/framework/pull/19429)) -- Support self-registering event listeners ([#19917](https://github.com/laravel/framework/pull/19917), [4d557c5](https://github.com/laravel/framework/commit/4d557c5f0aa81fb9cb753d77ffec931c9166a927), [#19962](https://github.com/laravel/framework/pull/19962), [5ed4f50](https://github.com/laravel/framework/commit/5ed4f5081f3674003919a79b346e256b162359cf)) -- Added ability to determine if queued handler should be pushed to queue ([#19957](https://github.com/laravel/framework/pull/19957), [efe616c](https://github.com/laravel/framework/commit/efe616cc2872ad096dd7fb1b8d6dd8e2e65ec846)) - -### Filesystem -- ⚠️ Made `Storage::files()` work like `Storage::allFiles()` ([#18874](https://github.com/laravel/framework/pull/18874), [7073457](https://github.com/laravel/framework/commit/7073457041a29ada14e0ed01d7d65f5c76a92689)) -- ⚠️ Fixed compatibility between `FilesystemAdapter` and the `Filesystem` interface ([#19389](https://github.com/laravel/framework/pull/19389)) - -### Helpers -- Added `report()` helper ([2b67619](https://github.com/laravel/framework/commit/2b676191b1688b8edc9d43317a2989642fe95b5d)) -- Added `throw_if()` and `throw_unless()` helpers ([18bb4df](https://github.com/laravel/framework/commit/18bb4dfc77c7c289e9b40c4096816ebeff1cd843), [#19166](https://github.com/laravel/framework/pull/19166), [#19255](https://github.com/laravel/framework/pull/19255)) -- Added `dispatch_now()` helper ([#18668](https://github.com/laravel/framework/pull/18668), [61f2e7b](https://github.com/laravel/framework/commit/61f2e7b4106f8eb0b79603d9792426f7c6a6d273)) -- Added `$language` parameter to `str_slug()` helper ([#19011](https://github.com/laravel/framework/pull/19011)) -- Added `str_before()` helper ([#19940](https://github.com/laravel/framework/pull/19940), [#20049](https://github.com/laravel/framework/pull/20049)) -- Added `now()` and `today()` helpers ([3c888b6](https://github.com/laravel/framework/commit/3c888b6c7b89c3d3f90e9024ffbebed3ee80bd23), [#20716](https://github.com/laravel/framework/pull/20716)) -- Added `blank()`, `filled()`, `optional()` and `transform()` helpers ([06de9b2](https://github.com/laravel/framework/commit/06de9b2beb9e3c13758d93cee86a1657545cb435), [31308e3](https://github.com/laravel/framework/commit/31308e396ecbfeb5a6e505c50a6b1a6b721b094d)) -- Handle lower case words better in as `Str::snake()` ([#18764](https://github.com/laravel/framework/pull/18764)) -- Removed usages of the `with()` helper ([#17888](https://github.com/laravel/framework/pull/17888)) -- Support multiple patterns in `Str::is()` ([#20108](https://github.com/laravel/framework/pull/20108)) -- Speed up `Arr::get()` calls without dot notations ([#20139](https://github.com/laravel/framework/pull/20139)) -- Use `report()` helper in `mix()` ([#20603](https://github.com/laravel/framework/pull/20603), [bf0cb82](https://github.com/laravel/framework/commit/bf0cb82a8990d99a0ed504c2fa6684b1c59c9d7e)) - -### Localization -- ⚠️ Moved `LoaderInterface` to contracts ([#20460](https://github.com/laravel/framework/pull/20460)) -- ⚠️ Support loading JSON translation for packages ([#20599](https://github.com/laravel/framework/pull/20599), [573f85c](https://github.com/laravel/framework/commit/573f85c3dd968f97081382b6f633b0a08b51fed5)) -- Support language specific characters in `Str` ([#18974](https://github.com/laravel/framework/pull/18974), [#19694](https://github.com/laravel/framework/pull/19694)) - -### Mail -- Allow mailables to be rendered directly to views ([d9a6dfa](https://github.com/laravel/framework/commit/d9a6dfa4f46a10feceb67921b78c60a905b7c28c)) -- Allow for per-mailable theme configuration ([b2c35ca](https://github.com/laravel/framework/commit/b2c35ca9eb769d1a4752a64e936defd7f7099043)) -- ⚠️ Removed `$data` and `$callback` parameters from `Mailer` and `MailQueue` -- ⚠️ Made `Markdown` a dependency of `MailChannel` ([#19349](https://github.com/laravel/framework/pull/19349)) -- ⚠️ Upgraded to SwiftMailer 6 ([#19356](https://github.com/laravel/framework/pull/19356)) -- ⚠️ Added `to()` and `bcc()` to `Mailer` contract ([#19955](https://github.com/laravel/framework/pull/19955)) - -### Notifications -- Added methods for Slack's `thumb_url` and `unfurl_*` options ([#19150](https://github.com/laravel/framework/pull/19150), [#19200](https://github.com/laravel/framework/pull/19200)) -- Support sending notifications via `AnonymousNotifiable` ([#19998](https://github.com/laravel/framework/pull/19998), [ba82579](https://github.com/laravel/framework/commit/ba825798f107c961a2337f13928bc6f4acac9447)) -- Accept other types on `SlackAttachment::timestamp()` ([#20671](https://github.com/laravel/framework/pull/20671)) - -### Queues -- Added support for chainable jobs ([81bcb03](https://github.com/laravel/framework/commit/81bcb03b303707cdc94420983b9d72ed558a2b3d), _too many follow-up commits, sorry_) -- ⚠️ Removed redundant `$queue` parameter from `Queue::createPayload()` ([#17948](https://github.com/laravel/framework/pull/17948)) -- Made all `getQueue()` methods `public` ([#18501](https://github.com/laravel/framework/pull/18501)) -- Pass connection and queue to `Looping` event ([#19081](https://github.com/laravel/framework/pull/19081)) -- ⚠️ Clone Job specific properties ([#19123](https://github.com/laravel/framework/pull/19123)) -- ⚠️ Declare missing abstract `Job::getRawBody()` method ([#19677](https://github.com/laravel/framework/pull/19677)) -- ⚠️ Fail (or optionally silently delete) job when model is missing during deserialization ([44b1f85](https://github.com/laravel/framework/commit/44b1f859bbaf8f33733c804857cc269de92b1fd4), [bceded6](https://github.com/laravel/framework/commit/bceded6fef79760b9907dbe105829f7d2d62f899)) -- Added `CallQueuedListener::__clone()` method ([#20022](https://github.com/laravel/framework/pull/20022)) -- Accept `DatetimeInterface` and `DateInterval` in queue ([#20102](https://github.com/laravel/framework/pull/20102), [92e2aff](https://github.com/laravel/framework/commit/92e2aff2fd9569fedf3164ef9a1a834e553a6881)) -- ⚠️ Use `dispatch()` instead of `fire()` ([#20446](https://github.com/laravel/framework/pull/20446)) -- Removed `reserved_at` index from jobs table stub ([#20702](https://github.com/laravel/framework/pull/20702)) -- Support job expiration ([#20776](https://github.com/laravel/framework/pull/20776), [1592b9b](https://github.com/laravel/framework/commit/1592b9b27b9ba25bf8bbb313900c5ffc635b0f10)) - -### Redis -- ⚠️ Several improvements on `PhpRedisConnection` ([#20269](https://github.com/laravel/framework/pull/20269), [#20316](https://github.com/laravel/framework/pull/20316)) -- ⚠️ Removed `PhpRedisConnection::proxyToEval()` method ([#17360](https://github.com/laravel/framework/pull/17360)) -- Added Redis limiters ([#20597](https://github.com/laravel/framework/pull/20597), [ceb260e](https://github.com/laravel/framework/commit/ceb260e6e8825a150651299b017b6a1dd5bd4db3), [#20761](https://github.com/laravel/framework/pull/20761), [aba76bf](https://github.com/laravel/framework/commit/aba76bf36ae9b301da3c778d7d4fc427a58f8aa4), [3684f0c](https://github.com/laravel/framework/commit/3684f0cfce1effabeb5d02c929d2b5335800f759), [#20772](https://github.com/laravel/framework/pull/20772)) - -### Requests -- ⚠️ Made `Request::has()` work like `Collection::has()` ([#18715](https://github.com/laravel/framework/pull/18715)) -- Added `Request::filled()` ([#18715](https://github.com/laravel/framework/pull/18715)) -- ⚠️ Made `Request::only()` work like `Collection::only()` ([#18695](https://github.com/laravel/framework/pull/18695)) -- Aliased `Request::exists()` to `Request::has()` ([183bf16](https://github.com/laravel/framework/commit/183bf16a2c939889f4461e237a851b55cf858f8e)) -- Allow passing keys to `Request::all()` to behave like old `Request::only()` ([#18754](https://github.com/laravel/framework/pull/18754)) -- ⚠️ Removed `Request::intersect()` ([#18695](https://github.com/laravel/framework/pull/18695)) -- Return request data from `ValidatesRequests` calls ([#19033](https://github.com/laravel/framework/pull/19033)) -- Added a `validate()` macro onto `Request` ([#19063](https://github.com/laravel/framework/pull/19063)) -- Added `FormRequest::validated()` method ([#19112](https://github.com/laravel/framework/pull/19112)) -- ⚠️ Made `request()` helper and `Request::__get()` consistent ([a6ff272](https://github.com/laravel/framework/commit/a6ff272c54677a9f52718292fc0938ffb1871832)) -- Made `Request::routeIs()` work like `Request()::fullUrlIs()` ([#19267](https://github.com/laravel/framework/pull/19267), [bfc5321](https://github.com/laravel/framework/commit/bfc53213f67d50444d3db078737990fa14081d1b), [#19334](https://github.com/laravel/framework/pull/19334)) -- Added `Request::hasAny()` method ([#19367](https://github.com/laravel/framework/pull/19367)) -- ⚠️ Throw validation exception from `ValidatesRequests` without formatting response ([#19929](https://github.com/laravel/framework/pull/19929), [6d33675](https://github.com/laravel/framework/commit/6d33675691aae86c71454b731ceed847256b9dac), [ec88362](https://github.com/laravel/framework/commit/ec88362ee06ad418db93eb0e19f6d285eed7e701), [c264807](https://github.com/laravel/framework/commit/c2648070eb2108b0f9a4189bfbabea195282b963)) -- Added `Request::post()` method ([#20238](https://github.com/laravel/framework/pull/20238)) -- Added `Request::keys()` method ([#20611](https://github.com/laravel/framework/pull/20611)) - -### Routing -- Support fluent resource options ([#18767](https://github.com/laravel/framework/pull/18767), [bb02fb2](https://github.com/laravel/framework/commit/bb02fb27387a8aeb2a47da1fe5ff2e086920b744)) -- Support multiple values in `Router::has()` ([#18758](https://github.com/laravel/framework/pull/18758)) -- ⚠️ Bind empty optional route parameter to `null` instead of empty model instance ([#17521](https://github.com/laravel/framework/pull/17521)) -- Accept patterns on `Route::named()`, `Router::is()` and `Router::currentRouteNamed()` ([#19267](https://github.com/laravel/framework/pull/19267), [bfc5321](https://github.com/laravel/framework/commit/bfc53213f67d50444d3db078737990fa14081d1b)) -- Added `domain()` setter/getter to `Route` ([#19245](https://github.com/laravel/framework/pull/19245), [bba04a1](https://github.com/laravel/framework/commit/bba04a1598c44a892e918c4f308407b0d297f217)) -- Added `Route::redirect()` method ([#19794](https://github.com/laravel/framework/pull/19794)) -- Added `Route::view()` method ([#19835](https://github.com/laravel/framework/pull/19835)) -- ⚠️ Improved `ThrottleRequests` middleware ([#19807](https://github.com/laravel/framework/pull/19807), [#19860](https://github.com/laravel/framework/pull/19860)) -- ⚠️ Return proper 304 responses ([#19867](https://github.com/laravel/framework/pull/19867)) -- Return the resource from `Router::apiResource()` ([#20029](https://github.com/laravel/framework/pull/20029)) -- ⚠️ Moved route model binding resolution logic to model ([#20521](https://github.com/laravel/framework/pull/20521), [370e626](https://github.com/laravel/framework/commit/370e626e5cf7d5763bbb0e58aa2a2cd3c01e2b61), [#20542](https://github.com/laravel/framework/pull/20542), [#20618](https://github.com/laravel/framework/pull/20618), [d911fa8](https://github.com/laravel/framework/commit/d911fa8f5db0100a861a3c1696d426624ec27b4e)) -- Accept string on `parameters()` and `names()` methods ([#20531](https://github.com/laravel/framework/pull/20531), [#20529](https://github.com/laravel/framework/pull/20529)) -- Handle `HEAD` requests in `Router::view()` ([#20672](https://github.com/laravel/framework/pull/20672)) -- Added `ThrottleRequestsWithRedis` middleware ([#20761](https://github.com/laravel/framework/pull/20761), [0a10f9a](https://github.com/laravel/framework/commit/0a10f9a9dab928c9e4d75c66620e35aa73f329c2)) - -### Responses -- ⚠️ Ensure `Arrayable` and `Jsonable` return a `JsonResponse` ([#17875](https://github.com/laravel/framework/pull/17875)) -- ⚠️ Ensure `Arrayable` objects are also morphed by `Response` ([#17868](https://github.com/laravel/framework/pull/17868)) -- Added `SameSite` support to `CookieJar` ([#18040](https://github.com/laravel/framework/pull/18040), [#18059](https://github.com/laravel/framework/pull/18059), [e69d722](https://github.com/laravel/framework/commit/e69d72296cfd9969db569b950721461a521100c4)) -- Accept `HeaderBag` in `ResponseTrait::withHeaders()` ([#18161](https://github.com/laravel/framework/pull/18161)) -- ⚠️ Reset response content-type in `Response::setContent()` ([#18314](https://github.com/laravel/framework/pull/18314), [#20313](https://github.com/laravel/framework/pull/20313)) -- ⚠️ Always retrieve the real original content ([#20002](https://github.com/laravel/framework/pull/20002)) - -### Service Container -- ⚠️ Refactored `Container` ([#19201](https://github.com/laravel/framework/pull/19201)) -- ⚠️ Made container PSR-11 compliant ([#19822](https://github.com/laravel/framework/pull/19822), [a6068b0](https://github.com/laravel/framework/commit/a6068b06ba42700f25b613a7bc3036be75d5bc43), [66325c2](https://github.com/laravel/framework/commit/66325c2c5768a5b10376e1838288c5212e3c9c40)) -- Return the bound instance from `Container::instance()` ([#19442](https://github.com/laravel/framework/pull/19442)) -- ⚠️ Use instance instead of deferred service provider ([#20714](https://github.com/laravel/framework/pull/20714)) - -### Session -- ⚠️ Default value to `true` in `Store::flash()` ([#18136](https://github.com/laravel/framework/pull/18136)) -- ⚠️ Store the user password hash when logging in ([#19843](https://github.com/laravel/framework/pull/19843)) -- ⚠️ Throw `UnauthorizedHttpException` from `failedBasicResponse` ([#20673](https://github.com/laravel/framework/pull/20673)) - -### Support -- Autoload package providers ([#19420](https://github.com/laravel/framework/pull/19420), [a5a0f3e](https://github.com/laravel/framework/commit/a5a0f3e7b82a1a4dc00037c5463a31d42c94903a), [2954091](https://github.com/laravel/framework/commit/295409189af589c6389d01e9d55f5568741149ee), [#19455](https://github.com/laravel/framework/pull/19455), [#19561](https://github.com/laravel/framework/pull/19561), [#19646](https://github.com/laravel/framework/pull/19646)) -- Added support for `Responsable` objects ([c0c89fd](https://github.com/laravel/framework/commit/c0c89fd73cebf9ed56e6c5e69ad35106df03d9db), [1229b7f](https://github.com/laravel/framework/commit/1229b7f45d3f574d7e0262cc2d5aec80ccbb1626), [#19614](https://github.com/laravel/framework/pull/19614), [ef0e37d](https://github.com/laravel/framework/commit/ef0e37d44182ac5043b5459bb25b1861e8e036df)) -- Made `Carbon` macroable and serializeable ([#19771](https://github.com/laravel/framework/pull/19771), [#20568](https://github.com/laravel/framework/pull/20568), [6a18209](https://github.com/laravel/framework/commit/6a18209863a934446d21ad8bc82c83d4b7dee5e7)) -- Support registering macros using classes ([#19782](https://github.com/laravel/framework/pull/19782), [353adbd](https://github.com/laravel/framework/commit/353adbd696e36764227e39980272d38147899d14)) -- ⚠️ Moved `InteractsWithTime` to `Illuminate\Support` ([#20119](https://github.com/laravel/framework/pull/20119), [#20206](https://github.com/laravel/framework/pull/20206)) -- Support callable/invokable objects in `Pipeline` ([#18264](https://github.com/laravel/framework/pull/18264)) -- ⚠️ Prevent access to protected properties using array access on `Model` and `Fluent` ([#18403](https://github.com/laravel/framework/pull/18403)) -- ⚠️ Extend `MessageBag` interface from `Arrayable` and add `getMessages()` method ([#19768](https://github.com/laravel/framework/pull/19768), [#20334](https://github.com/laravel/framework/pull/20334)) -- Handle `Arrayable` items in `MessageBag` ([6f1f4d8](https://github.com/laravel/framework/commit/6f1f4d834a2f985a06d956305fc73b5329363071)) -- Added `isNotEmpty()` method to message bags and paginators ([#19944](https://github.com/laravel/framework/pull/19944)) -- Return the collection iterator from `AbstractPaginator::getIterator()` ([#20098](https://github.com/laravel/framework/pull/20098)) -- ⚠️ Fixed minimum value of paginator `last_page` field ([#20335](https://github.com/laravel/framework/pull/20335)) - -### Task Scheduling -- Fire before callbacks on closure-based scheduling events ([#18861](https://github.com/laravel/framework/pull/18861)) -- Run after-callbacks even if a callback event failed ([#19573](https://github.com/laravel/framework/pull/19573)) -- ⚠️ Fixed bug in `quarterly()` method ([#19600](https://github.com/laravel/framework/pull/19600)) -- ⚠️ Support passing boolean into `when()` and `skip()` ([1d1a96e](https://github.com/laravel/framework/commit/1d1a96e405fec58fd287940f005bd8e40d4e546b)) - -### Testing -- ⚠️ Switched to PHPUnit 6 ([#17755](https://github.com/laravel/framework/pull/17755), [#17864](https://github.com/laravel/framework/pull/17864)) -- ⚠️ Renamed authentication assertion methods ([#17924](https://github.com/laravel/framework/pull/17924), [494a177](https://github.com/laravel/framework/commit/494a1774f217f0cd6b4efade63e200e3ac65f201)) -- ⚠️ Unify database testing traits into `RefreshDatabase` trait ([79c6f67](https://github.com/laravel/framework/commit/79c6f6774eecf77aef8ed5e2f270551a6f378f1d), [0322e32](https://github.com/laravel/framework/commit/0322e3226196a435db436e2a00c035be892c2466), [#20308](https://github.com/laravel/framework/pull/20308)) -- ⚠️ Changed Blade tests namespace to `Illuminate\Tests\View\Blade` ([#19675](https://github.com/laravel/framework/pull/19675)) -- Added integration tests for the framework itself ([182027d](https://github.com/laravel/framework/commit/182027d3290e9a2e1bd9e2d52c125177ef6c6af6), [#18438](https://github.com/laravel/framework/pull/18438), [#18780](https://github.com/laravel/framework/pull/18780), [#19001](https://github.com/laravel/framework/pull/19001), [#20073](https://github.com/laravel/framework/pull/20073)) -- Allow disabling of specific middleware ([#18673](https://github.com/laravel/framework/pull/18673)) -- Added `withoutExceptionHandling()` method ([a171f44](https://github.com/laravel/framework/commit/a171f44594c248afe066fee74fad640765b12da0)) -- Support inline eloquent factory states ([#19060](https://github.com/laravel/framework/pull/19060)) -- Allow `assertSessionHasErrors()` to look into different error bags ([#19172](https://github.com/laravel/framework/pull/19172), [4287ebc](https://github.com/laravel/framework/commit/4287ebc76025cd31e0ba6730481a95aeb471e305)) -- Ensure Redis is available in cache lock tests ([#19791](https://github.com/laravel/framework/pull/19791)) -- Skip tests if Memcached is not found ([#20018](https://github.com/laravel/framework/pull/20018)) -- ⚠️ Clear `Carbon` mock during tear down ([#19934](https://github.com/laravel/framework/pull/19934)) -- Added debug info to `NotFoundHttpException` in `InteractsWithExceptionHandling` ([#20000](https://github.com/laravel/framework/pull/20000)) -- Added `MailFake::assertSentTimes()`, `QueueFake::assertPushedTimes()` and `BusFake::assertDispatchedTimes()` methods ([#20485](https://github.com/laravel/framework/pull/20485), [e657f6e](https://github.com/laravel/framework/commit/e657f6ec20867fc748e4f8b8ca1bbaa344c07acb)) -- Added queue assertions to `MailFake` ([#20454](https://github.com/laravel/framework/pull/20454), [#20701](https://github.com/laravel/framework/pull/20701)) -- Added `assertNothingSent()` and `assertSentTimes()` methods to `NotificationFake` ([#20651](https://github.com/laravel/framework/pull/20651)) -- Added Mockery expectations to the assertion count ([#20606](https://github.com/laravel/framework/pull/20606)) -- Fake the default storage disk by default ([#20625](https://github.com/laravel/framework/pull/20625)) -- Support sending default headers with requests ([#20590](https://github.com/laravel/framework/pull/20590), [c32418e](https://github.com/laravel/framework/commit/c32418e8ca13e1fef3908d3a497ea49df0cebbb3)) -- Support disabling of exception handling for specified exceptions ([#20729](https://github.com/laravel/framework/pull/20729), [2db9716](https://github.com/laravel/framework/commit/2db9716186c71cd0604277fc377a2654a6f10aaf)) - -### Validation -- Added support for custom validation rule objects ([#19155](https://github.com/laravel/framework/pull/19155), [2aa5ea8](https://github.com/laravel/framework/commit/2aa5ea8a898bd220015ab9be453b36723ffb186e)) -- Validate against `DateTimeInterface` instead of `DateTime` ([#20110](https://github.com/laravel/framework/pull/20110)) -- ⚠️ Made several method in `ValidatesAttributes` public ([#20200](https://github.com/laravel/framework/pull/20200)) -- ⚠️ Added `errors()` method to `Validator` interface ([#20337](https://github.com/laravel/framework/pull/20337)) -- Extend `Exists` and `Unique` rule from `DatabaseRule` class ([#20563](https://github.com/laravel/framework/pull/20563)) -- Added `whereIn()` and `whereNotIn()` constraints to `DatabaseRule` ([#20691](https://github.com/laravel/framework/pull/20691), [#20739](https://github.com/laravel/framework/pull/20739), [52d28e3](https://github.com/laravel/framework/commit/52d28e3190833457d4efe811d1e993c1a4bba393)) -- Added `date_equals` rule ([#20646](https://github.com/laravel/framework/pull/20646)) - -### Views -- ⚠️ Camel case variables names passed to views ([#18083](https://github.com/laravel/framework/pull/18083)) -- Added pagination template for Semantic UI ([#18463](https://github.com/laravel/framework/pull/18463)) -- Allow easier `ViewFactory` overriding ([#20205](https://github.com/laravel/framework/pull/20205), [56f103c](https://github.com/laravel/framework/commit/56f103c69757cc643120a3de9b601262ed1ff2dd)) -- Added `View::first()` ([#20695](https://github.com/laravel/framework/pull/20695), [f18318b](https://github.com/laravel/framework/commit/f18318b35b246a7f279781fe7403d137fb55be05)) diff --git a/CHANGELOG-5.6.md b/CHANGELOG-5.6.md deleted file mode 100644 index e4c5604bbb82..000000000000 --- a/CHANGELOG-5.6.md +++ /dev/null @@ -1,636 +0,0 @@ -# Release Notes for 5.6.x - -## v5.6.34 (2018-08-21) - -### Changed -- Wrap columns in whereRowValues ([#25179](https://github.com/laravel/framework/pull/25179)) -- Make copyrights line localizable in mail messages ([#25183](https://github.com/laravel/framework/pull/25183)) -- When specifying events to be faked, other events should be normally dispatched ([#25185](https://github.com/laravel/framework/pull/25185)) - -### Fixed -- Fix URL validation pattern on PHP 7.3 ([#25194](https://github.com/laravel/framework/pull/25194)) - -## v5.6.32 & v5.6.33 (2018-08-09) - -### Added -- Added serialization parameters to helper functions decrypt and encrypt ([#25166](https://github.com/laravel/framework/pull/25166)) - -## v5.6.31 (2018-08-09) - -### Changed -- Make Auth/Recaller handle serialized and unserialized cookies ([#25167](https://github.com/laravel/framework/pull/25167)) - -## v5.6.30 (2018-08-08) - -### Added -- Support passing CC/CBC in array form in mail notification ([#25029](https://github.com/laravel/framework/pull/25029)) -- Added Rule::requiredIf ([#25066](https://github.com/laravel/framework/pull/25066)) -- Support raw expressions in whereRowValues() ([#25117](https://github.com/laravel/framework/pull/25117)) - -### Changed -- Stopped serializing csrf cookie / header ([#25121](https://github.com/laravel/framework/pull/25121)) - -### Fixed -- Avoid an "Undefined offset: 0" if no job was pulled from redis queue ([#25020](https://github.com/laravel/framework/pull/25020)) -- Updating the Pluralizer class to respect the grammar rule ([#25063](https://github.com/laravel/framework/pull/25063)) - -## v5.6.29 (2018-07-26) - -### Added -- Added restored() and forceDeleted() to observer stub ([#40ba2ee](https://github.com/laravel/framework/commit/49ac5be5ae9b69f160058a3f10022c9511222db5)) -- Added UploadedFile::get() ([#24924](https://github.com/laravel/framework/pull/24924)) -- Added an alias for a single FactoryBuilder state definition ([#24937](https://github.com/laravel/framework/pull/24937)) - -### Changed -- Allow closure to determine if event should be faked ([#24887](https://github.com/laravel/framework/pull/24887)) -- Update error message for MailFake::assertSent() ([#24911](https://github.com/laravel/framework/pull/24911)) -- Return instance of spy when swapping facade for a Mockery spy ([#24918](https://github.com/laravel/framework/pull/24918)) -- Renamed Mailer::setGlobalTo() to setGlobalToAndRemoveCcAndBcc() to be more clear about what it does ([#24917](https://github.com/laravel/framework/pull/24917)) -- Update the font path used in frontend stub ([#24926](https://github.com/laravel/framework/pull/24926)) - -### Fixed -- Fixed an issue when passing an array to Request::is() ([#24885](https://github.com/laravel/framework/pull/24885)) -- Fixed message string in NotificationFake::assertSentToTimes() ([#24929](https://github.com/laravel/framework/pull/24929)) - -## v5.6.28 (2018-07-17) - -### Added -- Added support for variadic params in Cache\Repository::tags() ([#24810](https://github.com/laravel/framework/pull/24810)) -- Handle unquoted JSON selector for MYSQL ([#24817](https://github.com/laravel/framework/pull/24817)) -- Added ability to generate single action controller ([#24843](https://github.com/laravel/framework/pull/24843)) -- Applied improvements to the generated migration name ([#24845](https://github.com/laravel/framework/pull/24845)) -- Added JPEG support to FileFactory::image() ([#24853](https://github.com/laravel/framework/pull/24853)) - -### Changed -- Stop reporting PDOException manually from inside ConnectionFactory ([#24864](https://github.com/laravel/framework/pull/24864)) -- remove unnecessary foreach from is() method ([#24872](https://github.com/laravel/framework/pull/24872)) - - -## v5.6.27 (2018-07-10) - -### Added -- Add missing phpredis connection parameters to PhpRedisConnector ([#24678](https://github.com/laravel/framework/pull/24678)) -- Apply realpath option to refresh and fresh commands ([#24683](https://github.com/laravel/framework/pull/24683)) -- Added `loggedOut()` method in AuthenticatesUsers ([#24717](https://github.com/laravel/framework/pull/24717)) - -### Changed -- Use value() helper in whenLoaded() ([#24644](https://github.com/laravel/framework/pull/24644)) -- Allow accessing the value of the current migrator connection ([#24665](https://github.com/laravel/framework/pull/24665)) -- Check if configuration cache is valid after saving ([#24722](https://github.com/laravel/framework/pull/24722)) -- Except URIs from CheckForMaintenanceMode middleware ([#24740](https://github.com/laravel/framework/pull/24740)) - -## v5.6.26 (2018-06-20) - -### Added -- Added two Azure SQL server connection lost messages ([#24566](https://github.com/laravel/framework/pull/24566)) -- Allowed passing of recipient name in Mail notifications ([#24606](https://github.com/laravel/framework/pull/24606)) -- Started passing table name to the post migration create hooks ([#24621](https://github.com/laravel/framework/pull/24621)) -- Allowed array/collections in Auth::attempt method ([#24620](https://github.com/laravel/framework/pull/24620)) - -### Changed -- Prevent calling the bootable trait boot method multiple times ([#24556](https://github.com/laravel/framework/pull/24556)) -- Make chunkById() work for non-incrementing/non-integer ids as well ([#24563](https://github.com/laravel/framework/pull/24563)) -- Make ResetPassword Notification translatable ([#24534](https://github.com/laravel/framework/pull/24534)) - - -## v5.6.25 (2018-06-12) - -### Added -- Added whereJsonContains() to SQL Server ([#24448](https://github.com/laravel/framework/pull/24448)) -- Added Model::unsetRelation() ([#24486](https://github.com/laravel/framework/pull/24486)) -- Added Auth::hasUser() ([#24518](https://github.com/laravel/framework/pull/24518)) -- add assertOk() response assertion ([#24536](https://github.com/laravel/framework/pull/24536)) - -### Changed -- Set the controller name on the action array when callable array syntax is used ([#24468](https://github.com/laravel/framework/pull/24468)) -- Make database grammars macroable ([#24513](https://github.com/laravel/framework/pull/24513)) -- Allow "app" migrations to override package migrations ([#24521](https://github.com/laravel/framework/pull/24521)) - - -## v5.6.24 (2018-06-04) - -### Added -- Added assertSessionHasNoErrors() test helper ([#24308](https://github.com/laravel/framework/pull/24308)) -- Added support for defining and enforcing a Spatial reference system for a Point column ([#24320](https://github.com/laravel/framework/pull/24320)) -- Added Builder::whereJsonDoesntContain() and Builder::orWhereJsonDoesntContain() ([#24367](https://github.com/laravel/framework/pull/24367)) -- Added Queueable, SerializesModels to all notification events ([#24368](https://github.com/laravel/framework/pull/24368)) -- Allow callable array syntax in route definition ([#24385](https://github.com/laravel/framework/pull/24385)) -- Added JSON SELECT queries to SQL Server ([#24397](https://github.com/laravel/framework/pull/24397)) -- Added whereJsonContains() to SQL Server ([#24448](https://github.com/laravel/framework/pull/24448)) -- Added Model::unsetRelation() ([#24486](https://github.com/laravel/framework/pull/24486)) -- Added Auth::hasUser() ([#24518](https://github.com/laravel/framework/pull/24518)) -- add assertOk() response assertion ([#24536](https://github.com/laravel/framework/pull/24536)) - -### Changed -- Optimize query builder's `pluck()` method ([#23482](https://github.com/laravel/framework/pull/23482)) -- Allow passing object instances regardless of the parameter name to method injection ([#24234](https://github.com/laravel/framework/pull/24234)) -- Extract setting mutated attribute into method ([#24307](https://github.com/laravel/framework/pull/24307)) -- Let apiResource support except option ([#24319](https://github.com/laravel/framework/pull/24319)) -- Skip null/empty values in SeeInOrder ([#24395](https://github.com/laravel/framework/pull/24395)) -- Sync Original modal attributes after soft deletion ([#24400](https://github.com/laravel/framework/pull/24400)) -- Set the controller name on the action array when callable array syntax is used ([#24468](https://github.com/laravel/framework/pull/24468)) -- Make database grammars macroable ([#24513](https://github.com/laravel/framework/pull/24513)) -- Allow "app" migrations to override package migrations ([#24521](https://github.com/laravel/framework/pull/24521)) - -### Fixed -- Fixed typo of missing underscore in `not_regexp` rule name ([#24297](https://github.com/laravel/framework/pull/24297)) -- Cleanup null relationships in loadMorph ([#24322](https://github.com/laravel/framework/pull/24322)) -- Fix loadMissing() relationship parsing ([#24329](https://github.com/laravel/framework/pull/24329)) -- Fix FormRequest class authorization validation priority ([#24369](https://github.com/laravel/framework/pull/24369)) -- Fix custom blade conditional ignoring 0 as argument ([#24394](https://github.com/laravel/framework/pull/24394)) - - -## v5.6.23 (2018-05-24) - -### Added -- Added support for renaming indices ([#24147](https://github.com/laravel/framework/pull/24147)) -- Added `Event::fakeFor()` method ([#24230](https://github.com/laravel/framework/pull/24230)) -- Added `@canany` Blade directive ([#24137](https://github.com/laravel/framework/pull/24137)) -- Added `TestReponse::assertLocation()` method ([#24267](https://github.com/laravel/framework/pull/24267)) - -### Changed -- Validation bypass for `before` and `after` rules when paired with `date_format` rule ([#24191](https://github.com/laravel/framework/pull/24191)) - -### Fixed -- Fixed an issue with `Cache::increment()` when expiration is `null` ([#24228](https://github.com/laravel/framework/pull/24228)) -- Ignore non-where bindings in nested where constraints ([#24000](https://github.com/laravel/framework/pull/24000)) -- Fixed `withCount()` binding problems ([#24240](https://github.com/laravel/framework/pull/24240)) - - - -## v5.6.22 (2018-05-15) - -### Added -- Added `Collection::loadMissing()` method ([#24166](https://github.com/laravel/framework/pull/24166), [#24215](https://github.com/laravel/framework/pull/24215)) - -### Changed -- Support updating NPM dependencies from preset ([#24189](https://github.com/laravel/framework/pull/24189), [a6542b0](https://github.com/laravel/framework/commit/a6542b0972a1a92c1249689d3e1b46b3bc4e59fa)) -- Support returning `Responsable` from middleware ([#24201](https://github.com/laravel/framework/pull/24201)) - - -## v5.6.21 (2018-05-08) - -### Added -- Added `FilesystemManager::forgetDisk()` method ([#24057](https://github.com/laravel/framework/pull/24057), [cbfb4fb](https://github.com/laravel/framework/commit/cbfb4fbf0784ac5eb08ce2effe8727f3428d5812)) -- Added `--allow` parameter to `down` command ([#24003](https://github.com/laravel/framework/pull/24003)) -- Added more comparison validation rules (`gt`, `lt`, `gte`, `lte`) ([#24091](https://github.com/laravel/framework/pull/24091), [#24135](https://github.com/laravel/framework/pull/24135)) -- Added `TestResponse::assertCookieNotExpired()` method ([#24119](https://github.com/laravel/framework/pull/24119)) - -### Changed -- Redis connections now implement the `Contracts/Redis/Connection` interface ([#24142](https://github.com/laravel/framework/pull/24142)) - -### Fixed -- Fixed unsetting request parameters during `HEAD` requests ([#24092](https://github.com/laravel/framework/pull/24092)) -- Fixed `HasManyThrough` returning incorrect results with `chunk()` ([#24096](https://github.com/laravel/framework/pull/24096), [5d3d98a](https://github.com/laravel/framework/commit/5d3d98a8c620458b9c1f80fbcefa1d88f9490784)) -- Fixed `dateBasedWhere()` with raw expressions when using SQLite ([#24102](https://github.com/laravel/framework/pull/24102)) -- Fixed `whereYear()` not accepting integers when using SQLite ([#24115](https://github.com/laravel/framework/pull/24115)) -- Remove full base URL from generated paths ([#24101](https://github.com/laravel/framework/pull/24101)) - - -## v5.6.20 (2018-05-02) - -### Added -- Support passing `Response` and `Responsable` to `abort()` ([4e29889](https://github.com/laravel/framework/commit/4e298893c746734de7049cc69483ce252f6d93c8)) -- Added `pingBeforeIf` and `thenPingIf` methods to task scheduler ([#24077](https://github.com/laravel/framework/pull/24077), [1bf54d2](https://github.com/laravel/framework/commit/1bf54d23b5d2207d7c60a549584c774f9ff8386b)) -- Added `withDefault()` support to `MorphTo` relationships ([#24061](https://github.com/laravel/framework/pull/24061)) - -### Fixed -- Fixed URL generator when request has base path ([#24074](https://github.com/laravel/framework/pull/24074)) - - -## v5.6.19 (2018-04-30) - -### Added -- Added support for custom SparkPost endpoint ([#23910](https://github.com/laravel/framework/pull/23910)) -- Added `Optional::__isset()` handling ([#24042](https://github.com/laravel/framework/pull/24042)) -- Added support for multiple cc, bcc and reply-to recipients on mail notifications ([#23760](https://github.com/laravel/framework/pull/23760)) - -### Fixed -- Accept only two arguments on `orWhereDate()` ([#24043](https://github.com/laravel/framework/pull/24043)) -- Fixed relative route URL generation when using custom host formatter ([#24051](https://github.com/laravel/framework/pull/24051)) - - -## v5.6.18 (2018-04-26) - -### Added -- Added support for MySQL 8 ([#23948](https://github.com/laravel/framework/pull/23948)) -- Added support for custom filesystem drivers URLs ([#23964](https://github.com/laravel/framework/pull/23964)) -- Added more PostgreSQL operators ([#23945](https://github.com/laravel/framework/pull/23945)) -- Added support for JSONP callback when broadcasting using Pusher ([#24018](https://github.com/laravel/framework/pull/24018), [b9ab427](https://github.com/laravel/framework/commit/b9ab4272192d079539c32787d66a35a31a7815ce)) - -### Changed -- Support chaining using `$this->be()` helper ([#23919](https://github.com/laravel/framework/pull/23919)) -- Improved pagination accessibility ([#23962](https://github.com/laravel/framework/pull/23962)) -- Changed response code of `ValidationException` in `ThrottlesLogins` to `429` ([#24002](https://github.com/laravel/framework/pull/24002)) -- Throw exception if called command doesn't exist ([#23942](https://github.com/laravel/framework/pull/23942)) -- Made notification email translatable ([#23903](https://github.com/laravel/framework/pull/23903)) - -### Fixed -- Fixed saving timestamp columns on pivots without parent ([#23917](https://github.com/laravel/framework/pull/23917)) -- Quote collation names in MySQL migrations ([#23989](https://github.com/laravel/framework/pull/23989)) -- Fixed sending plain-text only emails ([#23981](https://github.com/laravel/framework/pull/23981)) -- Fixed counting the number of jobs on `Queue::fake()` ([#23933](https://github.com/laravel/framework/pull/23933)) - - -## v5.6.17 (2018-04-17) - -### Added -- Added helpers for subquery joins ([#23818](https://github.com/laravel/framework/pull/23818)) - -### Changed -- Allow `PendingResourceRegistration` to be fluently registered ([#23890](https://github.com/laravel/framework/pull/23890)) -- Allow asserting an integer with `assertSee*()` ([#23892](https://github.com/laravel/framework/pull/23892)) -- Allow passing `Collection` to `Rule::in()` and `Rule::notIn()` ([#23875](https://github.com/laravel/framework/pull/23875)) - -### Fixed -- Lock Carbon version at `1.25.*` ([27b8844](https://github.com/laravel/framework/commit/27b88449805c1e9903fe4088f303c0858336b23b)) - -### Removed -- Removed form error for password confirmation ([#23887](https://github.com/laravel/framework/pull/23887)) - - -## v5.6.16 (2018-04-09) - -### Added -- Support executing artisan commands using class names ([#23764](https://github.com/laravel/framework/pull/23764)) -- Make `View` macroable ([#23787](https://github.com/laravel/framework/pull/23787)) -- Added database `Connection::unsetEventDispatcher()` method ([#23832](https://github.com/laravel/framework/pull/23832)) -- Support IAM role session token to be used with SES ([#23766](https://github.com/laravel/framework/pull/23766)) - -### Changed -- Added displayable value to `required_unless` rule ([#23833](https://github.com/laravel/framework/pull/23833)) - -### Fixed -- Fixed `RedisQueue::blockingPop()` check when using PhpRedis ([#23757](https://github.com/laravel/framework/pull/23757)) - - -## v5.6.15 (2018-03-30) - -### Fixed -- Fixed variable reference in `RedisTaggedCache::decrement()` ([#23736](https://github.com/laravel/framework/pull/23736)) -- Check `updated_at` column existence in `HasOneOrMany::update()` ([#23747](https://github.com/laravel/framework/pull/23747)) - -### Security -- Check `iv` length in `Encrypter::validPayload()` ([886d261](https://github.com/laravel/framework/commit/886d261df0854426b4662b7ed5db6a1c575a4279)) - - -## v5.6.14 (2018-03-28) - -### Added -- Added `SlackMessage::info()` method ([#23711](https://github.com/laravel/framework/pull/23711)) -- Added `SessionGuard::logoutOtherDevices()` method ([9c51e49](https://github.com/laravel/framework/commit/9c51e49a56ff15fc47ac1a6bf232c32c25d14fd0)) - -### Changed -- Replaced Blade's `or` operator with null-coalescing operator ([13f732e](https://github.com/laravel/framework/commit/13f732ed617e41608e4ae021efc9d13e43375a26)) - -### Fixed -- Get Blade compiler from engine resolver ([#23710](https://github.com/laravel/framework/pull/23710)) -- Default to an empty string when validating the URL signatures ([#23721](https://github.com/laravel/framework/pull/23721)) - - -## v5.6.13 (2018-03-26) - -### Added -- Added `view:cache` command ([9fd1273](https://github.com/laravel/framework/commit/9fd1273ad79a46bb3aa006129109c6bc72766e4b), [2ab8acf](https://github.com/laravel/framework/commit/2ab8acfef5d7e784148b2367b5bcf083a0d0d024)) -- Added `min()` and `max()` to as higher order proxies ([#23560](https://github.com/laravel/framework/pull/23560)) -- Added `@elseauth` and `@elseguest` Blade directives ([#23569](https://github.com/laravel/framework/pull/23569)) -- Added support for hashing configuration ([#23573](https://github.com/laravel/framework/pull/23573), [d6e3ca9](https://github.com/laravel/framework/commit/d6e3ca97ff4175ff6a9b270b65b04c0d836a7bec)) -- Allow tagged cache keys to be incremented/decremented ([#23578](https://github.com/laravel/framework/pull/23578)) -- Added `SeeInOrder` constraint to avoid risky test notices ([#23594](https://github.com/laravel/framework/pull/23594), [ca39449](https://github.com/laravel/framework/commit/ca39449c83b0f8d42e1ad1b4086239584fda0967)) -- Support higher order `groupBy()` ([#23608](https://github.com/laravel/framework/pull/23608)) -- Support disabling setting `created_at` in models ([#23667](https://github.com/laravel/framework/pull/23667)) -- Added callback support to `optional()` helper ([#23688](https://github.com/laravel/framework/pull/23688)) -- Added `Eloquent\Collection::loadMorph()` method ([#23626](https://github.com/laravel/framework/pull/23626)) - -### Changed -- Support generating a signed route with a `UrlRoutable` parameter ([#23584](https://github.com/laravel/framework/pull/23584)) -- Use `DIRECTORY_SEPARATOR` in `Application::environmentFilePath()` ([#23596](https://github.com/laravel/framework/pull/23596)) -- Support states on model factory after callbacks ([#23551](https://github.com/laravel/framework/pull/23551), [#23676](https://github.com/laravel/framework/pull/23676)) -- Use `hash_equals()` for verifying URL signatures ([#23618](https://github.com/laravel/framework/pull/23618)) -- Refactored `Exceptions/Handler` ([f9162c9](https://github.com/laravel/framework/commit/f9162c9898c58be18f166e1832699b83602404b1), [6c5d971](https://github.com/laravel/framework/commit/6c5d9717224f970d542333813901220a3e950fad)) -- Changed status code of `InvalidSignatureException` from `401` to `403` ([#23662](https://github.com/laravel/framework/pull/23662), [c99911f](https://github.com/laravel/framework/commit/c99911f45432440beee2a9b6d7b5a19ef8d50997)) - -### Fixed -- Revered breaking changes in `ManagesLoops` ([d0a2613](https://github.com/laravel/framework/commit/d0a2613f5af223b67db79d59c21aba33b5cc9cdf)) -- Set exit status in serve command ([#23689](https://github.com/laravel/framework/pull/23689)) - - -## v5.6.12 (2018-03-14) - -### Added -- Added `fromSub()` and `fromRaw()` methods to query builder ([#23476](https://github.com/laravel/framework/pull/23476)) -- Added "Not Regex" validation rule ([#23475](https://github.com/laravel/framework/pull/23475)) -- Added seed parameter to `Arr::shuffle()` ([#23490](https://github.com/laravel/framework/pull/23490)) -- Added after callback to model factories ([#23495](https://github.com/laravel/framework/pull/23495), [d79509d](https://github.com/laravel/framework/commit/d79509dfb82a8518ca0a0ccb9d4986cfa632b1ab)) -- Added `Request::anyFilled()` method ([#23499](https://github.com/laravel/framework/pull/23499), [896d817](https://github.com/laravel/framework/commit/896d817a13bcf9bc879e53e4f8b7b5b15c27ee86)) -- Added support for signed routes ([#23519](https://github.com/laravel/framework/pull/23519)) -- Added `assertNotFound()` and `assertForbidden()` methods to `TestResponse` ([#23526](https://github.com/laravel/framework/pull/23526)) -- Added test helpers to assert that a job has been queued with a chain ([#23531](https://github.com/laravel/framework/pull/23531), [696f4d8](https://github.com/laravel/framework/commit/696f4d88c132ac39a3a805dbe490b3b754c9ce5f)) - -### Changed -- Only set id on `NotificationFake` if there is no id set ([#23470](https://github.com/laravel/framework/pull/23470)) -- Check whether `fetch()` method exists in `Application::output()` ([#23471](https://github.com/laravel/framework/pull/23471)) -- Improve asset loading in `app.stub` ([#23479](https://github.com/laravel/framework/pull/23479)) -- Support ignoring a model during a unique validation check ([#23524](https://github.com/laravel/framework/pull/23524)) -- Support multiple model observers ([#23507](https://github.com/laravel/framework/pull/23507)) -- `LogManager` driver capable of producing logger with any Monolog handler ([#23527](https://github.com/laravel/framework/pull/23527), [d499617](https://github.com/laravel/framework/commit/d4996170ec0ea2d5189db213c51ebcf4f526ab6d)) -- Support passing model instance to `updateExistingPivot()` ([#23535](https://github.com/laravel/framework/pull/23535)) -- Allow for custom `TokenGuard` fields ([#23542](https://github.com/laravel/framework/pull/23542)) - -### Fixed -- Fixed clearing the cache without a cache directory ([#23538](https://github.com/laravel/framework/pull/23538)) - - -## v5.6.11 (2018-03-09) - -### Fixed -- Fix for Carbon 1.24.1 ([#23464](https://github.com/laravel/framework/pull/23464)) - - -## v5.6.10 (2018-03-09) - -### Added -- Added `Blueprint::dropMorphs()` ([#23431](https://github.com/laravel/framework/pull/23431)) -- Added `Mailable::attachFromStorage()` methods ([0fa361d](https://github.com/laravel/framework/commit/0fa361d0e2e111a1a684606a675b414ebd471257)) -- Added `orWhere*()` builder methods for day, month and year ([#23449](https://github.com/laravel/framework/pull/23449)) - -### Changed -- Added `v-pre` to dropdown link in `app.stub` ([98fdbb0](https://github.com/laravel/framework/commit/98fdbb098cf52a74441fe949be121c18e3dbbe6a)) -- Handle more JSON errors gracefully when `JSON_PARTIAL_OUTPUT_ON_ERROR` is set ([#23410](https://github.com/laravel/framework/pull/23410), [972b82a](https://github.com/laravel/framework/commit/972b82a67c6dd09fa01bf5e0b349a547ece33666)) -- Add bubble, permission and locking config to single/daily log ([#23439](https://github.com/laravel/framework/pull/23439)) -- Use `Str::contains()` instead of `str_contains()` ([ae4cb28](https://github.com/laravel/framework/commit/ae4cb28d040dca8db9a678978efd9ab63c6ea9fd)) - -### Fixed -- Fixed `unique()` call in `Validator::validate()` ([#23432](https://github.com/laravel/framework/pull/23432)) -- Fix for Carbon 1.24.0 ([67d8a4b](https://github.com/laravel/framework/commit/67d8a4b15ffdeeacc2c27efad05735a59dba1c44)) - - -## v5.6.9 (2018-03-07) - -### Changed -- Regenerate token when regenerating the session ([20e8419](https://github.com/laravel/framework/commit/20e84191d5ef21eb5c015908c11eabf8e81d6212)) - -### Fixed -- Fixed an issue with resources when loading a single merge value with an associative array ([#23414](https://github.com/laravel/framework/pull/23414)) - - -## v5.6.8 (2018-03-06) - -### Added -- Added support for MySQL’s sounds-like operator ([#23351](https://github.com/laravel/framework/pull/23351)) -- Added `ThrottleRequestsException` exception ([#23358](https://github.com/laravel/framework/pull/23358) -- Added `@dump` Blade directive ([#23364](https://github.com/laravel/framework/pull/23364)) -- Added `Collection::whereInstanceOfMethod()` ([78b5b92](https://github.com/laravel/framework/commit/78b5b9298d48a5199ad494a4a7cc411dacd84256)) -- Added `Dispatchable::dispatchNow()` ([#23399](https://github.com/laravel/framework/pull/23399)) - -### Changed -- Allow extension of `DatabaseNotification` model attributes ([#23337](https://github.com/laravel/framework/pull/23337)) -- Made auth scaffolding translatable ([#23342](https://github.com/laravel/framework/pull/23342)) -- Use `getKeyName()` in `getForeignKey()` ([#23362](https://github.com/laravel/framework/pull/23362)) -- Sort `FileSystem` files and directories by name ([#23387](https://github.com/laravel/framework/pull/23387)) -- Return validated data from `Validator::validate()` ([#23397](https://github.com/laravel/framework/pull/23397), [3657d66](https://github.com/laravel/framework/commit/3657d66b0be6623bbbd69ed2f2667ac76c36dea3)) - -### Fixed -- Fixed `serve` command escaping ([#23348](https://github.com/laravel/framework/pull/23348)) -- Fixed an issue with multiple select statements in combination with `withCount()` ([#23357](https://github.com/laravel/framework/pull/23357)) -- Fixed conditional loading issues ([#23369](https://github.com/laravel/framework/pull/23369)) -- Prevent considering arrays as `callable` while building model factories ([#23372](https://github.com/laravel/framework/pull/23372)) -- Move `tightenco/collect` to Composer’s `conflict` ([#23379](https://github.com/laravel/framework/pull/23379)) -- Set up loop variable correctly on all `Traversable` objects ([#23388](https://github.com/laravel/framework/pull/23388), [49770ec](https://github.com/laravel/framework/commit/49770eca4e2e780d4e8cdc762e2adbcab8b924fa)) -- Removed attribute filling from pivot model ([#23401](https://github.com/laravel/framework/pull/23401)) - - -## v5.6.7 (2018-02-28) - -### Added -- Added SFTP filesystem driver ([#23308](https://github.com/laravel/framework/pull/23308)) - -### Changed -- Pass parent model to `withDefault()` callback ([#23334](https://github.com/laravel/framework/pull/23334)) -- Upgrade Parsedown to 1.7.0 ([816f893](https://github.com/laravel/framework/commit/816f893c30152e95b14c4ae9d345f53168e5a20e)) - -### Fixed -- Fixed `PostgresGrammar::whereTime()` casting ([#23323](https://github.com/laravel/framework/pull/23323)) -- Fixed `SQLiteGrammar::whereTime()` correct ([#23321](https://github.com/laravel/framework/pull/23321)) - - -## v5.6.6 (2018-02-27) - -### Added -- Added `sortKeys()` and `sortKeysDesc()` methods to `Collection` ([#23286](https://github.com/laravel/framework/pull/23286)) - -### Changed -- Return `null` from `optional()` helper if object property is undefined ([#23267](https://github.com/laravel/framework/pull/23267)) -- Cache event wildcard listeners ([#23299](https://github.com/laravel/framework/pull/23299), [82099cb](https://github.com/laravel/framework/commit/82099cb3fdfe79f3f4f17008daf169f13fefffc0)) -- Changed `morphs()` and `nullableMorphs()` to use `unsignedBigInteger()` ([#23320](https://github.com/laravel/framework/pull/23320)) - -### Fixed -- Prevent delayed jobs in v5.5 fail to run in v5.6 ([#23287](https://github.com/laravel/framework/pull/23287)) -- `Queue::bulk()` fake now properly pushes expected jobs ([#23294](https://github.com/laravel/framework/pull/23294)) -- Fixed the list of packages removed when the "none" preset is installed ([#23305](https://github.com/laravel/framework/pull/23305)) -- Fixed an issue with `orHaving()` arguments ([e7f13be](https://github.com/laravel/framework/commit/e7f13be6a5dd8c348243a5f5dce488359160937c)) - - -## v5.6.5 (2018-02-22) - -### Added -- Added model reference to `MassAssignmentException` ([#23229](https://github.com/laravel/framework/pull/23229)) -- Added support for setting the locale on `Mailable` ([#23178](https://github.com/laravel/framework/pull/23178), [a432d9e](https://github.com/laravel/framework/commit/a432d9e1fabe14cebecdf9d9637a3d4b8167b478)) -- Added new udiff methods to the `Collection` ([#23107](https://github.com/laravel/framework/pull/23107)) - -### Fixed -- Fixed an issue with `orWhere*()` arguments ([e5042e1](https://github.com/laravel/framework/commit/e5042e10f940579b4457c99a51319887cd0a7b6f), [33739f9](https://github.com/laravel/framework/commit/33739f9887413f9855fb93a04211009256d5d904)) - - -## v5.6.4 (2018-02-21) - -### Added -- Added the ability to set message ID right hand side ([#23181](https://github.com/laravel/framework/pull/23181)) -- Support callbacks as custom log drivers ([#23184](https://github.com/laravel/framework/pull/23184)) -- Added `Blade::include()` method for include aliases ([#23172](https://github.com/laravel/framework/pull/23172)) -- Added `broadcastType()` method to notifications ([#23236](https://github.com/laravel/framework/pull/23236), [4227bd7](https://github.com/laravel/framework/commit/4227bd78d5ab2743e694bfd34784a5ccced20bef)) - -### Changed -- Moved clone logic from `FormRequestServiceProvider` to `Request` ([b0c2459](https://github.com/laravel/framework/commit/b0c2459d7e55519d1c61927ab526e489a3a52eaf)) -- Changed pagination arrow symbols ([#23127](https://github.com/laravel/framework/pull/23127)) -- Update React version in preset ([#23134](https://github.com/laravel/framework/pull/23134)) -- Added an empty error bag when rendering HTTP exception views ([#23139](https://github.com/laravel/framework/pull/23139)) -- Normalized actions when using `route:list` command ([#23148](https://github.com/laravel/framework/pull/23148)) -- Updated required Carbon version ([201bbec](https://github.com/laravel/framework/commit/201bbec1e2eec0ecc1dfeece05fbc4196058028a)) -- Improved `BadMethodCallException` messages ([#23232](https://github.com/laravel/framework/pull/23232)) -- Support date validation rules when comparison has relative time ([#23211](https://github.com/laravel/framework/pull/23211)) - -### Fixed -- Returns same `Logger` instance from `LogManager` ([#23118](https://github.com/laravel/framework/pull/23118)) -- Register missing `hash.driver` DI ([#23114](https://github.com/laravel/framework/pull/23114)) -- Fixed an issue with starting two database transactions in tests ([#23132](https://github.com/laravel/framework/pull/23132)) -- Don't replace `tightenco/collect` ([#23147](https://github.com/laravel/framework/pull/23147), [#23153](https://github.com/laravel/framework/pull/23153), [#23160](https://github.com/laravel/framework/pull/23160)) -- Catch `InvalidFileException` when loading invalid environment file ([#23149](https://github.com/laravel/framework/pull/23149), [5695079](https://github.com/laravel/framework/commit/569507941594075c36893445dd22374efbe48305)) -- Fixed an issue with `assertRedirect()` ([#23176](https://github.com/laravel/framework/pull/23176)) -- Fixed dropdown accessibility ([#23191](https://github.com/laravel/framework/pull/23191)) -- Fixed `--force` flag on `GeneratorCommand` ([#23230](https://github.com/laravel/framework/pull/23230)) - -### Removed -- Removed Bootstrap 3 leftovers ([#23129](https://github.com/laravel/framework/pull/23129), [#23173](https://github.com/laravel/framework/pull/23173)) - - -## v5.6.3 (2018-02-09) - -### Fixed -- Fixed an issue in `TestResponse::assertSessionHasErrors()` ([#23093](https://github.com/laravel/framework/pull/23093)) -- Update Vue and React presets to Bootstrap v4 ([8a9c5c4](https://github.com/laravel/framework/commit/8a9c5c45388fda18aaa5564be131a3144c38b9ce)) - - -## v5.6.2 (2018-02-08) - -### Changed -- Support customization of schedule mutex cache store ([20e2919](https://github.com/laravel/framework/commit/20e29199365a11b31e35179bbfe3e83485e05a03)) - -### Fixed -- Reverted changes to `TestResponse::assertSessionHasErrors()` [#23055](https://github.com/laravel/framework/pull/23055) ([0362a90](https://github.com/laravel/framework/commit/0362a90fca47de6c283d8ef8c68affefc7b410cf)) - - -## v5.6.1 (2018-02-08) - -### Added -- Added Slack attachment pretext attribute ([#23075](https://github.com/laravel/framework/pull/23075)) - -### Changed -- Added missing nested joins in `Grammar::compileJoins()` ([#23059](https://github.com/laravel/framework/pull/23059)) -- Improved session errors assertions in `TestResponse::assertSessionHasErrors()` ([#23055](https://github.com/laravel/framework/pull/23055)) - -### Fixed -- Fixed `BelongsToMany` pivot relation wakeup ([#23081](https://github.com/laravel/framework/pull/23081)) - -### Removed -- Removed monolog configurator ([#23078](https://github.com/laravel/framework/pull/23078)) - - -## v5.6.0 (2018-02-07) - -### General -- ⚠️ Upgraded to Symfony 4 ([#22450](https://github.com/laravel/framework/pull/22450)) -- ⚠️ Upgraded to Bootstrap 4 ([#22754](https://github.com/laravel/framework/pull/22754), [#22494](https://github.com/laravel/framework/pull/22494), [25559cd](https://github.com/laravel/framework/commit/25559cdc14066566658d6c9a7efd8a0e1d0ffccd), [12d789d](https://github.com/laravel/framework/commit/12d789de8472dbbd763cb680e896b3d419f954c0)) -- ⚠️ Added `runningUnitTests()` to `Application` contract ([#21034](https://github.com/laravel/framework/pull/21034)) -- ⚠️ Upgraded `cron-expression` to `2.x` ([#21637](https://github.com/laravel/framework/pull/21637)) - -### Artisan Console -- ⚠️ Removed deprecated `optimize` command ([#20851](https://github.com/laravel/framework/pull/20851)) -- Show job id in `queue:work` output ([#21204](https://github.com/laravel/framework/pull/21204)) -- Show batch number in `migrate:status` output ([#21391](https://github.com/laravel/framework/pull/21391)) -- ⚠️ Added `$outputBuffer` argument to `call()` method in contracts ([#22463](https://github.com/laravel/framework/pull/22463)) -- Added `--realpath` argument to migration commands ([#22852](https://github.com/laravel/framework/pull/22852), [98842da](https://github.com/laravel/framework/commit/98842da800f08c45577dbad13d0c8456370ecd8e)) -- Added `--api` argument to `make:controller` ([#22996](https://github.com/laravel/framework/pull/22996), [dcc6123](https://github.com/laravel/framework/commit/dcc6123453e792084d3eda186898ea7a1f536faa)) - -### Authentication -- Support customizing the mail message building in `ResetPassword::toMail()` ([6535186](https://github.com/laravel/framework/commit/6535186b0f71a6b0cc2d8a821f3de209c05bcf4f)) -- Added `AuthServiceProvider::policies()` method ([6d8e530](https://github.com/laravel/framework/commit/6d8e53082c188c89f765bf016d1e4bca7802b025)) - -### Blade Templates -- Added `@csrf` and `@method` directives ([5f19844](https://github.com/laravel/framework/commit/5f1984421af096ef21b7d2011949a233849d4ee3), [#22912](https://github.com/laravel/framework/pull/22912)) -- Added `Blade::component()` method for component aliases ([#22796](https://github.com/laravel/framework/pull/22796), [7c3ba0e](https://github.com/laravel/framework/commit/7c3ba0e61eae47d785d34448ca8d1e067dee6af7)) -- ⚠️ Made double encoding the default ([7c82ff4](https://github.com/laravel/framework/commit/7c82ff408432c56a324524712723a93df637936e)) - -### Broadcasting -- ⚠️ Added support for channel classes ([#22583](https://github.com/laravel/framework/pull/22583), [434b348](https://github.com/laravel/framework/commit/434b348c5dda1b04486ca6134671d83046bd5c96), [043bd5e](https://github.com/laravel/framework/commit/043bd5e446cf737299476ea3a6498483282a9e41)) - -### Cache -- Removed `$decayMinutes` argument from `RateLimiter::tooManyAttempts()` ([#22202](https://github.com/laravel/framework/pull/22202)) - -### Collections -- ⚠️ Fixed keyless calls to `uniqueStrict()` ([#21854](https://github.com/laravel/framework/pull/21854)) -- Added operator support to `Collection@partition()` ([#22380](https://github.com/laravel/framework/pull/22380)) -- Improve performance of `Collection::mapToDictionary()` ([#22774](https://github.com/laravel/framework/pull/22774), [c09a0fd](https://github.com/laravel/framework/commit/c09a0fdb92a4aa42552723b2238713bc9a9b1adb)) -- Accept array of keys on `Collection::except()` ([#22814](https://github.com/laravel/framework/pull/22814)) - -### Database -- ⚠️ Swap the index order of morph type and id ([#21693](https://github.com/laravel/framework/pull/21693)) -- Added support for PostgreSQL comments ([#21855](https://github.com/laravel/framework/pull/21855), [#22453](https://github.com/laravel/framework/pull/22453)) -- Better enumeration columns support ([#22109](https://github.com/laravel/framework/pull/22109), [9a3d71d](https://github.com/laravel/framework/commit/9a3d71da2278b5582d3a40857a97a905f26b901d)) -- Prevent duplicated table prefix in `SQLiteGrammar::compileColumnListing()` ([#22340](https://github.com/laravel/framework/pull/22340), [#22781](https://github.com/laravel/framework/pull/22781)) -- Support complex `update()` calls when using SQLite ([#22366](https://github.com/laravel/framework/pull/22366)) -- Throws an exception if multiple calls to the underlying SQLite method aren't supported ([#22364](https://github.com/laravel/framework/pull/22364), [c877cb0](https://github.com/laravel/framework/commit/c877cb0cdc44243c691eb8507616a4c21a28599f)) -- Made `whereTime()` operator argument optional ([#22378](https://github.com/laravel/framework/pull/22378)) -- Changed transaction logic in `DatabaseQueue` ([#22433](https://github.com/laravel/framework/pull/22433)) -- Added support for row values in where conditions ([#22446](https://github.com/laravel/framework/pull/22446)) -- Fixed serialization of pivot models ([#22786](https://github.com/laravel/framework/pull/22786), [8fad785](https://github.com/laravel/framework/commit/8fad785de66ffaa18e7d8b9e9cd7c4465e60daac), [351e3b7](https://github.com/laravel/framework/commit/351e3b7694a804e8d6a613288419ccabd22bc012)) -- ⚠️ Accept `Throwable` in `DetectsLostConnections` ([#22948](https://github.com/laravel/framework/pull/22948)) - -### Eloquent -- ⚠️ Serialize relationships ([#21229](https://github.com/laravel/framework/pull/21229)) -- Allow setting custom owner key on polymorphic relationships ([#21310](https://github.com/laravel/framework/pull/21310)) -- ⚠️ Sync model after `refresh()` ([#21905](https://github.com/laravel/framework/pull/21905)) -- Make `MassAssignmentException` wording clear ([#22565](https://github.com/laravel/framework/pull/22565)) -- Changed `HasAttributes::getDateFormat()` visibility to `public` ([#22618](https://github.com/laravel/framework/pull/22618)) -- Added `BelongsToMany::getPivotClass()` method ([641d087](https://github.com/laravel/framework/commit/641d0875a25ff153c4b2b7292b1d6c4ea717cb66)) -- Ensure Pivot model's `$dateFormat` is used when creating a pivot record ([a433ff8](https://github.com/laravel/framework/commit/a433ff8a9bcd88ddfe2335801a15c71b4d1a0a3a)) -- Added `BelongsToMany::withPivotValues()` method ([#22867](https://github.com/laravel/framework/pull/22867)) -- Added `forceDeleted` event ([497a907](https://github.com/laravel/framework/commit/497a90749312b0b75fc185246c94e6150a502773)) -- ⚠️ Relocate the existence check for factory definitions to `FactoryBuilder::getRawAttributes()` ([#22936](https://github.com/laravel/framework/pull/22936)) -- ⚠️ Change `Resource` name away from soft-reserved name ([#22969](https://github.com/laravel/framework/pull/22969), [aad6089](https://github.com/laravel/framework/commit/aad6089702a2bbe89b6971b3feb3e202fea9f4d9)) -- Added support for casting to custom date formats ([#22989](https://github.com/laravel/framework/pull/22989), [1f902c8](https://github.com/laravel/framework/commit/1f902c84b25f8799cc4f781ad549158db4167110)) - -### Hashing -- ⚠️ Added support for Argon ([#21885](https://github.com/laravel/framework/pull/21885), [68ac51a](https://github.com/laravel/framework/commit/68ac51a3c85d039799d32f53a045328e14debfea), [#22087](https://github.com/laravel/framework/pull/22087), [9b46485](https://github.com/laravel/framework/commit/9b4648523debeb6c8ef70811d778b9be64312bd3)) - -### Helpers -- ⚠️ Return an empty array from `Arr::wrap()` when called with `null` ([#21745](https://github.com/laravel/framework/pull/21745)) -- Return class traits in use order from `class_uses_recursive()` ([#22537](https://github.com/laravel/framework/pull/22537)) -- Added `Str::uuid()` and `Str::orderedUuid()` ([3d39604](https://github.com/laravel/framework/commit/3d39604bba72d45dab5b53951af42bbb21110cad)) - -### Logging -- ⚠️ Refactored Logging component ([#22635](https://github.com/laravel/framework/pull/22635), [106ac2a](https://github.com/laravel/framework/commit/106ac2a7a1b337afd9edd11367039e3511c85f81), [7ba0c22](https://github.com/laravel/framework/commit/7ba0c22133da7ca99d1ec1459630de01f95130c1), [03f870c](https://github.com/laravel/framework/commit/03f870cb0b0eefde363b8985843aba68446a407c), [e691230](https://github.com/laravel/framework/commit/e691230578b010fe753f1973d5ab218a6510c0e9)) -- Use application name as syslog identifier ([#22267](https://github.com/laravel/framework/pull/22267)) - -### Mail -- ⚠️ Added `$data` property to mail events ([#21804](https://github.com/laravel/framework/pull/21804)) -- ⚠️ Call message сustomization callbacks before building content/attachments ([#22995](https://github.com/laravel/framework/pull/22995)) -- Added support for setting HTML in emails ([#22809](https://github.com/laravel/framework/pull/22809)) - -### Notifications -- Pass notification instance to `routeNotificationFor*()` methods ([#22289](https://github.com/laravel/framework/pull/22289)) - -### Queues -- ⚠️ Added `payload()` and `getJobId()` to `Job` contract ([#21303](https://github.com/laravel/framework/pull/21303)) -- Removed unused `Worker::raiseFailedJobEvent()` method ([#21901](https://github.com/laravel/framework/pull/21901)) -- Support blocking pop from Redis queues ([#22284](https://github.com/laravel/framework/pull/22284), [dbad055](https://github.com/laravel/framework/commit/dbad05599b2d2059e45c480fac8817d1135d5da1), [5923416](https://github.com/laravel/framework/commit/59234169c3b3b7a7164fda206778224311e06fe2)) - -### Requests -- ⚠️ Return `false` from `expectsJson()` when requested content type isn't explicit ([#22506](https://github.com/laravel/framework/pull/22506), [3624d27](https://github.com/laravel/framework/commit/3624d2702c783d13bd23b852ce35662bee9a8fea)) -- Added `Request::getSession()` method ([e546a5b](https://github.com/laravel/framework/commit/e546a5b83aa9fb5bbcb8e80db0c263c09b5d5dd6)) -- Accept array of keys on `Request::hasAny()` ([#22952](https://github.com/laravel/framework/pull/22952)) - -### Responses -- Added missing `$raw` and `$sameSite` parameters to `Cookie\Factory` methods ([#21553](https://github.com/laravel/framework/pull/21553)) -- ⚠️ Return `201` status if Model was recently created ([#21625](https://github.com/laravel/framework/pull/21625)) -- Set original response JSON responses ([#22455](https://github.com/laravel/framework/pull/22455)) -- Added `streamDownload()` method ([#22777](https://github.com/laravel/framework/pull/22777)) -- ⚠️ Allow insecure cookies when `session.secure` is `true` ([#22812](https://github.com/laravel/framework/pull/22812)) - -### Routing -- Added `SetCacheHeaders` middleware ([#22389](https://github.com/laravel/framework/pull/22389), [f6f386b](https://github.com/laravel/framework/commit/f6f386ba6456894215b1314c0e33f956026dffec), [df06357](https://github.com/laravel/framework/commit/df06357d78629a479d341329571136d21ae02f6f)) -- Support pulling rate limit from the user instance in `ThrottleRequests` ([c9e6100](https://github.com/laravel/framework/commit/c9e61007d38f0cd5434551ebd7bf9c2a139f4e61)) - -### Service Container -- Support bulk binding in service providers during registration ([#21961](https://github.com/laravel/framework/pull/21961), [81e29b1](https://github.com/laravel/framework/commit/81e29b1f09af7095df219efd18185f0818f5b698)) - -### Session -- Support dot notation in `Session::exists()` ([#22935](https://github.com/laravel/framework/pull/22935)) - -### Support -- ⚠️ Throw exception if `Manager::driver()` is called with `null` ([#22018](https://github.com/laravel/framework/pull/22018)) -- ⚠️ Added `hasCommandHandler()`, `getCommandHandler()` and `map()` to `Bus\Dispatcher` contract ([#22958](https://github.com/laravel/framework/pull/22958), [#22986](https://github.com/laravel/framework/pull/22986)) -- Added `useBootstrapThree()` helper to paginators ([c919402](https://github.com/laravel/framework/commit/c919402d5847830c1b2a39529cac90251f838709)) - -### Task Scheduling -- ⚠️ Multi server scheduling cron support ([#22216](https://github.com/laravel/framework/pull/22216), [6563ba6](https://github.com/laravel/framework/commit/6563ba65b65106198095f1d61f91e0ec542e98dd)) - -### Testing -- ⚠️ Switched to PHPUnit 7 ([#23005](https://github.com/laravel/framework/pull/23005)) -- Support fetching specific key when using json helpers ([#22489](https://github.com/laravel/framework/pull/22489)) -- Use `DatabaseTransactions` trait in `RefreshDatabase` ([#22596](https://github.com/laravel/framework/pull/22596)) -- Added `assertSeeInOrder()` and `assertSeeTextInOrder()` methods ([#22915](https://github.com/laravel/framework/pull/22915), [#23038](https://github.com/laravel/framework/pull/23038)) - -### Validation -- ⚠️ Ignore SVGs in `validateDimensions()` ([#21390](https://github.com/laravel/framework/pull/21390)) -- ⚠️ Renamed `validate()` to `validateResolved()` ([33d8642](https://github.com/laravel/framework/commit/33d864240a770f821df419e2d16d841d94968415)) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md new file mode 100644 index 000000000000..3bb93caf7f55 --- /dev/null +++ b/CHANGELOG-5.7.md @@ -0,0 +1,5 @@ +# Release Notes for 5.7.x + +## v5.7.0 (2018-09-04) + +Check the upgrade guide in the [Official Laravel Documentation](https://laravel.com/docs/5.7/upgrade). From 68b84b70b97a0a0072dfd1e47de7ba933eb2d72a Mon Sep 17 00:00:00 2001 From: Rob Taylor Date: Tue, 4 Sep 2018 17:59:37 +0100 Subject: [PATCH 0276/2459] Added default array value for redis config (#25443) --- src/Illuminate/Redis/RedisServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Redis/RedisServiceProvider.php b/src/Illuminate/Redis/RedisServiceProvider.php index eb2cd6a97474..2d419388001f 100755 --- a/src/Illuminate/Redis/RedisServiceProvider.php +++ b/src/Illuminate/Redis/RedisServiceProvider.php @@ -22,7 +22,7 @@ class RedisServiceProvider extends ServiceProvider public function register() { $this->app->singleton('redis', function ($app) { - $config = $app->make('config')->get('database.redis'); + $config = $app->make('config')->get('database.redis', []); return new RedisManager($app, Arr::pull($config, 'client', 'predis'), $config); }); From d536b16f478cd6a05b8b6b146efdd76726fa9cfc Mon Sep 17 00:00:00 2001 From: Johnny Walker Date: Tue, 4 Sep 2018 19:07:16 +0100 Subject: [PATCH 0277/2459] Remove X-UA-Compatible meta tag (#25442) * Remove X-UA-Compatible meta tag No reason to include this anymore. Microsoft do not support IE8, 9 and 10, and this tag is only for them. It also goes against best practices: https://stackoverflow.com/a/26348511/199700 * Remove X-UA-Compatible meta tag No reason to include this anymore. Microsoft do not support IE8, 9 and 10, and this tag is only for them. It also goes against best practices: https://stackoverflow.com/a/26348511/199700 --- src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub | 1 - src/Illuminate/Foundation/Exceptions/views/layout.blade.php | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub b/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub index 6dba26cdedfd..943ad0bad462 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub @@ -2,7 +2,6 @@ - diff --git a/src/Illuminate/Foundation/Exceptions/views/layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/layout.blade.php index 50616e93a5d0..90d4ad247934 100644 --- a/src/Illuminate/Foundation/Exceptions/views/layout.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/layout.blade.php @@ -2,7 +2,6 @@ - @yield('title') From 4a5955e325faa2054420eeb7320cc2c81111a2f2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 4 Sep 2018 13:28:50 -0500 Subject: [PATCH 0278/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 6cfe9221a490..191ce34459cb 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.7.0'; + const VERSION = '5.7.1'; /** * The base path for the Laravel installation. From 0fea370ef24c1b72d2c3519a1348a6b979abd78e Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 4 Sep 2018 20:35:59 +0200 Subject: [PATCH 0279/2459] fix basic auth --- src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php b/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php index 4c9e68786584..c51df9064e4f 100644 --- a/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php +++ b/src/Illuminate/Auth/Middleware/AuthenticateWithBasicAuth.php @@ -36,6 +36,6 @@ public function __construct(AuthFactory $auth) */ public function handle($request, Closure $next, $guard = null, $field = null) { - return $this->auth->guard($guard)->basic($field) ?: $next($request); + return $this->auth->guard($guard)->basic($field ?: 'email') ?: $next($request); } } From 524e5ebcad4f6f20b70b29f075aee82e001fa798 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 4 Sep 2018 20:46:03 +0200 Subject: [PATCH 0280/2459] update changelog --- CHANGELOG-5.7.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index 3bb93caf7f55..d77a556ed998 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -1,5 +1,16 @@ # Release Notes for 5.7.x +## v5.7.1 (2018-09-04) + +### Fixed + +- Fixed an issue with basic auth when no field is defined + +### Changed + +- Remove X-UA-Compatible meta tag ([#25442](https://github.com/laravel/framework/pull/25442)) +- Added default array value for redis config ([#25443](https://github.com/laravel/framework/pull/25443)) + ## v5.7.0 (2018-09-04) Check the upgrade guide in the [Official Laravel Documentation](https://laravel.com/docs/5.7/upgrade). From 0e23b6afa4d1d8b440ce7696a23fa770b4f7e5e3 Mon Sep 17 00:00:00 2001 From: Thom Hurks Date: Wed, 5 Sep 2018 00:45:50 +0200 Subject: [PATCH 0281/2459] Allow email verification middleware to work with API routes Currently if you apply the email verification middleware to an API route (XHR) you get strange/broken behaviour because of the redirect. So, when the request expects JSON, just return a 403. This solves my issues. --- src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php index f9ee4babce57..54b8c7ff3807 100644 --- a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php +++ b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php @@ -13,14 +13,18 @@ class EnsureEmailIsVerified * * @param \Illuminate\Http\Request $request * @param \Closure $next - * @return \Illuminate\Http\Response + * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse */ public function handle($request, Closure $next) { if (! $request->user() || ($request->user() instanceof MustVerifyEmail && ! $request->user()->hasVerifiedEmail())) { - return Redirect::route('verification.notice'); + if ($request->expectsJson()) { + abort(403, 'Your email address is not verified.'); + } else { + return Redirect::route('verification.notice'); + } } return $next($request); From 045cbfd95c611928aef1b877d1a3dc60d5f19580 Mon Sep 17 00:00:00 2001 From: Thom Hurks Date: Wed, 5 Sep 2018 01:16:37 +0200 Subject: [PATCH 0282/2459] Send an event when the user's email is verified Upon user email verification we may like to take certain immediate actions. For example, once we have verified that the user has a valid email from a certain company domain, we may assign a role automatically. --- src/Illuminate/Auth/Events/Verified.php | 28 +++++++++++++++++++ src/Illuminate/Auth/MustVerifyEmail.php | 4 +-- .../Foundation/Auth/VerifiesEmails.php | 5 +++- 3 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 src/Illuminate/Auth/Events/Verified.php diff --git a/src/Illuminate/Auth/Events/Verified.php b/src/Illuminate/Auth/Events/Verified.php new file mode 100644 index 000000000000..1d6e4c0f3448 --- /dev/null +++ b/src/Illuminate/Auth/Events/Verified.php @@ -0,0 +1,28 @@ +user = $user; + } +} diff --git a/src/Illuminate/Auth/MustVerifyEmail.php b/src/Illuminate/Auth/MustVerifyEmail.php index d20418880863..4d3bbe29f2b2 100644 --- a/src/Illuminate/Auth/MustVerifyEmail.php +++ b/src/Illuminate/Auth/MustVerifyEmail.php @@ -17,11 +17,11 @@ public function hasVerifiedEmail() /** * Mark the given user's email as verified. * - * @return void + * @return bool */ public function markEmailAsVerified() { - $this->forceFill(['email_verified_at' => $this->freshTimestamp()])->save(); + return $this->forceFill(['email_verified_at' => $this->freshTimestamp()])->save(); } /** diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index c35f8272dfe9..7622a9446142 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation\Auth; +use Illuminate\Auth\Events\Verified; use Illuminate\Http\Request; trait VerifiesEmails @@ -30,7 +31,9 @@ public function show(Request $request) public function verify(Request $request) { if ($request->route('id') == $request->user()->getKey()) { - $request->user()->markEmailAsVerified(); + if ($request->user()->markEmailAsVerified()) { + event(new Verified($request->user())); + } } return redirect($this->redirectPath()); From 7b0fb2cf1b010ad81f66faf2a1713ad273925f8d Mon Sep 17 00:00:00 2001 From: Thom Hurks Date: Wed, 5 Sep 2018 01:23:18 +0200 Subject: [PATCH 0283/2459] Apply StyleCI fix --- src/Illuminate/Foundation/Auth/VerifiesEmails.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index 7622a9446142..87392f27eea2 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -2,8 +2,8 @@ namespace Illuminate\Foundation\Auth; -use Illuminate\Auth\Events\Verified; use Illuminate\Http\Request; +use Illuminate\Auth\Events\Verified; trait VerifiesEmails { From 2a58b15eae3b30a96b95a11ed0e61bd77e2ff263 Mon Sep 17 00:00:00 2001 From: Thom Hurks Date: Wed, 5 Sep 2018 04:08:13 +0200 Subject: [PATCH 0284/2459] Resolved laurencei's feedback Resolved laurencei's feedback, the else is not needed. --- src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php index 54b8c7ff3807..d30fffd46c9d 100644 --- a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php +++ b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php @@ -22,9 +22,8 @@ public function handle($request, Closure $next) ! $request->user()->hasVerifiedEmail())) { if ($request->expectsJson()) { abort(403, 'Your email address is not verified.'); - } else { - return Redirect::route('verification.notice'); } + return Redirect::route('verification.notice'); } return $next($request); From ee954c868502fc3630ec71d7f41e9060d6bfd430 Mon Sep 17 00:00:00 2001 From: Thom Hurks Date: Wed, 5 Sep 2018 04:10:27 +0200 Subject: [PATCH 0285/2459] Applied StyleCI fix --- src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php index d30fffd46c9d..14d502cb6f09 100644 --- a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php +++ b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php @@ -23,6 +23,7 @@ public function handle($request, Closure $next) if ($request->expectsJson()) { abort(403, 'Your email address is not verified.'); } + return Redirect::route('verification.notice'); } From b4339702dbdc5f1f55f30f1e6576450f6277e3ae Mon Sep 17 00:00:00 2001 From: Sjors Date: Wed, 5 Sep 2018 10:35:47 +0200 Subject: [PATCH 0286/2459] dont mock console output by default --- .../Testing/Concerns/InteractsWithConsole.php | 14 ++++++++++++++ .../Console/ConsoleApplicationTest.php | 18 ++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index 32488e1facc8..2ea3c7d4da5c 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -2,10 +2,13 @@ namespace Illuminate\Foundation\Testing\Concerns; +use Illuminate\Contracts\Console\Kernel; use Illuminate\Foundation\Testing\PendingCommand; trait InteractsWithConsole { + protected $mockConsoleOutput = false; + /** * All of the expected output lines. * @@ -29,6 +32,10 @@ trait InteractsWithConsole */ public function artisan($command, $parameters = []) { + if (! $this->mockConsoleOutput) { + return $this->app[Kernel::class]->call($command, $parameters); + } + $this->beforeApplicationDestroyed(function () { if (count($this->expectedQuestions)) { $this->fail('Question "'.array_first($this->expectedQuestions)[0].'" was not asked.'); @@ -41,4 +48,11 @@ public function artisan($command, $parameters = []) return new PendingCommand($this, $this->app, $command, $parameters); } + + protected function withMockedConsoleOutput() + { + $this->mockConsoleOutput = true; + + return $this; + } } diff --git a/tests/Integration/Console/ConsoleApplicationTest.php b/tests/Integration/Console/ConsoleApplicationTest.php index 47cbce569ec6..06ec01a1dd71 100644 --- a/tests/Integration/Console/ConsoleApplicationTest.php +++ b/tests/Integration/Console/ConsoleApplicationTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Integration\Console; use Illuminate\Console\Command; +use Illuminate\Foundation\Testing\PendingCommand; use Orchestra\Testbench\TestCase; use Illuminate\Contracts\Console\Kernel; @@ -19,14 +20,27 @@ public function test_artisan_call_using_command_name() { $exitCode = $this->artisan('foo:bar', [ 'id' => 1, - ])->assertExitCode(0); + ]); + + $this->assertSame(0, $exitCode); } public function test_artisan_call_using_command_class() { $exitCode = $this->artisan(FooCommandStub::class, [ 'id' => 1, - ])->assertExitCode(0); + ]); + + $this->assertSame(0, $exitCode); + } + + public function test_artisan_call_using_command_class_with_mocked_output() + { + $pendingCommand = $this->withMockedConsoleOutput()->artisan(FooCommandStub::class, ['id' => 1]); + + $this->assertInstanceOf(PendingCommand::class, $pendingCommand); + + $pendingCommand->assertExitCode(0); } } From ac46ee63bd8c485b3fb23607d8be0a8ae45f1db3 Mon Sep 17 00:00:00 2001 From: Sjors Date: Wed, 5 Sep 2018 10:50:16 +0200 Subject: [PATCH 0287/2459] code style --- tests/Integration/Console/ConsoleApplicationTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/Console/ConsoleApplicationTest.php b/tests/Integration/Console/ConsoleApplicationTest.php index 06ec01a1dd71..9cf0b4199e5c 100644 --- a/tests/Integration/Console/ConsoleApplicationTest.php +++ b/tests/Integration/Console/ConsoleApplicationTest.php @@ -3,9 +3,9 @@ namespace Illuminate\Tests\Integration\Console; use Illuminate\Console\Command; -use Illuminate\Foundation\Testing\PendingCommand; use Orchestra\Testbench\TestCase; use Illuminate\Contracts\Console\Kernel; +use Illuminate\Foundation\Testing\PendingCommand; class ConsoleApplicationTest extends TestCase { From 9809938fe97458e8ce3eef5ae4cd811ee4a00b39 Mon Sep 17 00:00:00 2001 From: Alex Vanderbist Date: Wed, 5 Sep 2018 15:20:13 +0200 Subject: [PATCH 0288/2459] Update documentation blocks for action tuple notation (#25460) --- src/Illuminate/Contracts/Routing/UrlGenerator.php | 2 +- src/Illuminate/Foundation/helpers.php | 2 +- src/Illuminate/Routing/Redirector.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Contracts/Routing/UrlGenerator.php b/src/Illuminate/Contracts/Routing/UrlGenerator.php index d77b3af9b420..53044ccc6be9 100644 --- a/src/Illuminate/Contracts/Routing/UrlGenerator.php +++ b/src/Illuminate/Contracts/Routing/UrlGenerator.php @@ -54,7 +54,7 @@ public function route($name, $parameters = [], $absolute = true); /** * Get the URL to a controller action. * - * @param string $action + * @param string|array $action * @param mixed $parameters * @param bool $absolute * @return string diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index a462a0ea1e98..28d276dae2b9 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -91,7 +91,7 @@ function abort_unless($boolean, $code, $message = '', array $headers = []) /** * Generate the URL to a controller action. * - * @param string $name + * @param string|array $name * @param mixed $parameters * @param bool $absolute * @return string diff --git a/src/Illuminate/Routing/Redirector.php b/src/Illuminate/Routing/Redirector.php index 1c39a59325cd..56119597b581 100755 --- a/src/Illuminate/Routing/Redirector.php +++ b/src/Illuminate/Routing/Redirector.php @@ -160,7 +160,7 @@ public function route($route, $parameters = [], $status = 302, $headers = []) /** * Create a new redirect response to a controller action. * - * @param string $action + * @param string|array $action * @param mixed $parameters * @param int $status * @param array $headers From c767e2606d4ce6e825f274d25117f15a3906156b Mon Sep 17 00:00:00 2001 From: Sije Harkema Date: Wed, 5 Sep 2018 15:20:39 +0200 Subject: [PATCH 0289/2459] Add moontoast/math to 'suggest' of composer.json (#25459) Fixes #25428 . (This was done with the GH online editor, so forgive possible typo's or related problems) --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 92a10e5a9774..4dadeca15beb 100644 --- a/composer.json +++ b/composer.json @@ -121,6 +121,7 @@ "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (^1.0).", "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", + "moontoast/math": "Required to use ordered UUIDs (^1.1).", "nexmo/client": "Required to use the Nexmo transport (^1.0).", "pda/pheanstalk": "Required to use the beanstalk queue driver (^3.0).", "predis/predis": "Required to use the redis cache and queue drivers (^1.0).", From 8021279218c0044f6459320b91ed6e0dc4d3ab05 Mon Sep 17 00:00:00 2001 From: Rostyslav Khaniukov Date: Wed, 5 Sep 2018 16:21:12 +0300 Subject: [PATCH 0290/2459] Pass configuration key parameter to updatePackageArray in Preset (#25457) --- src/Illuminate/Foundation/Console/Presets/Preset.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/Presets/Preset.php b/src/Illuminate/Foundation/Console/Presets/Preset.php index 99af6b6f4571..efa081757285 100644 --- a/src/Illuminate/Foundation/Console/Presets/Preset.php +++ b/src/Illuminate/Foundation/Console/Presets/Preset.php @@ -37,7 +37,8 @@ protected static function updatePackages($dev = true) $packages = json_decode(file_get_contents(base_path('package.json')), true); $packages[$configurationKey] = static::updatePackageArray( - array_key_exists($configurationKey, $packages) ? $packages[$configurationKey] : [] + array_key_exists($configurationKey, $packages) ? $packages[$configurationKey] : [], + $configurationKey ); ksort($packages[$configurationKey]); From 71cf99b88906a4a0480162bfe592993c30b7ccc5 Mon Sep 17 00:00:00 2001 From: Francis Morissette Date: Wed, 5 Sep 2018 09:25:41 -0400 Subject: [PATCH 0291/2459] [5.7] Do not send email verification if user is already verified (#25450) Hey guys, So I'm using Socialite to register users. I'm dispatching the Registered event and since my model now extends MustVerifyEmail, it sends out an email to users which are already verified (force filled by my FB/Google integration). This makes sure that a "verified" user does not receive the email, so if in your registration process you mark them as verified, they will not receive the email. --- .../Auth/Listeners/SendEmailVerificationNotification.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php b/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php index c7b19c851547..12dfa6979396 100644 --- a/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php +++ b/src/Illuminate/Auth/Listeners/SendEmailVerificationNotification.php @@ -15,7 +15,7 @@ class SendEmailVerificationNotification */ public function handle(Registered $event) { - if ($event->user instanceof MustVerifyEmail) { + if ($event->user instanceof MustVerifyEmail && ! $event->user->hasVerifiedEmail()) { $event->user->sendEmailVerificationNotification(); } } From ac5f37a7ca2ba5414b591de9985c44507f751c27 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 5 Sep 2018 08:29:55 -0500 Subject: [PATCH 0292/2459] formatting --- src/Illuminate/Auth/MustVerifyEmail.php | 4 +++- src/Illuminate/Foundation/Auth/VerifiesEmails.php | 7 +++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Auth/MustVerifyEmail.php b/src/Illuminate/Auth/MustVerifyEmail.php index 4d3bbe29f2b2..dc58e5b66a17 100644 --- a/src/Illuminate/Auth/MustVerifyEmail.php +++ b/src/Illuminate/Auth/MustVerifyEmail.php @@ -21,7 +21,9 @@ public function hasVerifiedEmail() */ public function markEmailAsVerified() { - return $this->forceFill(['email_verified_at' => $this->freshTimestamp()])->save(); + return $this->forceFill([ + 'email_verified_at' => $this->freshTimestamp() + ])->save(); } /** diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index 87392f27eea2..ca539d359dcb 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -30,10 +30,9 @@ public function show(Request $request) */ public function verify(Request $request) { - if ($request->route('id') == $request->user()->getKey()) { - if ($request->user()->markEmailAsVerified()) { - event(new Verified($request->user())); - } + if ($request->route('id') == $request->user()->getKey() && + $request->user()->markEmailAsVerified()) { + event(new Verified($request->user())); } return redirect($this->redirectPath()); From 4e84bdcdffcdb05f5b008456a8c77d5d64233c60 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 5 Sep 2018 08:30:30 -0500 Subject: [PATCH 0293/2459] Apply fixes from StyleCI (#25462) --- src/Illuminate/Auth/MustVerifyEmail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/MustVerifyEmail.php b/src/Illuminate/Auth/MustVerifyEmail.php index dc58e5b66a17..d7782cd694d7 100644 --- a/src/Illuminate/Auth/MustVerifyEmail.php +++ b/src/Illuminate/Auth/MustVerifyEmail.php @@ -22,7 +22,7 @@ public function hasVerifiedEmail() public function markEmailAsVerified() { return $this->forceFill([ - 'email_verified_at' => $this->freshTimestamp() + 'email_verified_at' => $this->freshTimestamp(), ])->save(); } From 236f9607844d7ecefcc6657347718bb23bc1c3f6 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 5 Sep 2018 08:31:30 -0500 Subject: [PATCH 0294/2459] formatting --- src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php index 14d502cb6f09..f43855d39f47 100644 --- a/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php +++ b/src/Illuminate/Auth/Middleware/EnsureEmailIsVerified.php @@ -20,11 +20,9 @@ public function handle($request, Closure $next) if (! $request->user() || ($request->user() instanceof MustVerifyEmail && ! $request->user()->hasVerifiedEmail())) { - if ($request->expectsJson()) { - abort(403, 'Your email address is not verified.'); - } - - return Redirect::route('verification.notice'); + return $request->expectsJson() + ? abort(403, 'Your email address is not verified.') + : Redirect::route('verification.notice'); } return $next($request); From 2524c5ee89a0c5e6e4e65c13d5f9945075bb299c Mon Sep 17 00:00:00 2001 From: Deleu Date: Wed, 5 Sep 2018 09:59:39 -0400 Subject: [PATCH 0295/2459] Let the WorkCommand specify whether to stop when queue is empty --- src/Illuminate/Queue/Console/WorkCommand.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Console/WorkCommand.php b/src/Illuminate/Queue/Console/WorkCommand.php index 8d759c7d0983..8d7866e11daa 100644 --- a/src/Illuminate/Queue/Console/WorkCommand.php +++ b/src/Illuminate/Queue/Console/WorkCommand.php @@ -23,6 +23,7 @@ class WorkCommand extends Command {--queue= : The names of the queues to work} {--daemon : Run the worker in daemon mode (Deprecated)} {--once : Only process the next job on the queue} + {--all : Work all jobs and stop when queue is empty} {--delay=0 : The number of seconds to delay failed jobs} {--force : Force the worker to run even in maintenance mode} {--memory=128 : The memory limit in megabytes} @@ -112,7 +113,8 @@ protected function gatherWorkerOptions() return new WorkerOptions( $this->option('delay'), $this->option('memory'), $this->option('timeout'), $this->option('sleep'), - $this->option('tries'), $this->option('force') + $this->option('tries'), $this->option('force'), + $this->option('all') ); } From 61396302621d3391721094c71b5fb75860c97bb4 Mon Sep 17 00:00:00 2001 From: Stidges Date: Wed, 5 Sep 2018 21:02:40 +0200 Subject: [PATCH 0296/2459] Add getStreamedContent to TestResponse class --- .../Foundation/Testing/TestResponse.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/Illuminate/Foundation/Testing/TestResponse.php b/src/Illuminate/Foundation/Testing/TestResponse.php index dbec9ee890ed..2c0d7a08dbd3 100644 --- a/src/Illuminate/Foundation/Testing/TestResponse.php +++ b/src/Illuminate/Foundation/Testing/TestResponse.php @@ -9,6 +9,7 @@ use Illuminate\Contracts\View\View; use Illuminate\Support\Traits\Macroable; use PHPUnit\Framework\Assert as PHPUnit; +use Symfony\Component\HttpFoundation\StreamedResponse; use Illuminate\Foundation\Testing\Constraints\SeeInOrder; /** @@ -27,6 +28,13 @@ class TestResponse */ public $baseResponse; + /** + * The streamed content of the response. + * + * @var string + */ + protected $streamedContent; + /** * Create a new test response instance. * @@ -949,6 +957,28 @@ public function dump() dd($content); } + /** + * Get the streamed content from the response. + * + * @return string + */ + public function getStreamedContent() + { + if (! is_null($this->streamedContent)) { + return $this->streamedContent; + } + + if (! $this->baseResponse instanceof StreamedResponse) { + PHPUnit::fail('The response is not a streamed response.'); + } + + ob_start(); + + $this->sendContent(); + + return $this->streamedContent = ob_get_clean(); + } + /** * Dynamically access base response parameters. * From 6b207dfe4ce5e66be9638e02b8d2be9f190e823c Mon Sep 17 00:00:00 2001 From: Aken Roberts Date: Wed, 5 Sep 2018 16:53:46 -0500 Subject: [PATCH 0297/2459] Add Test suffix to misnamed tests (#25471) --- ...seString.php => DatabaseEloquentCastsDatabaseStringTest.php} | 2 +- ...loquentTimestamps.php => DatabaseEloquentTimestampsTest.php} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename tests/Database/{DatabaseEloquentCastsDatabaseString.php => DatabaseEloquentCastsDatabaseStringTest.php} (98%) rename tests/Database/{DatabaseEloquentTimestamps.php => DatabaseEloquentTimestampsTest.php} (98%) diff --git a/tests/Database/DatabaseEloquentCastsDatabaseString.php b/tests/Database/DatabaseEloquentCastsDatabaseStringTest.php similarity index 98% rename from tests/Database/DatabaseEloquentCastsDatabaseString.php rename to tests/Database/DatabaseEloquentCastsDatabaseStringTest.php index a161c5f30113..aa9936c91533 100644 --- a/tests/Database/DatabaseEloquentCastsDatabaseString.php +++ b/tests/Database/DatabaseEloquentCastsDatabaseStringTest.php @@ -6,7 +6,7 @@ use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Eloquent\Model as Eloquent; -class DatabaseEloquentCastsDatabaseString extends TestCase +class DatabaseEloquentCastsDatabaseStringTest extends TestCase { public function setUp() { diff --git a/tests/Database/DatabaseEloquentTimestamps.php b/tests/Database/DatabaseEloquentTimestampsTest.php similarity index 98% rename from tests/Database/DatabaseEloquentTimestamps.php rename to tests/Database/DatabaseEloquentTimestampsTest.php index 9cd86c7ee8d7..acab463b05f8 100644 --- a/tests/Database/DatabaseEloquentTimestamps.php +++ b/tests/Database/DatabaseEloquentTimestampsTest.php @@ -7,7 +7,7 @@ use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Eloquent\Model as Eloquent; -class DatabaseEloquentTimestamps extends TestCase +class DatabaseEloquentTimestampsTest extends TestCase { public function setUp() { From 9c844aa37617d8694ba364e16a5f26ecc470c18e Mon Sep 17 00:00:00 2001 From: Thom Hurks Date: Wed, 5 Sep 2018 23:56:43 +0200 Subject: [PATCH 0298/2459] Adjust PHPDoc in the MustVerifyEmail contract (#25463) --- src/Illuminate/Contracts/Auth/MustVerifyEmail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Contracts/Auth/MustVerifyEmail.php b/src/Illuminate/Contracts/Auth/MustVerifyEmail.php index 355217097375..816980665676 100644 --- a/src/Illuminate/Contracts/Auth/MustVerifyEmail.php +++ b/src/Illuminate/Contracts/Auth/MustVerifyEmail.php @@ -14,7 +14,7 @@ public function hasVerifiedEmail(); /** * Mark the given user's email as verified. * - * @return void + * @return bool */ public function markEmailAsVerified(); From 7aeff1d4393afba36c52e301726d848e2a373b12 Mon Sep 17 00:00:00 2001 From: Donovan Hare Date: Wed, 5 Sep 2018 18:54:47 +0100 Subject: [PATCH 0299/2459] Add the ability to skip algorithm checking --- src/Illuminate/Hashing/Argon2IdHasher.php | 2 +- src/Illuminate/Hashing/ArgonHasher.php | 10 +++++++++- src/Illuminate/Hashing/BcryptHasher.php | 10 +++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Hashing/Argon2IdHasher.php b/src/Illuminate/Hashing/Argon2IdHasher.php index f3da9f74cb0d..64345fb2fbc0 100644 --- a/src/Illuminate/Hashing/Argon2IdHasher.php +++ b/src/Illuminate/Hashing/Argon2IdHasher.php @@ -16,7 +16,7 @@ class Argon2IdHasher extends ArgonHasher */ public function check($value, $hashedValue, array $options = []) { - if ($this->info($hashedValue)['algoName'] !== 'argon2id') { + if ($this->verifyAlgorithm && $this->info($hashedValue)['algoName'] !== 'argon2id') { throw new RuntimeException('This password does not use the Argon2id algorithm.'); } diff --git a/src/Illuminate/Hashing/ArgonHasher.php b/src/Illuminate/Hashing/ArgonHasher.php index bddc97c736d8..d8a10a966185 100644 --- a/src/Illuminate/Hashing/ArgonHasher.php +++ b/src/Illuminate/Hashing/ArgonHasher.php @@ -28,6 +28,13 @@ class ArgonHasher extends AbstractHasher implements HasherContract */ protected $threads = 2; + /** + * Indicates whether to perform an algorithm check. + * + * @var bool + */ + protected $verifyAlgorithm = true; + /** * Create a new hasher instance. * @@ -39,6 +46,7 @@ public function __construct(array $options = []) $this->time = $options['time'] ?? $this->time; $this->memory = $options['memory'] ?? $this->memory; $this->threads = $options['threads'] ?? $this->threads; + $this->verifyAlgorithm = $options['verifyAlgorithm'] ?? $this->verifyAlgorithm; } /** @@ -85,7 +93,7 @@ protected function algorithm() */ public function check($value, $hashedValue, array $options = []) { - if ($this->info($hashedValue)['algoName'] !== 'argon2i') { + if ($this->verifyAlgorithm && $this->info($hashedValue)['algoName'] !== 'argon2i') { throw new RuntimeException('This password does not use the Argon2i algorithm.'); } diff --git a/src/Illuminate/Hashing/BcryptHasher.php b/src/Illuminate/Hashing/BcryptHasher.php index 3a350062b462..ca617964cd6a 100755 --- a/src/Illuminate/Hashing/BcryptHasher.php +++ b/src/Illuminate/Hashing/BcryptHasher.php @@ -14,6 +14,13 @@ class BcryptHasher extends AbstractHasher implements HasherContract */ protected $rounds = 10; + /** + * Indicates whether to perform an algorithm check. + * + * @var bool + */ + protected $verifyAlgorithm = true; + /** * Create a new hasher instance. * @@ -23,6 +30,7 @@ class BcryptHasher extends AbstractHasher implements HasherContract public function __construct(array $options = []) { $this->rounds = $options['rounds'] ?? $this->rounds; + $this->verifyAlgorithm = $options['verify_algorithm'] ?? $this->verifyAlgorithm; } /** @@ -57,7 +65,7 @@ public function make($value, array $options = []) */ public function check($value, $hashedValue, array $options = []) { - if ($this->info($hashedValue)['algoName'] !== 'bcrypt') { + if ($this->verifyAlgorithm && $this->info($hashedValue)['algoName'] !== 'bcrypt') { throw new RuntimeException('This password does not use the Bcrypt algorithm.'); } From 757d3c72359509a667d5477c2a2f57b89bcbf77a Mon Sep 17 00:00:00 2001 From: klack710 Date: Thu, 6 Sep 2018 20:43:38 +0900 Subject: [PATCH 0300/2459] add if branches when cache helper has only one argument --- src/Illuminate/Foundation/helpers.php | 6 +++++- tests/Foundation/FoundationHelpersTest.php | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 28d276dae2b9..d9eb812a5f11 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -239,7 +239,11 @@ function cache() } if (is_string($arguments[0])) { - return app('cache')->get($arguments[0], $arguments[1] ?? null); + if (! array_key_exists(1, $arguments)) { + return app('cache')->get($arguments[0]); + } else { + return app('cache')->get($arguments[0], $arguments[1] ?? null); + } } if (! is_array($arguments[0])) { diff --git a/tests/Foundation/FoundationHelpersTest.php b/tests/Foundation/FoundationHelpersTest.php index aefac13b3a88..d00f16d4d1cd 100644 --- a/tests/Foundation/FoundationHelpersTest.php +++ b/tests/Foundation/FoundationHelpersTest.php @@ -26,10 +26,14 @@ public function testCache() cache(['foo' => 'bar'], 1); // 3. cache('foo'); - $cache->shouldReceive('get')->once()->andReturn('bar'); + $cache->shouldReceive('get')->once()->with('foo')->andReturn('bar'); $this->assertEquals('bar', cache('foo')); - // 4. cache('baz', 'default'); + // 4. cache('foo', null); + $cache->shouldReceive('get')->once()->with('foo', null)->andReturn('bar'); + $this->assertEquals('bar', cache('foo', null)); + + // 5. cache('baz', 'default'); $cache->shouldReceive('get')->once()->with('baz', 'default')->andReturn('default'); $this->assertEquals('default', cache('baz', 'default')); } From 327d5d6410b1c9c392393808428da003710f45f1 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Thu, 6 Sep 2018 15:05:28 +0200 Subject: [PATCH 0301/2459] Add missing docblock. (#25486) --- src/Illuminate/Mail/Transport/MailgunTransport.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Mail/Transport/MailgunTransport.php b/src/Illuminate/Mail/Transport/MailgunTransport.php index 599b4ef6ddea..5dacdca4aac3 100644 --- a/src/Illuminate/Mail/Transport/MailgunTransport.php +++ b/src/Illuminate/Mail/Transport/MailgunTransport.php @@ -41,6 +41,7 @@ class MailgunTransport extends Transport * @param \GuzzleHttp\ClientInterface $client * @param string $key * @param string $domain + * @param string|null $endpoint * @return void */ public function __construct(ClientInterface $client, $key, $domain, $endpoint = null) From 97b6deec70ed6592b529b29f13c1b10a05c2be5c Mon Sep 17 00:00:00 2001 From: Rod Elias Date: Thu, 6 Sep 2018 10:09:41 -0300 Subject: [PATCH 0302/2459] add missing docblock (#25477) --- src/Illuminate/Routing/Console/ControllerMakeCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Routing/Console/ControllerMakeCommand.php b/src/Illuminate/Routing/Console/ControllerMakeCommand.php index 17aab4723f06..85ee7d396a38 100755 --- a/src/Illuminate/Routing/Console/ControllerMakeCommand.php +++ b/src/Illuminate/Routing/Console/ControllerMakeCommand.php @@ -150,6 +150,8 @@ protected function buildModelReplacements(array $replace) * * @param string $model * @return string + * + * @throws \InvalidArgumentException */ protected function parseModel($model) { From b8d3665de081bc374816592d9055a98b617db223 Mon Sep 17 00:00:00 2001 From: Cesar Garcia Date: Thu, 6 Sep 2018 15:14:20 +0200 Subject: [PATCH 0303/2459] Make verify scaffolding translatable (#25473) --- .../Auth/Console/stubs/make/views/auth/verify.stub | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/verify.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/verify.stub index 75ed8115efa0..c742cb4bdcd6 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/verify.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/verify.stub @@ -5,17 +5,17 @@
-
Verify Your Email Address
+
{{ __('Verify Your Email Address') }}
@if (session('resent')) @endif - Before proceeding, please check your email for a verification link. - If you did not receive the email, click here to request another. + {{ __('Before proceeding, please check your email for a verification link.') }} + {{ __('If you did not receive the email') }}, {{ __('click here to request another') }}.
From 055fe52dbb7169dc51bd5d5deeb05e8da9be0470 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 6 Sep 2018 08:33:22 -0500 Subject: [PATCH 0304/2459] formatting --- .../Testing/Concerns/InteractsWithConsole.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index 2ea3c7d4da5c..37700051c656 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -7,7 +7,12 @@ trait InteractsWithConsole { - protected $mockConsoleOutput = false; + /** + * Indicates if the console output should be mocked. + * + * @var bool + */ + public $mockConsoleOutput = true; /** * All of the expected output lines. @@ -28,7 +33,7 @@ trait InteractsWithConsole * * @param string $command * @param array $parameters - * @return \Illuminate\Foundation\Testing\PendingCommand + * @return \Illuminate\Foundation\Testing\PendingCommand|int */ public function artisan($command, $parameters = []) { @@ -49,9 +54,14 @@ public function artisan($command, $parameters = []) return new PendingCommand($this, $this->app, $command, $parameters); } - protected function withMockedConsoleOutput() + /** + * Disable mocking the console output. + * + * @return $this + */ + protected function withoutMockingConsoleOutput() { - $this->mockConsoleOutput = true; + $this->mockConsoleOutput = false; return $this; } From 79edf5c70c9a54c75e17da62ba3649f24b874e09 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 6 Sep 2018 14:35:05 +0100 Subject: [PATCH 0305/2459] Added moontoast/math suggestion --- src/Illuminate/Support/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index e36143dbd94d..6e8a831a2adb 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -38,6 +38,7 @@ }, "suggest": { "illuminate/filesystem": "Required to use the composer class (5.7.*).", + "moontoast/math": "Required to use ordered UUIDs (^1.1).", "ramsey/uuid": "Required to use Str::uuid() (^3.7).", "symfony/process": "Required to use the composer class (^4.1).", "symfony/var-dumper": "Required to use the dd function (^4.1)." From e5a8b2d46f7e7183612215dd1aee92e76162d41f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 6 Sep 2018 08:43:57 -0500 Subject: [PATCH 0306/2459] formatting --- src/Illuminate/Queue/Console/WorkCommand.php | 4 ++-- src/Illuminate/Queue/Worker.php | 2 +- src/Illuminate/Queue/WorkerOptions.php | 8 ++++---- tests/Queue/QueueWorkerTest.php | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Queue/Console/WorkCommand.php b/src/Illuminate/Queue/Console/WorkCommand.php index 8d7866e11daa..67616151b276 100644 --- a/src/Illuminate/Queue/Console/WorkCommand.php +++ b/src/Illuminate/Queue/Console/WorkCommand.php @@ -23,7 +23,7 @@ class WorkCommand extends Command {--queue= : The names of the queues to work} {--daemon : Run the worker in daemon mode (Deprecated)} {--once : Only process the next job on the queue} - {--all : Work all jobs and stop when queue is empty} + {--stop-when-empty : Stop when the queue is empty} {--delay=0 : The number of seconds to delay failed jobs} {--force : Force the worker to run even in maintenance mode} {--memory=128 : The memory limit in megabytes} @@ -114,7 +114,7 @@ protected function gatherWorkerOptions() $this->option('delay'), $this->option('memory'), $this->option('timeout'), $this->option('sleep'), $this->option('tries'), $this->option('force'), - $this->option('all') + $this->option('stop-when-empty') ); } diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 4d3090ddd108..492fae5a2afc 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -204,7 +204,7 @@ protected function stopIfNecessary(WorkerOptions $options, $lastRestart, $job = $this->stop(12); } elseif ($this->queueShouldRestart($lastRestart)) { $this->stop(); - } elseif ($options->stopOnEmptyQueue && is_null($job)) { + } elseif ($options->stopWhenEmpty && is_null($job)) { $this->stop(); } } diff --git a/src/Illuminate/Queue/WorkerOptions.php b/src/Illuminate/Queue/WorkerOptions.php index 9138ee114d99..8e51c4de0eb2 100644 --- a/src/Illuminate/Queue/WorkerOptions.php +++ b/src/Illuminate/Queue/WorkerOptions.php @@ -51,7 +51,7 @@ class WorkerOptions * * @var bool */ - public $stopOnEmptyQueue; + public $stopWhenEmpty; /** * Create a new worker options instance. @@ -62,10 +62,10 @@ class WorkerOptions * @param int $sleep * @param int $maxTries * @param bool $force - * @param bool $stopOnEmptyQueue + * @param bool $stopWhenEmpty * @return void */ - public function __construct($delay = 0, $memory = 128, $timeout = 60, $sleep = 3, $maxTries = 0, $force = false, $stopOnEmptyQueue = false) + public function __construct($delay = 0, $memory = 128, $timeout = 60, $sleep = 3, $maxTries = 0, $force = false, $stopWhenEmpty = false) { $this->delay = $delay; $this->sleep = $sleep; @@ -73,6 +73,6 @@ public function __construct($delay = 0, $memory = 128, $timeout = 60, $sleep = 3 $this->memory = $memory; $this->timeout = $timeout; $this->maxTries = $maxTries; - $this->stopOnEmptyQueue = $stopOnEmptyQueue; + $this->stopWhenEmpty = $stopWhenEmpty; } } diff --git a/tests/Queue/QueueWorkerTest.php b/tests/Queue/QueueWorkerTest.php index a1b850acaec3..882e68c21ce5 100755 --- a/tests/Queue/QueueWorkerTest.php +++ b/tests/Queue/QueueWorkerTest.php @@ -49,7 +49,7 @@ public function test_job_can_be_fired() public function test_worker_can_work_until_queue_is_empty() { $workerOptions = new WorkerOptions; - $workerOptions->stopOnEmptyQueue = true; + $workerOptions->stopWhenEmpty = true; $worker = $this->getWorker('default', ['queue' => [ $firstJob = new WorkerFakeJob, From 20ce1f59dc4e53021de18a928e98f4d9ba73f6fd Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 6 Sep 2018 08:46:24 -0500 Subject: [PATCH 0307/2459] fix test --- .../Console/ConsoleApplicationTest.php | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/tests/Integration/Console/ConsoleApplicationTest.php b/tests/Integration/Console/ConsoleApplicationTest.php index 9cf0b4199e5c..c4ad45a7979f 100644 --- a/tests/Integration/Console/ConsoleApplicationTest.php +++ b/tests/Integration/Console/ConsoleApplicationTest.php @@ -18,29 +18,16 @@ protected function setUp() public function test_artisan_call_using_command_name() { - $exitCode = $this->artisan('foo:bar', [ + $this->artisan('foo:bar', [ 'id' => 1, - ]); - - $this->assertSame(0, $exitCode); + ])->assertExitCode(0); } public function test_artisan_call_using_command_class() { - $exitCode = $this->artisan(FooCommandStub::class, [ + $this->artisan(FooCommandStub::class, [ 'id' => 1, - ]); - - $this->assertSame(0, $exitCode); - } - - public function test_artisan_call_using_command_class_with_mocked_output() - { - $pendingCommand = $this->withMockedConsoleOutput()->artisan(FooCommandStub::class, ['id' => 1]); - - $this->assertInstanceOf(PendingCommand::class, $pendingCommand); - - $pendingCommand->assertExitCode(0); + ])->assertExitCode(0); } } From 22cdcf7cd02a6e35146b4737321a7ce18a075d43 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 6 Sep 2018 08:47:00 -0500 Subject: [PATCH 0308/2459] Apply fixes from StyleCI (#25489) --- tests/Integration/Console/ConsoleApplicationTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Integration/Console/ConsoleApplicationTest.php b/tests/Integration/Console/ConsoleApplicationTest.php index c4ad45a7979f..b5424ed960ab 100644 --- a/tests/Integration/Console/ConsoleApplicationTest.php +++ b/tests/Integration/Console/ConsoleApplicationTest.php @@ -5,7 +5,6 @@ use Illuminate\Console\Command; use Orchestra\Testbench\TestCase; use Illuminate\Contracts\Console\Kernel; -use Illuminate\Foundation\Testing\PendingCommand; class ConsoleApplicationTest extends TestCase { From 509d974a1fa079a0d60aaf0d39fd1f99181bc71f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 6 Sep 2018 08:57:10 -0500 Subject: [PATCH 0309/2459] formatting --- src/Illuminate/Database/Query/Grammars/Grammar.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index ff2e95e9bd31..14d2af25e72c 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -519,6 +519,7 @@ protected function whereJsonContains(Builder $query, $where) * @param string $column * @param string $value * @return string + * * @throws \RuntimeException */ protected function compileJsonContains($column, $value) @@ -558,6 +559,7 @@ protected function whereJsonLength(Builder $query, $where) * @param string $operator * @param string $value * @return string + * * @throws \RuntimeException */ protected function compileJsonLength($column, $operator, $value) From 86e1f98a6d2aab018e0257a7cb2ef2110d64a873 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 6 Sep 2018 09:01:05 -0500 Subject: [PATCH 0310/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 191ce34459cb..13cd8a70a8f1 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.7.1'; + const VERSION = '5.7.2'; /** * The base path for the Laravel installation. From eaac77bfb878b49f2ceff4fb09198e437d38683d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 6 Sep 2018 10:00:49 -0500 Subject: [PATCH 0311/2459] fix bug with invokables --- src/Illuminate/Console/Scheduling/CallbackEvent.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Scheduling/CallbackEvent.php b/src/Illuminate/Console/Scheduling/CallbackEvent.php index 1b54a1aaf7ec..ba6395b5594e 100644 --- a/src/Illuminate/Console/Scheduling/CallbackEvent.php +++ b/src/Illuminate/Console/Scheduling/CallbackEvent.php @@ -71,7 +71,9 @@ public function run(Container $container) parent::callBeforeCallbacks($container); try { - $response = $container->call($this->callback, $this->parameters); + $response = is_object($this->callback) + ? $container->call([$this->callback, '__invoke'], $this->parameters) + : $container->call($this->callback, $this->parameters); } finally { $this->removeMutex(); From 30cd783dc32185d6cde138d87167709f8bfeff62 Mon Sep 17 00:00:00 2001 From: Alymosul Date: Fri, 7 Sep 2018 14:35:47 +0200 Subject: [PATCH 0312/2459] Check if the comparison rules have an attribute or a value before replacing the place holders. --- .../Concerns/ReplacesAttributes.php | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php index 6ebdfddd7f20..42f8a31f94fe 100644 --- a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php @@ -259,7 +259,11 @@ protected function replaceSize($message, $attribute, $rule, $parameters) */ protected function replaceGt($message, $attribute, $rule, $parameters) { - return str_replace(':value', $this->getSize($parameters[0], $this->getValue($parameters[0])), $message); + if (is_null($value = $this->getValue($parameters[0]))) { + return str_replace(':value', $parameters[0], $message); + } + + return str_replace(':value', $this->getSize($parameters[0], $value), $message); } /** @@ -273,7 +277,11 @@ protected function replaceGt($message, $attribute, $rule, $parameters) */ protected function replaceLt($message, $attribute, $rule, $parameters) { - return str_replace(':value', $this->getSize($parameters[0], $this->getValue($parameters[0])), $message); + if (is_null($value = $this->getValue($parameters[0]))) { + return str_replace(':value', $parameters[0], $message); + } + + return str_replace(':value', $this->getSize($parameters[0], $value), $message); } /** @@ -287,7 +295,11 @@ protected function replaceLt($message, $attribute, $rule, $parameters) */ protected function replaceGte($message, $attribute, $rule, $parameters) { - return str_replace(':value', $this->getSize($parameters[0], $this->getValue($parameters[0])), $message); + if (is_null($value = $this->getValue($parameters[0]))) { + return str_replace(':value', $parameters[0], $message); + } + + return str_replace(':value', $this->getSize($parameters[0], $value), $message); } /** @@ -301,7 +313,11 @@ protected function replaceGte($message, $attribute, $rule, $parameters) */ protected function replaceLte($message, $attribute, $rule, $parameters) { - return str_replace(':value', $this->getSize($parameters[0], $this->getValue($parameters[0])), $message); + if (is_null($value = $this->getValue($parameters[0]))) { + return str_replace(':value', $parameters[0], $message); + } + + return str_replace(':value', $this->getSize($parameters[0], $value), $message); } /** From f357804f1650a3cad37b918ac4a31dd074ab71bc Mon Sep 17 00:00:00 2001 From: Alex Bouma Date: Fri, 7 Sep 2018 16:35:34 +0300 Subject: [PATCH 0313/2459] Fix DurationLimiter not using Redis connection proxy to call eval command (#25505) --- src/Illuminate/Redis/Limiters/DurationLimiter.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Redis/Limiters/DurationLimiter.php b/src/Illuminate/Redis/Limiters/DurationLimiter.php index 0cd555217145..55e506b24ff8 100644 --- a/src/Illuminate/Redis/Limiters/DurationLimiter.php +++ b/src/Illuminate/Redis/Limiters/DurationLimiter.php @@ -99,9 +99,9 @@ public function block($timeout, $callback = null) */ public function acquire() { - $results = $this->redis->command('eval', [ - $this->luaScript(), 1, $this->name, microtime(true), time(), $this->decay, $this->maxLocks, - ]); + $results = $this->redis->eval( + $this->luaScript(), 1, $this->name, microtime(true), time(), $this->decay, $this->maxLocks + ); $this->decaysAt = $results[1]; From ee02df8dc5668c835f75de5b591b286bd331a8b5 Mon Sep 17 00:00:00 2001 From: Franz Liedke Date: Fri, 7 Sep 2018 15:41:59 +0200 Subject: [PATCH 0314/2459] [5.8] Resolve Blade facade to named service (#25497) --- src/Illuminate/Support/Facades/Blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Facades/Blade.php b/src/Illuminate/Support/Facades/Blade.php index 241f6c6a09c7..aa00bf156413 100755 --- a/src/Illuminate/Support/Facades/Blade.php +++ b/src/Illuminate/Support/Facades/Blade.php @@ -31,6 +31,6 @@ class Blade extends Facade */ protected static function getFacadeAccessor() { - return static::$app['view']->getEngineResolver()->resolve('blade')->getCompiler(); + return 'blade.compiler'; } } From 4ccd14c2365ac12400ee63dab97dddc40cb7704d Mon Sep 17 00:00:00 2001 From: Sjors Ottjes Date: Fri, 7 Sep 2018 15:46:05 +0200 Subject: [PATCH 0315/2459] [5.7] Fix `withoutMockingConsoleOutput` (#25499) * Update InteractsWithConsole.php * Update InteractsWithConsole.php --- .../Foundation/Testing/Concerns/InteractsWithConsole.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php index 37700051c656..382f2927120a 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithConsole.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation\Testing\Concerns; +use Illuminate\Console\OutputStyle; use Illuminate\Contracts\Console\Kernel; use Illuminate\Foundation\Testing\PendingCommand; @@ -63,6 +64,8 @@ protected function withoutMockingConsoleOutput() { $this->mockConsoleOutput = false; + $this->app->offsetUnset(OutputStyle::class); + return $this; } } From 08ee734971faf758f7413a4ff0d33a7454458063 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 7 Sep 2018 08:55:28 -0500 Subject: [PATCH 0316/2459] formatting --- src/Illuminate/Foundation/helpers.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index d9eb812a5f11..ab38be1ff6ff 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -239,11 +239,7 @@ function cache() } if (is_string($arguments[0])) { - if (! array_key_exists(1, $arguments)) { - return app('cache')->get($arguments[0]); - } else { - return app('cache')->get($arguments[0], $arguments[1] ?? null); - } + return app('cache')->get(...$arguments); } if (! is_array($arguments[0])) { From deeb649e07fdffae98c68f3b5753a64ec0fda537 Mon Sep 17 00:00:00 2001 From: Amadeusz Annissimo Date: Fri, 7 Sep 2018 09:56:14 -0400 Subject: [PATCH 0317/2459] remove getDefaultNamespace method (#25510) --- .../Foundation/Console/ModelMakeCommand.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Illuminate/Foundation/Console/ModelMakeCommand.php b/src/Illuminate/Foundation/Console/ModelMakeCommand.php index 05366746e266..c44038a97650 100644 --- a/src/Illuminate/Foundation/Console/ModelMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ModelMakeCommand.php @@ -125,17 +125,6 @@ protected function getStub() return __DIR__.'/stubs/model.stub'; } - /** - * Get the default namespace for the class. - * - * @param string $rootNamespace - * @return string - */ - protected function getDefaultNamespace($rootNamespace) - { - return $rootNamespace; - } - /** * Get the console command options. * From 0efdd6d56c2bed3cbbe76e3be24399c3405c3d48 Mon Sep 17 00:00:00 2001 From: Lucas Michot Date: Fri, 7 Sep 2018 16:05:10 +0200 Subject: [PATCH 0318/2459] Use ClientInterface proper request() method. (#25490) --- src/Illuminate/Mail/Transport/MailgunTransport.php | 3 ++- src/Illuminate/Mail/Transport/MandrillTransport.php | 2 +- src/Illuminate/Mail/Transport/SparkPostTransport.php | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Mail/Transport/MailgunTransport.php b/src/Illuminate/Mail/Transport/MailgunTransport.php index 5dacdca4aac3..73dfb5624222 100644 --- a/src/Illuminate/Mail/Transport/MailgunTransport.php +++ b/src/Illuminate/Mail/Transport/MailgunTransport.php @@ -64,7 +64,8 @@ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = nul $message->setBcc([]); - $this->client->post( + $this->client->request( + 'POST', "https://{$this->endpoint}/v3/{$this->domain}/messages.mime", $this->payload($message, $to) ); diff --git a/src/Illuminate/Mail/Transport/MandrillTransport.php b/src/Illuminate/Mail/Transport/MandrillTransport.php index 685b02753df4..e8e6ae1682e6 100644 --- a/src/Illuminate/Mail/Transport/MandrillTransport.php +++ b/src/Illuminate/Mail/Transport/MandrillTransport.php @@ -41,7 +41,7 @@ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = nul { $this->beforeSendPerformed($message); - $this->client->post('https://mandrillapp.com/api/1.0/messages/send-raw.json', [ + $this->client->request('POST', 'https://mandrillapp.com/api/1.0/messages/send-raw.json', [ 'form_params' => [ 'key' => $this->key, 'to' => $this->getTo($message), diff --git a/src/Illuminate/Mail/Transport/SparkPostTransport.php b/src/Illuminate/Mail/Transport/SparkPostTransport.php index 8f0e788cd8c1..6598a4e915a9 100644 --- a/src/Illuminate/Mail/Transport/SparkPostTransport.php +++ b/src/Illuminate/Mail/Transport/SparkPostTransport.php @@ -54,7 +54,7 @@ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = nul $message->setBcc([]); - $response = $this->client->post($this->getEndpoint(), [ + $response = $this->client->request('POST', $this->getEndpoint(), [ 'headers' => [ 'Authorization' => $this->key, ], From 4665d323ad4d71d1378e9b51cf572c9547302d95 Mon Sep 17 00:00:00 2001 From: Alymosul Date: Fri, 7 Sep 2018 17:05:18 +0200 Subject: [PATCH 0319/2459] Force the replacer to respect the numeric rule of the current input and apply it on the other input we're comparing against. --- .../Concerns/ReplacesAttributes.php | 8 +- tests/Validation/ValidationValidatorTest.php | 148 ++++++++++++++++++ 2 files changed, 152 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php index 42f8a31f94fe..3594dd9b3540 100644 --- a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php @@ -263,7 +263,7 @@ protected function replaceGt($message, $attribute, $rule, $parameters) return str_replace(':value', $parameters[0], $message); } - return str_replace(':value', $this->getSize($parameters[0], $value), $message); + return str_replace(':value', $this->getSize($attribute, $value), $message); } /** @@ -281,7 +281,7 @@ protected function replaceLt($message, $attribute, $rule, $parameters) return str_replace(':value', $parameters[0], $message); } - return str_replace(':value', $this->getSize($parameters[0], $value), $message); + return str_replace(':value', $this->getSize($attribute, $value), $message); } /** @@ -299,7 +299,7 @@ protected function replaceGte($message, $attribute, $rule, $parameters) return str_replace(':value', $parameters[0], $message); } - return str_replace(':value', $this->getSize($parameters[0], $value), $message); + return str_replace(':value', $this->getSize($attribute, $value), $message); } /** @@ -317,7 +317,7 @@ protected function replaceLte($message, $attribute, $rule, $parameters) return str_replace(':value', $parameters[0], $message); } - return str_replace(':value', $this->getSize($parameters[0], $value), $message); + return str_replace(':value', $this->getSize($attribute, $value), $message); } /** diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 7abf86bed271..0c2add00f8b9 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1533,6 +1533,154 @@ public function testProperMessagesAreReturnedForSizes() $this->assertEquals('file', $v->messages()->first('photo')); } + public function testValidateGtPlaceHolderIsReplacedProperly() + { + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines([ + 'validation.gt.numeric' => ':value', + 'validation.gt.string' => ':value', + 'validation.gt.file' => ':value', + 'validation.gt.array' => ':value' + ], 'en'); + + $v = new Validator($trans, ['items' => '3'], ['items' => 'gt:4']); + $this->assertFalse($v->passes()); + $this->assertEquals(4, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 3, 'more' => 5], ['items' => 'numeric|gt:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 'abc', 'more' => 'abcde'], ['items' => 'gt:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('items')); + + $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $biggerFile = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $biggerFile->expects($this->any())->method('getSize')->will($this->returnValue(5120)); + $biggerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['photo' => $file, 'bigger' => $biggerFile], ['photo' => 'file|gt:bigger']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('photo')); + + $v = new Validator($trans, ['items' => [1,2,3], 'more' => [0,1,2,3]], ['items' => 'gt:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(4, $v->messages()->first('items')); + } + + public function testValidateLtPlaceHolderIsReplacedProperly() + { + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines([ + 'validation.lt.numeric' => ':value', + 'validation.lt.string' => ':value', + 'validation.lt.file' => ':value', + 'validation.lt.array' => ':value' + ], 'en'); + + $v = new Validator($trans, ['items' => '3'], ['items' => 'lt:2']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 3, 'less' => 2], ['items' => 'numeric|lt:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 'abc', 'less' => 'ab'], ['items' => 'lt:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $smallerFile = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $smallerFile->expects($this->any())->method('getSize')->will($this->returnValue(2048)); + $smallerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['photo' => $file, 'smaller' => $smallerFile], ['photo' => 'file|lt:smaller']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('photo')); + + $v = new Validator($trans, ['items' => [1,2,3], 'less' => [0,1]], ['items' => 'lt:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + } + + public function testValidateGtePlaceHolderIsReplacedProperly() + { + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines([ + 'validation.gte.numeric' => ':value', + 'validation.gte.string' => ':value', + 'validation.gte.file' => ':value', + 'validation.gte.array' => ':value' + ], 'en'); + + $v = new Validator($trans, ['items' => '3'], ['items' => 'gte:4']); + $this->assertFalse($v->passes()); + $this->assertEquals(4, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 3, 'more' => 5], ['items' => 'numeric|gte:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 'abc', 'more' => 'abcde'], ['items' => 'gte:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('items')); + + $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $biggerFile = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $biggerFile->expects($this->any())->method('getSize')->will($this->returnValue(5120)); + $biggerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['photo' => $file, 'bigger' => $biggerFile], ['photo' => 'file|gte:bigger']); + $this->assertFalse($v->passes()); + $this->assertEquals(5, $v->messages()->first('photo')); + + $v = new Validator($trans, ['items' => [1,2,3], 'more' => [0,1,2,3]], ['items' => 'gte:more']); + $this->assertFalse($v->passes()); + $this->assertEquals(4, $v->messages()->first('items')); + } + + public function testValidateLtePlaceHolderIsReplacedProperly() + { + $trans = $this->getIlluminateArrayTranslator(); + $trans->addLines([ + 'validation.lte.numeric' => ':value', + 'validation.lte.string' => ':value', + 'validation.lte.file' => ':value', + 'validation.lte.array' => ':value' + ], 'en'); + + $v = new Validator($trans, ['items' => '3'], ['items' => 'lte:2']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 3, 'less' => 2], ['items' => 'numeric|lte:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $v = new Validator($trans, ['items' => 'abc', 'less' => 'ab'], ['items' => 'lte:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + + $file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $file->expects($this->any())->method('getSize')->will($this->returnValue(4072)); + $file->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $smallerFile = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')->setMethods(['getSize', 'isValid'])->setConstructorArgs([__FILE__, false])->getMock(); + $smallerFile->expects($this->any())->method('getSize')->will($this->returnValue(2048)); + $smallerFile->expects($this->any())->method('isValid')->will($this->returnValue(true)); + $v = new Validator($trans, ['photo' => $file, 'smaller' => $smallerFile], ['photo' => 'file|lte:smaller']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('photo')); + + $v = new Validator($trans, ['items' => [1,2,3], 'less' => [0,1]], ['items' => 'lte:less']); + $this->assertFalse($v->passes()); + $this->assertEquals(2, $v->messages()->first('items')); + } + public function testValidateIn() { $trans = $this->getIlluminateArrayTranslator(); From 1ac97b810cc502c71d7f6ae9d08a7f0b010c9ed3 Mon Sep 17 00:00:00 2001 From: Alymosul Date: Fri, 7 Sep 2018 17:13:09 +0200 Subject: [PATCH 0320/2459] Apply StyleCI fixes. --- tests/Validation/ValidationValidatorTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 0c2add00f8b9..c3189ca83e78 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1540,7 +1540,7 @@ public function testValidateGtPlaceHolderIsReplacedProperly() 'validation.gt.numeric' => ':value', 'validation.gt.string' => ':value', 'validation.gt.file' => ':value', - 'validation.gt.array' => ':value' + 'validation.gt.array' => ':value', ], 'en'); $v = new Validator($trans, ['items' => '3'], ['items' => 'gt:4']); @@ -1565,7 +1565,7 @@ public function testValidateGtPlaceHolderIsReplacedProperly() $this->assertFalse($v->passes()); $this->assertEquals(5, $v->messages()->first('photo')); - $v = new Validator($trans, ['items' => [1,2,3], 'more' => [0,1,2,3]], ['items' => 'gt:more']); + $v = new Validator($trans, ['items' => [1, 2, 3], 'more' => [0, 1, 2, 3]], ['items' => 'gt:more']); $this->assertFalse($v->passes()); $this->assertEquals(4, $v->messages()->first('items')); } @@ -1577,7 +1577,7 @@ public function testValidateLtPlaceHolderIsReplacedProperly() 'validation.lt.numeric' => ':value', 'validation.lt.string' => ':value', 'validation.lt.file' => ':value', - 'validation.lt.array' => ':value' + 'validation.lt.array' => ':value', ], 'en'); $v = new Validator($trans, ['items' => '3'], ['items' => 'lt:2']); @@ -1602,7 +1602,7 @@ public function testValidateLtPlaceHolderIsReplacedProperly() $this->assertFalse($v->passes()); $this->assertEquals(2, $v->messages()->first('photo')); - $v = new Validator($trans, ['items' => [1,2,3], 'less' => [0,1]], ['items' => 'lt:less']); + $v = new Validator($trans, ['items' => [1, 2, 3], 'less' => [0, 1]], ['items' => 'lt:less']); $this->assertFalse($v->passes()); $this->assertEquals(2, $v->messages()->first('items')); } @@ -1614,7 +1614,7 @@ public function testValidateGtePlaceHolderIsReplacedProperly() 'validation.gte.numeric' => ':value', 'validation.gte.string' => ':value', 'validation.gte.file' => ':value', - 'validation.gte.array' => ':value' + 'validation.gte.array' => ':value', ], 'en'); $v = new Validator($trans, ['items' => '3'], ['items' => 'gte:4']); @@ -1639,7 +1639,7 @@ public function testValidateGtePlaceHolderIsReplacedProperly() $this->assertFalse($v->passes()); $this->assertEquals(5, $v->messages()->first('photo')); - $v = new Validator($trans, ['items' => [1,2,3], 'more' => [0,1,2,3]], ['items' => 'gte:more']); + $v = new Validator($trans, ['items' => [1, 2, 3], 'more' => [0, 1, 2, 3]], ['items' => 'gte:more']); $this->assertFalse($v->passes()); $this->assertEquals(4, $v->messages()->first('items')); } @@ -1651,7 +1651,7 @@ public function testValidateLtePlaceHolderIsReplacedProperly() 'validation.lte.numeric' => ':value', 'validation.lte.string' => ':value', 'validation.lte.file' => ':value', - 'validation.lte.array' => ':value' + 'validation.lte.array' => ':value', ], 'en'); $v = new Validator($trans, ['items' => '3'], ['items' => 'lte:2']); @@ -1676,7 +1676,7 @@ public function testValidateLtePlaceHolderIsReplacedProperly() $this->assertFalse($v->passes()); $this->assertEquals(2, $v->messages()->first('photo')); - $v = new Validator($trans, ['items' => [1,2,3], 'less' => [0,1]], ['items' => 'lte:less']); + $v = new Validator($trans, ['items' => [1, 2, 3], 'less' => [0, 1]], ['items' => 'lte:less']); $this->assertFalse($v->passes()); $this->assertEquals(2, $v->messages()->first('items')); } From 0dd0c63cd14e42b8fa1fbb5c661ff220479a330d Mon Sep 17 00:00:00 2001 From: Franz Liedke Date: Fri, 7 Sep 2018 21:41:13 +0200 Subject: [PATCH 0321/2459] [5.8] Register binding for schema facade (#25512) * Register binding for schema builder * Use new service binding in Schema facade --- src/Illuminate/Database/DatabaseServiceProvider.php | 4 ++++ src/Illuminate/Support/Facades/Schema.php | 6 +++--- tests/Database/DatabaseMigratorIntegrationTest.php | 3 +++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/DatabaseServiceProvider.php b/src/Illuminate/Database/DatabaseServiceProvider.php index a8ee7b030b78..66dd4b9a3957 100755 --- a/src/Illuminate/Database/DatabaseServiceProvider.php +++ b/src/Illuminate/Database/DatabaseServiceProvider.php @@ -65,6 +65,10 @@ protected function registerConnectionServices() $this->app->bind('db.connection', function ($app) { return $app['db']->connection(); }); + + $this->app->bind('db.schema', function ($app) { + return $app['db']->connection()->getSchemaBuilder(); + }); } /** diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index 31748e15029b..d3a924811b01 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -25,12 +25,12 @@ public static function connection($name) } /** - * Get a schema builder instance for the default connection. + * Get the registered name of the component. * - * @return \Illuminate\Database\Schema\Builder + * @return string */ protected static function getFacadeAccessor() { - return static::$app['db']->connection()->getSchemaBuilder(); + return 'db.schema'; } } diff --git a/tests/Database/DatabaseMigratorIntegrationTest.php b/tests/Database/DatabaseMigratorIntegrationTest.php index d13da9d25aa8..74fe108dfeec 100644 --- a/tests/Database/DatabaseMigratorIntegrationTest.php +++ b/tests/Database/DatabaseMigratorIntegrationTest.php @@ -32,6 +32,9 @@ public function setUp() $container = new \Illuminate\Container\Container; $container->instance('db', $db->getDatabaseManager()); + $container->bind('db.schema', function ($c) { + return $c['db']->connection()->getSchemaBuilder(); + }); \Illuminate\Support\Facades\Facade::setFacadeApplication($container); $this->migrator = new Migrator( From a8cf7f4b82762b4738f605e04da637227c7de5a8 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Sat, 8 Sep 2018 00:26:10 +0200 Subject: [PATCH 0322/2459] Add test for the Model push method (#25519) --- .../Integration/Database/EloquentPushTest.php | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 tests/Integration/Database/EloquentPushTest.php diff --git a/tests/Integration/Database/EloquentPushTest.php b/tests/Integration/Database/EloquentPushTest.php new file mode 100644 index 000000000000..d9dea105d6d5 --- /dev/null +++ b/tests/Integration/Database/EloquentPushTest.php @@ -0,0 +1,90 @@ +increments('id'); + $table->string('name'); + }); + + Schema::create('posts', function (Blueprint $table) { + $table->increments('id'); + $table->string('title'); + $table->unsignedInteger('user_id'); + }); + + Schema::create('comments', function (Blueprint $table) { + $table->increments('id'); + $table->string('comment'); + $table->unsignedInteger('post_id'); + }); + } + + public function testPushMethodSavesTheRelationshipsRecursively() + { + $user = new UserX(); + $user->name = 'Test'; + $user->save(); + $user->posts()->create(['title' => 'Test title']); + + $post = PostX::firstOrFail(); + $post->comments()->create(['comment' => 'Test comment']); + + $user = $user->fresh(); + $user->name = 'Test 1'; + $user->posts[0]->title = 'Test title 1'; + $user->posts[0]->comments[0]->comment = 'Test comment 1'; + $user->push(); + + $this->assertSame(1, UserX::count()); + $this->assertSame('Test 1', UserX::firstOrFail()->name); + $this->assertSame(1, PostX::count()); + $this->assertSame('Test title 1', PostX::firstOrFail()->title); + $this->assertSame(1, CommentX::count()); + $this->assertSame('Test comment 1', CommentX::firstOrFail()->comment); + } +} + +class UserX extends Model +{ + public $timestamps = false; + protected $guarded = []; + protected $table = 'users'; + + public function posts() + { + return $this->hasMany(PostX::class, 'user_id'); + } +} + +class PostX extends Model +{ + public $timestamps = false; + protected $guarded = []; + protected $table = 'posts'; + + public function comments() + { + return $this->hasMany(CommentX::class, 'post_id'); + } +} + +class CommentX extends Model +{ + public $timestamps = false; + protected $guarded = []; + protected $table = 'comments'; +} From 92d373af64b8ff88f53e3b94320bd27c7ff7566c Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sat, 8 Sep 2018 01:44:17 +0300 Subject: [PATCH 0323/2459] [5.7] Deleted duplicated doc-block from Log Facade. --- src/Illuminate/Support/Facades/Log.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Illuminate/Support/Facades/Log.php b/src/Illuminate/Support/Facades/Log.php index 589e0e193549..cf25934d792d 100755 --- a/src/Illuminate/Support/Facades/Log.php +++ b/src/Illuminate/Support/Facades/Log.php @@ -15,9 +15,6 @@ * @method static mixed channel(string $channel = null) * @method static \Psr\Log\LoggerInterface stack(array $channels, string $channel = null) * - * @method static self channel(string $channel) - * @method static self stack(array $channels) - * * @see \Illuminate\Log\Logger */ class Log extends Facade From 632c4959abdd4db861830654747aba1950b26c67 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sat, 8 Sep 2018 08:46:22 +0100 Subject: [PATCH 0324/2459] Fixed merge --- src/Illuminate/Support/composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 28a14764bd9f..9ad9055fdd99 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -18,7 +18,6 @@ "ext-mbstring": "*", "doctrine/inflector": "^1.1", "illuminate/contracts": "5.8.*", - "illuminate/contracts": "5.7.*", "nesbot/carbon": "^1.26.3" }, "conflict": { From eb41660c0182d4d3747274c5b7d3c67ec123ada8 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sat, 8 Sep 2018 19:07:36 +0300 Subject: [PATCH 0325/2459] [5.8] Cache/TaggableStore.php implement `Illuminate\Contracts\Cache\Store` (#25529) 1. within TaggableStore class we have tags method. 2. Tags method create a `TaggedCache` with first argument `$this` 3. TaggedCache in constructor first argument has `\Illuminate\Contracts\Cache\Store` type So TaggableStore should implement `\Illuminate\Contracts\Cache\Store` interface, in other case someone can extend `TaggableStore`, but not implement the `\Illuminate\Contracts\Cache\Store` and `TaggableStore:tags` will be broken. --- src/Illuminate/Cache/ApcStore.php | 4 +--- src/Illuminate/Cache/ArrayStore.php | 4 +--- src/Illuminate/Cache/MemcachedStore.php | 3 +-- src/Illuminate/Cache/NullStore.php | 4 +--- src/Illuminate/Cache/RedisStore.php | 3 +-- src/Illuminate/Cache/TaggableStore.php | 4 +++- 6 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Cache/ApcStore.php b/src/Illuminate/Cache/ApcStore.php index db11ea4ebf58..a4d1a2024fb9 100755 --- a/src/Illuminate/Cache/ApcStore.php +++ b/src/Illuminate/Cache/ApcStore.php @@ -2,9 +2,7 @@ namespace Illuminate\Cache; -use Illuminate\Contracts\Cache\Store; - -class ApcStore extends TaggableStore implements Store +class ApcStore extends TaggableStore { use RetrievesMultipleKeys; diff --git a/src/Illuminate/Cache/ArrayStore.php b/src/Illuminate/Cache/ArrayStore.php index 806f97116b6a..711540e52199 100644 --- a/src/Illuminate/Cache/ArrayStore.php +++ b/src/Illuminate/Cache/ArrayStore.php @@ -2,9 +2,7 @@ namespace Illuminate\Cache; -use Illuminate\Contracts\Cache\Store; - -class ArrayStore extends TaggableStore implements Store +class ArrayStore extends TaggableStore { use RetrievesMultipleKeys; diff --git a/src/Illuminate/Cache/MemcachedStore.php b/src/Illuminate/Cache/MemcachedStore.php index 00ba8b7c9411..ac5ae68778fd 100755 --- a/src/Illuminate/Cache/MemcachedStore.php +++ b/src/Illuminate/Cache/MemcachedStore.php @@ -4,11 +4,10 @@ use Memcached; use ReflectionMethod; -use Illuminate\Contracts\Cache\Store; use Illuminate\Support\InteractsWithTime; use Illuminate\Contracts\Cache\LockProvider; -class MemcachedStore extends TaggableStore implements LockProvider, Store +class MemcachedStore extends TaggableStore implements LockProvider { use InteractsWithTime; diff --git a/src/Illuminate/Cache/NullStore.php b/src/Illuminate/Cache/NullStore.php index 16e869c80662..ab2539724cb4 100755 --- a/src/Illuminate/Cache/NullStore.php +++ b/src/Illuminate/Cache/NullStore.php @@ -2,9 +2,7 @@ namespace Illuminate\Cache; -use Illuminate\Contracts\Cache\Store; - -class NullStore extends TaggableStore implements Store +class NullStore extends TaggableStore { use RetrievesMultipleKeys; diff --git a/src/Illuminate/Cache/RedisStore.php b/src/Illuminate/Cache/RedisStore.php index b448e464cf29..b4ac0a95c386 100755 --- a/src/Illuminate/Cache/RedisStore.php +++ b/src/Illuminate/Cache/RedisStore.php @@ -2,10 +2,9 @@ namespace Illuminate\Cache; -use Illuminate\Contracts\Cache\Store; use Illuminate\Contracts\Redis\Factory as Redis; -class RedisStore extends TaggableStore implements Store +class RedisStore extends TaggableStore { /** * The Redis factory implementation. diff --git a/src/Illuminate/Cache/TaggableStore.php b/src/Illuminate/Cache/TaggableStore.php index ba00fa450336..6a12b45dbfd3 100644 --- a/src/Illuminate/Cache/TaggableStore.php +++ b/src/Illuminate/Cache/TaggableStore.php @@ -2,7 +2,9 @@ namespace Illuminate\Cache; -abstract class TaggableStore +use Illuminate\Contracts\Cache\Store; + +abstract class TaggableStore implements Store { /** * Begin executing a new tags operation. From be4eb64203f3a7e4af1249143dd3f04aa808b09f Mon Sep 17 00:00:00 2001 From: Amadeusz Annissimo Date: Sat, 8 Sep 2018 14:44:20 -0400 Subject: [PATCH 0326/2459] Fixed validator() helper docblock (#25533) --- src/Illuminate/Foundation/helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index ab38be1ff6ff..6d9f1b1ce53c 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -967,7 +967,7 @@ function url($path = null, $parameters = [], $secure = null) * @param array $rules * @param array $messages * @param array $customAttributes - * @return \Illuminate\Contracts\Validation\Validator + * @return \Illuminate\Contracts\Validation\Validator|Illuminate\Contracts\Validation\Factory */ function validator(array $data = [], array $rules = [], array $messages = [], array $customAttributes = []) { From e21b17fd277b9a2424ea2b3f727325d1df65c713 Mon Sep 17 00:00:00 2001 From: Cyril Mazur Date: Sun, 9 Sep 2018 20:33:31 +0800 Subject: [PATCH 0327/2459] =?UTF-8?q?Add=20options=20for=20SES=E2=80=99s?= =?UTF-8?q?=20sendRawEmail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Mail/Transport/SesTransport.php | 51 ++++++++++++++++--- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Mail/Transport/SesTransport.php b/src/Illuminate/Mail/Transport/SesTransport.php index c3afe3f5e3bf..5492390f8e1b 100644 --- a/src/Illuminate/Mail/Transport/SesTransport.php +++ b/src/Illuminate/Mail/Transport/SesTransport.php @@ -14,15 +14,24 @@ class SesTransport extends Transport */ protected $ses; + /** + * Transmission options. + * + * @var array + */ + protected $options = []; + /** * Create a new SES transport instance. * * @param \Aws\Ses\SesClient $ses + * @param array $options * @return void */ - public function __construct(SesClient $ses) + public function __construct(SesClient $ses, $options = []) { $this->ses = $ses; + $this->options = $options; } /** @@ -32,17 +41,43 @@ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = nul { $this->beforeSendPerformed($message); - $headers = $message->getHeaders(); + $result = $this->ses->sendRawEmail( + array_merge( + $this->options, + [ + 'Source' => key($message->getSender() ?: $message->getFrom()), + 'RawMessage' => [ + 'Data' => $message->toString(), + ], + ] + ) + ); - $headers->addTextHeader('X-SES-Message-ID', $this->ses->sendRawEmail([ - 'Source' => key($message->getSender() ?: $message->getFrom()), - 'RawMessage' => [ - 'Data' => $message->toString(), - ], - ])->get('MessageId')); + $message->getHeaders()->addTextHeader('X-SES-Message-ID', $result->get('MessageId')); $this->sendPerformed($message); return $this->numberOfRecipients($message); } + + /** + * Get the transmission options being used by the transport. + * + * @return array + */ + public function getOptions() + { + return $this->options; + } + + /** + * Set the transmission options being used by the transport. + * + * @param array $options + * @return array + */ + public function setOptions(array $options) + { + return $this->options = $options; + } } From b37b7caa6e74e01da76ca403796835156fe0304e Mon Sep 17 00:00:00 2001 From: Cyril Mazur Date: Sun, 9 Sep 2018 20:48:53 +0800 Subject: [PATCH 0328/2459] Add options array --- src/Illuminate/Mail/TransportManager.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Mail/TransportManager.php b/src/Illuminate/Mail/TransportManager.php index bab48943d2db..bc1f893831b3 100644 --- a/src/Illuminate/Mail/TransportManager.php +++ b/src/Illuminate/Mail/TransportManager.php @@ -77,9 +77,10 @@ protected function createSesDriver() 'version' => 'latest', 'service' => 'email', ]); - return new SesTransport(new SesClient( - $this->addSesCredentials($config) - )); + return new SesTransport( + new SesClient($this->addSesCredentials($config)), + $config['options'] ?? [] + ); } /** From 544b75943c055ec7e6318cb00ec53d5cc8661aa5 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 10 Sep 2018 03:26:35 +0300 Subject: [PATCH 0329/2459] [5.7] Auth/Access/Response::__toString method always should return string. (#25539) __toString should return string, in other case it will emit the FatalError. --- src/Illuminate/Auth/Access/Response.php | 4 ++-- tests/Auth/AuthAccessResponseTest.php | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 tests/Auth/AuthAccessResponseTest.php diff --git a/src/Illuminate/Auth/Access/Response.php b/src/Illuminate/Auth/Access/Response.php index ee29c293f3e1..7fab01efcce5 100644 --- a/src/Illuminate/Auth/Access/Response.php +++ b/src/Illuminate/Auth/Access/Response.php @@ -35,10 +35,10 @@ public function message() /** * Get the string representation of the message. * - * @return string|null + * @return string */ public function __toString() { - return $this->message(); + return (string) $this->message(); } } diff --git a/tests/Auth/AuthAccessResponseTest.php b/tests/Auth/AuthAccessResponseTest.php new file mode 100644 index 000000000000..f154ef6eddc0 --- /dev/null +++ b/tests/Auth/AuthAccessResponseTest.php @@ -0,0 +1,21 @@ +assertSame('some data', (string) $response); + + $response = new Response(); + $this->assertSame('', (string) $response); + } +} From b2f1482098083f4c9a76d8cba8b5d76bdf80efa3 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 10 Sep 2018 17:37:30 +0300 Subject: [PATCH 0330/2459] [5.7] Added \Illuminate\Database\Eloquent\Model to phpDoc for updateRememberToken function. (#25554) - since in the class we also used the property witch present in Model class, but not in the `\Illuminate\Contracts\Auth\Authenticatable` --- src/Illuminate/Auth/EloquentUserProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/EloquentUserProvider.php b/src/Illuminate/Auth/EloquentUserProvider.php index e7b447d224a6..23b5b792cf13 100755 --- a/src/Illuminate/Auth/EloquentUserProvider.php +++ b/src/Illuminate/Auth/EloquentUserProvider.php @@ -77,7 +77,7 @@ public function retrieveByToken($identifier, $token) /** * Update the "remember me" token for the given user in storage. * - * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param \Illuminate\Contracts\Auth\Authenticatable|\Illuminate\Database\Eloquent\Model $user * @param string $token * @return void */ From c0dc90a42a3ef33839bff68e5a46c5d4f61c56ab Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 10 Sep 2018 17:37:43 +0300 Subject: [PATCH 0331/2459] [5.7] Added Unit tests for Auth/AuthListenersSendEmailVerificationNotificationTest.php (#25553) I have added unit tests for `Auth/Listeners/SendEmailVerificationNotification.php`, since I cannot found tests for this class. --- ...ficationNotificationHandleFunctionTest.php | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php diff --git a/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php b/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php new file mode 100644 index 000000000000..815f0d1d389e --- /dev/null +++ b/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php @@ -0,0 +1,53 @@ +getMockBuilder(MustVerifyEmail::class)->getMock(); + $user->method('hasVerifiedEmail')->willReturn(false); + $user->expects($this->exactly(1))->method('sendEmailVerificationNotification'); + + $listener = new SendEmailVerificationNotification(); + + $listener->handle(new Registered($user)); + } + + /** + * @return void + */ + public function testUserIsNotInstanceOfMustVerifyEmail() + { + $user = $this->getMockBuilder(User::class)->getMock(); + $user->expects($this->exactly(0))->method('sendEmailVerificationNotification'); + + $listener = new SendEmailVerificationNotification(); + + $listener->handle(new Registered($user)); + } + + /** + * @return void + */ + public function testHasVerifiedEmailAsTrue() + { + $user = $this->getMockBuilder(MustVerifyEmail::class)->getMock(); + $user->method('hasVerifiedEmail')->willReturn(true); + $user->expects($this->exactly(0))->method('sendEmailVerificationNotification'); + + $listener = new SendEmailVerificationNotification(); + + $listener->handle(new Registered($user)); + } +} From f12df3e2061707720671327ef67decd364b0184e Mon Sep 17 00:00:00 2001 From: Nguyen Xuan Quynh Date: Mon, 10 Sep 2018 21:37:58 +0700 Subject: [PATCH 0332/2459] Remove unused view tests (#25551) --- tests/View/ViewBladeCompilerTest.php | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index b68fede14d45..e83a470061a8 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -96,16 +96,4 @@ protected function getFiles() { return m::mock('Illuminate\Filesystem\Filesystem'); } - - public function testGetTagsProvider() - { - return [ - ['{{', '}}'], - ['{{{', '}}}'], - ['[[', ']]'], - ['[[[', ']]]'], - ['((', '))'], - ['(((', ')))'], - ]; - } } From bdd011362cbe857498a6934087659f079ff649e2 Mon Sep 17 00:00:00 2001 From: Franz Liedke Date: Mon, 10 Sep 2018 16:41:27 +0200 Subject: [PATCH 0333/2459] [5.7] Clean up cache integration tests (#25545) * Split cache lock tests for Memcached and Redis The previous setup incorrectly skipped even the Redis tests when the Memcached extension was not installed. By separating them, we can also separate the logic for skipping these tests. * Redis cache lock tests: Use normal setup() and tearDown() * Memcached cache lock tests: Test for PHP extension, not class * Memcached cache lock tests: Also skip if no connection can be established --- ...ockTest.php => MemcachedCacheLockTest.php} | 49 ++++++----------- .../Integration/Cache/RedisCacheLockTest.php | 54 +++++++++++++++++++ 2 files changed, 70 insertions(+), 33 deletions(-) rename tests/Integration/Cache/{CacheLockTest.php => MemcachedCacheLockTest.php} (61%) create mode 100644 tests/Integration/Cache/RedisCacheLockTest.php diff --git a/tests/Integration/Cache/CacheLockTest.php b/tests/Integration/Cache/MemcachedCacheLockTest.php similarity index 61% rename from tests/Integration/Cache/CacheLockTest.php rename to tests/Integration/Cache/MemcachedCacheLockTest.php index 9bb964f46b47..5d230d57a884 100644 --- a/tests/Integration/Cache/CacheLockTest.php +++ b/tests/Integration/Cache/MemcachedCacheLockTest.php @@ -6,22 +6,33 @@ use Illuminate\Support\Carbon; use Orchestra\Testbench\TestCase; use Illuminate\Support\Facades\Cache; -use Illuminate\Foundation\Testing\Concerns\InteractsWithRedis; /** * @group integration */ -class CacheLockTest extends TestCase +class MemcachedCacheLockTest extends TestCase { - use InteractsWithRedis; - public function setUp() { parent::setUp(); - if (! class_exists(Memcached::class)) { + if (! extension_loaded('memcached')) { $this->markTestSkipped('Memcached module not installed'); } + + // Determine whether there is a running Memcached instance + $testConnection = new Memcached; + $testConnection->addServer( + env('MEMCACHED_HOST', '127.0.0.1'), + env('MEMCACHED_PORT', 11211) + ); + $testConnection->getVersion(); + + if ($testConnection->getResultCode() > Memcached::RES_SUCCESS) { + $this->markTestSkipped('Memcached could not establish a connection'); + } + + $testConnection->quit(); } public function test_memcached_locks_can_be_acquired_and_released() @@ -35,19 +46,6 @@ public function test_memcached_locks_can_be_acquired_and_released() Cache::store('memcached')->lock('foo')->release(); } - public function test_redis_locks_can_be_acquired_and_released() - { - $this->ifRedisAvailable(function () { - Cache::store('redis')->lock('foo')->release(); - $this->assertTrue(Cache::store('redis')->lock('foo', 10)->get()); - $this->assertFalse(Cache::store('redis')->lock('foo', 10)->get()); - Cache::store('redis')->lock('foo')->release(); - $this->assertTrue(Cache::store('redis')->lock('foo', 10)->get()); - $this->assertFalse(Cache::store('redis')->lock('foo', 10)->get()); - Cache::store('redis')->lock('foo')->release(); - }); - } - public function test_memcached_locks_can_block_for_seconds() { Carbon::setTestNow(); @@ -61,21 +59,6 @@ public function test_memcached_locks_can_block_for_seconds() $this->assertTrue(Cache::store('memcached')->lock('foo', 10)->block(1)); } - public function test_redis_locks_can_block_for_seconds() - { - $this->ifRedisAvailable(function () { - Carbon::setTestNow(); - - Cache::store('redis')->lock('foo')->release(); - $this->assertEquals('taylor', Cache::store('redis')->lock('foo', 10)->block(1, function () { - return 'taylor'; - })); - - Cache::store('redis')->lock('foo')->release(); - $this->assertTrue(Cache::store('redis')->lock('foo', 10)->block(1)); - }); - } - public function test_locks_can_run_callbacks() { Cache::store('memcached')->lock('foo')->release(); diff --git a/tests/Integration/Cache/RedisCacheLockTest.php b/tests/Integration/Cache/RedisCacheLockTest.php new file mode 100644 index 000000000000..e5747a5ca26e --- /dev/null +++ b/tests/Integration/Cache/RedisCacheLockTest.php @@ -0,0 +1,54 @@ +setUpRedis(); + } + + public function tearDown() + { + parent::tearDown(); + + $this->tearDownRedis(); + } + + public function test_redis_locks_can_be_acquired_and_released() + { + Cache::store('redis')->lock('foo')->release(); + $this->assertTrue(Cache::store('redis')->lock('foo', 10)->get()); + $this->assertFalse(Cache::store('redis')->lock('foo', 10)->get()); + Cache::store('redis')->lock('foo')->release(); + $this->assertTrue(Cache::store('redis')->lock('foo', 10)->get()); + $this->assertFalse(Cache::store('redis')->lock('foo', 10)->get()); + Cache::store('redis')->lock('foo')->release(); + } + + public function test_redis_locks_can_block_for_seconds() + { + Carbon::setTestNow(); + + Cache::store('redis')->lock('foo')->release(); + $this->assertEquals('taylor', Cache::store('redis')->lock('foo', 10)->block(1, function () { + return 'taylor'; + })); + + Cache::store('redis')->lock('foo')->release(); + $this->assertTrue(Cache::store('redis')->lock('foo', 10)->block(1)); + } +} From f3a57603853a214e24de2e1b8de6a4e111bb19a0 Mon Sep 17 00:00:00 2001 From: Alfa Adhitya Date: Mon, 10 Sep 2018 21:43:01 +0700 Subject: [PATCH 0334/2459] stop sending email verification if user already verified (#25540) --- src/Illuminate/Foundation/Auth/VerifiesEmails.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index ca539d359dcb..80d13c1e2109 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -46,6 +46,10 @@ public function verify(Request $request) */ public function resend(Request $request) { + if ($request->user()->hasVerifiedEmail()) { + return redirect($this->redirectPath()); + } + $request->user()->sendEmailVerificationNotification(); return back()->with('resent', true); From 8f3610a335cc603dbf3ff5c5d5502ca0412577ef Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 10 Sep 2018 09:50:09 -0500 Subject: [PATCH 0335/2459] formatting --- src/Illuminate/Mail/Transport/SesTransport.php | 5 ++--- src/Illuminate/Mail/Transport/SparkPostTransport.php | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Mail/Transport/SesTransport.php b/src/Illuminate/Mail/Transport/SesTransport.php index 5492390f8e1b..00e92bc5e1d2 100644 --- a/src/Illuminate/Mail/Transport/SesTransport.php +++ b/src/Illuminate/Mail/Transport/SesTransport.php @@ -15,7 +15,7 @@ class SesTransport extends Transport protected $ses; /** - * Transmission options. + * The Amazon SES transmission options. * * @var array */ @@ -43,8 +43,7 @@ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = nul $result = $this->ses->sendRawEmail( array_merge( - $this->options, - [ + $this->options, [ 'Source' => key($message->getSender() ?: $message->getFrom()), 'RawMessage' => [ 'Data' => $message->toString(), diff --git a/src/Illuminate/Mail/Transport/SparkPostTransport.php b/src/Illuminate/Mail/Transport/SparkPostTransport.php index 6598a4e915a9..a2358f1d874d 100644 --- a/src/Illuminate/Mail/Transport/SparkPostTransport.php +++ b/src/Illuminate/Mail/Transport/SparkPostTransport.php @@ -22,7 +22,7 @@ class SparkPostTransport extends Transport protected $key; /** - * Transmission options. + * The SparkPost transmission options. * * @var array */ From b2fa4e7ecf3b0b2797c7e91bcc929a5d20e47836 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 10 Sep 2018 16:51:32 +0200 Subject: [PATCH 0336/2459] Fix database cache on PostgreSQL (#25530) --- src/Illuminate/Cache/DatabaseStore.php | 42 +++++++++++++++++++++++--- tests/Cache/CacheDatabaseStoreTest.php | 32 ++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Cache/DatabaseStore.php b/src/Illuminate/Cache/DatabaseStore.php index 2306fb06d3f4..dc1241c805ee 100755 --- a/src/Illuminate/Cache/DatabaseStore.php +++ b/src/Illuminate/Cache/DatabaseStore.php @@ -4,8 +4,10 @@ use Closure; use Exception; +use Illuminate\Support\Str; use Illuminate\Contracts\Cache\Store; use Illuminate\Support\InteractsWithTime; +use Illuminate\Database\PostgresConnection; use Illuminate\Database\ConnectionInterface; class DatabaseStore implements Store @@ -78,7 +80,7 @@ public function get($key) return; } - return unserialize($cache->value); + return $this->unserialize($cache->value); } /** @@ -93,7 +95,7 @@ public function put($key, $value, $minutes) { $key = $this->prefix.$key; - $value = serialize($value); + $value = $this->serialize($value); $expiration = $this->getTime() + (int) ($minutes * 60); @@ -157,7 +159,7 @@ protected function incrementOrDecrement($key, $value, Closure $callback) $cache = is_array($cache) ? (object) $cache : $cache; - $current = unserialize($cache->value); + $current = $this->unserialize($cache->value); // Here we'll call this callback function that was given to the function which // is used to either increment or decrement the function. We use a callback @@ -172,7 +174,7 @@ protected function incrementOrDecrement($key, $value, Closure $callback) // since database cache values are encrypted by default with secure storage // that can't be easily read. We will return the new value after storing. $this->table()->where('key', $prefixed)->update([ - 'value' => serialize($new), + 'value' => $this->serialize($new), ]); return $new; @@ -253,4 +255,36 @@ public function getPrefix() { return $this->prefix; } + + /** + * Serialize the given value. + * + * @param mixed $value + * @return string + */ + protected function serialize($value) + { + $result = serialize($value); + + if ($this->connection instanceof PostgresConnection && Str::contains($result, "\0")) { + $result = base64_encode($result); + } + + return $result; + } + + /** + * Unserialize the given value. + * + * @param string $value + * @return mixed + */ + protected function unserialize($value) + { + if ($this->connection instanceof PostgresConnection && ! Str::contains($value, [':', ';'])) { + $value = base64_decode($value); + } + + return unserialize($value); + } } diff --git a/tests/Cache/CacheDatabaseStoreTest.php b/tests/Cache/CacheDatabaseStoreTest.php index 0069b2437852..9587d8f2ba74 100755 --- a/tests/Cache/CacheDatabaseStoreTest.php +++ b/tests/Cache/CacheDatabaseStoreTest.php @@ -48,6 +48,17 @@ public function testDecryptedValueIsReturnedWhenItemIsValid() $this->assertEquals('bar', $store->get('foo')); } + public function testValueIsReturnedOnPostgres() + { + $store = $this->getPostgresStore(); + $table = m::mock('stdClass'); + $store->getConnection()->shouldReceive('table')->once()->with('table')->andReturn($table); + $table->shouldReceive('where')->once()->with('key', '=', 'prefixfoo')->andReturn($table); + $table->shouldReceive('first')->once()->andReturn((object) ['value' => base64_encode(serialize('bar')), 'expiration' => 999999999999999]); + + $this->assertEquals('bar', $store->get('foo')); + } + public function testValueIsInsertedWhenNoExceptionsAreThrown() { $store = $this->getMockBuilder('Illuminate\Cache\DatabaseStore')->setMethods(['getTime'])->setConstructorArgs($this->getMocks())->getMock(); @@ -74,6 +85,17 @@ public function testValueIsUpdatedWhenInsertThrowsException() $store->put('foo', 'bar', 1); } + public function testValueIsInsertedOnPostgres() + { + $store = $this->getMockBuilder('Illuminate\Cache\DatabaseStore')->setMethods(['getTime'])->setConstructorArgs($this->getPostgresMocks())->getMock(); + $table = m::mock('stdClass'); + $store->getConnection()->shouldReceive('table')->once()->with('table')->andReturn($table); + $store->expects($this->once())->method('getTime')->will($this->returnValue(1)); + $table->shouldReceive('insert')->once()->with(['key' => 'prefixfoo', 'value' => base64_encode(serialize("\0")), 'expiration' => 61]); + + $store->put('foo', "\0", 1); + } + public function testForeverCallsStoreItemWithReallyLongTime() { $store = $this->getMockBuilder('Illuminate\Cache\DatabaseStore')->setMethods(['put'])->setConstructorArgs($this->getMocks())->getMock(); @@ -186,8 +208,18 @@ protected function getStore() return new DatabaseStore(m::mock('Illuminate\Database\Connection'), 'table', 'prefix'); } + protected function getPostgresStore() + { + return new DatabaseStore(m::mock('Illuminate\Database\PostgresConnection'), 'table', 'prefix'); + } + protected function getMocks() { return [m::mock('Illuminate\Database\Connection'), 'table', 'prefix']; } + + protected function getPostgresMocks() + { + return [m::mock('Illuminate\Database\PostgresConnection'), 'table', 'prefix']; + } } From 466e404f2afaea5005ed86898222705a2f073bb7 Mon Sep 17 00:00:00 2001 From: Franz Liedke Date: Mon, 10 Sep 2018 16:54:15 +0200 Subject: [PATCH 0337/2459] [5.8] Only allow strings for resolving facade roots (#25525) Because of #25497 and #25512, all facades in core are now properly using service identifiers (strings) for resolving their "root" service from the container. This means that the hack for resolving objects directly can now be removed. In case you're wondering why this is necessary: As far as I can tell, facade features like ::swap() did not work with these types of facades (Blade and Schema), because those methods did not deal with the possibility of objects being returned. --- src/Illuminate/Support/Facades/Facade.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Illuminate/Support/Facades/Facade.php b/src/Illuminate/Support/Facades/Facade.php index 579bd7a0f015..3cfe8f7ea853 100755 --- a/src/Illuminate/Support/Facades/Facade.php +++ b/src/Illuminate/Support/Facades/Facade.php @@ -145,15 +145,11 @@ protected static function getFacadeAccessor() /** * Resolve the facade root instance from the container. * - * @param string|object $name + * @param string $name * @return mixed */ protected static function resolveFacadeInstance($name) { - if (is_object($name)) { - return $name; - } - if (isset(static::$resolvedInstance[$name])) { return static::$resolvedInstance[$name]; } From a602ac429443ff18fac46ec2eadecffa63655f06 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 10 Sep 2018 22:41:44 +0300 Subject: [PATCH 0338/2459] [5.7] Fixed phpUnit tests: (#25562) - changed `$this->exactly(1)` to `$this->once()` - changed `$this->exactly(0)` to `$this->never()` --- ...sSendEmailVerificationNotificationHandleFunctionTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php b/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php index 815f0d1d389e..49a681d33fa6 100644 --- a/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php +++ b/tests/Auth/AuthListenersSendEmailVerificationNotificationHandleFunctionTest.php @@ -17,7 +17,7 @@ public function testWillExecuted() { $user = $this->getMockBuilder(MustVerifyEmail::class)->getMock(); $user->method('hasVerifiedEmail')->willReturn(false); - $user->expects($this->exactly(1))->method('sendEmailVerificationNotification'); + $user->expects($this->once())->method('sendEmailVerificationNotification'); $listener = new SendEmailVerificationNotification(); @@ -30,7 +30,7 @@ public function testWillExecuted() public function testUserIsNotInstanceOfMustVerifyEmail() { $user = $this->getMockBuilder(User::class)->getMock(); - $user->expects($this->exactly(0))->method('sendEmailVerificationNotification'); + $user->expects($this->never())->method('sendEmailVerificationNotification'); $listener = new SendEmailVerificationNotification(); @@ -44,7 +44,7 @@ public function testHasVerifiedEmailAsTrue() { $user = $this->getMockBuilder(MustVerifyEmail::class)->getMock(); $user->method('hasVerifiedEmail')->willReturn(true); - $user->expects($this->exactly(0))->method('sendEmailVerificationNotification'); + $user->expects($this->never())->method('sendEmailVerificationNotification'); $listener = new SendEmailVerificationNotification(); From aac6144db22768c780ab5a19c1441830254c6057 Mon Sep 17 00:00:00 2001 From: Dennis Smink Date: Mon, 10 Sep 2018 21:42:43 +0200 Subject: [PATCH 0339/2459] Ability to disable register route (#25556) --- src/Illuminate/Routing/Router.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index c3077b1035a4..c7e7ae2a4040 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -1149,8 +1149,10 @@ public function auth(array $options = []) $this->post('logout', 'Auth\LoginController@logout')->name('logout'); // Registration Routes... - $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); - $this->post('register', 'Auth\RegisterController@register'); + if ($options['register'] ?? true) { + $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); + $this->post('register', 'Auth\RegisterController@register'); + } // Password Reset Routes... $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request'); From f748f7102f9e6dea47f2aba911c0e8328ebef489 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 10 Sep 2018 23:43:45 +0300 Subject: [PATCH 0340/2459] [5.7] Fix docblock in validator() helper. - apply https://github.com/laravel/framework/pull/25533 to 5.7 --- src/Illuminate/Foundation/helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index ab38be1ff6ff..be6385b402af 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -967,7 +967,7 @@ function url($path = null, $parameters = [], $secure = null) * @param array $rules * @param array $messages * @param array $customAttributes - * @return \Illuminate\Contracts\Validation\Validator + * @return \Illuminate\Contracts\Validation\Validator|\Illuminate\Contracts\Validation\Factory */ function validator(array $data = [], array $rules = [], array $messages = [], array $customAttributes = []) { From 2e01692faaa8cb889748712ad5cc3d9aacc95770 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 10 Sep 2018 16:09:16 -0500 Subject: [PATCH 0341/2459] rename method --- src/Illuminate/Console/Scheduling/Event.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 0adb9bf3d6db..c7aced6c8494 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -376,7 +376,7 @@ public function appendOutputTo($location) */ public function emailOutputTo($addresses, $onlyIfOutputExists = false) { - $this->ensureOutputIsBeingCapturedForEmail(); + $this->ensureOutputIsBeingCaptured(); $addresses = Arr::wrap($addresses); @@ -399,11 +399,11 @@ public function emailWrittenOutputTo($addresses) } /** - * Ensure that output is being captured for email. + * Ensure that the command output is being captured. * * @return void */ - protected function ensureOutputIsBeingCapturedForEmail() + protected function ensureOutputIsBeingCaptured() { if (is_null($this->output) || $this->output == $this->getDefaultOutput()) { $this->sendOutputTo(storage_path('logs/schedule-'.sha1($this->mutexName()).'.log')); From bfa7a90f3974075f3044354fef15590c082716f2 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 11 Sep 2018 00:16:56 +0300 Subject: [PATCH 0342/2459] Revert "rename method" This reverts commit 2e01692 --- src/Illuminate/Console/Scheduling/Event.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index c7aced6c8494..0adb9bf3d6db 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -376,7 +376,7 @@ public function appendOutputTo($location) */ public function emailOutputTo($addresses, $onlyIfOutputExists = false) { - $this->ensureOutputIsBeingCaptured(); + $this->ensureOutputIsBeingCapturedForEmail(); $addresses = Arr::wrap($addresses); @@ -399,11 +399,11 @@ public function emailWrittenOutputTo($addresses) } /** - * Ensure that the command output is being captured. + * Ensure that output is being captured for email. * * @return void */ - protected function ensureOutputIsBeingCaptured() + protected function ensureOutputIsBeingCapturedForEmail() { if (is_null($this->output) || $this->output == $this->getDefaultOutput()) { $this->sendOutputTo(storage_path('logs/schedule-'.sha1($this->mutexName()).'.log')); From 70a72fcac9d8852fc1a4ce11eb47842774c11876 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 10 Sep 2018 16:47:45 -0500 Subject: [PATCH 0343/2459] add storeOutput method --- src/Illuminate/Console/Scheduling/Event.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index c7aced6c8494..0d9c11be171f 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -338,6 +338,18 @@ public function filtersPass($app) return true; } + /** + * Ensure that the output is stored on disk in a log file. + * + * @return $this + */ + public function storeOutput() + { + $this->ensureOutputIsBeingCaptured(); + + return $this; + } + /** * Send the output of the command to a given location. * From f0bb90743ee327f2132d01825aec73b781383fbe Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 11 Sep 2018 01:07:30 +0300 Subject: [PATCH 0344/2459] returned `ensureOutputIsBeingCaptured` method and make `ensureOutputIsBeingCapturedForEmail` deprecated. --- src/Illuminate/Console/Scheduling/Event.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 092a4b34f65d..15bc9d273fec 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -411,11 +411,23 @@ public function emailWrittenOutputTo($addresses) } /** + * @deprecated please use ensureOutputIsBeingCaptured + * * Ensure that output is being captured for email. * * @return void */ protected function ensureOutputIsBeingCapturedForEmail() + { + $this->ensureOutputIsBeingCaptured(); + } + + /** + * Ensure that the command output is being captured. + * + * @return void + */ + protected function ensureOutputIsBeingCaptured() { if (is_null($this->output) || $this->output == $this->getDefaultOutput()) { $this->sendOutputTo(storage_path('logs/schedule-'.sha1($this->mutexName()).'.log')); From 49d1f7fd20ff38f06298c0933a38e5fa60fb47a3 Mon Sep 17 00:00:00 2001 From: a-komarev Date: Tue, 11 Sep 2018 15:17:41 +0300 Subject: [PATCH 0345/2459] Call Pending artisan command immediately --- src/Illuminate/Foundation/Testing/PendingCommand.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index dd54e6f9780e..fdb33253ed24 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -104,6 +104,16 @@ public function assertExitCode($exitCode) return $this; } + /** + * Call the given command immediately. + * + * @return int + */ + public function callNow() + { + return $this->app[Kernel::class]->call($this->command, $this->parameters); + } + /** * Mock the application's console output. * @@ -168,7 +178,7 @@ public function __destruct() $this->mockConsoleOutput(); try { - $exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters); + $exitCode = $this->callNow(); } catch (NoMatchingExpectationException $e) { if ($e->getMethodName() == 'askQuestion') { $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked.'); From ac42a58f42dbbd25afa1eceb32db8c3334c04bfe Mon Sep 17 00:00:00 2001 From: a-komarev Date: Tue, 11 Sep 2018 15:57:11 +0300 Subject: [PATCH 0346/2459] Prevent command double calling --- .../Foundation/Testing/PendingCommand.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index fdb33253ed24..cc3a8181ef4b 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -47,6 +47,13 @@ class PendingCommand */ protected $expectedExitCode; + /** + * Determine if command was called. + * + * @var bool + */ + private $isCalled = false; + /** * Create a new pending console command run. * @@ -111,6 +118,8 @@ public function assertExitCode($exitCode) */ public function callNow() { + $this->isCalled = true; + return $this->app[Kernel::class]->call($this->command, $this->parameters); } @@ -175,6 +184,10 @@ private function createABufferedOutputMock() */ public function __destruct() { + if ($this->isCalled) { + return; + } + $this->mockConsoleOutput(); try { From 2a72a44256a8c04bbe78efe89db30e9d31e9d38d Mon Sep 17 00:00:00 2001 From: a-komarev Date: Tue, 11 Sep 2018 16:04:57 +0300 Subject: [PATCH 0347/2459] Add tests --- .../Console/ConsoleApplicationTest.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/Integration/Console/ConsoleApplicationTest.php b/tests/Integration/Console/ConsoleApplicationTest.php index b5424ed960ab..ddcba2e8c2e3 100644 --- a/tests/Integration/Console/ConsoleApplicationTest.php +++ b/tests/Integration/Console/ConsoleApplicationTest.php @@ -28,6 +28,28 @@ public function test_artisan_call_using_command_class() 'id' => 1, ])->assertExitCode(0); } + + public function test_artisan_call_now() + { + $outputWithoutMock = $this->artisan('foo:bar', [ + 'id' => 1, + ])->callNow(); + + $this->assertSame(0, $outputWithoutMock); + } + + public function test_artisan_with_mock_call_after_call_now() + { + $outputWithoutMock = $this->artisan('foo:bar', [ + 'id' => 1, + ])->callNow(); + $outputWithMock = $this->artisan('foo:bar', [ + 'id' => 1, + ]); + + $this->assertSame(0, $outputWithoutMock); + $outputWithMock->assertExitCode(0); + } } class FooCommandStub extends Command From d54ffa594b968b6c9a7cf716f5c73758a7d36824 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 11 Sep 2018 08:29:14 -0500 Subject: [PATCH 0348/2459] formatting --- .../Foundation/Testing/PendingCommand.php | 64 +++++++++++-------- .../Console/ConsoleApplicationTest.php | 17 ++--- 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index cc3a8181ef4b..afed6072c626 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -48,11 +48,11 @@ class PendingCommand protected $expectedExitCode; /** - * Determine if command was called. + * Determine if command has executed. * * @var bool */ - private $isCalled = false; + protected $hasExecuted = false; /** * Create a new pending console command run. @@ -112,15 +112,46 @@ public function assertExitCode($exitCode) } /** - * Call the given command immediately. + * Execute the command. * * @return int */ - public function callNow() + public function execute() { - $this->isCalled = true; + return $this->run(); + } + + /** + * Execute the command. + * + * @return int + */ + public function run() + { + if ($this->hasExecuted) { + return; + } + + $this->hasExecuted = true; + + $this->mockConsoleOutput(); + + try { + $exitCode = $this->app[Kernel::class]->call($this->command, $this->parameters); + } catch (NoMatchingExpectationException $e) { + if ($e->getMethodName() == 'askQuestion') { + $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked.'); + } + } + + if ($this->expectedExitCode != null) { + $this->test->assertTrue( + $exitCode == $this->expectedExitCode, + "Expected status code {$this->expectedExitCode} but received {$exitCode}." + ); + } - return $this->app[Kernel::class]->call($this->command, $this->parameters); + return $exitCode; } /** @@ -184,25 +215,6 @@ private function createABufferedOutputMock() */ public function __destruct() { - if ($this->isCalled) { - return; - } - - $this->mockConsoleOutput(); - - try { - $exitCode = $this->callNow(); - } catch (NoMatchingExpectationException $e) { - if ($e->getMethodName() == 'askQuestion') { - $this->test->fail('Unexpected question "'.$e->getActualArguments()[0]->getQuestion().'" was asked.'); - } - } - - if ($this->expectedExitCode != null) { - $this->test->assertTrue( - $exitCode == $this->expectedExitCode, - "Expected status code {$this->expectedExitCode} but received {$exitCode}." - ); - } + $this->run(); } } diff --git a/tests/Integration/Console/ConsoleApplicationTest.php b/tests/Integration/Console/ConsoleApplicationTest.php index ddcba2e8c2e3..5c3b68cbbd8d 100644 --- a/tests/Integration/Console/ConsoleApplicationTest.php +++ b/tests/Integration/Console/ConsoleApplicationTest.php @@ -31,24 +31,25 @@ public function test_artisan_call_using_command_class() public function test_artisan_call_now() { - $outputWithoutMock = $this->artisan('foo:bar', [ + $exitCode = $this->artisan('foo:bar', [ 'id' => 1, - ])->callNow(); + ])->run(); - $this->assertSame(0, $outputWithoutMock); + $this->assertSame(0, $exitCode); } public function test_artisan_with_mock_call_after_call_now() { - $outputWithoutMock = $this->artisan('foo:bar', [ + $exitCode = $this->artisan('foo:bar', [ 'id' => 1, - ])->callNow(); - $outputWithMock = $this->artisan('foo:bar', [ + ])->run(); + + $mock = $this->artisan('foo:bar', [ 'id' => 1, ]); - $this->assertSame(0, $outputWithoutMock); - $outputWithMock->assertExitCode(0); + $this->assertSame(0, $exitCode); + $mock->assertExitCode(0); } } From e5216cd15ee8b947ec2ada827f8d1a1d45f71543 Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Tue, 11 Sep 2018 10:31:51 -0300 Subject: [PATCH 0349/2459] Do not pass the guard instance to the authentication events (#25568) --- src/Illuminate/Auth/Events/Attempting.php | 6 +-- src/Illuminate/Auth/Events/Authenticated.php | 6 +-- src/Illuminate/Auth/Events/Failed.php | 6 +-- src/Illuminate/Auth/Events/Login.php | 6 +-- src/Illuminate/Auth/Events/Logout.php | 6 +-- src/Illuminate/Auth/SessionGuard.php | 10 ++-- tests/Integration/Auth/AuthenticationTest.php | 51 +++++++++++++++++-- 7 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/Illuminate/Auth/Events/Attempting.php b/src/Illuminate/Auth/Events/Attempting.php index c7c8437db964..3f911bac58e8 100644 --- a/src/Illuminate/Auth/Events/Attempting.php +++ b/src/Illuminate/Auth/Events/Attempting.php @@ -5,9 +5,9 @@ class Attempting { /** - * The authentication guard implementation. + * The authentication guard name. * - * @var \Illuminate\Contracts\Auth\StatefulGuard + * @var string */ public $guard; @@ -28,7 +28,7 @@ class Attempting /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\StatefulGuard $guard + * @param string $guard * @param array $credentials * @param bool $remember * @return void diff --git a/src/Illuminate/Auth/Events/Authenticated.php b/src/Illuminate/Auth/Events/Authenticated.php index a674ec8fcd6d..faefcbecba3a 100644 --- a/src/Illuminate/Auth/Events/Authenticated.php +++ b/src/Illuminate/Auth/Events/Authenticated.php @@ -9,9 +9,9 @@ class Authenticated use SerializesModels; /** - * The authentication guard implementation. + * The authentication guard name. * - * @var \Illuminate\Contracts\Auth\StatefulGuard + * @var string */ public $guard; @@ -25,7 +25,7 @@ class Authenticated /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\StatefulGuard $guard + * @param string $guard * @param \Illuminate\Contracts\Auth\Authenticatable $user * @return void */ diff --git a/src/Illuminate/Auth/Events/Failed.php b/src/Illuminate/Auth/Events/Failed.php index 8341d4691b44..34f812487027 100644 --- a/src/Illuminate/Auth/Events/Failed.php +++ b/src/Illuminate/Auth/Events/Failed.php @@ -5,9 +5,9 @@ class Failed { /** - * The authentication guard implementation. + * The authentication guard name. * - * @var \Illuminate\Contracts\Auth\StatefulGuard + * @var string */ public $guard; @@ -28,7 +28,7 @@ class Failed /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\StatefulGuard $guard + * @param string $guard * @param \Illuminate\Contracts\Auth\Authenticatable|null $user * @param array $credentials * @return void diff --git a/src/Illuminate/Auth/Events/Login.php b/src/Illuminate/Auth/Events/Login.php index ab587f08d244..3005183a9bc2 100644 --- a/src/Illuminate/Auth/Events/Login.php +++ b/src/Illuminate/Auth/Events/Login.php @@ -9,9 +9,9 @@ class Login use SerializesModels; /** - * The authentication guard implementation. + * The authentication guard name. * - * @var \Illuminate\Contracts\Auth\StatefulGuard + * @var string */ public $guard; @@ -32,7 +32,7 @@ class Login /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\StatefulGuard $guard + * @param string $guard * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param bool $remember * @return void diff --git a/src/Illuminate/Auth/Events/Logout.php b/src/Illuminate/Auth/Events/Logout.php index 5e8f77ddee34..bc8c39400857 100644 --- a/src/Illuminate/Auth/Events/Logout.php +++ b/src/Illuminate/Auth/Events/Logout.php @@ -9,9 +9,9 @@ class Logout use SerializesModels; /** - * The authenticationg guard implementation. + * The authentication guard name. * - * @var \Illuminate\Contracts\Auth\StatefulGuard + * @var string */ public $guard; @@ -25,7 +25,7 @@ class Logout /** * Create a new event instance. * - * @param \Illuminate\Contracts\Auth\StatefulGuard $guard + * @param string $guard * @param \Illuminate\Contracts\Auth\Authenticatable $user * @return void */ diff --git a/src/Illuminate/Auth/SessionGuard.php b/src/Illuminate/Auth/SessionGuard.php index 5d22cfa828c8..d719cc5a2258 100644 --- a/src/Illuminate/Auth/SessionGuard.php +++ b/src/Illuminate/Auth/SessionGuard.php @@ -493,7 +493,7 @@ public function logout() } if (isset($this->events)) { - $this->events->dispatch(new Events\Logout($this, $user)); + $this->events->dispatch(new Events\Logout($this->name, $user)); } // Once we have fired the logout event we will clear the users out of memory @@ -580,7 +580,7 @@ protected function fireAttemptEvent(array $credentials, $remember = false) { if (isset($this->events)) { $this->events->dispatch(new Events\Attempting( - $this, $credentials, $remember + $this->name, $credentials, $remember )); } } @@ -596,7 +596,7 @@ protected function fireLoginEvent($user, $remember = false) { if (isset($this->events)) { $this->events->dispatch(new Events\Login( - $this, $user, $remember + $this->name, $user, $remember )); } } @@ -611,7 +611,7 @@ protected function fireAuthenticatedEvent($user) { if (isset($this->events)) { $this->events->dispatch(new Events\Authenticated( - $this, $user + $this->name, $user )); } } @@ -627,7 +627,7 @@ protected function fireFailedEvent($user, array $credentials) { if (isset($this->events)) { $this->events->dispatch(new Events\Failed( - $this, $user, $credentials + $this->name, $user, $credentials )); } } diff --git a/tests/Integration/Auth/AuthenticationTest.php b/tests/Integration/Auth/AuthenticationTest.php index d8cdb978ca19..00bb307206b7 100644 --- a/tests/Integration/Auth/AuthenticationTest.php +++ b/tests/Integration/Auth/AuthenticationTest.php @@ -114,7 +114,7 @@ public function basic_auth_fails_on_wrong_credentials() /** * @test */ - public function logging_in_via_attempt() + public function logging_in_fails_via_attempt() { Event::fake(); @@ -123,7 +123,27 @@ public function logging_in_via_attempt() ); $this->assertFalse($this->app['auth']->check()); $this->assertNull($this->app['auth']->user()); - Event::assertDispatched(\Illuminate\Auth\Events\Failed::class); + Event::assertDispatched(\Illuminate\Auth\Events\Attempting::class, function ($event) { + $this->assertEquals('web', $event->guard); + $this->assertEquals(['email' => 'wrong', 'password' => 'password'], $event->credentials); + + return true; + }); + Event::assertDispatched(\Illuminate\Auth\Events\Failed::class, function ($event) { + $this->assertEquals('web', $event->guard); + $this->assertEquals(['email' => 'wrong', 'password' => 'password'], $event->credentials); + $this->assertNull($event->user); + + return true; + }); + } + + /** + * @test + */ + public function logging_in_succeeds_via_attempt() + { + Event::fake(); $this->assertTrue( $this->app['auth']->attempt(['email' => 'email', 'password' => 'password']) @@ -131,8 +151,24 @@ public function logging_in_via_attempt() $this->assertInstanceOf(AuthenticationTestUser::class, $this->app['auth']->user()); $this->assertTrue($this->app['auth']->check()); - Event::assertDispatched(\Illuminate\Auth\Events\Login::class); - Event::assertDispatched(\Illuminate\Auth\Events\Authenticated::class); + Event::assertDispatched(\Illuminate\Auth\Events\Attempting::class, function ($event) { + $this->assertEquals('web', $event->guard); + $this->assertEquals(['email' => 'email', 'password' => 'password'], $event->credentials); + + return true; + }); + Event::assertDispatched(\Illuminate\Auth\Events\Login::class, function ($event) { + $this->assertEquals('web', $event->guard); + $this->assertEquals(1, $event->user->id); + + return true; + }); + Event::assertDispatched(\Illuminate\Auth\Events\Authenticated::class, function ($event) { + $this->assertEquals('web', $event->guard); + $this->assertEquals(1, $event->user->id); + + return true; + }); } /** @@ -158,7 +194,12 @@ public function test_logging_out() $this->app['auth']->logout(); $this->assertNull($this->app['auth']->user()); - Event::assertDispatched(\Illuminate\Auth\Events\Logout::class); + Event::assertDispatched(\Illuminate\Auth\Events\Logout::class, function ($event) { + $this->assertEquals('web', $event->guard); + $this->assertEquals(1, $event->user->id); + + return true; + }); } /** From ce7e1f5c3708fd4eb2f5382baf5e709dff68a554 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 11 Sep 2018 08:32:44 -0500 Subject: [PATCH 0350/2459] foramtting --- src/Illuminate/Console/Scheduling/Event.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 15bc9d273fec..afa62e69537d 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -411,11 +411,11 @@ public function emailWrittenOutputTo($addresses) } /** - * @deprecated please use ensureOutputIsBeingCaptured - * * Ensure that output is being captured for email. * * @return void + * + * @deprecated See ensureOutputIsBeingCaptured. */ protected function ensureOutputIsBeingCapturedForEmail() { From d2dc1f34a8a926392d3733d7e7cdf59968a2e9b5 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 11 Sep 2018 16:33:15 +0300 Subject: [PATCH 0351/2459] [5.7] Add Unit test for `Auth/Access/Gate.php:define` when InvalidArgumentException caused; (#25564) - added unit test for `Auth/Access/Gate.php:define` when InvalidArgumentException caused, since we did not have a test for this case; --- tests/Auth/AuthAccessGateTest.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index b2ba324a52a0..db9640817b68 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -453,6 +453,30 @@ public function test_for_user_method_attaches_a_new_user_to_a_new_gate_instance( $this->assertTrue($gate->forUser((object) ['id' => 2])->check('foo')); } + /** + * @dataProvider notCallableDataProvider + * @expectedException \InvalidArgumentException + */ + public function test_define_second_parametter_should_be_string_or_callable($callback) + { + $gate = $this->getBasicGate(); + + $gate->define('foo', $callback); + } + + /** + * @return array + */ + public function notCallableDataProvider() + { + return [ + [1], + [new \stdClass()], + [[]], + [1.1], + ]; + } + /** * @expectedException \Illuminate\Auth\Access\AuthorizationException * @expectedExceptionMessage You are not an admin. From 51aa60b5c67745af8247cfcf98b7b8b48fbe8bd7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 11 Sep 2018 08:42:32 -0500 Subject: [PATCH 0352/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 13cd8a70a8f1..733e4b9859e7 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.7.2'; + const VERSION = '5.7.3'; /** * The base path for the Laravel installation. From df72d41d0305a01644e7adaa16aacd6a318ebb35 Mon Sep 17 00:00:00 2001 From: Anton Komarev <1849174+antonkomarev@users.noreply.github.com> Date: Tue, 11 Sep 2018 18:06:50 +0300 Subject: [PATCH 0353/2459] Run method should return only integer (#25577) --- src/Illuminate/Foundation/Testing/PendingCommand.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index afed6072c626..682ab394f47e 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -128,10 +128,6 @@ public function execute() */ public function run() { - if ($this->hasExecuted) { - return; - } - $this->hasExecuted = true; $this->mockConsoleOutput(); @@ -215,6 +211,10 @@ private function createABufferedOutputMock() */ public function __destruct() { + if ($this->hasExecuted) { + return; + } + $this->run(); } } From 8a9aa85f2732f08aaf6e6fe32812d9887fa84111 Mon Sep 17 00:00:00 2001 From: Mohammad AlTawil Date: Tue, 11 Sep 2018 20:49:20 +0300 Subject: [PATCH 0354/2459] [5.7] Get always true when doing a delete cache query (#25579) * Get true when a delete query returns >= 0 Based on [this commit](https://github.com/laravel/framework/commit/ad670c8423a5fdfc929644f63db1b7ca39a8ba59), the command `php artisan cache:clear` will always fail when using a database cache driver and cache table is empty. * Delete the cache table rows first then return true * Use truncate instead of delete * Revert to delete because the Travis test get fail --- src/Illuminate/Cache/DatabaseStore.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/DatabaseStore.php b/src/Illuminate/Cache/DatabaseStore.php index dc1241c805ee..8a68c507347d 100755 --- a/src/Illuminate/Cache/DatabaseStore.php +++ b/src/Illuminate/Cache/DatabaseStore.php @@ -223,7 +223,9 @@ public function forget($key) */ public function flush() { - return (bool) $this->table()->delete(); + $this->table()->delete(); + + return true; } /** From d5f3e809890c5450c1cd4ef4d80ebbd7d16e17f3 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 11 Sep 2018 21:25:11 +0300 Subject: [PATCH 0355/2459] delete `ensureOutputIsBeingCapturedForEmail` method. --- src/Illuminate/Console/Scheduling/Event.php | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index afa62e69537d..0d9c11be171f 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -388,7 +388,7 @@ public function appendOutputTo($location) */ public function emailOutputTo($addresses, $onlyIfOutputExists = false) { - $this->ensureOutputIsBeingCapturedForEmail(); + $this->ensureOutputIsBeingCaptured(); $addresses = Arr::wrap($addresses); @@ -410,18 +410,6 @@ public function emailWrittenOutputTo($addresses) return $this->emailOutputTo($addresses, true); } - /** - * Ensure that output is being captured for email. - * - * @return void - * - * @deprecated See ensureOutputIsBeingCaptured. - */ - protected function ensureOutputIsBeingCapturedForEmail() - { - $this->ensureOutputIsBeingCaptured(); - } - /** * Ensure that the command output is being captured. * From ef681e23923540ddc9021af8b1e8c075faebaace Mon Sep 17 00:00:00 2001 From: KyleKatarn Date: Wed, 12 Sep 2018 17:19:22 +0200 Subject: [PATCH 0356/2459] Handle Carbon 2 tests --- tests/Support/DateFacadeTest.php | 2 +- tests/Support/SupportCarbonTest.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Support/DateFacadeTest.php b/tests/Support/DateFacadeTest.php index 70566cb19c50..f602ad992437 100644 --- a/tests/Support/DateFacadeTest.php +++ b/tests/Support/DateFacadeTest.php @@ -78,7 +78,7 @@ public function testCarbonImmutable() 'locale' => 'fr', ])); $this->assertSame('fr', Date::now()->locale); - Date::swap(null); + Date::swap(Carbon::class); $this->assertSame('en', Date::now()->locale); include_once __DIR__.'/fixtures/CustomDateClass.php'; Date::swap(\CustomDateClass::class); diff --git a/tests/Support/SupportCarbonTest.php b/tests/Support/SupportCarbonTest.php index d37420424e9d..d32e065fd0e7 100644 --- a/tests/Support/SupportCarbonTest.php +++ b/tests/Support/SupportCarbonTest.php @@ -4,6 +4,7 @@ use DateTime; use DateTimeInterface; +use Carbon\CarbonImmutable; use Illuminate\Support\Carbon; use PHPUnit\Framework\TestCase; use Carbon\Carbon as BaseCarbon; @@ -87,7 +88,7 @@ public function testCarbonAllowsCustomSerializer() public function testCarbonCanSerializeToJson() { - $this->assertSame([ + $this->assertSame(class_exists(CarbonImmutable::class) ? '2017-06-27T13:14:15.000000Z' : [ 'date' => '2017-06-27 13:14:15.000000', 'timezone_type' => 3, 'timezone' => 'UTC', From 94f0c26186b3df2f34ac71767a75a0cb100bc823 Mon Sep 17 00:00:00 2001 From: MannikJ Date: Wed, 12 Sep 2018 19:09:11 +0200 Subject: [PATCH 0357/2459] Fix little typo in test function name (#25595) --- tests/Database/DatabaseEloquentBuilderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 818f9be491e0..1aff7ddcad58 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -362,7 +362,7 @@ public function testPluckReturnsTheDateAttributesOfAModel() $this->assertEquals(['date_2010-01-01 00:00:00', 'date_2011-01-01 00:00:00'], $builder->pluck('created_at')->all()); } - public function testPluckWithoutModelGetterJustReturnTheAttributesFoundInDatabase() + public function testPluckWithoutModelGetterJustReturnsTheAttributesFoundInDatabase() { $builder = $this->getBuilder(); $builder->getQuery()->shouldReceive('pluck')->with('name', '')->andReturn(new BaseCollection(['bar', 'baz'])); From a396a4c168f2a6f1117451d8803e562a9700c78a Mon Sep 17 00:00:00 2001 From: JeroenOnline Date: Wed, 12 Sep 2018 19:13:11 +0200 Subject: [PATCH 0358/2459] [5.7] Fix app stub when register route option is set to false (#25582) * Fix app stub when register route option is set to false * Update app.stub --- src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub b/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub index 943ad0bad462..dc245d980572 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub @@ -44,7 +44,9 @@ {{ __('Login') }} @else
  • 9Ejk8jI>z+{ zQbyWH(FA$u3Dj_%$psCEF338%h7ic?pETRU;|&G03YA#+hV=jJP66A!j`)3fb|p!@NeG1&r^{ za4Y2V#|0RhNdqZ zEP4_|`n#wy5D99kKAY!A$qSKP9;#k=Od#^KEaCJ(u%)4Onel<#;*<#;g zy#Kfue1eo1(# zfqlTSb$ZFsj2FL0o#w`GbI<|DRzxEHcl`E9re_NP33}$dn2w&Qo!s=?`KZt{{lX0N z1Ztk7EIs~>HeQm1-Zw9GWMt5Lm8Pk{MUxl3jXX4MengxV6-Q?^Guc_KI5#x}Ud5gD z)78ogz|Co1?~v#pvWg#l9ac;nqy0d2Wa$%cDOkrmR&3X+c}Rfj&{qpLxd*Z+1+!hTT_?GId>B+orT zJ2PSJbJgk+DD24;`Pr~++V7Iw{!=s-r~TpS+7HxhN+tiYBp!aaD2azN(Ff$eZBAPG zZ}Q}S96}=hlckd$`+ZHHapcb-kOcSX`pm($W_szGi(l2~GrL^cG&$oSedhc2CIT~m z)Y?1`XW|z^jcVYzQ0Qh|BJ$`nP?M!U`|83Zd9;P`K_2mE(#d1xFK&4(o+k2m^JIrk zgU6?F2L5c(Iscyk|4-2gOb?3R|s) z>4f!!=+7eLzWaobxxFEhhVqZB$1^9pNHXDm$O9sqV_hV9!~Fq2yY<%uBmvJmT{sJC zoc(yOoH^2U#$a1N)cxFy7$RO=_CL90W<@_Xd+zQhG zE>4`CP8|oebLR(sPy<{XPEs1o53=%Kubr1f&juQY-9y^PpRBCf=U@ZG2BC=93iuZCFG3 zN0&ZHdbk20hm7){a%7}KmNm>BE$bmIGu<>(Y|6GVaE6SC9n%^=6TSO%s2P(`Wj-&X{~CPoLSV(7DIhz?Mm1aDobu zLB5LK6kGmTePhizNz8o)Y=gN8Gt zNp7{TuN5-3ot4fWvd%X?>zyQ$MF2TOGGazLkzA$R`n~|PK;ONOc64XuzofEGoewHA zjh_NFS>m&GGQG_-y~`d?NAHV2xapmFx6s>S0}p!g#k=&GN?C2{$=A#End^>ncr^ID z2xoxLo4YlP&p=I<G|?g}nak4GBv?@yndMDrNf321JgmgdWaJj<-|*#BB}Ec#FF-?PT^(aE%I1`I*V z?CIIbuPP?;8zt*pJovaCXMpF*Gqb^SmihkZo=LJhQ`5Wc(RB14fn_O9MS9f)p*J^~ z-q&yj^nTLi|B&9#dL+?1872Vv_DD9jh_)_Qe^%kL8V ziHFkLPm1*k7#)cHGmkyUMMI%Z`(6j!A*aDE8oYVz1D@Qd7id7{$$MF*-1(A`moo-A z?$p$o=K-XCx;h@zr(2)Up!}}to+Q6rfD&kb`JuG(^Uz)!5&6wNBfb0z^mqUQ8^l>! z{Be&5BpMV!j$fVS&>~5dUk%Z;9P6T`7*n7jJoyN5VLt1g|GNEm6VO8WwY2bNXZ=5p zmowkmXY8zhInOZdr}QyH>l^ceBYmUJIUQ0c;T32Qo(vm_Dtc9g%V~>87LpGjN2a}D|@i?3D z&h=fB#JK_B0__jqpH7@-dBi!qM#MR(6XsrEcKodImR;MW_OmD8&iJ|XmR&kPJwJK9Wx{-1*5ifwAxA#OW$po^g|1$m z>d41iTRCE#TRv0n5c$Mhyh155|E14tKEjcY9WX|D<5M^9d<*AtlP6p*NhbDQ zAl+3^ycT`cKOrH|(|({PL;ls&)wIF+sc0H<_;s=)2aR*!FJ$od`RpY8EpDUnXDwnv z$dNgZIb%gmPaNcE)7Zg1ID`D_nUf)>wCh9PNwQbUs5Hr7yPfVR)G%@jkPk)*lNe#j z!Ua8jBv-T)x`!sTla)Z?B133=425l0@o+grfs6g12JO2=smQN<_JX#U@6x@v;uz~JxY*9uTlU=XT8Pz4-5^^-RDrqxa|c9#Ue;!1KZ*ECm~Z3# z=-u5s4~co@sYcCEd&aI9bl3$iKd86n^OER)#_y*8VcBzcAnhm9KLy41%=DL`J5Xok zzG%y$Ub{?^TT1DPXv(;SrEjK$9OPCxj}@u`1)4W-&y_9^oKA+-3GKk!U5@;c`1@o} zH-GQSUKae#LybQ(f9E802ZG^6bn~JWKY0)w3WvgVfm(tE%sde!H>FND>hiYW<{^h0 ztj|rv+Yk>w1G44kI~2j4j+`Dm{$?208-oEWwvtA$q509)#6!Y`@FThtjfw7p>Pv8j zD+#?OXy{M>X>Mt;uU z!>ylgvX_N^en{~yb{&sk~Y zT};Z;+4H3y`g>mj5W(%R>IEP=3!$?>~%R_hE*dph}8gqmKm-4d-{wcDniT$zB%xG|7seUJ2#~ z8UZi;JdS0*N!e;V9XE3e!ObIEEsVVMRL12ObT|)5WvNf4SvfEqhtW|92F@Gt-|j z9=thN<0UB`%sUD+r-}#l+uZbiDSKJa+chhC|DiuR<(4%5=;v18qG5kD~6s@`;qlZ!|>4mIW|r_t@+>@{m5C*vCWv&aLDo3;O4wHlLaP-NJvPp=o^2 zz#|*LfBhD>{J)gFEa?9oMfA+{@0R?p9G+7CPaolyzqg)nz1P2`ex5B-=+yoSB*#|6 zZq_BcVm|Wje$FxG^WSSUh&rMlRiPZ!_I0%L1Zj?_k+>nQC`w_76CNzHf8}IrE@=YKmy`sJo7k9xc4wnR~?k9!S zyM}gUGiBk(aJ=yr2(q#Wj|jCp zLuGcwA`SL|L`wNlydvhi?m?$oJy0v^pns(<*Z%yre$z)C8;_rj$r80s5T)B6@ChxQ zpCsU;H@oElrO4Q)C`0ijIGyaZXOCq(c@i2YkppfU8@p}|_PJX!9-m7;A z4uarf!h>WFcf#mEh>jCw+GcJsuLcl#0DieI%;775@X~IHE0KRC>hSR90R{ijb23QGJsFcDTQ4#i-x#`)xQ+6XzQ`Q?hPjyeg;TAi!XW>u_lR#qhH_CfWZUm;8->oB zt{`IbuB_M_@*R@E#dYDzC7Wm!n`jlAR4b`R-U#r#(dtji#CzK3I=wXc^bb-!0$lE2P@SO*- z{O>yA^>!WJ2~>YdYWU?}e&BQtb|9XCXev?{hV~hO7Vrv~BLHATB5?$-yFo+q^mkbt zK}?cDIawJARO7rz!#O|Lbspi}yqDfN-^V&1ZMZRBkT)*Mu+1TQ?-kTa31Hs za5Ui@$tUyhMi;f_%lug8dgFjie76+5q3XOBZi2c*A9zVt9UE~7St=ECFk*3SUL_X4 z&)`<&mHK`kVu~;yHqnf>; z4N2TaArOX8C}ECT5f|B&E>a+Arl=5)MdzjvQ^ssVPe?KHm4Q^yU>|a+_tq0E^?sR0 z^{V%pgWvt(4P5-js#=xW{vn|Kg9se{AxLb&Kgcii9pXN@=>59w4&a(>cRP?e49i6a zwo--ei{OQgPcGp_#nwfeyJ`u-yeZXK?j5HwjKK3^U%#P97zC#U+)%&al~l-lUz%qr zqsqJhlR^BCL)qF;rZAKsP`nBEB)g@Ul=*0lxxY0*_`oZFs(%q?-$=y!YN?3xQr#GB zvkr~AOyXtNC3N__g#EfMxyQPMJ#}JF5Q2CR5Q;Q{F2&3j0~wTQA_PngC1``8ke8HE ztVKi)oJxzchU!mIrIX$Ki8`3z9fU{~o+F94y$pHw(6dMoQ@bj>5ooVyi|s@4O0zF2 z4hcv0MmQ@KiVYCPEhaupwhpDL!_G9#)~`at75`y-jq8`f!E}6x%G8;W6?R*QgnWH# zt#sI&roL4Z0G0ehfnpT~2Ws6s$%sj9{Ud0&^K_kTl+y%;!wMmE-=21p_6sKF1yZ*+ zLAM8;*706%RJvJ;b~on4{qRI;(t$9V59uUa|2+O;80&XIY8#%Pf4~58R@h1V+bLoK znS0F_xNKkY7pR$*@``AS8|C~9eslg4(iNG+U3;XFdz~UAh{rKAb^iGfFN5@hB$a>) z>+_G^CYfd)MjY+Q#G}pib+9~w&gLA5glPhDwd%uXb!Mp7x#&in)HEaprZx)H~@Ec>0!|KQV6PYn4wlELOJnCi!+YT%d|A)0rmRHc~ zPqjfeT4Y>p?g;5Rw)=`{*VA60<_BmWZI)372y*ggWUKPz!1TM+>zG~1JXaW6L-zgE zOWLppR^fyRqacXGCk~xNmH6hh+=aZ3U+Igre|0ctAni;%Pb&FrxfczBnF=w)Enq?P zt-F+yp(s8ch*ROfE1?sv!RZnw(gE-vV=ps?WO=DYOxwf%F2~ zLxE-?-w{V6n{wBUA-ORmH}b8OQQqj>^N|#{*_p4?2nyGfnn0ao;&!au@ zoTTYlSNQLvleAZlcJGTI^} zubG>Q-`blz{9bFj0P-7n>wjgqx!s=4@LT(U;e*`_C-6I8^9#o?h`xk>;E-6x4piOA zbFtjMGdQ>aQ&*nkP64913$K^AzvGKstQ<$6?cCP)^PT(qnw&nCd--p&H+zFOK9}PtGts{XY8LYz zZ@m=!VJOBg*9WRlktB<^PIHruzTjeU0viR~P}f#!O5{F@;@%2awy*9wz74oSL{?-~ z_Ha|Nb$3WMKyncHE0iapAZaj(i~KyNK0;bmkJm=~KAeMLPBiyT{(yS}Zu?gC`(EJo zutaX%@hn!=Dva~G{&Rj~&_8aY9(~O*F2ejqeOEk{YE1Q50QW#TmXYSK|AVs$sF7@g zzn~YJ29g8S_hS!LW8cDo%;oyPDyN7q;!xuvUb&>RFc*$C;wa%zjt4ld;6FMc@mJ#( zlQxK?${B3dZPQkR7ERR!CJpE$4b}d@`g3i3W;R4mZ-_%B`rro1sBVNRm^HI#k{NW~jhIU^C^HA_O;Z22i9=tXc> zhYt9UIuSa?EuM~D;LiCFfbtV}l0ZltaYD$uScq;p`7j(jfVqJe4s?Z?$Lwp&oLWfx zLnLkd&h60dOy9y9HFpn4Mok^au~6fo&_>Pdwi-2ka5qr1AH{?QOY-#e6!uEQsR&+1 z;^KH?qR@kv0XVGh12rY_)fy@5AJK#BQUa^YVC3ns7Dh0vq2T@M;+)g~Iq3=a^wq^^ zRQ2)!AR8Qjc<`}F2|1V>~3lWKe#izIPsX@ImNm5}NEoCA#o&=C5X|vxUJ& zC{Qig3N)*s4L{uy(_pq{!Hk_8)MMegrCBJ9P!i3$uUTSWV>FAAQZJWMLt3e?^-oqR zacwD8*uppJaR{XpPH$4AtML2^swgl|Udw-ksOQ?4FZ8h152lTvWTT(G$2j@{4A|H! zf9vVzL<7EihFd?MQ$KU|fPSvUR?_$-hD?&Uk@@hXiJvJyT829C-34hK zxh0OiVaolR89x#_7;SZ6zA#O~G-yq!ewq+uO7`fFI=2P_n2KIb&(~qa&>QT4LV*B9 zdC}aVR|<*>OhCbx+pA>q!$Ofre%xXz#D$`XNXaychT{bP5k=l>5f2Fx^k2&Uqb+)f z1D4Nwa4P(+?#@(rJ_C?g52&Ax=H#XH7A@=|seRnQ;2w^!zVe4rSu}TM8Tdh95)Na1 z{oo5(dl!g&MLeJ0$F_v`ThqDdE9=)=eW9!5zGA-C59rud$I}qeQv4pl?U?Vk+bz4W zz8OQ)cxZcS(-=D49osmurY7aUG&VL^|2rDFBwWQHh%<&is`c~Wq(5V|cqSgNT%5N^ zorR|A7t_QX|0nYettqO?jd0k5IBbzWzJhMdu+fSY-no$nuE3&|g3f$O^ATiMMaWqz zKQ(Fj`$uZ$4AFLNRT#}Z?g}EQ1V{>0Kh8G9X+^@wS^_u)MO5H>7X2RXlB53f9N3mM z4pH>ZH6uAg18Rg6AxK)~;u3z9;lY=*8!9F_p%d69K8kRgC2o!v(6wI`{iSI%4uBj< zBJY1xWF5=h@DTlm0i;@S0z%brD^zJJnfJen<23xjcu$;EfBn6ASNvtmVQF1547&QtH zbO>$a7%9OZ=%SL}u2`~=?I4v$lVNP3HS3%zCI@GNmt;J|H6A4Fln@UkY<(c!=3h8^ z1f+b~JsKM7yTe@!ARdJLhoF;aZl}vcrES1$@d&C(rc%m>_Ld%0Ap7xG)UsVo+;`r6=jpS}{cPtUGOjHOF4%F(6kK1l!f@26lOnjmo zy2Hih(YIHB%bp?AiVMhHaTRv9A9xEiK!nf_Luh%ThZcCiM6RKHb&9Ie>!)dNb$}Q;1?h-T*P>_Y*O724`=cX~bmG#U-Hvak8Mn65BCTGl^}u zG(xfMbDZumRR1j5&`p4Nh}?`GY>}&zb^r)}ImuBX9)_h_F9~T;PH0=8>d0!`7%g`Q znsSGlAyJ@@0@4F&_15;y3F{?2_A~4%*bZ*u(}}B57c7lI07ty+`5 z0*F({EAB;jlxk@>kGzNbFT+)+Q{}dptdUSkLd(ci2wa5`f*~7yD?!k-Pn-XRb246>}3L7w`wvGRmiv@{v@2IC@I388{UUB-OJ7-#h{ZvJVwFi;T)v(lW@;(NR6I zvWxBTS`@`0II0fo+fLU$i6_c=Fi+L2F;O-!pJL>2JmjxhHWbSMvFgWiKDFwmDSCEA zmyih_?JKcSA~eT*#}8v%!3n#0_(k92w~#al6<3Pq3uCwmR1iWqRKU>14OTXD)Sc)5 zDJ&LJrUJ-fZ5}b-heMLW)`-oi!&aYZ^e(mP)yZz6)%AZuBNdiL67VW3p}h6dsBhC$ zD_u4M^Q-nufgnENP(l$uJ4VcbYxUlP`f@)x78t{F2wWg#AVZXz zX|9k4{X7nqQ8B;<;EhTGuNQMG;4ye;_fmu5j#GuO*NvjE8Ac(|u$ji4e2XKv5YPHm z=r^NviWzNNfxX~9cW%W`-mCUoA++USIze7fX#9d!MoZuqbuBbJrS8hIwE&SX$n_FTYPsR z&(HPaI43HZXND7(Jg)yh%gL{{+^Owl5-)?+LbB|!7eS0q!csVp5cFV4XxLQ;jfp~*LJH`;@!C@-&=YSo^eYirfkTFM2D#rdx}XZAuXQ#5qeWY{(uHgw_tC3Y>z&NT?k(dvRLqhF7d~=W2*UX9|#sp z)WKfV3Cat&q4vB=&ykN<*`3VSv0KM zxJt{|j|5~YKUxK2;U$%v=X{b4&SQff`U5qi8>3^d{bH0co>bx=M;x_!Q?{p>Z3ki* z)?oqr`*;vpeiB}sO z&>x5jA(-V&Fge|Q%{@_ZiLgOk50r8F@4P+QBd-d7IW-YIfcac`IC?20Je0-KVX$_Y zZGlI2ITw5vm#u`vH>oSH6p$AIvq>Pi*Br%3Op;_e*iK^3TRY@!;d1dkk%fzfG{h=RRCn zoZ`xu@6e;%tu`^OUXy&(au^B|uP}&{~M(K8j)9nl=lr2}l?ddqnf83s>H^GUi6|rks zkPeLlI;Kd3)nZkWI{?8Us&$}lz#34*d~KVUtP6=xNW1B}AH9hS^EBLF4sCVmO})T6 z(UkuH(t_J?Hg&#qaZjBuiGwbtdBTY^dd2eBRkB+o82y`BmVib|c@4~vne=PtNG5$c z4~1p?>5@h)_rW`vLF;M~4Uz(>RRiwQhUYv?L1J|aOh8{gRQFbjCun27&p$&Uk%IdQ zt5*#sm>Oxv~;>N4_HW zGZ%1HA$=>4evsB}W3=~uoMN`r%s?gzwo~hke8R1@DxP>q2Y!@4)#>Irm9ls8u9s* zi+M%t5)we4Wtx)@S0 zek!g|?KeVL>mfD=tWpo;AT~ihx*=n_NJnziaFZP(?tmf+0G}mZiNO_&JA?}W1DRst z$kpKm*Mfo`B31kW#`({;L4|-F4&oQMwr~P8|c?K3?Mt!q; zX42=Kydqhj<@&H&pO=mF>NB^*(dP?qTKZhlKa)NO6r|JV*>a{KeIDz*Li9P{$A6|z zm_v@5W#+m6f7Iv8@l^Uuk*{xjM(dI|Nt>@*8?>l z5Uq*+p!97W+SIOnb-REo68UKE6=4Z2BZ+$$m!EULXX6;k+ni9qoV+BPnD33{wiUu* zh~jo*x&6;^a>GYoCsLRjK73_5q;RZkQdhq^*`$3zEIoncnEvSr54Fz3Z>C*erXW|= z53K|w!M=~y{tpg|^)Mt0FiGF~YNsAhBJ`@Ge%7X0z^>q|^1oYUrZ-oMeM209>MCyH zd^j9IYWkb9G9ny;SJ+=uYKHYlE!Yt1;0VkY;5_DDqQ3pQQ+Rz5gesbI-iaQh6ljE7 zAZe9+U9U{ckkvN%m|Xf&EFXzDZpo z_@hRb2WgU-T%;g#**gAF zAmt(}Yz)^L`Swn&kv#57q;ypt4_crN6zg4v>13)GJ4Q0aq)3Lc>!EpPDBJBLW`wYU z5B)BeQL?)kA!5JI2>&>fin7Z=vW&^SF8xzEZ?8*lNf;)sOJDJ-#l(gR&BO*Hi-D~3 z>PirPZNN#5PH<#q3IM8t!2BsvZwSm^iQS+{cTmMsFO+)6(<_VvkT8O>ic2phb7Xo* zoz$v7M(Z@t6keg05>uiAZBnB0Q(tPQp%_{+NvL}a<5F?0dfd}wt-8mvuX9Q!Oh1|@ zJxby$n14u-iEv+O9j8RX@hLoM4TqpvjhbhxU8o81m_~#fr z*Q&-IdTP~gque4;Grj@*_p^rCw$DlMH!0&)_*E0H&TZ-fAL7;Xos;9$gE*EdUdA5F}yZ7t871lZ0HW zPEKeI6=8ZmZ6lF8TrD8*cx+_eiIfVVuj8Q2)BkO=Ye6*t750@X@(iwZ-vi z9vj}zI!?xl;+Nv2>iIPw_Jn0vj{f<)Me64};7TFa#*i}wp&ijG!<3OSm?~nFgb)WI z)>bYKE>i#f3R&i(w&m&#Z-2@4=o79o0}Awn7TFy{o=2#1qktRg){8Z}z@(<_hl@y? zo!?%|o>SDL12s>v9ZwDXJ&w`H7kXnRX@Vd8-&mL03KG;d^#x0958f&!cG6$BNZ zyo)dA_M-$?kkavKHO7bjgnktX|z*y~}I+RsHWw{QaU2V!S-+*7~O`%xz!KYZ>w2zv%4$K~w zz-%(V@>&y*{=je1Z4SSnp8QsP;~_hi-);d}eW&6KxH0g$a_EszQBkB$II)-jw4p8s zNJL!7VnVAG(iUYGFQG9^_7pX=(lQ+WZ}jC zCa^I06=5Mzy^&&t^dW8(Rp2kHWEnjeDi;72kFo9qJFrMZb6y^%_J-4is)Ot+Jpq zg`9SMbK~KTwC9Q>DebQ7Etv_`N}u6u#f_h(1-qJ5;~($-Qn9q82Y^X@H9uz$4-hCT|676zOs11*KvN zLBbfF&^MxS0ip`uq~ZAQ8f3ncF4)$v&+J&IV0n22qokK*-vc*luoC4>hH z{-uw~a`1)vC{}{|^ie#&rWaC%BO&znOOdo&2n!#CBUnuSr9M)GBbZ_f6`@e^{#I|{ z;LLjt{qw^YL`&`ZD|Yf8;oaVQPn~I>e1Pt&YB>ON2DV(eAU8eu3Do?d z^$Eiq1PegCEuv2ca-e2xlv*2QvH`;g5luvVSR2-dw^#-MIU!~t1UL&a@0?+c0;gW7 z%NP~t44WXK2w&`V@a~WYt_!{+&9;%pFI0v4n5f72gf8!7v561c6 zRIPf^bF1qAF#z(jCw3*_BgOpMgx|BMKWsfKvHs8-lC;B++VD}j`ol*Wk0IjG%r`-% zWuggeXzz%Payb(7je6NAuj*Hq>j8*)KKtTbA)_o;Ry=zGk!IJ?4;Q4l-tQ8V^LFtr zj!u&5=#j@Q)IWN;M*WMtOl*cPR**npC)ONVN~Xt{f{g;z0m7o*ti_eHS6ChHatD1m znVwlmpq&;Z2*Z=rC3I$$e6}Tm5;;bNh892!@LF)$9oiv{Z){^{X_VfZd zIjZG9ruS+y-ZqY7lauCZQ|c`euyJlcro9N9793)s@=~n zdkXHZJt0@u_H@~?9(&p^(Vk9|^R_*GM!FK`r8+!n+0(g~YI~Bef&vD}UL1Q0ik^F& z?RC(DKKAI{W*!g;Q}-pc>V9PUt^kjA5qLm`q^gp%QXZ|e35)TBh)A#OYSnq3W@=Rz z&%R?k4{Wjg^1&YCxx+dx*p9EG@w~MZiapjg9#8y6J!h$Y*tL@nw2j-yvIL)3pUdBv z`NdF69xf1tSLx>q%yuCm%I%o%x9v^sZkQ6h$=T%g7((!_6gAeKA*If4<@2T=w7 zb1t#Z6CS`n^XvrNdWLV#WYUU`%!CmTiG=@sD2+M@aW z<$S|$;=Mwkz+|Q3V$EbOn*oz`!VWek==YDJAV9Ig;GL)AZ3`{u7DjeXb*O+lW7!7I zz?t0k1mU+UfS`_h-@-G*E7R1rL1DH`=H;MO z8dI%0r;M(|nBKU>v`BeH$Smnpn+1ZJA-M%1d!~t@`VV6m3f4$B^3#&#)xC ziMNA1)}pl)zZuS>R?Sbp6_|kIMUyL_$AHrJ;8>a??Gat zpYLgPgePzg5c87fd!qS%o{N@Zyr!S;fd@HJ&Wp9#OMHDf)96EJUI$&E&1(zA$pBY{ z9~N@0$zysvu#rbls=^*(0eHG6FyU_A5%W#0(tOFy(kA?Kj(nY6kDMn=)&8nL{ne3+ zD6c-8H1>k=p|}ZUz}#f;h_@v`m0@;P!p>~r)vEn3({b3!+89{m9&&K?FZ9G{ul{Y& zs;0h|7}mqm8n`WC2c@;@oqq1-F#hrE>v+sH!+TpT$KQdiIQ78aOa>&mW-wmOc-(p+ zfU?FtXiCUu#pimTNd>267N-NPjdIxld!QDg$A)CBel@bc3*tda+7%SGPPT$VH&_tV zQ~e}*~JR>SVJttcEpghylrvncJV8=y#BV?SE<%;H2%m!TQKH5|5#epdI@nr?9P)Alo$ zV9N+QuQF=YBu_K7YMf`^0n8ecBNdqew>A1%XdNd`3*#%r^LFwyqJDY{09xt-Py&AT zW&V)x{FXJ50zW&Jtm7Yj?s&Z^+qKp*GH!C1vx73_Q6pX)8F2KlYZ}$bE-GvuV0=GZ!2Sy`|G7);}OerCCw}pvTHr#4rEI07aN$2%5KeejN(@d=@ z@$5Szo>_72ltS@7wuhzUYOUiGT2cH!F_?Wkji@(XhrxV~9D&6t{B!Ij))nvWmzVwg zMxz`%>=l0lP>zFEqX!W$SZH%X_iq zNP*L3dvjt1t{=H|M$T(noID+L7-a32l^?Jr-W3f z^`@^3hk^OIBM%}``9tNW#UT8IqwO!_Po!vksegRQUgN`iSK*-UiH{P4l+MNcjpk3$ zJr%O29W<&4rW={x^50nOg~AIkoaMhU*aJ|pA^^`9ay(bF7&kY ziYEHOBlk%2)Wes#j0tA}6KyQW1@(1&izZ(FKh%98dNUW6GilTpV!6iaIa?>)x*rG( zH(HAq2aR7C0^JA7TT@6jZ61=9@gfUvp#!$SEI43*tAp7~jSgcuTv3SF)Cn&xkL_e0 zg#Hiw(uJKeUW-W1$H{Ie(BOHH9pEtR+|S=IP6GkGa2it|{Kn8#JPaqTwHv}l5C=Np z8O&(zQTj5@TO7{I2I6cHEpWOtoA9PB@MJEcS#?0_DL$|MV{&VH;hDqiGcoN&ggl<{ zS!d*-8KBUi;EH*v2jrZ# zoOpBVG^fba8272KSsbUYv+pdE(@2%#H{zUn>=n3%jmYY?XV8Bg|G@Qn{S$I`C|6z> z94!gr4G$3Lfvw;afGE}$8tt#uUl@)o3@?a`*Z;y>+wSw>u;s3zrl#D>NPfoL!08K$8rPzs5e>SSye7^IQP)$ zx(1?VtaSkna|Lp_(_4l|2Vo&P%zl_p{MiNWpTrJLW;d7TyqVq0az5eF!C6r&X?Ux< zP8vq@G9jHWFVwb7yTy9=QkOv^@OkptGa^<)6{ex1Tn)j0@V$0Gu(WiQyCqnQr=^|a zt(J~AEy>DfLsF0}K-=($>j*d;7Mm;yM|AE9!nkBDDv##Ligr%qzMiw!O?cK2H^6=1 z0)7cEsP5__IYObeo_6ooEDm8Os1I1`MVGLBjq_U7u0)4iy<&?Lz`Ny;i*nwQ1O%-A z_S}K>-$-c~v~>%$>YIf9m7aYkT|Lg^XC?8Dp6Gjkb)5Dcj_;&kY~oXsbhD=m6`ThH z+z0o$4A4QOJRg`(eR{`3QQ!1F&Uyl@EyBa;Iw(T@vzeuDD4HbR?Jo+L9+Phmxv*O&4}HS7XQaX5q~ z1>VL{l3&Sc3T;i$aSf!{La-M+vW4g0&emc>i2%4TVkqioK98KQ=?^7h4nvr4}Ij3I8Z1B zVSD|`B=nJK{YpQrKS*&9D24vug?)LwEqgLmMZdc6f1J%xqt^-~x|htSD4 zm@p)TLL6joj0r|#z2hjyyj2|vV>r^rgwW$%CM4Q3D}=hQphYl2&OJcs8F3~6m5e4BwqBQ2aUaET9t--*Fg66YRqu`g`ZWR0g z^{RcJgQD+r+?q$oplc=lHicj;?_&x=g%(CCpJF^w@EQ%ZSA(79#nE=bE%H zt+}Ef+kjwXCDSMzGwJ+sJPvK@bUug;(Ov;Iuw!PV!!SU+lM>{ct7$9aO=?$E|1Je# z+UJ>@>@)YM7w15-&pMLTaU(&#%^QPTZ@h(Sb+yrkfV+?c5tQjprE)}VZ#%~YWFg&E zf?Pa?kRfgFoThWXDO739_tL#gRH4Sd{^OC~ZYHYGuTE5t+=r626V?6Mi}j9+J$cTX zsIDP+6HAc0##+SY8)6?9Pb|(u3mQ*ZsBTSmZ1iM=kvs`=ueW`&Fnq`ZMQKm!{=6@pZ;!;#ua5qPGuIWCML zns_XDau;nZCPhjmRm^{SE~-_Rd-iqGO7PD|A{akTEYvEM%rLoOar`$i&Lcgys#Q+{ zYXL9T=;1wh3)D>0@e@1`f|VeC%7`RHR1pYaYokOq@cx*uv;nBA-~UJRk&vdIkDTK3 zxZ}<2(EYx_p>p1S-{9+VKH-IL<>n;-epPdd23Zv^gNlG3G)H5>PB2Vmwe2X%vsYTq zc-o^pFdM?na#xsc2n%_ZhqMX{VMRr<3Jy&%c}S8>t(xh%wpLB?>^rsVjVtLc5FO&} zY==v0S|!H?Zaldanp1gCK!^MYwhqnmH$i_XpU3`lq!~ZFz0?&tF@89#iDVq|{*aK# zIQGFY_w(3rYx?~mn{@u7#Td)|c5iB42GhAqZq;$HKwZ{Cugny|gz0jOu)G<`7LxmNfQwsm}#R^1X0g5zT)}&f9BOX3F`5 zuSm}ruHy~f_uY@&H)?3ekqK{^N9wUmXRK8Ld@6 zBaLz51fGBP>}&r+EuFj^{)ewWa>mg|;t;7S5Ot}mABW=Z_F|Pf^yn{8^Gr&AqrD5{ zUkb@&A0>j8{JS^u$iFo^v7*HBJm-xP+eQ8f&g4kJG)=KXTkT91^D=MmlMgoMjIhVvs1k%EGFF^;R_ zABBXUv?ZKiFEZckT`v^#t^Uje;jiCu`S(JG6;OmsS76Es7U_q_QMbgCoqI!DfvO#p zBA<$jwRrArwAA5~K(!w3;C0JOW0cYNebiVQYJ}IrZ3X7AgqsDf^F@$BFa35=^ zjp}9b&LaDFtT+AqOLpIvN1yQGafslVw*onF9#)S%3{8x*HK7sj(Z{fVBmTgC2SJ{Q z9eETl7zQS_X%~v%_i9i1@^mHNt=kjL)-OnDKPmG4Hx$FJZmviaNhu}d`y22kD)w#X z`v;jWO}_v6L+SGU)3v=qiX7^I2mJ9ZJy_$3IxQESCilrBL4Y7fz5mP4(s?PV0|jP4 z02gO6<`9~kdWL~$r#cTrW4YTma$FAp#bgSF(ZzqCu?P|Xp~@?|_m1Y4Z>RP5^`l5K zn3XED+rlPQl5N^A@F2rzGnEZ8!DEg((vS&;v^0lnX<~wSEY5Q$Pwh9rvJp(IjOStK z%?tsh;zfVoVHwE-QSsXeliMByOrEe{;>8E&2cb1PmyY@7RO&JYr2{uZf|K;=$o8h6 zwQO-E98O+Hzt{qIg-DoAt<<&$pxu=7gTpRO>VIQ%OSjqd|MO3t{?DLv?0(0w-@7d! zn_mzAftq7AzCx6Ne%=P}-Z-fdG*@|=LBw%yxe!r=N?C+oHZzDgNxPISQ}i_egIU-N zsWy)KF5hMlfhqqdMTV`E=1(5IX}YIa9u|i>E)or=e6NUpr7I-47`7V|I>EJ@OnjAW5I=#yFH` z##2i}xxrHxjds|K7g0}5gJ!FRh)n(W+pYc|sdwWkn6Ce0()1swX`U8OZBI3LTKjqe zo;vVLXkI)$c~5FQ?YGsz(-a3!w{~=d+%TTr{88|9)@bL3%y=5ln}C@FJgH5P4-V%+ zI}+g%(KC0kg&s^@z2{*EbRY# z7g=ho;NC|2V07KEzGb~sktZKoH)41CzdWgbh`)EuhkuYdq6-$g!h z2J?~4?M(c5;AL0*K<=8m?MITRGt@J5K61^3#P|XIARqa7lM_Gq8DP9amifrmHV%`e z8Zc?{kx}0XSem-DQkD^6VSQ5{8EFm}q~VGWp*?P0Dz?davDyw`;$4 z(EzFG9B9=^yAf}@gVI#-Hbs2uv|F^D?xszZ6?x>dBAQ7)Df)lIzdN#d>noRR)OwML z9UuE->_1R*rXJq_fQj+xe6t!*{q>y7z8Ie_`OdK~6QACzPPDI(*jMWx9s8;iFDdb< z`3a7>z}t#PN?k?y@=Gun^IbEs=78%Mv!fBsOJs9)_r&ryzkXF2*k_3`(VI zl;cX&*XZv_v`F3^kMFw^noU&?NygKMH}6jW6W6-&G`EunPlvPD2FFh+{MEiqb_dV< zdHOHHYoc87}Bbb_v4tn$_gfgDNnKFnPC-Izp@3dO_svPr7A!H~19kwuQR zRwrGJeAnk%6=@x{`l+{83uI&#NF^4f{w3)js^j%l&a_ukbFe7>C2U!BuY$ffAC*v_ zN~5pRV+_-~%tyYx`U2w=RV;V8xKQY8$>>DkX!m&1w<-0tI>!=FCVhSNndocD(T1R# z3_*$d67f)9qs)?L)h>x7t*?i^u}HG@)x#zylfKR+IWU>@`Z}#wCVky7m$FLG*G1-_ z(bs)QcHwzMt(Zq6(T}u*mJ;US^ z_uih`VE+EvM&}jAo7`}O!(h0>))w7`a>hkM{IGJ?QCw|9{edrvbag|Hp3r$DZoxf70#$fd4nH-kttOd-~7u_P>9| z{sT4gJgxWp1~K1){tgZ08GYhk9|^?wunE_nY{^&~en;Q;f!&!|L6OM^-=*)HZ1-m# zLeF&HdHTLD4z`%n-*U>x-yysY);Q1#OGYF(G@LhM#Nm{XQCW7_kg7zj469LG=9y_` zr-(b#%??(+nD;`VHKY*^U17BokVZ!(C`d2h<(Mlh#j>EXMXK!xSa)mJNLNQZ&v+N_ ze@hzASn2vQPz5y`HO#9G8QM+Kz-=V4+K1C zUFqDAIo^!tP09X|he|~w>IaO>vB$}-GRiD*(DCFGmZ!usB)imxTOmunZ7E@Vk-|T% z``w{5vw!^ReNCzMk2!~W{KH`MnkipPufHLO82ugcV1oWeEKkzk4}(+d@0`z4>hG22 z4wDV%3p z>o0VOM}IF=WY*uO+WsI!KJ1G1av{t9UMev9>wCXTe^~RB`|8J*{w`>Re4Ed299^EM zKTyQ^k5!KT&T|S1Tl16Dk#7ED>Cd}BQESd<9&S;zbefAIRuqr1DeBd#wK#S)<>o|+ ziiDyapEwk`DvIB`C@R%1Hw{J4ED=PtyUbysETfMe#+!gBU{9;o^npWivrPTLfinkv z?L<2VEvIh?!JoQ68+n)Hi&jO^sY%>oju*$}h2}2}0p|8=*#D;R9}jJE_<{~Ij5i*6 zPxFNg@-6(| z>q490{{svEy;_~3(RTEWiD-jFi2oH9+A3~0 z-*NLF0{;|$g7hOdgZtF$sgnEOamnt;f3&CnJPppo{`X4Xe{wx!NB!>f|Mx;S|G{P+ z|1{~Q%>E&LelyuD>QWu=arp;Eqx+YTL{EO&^twdZ3oA2*1*>HZ- zf(*udN0&M`7^l*}{H3bXQbE%?8kt*wjZ&Iso_Z29z1T~e-!zq+&dzVT-tMr z6UP(D>q&dLXaxls@_~tOx#UGxt8Y>BwdJ!!>RwM8AUzGOCrx4h=R2~?jGw>XbkU5^zf@KEA5n13tRK^Zxh*JbUKX4`1-%!w1iP zSh?s1p3C+GPgi>x_QA7fem&O@55yPX}jRyKa<+_hVzY$jt%27UfkX6=u6pqx~{mSSxY(2iwv~teC z162LPC%&qOvFbIcRS%J>%T?9EsG5rhZvQEroh!2r0Q4D&aiPI)0{UO(O z-o)cqlOC_+<2kM|1^oTJ>jy`u_#Bjr+Yfsp4mjFeo5RnBmYBt7)b%p0qZRMsq|hb_ zYO!Sx-)_8h68_y?cN8`U;`~&MHpjS^qh(qE7^{MC>)nWv_Rc!&GV{u9{bj$j*xPJF zp6;h=FS#F2TZgscvv|+rU532NRPV055APnv(_a3kU!uR*?Rc75w>r`K2WUN72Qvh` zWC}!ZLr6LWW!4E#5K7Km;$a@?iGrKaIUmY~_5woWwq(ese%D+DEUwT&Omh4(8nK;^ z7l|b}Udrk5NdrH==x)nWK3X1ok?2J6s(Ursk3FUr?AS!W#Aj3xM1i>uHH+V^%eC=2 zwy}ZY)yAUM`G9!&u-4cPT|OC}%X)+-%+z=;`_mKPc1ZV%I6Poskf|+KoJs(P^XZ8^ zK!Qifu>SQ*z-oJoi}>vh-jigLtBsRk0X&XN~8u@gxR)eY{Z0!2W&(26kJjzj9;O{xw;p4+~B>@hSahM84_d zCf&TI*1FtbB$SWHL=z@qTLF{MmwY03a69jN_+L^nH@42b1Ykt#eIC>g!Utu>y{%UY zJ_5=32(Zv4@j@y1_}k?QA3|Tvj`pD-VSgOd3hqQ6WHJ@I<;T6G-vENL5z@xqu!Nxa z5rP8z3ciTsJQjK?UML0Ld<}0hzUsTuPs?YLJV^hekUp?S`ibyj_=3xL&wD8kFv@A}vQFhI z#pNM0PE%1j`7HFCc%c-a2N38k`V4DlUF?;yM2t<5vEbuV?3edzv&ptWS3Nqry+Ad6IOlQ z8Y1Y7g|D$JQGP_IB9%)fnRs?J&G;j zsx5(50r*hz&OP7uz&kmB;`{I`tJBH*DWOJzS001tXiMnKbO#{Ef zh2RmZh<%_LxUS9)h2_||`}<$`@KvCcre`J=Cclfcp)GA<-7EitPzUV+G699nM^*%v zyK5%`8hX=0z$AE#xnC&$EF?_mjQ^;S0BiWrg3U9D?diBU!z|urH1TtdYs(H`E@Vc|FCbm3ogEgT&K9Jnu50vkMC zOe+iy7blO307bvLA^u#yPNCnP^@$t1+eg1-w_NyL+@ME0df@lL0Pp`Neiy*L!UVTx5-;?n9yX*IW&%N}Y`cX$rYxi&_!s3jFKJx@)%B~du$xH~w z*!a5?yY%dZ0Q-ODKM9O4VIg182hV8_{u3ai+^etxH#9Rx0901@`A-;R!hgaI{ipVw zUa{Z0U;G4v=+S@LGrtN?28rK(JCg95q+AZV(_`us9A1y^zmH$VuyxVT@EvKdK*u5( z9u1ekFdHce8h^F;^1Xy$W&tz?lnGBfwnR}KL9K785WT-ekU`vsc??h=MM)U<1GeKW${ z9kr*4ar!Z$U)ZclnbCkrf@5Ukz_0HyNh*l~A26l;*B0hvWG}?c5jv#z^q_mm`9K)6 zSG%ZH4zwrS1CmzT^CPq0F{^HPl$RFema)iO*lSs8EnD!y2JvCsxv*Dj` z2c{1*odI{5ZJ+eov5FB--NANk|4ge4|8K+jXZV6Fnu)9kEXU&j9tUEdyWf4pSzQk~ z_)X~#r#jZoM3+H)ju{>Zl69H-;ZfD+qU#7-O(!j4z(Nh z%WUqf&9vHM8@-2pt?+)CaMGYKG#Gdgh<%B&f!Id3RsaFFCEjzmNe>8SLO(cV`Om5E zV>JTN_&(NZV%B;xzm>m^{)H;5!aY$w^)Y=6X;H0;Oo3SD^Q@LuUq6wU30FMe|-Lox|HkZ^z}+rHA|Xe1vW@@Cw8m05&a?X(oVFN#>#5s-U>n5OQABs|%HR>Rr$01^zhRJJe+w z@@;A|>4>6Jek#L0*|cv7gzeF}VduQ`a!BpM*HAR(hLRAw-nFfHVa^J&2rxQ$%2u+%p!_h}1pt$Ij03*!;hsB7aYiLN0LFkM@zlf4 zz*A5oY|+1|)s8Le=7j-V&^eOZD9V!$$IuHee^aFVmgWJ-(2^e1{~|S4W~w!&d8rj zG5YIbdxhH283a7&&N?_1(#ljwfBvLEIslM{ZLC#nGOe{?Yk4%p=Hu`!mK`H<93tU+ z%l#${wRI^d}7M{i@^mj~bj zY#o`#ylbE(8#^+LxhF#28#{U#&Fh58`Qfky>a;u_D#=gs4BI$t^RVsY@+x4V0z;q7 zquCwVu4LC2gzb`|FhnqnijCljFka5%X`bZYd4Iq~nX$AYV@erX2!`>=wR-eK@`r}3 zhl0&0cd9x=ZQq_1iu}7XeB>u)`cCl##eh-;3U9bukCFpChl0@H48X!;C^3J(D8CV9 ztmW40lv$3I0#9L!hM@OZfc=^14{|n{bi{83ezQS(F1ikIn-C6z`3Irxyx5cOBkxg< zTZ{AOqoQ?x{sL)KBXrIR;u(6oNwrI39D?%GNQ0>4;XVH-Hlhsmb%F1Bq3^m#Uqj)s z>V9(Oq-IEb9m}qSLMVYk7^f5hx4ML#(Lgt*x}D5lLn$mPv$KN#M}^Q@7v?v|*$&tX zM_@KAL!re2hfghhjtElJ0-#3G4IcyiZb#{4&Hus^6iNUDMYT;8a{Wyda5eDQV$&Hu zS<0RQX_0^xO28-A=M6}f7QGVzq=f5xzgE$d?hBvrNq2wBjP8TQ8Zr9lcS+JcW2ORw zue_FGuNX^BtW8#cSMcp)aOe~&7q(O{xPd;514-kO=PnE;7>v|JF(mePhm}Tb!fomV zYf^xkAI8P^a6<{&;UBrd^j%l@t}A`lRr(s-z^cjIAhu6&!&pBzjPkev_HV#)a6`Yx ztJ|^67WI}_+xj~6O)#=V8hWKe+Hw*z;$hzu7`iaU7Aw3=ks7I1EPSyjbGhIG+c6*SY!{tk0^j?SRhvLg%4jdsJ>1 zOMB(cc(DF5Vx*NTTMjaj|5%syWZrxCa-v9Tzw5fvuZM-CxOZt z9-%|U?->hMqF%_E2p@k^z#e$oL!;BiIfJZnCwmiIfO=YZwi2=iYzjFIn}p1S!bj#E z$cB%TnMyQ`WPX!m9`NfI$aX^JPeA6}J(GFhMos4H{^5~XoJa+SBJ+4bW;bLmk~*g- z)(|pNKf?DVnUBxeOERDIppf}Tdn9voc@mAs%3c-E^eU?x`|J0RwndXl)TQtG8Q=AD zzH13uflrW@RriIolwo^tji#yM_4hNHe+lN7xSGlhh?2;bp8rREL3q9=|3?|$uC4T6zufRQ}+8_6Ra0MiM&yeQSp$SQcVW%<=1ry^ZB?Ydt~ zZ`?zTP4^5MTes0Csf{F8egfSJxbk8ACS3Wy;0w-ZU%B$u5BA}o!N~YWwtr4t%5|&n zn)Zi(qV?1z*`8IqdTo`^YH-`friZX3y6`Smb0$HfRf4B8@3IG8{@c;eaf4ccN_g;# zq!nniR#?Qs z{}_5{&SY3#X%;V=HPf_!FbyH<u`Gu{4x{ z0BOLK9c{rh;}>o7MU)a1=%m7MWV_pZZ2$ePsC&^ms<_6E1C8bd9E%_q-%f7cNT7Om z1#0eB3T^ugl#`o~#XSJEY^~_sJ;Ji{UrMK>z>?b|f)J(vN!e~Gmasg%um@O96<8WO z4lw4e5H;Cnj}B11&jL33uIKx%@9S8<6+v8TUivtuu`}^Vm4OpYC)Y&z5Tru;t~$!0!d+sZm(2s0VgjN$ZkYd822>o+Gr-w7`C@@-` zDs|$Hf=F?k&{w7HC84kVg-?os!Q_riDRE895%gB!(2|9BnnUFZ6)^L*DqeGNjhD#!{Vs`=S+WU`gp_^%Sv5?6xIuNn&- z*o<;c*5Xrp=V2D%JSQ9Tvx6HKk|v&T zrfJW>BH{W_@m3@90X&0o&MA%NhEL75&k(bo2G0bAW(Td!X6JIV_@h~wrgdphmVvoK zjBe*XAdWsCa1~6HR6(*o= z6LE+?UT={rb?y4DxB9Nz^)=AQs+gQDGOZV7-ZyOTAGXhf$Xo=)I1y-k(^z;Ru)(RG zuyqm8m~EZs3|I{`7T>MWxD9P^F@bHJXAM{lG_DSWEG+0P7I1u+>_FbS!en6_lWRi7 zUmKA}Q5l%Dh{n){EuqNj^fIfA=tRlc!7)~AsIxU(ylPfv*g89CGAscq=WI+6Y_uXajazCL!1w)bwQ7;77mZ z$I)c*STDfUm}sSl8tPuaZ(5wCf96gR-NLRj5F8_WHQ^rDo7P8R_}euEAv!ckh+n#l z(DJKPy5ZOo_xVaxL8h&M<_(nF6;Qo-<<8|$ z8Gkbt?m!`#9kwc{c`caNJ_|>uL31o0!|&V?I5J};)b4WV3#J0pa_K$3T>b_U)0L(` zR)*HOo1k;2PZWJiWm|SyrWK}!$PkiZ%-n`xW#;4RVO~MH-ChdCd1P`VJuAGVT@sF|sB-_Jn)P3))d^c%3XZ0BTg`yZPN6D3@IKDj~gxTwpbN29=mIe4JG1Asje! z`yP36oGmWlcdkKDt&g4;umQb z`iwG3eI~!aA`vVJcZy#m&!-B{L}OKZ7s-l>9#JD-;SWly3JqZHir7NJerjCM7cAq& z1@^#6Kj)bkgMO_RH;m?GXo4(L>tnGcOfBda=tz&4)> z+fW$EHWz}(Ex5L74^?afVnY9euwWgGSR^nrUkJNy6UYcG^N71=PzRS~xLk}&>M=pm zoE5~~@d9tC`UX94h5DAl+Ex-?malf!0 z{DoyuVctY|?J`hyCD(UYss!u1+j5cjaHzn54@iz+8(4H8*TXr+OJiwMek<-uBU{pu zi==MM$S&k^wBYfWVXb3~rK`)Va7JK?iRZ@oZ#gXKq?uZ`E4w*fV&YS@(bP`eD3| zwD+#N-##Z0X+NNDk$q0KD*kg-yiaUSnQfFovAYE|?c^a)Sh*E;-{SRk`DDHlu`O|Y z!TW}ie1k4XMf7kARgY!jxKV}wEn+bOjmGf@-_@8v@sMsPL$qVbed*HCyHMTzda)LK zbG0Y<1lpNEcW+7NM3BeDbA9 zn{ftvi#z5gUEq`bs@O_*>M@Z0hLjAvggiq2jk$~-p#y}mtEmI3iJy8g7o1~75;k+M z;pi4ACS8@8k1F8ptefso8Ov&4+d+H?g@Ce{1jXyhi`44^x+jH@c-ASuP(2i%r2_n& z=GsHmL<=YprX#ED4n0l^GgS*Vb*`vc?mn20;ee%*6AB3~Yyc8Kcm+8`p2_lV^^c7A zr&K+WFQ8zr0|Q{Z-~vdwJGFg2JBFF@j9dFFqG5{9*)9=(rBau$1T`>&=_V1*q%(4s3B+P z14TSkypu^RSg>*5MiT_AD!#N~S0Z5;^B{;DP1Csg8 z1UNKv1Cdcf3|0VxmCJ=yI9fgrxEbS>FjU9h2|HO2U(9ftYnC#l4fZC{LCuEzpnK7m zsVpmkT0|>Dmd&#VUIhTK@OO~O9AEB8lRQz=`Z{`%$n6A5@&K_H0e4=7VpX()24Zhe zDfGXtU1Spss8EJi*b|F9wYkf|2=>@aY%0l$u7PB-_}{PXt~f#@N#VEqfDp~Up%U<@ zg|(p?EDg~SF_s=0S(iQqfV9Ku7wtK}ZVcL?(y= zCN-A!jjToeij3$*R1`(eilPARYET4aJdC@4c!qD>$J9@Y{GdnoM}Qub0H(r}xbfhT zi3MP&j2UC?3j)RKYk|Mj(WQ`YmTteMyV4lYL3V#=PANNpSVo-)>bR$={tD$M4)Q0v zr$9C_X6Stot%#*2j>qVh>|f(_M!Q5s7Ys&T+p9LR@F3XdnOlfD?~*z9qMJ zACD*E9lh=dIWiXfi4~lQ7%;pXY&J3?zY>9|UE59pfg-zUw^{s#5owUe;k8@I)>X!m zgBo}Cs?EdnU5g@AavW5KPuTa2X_W*AFv%7}cD9{D_dO7YIR*MvsE9@NF`LJEZ$ zb}~`-0P(j$fuz(XYNZ6WKR9?Kvn8%b##uzo6s;Q7iKgXkxGvH40oSOM+`y3H? z11!ng*yBN_gFuK9ECoaGfETN@$j<70D`k6p0VXAyPe2=dRfAUrFg-Nec)lQlU&Tz$ z_>!g!b5*Hg*HxuOKtY;4c*SfsGPMA!ZD*R+_<}gofsKA-^`d9NXlsg9nxWB?PVb-* z&*EYJmZyZzF$qN_A8=d4@u*(WtTsvnJA>fu%2sS7*9a~5U z$^}6?=U4%*f=>n^pCH&1frvTMJm8K&*O(uQgEAcViO!jU{)GF01{ZY{#;EnOQBV?! z+}q?eW)iQy`#?RD=&3%^3^R!^CGKSR>rPI%fW)+cK)G^LNhS;s{6H3jqXID|SCEKd zyr_@vrkp(Wq$q$#<)^1%xvK_4Rz49~N!Vw|#}?%;&mqz0e9=N$SWl{W&e6XBNc=xvEo9!5+Awfe4=%3_B%3#_nozzA^|$Grz#Ns1=DUkc+rO+i5C?*3P;Y70GPO zd#C&5)M6GcQSew~_KW8W_71L07v5nwMc$e6M0#4?WdQ0KJg`bjOsBMjduUSFao}*m z=1eSr$pFPm(fk5^0J$F5oE0r-LD?)ZR~L*`HUnGVyykJX%PbTE%0-a|W4FV_xVWh= zfc6X-kchT9g%BC1>gUOayp*XUC+!M(&;L$y;ba}E8*q;-QEvj#eo(INQG-CFOHjt= zUHJ7G<02j=D5TnaWYn5`}MQmb*yxwKf$Ir4ANbQmj4L)KGU7KDmhjd`002F_pZ!=MQq|K11=iZY5KaQsUGN1=qB zb5cF1geh$~V$;bP@F#`_BFNx3GtbWHivp%okqfIZj-g^M*~o$)fI#0{(ByRip7Rfw z{P2$@D6&8nzZpt!;hW@Znb<4D_dM81V=2e!O)P=*i_b{K z(y^#z=VZ@J!qVKk@!lyc9s4M; zganaJ`Z+~ZfmDkR5-?1a!6_8u14dwy+BfRKqG14>D?pg^SUG?T`q9> zS!pE-_*rQ$kaYJmKLklnjZQ_<-(K>Nbf@=DAt~b#A}MTF2I+1Tm1Bjw>F7-CG_#L6 z7~q!M*TQnw1jjW0-DqBgNHlC!2dVlhx~jgiQl-^U_5E7TV4=!cQspBWZ}^dMD}POy zD#|`fI2BKEEuD`|n=j^X!DYz01y0PvvRSg+y0T(QsWmPm>uBN-pZZnficZr8qHi*3t8g=A$uIwwXV%A$HTdk@DK&Z2v{i8PD!y4htZ!e351YW z5@A-0opTh5oa=;J+o=@jE1zpkZf!4V+}#&3ccc?;{}ib^NS!t4Vtnom_(z8@wI)SP zt*t8kz=pvAzm@Yz-uZ8{&i6hp2$K;sQSyyA*;3Mu8)iE#w^X19jB#oB@g+r zbH-0k;>rm(rHXDL3hX0Se)rT5;mU(cQ@L_gy~mZi#LIzZR$O`AgXGFkF=<^WfqW)-dET;LbUVRN2=yI=C9|46nUO0p{K^{3`?~gl-?2ihhSy z+}swSipG2NC@kBj4kOyP0|k%m3kT%39bMMzDDzB zB3|PwkeO>Vt;Nl(Oaz{gRC)s30QDFPG;f@ZCH^-to7`zM$%zs7nLBnVcflTyfrWBu zjDy2A>p3ZA1r)EFHHIe-2)3g(*>t9A}cVR3sIQ~&d#NXX4xlz3nn$v@B-Ef zD)5$|M^+Rq=Pgu%cWdt0G;CwE25qOjNU0{xM@_nG9R{%VH|4G+ukWr`@f>%~BA$DO zV@EvqIDZk($uEfboIKCWPn{IRQSrhr^4{iVcRfREeTej^+4)GX?UdxIHPn-K_`P;m z+1{m%9gWkmn7$lkZhhY@{>GU1Al{opJ`7o_%^~lGols{8S!!5f3$=B?-$T56~DyPWK%36HyTn zU`RXa!bRFqUp7(|TAA*1%}@L%F(A{tdhG+gouF;b3Stx6LkC_wBgHjGt8~pH;#+&4 zxeDWJjt?hX^X=k&`Cdj#KuI`)Ino;ZvjHbjSfOGlW~6|qOVfh8$hi>7=aB#$d=c#D zHpAN?qy_Xe6+yia>YC^t2I0E*Q!d?))z3BR=b;>M)gPdh{Lz*_{&dQ`^Dm|<{#q?$ z=sq4$_O}8&gxwohZEapd{wY=ba~$e}f7T`OPaDdRf4(;6^^^0`w?=QEIX~xD!k{JU zXN|mcGY$ZQUZ2XKiFj4kU%2kt&3cnsE~%9h#?^8U_NpKZl*v$x{<9_pJopuh&>Sh` zkU44=&a1OVW0LgmSA&$`m3PT2)&-Ee(Rd>&e_Rm`!9!!5j*Q^c>r3sEnzz?g+S4-U zU@%zFEH_t;E(A*96^<_AubuS^X|8S{o)qxO%3jzH40`8WeBlVKs$#Ulez<>)<7%;(qPE&prmAafa zvSdGWKj#ZhBhUmho}merUnqEn20$Rz)vsYeNEs&?;JO4E^*0iBdNfDN%Spj9JL{^S zjYbYk2;mx-a0|7+g>&8=wffxE2HthD)A_BD^cnt%QMR;U%&YKjl72vvXx?M-9Jh+||D}k9e#g9MGVG^*Jj@jOC_1 z3PO(4%po$y(wj4;Z~;>BYAwwy@?J%$xxKW76>fpoNuLlZp&BXyB}V7jSsQ+;RKo2f zmvun^Dgn)o!=fUN#mDwKD0VD$+c{659Q|HJ;%T7TEnJB}n(XwTon!MYP>m;;BAo=q8jKQ&?ds{G36YmBFW zWP)d6c*K3covpnpk@4!-ugmT60%9e24i{KCJI~2Kl#pXm;+nj2dn%S?puxg8Z>-!d z6&}9>EtVI5Va%%o|Adi_KOYYmVO7f0N<1wu{?wRv9xsM`5OOZ*G~0Ha6@tTS;z;?> zk(;p<{|s4HB6iR%r?;KKca30tKL~_?a^f4T@WJ76PZzDDwItZB6ikJ*UR;3ZF1b?i zoXV3_2}yV(m{a^!5wr)NhEhaWjp@t|Vnyy6)4DKd4-E3LQ;EfzI>1vC?1FBPC$0dx zMYu$m1X?lS5yO;Qp?bzrbL>gQp=7y?)RzL0`mTeYKS4BNRPpI+g~|=7jvfa-bb|7f90ot20Ym|$jUsztEP$gxO&C++^?1TF8y9|#4}ciX z2L2mafqywO#3sw_p|8T$)TNa+?(SEIEO`Du3p3~2XZI?%PxM~(GMXl$)|g>mjv2On z%rNL(6$lJ#r3x{LvGo9KN@?*2Ml;VpW`WiCRRyY9fVbqD>QM2&XN@i|{&v=xqwUNV z0|{$sX`}7zM~he24GlSE`IrY#~MT2EGy zZh+_-q~l>&VZ7&H!>~^+s2^*=%+=|qQB}l^l4#tprz*Z&O;sVMLL&NOy9g_*1hdHi zsBwD8@NmG1ydL_F{)ZG9?2sZdISIId-4KWqBr!zL;k-3jSPu)^)o|*DFT8})+i*a} zaQb5aUX+7c!I1SGJ-ceO(ABeh4jH#x9Y^&FRF|6KM4~TiyXh=ehufhYJ=3visOR1_ ziD!qrqbXJ;_Lfz`wW$G@eTWn2#5sg0k_g}+ikrOPs)|A;%xS3YGwdv>h4z|zBHN^+ z4t_RK7&Zt#5)Sc^2F4fJ1OGIc#)d2KMsrYnDQGMy$>b17IeCfNmpE?aFBr~o5U|Cl*L?(;3iag4TKV@E-vfqWF68 zQwOzSRva`>g1;*;3#OA%QL4&h#?5g8$)fx;Xf7O#W6V259xN6}h$C~zGWf-qqQI&q zR^yO&%f-#`k*#s=NpBUmBs^rDb~NEEsp$F7IK+cpA&hKNivmC_hv>xwbY3MUxQX4{ z5))Kh?28Fb<#Qbqw4-oW&Y69zVg!5e!KlcXU^zRmBqm@L-!jfa$9YV%D8B@+R%Y}= zr+M6)&756h!BAFJfgkmAl~jkcl77$!E`G7M=ns>~p;&MEBi>W(lUK^E0AAgVS6IQr z(hgo%;&I5rVSUy#IM3A( z41T35#nV#!Oi$~dJ%CJ!iVi~cgr{}hkCZJ6kc)iimZA?~afS20(i5^KuNcI_+SBsa zh^|6OH!@Fbvml>d+&AKwC2Oc?Etg56b5%+BiF5#kgUM8FQp2aDqATFSxyPx7osoU7 z=cEViC^;!U=|Ox_O9$PwW#lGFE8}VfP$-1Nz*>dkP{JfPd(;+|z7-gP{OQ>+Iv|u6 zI>Z&xcf{QsdEsS5H@hY&wXIUAhPP-O7HJ&DyE2x-tJ~N9&Ov`+bfi|ap3YbF>Ar1~ z5YkpCaQ8H@=r6b)Bk z`}%^?$Y+?>XvjB17P=Gv_Ny`0e?r!7xr^R~{2=$OCaF8D6HY01T@3p&dKfaJ!q)1r z^{zVGhn}iB1Bt4mipnpKWJ7j}$T5_#Vx<>FzQe^EjfEuvy2>Z<-^eleH*9BafFB$z zZNzeH^M~+1=$%8Ix063;Fwe&f6dzQQnn*(*h;_6uw(;}FS{a5nHv?LTPr}8Ys1=+r zY-41%FxVhW&EGE$qv^~IFc@-_|AN%+YiPcE8W)n!~thd=rlOYc@zwN4eudr4}DiS zn?j}>nxXmO;!jJBU#u*fPe&^UXYx>RrM@@pgkN*+1iaY)Q~MG7RhjG zHh}^YkylFKDl$?6+6CuhAR+7~h8Ffz1%t0mf&@7G#lhmRp~P+Ww9ezTH^i z+um7zHFUD7cx7U2)%Mn6o}T;6~pmaMb*}Yj|rv{ z8Sp{Kg2;X7Nl$c^WD{gU`e=<#K7!Kc(Mfj)!4nt(4#9}wq~(#%522ZdZHU7N$3Yw& zikWtFe)k-k$b# z>c!VdmI^(>M&;|gdr^w7qu80g&h8#Sra(mpC;2*84kiw}j!ud`tbCmtr6>40Gy1cz z_I3QQMOV|;`Q>co!O+p9rruw-?blk-D*8I#%~B;9o)gEfVMawKRTxde$y#n?#STZV z_ZK?JZm4vlISY5s+^u~=Vktu>Cj*j%YiGL9w5V_1GV|FK5Bxe;lEmi%t zqi+v}xP_uHNAHH$(1=Z6`%CMwmd2e~-u0r!o%2 zEv`=56Koi6ZRzKQ)xO&(CSRf^-M{6(s`=cETTl3*R* z{8Q|&*v|GARv6iU%G<)=5yizFiTO)FpToo1+RHOkI ziCjuA8yQ5g|CcC}eFU;Tr`5ug^ML(C`}Efv}yw z9t=D*-z?s3L|%|5r)d?;z^MWwYPnh9C zDMHTryvPb#-T=!2iC=rZ}l}~iHuBoWvDX}CvV;&z6bftInB0(b0x?FMkgfs!Uu3tH3@DU2%P{;+;1yks2SlifWBfyJJ zWYM?kI69aLm^m>F(NAElaSuDE?l-FY{Ys2QE2FRA#(hBQX!}H&;b`&MPvmhrQ^Ec~ zxIFl9)@0KjvD#R2R!L)L24)3$6i7ZL#m4z)-eYj%*S;x zh}~q}Yt9NThatlt8@6eIwoNy~Hob9cbwVFwDjQJ9G6@0$XAEaS2fWDz62!dOZ<^N5 zSaTS%#&nv1`&V(insm6Uaqqd@K5D9^kyslv@#%*rX<~4(HceP(aKC)I8%&f!#SJ&w(nWAlwmTz@ro-HFb*|cf>!obw(fiG@fRdSYMR< zt!&nfd{NEltcv-*&@^TF_2Lco!_t+Pk_wf#@YjF|pXK2h=z0^pENLh@v6}Zyt$HK@B?yX+#I@1L^R!8hHo?a{((IcklOmd*K--{{& z?IR#6Q;Eaq317&@K7WS3b9aFu?Sa>iM(~Oil=Y&>aY#*W=JD6g z`p+n~Iv&&Sb%)|@($>Fs^vodnny#Bw&E} zmI~tznb47W2F%l*d>EBF$m&$=HrsZdWkzrgMC6kIGLNa1gQjy4)DE&P%ua|af>5_@ zfa;PI2OW^S+PMZ^=uD*L;NEJB?xNoP{ZvI^0!ou}n81WlC%}pR5(Sm|C)6E=Y8Nqv zS1dY7N(|C%ypvQSdJy}0vxfb+*`GjO-hoQgX}Jk`amw-!D)M4h|MBtPhZP0|cmZA%H6;wE9W zhlHO<#I^Di2~6O!Yvd`2DP17-*RH`=h;hckZ6SFhL}G@e*i~ob?T2W~>&ym`Izglz zAkya`5@sT>AVLa2T99dfE)a^OYIl$*M6QcK194;!nmn@@+h#uJjbzIpr5}8INw`PkF$k8Vsb zASf@!n;o6t;N?3 zxY}*!T#1Ts5>LgNy6HgXee-wQk-E-8S|xW&N+;*RvpH?Tq*REl>F`r>qKMaOJe#qX z6PjjBwwBrGmDJPtE|S#7D#5iG>P;YahiQ2Ne2^4Z_=#qrMxv!%2e5n!X`uiA6$p0TLd7u7yD7)KUU~7lTTf8uVVQ-atr55RT5fpM#O4t= zS9h={*cO$bjoJFb^Sy%;5T$dzNO>}hxr6S}kI^5Og+k~Bb`Slk(+fe_3y^|PID*EL zGB~;*EGgQXsDfdR^sv+v4Z;D;L}FjLtl}2;Ay%b*oW&6Pv+12t1SJNW z0|(1J=yL@OSe~;0fTMu(KY)W-;(#UV;WGdWd^|{hLG(av`_Ty_7fSHodb1N$k@*~@ z8Zc_bqQCszwoZVEhQrW_fU~me5TY~4Q^JvKuSwdIk|1lekUZA989erT`1&4m;Wxow zPLrGwq)bWxTMS`RR5bLY$|!l*b+To$^FR8jfo2kAhClBX3ZVXXm@&PW2^U zK(3aN$bwRwd#}Nbin&0YyG|FrDsw17!U z<~QWe45R%mxS<<I5 zTsvBG(`s)a1(1Rf=;J>4GSwiMjGx7uvnGv0q}V`qTiCv1!bEkzM1j_n$2&m0$(*v+1 zt+p@BXGX&T7}TirQtX_s{V9a3fJZJ{B@kH!e53o1mo)IiF?)bn#On$$iU)p@8wBvN zh9ls=Cl1ht_z0rK8a4@D6$5@ob^vY?{9Q<9Ex?|yx&sq6<&!1Y`Fbw~%s)zXiwqv8 zA@COlmMny=^5iUKV1@m&ra%<|_vCPh4*fF-Ry{k(V=K?FHB2jTTNnh|8zeYRM0Cbq zIs65>m;?-(9?@$l7D+IHi3BDj!gm7`s4&E6;#S}>&ZM`ohdh18HF$P{(R?oO;!!4$ zhWTfW{r%jZp?gj@w*X3LIUH=DHoAqtCp>_gh#u!;_YFBEFs>eC8z6~Z8(HqrXe0JK zdOFT%UV-v2<8vj7(^-Zr?_1-CQ<8_*K(Js6I14-D(d|yGzHP&K3ZJBh(l;_yvJlT< zjGz~(KT8-1nr@zEmTF?Vir5C5Oom6$#C0?mhYJMbjVN8|?hP<8uxt67~(c$w=Eqil)HT z#H4myU2HVH5s+t-jpj)hu}5=AD?@OHX2{R zga(4V2C1ypW5nfjgdW60Oncom9HBqXD+(hcTautgv9MJUEVVjJ=SA6S-qj)c3$k-n z`rp9uXaLjNM)Q;K|B-7M!X%309shlum;U!|rm8>?HUWgvm1&vA(n9RJM^+7WOP;Z0 zS~|AD*BDJXP?NZ-Fq*gpFXYseU;_xaFQEyP;|}%i!}aggK|sAY4`elU-z5Goc0+>7y;+hQr4Q zxC@^Fg(2puP1R9Cp5`#Y*`iBE_c0paS=NfA;J-@8YH-8$w_k z2iG=wGU4LsQ7}~U6lcT`D}aPzAqJc`E&2xMhiiU@3YHlJnr-0X85DrDI^Ap zQg;x~lnuC#J*URW@)Qfqe|Spce#~?wGdYf`rRYIPb|-?$jbRu%O`Jn*e@2MpF@~kH zaFOqohleO9DE5T~`kktPts?26P$od3cr*1NJ(%JC_{s{Hp@Hf8T>B+jU&25k8{`Vb zrKVL6uBa)pbFMv!*sm#oPJj-B%>$wpva$g^{j;0?ps@9vU<<1h_)Q=TC*grBy!FQG z)08(ZoELWk6<~g@(8Scbn>e8{r%qx`$bT3f2;R=e)99P~sCY2tJn(e7?96Mz2s~+* z`3v{-Bx3Xo$oj5;2*4Bq=YD5S#AdNDSXGio-D2ld;~fN$2lbql5IW4s_?5krQ+jO)x&dG!4&7TM5eL8Ax)<*z zObVRXQzF++&SU|BqA|kvI(oIXS9BP&-Kl>j-+Atp`JK-@gx9EDR(OYz*4+tqe4nR3 z0T*ndw|l}5Y2rRK0h2S{XreQVt1D{H#lJV>^vXM^9dzq`-1Uop0Dx!s06f5Ten=DT z|0Wbv+Q1?{$}YiBIQdCS2+)SWGTqbr(#pFE;u zfX@YFNE0n!a{4}u4Nlahbyc3*gea@b?{6Q^ZPhukdOpjf=2HxC3`xSV%j zYh^nJhyub^AYut(3NV|rGb2%+W=p(*3&XGrqJaV2FCjN?N_cZG+r*9Oz5@H>;J0!@f6enRW#@mA78hB5CXv5Z{IK&_)*^fe;|vHyZ|^-XkfV7AA< zpv`vum)#(e{AcI9R*;0qmyeDkl3s;6XYUD=@tbdYQrM-``kr>dyUk@*YqGw3J`i*{dG@5 z6)=*FUzdmu{gSxWEB~}rc%cx)s`p+103bZDPLxC#w4uqGN5M(ohA?)SMFC(64#p&~ zQ7l8hGCosBDR=*<&xL`d*vIkDUxj(YH)Aqyc$Mk<{*p0wF|0Y}qv70N2bF;JTIdCC zn1YEcrnRpYgyN#cyQo(e%1!4rPOY6U&urF?tT3^HjsQY(?ry2gh&`u63HTFEB{U+I zak+#W`7~W0{en{fR*NEYKf*>%_KzWAg@{f%^sSzY4RUpBJyC;@x#=!k7)y{wH`Hiq zLhqcLL)Kgu?lk>#0!EanLtJeYAk^mzUsQ4zuK-VX9*KB#1bgsnmKG{NmvNok9F3;E;)NWKQofE%jFNLzUl5f3sMd=|ew{TNjE5 zBEqB4xSccYC}mn?h0w{Fafvo9oU#-HJst(LU6J!!iFMDe(2Vnsdh{7}iLyC|Us8f1 z-icX>Grk&GRDW$ukm?OptZ~s+1z~;s{MP7X&r%Qa-l^jao$)jkL~rxAoOlK{fXt1C zL*}6uII;=a=VQDwmQDb6H=-y{%|EktH1S2WPO)I0Jx64*n$pH7p2I8taYU_hg=<)< zMqI~1*G-s~w=VG7qXYsvO}eA=SrWU4;Ia2ubEN(1TSr9Ne^Pg_5IeFuC=kCuzKdo9 zN)#}fdDf184|RnRsrO$%dLr%Ddv&*b<$K3ZNk!VH8_nBsq3dGyAYS(wJQkaaj`){E zCvTz%vq!CbmpV$M{rwL0-C%|CiFE7-y^(t+%De7t6lYW2E(4vNSX;46Xb2IMh$b zAG&Q`3mozhiqkBMQl>|8F=RiU@&1|&&zq#giBz4)rsTm?9{qA2A^k+Kv5Y3ALwIdg z>K4svJ12C6$UzlCH>BL)L=?QQic23JRPuOH9F`joE|1(m2SkktVXVh&N>oUSy<#>C z7Fi9DDCiF-5jhPw-~3taHkN*xD%b-t06XWt!;=L2AIHW8yAqJ&VCH%h*hj%0GqL0c z2=--PqzZPW07E*B_TH(3(14U~bqcIGkwql73VD(x(rqXwkGgg8L!t=Qg(VU(R>1v5 zNO23|Fs8>aHrdSPoUC5sp}MN`vnH9OY3!+N;Pr`U16w!WYK>7)nrv@-2snR^Zm* z6C;JjZ81D(+*xeQ`$Q1Xp3!hHp4at*Gm?&rX}$S!F2Bfu^QJg;grMU%W63c1vW3%* z#J|Ne55ufG{L$U;Vzu7UMXWGaA z$(nU~*f~2L6T#Uhhn)d0;~S#mkp#aIMH)U3f0h0?h7Xd!uf#}^nQmh&krjdE+SQ1? z=Z+aGsvRo505HNlV5PvjDB=YxV#x7|ds(mx{&FQVF4LIz5E?}`X>BdH)?7|p4%>(` zGQcl2g&63pXb|u-4dD*y&R{u(4x51RO6WHwfUh8zijJ_%~b#-^>57WMNhcP_p+)yqVS8{Ad1mkC)Sj) z8S@(KiC8wm2fHifX=MSv;7ckY1$OQjJhBhNPGxvBsVw)&6x=BFX3FgQ;fK zS&)>==DWdE%=lq7fX+1K>FD|vWJxh42}EyRgY*Ksx3RPYedD`_Dsc>popji9At!n6 zO}gJ8B^*s9`sLx2NG{4b2mQkOBe`gFLA0;<-eE4dWh-st&iu!}I_108?yR$w%S1gy zoqP%2h+D=;p-O!YVxp9B&zB!a1D5CD0J3u&4#qDS>8w3|qfEGdDt_y+nupJ#>;RkU$he%5(qkB!xy94r=Q79B8}%!x@L+)E}hK7$4G^?BCO! z?h}8X=unqK#6tXdWb-*}M$F-u zCWNm4LVIOJ?-+A8;ldti4FLDz5Xpyd2d-BQmQV=Ua==}~RYV97KlB5tk5c7AD^-i#R;s}LXta_B@+f;c z?-NP`x`-h)iQK~3xzpt#x>s+0srDGx;!RM$0YqZOYt@pr`m`^PM*z@8(Gw_-@>#K? zyAa`6KJkc9D4!Jrhvv$+#WIO(;CCyrPyo~haMU(P`2o=ck~bWNRUnXJjS*SSNA`rZ zF1gcJ>kri7S&D8x-4 zX=l0pi0TRNw!`!vqE&p^yX`61WZ&LPAg34H)!6%P_9%s7U=xT%9~7O>w}h zxjPxPwsAW(fKS`y!_LM}j3csMu%-?S)k6rm43RGa|B0Or_>?)zscei?xRWR(|_ z3P4u!gVCEPQPLTkxEYqlip@8Y1!`MI`Aj#eNMAfB_<3RME$*q>ou?qKSI?xyEfB zoG$H>R?9hNWKB4g(3-SCe(BKDBxgfany_}sc#zl%;04yJp?$=iTljL!o%isB7YFBXv5#m{ZN8>xkn zjw!~%2ca$^9j6%!gK|-bEnny~(uPS|Dg~f=SFc%TVZyQYbYn@O1al1OPMdkW*}1&L zSh5}G=BK~zoVy-d%2Q&yt@!*Ft2eY^q>XF~BW3GM;vzDLAWmNJkJl}7h3hyboQZEl zcI{`(lkYeH21J{Ajk^k`A*w!YW>)kk;+T^9oDl}QK|#oj@H=eL$@%!VS_%RiQYox* zgsQR?g#{`nXX&8$#F43{InF`>O=7ICtC_Iey`ypFIVF3dv1*WnJoY`0$Pa2FA1|=* z-2vV^**W4ioIz2a)6s}A8qRm{TAhjOBfEOfJja_-$clcBr~d`gUykgG&o(^mO!a0P z9*%TeUV9eU2B{GZK)uETRbdy>V#bxEDkFD?w2Ap;Dw{+O0Q5I&NU^)6n~F zj88X|vri4_N_3$29^^ zPKN=IJGw>?KFl8@yOzh4N7`>OnoUU9uvTtIfD(j)9D&%ecB(0kBE`7W*Ak4p4%0-8 zF-wD$m$ev2qqqii0k;le#S*gmOD(qV?M^e8jX;+IodzN-h9E?fS0W0&572~=y&R2TYJ;;!Ln1ArBhAV3}y+(D2$(1Y`$bq&th>v68`%nR_k2>O1(69^BQTW4iO zTX50#ac27J_>k`3R|R(V?;`C);n`2bTAZ_A);DWncOxMeC|s~tWA4dNIOgvn9a%F2 zj`>8CU*pD?JN5mVXgj#`FYF`wuY|C8=sMRnYz=x?SJWh`u1q5axx2+5D*^n3wNiafwC?O4^$^(naS)GxEc1-Il$pr1emI@j?eH|2 zq{disXydNQm_u#B*`Zf|&T}*ok=TRZ9#x7GOk zduvYKdXxGxErkLJDXD48+WUq`5TndprV=4W6B@>y`49-pRbhX=gv7^k%ueJB@Z@!H z;~}p#-m*5F`HWeY_DCv_uoa!~k7ZV?OSxX}yWZrx-r`+@%r%hDdQ3knkrRb*aot^N zwc~Wqc^*U~Ik^_;7St3x9e{oSP7FBXZ{*`7x}Q+%OH*Dj4xRuol1bE8vM<^>@nHEy zE3|OLKgdZGmw}5)$VqINsa`B6Eu&_hYc`Rayj5SlJ_{^Mb4ly8Ynd-8wbiKw)zn*H z!r3^9`Rv@VeJ+|mRSxRh&Mus+-`uVB$ck5ddZdbaWH3tDIfK%b9(hd4=d9|o__`}C zu1Bu+@F{U{PeQgglyh<(KBELESfIE3sI8miC`~v)nx`+RW>≠IE3!)oNx?d};P^ z@11;Vn?N>lG*r%daZnim+_cCG39GzSZcM4myb1Th6>x41vV+Yi?k6k?p-7P(5d#1& zA`s6=pbY}W$fj{h;-0KZ_Wgb~b$@oEOmh4;7~OLx8?k9PdI`KdpZ4t{uV)KOe^E(! zt)RSC5Cv6A|E6Pq@5g$Cjr@h1bu-^%?9lwUs1a+(D@eSULoa4z5}wE6cmtmG)DWg* z+_^_8To+PL6;V%>5S=aT1h{@&e!UcYZzAx2(sTHTEU`BFd)y*0~@(-b#0bjYZVqWOe}0v*f|e=w9&~@Ea#!d*C;xEPu7yTz(@0I^@$SiF#5Q8b|+v zOxnF=ctUoy`y)3H>3 z3ardjSQ$=M4jz*58^Qc~?F-E0MVqmJiZ+{KS;W6qDV#9bB$nniK87hZZhMheUF^34 zT_(`#(I*WRI)Zqu_^4Fm%MX1eT~`q2IWyP zeM5dV)g@--xlr^HB5bt7?|+sW&CjU25Ss0{!DxO!-)7+UCZqW-+?sYy(L-mY@kl0| zop&#(!`Wv>*BoXm5xz8c$_{+OQGM5ydu4A|huwO60;zPg=^zL4#$`jefe>)5^m@&; zz-WA}6pDom#DS1`IG;tv(fUhq4sRf+P3j}?V5hxfo4p6DEU0?)0j3g*a2isUIxo(y zD8Z62ln@*UPYKaT>7m^P15Pk~EtnQCf)W9(s}d?U&%Lsn;?O9qf&ot{9oXS1CFK-S zFD;W2S}(oUUv-+Kmt?E>=Go^`Lv51M)JuuIAt*}P2IebYD$eS%Dv|ZS!VoPPc{DL#kiZK%}?A@+O}hq%qNSUc5;4mcs$~QNHOBt zfC4(=x{=m^I>Ymnez3-Ja&A7UM0k}PNRFh^GE)^6c_iK?{iQ|X@2N3Fsj-ANoSe@F z6Ks~4<}WcECBjb5zc%rN6?`?@9vC^b6qj^Z70We1ntpea!VXvtjnK#=P3UsqZwcy& zv9xn8Kt08SKI@oE@vG+JJaT*X z=m2@fWcxg~quvi?Q+^}qfWYiW-`5+b@!p6|mELkbeRY*?Q>M(`r5x9Y?_1c3{q^B(+-J@09s`}s9c8G=& zkpWL>%=KlpfasCM<5WEE%345z2uESTp$!jeD*smvEI>gfxWBnygq9*yTsI&(F z|EsnaeJ=;-HL>Uw_;QB3;x2fnH)3ydl6UHlhn%MT0*+R`Z?_K1BydqHMV6japA~|O zTETl@uZF)7u3`R~1-XU^N)V^`xSDStIFinFlmO#ajY?rB^N=t&_i+>rJ0^DPhpGM+ z$tkJjI3|$?h0-T2=N^x*Fo}ypg{!|Fg=Cs*gXQ>4s2nal56{c3Yl1vDU<(R&JtpL? zzv8q*`AXO^$Dy{=`Vww;*!swH7E2|Dd|MgvZFT?Ls!Fr-RgEex8TSx%BC- zuBxu8uCA``WWIvR)A+wUJh&JqQGs;OdC293PmA#>J|A9K_A+oTqhzW4&Myec?@MCR zGIbQiCJ8c=&$--_jfeSi23HYCFZ7t7x&b{T1m6M1O4!O>9YM7XmU(lBlSK}a%L7*t^; z6Jy};Nm;4El2IEiXDHqCX;KLTX}i*LJKWO)Eh*7+LBzTTp6(6AQ$5<$b71gxl)WhIaMFz0WB_Z6ne=E zdXYWB3NSVpV>{WVa%6B0?}!wWL_Zk-_LkEY0YC;EsGIM+`i zS)X{r=61rjm?bqFX)HT3c;MvvUdFOf=}ZG0JaDDa^eTG53}ddRfsPFHl8C{+tFe36 zrKi;+-`z_Z38m1;>eyF_AN1ltB0~W{p0gUf7^7+-r*=S=XghTvk?hjj6d6q0^yk&Q z0i#{lCvzHb4pWuP(uCxa1g4hmCP*S!p-x;d3ze(_9`l_=`W*H+xqw7$0|c0e+=SvA z00e;b#+R&ZFhDS-<=cd%!mR?cHmvm8y}skV>s{mrJNwva+NLgl+M_PT)`;2Ef84Fq z=cbyTmsJO3g#(sYi=8jV+1h-hKO0WjGeF3c`NDa*4jHp#EjddZS3@(PUO4v7s7 zr8*6-M2b#xuWVh8D~_+k)OrMKYquX4@`&W-c3c{<+jO#Lr2K7(IU)gP5O9jyMf3Ps z4VuTV|9gi#{$eD7$FI+c@%SRvCOm#0%KS_ozmEGI4#i@6S{Uc?Da%vv_!h(E@vA(q z6_5Wjmprc3-<5R;^V<^n0{d&A`qa%%+*BZ~WqJ6H;*@w*#tp&=fm;|iR^P`RAOxEA zb9BD~!SFoM%c&EWkT`MT4o^BXVfV~ZUZ0q=qDV!#U&DGf)L+dg_XITp;g;ppj#2!$ zM3AgR1?6!K=}B2ZmLlu$AFs(ia-A$FKzHTUpkyU?6fYwZ6*$o*;T-fVOH`$E1=eTT zPA>IPJ_k}^#0P1?UQ+WT|MT;T1_BuhLDyhdxJF+)_Ww7eZNNVH^dGWeN8mUxfb~QO%`eI=eD(iJ$fBEe*#kZ zc#yfb7ykcMeJ3-AkUeDI7Yb%4?XOI`C9Zxw<@h<(MovL>&i8#}7W_X=nEvD-LCzR6 zA%8<}LH2H}9*hTrVKRU}nJZ5B0ckW4#b)IYxPCekbIYxjg_RQgM~FC#U}M&Dl4c!G zlEu$j`6<~t<$OdXW0Ta|MrbZxSPc(kNc?#SH-0PQ0i1<~bLBSI-r~0cPk%oYNAe6U z*);78KN9k1gd3jz-VCiquA{9DFPJ53Cml&SQb_KHAdpB7f*D$qyV^NgdWXGbwMYBI z893qZy!7&tO|{)oM}`?%+bO!tu?`mmG^(E|>Sv<-=z3|jCe?diBha-O12H-N`+wNY z&~6{`1@VVJ26oAh8T)v8THU2Ykm(|>Qbq&UZvRp2!pcgObJ~ ztjKX9FM64${Dk`b%Ey!pNR8z&H+Vm+6{$2h&>N{fTMQa zle<3ihT5aj{UzI{W&3e46bC@hZe$-oIc^n1g;Sq`{|cMy=twI0aoTa=jCo;Jg5g{v zvpp^*1o;i{)fR>N7asN+gqnK@6d8jt(7h=rgARz2v zC9=>2J2?9oV4dU!laTFUH73$2vGa`c@dL>~QJ%A(F_q{5Mv-2gD?%?zUm(UK%Rxgv zuQbE-z)QRtQHZN*HYI&Tb$LEu*m){NRRD5D8D2(4|CFi(qH$79yK#-aF{%m6SwYkn z9{`7hPbxk9=T%DNMy7yn&h6N>92w%S^CroQ=LktcKA=G@;jajm1 z%9XWKIJ(C{D>TC)24V4a?Tru=%^7}zsTjyLw*2HEXOzr5SP3)Yp-NE7EAL{JHy{LG z6P|`MK?Aa=kmAU4Zp@YeyLc*k#j%SnX39_MUw_Jxgm_Dd zcos$nra?i8Qj;hdO2LxWDJGH=DjB~6nB}aoW~dbi3jIn^zzD6x^PyIsU|HKnf63;l zw~}sUb~%Qvr=Ert)3G9ulQ#8O5=jwDp9z2ovN8n6L%pgvOd6gvj4;GylPrfEzjjKw ztN?Jq6C&baG(`VyhLg+tF;?>&qkUnDJ|8&}20D5IPAn*ubT-a8Jp_?=GysunDaz$v z68~SUqV!0qQ zfU6Om2)T)?Bg-UL+k+sOA0PRLmTaAdsnK8{ra|v<lx*51ccmX!rd$2gN6gU5F4#yy)W?CGbp>Uu>{#=O(x}45c>pOTptV;S zHZv{YTqAr|?6*{BO8r(Z?hS2Z4g&VcH?(Bqv`dpafb~5^sxgS;C22s_V!z#|b36ED zVNok0zzwpwwNCvj;O;3Q^If1n?#uO%@R3M_B*djBb zBrGOCfvCfzkA)uOyn9o9oRS2QX7HMmc{{j{8yb`NZPQQWw?W_04HIM!J#LtG95-bc zc?{e(vVhz+3fzXZI$RAXgJZ>La=>jv?U4m-{*rCR?Af?0!|9u;*rH+C!B}F7FUAhN z{MINm2%CcJ&_r2LW?$Y`^8VC`W%d=Uo1~+H_Ykk4Wje5;gvCn*i`Xp?P7%;`Ma2oI z(=2o9oCAT88xs}=Cy5yA`5Xfn2yiG+FT**WL&G1rZ>N5Qvo|5NV5lUw=*P*~c}~qCo0QRjG3xi@ zsxqQ?&nMkZWf$5 zHye9{qVt`sOwm+#XUNZ8>L;XrUaALf{{n()I|s;w799v*DE@<=b4=(#rNvNPE$`dI$4%|9 z;HcvPAI}>td9C&w!U%vrw(3aZ*J=k@r3(V~xv)&u*Bt7&VF(Jnq)P}k%%`hjRbO26H z`&kTR-k>h zi}o1PC(47&ADR)eX=VS2A7(E^B7t`}xK1^eZQ*drH&=d?VOl-G+Ws8K5s_IkQPl#$ z>6s=NLsxQLq~
    JqV*)dlF0B^%?8G@9>6L7r=z*0`bWcOq2laAy>okL$2&7|lE?eAWn8QRb(`Z>~@ej3`)J^G=2`NN)#vai{f%Qjq{rR$~8 z{;QEQBKjOMDAjix)bhdrG!(rT0q?vyo;Ndb!RBQ%t?cDHa#D8zFESbkRXZBpC&Tb0 z)QT!sM$X1%ypu`%y$TfqA1%u!5_aYuUgMxX-F4%;2e zb2lk#3v}SVB=}}ac1*e`c2F79|J5W!fu(;#-I8UVh_UHLkUKjkDMgb{o-EWuLgwzS zFVgwjk6)<)@ZMtZ)w-3L#LQdH*jvC%1K80-{*f^$@|x-dOYY#EOH4cOA^hL2Qs;K5 z?`K_{p5L zlK3?#uT7#1Mw^*SBnpCv*UkQMf(+7z6^i`q7rPrc@Sfk^>fU@TzY`ypJrMleJ)ZU;TPJwWc4IO z&Sw+=_%!oGoOU}EXXg1B2NgVu&NziPfqTwXqNpAJ z$iz~2YGrM`Y4=2u$(|bry{od-b)IyL@W_RjS3;529uF2`fp7Hdi67#1X5F!5r+Pyb zn((eue}G`mq{-lN5Yo=%0;${{04i!&PR3vu5D@JmfzvWCPTtu^(geb9 zMmIWd$hE23hA+)E-KkrcQwX_tko28%%(l39M~94 zeM(l=Dcbtiy;&aP*@@9KA@09+mcc_6UcmlThjVZR4=AMYyK1pYB*q?Z3bXyc;I z_6QZolLYy{MX#X$AIkq*4=w*&Ww_g!@BJ}B{@>ur|AhWcydJy@b;YF_j1Qmd3kC_5 zbfl1hi)ho7(@YDQrEZ0oL*$8?3Aye)r`rN83K2dCLBMa@TB0u!>pl!4bG7r?I1HmE z8AkE;ZGXW|70fw=PLk=n7m-xqCzUVJ*1zzED1Q&M6d1)+zAKoF8x4D?NPH?(KwC#Z z-!X8aA8Wyut=nR(6qDl(H=dUD*=ueb054AYhuYz0Grr#Z`%Ky6#TMO1|j z$k5yaB|__AzVt2g_0?$3%6@}CpvpMDgoO5dV(UPDRX@H`_4C3pq<%p`CD!X*R056c zydZJbKctMt_VhK2@Ez2H)=cOX&`xC8eJ3uUrOH_+I+8E--*OWflIu=DW1&Je25Xgz zLGi=Vl}gW#_}c8-e=zrc5U|h3@i?tG3~^6e`G8H>=&%=+SER3x2U9rD-mAFEM_nou z6Jk|Ht^~l&CI2O#JF~}vuOD~UI>=yg{=$CeiGJ{RA<30b{>~?FhFfHuq7N$Z-@7*} zHUZ}b&^M7@Kr));SD`h9tDQo$5`9c*fq4BkHW#5~#lmy4(81}umynae!i)F|7M5S& zeFg5_oSF5I3qc&?(QE^UIP{=tJ&{{r_gnV^(9`BZg}K(5k#OxP6tYZ`#LFQEh$Z37P4fK zEPo-LW8KLhr=Sz<$P$!dG$vfKh6+M`oaF8-1t-MF!if~gvPpiyWb!hxJ5p~4 z-8qWg86%j@{Nt-4J|5p4f&D@aF*1HqW0v`E=lm1xr=N7i8-CejO4B4Hu%alfoh zx@;==NJZWnDdxq;PWHtfvV3g9QtoD{laFjwWwz3i3+5G2j!~ zv^#+x3DN}jbv2qlz}H9!YBYxAqKnb^qcjH1#qEywshfPALjt{uNkGsWRwQK+QBZet zf-#Oq6dhU4lg$a@1Vb~QRoX*7UYXG6!n<9?(O6KVdsr-ud&x3OeT}A5sgEKo8pYVs zWJV55QW`iR!Pxqiag`QFE|?MWTOC*mKyFV2^(0@)nD@m zRnBFVXktN%s?|Hn8fsm1$HUG0WNk-RO%8@@Q&hd7&g*Dql{veVf*3~;_$Gf^o+Saj`NpQ*69dz|B zEaF7|1>EYkFK^fOPStjLV%uFjZST=-bH0=;xa8{&+CGeJR|#EpUQdf>!-@{#sKDr! zFCSLIGM?-nnd$DDL`UDJgP2aO~WAC5)p0fKrxA zvi&0YU@qY#C1DQ0j#k2FVKkm56Br6SO2!=AA$>6RYZSj@G<{3yxj!2RasU+j@*i*v z_auazRl*2FmUKz>Twa98?0ORmJ|%0X#VYVUd{Mv?H znAumuJawlFyakorTjz!-ZM~$YK{yakWL9pbvOYcyP)z@jf5)QDPSL-$E1g~c0KkJC zIjRcNggPUs0N#y*gQgmD9Q@vfsl+$PN`uw2Jn(?9iyPqUyn_G(CXUUAKl25JEy?2x zr(RRbL>Q^!zhYKjuF`ZvfcC`W^!{8J4Nx7-bQeoCT?e}(asW@9J3nVP?aRM`Gs>88 zGWrtS-^*xZh(T!8mq9oZn$<=R9o?yTaTHvM+w1G#S^zJ@)a9I}WVK;0L6xS3Y1?f% zNc;_l(}7yE+$!C!cF17a+xZ46QG-!;G?(j(P5V+n%*`hDRiKCF^{VLNBxE^nM^aG4 zSY8QYjOrBnC_nUZKC-%}Lb3@0m>>Wq?9At3jjH6$+qhBq0CBCjXk7~0l`!%c^=eniJdz+W{yWHDFrK%{hQCR&d_>&V1KqkC)7P+f zh?RBIL(u5VJoYY5DP1`Rj!$!5YHn?du4mmlrEXdZeUF``rk?Rxh%+DMSQ{aU^pW`x z`>Hl~Vi_s)5zfQd%!R&RB{f?3lDAQwH|d;@$|99gNxWUo5U=3dQQ>$~z-S?u6+Rst z6LkO(TSsCCPJgU&BK0#8c+>k}1@8V{#Y!2CJ5d3*vP;yC&c}~U;PzkfoZH>R+b7{S zbyfzDKayL-Lrr*V^|3IRv9#;vZBS>AhxVWBGv=@J&1@*>>0FIHZ6M1?upAr}^@r1d z9*3PBSbJ8O!EOi-CfOr8Je}s5sz*Bs1x6LVAIT9G+IKQmL}mt1bq1=AKIMGz3EAF@ zK~{1lD>(<1MEZ%CNkrOJd|SXK)B$OvFb2php%n&qk?03*dq;fXVjk-h`V&5}28T?0 zGBARm^m)7=8Oi_#um&5)fIT%G(NmR-pbGss5Qtdon^^~FFU96nAYwFj?4lo4KtpB8 z#`?oJ7OPFWtW#vN5O=<2sy>qUUr^DY`DiCv)TpQ;D)8m#(7sb#bo@69=veB!zl-Q_ z-j*LPR^VB$d4hc9TIxBd&-tnmD0&qr;(Wi6BT}ZAB(JdytHzLLT50Z@;#)4G$3Y3K8DX%GZZHm(#S26;ZreMnJ_+fy;zG)nSsRzo>N7zuF-S2ol>g| z$7g4HM~2MtPiE0yw=epirQV{wQHRrsMSGwqj#`*>1?E`w$s_ON+1`)1aO1oVw|iup z%pBqXqH7y0Z_zF+`Y4M&fufklwX1qw`|=Z5{*LxlU)#Ru`7Bx~RrfSzoFp=~moeiZ zpftFzx6!nVIC7Odw=3aZIU*tW^ubb$qhl%wI!Y1Mx)ep!D%s&i(=6Q34YrfN(7iZd z{sf^N_*f<=o$iaOhA9XSn>y ztU**3IZsA{2NsBL>>okx(Y3*S0QOp_yVRYnN$708%wD9kD+p!NmT5y0Iw=+R)L^%; zh|Q%&2HM!l9T~*K=%2kGQMxqXsj~|tabYGRTJVtKt%l-&?M3GW_hn<-x;!_LaTGS{ zI=P8UBMhOBn}{QKA}BmPYPzagDKUI%RaSfE1RjCuoT7{FWW^Y+1n(?dJ3}>ix(;nu zY?xREqeXOer+U~_acc2Hq?SVdakAPcoC1m7^AvGDgsF}-mD_hJksI#@KQ83QZ-Tnf znf8cpc!o#w3&L%5xx*qv_hA0$c(jxo%JKJ$z+q5`l1q;TcDZzb*)m;+YXVjgn%!2$h zZ2H`lR2_SGHlg?e2$yWL$$INoeEX({a?z#9MNVRoC%r}N;JzHA5%D}2#=S5DzCDGC zzk^>*^n3;0H_b5Y^v$CZM6(xzGU!0S9H*zJ%lNVq#DIOfnaOPu2{?uA9Oh{!vO9(D z9LQ3RCWU4$%*HlM>BPWC09C4i!a(9QGyy0ek<`j@CdmPd+Bm9B(P_c;bWbyptEr{- zcc#vSg66X2ob@6IJbc4mJHO?W`WGneZ2mVH6}|vXg-Uch@#FB7r?k5gqe2YdP4{6h3h}m>xFOLdXV+Pk0c_Kldk`(c#)--B>FQr zu?Gz?368~!OnFa)jh*=Qr)pE4YOV z7TwXxFtRH1x)us!vPYKKS@&P!j#RJ>X5g}r!_@``@f}OGfm$K>gsEhNT!N~+b2eRq zH5QTKt_P{9s-&`_=u2M6zDs~iglCtIAp2pY3z-0w0+QEmS1kcTF~W+bc)1^_NpqH< zNaO+;#zI0VcXvWL!B3FoewkG6miFbUSdK~m*+aM8lJ@0_SZ*82g<5;mT^(xeS$A5f zH5+oYJn7r6?Z5rcZTMD&!o=Hnx53*tf%%^-HzBFMSKF6c%yPq6&dz-FK~|#~;4oka z-KY|2d`cFgIN+Pfg>UB9vEGrYqlw5lLUj#~{wT}2ErA#K`DlFpcJx)})L|F~+;0}2 z!zYc0yHPF111#ID8KCb3D5`_ZE=T9zM6ra_dJP?^`? zApX8b6ucn%czgwT@hL}C7$cbDop+dpWM8s|0nZqS%(uWtg5IxsDS-m`xu^`5&S&%J zvvfzVr=vD{&EzX_m151<8O(-JxsNZZc~!)#al9(#RSo-~gO-+?fd8CS@Js5i#CSYZ zU@Cm;v$qt^(MA<&uS4gMpD6Sa+sEkxrX>LkqYd;juf%U z3p-e!&VgJp;bM|s*r55mr_c97loMp;7|lVM2f@aE4>C?+23|UF?qoB(nsNMf6dtoA zvny8@Hxb2%Ub5#)`4VpZm6-wjN)EC=Xy!u6^}-B#aSJAl`f_u9FW0!I3$y7|0tHu< zep`1YjCcL^gUoQo zkMwe7vBuE4EN&;MEVpYwAL$K(Ecek`XG@U+Lh5p`^Ik3KkqBz^*?`@*cB+9*EmSIS znUN)c8muPh{0}*5pcHb9fYBvrLxzW&xandXWmN?Dko@6zB!57kYVkh_HQ{&2HZ=+) z;EA1$DKe)_K$EIft%$j?`(E)kMm%CU;@TSsxv;8Alw@VTx)=>YJ^z#SU_L5jk1uRp zQ0Fd8XkxDO6#*l#3w*`=wX&z80`PSqW*bf8SjjqHp_H&q9!>@jrApEX$iR>Wv9LR^ zm6gZdd;5*`KT=5Tk;?7ks>47<6N_2MBo=J1V&8aV(?)gz%9wM;Dx{ z4z}u44;Dz>oUiy>qv;29#8_U_Df~9q3qHkq!8dhpg!hL&!&MvS&Wts?4PdkxGd2>7 z$fIAfr#_Q9?=dK-y1(kc-aE!B!h=oJgvVGGC^&a!ma#lgV2%x&op358xRZivC+cZT zxB9MlM8+NR!3=P6wm+IS*_izaaHMHY#*1x$6j5n70~Dj~nbiW~IoklZ^{b2#v<;)YCY% zhRXv*t^bPKMN?}5`xTR6BN*z2T!4pR5{AhhYK1HNUdVcx^)(&?9|^=rpU1Tr>36*c zzuQsM+O*z8D90PgiRWC~=b z;ATZ0LQEk%E-suDY;GOVS0KzEo9qg6SG6m7gMpmyjOv~&%qLT@U;w-6l_|`xdsvw2 zBqhx606T6^*)H|^WH~IH5G6|VTW%uIva+nIjy|tWgA8C78A`Ly#0Xmv*nDfso`OENyL7AU;Ujcl9{ao{qJ4N5r`V2;9v<3^{xF_!-tvZgHDDstvWdTGj$xNa@w zs+`mTFWSH5`Y=S8)^{DWCGvpC*X)ePw7ltYt!F$C_iNJ(${K%aSrhn!box4%d^`%b zy{!2qN@-a$fP;mCMRBfT))=08h#030N*Q$ajfzSHgS)tt03w$tDjwr`9}_^+o!oy? z009e;;~;_f+Yi4;w=CyKi|NDKKm2{12gvK>)yNRchTPMm1BeH}MvRUneQ-a}f4b1B zvQzjq(&{6~_sw;0XgX2kiklMUs1b0$JZFW*^4=&IeqXI4yHr}GsMMPjo9L368bP5i6_tW0m7o!@byS;*#MjeeaH-JT zNJI#gOpw{0A~Ay8=QM8=jqtu4)DV6@!mPgG*CKDD4j0$w9U9k%{X|@&-2Vlxzj;*S zdf!zZTn7c$hjB!lmm1f|jdV&s9);MR z;Gc%d34F)X!B9>Kc1dk!Ebj+l;R^Nx6d9NXu3M)>22Nak*A?u?;D~03jPD}i7q|QW zY7y~|R7R(b_Tb+EWNXuM$i~A`vvKYHalx+8kxFD#pj5J87XcG9$DUIm44)(j_OW7g zDdRFO*i|#MEYI`2kMZ_&=j^p91^e5w2Ce3_6jWLIYXyj+W@NYk0R0~$H_fPjk5S{y zg;{3M;3Q$9n#gXMBvHyKgG{_W&XR+F^Z-91El&~d8kQ@x;#3jGSkq}hMWeTdPn%}i z!(qh?%dxW4?;|ct--iV_0yFyeQAZt&iTNq#G?)^N_#-I`$5z$lnzC!tP*v(li86g) zFgu@L$I^;9qYuIK3E!Mx`na3_X(8r2rD+|TK8n3*9G-WtFiXFf=>vSJF@+Gb*CM&p zBWN%_$haD6w;v~k_K?pO64P*Cep!`z3|)|V z44pb(&~hXD-l5v<-wma(KQ;^2t2U0}?ifKaY!iMRvAH4*FqCn0tQcx)47m+p=VLn~ zY5z5f#X02NvE-JI+ziS%&MJ3U<=~d~QWh2T2N4Ofv->&^vHNhje07s4ah&Lf;NPa#&Sa< zmCx(6AFyK|jMY|1{CW$Yu-M}yf zXz##yJ}!VZ6KiZQ5|CAP*H%6}p{LrKohL#swM1~fZXwwrNU|Q(g2cE~(|2te5+J7j zEVS}V+1+!}9;}nDWde5OvgLe){}>M^K3DB|ab6z;|E-Bq?ftjnuRk*vA0?dEXe`UD zoqbMPY5K(O^dHy2>pyvQeOKpWVbZmkm*8c(b9}?zHfL@T{`{j`Yn!vI27h|pg0(0+ z^Qbx=rlMC*7+I5OOb|@x)9qgfE%PbRu}+YE%yqr+5u>SKaEyb=fUacM4CQ%I;{WeE zTCTYaVD&fUdNh3f_K+uQ*&4?rSq7Wvs)cWyHM>*`*iA;Mhw8*u;WSpbhY2on=5mNs zX3^W2_X}0VC(|Q4Gk7fl;!;8!pv({a1W4jmvtN^IR%-QKF4x@gX7}$W0D&to4>y(b zHV)M(9;h(HfrIu?-99G{)y+pFLY0;Zsv86y3aU#q$_Q1NMj4@Mnm{yl0M&wz4~?r` zAiImJ7CQR@xr?i+Yf|89s|Q!FdT{lG2UlO+dJw2Od7$bDR~LAo>YW7Dd(|nRy3zwx zxd*Bt9;ikg465-T9U50F>^QE*AOO^htD;m;tvff)SI^3|;;V<{TJhEDnuFkK+lO(e zI>Obl9;lYdv0j>jR%TbcqOBg3#~hL2%-3G?f#8_|X;zQsJPss`haCLM1*8W?bM9NJ z^?Z&EM0sbgyGf1aN*1m{>?B8XC*83ku;!QNu)}IJza!UbG{1jK(rB(!qxrj?@&0u* zn$MXP$NIyF81!O&>aB_w6hH_)#oNqVrC~L0u9Rzq^>Pgy$4!L*q{a>AG%#5yV>DFN z9;iCP`jb{1s;?zgczoPEKHdwJLR02}vN$h%Cf5q8t#Yk+VfoE*UT6o^#t#mSt0O#6 zotp&J=o&9n8dukQpc>(U>P!z*0}ck&U=LIs;VO7n99Q>($GjAraibS1jjOMGaa_GC z*9uqbjB3p`H2-`wJbO5}s_;Nn;(_XT4^$g&JP5AddoK=EN4P5VK=tqJM5uf>c%jm`dh@I}uKpp{B)Qf1 zRk^0vviqNYFsRP+K;_CSn5@eBD8vPfns_zmcgT_^v2da}bRMhiFYN#l$ z{_y*Q;A-i+hsM?SGvZK9mn|A`Ztp)X1+HE@Gmfj}a;^C4PjapJs_Vg^I?4l;iz}kY zYpIR(K(&>-Sv=OqzY-*a#?=rHR0BLvWqY8y^@fAss_~se<7!h=99PFDLA8Hu3S2$) z8-*+IQuY&at&H2h$hG3DcgGzBsxNoMp>lDR%vZnhKs5>I@Z##31j(Rrb)*NXz8M##f{gR-Xn;;o9uChH)b@M=#>4ECVgF!XW164=3njDJb>Lz#?y|{XAObT4x zUmVBPJh@i5nj_Z=SD~>7!PR|lADXW|x-$;dtFpEmmkc*2NCu6obPrTNoIwZ`RQu#w zLG{J;2Z1Wh164=33V5LEl?2t@GO1)ZUfc}Ld`MbXR$sG*ic+*zLq#ci*}?Z~YL2w7aCL_Vs^58_`qjapI?DrwLPwq zrRe&paa{cX-;Ebn8%KM&T`iYnPVzu?ora3sexZhnV{q#=2f@{+TjEf4gsam$P+gb= zRsXBKP-(00!_(uqdR?v+U%epLim%Q*7*v%Ws5;`Sg;V0VdIX?*aaEZhuQUa3^gwl) z2dZ;DQ2nL)Ah>#Q^PzFo#RHY{!pHflM*?5L%mK`qZ=Dv$)k?WmxcZx1D_r%8L8aFN zF?W`bPDHjk1srF|Bs31w{sgzV)^&@{GZtA zlJtBHpC8@+`ICHJ!>ufd^~~q|VRg)=0b8;`^a!(%vZaNk6#p*i)KgP1{*!n&p zR}Lb92`Lz<+g!Ob!?gM^CO$pO3~!EZapwF*udqBig7V(GCShle zu2ec8ht?q@Fw%hfd-cP7J}l%z=kjG=V421V<)WWQLsYpdDJlCq`{(wzpQ-b$r|22r zi3mK2fIoPd7jRKt$j5l0dguZCk>>^QjlTfkm$-l@&}ZVMpiMsaYGCIF|9}dGf+t8@ zXn8K?_q$lB51Eb^BJq5V8ODMMCUcV6m3T56GI8@88aSL_(9#{ z=|$lme2-5VlSZ{+U5*Q+j6jx=9d#EB+JMy0e$(O_{zZU*8E%=}__ey6K`qEUZ?a7Q zg{QQdS|>8K^Ufn129A_=e{F= zvohi=3I30ME`4v2T=nc7_<1A%W=j2ywG~$0T&@sRnwvjm;+iw9(xoK_rX0S4)(kpU z73Xi})K@v~ky9V(>bXS+X_S#uf2q!?|EBZUVlq1VxCT7)`~~fq{YH64N_m)lUb&ZN zVC1GbH$5vnb6;QdKRreNnM&ekjc1H(bR3y#u&XE`y}yu7jbOl>o&x6O6<$8q19blR zUYKD5r#UY?BQSpiDIckD`P?0)N%Y(PbK$>U;0O8CkqDrdK5}4n?YY)y9C0Aad?e!9 z+S9C3eFR}k?JsfU0L~!9=?QsO#@#rZFg*Hc964~eKkVm6uJCepKdMDkTcADFo|k7y zRLeHK7!ay0e_AlG^Kf9GMD$$aq73-Og&gOM$;Dt*XXNTH8W8I%GYVE2VlvAs07NwGqCa{3%xi~#z<}m4hSB`x zs(B6*Yjh_deK0IKXbJ46>599IuI0!@LHChNLsx zF6H8#x8O_n*7gV+bb>N%~8~j##6}dt{9$mRKX6!(^^2D?}Nppl3;WG4m1QnstBsc%sz*?jbA2`=*IQk;~32?xqWhn}$ zoV0w5=}&fa2#X0=Dy__m6)Zjt3!vN)d0p&sYA3=n{j4}FcHis9>i9;q!D*<7N zVnabLlKAUcvQ21r6~|;H$7Cg|u9kG}N0EsjUdDy@O46Dj%i4Wj#hDA8jb(if5AH{r z$!qu!9D;+B5gl1BcgR?bL%NKo4zL$BrrqaWmf6T z^3aFJl!rG4!W+uuG=;LQAD1;9Fd9Drj;Mc)#?8bQQ$1Oei&0A<&gsJ;&alJ+IJmXE zWdF2ZA)XV1Z8A0|W|WJh-`Tk=JUFd9JaTSl@YIhvG^LyZ~Z|B9w`}NN1_aE$fuZE2sW2P`3!gkJHok7i?0S zA+M*;cKU7=fcK=>Br??xl7sEwbfhc zG&2C>=iivXkMx0o4>0H-4Yp+qXZ)5Ufz>Z5hN`%KhNcJ zX+?;fFEPtuehh8(U0CMl&2A0)DB7aIqdS8l{Re4+?NK>Tr&F zkUi!B8ZkOHS@>8}uxZPLY)}hKRGI59*)qX!y9a5SkMF~q12`D^(sHZkh8QSS(G@21A}^+&t7Y0n$~rRzvPj%3RXjwZ3HWMgHc?7u*g zm8ltl@D*qUc|_5QvFyP`_-VwzdP{Cc7o5=eZrv{{n%sp0&PBLQ=LbL+o^3~_hI!zJwJHV{)|HlZ)7P-3)g3(tmjTim=!6$l zi+8de9MU%R*Rsz}qHI=v2)6(@(dqYFN(@(=xg7!ILS@;z&ZE!%$9eRA;@Mb+SJ8$1 zf?ZY;G`%BGc(6+|6`kl(8mGbiJSIdBNwB1i4tmJuOF=d$Z1e^5O#%$NQ%N=oYvGHH z555v{0$meAPt75Cj z>-2lZ$L7I_j6TmL{5mQedTJsL?kU++e+aak>uvE0wCL=aFES~jelEIK?%tIO%#hpQosAipaeGAKdrdA9g?58I#>1xo`?8AmWetX4zG=~90++UJ zrr^m!UY*8GobI5&IC!OCgp7m{a&~ZE8?waW#dj++jK(=qLbEtc&hheqS&wC^z)-p8 zwAN>|ob{5z7K6E+hv|n^)z4I>j>aWU+i1>XMd7&=3DEK-o2Ou~Ea07KEmZZi#)TRYB91sUs=+f~+HqN-{>x}-5JR`NQTO|NtE0o-VHD;!v(UKj; zoK?KwZWN|x6uW*xp^3dub6)3t>< z;lvj+V*rdzvLbh!32?3pz>O{S*Q$P5rq2ad&GRsB@kt&?PU@pIWr|{ofQdHA9)l;| zgV|@HZxEnF0y^MgK|hf>wTl;mW=$>Db4u|SxIBgwyhLqNO9OUjX_~}Z)%c2h0sY^; zC1?HJGBO6;!=Lu=-TET+uzXXzwlf#qucVJj=~Fp?{jf8)Oo>Y$%o8X+r~TmiGnF`Z z#ph+>q;Z0sFxno1u8oa0uYc3_7qlq*{}kA>u>V`wPWVY>)WiN4j<+-4xlc#?5BQ~$ zbuhVLSXkN9uW^^VjHcDHxI0T(3)r#Ih=c*x$or}sj=EZTuXC4#kxoG|H>%<&w1@mx zIyV^NUp%5PI-Pqqx>IU2SInUTuA-Y)H~~D5`Dg!s@6juXKoq4k2wq1I0Qk)rp(_B} zP|xABeAmLqv<7)k_E5^~p_JL<6rAkl`rz3&*sm`Gf_j5DN`T6;pxRr*-42TcU+&R1 zDmSH-d1E!Of(A{@F$?Jz2~bYhu8fH_cw&)m5a;JLXv%`+06TiZKRM3a4GIJ3x5j`B zol174kW7pDYyWq@YKH+4Y((LOx&m}wI||@8Zz!m0-~HnUCUk!^<*r@@trqP`!i-~^ z7|h&hg8m25e=GBjtKQ=8aEnAo8!>H|K*lOo(3vdLi_5bk? zKKy7Kv*dlFX`4KUZ)*Df|DaxD4iC8%@$>{Qu%&ceOIlh6uC|$>A0hbf;^PO*y+6V? zh0bQ?)oI+u8LMQy%UE%&ptGhKwnTh~L*#rb^O38_-xg&#oHm%6&EqB6VLN|eJ<14~ zzNQ7Yu-#oh&I_ZzZzuP07_=|NkAteVf zvo2tK0)^y*?I*KBuvFwF2pkkVA+eyIT1eR^V`cv&i@Vfs?y#eiDNlgI_>J2S>UHD> z8s%ZQA6&yiEV13cQiDELJ~9C1oa2A|x-GJlwr2bDZfB~YGuIt7xlDP#jj6jz0@nFB zLTdG-)6MYJIar&4;|D44w>9iCEu~;fUYnF-hP4_Us1E6MoLM4IKa?MjEaT-E(_Oy< zzV;}2wmB2znZ8@vhddK-AkP$7u6A_og-gX=n1N4X-V3GE<#0OabfwI#6~Y@O2aM3g ztbSd_`yd*0`f4opHS8dg7YSEf?jr*$M$!g_Vw=)}wyhZ8IUo}zR@(d?2m91$dKCir zMOHWHU5qeLooTe(TDb4H4h3)q6^r2W3}=R=bY~WcwSeu~BVfrRm%siBy0!`){esav zBz#-|0;8IPcQTf0E@K8F!Ury^;!JfkePbBg3k!mH8bGn?0LCX~Sw_qN^+4}*_R`u|aMJPVBahK8bA|3>+0TocTg%wR-Og(HUPR0(Dm3(hBl~DSnY)~3P z-LYyKZ@>umhcgNQScdbbyL1-?WVf3fWatd!kJuIpWa0}NC60AS{08(W9YR1`ANhg| z_O=l94Rr1$4S}C=bX_-oijL5>5KLM#g?MnC8pg7j>?04QYQ`^6SryvXR{xvuMviZg zNErsSVlERyC;TSc!FgZU8AkVx3pPqmj@-e)o4_aB1`kMU0(Qn3vO>TlEaVo>E5R*d zkzm!&g$+HgiiSQ1vqUV!(QY{R~)- zv%!j{T~jm4!}YkoCaVI}gNxyDRuHhBR>fXWa3N(=07!*9fNK#X2Pwg`*D-E!Dkrd8 zOsmC*Z_}Kq5|OQ0ROklNDTp^NwNmh@Vz(fI0iHnI7f$RzPOq!54|06&tW z6>JR@h$I{r>4F-ZyJu*7nS2L~CUUOx%wDLRY|PaYG(cSb%lz@L5Ft=WkPqAn3d^pB zU7acQ$%!}lb)@q`OXt99%~09HoiXL3eS1$k=6H^OJtRz)C`AIhvlck_KB+)ico3f2N7?gXxuf7 zr;byGi;t`yL@Uw9-EU;>; z3+Rtg5L|@&q4YCcg$Eb|VE+qqDzN=_c7;3;O%br>E_lLMv{fL)MpP1mttx5 z(sYUGQ5pYWB|3p)6_2#w6FL^4hunUHLebX)_VGKuBYPAmNli5a_JH|8&tSeY>y>2o z08$cmscZI_cd@Vs60>T)n8$8myL$UpsnaIYX;>5a6)cvRPz}3$asL3t7iemskT1G4 zV08`XImJ*U+$@vB>HYvMjjIf!=}Q|At||l zBneoH$SdWc@8KJ6!1D_03XpKI*zXl39~-lF!Ej+M?}AX;^*U$^S9JWOT#PRog|%He z3IQ!4Qov54<0#N^^|VnHSj-QEh2nlIv+AOAK+ZlJnO3zM=(sU*Ix1A-oHU%7e=r)l z07rhLMzl}v{$DlPMe*v<4ppSc`SMFYk(_Hr2swZA)5)pOM$@Jyl9!UKEypC2b%|+R z2AW-%H57-Pfp&mWrtz4+Qba)<(UkGbPiUdx1C{@ryqXK*&MMdqGWs#Ni%Aooa{_2d zCW9DM!@oTb#<2ElqS_h`d*5l3uO$eNkuja}1o06U8b1*zg=a3H)C2%?waVY) z+G;Ve;_I*Y55Q=#GTV7_DvgSABtD-wu_AmeB{=?*DYb}LLJ?6>^48RgumXqf!k#Wi zzyk4@<6JO+VLFhijabKZHI3*EkC075qZ%iXzrdua2!9@Z+<9S&OkbaoAD5hw8$i9- z&1l>-ZiwC9h;JzY>nlhC^wR;1LfDh<xsE#;4H8>~GMzb^f4WwsL8@x!wu>=)o zktBBJgd1G{qJB-A)yaz}7h^7`tT6Fu@bme9Y<3DjX4Rioj{K-R92$ao;?aJqyI(^* z6mIhQt75%c4BO3lvO#~>t-iPW=0%Lev`7COw36IE^fGF3+$g`f-%ZvTy%Fke z&VuXk5&))!GY~YB9>6hifs!|j&>46a?z5CkOPnz0I-(!~F?TsUYRF6->c%SUKFiAO z!JBFRPUZqV70Wm%;Xb{}JH)rQC8xoalI4Q$bVQnh^$&kwL&<+va48Yt6b}ITfs3)c&}G}og;1+uCzu1Iu0%u zI)1oGKICK%H>yS?x;g~3u?8^{b|!OjW%=R1y91mpXfu{QCtVBg-Mh`#_&%b`^%s#U zDe^M_!G}9Fh>7UqnP|msy+o+b`BLV7gyd^ru{|{?I8}ee>+qcJFBfz`R@DqrOjALV zN~CWQ6tv0+?Vky|F@PF~YN}PAGu3U6Bmu#czr+f3&jRgpNWc{WI=wo2q>(9jqrjk> z3^xkx;=^`Nkr9`^k`ZJiFv~2(EMg_Fv*~W*kqma0OXkgf#mlfLPsSCiCa{tt^QsZbX~&5a#PDx9HcM;uw%lA(-?2#jF{kI*wy7BigD_-^bd$0L3Ahv z6AT)sOTTZBgRoNSM$#_uLUpWdAZ4yJ7U-0P6k=7vEUrtJ=8?<06uVa*fxSOF%+i zuPV1jZf-3v**FR6M|p8EC~6uzS(&rXCwA)5DCPm1Bkyx4iuz^yEBms2tsSLH)YWd| z(KnoY0oZwbqQH$n${k#~KrZcdJ@_SEB*0b;`>;Ylyj%T*m-5c;Upbl@3Lb6Y5e`)6 zrllTB1Wbx)FXzWKhyleYJ~!9OeD^$h@rP#t>_UX&fwx@DP~3ST6xbs<#F3~u8d6{M zA!Ia)5P+u$5m_eMd4HF>>N0zn#4%+?o*~ujOyeY_UIoKYuZsY<-tchvwQ=<-uhG>k z=jB);91IXZ?5fv$#TQcca|Dvhp{O@e4kU$Ro4Ll#@|3H1AMfIV5iZ&&_;fYR?$HT(sO*aZ9q@{3LgH>r35@%?9_xSIR{BAL=N zR(YeW=Sv;dQu%~|Y+FRa13P&ICAxMJw1FJo!Fhz%<>+lv#rX-fh~)|GcNCGNjv4R;EUb=G z!{Y$XzvF9@frcM<8DTK9DO4#D!>y006A8j;a7$0R~}C zVI?a+>JmtQr!2f*z$y!WOWzD89C}T*6+!L<4x@SujS>^8W=uhKS@3&E@gM zgTLt$Pw>NOJq}K5k_t|160V|T_mqs`;k-}%;rIQ>FF%Szv$coHj|#J#{z&?Q>O~dt zOSHgluy=k8`$9inf?~QO>}T{DwAZ;FCpV+Lq2brd_HG{9_+fqK&~PMrzp-rkBGiHq zj7|6kD@!;Jc?)=Ckeb2=ZI*4@Hf5WvS^D?I<bl_IIXO(h<~js;RH0;Jz2dJNI=&o%hdzCp#LwXl+&d6r z3O|M5;SA>h0_r{NNbL)aww~YNyjiGEUIL4SNU~plT6imGo<%O(g29OEqO$PTGA@@W zJeMQ?Exs@#elhjb`G&~9>7#%_99KpOSqcWNngUT$wQW;W#1xgl$heS(LBr_Xlqf`L zd~GBZd45_cpfIZ*kkpCyP#lL7PqKdPFWClkZU(>yr-1XsEhH0aK}g%9VwZf6le^18 z`*|e&-G}@hO6Ibosbm<*3-Mf)MNHe7&t2iFmsp7JH9AoZm|G+cE2hs13O zTYb(}G*M(jVL4P*JFej)1sfJsMdy13s=Ju#5vU0tpsaAAcM&4iJNIKWtEI7ku3N)X z{V`-2#JC47;9nOT>4JkCIk(#*4P7o4sTlbLiq-Au!PyUEA@XOc;qXnQ4_hTT2}>`8 zpT6JN(o3rZ>3PuP0^UKdMbxRK7r|R`q?u~^2x$_rNE{cSOrqR!&UhaR_a0HW3G-=3 z>D#T;G1GT1;HS{HbNLH>E59J}B6*&H8N+d`Tbp^~h{z>;1;=^gB6{?~GacMpeGAW| z$+ln*ZWuc>n(th`3eV-^wZT^W#q2jI$ufCq&*jHh*s+IXJ;2TW5(UFi3PBG;j~QY! z|9FQFhWa|A$r2ql8LI*ZreIMU5FE|<03->)VohqS^#6e5<787_!S|^dQDR{99A>93 zp6lF<;v6^ml$}!`X4SWPNf|6$$&L_q)6PTAU|Gpg0R~tjpULMSyVypEG-&=14=Cl> zWqJUD_;nLP19BXBiU;L(pG{_%u66QiEDm`dc6^ZW()5!%j{THkiJK+=0{BU|QLk z&Bf=WMT1VxjbwB<8z)s}qknKV#`-EuA~W#@8cU-K@|}6mSbNCYADvWa; zLZ;a%PeqylTrV3HI!C;v_@W30>19Sf(^I@fZas0>vj6w6Wsx(h;fq4BR2ze(rVd4r z-r~u=H0#W5CFfwx(wE=VCTI8LN6v&PM2ssg@0z9NUqGmg6%HLLxX2M=F`aqYv)qe@ zocu@ssJww_3#td_U!h(EN+7#Dn+|7bsw7mxcU9`ZaW<$*QV-p&x1dzveEW{E=^TZm z3VKWdcTdQqJ|$f@AM?MYtMIwjTVfUN?GnR>l2H*$^qiKn@b}+LDc>UWTdDJpit5Z=i&p17+ z?7J3(YMUrz)t#Q9w-25s-;}F>D1dK7jJ!X$& zlWbay!7!Ku#0RDrjMKdA+EzJgsQF5K`wHvDZP$8Cf^W^0!?{8~rq>UHV`%K&wdrZ~ zKI<3cCi1p(JPzXI;HZWW0ajp0Sr=shJDBfaH@yMeEHmw%-?E4qwVWB(vme0&KoU(Q zxSqdTon&FgY}H<}gIqN09snBxjO$LB!rhd^&noIwl+7Z;gidl)8Wr^9@&n=0FF zBuE=Jx(}4uGwC`6vK63Unt392I-c8Bjy>xlL&^F;A_!#M%F!5RO4 zg2M&a87EE~j?mLFBb|&M42E!MU_gV~LFp7qZxE>oJApW_?9mIk`v+}^Tnq8yJUE7Z z#U0)L_~Dj#ocZzyZGRZJ;{-Zf)bIkd&oJgQmBM5+?POdDQv|58oX>F3BuRAOWv!9Ht2CA81v7rM`3rT9lZxJO;eb*tx^N}c~Y)SFPXB7pRc zJPaT$v6vtOoZ~b1u4ElX)5kQu_O4bp+jwISnP_tMf&&v?-s>5KRqlis=dVfu4AX_) z0+<0QsO;?Lbb*-5iWfP2>y$4{U|9@4SQKhWktWbwl%Ypz0e|hx8!yxoDSV&B@8cDv z>5B46QH*#@YAGII5`rCBWe~-&Q~wN{PlLaFoMYOqE0-$>wl*O1G3s(zx83*LC7jLC z7jY~2kgn$^Dfmci&{eYKFG5NF19bK&_yMqsjxI^xm6qH4*9 zM(7JbQD*hDO5QZ=zY!wPQ{3RNjdtN4n1Y?8;>k=~MT@n)O}W9K!83SqhL}eeu-jJV zs!z@Wh}qA|Pv6D-0gB12q#7BO-6NBt@J*`lRjTmsq_AtIN0GA$JI1BZSe}d9@5$^pn=!c7X`PAAOYmN{rsDf<=6;`&*{wz|!GJ zclHzQ@?#l0lpXkZCq97S#eC%;A4}?hBmz#!RL5FkEDAH@dtq)2#hC=6L-c8*9$Y<{ zTn)Z)&t93O%zPkP;qE4w?8&&B>s*%NDVQ~Qm2y;6lbgrEIwJ@77#??2RC9=AIV(1% zUSpms9t!7$HzDK-U@B3_CCIm>O1?eM0W*EK!r_y8)~|no3*uAMF7OLEEGJiq41nW_ ze%?A-DG*WBJXFQB895yHLC!^>yK<1S07@0JgwM3GZQoPu23?Gy(#638U5w_Z(Q5EO z`lMf)p_W1>xBz#d8P#UPEFzJd2j3v!UL9KfWAH%6q%E}0$Vog4Bw+OjAR)_j<=FNO zS84e=f3G6E!V$6lUd6mXeAxFV^L&%hy$Ts5b{O9j@=YMTDmsG!4McqwpE$>Uudoa? zBzSP!!T5`Aa{64UEDjt?KOB4+THT7%sf^~c$)holuyuVn2Kz?rp~pxn4{s(|>{vb; z&T(PO5!fp1kvVXm_P+uEA_mfEdJ90Xn80V+F9}a_CrTXI3->8xQz8`yz;rY54U5i| zU)k9c^A3Oay;~SyU5x#`n`>_dLZSoD!IZc(hxjm1#*7n{3J(J9bg@k4FI2et&D?t|jaZnOQ}?iO;EnHP+p-v- zT&M{%Cl$|q9R_&Rws{DDI!wUSCKicx(c(f@+DUXCyleH@9-A}s2YU-96?h@Kv6w^P6x1`&Bt zRt2(6A$Zc5GZkW>!XAdGs$mS_=`tK#fatq-P9g(BuO3G+0qCUucvtS(ui97R)Q!*8 z=$OTIa??78$F(w|^MA;Q)=>dG2{0wadcY`2Ns@WojLrF^x@Mp=24=HyXYi4P#>|M-$Bb zE|@tS$;wtFR`#+UNn91@tHurW$CumX2t8S8%=#_a3L<_k5ezvbTr_Z#jS z#)KJY$T|wvKWG)FS$sb9WU-lXI8+ zltFeHja>n08TJwedSt{qUu)`)<1C_fSX|SpsL75K!RYv5f$++T@FwJpi7W>-c^XmE z9$cWwqg9i?P(L~H19S9*7bp;*)|EhTS*8vGA<(LZcQvIb29T_QVgN;6rc=irvU`R4 zRIN}@hR_Dm(V550^H`!qGPPt4#k9*XLNCs-`VK6Vh&e3yK&o{%F(!0NTpmF?0hISe z`m!-fchR5bcZ5j-yHQVcozuJ?V&xgpn5-d(#qw9n93gqX78D|FS%l4C%>>X|8F#WB zD8|=n`&vC8ELm?X^wgi?e)F$zKqxbp610t|If21Vf5IK zO-^}{3t-cn-;7rhDxXb`!yJIY(`dlK52X361Y#*m;$Ljug7=$n4=*N5(*yUW5jqp_ zTRs1Q1dhM}pL0al#D3KdA$^96rHCepJ-FPo5V`;(VK20P&%GFxd!e9^B?0+j(5>63QK+ZFb=`9-!v600 zNa@sF^#8G<|Lae$2nV`jK0X|ozf@}t_ryR0wM-W+{JNOGWL@nbuANX!aMs8g!)=(- z*S?0?`U@qkK4bnmUn6#!a=%x}_6YX|4{D3<2GCZu0y2=uoX_u=kSO_6&Gwlg5MjI$hViw_7dz8dcUJR6imxa-!n4o!!t=GjE*OG^P zPT-xK3UFfRG&FUgoe^Y4vGV~@Cx8Vi2^eUz^`!g!aiT(?8+jUrlQk;uJ2X zVzn~oq^v{wk{LNwmANrx8E4l8n(2q9e!s?j|EtvRcfAVEdJ1f)?FjcrVJe0C9K2UdW+)=>74c&q(aZ}_A7~y6xtQ}WdgXejIj0JGK}2Qri0TGvp^iAP zp%bf#{30N~c(rp5AdJpUXwR5YsOMp<2+hJy;2#XVnev1!yBu0^?09J5ww1 zyaK1|q*xuOF>;e?7v;4z355fIq}@!n-Q#q$tdy!@{ngTLzY%KrEel5A=`b~h_tpz0 zz4gh0@@*kM+X?BRHY6r(wOeV)9QmQ2{bMe?dDmy7=0 z*g}%)MhY$pNy&Zao}&t}F61b{<2MQ)gH%;Ew;t*_QxDRb784kdcUl zi3%DObg0n=MGYD>u_6@7SReS)jNh-+*nn<-|yUe-^`ntp#7(ndCOhSe$G92c|!`KId@4nlR|`hnJ{}~ zX!c+bou_LK0TWy6Phg}lpYPye7vPtFes@c0!AJ|wq20nla@5Shs5@5pVi`aHXf*^t ze{eV&$Pp-p6r#7|F<^kio9=;x$h&&U!BS&3%8HS}6*1~RIZ64(evU609pF`a8=aee z*aZ)XJut_c*fFMt3U0A72Z~_*8Q_^cD*t2@>V+_|h>(1dyb+ez3C+tBr4%pwS8G}8#-&1T05L<*7-@j z4dMME;?12TcnG^ZZtUws7PUxGuA88Zxv{fuD@2ij2zxefS~;z{>LNd+ zC(5Jmb4_{l&Ci@chbT+(YT@5OI%}5lsNh#0CTju?Wp(H(iuw8=0Ol2$Fy{*$t>(4= zQ>}dg^rF02XOL{~gEP766ZER4@x{Q0|Df|4AH5)UfVp#~#<2$U5(?=B?>M7N$mTB6 zg1{)jy%~9tO}B!6IJZ14^S{Lp8r#zs-uWX|a$X=Fg`bYC1VUe(d{WtN5EkQ~O z!RM&IfBqkQwgU@W&U}?8#{yxk>omGh9FPwYiaHSUtZW(fqXJF`ML=H@T-M;U8NwOu zc?4ltU*F5ysQIi0e1n5iC?a3S&J{O3itY|709t3OVsx)b3@xi^e@orC1cZG?2pg9_ zx6GcGauJF8Gv}oUf@VHKGA)xlT+A@F83m&qRA;c`2LAnpE{IG8&}Bh&$}3v>iiu>H1wmLLHi2kr ztHfC$9werzZ1wg=t}2UTnp#VBCAK{wm7>K-_&%ZWEg-%CjQ^muLYbS?C)Q)|w`}S) zlP(KB-|N7}J<N4?e#fz=a7p$0$INwVH5tyVG|q9RFTt>7GGO6STe0Mp<&)&8WfC zrPdQdK&1)b2m0FTDpW>mhjzn&Ru&sLXg{F?b>?%xrNrVwgb+yPX2!!&KR+j51YSau zCqk!zTLEzk!)5|Wtew}o&F@7Vq@Yn_Od<#%W7 z5YD3pR~Une1zAO_C-O``H`t4x-Hs1#To*$%H57Ew#bjt_CS!%>t z@j%u|fdBTh2>%lH!%uFQ#ER-X7){V%YaRlu7$R`7tHpAPtLpPCFz$tCac-pO_mZ^u zf+s+br{GcM$qmRu{iKP(=Zg-*lA^{*N8nVO6@XeF0BEIN6Wr;$5#wO+$)f(Tllip+ zESFINkmh9b<=KqbkS`JPP@4Ct0Rz@G6RQ=K?xY`hL%qtgm2qUQj@ z$;EWbfToT|9MLU{1fY39bAXi6h>^ce7L=PMU(;CWdVBwAu)E0M)`a8<*otC7_rS@A^yY=cpfG?ph9 zD5e8UNt5W=UCNgZ9WW|K3?y*@sH`sGE$9s?6W2-#+VDinq7QH13K+x719w2irHu5jD(%hez%qratcZ;4 zk>|#0A|mI!@Z$L}{ zLZT1tyKJa?85Z^afJMFE?H$^utvvHP9tAbD?^0Qsr%ySlDbhhbz&4|t%vJGTxsi13 zG9r#Td|0EZTm8nUqa`Q2r;D;5Z^ce zzzjv;S&lHi9AW&>KFcZIoJ<><`I&bpi~4kchB8l_sd~4V4PyDCoZK}D_JXpfX^C_Y zgbbtdRotci2;Qk8DXt!nADp6;bu71>;LJ4OK&ta}8##;u^Ys(#eEoHkw&9GH3EXnR zpa|$K5Hzh;*u8E>571Pryw^-3vYTW;RS&`JKpw2vq z2MIb;;hqml?E_tSLIgSdK{}$FxMiWSt3$dbwzjjmDG{jkA`cxYHNOlzE1I z_Y1q6zHd5vF{fw;mv71l!!9Q@Ix4%k>`eY*p)pQEx$$PoA}K&qH(!3uJzkD+GIu#N z_}W7<%=#QVEeNa>1!hteFcK5mgD_zQe2)A!UW9Xb@q^h^duaVVL7)Sxa*`^SAz?oblpGyg) zRB(qQsN9X96585FPF|sWI+++snsp3lTDow19Y~ueI6`&ivt^J6C)ioAQ)zdKlet?$ za4))0PyDlE+Q~stYC(}9Oz>A}3B$-yM!+=P>gMZ`3A4fAEcjXItrCwhgfVg!yGwG- z-^Lc>{2@}4go;hWjr#gg1UCI}l`x$0=MRE2IZuK37hYr{fI_^7AO(RKJ~E2b4;E$d zK~r0vX-+n6N&FgTZP znxfbsi_x`D!+BCzb)H+nbqJq>gqX+1k+u8d7y+z*!?_0Q?Q9DA^dpSL?F+HF=DIxHLNR^qc?8-q>FczRZJ+$Mz@=I^x{q%~La++y zC{ZNU}x`jZecrRxstdXy1DfF_gyRU{{jai{umqK=ZGkR~VWF!+L! z$}|vHh;{8G31R3CmWSaW?TzB*zHV=n(Hr$bowimdfKit-JsWTcYVi3zHPtLgCECIQpm{wc#8J~4U#HE9`FjhW-pJ?gq2%@Js zVtmWF2s9s^RYVZQezG5*D+&>W3cI$>=1QK&LR`sniTryM{yhs@w1SPhaE3)zH>?rg zg=N+gFdE>x#F=Lzu0AVT5rohkK^H-DEI7yzm)zDH^K+3B8HSex2VFL15Wk#vwotTK z4bD)ijf04}i}icS4~!c{R_Hj5trNHCxJ>jXv8x^o(PLwESfe!8%io;Zc(YD+b!-yyHGV@|T7D+}Do7_(C`iKG^g=Er8qOqVj03bz}sMCQl)P zewamXnBATADoUNr?{6+P;~lf&1>dEdbst-Z6v3$y<)xoOUFlfeb=o;-hBFacSwQND zQF-ceCZLDSMsy-L8!ejNM&;t?5larI zX)&Kix$)(6(KEOF$Hs_UOJwgsC?-QQ-TK^L~3!^hye#j;<@N8 zA^##&+kOROWKKvyEky`4Oj=(F+h&1LYl>B=*r$lbjrBMs*?Lq&4{;*jl$x)$;e3J_ zPeb(OtJK4iipp#2VHsF>NXv) zfs>N50L9Xu3#FmFGL+Dq!o)5amk0IY7MA!Rg<^^`)q+i}xESJg8v!L*1&yu4$41?v zRndVb@1|v`zX`ysO199@s!a4WDieA2QJDqN0Ra}?UXL@D#$^I9JcCO{5gbp~J=zHe zOVyK-4&*_UH+Ckjv|hkGszX<$8tC>HDBY4KQ9D-hy+u;vM^&ROjPc_o>fZ&FYU2+P z*f--1T)_DsQ(7S0c%!8S;fUj!_d?YVhZ@mY!MMoJ-4$6~Gh_X!Xh|=K#QCwHyh-t0 z*_2I3gyj&C)I{eOJ=r+S*ufAhd~`B6d6K>Bvqxyssz1KmaUUQ>8t>X>eB8dhE4Q6?$`$~w|w=-mo$Zdt6zHPR0|=89eUTb+o?3c8DrRbl6Qsv zP`j;n-4Sf+YhYN*7Ncd`QoZXEzDf43bXi?7rBuR-VaQHpwA)AMOE*{lufFu-?}4%PrSSb7`BDPIc$-E__O?>{ z^Mp)2jC1@3jKpU%J>7PwPwNJavi_I2iY((@of@?QN1T-A!M5opho$$Paw! zYh8bVFMVRX9?z38bf|v&k!a=^by@|AeFux_mi}-?=H#wR@H`{72Orog14kNQ=dSo5 zt(`LqLUPr1$7pe~j3V^!$`#J@md?)B%|41|<*@r}WDLMV+4g*^d#Z!Q`C)^#IEfEShPVA0=MM&NyAuD>jbK2I zPygK*z@6K(dVlr}0Z5sdP~VSB5XBIaKeMR}@Q!(O!)GW zoN;?(%I#Umcd1PuZReb~SO&f#b2VIgM+dl98Bed;_YksEB_S+$-hh$qp<>-VX6LJq@PJ|0;|BFe>ag6h1 zDGUM!$8G3@n@WoSfzz|70H{Xva$bI|{LZnPKyL{1)GPR2x7ie7Dxlk3PZA|CH)%&z zHW#ZVATOFc@uZ)qV?2-oOt&DQ(UzecbIwiuVbX`VMPZH*HVbLWb^xV{9SCExc0_Zo z`5Gn%Yh*tb=z8pcw&WdRT-T=O{;#IHCtHQ-zF1oI4~zg~lIbpFDFg)qUs}`MO2}cl z2Z82YVH7a(q20!Y<%+IZj0q=H;GpjEl4bl>{JBW$z@{T1w8R*1Q+?`EL@Zsj9)E;y zg~EXM%Sjjvk-y-y#`ZZ0!q4t*i;z}aTGHOLbg(h+UQ%; z-3m=?4=wj|N3!t>H>VqRaLH^ZD~bs-^g)(W?Y)rn;i^1O6L4x(r)1h7!!(XbFW^G) zjeUwGw)k91rVY1|l(}&fLk{g*w3*;T=vBAdb?P1N6+1p;TS>0Ea;c7EHV8NT$`Iq3 z+3L3j{+<zlr0EzavCz|6J$) zC?AjUzDX_WMIk7Q4#s((>&i>Mo^;GPkt}Qvn-q%P0`(h=ZKyjY9atLau_QXOaPKlK zZ;#dRbixLySBfpXCEF%_eNHrMR#|jN;n~=;dOQv!fO#63cXp%|bBUAQI~V&`%Sx7E zt8pto+%uy9^-I2q9f2Rjw(ad2S|l0abF+iZ@4)Rf?%F@tTnL|oZx7&ru^<95x_M-; zb8cNnS|z99;CySe^9`12dzQCP=exRdvhzI!Ry7+V(A%!YtKe<@@GtnjE@=3^WD%PU z+%%s@p4bT|CIB(>KI>)JUw-1qMo#9K9eiJ4)*l&dM|+n_JwiR;M7gX()uo>yBZeWp zy5&`0%nqTd3{k|{$dMqIqH|}j*Y=jf(7~NOKl}4!b)8D zb_Z5sqP7yTGqmvU%Suc$gN(b;ZU=!n1FGO{f1-rDJ^y@w(X2TO*?8cD`_tKqlTetp z!q^CFGiWPvL{oZye;@0Kt@uaasZJa3a9(Dteyet~$78lF}>Tc9GIcz!+USnJ^U1v);b z2RrbrNRL^be4d0F>h7Kd;s4~}{tJbGhx-&iBA+y5wUEl?t2>a&S}m0$PyczT4Bqiu zj08K7#{gahZ(9M!37YjZLq+w&6+HGW*nAA@;64x8ZS2U#6!6RgIOaPN z4yp=gXsF#}K#@*7q_GdM7$G>R4E4@1Yg*wZGen|g*3=xvif{?@ck}Y+qb$Z(Rgt_% zRTeUY>hEjx;Ab;l;MkW=urMOEx(U6954On{L$8+7;zh-6Sx_=H2>tr|(i6n=zid~=ieK*1U*0kiCY%W!w;3z`>wGPCFo-f% zl=G+n07RPrqVZ7#&Wsi3>4hR7P8Ep*fU5cH=A3gf$BIyUcaAB-$&Agn8j+yMMXz`d zVair{jhb9S0{9Y9A}BdQCg@={D*FkN#)>C`OKHZ6qs&;b=b+E%=z=r&`8{;UvEo*^ zQZWh7KGuOCK_K>>=8JtwlYs9dNvl6MRy;v~-`7}i713mx4>a#ujEEr%!#czYCe2r% zmlt59Snh`PNO5rFjOk{iXev)#9v>+_gI$#vDRzPv^p;vls?UssI8yw+!b&z+@ry=^ z-+n?`dedeVM;4?84Fm>*C%|rEhV#mX)$RK;@rF~b|Cc-oku(HkgI!XA{O zR$`I{iu}Hznj?*?8M+S`iCh{9q@}h`z5r9=a!T8PmH49NFES8M4j~yOeh_tmL4YBs zjvN-bFpG*G8^}KMq_Z?;8wTo@kT%;p#ca>?%yu@$oN80>|7^Bb;ZOyb?U(SA5LW!* zQ@W2!3oCF=MBlR``L~tf*ibAaKx}hq-q4bblX{#R$(qN9rF)l^MTQr~p4tRBE)Y0a z>ASO|taKGdM_VW1!yH$k=JgmIZNbXFN&h@In*W!xOEzP4)F$8Uz5$i7L?JeTzx}tg zf5|3>CN^B*Le=KV` z5WjXi2172a+qe|xobjY9tbc-!;*t=veh8+hj7v<;lY~JPgNR0!b9>WJTqayeW)a>zLgU1Z44(0UmN#DM#L_l4&5vchD2AXz|fw zG8PSOMbrIYsQcvypAXFburvc1>HVE39yPUPFR$;Sb_?@Y1g^omO!Za;zuBwS zzp`VmdSL4Iy{h01{B!inc=qZTJS+d_H+xqE&OmYa4bzSq1t8jQOX@#3b0!Ipv_Iv- z5L`CCSmsUvQ%ZhQ-`R;Atr5ib3oH!^3ymGpP45hWS%2txZa_r7h^b@@y1~4_oY(ZG z#9ThiGoMMCut+})@nHc5#u+Md1on&{pq`luGF=Qw@vQ*z(JMIf$^R8zY(w&GkDGLK zv_}iGv6Val>yT*HJy=~LCtyMDEJEt@1H=Tnfj6E@#cT1aY4G}|4=+SJ8S3f71+R@$ zfY$(vR}wyd{a^8cs3DXA3lRK3_?IEK((6vjAn;i+>ELMA(~+z@BfXwZK;|%u%nyrG zk@@14G{~Huip-Y71eqKnQ*4n*E6)Yg?GSZ4M5%#ugIK^uBUGb$g6+9No|AhgL?aNS zr4TCq)h}HZNk=2)qIPVXLgZIl0ZG9hnIX%kG{xoY{SG2r4@{CqQAcs-?Mt{8{cf=+uJLY zgzvnYJHS^fByFc3MFVw`yfqWMrmg#iS*={MRjemS$LPex4l|CgJQ~3fWT+dUwxnL3 zF4VLXA#5W51fQW^p(K3TZh|02iR86gV3YrA#q>?z@cX7Entv>ukhcO8g7n^;cb8_7B{IL zuWiNBiV7{m=ntJChu)n~UziBBkG_+~|151q#)LE{!#w!t7ngr^>SD`)B(k{;5QAuf zMEd)`2L11gR#1sD=m+@9-BH;2K}!O{rP-^@+`qU}@p~AcsCD;vdzC@8cT^@|iA_l) z2H=XrA^spf-34mZ|AS zYVjx}>|hnfjXZY)s2H8W-lug)Tl)EDhIPP$>_}#Xs;Gm~UVvKZ?Cs<;VLw1U?B$`Y zh2cbu24O6qbg88$X?UOuqKD$!MHyMNiJv+6Y7)%T!UXe_U=JkzkAZCH10poh#{X_0 zZ+~;V@t^*Xpup8DGcu1p`^uI0Ou}E^{x7yd{PfX__pA(en>^~|+?CvF(P3HTa2)$`dmjEDW*i_oZtr0y=nqF_lfc-2eqDkE4rvLEj)if#A#6N> zteFPqX$jS(Z|Mzc=s};*6G6)7{wew)+=dwfpmB}^+@23@^*VmPpY0ftTD4wF*2(ma zjwzaGj7@;JX7?@l%oaryK7Z5e8U=I!9%klOGGN^Ik0{ptP#As~VRs)AU<%6 z^v@+nXtP?95$d*Uld*Tio!$Th#0~n8pFjxQz}xLQeS;iRCux%|0+I=w;3w3H>Dm-m z0|cc}E+Bz0X^I97T9uB=n2nAdlQRbIMAYWUkyX*aisL~?s7kh|5_QI2fR&;_t~A`$05z$he$xPj%vAiZEdkT4bjn8Gn-xF zrjj=;<_7lCFseEc;bJX9R~m#v)BupnDD*v2d5&?|=14bBq1C1T4+Q9zL;xQ@Ctn8K z(Z@uJF#qvzcLSZrXjIUrF~jIsd%^^*n>rww6;L0+jmr@6N!OMGwCm)C&o z9i0!gnjwzg<_S_!ep(b;cOvl90&1E2qbzO5kyydzvslZNb5O35{(S~Nj);g4CZ$re z2jG(eZcg^!Xve#OUOC6?A2zsOK0=#t?6njb!pZSo#SE39iU)w>{tjby6kaqLYKcb z9dy*?(Ldj%8@TVF|DnZouWKa4DuFfPeCSp@B-Bq=f!Bwb)TW5IPrfHl1+PQYFR+FG zc$Nfc7BK4q5ggm9V;i~Gf=l-fKGvRP1^3iFBDhDAJYX7z^fdD=>eVbQq&oa;QBV5r z)p&w;wa)_l@9@3&T1W7$Ew%97z1t5Ta2EKE^ug1jy8G_cYc>0ZFF128DUm|MVmuXv zurxfRLm2ycFn+U3V7%Vg&~mVqc67%2TYHkX#Vx9~b0Re{)|fhor*7}SX-KR1#yXFI0m@KCWCA5MK0g|NW{=Tymk`&Z764gJ@*Z$S0-Wi9GZU&CtE zl|cJo&6fY2AIH7g5kJD7q1#X6>d6bFSNJivQzC{fYMSp}okYO)B`-JuI%V&+5#zfI zSRtN~dCm%(d0+;L_9lX?1Eqbd6q^WJ+r(|&w0HVF?eq9~#zx^ZxJRyl+nDYjKTRHt z{$b`OA})nK!DwTgX!<|c^q&Wl7~&z-5eJ}1pADwZZ1kDCT$Qus$BaYr(|;fBKl_R% zJKN9G?c1*N{O!kn+fn<$nbWmAhlvA%GyVe{90TYu^r23Fl?Qvu*Y<#*WS_F~=@Vp# z!Q!x`z#A7;_=Vq-X&x8`HEfAK6I3jg<3vgen=xUFQQBky-r8PuE+CYT6DGz(2&L!i z&Bgb@{vcnqnXpC{>a{Me`Nh~<$#d{BgjI*^J(n!R>OG{HidfYRoHNsmXy2Z#ISSwb zcQogOHsp>_Zj1PDvsNyW4VmeA5ME)6xwy6m_hlP==iuQbmZ=?6l#tW=44>6P3Ku@^~;}RT$1yT*KjrM*VrLgR_ki)=QHn2cm zSAuGl$S`1kz-IxJ=P|Insn<8M(V+Qer0%6y^gmjFN4|P6%-2vgqFe1r zHe3di7npT{^l+*oG6s3HK7z|MRG*SxLol~9+ZVY+Q}Pu_{hb5ao{ti6=4cV}V95`v ztCn_6e?Vb+1IjW7hd3bGd+9P#gWb8)3WQM7{+I&cR8ZR2%^_i2(~Q&XvzReJB5MH% z$Uj~$(wAt-W}e`gj{TVPgAlBLU7Rp5gl3wo5k{M=r-hZV4H0m2E|Yl`$_gAI)=r{? zYilqEfTxn6;{{g`V?JOB6HEqaPHX_buoKPIpLIgmXmX7FveP*dB_X(*hTVxE95-4W zAvutN7vG(WZ*#SB-i2Eo?!j+`&2$0BCAjAw@okkWeZ4B-nx2S%n&a+(qyMGn=+(w? z$s}NN9B{Yt*A49Yh$Rue0$27-9J19TDb?5;tBKEp5LLp`SjwH&#$mRlTn}m39-qRX zkCX$d5`q=*LVfnUrd*4Z#d&gQ5f%qWIC$hFDIvN(D$aQk(G29_D#*i(S*&a351V#n z)=!f21mx2P^;afL#6h6X!r|SOtyIpj#R##B@EtB`cc%cQS1;jGNSsa9@;Yja%JjC) zxP>=B7F38cMs{@|#BP6ys#Dp%*ojK`1(Exss9=KCsn4+}#fC9(1QXdS|0s|d6bq1* zy(afq9@$k9SvfSaD)w*WEB=?7GCMBu>l3c#e>FjbrbFRke>7>yUkZnA4e1s&F10mI zv)9DFz=8}X+H>BIOw5?AJ@~#$Aq_2-d`)OdFto@PXq873>a0jr*nC?dplI&8iV$?-Nfz^!<$Ejc7 zbXBzXb?o!QdYs_H`SZwNdW-trPGo~61y^b`0z3`C3-pgZX|yZo=A@NIHrt?;fMeX@ z22uzXPj+UX?Q<(4FeD;(C(COw6UL94&M7Yq8iL~pK?LhKn95Tb`>YZB7|T?g2=b-U z{JXbnio*)|n~%+ta(cpI8<5rIA4x7BJ6Fm9T-$)C_AM#p_VOelADQ;8v}*P^gfD~j zK|}ud?fRs#0$5o90|o~P!*QTOKX?LD$gw^abM&C&geW8W=b%oHqF4l#!Vn9@IB!uR zAiae^RIF>UTzI9`o{Ip?WN(b+gC{ss&N%hw6wy2_yN2oieWhU%fzyt^i5=-efONQn zQ-Letu@OiEj4BI8wFM)Lpw_{>6ye2in#kl5a+a29FZIS5TBuQgE&#|g0;ucM{-j`d z`fv1Wya6kL@`Y1=+}r*;HdJK-i-|U6*`3H9<{|6L=elM28+80QfT6|otqX_<;>Y>? zMf@ng;PVpP^N&1ll`GhVvS)SZnhWrNHirfGn*Eu?MY1r3F8x?h%kS--YtQ<{7LNEtUAB2G_#zTDd^& z8dA6x-QM^Ey|Jco_Ax95^1!LsyOfiHk~m5w;f%`l30%kr((Q;b-ehxo%0g zzQfjbAIDEe<8c45NXh?jBVn$4B2(9xtaapTbGvKdNRF*VP@Q`j|H_`ki7U|{pu zI%G_;^paTN6}kA3R0mdU1Jd7GKhcR22wauMApm>t@5_!nr3R1`FM`mD-xhWMw`quL z<-=$pI{|)#@8U0TO7?@q)!)qMbj_rcIw?)57Ij$Kr=8P0RZm_3{dzoc!X(L_yhwI8 zZH25&1gS87tS0icuqPo>TKx;jG))eWR&+g&(hh5fkqr49Y`%^3iQ;UiL}97ILr{&T z33RA}jNi2@jf~@MdKv%oGd>wd(+#>s>wb-}z;0H~B|BUaP%aRMrCCql0W3I2L2(1MKP5o?Ym_r`n;znCpZ29F;}9D$hXhea z=obvc01M)5v_61$>bfP?bOMA1s#PN%^UtSZUK47~Xz;gh`h1~_$e(lga=zD*2cV7V zTNjbtFrf?h3ll28=w=n}Z8vKZt~c0gNca-gi8@e6$OZOafYh+JcxaLh2jQzQT2$bl zb>ZO!Ius%&CjFZ=NIQu6Jw%C$S&wCm{ad}`fn}1T0t7-tx|wAVXH+o=Vn2)}RKGH> z7a9Q`C$^0R4J<-W(Y(6`>w?nX1}P$fI2;2Ou8J<%cnb47Rs{MEC|A zR(%LcE0=dA((Zu87^~8LQCmsZweo9Dq($0e74Lysl~b}S=pKqzDx%ou3tL!ufh8f7 zC!1~52pgL9R(i-y1Mc}JqH3?*zy)jKBUD|5wlMR29RV6$M02bzet^ID`pb+2h3m{_ zU0a4^f=cDFkGLni<8OW|k(DpNfCPe+#4orJy~7Pefms1?Dx|)vBBgmAktVkpCc7Ni z>ZL~xwlngYq8xjPngn7w0`dKN69@=UMS$=}0#w^;H)qV-I-lXV^Gp?lQYyn9<)e)e z2*Bzj0IS-*pksy9F(R+ullVYBm+gC0P~SYJ2jqm$#(xZrH?tH~fW3$}M1UeX1>{x5 zXIgP}EtHYDKZYS72Gn&N;to(GL}ZtsB`aOe38Y{5$4-pE4G%E;u~hOc$bM+SS}cN9 z0c2WHja$nb@r#{4LHBb$z;RljQ897AAFspa8hbnbvZ*_&+%K;yAftR$;r2YCDHo3s zy8-)b3Pgqbs3|ictw2ostKSI61)`OmT7hUZHxLNA1`sQxJ{zNt5W}%26_g4q5VZ*c z(clRL2~F~lenPsM7{7c?^z#Ti&=294XcibWd0l9)-2tb(sq;OK`?6GF)-GH9>pZO^ z!ZJXnt5fw@HJymCdCl%r5qam&2_iyI1E^bVdDRC#hZZ?R@c=2z#4j+CMCFXfKymSy z6L7D7WxwC8jv7j)<;coAF5782HxekRY7xf(17N)bp zQ;N4(Bav^__OKQ;63h?DZ8V)e0>KBNGP~CVa#T738F2(R)ZZ_%e4<-=q0-)Ixiu^E zAio)G7F}f%HvI8A*Iv7U)|J*R*(&teSD%}#a;#2uVAZ%tTdSNi|aY`&$f+$le(ZZ*)q{n>Cl6z1#)(Og@ZaWXL^eg!ItX*1? zI{zM=IgL%Gtf8vWm|@^#FB;?`D$^)%Am-CWo@Ieq%T>cq)kG_x{S_}1racRZDfys;$ixhx+012Kv`VXQ7TjbjSssJi5W7Ub;{3~) zYLHPAmK3+B7q?JaCc>mP$w$oq{(;D9;-?&KO2ZPbO7_Ipy6_sU3qo+Avf?nQ^>Mz| zTU3Sbo{ZAOL`SvcC;;l~E21_!;L~qmRMPQ>rXKu(b!3hS<5`eYQwJUu|L0Oq#1kSa zq%Gf8>nH$MpaWyW4fiE5rVuW$z5(P#Hg8uaEO7ydNo5VeAw=lRd(3yacY2)0mgv=x^m0_NLm-1y%lQsS+3A365Ql=$7U0)PupH zOkv@$XZ93XsC#tHFLbL#AOOFIgIMBU_wWBx*jTGj23&3}g65OWMj`EnUrKjAclS zlYsFK84JoE2n!#|7$H1{Ie(G z!9QNJ2mUd;*vMaliaO_PNZ*~9^75~*2+rI^N~hS%ed&+ZR`3I~fbeId8}w(!FQPTz zi*>Vnsrs6DK)4xZ**0~c+&HxLv7OYr1!NI?QP^C>_p(qB5-CrKvfRQ zmCuQQh>#7Y#LTb?1)J@>^DsI2Z_`D*6#@NNo@= z{Klb0<@wvez&V>3!4{KXzd>KT$i=T*| zpMarkLz$D`h^Ddr$5%?7G#Fy>CB?$~i`yf;UY4e)$(MhGoKb)IN13Db;2*E&%N4G{ zkOrfV_YK!H%O(k7H#8_hQ(RNiG}qjm-IH|O7SAN8C--9%UyVZiZrs_@P0X@&2ZceU_IlmZxx30GfPlY|638jj_@va0Bv zuds=_MJ@C_-Zv_ZzOt%+7}DR(C;h(lQO)wXJ?)bJjXWq^au+8{&?M`3>cJUmqG-HZ<~Pd1MG!d4l$)cLPj=O+LlL_VP3ET+ujx#jjq;7Pd0-uJ>4PR+e6CEpNcPL z5w~c0bl_j_#~KE#jM8Rou|cayG8~i!C(4C$K$+G{{p)&5R#0z=fa#NnJk+3J_c`pf zL2EOotaLTrMXEskC0}sKn1v@Q*(+4ScWjwj^AL)3axoJ## zW=AF+_0h#ooeO-&{ zkrpj03Rr3z!78tl8o9>WKEwzf>X$GOs5;Qvm19?HyW-G91G`+pg+E>ku;yCeHP;2U zj2rl31@%N%qcIj42QgWd&smLd%x6{HvnmL6&~*uff`AF3*tIqoBoyG$gyMzz)9-wQ z!r-=%?}4h0acO7N)xXy~4e2n9Q{I-1obv8qi#ed(CT*G2s2jL`Qv!5)`rGbhPtV4$ z4RkPT3_Q_Os#@!?C2p;Tu1_PKsJR)i@DEh#ib*{ZZL{1$<$0rc1By2Cm$K$2Onj+7 z{6Ui-kB}gT@J2mi`*>k>!M%KM<-)`~;2V8M1%w{~24bDqN-mL1i$=0E&Rmy@2KIlX zd8&>$6;a{#@9mgqf@AYDG9H>u?)&ps5QA#KC1OxxFKXoi1_>_S#NfE8(#E~vYM%rE zA@M%NoXnZg89g-XuRVD~;=r{sfTUySwNh)sTkH`{f^ghQjF_HTET5p=*~d~DatAkN z963@tZ`A+46eoUwbO9@)URc2{>Q86$g=C)krlH+oHq-)k6B%KC~60wCA) ztyX`$?@1o2QG;ILvq*(JFni)5z@F_D(3`Gu$+K-|UW^VZPAGomw29g}DC2e86 zOqK}zEMTby1o#MKilt_JK7WC5?q%I#$)2G5EFR!Hf2H_*GKqb)i8j#_?k1k5nFt5i9YsR-qf0nZ>}P9 zy}>~Y4pZ1EtcVw1S2F-%FF-+esYBxS=hTv=9D6b7prORU+6Y0^v!xbL zg8iJyodaUyxYiPESOyLWsN03CDz-s2_^RG)sv3+@rB$lh1ezIuq8BotR#b{t4caQh zzgf_DRO%YNO41~3521O*e-oI+5I#1yoeko>Y^L z%%AI=OeIS3kA|g6YRoeWQHfpNCUSpghhR!PwH{s^oG=~JE zG;WZsDVo@^mpQZ$8SkUSXmu#pMoTTMVc5^qYmlETucod^Sx3hfRhU2%>Acf@l@k z8Lreb@n}649|?z;z%rrjJPdzAGyx;0XnQ16Q-wLeQ5}mBeI-*jGdTEt*o3+TtHGuavF`_3@TGV|>@8PZDam0xkjHqc!-g{M?{JC)&hCw*= ze$ngTKR^R^GB`I50eD1j(Rk<~g5YufkRSKPDrH1`bW*>}znicDL$ z9-_?J3v8R^3(q~$X^(>ZKVmCJB!;vd2x^Ne_LWny<01c9CXbjT|4$PD|NIJQTMeOx zCgK0d^PQ^Kp;|Ho*^uBS3iw`tq@sv{2zY4>E@aBAp%SX0C}c2j)y0}q+Q37JKqLuD zu%1qJJ(>9cPxge8s8>tO&3Pb)5~GvB)R%}0OyqYN+5m%?Rg zIuM6~KsJhQ&_loYLxAoHYR<)S#21az@h|Iu_hGR>#`*IA#NowI_AnK=`Bo}$#00;p zZ$C{!h>F3|&`aii!1ehA1mj@>*P^a|om^j--^izS?hkffLzcKiw(>=-8sLHV8sf@+ zsZvXqrIl~UVJ(^#Ic$&%H!x-i2c#kh1W|YZV#(!+`sQ|)B?aU1A*m15}HB%EXq-D*cm}V#BzbzfboC0C& zeM_wUKwB8nAi?t-p|a>PwGrhiPL5Y3o~BS!B&J{K6Mcv{hbnc)(#Fka6CTU{zB~;8 zFazquc(iQiF>F9Pso6?}C=h(6Zc}FiaQ;WSHsgE-a+c5K2Ez`-;Kf!g24R3KOn2-> zrM;+<3pX(Ac`XKEt&boW{7I@9EO^+6!T4V#i$NvLA+o1|D=tY81D&g2SLGd8w*f2Z<-j^vu3Dl6n#tsC1!(5V(gN@Ym}Xmn*C*DE8>(jzVRei# z2obx&xMl6SUGGGKSaQt`#E1p5Rj0SVwI{OF*`bCF4P>;T;~1LFYCSh5Miqk9NThIs zPLj*0myZD@cErc5N&Z5PgKXMbP0Ybo{)2{U2wE*BFx;_OIL0@4$DQnfAFSvEY=h4i z<%S!7>WUp>?#=jgJH9aA4ucqceoAg;xN&dSVDn#aixN5Y6^?rYN~{Ss&5;syEPJSwPZ`-@4wRn zJTO<3NH}R08lY#02FyuV8yvUikTL9yJzLdKSzZGo1t{&XL<8%=K-)~7;U_GTb`NAw zQ(HCSu$|a)K%`?qlA`3z8)3KBIDJ2G+?)0~OZN_PnjnaM_Bfd+yRvi%p^kmX@Ok4i z98IgsAH2#HZu#EwrMm`|H+{XgqR*SY$`7*g1G@6D`e*#n5UwYDGnz^AwSjzV z+FC{Vs-%2Xk_6f+&>I9Ka85e=6O&Q_z07GoBbOFWtDuIVEo$5=G-{+vQ(F~S^+8OMNC?iSiNtszO5jt8J?Z#oKP$2H zP*Ml70zY)Om%{oz#_Yty#-5Y#n>b|1GKX2k~sqOP#|YE;G&Qh>ifI28!Bcy;DAjc zn8+q6{8ZbIq`xF50L>v9xt(2^G6y3> z(yO2{P#f-r0cK);>#RgVi))48>&9s2hP5<dwCkF<(3a#C*McqoAlEBPZ)9xO@SznP3E0>csM2gOeb`DHftcMIG8-uf!@u@ov^|*{g z>>*S|eNw@Y-6#P^>~_=_x0pgJo8ag8ZIow!w9@Ed2?ZJ)uOzq-a}felRhWav=_u7W zH`(Z}68PmdXJkGs6aU zH02Mzd=jiZ^_71PyrYoh_MmU9kP%iZXw{n3>6@%IDc0({^3hmvLM~K&?GmkLI$YIiu?!c zeTIDd3iasnw3((R?0J=#(qN-n9%UN*GDE^jCvreEXV)Yu)ue2;KUWYP4A%0$1DFpy zn{`08uF;%#q~utXtUn4zl4V;YTh#BL(qpLxWON(R2H0tJ;!Awwxcwj4d{BRcDWBP* zew$KWBV$-c4OO2k#91M4>7bv=^^klm*@7;gNr|Hh;eY5?hFn6tM@(WLXqcGRNEh5m z4IqS@g~^o*H}L#io$+&E^ihnxUEW<=GDwZMYYzP&owbJQ-jweTQ^`jv03(V+*szWQ zSPPG2Y|IPJ@MfrmHO4r{hSN7`R+@l8y@u#5b_|}ksIn)M2&zUL1YN)e-Ne-wZ@ooX zT#=E9xv$)ekI08yg%`!w;KjRN;KhSq zqS{S&(cA_;9Z8=6aRlzNSzQPu1jmy+UZ^!M=kNb^FR)&N2lz+rTrI?`GCNfu&* zkLr+?%*6Q;WTKnnN~4xu@4T+7L#$cP?RoxnC>`y!+KI>!q9Rka$tiz}=5)WFYE*xT z6A4`N6w+dD;J9IApMf%)FdcrOR+!vq&Zb%^4%H46q4k#a zCS-jB9_RQTf5FGUQ-ueDgB`A)!T4kH7}zt=Vj@HbyaHOB^d@w`uTZ2+-BMvc-6J?R zErmMU?#FxYK+a;aHxKN^cQc;Pg?*cs#=boajL|3Bo=5`nAM}Z;T;#+I9zS#y#hH)A z{EW}}^8KSSm_2|t0-8~UU)cYWH#_>mkIzr3{}%eb@RJa~!Zgx;=Bc-&2qSR~2ViKA zs_j8gt`wfbFW+)rEePbd|3WWo`$g#bkgvab+6oJZ1H?Sze=i#E;Jn(iQvFM@mZ0&%Y%7d|lH&Jq{IMglAbqHZNIZaS(xUxg*gGXw+rr zB?v|#KB@(=HSdH7Arhf?as%kWHqgi4K+{sklPqaKAo%Dh3qcYUM|KB`jwFkGe@XZr zPXCoo-mJJC4mk_XkZB6$?*eTgl zcdWePm$@9gb~^epmv$^7pyD8=K>E(d(h9DMPL#f9`@hltl;c9=g%_@#P>qxH#S?TL zsDfw?BsO-b1UU>fB{K4)`zup6q5arND2p^UgILu)2Sj`W4#1;f68*$K`*VtPEuf0{ zvqHH59CG3@>@Fdr379t~ngy8@?&D`Nxcr35)%sNPrWoGt*SKSS|K%70bd zb*Qo30P|?e_&B_1wMCDg#_Rd(ZEP9if5l(d{371TpiHoPTxZL*2K?fIG|i0L=r07E z?rZI|gBU+VEHn4WJTf@K0>szr;`!%_k*#J*wVBmyJUW0X6? zd&w+rMI;|9+(fl0KHzMgnsl7;J=i96iUUZhHPHby;~PfCNoX%hVQ6RVmY=TW{eKyKj2 zg$(C3Y5Rl|?T?=05A4PfOe_$hQ7Yh^n7ZmX7$vNqdV*D@l}`rgLV8SKYG(dMKh&cF zLEa6#^QL}Sz~&0MRauQaTAFK$H@7jhIa)*%7E2wH3pcQRMPgg0;;HJc+uHHC2indv zQ$S1C)|jPmXfV=f8jKz}P1j5q{J4Sld}yA*<|gUpVwb_(X{yaF zO$3dJQ;cfzD1-B-={K6_hqL;leFU06$E)x3K@&)*-v0Z<>LFJDt*(A`yn6pL5_?aq zUUx@g^&?sRSY5quy!!jbS;bjyf&Y(af|ZzSS^bNU0AIVnV@pnPV($=AqCLg5sYz+X z=+ftONi8wQvAF^b&Ha~pq}*~=Vsi}KEHqu-NkrysR=-d~Qys7VYa{s@nM6)}c79^@ zZmfPdt9v6!H6#m)IMX{~Gp>JbbG}UN%Km_fXtaa<0qWkUl3X9()#bJtb+H|YW=~gSFIZ@pzGAqFur|VYXdUD3;azk~wa5U#~U9OnrcGGG_ zDlvA?Sv($8!4ka9c!b->aohBD=4_`1HxJ-uwu1z5&LO(BL#4IK>S)iNy0t1E0pUt( z_^y$g^V52!MB#O29GeiW)S|6nrk@LSKLgEeJ91Qdm|jD74{vTq4^6)}!)EP&a17Wb z@ttz>At?OwrIcaf=kpm%`~v<$K=eIqC~Oi#L9uTVzNpJDg?~W$j8D}eSS#d2nUZ1R zjJwnz5f5A<0@M5t*27D9YskZ%do^6yOkIK_3;k=ey>jn*$GUbs2Gk*(V7 zJ_4y0-1Cnp-J>rlhZCpROp>iacX`MU31c%vL%KSfV^w0#<_K>Z%&)5c9>;NWMBxE@ z_a7`$5c2By^N;UNc#crY5J4IZpB2ndKbndXKU6x1Pd20D)QuRU`Wg!~)$4ko z2KVj8;|FBeYE$QP5jAw{SCL`Ni{y7$^?rku$2mHT29vT?(vu+kxI=>wkM`HHG_Ye$)Vlt9B5UkI zo;)+5IW#{$GA4i_F^wON(Qu(?hWctH;Cc<;2~dlF*tR!z9j^T0aY8-{YG=-ue~rr3 z!TItSqc0*9dfh`c`>kPD_^stHA2i5?n^QfSRQJ@9duYqk3ZCbiB({3r|Ic|BEe{82I!ZB>exj9=AK^;;IQp zZ>qW9?A^N}kc*O?ye3o$Kxv<4nCuGBE+L<-=WXGKPQ|M%F5H%33 z>2f+b!{IRqfJ}cY1wv{d2ZIt}#-kxUwfE94^d9k~-q(L{CO=C67>YSOMOE&l;t0J)pboygJ`L%^j1ysU^!po&a{rk&V;`QXSVb@xRmFSKfEE4b+5(s891 zFTWyqR9Qww=>?@@`nR%|^2m`up<8dyarosMfIsci?It(ggyCIbes~BC?r?bWf4#_WrRN zb4o*@?RNPU@%|F<-#dC_MdbDJ$oBHcKguI-Q7+Ut-RUuHiIgssPPvP+4xhXxrP(v$ zI!K**ak57ESLhieha|NX+m6%VI|}Fm(I1@1_vo7^uj>X?5A z>Q0V(J&}|h@vqMG^ikE%@UP?k9wLzLz}tUOe_5u#i9gq0TKb);yZW!Mt2Fd`uuju& zKhsMZ`uXJ{q&{R(ci^ZMiB!uI*5o71n+Qkcm{u2EplOv0u7oIZ%dcojZ$D=0MxXLE zng-slCTV!bn3mJP8>dHU+&&$v+Yhcx1lqP=7Pn7xP5ayVG3502N$62(^&_O-Bq;8{ zI$zVIM;Vg7njXcb)%m7XA3c6X-zVzkU-vb?Pkmo~gQn5Rrnj^TAJ@NR{_bHlcVPai zL{j6JX`Ftxzf$-E^jB*AK}annsP4ei-$Z;t7Yk}Nt>dU5F` ziT=RiXZrK}Pe={d{oUSif5gvt-o>>Vzg|DrUtE6@{QKvu+>yM^GkyHP&(%ZoJLG>_ z`m7*i?!djiuB?4Y;KGTfm%GtRl6eUp)d*3^NN*pn(Cv?ZGm%JX+Fx_6rqrnhi!}64 z3;%w){nvi3{cBD8?+@)!Uw27f0yD7NHC1gkdw8YL~Nc~}(dM2BEpIx@FB(&j`bp@-k7 zp~JE=BCo5-cw5nTb7W#?<7Yhk#`boWXJsU}SB4t84Ya1-ACiSZ(d+6&-44ul=Uj1E zEr|Sxk?JA+OQ)>6itH$^o2U!HSI6P+c-RT zkC7^W@~UWPf=59%2gRI9q{x!!Qz!k6#0X?kw$SG{Dig)f?^v&qJl!t?T#r5$-Xf`= zLf@R_`>~Bfyf%{QYwLf9<)q|ILjTiOO5Kfkqj|Hh{ufJqkG}P*r0#=WT}=SQ4~AaN zQeNo$!P5PNdDrX0Fht5dshYdlLL5%(5^$bQHHRJGY z!3xeKc`b|L1Co&0H==^uGL+DCk%%=(9v+qYg5Umgr2Ox^^6BKKE?&MoBIPejTb}Y$ zJaxYm`6)taKl>h@BF!A(HIu-;RQdU?2kNJY&rj2&jep{$Pd!uXFHT$kRSm-*e!hMk ziWs9no%`*r((xr;#bo&@lkz@!{rYC9bDUQv0b!5BR-Up_>-WD+>VJ8#MRs5H+fXV2 z-k!};_ermAGQ9Kr$|Q|bFCiYCa% zpO4VC$JH&Q`kOi_pQ3;Rmq^EBypB7v-$f`9hxh&0q}owlwG{ehNq>~DA$j6&CgG6Z zAq5rM#_gR{ymwNex?`<)pbc2T0T`j#mZ;qFL z!<4^%U*$)|%OCc(ZohP2<@4j^Z!+y4xUcfxVO6Eyes)?f$bX0z8u7%>XN3wo@ zhvk+Ap2y$Rz<+{Az}(M2+LHx{9+Tsj#V8yd(!(F!y*8!`F}p`M1i$W)Fhzdqq<;_I zz(rE?60c@5yk$~e{A{TS($M2DU4A{DXhBHV{^EG~ zH!c=<9!^`H^s5=sC53)ZObSQtL0hQtBW6i|T)eRhLQjy}z!% z5pPlyAccR6Q|o`C;s4_=s$Z8{|G*10{=cYxk<|C(r(R3mkzUP++MB*QlWZ~XS?GTqG(uS$YAq}ro= ze}92d(qDJ4a&mv)bxrQ?nJTIBAzq}gKefNbDfKVY_3!&-_3Kb9N&Y@D{7=_Fiu@Hx z{S8i+%@HagRitCD|9-A-QJf;8jVE!m_;+WH@8c$cAsrc1i| zk4k-?J^SQS>GyW8o)O@*^qi1d|ITl8{FhumZTyy>T7UXaQorjjs=o#6KjZ#<#g9_; z9X!-1YjP*VtBZZ*_tWM7lvpX|4tlZ3-3ABYh+*aDncp5anZq; z|J$04_{}npL1<-kaKEy6bXTdyV0{AV zIlobFVeutedCqIaD42~8h;K1^v-cL?X13>v^O#FJvz6<-R#NCY3a=95=@toa&rGUt zMGN~Y7~46ezaIYjzef?qs6Pe-`*?t6;oE{23H^P4y7ae37x&Uj@qEEzDeu!4lIN8H zg4o?&y^icp9ZJOMF?qaH8}C(1p+}kYC-&whtf?a|{dH-7yk_y~5ift?X#pvpxv%nD zurtX(d$%~XKKcK^sha;@ z-46MmzW&?AQh&_P)-RI!K70H12uVU7?$zCw{rIkv*bg;sP$ntJYyznOYv=;zV}Ny+o|tO1#vf(4jm&iX!Z9&Ph7a zJWp4_+89mIWPIvOe`)0RgKva3BfL)2$#0R=_wj$-cByx`S8t#E&+zf%A1{gGeT=6X z(d77|P09=Xcj>avcxAKG#1r$Rybr!UFH0Xcd-e7O-zce{Y#%N;P55z|*F=Z>=#kq0 zrMmL&z4$P-%srU?)5a6;p;VH8&eZi^{6+QWNqx`ZjmB}PP_zF}+n2ycRV4q<nc&uL_sq!kr|yR3M#IM=%V6{%LL;h8kmXXIXj9jy6Ud3x~$@TA=w0)bDd&$gE@ye;^z zIrz!)D&qwzXeR$sp2MFKO~VMMjHdkYHm_gWi+$|i>zNK-YwgWQt?zbC^X?;do150R z200dgZmiPdZLJ1w+1^YO_!N0Bzz4rU+Y?S5$C9^E&GA3{m*8JIqLbMM-D2BbZbL@u{IkwNS(ZRaG{EuUZTx9~viQ|Y%iuE_4>h$UPr(Fy zmyOcS+l~qE6?msTKdcv=a~+(f{g;y{-~YJoKeq;Mx&O8uCjCzN|I#!qM{3LVa7HTp z4<8CWFSiOGMoub!Z__5>9tS1C-4^0KUa3#?)!$9V`STsbmiU_^@J@TKs}%Z3K z?b(K$Cid9T(X3R&5t<|)~vBMh24sIOl z!#{~RAI9M@OihZRDI=Yl#>j}m@+sdvuWRma_7Qqpv`0llWt{2cl$LCdY`H~S_JBV3H^AF0C!uf}$@|Yp` z4u3uY2+G*~v)#8gf9&?HK~5^Ylkj;~pv-kpj!ExSfFL53*ZxrimCO)U( zASmh_|~_c{F?8>gqNTaeVOzsb+6hnnxlnvuYN z!NPyFC49TSa01@6;2%5|{LlpaU4RD@259hB{KEPP++xieph3~B4 zN3;s>O@&{JCZKQ5Z52L8;Kd$%dt;i|bGHU=*`9CP&Gsk9TkPTIiR-1R`2f&t(CoMO zzgqkIrU|~(_pnvp(;6eSKFZ&)OPkBzD8bjB3;dWS&Wklyn0KZ`xC$Lo9QUP}KIcez zPJjHXSkHfU*^RLKgY>NH-h8}R1IQ%%of(n2L3J~HyFaI;!uQbdPqqplOoe}Ti^%JU zR^hz@pQ0c1KW!bU+$i{`IrzPs_@5bqFa7g^-sQ9JN1GQdjSp*(+r*w-vqS2b67dm*Y(VHXq zB44Jpf6lFuTBdi~4yS$XEclg3g7CKtKO+Ip{c~W)YZ|+m@#@YkOq@6g{FO@tgA{k}E&w;`vA{JUof&N2t*nEl@Zz82gk zeii;G!I$>EY3lj-H5##H`_o6@o%S7gU1&YcsmqoZd;H8ul>f`C0=sXk&5M@!w+6XQ z`0=3D=Q$4EvG_4n@TEOBKBL<+Q6sk8o>2+-c92<)FV`FkzK_7C=o{s||7X&+-)L0W z;->O$^JD*(X6^e>%hh+t`JeTDMsxgIHU5jg3O^|L!k=#^>-OHN5mWg?{VboF*bl+| z6-erP0!@Gy=MSyNFWg{_UVy>`nMLq*vXQuupuSj?)y)#y=F1WM6JaQ$WuMr(j!tiJx^z^YOD!D*gdn zF#-J3n&I30$q;zqcaetOx5;jMi}H_Lv=~!S)$3*{yY86q(*)kp$LnxJ1oS-V;Mnc4 z=?Nky)qlJVH$?#DCI=-+y%PMj@%u=9LSL7Wf_R35*iw5k67X+Y?caFJ_9NG7|HF6b z_8${|n!r2lUpr8@-@$3t{#5wRIAXy5Zx!Av@X7HB%H#6O1??;ct(iR9{K^n~;g=un zr+xWpgD@af-)#6b$V`&YwYNz{)fxqMrD=PnrNTd};h$^r5BvX<=-)d9ek)S6-D?ScK?1%DuQUPwKGX;;^KYua zJMz$DfYkA*Q%6(&jY@^T?h}E(s#W+t0-rMf^lX6#nt6nKkB7xU~2l=G9nbB6Ugo73};>=AYL*zn~`8g{k&< zfcJLE@3#I875c_zX%qZ7ZZCwyUFMLc#V5%>%uj)TUBer#!|(rA>$fidat*%;iMr{{ z%3qKIf1!qdzjgSj7QAIcKRI2?e-nhne&SIApVFUpZ11kFf;+&$?b&3#YkJ4#<6};0 z{m%jf3_Q9nwSkHHw;`vAJXrC*We!e~0di!*?yqTpO8E2Rwo7$SIjGI}8I<}Q`_Os6 zAdF~&kf6^i@G0{8-~quo+rc>&eHnt^B7YzLR?6A>jm?{6{@U$ZfZU|<;Mr2W$N622 zL>s7^Xv0qx_!N344iWqGC#Rlc(K{4S34YGhTUsu2P@C~HU+NS49}8&OI%?=t`%Hi8 zAOLLrv+3RTb+i8OhBiWGmLaEgdtl>F6MUyXd$bpxKI!0Uf)o826nLT6{86I%w>hva zjXz$2Z?XSwG-Qqa3wmaf}d@6N|k%o+D&W5&o#)hba(c40j_g^TcU4T0=^yK zIX*tE5mNbY^DCHu|K$hW{$rN!O~9LgXZZ!kDnAFAiT3_xhg8wHrq%XtLsk?0?{>W2 z|KK1UOJ1i5zV<)9x7x1}TWP<*JMwb75&}m!bv2b2Z=(Efw_5E#R{1%|Oda0RG@B2v zwt0}$oaX-Z8i1wZ-?mLiocrtWr#8dCR^yNVb@)R8)}%isg0JZIi(4w7nLW-CeCdye zV}h6F;I$;b+g9oNATzT3c8RLfYV|oXQq(_nytn0f8o(0rHdB-Ol!Mz$zk*VqBQI#z zZ4Pit^m!BTvCUThYlN2ND<=W}rll|LW5I7*$@V+)cwIZOU(1o2><}dE*9_#yek(bD zrF)9jDRs}4diMh1{o_tKh1QAsruKJ~)Ze0gdqI~mz$v38`<5^G4*fs$m3mKbaGL7V z{uL?h?R=5IZ$xU#?Oh=7DdX9#7Yfc>4o;FnHIv7%;7fnsc)sqx2Q^~L{WmlL-_C;f z91A`_0Us;S<##+5{Qj>}+Fu47$lyk#w$grq*YsQEf2e_5rhjSzzDSon$tk-f`5q;5j~a)Cev2 z&;Bpjey4oGZ$XmPc3ngAd~rbn{!LBKM;aXMXo;Sw3HXQSYkDTOR6hN&p5HY0$A$`i zi}s+)BH_pRPW?TT<^y*B<_La59##m>(Jxw)?`_CQvVUt=3jFeB@T9l!U(M$m(^BzE z{;B=HX81OJ!BqIZ8h%8p@LqwJ{_3S+&v#&3;(tzR`3p79(a&3LKXQ`V-{W;{|67Hh zkqTe(n!vx@DttH@pD#}Se>s5dXq z3L`?mK+-;6wD0vFG&aU+;ipXTnJe)f#x@`F{Xdy}Xa2ai@%~^zn*IJ8zJEA01MiVR zV|=);u5IIHssCqvA+TdlkU#iX`6UIbD(i!71JTYOfwqGB%2mO(sIc>!c&WkHOYxF9 z8ZV`0t2Yar$+f{0=R1J-=5V#2!_pPG3yO2$O>3jFUzqjO_-(ou#?M4=^ zNzNRrAMv5bOr;-jMRexx@Xb>I^v2^e`jKpJ(2s?99R98V6yvd0Kl;cqhhKhkNx{-m z(vI&UTn$QMb8y5ek&pf ze}&?J`^g83T;L&(4_@4Pofkkhb~r#Exo7T9` z8edQ#w%m6v4}d552Ug-pNld!u-TE{L??;E=x&S`dz9AlIBbmkzw&A94el`Rp)gXm0 zWB9VfdMU>@kg>UTti;jLI7qf}J;6+9+G~eh2h8n%_eKVui-}5VgWAvIP9~v=w>D%IsUNeNDMz2pTb{xU2 znvt_Qy5@8Mcr}^ki=3MGa)10Bug0v7<2LGW{$5GGg#C!yPIrU7Sy@QJZ~NZN0wL&R z-sy>_T=nKEphYg2cO3H6yLap7bI-d#gb;jI0|)WdA`6e@^xej2a%XxteV zzx%$x>}da0_)#~135d)G2vHOK9<&YDnPtp$t&BtI$-j<{{Fpl$SNkIPeuC!X6cpqq z3e;ZZNqhP~jQ7QvC*gm#SN#dZ0jj$|Ey#+!wIbe_=s)SNX#Y&)s?BVedFr=63w`_W zb5raQLMQb<+qVum>SN);sqbjug-jX@SbReq-J2+%_p#$@Red4*0p9!0`_Jd{<1L^W zSAXr$`wo0&EMRU8n7adJgF5T;cw^|`@%-W+uAwie515UK7(0HsoAC3^#p*?H*=N?_TLxKw zhg?Ma-qnL2-7PGrQU6$u&Rw=FnP0F|ch!SG_+A8htR1a<1uAzzj^)zQTe5L+sk#t2 zxV^No^QmMHuAcogT?ou7sKNcE$^7K)phxBv3jL(CZ+ss(c_yR^<>M~=;8jF_oUO&Z z=@8FNYPP(D^Ru#1=5HaaNc5Q{E>$f2-=tOqIh7>e04lXixjG9gpKz9 zYd+d)E<#(!;>#@YzwmqzE^nt&4yFP}`3>;sJNn~!sCyUdHa9Xo+h^{amj=RB73)Lh zW|1_D$`c8RPby{kDXl;;cLdBW`05kJjm|UiAqTYupPwmM#q0ie>vD=w4um}yMP+L8 zHg>nkTf+~#Ok6;s#JhCHYmRs3QWYl0LkAmSZ*WO$Vmw!;khnikI$_XKdC{_GQhCpYS^0gHx_MV0mZ&H}ix=V#yB`~uMj>`Z~Dtx z09m%q_Xl0G9~KdHs`$wT_4p*ZQTY%kD_BJ;&d^i@JE7aiD0Z8ro9gk!5JFe{2gEOM zpD;d)K*NAf2CT-%8lXo#<#RtA0KnEAj_o7)d7!0nrO*6MOvR2yd_Tguv7hrJ+Ov6V zq}mE2LLEKb7dg>qF7}zw%pqVN1dxF=b8z-eu@m?Oq)4XmJQctHE8Q?q{1&*@K#`@c zf)J~vi{gz#Kqg4N-g86aH=bKyV9=PGVd$pF?Y>&|<-X#3ty+(9U$Gw`&V9vfzf*?V zJ&#eGh3XDexfp~{kQUo~y}P zQFaypF2y^3&M>Ajr86GS(ka7{(r$(L0hkxa?~v+#(#wa{R`RT}Ml4e>%Up4j_P5PV z)%+lpny<5sXX}`in6FgUqe&P;AoxF*ofyBt8TS^teWAEJc)2lif=iV^E%Bk)SlqDk zVLSrn_radV%tuab3`G9`ebpe_eWAmRWrgZvmF~K!poTY1Q?KNz?Sl2{&kzY}6-J!z zV2GetDh7rx%E;ArnV;~Df15C%zRJenZ>f}+sHxNEQ!K{gGmIDx(I$iM=BArsZSbJ^ z(R98<`&(iz)@I@e%>+Lh<2RR!&Mj`sa(r+ZW?)3Y=a(w~Ebn{NH0%8lyjSPpKYdsD zOHeF5uxis7Fn6dTh!=h_4665lCE4l0k-UBUG-TnIS%0y!24)4lFew!myMnh>6uN>p z2h6eAUUNJqRDSbj8EBGB9R|CHPsJb>?fVga=CR!vY{%`u6#$U;S>SnN67(HY)FsH0 zotUB8HX%rBj*<`#TV@e9PS?&j>j@LpC@Nu1_HovJQ2Rae-Q^uFFQRu>e zbOjxUe_JWQErE3$2#&5QbiO8+`%l34a=Tp)j--K~hg`9Wa z;u5sd<%%z6`aQ|%bgNzQ_mlm@>q|It)N4B!yfKM-pZN{EMRm5qb~O4z3xij{?Pia? zVJDTif)`4R8;Q?2iCMvJNsT}Q*p8dL=3Z+Aq95R?7Sdx{u>MOEycTsss)qS&soJ5= zCF}I}YIdkCbrgohi;MG!s#YN{5W#n)%taWb)j;I#3mE4t@y{}=^q+W~0W${gCtxn| zH>j(k8OQl+f4K~vlfU+0W=XFlsw+mI%9?US>M@XVM25rfd{7AEix!0+9epREM?fVe z*YGgZu2Wr@Ih6PGMd)@R2@{phpPkatr7q~)7CCSrPvs|`veek4h$yc^*@(_1&A%K( z%vU=>A4%GyRzV8Q`SA}$0G;`t_V2&aY+NhUQAI&u31)PW(`;rg z9wdG5TRaF}D^zyzAn`kuQRiM{iBb;MH!~(r`#ydOw^O;}y+}{}CZ6qQT zb5|7gD~kurIL1xdMwI%U&s}GP*GPWcU2(~!WpN+Al>T@fQ}FfD@N7Pq%LCDe=_>_# z)vJg2AwRmfB_uV_>!`Y2KJ7O)jSA&2I`B}QKeW(YP*aM}S?Mltd?DLjWAcfE@C)U&xg@|zoD)3yB>4}|z4hu+Qw ze4oi#Gh_!%h4i)8)SqQhe+z2Hx5C=bIlVG|jk%;@r@5r|;OVu8GJDnCQ#YztZRnRv zjHkAu^w6ObjHkZE!#%6|MKe0adTWv~UPCH-pq|*3NTEH%U?=kvOs_4`62mTW7O{D1 z4g|%r7r!U#I6YF=Rcl3tj^w15@N3&N@0W@4m7VBEw}{@^%Ywz|;5~3ZGt|AG!dbxs zdd<$PAivdL5Ju9uU9Rn5=P0_<`Nb%*dGB<-^+3VG`KV}08>ZLH6@WNvelc9rE&1c!@sQg z4c~fZ{|)wO;{W&lj1HrT!+lWn0B!7L{a| zt%Kn&D#?Yb68{SJXDb+=Y%eP7IhqH-)km}ThT6D&lgDP0aI+!U!MFHw(Q?)15SP3# zuus_Fk{wx&y|`{jHNz6R)6h(H{5-3><{RP3XoxR5I*)xbq$-n^?S^XF3EAG|TO8ul zihp>Vg`W)kQ_I-3Xy2)*&}W9GGp!A(C3_f+(Ct;`tN4+;&Tkf*}G!UQA?9VS`!=YKf$lK4re0*{IZQCwMyyqy?>$J`^bNt?4VTZP8?~&k%kf+NqrnN^Tebr-~ z(dD`GMJaNV{OM@lEl|0FrStf0SM}uvTgzAK{?aPH054(WGv3EB=&+XOi9hC{`+eqC z^)G2yxgUckf;yW*^~GxIXKZWvh5Qia6kuY&&_3zI8unC#YAL)$nB^MJ)}a4bn7I11 zgZdRB%J5ObzvlM^JtpS>@Rf#CpN9g>&$(z}9x9c&bRHr>HQyJbI!vU!`PL|mnKdAh zh|iFk6Vqg@`49=7ilg|7W50a!yDs$wH50d2fY}olc@XANXS_#O!<=82?~+#i4Qn(_Ed86PlT@R(ma`buX+2bjT! zSzBA<131%D7=nl1@?icz<}gr`r*2rv8%TDj_n|l_W(rkQHQi)u$zoQ*K zky3X`p8`)8^dA_1>4i^N2?yU|EkzfAuc+Z73|7N>xc2fB!WAx8@GOw`{BKC!PLb$> znz;z{HLCsJrMqJHiUt$$?0F5ZZY=AUra4o;?$6lNbvn>0%7R=KL7l0Qg^` zU$Gr{(f!Nl(EjVti19$zPWoZ>#slQw4mIx?7Zf`UkHLr3R=jXJ`lnrD)j4N-3~)fb z0jRX|WB7_1XJIiF14bV{fBF`&FmNnV*9dgxGn_Td}uZLZ)}fIRR=kO8bMNLgMZM&je+PW2;cKKY+P9b^(=o-3k^)Zgc;P!PRo| z7wZvyA2Ha!hgJ4UH^z@Ln0Llbw0%Z)4g5#;nOm}hh(T{c>R=$<6x*;u?-+Odlcf1f ziMdFR_oC#P<2M!yZ;Bb)&7;E!1`Xu`Tp+(UR|U`EVil&&TnNN}BiU0vFcfY_(jww$ zJ7o+X)Zgz)b8!jxC>iw_>oc{^{$%o?5=Jtrm`powEU3OtU zfoDLNwO!VGLff-KThba^CC#Cn4}81eaCG^ij>MZ$w-Z6G}8Wq4HTqnA|{T$&4zzK6p-|sIolHhI>PBUV}BU zOsRTrZMwk2gdt8aJbxsavGh)wnN6w|za*EQ7|Knt@U-u1+fyzNiG3%Y`%hwSfl>ak za4L44*u)BS0!ZGWvQZ8Eqi`jX`JN|D7|MlV^aD}y)PGTF?3)Ch6a=d8L}lu{Q8KHn z^s)eGaWQPrwDo9v^qqXx((1RxG5XN%S&PV3=dhUaQM8|5Oh98ppNdD*b{t|2pX!pL zed~@#G@bD|HC?1DI38s5&rTkSgk|ckHJXXwA#BzjW!`}%d@N1CLMGTD8RTy4C8V-N zxoQo8`X$;)M$4DO^#D>OIT%OH)v*hRq&r7!w^?gzSvi)sb(?(AF>Q^R#ckn!w~r2P zs5q1{uB=~P5cYB?7x6c#oW*nj_IS+2R8RH8?euRNjjH2WIP!y7pJLw(M;}Q~&<1`r zmWIy@8v&6GdnC*0E|{}hM#BRj;b$UC+cRHi5q$qP3}pt_myuDPLhPX`{T?)3qUg;Dhai=kOx@~%#(k_37s{oA8nHS&F?mj`W6 zB~KfhH$Rr-o4t_QLKfhexSbA*sz5n(v#Lg=xjYk(x?XX)$}mj!UEGd}vPX^iS<`V4 z^^}Bnm0ek|9=gR=Cp<;Re*NJO}Zt&otiySi{SM zQr-m^jG>m(H5_S>z@DfAseAa`o6qXHaoRNso<|qvn?FeTeSj z&5&e-=K+3_4SrMX;enZn^HF;Gk+8>rHNuT(thEY(STt4%?f|(6X6303e*#sJ31d`F z8$@vUn`)@)&V}cU%0oGa1p(AqA9yFgJ>-6C96;(AT53#?S=8I`+ zI)B6WY**>UPX?bMf|;GZE=HX#=%dfXY%Nkp>s3C0iqeQ-6&7otdVRN5;r!qTW;{+; zmIMqe50+L$gaQOV*n0kPrJ^eXkuovU@gQJj-zs7}p$!9r2!!e>@UrEY0>eHv#+Tdv zc|0-y)f25Rt%Vszrn5qa++Ef;tX6Im7y3Spk(E+7hvqt2|KFp>!Gcu<^|7ZwKWDSa z^I6z8M7qRl#(KM+zA4b`i(HR5)2iTUe)A+~J(H3~R49Y(?{!|a2K?L^OA4LSOEA$&dhik4CGDYph!6As+eZHvP zUFHWp<*<H9Xkp_$8JazelG>7G9`64s&YnTBmS6HxgP9}>f;&~55iB1o%3XWtP z<|Y{+!Ig8=OCzZ409LDiXhUxaE*GK?aNyJ=D=S--TTi*_e(NbqjlvV@$p%hdOeMxo zv9FgC4vuIqn~)5lcB6Wi=Xxw!;7cDdD#wUr1@x}qnKm?6>9Dw|9!r95C(r``4JSDP zijILL->rr=13gJV>l2_bB>=5gy_$jk2y?Dp`w~$P;ag3>yfbUB-}sQrIWUqJ*tS@` zhci1kp}G$6cD#$@+(mnnB__5C+yK-^fU@>iFmS2Yx6Ebez&_(K&LB``bt3i`!Cr7k ze~u(Zy3@J*`2$X-f>+DD5LOT3jAj$LBBIgI+>%O2R#TOxS5T}Qt3Qi z#Pud?QKhSMxHgp)V0tQ5Z;mxv2tqXI%shegg!W=(Yo`b01+e&8tR};m zl;X;7hq`h873MnoMD+6!sJPy;VDJ?ihh1gGbEp+|rSG6pwH5~)bqU?=^tX_%qYz7w z30mWvr%Hu%(L%pxjHf}3$FHEM54S+dLkmWG&4Wpn-_ZkdKicRes=USm1J{ zxq|11*BfD;t+r`MBW+z^pXhD<4jHN|Bret+PfocEc@~~?A3;A1qqA!xZH>7<9TmEdH z!G0$^gb(Y1RI=p<1+jyOJiWhDp@ZNNw%A(b$FAJYG1i$sQ<}LSlkwvHLoghKe(ddw zoJ;eU<2TP0jqPo-SMUFx^kp%6;QDg9$f&nNhojk+`G*LLz(S)a+|1NnldB5dQHB(@j=HUe{y^}&%YzAOuXVecD|OgFEN8g%ic?pv)`Ae3-1;MPvkgu$@R1!H|NGfx*jcO3I2hw znqZGq{I{hL1ZTo-DUsT_OzfW9~d_JKme>spJ z)@;T4?Yt@Agj(_v<|@54~V7c@|@TSsmJ( z$kgNQg5>p2jDOf7a~OdJ1y?43jnYetUG;TXhxg`>mICoGMn5EZ)NnBE8UqNLjtrPH z@+$zv-&gS4svnKgijnU!D!(CEB_fE}eK8QO939eEkQT7wRt#B>w6+6yOhh|=lFcF5 zOO5~rjDSwtYjeK;5%Nv>MS#Y^Z?aN0}MKDJVCh3@SIm_af18yp76% ze1-8XM$A^-k8K|C3!$h+7&7CkRi`ruG)T(Xqvj3KV^^^{@Ld~}+^BF0t`X`U8w-ii z{ZWbC?b>PP?`F0NznpjSmrH>BEw+9~TE7+6?<>}C4Sv}VKH!5bmKTnM!AxMzF#V9^ z{3m<lN&+}fwYP!)U;&p{Z5k;^kK_+i51-0`+NkPo)%l99^ZrCJ zxoY7si!~QZF@Y$;z5qi!R0EFyu)Vp+thUzBW4pmB$FJgmzES3BP_)Sv%&Pn+rWRs( zV%Oryj+Yfnkf{zmrcT{VMW()0{S6SIA2N(^H&p4Vc&Y{^z-`^5{DW<+d+eJwh|+E| zswM(9U|vGa`vrkojMKiTHLZuPQ~;AIJ<>z};}>-h1AT0zhD(UWpS2R&-3Tuqj?JGn zlkt)#C9?I19^~2#;c%@@(CQ!MBp!@5cq~Tgno}4OV=w>pO4weoum zvL;iqUPuS}pBiWdV2|s?Zk>#&7U=Ah%p{+;Tt?*P$<|_@7V8bHV+6W&>)(gNk2EJ&p-xzABRp7CNY|upS&La-jIja7|AjsbLG5(u-Pc<( zJP5_J=~xWK>{lNhqea1;3pgWU%Zu)RuJ)ndr&|5a01bpd$VN_XEFBG@+)@y0N^L=` zUjstMgODkd*vhN$6uX9WO;K-u#&Oq*F~`P9ZC;4MUyvSKj8|*iMwP{&(=j8EvTPYf zbiSwJjT(@9G_2-*82)=0 zVz^jX*u;LFclm6XlTeA?{2P0U^=-%brkIKP)PL|4i1y!h8TRZ2F*>Txne_>>$dTQc z%vrq^D<$H)$fXW&>UPS{m@3^nR5~U2+sYbShm5M3P+tJ_0Dx^&`pijpg_bnNXa&@r zQVP}!BSSHXfF}DmIC~msD~zf!#D*LWqpNisYxAiCKZ76$WQFji?{DfU5{+v25KAOn zNGEPT;v$YV%w>dEfIGC#f&&*L{m=OvuY5(zgCnqH)9+#<{4aonYjB3L?D!a$NA8${ z5DNBl)nQF1jr+Oqn!ZR&#V{I*p0XKCU3ii@vF`Ipzh7%ASjbf|~e5Pw0!r*lXxa*iA%TNJwlOir4meGQB%YeZu%b>z9^c z{U@{JJDjL7d06>x>+pora%LOZ`(e*Zk#mg$^H>v@K7ntBq zc@yC=hIFt|%?gq2QGbA;p+uwui(JlwK(5;jiT&cTlbpn^FwvFsfDMr5s~)!UIy#(AHcdd?DLn6}bWF9&@Q@;+94f zg2IjPTc`zFR>=}`c@OT%#J+?st3q4<8>;iFd!=9_d>pB)Dfib8%y3&pGH8&IPmt}R_zbHaas<&pj%<0C+fJ%JR0k6)@?o?eQaE9TXx+{9$f z#Ew|v7kEzD)JVM|a)iLT&v z)EtPEW|wk5JvP0F$WJ3^e7z;#SHe^3lRps~f3%mBXAa3w_scxasA`k}3q0hYau+0# zHSCncD|^c({SA2WN6H{UdRT+k@zgG8YghQa1pX{($RjHklw?qTV*f%q?Hao*e5>$5 z6j$onp-Nws!LSRv<<-~qU`SULM2Eozm$iTG7L=mffipI+6q%Poo;WS500?c;Nc_r- zijE8a=seMo@(=E=z1IS3tL&tL#?bgIHzkZ>kwxv=8>+id-G3IRl?{;3Ty<@U9#=-H zsxM?Ig>2_iy343!)X^h5?qWH%90h5QptP#p)3SVD`6l>Cdnk6g0|Tb!z>L@nNENw5 zy>AC{g$f^*z3UD+6cF+=IH6!H+-^50Nx8};GwaDsMO z{Do$(iRnT21&?S`c#@o%=o_+5{V#}o!UhtMpp2Hyl%1rRj1>C55hpiuy0Y!$G_8O9Svoi6ZhWKIWZ ztiMhVHt&dHB4|>uN;XZ>ZN1`a?V5=15zYL3XEt}9gP)Ho@YC>Omvp15ysQn4XBT8v z)_}yec#v(^4L-xW7b`1$zSX5%ff`uqD67=*$*pw9mkIcZRbHZi?yg6+UERGh1Zf(mvPj8!9y59nqqH=e?? zO=V|0u$7HvcOXOShB5}&DpazRGY8a-Owq3W*aOY-Myj)s1tU!DGRx7%*m014wGAKK zjsKkrqLu=bmEHQKZ4L$_zVDIEFR?!4V3L1>@Tkvk{z9X<1768&co!}RMHjr|HiWN2 zH61ZVqEB3)B17%Qf;qx=xFW^2H#!`+5yj{*J0&fP0;W1C3TgQWu&R15MGLX8jjG>+ zG7kHM(#P)PV4cS2;F;=Gys?Q0!!J@ZPNdnzQtW*7!X4aTqgNHMe;aRn)|)J?cy}Tm zs&^zsJ6|bPa!UhTdrtM|L+n8g_D1t9Q)+exi}mX`R&8#a4Nk)J)p4pZ_5q6;P;e6J z3>`i)3l4pwQ8FLZV^I;Fq{t=O%Y#=;WEfty$0z1{;Lp((m~$N~A|)t&_U&vR4km>T zHz3}Qw#lY@ZO_&56h(GG{0EK;*l*hT0k|X*g>8xL>p?f#d8cmJsigd1S}+$YEzdfDgDn@7Ijd3tW>S+7RIgoF-mHJ+Ux|H$rt z9jATYkq6wzQl5O?+nR@$VI4sx$+rJpP^0;mI6okg#9)0ibIQjwXrnONK$>zXO?=3+ zA4IxhWn8i3V(~D?ti2mk5PyAaC|}&vq|hCwRt(C)mwvC!UR@x zjM5AQ?+8izsRC`BUJllK4sD^NbY>I9 zZ*D{9iD!`6<^xEU0nPR^&!c4NT+8ui`9-!n5x&(SQaRDo` zcShQJ&!&hgF^5`AAvuI$is)sv;Ng?xVGVXK%;{-mAHUMdevQEWm!rt}@#hlyg~akj zu#Wb52kU$$P9RSF@dK6-&GfuqECz%%%7Zl1r%%|Z?=I%ZD$V*$a^_<_-)k z)kQ*3NDf^m^di2?;h#QlV4YWzW9Zn-+u$+344_Hcx}>poS$j_wl_q9ctg!)yg(q8a zFd930_oxT{DzlXdFf@L{yAj6(5m%tK#&vK7t8ByhErVsFV3#23*HW3X)#Hb`{tO8} z7u$2*#0#c{<(&hRb}!Gf*YQL<^uwKjXutwk!V)ZqJR_iTOCHFFk zIY`)#f>p6^F~lYK0e!&`+aA8Gs3JE2V(Ym+FLUr6a)P^}k~yKJ2`LUsD7&D55g#P? z=9?NgS{it(RyrD8xo>KZdhv5AIof)futpBh>{dAd$AS^o`uoeGUhqPRUtXlWz-$%1 z88y)Gs6SaxxoQla#8FB*zf!rr%&XyU`y&Ymj*~YYOwLor2o!?$z(wkO@{Vk1{ zknlu{q4TA07u#K>V?4*|GP|dAzd2nt1zr*7u&bmu>Ap%-PCbvF5ZNn{A ziscs{a-;gki!6X^1tZDzTr~n4+%U&d*Z-TQR0dvgHlJH+l~{feOAACsp?99Pip1E` z`H>$m%QCkl_0C51>RpV5aVsqSP{{j=zFInR)z{BjWZirdA1Ee6tfy?{#}jvMg%%Wx zjiN>*^IzMX_HPvflOgyPZH}ByR4+rr$RQYDaJ%o(|A?PIH;V$_>F=_E?>D6ELQp1> z$;%%!z0tlg4gGOD_08WTbuQKJYGGo6Q4uk z1}o96{-P5nB5}1&R27mGJQGP@SV{LGsUNlrhvuit7I}T&MeJHgC7?dBpayBgQ;_r* zE2)ozm>D}+LqBh2b+NJ4K7~<4Hu(CYh^MLS7vxwi#>wZ- z$5!#fM}h_LU{0mqEdgvf1U(DQ7NOPiF$Q>%k~r6Y&ug+svDUV87%8~D{h-XGK~3nW z8?KZ!iNDZ*^;y3Burh@e- zqU^JRRq>^w_iFvixYtP}fIHT#{lVgRdOyhFF@}1?&LZX#gx~f6Ha%b!g;3mAGjO z(eypd4&VHM8!litvI0flmu+Hgp3q{qx9F0xHxNM1RofpT4db)b2K|ty*6;z{{RMv) zmxvD(h}@ow-ZsJ$K%pm+laDz4pn~=B_OJ^uN}i&w`N4~1)4aLP{I*tEbY@Iit){1! zZD3BGxekypV|D6})ftG<-=0gfvZa1Kexf!$WvijqQ=Ym4Pn6IBni4G)(Fs2F;7bf4 z;qtMb%)wnF_Qg=@BqX3W+9QEO70g2LEJn;urwn7x4KYcWr&w&9Tn?u7pI~Y{F3|f* zkGoCx$7z2$dA;x(+4=st^yO9MactkmMzRHg=$LN7_LRpLBjO}q4sLp}JAW>zM$D9l zN?!+UP>N{a_&n_v;`ShQ=uhN4FUR7(Pm-IUb^a6vUlp3?cP~OIxSu)rhCk|U%f1Rg z-YW{vqhFeZbE`O64j@+PbE*tp6o7s5MaxkiP6XGfC@Z7jG9AbPvlf?)aJ&oEx^eqO zdfs`l;ds^4?FaDGM83(7Qhk3KrTRbsw?j<)u?h|IMJ^xhGaum+bOT4fY^-pJzdV>- zLMq{wW>&sRQ_y1cTD`K1harTUk^4pmC5jPvLWemRxu)^L9?b2O)BQa;YT-H%r2C^K zc@pV{SylJQ_-RxXV|*)(lx2G&ZQzY#k;@2A2OVg8aY21ZxxqZ6Ivqt+c45&t4J3o! zy*z-8AvRzhz$C=OsZ)KaxyHFq#Z$k~UDm}HDa9_^gR*!6;jUGmKoB5x=Ta@)o4noo z<(CvS=ygfJQHw=8N+Rck-Ag^IccGZH;K!cO59xl)M&wo@jN66SZw6v?9Ipi2lx@(% z$Ui@QWiQUPjK{tofAlK7$S#-WEmAiiE@L5eb}MO%YfsaALE^OM)j3AjxZJn0m4gzUGA8I-HYq+_;b~w*& z&mB3Z#kxod^ee~?VNC2NdJT4b(p!Xe8Y8>`X}G(TW-t)RUm;eCtCr~AJX{dFKr{|w zE^0SD-R0swcwvh=MC&0O8FM!MYw_A~_uw8i@@=l=;gW$zdjukX&aVO6xf+{C=)n@- zvZh04&E-6GA=fYm%Pl>Nz(J}NuC}YOMKMop2Jgx3vyNlq2BA6d2GEJxHwZ+=IKqil z@zE%PCD_8r;uwO@C(IS{TBb;X2<1WWK@^Jbn_((_r)-ohuXkU@w(tvL2rGg zGzh^e)SP5UZGN%OdixjaqpKDvgFs3KTj(;5N3`_e59u#vxwLUf>Q;&ZDN$`j+l{J& zurbU>{l(3Cw;a8DI>+}7C>U4pT6+_4n}yS}MkRMkmPT&LF4*Pe!Z<8XZ!f}79`g&2 zxhr6^W-Km-c>!lIF~0fVy7w?&#giv= z)#Kd7*z(eqa!&nNY}>2eM)gI=DcfnT=(fbf>ik4hN}7jh)ujIj8ykp>MBl-m@Zj#G zEF*;Q6Wky8`BX!1w7d}_hae0G5U8gS&V+s8OpO|PHLlaZ0?{Hjl=Nh@rxpG5b~|X+ znu~A@0KQ%A?hN-*U+wm^NX7+lozjfT1<(LA$jg(MkPDyJ+*NA+;5Yx{HGej-a31&j zF#@4yAS*Kd^!=lln(!HI5oTKGcE`Ql4x?j@@cK5K+}Pe3T7mIrwZeTKTTo3VGN-$P zA9KKqFYzD*ltDKyn$fPP&Uic*&58~vW0Rl^+z)%MY7GWSMSDMqGex} zqItP=HZf@IE{$~k$rm}NLDp(~tGBn?XJ(7vjk_c16oj{d7(8F;_S=IW#K{X@wmkl^ zKkLj|?W@D6rMZ^|q8TT8B8BEr)}K~ZP*6{Kgk-q)whryVQL5FuvC$?ixV9P`bb+>p zue-r=7qZDki^kpPiS+BVdQWIadf8RJ+Rf>Hcdb8CP-=GZr^`I^XIwS!GkeMsqc8>c zY)jLzyyR(@(Mh5kiTDr#w>5~FUJXyL)a;6);IsS8bLwI*Q#GP}FaJuG(n*TSej2kL z(aHLMdQ#i)94)2`->u>>c`L7`Lry|6lZB@7Vv>`ml$M|NZE z4s3{Su_|?s2t)A8)cRIh$um8ne)*UHqGqGA4cNs(=!V2PS>n}<_~$gL5q=02r=nGaflI~K5wk_zXPvfS3 z2gcd&Vy(wB92AJ$Iofe=8La4(h~_x!<+w_n6MDV)JOWAzZp#hT-NA51YH-ueL+B$; z91A50LlhV9uC3GSibmCD;Oo#sw8LL;xhU3?K3mNFcze_Y+0e>MnRsE40QsYcltnw- zeVPDH2cWvafnw~jx+nhA^en$q=+Orc66tyE=dBH&_&?kNql5^Eu6Jb4bGiPx3 zjmAO-c6?ZSvaWfJdj>oEP$L|PIXDu*N%q{y8QAR)!JSK`P=BvVclj5WNR&@Kg%``8 zXJbA9nY4RZstt-V*Tvoinz|c6+5pf+Q8(dLib5$8wN!qj#OI;P&5ImMs)izwW&U_u z+%g{{fsOBxK~_&e*ln_iJ!4LbV}+>KmcN$bfjXosXWa{Zp+}3s=Nm=`BDdvY-%)5m zp}j>y7D;^30kB)JqE>(^TP+jeHLA{o<)EvRRRYIOPBdiXC(Sx0(H-`{l4e9RI(do~ z8IPX=1W)wxqh{^OSi2=~He+e}Cqw^a>7VR&OB{#1>q8fX4y8SG8*C5`9g8E*1C5R& ze!uQhiIQB5Nt^f_u^2#7hPuTI^-w3jGSu-}h&*G`6oI5)T#A0m_C)V*^rEp{_2eiU z_wkL@KH)CRJT8)vBK#Wa*M1?(AP4XtJ;a^=8y+GiEGz@8?OLd}!ey&&Ft)Mr=vAZI zhnUqEPQg02=&yI%X?|_4#I`HUyfC71>V;s2O=0B-F`C2kbK%QM+;mia&l0ntM6T*& zbTAJS!LGPA9FG{KevS`M_|rU%j{fvV`YlkejM9^`&6(&p%t8l7b1v<+(_6F?d+A{` z(VdAgDrrEK3EJY&4ouMQ1q>!=Z;`3F@wt%cne&}7M=Q|yN(?-ea5+%(O6A3*?AHlK zAq2yiTmp8rCLGt?p72plwP$JZ>ry1+U64b^T7HuxBg82>9F?xdxDVi&bcJKRE5ld& zLmDmFLGZ=)bQgd(*aYBA{(ihQ-dGaJfal=_@?>llprhLr2O&VFSP9Q(V2Ud`8iAq$ zGaA_wL|&pDXdm`4yHZH<_z>4I8fObWs&`;IWzHJqqh@OWqZbhh)k7<1HzY zSHs3Pkvy4^i{x>IPvQapv)p|S(57;CPOEaar$xETbK>7E+B1Z+5YqXdr(6G<@>icK zf1aWmEk;I(!6Yat5Z*HH*t{yJ0sRxt=6@<)Rj`yQslX|EHM2$+595FW_o z93$5YQYzcQ6{eLK`#XwIS8;;*6plEA!@i46YRm8K8IlNZ(hMoj zW8xM`0Jo2wkJ(WY4d*nW;RtAr(aE+ohXFb#+?Fi*j@-vyr3)Xh2$sV|UxAC*QoFbY z1vUB_e!_?6+8U4loxF{ngYA?Q)ZMBU0t(?Z!VGOEoO))xuCsy;^{P>e%4`SOel@j}F-Ipc%YcMq&1V^hp*Arb95$#k*r}jgY^^n+g!ld50W7NScf2^rB10 z9gn3}O!zYnVm|}-e&Em9e*jmu=+VM)?E!+F_c?HbGp4|Yb@F|{zYOT1gT2RgN4z}! z`rJ@WmdWxirZ3z*_SSRB_wmRziO~UYUoXepiy&niQudpmyi2$e%%d47gaw^*kdFQz zQI7ADf!SCU4>=dZuw5t%%ki-Rtfv|MdcFM{y4V48882-75*rB7d7NNzjz5fj3P)(* zT+VpV*VMehs?XD?EmDf5_NBq|DPODnMa##w$3Ch2E2BC1s!Yz)KspOZkXS!PVU=cK z1d4uoXeFkDEOh@I$yblR2tADU-Gx`IT~fw_Na00&IY^F4@=hdU;(yP{X|8H4@QEhu zHuQ=jnz%__(@{1kb!@h%&&>TDtO#m+YfAs=_BXQqrRD-M_Di(9Cyd@mP9w0IhtU@M zxbRJ*$}t#OupQ$v>Itqh$nsxuL-yGF{gJj}CAN|#9QQ`kpMhsR#c%TRB@F9Jk--hU zSgTg|P07SFSJd(4Lrz3-=(q^Qal+p(;3dh{pt6H$<9Y?68RPts%dqLdw=!mgFC+b_X75B}a&M%n%0FRRh;PmG zzYbP=@gSMl*{gPby^~1W8JP(}s8XlxdESHR`Rv-M9TF#ny5Xae4*Xz;dcz!S8G?X~o~0B0TY#U+bOw=a!KtM&&pl z#2$oYo5JW^t}8gwA9^gy73}DbVDT0yD*q|&fDU5WzOQFCT=?Tr9KN0K6L8e5hjn8I z4{hF9bDh=PCT+xk*#@`>wx5I_3^XQZF>-dSnLL%6*7vlm&jy5k#Ge1m!;ck1Td+|P z13}Y}X0I9~N3ceM}8y<@7hr#v(;~9c6k`K7$9BTwU^_QED6v5@i z6`i^EC7C=ARh|@LQHRmfWKmD-A*TV#Qg;=A?GO>z6JzFjNGI>`8#cuGMmCn_g~Z5I zxp`hESHLAHAc%u%kDur=4gQ>Xr zCv!YDG)m3#!Gq@qz-NNOa-Phl4pw(u3z1}_$=Q*hM%d@@Q8=p}JP*k*6-(R6F1B*4 zZY43!l26$s9eJ#`I#G%oKhn2&V6iT6pw(pqd-Gk@JxPyw{Ae{>9_Cgsal@X-948{;<7YF)b zYU-Eb`|)(%3wZQ{-y&{&;C&*l>KyzhGi!hJUJf$%!W7>>L`*T}hM4$Kt+V{lHW1^(V0Dri)fD`#}`eYY>l#!l{3R-PHM4(UxxLMNg z8`TsO+=zBKA4SWjM{tH^lNzrJuFM3H3?UWzF9F4Wd_$h~NVX36{L&IiL#%re-jYTs zJ(T^{7j2KB3`>$2$^7P5MtBCMlSyFo;W3!Kgm$V~xO7Wk)%{n|!do^pg=dsi45&J? ziM|+?qUyyOANxbqT+PDZd%~?!SnpzsbPi^04>_choB{0zj8A&J6gp%?^UTXamGSrH z<>5zV*gX^Cv^d&f=ZCsKMtWvx=Z3w)9UV8pdN4N43+O44aCMZ}Twkw)Xmgu~O5-=7 z9Vp@r6p@OJ`$R2l&ijbnTisNuO<|$B#(I(xbz$S6x_xg!IaqVze!t*!P3`qGcAN^O zYihj~wWCw(Tddy2fl^ZYFEBt;TXe*DoU3G({j7Mb@i=|YimwO@5r@a+Ra|ylS*O@G z>5gJo#U;p=`vSR-wP?dbyFt-`4?xi$U3v%NK0xX%gT3(KN1TP(s4lu16On>2gi#ME>w6YkGYyB{z~7!| zFSNu6PZKK88uYL+>1(pjJRIwSZqsr^ql1pZ7lFpK!zU{-2=g+=EY;7V5ceMj@0Di1 zHP~);@Fr}QD=YUE#nIRzG?s=xRD-fnYp}1h7?sCHBgLiKbzAP+vlgQ7iGCklEvzk=xa6YSU@ zX`Q3}m*0weeYa3P*?-u{`%gf?ug5t!ge=POT_@ph!@9)Uk<^CI;O$mjtlBz*aP`gu zno7}kT?bb{)l{U*D;A%xBw)w_9GM{I2byVoZxoSo2w5FDjYgbA=<6)#(Fy2(16uV* zy08cR-0pqH?^GpBpThEN&+(slq25LYjZ8l8%^7!-_muPC$RCrMKe+-lV7beZFRmwI zFNd@Kg?DU&OwKP%!H*8YZ3IdEi}U9dg~yd)cMi+N=vL##d$8eW6ye2qDYt23XwoOm z&nznzS1MOvVQKT^K@XGmt!}a|m$)!ik1OU8#11$lWveQPg)uW5b53)9cvacev8Pao zRliZaGjya~Fc3PD7aSBVsmI2rahGw+9KLC`E$Ej|hSDS5=EeyroFZsY-{FbVSAK)> zL|j>4T5;&OvRU%A#p8m-aD)00{Vb$Hj6CfY#Mf|Mg`K@X_VwDQo=C&Fgc%M$&5fWl zj*b7I6#c~-6y}l;Ous(VZB(8{;~MSX7GihrNr zH~kOcCg#=ePeHpm>E${m{0+5T8=bmW&yh6f_=vgWu+c?|7_+5LIkH}P%KPbfc# zv0s1GGX6B?Tl3vsV`g`9{~k}&o8QncW86+p#eegH+fcQ7$LG|$aqKf#@9VV@$=sl) zo+e3Rr56OR5>wTvnFXy1_Q(2d*=4X(-C(D1cvdKi?MI6(`=^^#npC_IIuE>!U5fwI z!h5g=iTNii&Q>aGXO?W%#^3WrulM;P<9f!%R%UX%*YkZjuZ!<1(#1l&<7Z6$A<#at zzHqvDi6Ff;bsCUh-F+r@#)WZp5Vyo*U%Nc)GQzmZ5Dfb?zXGr>+!H40nDOtyE9NTt zi+^XM47~8n<^vU(G75!HAYz1Z6-;$z!{q|RK2>}Uk5ZK1#(^_et?CXK#7=-WIm{x& z9SEQZ46v0qvV>^n1Z?4_16r`^Zr2cerDL$?hEj7gyy)pDld~gu-Z7R}sBXjD7jo4b zqYmZEmt?8M4#A<9=^3U|=PZW@7wMOe+XDi9Sq|vIDX+n2;2D@H3$C`EU`xpP2)Ybw z(k}^;=0Hy&UpR2zV_>K>FCB@oJ&FE}W`2mB_G}B9A&uFL#(?_d#=zl|wmgSxc-fW~ z+5s7yj!-PWGIupfr%du4M@C{k>wT8IFN}Gt_bjpVdMJur!bG9))^22R-@D(GRqYHg zR6Tl^y%s(PVAMRl$uFG}c?xs6nw3HI+z^L=xC&P!v?E zwbD{4-YUwj#Ns8miLl+S(vMpGwzgtztF8B{fH&?C)T(&DRZ*;PmKE?)5pU%Ce9d{k zHw)VDqo2p)_s=g6W#5VZGC5F8GtJ= z-W{&z+Nc5kNs^WVo+r3I`%{F?t~QQE+Nh3oOXIJ6oX<-(L6AUZ))WKu>4wW*x8wVQ zfEX`#GK#lr65R{-QNhuiCO22{Gn-8Fi+z6jSHk?^nS0xWx49&P%U26u#F14bIG_S% z-sEoGEPx4xOztANI;D|8Te94WjEZN^FA3~?o7^>eW2yj&FS0e!JG9*YI56roD2G*- zTk|teMZ{#F5)|@kBFn(t^4;5$$t zNXA*mz0677^4iNQJ1>k-`cucYq?gCjFS4s6>boC(u5+l?xzqSX8uX`ei4<&t$gH>H zu}0^fzSXQMBnB|2h;XgTzi|7@a*y6BhBPr}J1H z-#2J(cYZPFL;fNm;^nl2#)5l2?FSW=!86d$Yc(0N8^7Hj?|LrB(5=bGY zIFAnqtO~IGnfoR84QZ=uo4@w7rF{71%B&*ge}VgtmYBQ$eA73_^9ei_Sr-djm<(O)s7840l5m z>AtYsP}&05mj?Y|b8D-c*I+oYV^Rb8DSk+h3I%NENd6kf3tEJ|g0FMeo2&`+JMyFy zfnjuVKb6vHg*eZY8-vcoo7Z?xv3G6s)#ks^Y2&BS{`|R@o74Y*na0b+bFI{l%JU`cP(9AMITEcNKBo{8wDWAk0( z&oB<$e%-$5@U09l7U}C-27Vz*joqSPXr-)oE4d65({=8I&k%iw!Gr<* z(ppSVDn9Uyc=oIkx2L|#*4#kd`u11)Hr(F0Zg{|d%afh{D|bQoUWGSp*6_DB$5}PK zZakN+u}NEz7;U-*tmvNno$yO=?|w3>VoAl?7Ft#@#|o*O$F#C%1e#FkQ~wSIcd>@x zr8^!&HP7D`NC|iGPr_j77rObM#I*73G$v+I4+l8`99ej%R;lHRk)w-dtbN1G_J?`f>UIO=E+rg5?oL z(fOpU>atjK(bwiIe?UT!JPqrs5`^2-_pt|+`d*v(-`B_PVtwwjvwMc?m7qWMZp4qM z1ZmZW4k_1~yP8@(gvINvK>zphd{Sz-jijg;GS>cA{eZK}AlN3xNW_OqHQNaR^1 z;A$qNuBeP84yt}LiIT9PACj-Zzz@d3Kkm^mo5p5tvdH|+OPWBPpy{d_53HfeSPD}_b^;r4qU57QsA zZ(Npkgl6H_(vW&T#)g(8cBH9fL#A{F(Q$HdOIF`mlI*lCW@odU?9w1;u{$ZLsig%K zhA7_5D7K|@$7M<*eAF}1vmtZ1I)dg_UshX{*oR;6QmXTdtBR(zP`_0ylGtuKC;@eT zN$?PETEWEH>3*F+=w;3?%QW?^Z6c*C`bFwpkuY;%SyOfr4r9cMlvXyS-)%gAG(0OC z(@%PT>6XB`8*fD0^tOs{yd_w6muy_zyENO~0eVR{YPA&LMvUdL8`b-kUv<9o9 zxyL=vM1??BB-A&8n2tc`gLw1Zod_J=@fuQ1Du?=bjamlD)nj-Kz=UhO(3qXjl`qSj zg+t&HqLsw$wadj!)M;)zY)6jQs5C`I^sOXxOhT)l^!N zYEr0>#&YI#{wGn2g$UH?fXJ%&HfMVMuUsRceEje@}OL10fz^l~Yk+2=CBN#WoLKf&`7V<0_+52U%$wIoRZ>}dx z>}?!b|8=u>WVPRdBWrmq^(>2X_Vg7c)&o#bRum<+o+z1sIPr7Q73m%&N;O72j5mIHxU+KvL1k=9W|>%lIXdCJZ?TnVupXg3~SvVhZu?ym}EkZSnIOE!zVJQN(HM>2K7t8w??BxaqfAL_>HPg z55AgNT-9;@A#Sliq`H7cmahW_~CCWvk&bclwDw z5gDlvnZC3F(IWX#iAQ%P?@X+*u2|j7ocmhpolU7NSofr-q`v&O&tuW?X8N_*EL##u zU)By>g?op@6EFxozqgWKH#^V+dFcFQU%w6^`X(6%pJ)jq>u+y!A*L`LSko-%Q$Xe5s#fJ`fwqzK3Gv@^0 zp4byp|A^F<;q|c_SERNa61#D6efzVC<5OGCOf+eEo!{5&>gb!kP-j@^xx|4gR1sUy z8~-bE*3~Q`L6kWlNz*uQeb`>WUo2VIx^Xd~CcX5s>ip?eFJs(o>W3qfxXiFcLJ`ip z5wNOz4HlJ~ z+-QKyZKMrP-dASJ**y0uLnfe0c>c#SdsNRBdhQ1lFRV{(P~?;;AgDK6Q~w)SN!7f= z*aaJd?cNuBhDY1jtE}KWo(AoO1JiR60}?ih9;mz@$zhwJZfTP9Wx zaFg2~2!+uE@`(Z?DB#gj%ayJDQPY?DMd}c67&Ms<~h zB^{}hPcozpHe*m%*Q(T(cVq3Htac`vJ-VjWSI5A1oGEhBkwPG*w=J~xkOWvSat ziH6j&l1Yt2>1j^P#!xT+yGkKHVyXa-?S-smc51Vql72Lr@2saYNfViYqEYT`$} zcCA8g&E;4%j436_+fysOt#?xcaJXIQasIkM?n$T*HbIZ(<1YPaFI$joM;^(iLOXu{ zFlY-5s;yW%NkAzBwsJaTe9~-!s+re_2M@6SxHbTp{jkiukRTA0^RYl?d}srT!m6wK zhsey`%h!Hhif(SG=z*~#8f*Wx@Ia5&r-a_`v(+2M_kZIfRTiZ( z709h+#xN#`wf~duiX~=mN9G1NluU#h-BCcJkDun7=F}Bckwm{{a7wIgrJKw~qzZ<_ zg>l?bfMeWq$vvVzWXL6GgZi7$=b6Bvn7F#kJ^BcMm zl6Nz~Xpj>!!5C&~x_utezv2b;+7jNUSLK=vVf{{;&nX^qpm0r03uZjceV4CHSm(;P z+C1WNj+)Ylmoza$zVDB~SrkX~+cGin3zHA6m67Bw`4-{dq(KwXU@Ezonj{Hc!sN9o zHt#e;!8=$dCvl#~r1WX~C$YKWuVj6TbyNUO;p0m%d)jW#rb!Lyrv2RlCBn>3iRP}L z6pO4K)kU!Yy#v*`_n@jO8+jf(Hpf%OFyoF^KRd1jyq*E$Rn_5Aj>Dl za_$3ux0{ckkU0)Vl0)L@2Tfk3ua~H@Re|QB*;+!tiWu{bqf$udf3L6F5WJ?EfwgyBkDOcRN=-h`q1JUr#B`I&=Lw}GvIWFC=yBnwmk7YE1 zpk-*Ub>IIHt4lPwzGy)3(nfcn9(X^D0KaeMHwE?iwH9gU|LyiUu$yW%qM9JiRTXHq zUop+zRZjw%73c%q&ebpqp3feex-!}$t`y@RqE}{5LkDQBi)Sw_b4Q4sg`b}6_SjC3 z@n1$hrLA@D!LWBluQmUnzm6SC@P;Z))W$PCsUuPLD3x`67+YM%IP7@g${oPqnYlUp zt2eFDNbSG%W`SkM$_qn8&x8w>sOOB)U@m$Qr2ah|V({TiEf*-l;UuJM)NjsT+D=x`v! z^0RZQzX-p%{I>VvznyYx_0Zb?#`;DZ$>}ZHMCKra70m%8tYY`~D8f+%Py2j%(5|#! zE#4ctUee+pBF;my;s}qoq!rqlp0z#8dUqLbOl}nW-MH&VG3po!oIW}vl6*ST z8qN1w_+8O5JD`tHovnGf16QHfiHTd+i1*u_2EXh#-wy933_wWw-@^N%75_GPmG|?T z@V+d~7I|$qDs!ozpRafZXU&JV5g8KjQa*{|K*goPHDD zBmW=p{tQ6DZ?ZkW@5~Y1_#Jm@^$VUEzFeSvT3{t!i==s6cKS4z0=@AEwvHV_HG5!b zwbQ`XxgQyjt%o4S8D?t;%DtO%h)f$^X447emLCV}8PDX09Uo50Z_F-UA8KHgGaDWY z6F0b_s4sgwMeGE) z1}=D1ap|O{^cGx&s-Mh9Jzu34F@^pxcHLdfNnD+IMI-+nlQ@=thbM;c?;(jJ+CKkY ztX-0=?eqF%Z=OwOTa^h|hvx#(BHj?a*DmI-BP-zIX@A886z!2XfhG@0HnFZ6SyFd+ zq7<{+kkn5rqhDM0eCxzGnr)f*wKT60ZFR@8m{n~jWfRA;2{{)iy1p0dIGm9bM3#P) zGNpzEZ=_*?Og?T&1Bow%4=rDiIBa=-_|1J@fTj=UsGG%kj5U?C_o$Yw?ic&|EF}B!kpcsT@!Qb$bxG`MWF?D|E)Rc4J$H>eydP_q z9ylU4xAEAnl>1&?N$i?heUbXAB-Z}4fzLmY*tI$gqy^Ct7(Tn)#e0*udmvPTyH>dO zur&+05=*(y;4?4J=+BQxdComoSK>FyRqh)83Hy`Tl`{?rbN$F4ZGbSXeZK?;Y7Es# zRvAxQO16S|{&oAlgXuHdYw)OgoJ@MgI)1Kd7tkOOtaiVC0o&v4JR<6RC!Vf>3Mh~Ahd0o+p2M!eo7)lQDfO&lSk5#A`eQf zAs}-Quf&&{_tOU1U|!2YnKRukc$+>V-fwuG-_){-Zr@n1m%$ph z&5&!)dNRaIF@Fp-zRT4NN216+8P0Fs0v1eieO+>>*0#2aOO~-6*0*GjCnr@uIb(4N z#%&8oSiK-Zg>Ek)A7-|huMuX)|Du_!CblhN{>?hbshpyz&vz`yDSxC(?7F#t)bZqe z@oi%)?&Lm#4lDO0r)?r+@0B*`N&)(~)gD~PCJ_ej5Z^Wnv;QWu!J-Fb*KIw4i1bQa zO*2hVqL7n^VdEayQ2SPb1y&M9Tlc5|K5-9eo15I1pJI-Eq%hyJf05{g8&Gm!bNX8w1Z5y{)(sc(eqwJ4R+8;W^=9BcDeQ00G zO+iyPTh2EXD&oz8bj2#I-iCTivvScTAFzd6bGmT6J=`hcyX_Sy)4Eqo0ajiQ5X|5~J=b zN(v>TMC$#ezAKwxdXsOH40d#g^-%7oHXIpl*_v?%w}<*LpjHVZ5}2rMoJ~u}_6jibF4K|Wvv#zBMQ5XGUqucjV z!^9QDT*TUc$s2ifvp_ck=92IG+3G2tQ-fTl$xlj7L0rkr?(z>+#mbOfRMu#?skhO- z!k+zadnGFs=>4n8DfUbBv0HGTM#vdIXdQz;Y+_Skq(6cGH2C+} zzwekpv9OdXMuXgi)K|nmk|%|Dc9SPi{}Uo*n{378b#lo~x_~&khis7mS#utQLTC_i zJAwa6b^Q_N2rCFS&9))u8G&cWUSTZAR@iS&-d05`KJVs(vWAm!Aa$1*6YD_7V*VBZ zSd!wI!t$=ZOy{H3xXTN3zxzjR&_!{X)<=|Y$(~l%l0C8P80TyMNP|Z|Qz8&Kb7vmR*iP@NV3!V2t^_7GFlGYzcL%6R^t6AM1FAY?HXt2x0_edf=M#Cj(Cyt$acQ8)s z8&z8qM#%w^3|d^ZmbsgLt!kN;2jbxsOcA(q6%CZ*9?;XD_l`7$m7hK_ zprwg%C9&MbK41-fDyi%ivvC5F2!C*MxooIime@myGr#JAMe59KW2CES9?)a_!?Q_N z($h%`8qza1w|}45+`hesJeBM(do4D){>k-c4qoKH#qV>;nFCkqCg3OLV4XxGT;(nr zKxzT|E99&3`a_Vvf@4y_3QCiREjNIUCksQpTUTQ6muv9H+CSr8Ls`J-8{O}>gfrsz zS)^YSX%K-xq~Uy&5x#^S-u^DI0CbRRMKXqFn^-i z3qukAIIGLr5f9aZP{IoBhHYI`Sj!BhGI!L88d^$3x?a#2cE_v;@QlsU_0&zaU*e!$ zD2ML*PEu>!0S$ObF*e@fu9-!0tZ^lFM(k3YCC7kfc48E7L65iLX7r1?@ynH)=U<5< z8$=xR`I&}*nkmz|vk-9WY@=k88_qc& zzAMSms3xiHa((*w3@}Y8Y8Nty?H*TI*NhT{UJnP1^E{wAXpB+uBh8)jWC}Oh=dat2 z|6%xV*aNpPCo=Z?87NYPZ@M$IS$(VhaOL*pr*)SH*PmVp$`O5T&SG`s@F@@>`|`^_Tq@<-Ots<6<%NK0M_%{cg{vvGzZTDUjt) zpRFRDi(5yEqJwRH%R*QdoWx@) zI#~350405^D?{6WGZy=UzF2rAYt@WDbCJf9*H4;_#V3iWm?l8|JUHDnUzSaME8YEv zv%}W6GWGe_ikF0c^zdnx*aBoJzq|y|t!JK%`~tZ)|dKV zavGNuz~pqbaU9ioPSW|z?5EkDK-68g69v%=zAMF!9^ASgmZwGHZI*(5{P@-T2i@~$ zxL@|QYlz9vhJ|`hmS2zzYs>=LzyfsR($8?$)S$OxrCl_S0oZQsyhOq9q75_j${#nR zzaqW{sLal3Cwy&eL~i|$2d;JRM3kV^_`s#f_t*t%8K?je;1feI{@ipb&mb&zN-UGa zSg5x_X33xsORs+v;Kxlv4y#|GZhk5-5(k8Gf+Ml4-St!mQd$S#?-R6JbRMMJsnFg( z)Lv)zS&#<5%l9D#exw2tDS|&Te+{(#Py0O;lFz@)SlT@HFE_cJza+Cknl%c`p>?i) zq)oaNhPi-0itI~R0Ze~sMjl|ea@D5>X%Wbk^0inbd)OZsBHFPsi_(vIpCJ?IqSP0C zrcHwdC$@A%;w8B*9I`MeUs)1KjGELiqxFJFed5^W%#`uk!K%@A`OF9H)Uq3voy$>U9Cij$NRA#p%+?OU;#to6I{tXFGxV7!F!)%P6Q zy-F(g^a_(n2Kq#1OjWg{O$!Vkb@%*Lkk}$1`CDMDl3Ae3O}ae<@K*s`5dCiHC*J|D8gfX*^e>*t5*iL>^Cazbi2^)UIEoJi< zE{bbDh0Y49l-m1`zV?_6W@STDVDv_JvoE^0x`k|N(b-?9*Z3aug$#Q$Z=-PpWH~tK z>pt%zp-ruBQ*c$~-sj3hMrzrF5RDA~`bcVc5BAqC?FjeRQpfgT_tvI3Y)G%TmUdJr zZF6--G=XaL;8T(RETpIHXC5t1=!dM$opoD}h##lQe8__q9u(UHJb%6-HKobNx61xG zOVd`iSL@(<*js9~3|I(vur+~J4eyh~iz(qnt6ikqEhAdIv)%97S#h7!PVe3ND>Vzn zI*uU4U>vK>hblnuHRW}wKMk$hf1#BS2Mcw^+E2oE+0;RPh(GycYqPG|fkK(b?F0A7 zyHXcwo;eWC^%WXdkA~&P(T8mlad?til_Z4O~Y=lI)3Ft1K3r(dsI7Jfqa<2_KeC# zdm^#2z4kb~o^1h-Ee?r_;`doWVM&saC<~hOWd3!3<+C6fdYv0&Z+y>Nz`*@{;nuCj z3O96EBGly2d@{+@S>*Y_yKaq68C-OBe{f4VmJ39jo(W;Iss8_+}V z6=1q4wP+7WtNPNb_?RMPiD>Fq_JoD@fF&5}mD18?rUR#yBIDP9y~NHCyS*J$#AZDQ zGBl7T2)}>FVjkdko}OpA`Q}a<(O+=~wgDF0Gw@(WRz~`r9A`C1C|*Sz5Zm-+w%22a z)q{A?RPk)P&+w5ZE*QN<1bj_@(9e<+_)&I1gN0SP8(MW8vV`sberljy}}7S0Kk(+6qlv0+_d z<-^=B68n(RKpKe|CMfhJn>`weynNj7=W^y4)=i9oqt!^z;t!AQ=6luF&Yb$M?4uf0+*<% zKZab$oV?}59DD464+k!fg-{0He;kjfLMs|8PtkjgLb>d@4<0VS%fcIY(E>u21zmF} zCwSt`Y3Igp>R!MD{>VwFrFTI}rNM4r4$BM*{L92tIQD{yvID-}%x3TSD`d^KA*!=9 zgd^V$h6>D80&+}=`y*@IpwvxP>L}g@d8kJ6u2^1PgF|~^h+Y=l2z~DEV}kMe3)O*r zZV1wvy>-U3SRlR!rh_FI(#IhH_-C-&b5oB9<}s!p1hkj)epK3!Q+QVg{k%>Pp>IZ+ZV#atM)hz@ z#^UF?-uK-Wq1E1V7{-_$TF+=my^q=PQ;2VjUcE^2w&aoTsJ`?j_@{_FG}*tCTC~5( zUc|as!6tfL)cd`3*Kv<&QIlp1@Rbi}STV)8twYp76eaiX;HuTF53VM-IrsEHGugrh zg!Ic$?QJ+)>s~)f*>3_p0^jWl?D^XY_n{`|p5{4Ndi|#?(z9cBqJ8ARHBT5gxr1Pz zV0}nEVtx0tnrEs!03dTGA_;=`*#Uo@s48lHMokNMr6@L)K*4k?_QA*`hZJky>KQSr zh=ne-J_Yl^xj_f3+(I&%<7*BbL83;4R74?Wh)&_#1sph-2Pp6kkeOeN57#s~8a zm(A%dj||Wk>2;~CC1SDCN~msW3iO*K6pU0^*;W=8YvZYPTbk3bj+b4{>9#o(X&$%* znhadgFk_KO(6HF`#0lz?_@Ch*HRA0hSPBRFE}d{1T|!7jTyMJKEg>&$XRp?J$J=B{ z4yCPmw!t;>Ni?pdARi<0zhTVd$>i|W6kWvH-$SF#^k6GL)-el>TcT$XFM>W}@w>dT z0#GxzRBGRQ^U|KN_6bqSk^XLo`X6hzZEkMs{q5Cy3j)S-%gpHW;7j&R;DH5;`3RT4 z^D#>h$Q)lqW(&+|_(%!na$XqlWx9|>k%v^OYBf0b`m4nTEmuDy<4cI;tUpLM&iXR2@b`imLT&!wgQGTKP%>d!^y5~W z+r)E2<*|C2awW~R%VIODi;Bou{B@N=S~d*iH>;!6nde#N?{buv)&i1)kllpL#dTU)uHTqU)Q3YnkLIHmB&-okiE* zhA1}%^-nVc-F{iBEG*c@H(Fn;bq}(-2woB`0pant;H3%)7Po8n$2SKb3of$+>HDeO z-?s+e>%G1g%+FLLL+BoTWi(3f!#HIFDR+56{dAxZit)FU1M*`i7l^W z5+#Fato?D*=}b}cYhKvCC3ClRMRT=iqLp1#BS`S+rc5{16gTDW$47X2&JpEH3}x*G`TJPM!{Eow(Ni9YS=@`&y&{|2 zE0=MNh}tOtY{>Qi&F8)T^t>F|A*J*%k$^>B_WDe&+7iWYnfRzw#8!4%mM~SC?gY5o4V5MWL2Aj5U0( zTQYz0vwjE4icq2MxmLSDs7q%P9Fl_d>Tz)o=2*WxCc@r`i{jg(?0Md9o!hhoWhMsv}f6{M`*WGLS+jxQW3{%lJy)vh)Xl?N-rHBhlUu* zh%wmcj$qd>=XcQjRUS*Y3RE1l$Ee%;Hot6TfW3_*P+Zf8Uxh79TXz?6c)RJRDgh(!H z^5@nh=^kyV^=-If?h2~^yMch5a`SiYDca@+Sbc$h0q05apisn;GQ~P(%We_s8?2gl zIz#htyQw3wjv2f~59fJl@VuUHbLZLPdY;$ZHeQO~nowz6U`pdHyY|Gu%zJps*yzls zMW8@VZQO^AtTWUu-Kz>xLaasq2$?)@ zb*tjphfGceYwktV2d4Eg|LIbKQ|kFt>#r{ct=LX>Pf5wAej#C_+11bHV8% z#*zYZ89ZHX_;-ZdHfpo3s}=2@&L69cW6CgFd>O>Q@<2oFltHr`#mI-H2o4={D-KEozJzPy6|FK4anfcIE4 zu)V5iB@3cq9bJ?mcq=NO9F*Cidki1|YgR_Y$ZAg{JK!(&@!Rf>y`+Dpm$zQ5rlW4! z-llhw&NXp12VnITAG5XAQu|5bBr75N_fJ%aoh?w_$uL1aU<`Br-cbGxK?FS$iYk2HQFF^c1ZqRD?r|gH?&(;%L;HI8J8#|3tUF*Yv<8vGLraPe>K%Blp&Rj;CmIv8CvkFi7Zj=Sf zJM5tO4cqSW<)#E{;`tFY@=(n4+#7W49vXEIm~*l~{B1n-WeKwzzW6cU%z?P}^CsVB zZ4tMWpg;DCX-8+YolgzudHCrbe{X=F%a)maA}CeUtTy%z+qmqGTs5O(TYrGV&7q@p zPuoMcjTbz}k7q$rWG`TY&^reN@+`J+RDX_doVE|hUOl%?39EWBCH5#6Z|%_aPQX{W ziEh2gUyJv<28G4rXZv_R+`qQ**Hra9DELPbXIWKzpX%zv6thoPS!CLG;uEzEc7_45 z4j@X0d_vyiuEZ&A!y}2&+5*lVR>xbyP`;{uGo(+_RtEpduSX@o(L%{RQ_K1NGMZdd zyt(iD8~8DpF+lbLPDbqNGwr*yyXIj!4+M*8I(7MwsLod>4A*zC0KYH4s|WQyeWLQ2 z#vxIKMYCV~`BuMWO~?#j`oZGE+hPlU(LWKbeJ<9~$(V3|hkW3ey!aX+=@qu5cVDeH zJGj{Ta%rZBfXnvl6={wwZ0g@kwn2M#eif1+o*t_KawsrNN{{F-x{({CM_EJHZer2p zt(ZTRSnO>#d2uPuiNq0wCnDfe8_qu_QcjDK_}c}3qr7Saya#s*O(svjwTT=}sc1*KJ8Zn_3(lohki(?dL7&(jzWGyR6%>rQ{c zHm|gLQe(RGXwHb}q2RCsMVHq?`ev%{?2$ftL8)43@1a-ESUst)wTT_agj6`43YgD@wHGdbH<5?~kxmCOY$%Nt13{Q!}fu zz?kL!5AD^uL=xLuVzPXC&WBQR4k>F`D8Dy1nF5+km%D4ZvJtdeO3tc1Q6VuMpTxOO z@|$Og{YH=zpDl$U5%*k_DK@n%j*&Vfv00}XAK9iJsdv6i-YBLhHvnSo!{FkU^n1z( z6wROI@kLlqEW3^l0$uVF_(=A$J8r>7YCZ?ab6PmK75-Z7{)mEWtmRg6RqJBy@949y zx5nD%aiMdgaf}Krczkdh#W03kc?*3`?jBTK$9^MK=Wh?>wnssskzrvYh9CDmZqU zlwT*%qvmw)+znKMok{L8TVMtHkek7yg1;OnFOVL(+D$MhNkhYq>UwuIudN_!{=Tks znZGM@zpSuaL^>rl@U@3i#Yef(8V45C;0MF(-V6qDV16FV&<+t1Iu>|kfgnnYF$DNa zwT2UAx9tcID)fbWSPZkv4J&^qmhbBY|I~HVZz%&Dio8R0;ECZq6{{Jd$vj4=XO6#(p@DxdA`7 z*<>HF-=Luva168JjXpa*m{HNVCzhJ5AUVUoB-BxWG$G&e&EIn#yb0!&;E7);l^57KNaeI}CuP!@` zgi9I`#^{IcZ5f8PWpCQewCq)$9v#WQ;pG}>{E%9k+#pQ2_OVg|A{XNmmv|5>uQ_$B z_8eG6HDI)p?IHDfS2{)@QcAJou7Kz^UO{J~z%{SF>^?ur&{(4Z98Ft(ir(-Aqj&#I z&jt(>s%zUyy72|)<^NEuZ)Rs&@fn?3g-@E@X>KR+)S}XO?Uv+6XmnpKW7XkzImcqy0QAEWnWJE$9$F04?pJSe%ZN*-?|BUIWu ztTcI-MmSb%w)Ai`b1M&*z=_RLdBf>w7|30%xsxIom|3{5a7S>jQlC@%=**QUndGww z$_$|Z#oW$886D`XHYx;DT(#7@H8!usW+|}4o(ORF)gHbT(}#>RTuzTd_Q;(<@uKnI z=O4e#_zSf{Q;^?Obia7JumZWH8I$HB-n3-T*IHu}I$||vvrH^oF=8^=-8OZm zWI&TxBnO9^J-~$A_?GO%DU_C#MWxrdY5v90D8Bf^v-+LnAM6t+y){h17zm`nY&Wzk zJZKz^Y@K_&e^0o3lY59?&C&mSeSHv-{-htTFwLQoX$NI?Bi~r^@XW~4_>2_-E1sS= zhoAIJ-Gt{!`GsH6_{;YDVx-wV_8!6y$OxA*FKi6}5qO39pm_fF89Ox!CFNYhTOs0N z?aS39TVA$+YpoPsVzb^-$;|nP;0=l1oYE9YHgJoMQnR#1MvG1E*}Np|%o0Tkx>G)sv&V+SEe)x!i8)@MXr!Sd z=xZ2h^U>Fs&p>JV0FT-kuZ5`nZ8v`0U6jhZg8o7s)vBXZ9bDw@(c4FD{IAd7%F6{! z-u$8+0p4fz{

    aXYn1%Vezv%!8*gj}oA zRe5sn+|h7gX#X-=pxM|5$zSfLwy)2Uar_Rb{`Xk}h&u^gXm<^uP zA+#oiz~c%xt;!Q@As;qpF5>*&4T-<#h+39(7vbbXW)H%0`bjP}lTf9(_JhRClQN0- zLH<#d&1AH7r@kqHlzf+0v3A8qHD`ZbAquzbDhlf`jd)F1OBIhZ-t&){0%v0a{HNE$ZQo6L@g56IZ11a@s@#_kdT~>wO0MOGN^!j$pMA6IAr)M1HsdH(z())%M|0+RvCxt&v1MhE~o)F?-O^ zTkPS~LGetZzQ>L6sMp*Bn83-h^_GbQ{1gOg5o$b*+UE0=q-j;~B`g_h?}&;gj&9B( z;#b#8@GG>g5`J&U%#);{Z&CMW^lmj)WhBC(fV(L=pIMt`V$NEH&8e#f zvqV2YESo*4zIqXiZwmrT>T1)Sr<2^hGADC1%%CNxc?gpi5<3u`7VCI`TGS@5>*22P zu*aK;x|Ym@s%B15sa}LzNWO1Fb`qn3e;=FFvo-JclzQ05)DsFWn0 zN4cJ{UXcYFf+pqMPkB#YSaRUUE^sqfMBP=d+QV4;h5iXt?&;18AD*v=+2m13eO`=+ zy8Cy=kd;kV@SxJ&&W$+CMBG7TB1LT01m+>l;?WeHFQG5W#5y>3we&yjj8!p?5pPI* z!)>O1j7IO?`h-qS8xLN`fSd{9f00GU7E1%-#nHCEOMmpIYtc%7x}IZKT;qGd?VaH* z*Y}6lkU#21|HY3-`Bw}2@wNl)c4MC^AmHyr1=w`lW57(>2vlG=6mD*jce<1ot|sd$ zp8w9I*_gAMhmL}am&Z~Q42!25X-8+z!A7*s?FAX2%WI=SB=<5KJ<`t}EpJw8JY=N| z7lz18nY)LKp+cnmEy33~a>H(+0|u(RI1anr!~Z@_HEeDw#}xJpz?6RUcL>6#9p`aR z)wC4P3~_h=&?;=di=9&;k%oW^&-FEKzlpMHd@YV(i%8$L@5pZ~T}2H!?XNN~7`@!2 z&wBVn)r|4)tWy&9TpImgwlORWR}s$)cGo>>(51hRs$;yJt+{J>VY2a64W+95gZ?_k zb-a_V609}HKl*C39*tnY@$6Rt#BtKo$uzS@)5>JM(!~^Axars{JhPC2D8i}l_3Gnf z83iixCjy_geh*^9S)gl5U*TRmFdVoyh`*o#^kjX`W}&a?3VW;%pK)G#B6M`Sky}}) z{;F0a*OeB~KgD>jn*1iqO4I8w86Xj->iQTmhm;jR%yh9FvhyZFh5)+tNo!v=mmlF(=pmMv|V*Bk|@@(RW1p*{??f# zyDw;WFA_3gnnCVeUZx3zy+D!=M$FwAaM<|br|$2!dLC=Ph1a>C1ZDVSv+EP}qBVwb zm1b5AEy%RT*rV=pKclVODSR<$wx2~hKBvvxao8gPHGP6A+=YMOOB)3_owh(ltB;`~ zK}%XR>gjU(sG^&FE9>=Aa?iKXQ?E86a!pR=eoi6j6Ah=4G6kCwN#3@aKJJxpB6=~n zCd+jgM;moSvLl$Mu9?LZD!|l+=FD&OIG!mb^ZOc0HN{49L)XhN-}1x@Zh%6Tn3@}G zb9(R4+G86}`Y_@{axJ}!-+?{=q|l{?BfJsSjs1uN$z8tF??Jy^u*Wg34zTTK>F>`z zjgZiB4a;?*9Jh~ip?+c53D<|Q_SH1lFs^#hsSJI#p-{B2;3N+B`qWtD+@K{=@fio3 z-1Obx9)71%Q3KMUBtCS+V0H^GA*09ia?<%8f>l>*R-ZXKabVC+=6dxjo~c{nH1x!& zLsK4K%P)DCZ>Pv*VFMGhKAt{4k~k`8AB~0fGgm}h*Hh{aiq&Ra0K`UqLmgqWkaU3CEdROWFCCS}_g|?MTb(PFl6$zc0xo<6Q315T@^V+b|;_}{# zuynS!WOVlCq@75oYR6z(?7uJ{H*FpjjDFa6Kl*eybd&cu>uK))Pw~BWEhnV9(BEw3 zkU*+nhpRXJO(D%=G;dVsEp{F}TR>}hlqU4JDmHTieW1$T>Hs$K{`2D{tF)&sR{tvo z2l`~v=A4b)#)b*x6)3=m94k+485~PJ%}|c_)QTd5%Dmd$-lph~UPlR7HiOZg-krfo zsS5)<7rsjszRM1{Y4>63X*~0tc$x)4p7Z4kmf*?((aGz-n3Onack;&dx1JgR4mHI;zNJ2l%YHYNGv7T;s!Gtyur5DqW)Rx1oD|I`@X0jzf z`2H%9Znx`8Nz~7`-Sn8K@4E4|Y(PklH-P0^=s~QNFK^`gJ;gaY>_!+Y_g8%o%FhD5 zmzvrk=sC~(!{L!)@Zy=ioP+WGc)B_^^99ull%zTm2;JP1JDGaB;XRZ3wxw4*^IcKk z3$$U|AF)kncjj1saKx^BtyvnOYutMPgvxDYe)96P04H9kAszY)Wmy2p_1bUXN!G&^jLO!!{guL9nQF4H31ba4TXJ~{|K|H-%NI$c6qIGk4&-4Zbl6uz5PNwPR6Ztm&P2c0{?>5`%3~hq>&cQs(Jw zP0NwwHin^Cfqv%B$2nIbOydP5qK(IzgYg*{L(%?+1VuIb*9S!vAsx^3XBTri3(bvg zJO*Lj%gFmoKaw(&eREc+m3eRxwP~i7j`1ZF&*yt^Sz@ZBpI>{e3;4iN$-wslPG$Sz z21y6oPhzCy&eU+TzXDSzompm~I3P1y5CKo6%yGQ!{fLmoF*8p9CBKu}T1sA# zl;6U%j6N;t+h@~G`mUS#woiKnl>v%7-y^{UNvHub?0wKe(2&Qt}ZnXzE(WzqXN%-n#2FZ>%` z+8gU@@Y2hxw&~?qU*%HCC_`>?GW}ZD^-v!ICdCv5e(=$Pr;@r&0)nmJ86Su^+A?-y zo>Io!#Gv}k%SrWxErQ3aP5!!2TK#nL+^$*B#Y0zqO0P&dr9S7&RW^zJPOsOxKM>&Q z-++akQ}36qNbNeZ$1|+LPAqKbhpJH?!%|`mnHwc!Zi$P&9-CQc zES`Q5?=?5X=+k;&+ZE-JhkLRV{xC^O0*n;=?^h^Jn%BU@#nb$@OT{u{D zru0C6tex~%7_af{sA$9K+L1b~A^mJi`tx||oh>qW#0M@ub*u*qnqbqL@d1`0fmq1$ zK2w<2AM<(jqRmT)-@Pl=(E~o@q=lLL@^W-~rsP<2=ghGEhR&Iyw0g&7SV8-uBwlEp z?nI3MO*dbo9X6+Dwo&=!r5NGY@=f~f#anw5LfSEl7SJvqKs#wpk19*Qm3p5u`_@pT zC41Pv*P`gL+?=qWq>N%r6IBKx7lZ8rgDcnZ@ZlI;w0Pqc_GVp8P=U!|fhl%@DpT&R zyI2;!*et04YJ<{iLtW;`q<@#Ecs%RPl?@8R1Us6ZdDIr%lu1cM2TfGgFQlf3n@6`* z@6mKDS-xLVGLaP=(vpx0t-n2Z6FU8)II&JDJuM58LK`4bf` z6az6=oby&diU8jSqVRisPk?UV+l`&SzAH6^!z|XQc9@`^DyCBfOFx>8xc$Q_a);UC z$jb}kLXnhhvb!tW^eqS!g!=AiFVgljOW&mK2m|A#maNF6U z(wOHOUj|HiuE8NDJ)0{rsh}PU2)6a2^4DBm0=}0wr~5RgzWRLHdGaOc?N$Y2%1-9S zY-@hLonirZAg`KBmd!sONT{HJ$*yJ@j07)Lf|b_eMfVBQ1i`v_WA=Xqs{=Py4(O8-;!Lw)r>@(P;Q2P5v!^CVGQt8Mzs9N9gkx;^hUa7L|2 zY0lS}cdt;Z}yn8o%-uVMY@!0zIYQat}$xL)(?Wb|M| z)^Jz%5V8O){1gD0>2P;Q_mnn812{!)E%3J+t5*Hqt={{F&srMj*JD{?8=})+a*z&F zBIs#bs3{k|-pqkCu@2?EU}@&bbC)eA27Vo{T|c!Ve@XZJ-#l&RwuE} zs`C|k-%@gyDx_FJWk-&M*E(;m>mA|`wf7<;GpuI1L_BkyeU`b;Gn(Ru>GPuIfh*vBjRY@L`}d#nVr1-?7%6 zIjrg-ud`?@HP|T5KenwtRb(HT@qwdQ`=ad(;${X<91|OejuIP)zfNr64V3~eHqg7_ z#0LJUa*o~KZ8KSH;6s&*?EZ1f8ArD=ra7^fgcUc|q3N#0&o%V7deOeF;qA^E{&rwKOL#%j{Jy9rzjz^RWX0z<0CVC9d(SUM?J zz^EWva}{m#DX)i`cksRU!bzFwRqoHafDwML-`c}^Q^mB0X!-qDhezD_9HKZo>^5D0 z@E`>wud~B`%{?;vmk+NmvVZ8^Hu0mGtIBgXO_r~Fo3)(k9Gsikeb03I5z1qefXdcf zN|j*G_1<8q6!vF!0ntMT*z-)kpYeJsM{$-uU&z00So|ivzAqcxPPw-^#?|wM%^%>q zh(9$aVWga-qu68Z86c2D)d}~hgIn&qbbwpM-Uj_C59S^-73o#t{djiD$;QDNVo~=q zSP%lU^KC1e#PWDHKE~EY&$+zbDeGtxJv*TSN4Ij$Lr#yV&om8c#=SW`qET)5RX!=N z13WD_8F>64*`d33s!cweBN1w0yoo<>K=lC!M(E7x69~S*_Be{hNMR}822!gg_J;#^ z3CYvV-%Jrjl7vq;5RTiu047h-R9~wdYGVkHg^# z@}=*&DqOUt!eFH!sK1R0`GiTTh16-h4S8;x_t`P=czVnPPC2vwnLQR3!H0S=$%G8e)xKG^bXSQ1@P`$!GO#TT7??b9C*-*frBw6pHxd zb?#97WOmHUGuC{qM%x$gZ{2>ecAeg5=cwSNzo}*5diUH!o!lt(^<|Jiy`xG1wPSqI zc*LhR)}H3Wc;^ZpcgZ90!}w>PXfd5Q03%quW1V2fH~$E|-Ix$0*z7b_ekMv(`R!e~!`` z8cDu>I$*y16Mp<_eyLfpYavzo*P1j*m)^eAP+jvnxpf~A3gAIKzS~nE`5d5>SvO*{ z7TGfs2OHf^Tj-F@m5GTmVjwSuU8U0hL&q{B`qQ^P|KFO6+wx~PR$9v@U8GlYFva`2 z$`0H5EEP4w&=z-3APi`!IhX#S>RSJCgah+kZUFrh2B2%r_5M955Qf|rPi-^nhx;g; z6S8|Zo?fPq5j20(w)3Hvm&1|(0;bB`Ua%~rjB7x#$bH-G#40-I|KXW>b(ic@X9^1q z0{&Ovj9CZ9Et8G|;H%x8I05Pqa3U671K#E$I7R~pe7mZkKjz;26Y5y^_`;B#9k%Y7 z;Y5QHSG5&1$;h(8C^Ddn;A37#XxRIyZ(J?rlH2GFLd8{g2RT%hlR7IqY~d~-0Lit& z^~PdFua0xWKJBT!TU^i3*R#W(CKc49KUL)vdROj=i%8j&9rk^C;7;C6F0RS_fcNkM zya*`XD;3XU(51@_qL2hEF`kSZ^4IfQU}wgm1lorDTZQjE5mp!OIS*bI{v!Rx4v;V0 z$L5WyEY|N~Z$e2x@{6k#06rhsb!_}=(7^ET(~)%7ml-u^+xm&oZccyEz!|5?ENeqS zxt`KTao+B$q$*|ht7=UDuyT-_K_@lsZu7nLAMatw!4;>D4TjQ-B)DM1K~@dTql3jg zV-zBTs-O@7CeM0;@Y#9mAQd$@gOyNUs`W_`IqUn3s2;xAgsoPRi&PL9!Fcw#e0f?uJYh0h8y@aS`h{h5 z`|I&%#M<}a3$tInYH&|0=hS9aF0uA|m?jz_+@R)cDXwUJI|%>k(m{i@-}){Iksz>2c{n zE!jbrvLtSPp1tZ_DPAbi{27bHExX5Np2SnPXqlD?LtX2w^r&-$Og*T1K9(dfRn9hf zB)Lt}YF>Xse>*;N)F-0ixZ7={w(BhIhPJv&4&EMOmzP)S=xw1qcOL)1h85iJ#ig5L z`q65Mz&G6|f57r`4bypmzsyjg>D`4$e;Wwn)W3AkmNfCBLXM8EB*sbuNVnO>`mZ%` zax198<7?=GMF8CJM3jH?bKQ$edqlh?Ggm?5)tmEwgpq#VIb0&xy$|?CX4_0*QhKPY zdvcu5r-p~zX1)|bJfw;2sDT?SNFPPVL`uFq|vj)===8oyyLEnNuHL_x2w~@9ba}nl* z4T*Z$UNieLRqYzIE9sM3T8@F4Wk6=AHt@&XCLTyKVzF<-VB6TYcou4|-rmH&lCwqU zt^YevHliy6W#c{ukfwL@PBeuhJ76gBOVDR8%CHP}ce4Q^AN=H%A|HdM*LU@GX24GT zOg*us|Q z`rR)b*?j)y@;s?t0=_q)?hX?;^z|?sJ5&E3W2bIO?mGhXu0>ubO#B^Re!Ebx@dXmB zXJ-~C(yEs{LFVVLDeyn~YQMr}ipRxdn#j$yL6|#(Hn-7l;J=+@o(b?OTVnBh3!)AN zN9rovb@mDHpJ~$AK+z;0nruX6@!GS>r@3xM{|V+&>}8hy{M70VBvpG!W~Lb*Oo_-6 z&?_UpVKvWSt@^*b{R@0l)z!z12M8DyJ+TE%tF7bH)W%CSJcWm~XBZ;P7@lLH$ zT3d@akyvkmnE}S>C{M*pt!>d-rL9$LyP1V&F!})A*J+Eo% zF&^2xr~E)IO5BQMrn`4uQR;_((9~%H6N1s8=+anDeHF0KGXh(IP$n0xU4>H z-I^daVMs}3Z8SH7CrQ&b7{dwD#nekm^Kp-KDMWrN#bR*M6|NZz37vW_Sva|(_vr!h zpvKGfoPNA^&F<#bd^h85&99^zGf=twvHKA8U|U2&;%e9^lM-c$WL-)1$Y=p3L9?nu z8)r#@q&Qc?@~`o7^tF_TVsO;Bv)=uf4O;SbmiH|z$CxN%oA*~iLa0gDsU~sR{~eR( zF$C%)xbmuH>V=3;s*9-6PbAz7SQcUZpZ>ZMcvf-%O45Xe_J6=l25QKcJ~8vnq3MH?iVOw}27+vt7@N(yHU zVSzW?3xN;ZeJ!RXd4(6%y-zJn7EWRNSm$1z2P7=wpu}=MKj#|Q@&^}!=WfR3BySJr z!}!51ep>GNDm{hVU?o|$zdAkV^=U9-sX|+au$cfNLe)=A2-TYoVffw4ppeBK8vYds z)l9;7g_F!n?r_7cdnBOWt2tJe*8ju0et_iTm)m#j{f^`w_z6W5JdSWE&r{jhmfuSI zrs(Ny_;EeIPM@6jH{LLLBi+eQdlNX#+4CP#;c=`vE7kJ|3;XGn+Ffhyp7-b8d*Dwz zKIT8Lu}7n3V*$cP+Nfh1@L;qwnjemNexCGh=2Kp$wK~aqo3m1#3{_kG`lSK% zxHbQw*oMt4wy7_BQHiicAZ|iMTy-kIp zHj?Jt!|Ceg!d#z5@zSK4*q51pj1SeR%tO%qcY=)UHS~oetZNIcF?OQo3(YfF;ddnp zhw|Hgt6FT(1&5|K=?ky!Dz>s{e^R?xu+?%E_Qeh_RvsWaRWH)k(6=UWLT1Yci4$8W zP_KRxedRp%Qb|D9+lMF}OoI^IIdb;6)%iz)ODB+z-KM=_+*|p#gG=}05!2A_R*HWV zv+iHgv(+cNU#eVHxr>ZEtrgja(>qzb2^x<_Ir@g`AwLT$*-}nAwkolpnci{&Bi~$A zdJ=ws^`L$seOJ~3mK8{wm9;J7-U{ZPOs+YAO^s08Tq@(NyUzqiaWEtd3V`FBejph{ z^uA6VtI?28Ikg`&e)tOZ#fT29^~0aSBg3~_*Px(c4ht7t1PlmBCNLWeb`}gq)&hgi zg;9{GKFZSg{g(?We+&?Q3=k@*Pe5SRl}a#$gX9t6cPjtafo$QJO|6hPkUYiV!Qu}0 z?mmJaOo7Qfff>uhsyIqy#Eo1k`L*Me>6s}pN)Ub>dO&0w-W?{PKb7Hr;=OyPM)Z7o zBGVdUvB-qyZuJHCu*2#jknqo`M@b0JqF_0caTjsL2;}Jz+wvgR17{~($LKyG(2Pw( zm#NxgPyLv#kpCaKYExp5A<%y@Y~$7t2alFVqZ<^~0xJfEft z3(7{fg1Bwho*Bmna9PZcfU4#kH3$5GW`@Rgj7;<0KC>trL7T4m~+#{ z{NvN-ytMnr)4NNf#@ z{8uVs6N@K_@mgnl7r5(|at0baI17uQw$N{{l483#Zio#YHF)?Ut`?e^1EkeLbIo*q z$GZ_YM=K_#6$S1sh40hD?^n6!>xYAOU>WG~b}P`!Z|Hm4N)akz8toak6pt41ioy2q znnI%HfJrs9twY=un^wLR*W%%rWE(ZSHu+c$G{-Y zgoSt_eWW#t~*uQJj)7V>N>XH}WwNeMX*s_vxf88cA?C4Kt%jPHRR{;X-7C z&Tum*f}pJn#peQWqm5C8WkDGREO4**pM^%GYNGM=`+fU9idYJF)KO}53OYkYj~-V1 z!B&82m82Ji)dsmkz^vXscz$w;ACKrkS@@8En19D};x!tmTq$H>mqnhS2sJ4D$By2r zoqA&`XnKs!`60*4p&-IDH3W?oYtYEs73kdM4@AuZ6G zXQ<`lXVjJRi0}VNc=ORz$_2~TsMAu5JYi)`F%sl=7i5T7NUw1oVRL;zRWMAxJFPD$ zGeU_|88N4hui#@FkKh;Cj}T`<4sg>l$+lvu@xNnd7CoKTPfJ0_82K=@k;8rV5oiV%u*)?#0FK@pht(9n&E#5iSTj?71PRFqTf*m!U`c118sN zJQ8#UGiFCU;jtiN!yUWngP`Kx5ws%e+w-K)`>yin!Y&CetE{5!k+l*=&WnRG8^{As zj6N54ctxGn`gqm-oj8f=|K9qT6_!LD|3jrk$%{Lj*XHzvg2pk5=j;1TS?U{XC?wDiJJumJW@S7m?P0tL+H5lfV1TVWaC238=94j%@_M#76%cpN&v13DK*WxM2J6S5?g($kFrlBV2ItQSZ7&NXuUFk`UHSV# z77S@o7Zk7xhup#X?Eg!B=e-uzw}Xau$^Yy6ZunPl~O_lj@^%b9sJ(yP9jK z&p9IogNKLOxnJ{le`z0Tt~2^4`#@p*8aHv&2=1Ubrgq$u`8Bg%oKAN~YOT_GCs48S z$pSu^Z={Ll*GxO@H(0*7{{j8cUJod6B1*!kYcny?oLh?E<_IVKF6@wkB1ZUQTp62* z;wE){euN@?r5cei@(<0zZYC<8-rduib#5VDgz*zZhlfia)O)3WGsgc{O|!MoR=I8V zDt87|ht5^=46mP-rB)T4B`?6JZuQcWDQN_R}IkxYiI_)YG@|EYN&%>8Y&7tBx$R-z$a<0 zxX_ZcI5cW8r&mGtWk4Zbi$;U&Tr1@pE-tnQwOw4|lQdsk>XQuBG!niO#V-GreiT>x zq`I=kC)Jg;KB=y(w*~o}%~$%12a9@wtgckBK~%Gos$>8N9h6j8_YE4<(3KInY zH@d(5rXPa{wE>W2ycGt)vlB2uVow{uC01+!Ghkj;pfH z7%-^~P#yy&wE@Rt;)X&0ePh^6bDRjoY6lKh2Mej{&Hin@bOM1L`}vD84|~V}kcysW z{aaDEFeVc+F%{|9$;noDJ#6YIsov5X*5#6m&8w30FYXs4Q{#GO?TLiOI<^%7NpbBL znQ5J)7qHr$VASuW_!5bQ=;)Bv-r2FAnXrCca{f3-m;TKw2rTctgl`cuP zH~Kb)9ps|8?yxG|0oIiF1G*JtH`AjmTEmS3c!c2UtRZ-=UfF=7j^F;-v)fn3JX|_x zP=D0jY`yiH0VHYuUQnZ=R81+-?Ltl}#4*ol(SMG2bb7t=b@{mRHT#HPbSlN0R&-S8 zG%aF#X8l(ARDYgF0nR@Lx&NYA=B2FwG(9r&;#TfT3OPLx=SLSB;+XozoyJ3Q9LU1y zj9_lB)=~bE2!|w~jk&-tu{Fvn<58}gM`0@9Bp6Nwq@optVO2?Cv<5%}*dXDQboN2x zFzA$Cfjc$vx3q}&O;G+qN6kH&#^(I;ME?E6oR@U&Ju&A+|MNjb9F$nJA~ENEr4l5Y z8i*457+)vmd{D92-Yr+QPj)vqJQCz?Ash9RHzYoclS8H(OWgaTxG0ov1$XXN)v()+ z>C!zm6LTosk3UU?!)uy2FJwyo=KP=4uQ~tpy$SpFVb~S!Sugjm;f3_~!IbxqfpOiBo(`vRCKUrGQAaxcJ$mb!Qki1jA_Na=Ne#uI?n(+fN$ z=6o2A7s!;M(A@B3keh8Ae@|UY@z}aCPxNlb@ehXn!Kn1%411SE!)~8Tzg|XZjo&(( zptBSDJ8LLPkI$s7kiS93(0Q-!;>c9#2)bAQMDw_A&f;ui3yS$QSPrN6pWt^w{RTYG z91C{df=)=RN0PRU|7laARbW}nGBJDD*-+uf%p?YblWg2M$X-DfezV&zOg8TJOpwJm z#DN7wku}Nun%TXEwHsU)w>DGHf@{g;&?DN9AE3L>JcKvB^TI4T8tn+Pu|KQet`s!U zQI^QI{$3%uwe{|1bV8QM2I}1u--Elu_6t8~1BCc3N$Ru-UCmU%@Ny?!_5mePlA5|< zn#QJjXGDpaQKG{qvbCK`@TXN-2Tg|*HObVu(RFP%f?t;9D)-gfQHh%D3qQw79?NNQ zsJ3>(-^s0(P*WYtgf9b6>?<8@%}Os;GyEyN#3wDiG)mLvwdb2Y1Kn_toyeRfix>9! zz;ttc4%$Jscyf@MA)*|)-J|z={p&|s;SL2+XC!EUgUqgi2QOzLoncN|?!L&VkdmKa z7*dby!(?a}U*R`d^wH_vt0<}qaJi7XIu&}xKllDHSquZ+^Hy+p<6QssEBu;ReKRG^ z`3+!oRLIqgro}xg8Vl^eo9>Y+xM*D58g)B5PHxXzEAAXV^b;ylhkqu6oAb$-_r#y@ z2eZJ%7d@Y>-B~^P3e^f1Ogh=Tws(0nk7yWs+%aKpP7xZt0`NNjy{uCu!A>DVX0m>S{QRHb6QpNEf16n}`;oukih1R2b1Hl&%t zz^R(#mO`yd4td`0)MC2X?l^5ZYnRsqBh>~=E&DKot?nP-Krql;B;Lc5=@vHaS6 zeT1&RKu)+JN}rtXZOOlZcdy)rVa4$GmckM^!*^i8eDba^9-SVM91)lN|RJ{L-v{N@39ZFD)N7Syf)+ zPO?WeGjtm!RM=cvqJ25{gyOmBf&*r7%)^m?O6T}t1Q1dMK)G_2fUN7gM3}l~y;Pb? zVYlFCkw54@JPKJ3N_#Nu$8R!1`nPYv%`HxeLGof*Ka6)g!WHz4+YciPK*Y`k^L8;5 zLT$+Le@;6Q7>9EJ#MFfvGH!c^jBW@)_~vM+I|P+ zWhENNnlX(NQwxc>&}mGPyRs^@Dsqag)p8q>GY| z6<3D7@QrcZv%mu21w~N@rDd#lAK#3Lh53A@Qn-Rv@3E%Pu8GOO#x41n7QBjowOV_e zNYdig@%hmPHK-j?{q3wB1t;62md$=jKVsGo5;akx+7dc%H=8Mh=sl6@S;>(4dRqt5 zV=W@4-t1+`;$f)oNBtB(Rc2ZzDWHlM;7{fb)JSv=NA-P8$OP&m0MT%A-11p>D}~BJ z4&~jnD}?9cP3a$vd7_0&fxRbrF#iGa+|?XU&}yo7ho238|L>iLUOk`=YuJ|$3qg3v zM5ZjWvLSM@GdTnzl+|#3y`owfQGCR>D@FUDhvrITeMD5`6@5Qii(08-QzxpY@pDT% z(3q!Z*1u(osWI`OrnvW(kX{$Z<1#*%jbi6U*YT2nVU!T&K&?> zxs+)C`p&uB^mqUz#%wB`%1>m6MBl>#)WplSlgvNEITz-Bs&Kzru(A1cqZqXo=CU>Tt+QHogX-_sPd!Cb za;}Hr4(9!mJ|znVmh^>1FB?W4wkZgQB#Fh4WJ{tm+463(Y3Kz_o_jg+%20+NWHZh}=z{JL;zq z5!v>K|CWe^>z0wU^T|MKCGUt`%}=Wr8edHV75kbdA_6L#<4(2vo; zrAhkWjhe!Q7J!p7x2?x7!be2v%rXVH(1?kn63s_7_v91ddcH<<(a-;Wh5 zAT8`KpW+Xa#T{~g4nkLBT&0nrB1f>R1?J-Lbys1#EF9M%x-gYjh6>Z7M2Ald7Dd_w zmzm-&NnyzZPu<0c&q5V5N0T#C^d!ozaSNTlnY|}ikW(AX_DqRG^x!1Vt=6f&I$K-4 z6Kp<2I@kVysmN@p3vw4xIP_jP=lZa+j`3!t$IbRBoqy_Szrap-0b?8p$6mE5sBrVS zau(u+XwrVGTCL+cQeW9ZPmqq~5R_6iu7#9*aR&xe34H=OX`HT({oXn_3N1S9$`1nW zKDXgA4rAP5{dFe_FCmmoy1Ai!vA>*Q6`%0s4Qm1_e;-5m9r_}}tEZorx#KnCP|EdP zMQ-UdYW9~mEE`}SAdcdpl|$Nfp`P_e^a~$2&p&W2E}@;oIp8KaHMDWBb508+*JUd5 zf1oCSBe6X9*C+#FZUq^s;^e8V#o29Kq_zkPR!YpauI<)@#6(Aye_!Btv)76w@NzeA za1#+o6k11evT$m097-ZMhhRQ2*BEr=k%s?r%wu9hL^(EUn5~Fy7{#f+$R483<(}YL zoVN6d$>M=)#&BS-tG8NqaC7e_ruMkE()*#AZ7LiVlat+sross`nz31rZ1Qe<&A4Se zgL0=TDfjAeZ?!*>9QS@O_dVvTWgLpE*GVLf!SxkG!wzRX&l;iw^^B9zGBz!-tIgLz z!#m;ljzc(MHWh5q#!KwMICFOQp8fQm`m!zK0> zFN}NgviA2x8{$>Vey2ineHSJLV3bt^Mq;qPUCk5zccuq$?r^lJNWHr zDO@AKw&s7PAD$NYC;jlWke@`)9MLb3M#c1|rFh9=ev&J;#Wn8mU$O3W!%VYJ%y8p>nG2VD=Zd)!}j>Q)`y340_h!3g7b9bOWf@Gri^iy2m;-oN0?z*_n) z^SI>sb*@3Hn-^vu57)nYhbX$xi)X}54%mOR-{6<0{iZd~u`OMArt>h5qP|@M61CUOau2#t$s+k8%q z(o=mprt~zQW`kQ)JA*U_l&wy#<&&vyCwl09dWOv+h8o;BRJA@r6UE^Y=x~r-&doZy zS50j&s&`b1?3p~eXBKnMbJnUxktJVpzF$l^UjBfm+$NrH(02F}k}qE~kMigcGx1IKKwC>HO5W7fhKy7R8r z=6Szm0EoPF>P)EsA&n<4ogI^m@JO|b z?IejgA8F?ZvcIF=g5AT+&4NMp=X$(cgszFeUKwI5Wq-n}rb0#oXwKmuzNnjXJNzsM zDpz#po=5~&z(6U8kBm0-p7B`RZ=3w@SMk}no*?H3@+TW_abkyfe-7@4>y6!IXYAR; zsXk5LhgO+(?Aeq_7XGwe9a_**JGqHr#hVr!T|0@V=B5QF)i$}WK~kE6JCz&UNsf}u zB+1jMo;dx?ZBMm{hKGZU;%_I5=d?BFw=j$#>+edwsK&kcbJGFlhX~NvUU? zJr4X$WiG4+T7)iUboU$b(vvDzIMu5v-@&w_&bGPZPg44QB0OW-Yrs$VvmE8LQ_vRlI11w4VRCW~i5EEgHtnhJ?ZVJ6TKy z5_+lCmn`~)DF`GP7qpGqS*Tw+*y~ZXUq!2zD`9I~8vjYC^O<9wBU)7EqNx?_JD0w| zQe~yUGvPxtZbgte094^cTl8g;1ISHfRIrP6i5ZX#n%-lG z{BU<1|32ovfcYF9!*8NmY?{(Lg?jXT=o$NDbM}#R6@$;+%5!tW--7u!l1N}3o&O6G zO?vZ;w$#j}JSK~OQlq6m^TzMvxxRRCMNhn8OE6zo66!l$tS(?@MFIVC5q^Cie9PRY znW)s#$=F0xrnhYt=v&E5uwWJN{kMHoK#8WR?jUy{87;*VJCentkZ}9?W!A~iW)6K0 zYif8l$Q?d{xiHCqgP$)ai}z`9>7)V9jCYROrm0~R?g8Tl7TUl>`@@1PpC+xS2DdiD zHma`v68LNFG}&TmPzU$Y$Au|SP9}QFREs@Vm@b%r zeeSq*LQ*wSvB@JO!~7zgtQk5tx?S|)!J4auqK4JN*#EQ{uK1(h3{UWDPx~JK>G~8Q ze3;Z;r9aiy7N$vRD~w)iSJNM_g$H3$n^c%glGLh}Nyd5>t|fS}H~xaK{>5A5#Yd>s zAloO@*|L?eBwPBIlY97Q!&%gug8XZ|ZOXq@y2;GYS!+OWB3Pt95cdBm!g{mbs_>P#0qM5}q_>1=79n34z<3j6PXwurE*(jta8xY+xOZN_ zC1Jht8+o0Wv%z~1^!axRg7#Itnc$yy;n}+|usjlT`YIMf>!5z|hPQ*<2h8&Xy@AR# zuyW)N)trTjzDPo(5+DZIr+C<8yIf^@uT2?^qB0H2+Qxztmw4g^_rl3?=|CWE2y)l+ zMXE3&_k^95(C$1Fz-T|!6zjRep0)Y%(5Z(aK5;?Q^1`B8`eS7l_}8o-%$JtVD2oV| zyttYdL3XLV9{!6T$^UokmHfa(X%e)9LjZ;+f4Gg+rFjyyg`H?3U=U|ccwqU#v+Hn0 zVg=q3TV4vXmr#!7yug>o@}|Y*hT9) zZErCUz4Z5R2PwhyNofKDraNe1B|BXE*}Br8W4YeXkjkS2Jx-7l^7~0Djy~;o3Mn}D z&L1+((Ue`CmsW(d6xKgt>xgJ zR~&tvPwK5N-&Rw)_uX)Ow7i|h-DR3KKd|}>0G$))c4kN(o{5GJ;0{W+VQnG7E*JKFN+zxZ5Ye+CrC4#z?OA zNo^f#d{SG-TA$R`vEGtx@luyH)Bn6u&)T~lr37}b-n1V_Q(>VsRahcym9%W}K=H?D zDJ)iP=>Ya#g2HRZn=2sR`7fux?jshsXY3tEQNYfbz#Q!fN=orZ`x10aYwK4)OlKcj z8!wuA&QW4o4l7h{X~NT0TDe!63R6LYsY!GyL2f1>_TAyE)+1s2L`*1ZU&9gjuCOQ5 ze5*^)SM}yF-d9z&gzcv%7?;(OCnjs@dmul{^p@48Q@!y|Hmj_x3U}&{qqVSzGJaKD zLdrt3r83JpDO8cZT~b6dly}Bx=DpOxD$lDT>A}XnHi)*BUfo=Y9k` zT~ow&b&>NA9Yor3j6#aLN+M>l0FIGk^C*I2n6r&CdLOim@j6$-$>+aYAVFn3;WNG> zZFQ>gmQLCW=Kc^+2{~DM9`dDO(VNn~kPAcH%<8_<>4w0&W|nqEg{UL^8qI-jM4yI$ z`ve<=68urNiy!qW$UctAjcK1l`y?pr0SZhI1;J}cvYwVlvX?XQ+lzb zB;5HAY`-e{{md4NbYjpe2s+eXcQs!mpJhsS@})bQ2bjhWUpZdU$AANsIpG zz7}<84%I~+O6L7_4CO}ubBFew3;7GOhe^jdfGO@fcCHGMY{c>6u!$p-c6Hv%Lc24fg5?y|IL<$5IQZni__2vy7{U(Q<1e z6e7qxXfjHO+v7a4&i+OJ0Ojq`YjE!OuDWOtmd=y)xW#-XJQQ)8;P$R$nMU1vz z9!`eS63lxU0DW@yzijnHK0W&`6!+>|2koYr`aui%CdgBWcP$J0@lLX%$hw)ZboHAz z-&MKE&v~`q<2Im0{e_Z6F@vjrfa)A{hw1*zv3LlaozOYn0@z+;FN-!GRa$Gi;pH!=4 z+Bk|$fAE75DXLEvN6mG+g?)Y2ptmU0MuxkPj-M5-wT4AAJ86>>kW8s+)1L^x=2k6O z^AMmddXL5!fZ=m*Hq=G6Rbip^WbVNKofK5)4^>bd=DF}$VyY_iLtIoF;~9Hpn^>Tv z80?t3kCAp{o!e>(*b_MP_zbvY433Xu{_YWm`=9Gq`Fk&r21L6!DiuEBYM#&Dpoj`I#>X2GBos{gTsw}P2olf4<564 zqt7sb47xz+^=904#)dCXK3JvEIYONU2`j&e-jXJr~fD%>#m3WyRp(UR-jl)xBQm__U=1) zKs0Q;*_K}m2Qu*W$kuk!7ySiu?-!-Omk=v0E3k!YBtj-(OkZgqz!uS0!CL`NYdwAi zSxJzfQj9?O1PjqDci}b#3_u`zF7Lg|pot6p_iwnD4-aXx^dJ8Fv;M>PG7j4Je$NgA zv4-=jdj0$Rs~C`7MJ)a%8b(B#OJ9R1vCl`-6lA_&2pMAg1N0`Eb*9Cz9lV~nHq)X~lvxa76QC?@z3 zI##*kT0Nt9>SSW_?hV3F;VGylqRpCSmQa8Hf=Le~5_|CQnY-kNOy!`p1IR=x6vWi8 zoq201k~;IeADc9NeWb6tOP7 z2-PytUAz7NtxIPMog(SM$SE-%0rCKzq7Ur<%&x6@hi^Z@Q&?Ck>t50#Ipc)(TNOL= zy;1JasC(Dy4g1w%)%^d6$qji@7}C;QHY{fUerAE6_xS0jI__d@1<``_()*9pc9|^o zz7&$5(u2%RRI+rmbP=8|l|FCl)N@Us)j^UN%HNm2sG-_VQj8zibPuK?4;j3DZTgv%Uw_O6$!M7QzcwMa%+2M`}0us`PV?5DbR-Sl$TcrR&u%CH@gw z(>f5s-oJVPA%C3*Sld_Zoz~WeDZjRcHLrzL-v+je5W)guy5gvqauv)7n0(T-$h+Xo!l%qeM~(aumIT`1_Nj zneAv+12J=r{n%aO-;L2bg!8|P*v<3rz9h0$C#uBu^0w(5@%597R{J{5E4@U{9O*VR zYY~W=Js+m(+>@mET7FV928fp4QO+C}h!?A|`*1pNnBkZ|F;x0)<3xWfuD0VK>$|+K z-(F-dzKTl;N{ZJMF9L;Ved1{K+W1$7v(BCHW?vtH6w966`zlWsV=fk^>fFwx!p??H zU1k41Iqp7c4kkLy{&Ks|b5LhWvGIlTS0xJStZZ zDXnLX9pybi^B=nZ27w?)=`VGn*Z10u;cwhQXdS|EET=nJ%_L28@53kjLA?Iy9;8@q z(eMFMrAOp`LlLLq&BnnFWH*E=)m9scPrw`TmzUF`+!;#9FvIki2g%GRrz1+(^uWxB zPv$=X(+tw{oYP?0QJhB zKHN)%J*fTMqZ7UDL08y?n8NWD3zYNtWS^yj)`ruD&?Mq;LIdnKVIIYK*0jMZ@l-9zTeSsEdEWE+YObi)<(6Pb&(`b!02iY z6@avycMMZ?ZdB1<)r$jxuxh}H4)t@?+erqdKjES94>YPLY4oc>367EIWn5_`l1hZQ zRWCf~(hL5SUhR{XUNa!Qc0hW4ISqkRTD4A9LKs7D_)p0N{D$awH^~Sc-%?5b)Z7-I zw6uK|zOPahVOoNs{@hier246ep=`@?TzV_=)^D~;n5G%AbCjG4^eZuU)yZkv7la5|C&c2(77 z96+?IaNp-L5p$ldN*3<7u7)>26@I0eaC>9E)R66dQ7t2(LrXDIj4P-jQyyo^X<$8H zh%B|_yX|g0fgM(D4X^a6ut(2pd3N6lNz>^tD%zs3nE`%JocP|23GvYhRMN>lu zZS};IV28J5IehYWIhUY)kNv`3M??{*$!JJ`z8ydUBqtS)>QGm!nZ4keFf5v^9#yVX zX#gjv^n+?d{@6Y=nx;d{L_`e#3nAQDz-^Libwlo5iW1K3HypaC9Hapq`Pq5iSBLCH`ze*HDaJX22DjF9fQ&DmBmOse! z9r{hyTqcV)F@BE}FpbQ_+;{S3=DyfgJ)_;Tsk*`~8)vq~;RG427^<8)w@-(H$8T`I z=C%Mfic`rM$=)QJA1CU)yT|Ty*h>2hw|TbzW@Ayj?nbwPU--JI{kIF0unoIK=J5D2TIyQE-)e zns+wckdAx(g694KG*o^*z8QAGmMrM>syiLmU+N>u=5`Ih__<&K2UpG|__m`U4Un&=t`VFN7+0qY1 z0*a$gKHQu(re6n<96=uU$067Exu;K(_M*v8BeynbeqBBFsdF*6XPByU7mR|E>H?im zj|1j>@8*!=$_}Rw@6+Dt=2B&86ExTAb$>bq|K#UNH`$B0IyJPk)*d?Phn|O*R`)*( zZPp+3T3_Zv;s8l!#^MYr(v^uqb7iu4bS*~YSNRUgH_GjT zo1904uL}`CL&Jfte1wKO>ose!#vSX zEsSutzo@$|a?f$=)&j9Us*Upm8{Dq%Mz!2F@O3Q$s;^x7(3YaNEVC_tjz>nLr9hxB zBsVOC7Fu2q$X;gshc~(HbH+P9`%dyVkx_u7QBAc6`cT<=x0sqRb=lZ>T;d<)j!^F0 zEw75Dh7!d@lxMbhFr9aVjtqHuCF&V_`+sM(Q4ZJw~ub2Br z?V@gbPI0L6cZl9;E6eTWJeN}APGtf-LLWnlo#K|A?07qe$C%Rr8&p4i2EX&a4e{IE zdVJ`w(EDiAU)I#NQ*2Fr?w5ntR5TKI9$%IA1yAiP_5ux|FfpElm|m*V{`=GpwrN(-PGcrFL~L(`8OynzqsupLyTFwskFXN;gbdg|)8%W{9j+ zXnlL1#f!YcVYV@tGPi_5jyGgJ9s(wDxJiA5jbfUimA@fsjOtOJDr zW?7PeEV4C_h$(@@6|Wo9#U|2#XbYXv4!y&PHv*gD*rWaj$O}>2j#HxvdOD&{^oK5d zD#C)+I*cA5{uDP8_O<;$^^uF9t9-G^Ve!c!?=v}O@AKP)-SYdp_3KjKulpAEySk*0 zi+c9Npz|4m*Z=4J8|M4B>wx|}b!>nC`Y)H9cYX5nHD*`Q&+? zWZ}>%&uyVzaYF^zxd(aF$3sB=pt6QydK2n96`)}D!UQ7;(eEQ(i7Ml&f{m+ zkTn0Z#!Q!zd3!T!nT?`+|NE*;gBA!!dpw@6njEiKH8~+;P>+QPBNLpRJX61O3~YTD zvwC~xtA72hnr}4>xQ~VtKZ@g6rT7lR74CL#d2x-fs4<6NT#Hq#nwY>HbzAlB17xGKZkgNmO3brFvbP76gYM5=ZLgUFb zv!3U=0bI^DxZ4o348YaVPQ!UF99I+3CUB1J5tv!?>J=M)mHP$W{M7b{XkZmy?n`eb zE3xLyMCR2Y=^rLCUNJPJ1oP|pEGT5Pfw{j8-%nK+-gNSUn{upEy08LxqmW$(WfOiqsaet&Z=wG`#C-ODgE$;%8J4CZgBn% zpUjuQiI&&!)vbFunw@4G51&xHi)3}E0A1(0iKjwXSE9I9O#f=dThk|0a2XJ|(+%z< z#|^{18ek~m?&h@?yrq*4@c|*|QHveDffym((-)R&d-4^%Af9UBss^~Oo}gRQD0}_R$zo+^vU`1H zp=s!rycI+-yO8S~lavUy5BDqDpN(srTGdYM{*hq$6pgB!SUUBeSibGAOpi9ryN+U= zX`&G?yPH%+`b)_LP0=f~XjXNaL| zbRT@LvZ8nY=zA+&FggoG_1jNn9J?9eGdH^ZUQ&wV$APJ!tS z*ReO`EOY)$=u~DQuk=S!ALx%{rzHUHF0gJhP{BGg+5d>HB*&dOb2j&6oj=u8sE42& z575xkZ7)_-EPOD=r|#9$)%VJ;s+wSXX0SYejK6rRCN3G$=*)wD8g~!%7lr$lTJD=p zix6jV%Wfz3nq|2A_M-E}`|1Sy9@|;e2uUmFld3^~?k`8c02l8QX1lp`Z`DM07id4l zul7YqPMoRaoL?{IU)x(4lFptQ{%HSmlMTb~TS5VM<_zuPR^^GMW$Qx(Essz74PsYG z#leZ&q$ILU(DEAh4#1Me@b?0Kj@gF5u}E}tiW@>a`-A%SM}xP@-nSOMI}t%L?ri!}g-%a!hmTz{W&wnn?+q!Yub-X;pu`Zyh@*+Ga3Jv zsbiiytgvsLu%q5Lo&F+`&uFbUwJ&WpcY+qIP6m^^llc{}ph; z&@_pYbW@^q8RhY&GLvTx>CFQyFVE1MTnFIdPTVh(l)v!ZK))iokKPD7x+L0L+xtIu z|C4SCNfzcC{V3jQRETDe3h}{K$8Mb|NVJuJi%Jc<*7VT{oVTv0?jdQo@{R7cXEoVe zE58 zP`rz;T-9_?tl$q~YMTY!*64lLcvh8;X!o!(LVP&pD2oGcI!mz(g%K@Hfo<8N`!*j+G5;kMO4L2EvQ7B3K!P2=HE?k*Li*%k^U-QqFzkS z?w#i+D%!7sq3OF^6cV!itFCOHum;1Lx6n~kUhXroeMxFWE;*UXA4 zjvry{hTHJfkmjLrm>lSZ4i@1tvh0eq&35RjFY4TcNt|N}k~Y6$=+H*78ske=sm#GYW)1 zJ}i_Duu*IJzYXhgU#t#?vMG) z?1SRSF1U!KF$D76K7)K>$wDAYQ1Kq7#p=r~v_z|Jw3dROy|*zC4v30oYbV8MEIMFm927xMrg zG?;_7zf!esz_x1Z%1^vG zPwj7QStJ!mQTzF99GZA;k8jr2ArA6Jp0zjXeJX!#ZI^zdmdw@Bx0=FX*UFUh#C7%~ zOX)ABi-t@&+#~%rbkOdrHoNPm-N5mYE$&9JFzZwD@m`z|X*~2CdM7zSR5X~cf8C^J z?Zo~-gnNH?d5C7Mt7O_1D%{nd-m9DXEB%%=T}BNq0&71svwBFr8Irq_o6xol09-$P z47;)c_iVCcxmeumL2FZ#cCyJ(wYqwc-U{Fx&C{KwqyG=h3i&d<=y7O$;ctVhPI zokf32FZ4-m^;$v2;V&MBfXAFHRsnuH`Arq(Rj7{4meaw1dCE7=6DtGZ3o@rN_*CJ_ zEh;Y}@!U`n#eF-CP;|e-rgW)&T&&z%>mw$-j~O}<@s^Sb;nE$34B$9pl6oW_c_P78 zI|`AMdzsD!*^vw=$!hDQ2u%u1sp3y+B@Bn6rWxhx-7rT%Ea9ExBpb&zZER%WPNz9x ztA^Yn%S)ngrBH#Pr}C5I?#(9Ka2I@;0VOugTTB*MJA6LZDM2b0^Rq0@J5>0(i^pw5 z9m=9uFiO=HC;KQgC}=dusqQ-BL5nb$yj~oA$$`}v0*Fu0yoRc;SJgr8Y1FDREE4Jo zsT|UwhZ#y?xYcQ2Qiy1w1)GPOaGy*So0H0{6N+pDnbj%}1WgPTa8nfTwO_FC0448K_dS=2EiUMeW)4B~PytpsH#a9;zHY4=x9W?Ds>Ye?|? zeMGPc&n*zE|2{oF$Un3U>5&)i65pK#>!}D}GZCEAu}d$8|fGV8qF8r3KE-gg49si=S_B)kv;(;f*RhVTH!Wqh6j+i z5H6MXuW8)-gKT($4Ce9TCVv8~_qXN!BUNaRnfwqf3cbUdu zo-8hdrZP7+dh;<8TKYOq+7J5a4`(Jg*vyMNJ!}baqF~Oc!ZOhx)D1s_-Wzd=>vevf zUZ?W67`2M1n0)e$poL^Bs=oLGBHu!>;AuRmDz(8MuuncfT@|Gb;-+le;nZ4)R-<|Q z(b3YE`N!uQiEAz1BJnabLcR&1OS%&ulZGo;Fc}=P^|X}+!sf%yKx8=(w4D~SbXqbR zO0fkQ7&?u4(k&{f;_ahER|?;v@$*I$;>mm>DfQ^1s|l<7JL_{N`4D)Hl$ZT$Q4MSv zdhVXkW)4^wymXQ(dol1F;DLKYFh54`T*WuFi&`;vdyO_xBl)V9q@W)r1!4V_UMj;U z87ylW_c2TBdt5WaTYKKh^LJrJqUVoz-Y>}I^qlFd46=LD@y-jzeF$3bO0sljxjvA% ze>DYJ-S|*is_%-~+D@7V9kdsO#JAo(r6tu*{+ml8|KH^UgrT9>YWw9gIbp0q*$Tny z2o0(43w7JvG;B6ZRknkXYCbzsjm^_2Hg(oMrJU6PGkDqg=9;Wra_qDRr9_%L*cdHO zVjoaGk_WRRqU^Y00i6|*o50IMJ1-bpv48vR`W*r>Wi~2;+-O=YZO1=`Z%MRUalPL@ z!oNGZc$CE0Xuah;wul{qAr@@+-X0izwrn+Xwn$z>dWZb-?$>tbmX@59$r{#k)D2;; z0WiN;vT%jAMXM}TyaSSquK!{8+`dCq(}3^K_TT5u<)aWRIivA~E7tQ-komi1R4$*> zQ6sr9$SJx5jD`y7ML#hw{fgm->&ftJStnR;Cs|4dYVH@p1E*^yc3$ueB+2T8d6oF3 zcqs?{eH7wSMrZz+v8k!zQtcK4DE|%f5;U4U*y~%d)474oPCnF9aJ9`xyi3H9Pzi;EtLJL#gkQw z;r!821GG8$cQB^FJln=lxKCt>1rlVxA%rYe-s!36(c3IFioJ)S>0u4Y#=|)H_Z53O z6z$c%tNk&{!y1^w{^@J~oL2*2*0TFzxw&`|x~dtda*}f%(v0RaS6d~`PvtY$`qcgT z%wnHfna|u{sod$zP(HK7Km5QRZsx(gSmb)(%u4jne!DOyY<#($+k#Inv7PYKbFlYFu@r7YkTT~$()Ih-4 z)eq0Eo$8lw63b)+9`hWHxBsE{R{Rg%gd^Vf&Sc(0S$pM>t(!77>AEmvqx;!%)?D$z zI@i@ef)`2LbxLQ@isa1!_GPqhex^dn0h(m?!qAWd13Z+O>Pnv}&7DPqmyuO>j!8%+ zBhLCDJ5oEMeVR^eTACEbri&P^<~2gTbC~ z9cy6Wy&7(Q&8PH-bivdlbFIgr<6z|45E`@#mw1e09Fn(f^QK6ZCdH#((~zaoWrqE4 zKTXzfInBd1KWQo?Mu`LB#=dGMAqC!Px@!za(e>Xk!DlyYpb%1^E!L?iTJTWEw>ZO z<&%Z|RTb)N`{TrIYscSIeTU>jc7JW?8Kd93FV3UUf z?<@M>%ct1hN1DK1sYII)V$7biDRfya{?h1Y=Jk#NR1UdtntAeST1`xxp%nYnygH^* z=@^w|0hD(2c_Iq1aZCBJiQs?~xQPJ}>mO(H9-2WPQ$s!??w_&M2%IS{uHojEw?G6z zW2A15i8Cvkd67bHN~YjR>!Fm~Z{0NnVw$4Ow)D3mkvTnikP`o3Q{sCA09yP3_JMv) z{>|%P(6A2NyuWaa1Kim|>6Sm7<0i8xL&W*kq1(Om%?ohJAS_nWmjlzg_AoVdAyoW{x?;w}1WKs(A z7W4U%N}`MLD945ym_VsXr}17LVoe`uB38BgSxZ@mX})^!5X{$WT2kCH7!Bk@`!1ZE zD{XR&?f-|(PN*pBUOy~Z{K-(Mlx!zYA_8c-G{I~-m#Qe9DtPw9 z^m+#)^Q8)R7{8+ZFwP+U7r|gR1cL`U>66A*ei@HjQi%$U`1SOeABf7HVf77@1PiAP4U^3(F z<3tX+cL?RaD(C{n2W*Z(PWo@*i=v|$9;kIO-v1`kHpdB0my6zG($1hlK1rb<((;>;!)j&~gL)64 zgN3N`58T<6D(sH2rP>|0z1+-$oJE|cyOcP}kQ1lBnbmGf$|ERJXpOLq>Sm~pqpit{v`gy++=))pgb~OI7nOOB}2&AcRhG44R*aV!8cB?0P zc6WySXpiO|xp+nTtWY1HK0^m^CY9-5vhaDYe&=gbzi%H7agi!zBG7;7aL;-1b7()+ zKooR#m2Ykf=AOm4rC$T! zOjc1B7rBO7ef>jf&|HgGk0A%A;)Iv$uE!G2`y+sziR?dY;%0w4kUGSjHL;S& zr*EXU3u#GJ`h33_xg$w^$n|M4REV7{oubZp+3P!Cdq^g*4eYgJxb8|w9jSb-Q|;vK zF3~a-lD@^GlgFSaqu3PRDI$>NBf+9F}WP4k2mqe(OB659bfP7u0I3+d^8uY~lp zV`6!u8$e4r8p=-BPfJ^hH+Wk5S!A^R>z;&uFbNW>OI4ehiDNV*PY{=NF)pv--d^*k zOPYUnTb?ZJgNeM_Ww-H5`a)G|vAMP7aMaE1O@9R%F2G`4^snZ)i}4J$EkJ^2;=?E> zjb8g5WKN+bS!p^MmM!QN`dX&FqId8~5gccMWum-zQi+~s{qt9dBineKAzn*`qPNG&|KKn{rS)I)& zYH}aZIh#noxS34jZ-Tks7Fp95&=@md;g79H_srhqHGUVhAk4qYYKdUZ&WX}e_adaw zNO_R53zrO(-D*2jzL|P1nCIOSrJ}pPwo`?qquW4YfR1jLbEk7|;fKf-uMTrJZ5OV< z`zR!9TBrT`gR=d-&>{@6Ae{Gdo?nOiE-wX!_*~Y;uu8oQ!VmDhy}Ut96}u&s-k`RS z2mQ&2rcvon=}sm1E6Lq4vR8y-AqGJ!0~Rseoue!wf^}B5J!-4>D!{iFW$b(}WlF6E zOAiZMgMvHr#Jo-E?r6&%&&umkUqYp zSoy?Z#ZlbiH|lBQwuU^CZi*a92FRl9&!;6#hx;48PZdVh5^DLb?WRj$nT|app56&o zW@^9P@SPRli`YcgF61q)j>k26cgCSw#2x2}xW(;M`a1V5SPFTBt$93+;TVam@|q{ze2YDH_IYy%R5PG^2@hWd8 zH$RS7TQGm6ridO^LD;ZDjd!~?dg7+T9OKIb&U^>bv&5@RHn~sOImX zRI|rgvkcxdD;LGj`36V?vr;K$WtEtfJ@s|9CvUsddGhu;3Fe!K1dBRhJ3JH=BuJOR?K~)LIlV7P_mdWo9{5$sbBs|fuVwZq0@Cg z9d1N1eQ(H;wB~;!f>rMDzhg;+C8d8Dn5;gdIth!U)O#Zi@Yjd5>5WoBwCT)uYkDv9 z@DO>BfAzApv?XV=&@Ilpp=tTjq=JTe@8C|V0v9X4n&daq_n>n#VzSqo zNCm)l|Bz9+Ve^c>L>2h)6h>rld)hMO+#SP#n2Ql|&(Wx1Z(I*zm{(nXE9=C3p9*)X z7NCylvBl2`|U70&QO_Wn}TJ>k!UhN{;;nN7n$>u?%8jM z=HS!)@kexvZn*c9z->C2|C`*hLdneb2kTVikF|uS&>u^VpUe2n;{oS*j4q&X2@!!n z@z%NHJv_!Hi{=5X)4f+x1XTGiWk2!{1J};U{K+h^l?1o<8>~OiLkV`Vk?v)v z8OWw^H=!eOl>ba=Dr+{vhoJ}TGxt)X+#g3uc1@kN2 zTn{S@`IK(Se_&fRIrB6p?kTE+i%sQ;XzzH@TKw*iiK{Bd?ax1ZK-A3oiO8oF*_yx6 z*5H~uOx3aAYU{s+vb9c|D(W3@2#{Wk-(33heAq=HloxKFgALT*HMjmy^pvG)VzoA- zjw3={7}_js>Z|z(yCM|gr6HO1L$_Unn0Ytv+(pah z$AJ)A5eF3|fc{-UM1vP3O(Q+AK$^LEXrYvdUTSwPgE zr!GGOnL~XH{+fwrspK5Te98^2x6DX1w9 z?KcFj20Op)ZCI!x*N~^b@VsAsdFQJabC~V&#k^}jfy!5WOGhX(S}5rqGrtxlb3W3Z zRpIRif;LbX+l%`Tlr40XR z=L*;jIw8HNG2cv0tZ$9C8RTvv5C0K5@Hy<4M3>L3;>^MGL3V-=+*6(Lt|I-~(ls`PiZ6!|0AvF!BDkdP+Yg@M{ZhpB@AeKpx`y~~+pHswMl`i8^vygf(nuSA1B{F?4a%BK{SfLb?uiutw z@Gk6pH}J3MJb1tKFyzbN&clY(cV!<=ztj2teoKe6zdoj`^T$K+tLqB)KZpwi?!6C6 z(24K}-@x-C3gn>iEd)Sz++!G!DFm3UREE-zsj8;@`mi<) zxNKjB(8*Ga@VcV~4!s6ovbK|jLz38exoVIV{#yPo?!eo;SgTzqS=c^#HJ(eUVdHC) zdv%Mfr1B*5+fUdpR#9g(43#-}8PU5z z{8WR`KKlhays3K#w?F8L!Yua#1JDmRUR-Ax)#>d!FW9+nKkSb*xv4uwoDfUIea6A~ zAKPlF3BsquVxU<4f`RG014@(?L189H*uW%D^Hyl z4I!ob)p|W%4^K6~W9IB6f>_R32k|JOPTUp$)TQ?*M?8s{YoZ*57o99Nz}O9yGm9K| zFjB4F#^hI1oLW77VN0R0W!%QH5ice+s%ra76Rs1wLejsLj|5r zYKG@ak-%)=_o>^Tz@Kr`%P~kcxS78;eET}b44Z0)W!#wYRkLH7yde7u#qD+Fco5@R zp2mX*8b6h6Ib%R2`&cDGPS77vQ80f!FMMTJ531}EUs!bT$9oYRJ zTyHSYuyL+_vpfh5TO-i071oFE-adW6un)BFf}9)%{kMM{^z9Adx7Ye_?-}^*mg|fb z<#fE?e|zqrZ)b$xPV?W+8Tjq};kSD-D*vtSS@VEbpZE3O=0<4fyYmp@GqMb>X9!{w z@nar8{-hu~luS@7nD;(!$M2V}8V|lFNKYv?jUSRKj@;MwJCtnMXC=VhSuOQ^=Lh?x zdpkdfrC%+L<}FB-ak*A^i&}WziPomM9ZOfVeJ)5&Hw|@hGUVL>> zVb|kI_8Fc0&XaOp`u{QaF5ppC*ZzM7f&@h;YS7qX4H|obQVCXCB2;G}!5N$=6)#wA zrS($UVv8^XQM?2vBaGu%TCe^0Mq6$1Xj@wq@tz=8t%`WVd(^6X90f!L)Jp!J@7nK7 zg4%P=?>xWf|NQejFz>tHeOY_$wbxpE?X}nb7~5{9)7V-#wxKU?^>nQhO3=ESuu1%v zCzSSGdSXqhX6 zTz>T8>tO4BdN%CSJ*$<}D6R8L{rb_yPxos`v7rzB2K^gi{VNX8534eKLirzRP>-JNmQr zNi)S!>zHbpl14DL8cMBu!|fM_7~0*72YG%nZqJb^tm2Gw`lFuI=24w8X+9IB;S5VKkcTMNuWf(ccZ^I8F4p+^_8yts zwYNT~aqmzcc^qCkFx~xf+C|6hH}|XPhL?nnL=d70g@Whhq4iw(J+S@5(>a~`;YcI= zRKM&xfeZeK0l2>SQt$W+K9n1GgRq~QQZ0X=>)ExJfqFMWDec+Qe&opHK1D81ZMUJy z?M>>gJ4j8{tdg1PSoT7`$%G-Gz?AB_FDsgEUwx|2`S$EK9dCcqbf`x}ys_mx-hbtGRKJqx8*i(4S60gB({EDEMQJqX{(2&mUgb! z5(9gY9Xw~ffr)38?-2gsC%bW@xQ0VV88HjjBU^>Y|wBO!lM8^TNX2F79SAC0ubE*(0B(K@_4KAh@S+BI~Z z4oFjipAq0+W_ayU`UAZYk$2ewW)Rze6-HB?=TGTNswC8}Sk^oIL$8x8@QQry`ho~RnrRM=P)S6vmpZ6jlOf`{^ImRCgC10UnKXr`iV)SS@5DkjwhSnF(CW}Ys9G-%CnZ5*9B~Chn ztjv05bZ%g5?0`3x$$L${kJ~o*c|v;oh1D>CS9&8#uUiZ(x&Gu|O8(Qz1^Uvv&3B!* z2a3Hx%4vnm)pmJ(;ipIMyZD**8<-AN?g4Nk1P*Dxus==j5o>a@2d%2?KXO%bf2d8&<|1>A1Vy63jvKzx~=mi$k4TykLH8gOj%6~2G7 zq~r&n8Hj%nWqIDx^!~+d@iQMquB2iDILH;tK?V4jZ6+t7j=9* zcINZ$m%nCE^U3{1ZGxrnpP$z6nobvGz6E8(@%ec6<#5NfR3C48F_t@*V=3#&rww+(o68~+ z?Rh$pPwdYiwJaPK&U~4#2~kZk)HWO&>o*{meGANCMzx*)E7~vIzXG%C?K~<|Ed6m$ zs+edhUi25)d=?(8@~Y34O_)xp6-%-|Xe`IKyz01!DmvO#MSgVdW3UiFq7a42AGye2 z_&?*&F;sm@kEw`eH>6IC*~Hx(321puW7G-r1@;bO>w z)2wqh#=~q2Al9u7`L@-#TdMkT_cu@0Lh%N$QGCS872co*xkJq37iQE!UBLfYd(AHj zpRunjrc3`b`-+-%-u`es7=JTmEi+XP%Y5Kkl2D&?n1v$|8nsO?bIx?M&&D zX_hjPr@l!sxeH-x*fgsA8EWips-jluW`|(&fD|kO?iuMpbW>^&G+I<7lFARB4#F*Yq3vCCpOog#X zIk!9aX^Ufr0}*&G$_3!9i{-wmNq!i34J?M3r|wqLJdWV>*0u=!Gu)wT`O0CAb0cG8 zzjD&wb>2;mUy0oJiTem&-;`*2BN3kXhPge=WyVd)kNA)9(pJn<8;Q5Ci(NI_OY{H3 zk%{c)>_a-BJL-9K)%uz7ceSbm|qq&6ppZ#IvVj;quuB(i4#7$3u#D@ei* zJ9OARB9w54Mnr|G&?w+2&-b*lFxu13>~bN%R@Z1Otur3l5D&eCrnCq8XE-Bg!(MqO z14HmB`5rK59=NE`kLb-6#!!EpVVc=|707oa3R^_O)m9yp&_#oh(3pLb11a z9Za_OFvx``a`@;Gc0@&~kVvZ&^6-2NH9 zF^}I3j(fsC?+hQayd>F8?;~e7IhQFPf#-`)1aul+x-TSoGJJcN7KC$aEc@Z8&f=HL zg{Ohzk< zX9;P%O;-sA@&SuVht7ym9aYl+9yh!KM(T^DKl!#BD(o&o5NGsF_LR}?2U&!qejUyp?zbNj=cnbnzp9-AM0 zR&sysA1#md-{*Av-!)h6frF5p<%`rGupcTvB&bKLL{ zavT(XR()(%g?O?EP01l(jG&ebPdM`^Q=*X6{9)Xg>K~6xnWf_uFRNbqre+k8YJ8Mj zhk4n=RY8_t&kqDYG!@&nPM3u&kR_xb9|f`WsqjuVcXZ$dMJoGXJo^?d=8~k@&7z{8 zs!Fum0yPMy;Q)q!`&wu3p+BQO%|EY6ccWfYmv79eDWqYw4W(m z$yvdCS33=6(6zXNAGxPy{5&Q>{;gz!2VS7In)Chf@THAtQ5DoOW4)=MUIJM|Dmq zIk^B@{t|Wxo-O+@Wj}~waVbS&X)OB&x!Djcv-T7b@HUhm;*w!#VEc8fs{)tcjqUn| z(R2V&i!k5vuG;7{^;7fGd{r!_r;GOXta2g(q>s0&NpMsS9=%1If zOPg@%a`v11uI~c-Ztjdaciskul<0lg72e0r>y0@Mral7!*}{W0EeJ~O-QKqMVX582 zOD97+$rof({yy6sd#m*yJxg8!)k2lj^j9v#Tc=uy=_QE>MCYegNp`GWqt_tl=ycP zzfki`#%A(JK)fqjdx`hLe}($2CgqPl9uc)GZn>cl%qG@jUEJxU?W8@)q12lvzJCA%@&wXwfNH{KP|#e;_d5UOGLL+(F0a7R^-sm^%zS*lIl)Qf)&_;A8GmrA&KWY4ZF z{=OHUqr#U;lc(*Y=j8bR!f;0BRa+V?%05wYa^`oaFy8)HKjuM-6I3r2{%R6in>@KA zjF@Zh-i<8odwsCR3p$0V(Kn$f2^uVOhaF4=-q=UrB#2G z`(jYk++>PRHfM|NkL`l$x!ycT%>T>{Wc;CB_8I!K?m~I4DIOg3NBXLzCHHRs==9X) zRTUT|f~3?tTIKfQM))-OBV6kwJz*J`;d{F8KZ2mk&4VSZbjSK<{FZ~mdgS0FbpKfY z>2>Ze>x~rzyDwTnAiyTn+AoCZ_gQw*FJd?mWuLJ{_^QGKtO!3P4`W%@x|1l$D&5%7 zZi@zzr)=-cO{{4;rsfjAJ%3?S?zo1g;~VAPH zj=f!c{4_$LXB4qvNhqATnqNN$cW4fBd7?16MYV1t{q&S)%V9S4r;bbA$*hDv(oHrJpWUgKlCY9u;ytB1SRReS-G!Z9ecB87P zx?9O^&59D%vsYVD65Ag9b6*HdE4V?bq-rg*zD)Fep84 zn^N#C9b?2%Je~Pr6k;Q@&Bea17%eu+d72QhKtD{6UP?(>)4F?2V9I!NP#MUDQ}q$r z9aF*9joSMY?ZL8tX}8h3o8AlLYeANb(s-0G98t*#eK6J7sDSf;G_k`?J54wbFZ@s+ z8H|`o_Z==4q`#tc;EB0i5`G+FY+ks+vHm6EY51+uE7IOQ!VB`8$w2Sa^3+nxll9>8 zD@~{Pn()UITc14ImZ)-|nJf^d5+bQJyWNdmTg2$(QZZ1!SCTymty}z6oT)u)4{HI&k#ZiIieWGq?z$MCs z#;eea6xxaZ!tBK9U`Fi9KY(!=)?)WKL~)*zTa&r@WuI~f!P-G?hFwyYbelT)w{}Y` zdr0<?6K+_yC44%bWQPs8p)p)B>w8`a^T}4Qs6DDuH2p08MV(`*cZbh2_a)EPW(5yQRLIyFfbt{b-T? zw;wKLH~Xyn`MV*$7OOlTfaRxGG@1?_=!eoQVc@@fR7V#2!rvhH-v^Bz{yM>57z_Ty z&;2TG5tVv;yRj1KP~vnga>E@Vz!LM0 zjanbg-EOxD!NBQpoeZyB>R1V&?vJR~u{85EsFLy#&a5EnSx|_t_zD|B?h17}Hv{g; zQs@$_;ql>|`Qv_1s)=(kPx!hn^R4`n)??Q!?|3|Udc0}%oKsW-mE&zUDL=F!G5o#a zuGWu4)Ard%f;Ytv+!%`MmTnIGcD*`)**K)a?f>~L1a+slHO8Q0KTme^k(G#qtxo>g zG0tqy3}0H%Fu?3)#)hxbIM=BF|NW}IT^Q|uIzTZ>4Vr$^v(($krl*eOQ<8(iFSHJS zn@zYx_?Xuc+1H6B2(slfnEN*2{+=fSKNTWhxh-WvO|)rzjgRA_Q?_7jhWwXj$JqVj zsysEAn=)C0*5>Mu@L>br1!QDK%pJ5=i2YT)$V)4p3DCW8*l`fMj2c0zyWJBcB1=b1 zII!sQkEj$C#uZJ%y+p4BP%M_eeyX}oMTZ2^HO5h?4H_kAWorCTv8}8nDAOI(Q>Lpi z9BXWZc5X3k+VEu^q7+(SEKgMDP6rh@=4Kzq(~0G9*DC`whM{K@xj~5> zXC!jxQ~ErX*XtAc6MB-Z@odrBiRUMT81t^z2E;?p$8k(hF>0X#O2_f3iRCa>_9uu& zRh&~r{Icyafy$!T?kDi?iPSxb?4U$e2Qg?QOCwNl6`o}iLjo9g^OcO+=4JGPZPX9A zF#r-EM?t{`OZ>ss{!JXypL2FReL*89Z^qXt7kA#kpA4BCb3K7kn_25=XZRY4jLEU^ zUzgM2;hYqG*F<$!@}PKb0y->(Rm0RdCJ`EApn7V&scWwJ^JpWp@LQ1BM@~+Sb-4jn zZdSLE6Zo$J|6dVpq%YFr2y}C-1zzt&FnGYE)-{SOjBVuZtzS%66WrLk$bNt2&!*>M zRqpIAlY8?M92B>YP})M_MSYg0=2=j@Y5ZioM1zjURF!fiATA7C%REWlYc;s_kc_Ic z4A22bVJ?8unTF?4-c4C0%H)XaPI+Rv%ZvsO9S`;S$JOIwG(m^14!B^KoxOc1?8EZW zE8iP-9SjaP=wa1-Z@qXV@#h4Ez6pdu|VZ zB1A#oVg;R?_tQStF7*0!t$HjxShvSctPNlKA5!E>nEU&RLQmmbo6dxH2Zd7!@>Z=O zztx8Pik+y)O}W=AYh$g%Mb)k!)>e^ZJhWOvY=v?`p@6yyCo6M)^chF>>O8-MB}eZC zV1u}J)H@h{4vN395E<^$%C@$R<2f;f~I4Z!M7{6KwN@< z(`be}v3q3xnp$`X>itx&IfHpc(Cc3Xz4o);dj0D0zSlnqh{AgP>&VW%zE5z8>U!Bm zX`qG9aK~QOYf)JM{lDvWOh+USQ}srZrM~AbhJDk2;})gcHxVaTIU5my@-KWtz^AKT0zNi7@y68>L0d1H2~C`l?(vX_{J9@qi~4 zrl>GS1ghK$`-V;sU+v=`S>zyS`?RsWwEX~?%qiMk!;^p^BvhmdL=nV`s#upv7fs}U z(uNkF{|Tz+$BF#+VN6(W(wDS>PxeVr@FEn>wezUB39?V-(hKd4n|2TRKpjFN=9fvy zbdyAwdhZjjE5B@sK3!rHs5k3lFiYue`%;8`kUfggMYdVWRiDqBua`=?} zGfd=4S(htXLjTNF&Tr1X@`PK`FV(mtltL*z9{*<}HtHXY1+mNh_9H1>jPT&(pSaqH zeT-Lfl?{~XpX?u1tSvLGvcLWBk@m#@SdpmOE);$k7ZI5tiLqK+}G~oAfRs?duvQBo78K1YcAnJ-*o%%9g3T}bJRSHs)m2!;KW(4^7A*5SMkdR zpLNByi_@zZU2L@LW*;1&A797AHCoSt^QU5=EyreSo)n(jCrzs=u8>}mzEWZ!Ul~+9 z-zu)glbKX;rDGkIhy-$$VizS2Lgn zlMQGYrdbchn$YbI_?+gL@t|R+mYRB7O1IVYOLbc-&;9qUthP?wCH}2W<&W?^;*1)E zS?UShzK$I6?0c>Ke=RbNZk<3Uo=1;o(!e0kSrljc-oK^ZzcqBuB2p8UE8M|8AmIj& zjc_nLwP)eiya9h}F0O>+e?+%NscQ4_*}+dn+vC%!goWT^>b2haLIvIyu0p%EW*;v8 z+W4L-Zp2YyZK_ymfA``P_VaQP0}Zu0W({q`J!VaBeaB~qKB=;5F4}(Vv?{9bC)WD5 zl)AQ5>9Syu3a>FB5V>fdB+UmAKYA=Hso}%{urH$VkNy_SAEFHky_$eBYs#GXgv_Bj z_*1sOh?-+}L(Tcow|}))QeN}2$%&~Zqxx)ObTp&tu094O|&$yC0I@}+Z)x$BH` za=H`e7Up3419kk5WSYj$&dgXRu5$}yo6=Zv!tJNBU5(o6jaKVQ^DlqIQ&gbats5T* z*fb^#L^u9Cy}Vj0_(z4C>}FWt^8|+Sc4#(3;{ES47MDA|E|&gq)SNxzWAmHII+um( zxM$6tA#W6lWF%EE~cmX!x?dfe#O`*6a__crI-RLE0GOQF_SX{&5jM zWK*gs4m>8f2{2#NHTwsN{J5387KFa5T19xN?yWZT$&Iu`*8-2IfhcsmHJijF;|A)MjND+|}oP>S=u55=>SSm}+Q z**d(7pEmK2`26LI$z9xaqZAoXeZzPbb4M%iU zrVf;a+*RZVFAGvq&udlD~TMTlVH9v?5vJ`p``W(8;O^Yda@ z%3hM3$QprTV0k_0~D-mSz;Up{@BF+Zndj z{2fv~(WHioe6IjDP2n49$m?^t`$Uq<$itxEsJbbZKOVE&M~b%9aRSNS9vn|UAo5~j zA3~bCHHlxQUS}+K9HacG>E@@i7i4tNSwm%lD!jMxfyyNILW36xn3ehDjC zUr3YB^hoAKeE#aiDh5U~x7z@4{D$+*jAr3N-jy$&KLhj5oAK5DW^8`jD8f|kh46QG z(FjyffHLs+oc8aa+D}lC?>zFyb4No<3j`j_t;)6PiEn4qc6vtr&`{x3q=V#qc1xjE zz-J$h4}YkzMvojnKMWC}g#?=;vz|pnFg16*-B(uaDtPjXy0Z}wZrIJb$pRy`am?_7 zmskb*#bqATWOSLh)Lr6Qn&9uh$=ut8VzhGfS9)6+Oe@93Xp`m}Q23f;7k}mb>Ryqe zcpfZaa>opAQg9~3qAgsSb0fo-{*hL4r&Q)E_ln{Tcp29>R7CSFJF;Dm7Y41#c6Al{ z`JYPvQ{{iE2d!bWxHd=9X71NHQ9XAWkkl}LEBLL3sUw!|*N?keNY=gz-2NB4R8-up z)WQh<*XD?JLOQpEPaW{iK5UDGr~2PmctmH@aw@M0U#cs1Y}{qLkLJHkG>{qf77@Lw zIad)KwgEpx&MvU7O1~0L1k0*ibEYD+R%@zo<_l0__PJ(8wWc|{68_SheX#gd^h0eU zY_hO_&7lv5J=Ii9PS3h*;ZrqLUgj%GO=fZSkh0g3>%{tMxK<@Jy~-2~_sQE@p;>JR zt4fw?)u}Iy&s81<5TWL9%O`3tXeV`jGut;c`yz93H&!*XRPh+~sp(cq&o1YRw6 zy2GlHHJmsSh*CBnhyIs!sm3a5)bs}PT3z;vnFrYdf7~?>a{oih8DnSh4`d4cJL)-^ z=~tqj)1Vonp5jS6k5?`rGwR@db*00v98zfNqWhBaz}5) z{iv87-24Ai*kj7Q`}aam3(KQsOjy<71xvvy$gC#RGGK~)E28%^5*6Gd%xUp}J~isC z8usiO2$8W2t&Qg^FU?hFpMGLv`i=fvT&&Sc)>plY<8CVh1MqW%|p<%#$

    &VH%UqqdgvLtdfH!#4c85>c+w zdSVlfRsE7r$)DnhH?}=JY+E!tMjeedp*UfMqUs~|3ZUJXN~THgT`RrI>bYXg)J8#UXU1-l(74l}($u(uofJ zcY~B#`#%|=b^-eT)%d6%O{>C}Jwlt&+_=4-*pz+~V!EH#|JCp`Gd!)?p$zJY@~j!L zyo{t~s30?%IU};4{gq}hT+wQ6yzBM;ipaK>d11t>Ej;+oMt7%Dc&SrzwX6NJ6jbo7 zHw6i=j`FceBoNJxs~6K#!r+1~o7xG8!Z%?8|Cak26HKO>$5KJ^$JiE{vmY7@{r4=h zu!bfWZr=kr$sWyW!F%9qP{)FCBLJRK7cYX z|81>>61hLsX^t~0?7(Zqj8uaijHp-a=?*zl3MGxv^gE$Z?=V(3w zJ;E|2a*G9q=GfpU)3i#%6~46F(oU=|>v16zt^Y$kt|7eO2Ph#Xk>wu<03)PM@Y^7W zOZwc3zw|Qak5~s=*UO@F>CMKT8$5e{lkb4qKpnDl_KMBo5V+1@>}*HWt1Dv9Q-nyU z;J=cg#-0b;wD|vx{4DY3l#M}|Kg+oMzvj2xJ+*&~AaSl|53W39-rAK+HuOU#!koisUC{hpsZ+{C=;SOYJ(` ztL0vmmJUy;>x{jqu$)2aa0EG_4qd#THydJ$o30@zNjczTm%c6el3QR*BtQ5Bn9k*h zn{}8Oe01G%Y~2ad1V=1C8#T->J70(Z%U|vf|6{)rfr>CZf>;|ePKWP5uP3uLyE%DKzHM8iy{B?c zVO(AE^{zK+yWZ-j452NhEGa?*AOy2h@Xa`}K7n+L<(3HnZsNP96DBZ_EIb>wW7uJt zQNoWQh0r$MfpFCVnY`HYctdBAvHDIkZQ6C;NDc+=&A_k#mUE_l=Af@iSc zI=BYc!G&@b#C>r0v#W>l^$38Km{^*#F8Uy^Vbgu6Absciz~S{YLWJ?!Vb^=~*=;TS07ztPsm zH#c2aKO#A{S6d(P?-_jI3(%|0!$2=8G^m9c^&<)u`oh#UFXx%A>Ll zQ+lR()i!v8*`_aGFr%}W3guLM|Xe+@9Wm=D!}60X#f_%1hAw=T%*+;UPz1#I&~}_Etrg3 zv+uTMU9$n~4*S+Xy5Dx8XqwM6klaW*_RL0KO~U|T@jFe=vv_gjooLoPdh160&Pim{_K=ryg5FT;zQpZ; zQX+H?SFj$&yA%_bInjn7cxH>4nZi=p{ib2a1^Stf5zQX5k+dVAf-Bdu9LKp#r;g(9!*-BPwq5!Z zn6`-KvK&9?4x|;sba7K3`s`z`fD{wC`x~e>FjnB{W@q`5tbua-YBNpe|Jl&U|4?U9 zqQl<#tREJJiWiep;<>r_VfET6>N6tTUOUBM82PbN%*6w1XZ!yC0F4J0M&9I~<$;Bj zqRy-oCI2hvpj{y1e}&N^QWwMjO3ta+R{DKA>UstB7cHtvj{{WZyFcSy)0 z6KSr;9ZXSmXI0yeg&Q%@SqnU7zHKbvO}Cx`0bY)=N5e~kN8ts3LLy``!r9AXEUkTU|wp}-&<1Axjmi-4}EXF1u z;HeatBZwpG?|=Bf)C|Hv>KIz?H|-f5U$&FtA zZE|ltX_Dm-Pk%2YcE~|Mf}~5zW(h(6B$p6$CpVshBRd(U4L9bzTBEtsiKeHx3=H8W zcQ8?%(UZoYn!p>8Os+qgFB9!S>*3akHT_dhYE*CW^Y50R+&e!|x#Su((MJL3#lQUZ z_KaokG&iE`b>>0T>7$|pN(82isqsw!@`5z~z*O;9gW@2J7Ki?&dm`B7zd<2`{R3`(C3g_}K5^AL`ryJCZiXHvr}5&2;1c#RJ-$ zsd|MDa;v|ei4ReVulT|J4Xk77d0h~E#M=-O*V9U-6T!v(LS(pKDvtj&%6|%XOy4P; zOFPs(w^!-&cU7+k^!{2(lR?nBJw2qTN{6ma%SNv*xUpHer-c`u$(#D&Z%`Y;B3r4g zK9x>wbgyjrgs~4VlrL(a_f)%ki8HQ5U7{|MMk7Kz;u!O_-C4(gwtL?6aT|+*1knJ) zN_SfgKHq^szN>Go9Z@BQuQ04X;<-N^!3Yg|1RVdafhAQ_o`7z51a@Zyuub;Kzg2OAE{?dL`@E?q-SxKzBy-w>i{yLH;9L-K zvx4up7hiJM{LgqA z4Bo*Nn=2~5QPC|k?gmi6sjB2YQI3E`t%tpzlLv9-4IZQ9iRLEuDHkQeNwlkbV6>Cl zZI@DziI>P7N>XK6)%YyIq`Nmo2X#ibc2+kpY^e=rwtyu7Oh)2z!m<%W)Vd*$21;vq z;YY%wsTY%vti+!d-Oe{gOa0T`+o(=e(R@`nqjd#`%n+9AljBSg#tpPVH9q)AxyB_y zjn!^PQzZuzPO1fTRrcz(LF<-OQCTVy9G*;aFMyQHppuJAm9%|dAl172K3jphC4ENP z`;W=*ncrE#Q?2`!p7Qt98QpDk^VaGfBp-Kd+lCTH3{;m$P|ugk^$ac7vzML_Fki?s z-0J!@_)s zaFMMyKbUg=#lj&Lqkpy793jw>O_^^WW3S&!jyUD}co$)vNg0Sf+{-b1XVX|(&8({$O?`gF!O9CT2*j@GK9qc(U-S=jCAQqFm z<@WA+YoGKMZunsR!<9PgU{mTp7tX*x?p$O8_%WH$pD%wd}Ob{p5SNZ03o7Z94v>A8z<}40f>J;}X1Hq=ds_qkiMq!Yo zuSS=hpdPkTYbn#pa<*nR2xtL`E){mr0hO}e1nVw>^ZsiOfO<6$dG`rFZZs^q_%rBM z>#f$T#RF`~t_-X_a7T<&{|G!70^O(1&3wo&TkfMRc0B@~u~;kxqb-Jk39OB6_iSTx z?${BzDcG}K7E5RZHWM9V^ninxi41*-SVFjYB|M=SQ$TGZ-28eo0tF{Rd@hy6Y+g>m z7_|Uf9bWiFYm2<*S+|VCkeU}QnYGQ~RC-yCjcyY|sh{I}dKX_s(_>SEm& zDT~-zrym-C6w__N^B4|ivqWG$FJpnXb2Sk2y1tRQlE}W&jNe9$n?Y1&gQJ;jHQ~&K zR^forcmnvf5`4fc36qt7rtFW?)zW0Fe2YOn9ZFKfTIWFRfPX0#0pF*&@4c&47^Uf? zYboyFZt|YC!wD9l+kOuz5m7>>xQ(8O+AkLo8BWfo&X(+tYwgB1{NCI@*YvO0nikD+ zifwyx_h|luoAg#ass0tf9&2U8)sM9b^)kx`KnmwpX?qxb; z0JL46Ko_12smhS;IG7&5rGS{ZtF9K3U>NjnGK_kxyQ~-TRa8e$lXFz^(WB9<#!{v% zKi$KB4Kcq1xA;hfJ9K{uh1JD}y*|~Pea3B|Hap`iKAa!@%}TZsP)QVNP|5*n-b6y6 zYQU;mvdz;YE}yl_acc3lg!D^AC#TNw#N8#Xd2_r`DGH ze;UEAY=^*>&XJ1KMs=266*_cL$v%ip-c&UiX47xS#6#;6V3|#LW}@h#j!sm##9=1h z7TUc;*jO56fnwP$ZIQWb6W{QNC9N)o5=RUoFFQ~8o|QBWL2QImy#yiBMt_64@Ri&( zqUI>)su$A`ad^}xo0^-t-r7C=iuksBC$kHYhf*^%XFgjZo}2TT68HELN6KB^+`&Gl zo!Or$m9bLcj?o%ix`NJb!IA7llsEt#sMdvq;p|?P1$2P}ckWl%0s|N66|p|E54tVI z5hREpN11xpMK;Mrh1TV#>cI1LOQ?Swwar;NKpz^_P5<*ME0?F{Dp6^khoENmmt**}Bw$rV;M zcM?VK5!yNW;ZP!I=aQR>tIO+>+ZGD6{D6~x1~2e1^|{~0t1-Rz(b}Y9kgL$R+!=)W z*Se>T8VTHl=eoSxkG3*cIM7!L0oBWH*p-23^o54xOw zdopV);%|B%blK97yY9^0s0ETjS$@Nve4q4I&ie9v!2wqNWTD`_2S;^oUGOtH8%ho+ zt*0O#jbC}>PG;@)k{`S)?f#6m6AV*j)|x*n2s@>{7?8FmE#5_VL+}W&e)ACy(xByu zJ4ExP&nS4h@p$7RaYM(9PYfNV^!@NpkeIa2;#%gB@Tsj$tfCh3a85*e+C=&!%fc|4 z<=$;VNXTxrkx-jgd?^&1i?JKn7rE1**y0Q2`I5+;GDZQZ+58v=8ZvVmQFZ{@*mZWR zsfSMr?|wDbsF)viU*V`u9|_e^AIr~%^}Xpf-qXJ#H-U|d*%6l4iQGwJ)a^>@lWQn= zgpKAV)Skod2s9$xThtT`BOmKYe^@nln4j)Xbl>z{fC*=$l`rX++*OOI>QQTpyDhS( zI9f|Yeo`E$Z;do(w?%uJGZi}TM}iJq-ofSdTj|2l;X7x|;PB)*(fQpK`hR;xcXIqW^LJD%P97`2;*+-$*e6QJsPr3g zJMzMFXUmx7RI(vB@TI#yOs}cT4lLf|-&NIaR-*V9$swz% z*j0wl2K4J#`Fn)8~EHzv_@ zRCT4#dnM+k{W{a#yQDk&@oBL!u0HZZ^Fh(zs@fmWGPnX`b?%bsZUBCAoGhQNB&Ojy ze%#OQ5=XeFQ_mmVAS-1~vW^$T9ds>@ZJB!`ya#(Lhm+5popZuC42anP^i{;dPopjs1@COK0 zoj*t&%-<(UmXcJnOxk32IaaGxx*?8B+Wu*AwZkpza8lnH+svot+#Lc(4L@tsSpf9l zBNTmnqrxZCL`HEgRo8_1^J+DOUU3&9O3)lvg64MuqZgXXFf*%$ead{v(Bs!jTs{3+ zcnn4U`h@^d8Qp@~RovzNYU&12h4s8ILb5O(o7|Hqg)EB-dyrU4>m-dZoL3i41?>TU zzMIFM>^eIXoL=LD-Spj0H2nj@IQD)n8e`!Eagi$6)oht40D;SELR-ja^4b>w*Y`U-%xg zSnHwn$x1Z%?~757=Z*@?nzTdK2q4D#9s5qbeXHs&)#ScNHKK>}=x1^5qF8PgEu0^5 z{e$$Ql>WE!{PKFm@5=9<5tx6@BQhD`6fyt&T5mTMiz8Sa^*x|D35Q@)`A0n@B0mQc zCAKMrX6o&iQ|bUP^<5&zXV(OVk_eMNYDYLM&^bINd?(U_4N2nbu)0GxIj|fzfO}KM zRYt~);|x+k&88J0V0%sKO;hNDGw0~{xz>8a5J5AN+AJ=8De3#M+&9q#ysf+%Wy1~# zxP5N&fn2oshL@Cc48BX`A^T2+8~<13Y1?C)3XKu9`~J%-;EgLW_S0C|y{L@8+|0pE zslgnUfev%A`leRGl5Z4EraK!(tv!eP%8#guj5%VraOU^cEk)b-uqNeDDzs2$y+T#k zv*`cO%IKKW2UMhRs17>Mooa<0R0bVbr|qn}&+q>5Thu@SUeKM%Wq7n4sCIKQz{?=j zjanbf1Ma-s8(69%W8O_2jky;vKB`F-xW(%WfYB?jN3HkulfODTCPDE2OgVQEa1;7t$YmMz319>+o}Acxt^sF})4_Vq8TeoEZv=qPa-z zH#`H=af)D9KoKWOT1LM>s~8C8vjYR&fL6Ld+3QxV&mi4Pbr;$`(U)i}|@8BiS+b`|`Eca;uSJJ3r1#N&HrJ3=j zILUrL)a!4SMHejjW$9mXmD(B-eFv!OqvsVA>^YvB41f8WEvIBvsREHY98{@a_njMU zPA>PRMwE+6HD%ig{a_0DU)8U}Y_8z8?c~#+o)`K@pRU=)ALb~<=+oCAMVCFu^6Qmg<%EvBqF#NJ*n%4H9a zD9NJRbmy)V6?M8*v(=qwwky1_Xg$B$6HNelB2REgrRVRp8D&p*!m5~sk(AAN zP^mvXFX{6vr=L>#vOdq9rDql!b+LR$yC-epjftA|49=btt9o#+BZ|cVW!@T1fA|Vk1vXAPma~5j(HMWmBTxHL)$Zn>Xicfj z-QNXIjc)Ewn0BO%agSW1>pRI;l1JKrDY0$wif$_O6`gP&kdPv*xY4sD5eFlw;32y?9PcM^r&!HcLvcZw1VVu;_St<@$xSfTk*AqnKny`$>L?E(h#p^0$96zD0?IucCMeAdJ z-gNNpme7Utc9#D&`+6?>b>w1UAURlHm4+0eXulaxs*vxeKv?{y!QWBXuDXWY<;)0p z`O{`=MbuTe9hicb@wKP$z9~8p5ZqxjZp-%vhLK6$z;k9A-{v+3A;|%C69KokCGnNwVGNL; zac3H~kYoqTkal>GHnwUD*D!@WJqGi}?<3`BPYqaIqr3YD=CGI@PS$98ZBOABn)aYw zno1%!t=6zqBdw;?ZXLGDufjSK`2qJnuP6q@pOh1U=xaM&b6*Zl*6gER(DG&w6Q93g z4L^zO4fS>E1bKaDd`md75v9FT=$lN49LurV-M1IJvulI&so{=2ptxAx95gjdZ3)cU zGZUO@iRgwLPSqlo*h20*YSV=uwkS5bb}A##7QUdeI&}R0i`3;Koo8y*JKcIi-s#Zh z!O!Bva4QT4?r>;~J;4gYdx;ic$V#kIA`$0cvooD!F?a$jG|{3eou7wD854z%WU?Y5{dUGkd_qpRm4k!J?u+Y z1OcPEq&l1l^9rF~_nO$$?!VU$iaW#mA&=$|#D3r!_S$24LW@5hH|dR%=~YD_eIXLJ3yb6Bj0 zJFa1B@qS|cjB~IccZaX;(l2JYXNsL!Ip3}v4@US?EA0~2`%ph7 z5BKNSO;la`qzCr~6OpBvs!gwO_Ekt2DwB33+SOk;qf_36bw=DUXKI2n&Ft%T^QwXO!9P?6e#fVhGk|96iVzVG_t46- zl5I#>iw!pONs7O*LjY-vXBV`ChSuz#D(DUZTTHpuEk3KH)^5GLA2fSR^|ASy5sEv& z=Q`f;;eAL>biBe}kq=^Up)H9JF3NC%tLtYnHFbO374>!c1P^Q@WmHekIyseQj;6I3 zhKgE7U;>@ca~;pu1<%zy??yp3WQgx5*huJSlFe&y6KnD|9Q(uCaC(`Q59-%FnYl_h#^fV#FTu?v zHaL-w)t!LSdqS?7V8)g1hw#!&=eJHh|8}z{Wx2Znmj$i$WY-ZS)75vF+ZRpoXSHl= zJ&-Yz4?XKlp~qbvE>kIZ35 z&tDVuazDBykQ1f$V)>lb_$Z~)CaU#HizS>YErLBrwWIdbN#lX5d?4?+DlZfFE$Q>3 zyCojKJ@{%ww^rWLFTigiH}0+Ei}BnkQ^haXaC@mW|C5Lt^SEc;w}yM^K6#)Z6DL3> zoH9fCq1;9{^aaa%rIrPy94+BHkC~x+%aFekzVdac^a3H%pDsg}DqqA_8 zAP8{NId&+WbX!2IvvWqJN-0@&2Eu0&s{1u=99t=`$i3wO++ z18U&IGl-k1UkKT%%7+xxmlpEYXT->h81 zdv!Q_CL*>_gKeOM-*RyTu`%dils(2;SlpDkV7TKF8qyZN#?75e4_~Tl z8Un zqkj~m%g$ePnda6mYCM96^eY^+;MQ7nl>ti^aw(ovh`SCJZqcc_L971EuIC@^`PM$q zT36~%i-pC(Z)fn^9sEk#>$@K&uSc=hNek=9p+7x4|7g$j#Qv0C)dz~|KF;Zhpu=Fvn99lk0ec22>CjUcj%O^#0^b`;a%w#-sull&Zm_0P+`#K+f))@IKrabpyR5w#GCWC z)QcqCy!D^JC2-MPe*Z{X6T_&j_hzlZXCo-Q?myO07GZryLa&2Eh9R{Ux|$F7qY=M#v9ms`*%WidVCHi2aD< z;4R^f4@k`}hqnlIE2`yuc2afW7R%cKbc`e3J?z{AR&aTpVjdMPCr7D0&aC53RfDFx zjQsA4f#NcUEa-(82>N{7@stgfE#CNuFA8LJzH$boU-TI|&L*w!Rja~0LA3k3fiPm-%2%vwx) z1D{LsLbfNA-5J69is7m*yo>Uwq}sxJ_Hh0J-(m&oN2F0+Yl-vDuPI0(aC4>*YStF_p!rz2U5x92&sz z-0!euVafK6jWgHH9z^Y}d8!%BkKNYpOA|z%GN2%UiAzjt9xw4#D?C zzTVJ#3XeKVXyRd=m9mx88*V~SmG)EN%3@TFJ}Gk``Lu0t&GOc!ZFmI_Tb{^n&pwlV zI)b}kLtH1N(B3wnoZXJJ$O$m43A`Ln85OAWtj3nSnJK{r;EA0{gkL1mYf4u2%zJ#uU1F=3t?vaA${K89sz-;_T-;8pGwO`>7BRDQ;VMLeP=-Rk$?!Xg20}C3pm9TPkJhW!Fl__S1 z@usno+IycY(n~%d(#$+;%l=;ad)0M3Wb_yA=oFEq+oUt!!DFInGrnA_XqKPVo~njD zlif1xqrzWQiRH}9H4FqeDDq4{D=Dd3N9zXFL6g!h`|IF6~O zY!(+H{7U~~4LJJis!xX+%-Zf2QIYNV{Dgwy-vYIyH6YNS1vkPgCqF$8BVb9HpQ0E9~bZ0x4L*+&)g=QKa*7LG8X4LJdj zbV$TTq*o=hZTiXXFw5MQ6TL51zfgfp3FW;rcvoR_Jz^DBxcvhf;-itB7R4ext(lY% zUT{7`P^i{8P*I(=>UAu6P(X*MM{EU=jvp^@nU@HRFjDHYiZ!ZO=?Ex_ihpg>4_~E{ zy9Gpnk*L3OtDreiyC41zU3p7Py3;;pNAt08jpZ=i7t6Gi1vMu_?|aWsHa}$W{p9+t zm~Q?G>v9Q{68@!+PcF1l58am5snTe&a_hlY3T?F*f+*QO2ZPYDiKymU_Dhcj`N z`&&M@*dQi@8`QK1G;@k_03FMWm)t?H4;1*cdB!KvTbQ>(mtdErl_ zP^s6)cN(8*GD=_FNq6PbQb*U&s&q~(cxWs=j43@tN)NHp!(=_As$le)nKrarIk>YT z$zXFm(I5GyFJI#eLoH<0g*zOnKCH)4)BQx8qLQU?UQ57fFd3IC_%2&p2Gpe{X;kWB z`4ic8Cs%`;NMtQf3KvqB(A(gaALpr{)=f7%vNWk3m-qMdFs+v!T4EB1O!=0G9wNox zo8FTpMhZja=AFsns%eAKLAc`>8{*L?GXqLP@f_VWt+x0lqpx7cszKv>@zXZG5{~8Z zeaUUV+iSKf!r6WKvJ8gY6Kz@%?l{xeKDAHn7g9TsAIzz9C%9hwo)&!~CJ5+OKcv$8 z^P}fK)C=49bEQ8^ zDnI}17IqXvt5Cu@*181#g0@lNF8)agw*+5oC#9kkT{U-fZ0t9V|KeE0_zIHanl6ND z;C{rxadw%sv-BA0ka9AKS*hvKImhcG290;I*rvM%+WEcLw#Ubwj$QB41tjt%%pHV_53Us?ud1wO^o@czk5M@&_IQDtzG6*mly%MBSp1#F zNjt#R#fV27gk;s>&~z+gJc61!day=k0sXXS;bbB%+L%{2)KPGkgji_ooR1(OI!j zFXf27{T)`uhrZ7p|8Kv0hi^OBVy2S=Bw*&+5D@Qu1@J1wDW~J!vjIktD!RV-QF%L0 z`2VtYF7Q!R*Z$9t0S1YjsGzZ;4sFz+RD%UgBjWEKPN&e$HV7+E?0!YIxaSzQ`@ zuq!!^8(W!>xpqQcH@ZrjDsU9z_K@N+QD+5y81I@T8fEb{bcj1(u3^8_3VhQF2bmL6$f^HOWxYXb)vEiH8m)GESvniHMmIkDiV1&Bxv)H-$ zV(q`}@ASbN8Y1{fjN12X(EZCd)$k?}cwV#b+;pKH+z;xD2baf&zw0#Ltmo`d!t{)- zg-j*f=kfn3c9u^H5VoSYmIS?68zjaP#ud>v(}!46(e#${COFH3{cBq%d=honlO3!B z(QAn!#TBG?@!rwvaoLg<5vtY+2QZF}rr$WP&Ge((fcDso$0^{nPB=JDzwzqLtrNOZ zH^&~h&xc3M`QwIo;JG>o>t(U@fj$fxH>=-L8H6r7`bUoslKau5K-;^0=vVs9^XQhd zeDKlH)+5~~V(oAAY13U{HO}(q25gAkMH~I1t>Xgx4&t{@bnUp}v0SekOt>53r?C~n zM3hF?dMltiyhikEmL8c55=W19Q1AfFuZJ<{CBdRs?1e44pW9Ulol{Q_-?^UskB|aXM(ips-Mz9nk@*$}JySKqphCOp!xk2i z(Z`-=)09K4pz+A$*eDQMtB&~|GIiacBBpFqADktf z)(_|gF9LwHrVkn!r*(^$(}yxa${=VxO%57Dg%|e6jaI1?OkigY)@SPpxH<{L?Y-^W zz>ha7>)gLj$d>#ErI8%J6m8!htQ+vs#MYA26Pe3UPMubton*hLbK40T){jqWgg)(i z`_vA222Z*1tqYH5r&vJQfr;$bD0^9Hv^7}m-2A9|u)Oy0B9L=bKlRg%nl*a@b9^>%}x03v>!!lFxaF zf?MQGAJRFi)%yzxMGM-W$R7WP)lh|OqP%b1eJA=*ds|x@K5)SY%P4|Guh=%u^6_08 zw-EC!p57ivem9*9#i~C{y)C7W`=PxVu_F-O^QQZ3`@8+xbN#M)d`fiq`uL3XQFnvp zV_@s}zKQA%E;Y|yg1}hE(Kq*pyHiSec}Z7&^)s!5t3;nuuhX~W=b(;Od)k8^a9`{A zzUAZV*ukqbaRf)n&l-!E)#Bn(Utp5HV`iEC+FWV4t^xqBBZky4och{C=!@ozwDjzJg*4Q|*eSm|k;f`b}w@ z#XZd%;?=9?Uvz$U)G)h0o}b?zotygD^@)y9k(1>~dBF z`w>aA@sw+xn-W-=s9u+>$D^@hi`hKG=RSqPmQC^bu3q?l_ha4o{y1Os!gmNCJ;%su z>>t`8VCgk|oaGTNwh8uEi~q4?UorpY|DKlJb$ec@e&M=*3v5ULko4YQ%$cy4fI-9e z7Wf^zii_LZLg{w{39bsZl%h3Qm3mvsf|ir*S}brODBfz7BU@-B1oJ9~Ia)}h9e1nd zEzIj4{GjI#ys7s#Tw&_YV;kl}cWsgj$qVa5+hu@wkAd9@XNrIShSS0)o`K+Fe3Y>)LHb zY=+r8)+*gwJ--U-P*?84lnuoHATfL;H{Z|0e%|BhH*g;rBTfWZZ6ff~1RcCSkzVFz ztgYWpBfX*US2hKkUGyJFJ zO%!*Adj`tR@cYW|w$C_g+22Pzy`xm=JWFK&%PZ}776peKcO(n(TT-dlyeTt#rEgra zTHRQ+Z1P%I>&&HS(Kjav<8%YU1s8U_2WVkSUjse4V~K9QY$iu@U1IGJgnIJNl2594 z%_WKi@=Ue_nda$v1AD}86e*Y-8;(ULw=S%Mi?Uo_KPvMndu+Igx#Qs)eTL%lL+Y=d zU&_tbW9Bog`K5FF)85)(r4@df7yx}oo~zz9zklvIPVcZE8orBJ&aGjJ>^e^HUUp)j z18XrH%N#TAoMfM_WQnieKc}QmDy(-xm(=^L0bP-ar9pgGu8B%`pQO+E_Z_btGM@?J z(GpuAa|tq$?!fM!z??pTc{jg2O4u9}b1$a%6G|=0=OXmSVsNh$=cBnOm9>%)I`<9fEGsHIwnUry{!Tu^<^6ZiRvv0XClY^ zGeVY@VLt}$yW_nltxM}Tp?A4I<55wF2T3emJ4Kt4{k@31C#an-B-}4Zwji`hNMPxv zkLE+ZrU-X(Sy@*V&LJxwUyZn2ALA?T-5Dt~pCvS(BQ)n6=|ZFhG!$qF(LsTGgbk3+ znG&cRkJYh&`?Ry1a~Mt(suGnfDo?)-B3EfMRmq4@ya6VE9rh1A$DCUq=F0>oir9|r z?)bc&e|IG(h>5_P6yP?9Q#n0JRYZ}lYO6oIaYlyBbZ6yt*neU$!s}ReoLxQ<$|Yaa zncRqTtOr|c&kNkJ?kp9*7!RzI2;V)x9ZCL=76F)0@3;$aTg#j3XL@YB>nxn7lI3naMG`Th7)K^;APhldFuM$2<~ zcpL%?=e9kNxRGrgk3bJRJ!h$zQ6-WiY{T;SbXxQIJCtU}=Fqg~pCx&7$-UDYB`;ES zdJ=Q%CzvN;XsM|eg{SA>FXM~{o?(o+PRknk`Wv}HA!;UuZ_%oZLSEUUE2)bQh`0bJ z(tIlAqpgrKRpG%Yr${OuuC%;H=l!q{5gX4mO28|7?b5+19wAVi?cHuSfC0prA%cidVR>r_KWY?6kEqpFUM)stFJo_xW$VvfTq0}W6$+CX#}d6Gaku#$9yzl?BFxFYkEXQ z0%k~RjrDUcFbgjI6n|hZ$;k8fig&%@JLrwyd_ImgR`h|Vv~QMK zL-crB9)@r_$sfnFDHx?a<~5Xs2$#2MJ#$&^xt0;K_US;YF__4fA0xh4uv1VcdCKEQ z#&oK}kogXa-Tw;Pcyh36m$i1VytcKbKW{K-CI&1zhSxOp0qz?CtLS&Vd#yyH3Yfoc zzQGPth9c5l=lQ$%I&Dq()CS8LCQ`xUIjoy{oL3OfphwIW%-8;&z@LHnc1O{)gry&i z_UC%7xz#4^#T;ppO*Q2}4j;vvsoHud{GJ5n7$e(QD!82UFyMWs`DGG>jV?N8aCyqV zmscnM@$}BXIa7*~AA&kws5XSg@{t%_d@!ymd0H1rQ^`}+D*+ac1`krpGV>E8ZH>AI z|JQSVrMMCMzGnWWN!i-bVnsy2^=tbh0NknW`1(%}^qgRMYHo`XbA3JsLC7KJf^11uJiV9o6yPbI{Vs^NP1{FQN0XoafzP_!zn-vl9T zEkddbA@gmPQrumoW<&LXj*fq|M<}+?2d1I>Wodoj!`w^_5a~k~Xi-Z^xjCH@iA+g( zM^gd*;;-o8_(Z0^=r3|+qKN&tp)31cuIoG)oOgWF-Z1*?>WQIwkhEjO$XR8#PY<;@ z!y399QmdiJFCutIPnWqC3i>tvpJg@C_`bdiues4=M~T-@N#w46m186p&iC7#iB^?M zKu#}yE0He>Vhn-z;9IzHjcQS#A_DnL0{``}K^D9{Mp7xqShZTK{ar>rMLt^Cs0y!|AT( zMCa#t+@;3WEKXKG%ob79QO^1RQ&05Xe;$v#0Z*t{d+3SOi4;4|ZW^d9Ue<+7bg$#~ zk(={+EHCK!Z8b>eHetV&Zp9nzNzQ4Z|kxduaCmZZ?*fw&r8HOyK!#Kj83pp#8 z|83?eis$ADEq!`Lrfu8&RTWvGmWD@_nO~}8f|3sli)~ybtsi^7^cytk3GgkBbnV>i z0`ypBU{m$yofho)ipDi940L@yo{iw#%0U#1pHj{Bq#oeEf}&>+U-QR7MdEOaS_h9* zO_t3U>yjB5XKjl3-8_uafG7ZnQ!kQxP`S}3aw|e-EGWa2EgNt$tEHHrghKF!Y!`!s{S%w|C z%etTCfs>om{Vb6pe;=Moj#=+WjUE&u;lh z1gkc49b}x$P#|w5R`LjYcu*JEnh7qcb>G-%?(LJR53yA8lS;5by%ZkEoJ3k;i5 zF!`G}aw;EWf)#vIoIK{A(6eau3CXRLMS|vnI%u9m!F+JXp86&4ex%1Dj0n-+%&vr5 zO0l#mnPhoD`Jo2u1UG)hhwU%oDX-XO@I{kmi(tksAsjPx75rB4Tgh)Fzj%<1uS%A{ z=$c<$tsykV(7S|9|I=+F_>j5d!#!?00dLKI4sk4R(y?9hZ8~_)x9sKHdk?+j2!YtK+KzLss%GQHHE~SSq)?Dk>J)tO5i-AAYOPwTW9j{;NIhOU@2HM*W^y0W{?tj9jHmZkB!^qPBt#{f zwWRGE*?`#oUyiy%kyU#H|0{~ZFjvsLa(gJ|io^(TbSkhT8lYo(-n;cDrtP1Ol)(6j z?i3jrYJxEnY-cQy-)UZ(4v?~=X8}cf1MBO+|I+Oc@);K?_@|r;%@deavqNMq(hgCK z`4B9pz33$7ErH(ps{H!qNR>WiM_<{hc|G7OLd=29nm#di&h4w*moXCNwC?tG+|m)P zdf_^>XxspZg+WF0=F||7;8P;-GB}vSFuFY{EVI_sD>B0fX`Gc0GCahgcf|ly*#Sq1 zoymY7lAZ*KpFjq&XC9wltK_Gw=~vD@XeHlziN8R!ULK?^Z4aQS zVb56S)V&zX*7ZgDAdDu}QV3rb-+y}pM}?qpT&D26z+FG69W4^#6w_J0p?agURPs%F zf1gxiO`lY(NJY1h0v9mi~f$z+N5yL#mU6rhS3mQfkA?-bU6@2k9u9DARPR9ZlTD zluTE3sE1*JsiONjdHAs&UtDpDqY`Mej^cjG&Io*%X+>Q>YJ>b1_zr`n0BIcnq1^frtD#O-tXBMDBXYtHQFW0GJs0uZ;HRp$8Dzb zHKAhMjg*R z{|+fR>IzN1|a<3k`nl^{{|g79Xhh?e?>ob&5cGgKJ7@I^*^T@G7#^z zq`c6@J@992+QT3F+Y^6o$4%15p9_H4e}O;q%DeGr6V?d5@duW}?hO_7Zl|y+S{-uN zJI%L%e0hrE5iOshh)3@u$IXLu!cu^H5u{}rON=m#4t5A_&v%C!BG7@FpG^jA^g_F! zXtkDOt#C(Ls+lr#JuU!N*WbOP=WYP!dQ!Mg_s40L21KMF>@+tiY4;*q^FJR&ZZuPn z?}g}HZa=^A43>;(Rhw}T@`l&x&HvhA`aH@ zRxA-V0&qz!9pvXe;ZH&SfdIbDGZYO@Cs&5)_dlm#fBL+gMcbI|GZFI`Xr7osD0&dC z^rs8oMB!)#OMysOvv(>m)ly_P&-G&_|9Qh_A6i%PoX>7_(5DI>q1K`qm~W>g2r_hJ zr53t)C^vQ`&=)Ne_db{N-HFJq`+-sN1h!hU_A+tLl4TpiW;lg0)~YaJn?SOq7~(A@ zs?1NllHMbQKRHf?CH+>JT{gX-(ri=0ef_fBYa~2ABX3{aTmEnltdK0=u_pGWzfK;_ zZ%(v;M<{oiH}|!wI-%+;bM2R`W3|L+^9|C<#gWT9a?^nl&j0JFLI0HA;3bQQeYi%? zFZ$0U+em72Be|L%>4J#Uf_$b!j5*dRxBb0v`ru)DZsfVtIu8B_tk zt%LCJ*z|r>l6~M&oaGH6Pj}%o6Eeku!d5*eD0iXNWSI+81&~JCUTdP;^N>4(cWU88 zzXkjHOwKiFL30JK!XecFTdDu?M~uoF#s_^^)kOFSC)|Tf(oD*i&OGVFgX#6*nNfFQ z*t~>|u2*y&MWwu(U9PJDtklb|EL|i;jM8sZu_8IycGn~nSw|kI_bT6M{ySr&eld?V z=IwJtqdi#AIU~Pj+u2p(A8QCg#y8+XNV?eDS8`Jr$4^x&=ax#FBcocfZ#|M4g)j}( zvx3ge+*(;=`9L%4c#D|C{UbUx^;p?V5IgT8jl{ZuD<%*sKEAH9SnKBE?g>%%+LDcL zM%@XasCzLce)nG(cGu5rH+=_eaG$_#c;=EfPdwPZrSE{1K<1LL-i~(GcgsZ2<{&)AV8WuGI6H z;7O%?;tYJ4-34+4yv;9}1^5z;C1Os#Sn}uW^6A{b%ZQTSfSv6aBt29V#=frln?=bB z<3vQj(+6Fnw|xa3&jfFh&M~!_S4dJ@R2E4JjvQO6A5bNUu-SLCPG5GK5A>@xR9))N zyel)Wkw>D`Z1NIe^Q2#THNRLwfCkg)d6CmvEJ+CP&XQ#o3ehF2MGAXpF*Pi#b{HFm zIKr>SYaT13i1Y)q%&$apr5F(V4xO;EgOSNU{B>-d8c?248=m1Tvj;bF)!-Slww~hS z#Vjqu@W{<^_maw3wz0(gv7s0kHtBOjQQ@X$rYJeQTRw_qJSuyBre>Go=9rElfT7x( z!})IrF#p~V5F(pj@T=*FnX?Jpo5Oz!dnmIX%(lwS+yLfonF`D@7sGSAFXr}$H@E?E z0R5ZvQz@#}nf>$~kE_{sq7_JlqqXb}73;52VSZ0* zIa=rC;blLg#_Z@#bGy~=w-!3HkfvE#qc~u9dMrvg&drRb7nid@wN3#Gw?)Rf;b9lS z%=TR00Z)*u4}-VuZ}y$J(H!&Lqepo+{uiRSCxU>T*~!&CDBR|O`%QQAJn>k7h{oT`j*9r7~HM0dN?ox74l34P1`GhfM1QOgUdtEyv#hLv?1==}Q+7e7#xQJi9tuft;|yDcYLg`4 zpqTiD50ulvX9^6Wz$N*fbu{;&G6GDO9#cBduo&iTf)YeV3+gNTZug%%O zHvRXm+zUL|MxkGW5~y3=ZLlC8ds8`Ja+MlkQ03%+Po%vX!Bm5C8xo?kYNh#8iEenZSv zMEN0=p0h-8lOU}4w~}SHG-30}Zh?gjt*x`{qTZC5dn!ETX~=9>8NHT)u=^tRjQM-T zIGxb^+w$`Y4>=wc3h?N*8}?Hv82Jjvllq*K$RnMU*!9J@)#7~nfhWZgM;L{ zL!1lOO|*q$T=%E5nhI)f(%0CYWDh^#E=&0~U)xRjZU@IL8P;v6J9YS8~@ARFE+IFWI1{>df zP{Z@%Y$-=^#5TWUMnN96cWT4DJ1w)kE$a(Ew3A{_@w&d0pOj1T=Xa8|ti-TWQ6*2e z!E+m{yK9jWAyW*}a;_%22~h&Kcbak<=alH1=jfCO(}eD0qUm`a0~CqCO?FKPKu(>>yRV%bS0k|IN98E1W1-Py*aspbH3rx^%57>+xi;dI>1evWL& z7v5X$>@x3q0e@YQliWi7c~J@@&pXRcOmEq*J*o`j zV0O$HWYv8Z{Tlt`d_NGyzv;1r98#2bA z0vj5k8-7juFH6pC+CME-0#OSyk*Df zyvm(sB9s+HnhpSkU(;(m8cIzKwE@QnexT0s5z7RInlC!dKjVFE)!Q%~&F_-rqs!yj z8!@wyy)@<*WK2u_t_~Bu2l?c50lwp>YDY~nE*g`?ZthhJ;acI;wDR&g-MM|MI46PA zX?~2ix~82E@F>(BXcn+e%hg(fzu@gMz17PL0bTAkTU!$y(tORcA)Kzj$nNswRQ^sQ z9BZHCjV;IzYm-MuT9f5t&E-c3Sfm&u#+rYMR(-TM!N3+zRJWs6@sm5jPK#C!^?F$Y zZI=37^|l87=ofiMY-+Oo5|Ry=e^uj;vPs`-=q+NR)WJUVs952VTE3O9&wbVMpw4n; z%A3;M7Z_}T9!K3x5~xDC!@T-&I4nP}*4^vAYU3U;$JOoFukwjtP9t9nk3VHGqAYk-to&CaJ zclhy){Z>!6_|&B)+`SwF*)3uN8NEu0WYy7+}9m;HBy` zU#<5n)Jjl?Lp*F|UN8BAnLa64QD z5w9W|g8VVq%aUT^E-p0mlcX2cO(#R@Ab(?6vGW^e;YR4QI3Mxi#ck zI8(_5*_zJW-^l3RkGkHp0!3lG80yM}N=V-PDD6itiDkzf^teQhZsmaRG|otIdEQ$i zCmidX><{e>PT;bNEBeII$m81@%Zysb2Dq-X>j-waTXiO!sD5iX>NP(cC`&RxCT7b@wh-at*7Fn zR8w~yGVOv+s_!KoKSuuW`VHfCXuofKD<`Jx5O}t~8Pu9XV}0}%87m2bpNQ*^WoDsn zsy(_hmMM!@8$2HBoeNB2%y4I^PK6Vh>&p^o;coe{U>kT9gjhogc7-FHQQNgTk*tH| ziEN7ak0I&Cf*xkZv$HF@>a(-30`0i5yyJY^f5=|TdOn|&34RpEzYlS0yZk;VvzT=% zQ)%38&x=>Tw&)*(1ALKkJ7ss@quhW^y8IOM)Y>&t2(<^jMJ@UGi9d(*{y}#G3 z`oOM4^{Pc}tQm`&9VY-(Z$I+d(V7pw;=y)R@~(LGjzxXztJf~P3eS?ouXugNw~8_y zFMIQGVYX!Fh1uXo+y@J}D#3Sjqz;Qvzd;jO=Urb8wY0@DCDsBz)T2_K3MXY{&aFDxj%O^_r(Whp=J!J# znlO{eQwmEX=R@9ze93#~bZR))?`d)nvO-%mRkz zo@X~Jz|(fZo3`9gK8R=fNQGfL^;4cLF1ousOq7B~rfIXFG&oknV|zX(aF`sMIye6- z3nVYsu8eW{`O%)cYCz>B&@0F$s)zLW@wjpGI%s^^@hR4xX{ zco9Hk^$J$epn@^crLa;BrkOoHQN14rri63B{`%?z&MkYj3dW2;_V$&yQY6iCnx%k< z;akz&f|aH))_d8Er5dr_;KWOb;kj7#Gco4^LL{`u-DjNJ;+EZ?T|OrsSd*xxW}0qv zn!{xGu8@t&j^|~wot=}Vt_ojHu-ULpIu{TgWF>^yx$Ot)ihop<2$)zk>(RZhyh$Ua z?hu!EP$F)jfZ#jblbLu^p*-jnqK=2pm`Mh1Jd3}u4~>8wQl>~4ESDf)x+pl6P6QE{ zYL19iA9QYQQNz{GI=3z)VJAXcqTm2XAuX^6fF16@oMs0AMD#rT11_Uu05~(QbZ*L^CcCCgr4p1DX0h8RF z7!R4T94P0w)~&z~#)+ZgK8qu`C)*y+`;OlV2;Rr%XBX}Ome?=y0=K-Jj0^#3_F0x?q4jp5hoHXja_6JU(DPl(1_vGv4EPKpu$6e3nZW7rAT^*NsaH#&^ z#&22B0}LTi0=L~gdj*SrT&++V4@_VSn!p-9I_^&B#3z)4qb>#nU4k}Y0B%vBotC+} zfud|q7nj2091$n52O7;qKhwP5_9UO=VV-YhnQdkQZS?E7r?78=7v1m>X9pH7{MZ6z zCyKg+$3||*eIPQz{Mg{(8mLg@7i4x^1ph}69S>%LNlx+9x+~2CnPHoss!HH|hviZW zb!AJ4=ulElm^{_$P-`B(9+a$@X`X?B6HV}eY*Yu6n;mkoracNq(Z8j4X;#p{)XEDf zmbq=2o~t*^8wF2meTzmsi(|6W{66{VMMVRgrQ1kpi_i9bv>9DT_eIqa6v@6`kmx`% zi(AA(n-}R?_9CB1YjmF~&(5vDN;SgW*~I%9dUVxL0?hnCFDwJ1d$v991J)z22c$eG zzm{uWy!B1Mm7}@-yfk%f;iK&x+#mkwa<=}|*@a>|6tIsz)J1yNS8{Y!Nok716aTL7 z9hUo0M`Rz}-H#~|?jSGlceu~>tHS4<=o2`G>jw56x%2F1!CHNy-B*Qg-n3=z%{sPI44KuAh{eM#5xA*@K>!W-7 zW7)@=fWFzHbA#-|I<+u=+t*j=dzBv=hR!(q0}gIPMm_iwFwHwE*pMQ47N!%w+-D>o zc^jbyY_*>(l`}d@$Tu5#&qyyp!3KR44d`lsrHHz#Qd-%UG_BwWExbLsQKl;r7* zxX9Fd55v3?Fu@Q%ZdFt?{?vWu!h@^SoD2w#tQ3F*!^Qg6l9)lt7rzqVQ! zQ_$+u+qK=m(c7AQIk(>3? zJ@wh(%QZqGmJ=>`(kO>wnHzz?nO(~abpg{cvCOxbnVsetV2t~NZM|vXkghWbVvre+ zu4Zs4{Hhd2XP__|u)ct35ev7T_|5w5rO#H=%w-|I*laZc%= zQ>R4R-#sjrT_I#dYw>KY`z&6k3HLP$=1%GCo9CnAZb%(2tVgfEn!M+xdgc@Ox6l`< zP+7xTN4lrmDO9R=d= znWxZrb0GC)n(%_%Xd3R?qiIB`ve=l})NfH`W%Aru`W&pzwxpiR+<=e4karhbJ@Fqe zmjaz*eA716#_sI+i~8yAgqbNZ3F?A^mvsE>vCq+F$2uzx_2{p~-vb)9yx6&d^SR7K zVmH*mf$R$$y8~X;eHV9#djn40yED@ZYB;(V+N2Nm!_C8Ke$uAC%HP;`lOwfWob?B^ugI?eJMyi(vL{+7d}g|_!!qMB zcb7vlXUVnYvoqsiGx3Iqriowy5ZDM@+^uC!^g(4Y)(ymO2|iGv`rV!OlWWcOXUg_C zMVKzWfrFE%;5B@qn2&VccZ%taaFe>zQrCn2+S4T8xk~eYFTB@Dyzh9&qhq#>8oH&v z*yclVsrJ>UN^=E$dPu$TI!57(%FoTs<$Le!>6g|%ZANBL=8_~1qC8bEZRIIBDE*te`8~*6J;%~Jn{vM%>EDCOmwSIrQx}#O1#Ja>Q-AB#)Xlw` zn%b+WC%T(T-O=%jL-89~A8%xl>8Sgp&>WwnkCCw|v>Rpn)`ic7x4j`Ep+*yBC8A0t z3g@+@Hkl3%AnT^r$^(Y84ke6XKAZ4K0{?QqeB&TF#@C zJ+|m>r`eCo1o640yh)7+AGrX_E~}_T12bfb=WE27{!IWv`{rMMi*lT8V##WOrk4az zOC@QmuE0yxyKhx8SlI4(;xaG(NE@ls`W|0q?x?h&RakWQAfdyMQq7bFaH&#C+wZhj zrRU0up#?%-6cAlp2jLcN_%4O)-48k+^wg=CO_(dWIbEkS@){FM8i~=72l$xF=eF7n z#JeX}?_v@G@6yP5Xwbvm{=-x~-0MF~uXTTA9~3funKF6#C;#OvJ*a-wF-H$={zIc4 z*4u~X@+STAtYMfrBUli+6$XHpneTr^`-cYB@-xvH1UqD>cgzj9a=muTC}0%eWo`-Y z?7p(FJZ%1OjYdg!<4DNVm15~jWky(}OEKBszbgXY1rn8*@qj!Jzgp@pv0}EFJ^5gl zTv%^!%l(0xm)ZVgd?QYO?#%pQvXe-CDVFgj(=6vMVC_=_WnDx=_nfAY_%FZOKM3d3 zm7A&h%umYL@OBmWk67lX>e(X6n7D-(R#>7caAP zFL$S88&5t_eb5wp|tL{2l47E;?%j8F(T?>t$?WpK_K2#0Di7YNB%U!wOyoF zPqp+~`je4u9v6m(--;^Ws^|m$0{53$_NU(TAv;$|mr`nPA5{GzhD&=ElQH&eqj_qO zm8_;1Wa}c?Nm8?54t{947i%v0=HUtxUlg!{?m8~-pg;n@4X#uS3u)K~{%BFn-I*zh zx=ZuORBE53e}(*f`}0`Uxl7dmPk+Qjf+zJrc0Fz6ax*ctdA*6d^4Il{jWi3~v+yNd zrt}tDzRs36Ub;g0yS#Lz(rStFRZ6QJ(h;S_Cy|DdHJ6uq=?0}WEb^zCFAU+z*6h+I zzGsr(9)ryfx&>=v*I>@V%}MKDk)G|?El_qh-A!o}*SbkrUU~nDKx|*@67V+FR9H$N zdVU>6VL-TFHdO-|kOA&p6x6?Z1rlx6U~B+Ka0~MA;jcYB(nq;J^R6IgqbBim5XZjn z8L#-q?T7J5&HCWewSS));+dmq9;3i8qCSd&DJU^f6cE&r-!guQWOH$tU%jv3w}RhF zek=K{;{YKfKW7jnzWsvyXj`sDQkOOv4yXoMUd_na-7?bDh}ewEU7vMcRZ_ z=HRJ8eLjcJCwJErQ%zQXmtDZZnh@&pZe!oTCk(><2fumw3$%t*h0H&y?a^E4)7z(q zpXv4341=N*ExC_SKNz2}3&fsUm8IVaY3pL!$}_a$wOgC<_BI#>wtBMt*$w4VDzmJYwY$};W*3Bej5$HATG@l` zzI$K!7LC1St#~!i?{1#N(?mES3M&yNQKke&FwNz+_^;;(;4kVy*7|aZ1P7A!=-p6b zNO9D%gRlsdPP05rDML8(h|~NFJ!Iy?MR30}eQ2>a6y|Hnczv-oe#?G_im4yHMXZW; z-MNd_)bDLHhP8?E^I!M|*RkvrRsAsNRAe?OdY-!z@yvV<)dXKQf1hs%eZbx5s-ec> z#O-#YPoD$0727Vo|FC3Vt19C(!Oh7(rpx>m#|8Bk7azIpCI<@nK;qA{5VSIcMOso} zQ@YbD*=XzbA(Zc>Y_*$de+3(Ec)yz*PMC^8pdCbhQyGK5r zey20N_At|rxQ)V&gUpeg9%5}m0WFF$MO&zu570+M%){Ju1z+0o1AqE#ADF&M^JQE# zay1t85#aVy?=t|bYG8dW-9&z^%Y2g^qdvl_7@<~#07N&)RG2eB0M-2h-4JSY*Znd6 z4w|zARG(XGf#ktcgH#27?Qcfr4q9ni))q?^m3erYWXd(7pws*>phv#FbQR9WFr-~z z^uvs#Xl&6IM6+R#{;}F&PSQP~fa}=J7)+#B_0OGV+tj$GMAWr5zJU!NdyF_orzOXB zVBy>Y@&D|jbDTb>_xHnnPt!TTR-~2Sw0y^|nf|FK)I;|2JE^7Tl0XXcXbO!LnP<0I zylve{4I1{{WIh0-L?JLz&yF57eo&G5U69rgfcN*u52T7PJIB!o^`8`RTD}JE_2{6# z-kRG0KpsDRzrtRqCDRoj&GPs)gyRNpyt{L&kckWU&E+N2dObgvi}id?A1D^7N7eDR zb31b3lDF**xd)0EP2N)hLvKb^v@TMrAE$YXMvz&mP59nm>Wi3$O)W~E%o-TsuCE=r z<=?w_kvy8T`{qeS0DH-s${DZ{c6Nj$xvA|Q1=~XIqattK471~oE#glKrQTe4lSL78 zLC(r;Ef<3|LKTq)p>0GYe7ZSrm=(HOj-jG>wyr{C8g$^@R8^S@-5cgYB|AL|9tmST z>)wEZh*)t~ce<)5Vydi!MhO2EiBQGjE^$g%=_IMkJctVe+dxdlUr!+xKgjS|KRc!V zF}JjNW7$fkB$I{ybF-e2k)}iLRY|kAU|L6L!Tbrt^XVaYLHizREPb1>boiK1b1Dfargx;#F723VYCyPmU?D(p~mEYog$$**7Y z*SEdZd#M)5Rv2TSK6=CXHMdLx6Q}tJ-b5cPihv&6!ib1p>&9wwf9p~Hbu;TR3!|1& zH55%Rl8#PpG11+1=dlW|B*~170Cje+-bIx@iQttS`(+t8LaNbsZ3F{=Y0YyR0I(mw z(P{ZNYUTuY5c-@mbm2Z^oCq(S7Le4W;!iLXsCZ@bs+Dm zQFIqV$)*CfJ1r&5jKz1t`H@8H*s_)J_3iIv5EIn(TK)HMgvpyUw%KgaJO#D-r zPj3?&h9B)RFur9Nqst{M2Jn&f!JuRLpeiu0<)BuCEHE>rqs?b<>^u z88Z2^jXB<1RyB-=x53<(NEG8x>L^0?X);< zansvxy38Cbjm1wL5q+o^!Zgg*+TH>r@Spa99)Zxbj1Y2JQrt3(WbSf6>i1)0+d~3f z?zdV5zd<;$1biKhT7tSldx-Gh5mtln^z)jH3p?e%L}5R~CiCA5vCOSr>6WihkB3ic zMD--Ks>awcHIW5v^m?o`e8R)s^IYIh_RktrWRHx^wzGp?ik`$)!U0ds-3{08*_{>2 ze?ocqnM)}QwaE_o51ui%{xd&L^9cG6ZaqMAL`FFLi+ctY%|F3swvo)os%-w8lJ}FZ zBCNf~dQ*JJ!QIrc)PNv-;*0ht^!{W>m``$RC_?$4pGW#Zn?8I5E;2mT%Z<7h)5#LY{-|hSuAJrw#D(!j9kdpMNrYNCFSFCkGG`uJ zTvR&-x}j~NQJe2{#*QKL^kk@+Xvx-W#k-HZ(M=rKyGl`RF0jf>Dvwsz zm#1EgX6i#@CWTU0@>_-loM~%lQE2xA0#A!a0ua_L~M(y2x;G^0s^Vl(7 z1CIEv9k~|Plt(&$C>(~bXfQwJj7m84w^vXXdMKD%0{PQ^U}5CbCjqskR*TYdr$SJ; z(;exzi*u)wtIB5C$u>VOQ={H|wVcLKX?dVNWN3Y$A`(LNFPiyIh0`KtIeh@`_yQ7n zvWVD%GEJV(Trz6DTH@^qCs3kg$Bo~VkDG_HFgZ{^3eFk1n;1H#YloU{98LkXV*9^) z^?9j&_l8pAWLxK}8IJh?55D;p23`&bT4n;|GVHRP{Id#WkHZHd-5E@|9V^s5(ROb! zXB#Wb6-TSV6}d zDov=0h6K7-Y@krUx}L^Z>FN42%V|-x7;aiDO~vG)hVDS(@f#TP%RLQm2xvk2WmK<# zK5V{9zETzDLQ>XsSku$%!~&R2VM@`9N{1|h5K{_8K3(egargPB+MBNSFuHutT=;N*I#VXn3{9O9@IA`+qSef|f z@~-~48y)4F?b7E=1~ z^zl-+0(=@XQ*8fv{7<+~o7bpIOCa@qp(5wq>|ONksCp3gI6+h)>5n9#rB$|qM3LF~MgfugfyWhU2DUWe5}JDMKl*ZTilMK& zI=8@LZxf%`8T%BOklhSW{=dRj%}b9d%3W)l_voRZ1G_!A+?@HEwk`$Y(0i?CjEPFh zy|bsn`8n)X=M@&eA05?=-}Cn8@p}~CwrqA^becaTl{<+)z0S*Ji7)zl(G&)WDLJ+- ze~0ug6DSC^oyT=eUN^3v4X$&+%cs$t`+WiY$Q`@K3%8p{6Qor5>4EltOnCKaL|wsB zw^D!ds2%b%rz;cGew(J$XzFa8EOSb}(;T@ekK5*jJZ`^63Ly_Aw+5J}xSn0iWaur* zF5Q0e8HoM+0s?!~UDPxzddX?$Y6U_SHLzq@I1VeK3j%kWr|bfti0?0YC{=z@g*x%t z^p&@l|0Cb&FBLjHoRrkxEn*xkUEUozsVRAQ(*rt$h0R#cU(UFS{9)z8nMSX`-YS+| zP->Pw3#oS3_(7waDE`@a&X)gwh~^QR@zGqzxU&IGo%~&+>7IF+f!fy9prsBXV8=SzGJ3u5`HFY@cV*oC^1FP<&o?8f8^8Xda&It%_qu~Fz3Fgb)i6MKGfL?UIw5twfhD#fn_HV<}ipc zpFe>r>}n|^r3+ACEPg$lA6|tLPV>)MEBLwXj%eXr&%^(I zdtfX2^!AX?%x@3((3IUC8pML+DY(2a&1D=?u}Cg~0NX{f`RP2u{`uMbBKZv|f05ip zbNPLP+YOfy``YdspS5Xpd|&jpo8__o6CHL@rugs>e#dSFJ6^S0f$hnc3q3id(39i+ zo`^zS3rURbZV|)TCv{kK_fnhUWPyqF8KC#Tr=Fbr7(Vg%IPvl3JAe1~1+mM8b@ds$ z_5ba@pvm!8y12+9m$z%!6JA>JDwaIKHiJfDQv^gKdOR(p9SngH0E>1DBIOr&)o;(AhLU#xL_;g&E`7 zXyv|kEE{*V=OlvGGySXbyXnutIQ9>%BxG{k#IHGfKtPdHWE;c=*!SKI%xZOuieQ}h z>$~~IIMF`GvX3_L==s2!E>xM6FI!YhPvKu}^rPC=+2zM{T$-QnOv^GpAb!yfD)gz;`E}z}UVH?3G)tg^u!NC05hpE%c}Ltk_*_oZq3im`xGBD3 z?s*hN@lwixPkhWztsY`-NgTz1T1{kXUgYI5MajbxWBx;P;oNkMm>isko@HFr-W)?BS5tzG6}PkxHSq*{~Dr z{{k;%KbP&>PM@req4d5ZH|IC9ys=qcKIj`?P%QM!zqdHYLk;aASMIPgojbyIk9yj$ zGtsW*QQ#Kc{hd3-w%Mc)cuzQ}3TX3@0z3sn%Fgwroce*?n{H~g#@D%XDALT`J#;qt z^nZneW(hh~O1^wUu|-~0>-9~63-Z0sjo_i@dbWc1Q`U^#UL%fw;PzSh{S$R3ANJlf zl@qp=ldz*S_b)!sr5hS?I$rt{H4A}1S)3W{ip&s1S!Ww}D-|ftDg6RS4dC z{0+gjX5+Kx+Yv{!`^908y;AT$hx&6^f7NW?KVcivW7~KN5x5?mV|MhG3jsOq6WDX; zCaLU@bz~&m$74?I26(K%4)eY5vF)b&;cd=oa!vW%R3bZe#Rp@HIuiE0CcXc2&Qh7- zW#>llJlSpDwJ??ABR($gnV+->#5Ls>vgRrOWup4LWCE{jRgAatJSb~NYdsyKo&Ce*`@n^>GeSRyCaC~fCJ!q82_mS((d3WTT?A!_JQOAQl)|(cZSkw@j ztz?a};!K#&pdM32Fl8&)$Q!ey7|25>V@kNMkaLh95D0B;+x%HLx1 z;kzJCcPE&wCI-+`-;1(At#9ORP9g!&2hI%prrrm^GGD2PWoN^jvZ5jORMc~gSLJge zO2}ill8%YAfF^8KMt*)Q&N*~_s(tN8Put+-PepnHZ5NbA*FmAQ3&985pdE?q7frpE zTrDzaAG-z@M7TTCsr%S`hy|^db*QC{ksi-T$v!}2DH-nYsH5xbi0GRJkT*SB3;2t15sTC>s4uckWB=Fi#7~)B~n4WWt&QJ}Hb?{Jr85=KAp&D68*w1|A4A>FKV}{DHu7 z=mng7E)P~68t>R{K#)YuLgu^#)Y7z52`Duk^L884>=z(Uw5cncIt;*bB4h8zy1%X_ z`iO|J+fEQk(X_qLv?J47;xpNf>WD8waFmQI%I!FAIl9YOf|7%ahltk=o z$V6^X2XLLtq^8EI_i$oLJKBLlUC)WPdB8r_S5S2g(IscktlkiD?pQmMcXzZ!n%5== z%v4ZQ5qh54lHEXsP_-r3At*Xmsl{pgTmujBMenk0`tZx8i6Kk=lBS%vzvKWJmn z{98{OxDU<$Oy(a<;?gb?Z8{K6m5glLU8h+$bY3#TFB@sr`j@pR%ejB@wVC>9-1~UT zvEWI%on?Te$m*K$enNYF94_LIh$fl3X}n=kbPF`4N_(}n~8JK~mIyq6#6 z{zqNTkr1DDs>WsRoTu$i%v1SbrtaalS5O#YG?R13((0R$|Mlw3EfjTdLfl) zk8U%MQ<%yR+pfvw;-KccD89B%lN-bhOc77(MF8B_G2Ot<%F@-k%C0F|{IhxxGQpEp z&&?eL`10~ZcJz;)&$sk7TI#sn+mEuNKaS<|Cz5YZl_VdJexIJPYn(_g%%fZLEY1(S z_3F(J<^A>BbAA+-GUnXRW!M-vbg*x*OIYqzi2{>oSwiJh(g3ubF+$(NGt>L7be6tN z7LN4pL5?gD(|AgE_H|lzkziZDgdVfl;0L$G-L2N4%4Dt=xgzLfO3TpZfqW*J&%Qzz ze9gPnFVvuSv+_^lG-0evIy`y|qwXR+mGzO~re1e1+Xy-{b1H0?cEYRQ)%^6c0Jzkt z_5F^8YU@+lUv`={ewh+nYg6P;J@zdsR+3y)w%w8U@a*+SV5u3H#V>@6HC?=jI8 zhWoqi`PcIvZ}hR{4r;A(XFZkDt4%rJ?COjHh#mr3a$;)R!dHJHvFrr9i8pxJzRmu< zV7TbjbQZ?U=o0L`wm8iT{D;{^TeyZ2c@Zl=^cdX48!@MJ+7BdL(}lJ=ZGXGbgQAnX z5+T&7-9`32WV1&?^MR3qN<_3>wrqZ&KaB%F^DN#eoeXU6A#Jx7c@%$6$Ybvtwj!^W!~tkZ&CKYSDYKpC zdjuV85u6=8-LK|#Q>AJ|u&MkKa#?vS)6bI|<6hA0@zaf%?iVd4)UxRd2UgFu8dmcN zzbH>NJ2=068V}H)M$Fk3egZ4@Xb(XN^H6X3o+XRyix%d&pX;5sUM=I2J$~yp@nc1P z;KzuJOG*)GPqMQmQ@!Nj>iW4{o^{(AKXbO9d95=4B(M+*#0p9feINUk|`&_Es`IxB@crRHDA#ygG;ReR;kXmy*@oK+LD@3WzN+1Yrv!D(L3@NHx* zAQ%D<#FKTIEjM<Sz1!k=@n`!&{95+-9q-s-19jrc(@U^TZ-iaOemt{xl4V6%06R>UR4IUEGqLx}9b;&z5mL z(vJ9DcvnKZP_-ZhbJ%76x=3_*bmam~mUd~Z}b5j9TUhaVzw4P5;lP+TR=J_GZZMYv;hGWV0yD0-i=4>5{gL+?) z*h9o0EevPrM5!LLePh7f-Axbyu_`l4{uB$Wmu%cbCD8wq9^q6}~ zd6R0%WM1TlO)>8=bBkTwsVeK@bOw#av)50v*RduT0Ly{%_bUgaJF#4od*hB1j3iK*=t);nl zQ(5=c>-)R+1UPf>drYI8mR4rM!rcPg13jVTEYLp-+WyeBapj8WI&`E^FO^QkHZ&(o zG4d1mpTDQtNB_nCeDQai&aP zIbGXt4sxvkREIbWEMRpMh0UqBapZo@@a=p}ne2mmKL=Fzs=;jEBi1h1ir!eU_T zHpZMeg^+7tVe31*EvyAVap*c=vP+md&PdkaF2GnpK$UcD$DuUHJ~_%|<}kET-FgE>PDA<$`z>D6#wXw0N>^7hIm+5;gbTA#aP zGRI`k|0KOPFz;{<(vzXQ{LcHSgoG&Ii#S*)z86~3k3TdiQ=D!1gwN(hk;#(;2KK@c zodzrCzX8j;7 z{O1`|rDx7^O6@w{<+S%FxMfS*jRP&P{PmY!94bn^$N5+h=-sttSGqr;JG#f?ADpqR z`Q^LgWqmQ0xpSGOBwMo*(_3%fiDeF}9!aPj!bovn@#AbsvFd%P+=r{I!ZrdQd;eW_ z8kg$Rd9Vb*T~rPM;%_bJKe4>s9M&B_ME&odIflt1?o8(9_4?MG$Y(ci@RE=deb1V> zw8kRce>nVD!Pui`R}(_X0zfFWDlb3QyQ_s7gcK6$ak+u4JCOzu(TVXWiX>MJ15!x z{JHHNTP^*~jvnUq!u*J8Z7eY5d-7qIHPmA;8$jJUn68A?ygB*J#w=k8R{5r z@sX53coY=bGQ;i~GZ7V3%Z|oMFFC>(Op!TCW!l^|*FS2%vd_$5 znQMAXIZK*eLZ6$c|1qAcu zj>ZX|UwvjCOy|zY4Mt|-?y8o}Q!j12p1JIIjwX4hIfq#hJJNWi&Vb5vy7aAAy}M6{ ztAt{+Y~c;Ksbh<^kbH zeE50}Qj)QFx|5xmWt1ckdZQO)!YuwX4GT$#<-AyAM4CV^eGQL6d{6M?oqF` zC#%p~$ZXfwTL4^h$8)eomFzp_8dBgzMK4|je1;(0z=!nqR|C6ydpV_T$y|Rv=H*b} zlOIZ?@KW&zeR;>be;)S(dr~2lQ-iMf8mz%FS!j|9I17T6f)JKnt>D)t>_)62mP=J4 zqE}{e2PDNs+C`0GCd@bhwCqErajz^qRGEd}-~nLG5psAtBHA}l zf@RrebbpYy%vPBq*aCZk-Jsd^=&OjGY=t`g2qN3k2Lo_9-M52;fQvny6~uKu@NHLE~}?7b(Lv@%C;4e$}b{2Zchr>|pUe!t1zcM>cYSPOHZL}@;!ObLI8|3CMy zB+s(_xQu?}ab<9!C!e~1g~+#oZg>XsoxmEw>t6v!Y`4_WaK21$tVxX%^c7>t`*foJ z?WM8iy;(*o6=2eU^f$Yr+qt=B4-Rpcz z`~PY78w#JN!kGmjbC#DVHD9!!bJSf%nK;M7tPsJMYy;wx0$5 z(Q0TffG4~-0_xQPIi_5v;0W*lw|#GkDSH~&sk4@&IAs6v=!L2MEnQ7_-hEqNZ5N{fz0-TX#Itw$+3VVy zzbka@Il4x-X3>#+*RG^%arbga7AO2nme-|dLEizamf>K*F{1^R`RK_!e%;nYp-m`5$P7vxP3e%OlXkTpB6LC}k3uIP+qzQgZ%gfC~zF=xU? z^A%>0bJQ=ys$acs%Bs1}E2?q@Mfz?=0yt1lcq8m-Gji&r+yX zK)Wty?Ar4A|Ma;#e{t8NQ|TFxxO+O9#Gotz$s#jn)H=UJkO zz>>U+A23ldv(}T;7U(o@=dX=R9+lGJdF`?%-=hFWjSHiMM{t^3DZm#pEsOBKd#6UR z%6Z!UJjE(yMm{b_fh*y~j@;;}Y(v=KPQZZ_ADtu37gyKjYK6|JxM!59bg1pn(%IxYSg(HYkksd4@xYz10a7TK3HE&ta z>ZhWuZ*v>CFYY$YMG5*HE~~u$|FQQj@KIG)|91ibgGNt8(5R?EqYX+G6qQJ{8AxEF ziKN8~-l=UdYFiOzAg!XonEKvckr z9wSZC}-u7n(M zX!Op%2f8Vts+o7f5Ev2+yDyvxl?YV5+Kt zg{OVG)j`bbN@hTM(K()00qcR2cpSkPv^ z>Jnv()$3c;k|^!}1{AG83)SLFMXtyZFAf+!D+V)vd zjr&}E;`HL=z!G;k!v1=9X?6eSLhfca?Y^Hr(629q&1!Z2N7en)6>r!$Q`vO!^~uU< z`3pmd<3c3DT9OWJoZBsW8UN=;7YgPj(3-@MdCu&ScH?NJ$SdsIzuhdppoqJmVf<}+p5&MnUbI9-R>2nx~g|quyP2qGDylS z%&SLm1XH}UmQ%Q}VRM$WlU>t2AQZczAU|~kkAeSAU~ja|<=&6(4Pd`VSJ)p7?9T=E zqXqjz1pB=IS-4AoxKp^}cf`01?4R2S?0>gQ*nj(%JB7VOwkg?zWkH@=3`;vJInt!` z@Yzgv&e>xYzuyZ6XHB^~hghg2isq-l{uJ7u;$Djofy6d<7s^jLmsmL2ougX^w{CFG>(QLQPu>P+to;o;0~b}CTL9wpo3sFv)86vjf15DTB_UZW-GDcX@l1yT7f~QD+1QcpOP;2p zd@`;ZL)?nZ5ZOE@y5w74Ina0IlibS;W1os!NbTZ}#X)R_*bj#E?J39}VI9 zhXkJ;P7bz?$WiWwVE=PpmHen}RgVF$V#fCv2st!=17)JC+*dOvj%1&G`oHhK>Mm|u zTR=aJzQEYmxy8rT! zTOrU?{Bu%GO`_nW&=N017IHLrZ7aIh<}a1OYQ0-oR@0tuUa~^q zsdwjudi6QU*o#w`k7`N{(Cgejiy#0+0KFvv&XFdoWMTxU7JJ|Oxt%wT7R4c47_p`( z;J1+C{rFYr^72l`txPGQWZ<``Ll}_y2U0bWn86+3WjHzT79N5UYrS9J6(CIHRCxN- zA{G2DM43e2;kK3CRpvU%Xm;_QWLv|3UiWTIY3dTzhw$pfpLu==2xTGe`uW#v6OmVP z>p0qf*s6-GF($q`e4W~pO5M$VfQY+r-q_DZG26q$=!+ITn%7S7Say|a#EYwy%HzP+ zSo`cAA56>3<7qPk^X0EwE!%|Uu2pK)B~Akm*?v(@iT(}&|3+1Ui($)C{L}Ch1eU3E zW(;TEdo3cA_b9AVVxvzZfak~t*nAwJy_b-c^XVm(^@*$4%~orlDfS-aX?@~e=}0j< z3KG)TorwL%8_OgT6k!(K3lw5XiP98K#><-ZkVV8oA>AkvE}TMqhno`5S!NiS_}A!? z>9O46pB)q(BcV`J?XZ!JlSuj;+Bp69)I!LlKQZHoGs35LM^t;xINVcMYh~njhcW0_ zteyWJ)Y{a9H-tIkoSIiG4&HnR#*|VGo)v^<4<)WIiGG8?`nRg;jdKbk$7W`x8M#-f zIF5r2zvQ;bj+67!r+IfVXNOz9CAOj<(mVGPB0tkRuOIl0jm#jzfQ~A`E&-TvJA_WG zpds>wR{`p<3rlf0sD*jUWtGUxk$g5PltdMs974IgT6Z}X;Pvh&p=s}F!wDN+zA zWN^=>d$Lc}a*C-~?Zixe$wbY#+T>OFXC{Vht{rx9*omD(v$BLGHY-#6hBuuV5_nGI zIp8_7GDBJ_VDq96g_^HDwBfku{l-vwop%|bKEz<22{c*RbnSC>4D{_tPq*VYe5P>7 zgh0%SkjUq!lc5veSI9nxLuNam`=|bQ;-3SYQ-#e={EsYRXU1A4-XOmT>gu#4d0LyC zQtquJu%aRhzQ7k82-LFdriPMf%^QHCJ3L=RATQNI1!leIZ4+P|2ST7(|8`kvsxRNp z3XmsqBs1#7Lu!C!%q*<)?z&y8|9Y;mI9lsX14wqRTF&Cr%t#dSlqfDGsjt!t8O>DH z6Qa|ZeH9B#(@Byl!)g=~8;_}K`@G0S*)oF40a}&130dl%c1%BOhh0_WOdqNFAsbrr z)V$-OYsB%uYjdiob=TAnSmTXCrcQTj6Th@;?)PQQ)KW+41XL;OJnuFro3DA+!2#0s zMgrzk%S_dj^KKR&cz;@I*O%;Q42scEQ(c8OIaZsvcpP3XrziTQ>xO*`jQKue8{T~F z5e;OFyp(Gt`4UEkW&Sa?UZfyGEOPaf(SwD^GtxuJUo(3|hAXU)F{#3d)>oj*iIg=( zjy@xC;U_qRT@#*kn7pQFVHkLZV&a+xqZ?c6rGXP{@N5A#top~w9>2lQ5o%~hlg#s$ zVD!+^Du~j%4#$;pfOP<&7}A}GgkA$#<;zqGc3r|W3lgPRG?~>HcK2Yi0P-bF*eDJ( zGE*OgqsSL+Ofr%HEl?G>3 zw?y!_D)P?f1IX3uHP|25VQ{4L`KclzP$a4|#NTY9PJ9pchsQOr)aP(vjLT3!Wtb5a z)FGnDiB(WXo%?Po&B-<3A4I1Pv~)^~O?1kp5s6Qx^fQkz8{W)MsrNF|0np$oAh6E6 z=N91*ssvDfxi|fGB4Qmv^Rvt}*ctd05I*%Dt=5)r^2&%8Qy0@c)sZ=5CsYx{BHqRu z)%^Ue=7DIO6aRQ$;Vl6mMfk@FDZ-Y1h&q`%yfwPi?V87Reqkg z>1L_~-r$GXNj}xwGI7u8qsDOJrg9ClZLuc(#@&(^%uC%#{$J{gJUS}%H&A(-(Gs4M63R#qM-`BQ{vg?W)HYAZ-m zc#ml@60MCrn?E`cS-qKdA_qVqMpm+!MShc0DEg-T(u{7N5aDBhth)vQeyj!w1p`VZ zovayNdbs*WC0dEB8lz9OZANcIUMDzh=UZww^_n_F<;*TA@k66`o2H1tdTW2mycdEQ zOiG-g+Hat5A9tye+R~2)y-q0)ilJASpuFG-DYtq{5Q?L9WYSw&S$zTBb>eflt500q z6iSRJ3RR52Kjj$bhJv0HNsK8-7W5`3<@7nQ>B*X{ZrkEiuLW*fTdJG=DX>3<_NTbl zg3Ljq(3vp^If=sV&Y0c9@Pp(kF~5bNP;hLJ1zWKlucYoo==>v#p$;$?=N=$nYEr~$98zfvu1?arTPNBm)QeKAW(b(iZM^+ zI`GyfuIzNWsBX#2950-f5ZEZ3u1C6Ei=|Y3qR)qQi6NVe#Z-97s$Lu1V!Ll7PG<(c z238>uLK=|ha~m!{IQU$h&uwjfd?A6`+(omhS5w^RCNBUNgZr>G7sl ztNX7Cxq|>YTeIHXx3>ET`0fp1CDi!P-Kpgdi0F%^PX*1LVEXH03GJ7f-rjN*LerntJI-D#Nta&p2z++gO0X_z!r z@mnGK*PyUvo|VHDfsfY=SuxYijeuY4jwtc23?6dFesB$pt3Gi*@Y;Ut7gxS_(0D{a zt$Ss0jk{OK9Z^X0gZSmF2ur|>mM~M-Bf7J$<;(&ksb?rr(9B+UjEvqiX__e}?qFtv zBQ~>!xMxwQd%;XQYwn!r>S?PDPtj47zZsE^CW2FHI60(6NJgBh1o*^}Fn{3^kJLZ$ z<=}oTHm#(^_EnJNc@+`MJJYT7YP(M=epIUjC~sQSzh@{mq9C9D3dvwPvI%!Dz*$+G z8pIND+@rN?%zzU#cu=1h&kE)c7ZPl15(CSe8!i>w4nff>4rv+Rs#X1k*YQ;>U$c&T zQy=SRd+XR+`d|L8!V*qnRM~0udh>o_j**2Su^=}rfD`a;VjfwTtXD9=7sTbPPH=;) zlIgyj&&x9SQ?cHOUrKN6x@Fosi3MVrbsJr1*DS18t+33l+JRkGZL`2$Yu4>)UDoZ8 z+;#gER%eF({(I|}!{62~vVJq=JFnlZtX~19V*RA*P@-}_2^hLZE4nOS&QrnqE%(W_xo_-n zk8aV()Z|UP>VAKi9Zk z`gzg?!$`d(AuWQJDN84*7*51u+ zlRfJ#7$((J(ET}1+~pd$05RL4fJy}&Q);qjn0taE$2Va(ngd7{K8K_rA@vRcnK~O* zrP_TF3*Z_Ht}}pEdsk>7osJ9*0j-++rJ?@+sIFMy#D7hL6eZ1^?VKT;S#W(v;3CF( zdV#4I?EyWJEbp(>fB$>&ll z$I#T}=4=8#ZT4rguPRS}JdQ1I4l#x-ugGTjuV78|7T7JJpbSRA{@TP}ewGkel?e7vJQ zsfykhV-EJDbFswkyeAzGnrNS_uHek<%s7L6#bm9BfQjBGfKGij4CHosM|P)OZ9^o3 zVL5GYE9%NXR{8tT|1|%|dRhBL_Mc4o&il_=!#@gio)dcrZja4qKf^;ZWNvr75e1B7 zr;P|!l8xw}z^W78=cg>*o8Mf#{}G&zkM|0rvJKvcf0Ui~OJu7K-uIxO3y$qRiuGa% z8x-4&UUUa2W_V9;8JHB{**XmW4bR#M*=)Ji>DwG%_J-Rt$Co~0Ygig8X^t4=C(6F+s?z#_3gJa zJg1%Wa@)C&PrRk~vegXdv466F*{JkVw=h&asBxEaE?Fr;uOQ@{P1;jG;GH(cmes6> z)NKBf+{0%sTJA;xpSqg=d_9PcU}nQGZZ%e(xq`hNnhY{ES|&u#CbvU}TmA^4!I zQ}6WZ!QfS|pl_i>L7DU(YpKbbrm2D>C=ne*f|HspqYj@Y7E7daNkBkNvD8-JImUV9 zHmQi*_4uS<@08yfTk(0XMWmUXY2xi+UzzN2Zbf&{Y(@zv$6c>wT68lcy65h*rRGi& zO77mWcXB1;ZkI{a@4Ig`Y5Qe?{5!xBYpc^gBayTRGvi+*ZER zsg+TkT1lzowymtd37%T_QrTfKSr`xgL6q){eH6Yq{Z*Y-uaXisvINQR&?w2X`9!r*J5Dl zbNigI+c))EG}DAJbl0Qp8~SXduk*-X1$35f)gr`E`CgP6MHh@IO2*VFkXK%Uz6syf z2Pj{M9axc(Q-coDl)UsyIo3rFVJ#LpkKCd8X3#_{U&K~yLfRF4;XGmnxX5GVsRPU!IB}ZH+GSZ> z?WVo6?uK3-#0z6ioYkiV=(osSy!ib^-r^LBN9y2+*K0wqMc8X5M-9#O*GkM7$_!@x zE0ZG$ZP9H?u{&GOjWuR7O)~Q*euQ6y%wK)`W-s)s91Gz<-;5nrac=$CMFa1bBRx{R z*FbA+s+ekk{m~^4O{Pej}UHxXA@)CMrv1)#^xY9_qMN3mY^#0d?(YlzvmH zLRNno!Wx`vyG8F%wZ*E?gaqFR?daZR}&Aha%VeN#>104M%+MpXln$2Gi~h89 z)eur0bc>9brO$LQU@(^(HvPK#^$&#QJnN|%^%gn(Uje!9B<+)%~aPP_#WWeueg18?A{{z28o=ek8N z=KuWYqT0l0W0%%hP6Edk{i`qVFgPNChaHk}IzRIV_UK+@2O}{D8dGq|X}JbuLhlw^ z3A&5|AQ`%Q;tJz7QRhByQT(7^G9g{fQkV=oegGPIVLQMqXx=F>2j&9vF#7Q&!SPf^ zwOu$mExmbVVEMNl!}8BNf#u8B>=2eys5z@_SQLKNs9v?g7v;tHj-sNx7Cn_JS$^lo2x9QKK zch1ZsO?9l1jm_FRiHNA4)8TS|SdC4Inj$CuGb*j9!DIG&7~g#i)lQt9(FyEH9bZr< zQ02_1+RHy2-%D)_v)b3~RiWPqbbDUw4-M~#a35Y3WnlJ5Y~uM$F*<=NV-dI!r5v5F z5|{UbYmH?_ksv2?nm&kUi}Ep2r$CWZ0N-Kxi({xG(t0NizztaqzzYBj)SQa;uO4Cb zz`!uD--o_opie&#*HzU+JP}imk>U=$QPE6dC7i%D@xE}4gq4gO=`QfgqcB3{*7i=1 z0c|j^4^ryn`~?)j9|fxpqW|6|bVa?}uZ>(bfg#|)IX;kE zlraV=VAZ4n)fjzL0m_nEtnwuH^O~4fKuh>Bj*V-*WxB_hj%UT*ut`j7O#!HiR2#!h zV=GwgPR(O&7GW`%azPPm1wW!PbpU7H3}y;>axnAGe+e@S`O1iG$bPg#%sfgxmZK|} zS&lZUGiH`VJrdbYMGVX!oEb~NMByfB??F!|K42eK^ip;z@IFA&%>J?qymVRy3wd{m zn-U}cN8+W0+vZ7N=8)b-BpCe{Fmo%&7hqP)`wrxoS~#j7NGW_6xWoSBt~d0cy~lv{zG9fj z((XJI!-4x*brPvJT86sS{YEO4 z&0SS06$IJ34|*v!ttNk6sQ2A(^9GzR^KC6s#bmuK6{s{zsXG1WxDW~*Z>^1l02ht;w!BIckJli9J&C}g}?Wr|r zO#&^Bn80c=fmPn&5RR5s0iX(wui9xD1ean5Ko52@hScj+81Q%AFlM|Cqi1O(**&UJ zIuxaj0%L-Q-hq@bk9n+ z_XS<&yM5dFj(jJ?MpTo(CDeaSO~p#hbyj=UwLyQb4??xUTt8sGblWo@N9R@#GkEtF zW_pxK56RH8?M&3~zSm`v#DhR8nSN~+E8K&l!PlTDRE|8fmDsdAe+CuzwZ2}H2C%f^ib>#uhL7i+aP7oez09W=+UdQyUpW(p!05X|MzqFpi!W*R)F}R zt62~^TTHqSdwzxxiVwO78SF0ho9O@YL0^my(r%Nw6><@r6pSa#|(-~47I@zqZ3 zx2PYH_*bEV-G`4LTvfiKLqFfq;cf4+tFqJo1T2o!QCqvp`uq4TnBUwMYO*cd^YIQ^ zI5($-^ZXWWrf{b*JoKU+gZa&EVIeAEe+>U%?Xc7|hO8R-QxG&@mOf*bQvVlG5DK^Z zI$PGtY3vMUt&F9?9j%ocgT|giDnw(sYh|5x-Ib8;EN6B-1>nk@_}vWJ3$eXJ(zSeo zWg~vg`ep25oj5JWZ^M@j+0L2a|0-W*O#V6@7{<@qfxTaSvUB0i`dS?rz7S(()wG?C z3{ukePRTJCHWhh z?GQ6{UCKVGZ71x9n4YhoUNKD1b8K397!c+#JgwX8Y^(#bv!#yYGykNnWcGH*@KS|($*!uMIdVGA{3C5wV9R#Wn^Y5U+HRfg)cG(wMvc2AHAd^a&d!k0wEdhe zp`4rF${yH}(b0X#Q}6yCN!zx`yYxGOtJNQ=CE&L@)soz9EsIslw@oeUynfV@el*M9 z)VS>_MZ6`?gl0Fq*h3c)?zPCcA>w@4n)(LrBxt=RU14U;W)}`H$?Cku2CvRGj7SZZ zQB(6$wV1E*-7xzyazp2D%7Sl*&SVhLeDf!WZJ_g$#%k;3exsk6E{cntTAEI9ZqF^X zEGTubt;?3W!|;pV1CT7JQtF4OPrYB-8-IsSbw~{fxusTI-mLyC5mct2ltG`>mx;lP zt9YS&cB~%7e0mP}1T4d8eq$4@R=88e#|PgZ*QMeEgBSbTL6#*nL}C;N~a9 zxiy`DqvT_(ygcK3VVoeAd-p6b?+y@Z7lsp0AlSN` zfw6(h{|tO@1-o|&U#F!z!w>w>cLd}6cM0RSF4-xJ$J0pa4j`2|4`xA}`oJ1dfbA!~ zx<*TmWGi;n-4;j7$d1~PDixp0-?71dVdBHE_zayOyrV?-$sUI#6!G=D$k^fB${D-~ zFEU6MtP-uOQm+d>!7J zJ8exR;b9}t0gf3raX{)KUIgP+D<$$1Q^TB4Z6RlR1!d|IL*^Ktr-9ty&Iq|iiQz5W zS4r5N76#aXSUT4kG!^}m%HUeH+`IHibI#qzw2=Od&*w5~-!+dp;LqxBjXyFm@{GEq zE_o$nOrRg?oyzGTp!Rr2CY7i)CUugD2&fSH3@m*me7 z!J#?xn87zwRr(#mHoax(kja1WT0pHbw7glLxTnk# zY59#UlXGT=cgDpc)bAK~XU4FuT1r)m6{Q+OtW!h;<>LZYM5EdwMU!#YP0h?FQjxENny8hGrRhNDvXT6z?E)!@IO_<3x zhnRudgL*4u}v)E*^9PKZXJ%nvM`3!9iPQ^zS{RliLDH*&JNwm(5{kn^wV zxWyk^fAg8tTXGcdFRz*4Q>o|*r@&21L(Xn(;&ExZZhy?K?B|-^HD8mLGea*1Z%j4O zDT@a4q4$}5!AuD=FEk$H4+8bb(B{1+x{$fWdTN*M_L=M2J z2R1~3fxImb*>@lF4G9;`J3JuFyLSJbCZ3r{6wSq%3tiFSiQ1BBpWXxbBL__TRQ}Tu zr+MWw)*+oRrW7|6fDjzfg@k%f6da=^(NFw~qD!sz#=~myWY5^<&!bbl+o>TOdkzfw zyd=7q<;r@0D`Z{H;LXf(a%P8#VY2~Nsci)kS}=Ka^UA;XdfqTjwp;GMTOedT19eh7ZyyyPw$nyKss~9r?_+C^4Zl1B()3 zaL@6g>@|#Iunj?P(q(B?F_{;QfX?+*^j`l*Yzam zUpO(PQKluQ5<+cUII)K_yDH=5!NM-ZtzloQCn$Q&nO$4iymAm!lEH^7Hbme5Xs+Qj zY%t|!4M_u){`_enrwL91!WMdcFN6v)<4_(bR(G?mr2?Pj4V&s)=%m+}c9@C1QmfAO z)J5iJoA`-|8ST`Zfv*K@@|guZ3`|sRznSZb2UISchzWZqL%%YHDyCk*X6;nE*f-hr zru_3yYgI9t&&?=mO@J}4{sJ=&#Y_B-D0&~A6dTVs4~fsK7TxYzNBe4H9&KMlen^x; z6RV4-tGx>U=@6c>!8~QV{2)%h;bB0#Yiu!xwO z@AaYDaK$fFV9L7!mfumLpS!oot{~%|J44YxGxK5hUz3j+$+u?bbK){%`csdOp#n3j zzh)blYc)7ngIBwy(JA;MRJ&IeL@#FbHQ=~AqA;4PD!sacJZ;(X}%vx?%@cm~S`LaT__(Zppom29fQpsofP+|IJou8UG7;Nr_84`ktInUT-d8GZ%%O8X|YCZ3vC= zq^E9aJ^#EWcojns4x&YRTW$TAx?ZCb4ed-v6^yUw8z*}?J@SG;20|>-xGiM-rm+$5HFrPe&Ay$y{O7iN*|62 zR0uiOkyp5%Wahx}MTDs@v<$Fl+XgL`mu(iNnFvlm!)o!KYnh#L@A4lr_j(XA#3p-G zX8+QpHO6AO@2RQv{cf=h`G};vkKVALtP*My z@_X>h7W{&&SbMJN*r~JpFS@~A5Xws8|Mf0|Ob$YuIXGv)6ofd__ zFX%|k<&}j$``62sl`?$AA-FpQIMzov=CF*dZJj+2`nXtw3dSWXM9a%Rcsusb&j~;9 zn%94d)>6h?)s|=D7o*KmQaduWgLUXhG+uJMRpU4J$V@F0S^cTzWK+qaRP3F6@5s?T z2)Hj6cLbEal{mG;0x+Z>hQDJG=Iht>%{k0u`Tc0xjw`egd?_S$Sz;I!dwoH$^djiB zqGXI!l%c;Ms!cyVi$oK~Sf4D*)8?7&(4CVym-9snBLP= z3+j=|j95X`vY}}e}Q#TH>b2;;ByU}zEX=YyY?k9;p8)qY97_q`J*;-ndkj^Qa-@A zvPnlIkbWwgbVuYk4j@J+7u)Pi?uAU4BM^QACeWX^d^8&C8pB%6uPIO^%+DmlPmc=6 z)*=I0?mh5;Kpt70xamIL6Xvsmr-tD4XEIdca%nI~j0>^a$0Gr!IeqwHX=mBbgt*s} zlK6?+)kx&2!5;t>f1Yld#UsYAI)TCa-W_*SA9gX}VGpRd>YKO>--%{!Ov4M906k4j z6dCIbZ;g33^0NdCM4|V9p&%A&Bv_hS;ti-{4rCfvYA;H?19SnYaP*6C3jVc;&g6M7 zO=k|0Pb|>&9D8k01$s@4WRDi~r)#yWKZUYt*RKi26fYBgam~IH$8FwR zm+RUbrxlnfaXq*kFEjhPG-`K&3M4Nde9l(nS&!UYCW;{+i4|LWExIp1G&63VLunwX^qs9w6=jw7739T7dCHG;cf5kJ~w4s&KI|A+BF9=wtI7|J*v z=ug*;{xz2q{7Y{nAxq$~pL1ruLn#yNEIfZ6uACk2eDA!k1840scN|0ww5!@4??XX} zCg({$2pW}o?@))l%Y7m7w1b@~b~Tu-OE!CnFJrjy2pit(+A(#cYLMWxm

    S@3Y(7lGV8-t> z>35vzcN{Dn&?5x%lxtX{(X^WWq1Rz*Y~XHh*4KOHO&eBS`;8G!OO5}LLQ^{nk_}sp zWk9icN-bpUtf#gn*t!s(52e={e4g_>ssWBbH=DM@PW7D7MvFdpyxXX1^kggnyg2b8 zQgi1hJgRoYU57?>W+0k`Yr2N$s56?_Z{bwJJkhU-W$A}HmBU`4_pT_b#CM$A&Jc@A zcMG%D3amR@?uFB3kH$OtMflV1&JB+oYRHXbr-oG4yKhOBIxeXwsEYE5kx!wl9Sao& z^;(9G)}wG&QBd*1+j$h!Dz6msETvJE*+;h<2lZ$SnzM0G`;DLFZZPprSM(UL0gFx> z|MXQ8|1=Y#aJQnL4(7n6bsT~?{TuO5Uz_~z$3JC7V8dYJpDOfe>PF#w^2EoM?wwaP zdr$B3?*$y#)$kbDGY~m7t$1JKCY_9e2?xljoW-QM^rMt6gSwh2hEoaLLA|-b!`wJU zgn-mDvf=sPn`29NFjnC$z=t9wJnP7L#7Bz7EGS6yMS z{45{?bIGWmGFMBv>SS~A{oh%e3-c?R3j&4}sDDmu6kpH-!U9iU3KbHdWY7rWw|ziF zij}O-wca0D48fw2dPAoPuR#R~rm6%e4xU{lDuKpCPke6{ENlTE2F#MN9MB87&_aVp+6Yqp8_0 zS{@M2qUH5`kU`6KJ_#q|MvDY`m1_$Utv3A4Om4L0u{gWeB`2Mx4X6~9Fw`?j!bId#riiWbZ43d$R+@%hXl#zS+K4)JAh3=ORpn z1|Ep%M5{`Tr0SV#x{(w)Zt}X0Z(C4Ef;0MmC*{WzowzDeDr!ZB_$jB=C8t!m8^)s{ zDjDDQeBpTa=CWT>%;fKw@pF8K#ve)Egi|{lC;oUb?apo;FQ?+Gc>|3Mhhy!VaWf4k zYx;z-mm-`?A4pd?d8c8O>fDFR?xHpJ84?b|> zuW~$AIL9hOio=PAO+AdM!Mg@|vk^M*fq9$py|R3nsPj1gGvEDc0PI1=$z?`Qpr3WW z8dbz7zgS4NM!dve91O!$L2V#rlh39!>d+NLWDnICtTs+AAMfAUlyZ}I!f^XXO{8@I(e`z`-$Tj{;Y;yQ7tu+2DH~qZe6kr$^wt z1LNOu@+#?S{40+Ze|LcI4U<}hj?3=%M!Ur%$kXT+6+5v8S{HXw6&|31tiZx>KFkJ( z!}5Hda~cruAE6lU##YRAVvXh#iTPX23BaBR;Qvj7)rtGe7C-${EKySo@P zLm@?O%%ISr@`(EK{Gs|lpmOoY`a|sif7*A9KfXVd6F-k_D%T~c3;rC>Yl}baJHnsV zq1(fsEJ6e|X7FdZnuPxVd6t^iTX$$WeqXof;aQ7uOwA$Gxro!6ngj2d<195U2o$?L zXDMNo{G?L962s~npX-a2tiC+qVft?zWE-tBZ==MLfiv&Hr$YSMs4*v&hSA$g_kqXc z_fLlQ8)x3etTS(ub>=ORGjGD4khfRyoXXA>KcxGh;=a48ILbge@%SJ8%<}l=S3JIn zf=JZ$lPC#?-^jtU8%WJcZ`{TO=Onf5`}-1AE>9-^8xS*hYT>7T3+6Ysg`dI=`YkNn zyn_~&4$HPM!*Ag+3PZtm-$@3}?iH4S*|7W3=#Dn*%W@h!h{if^*yn+^nGO5b@R#0K znA6?i>|O_y|2Ai5_m%%-zV1ukujLoh3Du6e-6FI3%|*4NKp7v^96s7EGGAViMYVpo zCYA*+<_VK4XMzt*H#itdME7D zitwhF(O!{Uj7O&@D@(ltPxAXQ--$aa2ctKOZ4IkTv}Te-Q;ebSu#Qw8cLL=k;*hS7rQvd&hiE2VMV!Q1v!z23TSrQZ0&{`MAG*DlXP zr{w_dQmfc_EZqxUz(zVPPxD3UNBozopFImZB!d2J^1gY38J81pBn)HSfc2>X#IwVi zYip~K&)&yRAfFw1Hp6B&Fu7Gymr>4JavUKOkL63R7cbNAxa*#h%+^Z?(8&{z*Vizo z2!_2v3Zx2Gnabze%FoEDJarbYw-S7@#$A)zOM~=h&qbwn;dIt%K^gq?S*iP1s!V&T z%>@=51c)ZGrz*g15S12=|@XOW=Ba{yGh-xQ`Q;8=FNEx`npoFx?>NvofY| zTe{SFft!aZ=Dvy1E^*6wBLxum76!dW>E- z+Sf~X&PZ>~c|An0Ywhbh?CU8xulwrt(e`zXeLXhk^~P`TdM{opzHwOcF#hA<;C*me zH(47U05V(oj8P`*q!Is%57p9e;?A<$&74&3Q8l!(d*n?`62As6wwoaWP62NqYAZl}MTzHm0T4rf16_vnY(v>c5d@$y@_X`7L03U2r)m@A}2Z`^D=j-gRy`AXEHtQ+y<}jD~Z|pOjmEHT_fd z(ebtOM%pXWgC6g=#Q8*O4(Wub#Q?fgjM)tzN{v!W5!Vo+i ztlxp?)YgB;zDZRB+EKSbLcg=dU>%C6$!r|d_ z%|r7@NMnlJY$V&yFaj)X|H&fP(_~|Q$b}Mk5JoGt%q&D{Xe$MopG`%vP2W%ho z!Azu&m-==$TA0tx+=BXwP0>XfVU;l>OncXkw{u^v$`BQ|JO-68R8F2zy~gjDI^6Mmnp#c~Z{%nOHQyp;>P4OiCq5h?O5XRIPngAj z$K%w=5J-*&DYb^f$uUMSQy>Lo7Ane3+N66uF%#~9?ODv zS-r+^nm2)B$};C&W-p4pi@8wM=cs}sIiYzsQZ{ukSDLY}@t7)ar7o&m{b;tz78Mhp z&Ff3;>jgQl$LsYgymsPOQ5S`te8kjocTS;@3Y{ZpN!aHn%gIc`n6KtegOsb=Ov9i~ zMLq)ivQu#oph=zm&bCwW*+5gT6aO9M13`hNV@2>{7B3Ko>uis`Zi~cA-d~xkoGB@U z{pvc$zYe}{=u)v8yf|4EPqh`}WPbr$N%}WktGOU3t)RlW{Tm*7*9$41TH{Y|TrZ2tR|qUP};l3J=bJr}G{%59|hzs^Ezu|BJx!3~Rzq%#QW6^kUe} z6?!4|TNZ+`2>Fd@ZSpSJtQfx?VMnMAdpd0CjudsR*5VcsOz3kN$&4uWoWWa7Rz<_* zCi^Y|XJsDtbSc$%$A8mO9wkV7S{=6=<_keZy;YI59Rq)s^6k?i%2eFsZ5(I6ou>yj zYA|IUyv8r%z3RWe*Szn0u4&j9$eB94NBsBG&HEmkmSYOr^1=L=*gohnjl@b!^F1oB zqt9-v)ZTrc7PvE-&}5GWdnZL?WIyZ9#A3YSbt&Q8=b8qSWHxVotb4vO48>^GIEeXj zR+^h1uCxRk@Q%U*`ECP=W_#ym-WU`y#kBtArU@VzUgiI4Z5`)tIOxsWy zJiK+WZ|kLwVecg$b%RIVUqG+)GV(Kysys4p5NRnl7tsMUo1^48XRX8VXSeuf{rB*> z!PQZ?*2Q1Sca=(1gcDa|#yX{O;vwmaZ97I8jSVfkd$##7K*vtC42|ath zyj&md zp_OZvB?lDmx2WcYW1}xo(`Gxr(SD!o`z8o)aM}CSv6^e_!DjZ@4?>a2iaU`NLg$)f z9DZsXs7V|1&oz7;O86?}XPxQi?8AMsy6lUj>nn9;+(KWB^vFR^X#ra)YwV)?+rVfMFU zt+KLx7g#$t1@$c3CP2@4@_Ub{s>4S4KP{f8Kv6NznSKGtl2Ix3hY^%6WFu# zQ7}7C05eIw6xef%iPE#lY=vMML8HG|&c+{OP!Wnvl?CMac8e_a(I7W#qqnLoyVVtT zLIW+6W&I5rknK&$-ha{CXs8M^)9)vH*YulY?*%e*yn}}A^b<35C&}LZ>HiMXzoTUD z72v3ejUjrz1G}l?JJ~swW$F9>+w2{k>6fycb8@~rEnnxszmoU;L$E@zn`&*i*8+rX zWeWGI<<~Ne^8y;8QfY|3t^7^W5ZN@0pB^qY*d}4;6y&9J53|R!Vz2HHrFb$bqSAWe zz52=F%R^R4q-60$sc{@?JJT%Xh0di}&%t>83pA@2q{`5&6RB@UG^>LCvQHS1!dhV0 znPwexST4<)02+FmA!EBmvvi{V_i2{l2mYh!)=mszc8gwh>+rgPCQ9L6V8qmB-<_IQmuLv0z;?6Q3l(bTbPmiD6$F+H zX04XbA~u(wA=KnB%;a??hhZiXY;s_6|F_)jq?F4>fvo_el)jX0u!ba|Yy22JWUx~L z1b0J-U_wi3+!xbhef|{h!TDUu0jEgO1%>y8EgNgfG?!y_L09R7-`nb8KneF%8co75{1Gh@9eW-8sYpc)8>m)^?tH<&pg~=7I2;84wFUM(a^5lKv`M-WKgz0D9btHOTt%|mAhN` z8rc7A7hfZne{o#Zjv@OE8_RYVxY}|S%uISHOM(?You85UxALf;T(ZBxH3v+QFtAoZZ0&g6N%hu**T98dxcXE2qXo zP`{XEhyO(A8on35SnRw+pWxIVn?0+KPZ2`BFc;&mbfd%o(#afB0GN&7{ zR+)I^sS2cfopiH@H(A}R`OWBN%bnQeltkxLib2a~pe+=tv{O9R%MZ+A1M+Q7rf;Oy z8JWboRzGawc|D$;Vrw_QxwY?=t^G|XoG9=%<}!QawD2Unn_75*!e11*-wTktb|=XF zGtobvJ;Q6b3v%Dsw-a(N=QLuF`v{Jb-e|V?ZIRoo!~ex=5rqE>cs(C+ZzsGyJ!&z} z{N`d_br$pT*fzGo>z_h~14J0fJPYeS?uyrIBDQw(n_K%TB((mj8I68?yLf$EP7Ckp zWK9cSqcEi2uoD5jN7#)>SgxzT;+?b%5LOa+0RMp?1}v+Rk>U{eB%0de9t z@nXAdNa_c?$=PSr;&EzGyiIh5@*UsX3ASq|+0mO{jh-WR0bEt76MF#9f5xw5z~@NX zjtZM~oprrBfrSKgjdc2K1Ksyir&G}9BLjyxL%HN-BkHAO3zty_hN#fFVKJ-OocYE& z_I!`L7AX~C1`c^T-|4Vd$akgY(033WlCUi7ZLT#RmUxHpp{Zeidr|7`&4uJ*J@_RO zg~Q-kx#sw(xU?-RVSVrepWMfE-iaS&`%ns(Ut)v5UJ$(6i&vuNIsk}7w7dn;@dj$j zt^7&4p|DaGW*dk$Q2BvD4GU>3IOy8Sx9;b+`$t}Ns{C%y&HKAxnytKrr9hN~PC;}h zPt1)J`$t<}J&I9^=^ys*c;xt=FQCX4*0h0ktfy0lywC`FMm`=XWL%ueY~$7Dh|5! zc0^$3k)U`gh2%th{O}@5Xf>otvC0YL;W)|{Zktcf#AB4|;3Hh{<*y}~HRq5`a!_v- zKJX{`a7Gk`E?BE(z_N=g_Ady-NlWh<4w>!Jkh;^{rni2 z#KRFKWZ5=_6Bm$R?;LVp#mg2^UVpk?W-rZkdvFca85B<1f-)nZoEN;~dVO$>YKz-E z#;8AC7v@|`O&&a#1}V6f%s#kowwLBx>5lZLdZc^`uB&pc5!Pp(Hw4!@dV1?>qy{5I zrZaORMGUEC!6qg&Y9#8TFY+(;p3N53@N*Py=kH@M0VHY{Upy%8D>QnZ)nRBdtvy@ z-IFi78v=UZzH0pGSM?b1YN)&Qr^lP#-4I=s>rY?Ze}((1ySQzwN!-)6s#`v>t%^>l zNgP=1E?2&n z1pgcC)BIYNh!&fJ8>&jS6Xhx{2E@(Fe^iy z*t^h7n3aAoE5`hkd4gH-3hI(&Et)=wnQst1^%<7GP##MsYkrEn1}%FU%NjoO_g5K$n1#f0yj@N3M{E}-K6WqRzON2cys`ItKsL`FXGA>WtY-E(K=`!8 zIM?{C`dDVL|6bJurlF@BQ>7KH>IW}`suX%_FH$wm%xm|R_~;(1W=u{hmvK$GcUKkB zZSV=Eb$uiIn-ZHC@SN~?-BogT+V~^$#+kd*oY^BQxmzEe_Rp=zsmHq`Nf>wx-BrTC zk(J?CWm#U-4=$T{R1zdbuQ`YiJXPMqpY$-pR6_*8bKvRE)*pqo9!3SH-)DRHKLE}`4j@s;1hr_tz-zm zwR>iiCSII*Ls7&HqzlOJTkhRrz_6uX7`4T>F>Q~7;3 zK7wL~uz*nBetQ@uH*9oROK9192Wo=`nyJ>#OjH1fVRBr?LAIY9Wcx{#d7{;2_1l$$ zEYYz72ifiA8fjJw){o-L*JoDuZ+GV)qka%{SufGxtE@ zlB3Vuyf;`!-sReS)KG)#-A;)LcbIiV`pjx~y##CPcT2DqCMpfKR8@jikf^4lMwXz2G}H#9OvttF8`bW+1QF#>n!do7 zJFf4l2O!xl;bR~VR=Bz~)c@_8icg&Q`N#!YeH6x1Q#iw^(*}Bh)7lvvgtzAkX_I?N4u7L1j`%*> zCVI;V(K024r;0!|{Y0BC2ZTJdT~J?Q>&0% zW%_S3PmZiiy~JC|gWXDeDj}RKX&oy%qBGLBWoVoXYjSAZ`TshNo4OMkcYBX4jq6_= z(71CuVeiM^ve;{WbFep7mZfph+(P6?<6MC5maTe~cWO@6^B_yP6mD=gP@N54a^tWw z<1tpM5v`pk9q7kBw@d71S(MzNiH6f64_M}A7qspFNxF98;2eJplTYbip>KXZB_}4+ z=S;For{#Wbzc_{a;9sC{TH2j(WYIS*j+oyZ9JyhJn2l5P!7qd7TD#PPRz=j${V+=_LZNu za;N2dL#k4yQmWY=b@ulLt5*FRjRy5UT-MB;Na487q)-8V-@zW2x*0;L1SK2E)01lB zL53b?9I{N{mLP}=QHIByBx|-zT$e<^Zx@s~@d89gC^ajZ$jiQ&DrGrmImLNlpEXY1 zMj3gE%u?s%?Xe$(K|~hN zSE1DLJlIbA(Rk`;*0;e2!;U)BUl*QkORj(1u{v|+IRFMGmt5Zf*5r`ud!RFhT;C5| zy_)>(l56C9hK1M(z5WTb;s00k`oFY^2g!+@mKeAH8of4Wm*23Mc64@W{X9FHwM>^e zyQGc*70jnISs^?6v?b@$eS%LjXOk)aT&*Q-&n7?SwO0e;?AF=j4u-o6oG>{<|3ANf z`{$D;7Glo%%QJtJ2x76N~iicH>3@3L3_j1 z9*=Bec{FXcK||Hn21MeyZKYm7WZ&t*ImktKFw7>c_EGKP#4JRE)E(hQ=%Tkx*GG8;qJZ>YoT(BvN3!sIOTz&|8dzT%A?$JZ!gW=?)2Cov$UU`$CVpf~nCAWvEaoC;a>xm0|S!DxZxnGVP z>fcq33nz;fg%cdUTMNg>EQPhSK%r60~6@gQ5!i6h+ZG+_q>FGlGFaD^15 z9wcA@9s3OWY9`|t`!48QdS3Qy;Cq<51!bwb@UAnAt>6?`kk1b47}llXUj{D@=S7Z> z-axh{?`q~D7gBrMgN&JhT=Y9Hs6@tyx#&_AyqKVsnsp?+o{Cap^|$HhKEW6N)upOW zKJuaP167rEc3drI!f(*|?H$?du`oCj9w9>+KmVx72NZH&l?wQCa@XP0g#*)7cyl9u zmp#NQjV2#Oi`GOqi8m1IOc+(au0W!&F*Fxz??II8$i>QwSy=CGMxLkR0^2dTx6Yfy zqL(u9xkw*xhHwYuni!4^&5P6tF9ri&93xfd@75ORaD+2gV~%Fe$2)S2L5JWj)-8Tt zX;6NDPd*)>+8@kFKY{!#(S)%}-+Qk&-m392ds9=2kQ29{LrVXg_s<+ef71WRo;QPdy~nDF(JRd}A4?L-JbuUqLLP}4Tid#Pzs4zlRDY%WALJc-x7FyDcn{M% zLUNMYrqkUS3jLaX2wOe z?m{vu4PI#7@P1fhRCjYD#okY($pr6@Hh5p)F1ui^?c%N1nl3JF*gMaCUGc9Gd8XS1 zr>^+w=RfgNpRAAd%wHdyE|BGiNj<5BcFI>Yfn&yEEh8`AGs=vxT6tG&qDF=)Igp>^ z;`hIRe&lAf=#pR2Cpz&1kyhty=gvh|$J(tpuyxodczqsU^582dV#xBNKD2oU#MUc+ z1X(0{Et(nAvuX8AN;4FNfsyBo4mR^Z3F|)7c)TUYC{fQa@0dH;B<71s=8;^*(Br|a z^0K8T)?;-%YRIk;0Dd;pC(1 z`OH2m44#p|2~|_Mo|a;ilW3Mn3t1wa>5ul%XOkP91UhI)sO;({dXW*Sr#K3&$Q+n+1<*P<77m z^?E}x(x#F;C;kL)EET1_LX}XxgDgIqa+)HOLbr;V&8=`ag>8|e(&burwIpb%jXj%B!L##*JC786C0nqtEm}Y_ zt$)-FSXuAxAKEzTR4QJgb7%6Ra5(nvW}BcQAg@L(RPO!S2g_C!gvo9&^jEIh%e|9Q zFj0v;2p0mEeN8!GtO>+Fs*v9ig>;>{lHrq0ZS1WG-g!Q9+GwBQX>D~ba%0=58k`!UyNc^8Lt8d^1 z!PRsn_Gr5ra9T>tgsFG2M~$tR6Yncb^jqFh&)BV{&$Gj7mN6H5^ybMGJv&-Bdf$-~UBoEsV-Y>6Jt)Vdp> zJEF>hZmxGZ9&rfNXYNZ2a!>+=FD#ote;tm=#R<2<4S}WJHxiW(d7Qox#C0V{>oj3N~0QU`tk`n&3M(b)5-z(JVKK@4`1f0yE&gI%{xiZSZ7f{ag%N2Gm zcZVtG%rq(W$Te0w?3eA7oHU8p3(L5uOAK5_9Z(r03Eu_hSxP-HWX~+6u~d+{f)@d? zQv8xr47z(;I6r79E@iS5vZ^FiB`_pUoI5e6hW%B8T~1%6=G|CMODlurbP)5)a&mhz z&8erDKMObLKyC{U6I(I0KYi3r*)27m!wQ`^bb>j|{5A35vn$6zZ>x?Q-EcCB;>`CUA!Be!LhHd?zOb5YDw!=#kx0$}NFsjhVa zt4G%0@B=W|x*eq3KNp#x&{GR}P(|I+%W+&Z(#MD3@38SVq(iOI<$S4c1M9sJ`5i2%UomLP%I?+&q*Xw$|_-9@_inId>QHj*#lsBz-cS~lgTDZVqD#@KKoT4j7m|ICO~qSTXn4X) zG}DFZ&NH|35j@Ld`X7EGoR~3-OT<8oTah#pM02|S+e{4Sfj#C|!C}*gzP3I1Z+$;; zq4(W^nmd`o4nI)6Fe~OYw3UkN5#3X$xDdUKJ6Bi#Egk2yXEi6 z2M*IKr)MnS-qpRnRjSivuTbp0f(YjO$EXh`W8kp?e;%Bl2@L^*D<)eRZk_m9^w}hI zOPs6ZyH4DmLr)>@B6}o#ai(t&gpw0FINnyQSIWX7k|!DnoXldZWx8--5VNAsKQ`dp z-+tbw%$a_OY2f>o!W4636POQP$UdF^7DPSH7oclm;M>X%eLnL9V-xD&+`_RYQCU{& zjQ*h3Ig{{z!PD!)YLq>v=-|5K)%mBp+TMd+)K<)!bm{4dfg1&p^J*~(O`g{+Trqdz zF9bE}t8+i{YrpnfqT9jKkZq(8$~wrV0D6Pe}d}(14feqa?#{p^XXz?aAEp35)(hd{IcH79DhD$ zu^f zcD~`sHl!2T^L)+Vjp^sIx8&ot$+*3{&xGeCNA1t`OQ2R(PoaAy2d3`cO!JB-CbOwI zKxgpXMB=(k1(JR5Dm#TL;AfsK%$!$!c)OqLw6_S*#anf9Mu1YMEPc?!Ix44Je8X?iAby1;V7jW1<#|WEA#;I2-UXfeaOY2LA4dNReRz;vmQC-jwos3=YujR=ex$;B)qGgB&&xSnmD`etq;< zUV#9-6&f*ZjpEvb-4)&mZ^0zFtDX@N@W#{2!L6~+@;RmgU6n~zw|l zkANgIEb$*eZ-iEZ0g;{BAa2^h6i@#>vwsMN0o7p);#?w!LrTfA;eHnBzXPCM@KI*G z31mYvUR~Xx4BORekVt;3x%a1M3^TEeTen0quPUbPfNRyo+l*l227^dK|EJIJdPr!{>CJ|I}VHy5;4>n-jgNbvJ?* zwa~1m8>zy?QLA;Al98U?7JCa>UD_Jlxsi%GcTk<%SX$?fYoH}2WN)({fP<7k4(g8J zG`tL;8QEm$BG?sszVhaBP$Kg0djTFmbqc*d`lqMD^mDoLw8ZscZ_F#ynYgChJE%7t zV&a;y-oCn!v~nn~g7Io$e~vv?vhN(>N^A|MRnSpP4rI|t_||&AMV8Edbpo4AiT2$R zl#i2+g!?NFe~V8G=3!{}lI>?W!KU0wDwMC6!j(kVGn8^0RL{b9jL9UQJog}`pQOgi zfR{IRKb=pTuqOVC?!(C^?$b|VzY87{vZZd{uqD%9KjCr)-wh{x8>LLnWxF@QLQTkv z^b7c2cGpTkIyc{2t|3-jG+|0AoSZt=%R{OhPCnJl*It>ft;W_XSt`&?1<6}ld8a=v zAGKGye9*u2)-F-Wr_^2VWkw-vXF|#7yOcM=$B!%mW%_Fno+F`Wez^Ms3-mw>INyms$#q@wTVqYaYQtq2V&Odu*;8ef z)@jjNd=Dq4nfj7Vh2HwTt;yzJRH0P+H`%8447&@$-G`T&<_Izu`;*^D<^+C@YEPKF z(}aN>{Ib=gG)vf{e#KM|E<^mU1JyiDSB$9($6{(K-+3gOm+A#g8$ZkRU2=S;x|r|b zZoHCW&79N1(aJ*Ie9uFgRL$ORDX7_ypiaph{||NV0v%;_{eLHrNK|lQ4H~P}SYr)d zYEV!jUJ^)P1_z5pg=(!-tzxw;l}U)A7@Y+2IGvVWY_-*DZ&s_nU$0uN3gM2nRTNRY zf_UK!BSN(TikSEF-RF5G6ZCiauk~N=dfzN%p38a8WuLwG*|)P#*kW!c*U`MC7vXUM zQ`5_V++N-@aR=Y!W>KrxyIEs;C)4g!aV=Y+Dm{zw9A_5Ty3vgWjr_^?t$SxiAjhwB z)gjK9KLB|I-U{1dA;^p?gDo{@zJlm`TbRAx%!gR7JY*In2z~X?`4c0FXC~E%!>^uY za!I&yiB2YQ0T}0_iqj6^v@x-uQ@zUqa z?E8Yt%lzTFeJg?oaBi(|=k5h>$hL}>>s^AIT3(KZh!KPsrGQsjI2{@5y z1S?F(Yh*GJhk3%nfvJFt8ePrFtZ6fC+)ky~J|=Pyf3%VPJacB%7#Z zvCc1I8;Ylmk3&aO)rZW@wia2?16ut$x418%^Z zqXmsz@n8o(p+KXGjHP9Q^|pBCc720+pQUbi&zO#DPw3r??6M4sRPL`B z9ibT(_(`(iU7w*JV@)ESu~jKP+SaL9S`E?hKd5P`rBh@qRc6_2)#7+?zoyropRVVy z>7%W`@nC>f$Kg+R%)Yby+;3qJ z!35q8-`w;lh!)y|wIWP|^%J;|Q|99c|MYwZ+}$AA{(J%GU7oLOaW6(MV?jH$CNqz& zr`w!ElDaRMZJnAxUQ1+VRZq-Z25H5)9uHMb!iqf}b*#PA*;yf;{;pKvc&5G5eQs~j z-)vB1xqEyMnYhCjL;MTSa=H6s@r&jg5teX0>BT5S;KCP2`xo%4%tr?T_7Efif6Pmu=hAFqw?W zw3XW1j;9z#1c08wJ}3aJw`5wYc!U^ilk0w)BpA+5H1x$>$GR#3Rc;0U6!@$~)8S)q zdlKkI<*`lz30Ox=8cPPh>0vYl==HD&dD_U>d#J*&KU=j1r0k8CF3urTvK~fXcoLd< zT`~DotE7=nSs(e(ZVAtmN8c~HMRgn8T*{7y`XKAnfr}r@IeJ~7*ATSE4w@dRph#{s zpBLWCp1{MBT+Ehu-)EcrCskdhZ}NY|eZoV1_|r)whV3^0vAGSxs_elL4q!Nnb>2v<37;K`jp56K&1MSUKAyAT)yG8AL0o#D_u)*RgO7QXu50YlAkgQMM-=7G! zv&!G_R<}A8unUmovc~+a4+&yEp2FBZ&;9CD2cwaNMv60y&8g^Zo7CGD?`>=BZ5!3w zR^QuJ*V|Up+g9C6Bt_;#_bu&>@yh@qE|3kM58s@S`ha3Qwe|em%{=jXM7F&?k!`D& z+~?*EfQ4k+U_i4g+%??51jbEEWZLS)GGGR-d=IgVHUxJRuN~!5yi72887`k__|}ZJ z(_tutl#OtS%$Y2M=T71v1DM%~?q2eu*s`>wHDdsTPY49N^NDQvVX|%m079Bbd!NWG z)TB>}XUo@aQ~H&ylfGW^b;!yhFOz5q_}@plYj=<;8%ks#OHoDPL;0T<+h3?~ssxZ7 zp=7Wz{ZXlaOK3T@w@wrLN(5E~LKllabwTnh{#=mYn8lxq8ZK&dQOAX;B=ua>>&YlC zOeJaLqR~XEsYUv@!r6u#`z2PG?8u{!AYui8kzbtDGzN_Psy@-*=0(!ncGk=7Yhj<@ zkM2*pYR^7-zDv4!T=qngxn!=dY(1ht1wCSSaH-=7sYH0WfR6=brH3J(;row69Vi}F@?$T*jOa4 zDOg_DOFZ5gWz*mOUVO!P>)49%H9|*jD}5U~2F)7kEVi`(ictT`j@YasnEsx6%!BhK z95I4uq^e27EQ}9(LOe63GBqfknZS(36mYdiJcEk1PdrTHzhX=XoH5q8Dfor&BmF)z z#qfcUqlU#Zk3v61I+;)!PrnaWJp+?l?W)Y!nzpa{$u7b>G3!~BzrNDAqyfYo5cd3Y zVb2L?tIq%4^QFK2F8q`K;y`zs>+L_*+;z$Mw0m08Z3AHzL%oG zxd?D_?8m0_RpUoNk=~mLB=ZIAVqhGd_eS{~ZKawg=|rhmi`GmxbfwK*tkYy$K1&9N zTP`3G#u*h!4DsOBCU@*?sS&LQ%VmWjP;bxHo44cHQ&u(guE9WYCXZ=VkAc|d)e;`7 zHA0g3uvLi4%j_~cBF2gnt8klE2%%NnzB>bdg_g!+@Dq)#HvUC8TX+;kV@bTKHe8F~Ucq|s~Xj_K`cg77xo}b|Crr=e=X>Aa>{M7?k z@x11!_&c+2eq?C9X0klFbE-im6vltF4#^LnFU>*Z-S#;Vy-Y)y5o-<5t*5y-Yjo6Sz*u46d6H3}zv10S0T^n)D)>J;r3XGqbh3{J=-7 z<+B}4z0cC^Kd6X;nD7Q;hNF%kSp();1+x|=vdx1^7!w{;Edm5pxBUiLfZn`-)n?dYkBX-( za+mbr!njFdL#97}jQq=M;H+Pu5@ZNO`&BF(vyM(?N9>hsI0=X4%#+MkKnLd(>2?0g2R~>$l0CiVIy^JPevkd;6O3LD!*E8 zbAMi_r!zw!g%vh(;^&C>gmx~y*pEMx3{HToV6o)AZUMWkBkH-B2pQfD=tjbchy#2n~|F@ss3${!DZg9eG4 zWvzin5Dd;S7wga9RPv=TgghMnU*CSDI zm&lIjnV2c#x~DXmff^82Wp)<6*j@g&^e(ks4&1bPnP`OhR3-7oVv zj1NmA15XWu7TS{mKAkN+y{q6WaL;0H(P!UIP*C2y)aPXC==`i!b&4jkf9=pb2ZSP+ zY$^n5y0CXWGZXt!bL}8IjFfosWbL5VJ%;ymKGu4B(<9=ckzB}%-kTUbZJm#cgW&lATfBblU$)Iz@k z7XYjlSFyx45i6ZLiKfHxSchVrGkKDKO%U?T$AhJ4f`mkG)rlG1A^%Y8p!m^uD9(`; zVo-eG9Xser*JG{nThw8}>x-jjp}FRbQ^4<8?Q9zv{+I-33pCS$h@gy?W*5O5@t~~M zorCEfS?I9%K%HcSP3|u<@cI@i?L!!M?|ORtasgh+%=ZPFb0$yp2PCbHs$U;n=ygeo zUc9I^L!If#A6NLkspI`)W1Vv;!c|RE>_>}QVh=nvu@wC4flzwtk`1d;$MDb0w_T+=3TNj%2rA5YJh^zYwat$#<;kAEkuAMfxJ_2br;!hTp)k^Gb`djJ%l%Xq_ntWrN74O>>D zem$}A|Jdq3sNeXrL%V4tf3=q*7}pP|@5Xp$ZgGA8j5l;^C~c?52X>3t;-kMSgqe99 z1=s67TLnDItZ}Po^N1Ic(Dxvd4^YFMjKz-UY|; zsqF1vQE3^s7pE=_AM!Q2iE9quNSsU^&&~vMN3BZ^d&k{M4NNuLcUoDT)4{0d%?-P6`+>UVI4>Nqs5J**2K~ac-+xmiksyhl;W6N&Q|Jm>+g@Ci2;c~H+H>r zU2Cq9XZ3oK2A$qP4$1?dUpW`#s;Y3q9tuBOq|`$dvCbWQgWHU=#wj;ud08o4*nyf~ zY3F1+tl}$L+bsa=o5G>&$c}MCD6%0U$cpD#*+G;$rJ6BOhK_yH1mQIb^Ei97sPl*K z*7?R!%VKl2;0Tp;KDV`->P`k97^Vp--_wY!BFb5ZzQx5ubSjMgj6E>6deN(7CgV)_ zE$Q_;_gvI{MzwoTO#ukT5$inKhJd5xvkyjKh;{DILo?eesuTz`z^k65fp{>xqV?>? z&dm$TX~P>>J5DcoRCldsmfpYJolsdl2h?03 z=UFx(vn%P{MF5J@=+9C2lpt4vZ*DxV3iV?JNoK!U3SQ>E1+ORm;W?~`y}2z^W%J0k zq2L3E(|yrsYEe!*!TT6WI9Hyk!AW<;pFNmG*iEsUm*>7hwSDC~&ZtI1+UR~H!qe26 z9VL6}l`CP0!9aIy^!#LXH+$;Y_MG6di=!8Nh2s$B^%F{r-wSOX{FBu!G@hpT;BC2Q z)CYU-j((Q$J(k;xCmJ6EJMcGtZ}f2tEVobiJc-(_p@UeWp>u$uQBOQrlzR+ixv+i( ziwo$wo}tqk@y#08G-_hjV_gqZJU2e9*WJ5@iSZoA=qC3BZ~EY4)9mK{+IMM?x-^^b z3-hHp&FyWI(*Z)1xbv+(AKm6Fyp9T8vwv*t$3MPQ?HE7Y8=-+U+2BFkNk9ES{8H~L z|NHlYAaZMe_wVs8R>KziEGU&eeIpFdwYm>Gf{jB?OhbLhi+%# zr@2bs-dX+IyQyD$(kIPg23)s|t1fNDT!_gpgPlG*^nhh1WxUcT+S-DpKOSp-9ORVE zie1Wo__oGV{;%he!<9+q=4dud)b#Sif}@3G`(O4^Z~iXP3tIn$bdd9Lf4{M}K570}Ibndm*J_D5#>*QVJG-EU`oho++HO?JLUn{VlzLly^$NuYZ6?33(HrtR)}hgg54eOm zabLdVBP<8-O6?H*NKZa3&4z`#K0dnqyVo_q`+pbX2D-vjBsiGN3Hh-%fh zuP~$3P7m2e+uQnc&M!@0r|lWCr)Ufq7}Pad9||VlRuT5q{pLcmLw{S9eCcAkl)kRA zBsE42V!(Rat&v&yV*vo}l~s!0X{po<`S~_plYfRAk3YUq+WU+9#eW(=Q;*TT%KWc= z`LI(XKiGFji96Ky;$pg1s;<$Q!BCLj6~ayL*9>7BpA*6Yq15+PBnQA$W$tuH%ukdO zaS!3n9UHcp6i9L(^zlua*tM5$;vQ;MZix(ZN=IzBkCZQqXfFGRTOc)u2E*>hFM@hIPC zuZ{=LVco##u*Pk_7f7Xd{Fo5jS?ubaak){4tM`M!)Skj|+dkc*tloAH@fiQX#NczO zVLI}$;OpXTElnM%DtLcg zUuR8HA|L@HEQ@%2`|9|j{OR$FQ!iC=)=i09jaHILy;OBH5A^=xZLa2<;^tf2Ewexi z>N2SBCWnggOw3NJl;w!iuHPX{Uq*jvg~8vkB)NmWYLc6D<2fn6VD!lRD&-?yDzmJt2y{uV^hcJhs8QSi!j2@%1@`xKo$k@7`F^ z7+XVa050+fd&#K4kC=~9M&7&O3B)~Eeu$u@G52pHX3xJA#R0y-nNPvq8V-4$S|}Q_ z;1$9h?7mXF!`yyI=B5gaDr!moquG_iH@o*l;gS+%?K5+9a0QqpuaBH{a`;Ig;g@|P z+cj^w@$|}nzkoddCFW_(KVW6R(~KI8Tt@E4?AIr}at@WVAL{#>vz+#zknCYI?xr^f z=C0w+%lBIq;V$#r3ey10T-=AB7+v+=;`&r1DJinpJ^^c=jnIQV8PQ<89ip^LgmaYV z?|6?ImdqR^nj1(`zag3AN=e zMzY!GDD3O^?vtYa3iH0l{Fq^X*W_g8$fitLEgizZm)~nX?KU+WTq~XhhYQvQ&->)B zrH_$wceT5FVC&0zQxmMEBrsjp|;K=9xx% zTK}5=UD5nlk!LAFEFgB_Z25+;x%~GGAMO1E_P&(;8rkxr-uB(eT`2^HP8%)GRvp*H z)aat!Uv$=X=z>4Jon{xXNO?B*d{V+DvKp~WGw7MI(OBowK0^ zF-nBHF*$Zf>wjzkLra}#N%n%pu?1(~w4JGx{fC6~AFK+G?H#r%TSf7G@D${ORfp{e z%4#QOzETOD$o5;4MCh$c2JdAK=FHz+Ey~37iu^Cz7MHd{{1dAQceN1q49>VIpgzqW ztK`(pr8}Ds%a1;ow8@9V{`xSuDO05bL^o|)Jb;xX^*~GTMgkKZ@T_Y}zriL`T8(vn zB*2&~$!2SWXd;(gdlmUYujZLx3QZHzxt;42 zp9}+idaC4LzI7Grd6d3R2ASbjE1i}IyLWu_btS2C*G|}eQ~IM_v93VU**z;U7U6&c z{c_jxz(#Ix$PEC68W1qBfx%4^nQ=A23sw{ZE{*3V>if(2J{+TUiY#>EovsNzoM9TO zY)!=ec)f5)w9`u;I_X0{wCcJ?O=m~W1VBD1*;C7QFEZD9$6*}lCwg;FQN36Xvri8v z1P8y97zk4SO}2PW#@YV#VUBcF5LCgci9pwYM7{!P?mosT zLYS^;6!K+1lK|fNeQ@&OllZVQ);S*^0C~Vvp1_n-kK%P=(HrFxGF5~fJ!_7}J?<0& z%F)=mLYOffL(dq(`GgXV&(FxDjzc@48F3X*eMO17o%-z9%-P2=pi^qokC(bi!?RfT z1AO5NQ<9v1ni`hI=3Yoj>n5=Fe{q;hGiKAKbT28BR)MDSCpHH= z3a6kh7~u1G+Haim5*rrN15Qi)HNE3AvUvW1&su^H`yZRI2kQXHVnLhtV@ywZ~(<%8cAX_@OjIlbt{oAo13ZR z9P76mJKh`^>#Cs|qzqyXCf76vPb4#C+b3pf-?1$?@zrnc`A$&T!(i9v&dSEO)8J<8k?fs+Cj1`aIfR}hF zgvaJxoQh+K)&$c>C4(B1_yv;q>h*HkGwh~4%l6M51icE`!Hh|9SS&i!9$GNpM%afY zN7l3B7@S}=Sm%zKBApq!5x+%^AF?NCYK(`)?e_P?vsm0Xn_EWp-7CD^SNO(pRLI0z zh0mY6TZOj}-x^hz?5i*$gSe%~N)7fj3YvvlgUo$&NKSDt*=5Pl|LV^@rR9eBfyPB$H4&LX#kNF} zkP1<`3H7_8C38$|?8Y}4cN4wv)P_-i$lk)^mj5GSyA#!8cVauMcW}u&v8mp* zO@n~k80v_Yh8&g>SjR+$^D!!`x-oNnuvH>rtn1e-LnaAMgjYjlE1|L#iOj)E3?V^A z&J`LUDid*ud#wgHAdC?oC#8e;Z_1p|6uj58dUI398v|NLDX#*wKT0n9=2G|Hd=+fB zquWwzG}EJ+9`*F}M$`5+&4<0+6r9l1z~KsWH`27vPw)A|b3)T%iqbL@l2kmXwhN)35}*^92|pp3sH- z4wPAEx?PXz+b!Ic%DTk{b@eOOX+9S6AQGSO9!bG72ntgGgcSYJ-4{CB-fhFtgj9vg;s#(VVjz>#|(%qDDCWNbuEX1V3VomZE~@OM+j!ikkDCUNBjwq z^Xo{Fu$5f8Cmo; zzrLm6L%2}ti^U+yQ~??y0}M_kmB;M-z>W>2>_7gW2qX6<=uDmchFhlLI(8A3(_rfl zT7qTytdI@i2l0NAap>vd*As%WP4?_;1Trrgy4*d~Xy-)iKbD{Pxl^H!+(|ql*igr*t^e`%T_=CNhn(>d)|L5Tm3;_{*SVi z4+8)HqioeMux(7AT-ADFzZKwrB~u+P4)zIb^iim$n2pW@q584W*xdW!w8hMCJKPC8 z<2ZE5CPfVJmFPvcUWg`T^)jp-gM#(RSbLBE$b@Tc)%I8`EQe6P6V-U4uMr~g+;hJ1 zOgWRykOQr`RX327PrG+ekP*xnqh&R?3qgbuIVAr@K< z-y9)dG&%tyhjGuwAA9b}y#&}gxaWw_Zh@7nbY06~>slHmxhZikai{%PKqmKR=BlY- z4SC2@Q;Nq67qpRLp2)J6R&ZTmeNE&fTp z%<n=Es_qeiP(B9)Jf84`Lg> z;e*CQnXFF^L@uj+(B8(zuX1}#M)Stje@J&ZbGx(#f3B?X&3ud{{e0@{WCKPVYsHFj zG7HGe`GXBSSuxIh<@_4^jA!St@o-#?ilk4*+P^Nl@qmaT7ds4LnesgRpS2FvntItgX5lT3;?lejmT`9fV& z@2jCb+dB@FPfadUUTMGR6@)wDP0h@zLC|mX&@P$6Pby1EcuEt(GINV+gi{qhT|Zv;bs1OZp<}bB%y)Wh6rVu5uOQqO_4^z28#5;TW*c6i z--=Z7{XUg`U;bbBI~??p#UB?2J&SyA{rek@^H2T9S-{WT$7@rmd|8Lz1aT-k)~C7X z!)J>>VlPzio;i~i)H8CoJ!^y{N7Hdwu%&9ImX>m)RwZe|t1y(~x|Yikqp>nFc{jGl zXSee|2>^eKN$J$|U;+EWRP&!Evt@fFM~|O0tJXWM!3SZ;z%O7ndeR*MQ;U~gF*O=h zA->D|yPxyZ^q#!(Y_<7k3mk~>Sx_R@xtLb4q}L69ad|UYu8aY^sg@hoa@bT&8|P6} zz0lH$eg9KJwQE4NGm@DxHAJ*>ZbU$C1Lcxz>RpxIu_0B5szR_ty5D9H?`P_dZ)!_P zIVh`XUOQ_(J0N1E2QuwT31~a${Iom7a7^1m`uX>ll-jp^6Pq^`HkV&+^=C)Ey2ipv z-LNG(;w08}Brls*w3M(=lNh0_mLD;X;!x2`=Uc#i?hJ~0Iw*?IQ2fHXfGOU|@e~+k zx|6jB#5xCRdC5$!(>^`<`(L8gBtZh?+93!iiwh0LS&?XX4o@-4)NQ9)8o z__BSu(5jhS0T@Twx^hho-HOMWce=wa(pG*%*=S!tyvVQEhhP2YMMINco&m&eJQ1(} zvA6-L-^Vc6k>7qs@P5ucw8+EzP1XjpdK)FMM%4@Qa)#9L%lYe~Adu!jL8wLtvee}2 zXu(JSd|7P?bng9oxkA3K$Un>ZmuFV6wK!NgY*oWksR8dU>9~GyN$XyuQyA> ^= z51YTh@VzN`BE)E>ob?7P77+6z$O*v{y8D&lpT1 zJ|=Uyz&&oU%u4O&>3Xjv>fS(7^uZ^APMGk?<0e`6|yXzt0Y{22jS z01T5FV-FDbv^B_u@d@kPcbIgDt@~!{3NnGd8&586J?sd-tMT6$IxtQgjrPq~?VIuq ze>jD#8cpe4<-(Ow!WCUKMi*0~i)nTNj?@cLCe1k-kGVh)xPG|Vp<;>z?v%EPh_cr9 z=jpTTkj^>_Cbi8GaxMlK6XR$4$eO44PV!j28~43kz2c2;>j{o57Hd1Chw{SE@ulWj z?S9!l;I$ny)RMifRJLUBy>ESB;!nItO>TFKM&VWk|Bs73P}%Xp;i=aTX8Z?+@Vis+L!u^9%-_7 zk9SaF%V)Go>Ij?n+*?0YUZkPN9ytUb=X%*XmGgQXzUt3{-RFaE+EUvGpThbnPCG3# zr_vquGsR*f)TKu=8Ov{^6c*I`SsiOV+K#2Gr38@sB74b zsbjQCOWdwoEpWY4$?LQVHOhFtw#^P1YYU!dw@?VQjqZz@PgakMSE@-f`AoIc1WVeF3|6?O zxS=2IpS7gf&B3dL%~?L>U>Qz=yuWw?VVm0#P(AC=)W zP+mdSSpqQG?po=lXthl*Wuk3A*Ti7Crhb&mT$Q=p~?b^f*tf=}3ohNW=$(@8LOi%|l z?C>YiEsb@{W^bun!B=Ic-0sThO|uPf_6?dv@JX#k_@rR>P(Fs~y1z1qV1ijBJ)AeO zaI2B)uHV?(u%u~u^Ra9wI)Um9|F&CWt`dp>(}Ci+IaJ`A=mQ=E+Ng#5u-Xv8VY1-( zHNUd2+^6`)i!K)e%D(=LeC%-BOL++WbrUJ<3!Q9*O58z(Cz5?^fBLQk9h9|oT~dmB zkRf{lOEnUAJjx9^L!fFOi`4*5IMm_aUQnj$U!iVZ93_9<*7QIz786MN;N$N7Wh9S~ z8kq5D{k<-dGoG4n3w~}nHG2NTz3unP{h3EvH+Sc65~CWAsi#{qVTGh%44z@WmS4}0+`}l5pbf}zRz}40d`3{z0LCVnj;RIs8Sma7l%sUYNeVuB3IJ z{HW|$&U0x2N=s%QlgOL{pCG(i>FRJ;F;3tzwX5f9@+?MjY`Bj^5Bkgiee0WFkHYvy zpJsJxJacXxe6q~+p?gi{I}kMW|YSK$bo>*;B zv^GG3rrxK>p~kGg(Dr>bcPllJSgj`aHKR(_-Gl%Z>%5Hn1=D#OQsc5xca(U8mb=9y z;pB~SbHmSQ0dYes#F%OBMA(eVz+@|8ojLU{7{j7aekwNbWN>nP#TaAaE5;}lyEoyd2tn-id%?j81O@9LBidgq+TFs@c_`z-{ z$VQgm5}E7bRU-9We339a!_-Rs(s|Ibv4#puyoAT$pPw=P; z8D2v}?ozG{fTpa!&~}1NZ0;d-LNIVG6tK}tA>7flS8>Gwg=k! zz9tmF*a7ixH$hz{=MZs6a%m?TRwi*wUB5qMi`)+bXJIxv)E;e!Yv{WNTmJ{pe|F3o zBYO7sqD>edlh=wjXiNTzz%_n0DxiV?6M0*6sA`68$R^ptt-^N=CtxpOhk{rxJ0_XxeC zdJOW<&x-7XP)h555rJCjq;Ng#+T6M+SiES{p=cMc0-e_nGU(jLBuCJB@V1DJ^o0A< zZ9jy!;U(!4gyeTY`B5c;Ckg{gWWG?7Z1}tO<5xZ3am`=|@puyC(Ypj@#W&QgOQKas zNv}*Twsj;LkY8uW&@+t`5vgUUh8zrJdtMDJf=5&D)6jDrHMadH>@m~Fox%=5RG%y&myc-D6?o1Uqlfpv zE%K?cvSmrno{da8JKWF5n#d~?$_gKj;~sujlG1upZm3Ti3oIS+pL1GTn%KKkVXRJ;-QLW>#(ZHwexATzGdu!!Y!ASdb;?uFl#7iECc6NkMt4SrSr7{ z?ad$#4e2ggk&AG-L(J0_brYo#)jx7??69G)Hl$%FCcd+{B65RIHYMDRvSl23bM8)r z@3rj73-c2pRKX$OcV~*pkFVG(WyRL(rUS7P^hlBPh!!? zH3w)T=K6r-Hp)w2Ty_Sv(RO{oJScxbcH|0*#)A){QWHL2s)(K<{!b#Wcy=7gKQT|g ztHBgu{oRdpAs|(ISuNASBEMIN?X24pWPIw>F(4-f)7ICt?wx}x71FF`V+d89I)N_z zO)Id_aZeD+WZb@Q_we7QR(~+4=m)18 zjmE`DFohE*ln6LbYvH6SmU^~D!kz%y?&o(PcatZLO^!k?MuqAwv${LQ*{De9K?zWM zY5Ic=!K&6r4gY*LBln=EyLR0R`h@SKwT_xkvol&eu-AHX>fz%=b2 z0tO&D&J*v=O#?d0*k(?jzJ8DmK+r`9>QY=>9^TcVo`N|$$QQ2^eF4-aw*o4P1YSEY zM8Ym$vXK3KCEqY|*hZgx3%)!v6nv3d(T6kp{}?=_mtK+RCokCk8ncJA1WUy~LM#1r zG?F^A(_4xvGlocEu2C=hv}kr=)WEbOO`6{-74YY$!9NoX7PlBn%Xdvk{s-o)I$rcP z2hYbBlbNr?C!%mCY`>++BU_q!SBq^NFLV8|@QyDd23E;8pnXxpdyF3051lM8X&N--F9cL*I#q{w0pKxqAg#fe2NCH<7%;`tZ{9j>Fr&bZPqiBV+Rf zQwG*Q|4W!tR-UmiMvx;{$rZTd;6%gQt@pYK-~uC=+9&MDAr!4oP=!%}cA2_$ATSU- z`qK35sv~EO(tOP4{`ct}J5%#iM?YwE&>P?(anh~1yVNs?OM}T(xTQcw4jOG2sw85~ zyWA0{6o|Smb$D!HV-*9gC8{v}!AGeIP7vyl{eFQ{UKqE^-6A4WS-x3FSidA=8dPhYp{W9$ge_97I zJj~VIM5`+HgG{lrwk;{e2ZlxGDc5mHStWa&J&fM*enfW=oLg-CW_9YjrXTwlE4bDB zY+4U_UNbR}xo;Y*JE)m{oVr9?+V6vF?AA$p&xzFg(sXy({;f9_pI;aI>nZzQ8k|Bl zyu}0VChhD6RGELek6&i?y?a2gzlBo7I#1Ede;ShzU8d>jM53_$)j(gusCe0SMr}pt;;lD&5x~ z>E9uJ5`A&bWbL}}`wJzw7c7LjFi#4_$))wwOn zKDrs4dxo2S`1(rt#Z|8^M$< zMi84f63|k4s!a@bh8C=PH=Im%lIJg%*8%=BO3PVcVc+SVYK8~UXF#GnYks$8L=0w` zkUUaQ+&q11B<^x_jqIs|V&Las@HW51bK6HAq!+#U`}?hL$Q#HStZSm@8c)xm@0z)+ zV9;XRmHLg%eT9E1LKby$lDvl_CN@tHk9BtGg&nv6d*eURrV*w%z9&rWM;Bo}u3vTs z%7q}}B$c%hXKh&@Z5k)o;;x6kiZ-Xn3G)uoOq$|P8&aK`+NVI9cN2q`Kf#Y5rHB=x z1-YuI3pbQy|6S}Qf}5N=Hb(8vyzJvBcBxIF`V>i0V2o1$xoIyVMLiXZJx z&qoQuFZ9t*KYA|L%a7ADX-ld?a^50xPL{r!TWRFn2xgbnJ}gNxA+WNY4)kKN;2%Y@ zR&r6PeAo2F>*K}r9YV3ebGTUNa?0f@=tB{GL(JXO?o;f?1e2hDiv3uZj8~x9|IIY} zqMkVU_TxrITujo%R4y>?K|fqf)5UZyrt4w`7c-0q)Y~Hc86hw`B(^uWkR6#>HaN`B zKkhq`-to`AsW3j8`}?JY)AT(o1gfC^EU2MwGsKZC7AE5EfF)=}MyVYidtf#E5G z|3@KWd%`E4Nxw_(wl~wSm4c(CFQ(V;+H*-$_m^=5-iUFUVxOkh>4LFyzRP5yuCaI_ zZ&R6mN6;-#o=?f+S!5sBN=SmX=o7-kv5t?$Zbq?O(U==+2*^PTiiaZ5MuP2Nk%aO~ z)M4J+`F%yaE!m;jL$!*Cxv*L%g4g4LG#uAGOupVKPP{cuKETTf)dkB^pH|O~`iyyb z>LRbVx1+nmvk*vj=nUEnzdI}Xu63m==PjP_h4axY;f>eV=Vro`Oil^!UpsU_3HPBs zs6^h%?riv78RrCWY0o12gZ@A}{OnKub!118#9= z{oEFW?t7R&+!5M9-ukKhx#2n>3!%m}PUGT0Z>Y7=XRc~)*wMN^ks0N-f>IHAYwe}Z ze_EYaV;$P)esK|I<$|9FCR7vZV751#Rk?}5F^FOprn`?=0abL#?KTH-qv>dkVbS(9 z{#arDOwWH0``e)){2(FD3m0qkp7bFr_+7^jDS4<|Xqp|d-@A8Vr_p}xb?&d1P{a}- zE=`d?h~$Sy0C9$b)gpB)INLgkq=$zw(Ocrd6KXy8Z~Eiq=NUWl5BI^_?VMX|x}I-I z@j&ob+!#0#^_jTPS6=f|;5kV3{Z5UnaNqDC#r+fOY+|8K=-5gW%Y9v1eb)N@MXle# zK;D4ZsGRQd=*=X1GnTAE*Ab?sS7%1AEY67JhKWp9kHKShHKz{N=rTy_NmHgvM~Vk& z{mYHmUXa$mZrE)ePrlDhJbOhWANt6kEp8us)qV{Qx#{6!_rcGMZ(oYki-!obnp%=- zD9jg5jY)u&=(?@32ebpBe$}S*JLDQGb$>+Ek_B`HC-b0DPHbqMI%`z|XS@)-zf-9Q zo(o0tn$+W`v6qQxU89PE`Olr-6|EO`s&0+%PL1dI9`&i_Qkhe>#_IU`ufl9p%ws*hQb z=VZiru`5W_ZA7?7AVXA%a~7Z$aQ(%D@6>kamuK>|>(6B$^?4|?Ng|%@tR<#{-;pOj zIk?2kyR5%r)9#$#`8k~vmaCy06DX)y5!kyM{!?G(Jj&pTL_t98Te^o-kVqA|q;{J0 zkvK`A$!@in80N}0j@&vJ`rqz;vA>o@4oIw+te}_HYgI|Mg;i-8Cv{x)B%=8!IP<6D znZMMIQa@Q#CTSG#>sZ&l>X{U3H|$nsEJIAyqT4FCO+aVn@}XFAD5JJ(r>$@MTneR#JOiFNOx$LUA>?8G{EAwJrO#2tRkpj7z= z`pCFz_@NQ>|9Iv{wH@5RLF1V}^l;@|%ZC!zX!*T;p`mEg~rkS#j!}^ih4tl7ZV6k8id#8z<_LFcT z=l#}CWUT6=(9NjYjNSyl={$}m;g|zVkXTRz$NSN0)T2gH%apmIsJ--(fR`nCYNukO+$d&=MJv4-Vyn7cs ztTFbJWw9Uh3|r>z{||lE7+XM8tLJdf55;Eh3i{-}ixbe~$(UzpHSof!_AZZrm z$esrSq5M=))l`jCeBy3h@TcoP_)B`gd8M7TcXI2V7;Bgo>-=1q&{4@{UL3{AXHaam zeA8U2PCJ}c73g}EF8I^6^OttLHM*wy9=+#xJ-_a`4>bQguODg^lbmY0# zUy|a*x~|kfvbR}b%_;A!Wzw(Q=R3M)Ur>ZF#TVV*xsvF(L{F^8UpnbSoeclZEy{}X zh_M!E)Cu2dXgzi5&;WL`lIbzYPDbnow3;7o_{Sk{A)#MnEV6Yt2Ibac*c)3KAKht{ zDQ$B4N2(4|t>>3x-xentULpDYQoNkRe*z;nkTK#fw#q6vT&^q;^gxc!xCs|4*tVT* z1%I*5sPjL*S<`*>tqKFiJ@iQJbgC_BMXZsbqwYr@;U~E{Cw|zQdy|^=qQX5%M3k1k z75u82g}OHwoI^oi@b*tU46Hhsx5oaWEZo-jX*LE@c+L8Hc?p3h8lXxdeO$H9H~k+! zjG7)ujbb0d{Y&UUt`4;r{}Ihqy5+>AqUFUi9zrHbA;An{9ufF6_ZgTJflq#iD}i<2 zc@0h3DY(;DCxYkNE=gprTm#>Oe_U7Z(qEPg+`29vd+vn-S8b;F}%(jLI#5s z4Cntx5hl7ubX#*p7?X*0Yja^T^J|aWR>j*`JmqfQ^;4OV(yc#5GW2F-os&L95<{ZRaoi=6Qf(uk9L>GkTvk7vZt#e#UW#l z5$8#mQ8Lpw4FwZ*jE!Et|Aq6%k>A36y(A@(_C|!9Oa`M&JUSJ4Wne>Cq6X_8Eo&-I!P}RBPB-)z&MEjR3Vx8Ah znB0-Vk~(~qq_92Q7l+f=Nt4E`|4LKubMTkA6|(Or7j7R2Au=9^s1|2rZRKh^TPxdh zyy`z%4q0$h#1+3hz4+fXy zpN(hsqwxJ7_7y&`Q1~fz)BcL^?FWLUTylGG5Md1`=CJVdwcv!yoh&=7hwWi=QeG7P z)Q7LaF#NRsEF^5-V8%v=_yo+`Nt2-m*`XT=Oq0@l{dev8@iJ4eK9sapQ`wvI;OzeSMCGL$Kb}s4wK=(~=G)rfPHa+MOQnNa-hhPQTTu$hG`Z2;;LVqXt8`ui_MLzouD*7{ObY<+m0I@nFo z4uu<*s^Vx03jUdFxQ1m%w)PAz3D%ezi?c^z#yGjx(g?p$(i?)AX;~r+c z5Pw?Up6YtBbx>304p}(TI|s%(?-{5d*4Gp1g&jO9NnK4U&xypL3M=yac{nKz;KYWz zRG@7#;ePFBX391+ZELI^(E7Sa*nEK7o2JNDRv$bcY;vC_gtV*YD;Hk9ltxWHs&SXz z)I`wpC%dX6`y^RNyG0P$&^H#?UZeiI<;@YPKUX^uQuUpb?EFWs<;vBfE$I%N5!gZs@wah5A|_- zgBVoYgq$7(HP$k(`v2K(CQK9SLX04mvRL`QSrTmEa#FEP4iwFV1M;o+5-_9ApoKjz z8CPhomM6L4=y7yo>Up`Vm@a*2+dzU%(I>!*{H<~o6L$D3@-Y~lH%)E&QY@&2>~q)i zk7s;8M-cVxXBIxF7FZe3z{WRft=QXw@cex4e!fPZz1Dmrp{c$-T<|KX$_TPLx~PdR z>Y|JK=%O*Yh({NbqKm1~#WY>SI=2}yj;Y9e5i$g8O;X%@fGo4#Vly%O7gOdZq8)Vb zi4{120ulqN0hi{zomzZAx5%HVmHRCol-0Vs&{HH7>C77~QkBD>*1=F)+^JZz^G70~XUTn+)d?T}(xV?y67&z2xRWussw&=J z{*rHr*|c?q_9kRTY;~V|O<Z<~*n z)}$;U?$@e}1>b}iY(@<9nvndR5kG+|3D6Ob&mCig(^%qX0uV6HeC|f8VaOF*O)^>i z+t6=|Fv$Lz+gfxW! z(DA@rVrlk@>F&hv*&)%hdxdE3(D3mf|JcQJpLtjq;L_JJ%{tKOs5s)D^4%Y17o**Q z`b{r|l8Cp>?adv0pK%&LP`4#qgSD*sf_n|M8BNzk7X=C)6+LOxh3kQF^%KvGB#W<@(Cv)zMkA zZmf+pj6Nk0E{d;UtE2+FnyDVvH#q-lfB8I~?SH;uW}d{IzWBS$ydC}SEp{dS7E@8a z*G!2Wa2pLy7nODadLp|*aT7UEi-RAsBTIyK!3XjTYvitbFD+jqYC{jhI=B7%8qr2P zx$c;ccG=*5#3Oec$ceRqgGKFNqehXWsXKl8j^W#7;0?a|p46Vfswi(vcIcMPG)r#D z?8x5&#D&_cg&e-x-FgMNbL6wlKjqK2CdAd;;@aj+%-nJd&5_}>?kYyeJlm>V9SyU_ z4-;v}y?vX_=ygEj7Ft8Qxq+Wf@>y<4#+se`3av0}7f2_mw}^%}C5H@RaJJ3$ECB?T zw%z@DzJ_Y?rWO=%$(|qR^fxe& zv{#gxS31_L1Sx%QqkJwO3XQiD;c16>{L|xedBeB;gzh#{X0|^fYl*>dAZhwK7z+cu z!k{EsEyrTs=|4>?qd;=IWCWw*Mhv70efzAdD)>lkbTFXJ{P4249 zfRbQ|IC?e1l!LgEUt*UEah~$G_kCk^y0>o9SNW9@e^h8xcIc3|2AAYYnGEz7-S4e? zsq|rfn*uy+cO7zY`LQ!T5f&P`>qbanC>*OpS2gI3Kea)B(evl*$OU=R-!yj4?-=wE zV#!jlxOI4X*MQWi>0JX;?de^mDaDYCU`j2NV0h2N^sm?LobK0(!*_;*4UH)gJ@>&V zJM=QzaTENA{~p>i3h&*kfj}XlFV_50{@&f+1BT)HelP!h#=kH4nzi9jTc5?BJB0E0 z`p3Y(<>zm>tyYiPj#qS4yP`+7wV>dk+^&g6^dy1~L#^_JquJV_5 zy|(Cjec?LP@5Mx?>LI_=^qbn-vYEuX7NB}cwV2PtNG=m94td)XPpsSW)^LW`i?GrL z-}h8y`q$>RLA&)&RK-?Rk-5J|KXgvF`qT9ee@P2o?A!8La~3U$b^k^s@H1G6SZ7t( zogN+|fru9nqqsa@3w@bO^Sx`Me!Ym0nLw9Gj=s;no_VFTC+kG8<;+a269H|LQUJ;j zsl3rWHrDJft$*bK2lul%;wMTa z@Dxx^@043O+PeQ6zU4`*^GrC8jZ78P5vC5j>lu!_-J}w=bG5Z2zwY~|Nj_rTFVce% zUh&b#=KWKpq)SZD1+bh1gyiy{;TW&Lx*S`fk9k4Wa?o2WYhda$mu#NaSbI6*Bb7#$&SrkBE$-(PROSC zvX?{bx9F>0_xKT}8MEtcsWh4I+ZXCfDSg39VI7NgogwD@dAgLp-P`Ln=e8S2K(Imi z(vsX%`;fc$H!+%GG|VZk7K!>TG6cc$&%UkC7ChwQNc@(6Sp3lZ1z|p~ZOU&{@E0Is zT+X7@^>lOQw-VBXGu6TqUDVixmZw-}9rGT~eqGw2>3MPPn=(J?ph#0@d}?CWtR^j) z%i0s!@98O}_;PTpYaAtIxM0uKI@h$(P;V$~JY0i(4kVLjnKFZprCKrN4kk4s0e!K~8O%b)!i@0sov)r1;{2?0=o|Z)&EY!?%kNvrjy%gU zGfB$Yrv!7%Eb4%`L;c-SB5ekOgBg2CpZ(s)X8sdzUv4M!9F=Dpk9f_dG5gcLX&lFX z4{tbl(#kdh{~@2ET>jaDJ~+7|hv2!pz27HeXd|N9^Bay*z1-h~_M+^$Q=!N7@=3X~ z)=GZi-fwQxqtke_n>>%6RqWr2H_V!f?lq|mZ$jDDCG&T;SFpmj`(WfD3?CsJR~Y;V zQ=!1YdB}R2`F}ka*`(Tb_<5js<3GP@5I^YFDBk$l3qyF5*`@#ZZ9gB|+qCU*ms}2& z+5vz-NqnIh7uwJ8zK&RDDI?U-2>d(s7lXsVKawV7X4JoXSFCFTBbWU4!oSc+R4h|R zASG@)LXh-)G1v+M_HFbtx?p>AnKe)vn|miU*hX43baP=#&oB5@zUC_(u~y1Lw)SNT z^LBZeOQd9mYbB$G`Zn?|M$P3~4EXhKB1;+X9)ch0b*i4gxEcm<-YqILquyN!^P#{k zdV6MOM2#5dK?+jH#f5zH^~@+B!b?U_*xzYkrn|wj&wnYA3H8V;?TYP^y(pQzh$xG{ z-9qP+*{`#ja^AUF)>;pls58yk`Mtp(mBO1X8^lp!-M_WcS76)O;;vXN-gpK}@MLuA znUnPFug~~$vOk9Ux;NoGaivT+>4I>THC-V&Iq1&P-PjRd!CADrZ| zN=N~UtZ+Zg8AU!T0f>0oITddDNeZoBng~|R>=6>&J(3e1GoM3B!+Qk%^ID#8CLe>z z2;%ETN#N4?>zu&yGYv^0$iF<9r(segg=B;IejdjzZyqTx%7;0)WP~r0VyfMlbW*6+ zFd;kmaDfTlG4gA`nTQjNfm?P+(ca^QE22p zntw(B!2OJJ#r?kO#n12{`83kRgUG*0~ReTP$SQNaWH`q9QVld zNPwBRT`9S&(gUp0vlX+Xvdk~}?F@VE^$vC0y!!s250xUW?D|Hty1CRp3cWM)yv)xg zSC|gJ&b=PGN9g^3swT_9<_`J3pl0x57G{jTZTrjxztZvCD|-K%+6gt`}rXcetMAl+Rm4^GV)5#rQu?7_fzcI<9= zT;Z;{(zh|j+L+xK#pPcVK0nHyKRlmKMX$z(uVVIUY!u4xk=8rXE8SSk3QmfT9=fSiXLM`JfJh5!k9_mhuD8o}O36ReIg_>p zn)m2eGWb;wKPzlAf{-cJb(Oj%^z_M5*v&)a1JCG!fNfmE9p^wc4z7NV1wmL$?_8dR zF6zpKbjA13PCi#xjE&AJ>c)INmZka7mlKNC3Nz)f!IAycrnm*-+x1FV@D{*d~AELf9`2O zQ`58%_R;Hp7JfaMueEsY#1}{{`31hb%YQNAFZao=;9lfD%%I?T4A2LSg}|M^g~wQ* zJP+T>?s=p5v6Zo|4DUEmD~CaWHNV8Yd$x8!zYZnnqwL7eHIWZQYe~~Wo&rBLW_Uzt zf5q}-=j(}+j3u`E?}$M8yXdUfN8QgT`7wHv9QsQN>X!tuR?{e(&}*+4VA&x>s{a94 zbC>atJ6D|>-kbZC@7q1k_~~3&@27J#W&CtPu_d8T)3*;#-C+@K?_xOe>K%CDx`;5= zmWN6x<6szjrKKP-eQPOh2swrP_ZltvpI$SVWN6oX6y_Xq9cM8WlKAqE7RD=mG7)@) zvaNMm&;EwplQv-n zw)=FiEh5JD6O$R#OSvfUr<;dnU!j0m3V*vH^gYxR`W3;?_v-aN_?UjUEt1FAXkYsc zZ%q|fK}^GGWm^ioEmD9Iw~&1*x>i7ObS-0Ublq6E4n;Tj%N+t-tb4pTJA^a zA9i>Nh*p20Y9!{wGmnHDr-ojz+z@Nx(^^sPv#R33ZMCY#{p%`e2-e|CwL)Z%Sa}Xc zrI-KB`CEYL-9PoNl%J>Mt4my0(K~H+HjMLg`4gb;JjH2;k_|+uW}z zK7>w@P?x#2>t$El9P8dfH?*iuQ#AXX)RG9yc3&@Otmj?~8;%&7#YgF?UC$cDgQgp& za5qu0*fSCG>h!#)LK*_diiDdcnwUXdeJh0ee5XD5T6}G+C%1P zdpe@dJJW7|6nQ$K+u{Z0v_vSjjVo%;j?uwxX zzHa49Q3EsFt>rY8^;=qGZ)SH%4aY?ZMd--GWxgXb+#k6TChxgU5(>JT>wU#vRl4`W zt7@0$DmM`Z>em;cm;3;#s`4VwnWwt8SF{K@Vkkwa5s~9SnGe1Q8G6(^CcZ}BjVg5E z^I;d}hRxNuYYSbts?de$;nno0an}YkNdW(<^d7%EW1EP=b+(Ly|8VJ;z*O3qr`H0tm|*P07OO`|BY~>TH%3HU-o*= zB!2B7Bl!0d!d8rNZZGS6tou~en;p68AK?q3*4qfg!t=wd%^!sm;rAV>$vbJ%Jp$oBlbTP{|;Qmkx9PlNJ@6UQwQ26GB zNC;<1C}1ozT<-vn`!)3Q(0}?Vh^sn%9$)t2fE#9Aac6Ja_|%W1XsoZf6}TTiQ}wpzqXG2tp|y+E~y zRZ$f7Fba4J2ui;1&)Ux^CAw;Z zJQ8kHnXy?nl3(BHq4s2l`_hXZ4ly@fS2Qpsd{X5mah2n9fl+7n^|ODl3#OBvm)2X= zIYUhRq;gL}$sxwdM{9H-+a2mGJ*h7Ih9?vhYu~`b!k0l~?hEX~?42g}*Y$KI|A>`v zow}j^D!0h4ZuQ%0=@|BMof>|tpRX(_Pj(}~fQ1S^yUk5CEX6CuMj^wIi=@IxB*|SDb<>VAnt8S*chZs* z=t67$MvN>y?xQ0>NkyG(ZmD_K1p-UDI2iO>O}nC>4db}NwPg)8fgP?B08Wq&?9$)AV zzvgXasZH><+qUFFPRq^K}+gp4i(0BEAz(?|~9G za}Ew8b3a?>F{IXw{MrDW7_4I_uoMZ(l^%75Z4={cyWay~j-uA2I-tX`AC2}A^NpVg zKDPdqN?@jV0m#FHqx{gO@L>#>5x4n5&x{FZZeeuRn&$L-J)V8@JTRCvK=Y>KZFA)j zt*bWQk|7KaBqk2~rs_&^Tn`JdyGHZN#ATL?$@?7g%|OS#y#7y?yGtd^t>Mq z5QHSqweEfhnp&(;(}m#d&W}wA`AT0+UMEbuf&u$|I(Q#O+QGjXWxj(s{Zb*f(Z zFhp*(?xPPwh+Y4D0WOID&<3|@Pib&L$DvfL&c6dcFHAPDqBqH9wNQ_L{Co)o_60!; zABos|t+oEV1QNXV$^S}*liN?!JW_OtZ5*0w3>KYyU?N*FI^MqLM)tj~82e(c|7mHN zLW=SyACw@KWw2yWymlogrexkqy`FYs(mRLD8l{0nvsHkmx)eIpmnRs*-h)E{pO&_> z3A6wgkEQ&`{6*y;4rqvVzoiCG^|VOisbf<2spjt#(X~T;kV-97uAdO}aeH*HJ&y!j zEi8EQHRL`+Xra#oAUhA5Ac+n@yAA~ESN#44_snjfoPCA$-#w>GM00w>a{rDy@@!@L z4i;QvtVt~RU7jT7eH3~1{ehw$0*z(VS8OlXd%UKtN@D##R4ls+1GW47=eew#Q5k$! zN03{9@_1NmYAtO(%ry15v(>6R2{57kSBY_wk<0lbiaXtZo-SNe+dEo0t>aLWPuzIE zQQmKQzBF`F?IgaRB%i`8cigVs-p%uIzkm`o=n(sB=UJW7x)^WF9qT*nelVqiITFpe z#Q8qlqsrY#!`7JPP&79|&KfKJXRn_OldkHS+V_2w?_26L)CUWdhOqDf3bDjIPM6&} zR%ikDJdJ{LD=G_LVL)CUewb%Hg)#i`_ZVr3aZ|FNab{G(ZRV<>Y6~Yl5EBDzXU0T9 zLr$)reVW56ApPZ00!@`!h<3+KU5RByJPgTjLcA1Py585{w;#al!B{PxVlNzR;*t9@ zD^l;CoXrkKW!?UV@JROd&F;pnB435J+^>h=y6mEy53-Gkl@a}=@UbilZx>62=kwG@ z*CW~pe9_|cUU=?sJKtoAK|ER^(8I*f1K2wu`^jM28` zx|zJdzyIE6CH&y+*ycvlBlR@-GdPwxl!HbNF|g%l#wfTXeRn6m6(Y|k?d~=&#b@D9 z;E>YBDN_@CNZ$eDkCqduIHokf?4f|Fc&DvbrSplj)52Y{<|8)IW7o(}DN|P7_HUP$ z-Jm#;&H;)1@N#7s4i@d(zH3f$OlD0gT8uAjAW7hOOM;>N0=!-_*0rrI)iS(1STwew zeb1cK-&IBhJO}EvCtYaF!{U;yzusQ-QLnuS!wlOX-i*2HJ|)S5SzXG+viIE`KE;^T z3326%1dOlxQ(?5uU3rq$@cy~-dO5Cvw)k4_dQ`$MIU9C|$>lHteZ9%M8LF9OQ^ajy zH5Epo6$EA+t{9jQcjf10U2af4?iFMU5f;fpnHUMfBX;Zt z-~^s!U-3*McP&)7)U9BLx0QfsK6qcVUi_Y)&kk~+KJSB*Z(SO%eKxr1It?EgF9!K? z^o{_qiFs5*pQ9m}fMZ&T#vTF$(>tqEQ-#tEmhag(RF8Z9EQ95#9+nSk)W%Uj%~#yP zV5x9>6g9(Hhr7p~HtBnK;R7IFT8F3-2CKy0?)Kp}%#1Q8O5R$f*6%ymT0eUB{=SrI z4)|ULeglR+@N?NPH@jmc5=a7Ckt7J3e)4V-2{rX_ zP{D9?I_wP71{j6C;(iHBr?H^Jb|&Y?4WUxg=!~DcW%Za0#q|pZ@TV6)%wAW}jxJ3{ zmAi<^=wt65K42Tb?s&-xSzgd-k%9u5WKUkj@5lVJJ`JZ|6-n_xyU}n5|PMf%#J4I zzEdUnC)E6e6T+5HmELY8{JKnARl;xbN$$_7MVXIySKok(0}Knk`xJlcFY%t6`Wu6e zW4Q3vrc#CF~^ja_Yrq7|^Kx-X%335RE?6dI}u zXbz&b&NQNRUaeY77Do4{v7We24a@6=%^4?{yEov(iQFSrnxRy?k;hwljcT=E(YU-+ z3kVEu=W!ywaQx0 zbzhsv5(g?1VHWAEcxgya?cd(N>;^o~8Vn`?ecQ7D0r>G$OjN0a(Yv2=gb*5hA zXA=FP+^}UYyB$w?cJnEej;wh;ZO;lx)xkXmVJ9I}|mj4X;Ak_PP^; zj&E5VNGv+O-r{83&JbU&wz7TmH04-7PwJp|i-q%4I8Rcx=a>HyzXo78(Ci;*wbEHz z?1IdxcK@$%w*?UEs}0uX{~Ieuo#?UBSe6F-E2};vMfxkMDBSqZ`x`eYqmLxcCYloY z{L231Q1y@`nwH$%y;R>z5qF&6+ulxzc>5f=b-yCqDWNv43v`9MU{NJ`K0jq(`ZXe& ze{9_Hy`bYBE(-a+{xSFtb(e(DZ2V=9Eo^CK;SF%!!y9^G1;dwMxYOI0TfN)n?ovlv zLW(9uPg6t;uz#W|BG=-63{<)H$Fu*stve(*x%6tGefL6Xac;Q8e=9ozFY!^sBE3Dz>M%4 zO4s2GxdWf@1a^Xr&kP83E7aSzx*v6!$!@^~6@GR#vi4f0JHZ3Z{P8W9drS*5@AIxn zJ@j??t>(SVOyiIy*z}GV2^}?N`S(@ED~ws<8aL*sl2WZONo7X2>qeZi@DEVb^lIQI z)DCB3i+lGF6ERX^PkN!TtDo-iqrIpT!!RlBW(!+j_hQvwB@=V$D|Zp4VL|Fjb~}?% z(Ak5?$+jpI2u}{_-d6hYyem8lo%gFR>JIK--*8`Fv=G?1#3{3g_q_`v86753L9aX@ z3vHBd(mOfeiWpLGEy(o_cjS9D@mi&ZQIQYjBVS=WAD&Gr7GZ#^$J{fe>Q7v;* zc3IGIg1;PaWzcbizbt3+s<`xL)YtGyKmDWaD05_JovwB{ZUlO)2K1#l-wH*pbSs#@ zLJvsi^BzpkZ=jb?BI{YmI~z zZruYYEkAzS6O?%i^FFyBcFZS|5(ziC7UZ#xP9@r_4i<2LES-DAdO(@q`ZDTg!oB-B zZ!s8YB;?BwWal0}tskxSTYE3|5+dUXdeK;4Nce599us)(|{4|m@`%=f3tRrU2J zMp6Ci)z`f}fOrk~!PoB}u5IsOhv?+0$x+{t$-YAh7ku6oDoYwsi9c&mA5}3fD=eZ9Mgx%R%9GBNZ#9S8|ipv z>rP>!y@9olsJE?7Iv$pDsjs7kaEdb~<;8nS@)kXV zK$%mvrKyFIIiYYJb;>@5b?wn}DdAqDx3Y^y0Y_rV`C4CN9%P1(od=?!z^Yd5632Dc7b+LT#+{o(9EOT7f7 z2jADX2K?^$kR+@{&UR?Y9wZw`n6G=U_!UdbMnH(yUeQ(AO?8yGCPC%d=ZV$j+RQa1 zuMOrab}oN9rqM1psH<3!U9YS)nGt#5A3&cMiQc5kM4X64xK=KQFU?sewXat$EZx>JT(RhH8w$lOGIR1ocY zjk(=Y*=enD4Sv#VP3voIlk`pb(5M6UV!qfm;;M`WmcyEQ)v4ae&#%*lb- zXS=o>)b%PmhF6v~4tX|y((oU&)UC`uo_ekBgJdFmX0-7zwu79+LhxjBdTV96VgZ`t z=Mq^0qqCpEpHkIYwf6&jr_GvtX71$WUE2ni@H6`X(PG7Y`tXO%5T8mHX!xAU)H^n>=T#>6Wp;~yGr4co zB%{S<;aS~^*}r8eYytjJH((Gz6I&42fHd2fK_VDXZ|-Q_?&Y9}KgtN&&1E|GFS<-9 z@nS?+Q6T3q`8MIf#;%L^`$k^kL0JFOZsEYv83jM=?SJ709`@reiI3%z?r#tD`}#4s z_2F}a5Gx_Xs#b#}urTvTkilEZ&H(h7FLBYrfnRA?mYC3UC`#AOm-6V*NX)h+*Xp+= zOHP=>hZ+*$iBKe2kg1_2oYqNgTL=?-h_*~}g(zs@SQAZeZWIJuA zGUD@eFcwdLSU$Uze2qcJ(cny6J|R@>I7?9cfimFLxL{OSApt~;cBc2E9f368b_6W9 zw!pFDP@3w?{>>`ehss!!IGnyQ+kGV9=xGWTt(>d)McM%Bd=@kTAveHQmzE9L?vWCV zOuf!`fUP#|4v({pT%_xKMZ>dBx=59T<=W(@zm4)fj9 zEqh%dJl{CFEWMR| z#7#BtH+8ITp*zuu`Ey4^lK;_^kN2=}&FPt3TVLM7u7Zwnd>DsKDJeSN!UU5i$Fm>6 znfTPcNZJ)6)mmru9Vq95H* z9Jm!S6!!$McfTwg{NE&T0&2Ov~ng7 zFir-%*H9VGKO1G?8LfQp9Z^zL-bKmDE-lD#K)z&HL-%6+6gHu;6JH?z-g{(98MQB> zBKG*J5wXBm{#ZEmBk!B&j+o>FeK)(`@uX|#p#aOGs>6MVewE!4o`)Rnug4{edv5HD z@kg}gQ$H$;@Ep2BWJZViG`~HGn)OcEc_nIdobb+F$=4EP(dam{R?0kLHdsp_Ddz!=~ULXx)3}_1lOS%<{Ie^ef zLIgP23PG$hl;?gOnt9)X%0+-N@zY9k(fg0Pqp|epqy=6-6*eq+#(H?Q7vg zFIEW*qHf#(&lnW$$9<4V@|x)Nl@*oz6h+%CKN2XimCbce&zdbc-o#MoYu~2Knqa|F zKpbTL#@wpmnx!puYl2%=aBJ3|X71)|$45N9D|+2!@$RLZEvR_qCfICcuqetC7X4vC z#~HND_QlGUnl-IuYfY4)MGe1db~flRdjVXC)80F5-(C7+LYbEr6FF>6C_w4W9B(?T z5p^+_jB=SAwzEZtv#w0ke2}Plsu-z-z# zIBpdnFfUUKWIT_EXWyO}vQmTjr>`qZucQC;b(Ot_8&E+dhY{^nKX8rlJoZn&q}}Er z%h8`2{^@JlV|(yI~hR$}k~6?zUf}FL-=4Q(R&d({CXXhs0njOv=YO znTKx-$T+>i2PsQbbQW;TsFGw z%ch&V<19Q~5hsUJk8v59e*XN0Qf!G|bVFlGwfpv;N-wZVs|^lE0jp?K8NQ@evV=^f zdAX{$xje=<8eR|t&B*Q|HZ{gwr0ClGxVyioeXr}te4!|$&8`U(iw}fZSZe0x zn*|O;m}-39M;g6mmI4*1{SBZ%k6)zYm;6+1@Y zPUh1@l$^qO0FoBQ6;_b$r4`M829{4V}!BM z{9X`#`*$S>A4}*LwyazG!8EFl<;P9GWN(Gob?>n11C5@Ase_) zm;UFb+Yf@%U&+>d@@#joNBw*jf2lGVgWsG4xpIabm25A@A1-+6oIFNc@xoz*A% z_`Pa(Bd%9Jg1?=-0>S|yU!>R;;+JF?xVf3)IDxG7*b4oelPsL%cyY;KfU;W za0&na&=3DZyf4g=SGdkRTXS^8{{M&_$1DVF^FmY7oaaxK2(@4*_P0MS+ zsa0;J?PK}E1#JfkHA!IKP3^1$H=bzH@K9R95^d`;^XJ<+JZy*HvHtR=Po$B46Pv@_ zScC%~EYyLsA%okx(i_U{w5#vY__f#Q^ed%wOfRqUz@vdkW=--_;>3wJ2sKm_kzvLG+u*sBwFzXh^A638_&-dmIDQSkWSmghF+s+kpMu_G zc`J6fAMfKO5^3k^(S`H~biMgbEtZ`&-Cj}BOS1XcBC?3Wz-y%ZFfoOPVfmjaMG$A^ z-L?>gK?UxXDdBoSCnOt>X~}w5YkTbpnDW(V{(#w3O8_YBT<-b0p|*lgW6o!^QejSOrMhem$ps)kj zN8SCu=?$mSz9L*Y_fH5j&Spbn|s?0!xk z3uAfK$3Vre)TsMa8T%B|d>z)$qcQY>EJ`!>YKEi7-F#ZoOny<-GYt=1p*b4(+Am=# z*{=S5x;QL3P9?o9io{*$EEHeJl=d$>HY__tWu*`^k?tR7`T2T}p7G5^d_#A{Gk~z# z-i=v8eOXHZ3&H*ckZfa4Hx4xSd8DFxq@L3hk2XZ0g$ zFSJmOxQ)yBQNHZtNeJ>Eo=SR%@wLgLxsHtY*JSV+_@;kOSX!{ClQ8Gf`cgW7$ZRS7 z&L7vbFcv(!> z?&z;T?Ld{uBHEc)s%`G|8c&Ruhz?-HmnzNR3ypG2?tsq30AgW$ESIB#1#eK1R_YQT z(M7_yRALO!+Y}42butS32n;?Z>;XMW<-H&&{4V9dQA{6@$A>feF(t3PG?AYUqU^@t z@k=$BKW>FY*Ww{1dSUyQOo1?WmAR2J`fR#LHFt8g5czjUM+g8*KF?tvC_GpragFif z1NTjQIdERiccVMa<0myxqV~G;61fVj>PU;YFJcxvDedKcCSGv*5I9kO6mpbi2y9mSHHpJXII}#*E@E{zQMm zP+m@;SjOR`@$8fAYXGy{F_**A^S6W;r1>woFbyT#df+7j8V6AsCU`vX3@k*2gv$UA zbdJW+jlqJg;LMV01}6aBuoWYN!ctf)yc^X|ysDbsH|dPa)*&`2swfCBL6`?<4FQnx zDjw5|7_-n132-R%B0=b1u`&{}at+f#8>V)%TLiu-=x+(dn`yY(%qFtqXGzXK68hHe zFM@0^rR)eYKT@&uoLD4<=W>ot0R2c$Pzt~pSy>8(IPNrd`hhW6Sr|+6cveuAsSVOv zZ|Je%%@~gY?2%C4V`pS5K2Z5e^q5pu^(5St1S{&Q%H0F7bye*q7B-3DHx@oC-qb75 z?uFkSQtecItzlSgh+#U%o_)n?1q11n7-7C6Y|BJ?X*I{AB)_9Wu2Tqm^1iLA=%TZc z;>(_|H?L}n>7L$)`01Y~av2MxIwMz)*M`)LkxRQ_!3rVAob?JJ6 z8s?v_#Rm0nuedOt-(gQ-b@i7D+kJ$4Kb9xrnC`ZX_NYD|rM@NaTLIh0cAI{!#@pPF zE#OiHm+EMU=4J+W-!F!Uz9Ps>p#nu?-tPMn(k%FAIL!`Wfzw!au41Rq`cjY9ZGZxB z$g38*a`F|%;8dnT6G}nbf!csZSphaCAtJvCH|CyUN`&Q-k5x9-M_%bRTvO(N>DAAS zPEZzUS=43Spuz^+mh7T}1j(;x6g?`)+zjpGTOocet1UN!?0I$agkZ^eM1Y)Crs(); z#Q%dA%3VdwMAwFajWw<@e_Um-WM5=|*LcKnxTxlkm+$o^i9R@BwX3FB7xt%nSy>8; zY-<(H50g0(x%w`5$(BtJSn~Kd)Y(+Fr}2oBM>o}Nr9Z&cyd-aTxr+3w0j}6g+3K~$ z?qvg#e@<^KZ_RE_&1huH*{I}YBB$71YPmvO~dP&qSsE#wN~UShQQ=U1vj5l;g^N98<1W3 z?A9UMvn#u{4)8w}{wL~xDu>8>mEKtn$Y%!g-(l|39}Ea?t_8a!cVu@p=0=Zh6i<+E zHFIJ(xo8cEvS3L=8Ee_$ef+_^Xuy9H@ZZyzuOAdFp+w3x9Y&Cv2)^no($J}h5%&oLzf-@N|sjz+S+}_j5$O0ugwTzVU^?json$q4Z5HF?rJ}`?G)wNZqnaEfCSv|@n{~Q5Dw`O;w zH*=C^mndpeS@P$N*#XYnH(9;&eU|7x1~3irzS%Y z<%zPDExFIMWCwxbF?1Q?hD;>q%-YJt+6@{#i&txQ-H?id!m)Osf%hoKDmnle7Z3|8 zI9qF4EQD)Ib~qbQly{`Dj)?W(rVWO+ETNaa%G5MfKt1emAs#PPnQe+PJ<05x2ur}I zY}0Tt&I-qO{(1!VI$Fg zd(&aRP84P_U0%LH7MjT%W5dBnRYUjL@3yLw*FA|HZ?i584(7M;l(XMlp+a*^e(F~? z^*n4P_|E-+J0Xetj=zYxdAdLXzTO@v(tj>N!kUEXZpEho&^m;4$Ef=$4Iz2Y0bNVv z{rKx8@=pHe-lW|L{xq^mH?roibkxxo;4)LQt5bM7<47r)?}u_1U2Dv)Yh+Gr#rzmu z2Oa+SEz$P67Ld1(wui42ZI4`Pv|T3J-cFxO>mM}G41LG@(|2co`i}k^^t~>=mQa!n zM&Dt4V4Ov3g`*cT098A+O8eoy&p_EcDPfR;3^v!#X5^$ndGT>kT4Rwz`Uqh8`%8O;x&o?=>Mu zQ>^d~h-(J}Z)waHJgTx9^{yJiRzv7;j9U~UT7S2@#`O$KFSU=tXl}#*|<4d8v z&50Esy<(wP9@a8a_sy~%PjBu@t_uHSV5XZQTRI7tH@TnsdXjaeUg+V1@FBaNn_?!_ z1|8iy`-r9Rbu3Hq?8}8g=wVQJ;WJeI=ppo^Ak7T(d!PK_brTLs^{4H~3O|Ekohyy? zF1}bYg+E>)F#4C~i&XGyp2`q0gSp3qk&u~bEc3>gO?+o@&M3c(`|uwCA}`Bqej2u% zrYQOtk`hf|mf7s?fo~uXAB-jO$bN?XzW$k7zS&KK9~RdmKf-_z9xB{>huIoXQC#i$ zotrpIMy|Gp3TMDJ`o4F=@W~m_i$B-;?JsZbm3KqKvPFR(N=l97QMrl3>$YEeXl`n> zW@*j#?8M<{_WM`LSl;V(V7;!JJ)HBj0a{})@f*Xl?>B0CQtiR1<@EhmR~XL1mhG}ExTnds zcTlffc&NMM1@#?w!YirmiB(PdRy8wjbvEPga|&L^2@sw)ORg0KtFa^H{dbqWyKEux zz#4v^exIL$q3HQ*N90K8ls~u9ZiXf}<^V&(Yws@e_Cd22wp)93JCZEyxERP#Nti>H zJhNx!%DZqFGhx&cW#oJA*%LFB}8s>YM-c%E9SPI}03IjMWo( zGJXc1`(iY`yKL5H)5`{@H}ciXSYF?OgbjUHB!}xnJNdazcoB#Ifkf8XmXL->{t|sr ze7XdW{OM(QCdR&HezUrzvyU{_(@OVc04_irKwua&tIA%56joMLfx-j`Q=iU~Tj=LQ z$$FJ%JnEj*99WC;6JB^R7R?+;jt&j?9bgxJmL!aVD9>GDUM~uy1VS(JbUU^it5q@E`@OBxi8mfRJXzGh(#mH&o6h=Y?br;VHSLv3$+O^wrLR+883ku#r`xx1C-=mi}j!#0+ZN+&K$<9lz9le%zTk z8UMGr@f_I0qPif*)whVPm8y9+JzAdkBg~^n%5G?60%o#zC>SU-7dx59Lv}Ks{`z-V8K_I)+Gvg(NGqC7Z=P_n`i)b zsJ^Od&dsUy?oC#R=JMH)-p&Le#lat*Pn11_5W8cCGB=PbWqBgIt~vO_^2842bBl+M zR-a{>HFqa0OzC;JSrhiysY{yVE~7cRr0 zB7fyvZXXn+AJQKwMZ74{WAMOv^}z#^uD+sfDd*`yX;;7-&$$B1KT_55`OSPDJn$G; zSjl&Q1LEn=PtU5R(3uo++kf=Q_a#3HTu_ybu*#mHvSs}W_gl|lnw5Kf~>d)V}=s)x-vC-2FI4xb9GIyn7WvTUuUpSj=&W%O^G@$|sJ& z(mSxZ?)hN;f1#>1r}qq6tktX~n6$lR{B^bWay5B7E=qPEa1_k1DdW$__Pv@G_UdSQ z#cm>uo~2%44U`%GPQ+B}Td?3#Ft9YN*^km2qQZQpa4OG__+>#xoPkGupPw{Gb_7k2 zF%eJA7mlc=Q-3J0A%_Fgj}8fdxDaD7&!9tk1r@ycpQ>Qoy}e&V?TfI`6aEW6?@WD) z(o1~lA5j|KPXo;L-#M1rs7CF5AxC@pfy4HU=jd|DSwE)+%mPth9AuRF4F|Ps{5dWK zlXl+IDVwbcF+W=@r3QuxEP5drF0e2C?9RquvZ3J5P#bZa^=ROKyAl8zA1e?r;MY@j zLJe%LSy{M{uPxq#)tFISL*bx`*LRtQQd1$j$${PuWyaGB0G$&@k} zCwfiM7~*7fll9p=Kw_4C$P?_n8u2(A( zWeOTAKQo%+^sKVyTgG2LMk!OW-;8o9eU_WDcM^3|Yp<(FWT#>&USX=CaL%7|&#IB0f^gE%s|dKb0-Q< z81TfZ@Hb|^WN{Hk-!mkbUqk7zsX`;yetj+BC#Qi~s17ScOK#jgJI8|&6MA-x7tc%W zUrdzN6NTrr)V-TLr8PJDmFC=WOfctBJuURdktlxP>edQHQqOVl%_n%OqGGQ9R2|#S zTC(rA-kjOJ1crh~YwE$x{PD$TwhH>~5#jtV zIaS~V@;Qx_;`_3V{WmwUDn2B>#CU(Dws2c`Kl{sICIyj4?2a4|@Y zTOmJgjB4{6LUxHlJbpm?B4NhKqZmy@+o+~&2FgW})eE&QRNn+t(#xx}{WY8rudGAG7pVEOeBmYxghf2j zU%n!<;{Wf@Gn_WpDB#R$0?Ix9Z!1mZy1uFO_6OGE>!qaHv3uQX$wQmiBB9x(-TjDeG7>_aA%{jijD)wW~Mv6rU>T zDK}KR9V7$`&m4in$~=UqC28^9WmByZ-#m-SV5+OM>TX1{K8aG5vKsa%*tFe$*G3z! zBR!ZH;GTSp>D4M$e5R!TGZf2!$@;X}U0q{lqed;k#<_@zQq=zz_ou5YNSRdUwg!?u zGIo|1o{IH}>jpA^IQjDi55OOgqOHc6~KR(3ox=B^nR?Wr}Fqr||2;W#) zI1ftp?>`+q+>KG1GP_@E3amU*9#>(va^yAU)<0>9z$OieGi3R~k#b;`Crq zegH;hI^{x z4!U#KfK)xEYPC+!WHZA6x6QQ@P^u8{+cdo}gx*{SrTN3OQjPI3aaU#Xc5E3{s6?^k zcNu_s52sIE;tH?;Mty519qv%78a+=xfnZNNuE>rc-$L;x^y{uNnh!c&mC!+73fEFz z^G|u8*s+@Dg>&th#~=6b^04;e9Y#k#hPesGiq9;ZOi77PeehwMi0snzJ7wJy zV`UcxO-uXi0e$#EypWyW_C5rIx*_~yC6gr`X=99I-PewcT3O*Q?TaG(wn~Ljgi=EY zJT>VZNq0Y^>wfWs$#e8E#~7|2-xfRsSSzTnbKHt70-eXV=lzr%n$8BUVc8j;nNOod|x))-3kmOmfdY+ zTeLYMEKQn)(#}LaWU3bI6wGqN=mpIAu|#JSQ8hj78XS@s`j>?6O-GPoM@kI zbH4;}_%=C#+GIdyC5a`+D2_RK4Cgr}Pl%^KEK8n-;_goQE6E%db!I14mlhd2;Z*Z! zCqG^lORZTov6_m-v#Lt)2PhF93v)j9xPgu@EwnP*Udj0#%*?~j@bhTF>SL;oK->rm zF?+1#TW`(+X1R?xB3!!#atF5)+@9JeSX7?gu)F>k^19J<6Q1Z;Q}*%ryw@5Iyq;bdWG1o>)gMM;MSk^s2!ab` z+3}soPb?eTo!;C~{4D#m(;u7`+}g#@F|erUvq8reD&UqXHgMIPUCPc?;L%w|YM8Dg%^<*LxmpXR#t$r1X9=?OCXs(>ahRw(C^ z`r+YWpmCfzW}CT8TZvf)3fn*u3hi zR2?@Sm40l1uY9BWwD>TfS{R`!klswjEc}#yKx)P3^vFQ3sq*jUX}kh-s;YQQAATxL zKbhzTF##i)fbEu=h<^7zACY{IciV~H@xIbREfw{B@AbQZN4`&&Ofiz-#ppV!a?n zmcZ8rmOT?M>ukzSu2L6lI1exjs#gtB_pG6`mK;dsse4=M7{-}YAp;g72s`bbO4K~= z?%xM*tt1 zI;8mNKKv-vsy9iF(dbOQ#pQ_PU@N-s!jIz_w(2U2OGRoNb8x417%=zmbGwk*`t=xn zfcuJb2bl*U1^9hw71=GA!wYQwwsPa=uhbv=M5gExf_+OwMfucAg>P_K8b5Z5gQIl> z)t^PLN{BVdTI?X*BTmw%3a9N|{?);sEMLGON1YAe+M-FEE;6g^u2+&*rrnVGidmOx zelH+<(1VLX8+HDX3RK3Kf~& zsTEk%w_hPnu?wO=l1ppf_AQvss9kN9?vcOP+JUdvJav9w%Jy`mtZ=8kL<^Dhex9Pr zwMG!?f!T`FD5UYXq46JDXy?9fzS&3FJbqdO8g-Dqf;ZqPy8p?~Y)=ou4{*SQ?Q|Cu zO?4ZJW|tK&ao z4l|`Td~Y_Ct(ajG`EOKuX?mNRL@y-mzJhtt=~Mw}|E}_7WvzXk{aXkP8-X*b^j&Hr zyRNsrmE00m+krS<5wo8B4vlPhIhk z5Nw}}Fbw%rBKLVz9qrp>l=@jaV1&`I|g(oGm56s=achUBOztaOve3PAocNIQ!= zsv4>^AQiB>g#EDZfs-ZWsVqo4_H-nWv@cMtWtI`PcRsagXe&IaAn!sizS=Cg?)Nle z;FicQF_R6`bM3YeE`^O&c}Op+U$Z$SkzcH$?iliz6do?M@Aa9!co`F9vnrM8;2+KNMs8Txd zj1JKW$H!6{Wd6WCa!f2Th_36nMgmqO&buG7xC{C#lBd{dd)j}c+O#CNAyBf(+eG=< z_LPsU@$D3*Bj;nHB$1G9>78Voe5fyVZyW;?a>pL@8;WVFKVXY6uV|?4^Oi9(lKNq9 zpF0$v!M1`@zJz}9fZr6G&>}(Jvj3ozyJOv+()oPnaBuUgjxH{+)TTe;=#cR|E+Iu} zelV;~#{5hV3fJ@677&=`S20lw@;@et6433qnHkf&mfWRPg>Q2Mmxxjb7Z3sw=h4!* z@y$Y!m%aD`qck1Gb4r;6(r<#y1ONImegUYpZ`ZfD)EI$IC>?X@Eyg~^8zjVAw;-!C zuWhw%@p!WtpR29sFc2WT+1+aNlH}m(+#$apm*q5OekB0^Hxc^`G|Ig zyNADO8=pCC<@!}tjy~CocL-YrbCj2%R7)emJxCT|X}I|@eqr3%!4?75%b&G=B(yd} zZNv)wf|H*|BPn2N$8` z|D84UacX^^WN5+c;l(d|d(y7*-KY7KDNAaW zp^7buW6KrL1aWVpWMzf>$(25ih?FB#agv#$^b)!3k23_+anD}Cw(bhGK#TW$jc3d< zE6^6o@Ca_CS95{ckZ!;y~f6LZ+6nt#gV?JVz~-7coL>%0~0oAU?;j|NNbGz zi#Di{ax-g8FEL!k^xjt((?Dxvn|lGA2@gBMY_`pp1grxENXzG%7eec6!twB!IbN}-vYg0~? z%fQm8Zv_Li``%kb&#r(kPJmCg5(oaY$yV`|6Wb!KL8BSdzxPMq`(u<* zVq$IT)MoVZk~NOQ)uC^9152Nm0G;T^UBx|gX!4PNj-#p}!hyYynf`#FN5?tF7Ywf~ zCE}BbRQxK+a3bz@HYb^HlN4=!3N$5{Y}ugZmy91$0#H?Yk7ob)ud%C(Kj|;uja^fa zjk`bpRQqz>sC|&@kY5?e#F6s7$ISSvyKc3ZBJw8*GSmx8h=_lh%CxbCt#Yp}N2#zC z?C)H$TZ9gU?6CnfWgU1_C3qTAh2Z4{O-mG@H1Fg|rXSV);85jO-)8LiQnBHezT?}d zLUnQ5bt8W^gu;`|chqvdTU8hY;`B*4)5OI-rHNlO%cpcI+M? zfr9lnRHm2tiP|cD4X=*6->@yuSO_8h_OF*8!>IBHT(ZAn1h9L{md}dgg~@pTgoB>f#1l$ zTXM&`cmLOq@N<5I$D*(>Km*#k@D&kaO^HN~r1NbFMU7%|<~Roo%DpU#d9v{?B8R3Q z?;lI@nmzwn@ALb^=f1xW_4bzyl+nULTYBXntyfn~C1^am835XP-O%9v<}VWN30>&xrCeOG z5LK#oZfyO^9he}(G|Nn%2mH^+m2nqE;G{=ZeZO6)$(;#nyERY!E z*>X2A=KgXtsATaRghh1v8{5l(;26&8-uSA%e+pzG{tf_t_kRqWRTmaAT&X|6Pyc#h zDEXN~^E{bae74*>76kuXnD4-pX^5jutI}tC~E->#Cxhi`5*ODbK0NdH#6B21LeVC=1z$oTep?#a( zi{S)h9_IzyAwhzP*rJfcSGf~;hsPDSd2Cg=mL7BS>m)(nUp#NVhX{GjL~Lu$4Z=M~PJEx@qBVD8%naBqO4Lt<&6XjO z%~8tq(@ra<%Ak}scWncS(e)_7rj$KR+O)o_DZ863)agwF*s#Xf8%MY44=i{m`OC@R zNebzWF`kezdQ$_&K<|1+eI>fa=}6lTue9$`up` z8x$wvKc(+@%VRKhI^^?VPZ6>U;?uccD_JagbezWU$|pagzz)R`s1gMX)IAn7E-ij4 zZxy)_T8&YWOBUtKJ2Xw*^oIy!qFe+Y9`Fid|Uylj*{^h=^)LEl3HM6! zb{JvPRbsX~))Uwv8*?r@JIcp<)+~ zF>}W zJ;+FAFPzUGhSq5LB=6uescD7d`nB)IBc8z$jZv@{AwnFx+7qEw6>bph?R&SsFXzYG zSy+d$!1Z82FMZ3J=mH+v0$q5JD}?MrzCc76URtKby+h&R3*zsk{IWjF;e!G1VemeI z<^paA{b31EXkT_?Y2TRgtF3CXUh*3<@+RvI_c6YLCM8bZuoJzW%^dj~5X$zrtGVTR zijH+a6uOvO;`jaDA=VFe4!JCfF)Uv#`z5TupVHfNLf@46r=L{c=DoR&;w8yz)yK}g zSv5KA7^WB%lU=~h!w|+a*ds0yrHd)0i|M6{OG_6sOBZeaqL0^$->A!_=L`E?-_h^- zu720|_Pbu(@4B=1Iz(voGp2{Ss4iWM(S_RuiXaEh!H0}LNoDdEVTwSRY!G*0pvcAu z$?V5rb0{S_-qtqzibv(iov6fc+uU{j<$v%9*~s4g#7G3koN#HXe}AA7wZYOcX0aW_ zj9D-6M&hikBJQd~{av-YEW8@y&JVAu+{L5K=%G_J*U{Ba&M$rlb-yqj8CiIbsPZl{ z*BG~qAT&e4rKTOb{nzVW!vCY6q9zdfF!Bf?&5l{jrvwaoI`Q($(_VhDBeFRI32P6j zq@;0S%w1MGBU`YIQk4O@vUE|U3pbGLu8JbMSth=Y7qjbvj8Y5}SYUnH>dw7Lvq1dm z1-*Kc>%1U**5oZw;QKwLN1xRrq@+#mze|q}6=>nsEC#I{E2EXc_OfkrgD)x_kRElz z1P7p9>B_<@&R55dYzo$Qb&+2F@yJ&AO~;E~KC3@ZeF`#P14e}j2IO`I0@94T;5^B> z+gw)6i%R-UP9MLg+}qQ9xy$}ZIm=i5;L%j*A&&Q$NI2PY=DoR75=4IBNl(Z!_mk20 zYT^0>I_pWoI>f~kyO2x(1|l>QM8nfsJr%ysKl5Um+58QWBLjS}g^8+V7uJMjI^`l`_9ZE&{@V8`Q9)zjMtntAD`Gym@ z`$Oree)NNjX!arDrJLe3K64?w&qFayrIg5z`|8EAlgbo(u^nMUpiIMq2h)!rbEx%EHVO_OP5e5S8IAqH z1c^B+Od=_{d?={C>(->;AoC5~iho$>;VT42)w|vIDGb+o?9F)f>>lU?viR7gA*2yS zsnw8XrY<~uH$G`$#r*e33KMaG0} zZWvqri?Lq$Bf(T@;tgW)C1Nd!EH?lAz$!I}jl^tZpr0mJC3$t$Za>!xxOLw-R29GC zu4SMCeyzLfY=1Szy(}iivubzp^`x9+0&kgW9v=9k$fX|%mh^B&;%9GwI?T6GH=S<^ zB53p$&`)!*FaO&SY03~S=-UY%(qHojJbDiFn;&=WKr^o6nuxefofxfHipiL1)ih`n z3kHbJGd7on|A5#{?#Yjs;lF?DgJEHG`Ca;&?|KSN{PBEO5N8*(0K_!WD}jdpERlBK zgEgIAU<-{Ypo^9_Ggmt9*QM#sg2cN5mNk<~ZX7Z^$kD9UlJH>NmwM6*i7x4^0qBYsXXode6L? zv+bP}X|BO*&{DH9KCkmJZsT39oHS8762PzCvR7r_fw!GE#W3o{9VLwT;gXUO^lyD# zHMy0(%{rD1o94LKLsU!hbeSY#j}D{-xAoERJJug>AL)(X&X4;Ht>6u^g5ydJSV1?a zbX#2cG5B;QVxR`g=PY7hs z5Def}?nkc=_*l7drEU$|{3kmbh5bkEydB%QYQFlZe}KNEUnSCyw(C)9X!=pT zE<*uSIJ$oyzKt%9^6H^Tq%x8SCeCl?CNaU^O(r_IZ<6+suWeg`48y3XztcA@x&M%_ z`?KkXd`p=+x{bz@I$`Wvp6;8o?BD6stn9_RObOl?ewJKMC~jMEy5Qv=-l!zfd;An| zEDWvWrp6?+);vp&j^?tb6E%2(wj^@DR}XYkKDDj62KCrK$WCqZQ7)3tGBO50TR7+H zRwS=Qk7A^Ep#tl^@vP?1!F+GgiD<%jIEwSht9=f(s<^8(Up=ZJp4GJ9T z4P7dXfgBsN*Tu+PS$rhq&)KV@b_}A0d?0sei(g?gEG2xe`<9yb3wSf6kbR}K52r7~ zY3Vonm_u)TgR^&ce>d)e0b@GHn?wivSxo=G`yxLS2S!j<*m7rJ0%DB40K-h=>WEU}? zDg{!@%|7hu8(ET94Z*FeQUmqwG5&D3QjHBI%E&%SJ=2isN#@xUlIc#~jBT`(&%=l! zcX~8??Qk5L-KSSpW>1f%4p&r6{(uA>n|(O45wYDpYlv_^MyMk{(XxfU#1)j7_42BT zBQ<)x)Vb+BdaoFDzm@y5w+Qsf<;8U$x5s+X+V3yH!3BL*b)Oz33i*4g4Q@K6F?WhT zD&?mEm!x7#v;v;!LxuL=Q4t<#)xQ9%JXIwt=UQ#jiY%nYhR`IHRt$v1jlZ==bx#6S*i z%%vhlo$Ggn|D@xKjK6sM6$>%CC>Z*}IA=KwZIx&g%x?oqYM2gY>0sjWkqg5P!as&B z?preUjzw;#7ckA@Ch?hvEGig((~##I*;fXcHnXg=qF*I*c@>&uKf?aeQ+rDE8ebBj zp27^e=i#x$5O#XseFd#p9=-5AvT>wPTY8`1Yz-p8DqT6L1DO1#gS#=bVvJoGE$mOB zxNT6kGw1C4hawGpejaZ^ewuG;;Lvi6h8SQl03&)TD%sutqy+Bdl@CQ=>;;`1;LATG z8LA&WJ!IV<)bD*I?}^syEl+<7oBHkbe{6$DJFZh z^*w&X9wS=dJ2csJxb^d)$PlRmb7{u%H^qYoTISFY`0X%%~{-2>Sn*{Gsgh{}1>By8sjY*V9DZ>;%smW(`8z+P;ka zW#(Y%^=EmICm!y%gWAY7M!Jn_9v zJ^kVb``hy{ci4eAEF46gqJfLu!`~Fw(jZMb#=WUi;Do=ZE?tb#1w6c0;Z|{>zLYMm z#Y-exHs~3@N+hW~Zf$5S%=G(URqphP+!vy`{YcTQ!VxsH3e(pYQwAG;#eiV`ZCu82 zXdD@#!3p{kWd6Z3$?wk&kxU+RH0xg068TPV*}h8;7er}5524(xZt_qox!`ObcCW&e z{zJV*(X3oDorc5ExJJn4r{6d3r)}l zVQ&!{5lPJO=f;5DSAm`K(eI05qfZpn*u82%lCxkBn6MM;Z{7K1hc5DcJbmR94);92 zmeVacIy8U4=Mm*(%UZF}HrzhF7Yv*lj9}F^dNSPIPAd4v;Pi2N13P;fs@{yv+ zF@F_%2{L9Z?vrPwK2|a=IL)gX*WHWM$+iiWljam~mO)tjV9Y%Wgz10wFrF4ih3i*( zC;8Q7n80^n2VVS`YZP^Lg-5QQ{;Cg!^ZAPPtc2_j?@u{^t<@n?I39%Z{M34mUpPtM z)!2EwalgehP(aece{G!5#`zldd8_#&&zv)=3AhX9+E{mZ*xf6|RK4~Oe{dJ7t{r`T zg5td;sZv3s3jzB3zxMk7`@^J84Wd%FNrjlIo&pyPqXF6)cf-VR`#3813Z54ioBd$K z6rS_?t%7|IEkxXJdK;M;e$NbZNUyr~S^mhfad>W1k8QW)+t2l@`fGe!_<})?{!6yO zVK0Ffshh7OxciZe*%o%Z=%IPU`lG z)aR^>wjCwvzL=QRC}s>RUdLHg2#wuJ5Im(a#|rceQ!q#&+A{4?KJG zZ7^CHx~JGU#bM!v43LZ3(nUk*LTp3GMO3aY0xI|mW6Sy|rYG*}TRgXvKqi*@)GeXc z5R)bkX^ME1j1wtL5(vx|mc57#=3>OLO00K#ao5(bq0sQz> zlsXBNOityO&7F{HJWJT{VcAVS%4Uj0tvb8g%O;br03`?t=Pz^xYhAye^=cfwl1dNl8|`jk zv(RE7ErgDeI^_B6e$mV;=h3;u@WPQ<`<)xX0dj`% zgm!%sMOLn&)DOH3GdnF-To8(SwUYY=y3bXp_zexZ8*yP_+X|LEuZL?a7Zz@$+d`MV z{^+y`JSxUE{$`aCw#S~4@sBVG*xf6-lcLcSL++*`dY1bdoBqBQbNBI1@wGYfKBWol|VuB@0>)~8x{F*8^^`l*qc$q-l zl}pXy@3x&~i#4_f!o&!#)GaClunZ^xYTyI`fK-UB?U~$@O_O{f>a{1ej6%R6(GbDXt`d!dr84@07B@@gv{L7nKh%C|a@;#Dw_irZX(D5qi*6NDF z;RgN&{3xtVIC#(p&8ISxW6{lY)njLAo|$j?EAv=~8lW99XXjgD;;5!Qh60p}JOZcri%neV?3mjxC0hnb;1wbv? z$L(8r<^A?2P3kY~L+_9GAM!rPA~yCE)*wup2~az?Ki;B@O`0b95iB4*F)WCVB-q-k z6nIb@u%yB;X+E9R)Qi>QJMGiZxNGNx_P=LT7`$kvS^dq9_dD@lH^q|!{NA;;l94zug)I( ziK(`(f0&=Pb&JbZa}S8GvG&7CYU&f#B0ZtbI%+kAW?v3A=MA427YezTp3uN)#JtL! zO`$C&M7ajrH8EM|M!6oZ(~4{0=iKpJPvlzViIgYtJBi;Z{7xYxD*WallBwSJTP6^A z@kdoBh@VH$Z3P^xe}Vjxyn^6-i^JS7yRZAav_0(19%nyk z)asbrpBdc!!FUBoiv?_;7Csgk zZ}0D~;nwS=l;+2)j!$hWts@@Alhnd{bp+YB`gRZ=Yrjx!z#sH~3PQvQ6e`VSk2rxs zjl>lIYmF5y%5Lq=s4qU_z+c0lW}3q6gs}P;W#7qqJ~q5f^<8%@R_m_lrR29BP2Z_~ zLh86B)(-7;dk<@UupS(cIU2OU0WaajWJ{*V3*x1DAIVI&t<=73O`~?2J8aizF5J@C z-Qcv_V)+(EEGe{o-B{@|X@etTS*dx1&E^_O{$zoAu05>QD$UUdYgG!F^YAiYH-f~M zwRB5fvA53GZ%2^$jrF6er-E5GRvizDpDw9Gbs}nxy-9X;Ep1-gk?!dUC5gUqe@C;A zgaI72Q$&~gBo3!q9b*EzR@1Sp80tLynEPho1l!GD$YihOMmSXkT7_PK--ryeIvPtr zJ^qV4H$940d9E?Q$F~i#V-yvbd3+X25X<~bViI#Bx*R(@IwHD$$tk+Csj4(_O1kY~ z9!GrpL(I^r_BoS6xdjt`d%a!Pep5>p^=4PPO-CSK=qL9#OR{IBDUwy=Oxs(*cjk~7 z^PjC^r9}rgeO?gHWgk0s_B)kYXPIOF_vy#(^SfQTO3NKav_Xy!5dmZ^TuaiQ-J6f~CJFEZ#spYs?0MzqRTv%DN}e<{ntm zweGdfq6u%|9aTT&2|DUK`0*A#XkYXeK34T(t|NX&BVl~>*3Wf0`}L9rHsZF@)b>&w z)tW$E`=>TOO_loko?cw7EX`kqbXA_e3hSyOxSE{Wclq=K7M;RJll`CCCMT!5E}!m2 z+`UF_s{P54)Nb8<)V|q>*@ZegIrV{VJ~Be(M*mjZH>sP3MbmC}ApO18^DP1x_Vm_% zC69{JGs!hj+ds5;zSYi)*LsTHfdsSb;kCXIf=W&QMsvj;<3et`8)Nm$yjCr+-8b_% z;fO(ADJTt*pp8pNNImY}as@ivt{V07w6JpDTJ2Wu6v(w69o}l+I^@z*EK7MYKW5Xj za;tWk>a4b6so8$2d^?l<(!aOnOz3rvVLuJmN9>0GxZYaEw!KST*k)^4dh7n47F-b) z-fE{hSnSNT_D-H1t#~i^JWV&1 zA15GA86nsSzsHWOg5r4J+qW{9fG=`!4ssQZ0)|Z4vp5%|^zqKHm{zm4tc>6W_ zD}&`IS_^g-8}Bn#B==*>pJaypsKmj+1v8w5^lo|=z(HyD{Q!SyELYPmW3m0f%U;yT zJZVmCmq~Kx9yY*iy&)?jW|f#iymWxBvSam; zqaP#b{cZgkW1;>gHjdYJEnnX=D|yX5p~Uq&9U3{Ausih-e4_sCINiVGYmln1`Rb}Z_11i4}~{) z1Onwmi})kUvoGs@L7tRvqdb|shu$en$*1@3_J0)h4)epV{FmWGWua&F$jY6$4 zTg$-=T5-sE@?$A4AK#C+-&2UH5YJqS6Y?z~3%9ZKf9j|ko9_Si&PX4iPZ5i3O+zV+ z%Op-BTjiU|^)ACSDsG5oz7@)Sp6#nnXtxG{VMW=g_{1sr5iU7=brW}tu8;OG6Ta)68nY#CE{0eXWC?=J-4{9Z@42mS5xf4X>O|E}( z`X%1NWXWU#cAqy{%mw)_cdKuVw_O=3iEBq7a?Z8J14)g?CmgazaI)K%8i;4m{f>X* zfhfo>+dVnr9~Sqo*$s(rmzC@T2TqO*A26M#7wPE$0d{=&6;+kf4vY`~b=6(;%bTkS zD2!inXLTbQ9gc11v_r^)3vygq0nAl2*Dv?x+@?JVOpRyPo<*5?7PJVWT1eo|-V;&S zP)lM7ft(~F8oFJ^H1HRbH}E7Z1m@17brIdw*`KMD9=NM9jryB}m#qr`8cLv*Z-9%L zd4h2&AXOf=5@$7e3&(~gHx9qmk^@8 zmX{=+f-0FAVrRXS9H0qdwjbu!4Z5`^@dp_3c>M}*4o3M%JUC~V>HyDnZwJ7+K~HpN zq6+*1{F)7Ah8uS+JCIU?i3FtzbGj{IuFKZM?#^Pz%upm+vgC@I*B&nM0@BZSKO(LgJoJ#EIY_$`grEAA#o~%{nRoX`lzb#=+2pc!G%t(Ge1CQ_(ds|@o?Ijr&ySFTohw<}{IbE{3H%sb$Y zTdgtaWPfJJM&;-%V-r9Z&)h$r9*eAT91}E_YNJ(lXmRr5<#<7)UNm@)|p z#?=V~Hu5wkMP;RaQ?ZhgDWjD1*#eZBHoIs4TNq%5?}R$b?Bs62&^Lul8E6 zykKYR`tBx9-sX_RT^vH>+ zv32FMzlO+30)>&)*;jzcV&HfcT$BfnHI(zi6cy*qxu3V=nDhm3aYIy1sR1<`hX~xr zYrMc>x|N~Kg1VKV%%ZxLq0GX%m7xrbxRsggj|)9Qvp~nV{oORi(<6ZqOas#+sg|nK zBdL;V(<7;lD$^sWit5rM9gGmNnRQlA7~%gMMmk4Mp$ZV#$Oiih%=oK^>?YhxZM&P# z)YvKI4q~G8g~p&0Ze`=;p~sthGgmzzD0?+`pkH*RXzz0(_G_$~>b0UE%F|MDbSasD zBa+99I*~b~FOlsYQGSf$!n0VS-C@iQmq$-bkifA0{rkiLjX`n@kuiV2GT9xx84Dy- z$%)x3wUE;1MKGXa?I`$7<(bhRf)A!2oZ46BwY@~m4XsUM+#Q! z7Xxs1QCuUPO?(a!ra#ua9yK|35e~{D{)GKwnF*ELu#k?It3Xc6(U4yb)H@Tc5m;pQ z*R4zyAxL%hXillxb~?}$%Id_*1GL+>uVTKiSn!s|N#jD3{b@zJmUEM>2NeBxTlG2t zA5z@9*<-ir^XDuP7@^1 z&;eM}$e%iq8c~rNc@!UE~9 zi9--HxB?oF<_=b#0&8+Y-pn2?%7R|Sekg#mx3?XO;48=)^_AM3!_RoK#i9)}i{W?$G z(2SR4XQF>C+Hcvtb>Nro^>+4Xdjha|MlKhrcP3&Zdi4Ui9cnj$nkuQzGDzWkp)Ox& zumx6`-G#-LIdYK`ss4ofa&Ck<8TS371hG0xGFM2*u-z;_!CF3?&BM8chwS4&xcj6F z4nz-Pa~@jKuf+W7Ub~@>(G##f9pk_@8SZxMKE_{~3;4Q40$jCl?2#XFsBJMv@@r!s zO>{EhKpyP&xv~DdF+cF1mdinASd!(yI?u(7V>ar{VTVcdJE0$H$xQEaZ)0L4pV?e6 zvho_y7{9HF;usLfXf{4EZRUYrSOd)YqLUQsQ&aQ&D%ntB#UYyGkH>3P@^R1L+U)`$ zjKE(Sk0F{g{m+sg7iTC&34OPh`sKj5YAd1hif0%hQnGf35 zx4ff!nV$M(^oue7-GYiyhS~np%~pd7yG$~7LLD(f2q3P2r#^`&U#xIfM!+^KeWWC& zjMJKBN7WroDn*l^V8P#&FG#zNzdK>(tY2tQ_lKonQZ@3$)GsEq^IB)A)j8<)yZ*@pM&Has^4eo(8`b z`y*J7B~a+TN3^J*5R{STU`lN}c(Y-HM_M9!gJMKtJIEd({1isF2}PM-sWzy?9u9;;fdYeuqK zL*$=?*!ElqnE}%@e-cPnc=M&d0HIkW-i7K^#(hIqRy_v53Md>FB~)|Qi?Vd?Y&lOI zR?S2Yc#wu@(}Aj0tn9`%?f3RR_F_Dh5c?KYErb<$0vPHtPXPDv%pFx5d7eAM@|jWf znmWy|ik`*&7l|(=hKJJ+2A$XSPi0e7-Vv0|3BaY=X)sU!2`fKRyet29eyL66yP7R3 zqh9k9`z})!^ZO8_3Vo$O3pNAiKq;`Vx^j=(anQ9E zy2F4=vVD0!Pj7N~#4~5~*$w0I1MN30lorLLu2ki2Jz8beF8Kd$@l9!d^0O6uhFIeT zO-qG&^H;bGJM9ljj0d1ZkhrS0%IxucS42M(KZ1_waB9#5uCr6=CUaxHOpm~0y?4(e zL7rCCt+V;|T1!i`DpY`jiHwsrnBzW>1Oce<=HE#rQSNJ%qL~M)v|k=MjGJ=gW_2H+ zNW14zhyGEVNKsej*}ZPvbP$g}M6;_?WymogsQ^l}8w4KtiX>8h&inu@=vr?L+pYz@ zy6j*U3OJ}RcOR_7Sx4nK?hzsil~~bqW`7LL9KfHOA3@7R^-qOK`9g~;v{ubhfq$C8 zAG#vFgsQwbZ+8;SAV z5A`c?kuO|*HB7&G@;jL{Rld ziiB-0qb9-=;wxdEU}PFm6bl;jXD*r~N0P4q258`%sd_m6kuE+o@4qM6Q>Tmee>5*9 z4*%FIwa=Mn+)J!)Jaem^y_N~;Jv&{Njtt>yqS?n0jR?fH%0OKprjvB(AVG-xD8}4s zRRvvLrvAtPy6kse>v42PUz}axU@C0J1f?2tMo_9Vrv{~{iT&XN%nkuC9mHVY6;^Cu z-n+mFv<_mW^5Bi2hA||-hiKJR3kE#yZ(LusnmF9Aqu@kDca8|&U>)EdC!N_WQ z&=VZl^Ov$)%X zcT~sneg~F+{8ojX`B8t(^N;(mlX9F5L3n4;mx8??oQ)MajGh$DOoYbS+m#^25KIoS zF7Znnx||cDE9WhU7Ux&{5>`qRA*i8vszoVv-DdsW*GB-XFy??{fQ$Gdn2UoUI5~uF zc1I45T$b;*=q3E0#2*AaCyIb~T10v@3aLaN6=ntpLUXeVGc%m$<2@G5A}@#bbP?^B zLbZt$Y3GU5(-|yJ9f~6#=fw`x`*1ArASxm^8qHia6;m?dJT_y1{QwTMt+VP%h`dO9 zmLM6zG{ep*uzdr2z&X}wW47OJiSQ*}8&WMK)MLT`n$kHvS3E@>k{TKL4RMJTp zCBsZ8GHZ`A7!h``RRcmSP2#TLzVgegQhu2|HopunD!)v-@*9Ts zd@WE0t?V<;FVOktFG-$h2f(;AhPDwbV(oLeFGc;F67q%#^(5f8$a>Cshzz+3nGit~ zw1VPKQXhO2bMbt=)*W`|dwz%22ZpyN%@|( zJw{b#{Pp{~tRN}(y8=C+3@u>n180G;KY8R~wZ~w`ClG6^qyL3Pr4boJuEaB$>3~irHX`!$4`hG;FHOan_Pgy+9&dv-wr$6XSITNnz z<8mfc1<&H?DV5nHxClP7K$SgPgUt*Z#a9|<;4hbN)4VqwryQ(8vU^lZW>^XDaX#6; zzQ8k!C$rU5@^SfiAYUej+Ral+5)*_t&N%2z6q%y>kt=l@aFZRaW1?diS{)q zIZo>4Ns0?;F(MnJ0ZH95IGNXAY?kr;MVDmva^k=@A^|bu-_h4CYjQv9md6oJZZ$7I z&s#Bn6|!QdgH_CM;b{p4*fwEJ-8m2~&@mq%;Ipz*+~@>9Kwp0;9sZ1HnA#7d2jTAg zl6EPWuKwnnAEL*jklRo^{?t6-DWtc=J(>Y^c_s(^BBBaqFK1=xH}YY5=k3M$il29# zAJYklqG;;aRLXr!7!}Ok`Fc2C-^AA!IfWMUVQ1Y2FLe0O9s_b&bt(i-CqfRUzfwm+ zA8+nFx`N5y8b>7t$uo2i9WPMgD5xbXLW}iN8M4u;8PYRJIrU_;ehKL-OP`g%tlzl; z;lx*h^Du3@m{MLM-xhB^T(%hj9r~L2=|FZYv-fK_p&t2?upgS_y z_xk~7=iPQ+Fdj6T2>BI&I$XQe^VHm72^?2v^AW0Al|8N%s5O-S?9|{{58v_v6hZeVUnR59jQFJ|AiQ zoW1nU{Q0{!p1GWLl)9kKJOIVc>=OKv=<`xq0?^%IoY2$Tvl*$t?2h^LI8fDR7R}-! z>Yr#fe%l?^*5N93(-hF#tDr6$T&2n1X^H}bMf`gNLqdmJ z^_az!H19_k?t^^#i&(toD=fS}3VK1FblXfbdt2{6ZmT=w%R&i?-Dz{0)J$=0-KB@{ zy_w6$o5z-m1rS`e|3PA2aO7q)&(_j1)4HRi$Kp4=N>s-1TDdeCge8LROV~(tpXAds zy+>XT*9!f@!EBlSN}98WTUZ5-P)l-{_byX!uAj~gyZ`2tyTmC0z2v`U?~=_o?@IWw z#@v3P<7+POIcL8^Xhr`X&(BFcBsX*7_hrZCejC8OV=XSd%FRd%k94*#zQSEA{EMh& zhVXV_EzYLid}p68%V&A<{3|#EvT=(J8Z@tF{uW^%Z+;#3vIp|CSifNXIX_}sMEqyi z7J(ahP2fbBCY=A9=JaJB5NL`ptVE_nY`w+oobQ&^DiPAtSn5q${ga{L3BLYCm%yDp zl^mEG?dFeMwfX$*WTgW_DoWs@DAUEyk+ZQ>Bw!a` zq7YPXo42V>SUH4DfARMb&r1F-<)pfQ(>d zCMPFCHI0CHXoXeI)8ERXCoh8^^1LK@c<%IIf7n!dj+KM(1LBZ(N|xc80xsV+e|pct z(eu_1UtI}Dha3uFaBtu0g;#jdn^)|XCBoEODkBUcg3KSvG>-pS;-uU}~a zo$r&VI<|A1SA!f&%)7gTdGq}BY@!Gb`s$>$3n|Qp5-(ceOKzDvZ>+v0@PEOjtDwL8 zeZo=LI}#yTV~nvU8w7CG=Apf!a|L?8?;`0?B$uU$txZR>B^Vfrf^XRNM{|12_ z4{J>LT!}Ojztj~ZGUWU=gOnxz;@P~&s#SriT4(B`%&@a;2+)@U(lPQFo1)7+ay8_u z3~->sj?fF4VaNXo4jW-QBwpk(mZ{6!p_dfks(WZ|Jz#9{eb%=9r_~@T-wQ<9bMhC$ znGv6LW7-_PoJEB(Kpxtl4jmtQ??KVbO?ENv{ua%*!InU{e@Z5k?na?ISr5(pImeOY zWr;;em^fQ`7EdN12$5hqL7R38!7?PZvX1-Le+O&yGyQv! z@Rsu=cP!f$W63k@nh*OA{5JB+^*?+QMgb7&%KhB!W4o}R_{G{+R(8hvhRks>N05d) zOT=Jcl>-10CxWeD{W=Tw6=t|p1V>Wh`XaXb-l%Ij3GDEl(tT_*Z~a;z<}bbe7@c~ZR6|dK^hq{4L4JKYoh@4| zUCxef!ugQ>jr}@1t*IvFe?eb4GT6m5Sg^=;y*uB!x#}AbnVn5xMqOebnhUt2qz1Ee zOYjsBo0)G{!_U|Rd z32T`AYjpBu$rH?r8??#2`L}}4h*{N~zLJVTSxP0-KY}zk8U{r2e(UnY`EN?{T{#nmMh_&TG0{yTkaMsV%hnH?+U^lqPy<0rod(; zI3(>_J-AN<--q&2{S8@*C-!3l|Jlm6;16>qxWQzWdHKy;5f3<~0Kmjex_$8oinb2-1YT{i5g`P*o_+pKWtR(fGG=PkZh z^8$^tcocc10kTG5j{bgGQ%Z@1Ez~1rc1grqJ_3JUYZ;hgfflD(=bOJ0U}8y1SH&{r zbJ7+53v0KfHe>Jl1G)s1ur5G-vnY&sdg!j^^q_Yg`dPcB?*~4vb&Jb%u*qS@;uUZ4 zIPx}6BgHq++#T;*QalIGt1|=h@a(T1Z2Tq6(c2E9Hv!S{O!xJa+v4yNvvKu@?cx_0xf7Y6T&_;qel+P##_!U2JUgTeiQOKjH5Vx=9i zbZxVLcnmA|a10Zw|KeBuO5XD(y5Fcbw7q@_U^LWADYF>IZnfvlmESyq((2l-j;-a_ZnNlv;TJXa9-5BHv5Cx+ z=%2QkJE_txpicBk-AU;V7h&BdjNS(G`jrM=$CGk_P2PHufVptQO?T%X?XzdS2Vb%xZe|iKWebvYt@nZ@+xmm13N(Q`w8I9 z9inYq7=HZ@%n+FV{|=awtNwLBe$@i9a@`lfapi*lNARoRg0jw!q(>aQcDpE%asNAD zt9YgX*q%qR2T*12296xAmfBe65kkwrTy_0guT{RB{<_o~!WHDl?LH3X7LEfxYdZxt zNMP9ip3bBt9RYb|7o4KgfIrO3!{l92CnABDd<10JAq#j`jPSYz0qU?>^&L z>h4E&1Y`R+BF#=?_h~R}xwp&FJV}2K^4w;wjpVmoVi^2Z_Da1dO`bNAL^2n{7j(8$ zXIFIByMzwfZ^ljLokfC3!pM~?zFA^keW9ys;)Ry} z%3ca1ZO_W=Q_ML0&JKVdQX}!l?wyKaiJrX}Jorz$VTH@G$7zx>L!Zuf{z3N&IUwks z-Q>2CTzdf(fL(|wz0G_l|7MfkWNe^2O*W6doqzOs9!0Rcvh9hwp3Y|0FgQ4}PgxWY z=#!kG-QNST1Mvj0wL^9X%OSCeWekSE)gW~Eq9y-rwj4P+m~&vBxqXbL2a<0ysY5Hx z)`UA)L!Av3!o8M)MHnH%+RC%l9xVjzAC<)t=NzggHjSz?(+4t#1I-9sq^Bc`*EV>B7B!3+yz<{V6q{#&R|CDwAi|s+bx3m^=_>2cg!vsWb61P1srcYPfcN`b%wH z$-}b4xgq@sncj#6P=ACsSNhm!`Z~CmJZo6GDqTJoa=R?~N;G{=*k6Z&dWn{_MnWs} zAWbla#K4kU!z3{VzoPRxTCvej+>I)Y+^JYCZR9TbI=!|-XhEODsA5k$WWZi_u!6{- z64i%0(ZBW*?yN~p1*IT&P*vU?9n_TQYin4`dqO{|B^1G^y-w6hgY^zVnnDUN^R?&L z)Bf^_7fO?P+(2@c&x+&dtNiHxf$aA}tWCv^EAWejN~L@I`rR z6s?~&k+cPscJ-dou+w(+_9y5^-`pg-X45bDto7O$#cxugfbx!=4bjph)Tmq`grsi* zKU?f=5jXXinl(b!f`s}bX8ghN-+Iq}zOsYS1g|N9@ z1)w=?Z#0o|*YT)u(%O)~h!bX+doQB0R3LF>G}zC}Cx!E%W)3r>-AS+q4FXEZ1Hfk!# z?~h)|lhA+vjh7I=$RY{N(F!D|Rc6AsWg!WOR>(`bsbXZhJgg0sC`(^LPr!o28?3KP zRB}=e6ho(U0)y5iYP^M`4y|9Es78v)(G@a3t=BY5WZgsjQh?tbsZrt5+}gr?<>Pe{ zqUtH(wN%%BGmc~uTj$gf_@1gxL+exw|CwRCwxOue(H;c!Jp6({ff4?_(}tI(@#*dxzGa0gpzbG&HPD@?9Qm9TaBDkvQ^)MLE^)w3AiVefDGHL3BboDyT|^FX1*O_kM6B) zw=yETzk-C#onsnk(MeZcvhKG-_M|$ZPLF4qNplJNT_liVjFQe0=}h`mfoSpsO*Tpi zGm{*T`AoOm3UED>-Kx4dIEH`!WY_?J2Q$e#U* zbw-SYlkotx*1^B0WvsYaWxit#BEv5!Nem+}Xwi<+PMTv+nhiVvbMYRVXoA0yT6tmFt)N#xx!B@`VWKcdgqIEyY;9 zNe_f$nB#!fa^vsFmHRIfn6X#xel=n%r={dwidId(C*;@LE;Q?P5x~M(e4tJv z?hw`LFxPfKJ&-@4pKlO)R6gVG7oKsbje3LSw*H6KSS*I0cRIOOmOOyWy+URk<*!`Lr9oD)Dd1}$35*0E8 zu+k3v9KjYpzuBVPAij*IFGWi;X!Z0p zl2=hN=&PL{YbR4}4!02B@*r=2L2qYoIWTMlQC`d~luK+-{U zK#|7vseP_7GpTeJj0M4sU-Z`?re`FQiDm}bfiMb~Qp+x*L>(RG zB~F}}oc_}zcE`(RRGL9-cDIP>n#TGsC;ls1c4>vqCDOS2FZ-SDYhQ9XB#&?OUFY{o zeXG1Qn*bWM|I?%T*N+N$a|SXM5Ei`{FYq$gDwUefPOnR4G ztuPb{?+dXnksa17yPS}J?dHDk`4tP8#>lZ{9~ZtgXBrQIU@b`BhDrK1i(!;l`CH@Q zji2>Jkp%AVR@B%ngG--^oF=u2St&>{ytcJm_K;*m%SHwAw`d@L(-;xI*^xNuTXruHVAsIYmmp7?RSlBWt0 z4aiF!>=w8C5)gojAL|bV;8lcE8M-6CpP@dg&CwwHY^eCWu>EOFpK2rV1K$+m>8mQ5 zGLs>&VGxvTLE`G_hp< z-*b%?|H|O6$$v*=SySmpO@o&=)`Jx`0&>vvM96nwksg6mBp%3W^1J#gyrfZ9l{Iw?X(>1z;;4VA0dFw+yezP|DL$M z!kagpIkX${BOv3mHsnmUTz*5IK&w4BO_t4D$?uPuoydS4sS=fuj z$1fIy|4aMuES<^VtrvFUtu0C$tJm!7><38{FRk--(IQRStnQBv~QLt+3NH;l~CUQq>0KSwQ4%pc8) z{aZQ;+WM%yXAdudwkgY=Lw9;?!E6h68tc&~X|vW$8=|gIo{6-4Gt%;%=E{?R36Lg| z3<&6*=Bv6^=wNYpkDdTXj4IbR%5FsjVr>ooRDV=|ZE$NR+CvZUqqLKd+uwqOJnW?= zGkZwLE6@Xc%LyebtWXj*$_gcA{PhX|mBI?4`U60$F1k|3$@8g*W$dgpECV zRTlKh{ucLYHH#DUY78HNgg)7;(M7#_55%cnozBae(7Hy_gCMJ@FH2m-L0Z$TSV|9^ zo5yult?sq$(ntgdn3)3v|I`WNwH{0l1Q~$Cd!Gsp*&TKUHU-UHQB{-6^gwszRtQYw zrvvN3p%5w<94op)BdD|{t9hrB_G=-tY_o0<6E6UQHvxjp=4&U~nNNJX8xl5~=HTXq z0*ACTUTqUWZbAz>pKY+fPt;Tyd~{rKO=ZE&3c#4U6bSskSl`@(q65x9j&tQlOy~lu zftu`(J~aC^jL(P{0Zt?257+0|YsgbVJs&Eev*@z3xR}vv^6X7S#KgqA!CQzs>@8^L z?&#+D z*3BejGw<*OZnzpR1T6Dh+QXHXiqXBC_%l}#P)y9lx`1ope8~*^ zyal^y-`f{0o+{CY=04i(p1r`|-^v3pxKQ?P# z>UL`TDpJH56_e}NM!nH%&9%pG#>1Ku3lHn+Tkdc6RYP)dKv%)z=NHSGPz7{P{6r8| z^wIn7b^jE$XV<2vG%5ASw$Hab!^W#ugoeMjI*%0$azhEkC54_tRpswcne`unuhy_Jh%2eX( z!vdmV`yP)G$I#Cizv~`Oe!evxJmZm%T8#n`59X<)EdTEb-pkvCy0r0|o49e8}X&4v*5*D7izu*VMP zsKY&|9qST`Lvv>XRegepx($gNI4lEWx#5=3lef0b)%)@J8~X;zpDA1a$By5-OZ;1>lI+WS~O_;qNXJ z1#7)PTWzD$u~B->EPwgKu7b^dlu*3bHSZY*mtEg4Vd0MK6HG5Gpm<$)Q{@%6@%L4t zI`ald2*1l@tzH0Oy=H##=7(Jh4A#0+3tAZLya6mtfq#XL2lR+zwY!Im0HRv;KEbP9 zWmVKRM%vZ&K&aot00`rup8PWqLXkg-H5eQxBOjQ+s&fuLy#{Y zE^r?{>OPFv58vg(bNDc;L(!(z%KggyJa5rsH-78^FO}*2;QKHGsBIUWpJqa_NW#h# z$pg1T(iG|@QdCrjP+i}KIeh~LHa9E}e+@gAmnMlC_!VoAha6f0gn6G6SSN-=;4T|W z-^U&=)L8#UVrI9-C6d0{@@jq2a% z(s<@9+27%CFZ;V#s-s|khjyPQ$+t1U3q}0DWk)d`1^id}Y4|Uj=D06DKmLvLcipzn zI)7J?s88MJd_juWFMIw`R>V*Lkt^z7L7rW-9#%G0H|xtxw`BY2Gm}SAM;&TSWVo-a z>sRE|pKXGc;HY_2K2QEr=7llVQgyXx_a7fEKf6sxdv!IG;Q>2#qZ1rh#&BTa@MOYC zr5o4}97Vc;4bY^J)KGczw$HJ_Bk9jJZ&R%8BJ;MR^6>C)+qX$S$6ooj?c0tG3&yPv+RNw-aj?97hT9neNt zx2>Jo^_BmEomo4)(7$IoDNe#ld$O?iNPC8|wc;mny&3NiFRAz!<}p%D99 zj6(VX8V-dx^U1s|S3I!g64c#&WcNCM7r;ObnmvRyTF}$ft&UsWrfz!~4JfW)>XzgB zUodrhhS&awrfy0xX3tmBrMYv};n~2}Z4QtBRa>{=%-_eMKKnB&fXsHbZpHJ{2Bf=v zkho5B^F3a4wrDc_(j;V`gJk%mA!*!wm^iKHE*}=$J_@giz-kPE#`$WV9hkvt>?2l9 zxP0b7S_Tz_%|S#Og_Ql~YO&C7TLv1kbWwf4LT7*asU3LgaNG05UwU@n!Ql2!Ev^wI zBH7FtpaN@CQlP)3(|g~UkZ_)zAMzGXM|_A_@6_#<@JS5t77mz9tn+-BPAQ!&|DJnK z^dq0|MP5*2-hgf6!#Z>C06Iiy%Iq&FEFen1|75rPC2?}<_1ME(XT!C8P6C;Yi9_{s z*W`yw?t1js-1eH5Si81|OE!wwTkvp613@;r={;}Zexd*i^dI3)E4Wd7EtyQ=n)d^C zY-3^oNl_XIJp;d%YVYOj5v)9^sD4DKp-0#Sq_q3OUgS%fAN>7DIBKJWnj5uTDalwi zKptLn39e(=I;JX5zmb2vVLHZdL}<+noDM6x+O?Cnvk3I4R`dPs2Kg8@N7I+p$#SNV zlrFgH40QY({8GGrEBVw?ODhxTRcD4CmHn3_aVrlI>4vS9?MFe@6MWZ0s3fmJjL_Nf zc|zGrS+r=339}({pO)(kmq>28H}4K1hxFwQ=!sx|(VxP`kl&n^qdwHEza@v;4s>{o zG)J+_=*rld?J(|omKaXB1`-VrvTl2HO^%^oBsmAX>G_CRrXyx~-W&bAx9~X=qW=h5 z5*OX_NX&nY&y&kBW~qvvD1mlClp-}Sq7;~Ibndyc@_HtGL)v~ockoi*4wIYI>{!y(dQ$_v-OqR`fh26rM5}(!PJo$ z6R?YCW+EH;a7Jfwwahn&VM|dc|GS65teyv)ic89i`-*CFf>3i8Ho zuu%TF%q=w%=$Ss>bpgSD12kafP-B)8y;ub#l4h04olWdZ9(FcGEBIY3bG0W_V$I9U zZv<50F3v(06|a9E%gZ_s1tZJ$(12MVguT}1cvbi#GZK@trKKbG^X5IlEg0vV7u?sq z`?#m)qcc}*TJ1e_ZWkXX-@rrNnnp&4ylm132TlD#ef2wILtgV*@1u+j0YcJuqeGBw z?HS;G_YZa~O%1W(P0?vBSdXyjVA_|e1#&h52MzpR67!oIY}e&OGB$JGaCA5mD+r1m z=6_4CXy!uf#m0wX^&7mo3O(XIbk0DHsO=P14@PtSlh`n=c)Li*SYY4BX)dnD{QOiq?R93tfl!UiH8(Zq4Z*Kfo8#EX8I@8$jk>(&v9JYY(*Y}ItY0eoQJQU6JpRRjW z&ib_1+RCG%&dUt^FmJBp2AIOfaKoK;#ZrmbAl zc3a`@GI#fA-MzkWcM#Q@?~ve~DX>F#RVa`i-bIJ;)XI|^{dOmYml-ymZIRi#b&5zV z0IMeP6t%N~Hd)nz%#PG~)cy*m^i5jL2VjyI1sC!m!mag;e zT#{PS%e+5yui^p94*ZNWnX<&s?b~srSCRC7*7I{Hsv#gyZl60rz_4ICEmI(3g_9ph%!i2m9%Bv>(HF^UhQ%CnF?f2s85?J5r#O&J6fk=&JB76ckqzzfrF zP4-Wtquq=q2ckKY#bS;t>zhaw@?{?DqRHAbb>$9f#0EBkpM6vP%U94KUtSW5kQACq7-XA&|JIy&O7kF3o_Qg8H1p59cu-pNlR z)Y4eG?o%y=@}Iqy_tkqYvWSH!iLHGjvTJSQ;PnyzXgdca;+y+3o}@<{X6>-NHYL~) z!x=4I5lFlJOJy%R1dOqx$}gS<$9)!9J*{0HfYqx&Mo+MMqHhscodP(1HdxJ|k^fU*<$OL{ zHDB_VD}t-T@t6B-c>0*f=l}2U)L6f6+Sl^1L{jJfAsijxRK_pc8GOym;ZkDm*TUrNvL#IC&1fH1*?;H_ZJ4g2{4k`_D=JR(dgH{q8_#XZC)$9}_!Pwa28_=Ly~5}#CJb@CfPUq?n@ zb#hu@b+Xe;R?`8Pxmd~XW&e|xd$iCo#kF96i(Ba5-NIH$06wjS@}d?70*jEi*;n;4 zhl17qe-!gyl>gyd0F`PGE_{iyzdE(a`W~*y<9nF>c|Cj&zrZ5Ms-#lBhc3T-;`qYu z#@%Sgr)}x%P(IVa8%>kZjHwOwwq!8_cVrLbsi*?iK@<1sV5gkf6Jdvx^WCwID?Q%& zv_q;#r)?k)dp=p0MV%1ml?fQ|2Fkr9dU06aC8D}E<)tKdR_CQ8Iix6du*IPCn~+_< z#9xcy>3hM=yD;S!T*>656&Z_=gf(8dy&DsDL*+&8E3Z{nGsV@7%s-IzjOue{?QODB z%H5ZzACZ-WvJ2l3aX5?BE3oB`QjMo)K>4sz@=5w0Z&`{3VX@bGEI<)S_sJ7}i}@D9 z54>n?*`a0oYmF+s#a8S1IFDsjz`WyvnTrqhMmxB(3=br()nXNJS^GNQg3m? ze;X&HKcsvpdk|CZ&RIJQRS4PKvbcxN@9b9t{y_2k*5g-YL&K1x8o3K>!W8Vw_d5xd zw?ZjJnOL#3-EqSt31J(IW_`9drl$~}f1B|}I5v46Ya{i22(LN3RtQ;zxWeIoj{W*0 z5@&vvuL>u#{N<>VLvxAwZcw3;>)8tJ=gAIfB1fLFkNm-jt#H^^(-Ui&x81}Sei#s_ zQDB8EV)R)el4bm&ThDzXfHUlUKVaKzW=hyjwe3jt%<82C+Fv*ddEYchW7(y}R*E9~aQddLeU?_gdEVz{V`bm)zOC`xP0<_p_3^m5;{ z{Ez&*>c5n@L@QYAVV(EsvObSvIk?V&huN)RXggu-Sx%6u8^vp4`zK!pc4t`jA9kB2 zj{&QOtn*m?my*At*U_R5L-#vOU|sEJCuj#?m*~ z_vOO}!7u$rZ5D0)1jYw;?;l7$X7Mt9N8)F0+tt%i9jYL|f0;9XiMRMGNMvS|y2vk$I_5rwzw%cf%S8CNe|J%VlYgpa z+rH^|EnmHqzj=J?d|l(|D`BIpP~2{r9)3slgQ^mzYx{kw)_!g6j7trTiA#4s;f$ejUepAbU$k*_iEaQrHKVeT{;{z)G zk+npmq4#ZeQj8_cYDSQ!g8oL|$%j=G_vp{=sb_uj5FH~~3MHln@wBGM5x1^({o_Ka zaPY}va}xr2HS$zWi-ze<7-}d4LLFJ*aQWPsIL%vlpi~kiqS@`diBgnVM=qOcVg*;CS-#f3iav-ho!eQr+Wk*zS-Q9R$m7cu`C zcUEB58HY93S-~!=wsH3*kzg^cILds1Fz+BS?fFV`HZvScKmGu{f_#nn%Z!&RWAN{y3K@XZVhEI$7)!2?8;2s`f96?23w;Wt&p7_Gq`M_I*@aQkL# zrtvtuUQhPgM(P!0pL!#tjpl->n)ev9JtEHLaET5vI&=IL<~|D*yP+)iP#Hl7+=pgB zezCz^9I@oD*JD{Ukv${mHI<{mUKd$W?lD9}+k4F4f)Tt)BjBqbcx6}g@^z+EEooQj zY*)t^UHc;?4IFh|<1TZ`D`FM8NDDA!&s$yia?M|@hByI(v42DT_BUw#Hs7rHc2gQ4 zIR)8UK47NFEjiETL6LXU_v<;C z3g?-7^hJ@@pLS9$(DQ00sM5T5ir{9udHF^QQw-H~F){IaR5#17`$7)yJ@BIC4HUP) z{F(KI_NWyq*bgz~(36wLY4&3EuT38m%-j7pDS-E+2KzphMeCPOe_SR<%X$vE!7gx} z?TlH4GlPIqLIT%)g1{3NGq+Ob6j4hb-t|^j_E?@eaqJ>y1fRd`49MpN-GbO6HCnal z{a-e&Y}-eg+H_ibL=i>U7}slK%;kD#N)DlT+xKOSHEd@u^*57htpuSz)0KZ=fz?Bp&5V^Ub{_DtE-q%GoO@XiPWEwL zu*07dFm9n|%uvH!{SC)zzYMsqHdJ#NXZ1jQb`NbaV~K)bpTEy- z@1cPwwmz5m#;gxcP9EVctmxKsdu{rD){Q5YmL$fC*wYEf&ITWwADn7o@p6kWNWXF- ziYnll{s|I8K;oUeVIeWF;4J9tcu`opNu*OMZ{Jz0zs96souIm-{uRE)DDiHO=dEYG=O0y;+=Z|PQe6fZqZ4! z{ykdH#~%1urDX~7Ax@TB{g1;rHsR?$;7+t%NncjoxN1Oy;3vAN?)el+p zj5;*lc8J166+o0aN2lsZi+j>qHA@Bl8Se`=r2EB)P0{2hD{|jhph&6^FxAcV+Y%Si z_+w9NBsTnY$H{v8`d6bF;^!)mk)^>oLUmA^G7S_cxavJ{Jm~z?lL(iu6MXhEb-Txj zB)reFiBcp^Cyzpcq6mfgNY1039V`-p-KdYg+bI+0-l_+gq0pDkTTW#-bcx+4$B6W3TVHUW?{tp# zT-#+%;P8DD^Sr@quF(eY=I_%noSp!gVzqMH%}rn|J$TC=+3dY(P{|^Arb-e$F-~6^ zv=&m86ZW7HT^j!^F@$PCDlEuHY1kAm_%1z4w^rT5uh;q|b#6GHdUH<>ir`QjvQ$l& zS9o{mlhYwNsWocZH}2bU4bc1C4qJIodTN+_Qd+G}h`MOmO@x(~(t4JyLj)AI8!jyF z%`7IfnatX1o@G$t$vL^9YjV&)ai$UbgD9#WCw^t}G6TshQ6~je=EhP369fUAHUAI- zZ*Mu?dVJJx_gaaCqPb2!RLfc`iWD!JXY5h;U-A5Cc5YUjq$7&aqb+qD99-A6GTHW!xK?>XR5 zg6fIgK-l;XTn^FE6)m&4=}YF9*kCxyEo=_m`j(JsSg2*AK!{L@)$CKS0lSd0mbbxc zla+0-cZ6*av`s~hq82b~S-zU;^YQH+w6cjY5gAsgc+#h6P^}l+8QLB%-Q~58SJ~}f znfaKSfRO$#-Dm4A(&)8Z)>*5Sf}n6etrAFe45`A04b9fsV(%{(kpN+S(4^gGyR(sf<1B?0^HT*tO%?*%2HRlG<`!*Df5ub)}2uPoY_nJYpYwqEV8 zp130`hxzVxafs~&){0K6}{@8mDvZ-#4t7oI(KAQW^F-o2Zj0Y3~Ot12m zCh`JYW~UjedzoQNe=C}ENwaU1ukT&wU;1;hTclQYWuFAdqF23Nnf-?Vuq(R)csawG z^&CM~x!iB96;I;8Gc;Z+*Gk-x+iauE=hEG@s^!PhUu{W`EGLxRglPIUNe^Sq5Q=+qPai!|nn|pCsCMqMdH`;=iTG`7V zSze&O^Kp?ewLU?Msv1kC1tqW9sKAYMdL~;ZVZa%RQK`% z_r|*JH&%BSRg?aiKJMiQRQ_NKtz;G{=Yje8?J&ccMRHCu-&Z-ks8Zz>!^Gb%YNt$_ zx}|@n>i~hm%qiv})sdb#)%=0N&Xk0{rO9&A3N5gfz(3$_fZrWI`+_6Ut-tTHO7TZ+ zFbMMpNd1B^P}G|pHhBr#^$c+vIx#69z{!)SR0$m+B_#<1T|{|@o&}_aZcozHl>F_f z`9ie{X4ly|;mB5?1cZ3hQg2Ihvy(qOW*aU^P8PI+hIN|2_V!f*q&XY-TK5qNyw+Kw zX^8oUn)$!~5SNZ7p0wJJWBz_TH?^ch6h%Kozq6Ok=j}#+V-G^U!PW*1h`cE7KNo^)dn#SHo?LpdP=_#pFNkjB^ZKhIf~5}wCk;I(x|n@EZXQWEl!%t z%y+qHYI`$rb|m%T2ZR#)z}$qQ1uKk(WZi(Dk_H`zP5=-z_@42idK zp0)p!Zd3~X|ulTt-pnthX^3NmZ zlk&pO(aw3=X60VnG5kngK5*x}CW>K6(QXcb(&w{;JLg60TdigM?40N8BJwzYOOk{O znb$%IZDw_(V{0#L^GZ`sjOPxap7wgJf1;Fn;)lA9XRag_zz&M>%wL2l5W$J4JlZdV zRD%+muY6KFM;+4;O{au3z19KzO)autCr;~L-vGPFBJ%b5`H%PO{#YIIS~t@_!g(d? zK|rc5n*NJ@uyD-K$-_qvO%BGAe`DfEbM(=oVH4Qfk7`NPl_mRjYPKvL&IYXE>}uQU zo5bhyn{Fxe(mYkjGVW}sE{FUU^uGxR7U<7WEop1$_e(0;*-&1Z*k9uc7_Ri~Q*3uq z59r75i1uBRxRLZ`i3`&f>!ntPQY*`STQ1f^6#Nlr6^iy!wW?jPz+EeDOjcbHzBDbI zW*7M;uh|F&A54Y${84tyw>f!@Yc}_tJbY-S;+cg-YjndrH_a`-?y)}dOU|#)5vfJv z84od|s_0X8qMZ&$j~1<0ZBUUn|Eu&gs7%X}xUlg3tB@{1tzH|1SXUN9bxU7rmw9d1 zh_p%FOhkdUuTjiiZl5-4rZq1(YIoUiBnAB9?jvXE%Kg}#&lbKAsD%MFwJuAu?6vuN zggb~3CGA*?m5D53oasYt`t^18?LJY^v(@8|3GoXe8B@V8ScK>i%46b>q3Y4#k1^n~ z(IAg8HT;4(#=ugK25pRK;5W)|l;83Ej^}qGzmS|ab6UXb^`_ysy;{*-?la*rn}gzwDpCFGacwGOn=g2W5?GXf$)nLN^;Psr-T@le6*GKi~W z6~Mb^v}1R~WmMFe4kunGI+s19MlnKYE(HovfiaC@jGQnO7$j;d3XIY!ltwX3s^Jdf z6w~PwIEVrx8^uUSk1j4 z^Pc~gO0A@YsZmO|QU9OrT>7r?_;fV(favb0~2K@Alpe0ul}b79h($o60kVw%KN;xd&%LHm#JHU&+f-0u57drT&(1OQj#?PA|HG z7=IvyM1OPQP^W>&<2x%v?zXoOeHNU-sduKN?HO}VMRJNgQW9s^ZoQ}6O3wEtuDK_a zI6DsFjR;F7@d_ZUkVq2X4<+4}uIK#ad8An3Fd{%bC4Uq;odEV4;DzKp7AGWsF&TPT zFXi!dcb;NX22#{f)AE|D^qx?14)z`j>l_m4_T$=ip(JY@^N0=on*Pfq1|Lt~evf_- zKBN~-u{VD506*-d#LWC|ie;L^k*~%w$qKZ+nF%DtzA4n~ztrrnjw5M-Ez3b4b%q zEa)dj_ABwTI1SD%B?!i!Tm*}aJ>dIXxEc$kXmVSh6)dOc2?(jOWtz+x-;a{6BbuIV zAy@K}6ff~$l^(2o-@CL!w8p`pBuv>_qUlp)(?V$UKDFzS(JwXWGTT4SOS@4BxM5r$ zfAM46$JG(~$ksBOO6cR?Vt%_?O>HcVtue8_`Ig_0sTXbS?|T!`pxz`z=Xa zv~P#Hvx>*7vQxB)^XK3DUPbQ*XeoO>cadw@ImoI4cV0UFBe4ClVVeHtRQg~+(lkpq zCS^8*ijG z_Qo4BmR?w6+qXP!#Gj`=8ikw(*7`*{?KN)$FZ3I>UR?+G#1R(8{CO36yM2d54^IfZ zBB|Rf<`LfMZ5AT$r6a0R{DMe$`XG`qoV*!&cITL58WM-l$Sj_4x1<~1!3Ke@)gp`q zami&dC-cjZq98#vQgr>!B6odE_v*z$g>0FXZ2Kb5vct89EPs>QxG&XSmW6QzI-ol= z9Ojn|SA+dq*eFX20{i*mVk*@*&$_XZHOaN#xwsL`&GB%4m3G;(&9o9@Sy?l3(lk|O zvF4){*RM?Pr%vz3it;%3x9;%?9s_%{nE!%KpC^ecL>Q?@Dl{5&R=^lOo7SWON#swf zR2|4m%w`EkK58=Y!XVv&%m^bFU~$N|R)y?SNtOAxKH9Z9T8|>}uhB99B(?9O8TVl`*2~I!%)s@QSiyfWaVI_NoF(uSs5vX@XeO;% zu)4O!1<#sR-q*^?bHdV*xAX4U%&n(J)R>gy1Y^5QmGY7ePfk8gEt$=a&akyanchcj zlMGDu84}q;b_q*ldLPQJaqE=nZS88f4_VOremfEfHFL%FvSr#4)grmrZ?BmKq?o{F zJmw#Rt^Moo1D@9R4K{gwKWW7T!6hIPdB)ArR&|5*rW=kp)sBIxlPJ(sC=M&4l^&_Iq1gR*s! zfFXOLL!O!4A=rT+i~0)|P3*OK;z8+q>Q9r*qa_{OBLA=>x~BNnRCn)VgTO zkt3S^v+WKxYv}7ARd*3xnDbt?@Z`0&*-BFXi?%m`kFvV@_%o0|K=6qLG%9LrQ4>W? z)Kns%8AxD86Gd^M;zDa{wbrf9KrAZ3NhFWsSgcz6wzaiYTdLNjDk3P5umpF&4W-Ir zg*yxgZtR%<_jm8iWP;lFegFUW@8=_V=6UXV?m6e4d$z0hb^e2z8s`#Q!)o2#WBhJA z&CCabZ)4}|l84yEa`5~H^XEgwW%Q?UsyAP)*wVyc7H{Kx^=W3+x8U=UFso3k`2jv)5L$@XF2T*gQxN{8C*!cZJ^u|rBfuGU}v%j{=>%ATw&v^wcM)cvVK3sGH* z>sCM>5x#w!ygQ3Gp@4g%+?e+K=0=0Ze-`f~_=0y&@h5!M7p2J=JY@YlwDas?=V=hf zY=)U4p%VhBt`oTDRv;R@;rKC*9uF|?y2RC>#k=H-)=mj`wmcb2kd?vFQfl+WLsgq; z^;4(V9ahZRe^-pU)Vz5EP0KD6dr=I7Zcr2OrO<1VLN-HBp}5r=$^sfcX+_9?W{|`o z^D+7Lnha(R$zCDL68Al0)#fi_8)!D+nuCNhkZoh6lXt8?<^7t1H|;D@_WV?t z#p~QA-?4WvMNYpQd27A)hlkZp{vfty0X%1G=J2unPAk~|i$58+oE~4M_wv+hX?)SZ zCeTQ7GJWRk53r38s9Z1iN*UcGb!oF?4TYJ6aWKnHiB1PLh7JKO)5}slcdE?&Hm-cQ zLjOxE&OhiZ%^=BWwTeV(mq==stW4^+>Df*~4<(ubBfd`mYt;NxgMx*p31*c}@)~*$ecADI3!6%e z*?T7II{W!rCmJ|N4ouC-nbEV~+4gWc6X?Nq3wkTS;RBK$y{i>UZ}PdLZeY|68a4k| zYY9-7X<~vIlpT6k{fg^Pha4)5(Im!M+D$Kq{1cE!_wGt#M-mrEc^YCSy4FL^-wVMx zV>TdFi|$Jodh6)XGnBq+MYdnL5!6*ZZNJ51(<$QJ*37#zKNmM%6UsIf5!{RYZ}j6tN7ran0E6lmRB8%z2*n05{%t3 z$jX~rg0cKT0R_MVTecdG3y3cHqZyL$qCo~k{lWq{}p|1c?A#RmHvAT z?{gwy6HA|=8<_#;H3Am8N71ny!REOgR-Agq)w9mWi|l-(zmmJh?REamD5+BSSiYVZ zu;zBlA70>3`eJXhj)c|E!wB51R<2y-vYY~oQ~&|A!(Jl_e=>Jxt5k`Dbn@G2Lx6ne zejUGcf?Wx8ythi-6Y_g>&3|(1jO_O(GvBl7mA(8!CDq`(L!yS$BDJCRMH;e%FB4+D zV%ra!7-Go@#VRm08C0l6zOeoSRl6pg9`*+gvKp;I2X5@WTg`!;MWY{Ly-uyt{GQ&t zM`P@>tzvYqdFA`&m&P z`Cf=_DhgLEy=i#&AXg!rCsIuJ1I|niouc$e$LhwmF(eAmi@<_m|gUa6?p&3 zcMhwili2^cyKxJd-_eA5P1E!~G5jWt@}PJfH#5Iy zY@O%LJn7`>mK(kbS1oB7*)eH3Jw%FKmBfGwnwn4S=4y)NcWddcVPj%&a(pOp{tD9n zl!Bi=Q>s`VoTYSA$r~9t1B0BOcGD#D4$(tDp^V#4{m*O+koErukG+{a>JkNu0bgC> ztnQ0PcRL=Z4LisU`6Not&m&ryzx|6^MhCWuHUvjnuaA)D>cdX6-2g*f@5G4Rdjb0mWCDJ3&x4Z09~) z?aI%y-&N^YNJtVoYJo%G+nKuNJXN#~*aDI0v){%&l9e`Da_d|V?J`595&iyoV_$UL z+Q=-Hw2Z9cxTQrqOix-{Tyso^C2X3tO{UL#iGsVxM4aVcPCse$p`&52Zt6&~OprYp z3C-+om($N+g0dyA`3ul@7nFso-kvmyL?VD%hW8mSDH4Rt$I*($n+_@M9X*<@94|=> zwz9uLI0x4IG!a`!YLV?-HiEq1JQlno^-%_Y;V0<(;V17nqZ;5{Z|7t6B&*CFjdF63 z4#{G=**!(SSIxE23>~-dBet;Ia*s5g#aZU8{Y@7Y?VZ2vKYxc8Wbmb@c)^gDqy4jJ zv7vl^1~0ssZDmV1&;RH0PX;pOE9MVbhT#o)ZfEH%(QL@y5%NYag(7(sm{=dNv7_LmbuzXrj|^0S69O}~xO{Wj^|d%}oq*i>(=7S& z$;OP6Yrz{$BAYV<)XmRpnt$W4)D@Njq{eD`sbPGtCEm>5Lt3L%szqcr)lP$GutO=u z)sz!$J(u0N;W%&RndB|WCtb-LYLPU3NNc3so4M3qQnpk?@A}W=3A1N8=|4mjKLrIi zYur0uv_rPMZ7Z_l=h#Dny6U{f)8s%vaBQfmJ^GoQ6=lTlyZSR(emS=UfLf8sHs1mc zr-=>``MRRn;_{N3rXbOPoyTAr)FCp@zY46EDYTPMnYgiZxFK^6h02F4fMLx~y=(U; z=<#6Cl}vP}nZx)1GLBE~&x2dHuf;ps_&!T-3>7kqUocRK0IX@GnW#PdIHQcEVkH6* zo@a@^N5|L^viZAFb6n{?*X?rYCrT)XuL~$A$C?%!KceGSY*(q*^dj?Nefl33^jFk- za|iDij47@Q7v5!j348Ni4YjT*2zTF?MJ3-mQ4)dx9Bsh!x9&sDd0$w$kWCgvBKI_h z0w9<-w|_U&OLCxiSgS4w$hQtbUh`$FVK6>wpu0U3VUU~YD&Lu!mBHM5bJ6-e9jQ}t z_!$EZZu^&APz{`^D%q=}@{ZXXY;c8lJ@1PesWrFNAfD!%(Rd0n1FuQ(BX$x&$SHMqP5j#8)cu`a3Dnx!3R1UcYz!t4n$7xtV-NFD;*O(do&D-_Nvv z)n4@{@AW&r*YDr&)qXxeOis*c-@d5Lw!hC_^$*_b_c43@9=cciDE;%2`{%T8Uwr&t zX8e!7+hxAVIeYznWv|~Wfovx@QRfvTlc$jOGmc@LuE0=IS1Lbcv3YVHRB!Q8n>mG7 zX!Ilo6GzOCQg3eeij`7<4FRQzxF=cND*U+W{MBK9qyGWIQ0j!~LAmN?^3`qEp_r2i z`RYz;Rj-l3?%v1EHQyshD9EiTN9X2rsEMCslhu7fE8QZ`1Y_&Ea~~|)IVDv<$;<+p zS6%>WiGqKxJ4LyXd8uo8!*W6j`X8Jg&o@>>u_abL1|9bB546}b=vy-#qHqazwC)zn zp@-FiA` zV)N{$FOQp+0DS+e>#|C`X&3fj8FZK9ZdMZ2(qM5FsjtMnGD+*JHBT!{v)%Q~O~wTe zFeiZCwekExHRKSX#cL_RL`pcv(T=b(FK91FOk9DDa5OWvbjqo+)MmEmyf!PG$iFq4 z>y4mphQKnH+Wg0Iui!3*!P|7Xqmww^T;FS_P5GwVshVWc5nmxM*BPWpyusyrD*>6C zG=y)1|I>W+4lwh**lqwz^7`+*`3cD9HE-gl@^Xa(Sd=U3{R97(3B?Dn zp~6g+n@fAE>{}NhL6BeL4AAq2|4Dw0Qh!16PRzrO-orxrVB#9GV?*FVN)jVZUk&7B zy*U!>@aDFx;b$oEr2de=gM`7=-wfBoH+(~S#CZORE<2(~Uk)+Qc&)z;3M{SB&Fvot z{oSccGV2wN*Xt0|N$6+1XxU5C%b-OtwvbyO*9W=(wF)`zZeHb*dnQ9wJRhom)1>nw zz6Qu$enfgqy`WrD;Fh(i1G>F(;VEH7mt=TBVv6zu`j>=wiGmk7mFlKiPHRxVQsVU= zlKeMz+)TE;eI;4_?@}&8JXb=~mK?8!w|^TsJ_RH)jGWTx1 zkME+!uaRPEfUZ)o;Zl4r<;GI0CjIZo(%vEQKO{+|mCw>&SGxR9`Th6GzW9GjkM8~m z?>0HetD;8wCVem#9&E;pcF^DerzdH-$p zyiH(09v7AYxMIsoNuOuFg$pEA6(%t2!!#3+fm&jK-L_Bn^EV{lql9Qlt5WZ8tlB~T zy#4pepLZ3Q!ngm9bJ_gI9J}U3JB7nr-b)LI$v8(WI&xSeQFlyEK(Dek_ndUSIiBL; z4eOr%d)}@QL^VlEF~p=pL( z5m!%;xH>Y?|M>4=v8;NZ3%w)9kzkLaC`r+(!lv#B%=cU0{DgM8k-RzbL{?}WsHGVw z94*=syJ}1z!u^xO>xGK3T$j3J@8{5sbjqJyJ}O>9a;DqMy}6BRm=_9)L$l+@Zi{^% zgGAZOi9X%Dxjnc(EJdHihreR8hy%6fS6We-q2vuMj+~^cJ$$C}0ayPJa>C{0C*3tN zQFm-!{8WGEn;WDOqo#xY7-8p^Ui-yHY4N{BEA}qUZ4T7kc|_ zN?sBdbMz^=Mqe}>&bdQ@M?o1cLdW1ypO{=2JNCQ$!oQ)QpQ;^qyp|m-U8S>_`O}l4 z9aK&GpjyhrVR$+Hlwd*`w^J>ls=*E7hrM(7~UV}XZ7b!-)!?+)%%O=Xsmzt zn^xtV7(S3O)x}RWC)qK1%_kvw;J^^!7=x2{hxr5J)0ylURxBL5mU~G_>LL$^Ci!=T z10SaLvvPcW{51R49?M--o3JU;JIMVXWh;U}o29!}YjDal0Nq~^?vCLL1Iz~6#5HEO^aR4;iIIi+B0Da|q@kHNj>0yf z;Rzfx;|YwXkiWnL=`pJ<&diUJf2L%`^0|fT_hPii&C3JH3(XSTs9Bskz5du>5oRm!_6X}o%a`Ji{(`yy zrW`9*=Wq!JSL&^yLTYguFT;sz^K1RfYwFlki$hhZi67GB5!0CoCnxa+bAs((5xUI} zGHkrLtPzaW4V95QifNfuq7TblB7Y)XO}LDFBzs_$9W+7kNWlE@30uHxI>NRoj>!u5`LSrGR+;T<{(-2 ztiBVO7VVA+&XSGJI-Rwfhd1o7i?$wuw2MX$JN}{>;7b>xG zO-U6|%A3Tsflyh>P7||12lo~wCI`&x3|i!HJspm7{%x}J9L4L!`Net3TjUCJ1=d(edR~HS^0*u zq;n(?;uCXv59R1>I8{4PxfB;A!CAs_;SUA2nIspmPyl=RDpP+cK2lN|=V~*Z-k$hd zJ~D_OG6?wTKD1#ry_(^tuefy=KYcrtxU{z{gQ56{!p0$ak^SUjgFi*Px&KcZU9?Pn zO?|{66IT)6Z22TC2gZ3JTIo*yZ3iPcD^0g%e747RR_|w-*cW1Am8CreYk3cpnuQn2 z@BpgrD~^zHk6OTeJ@OEQ0@s@#{>mjUj`Z{2>rzPV+H|qj5WYFsfoWdOUy*ms&0v)X z0Ao9mQ0*=fsxPVN>3(sabR^V@SN3%H@1-7f@me2tk>A9B>-{$z@3rw3d%!b1-dq+y z;nz9KC2FKmtJq@Hx8T_37k83B(x55#nm?zYg5^q}g2Q?Ue?Cno>m;8hNo2&r#g{Aw zIPVs7>76^tQM4y=ir?0{;V|;vaoICiqrS~YT+SypJoMt-I%rAu>WUMNp7&`Q)JUsd z(?9r^Ae9#Wu)ssKL6tK+u}kvXeYr}9ZdcZgKlgF9gJp|guCx^^kdXO=!g@?>|;%C<2 zdIOzJEKN?Z6h68<*Iz9@x<*Ha9C?0pDEB+}d5ziYH}0aH<*on5Zbn5=^fvRAf_ntv z1*ZFV^~f&PU&bd*Jz2CJh65S?EC5i8$CyU(ycoAI=d_pHhl6y^Z1hO&m78--x&+4%}`c`?Q+F ztAr3Q*fve`UxXAd4En85sKNd~?O^^`LVk{3sH*pOr-{SBv{?W_+2xLE%k*w!QPkwCml<282?$xtbCs)hYyRjYNx30=lz=yub{c z;>bAi1Me`9}WhA$9kWN9k( zpp`$Z1SjHukbH+&8f2xg`$wX3>t&WsEtNgHI74MuQXmKa#K;F+8W1D@6khJ~dAfb~ zl-JVx?l*0@tK6=;=Vx~J3wAi<^0Z#bxqR z+Br#nPbYdki5gIma>c?1JN<36*;q*yKwgJ((m6l-YePPFTWoH$jh5#4d*?EK($?8i z47;P9A(|Zx&R?lBO~Z+___!!o`H$C!{DA}m{G7$V9f0xq$WTJL7x5xBh6>V8&4$@BSUp0--x4)c-6V8BQR{gp>&fo( z{rJd2Og;-T6}xxzb`>9Y6$|*DB94rGJ?x*C7sNds;+G7PRxjkNZ*C!uHMxbl${!%B z0Ah`lL1Z8pskug+z_}wHS>s<(Xl1l^^HY$GB|I#|Y-GEzwFfbf4=FHBU&Z9jFJT9K8O6KNK5=xb@q()CX}vOncQQ3f8{F(&jSi5~g9_ z49PrH+Xv(V5Y$@u)Jg^V+3m>QA%| z{(=UST`Yjz;&5U$y<&nt@5zTCLiRT+4b?~I0MOXNA!4|~{Y?IdM8WSb(UJ^!h(8)c zqVfTr7|}etUD6Y49-R+Mdy@I-ynzIrz0Y?TdmpTUQ11n!bIB{0A8LQ33@(=o!g2~9 zJB&`|&`HL9`~X^an_8QdckCI%1xHKTQ7W25!J~`+ugE4H9b<|F5(r`39U7n4be$y@ zSe%Y=Be%N~eK9X>w29M|B>LVvR%@}r;Ru*|in1h0U}&*Hf}HZ8n7)naQXt@g*#f`Q z(#gn|7n!8Bsn*fvYP))kryS=s&C_?qqvQ5WYDF{er%o1WxKf=XRDO)af=O-*~Z|fL-2-`8t?)n0x24rKwNH z;Hy(SS=)*u9D*VNc%%;rFkyordE`MtFN+Juz_KVDYmg7Vwr%7O) zxqP!0uiVDS?cfQ$w63;6^V-gH)4Ty0^=EOM1{INZgvgmC24e-n!&xe9bsJw*G{69Xk4 z=baw!zujC!fVzd0M);@{{b+bcA>b>XKC~_ zyFdenl!wzcQ51>FA^@!tLYO(!>@e@B5UNyWm_I1BlrsI(Wwdk|B!7}psi(CZIp;ge zYjk&WhNqRnYffu(ye7+yv!a*TCt_s)T}M*HqfG$;{jE16m;{hK5@<;xGoRgHPXbUU zWlY414ie5TtWT3psUsauhq>c%*@IlnfE4-HNwM4dKV^N|>5*E=$?YyWG8Zula0P9t zxqg~Mqh-<-Gr+U;iEWdGTWn6+=-8dSro*vC``D$m_p7k=qI?@;zDsfIJ)D{HDiTtd zKFHt@b+d~*SBeG<0H>kscB*H(c?2v*B$E*0wK#dC^6WFk{HYjFV!wm2KO{kL29Dx+`_Tfk`)hs9*k8Lq zV{f>A?{P1BU*m50fo3tr^t@h+u-ROChNTX30e`I=dR>NlvRyXOuUnWIDrPJG(Nj6JsSI?IA`I&qnGSwUc@N!PnmeluVO z_B5%rE{AKF@6oj_WPwu)awnAv#^M4{_*GpR3QA8425IX6Q@$pnnnyW{Xo0R_+}T~} z{P!$)Dm8@J8gruZtW1M?H_=vV7?7=SgstHDb2S7C44{&oTXH6E1dl{z@O-g_4VEpK zh0mq=Z}MI{>dIp-NDtU?^M~|ZTVFED_fCEwMj)~)Ha}_-xkRPUlYwY{(e%~#Wt6|gOQ8V>iG4zW|L9D1I^8n;o{iJNK9 zYCDm|0j^b@HkCN~RCc#oe{sg`UaI6T>>2MBv+Q-@X1n?O60);OoAMsmNT&UDkUnX; z(o%Qw=q~sc@|V=gO+H*$7q1?Y?5mGm_5+*ERTv5U3jQ|dTlb}>r`k2_BjCMjpOJ@n zJ_aObK`!UnYrd1UHDO@Evi?P93Ql77$R$;S|FJm^trdlj&g@~wQB<~sc0u@Xj8%N> zt5)y*IX0CAsUFkq{wv-V8`VYUphBxD1b&o(9~>St=cS{cNmE{GIqPWVxI%-|h1@cj z0u>SxrvA}Mn^v#Y+#w1jpRh7_-*PA9qyu@B2X|gi4FCIV;wwE9cyBh{{c(pWMQ4d1-p6}xps+iWSfJ`Hx^Rr*yJpg z8a|Uhcq*BF88Rcmm}7li9A7JQ zZz;EMq6wLIerqp3o`&`q|DkRj%d_3|$#gRXD^Va9e*$OjM;b2yfp+7@Y=2sMMF9`Em|7q%c zxsacjxh|t&H%}%QAO3UIJ&kv1b&+RFr?ru+|J*BR!NqwTI6YlzQRGn6Va3Xul``KO zi5g+}5i}!>X8}E@UNFZ!g@pNRC&per-J6Mn)&;<5No@6$rk8FUreMpkGM?zauTtO1 zoP&6c2SW1_T{_lAY})A^fV5}WUlOEZU0^=(iz^ks?(ffXRiiGFPYptp6(2i$97{Y- z>xQ1xnd9-D)huF3T51M)k;81g*oHu2WCuZyD)mw$9|3erpZw^@Qgt2Tzh{>&RQ2hk zVi#AKIH^yl>}B)xuTYFh3@%eZVG(gicK!F(2mC=RG_!yt|=%YKp%N>O!@c(V?I}jP6UM)rwB|!|xtHOZ%Zs$?ud_ zLoj%22Q2j8Y+iXIR~a)-@kI`!wiNo60TfBy1%7IOL4D9d8#$(@sT)h+8nG$;e>?^8 z;`^wm9cu0iYHG9%6SRLGk+&r;&)x^%H9f;hDQcx?Yg-`t%h=j({)*^PG<*vUTRgCt zz$zC3-t<__U5}@EF0)j3IbvgVo{9NdFU}FHme=$)&9io1lat4zVs%d<)SH2S-PMtr zn*$HsQFZ}!iT_y9y!^%o%_;oAUo$U`B5Z(B9rG}CZg==3&;S0oLk#$wov?!37+6>~ zo0yq<*v%wi?V}8y z$$5-he4Alt(|l~G-7EgB8SBg{=5H>5TfnNXz(6~L-+tQ>c}uzaVy#=hMm)5BFxB3J z5&3QG6}Vg9dpL90WD|+Xex2B5Ry~H{dquL&cIn1T;hQL&T4t6{(^Qj}@-Y~@Ij?{8 zndImUd=~Q!L$s`1C-RQ5{El|WjA|1TqD{AAFn4TNCyYWf5n?6JD#xgw^8~4gxDT(k zg8L~N8$a8E{EQC`4IMsY+{t;7@0;syx5&AuVSI4gTYRbU*VP>UiMbs*qQfIe0s`%3 z&cGS^besOiAVYdS@qUoXHTJw{iN$PqG$R_!vvAh;BXhpLoc;bM%kN3PFn?}qw?YPK z9pg+dXAS7k{ zS6)N#;AH3TG7nnWwxMT6o)}5{D9A0=&pHRDmi+WDyU17W%mV&b7Bh5r+iZ)w(fuV7 zm#5Rs{%--yNR!0Dt=1dpjb1Eo*=QVy3Na zlLu=JM7%y6>ma9TZ1r;mo2HToM$$~KKH}W-f;NA_o9KPbzQcv=xFe<`mzsIEr^n1p*Bx$O6Y}goYhJ%m~QrA#EyTueJoMg|3n{I_t4M-rL-=YYg+MXwNw(u=n}=$M=BblUwSABoCDJ1k6Rt}s z{7)P)KGJM?MayTD1LRlaa?yd1tA=wVl%a!)*CPL0oeEIK-ZQ9?A5!mZHgCHEo4uAE zR53HP*xGi)_N#S@Emt$A-Qlv%{*8JPYR=;x@tJi6c|-bikDi*%!mv>do-{PAuJ|=& zWiaCp;urX`a5Ybz5#wq6P1EEa4lrmrB83?n8@gmvh!va6=jj90%2UvyJ)fm7^Jq+L z0)|_@1*09J%!Lo^BI9!EHxBNM1<>^|4^a*1^dVd9jo?3*6iE>Qx%?>1E+$P}#e7tr z=;BVFv8N+>o}Qirvi3lg9K}!9o`UI;Cj+gt+!H*vc{xWY|DD-N40@h-=4Z_>T|WDv zsb0;?V?{`NbgRdDa~}8T*p2RZ*dS1i=5f$^0DFv9rQsCV&q%wBY=sx6vCH+x2%q{& z=hwBFZSIl3&bgknlcjl0U3P+s^%g@-?e$dztbVQa%;W@GEX> z3?p3muUi*<7j18rpc7B?v#h)%G5ZaxGGxq$Gn>!&VUyr+IOZzjrvaJ2$PVNR1|nXg z!R$?+$$ef5{| z=CyoC@Tv?U6VO#Zt7oa6=BS*Rb1&Bw{Z>-Byw*Xv2_Y~1eyD22r2SJzAn!5C35&Z? zLtm;^Ox!PIk05RK-m=D1j*oo6m*N>EUi05Us2N3Gv(I1AA;sVKZX3@p_Vi*T0;Qj} zJ)2SLlp-N|u3CBv`Ya|cH$tVZ!jjT(Qsc1wxf^<-Y9vMkQY76;?@!3>jW_k^;NuVU zQO0L9W>mlN-vX@#AF9s8;2vbJxHzwAWpqGtJyTBOKe|?>E4etYao6#Y&ze?7iXGl| zd7n?MPlAhUC4w9ZP-h8J{3jrcvC;Z{)wfInHDpbX6RFEXId%Y6AMm8vN6??|&F#sF z@A%C1@O~Tdr3c%6W2ucpSzS=JG||7%o4YT0Pg4HUn#1S&gdC$%tdEZ^s@T+W(V&5H zizun{$@EBMXRW_5=o4T1RlWaiYRKi&Gx0b#5RbD3CD3BQuh4vXtC(!0G98a|T+QKY zhxR9G?j5h`AckJ!e@gLeOwO-5V{-g2Baa3BjRdfIGwC}R`*(L)giDkrxYTPthzZtU zj9{)Fk4-CsEf-^ddIAQM<~J+Td;kn9G9Ol2CB@W*B8!ZCOOpH?`sVy(^`L;Qp?Bj= z2Xq`CB>>k_M=0n1xW-{UkB@AyxQ8Vvx+V2tZa?ej$Dy2}dK)0+WDCsE$}6CgdMGka zP2a@@9`>%(Y4v*ja3p6kI%*sv8-S7b)_yJ zxmT%uR0=awdLDMwJ6Aj@Wr)bP(QE2WXWAQf+~hX!Ye|TZ9k@PJyJ5EsQbE+zV<4lR zs+{ls6h;OC=lr3LpdtrQxg?>a`0*oiGY<48nD}K1 zcV--D^KNU;=S5<~SAOfVWUnQDYiqKb`;+hf6uLh}y_Ud@V%xhzvfi|lsAOZDC(|69 zNcUpq!3lVs%{cHn14s|D#A}+sWUV{CMp`oW5v}YCz%ZUa$VEACDMUodA4FpV`IZMW zAhqSsxq1sQmeeE~IGSCLTcP1gg(=ZnA<}bE!`Zn5`67;HE z1t@|CZ?lL+7J|=0Bp}%C<0~=OCLov$!gURD{?GhtyT4bUbA6&uQ7~TRf2FRwMJp<{ zivJN%64+96`1ZZi6r@WB{XM}qHxX{vE%LU_vJiT6-L`iQ=d#o)8|u8pi{%04_^^I& zZjP-d@xW&c(?vSBh2tmG`v>JD9tioRR!wL@5_)sBo3p>CSAM^wJY|KV#DRgZ(K3#R z;`W_FJ-&^2%R0gSd+EdeAfaQTay3^&An43HlnUq+TK|Y(65K{(s4QTLOR48Lg3XBT zDEF~nI?`6&ewug})18`NE^6WynwZ0vj^qnCF$hlS=RPXo-XTXyq*e4e2de@ znP2l%4<;1VCVmOQh!p0cJM^0F5O`ScLZwnT3m!Eoz)p04lF1Ma`So2$tGF25!y1od zeSw!q8QG1<)N+^TV4DWJJi9gdDUuv$b1JX(cL$~F=|89jfrqQey0ED8itHHUvxQ}wym^eCj_ukhdN8c$5W({j=sd;nSD`}PR_f~i)5 zzgceCI{d+H_A*7SWi=_VFq1miC)~Zt4*JL4DCjpF&~=roS*@m#)W|T&hEqGi%u;ul zb$=#oN-9NkmtgW^ zSN6{P%o|r=|AsQ*>ZM*xCn9zNqSc>7ZjBEf)FqUBA|UPLD}?}7!Q`lU(4;M0W@>sZ z{U0*1*TECZ#B|N-w=l6@T{`fdoi&?)AHbd zq<}Wz{|1ZyYrFmb!^du@&+xG5$p1I|>mblG%_GM1*p(o@hF-6)aOh?K=Au_SsN&FT ze-LeN^f~~h)rnq`^MzjfP|`g1U!2}d@<8(ZDlrE#W4WYOU>bJrGAWI~a2E(f=7 z;X$kP4TX>rEJDl*hM_lol3|7s^jBITL@5N~eFj-sq~71IGzg`VLd%R_E{Rnzj~NS9>q(I z&W?(aGH5%{^vJi{fog!wm$E7~{)(D!U~8SDv)9tPX0mh6G}Srr)N^URh4$dM<#PG0 ze6~va#~QmQr1z``Se-<{5BL!BYUE2;_FI_OU&Y=Ml@|}q-EZbFwhq%v-|H~vvg}&0 z;!NU#63EyJ2{yffbQSyR4J%cWBpQQheUN;}p-Y!~W|Bph2v=+&VPq>WOTWIbh9&1w(oFI-n9kmV_m#5X-&xt8* zkD=q#!_(7!Z#Ml1;}XbteL%mD2rmlod`UNuX5`0CynNz^R48wT<&w9DWcqZqa;7qjpL zcxEKyzfmAK&&st=s@S%Ll8}j#Ox$DF2`_33U0ra0UBI*eSERJTmZK(zvDES_zx5jX z_Bc0q6m(Ekz`SbT-uM=s#!qscre*09=rrZ0K?KL#{i@}dFMjl2KBei-K5=2n(ioM zrXe*PFXlbz=WNLSC-RPKGw=ThS0de=1T7wWXRV+%$> zgO^M^J}V%YTN7|qLS1Q=@uu5*5yqN4oW|tw&dK8HLOBIklW1K?85;%)iKX^iL|S{F z3yG{caorWXty&N{nLgV3eqH3y8y0`q2DS0-8#+xiXHvD>_WsRrq3M;!DJjgZ^upW}@#;Z{8=5h`g=- z+iCZWoeXUPtnI8{|2K?zK)L4YwFn=rXDD~ip!8LK8h=&xt}7rUy;BK{I3#Y2kr^4w zY#+G0qk8M2Kx9Ph*f+JjV_{B&|GE9% z%zImyVOq&$NZL-1M3CrPxDP0ts2tzc8wtz#tM~UaGRyKV{ukPKtgxbqp93J35b#?; z2_#B@L<#q(%TN*7*WAI1!;i=(<8zrgLXA8Ja_n8zGXoq}wt|7#j~36&Wf-hp6a&&_ z0-AQJRqGpyAK=aHMv}VyQWx3Za#qxf2ub;u#FFK)9la)z?qeC!l)jHnd*iNrIjXRbruCXP$Z+rmG9% zL;hvsyr$dLYwV0rpf2(3lX^}(E6ux&mDpzf{TtPNc8NYrT{Pc)5Iauk!_*fB8D8b( zZ8>eydHS_I^J{b{aR%NMW3Q-7jJ(c@Sldj)RRNmaZ00k7IM>Hdwa1Svp9qphEe%sA%b+Zem6mzJtsOy`0#6Me|uL@F46N&5)hc~7FJmwxe`)OR!I zVUDA9RZAk@X&ll!`k8!AVk7$KO%&;GL{W`5le6jRCBZ~!b>oghCtd4U!JDi94tz_Z z!N2E~L_DpbA~b=q+P2o@!xe~+13noghE`? zgn&>-Ca?Gv4PH|{!^L1GkJ3YeZ2Ta1CYA!1h=UoTb3+0P(Vj_mGhb}rU!~OOH4tx=glmdHH>Z=cODbz)wuImh$A+CcsPD0 z=CM(ws&AP!;t!6!McFZ$4w$d&+G|!em2CHNY5aQkbe;T&FOII=jE@0vLdQ&-ueq|j zlqS2=4seI_)Fq}A*^Rq#NVV7edmwDVz+qXk-A719+96}S*Y;A>IApNbbTPl$NA~Am zKz9QHhU?AjbioU|6pYw{^0&&v(EzJ?%PBm^M;5Ei<9Q6nN8!{|TS@`Qbo&%<+Fg3` zMqJ;T-Y0{kMnxx}xpjvh5=hee&wc7IR%L_vEI2 zEjYE0ESW;bv-D5$hX5~4ziEs**1^{@7z^JA>4bXT%>8F{YZ+VWHHE2zRqVOC{lB_A zNIzfMl%1LVPdMW>t)Nn}lz*lJ)&7Dihk1eD|4n8+6P15IvXfstdn+0bphw$j)7%E9 zFQC3X9}Y^_pF;gqTcWX$JAE7{wzmc{j;%@t@|M;l<`1$bKv&!RV z4g>ntEYAh{T^%V1#m>57ASOJFu~XN9*?GwMxMFj_$jd7_f`3YA$d)Q3xvqTx3*18q zYiHkdLsYXlfw?<9YKqXO?6+O(3)d~#cq|kDYZF#df;2lS2=t^bDso2!KQlwB4`ChV> z-;SQthVGkR7Yck}3O-UBL4R@dn%VL|=XDJ_q)W!)Dyh@Lf+?@_JJgyw&HVC`k2^R3 zj;*WO6g^Xf?(BP}Z9PlqFV66BDaLF3&&@HktTQ2vW=@jHzPHB^vp`>dGu`ejvG!tf;vW^gCZRzt zX~$*o(~2vJDaEEA-$U^^A&Akudm%!I!gOBeLE=qkd9FYzPCoZn-LBFI=wKaF%9Hnj z-{11vo>z3=$t~p}W`8p!QQxrZFEl^onQ$u@G28!Qo#X%Xo!zdx&i?H9=)>Hgni|t7 z8dG-sTjT@6y!=V!RxVBVN9q_ZOkwhH!1d;*vut=dL2f6dGYeVV^WQhGeW-PA_^uU= z-SV4WYaISW4z_R2jr_K;^Df{#!yl~pz1gfJ43)^Lx6<<$zSd^)m)ZO6Ut`{2YaxKe z)fIhWwVs5x)-P3=%q;SjSa5>HLoyH5df+n`mK0pvtP_uQ65GLBoAv_0ftRLil2bz2 z`VBxrW`mc__aT_&NCB2k{dZ0An>O~jIl*V?&l;9050hLa z{Wg10R5SfhplL61o(l+?$t7??>;=}Pl5luZLh05&+MtoGX2J8)LU}F9KCY3L!YRF` zkbV*P6jQ=396S_Umy|BSN*d#+OJ%DdoSA{=u?(EHHb z2W?W#PJ7qBay?@_=6XiJMqHRQ3^YTZuz>eUoWgX&Jp6q)Z{LJ`m1JDW`ILhstU17p zy~rLMAgsuhPLUyL_mFW`kr72JK;P+MD9}*>#m37S$4BRLURUowQ>&D;?W44Kl)!Kif5wDC0=|M4$i2JhHpP}(cbxK$=M<%G&`em#`XBg?SL3O?q} zt3?_Ozt9?C)hjafuY)SeNV+KE!E^+o*+7*I3xDp7P{G=;Zx{(H2N`V>j%+oUqXcKp z`)8t`8h4>R=$B^@lTmWc7s`#f0AL3erJj{sL3#OM52OZQm2RZ7Mh-u9g0anK@TEQd z&m99sihU_@R-)i1Q<)|6Dzx+B!5wma1lNim*cE3p!YP-}@*}qrTS$uzE;l`4VG$Eg zr>P)YzU8%#iUU~{c6VOCukBceP4d0F$0D=;Yk(=y_w7Sj%rs4jkIp+(G=&3qnd79B zi-WWB@=EfapGku@z{hO-t#F?rJ;Ee!N`daH%x`H{xKq?8tt2URu+#dQM{mp=7uJcs z&F}dgYPVz7lr652usA~xO3Aw$-Ow$?Aj9XTKGPk#JvUEQk?kOUx8<^^!su8M{k`+; zT8=T}fr7ti+=Uug2UzJm^BIbhH^$DcJ`8BN@Lewp&Ru-0Uo1m@$%kEcN@1XyxWEs-(e6CPr-F2B+VKaE2-5n%OAi)Xa zyB4DH+lV<|9z8<8&$^qXQXo5X;k<4YiBegb9?uHuk?)9VvaoFw{M^aIr_^TiBw5TX zA0QMppBgHikwE}}D~}f9?DNJ}tkn2)E{#no%!_p17o->wys(HVTo5o%oFndXap5Fb zB2ioq=x2Max&>!z9m>XJt&%dz!FO-H5vK%DHOiV%1Uho`fd1ZQenVZLW17PIN5Xh4 zQvX@4bEniMCCLGeH6E~+xTDyxw!FwCHZH>|PZkBjRisLrI5Zqb@e?0rq+&6l_*hDJ z$HRN6IrKc+X!Lopi$ZhQBuOVcrDkNtYel9`n2N5=3bDF&adf8Xlr0wU7FV5)-@G+Z zXl%`@umao@T6n>h-*|1I5O zt5*#hhaGoY@+saD4?HRme6rBK^_u^vX1Sa+_+(M?*RG4txxOW%6zqs(cEj&NxelK> zo)cfv-o}fLs67jHt8%$rwk%Y&EV`eMKHt)ImQIP2u|2cb zJH5-Tna)#h=kl8_{olzTy7uqQ?1?V$7>=_;mPU_kT8^HuM0}VR+0>G5v*7D%m4^DAm_ zSMyuuAyIO?$X1MZOD!;WyB8HNQ6lwB=l+oskA^&9N9#5HR%n?X@zr>PD9qdOD;gX; zNW(k7dPpjAxEbb}bpwsoVPcE+sr6cG6{pUZ*vL8ct{Y7jzw|c8iAYZ{HzHqQh~-tqLVZ z2SS0JsRO;4h5Rn#8|mBT2Wq%IcVI0me1MjZSQ*%9bfsmsZhkc7mNRpHQJ|jk=e{YE z?U@=}Vl0j^y5OFmY_PC3P=ogIP_~>R5$PeO6EO6_@bJzY8pj>Y@m-f{u^$+jqQ8gAFP+~yZH+v=$z znQrm;GqRecnF z+nZZ!PcJCRJNN(bWlIH@PJDFsJYa72v$NzZyukF(W7UFR92hEFfD$^K7&cJ&ki6uq zOdiYena#!pm}TMN_Rrl8;@ZFChj}x*OaGso3X-D_SOAQ85s7+pw@4~@xsJZrf>&mfVu`o<*+JjX0yzweN7XBddaqH{1eiU8yC%5ZIFsJ^h>WrLX=h2U4|DHD& zuZ_*7TY4mR9%Swx8IWwSxI3cxYKKqO`i|l2(;WUNK*{MNohsg%Zp={vzm=zK@&tsS z`2p+Wp#4eXHL}S#{?2(n?AtJG3>&b)){XgGOfPnhJZ>}JMjGldbg;QxTEz8b`QgAG z@V+i_!n`Sk%3aqS5w2HN{( z)BWGxFWdjir>FZ5zM!*4-7!BNR9LYoLl5>0Y6)O@NWFXh7`a-69P{=|sk2o`@V*@tOZl>nBAOpIy29s+UvE{?b;{x1#OJw#vu< z*`_@4MHO5(o~1`wMrNK;vAu>4gY-nlODbMYcaVCT^_)4PTkGl~qV;(ql%lX=d+ODk z`W>ltc0O(@$)C9$JlnqHNi5_ddr(;-Wiuvjmc5Q6qSrJ7NO71%dx|`t8gTja`ox)B zt8r~%cv-UEf4v^={JlE=bDfWurAU$a0m}E2gB@?jw&z7^rV#1-Aw{AeAX*Q~n}uM~ z5g8CV2AMh}iMn+UVqK|yt@Z0%x}5pjnvvDIt>GB!38{KJsRzqpse@EyTshV8P9n4tf z+*0Rnkxu8T85gIf=jvCJlOf(5{*?TEZI|ETS2{R~H)?O4f|NT1E}?VDbrgkb{hU|x zJ)PWFnTy@4AMomFeE0S0boXi$ul|@Wb+UUkl2>=7Uk!4vP_$G|O~2aDy*fnuM6r{k zdr#-Mr{hG1tuM$N|6r3gEgDBIcd0Rnb(&sEUsKKfrT$KtIN_&NOCu+GGs&PdKhP3l zmtPi2oE`9Hh816QLgS8$q8}(lDV{hOt|=US)6p?O*Y=>7EgU7CLJe%Lsx5NpV*ZwG zM*vX!ZP5opgaEU#r`F2fg$;G7zPfgjbKo*L@aB@M&oVd%J_+1!yQ?RLgaThFSAiog z@J`IV#Ji_v(D7+a3rk%X3M>uj(n=jDxu!-M)G+D9wjt{@@@&~K_vujbh6@mQQ$y45 zt+Nn`(bk)tqv5MkiDQ-j&}`%vk5bRFb|2~&p4X)1{@{iK&PZG|oCZm!V#|LR?0AQR z!?U448e?rgC6n$z8GC$Q6bLRHl7qA4V>O40^-3MKP<}&p_$Fug(}GaEsxhw4n#oxs zaK!ukr`Q)>VgKrh*Vt|NNFlv;Eb_8yz@@8HTum}@d zJHK&fV{|BzS~shCP3@nazc&*JwLOq7upih^)f(O4FUg#D5Ta}g3tR&4EdR3$BsBr_ z(B6&Vc9<*q2Nl#}uSGUJxVP8zIuEy;D;_>2wmm=kGbEtc>YlBuzvH(`(21=+t#x&u zz!Gof8Qo%QPHSD$!#;QCInZjmO<=sleH7i1mp7?AwI9giqPNXL^Cp_i-J0&&|*F8)%)nqXRFcTV75~&BOFJTt6nh zn7FH)i8=V~JZ$1WQ+Fdj&}D4RVZMe;V?8=Y8rw1DmR}{W1_q8E@RxC3MYx`#{~RS2 z5iL{D82`Vddrm>r&%8?t-k(Ek4?l(3EICnRt&CslCXjiZ89Nd>=~AmywI0jXD(S41 zLr+>CbU53zKIYnLAv1FPA`{t;HyEl0R$T&B+WYu8tc7X%=C$2f1jX!XTl&=ok$nSy z>czb>YMxWL1Qv7SPtvDwHNAKKg>NVy?pi+EbOwIKT*my4S-|`y6WaWeo$|X=9Ig9t zT5&{|#a--c8D0V$rfys!29PMY>ngIpU2w%W>8;sjr0yd{_|%0e-AQ$6epQ!vVm0rr zC7+!@YUlTWsy1*R&bHVbvlYN5#_qC-MAn;&cIap2sdzAnxx8k77VOIiMCa_CkHNm{ z5?8Z1lJCS~hb*VM>?3yb6&;boROzA$#hMB+?TjmuSi~r z!Y6)XzW0VQYBfK^D#Wj6Pj4+u`Tm>sN?0=UM6S7N@xX#|dY7Ei7U`Yn|K)ZX3Iz}> z-|?pXm1^Ot#on#=^WaC%^>4lc@80`p+F#}RK3YV=M%>FqBgp1M5Y|IKVno+b%>0rk z%M6lOL_4lpTwG8}Z?qYCQZxHKtuV8HQr$Yf>fJQ=?tH!L%V7LfayxB3&33ew$t%`E zW*#~ks*ZZnkt&|)DmJL1?!0y9Ge^@7onupUef>mMGL*QgROhgrAcgMf$)-xCl*_e#`EG`d98E zUQ@9~F_g#`uUXI~0U?ZQww$WW!zWt9z1Pyjuc^ZZjR}rCBRUy`%s&End^Mc6-J(}% z2Lwk(o*SK@Mri;=YT~+$W+qsS6H7-VWC@QCv-?v;*4Hy!%MI+GBTLXND_={u6`V5r zrTGWpM6vB;UfTxzyqPBjf({Appr{Wfvow}7B8O?U*>=$LEpgjz36=rfdnf3}Oh4seIY**Zt2qtD z!Du)k`^Kv01*h@JW^QG1@IY+0k`rr#cx=ds#zHzPg_UF&SMiOHWcOD!gCNOVwQ}gK zIq#$oJMKEAFv}vDti&49YiM+^*QD#P>l4?Z0dPh&tIm2&CePi&0i`@REc4r+a$3=H z+=KU}bpUY1qrLNHU&k|)pK%oCu?AspjB15o;JUb6&)4yMhLDcu2D7YL`9{6weR;#_ zQ-`GU>?bt*c}|<_u4Vllys$FjS-6n6ARRn99;slHaLo&Nf8U91Na3|9# zEFZ8oNZc#0EBh?e{XDemjN-h!$b)?NlNi;i-vv*=5=~1GBbx@1x6U^NRbLxFCOLv zz8JP4NM~cu$zR0G2UM*rk!aD4Bvo zYtQxWI7B_MVbXCuZfnt!5E3KZk(5AR;y0h$`cbz;{**-iqC&MFXp83`V z1#qSf`<#vmlWphfA$y|ga>jIYeC`3ev!k_R^F-gd*x}315doqbb%!?Oy2TtKSYuXZYS?W{wX&7?UCW?IO>Lx7mxSWlzzK8PiY+CN`N`iB5zo8c0B$*%}61h``IzT-_qL4(MZZQ&)Q2OO`3|`47_Il}Mc4 zuw0)OZed@cRpbk&fpCB;!zq=~jYuw_zq@lw$(mRdP%a9*k`b8xauaMQR96I|uSm-UAq z8$XLJa2F@$J{g?Xyz3IrX}qDtS+ME1L-Bcy`W5fTPNwbaW@Jg$TnF}_gc6gB>inxp z{j17diW_!w^C|;^7K0qImfa>#*>Yr(qPnuRp+LV-*`gr9D3gYAWf(`VLE}+mr^zk5 zzan+OkMdF8@ql)T^`CD7Bzv->qM zJrWz=1g-1*MXb!YQ2aYeZKv!+gH+P|nY#@vJ{Ka2GSD7gllEtxdPcwvFl1Z?QfLb^ z?US&jA>V7FM}WrOXuW!%8-ml!l%LC|`h`J_G#`u~Ad|SRxe%e0lUKR6Vr%g5r8Q__ z4#>(IL3HXhfiDk#J6L5RKMBVt75T7{8#C=3Ozmzt*N4f{&$A@vzYoz5W{D}|J zOybogp;-6+p?JOt#YG%lr(P|3ht6Z`r!+11eBEuT<_85WjW6M+lqupcvuTY@5C5{9 zB-ST%@~4`rHm~WvOa%!P6!n@UII4PG^BZ1sqxj>@!cgn_o>Id3ugBI+2?e&1;kp$J zf`^5w7I}AGs4B3dJGsMy<4(UM*Kx?-nT#7!B9sPaiFWKw0&C3?;4voyq(n^;H^IH8 zm|c(mhr2hAkGi`4{}Tur5S^%?QLzph+n`oS1to$ukpw0+(I_s|t+XoA;zDHxqoM|r zXr|*-TCKH$zvU=bU>k$YuB^&$;Ob-Cb`AAK&M<&CSwV!h$x-2$~*#?G_6>vq-rqC*_fI zc2GamA2EsxAD?Dd?ldfz>OqRfBxIvFDYr`kwG@AG3;@e1GyxI`&>-@Z@J5B&QP9vV_dM~_VnTePmWZA>Z3XNSff zOCejy#@Uekg?{Qbxq;t8KTmg0$ZdH8*ljo}EUhSqDeuy2qBW zmgv?cuzWQ#qA4{I$;086E6}`KIM;h}6rDSkY!>qylw13)PjwYlxY zm#+D|M6hNl=^Tn1*s|G3_LYq}lEvJBh2x>)p``J7U-Rg z^ex109C>X;7k?vdx+^4xu+!3-*JY~kBVAkEFz1av$EJr7@9J~Y0nJFqE&w_#ZBWlN zP<-Od*-@%LUc>*~(u0AT^vei~`LNtPip2vsHH3hxG3yE1(Ku8igsEtU(l&g3!~U^- z(v}MA1mS* zs4>zJ-Ndv|GZ}zo6NG{qlV@WlIO=`j{aPYihD}FW(D6;ZM0)3g8BH+o1Pumw9V{?P z|F$8ewANj3EXnal`Hf!WzN9nZdKZ`ageav{FUv2=uuj`7VJJeU3?&>|2+Lp{GN%oQ^G?z8C+8 z=e-YfYTGi~Nx$TEr z90zA6k3kYUs1koC$3Kz=F{=%VUw!a!*@ zpAocBc6OWWe1-3|(s#XbV!|ZVmx-ze}k@R`qUke6_SF+E_#XV8)M2j zodzfEle>wo;?}SC7Wyy+SEg%OY33%?wlHO422})KxEu zw0#R6{$C~A1=%B4-wngtDs$#X*Z9@VrQyd>c|aNS%2-mFnPlWmP@3bKWZ< znyVLXHa9{NLYwl1+*Zhu7Z}uRfmmmg4*I$st0}AQ9l7cRz5$^!xXUCy+bT_w^4wCF zo+K?BtKH0flrwJK9ix)SgOLnVGjRhiD(X{RXArzLV# zl$N2HGB<57STUMI^)zH==BZ_zSfJ{8b;(_mqp=^rCL2=^i6rfQ8|CF}N>(4XIP$weV=fw&om-B?pl-{B>M5 z<+0*x#2mx}-9~YhZ=#as(S)h9?Fhk{pS1=op8WuIVG@z{zw-bKu!Qg*e%VrxT$B8H z5|L&Au|o^mL>lDI{SRl8siKDEm36RY=;u65SXvSg&1J{Fhk1l_cmxH!t@g+8XStcCFdU}pmB#!?d@rhBaJY^fpw2{Es!M)YR}IGNJlR*Vn>>zZc4zh7%SYpTeGS91S1&S4dBirgb2gXr zFwi@mp`h10&fXguyn}LDaCk&{V|vsA1_E+??q1$k>d9r$FSO6^Zv7^cLgsF!WC*4j zh@;*TM|bEezQb?jtGw@S2wv`u)}^Y_ygDvKlTd#WKN%UgC9z%|1O}36=yY+QS>ixO zJ73z>Q9-M03&YX9?}h{~@2yMi;JaEJ|5fHt0Q2wp3)J}{<4`pIoOk+U-ugh#Y)hop zuKf_uPOlAZ170p_;o|B(BG#W`YfRmyiJ+u-V<(zn1qUh4Bw1d> z*Fy%>jvQ1GKSt@m%ko*oW$V4lw4HxhqVVLh#?(P`mD>`#@8xAwb9d}z0ekKb`kT5{ z9jU3r{nCEQ-A{OJdXQ@ko}zA=RaxyW;BTzELsj%IRbOf+f7r4NAkbII;Rbz8OaGYk zMWz-nb0d8fz0g0dGAl2N?;Im&#@+HOpw(SpZtqi;`wTRwX^$z0D4bXq3aBk?Awi{(F_Oqt(8l z9stXN4uHnO%l=yFy2IN7mXZEIsiORt9} zQ;M%szJJ!lu=L{%Yan{wLuHM^Ph9%Np8@WLaxv(j`01iAn*O*d_bzz%D6% zQ+>vX({TO#LQTO}u<55p&Fy(nM)dCZ>#pkCtRFDqWcrAr_+EaU+3W!a)hIA3rCP9^ z44lKlGpX-g-Vcpz6QNvFMiHX>%;QSDm0jU3dfD6OyIW>8q|PYMG_q2)sRTDdW9*O- z%-=@j4md&SFA~4<-=sCB2X6O<_^<*!`tz0H$-L4bJ<5U}V(GS`5}`hL9{H*0$#R*ps%#)UIowK7kmD{K982?;`Fl)JWfK27EB{QtnD1KO;8fhGd5T zmpPx+CywAmgbG3+IyyZJs~}ah`DL`e)sLu9U!6Gd;+5g3{y{&vQT;|uhXWeM)q)F4 zTo+Xe2lATTxhD7iHvDuEo~PhE+|XFtrpkDOkLQG}V9Pl074Pke|D^?Msc5^r6#J0y zNHoPtE3R#F)O44sZuOIk*OJ@UQnIudCdHU6hIxf;V5@ zcg?Q^$r?OnM%oADzrOCi<-h76KvG9tHpqZhO)BoQsSPU{q3K52Pg9+ApFiKKKim#p zwcb(;%dV)J?6cg);lg-=328yTEwPjP2-MWOYwaB#s^r>=iVvbE|Dv6e*IKIMD(H9;8gT6ZoJG69B3>}cO2c0AI$nZ#7Gr9>WBKC!m#$_jurox)HBe4f1{35qf895k2OCq*aD zS<`3mtJTlP>x01J>j9_$G?^Bx1n=paUS_IlV%da4Gt&&a{Ou0MCI=#fQH|)Z!vIFIw276YxKmEy1 zcJnb}b5M-?*;|{uc!OA53Z#SK3nLrYwz$L=hsDPw)b|ON<&@|wOw2`@&1mOVZes0> zrf6%C-D@OxE9q~&fm%Rg4wl_4&(8vu1Yu2_5sR)Asa5|`BZIIq7i&p@*D1L%zW3%P zcxdKSTJ(~*nWwGzBWgPer+o8pNNDsW#cp!$%k4`-by(X@rZEPAahxxfOWq%kAz$$= zpOP#8v-oSUO>Bc*wSq9n%zeYCcAr@%XoK?s(rkWIDKR9Z91isi^nnH;}-5I)huy$7TG2d035cn z`V(@)3i31)c>LJ5@DwnWW`ufdWR;fz2opU*Op*I-nJHqC_BLM6p2`2b>iWVi_8xf} zX_wH{GOpV>D0_{)z=%Y|(Ym(YK;A9{~6~04E2BDSNc|?KSV6W$eK~9 z=Z54Uaxwek{dOF<2K*Ub_PWWQohjh{4taW&|79)4<^)%YG4TWJ-_t%8kq_2ts&3q9C28yZ&EVOBF1okg{&ac z`h&dI7{*VH0~ABuVI7A28%G4l|0T(FJvA8a=Saec;9!X0!OpFT;Kr9WTTbZ25uOA9 z##zTnUbGypA#Oik$PTl`3CVTPqL2A}He=+0$LImI4TzxySUPF&CrtR8eVo-T)TazS zFA6^CfuAk!r+m>{m=hGb+TGo3eNI!_ee_02_6_dS6ZMj8`*AyP3V@Vj-1UYKpxaks zI3s84z_l>`t{va*34d@}&m9bsff6ikHBjbpVR=>8KRxGO7|C7c4~Apw~W>lB}X?~GU#?nBC2&v zm=js-45ox7ywRf*~0Ob*8&) zpluwtpK%QE#)Ft1e(JfxhqdmRO5Uo#B-~>wj*8BOkW135|E4Rh}SMvC;{TGL$ zO)Rkgvct^l*?--x(WU#;AI9jx$_aKui(SEEiM}-h<1u;|>ZbxHmt3j=1sMqMWA>g0 z#$8n8^AGcDg1DBx8_v5uuG(h$+;9K9rXT5SRY7rNGSpE1>|OLb@c6|~1lxppHLe?% zAyhKwm3~<3SB7vDGM<683#zD5BT>;xjmQDU`f6Ka#o2Wl?i4qE+NPfD-k$%dOf)Rx zj^c}T0e~r5>i*uPlUf_xt^5@gm1}Sf91>vDD2RplsGPbc@ALeH6V^JTc8jKv?(^O- zGTxR!*$Rqo5I6aG;PiJhANRoND7E}sVBfqkAkR4Avd z8gnS6ULIHUCTee3jWT!K6_$7MND1*$H)oT6C60tX?qc|gHY~H$J+qKCJ#OwnLH@(p z8l5V%uG*v+5>p5)cZJCfzF1XP^|q#l(mhu(4pS}A6mc|5Q-l54?I1^zLJR@3^?e_r ze%$jHv$*Q!j&p64!)Khuj`?x=p33<<8v&Wd@4S|LW~dujauanL^5I>aj9mVd19RiJIPJCY^a-#m|g(X9vM&e57F_&T_ zu)nxN4-77BD9lurE0vp1Ecq;KTHEm-Fax%X+1t00KQhYh31{Bti$QammJ*+}>S61Y z`UD1$|6X`jz}P-!St`M=i>kmc&T|%GSHO%(l@33i1iqLA+nH@2GR;EDMnA7Sq++yp zJi583ZS!Z!hcmx2H=}SI>4B@ylIXEYJ5kAQLP^-Yn2QRwLD zym|tsBx+5(f=eat>Elh}9)anmq&QAm)kes~XVqn77ZOEBqb3yt{=Ep2oAxadR?76^(b1~K`wolHzNAtuSj&JwJ4pOajhu;M@_2D)J@ z4HpH4I7$SsxokSh&3Av)ugE=}H6BuBqPDdt`$%qBXDtepkMH4weTuj{+Vi&>^1Rto*@$i+D;L2#+D z{j0f>BB`xEe6ucfc;u?vfI;dMMVQobRQKv{V6~}DkNMB9bLJe*#fRf_y!iVdVL1jU zxvKk@@VCkz{BwP_5119(E6EV=sy?56;Z{!OGtco(X8W6SGM7iLDx;*WE2dmxB#y;R zsf!0w7{X?kaU`Jq-t9s3<$OFfcXQL+ai|)kh zt)Cu}c%^Re)5%P7jVuJ=y``y=UGaYrP9e7eARVM2KrVyAE2qPtv~SYKM)t@zC%qus(odYH^~UG6%?kNlfEzl9_t%rQLzGs#yW%4;Qg zMA^)u8=_>tyA_s8`F#c4hbBRh=!ij=ErGtQ*qBnKjZwl}2ViA=Eylxcxa$dtqXE>!w2zF9|IMFUq^1 zeI!(4x@6aaNT@@r*86tDsKT!(Ul<3~h>a?|U3`S#Af8bJw&r3RA{|viZ$eNSisv2IoLO?^`zzv#N(c$M)c{@(X^H`4fK)(<4{^inz!x#rB_p(Pq+t=ib9u z3bDQ8^Hqw32(bMFP3f!u6X7(C6wNtr zH}Sj9mM96)5w&5Z-3Oai;RdWPL8h?_JOj~B8(cC{N;l=T$;*onYlHaRKlA5}3MTS{ z(KyUpuFYv#H}f@I!8RV+m<_F=!}{dH%=I8J&6Z1U`d8JPNZQkW8t=Cz&&&qzP2)^ZN>E z=O?pMAQ3+r{x27y@=N3idU~h~A4b>%y8&!}YrU1GMz7qi>}pUQQ7EU{zO~XFf3odc z$7sKcCsrx@Q8J_MS53ADAt8rUsoWosWo$kQqnD6b_Mxcl>ariu17JAl~$SfWb$ z?eFe5OuS*O`#vF0f)FbkoW8X4y*us^JKVM>PmH{@EFRG*?zXw*Z5y{sFy48wn~2M- zVX5Ynvc0Qe)?;HF@jf{8zw*0mo8L+pRQNqw_}lMy*4wtrr)9-n3q+gt1EPfxj0#F- z7|>p-%)NEj=APN7^G?G2osAwX23Y(G_A5d?0OofUKyTY(;1faaZ4HK_L1zl5eK@vz0rJyBIs(i*)FKV=&NByKA7C6L@3tlJ%%8gty%9 z>4As+kh2+cR_pw#{XTXfzyG1%>&Ko@6HAYs^oYP6i`31fGXHYx$M-1TPyDLysj(wE zx=h|jjvG5--ptzM(#CY3f87l|qzCrY9bWXXHei`w00bK!dFJhyD#FcDIB(E*JYQEG$bLD_6ikkNVeLa zAsZ2ZLl)M~=o-)4+BvQ_D!q=K&6uy@=JRhQbwA&f`I_GFSto#`nx31sM`$w8<;PpW zBNvb0t>EKHa37^|pDp`*89@mxJxk)DhNgiJ)TRGfkb$ABS5fgJ=1gi=A1~Gv>0GV~ zsc})UAl41X1gl;eyh^J1w})K`+#AoR*?H}4S- z>s?ww-bR0B`!LRddHN6S3D8Ze-CsZpqo?Qd{TP3McHKNE7Qwc=dzH0aKl+5$#B+2X zm;`EovP_xJjKNa=X5o5QJ(pPwtEaPet)AT{0yC|Zu^TtYjCY5EP8c(KdalH-+-LpX z5>(zY8r_P&Zi59T$b<#%M<@8TR``YvCds^Ha?Y*%p*R+oy@vLsweIp+g1*nMX2M8Q z8*fvKbgpB3jp;ipZsD)iW~gn4Fh9BnJ~TDI^I-LXwXK(UqPtF`|i>MrDH1&2jR$@HLmjzlZ|Jq z%}V#3+hiv5!m$}Dz_$g34J&v%p0|=TMeYJ>+DMeE;`p>~3rXy)>n!~E+!bYtwum3G zHGY)?$Np}Ydb8BKHMa#~cgB3JP0lDE%8Sb;F>0&Pb%0l4vX2PE{pFm7br%l|vF;YW z3@-R`M()eiTjO82=%w!0&8Ajhy9A@CzI-xvw_AU!xwP!)y~jw@``B6w|8%)WA-+jo zgJ0N3WnF4E?$Vh4=I{0rcgY*ca*9t>aLWllo#-Sd-#3_dU|F-kFgFIgHtTs*)VGN1 z;>|D6TnHSG-*)OQJ^V0|DccspEx%V7hr1KLaZ=PszSiWAY%vehQIXqN8+b(jxW2x* zH2&Lw=H9pb16DVwda!E}1W1AV0#kIivUn=lGC>^9w6Rh#jK{c69=Kg91πeflsi z1l^_^WrAMqt^41_2ufKFz^%QNu`W+w#|lPjs#`eB;~6FvZY_&@n`{G_bqX)>JZGT4 zZ^%~vl3jz<&%8nb_g9vjWxRa0b?Np3z3__w;Z%T60juGhVk@h*% zaA(7w^?4AVQiUmU9D+* zqK5Z%a{TKkZq%Jloz%GIhGf@nuH+|bR4-~M{yzgg}eGYytY@LtosOe{t^DR ztP$!`aWIkkHLhGQ8KGyT;6;x&TCcG=B0_7jasjm^eHTI3E4TjcOr(zQOt z>HAfYdgpqF@6}UTL-l<1bXT?SKI+b{*+d-dA%HrTo_eBaY0jE~IO|>ZZCikVdrX}) zXU%SU{X+O!jF#TZ=B(LW?;qto`;#wtXG3{~7oRw~THVK*eFc5@%U6=g+Y$!L`R`Zp zGp0V{O}Qa3x%2->`}4e!=$-Mj>@-qv$}XIzulqiQK9VbX);lF z(zjV#MiHfzq71IJupDmey3))>UU+`%_SywiJlkj2 zDDW$=&x{U!l3SfixXz@BtV+BnsZYL}JwCvv*69O#4vD2N1cvGlBkj8UsFv8ty5hI?ql1yO8ILDlO)gXJ6sRUO;6^Tdwd5(a z$rlriIz0X?k*(Z%6(g{fBv_I59cV+l{p$tdIUdVJ`lh zCSkzIu2`}^L!d&4KkEp&^eq4mR?Xkb918`1E{?+lyXG-#wYLc4JIjr+<8&c~?I%ed z&eFER2|Y+wyi@Vlt&1|H&7 zwn*nNbwP!epp6MJg>2r;>T$B@8#_zwY_|@nX3tCXz`qy+>9W7w?tx{cX&|2aQ?MP2gEy5!1` z?VR|FqCDSuDbXap(=EP3nH=Ns=hMKiw{wgq>Q$;zy@5eM?w;|;Ps#Fn4pf(Xt3LU$ z@t*qAD+a(*2gr;!LMr6f$OfE;vT^tou~c)7d+{YxH`^~~D)p&Dz?T7a)h^P0hhQ#0 znmFHmwmRYq=rc=5M6rL-I*%t>-Xn`vO8=Y1zH`QL&AjN9iNG8J{w@B)@YlMLZ+ZTs zbkP~M)dAmuuk6W>nRKoJc2S?ZvxEZWk@oZXg5SC}o#=szZ0QdJhurFU1nsHXf&H<*%{gDB?h*Z@bj zr!fBUZ}=tFiH*!jTDyI8Y9xcsO*GLPevdXH(y<5y+wFCeP|~v&cjjB42KXQ(Xcas> zXPv-4#j~t<|066V)53qtw*r3UE}>D+ZY!~!{)c=jl&@dKuLfu||1G~dhzbAyo?rcF z<+l84yx#ne_|*kBeg(hU|GEE?UkxhYSHCr+4)|5?UhpdgCUbP<%lK95_5T%qb$y@z z+xXQ1u=f9V{7QCz(R&LZ%JHko{P<_hFj$lqFC^C&S}{B8d{f7{IO zLjG2UPUA+BdMU@>u6RAi--t#SUlfnkrXr;HttHXGjwWYy?sw!q@u7%@FU>NrLYsl) zGKwLC=enjPxLHT;lUO3CRJxt^6jws)Riez5K)^lvQ*n5&y}IKNvHD!&ZvFXY+_M)G z?K807lgjI`+MTeQY_BMX9lan4ONSdDPkdM~t_2*$J0xCj8E@B+@z%0WlKo)7jn8uk zp?BhS86}h;q$8^@Dn>feNMaTeAU*sdayL+#7~;-76-)Z4*X<+i zQvGGDiYaSWb9PUIi)7nIJ}A{;ta?r4>VdQ>28;%R&io(4@W{M|f4<7)a9C12qv^f^6SdNO6gXZ8w}G-+V0%z^R#a{s2q zO~z`S1L)`FAwW<3ndekCMn>>;U5QtxN`8noKF02{YpGIwr%mSKH#`7N8Ndl=DY}WW z>`{In=0O$UK`z5^KHG%H11D$*4}L+b0xik0t}J(lzoGz#E6d!${vqo2=Yj2|+nc{^ zZfDHb7HsQHV!LL|{n}51)F+c@gp<0aQ}{hs1~VR80KYfN0}1`CCUY|+=*G<~!1EiI zBXXBVl80@iv3qHTNd@g6SXl0YpxpaVVdf{4n+f=3ge=OO%@A@wwkHvZ`@?5jdfadM z-$M+g$IcnL_q1-)AY}KJo=)TmnZnOS&{?h*5 z+We*Sll=g{z$>rz%jX9cc)7NUUH-YfS8%)B5necG7|XqC~h&QU#B4q~?7?8n?Q zizF;?c90`Y-W!5r$(JKxQ1PmGdSXJY_o=1(T=o|RD=G7)*@uZQ2uO=wCk&3b;$5#+;RS!o4W^xfa_ik*C_j5mg5t7s>M3?t3Lq!s^;$i{1 zB`%37ek_>_!S)>eh<%r0KMIPU?~6x$QIcc=ias~RjmND`?`*OD54od7y;t6bRDF#vo2;)3vJAA+ z23X?D4|Pw#5`6h1t^Cli{IHD9j0fXzhi-z;ch?&(d4^L?@tJNf|30cl{re)`hs}?0 z+)x%Y|GErf^&^t?quQF9OPJ=N<{h^YI!ngx? z;NT2cE<;tCHq4L&^|(V)-cUuu!y=uLJ1iD*Vmn&_B*}~(X+Ii7jLhD_8)qsN zmU}eC;cnc`wXo1Wvn~k79kPyVr_;jJk zb;&h#Nf#Px2K=(nR&%UuHAEd^eW48D;8=;-QtwYSv61ti2XVKu5}&3w6wg_SIdASa z@#A=?Z6luulfua1^B;3alfsN&Ce`oFwY8L)_(Be$0)4&BAgT=Ptce+kfKX^aUTp^C z!=DWe$SsFsGfod!ApA&R!B8%V)Q`&=c))rzY>uEC^{U=WY&Il6?Ip1;%h&> zVpv|@Agv~aXNC&nb5USdg?0d(6f4}grCv$C0qU@90bZ}c&a;9yIefRtXG(H(T{rSP z(5WNAi;V0CjHg6{&wLD(`1#*~CpB|A1=L^YOXq;9iykA(Ea#fQ^I?kxq_}y&b&d+Y z8*_&cBm&Osc8opDz_`}^7R>@B41MuAE_mu#-g5AabDA&ix{_5~>(~9O@ah`tdOyG%N+kC9hFep>pdc+~|H>xl^t&kfi>OP!pz>9-w{6t-; zLLkD7ZvUMGC8lQr!Q9>h=$xjAlO=g=cWqDe1Tp%~4$YV?Ph}DH`Hp;RDRb97<3%99 z7$bvj;MALIxIvnvL5JVvZV%7^jj4(6?!69u3jox*%03JWffGN$&Xg#Bi1m@n9~OjX z7UHXQU_(BYRy1NT`>V>i!zd%9KA1QQ5GZ~Yz|U?H@K@*n?3YA52pmJ*=Y%~VkS8A? z5ETUatZ?nW5^Ifg-mDd3vP0d^mwl=n4o9h9Ql z1@xI*F$)3Ly@$J#oYI{zZpc<8~ zHOfGEDs?Bf`IE!P^4Ee}TMCpxgBv`?tsAX@ce~irh=gKf=n8l9N*i$UI7Vf$Ln_xf z%P7sse)@xTY$&mv7~lqIF@ z{o)p4mH>b2^s=6V6aBLT#J^fc4Lvx{?aJ>HrTlqM0_nVvTm>84$21QF6Tguvx53>H zLi$E$3A84nzR=$-d{W_uuJTcUMK)jZulV>jeYzRiRy!>hd!)blMIn8V881Ej=x_M$ z9&rA3r>$ddonWF-oBliQ1}_Ael_l`>5D%hlB6c3sF{e<~d&-CHT zOy>9sV5QZNz)oFj1lID9$f#f$eND~WGHV44Z~Ak>KtcNf1Qg&UIH|FsS%FE6w$hK5 z@Jq#%H$NVfO@51}GaZs>>EVyqs`_xq*Vzbrf_sRMS|9E2Hj~vuC$ed<)cpp51vjkl zS5fFfz>E()aK|tAfG94M}+P>f**XIpV(qKeoz9%A8xX{WrHKzmX! z6rroX(zS{LpKkD|J#X-+uX_B)P>QtV-`^8FDhjE+;=cTcuKeSo{Nq#k$MJ9xeyPg| z`Nya7kIRBb!V!}%{o_Cgl#pUpd;+(ZL^}S#*I4?|3N;f;-)9z_hj*tv3dvlDX)LBS z8t^cy>(eecZ85}<-liBgQ4MHC-)0CZDq&9+SG>Z~%m2K;_bNY1L2U>>Muh`8e)>z{ zrXn;kQVlhAoI4RHBW#R{4r@#t<^=GggS7pQbiP0@tml!l<;Xt;0UM-+03!+HeYB!d z>y5WK%3rJ_0xDn;u=J0WJEXT1 zjFifyuI>s6YRQsI`_L0lBV5hvo?i}iFI|ppPPN^ry*7F2J7d03uz=pYzGzg$9^C-t zj(x$9|JMvjA+#f08vCc_R%wxn(!7CXB}t?hI8j$|sk=7FaU?|m)b8|4Ozw7^s3l@z zjn;sQFtN2r76I>YKGqWStFzk~f=CPEe{8S2JFl=u3ip&Tsg$2K2n}|qYY4Qw4_JHk zj;40KmJBlGeo-!Au=U}i`hQC6yzK$D<$*t+xq_{uZWsW)PW%bFye%) z>-U(uJo`vc!sHGy2p9bV97+#=Y`-x2y(L%dYKrMLg&tSJ0&84iml|}ro6B+-o_ex2 zCg48X*F$Ka70Y2C6-r$##%G#Him#cvF8+m=_`tE8U<*{6LmDS+BY(6GegMxci`rq2TXM^7Psy;Ai_XLJ!S zzEjCvvlxiyT)Z1^6CXZ8V#*$J0_E&wvD5(h%;Rq~rhZf=0l$nSRkSkNMzI}q)YDAz zx6x6NfsYKV?K!Ciu*YYDQ*=W~AY!9soZM}!)z<*$o|arB~9cNL0LNbrO41EcL(zcnoM;|fVkHFMjY`=?{AC8E^#SHqX= zccU89=dht1_zxBK$8p9K2@6|xleY0GhEpF|HmTGn>r#sWu(4NN41CweXEmmdiyC9A z>e9HH$g){Gvbj7`x5&qttxLR1Ky3W_*jXPC!WFAtIJKlHb^<4c#KwRXyGkM!U9!qTW+7*i-&I7|TWB7se+6tb)Dt+Zp_YnXxa6Ur8t>JC( z^b47~tkMmc%h}D*Qvh(^So*S|?%}Xz86Rp-Y)nraN<8)_613V(p_QEi27^6SNx z0Q53moN87%6G$bXTi<@>RR+wtS#K%Ramf&?*=!dGRBOPZs)9L;6N~;2$=F&)ji28%9;+uBQ)B`Wvz28AXL?9PkTw*4v?dd9|$% z%UnjUHizsBdH!_bNy!%t707^PHwIgDPwHe~0;|7S14vyFQiANc!@5UakSBvBiT6YX zEwQr}lfRMMR4yi;kJ#ycpfck_1?QJZE1x#z7~A5s9BMn(Sh6>YV_Pl-Rt=l!if75# zm*Xeu9G+QOwK)5GYYJ)G-|YqspnLYu%CXk>dP#)j8ez^2i``N$}I|;LN!>Y$?{qods+8I9i#G9fs%db+)ealMw{TaIB3!aY?V!J-RLuxlu zlqBrxbOYgvo^fT&Irex|E3{N}r?p%V{~=h(WZcl-_T0Ze}%WP;O>XJW39 zj5&q;M)Vz=R}I1!lOJ(cDH`)bLIuJ$qd67X9rCznwq>-fxK8fubda(-Mmn!hS)@ER zLuQ5{fPA5VQ_`;GNW5`sD<|NLj@?_2t?FqT(JTH>hC1L7+o9Nk!ulV2b4$-7tXfZY zKKO?vQV<~hU(X2>gako*r=3A=f+b;IC|~}DnYN$sOJ5nLBr^PL^LTiiAyw7lN6^|J zwfCKz+Kh5{>nN6#EGD4^NYYLL%?fn36~LoxIG8KYs_&k@p2*WzLB2v*t`f$FnaK&~ zb)VT_vXRpq)ReSIb7uCpu36P4MsSkGGWhZrOYL!|36H`#b~%elI!I97c|JKLinOsfOnV7w+c4aci24|r~*<8j-i_UgAJaY_bvQXNPk~|clI_v$$LG0 zdELg`NV8j*h7sAVUn^THkX+elhjpV^#HwjilI6(c-~C+ zx0NCOzH9i4?s8c^$&qyfyZXesBKe&g>3b5#JgqT3#h(tfbWR)GArJ|ieHT9ScFm28V+YtlA=M4;YhWg1?;dz0 z?`eJ-*Zk`|LEZkBsa^UVi6_dlY z^Kn&|-7;y+0l3@>E&ONEG5nX@I_?rh*}V&w4JSHbZ`d86w?h?2iTcfh(@!4_B6E zwzmSUfJ^=Y5`cns9~mH0SD;;A$c*1h3~Weom@75XCMFaA3^*U~oL1J*dsv10=SA8$ z#v|e9Q2wO2dJG;+Gb5$i{gz4wu;2{ho$QRoX#nJc?9I~OzGOYGAxAKKI9t!PJLcJ`~G0=`=wv{{g=7#r`Y#vwyA${?)wq;{lTrjhbf0)#M(zce6;q_ zEkE`=hAAT3TFQ#z6Tq*?1KV*0#~Dl^i?>eliW|2h5A@>Yz)?peK8RJnG_`;0r9G#| z-|=vY4Pi}IxN{f*ZSGCdUqsJ6KMC^H=~KTenYAkiNSO!NIkn9n>Nh*J7}Ev&F&IielAM>hAkR0pDkm$Mdz0`XTEy5oo;Df$ z?Y3PFHabNfRvw?D*@S6qG3RbE$JvoW!Ts|vS| zrH*Dq+j#}Y@}&&_Cdr{g?)R^k3%MV9MhGA7Q6VSQGXPQ(6bkAb%A4-d9|)>K>;Vcg7wkwyu9-?mdt-o5B$b= zNgi^#p@X;g2ez@m;Qy&%Z_C&GXwF)qBYit>-Mjbz;%+=#k9&F3!&i3%rXr-@^K2Nd zc?n+0V6Ah_Hm_gg{drFVYIzxyOYe7rbH{V&lacnH^Gw1q(6s73-Fx3Z`wiCRqGP!- zNx=$JiC`=rpPuT?t;&fP&5E|c?aK_2g8%Xm&xJ|_^kRj2 z+>snlq|ih7Q2JNzkhq8J6tzjEgblcV;KBtj)5A+yPtp;DsPo4cx0+-1sZ3m zdlp)xH$;dLmEpU$0LgyJmt9gjut!@Q`Ndq@_=xi8_@Q+YK3qi{RVk&O7Q$P8d{q$aQBZg8StE6bnK0&7Bf^k zJ+)YDZ2uqWxzEJq@M9(5yMdk3{PM^HT^p8J(+ z_4un>RSGr}%AL!$@MSm7Fp`#Ax^#t2dFCA2oH!G9gKl|6A6m$AbMWvuI&TOPC_nui zn$H~t^p2I$j8B=5Xb(DW-Bet^2PV$iwys`2GG}Xgv3wQDr%{`$7E2dmzb1G|(|aAL zm6613YlXo5m2tt55%X|9f$6;Z_V?nafFtpv*_GH2Hlp!>F#(xSwWJpV*9UkoZ@xDI8oOKMh*mrrE1~ zv-^b2nuT|;w&0p84GzyYD0gk1KEJ%Z!@jJ&IR)*#oyiUGKWXnBZ~WPMd`k-^{EPpt zy&J!*Jz_I*^R54?_KYIMJR31`l7u2Yl&h+u@;S7_j^vT*uXL|*Bu@j|w#D)7Qw=5j zIYn0G#%kgR4IM)?cl{Yjavn=9K*OANm*92_9YcX(N~Hu%BtKIm`ArWTI7c$HD@HP{ z?29H3(!*=7%6HQemjC9KzEG(gY!&% z3VrtZ1G!1iZs>EJYa;JQNCAWWAUOu&_qsMt!DpjXpBHN%l3FQH`F)r5=?2k@A`l?6 z#mXyviP75-cjBD^W1ok9Y~Pd5y2n?0FkqJt;lPzdP_5ILOll^rrqa z0!@)%pORo4w)b;BjGiyrH)1oqme;zAG`=0UJMG;T=n}fWXmD|v`Bi^;4PBV*|+1K3a zzvZRk-vspZ6bxr8+~YPYvf4}$ciShHJ|kyt)90?gnz?OMcl{LY7;M=alINqr)<;?Q zB4;JQ&t%+YT7CC1&Ri>`AV&Kr2?}p7(0!R1iXe3fVnD0q7*yzn9O_ zjBFF1I9r3!4llI15&I_tl)aQhtZnP@8~M6O-Nw4Un~69}?1ijabeRZ?!#iGpzwsm^ zHA!hE=9~g&{nDnHpGFB19bLLBx_|rtGto6!S0=S>RNgFSC91k=@zEwy**iniz^LhF z8aTDTE{ww*%j`{9;IDa5gC#QUR;NuLOT`~6~0kSEq z--@N$7i*u(F1Q@X*uFR#K8y$-YV1LfGT;zM<9RQZ@lGL zPUyw=)3NZOfrhujy{XDRtnQj!q_ct74f$=aqCT6M`z*-AZAX4K#Od}EXWA$<@NuX6 zps!>23o1_WTq~E~ktyDMsZDKw#_Sf{~8tHeJ#IDhD95 zZb;T(Y6E&aAOnCl516enKJXCL0|x9G+^hhXhoO2H!2=df!j*Wa(L;=fm>$T4RMV^n z?jo%juZIadOfW)hVSfr?q<8$`C5AMY^$H^>4rA!>Kco5lasl*#Z3y9i6iF#_R~`hpmtM(?7JAp&b>?Faq&0o z#}j|zNY^}bVM3qChxCpQG2XC$=+}>6q(+cBr3Dy&9CcarF2D1&fImw%4k`_rJr zS~rK^Vw;z!FLNKdqs|~nY1CRE|J7-FZw~se^B#GQ zztfkWP)%Hm$F;)Erb1(z7Fx0zQ*YW;|_$`k%!=9iqlP;QV&^Fd*vQ=q9OQ zml@Uy;Q_EfmBu2GaLW*vCBQ^JrIW2u=Fa!lSY=73o)_5X)5BY*i4}uyRx)uk$q;u5 zM!MEL`Ue}S+-v7k_FT#`P)&0e$zU1y)&c{+hF(GA7F$6?XAfD(ctvKUZN0pFj-|)5 zOMESI^=N%=Dc&#AF^DJYPlIUm{Uu(ev)k$H@e*2xd)_x6Ihezp!)&z;lUzSQ;#a=w zWH6lb8pf##7T@-<>1n+*>hoT*AiqDbzy~mnX}jfme(n~VPyA{P(ZD1sO1BJflgOJF z!mT*7Bg18I=OsjoYuyeKBLYKj;OW7@f^vStCT;dSg_(>X^-J5v;`q10AMv>r?gts7 z1KWbj4Vi(mK@Wd+OJB`)yLS~iy}}(;Sf-U`SyRf9DNt<2-OW{?RI0vT3y2O&XsUaX z8&R^q&*3}q%|keWG$eB zY;Y%HS`ty64sb0DltiLl-stwh)oxhuUDqypUV+j-!Ae>&Emc`i#?mo~;YV(_BM2ky z%z^y5SDYx`NxZ!MUF$C3uf)Mb{@O8OL8Sn*pdSlKP476daIm*c^n<;d($Xku9(h2+ zqJuLA8Z~xy@P)|uV}B3wsDR0zCD(^>oH~p2^V>}54HRyNm$teyhMKaDp2Ex7J+$hc zIM`ktrgoxwU*oQ^h9b!!M)R%o1>Ovw!4TP)g%^DPV9plk-&E{Ok$8d0bE6&4Q|vd} zFKNpGsD;U8ZqYd=G>QB^R7jdBw*l-3GUFi){Q>Cl(lieu?=CDSaG&~o=%|v~)^SGl zBYzR66ozZNzg%G`sc@6n=wo3yDwYZ|z7?$e+wKTI8m7*Q{{1fknjv+ZT=lvQYOTBd zgg_!x`lXYci=}3H8TG!~)LpC$D`3|z=4PKXb5Ne2GEO|kCeNHKNz{|XbMt@A$|-Ph z77yFlFNoJ0;ik&Gl_nhTRn9x&A)Vl6sJg0jQYGZ?KD1$@>`h(c9^Rj(b;M-GyV^ma zeNI~_CFV?AuD1*IgxN-0rTi!ok(GrHm3m;dF($1;DN%yP3=ZBFtFlI_Zq0mw$fuVg zv8a(-6mpw7MM~7NfLb=V=M1iq&V4l!p_^;I)z^GTeGA*Fo_p9MHu;%XDYx$il8hg5 zJlOG`KdRSYN1z&#?~o^nO2if}=STKidH9Nc%H$K(LS6W_2!PWP-{RWv2F@t5>zo&9 zYo)4u&QUs`D4Cg#t;Ae16ka&MU1mGsOCD7H@4aS&a1S;^wln4nhPs!{@2mp5M|$|L zm?$0+f6V;!*$PJ3;M%ETxF6IjsHN@&S$EG{uqwRT&{Erl1#OhmhSkl^ojJ~k5~Ok8 zBK;3oi#gY*e|9ach+MvNol*HtrzN{H$Nnaa1GM_!<+k~AO}|}sL0-Rw0!1!o%>OEK z*+#kE0SgPmfQ>*NXF}&l4-9ZO;H$Ps4rrp#o+rYzIJsEcrDflUrS_b*4+!LjKWk!h z*T@6MR91DZpR*#qUt6Yc>!y-v+SpzUG*AYyOiNn3(#HaLz!6HV`TTl&eYwZ)$K`@a ze$s@VIOAPWW7`#_y_nmKc}O6;z@iYr%PF8!6jA-np|c)F=na2s^jG4iIda21eHd>q zc$g4=nWEP%{&jmrs~-55Kx3LViu`bWKJQ!fa39`$^cOC6;jaZj-VPpFpbn=b6u2^e z>F0LVroCGw(rhXNef!&d5Q#PihgDu>E31U7>9Z@Q2!Wo(-fR2J<2j?yg71hvcieoQ z7S{!Ix7wZh11%VvQS4UJE2bDexwk8|0iEOa5#>Haw{4rZMA{`^a{eUz!%com`VfCj zTHVC=5Rpy2uhE3!eeIyo0pJ2jRF`?a-@Y6<7q7M1xKrYyBV1q{FIeGz$kk=2p~<=N zzPiSV2=&CD+CKd(KG%JZh0g3C*^!Hv@(nDUYWfR10C(V$&;5NGz8{;Ddw`3n+0cE{ zegzkjyBUZpoA_j3=x0_aaXz|1$KFC*Sk4q!J1@7vN7|2}3<36Q_91a+$4Y)=s`=kc)2|=rDSL~_JFs~v3lidTRo5&mw>@t7 zBh2(Bih0B}`SrYsuxE4!vC-tf#a&-clLIP@5xXgm+pMP}H|@G8X%^SAu#ji10u>51 znz!8#&NRZkK+Mt4T1;PadWdr+Z5uPF- z=V^ZC{Xdo-)&m!#k2{0>9~7@;Ar|Ce|m&K+_oQWZhBYBGaL55M5A-bA+6^|mu1R^;zi#2?y` zPnIk>wz13}A^l6n*YvmnUL(Hw2`CVKgIC84p}h@UTwx|R^?J`r{du>(rm~MVJo2Mkvl0-aX?gwV%Hl*iXnK^z(_-LJ({_#b|sl0;>&!W)#ta=P27mxMl19>WINM9qJNN-`J=oxyd%=&Wy@(Kp}(=Aw+ zW7P=s6_gHMO1Rvl_dZa139#=Ke?pm%@Uw4l=@(!m>G~l#FcFO^Er2`l=p*XR$K3&r zq-#ppTuu8qKE_Drod%Bk401w`GB50FvWk~P1>fOHne$KD3eW6pAV041-U<$ci;7Sj)eAf!qUhPWn|1{7NE*MLx<;i6& zW|>=uujLU+%b0Te@*S#4$Q&^E|{9y|P0Mpd=k9d)z~=sTj)59`gE z(Y%#mxhS_@`x!p6UMt-Ae|~D{-7$=J?gCtFBI@||L12RPrYM&s+wfPrACo|hQ7vex zQKzDlinAf%eq4siB90MN-6b0*dyb)fY=1KC`zIsL4_V~(dy;wIi^j?+v%Dwb|8 zCfb3rvE(>jkBdz!A=ZCx72@SX`TBo_*Z=?vnv#i}d||T_&QyFUqk9XpG!4;*#tbpgg(Ltid_E(g<6+965Kdt=gEW`fjhZWKr#qT z3LvzoDSfK|bkXkFW58#Z1-OOqIZW`;eL{i`BL!p})*67C@s9MX>2OYfv&e5n0`&-f zWs@gUNBecO-IzLSitEMpoNEoHUi<~vY<$RIqckd~=E2h#fM;)=mV4iQguff`L<~H4 z<>YMxCuRm1@u8n{|FOxrFo3BP>-%XNmKpHodC;9`p!4?Wts(c^{RX+;XR0WYYv0=s zJ~OfK3BHgA1S{CB)A<$!0)V^QbNh92S-gLa#R-mo`Uh|XKs(@dM}i_bTULbBehq1m z;lgJGzZt%JfsMZK17_7M-9jX^?i`zsl113|6?f;lunA>SM(xR_Ak*XoZ+I$UXtl_D zrMbwyWK}YgG?@bXi8M{{L0<8W#lcA#*o5)Y#4c4`gh*KYTIe(u=7??KY{9kbP<~hi z_}j!F{)SI&SC$sX_vx;ek*mjz)FQO`PzXZ@FF)i%8BG}>Y4+9pen#&(P2rpAMKm8d z7sW|ls0O_Cp8aM2nlB$q>pSwD^PEzx(~~daqDpg4OsjGyC*zo%g{PnN5i} zV>u%+Wh|-(UI=`qWR*FL*fz~b=X~Cw@9MUZj$8EID*=*IjN^@*?Q;M&FbSP4Rz^zE zRh{zIC+F2hZs^t*^S?5)Pw~wg2nopc7WPSh@#3K6d)o?%qreK44g5br`4-CS!u83* zuUYJQao1IZcER-UAA$}6znle2?{UlS#0KLByw+_#N}JdX?)oP%wk%_%Mucdq-2OA& ztZVF?SmJqIbE>@ke*Nm(d*X+Zl99?dx@=fSV!Dujfu3v5$fG9) z^zSg5%taJ6{_g4PbC44I9PAs?BH+IveWU2i>&r9Vt&xh8dO&)DmaoiQ<5HKCBm-IN z7Mb8`+0Xn#8{A@Yu0UP;H*qg?@(so6YU{DVy&+w2#(XsvPFd$oyuQ=EI5>u~O#$=Q zaXt~UX-rQX6|&NXRJ;zW@N$M4RVpk2=06ZOoO3S zV>=%}7-)z5Trlsp%Vd{1hMSlc@WK=sM%?3$qd0nX{D5F%9Uly7;0JIoEn>9z1KPGp zF;oM#BuY`S2VjPHUJ-$Z$5N(WDeiCRBXU%-t8S2n&%ug?Zf~yDVnDZp;zP~zR>3BU zHrN1~ukB_cU$*JR;{)qje5Uq(-XxXyE83xuEl^xw`J>CK7H2T0`*k)Jy}|t*`2{hw zpTr`7{#wySMGsXiZe%_Zgs;15?oSiJlu_3p1Neqg(1_L4Kwi{@FSaJ*oXQhvKZ5Ge zlXW4bqsJAU4{P#oghmM9f$?l#?xUJ4AVfNU57nFM;|}|Q_JjBzZ&0`SDr~<7)~d>a zpvq2~2U{}sHAG_q(JZ}qh;(D9_5P*IKxSq%l{>|q;R(dP;x!PAYHmFAt9CkhiFgrnce4X%^Vg|5GQ6zA@OqbqQlTmGMgMwv| z|4osjKXYqmsJ7X6A{}DUqgzL9e~7;)ARL72$3Q`+%TD!{pTH&^|4ZH`jmg`)1du2q zv_XD<R!bl{mJtYd{vx* zRCw>xH9&zY+;Qe8i*#;KapAcX(_fzs8U?WipV)_B-yOsH95~eQ-+;gB>Ccq#;826l zzz)UWYgx-9;ln@F&9q3guk$|O`H6%Qg-vNn9YOX7oWC3pTN-+y+fKP#@Lj6Mpo@Ir3EbYBHvOna8qrP zBkk@EFEmF7HmZj7FQprpXkX!;!h8(izTR_RMJsL9p6uge8FD$~+a!aFiPB*kdwNd& zF3?kt1<*73?sZ~Bdd^9I=3nKc|BGoH*yhS+OYV4+3&JPH50ggC_5dJjWO|q&=`$(( zHboC^3nXQG5_GsF$X3C++`o&oKWi^WV@&;jNP8FXD64D#e*%dF1>dNk(W1sVkZISjDuM1scmg->uGCiFaBzem#P>p5-+ty zsP`&pRrU}Syg@`D|Ic^rcXCnB@A*B?KaVo+yWf3Xd+oK>UTf{OVU`;e8;&1Qe{^uflAT*8Z;P1Gb2Z>H#Gy#(mHIOhXup$QsqW{p&>5N^UB zr5@Yv-apNoGT!8u0CU%_(?|z^rB8n2PUN6{7cf(3;W<*_%}k_wX9Y_qktWVpryiI0 z!^iDk7%|aLKTo&J-^xJewi96yU3Jp#4zlljY_>e#h_MGOGKOg8WHmVdF8?$;rm1 zVAT)`7B#f>3{M?Iz}VCX9`|o~uHjyZM$Nga+3G5$3Wp?EIx_R31aMm)Fh;jrL5!0! zls2@TIXra<;e1Ul;cfrs%+slZx<{`}5bw^n@VWh4_EYQg-_V+23BKh5=$eMuPCW+2 zWr|!Z*OxMdODWHPnb(NVP;y=}nIYm7Lq6N;9KV0iel;V}NWWnt;^tjEY~Nu$Yjk9^ z(J7zYI+ZW&n<|nYdu=b+V`d4&@U=g;{po`&RQxZce)<=@bEUl-CRv#BmFj!FTWTUT zQRy=8lPUja{)yxOcQN(&HLrkmE8SGp+cmM2cB6R4KO;SfWv_ZCM8#n0{%es~ZclIO z^Ed#ZAVGj~Lp*YDlcfB~F+c<7)L3?@EsYK9i%UV1rkcFYd^&gQ9v^oxUrp8SIbN9x zp;D}St9#79+RSu6+Ze3s%vTD^na2nqYWl?KvU@88Y42ji3)L$vR?u?y4^S`QPySuH z$7(r?-~7=42pDt3cLGlZdVyQu8Zsv!FvstJTy4< zV!mZ=`(ht%Q#S!paM4r4RZuF{a<^$LluCX~W;gDmPpX2AIDQM03Riy(r}QcrnMG?C zPLPGbxPjsz)w^-0D&Z2-Z%#Q^J=^TIo}`IO-IV~@E2NS;(C|ru_On2!zWuZS z@W=1UGO*oUcnS@_(0YRGZ|p5I6{f3i9YCN9^i8>|$Ss}7mVXuY-x~+ONA+G9)w}Ox zg7yC1^q{xh60O_rUk#L(z5E)PVL|a#cLGSy_`D9K@wRxsvIKlFL=Xm5kdcvtIBwVi z!+1HDv@ZZd6WNy5WX3#fZ0l}kZ~ti7x4Yjlu>fzSUZpUU|EYWbnrO}7z&S!VPQB)# zUaH%<8cE32-qEbt!-T#aw7UFErWLnLEHeVdam*-CSEzi&QpnYQ-!gA^-yK-* zk^54LYB$3gGB+q<_HKFxcK{-Pc{^&$_odhgme-PzY6X>IH}f+>O_Ls@pi1EH54AUK zIh0`(v!_2Woz>DRN@s7^Pa(Ib9Nd>)$ZZ;{Lhdr3Tdp53J_n)59F0m^gy3jxs(iqf zO7=NCYBeVietE3m@lxmtk0>QeZbV(rV-=5F7NEyE9=~M=O(wST_L0xwH0p5iPRVG zZrQHgAbY{c&i@v3ouAI!MDKg_-dK32ygQ7J*a|Jxao#tC8%myoO;ggnod+(QOUnL4 z<|DOW^-HmwtNkNI*t_hZSOr7ha;xa+|HZBTP->Q5FjXNv;F&_qW7YZex(aX38epHm zT`f2A%ngynQj23YG%>T5k}aIItev3lQo)+fMs<$Tm*2Zrek?;&_ibJtLFKP{Mw7YE zlcvJz>E1AqepukQ+>ytvGtidnwjW^x0NGnS|6qgk!$rO4mkZ!fMTb++*Wu1A?-6dx ztNRMRjHsU(0_!}z4`uBz)i8eyka=S5=`prQt6wh(i`Husen!Ebn5(@n>EVt}%3LpA z{$Vup5wP1-i{F@Y@wTjGnfDdQ7*#mjr_|j5HD*nAEF+s(24~JXbq-LmGNy50S^JzqVf7BERLkelbhBM-Srx$( zwljxFWK2Lc{nk*3qw1YU-SO%%Xrp)v1_>RPiEJKpwck_Dvm+JEY&o zWwW~$QpLCXWr^)r=v@ovN0kj+GF?<+3;k zgz;~b&7FimOAl<~=GXQ)p|bZctefhorXRGqxPTL!45rFfB3b(RQ?54Q^Faw??la`O zcQ>8vzRSZ&^L4@bbjZ8qt-mFX>f1UinrEA^GJD7rR|d3+(Ol$Qvu9DT|?`lE&XzE{Pw6W!|m z_G@$5Kaw_C3wZ4_13J00UQ)69`;9gYb$w`vd`0}X_!r7CLB?VWOM_db%-r?tyC88J zDOUg9hlFD2l|(DtMRN_2Qh0o_+}KG>gMke7D^>Oc2#1@bc0@wDUzIj;pnfol7nMCq z{U*}PA>9?8uY42R?8VTW7i8lc$0WI#%nWDoUj_frVQhsC@pfWtx9nhW%{)1o(LxSt={)rrdk=&{#R;A|3*3#OLn*?Dft|z`rF`K&LOBJ#cgn+@Y7cYhZ z&G&tE+3wD=H|9G(M<78zAZ?0&}%&iQo5t6&y>Tet30;iyTu85;@Y5(ny=v41^ zw-$0Bb?cT8xiW;l-r(*-b7$`wUp#MK+wO|gcf$Dlb59QLUXym1jfT%VB7X}o5+1`I zGf`@=%s8p80*JrW@;XJhO`B}uEj79q0G~xWITwD)7_UX()2gXyn_9t|npln>%m=VR zTOYofpkpp8fc4OQr|;LHUCsIR899nep+o@M(SB z$F(bK$|A)0`H>W=owP|d?z7-;x@V8s1&&V-9b%+{10)>GGAqS)_jC1ENWpo7b?`kS zk^{q=00-@L@8z2b5!x%e@AB6DbYK5-wKtqykejgwJ+vRtcfY=Fk0kLjF^9qNKA7^w zAJ0GUf6d?TKjXusz^fl`0@=(_jjgxFYXY2m=UFpUH5)3c0Xwwq=dRsCi6 zx7_hegAze1g5AnuXCdMI$(bJE_2|c`YeO>0R0IAmO<+8O_@i`SfOJdoE(3u z5rZI8UD2;J0R~loJ?1_KCNbwh`>%Lo>ln1J$?z3>iyri5^z9AqW_pfZOw&n>LPfndRkqRdh8YcC?EaId z-`Z!(6f@0d_qoZpoP3vF)~yg`;H$@%rxE%SxZ&!ombw2|D0Is#6u9n%uNfCh%}ZqV zGwsh?68ny8mYM{=q$)e8DRIe-H9pyTsN!&9^SGaOu*V!}w*GVE`4a7wqnHBi`VQTI z5I*Bt*n?Pog#10U`^Wth+I^Gj&yDjYy0lbc-FFYd2S5K74@&Y6n~68j4-3&V|Imcn zJnNyxTH~Qk4{jZSJ`pDD#BvS7vLZoO$!Vj`*rl!e58O+(7sIAgXOrZ9HcKYnUGBg5 zRZ5L};Fo^N>fCueeeCWa_kX!0)FvVTnCJHi4>1y_L#}f7wG$g=kYPV z_UcEVD{oKe69FI8=GRp$$B(Vl;|112#uvJO{lbs0-hH3(<=+P&hBrcaFmSuOSk3vc z6JGh^74e}yl$qsbr0lMqegeals7 z)n`_B-{tNu6w2SNS_aTB;cGJ&tFg^y!Ce4{qV)U3B>{0~hnW$TAE#1%*z1BH113qp z=y_)$FUm>@(qgzVq-_@IhFQJtK5cYOam-Sa3cgGe1mFty!c28?v)iO!QmWjK@Watl zjoZ$X&UU2N%`T8`J7xu)FgY>IK2Z5{%^IMvWh7*TYommAm2KVLFP&}^pF@dt%2N6lf?*$ zjG?;WMk}ZU>N`#Tj3W)*g#jx7P{VYo`xp*}?jGvm<|eBkS2Atf{xQgTXqCayFlKrP z%nvZiL!YQq33cxEpMmQfHtAjI=XslE(bG%j4|gs!MBB+-Ou?#5tu8W$v?=`H4C~zoeAA9a>*JRk%s?k0?C!dGH>s z-sZ`eyeE8sw2INgFAc6nJb>)4cl8oeJy-HaAPh9%ZtgA~3DU!De={y>#ghU6a!!gn z)oG6z8aeUI{Q)QlRsblFtTX)-t0nJFJFo!4E_JcW-9~46^-3aHteLX100DeFX(L)Z<9qFbVQ(cTXBXz$e72&F&C1=%&|2VK+#=m|QXN{3mh2 z2vOC~Pk65y^q%RFz}43u?cq)CMrpGLAh)34^{4#FWIbIoWGF=Rw zuj7FHg)QZHqpnRlzAXt^=mWmHK0IQq*12%5Dm_x8#%_nE__BQ*l> zXRQX<8luLlLAws8$~0VN{v@ERj$1)@l9|;_!QGAfgBPFgMc;c$3fIpgPp>1KQ*ieV z0#KeBYdtX;e=Ie8^77*Stp*>w_HW5tL(%-sMEZlOiR+7{lf>jqNd3(Arp$ZptA~8Z z4NN-;LziAx)0o*(Aa?{WYy#Qd8q2yMr0?KwlB=Tf$5H;HpKX4Gn$Lb8Duip|jRH*B zdOw>L3^3N+CV49)ewXAe!TTL^3>EcYJr3HBY=kF+|IMNp2oLx_caI`olg{TMV{UKg zeM%U>eUm_qIZ>KB89Jp@ZbbqcO7B&hMBxq^pLMgS4jM4arxz8)ipF+obq!cw z(k`PLBRt@&(uVW{l}U2#OI3$)Oca@?t_JV8Z|0dxh0a*SimJk*Zz`%<^*34O+}X48 zVmq5L0H4wOo?&~`5scM+i5@m^5t^!n)D@x!REwG_%B0fS;vU@@&Wd zY6rquw$oj8B(sim8;+}e^@P)7sf!fIZ?h(#toMAco7&pi>`D(J8xiS`<&cQ`;4l+Z%|4=MdaR#bc0Y}Ocp3WXw_!eBUiR|3zrRKJW3yM&_tNiBIe+Ao0it>DM#9tn2fi4RtSZ19UIQbZ{kvCGU$Ddn+W?$sAb!mM)5>#0 z7Lg=-XqZ8FP=$!RZOC9y#B0PGW(k?2FVGR)@m)k?qC)^;j88th)M`5tjF~#2{nbPs;F24#ujnRobL6 zm%NHu9Q#sf!_MN9HU~GYzBu!UR#v1>2BpOM>V*R(?vEF0Aua&5_4aeUDd5KsdFa>I z%b;hgenx5f{*bX1v7U2x2!x_Ze+7Y={m*r!^-b%ck8MleRmcbegc+6=CF%~;GE)L; zt^0mk4_)cOOZvf2Y(Hyl$esHO=`Hy2Q~Q>v8>jkiT;;pLJP+(fz53yE4(P|7BM0^) zIv=O4PL#)8=1KIYe6vOw43X3Q>*1sQzRt*D|91!x0M9L%X-0)YFJ#UB{;6P-9b3Dx zjP8cHyF||K(-oL*zm_4fw%bHu32Lz24~dU4-~xL=4)K>C%}@8Jl&mt;zv>{`0I zXMNKQD2SpfE4(EVHo-D^MR~w$J!X&!^)JkJ%uri=Imo`CiL;dG7uiw!2~cr)_+h|6)XJi0)bCj+9-Hb#Vaz40DSRaSNVo z{7$pB(_4GO>JM{MYgXrn>dXs69%Qc}6bhS5t-Y5o^q+}*hEz5}E&K1Bm@E$3bwZhQl@;X4jkVI0yi2mRPy9KF zzTnSDv@#w4V(jF{ zD1AhfoT+EHWl?4_Ja*f1GIzj~JN4&fqJS6r{2~a?QM) zw~xp}$b%*m*%qi`=j0@px0jr|i1B1kkw86oI}m1yD_a)G!CnUqcDe^q5_unbY2}s} zJxXL=Yi-rCL$;vrWk#2@_#~mUep?3#;oka8Npl7+e8a(ayPHx<(EF)LL^q&V(I*)9 z!|?{-g_YOjtv6c=-ac}HgD)Bj?|!(Cf2+oxVNooi?mw*Tx0fJ;**LWItJAoX*)xLn z2bkZ)wR>XdsOL@PY%p*qF4x@p1o!5-v!Y`Hgg1?KO$^D(8d_Xo!+6Ub!`Ib4N7L)N zLa$AG(WZQj*#+T)suj7izOi~QvF{VXq&I*_&@RV)Op)omr9t}l1k zP`^S-c4AoMCa5@mRrqI(os(6Re7HgD{vF3`Y-EXP_klJv~BhTxv$=zUjE&%XSJG-de; zbMaRJ!~N0r=)v-90Z5|yjc87S_RZ>9dJhbIVtpc)`b=!@RSi4W0o2>cCBEx*rs|L7_Y|Iz!>+?wLSTnq`DuJL@1Wu z%Nmeek%c4?tlq!AzhVvPRVIOHuy_t@5siHT6MiDSs!qIBI9uLwM)yLsXL<#R zeH<440$vihLV{wwy6`Y=-wwE}7&CrR^EfL!m-|td)`$`3Mqk54IsS~nIoXqXq#T;e znOSx=cQkY@9VEpu+;GrRRlAV9;GX(XS4_Bpg9Nhs=T<6~^%c6Ba_NJNUtTfc5iHGLB{!on=_P2tf&l`I7pvj4co`sx2soFZtHcDDodyVI+Nf(ck^>eF z<604jNv6m$u6D?gr^kZ!1e2V|T9vNzTyM8rr((Ebap>;Ip?G3Z?MDY9I9zTGqht&^ z{-!S4`r%k@xxl2`aC91#b=O##>~urZTZWAv7PQ~0A&9{za*M0nOLP4FlN`RL7pUaC zAb!|XInypxMREzR@s%XHEQLyA4eKY(h~XEorK@w>(A=n}#6;4s)D7Rzu$zN(=kH+jv;yZpi|!W&^?^I&nahEO4XlAgxT+K zEauuaUK6=h`a+D&`pk0;y&Ka#ucW>Sf?g9<)KMOE$VNyPM$+3tSL1Xw{~g9ALGY3y z2~__jlp))z$M>_ggFk6RQ&bGGihSLF;^9lw+x=@EiuLf*hRo7w)D!`Nyxy%ae+Z9$ z{`+}-ecO^5;OyfJ#B?2yxnl|`$Xo66=aI7pEx7dwqP2$(IVuCXOW#-)w0Ar zpRi!x4|9cPbPM(Y*)qGw^$$QTJFS$pi_|%_JbS}+)WX{l`r5vmmoWE#mg`5rraqe0 zlQe$8P3zJ<+fy@|+FxxsUxL^9R7MYq@Pov%>!Xb5{QA_3hQ$1(G@d`Om2u1VGjHp5 z30Y&`+?h62P|!}S(BAIV5ueP;C-tw7(0VL&s|3^R6x{=HlY~O3;nTh6p)(*j$_?&O zCW5||lc@?!f6o-1Vb&sT^{!M6${1uWrF!=-Wv0ItADDR=1=4y^z5Nr2^$((b^QB3w+fcbC)P8h_3<5(-X+6})NUN|}QAYJZt?N`$K@2RC+ zZ8_LiI97Be>0A)gr;-zY=(A5)Shpu+74--0l8BTA&nO5?hc=YP`jk4&x=m_Zlv?4* zO2KjMc5r4X1HXMp%YnDU$`wbmp)FaN9FoX2%~avC{Ld*`m|q5(=<2WuCe^+BRZq%1 zz5}2{Hm8p$G!sLAU_CLyD=l_1b7kd>WHoy7CeATjE<@u&j@o4|shlm>t2yq9Vriy+ zAZC*2YHFpLSbF!qpk3zx2;~>FxA4%hvGvOw(y>OW-wESuf{t&KoXoZ$g6s@BWL0d~ z+2N71<2K$B*^W+r!uYen(s4lDl&E3#vx$t2BY|$`BtMKy+z=^}>;Et3`4Au~#XS$U z4MifmsKQ-iM^jrlW-J-J0jvpWH0E#Y&DFLaD{2X{NL&vxiiXquBY^7le?&OE!T58o z}i2osKl1!Ei!^{Pp8QR9BO-4CEj@m$cC5iLOLSSA?XvNi|x;&wHC&1t|@t#jR^ zJ-d;0#F^5M6dBLRm(UORKttQ*l}REIZjbEKLFQ>_Tb{#@eqC`ENfa=jw}g7}w?*^Q zTbHBHT<`9JbBcz*=L;|epOTI9%?c~=e!3%F}9 z^K^7JKfRy^PQ6AWPcNwB@g4)hW_P{W)LO4d?T+)6QPy+r`pu0#kjJ(#SsZ5ORD_wZ3gNBJbJ4Zw zy+th;bC9I5 zuYr4_tGJS$#V)oDmK1h=okdNx_@-WtdOqJb^))q>8~H+ont{L%Zp!FjRKC`i|3y^( z7+-$0{fs=?y7{s4))TMZ@25XDUy|r06H7U5;_yQ&#a|^8Uoy$d#Pb1T1+z`}?j!yL zV18w*ekRRb&bMKw@V-qsZ4%RGRsg&Hv zXW5m6nUy!&_vJt5r%$q8=|1(ff?WN^0J*x4entk1zW4kc4TIt#O8^^(dKE9-54rNZ zg34jYlYuQO77=qW=SFqvzCi_G!^Qb8^RV)x_CV3=`zBC{H%y>U^JknS+;b7`w{$G} zsv52FDr<@d<3#+H&Aw`GitSk?@r&SC^a4vPsuDPnd+KZhGaBEZ{RIl*rb}@8#pbq7 zCfSrA?>DVa6s>o^RbCc8Qhq0{1!$vQOjdWhuaK-AEK1`qC`azf60ZH)8Wz2Xea!v$ zE>6xdp-kMVpa%v!@sM&X#KAq>7`Szs8SD`Z#}y+|n|}nU?hm_nqkPoUT^~?^5ub6j zKRoF4*o=!(&AOb;D=i|DBn5wKNkiMYb>^M;Cu@{*1g0{VACW~osJ#sYw;>hC%7tHz zbm>Hj986D4-Ad5!os;W|6qur*%1wcb3}40_$YN$UpygB`$*vEHwOAky-#Iu zS1B-RR9{HoZT?z@yH8tft<}=s7TmO6chfFI>B!LCrCQvr93)^8W zb)BQ)OA1j2I*zcq?3m!HdOjvC=0&;bQ*gC#JN@*-u>AdxN&Mz>B@%v6BQ$5O;EI(= zOkK%a^pi(uTFJ4HaURRvHsLGMCl|n_VBtCGS9bHI#?3j)`W=^!LOF(+oY}&u=~Hb4 zk;*N)5;N%z&c#X@@*v$DQNY?ExJ0uA1zwim-*(8 z%%@*A@A(}#izfX6r2cE#`DHc*OHXD((jN>>Ri{6I+MA!3?>ipZmM4OJvhx>Wad{;04*ohF#)qxjg~Ws-qM<;JIYb)a{pw)V+wBH4+G! z5NvVNB%*XCcW=U(c93Q8HCirz*;f6&| zRc`NipH}1Ejh^aUo+sT$@C$$uX1N=FfSey>bb2@c0eIl~N&17LpktVF=4xX!{r?9L z^*bU!9DU^fDT4n zcN`mLMkt>D5g$E#$&wh5a|J$DeEg=15_oimQMqeouP$m8F$ zL%Yykxr5yBvvBAcVKq*_-*?`6#3x+Cqovk$Fh6tqeL&QxA=kfQIe$_Qrf-R+879*Qh76b$AD? z+*=Eye$(JGH9Kbes*zUJX7`&jJ)(S;*}eD(Zybv56Bu!6ga!;V@>v)}-~Cw@gxy)b zj+O_aqj8(v=c8JG#}0~PRktN`wJ+_djfJzE0Pv|v77L)JQ3AQ>j^gV;JAsG7HJEA9|3-o zB~s-momiH#hMHUs`CQe>-ZK9W#*g^qPNz0V%qU3XRAojmnOo}a1hC9@#&oQM`C~*Q z>Wyy>QZQRv?zL__5dTM2f?NY_0E5I_%;fKTJ9K^JITSQWIlt6a7U zx3i$VmFM)L*f6i}qFGy7JKZ!)O2UU{Kl^HLTUIR%kv4ZwO{t;OV(y)U&L9Uc*zR_r zIu(c(sm0t~J(djd-tJzUX?lv~rcCxVp(gyHWspxBf%b@03H?Q{6iaDgKqvXNnx+9>aKMk)ro}8ZU zxJ?%V%&v)Zs3S7&U&cq{_lV2`+ki7?)Ni&h!4dn z-)YWeqW9mzMwRM{&=SVo!xzryKGWg5Ps+uL4fG3#YMD zh3b2~G+q>a^hS3;4oC-{h4qLzjUgD#9tiWiPIdOvd-2PI`)n}}@~zk1egQgcg|J0l z6SXy;Mi^=|@Rp0y_ut82i(0N8Fy8x$HGb(kjOVnTf=h#tbMQ*ri(acRs=`XU=G-9? zB)zEH-~ZH)KGyf{rJBzo`dgUKz0(U)@k749T+>Mv5=rr!&O8=ouiwBkM*@1cc>bjC z^RQTjt;uX#8{ZmwUmn2!5GsTAFR;-3#G6yZo>iTw%e)*+-@e$;KRHg z%QKV5`%OtPv4+Q=qw6LwxKi>I`bZwxw3ci$i}l0`9+#M+ZDKu-?fx<3vD!B{Ex5a> z6goD11KW?|NLy~i%l!_OFBo_sbV+=ckEMLHUb_|k8>ewDpuhKfV*XO^1yYwBm&lC4 z3D?hC6wskQ=BA!sn32~^enu4S`Ak98u+g927_g-%2wkNJ*=6qU>@3sUr3 zrx=`5Cx%7O+Wf5_%0iGc+1eHiPn>!FiHd+bpdK!8IlW~zcO%kzemuDTZ~OY$Ax8C& z^z}#arHh_j`H}i7+&EtZO8!FXcy;OdlYN)ILYJ=iX#Og9fX{D3u>8M^^5Z)F@%-iP zg_8#M{|UXR|N1AbfByIh`Z9s)HlOq2{EvC)U(bWbyI7e9!t=aOFJSX^8 z`r(;BQO)(Ym;cn@cY-;eRXV``JbM_iRZ^qp9i83{hE6U^{YQFteX1nAyR79gjQ%@`)F?&VQXDJ=$cz8~^ z2H*}RgEH>lm+=?y7s*e3_CL;-t*RlfkrD>tk163R^sxJNTXIYaBfELHkFS zJ-0Ca7ybBoXN)3Z1!popexF{^pN@E{_3zUSCSG6h14}>Er&smm&wm$Qvl4p#=!m}k zn#IbgCa0AY8h+HCF;L&TN4&`^T~#dy%AKu$j};TT6A>WHS-4fEjEWS-SGnOEagR=~|e zqh5?vFQ~PGQlMj@7X$F$eb`*+htX5l&HLbfJTYkhX85*K+{SsEg;Wj9FqH56*nbhuBu69 z7MWa90A0U-pH@Omgmn{5b8ViZY}_W7yJfW7{Xa&}-KYA-cela$0NxW_lLz42&n*4j zq@@qQtEEam-xw7dB^#s5MIA1Ojd4$8Z&$1o$cD0Au^aEac&)pGdJMaCl_>L9pf45{ z{yiftJync4-Gj|=?fl7jtsU;J@PGK3+H){Z-sc9rVeW{+#WurY1&F+5BzjpUPov`_tG{?Id}&y*MHqv!eUsD@;!Zv#@8 zA@Y+CIGLS-V&*(LRQt{Qq^y^sO~mgt*R+l8XRc(aYKW8H2X@cZJ}_Lmna%FFmwn{P zMXDKtOPP04-R#EOht}EDxtLR1%KO2V-SX?iGKESUEzP5N8xw*lEP4`pw_bwk8u;^L z@MkE`buY>;wa%Y<^YZpFv>CZe+%I`k{i~gd$jL$Zn5A&0sldPK^mFq$M3Wh28pMMB zTWU!!&k+DT)01KgGpSx@V3e-oV45aTPm?=1KaGdBYe z6-CDO&dd(}eN^}IZhbclPUy^Ruv&^r_mAoQ5gX&X!KJI;4Zc`1U#Y=Go$i&byL%hs zuj!n@R?}p*DAPt$`td8ZD% za|}0Feut?RXk!%*G4~!{!fX`j+|Jjo&y^p=Q49RTz*C;X+UK86~)8`Zx!g_x~ z)ccvPjEX_OmbBUdwr{yr??muuX-A<}E`ej}rGAgTNqYzD&u`=0YmlN5^;@LB!uMM< z;;zgVz|`@@s6>_fA;SSyO(jCpD4^+$uN5*bud$34VN}eB6UYVZpQf7YdpAT~H#?b3 z#+dTz+{;V)CePm+zS>^3n`jAZZgciSoA=zToI2dnvwqqQ$Xi3!~rppZ=-B{f!xo z+@(0c{t0}Xo>su!+@>8p3g)TWJK90&d>|dqN?T{$H}uo%^h2FM0XlU9|4LfZsdWz5 zat1E5R|i+#;9w-igzhS%pH$iMB{y#}%#oH#-IZs2(Cc-^ss;``mpBRLjz%ZsDZ$NT zIGEPBiKF)d(w2vOu?r}MX`ErMcZXj@fFCXpYoh`$47?5J;u_4_J5JkoSP5PcnMJs0dSZ5ZB$W(>!l*QMdxYj44BiL`@MyfaFu*QyDL@V z@Qb|m@;PP7)ec##Q(4>HFS*=U{w1mDK->r9ALLh3fIGFaFh;nIyBSJu!k^otE0v*7 ztb`Ho{<>wjMGlhvn2VwQ;>(#G&>Cb>MkMeZcMhZqRmQV|LyfDbwOdeIhBr`AE0pFd zKKS|tTuN}MFA{S4Ls`d1k^CP$F|LSc?(NL-69~Gl$9%8w$bi4 zJR-_B0Pauv%8131`m+4uS?n+}Q3+JLo86yZ*OCvGuhuAdzxoxeVR;LR+9hbM#;sZy z!SD*-^P}jwp6c8vje)>WbgqpGxSy>da>>bG@0GP)esS4CIzqTH$^2D(cc}r%#xm{n zhp+qDQ+&<`JzoZ}UwfmqvAt}gLT90kN z*+38Xh1rLe^D7Ct%w0YQhWFPyHI6rX^aViMCB8O|_h7aA*P6!Olr2i)LY@kEbU*O{~z zQIQJwX1hnMwQkct$bfTBHWCLbb}s9rbWuwaAU$eNpF8~hJ%AHith<`nw0{2Yz0xXi zv2xHQy{>f-885&cG@YhmpIRw0KJtnWHA!ot*xI|?I@@>RZTNe9w2_x|CwFe-ft-XH zyOG=M-SlgA3rE=WoM0VoMIc>N!$F&-uVe5!Rh`BROspMrV{lbm;^%}J?%?_{HY>ajkNHHnVJ`E$FyjCf|GRk>H+Wg7GZL|b{*xI0Q!BsXCW2<&G0 z#-uny@?n4-C+aKVTbRVtr@&o$VRguZ6K?;2?5FwcTy6{a%U$g_AqP+0ot_`VqG1dj z1SRUV_+171ul2||t_z-EITq_2S8IW=nr=yol~2Sc+Wj2u=3#)wf8E+M_XsWXU#C~l z0e2Vg_)(M!98s^^67)LZzcZqi<8}P*)%+Qx&`Hk^efQ_7u)3c=f%^3XO193)&R*!I z3d!wulT@SsASrwX09yW*Sz2+-;@X1?tT@QlU=~u-7m=^Lqw`+%=psVGd@=tZ1>F9$ zmA^|x5i#?Gt`Upsqc{Ds^r~kmXGkKM+TG~;fy5lN3$gli;wR|bLGFHWBY($|S)oRm zpPAX665dpV98t1jho;mlOmmG{nT2UKOPo|0rvBg`5lu>l_zV?1Zk0PY9tu3Z;U8sp zdfPuvb0G>{q%5wfoi#fwD4)HL)=CI72r|O`^N{Gi?N>d1xS{ca-g9IB=yl#Q%r*25 z;L>%9Y#J=BWQFPetz&-gS2#YN%#Ytj)7m*(P$6*q-zpA1qr=>zn}{#@l|uvLkqF zF2Y`dm5wmCrjxAu2q~_o;l+q;I{-?lU{c>Qbbah(14+E6B`+OWuJ-1gQ2Py2E+ubj$f}rCAjhW0bx7`nz(1eTy2z12&X;hq{X;Ar3Qw!@`&%V%K3xz(U zkY5FAFuzwTY32P00lj%Vf+KwswI*`&OPX_w8By=9VCez?>z1Bg@K?V%;#V3jOKa&p zl#GP@Hu|Do4J>_yut>4d6#@%4>ELKm-T}_xi6XQ;=&jlCU1=>4k#VlCDQLf3Sr~y_)akXh zJzb-8o#JVgXRj}=69kw{JT;8&egq!DvODGd)l)G>Hp7`4 zsre%~1D()pd75&_sj$7{eM%y|@55l(JYFGanLY-GBPp?QDkjsm#yiWbBH`8&?E* zxMf%0{Z+3GnMuVS>04=r>`yVBMj!o1KF~;X)Xl;VkkcJs7=SDYX*VCG+=3$agM$i)BhebK5v&A3;GmU&$kN%X& z=1#cv#rQ&I*27%W>x*+Md-v_zw`;>OYp#8zjlY!3Y*_8ecCBe^L#}Sz5auQgp}8Hg zjbZwwp~>p?Vf@{Bhf*m4j}B6s^w+pcW^$&q^7 z?)d}s^d?W_DFaX=&r)ZhDt;&^MTLjhO4(rrrzJm_~<+1a#P__>h;i@*>b3kfZx@QFTJgEc zHy7Ug_H~4{w7-7&(Coj@c(bPY$|3>$4GD2}aQA2HcdkeNNNB3%m-uV&jU&hn9BI(@ zMXy|MG1~gooIUBKhHNuF^+CJrJ>Kc2yJagU5(yD30XSDuce-|^SE5i8U)F9zM9dy4 z^uX#-R)j8EE(Oik55r0GS*qim13=C{RRkS63qu<2^KbE#e!V{E&~B<>=j5UxL5KNc z?HtC_86?v1s#?@Cx~U>)cWN*zC&passflY@z#!tX*U4w1jhWqSJg|=)$-YApV42%QF^hz0O8s2PRGLg+I!%37py(bR%@4ZD z_=^UE`6Ii(%Y2)2(u?!15}dMS1m1g-xSa5+?QSgX(&Pe~{HypFExOOF-Q8=Kd`9Pq zj^y2_u0B?*QD;h?Jk7VpHc$eL6xiNcHi9#&Q zNDlR|;D)t@l}mIRZdn3SMWa3R4`s#5MD~#8EGWgzy+qwj2F-s@W}Zk^KLu3^a(|)i z=6F8H-JwooPs=lrkDzqnEukw)a*J@(09dSty^D@W#6NAR!B4yNP*ETJY<+$EuGC>o?Y*gk1sKiD zl=!HpgB2I5#q>6A=j|?2=JFsnQDa2*Kv~5=1+mfyx<{$AK(`c#J>aMJuYweROH5k9 z%D<~ePZePt>uRv#Wo=Q?@Bo9cA;f?ZHrLblvE-r>rNQ-wh(F{;y>E~ndXu$cQ7#nJ z0`K5Uh=-ARTlb`L5%2E}+R^?5|C;73S4m#on}}}!-s|z+OIAOTjPDIroI^jF<2!;C zP3ll~VP31CvnS}NO;i)s)UO@x&PY^0n~eXvIcQ!B zxxteP70%nq>aESyZ$rJ4)w`2Lk0qk{h%GG7ZT|=fc4rT$@t}<{E7pBHG)?^xPy)htaLwKe#W2(khRulU_GKSQ37n{ zV;-ahn(~wk04Fm064f|C`-O&5oZH@;t9K;g9Q1e|SgvEm^SCPk6sxyG1w9lK@l8SQ zR;o(IHwG*0L>sGUMv%*@dcehsyeJA zB>TE%b`MGw$?hZ0*Uz$4tWibz6pzjEw}Os2+91Gbr@@rMY*;Q%y@*S9+Xa5uVexLo zS>xmS;-aD!qy&uBxASFy)TQDfmGu>WzHhx#{vF+s&R1W)dzJCkXl?JvAFVBL<}vR2 zyN(`lBN6b+@2_1iB(b6>f4a7h45YLuPsD}+Bou$*2D^sPkhW0{p1mG6iA;W4^w^x~ ziJs)VH%Fl=0mp3F12*dTL3$mQkVcER@VO{s!+A`5^c?+wYgRleOT6sY-Hm<4gN#G? zGGQdYg(o`JkMaY$n4iIvO5xsX5HBn;rdF(ZrijMuL}p|DT@wJWtemOn^s{{hz~l(6 zCKjHSW`6-Rzx5ICBds&E{5kmy=R1pxT=vk7|$<4f8AqpoHZ?bb!@0Y3AiDY=VSM+ZLz3067ls9mFbjHE{V<*bebABLne<%!_C%9WAJ%M(Vzv*(| zHltrdpDaQdy?4+2e@5`d-aAwzY)iNc;k&0Obw7K9&(LJ=-uZW;>lhM!+{MRX^L`et z-a6Fv#3JPcN=!xAoRTZvTWYgRpp;72oEyKNd-X72TJ+vuW9t6|`!`798Po!WJij%} zpwi5y+f)cAiuzWy?+q{4}F z^s$CIOVuFHAA_9@jq{71PZHYf0j<1$QTxtlnZL6o758;+FtnYIfn)o`5E*}j#{?i}{A=#VAJfrb)VI~p-aX1N>$I&2yX)<;0@8t+5ov909tn4bb7foE> zcw9{XPVl|zjinCt@KFx+vzKmJee6S`KGB=Sqo!mRzSc7(+qjob%%KzW%Tw1SGd&4u zEFNY&NA=PLK#<^eu%PLQFz$jC&sgWjO9eu(-|qh2ud=CqtU2>Cw9dExiTzI^T;eo| zSC2!f#z^drbdxqyDP5BxU^1GKy)phhG8O?g^_l+lH4xl=a84c8H@}GtF;@!UC&(H+ zWAWirv*Z8K*J(If{M_=O{UW1&TbeU}V~l>DM9->%j>#h0@q8lJ_!($Va%61L*W{L2 zy$v1ffAkiuukY-;WxytJef6zL?O613dri8+9Ul>1(P04>gIx2JJc0EYK4^ zYTWVXR=~++F;#%LMD7;bb8~i(B3l(&VhOT~K7UhHSu(QzW;Z)Zp04B^J9sI-PGua* zdzR&8-RJ-w1Q{Qf|N|@_8$*TMZ(qro-WBCZ%Zv1EjQQ z{uWfk77rQQsl$}nPti!w{s+xa7Be~0MVp>iZ{dF91?4dm9lQeXWbU*fx)7&c)aZe! z*<#LcZj)FDF@a>Ymb!I^0GV+M$``&w$qK4tkB+2n+#@&Y395-LzK+66nN8&AL%R?3 z^UILi6?2F>3H3#t>-+1RV|C80SonN@XFJX(v-Vx(`8PH5oCmF?$IMQC7Vqu>6DPO2 zQ4ns=4&F5cu|9G3sJ~CP4Khh7xc+NYn%5;;KE840NskK(>%@{u@1{?a>VkID#%9|j z-y~=CCT1loi^py}CwpZN4|6BA zg{xm1%B{gC8>z=*d7;JO$L$9~1#?QwWQL#YX(2wNobSyM=fN;USj3iP4e#Y{m%c{Dp`#RB&?Bto@tc~HUN0V4!veE}+e<*+hl*f8F#%$;& zs0bn)WXb>TAi`06j2_|>f%0#b!xa(b-y>AeL`0fdw^T~{X-PD)mjfzM{^S6B}T{VXmn+S;W~jzkdRz zv->M?E!(^A^ZOsxJrMm6Rjt>J??OR4F;_fXJTnyKMzF#G-gF8;r!u^mWz&{GUX=5} z!#jZI=q|Ync|#dN|BY>kWs} zHu}0|#(xk%)FG)g+}AUU+fW<$id67PaDIgQgSBIIf8O!$-h4)jcb0@#3CjO?-*XTd z?jO~*mlaaegr;0nWC;n}PsQ%FG4ouat5b-W$ejl=?%q59oTgk@)cqebH(AdgsaA;jDMi8SF}qyRa-kEsFp2lMV4l7rrodV-u?B;wjltz!b!vg;!VcGo;3! z3vOD|P_&5~rdS)DEjKiYewNU3^Q;%pglq;wzgrP@osG0ZT1Rio!THV9+YdjS4isfD zk@*5kZMW)p(>=0X(^Y(uARf&@(X+gakxQQm;<^;mamYx2y@S`yYy0z3l|z^XnIdWrVB^)h{+wztxaoalH-JHb5mIL$k%0=7=== zb{t`SsGXp49Zz{+1ns}$A(6exoc6jwNa%+2@wp4YjSVeh64@`H*`3PEV=X~Q*x<~= z&Dka8g5xttiqKNK6;tK>>!419bG^Ovm-`wDeaJkQ+2($0?6&2Je4V}%?%+H8=H<-? z{v~Iv$;*yZfNvxF=rN5{P}coR5X&&J>aBk(99l2+xJwR+c7*vIyxvbGz1`0t!{<*2 zQ{BEdK~Ru#W`Vwly#o`#-jI2=G4pa}n}WZmx7@1bHOK86Z9e-qYk9gNst&UpA3JV9 ze+JlF*eY>-#_ZHOyTN3eSK*nv-S%nUC~`8BU-U%?cBv;? z7)shG5FKsax>CMSROkt6J=+e#OP$B-yfQhyoP&9pwe^EeRlvx&gWjWx44=a6D$&)s~yYfbtZ2WPR~r=%KnFlG`lSIU9U!%skU*s|z9vrTvSs1gY#q$KA!Slgw(AdRyqGi3gjugt;*$ zEs**usgmIu-;N0Iml-O`l86BN?zsN~V;Y(D>5ZJ=%boNhg<_e4>1MkdRw&#+;po6a zSGfA$D304rzvC{T0yXm@M9`?);Uzxj^G4^}E1#uCcZ!9A zbH%Y^deCpIPGrXrqWXoFvH9DIMRnTv3TeNX`}rO&G66M9dZAUd1z|p2HDWr9c()i< z_O$iM_@wfdb?$f;5VGd|n7L29$;P450$KKe%!rkZnQ@IL`td3KX42CWi;JdY#`Guv zPy;ueEIo{c%{M^`qyuhan3^8d&{#PebzNyu50JT%b`3<8!LsRel8=Drrh(wWPbkcO z-%*lMHJL8;G(x8^TfD|JnBk^ZWJRbC)7!`lYXNsRbrU}$JZ3{d*RIT9f^Zs1^eeFa zOb;qKUQg=2rk}si=RLFqUul-CYq}nKUms@wOMPHr&tz%{aDuTe8-&@5%KJc=7YP3z z#xG^F{AJbetMYQXFbm7TQezVUj{1nZ7< z;ItiumbvQ_(U+O~vHOeLMywar(%O+1$dyU!3|7^_8 zDFz4kHG-n20hLigNPa80P`Eh*w|cnybI^OoonzW(*`0cfsiLuZO9PgWc}Je;n^Mcd z2*EpBU)&IXxG|XQv@d}(Abx+y^_`8??>1Jy53Y=v+Z4ZqvmIv@MhfFNsef2D>c;Aw zz)etphp(gTRb%&K4%)u~rZsUA24(MQ;y$H~7*fmUEpFu0Nafu5S}z)Pqjb=bpqjnG zgHv0DQEPM&FGlM^jV+Dtc!)muKdu4!PK&4^y{~BA?SofCG{y}!#`TPGhqXI@xu0(s zdX3K3Qm7G&>g3hc&jZXF(5oHb0IN2B;v25szcKEW?(;qkfm34U_eMt=p&-iI$oqBn z>+_k7O>s+_;(Ikkm?e832c2$@hvf3^dp-=*&I*CC|j(6HSXq8DXzQ|v`H*>qQ#y9C77D$akMtv!pR zlF6uI%fAtDb8D_(UiMd3_Zy zYf7egcm77u&~ae5H_wf5k@0{d)_tR}o?Fnaz7?IifX5yxjC;B?mk7!25F+8~1Ae7T z+R&D8b|W1g!^3oBvZ_HMM;5(m0aW>y5n8CDjY=i4Eaw->@g*_e8PrfkX`*=HC;`RwQyPj#xO@jK-sm9z0Bp^EF4yGgdc`VL*8z__i0DORcc1~*HDTq zJ_?t}-u+Qiqtnv$e{8d>j-*R}CL##bF3h~1$ksLZ%Z2NRYVpzYSl&N|o%gWF&j$IN zJbnA?FoT}DYjP=7O34)b>76JDFNsx3u8d9EVx#4s%n=h{G}Te8!E&yyy{yH)#~;mz3K=zHO^X zPATpuKA!_*_15FCOI-rU8;LWR84{+)#Zsd=$$^ezVuhC!H+KKd_B)xO-LH#Zd~=w> zeya916^%|}V2;KE>Ro1o4GXFthiAGeH?=kWIr(s}B_2U?DBs4u*p_+deM)~22AM(rshbiDAfFb-8yG*e04_(%S}@!X^SqZ?g|mGDtxF$m7Tq_@xr2tWM)Iq{#{z06x@Bu zgcymJ7FGCr2dz+;Yb-13K3I4k+-*u9E0!u{$DNFKwrrb{Yn)IdPuW4=gZ6V6YlBp_ z9G-d2!k&0ID`r1R8@JeaE2c)KCBGc(1zsM1Y%*|>+b9C=`EiXVMd;M)TOZ@sA)7qS z&A%2Ks`+m%j#G^Be|cmZ2xRju!iSJei+lTJw(V;KkaC+3dHMV|%;2N*lHS5zNxPhO z?Rds^G9TTi7v@8T9VVg7P#}p$6ehvOgdt}h(Lw{DCB1cH4h%YmD2se_MQF>HtOpYL zLxGPUFL*P3f@y;(TgP-9qP6@{BheM?O`h+54js{~r!>J;a>c7~XNW#{PF^F=xC&|0 zx{oyY$VbR9m! z(9vq%H3({NjqRXZ)h^5V0%J*s{{cTOZ+@UVHDJGy+P^{V#_Cb3@{*dPL%9k}+LINe zXpW*j$<8jIuh|yl`zPleD z2sVv6QFqjGu_@jTvF4qF;_w&tz5`2MYoeFlTSyI$_O}|VBo&5c!H?RO#5OwVB9#Yw8_l&I032b2{ zg|}57sM8+|v!zun+15t6pJF?E5Z;Z4q1x6+qe0+DO5!_l@9f)}ax!Ai+^%$bm6hFt z8{^^T1!I*^D;0uwlrU0bey9(9c7kwGO{VS1(N62n=-B z`uHDX^$^Tq?Btm7In`(Q?NPBxSa3jw1!Ho$Wpfx0zg+z}%YHAQY*5Gge#FLeXUIo; z&lu5?7*A}qym70oz#%KZg7~m%=Rx+_f&7{X=@3t9G2&*~az7v{-T;&6I@EC}%|#tk zQd00)qwXqM8eTQB^CiLL5+=?o4@z5{p*NUkXN>mB2U!(ISUb7#z=@+vpd_vv^GgvTG4oy2LqsAl@0RAmc;iKgi3uCO!+u)4{Y~D<| z&rdN9!n)Ag|70r(AQ*tVQMYs|&&);~@9{5X?`}&*)LwHm0Q`*F*BD#sY5tsm4>CVx z6+JRP5n+kq6)2XI(Lj3)D_LI&?M|6(26kExl~pw9Xcy9BI5g9F5uHPd(?1ehhXa8d zZ$_{X!QeiUZG}2yBg(ei`lO83d7HdFe%@)Y9&Ws;FEe)pkw5M*%j{jrHLu7SY$3dN zl(QWdN+=Nj6>g=dH@WWbLMHW{0DMzBV?`I=ihGkknpz~r+vQ81{BsGdh#^aw_mZ8GC6EWlnwu;Zh}1Q)TX1U=iE1NNjF{NF z6dAQoP}-Tx9C4=}xn@eP^7L7RyVr0(g9WkZ4E90lk~D}w6k4QhNZ{Es{&f#lzw$48 zkQn>FX}#N~z2y8O=^KsT60A+*zsA?5zHK}o{||i&i?VA^-zOSCgmAq#y2)74&e$b( zzA*S@&N~uv;1CL(#Mv0=;G#NyBm!NKv^+2Ql^t*3#fF@OJ@oJvWM+9Ng{p5=%vPW^ zW^-DAe9b^YzU4VD!zXSJTchGgkiB9PJ|~K zfuzTibU);NFh2W-@IH3k-`DjxT8x#&vY(w)O`}?S4~fOgP^0cn@^rhh!u#mGroV^# z;I*(1TE8!p!;QdYrl3->9Oo5!l?bAh<8&{64^5J%qPDPuU!%4fF+6)DS_4S*3bn3{ z>#>;qr|&HUBaiOMVJptXfBAhA8OkcjE2~;yQDhBLg?Jw$dFRNNyp-6S_~QkVL!yq@ z8T34guYNvXVqWkTG{TxdHR;cjOQgXpOkh>_-EMncRilSGTG+>XsEy@n(BxW|VjkH#k@m4KI(s*+xO9ukLBv)BLCymzK?N#Ok$pO;)FDhJv4Ai3S>%RN)H>kd6v;I zU-ovYX5Q5r3wIdxH%VHcRV==0zpcI_gJxk~_}qBvmtb6h?&J%!E@sk&Q8`7`3oyKI z23Tzu;(i;vtZ(XQUZ(9EtUMnp3X&U@#66;>?SNFNJFrI>>;my?Xlu$o=f2{pR~NmF%V z)=dlNi={N<-;R;56@H=mRxT7&jmaTFoI+&mmp%7IX^fTvuO>Hcd83zf*=_3nB$;Sk zHJTDvy*~b5tcKHpBo`}&ROWfiar3-O8N+?~R-++T)jtr-M!hn_3cQ-Sgx(0>tE{Xwyy~~f zTG56|M{&$;m)8m)F2BzH5-VxbjyA$7j$V-0Z0fG>{AZ>nB3D({whzp3xN zP`!Uvzw0RoBr)%1B+A{Bk;JtjO^ZVLF5GqL5NnRf`HgC-1jmuLom9kmr_5d1M1B4e zUnf;t9^&XI7Udj^u#lL|8jFNB`h++6%^smQa&_MWQYjcPJH5Cew@Xx7oGk`rq9cY| z3y(8~Yy=*0fk*jC@Yn(_`0)5ZYVnrK)(%-@5*(CBU5b=Elfy@HLWd%p4ewwNWs$83{8RA`#AedZm6sgh z=NdJLub?WDB}5xB?~w+9nv3hboH~<(w&==&WK*ed(r_5La>GHpDU(R>;9?} zcSs^NvcH{U>H4Im^?sSbY`Own3~ZIK{dLQQXFHbsiU0jAwq~hwq10LF*V!qFfSA~Q z*a>y>CO#e9I**^(6{}u-xt;Zfq@$Rv3tv$_fkS}S#M zvWkszxB+q_@F0MHxH&S*sMDK;*rm?rwr=4cWe|Z4X5i)UvBec-ZeihFvqT&+8}KG> zMoi8U@!_D%S^Z*`H+&2#1H(J42+L*;n2Lnm5D^(H%zs7CjCjT50@{yPaMQp;+`C-Y zbn9(Z2`a}(w(959U*^1N)QbOB+7=`(SK=+|?)u^=iY1Lxn%aNNBe?V3ACl*$3au>nhH1dGD{{+nhI~OKj@t+Ek zW6nn~A=8okG*1xJWzWl!8+dGOG&vf@DzJRq7IQYLP|lG+4+D*anqn0!JHTEp4|(Ou zU(lYm*AhNfpqqLGfU$L$2;oBqBBA}M35s0t9`z6;r_SyBF788VbisVfsB8BrPky}O zW_rM}h)}kL;vV#nfXdB@HNTN%HSf*>-4Jhyn)^|pVyqZJo#^c2-sm%?c;oWXJj&(1 z&S;_>2Vckro5cvFTjTeVq0JX4k>tR{`H4rC4$z6s(foa-A}YQG}$&}&)3LZ1830r5F- z>0=6i#h3cPv-8I zUfvd&nfP^THz19>U&HG4?d0=+Q71m+$UY$~;$|s8gCR*97rHq^l4p{Gn+vj2e^N6c za^&7~(?-#qk|w;X1jfN`GdF;@x*#Qlw}W4yCrYjDJzV&6x@CFVYDdls<&sIrt>uj1 zuqK-esk0GV#2i}QAPb`(4(EW85x0u9y9CNQi}PaD8*=|U%q@QK?(`y2#zB6bQg{&$ z^jLvcWHwkyoQ$q>bBT)@%eEZ9eK)b8M}>LJn#eScLyO#QIogIt1UrI4mYcghT}JiY zohDYq6A+6`0Cu~j2!sR_B0s}Owr>;|8x40ex1z$AmdnLO@Xs&m51WJs*R&rrk<~1; z|E=UB{`cRh?-(7*%zR_BE_6SMarajWQVLsElYsuisvtU9PYlw7SUCzz*aCPcfD@F& zyqG<{5b;A4lE?bwp{VLVQ@a?KmWN}WBCyA~VQc^yd>;t65rm3$%j?M(`+2x^wt1KTQaNNzei6TEsm`JXQ# z!MY7LT9W4`r}8RK1lq1MZqj`7R6-dI9Z_R z08{5|gp+r^gQ7Hb2IUkwTCQFucjXA0)_qm*6|@uF)Ho<$6Ty)?GkYq}GdcE5=QmL< zGMCvReVHq>Tq3fTIf}y(vw#|z?>YOZ%zl21%sDGU&5}ZTM)@uJqRw5ilSu{e(nzNq z1c+auAxOp4^8aZ&83WpRLaGB6xqG=<_k~m;7COrJ3XgFuS9dR0>+zp-Fyc;u{!D^k z-jOHQs3Ipp3C`W1e1n9@3G8Vevw|3#>T*@L(Lg%W`(joMbHv==YT!kR@ThC?hF0%in@idjR`|M4j=7i9150aSH)uCSF8RR zv!BNY{Qas{ac`ZCaInbA;;iMo7aKJxKc00*L44F`#14}nMNv@ZC^x2nzeAGAmN)wN zbq1ZvV|$TP*i2-f4YRM&aWdH?Dy%INwfLHXov zW)1p0Tb!SrW=t+|ot_6V`5vp`m1N>o#t%O9iOKyq#d03N_GA#C(<9!dbPm`{ltGQ; z{!#>nhM64ucZs<2vsV9};3AQEadf@qKj?6~QTwLgvE8I1|K^v=3pkM{(v}9XA=lUQ z){0ku8D?_DhIgOj@q(}NlX1N_Zm;}GnF5fiOm5LaDf}khX5D@~`&i%~3o9f}L3ZMn zI7d%>KfhMI?uU+z!|zlmJ{kmi#JQD(23Tb*2L2V`{rE zfp8myA9d%jvCn`>XcHH9!}=%|(jstfr-&O?xBWKZz%ry)?yLe~F^l7ft>Re{)0m^L zj0mH#tSV}FF&=8QLi@0-LAkXZO{-;0*--{(Yy}PidZSjh3?cKy;CUIBMhNrNJvmJu zq>r--tgKmdXoXZ9bBE9leC_qc%HJZi!wRFjp3)w7+T$Tqxx8GDzNGa~3xQonXNZ4V zb-qN2-Yu#f+%9EKGCKin-0*-c+w_$4)4^ej&znRp`5mSY5UbxQ*U-T9m! z)Py29lWZ~UnO3Ov;hp_{fkaLtKFezo+w28pVS8t%+PpY-wNuwA*SCQ9gfY~P7mTAF z=DHdo$lKE85+ONIR}_+Q99hboj<_fVlE0^+IH|?*T9OJ-)aL`Gte!z75qX)hEwBv zJNc%P<=xqt`VZA$39~elP)yt7StY30S{GlOl88b=chdC%uL8bmm>m+(dS|B^`|CWM z{DH3XCEpFOmOO%u)r!!9V6nDl8dEN;tH}z2uy9(%N1GrwVz&vhS)-;2*sy94@CE*+ zFqkM-ZwFI<1TiZc39yJDxk;*)yErtf{CgGUN6w#1ukzOgqPHkZxRG9drE}oScC+7u znspb;0tZg9s~=X?EqSSC@dX(fRo&fx5xOM}tA41q37_kqlX09+aGHe3WkKvPMx&!M zRTNfQT6LjZuYh`4}35l=KIN5E$P9n#kmb zyO*BXJ$3-!29uV!h|`Zcz!cD4iE8iN$;Cg?iVot&`qaS?D*AJ>IDEjuh)Ox0Hfc|UxRC_mW zElMKDvK3catu8!oi@nQ8Tat1qtlg3&uB-PokL5nujf^_^i$4kXf+sQ_6NFE%Mnd*Y zED(k3I4(Zj4+iw=)mQyqb*Jq#gnP$T&T_9!W<2)>W0mr<>1g~*z4+`K1H|dbONK=3 zo~(%RKnr~K{Y{aA7E#k>ByNnX5Axexp!X|$3{7l#Kg^22t~}7p4ApK-ToG1VF;*E)mqkMeHbUF#Jp>kGjO}B44VrUB=M!GaiUEO~i06)z{^~g@g z1!?LkP|N)exUr-}5r6TCaLdNA9nXq{|1$qBclvmuV-Q_2)M_qedr%X-2+l8I^LZ=F0eh^;Y7zLzT=h=uOPf>!Jxnnr>s~5SzX$v$Lp4ji70_% zTU69S8Ew&G`H6JxG@WMCiH@W7d3QUTXxR#FP2NvSZgiZV*@>zO(~@V=XRGG?&*4qg z_jG$cAHcwHPxPy~URPr}UmJgN9W~Mc`lUo{F?V6PGUDiZ3+rZJ(}V`SM4Xq~QvYD- zsJ^E@rI2%=epUfd_(<%GwW?0&y#(QCD=FYf?3s)F-#q_!jQqkb4N;->X3Vy{#&V=E zTGEZtzkF^h$<;r@Gisy~9oT?hOD79Y3vp-^0)^Ut4*zGj)$IHa?cvf^^G}|H8o~!D zdcT%2^m4zQFk7Siz9ueiD;cM&Q>G6Bfo_ zi#Q)R2P4f#v2S}JPb@Ff61?0QFGf+^c7eNt`LtvGPdov_g2>Xo+;e zbneJ@W{pvJ!-A4fiiy}OJ>@0RfYIAltok(#T<8g-j_us@t@ z)V;t1y(2!5QQN_@@-cL$lrS3#`WzdK+8W8^E-kn0g;s|2pW{pGx_v-Sp+s+|!UAHJ z)k{Xg{F~fb*;Z1*8?Ub?_tB4t^E?)xIGYTX4z;rXFG4W%Ztqk^R;r-Na#Ejs{PfQL z`eZ3yZgsDa{m(lsChu*N{2856GPXA*K0P}BTJ~?|tq=Zd*(rLv@72>ndAW7)z;gyY zQbF3){8psr_a@jFN!Emea;D6kPE0>`06b|(&V%cXxU=05E~ku29HvHgnTQqdoDEUx54VOtu6dH`;cr%NM0Y?ZJ7Ued^HoxmGfwkP91c3-0ZuH)X+;7uX*PlZ71teD zsV($!CoqHlqH0X5LJBg``G-%rCRKcE7`>E690o8gh57JeB zGS<;4AoxX!jP# z!p-4>^NUqS7Y$Y5M+RI&PV6F(lUI{=O8AHO&wI^z(b=!4b0qMzP`$35p@VGs=0zQm zKy)TeNeA*(RUCFkP?Z}jjJVThnxP(aS@!Qp3AIG7o?dJ$-;C}s>edMv6+_qB=R}tX zFO|o2DGxu0JB+h%j8q3Bm$6pX89RoIA?%;@{ z&1qRk#a%m{PQc5$EunW^$v}_pq2Ifb05+3Z;jZ~#S3P+=Th=2SDJKj(Iyt9ypRU%M z`nr;@>3%vpKuCXaNdSgGi?dHPU}DRtV34iHUlJe&Lw@*`>Sv`s1O|$gdQoud2D;O?LBso0H7bC&0B{B8)1{Zj8WNe?cHmVE)D=>n2yQdbq^ld_ckTp$kEbgq z0Q@xJ4^`hs4(R8*!76L4&4WP%B zIk)CVox70bUKVvKvErM~_8W0#l~-M4hQ}8s#_0`UMD-|HNx`aNcF%d$BlZ4=IwdYg z=EEj_PM3e6&sMhsE)Lw;?uf$3sBdRSM%`L~@+dGd4;4sYVo@v*EkL20%OcMfVfRAx z<`H{IFhD}ac}<6*ZzYkeXt{laJ!cdj?IWi{aoKL{BWD@4DIUgd47BHTb92GW#4yz< zh(K=DrHm|hEhnB{1ZB|;@FFt@9NIOXCHu4N>&JiVTc4uJ5-Ho&5J}l{#;J)}E?eD> z?qQXU>b0KNQ{t1_Z=4qairNc+iPK>PCg~9~(p^jhw44nGy39_L%wM)!Z$wRObtJ1j zNN+&$%2Pf&VW1;+brk=VeX>dTQ{S>PzS#^-~7R;i0>GB(zo7O<1B9BgoJWGOBW*H z=Of0%=gn{rrJXY~cGqt7EKUc+j&--(z#3l@y5?}}{J4VO?XWxp;VJK@gy(=-X8N_XhTE$*Ick@z zw0jL>`5s`v6OM9MKn{31!>Iidp!VhtVH5tGYVZ(8^a1#Im{;B2bf5p(t@xiU{{Gwi zXXGutpg^c?EWu&61U`y2@8NW_)NUDO!eF4!um25$1|LkPDI!PJa0f>I-;Xu|pep>Z z70^;*lnQH|s)a`Vb3lLDkqgOc)Jvpim=wWo`6vB_N5$WbPF>hX z4drQ*zbVE)arCBc(nU@+24fT4mcMok4YsLajV9M4;b|$K#|baSXNbu03Px( zsYBfr{*1&%NEu9yhHHBNN|l1r%op##QO)33QX1`KP3m>^Ndtl-3}{-ngn4GZSw_@0 z8f%<1eTcaWP{c3EN2i7;`P*NV0}iTrXX0!XA)t}{zrd(HO7DCIkcy;T0WZ`zW3Bv2 zO`=BKKjhZPN7%@wvDU*!AZ*)09g)yBNC>?9G;ur{+eCT9M}s2`xm-dcezqM|?{RC% zv{+yRCwBJ5Xhy0VYaPEG!8na}ual_T>Ep+{S(D80as1BPq@5D)j^oEe2fKFqJh{)0 zXGNz$B&46IZ{fVI=7(|0d10;mN!`}he$-Xmh0`2rH3Qoz1)xg6O<_6k8)eecOYvRz zR7>$}HN29HP%Ghs0;*Mox|O9q4zUfSzOB||4J~J2p5#`I(-@N4p`@8A-D#07fPg-) z1A`oKmP|A1N`Zk)(s>kKD}Pe|g{e)tQ;*(rs!qMEI;HAW84)N;D}4wF+bf@Yc>fIF%G;Ju$draLtJ zlu&vP3j;mh(1fTHohc(CQZSoj)h(&7(p^aqajud(q&_X0ac|HUzMmsUPIc&+3tbm% z#bHYm1vvzP<4Cmzt)x*N=NPqDv0m58m(+`@yU~n1Ue?N=)H9^W>~hQ$I_^{0kDOCM z@QZX zI$?^>0T@a*w%Fa7_HG5w-!3rLMskopx%4M^pvm*4R6 zFX8iN**5{vKz<_2-aQ1Mq#k3^z*d=4e0?>ho~bbPxV;IH6rS--sd*p*Fb%Sd#vnmQ zX#ndYBzvnWTsB4>vqaR=wbK{2fF{F}tqAYbnEP-m0xvBH3VOxRL!8&7kO)T;yD5hv z8L5Y`&5_k=_grAq-p5O2#Qu{^aE4L0iN9&MtvV&#DkzZNeb!2$QyiOwE~I|JW{}P( zP#8hp^l>ZoeIOBTHkQjZkLmV?EN8iP!_J&2yx8}Ss!0T9YKv0?>gIAaE%6vlxswa6 zr;y}08KFeYC`ctJB~(EP83mJjuEN`hdw-2U&xhm($&wcFOKOj-k&9`hdjbwET5~<<7uhWlJKAE9Be~QDY(NI$dPWy*Q{L zBX&zs#fZds0|~ysSd?Xb>)V&J_Q`)mrIIdp)VlS-1Y|Ke0Lb-cTXrskv3-ev{blH*9kU@T$K18}!bEk=}$4|JRAZ+B9x zCkE(~XkS~2^~risjiFBxS?~7&BZ_#`OemWeEY`7O>?IjP6IUWQM=68MT%i2*H{}#x zRn`_&5`uKoN?Ft>`BlqRDG`1WjP$B2MWUfJIygX$=1ugt;pzEng-9fR)eXB-f;lJ~ZJ3{o4>X{%B)qwZlkv*l4_7DI+oI)U$GBFt(9esDd8PdZj?_e|aX%+- zRlJ2tv*m1`Wo4D-*?*Eg1y#80(mVyZste-oH;Y7%kz_)+YnW^2;?6gV=&$gcFw}mG zUZr2Omy{1N>dylxO8(Kk(?92o#boC#rLWNV((VH;y*~-QqHmf3hHOb(jQaAb(-Om! z(T?7~+%ItfJrKO_cs#y;G%TA{Q97a@(!t zX5rh8R3CGcw_@IXg`%ji?6-TA&#l<+hq$j|^Ri~qBsHhR6_;rd4`VE|U9ON8k-uA7 zz;6M+OhL4W-!c4-;kTGyRw}ncqk!bs;@9FAA`u0lxKzjW31I$o`6e5?oM-KwAD7iNUFX#nN#}j?oEV{oFTtQo)X*_M z>e`*m`I(s4HkHvG!H_!!Dt8-W-uDatK}!U(ul|`|bAPqb+0y)+lhfyqG;mq|gji*`-(qw}cbB>JR^5SGbDy4<$A(`wOGM|Jf3SY6Xy{!MC(!A>!!(bAANT35jc<1sf-6(JyE=p zS>tzFEvDj0qcbfKY13LAl>+6|qhiGY5a*Jv=$QB_*iD(0rehtm!uzV;W7&MxyN+Gx z7BYMB9E>3la_&giZ>-5y`E4`4ome~VRqx7vwN}DMm~Qr35r-*yR%wUfLe38grlvAE zk5%o(H5r;MNbfwa*s>aVwm(L2bW7nY#`3R_xl%MqGkKuGpuUP-!jhLzOLJzWedn=^ zs+;RVWKxVb=7QFDia$T46iMPx;A_aC5{cZ59t~?w@6DA6ERN zvjZC68!+xO3%6Y}jgcA4|C{ExWo#Ri<|jNtUkg;$<0Qx|U^Zj6J&ULhF=u+lhK!O8 zC4oStGdEK{os_&VQ_Z)&w_9zc1p_LicQO=$ifjXdrOmL3tAx)#uBQre1gXXTt6lyy z*}d4&n1x%fDTiw!KvCh=1=+RWK@1onc7K>r{u~UVvZn-W68z^7FAq_1Mno}vu#m#jUC*Gy!8JC=VMO$$Mb2i!ZFHmWJYuffeRRLJ6gY@_HS~{zi9@vyyYH|nM!^U#4 zkATFN2ZBn#GH^hk8gJiqpT_xuG_-*ImB31StJEDe=S}-)~{b;a|ve4frdk+uI_DlsFra?Coryw-llnSbfXc8O|mS-R9Nx!i>4!iHpI&KBIIKbNr4kV*`Zm zbQ4f4EY7@;Y z$tWqls;Wtz0wu-Y3sgOgtAqp!Vgb_;Ic4ta{$3-iU|wdlxQfs>5@SkUvv|!i>U!v$ zyasv2`1kMr>mXhS8FkJ6>tJ378+9M}uS0kp!WF{2(iC@`zkpV6^%bOoF0YY_6`-;F zZ+`9o=?rHf)2(12&K%OQp7jDmb+zE0xc9^{03GTIZ+Biy91bV6427DWmx?#ZE;8bb)EfwY|ybKQ~m{()5&3qa~T1}O!s!vT_Z@M zB705tf`xchD@)M`*4{W=H(4QU)u5D^+D2e}1mk!Pf*0=OnK)ks-FpR9L;FLW;TGp5 z!!84Earbjk_uJX{xf-<}$ee}=c)h6HwI!?jq%>&Qf8{S3>W;9UA(E~=0x_H!*x;z| z-tfWpkxXOxJyJq75qGDu8g5=3YH>OxGAMX8eyHo#kil6rcM?dLiDl2&HuIv_dG9Vy zkKg-VW`q)#OpZgrnW*4Z?xMLWXB<{i=O%!`Lf&Q@Yc5AzI@+pq&h^HR;SA!aUa>u3 z)74b<)UsoP7>-e2AjsinnV4)VnU;j~aZAmVTx&OWi0*b zykHTqntPYa#~zY`FDJ7bnWw;Gr>Gq}`D{#|+UNm&Xfv~gNI_{h3x#^TT&@Y?{DTKY z>K4|U)2Z{3?PJN7nxqoP_EtKJvyZ7&N>3xs-q4;@8(V|k541@c;Y7t~-@P3>_P3KW zu7$coHH+{A#l(K%b}S5uc{bpV0sy@Py$fdT5eEaUJxTKi_(=us$S(_EsLw-DXjVZa zL={!sr@<7*;42D_tD;u=n2y)#d>~Z9U9T3a@U_c&749$J!g|#!8PDHxuRPOfyJS(^ zSUv6xy%^o8bFr&)C(jvs;F76}ovCv%2*XQgGK=eqN@v`il}={eA@^RHT-W_Mf7{eV zQ)`BEuk3Y>dmn!jpSk+pRs7B$=}tDCw$R~aDcRz}FB{7zz!vnc4@D+^BcD{AM*UA@ zF}l)k_sNejeX;jsSzJ^o)WtKik5-PdrGA7*@FAvWadnFvK5~g0zJ4Fs9ajp$7TZg6 zG8%?|!C1Y8xS(fL+O_w#2QfCSyoOuA>TjgKFvYjkK%OQ}_wb8YEb#G7}_c~XXp<3+?P4Va;AjsmtBZgLc%tiIL_I4xYX5ZZ+0%EBB6r^?MxhjMW&e?7VOntmL(+H!2ko-74}6;YgBAcw2E zCf?Hq%#mCB&WAumnpgM0Bzb_CmAeY&Lb2Q@Wug#pDv+Aa@asvEX~A7y=<&S*#)jbO z0`2E1?L(WQVOu_-KPOeg*j8f-aG3(#@_|dV2z3e+Hz^;Z>o1dzGpa499dyZSG?_n} z53+}Sp3K5XUj}B0nPC0L*u3~CZ2z402EtL0OCz#gC8?XKh5eGL(153s3_ZiTG5V)F zm--RaHdZz#xli=$L3eQq8zj2gPxZ=a3JgpAh?*LG3hFAL%M8gS2h32D&`rdujAZP_ zL{F+;zA=TyOM)PBH-Yf!q|J%b#z0;^BA*RQ2-fy6nOKqf|O1oj8wT{{m8%;(T%snF}QvNY-C{uC)1P_YFgt)k0>Tl)QbQN1fEKRp`E(+z@ru)r!+^v|y-L;UM8Zrt)86hyK^Q1HYmz~`R zZ<*;RjuT}*GVFH)9Ba%$8PSVU=GZ3lqV4F>f#4J`XmT(rhF=_iJwlp1sFRRdsi$f^ zM~G}Qz`7RVulXT~16Df;@|vEgPg=klt)~~C0%LZHHrmZ{=N2Fvt~(;D1EF<4k&WEe z+L*@aQtQBzmoqfEk%7=U(A{$t{Y~7eXzy@7xr$(E zK&EDsz}Am)4{&H9{&?lRl6(5h1{* zPKmD_N0}0nK6%aS>3iVwr@O1oar$poQ|EF0^J~ z%kCo6*$~?7Jt#-e@K!^0MB|Lu>DNyOM`UVGLoce6fpOinq$)}8bMzVMYp_in=wtv! z?f>I%dNC@FN9{Wji)Y0T_>>-j;(j668DlZUA-t!rNrXPBhx28M%Nz_B_Hv)*^r>guBUAaaSaHRV&eSfEa<`Ahs zzEXH*300OjLx;t&#i%{Vd?@#pJv1btUlBUu@K0&sMn~8 z3VJk2n5J$pY!UFFE{eOCn9h9kNmp|Q$@R~f;v`&-wMoQ%TI#TmvEwY3g6{o7MA2N& zjcEH)0^<-%uWE6bJ8O2-ogOE|<{Vi2D~MP&qOj4Mmx&4aHuIuwNC?J#VJtTF`k_~@mtkAyaq1rA4? z4XGWVIOf~gmny|hRTm&oVBJ#HjvR&4?E!J9KTA&6PU&nQGZ4!2*QnzzsR_iMb40-) zjI}pBqteNpl>F>6JQ~|n*XSM5=9CG6Jd!G7RF71t0H8XcywdvUfkKZzkSnc|_jTdI z_gePS5*C)DA4MT~mpr=Dwh|&;K1GzipFd3f$VF`l~a&z@0w2Zp*^3*qdyz zcTcigE`>}v)3ebLY(Y7G0ZhJx9bw?UBVBUnWunH`N7>fK!>>5gN3Xk-O1n1*pR4t0 zyVMVd5Op7o;CXiP3T7Az_JUFOB)Pdityq8s69kawi0sQLo#~b)214(>r3eNp?tMz~ zdxI{Ta3!q2%(DEm+SHnq$9^)|PjA}nG`{q6(EW@galL|VrE^t1ffi#8JczxDH)9PC z&#H$B>_tubX|Q99JXnUTVmzNbpr4QA2^~ z>tfu&BuBe>bMTskV5}E3kok$Cq*aZ)s>m^Pfr&T8$U|ytaq9*jXjObs7cM zPD2xaO{Yd+%P=+F)dlSLM>GhO|*>`fObZrxl z5%-1yk)7KuIFsI4B-3VK+Jb**3-^bgEBA+!PQ$(2Wfa=hzh3*lN8OldArIvQY#GsQ z(t6e1_MHn2JVsaxD)fIcHzt_B598_c7~ko|E z&Tbke>ujCaqow-yFZ~{o{p>h?M1f7L?$Y>UX)7P2_Q%<>4Gc2sf4~EzMIh0Q<(_3< z%hO+ZvX2GXP9nzrFC>Ot^J54J#tD^ZOO7l*}4)53h3H$7#5bZR-}Z=D{xhi)+=ni{LjAli&ugzn6bQ$ zrYG1tEi>CIKPHpCd=8z!PI329;rS=ifN~|AN2k08urbae)sWbERG`L5-S9 zz2Tqtf=!`jNj(-c9%+)dmT>3N9I2shl60^%+r3xs3r5}bz!gR(@u&tv-4}W9{-HYO z|C{skJELT*GN+c?$IVn@!OZo@B+7N>i9^+1ah1EHaz=WojFRM_T zU(vwu9idO)`mP@=lm8PD7AYCjKL#;0)y^k#-dSM%>8V}Lhw{e zfM9^hiU?ECBByy>9bP0(ds}JtcX_wl6;4Fko%X}KL!F%|d`F0Dip8nZf%8bH!<|}W zH;we>1)TXs&W7f9vr8Hf4o@wTTspNOc!n<+WeO5(vV5C9TfRe1^SrsLBzI0r$$D$xo!EIMehf>)hU-RA3nt4|IIs5o|S6>P8mxvwG7`1Dpk7Po} z+{vTU@~9OO7(Crsc#!|={w6b$QvYbw;)4!vcS=VCG~ZS%C5G3oVmySxte6dg*+&Nb zzY=4GToq#<8T|j6*3~dOhPf#vmim485P43>S4uW}HQxT!na2A0<#N(^o(#xa)Iww3 zp3^5i_}_~SAYjK!4G{eZ&bABwDZF3yp>)cq|Bk)NNYCd+^M2dJ&oD8LNxUV%&)9#Cm~*l1ww)rcYGzmZjcur3wy0 zaqs)*NSC@R`*Z#s!rh6h}l--1b3XWLd&xIK`Rtji_`CG3aLFNph$t9 z$J%0{ZvP{ax$;w|AerZ5eaYsc#UORvLWw>DcKh@Vr8G)aY#c`-j;F_qzn~Up0aoZ^ z6fc%)I()Dr-dhry}; z)(?YHKh+Px)P4FPE9L5k%+%dH9M6xbfEE?6aYD*dteKcB_Za{qA;LiqQ?ljiA;+lS zD-TD4M*Tl|uqu?UHtv0D@Rf9#8@^zS!uJa!#X%sLo%l~Vr!CFPsQPaB#l$%0r;3wm zej^wUykV@FoauP_%rngKge@m2=y*-~X|Urd8yHm^C!aha(!_UJ&wief5>`OZi&b&Z zYJMvi3!CGzs~WNHzF((5$38EHLAl9$kTlsnA7Sj0n>fS88lLiZ^p)pIgu0D7)u_9X zWU<@fCyh^f-WT=dS3qi`4&SCy#}m|tWA_``_R&idqrK>Qd*?@qLi^~=iIMiv+X*9X zAN?+@LTz)xSawuUS5;dzANnORBemW9Fl9F{M)OmPNuDEzGtw57ORyE4Hv1H5N^~EfdkUK`bh@z+hjO-bG1$M^b$s3Ij!)CWMo9Snzq6Q5cmc~S`o2e#t2OCQnS`Q_PgKx&J=-_V~sW) z3?`P86FSK&8{*96GTdHg@MFDa}MwB+~eF^LoMq7Mn>=S5_dil zh9%|d6&XXhN`hDHPnu1V5`RyTHMsI%*^A00 zZypvPp2`U0?aas1UCy6;oei|b^h3>^2tY}jL)w4y*ty4ao|M&KI*JWMW>mhRbbPiF zx7;g-cT!?<*mZ2Bl08m%o%$uNBk)U+!~YnwF%{D+h$&?TeVx+^K($i&r1Bn<_rCZ) zlS)!@T|(dbg5D~%Mw$sjsnIXTd5ish(AUQzchMAI`sS955zZ|+58ABFrkm)8ep=1` z`c5`B#*ww01~YE>(lZ7>>*QJ8Ujy=U*)IS3@SVkjeVfK%{O5V-bA;%(zgOSg!Rpdi zf`bxk)R~m6qHH^p^7uuxj(FXjSio-qzeW7Q<4&Zblg981tBC-@#emUj^E;d0ISONWnFIDR-yLbp{R5aQ_!@JAgnM5^KXzcFuTe`G z=x2!$yfS3*ZSO>9=mkxnM>{kC}Ri0};?dP0L+fi20UDovfEBn_$DmgF~8nzD5P z)Qj?xH<17vm`7ZwSQb~O#zsveevLD=z`a-2gu@Xf=9xtQc5Fdn>_EL>i3n_bH1?Dw z0dLkYdg&=E4&G+#x8DyH2-^#JOA8s5<4zyGg3|-zRS6G~lpPst?Csv%s0e%ahCY78 z$IHHV@Ok+w*%^KEpS8b5k~|>(73|!dmtC2m^itTbK4iJUmVx&bI){xXj-=kYgP?r+ zJmVZrJvyg9ezf(>+q)lJKDTB_jYU)@6f=kM;^@Fmq)p%R_+Fl|ruRB8_e`t#Lj+0~ zc0)1RMIOoKohObA>t1@{^3!$^Xu=A>rb^MR7*937iwRM)vF1>j@kF~7;5tEKG`7dF z6gfVq0Fft&*hO4{U4DgRZdtnzP9hfSj0N_W5sSn7!G7KoXT|UfwXTtG3x>qJn$z(s zh%HOWH*49E-MxW~m{E$w`aK38NKqdorFnOrmD2$Th2BVHgJY2y(!t1$PN%G1dP!Kt z4+C`lbyxtRo+S!*BG-YkDy+PU2Yh1QCs>4BXOEfj`%jz=|FOJ?4`t5lF{gFew+i21 zMOw_W3f+fmdQ&wiM_r<7US|I}ga> zilu@Nd6hnN$gRjoAMvG@Iu{+0#O;!}okUVfk1;oKz6bWpBym=k2TE*;Ng_eHxIe%w z+!??676w#znGoN#eG|@_+bPZl$=Kny;|?}%9ad*jiZ>^jS8xRxsLU(y$5M!y47Cj? zeHhu;zJFT=#7P5O&r7{r*aVY799ulQ0;?za^I(6gup>{;gPwwup${Ad z?gIhp4Hrw)Ngo5&n9~)<#Cp4x73YuBBI$ts71DW}!8Mp-_RPl~66w-y*cj@G;0`4w zf*E5X7-@%L)C=n`BSnmu%xg|^eXb!VMPaBVTe5D8H=#FishDjh#o=?OgZ4zXLw@f$P!uqMkN;!|kD&FBLvp;lyLDRvC7Hg2YJg_3S9*Pd_3$DPA#0+Q6 zyE*Y)Z+OlGr*`EkwzYW0Mrv9*kv~hg_ojubmE+!s`m%~ApWacQGy1u> zv#&B5PR@He5yxg(>J!I}&iRk&@!dSp`IV}+-~Pbw4?Y_Ao%?&nQheX#@?+Fj1B&j= zx*S$EzyE?HPrT~)*UGOL%^Q<8rLH5>0RAjJ__RHguu<><+(taE&~z6Lx7_TudV!ey zYpZ{hr)z*2*9{sgRzS|VN?B&0do;GKd{a_pc_0*|Q+uxrbwh2Iw2uT|@G=r^yX*W) zdvP6hJ%2&ajm+hiI@B=g%hI<@_c1B$Z0(NfagiIm$Kaq>2BaXQ?Q?~^kTr(d0GFJYGZAvbB ztJr5P+n^WT_$On|hgS33nPuJxw(T|ZGx?KPmC00w_b(Y7v7ZkR%`d!(3g>4o=60*C zl@sjRsnP-NaM}_LZ(cey8rsigUz6P7EAcEOxD*(0C}uptCjO)#5=I$`bEVd6G9!Tl zW!wyAJh3Sra0R8LZ-V>!{&FQ$dmp?uy{~g^*Z%9h5%bF`j#7603L30rfz*ACF__M~ za^AAv4a6%p$Gm6S5uD(lwulUgJ-8uECWceQeh0DQ@*h$TcdF;4!&EO-$)oAb=p`=4 zz4E;D5fR=lp;=%f^^)lbHIoVz0)p{;k;R4;grjz2D+=>qb>zM@UIb?76{O)_y%|~9m z@Jv}%iXK&F1oQp>M za_A#IZDyYLU3|R~CNAW@+|t?HnX=ysysq4k|<=_ih}#UTP%B7s9WSMyPw`gh1^|Ime(6a$Zb)J?iX;Ic zN=!ezTL;Gi?~mOQc}8FqS(it$ZqHcrIq@nAA1pEMdjTKcaFemJiN!>7C-;u_V`|?#sY#5iy$67CC5~*`wLA(=5$9O^FQVZcI^JNcqBY%54r{@B zW~@d!&yPYvlpW!X#)=og3WBf-Y$9E|G!R#6AhNbhM?V9xXhZz8385#LDjFy9Utjnylqd9xumfVXDf9ByR#X#cc*)YvzN>N8#__J^m7h4YGg z09J%sO}MZs()G4#wx_Sjn5v&9v-_GvQH1n}ChK*R!GK%uw@5(!~6$NqVk2qM>$hN?;;u(OB^fAoPEaaejK0g(?B+@w*s7p zP7O|>W87&aYvli&Xq*gA-9!7s9Am{k`tMCR^nVJ@oD;$MQ>D8j3bh$%mStxSQ!Cd8 zl)sLZmx$Wm{M7=q6oG3=eMP}qE=HiJUU-3xeK?Vxd1K{2;XhG(G8hR)o)yVy>T5!k zN)4wY!cPqIvkW;o%YKeo{(K$Z-U(HSr?;Qatrt^~$c?(+k?E|DN2KSGX?0wuM0{cbq)0zg59)WrFO63M+*Rhf;w?2cS z+%s#rkBG#c4L&e|gItODY-fpVMHF0?_t^(6;?`Ack2-(DJ^X?U?=dkIVcYxz-Tzjh z^uMqW`?^T@CByrsA`5S6y8RY?jpiIok0DJmqYbzCB>T2gk?di|k?cs<#}mBxXBo^J z)bksK7K&y%uUg&(<8R2xa7R3boycPJir=1;lMx*i{JrV?E%a*mB|6q*cwbgM+JKf4 zf_hSqz5;o;9k}-QNJHA+K_U&KhxP5k+=nE99d$Bb*-vr&V;$GO2x#cnR{C><8JXLNb^+>h@4eLJ_KGcE)llh@4u-?>+%df39})r zOC+aN7mv(J;}iZ`k*qEBo2m`|=2>Q_$!VT|z34vdU2my$)~LmzK8kz| zo;pKkMOC`=O6-WvRb0f3Jopya7N6)gh@WzsD#a{d7p~~1Z{PU|1&&YF+z<71uTHm@ zm$(u|>|LKeKBK1cWUOp{Li(C*KOyLxEo`OcA3q`g@yUJdowDD@>+ifPL;r>Gfp^;O zU&v4W^9<4Q9uy@oXX^f8Th5x998kHXX@_KVRyL@&mE$=zT28%E200HZEs(QjuKKn{ z_*dpm@mZ7?rI3~n1WC0%CMHxBrs*h{9vmZkzKRDVTB9cUUcz_c((qVE0ZCZg_*}EIJ+vFQ`yYriOGjM(}|er zl?R-ugmvA0cncm`V#$Nao{lErB?bi&7f50I1w4JH=2_tn1TQDE$CdR`Mb#TZ3etEu zwTK9@sP($uc0Q~e<_h+B-{a7&o}5KR4Y}tWXH;mceo~00GB&(dkn9;b+@(1{l~U>0 zQcY?YyIvaqQdbM9>gNYF)DDu{+s^eGM}Jx%GHcWtE=e+gUM zrY6>p)ij>@32Q|!wH)MCdV!~IpnB!+gIkZN#bVA;xh88XrX8Xs=OFVG5EBEW759K> zmiqx&grR>gc^)Ygk<}xwmr{h~`YATlwPG~x?;ESbL=%1XPjYfZg0%<6Nkm12pTQcd zYS%jEG2_o9X2i1YmlYCoJy|m`Z$XflS3_ftN)`Kb?x*42bj@ed2>Bk0}*121vz!9)&C2?CC44EVC$%i4y%*35OGvK#C7V`{%}~-eOl(q zpG0FtBV9ASd(gx5!fp}melun-SV={4_Ql+)ymU#^y8#!C>Cg=>UE;HRGd*skA=n?v zt~&qh%D1Qc7w7&+*N5KqAHbnfjW?h_^aIwDn}83|=ZJF{A1^s9OU2Qgo)g=Qazd9+ zTq~pY&!|H-W3{K5sN8HWCQ!goObDk>GqjQY(~IGVvJdD#eO$x2#tKma>!XI)*qm~( z1a_j4|J`6=Ew6uHjz~=SfF`j3I2Tq;#Hy-;C~i{?%%oli!2G_aWf2h5U-!k#*(~5l zciiNh5Oro1MHxjiY5ssP-0D8alC}Gl^o(Byw z(Q^pya2L-?i9N`qJf(Wm^%i(UPgETmg?vC(J?k(0FA>NVUp002#Cu7TH+6%#x(@We ziQ1dGpQR?)%(CkjIHj(}wvnJ1-n6BsBg0EwAep=`4T^aagFZR3yeEY8aA(FmE<48) z`fBp{2(J+RQdl_Ib700fELKKxG;RyxtFB^G@#`<<$ku=1wQ|Aad&zU8KZ8_L51PW@ zJKLXG+SGfnvhh%JAThMkE@t&TCLh?W<-!DZ@;5Dnh!XpdrCaAEnK7jath!R7AouW^ zQFSTgK$dp*IZS4)BvC;N65$r3b{4f&anIDC7tN@kyDUMHawC4Z!p|Y;gwKce(0-9M?x< zdNt1CSw|RY2ifuA*9ZQF;n|4_mgeFxcc*Q!71I?!DZ^+HEF- zKhTs^p~!cR}Fg=e(^{bIGa;5}T#kb^pNtRs{^RB`w!iyoryDKc8?NJI?}X{Ct-y{pDKOt&J!~T6%sDsGBDG;k^9E zvI1`Gs5z2jEMLJh^^P)X8!6>Y>>7{zSeW19{&XC*KOm@&L^*^x0Az}(lw!(TE`oot9?@2k4R-t*N;`$)xt^P330y6d8< z^M#38n%zsrG=9LAD){&TYWwXk;Y9f+R^o|E_&GBpG2+mWysFcZcQa4OtkgP^ZG)Oj zB7_aeuKK5X)%B&7KFR{yIyC9rrAD3HuZ_Yz=4_4;ZW^sQc9I_%wZ9Mmu3j1_sp(~k zFTqWSr_uNalHHs1&iJ85{k)N~7jVb4+=&yokiFn*yd{2o_5FcFAgO4U}9 zklW6WqU+=mZq+}k9EVfMb9ZD^6JR9>wp^1@63B2$F;G4PyUX{hjQY>#@?@-Ti&X?` z;(?~#oqhWSMnnO^M%8>+Tz!jL+XU0*9`$8!4ugnPjkQ!DH@bsGK}X^$Wn+rh*Ll4i z{5=c%uXF94HFo=uhSGDp2MfIzyBA<#Z<_4iasgxsfG9opPYgUm<?O~&oX9JfK#V* zQsqs+VGQW$p;DQ(jb~7tqhj}PX$P0$xM98-cRtYb91Fi|)D8h`SiJ>O574+yC*T|m z#Q`g{hg}wazXK~L%35ChZ1|5-ZoRlsP9k)rt`efPp)_z++<7xKgG4o7k(#5YabXd? zgiBb;oU*?WAnv*0nKef^FFbp?jA=3mgbAeBVsTXxK}2r@DBMs&hUxM|JJR#i3{ciz zx6tmf)CNbk_d4UbV9|K;J_hDUUOF*G<^N27e)=)gsCy6?)GRs|b7!~+df4zSaL-tM zmebLc%zU)K`2V!M3w%`7)%Tyt1p-7*)CloX4H6X;l@ZWHLe0pG%;-dEz0rDos*kl* z>xBtmQHjn(I34FHZEb7c`dE9{s=ZpJikNTm>Kdy)OToWE9eAq&Sc&65i!*l0IbHRXdf2bUqAY{p zGx#`3i|QOa8OLjM4`1N&{6Jb40PvQ6HFRN!>GM#Zo-F*&0gATg0|X=dz0}#$jdONJ zbRn{$Z$ztrruNc#bW3%y60(X8*^#5H$^yzNWlXl4AL9S5ZszB5b|OkezQ28vC!#*`E}sh<&5*mku)RAjoEns0zS1`m~uuzT1?>Qv)JdOmp@ zxOwkf-Wn>L)(>!LY3bLvU`(;0?`+Tl%i;^F>w|78szaS9PC=(RpX`H^fP8rS=?naKr{Yi)ddUtnpzqtS5|y6~L$@52Fi3=rYvgrhfK& zg3%1y{Be2w+yZ`Rc=$`h#TDwb2UCFeH>riGT}+PC8n}1uPTcPs4tG)wV84MI*)HeZ zp#L-~&z0-L1;o@!O91~KTmO)khN%8kXvq2c4{=&2Q9rYr>dz+Fgevn1g9Gv!IgrZ@ z8o&7X5IhAxm+SP(kNXlaEyfKC&pym(KEqFZMg&`lW^RF}w6+!sO(gu#c zjMgN6Zp`7C(w0oPXlXd$-8gzf$&K!q!<}gZ4H3hW=9)dQe3?EX^W^4Xv~se#j-m4A z!_7)059ialy;1G?t>{u=TB-a@E0xZ)7x-oXaJ6X#`An(T8aTJ}OTPH+oS18;GJ94b zKF@Gke@}1dNv)~lC_ZYu-1+o{*;_P|K=-l;kz1zq04XfHcw3Q8+EjSLYiP{W;{MC z9xu4Q^l=VZXpz!FPb{^zc0jFpdakD*GfYH;JB{49us_VNqG%*Am{1}pOUR}xIFGP{ zl}C_3V1jhrtBDI6ILP@GUc_Th0VECmozy%?v}G@%@JZ%U3(*BrAMijmEu8%Ni){Uj{B;X6 zX4#AONr2`lKbi`S=4T9F`e?4zMbL*o4(@5NE-dM&3%jxe=G^{A^WoxWG#Syo>To0GrZvq zh+8C!x@Ni6FI6B%AEw9OH?6g(zgi8|BS>oPy)>8ENXq58O|5 zIo4oBFgLmmhh<0PnwB1vIEk>x-I`B9-Q7yhpEN)zn>s?vLA`DzGjYNfmCmV^&CM!_ zLRwI=Tz~a?MF~NwA7UpCzQ(n)r~tW--@4k7>aoj~^C9*;53A zXG^%nzQIJzIs_YI_I?surW98=)2;*LoGdEFptCY)%tt@q{7=_9gW6|Q_PH@tpONNO z&a`3_Q;UBx-H6DU4_1jgJwK52hM`teWhe51G$ZP=-!d)sFN4))|BT?_LzzD)v*1eo zn5|VKCBHxmLu~pQ`m3T6+R5r#OKG>&nm)(dshI}FB>9p*^kqBcQTiJovaohe-44yQl=YLHrr+hvFc&o)gC%e8%S z?%_DoiC14DZY(>@>$7X=hqCIqm~SopDox3qM6!J8bWv^2ERp>?S%H;R8CUW>|FVb| zvC>3e{*H25hr-BB(%BuNt9l<10XCPqnYnFRV z_6tkc^=a9AST6e&1=+V4mCIk^TvS;5p}Fkm6l8z8F#GX^wO8h{A6=0Bmcs1Y7;?Vv zeRJ8jL+iP|pIVr`o$M0(4c~E6k4cM2IIU@Z8Jrc!k9B8ws7=txlr~NuQ=FZiOTP^g zS9+jL$#;-!V0aS`2;2UKCV=eW(X=J}%OSUaMHAhG|GID~!avs5Ro3}eiSN#*_#5c_ z9e;auKE~f8JO2-V`*uFW-#(rH#b2j$I)8h2-p}7k6A*!ilI-nha6-D1YB9Q(kB}F2 zS{rF$B*h_+WVTH@YA&UpQvOH^Gr{{7TQ~kB__y?*=P0dGS2cuxL^kW~KkFWEwrJq$)7xFB~qZJsum#OEQ73)hm z|Dc>wpuYj!r9ihnjbaMK(RY8%6XaB$eU&z1?k2;Skiglolr{_~J33d-H>f9XkifG2 zW`Pc14H7zs^}jYqJnsu5p`!*0D9Y~1wYZH325wp22lj>Il8kAkeX(d+#ETi=8&HH9 z;45g83@}8zQl1##VcAUzk(x91U{1NNp!e3=)Z6bprY2)@`WFHxryDq}3K_2+b@S;_ z^d>K7dJ(bfe<^3K{5L$MTh6rjZD$wC(;{aoLhH;(oAi|&iTw&=|Ft#t6E8U8d z*`@V|XOVN2X{&JdT=1EcI#MFRuIz;X-=OPc5`>}F;ZQJ$i8!r8cmgqpW-mb#z{t`1 zTb2_odvA79`UJ2(*dqEc2eJiM)L@s|Dh0U>q*d)dNba$ z$=kqHM|Wb;pwnMv`Nddxx(qK4I?5BYd6Jpe{j0O%eD$Dv3heZ#0GE$Xp-D1df>0+< z0}&l-`2}tR%=Or;Yx6z%d3R3;vSe0kzDCoQTzd%H+py6bQ4BL2*`@M-CB3>Stv};1 z1G|QP5$j_~*4x?AnHdP2slb{C}$+LYaWboYv zk>)G^nBae=@=hM8^I|8}&jKUjq;`{&w9}l{bw*L`UzM$(ot_B$t6xJmR3FRL`BNT@ zfjp}l;PXOjfcWMNqnQ@Y=x=?dqAQf52?oZAm2Z`S%)gnq-O4}*LdA^Dp`Lu}{nffI zfVOsKbbO33&r&Hlq~o7-l63si`?$6d>&vraO4xI1fYn=#?!&>-iWb&Yq0yZTpz?rx z61vFc2BS9j?1J3O3&DO*L2g$0Huu8?xmOkDzL?zL0VQOVaN{r7PmzFSF9lS;k=!^8 zZ;$BB?R|4wDiucjN)IU3Q*KM8G+))8!WK3wsF*nZdh_5L>zVJp$dw~!JKyh;+HDqj zg*-05W$^j)ya55I`n%`(6g8AvC!9|JyZ?(3^&CtQ9jjrL9RfE z2impz&4^s;skw&}>}RV6A8B8#E>oV%(gnDw!7N3yJ9vS(zUs6NL-T;=9hE)VJ{*xf z&OY?Z9%&wmtya)Ri8%3a&|kK$^N0ErX{Nuw=0SV&=5j8R!c9t~I8N#U0A^AM15FAx zqew1=_$#EaqhT(m66~%tDZP-gk^@SKk)nrg8akVl`~*D3y!0>4e#u+%V_cRAX|>&QzIRsO;+9llF^M zK_9g*R&V-&vX%PTQhMp*zf7{(4mTBi+rDs~mfEhiFQUfNquilcnVn`dkij``ab0J9BZ!r}v&IduF09C+%6&v1?L1eQcoRn*&-X-J9_r`y zGTZkn*5NWYAjT>6ruq+?AI0Zyz|J{nDI#sSOa&)@@4~&KSK_t^`{F+k2u0cJNwaoebIvq-3Ge?v0V>MIctV0! z1ebFI-w$sjqF-`dY2v@=)YOXL&gWUv7R3Wwy%SF&2-Il#;yKg4rOHC?SWY=)zrnM$ z_d3sAjHG#PY+qu$b3F?gCiM+0RG_+-qYo!;j|Vo!1KvN74RS1Wl5YVtE{?=GrqP~n zb$2CSt4VJC4;(hw3fa%+*h81NZ+3Ta;;PJdm(tfh6JN`GcLfhzl5szS>ughbQ}QXlWadsX9_TwMEG;0FCQS);n;OIdFC2G=^%Nj`~hqC0D4+f6=m+Fx@*?pmlcS`c1<7N_f&-UaXGl zRJQZ%SFsnJ_6B7j4(r(CB^nmQ4 zD$LD~eP@dbI_DTXM{!Hc!E^!!@e5ekTIY}ynV1K*o#LD?&EtP^TI*;|RGvM~K1@9{ zb8(>a;mlX8la^c-liAZ+_5i{|$dSE`gv`ByE^b#lNdYX^Iw_qA;%T6hT4$edz*=RW zMmwn`JSDf(3ewI4?Yv|agIM=BPd$$2vagV2NnY`*%|MO+h@Bu!N;4CpQBUFo*|T_> zfqxK2oT&}RBo0ZnCHmygYZGy308H(uwp~k;YmZ5;Yr&^u?0~t1(Ugz0y~3CgAe&_Bmyl2mAf(uKU04EKFZpg7loX~s2j8V%p7fOZz~IMY@#v@cO%-s!s7EY4;`V3h@nzD zkL#2MjV&KOwvuX?nr?ghqT*0{ds&2|VD8J2;GEFF<@_C+NtKu~>1!$@ftTA~E{+h@ z%UNu*F4X0o)V44Lj~&>qzkd7lt11#`r&Zj`P5!nrb40aG`CkbImqrFIn0r}Q<| zp}<1?qeHYoKLRgvf|!EAb`@9}9=Isj9_sGQv4Lgb^bNK1LUh~Z!rR5bDX^3qmX-VU zaBz8e;2i#r?XJEiFh@Xemnw5xStu}vW8%uaDjZyhj9fKvArE7_`(GOlEOk2t7Dba{ z#B+S$sL(sWCJZNg=QCg${Ka5e`*~m*`o&;c|9M~<2ABjRfr^p%kW!yKV093fMu5%F zgV3hWgHYWUL1>!+%p-;h4V1#^iyDAV4mOJ{Y~BvJi^I_1$C2P%;203yga)qQP2n`# zA^~os<6>je_xIWtKo3hqKfx7%B^;bP{HofS5Ye)^yfT`ZnMaN?H3YVUHV!^eBJh#B zAhPI#zH zML)_e)bm;{W1dqM3a$z*gBa-L`I%IaZPrjz@a=&+h+4pRq9kehr>||VldG0p4Cprr;x?gs_^&KCaab{?y zl-Ybk?dt}rb0g$wp9_pu1Jy_n()lO^q?XaaV~4+TGFWanp|Izc5h!qN`>Gox zE}I|D{ARFeCS1FoR#pM+a9~}?Wdia4$Dsg|bvKBZ1!(~Be};f)`~0%t(q(Ot%&Za> zWw7sr6$dX2sMqSkTTV~~*AVzB9P}c=#o^4|WeQC9dZ_(XdbvNuxR=d6FZ0MTwwDy5 z#y}?*1BZj0I_ZoAKR7Ql^cdB-KGgn7u~H0~Qa^+M@ji20uIPHxvM|BNZK1$>VfO>D z3B>`_<01q*41T0f@0fB=eM#j)E}f&l8cV3XgQA2zjF^5$f*V4?tz$EHk1h%YU)G1U zp=EH{-&ENKbq6?*fWR)T3_n&z0Q<+#~Kg zq4s%{_$NRP1vf?9b&=rSv6&l=gnloron<-`YJZK40DC^PKSxO()t#4l>d0JGABPEp zC|JH5aW_VSZ=a95m8oE+rG?EA+x=Cc;C7YY6doQoV*&0*x zm~Q0YZW^bb%tl76DY@PZ?3n?%N@j`A&NQ@bfxkKu1oNGOe;DHYSZEKqZ%2aLL(AI7 zW*+HhOKMITp1s11V4Vb4Fv|=Yo2lwYwo;Rg88?gaeAJ{uo=5~P4!PL~d4q2SR}Lq} z-&iU1bLBE?~%D457Dx+4~U(je_q5H-@=7E4XCYoDh7Dat5Nv@uh~F zZ>N(XaW>c{{1drY!BKUIVa@NC;Z~YF4;8C12KBl)Twr|fU@)Om1S)df!(D7@60;p`-n+*;lOP$d$fX3a7Sd|9Fi!!UfmW*>5KSkP_;2> zHCZWKWDB>uOW|+`EWsWXVS5ObBwXu}cP&FkH((0$^13Ow7LI1h8Tkx9UOEsrx;91J zfu#;y7z(secoX^816#q1I!t*6OvCH_P6rl*sd(Vhz&6ANC>Xdhuz-TwDCoHcc&5jz zcz?$f^fIYpHLMV;ZQ+3n15!l7NTq?xOn*1!0IMp9L-!#+Yb}gbjHWjUfPv*9*FtEy zyCWP#Eu$_0TNJ+yNV`j!iX!x-`m;U^ZM_b)OGDd+s&berQ=$g|EXcv?rqIA01`WDR zO=7|zY}o=-vtb5WbQSVr8i;h;IcFpZGH{`NW@d#3Zi`r*Arjmg9)33(k2^;+5oFTd zAXVnwu*8LUD!;J!j`K4Qe%W+}TRG7;?`CEOUPeib3|tloei{la6D=)wR}Ngl@Pdd8 zNreXo8eqW1+r`8+goT_dl9-qU>g^ls0^vhFbpI671h9D>vXBe{q`8+0&Sp9<*&6>@IXn^Z>(N_co8o-Kh&|RqoLHdrk>g)Q$ z(M33aoE|PC20^Oac7l(Zx`sS}`R7ekGs~gZnM_tuuOWENZ!<+jDu$bU!Av#NoMN+p z7(f05|I9oUd_QNZnt4t!@G3T!pXG+Nh zL^8)7PQ|YPQH5%II~?4hA`c$s7l9r4Yk?hF2DrTsB)=F zzuY$IceJN@3QJr>e>X87nBx!~Z2Rp?F4kzrO~JCY_Gd=J77&dH1j2H#d! zA34I*znucJ1bago5;PP8uFELdRv>WTIjH8r9U=EMdfx-A$leZyxi{i=M1rq{-Ms>9 zg8?g*%rl_fYsJn+5@z-Q@I12$Js7x4$+yq~STF=4B+TjoVVIr(E1g6D-RlGNbuzwU zbshuEpqgwegy$;;p1Ti*r(`rTSF0@p%eQ%-N4Y#HECn#H`>;F!ElBVqa+Gf&P=#Ji z2WJiN@%B3TK@N*nE5v~eLYz4-(9Q(3{JerZce;TIa6t!!px)1gshH4G01A-9R&RbV zV46d`8Rh^}L1w{MBwN}-!OaLJ*yg-Y@Ez%0XyuXvl2if2BqY5Qv z*5<_w9CRC+7~K3k7_Yt~am2-$wbCvPqzykkAm%wQ2=jb!psj~#0KkDOXTU9&UZ`2K zM>3a6g74C)SD5fK`CS`w7cQGmy_-Urr_M0t#qI?}Tht4?ufp4dZy2GPzP21T8~j9^ z+BPP=GB6*l2yA%3iAa35;8HQ$m(gPbb68CEQ*JYCIP!{Rz-b49or%WNM!ObUr3FS{ zX~`88CAU>_>41Ahg?n3N$;DMAlgx#p?!{H^q-sCdvh1+F^}Azid0Q?UIJn+u*4|j~Mnt17%l^tWNx4pl7E;es-4PVTCgKJ=7?x$Q6+&kv(&_wMX<$dPtK7N25{q9feQ1;WQPl10 z?rBQL58WMi<9&C>GZ&P{lJD=14|zFLF(5W%1<%Pn<#!&_!t}96)W3Y8 zd+cF%a+0nHAUu9<;;<`&ZGK>3-+mPvvOh*ZZg+!sCVK_3g_8d~H=11A)|5%~YE&rI$B4gM9wSibvG~9{_fKV* zv2-uOi`K@#1d;2!SaSXDSo+dlyK#gKFo5?tK7B}0Y{-)2T5cj?&|k+Y$1}RgGDZQ`jnBwDo4`ln0 zFoQ0ZHaE)AF~BRwg8DyR9GZS{76q83dx?AlYyTsOz#ywix=!5shr6XC(eReMwE{!rb{i z^2IWD*Ww#7+~$1V& z#9m^G6nVS)vU{O}L~|1-M>CV_%yl1LfJ0H+k`az}x~GQS>p8S(;+ETeEw5zgKH%KB z`QZA^ep8o?@4~eQG53|YJ2&pWIupD={-Btk15w>|A9bs06ES~$F%aLn`l9sEy@|u4 z?%O&oMO=hyppn+LyJ~UhRx&<8CRz8`lY9uLGir&vABc~tzjJm}+bVIF3DsjW=yUov zlQElXRbuWZqQ6(0+SpvuOg7tB|;n8k3`Tn`l6`jcs0?p5I0?bCKZuaJ05WPf+joGI%JCF}E%&2i}Z{J8?OP5B|m6UqfxxbW;ov-8p zmG>8yF9eQ>J)#l!pik&0A0Oz|%Pyf8+O2#Y{NN~XZ#4sP=|aA~ShAs(&8$mn%M+El z?H9nkZ97v%XNu{}syn|DO-IV3qau|P?&6|HykNK%b)LqNi4tml1X1>z%A0iWj{NUq z_1AK_%h<|^quFg;1rbKm!@S>}`l%*J%w<2__*Et629$A93q#?&c#p%(E!2XCN9l?B zb^7^oKwZ#PQ4jpVd~L?tbZ6pg!R678HbB)C-L;d?#m=-}^V$2|;CKnmGIM<#STriOBcARHxRGATG z!ekS?nEkQf&g@M*=ka$5h^=9ZJ9By+h%sC5{viEx?os%^z3@#(_=^%#xn3p8Aq)2d zuX4XGd!Kx(V$nOZd$a#^2OsTu?d0w&6UPu5Dd5cR#fM{(yU*nu7WeTw56vlGmRK9D zKad#Ha&OmFiMOLebk4!sv0xAUNuE2rC64fx?*Zhb|Di+a^J=b~>s|W~`v}5w`}4t_ zopTE5moaE^UJQB{B?c11%8&OQO;;_@oz`V7=M**LumA#x)|NFKTY69KUTf{wD<)QV ze5{Xw5Lbcqa3aY05AbV_zwlcFcIfXe@4JAP5%)LO1r6>&7GZHI!Vd(Oi@AQKVINc9 znf?R?V+TWZTEJRD1x*3K3;G_nM` z_oDF5YVTL2d7*L&f$th?8adh(clWUUAH`#!$=MSu2{9f@(^`c$f*P3q71`eU)J?zHV@B;Od`JGl?Jq$fNw_CBaoKfS zqIaxAbwhxg6Xlv-)WLiwvh=%3O->QpS@h32_&A%b9Ud?`dM^M~gATqR7Opt`oivwJeLK504=s z)u%r8GdCE3j$gC^o?%AofNoNY5^?oK9DivULrfVWx=RO|TIsDgu#V|GrP|YWHV=(n;6#{WhD*OX@NuK{jxkaFitaXWSI@r8 zh2sc)_EGf7D+@HPXl86VI55?^pP>Ar$i5ZNT;Hg>pLFS?CG=$bIB43`2eD91u#JjD z-itXa=3hrPrc!$M*K18T5Qdzt-r~Jr1lnXgt#WrX+I@MSPKGip(Mk7bqaft@9evZn z<0UCaD1z#eS1u-O)uX66E7swSq#BTS)V5?vAc$Nzwzj*%9_>A{e_hY^d^~t_PuSOG zh`DqA!Th7rq;GTDdlSBgD4P9DP#j;s6ccRTBKUc_g%|q2GJ7_SR}e72#}YzB3P>3Ul}HAt=_!!ZAYX0~u!qhIfkK>%A#&LgMh>%s9; zEdN>}{$*AB`!+qU3gqa59>O9ZETv$)YI9P5EXBhKIephKCElb&E*sMG?RwV3WIdp1 zGs}l!67|Y>jwZX#ogS_o<4pT46$E$2p^HH{YU}zpkXyr2D((&@FasV7vGl}BdW-`L z@Y)U1-1*M*XHjF4qi~=3EjiN3$7~Zj!?od3PVMuNJ6%(?EhGa$=D3oWU2C4wyiV0l z=L4@Tf3&YNctt}pL0SyhI3^`l5alx9+VOfq!rJO2&B%(QH}g!NuhSE(ff4Jet|@cx zU~?A5ea|SgUE|74ms@pSTZ0=frB}Km90Oqvv*w&$Jl)vn-G`qxG|4IBH`QG@`b|X% zjoo|m)7^*!r*)UospEEeYhDLQ6F=HdnvC;}bWEeiRV`%_r_V%rTH+*+BnNE`jRjDW z@k0+F#riglx^b9ue{Z~sTJEkLg9cpcHz`eXx8Ok(vDm0cwUa!WOlY|XM3`rW7pYx@ zEM`^OgxCM(#PMcWvCKVn(e&+&-Z>{2T}%3k)4CZFf6?F|AHVEwXoH{>fI~v80+rXE zDPX~zdWDv==g~%9zt9-lNbu2FX)$;ClRXeQ;OTBeX3soG|GBhwvH)YW+K)Bk0AL+U z&+?oLPqdHq=E<()Yg0XdX+2B%K)|q~=F>%02ZzT zF^}wpY8+Sb&9nFNC#SD=kNeK&zHrQ)kL36c9k~v%Wl1vu?L(S?2~_iCydlsQoW|9q zMW#zB24?BR>Wex;uHbkU9pac;dT59`GmQ&T6C`8KDstAb4 z-U&vHJ*$vceU?!zfGY*yT0>P#Y--}!K0MpE_A(kYSF)gcgJkc%eK1?m=ji<05et~? zw4Q>D<7$>{Bfow>efm|k**i^g4u1EP2RD23#kf_M)?G1F`7c_EwT-fb5~c&FYC(mS#3Qu*2l1d@R!hNnBccJCnV}I}CC#yvd3~?g6A-QSX&N;@(x<+k^Mh52|jC4>+T`r|j56xvR_ACxhh?}D> z*3ghH35OaQz5laMQmeVvU$(#RzO6exA3}T7NUF(G;q~9WJEvugvx;0!f42(>7Sd=n zSlZk-a-AIif7?l;NHuyt^7aB(`f7TuRW~~AaR{1%zGh{y+2DCPypZqfw|C|HI^Hri zJeGUvU;oeGDQky-Y5@5kG+fX*ACMRJ=-jJ2^PRJRls*Ih5g3_D)q>+E(H=TY9Xd_i z9CXm^9p|L7sKeb#&Fw<4uhjetUFJgkRn1Wmlq73@Q~c7HVo*yfXzhx-bx1N_>U|h8 zO#8=e2$wj~L>`5M=p@E_RMAt?-SV3rlI}EaWtRpsgHFYgFFvf!5vfEBh<4z22zaFh zHwRb8Gry^A;Tek{7Mr$io#iIqd{?NrG-iKI)*EL?EkPhHF}lPSY(gV;z@gJ$Mt;8L zBv-4tz#A;NzA2R=uTMC(^-(vWRJ=@QP%17&2r9azm`)vi{D^1SWn!boqEx&=rWg*Q zMyZIx^sQ1+ic)d0Jxcf#poqJ}Ft}r>`EL!>dB8EHS~Ym1KE-v9w!-m=IOFLNtD4dm zjc?+OJQdSK@aA6e>P_G+>So zsrfnjg7|y??d!Ta*A`$muOAtHy&8o4K97P4k7$VFVwsC`%zA2#cLUT2v!3g?Q#4{L z30nKndfe^u9`H}C3Q-gJp0y^>u;7edFR-#a6J$-*f;Rw*2E1E0QW>JCAA>b~UMRNu z!2JeUldL`2BxA6WS!K1_sn9gP}3eJ)w|+IDFjo?y+gN2A+RejicUAU>ro)Zh)8=-45QNPnM-RBL zTMtN2h7QpMhJ(+~>H&9sJzxv+Ne5K>Aj3XK571VJhQ(q4Tkd$T?PI?p zk)2fh@iDgOm=VUHX*B^R5Yxs$Ij;#UHBwVZne1)af?O=2yx*ScH}cr{e0Tl?HFm+S z@|+s09&~xtTz!+x=Cy|>RKpG32d-qe(W9&i^{c9`C0hT z;!(+|(LnPNrU1JP`2wF^@8;Sc`~~g%^-FwYMSG4|1tI0Kqi_=Cw&x7~$$ynnuqbKS) zw1W(&J-pw@`;}K`*Fd>>J$ha_TWd3{zQMMN^bK|CLZ~5{x&1I}9dze=-=mK-t<9!0 zqnXQC3Qn%jmf7J9D(-UDj~3kbtY$z{!)YqGJewM_kEXB>rVlgr!9t^Vq5gm-ww*9u zZy5eMa_0bsjHRU4sWNpobLa07AY{~$COv(~20l;Fsj6k&_FPQ6h4fcok2PCGad$D| zUj~3!I)t?f?kqIesII&nr0OwF62XJz4UKwG8Mu;R7UPtlEaP(z*X15=$~_p)k{GJ3 z6;zEHR&4<2(pp&QIFmArhiav;ekNL`bRBjzL2juYF(^{x67mYlrt2C_#Hu)%GAd#=Dmj$2Vy!T1SuK?h;CP50c5mlx4TY z3BMt(%V;a}y%|bY-IJQ@%u_%~aX1;FX4T~MSF8ECLp{+xk!rt>-}+9pXsv zw$R1Kpp@G&HUP>9+lO7=1&!Dr?wcnRhuyUWOK&5etc|EuJKdpKnya0QP5S7~G?O^w zzCHS#`5XQ;&zPy_PS4Xo89a_3II5+N{e)JQUot|pG1SB`ixAI{^$&Gy4f+xf7S zD$Iu=d^pp7SWXmHZ)NTSYr4_(ym+av@9$!Nc`olETJ&xhw9mX7X~C4tt!J#|I5T?v z5t`Yu&z5_;I}O*nflj}xm3wC70lo%Nbl>tSU|>LHurUE{@vf#VSB?CJ9Nulf8l?%2 zBd-91Ckofob=EU4DUi0T$z9&rhwSU}-UoaspeRdxVmq`sVPfJ*Vei>wBk8GV6z^zKRfxCf^kUUd>Z4zBjD+938h z`jf-?*an9--Nn@=xBrB{futXmC5R`}$&JV(pP+y2m7D$t+pLIgu3!YuNq%HT1`GOs zHR-nhkLSi;7T!RMpZ?#mwHyBb-OqR-%)=9*jZZtrn@_@=cfbAggw%m}x z9bv_`9OZC4Y}mk!(B08b={1X_o6Eh^c8gpmPmnTJ?!C5apS(yC=h@db^GamNmxLIT z<7tv0mNNR#Jjf>fACr_o&tZG6^U$1p&YX73zH*!xhSth_a3nkcnsHL%3fPCtu1ycW ziCj6ucTC>aPgKY<{lqup*lGbm;u_e^VN8--et>bI;>n$F!pCj(UhsMhJ1YZ~p~KS_ zPAV_T%2~zO)iR^|W#9~VqX7DeEp&}@yxHZ2{7Ms^yQ}1!lfELVjl{QU0HMw#);_A` z56YDO)5DY(ayS8g4>P1Iabh}Bq+(&49T9yKs~xBLbXGL^ zf}}uE0*h8>Uw?k+WBNxeCf}6tTMfSvl$_1>T6y*%=DFZt^^MmGNOYz4D%k=?NSJkZ+|`D7$`ICT-lp}; zvC-!OMP}T@f!;0U`?`GVZgSpWocVhQu*M=kZ|2YK8rV|b{|6W_;+Q)xF*}-Ryw2ZW z>yR!{>Ft5P$IJ#rx~g`zKm^$JsoFaf1GYrQG!nb_fW6<_`V!xe$5Lf*XAFyjkl`)) zK+^-qb*FU&?@jnLMw{@d9M^-q8$SR;=aZvyjdH5{mTceYW5jT%G-!Ndmr^kq`cq^^v4Qu+7`w zi>1+b42^516%}nu_6`*4tI^D~Hj=yfn@Bg=QRxl(rx9wsebN@+?(F7!zolNwx8Lu{ z-z<-wdb@W7sDTtKugtmt4&t-zYZ`oJf3a|X*6uInr;%s9$tK?>Q2oN#QX%i3U~i44 zpUh1#KzvWN_m{N-?1F zutIr;nePT35IUT(03NZ8-SGHv*%!b=u*^;amOj4n6H8+HzD_PnV(=t$6|9 zb$N%8uk$&B{%-je%{V&Fs<3e z(q6@No6_H@WRo=HZjHNMlgkZUABG72;?D1^_wlrIZlL+7Sh}g2LylHMN;kB7-(kpb z=F>tr_Cx}^!h;%WBZR6*{TFrWG^D!+{+fK>Nnh1k6j-#PbLZUR#NU%2lr-NSuE(&N z_!e6rH5a6-c57D2)dzPEY+dxdKQvg^gIC)5;>^B)73!S?#Xs5e$P-(3@KYOB?=q+>x9Rj<$5i-j^ z-0i(s>Th<6r!PXyj+T%`W^*~oh{=|FdkljzlPw*osE=?e{+=S|e(jf~FDuQI9v(tj zd*CVrl3)vA$?k+L-nKq9mlf>FHx9_kl8p^v_ zpi&zewBh#NO+ejCz>A-o7|pvDmF7S`!+SliEQCk@vht15KInK7znc3}Z$PKYZ;6f;Q?L8doT~bD)j( zjit2NzOERr>m#{m?zoVDH$`Rqt=wUyH$Y6%Bcsn{HVxlvT5LV-oy#nyyY zYz-wh6epI4UJ$>Jt@t3cYeje<2bMXP$++w1IuBfgpiVaoSg|#^ffy!@ym4_yNi?t^ zo<1(lg0v)36Hmiz{Ox3ED%`LF44T~bCU;ez(gFU6Tcu?Mm$NU_mJRV}`x#H)S{ccF zlVDu9=|C-9^)f7?OUWJ*0vF)|$f|Kn8Xxf$-s8knTuL&_ayFPapIgJfp)r?ZuDiGu zn&njI<)4{y``*)(!+o?2N|_r71=d6cZiv+Ha#9{NQaI`2nTl3w$BJMkpXV+}en^YQ zlkM?9;&);Be{{}rW{+b+MFXkjiDSTD7+sEQp+Q)9$hL51M5QzPu+;KqFEa4M2*=uW zFf1$B$J*Zq_SrKTI111LJQr)?ZpEDJV{j}%%jmwUEK@aKort;(3s_M{OPVWZilzbT zuB8KeB_pMQWTc!;X#{>WJRT(ZRDkQD?$t$Zq#|327`f5e z+O{L=oYJ<#`C3`s=<=c+&UpJ9b%wUp&tbL?b&{_EEZAO+<2+Dl5iz9l zoMkvz)XV2{78yMLUvZXgKq9X%{crfo7cz?fpZH6-e$|ApY0LZ;($)lM+o!GLDD=6sb^JTswDk@&#hy_1P-TV5#3AqQX#K`d(j*=8G8u7f3=)>cI0xpmklIIQof+1wJ&muj* za*?R7)TAdOvl|v!~tca#3X{UGMH)u~G3lTh)x&HDm*^&)$%GSn@lif$a07_GtI>IBri!WS+8eQoiQYs%_M_*>jh>Zy1%O+ut9*TrE4yVpkCa-G*9>+T~7a z7!(joUp$_jt8ucKu!S`#+LRtUxheDgHYTgrvCY^S+nwoB1lc?;FLGMtuNzCgWLEG_ z>gT*^OZyg_n+G9xbVrx4f?nUneze;@nGna?D*lBEOr))8Ej%a>hU%@_9HvODh^_P2T3^K6kE5B>mJqKm+YT9+ zE_z*TqZzrBy^)N0_-jpM^m+EcUy?)&rF*0G&`hvRPJ2m`&~!8Bu^G9ZWP0ngDlzJg zsBKE$hCcTJibm%!;M%xzexP{(*s5k_qp?VBe{Q8w+lNSP4+lOPbQO9^{RfFD?ke{! zJEueGTg+VEO!?x(^F&$uXG!y+^;gwaB(zxx1((WBi{UeW^RU%_oZ082PTU*7Kj|oq zn`mk{ShcS!)6u?Sb1I;@a}W^bmg#KVjJk!MBgN-cfBw0RX(E99dfcq1F?Q~pHiP5< z&WiPaQ-)|d*}~7nGwB%`jI~@s&rvB8F1o+>!$Y-3=Ba0iNlTR5o*+nV#eCkjOeWgQc&&-!RzUrd&&)LpcVnxHMo-~pr9q3p5w|N(lqs&VaOuQOi#RM7c4Sl#Vhx*X=4^2@${5v$S?&m4Ykge@e;T+3p@mT zsk$fXKxFogYegvTp*`&;&Nu~^H@RD3WTheZjVAZ?&h!28JRZ<#qe=468SE040fL5P z(C?Uc-qhDcHwpt#!N0+YU=N$&Hc^lngdoV)`t3Uhm~q)vd`dp&&d3w@?Q+Z`_BQCu6Ue3Xv!Hkwqwai;~OX}xJtJZ#K!`t3NWL6F_ z#c2JiNo%4R^w3AS0}Po_?#*99qse(#ZMZu*`y6jRKBLLW_^1DxW0T$;H-6gH`7=M= zxUfTi>ejxf`-Y)=?HhO(oGyR9$!zgyuDH4*#e4Q9mc?eeo8A0^@pB?r2Y}L(k=0|b z>sqV&cAF!l3wqT0@oA=37>A&!TJfi5pO9^baX0x@i(eRa*tsRI?-f+1(+H-AkK4M~ zyfAfjS9CiSnJtT4JzHncD_jA(@x@V~!O{Bd69*7&P-f~Oh@D9|^emf*UqR{0xdr!- zT7Jy#gwFry7{bRwVK=eF+*iG(Wrkj`_4=V+@y*g|;XnInxX$!Bnr>L48ng@}`M z&Sn9=r?+K*b}Z75xo68ec<^|$2iTm{{N{T}=E(ahMYp71{yA7h6V zeitu=C5ena5oKyWu}%};+zEt5+&f2aS^+;s)6kE17YdO+W4(;-S{V;~=$*_~6A+lf zW&_8|BKq4_KBsw1Ect0b@N3otjU_h)yv>X%R=iD~vATR*XFBryrscbVzRg>>8>u+zUQw4E+ZdSH zmn;SHQ4^9G&AhsfQC^w-!^@bP^W_zGc75y4%eXYXjdFl_pN_@-bTkQ9a+QlH2EG4(0vLB>7biAG=@Y&k}tITC?$ZOb$od+BwdXXAhE>?p8Q*g;z>% znEpC9q}|s%zYyVYc>N>WDE4Av<9mJHMBd?Ba*f#3}*z&~`#9yHdrBJXEg{Fy`v8~wMC|71o!cToOs z{hR#L4$5EuZ}MMpQ2svuCjZF?<$r7QzwZC8 z(4w*#$&bEW>^S8s>ym9a8h?uiLxws&>U>_4d7H(H2W(1DL$mrt83wFrtH6M zea`F=)!vCpLK*YxO+1c|!X&T5Q&@1DA+t8SHCS)0&^we39~ zbxmse=D~?0j1STVZv6a*!=oGy(lFF-A(^nnUa^7FJpu11D=;YFq<*MenUOawg_zj)bvGcp zzUEQ|jOjjtq4Vvld=nhbQ+chJMvZ*#CnJgy90KKpm$ncdr%iI;JNMq*j9=ac$$2&1 zS7-}g60k**B>FP{O4rMUDe>j4?WgyyQ1QJNfpu5s^O^^Sf6dmY4Sk8PcwQcdiSb5N zo>o$@x%;yHnm7_>hGuoObsdlgjq39{vqp{^fO_xgg`WLno^KHCd_6D!`DEpLd!c@- z{mEY2l4k@GWr`*2$AdYb1!_Ef8^`nk{jcb)79x@?ZHa{8ql%+|gb2Iu+XZD{QM&Yg zRski=7x1ZuPto+TbF?3Pj^(@fq(sxFM$>iPp1I(`yiP9nHkp?x<=zK+(7C}*ZQ&I?3F{by104>+b$?X{84L#6keeW>yN$b;ng@A$nE)cHur{)Bg5{z^aZU;ur4=IaYa*mWfTOp^X%^HurvACHfj2Qq&;M^(Kbq2(#ibTl*NCadmL(iFpUWZh=rg;&Oo1VAzM6ov-eq^~VGns{^QHEbGrTZo3CW(rT<&h4MjDF}KbI@z_T8Y< zHl`}hH0@pDx3}&c5_wjxWfJ&M*pwnEot?}ZqAdS@w%LhQ{V zw>(5TnqOdbTPO0l!9NY9b;r}9OkX7n`3=K|{bfi&1th zW=Cq)2dt<$0EVu${Bx_f?Iqh|kKfL}+kRR57AH5fOb#W%g%+UZRajdekU z8Ifu;fS4Tc-V|vYe;O+%&_WzmVHo7T_HsE#_M2-v&+_L-%bu$e7lx)E8h7{Uq5|jH z3kgXwCBSBLRm+|en%9!vokk2JEkQ#IdLc1tG>+UtA#{xyMx*vaCt;tsHh{EGT!>WO zun4KVQ#gQEhS6`9k`Nt2AStz08VF54zpHb4em;1ou7_n)v*FDJFwz*gJP%?MQs>X6 zLR3rDMSwtG6Lr3zY=J%sB;>udmjO-!uk7YnIJfK>lo-{rXH?>>P_iumR3c7fj#bY3 zlJ^V&V|BFt%?T@mJ5kiGYIJ_QAh3;6%`Y2%PMFP5pY{+3_L^re;F3Xd4v;(|0)JOH z6WSGO*{Pa%Bx4KR$RZ>w`!C2?#&%^F(d z{cDKC;20_YHlO2eXLLwsG>Myf>i32arUbkt;;vFVw7q71nY3~{S;?8I>X_RWub)H9 z32s-t0I+WiWbW8Si2l-v8`RZx5Ke?!rW1Ey-i*jws*Z~+Y8yEK51Wg-HWrzYyG9u! zb7tHw?w6jpt)a$gm7}rJJ3s8^4)%>sAV_AW|b z{!^SN;pkcefSlFX!ijR_n zY4~}0Q{W$i%<~TlV%Lq@g?Fk}wMS3o90*2Yv~g@faFd&8PG@)!3>>4@Ml{SYTwCYu zf0kX;S*B2+xmWbzXkZMh1{J`&^Crx96mC?)q;w>#mukIC)>DnaFHG?|?09wI^sS9j zXa$zt+>Zn^7@&3k;mO@KiH*tKeG>o7jQfNQ+llW+(+#x^gTn5ujU5qIHiE@HoITu8 zT2wT(MqvbYYh|tW`ObP9S(v?_B-38QC@y#+XTz0F>nh~~Ru4ZfJmGU+=vO$-`+@8z zq77!yD6-DJ+O*Z-trA`}Yu;jg3#$@~by8c)c*($B@3J!w18pxFo!!K(w2%Yq85SKO z_tnmCYu*z`uO>0Uds-YiT@<_i4P#v2Svrn0bJaA)_tUs{+&-P|w6;;Z<>w+Oir`cc zNSDr>UUI%O`0o)YY?|Z+6{}La%3um7| z29Vb7RqkqUAva6XSSC^&cfwxLqFD0XlGu=Uz5b$92^=hatAR?cl$X&5ms64R;zM>g zsSw}rxQgz=U3HE#?a$QB#WT_5-u*W4RGh&>Uw0OVUKC<=9HR3!X(1zv<{3^;3M-hO zq9!3|CI*rRPH<8~0A2FHRUCW;BHF!uoL|jLnAQA%xA%@cU9s!u$1)YYoY}!x{VVQ{ zNgXYFPjFgqreLV$?p}eboz`o4Hf6kXSPwE_c#U^0H$*`|uvYI<9<%pj{qw$ukH4t+ zJp0i*hu`38GZ+1^7K;*&KS%J!!$R4`+H(!G?>S^mGY39%O0s+YdN+%@Sb13*xDgtd zk=+G<^7%pokrHK+l7E+_XRXi(9cAGUDc=b{5i{)YDwPT=oD3+72(@?*9By7D1udTh zguKH{ORVs=Aa`QU?2etK=Ruw4P_RVwxt~?0? z^GS3}9Z5f{j@(@vElM;>#^!AEoWkLhQC(L;$Cxyk(+}D>E7UnIHl!U{sr2z(OTYd# zs&1{6WDygB@n!q7@oeRmyz|1&vtJgNTYpcUm;m@JW6?p%t$BUZ%w?1jU0gep)XufG zywbA+K%tNCxSB9RzbV~ZXCiy<@_zpuV-SN9+j5?*Y}pG{oW}q$BbJAJt{6&2B&hG^ zNEi48#qx&*i>-^IOH=z6r1NRD@nX=QUD_U>ajg$J85;Z}+SHG*t28m`(Frn*NU&6kc zuK&2@?y|0{V{SXw`Z6xfx8={Q>pE{i>2OH@(%SJ&+9A8!-~h%Rr~8^|c0{1jjFX5? z1pH*@EKWW^=e_pUUd6Q#8KkI9wcgEdmQY|hcstMH9)<>J!h^yCI0ExCN)h=qdz|Ej zt`EcF!X5_H>b)l(AiB+(^Q80w2Z1AJw85(~BY*Hxc~QiD-xx_PSLWbYm}63Ku>Yja z?6byQ!ImkdjESmavrzo26gOqbeiqp+z^=M^PgnLH3W~SE)?kApddc^MEda7mS%i(n z%#qJfI_kIA`Im0~Vv0Ol)hoMquh@i`$Ir|lAhYaW;4|JIR?)Rnsm;jKSo)&sNc#Ln zs(hIEA@u8ce(0&+HG%bEmH3Ttp*Xns(99QvPxzaK@X`Ec&AF)V-ko32J99|g^qe-n zWZSr$A0KXcke#VklJq*4_h&ZmDFyw>jTn%XDEp-*yJSkPXWlX227r4RsIY(UUxh!5 zffgcuFuc|LYciQYveSY>dn+^i0gqVv4%^$JI)J> zBgfpY))9>_Q6Eh|V5~2hBd@6xtv8@0p=v^5RWbMdFw>)2o|J8JWCmkzl2GX#VQ$5o zmpk`M&+7q1ZY5Mk`&K<%Z4AKO`k^^}WR@2-(eyO6i-f3Bf8Z#INw{IH#w=7n=gz*& zA>Y&@w-vf_AT*1)X!WdE`hmw(CR0T$KL}3IF7HJ7`)-Z*v!Ms=Y@Eu3t!iDKxg-#B zBAa5Pequ)JuDJ7gj9SMj2wxvXDQuxWnUrgCt3IuVBuGtQD`TMcUNvzMoav8}HI_CN zS;>p#YMwene4aOy5-a)RW8_KvN$9N(rT^<;-hiR++nmPK_8(BJoa-l_*_65QCMou> z!BRTANFF@%BL`!=l-Q%$}gL=?p{Pt`uguUJ~; zKTb4H(m$Y!I$k6-_1vgu1;NXdUAG!;&e(<}dUFcnG16OJn5oaOWL2F0n^94Kj5N6H zw-k$bzm1R}(P`pk;0T{r?;~}-Eqs@E)n5QEah2mkw!xbunOMA3d#y?~>cf+2z*iq? zyv<@V#?m1+j4tq?K1+T05fAJpS1>%pg-#rgi?g&FW@b>FO6i+f@NoLa`^kTTKM{)j zYzK2B?i1ZyoH^uCqE5h-zA0#DMn0xDcWcWHwYPs7=S~flIaZ>nD2jw1n2i_EVwG<1 z7W||jAe70&|ES}~rrkHaAJZVFOH%ASC_ad z@S&i9dMUps()Z01CUZoG4aVPPG#in|n@`1iQ(VIM7p4KT4H@^5^VBJ3vO2BTi+^`S z490y8LhY!%timAY^^qIkruWUY8>ef$S8h;$c6p@}^t;X=Y>jskZ`mfueTH}Ca>?BF z*=AD*WP<>OiER+I)p-9cyb5z!9Y!(p{hk^qtK6GF#R6-#nrgb`mxi-@>n^KGkzel~ z?}qNPo2cXNT)&LY8L(@;YuS%Xop5af2U8=V!T#`P zGer|WkGjdnRFnIpdW{2{=^VNiAIzh_)8K!|gxhw-3DYNck_QRch3O^B_Gd?g!Z81i zNTYsjtj|5kcA`}))+Zy;#)J1d*fA>dK4s3_TBB2d5lp9By(j)dlikb$MJ~bZccb^u z6U{V`DL|+HTQ^U>hz^S9BQx04A&*fn5gVuMHezG`?q!=3Bj)o0)vfOpLVi0%I~&Ck^7> z;Cik-TxsLu;t5T5o!D6Gq!XDUt}bd{v4y(0a^jQ3lUyc%qqFu4!u1Kc5I$-e9?SL| zZc$ZBJ4%63@rl43 zOyxz{bp|tttlQbFZtUSF$~msQpJ*>U06J-`V&LNJc8aLx&fkE4wdUQ(-PqQR<_89c zo!`sh?_hjItq~544JKNx_*|VgeYg0WGrihJ)L;!JkElD8YH3~g5?)Z3IgJDJ%^|NU z=Y-o2{P6*5SQT6?G5d~zpisvxR+~G|EX3Q|9Nx;kkuVnUcBWP>;B6>)s}$Z|Pn^!| zVt4fOakew@rx1s-!cOFd+A3XRRV8?odkcPNwp^-0^}RX#LKox{US%D1f!77;W7m3T zu49zRQAN$S*v(ZCsZ$1oQx~zWHx>eh%d>|=HCT)mU@<>G{-=1W1aBrfXJ%yJZ{2$M zJ&R$kRBf`*4FgnH~f9)>ZNMVEZ>@|{shOd4uzH4%*w#w4O+{r6^ zD^`idR|oa@_{QgAjlnlK{6cIqF*Lq2ahDamur*^=9`j8J;SgN1BF zaPnJ-Xj%Op;}Wg-I^S0Bf!`W(y|X~!n+sYjaeVDpkO}0n{nv&_Y-pZ>x%|JTlaD}B zj(^LJTdB^}Nf%+`XqOi=M=Q`7Tl97zXG`3<**gq@G}>W!mun&z%ANH~(J-qDi0isP zcJq$XjvVi}kdl@lbZRq44`wsj+%l7kC&jvM`m0*kX(kCy>@aKH7X^6eml#RR1KhvS z+j*&6aYqigL#{(sIogWNrOPY^Hh3qiQ<<_lRfnTjBm0jSac5Ukf%PKm1-!c{>om4m zW=mSyk6BGi{{-MbJ_$rp+?w3)lzWfdh&7*hA@<%6Hm%0P!e#tRr)t}%BHdW!5{@SS zhRTwA2{}JLAEpPJz+)8t7fP4b8nVSU`bMca-B%afY*}7TJ+X8>*lCqnx(QosCD*=6 zW%NSYKbhOv;LH1v^p&GyEM+Vq8?18lq=CUOfrp8bBY~~qL3h_ygzC3CsWDUt5$BJL zhtngHfkmMeTd1ix@n_L6TQr1xR6fX^1628Tvt?z9Men7K>{P13Se} z$^=;FJu!|*0CUVynpPw1GiAS63}!&-O+d^%+-@F#%5^zt**V_&xH61tmB#KQ-vLU| zbmlRoA^cOfmh-@3J!+hTj>X*iW0T*9esEE`u@cvy32cW{wMEmdreLOGspuUVn}Vh) zO1sV|@$R9-OUlLaAF?Os(AcfnV}?lM;Cg$t_uOCPQtM3rwL0QA27%yUk05wlUGNf+ zqFf#f2PK_y%E31%N|t z^#)Uyc2vgbw3hen%d~u$fHJ`bu@as*N^Db0ha$GOjHP2L)$7wA$!k{W)9F(I%jjPJ zse_f!)!>42$<^q;l(NT?hj^Kx{-NZ~LAPKdC$AOgp@zMNY&a~4t7#+>u4oint8rVzG?=ULNAI*PNyip>8(J${)cr;&t zd+8Sjn8QN#gcrDf5#L3c)KNhdT%$&3i!$T8I*){j*Wy@E5ztWTx3QT~MqZBHG-*4) zU8rO89>?ZmnbKtUQT;`bQAG?kSkuIi6+m@YQ+ntQ!$qPiHuTwRPV1Xfgei}v%)YEP zY-5?`e{+6j;Hra9>tjLEY5jWlfZ_xcHwS||RUg|ufoU7jabB?N&n^LhA!lV6A*)s|0NzCe{Wj zIKF>Ir(^6Yo3$FzrRsxqprG|fw5+Jm9JEU(%8Kl&igO+GC`L{g4;M{oxx^nTl;V>a z@dkyEC=Dw#jLPRlL7Xn#wR~Wu{77*A;ct1s@HD&9a*u_R%dHbS$qx6oG;HsTz69+U z3l;qw>>q8V;wb0&{l(SsK0n64!c3rboa^5h&J5)!9&4{=FEsGou$yH&C*p4T|EPNx z@TjV*|35+}A9&;NP;d6YSq zefDMTwbxpE-F6PE0C=y=*MJrz%F-{ZL3vP9k$TcTkX6|#9{)v3_*0zpAhzhwE!5!F zXG6`;uyFisI&S%F)8{SciTUR95-4mjj7q@=SvWb;)o$r4-$RRS5B$r8`sL4~#g?{a zet`|b^r0?~r!NFXX4f)RE$ZK1U7!!Vcg?&LYzInG!2BqkWjRNRlWsu(E``$^U#W}Oz|MdfonM=- z4w%hs#AW!-)h#wPUkDeidWm%NsRioFm~?zQO6(Fe6c3fO@_+?67Ph*6I$5imRKl}+ z427+VRwP%#w8}Fx=^e|yeA?++!{s8AHttZ?R>v7mj zx{q8_)E4BfJc{2Jf;%gfCnF;6h!Uo>QV%>S$*#pW8Tvu9b=E#_w(M_@*-HKwCE3}P zlLTTheFS*rHVFh^zL&u;HJi-zhq~Fyty+if+nL|UnuZ*+G4l}0Cx3dazU&#{e5Q!m zjiCl8#|ex|E6HuYzs-|l)* zrK0Jf8y&L6WPZnM(AJ|VPTTvaLN}QeAQ@CP-rh}E^!QQ#@#B#cXJv}QNNe~x)d>fY zI5Izk9w@y{SqIo(vcduDc=kN{*(HRFPjl2_6P9)a=hafLR9Q0qkEx zs}IoX!aqlug_Z#K+(y}&$_IuP52eyvi&=dD+=xYhmxZ{foQf3#?eYtbo;T=H2V#7*V`` zW~|s#udnE6&y#d%9u!nTk-P7)g+k50R0%gJvkIH~G4L#V-k7VS<$C``hEjG$Tz*H^ zaF-Z@bnm$z*h>_ey(eVsB^%P-Q)EVUIiAbt zOZMqie#nCd2a~@z=i!i%9B%&cBr;ID?Ir#7jLCV?{aSrTkAU#6k=w;<}#skV!7P}TO=Z?zypYH$5RZywwVhSLZR+rje zG%t?ppgd&!1DaN9&`R^UHj_ru&8sjJ{JChC-ooi>jRDH$_;^laL_$)MDB=RJM zOrCi}H*Q@4brJ2OkfAPnu65l&ZC7$jVczD^OJcbd^k!GSM0zpM4r1K zJoV7*V5iCnPs7~J!R_~m0Pa^)-ju_D)TSI709lYLk4hALUD zX8b}hpU%tU!%58wn`wU`r2z>@6;gg3*B0RIX7HLX*e}w~5dxW$P81vWM^^g3XZZwo zonnkE{<-UXyDpG9H02!(==Pmez~JqBuN{uU;C*lN1~f^~GW}ojS~VZM$c3V<4owry z)eVnaJgTLja>oQdvDA=Q>N-184@|cfn`T?1urD8Xa>gs!st!bCCF*ozEkj&N_$}tQ zl;2W*%lR$mm%a08F?XUqt8A~Sw9{?p&cmpl{qgfNGx>8qHWZAd9^1l?4g9+Z5-2AU z;51JUuA-=&^+sNp^Y?2^1|{tkKwagwk79l zV#}q*L5hd=a_~A$iq>+%!?j^2?E%3@OV;r)nm-O`HJ8|J zQ5n|mdrHIxow7AxoVJUNq2?7L)pmJxVX)R3Up1+y_E=KSg9D-Fbt+5fKr0Ub6fPeq zJ@4Y7=?6i2zM7|Ih^T38m&&vOV(C8S5U3+$}}7_3(p zPjS_{bD{T?9n77JyvtH9?QmSD+$7=hUaL<-32dvfb3|E#E;VtKkJ~`ymjaLm-GfpM zRI5OV2I{;Nlxm>DO94_tIlpv<4%sfQHm6XzWd3TSv|>)`*^(x@U|#WWT6MFWn;bT@ ze2Rc#*9{&#!m=I=+`}7-Bdn!-^7SgVR5Q?E5d|@$TG)nz(0g*;Wj=VjKAO*IhCHTU zp6iiCkBmZFEL|WmC9|Cw4Dhw#Y@*T31>Be)&@T@#3!zy8Ov_dkqQQaYXMglH3z=8- ztb0C5Db9TUh+0flR|VhpDu~|*;MG9aTx!<5N&H_=VCIglP8D=@YK=r%+tJVd;CD2e zG>hyu957{W;+rq|1KH3>#q&nJxJcG)G^H7y!i>LEpMtrihSvu^tCuo4fUj`I80v$1 zfC-a(1iX3l&U(Xhllu75M3pnh+5i@R?PhOZpLEmc~O*#u+{qXb!Ui2eXgh{ zh?QNOSAqnvRf+YHualuiDS%g->8ra4{&4V6OKzRj?Rj_3t$+U-7iV7NB!u|$vRrK>3f{$b@ zLH1V>Ntt%ebmJ{gc~NlFN^!j@&mP4hXx7(|kX3;yj8UOG@6~Eej`%n)ktLKGFLw04 z?lz1uDC5Isp%ojG4vyd$w;VjlE1<0TFh>H&XWN=*5eK-+OjCd4 z+TLyk`Zdd(!5*a`R<$qDPMTJQJA~QEe%v)FcTHx2r9d0Wj1GtUlwdw{+#*cf!By&j z6IjWBb`F1`A={OCpnYkdd=4|6%Gx9 z=#Q4X$rmyA;gT)-k|{C#>QC1@y-Uz=$re3=II01AI6@=!VU4cXm_4Ek-|9(*uj2#G zi8RfISMTKfsba+iKa9EtUcCjQet9&1^gwb_O@CE|nH4WsiLVkbEU0THsu2Brs9ERE z%FxvyL(sk2KXWr)JFEHj##<~Fjh~hP>ZI-|nXg|~&J=!a_t)rxKlOW|ej(ip?EO6@ zi|qY9UZQ#4KhAy3-R-&PawHar;`4AqSv;QFTv7@e3vgFKqhk4w`U}v;`{lHd&9-JX zv9bIoyhf|qG;gI&XjGeXUMHXr-T8nTKRpjzmsYuw1ZU34c`$+~DAZezF$rY{aGvIz zcHKqYccQX->X5W(`k@kAbk26YTIy8-=503Ln`^D5F96G!`*}U|59(1Fy0evXk*2R7 zV(lM^V>6?u#^aNU)ldvqClN4;SBh2bPGmVIQwq3fpxr@SDv!?TBvAkSnER{;Ghiif zgy!8WEILo`Lh~kCjKUMu9uVrJpYTAF_7-vsEN$f*^F``_$mjeMG(=QmaEp5^lGW=h zzb7p2X-+xz%$UbC(a9iKss%k9h8k))%`)UXmQuAPjTIX$o}+hv$CI5OwBAT70#$#T zy-hR4vbvaf%c^zp;aZ$8&LKFQM05uNp}XRs7$rosTc!xz0AY&73&zP|r2N@0q-Lt6 z-zrusSpyLDlrQ{QL(G?xsd5RWWkgR4Sh zJr48OO#Zcv@^AUAjlJ;6YRAivRk5ng_Dk=nmiszB)t|0K7WAj1*nGGu5Sqx$!ADbiSQlx5CDE*lI(t9dhebn~Vft29SBoYW+(RLuU zK;*+*fH4TM;?L~AO3h2R`?Bs8bVjqMefxOQa0)*je^xTn*it=bhty#%!q+4-1Af=N zKg*GQ`B~@Tn39={7y?pNYj95bSt|^{XT!S1Edk-+k6te`&BJ^A z63)2;A1GEE=0tPF!+R}?ipge-#V}uX{_}HRbY>1%O~05S-a2Y+0iVfgpLUAP97uBJ zZn|T+W<7)l{uBSE50m@1s7FX%cu}#j1#a&$I!O585p9KdX3Bv>%$-);C3(r;=2#wP zuB0dCm%qX>>ua_L@XE2v#Js_DT#-Q#_iEq?_hRj_o9xXmQ zvcsqk((LSdGjla7rssZB@i=aWvO9b+E(x5viPH=kkgoA7H-U*6PMnip!(EhZ>> zjH!q{n9kjae_-OS7+K$0!`7_oFf_JZ#D&B>>n0^>pH z8G^Hc(pF`&UR_ffFy}%=e8HgeDT~YZ)Qrf1O#ajO-%B&=bzQw~xrjmMoRA||A}CkW zYun>c%UQh3Q6N8{{f!>*5Dh%mS0)sjJE@t)I3e@;ZT`6&=o`9pDXKTsr>gH#!8mkZ zE9W7HMlM%6zV0&J@9(znM}O&k^25Z3*-!CP=JVUyQitBKO3Xa) z_X$@#5V?HU9;H7;{}e$XpM9`Ld)!C(2uhGm$`7P1ySnFi#x9fpg}cwweJz`9mv=nM zsy+fBptZ{i?`Q}rR2`hHpQbRZL4WL63)-8CxYKjTov%Q2_x@5U>^k?#{C=S_)O6j; zKQB&d#cYYkZxyb8oENDd`pNS77xxW{1H(k22k~PFbW8lr>YomNllZ8;uL#D91-MSc z&$3A;o7E-di%9MbhJMmU#pEvR_rjMx-0Xkoq_soGD+no>zPHc&Lcjb;`S{*$r;Hfu zzs_kBgYg0Zy7W>L&p`#2Jdi)TU&lNRH3%O~jgf|sBS2cMdBw~<8-?D)KMPP!DkZQu z>1T@h=_+vzB?K1e*N^5|H#<=<^E1rxOW**Vxx8yV%mygl2>x>>4jF!PkWE%$=#I^N zLdpe_(K>0Y;+vzLc zW;*o~Kd(s#&xTS{naD*gF;%tc>wA&o!G2wYxth01j60}egRT9RyS>&Z?cLvw{xo?| zdg%q^gQ`v6)amwhh)rEj0@&7I%XW8Y5~b9<*=5;v*s6bjK|1*7=)~=*DdE%wVRvd6 zg>oca2a)+`{qC0SvmPZ62i>dKaACUSNxRGf@8p`CEt^Maj(!mD)CF$>CBCAi3(OJD zKdDWXX=_>#N{aKP`w&tOY|kDkD4I z$M?Pc;uFF5CNfh@VB^#e_C4Z|Na!ANUi~dJ_dQJyW*i-Ut+Ut^p5L2acogni9N5vD zya$wwp_7|_V{*?$v#*mk&EkAc_p18a^Z^S(i`OOh7ANlaY(e=>RW|W4d6pg^P4IbY zVcrCgDyK1x2_7L^Te)#W|4_@dTKU$N#P@%j@v%MTwpJ>)PIDt{*IsTl-;uI} z_XD!^-SkG^(I{ET7Ux6ucarSoWA*IRIuB%-jnEU0hdjowPnNZ4`gwtoC#JvZln_$u zDiETFdW5-&Cg&9c^+09_9rXQjGKbDMSpRGFF%aKz?kk+x`Wd-r(Pb0^Lc>9;67mpp z;y0uo*ZgS#px@YGCh3*jyg#*S?9JwL`T;*Y0cHWh7Mgo$k!}?t@~W;J!jLZu5n1{i zBqV~tFb908fM;S^(}f?xuPFQ(eT!8ImmW?xTwEajYQ8VY&-Z=X&ICz%IB%yoq&?8| zzj>5;(nC9S8v$8eks$R5U;6M^ng@onqpyWwFSrSXjVfF|t6D*|UNG7*c4*{{iodEt zKW&8MQ-==xlGDzdmFiM%fI!{H6XmdK{5oGqFexzC=rd?RLCb~&E$lGw(+4ln)t~I{ z#4Ux${|Wf)FxMxPpJq$;R}i~*ZkLPir@465KRk#`B>b~*%FN;l?$ndt677>XRR=I7 zu5psjYyR^RS3AjN-qrXe*YKbR4^Qr%HEVdcslwcdJm;jJw3ImgjDB>4)g?Tw4R90= zsZs;$CamAxWtYed=M{X?qwRsEs-DbE$Q;dFY2}YDicP#UoVv6yl6IEP*)vB4=B4>J zlH7Y}XkOC03d~AGI$HA+H`k^vDyVB&+xWfIj9^Pg<8`U?TRI!RQ+LDK@L_p*lRHL4 zC$>2gJ2*ebnb>~Ao|~9a>V3uu>`Z?@AJew;GCU#XZK0AUgM4~%GrxfzY#{xy_ME_;E$hwbF33uc6{^3IBE*w_V!n7uMaIN zIit4n{rDN?w^N16*wBj>Ru$bJ|Eh6*U>|e@#}_1ypFpU;uQH`)5NFaPgqB@?dS3I! z#M11$6Dqunj+-BAtEr3K;yg`%8XsbT7k=Lx4BY9$`RjsZoVYMK+bY=hUAYvU~qq-WJ+H)2^n!3XK7oyh~og=~_7Xo`awaoB#5Q#v#O!4l5D zMj`~B_8@F7u-Zh}nbj(AKT@mpu)4n0IE+*62zH<}9oaFw2p?Syh3NP0Y zp}P*}Dw;enJTyX*1OmAujaRrR{#^LVDz{Q$EO*Hl*&B0I@MwRgqVf zZAVpo&3jL5FQ8f3*gc1KtW6rh{Fo#e_3MXlTeXHBhg?2-99nj1prf`SKsKa#EFaB~ zojX9mXXJ;6lBi@s)1K2qcgVf0Y0r>ZiKad0hFYX=07?pCCVjNCJaY*((2rbK3j`pS zh|3OlhlQDdXQrc{(8j$FUwb9dx8zEGibycdFYqC?W$v|AHmiv|Ft;Ex+CFH~z3|P; zH}SM~YU7aUcKMd{(Bd;R;$kQ5>9TYa#-B-QA~a@N@iZ@6%j4abk9J?Sc3&>)zI?d* za-n}2YCao&OU(%5N1|j{j@nB?x$>M@#H{4leH?+QCr7kwKT!GB~N=ThbU}Y?qgSj%owHB zp~YnEd8)RK`hxM_$I>UiQ#BMG)J+efsiB-hx!HUMIbvB6esP4Ybro5O_7{?mGkx+6 zd{SM$-NVaV`ITMemv)!$Ys=qqwk@AMLE{iHtGo$Un5y=8sd!^@WjMKiFb5RzS-ss# zZk8%A?$?LuX!?toe$u_qq#CE~!=Mu|IHMMHrksLQbz$PLz?#XeBZLN){#nCHJ0rdz zT{Jwj_*B7yybGZg1vLxJvBUvca}CNnTMgoUsCh1&$V**W!pv#?vb+jwC)3V|`iY&f zGJIGd=Te=z1Et0W{`m0c2(4XK9zIG_IMA*ZLGdurjPp9TeBK*##Po7>xk9az?y<$UZvXe+HEOC0Pq)Oix6)NjRZTG01N|Mf4>`l$F~K z$tV9t*?VN%qgU2qtXPod`_y{bTT%BF&0kBkZKR3OSuD?pp80&=Nfk2O3eetxMqMZx z74V4$QA(&DF%`Y7O+->!Yen&Kko%j|m&sDeqy=cV1$0_*^ZAY;=r*&;wm|>=aasEe z<9e?9`LKJY6VJw^zJ*@XE{&D|IE$WM(`V&kmSit?&B4;KlOEg4O33L*AvOh-&0N=G zJahIpf^sv?waCa>TJAPy$%@ZQFTZQ~=cP{DwqDMz_v}wPc=zNNNEH%nQn-jywkjPg z6V_)3Iq8-kYqgxWn!0E7pR?VHwvSpIi`Zi@GCLrj7>7jS2qkfk1RgBsexZ5W0X!qH zAX!URc{-L{bq!Ea(aaJ)Bi(G(xt@H{{5qwR`;Q9UrDQ2mIXL`QY-k#OI;u0~Z}RpL zxOup*?0PfsdBv)9?EsHFms0Av<6E-d*tMOg+1dAtE4F(Q4pH<6uU$*nYTH0;43Y-;m4&+E9bL*wipc zh!$UEF28|KVNK0bC?(P{UbGrGHL8lT2b6J8JmOErI_ Ve`*LwArYH!k0@j3v7oGpTd-`XXtkzcpsF$rHdRls z#GE?GpB#tfv5@kr=6Y<{H|l}biylnjL7e}m=%I+H9wNzkrqrBAk?vdVOFtJ9_iOz7 z1^VTFoql1lwdxdVSor{ORqF9G5JCICGBeGB0U2pk=&8cXI#v}VVoe_g$t%g{e)2>L zCjRRAf*`I$lAq&xu-Tj|>z1%cF<6_;7>rgTf5na)$h1L}a`K%lN~sYg<`BPpsgJIm z=1oBr36XxS2rWA^eW9iPr$_86jB;q#u2#|i__3fAr!y1%-cjpF01!R$>13qoeD)eI z(^-I48+HHcISFJ2LG(O6ywBe+pnnT3%kQWi83-mg$MNJBDkKr)_H*Lz(&K%A@yZgt zdG<&LIJYMcM3xa%3DrOO)ze|m>C>+uBs+Uz4|xLq9!(7d3yN z@qrz+)*okJqLFSrH+X1XE_+-P9R__8U;}Yzuxs9G_7fvc3S%0zmb&`+ZELi%EnD)TPOmtOtX5Y2OLeuLg%kPw96(poUT$Zw4Ik(<5o zzRO{X8t?S0x@M?igPF{STA!ye{#-ve#%BO1ALqy~cRd=WWNTq#2iv&%~}3;`hQ zfv+j4^#P{vDI6v;MD~lMR{4$I=rx)jn)?sE@Tl{Ml8O!9XXazxYp!!mm(`ZUGjhuV zXl#7CKFGcIJ}cXXX!DC!3J;{81Jl8m7<69Qn!xfKHb}7`z}`*GnOW3CqsGRs;kwLSgLS0LuQdpx|+6=E6Y)%e1*8KpS5C|+@-@I8YHr6zqPU;-)2YKaih-(;V-oMLB z=JBHaK;F`42||OOR>QW$;Xm<8C?-pBX&u$22!+4rZkOt+)KmGIrhDIvsKpx_nU2T???CG2{W}u9Ta@Dqh1&yAR@9WEwyT3?mGn3}pV>I5y{-iFNQJ6WH zYcl$#Zbd1y+6;R@*7}-)q*EHqC=p7Ip4#$&ve0aZ@3$s`>`z6ny!r5}Yro!Bm-tiW zQ&t7)t!{cM*aN8icpqjF_9|T$snuzC2HwE4!)DBSxnC%`c_0DMZ5IL)be2pLqqTsh zQ@ti+KepdXpQyRVoKKALCQ7761>Mn{^*734M2-EmlP`8cwPfiXU7V^ZWnbrVL0<`qn|_kK}So)$sAyg5Tz0Sx8Lbr#LS)vNYZ=xn+NHO~4&l%9%7rV*xEj zxiu^748NfGw#&N5$N3)}tAiw*N%y`5sjBH^a*5YeQ-7Yz$sn4O?M)wrIWH2{szfy4 zw9Rvt8y`(2w;V{W=|w}?d(ltXCbNrj@NXY&vD6-!!!&8m|^oBuPZYn$(ecmW}Ft$0m8&H-3Yc% zELwo_zH`eY{QWu-)No@-N!#|LlOJ;I#r8yBp)m4T6tV>2;0zmu8APtkgaB9$57Hy6 z)$p^LIvUQlcydXt`#ExqYH7n#~Dd-b}9K*h)*IQl$4zSZ#$ zdi1(Q=^jE)jT{U`Zf!ZoGLC^NDNa$Wilg?AW6~fO|b*OoS?bl_X}}IyrAAH7q1%*^Y&ttDyolWX^fjvx2s( z$#Ol1nRq>^)VUG5)@h}-Bjs{4MHs<9SVKS=ZA|Nj!gaJ`;6TYnivuk;+Mcs}Bk56b z=BKQp-2SCr1Uz)-FL)#(9!lTKl}BzfKkO=}{xK;GqTFoxLQ8jMIiYKn=6&6`b=6-w zze#y+kYDh6Bk9yppcLC1x;eA5Vgqm^A$GC(*6ZGC7z8*}JwM(2gYf((#WQpCnp&Rf zd9S6B!+i4!>xu$ldYdcX1uv;F@vmvLex~!~Q-p|xKox3U&I|R*)5eMNq%S9!4uXn&)vt9xKdaM)ke7YQR&ta>b`Ko;af5+qYfptJi zX8D@pP_y=LPU?z+Oug-Np6!G=8}XEZY_-pt=pP*%SIt-|z195&X`ZDosq+Mqrzj^> zY_Q_77D6pZsW(`wb$JSvC z3NeWv?Cngx*p)yy1B!H-*4uCvXyJ-CnH9D|;nJ|RtNVHhu=NGp7C+E&e4klJk<{pc z9V^4}V>(s_BpD@+>R8z;aT(h8#5qkL>>$d|ic;0UcXp+D{$l2mINZsw#EvxP*9r_dhBH< zupZ~7P@PLsFRYjq8)J5ZNrIYKJ~iM4g>`FplvBr6OkU8l8+ZRXIAK_gJ96rLZcd@=rha^Df5d3(VvQn9za%R%XjgGX^_6+aju z4>I6!)RCxOb zELhiYu1xYE_b^})A4JZo}1CUQ2>~4PA+tPS2 zw!KjY7Io8|NV+DFk+Iy}%;ew_7|@9=gGSig+pL+wtGk^JOJ~3*7^f8tbHXJy5IrOP z?Sx$l+m*oC^{l6*#KU9Gv(WkSwu(%9cR$AZbTAz}oKq0i8z@BRu}w|@ZB-M4&l?3o z96Fkw71UL}oj5#-ms>Qsrzo*i9;1x6uIz36YVzVcXAN-Ms$Q7-l)G-%I_n(Stk3cH z3}j7@^^-e)oND`mr+q44NMQHIqcpj@D6y@)HMg$_EnZ%>M)GgBKURg!Xa5p<05pB_ zw8UgrfFC>r)CxYPbrCp)_u&f3`B>O>i~)NXTqkwNrPm)=agk2hTwRq3)x6}sz%n&T z!J|wYthg0U*-O#DU(A4q#RIm-%RTK5CRFGuZj-yraHtmCA+h*h&4~7=;6>;~tX53U zL55&&9<-lXayo!vM}zzc&D&34BEtz!VwW0ZyBTf|mQ4B1#K|<`XKP52Pj7r@(`|vy zA&C<*kMMCfK$~tmx)bGl4HRMyFQlbMh{;5JVGjM@H{R>SSs5WW@Jq7=m6`45K-iG^CZ$97fwl$w?Tl13UvR08*679@Jtj+ZC zn|NKjJH<3P^c><^@BY2c-EE~lam4h{Q=@VLe$^8j7JDCk)ycnH%pawL4KErp);nPF zDAHwX*K`o6@aBW$kTJ3rV%($vzH)tiy@MR|KO4u6F5F2U-UU}US~_xjgs8b$Ud8(9kAsi0R%lkICCgtmtR2YNLKZCue7ULqK-3X`4)c6m}z@E zyEc9JD{8y&5HAEM4@x$f0`c;%0w@INy+?-T%~b`dd95e&lP==0u)Rg0xo_#KWg@Kj zy)Lq^o?pXHv}}_-UEw2abBOt-UrlG{nDi6psfhKc+-gPvs4?khhuN-n5&%BjXE49*qXzPrp9(CY9&g2*@nQ=B2-Wd}hia|Dg zc@UEzKNX$J^ke!1Iz}%mOY=~kc-e+N9y{Qq;$7=;3L@6Bkm`t4Z^j7{k12o!dLlb*SMKnwIyD)!MV9w?_rpW0*TdpGSD@( zqN0cpsOw26fQi9;7m2i`6-h!mTZ{*<^wtm(VRG`ELcch@tL}5PnrklcBRen{MKQ58 zk*a!B0Cd(}6KaXjRL{QnL-hLMwkr`{^Bk%t6&YKH8C<#R-1Ufs#kt=9^B0*uRBE{f zX$>;#kmhUEH0loayQCJwufi(J$tJd@K0gs&qFE&yyZN z2XQgvjrFFs-_HLas~@;{j=T-#y~v>c4L;7iup1vAreTYZ*-H;X#oN_1js5(m3Ju{?zWege8f+Z|G7Tudblp6vrgq6igPi)wf94)pA6^+&A8?DDc_XX)jkI2ZpCK2Gg(b|Cxn?9b9 zz7XAmR{rotE1gz;Svs|=h7}}i)+%BFH9yae@82&4xuSGZVo@OeQ`RbLAmOb6#~rj< zxDT&eC7}HC8pxpCu(%MKt1yCpg%3x>x>2pl4yQX~UY}?Wd{8*h|A-HRz^4EI;=?ik z*aIIP;9q8L1R( zd0*HREK%aR@gU8Y>RXokYzxEgS>La7FWPw_OM>b|v}^el^=JRsEx(glNU}DfiMQT8 z`S^e&KTAU7Q2E)i(oU}IeGO;Ld5>LYyYE*VrJ87fIS7Q3v-sp zVRf?AdS`Cc3YG+bDu}N=|LB(OOQk??(n|)?nNTh1faWheS>oZM`*{#^mn`7Ny`E?^ zxsTpg2{lMRvxX8TWv~0!jg!&(y{>IX5xOZc8reJS8S~a+EA22;r2QF%nC?)d$8CFe zbI|+;jhBi~p(Mo)^V?F{6nNWiuC#AE8_!3ngHq(W0u#d=fuMax)IH8h^y70o59wKW}2;BeSHgo_gW9qdee)k?%W%rV6KTcbw)c;;q& zIMPv<7f5_Hxes5!7?Z%TIOU59dyEW)1+xenr&?3RLB^JMM~AnxQf}Hy(R3YfWve=>(y_^*CA1WK@=y)iVao=d6ZS>ZPYM^4)dlE& zmzyI2qZX)VqyRWRG(xxUfg*53^kRM-g0L3QD5r1|hriZtAMLhnS)uL9W^)@J*TU2J zDxJzj=WljWjBi|!&qQ_18Te z+#0<|4_Jne1ZZUX-0DH^3`)40e8^U8SpSLn7{#i_Q=~fo8G7y21**HfT0NuDmu0J}HpkteH|ixLg~jIzEo$#01s`ujwqU|^aDJKaHw)OU?c0QgaY-ym-Iwpmpv67+ukJ7>0)Kr^$ z8||isXWA_c4YlBt0dVZD<_zs>>Oys2*tTOgOpH{QMdg znP=Oo}E4eKl*^ARhXl^s(RF_B`?ok`1Ls7lUs`*EDs$F;%Xw(ze z>3f&&t=t5u2uftJ+lvhn%u)S>`}gEB@bmc^H1kGd|us6j&5K)b{}RF zN^3^8p64Z$w%etVU<`o8hv!D(D#k-1zD>5i%H%#ou{hj-lH%zaf zZY-`v(e!UOOilC?d-%WDFV&}mUpaWY)Wx6w&3?)MqQ`dWjW2DNv|Cy|J<=r^C(b@d zDt7*9m!tu*OH%)HyQGVlItiz;W&6PJq+*=|UhD2)1))#|Y}3kgfEnvqlJN&f#vhq! z=Q9H~QKTf}kIY2f!(yeCHLI(b00d)w?m9Jl^}{Dq1DMB*F%wTLNBQiJS{>U*x1xWF`uZ)&qHT4khR>Wu$#@AX`TSW z=1gG*>03F84J6?(L~}$Yd}` zTbg`XC+ZU?gHYG$uH!g?b^j^aH-m$q{fwvo9m@CmdN;~Xr%wl?{AcG96AfdiRZjiT zypt&)q__B9$1-ichAFj60PKgZ{U6Xh)bgH%>Hh)ctN*{lcW-d5)4=$lN9c%?{QnKc z*Z079p}MfXjwD7c9|N8YgdA~UN9(6f=+xFvL*MFs*iSuGj{UW&oHmHm&`>f=aeOy) zNWkS>f^Iq_ARA=khI{8GGj2rpWUXapQRdhaWDlzS@dv%y?QhT8|C@gJwd>e)bddji z1i?Rsceikz-@-nyPV4o0@LXI|DvVcl=TsQ~id9O5AqzMvj5EE}NAe&>Q_U(OIT;kg zUxnQ&3~%*i=J1smLA80{dn~W?uro)alXjQq)GQ}WfQRtD)I2?mo^n-b9^=YxTQWhm z#mPN=CG|_*)nA;AqL*$k3JIyVNpj!zGS875>4RQ&lf^dBl)1Erf6IJ%n&%i(LFNjo zH0jGYulgY~mmja8pE7(alcgItA$(kMc7p|wM32lHnmH?`FlZuaCt|1b!rYx*e`h1n zH#AR45=J6mSe8iPGfybGXKq%Q)<*Mvt{vfp2x7WqU{42hslkNlxWCqX+ zPYxx4cNI&Ooksl89Qjm2%1!1(|M9(|qQdsfa6s&h;z6Wa^QUidQYu6|lVmFa!1vZ# z4tBOqFl1_4EfeU+B{( zGZHLpb3S&UUT6&-`1U#cJX>OuEug$dE6}}3)O96zuRmQ^=dKCikbxgI-_e(y7Z{3b zA>zFR&NQ(hcCGlL`z$;-CBxiGgJe=965%2k*l4i+8*D(AhwfNpzk0|M#L^8P$Jmn`Yhb&fZllxiHWA}Z z(W!!#J>9vAFKuW-EYxznDi)5W0;ffSZiJpSmrSukKvvXEgMVY++;3|oJSLhRT^vo_ zSKz-KNDs6bwObu)vI{d}IE^Fl>CmJPIEq1F>)s=giPId=()EwJyBcv!4ASoE!{*4x zJofk<9(R9a{^EV1hS)aAvZQb5oQ^VOb8Lp+2we0?x{Wiq;WVg@ica%qS5t5iy`F(x zU}h2fSZs2i#>)O~7Ln?{rBz3t7l-Eer^=Z7_n6M<#=zZaj``4=!!;Uv>RAgNQ&*v- z3ImL$p4VpFa`t33QbTo--HtbZ;C=N8V~(bu(oWwVa7a%ckj0Ie3s8p-L%R_dxG0T* z>&6mt(!3sZKc04TG&Rq~#ywi`;ud_Ru$z79B|syB1AAj<>W^Mw|RnT48F%WG)`!Y0F~#c45K!+#FO_gu1{& zIT6LsT8Yl|&{|o9NflH%vbwPg@$Rb&wZcF3Te_;}EZ3*53!8IGL;zW$mVl&Z1S>YA z0{M|bo7y+DCPF$4vv{+IZAUUld9j@`3!(sr4|7hqwTf#XvnCNf%mfIBVoZoucJ@r4 zPO?SQJtRapKbIAO^2d9!*$J#NMUbNCaFm@hi*eP&KPOCC)S{cz+&MJI>?M|F?iMhi z<>R#=t`e626s?eYo+D}=`D^&t^rFvXQqr;#nv~PJ+4NnppwX;dTpAwV!Yi}yqurjZ zRt|@m59x01Mxw#BCw6v%=g#n?>cU(-bv1!$f;8lk3ISvzW8gU5(?A!FiT4||O@^9( z!$&zi)qQ?@!xndO1?>hV7XeDX3z2QrE9P~fMAAn zS7KMCttCXdNs(ULu9FHbC$Spwvx(sV;1x(h9#)1)T^(%}!Fm3;X22 zGV~1V@izY+)~TLR<>7mBRiZUyp>>+`{hH;Uq8hqtpVPjDM`rekyX>7H8<87f5m} zq_b#i{s2_6d{}$J=T+O{6SaTu>DUl#;XC{`(C5i@Bk^^#kuOmQ z2MhF&_=6#NurG((qL4&z>qCF=vEYeVK{3?3H2yPbTXC|;qlWx=Fp|2-$C-Ie)Lm5? zYIy`NYQ)lB;}AU?|_#W3+<*vaD5iTcrbGXP1LNO}*ji#Ow z6PLKVNFTdzgH>UPOasj#j@ALN^Ut-?lvluv{f+ilxzduXzQL1jNlZD@&mZiIZz%2m zL6g3yRTNF%95yG}`VdCkV-5I2+6 zg@Md$Z-2J+92OH(CZ~e|G4_fBv}H~Yn}fbKC&}y|!}I+XuZBf>JpWM7KjgVO)OZSg zW^7aR>(86{F`0>5Hs0c9p7%?Av*+6cZ!^EWaMh z2sDgg!r$KV)bCoTw`-Xt-jwRmeUoA=&E@9KlO=Mi74LJtO{~7YxZf{bD^e4w6krHzr-FDLFP5;I@dFDr~21MBY99^*$Z^z6De7Ha-wuMbc z0osN1c^9eJF{i%QnJaRjgk+Fb4$kF;%VhPa+a7M?eLv@5jk)t_52e9tGcI@1Q%=JH z6USfk(ng&G-FTssy4Su>Ke<4~p!@H?BeU*ilN})$iRi-o;Zmc%bGeXD$9FZ57=m*& zQ%A0@?NtU2Nl;y}!2CXXkpHDTQpsv^Ku)R9rb!LZCWJF)R$>xF2*B72H&|k%@1-{< z0qYVJ5!IxyR&uWu<~MZHMskt5)bo?J%7iTOzrNdV`YEsDa{aBQq5T*APYr!!2SdL`v=jT&^M5@=1i=EW*bSLuf`W|&Zuq+%< zDf}EzH8`oHow)oU#)Cf#2B{ybWfJc`{Y`$^z?)oZ7M6wq`Hig^I zD`6~4b)N>w?@tOg!se1)s3tq|E{qSI?)G&{=P|ZN9 z;Xw(JD1dm|n}B%ENlHWFX+=${h z?(dMGfoR}lFquHV>SUR&7R6##Qbw&_~O`C1IbLeGjXkx z+|zHyS|?r8i(R>sj`z-s4-GB*3Tb3c$ew2D2dOn(8#kbr+>nFm;@)}98{&n@ZPY-3 zz}|k--;N@!a14AN>N3zo|HvfhgSmA{n3n{D<%|IY& zsX(zVH2_(WCe+(*4odbLURO!4fzeFRH#{bpJHxh*Rgu(-b%Y*z1ySd`z$V| z`xl%kg>OwcEfXi#nZuj*ngZ4}XgS&8Z6$BVi|;A=_OXnmh7%&GOB*ApyP9k(qyqqV z$v7%Z+JA$c+NvH{)H#-@y2h_*syp8hU9e~5k-MSC&b@oRORLm)wIv0n`gqTsevLkB zucI~p+(l;h;E>hoJTtbo%MYigf3^o-+zsv7Z(lcqPTfsrBdkZsm3ZJ=YT2ZEb&pXN zET3=%q^%Aan1f0;)$IOK{#hq=N!U50kh)-aj?XZshUa{SqbQ&0OP*WKl4b&-JdJOVM4mLX`i?Sd^ogtY{C4o zBlzhzf9!d&{A-bl3d#R5=Ic?UUb;MHlrC72V=mMMLeH2>B3u-^W3D6>T&$#Ik~`+= z?2mo=l*6|I|K7T3iw!5gE5{UKSxAAl!?eskfFhjybA(e?v?@+P00LadKap~)w`Mz> zXZDZGL4C8gUOjzqhwz&OkmH>6?}Tk2IqdW=sD>?_pn)RhR@{~tfzZ5NngGjm*-yRZ zQ7pqVs2P-oIkAbE&6L-LKAU6dnFS_3jBEHT;6=c5#2vpe?u$-)iZVn;)ao05^=kUL zY9}0m(y(HpS5m{xfKp8q=f&7}V%Gysgky-C2?u0otA@Thyk?DP#l0HYjkSJX{7|yw zE^o^m-@GOcfZ2~hl>nq3~cMU1XGfRJuFaPpvxlg~+i4l?kUmGhT=q|^@6c^&x zr;qmGZ+;rt+qqOs1sW*exa)eZiv`qrIJH86C0%S7ef!p5nPBQ6k7#vq^^y1F({mgmJFl7BYpuCeK5dPpVf zMnjnXtyH4(_B?KXJS~DJrOKS=$F=0}tyHW#|2XyQ=&#zTFC*U}<88XN*N{+)(iW2; z95fGrVP9j!lz#92TLki?RvO4pJK86pk9WS6&}|1Ua;T##!K1e zBwKr}-n*sfC`$@2?~66<6rqI34p1d#ho^CB3lNvp8&7$c#NVsemur0 z)tI6BXkCieFd*3f3NJKcJ=CQKJr`!1r^pybmH88hrvbU{KY4fOh``aUWW*q(?H!ti!2GNC2t8z(wjxIZaK16sH*e__TPylN{NS*(K&NAz zoU%5H51WrxI3QHN-#$a@|3}^tOK9stQ3I0 zl#G${Ssn-MZ1Uow1M4q>-P}&hn(zng z`I3A{z5dLn&PKKR>&#hDz~0xX`hS{pJK>?`_3TB(!jTJbi4jg7P&xutLOT1yl|?$y#2aaPpR5*fVQOEV77p4)>yRedu3G@UzC6Iy(6DVf+vOL$~~yW2gm>%Fo!)_+1?rENiXUE7x4W$UWi$uLQ2>EL@HJvHBkqnnTKJCv^k zV_*Xdst2COKxuuW;lW(H^V3!5aDC&|o&)DeAf*<=4ilZ|J&_lZU}gggi;d1Y2jRuw znxz^A6N}B?&JZSsnm^=$Kwla~RU5K#zflgzkfJMW8ikPha}Mhu5s1Lil!2&HwS3Me=o`D=%HY{mhL=_u6BimVRyVVE@q zlqed2W1br4eS!g8k- z2(q{@F;wk|sQmX;d%c`P88ii*g3nsP$ESvW;4S?6IW1^YUG!dO=4?s{D1JV)hXz~F zw8+CNW6yt051V#McLg_6LH4=s^{1fDsOy~{`Z>J)HOGB9CKaKQb5}!hK0E*4QndH2 zSar-EyU80RN?uI(uBn1ji?t}r6Sxy~`{=h6|7`2Bq^*_M{1Go&VW7I3a!Z~?p85UB z+IM_nNwq2DI3Vcs%Q^V;?C)!1>1mV$vTe+6Lkx>q6Ch;Cl*TV*!&{}U!?s}X2Shaw z-Yd}utp_B;wPupXps(hcoxJHU?6%ID&}N%4%^sFy@weVeKN8v{aWUI0BBKl=o&mcc z@t2qYxXV^Eq~7!S%svJ3d-E$O!NE6~BVjMFyR;Cr9M2Vtsg+T;s6-gcedcE7*v6aJ zk#EYTT_Qf&eI1uxrUp4)g556KFEm?^1nJMaiSkxl9w}8`V(obp1QC}=u0)oWUic1*j%<2%xVHL3;;4>CV~nyYl98*MhwG~$E!(vh&kH$* zK#569I*C}U-GY+;an3%i-N{rJx|17g-Ct?IweFvr_;G7+ZtcB*HOO!+3g&F2G>4A@@sbe3qQTjOw9v)x|eRMh*;kL~64T%PA$ zPH|E~G6lVp-J=IzTVTeVjeN&rOIUim>A`=y&s$;FW>ceWh+prNeah;Hr6%h*?YI+5 z4M!7t2%1}yGTN2)YAa`O)Mk7@PFY}XJ3NPaiIp1um*rjC z9jL;}VqLvR{KY$4!_#m2&|cBCaHK|& zcEm=lnnkF(xWu4l}_q7?JY6S zh)@-)b*GHD_sz0Ymzv*rQ1mqSR?Sp}#R8%lntP~S?2ulogWF^j-!JAQqpzevme}Pb zWaNvNls>Hk7#I}Qn$I{+P{sbDmQd+Yf_7~&j%f=weZAPrOXlFf%wg`@bI_Q!$~|lO zqhHHhTMJnm(d5jO^_ZGSc*#;NXgc?h#CM(a)UH~lUQW`ja9-mHoHRB-PA@SaNxsO@ z+I#9t!fr~j43U?QrSol{cUT_63eb`!FJq6DB!Ee(_v41s!;U@?cBi4Tdzg8qUG0@$ zUhQ4;;k!SIg9nC!1ss6p0iqJjjANTLNCWeH(We1vF-!(qro3{o&6SD2o z8W6t0XH3Hw|EN}E5_1+eng}eqX2vM{!aTpvt_w_!q2_bJC;1_Ccc+z;KioR@%T6+}nJrFkYMbs*ztDO{xz~@>w7oF0rLnV z8_aUx+2>%k$)Au*oFe(FhyDS=CzSbz6mvGcjj&UA(|D+8I!>*i#qG>s({Pr<5A9Ue zga4Z}nPG3fQ8@bJ!*-&L!CwlsipYDM9^41|t#x;UeZ;oA-s;XnkL^T%ew-6PHsj1? zYapaPls3ruR(c^~4-`WTHg~pqDm>v)y>+=`%uSVa2M;L-LN%MH8|k%ee22M+mgqz@ z|9nf=S&=Ku#>4c?sE8AIGn)TxRw9RuTk;C{zD?ZSCbQa(80t<(;t%o}gYx7#uR1FX zexz-zNl_onhcmjd`5%SnUznY9Jsdh4m|xgSCTp_L1nS)xVZ~Dk^#X#cCQBV}83X!6 zQ+-FS4wj3bBoE3FW74OSVAVq7pyw)f5K**g;WBT53LYLkmFusi0jcv%oP21IXVDb> zb=%Xd{lWU{GWk|1eq1ayDZEUMLLTq9Fg^GrQbt z6+e-a0;jFwh;K;Xp;X4+ZT}acxeI}|nQ&SUdvf2ZO2Il$U(%R2;HlNuLJRD z|3V1H$X*q#zTvN`Z7SRJ^|AcJICB=#a(L6;1MwSX&2HKYzF?3f=jfjN>BL3f639!G z@zd)-;zWM(I}^vY_mvu9Nsxc2yNMsxhDV=s{tx=@K!WIqJ^3@nw)aK#mbXOzlPdB|;*b3FdOq=pcYdx7FR}cEr+JCr@G?Iy@r(Ap z>WkMQuOH$#2W&nyoVhT?K#t*bh2}Fz8Piy(Lu&2zb23qwH7N^pb^y6*PSs zR_2Pe+0di~O?!`@K0rsIR_%<}Xr@qOb~f#uo%qQ8YjW$p>ZZAio-x=67QGlkjLcNKvbu7T`c(Yc&-nk1>jsAI z?vlcLo~PMH;NHN1TOZ8G#JxZ_R+Hh^BmQG{1qdIkGz$vAc7&Gnu<-SLArWm8o>v$+ zfLwjbUSD76%Ri{^hyu-HwN%T0s6obkzz5S5z{stI7Ei7|Xa-Qo@O+?FvN?_x*yXf% z{!FYwyRFptQez8K(+X0z2F>p%gKPnN8OuqEUUH4{YQKvw0EZ6^v*hHQkpHrk-%_*3SF~c^iT5`B>0Eowcq-=vXvU( zFJD^^#St4#1WD@}QDCO$Nx{&b?ME8%6*_L$iFl|O0fytDtuS$xQ`y_(7c#$PwqU@w zyvA5o3}7sk;HBu3A54{_z+}7-J>&U7ei{|6h!|b?#taTr|JRzkJKt5cjdmT=cTb+8 zjj6ODNvpuTB88D8BP}+HKxaJp1%IF#eV)3t!JMlLIR;g5;pZnuQO01GT?HJh2F%-K z7ns8|m%b0g4|yr^^Hc!OGY@L89;6~CK0stVoO?5mqC5ucdh0yncG=W8PSS!s>JDO) zVU=1drO`J~(=zpr^Tzv3Qt@6eLJse92r zPkGN9x}X2K8@kfZ?8=lLc(+TRY}ebo@IFvHV4d+feH?b1;7P>>jw*@|*6k#2LHEmm zet34@JU=RLlTBv$kKcsuYh$rjwj~b1`0U$lDS23t=4sQ@;wcj-b@%eneXV8dLd#ld z>*x*1_j+^mhr7<3H*3PqKJWRPy+*H4DZB_W;BUA#{sSjtSLyR^|1SMh({zEx?^zyNyaAq#i&QX27WlPkB~T-bSn{4= zpY*+cx* z4Gn)@Y{AU&)?ui5kw%Tafn9@KJrGhz=I4&rDhc~KurB#Z^;G&@DqJe7nR>PQtJX>| zKMQWE#B@p!B6^?Yu!#i%oJd=C?t-RU1Cv56cTf&PJlm7oxw2@Hxr;0CP4;Zo1hbYI z!xK^4;}}aO#SQX{*;p(*uA{d9hp%^mkGm@K|C45tOj2Ot3Rqc{uvTm<)|66c6fkMi zb_S9*G%cVmw$o&q%r==BGBa%|7mG=tvvIVp?5?*(R`;UouGZhKh@zMRQZAx}s-TFZ zu);S4Xo1~c5a|E?dCr+hiu?NK^~#**obUOb>vNv-+|K!WJf6fbGR^-veg3Z?^L#M? zwBQaQ`QkK1hw+jcxt_UJ`|iC$?ah6VGi#>OWFtJIb*x5HaXGV)y9^#$Yx!bsx8cy; z@I6h_B*@_(9yg^oCtAT1IDz4#)sdS%ZP;|$KfeWBw%zfr<4+kKWeV*JPA>+{N9|*0 zqq@%$Vx+qrMx;>q5DK%%$TbwuI(+>}+zW5!x5Be`2%&=gmkSS;%vHghn$?buKI(-t zF>SfIF44Q{xtN@GEIm1Y?T(?!`ux@%Loi4gp^&ft2iVm>!FO;L^XOMpH|Gh4`zpZin4Y;(JVF0m4;YaXlREGw@nf2+u~M(Eun2zh_6k4TP) z9=2*79k~l+q21aKSx&sZ_t9Er`j1v*3*{}jKZ5>F?B$|yHF?MbmRamriX(aOPx;j z7Ap!85WM&gQWOD6%lwieqvO}FkWkV>(O#y0HrV?|+X{2{F0g86lmWNcw$70&GS>UdS|}CdOuS+L&}ng`s&wmx4rLzdr;| zzr#L}^ZYcawSCU%BHb0TvNjGs-^WA*zv6s8WO9+o*@$(|2Cul3*;o{{vVX~^o+-Z1 zF&oqR7h|=i{!s4UO#9%kpeG_G8z~Rh-yq|PME`tum@j&dzK}n?e4fgE@#=1D;V~i-pXBPV}k;!(6Rk(gm1rnj7V^;nQe%tBm%wLo% zOC>!aUvQ17vk^L`?kDq@wqTi?YLr*(x6Z)9lp6mmhq%)0a*vUl<-H^|3Jm(1xNK(h zg|a)QCpV~$$*l`u>mr+AVnql;+2p&A6#OF9VYmDA) zBpRbP^&ehNa17ur<@9g)boCbz2yiv9&{TlGk2yw-Z;_(wm&c2XZIfK8O$350VvXwNtS!Z&Ggr`E8 zjC^u-S;Tv%;KP&AQLP;$>QC?&9BA;ZB^bL6k8UqTfyYZQ1vdqccn#GXY)#RkuLW5& z(_Z|M`ywSJkaKD9SX$$PpY_fdTvX{6H%uoS;`DiiBc00KA}6C3K};UgC@4I6Iz#Wq z+jay7cS{|D*FmO`9V9aHRoY-`?jjkX(r<)?$M>4^9?bA)56`JjOkxzd6@MZ%1lL?j z5lj8+f3}@!^!L1uBX^i>II_03f<>>*iD7z2d@PIpZpg;9{-{zXy4WPs0~b;&r8>qe1Opj{?p|Z z`NLoB$>2XUlOUJ72c9eOaSJ;4A%F^my>|Z*Y)wC7Wt_zd;Ep zL&PX(Y~Oinb((jv$%fB11ujvwUZh&F>Q+8xO%2{(YQ@MW#1@%<+ksk5(sMsKjdrn; zet6oe?pr77`qJR>e`R2Snu3RcRQLUa9Pas(OB!AM#U<;lyeESLU$^Dj!Gu>c;R`xv zO!%ms+NQAQDa`nb5*;osnSWw?7SNu_E!JA`jm0I$Y8+DC;L0C}6`qhKB-bPQYh-uw zyD&2)d_hXQ@6PJffsl;yEdkR zPc{ar7eS9Ptlu*bwDI8#pHI0e?=R&$qm4Vo$(MiZ_5;isT*?mcwnF*Yh#R9EIFA-;+X|=CIRl}U={Sm6#-W+gi zz)o^+4XqwK@45Eo|IKYI8=Spid~T`2&y$Z$a_NeZ<2gPmR?QcqNq4>(=`mT%3?g3(ddi~+S8kL(hFeBEM8OrngtIIi9vZ& z#uljMJ<;3$NLeQofc*^X9W)bv65o_9G$lG_ZO|x<{uUIT8ZOg6s#zAIn*aU;=q;-7 zX8pIfUrVHi(L&uqpKPLx^DL7H0dq=^8U+NEwpeHmlo_M@Q}3Z6lI#ODxrArJ5AGqJ z;o|VR9SP>XOSvS=y5gB&CYuE^M0jnUH!rqS1W!jweC`1e{+pjW;CY@$ zPO!I@mwxv>Dwq}jSLB?=H#^N{C%~B1n~bwzsq65_hz5xdDMXvGBNv5^*$@KkZ-V)J zK`c5pYI)_C)%@7D-$aYo4FwZ(L4~m&e}k++h*}s;(EH%Wu9`eNX(9;pHgemlp~!8Q z4-HRL4nI{ne_#GIEKr$f^O}t5|E~=riP%?G^hHtf&yYWGBbC}!{!I84|I4jZBiZ1b zAIt-i$5;cGaciN;x6mi*)QaS&|FsW|<%VL@eO$iiap(hArZi)*`}%Q9@`H<=MMUeCdmEjr8tofEs?&b!-Sm8Trs4|{lKrf9i^K;ZZ z{P8)EKP+oB(B%{2??4+d1>0W`(KfeEc(>?q0Izh;`d|cMeJ?9uVOC^;bnyak$M{$M`7uU-?ue}=Sq2fnd52cZs}h+?_e5nrJV=) z|5?wJHo;nxQPZ8l0kxxnDwcW$P751@NaT-> z*V?TK!9QhL8#mmedOUe?>nl3;J*y4o@TIT9c@DYxwJl31#{+XZ(l4Bw&t~{~k-^))dL`~xEG0gunyW{ZD*K=oEC6Uo?hDd7+BB-r$ zc<)fK2|Xqan2ho$_|-{lKNkZzZ#QARtP5<*pLXJ)jN;c|pMEdSy&wi;s=aXUwzKTK zjNLW%Z16dEej(2wOzU&Z-J@R!zu@CiU0f)9^+{Wmh)I$!*K-XhE!Sy3%w3v3qiS6I zyvfV&gWCLV*5=IS2lz#vo64tH{c#6EC#$QDT51#!9i=j$W2}DNfl!a?WiG=;z`vKS zv9P=kkk3B~%y?goUBQ>brG3;WRQuDVee_A&e>BrL_P%0b7c)NR|Kc)&!;aqJPa_mU zNxA}N0+PUe1t1+L#nwJF6hy4!L#Sa%EfFJG`KQ;fv9NqWuCzZ$WgJ{VSKNbN*m%od z?-jdyo)$IHtM8lw-Lkr8QmqsDohT^OVE)V+`+s}U~Mor6xa&#_C@*-sMp`b{K;Op6}7vp#@hh z@p17k!(A>xpO9^^9LrpSX50u#ut*7empAHZdA+&y^$W*#U>^XD+HGsRQrkHw^9vmg zq*^a73s|ZW1hkZZsDNO{lT?6A++?P0@r$?oNM;-SfJe`v*^%$J&AqTK@_o)IN50QZ z+xmiJgA!X>5C3$QV)GPh7qlQUdIJ(!>+m1=_{T#)_TI(Z3|bj{K}Z4-9QjvtiYkdE zyI02>Dt{k5&-CLPI}d`0m+pm}ug949R`PX>9(GmdE~Yk)sQwv=r1Z>P7K8Fu2FpsN z{)XCA>OAQe(b-b!-?>s7D>$r1lUgDp57J>Zc7YYT`pyp$$5+N*baMKHwa{ERKT2^p zr$*;LA)n32h(0X~BUl+cEKF5570^mAd-y!+c}?=ARy+ zY4==t0$*3!zf|=H3%R-HumPI-v@v+QtB+mr96rjYwo5{Yd>;Z~gO#M>SYg~$vzk8$ zoAMyPw-?aREf!}m_9J7vf`^2Y8iRXiyV!inn2eI6RDW;>T*sp0lP_6X3+EqQT;IkO z|7!?wlN;{H$TO7U&bg@96T-*B9z%y%A!45k54P}rY_FWf{Mpk=u|#Eh8q9v2m(YvP ziFsYbkGai@ln(_j{gx-iCC6WZOuJQBa=^NPGADmP3*}#w&brygcomlntD?eheI?e6;33{J^=t5TAbWMu{gY=} zB|B7tThG7twh<@V!S%G`E9vwc!M}+ID=zup&#Lr;!Bo+)lCSXcj%((j?!T@!GP;Dt z0i9o@CWvwuMRG5l(-|#h`AGe84sGh1i{MVm+HqaQ2lz75l^=D-H8}GZ8FlmEu7u%! zM@<8(@t)x0fGk8@%W@njJ`$|fBe?uCV)H>;*{d!sUU*?p`-FJ^$jCw3q%9)Y`WtOz z&jz>r&hke_61HTPH*im&j@zB3M&!7nW3j9eeeU(qmv~+ArMwM->(eBqZBM>vMqe3; zS3cuL;=rdh61j_1R%B$q>gHDSmr*@Cufx_KX{Lfp-Z(Y`Ut}fz^3*?;`5j#@a_{na za$Gp{5`GVNdb||^?SAZlz8%$Gcwb~x?#p~K8`foVzYwQ{@7CR$$mox;oTCxKj|C5f zT({O>@FjZ3n1R^2wTxvx4}LFVDlcuA#MrE4U5k-~ev zFZWl`F)lE{?9LG^Xs?b91RuLw*D&YKY8Ri}2DQ671m$Kd= zPFR8`Q!#dC?xI-XV&$FTB~!+;hn_{3Fm4kQRKLc6lJ9oTqn1^ycL$&O^#Ry(&UKdQ z5gmhjqHp`@8#*BP61z@940MBp-+P8WYUky0oD^dxbOPMpfi)ltVXVQ%DZyU)K^P*#Cg4!BX8kE@7Set#&+vu@!0LUnBzE< zg<9xHxuO&FA?~oLpWCt1hhLo?84U!KUsl7%UYwrw$g6(Vd1SMG_pTZ3`kbqacIBGYrjpA=@Qp{U zZMntPCU}R8_V-UUm=s>np;}vfM$dw=W5--$CiPvhUBNZPVW@{@{M~d*g`6T_EV&6=HAAq zL2Z%xh0c_UsIWBn2|92VqCc9%RIx8Uc+|IlYRckw5Ql4ZJSPk8()(WbgKhq<+VA*^ zv+zlK9{a)iu2#406~FTZ?GjRB4gbXay+s$SzXFUY&do35=WqkLIm$O7M$4Gr;K{wO zqn`S@-ra`%_Xwr8!z(rfXJf^aIUa7?7i8l$HHZEGU~nbhOQ2iZ+y=Iy`T6UT(Xp{_ zs4>u*C!%BjX$=$A;8cAud8d8HDOcyIP5xrhp4+5$fK(m~exPqNNUbG@#&B*uUUT`T zR%_&u;6j>64cB5V+`)Krpnd|>pZ6#GoOavJQ*5|nR@m^xcqDFQ+Nb`@=wk75cKIa_ zPEBKL{D_bMAs{&NFmp$#PB@?T*ZDuwic9|csp&%AK_N!uCKJ@f{vdw*Q5vd=b5aMw zrV|jM4I846YjN4Nu5fZ5KAu(sOAkT5UT>%4Zaw4E|!& zw(p>$SdQ_o6c%(c)MqN$p6ZFm$LHOxCjQ3AY^mb5v8LHMqeBD6;e4Q9Y;~6#EQn z!Qh)eWe0iaXFvPdkw0+hQ!(^6dnRV-6Ht37d~A4#Uzmu|kMNc@_e*g|R-qYg+4}G; zx*zR})`gqr?$Bs~V_*ETrf_Jjaz8Y3^!Q<$LsdGD4mku7 zVIBLHb>W4`=-$c(lGa`n@s3Ew9i7NGA^z)Q}g$8W9*?qor z=g&!zB4HSpkfW7_Uu}ICxKjU2S>PCc=y)*irDHG|UO#rjJz6Pm(k-;ugtS=I^;GB( zX8aq6sq0AajUlWR)M5J)#L2N?HMT>j{Vm3)JQ}~TmSZkDq5o3)Ee+B?(I7;2<`_P?3;I!z|J~C3+igEw zQCwNs{vlU3--aFTQR~Ns{XlT{!MF{?5>}D!wO}Aj{{wxQ(Z3@v(mx4zlc&>~;iCs2 zcB8WaCs*-PYU=2ErOc)+vMonNBW-0Z(tHG6_e*9r8&L3)@n2^fR*ls%zPSdS#d#dv zIo5aZcI&?2-Q>4R#4r(FL7AR@IREg&W~O-vg75U{@|Ny|d5i7^{h4yAZY%*!C17a@ zXej~Kyy)I#ersLkdCz5Ylp(i-b^U^_F@oqr%OGer>e@(JqJ^7w7;b%kr-HGcd_%$L z@qF4$pmOZJ>ugcfA)_dm*+5#57dbXK)+vIL%X@mNZ3(BYQ<%|{*t(9dox}8Xr&>$v&ykL%_Ttw?zTHjnt_%&@ zJe4mLl>SDW-MpzbkEg7J#hU0DC!Iq<-9}= z9<+%+wbba`H-q1STDJ?egbedE2Elxl128!OK8Y+hPOYA%A7h`lq4qqwE@wH?di?UR zmVxw1FzRUX*h=~}GWRHXbMK6fEo)H^PE}Hc3LjgxQE(Vo_ZZW^ z`w^H$(;?uG%$VQMz1+s4yMuCd@-wv$au=8326Z1y+2E7qrOm6*MB1yf0-4}HZ+5is z>renG0-7rB_1@t2oQTjCjQl85SUw@B>u6)uC;s*Tgo%l=J zeUjh2?&xt>Tx9f}wAM532ZLQa;I;HO^_?8Oa}bWZeEo!2qZB#x6{)7|h8U49{YKWpRM0y-R1hu`6o(DlXZFGA-CL*9jrg zjC`0k{D_R$CyMAB(^{GtXNwShx{{ZSx^HyA$lUt`@F!kgt5Sc_YSA|Pn5xYv zbo|8^g{JOEfH+cc(bghG3TjeXpP-g9pGp&=V>^x5=u2+@DYQ{3T38puT{h$ zvQsw|#(2C_gC}bBaV3067aOvZXJmhy6B+$7PlIdGu8XP85yt2#>-Yt>9LAwz?7!yj zAWICyP(h0x?_jv#*m`vH?*DM>3!K-Nt(f6n>ebN3^+nx>vU;dVjJTK+H z3{9QG4Np{z&X|nyU;~TPT+!5VFZ5hF`3>e|g>FwItGyH%*+tUS!|h{Wm&}1!n!wA) zqSdz9$jAzL41WGcjppzirreMfeT24NRz!Qj+3%yx4`zqj`H*&a>(#K(u@AX#iF)dK z&SS#n9keGK;=tBpLL`nD{!j%*$3CUy6uI&3{H`7g9o1)X#U?h!#xmS2DDA=ZcL}k@ zkF!pM zVrZ?oMENAUFK+5FsfSMS?;RE~5H&KTy0CIy@QCTi;SX>+IsK;Bk53jbvdfO7{`M7HF2eP3nk(ELog||-2sea!}Y4bpOFkH`0}sIJ4kTT0X7ejgULI|G_6bkFJjo; ziYvboo4=21aud4CKhm*}l%Cl9LrNifA5px@?}~i(tMsJRRCy~f8NS8#bp))K-KTTc zC*Rq|*Hvm)pt7B8-NB6p+~lE$T(IAK*Y!^?8t-5u>2()KzI5%!TW<#oaJDU#!@ZK0 z^`&dyPBENY&rMxuW#A9W*^_AVOV>S%78fqy-5r&8#VQ}Zq!{{JN~q|le7Kz}c)lXt z@ZE2|zsPiWW84q&?mNT?Uy}*WFhI_QL&t-YEpo>WiU}%Rj*Y?5ACgtB_mRh5fAjeT zUtVXhUzud9en0>hC4Ovj;!%he{BW%BsMB=YeV(t_e(O%)4t0!D@~QZ>uC0PK=1UJ) zRXI-*i^Lv{?s;{VMj-eI#fV(4X9u~Yc;V~nV{r3Ns6|Rx7GY$hf=7J5u3~s%BgW#E z$jB|C;&>ij_2lcv3-^*~sf}*orTr7_-G^d(o~aT}t(h)lp8sy2P#eQ8IQ_LBsUK`n z+K#{XYqVglx;}J?l+HI4=CVEA9j*Gyxf=}!Fj1G;92Syj(taFh{!;wvN9m^Yio}{Y z0o$BIyL014CY%piL+OYLhZ}?c_#O2$zXQ|iPd_;?`tV$wFC{UIg&3mqeri2`^-k+~ zWF%>%--wWm6kl^qG&QqSbnS%@hTnO2nF*hr?uv6l?f7T%g^&al)wAM(ViDLSVj9f}*Fr-eM?&wm-*!h+$ z{}?`)J15qBc{u+ZA2{aLzbnEq4tH}>mam-CzTkG7;M~uUDlX)LyO&~Pmp4X6cIeIF z)+TOfvXR~wD_p^dvNzrpeK)L=`Z6zC4DI7ETCDIkKG!2s+vj*3jqgpjiUbz7%!=un z*n>g*#~x+i;a{il)y285i|?V;a_-w3>;`kiZ7eNi&cvE=l7OrnGk{R8*a)<};(knX^@&erP^-;`7Lo*mt zueZ2%ZfEfGUmDuQ3VZw&?(B~nwQJ!Zd_?3qmf(Jb`CpfU5#?v*Uv@`mrqNZ*yt3%*8wSiSkepdTN z@l-lN*Q0#51iiVa!Id#ILhx%^kM0)nE8X>XG6#3Y#x84|tb>*ZpL-n74azQ;JlRR| zk68*j!Zvw~jU^Z$&t$W5cUx{dlX}8SdRrT8#pIun&F&Z1{qNXT7mdpT@}M0eZvBz? zpcosGw}hZ5lL{(YxNxon_pw>f7f+3D*XPpPxdU8Q>rXQ%rmcZr=&KB_voV62>tZ|; zBvycrcMU%U9eWizwvSh1#dS+abX7R!X8Vs2rN`FK-GA2<$O{sZNK(mivBf+Ih$?D(URQ<+XUVctHbqbSRu|c@<3lWu)Pyim&w!UQk<+CAh?x`zvD2Lu8OW%Uwl%D1U%E;vXXyR{u_Y zhNp#r;^LU!URu2N?X#lu_eAGo4!bYPeNaYY3+O}&!xOv^{5#$hj68cwWTahU#8~%I z8+$otR(*b)JZp;Ao-JNsR&elpj)2|7#b7_wo*2Eze$}za8rs&?2~mHTj$RpUe&CZI z(+Q1Cd*#a=#kNx_r{3%Iaod~t5Im=D>!N%JG+ zZm>38T0Hf=mloS=F;qS&k(TiqOU+w!SX$e9j(N63Zn>9pF)cf}8d@#e3rqfh?j^ZE z*M`K#&U=Y@%Rk6K`Nu6g2iaF2$Unga^_}WJ3>!CaZj3cQbV>14@%9yw&yMg5x2#7; zeh)kUa;);6skv@HyAY?*AtU|E`{YoGD&W#9-J#RTYnR|)A6j@}W&SsmnOR*p=e|qF zLeJ|d_hYkB4DX=iOA4pn=U&=_5I%X`gMKV{ER^#@!XQj^G(##b9g2MVK`P{~R&lsT z9_uKcbobO;wPTL8WB3qn(UitY|7uLv!!}P``ysXFy|iXOMIR;8>cZTB1|3ia-yo?8 zX%G^#O@x}ttJh%@{+0-vn4?+W1@qkMn*1iD*^L7W{RxwD=0mW`I32A##)F6KLFKEq zW=<0yKX&4psU(dx^EU9KeT=4jaC)^oFXAt@c6bum=sD)|(6x_G{<>VRaF@BEVeW|0 zIw5u?axFB{b44gBC=QTkr_9#3W2K*GViqFf&vKXLHHLeCa?B7b9u3SGpOK`FH?`XaS7h)pEqd($uQ~_!T5JHg5u47{WEfY zThhpvsTW&=7J>fo?CDg9WTShxVd35A{%MYAk*`30v1#ZTnd7(rB^oxbb@Jb8~i|;tKH$9SC=Q!$EblG7!Dqtz#D4enQSh z+~Mcn`+hl0cN8zI)csZGMd$nTM6k2_VrU08wiaG#E!@SM&nv^y*8NZG8+sWM0wr9y z{~11NjZT7u--$_S(N=VOYcYGg)$Wv4rED+y;lX`vg~M%?zZNYdc2o~1S`oU~hz&=G zA8H*wddjx5Be$)nCAgOd6{JKf4~bu-;M=2TA;*P={r4za z4&U35-^6cAWOSUq6<%s9Jh}hb!m;5=c-)5>Z8DEVZX1IA#9O~*R^eFd{G-wR&*{j* zU9CG?P0H(NK9-#wMPa-<@+lqe20bS~M`_a{CEt6>HMc}=d!wy+@7B{12-o}ea&zi< zIJW<(_R2>JFRdv2meO1IKh;)vm9}%zmR=Ls|>>6^^wPeoqPepDDZqSNWQ2R#U6j-O)8AKcB7IT9f zsCd;jT_%|)hKqw9;Ha@yKn9 zT6Zp@h;6@xu^ZV3Emv+=CeC+tuFP4yN-dR>-ys8Soa7Rp$Y^N+oc zxJQ+(|6ypdLYE-#HB1qnECW&AQn`F5Khm(onqSR7FDyYBg4+nHaL_C=EJghLh_=I3 zasjf4^C96{D?4UASXQULfC$I9ts2DC$9hV5cAn;e2{ig*h^CR#-g)lk3U( zCQP25um1y|C*Q|lN@q0rA8Y{tp~-(TomKS@cKzwho=fKG;_zpOon(H|RMx;J=FY`G zdeQyU8Mw8wD!Nzpo@< z!0BYU+*oC^_>9gpM2lZBYvb*W!?$zE`OS0fDWZwW;^>rwV=^rdm&?=Dn^YIAyg%B! zk9)JZ#z;r%{=ogT+H;@Lw!2hATk>B~hJ(R-NNPQNZ)L7gEZ?7V?L@2)uz&74yoU~T zEatm!6#DRF{$T9kH)JL-$A^QgAA9RB^cEM0qKkfvw^%>+Ui;#C))@a@{%?>B)C0b6 z@Uiwq6W+1&Zl4;RK8GmhZ#O=yxBKs^)pg%KF5Sm*dTml}bkW}7S8F3T%2Hljc9gTJ zUm-J;r@a{ZX_&-V7#h^)E+2jv8{n?O@&udHDX(!RjucCvH%{T zr4PrN$Metl4j*;r5b*m%bvpI^$vcFf)A%=uIbtThq7N)^2;Dv*#Ub<7b?wFXjQ1_B z;44n=SJ>4){||`pdtS%ul@p8a`4@>lFXY};8gC~uwo%4$3|!K_G*9K9L(Sk1UD}z^ z8TG$%HwbC^cCKDz0^a;rX>QtYPCX$moW^mgqOz6$W&AJaACHX6mHe;be>MM|{9nfZ zTK=!(|0BGyf&WeXck|!Fe}ezb{P*(T$A6Ol0sd3`!!cG4@}K2D$Nx6|hpggR$+Qd8 zJe#$UN@um^_-Uglv)a=9tnA@u71GJ9RonTACi#iA>4#R$is@-A#ZS93w`ck3Q0CQw z)@1ZE$j>@GT}Pd>;;Lv9Et=I$GiP-x+CxWX^(bvKU759+HqY8@Q9bQ#(vPCO7F8*| z+xh9EkF)wd!B0}JCG}cTPy4s%hn~&qr`xjz^zJ~OpOo^YlqIb!X}yuw)3oxX8Jk%d z26R?NX;(MtXAwVx_H(YFrTS^skBS;()MpJcuwh zgA8ufiXlB+wVYY0T4iOfN~)YyRzkE#d15JMfM1n)X+q_+Cz!UX_G}-&9qZQXH_pse zbtIMEkyZ&ES+%4i-_P&rgy7YQZTd~CoYnaOe%JJD(y!IHreANZ$?IunTyUqQcc#_C z&YW7(X-_Z9t37KMov+`;=ju1ElGi3w=2~l2SE3uZD{-~`s?4su>guw3yS8iG*2UGT zb?Ni;n^Qa24Y6eSRsQwsSWZ>ztqto3_4M+%+Hj@jyJ|x(i>PWtM!)e*;8s<}mc)?qZx&8Fys6rp7u?&;;;rgUD1Wj?wIsD% zs*)*iuWCzzby3xyP)dJVDTZrR199-NY9IkYs2a$t_EbVWN+ncUN=u+Bz3H#?yIH+R zYe7||`|UTQTGDydn6bWRtW_C%D zTAS@tPqTe$TQ;fwW|L5hs%%DW%VyNJY({O%4%)jph(cA?`jX9SezV)vyIfpwF0K-C zHorL=^IX3@O)ppakipy4s;zO=yVcsW%|>#_@NH;2wO3SxHutNjicnuX3kj?U4a7B| z6`^ceRD^K5CbJ@xOAbI^LJN{wwV_u26!d64hgt`FLH|%Ic`VS<3N4Ed;`?HIKeXJv*A~yki4o{oTXHk3c&II%ve=*&ZK!RV)v%&p3o`_% zQAI10B2=N3bVR{mLNBZwOe@REe2QfoS~ZwvJ%^$Rk%3S&X|+ewdA%M>ZD#coh(Hl! zU66zDgkss{>gJ`chW5BUYfog=qxPhWrMtHf>xgG9*p!BBg*paADMQdLwWTAy)dJVe z)r=O2tBs6?R>ueQY;{~DF|;}%N)cKO`Vg$ih$@CU>C5LTjNK3VJMYts8>1iEd?Co5-lzwP}&i(AvC>bywV)+tnRc z?Oln4UMEnsU62I@$zFSw{DfN8t7%oXr?SvPrRRHXvOf6EWzdMsS_$ z?YguGZ)lyHxOLkzDs#QVv-PQ@#`E%|D1GRPc)uEPMNdqPxT4R7=gK8b&BQ*E5HSsX zG%=_ieH63-TjSl`AaMvv%CZYVN}+xs=qC$90jngmDV|l%O-WHnf?k#{K~7l+EYT=R z2%2h%`7CrTv}t=z?{$OF3eqB%1Q|W+&JC&B?z|{dUZKD>um`+WENk`k zWDfnGOZXeicSwiQuQjMA7|<4sB*U6*Gbn+MKtX&}#Ll z*Jvt%7>rOatAoH%fKVS8q8KPlknFLFk}ML%SR@u`iy*cQS`B91+7{|(0V!YsSzxh&_!hN#AZ}e5U{xuWun`>SvuPYirXawf z0oTBRbdSc9z}~YhgP541(12@FiZw?Uhqmi4X}3*CYNO={NIfKawq>}`mB%d)WS72BdMFqCE4 zD;VsyST3$6Wg!9`My7M;lxw!dCR+fyv~KY{&l_OZ7rAiaLLcAd#=YY6E^Jxr+uh~En_Yh^{?UaEfA8a8aN(i9b>YO{xUl6*F5LKK z7gl`Hh2vjw;qI@xFmsCw4}IQ+oi}*=`lJh+u6JR>bv}LAho5$Mw(({ke#V83_qed) zyFUHSr=CLd^--gc;hoJobci9|8?<= zFS~I3ZLYk1wJzLsrY}F_!j?a{e4Qt|_@ThXcb)3ux4y-NO{e%U;=`wWJq<3tYr=&M zPq}cP4|hN9;yXU!*2TVc4qtYE&W&HgEq>hRxp=0^=RfAlKkmXq)h_+kH(b2sRTp;p z^xfCE@>?o=zF+wHd#j7@KJ4=EewT|ky~C%!-G`^Su(Qk2fu?mX+_Bb$4eMRl_+f`% zEf=}4^FuD&c%ci&J>AQA`q|>?=RW^_#?#MnPY*VF`q|*==SELID||TIICo}TXT^nZsR#|BS7cOCKb z;Kym#^DaI<-<7kk(~pm*pDmt#PPF)O@pNI_)7|l7j&APziVHI<9X;IW>F2&@+1U&-pACQG@ch=xT)SI5{p|GgbJwk| z-@E?Kg*!YQ-QnryMo&L)_4M+Pr=z<(ovrZnv%%BP3Qs?GdHQ+l4mTf%Jl!1kbaUgi zex5$%!!fshCO+@N3Qs?8z1zii?Do%ZbK&^cUD)F3XQQW|4W52BdHOlw!xm3JcX;}_ z(eKw8PZuXVy*%Xi+l;3-4W54PnDp!4)6XVP7Z3S$()pTy?&)Wzr=Pcax>4cj=dGUp zZS?fB$1lfJ^k$T^mErg_;L62v%$Bk(bLZgPd|5gI@#js=Y)U0 z&+h|Go_>z|{EeP|HhB8k z`=EIp|`UzAteNH#2^dP+mvrP za+l?kjAik37U8;jxg;XOw#249x(LF4sa~pAp!`9rP`x6R8&v%(uFl6TJ~)_GJu8u9 z60%ULwcPZh)zLWGK;qK8C_R?yNg&=6 z<`yq<;rWYwc%H&+oAoc2U2W}(`SECvZ<6+-x;>5fP1xbbrz0^aRY`S6Iwf66^=hXR zs+N*P^{tlVsSr`l;`xD9%N5TL$ZSx(W?RbUr8AyNYCbySgEn5MUTplOg3)`OgKj=M zB~KAwOG8xd+C)|wZ$dYIYtwnDORA+Zd~Ci$d@$<3r(fcf7k#0!msWY{#l4}#zOE)F0SlzS1^q7RErL0C5EkU0U@!GPOT%!p^MKzUFt-O6SQ^U||d zZ{BQ5(dx~@YsH1v7Mk2$jqPNE#!=zbKD6iHyZSHHi{icArpc-9b-I{pX;_*_N5zsU zg^PUrTtbv32_$kt=!1pG!wR$Ko_n5!ZC&du%;r>2GMmq-9b5c3Z$YK3{QXYhMaX(k zJUJiZoln@j5$08oG$WcPg&N;Mty2r#_-YxezAT8Wah29X z`4uWZdi+((7514zf{=Brc(PYEJ%u(Ngi`BNXEX6`)k~PNa<$Gao|OKDbk@7V>;{)V z$GTQr>)(a8ex*gR_j7q!LaMW(0}8h#Y+dF$Ot(~xQb=05>YT@0saDjk939iRiVUcn zyyynuR*xU7I%!>qLq`;P{Mp7ZYrYi( zt^$WEDry$^rC6h_aMAfn0a#3-2BM^5U4I82Dh&8R*W<) zZ2(SB48UkZv};=PxjyYqHOms4QTqu<=FFa0!#g0lQU>EGQSh2&`R*+u(KXAqcbW3K zW_di-Whu-1;wkMOHOtcjEEfY(o0II1HOs*-5#*ZX>|0h>TcX=^`!#HxP#GR!14Z30 zAf0D609K@Y9_$pRgRcQdS_@ak2a?+1YivhFXJ4}tC8PGt8cY@WjM^NHXWP@NJsQ{i z2|&*$&9?#CsA^)pC@1v@vqeH%2LM~Ch6UjK#U3y_V@)jUOfmq@5CWi`P?@t%Zw`>n zTgmNcY_&Jmw8yt&ZWEC1?RAgR=`DH88#S0{%_3aWkzfkcFwC_%**yj1t>lh;%4{Ju zGHqCatJBU3P{Xe4UI#EMZOxj^n{5NFSu>b4PN#-+40#l2Te1d0T$I ztw%z1n{L@cWR9gPavHW-eZL}+?CsO*GJ(Wc-8CC}5}QR1 zYBqp|qW3lIg2}BccmcL!*07@^#%08_cw#BB|j}=SNL%_XgVm0UQfc)4N$S z$Rn9sY*RHYm(WOpovnl?TNU?u-_J}fJCZS z>{AU~Zz82;P^GyR2-sqig1v)9ZI8650R}vi2jIB08si2u&aeS2a|eLF0&H~~kj*Vq zGa$3Z`_-gig{+E{>{uF1Of6>85McaX4b$&tIpsN|nv`cTYEo$#hxJxE2Vx8GTmgXF z{%ca%e%l9Y;2&6nehz=l9}lo_^08*5Fbv~ylv8cfzlPa2-4Ml6esyk6?> z58?5XY5c5qQXU~c>GeUQQ3hn#fgAvhGQinu$dfgu6<}*p++xk3XIEg8wheQ#O~E#-jjF=`)k2t@ z<@NzL-0Nk24Cqg7IxSj=(|-OY!YYmN-Bk&qIcdKGiO8%uhu{?ShXr zIi3kxlw z(t;#SjF-vzwQydUerW`NQYl8%{9c@cU6Wat9IVfW~jaoUA ztd-kEZ8XiYkT+XxtZU5`<}Xnj+iWtO(j?nyI|mXfs(rES3Q4dAT`pc+5Tc(O$@Vn- zsPrne?Z$Db-VV1>8gzARxQZ5E2;o zQ)}80%eS_~x73OaGu;)?W=NPy7Dr}!8K7*sUrs2sra@T`vsv5K&9K9}X&Du^_mKKIwjHaZLFuhhb<}2I7WI%&68WPc>x5_SUW&+`iVF zWdu3*m)dnhV&qhcDscF`9*i{YOzq{&ZZa)g6B6{uPqOw32Hy48bTi^WYYmbwYVDO9 zV9k2a5Y@_y1R(unU7E!8=vx6C1Q)_x05l*0fCu<9G{uF|o8-t*9_XcQPEj*jn zAP}B{Gz@3g)D)NYbyQ7*Byru(sa9Sa8)tA*8Iw}4xz-L!p!lM!pXS(Jlf zcWQB@SZ)q4wWj}R6;%<}=jevmKGP0BRR@rR)fS_#MtuyD>ji0_|zvK9_<8}v%hAcFLwCP5Ho*OuOHZNw_Cw_CWTULq+7+a1(pd}ytldwRu| z*UGWS%|fq)Wt%OCEiOGOMUX4GFEQj?k7~&U-BWqV)N;rF0eP0NHtFbd+!`tw+jo zTyZTztk#s?$aogM7G7N9A!$fj8PjyuvW(fz;EaGoJG%_p?)bS{DKp%B;I-;!E8{4u z@@?rw(WUY-j&MgoQGI99&)WhKh_^lYCZ-NUKa_3*Osj)7)P_#m>4B*Br3B z@Gk5=Yf3GU+SJY9wn545mL{E@(c*26%dUm_tgO7@tHm16g}V4HZ`4o6tKT;LyrLqk z%0IBV%-Dv}Q1yKP7fBw$qSOY^OLzQU!_t3KR>9;xD{_G8e`~ zgdLcYCJZp$pIfNIA0E{H6kf2I#pDY!&=n>wmVf1C882KTUMjpGon0vQMy~;i3=34X zEFv<%fqGk3xHSv+X?nl#GVon8GZ~g4dJmY!C%gT-y|Cfn=*Gm>TC1;S=+ zGbKzIRuyNrl%=w-ITkD2wz{j7w~e*wt7uDXW<|=56K+dny9bk-49vss7#9&*j!76;ORAZS}6Wzn2Ip+l(*}JSEaiQt4S3z>ztwu?25Kxcnh;$GcmRW zfozAXOxJ3l4Ps4N9s&-;0hev`@w|hdZdu zS^mOka@IPvtH4~+?4DuxQ}t5A2MC9#Qyl_Xj}idFsHnURHH`Amn;`|3UW2cl0hV4{ z!=C2nculS^G3c7(6p3QZ!^ZHkss+MsB!{dGun(vRtV5l+VWzv~%1(y#R<=fsnRs14 zW&-_~tz|%^fgyv~T^VgX=$z9n)z79ftVu~FY^gFBdeEu6N!@DVxKdF#dF<Mk0Nep#1j2^+p%$p6>{Fc+ zcUbP_Zqqk#o!MsrQ{AF?$_pq;0NC4&d}q$aVN?4V2V;B9hJl_XWaxt$tx9VjHPER} z!}2}%6(_SYd}*5tC$nq2T06VC1m3d>TeQj|gOxyce(O2z2l2WlWIYNo?G zVU9tu70DJY&?q8cYE!Sb^o8ZE?pTnp6syh$8c-C`Y6INhn=VFSr74BOsWOirPQj!) zb2%XBZ~<-;sSTfZ&&PyOnwAP9E3;;EfjsO*f-s#x%P6gPSX$ZDrpz+1(_|V0 zedmpAxy{|cH8O#c0lo(=NTB0(9SBR~utdsKxtS;foTn(F2a{PfMI<>dqmtWKzr;)WdqXrSW&!`Z%kt_Q~*Wk_yd{YqyqP;}6N#t0)7 zl4>AE+OR3X-8#;Kd7e0CGl_2a7OM?mBVqdSFf4M)$v_6C{A)5tGkz*e;JR&ATXwp~ zxeaOUm&yS1+-I6qfu;2ZCU$P-gd+Tgy zorGGqpc`7*$Qw%6Fr!+AuX3$J7?1LWy24O`8 z1w(+h4?wyEZ)JZJ8UUl%Kq+BtV%@TSHcK(~O4lOt?@HeAK4W!`gEhTtozs3VU)xUp z6{&1~Fkv18z-YOaZ5K;hr{Y$|x5{e)IMw4h?>g-e);^^JcZ!Y+W+(UDW8JFsrjnzB z;F3c_9UEAt^seBTOf-O+i>I;Yn*AIG|m z)2$Sh`4P{9&STULnBYREV6F=5gAGj zB6SD~CK_ojfJ^QRf>8^@E|Kmf2rFM>Q|hnaQeDUh-3Z~*_12j$Agr{??8E~k*^NkK zFnf~|aq2i#UUIOg6C+X@XThcUU7PUwS>Ba&wN*6>MjO}DW`3P@;@`dJhv1TvgkUGO zkRKSR7&&ZDs}l?rLJGbr>(F9y>$`~5*ifVHCQi~V2=-$ z?%U&FDj^R#^pd5pPWaXBG={+7B)!p^mB&aN9WdKGa4*xnNt;@oq$zC)Z0W!~Fcmx! zEUoz3E5tX{ZAzx-Aom&whH(%d&CXUQDa8BP)tT(!cvJ_wW2nGR5Meh4&f}lK{w)}D zmiJw#>z20Fv2AtE*P+A8H|Gt}0`eQ|P6^f_LYUkj`rngYF_ge}LVff?giaaOB~Z?F zJ8dd(S#wm!swr`Rb*4k{V+F_WaE5n*+4qe7uiK2vO~P?@!0`W$=`+MrY*PhE}t?{=usuKohbL+%52zFwCxQY@i&ZUkapf=M^ z0yC42trfh*{DsNml*4Y{!H2TsIZ-!|MQ(87OI>PNSC`INtFBaHYrH$}a1zEH;t0*L z^lckxr+7s2Y})`YC2tSlp`7Q<4c3SXKU3NTo!nbzQ(A`0{CQm}Kj7Tpl)psZ99*tT z{C=rk!KHdpedWwTNq%DheP2rKf0NRERhm1r-(~y(-hj}uL3tPjM%j&zWBlD3)L~f9 z4%MOk78+RJVffL#7%x|6Y`({Tm__Zlx@Dyf1YVb3*O$~-!Sr|cIkrl$qopn#du^AF zQIlS_djWT=*%Bau(NLFRDR;ASM5r@gP$5kT7JpfS-BHv!a+U;9!H&c!4_l7+eXh%< zH{+J+){)S`Xp{07EAG}cO7 zr<4+%+ygWVj}JO9!T^kjL!Uny={ff?~ZJ+Bu7>^kft zdA2pNcsyCuWQ-;}q#|WzR}tfIOWDe-te%v4Rz=P)F`kN)xl={TEU6+hTi|%@Qqi8v zv=*G(G^4b0XEx{DnJqYXW z6Q9hOZC99YTl36pSDCrNw~fg3P+cXH18jkf=vB5rOW7>qOS3m1HI)o}JeyjyP#lTg zG24U|QaK{kPdOroy>dhP<%R3Vs*yoPGTQ(b0ubev~blUMTib{udT8p2;E-U_5tL?>&BS5m7_+q$ibKyH@XH zwj_rZN{gq6gwlnuvrtYV&JAjz4M-^h{g{5jrdBT(qI`F*@tW&YfUc8SxW@FZV|U<@{TXcnB@9Z$=v16*2j~W9HTfLCa05nEHI3j z;l~ zID1RNbwgDa%G4Z-=oO2kkuYsD;E5~*ST{{zs9&AdEj-TmyME2`u1gfztyFAVqJXxo0mS*Z4VEuY787Ucze8fpVM6&VC39$rZL*z+r zPRezNWdP#Gw zew=}%ASp*=Ftf;zSFcd1S29D$MI_Q(sDYMR|U+Fyy|9UwwFU2*QNvw@zGx@1B@J^VLc7`V~ zUru49u}-GM@H?KF2>v6cjIby2F<)j}9#2dY$_}U}Wm01iXrFgcrImxrG9;? zjWP5hReefgcR3>8bJ1UIMhH^vu$$(4q=-p6(x=y_X2^o|DTK9T%4x*wIhd9(w-@!t zPN{h-Nqs6SVb95r^(DEgZ5AxjwJjm19-hE8d;K&K z=84rPk*}VkZRj4HKTtib(Xuc{B}EX9L=Th=A$WsYBZM_k$@D3T-CoHjdwqt!$P8Z37SWa(WPnkp{tx$B1iArRgR8()a27h#~ z-mDF!$pduQ1nIOdp<(Ma@C$@+@-ksA{eLm%dQ{fv12W_Bc2CFwG zAFtD>$8)_E-oc#2>eWQ1GAo;EJvaMx;znzZhZVEE9OWzs73H|ouuR8?xH*j&76v)m zIF_{(b37}tG6QNkOI#i+lV_zEog-$fozoJ{mT)F!+Xx4-MNMTfL$PVONwI0U$6{q6 z#$si5-o;d?cyq<3B^<@3#RwNuPHF$AV`A_Xo0bYJHnW{xQu8&Od)~~pcv-FVY)M%} zq?B`~p!%O^cQ7Ns37%k~O4~XND5sxAav$=1+(Fn4L)~KNIpy=QJ8uex^&#>=`|u6njaX{yLi{n#KM(nem|1?DrDnECK_!1A7jvwE z%CydTFK-tsxhu_HfVaa!j3u^(&t8CrVIlsX=50UQ%Rf>5%WU2ge0cWY|qZRmWZgRtiBa=v8_>2Q7q50 zF7~Lag7w+4$Fhoo@IPnfoO|z^oXq|G-{+&@J2T%qedf%WGc&1bF*12Mg#QuPKB7A~fx2qo>NS$O^)5eoUd^OTC>&g5p0n^cZYg+0Uk z5;zorJ2t6mmG0(GAqeC8c$6e0*#M#CJ%rTj2tc3)_K@1wB!MXv+5)#^;8j2eQiern zd60@b7N|ohS0#Z6W&kauD?j(tRVvuo<0&64nxs~is$8HD4qwp%xRQDSfhvWBd(68M zr!gEZi&7zSsD@H)eGCX>Xx%=QA0SMLr0f#ro%EiTV4S-ud2 zrqspw7y2Aj8X~ouP_3o;)LIyvOBa#En+kF*Y}#?@;(h^~^@bA(AiIIzGB}8Z8z4Aq zBPwnz!No2j6!9Q-WrLMk>z83uLHY!NROyZ}B%HCtB^fjuji3;rAEDVcs&f5M^oMfoO@BPDI5lRHZ`WfhME+Cd2@rL_2kDkp@VK zu+$$K)SjtIDu&c5DyT*_5Ypy9%Hjaq2*$s%S*p^g%R5ru12zEhy2=+=4!77WE2&s)~+gXho z=%;n`ddGp0-g8JrsTp)CO|TUXA(eJs7ZV~^z{J)H^Q78R2a#8yMYXVdtR-XcgQ_hf zeS9j4l1fs=9W{lT)d6#`O-V)L6*%Cgcc_$FK9olCWqGOA)Te>!r49$KQE-q1f}~MT z8`a!Y0s7uFZMMQoc7XoL7oazbVqlOJJ*_yx(Vlu1AxVoU-XI*~Nr4J#iH&{7dwO2< zJLzg)=Bs;rT?kw1FwY}w%sv^i4{{|!RR_2wjWR*nB&CuAfdvf05Gspk)Y;&v z!8ABQI};{2GPp^bf~qvI(F9QpWH%S0*nqHZF<3B^muZD3KqY0;;fFM>7h*Y@p{h{i zs;Qgh>NKr1XW;}O-hkq^4LrjDySrdMI~VlmX=t&6QyduiU}Km@mPy+DKMhn!F#oup zBFU7*tTfc1qN-5qvjM7;yPhvFL4~SMg@W(0@-j$THRxv`q8Tvg!dW^}l>!9am6pFT z87Qt6kcI~#Tv_0YNZ*fgaxI*|gnfauSx|01-&v^Ma%J5#QlGhssILLlyE?lPQ%p%D9LelLSGb9Kz2ddT|?zVk}vq8)e#%Cr9tYkRZi1) zz@>rK9_&g%jt0{i_!RaZ&|rbgg;&C)L51L{T9DDu_$*B&$SW%rlX0Gdj#JVE1_tU- zBO3IkEvzgA)h9HzGSt1K;dp}cw$}2bmFm;qxIV?eUSbaa?pJ?DosAh0cjw}KqJC#qhMtz_A}OZr&X5XWljyG;Yw3lSh&JQ z%du&$MT;_MNK*nL7*azKU?S0s1;ybaC90=^0=CH8DNj>MNwju`qJ_XH7Gg`mwt)~# z53t;|=#qv~Co0{w1%QGLU`?X+@Gd+-UB2!@Y(elT(zKG~n5H$V_+4DG18mS@kkZJf z)oSB>5-ij7g&Zi)ptPC>DaePl0;UtW`sNHhZUC%@ITKCwaF9U=t#2l%LG?NwAYOY= ztLhDXLE8u&G+%EEq@jezZ4!KO7YNo4q}l`sH!v&%OQ1z~)DNH%*P69Vn+D>nDmL6; z0$(^Im+Jro znGKe6pg~rf4{1$xr@{(AkI(3f%R9Jj2QIP0!Xb5k0rpr0m!nc08xqKdY5Fz`y*>n} z%php}r=_fU$3)aW`sL}r5yB4PD#F7E*Avbmyo_)j;V9uS;gy7E5N;uyPk0UCd4ywx zBZM~)t|Ht@xSsGP!pjK92}cQUA-s}s8{rnhTM4froFE({yq)j{!tI1x3GX1hiE!vx zU5;_WDTKEW&LZ4KxF6xIgdM^O!ovt}C!9mLop2uE9fZS#Lr3a#%pjaXIG=D9;dzAn z5snac2v-pvM!24E4&h~l^9V-?hY7DFJcDox;e5ht2+t!NBOD>Tfp8V!R>Jj!HxXV& zI8Hc9cnjf`gxd(W5Z+374dDdg7~$=NHxOo;d;V3gqIP{ zBOE0hCcKjH48kph^9ipZJdbdUaD?y%!c~M@3D*PaEreGRZX?`6cq`#G zgcF2ggtrskK)9W7E8!i4HxUknss0J45Z*#Ki*Os^euTFYb_gd34VW5OxSx5gtako^TG~WrXtxM+t`suOvK!a0}sl!fOc6 zBOD_fA-sWb72#IG^@KMOUPd@hI7)a6;gy8j2)7X4N_Y+71mPIr?SwZFZYSJIcn9H4 zghP|4{t2fL-a+BfOn(4&ipfd4zWm4igR?P4!PWg>XLMEW+~$ z_ahu3>=3RZJdAKX;T*!t2V+(Hp2Y~ zZzb#yP7oeOcst=7!tI3f2=5>qCLAKUWCr0B!uf==2+t$jk8p&rL%53YFv9hOa|kaZ zoJTlHI81mY;TeQm2dzh9SEWCQ&rTu->3aFlSAa0}rU!ZE@z!mWf`3C9V?3AYh$ zBb*?dAly#4op9(*oxacm`fnEDEW!?9hj0$z9KvD3VZ!-@^9e@?M+nywt|uHN93|XB zxP@?xaEx#(;a0+N!g0cFgxd%w2qy@)6K*FQx{LDvAmyKM7Ga05LpXe+fDB%{uErer)V}x4?w-SyMjuUPp+(tM-I6=6ba6949zbOBYQ2q&L5q1bW zgmVbz5DpU#6V4}`PdGw2Lb#rAJ>e+fDB%{uErer)V}x4?w-SyMjuUPp+(tM-I6=6b za6949eU$%Alz+lmgdM^T;T*y_gu{fxg!2jK6OIs$5UwX&PdG|AO1On^3*i{y7~xjJ zt%T!*3AYe#AsizdBiu^3m2jMJoNycAHo^(Q3Bv7!+X;tQ4tR|6PdJOPL)amlLpX=MCK3z}xrL z4xGN14gXL|vVV$!!v;RXz;VhA0;fzrW%Cp@Fe4;g7?&Yv|(N z4XkU!3*S}Mj)zkWyuX158sCHb!O!D6M)+X{?q=`@8`v>$#NZ!n_``0V`f>hO82B(F z{1t}(FvEY9;lG7C6n~$F8@GI8M)(oN_tqQ!8w`xW(TTs`YWR;dzL#U*gb{uRbs+v; z3Uv_1)cxJ~Lc06Ac&zdL6vH3xUr{0Wds&8mKLd|9zL#zI=NbNE4gau#X}ECHd$hqn z!w4Vms{?R)%MAZB4IDPUw|!?af0E&UmBDX^zJNcDkA^=NPuAWpo?_sb@x7^r|0cu# zNdwO?!oO|!Z#VEC1`bgN<@C=nzSqz2&o}%X!#^}m%8$G|HO)E{8~kdusyjPE1F zBy;$P5nqjg=NbI{41Ah_*Bbl?`8%7ZtADY)!??`wXL*PH(HqBT#w_nJW_gEkmGM26 zci5lh9mXv0Fs?E9Ebp*?z2UEG$4lQb!=L3H=0^>GmUr0y0>l4e17B)jmUo!X@(yE` zcNn)Ae3p0EpXD9KEblO8d57^D<9jUcus_Q?jAKUl^#%s0Mr01Z!SH8!hy7XJVa)Ol zW0rRqv%JGNZhW8R9rkB=hcU}Lj9)hREbp*C%R7u&-eJu04r34ol)S^3?82b|b7`JQaVwQKNV z({SR3XL*PH9V7h_<9i1i{w(h>pXD9KEblO8d57^Z<9jUcus_Q?j9K1c95d3#@(%m6 zyu+B~9mW_veu6Q}JB&vf>B}*2!ib;c9p?nB^VDc}9L%-eG^1cNnw0!9oP zmUkGlyu*01!JlGamUlS(RKuU;9rkB=hcU}Lj9K1c%<>LnmUkGlyu+B~9mXv0FwQs9 z$MO#Qv%JHY?=TKI`h$#F-eHWsDDN<4d51B}JB;V)&$;1Q-eG^1cNnw0!#G0x zP$-@3*1>!i4Aqh_*kA*8?bz|E55Rc*b`%~E*XMB4_2I8k+Q1k5>ExugeMNlq5&ko7 z>7KQ^ve!oJx3UJDJI-e~4tT8Jf*bJov19YxyHXI38|Pgn0~qgE2g_`2)9qnx)D4)< z`{}ct9!ASNOfUHR&UY%@K$g#yA~(?TM#lvQ^C0^Jy_aDAED0_Vt6+* za3)J(bzusg^F`B6@YlD*tJ7c#>$8M(CK3GIvxR7kPgpyGb$Yt8PDcY(JVn76?}kK6 z0-F|gKTXzA0MyLr#8|@fUU2#_lDb4FnylI`)ueY zemtiTzYj+45Y;00dw}sspo^7RWoc9PiC|id;Tdy$jImtt`;5_YSYtdFk`0!c4aY^)CirX9d^i7uReON+O)4wX_bL{^tsIDz!M$r#p3WxrWP+X!Cgl)S6P&G57WwJQ zoW8)dvrfmVoeMVs@b}4ro$cMzr-N-inj+Kr$MoZ;OvyiaIv9weRWQWwn)l;P2Z$T7 z_H+`lzGgPUeIR(^2yV1MJPXa5;T)l|I#*cTd!S8U0fQ|vp09*Q4b)wYfVDX~nDFB( zMd`{OeG;4ig(qFGzp{xOIdAYja4D4~izo-tbAMs4y(@%zHS9~WzJ&b2Up*_IGXL!a< zpC&~N*W$tLf$*Pt10&tLYUE@z?oC(c{Je{>)63DOeFk1~pw7mnLtCCR=TztmbxYCO zIbFT~jCVK!U16}ehMN=M&KEe?2>xs;PAAyX@h}}&eDixW>0k~H1DO|InTLBfOQeHA zI9&2fhfv{r5VJZ_2Bbzy z>Lw2N6&u2?eR?{67%bUgd{GAK>2&di&H(W7s&O#5=7;wH!%HQmc;syFGgeN0!KIND0p2&kkyO@6$>&q(Am8~|Kgkz^ce@r_R z2pQ+6YXfXAf9|<9eNSD6cVmGbaC{DW#PK=kAtwVbGSCOq^qdC{?)fw|siQ;EEDH{B zZ<(6e^t9`9(DSZ#z%iAs6H^ZUnG_rr=*foexj~1dgJR0TKl!5r9^j`#TcHp-Bptm% z2O9A7*`y48r5W6-MCT?lbh5dGyTCW#gkQFMoh^P;B^wWK;h^R^z{I4!ffSr%wM{&9 z78OFzs*UQx4W9#^h{J0VAuv=7~eVkypN_R)@gzK2sJELe0GTZA}%ztSFvKi&1`2 zAEn8XZk&a0kOLg0!BcOZLuH*hH{&@}p`hgtQH6(B{0`OTHx}by=MS+M2H8bP4tSn9 z$pJ4?@H;fZdG(}(sR1A<1m1G#cc3TGy`6}%DnkM|cfh83_(wCvn@D(m!3wLtoh79k|QT=g~mcqU$rjfv+h-IT9#vLR8g2 zAO4j#6+X!MC32vIb-a0&`{6?kU?epKID z4Veds@8M+VV?p@rrB!~<+I|bh?rz4NxfG6H?j_2b^ z8Kr8(S3-$8kOdAPCBO+wp5@U&-K)Tt24sLYB#DJJ_$VEYD=upQ=?j}>nR=7nyC))} z0wh!Qu7o;i3n4JocsUZZLnUh{holgdrIXdwZ+HWq`e-G@iwF5tr)-38-~)wlv2<1W z(z*tGQX~W9nQ}Ol=^ly7SPTLuyyAjq2H_$>2(h@i5w2zTZW7C25kn8s5P}`t?BgLb zU7h-vS%z}JL;dP7KTuR#m;&eNKzzct__PCDa-!xeOsT$vSc?mIt3?JJMuVFOKrn@q zVkmlmLmg%h&Whmx0uCsvpe)OmYh=LaS?Iq(AOmDuRh2BRW#IUxM8iq?4yz0}T&AAa zRLuhl$oOUQx%!%#YFIPFpq>27boCPp;gB7!P%}ZI(QgxH)7+t4d{cuClRWZc7;>S3 z-RGiinMh)(TeOl~XiNnb4R<^sW-1NE7=74XiAUgqHxT)>6v`z@FaZ}5m{^m7F3GwO zbn$BoFg@yWSKoRVUAQ>(3Rb&#Yt$~lQrEbuR)~55{EpJuH1aK_t_$W;-9d^hB?rO1 zp>WHq8XYr7lv6Ebt5*(?<%&i$v6BmmIW)?E3kXO292@o`aM98chN2QvE-F#rHrx$^ zz|qI%i3Khr@ggM9O=Kz=N)Pv1JE2{)5QTk#!>C27daZz6^k9RFM|RO8y8k;c=E94v z(92+*ufJS8r3thkc*hE|K(@lB4jmH?maBZhDr`P@y7zZwjzAYEW+-)hpafYcUghH* zcq*CrWl!Lm1V0R;?w_5;SF2(eB~X>Yn?P!L<+?P$)z|6(KeD(T@LI-mff`h=*rSVT z8SWkV;KCh69UxX;W*6wo*dx6#cs?2Lc=KG!7FNPtOnw&_Gu4}-UYN>KeF1^r1xHjr ztENIP9K1041g}2~TwkZ|=JLYmi}?Iu-~tmElagHUu&d#sUvl@p125))!VSw%X;Wsh z$_c-tZoh*L0C!5j1fS%B>48}i!svVTvc1}YL83GpPh+Ey1Bde=4C!I;K`NB2&;_Ov z5R(d;Cc#xCeixiAidC9bhr|miil7Ck_S~$lL(O*Y-^|pqQ%Q4El@g6m&kUU*IjlV4)Qs)02*gz@AhCG~&{w8@4Nw_##>d^c-p z$pl=~odw=K1>Nbm8mI~?8o}`zl-VcGxbzE&(rk14q-*NRhtbxkZGL;&VP+0;kss!GT zhZ?J1rUg^&f=aFF_+A~{9D^=6pZcYhOr^QOtJnB;P;^nZlj;Eg=J-rF=g+r3%~6+t zWWt@SrS;8l$XsjOAdI@KtF{~;XhfYGxIpD78OGHrfQzaf$bbDTkO)*5D05r@>1qTQ z(9Bfe_rseV;Edf&dLP&M&A?4;!7sTGjO*Y=o$GmduHR( zl6nwnLGS<-A&z5NB#+>FWE2j=;H2;J@y`a}WDc8tCmJ`ia4+P@1#VENMs&i7z&C?~ zQ|`D4UMN^VqEp9E@Mcw#Is`(gi~W!cMlxcA77ItS`Opz0)YhVP!6#zPENibV2 z&0u0hCv`28Uul!2B@;+2zTv7=i{OM}hY}ia{RdJ8IYFr5yrGh%bx{6Qkaof~4=4up zwt;rSuh4CF_$|D9kt76=WUw*$olw{@oR+}bFzf_96<_qwJunMp3q7f*d+^k^P?W%r zz^zPLBFgef4pZh#nmrA_g~bf7JXV)3FT$lQ77pxy6zZvlls;Lmr~r$FS{SX6$dv&S zpcWQ9Cmabu;p`6u^NJQXy-;{dmk|o3CAf~)Pedm-l#)dj(&|WuQchY*DVVFANE*S) zQ(Gbsqt9sx-Y@4lxevyBPW}uL(S4%b3k9W%N%McppKT&Sw#`r=aX?8I`HA2J&ylOz z=A?oXzEPYMO5dC2ck&k@#fSockw<^2awuP^lG9SqXDQ*@%Ok8&LFoW;PL?OtK)#HI#Vj4#P9)7K7R>Xobm+fi`mBns5zg!e(g!X6$dN7)!d zX=!IMlyp66J+ib~$diT9iC;G;KxNYC@g1DTo;}1En;z0j{7_Zy7-m z8WSwc?^$|=^JpkPP`TjPo8$x~gH=O^HRTSi=1~;w0=5W+oNkOf{ksGNclH5o!k>rMPLl;wShH?Vk z(160PoF0NYDH1j)_4ksOF4`@5@zMp-tW*<) zYHdUd;vR5KGR*bMnzGfq2veFs2J0~bwRdQel3i1>Vmb6G<%ZiyIvX^{LpXH9Y0{nd z!42pA;SOH^L|5{;ZtmJ!eNTr=s!PSyU&Y-Y5E_W9=62P0d~V#h{NdQG-V0Zbo3O0d zpzo=fUAtkqpfI6SYjC|CSd+jYL~b=8H@oH~+6~ufv%tKf2xb8emwXAG4yV=}26uKj zT<>JKxm!w87Q!N3bEzAt3m^@*W-aaXFq9p*@zX=eBmRr&kc)-Ba5-M-3>r~*29({@ z`#Z(B$in%dhgO65w#P9Xw@9oP%&&ISQUl&3hTA8|s%w>wGudsK8vp!mm9E0e`yMO->v_E5H1pu> z=Xwurd)&ps_h2wyq%ZFF!r`mmxVra$uU_Cb!c%KFsQbgIDG7#)WVc1?dBkKlHaYU* z#ZHX(w)(?i=fWX1$qio&fXNo?O(|gXjOx}Uba5qfzzuxv7{P83g)-H^@9CkSF}tL( zw7MFW>*{+x^B3G$RpGQ7He0$V8o1gGhM3YStrkQ#Ewaq1ncY}fh40UJZUs%pm&5xR zAUSz%g|LwTYx$&bMZWy<_lhxK4K7l9xB^cFC>iogP!tC@xI;F(q_h+s%usR=#-TRI zk~U|^ZJPgjXmUdn1lq(waS0Z_Brd7lMUaD#Ye^+b;{xOEZt zxyn!;!+L^nYW)CPbK1%VzTUx2iDx}fA)?9)`zoqsARKJN7oOG7GzNsavC2FM+;F2t zsp^XACRM;VfpI8#3AI|#97%oA1EnLn`;R529_kuu)TlJN`RF;KLqiCK*wI((=!iBN zhB%-c)%5176e(o##H<{1M~|H_HgC-MvF|tjI>k4$F3Qrq^s7Y3_Qu| z4IHT{KtxNth{#dN4bx!4P~YT6L(fbkIaZdUg@{_Fd*1|AD+u&zZQ?mDR=Qucy!JVw z6>%wC59^Pp9-5}I|M5Gjv7}6?cRl)&vc@{t%tEz9Pj_LjT8@?=Jja^y3LNh6N@j4R zX>n!+27@^e>1tG=Qo*qlCc&QWgdtlTl1Zt{Gu+xK)+<99r{R$VinG!geKQKLO3+A~4usb?nDh+s&^^h1Gkn3`ba z-BUd)VN5VRS!oa3B<_sW6L#%AgVb5guvG$dnoiX0$n!~0*cd}zdD)!0+DYmj;!vp9 z2x<84rQR~qGZa33iK-Y33wD4L#!MJHI*)Fv$59Af$9EXk(RIQC?j^ibMAzhTjK7=g zO5cSmU3|IPsF^f^kz|>#(g5gSE7}s&ufi%F2u)-G% zSNa0z<%L|pJ4o(;LrMYoE?680-!)w6yD)_dVGUObo99*=PE=}6g4p0hhVTW$mA(M) z5eQ)y_-AFkRRG`h^6RRUm1_r83%dG3dv&Z_X^ z-&96RTy%BYw7X#RyLwB;4z6m^=y&y&gML?U(S)ur8mgs_x6Dzl9TqU?%7yMNC6ueN zm{2`-ff|I9Myy_*bw_<}?pU($NOB!FUUnrTBnXRojmB*CM-RPSV0=(28MSazRu{?w zgWMgdqaO3-7kqSW`dmRi!&}kOs=A{qs>_utb<2{nGr{OhOB(Q9a@9h(n+9_A z4lww?0DIQ(QB(r@UBN&Hs%QzUocykprSNo8Ia+l1U6lZZs-UDVz?uzKzgjTzQl?$? zHT0e#}TkxeQz(Wm??srNyrLMmSEx7G3yVH4ebL znV>d9>k;*CNH4AMM+*wDPM(bKEQ5NW7jCgM9B(KMdT9lLGFB)D)d{M0AT0E!8kBu} z$~$lcnFsXuu;7LhFH`GqQGnlt*Vf>XE_kmDtpXr*P@CY23k}*^#SbBb^nx+vO!bPZ z-lf*o0KFR2>kYF&ZwTGHK#A)RHp$g(zogCwsR9dyG-XKKy<_65#7M0*v6AHk<0eRcwR&s;gXW4a>fDDicmr0=jZ zyb|P&1vEY4N0c)qhqe!tv-}Z5HsWs^&N$KIN5;C-A<7DBt5-XV2{dFL{!} z4sAGdXhD|2lo$dEeFV>wni2|x&Xo%`*N`~*BZf1j1fEn9zis4_KhjA81z`yiI7UvO z=}ak6A~97w*dxO}q^dN0)k(-aKIim*aOQ6t*kbsN(TP2~u`UXG%A` zg_ZPe3Ozwi-~_o$e8Yw-gF{MC@({)o?aa*zyS*wCbY?+>1#a~blIVQ0wQ>dl#1L$? za|g*5oR5?X7S)aZf~Cwa5LBe_k)&mU*BjhK`?NzCn)Bk*4=HELIH+>fqoKM>xi#t2 z()dIBR5Iwyd3Uucss!E4__QUxSs+%^5t`enQ_!w6rxLA_@FP^%?5t%ga#kWW{ExMI zy_N9l+fvY`P1?DGi6lF#cgZ}3zIN7HKv!JGl=v4<5b5ags0r-gJSNw3Mll*BX0%t- za&&K3Vn#vOHGAr#XC*d*=$ntvmU|z8Gcn5W5k$`};LIvK*m~hjD-5lqK{&UHFUNz@tVs!7 z2gpd&*rHCY8IOk3n~QmD?OYmAf%b@b@M0 z2*ble;No{c@brxW+DHJyOY^&O7shjRAMgJRX=2cQLMQp1(8+fu80CO-D1N7t@&_T& zmwYeY+&p2@h3||3D_*G_JQ>+HJ3#nx(u@S|pzY)F!!t?%_dNC9x-n^@yC=JNnjds` z^W~evz};}xbA)zRV_ee8Ub*vV=38z1-Tmurzq@}G?RWQ9!Cj#IwE>VCZ9y4SL+fjD zS3SbNV(p`kYa6C;_?_glNs0pnB^Z`q#KHrVIy{YI?u2Q&t0Q?z@1(;Q!5q*C!z&Mo z93EH2_)aLtjp_HbS@>r$Y**tH+tD2*H~bDf_X&2{u-jCv?yPXjpS4vm&%lt1dMP}8 z*GEmh&=Aay}lm9Vg9EfToXKArv!PqdypjMcCsSx2w*f;+V~(D>jY z-TOYdSKu4W+RPV5TrYfOsWO&Cb%&~V{!S%G*C4BrCdCV1kJf+9yvgXf>vTem!SwI{ zKBrSlynWpLGBSiEV-;|x-7%h5Pp0u-&8=wMI0et*pj~HEBkp{Go`QD1)YO489&CQ~ zfx{5hrM{pbw^V~cd>^pSm_d7JSMDXv$^OvBs+t#~ zrSB;0V`U4~pHOIjJk~JY9mzahH+p#Pz9A7kyzo999(as#J-op~#W8-gBuxXu9R2h# z2Oi#<21?P@foczGVt%EK@<osxPhCi?vTd}Jw)vinFpT%gZg2Pe=58OuX;Grw3xVRWDC`)3v9%DN5fFVmW z;9eF!a6e_CUSDXBM!y9Ed*I-w)zeAZ`u)|4ggmel>VXmCFosL4791~?2b2DT)W$opsC+=`;sM=TN}~@* zjqKwa9Ka_x4-JxzoG^aE=o~O<=EudsXH1T#V(~4W!3TC^rM|0t#LlaH#NG=&K1GRt z?9e`)#FHnF1;Ei~yA4T3m7Ah;oMVy0MUy-`_SN0GgCzle%}@zU;S)dPqk5)K*$(}i zeDK&dw529JQjE#<`QRp<+Zro}dp^))hda1=Hzt?I7y6p=;UNg`{0DIgrW5DtLDsFZI$(PUgUVAMN3p9DRth zsJh-g5`yJsjB;i8EG~{_Nj~nNh4(LZ;saf=6Q2p4`W)GrPi|hPK8oWT>~Pp}6)k<; zLCxHW^n8+cBQYMXV{CU=o9dBr7zsP^QE78qb!DAC9RVX;gDN-nQ6n4Z7_|I|^}|Ek zobo2Lp`shW{60SA#-v)b6MOX%OmAem?Vg?4<<=J7w(!D={>i;o(_WyUiAmy-tnYkEMDV*s_U0LT>5uI z(QCqy@B?v&##udWDVDb+O&&*pbz~=l4|px;L>NIYjsz;sKQ;Nik|rlih8mf;xnNUa z&1644FuZv)n6kXo~1ozkL6VfZ65b?yOpo=;0gwdmwOzqY^dj zsDwOKupP!FIXx}0lKTdNl>@qf17OmgH>svKdMG3)=?sqEbZMLe zSFqyEaRVgD$1U6e9Y7$k)|xXk$dRX$KnL0jeP-uUfo` zM*EVc!`B{4p+RB1kbKsI_Pc^Evv;6w z)X>r0yIw{*I7invH9)%^sM;QOV_F7JhhdBxuHcRLw_ChnY;f5j`nXTQ2M0hZ%ZqW) z!XZ@0-LY3x<3&U0jlu|SmFvKUb_Xhpj1bkyC2!{HAt zqKNPFS01hcn*6B=du^Go>KUX*V(+Z08kD^@Oa6G(C`)+18Fd2m;uvxYGb!$DIb?N*+uSFJ9L*6Awj< zpntK{%K?%^Vy%3|don{I3IP8e?r=vf^jkL#?j#d%f7(*mT*fc(_^j%uqtNLEpk`)F1 zIrtSd8PXgk^rJ2i#Aq8GryL3bHz?^1gaTKQ3GErxdKgh>jT8((;5K9!_&W=tEFGGf z8*D*%hYr7jy_z;Nr~Y9f>5LGDDHVdIu-fE zAbzorif(?#bh?5!HU_o0>3pftEwmrla-bOo*cnRQD;K)Pe(pj>43YzVV@T(tn%iJH z4dZJuorm$7%n;oPpqkYLL$gfs`gn-$1<=GhlbkTkzBUg3EG{J>tr*Ns;3yET89Ica zB?YWn+;v4#7^rhFsVK(JHTZ6B?ko(-(8Zt>$J?EUbm$5l$J3-R)V|DVPKW8NjcV1- z5VRbEggR$C(|LI|(J657nnqlbIq=GrFAT1wRj@I+6P>CRIHixtb!k9OWDUiD~fLxCs zYpV2y`jdp!?r$M@m=l{(QXpTtF-h(N3`6OvDR>jA39h$A11s3rX|8UB7aef=Dx6k? zUy>@WY#~Twn3buMvF7AJweSrG*znQL13{y$2@KSbp7<@AENMYEjD=R8`09qz1Mx@)I};7c*i%@(J;>iTJ01Fy zLg|v`hktyF{iINxP5_;SN}dCBDD3Mt8OsYri4yHmRH*qZeW2nQj@^4Zw{)ugAh7|$ z$blyW@S27)UE5MKh1WD3rGW-z5RM*c1=Q9%mEBP8I=Iu8lT_UY>+0t8ivl{>h)^(H z5YU-fh|+sg?s4yfgDPB)qdFLtzhxfANU>eH?MA6}JQF}D4XvvXgL$UXe4^=Ku?k9? z;hM81U*DC3Rn|jQQ6p00z#*W3!PK#1XBB^lF5l#Qf^eE-R|N%ph?u(K%3>qlLum-+ zcq==6i{4zIfXNYgQZY|oq0piJQ9;kZsH1>a&)Afi+Hi+}N@ZOPSHjjTFNRH8b>aiZ z?L+;oz}CZ(0@^y+psI!2ooAIMood>KizX)@+_a;!Nzp)DkXM;-M zZr!7fz~xjXS%+9xL^!h_<}aS)`a!j)JN|P>>?d5^oi($=!~!by8jpH81vB1B$h!LF z+FlsvsJfcYLza8rR1a}=9uk^|eyY#Ghd{@V?K~t*j69&IPL3gm>4xqvkdf3)`7cj1 z`f{v}Dr!)&EA^k-IPt5{X_dMFWnEbhe}+9x93#z51;RBWMj? zP3T}(Dw>jy_v=q|lm$G>3pgdfy?)qze0JrXt~rM5a_umZ7kX+XcQ~i8INQQ#>kb|r z{{aKoa5Y$SHM+-E#1kvSoLU-&ShkGUBTR4?8LbF$rwRi6)R^v!9Gzv>J14F%& zxdsM5!k7}_B4c&MX=inLggXZO-&*StUUEPwQJSru=bh-lRc)~1!)Gvk&oN+nvMD`+ z+E*5)v%LuXrGs5w$$hwdL?IBG4z3?Vp;2g|0rz;hEg`USM^R%}p8!doOA?lec(qH1 zq6&p_G=qys?I@3QmCz`8c`9k;i4+`MNh`%f`$&)@X1%P@lXxdOjSZzNtzhP5N-Yf> zXu34ffupj#SJgSC-Y3)5Lp1+~SbRyD==f7<#L@sa@j7l9)788ao%)h82Tj*;K*&SN zXkEx4P@BULZ;$YOv!02=XtBtW1XP_i8g_I%Zd38Ku*P~W*NKiPX?6?k3x}U^Up+Le zvr&n~pByqr3Wak0BhLS|5OTc?agi;?r!}F`Q-7~dHiN_*jnO5ihHxlNS7>6{fd6V4 zfhC18UR1tvFv9LV>;I6p}g_(M+m_#FE#r3|`M7@qp%9%lf1Jbo&3oy%p->#q4pHN~F zJdfo2F^~W5v;W^GNc4g$M^pxhu0{BmV zcu=auzi*S~N3R026yJ~AJ^#%(_u0cG{&U2SRoe5vWAhV>C4SFSbfk&Jc7FKBiwY!u z&efV9nG0KEz8|NX|Moigy}Kp;uP19#bb_6~I(zv|5`QmBe>|E|wxy(RG< z$MG+#ODGY*e{;aHVcM1u6b0)n6ij|LN?l?@0V%F#p6c|CihIf6V)*)A$*= z*Ump~?>EyW{sXt__~ZEgi0{Yq4*#vZ{j{qj{;^v$DRG-U|3$w|dspH=NAbtj+4*n% zJVqQpa$-9E*fzML)c50b^WSq1Yq(vCfBXhbirj9Ge{EgvM2SC>_=y1iTLbn#R^q=+ z`H#G7PyfD;O`k6D6W8nXJ1;KuGc)!rT9_L0_e|i6d52X0}^7#3PonQOQ#D7ctv>4_8Q9J*Q@0+_y{K3SJY_{{izx$I1C4O^6 z#~;hE_umiSE)mzSM^pL5pS1JKC*CUd--g3<{Lahv^gsDoX;?~s4Yi-hD*^o5OU3+e zqWLF&h<*I&anvo(Nb%46ipp<NygBuG#ivI{Zf6tVA z21)!1s=rXSou4`T;5ib%iR*u~oxl8sDOD1`h4|qycK)b0|GP%w-@@r1Yv=!K&!TT6 z{{2*b&Nw^&qQzTwN&I^#{@8dszaVs+xPJV8hOWQxk#_!Z7vKK56#q`*hmNxIf4gP9 zC_g>M=|9@eKkLrHqow$_exlPK3fuWZHvLkW_K&L+*z@NTyc$&mt{i5b43hnX7TDFPucMHisp_A?WCmWAAON#$G z>VNS7{?eVh&XD+jqxy4BvB#fQap2Js|8gFG1Ng6XkNhd|*AqW9-yZ*eUjOh!i9ejg zzUb+8e#sG;;`)07k6*=hervzok4o`x=JGGG^Cu5X{7>Sq=ki}@=XXE+E3y5(#N{8r zUvT~6U!?d?q4JBD+2cR--E+k8@V@JA$~M~ z|J&vBYbAaq3~-CJybH&gmUci8z|zj#61zsUGh z$Dg>u&ae6){*aXZXDI&gm3IFBcFp=i;wM;sdYvm$rzb`KarLm@#aD{*=l9Hi!_MD1 z@3B!*{Ban+@fUv6&Oh?Hlf?0(lJsxU0RBlsk1dnpe~I|<0DgP76Gi>`Ta^CLf9>h- zvv&O|DgN-CI{(oC{;VrL+$`}^-X;E9_V`;5|8j}Mznb$O#P2ofMTx(T_~Ezh@$X1^ zbhyO-}o%gG_|2v$)C+D~z`(E$E{(FH4|_-78L@=Ms`KmEMLqW#aQa6=^i;sN}h_qypzDgJ-O6g?FE z*dG79DXZp5{BVorhrh7%R}EcqvBZy){22Yt&cE}JmB&f^t<3+?&cFStwrYvLn948o zlb!!|LxwnhF5>q4vz`BXd%7t9%;>AjFZPF>pM81jMk)Ou@Q z9)FKBpBDA^mz=2ii2(kVX^)8VNB@6le&hrD{>y`Hqt2A_-*b)TM;F`q7Y&+nyu=?# z@jJD4{yDE~64yVgzS8lB-muFrA8lTLnG}DBJscd zSSLF1p*{Y6w>=~7zn}A+=Enlkzu(*+MEUy+n*U=T+2fzMwC9IX`qN&g_yg*%t)_m0 z#IM?_`Qfwd@gH-}l}}6jeLm5AXPlk?;h#%I`FH#C#Lu(W-^`x(i}oA4i62SW<8R6B z+FMHhSx@Nr69M@jvUyWn;vYoiAMS0pKU%SI-XRkI2I~LO27CICe5CkBiQo1mm0zQs zf8Rcr6-fNOsQtzR_~*v!ME&jR+bI5z?eU+}aMOWO{5L;aTkQX9-qQTUk9L0Lx|=SS;(z=x;s^BK_y2X5DE}4=*8FG>d;8g$w=N;Y zzwlYjj|G(fm;=&FB>pO>zbMQfu_NvIAF=y$$#+!?dfm$N6)>b_zxoa%NcLy zpY+9UvHz?m`8yG^x1V13p7NL!|9!-Fy4d-reSX~O5`P+{Kh)En{u_=tLtK9@B>6EK zz&|kSYf=8ZmHMA^f<68z`@S$jN`D*4|Dj%X{;d~ejFtEa;yXXv+t1A{%>yLM$E)r6Kew>%XDR&? zIND}=`QOq|(=72vQ2oaO_`iJq@beP?Q0l+VM0@)0995Ab@uze8Z{mOG@-*e&y3==v z?e`3xKf2rbr#qjE^Y(e(txF{ycm9_jg(Tn#4cnBh8Nl#NR)%xWB}IpYk6K$bauw2Z;MW^QisA0^;9) zYPV zr~kw)@BUNbFQfT0y2w8MyfC8aZxTO;@*k#X zuf6=P8-7Nq#NY1+O^*ePA8Ru|`Ap&uBYq^H{hZO`7jgW}r~HQ(+skiWO|vLJM~Ls> zEAhUcIsQK}s6n(Je(C|re?a+X?tNB;l>b)hKhc2lpWAokc@qCkia!w$|Af$uqW$`- zG=4kj_V)kB%e}9c;{PkP|40D8>AJbO5}&u7V*&h~4~;ID_+L`~Lv{B0yE6NPVu_#N z`70p){40+U<)3c4kAOYJ`({tvotd{!#|LpE!EB7i?-`X4_?{LiTT;sN8wSGV>P%P;3w z9e;G2J^#miFz0P4{#iSy{QB9)&tD$BPTc<}*h%pR@Ou=D5c^*p#UBZ%zn;&(BFbMq zU(@kBJM8`E^YsrmO8H+&@`ICUFTcSRJ4F3K8tK2nL+s`E#<@GkOYsk<^d|!9@8Q2&htr2n1IBclFsH?_Z50RNSfeiY}Q0&0KZcLU1r=9{jS(ti~7pU?sJ@*DQq z(c=0&lk|7-fcA6QUZ5!#?*HhQp!V~VJ^jxV{2|(J#;E;7SJ~U&Y2BynE5$$XCmnw* zp#0wW<(exb{?Wt_y=PDVdo7==llZUD{1-dgp8jX^AH7E6Z{qw1l;62k=PZ)=xm5nq zfcpRRs`cXj?+Gw}g!{nx<$(6Pao}O%`t=}cKTejt{5I|`7$l|ti%)g^MFRM5#s`V> z*H^Uv7z^MZd+m%lQv4OP{!Ik%FPrzmEQ!B_#&4&GJ^z;Z?#E-7F^S7T}c7~Mxo0$K!o&TTu&wiKq8-X8% z@jLQ`eg1#%l%uYb_^(p@v19D~^EZ5SfW+TU{Kzr(^ygo5uDJhpKh#qYQGzd7%{BkDiyg81W*{_wB%^53vz;chAapFsVE4uJL_z#n|&H!n&2 zk3oJ313&beJ^to5pAy&a6G;Az1uR5q`1O?jNWl8(se7*!_pdME^n-c7|7Yr7R}@|@=Kt8|G%NCz zz5O2aWVBUE|3#Gk*a|y8^{GB>68}@0f5KPnzl!~T7sVev z#~%Ogi8ov!5vf`$+_}|31%G#H9SsC;Jy?e|!HswC_A|{a!}=NC3a@zMDk- z-D2X$0{B0C^rE=_$tU~kL;!zo=JkJ<@*gApS>hpk{vUgJOr6AkgY5_V+WEhX`F@SW zKk7DJfAIkQ;bDzmi29p1sr`le+uP5c%hErP;{TBJKhXgG+mD|s_TL1@KfoUU-d{C~ z?dN(LzoG&BJ?+!w_1AuS{*I*E$KMNO zYWiLYksV!J^rWDCX4n1D>(nX?EHacXI&!2zYpEN?DV$tkK8&*+`pJa=}!dk zD>p6?<^M9ye;<4Nd);w(PbvL<-q+<9+277DEXuh|;@?R67pJeCzv!|1#rnG@mD+y* z|F*Bk|3!+wCPnjO{p|5~J^!j3B>v;1|Bf7B=RZB9UbNr5p4)$aJAZ2QUyG&qpP}+g z1n^&Y@@297vZ?-J1MKntH~!}%Qv6*$qxv6c=Z{%?h^Rjw!R>#Loqx_FadH0KLgQB= zfPdGkUx@3EVYGi18*Gn%_<3iE`k(J9{>XuL{-l2l5X-N3NVh-7vGWHk_9_R{H(47KyO?m4nlivNA;KTeyS-?nhoy%K*H z_rKTed?)8R@%+;vsDFT8;!QjM&Abfp{LBqB{>R?8^S`WlwU?Cs^`L)J@qb|F9~B)a z@*~uKBOlu3zgIpuUF5ePtK*LZ$dAV*9==OTKbtKkzP8I>MMYQrSK|Lc$qo;-^Y<+} z^hAk&@{KzEu>k$q-aQXHPvY-8OY`Fa@h5igj7t2RcPRev?dh+2rB0OpUZMOaF0u2E zfBA1;O7Zvpi;mxExAQaJz4Ua6|02u(OYQCN>dm{w{ofZ!|B!gV&M&QaZu--e*ygVoOi|fX8@I7EMWW?@XkG={pt?Z zU;S(^zl`Un-zud)Lj5m%wVi+ZFWW`=HM32ZebCP{{L8AFWO(M zr18t?M+1RQj(hJ2>+$Z0?|q>Ze-XzYkpDOD9wO?`Dv2Kni2u_E){5)T9O}Q(7JK=J z|Mpm_l>RXH{~9~LX2`Tv5`QR-e~Dl1{0ATWMV$Yq{~Ppg{Xzfzo1I^{Z_oXu`12|K z@oVh-gLjVYC-JYO@{b>8AO9N8yhz+XybIb-9MT_IWsm=?H}=~g#b33a#-D)tzu~a! zFO~T1l>bBk|LEffc9;0)(ERHhU~m7w9e4U(694CiDE-&k^Z#Svpve-ylxX4AcK+mj z;igH!e(N2!-?`OZf6>*?u9x_sb+CUj0A%Qm_VIhbt4o?C{>wCe#Qw1J*X{V?ZxX*J z#2;WmNha(;-_ra`F9?&m)~Q@JUm9?ulr2%W7F*X zE4tq_O5$J4>&M^i<+tIuvEusu8{WVB!_IGcZpQIa{4F$pM|RrzHxFA~De=dzqw>4n z&i}`yJ>Qi0dno;p>GtxgZO<0>Utm{P{o(=fzxMg};`q~Rqvl6$u&4izrBgna(tjfL zpU_16_;dXu**8o4!zljf4fg!UPr5E&;uk^x3lD_x<6%3$=IyV={fmv%e?n{Q`5&?P z{%%tI5z4=Fjy?V!C$4=?;!mXfht9S0cir1HEb%u``*n8N)BnSw0#W{o(fl6^$bZi3 z!$kYV2Z0}j@{din$G`O1eZ~F9Y?y!JSbvY&+s~k7`-}T8GuG+$n+VANyl10yj+Xcr z()<;^(O!S&Ev^^sm-f*36M4iQe~%wB#PJhewNk&>`F8&MtM-WYllxJ!BLU^N=Hc)` zQvQeBq~nhtZEt^dKRqq#FLH^W2q?ch{{t8F2=d!Ds=w$>_VSNjw@lnWSoJ=Y-=B7V zle1jZpSFPf932GqPiySu-!i*~nI{3kv!b%B)sZN!fSq<_SuS)%>q zdzAn1NPGExcJKmm{C|P^Z}=8_`a^x394Y;WaQh43e|dMKnEs9Hboqtuu&4jDi{}+c z@rQZ+Ilw-C_CD`8as8f0>33rG{J%Exxc8;_=dk_K3HJHp^sW1e>#sAo`~vt7beUZ& z#s55&Up!#_zO z^_B8}H_0!d+wAj$T+ zz5IIby5l&Be{pZWY>B2xM< zrv4uZ7{3bldq!M86jJ%ey4lme;;S{H{_Qd9f3bl0&#v2ZrIh}cfFFkPkKSaDfBnsy z$4UHM)c&3A_VIgF`FG;}`7NaXi_Ege|I^!dY?k7`i_8BGd;2}`Kix(B%M(0)2b5pD z@92?I{0{ZM$OZQF4|yf!M~VM4wcp5YJOAPn*Oy8B52^o!{%OzuW1*f`N&Gvw{co`I z$A470x5RHCnlsQ||F^B}EsozA>q-8aW{-c?wiTlMnMdWHm~Ah=H=mwVD5XDz?jMcq zW9P4Wea)Q`e-QDbciPkc-D!Qr{qLT`bp9g&<+r)`*c+tyzv1(vC)(rRkcgE?{DxgR z{@5%#|NE!fMg4nkvcHPWw)3Z5Iz(K*9lo3Df3BT>Zr(dpQu_1m=&C*to@cMWiYBgM6;GREA{AP~7z#jkc6>~-V=NGzD{QtJ|_Y}N+ zi4^}UFKK@Gc{{)2?(A}j|NL(h|6%s>&vA7c7be%AFLzrr5> zO{32i<=>mm(frs5J3oH?X3_p(MW#-_^NKzFWeZ*s^`CdM{rxF+{>f|8ME&=uu2g;j z{F}NQ`^1kiCGj`)@22`++F%=Nc_=*boygg+S5Px_EDnzJm-8Ge~Rt=_9f+F|Gl5v&uRAb_baIv z<>ve4AD*yTR_-{G8%MlX)KdW^96C>^MKXuf5H%k0| z>vjC$HhcVczIDmj5`QwBUsFH0Ue*8OeDmKAukG>|iJ!~!_sw>G)oD%Q{I%(09c$!n zd-}Ido%&BH{?oTps_(J$tJiNA<-Y+BYkndi|A%HYel5lSKi>bj*B<{#rK833CvQ;x z69N2(u2_&E#lMX5@8sLdKjVn6ME&_{;>Rzs^Ha7p-7dxd_|LlhVvpMSy%wLdTH>EU z_qQhk(%(P-&d(%%=I1*8=)dgcUzq;VPKm!_z2-aj+4<+qxauc~KZ@EQY z{-+Q>G}s>hg_piMSc?A&N`HKsef|Gb{6TU5Wf7-8Kz@E}pCvCy@gL9q|L^wtuldWN zqW*B*Eb4zLcK$W%*NF1_EnI(vcK)*8-^-HHKd&#vACUj-UsioD@dpm0_A_Xq{s;X( z#rXSX4J;Ie`TJ1fM*{dennsEBpF{ju0Dr@w+isHLUosdH>cIU80sJ%m{kQ8S{ujAA zqt0M^{!1#WMEil$dHuMbz5agu;=oN({8!QZ73ps0XTE%;xPSBy;ybB!{xK8&6zvBd zhiVOD`33OLJABZeQup$Yw|F{wJbH|Nd(Ad<_T-xNE?KITYH8~BIT?UZmG0GnQ$t9nRl=!Q;{akIYznAV>eY3mvZse*8J3?D0>2x%CH$A8OJ3#NGD%AAWrOW{F=&?;Az# zv-3;e-?~NOIe+2mWi)^;@-~Qi?&q;iT(jR})UjLW8a`i5WzxG%izw@#^ z{@cI$e73|N0`-T#$SZdKU+1QrEAgKqnscnZ{onOT(M=NnD2hLJnw|fj!yoQ0@h^|5 zU{`>Z69e<*$ef&IV-6h{i z@pr}c55Gh=JHK}KEyqjz8PI+dKcN1m7Ckvp;=fASHs41x%kScD;nfmRU@TeIsmiQkXv-@M<`1pV;}wym7@GiN6c<2lzAZmod}-QSF&E68{OB zf6e=4O#bA9Lr+NjuXy~u(7t~EHus&gB>qMkKO?`}`|r_D9`d%tui*7xqn-c5Pj8Fs zpF*C0AGVi&_tVGyF2%o!#-EsRKaE*_hg_EZvc!+aRP}|-`&mr>hs0k_`Hwzh zFaLWQ*4`rVca!`aG46LU1XRUaHH@oT94nD?8Q{AU(iB#wV?#8mVl z^L`JL-_Yxwv!(dMxPF@ew^+Mr_(6?=J_m>|H8SeH%ajqQu&$Zn@oP@b!Us~->IKch23V)|J`MY zSETr-Q2&nw@b7y6{R)X+#qG~HUty;InjLRsO8iTy{h8+@On%orOYfKX#gzZ}WA^sD z`{nv4C4Lo^f5bRnV8*|#bgVf4o=g0MalXLh|FJ3OpHlp5x&Q5LpFft)m~p7YKa1L* zX`gP!|K^6DMg40W0fy5Z-XTMwduq+>^n_ff~QH2KZh z-9MD#FC+bnXt%^ zKN< zYjJ6LZBs)@jccIA4rHJ;ek>bkbql2xHI!7>ls8PTE{Dh3hm|zejy`H=U42t^U2RFt z$ns_NHPxlnO(UC1Dvug7vaGzKq`9W)sL?}V`RI@F|I5}YiTVF!Z8d?c$re^uX3s=} zsuAwL$lwYrtvomW*Kka&YZvCTCo6SEG(rZO!0s%&w4}5OjLNFY!GukjtIe%0Lrbmy zGZT#2oDspy+VZ89&ImT0tDNXGHkFhvQpEr^VqEOr)`)X&F|V4gRB!H918@m#&rZAx-NJ ztd`io3ONJvTEte!9lAReDp_WhEL22I&rZu15r1Z2qMCQQH=<~!r{84RPam6`Hxo_O zLn+tGA{l$?Q^U+tXQ$81EMUy4vNhuiCv@l%D&1MvdDC)+VTps}p7wCc^ciV+ZFEa~ zr5S0c462me!U>@AkeTwcrf20$%jKb%mMf-173!(Xb+%bw%&1K7^sJ2hp8B+02(<*e zg^!`;y@ckGdPV4sg){}~bmS#69<-NII4dr1x*3^ihKlAxaeyV@zmTq~{_5*{>JhNW zex;Myt#PfQAe7o)snk9)nssL8T&UBibGM#)=A1MLvjr38W}|#c)GrWCfBOR*Uw26P zD>6RRL-CFB`6%@i#7Fe#wVCr({C(u}1?_$@KTP~YNuM{Xo~v6eCT70IBrG`3Yyops&7A=|4w~Z~QX8AWp#8)^BdI z=N}v&+3YuYoM7-t`#JG18~rXmpRn=&E5~>Ae9Vdex^E^=RPmqoOZhKOHUBvAKcDwA z&JWq-C#)0vRDMqUZ|q*yQN>>Z_Qyo|j}^P2a*(^)tWgcNLirVzu=39a`vsyX|D~~) z&#e|8f4`sc--YGZ-Q9o2*PnYxYS z(c(%c{y?|5^Hux{9|pdj?)-YS`K?v_1HOU!69xao?w35O;$I5ScYGeOpKJ$6|FA_x zz8+doc&)1bUJUjRDEO(~k^Rn$eOgn=pZYrJ-!De{txBZ*xcs4`E{Ijh@4XJ5t#ppF z@pJiW`t~{s@)z>9p^2=@2<<1YW@ z`<4V%_Up6?ZO#cmVf9vTV_7`8;b5z@$ZoHGnyv&{c-6gAn_5c@y6l1Rs5x& zMari*dEz5_FuB%4D*j$ffBzoQj}RZxx})C3=WDk7XNb!|38}yAM~RQYps8B^ z8(Wq>tm1Ddzdua;{AJK^q zb-Pl5^QcBOZJGYZZUn zuOj6e3F`K<@wao7^*3Mkza-zO|9NBiV5R;8Vgx7g(>l1Mx6n@0)~s$?pc?;8#`~|U z;r{!OxYB9-^+dG}kE{4+0>38;{^X+XidEysm)3#YK`~mQ97j3HAHLR$<7eCW^B?Fx z0#Weaxu)rG75}YJexAYZ@>gD!b)|}b9Qc1A3jR%JexIx2*TMfhL)_)R^X!#R0KaYi zDxxa;38H$Fzie+SfGPZa#yb|wA<{5Jm$qW)3v_kSQERVCkx z?bir*{o612YJf_9(uaVMWY9Rl_b zjJET~6QiW{A2|A^>i+q%t#H8@cm5Npcb^3QB|5wR{`M%?KMMZKTFrT1#sB^H;6G9D z_h?wWR>eOJ#$SOb_%FNZNM9BIjsHOY$GYeLp%-QzQt?;)0rDROf6{$-jZ^Ut3qt;* z;6Hp@=QI`nWgtHg1^+W&?RiDT|I!)A|2X&jKk(ZVO8cz=`+1_^AAG}|=_>hGpMv}= z`1$xFqvWO$P=9Rmccs{WD)_noug&vb2lDUY{(Btj|Ml+q|ESq{zbf^QgRxH({A1P) zdsW5n1%97`pXa~N+poN=%Kz=?{|bJd|Lo5HzOBlCi}jHI@%H?4`Tc+R;USQ3oBtc} zB9y;^pSNEfPJj9dv|o#P`_&cOpESFCuK&nKrngktZxXbB9tD3az*7)hhd~fcYoSQ*l~i2cfOg`1SAqT=xg? z+xpMTs)GECu(gSw=l^}*Cnq5P3wZt~Tmo`4?fg9dv3)ncsPdl-;P)u_dH&Bm+-HT# ze`f)|Pr)D7NZ6%$pz1zV|Cb8S{Q?SpF8}o_#$O2Xm-6}NkKO|Pr^RTgAC+(a$8u`j zr{c%&Z~MG4n$F6P+i&ug)7w?{!|(3~3SzWm_WX(S-&m*7CKW$^zcw)2&d=>vca#^O z-`MJ(`Tg1(?fhK+*{t2|RPyorvpxksm;X`Q!Gl!t@%yE|Ibc8b{E7STk53$WPgQ^M z`=tQ|KbODf!PoOu^3Cs;&b7s-}t`zn|udf`9FzjaLA_t^LREhXwAi>(A}q@R7aAD*NO2 zn|ycK`MLl7ddn;vzu5Y3{Qi$`k)5C0|K{NnYOC^(-%s%^vGa5JGbh~msY*V6zrb_9 zouB7_)}h!vs{G^k2LcLyE`LC9au=0+bN&5gcKJO2_m3Qa;|E*$;rjEQ<v`Q9}Uc6I=DH6&OfL3lGmjsZpSrF|dg0#$q^4O2LZeHlTSUXSC`Y2H9; zCIn(mm;}4H@?TEo9EhY6kyRqPQjIXn68bj_qB8R=!DJZ_eb-8Ag7H`u1XYw}WN>9T z))IozM#*T)iXlL(rwrGem02(&*NjW`h?20_9amJ$%bb;4kU1qica}Fh6N7lCV0@=T zP@NhA;!*QwOiA;4v*%9n=H*V$%goPrjLY*VOCxuth+XTc=VoVE?CR~QPnkX?9C$b# zjoDWTk%enK=0ilB8Ab?EhSO5hre_Yw&YT6Y%{_HXv>amelWrLb2d2!nI4f&Zk zLf$&S8teUEz4%%q;b}$_Fs$lV*G#&|5n*=Qrv8qHa^~l|MZnYJwvX)5vU~okn3CG^SfpI{RE%9@1peqe8(!M|6ARjAFQ&^=0Q?_ z`TmdZr^?~C8<5ajWuIMyFW;~6{aiWx2kK^j9~%>6v;PjTzfZTkzw=Aw@QZR6;qzY` z{*W=kJ`^|LsU&{Y?SX@_v9UJ%3tyG?m+$WcqQ&oALoiBO{oa%Ke&n@l=Tu19adOi{OKgT%$ z%flJ$^uFBWcr0JvTEjd;>+_D2_7Anqp?`t2 z4}D)fa9rpwq7*o4cz-e*Kp!0T%zIeA+T#MB^j}5wmzA#@zNR$}3xj{R+`Ap)yOssk zN8 z-`}eJD=Pf2BtEUr?2-2uZutCsyEjHZhV7e|wQu93eM0L8%JDzvkI)@=szx3;GqT=v z^#9a#hIxYg|K%g{x>Ya{3CSnhf1kNm&QF3oC+Y0`<`^HBl)By!C%zZ05 zljG<4HiaV(@blHXAKj1kDP;b6hr{@p^GBkCP33_dlE!viG!XSql}n(3$a4%I_^y8j*bo$$}2^81OjzKTbVZ{6?>0UP>F_zO@C}l5=num$MEmQqd=1$?YyojTMfu((*d2c_l;uhnJb0>$ z**>He8Rj9-0%ylMhbZAo4AdLU&8Rcvj64y zOC#BBd)aZ3hsNI+^Q>9FSo^TpVf?c^lHImfiye9Cwcq++`%uc-hc{sU3KPFS;{4*O z@NZE5C3ymHsEu|1Y!mznovH8zQ4Z z|HPkX77Xfz_Ah1rIg<2e_eXB{a{4DE<-_xzZ-M%2%zyp?{XGi(Ie!R9{u$2>OkTG0 zZqz@8`A?RE{%-i&82*K=mOqF7U&{3NIn*yVe4oT8+HvyqyRiMC@$DSv)@jz8Ns5*LQnzmwxDH+)^{O(d=V?T69-14V{;i2BDp zpg$(wzq{dkOs??H@c11^&Hnds!#qg%2PD2B$Nw~c<%ZACzc8=!)hho?7%X()<2TM9 z)>Qm6*nt^0cWj9E;p5Mh4()>*et_YRG$xj!eYEvLGTG-DhxWk@zm~jzAu-Eeed|-R zeA)PFheQ9knHU|Y&hT#^GG{8{Ypj1Pb-*uiz@@`~{&|7=2rl9|dbd$mNozOqYh8THZU*xWqdEeIi%=*Rjf78K#-0sEW-K~VExwxP`^B&Kd)b$pTTL_?7*!l-rLZB5}E&e?ohwn@HIC6ygTnSt{-ok zpZU^&_8Ii|%l3!v9|KH3zFU_aXusk5O=zDoW}hZtpMb(XoS(tj-cO&GJO|ewY|rD9 zI^*+~%OS>Ie!tQ4q3|E+ejGNmPwr22b;_Y8D*Qt*f#3mr`aWM^e{}fCQWD|+U40dP zeqcPC%EC0U8o%1*fAB?_e@G<XMxx(u-{M)}HKHo_)Wcx|}W84oH zHUs<1^;dmm(b=E$mtwTrvcA0;?eAsyC(-`_Uzh8%2BO4g-J@3XiRB})edh1y^dkGP z@sFE*$nKqFx%jhs-QH?gzWRE@JV5m;S+)=S z{*LoAIL*%vEa|=kpC2vrvi?yUD=y^z>4wkGC*D?kmrDOJ(*ODRg!40XwK?p-J^hxM z^8=}@e1F|5F692>hJWtdx!bKGI_=P(NBs-A{h@pV*uJs)#rdsR`2RL`;I)xe_oDwB zO#k!V5f^g(#ps)XSavV8{Kvn0ep#edcKP|D(k1YzF&LjS|MWWeC+80V%Rl(t15B$V z{i4H7pM(BMg|d8uC#IR_yA{FM9Lra(ukSgPW**1avdc@yt3{rj(c>=j`A7=aAICqC zc>j1t9CrStjzwOP(j@IOw0|nYzy1)kKcGK--^KU6(4Wt**#zm4N6w5r@h{^0ng4t6 zKD`Ctx5+RWe9}Iy_)PyB&O5(ArT_U-UG6`w_%V_CKlW(JIrJYsf7r^w|K0Etr2a%l zcG!;VvnLtS{9FiLC#f=FmP|#Q6EH zU&<%?=-v`sKPky8xaj=v=mzgW_LpZOWrH%cmz{xe77cfAR@Q0Dazeemp@BH(RAihy#m}dxoo!Z{H3ApVnUv$oUP<&odLLy`~+%q;xjwPxhhmEyVeamf$}Z zOf@0s{RlUF)_iKanjQHa$3Oi3@pE~9$Dfb8;p;L(MB7}y0iVAl1!VmlAm>jW0!Q

    Q?~pdHdsr@0EHRl0IK&KCWLHnjd>i;{Tc;8XCX+zK~Bo-*Lm|{8l! z&3{(P_JQ}0ZutEC`uYD1RQdmLhxq}{FU=4lT>l3*y|7=U|3KOQ^6`%wKEHo&(0Rpd zY~MU={Jciqzw`Fr4WImmGBoe>jBZ%J`1rF#;`93pH~c_-LKgIeS$l6n{6zMAZ8!8U znCSa7J{kX?BHT)xRQ$?iCqrkvb^A9!`vlh+<}qr2o^ojaFAZ_3|G<(E5$VNhcYS2q zr^qmm6aH?A&+X%e9~ys2IosZDj^ocH8o#xXC(BoKt$^L}jK$?ZuUpM@KRTlg|JNE3Q=%3np!#qRy zWn_OAf1;aLIseFJH*`Vl;u^hC|1#PB6Mjq3-vjpN_wS8Eoa#RuzwX0>-$r~-kzq0r zem4jExZ%IW#C}rc?KxhELv4{{ivXEOaFwbir@?EIn6+P{nX7c%`jJLrEI2W0zn|3Zh~d8pP@ z#1An1VGj6BiP3=`uM&Bp-8Ez1G40RV=d07ibq0IBa5Kw)BpU3cM)p9Dq%BH7|4d={ z#V~&Jf&cq*MEm2B!o{I3U~S_>E32#P3Vm@HIKV<(K`7CZBJ*;ipJ>L@)m0gF}Fyq^&T_GgIXF_C@fY z0Qe6d|GVJ}6qr{q(KPL=UaM9kexk%LmiQZR{-HJC$BOx-z>lIrxZ#uDEhK*bLs@8_ zBwgYUmH6*M`Fa4KkN@59`S|m_8Zlk5{_^qXLFqrd{<`7w@@>()>10*;ek1Yu_}>km zpWnT6nfL& zB7O?P|HYyG;rxU{w2b~py5Yp>VQ7D?$S{wPeQtJWKi%+yto={8p`9P?U&i!b=FmU7 z;iHn)I`Heb)|aFI``P@@=aA6=*q^@t?l~^n2jpie;-QFS?IC}Bu&rsI;3mVohU}9N zfZaAQK9uF_k^L85QFo7d4)HxjhRHe( z+STPhqJ2~T#`ZrcP-K{AX#Q=iod4wazwzc(&OaV@YS8*eKSBTWJZ_k0sC<3&e5$t? zANoEO1>%OE$nbx8ea|guA3pz?Ec+LJ|LcbDk@!SYJDkGrD<`GM{yks%|NF(zK4bl2 z^OLUl36UAN=4x*nY=6A#4f6!q=hq|RI^&;o^N;7d=`7#Q(%+!_ zBli5oRey<3WU*(YIsPYn(!b5O@{09Re>uL27QdThPbw`MV(KsLpDFEs4*IVE*q@KD z-0->oES;CsPvt)~h6n`=c7NoCuS>m&-15{l=JQ#qUu2()B)(tbQ+%l#K0m*pUveX? zUpjlf&=mdu3VZv{`AJWrI{lF}yVr%6pnr1xM>))|y5U>|xT zAHTWb^Y-uV=U3c~N}P9G}d1l ze~y&(cSt}m8f^Zv3d7^OgiAE|w->)pWW)bl&Tkv2SnqYES*ariFt{Ue{> zFjeu(_iIkm{Q3B)=J7z3_;X~2W=ML`(mfcz9eTdAMA~PLY@anbFYGxa@+&21T9sr2t9 z@%j9N8-A+Po9HK(efJC6KUMZGyQKZUE{5?lwx6tjcf;rUkNd3?#?RaApZKLv#J^qm zkMC%7Ceme_0qYcRpr~!p?`G4=jT6M zadMH_f3fy$kSt%`zHxqOh7h?V^iTZRx+Omi`0Q}SUgd88r^$F#)E{6^6 z6Fwa%zJ1bC)ZZuZseDJj8v~0E!}fu|4@8N7oaOJ2>?)#t+hmv`3BLo`|NIQ0inPCU zTT;(P`TTm7GsiAM|J2y{WU$2N{@KTd7`o;Mp z(P5A5Bk4CyQ$E7-O_BanBA=fw4G2zt|L75ioquHo2v!%D1dq--f%x?PuV2Q${RZtb zrr;0K|Bnd&_n1e^`2m-(rsTG-tT)@YBEvjP_PI^^zrn`;9`h>aAAY{t*`J!B{rUZo z2ii{$_$RkN=eJ2B`^ytwe$o@)?_NgsC;jgf=CH+oy5h%0O8hG$=X11=hxxzZ;Qwy; zW#=OCZ#fY&6Yb+;{^@t{PtG5ShI*1p~6(7yGHWVh`lGyfd-?kCrw ze;Uj`H#+#IE55W(vZRgcy=2C3_@sS~%l2)3K&Ym_CEEXhT;Hj`P2_6K#4Esf86j>FBb9=C9QVyk{alre(9f@T;H_;^p64b&+*bfPl*C|!yhF5 zo^sV__|U%SKP9aHU55Q{JNQOaslX3JiNBD5B^}iv-t?amzhNGs_H8N6Kd||8H~pzx zNld}~>Mx@HRKA42hQ>c^e#Q--pa1*&4MVX0mazIe-l6_-e$taD*FSbztKlmB*NNh^ zwf}DTSCJq|@148*R@A?g=|3I&FDPH${&0Q zkH+(}%94G1g9^c*u`X>dX{}+Bc%{)^8_VIyz`2Cj~ zKDW>JyC)Z^>{CqsFW>L;$oM@s{H9WGB4<9_Sp(bWV3A=SBLCkJFn4YDM{f9ZUn;m^ z_`UOhIlrWBGR#AS|9(JR!S9dU@Ka>FEVwmo;Ni48&_1QC{V4(e4}kr7{MA5Wbf7%` zXV{?*W_(B?^Us$Y`Y$(pBQ8>K&$PB?d{G&*&whvgi`zF6P1E@Eug?3QYiN$&*z>O+ z9Po#8K(^nF?LU{&N;Vqi87ki$4)wPhX5U)3CAu8$Fv<-1(guld-1 zLa-{YUvBuVn85r`=PX74_p$Ol77!Qm`!6^AQ4GKFh-2dU9V_3zB|i6mH+-G>Pn!## zH{+{)41c?9A9(xB`I)+~3;nhwHLY>-8Z6&J*8V>&*GCHMnrdF{IYAwcg<0`;13Pvy z=F{s<`>!+1Gvq&SQ2WOE_mPaB@3u&YJQ6HCX0ESZ#@dHs7+-n7e}Yvq1cRI(kYXc2 zEPFRkZ#hw*vpdcy=H`^;S_@I7+` zzAs9AU9g3IJKyl)VZ;v<8Rjvj`RQ4~%_8F4F=1<)4JtkN9=gSW#hhR@IU{wrmh>HqBc=^R>1{>2TyEo&d% zum0Ii)Zfqg_x0ePn7ICv#9_x@gPj>3Y*+*B&(}{|K=zmMr5+hy%J~_b=3)9@`}JJ& z{moLQ|4s+}-S7u7f$bLmFvzUGtpDBDTwKWSU*xnVLkaH|%D;;xz3z%f%=gE2S$_}8 z`djNLT+klge?KYum%!09lcS>eAK#j7&JUz8{M}H$Jb=%~S8n+H{NR*EF<8Dj^Up#m zUs-=?eQ(Y$%@878LjS~{Jug2~g#KB`%6Ftg{c^)kmiSapT0eRCUikiBeVTu!_W5C4 z=*|GvBBRu%rU-$&vH?-BN|sQ+A+{xZH_Y}3E$p8}uk?|(|P&-A=OoVEXw-HF!k z_my9T-%{d-{70^@8+=aQ&)A{OBZN!z;U6Ev??>45@5IWN+UF3B5`Um~>KGM%sjR=G zKjBu?{xwHDgY(Ze{d1oa3KBl~O-1qVYF2{tlQ#T%UkQ9FUww#Z7id1w!91a-Q)K@h z?=62^g@2}|XctI-{ebZQit2w$o>8L0U$rjMKGZH$6#v;znmw<=Ka2efB+{SosT{;v z`!Csr=-H(DIKOSP|Ht17UXCBQsbc>B_^010+lQmSsqrgXzn*Q@J4>biROvrle zLw3uEBV-q%oqqr2lnTGh!9M_P>+W zU#eFX_0P@A*X>a0|E`?B3h6K7yeis0k6t!KS-v+P6&9fKrE;yP{;mFq@u~Dre39YH z_aG~Zzog%TGgSEBvi3Q2A5g*Z$#w5q+Yfc-t6#A?Rnrxqq5u&{bR1&}I=f~Tq^dBho z=j#twRR5AQ6I-e9$4Yz}*ZSo8#uddM(e&FVRQNG+en6ip$K@Z1a;PXi&EInSS9boE z%9ZHd^_$}QKQ{kq^`$1#4YEJkUpf7&#dI>~pSk|?<@~epnHcwYWSnwE?Q_%SH}Uy` zP5=Ak{GPr~=&i~4>WbpmxZ>yMRQOj(`|$X1H~fG!Yl)=m?r(FE75`&7Ka(u|hrWBK z$@uMx;{W_gULO^HJBd$r_f-=As$FNUSK*KHiwyd{67~;N62JJO?n_ko1Ev1HZv?(a zu76cg`}}xdrMdny`6t=`qp`ApvyVsO6V>;g%dz5RWjp7F4^zHo zB3fm{tZ7z!kBmP&Ajh-*IdXg(CBB?))XIbytq zOXRAhlV8Q>Q`|ojUlUgZ8;bG`$oK&_e4hlKBPl)KB>ex?^G(91_W%F-`6kD&?DI{J zvQw%Um$#{Ur*8ajjazKw*SCZ(`M(Sw`esztDxK%C7DSOt_{kT*NMK)*#FsLuv$Z$Vy9JzsCtDsOg9 zLDsCywzKlRX*qBx>*h?oRp^SG%*>3NGxKuwskyn?`aDg$y48gC9VUgqGUpTw&73L`<&_-7P!ig>}Xk-{Dxg0D)z@bAk@EB)rW7?>t-U3Y}cQj4v z7Fn=utObp>Rvd^dbD7g&GN+_S#dHIWMaj1`Rn@d%twIH9^$Kr$x)A)q+rhfiF}yQn z`joImreld(;IebmXX>Qotl0&bb9(ACGSf0b$EJr|tRO8b+jbb?hKIGw%t@P?ota^( z-Bb4h&V-JW5TRR79bGhZDt)?e)t-7>gw-*Rf{-OCf zn*Vc}=OtXCvEwqaf3xAgUW0Nf@nt*Zm-AfF;=fa?T0<3n-Wj34K!-R6`FxD#D<~h7 zOQNJV(XA8Cq^t0~u)aH{SXpAm-D&1N&2L4EU%EGKg9^XVX@-AKFx-D^&Oi=P~>pk@k-k-?z4HwhDiYd`~I{JjhJ)K9=lHRGbX|l3j={ zxTcfx`D(orf`{Xi-J`8vo+qC?tr zvBrEAe$C$_@%@#=|Kf_RKdJBsg`Qst|0I2RKj5bS`b!$(`|-B&J@&rfB>y3NqS4yF zW^vX|75?P&BkkkcE!#Kw{EhbA^#9@NZNI4S_l4pMgnj7w3F#lLe>S=9RZWGT9TVxF zgip^uqqWbGe@E<7;diN~#;>UV&w6N2Qx$$2Y5!3FE8}bY+tW;wQ$29A{~zx>gYS3R z{O49^KYatR_KJLj;!wX4^(3>O_&^x3* z!zVdz_Q}h?5T6g&@cSgF@yYIP_93~WT6goo^RYYl_W|P9!`k92W3@zh4vms%{CR6* zG5#zxlC;8)=_sLvucI^HjrAvk{`I_ad`sUa^e+RRX(A8Eow8k&YZyuWkNOolJ9&MV zm7xD3uK!O%VNAFxR{Ix3sPxyj*Va;d)h3t_<@h-b>UUDvXX^*xpR1kmjpu7?`W5c@ zRrVgeM}`0UlVInEW3^Tl+aG{Pb;5 zzVUJYHU6#N|8|86e=Fd7zWDF;FL-e01Qq@%#Q*ZY$A7rVs!LV)o}a)z!T%n=?9RXb zR^h*03ix0D_xKMSnf0hRsbkFEWKRpVr8MqVrx6GR6W?lq8giCbq%3gn{ z@CV`i9wh&a^6^t=)zomKM7Tr`*9xpt;a~r^;P6~3@Q*Y7X&$jOGf~5h65$dZ{l?#o zRQNs_|L(~W_!{fyL-;?{)JkEaM7Tr;4bu%3{_R@?N6-a7aI&U`8zsUeT5Uwv_9}dH zeifOX675=f^Q`7vs}w-EMC<)lx=4jT>~+E5?=0+-a!I8BkbU$aRW#fv5iZeP@9z6a zh5wd({u%sQ;A4E8wH>|2VVpv^M7w|Y^0zAdl`?)aaDlk5=Jx@+!zz>NCM8^=FEwo3 zMuq>B#P{7Vo_|&r|AwM{JyiHU7~f(tI;ru={+@y)4L3@pH_=by+bi3Lf297wTs3~Q z_PKGy-}kEY$NMi#J{i}_?Gtey2KQo=NN=L=HlC-fU#D^W0LjxylyBgVNdNJ`i&~yf zW3-a-b-cM;k_6o(wper6PrA!!k>cgZ$a{ZE9$Qk zeh{#6qeQqwr=7a(hzj3J_Mb267sn_6DZHz;h8rcqCHm$M>CdY0@%|AL#V>GtDqp;h z#ElZ+60Q37`g1D$58(dMOy8;P)4L-fMpD8h`ti(1epKO?QvLD>|6dF+*7k?&6U?oq z;YNvYi5`6N?iW<}LBc;J?C*qMHnW-9u2!ZBfA<@LLtiB9!}TZsNx3>f!;KRCBl=d{=2adSQedM*xJ0kt+hVZ_-<+QTrhqJ8j!*3m&eNE4HBtcK61{upMO{_+I6s3) z-y!_d2_NTaaHB-HM0a2G{sI-g7wyvs-Vf*}{D;rewCq8Mk(6+W4tmI_qQb}dA51=} zKgV~P2O?ae(>L{ArNU2K1K=0OXr2b5|K<4GQb6`+d^XJ9{}z1QBwK~QQugn@4Ql)3 z_cXI-`ysuF{&jJ`^(y?rw*;%tC;Xr5Kj&f_w0VGVL$q$g&MJJIKfy%n({TJ~?SEU$ zpG{Qw=KKlZ>vCSBviN<+^o&*E7vcOT;>-1Ex;0n#kDi;WXt+@d*+m{Wka+1`D*SgP zzVEoGUxOHahpvPeNjZM^k=vBx=c#i3C-9{3pL%Sb<`IPb64n=hg*0)a#PNTAzg@CQ z|1JVn^ZX_B=lGqVOZ4w?_y3!#9)4Mc-=|DyC~uw;=PD_2{DI@H9HPR%WwYS$EfV(O_|(7qc7c6h zqr~w`uYOP2{>a-F&A&z1hvN?eAgo_ywP5@Vo2HFc&SEO2Me{Om6w!?4glJCYO_2xE z^D@&4WGo!cxJ4#Ca##D{!4|JqQ>_2A9G}1Ufc8Z`SN6&8Yf=7vYXwkv=1S~STrr7R zTf8v`=AW0P`VI3C&2QH_4dZXX=j#vAot6_m$tT*oR?D-h=d)ej7j0LZc~=De!2C2* zK2ds3OYsDxFX0mXaL_(npT_q5_lkM3CJV=Ri&G<9qPI3!`ML`K)qM{7*Awk^wEBO4 z(Ur>h5YMk_e4~Q+eHx!r#?K_&>R=!F9G>*or93D5f4uZPCH_s^{tHF<8bqZWxANW8 z@Z1)a{flLMV5od0uAW#i`*$?jsOLVf&#Y11m_X}Ee1;wO9Y{*nBi=;5BF)m8eZK>rvhM}Ly%W}iVXoVi(r-xB6OeIuRi z0kJI{hL(yjeY_BM>*sBmJ9zeT>SIWRu4a> z!tVw6fpYMvedGAdeY8z2PWD0n;m`NIIDa_RvVNG1PbU6o{bzQ<8(%{E(3##(qVd(& zGQN?%A42cp8#RSp{CfmVfErsU>p03Lza-i+>E6vM{DfH1E)YJwhpg8UxWT=IpR6TH zT~zpS!D)3>_>cT5Eg|2(CqE2IeEnU*kI}}JqyI;je1P$XHv7B|?T?uxKJ|zG+5*?u zNBHI2XY5t_V=DX=ZwUC%`}Y)oo+xnr?-73a_F4MQPqS3`jgATY(EH62Ur!Ra!S|!X zZ+-8r%~beTeJAik?;m#+?LkoD>!pNWzJ1>R?8pHXz5)0iFWg_q_mAoQ5q}+lYkU|T z{+Gvp$M0|0%J=CvBK0T#G3p9j|3`#hzW*$_yirhvzwHNUfA)U1UQgf#_Y;2k<=b|5 z!;vcdTgm=%yhif`cvEFk0|JNpSzER%j_S6+tiAKS|JGw5G1(epdP*Xs-1;KAtd|LL_3 z*9W!X-zUe1^!_ouCmfXc`ey<^QEQ=I4r1J z`L6ux9b8|{hHuFEE3yl%gJWDIaQ&Z?{t0M*(U^lhsof{qq4frQKg)*S^_Xe?(E6sd z4vyYH;0C{l4!>SP-)~j;|H|?u{b`+%pv2d|iVpvq!+VCP@Fz?EBz*Eye?x(51f#=$ zX{Vv=Uxv!(;F1B{2lXRTB`K_P_{pWPw)Bb7Yp3rk?8PiwyZZ?g?~i$ zkAzR}u?Ho-evI&StuV&ffBfe)pQpl~E1wUB@Z~&{{}O>~d_(x<`)Bdb?|z`dkCF4w zbl*tp$QYLjT>rO%#>3a_%gSkg{(QOdA1ZvE;nO-Yx-M{o-$jS7e{}W%75)?Q`7-HG z{Z~-p>)#W8jMl9j{i_x{(MW~AjrtdwkCFY1zp=nIeh@T4i!Zl-S>jz`}NdVq22uiK46Ym|hC2IKl zHiX~n>A3q;_!z$tg!c<*eQ1vF6u)693RC9jt70)ef0T zm1f4J<6o!yM|qjHVDtPpaQ>FZPrg+I_eb~G=WkD%geO8Q+w`I%|GMwwE)CdlmGMiXMEm-S+UC z_z;16T|pXzFyjT{UH5TH;AuIQ1s`zrg&Whd;Z6Cx>0TDDZ3@&|$&g=fI?2L^3TkLr zAtAgPz!Y3B0Wk7_k!2)z+B5=-%oRdk-)cgK&RzaDrXFvLWv57Wd$6_jh>X*QNbho1 zpqQvMcXnES!AN{!6OLhr0QOL*dp?vISSd3vPj3Z3xv(Hd7KFg36=db+3^HAX=(;*`S7=+t4}yMA#V>>U~{R_!li_`Y%c|O-#>I zLiTdOPg`?nw+jE2y`s$G%+iHt>1_Q1nt$ZS$?inEw_g6P3cv1cOn+(bAfuu2!v#~# z{1GnEzDsKrtMDIrH4>lZ#Y1+9(tozrUihR6zqBwC-==qz{?qcExyt94ZT}H9hU`!G zCr*^+QOPbuAN2Ld@wd(Yz07~e&bsu=keyuoXM5kp%K81_hoS$z8s}$)ooGI@g=`2Y zALK_)`p>#`WGb{jHvOyP{fYVfK#lL2CC9M`rrPRZtbDM ze*~WoS@8AWD`%fgH~!UFh5rh)&jAa*uafv1W^P-d!jJzQJZ(zYKEX=je|h=WFRSnm zV*6vk_nfYreV)oIo36rt68+x@>+i25eq79$11kI@V1J(lU;CqS`akyUZ6{RtUqk#v zz=Cf?iBIhWwQoO6eC!`+-)!&a?|2dL4~zHzW1*;tFBNxWO8lyt)=Z~8$S>^Eb%eiq zN{wME{F$YI|9PxAk6^{8xVF?lyjEyv+6B|pah@dg$z?<8sqB-S4&{4Sj7IM#`~Fnh zALDv4k=|l2{F^!O-`OhsC&2#$i^BN9DDg=S*(Yi3Rllq3)8s9{|H9cmp4Z~FMCcma z>{E2hr(0F}V|=Y|eXLf{-Y_%kmvOe?oQr=LcZ-SihLN`NJ`Zl%;YJ*my$juj!<{qS zvD0h-+`Wfx>88V}nOSf^a!j2)O}^+169;&!mnPptcDTib2trt8(Rxz6Cu~20;vL@d zPE%$hFB4`cfXRG`IBR;uB9k|TbC91k9bU(VTVTj>Zgz(11m+{%{zkQ3Q-1Gm%>_Rf zIZ+|kTg4|US)s&wSCItNhs7g_dACdCiQCAzi!=H)8+C7%f9pym50*7Cn5J`()T zizD})_DC+#_w*kwRmo52BM|)EME>zU#VWtecsOs#?*amJ5-g9?WkkI{?X01a|I{ie z{~NV@pDyiR8{UnBjo!!h!GGMG63HbxAid{dm3;hu3?^fZX#e7&AGPMcMI1c8nH8&f zcGWdEs{e&M>uR_;C6Y^YpYIjr`}tMn`w3bjk$-$XWR;&n08$Xi_id@I;pUWxjcC=t zn&(yd*H#MzBVW`%F5jphDIwi_VJPyLYLDa+9o(?)aFzU5gxNLy4t4&EFNHdJAV%}` zfc(Pd2S6h$Rx5=6xH%<~OZ2Om_bcBoy<@#V2)M{k?Fs9Q!A9~8_>Y@YBDq8-Ki6xv zD*rFh^VvJg&wolvZ4Eb)?}7igIVF-y^o=unmF2$(=65i83e@FK_Sf6OI%u$w{1o_) zn^PjWMC)GmM| zVI%n|@E1Fx4~ z{sEAM8_6$)|F}6Nl1udJ?~|@n$?quT>$A(3@9ze(aRWfC|0VDrH>X5$i5`0X+B;P8 zuafdTca>lMfi94L*hqdU{Kw5HkzAtNmhJzKNk^)PvMijIiOe=A;`r{6I!9*rhZzKO4d?sS}OI4JZj&gd=vd_Rofd?`JXQ32aDAC zpV2cCJ0}I^gW!E_w?uM@E_vUhe82Q&>3{l0wfx{kLXzGvUc)V~dgboFP9%SSl`8+Z zKBSp;{cr1E$?JPBQOUnW+CSis|2B|cYbt3b_I&l@HQbyM*`4V2udlgQB_G$X#AN)B z^WXEc79XnQAAMTL_Y|wk|MpZ--epJO9b?#n4~qRl_>Y@YqI?rg>%V5OO8$)V1crZt zkdJuQ{)ew0@I>Rv`Csg3Qzoh8r(6&9=~9TFv#gJxlAlM)&tPw^#=IPAO5IAo}j)#9AP~p261V9trCeYW>3H7nJjy zbc86$p?uM}gN}1ba*1Ag{~!2##3p|L%#$ zyjiQEpJVY~Zu<`6HOe>9vd1Qrs^q^pPvoEE>%}7f!FQ&b(3D?_i{~_2`HuunZBofk zlksU}e>eHMjFTcgqLn|tb^oO*`TzNqmA}NNd{g-o4IP(pXVJ><>>n}%{NEOT^U}}Y z|AS&QTK|CJU{WNoKVOsw<(J}pC{8I_`MdUhhwE$G%%{*dsox`d zd5b54Am7&i?}znc1Mq#2U~9w7g3&Igo`9a9P$0FZo7+wDNz_=IJC3i|Bm*_8Tw)IfS zUjfe-d=~k^DCIAi05JiJoaNIvjq2b2DkE@xCfoQIpKk>|iG05bQAuy>^R3d!wL{}y ze70pwah_i#exjT9Z=I{ke;>TRzt0l?BcHR0(U4fn4{eO|PM9cP6&-)o{7+nS=zqKO z^%GJz2uc2U(a)t`tSb|-pWU;P`E{rkiHrRT92ZO2G~Z(O3zKi+p@BKy<2Z}4%U@co_T zGY^Wd&CUpi_soLNgL>g>o?iTvY$&z~-_c2j_h|CzelQ!}R>};0jdq5J&xySM<3To2 z#xq5{sAT_wuE?wP_n*i1H&w-d;rjo<2V%8B^9}QIzx)n>l^6e)_g#Rp`cz6`E;>SV z(Xo39RONT`IHf5dHTY}rSV%giA4P; z(ct+)Kk7gI=fr+Uu>3=EiC*!@+f!BYYkUXw2iDhdlJ9>z(?lfsME&Q)xRUhX@~Pa3 zwphQgiK_g2tcUzt`ft67y8L}ofG+9v(0>LqVztF1K>vvO8gT*1CEESN7n-W%|BdGR zPmFeahG8=L9po>*QsC->Xg+L6VBV@87+5u5PI8I<*vG4!zo<40_(A?eIe(#Frp`ac zO<>Z^U-%xdj9Z}Rh4OHS#E1TgKkvUePlNYMm+0*KTh*Zb48+En-`~QTK>AwOy*6ei zX@8#=3AoDgoTAL~T?D#{{Eqft%J}{q*x&a3tm__z@~al7Vf$>APxC{G1ywa;WL2$O zKR~jS^Lec!_n{D#?KpfNoWAUwIV~+6USXVOJCcLZo}pHJ8qCOrFOhGD=2{Lxa4Nns zigR{(N||QxXb3MYBO}lDW@%1Xo;MG`UVUl1nt^rOmgiv8zquUbl=%QewF-As{}`|g7Sl< z)ivBmz5%-6Mv3GS{krj2%IBXiZV?>1h7GNzMO*&H#~=?jk{^WsxKSdxM6*_YA5`W4 z11aCApnTtcC~w$EzJ{{Pk>6|R;S(zPsq2Ks{tC+XLs{cS@^#P!H%gRmqECNQkfD;_ z3C35L^seb9#rRWe{ks|JUjW)wy;lu$YgP@~iiPk!&)zl6Z9EFdj@3%xJZ_XoF44bB zoA*=6?NtXt=+h_{2y zy`K{rP`-(NIv}G!W&ginegIR@LH=NP4q;7Swgi8$JeMHWsXwG z&zJFkdLMQE$^TNHgZM|-sQi7~ARZGoDt~P&$i_`3l1sGRyyBTE`EB|LhM*<>&szTY zeHC2aT3-b5cd*5764x8>AGgAU*0%ZAcKv`EfNgA6{7rc9?F{k(-JRu8O));oGml1sE;{~=}kX}7l|-XOL8XQI6= z_f_cs*6(S|m+c?PB}#IM&P}SJjKBDNjg-GB-TcGzABuk)38!H@IE^F-nsPeXa>-dp^CAB5EKuMz%h{+ss8@6+M_esyZGI79QpU0w&j?i8m5-;o@hgddP66Q%Dcw2-*N z+SB!--pa!vk}Us`{c|&3ydC6U#OKF%Zvgo{V?y(rJ_q?Yzln+D52}|Y4*Vji*bDvA zJPFDF`qUK(D4&1dyvB#n_gop4ugULxQof0D`MaA4xisGv5-k7l{BOGb0DfQEmj9|p z!1pZjeNoE4beJI|(R+(b0iJ))Rp$~_`N!{@8V|wyG=n9c{Gbozn<#$w6cgG1z1D`g z@05R%PxSA3btZv)+w;N8aQqGNK{UVYlk%|+U?NKM%Oro(a5xF|kme(39BeYd50yJn z-!+GNsNy5$|0;4=Rf{!Qbr~N)l;)2)rFA&zI{v(zmw#YKk1HYnw&!Db{}(tDtNFT$ z{-?bAzu>9!!|fm3{{_m<54C@I?^g!rDRKGl4Zq_*D*1T-=Q#`O`#xUfn{zSg5+`42`ZzthX!;VSuc z-T?Vs<3jR%QOfVwRoI`Ne}oJ#|B&5@KDgn#`YQP)N5TG2gym~JqsxCq<=6gs{Y5JI z-UD#&QD76Kc+Ot=UcY=-va#K_hi`qzW*cn@vK6;UA@~8c)qln zKVN!32=<>4USCJ+9bNuQa|}~LFi}1JtH!(7ko7S^!xx9TGu~{QvTy@ z1dcISEuY36L??f72A{9m#vh|sL-|{tFKTigEKcfAl%6lPkjH6WlIA069#Wpxc>nwL zgLOuMd|UsI^KTv)o^&sCi{%rgb z$iD~V)A&!$1Bp>lI6emFg)mY6f06wkt-B}AhJQ(aYJaCUUt5Us`S`oRo8bRT!}5I< zlHE?!N;) z;zH{$Y5mmlab5ru$sdqvnEO8YT}5-p@P+TyT$-~W+(jT$hiK>m-l@cU$|^&-POLj6w}eE&OOk*^JiF8^!B2^>!^wf|B3 zNA&48H{$(|t^cXD0ouRiFE8Cbtm!#v z1+()q`@*5Ttb!S{U_q{|3_UGBr+wQIQ*X#jFBqJWnNyH8Eh`h2uJ+EJIy7@GUMtvB zXHU(}N|%Qu`;4^w8G3r&TyH^c+d=pr;yrG$uC4z6UHYxzoaf{gWa<>yf;;enSz7)~ zeL}}c7!E;sk{XE|g(f-i=3sHJMFh#2IGPH+*tXM6j zFX#brhJlL&rMP+GBdv$0HW;UhulpSH-wnn;aG^E-g*br3{H?2|1=m#5#(CsE5KPZO z97ezr7e(`r9)C5ha8l^(3fUW$m1o@a~ z{@;6zI{!blHq7g||817X-TZILk{9v&+cx>T-)|-PJpZ+}_jm&32U-4SL;igrpXQ&uBP*8wHu5=uTmEmJoHbUJ|My}=`BVE_ zRzdlnw-x12-w&t!lii8l*YnNsD)}{}|B-y}brs7$`9HnS?j--zxqn_z$zLMtAIUGP zqmS*j=nJu{2ddsJ0V zoBr5ACI2Hi{vrE&M^`NWJ~?=S2A8k!ZQ^{Y#>|a(v`3d>b{|n2PUznesuaf^1 zjDLJ9W3*yw|Hf1-|JTwy+y*TV%K zZ+~>q1rzz-+#B}b_mM*L?<9ZfX~_SoaQumPtUCX(iwzUcI3w(A?!eD!IS;4FI1tKz zH+ew|NsFI&da+gh)pGn7l=Yw9Zz^+;-{NY+L^4hY{Uoe5PChrF_=psFg6vOp@TWz6 zQNB;wpT?iBLi-=vr zxc|9hpSY0fUzvmaPdW=eznq^H=$du~9lthGzAi7I@_+d58UL}`pUVI7cOvC`uUF^a zN&fp%zVCbC7gYX4NzYqGtZ5Sq&;R)S{|dbSffUNWi+oxqL2$wCv8;de{3KqU@JdSl zFlgsr+f4h*@}DIAZ%b|P|JC97U+;Kz{#RxgCSvevG0v0lS}ocB`R54xlRWY}vj1m8 z-)n;M%hn4Vvj3i%k@hchkUx$5kClJu_@hE^vb#qrNP2Wl`)v!#4>12PtO4@ZSn@wX zo&O#*&XMaB^86bUME-SoA_3+PFddiigPWThsaF3BelPqV*Ix@9f%v0IhIxINgZy-v ze_AKaycm9xss7)j_J3VoxccPYJFW8j$nqcf8?4Px7#FVp6V>?-$-gtQ{9l%O1r7`O zWN(s7^oF62;`gUR?Jvn+4Dx-;!t%>1DPPBlBuGy3pDAlQNhSXjwEz0@uzc^N%H?1C zx_tR7>fKXSB|ix5PrxF-tdjBr$0Frx+U?=#Sj&6+Q}tF;bF&ND_M4qPGZVhbQ7}gy z7&WJ-o|l;h^TAWIGtGtA%UJr$7)C_ihYHlukdNds#2h2#z!Ea#Z znx7|8YY-tZf~Tj>wfk=rvQ5dF{y{&~P7s}UblByp_-LG;#pE9>{Nn#|o)+h7of7Fq zboP*;J5~B&{4geeN1-3a31c5X?XG8rd0I=nx0bn0*&+4|XV=nj+xVE+*Ot}NaNAD% z@~{&jy@-DGYRio({d%tx2*I;y<{ykBwd%*;Z>6}>Qh2u#H;OL}ybJGp!bbDFg>Vix zr$l-YZ9MPgFID<29w!id_lttYd2XwIIG=4zzJAs{Oc+)y9s4`^j!q z^ULQ#iviGTKkIWEd{$GD=QQ}N#wn3rMBDc9U8K?vpWk58<#UsYJjX#k>vJ63k9dxQ z2OJXVMf6PGPs;XBPG@MwpQ3y*j>u}iJ-QH3GPaI}n@;V?^>s8aY}DSRj)C_NVS7>z zuv6e#+?*2WMfBO8b(HJxV*C*%zl?jrI3ufm2{54YL3=`J9eWO$4@HRYU;0mC3|*Xd z8kwU=q!-by2a1*7hkEBt0T!H>Vg9k{*Fc=dHPLbVcmU`F?VSPtaoZ*JDg8V~!;RkO z)DAvWS%OH76JmtlLN zab$kPS^F>H6D{(0KLF2PFEZHrxPu`6#|P^xwU}=RkStM8sAP!lf%lK_e+wyUZ)^$Xhro4oUEyNZgSQSnguhF z{k}bZ*-FsQ7GG&qJ-czz4N--2TUKkQq_2dS`c9UqjzzEh&|C3^4n zcH2NdTm08sFuw9+!1_Y%4HL>YQ}`1MQ_V#5U-_q-JifG#XlHPJY^>iDfARmA`wlp( ziLU)&SvtZ}RImmMu7Gd>%POd$uY#~3;)4I3_58W_)5v8+z2LBK9zfwkjwtRnF@BcsY7$5Woit)?P-?)YJ9N`$-g7kNFh8WqI^m!%qgB(ft zCTED=waK5>*`S^=|2sBnSdXz`Chd7SP!8+TpQPhP4jo!BV)QV+9XoU!4Tl-vEs#zzbm8&4Z;CWrWpA2DjE`k*B=I4r&Z{pj%QTS-5Sy=9K_>B9Xh_2*Lkb|&?) zjMMzYD4l;&GI@Zyx%%GLL?Hj1f9vqf7PHt6ux>NTA^bs+Z=kk!(GOAi*J26jUE+Jq zQIEQ#b$Zn7R0k;LpW4i?PQc@PGDH{I9(_1N^dOJKtr=puMfbE{*p3BcYqw>Hy*(-1 z%aD@%_yDfzd|#>ci<_nXFg^z3L!T`o{hdYjI^Izst!tw77dP~GtDz@OMqJB$^p_)j z_=7rpk;n9}PcyS6KFpuJlk>ND59zO+|Np>Cfe-UnZH{klcSm3Ge*i(NTwD<8j1=0F5@!32c$L#Ol)M}tgvZDI?a@;yO{x_+= zDXhOqUz7d<_{5m>@WpxluV6hv5BV)LK4V@%3c=Wm5TY z1Nf}*>EYYmHX2`67tP22x>WkJ7+)6ChaTAcYY^XAj4zvtS$ub9a{Q8)0-tR6$-`D> zAy!}Ds4I-yVz$_xtNG#+tw-2D{6T>W_p>It?Fe6ySw7B?)j(H&e4%q~wEj$d$^Sjv zZbdo|Ug@aIIFGw84-#C7T6!~Br z_*v}BAU^y*`hE$uGfwvBkJ{Hq>(9i8_LX&;e$R3;qVpw=y0pL0xS=2TgCbu+zxnu= zS`r`Z59Q;ne9GS(A73I(e3)Nr-L3Nx>6-JNQ|S-5K#OY**%*ay-dxh(FFrnZLVEfG zzW4#+%VU8+f1UAZpJ4tz!}j;F)ZcqPKI?{x;Y%3!HjH*u%GQ3J@9FCAnU1qAkJ8^X zG86YDAD>r2e2y`H`atuy<*c^jqwvZ8Wt+y=V|@dM`k|y9hm*0+<=a+ zKlzkk{-S=ljqrJc{Q5=Qm|p(28l>~l+pfzgiz86~l~=z27w8EsKD<2&-)H}#m96lbvcCX6_onpp2m7o`?FXe=mnaB9hZvcw^Gn-Q=um5Z=^{dJMn5p{FERF~GCjW5Xs$l+Ne9;8ie>S;F za(s<*OSJwh8IBHHooSslZbzBlzk6CbDnw$k{w_)N{y@HhHm&(wbBQmH^B3dqmOV@D z=X)wA=YLRPQSoOm4p6LrU^D*-&PQ`R&=(kwWy}ZR$CAY2E8v^|UY^{)q_JbzpIo2S z{wpK7{(3wGzTYe92yKpcQHuWWX{{X<0(Ob~Mq1_$A!_o6qG&9Hrxdev-fpT=0MG%MKY5UxA^&f~C}kE%No3NE08v-=HU? zzpbsKF2PTwzifU0_PMS_m$4F`%lObg^ui$0-v>TEcXE3AdzteW`_=>Bh~|uszmF_< z7!>&neCH0|C)ej{Txj5%O!~7w^zm7@{WE;`u>D!*kl=J!>Rk2&e9+^mFaDvvKjMrJ z<9DBv?Uw*P?;qmJ?c^vh$X`p{l|7mG#&!_@lKLw#@Ojfne;@h!b9kTo42}}iEFY=z zHwWd0-yiAX8?b7#+@G#-!oXLL`ggqmK5@rC%ikVcKUY+LXY4rgdWkP8`8vwat-?4@t3b8d}ZFhYS{f)nm@?p&c0LY5AR*jDV*OnQ;geq?_^@o zdp1x0$EW$U_@A%#g`)ejDwF&~&BI~_XziaDT`cvN$NKBU?Uzrfe2DoONqh;$2fG6` z@j3k*l>+in-Ovf|6}0c6ANYf!UaroJ>91^;`vW#EWPGUqUZ(b+yC5Su{?)xJ+WzFY z5_#C_Oyj<~JL<~BHv#Rgrv@qiRQN3A>;H%UWcbv95+D9Ap#AbDwGR>jeAblo@V(UB zQ7M??#h*M?^RaFa^uutH#NsR9AAaiRa{a6%KJ;&VO8D$?{`>(iO?)l69u`-H`*#yv z9hI`17^r9}eAK0)4$zW0zsmXbjf**d?LAj2|Gm_|D>_$6=C5;idiqO_EB{W1*Qp6{ z0qf6grSmrj9tPdO_n@mz{`wDz&trUhxP0{4P35kuk5AllaPV2}{vKZr7irM09j<># z;wxc%xja8(6ybBv^YO(G5@8pKgPF|^_RDc?5~H9&%XEI=+7SU z_xN%$G(gajKP&f__(~by7S`Vs(x2$%<4YVQeD3vsk8c9&5A;xX_Nfw|nC~c`<*dJ} zNPk{$AD?^Q!O>sh&cDZJmh02^JpR61AJ3d0Q++krU!Z=m?oSUN=HCZde&tGS1dip!HM8{(v96L;pS62hN97zg+9T-{NWF+llX7Ue6f%*}>mU z<^4YgKG17^d0zG3qkRDT>r44-U+3eq3)9ozF?Kb9mmU&WZ-u;c7c zW&T2c_&*(cmA(P*53GMUEn0sjKKws&It@vtDKB<$`_KJOX)Oj(fX6) zvgKi`vk+TbJL<~gc0991U9|7Z=|8pj0qAdI&q^zT`a}8n;R#Cf1{%A}_{7Zg@VWe+ zKs^F{#hkxhIqhe&+;nJp=8;kF-@ydO4d9EXiSOy=j)G)mv5xI`>HDD;_rizL}2*hjIaW=$PZLmij9(%E#%;2;WV<{@mH= z=@0EI^ZOU`(c`=xfvG3p10VFB+}DdGKD>WXzkEaWixX2(BY9TzJDEl zFQ?KUaN)T_toSEU`P*PUg}B+*pO+@Sk`(#79sF{}m(&I@rtOYhdc7>acHB`Mv|rZK z`%T>9<8$Vwr@wYRbv$PIh5oSaYkB2YfuU2~3;&Y;kIIyfIJIAd>*Ete>EXkE+2(pw z`|>qz@KfclMajwo`MkDnrfUD8eSrFTatQ^R?Bk24i4XM)aHz!Sg!-kt{ukf^y}#C^ z$nw!<9+ltQe0=u2^z@g>?>FZ$-3|agSuR~pTEw+^z?^y z4eY1G_IDTFzsxTWANs{Eq=rM&W+!@xjKsIg&))SubEapEHs@E%`(_Tu#P2OM6b zp-_RM=-)uQAr|uWZ!Eq<`FMHT9ij0}cz+a?kp6c1>#HZy#E15u`TkwS?NfZ$nfVBW zjSPI3c8crv^8!ct0ACL2&kN|!ji;x-30!`$?hMjJzN1~33Lo?a+TgUK)&Etq{nwrF zxh<+B*T=Dzq=#=J*CX*K!|%6MM!6{uALQ!z)Bdlb>X*6l{d=Epe_opSp5gutlvAX$ zz~HBg@5iQ-4#2^(%&%ZKkz>B>ld5bBN_Z4sQLZ7m-~nC9f@?d3~293VcC_iU#qd=od3{Uv;S?uzv6Zz$I<;+b&yNca8g@9d&A zzxa+Ps!Du?E4BV%e>ckhpsBf zpW^%cVai{x&@aDUn)v={|1;iiu+O4@|FS^h%Uc-M-_8=kH_gZA@II?37ocYO$h=I) zgZG%uC8|q@GoRbl&=34U!3TZ(n??&IKGZMJpWOe|uIjg+#j5o37wzZ7)8Y3U+Rxxa zKfslwhDS!{4W~={%UkNGAh5sBD1Yrwefx{2i4XRd;P6QIE4Dw;OP3quBm6;4enD1T zNPJj74)|75`4!Xs{IwrSPk+~(?x>_Z{@z2n!+BK)T!c`vZ1qWFvwJli#*+)!eA|ee4p#_gRJ* z&;0@J!_oR{SXD=Da|(NM9d%{4|E}it0otvpzRzoOJRnbxIQ`G4{;NSf=>N=8AD^{4 zJ$(3nGsnlij`m+U{cG6_4EfyW?N^?Z`HTLccKm;J!!FX_{7Pa2=dYInpImoC9=1Bu zI;q_qb(Oe1TtDN#A^L}4U;J2-SbPQl{Gwei2JylE2JE3aD}c{=BwBwazLjhb)?+$6 z62|;N;4|$E;TqzC>Eg%Mjgt9Wy2w!+l;3kpseM5C3;l^T>ESC+fAKCl9_Yt_lkE2c z|K?vRzf>(FqfGnd#}W#$z|Y@!n)t9kk7e|~Ab;H)UH{?z100|QxL`WxfsPkQe6hHr zIMCla(*6SY>_^knAI4$ZEDw@9i^nH=_iB8p^fww0Fn#``cg~miECXNN&&mE4`ua@2 z#xmvO;wQ=ecKi6eH1SPhJHvMd@a%4ds;k(luKQv@M{r{a=SsX?0 zuPXE~i3GNCj_?n z0{EJDSfj?T;r#}DJ*a))QT_s7{C^3b#rS}K(2`I41@(vWF`L>4UbV_eeD>q%=@0ui z;yuR6iEQrI!n_~DOb|?%^~c3N+89&Hfcl*7aE&Le!*RetW&HtL-(d@uE2RR9P_lWgC^yZT|f zo{GXJ=a7J^k<0~nsEu?E7 z)AxCFEgg;|E@l+Y8**tBKDqy`JmTkS{mF4wL3~&z%4yg@NQd>J;)ga6(qY}G0`ij% z>qnK+wRBiV%56Y?q-*JbFHYCe z0blW96rLOo6W{7ZoxCV~M*yGw_xPN8q(5@NS6H9$kORH~@{QUkLgPg^#8vzj@so2|Cx#mvymrHQv$B$MdPJLhgCeS8zSbC;RIA zf}S+Tog5Am-^iZb*G1t||9|NrhyVMU_?pxVr?=#IokB_d3?W^WKKj12L57gdYDxDW z`Zx*+uRIFtWhkfb{C!4%v)$dNMXry%c)flC`xcn^>`vOh_{2&=x)ZoT6l+dv`jPv& zhW7Vb&^qnpq&&gntt<4M)r{t7lfwaApzq)K>HH}DJwW}t@`!u7{K|c1gZYc~le0F} z5Yl1&WRI?;%W9&Z$N3COFqpqsKhfJv;mP3uF3_1>X1o}MPwo#O4{LzNC$EF}%=JTa z=zSVYzh5)?gnu}6AM{VPo+xmEPAM6`CJLY2KR_Pw|6_d1PC0jW6h67XfIKW-*I!=$ zU+AxB*YL>o?dARh@`(Q*@KbGpQp89)6_Cp5shxOx~233W0-}9@( zsYmzZo;!uwFY-I?PBJu4j!lnc-;vF|UA!Y99f)v;EW-~Y+)VEHYK z1K&-+x1;|D^8ZJf^ll){omDpu~%y(*N>HTUu>ga|KYng zn*rO^zS9OS z$sHK|=W z%m05_T0wj{{68!Hy2gR>k=&P%=QjX{&UAmDB=EaUT=9y;C;0yi{vW;hI_2+dA7A07 z1Jj?mKjo^iI^WSx1RSaG#s4+z!(jdb-$pLK*gq|{xnlUPo@fxdjIY9llo9h>hPcZSB_g73leHY;?^M7lxp})e{E2h7;{GN4;@dlfFY5jp; z8;WC!`~|Id_Q$P)`HS+=#V8-KH!6k?|3NTL5&FY^pH?d!pQ$h40{@}m9iI;3L-}ZC z)Gs9!#P<`AhmCVR2YjcTqV<<<{j#h3;vo`W9@`(rZ%m}}YtQlDZv}5wOn-01I3M{v z3w$e@Yks`z-`CI3<0<#N=>_!%e9aFr>c6)thOdpGC*U*p%|<@5`6cTY;H&du_r6j1 zE;I7CxPti1_bl+?{eky#Dty3Ov_ixQUr_<)Fa8fEx*X0A_ zhhlF><3l?c^#$;y8jl_0_CeYA+gyJ?lEA*2gK6i?p;mIskb=S24IFvx&`y%u&KfrO zdf#i<;ES&rdv!Z&^w0_8I}RK>b_DG$((Kw1qsJGFA4^=T8C}vN1%W4MV@w^e*Oga} z8#+D^d|ZLWj~d%uLeHRXosw2j{X?%lq&1OvNVkKsDO+SO6Y>N5eArf9AszPnC~Q(! zNY}%r@e8!?NBp?D$}P9(;SZ?4?s&Q>Hu!gcjsSKIST*& zd>upLG>yM7H;fyJ9* zC*5zS>-4P4YEz%C`PTNO0dCMWPhY$w3jfzM{#PFMl^TCyYBc`h*XUn0IpELQO8>9P z0l!Or(gDBqW?dm2@O$JZ9q_x`C_K4T2XKQn%igdl3jd#s-x{Xzm!`m9@@^d=9q<=y zt0SaK;wL|s9Pm3I)DhAFe}ep^1OAd76d$=%2XKSlSh?|oQTU5L(=o))()EV?e;>5} z$a7y45<;U#{Ttl~U(F4<3DKgRoy4I^x7h3`|{0XOKqLpMhLKhNH%W3bLH z2R|ot>{HLD{KgL*q#n*{6V`vS z{8pp=OUc20imTQV(!qXg=|?VUKXmPo!#ctx6jr*VJ<)Z7T&e@OLHi}{+7^X>D#llw ztLUhy|5vMBi0d@| zDHLH4Kh}w~=2xTrWUC3R7wOQobXYesPhOM5`jLXJrIYz1$I;nzEgjaAbm>~UR0nW_ zetKB5F;V!NmgpGb9W{PAz95J{{|NfGwMDlPWXLx3zdU#plYj7kGyYE_%=*r_()3s3 z|8LmWzXNX2*Vp|LIljq~^~sU+@3@BU-lO-24&xEr3H60^JNW&Tptz(5;zO6>u8#QJGBlJ!@3DUC@WH+!Y_FD8HKwo7}W z!=rjly8Y7LsC`k;Unp1DTX~mz0&dXF$1b@$3je)4zQJ9h?cc;dyLs6D?E&HY@81sJ zugcMQ0Wj7r?El{v!uJSgQs4&ty6BS*QTVTw_D_eqK;xJHCxi9_`_0Ry`h{H9EDB8e z%xgjSw#yK*UwO_<^Dzv}Lc#=qqv9TD)G^Sn73v4(MqBXm5# zxwVB(7xQr}JdlEJVg3fDUA8>5GdTXYg#XX(-9@(3-rrx${v;Yd_O}E6tJ@4zF~YKwCjP7V|AqAc8X!6$?5k#t(|UmZR*iI2fH>#N1jdz$ zoDtJNEId4qz#0Qf~JDuI~2}g7%O3uLXrT(JgnAeGM0l=B) z>Zl-P`*ZMQn8I#Am)4omBWOR^pRdwfs(*?C``@LBe*yO|xjZfese9aCW__Z|1@!24 zaa0g*r{-IDAO*FV4?B9+f&m?vBFNLRK^l)!Pvg<4 z3Sr_z{dvl1I((wLmKSp2Ig?t<0RAJ-s-gC$7e$WpLH+r}ezN~7eEjyF^zftoW*Pdg z&h;et!1*Wl@5ecQ;9{6%i0OYw#v3Qg@|(r@QGV|u{d)oY;y>x(f0OYf8ie)VBv0$- zpW2Vb5`oUmzQB|AkMeAwIPtgB_PMTld zz8C6YI>q<`^p!r9zYgNRnCl;FIko?rXD0U-bH9q#KlT^P=XlNWZAf?N1&+Ez{nLm& zhH`t!J&(V$@jwci&3wpz!Q{8q`qI!p>_=|T>J`vGs>>Ypg#F)W{Mg?M_#5&27yEbt z#$2v{&`tpU0bE~!Z{dLyw0eWE#}#`|o~Z19g`+%xf5TG3|0nH_GFLjpu*;Zrvb>-@f#OG1@ zZLZ_@QsAG$(Zl}FHtYeZC)YPH))zPTJ+kmX3YyJ)$baKqmo5t05A@&g5^6t;_4ki* zOQZE~;%~33bMCw1z_%C4mk3CNM?-1Dk z;`?a)jZV@jz4Ifkc z;Zz^LmnQy1WvxdO|9kx%m7-fXL{Z>BjQQSf{T%em@X8S65Atu~hI7^aH|W2G{qNsK zk6!EVpW*(Hp8m0p3&za>0M-S8T_Js!>u2z@@IVR*{0P_khcoh|{(&F$f87#le+KZ| z`_jV?JBOYDBe^c>5dB^N{$#tF*E0kzJZI88X4p($UO7mvkDqKmz<$1=_H+Ck-+si8 z>EZukkE3Ev*M5fcd=~HX^z0|jxC@#7(0zC4{kxm(zo>}x?^H?dZ{nrEFaJx*1LYU% zqj@KV-@j%*xvQQMVmFs-`(2HH3iDGDi#?D}UtIV6*;4@Z z+$;0*peFw0IwRcA&%s5$(M~}6=x>Dm!@lvHNlpL3^Y>mz_={}DkMeumB~*W2Pvecw zb5s=e&(Zc{;!m}|OjUdr80}{hKjboT<35`&P<}S%w){S5|G?js^zR1ni~Z^0AKb=K zDY(3k3(`%Xox}K{$G5uc@X)`72U1WI|L)(Od?yNjUxI7VPkroP;-$bZ|7*)5UlRfR z-v1DO=pFQdBWBC}8_qP>2kJPV?5DDi-~C1FzY^mFmG~qb{$&59_Kz39 zFMdl8fAT$*=K9_Jxm;uXCvY*mG9)V_%=*~AOYYxORItKP9w@(s^!*}k^7Zefi685G z0}oOw<@yul6#CzutJ4)Xr1$*}yForRIc?RQ%6{hSc+mg9N`8Oc;^TLJPf!1;#v>=~ zYIWFt#^HODzsrCNa+jr*6bs?{H@s_{#Ea+PQQ z*^C?X?hCg4DE03yaFkDXZvWKYMELLY@q20F-*=Oa2j5wooY*@(%t!vWxkvL8FKGN0 z9!Np)9J~+hvZS*tzgT}4<@bf%6e6&{f%{i_`me_Qb*BB4ay^52M<~Cia=i+EZ2(I_ zQGW6Knzr*^QRR23qn-f%yXKMp@AdU>3!U$kIbKk+{?Fxl#z}L1^3>zuqXmHef&Y@* z&i=2&U&8hS{9_)W=kN3Ji%RL?M>%z#()Iup$?p`S|7RWgMVVjTFg`PXs+@DS+TSK& z;6MBc(tiNImnMG98;3mr|2g=t&GU&e*#r9qx!rXA553|!lfr(G4{Z}xm7x8g{a;){ z?VqW>{@sl9^q>5GGV^~fB>Qm#_(f)V_;dMt z$E<%^_R=`PhyE)M3iBaX1a!rMKjIRD zezu?f{Qg=-`gfLOB-iJ5t3>NR$7nyd;qNcgevaaCP2fX+745$@?dQ>N|EMAD$7TGe zKc6D}qD5vBzg;yw{9kc>80Y#B`k&CsQI}=fpUg-9Kjgx5CN=Tz{OvZme@_|vul_te z8CV}(R7(&4)k7SWWWreA_EGMq1t0c*snP#j9)3&3?ym!Mv$+lrJK^L6_RWkN>o)v6REI~tnEJ)@pcXEezW?1txl;dPv7&4)+rFR+C0djb4z zt^XPQ1HWUmOHJIk&*2M;>DYR0L;v5={&{W_1z76akImy_(e4K|?dNiSPkFrl4<{pr zFkk#IP_ba=8}D$`J<3H452T-vm|9aN{j7l`OEPy{&_rUOrh0*$V;?elyj6ctZ9J+$tfL^|2!4X0HrHp^+ zUsQhv@RuHB{Pxml{0YXNuKjHNY5EUA{IH+PzM}FQz+aqoVEXq`=wGDJzco|ae=7Td z-Gkox#hrHq@#nDpkN=6XZA8HS>m49|##x=M0OdCoey1G#up7|1x7WHph~H!T`E5Vd zi2?kv`Ui&JT@r2o?)+%`i8KCG_5<9YM>boe)(1rW5B$gcLiQiPUwV-7CsN=~l!G7j z4hr?quV+mr{TBg0-d_`?{Ri+DH#oTZPgVcm`#ui<4GOyl_0F3V3)&Ctzv}Pw;8g+p zZ+Kw%6DjP+PF4TU`up-*!193hX?nq)ApT;u{|;n7b^w3u&;!FC=X%mCzt)4={<9em z-oJ6iKitqeZejPJ*A-Yl2JyrGhe-Pm;4eKu{HW*4;OBhFHSi}G{}cc=XbIng4q0}} z${>EV&^U!Tl)fLm0RG~`4ov^4@Qanv^^Y}M+s_sQH*SF&wAQS{+eG0ns!R=#s{{6b z_<`ZKmPgm0sqj1H;U`$~C}AqzDxMg`zlz^q(`fxeJAgmd=)my1Dexzl4?9WPKkx&e zhMPPW@D=Da8(Q@a;z#)%NiT3WfWPzr@yAz0>)+vaMKIoeJW=bk%ioeXr#A7xe!!m0vr6KX&9n#=j_9|M3dqzijy6F+u!C zvHi59`qK^IFFnZkQLmc%PgD^9fGt%YiNarLH`#vxfALWVSN~#JwEnHR6|?{4CmvNA z#1H#vCfh%w0``CO!Nu>T!0(iUzmV%yQ169qp9S$3vi)qK??*d;KX%N)#cy-HYT8en z@lQ!n|D)ak-Ezaw)j|BQ|LiZx{sZ_+4>Ep_+YcuGL^=8|<(d?9<6U){1@ULH{=Xsp zdjb5##~zse9mZLm(?$L7a{ZIde7wJ`B5nVBm~Rr`26aC@`}ZjP4FzT3=z#rO2N!=L z1%9U-{5gg|L-uWZmhhMP{>s=z_8-6>YjSY$Rai2^GVSaVX|`2`2t5 z24>>V24I86_#X7Q8rg%Q@Hb)oV}1V83gS<-KL7fQ9gW}}t!Lmb;_)@sWtyJ~zs2}L zYn;CFMTy^A<|v=etpA&T*7^tj;u9;T|5W(ziUlfJ^ zAM3%TK=HkRX1H|J?AV z#*g)LV<%M%f2#HCF+TwPY{1cm=kb7F9)9=_{(0aH5`Px2uZ!{9o5+6b+5Y&Y(hA~# zqPfD>fWIKG5;=eUs(Ue*%j0O zM*OcX4%?5pE;R6)>q4iCf6U5l^Md$Me)E0|<1aY5V)(Z+e$?mCf1K+XtXmHJ=DOSI z;$O37P5U7JbGiQc*|h&=6~k}ZIq;iy4*X_$DGxvVhi5%FRpPe|`=2+7-oJAK_FqB# zu=DtNVf#t0N6q8)fWHd=KP_(@M~v+s&wY5usR@Z6{r}1O=ZMO}ruD^hZ*|lY#m%Gj ze=e6hYp?#E<>&?KbF3o;{kOP9$Cu!JZ!Lb{a{MnoPmi0+Mnnchc+ldaey<1dcVzp? z{#>_zP=6M*h{m64yg%x5)F;6Id~-)3a(Nvi=&>r7i^S(z53mmvIB>E8*Yfhp;qSdi z_=`%|e(?Wg^Yjd1&-3jkc1kq<31b}+2e2ljO{yjY29N~fgC*~u(kAH3C zy5O{oceAlWhYg)j(DItmL-PiX8<#isnqlp%>qd+lF~0Y;L$8&KhHL*Z@~)Q-)Xt)X z!v|k&HM{cK(Sx()65nmxw6I1EEVxu(UpDBPYet@I$#Xl4BkptU=%M4ROE0_hG8Md? zHDdI*ze&PaFdPbD3O#_XnDJ4QsP!9rcc<^KhBW`~Dy?_9&R8{y1N!>%sc^)TUkKmt zKP7yB{)6HB)sKen=hh70zg304ziEBZ!tZJ+2VdX@E!}r$gDCtB&(%*@XX^4K*SQMf z&+3mDHO)9Ve7~_O$^RjJ13jCi+?#E~{(J23eWS+V`$FR$zQ7H-aMb$jDEzOsA^A!F z)|!yukzO$%6OGv2;c9;20^D5jZ9_(fTf+_@sN8^dEHqH)yTi zH3miDfBiH4bi94E{^k1f!NXjyx~UcPrLma*3E!{k5WX)p?t76uQ3r5?zHt3nSyA}a z`X>~D!|R^NbwYynvy<#4xc+TYe{<@J0&;&HNB#kQpV@~Z3*3KvLKvObPT$9hXzh1$ zcI&V|?tmM#>!#K-qVQWhFbea)?_N#)FyzGL zM0fb%?b+e`4a39FH@!kfoHdf_JaRaI8}!v-Yfg*8ABX;V9)*ej|4RQB3j+N6Ze5ry z$L~3F9p!`fuRBeM#B6{4I`34S50&|OP+2cYt>!cTu!|gZWsbj%b<%w65U$TuC?U4C z)_jNgc<(l%3t7JG@%4oBI^H@oq>Y~g{<9u_U5-Cbw%>riu#oDE1~h-aqmJJ_P2Xdd z;FtSfxDQqqrQjvbJyPS*zCwJ|+)sXqj$#4-NmT8-*_k5eR?Qb@MC0Fnk&X%Y@!ji;`+NKthi&2q zP7^<)5HuuJ9UGW_fA>%|e;Mun{oMb#?MbSC+WYN)F9m+AKMee-*1sLKMI*2q>hF0n zZ*@%lkLF`t+&sqBox@{Y++yaJ@N>mXf61u!M$rD>;P(HXO%x!oey^Jot$!2$uZ;$( zn1P3r5icJW<~!_hM7HL`emv%n*%#(-VZOx_WTyC5u0K%Z8TRwsGgSUN(Ep2P92L|) zGaA1fKP(UEzqpH|?tw?$(5WWZGvHTe56r6qKa2Ud+~lY$^Lx@}{~V^7Vgm z#rmJ#o$SA3CDE7D6=y}`-^cAN;7_&wXLXhf^(t^;{bBD|DsXgI>MX?jmpkeT;bY7P z?rhvwop4Xke$He3ji?}b?_?y`ANEq<$NIy-Ka}eetOv-+h-~hMw6Zi#=s%I`s36|M znh&|Au)H4kzgrxU%@p$V`1;OEg7`0D{7nhJ+m*gwxc}U37p;F2|AelNN&(-8oLtIv zl2i4k=d-+6M+^Ffe2Dk3ZFOs_`3pS%4)tg8`=tNC`pI_te}*6HoItKj24Hn_)D`&1 z7l-kKk9il6qY*#9yTxmlOZ^ve`=LGS|IN7+;39whOmTKJeyl$X`$=X0SeM)EH{ab> z<9DAJq!0nu;a6zB#p?iD%9p0pF$Gy$ug7Up|0T;E#e)9#BFNL52Xwl^SidyCQ1j!ZVVu`7-`TGDu{PAka9|xPQ}Wr1{9drL7zlB*EdU^8<&Wy}|t2%!eGXr;7%+dsvlUu77&5{&!LNbp!bA zj_KjYdOrA%#mNe+Gh=Vj_<{45UXBW4wtuqD(0uphaC;SYWT~fw_~FZ@g~9p<^Vj75 zP3{_h{V~xg8b8+Wg8oOd-MZiD_9G`F_Hg|PKI}jFKY+hepx^xk8b97&r*cHlJD%_V zYNw}z__05$oWAbeU)f*(Dg}PIev~|bANFq<>o1)OJ7=7*pYi+`-%&n8*?x}un!EZvK z%cHX-T>mH7eo!ueANw!FJL~YUiyPSf5xx=QwiHT#pYEzt^40g3x6DyKu%BhSN&l04 z{Gw}m_}{r$$AffLq;%TC|Bb+houI$M+)sBC>jB{*S5-vF^n@?odN^wS?_ZBo`Mt@< z@1==<3b*GIZ0AUBD3@#SVFvF2Cx_4A2lfwi)RkqF7mNKt_Mcf_+J6!B5BnLpjJ}1= z%=GQQTYCB*j_;Ib2O$YX3k*K=fBRjI@{co4*wvj^GN0QI&_Bun=uu;*uTyDt&uc%F`3toD1AkW6Fy9jTfIr`g3!iP#B0_c2b`Inw!$!H4~P$~X}oa&0&8LoVP)xIv${x1 ze+k#07LRWL{!znp{3gyv#%Mm)<$#@M^LK%nFO48LN8E5gz1dR#iN!h|;9sVF!f zj`0Itn)o;KI0omLaQ&Ib?J?K`^oR0mwmcWC^UhMOG!iRTyHlTiCNq5m2B z&)H7(=k!Yc`aeCR@nij>0*-%0b4Onp>nFU`Li3?#=<_OrZ|SGSc9skMpV`dEbD*n+ zPF*kUANbM#b4?HW*D<5A7|(hTy`u3qtg0gh{{QxJ6vO@{Y(I84&3AZwwtk9ilLGG1B7gYsL<4+8%qwWrq!;>Z4v{g#vdKg&qs_tM1wdw-2H!TnLdc_Fud++Di< z2cG2jKKFk@&vn?|yw)0jj3dHxi1(dsP7m3BGuJPX@bk&bFrpx-LctsfhPajkJZJEFRlIW8j ze&`wH6v>@(fsWtA1N~!PGw2uVGI@9CbdTbQEQ8KJ=D0tC_K)$C!`Bdgsy|^rUYht# zd*jw^8E<tNo9w|AIb3%&Wf7KVL$a4g_REbsTZ%RDWt>x>3QTQ z-EXI>j%8{&2jbj6mo%{_V}kqM#*;+l^=P;$7s8g`)tW)kbmp4>HR|ERqV?eD0gpL z6VPG|gyek3os zb*Jd~^5|N+Pq`r3`4pbqF){6rbH6J3s^DUhhg?_o_bzH6q)T-`F3^QvuJxkiQ|m8M zB#A0I|71H$K7;&gxLK#*%&8)z%bKC@y`m~Yy65y`BEE>mppd(XJ0NZHldiid%AayKKv(0bPLPZmD_D-XG6ZXVvYhG=lMX8&zxrf z+$wOy3G#t{KeTm5P`+Hwzt)C)u}do^ANFx@-U`cy{{{G7fP6V!9EBEq$Tyn5qp@#- z6(LiQ1-U>!yl!->pnR~;YTLs3mo=bb^0`KSRA&%dm~Zw6?}U9m8Me=4e>w9jD&K!= zbv`R7Usuk*;+w&Tv$YnfCb+${*V;P4v+5w$cJ^gEiT9D%7^C{-7$GcP(Jj3er}Y%;>#;0 zA8?uLh2#IcS-)U>CGs2i%<@{Ee9)ItE}c5G`=KAnS5#=sFX?#;%`YkP`?m_Oh?eip zd`Crv_Y>m9_j!EqAjPW09*^*Q4&gJI-;v87_;|kxy#J2Y@xacJj!Cnb0ow1fdOrvA z5B1C1qbsYBcs~?4(ekD0?@I2Y@kqG-#JnKvqXB)FvK-(e|1z$06b|q$b(i`C`9Uw4 zIb}gq`)tem9LH)cm%CU9*<=JBIlmyjhuSz*>nPXdSn_;0L*yM@N4Xw0we4=D@y(U$ zD7V}q{}1SUiSDJ_v4HxoZlg#}uA|)Eo)q896uv2iC%67m3QtE#wK~e>zo74(OnRQ& zM>IZN9$ClKQBL3KHl)0Ud@s%YY=4w|HDA$BI8}8!Bb9u4uaZ3EAYb98Izl?gXK$<{ zq=S5UuTXe$N%^*teB>Zs@#Z>0I>-mykPr8e5BH#u3v^AJtY@O+TlbKD!kMD;FK*;t zGnrq3qp1#-@f&RRG@1arh zy_K(@bFcTmZ-e$Z@0f7Bzqir%v5&KabcKh9{g-igXGfNhPR>t~-}ea$E8UA6+fn{S)&4syr$~5Ds#Ij{bhYy;1qsiof6O$=dMb_g_%HM>s!X_f-+n<*~lw)9L$++=31|MRx{$ z-;tZ%Oy8H%wRBs_K5de>aApDpj;L0jOI{E$Uj-vX= zp?h*TCg6hUq*gD>{XvS{Iga9>fA#Bml>Vy9!hS~c<5y}q5ff-)s*Y%iCIaL0-MjVs zirHo67g+3Jj?Z_PZ;sC&&iwsdbqKsC3z!eG9T!Zie7j(k>VIA8C=TTNljIW*RTg;CyCn;a4VV}=XeQ1A{DSDiu@%;B%6Auk ze7eQ+Y*Fq&F+LsgUDZ#=Bi4rHd)~+=$hX7M;gNr`4pYZSM-j+}eBDzL=0hJUFrCc% zAGe%wm6Xr?|1IYai^`eF@%Q5D==?L~Tgm?;otokL1>^E9qn(U#A>gB*{qCV!4u`|n zW&xTS--(c$y~PB+&`%4Iv*NHHqQx+*@s(nyl82>sW1Km11W*>n8)w{}5#@~!0eL*l4# z{Zc&2QRyXkJ`D120?UW+$iH=Wa(Iph`FHBonjbgj)u_nn1o=SQjQjCSRlh9P&tZPb zYyYDB3(T*v_&*uy6;QMMoxfGbljyGXi*#T7D9nd^BaQHo@BLfC;UV9X{WTx`Ql`z(<{ zzI{gfEGgf^gOQ}7i}M^sQSTxDn(}xu$OpNr^LtzzspGNK(?X#AhjytcpUvT*k9Ac> zA04b;&S&{V5#`?p8Dap-=Z%ZbKg{2m!ts`La?};@GFyBBJsqmcCFC>byJhhM%?our z@h^0Ei}`pj+D~de@`=3#!Xf^r+x|6B*=LcXf}no6>v58AyDwjSe0uVkc#-Zfv}=rZ zO01Jk7w_x({JcS%00b z;Q444NAxF`ORvjN#ep2`U8a6%wR_Nig5_@z%lF_~vd>DDMZq(Udepu?TE46Ybj*l<#}xc#HSbXKGhNQVu`J(fOX>YL z)}NndO^BAS5%oLC1M;ORe-qK}=l3<_!~9sMp3VOCVCTm7Fv2^=cP~GdT&E?M85>SoJ0n>BCUO2vTut>0mB09Tjtc2b zjLtvI-Iifn3>3A>?&}Kde z!dc9?Gv}&iQocCnALbX=Uq&oE%<&OOw<_f0aleocdR* zT((<$R{-zcevXO~{3b|%DdYoP;2opC-?@FA$NA?xNA`J(FP}RpJ^3&$B)(eXMe>jj z?PADxJLk7q{*LAR!~b8%y|;y&f|w@`U;!S^HTf_-y(^1T7O>J%=2UapSc%)bu9G~dj>(+xi4z&Kdw z!&0dI6XXMD$MWamlz(NuZ#T*MhcGM6Gygx7Os5bt{rN}kZPEFM z`A3is-vgG>Kk?o;MR_wyN!N&$E|IkB%-n4ifW7$0PoOY|=}+#ZK~n9mBn znO_KpbeoPG)=QN?WBsEepCtL_2j>6qJQmm`Xue^eJNWzEln>uQ7S|(?FWyPZ4SrPy zHreQ(Kz^I^g^=Hn=O|n--Ez&;Q>1*(GDmSxf6m-P@&)E+S$9U~pDABO=Vu*vg-#dx zfZXQ1A;?#6U^u*)f98F&9}4~zRsNcNPVJZFf%#8&{WJLv*8DBZi%Rf(I5Yq9R4$2R zKgHco{rQnBf3d|{FH^aFeIu1WcSS~WfBHlU`7pm|3dcLXJL}izpT|0G=x;zd$>smL z;9DHed!xef#F&4W(GOrVA0)RDt~Bkv@RFG_|4QaKiUIqSRz!G1vH zxUCF&vOqmeL*;tv@K|S(*<#OV&3E(kd(mc(rTo4`eP}bj>AiJ$yazfn|L?|axxH#9 z=hs3X*Y;f%+8^n1&Ofh>ez9PExWc=&eWLt>rkek-u(`(P^ct!psm}78!S#>ZTl0~R zjqsk>spUsGig(rVc+9sro=fqa^xHti$!0#}0)6d|-(QjAKhZxA`8u`@%U5tu#pE;P zfP5w{$Y<&U@|ki&K2vVUXS1B3bDMTJGbrC^&c9fOwm|ex!GlGYYaZ*Gr!{@pZOhcDKtWu-|^YZ2gUO<+gvO6_i7yD z@z)q%Ui}9en;Y04CF}l*$%lD3=Kc^EpN4%?Am5g5jzWlb4DgxjqF5|PjKib;If41s zY5I);I@fD*G|6{K{6R;BaJYY}wH$v<yHTEr@D)=2k3$e zf6tfif7Gw}Ts~K?qxb)8|NngAfg$S2D*QaC{C{1EcvF~<`O)r6`aQsG0e<2JqrA3u zR1nx9^xJH+=A&JJ{66Fl&9|HA`YT&KEmE%M&)!LbdVYGh>H;4Jqf5*4O zeAxdTg<(GI-@7x+w}d{5Ukvk+AMBkZhzIoZb1sqN8j)TFY4*?nwX*G zM~wt3<(Im!IR%t+%nM+)=rYJrm+^abe2{aCQ7;bC$>1^Z+$G6Nb@5u@zO->YapDD( z_70Rr8dDF&h967b%}rkEi$1%W%keu!_7X=i@O|JW==Rb;{?AM=|A&mx@mLK9srYcp zH~5+Cv6tIX2oLxPgOBgH!*9~@I~+gs_#S_k*fE_h@)zlY=JQ1^(_d~)d@A!F_5Xcb z|F@?1nVn5z`=4=C$i%E@`LRA^oa4hd)&#F3%IxI&oZh=S{~;&lVZ}ev^|{3lG|F?- z75=AXGk^TOnveHFjQMScYd+SKw3%-bgooa?9P{fOCI52${8=pj3CpPduk8PyNX(9w zAOFwdoDlxASgo`?NdK6Nb^PE%ezb#}#ya1C%j_>keqtO0+IbcyFx~i11$`lXP{f1# zCzpLA$9I+KUp#3&z5j3a`-c;A(v!da07pfQ{urdwhWQDje`>-o9UgqND{f=H#o51C|^3P3A{ykl_Jl12{&XF$G z$HxCc;7+!8IXrNuYVUr_Fpje|M7i>`fsoNe-)I!C_VY{ ze--wLKAu=7mj$H6zs|7GWMc;@4M$&V#TK3{<@;}KWxxM(LA3nn z|BQ3Ism7nx&T&)-w^Y{)$OrU8dCZ61E@FMbE^Lnfgh4tU@N=2}2=_n6U(@mDG2bLP z%z%9iek5mHl>K*;`MaQGjM`v$$j{^{PzD4xC2HP33{O2ujln>tj_saHP zaiIOXMC+k4KMyL~zp~AS`m~^nj>qi(_>TJlQU4=-jJLsi3+2nE{w_H`8pro@s{Bi2m9YK{@;E}=Nto1kt|tU}&3%iJPv*YG7N)@XA9e-h z$NEH5I_Mlu%D*gHe*8a=chdC)(lK#Ee$3}E`}+G2Q1r^z&({Kz^sqz3+WO@{k^}Ve!keNFQm&qLf@CZRbNOa*ME>l!It{U z?LSiAm(sm-)@*%`^KFZ8rRhxLKBtxDmnP_Wa=p0$?3L6P(p|>?2doVgH@Q>?^a7f< z>Eg{%`njIo5AtwpYW>LfKu|wfHMBp@b6&uertT@>`}&uK@6Xr}zF(LVzAu~=zJH@L z-3Q(WKMo7u|H}HtQ}>+}em|VE7(RbbsaU8Zm+8Xg8(Rk3&nx-+!7Zfs|CcoWtfQks zS`S6nA32BXh#;;xkAssDjrqG*9HHykM(nY*xudS|y_wB?jPn8??*V)#W8W&M_0%EZ zcp%@ur-%7@9Dgceu?J|;*8V-Ee(X7p^1=A@S0AEsyOP=$_iDcVu+|S3D*>8K-m>op zdPn_Yjn;Zlk%m#0?Gfd4mcfVK(0;eAx*|a?xxP@7y23iHZgPF0I9*%E*G;z1 z<8+;MLfvHh+@$YX;h;toSzW{X=5es%U3W$>Z5sx2H90{VpBY8iZs<9YN#9Uk_U&3tn{ zPmKAg2=sz*XCGF7P_TSm!TM3%r6ZQ2 zXI;xM-xB&5a8Z~K{Y>en`F2yS&+_z>!|{QBw!HPr(ta?1c_iDvvfTM{p5Dm;VtG{9DYk%=JURb z&`(F!Pn^Hg%hM115pTOC>+h2KiO<#XpUe80`!9O8_YeI4dMrKtU_85ZPPl%?d=l*A z(U9fBd`9b5txxCy|2Y!%b-4gu{9kf-o-y=*d7KvW(N3<8|7gr_$?2vd1?=H49dXl^ z*OmRSekQVhu1rw*3g}0yO;119_tr7T>uI?-8DYwm$sU-;54m7hCB1Y!;G=nC>Y1B? zV)#%U-sODE;`om=_%`!X5zFxCx%aDFS^s#;9OZ-hr$*IE)By7B$6A-3eyo>uJPG6f z>G*fTeCTKEjxZnkv0n=Fp@+r%J&E|ChvKc_@UYKGc>gjU*r!Nw3}=2G(?)hT)xU!N z<#}vBuWcjy8S9UqvLBDuj~rhj57a;A`&9c1QPKIaSP#qjS=(WZBT964)D`+;Z047A za?};(G3GM=xvMlE-<$f5JtGLx0qxUbXDeC0-1+)R{C^S4=;4X}_qVe?T0i*z3jJUm zXZ$w+guDSde&B@tnEfuWpH%%c_`ikugRqBlFVOL09;C$yC;#uQ(Dhq3^HY%=_OO_a z==|Zes{UEwC{72qpXz()c9O3j_lflMW6H(Jh??9#hkiTg;SAI>#yp7P!H#+q;h~2{ zU763}EftE!O>=t*b_G2=Y5f0#UGQUN2+Acq{(DJNOa8yImO6@s`loLRm9N16>-dxD z>E{bq$76B73eve2{Y}izV2|e9pM&tQtK$rQRSsXuc8Go(=(#b62Oss-uSWPR07^kk z``P);7P)^*vi*bi`(H)W{t3+A^PWmiKW2FW4AZV4*V^We3X!14I7ua1@a5epra66UAwe2(mAs$aem8`9HHs{YWV z9(dj{^m8Nr|Ng4$2jDX6t9q=5Z}~eNc7pOS`fiOMeCV^7--F;E#qp#fh!6hR6W8~S zDqqk2Kp_JA7l~)0^@IPz8#qGzAGVD0HQ8}g2=Gz9*7enV)aNK)Kb;>A4}IQ_?+A_` z?IN#}4xeCtEuoKTtu-I}IHBCJcNt>Z*IDO}dynj=C~L8f2lY>_|I(v@`9apR>FLMR z0{}n|32w(iUQ-XSA5#zYIU-XJ4VZ800d|1-MDeFJ{_^a{=J-$#tv>Chjq?A3z0y%W zSM&R;5%vAZ1OFFd&*}If7ig;gE7;f8TCd9u!WXu3RJ`sG9Ut_Ojq>q^4v+F-{-?3j z(}aubl?0d9Z02Wqj=FL<9@v9fFG7BPEJ+X^>5r-TIvyCXF$a_)Dy~a ze?7u4sDUd@v3@hS*{EokaeF3wG@ZZ|PHbU4A>9@(NZ#CfLb_e-A16QQI&no*I;rn7PmoKl70=B9m`f~jie=*vA_EpglmTD#7a-+Z<8fu{u1yQ;L~i^QJI=E%P^w3G>%6zs2A%|8eFcebDKOXmQ zVExc}3DQq+{PRoE`a%B~^m8%iOQLRAKj@b*_me2RS>wd`XB3-`2ERJv@4@mSJQox3 z=v_J<#~2q~b*tv19|`%gu1^w9Y4l3L*9(unjfz-SOEn7wr4PZ^H9aN)S3G1xcs{PG#=!0 zpI$n=lcB@MIQ;1|na}O*9OgGfx)7_Gem}X(YYFLk_169zov@F@m8Q;Y?H{M-rF)9sKZ!?b3F&H*BIWp- zyvJ)P*N_$KuA=zK-F2dlC-E4CC%5}7eP6P=mXPiwDwq;qVgdP+Yjh0zKT7`OQXQuL zwvHe3a+Lmt&LjIehT^|N+q3Kk3hM90r@|@hqlkn1B~0q1@s-r2F;wJc4q$oTB$>(G zc|1K&_;KKWJ?3f^}q+4~g zzK^|CNl2IKF!i_Q<;!IKRc3yd9N%b-^Zze;JkAj@gJRrcHYbSxXJVi(&%lBIsl{*7 z_(gK5#zW@4MdKyOr5X=u)3eeowFJqnndxr3dtitfJ8Bd)G2;@&C9z{%cp7z*r-t}Y zTZ0jeF{9aViLaw3;+lzDh%w3kd+MI=OjTuu=*#2x=hbJ<+Q4lhFsKiFA2> zJJ)S4GyZY@%=IYijlahdr<`hzd%<<>ER#R`Cp0_v>iOOB>X;j5zw)gwJ8sxke1sda ztW8cjsUH`s;jp$JAe?AN>*E-uipH<@iJUvcHkP z^XsqsXFI0;>}&ez{}kWe`uoETU;k5I`upl1{rU_4e8<$E(~tg$Z*TqWzt4r~zV!Ff zd(dA7^CumDvt2u;{!0DmkNEc1-@GsGKBzDKeFFVOJo@W=cE{9Tr62tf-`@I*9*Hjz zd-m5j|C5bGb0{e^$IW9rZ8M}Ne(xBj;5 zIn4cjE%$e6e@KD*Sg;i54PXQdV&z=FX88RO#M0i=#TjJ z*5832$KL46{%VH~a1D_9%f7H<>aWy~{)lgH{at*w{Z?Q4du5Pcf1NMxnEI>qqd(%? zTYs0`J@n(g^mpBx*gy8nU%Fq~G4*F(*H8ba`1aP{>!qj8>q~#P%KA6kyM7D5ykqLm z=|_LWx3~V5yz!0Q`qG~h7(cTAy<_UH)Q|p%Z*TogoOS*1zVuhz=%2rIR(4GNRr=8% z@$Id@)jxmB_kK9nA0vL_*I)PVc1-=*Yy0W{6yM(Z`{L)`pWc`K&BFRuF3w-VukM)o zbNbOA@$Id@?AEXTyf6LzEUgP?3euZ*ZKP$Q-76y z^hbPq>+iVi{jc?J9PJJ`qJNCAN%buyk*DKpVN>2 zh;MKGJ$&q;eXc)l`ng|!**A7f{gwLBAMx$2zb98**XQqV%YyrVZ|<1-tMsEk;@ew) zNB+l)ea@dB9N^zS=zeR*)SrDrKmDKL|J(ZGb3Al^a%uM~eLcT+r9S@Ytd6@4S)QZa z13o^dvk@8j)5x$yH{`iX!mMie283=pj*H1I?kwf>igr*rs}A<9$=gqfBw-E%Je+iiX6?;y3W%5kROTQk+)e#g(FMB~0&?GJAa zgwq4f^Qh!%XUC+#j|28tlz5y6SY9#ArKbb&Lj(8!6WF`=`avL`=NERi46}sxh60K& z53oXzFLYhNK1&G8x$7bD3i0Cee=Pp<@6@N{`S8x`9G8XfH?92@V$8_uBs|gI5CQ^9>zmaGtBj{`ioh^6UF| zyua$CAGa-YJrFiH%gO4_p6$m2-HJ6t)6==(@mpUSJYc}}_BxY}?-y1&U@tQV^t``P ze7|q~@%-8#|W<(Q6NDroZ22DkM*Bih*(tq14j2A4Cc{N1W2 zo{zIw@z*vPIpyERTx7lCZ?_tp&m(s!PA5W-y6?37;8f`EdcMC&`#bt1>|IU5_p|l< zCF`S4r@tugL!V=2c7v8Xu9wd-57LM`wY?Lk{`mYfarQvepVj8q>o?*mf2h%)t@58$ zJ9ZSWR{TY+hmzu9#hV%&*H_Z=*D6jYsUFtDzTf@Yn_m07Q|)gi^k)z2wZF)pKb`*W zn&-GV@VjixcjN+t(=Mr}=e6G=&i>_qWq$slD(If03~uT9p&`Zl(^D>L_<7zH^>nuC z$v)cD1NF33-~Y32@Y}IwW7VmL?j4W6Gs>&K^{T(&SpSw!?mb_oxV3Nn@%^+dDtGjr zraf3Mn*5n>&wCA<4Nm+kku48-w2Phm+6x!+(6pAAVHkN1pVj%KXF=?!4L`z9KMxIhF$g*dizIVV!%B znICs{?qQV{?P0B?0uV3PteuQ2|GO9LVO@1cZ`kW&y%4)?#>?kR|JQM&<3iNm)7K;4 zFZG@eVg0pl`{VgETU221d=%!haEX!6_oi8Vz86cJ{T$z?B+hpF6#FxMFMDsz;Op8> z$xl1^ae!Z6OSUcwl*d*%A)UWa&Y_CasZ&ox-OLlC*Ld46zi+tUKIm^y@A=Y^Pd=Ug zcrF;v0b#ybeGjH|y}$kPyiALlsgYl+a)R@nh~jjZp6;r*e{+MYzgr!bg}=WQufqI!aPRlIihuib`uqR; zeI)9Y^}zR$h_fF4)%!?xz0oV{f%;3ThwismoaBDrmi^yFI)1#r0s6bLxBZs?{^|4= zonz{O<0u(7-ZX4I z;6;J)Wmk*`vR}ljnuef2M8*Tp#r*(6&(NbT_hTyWhb*D+etw22(-8KIH{Aas*Yjq& z&Y(3H`&B%LTEIUC;)DA$JqZII>Xq*0<=FT7(yzQW0&$CxmUjz-EQKu7w%;V zIs2nO#r=fN+RLTeqb5Fl)n1m+e`+{;G5A3?-Uk-`68MG6-!%N4H|%8zeQBWyN58U{ zCA5CB2^VkN%Mwa{!KCk4v6m(E=VMKLS9UK;=$3m;*gh9|f$rCEu>%jY3) zp)*am^5wlOp_Y`9-+3L%1N!6PCcZnpmnGESMZMDP`ocMf_NCu9VZY`5us@kI`uzZ= z=hd$ru)kbjf8~X0e+eSsFMI6iD%-?&@4KrdgcGKG*Nqxaa2ME@_u6Fp?X6nVcaGfE z5_%T#a)sa*stu%nZla0j|NF$=Jy$sp{;0`BmUrFN66)`wUg>tcRP#<>`jz>mT+UyN zer0~?)$g|Emy&KrnqNwJyz@($V{U7HDg32t{IPbtITKGN;wu_vTrNTpZC zT2hVKLXHgihTdXB=*mR8x#zy~xUt5@L?M>y$=ii|B3Cu!ld;CkDkIQ7kD5-ZhxU0) za-e+QY`?CX9XE#a_n|+=_&>?>{`)SbLm#B+>B{@>vS!XI&h=OD{r9UzJBH&q|NQg1 z0Ito#;`hWY<*!rue2+f*INqZ_X7}E6$$zrD)irhZo^#0~8}T0f(Y^1<`M3B zPyR`Sr}w@m-}%JuR`>D${(JIaEhq1zSas#0?)-GEx&IS&e)atq(SI-NU7y=kM!!Qf zJzcKP^>Idv`#?OORoQ#qmoMpgz^tD?zF_htKkNM~*Z6U+o7U(&zH&*-6)k;|TyuZn zxGv?e`{z1~=N5B)RQ;sk=efnUo7%GK&sAK@Nj=3BcN8D3{6U9ymehz>TYtBkcl~sM z>es#z`n_kTp6_!OhxDyqITy>l(ErLcRqfGs4^TIl{4dRL#Ig9@&Vg>ovaT5GxW3?b zJO6Wn!JQe#-ffr5vd&bT-{Iu_ub-*>rx^Z-^1nC6;M|X_Q~d1!9#y;;z%h)wSMXe1 zNAaK&QlLuRkDgq9x#%~1lj9=nALRQMk#l?3R~7xv1@%Ig-@S;ayi|>m!*fv;w${`c zoa;yCzpd|NbnJoo$rws7?zX;@(Y^Zs%ln;-@~{Co+svQ-fAc#T_ReZlo-9~TbdzU3 zxtHiSdxzt471Vx@ydVAV*L&Arkzsw?FZWN_KlGfxtLN!5>;BFk{Z@m?m+LatfABm} zw)gRBU*xwngVk&|fpajrb)8TCu=3BM9VmaT;%)OB*GK+{;$K$Wx!v?jYzG?M<4~`3 z559EQkm$Et?YCX^`yV$zzn=3;OS^qK{RYn|Wyb$?zT_4|mfpV^+M-^-JRpZP{q&UcPf{3+A_ z^rv6m7u^lJFU|BdzkP7L5zO=30W~M z8R&^X{O4If6&Qj(r9Lamah?_ENj132SqOtp$ArdP-#y)plwqX4R8hexp zcPEiQX!BtvT#jM=1)5fG!j%N%gXU{E(v0)IK!bEb6IzD#ABY$2kM7U*uV0V;VQ=Rz zW&?%ax3;cAihS?+^W{BF{{S_*7hRq|U!|(e?rYY$H=|nY)`3?2E+)LP8p-hd%WHGt zq8`G?PU6=gz6d;w`ly^W&^jIaJhDzMHUe)RX#L@I;FsXLh_}JLXrOfi;w9Zih>5Hi zXuXKA$SYvL6*(hNPZ79ZLRjR~+Q1?Ad=$S3Io$WTug1i0MZUuKLBzPLz%SunBE87p z{|JPoe5h|ZkBjTPjBn3VAo~1yl575FS+rhd;79q`Tmn!<#o7GT=Jc#;c!_m zUzlLZ;YQ+Lm*~%P-5RjRp64^_ce6S{{GMdx^xZ6>mT8{E@MZ$*|DNwnE=77!dw~D0 z`Tq35?@{u5lNQnn{j2XyejnY6w1>#T-CTMG_8x)Wd2Jat8n;8HYRz{T?^Ks{4xL@|X5D_RW?;cgrbmv^7GDcGg(KZwJoze55w! zGIE~E?&YE@4L`q=WV>9LH@{(UJ8$|gR&T>e2Dg&NF4idjT`_|fbB4c5@wun^`8f|- z*J5y|V)*N{{I4Bs%2^s_S={_vu^zT>nx31=T}o*9KqS%b#%EF!$Z7H1_a%#ZNSP&~DKhcBUU^ zyX$<|;K6#Vx!B;2=4)H#`n~3B*ZS-6;^z&2QGd@3EB`&u8l2~N>M&syXDa_YM$dK1 z-+YGh|IyT!329^>4)dwjIJ@P_OI`inYEsTq{ja(n!_F}~TkX2vU)r~C{j-0k{`>oV zZI`7+KIg5}{~7u_8s}luvpq-oN0@rtTgzK}g25~LyYuH1pM0(#-$(HusC@FH8+ES_ zw4Ii|WAw@P_}F~MjpzEyc0-o+UfAHJeNB0&zhOCpJ6g{E*5xXu=UhOhpZ@6l@ARer z-$MV^y}iG0+WYmbf39z~m;Oti|8)AF{Xf*dz2URzzp{Vd`mbm?|CRntZS{T+u-H6J zo=@7(zRARt)c!-V{<(Qz&-wDD{Xd=lAB-9~6+LGbwdh_CH#n|Koc7Q2pt+u*{abOv zZ>yctKJVi?PjL=|yDGo)g6U^$%Uszy$MrB@+Fc}ovtOuHymW_=!~Q23!0S|g@Ou@D z74OgK9Asi51C9I8fA05n(Z8em->lq!F;~J4|^8!25nxUhTj6L&L!LOFO<`^xrc+YI;8J z<>X8|R@kZ;=eS|d$x`xSR?@b?Eihm_}?*{)Q}T2*7@5U*Bz&DjQL zd!k)m6ToTLPhV#ESq~AFvsLY#c%9<>y_|Sd@vAOzTp#iN+JWKf)&J(p2mGZk{jUk= zKXl;#O#h|NsQ*$w`saCRwtJVo`X~N>RsX{u`|Z*N=wrT*+c_Sx*e z(vSX~ZyGs4{S*Jcs{coSaqEkH>HiOJ`}H3>c-#7~JZ$u%=GoK#RF3;>`nPX1{Os@9 z|Jc{{t$*VGSM~qFut~o6L)rhI`@UcQ9f$nS^lyL0{>SM@|4u*pC;op$|5a+BbT4hY z|E0e6e{NW77;Vq!_|MKv_xF6ilOqV# zZt#6A#ya$Xa9cBYEr7EwW_BtyR1$fJYQBv^vJ8 za_SVX=6YP;YldHH^Fr>QXg1adlN{GuOc*^-&uf<$ymCv-ji;V()^!}^*lsNLS#^EE_Zz6sB~KYS z++U)8cGmen*CTUP&KAx`bsa~&-N1RR?kChMe?<9NU)1LdI)CMNk4z~n>xI+(P3p`Ibi*e$CeEStscFlzQv= zJx}pkO~83J*Rv7DTex4O{M7R`dcWM~;r(5)#&J`!UQSjyoq2S^{)OZE$j^H3QoRw6 zDF0ikXX32)NpJe)M3w*bSN-^6#mnlhQ}@GDn3YX2|Zhy9;Rd-Y!${ps}2 z@AX#hGyREXV+Hp~sDFO%j`tPP1b3e1xIWq;_1_sbIQeat%d!p`8;nEm0f z^6#fOe=koeJ}n?8tN5&doOZ>h1mtuo{>ssg>vOb!Tdz3po9>=ZOuVtL`OggOzsVK( zrqR3fGkYUU{Z#gIqphyL;`=+GR~MLY$H0M>(7M|-{%?o}b!&X(6Z{4X+H|DyZ^bh% zpnE2nF#qpYOP_HM)o^i_ftJu;zh&_9;DMIVp)*am8*xH^9%91To$wn5h`)!2-^Fi* zpuZks;`#rA<@6bM?O5YFpI{#zw9hdnT*8CKLflC1`Uv+2T6cztFMf#MMnU6_HQ|ok zp%2haQ%uLUcI$5)etd*RG```-!;0U2rXR0U{OgV%HzADMkNEL+<^RoUKi;8u z&+l@&kBi%IucO-?*X6umy@9P-oi`Qrcd$*0e^2>|R}?Q^qaJnsruOMa|2b5p5Zyc8 z`dlsQ=bygM^n=CtJ$&z-dwxH2#+mxjYT(a+mi&IUCuCNuTt1&#KGg8D1pjKi!Sx0C z|K0V)_F7M{eE(bP3Cg3(dZGJ^yY_moul}u!`YG;>wtAcCm!%%$w=DK=#eFH!xc}~X z8utg*i?<%{mtUOV53@cit$SKRkNBgl2S)kVU%~pi+x92;`w|nb+>iHZKp)kZa29@{ z;CUNY&iBjz=m>xKJSteTx#A#ye*LZg)+!s@`JeB)_Be0<_O_1yAAJvu*i5$%iMc6C zHKsl6rs?VO`;7ekyhZz;$a5y0vRi)}@3>y}8zVI0jg$O%wc<@D`te%De?Qlc*D3x^ zpkIP{xmR?Cc^ zCH=nS8pSv0e1Yp2)`Lb{d`@Vq0xNcX+xPv|VLJZ2dkdZqIA>7L`Yl9ynp217Un|#ZP->K^&J7Vz7ir+;1 zBZF^IoKBT`=qAqnukOD3H#wicLjP9La~))#WFJ7(Uu3iqRC)m4j|6=!YQo+4kfhKD zJDG5{ysIU2)-v-vkn`rQmXLg}Ql1Ygzl-PHgvO$O@a#|hTIW;Q^+*pIiTRN?{?9@t}>GKD!0^fdCo)`@s+D`JN^G z70~aK$UimE3gg~|7JmVAU6eoj3#13h`*Ctro(4bYf_f9~dJg%42I_n+@(iBm1M&Nq z9Z%r{zkH6QT;1U2Q|$xd6X5L%gHvmw%k{2OYzOy3vS@H##TE{3CLciQ(@r2i*XM z3w!I&p8DzPuV6 zGT0x_=XTHQ@(ceN@<3}fT!vrhvZWZC z@qBj2heKUTAL%b2_gf?p|-unAj>tX)> z)^U5t65@J_WeTp3Uq6sB#{I0n$DJ0i2l;)@cR}CYE4beJ(Due!)~Ee_j;SW0ekyqG zp4Y#-zMjYqngZ2jz0tknyirws)!&b_!IzFP^9`v#>BHFms(Op+NHhd9?l$d#=nDvYuLjfXd!VNR>E(P%@AW{Sy*CBoX+Pm-aTW#W09{X0hWq&<%pXgL z6AGRe+7W2)9n+Z7xVtp@@Aul9{NY`0_wy&UeG--SEb~`hoq_nZun)PMpNCvBp@06r zB>+_yH_Q2t*IPP1a(?sfn~-%y@AH9?nPz<4L(|jc{1iVWy4S@`j_Y#Y+n|>9@|Av^ z_Ob%O2S1TTU)Q^W1|L=Wbu8-xcReZv$j_b1rG`McW z{cl-6d&6;k#OoBlX>TKkcvSIwuJQ9PR-ErEm)ebd!-Y?#@8>U1sUQAziudPq1R~D- z%3;?_{dSieH-`25wOg@2_U!@I`h^C!XZ2mbi@#_DvVN}`WB5xte=xE5K6wCV{YGZ` z`B}f6+^-4DQ#Xz^{G4}=)C?X_`NVC-H=nBf`d;FpicgtfaF&zy&_P`J!^*#Yk@71} zdkCNC$0N#r^EiV$ou>bzJv_|&Qk?bvn*e`O<%~?LoS3nPcE$U1s8_n>OTW?Q`N1D( zy*XvmQOf&|GDL+`@I&YiWqsWFg&{75r@HNVSJ;V}P95wN!`FQ^k^lROp==>h?2c3VkiSJm8{6QO4UgtfC z2Q`e*_!`86S~P6KFSHXY>^N*(fIfe+;qN>K=|Q_|e7F|xPlBp7-kyl`potoe)D5wO zteGZ#bPDbd#QhLwD~_7%DWaUh z_gg+6ds(2h2+LKu67oTJBP{&IcI+pC<{e|=?Jr}$3N#KKi=?;DLl`uFR};_w3zGC1 z_j#@V?#r>?2I9qfr91Qf_b2pKzg?`~6{de#0|EPk*nT^;{wTK`sP9dIFzegCe6S_- z9VC?ZDS7dEvvOuIzMD7L>RIocjfpPkRU7txC-&*&s1fxo`CI3pJRq)DoG%ZygmUO#yz^t)0}Hes z1BqMyD^PyW$%mP6Hx7aqlKn?nFLiuae2MjC8< zz8|L@p1Q`54^u&ftNb|a@AuF9aqd4|_^KZtVVNrvz&Wm8@uZ*MHtg2T0sK(Kt4{ax zS1X=7&yVZyVx4-l9}g@4l}&!UM)75r`Ed>_*PQRirzrpTl72j*cz+J{O?Ubi@BVII z?O%?6Der~;M$eg+{#~}Lseis-A3hxW+n}mOlVj%?^nW1x6%#IxM}G%8D6syO^|SZV zZ4@g~gYf_~aFmJdJPz_eQ8c|uGse4G^uM4hj5+p*cn|SKydPekjQl`b15IE9)<<$4 zJ+EqAuQ1#Z7(d=-gt{>q4?N?~+=58E1M39aXNuqRqJXcyGKjAtDK zhPjjtjQ91J4|p%y7ctsb2V@Hc?dv)+s!RI{AwMD77uoKI$E)v(G{~2G?d95lJ>4$$ zg!0?F;{HH#K7f30q5B`uCn#u7LHkJ`$()VL`G!3b@<6pR*y8Gdu7t*`J(cz!W(mpo z;_lZC8)kKbXm6E6hgm{=9;xzI)Hf(NUw94n;-*L0yFp?PazD{8409=2r{O~o2Jxa@ z&|P@n@3;14ALDK`DT?1T9fO=RKhGkhGw)wf$8l47Y@y__pEC9yr_*sy)Mm!}|`mgig`+*)epuCG@}@Cf+_|IG#Zm zZXNxc2}chaZV7ExdEEnsTSBu`Ug#hA9uH^}(o20=dk=Rhzuu&ej2dnU&A8XZcMXF+ zLI0sm+`a|(588VTymE;pEc|wDXYnGeEsfo~>9M)JLYv_q`li_Auv?U=NIOefAZ@0#>OO1cI zq?Y?O!9|I)d+tq6jXW)rTan1kjWr}%^7hgRJ=_g#O>_IGU%>v%jVgLiUNn}&euM7% z=ucPo)qkAyJ;Prvne~V4^GTEE{KJCjd&hI@^Zxb3?lPWwt^)%6V*=sUq+t%9y^|&M z+#tVv9EI=8@8v-FwLtjIK)5>)zBiEneSz>N0setI`}3~~gm({w@o1p0y!!{jkM|Dw z?v4NCFhBq30RQ+vxHb@8!ilZwyfF|Ss{0MBk`aOM*TC;>Mmj~uI_nhvJ z4}SltDEl9tEBJk}bf7$IxbV?5`*VSz;a>&j--p{C;qWE~`{zSlkXM%RMz4_0m%F#( zJTlM&HX=On_BCdH5vgFW3RJxlQyTZaY5uV6*Lbhd)4d_fx||iJa4EpQEWkfLFu%%b z{-sy3Uj|wqnD3ve`#l}cW4{b^SCc7!1!Wi7s`D}XP3+f!)}eiRFGt7s(p!)Zs=yv) zeiemZh}S0RxNxmi_t3^m4)(quTX_c=<63+K3=S99-{Iv6H_U3K8+`A;Wx~I&WgXXB zxhv+nRNuvm4bI=$Y0ob=`Eksu+^e(f$1&2oS22L^rT7=Gaa3N?xz{5l0!E_ghxnW%B%^ozQ(_!&|!c=DvRg9 zRUWLegm@lY@!={5I#B=33;TMYBhW!QXA6O58AH;L!9ONam5%(qM!9@`##B=8= zkS)aX=Zc6E;yH9S;)M8oM8#(P;{|a)v;%2{cwSu>(hBk1 zx^DP|K8Tq6?S2XSiJ(=GFZUlp*@bwXT^N2Lo@?howh+&^E1@ogxPP97Ux?@3MZhcc z^zBfH=h~v{D?%%!KlF?TWvn0MygXh9kE74H=LW(&S1*dZg?Q0N_u%dqj_J!j$KItW zuGqGH7B`~4K(x=!O{gCb?bAV=5bd-3ap)UF`|Jj<5bd)Iej(at_$P=HLWf;JeLL_A z(LPI%Ekye)Ax?<)S%F`O_8EQxvOu)Y4&)_7`z#_(i1rymS|QqJC*p)?pJn7NMEk5D zPKfqt<6ebmpHcXQXrE>Hg=n7^$|6MjwBZ+`eOllZqJ2gXCq(;n;1{BOc7Rui_8CE0 zg=n84_=RYn75IhzU)g8(k5T_1Ui8uZ^^+6&{64LmzZTgazklhuYyI_~q4nq=K(tTm z@8};uw9m=|gDoN2XZfet{|EKh=ReRNfM}l~_=RYn*3TdhMEfj0GuRTMecH%di1u0e zIr0P1KAmUr`v-{jS$PieAlhf=Cxa~^+Gq5a`27V$`*fa0dJye1`YXhPMxa;`^zUKh zEkyea{Tk&5(LTE#!tXO6+Gpt}_&ojA`rXrJBpBOXNijN)E|XrB)JLhL^y_aT2!fBk3oN00|% z|5*XA5c|&#_=VVihLN`rFWM#Dd+%TVbYK1Funi_f>0k7pl|Q1rfoPwh56~V#w9hi) zglM19KcW8s(LST#6{3BH#Sfx=c7Rui_F0Bsi1ul9<4!=dPwPE|LA1{Z{4VME-hr?X z?X&xRv|kYIvw}Dw+GiGd3DG`7;1wF7_Gu$;A=+mIaYD4uqLd9p`|N~Yi1ukiwh-;p zL0Tc&XAyoO+NXoGLbT5k;)H0QW%z}9>=V4*pfJ=T>*o^cLWuU6g#v-yduV zvHx^lM}GjKeLBcXi1rypUP81_3w|NmXAyoO+Gi*77NUK2B2I|*8N$5^(LN*a3(-D1 z;TNKPb|I}0?Xw$xA=+m*@)DwbhER4P+GiMkA=+mVvV~}$VWbtJeOmAf(LTH27y5r? zpB2oNg?Q0Nci!8d8`+nA-us^>Md?qy_W4CX!Szw;KG+k8_Sv-__XnbV77-^z`wTq* zeS&D8p&ua(qJ4HFtq|=q3SJ@FXAyoO+GiQEg=n8;#0k+ptsmk}LA1{({6e(PPUIy- z`z#?&i1rzVEFs!w7vh9ypB3aSMEkTLONjOvxgU9hXrEd5g=n7@_=RYnHqr{wJ|pl8 z(LQbP3ei3t#0k+pi|`B4K0CoHMEi75Rw3GF7=9tzrv+Z2pnaayyYz7lBiNs=8$=5; z?*CT*8baBGc+p39@l^+2)tCLg{ko>Obldh@eiQZrqWyNi3;P4neoKfGT3HQwGM{@J z`U25@!|3~6y4rHjbq^sdMElKxSBUmof?tUCTY+pL+HVDMLbPA|9n?37_M3%Yi1yos zvI^0D%ZL-A{YD{6i1yo!I3e1v^%gV}55bZaDv_iCB z2Yw;iZv<(DXun0o3DJH_@C(s?yTB_%`z?yDK(yZ|{6e%}8@xh0iv5OBHX&a0(S0f& z|7~CPyYMxWqVzB9xAYt63q^Jm0>=Q)$4ZVagsHgu$+HMf- zHws=M+HVnlA=+;lvV~~BWyA^5eyta9ry$yI6n-JvZzu8+qWzW-Cq(-VLzWQjw+nGX zwBHKy7NY%HkR?R>jci8VAlh#hej(a#1%4sguZ^@qwBHE)LbP8Syh5~J2XR8Q-y-}% zwBJtf3ekQYlvRlK8-`zq_G^JxXh*T%5XvURi$1y!eeIPG`?B9wwcp5P+wOm@mmvv6 z`whPWeSm1cmEWR%Kr5?_{bv6g^#`K;X2B~&`;EdcMEmUouMq9G0>2RL*GAq#v|qb| zFo^c+z%NAm?Sx;5_8UT8LbPA&ceo!A?Y9GY3DJJTh!djyMv%7a@VmtQ1B5$3wBPP$(BFe- zzZJv@(SEbYONjOx0qYG8}94N ze%EOKTfBVR{jc*H^a-NR zHv+#9?Y9WoE;V9*ry1`LAWn$(TZUhV{cq@X$OF-Sv&c(`_Uj-{i1yo!vI^0DI}j&C z`z;}VA=+;laYD3T3u%RDzhU@=Xul=+g=oJOq!pt5S}2c7j)k_S*r!5bd`cyh5~J`xlT0qWwCM zEyVuUL7Winw*eBfkVMi1yosyoG4LS;Ps^ev6Vfi1u4ToDl7| zf;b`CZwRu4Xun1Hg=oKJq!pt5R^S(+{gxq1i1urt>_W6(8-5|$ZxphHXulTH3ekSM zx^RCW+HVPQLOY86cA{)Tyy&A_Ke7F;zU=qH@g_y(f`sd_5tdhexPOLMgMC*i5Z>uv zU$pgbAU=$E_xS*28==qlFx6s&<@p_6TLS5CGLPvn8sA*(^@=a0&o2{g?0p2tg|-Cp zdob{Ox)peSxjVo=X(%Nd_rgHoy^plJ3GKuE>DLDM zH{p3|?{#S){T~ASUS6*sj{&$B?f=BF*PbxAs%l@JPs{#W?7vvQv*qk-p6}U~{g>9` zoq&LSeir-h{s7Pad+f_OY&Xkm|Dhk^{Q{5tj`A?eYyZx%yZP+D`_*AS`wzW2%<|d) z?;y{UU-aW)me>C6&q1EY{-ag9Szh~hrtfBX?Z0E9gd_(W|wIdfN+;}|Z?Q^T;M-^QB zE)u^tZ2zRuMCgBhZJA*LUw9(5*H`@_k7{oxK) zgu)LW;E&%N;QuP}^IoHopLf0#8sUw_E75`H$wLu;{K!D~UC8&!tJC*AnQ9|F>i$LK zd*&CNlE3GD&XWVrw^#6clJ_bu@rLmI)j;?}+h3kdf%}Wj_s2)~^UK@sAb)(%{Ja6r z1A)eR#!pGf_suEg42k#L&sAa|c%P8h5tIC3=XS;zw*$}Hd#_R;92Mj7TzKTwr~eBO z@2wBdmWi8c4ayhsly7-pK3h4&BOKm05A%l^qTSQ|*7C-6ecAu@*P9g1hjG^<=e&-F zkM|LJpPcMf751v_=LCo;f1&P!zVxM z4_A)&hZ_U@lV9=2=jZvuD+By51j<(*NPlNB|TK@9Bds#xq+~eop7|>^Xpgpqvm3KjU z(9EU&^cxoV!|P|5u(M^jCG@lyo9BAxU{3(vNrOzdwCi4$&^;O^SI_yf!}h}amwQ=O zy@}}>fiS4Qi`@=g>kBi>?)>Ox$4zpq&W~h#C@$X_&;1$P(QyLJ)V=7+xN$g;#fsk< zc3dCFLxru&CmEdQIIw*_c$D(LWZEIyUsbOuxFWpcPuKo~t!<4z_S#*nZH+(Cy#`y} z@h3Zcu=QESpYpZ4SpUv=Q#^36^?!N1iQxXd<4tzI-t$dZ-=B57+1B{cjr!Tv_z|%O zTi)@b7{c?gp7A3*63@&X!jj=kfjtNJ1_Hj0;RdKu_ptA;m+vF=eBZtFW|PZMhxQR! z(|f*Z@v4N2&PbK>(2)j@s2p4I#svm1g-yHUaCYcYgL57nR(>mE@N(9ar&jS%R~g(< zyi@VA@|U!nojaR|tCXMkdc~JCsT}1mE1nJD8x^lRTKN~4@@!Ikjh3J9O>M$ffL!Zm zIj+n1*}4>eHg0g%%Vx#HMT19vZRX__#b0bTc;zUQ?^eZ+OR5}wA8hNMmV2e51}}Zf z=-E=cOHdDbUYooEFV}fbIEN6t+~e^nas)f&eLRQ?f)Uz0XC`A2BO39e_W6|c=JzuMhs#b1dT zy!D>->0~;#1XL>{Cto9mTId(l5VL@gM5?v8Npn_cg_$I~I4AOS3 z{2{gX==**-ixm&9-%E;HJ5B68w?d9)=s5$y9O1w-60)(zu)TCrje872?Xh;l>Ovwv z562|n@Cx$CsR=opPcc8yZjPOpF#cGaw_v~%GYxr{Q^0gKmx=d;3OKz12UX~44Cz&| zRB!ThVVuNV}s6rSYAHGAu!)qY&XSXPU{`F#i-eym43 z{J3_bct^zG{LbnK%Uqpj`T1?dH*h_r-xsS^d?@#uPcrvgtGLtXxIRbmh~gh>f64EW z)+zpgj-Qo9rXO?^e_#81-d9rbv*#NQ;#tMBvkhL3nen+@@%8{-RQ%3_;isH6iqDT4 zob}S7_yV2h6;C$zyH@e)afaV|)|9`b_&4GPuWU5qz>>w4!#BZt2q{^mci|FYV%{<+!c z-`3=GIll|-WFj_CcU%wW9R|fC!EARr&#Kah8^-$i*ub<(^*D8LJj_g(DoUDi9kIk%hkcd(|T%k~%1_ILQ{ zj?2ORQrWE&bv!3tr4hmXj*#L-ZBN{n8=?3s3mn(S{U}@Uyy}(sp^CQ#_^TDaRqLPp zqZMDT`Le$ZD_*7ZBkniWD!xn9aed^ED87vLqW$hn#kr5i{i`~~xsOLYs(7NwaeXZ3 zV#R-|?SQ|R8!pTG8|~;WQ~ycjzwj!4)2{gFyy2((qT<~5tNh5wU!(X3 zX+M95;@lT4WsIG!Rs6n;;iulpia*}0xbFLHRQy53`Te_1iZ>ROU-jIj_-Trhf3xEA zFEjj=DpQ_{;@yuLoO<4(ctvr_=~mpz`T4ghzJmKxT7FC0TY>siyh?G3qnjOMe2%&c zQ%;MweHOPgxeRwaU|Dv2kX82;$0WGZw9i9L$fCRD6a(;lwzI}6e_(uk^%XxpLghTO zo2h56kHU)oUFTiI>l82Rx{tU@wUVvs(|p^N|B5#ZZoh5nqeJo4idX(-@?Wd?I<714 zH~b~VZ$H&>eOxznD&F%Q>bs48)+^p{lHqrbGI&|>xhjV^=P6ToU-~;>=RlKSh-2hf zit~4l8#({f@^gRp=61th*6&%Cq1tCXL3hvHAEe16A# zo#Kmizk+yK@kez2Nqn>7X_ZgBTk&jI*Yg+cw-ShVpJ&4NX-an?J?KP@@BTXEgF+F1`jLUKd;aET=ufYrrZ3(;%yMZ7 zV~iVo9*NI0c3+JAKr`kWzQ}FE@GitK>#0%x^tV#}1&|NQ)%fG@4BX!Xf$%GSb}M`h z^o{%H#r-#iU$Bj@auMnq^sB*)F>XlhyyHTgUk=(w!_FNzyBxF|4N#MDeMBio9z>sU zJCE>(pO|REHtJevi-xUphT&nfVb;^rOnmV&=mYechPx0aGz$59?diBcdHDQ@b0^9R z;_vC5=MS@lGRoiaAGkk|oJT6pM>)t#=wCgLwNmxLyBaw|%Xs_L6{J05O){vqfPb&Z4bsbOnS;afEe*SjFkG|TE z7Zv|mp!{nTf9Fa+e~02f;{06arE3*G_iR6ZN%5vYy{uDw-RXY*PQ~YNo~iQJEB@1j z;qTc8QhcN4+k;n`h|OB>j>_Tw&}EkzImEd?6n#$R4`^@&aDQl@xWPHDa(`%$?ynH% z{?G-d8UEsVMh^Ff)&}a)*7mkR*EOuiYK}(%dkZW6NdT`^ycn>Dh~nu+PC(DTNHozYRC1l z-+4pv$F%<<{-)xuay(QyZzW(}evH;{Mep}r#mk&uDE}W7k6+`s zKI)-c@i|GwRnJ=${{i#W=PNC3KV3Snp}kcpzDeh^>>oplZ&vx-N8tGUk0z5Z?IEoE zLj!ig{%CETpP&6vRO_8`*dHxf=I4*9{NQt-?2kq)H~icmWq)+7j*Ai9|6+gilepn` zRR8EQ+^eH(aO!!D;#DTPXMdsV#FcyWwZG7GyghDw|^`;XakYn{;{J0 zXVz?^e+(zk|81jxEH?T3#}0(O{bM9qWqJF@(plzw8SnjVtADhy+34*b!|DIs{;>%8 zpQV4a&#tn({bM9oh4)>0@1}(CztcZf3RTv>(?8lPtE_GHkDZ9$R{vQ3(r4=*yU(d| zzfZ;fG4kaqYg_$e6rJhz>>ooXR9V~VAG^^XY^#4P=h^%8)+v3Ap?lzf*f;x{-|ce? zQhW~k;rEz{PUsJoH4hN`)jvOg_i?@Ni=zE`!^yyW=sZs3wIJ2MWr>Vi49xc)GTmhl zlO1T^PY2?kn%l$bdX9Jk{ex$Ibk6Vn;XMxY^G|-(AO1@~{=PcjtNblw3B7Z-pWnL2 zAD$VQ9}W%7hdLkf^N$R~zkQ=We!>s^;p(^i;fbFS=Rdjd3Ip_yCyKdozUcOkFx{(^?`6&%NN;cPfKVm+PC*| zAkTZ1*ui}Qdjc)N{Mf56XQAQlM0*k9wQeWlt5SEw+V+2V_uoe7^D)OtfAiJe{Wtq( z#(*ZPAiCUtEADI}E*$N+9zG|f>{iVZgFCw4#p3TiUvb^{h-iX!QG;`TwodWMy6-{x zQN^ughQIuJgNtxJJ5uMfm7>87mt{TEsJ;(kE`Nvn-?HwlF*xO~ReWPwaXmk$r1;}U z8l2Cyty6s6Y(L(qcl^@^{}8h-9$Y*2i7(vO!F->Un$+&9~#c%9};Ihz%~FXy;E z;x8$_^#ng&Q9Ss3)@zFYmi49kEn5_y+w8bL?z3^S zzoPB^Pl`8PZgB2D^LdVIY5%(J z@qv?#9Nw?3_z$#Rir1U_tyX-QwqNouRy-NN9mP*k`{e$1Qt@`}$0$Fmc+Wa}tGTa| z;`U+HqmDRo^q8?ng(ps)GWEFQr_Go(ci#Nyq9scY9y(;XlWffw&OOhrwvV(UcGO;a z*g>Q0QPrb{j<&}fcT_4I4lfSp!|mfIPPQj6Kh{3}_-XTI#Ah_k$jr#kiOy}A+d4Nh zw=lPDUVL6+UV2{p{Kok$^E31F(RtB$v@x29Hbqm>OfZ2Gd9%T8FfXxS;tPFogR*08K`S<|xgvfQ%#vcj^qWhyc;X6)Fp%Bsb$so;>b&+)ZQSwDjs}+1#|Y=IODSE~=@z>UJVq1D{EHgKe#(RtNVyow6((`he`LX%)S7hdARxXGaqBExAo9T;A zs9zMrJEPe}ZRz@0bA7U{zR*(NmZ)zpoKipI)L81YMB}pdbCypY8cR3En=_5E)s5+V zBHh?j$Tr9A=2Rh>Xiue^@U|#Eah{H)(}_Yl)sksAD;uARZ=~n*$wEBa)|h?l{`@l= z@_&5fA^RZQvgEwJQ^JA@v`H5ArXeL*P<`PW{7c8ik_i7iVzLZ$BDweHJ#!~fo zO}0LlNDLj)I(507o*K)i$Ke)_Xo%$#4VjjLyt*658^-Zi){e*W<3Qs<6F@bfiJ(dG zB(x8?O?Vv^iqAK-rBN5D#$=`~mn;;rsd#HP)!33qHN#C8YE#*jHK0i=Q0|sQtVzB; z-2Wngk)%w&Ur-R68lbq{JrAL@?FZ z4)c!TA8f<6^QkXQwF|KZ{L7%m+l09d%+)ZVQKKc3aboyK*Gm0OKI)iBQxI|7w8oZL zE37}&GCkJX);b+;RSL{`mQ!ObZHZW}IXg9$%f(is+OkrYS*gtIgm_CP zpJ+@pv^6)yTJnjeSX)b>Db|FGYFcB3c(PRrp2ln0d8t`Di*o1jGI=VVZB8}jrIzz&x22>C@t%0T z1+O*dTT=0a`|`WgY3)iW_^Mp0kg%)K4u{&+tE3sa_hZKz8*@|bIK<9M?M4UKz_}ryiCcJNB@A_3^Ef4@I+VoqPuV=O>RvE#lR3d%`hc)Z>&f zV#rf)hhxW28IS+rX}MTKDvoZfEnk?PizQoAGh(?^ERDvvqBS-n)7qLU$p1`wMkZTG z#b-{Ra@g6&&CIklv?NYw&!%z-^m*u$W-pMYH#<{ErsC)Vo7-CIVg*=tU7{hESXH+= zn@ptVMCZlwE9Rv0g$3D@@Unk0by6~O){4~JL>9%GyE=}1=dNzV|9MbLp#>HJ$*> zg8M^P5KG5SLlaFFmM)ib42H@GFl2~`MEi@S<4IRLW8&^z$8)Q*g-m0n6~_xCniA=F z!kmnd5X-g`ZmQ-C?km?4!d+%uM7HxkTZF7WBoj z^y~#QPndqn?Ag##AsK@ewWTu|F_&pA1##wQvKU(1V!72PVVH|G#^%i&KW5>gY4c`I zbRBehu~gjcOfc%AeWMZ1TOCWc#&Q^LGYyH{f_!T%y*joq)|f)KvoHY_K9x(h6=E2q^RT*8q@$WVbcxZ+ zkVe=_&K}~n>8UuQK}K5SDGp9Mkjw3GCX9ETNi|IdY>uO~#1qXXlu9Fgsxh6(N;(t7BJBOh{oLIZ-G-QoqLUH3Xrd+Vmgc40Hu-jZ> zWg>@)X_B7X&ZSJcyy487P+K|;o6?gV^6{K>gs=}8M`gUqw7E8lF{UlOBAr>47Ky2h zd&URS!J=X<&s>8s2}gJ|V@iQ(hV)W)Ydq5?qn2q#03k1fcvu@WqDI?@eh-IpB*e|Y z`k`+aT71P+%tGB!q~j_d7CES6b|RB&Mt-wX1$Qi*-F6mit&p1CmTPTWkxbR4agMWe$wvw9)4l5Q>}<=&*}U-8zjGh@xkQ<^bIU^G~=VEzen=FeKNbn>c9u5t46 zrKTgZm*tOGmOFk~dMIYkW5x^}Iz;P71~bg!>;{}QlES@W4uw-%;w#W-WIUeSsCrF6 z`7+v|n?x<73Qh5F7}JlVrOT2-MKG(B15ePcx$Oi!TPE883rOPxnloWf=%6vxYQ$7a zYAM!&qeYq}W0`89=2yTf(=m)-YQJM)w=1C#^jA4_$1BH**~ZbUtMOK^YRD&JjhR(; zbyFr6Pc)8_W+@p=wHxH*88Jn-;pfGc(>Bf@!7y%OwBt=QVxY#Lt)q9|#-tpxHL-dm zSSk~2OvVyuu4n*gLFk#swxlrnibqBUK~l|TB2Y-WlSX&Kc9hK5Z0LUln%LCC4yrz3 zas9$+m`Ti8v}n%!*`s7S?kWot0n>^`+vv5WIiW9~48?}SW5_c;93BTnPZ$r+czDK5 z8eda0u14k#6PlV5E;1Pf#tmX+C(RBc*3{{k^~KISHI|%?>Gq0z+ltf-7;y@^YMqG@ z*)nUJIsC>#r)?Yyc(}LzUKh}VTlYpnKbzY*7%rr)0Ev>6_ ziFCqk5z{f_cRi<|_gECe_>e-kjx|`pZAI>ELYg0zUT|Rd=-iE>mQFrHEq!vVCEeBv zlZPjpjJckCJe3kpLrW~ZLOhs(=UT+mDEBFz=3FeB6i-WLRU#)I41{SnDhr!)J(xYl z6B5;y#rZ~)m&Xd3)>J%`t2NE0F_mk`Wnzt()gI~dsl7~!vqJNKZY+exWEJ3SR^yx+^Tl-mmix> zv?N;dQ?>h;FrJvF^*pVCe_qqP=&+mE8sV^Kl z((c?ivbNq{SSmw#>Lm%2qvcX{#I#Qg2k@GFRU%NRqhF1#ury(;=}!Q}KyC;%50+cT4#skJbxrzsRm zf4a1>dW|QHEUPn+rmIFaPD^E+y1I-kA)N&-N{ft-o;{A58lFbVCY??z)Ux8g+Yc*Go1@4Rxh{|GYccFzSh`82X=(JZBQLKzBh#(Zrun>6P(c=6XazWcf z;4>$E*UIZ6OD5r zfHqfV7CA9ZrjbQ}iZjWKg?smrNYSuob(S35+k{ao0Xri2H+v1#k_sL&@EAB^(c8a( zPzt;Q=TjF?O{8Fs3K=1uL93QV%JpDkDbAtnc80O8eYS}3gD?(Oz8J-v<&`s-w~kMo zI&pmBl}W@KoBoAavCE0(3P_Bw=Mp65$;lubU07(J@7$a*y?Da_9q?WQZl{_XGZPC- zGiRF{)2KVIiBF?TFVC&doLolJY)`v#Em}QoI;c(8YlyH*^Srsf@Y+>4!3^*-+X0Xx zL~XOqAN%sk>`@1)$)(F{9eogX>qq8AnNft@*0|z9+k1Z za09M)O$L?)#s$HV*(jpB&H@k`rPl2th_pw9AD>2XnIr8B8109o$%=pHMBNR>^w9c9h~V ze{@P*1o4+)v}WbJXde{J&QrL%_)2}=TMynr!lX>EfU zJ&Jzjs3_g-1uz>^DMmVs3~EWy#NR=~6i6s!=6ZRgGSa9w%$8Ljt&CO2YG!yivCv+a znZORWy1Y0sdGca}qm&~+pVMb3bova9KHFSv--Kgg(_a<#U~DiM^hZ!FW0|jZI_sSU z7{Kk$wJCJ2n^$Mf($D$ntLOwlwVhsGZO%+1hM`DI-(Fl^Uzj=HoW~;7T0ot}@E~Dr z5hFeKU=%?3Us}|&fE>9P>W@j9=lLL6>)ED;3D9$x)!VI&b!K~cUS{srZCTY=XF#8W z7=L=bcon3=UWJVWB7ki?dIa8b0=An zz$}4qSq!vw5U~Q%;cEW;tk8bdlCBEq(cw{%z(`rb7LiIjSifCAlK>H)*BF{>9S*+i z7*WT_QC!<#NK^*YP>PV5$xO9J%#em3aRwVCQoKP4YY^9uW&C30n4?W=12shqB@)j= z=vbYbsYrA%sG7wCZyqXUfg5HrivT#7Kjsv(D;NYVnOj}H&VmSBB2~Z8+@i`#%2M%5 zuyrFhX3$tb@-nMNzFX4fn6+71$^#yy;#IVtfDT5v3?`Unp-B#ZRAw-IIHH&iT0D4U zV{P>aT&cNuWPZ8YDAz{E>Xl%To8vl)s)q?5Ky$mI(DYT=EoNR>xYoS3u^`ds>;~pK zpf)GfOifQC;sn9Q13|V?VDii>ljqJIEnZ{d34HGI8 z4>w{!V_FoLtuHSZk-FxAnj4+PVimYsLmEMUN-+YEbpw)K3UhV6LmO{Lxl>e{iOVSI zv9;CfMp2FBV32?pG5@kntZg8abja@AXSG9|9Py&qeo#;REJ zfe|3^!fVm@iiaJRBdzVM&pHID$44X$9a-xv&K>F8>XgSy^=hp#S~W`=2H(+oty&&6 z+rUw}2q7qnfE*Rn`mwV`K^P%7PB1{y_1D%GZD-imnx^a zLX(F5Da>V~u928WRFS-FwX7jYK;2L*7@b8l9|vN$^+QUV2+67jC=?i*ZRqAIJjda< z0+n9`Tq0C^2&iSw)CR1Ko$G?Iv@L>iG4rBke;-u$`f_^%$w+;RG#E7uSx@u@U^Xhe zhJ9jr9i2a*n~#u03q+-x>cRC?EhMzsN#Rql;KZ=Cv36U{knJ5nTe?QZ5W zT79%pt(Qj{6;m!@cg`M#;V2(*_&+b)d+GS}#N^~mYM*krJST$% zIGt5-#B^Maim=thAh z$R2@TN3s`!!z`moB@e-)t^}b%ftqT#XcZcvh{AQazV&*=LGLP-OmUbM3?iypQnN&4 zr=cnAn+(9RMoKN4i&7(Rqhx6{4=XN$hm(BAwCmCfbMkJanZ{k$aCO+g1geTo=sa}R z#=PHgP)g-WwKg(}q}puFB5_n;p5?|!eXLvx77cG8{7~2^iWz961HvRyBs_R=<~YF3 znpRG$JHNbs{@kQf3sr7VW-2_s5$iML1i-TJMfli_&a3bO*+6D6(ybx)x!nT|5~IxA z0_$RC-#9Mw11nsttWTafk7@rX-IDCLG8iY$(EsS*8-L{%Mq}Jk%B9m>UlAppK7JmV z@68RZlqzhREUfo79Mvgp2V==1a>7#E!nd#EeF4lcigLpkK6&EHa*H^6;LWeJHn6F$ z+n^c0GHWpFyI+(1$yY*#k1V&5EN@23Aka`vx2ZcuQ0yw1>oaI~H;x5)I@L>jMfzxQ0`&#vanRo?P9C}7sG4GCasFtrIG>lhrMzZgxqe)j zn@jTtyKWj5Q^=Tnbq0r%`U zdO{PfVOVb@~fggyZn7jH8rBjHi^#W0lfa zr7<=#QZf&jk+IQIZM0Ua*GJsn0%{fLa1iG*(MZMwD3?U;^T;q)h3YNDZbeKp*I9(& zCQ^~~TUK5=Am@q8(?_9M^wumMlV>I_oJSgx3Kw!rDlD*FUENq&pO)eVYRp`cVG~L4 z@{;f#lV>y{Y3wg8EZvqyXw;8s7{AU4^B*+V_j5SIXRtl?)`l$PV9AyA*7lQ_6;^Rbf16mDO&m70cLrd=$Pfvr4 zu!6aT*#N$BwUF)d_##$h40hK)F9pM3GVts7a-1)sVMvlI$1)NEv+~@)DmjvW(rRr_JJl8(_bC zNTe*e8?sNKh;+wXf)jMdXmK{g94-DBT-@M4iWr$XX4uc{8~W2BRB+zIXUr_cJ{s7p z7zMMXxq!!VLD1$>p(SF4u&MYZrYmUTd3cVtpbet|QmH=U#*`@;P^UVp63Gw;i}QzH z@?~2mCvu`f0qBZybIn4_74FWFOFwp`TpKHu%cC$B1V(qJVj(`&WCGu**G5VsjS}2u z4CFI)e1at~InK=-MmrnQ0kz zeL25#EGphP<322hbq65Xv}h9vgAHFUX^hwM9GE|YRelEJN@wXtOW#Woh4$K6Tl_&;X4n$Ag4k7@OGIkutAw{k7qeV{549`uA7Zf=p>qRjZ<15yB zV=eycNiUfi;cEkHQCO8!B)kM#P0flt)xu?GN{R66)y;@-N<@c zV}DPSR!O^~CPho{iCR0qfHG!|XT#11-8mp-YqQ2xCCjE!3>YL0j=H9WRF-rxJx6Ov zw_<3mcm5dh8`t4=Bim+=FrQsb4rT}w3D7p77MJDXg2gTpJ!2_y(Tb&@0*g^H9XA{T zyW|P?<^|cv7Ws1Vv<%4m53KDM57m8;Iq>-|{ zBEp2X&hn9Jy)sf6E5U_pqvbL8(K(7{F}JRXN5Bw=VJbtVq4QJsg%kzu4;;xA{ zTmlHXh{H4$<#b4~zf^C`y(`<>xr?u2d&8`H-IqZ{A5JL_c~kPG*y%L(|I9dx6b5DJ zj=PCZ@N6fFq%%{pC~VlfuSbOmo9`-B!0f*m2#zhg&IGa}SANKrtxZPs5KRc3N0#-M z6*mW4cUt7)rQ+^o3yPD}!^F9aI^4pq?B2NRD^Wj{01($PY+XgJI7RU(SZ#CZkO{sj zEykb^aF^(leAry_)8aZ&kpf#x# z7GRNSgq>*|iUVX@-fG}x(?lhfk!0%-u0`8btHXLO3MmV+?P$Pq;^YgHl9q)6lJ6sj zm-yjIo^vp%A|i+`X=fBM=)A!aZPLiGu(ZiQAUCttxV)75B}LlP!9<->t?Q^67$j$> z*EeuuH!)JxrAk3ckq~l&!$d}$q7+9AUo!kljlHtj#+Sid_s!Fw zsbD$C>ARxrJ{&BiqWK`|+PoY?z=43 znK@;yvnD!Vk?9s51Z&{3Y|@4UT0{w`7rC;t;2_pZ!d};}-x)BP319Y5b2&4APfV@L zOS2oR@{cl^*61`Ier~p5Jj^UuH09L@D9kkw2?Ijo;y{8Zi|O8C$H*&fX4q;tiU|?} zPH`n&Y0s-4teMKe1l*w=`e8l@VCuvwbwW$E=Eos3xfwbQMb_kzjmr#ZApJpezMy3U ztxIZsxOhP88s2tE6GUQ9mC~7Se4dG$ISJK(p=h=bFE1_LcG~FqyZN!KLiiSTM+S?0 zwi+8D85JxAcY0|mmF#e7B+Idm&@iVoGDD2wu}s8AN`wU1lDT@@DV|4rv^j8RHzHSA z%M(S)TZW^d7}68%KIFvkpn(e}X({Lu6`--P<;t^x7+?TE;(tL@0G|o{kfZo(r#vCP-U*Otn#I$Jbj-s;^@O9a&^Pry&QI zAtU~Ad6~fwWo)y3%G?K{91^VK2J@*qUNjpD`SqNY(Gc(gQuRtF9Rw(zJ0z~~;} z1P`JPyFGx8>jqXCZuz;(V767PdH*tGaR))LYC%va?g3a7M`=!5!n7R+@{4YuwT{_1 z)4BDIoLfz>I7S=3JR@;e%rseT%3@T^z#NcHLePC!7sTr|{HTmygYv$BCg@9*lCIcv z^|u?xUTv-fiCIS6Xxuf?Vjkm>i^Id(pcL8O^-_va5vq;prm)a~7#9FvpcGEmv#xs+GAU-DkK+-@~vP+OPl7`vAR30L18ysM7LxZHu z5}R07MX0vQ5><36^ktF29t|cP)Pd%XEdvIN`iaR)#pz2I@q3S;$k<>&l^m`mok2FK zVgs{Pgj{t*J52?nL>PSSv-mpZtwyypTC0wZR2!pXqu6?F8(kdRuIYN|-10oGY>P9t zS_fmBMZty$oQLHg#$v`~l~5k=Ge$c>^2rN8^AXv)Z_*fu167M6{HUzE;A$Y=GSg-2 zh!NuG7|y*e0Eacllqbo3YHj$0S-B9((Lv1x!bDW)pIm<)B&BxGS75v#4=jv*t}tP( zzn^7<0xJuMQRE&&3 zN{z`}-TIQGGj+)a%k(cT#ze!c0X|g&&$1|(9-Wf2lz9V;28X6OiDP=VGqe|AU_XIk z)7b9l6m6Z|2E@<&=fvz?Sjd=+*khNri@51Tt~)y2x)7s%1>y5rpq`)`5lf+Iyf1QS zT}q=RqAbrH)QUKpv-1evg}!*%;sk)65f)O#OxNzmRPiQuCW=F061};8wb-1aT3PC^ z<<&1*19vdTjc)lib(6~MZmbrIGCStxq}<@D4-aASVaa4blVY9En@W>MQm(n%pu7RTT~70#z1o z0-))o%DD}J}q0Scr6Lou8fN$3(h zciQtQn;|X8lhQ*1a-F{yyKoD*>XN^njG!4ZMAs34v`kSr=Pv;!wk4_<7;?V-;W?U9 zBN+fZOyrdA6kJk`ptmtTAGP(?!+{(l>Pd#VFCJi1Jiz)UGH`RzB=k4$SF0vKco{;1 z{E`B9ww}v?%tcO!{8u!a8P z)|gbK4sPg&@pHpiET?LkgH-2;;yj6%Hg{f@&4@YZTQ>8yQVs@@1GAYQrr)P`!*#L|Teton&9eaUR(yFcy<^i)Z9@ zVvNSaj7Dx9JO{n=h>`lObr(`abH(D3Sy#~3rAYdETu$SHtjc|4)qJ7P% zk7Sx)Yx;sm_MotQ2VZi@9*YQm;WE@gCFJJ9d$xKJyEV&Zj1s?c zs1+U{dDD;soSI>BD(37CM@TGQGvmIt5k?N;^T?<~m4!xxr6Xnsewa#gB$yLx#xsK) z8WT)uq1UOIGA7*DTuX2-mQ><1xX$yQn?{quuErD{(++tj+3sj&)uTmU$#gT+B@*w~ z+5(hB6o>q|9}!(-^Eblg`V4g0mtuwXAd-xst8oh@<|nnLiNl;3&r@sdcYa-T8^fe@ zdDF}7^n+qcsLJxHn>yUrOo|*cE-R6dsOS@E5RQVkVvqn<2W1|Pw9JOwp#B*Yg|r+y zF^wu6$*A20^Q}RmH^`TCKv!3@jA|MWD%VCvFtCnPkOfCav3E2|qwe-tuhd7dij0u2ow*-J*tOH7rcPhr(V5)*~Zw4+HpDV z?V8XQ4Fn}KnuyxC{1@llJYacU=6zGF&`nJ~kRdRY0>x6I6E~@;4uy3zU9p@3P;CK5 z(o=EH&I*{8{63H9h+wbn4M=Xpn7P4BCE9CIY!A;ZX|o{)PicF4N3J%J`Z`~T?Twak zM|n^ZCk;nQ8C7LK%$AKL>>GaaQl^v#8lBe^#_hyuiW$KIfa+A3 z<X?c;ye`Q4E>EmUJrvCt12g%OMe&Tz4PjrPl2(R47hO*zrP|IT>kj0?=4fjS+zA zXth38Z!}7E#It(2GB#31QZw(l6Hp&nFpb?>^|s{6c(0u?mt(P1v(wVf;H9F?#SU6D z0&Z=uF*~;0(6tDfjgvA;OOtndG+W5*CTIfpNczIW)MeamRyN#!I$b!tgvOat`hyFd zwL|Kci3@O5_1F|(gPW3sU{)~>XzB7Y){x-nrd&9?NiD)B0Te-nevptRYm!dGv7WdR zV1_>!w0lPQ8t*ye#o!&Nl^t7wbtwdph(;uK-W&*y$&g#MKu&WSPL0?6tYm+qmhzun z>B7QP4H39pn7(8?)V(5JB|)LO`eoo*{KBd8lV7-Z6+;~F(sD3_Y7-8Yd!#@) zMvFss<8ThW4ZW~C=9rX#lHD6|fiovB$+#>hmIoxc%YU??e&^R+S?Xf7K%4ntMtef$ zatXq@4A;d03^}lwE+Uf4u96D!fdY{Z8@HkLfyqoZ)+<3xG{P@k&y26joW#|6O^)vO zsG2!VPBWU<=6r*K*9hguf+z`*WePwsY)!bmb_7y?1RU=iS(87rG^=u>+!$+&)!05< z8)=M;*6JgO(C(o(RvN2~)#{~ky<28wL28G0ZX1#B55LHFW0+)JfEmu0Tx=I% ziyYVV9%(Is?7OUw)H_D#BARA3B9 z9T`~5^wVeLF32{92STo6ZNzGkrQ$&y>vilv`%olM0X5O6GwixggUIPsqPiGKa8hPS z)j4-|J_uDigrXs%5$r&!GszB!XC#hyrP;!WttJ?P0Id&^S`aXyv?`RJ@B|?muEqB<4X$$e4b7H|&5%Yk) zBx(&JXeGEEfmvu9oZ;bfs&?<--u&`~cI$2YAS3l8_AgEWphgVRL`#xKBlvDU5P~4@B~v7HdeITJapK zv&4<|^1QPYb;mq+(!^*!u(d=G!+fkX-KKs;j%y1}UU^WMAQ&0T4GSDaWsoaYHP3tt>qWQE}Zz0QxlhplP6D|zchJz^3+8cVw#IAjGLfyuUu8B z)T?!Nc8=6)RTjVSF~!3JBZvEvKv6z^9Nl#3Tm8?%9ji@SBZh+Uq( z2xG&{xr*Hm4g?N3%P*FBm(~t#Z^n$ z(MA6xLz+Eb(@N)af_9f2?1ri!-Lxg$M6h4MB7kcJ%sMaozynFr;Bk%1 zSgJ(1`>ZB2NRkvAEhp^YUtQ)r2g!8{%d_i?#Xq|$JEb*p_cxg} zP6oKCt>bJtiIh`&JyYZpsKthZ3BJKBP4%u2AH30R1;A^UKTmK+hZGB|Jzi@dnpv$G(=FNb5a&`EtchekDrWgAM3 z5#@4qw4oiT^$PCZqj+)RKY}t6&M6!jZPcn56&s_a27hI?U5|}6#>T=?Y-|q z{^VsEo0=x$qFQcp=B~586iKkmOrHffvlA~;6NITBsAovwP#a@fICw?qz8^Deh-ucc&H2P^A5sS<1c39UezWzlZlyy9k z?L1)9Wh4(D;9wtpJ?hQ3T3fljPNG|!E!Y4U@(IkF}5l#_E_9b->uEU~rVJPUk{PLBK5{Z;wAM;W;|p9yZ!zHa_#~0L?C4x`6#peAqV% zWrFtlI)}8_UZV(h0TM6k9G|w-mmidV5ts?-GI{`$I>G@}*EYYCg5VK#S_4Cd%2bUU z)Z|P74}&UgljGJTixHK!_aJbTAUl26l1d%Dfir z*bQqoGL)1$(Q3<4DWK zNH}<~UM`K)kce60<1mR5JNO&*a=B8gARya@Ur4~j*>fi`J=n%NMg%LaiR5moYa5N2 zJl{nlg#Qi$5D7AT;q>&6L1k=zkk+>B*sF9YLBvJUzOPOTdJw9b#fuP#ixk8e6x|-p zRyv1eNxF4%#9-rYp^23w3jJlPG}{2N+Dx3V9jo^m)q)dsX1^7<3%MOoRgxr{5EMre zvk{KK{4Qaw(X3>PJ~E96I%IQ#vBfR}S( zAjif=dl_}o2a;~-1g!(9dvZo@Y+>*L^kxDx>d6IjG?Xl;sp>XB*=D8(Ky*s6JVTIU zeL<+Z1ea~^$BDEAUvqv?2AvJB0i;!UXV}?Yh{M7e+nb+aHG){z83^~8yfUQrdAny} z9?l7wLmLWssgb>1yf9tN+-7V5edkUWW~XfcONH;++VhYMTFZYx25XU3Y=8-V+5vdD zq6Hrl(ICmC=GfgOp(_?(45JS8b7tNWKkFih^IZiL(I4h#IYw@zrrp(FbYFw%Taj7GC+< z<0+`vD!*8Q$0+j>wI3e<-!O5~kI0^x{u|vszJ3sMz6PrabqYJYV-600)(WH6an?=S3(6$hY{P;w1C(b%Q~V$V zfTW*nh&iIMzoi2OK;_I!Ip*NdFdIYM$XM29mu#wa2Z}L#8Z-HYIT=)gSttr+nU~K4 z$d-E|q*UisJBIQHQMO>OdH`W^QGFN^f0|Vt9eWA!4RZSm+G1vyvtPU=N`g5}`OVKF9?r0S!(wuvGL< zncP|Z8?B;ab9^MnoO47Jrt>-s9lsvd4b61kXf(=o4(&l(;2@9@Y+=~l>qTNg z(W(tl1w)f~D)tGG1sTj@Vd^%!=Q}qqaU^bM6?06tTa2|)P-5&F(C*mJDVfcG$^igUn3O5o()JPRuk#Oa6<|-2uvY{5_H{_!TYTJ^V%%g^eE{SBO)adfGv7|*;W4Jo5 zWbrmxmiQqbyewJEbuBPh_QMEu+F=1_c42jP17CYIN?Z43dslIJ)^?n=9WHaLq{13N z+HEN27Ju)VGxJv$e*D@ZXE3b1xw^K#apUH#+h3~HYNdt_o@u~w*q$f*5kOlR9j#Yz znlblK)VeVH66WRF#5~+{rq1N?k!knlNqJ}l-E^ts)oF<5TJgqO@zu_CdzN_TW(DBM z7Dn6vFY&O+kfl!j+N_KbWPu&6tLYZE=mF9tK9tn+HGXV#W}r9!RaYm`<`RF-0T#XfkBE%8vr!Q33#4F_x4P z&B--8kA$C$iSU)Peq<`_N6LhH>zo~jb$>b04r12y?qd(+W`L%Yshe?@R%YW8mmi{4 zoV!1da6p3jiH*f;f%TqN+@= zqWRS-?$?cQ;$^o9*1U(c>Vudd%7<8ue7I&_+K^&Sv6u@?^ z3U|{FcfkJ;k|iNCr z8hq9k`6Vv>u9Y+dJA=E}&R|J1f--=}Gt9fVtgCdx(x06;nTwaNZ>9V4!d)pBQ*q1Y%^wi@7U(l=fK zowh`N@$_LGWgD5x=d}%G*xU^w+G?EnAvZ*gACQUB@6MF-!iGg*t>T~~owZjqlA2=E zgAJujMRO%n%!0}$Q;Lzy`~<_K5wK-WaHS=##{pJhuOc~smsNh%C%R;H3C!0ys7Cf9 zTtU&d?_XpzSVQQx^LEypl&4c^d_J!3nF1jaZ&?21m~kthVB4_tSU+D0H$S}4*11N9OXb6*O0hh0v{XA<8W|pom;cHfo^_WhoTWE{M+;{S zX!m6q%N&c+CEWIycqTubyw^>R<*=f2NVHrcHvlt7iXi_0N8hla%@$EW44iUxj8dG$ zrk1ym8TcVD!ISH_$_5_Esusk-2WE@l}{mjG^eitY>lDnhv1x$XZeC~S2^zF6d zGN4A}iRzz5{Q=5p*yU-AJ)Hk${`r#M~KBKK-URK*heU^7dgZC1tAsSMBV088KNNIb|g+D z+mgy8iXM2L)7trBK8xcA^dlh-XrfeW92LXfL=)825BPyx0~p>1%kYsTrgHp80WXTW ze2&W;dWXhX$35M46JikNFdj~Q#Nm{+U4Ev(eM;GG*l6%G1#&TEccB)1@kixcc4Q0o zbRoXGr&gr;5AwjV-GRa1u9eAgQ>&fVkNZK^94)?}Vr$2q48K7;7A(Uq zP(Rzlh*qf!LO=%uIfyyyslI90O*a0jJN+34>VhY&QZe!-s2Rvf5mu0OKO74%)3LACdwFbt<4IqQ2MhRZ5^%hpRw%r^s=c9%vbVg8H( z!0rJ=|25dGstgi2Dp+kDh)vk<>m$ho{Vc6nFF_{{<~&iWCF4W35JxVPbCV|xSYa&H@D zy{`l~1I^XZaEjWLz(#`DN7_fG(H-^czrc)dj1!hfDu)0{RLGnOf`{O=mU81hW&d%V z;PWL&wrzC}w~ZOA4F0-QP)TR}Ari(qXBjRQWpvKjTLbqGwv$jqrjGl-i--i9euP?< z38GC8#{g8Shfk6Hx=v28zgOtZwdP*OYpq|TT1PlJW`3DNp4QndCe@ikofp1ji^vb@ zbgpn=x~((|-BZI zolc{NK1hCwt`1s-HW^5^KM)DxaS4x6fqr?IhKbVHx&&;Sa z1rP{cNfTFS9tc!)|La_+g@(()c76}RVhuky{$%It@f5}f`-%gO9cDQ%XGIBhA? zI&6{r2xrB1jtP~t3eE;M?OJsSS-FEVK{~fNqn+h6P%?MQAQG`=VG!j)ZK&ToJaUkj zb~gAlnBaD4*(*mv;j5)cVz>XdSu8`2k4Kt7p?A zARcHXfhPEm4WWnlLvW`wMaEQBV9n-Stk*VE{xC+n*fwnO_xY^YsoEVNpCK$khH+~Cjo!`^wu$u0~F?cz|wYhk>pln8r zxNhF7xNLdPI^DziIAO zlue||H^@5eD@$QBd-x5Gobo8r5_jjxxEPGEA`{SU*}$1Z9>aocmo1fziot(R4msdb z^a{%?)5eHG&u>@TQ|oJrz+W&4)S9{^+}dm|C2 zn(}>}wS5)ptK?w}%|`y3UAsati>+zVRw8=nt*wK7L~o7yX&EQF^87HAC56a97A5+c z}ol$tPHo1Vck@2kJ~r0kflNE0Zwuj@kKL+h<}xiU{QW3?peQIHR)e1{97L z)Zz&wHd2M0Pe*)#95NV7WI^;biOEdj#NX8Eed+SyJz9RA`XRq|AGKi~Q(cQX;B`D^ zuK1}>fhe7htM#n*#Dr{?yG*9~ElD(bd5gG{iQ9EwDwfh0pwsN$%Qo*B7`1<#!{N@c zR%pLVZX1Gm0VG%(7K(OOhcowGwjKe%u-o8xi^;>X8U_UGI3{%c;EF|+yLjPsAOS3=pKA$*B~o8L`08a#PanW)n}4(4vqXj4Je1q!Vs7*yY)A++#;8*kdRB zcdMyM*GM-Yw^s1=N?f^1iN3pW9yTHfaa+6Ax#``=nI9yn**cHO6xdfDtU*MB=JDzC z!;BGKM+e}1dWlL?I(B>_+v9vM5s*uQJUt!%)4f3flFjDy0D)KM8D{5Q`VL!&h)kMB z7JVP{vhQk+OJKIb5zo8G^-}7$>^~1Suba~BUTHexD;$wyl%Msr(4Bi^{fK#bSF|nI zny|fTDKH&^AW8zH$CZO0*x(z0l#LH_Zit;kXBzw{+LMPpHdM2K)_I8J;tm5pgaCsD zB@>l@D2)fL7(*_c2`U#nFc4stH&~fB1{0RAg>}ge9Fq z9@Yr}R1_`S7@bqyx24j%%!1L&ei<69HDs}OeoVovR5|DK!Fe$Y{T?kYjnlGo4a<$^ zV(P~8;FTYA%(OPPxZ2U40cRtyoH2Fy5N-kK>Tsm9(mpS6oK5^Kf}qSGp2kJ5ky2`0 z3bw|;PHh95AUXUNi%vGBC0e9pHWs3K+WAN^W#ZyF?Ir+F;5Rab7&x1BknIYd*0PN0 z$}SdxgYnb|ej!h1th(aT?`x$l^k4tkx`5 zXUlE;+Gbf1Wg(SU8l^TrCNe^FrQB*)@p@}CS|f89%qVEKQfbe1MrYf#YJH?x;-8)5 z{CZWbJ<=$TnR`*aQ>{UQ+)AUx6m--e{_^v_=`L*yqW5!li`GPCX24$y4W#jNBP znVya)H4%%dc{gC?DDpc`!Dtm19wdrNTbVvSbK(5-C4LOuTyi66l*%AdX}-hR845yP zsfRjm$JVc6#9+&QlQ{*JR8)r__*OF6NVDIcLtp1rb~Y|9PxxjzUuI+&L=?=>+r;sJ zl|k_{+vx;hw!QO3erXZ8b^YpEH!<=OQfcl5klPL}6Tq6d7nh)6sfRuio4SyQs&C^F z40z&BCqXUq5y?w4$SHm(eC8gZ6ItBoC@L3+x9A(MP4CeUH~UaWZ}Nj?Zz+Cy!?!UU zUi|c-;X(B^bB(e7X9SiX1P>>&r$;7f$tw)Np{!bdTgvvJG9t*IGzkfTGhZB@gz&8N zu{d-vR=siPN0&DoS4p*lrJ0}L$9b~u}*ok(wgm5wI!xiEswA)INNIJ zG(46zAz|gYk&)&s&b94EvsrD9RXg=owbN>~S;HU2@IKm_9UUpROQWsQ?CeOjRhk>E zs=V21r&4cMaJp)Zw#xN(d9KnaS7vLKT79lThSAQ*Xtjyw;~WkFY}9FU2qv5Ms?}y` zuGWMA)~Io;F3-m#!dT@ZI=!OAfoW36*72d0O+#@2wd?7np zj=6^+v1(#E@33h$C;1UJ6oW3Ez<)4KzzbZaN1947wx0;VQV#tQKa3#z0#6lyx3vES z!QXzZhODjc*Sa>_l}B+(<$R^lDhu8OICqJIO892kg_8yF*UssUGq^uGf-SB3>FNewC1WZH}ZH9wDuu)D2UXJ24 zkIRERCbfR{!<5EZTn$!^+25|;FRF5QCPlOQX0Dd3(v>*&Po5OzD36)A#G)Y5l`QY+ zDtuU%xo4puv%Tkb0|_?WnyfXzcBj?^1V<~gqjMwevCdedHOJnaN*nqy*O;r7+pRXv zM$K}qKHC{^>PO}t<-Guqba;uZQ;w*YSzbENLgcZ^;)@udmCE~o7D!tC0d!Q zjI<%94A1CnwaF=F9o$VSjC->MImPj9u37I?sv^uaz`Ro$8Eti{bB#)yb4nZK_Sozw zP8;9?a-as7!-3{TO7d9|afXtPHK5Ox4%yokM9|p=Kbc$Y%vPER9d@F;7HZ`)Y3v^z z+m_vQS{VBfgFxaAQqT_{e|Ltvjj#dPA!>n>-h55;z?%+*X)!Ek;KlRi>nBf5T|6~$ z{L-nDUo4&qR1*{kOw)E_3#vgqx!kN_aOZ$olRs^aMU>dsm|Joc&B8%P=lKT4o(fcl zwAVvEXV4xVYXChma(#@A;o8{=@G?B|CeuL-h}`_N2Pgo^8ml$f)g@O%s1^Ikp;jEl z01pCoOHG`cf33w$%REhr*5)q>Ol9kw_Qbk4O# zDrMlN(VU~*ty;UvPcsAdt&vW>4hXTTUTGi*v}enedb2V&*KD+5{EM?{RV}L(*PiU49Y0GeVTKv zHaw_a?J!oebgIJ{fny_-&A66kLChAv&RCsmwmCGOaj(wSA!O)hm05fUP^>x}mNPmw z*T!KLp2vAy0F%xvg-=1#fE(xq#}JI+%ZkK;-Uj%f*o{CC0l+GIjY|TV+9DaIp5Kh;#? ztV4hZ_B#SYhRy!}**F6|{U&7{@`jf@9b?}V=j{vC_-KoyVri%9rE>OA_kul$VP3znKBTf)63+y}$GH{7>}`_6FR8t(n! z-WTrM!hL+J_vf8(AOF{{TFN_Tr|rJ-ix=(w{;&D{onQC+%6I&J<>Q_&`Iz4~!+rcY z58n;<@dF_o?jQV5{{GZfk1sy&_bZ3|p7i;Bs_yqYhy7k0_WS#jejoZXFK4sn;dh_) zd+ABPk5|I|tDf)fPx$@)Ykn`?^81}dzi(a-@f&`BKirGUAsp^^Ry@4&rr$Te;`i}Y zzb9+qe%tTwhVb1G-u#lsPc8X-NU-tV4;r{Lo4_~?I_q!)A+k8y@jNkA4vftlp zI=sDiGu+qxUfS^cJK_F8xKG{i_;{eE}D?<+U_ z{=qH3m%irrshfVk@}+QJ_xpQa@%#Is+;_j~;gwCl55;o69KxZVyFcyWE8oB5@VIf> z?xnB#{hfb#(!%e4&+qSt`)0T&Upr;#$!~f7@o<0VH$8mizX|an|9jt_u>9ly>bTuk z{-xiO5Kcn)y`S^mDxtf!|ktBiz^ge&zr4a_$sQSh?>F`TgC0On_n{E~LCE+1U-NdC{+8Ew=T4~i zPKf{6m>%wTLVy3*%f0eFzYl%S-}~SQ*hzw)yl|ITlFzlL53>HmqxkN*u1Cm##x zuX_3KyzckXYkq(K4?O?7zwh^{U-EnMAN%{8=luTOH$phf!+W8>cfRlO?}u^yAl$FK zANuoszfToHJ^#-8RlFVQ`;#*c_kZU1D}V0ysekYHcf)v=>SrA%6K+BtNpPJijVKA%owk@7_Ye4NA)GP zA%BnWDK6&Kv+9cZVn1S@Sbn_6cwR}{uV-E2 z&uW8YkTgC#D}R5;qvwz3^N=~dtN!TO+7O;qZ?endZLD(nRk!jhUNTQCM+N9vb@k@@ zLNF~qKC28XH>CB1^3@jAt#b4%nMu#eU*Jp6Hf~`Y^elLYd6XERV;fXnEJtm7G~|!- zsQk*K{_9!s$%p=IV>{^2sw<9(%27DJ8=n;)=TvbqUhUUM`Spo)**FuSu;y@2NLL$T z-UwqctOPwPK9;Y0@-dHBnSFdIkK*GvSR29^s+|e_QoT%b+8*VPZBzL>LOC`jgjJ@V zA0?BXRaY!u??!l2T`EXnJsw=iB;(g4c1U*}SbNOH9 zS!JnCX%>1Go$DHZB4a#BR*u>k^XNIwg~p+mid2`LReo$koF}zGm*Vw_W1{j3RAg~H z>;3p{jJLTs;PGmc8m2rdvp@H&IDJ%SY^TO1J}ZB0PmGJ@2vPN{y7Fy^&${c10Px)1?XA%WBZg}btqnU(Q`ekA6NOP9KlP>AKM$t zjPI(^H5nnJwB`9dRE)=b;UL-F47`Bt8V4jT^)$; zK9!5_5An(q$6R9)>AA{zDdbmt@`G*2i~@df@AZ{_r6Wopb~{-ogVDy|UPU~|gED397BT!{I%WQ*k|d$aN1 z7RFF@sXwuiZ;+7rgj<}S>I;^SDTzk9>G zR%U<)<%w{mJg?;7B#(n45PDDL$97sdeZqLB1F>xuA7D~>Re{pP)0C!D{5%Ycw<^Cr$rkU6&2?dq#pyY= zL48mt<}Yl?U?Azq+7RJQ@AlGn<@a&U+Vd=gTk%$Az;TUjEL-gt4^vp>#5CPwdu$wf zGTanBkMGBN6;4QqDk(wpHt$} zx1b4;TC$z!p3VpXSbMHP%M&-4B?eP98f3nkIK=p`U zE05y)L)-McJ(Q{E*fy&-^h@s^Cnc8O%jm{(l22vr%=0WYM0vcOS$h!ME#BrL&}3^v zh*$nN7kXbvsJlNq4^kgv`xPJadtE&?1~v{oTej)0PcHzf^k}!XGAymn($$7!pjWDd zje&4V&o(9uO3bf0(z8Aq2i?^djhmjWoS}l1WBo$7QM|@b?bNeAz1z22+YE+7oWb7K z{;f*4=R(gweBO=Fp!U0*xoTxtf1v|b9%)HmPeIT6z@zP1d1Bja92s+^E4~LRsJq}o zN??rVg&sYtZOO+TvvR^XXU`-lkNT*zm_OggZCo+WAcg7K+w5&n`P;)dD_&$8|P7ViI2qc z4mklFT6nU(m6ilA;wES*R$7KFuc%QXe`n^FkLJggMFL})Dl0y#0eZGM+S

    K8qLY*~;wQVtr9NpHDuMO>Dk~A-mPcBA;lYxTRgNeEi>6-eb*Sq_GrG6N4#F;+rmWZuFvjWyVCNv1vpoH zQt*29u4uL5R2L$WJ*)ki2gQdmPvJk}fZu?qNo7Gk5w=q}zQ!oa#Lww=adVbZ$#L6Twwv9QmXTuBfDPEs`214(uz0!+gen2v% z;S_K2*0w<3G!7b|m>&?ZdNmIHTeo`IJS(g`s#kPCbveHH*a?QWGm6S%^9ViHv+_ka z(Q|K@7d=ZBQl2nYX_-~xVqK^j2Dd6x`C^&$#l}rz8(~=KaV~s3easDR_xd=5_85%W za}G{oA9df7Yo{hfd7WQ3o=_WrxJ&0v%goa#ge1k=oCexx{R+Iy zp8GQT^OKYs%Ypo){4|cg)klZyZuL4|D@?5Q*PerHpgEGAEtCg*!XaVjt{8K@%;z` zG2CyI!P6ZF91fJO_pI>nzKz57UPC{nt1RIjH!DBn6*ya1`DLflr8xCBUV7ik>)&nV z#IU_gn!+kr_^(T0eUhOko<_Y$%kM=Fk^H4JYuMwD9Xc4o)-dojwnyo^MbJZfXm6Ts z_1Q~VeYl-Q8gmlSsIjP-@`?WX!QUQazGD?-+uV`Z-;ZU5dUEka?vDE=GE*NcF3 zn(lAU7QtXKo}toQ64?h0F5?&&`>D6>nJo|_+g-$i~)_m1^RG`FzT*W3Su3edB+ z+<8;1KQupke*nVL^?skhQG7oS|0++z8}obl5WDcc?&@V%dSCZ=q2r|K${&ie_GsYq z@NWHuUd8g%rl*o8B!XCetIulB^|!CzqGS8v0Y*a=)_Zw)H~Qk>n2rbdoZ_e6>CcV7 z@+VvOTep>_@dr6oti5k_LSSRq8UhcBVN0-(=ePMwcJA()zuh~xK1LpurB487d)D~m z!(n{V@wA%yw(2#@Z}meURj(qgzk3m?LRk6X*^}e4Sw^?BgRVhnHs!>l;eP&+`u&gHe8c^5rX>AUo(iJuAOcOAlLmPp_6t(sY$z z`9gle)=lNL2U{uj{MJ6i#F#&fmo-88t^7xxd`4@+@qOW^&0|^~4_r#O@v~5_eA=UO zm9Bd7@T79`{q^T;yp>=2wJyD{ameRaI%QY}rR&rCiBBY&U_Dzx?tO(Ny{L?suKvWZ z&ClR=n^vXU16yH6Lw*~tq}LE$>8c+JVz0&Ws5PZeildYP$pkUKWNTe%ILGg;phE9H zrR&+s-?7sea2gi9CqZG2x3?+FAJEI<1;>>z>&ovV*<%2&u)Q1jYnDy|m%>*6mj10h z41~fqzlFz!_CDfa^(5k7_P)=z%J#L%U$fU@dAkRk;I zO*kMerbqaW^-U&|D$dds7s$7TRrbC4ljML^sq(BLTb;nC;l8a~MPOq%woiFo_bDX5 zif|s&DaDLcX&4pD`b~a~=O!OrO1JUc^2{#OW2;+myC*kZ$`da=+jxjVhxRC}YX=Qc zx@H3ViGjSrR<8gw*M3G|i-uI``ta6n8Hm&$m!-XjF&z7=yaKH43kwU$70+*sG}+v( zHDRS&e|9`Qq<7={Jf`rY_m3Pod}v>2kL4fOvGZ9v63dVCqp&`_-2(|v)01n-mtVi& zVfBx6Rb}b+(9^S3cfG57lm`^ncuD?MpJF;WSOLk00g*61*1qje?9@HJpA-g=s8p_O zI@zUk%ijZfg#M}AQ4KLl*C%-a z`jelZp@F{rpUm2e{Rt~T)_+WiCQqn5habmKm8H0(&pV*7;CYu>YO?Z@(hI|fiC4Of zZ*jmzEWV%bkKxCTU432ix4l2@pTR?TLGSzg(Pt`7%R?bjKw&Fy+rSR#;xV0AGsr2d z`4jeO%+mY=JGSTZlWIe%bk(=pmlG_%)t?OQ*u_97-S8QPDV7z>+iI=%u)&LitBsxP zyf%j1m0#(qPBkiC^JinmJ%(GBE31#Bp2GLD`Y54`{}tNg;EL_X;?=VSfi{Ns4kbfs zM{IAhwa@ff)u(Z2@zE9YCyx!70IRU|$IU^OuD14GO|D+mosa0}TRHgCd_;LA)|VfD zji-;c*QY!m$4(dLM`b3M^>vTsyL6JZKMbF>NAqEm$351EwJ5d4h5BrURi4J7aHTLF z>$7)50eau^hZe^2D0!C*@_JwMrB8g{#v=$c%J1_p4anQ0cX+}(ARq4OwfBhA_#e-W zpUTL?qsDU=@{<5h?^yYKsk~T5(zn&dPhowqcku1c>d#Jkr2$cz%HxZrw1F%Ag=q^@P?Z6xO@yk0?q^kNs2F+A|>fl50<4 z`)-Y2OfP8RiBVA4$5Rv3V__ffUcs#oc z($pThWALZ2%J=q%vIrBiMFd^x8V~fbNA@s53Tytfh9_T}7*=^|pu+k@e6VN2szL85 ztnzxFmFL0J78ZPe>@h*Dr+ZWRW&~n+FTL0(6+?O+ew42EYj$*3Sp8!>3ldBf_VHv9 zD5P6|h8}tJDO#X(3n#sUyPnx$;W!?e*jS!wk;WCv!yb=C-qWpqH8)qjfeQ&Szo;SI zv9RKjw!XYPs~_8T$%%4qQe4j#5$Q=G`e1d+jbZgJpSfSAH`ZN#LV!oBG52Yd@U9o4C zZ}o-oSGq=*=49=`x+8g2Y3e^?ujDMf&*cfFtNz~4e)hA4FdkMPxqAkRS$>vdFj=MH z06rF0e~g~fFl!58YU^V}Ev)h>uDgB<`dWhPUp5OicB0+9L5^+K_WXG2+2x=9fvp35 zwpOWdA^E-D-|PL|UiDRZoIJRVLHzHNeD?FFbnCBvvVsmPZ1BS?yl6IgORrXY3nd>r zgWmwK%CFDv|BWk2-dA1X58hHwQyk>bu9)9mCthjNe~$MYSFu)>=EaLINQAOHd~eyg z)7LyS9*hRxx%Oy2(XnHBaQHrztM^m*TB5wN!N zEFUxJRIxnXX4TirS6s5=?q;%I6xGLXrwnF1E3A*V)}IX~e0tOLow}Gf<+XuOcX(3$ z>aYASbt&E8@v)CR{>FWxt$ zt8J{gsu*j(O9p#*&+$WTdo+2(+L4w&^jKeEXwcf5_MaAK?bQh7=9^9o4(!O2=DMwPnxH(9k0WelafUJ+VB^N45INPbT{f zm2EuDkWKstyFXO6v|eiL!%S;&aSU{iSL|D|zjE}Ymwh&4TD=2dcRi`7YVj8nnF%zSxTXW+VYdCTR?f*rkUt?y%gdIm)~EKc*69C=W0%8B_35bhlXXHzi_@S%0oLO$VxkH(IHZ4&ZBoW|gjA{%NX8I{lK0FPjFJtFpM zkDz2M*+)k2u=3fMu7O#K0ss|fsh)+9#~CiDcxy?%juNzE(CC%&=zU%9@b`1v6;^z* z=gCKt#~&FGp;4SQ{_cA_b`0#2Yk=hueHN8=kEE>4YLS*DHD7vHvtR>n)9G>6-`+=` zees1C4w7u;DX+?O>YQs!VaEVg!bddr%42h>u?xLZoW|Mf=pHL|U*o4(<+HveLytW@ zqpPlzE6!l{*0DNRlfQV@P{4W`QBZX$;IK(n*BnQ=CSocXtMV z*5<;#J$s+tWdtj>&xTY$NyUoOyZsjFW1~20%lPp^-*ZDx?qy&Ur?!T%w^5AmN>`M& zDE%hQ7a@UYje+8mlH()F@EstTbeEL#8Ys=8yr=NLN{sBW4myS!w zseINaEM_uNOEXK~O$vLSdSb81xr(!K9^AFHe@n5na>eVgwhZjpv7?VV7<=VYoK2Wd zp2exZTSi78(X!=~(tOY+bSEva6w-W{2W&l=S1eAjE){3nq5tFX*lmxqwj}rwj9)1h zFej$%+lw|(-1{W$PRnDusX;aSyXvp%vP_a!HvD=JQTll`Aco+}OP*mvN$Qp~4e zQj*3%c?6#56x)7p+wbz{<0+YeOuuIQhG)I23ImMu?sVH-N0qK7keAM zd+`f>%H}7OLy-&$6Q((fynD)7kJX{}*fi2a4NY3F-V0-;JT8~2P0!%B_b%1|Zy&ex z%GJT}DCGT6=T#K{b}1#a&tn(^m1l4;e)qcrS2m}PHw$J&SKi*;J0K4`#Hq~{DvZ^| zPbd5{NNS(xT9SM^c`kV&Ihbr(oZ2j3KaHb4szc?;U(jt7E(6O3uWK{;nYWX--%jT! zN&Z9spCRiB&-9-0?)Q`AuCj7v_5M}hp$9#%*TzZl_g-p?VCKk?BfDiAiesU8<=>v* z+%9KOO*rA0KPem^AOGCc)TN74Cr{+#lb-SM!oE`D#iwmdVmV1tO!gf*RQ>dkPd;A^ z`8EE`v3NgEKIF=88I!G&Lob-Jl+xvZ9= zzN##Z`tR)iA9w%L-T!3w?+8(e5eyfS<6HHYB;z(*F zqiSES{YkQqsoGcgbm3D4;g$G@kLR{My<7Gb-eMNV$Gx0LQ)Hp}1(SNRc24qM{>s{~ zeH%T=w?nBa-^N++5x_)Y<#*mC7}XoESaGraw;3H>09G2W_QbHqX6^Zqh`(R>dxg=$ zbA{)~C)y(12{giPf+NLyf0NC>_B;Rd-~5}u`0m~DsUd@%$4TR&B>lf^0l`$jGm86M zl1y2&mErT~Es|DQOg3}ze_Hs{WFi?){$28i$w`a%@dOxp`g;HOLZF)sbOBE!Ib0CY7w6V zx5B3_AJbT^Y+ygq{M)5II6R6hmXex}bMH89Qkuiw-hrWk9X)+L-%P%i97^^PpQZiH zfwu>KYG8Aq+Vkn2qIFXBsY?PgT|8Py-+E8*q;WahlmB!4%D)%e*!|vQkN(_Bc-$<7 znmhH6cQZ8COI%75Zb_C>qRDrmRZ3HR{!+YK$llXD@tVD>SL7w3u-;Qgtr&gr>{r3Y z()*}hY9%ZF?X)z9r6T;{IUs2dm^?0cGXJgTLMdw0IM5a^&5z3D0&~U-MdT)w%mOy~ zf_S?6Zfb*lVLSAOS$)F2NI{?ADYjK*3TJhdk|OcazD{nDZlyBScl9w`Dc0yceV$ML zZtvgi{YLmxshhouSFeTjMZPyxf)PX?7xg{X&trP&Js+17$@%1b-}!>=^R^^I4A-9CJ&*4BIG;!N z4DE@1Py>qC^~aL`w(wcJ5I#+5n3%#cbA3GH~t#qAH!`1WEFuKgL4U!_29(c@ey_|gK<>b3BCwE^qWL9!M zoe+i6ZSa#Rp1K_C*ZW|{aZ4BR&0Q)#$k4q8YgGP${r`K*rF79OzlxebK4 z{Zm_$1Griy0CJN2nd%p9>f>XC*RX>xwNo*CYmPNj@~4`liSch79MGlo$m^Kbz7u^D z{JqjQ*>|?@90e;~^P`6SIq!@!bY&W`Pf=8my{}&C^LGaS-r%tTxAC!uZzpp$=@`t_uSMPu5{UbQycWeT?ZRI=DUMR0q zV?D+8KU#PckaXGvXo83IHniW{CrOA)q9jQJe2s_qFbD<>~K^Ae|LyaWd8Qu+Gq z7f9u`&>j{>^7LpOLjejx3sUTq^8+ zpPvC*aGVmh_I|B*v-b`kx?$E|Oq!IqSK@_aA?V?Lc*Ir`3 zt`w5yhlS3Eh516#DI^3n<0cca{+wN+=Y`~HAW>~sA13)oa&Z}YfO7qhXv?EH_?$r2 zTA|tbT=<(Zu}|eV9Ppqy>XG$glRnE2emp4>t#Qn7g#e9bmY7zsEOe?n50v5Ce_6Qm zmni&tTb<=no~+M4AUnP(b|Gwa8m{)nHlc^vpY}qkS3+GugJ_}3vJ2wbQ+TBCi}df& zLY2SI7QP&MtN9D<{>k?X^Y0hVe6KJ+r-As1_Y1c^D185_4T_bgdVjO-t&le13t?-#B}#=UaS!fsf!v zeQ_xu`#z2&;D032HV3IliJ{ zV0PiZ6hjlgu9d%}XY<*smRED5akl}qn1_EUujA`DPbZVp$y{E{$~GA_kVNyPj6Rd+ur1bFd zyv~O=lV3?T$2WU6dpC=lrOjk>U~|V?eQ#0DW5~=0xeGS~>?K!t)VaG83A@e!a5$9o-?c_6Z;&&1Vo3P+i-%t84}GU#{&gvTkXvXTaPR+Q zKA0p$5;wOd#asQr?UQPe;giq#_>fgpq+2_BcWgJB#PfJ@d~^J##?25?7&4yjGAeby z|7_C3XPk1zsegsLE^11Cna>?Qnjg*m?&L!6y?^7qXXt^xg@xmM>+XKF>W)o}b5q!q6;)yrDSss78Jf0NwKY4h(z{A1uA3Z$&#lz!2 zdSv|e;qheOI63uRkllDXYx?3iN?!a=dIErxn!i+Mm`l&`wIult0!otnSMU?b0?GaY z5CBFiUr#CN`G;Do5S+&`?}yX(Z+@?!k?Oy~=ax^s#_Ks=Z1B+rmQ6CKKEWp!rEn<| z-7Ipmh=70!X}m0D)9Vud*_M2x@C~3)-`Ue9dJX0CdC(=A0La^U?cWB0k;hZsOK*6Vv3uk);eTi^1CuNbJAMax zUE7t6?n-LAliFaiKA5ZwCLi!WklZrZDp4@wn)H@?l6^fds*=0OzWs18;vH8U#lc94ihS#nl?czajE&NyebdUI}2~<|i=MlyGb>%qYP_Xav zoSsMgdtT3F``*{q^C#{5mn`*r7JtZ|_u03@az;-#X^Z~eX3pMDzN^pX+sSY9`A52c z&BNb)>+R%UeZxQhn)@Q3tE_R{;?oG97ig#G@ksc~o??tnvhyo@D#oD-DaCNl=kwg6 z&4TlIZ367b`+PG!d{6oJ6??wrslT}8gJ<_9`hL>BpRn(z?K`pWy<3&~H~aPN^9Xu( zT}+2STGfF6f@$l8;mB4c3h9#nNMEP)wP8;?SdloTX|*`K6qFN7ioY!|Z79O8xBT{X zzx|Ql{(;{D8r$n0!?)FzB!BD?zwI}{H`m*K3n3>>qDOwI{d5F61HcWi<)tvRw=l%F z!UlpvBqjyhTRDKYAM~r74D3tJ7Ls%N@7baMWW0cxNAzNoA%Wbp9RJfj$!Q*NQtVNE zf`{z-5LuzbNk_f*-EZHYwC}Qgt5x^{?Xd5i`tJLG*n1Pes*1C3{A6Dskg#v!Wr-w# zEPxAyB?(D@AP@`*f+2*Pk%fM7JiU2Cmd-Kur3ing`3TI-6|y4AH-Yu!p~ zwYJs;wOW^&|L^zA%sJ;?643g-egEJ0y_3v6XP()gdFGjCo>`896wi4d@HO&lhh(}1 zBnbH}mS6T67f$==tJ{j3M8xb=kKO9AM?KyGKf-^OdfccUXQ)T2dL*ld3U7XiN*Lxz zIf(Z~^g>eN-)8wMM*lAcFXx}q0;?IW3aNerR`g$`rT!@5?)!()R{qrZGL;2zjFbqi zq9}AXo%lJFgEhv~*y1?rR-h2bz)w0E3~{Ce7om_5&%l{Xsuk*Sei#hds-NOGycNeW z?gE0Mj1&S1s3(O3m|`c8xbed$(~xBGT%v;*9s&P8g76d&M?2+KF=C~7iq7;{TM`rZ z%b3_o=`!_kvGsV5iNz-8WieJ|jMb81%@937d|xd7l?YR2#g_H)znK40ni$YNmY~wD z@^q^#U4}(K`uLyHXJz+US$$SAg7&e?$m<#Cb$$F_W~n+2iNl|8cu4$%{2^$BVR-(j zk->SRTS1k-`gKE93#I1jv0RyXnkUbT_dFIFWkR@g05E<9k$@QAgF@hDza24g)` zDUaRt>Y-eZs>cKB@t}GXBNpSS2h(6;0~)qgx!cDOgn?b9XPEjak3QomPl7Zx(0!Ev zg}~IC^Q)5rK)rcvFWcuT8)WGm)et_{f$O)#czKaidGgk(Jov~|ev8y2Q+f2og6#G{ z5S7Pt1uTyBa2t<>2H@jb_+liwN**3vD^oc=Zkyq|FOl&$@q?KHyO1x@X14~Mp`SZR zO)!1>d5U=|#7{p(J>$*uH0{1dJuUM*NxM%{$*Eg3@xDgG$Ejz!oEo*PD*YUxpA+;m zwLs;cY@QmP44GU^F*pDXrW0Z|>+(vkKsEFeLz42Runj}LTq1qI?U!U7xLERJrut>9c^PTHSlSB+SFvWIK+>=9 zbQ#k^8e~iD$_-z408GlxsFmKFsIZugna#_OVo3Jy&iKO~mzSu|S4qUbma*ADnr_;CiTvHEm z8V4k2?1^#*#ui7HGrlju2}-hwaz+ylWrO?OF{0kV#63}FndH;hyM7dSr?QTkBO5Hbr|3 z23O(s$yR}fMyI0P5W5F517Y6A&j1ky$#vi6O|<&R2NdHFJ{sP|k^??HDpLcW5d|0L0O9Rm5e3muS2^u)d;vVdZ5+jJQQQFKIVc^P zmW*zQ0pZET5sBK4!Qhd3{LYTBqk-Nqz+9RHatCJ#7G?E7&m^x#K{MH zrc6I1d*-ae4xhJhaZ$;V^5sX>tgk;V*mYv>`QLy3#XbM%kBLn=|KK=Ja%N0sd{*k5 z^m*e;u*y6!Ky@#LQlP?zziHOwTYP z2lJ<48EEz>rz$Yq#);{rm@`XGI;HG<&zWb$SBU#0PqO__Kt}w~*ki>fa>>V}W1c2o z<2L!Ls7}7dKboK`&c78X2a>8%vMWxSUNP07Q%S{kU{*V?HI_N z?!WUMT^~DR{i51=Kfeb^V9F`!OOn6BPjtS<{gomkeG@+VdHj3#e)8JC{}c1_zaN+R zrd>7tu>qQ;D7u)@?hB(L^$v#Sh1T%haqmMl@}GRTN*h(q|F9Ehz`tRR^;2D=;C~W_ zcAI^FVfP2FGPrQdSKjmR|ELj6L<>z(==opg|6<^OG4Ovi1_tMitah*F|9{ZWUIXaA ze-}ZY_xAQ?jLs;@$QY9`H6z0_^|s{p;VJL;k4Uw6AymN$$vd+!xK27LeP`^@e=+=7v;W9btew@pQDbItZxZ(KT9fnmc+%M$;g8V0(c(+5E54-G8!g`Ss`M){ zc;cWrOmFlc*^Beo5vCV6Oh=gBf+*9wIm-0zjx@!+J0nd@uWR4!|71Cqm~zDI{7!L_ zOIYlUXtF_@{pf%7*8EFW7BVt=G4Z>Gvp-{cIi+)%&Amk$`SA8oL=#pqWI4)M!er^ z_@1H*qR=?Y4?lIY#N{bp0&U z&kcAUddNSv3@x?96zJ!kQbo@1^(wg4_ul-^nD6~M{4ceCKX$r_p_?!45`1@c4e>WW zSoN1zBX15Cj&QDv8Gqx(NFnCG%5C%mx;`o8^U`R8*zLjnYbi2MW*l#^69lN@BvyVR5k& zu+ems*-c`+&9l$ET=ILLyqY$+DK|$Pnj4;1ZqvqJys6w~!_gBuKFjGc zeXe)D4(bMeh9)NGoVNV5Ptsy>MPGcBrmrBkAT2Rv^J&Xtd~sNXM}WvZ4+XQ`{y6s* z?_qwnDJXIK$HKqB_Tx*zQEq>H7%#p!!vC8(3|%sBE*)BR7!Kle$s7wFcPO8(PX zf1~_(A6imkLi~`_l;q*V(r}5+*K>c}%wPU(WPgc{pZAx@{$uEa;V8ct!)a-BT)KZ4 z)n7-yqS72C#+u%)W5Gg0DcY>|ATKB-}Ili^uQSXEM6i9 zB`oXl%N9tL)-U^~>_NKf&Vr@?fx+|;%^yuxTmPi!O-Yluraj8t6~%97Ma7S9pZlZQ z?~y3?#;Ex9QSS4i@{dmc|8)1lQ8$hIZNXo#vux)1O^X`Xhj<|kn z{kh{(*M0Y?qt|}$>c&5hzw6I;uJ~5whf`iXezLGzmK085n<=hc+CTO;^8+Wm@t{!xeT(C*i@+nj+k_||8_b*TUU zKQ4)qzoJY0P5q3S(_cc-O52MoieUyLF3#$BP{Mryz-mI6DzmcD#s=tpjdQuuaOU2L{ z5r<=~8$h=kAZ`~xxgCIZ+W_M>0Nbqrj#~j-ZUMO61Vp$2h;*wo+~t=|maaghkUH=k8NCU`P}oH41>Ka6|~sjokq5XmtZ*i>nKu_Pja(y$RL^m|d|3U~iMv0B7H< z0$h@R){^tejyUe=&v)N`{mZxiHQHVK;JW#HGxlz{?xdpgpWig;=4kgNyOLgvsXckb zeW%Wz{>u}F)1s zJ2307xw}pYuXyFATQ|OR#;04O-Bm{|zNG!(**88qBktBmdN%Z^Z zx7*fS_sO-N-uJ=w;~tK73+*Q+rw#!f4<9pO(m|6CK6na&aro3lLQ*ow5npm0GGvzN zB)l9aHV$N%lyoRzbb`o?nJ+M|={pPh#e`wS0JNII8(v8e?j;8-k+-`NehgtS zOc5zalAAPyAb}!fufQ10teVHg373O{8RbG^G^wcp6Hdyg;)hgvtR1`75cGoKClRL7 zQq@2*XQ;UP7vBj&y5}hutDlsF3=lQ_TEd7EeE*a+M0JvGv0+kbsmQH5E`z{Gx4v72 z12TzC6d2}V6;6Hyu?dOEPwBYK#o*;R6@nmbV&h&gaiyvZnUMIZz$6y4rAc~&FvKE~ zdD|(o|GSB+Qj-Yp3rwR~m-}NK4h10wft8e0d-02YQo_V!xp7u7#d;0lPL8xOMtIe= zVEls=j3rT}17

    rUFTsf$V(3kf+L$tu{QpScSufT0yAH1BA7ju$XuhOZX^BEu&uI zg3eNgq~W9hjtYz#9hSHxGM#N=VrrknRagNS!G{h#TVSMj5Gh$Ez9@6K#3iEQNe1X2 zX=%Fz#sW%6(BF`uKNlEI@USbf%~7fcR9qApG(@sTnokj?@XlWe{+z&276c=)r3_6= z`=bhn^pKdk5;^5>Ixcc%D45hCpAcq@^rVD@F9ar;fI1YJI}3OCHXaL?lA1Q0f*=t} zry|KA6GS*<$%I}|oFT(-fsz=esCsIA{45ntQ6Kvv%6KSY5*2NfG8C;ba^!Li1DKd$ zUr0Gh#U)WnF3f42gws8SXn?7caLk${O43ak;+JsB&2odoq;(UMxNKiI+4F}E{hh#ceRXerH7Y$~XODsjsuGe@(s1}?^gjd^8=r*o4;zM$ z8;%+~E=}g-?B+=%-8A5S^fbayl!T;Ic8!sv#*7`ekTB`bf;$|i89jC#VZtsFQ`126 zqeqV(*FhKwF^%0ynUf@3>hSbY<0gBiOgkhiXI9>AgsHwiL^2&ScKlO>p=wEr2F8q= zaM0v;C0v~J%V8+n*m2`04xu0mJSFp7PddvtVL}#R#H4OtNgWPM#m8@uFs2R`gGL&jfn!W(3QSUC3EAJ$E|Iv>19hKCPQJ=c zj|r&!ua~&&8Nv?O71C}K80w3}gk7NU})Mi8ip209Xc#y#3(fS8-zue znAo=zj9Dtq23mb*pKz8H1!J9K_o_UkwC3l-0pjil#=1(^CwYEq#}(X2i((a+tHPG6(|!(MT@@cbllfnPSNEAi`iYLIrlPh8ZxEm@etbI0Jbm9k?1hZn31N+Ja$V z63Qj6hAF0>x<@6mlHEPSP+b3#!aEJxgGM z6^YLJUaDY{G3!ioxsD5<0wDYA2m=81RV7BDZ`9#zvIiD+85n}A@G&trE11OAKe0cw z!?BS_y(y`88kori`QAqu8LSL79BWciAD3_#PB=E|0qA)JV@#wcO`7iEU6C@l_!rn%nGi1magwc>L85L#!j)4)bkQ#fQhKW-sGB)-C z1ydpP?}hHTj1My?j18_RkliTpvgo+*znm}xL%BpiXR&`Euo%b-K=M!!KFpnjaYO;L z&%j^=`D)Y?0z*_W!evumAj}xhAnW_8f>DSdb3(%nOMg#b5mk$M-yK({@!t(&2|v;0 z)0_?^PD<)0jOas)3FSg=8b$>YSq`uuqa!{%Xzs@`RpwK}A}Tj!0Oiv(Nl!PnJmM3w zbslUF(2op|g?8MyM79XJe%dk{rb!6(s1z6yQiO(9NlIF$!m(=suJ~0gVRRXTDtQTG ziG^TJ5WVTJh0b6#k#KaRNoDjWqX!h5$OnRy;g4^>{Tx3mB zA&W>!xlH1kBD3GbCtRt*Nj0P<0AHiy66Z)jQoTXqf}V|Fi$3^M!pMfSVFTZ#!Z8kw z^v(NqdaN!BL#F?mqp5*JaVHPA#joBUT54m|_}J`6nsUF2VcF^(7n$2h=m zCW%;^m`E8G($C0|2dRZf&7Hv)!8~S|#YqH*A+}?(Y?uTUI?XpQ)L%Lx>UKC`tOT1| zI8IX1B0HRE^tiZU38xUJXeJ?{+zDrMjw21sE=f$xN*g9clb=;K%y7wsgen(|XkhL& z3Z^qg&X7gCgefW$Cdmo@u@X-45Ru!_9k$u&QNmUAJ3-=VS`%)Zm~;wZM3XYo@@J^@ zoC4$ROea0oPRs#ex~0CY<1#_r#0eJ=h8nrerG$~WaG22M>V5K!iM`f=Awi63XuF#P zCets@*I-goeyYMDPf)4uGxrc?Fsc!Kzl2jrSG_kW=}`$s%prC5Xqcx|daS#~O>FEl zDn0F1k7p$u`5#Im(q!7OKiF~YsIh-kFp?B2OddAkBY|P=Vk&`oS-%~ZSu6AJ!%%rH zkfQ5y*g~J=bpd0?6Nay@V_3sbCX=R7xoRO*wV9AjLgHZpQ}hY!u&Gjt1%`SVFg(gt zT-CpX{1OsY==5ZO19CX{R}&`UDO(KFs}Z9{wVJr9s`4u^%19h$)J$q@pTuRi;GmO^ zk#_Xxi&R`8GxKxF0O@@t7+U{w9hY@eq>zwswJSZ-@Yk4d27u?au5hL*1HrDd<4T)A zlQv@HorI|_kJ>`Cz~uBsiIY9kGBbF&Yg_^(Es&JV zPSZ1{5(X$#Bfu8N%VEQ23rw1q4JqU3Vu67fXzdcGo~sCB^8!rG1>+2gxw7-moiOYf_U_G%#JXRnoAhVCWdVvAAf{SPt^||!1y9JOxMqbxiVh7 zPq>)4Qo`7j``u*0>xDmrV6bJ93P*&QDDqR#sOhY zO%fNcAX>To4pMoSgj4OPFd7%P-Na?G+PGjcgQk-EbQKPz5YdMy9Ck5bBo}2kSR{R) zFc(fx_4sQfu2k2Ajk{ijlUe~NEaqk%SEK`C3!~Z32tz2er1W3vkROorOfD=@u&X2N zZ};Ulwgd`2R%f_1=<_z!H{v(!^E7+?ZN8>LPiDw!_qMeK8r=|9IU;tTE9?n0d)j^N zfnc}C-{H}Tg~Hw-ZWgCm?em9QeL>IW4sW|}v!^3~S6@4F+3X3m2D;jsJdJ^luorQ? z9W8A>Peah#xWyL^c^X^2!BC#13gig~Je_d+JRyHehd106^m%ewNNcU_ZuE9^1j3$H z?^Yku^7z_2!`&X{>Or28CClU6-sx)$`##WEFG2G>C zv${gQU>>8YHx;=f;OX#fYr|m&Pm6!6uY(9`4g}kgmM@nzviu!ey>0#`PfZ6BCXRuJ z_D(A^lo|3Y%nU8|WOjKn8#4>$G|{G7je(#qFX-zGg#2M3kcoN2TYbThKhR<2=e795 z`4)bf{J}!2vDMeO1^6!Xv~Ey_CS-* z3ZpEDrJ$kic2r|a$SMu2Zm!Tk;1R`X^oD#^r#IZ{@rTe@VUO426i~>*7YqWQ+gg#b zM~H@nnUNWqVMX|~p;E>}>e=88`c(F9ffkS!%G%Z01eyye=(a#`OE~D$VM1tqUz3wH zs@CWO*7KTt9o?$~9ZS8TFz~g_8*B;z?@hk#*0PG~`m%~Dd6t$}tgKkQjPCN%>dLB$ z^0fl5SY1}WzJ6)N%5rh8E?HH+c1=mCa#b!_fxvd04HD$&%BmyltEX(<7lv$a1IVjhv@~UO!^{dt{Lu0Yi3TZSp`a&V}{!qx<0@eYF zKuQgupxky}u*H|}2Qtu|!)Uii599K7cD8lrOB@oXj;x^ayAM7 zJFd&u(dY~2hXYLkt8{sJRn><2H5H{tD*q)FYuUCdE0I75L-AlC<$_kW)y)Ec(t%1N6`%wj)tt!t8q2mJ`l8SG8V_O&cAPDrt+2lbq zT^*sW&dxxPtjK9_kJGk!p3084ZUYE;x;ojuXmfN7j~zEprDnPKq>BJt32y@%_82ly zlp#?y*9;)zZ9zXq08k*AgEXfHEl9?TsM5m`1I*mBnXGBE3gHcl7uki)51Ft-Ce7%c z?kWo7GRa9-DXUmpT8XyYP+wA7Rk?PpbkMaM)>fCV691Bw)#X*IORCH3qq-=&wKlpQ zo&Lrx9+A8%YKoBFe#ko*E4;Yuc3j27gC>s5Nz3>NL-qHg6+FtIp0~pfl)4 z2Stmk{CwMeja^}H1JWmbc~qYbsTPsE?b;z7WGbDl(FZoL)f@B&x)mMx0y>U0v6?DD`*O zzEz~$dx|(jc`R>NxD_OYQna`Gi4h1=AgzwD#{w4$G?Dtq&TWVBh6F%~L-?m}yFV1R zAXbFBAbK?Wec-FoFYJzl2J$w68@F_}K<+``1Iei@&G1Zd2m_82Lwi%GA|9<&k1Dw% zM`=k<1uXP5b_J#2VSlGdl%(724~D{MZu&6=C%%%y8oZR;SbL8WKU6jvBP0)W8+3e> zm}3Q#WDbxP`6>bwWxbBZRuxfo7cg-QKTV!+cc;%ml#Tc+r3X zz~gOdV%Y+oR(}(OAE`Ziq@6}r$Ci%3whl;qPNbj@(kj{rtlPq%p-MvO7V*M?fTzjl z>-1!0Hf398e78eco-9qI*+?=oB=VOGJV8ixpn5$d0l|DPRRVC(7YejN26mE>D3BB6 zDPxv#7{Nn%nN*FhmpICk-e<67Szsd&Sah}O!8d&9qxCIqfd&<3V1JRVCBT6G z@NuZbPF?X;_7KzPA`hv27#>`7D_W+>)6m5xXDDJA^NgSfN38+$Fb0IAiyq_O;U$A4 zP1?herN@zdkm$);jK16E+v;lzNtm^b2h^{5pYhw+?#tE6oYThilgCeK2r@V1jxxpIoE zfFN5Ju>lD7`7k@wGcTrYIYfuP2IM$NVYFfCR4CNb78^0SQX+#lgrSP_B|Cd*VHE>x z(E&FHy1+^}h)Y|xdg0PdrVFPlCo_ROPQV;#+=F2zjNwrFn89}@#=&Z`(?BOgR3QV+ zsYEzLCA}@^p)#FgjDFHhdn@c2ud_x#?z3tXojYnNj z76>#FF=U_(H5auS$bu@DuB|UCUs+vZRh2K*Zwh?_M79U!ea9Py=9q(TMYcEiTe>J- zwLvU{P@XG&UuzTG9LLFrZJ-88@){7l=~hBM=vNQ`IF)MdYJ>czJDG^yUZBpCCGj~V zF3R+0Yl&Z{M`|+Sx#5a>jP-`L_?mLrX=F6T@FVgOM3(^NA?5M~+SH2@+t3bSV4f@f(0QBqH67(v-tHG@l3sg`rA{g8r!1 z_I7luzDCM+Ni=E<^nj#0LY%JI3L`xQQ`y>loQ3c-K#f8!N8O1T@I?qG)8Gsw9PHK| zNEaV{L=hy1b&uAF8Cg$D%Zx}w0Q(_Iniz<|tGYEkXg(|9{DyG#?_GW*JBFYd(3(mhN`nbk9%+kaDW`85O zAuA!XltNEsr>|q}+LeZiF*afH(`52>#|LFX_tog{1V;jA8YH4Aky4*{w)nc4R_i10 z^`8s78}@xz&!g}4Ujq9Utmm=!`q#kr!9D|<^*G$Hov?SpCL??StS~Q;qjCye?}D3V zAM}VeExX5Gpq7KKYG*?hZI}Ycz_!gxY26)OO-f{fNs)&gnKN`W8SCMU>lnd0^hDHz zqvWc?Em5M7(aj;KPQ*jy?J+C;4IU`rysq>_Dp0d5p$4#d-G`X3GmcaAAQ6D$HV345 z63i(WOW_pEm4i|=Na9gZln+ZrUu$;WoVlZSA+*@UT^)_;&Rjid#wf-Cz*s5_MgjN`itU9K>u zJ(c9uf`&&Dk-EE}k6;jqjQZ@HnrNI9bw3cLip!IOaaV_l&vsIi0bxTOE-#1{Dw-X_ zjunwvMXL_Zw7)Ps~QT@K+p?Sk%Z9Y_sky5V~)yPhI(^LBQHqk%^6%Welc!Q=xx-4osx(6|FJVo0C_ z1U;9`ONA=1_F?LUc#alD&D%Lq$u&X}lI&;+%Y1oY`4dgPO$2ucDMm#Iy@ChBt(0Eq z3}PL`7KJx27HG^mjy<=R3g{oUp`#X4&BN&wN@~_yt7}%my~Txk`WoH(;Lzhj1dnSNa2<@K$n*)(k-`b5cQ)!nd7jNi-*+{rd`Qi;AldECsf+ zRw9$2guUD6si~?^;mqhLHRsqu?@%|mPy0ap%c-@|iwM0#wo`lt%naI{U;y%oh=v`M zPy*1sbp_kp&2Mf0!TbHRYxL8&_xCJ_3Y+e7n{?j4UZuOgbO!QcJa+*_90kL#Cw9UA z-F|$x{i!sn@9K>9Kaksf_VKH{b3L3pAd*vbXxWz$afC85nFIMphW?McntW|xG6^hC zsd-!zW{-+Y_23_*#?xV2T3xADmH`(Ho0iaJW`ps$aSO%(q+7}Xdo9wAhOLy*Kmu;V zWHqpD6^11azsMXcJj78K1Zxy3vYzTGtQv6A z-wu8Cb}69rND)G)Dj}O`hB_5n2W#D0OXGX;$r6U^J0-8g;Y7LtjBErR=J<)&HK31bOjId~uc;Va z4Oo@#0zWcqo@RNQEK|)5fGT99Mpw>xu;LB@*+4=DWZ7e#=0xt4sHTt}Yk*OLgPmHq z8`36)g}D|7LU211!{VZlDy*Q-1c%`_l=8?py6Hhq1uxYnQPvK4UwiHex zWC{`lCk>)xu{%JBMONdGQl>Mp88Qgx*$FVr4CZdjgA~W0r88a5HSQ@sZmLaU+&2)? z@p`yu?m=TfR#Nqo6&%X!Zpq^S;n0Dg8Isu$<)x@}?a3Jy$n0=Gi2-j;5tLwu3}r!y8Z7cHK`wsUF&Q_CcaPrd zZw(;Z|D5Dp~F{Sp!fi&Gx8c_`W1+rJ*R6Sfa_UX)z}_pIc-{Y@!*`(MFx5}s{% zy6xF;_l@7%KLYj_`k9BP+tTmQoW1=YXYcKQ8kW!7qwG$&bv;{xfo-T?Ljb#cwt;Tc zN{VGz0p~7k(vU6t6%FW9!m_29ip@$uQ#Ju^13l=U~T(!2k=78D%cL#9F zgj%wa%T={da+Yu1(d#!H<85e!N~5LKf9#gF_Kra3aafA)+PZCf_l_ykre_|)>gBRR zMa7%yHy__~!ikY6-mmLx)Ne7u7CHEXi?_iz6B0Gk(4P`SQ>dg}4HDH9%Kv}(_us*~ z(`GaC4RS?XlA#rfU?qpiY=0{@f>Lq4pKz^M_{4bNYj5z$h5}g(*Zfy)CBi6@%OJLV zp>$#p43v~+hr+6bti|P-dARK(@mVzAc5q(mXSl)Dr_~d-JQx{1qEg($(1E3H?mR+) zD0wZwW}$76#DlXakwW>jjX#+3aObT-hFTzvE~zQc0IAA6XW#HMylvaO-JyD@FzczM zrG^NVki~z>OYIO|{oEfV8;HD~9ll^-hF6xUxRa`>o|DWOR&Hifu9^gxs@RhN&V_8C zO5OG|?f1;_;F+*|-U#dIaqN2S=JSb*l^uJ@-u`S@5A553(N4zuCwS)IDS2X|QD5Kb zrP|Kcdl?VQZ#Cpw-h8FI6tN52mPC=M*XYdTDWsra5TFzPcI9gCfP{}#ISn(Z+V#?E zSIlrknQeqSZsf7ru>UWJ?a%PUEGX5=Z}M%;@4%uYcj0-kZH@X-V7(CsZ895EuqB17 zbD52{OTVOAg_#A1Lun>Ip}f321e4#!NFPqLFmOX;=(3O;oZJ!|+E~S=J#3GnQ_zA5H{CRP3rc4|_T^!g4l$X+q28imEm7DMtsARB zArTMO%@@RGLC*LjO^*m$oD_1GJgNs_-X&3Cd02NH$s68kV~Pu9x++bXnW@M@wqK$y zc!elSjEgaf6+td0a}e;jrh^WrHctHWzPm8i< zg3Yp|gtSww+BGHBrOWF)`h|p*4+{Vz=uRga>}?Vab+xyX(mxf1gTi^L8LjJ zg1kA0NLJy%(-Ab!9DM*m zEG|&#$ix;KAbdFG0BUK&W;w7nIYhuU5U5R{Ap-I1#)htxzU~HW7dKX@$5To~rZ1fsq-A4G&C3PR z&Q#5%Pg9kUX?C8cLZ-@Jy@+Z7-qF*EZeCI>#1L^ZovRRF%+ z@uZbNEFAYRYjWw4)Q(W85cVP&9jZQ$!6hE5ykIo{5k;$wJvFmdwQYv39!WC*!(%T& zW0xEeQ1f(j!sv;zQ9dxZtK3S1s8t`bYo*=W>GD@}@Kq5)zNZQZjH%@nQaBv#{+3qZ zp-o+)EA^5mn%%2t?8czlW(5|@%`{R<)XP?-IQVs)%`s$y?%7%>GLB72W-ES27X-B+ zz}(|xqtXx}Tgr}Nh;OjK(49JTBAQT#(!u(JZeO2o3wsgw&>EEsFpbrGf1@9iYW6sW zpbO?X14aGhyB?zegA9obDJo%yZzFemb2G7Xf@)tcU1gVt5+jT%++-s?#R8`@Oi%Jv z+9gASM7Qe8U5$oZF}OzoyHy_@$RpryvcbT%EVHUDpv)e`Z(%>T54wABaFB&%iF@_$yUvw7-h0cCv*7_1l`Tkc6dQ z+c@!25{XQGYE^knX*CZSSx-Je^HEWy8ch_#kb$nD4XfDpAlHfk8;b}$v<6gFDS z6r%@T)EcBB56Fq!0F`H9Lmxx6c9bw)zED< z_#3$7(%9K)HS%Ctr`6foDJiQ{6|ADOZll*bL=b8UVv8C#%9`yO)|5?Ic{xlzyC};a z;>%3PjXg?g4fSYH$cJtK>dDU1B`KPoIz<(evlRuLo@xp%EUO8J8heN@t`bQNW)cHV zAdKn|0(uab8|!>cJ=hPq#R;eys@9vkqa^p3I{hrjonK#<(^H!}v#zKXjynEKtIzY6 zG%RT>Z7TDXH!lV5YklQ)wKH>7nEJYz*+o5z7WZt-+nCq0F=t~=PvN4T{6#&B7xgT} z|H7Wdi+dI>?y22WTPW*REf*3W%=qd@dbJjU|ChksvZ@mXUWRS(j&#Mtfac6C#!bTjHyJw3Z9d- zwq{9HWleR(>hhkYHLFXjD=JrKE9}$~Awo@-H86fQ=4I8E`|4_sIu0dX-BCwJPwldn zy4vcnysm7sU#r7)wN=5o+L|sMY-w{{ZHc$8mSNV0G>`x$RMv!qDgzQlk}fhC)vnvB zGov?B%?7sZhRUm(nT1p<{AEq$zNO78+p5Fsw@dm(t}r=3Q@zvFk*$tK%+J^DSJ+dV zzi{!Qx<&hMHQ;9xf)T9;2&kzUlMk?CiP{4vZ@(3D@1f-%mfJ69r%kzOu znwPe%tSjm%sNKH4VTq!2Z*Fr*?o#-P5Ad1;BxN45sb|p?U@AAaXXDI`GePi+ia_#< zi|{z)ke-eB8yq>CYMoAzlciV^IFhSlJN_ieo=usVt|)mqsyYX*PfzWl6BjNsERTLKX{~563 za2UXlfPn!cgbWw^qdm6AChlF}TsAK!byKLT!2{y=wn4@&tgD|fB|;s0von;ASK;(t_P6wt`_a z3w_h=MxkY-HKVaT(&p9%w`~tp9lgHNw###~)uXYqol?-Q-D`T0CRc#%U)Ue_|#G-3$b^i;h2GD&&Ms ze13&-c@v7Cm4%L#ofCqT2vM>JtFN74lRXeg!`T~iB-4$@YaY3Aqb^r5hWw3`K{QkQ|bd!cJ&%gLJFlV6*kQ-_g1E2}WV3yo%k09~vDkADXk&%0`r*t@?G z9nEXTbK%?@b3l)I=sbf`qh;!wh4E8HNh9~jD7s(ahgWN82}lV|UDVY$a!?i(0{+IH z&aMXRC{{xo_&7#3|5i*TTyj4JtF8VZuPW&Y`MfwK(ZkKTL7aW;!My@Fh9fL)W_C_( zUG2if#d#;z+e}t**qH*3hGKxv1J70b(V2MsXA4%G=PuSaD~m#g!I8HCBPkZcq$A*p z41**+8sbB??Jj{rjk+ofiPFfcoXyIthjcG9G+{u7Pi5)m+qczp^UC0CXRY&&nD!wz zE!1-SQQh&Y$+cgF|3*o*(S2Zlw9krWnF39BOWM;hhs0QCvyS@dm_v#TuO$vsL6IN_ zO9E_Q)5hb${89(aMVL*Y{C>?OYd1Ni+c>>0>+3}q4NRb^pIG!Lkdw6-G2bvG) zqM(GyY-=N2sao{*AvtvuRbCbd45u3F1(ua9sxGsmRC!@zxr#uM$pqK3 zozIS^GoqSD9h0Tj4{J8Kwk6x_ev0(8pjcL#U=|EoHnXMx>BlGu;o~~$xORETY;L&Z zg-N1Rv==BO9UoSekdj_!kpe%Cp`TlAy`<$K^rVD;=~i)LwJ*iq>Qd)A-F0CM|aRhpxFU2IS0%;8gyQc zPE{1JvVare6?Ke4otHvBGdJSA5^IOhK(%`3-B9^C`#=ETXv72bjKO}-CJtFDwLJ2G zJXzt7favrUovyMkG1H02(o-&0TS9Vy7aN^MmSA)c*}%eWAY6gz5M87y8|P2B6$vv| zbuLncm(ml+bR_wG)Y4LX)q zbJsom+tad^)h$k1al*H{&%P<`sGVotnSah*J;P4E?6J=B)s^d)cYJopV}Dta^3Wrn zY>ORvT>bF54^5fW_35OHnw1T|+xhs4m#*$Tv^MLJiR+SszH?vsXw?;8l*~Q<=~G8s z`CdWWh6Q(&RZom7eE$5qN56R6uq~6D&nO+abkU-DfBRtmVUI6c_Tl6Q0$(l;XY~I3 ziN(Q-yNiET+TZ$%#ua1kSaZ%1cXuwRIN`c`y`85dAG|m1)`Bl`6IK^~dUEp-zdwB3 z^ecyCX5W8b?R#71h5mHpx6>LQJZx&mpZYf5cz9y?`Y}IE-Icj*<_!rC)_9*SJE3jw z-ne(RSIpY8{)?(Z&fc+O<}FXhcmDQ`&ix@ zfBvqn%a+ajVruIluUtH4PjbfMce1W4{?o+G-uD(fe{lADYmb=z^qUpeFWuC9WAoeN zI&Nz(XgvSL)yo%;T~R*ynnO>1eEOtw{&rr&@W$*_v89*Kedyu|6CeBek9`lHvZd_T z*S%Jl*13L!wdS3+oxiUsJ^Rx=i&o?|k6xDc+?MJi-(9z1OKsMb_rGeLe`V{5BgZ^* z)a1i``7i$I^`z$?T-W{5-t*W0?%5fKWF%ZYY*OZ^&MR)YrT*Nr$4^qfv?K#_K zPdb0)!i6*DeD>DW6Fzx#RMXayTaG;5JN~eHZ@==OTfdvrc>fRHU2@xLwF|>lua4>t zwjTS>&z~v($IHG2bBDh^a&i8;_FVs#HJ*ys^4`2+ed62qzO((fOyT zx9oYY_uA*iZu-%O*LYfIOi%VDowxPR=VWjA>yIv@}>T9*UlRI+O}Oq&mDbmN!4pNbku)2BK^{w3+G*!I%Vni=D*Q$ z(fBpv*F5>c?7DXvD_?1PdGoVn9h1kN`_|zTZmnBh^60jrm2W**a@N8!|LK$Vj!pb- z#k?W6f3fsQ?~ab$B~Pb69ULE{lJbLZk3S>-u)|Ls-nYE;<;2aaKmY0E zx_i%=w&scjbr)6K+x0zv@{kF8Zk;}Mcfv8xjygH`%Ato3eJ<&P+}CC-TRZN<2aX^8 zTsYyvW1h&lbVqk}{g3*4s?J#v+dcKv#BglE_S;^#W6k{^$K@^Vy*p-Z{jlDDeCv#( z|9SJG>`yNFH2JeTS8iR{_V}jRD|XPqaPR#$mZWw}8h7+}r<^(%w|D=HV}{NzBe2Q-9K?U*F#Qo!-Cy*8i*d`F9?- z`IKMZa#r_*anJqch4$^4Nxz?RPB{M8q3drw|HabOWz){TZ}J&`Z2YLJ;CDZKZB6&b zjXR(G@uMH4mmfCmx=G*v)#S%~qjsJ9RLiyPl@ed2;r)+6B z|Gj5_?qBSC_rXrB;xBAm# zX5AP6txNv$|Kd%*IV-d&ZgI{(I$z(NeD%?nUc2m_mFq9s zF#5wcPU#5s#1E1mR*#0fv2f6vn^-%7sdFW-B#kaP z&~dd_+?4hHyWt1ZigthR2Or*EaMaWo|7Sr1yZ|7Q5nKW|?5#Y1=B6Ek}F z8@s;!=bx5uT=Tbg^S^D4{Br(=JI9@TcIjhBJpa~Re=8cjWmEHgH_UvpV(XO`{wZO} zi3k7o;~77jv+{$=*Z+C*pU=%K8DDbVxZ9=_l@5RZTNAE3dENUPs{VA-2R~cilj8e( z<~3txKVARGsTX}Tza72j%(y!jumAZUzdQ5TA+4XiR`ttCO{dR$@|o8zxG(L{ zj=(S4e|7B>56=m1zw*+U>${qs$(Z%@;WvMJ=wA-L>dFfrT+vXzb>w5OUQvF?(CkUy z?)~WF&L0*3_~qrF?eJW>dfK=CcEMv?7tA>K)laGxT?_`Fsg;=g1fSmVll}l+7?3)a&T3P0S=C7{4zGn5>^6L8f2-wn+m21nR zVAWMM1i^5B32!m9_Z52<;ojkp<>~Qo&#BBIa{+<$+t4kFiyTZ@Gjr!Pip6$NJa=@d zAGp*VzdpS&R&D47RBfk?hRVh}b*xuy{$<{F9OlXCI8bYj{?3wuU~uxG=WS7V;S&9%7O2savGdy5Lp2j`XMDR8G%U0VRT z)y$rBh|<8^np8`4*0}^@IoL~}Ts6}Vg5@=WK; zbZaIQw%9JrIC)`g@^%WQwq?`9>|^7(M!5(>&F#!qPczHlNiEq9jj5HUV@%FuS2w8w z=k%iD4-`>t6^hsrPK0AB6byFrW>tGiuRytk;ey~J^cHU$3*4NKE-dpPxp~I2cwY;; z9Jdv>LcfAW^rJd0o)&Mg0n34^kofJp{lk9G9Ut}=z!t-FSav0sS0 z!&m{O_mN%II;5H1@|Iyt&bPJV!VDD(b5)>4?$&Pdha&Dba_$x5Rz#&f&@2uYpt=eT znqXZ(RGdJP)0vBSa3>kK7%qPjZ38Gv?dnyUD_3~cz}(-2jtFfRx5djD3bV_O)iPMX zGPF7wt*=qx5$sNGzSBn7tkH&%4Ra5fxf@H)6UhB4mOF^3L`)d=CTi+fN8rb$Vl`Tf zkkN=Z0HxH3){ubBF%?|K)8TBCQwlLN448hSHkM1sLbD}aYNUcwA2EaXJSxtv` z@R+^|DEsNC2EnCQUFsr1g&5IusC~P#x8D$jxtQL*yhHH_b+p690ffmYsNyi{1}D+C zvVDx+z!@#fHPd;idH4q+QZ3OspnVy-l|A0#mO*)Anbm;;m5DwXp@;=lVD%gx0Zikh z54QCf{IPf#!G%XgY&*nQBd0>3fyS*YsTkP7D?FK<*gTJe3!qsZ00O9qTpnDDV-SxZ zIK0orlqIAmxQ)3fv|3GFomd@XowV`>odZ_`i0(%1*i-?R+WXMe=pwV4_DE$w;^E{ATB=8-OCp?Z(dnFe-%~y{ur9fJ)t6Uw1qQuco$w zTRL<^ryf)a;tB%6Yo5AQTHU~{RpZ2?WQ+Y#&8XwD|+eRnELc1k@7 z>@x|4!@eSCPp;}K>h3Dk#o=9=TI~bo_PFH4l`CVxAyjPsat1>BVLpR}GpK6Co^ezT zgP=0bSx|LKSA)Oua2TWk_sSA@#L4PU{Wesacp=1XUNT>vnY|tNF0EMXuM@k(^~q8RFDHr&4gV z?}kQ99Nf@qVTA%^=T+`bIKpg_<$5PXW6HdMQwgsU=Se&Uox!B^eUfC-2lxj&<#t3Ai z&Aw69EJt$H*Zgth7$BU!&BV)NNLXRzr;B))PS&clD2j7dIL3f87*Z}9h2|SX_SMB- zF`Q1FMIWF%atUs9{?7TPCY)~#;yQ1xK}i|i%hm?JWPPSo(uA(^3&wOiATCBDB~WQB zsXAi$jCWK)90CEE(^ql{ioN)3WNjIc2djq~Fl;oM@@c(-t5jH<`x-e0+j)#imhhFp ztPUk%<JNia=tE-uRwV@93^-*NCv5ocNbQZOOZt-v~PJis>!G7 z@|c^GC7W2?C(REQX+d4>lN3&@aT75QBtK^=x@v+7SAV8{%8d#RAnG=KQjAkvnZfAF zkZnqm7y{(lQA?G<-bbmz>3x*U+XQsdlYDJl>Sl=E|49By$;{nULdddfQWE9L3QvhE z`WG^Ws*mb0L7gIdv<0#09rC@51(Koe5w6|fWml**@u6rxNqaPUE$5mBF#v7OxPh)IF%Ry+EHYD`p_ zKTd-WC~zUfJEx&+Jx6N#gc$}ASMek+I0$enDeoZIGMaC?8hlE65#=y- z)aB;&0Zt(~Y*72X&j$x>{pG;nrS!m#aBYP@Q(lJ(oorYJE^b0<4R`BXDx!SVonpKm z1DY;mihAJlLrB`S?h{!SNmRZ{5~W#C<#E!N34^)6h!bFr1~NP1&GAT-O=AZaJvmxk zT}^L#jiEt%_*9wTm;Kp}Y&tc|t>jc0n90zDLCNR0u(IIKmVKP2;I2vosWLH@=42*l zU)8oMJ*~E78#A0zUZ`YeWcneI>vrY{x5IWvonKVhTAo!54{I)*+!r&3ecR`jY%$12GHjt_3yluLTn{va|Lp=8Z&fcSbz z)I_aU;jmj7-}0L#gK;kSD89e|F2h{|vgDDgKM!S@??mC#&h4FCIYmUf29DOno~mP0 z1a*s>s9%IP5>%h^bAn2%IRXvRR$0v08G1X?=8>c&XLemGXzh&{pI|q%byV`@Ni&C9-QR)LH4znsm*L5J8NdqxLZH6r?UaOYn zKp{k)`$|h8H|*BI7XYDRkTfI)hZ71V%Ix=&Ax$h+epe`nPwJw*^3nftK?6RVLQtQ) z4q5s5B$KtiY*{_N2eOo(wXR%MZpkI-{uYL}rmrcfUT&$gKo&n;34OGBL1*%vD@QA3f9xt^Ib6mC^gI!brN%@y7dSN0>e&)Fs=eeO5(vi=k>fNT zoc2)TfztnTU0UXgdS)Yx8T{1!T~^1-?i+^sBa)JDy`fRj!6A-?@>MEaY{OUT1q4rw zrx4W~;Sj@{;_m`yAC*d~rZ;OAW(7vP^nl0ktlDbkr6m>&FEhwL=~u6M<_x8j(X)0t zywVAB`+zHk0`3z-BTzr=^fh;m^gXca>n?}=-?n}SekZGQ5Z`$;PEQ{d6r=M<0E3ZVA4YjA@!|+pt#ZFTUZnQTJ_*YIp)U^MqLb?7Z1Xs0P~tb4ywf zwGfh8IDbxF0ffI$HoTVO13zTuc&!GD2!YAxmgA-~3Zu~WQRnDua+PJJeCP-jovfIuSfzj^4TvpQjOvm zbOzKzhmPs6m;r0#ZK7t@AM)`V;yRo|duT``qQ92KjT;o^P0=B;O9VNK2p@YB8w!ee zvdzutTo@3y665$AZ#oiT*8NRG>~6BRD_Qxny_amY2r;($8-0sNO76Cods8m>HmejIzS^_PjHQ|sQZ1IlrRt@-- zI%SD{dStH9QbIQ2rBGb6p(!<6kttQG)WK)+3Ys%BF_tvtoBNU>Rb!2xjbKkJve4?; zhWf;dMT88?@2ffr4uya!rNq)ID$*Djo+li`~|$(21K>Vob{TIbY%y8<;52fudHI9BGwT zRXMxCbjn=BgC5rQY|fPjUPj$Xv?{3LBU)c&4OFrWM>85 z3JUl$Ur|WvM$c-rif@~&Lt+}jeVd?V3f)M+{tASZD|`s@i?dfkfAX%AS5ld~aM=Qm zyp7AKJF%nFUXNDuAvpoE&)uqu^_#U(Al%*t-|hq9JJ&<#T}+arX-zC{Lh&y{r2+Bd zlt8WWQLW7zUG>PyyUjI_Dks~6HydcufZ`g{R@+D4@SZt@)6vwq zf#zJnkm@=6|IG?~+`s;~{o6}?ANPBjKki=#>xF%$4dL7Ige~a&xPK2V-rsNexc{H9 zt^SYuPlrv%`|+?A{4K^oK6{S+xc@EWxn~PtFzE>~*4TuYn2`w?*2ILE^o)cAYkWdX z{OE)d>!5^~;`D?#Yg|H1?5Kn()}(|O&xnK+YeGUy@|c93R&fI3$0Ght#2?T2<1!MG z7(a1zf|v0(rzgZSe%z>p*^FN>A|Z|OhmJ{jK;mysLLrjZz@}THl0(*rq=WH}&lo1- zBJz~oR(cYo$K=hh9=NZ_ zLouA31^2CZB7x*HV3))FKH_63Hn|#hlr=i}b;QSgp~;ZFk`IOdqllk|cQEhd>2TkO zC&QltTL$-Ah|lyk!cKzw5^Ge_TD`Cp6tr{NvS)Z{tve+c;x!FvPjRJgChGZywF*d=iP8S#O@xPOKx@p%^P3b;Q)d^BS6I@mE*F{&~$X)fNk!X6I)Cy@Veykjjt z`4G5o!IStt4R$Hqe@FZjyl;Y?4EN>8AG3mFd;unTG2E{p|A~0-fW^3!au1%vV9$YF z4fhw8YX76)&OrT7*6n{B+_T~TAkt@fahN}O3f$M=83Vf$wgm1!!Jp;X06QM;^L6`U z=X~;fxPPPD-w!vwLy&SCo-FT~uoZBBfcR|B8racRdU9-xYJXgsl6)BaAJ^^ggF6%M zU3d~-r^1%Q{WrvC``5u91ovgS{ZD{<5!^57_HTz9%s%BVJV{UAhFt~sXNb@CC(VpR z{eP+3KLj`0A?0D+{>14txPO2r!=DUW3iq3c&-Sl{1)ftb((Qjd+za4-LAO6nDX(du zoAQ0#{=IM)!Tp+Ue_U>z452&aK0HZJ-+`@!`%B&agZ2LhkUragGpq;Uug24Y?Sn0b z`;YKv`>%%`2lsip{kOwC5AJ7m`?tcK1@}+zWP6xVb6wL3HPUn&-NUw|Nlz2 ze*?lyMfmISjDX79TS+{>X z+_`Yyjb|F{w_#Vo{W;>Z{Riv+kLdPqM3`v^e*>Nje==+-+tyR%>zCH+RxG*!jYn;V@_AdGX+dXqP(DmCd;a{xa_1Dxp6glV4Q}z2;81zc zBT*uLxa)zR+1O9~6*y|1+ZMoK^JSP>;nQ9GE{i+S4j<+OO*r5L1p(A1`f51NdMsII zklC9J<-FJuWvznaNRaat3H^Nmy$WFhaN+`e20yN4_NlomK~%)TqGzBbEl?5Z$pQ_r zeJr#-@B|Bq5-o07n_>H4cf*1JtiFFI0mjuPIy!oklmR_O$^i~0WdY}t@{GchWx|Ld z<;ud7Wy6Ri<-=$wW$eVW5B4h9-LQLL_c1a0gM`T`DXFPLh75&CgBb=h941|x3~fee zGg6yTQD$_M853p3MwxL3FyjwkCLF*_+`pM5>lyJ035hUCFv;4aXpzU$`~PCg2DDC{KISlAJ;99Jg5Cc=(^9R@oYHU>5WHU)M(EdNHsrokQr8wWcQb_nc5 z*d*Aou*M8U&S%4}gna^b7VIssZLoibodkP1>_*sEU>CyP1KR`p1#B$rNw7;`AB3F> zdkt&@?4Mvqz@86V1^XM=Ik30E24O#dO@%!Rb_ML?usN{1V2_3U8|(zw%V3XzeF?S@ z_Ab~Ru%E#u!kz}Z6!u}*LtuXZ+YI|A>=@XKVAsLE0DCy>9k5$rKZYF!dk*Ys*r#Cg zV1ESL0sAiOWZ3V+Zi0Ocb}{UIuqVQP2^#~u6Sf5Q0oW<9SHpT?{|K7_dmijju+PHI zhW!cbaj<(~Q((`8t$=+DHXHUPSU>DvVaLN>3cCUJ_ptL}e*xPK`zb6b=Tz8o*k8eB z!d?&SgM9;bH0*a_Yha&;Jq-4C*e=+Az^1`|8+H}!ld!q4KZI?EeFyd+*ehV`U|)q@ z1bZ*+39$cy9f=x@j7hQnKj!WOJZ>^wAO4#LhEPN|OB3CcfFKk@C<uoS z7X4WCU(tU>x3Ah3M?VAo4D?~>!_c2ae-?d1^bOH(M!y+-3i=fEPtiX`Uj=;?^h?n% zMIVno9{mmUH_*35-xmFT^!w3gq0d793H>MZWzm;KKOg;k^wH>}(O*P=5q)#?&C%~d zzYBdj`gHVf(7!=n3wrY2~~?~MAf63QN2-vQR|^5p;knVLv4jR64eV^I0ZEb^(1Ot z)b*$XQ6Hi3?2nh^ODwizpT519>a}#wWqSNqua>LNTK{{!`nt=$*7@H!+1FCl*HhJP zS6|oJ*LL=qxBB|ZzRt7zt-j8(ulejx#Fl-{Wefk>sg!*!Xbb=PsubG)=v2Kt)ow4- z!euYp!euYx!d1Pz)&8$LO&`VIVIRZaWYO^fc=Mu1SOI!Fs#{f$JVJT@m^&|de(t;w z<)aKL|J&SoDJn)~f1f+A4OO6WWOe8@s3uf|yz@D%iz-mHsJvs*YK8x-LS!YBhjLKe z&tiY5GO7vXqH0j_)3{uy=qYqt&&-|I0e3!uWvBwqp2W6LHK;ONXP2RT`c_*UV+7z{c&R3TWhIc~Mqqam%K-p|h)T>yxgubg?hVxC-gT%M zsKKb!F>c{{@vXV@PJ8#iE<5HhRCVlfIKMOMqc`#ML$8*TV}I{2s2Jy4Q4LyNuRaF- zU+*Jx=gm7&^L+3R>qSrh*YkfCy)^$n)Y`^=NBM@vY`lr-x7ot)zVX8T`Inm`$M>24 z7x{5`74v_6ni*m);3OQoU!8Si-*L9HjwUK!Sf+hW8Nhp0IYoaWgP;8IvY)9C>y50n;ZPUEPg6 z|7ZKDUc^P#A3kc&fg^?wo-kze&NR!;mo(M(;Uf%+L{|$8%33Mvomb z*v`)!HKg*zZIz|f^)YfRzRYd@+m4mFAJxB0*eg&SXm_&5*hR-JG{0z(jgA~Lu3_}x zMaSwr+J!f1C)!lsdbH;k&Km5Tt!mhW32BR@rO{&+q&On^Us5~cw7PC(p69|_-hGcD zWA?&rHfH#!Ve>~}vepsy>oV;e`bG9Mbj-kEBZrJyu(yMbm^h^}1Ili5#Lx*t8cVoY zhYU6&@Yy(+C5w-F!QZB;^RO1#mVP?pM(;Lc!41A(9n4kGaa{{vT>RX|VgD0G3>h^H zS8I`|VUJO}O&B|TZ~pMBKPjw%AJ#$_8IKeD?sN61+C{c899thVYT$^4?nL&c88puR ziOYV>Pvx_9@YRp}5J9}>Z093XHc=Y52kux#^Y1V@C!C0hTg-65MvWdn%Gl3!)Tj4x z+Qak%E1zpH$qXJcVhHZFr9H+O-8IeVlKo!6v1Z(ufrEx%X=yJra<@UFN0^bgLmPa? zeQD_MQG+XIFsXP@gV|%0{n|n^W=Q4!FmktnxPR|CeB559^4(PUzCwd<{~R{NjO;gd z$iOjJVbthx!-wvL_3(X$V+V~HzKgv8b_7p)%vT?9mFI+idsJem#x48=@SleL%ecyu z!hb(*!4t*5js2I)SA9bGw{e_HXa8o2zhz>|M&+kay-QZUpjX#-x+Z4wn(za|FhgPT zv;pq?BdG0k4m+g~t5p8bsR?S>@Im&TUcC^Qj5z=47?VV&+T#OsL(YGcEplJSaD2mT z^(no2*RNc#>SK4&@s(rUD<6}thlyEeLK5y~^RHm_Gd}TnwzE6`=cnj@KJ-71#GJ>< zEPp$%$NsSxGw(53YW^hd1z}}6&LZi|Y4+EcP7CJ8RA#N{GX?+c>rxj!{_F_s$bOG% z<+(@S^sO&gwNv=GVI5CVIp}bajaFv)VLsH%Y1OSPG)KqYij}KlDwDwNm8%@@v*=uW zyN3mz7&P&~%2ZHJYUT0JnCMwK+Vnq;t9*7q<;pHJ4Ew7buA;jUR<|FqWAA77!}Y3j zlCV8HW$Ax%!UTIez0e-^f_omG@Nva>aJQZ1waBL};_1v@rhb)g6JG+;rFOKFLGiyO z&5}#hth29~cH{y0ue;9rGuAQtExFLmRk;?pj5y@6dgR&s2f$=}y)Hi92fJN=h8d}E zf!J`r4RI;(u&cc1P<lc= zgvzC|cTGD}+O5NG?Y9-<^8#_K$jrl_NgLtztX{IiXX5Km>>DAt=N^IYI{EiYiNOnv zw~u;z_gHkjKV9u#uAiN1RGDPBRnC^%pdMfh`aW}EIFpt1kbl&0o`L~>lh)>VL^gSH5#=~xK za4&8WyxFtROvU*l?8L44?*>(l(wR~D_Q}dDvC7*`b_y3i9RxeAd`mU1-~42T{S1K0 zG*GN}FvcBxBwoefLnrYWta#$Vtjo&x&R3sWDvvV#9_ANiEEs|x+d|vGfh0}1E%7NB zct)8t5pRRx>nw4Qx+#q`14kNs7xa+^^BwVVml%VYj0T^LG}C_KF%H>9L`h9DneqwxbP|FN6J%b{IuWS8J2Ha3hiqxQB{ zIfEs*j6=-WnbUA%;h~M&%Jy+HC(o#y89#XvJ`ah@@EtikHxyqgXGe{-Kds8ST_;YP zY2S1lI{APjDrfM{u=)qp9I?9^8fW| zEyQ>?9)E*3_?w@>-#QKchHT8MsP9qB;g3rmY80v;rdl6)G;Wmx@DH{_?EFOB-4DYA zNR$bRKCW3Qe}c~v-<7Fkjt_#~+a4qct!n{`Y&>4tPWnLY%4f4o$BSXTpq_XD{;7$V)R=gTYlizF9*6ey zXP2t-%#6YKYPZU`%JV+{2EZ4BlPkYa7rqviUtSow;4nBCxlan&om z@YeoQ&Ku>wy+V~s`~Uu*|Lecs{lD)2e|vo8a3Or~GG0yEKi8Z2$Ar4$#ta#PKMLR% zUFCDz@kpvX2k9pMZ^yZH3q54<*D-#)yM651musfG>!*1&pZ$3qhul`GZqK)&{;PHV zEVJwKB}CABB&- zS6)tP$9RIqYZ<$F`=^>&m6vun!WNVG?S}(b4tE_i1_^#P)qgR?-~2Q$`x?Ka3idK= z&*K$gKRhG#<0qx-uoN?N2>vE9!TyoQtUm+)WWfI`|E`*T5H2ph`eDWrShD2&3#rHR z@WFVC2hY>k?Sc*Pg4=(TXyY4JKE8BAv!RRsV}q5eVR$G?^)>Th|Z~Ci>^qpA7$x+yAq%x=58~e;X|Lw4e!i7?Pu>Vxbs#1ojgA~dZ7eQ z>9{*KRenv{U;KLFUikOGg7p^uEinHuy2=OR=*0++IKf|Tl{j z{I9h$H*)&$`>&mq(Sa{NUkV#{TOcFMKKw{>me8{((gcj!v3? z#L|LA_-W5SF3Ip8LHsO>`G+V~w`@P-6ZcHs95_A&xAMaOl*5ryJb(uWXCA|&Gx5N} z$_rg+9=$ZY^3SRTFViab-T4Pv88Z&AaQGFJ_DDRu648OCIAGDf__2qdR&KCGHod*e zCo(RajPDx3&j0i2uioObY_jRZWxlrk!QC;L8mCpCI?TSkYtH}S5IY^tY<=T_pV@x> zC6lhUean`&?X)^`L;E|G7Zz)N_F8V;^5)C-WwzO5#C`VdVDrdvcURu5S-fBSr`8v& z@mSgRNzVP4xNFRJZgPn24TnEqUy_^m20nVK?Z?0R7A963^To&S9%lRQb6)+y_GeFf zAaY-Os!^b+H3&KXAuof3f|?rR^kO zV>;Yv_MZl3f9GIK2sh^Afx&CGA947U>ui7N<6f9ZZp^S(dt<_`F~6U-^vkv%I%mln zZU3ch&epb1ZN107tTeAb_t4w6`#(Q?yX_xM?cCD#nftz9`IGI7OTYe(^T7FDBa?bH;JgH@AJc5lxM@-?qlY$8F!S-$6JS!I<*E zcaE}svBTfSzkZB)*nPRx_Kls_zOntx)9yap_O<5RXW#BOH-7xsHMaMEwY|&s>z-S@ z@R0!|G`eaH)i}(%l>HlGjAr9KbMw1 zyMKA>&)Xk8+xFvH9{A1n_t$v$0NaQ6dut`zzd!Dkb8MeH;?-YmZ=84!CW0ID!tQf0 zVIO}dHxFNL`-k2`_MeAl;EnI^YWo|PbYem|j*ouor5kMj^@rDAvHg(G4jyFtZ*NZ9 z%J!ixQ|_=mYY*PCeMZ0DgKht0jb8n2pD<#{TWx>txTW8d;?k@G5?d#8J!sKvcW}i0QwS9?K4|>4%Yd)U%g6+%v{NDbyw?6k~<#p9MtyyAy zZ`&Ks+P=z;v-h(7q^0lO%=Q8MK61b9cT9aSwcS0X{VUt=oBi13wlDSJeZ6eI{N=lk zw0*l_uYGR&U9(=k%J!8uc)Pdlr>y+W4BMCQd*Da5pE_XD#kTKs$YD#{-nRE4$JpNY z#brLW{i=C5H~^;&@2pG_*FIu*+{pIWJq;_MPzU#53?SDM6*ul2%H~xU1 zY=3^rtBD}_7g68=~~;LdZM%5_A%eRKic+hr#$qM?Ni1-e3R|( zE;eUp+jraMo(9|B+GOcY+efUnvdHo?XZC~=D!+P3&%VIdF45yv9S>_AdPn)v%5w@=|zA_ESoV@E} zmsqcOO#6qn-?_=%$J$=M+I>see#Ln&UugT%kG}Sa?e~B4&T+P{{r=m1ZGZLUS5CKm zmk(e4*7ok%?>5;!?Uc9Hvi%<`KYEhw`)u&QT-!gGl}xvN*0B3)ZU5)q_Fy7>kIf;= z&a?e*0~R~T_I>;ISkCr&S5H3Q_Ji*{pxgFW<{diG_8~7$UD@{L50{K>|N7;n->`k$ zDZNM8{>1EF+u1&GgDE%L{?p1qX8Xut2M@RX?OD@yvVGS>Ub@rvclLh$P1_IZ`@U~` zF`#o>+sEGd@GZ7Kef2}{*?!`S_YAZBvw3qo+gJbYkwxl>dX1jOM?6J1rbp5^S z+1_WH>_OWvTI`K~*uK&D_r}@&*pxTdwSBW=4w`Ly`>qq8vc2bOP5aq?@g~zZwtd@2 z``&B&wdXDMr0uJ{-)C>z&;6!nKiiGd!}zEOm7?q)!+cbPO6?!UmWNRhDn*&Ups#?w zB9@~foR82`lvxSOP!TFcnU!Hwgi2AEXlQ&?gi2AS7Dh#=6lGS0QK{|NPh|In@>j!o zREjdI!>9$N3yqJ8u+0cPMPb4vp7^jFg~^}Bx7PvZQ|q;1 zRD?=VW*rz6p;DAt7e+;>6lKQdB zwH213B2;QC>uDk%9p%4-r=5Z5wl3~zVpN3lDJs|&zj{vYW1-Jp;0U+!sATbE#aL$NJeuV7o3^)?aCr?%i=n_k9U3hVxkalLvQ{}1$G z_Hy?!KDv*~8+?lGuYmpHd}=TMc35_1FO&Dj7@Ut#=}o;%iXLx`?Qet2xjoiJxijFc z@GEr}tb@zq_rN+hAEC_V*stw_Fm7us{{@#9<^PI~@_$1|`M7L8#zd$TWd>v0s0fwX z^*-utQoC$*T<_bkFWe43Dzb&^kfQPxaa%QDIVwV>C^H;Jxqrp&f}WxxocHZ9X}cnO z73a|-RB8*i4<TQY>OLw$r6^1eHaYeYY=qky=Oa|S zGHwTSQ^MFwu}}2a-v0HyO$peVIuG}^R$MMr(21Y9 zy^L7qzuwchm*Mfg7%n$v5l4q(JuLIzK#uY|(NX@J=qUd!bd>)#x*c!Vy&ca3=qc7U zE*>{W;Qo#KjDI7y*xlcZV^?-3sT? z&5_s_Dng~W{;BQT^fAG97(WyF4pYdzY3Qpz;ZmFr7#W(F#g%N zEl|-pxE!#1Y;WV93*&r>itfN;sTt#XB1ez5$MWs5{?SwlLltk7cL`m7>fEFe*Z&C>%IoQtZb^k5GPZ>;v5%fas$l zREi4D!?sSsGE{^L2J|xScDOFr;4;AGWMrram0}wamix!yHiXS7SiU&!Pqw2{lsOgS zQ4uOdnbTmDIUnnyr>H2wZPKTgiLuO_j(zsT?T;RzQd^hf{&5D@dl&n%9ml~(=qbvy zz^Dk7qRg2vD#h5yc9b~_%ihD~$39YYACBy@_puBe2e05Y1omk=Dn*%dkfS10iZbWI zs0fv!%y}>>LZv7i0AhSpgi2ASjE?Q+_V&SfKgYgM{s*{RHbeJg+|N;F2V5>JGZ$bS zDnh09{9?F0uEn?yG3G)nufuKIhGlr(k6^!y_3Ritw#_7Xumz8XST=B z1>?-7xcx3dj*3w3Oe{y9;=H*S%Tehi$S#Hdiu2YuAK45xHballQ)^_tE!ec8qf*;1 z!x(g9J1Rw)%ds34p;BCr9G5w|pqFtk#AQeMAN4fub$D*N2-o9cWH_JNu~;58|ljDayn!Dng|wb1jUDP$|k>2csg}4}!19a-4S$#LsMdcmS5$!t2J|K3C#= ziZVN387e}hD6=Dsicl%a>;$7CREolZMJ9a#{Y7lM8_Q8S%KsVH3uS)6;}Dgi++UHS za+LoYa+LWUIVwfDe;`NYD1RPuls!@1aef0a+gGo%29q_QD#}> zs1y}B7=y}D{&L7sW_jeO6y>gfF{m8nuZSFFRzi+SQSQpfQ8~(A1v$#pB1c85Vhp;A zo}>J~AV-9A!2}j!IGPCdg4a%HI?@%Jf5yN>T1+ z$Wb}U-yAv0c*s#H%H0AvDo6QSB1f72$WbZE-3mD>NBLVLN11Jqqf(T+Epk+j^6QbK z%y!68Dazd*IVwl_1CXQ44#-g{%H0t;Do6P{AxD{=k)u+S>mx_yD1RVwl-UJ2Dn+@2 zkfU;xKNva63_*@cQSMOWs2t@FLyj^H$WbZE9gZB8qx@Zwqs(r|Q7OtDfgF{i{E^5} zW)yN%igHIIN98ELgdAmdM~+HS?il2#9OaKijxytrqf(T+2Xa)7^7llJGUJh>Qk2_> z9F?Q|y^y2K-pElY%H0QjI(mq4r~v14bpLP|S&VLuz;aZI%CXGf7vpCjN98F0NQ^_d zM`0Pt%*1$9ippVs7ILg(_Cv>c(~KOIqTHjg4$40U%aEsb49@3R=I)QN$0A1$&~tQu z0&-LenhRE~1*fKf3jN4a;xs2G)_+`Dl8 zZk)dl=kG^`a%ZEXVpNWD?}csIv8Wv5-FskEjLL0Co}=73SdNNOIm*R$15|7a+s^Iw z+p!GgVmkpU#`)a(0T>mda+LcZjEYe?%6$kOk$6-{A%2DnUFeB=DDx6>jE^Sa{ukl? zh901s*D($ip;8nMGRD8RU{s1SoiHjwr6}_zjEYbx%De@mB9z;O?cIuPpM?7`&c{#S zK0O)tbL=O!9b<41HU7Pd<>(PAwSEWNKt-q&72Mntw=2fm-iF5q&PV9EEu8mn!S+!8 z6Ua|Oh6=FF)Nc1=Ec*;O%AJDC^DeG8mig!r%AA7nSRSCKs2u10CX785%TWO?e`?pk zGIKEMy&ia-j?0AeIr97mj6V(AN0}!v9+jfZ>F5~a9)j(la+H54#-Yqqj6?1|g^u$P zwwK!d;JkYnx?LB`+%u4&a@(;yNBJ!na~rmUZq9`J;`Jz;qatk2za87O%co%*=ozIMY#_m zN98Er#r0nsw+VWR?yrN|5Oq1cG5!s{A1=3b9nRZj>*4&*xZN(pYjsp^|1IBk>U4!MwbM$xu#&3>_G42nHxfa<581G>$_8VV-+jt@_ z!#pfU7F>t*x4`AU9%Hw}a$H{@*Du{4%lgAuH%1oSh|6HGY#sbNWK--5nfo1XOM5-f z?1SHZ7>niUR_Oh(t!DHaV4RP(z&cph-wZ~%N8_?=j{Tsb9{AZ~obMq+`CFi){4KHH zZ}D>~w2Z??tWYzYkWSE&gEG9ad*)A z>alvR?(V2uJ=T8B0ouNn=j!fG8m}I!yQ8#RJyy@v-OwL`ZN3t(>%8~3<-VMh4xN~GBR-QO{HHl^FXr^~YY z1D(jta}zab>myevfTU2S0PXzYSgU zi}o)^a=0yX=U3)wJ>4ez1GK&0l*^rRF4zCg+}lCx%g)Yp;~&g@pUz}&7douW2Ep^K z+$DQMnb-E{QQ1H$x5-5V^PnelXA~XvqQjE%-gG{O_WRJ@9(3(uwAq(V7N`9QbX=o+ zGF`uGxZl*Uh|YnG-9xh%)WFmHF5JIB)Aa&#oO$*EksJo8KrsO*nr_ePk%Pn-c3SB;z?yOaQA>Fkq?O#UMucrKRI+NWi>0ou{nVief zRm#_3?p;mivWe+%O|36?%h7er?OYLi@~@}y2i%Ga+0GZSr{G5B&f0V=H_O4z%!759 zdu?==T*yu9GEZ({UdY9*bnAM|quXd_eQob{<#KX2oo}H0e%hH>d4;BKDMhL|5Jqu|L0$>E<1o zho907JJIoHbluLh|2f?*N3!QLcfMer$icUC;~?hlk907YF3qL8W&d|N8^*kl8yhtK z59M+^j}C`356qy-^{m;I&U(|0yU}?c+Rjt4r*Lt)GFJtTYv^Dk^U@M@mmDrhH;-Z- z^`-4R7JG7*rW3g=*Oi#(a;xkw!|^q{GcPYox5?phbi)|t#R_!oSdCv%<7KlF?T%ya z{e_PAp#61}kEi2x=?*zupKfW?_BWtw_M%H0DwhknW^d+M9rIXrH`4n1FgN|=ed%-y z+TBmv?@xEh{?>HI{>=03XeXeZ9q3#R8|cbB7W_O)!|Bq2+TSR;c@pi9rVH8KgLV#L z9*(Cwt8Uc#QdFg7pG9LsR@UGGNCom6Vx~uAI>E;uaUq{zObSB%mBKG9pz}!8FF5j%}$)=4C zPG+9VHK%C(+04DuXzyOSLr&(DSw!*Kbwvop*v;&QM&mYjhF3Qk;>^Y=624AJtcC@d9;%%mqWRbb2&Vp zEj8nYUcW-26h5GtcDaHahLayyg~d zzc(GpNgvw2uW3)-VzhmK)1FeZtIdr?6$_)wgWI5&?a=1M0-_6`#LF>zj?A^mWT#oRYb)Ai}bhqb*ry6zD=+(_f)M6P?3x!HtyhwRDqk1@~WcG=xj+fSK$ za*G_w-Ez^7Au6zC%v7p_`v&?rlpKaC0MwEM0nqE{)T8IhUJWRlbLEIo^|QevP>quUrn~#@CtWaweyHbA0C;%(H#yrcT=5 zSKE_={b>7szCFcqx9soFJba6}GePUisT{n`+&z%FeLvrxJUNyl*?E_FGKu5c% zV;&#GJdvF#blv;RBe_*h4`tq*YyTk~eL$DwPPr^Me8@bL+hzZ7uJ3)M{mHSM%C#Re zFXTur9jWy{VeTA7=W;%a4*to!+^k#%XSGGwF6Ylk2}>o}a_Kv7pVl z+Mev4Pq%){JeF&}qn!(wXR?0@UHgObztU~8+e!yNGWRZ{yX8!7nXCLt=8Zqmxtz=C zRm@wunHO@G>|et?`dRD8wEGKfuBDr+zMgLQm3efd{F}Bfr*d>Nb35ITaIp_ z%YQI;Z`1bX(fPe}Ymc6l_0u_YT~9i?k8YPs?R40SdHfJ<=gQhsA$QB>QRYb>=D}mM zzZjj!c1~^Olqz4GF3IgxKc(%}Fpp(-3A%WOd6(=xO9x9bPvk<5JD8XIYI}d9OH0wt z^K>pp|DcnlnWrz%jmyx{i*%RlXLNa4ZSQ5e>G*9rTtVA= zkG6Aw?Wz1eUC5=JZeEGG{{daIG9AfwuCP5Na+jRTjjJ$sKIHnT>~_(1E^+1b8J)tA!wsVf{$^VggryTu6M{6=K(QP=cgoRnbj$k8-R0?;4d{~GB$wq(j#uFLa6^tyR-)~EXM2iQ zrrYIW6*}06d0tBwva>4PurYH_Zj&>)ZWHF_FC5=0`>WCQn=%jNvK+0>-08=>EH}x? z8q9OqU6XFyjN@ZDlZ&;KZ?65VO&7Aa9&P7nS56zzcAmC9#hcQdThgV?>5l$%Cf9F8 z`&%)u-ekZRy5snU~~tIjCn|s%M_a9daT2+cEdIn3{PUJ%Nc4h8O*7jxRAg#ZfwlC*$Fok*J2(8~lcgnF`8p+%_gt;?{ z4iBYc**%=@8qK^cmr8UZx69=j93Sq^+{~nF$H+&~?XowEZW_znZKmy9eS3S}-^{#iB6FvWb`PKEVs$I?95;uJkRyps(y)1k7Vw=OgGG= zL%CfxuQD$krCd&B_jRp5i+L({$jKYb8=INuophHRzDYM7&D^|2+v8U3sq{7-9z&Pq zT+ZdvvCM;aI6jk8x#2ji{~q&hImqeubj z2fxwXvik>JK9A!g*_=+S&n-$@0QEG=;%U@cX}(A zbGi8<=BfQ&ZhN|z&X=T9IbNS`yo`CYAzgF1w!bl5$fZr`_zG=bcCMtoe#~3sd~>?~ zD(1OIr*gc7@~fF={poJGybYaQ!#vrJ?ucoB03BXSM?2DW*U@GtI*|*xbiKB>GxJOi ze7f-l=CPc~x!iCgb7wHe*W5%0awO-&n3ry5?lsUIaB=e%0 zkD|-Ba(uQ2o!ur+q8sm|8DxE}!Ptd{1wDY9K%gu6j3UhmGmp!?s(yemo zG`jw2=CPc}&gsm(XOy2ocgckuJj=Y)!n{*Xar(DR5uQ89WR9^Mf zbn!a#M6Q2>F634@yoTdzI+^EkBo}ff$1%q@y~*+ZwRE>!k{jM)9?NZVA{TP`dafV6 z&GD(6%l-|_8{SbaCvtcrbN5~5-c58_E@bl_^W0I{ip&LJDZf4V& zoXHKJFpuwLp331Iy8fTc{rl)dcJ8O^K4qTEZE_)Z%ch;Clm=t1UPa#{AiU>?h%oXQ=tc}SQ4OYKjN=$$- zx5}|x$eG;mEytTDxV<*nlg)R`!zY<{%VoLYd*+GUDi=?4yz`^B{|p_-j-1H8Tr*eu ztB$YwIj-N(&AcqP%8A@1=YQk)&YwBnd7k!up?$eUF3Fi3%I>cmAIVK}S#FnOx#l;H zPvk~9mD}XJI{tT#FXTY>{-Nvp2lF(e%cfW5@n3p{E_%@3TeQj%&pebP+5L!lx17u23LGDNtjjOw za^P&b*Mza`+8%vj%fh(9LorcgfDT z%!4&`dE`zxmFw4H9(>2~iCp@gu5+0uax6PPFt1%(+n39-_ak#>9j!07$lhG$UDaGJ zudD6-#M~Y;Z%?){bnE)eBe`J%I+qLC|Apg|4VlMsSVx;*wSC!>8#ZE|$o5!& zdn*0L@%0ddfH=K@SXIHwAJLS@99ADavc_Men-s;T55zKSBb|f9F!90~qYij%`ZBK3) zO*?Bbk4tn}uH9X^%e*X?<(e_fgSDBr$hmCBGEdiG9?AZ?bhqrSM>mh-_)PAS3%Owr z=I#a@-zDdAE5-LMZ`-kh%6mo{6_opP`xUEYs*(qHTEPZwL!H4|uW8#A`eMsO=p>JBMp~Q|Ur39Y&XrVD3$$ z>t@igoXGxk<_$+OFNJis>>NRN%+&T~&`n3tg=}Wg;gQUn<@C>EtvzmDAH{{{-gY8CqYC%XDL;?O!aPB)8J_C(BpTEvL}I z^>o{*bopkwd>WnILVKsvrCT*#&Sm!u=KgKWTjb&{y1j*Yk!X8o(!m_M_AENOU*qNc zX}a|s=A~!onsc>1Ig*2CnHRF@pu_VxzASgi?sLqW&S&oZP1`SP`x$L6q|-OGy^Cn` z7M;nFT)J5K+sb9{JvzNa+m{>us_{AVPPr_XE@hs4pzX=dhjc?L^H6S=GugY0x%Uyr z+t1Omr$ny3oc2FvUY1k2<_hNSC(N7VSk7hhPhFlXIX;rx_(+cAPT6!Z zFI~;?shr8B&zZMf!`%6T_G9@=y0hx9>6UAmC*RPe>uCR5+I~KlJ!NtvmwsU0aD&GG zM7uZAkzAH@+1#Y@-5ejux$NA`JouS;S$2P+>)M!?<+7aq%G|j{`~RJ8m)$?K{;k@7 zkA}+i>XN-)bon;sULU&tb~;#$?v|a!>6SaRJ%`Tkq~jIn%IBHeJ=M}33G-C8pSNsJ z`Krt_*Z^I$e}cMYvy^_p7$Ugc}iHFIdsrQ51rn{K#|c_g>X&ic%= z`?dZCbkI&0awZ2GGWQ=~o^DK=2Wh7toy)o0^bqr4Gv=LgE;l^PJldRjDmz=yjgK%d zDp qsp?qIt9S?2K&I+M#o>BbJ`$uPQ0 zP8;av=a^^1Y3FaWzZ=~qha+hJd2MeboyqAay6NxCqtSFOm*u*DFgGRUu^h^^FEG#K zvRvAor_V;Ao zAv@z~|5fJYCOUmx+dEkK8+34p*01_7y0w#eIF0t+q>GR)sKcw@^=x*7)oGyLDJh_7IlEW+M#*dko{z3a+(B&8D+ArxWqcb^tnQs1ydHf3P zd`*Y1(uo}BbVtG5{ebqr)%Iok`J|Q8C(P|TZ48NXI`vDcgSW7x>!Q% z_ow3}>3nNC=u4NjqwANVo$cvF&g8nKHGTl|R@v-8*DS+4kelUH?vni-IlggOj*sL- zF73qJb(p(5YkzX?)3wWKe*@_j+1Z8emdkR}@)|#gc`oO2;|k3E!OYv`RIXc*c{qf5 zt6a!6D>09UGH;fnVRRvT4Rq7W93RPvOz& zI9=L+HZ$l>*_ZtdnU`lWckAdxZk97SlMC6~NZUV(>$k{`oXehUzn8|IN^+~5$~BuX zFOK2%aydDcZrqf4a2%b<&hfP0k9jI5vUdXWy3MqG*?z9GJw+!nuic!EBf2b?PNHi( zZU1CClA}}TZn=Ca9d5z#;Tg2IC7sK$oU|zK&)hkS?v%50>GrLd$LG=YThoP{$o~1v z>$YKDmSZ`WYq!<*${Zid(FIz+UhB&(a(W^2+U=NUauPi%Xfe z4PYL%(%ueq=~}vdM>@WNZrMq`k*?jD4sW8{WannO&S##;ZL)U@^Kc;Z@~w2Y?A%Vb z?4tY*x^@t4?xK^b6WSllJe5;9xLf%Ut$z=l%CYPZWgg9D-XSOV(v8Ek{W)}(9N$mJ z4a^g{X1K;bz&w?`2kH7mb$LL&ko}kMkn7c2~ZKLS$CAwua9m`#^`v&ux z-I)h+ASa#7%^2qCn{=xjzeU%LWuD0`a+EWV$1yK`Kzn=8?niW|T>ggc8qYlbp6+PW z_+GnKo+nEC(8W@8*S>UlRk~w;I$cYipxo8^0iCZ+7qYi59Zh7O$>sn$Sx>p_Za~)_ z$h=fXr*a~DlbFXFF;C?3#+ems%g(-ZLo@Sqg2o?BM+eXya(tl1AHzJKM0d*OAUZf!+dG)9JB~Kf z>6YWQzU-br$074JIXs;9PGlY&K_^wuP#!5iQn~ERq}`L4r*c^ik78bPGV{_bx$tmLXPD4Xy)B=a10%u%JJT@beC+7ql43!=W;G*$16Xbd2#}s%khcI&tM)#beHU% zOh+xugH!05GwDn&%igKV&tmSMMwexCy7IG`r*b4aXD~11vfOlz_9tg@)WY!%=Q1yy zNvE=V7F~ZH^FmJK^lavJ=QEGap<~&cN7t5_2Xa|XWpe@ZTyBz`^SOS9?8$W(a(qc{ zkwdvlF3Y8hI6jdRIg_1>nHO@i?3TIzPC1bMOE|tP$8sv0zcSC|KsFcX`pBMKcPYn* za*LeEg={Y5`i-p|Uy@TflHJRgC$jzCXnV@!TrT8>%b7bDarvGsq1+^w z3NQKZsGdvvM0NLXI_$98hc=s-@pUEY;{!Qkg9Lr_7<}K!l9Lky8DVv1b_utn3(m+@tF!dvg8z9AA=SIh1R1=4H8APUKw9fl@qz{Q|6gm zmJ7LCcJAZ$gDzb@xkC?v|a0xV@(DIX;j(7KewQ4| zjXgL%l{;kT368Jt$=sJ?Ih1R9F)z!ZoXDMWCi}g0`Q$d)eUkfg`e=W0BnNUKM{=+j z$H#IeyH9a@rNx=&aweOnnfo=&J-JOT$<7kYL%CTl%ekD$r6oB&liTG&cKb4Sp5gw> zvM+bbk=(Qt$0u?o=W_kh%+0ghUM#z^vkdc++$@*nT+ZauvK;SraC@m7%AUhKmRsda zHp?+D$J=tGgmrrh!BiUI&`;#L%l?yqSgB3a6{Ehp|WLK_VN&Ayq#{YB@fT+vHewR%M>a&9eEsZa>+T{l9R$FSp5| zT(cVUL~fD`Ig|Z=aQpSEb9`BDlT*274d#X1Bs(u~{SMiay)`+$B$wq-F63A)t;O-F z+%D&`>oPYla(^wdD;IKH&DZ95H{*DB9XgiFa_J@JW?kml%XBKouhZrAmlzAdHNAuvk{$qOvkeK30=Ff^3Un!O=#~6x{wpOX;bF$SIler(WS5Hma4y@ zYd2%={vdBo`*Z0`c7CE8J&o_CbJ>^cw_qN~W!e19@ikj&`@hg-x%4aT^k;51Y6RvkG0m1D(`ryj-k9dpj{NZAAM!%bU@4KJE9XO9Sa> zN4jeljX#ub8b)VRX}5tk)96%or_+tYnR|!R-LgM}Zrzo6a0cBzQa+OoM#*PueL0nb z(aO(NF6VMniFx@v=AClse7dwd^HN#49A7{;jbWZ$NEfnuF&&L%UR+Mc<7oFPI@p6w zx~1F6QXH(Cy=(Cz%t>Ddr(&`#!{v9na}8XPFDk ztt+6%?nnF#bB?(s4n6V!^giYcv)uvReh_*ubBftK0eXhHi#d`({5*4-xqT(4_Ym|U z<^*$W74+yM(CtoefjPzOJO;gOHS0eHcdY@(9tRhgQ_S%$=*pAOm2Pl~Il&xz3i`0e z&w+=&gZMe-=vq$i1?Yp!G3K^)(9>@~w>R+qZ-NJy<8OgmHnPr~X13pk9!@}yyaP@% z+e5tniO`e32HTrBz2AWQnC z%#q)L+fQPDm~+hbAE5V~3_bcG*y#aBhQa;J(LaKtr$Emz_cJ?x;{8vBo?`A}F8rDI zKMi{Nh=XuHyAYgXj$Q=LGpCsgMlh;7cF)P=Clbcv)&NGiNXL_Lb_91?OS-B1zIR$zbbBa07tegtH?Rw6S zIm;Y54SMSh&@;?~%+b@K$8Ut5W*%gYp8-936Z>-}c#zpX3*2@y^epoLvz>(Aatrhr zb02e_*-S$(Fn2L4XJh{ybNpOz->rzBJCD=94V=CJY~If4^>TdX#D%Qi!TOEhwmZR* zAA@tuapu;$py!!0%$dg#zvXV;e-NDM2gjK0d%#)dq{lBJzWIGl|7YNS=FCf+{=Lw1 z%t_|-%h2unpcj~v%<A&_hz7H znZpl(op+!QFe^jgwjV%GF=v?z%&iY|dha2A?h#He4~{;{`!i>m0D1@y?F;M_04xg){DzhZ9Z`0s)fM}u2_4K5rDHh%+- z9}ga2b~?bR_n>E)!+CIQ74%`|^lI?nZ#jN9IQ>4@UJGvj0GwI}4*!mMJvhs(B*3ZP zLsvF|V}Ae_m`9j%TcKw@gq}PJ93AHLPX_0h3(W0*gdXdGo@b7p0#5!3dj2$U&9 zS>TqxFrN!nJ_0Ad3(hg8E&wM!X8l5N>tDgCi@Hh)T@9~G=wqod+KZ9FBoZer+ z8RppE!C@PE?jPVmW@QB2RSI4C3Y;zjr@jWq%fSWZVD~th6&zoHGt5cmwo2$x4SIpu z(ZPLH&~wa@YH-ScKFA#Pfn#CTne)tf=0pwae#BR5!BG?3%Uoc#>!8O1&{NFu5^%bn z_qV~(25_zl9BTw8tHDFe*)X_k4D@sjxWF8%1@}16ojS161THZ5GN&!XkmT}PI4)hFjhB-VQy4?gl$(&(UCO}V)h2G1Y9|w+3gq|A@9%N2V z1h=<9kF|h@nC(g6_$26&$zXFbIK!M`&Q68iIt98j4Lrb{WR6UQUSLi$XQm^5%QV)R zGtBl3=+1QLdFFoROoaEJ!THYw_c14Cfg=&#pE=DOnGM~Z2|dA_WG*lln3Xw*ADe~v zHuC^;VlMRLZ0Nb&IsG}{_#WT_bAh>iH`e!rKFA#17o499JAY zne)u?CD6O(vEBw&_5i2$2lp}C2Y{VDS!eENRt|(7nGZe5Jiwee2zuLItRD+%@mm%`j~)t6GiRBdeW1q_1$GXC9@z>WUJ5Rp1&%Fa{cP5m?Q_7181(3Q zVEYiTeLgtFoM1MWLyvuzb>{qK;I6}<7gAvJaB%hta38aCCD=X!dWyN1Id&E6M?#N( z4?M&iy#d_c4&A;H+;$W=b~AW{IeQDZ_h{(p+reGOfOB_%3(U%0;GSbS{RhFxn>bmc8@&f^cjN;mY}U%|2OaC*uzxBoJ-7Mx*Dtpi5{^tScj6myn2$Lwr? zo-INA{scH`gTp6+?J7=h6LSMNy%}6+WPJ-bH6Glx73@p^4>4z%6DL8BPlRrs%;_CllLRN{gNK<5%<;3K$M=GsW6m+RodZ3#H|xyy0&x6X z=sD&*b7EiU+4DI4#o+ey!HNCAL(KLP*1ro~X=9zaz#PAT_df)BwijGrj$X+6a_9rh z>BGROi#Yxf;P#8bnWMlhmw=sPz(dSw=ESAYbH_rrF9XNoVC8b&{{(QBIl3C0NhriGHGxst_e*?YsUg-9F;9=&(Z^7C7 zpeNr4$LpA2lp|@eBic6pr@DznbQI2J&$sF zL2%0t!A>za&75KmKL%Y1K~FI!O2N?q=mq8hW~B_e^CRf-3b6TOa54;zJPuCRf`^$4 z_2Bdq&@+wTwkN^4G2jtq+X2U);`EvG%&{iuJx@cAjs-hePOll9V@`|%xBmpXGlk z0pR${;3)GTbDp{V73hTn5x>BkISAbID)j79aQHP&F9sfD&K(9$<)Ftpz?s*1|25$L zpMx`NncrajG_d&=IC46;hdIhT#GGV~y^Z+sGZ0^Shtp&3Wlo(1JwF6Je>OPzOK|QS zaQm;onRCJRyUgc-hnSV~!EL{W?py#K{0%tU3s&-AI|VNM799B=xb*{Y?nZF@ci`Af z;5@T(Gq~&b&dzs_R z1!ns$#P9hN;un~eKQrGAJ;faF2it#vuG|CeWll0HA3=A%&*?Kq?gK|YhMr;WXO7$t zz2&d0Gxsw`9)Ru?peLDA%qiv(X8R$;&wj%39|iaS4Xpf#`BQL$Is6$oH3EI$@8Im` z;I@B&qhEjrnG4Kq|K$Du1wG3g{Sw?d0zJn(z#RKG^vLI|GiR7%UqNsA0(zD?%^dj} zdiYaE2mpP${WZ zIqL)WD1O(koFA;H%qF;(InO-ou?0OP5Wm1&V9pdlPiWAy%sJ*<5PD39o@dT5r;DLS z4Coo=6mud3-S$CGGAEc5rM$nNb>mOgdS&3Ge;^}4?vGHrle zpr@D%%)`vF>70HU;z#Fz2gbbAl*FmswY zUd{QSYH9|cfip&INSs-FsGPv9juRqZl3^7GApaVZOy!YC%C|zSOZRsgYI;J zN0@Wp0S}Fb9$O2JP5|eb`}u%t?$EQ$z0ApLpewDsKXVUr>RRXpX8U{K_&mf=xxw*%xUJZ!Trqkq2RXl(9_Jr9v=ohwE=qMaByTJr^h_VoIL`1G66k$B-l9- zoMRqjj<-Ya+QjjX0*5zqeC7e>*wN72w?J2p0V`XbPpfOE`w=AKia$K%k$r*iro;4E{RIer@S{0Y$Q)4_?A;0$wQ6*ztd^enS^ zCOFm!y`MSH+;$eHw;K8|bAh=x3El339z7eJV;*Ksc0*5{13k~|oC{8W2YQw{xfa}h z9>-@MVveqZ-g7?h&#ZhG?5v00&zxj#y#RWFInNy1fcRa#(6h|;g`D0-=zYvd=GKd# z=b5w2(FEehFNU6G9%i;rgx-4z^aQhcDW}KW&m7%^_^p?5ddzudWi#h@IrJE_k^*O# zdztMmh#$EEdV)F2oMY~~5_)7S;un~c%zalu&oet$gJUNl{vdOPx&0dG%E{1`Yr%2m zUgjKgjvm~=J1W+=xK=dFBjr^i0HWy%l*7+Ck4Ib`_NO&8Rk55^j_$ND-b`=oVg0zdmr@l)nMm-PVXA<0CVD6aO?r-@$Z3$ zne*3i{0E^cH-dXJoc>MV=tJOa8tnXl=Eqz8#!rcJ2iCJpw(&>^#cx z?}FaX9AOUs5PIxx=!4ApesJP3-v9exX8@eP7d*@yyARy+Bj{;n^T*)mgB+jP&T#z4 zp(mJ?C%{?eUgpBXh~NGsbo){82y>P>^%V5{51~h%2B#ha4>BtQoL&}sfw{mO{W0|P zPoQTW2gjdbev0>h7My+>Ji@Fz1I|AOJ;B`dJUGuh!kl>)@zXDGde4DlKLy912N#&L zFMuMR53M;K<8h=Ou8Sd5}5v3iO_rp{HI2M_vIduYm`cb2*OxD)hq7 z!L6@><8OcmnPYE(`*NJ#+Z_LOaE5t^IW+`5{c}$L*Wkh%U?&eAd=nghAKd>IIQ4sQ z-`n8KAHnf=z>zCeE! z%=v$S2YwCR9s$RH15Pp*JpO{?zsKo+2~Ot0k$;23zXd0l)69jhpvT^ao>dNYpU1)< zfE@uIWX@>dzTZJtba2b>Ieq2<=9~e&{SVM%KJYMejyd@u=Vx+y!{9V?hS>=~kNy#Q z+yW0V=b7VwV!a4@fw{n({4?}K5W4*raDh3^oGOOi@)4&O0%w`?%(0JIFM*zCPM3mv z{|enH1KR~~nz@fTUk*L;38z;9&N3^N;Mm`wCz*$tl`81TPkH}paLZ@lJo5l^qy~EX z-=SxihnXX_(0l&DIr%ba13j)&g%73<7-=I8`Y?`!Bz3#X@;?sXBL1kN(&ncG$9 z&J^g10H>MzJe~%2}!9&bx<}Mw2b_R6Q07oO>KISa5<70g$^nT_nbHva3Ea(Hw zS>`qqx-tj)FmsYQ8DM=k=(YvUF!wV@=R$8Sf}Uj_WRC3)y*&s$$2`m&Z-w4d486c? zhQNt=(EFGR%q=C*qkBTnF(>DP<2Lj>^9ZxO7w1;;n zEa3bqpr@Jh%uW<~q7r(R*{lM`7eY@nJNtlJtDz^E2bnX>ZDHtri5^bE5y0USS!(_@Y%z=am*Ip&^8;KXL=t&_p&t>9ti{K??HDbQm*;P6y%{xq;X z4V*b0oMO%~k1)rR(9Ic$pF9^l!W=mtoQ^=xF}KbHN52bwfH{2uI5rEqlL8OT2FI=d zr{;h&SAnCuv3@OhggMs-9-PbZZvlr}!S)m2q50tG)8PDG;K;MgdxKNYgVPJZ*2Iu|_9%4?ahq?Eu^fKrL4cs0Br$XSuA>d>kID8m5QxDEEryIa+ zheKD!fJc~fP2k)Sy#H8m*OA~I2RB(nl z!fYQ4J;R)0cBUhK%W=@tGr$APP6XU~JalCyIM1AC?pXmnJ`1`M2Rm~(J?1QPdk5>g zK_6mPcIWsfK+iL`t>pAup=X)1dw`RxIK4f=1?K!Bu(F!>UjmM-0Y?r6N4vrHVc;CI zb0j$P9q2jc*jjL^9r_S+_9$?29rWZzaC##+e*w5_6Q|b;9%fEn$ogjJ1?D_+<|63v zEzmO;gY(RZOIY6uJ#i`P%mwDyNzl`mLC-QPSAcs@hMv0;9O(haZveNQ%KFXV*lA$r zc5ut-;52i;$M-;2&V-)07u?UBeHh%D=T%31<6y z(377cy)<+DOK_nNy7O;v@;Y$(YjEUxPQU4J_x{j&GdM98Jj7gJj^4uiH$xv_PK*Ob z($J&h!Trox=J2i1l?l)j%n{}sbA~y38{+4g)6A)f*gt$b=hp)6W6mR z1L(2E;PAuX=zicq=Jfu|k3dfz2u?l<&K&`6c?_Ir2N#%AM}gA=(3NAssULxz_zDD%b-Vo z22L;!Fgq#eiIaI0q%PPoVp7feiLlp&GDI2%p=Uve&~s}5I^(Fg>HM7eOXb06k4;mS^Wit z-z9sGOl~S!>WkHGc=IV6R?g_yvT=R)%ISx0*|@3m@a_#;X3tU-QLO02%0E;?=t2{6 z7kA5Y`pzqgV$&}&{dp9gPqu(eZZdNE+tQyqhte-m^b)0481zpcO+Ux!C$~%gdJ5k} zmfkM?%(tbV*s_T-FcjTTuBI=!OOXSz6&pf5) z<@bq9`*lUp$-Mj;Dg15ut)4xL^Q(>>vrLW6Ae*&}E`_|Rysb8gfNtu3(V$s+xgH6~ zD|&|ClBe!Xsz%?6{TukvMfrGsoI>GVvP;N3KklONxB4-6&Ne@e+uo1&Rpn#X5Ax)j ze(dS_p}Yq_3Y3rMhx&6xG0BR^JU_}Q{B3@$+~!Al^za2#{|V*0qCr1M*8eQgD7-5+ z!TH50Jukma6h4LQbTTi$^C9dIwh)PKk@&-vvjJuklxDEv9uzsbD(>fbPOE3!qN-_ivHN+wdW%X2KB+0!izce^GP(Vi`$Ff5TRYZ8D4I|4`IPtRi?#x% z8>2M5bXQV%HCgv|>8{)L{l-nVmC~(Me6`9jebHur0Dt?pOZN#1KTY<`{~=ws;jdGC zb;`%0j?#^Ay2@Ll{#H=9nyi*gZn7T!o4;-YA69%}tAt zC*9*lvBoOCvC4O~vF<)OPB*??x|=Axm8|D~Nq6oXFWqLv*Q{KkHM{95zr*=3uwA-8 zqwp(ax&I+uYR9~E=PAB<%9YwYH{B?wYrivE56u*wKsJd?Zr@f9E2(0=g!fc@dn$d} zo^qcgr<>R=-E$~>DOrllYX|x$EVtn^{&Rnc?tfnLI)cBYce%T1$s5OX#WT)vk zJt*7a0_T^f^t|ivGYbEU>?<-aKi|-|=jS#$qd6Y5f|~p_%59X}BAHv89!3`}{(Bsc z7^Uasw}!$S$WA2l@;imXa@$q;ymsyzS@!RkWsdX9QhF_vp6u7YPT`NpJ|Xk+3;n{) zPMO2?xsLmxUjMdpb;rui&J*dNQfuGoHmQ@{&ugf)r=~yTw)yV}GaG+IxSAQ6k&qS_E^|8V->UCk%3!&8uBRE!+@jq)K z)!u+A@~SFtmrC?c@UM^Zw~3{H4^a3~vH>#Bzn@T8ZZGfRK7vQP&GN}EK~CzCJ!hzj z8C9l-M4c!Wl-D>>Px~i1Kl4|L;t9h;HQ{xY9~ zl|4dcoft23ne6VD<9rg7j#sXWD0~Ik)nr~iH&Iw_Jv%)wedBpGw$Z&b-LmZ`^E^;F zR+cS{vW4k6Q*O?m7rNiWl&+WW2!+2U6Yq}ZYfxBjzuQH9u3WS6@XejHPkChg48LM6 zP}&zL%1q&xtpIIt&L>9cc<24`6y89#iOehC1r(N>ej)1dpmXuNIJ^D53bOnDTlnG734h6&%IfNrEn{N6qDDM#Ef{(97pnG}}Wo97_^JGejS`LSusip||?I#zD!-nc>5aaO%teOgts>a9WvJ*p{_ zLsh13mj$L6(=|Qd3!0OiKviY&?jf;Pz%(l6?PcuUtW#*x!?~(-yXs-!lFgT zO;=egr+PS{W98a4I9@N|cZ=W-R(a>T&miE@h!#}quMUsg^5 zDoWJ3VgcQcGM}P6!{o15zn@ds$SX>K%qvebh2`cQ$DPZwb;HTs8&<8CC5c?4&QK#Y zGl~@ZbyZ0kbX{8Ggx@Nzu*`_C`~jbTh9w_`=gPIC&0lp=eNR10O{(+d$1?fRbQbxR(UdEFRI8TdbKKE3 zO|LUcL_m~Q(>?o$dBPe$TUeG6Hk-vbs!GRPZ0u+F>t(ScDjrbnAE}n_U|}0|#hN3`Bb)0c1Z+CPL?Bq@s}WVlS*wJvt;<;J z%=FKS7`ESO_K%CGYiAgdV8A}mYW0aCy-e7;Q{uNHM)AzR_tn56TU2efPWAa}e1bBS z8CQzg+h?rVhO@-qMhR}U22@JJ*Z8z*y`Tznif#mIuTuS2tJ4fyrS$B;O{#U9>I)T5 z5|iu1Vzs6y1dr{&qpESG+Hi$x^{HYHV|S<1znYSyD?=WtpQ`$ms#tH%_IHR5bsv3= zxLP&lT1SZG;&N4-ERN9kt(+GgRJE<;ORXdA1!MR$Rh+LEy2ma2!RYaArSLIiE6BX# z`x1rS?KT`&<@W!4d=KBScEiS#H;kUHW76U`>McS|i$^r~YmWOl(fvI27P@=eSNoM; znlr?#eH^jB8mwq3s;%+YPTODXYb+vL7*OemR?McmPN0d-ToIrnTdZorHj6E@+*hHM z3RMJaLWWUPZdC~5kf1}Sy|~8o5Rl#|j#l z4#^74ihbPTIlmk2H?&fCDcK=pUOk*aVYz*_i{}-(UiaU;WaDW0_2^x)yBH#?BKtmp zV$;CIGXZL$O=_Mk(`*n6)nKs1Us5S5s8OsC{t|T=DSMFx4eHp;5|0Q`CG(By@NaLhx00Pg=H+`Wh2`eePybHOA6|QQPO4NRx7@zie}0$ZJ=KA zlz$7cynlaA;ou+0Uoy|XW(vzK$?a@*r}25uzonh)*Ka(jQ@R#gM&pmWkp*B%#m%ac zprhxj_Eif@pDL^(*O~F6S}btAq2uI(KMBe&O8H5DE~fA;WVe%f{=7(GxxM?{)$VuX zoA-IQ-8^(%_sY&i8xyBUj}i~7)bk09no{w$s$5HbpfX>buiEq)B1?=@sn@1b>t|ZU z69>4tDT?EVpWzQFOutD#=TP`qvN)ON=bIFk+shZhPxA_VZ`U7j{XFcH zMCYn~)@@w5Ryvwff1$a(+Ed)mW$tIp{hZ}~meQwE@sy7SwL^NXui^-EX>qVYOtvN# z1#64xd8$qXoq9R!s5S_lE_!+-wcU%JE@|N_5@o?av0<2W*%Z^IZ~KI9O zTubrkNo!;RT-qNPms!F(u0{MifIg;4p_)2HeA+J z!`2O&EGr4f-&(A4vs_eBNvkPNz$h~+4T}ocXg3Ipx z5O|LsTPo;3f4`D?c4c%gt}p|p<_pk6y6LBzqR$AKmDCsYS-PQVmPQ3PDz$oz9^fp) zEDr02->5PJhUVYf8XwS0XfGL?P%p|oJJ!$ojZ6w)?jt0!l0t~ zizET88-Sx!sjjB?0 zr1HL6F7}Ym*VSSsKVRoKzqUWqSTdz2&$FW`d@E%{kD14fAGhJOF`dK~@nH0e^8%3?CB5S69<3*2{>8qvgpB=2B$&E7VFo(5j z;Wuh^zn_}-q7qT3SDx(enHH$VRZ2%BWEx?k+OSM{HHM5DLoIiR{pL8A>%ty2lNvJW z7E!P8zwJ}+?ITmH+mQ^lOc*=phCE9gqsb6%o+XA>C5&-Kv!N4DG&G7ofk-v9a$&Sk zNOOOiY)o=vPNhfUJ%g4R@LSc?;|K_oniQ&~=0ioeBqWv>)3DzPGou<0s#ckx5v_Tm zu7*y82UI;Srifd#U{WofQPHHvN@rHhG+Ih*Ym+!zRqqk%e08?^uv)Qa_1fAAHLdky z#+;-(^1g#DQH%4nm(CA|ev;?UwG_UM>@G6z{CSnaayu-A^Cr&U-u*_NtMVF*okTa~ zYt&_QTHG&`^Yo^cGE*Mqaqh9Sj50ck<)&fysnxI3O^tX4IkU(&pB@ay&)K) ziW@JiQp)}ieY|kTQI$wN^6jH^z3cZr3O`Kt7@3#v^A!HJd@0A1{zJY6y@5`AH(%Le zjOLr=eC@xE_9L4qJcq26%**#S3d=40D9UO7WXJNZT(@zv*C5s=#l^luFXPmbxp9I< zImhvr39G7_ZXiJ#HYoF3!QwNDMP-pcIIU=Zc^LN+tzwHFR4-KZUX{KVtFwLMif7pS zi!tRSW3wI9w^Y*PB^yuXm3tb6<@T4eP~QL4UdlRm+spVKE2zC(pj=B2pA%(! z8KEUF*kYVt52feOPx5@fn8H_*T|?&OcN2x>*0$3)sCT~0_EP3IOSaGPMKZrO`rEuA zF;#?Qe)8OrTblD5ru15fWqw~!c;+XHvKyI~-y?r>qbqZsM)`s-?Q~o@KiNKK#G~Rt zp=QJh?&oiG_v=B^{o2F*yhL@srnsMnJt$l0>&lfM`rKA}zR#jIIbn2`>2+0gWfgkZ zDyD{ZwApb=tM#%=<&&>$s-2yh>J}Oql8yC5aRxWl#lE1Zq>(;qw){nAwN|YeKEGD2 z8oK4LrJE-;cK&L*=q)tW7Im9^MvxlAN@}Rfi2P>ABwJvPaG69;#7Y zzXQ3=^p3x1RXTOq%Bh)_Io7$2a22s_lu{EeC{GzKcf+-GBdH=EW#e5h<5H8}Xfzm0 z4;4;LNEG`VtyUK`bYUztA5o3d=!(*$X*B!b6V$)=JA292+VNWJE&AE2Z%=J^F_kWb zyR^{h=0deuounRIX_w8^=7|ebF;n}ysv)e(iO2`}R6I8P`ker=#cZ zeiS~G>_{^2e7c6ha?9Ps*9(7p=dV0>WqTdJQ>BNyUa>+p51NuSskdl`TASQk^EVo8 zdCBiqKgSp!ruXt3IZ{J6DpNPgt9`-Qbe(OoWHY|lSg$WuOWm7{Jr({AlRpmmBhUY@ zC~SO2?HrlsuT5dO)pP%S=j(fO=Q?V`H=MxtnexOj8%?F^BxN8lRxEX&jHye+bAd9Q z6zAJc>Dt6H-);)8BiqP%3HrT%=lO=t)iR^$^7>xaxq+&vL8)p`en6vm0okZ!INgEm z()~Gw-y{2g%q!2Nze_J@IF#>8$(`;?Et5~~=-zVTr0J_@rm=IY+pUk?uF}o(H!3af zsk%c`KC_ziV%a>4fLTkABGk3k!%fE2lFG75qtPD-l^a!-JU8hYvHYc?iiTm!ij79A zlzyYI2$ajN_8^^d>Th5N{EB=h`#iFI$D$@})sA36CpT{gDW zDfP!RH$hJyOE0H;O!yw5Ol>mBC#%$;GruS(e7?hUM_6@+yoboqZ{e$>;pJ-E7bv4S z07YpMU-9f49k&_qFZ>VGpY(4cg=dh>CiDC|h;`2|@7wclU1!JYh;%RdfSec%=Ts%$ zBpQT|nl0-4i5mL!(H(urCvmSSS5a1&L>*r$xGKM=WG6RwA@V;9!EBjf0O5{myh?o zEx(PMx5PGWT;08{bKj0F9h9@G)T+u~=yBfN@|=Ex(sJk*S+0vId==TXWL~+_6qcL! z9344x$NNyrN%EMm{<$P4=Q^a+uN;iLZOUy>O^HeT} zev$S4ZweQEt|%pBUb&Z2SZ*)#I8%0~@vj}r-FZ^C+mY4d_sG(oNaj~+@79!?X-3IU zk06eyv4t9>VH%z8$GTY1pfy%gspVBi&m=0X&CsZW=WBG!WBC1Ai5yM*RMi)W26cC8 z?09o_ga2vr&uc%k6n>d3N9OrILSeai7*#I9T9#qA)X&ogx7k;*VF3*%a_U5r>U`8M^(~BRZ{FyV~IyS3cAfDFMtp2d-ex2@qhMv|f#rafM_LxQ206kFa#dM0zQo~|{Z;U!w ztSvsn3%@$<&a;}@5d?pEZGZWp5L!fSZ=+$n1AS$ zjvl&Y6OG<&^OoAnaa<~y0f)5s!Zauf1n=Y9*X zmrtzg=tk{q%dS#!DwWeKo{4bF)v7tvDasj?&!L^JMdk@DjkE-Li5ac1>e6cXGL;@+!_>PER*W@`x{1N4 zZB#dhjRrc-G3t3#QPVwJyeuDDt(x z9?jRG@LaMz$h>^x6qZ|IQ+#0&2+_h}^KhZ-VPWVq4Xbi~$$Z%-iqoXTI`LC);yJPp{L4`O-f_%Q z_$9Je$vpqwrLf#~-QF!t(8mPm?3pQ+;OwFP zHs{+yIXINAybkA4ct5fO$h>?5+|k+9b;$3L$kQkGg`k{&tx-379Q`%^NRud`iZEmo zYgr~44erZ-7Ok(=bhc98Olyug+nS@#^w0H+Dq4RnElBrRy~b(`92tlg*IA7^HPa;v zeY#)w7x^l!uvu+|^-6!(Ut`sqbr!8bGaD?&9Ah~YYO=l|Tp&z0xwJ3e~t04EXEPh>wF zr*^6jlk4kb3e(CT<-25Fecec5xute-eYZ^RqLomSrgv{xxoHDUylq;&ZsW=FutnNw z@kKc;zL;>4s{Bbbm}M1)5tesp-KwV9KzZ)W5Qorp>26u}XPEMH=ofkXg`+DHHC~l@v{QgyQ0Y4AJB^Aq;nJGKLIeu9^jrPa@LcY5M0`XXPiwv?yH*E*}#s;~m?khxDa zg&aGmm#Ze+aDdn^8iTZi%2&Kl+b85}3X)140jpD6EuPT*kLwF%d6r#2zmKMNiYM8Ag9bpxHwI`%qo_{xYp%(#pDeI{ zV6AX(=NaAV7Spvo)TQe8gf%AcU4F0RVAM~R%I_W5Hz_ZW7m%FfN3-Dk<9`kaspXl`*A)Es^mon`Op%J1~1idve(DHApF*iqZ1(K5qIx}g`F zMKqczFFIOR(rBy@QMzo^kW)z=5<{o4ExJ%leS9(2ff!}u+}fxJn8jwJHp!re0;96d zsH&s`exiP_pborfKnEZZ+6c?BKGUki!GI=RmOOSu5pK=)ysBomHv|OplFp%Q#Qf&k#$DGmR6qeT{=@>L+YmOuct{e58lZ z8d0{dwp5f=Q4s_BtZHK)b0G~Y)^CewjIHoZIHJ_&qa8FoTvT_=INc~VD{853%&IY# z7SLAs<53anD2q>{#W(?a8l{oSNfl*=-!>=GNnct)Q`IFjVNZ>1v5!VOHS&N)TWMUg z-k@hJsaT?zR$G}B@^`a16r!2C=4vrbzEVbe1?t_sW<)IG8dbZ5>euY7^U;WE$zEo$ zKV(|fb=Avd{hy=iuL@eh6Pi%;fU4c2hURE@tD?f#U0k91uT)zDnoMuaOALIa_u zD5uktW{4Zg%plEF1!?BP(yD3d*lY?@Rg{!d3n|NXvYuCchigx&G=i&5^Oe#AMRWzq zo0sLI0?GT{-zi)iP?b_Lue>D|$~)&Vl(U}C$L+2!T9`wfU#xXcs}BqJ9`Xsk{$#kf zl81_vAJb@Iy%@9YU#+MO$+fpMVoQ^ig2oAhAv*EsMqNeg0UE>@nglBI=|^ct(=r*F z+M)3Rx*l~p^0Z2TMmcD_-ZcE8x`K*ZYa50;Y95#-EIAU6+b30^M&sdOA>`Sk(%AS! zBM|b@I)TYFo#~e=fGIT7Xey)gj3!Y9r8wDGOrw;7QuFvwcYM8K8z0VN^3bQb6n0fi zqt;RwA$Lrk$|s*SheSn%xLeh3P(@Q|sZF=-iF7xos*0#n)Cp>nTEab&P8^pWs&}t{ zbSZ`JB)f;qJ1+G>9GB>QI4)m4@s0CP9+wTBJzHc8krU?_ugN*{moZs>wolHCPxzul z`C-uvQDM=08y0m6sg~ti*Fj&PjTR3YW#;|#>}>j|O%P-IRP7qIUQG0BH_Bp^JfN1J zEwrkD7!!1?IW+!TM$2pbL0YF#rB!OQBCk}}mkC`fsM-~(d8MlTRTal;cc|Lqs;D;0 zN)3NdOe&?v9h;B8h}M+Rl)G-$Y4stRV3$|9T*4!k`D1mP3`)c>#+hSi3g>_^^>pg! zWx>h9*eD&{PD`pZcw1XaU5hfh#7c$jr!H$#sMe?p39E8khq1xfXeO+xdh$4|*HafO zWXhaOKTZ4!quFXGrKGFr;Xe-cXZo?75o%Jgtekpq56DFf{%|{;U>r zXegBe?p9zwa+HtP-n~!ZPsu`|Q9rJ>;m5m=;Cg!Gr#oI(ohNmy+}hzb@3biS+zNNK zagx>-lQ(avv~G9;b&Oy0Q(%Z%D)o=lsHkPic_lMwQk_=y(Bzx;J!sRJ$emN2c}zi>{SYiWb<-_{bD@1&j)#+$=K>Fl^JL>B$hyo5*i@SyD4b%el(y zO`q9hRG8%kEzh9!VHc_9xoWlQJ4ZDZ1t^MT7n`PKmeN}eqLLys(A zh?d)l2t5dt&T*scMT@_>X(!6~Axpc`qQ;tBrw2=N-DcP8P3>^4ot)oYYcdWd*Q;r9 zx}d(vX4mthjbn@-sK#t#j*x!uN;IU?MYLzY+>I{nZgbmylUU3jw^Bk2* zdYpVb@Y4~}Os!3vC4b!CC@I&)5hN}#4l=J$>&i<9RkPlBTs0?_zM#@0wh{Cd)65h# zjx&97B=(L?%FT(2W^9XNF5$bLalDLoI9)sT7D>m&-x?HlV4 zcz$wQznd=D@^~9f1nBf4=7cp$uCzf+r#>MqW21E$G?=o7K7mH$?9-5Mg3|S_&+{pK z3EAajUcNU_SZ-cBvF$yK(R{b-kCev_qXC==8b&{9=@z z*PgGU@EWr3a2|s4+10!+)vGMu+D=7G=&@NA;9?W4DzjeHO~oPyRaO zue@HLrSO|%Lu6igS}IYV|MB>^uhmyaZ{6|u{7h4RqwZKBdO_^}-vPR8#{-l&8|CRC zf4$>#6@~90>nHQdGeTjx{g20o%j3RUF?xJ{K?_R6uFLcPbb$JHJV3E?QJ%J{(ekXK z@C{_Qka^`4d;_F~{B5bAm`MKtPT>)ip z7iK?5kD)D}1(e$~uh=xsK{L%XEJa=QP;E^K-QbFhvMIDUf*wCBX3hxgO%I?VparJV zy(d@`2+*UaFlNpUisB-(tUOrUU^Y%Oo5q_HX8U|ow5i$@0 z`dzAUXviqmi+avbJx2ICc$valnA&kNubzKOVYwA9MZa#B^^EI!TRq>5YP=d>N4T}Q z*8MzNcfYQKvY!iky7l~+rF^OX=X!41p`Ph|*wK1!k@eif^*nC|*Rxq%W7bkVH<@Fp zo@v-Xn`rD8zECwT+PdEpGI=O$Ute^>RiuKrl) zKU75v)pP1n)N{CIw7r=`;e*MRlX>-=rLf#C`7!Fbg1^0S1DeI{-qLXboy7FQ*DZL{ ztJ;0X>ukLJbtAr>CdpDJKOIo^o*`}N*m9x76e`wAg^prwl3A_1Q=}Z>& zG#XVUifJWW@f81TYc4$jO!6`*F17ytuNeR;^X*)#egE#fx2u`e>oW zEZ+Tm9)%AeJDAL?kIyMAx1lWRqjjhClQg66)kju)&Uji=v)ZTrrzwZYzb#fWG$|*S zKUUc`JvmT8tF%(;W0nTUDM!p8qnWa*;u3nRT}%@5jDTHSQa;6s`GO_KSgU;W0>B&^ z_Y2Xhj3F94vs8M3>$H~pe3xn(y*n~~vSIjUQiq=s@m14H*@iuxCZn5aLf;T26ZJ;Z zZknDg)uS0$I)SV9;(az6`nuN zjqoQ;`8kxItfz-4`~+E+%=72x6qegMUca;R`ty|=H=K0Xti{rmSSL+8*3ruN$+yv1 zwAK^~(bz--O+40=)X7EYv#Gvzr)Pf(Qh$^4cN#|XpGo2QWKl9N|HCLOx9l$NYsi0p znSXo(Jtfr9LeI(f(!E~Jl7#~FDwFF$QJp+F=IgEpa)uyz6PKUT_xcGBQ8-KX9GRE@ z+Z2}D%e&~u$^7@9<>nuoN9CX6)R2pBRhc1%l|kE%PoB~&V$UIJDv|Th)*j<*n^}xPtGpQksnWrv#2Is(P*}c zyf8g4o}?Ga>8}RT%=|b(Gl3Pp+3FN|rYLFnlcD^)``>dEeuL~CGS8onC@i;Qc^#B@ z{dni+Hhr+i^^H^)(c6)K)ET`# zmQ#2I*-A1m{}U-Jw|;(KyS zIhMjJ$WCA%1bOm}=U#q(^!(VEAU75$Qx_<0GE;-boGI5L3eoBaADvH}&j6)qQhKso ze1XCrkbOwzl{+>T<^IO=yq6!|NTnIkU%NA+0a^3zhb=>ObPT3HttrRSyC-^?&!ll7 z(tde2L5rdpt3Vr`O`UaD#ICT*}Nq|?NON~1C(suhQeA{F8}7_Zc+AR7S5T%E>1yP*+q+i#yzD z_sdm%H|a~HAAYnnkNPp6!b`{wB=h_@j>6yO$A*ntI!~sx2wUaxt&X-tpJL5p%R>neoD_2B;^Y5qhy?S_@!Y`2hjLggbeG1F1kJs<+d>@qgZ(i5w z{xPKLSdV)bpzI%|*Q6M~c8`3(Udr%LNaijf%r4&An ztb@$+<8lhiEzj=>Z5zMh^G^D)#dT!+_w4of|Hs*z07g|^kN@x9x6QmvW+s{JAtWIz zVGqbAAOu7NM2O%LaUm>WQI;4$acPZK6t_yPRcc#Jt97ZiQnePfR=(D~RZ&~DS}pZk zTWzh<{%q^Fwfg^@_ukDwZ0z^@zi?(wW|DW#-S0i?xy-w7i7P~Usj^1ht*zZKm39!v z_pp`mIKVqu&cj(^MsSw#Jl96aQB{vU=rPW3Lc;sM6Y=>9d>A>~yWoEZ{s|a9lY=5Y z`-&5r=ac@DP?xH?TKemY%K8UeHcpX=;V9x5A;+M44y>*_BDyU+*U)VT?*KLfhVFK7 zDgT-7Y8fakrU0MZLX64RBg1fmOUF7)+3oV@2-P7H5Sb>(}b&$0$R;abzqJjZn_BNFqT+3bg zamC-ytr}eFu=Q2&7tbkoFRFm#@KWuk{dw+*<@31IWb9Jnlz4%g^U^69BR(pT(sF-b z4t-cZoz47^C3p44LNU*upg=8iw<-4vYCg+%C)2FDGQ0;h>xXTPbyOLKlRtHO z6jQstAGKrMkbHkm0bd7n0H!}H8$Y{08;7l5(=LWwo6g=eLzF;pUN9)1rNgcOn(+{Ke?4Z3G8Fw-+uK@oB@J+z9=gZ(yI=&k1*B!APf*F^z=Za-3 z*0c{DC8Frro$cW*qnof?H_8R*A>L@PF4x+Q0YRgaCQevsVx*IFO0dw!Gd_j3NIVjp zA{0Lxb#-BNC9fHcb8r|7MTr2@ z2*;V|`vkYSI;0 zQZCfVGwiK4bA=JXYsyKry63nrYWook-j4dF*6(R|ntPO+N>^lblS3>PuH8;H@anyJ zi5j=q)BmmYue5&cQ?KO%`OWDGx3bZ58yd^pW3pHdHF9hci_Yu>cYs@&80;M$OtbH> zHMT0Yv)n#~ua`2zGnEf0_YUPgtK9Y6&|g$uhwD!e*_?Lk@owX?j;)O2PAJrfhJ^c( z{-|jqbrXgc_OG=21C`jOQ`>cFa$;iHMamuTwwee1TzhBx)BB@wJLp6AA^a@d(L4e7 z3*V_j&hGb1I;A!qCSTEsYmt(mxuWIp*;serpWdlFVy1a8o55zUF!`b+77PLkSARXLM6Oy&?+ zl=#)v;UVKxy%g8ISQp>)Sj10uME?BR06q*D2^fCHgG({~CcW=h8`{s>xcs!(-MeKH z+Nq|+)?PxGj24UHLwX`~?}+Jj@jP>0z6Shjzzu+*cMJHxr5E2Hwrtq6Y*qWx1?`b> z?C{YLoNc`d!2v>WupziFrnjHxnfBHru?GT*07GvGxRgHQFmsCQ>|7Sw!4n)vb*zxa zev8{ms$P#kKs*=mlbqXamjkh7Eyc0tP>u_MZQjH3 zRMZapp;yNT!cTIvvWkH+!0^)uE@f7HesyAhCA0r@w0CY=y9p1S&88{1LVZPHN!rA9 zd1qR#6^F7}Hp)URTgWw>emI`(iRpLn{5qa5^e+Sd8gL_E=qH;Z`c1JMrRk=F_mN)o zL#y46D{Kbh#bWewij2mqF~dvOi^(#kcZGx9@>F6VlHVkbc0~wEQz;2q&w7d)y^`Z( zQ6l4}*%5O{kF!J#W9_X@dDTcx@nA*$l`2V8*tc~2!C zR?ZkT#vS5}Qlr$F;bC;&&!YBjqdsPSZwBuIE&@z_ZvmIm*Lt#g#rkEPr=PWa>3TU1 z*PT$S>bex2JNAEACpZTe6myBhwqLvkwLb-ulnNm2BjuGLu*o?uIvekMChmXe8GdqO zlvN8f0EVB#zz^hSPApe5{ePCk=~^De=_1|6(vHsd@FVF6he@J3u4Dv=S5@8l z3G73NFEF^69-D|ePNT|Lb7^|u;F4SDf^lNP)r38Y2#b1BG{5$|5VcDS^y^?* z*0;6boxquZ;qM}FDTzMf&Bb!T6|AnNYnoeS&9}yWU0E-1pl?KGAGi%pKiu}bk*Yp? zoYnSXM1L>OZ{{PR|F+N_&t3-@`iFu`nH9%_xmrW8}ZbcMa&flRwQdeoU zL(d6c*M_eJ)>sr8Z#w1JJlbiI9~D+*vzg#ftg|>XP6*~E<^_|Jy5{f^x~6DWmeq4~ zzX5gwTj86^o2#yixL~jTMa1`Z_-ckP;kz6B2f+P+;rkchQts_7=RdGt59FI@Tyw)K z(d6)TmBcY0d!@Ga6R$OmNH5T3o?VeEC-{giuXhJ8A489JDd!83e@XL85npu^^7DT@ z_%vV!VE9@HE~R(8>Vw*odA4GmDD<7?iS*@AYizsq0J{^n7rJtQ!(bojj8G|_vn!^% zljoZC@E-67fQJA>_X%(*eXTnY$vMk5#gQjBh13^LXK6mx`Z=@*%Ap0iyh&`D?8{Mo zvlH`lhk=g=4h0O|W5A{KCCBZ#?_2?)c@L1ZH*Ymj>R<>`2XnEV)vc!xB zih-fh9RJeRz39PYnMrycMtvEU8$xcR9Q^(eBx&@f6%Mi+F?09&Bj*T+7~!Og9gO@O zh2Igs#c`#UpQ{0Ui83Nf{=ELR@loIL%cx#&!*?Bg%luM@Dysm<0H$7Jz@_Z(!yivh zA=00-H+IfgxiTEf+18B8-iCUVz5a26Fo~nMb`DVzize|X(pTOu5n9FdUCcOwNaT4)cw}qbmlVrLjjr*=+TpFYi>k##x8=2{eyu#e zndeJ;Zvwv-xE?U={UNxN+v4@C_r3N2`U}l{k|piLa51|k(ss`Ze|QN=0Fs|YBKR5i zaUu-*>?8J=uEe(_N$}@VV#-blf>BedU4qo$my&o>@lmyVh8~G_zrk@25f6I$Y)+Du zJX=+T)+wQ}VR43{j!{vyrsVr|E%-WM zBOv9o`qk7|`ZWw3Dg!R;+*#JRS!6jB;k%B(Aet>3uUcP1B=`*9_Y)fZ*7=;!_@u%6&98&w#!_ixF_(SwMA;d3J;ajye?oQwO zh!9o7yo{G?9jcSA(pwMs)quPa z@~bJk7V)CT1a}BVf%!Cc!3lytru15(d8hj8i6fo_#9$dUTNk$o!s}?|#TXI-dHKF^C}8Nh#H1YRo>)O>reH$mMR@z?SDs6N}_ z*Q|#(f!_=4226dj?A%iJeI=?-Q!F1g6mnZKmykYCy{W zik}rkcyAO;+6mIc%|XD1TkQBg=hWSeM+z9aVI*+0hhhE^Rv%e+a>Ae=VP1PGf_@41IZ z4DXHoY#FKLD9=A7TeN+4r+{{|Zm(sVLa)IZVR=Y$tvM6#1yB!zpE{&UG9mSiV1 zXkZay28V;@H;(>TrtO6);QXJpTkNH}0Vi7fa;4v59Emr(^OW|lww<&*vXHpa4lZ@P z9c?ejX+mlpE1x5S`L^rdLbzW3t%dm;wEYe3ZuJ&mxIWjJfOpW3ahF3gYpmI6dNN z;W;Td(O%&HLD^Tj_8!N*hvsv-wEdW}zbOd?+_S5f*vGkpma`(cPulhqc4C`C_n14` zJ^=;52K!BIzizuD{b#iQxNBdd_{o05re)oaixbqh ziG0QQYx{FFPIod6C&lCRhu}{FKLgA-oi{5Qr@JqW)7wjNXHdd-xZpcB0zs7A;qXYYyE~-LAkmGkj6dNg zL|X}69{yY)zkzgVRJzW=y_MZNs3FjmC|CrNyiWAzxEQ9oQ~ZL7y5#eTb3^5uDA50I zdnXg5l*~Tgj_#gR+p7C()DGR$vo3Cj2f=>|JO`L|_!GF4UGaUsx7`CGxz)#-^aDpP z+Y~z3?NGmn{NpEHB~9=>ZGBi)j~M$1SRbtlovfFWa17Bu>6R1q61_k-z-`OlBEBXa zkzYTL0zV#D0vNs?J2K+yQ*xNt4uXE_=@Tb=1uDtxtE?1%EVLddPZgIGxi>iWHiujndfkJ8cqs;v^|Dz*_ip(vu#x1w$DDsze@K#VwB)r&ZrINwCV>GXH(swS__9x6+4h+{R`)+2W&0Obm_(cX$7GOt&Po)s}A-qb& zHy+`;jjT(5SN4Z08wBa#82?xzztB6*`Obx?Dq~LhMM7!pk+p*TZ5UPkzVF}7Zq1tV zSC+{hrW*v`=AgRtxM~ZJ&bP!*UYCZ({0%{^JUdnw++b=2q5p6%C zl7II654@6}v9c)pi?R~AIsaMZu_BG&XMMS{&yc|F?jYy2ur9aC#g)k+b-^s1Alw}N zO7M@A-my`uI((LM@IK_4%P)CYCuFnQdEfWSF(!8tk%@$J?vjeiA?Zkg&nz zX>!fXIYdu2Pa9?*%JaUK@NYmd96s&Wb|P#8_YFJQ$hSw>uPf~9iHe?ZNIoQ``Crkv z&d$l}YX*Uj1jYbnT+aoU@@^mc$WSX1spw_3Y2GG|LK8UbU5~|8R#%0~3b7?r(#z;f zhPgFD57S3Rhb5l7Kjvd6bP$$>`}CdQ_W<_+hL1s+>O=%^JUr!r^w9qJbMDhX+FQuz8L@l672(rqjjsto9MtU2`5puNdN1Ihk5w^$@iuS>_f6*j@QWxrse_3SnabH(rm}+KP$%ir8Y963cE#(;)i}j!5b=?j<6AV+3Q5@xs&!X=j8jr9|fKS zOnbfuE~PKI>w)dLWy3)&+Ps;rK8LQJv_pqoo#i%Km?$l>i%Dv%oir_3DA73^xPjtH zA#O4w^f9_#&DK4RdHdXm&*u60{rObzGk`6C;qwk~DUbGXPC1ZInX{(biNdHtKX|dc zYZYcMvaO#nE{h26MPvo?aN;I{9x_|&5B7@1E=JT_p4yDF z>sXAD(#`;aQA`evOgsFDf9vRcJ6C~^1jYb{|ApXEcE$07d*25RsZ2pXdbgRGjgz>8d9W}tK_929>>|UC)e%Je?1r9cm#4vB0$v3S zKYs_8vL^1g-uxV3ju)wIuNJlK)XTJW4*B=!Cv2XHIe@LRqYLHLCu&j&iQV-ybluCX zu7Ze<=7st3gYmr82CM`OAKlJwt?H&=4-z(G09?)Ew&#W<1GdMT=9dLM&J`HX&;nHx67%HkPY(UlZ|Z_GkDzIuve}cU+*DykC-+Tf-UrE8Du6#jQg539n)T`)Po( z7!#4oDaZ*3=!lq|bB)A>8AmF`1*(bddWd~u#9&8J#NT%48+lYW_;-Qt1BO3)al~I& ze17QYb$$qgxUX7E+P1alMDaH}o)4{JgvDtba<2)`pB2pPQM4f9A>^%xqF%C9z_CWG z%zdn3NU4U5J)om2`R5<*&*rd*whoUqPD8|l0ViT}kw1v)jL_e+^;oYK8@dv+a_`SY z^=XA)b51)Ad<$?kVCwT#a4CJAqs3Q%>a3RW*R&oRiNt8?@nvQGjS#P-Smdt6KM&tT ztV&8G%v1<))yN2_H`|D{qa^PCn4a|iN8tXki~+##QvoieJC1*C-cA3n=xiq{Obi;^zw8Gr-RU&Ib(LvyO}C?vCk}#P+j> zF7FUMgJ!^LdRrjo(9>=YtlRWJk85QUvFVOL??&%oqf8U{1%7%&MHsQJnv7@#KCuP~ z&{F3P<w|+W#60X_u+r(kuFIFYL zp!|!G)M3|psq(K-$&K+d1G~oFxo}ltiLOYNdXv?$_7r=ZH^|K^q?)Rt_TNYQ*3li({(l3nJ|6uBVA_8_xRh)h zXY1yN4xabOk7ge*t7`Yye|AFW-Dhy##fSITDtya?uLOT41L?G#B7D9MNr2kxbD$kf zls7U}c#@y8%t?+d@>`4)r3k*7^!hP}Il<#}DOw}~ z)QO4^hlDAtatUJD`85quK-8_yS$eL0gcmv9bqtF5e=_Dz#`!DYzXjd~4F4a;-cc(@iKF)wD!mJ=Pb#OpOxV2fDXXWzXn`NA91NiuWVnwWwj{3k&3o=iYP!@ zqUjz*q~poIK=uPGMDOIl<07l{*_8`{61YiZ#Ie0tOlU^n{SkAvw=rs$SDG6``hcQIE0t98RLiOx8u$N6c{*o+UkF?bnEL+% zT#AubnSLG{z3~cRQ4UJkA@V^Vh!h z5@B7D0GfZr1cWAv+TfHJr(1P0VE+$BB4)sj#p8T zNYx}tIeogA<{`#%QVt$e6^~w6OV)ogj z9?YIl$k~R_)F`(T1&APshZFeq$fg4|3ST)~tL2|8Z`+jfuSgfua!6E<##8h6x0ArP z0_Opy9=pM%Z0_T}{cp#&Y;KFTYzP;gBM(2IJ`YQM?w6P113(-wC%-YxPN}ztA)A zlhr&vs$XJhe*LNh9}bKLO#QsJsD6E{U!zv9V9s`ii&op?F1NOwnwM`V?rxKBOj?hp z>w{W7jtOQbN~?&OrYi7b@*3QMQ_FnqO>ytl&dVq_aIvm(3o6O?N_tGrsbV82IdqUe zkl#BigKd;VB~DLBIZW!bi-+VJDw#-mk_)WA#*>MmisgQd$iveAREaLs;5^IIKP1!; zarz1wvE>}l%1WnHI_abQ`Fe&sv#}gd%>hU%6?^DUIDgS0v5d7+)TobP1>MA=56&kPK4Nq{{sZo9E zmPPzZeWrlV2U-AApL3Q+-<$hO<0A*3pQHL5+upgJQ?z7GVI?21*T1anIXNAFO+Uxk za`Fom)LN8oBSFcIB7S-nQ?AXQBtH>n<7T-$PyTIS?JmP{ zw0JDb2(H?CI3uDoo1J-BP@5jYsBtmINOHz14#qSREr=iuI0dr|<(^mWdH!kGsAcs{ z%Dq{YeN~Zc`g^MACbm5uG}UplLv-drWhdQh>1|2y_GOH}DoHwrZaVd{a$n`wQm-lZ z5yg<2y8*}B>hGz-n{@GV_msddb+`&kh^39rB}!kQ5oA50ovY<)hIPn5CHbfJEQs1^ z7wur=d(VLH1zwEXM$UD8*%3waQCerlnakF$i;ukLS(DGRx+-ho+3{p8rRi;C%-T!Q>YUtnNy-HTLQh zgt-ej#}kh%LoyN&tSlfC zbgG1{yfz?NJjX$n3?J8@fD08mt)qxkU0rZ!IZLK^vZ~q>bSs@z#N_5@*2E$%U*#q2 zu|(<+5tHX0S?z<#1z?_jO|f!(C&8j}M10t$zIDe%?bEU<-#*L0JApF+(>{B_rSx?V zVjn%rM5*|Ls7)W2mva}=M9(_bcgy1dcKLd@cOu@#p;MpS@*|+ zPXlHGrXK6!@6G;Y-t+sIh;u^|?eH)!JubHy)ig+Mmj57vM?V5OQy0ltAoj`}LY1FR zl3h$L!h9l2p&f>rnXKFctaSSB-b<)Hv1vno7`q~)rfy*psEmoA~skQ3iYM`Vm_MJd!2FE zY;viI#_p~qQF|uV=Ic=fJ{TAVn0lNVe{brsr&qj;)u^o3;hZV`-13Z!*@-e{Z_(Dz zYZ$YPKbJkbfFqhD-AI#dD9dp#!FUu`H(lrwF$0l)DSa-CPIiuCC~rW7hVP*COHlmxC$x!^LH89(@I~%* z68k1^9VbWhn@-Ey_0Ir53Rnmj`e%VlIj@g=Y-=}fTsCX1q_=ajk0~TrRcuMh`c8l8 zW8xknNwu8;7|Jk(wS%=H=QcfFVM69}Xtk`Tl~X0pZ#yO8XAks@o!pDy?*M-S3_qo( zNBj)z?Kc(MVXa!fdBNftn~q*A9k)Y08`*_T4e#0KN%oY<-$C!(U!+!~vml;8eiW=g#>1|6HHYb~tMFyPdGT@2Byp(v_Zd5sLnPK^9Lx64o%yUGCog;G8OA zZLH*wIZS|)>oATOr;hQ*C3W?9e;|thH>(tuG^7}yjkN z-bP~@iAz)TFHuhFsC3|RxVJgoXkBX;U&guC^9s(dF2)p!12LOWsQ~zf0u>O6_XH)-~Cd^jL2G+h}1cv8YDrQm!4$pEzTavvoAKPO(GOoT2{sZ8C!0_=&{QcYUKJsDg z*I?E)!-pt|k7UPPae8zN|C?yk2LTP7#b^CSTl*2RUy{#?1s-|Ikd8Te?YCH&l!C?qrQ{XRaDr;`iIZ@n3~h)c zJ0eRItu&kk4-@tw=`u!Yc_|t&H^((ekfKyB8D0 zhC6PSWmvPq1%#9fr7L1a)=0Wl-YC0bKDwY|&au~m-vWFGFnqiXE~W4LLJKQ!#DomD zwwGkWi|NFnh~8#>fO0H}lsJ**%#YI&auDvKDGnRRI0D|~?Ct8Z@jlMlnJNCv5d;J- z!#`K<2pJIwjnF?vCulXD8MRx}raZrM!H)-)0EXZDz@_wk{|l35&s=?YXFCy*!x{1| zIrQ#OGBtjI)eq9mECy{^yB{Lkv{%86AeAn!agTKuyYo1ht@l@Qx#pfu@Qzdb%aoAdLc8vIb; zFu>I7HE=2Y;{1V4aXe2m9yYCDy^>{@8V%UxkG;!RyZk>p;oAjX`1S{N7t?aqLxtAe z1rk3w>s15|#mPh!X6v~WNjG(2i+cnS2Ur7$3N8-7LD94XPE8W_Y#7l>DptE|h|{d) zy|iia=tL9p>@kV468Ehjn_;9CIrn1F9E0gpW%G{CN&* zlxjQW`Q)>yPRNT+5so}t^c<*k`HA`x$9rBWoB;6B8|+L}i}VeOm!BxL5MiM#D0@F2 zwOjL+yj=W5@Y8?|fN8hK!KE~RFFH5u`tHH!2Whueoy*n}HYt|obBuU5I!4?cT%{Qk zds5bYg`?TDFtA7`5Z{kLOrcM9=2i>~DwBiJ(rB;Wa3@<`hdDzE6?5POh*>zRA4K%b{7Bkmop`^9H*UoPo|@eSxw!5N>x2jy3j~sx}dSGK^1< zmGa9{vfHA1PdYO{4~_<32DAgF-d_Wk()<2t#!G0g!xfq8%N%HWNUp{+fhM37rQfV~ zwDokFt5b10QNo=s#br5{5NDxmwT~+}3K`{N1{YrDQPiW%F94+fPS&T9Niw=ObzL0s z`!@WTb>{IYO-I6xR70FIy6*0mWCP?T`W%jyx4Qw%F$ zO%Zk|!ZDW^{7RCfX%$V2aCkBYQ@uLkRp{@#B;t1`{Fr^}cJTXv2LQwGceY0S4(!7Y zef5f2on)d8m&7+5mczHS9Dv^Pt;@397ZR1JbShOUY6U+l33723VSAC(Xob}U{k;aS z0uz@a@o_Bl{X&}hOnfZX7pJmQ{MnvYDcWEX45c}JrdFp;^Tq~4*`Zb8M*qx$bN#X8 zQasAtoCpe4>T{_D?jm=+-asNUow`n?t|w9x!B!#b-=z4}X{8=X&erKs_;IH~D((i` zb&pKfl3A!3k?xiZn;`>_Wh;e z;y>$3$NE(f4V^7yPbU$alP$&`16w4?uPG@i@x~cFcu84xnyj3X#W&xv57n{Fy3p$8_?({@I?Cj_ZqUM)-6-mC8!&&k$f1Z1cy$IK4GR2h#=u>Ob z%{h@*RQd!p))Sg+x4{|6L8n@BNOPl@)a>e^_ELLQ;S6@Vv5AE^4Gf|M{!4p{)O*VL zow6fa?=MH~u$_9E_31kBTY)fQ%RFh#c-em@tevIxPLVhG7g_J6EHNyJ z!7!0|F?L$jQr+fo=D{M|EhpnylAraIYK1GF8Z0sPP-V{3XLutyX;+t&<6!7y32){N zCEF^pq)d?6sfc+vLM%`Z3B&b1Mj!|MwI~Q9{O{Wt)i?3E{QT(;J{~v}F!j9&TuOI* zFX)QxpnB@NV%C=R9X*y>xLN+l4XsmYw8@bi^NbonYSNsmg zNAGCVkEJAqBB(|hLxx0uEb`OhfJfCE2tk!d5Z|@fYbYlVxg2x)HRKY$iyEl`p(ueA zGW=AzDCL%NP4)ePcGgMy_H5@h$C=^&UON@4(HTdU@Dt=-6qc47qIz4O&#!-#;0?eK zz|?y>xRk!)ghcV#4vhNfwA?HGJlLA`Yh1gDJX__BMlC6p+Ju%ywWLdl1~5i{FMM#* zjq&)8>B#!^E%3X6`vAkoEAjW{{{LjJ`+uxwUAy7z@a7p_o%g9t;WBo!3YW3_wY95U z44Mk%;-9SS9~6#qMk>)J6qIHv(&ci_x4x;IrMj^v&U{CA#9!n2Q9B5K&EN}x#em^& zZT$V7cph}cb`WNKNLYd%Z~2hBZbeKcj^dr+JpBjeG8Oe)Mn=e$o(tn~c8P->ibd9V z0^bjaF0sgAzZvnfJEkZ6JP*DP_$^@g`A7VHU;G^GzW?tTy7qs;P{+3-e&%%L+h-~G zDqt;O_}L0B#oQy!yJ;UxLDp_svq^M6VW_`c-9$3X&0b{9uSprLPEd*fnCyCDU%WS_ zyNBnRb@O@fUjnZKhHm(U~zHN+nEl>M+$d(@Kf^%DIs;W( zX$nzRIcb9NGdzklb39?cbOVkA|5TFUCKAa_RezNz+_*=ZitM;G9{(5S>oFDla9}oI z>d^{*U_E;KW3Jv9wsTaIT+3nt!_M9y#_U|}O1ZH~)Q}RfA72m$FTE|I+s$)L`~4XF z1>hyX(ESixN?-kpe-`df#KCIcuxU$YJIck5@Y3DVC5u#fycbDUnAyK3k_JJBle&&u zVt{96F^&PQ!uCs&!6qd=06l#+i^I4B&g(IsbH0#YN87;90L}pnpF|r7`P_F~v|m2@ z;KBF69zM-*tleS1k+{lMJM3o*u7cj|=dkN2zM$CJ%ay(e^Y=iH5!;TmGuYRl94<4B z@av>U+N01lp`PHFImRAqUoZ9$I9$)N=kn8d`&Y_F1%G^+$Vhc3>XXq8R7}^?t4jyx zkUFQqFbV&y{Z~llso&B1FWNnU1+DUC#%40zKhf+Q?v5mc z9=bg@MdnhrvG@7PPrRe_^+alp-w#i#bh#KK;1E@m_TBS{RIn-0=uLA^A!}24Kdp~R z6xk*CXDFMjqE8S|nmF5py2zxFqhw0#0s_a2fcHL?z)^dGJ;rU~HjRYby+t{I1W z>PE6aaqY?a)ih5M_m#6_ZPgf7K{A8BGD7+vjUs)$6eg37e$?`vm}>c_P0`e9U`HSlZd z^9ArPinbLn^|=#VN?-nHz3LODiE*;0qCg#x!5fp7`3r}8QY#}!#yb|i63CQ^Sf-05 zol-;ia9*;zBYyTn&+t>UU0EeSIUwb;>}L+9jg_cMG&A+i;%|A zTP3_2krJVNL!U4t40?X2awf{^U3Y)f4%VglaZkEIs{t4c82%=Mhy3+%Zx;Tbi0}k+n4DmuvLohWJ9JEc+z5ULa2H_s zcne(0XN`}DkB%+j2G?|%w9ryoXx`=8`kAUnb($nvy~L#`$&$JumEm%M=|RrNk{;cA z1$wV~T%oGLeb(m&TIstA^Y59mPINyIwHJ@=;d37NiNGm<;d2|f6r(@+w4aD+ug#rj zAK4zV+PoekU$I;+n+~^sA@~;pY+TVpkv;EaDLpvH5sb;1P3Xd0DR}`fOM+<`~J0ZdlGB$u6#NhV@n zOm_b$;%_VT&3gM~@Ed`f0Mm}oflKK-j)Q5(m1{S3Yz*BL%Ij`ajJ?WQTJcqK9Kj%Q zY3X&c4b#I!fO3)n?gAXOeK;}>}OG{4IUkcaXu7@K2Dz3=$cL?}QU^Za*TLmtq z?{k;oZ~3xy%Qmct%z0ZGlGVUqwyJp#5ii|=MdGg!jFv-0I2;QCWbw#cN<;DJTs@ZK zVT0*iH3b%64yW1R3Ea* z3_ij73+|v;N}yU~%FZ>`Pt1pykLD}$d@Kb&4OkBtKF$XJzwq&InfUnMF!6BI4tsdM zX@?iUUk82z82X=pOX=%=!RR(5%iAz|Z(D+xc;2lfCUEOfl_6`uOKXS(f8_ZMIbY24u>^b>uo5tQ;O!ss(bsrk)iQkKnhqnkz`R!L?ob?p0i)y= z5YNmww}3n-yC<$c&o%Xb9{d&HHNepQJ-C$5pu1{I7y_k-?4$pVY)4G5>8d=vS>OwS zMS!8V99&9Y?aiu3lN*xFN3iOpiA^(aqxEyhR)ub?B~C{6iAE$QjWX<{?2GB|;`ye& z{{{Xc@G@ZNkKggx^z+2aJN{{-cl^EL<=disoOg$BeasesWgTLDVu6fsho%M$l&y;i zO7`OM$)rDl&p3k@S4*~~WMztTe!3W&2p=tU0av&J-kVBwYKl9G*U|3a+;Bc&hrt|G zl&R0!h#UW^F~8tP%8o~)e%ubt%YjxO&Huu^o>^{8W4?&(8?( z!+;rp;b%LzlpV4CwH3dc^JgdV!#h{X)f1LT0sQ?a1@L|?>3-+`)MM$J3TOQTVjDYH zmJx)ekf>e*ab`*;7Ltpp4DC6pMob+m$k9pIKr-QQPX_#Er?9X(1ogHIE8;qTzi)r=p&)MF92l)mDJa4(gRhdsxe@}^%VSRMar zbFi4dKNX(nA6Ho9%m4dTF=ocJW`$jd7Q0@I%=B^#cf+3<7Y~9z0sIs&{Qn7DO5f+An1AAr^w`w2+#Fs03#|EX zV4aUG3em+F7mf&ea2PAZOJ_84IL?mPj=~z}pdrzKZQ2|0HR;RBs)MeaYmWzC3#?CeOy+zV`8i_9`s4#8nkNcvT}0g2 zY+X>#Renq`ws>Tk&=(T!vYd@nVi;#~P6=+a%I`;5v7zw(4du*IE6ont^?bzthwx|G zwfGu*oq$6C!~Yg=DgUuuWBw!FZ`Q*6iSm+9DCtWr9<;4}emydMAG6mb6uk2k^J2R;H!ea`$!RG+=^Jng#vQ}UN+oQKZKQMQq`e~Ay*S8Z03`CnxREG`57 zX>Ug~Mu;cf5_fsX*w4prAi?O@_1cEoX+%(~SxF2i<^UfqGfF*MJt z73<9T7ijBONs*FCmYdNi!~&Gt0l7p<{2DYBa6{y><6`Y3>*LE2Uu&Ri)}d|SUjn`Y z7{2ZSmtyiR^^VtbFkhj8pD@>Qi_ByZ-_8GToK9JEFyz3fdH@?KI#n9H5-og5W!QK} zpgS5FbJq1r#Fuqlp05Gm6M-p!;p=DMQd(kt!;UY1*0_-sW9mV4SUDq5HaADCWf8$4&Sl~9eT)^cutt!Fz^aPxh-j2S59U^* z1qny2&eevS;2C3K$CSdBh4P1&D5BK&p9!xN>ZuJ5dfvQ`*%e>`{=)eqv%RTGEg8D!VgLBx$Ci`U& z;oqe~f6sEP_9TL2DP6`v&}D?EewDd^t-sjKd=71U1tRH$I7*$O$2pH_lzS%h{k19|lr7h`h(Jj5*M~{JCXC=* zh>wVMLKq6EJEq&hbIrc84ty(c9$@HR11{yxKH?x9OgAX*MUp9H_l7_^Im$zgZVjV zdgCqNg$v`~>~LlLU0^*eoFTRtmMAUt>p11slk!hjhS%?rY-LG2E9&5V5Zg5Yn*a$8 zUyVv3si$~DdBt{}&kGT}50TG;p>%$-5YM1eAXQfBR}~ClUKgcnFVU-%C!^py! zs4lLS#rKa&cWLiktybBG^N1fHY7OhR@ApxA?5DnUd?M}PeH}X}pd2vmu@qd2iAU1g z-w}I@Gut<;ZWjl1S%BN_l*9HF;^#d7HEq3z#a59*$~=|`H=-wCValSwvr*qC)gfW}H?Ag;==a=FDkFGS5tOGWERb%;;)+4S#Q);Z4Ep_a5bLG@}&x$zS6B z@6Pj2eidsJFcvWUuL75{H}3zgZy(HmG&B#Y!mg+aryf{^dolShKA;MuTg5Ac3LsGm ziVHC8=d3(Y=ctIhm*iO=sZVlFRVxkeEgwXD?}o1?_>%SDS@5@jcL2lp+;7Hw-xu-Q z6~CMHfOf~^ARjGmhx%P~%6%r{epT4=KXR>|IaY)?ZgG-xC9X#Ns|$kunQAY`;B&1xpa%cY@)%P~)(IH0q~= zs@$?eHq|7mx%odrcuGBM7)@C{B@7mT!dn;^?bPa{l#$jj4q|>LeJejN7lEGwECUQb zXM;R4*j#0yx@4Ynl0HG56j@(|>><^N_*(;gvyOcZ{8Hdb!0`7&a4GxxkQZQK zbu^9+lCmY-b{`e~Hp=??3)U_I_~R7|iva;1#E;TC4_og_ zMF6LbvMxwz`)9;o;^sVm{lNzTjey~=30z8FdTICz4XtdW+f`>N(8~R?&C|muLxgJ3@1Gj$4BacppXWQSt5kd>aNn9yk;*{4EBT z(wCf9+C%sfmRgoDuA61gW}a;?!_tuqEyaXf_7j{9)iHfZ^je;8Oas&x4PdJrk^Ln~a*_jG6^6U`E501A7Z>3>z{05FH@#*a>?L zHzI2}S+9eax{o718gI#uk7?j@f%$;pV+pvFzU4*HJRdr0eFtrl3+?=?xj!seWo>8S zkt+}3oJHK-n%A;0zhnBh@q9CXehmH;@H4>Be--?HM}K)le?qL|S+LH!9{Qzu`llX9 z-})r3KPr()5RmaY1^h(d6u{7b9bC$e*dG6iUiP7zHlu7Z3*9dDl6{v_yVRoa^@7MI zp^GQj6fAg$nq0iLk(|q9%yWEJsHs~AvHiMrF zd>%0TT@5a!uXQ8hZ#KJgxN0n8S6OhLwF7x8alPQeI2VSklh)IXzO2cM=qXPE%0mu|X+xFwJ zK7%2v#gE$IZRphTvy4ycPIv-J0K>;Da4Ap5`K5c$mrY#z4{D16-R|T1Mpt#ahu?MCfo5@lBBcP1v7zpYaH?nOT9gHGqd`BL zjQHItJo2;fdo%c5z&(KB_jzzBz56YUZ({nZJWMy*D*N4CxKE+mWS#RRzD__sQEk@} z;E&6m>r3Aqty^JZPfWk!yZL>01o&aV48YLe3@&AF?7zLg*S(HR7AxA#tU}Q6NMyOY zTZyD$!Pi}D2Z`uJZzDP~@~0!Y&ADaiQnzXpMjFVphWNvn^{74{uq_p}+g|uG?e^c`?*jV)!*|K|BEDPWdqPF8I3^+Aau}9{u}eLp z&u3+PUt5p#uzLo!^KL3#;AY`eq;GhS!D)1q>aU+ttXR{KJIm;!eF`JK*2HwBKhFlg z0N4f?zP=fM-`9E_@)d4=a0 zF`aN8FeoxW4lsN)fJ-s!vw1h`v{-qK8cX9$+PkFrxg~1vlKIaqAuZH%tOwp4QRNh8 zGh?t`g@dz+$q=;y&&x#gJL2aH{foda2d)AP{qM%#8@lG*&<`_t;Ak6O19DAkF{Ej^ zg!HO-Tx;wFTzqNW02?k3+$w^tn$hK6?{dsm*gYtYC0B&0{g_xDZC}$2yUSAL0&o z2EKAGdxXR1R!4C}w~ObR`T7;`8-beuL-+gO{~Nlq+9SGCW4b?4*3-}(nx{J>q}!Z} z=CY8E^L6VE16=eM()rl+spUGSNG7UEQgT`kGNCH& zOUh~KQJxB4r4e7ZLD#g~vs`4Zhu{#BO`4u&we<~v_dgn~1}%<8C! z_1%yjz2dkHXAy4qfLZG_ zUqytcX5U(bPG~!pIcZb~qgW}+$WEEe2IZWo%k_rHqI+-5N7H@z`EexpJm6@+@Ua+N zN?(2gBDaZoXpzg;q1K{9t=(=?H(3@w%~rNwRNtLE$Lt3`0N)Kf2pBp~fJ^CXUs%0D z^zgmMRkO9I*?JE{yK3egDOS11YN5h8Ii{QVVZNOk!G{B*04cIA_8nJ}@%-;dZm||^ z!K|)EGG($wlcm-k>u76lOm8dCHuby?{CeOU2hi)ge#dPPckSLaoMkPVW$hq~`2-y@ zT~`ye=e`5z{2lxsz`qWl(|3Pu?jR(&9D72ehOBjL*4nLPD2Amee*T=@`Ssvb@Y8?| zfG{ELwi8@RYael>HXsj%j)cJ%8{G1?M?_Rr$I<=Ri?sD)rW)Zv^dL^0#4qP=j`=c+ zIj>m7VXvjh{GmfnyyF?dXXfWmbN{&h&^PPnhu}#z=0ZS<@Yk39Tg=y%9_M(c?sVjf zRX{P|TE`-|eUiz8bv?2(&Rke7xdg}6#TlX`csf@RrsWmkcTVLXfAmpw}Rl9Y?HH8(px{Sc$fM0bp z;?E*6&hI%Oj#_hl)V^~N*_-w~8T@o$BVg)tF}Rez_NP_Y|8Cv14&NcF+J-2B<#K&Ifn09>&`~%=a!0-_~82!Fk zCpX9Pc5}W6`H;jk4*Sy0{7YWshFxxdPGHGv@x=%gFO&Mem?*&%tjp!xRoMLf%?x$yPsBt~g zRHcK03lw{1wcY4w*};$0EA^Gc_zlTfdj>`P?S#JJ?{@H?0eb<%U)4hqe{14%SZ{q7 z`Kqunl8t-7j-o5=tBTZ)qMGpa3KhO(!dL$)?$xayIo5WhTuF~8rDtcJb!M zs6K1pw~i`?_h0Y}fNg-O&#mB6jNL`=bFb8A%T|e-S>Eb*gnef++5IB7o!CXXKQ-VtQ+Mo>?Ex2frG)7BKYg1DDd*`oMfx zBqrYLXD!>jOj@B!ot-z7l_ZO;Kh@SP>=QY(gE-N1{}_X9T%c0&6Pc01URVn8G-kAP}@$;p={vL9{0Y!kJUjr`1)YH71`V!7Qc6S>i-9O)Y54zYQ zV1E)0fX2AObtB^OA3rY~|KR5V=L3e`Ht^4)w`GH&=vl3vbs>(%ICObdQ~dlV`Fk_I zUI+gz@O!{K|9x;NQ~QWlvT5yVS2icJ;`eQtG2Gd2Y^UHL;;!TOyyKD zkZ7TW_3nUvI-4Bh(YCi~=V;CmBcpcR106GtegXbl;BCP0p&yC(=xd*e_}CO1+Bv(_ z=1?UyjaRFcbJ7E-Ob0TZUFH?Loj4KVp^Z&C9noCd~5}m z(${&0`5m=~)2%kM*>j~hNkv}tTaZ)^NKspnxgx){FiSl8&fT33iF2&F>?}pyy zH6%ASYd$gT8K%<-O~XxEhUXYW&Ad_e#q?Tvo|%`YgKq`S0}Q z4|_vAOp3fB&L(bkH7m$${fwBv3<&8rkBj^NiHIL*pE~d{z<9v$yEgvbw2OJ~X&>y( zL!LL0fAs%j>`VaTs;b8S-hJ=Qo0&{zCYdCYwON~{d%Cxj(v+4i(9%Fl*=m}$Nf&6F zkfu;jAnb@N5d@2D5!pqkfPA0`6;V-?7W5NjtvmAZ{jJNV6;c1c^WMFgHW2idlXo&h z-Z^)__pE`usGpP@TwnU_@9;=?MgipL?#OO-90_z_X*99@cTUYkAa^8hTnJe_vRcq^!zSeIbn*7 zp4Q{gX=azxq32uga#{==lC_4yn;oF5o7V(OU#F!!5P#7D*ZxyL}?n0LJvWlkNnRbR0t#xX;GbZ59 zvifF)^|8L6+dnhlwZKTg)Mqug6q9cy{pjKK5mlL~kiTEusNPoge)Sqjt^ev;`<*Of zQ2aS0&T-S^#cB#+U9k>yZnSN3^o(w3h%p=p(lG;GiPw`K11#$v6>oIf$;q?Co?thG z93L6-yIb=U^gH-o;AOz@`x5^FdZ*r4a>aFQE{UB@y zp*shB0k8-#beHSz4L$Sx5Zw*p5IIQn>7hjXG`(HC&zx(%0{$)FJAk2=dLiV;GIptY zycv2ypY(M0?&uMEtRRmCD@f>9hi{s7+OL)ME3}3(_%#ldpB}6SL2e4&WHg!AoQOLk2nscmAlszfOr^zNY^s_U9qHBBW8DqTNs&dIEcsBE zmXPn#ALjTT4?YW+0~o$f2bVJ3{bUH!%{SO62v6sZa$3K#?j#IMVU&EHEZkaFoVh=DcHR@E-s#0*0TxKMMJ|>ucfs-1pq!^K@gE8Spsc zKChi|^TZkVv|psGrwLJqn^+0K`4hxmPBx1Zw8|o}AP*3BpJH0+a`P`2L%9mlQk~&_ zg3m9v37Z-SCONO4L+noZVxHszCXdw_-h41Oz>bL*63`pDT57Ip5pUlt9;dtxR}uM_ zINfWjj1&{rlYJqIwIa(O!KN_Y%GhGU#S)lJ9_Ou!=M~}upT(_xXI`xFB zNqHC^v-L$n=Dciu;2Kk*pY_P7Xm9grO2&Ofnf`x7|8P*b6XIEWs&|X6zHN)v=Lq`< zrz=wCOmfQXBa`!ydTmjq-s1ctlji~RQ+miO3Hztz#a#cK0KO798IU6K)sH#%Bd6)+ ze_|}>Sx*qwIwF6Q*6-cLJIuZA%is?IUp?f#4a4|cY|eqad4+Y_3hOQGVKLH) z67EFgoGK$!*rzlda!Urk%lcLcUJo<^W_(T1-Z@5{nyfz} zJ;FQ5vdVONdTT(_+sXUPy6|c6e&7bc(7PL4iqXGY7aTsGI|j$IOZFUy^;#c9Gn^?z z-98#IIaUy&zBxuo>seOKv0*&!=xhY<0=5H&&K2MvMaQ(KA>}rIiIpR`iQO7Ys+H7> z-IP25fwi+`B{?B%=0)k_!usvwy{27%0sed7Pk^CY_)I9$yBR@|2F#dzXHi{?y|&ti&Gs;n45u@gRiZX;=8xv$*cc8D1f;!|yHnEgNC1 zv~h7H!OX2EO&uwd+>+7$k+MR@Nk^tq{J}I8Ntfgy-}6~jNnD08S3RvUHtvm_?0R{l zr5>lalMt^&IGOud$XOBqh@NBCj0vAE5%+2d+} z6MzviYH5_a@{+Rh5K$xLvU=NN2$amI0plaN}>;$hxA$kPbB<0tp9=-NQ*F%oUWFHHVy-; zLVljm^rSt$555ohF<|(4Q-5#T!8{LZkL|MWX2^9OwN{@%YON~fnHJ!W*Y|nrWL^KC zhV>JAv%p(``GBFfOn-0anCD^iwrx3--pe0FuU*sI#rw=U{$=pTfhPe&@B83VhLdXs z{k@L7askD;j5m>4tiI5C&2B&oUmpzuD@$KDsuQW}eoZ(1N{(&=_$*)!Fi02t-_kX5 zplthP4*mQ+>F{yDRO#@SJhC&@x+Re&ayGJF5olIcEq5V4d?;j{2pKJ=y5!3gvpEUq z=^-J=vcD2Bo`~xWs^Cm-8DvFb=O__>#@*5m(Y zIr>L{9}65082V>}|6BT-0x2)e@kZDj#X)o2!V2I_bel-%Ttidfe(FnOuoBU6d6+YB zqjSi?AXlT`+A1)cB>!E=*BrPNJGJg*wp3Z>#5DD3ZIhl}qx=8$Tz!uOUjQry4BZpKr3|ZQkV|~$28_a`y3LnL zO6%44V4qEG&kAc>i;`}<*?IS9x&!*XvhF?v{vF`^fT277jgamh9e2D}>%&buZ`Daa z2JAQ8K&^6P7=~h@grR7AJra0<5j#4OmmrvMdW%~|F4=f|r0cm;7<`g*T%a(DXpMC< z&56=;OA^6vg&2Hd(-c9SKP#fD(^Wxm5dw@5D=d~Su3!w4yJ{BgxfF*P`)Mv+_;`i= zS+hQD*PWVwso! z+qNdA%psTC{hCfI?`h^uLZ=;k3(yT1I=6!dMaN&-JtY5~$Z2}ykeF?KP$8H;V>y+7 z!m%zzv)_PVgo9e75i$A%24_Mw(;V?Uk{cu2LU@FGwFpM2{7DFxRh3(8x8Ob|jWMtx zY=;BTZ_@ll-o^$DNCSqya&Rdv!}zU*{N)ak-7C8o6ML$cF)1d`%{5x9me*F^g?y;pgk*%$sF z_y_X-{W*H4fJln~9gcqoYd}X!n5qWAFF2eZYQ4S#5iw)*ctj z>OfGHc8?+xS-Dz-Ur!Q~)_xnS=9KSq%Ro*Q^V2c67%@mK5^!Q1MW(4jar5N=!7Y(4 z^ZgBsXF_ax*V+*{KGpr3?Y7%%?Vs6pMYN10^q;p008kcii@(5`VS7FS|E7K~g1-Um z2TXge{driwEnf}gCI|J?)UT(Le8)tq*7fuI)DOIWNtX0}$7=gU)VdmDDiPhAe+c*@ z8>PqWWFN-{yr@^jWUkMzT=G!R!{ya_(voc6=_mMc$O8a<6XiQH`=G#v+NPh{XxZ= zyLCHIPqQCB5B>u1qOQBFpIe5Jk8RkoZGB*XTVu7=SbxDj##2T7|E>DHrN79v?-=k& zz*NAr?~&kAhC6?+Tibzmhz_hNNAI?|ffei!b)nU->0QbDOn=@2ekX7@VCa1X{6C>5 zt~sH00fLuvsTx9XpQd+Ezfabw^e>5l1C#@XULCj;bD!NZ#Qu%?^>l97(z(9Z)Uta; z7q#4KT?^4AvMnrft7Vf2OUqede|78k3f(KguLG_J4Bap2@6Gyao@U%iyRsAn1{)h$ zXq8K%X*Rzjt=l6>w?Tw{<3-lkr|Iq2?-P3e0C#_7TRvdurNE^aI_CM2^svw%WX7RH zcOOQS_w3PhPtorcx|_kb0cQb*?m7B68JBG-vEYA<*&o~4R`)!h;Cfl(E*+8ZY(Sx7O(6pan5Gf+3#Afa+4}2 z`P^bQ-Av3cXR%GCRdpohIgxQ}z_DUUHHvyNx}boSz`no_l5~wxH`?kpWp59yuY}*$ zUfutiA8D6Mz^?;t01UtXt-m+p?nClG*@d+pKHI%dA)q`O`DEK;j&(cn6_X@w;Di?Z z<5n5|V+AQPpUQ?w0*M4CxG1 z*{aS7=@01lOM86{d=Ky(VCcWBzc=H@Jk2-?f;(?DX0+LsQAkcVA~-)>moGu zmWJ+nbJfP&xv77ruK#ZjsXzG9z(T;#zZhJ~aN`ToTeo&?Gd&gx<8G9=B5mJwtX)Ks z#C?Q>un~gnrg0x+BLMgp9}`VV_>PFg#l~Ym)W*e0*-J)FjgZ$DFLd<)2XcFHz;ye0 zA;0_J$Lt4hgZ~fkd%*Bp^-jp|Vx7NpXn&bgMz-~!M2A@>$FJX_DTUD#Y3q~Ze#3@W zrO0DDP8DHxQO30y9~RE`%+Cy&YUTJfOSSU#nG&T%H|f4lhWvFy-^|yGz^?}S0mI*e z;8KR$S2nH}qYxQOndVNe@rj8rcpZKdu`1e6S}~5m*v`R^d&9(s+0?nEJ9Lk2zenV~qh*AVapSd6 zIlxhjv4XC|NqVsfNLnKjT+mIUhl~~@Um)FeoKS-mu|UdjgiA7xnL(5FT@dou^lnIB z=3xu?Vqhs?_&Y;?Z|0wQnt3R82j_M6ZjwBwTRLR9ZN5(Kz-?cp?~wf`2~N*2N=kyg zL@Gnbf5~HkcLJ#w)e6&loL4Ul`PmIUbDsVV`18OEng==e3@5Lb@ts?b(pFpAdM(b2 zTJ?L=|C4*~c<@=k9Kh6bEw~hOPB-hcsptB&+c)%dZC$fS5)!y#!5eyUexv z@@h+ih-?uOq4*@kWa>D0r`LGJ;V&|1H>)q%82|C32BARvMY`V5H}m@k;6DXk0}Oxf zflC=qKLCHdT^olmx0s=Ovn|YBqO8aAYDrRwz9>S@a63;tINM#5PSxtZIOJpId%1R6 z3Vs^U1{glR2`*)~_WNtsaZwIwr(8E+cKQ^1E?e(sxm~>MS#RXA#HdCBo)RC&C+I}P zt0k&*c`QOovIhKjZHY&bSD&eLB2FzQZxk5m@p&WCkyw3<)I#aX7z!dH*jIX`X+*tT zkeA<$nyxTD7Kdc}HGGa5qnWF_;eOHEj?1YY)zt@7_4BQ47J{|^_GTc046nC%O z)Je({y_)pEOR?~BKNmrGDMM$%SqG6o5Yc8DQQjNiq50Dx{e$}bvYw@W&-xFH01W+R za4BXTGfy*q1HJ5F3~YpfB4OY*B9Fm}EXmEkvFza55~y#ggJ%v>3<9tm<17fKFg78(g* zmc+!c5?z5DV-=TK;_cx0n=B}<40R3|K_%m}{3B!B$Rp)RNf)<7orqn^3I2(s2qv+R zGa^=%7(sqbbjoPWe2IZaxQ{CQ-@Ig#Y?Okt#rB++1wJ$C9 z0@9S%=<$EZdsBbF?+K^@OuJtUF2%I_>LKx959{|s8@~H8hqL(QVl2@16>biMyi9WN z7V|P>Rz%fGx^aHT0lk2GgzHU?P4W=lCe-Hc-F!fCS zF|4N<*XB9cjzL8kQEtuVYL@nG)@w{>tQ85%E@~>5WvPIJATwR=oNET{TQvPs^!tVW zX7C-rxqzYnr2gLQpF{6CTLb!&WJtICz~<2YNjbE061|u(l1Vq6Op)D;`%SdiEsw?` zNSMm}8bmGJCCHnK-UR7VTxDpy3_3Jy8%UQhGKk8t#J$S4%hgCy{2hU!73QU+KO44N z`cJv_u?~C+Fat1r{}o)yer!Rd(SGwz`Tm*c|OrdQK+1@p;Vl*b;xH zSD`9B$+9%xU(5`x;LJ{daXwQ%u`QGM*x*!H=6mH047$8v&Te-9V!MA=?i^<=sd+M9 zWu(%tj|RR~LA$iv7`Edne-7J8`oA0eQ$QbJ+VOV%y%~4rX~rMV6>B$iwu)woM3D@G znoDeS_7&Bf8NbDPKt#r(XsOH`Hdo|pRD%{|M4&adtkcPb5%g^OrjVa^pl8la2f@An z!v`2J{44{P(yjB0bn867h9Bevcn1j|pTFNW!Q_qpd9` z(*ZZ5NQ&@B9*62=5$%g5NZdiQ!c{JwK~(K0N04St*ll;Gs@*oGRM!!(CfF%!c7=Qo zz?a#t9|nIC_$FZZ{w=ta;qC=;PZ74=(4l%BJA$&_D`wo4WJGm;!jxCmUzaQ2;I z@)LBljKStxZ4OD(X;9nxZYgf71i{2d9x<9ey3#&L#kSLZ-?&uw9Q?ST(7PyQSH4d89fo17O+90em+F!MUp02XSjRW zrZE3ix2#>wi^*H6aD=fUp;?gmW#AJyNRbAoxAc`P9t zr1F{Oqo`&~RQ2nvw<@aKGInAjSxXAJ`C$lRnWokOP1pKI*semi7`zr32^hL3=X9;oEV zf>Cn}nW;$JlEkPXSF#)dQVeTZX-;;>t7CI=g!cPFzGnV2q$};V1pFl6RKW0ciT-}L zcH6lAkd;SRS}ZKxpsbezmXa)kJ~Kxw41!Tf*hbm8INh^JRD=EJ+`%1Ri$koM zFYECSUxx47!CwJh2MpgQOYj)Vtxtse%6s~0#y^qWJHWTCUAIM;$I0a_{|<%O^G%_z z%N=&`+uh-BFNeQf6+T7;U$u%eOxq(F>(wfpVUo<=;8>mJs!_=TP*oYBu6d{BXDdt6 z*iR(wH>q%`x16)~Mt`SwoPQ#Jx58h=UzK~=80$FH zZ??T#?Yx^+>Plh;RgA45t-GvvBU9{g-?Za**@dMj?K85j5i~H;n5buB)9lzqws*0eIwF6DpQy3@YwY-?sPoBpve|1dU7WwYwA?FB=eQh8s|EXL zyu{1Y6jbLY*Lf%9$Fl8eBci*LqWNAm)9p0(2;z}PPVhglqbK^Cl8aSoDoKL2Oru(t zD9xK=uP>RF$wZG;{kDIvaxS&q2KQ`d3L^5>V3O{CEF4d-GG5HO@h9k-~U!*S5 zHb{HE7V<-yvw)tg7Z-wG1zZc5@r^1g_}=hgo@RU_cO*hU?o5zvUI{aECNg9nwXK0# z)-i%c`&`7_1gRK^c!Wt5u39wd7BWlm2ut7NAwLJ9XW9qPTdNGH0t`QEz@-?y<~u{~ zgPXUVf$o2!NrTh*y-fAz~}`<7Zrz&FD7*h78Iz5b`*Zvy)P(;n}FOF3m2doHmy3-17H#9Jc61%RW&JnPPSIqU`r zXB*w3oE^sjO?Rf38$XM|PXbN_4BcD6r3@D*Qt0X|gSUx!_=|y+-!-oFP`&g*ilkuE z-D2F><7H&QP@`n^?R5aY%(&-1ZIN)rDh3SS)4-(+ch1}x+5s-v+AVe<+2(_C!aPc*A&&XK zfOkZm!aMuqGU@fe1F0BwPSCGo)XNg$klEP&Ovq0k^b9{YfZq;$5itCG75qQoCuqt{ z%{U}PK3*Md$6FUS$o|0H7Psoak$sYjv8LGN1ZB6TZ;=Ad&@TqB0qOxme+syi;oAcb zUCCVhVGjB~mV-UI{`&ngpFazJD{u#3=s&E#H|wE!nst%5Lm0q{oHSE2!PLIh8fd8E zRKl5FYM)P~r>K&k?yZ{cLEdZX9g8Zf1Rx~bAl(6QDZ`E5kZ!Y#fz}6H?oAIma&bE7 zTaP!$0IpIqYP@PhlX%V6sIhWH;NNtxnm9N@#)7OW^<6GUEPo91yyGw*D2%h5cph%9 zi1JdNIMO0J37$nHERf$z(07p%kF1(y{Ej?DK8>>jd({O%79g;uSYQ3t!Hv~^G7K%& z`kWsB)XSW+{wej1DT}-9V7)Q%3FbOhwG7qMm6kyxp; z_kgC?&if3#o#2-MR{*Aee+DjPslK1C)bUbH|1!A5G@tNa+Rn^ve_yd){0K3{4_)iP zNaVCgbr47)gpy=(rJRf~P>Q6|$#_koh=xybU(1{09mQ#i(5^HVcec`mU(3%(oO2E~ z8`(6XRIdteW;Ee$7iTW}S>cd-(s#plYl`Q_%TeIR0E+=rkCot3hC5FTtwr;!iPYdI z>p)}RvaC{(iW7 z&td#*Tz}5mzid1VfLoq$iTbx`3h{I1A*SO+* z354B?RV%`PMTErIVh#KttPY2XWh#em`Gc5o@T>UlfV|3X&h zLnd$QR}^dITOw>a9eWAax~C~MM{x1L(wNMx$>InCI5~AOfsrz!G>xt( zBfoYrTEJ4bl#s}U#3PKdo^q}vm|_9Kn~MB&gb{IiWQ~2bZLd&|1lHKdS$-7O=K%bg z@xk5Hssd^OQ=jGFQj9)f*O2&_hty{SrX(^tx^J>MMxF#@fN@>S>qnIJ9OenJNMUj^ zxsF7%nP^Pad#V_*coDHG*>b$pL@vn%L82AHwAgO7J&$wiiy@!8G#@e!o&x_a@B_f` z`3wEMnP*Ff#8(@_=NjyOLW}keVY&5U>4Aw>+v6m|7()*riZ7PyUP*?0#?{2&VH`YQ zy9ujrZ^%zmD%Wm{z*hmM0fwJG@I%{es6KNjKi!)3|e*|;e*2tJ3uwBtE}fu<;CGWHxo*#`?i%f67$eehxW_c!2w0{#jZK4+vu zKJU}^IIh-r4bGq3cnvrAV61*G&~|;#vEGL{+1%xPC+c8)57Mzb#5AO%4KznF3CP4n zP<|E!YbnO>UZfS}O>qiN7rEzP2hV06$#a_3xr2hG^vfat{qSe@%iF>42fhLr{=Ww< z#q5_ehr|`%x^~M(dN|vC1Y>b?7ft#d*3)sA@v3NH3gcbEwlbYi-C#}$KjYMBbUNb) z`Pi@dC@skGF&ca_FdZ;_91kwV#IJgA$oNCvpNn4APwbgMxAoY#4CF#klpuaSili0qY+-Um}6@m)=YiMoXf3Zb3R#N5o2&oLN8xOMIak+v3f2 z&-aKsn@EwpQ&u0zzLST@yC90V#;wt&pygr;nqTauCdLx+iUfaF0AvAgVq(b5c|1p2-xQ40#<$zmK=E8!hu12UtO5Ner3d@RRU zdx+UfhV?y8&=u^w^1O<2{!)TROjda)S=mRk+G_kZTiwn&=&Wa398Fy#fh%k<&IVo& z>$#hHn0h_~{sOQUF!h{Nq{pR}R~$LSZfN5MA}t0Jll3 z63-HX26^pe5*DM4K$`DOlyy|5dIGn0(@z=cCyu~}_7m=Ox}Pw4hz9lpsQHDjngr90%8%t+ppo zST`pbQUupTU82NrOx&Jsw&{~Zzyv>9_lJBuq3H-8`@mlV-U19C@9XdPXgSd0A#$Kl z=5Z(=t?L>0m#|J@LHYrVpa4Y-dl)msW}r2`3PU803*(`-{5<4maY?RS)`On`Yy}KI zJM{PFyk?$e-@&gXWT|UApNgjBA+Q86be8Gw&HK%BkPfB=ojrKZ z%#VH#>L9!d?nB290XexKCqZtw?zhXF(HQT@H4W1fTbg4A|lFk)(a&lG^y0gZs66V64pIu9{H1gj5KaHH+rWS7cEs8>;|rDK>YMMmR&hgv#<(f`<3BtFWYh{oY~ zZ-Lj= zJR7_ZxD+t$`+)x5^q+YSY2V|!wk_(C)q;yZw|{OhKO;8pRGFpNO3vthP2cT!x+h{qmKcEaS{LBWIV$T0V<3{TK4)_WD2Z_~x zcWBWt&1!oa!y92LGTEtgqfvT{EE^mQ>87|ZCJmK-jNI!Soi(T! z=zlkCpL9izj|T8*z%0PRn7{N2E9s$BGKGB>C(@Ddx77!>%V8TioN`~c z{nrq8C7g(SQd#8sH!J@OjGt^4A##L-;ZeWBeZ}_QvmIn_M3;+rQB~%TBJv1U=yFk$ z8^2gJ<#7h&|G?u{%};WHW{bD6ZMwwvHgSlHv__Kk1g@U!pB0_!UrJEFVhLI|9{q9$ zAC-6~`KyT9IhvP8+*)r$MYM3FTkeuB120s}=)|UK4g+|$&B-!?53uq};>bMQJYT59 z-F!^yN(pq5l1Ns5zLy{9dD_)=ZuDs#+cE2G~ zo<_z-o5qVB?2u#bJ$OPOwWQfZQ2K;TpX*Z&c18aewhKwp2KgETJ{y<|7``@v2SwY# zcHeRM{X_d#OS@o`{%9C<;&-7P?9-%Mm?ihf30ND}A*Yt1B?Bv!hrWP;rSb@Ri}p^~ z+iSaZ#6%iJaEwv0T&BprzlMD7fe+JuuYmso_%&eo{5!am;pCE=x2>0(cxWLpv=bkh zC6Yl@irTyst$rvM%ms)!p!rx_9nz6?{&eu2z^4Gi$NT#GJ^DO$Q0E~x>qg+G*b$z4 zXs}x&f#L9*G?+bL$IMR_wB0f5`B}Bm5r}siutbU^(j3Q_ugJ?Ke%h2N-c;A|;>d#H zQD$ZyYII*L&K1Vu71;z|7XVp+V{d~j8gij2RVVP%i;N{EnOtt-T*xZC(weNQm{>9C zcK+1oT+Et9k6dM|bJeN#ZOUEcykb(p415swM{7;49ooUq0JZ_99lC16?}s}d4~l46 zJHHn$n(sud14q=xlf<6)ciG-&S;H7DSJ@7k%%dL53s&IXHGGN;Eh2X^xy&ZT)1Esi z1|)8A2Jz{5RY}5cKFuHNAvkk4cqenUnaHyfm?*9h1jlPACQF~!cdx8j3)MwjQV1BJ7qGN_ zOfatZ(4J=B+z0+D@CIPo`+~Z#y-gm1q4yC&6U5p!0Xrrsi`VEuH{PN;@G;1Y}LJocw6Q_h$Q; z!1z<0IkA}xw1_ufEnoso!5yUB8x{O4iMf$^{sIZj8K2{1yi-c%^1h7MR#END_Ey(d zW9-Qrl>7}5kg%y;m)uBmu$$@BB z(+)kuPcQgqfa?Im&yt3a9}|b8eMlURKwlpuKc$bV_o>~(0HZO7^UTUfTugNM$FR(MC(M_ik}&-;^I5UupYjb)-j2mCjiAY@KQ zq(xn3`;X(W?gN)H+&;NA6z^oxOH%0fJFFkhtw1Cg zI7BJTG%ahn%aVcKDIL-)9htK$7!N)Rm;)Gk=YmUFspY6c?d~>i=~~CyewLQDwEsWZ znWu>F`*R4gTiE>wmg3?qK?0FQu47?RbExsJz&A7?3vr)qryjrx9pmyvDy zE!#a>l^cO&UqQ(4^YCNZ=QZ$O1HS_dzkdgpGFO3~W$S7}9TP%+Ws){3PHMK#KevZvPGFhK)4dY8!7oG!J(j&VG1I z1%KPB-#@^+%sTfd_~XEnhrEASe_#4Q)bkS1b%xb8!}{So565i6C!sV^Q3TbY00E7aV@wMlgI8u>nZfKB(Zz9=tV{VF(59Iw#&Ex9^Dj=AZr`T<`o~| z<>$dmBHngRz;djElT%HAnuyR3e}^kO|v)H}q@xM9vxC0e>BM8!-G8H--FN zs`XKOUL0~R3;Ej~X2+=8m;R^Po3{6*X9Pd%_NIkP*ZS_!lgXJNF6;?xC`Q_mNJ*qT zk9d#F1NYRT?cC1uL!Ub7t3M zT`mdvItbkw=t?`rM=PrWs0IvQCxc5#3==;m;HzitI@vkfuaL=ojr=GO*1k`A$N9A! zS4i?8j2sz_#Fi1nhfNi0RwoiIIYF&Vo{SBtTTqfnPMQ>-ndJgjI3H#)^8ci)eh0E4 zp9Anw10TZYqu}2Lz6TgSe+w?fy*%t^bG|g^O5qa$R}i%&8}c|BJ`06UT(qB9fE_kQ z8ImU>OH)dJ6Id6Eer)>W_qqh)j=3 zlE*g{NV>S)JBUX&Qq6su{wDo?so(kFmjYJ+hW>T>ds9F2JdA!vmmyzMT@Bd=>-L4R z>(fs-Bn13hIl*OTMV-eX_MgSFx*cC&@GEZ7nYyG%_c)qv+j<8kjoCnkH;Vk|+`v3Tx*OKGVH z`Rj(h;qQF#KHw6~lW;b)AIx~(xV{56s;#za>#9YlQBblV*u$Pozjq(+Fzd~4!2bfg z514xY6I@E`kT@DzM?V-`P-kT_n|Q-=(ZA0BXZ+L{MI2YK4BiGOX9)@wxf& z3GjAcJs?GXet3QahCLG&k?(QsMk6@Nx7zcqo_zlQe*ND2c!#Oili=S6egv3$y#y|0 zXuS@Jm#Fh0engdaez;1ztHSz}PRP|~Ja{uO1(5Pl^%?A^uHewRZfy|pd6TtnleH8* zHbN}1V8Q7;$?ognH10(4k9Sluc%x<2j0oxOf`%C%_ke#D_!?m9`(1D;MYJ=*Ssk-g2a`&12|31Xuu|di`uu(o_1l}TK6qQ=Fr;cX&jk38!KwyY(2oGuEusuy^Ew17)z0haoHB8xX#Ue+&9N9xG2 zozE2mkAlcViDgBmTP%y=Kk&v1JkkOT$$t=<|5&#a5l5-|FXg`&p4I&7bs$+`BK3BCka2AKBwhW`Fl-9Fs|ho3jGbKXvZq;)$so*m{8nB;evNs3jkB^$HAox6Q5*aP~{0LI(t|45c5|rgW2}uID0+r zuA$mr@~l0PS~n#Q*CX;2r$VmJajpZZY7*A1YNV@1ItuMqy=YLxja-0F6+T)5aXV5t zTkK=2mq%BKU2HWD(_ASJ2T5V%+f|WxA}&?`x$WNQ*g<6NfPL~P>Ul6Vcg`#TF9NcF z6#4nad11c}U1xeXZzUd`_Zje8fI9%wz7^9#+It=f=@xxckE<}~;)LFFyF1BBex^hMtKR4Q+28Bf`8D+cg^>U*RGT=XIEZw~gFw9hs1rrzTqtH$?hFS{ zt?(0~aHHU03Wom&ItTgx_+*Cpgee&%J5LK%bUf`6Op!^tEK_HqYKHU;PJErc(cX%B zj0PtZWU!RBOby$6C-pP?c|Z8)fiD22{&#{)`A{4uU4IT_U0crXJbvxg&gC0u8kK38 zGB;|iJKlQVCjqQ%X%pPCP}d;u>DP1*@LoeVI$c>Qpb#*0%fY4m8@elL{vmWP$L#;Z zboXnzn|QCG+XsFHa1~(aUJw4C(8W`G2;J*Hl5X>~u$}kwUUQE4E4V*{b1-1&E&`Wg z;#3XFadbPc?dUi$L_@MfD(@mlL%;o=lB|B~@Dv^(HXh-p2-!cLq<)CER3Xtv5NRTM zpNW~HpB{rD4I@ZuNwH0`Eft^ zgTTX@*MQ?;?xjs*HcHg}?p_Y<>(|QcsI)pN33IPAl(*{lA3Ws!$(h*x10w*_E(^e= z4403Ze(2oR5vF8@NVa>g2s=vH#yhS+I)ig@0^MCfsp}10BgeWQd^hkYVEB3pT*^>6)?xP~35FC}d&KrO zkZ9Br|7ax}KtON?2kk5e?G2l)Ysu`9L}?KBWX)wMIuhTTtgK1aZcTqD?>F?X2LBRp zFJR~|nH|#ayEk0-58R{I{~g<8%bBqK&@RsIvv2YO1NFy4JN1ga%%u%i#e&o-C}HCj zMXb{7jTo$vabjGw7F~1^r$={;H?M3&k(;RX>oRUd^3*B*)RPI5n4RG_5>_ssU^{i9 z#*KUBu3wN$Am}Rds{H8$CXwBM|9g^tvU3E#SMsa^>hO8O19)t#P<-J?REpRgv-cA6 z!KG0^CB1s2sd7VJL^cS*zxnaz>R-hFb|fw37bd~RiE6TF z5X0+He>Qm#D;*pDU(@u{%f}t00CgjFf3|y?TES}BsJ>}?zf_SjiI+n;I&7CGsJ9tM zd%<4@{#&<&w8(IBVTsOo=nxujZ5VI;lXV=mR|Fq(#D@gQWIfh&n&#x%eu%EjI+gs}M)+2Fo~fUm!MEG^e49#-r4N>=d(!F?!QxH5_a7JX*9v{J&z}W;K5!9W z_X?YJcxHq=7pbE-HOuddVEJjAYi>Av(#t}At+}~N z600KM*V5~cH6+g{+=_$AmLPiyI_o`=z~1L|H+a+sKZz@d2@nzg__^-)gnc>V&3x+! zu_Uf{(}Xn`ailw=s)3*)@deQ|XXcEmc9Scd)mZzV?yp`R$7gbOI_lS>HE?Z|b^IZk z19V046xrM)6y)pz3}%|6aV+C*w`18jreF2gjb3YK<562VWoq0Fwzo@yW|H$Uov5zx z-Q&rY=A9I8lSMjOMSKE3Iybg3mX9CQwAfMHzZ|T3iRmlW0A=I7$#}}tCLOQETf`Yg z=HR1t1cTmE`)bGTKx=2uQ#QxmaI6ceR3w>7akY=;adGjTyvBHK6py_sEb9q?#T|}l6UA6N;RnnH zG$N+v)&^Qu?)iRVLbX>@B#D!3c?Z@}anG`Du-(0S@X|i3!uB};pJx4tAI%*Pr~pho z=7CEYx{jH43IxIHyLTYU->_Ma`aXMyY$K}?bZsF#-WzNqn5M{W+|5WRNv^dq%rY<^ z;|hx{njeIV+lU>To{Z3IJ~`yCU(=WV`y%**z{7yy@0cOn z;7P1=vC{PWoZq?sQg)y70~I_Pf}bgVT3i0$Tm8;tH66WLtdu+Z$Y_I@sFzmKX13gy z#hX(c=|o)Wl|@ImbG;UFf31&p`1RgQH&(#1A<<)EYKfa3MHIw*{r|dN#avZMq$0P> zE9WofM2|w5T1LX+Q@k@9p;01gRmAdyk<74Zu3}4dzhrYIP7+0u^}#+rer!-n+U4}H zKWY|)^_Kpa41Ofg0+@E`*Wd5a@}H-M*fmLim<7Dw{;nsNrY*nqu#b@S4|fx)QHywI z6+52i`gsWP7~3fHNNwX08GW5okx%p)z{W8LTupCVxNk}JAF;ulv zr`CZk4x$D0wT1O~2R_ZX{}(tH6DtOodQ^c+8E)KnZ0=l0T;~;o84yJIV{K`-E=Iso zEUPdAZT`usY*{1J(YhV?Yx zxteDenBCj5YTCngN-xaycQtq;Fd8s?PSM|+d1szx{;ls>yM0rzR9DMVeS~#=q^g`Y zsR(9WxK>L&+cmvD-e>yd^We7wcLIjqgWytz>z8d^VVA7v4K)qf<_kGXZ5bf4ykDzM zBd#{}tyMb)SDLk9JrD9;LpQYu|97AqFmxNhKaMW_aC}$q@@*fcd+SHi9nf^Ud9N7< zmw;alTn8AscYsS7POow35OAC2&Q)e@Imvp6m>h_NF=>c<#D%b|Lacw9l z)=yw3KazD*<%N+L{$)Wd4LizNryi34elvn)~pi$FE*WVO@U zy*}i70KQB=Jp%qD@DyP9ehys9aOd5vFs^;}-IkeiVQ-H0JpPI!WtvWKwbGPzUDHc1 z$F>=vGfy+$AQ!kf2gIfdv02t%Acm2-gkBr0U$>@rfcKg9bdN<34x|A? zuL=C)>bGNCKn}7(v9$}IA)h2e)>Vi>W2)(9<$Zxes%R_9!vk8UDv|dc(Db|Y`=!2@ zgI@#m1BU*s`g>DP^ECC{DhH_*!6FzWfk>BQ&$VS5`5*9q;2)YRao)krE2xIm+^NUE zey`9ay}U(GYpW12bSHyLF?z&bU3B>VehA&cDKF8UCFl?9%}ZqJ4KgiMu!%DXQDT*1 z(GxH5NbyNhS&_Z3cF)YMw`l}YQu;Jq;p=AbyMg-w!`Dmtd(#f)`4R20Z0+_iaoT<2 z+?-qvTZDLf3${u)jg_mqzbWs1bU_|DCS$l`cnLqSv<_(gYL^=rfJAqY6HxFEw*t0Ehxte- zeLj)u1f_XXNWXMhZk~(>p9;(XOudf*mtxkPq4f@V*sgaaw|&zZ*w|{lgSGWUt}JLA zWP-L0E1g@qWvi@fY?_hcf~&qA=?eP+nd ze(1G8Px$#0czii?A29s93@&AlmY4Mp(O+)t={m>ogCq5?oqyRRiF+jyJeK@RxcYLQ zb&uUpSX7k2WUhF;Gu2aBtY71i<;O)Xww*FW6gbj&wWBzUjZ~@g)ulEjR|LW&#zSIq zswVB%){ah$hw#BpA0JTjKM99Nb&`YIHAewqMTgP$lu2{MB@ zEsxFkMR|a?##x6Zi<5I?f|KXeM#`NsoO%YoRqf^El^~sLnOEoJMO~hgisMuLC9*#K zNU4+D&)d$J$S2fv?`khv%{9N~tgszxTEljdcANq}9hjv*lW)v8G*7cW1v5a_Y(`{< z)ze}9fVHUF7AvzFJ06j42ui=Eb0zOI9YL2Z6z5x^)jIc7q!w z0YJ|y#QtOpZe&u$xU0p2G=dU2G9DQ9OAvr4!RpWwarDW!eyT!L@?OP==;%OAxCw_y zj6VrqM85>3e|y*uyWz{U&-cK847>suzP%GezK65-5Bfv+mV`XQcFU{cHN6?9>7HLI z>+4P}u^mWyNZbj|XewP(INBdWTt_0(6Sds;M~@NR32Dv(KA*AOI(xP%!du-ix+CQC z6!>ViX5G_(TT8u2}h{F&zGR#g$Q**m43)*Rv66&&ibd@0xreuM`k}hY#s*fxn@25_6WP}-;x`ok2OLML5E(2 zRq>n|$pob}iOQWH=USUWASl6yGJ()$903Xfja|*okgt}Nx%GY}_?bW#VEFnMxRidg zz7Cb2$~-c2sCu`0+<92pyVVPB@HpXNcFCT9M6D~mi5zOlL!2&lYgs*#H5ptABt$&L ziH`6x#hkIyEW9{56nRJEmZ2Km)-#iZ9LV^~64yD}TSlDzr5q9$Axw+;ggwq+;mk=< z^pogki2vl0%dga{t;W}f{GHg=;6S@}y3F73eR&lX%u&NR04 ziKm9~Rl1zZc5_W38clolPYVfAMYKR*TYz|7SF`{$t}-FL$r zFVpXkVb&M1_D3XO6mCrf+)0+?Pei_iH3==_5V$c<^2+I^IVwIs9&bSOgd0+`njtw! z$erN%=?RJ{PqNlzIe`WFzuDoD?b4V8di1MiA)WE(&>UH+FKX*=OW0P-k+!*u*)M9n z3(fo=xG=2uDXVh#&2I3EfXe_=?`OfK?EYL>-|kxvulL%HGj?q6?G6)@%efH)tFNlS z!0K`yRQqSHbv#Z-m-_DT-g(PC8+i%wE)MxGJvrBJ=Z!IK}w{{}>Y zoiJa$NBvPfqwGEE%|!6XK7-z+=lZnuUhD{jlCfwsn!#kr;qHse^i{TderY;34x`?N z(U^LnsZ@n^(UD#wfmdp4R0hFLUA#E;KD8lnv#OX?kETdf93LI!ot(vED-$n@k5q|h zNo};Q_E>jbepde1{5SbAu{2XEwY|l5U$YYvoat(&+o&$Goo$gRILKaY`*YN{Y-f*M zD4(Xb*<%VPrJl1*1Jzs=womgZx%G1a_#)s~K#Kev?tC8ht4{5?-s)LzJ)PG~+@(fk z7fajr>-X$xRj5l)6uzs*m*K~TE1h?rNzmF_(oo>+klRxQU0MA z3hbg<)NSEj+xMBUe(6(l^=kwl4U7Y%{QLTCm$bq{cZ=1t#kw+4BD63>BE*M&|IS0+ ze=Ydufm;Amzx%zlxvmM zcXe2=cX)3Nzsou9eeiz>ozrslvWB@=Nqp(;8#isHPG?$#1>T(~5pxbi)G0Co;ka8A zL1}?^gB`x>fTq{ZyA8ebz^?#41DJZg1TN*d>%#f-s~ZlVM`G8Z>uTCG+x?W>ySaSR zp}$7`nII7}!BUWT+r)P8^V69`!6bE}m!H5Ai!)aEX_Dx~7}EJEyyRRG$fmXubR_y>%bK71;Ap!@c$IJl;Qlq)^~LiU?h}H)(!am z{vEzO;P12VU={7TCT2aJKbe3#K?L^5QAJUVgRo4lC`rYq;);>SJg=D$Er=%&`NM#h-rR=I9w2w;)lc(q$#3MB2;vQ<|b>_0fj% zXmklypHjP>>PcID-Nj~dF`~FCd$Xz&v9Oc_*X!}WIye4n!0UlVK#Kev?i}9JwPRa{ z9K!3Zo_gyym_sS9*o=yZ7yNC_4dMHD@-B0pxeELi;10mF>#k3PwC>XD>tlNl9~Z>8 z8f@16-n)^vJ$t|R=fbzCN6%-j03YN9JM(KQa=RVrbL=nLZnIrsH&Yo{&4Two*?P= z266Yvww}zLV3FJj_8@~R7>%i^!;w2~W3u8+BNmyAclW4ZQp=0K7}oC~bjdc^uv&+Kf=(OjagRQ#v}VnaaEE%dzOST7RbLn5x_7sm4>nS2le zjH3%7z@i1DU?9n~I2lJ`>A1=wpoteDp{ornVG!6c!m6mu81+4+wwn4JxHGKJ^O|4j zul?W$fIkDKJ}vEGeT-dx&5-;@a>QIAwON6>F4!@5+b^kyB`4=`56f}uY1k)uS(>A; zc-3RU?&KqNkqpJ@YE_4Fmr+Z~D@7u<%8ZS!j?-hx=6H=ULVUC+G>g$h`dFmv2wN}N z#QK=;OYWo^v;0`Q?+WX)OYxc$;z3+ zx~iT?fyi_)SjMD1Qj?EAY9q!OZhk>i3ghN-Bt9d(M37?U&vx_zbviB;+w}k$xHoLi zci?{}{7ZZO3p}z8{U>1RR|GC)K*up0dVf5$ezLr0x=-keTD@DWZB=Zro}|*lCQDYk z;5AnIzL0J^?_JDCLiZf-3xJCNL-%TMDW~ZD|KsRR3FxjAx?R@UA>BD4-9|&VPt$#s z_nxBZ{vP}H{nYDj&9NU=w|qYYi_{;<*k)Jx3i>+M=MK4KD6ww9O{A|NE!cZ)jK zEJs%B17SOy0zEU{wt=4uoDUd&ZUmRop!Eeq+o5MI`@8VbyR}2Br7HyPPl?_IX_ zB3?qp9QYheUmD3^U&o>uT;VpklMN?d4*A#*9n&s<2ak24^8ySXqrj#7MC&`7hs4R# zOmq#lk1*3`e<`rw8G9l8kWlm{RqIx%YR_@~#5mQ2A!Mn`awx4sE|2MUoneaemF8mXrVFLwQJp#tHdi(d!KR>-S-Q-OK~l9&oIOR4oTd!m6<= z%4MgNIPfmszJ6g*l{><-D>*qj;wVEj2K+==ox#O*MiFvA!aO1eA!RbIR{XVPUBQLg zoyb9doHHW0@(+9^Z0E%ra`jmcz8yFRF!lKwxRlT7dHy*)@637~w6E0Tknu+noBs;e zP(N5V*+Jh@6N{n+*o{O;lz}RXgtC!p)EW64Fqc-SnrO9ClaHjW2=kF?vEq2COYkKu zUVL}lMA#=?${hPH+g(UN5q_ogKOFKO-I%+lRDh2KCIW{4Mc`6)Yx|a=;{==g+`Q?> zJ2sF5P8K;}?;E!D2(tJ%x0HMzzcn&Kjmc|FcxAA#Ju=>wG26X6%$hi^3mwxVX=SCvUwBpGR$X z5d(64Zhq{3B;;oo^lG3d`^H1y-vqt|7=B&{m+~?E$Y>hmr_cUpFlFzuWzIh5SXZG* zD~+@TJYhEKmq!wL>z&|w^i$hCi42n$2v>cNh5R&a&c#Wb1-=AW1{i+Uf=h9A9REQ- z5^b-(u`6hvaF)vSB&<_wu&Q3o#1D+2d{@@hCfoOd<#d5+A;j|u`efAqwUCe9&@uM4 z&w{@U{1h;JybCU6wO-FY%tvmR4%pX(jMN2;kksevFv4t)jDnF7FhX`%IdGnWr)Yi1 zNcZC*A2ZL$_0MtOrvYt%;iDT|ikUCN@e!Qi`|b0B=~5>-5qqCufrpQHjtl9Ci8RL` z7mVBg3i;RrohInWIN1ySHtO&Oexa5pLcUIcuHowp@Uwtk!0`1ca4ByL zf8Od{yE!RMQA34I|fC z+uJ2FoqOO8_=1;=7m#%aZEp$JC&a2;Nl*o0`CsgeaYlO$E>5}JV7R2@rBXiGV;pRF z2r`zc;n|QY zW~fill`sU{7Sjrx%fBAd-N$>=yjR-c7vR4J-T@5VgWytz(>sZrYuk=M-?Y@~U20t! ziQ6iXWsk()R_>D1+^qclZcVRcYp$NBfUg180fycda4EytyUTr6cJggqA}OLL+}35w zZL9Z0>j}gZ#2`~e5*>VY@DhHczY*5+3H@HF=RWXPfY$&+_viY1b1yPav)_sxSrGZw zTw%jtyJyd}b{-aMw^h??+LmkAh2YD8R>06Z4P45H+Ex3}ZSCB;eoN2sU5h){a+G7Y z4CS(!=CKo_*4YcK0gksU!_uM6Iqxj)Bbxqwyg$nOrM^#te+PITF!Wyrmol7PmN>$1 zTPqG2+Fhwx=pJW1!JNVZU+7k;QO0VBbDE}G+Li0yiQtogX@C^@*)ZI^THm|*?9OFf z9pu`Q>-2nU=X~p*DDk~Wh4|vNJQen1pMICr>qhWO~b%FM;-%Hyi2{gMxCP%kaO9ew$zZg6yBh|G@I^LY7cz_HVu6k?#GAJ^5vS z&5@n4z5W|9w=?#K>^EY>?s)~yo^W|)7Hb<9(&;|T&0xel(_cCyK0JP0sdrFp;Hlom z(b*YZ9`AzWRNa(CN3N zev8@?Sl`s!mN<`bQrSqkr^cjCUac~G+t6q0F_$A>19kz+*NQBmujj+K@xoX(Sr$M` z-l&|x>gR1$&NEO>RFt|eqSf$qqR&1T{(<}{_{?w!Q(u0`^B~9z4Ny@+E^t1g%bt_{ z*ykpq%yc>pPgP^Uvl@9b*aA|1Axr3w&vc*`Cx0gsxHeD8a<+ZM{vpgO=2*;3IT$rN zltot|oA&u7wCFsSourCp3H{6bx8drZy=seV$Y?_PLqyW$_nLz|fI0<2v( zB1`DHN8bmRnRolVXsA8CX5&_g>X99hUxl8HxE+zpBI<3HdcD+DZ)2a0VD4vG&WF)* zCY0rS^RjcYa!MGU&K*O&Ar>mh9Lcu9G&3XRtgtJX9%C^}Z0_J`SxdZv(mcj;W622X zqYHA+%-kM{?eZwS^v@DUg^vz1FG_xPR&;o7X>l~8bZ&G(=Jf1XX_%Sb`NguXbAqbE zf7kWCC5I_^^I6O}#+y!a%)gV08Y`1BuJLI5RX?ZW#n~F9S0VC9Fb3FosX&&n&vVVx zQ)(r#HtS4SoSZ~@9SjCZntjVAxr4%en>N;uyT>y3#T}38AEly+!%kVEg>5W-$&@P`626c@&Y&rSiXhG z5*{%78}>XeL-^Q#p-$~P-0Hrl8xkj}b`28`asR@Qvj_LtgfcRhlSH!o@uA|_Smu63 z^TtaCoy2CKbG_5NRk|hqOC1j_@Y;Iw&B)&dcL8hH1IQ9u`e^@JyQEBLII^C2Sm(S* zJS>tjVTL~;6%U5bIU}ey4?sQ$lmW{(2U)_W=De(G({E?*3*l>QSW~yLsRl|WDSTed zQMg~tQP_4DJr=~lOm5ly&>hUlkUo^d{gcU*PjKECdJ`|2^oPg#{SD;Z;4Wb8_z|*% zj%Iy-+UKUVqoGzkE6qJx*f5HQ%yJqs+pck)KjA+!dU#%YOgyU)8=CxL-R5pL{IP98 z{u_*31||W^e+04wTaWEopOknI3nUUMM>GC$0;po#W7{7&E0#E5!imh=kx@7%Y$c*| znSID+qcZXEtFBiiy#W&1UefWg3%)A;m-@r)$Pa<<18dJ~$P$W7zgW-sV9z@#teKMa zwC;+TEp5wf-)43_6`&ccVCFz~My?q!rmahlJ6$q7k#lBB)|~IZX&;cCFKc_oof-6J z&O=@dmH}(eYGet0_GhwQo*i(g_+phGzsSvVoo$!7PCEyK=P`?u?m4zkE2eDYsUFIX z4`nHkKbmvBf2H|%qd$RuRsTi)1$Y`*{$C+W=xe_QRn6a2(_qr5FnJWklJ^Gc^BK_qX>vSqKyeEz8gUOHE zpQL>xyPwKH_i&14rkpWQG?5+{wsvQ&Dy#Ie)CstANRw^u5#9`yQLA3n_O!ug>vfMH zKMtM*)}9xTCG;G()0+m!(Bbj40A%``-k)LnJm-A6Jz1kD>jKB5njS5NFL74zd`KeC z0&{@nI|Nxm&*y{Tt8Ylrsck5>AL?97OJ{_xp_JIth<3B#YeAoV4(vw0A3Ovs-=oM9 z_V&?lu&$mF_$CVG<79&dakFwRcjAx*QD^%W=T^AKQHviU{FOmzNc;IU9l!CjgZLeZ zTm~ir%RdiULeKcMXT{i4 ziUkNV-p}sMOrMZfmTPcSQ>MFy(fR?>D zGK3AvXjw*Blt^1=1U=9*ykbT=J)DyhqB0gmmt@4o9u=+1m`gAHSFK?hR}-2NpV!Hwz|1p=v6P$RsEWpN zR|-a{9>say#jZD9Kc73^()R6!-`*cTM1C4P2dsTL&DuVD4&{mqySHZ>H>_>inktNV zEdEkI7Mo;*V*9%+lE=mpHu%kya+yYy>`)ZV%i-XS+zgH_;}DN9JG!d_vKR_t4Kag8 zv`wSxVewZtQpQH?15Bh6PnGXzyQ{Iw+IM@)0ab8K2r`v;Vr4rsqxxm#2K05S~n5ZU(Ip z?shh&&(6$esX!hZ6>+pllwHGk&xkTW&u8%vX9Ob4dn`(;oV>+uBxUY+_jK{Pd9U`j z3V*D>tC2T=jllZbge;+FKb721cAt==>8DD6K)psE6?1W=hf2N4@7oPuJNhi&3&?MQ zy}<0}nB-Ia%Vbp+9c!G;auhSmieus8 z0?O0O;jxjiI5~AFg?ca?VI}V``X^!*kkKOk0Cz`{s&lle~T=k=l-{;@>%lvLcJ;2AzRlnEm)P*QcBN~ z%=Dn^w9-l$O=cg-(`%eG)pz)lQW+@OrR_+5ImpjPB7Yv72&^4nM3&I={_bYSadjK( zY8vZOb`&O#WFIeOxUE2c7*_&h8~9q8yA$ZuG|a*-SKIWPL!i zBt$EYItUB6+3l`)7^hrD6KpV=$LTX6@@7=k+kfNo_)0wpk{{@JTaP`~-V2bw0$PBz z_by}!ebtx7jaL>EWo47o+EMG6^_=URz1{f{YgJ^c5t-dU`-z7w)01U2u&f8(=-cgu zoi=07NATHlpyVRfcY+FF?b(7XVYg}b_w4^L_NY7H_?p!l>)5YIA0XQ5UKLW^AY;^P zj(W|PE|If82|3qi(fEms_YcOxC7C&FOTuYda+`SJGH*PqPG}@YnJXu!(F|mOjU_8t zxfunL4-aSiT0SlHmQuR4eW>HL9XsuP{3i1I;4i@Xk+)O(aoM@O_Z#%$hje*zbLd8D zyi~_92PMCjg=wKYU(SOaOm#jxGoF)Gl%Jz==WbWWal>D=T`S%!oc!RLOuZgg&R2; zs%)}dpj2FWi>#JAj(&}^zsAnzIWnI!pB@eF1rFxs{-BJ@W_2%X(1WG^sC$v zk1p_f=3Q^}3hz0{7l4a^<-O8ew|w@!2k+u~HPfrGx{@gY zXRmY~f_0LPbavV#tvd|g%SNB@eSrKA@F}o-k;@LuPdW0yrnDvfQBP7lO@6HXtTK9q zcLQ<*Xatt`9CO|JXWx7Hxg6e}zW%HiTBpVEK5q01?{AUc1%CvV_wVMq<+JZSdC#E7 zY9EK6*_XM?@K%0B$D{C`h+G5K0L#1CT(^Aoy*J*T4!^iBtyA@hj^{n-wa?RMkzWR{ z0n7UbWC?vePu2ajw0;r$csAAP`{_+}KT$7yJy%XnF7*#%{~R?}`|}=Mw0Y`Ys{T~- zS6m+WeKhhaPzx;o1?IZ-*S>f6yWU1M9p|s;a~2-vjnZ{b$oUgy6!CD(r>1+po12*v z<^Ep8M8v4K!VgQEmzgB+GF2)*mbCS1g37Y zOY(Z$W=^x=tGptJhZB%b2GzjwZ8p~}kA3gKx15E}^3W};UMV;B>CRO!N*4(?x6}cv zQzhzWCjE_G@v{T@CGZNcynD@c%V*zv@K({P;&h~R<{NuuZZ^Ehmf*R1C~_4z9$4Nr z$Pz~PF)za8yQ&)2kWq?PA4$D)x>P%FW{ZwI8VnIi@9-qfnj?Kb$FPkqMyca0QF`0Z zZ}a`nkzWF@0?YqrWC{Dp_na1EENEd8oa#?lt=cVDdd?oqC}RFowzrt^-Kh5kpA+64 z`fdHwQjZg-%GLH%@&gHy4l9sXfz`m;v(a3)@o(RIqywi=FQSs6(!mt%&+L=ugs08$ z?m@48o^~L=0$vA}w+mUqe(DeK9=c6!&Oi(9DI$W087C{fNEDQm6mjbncwdwyD30?2 zB>;)h>S@0#t_t{%MLrRn0xW+MvV?x0=S%D1KSa*nl)RAkME^8ze^2z5khY`U@JRf> zjQj@p4X}3n!CbfTZr{7bzf4L}H9d)cTaCIZ-b*#giTlR?uLkLU6!MAS6kvHbo9mX( zzIWq2nq9QjIo>YzOM0&)Xr0yZAnkR>F{JoX0Dudg~!aIGnrWi(c`_+ z;aL2t8#&rt!a#JL8h7o?)b=~q1nWcwBF_M`fwljmUD|&C@wLj251-QS*8X+$1WDI| zL@BvvWJ~7tc~@k*Et#(tsJFjntG62?S7hSEcV{>sx#cXP%J)VjvNJa_xq&%z4VJc|Cb^Eg-}j*4!Z^w#RhsqZVngx-p|NoCuUx#l zU7^_Kl3)3u)<~=*_JSYoa>IjTPjM7;?1z4SF5PzV{Fl9wS7?>QuJ8-l_KBGLn(Mt2 ziaqQW+!l&OvYA7YT~PFMFXM49GK?k*v7E!8LfFk=u6<~GtSWr+5Q+E9@PlsXAvcoA z-i(~`iE4%HLD4U>emwMwoAag@dfyE{FQ+Ix9gaTbM=o>2BS!hpyYz;A&*dD7(wtCH zQDJE0G?qKHx!&)XwUobxuG&#vX=!L=ctohEAUF1sTk(*~Hqt-$Vw+>bVngGn;7m#E zr!K2mne4=Qa~JtpmxUr;$)TacBUgq(H-x;SLr=M}@4Det1F$TAVa6emap4gOW)UCZ z#c%SxTj>*v#KMuXyo@+Adb3Ay2>7V@D27J1adKt3w}Wk3VqbS-=ZC^ivNkxD8ym#Q z5MJyxH}eB-8g)YWrhUmy3O7R+j&y}$?}x(IhK5F?I7n58L7?o+@RayV zUhEZb#$}=K6(M1H(+l738bePC|JIGY1&jLm#cud*FY<&JUPbGaGk(LI`#FFKLxUa* z75q3f&oN|Fz3|Ot3x~8$gD6K z?~CqTUdG9pw|Sh79-0!H6v3(rCrwr{W^Cc zKMdM|Etft-me6J9=X}~@UJ6HQF5I&2u+3{_B!Or9VpYfaP#s#a*^QPGd*~lR7yuSXWrv~mf<#Mj{S^j zD?7dvb{@(orwfce7IqXa3WfY)pJT3Lg^Vo6TyJu0Le6ME7Mnm16$@4K3*~&}Xd=W3 zv;!j9gJOf}iO@@8-vuzY7BOV}?T#L~}`;=F5LPSKN`r2Tvxy|zF1 zHRL~nKLg7<>KmH(;Xe97Q+}$6zU>rXKMuR?;XS;OD7S^32Qth3BNC;49>rXCtX_`a z;wc_ySjWp~BvB3;Ascto`$tcBMr`mXQi78YpLV?g?jD(lX+q}|ZSOYhvG!h!{8jKZ zVC}shSwfMqck!hmezvV+N6`F^BYv$cYMkzl$m2Fgk>wv3@^z&GKi7dsZ^GV z^RS?t*^k~3edBf}wH?ll!F^kRJQ9on){ZI2687{p-z3eDcJ~t9hL1`Ue#iZc&(Yhh zhuSZ6nU9MNty7Kv=uMzk^5vz-H-X!L<$W7jLWfyr-SzeE{x`0#Kf~^>L-BT~D&AJ9 z*EcETh>dUisDAku1*E8AVH3vftsH z*-g2SHI0MPLR0;6jvA3~4hj`yQ31{x8f8{`E<=ZSFrGQF{)*5HCWN2ipW&L!fSoNf zwO{epz^^joIbc4pe%*~Mq2VT-9#yw?PnXnvRNutbZE7Qdc1{cZvCGT7zRDM0jW~C+ zWlNZ;I5hLwUZa?^%9#M>4s@fVDaS_)V9$^Ow%1@fm^X{DrF<4)vEg}Uacp#{d>Srd zSd=Z!y)d5^GpUhN3b9I=ggKT zZL_uCv6}+FM31*cG8H^dp)V3WvoLlpUvgS9+ zO`VxPh)pNFLb}Zk^C#OWcJs9zUGOB}k@$<=!uUTJ1gsqkkR`lk?%O7_-Zxe5rm81Z zi&XAzb}v*5OJ_3}vEw&P=wy$NcnnKuybobE4ZB^CCD}iYrN2X6Ht;M|qoh~4jPlPh zg$jIK#=aK#?YPyqksknifVJ=(&2;HlKwRjt-(TVU>kTZ8_!QOIM#1Rz0P`#Mi&+<3#wJmC6Go9bm<=UuK-2{so* z^2@_hL-W1KnWN}W9zl+um$@o@IPY^aIS48IMQ>H+Xm#khQ(dX;*kw2+o$f{61AYKf z@nEjoeh&L?(}`UpH`dk4S#garB~WS-YyuMFJSAqRQQeiz?t;@pcrF><_-)!(;hlh7 z4rTz$yTDwxeD=K;-p_3|JzFW}$Go8o`*vgQG`u^}Yty|I`Mcl;!18{8Ea7oe?mW*eMSo*F4-nBedaO=Mn`0sDFQl|>UeCyUhB^t$oGN=fc58Lome7BkVP4-v$^ zwj;DZ9oTEf3EoED3*Iw6h$nrOW0L(QH`S~=vQA2{bx!3vr$cuC^s^^NC;5Q8M&coH zq~@vkb`WnzARhyk0}1ll*Ln%XW7Z8_OgRZ&CmUr(vWG?4m?Jur4StxDFY{*I{6hRP zd~Iobk0L(}o&z?W-bR)%u8;b<^$+WclPj40w3OLTm5;j4$B}u`WJ*EP4j2zAgn`bCh0#OC&h_Te8|6;So;V{qb4niV5qIE>0$9RJ z2Iet0kXb=FA>e+=%^OI|Wo!P(JgvGQ9-bFp9?ghLoIKz%8-@Gi2G@Vm^*UwSlXGQi z@lei6xZTYt^cT7F-4jA;B~Zubbo|Bd3etBp@~hwtVB_zz@96kzZP)Sk;j{b3U*n;t zZLN{9tdZ^h9qx~Px82_xR&T}X^9UrjzLQX$fC(BiD-zUFt2H-p0{?rQdVcEbuCsX1c?V91=U^V%PUdE^%X#veUe6vbFOd z??N|nts6O5UdDD;&l#2Kj}-(^e3f4CaI|DVh?#&T{yYYNrjh?jN=ujqNZ#5^$I~&K zoqfI+`LXAp${=di6h64gjn5~d#(5R)FrQbJzRjc$`5SKb(yV3KZ@XDd*%x{Pr*ruf z@O77$kK6(0h8KH>L{~~LNyi$U4|m-i^pD(y{8R7*u=y~0kIsjEtpi+BS6k1VX1y_z zAHSIOR`CH~6KIit#;^dZ*?l79tmmNGSP3 z{7R-oZ~|zC`hN-&3&VpP=a!H^Rtk{Twc73~?6UnjYmm5?5?BwoM!hl zEIkB#4r~NbZ2qa|w9}y>a|YQN(wC(Kvj1m6I2x1f1>`^J04iW^er_b1tN&M@NR_w3 zS2IJp)@gg4w%|E=5b`3h3|MdC?_+EXVKh>t+ZFzb6n#TH7QdX{7%kfyN*i&Ky zea@@u)~`_$Y}?&EbOuogyILPs@%NcrH_1Lg8p3Sv^x%vBC%V6_%7Vn1#=MLz3?Vwl=^RHtZCv!|h z4q_m-8BxgP2)1Ze0n=d%vcn3vLv zW>eY{_T*w`*FqYMj`O8Z!G!RgK2FCuDrrJ!LTHAYbSJo}8Sd4abb5A>Ubg=D9`YxW ze)k3GnM9Vbv5)=%m7X#KbQSw9G;UDsxZ;L$S-p3q%S%49-OiUB_!be(NP$}Dlb;!l zgbU+7)9$ki2FzlyPKe|iBa3#JKQSav&0hVs>t7X2>vq~UYkQlq$JWzsK>iN657_({ zyI#?py*~?sx#yawz^bM#+IXy0(>UepKH?jDFuyd8%(6J?K?8K1}poHpV4 zJvMmzm&+$4ljBsLru|xh-PW%!B5w!h0_)dx$P(;14bywMg<@?Nw(+6lwRH(Kb{|#HhnX@S4j!2Lt=}zXD@sSImFXMr8S@?K=F+y0)O{Z*S-vpQK87fZim=9IEu3oyfRx^EI-P9Ce!iguGHWtbidSbZz-te>;o#Njw zkzWIy!20)lbKUk!*mqlA!>7(3{=B5;AvIgJY^d9kqAjkv#ibTr^qA|MFqx(Ks%vPP zmv#(^Q{ANFx#A)1o7iz8at&AmtR0)pb<1zxd)grl?=@-)P|AwJs=3F+oT3w)7P_j; zob{68LfB{&6G{&?=oP;oM}8JO4=nGC z=DOvx?HHI$x*Z+lfBgPkcA>z2E`EA(r$tpKaWD4y9#&xExB$eEl_Rj;`Olv_8ce zaRx`6%fk_;%kX?;bV@u9{vP{ZfYHGEH5plg^~b(jzs8NF|)nX(_J4 z%5e)~PI8fR17qw=2$ynVl8x6&_PUa=&FB~Y7UZvi>w)FJ)m-nZoZ3X8QD3{RHejt< z$X$~>$$2YtGPy^w&bEakei+^^qgQzIzRx+3U>LBx6OkqK#oHjY0ybCJ+@uT$=&O%g zbbso@Y%WebbcH##_E2vEx5@~Q zLju^4wlu;*=nR(PQ@6=<^JBR*u~k)aSmvZ$+T>J^>HMHdEuTl(oJ?(FTgq_guwH(} zzT`vI*>D}Mf32UY7*(CE*wmN8&5TlQRY&sr)tXC z!erT$m@|DbOZpCyd?y9LWK$5d8vbUZU()${yD=-n9C%Y@zIr7S5-jON)ge}VHe8envyN(7YY2xv9D%|@^Ie*^Njz@5PI ze%D;LeD=LhUiAcT_#ADO()vti{^hQ-J2KUq%t~2Rn>p5-rW{Z1(0+e}ep^qU`eVj@ z!7Ly_Ui<1N9yfknt;|!}QZMr`SjN!Aqd?kC$8FubS=IwCUG(|-EvKeM#%yQKYzpTb zW^!h83U@?NI1R>*orY85;hV^}gKq;H5BHnv)_?nM<6)g%kQGEdy&W-UPSSZdPYy;^ zC&84;9vqt1X*Ik~d+@v+f;$x?F_B(Yu4wAXs-B)GBi-jLcA5)@ zGLc?qd_7U9%kXY9dd1(Xkgo$b0Ly#3xo-Wm?}5MFd8OW_2KeU8cRtJ?8fTa-A743Y zSG$}%SEqNE(JQ?9kI*IprNHtYge<}G+4t_e$JcG)Sks#BjRZ@7M z46{g9=7X}ZcpCp9)7?Nf7A3(^{>knrZ+xnJY;M-^m3TC0H_k^s3>*cly>-YE`rMDE z_K+Pn0e@&16f_3}aqav^B8X1E)hDY<93u#pqPm7nZPB(+a z_{=h9@^WT=DKn70tdeZ+APigL&-I3e4)z(#R_;61=WF|x{Uj()HXv^V^+1BW_O%{c zr|WU`^-VlR=+6kMlLMT^18CF_P%4~e!?VZelz8YsehqX28xKW~X-*ptNz;E~^YJFq zWD9Jm0;9NLJ!R$(Wy9{pKWFiNXhddCMuEyOUI}M<4D%>Lhx*>|61HH^WcCe5?y+d! z8&v3r2lBs6JzO72h6ZyI8A;ahB^@8t#tyOb9OMhYMZns5rMYhJGy87sTvxlWQ7W7Z zrMjCkRzF!6FLtht@?_Q9fa)h};sVY4GJ0))$Dfg-^jT#A%R2#Cf<3osV~_o98d-qY zDCeQ1IGJTeH;kO_n5$lw%X*>347a_LeF9m8^MhEipW$=LRQ?d|to)+vJTD%Vp~?+x zK6TVFJ9U`%vftMOQKVeqxYyja)a|u#tiz^REfVN zXnnBH;f31o2BTm2uSEVj_!hAIFPZB$-_GliZ&Up0z#7h~Ntro=PesFh49x0wX^oUi(#qwiB-ocOWN43cRKbsWa_V#7EJVhCqZgjG|A(VN&Q z$RSR6p2oH@Jeq0vL^Jb3Y>lU7d5F7gPQchuMZ7Gf7hkjkC%;| z5|3TTpUVGF1bz%gme5x`cJo6$A**-G9wFz@!atEb_i$*uw~~o2x{W^ztJng;&5*kF z^)Ai*dXWf~U(xogH+*8xdB|6SYk-Z{_sw;?&vo^6-Q!iVQjdsjb2%(lCh8n~k3{S> zKKpA=qcuo(J%^Uep}U{+GifIlF-n`8mpO!4PIUZx`Rp$yQOnLyjLu36G88RRn;WqO zSFvs+v9rHywZRoXTB@S?JvWkI&$UTzL8K-;DOSQRWy-TVUs7>n;ten8)y;7z)o>=2Fvn`iw`J;+-+0>Sjy~FT7ZuCq1 zzJdG>_&u=ve=*lBuYI@tYw8tqD%%!TmeYxK;!(~88D;cBt3qOytxS`yi5Bg5qM5&S9>MJr`n0}Au^_#7j;gV@7yZON;onztasf>$_YN)ABK0_(}AB0ke7hNfaP6o zu3P`?yY-X#-m)QM;A-V$;`fxpoChfSP5e$vi(ltT9lxzcucYhuksk#=1D5wWbKUaU zcgtH_)3}a$Ow-mNPZd|)E?rQk{M>aqnPJW<1=TX1%7is@(-MCjhClI4;P)KlgUxGz_~no-~RRZRod@eMz8pNAM*FW!@%;ko9mX(zW2d9O|=gb zv`SBz>pYsxaS8|N$gVPcv1bE6#~@Dz<-qbCY_3}#`)>Itp46EJXHs$8xG|N?#nrFM zrb?%1*g15YiVqy_jhB%vEF%U>r&dT)^@}@f_RvUJO|7N){eu>b<1zx`?o_qK+^2k zJ9e_iv6ZGrCf$zswI=-ykHp9Q$lnJ)1lEq9n(LO|zNhS9RXdXrx+RA0@+9LuG;W`a zS7mtP&jtQZL7oNX0?T`>x!!J`|8JS~Y`yTVt!YeaUR7Nvb&ykb)7mYYM}3s;un6lg z-DoVw&y>w9<}tmtD5!XTO~*s4;gfiH0{J=cOJMEkG}o>F_Pq~#R#6J+P0-RufGXs^ zSnm92{0P5@qqEfn<)lnwpnuTVG4A;wUgjYm295&Oj+N$mU-b#bE7qlF$t|+nJucaj z^W3hQIEmAt)RCQ1rAhj=cDTTa@6z$G+vt~g_%ZU&z%PL1{~vSR`fuNDJW!u$VArCQ z35C^5SK;((=lgJv){mMa)5_mw!<+b@!0#Ezhkzx(@*Z!l_vQDxwXDQUv9iv;G3EGe zuJibm@$3wha(rswc=9@v{zkv}{e9#|z+=GjKV`04f9<>VJ2(e3WrV&Bwk&Y2D%|Hb za2gD6$u9%Hrywr?i-6@l#$4~qZ@KXpDoT+SchGiz)^$7F=(Ci3JE)6am^H_%#d%ee zy43Z_Z^82?dA;%9@QD9+BYz(}3alMZn(NkY`)>U=(>RMOhf$BZSk3^yfL#Ep-09A+ zC5y*-;|`t9lqj=CO;sGeu6avd2>K6ZA}<2VfaN_BSwdg)CB}`f+p?vej$t|6r))Aa zC+fFICtb6<-EQ=-(|yx*BEYHl*Gs;a&}H~{q2KmjJc!&5ehMuAFOVhl&EK$*s+HnR zqibk1oDs@il4cdPuX2}Q567O;3Az+05OnuSD@0O^vUFHu9zjS-5 zKfXm@BQiU`GCM2FbH5<%FScV)oXluCEh@)_`#PRmZ#4PhCH=p|OBwP+kTjo3#MpSL zX{3W#ZLH!FADsJcCUUeHJ=Ofi)?*ux8^Ia9=;3@QPQW344@S+w4vYRVSw}2Us$9Ye zR(SfFpv&lQPt*Sl^8bLBdeyH|&rhC#{qnYC6tT+b5|@{U+4ur`RkBEK#0PRHujDq_q+0o>J>)xbh0}lKI%_=T ze|e30Y|J2^sRV6p)$!Y6Y!E+hLB12T^8Kly|?$0p{(3>a{amNCo)HiKBrR-V7 z31>}eQGXPRqRw61`C;~JHToLT^j(O2G5AU^`cw*<0asi+1YL(XKO)P>sqM;mb5CT+ z$qw}28T}nbm&D)e$ZvwT)AgHk%1rhQqc_Z&2rSg0&HDYS=Op+@^vpn>4dw$05=YG+ zuT`@3->gG3YG38tNtc&qij_S63jWPMoBNp$c8gAjJ%(HCc?9`!@Ra#1$hE}tN7^ni zeHh_9l50kVYFe`x)d z$NDdP<{ZD8V`9*q?OYf;n*kJWic~M1%3HM`JJFNif8p7Md=t10Se|bqOGudb?Tu$9 z&vLJ@#jUx*)l54Brgp>Ag`Na@gvb3gV*(%!EYARB75edKYIy}jOw0T-(=xO0=^o-S z#*4GYTWG2<4Yz5(s?lfpPD4HmGy}``Wn>8r{qU8~mDE&vLyyz%_jaB;ZRJzN@KHH1 zIW_?+zpeRN(3e1;_;)k%-Qa#;`Su`7sOslFsF*ri60oAB*@du~ArZxRZ8~H84$bFu z27HCc!@+1^`O1(bB>VAi>da{sl7JA(Ezzv*3B22tM%Zci8qk+OpZNDByNW=aCWC$~hix+mbfK8>&KPVHYO`V#09zP})U2K+Yzz6@ju$$sK<=8PHB zbOJWZEzzv*3HWYE<7>W4^HrfQfj;3|gWLeN0_)#)WC`(p{F^#$YI2rILAfQG)ja{> zjcJ5R3;EzXn)h+^CiqNvUqjvt{s=7Z2gnkd`{6C0Sw3~TNl3Xhn$^7lZ|lCiiMus# zU$-1v)tN)y8RyQZ}PVR@1e-c!3tn`Peztd-CsN>XV02C!z8f2 zWm5Od?LBx~+BENO^d`_N{{9g8Nzef-?+eHhI{V?BK6Uo=X-Sj7`qoL^JG*=ER^O|6 z6K@5)Gmsa7Wx(7v| zPgk`bil}CFE2ZwGySwvt7~Y-eO`uo&y%G5?a4)dD4?fXQ&YGGerfmYNTPbxf zwRPuheL(x`yc6&iBaa0Wf#scwEFsa4zf-48FP}DS??MNcp+)Al?>47xf%7-*>7kU%u72fFYJf|28 z0hV_JvV?d)@yyepVpejtswF92^%QDO-AfOp@y5TadDo*ifnMQlMs5Mu0LyzlvV^XF z%d1(_W=)@3p=wKtSUrxKQ#aF|G-9QV^1$$S82!TkTjY1ZyXG_bs;#d}C+V3R>Nd(| z#M#svvYj8X%1e4|bbGYR=o`0J+bjAOBQFIR0-mR-QZm3l==7QFnG(TMD zmofRl9+NN7VdrCBg8UV5rO}&i=NC6|=%PNwV<=jNI&aC)xN5vg|A;n@A0&+44y~hE z?0p&eRq#fd-c&!!47AN~K2{BK-4ssiXYs^R6{?NiG*va+Y(qL_Wlw1L-3KYR}8gwrmaiDP`_%CYAY^tzRy;q zHkxgVkyfc`HPVhTJXP-oJR6Zu2WJ5Z^4ieX{S~Z-qF+%KehGc@1(&&vlZmaJY;~TQ z%b8gmmm~2r-}Fk2)SV~9K}5`wIAH5S6=N(y)x*(}=Dd8WnaS)qTU z^5JUaI1a74k7F zVf5}nM+ruX-VWrKz^g{DSl{`HzW;i*J2{VjeNE%~Rh%WWQEm0%SIt*he3A2q9L^+C znLOweNx9QtcoTmN^7mBa>7WAGVB@Q%u2Fb!rwDh7oXc{}U1Pr3V)QleTkFRK$QOZ2 z`_{+qPN*D+%7M--TxLso21=}ww56O& zCcm)x*m=a1e_cWT9ECgvj0ZOK$nUE1JB`dV&3U*`$DeFTnL*5G)s;r?`ZT>~A@2a^ z_pMh|Zl|Mny3?WbO0l1=x7p}@938?W`TrH z5R)EAVu*-f&g_CR8goZGI|oRL5c4L5l~($VjNS%x z>rP8;9H;Gm zETvfIOrtny^p5*L`!4Z37kL3#Y(A4X=@uWRlzG_0WM1AHpvx3_{6^GcSTd{0xa!?z z@9yt1W*G9^3VE2N9_lJ;`BYT{v!#@hE#+O!|h?tGsS5hIxR+D1HYyH zr1I;z$mfF#)AX%Av#G9e@}l}pvNnKBs&&2IO_y-D8GY^Mw~{W;A-@1#Nz<2RpG_5C zQpI;ZE|$?#8?O;n`jbBIs4_~Tk-|-tL;I6$lt;eFkL2;K|0MO4RLG~xRBS6YsW+$_ zM2&t)RZT#;c<%9HjsBBwxVK=7{Xl);AQTSt@_6OYQeGq8N6K8$C|ok0Y~F2=DicND z^TNOJLO=Ap2fWZNUifg)r3aux*&#|!vRAfb1Nl?6O>2;32w!Cjsf$SH`l-$r6@LxN zouiPe!12Haof#S@H*RfcsNd4G@Prl852RaKmzBy8mbq_#ruFSi)Ax1c8^O(K`gFeN zP208U+MKx2_cFg7hcS{b-belb{4GtNwU3o-b=#J&$He8TsxgAhF~VsrWv3EiQ&NFf z^i&$X$-f2p_fX_z;7DMDwzGGw4-lQ*wbDMY{%al0V(&MRZvng0^xAyfQ}e%M1do@F zQYmuDw4}SdhxMo|5}*Hpf=6dA_s68C$s_6C$dIIGdm4GwzZt|Cxybl0Zv=IX4P@kB zi5LD)yTZt%1T@f+Q{Rmk4b~R(X_^M9KPz7SePe^@?yiA2Gr5`jQ-7D$h1L#gaH*@> zO7^iUlJCh#v-$oAZ=(Lb{jR<{@pdN7r%0$O%t-=@c%Lt%l%;+$!keipK5WDai9Gft zS$T?PN4TkVVJ(Hda)fP^$UqIh(D}UKqaa_NhkOCp32e~$=P=2Yhfox9&ySq@1oDcxNv(DIoC`L6m5KRTb#>EV1#y@vlK z{&JAxpa|HY)5C7`R)&*h&Wj_&La|C&imjs^5k-{}1!@+NRvnqGT9%jC%| zHR=?u2`Hc7d@w?{`Nd!{R?MfUtTcMtv<{U%k03t=9`8l(mb#{`TQ(=jKQa^#M(T!e zmC^H2nx2eLXa|EhuwfM)BdeO~8|v4pnF#37jqB@2ig`i#-C*=BGryI1T!Fk2tV+{o z{asgIr_W(Bvm-{zgeClIHhNn4jh&ZrEAqF%oxSK`9l=_f=wex~e`$DY>rRJy)4qpvwl z-!;g)zzzNAV?TLi-~*#iqNbx~d!S+KhBd1;)}MjaQs*+a zl#`#-?V@j_)ML8S=&$%^(0_6y@-bjJkRbZIdg$LqN6PBc4M7}&xHDSrc2TdsZ}jdo zIwb#Gk9;Gz#e62ZZM?4GOkh(IaV379 zk9;Ax)O^;{PuWodKhKNeCoeCvnU@rM+PVM#{r`LMKt^is(D`VO6H4`CzKHw^cmvpA z?-$zVwHvn_T`xz!Rn>DQi$1L2%VDR*03Z8=(oJPDKo8`9!;Q@xtF`pX>W zDwmhV%EWVls3Z-+0{R9AJ6u+6d6^ zx>G24-QRVSI7`D

    `tl5cI?duToYjI_40ocQ3>#XqZIg?UC&YFo{@em7h_ui-_%X zO~~j2bzk`@l9~)E9f9%!8KLXc!Dne%MJzy* zOp1=CvSSc8;-el->P2%zTO(J*Gx1NS2z4!~sf%v(QhQf^Dc_8JQp1-FE#J|81lG9` zWlh>QwNK_Z{G!)iy_d@M>0j50q+e}>^>y8?wcoJD^!#7n8QM*AKX7Mgr(M>6>I87} zBvRe{R5}mWb!M`mN+xxc%%6Nk-yaoWbuXxT=;6pmfn)V&>K0ig6Xt6+t(iG}728a2 z-NtjQz`5Eja0;Y-Ks1^gsmkcvnWpb@hvz=iQSGr!@VD!Wzq0~6%Fys;7AYg;lQ{SLQQ^ufYj5E`;dC(5DslUAd5Jvy>cBG3IZk-@;$2zMeJN2r$%jhkM271RJmw`#Z1{)8u+7q>-P&>-mE-H1t>1lA{ zRa5`bI#j-CM!pDK+Kb+;jT_na0nL7L-V}~LcNaRXY&k30Q#T63s;tzFI{Cy5!!;P5 zm(gkS!(Qa~!27-MP(5whARg!(@iTe>gu^DE(`@vOiv{_87V;c0Uw@{eBo!Yu8ycn6 zJ^+&kIL|9})@V`MYV>VO(|0NI<>0Em^vPs}l+L&I(J2PB8@(Oqu+OdEBEJLP?L{x+ zuN#^+Y*OdT48+!f&fn-s)TNBv5uHX~A|uELQ<0~G3Sfivn^hpSEd9mGQnZyi7aCou z=zPtjzy7UC|Lw?M1{bI46PqS)R?QJVIfudUq)Pn;XBXRzOBpXgKZKMrXp<--7%#@bzAJh@G`( z$bDKA&&iYWV5IXh*6Zlupi-kfwSc3|=aOKD4>(SB zx@1d=R1(OMyTYk!0m0{Zlz3gIM^$zZZ*|BUz-Ikf_jprrW+_=Ec&*FJ9eNdwTII#^ zRNRtmEw8$?lW4S`Xjy%ptLqAED@Z*~zADuYsl|CzEX_5=PQRD2^P@C7vvNXCE+_yt z*z_gdbypHmpM{ZG>~SYIn|*$F8GXz2Z&f^h0r@0Q-J8BM8;@eEW3*MEt%CJBI!aY! z64lyMscq;!wd5N*UU#SI{~_{Y;PGDcoBU`v{N#};D<1277}i-)3JKxT8PXOcnNEx0 ziRT9Cmp~o`#_G?yrQfElo3$JIfqJbP?3Rd;1hF?Mzi2ml*Qe<{6Zve=+?(E-HK*$* zND1*%;@qJW>ntaCey7p5Cr#hak)Ht1^rBDg6GLo|L)$o~9c?xSBo-tu>GCArspC1G z7x+IMc_bL4KkMc{^_0z0SZ+n{R_7H}#pm``H;D9y(gM)hRfSu4$er?ue3LOyCUC_< z$~Tf4%`Jw%C5`_!v1=_t}q-ph0vbW2_OkB$DWH2tCc zkP`u!zy^EYv*p&tjc3%Tm7T+|beQuZsb&k@Am3CQz18Tj{kC60z8ZWDNbZvK{W`LQ z1KZbloHb+Z#;uL(H`cE!o3wTliu8VHgBLq3p~bSb1qY5Ot&9g7JNCk3>pvL<^pSu< zVC@))ETQLmV%f)a@?@F9G}&_76W-*Ka97o`uq(2|@pm}RY>zWWWZ#tJZ*=;vK(FOJ z19>|*$8d@N8_!y+ca7Mg9$V2Ux$}MV4>?eyvhF z;NVel)wyid5V^^9eBd0+k=BFk`s~DSwO zFOVf1fWM6mb+sGRxkQD`^&`uE!STO9mh~mWR=%zMj1LI-#v@M!(}Crig)Cveex|b> zENm+re}%A>C?{JDUo-lwf8Rj96?_X=zB`a59DskarK4;o-{(CkdJ^wwKfBOtd9wym z&jI;B!U5fvX>9YH$UMiNr+!;)^shjd)!&G`9h?KKU(Lu84#Y3D(R#mLkzWjN2YM~< z?~y+Qe+QQLV`K^YO+USUTOmmlX%RtC2T=jllBO zBTF~{f7f&JhxF<6dRulFzCGx(es&rBD3|}kyte<<3e*%6EEZ>vJ z688HX3E0-+XH5LO3_k&W9+uj8r1|&S&yqm_?=0l`U?H%)i;*Q9fS^&jNFS&$*J=3Io%OA8I@zTJKG02lZ5?DK?Axr3auA_dgt9sJP znJ4SnB`Ud3lCu8{$7djUF-OMPdRhFBny(ps*6*v4zX@&umhW5068g;F>1_I-rrdfe zFKxs#aMpU2%ENZU*M&aI7a09%Y*Jb!R&}aGHMgBAR5LmvyBTG1de7wr6KIyf5YItA!S2;A`TY+2))&a|R zDzb$A=G%a6jxC3Gl7_%Zrj^4^m*(ArUhC)c$iD)w0n7UavV;Thb3G>k$!daL{cJXT zecV}Rvbjx3?ibhNF9fUVzhIR0ntXDfQGpFcwWDR>-M-Y1bI9DtvzH#D8j zkHiw?jo@Zr{kk1l z!U6cTseaAYjdf;~NnzFL(sp6T7ax#yOxvaU10A1T=(X{glRySTfaOgfOW1EZc4IBB zuBCWASxVR6zzi7k^_EcbRQ*Nst`{!!N`LG{$d`jFf#tm#S;7JM%TWii_4OfJ*Q!jr zPgP#&X*0Z?=(W86MD|C7oG7ronaC3Mdw=#|?WIbu^u#~Z{;oi;<=u{a9=HHl-iweW z^jFT7pKNcM9^@y>Gi96OZ{vhs^Gsn-XUwY^qwy zeLk3*`lO*|O=9KD=_hYxhDt@^9F^ful+@qq_*>=nHr*{wo3XP4J8V1*8_oD6m;|hy zQ;{X~ncx3ARu)(7Ah*nsTJ|gC7T~nGe!}*mP|p5c$7?h8SbKko{3>`ISbN_@meAjQ zGIN$xNd7BvyH9N`{*g)lg91CZBVPzE0oKmTktOt5Zm#^VSy^2DqEu#cS8*#|L|qm* z-*dgis-Bnlhqm`+?6L7WX$*ZBU>30U&Ow%NAo+DkLb4yHYz6tUHZeZP#WnP~2A3K+ z0;qOlO=F|_mCdxhm(t8{HTLer9&7Kb$iD$^18eVIWC{DvxBm@m_buH!jh)G{ft}YQ z-vn+2*3NGsOZX4twJ|Y1h}cFtB)i9JV*EZSvAM2pjZFMZtgf%$XiA7)BD?ZqoiDnu z&&KnLaUo|FSPiWGb;uI_qj>)BSif)NV^6EGzYY7W{ZAwR61)Vg{jVTP=qLVd#+7p{ zQvGGUM48g#e4^tmQ5NvdMV=290tpB7d`V+Vs}4Fzqkm_b{@al60`~yx*L}zm4!|$Q zJ=6}+>S596bJOrT;{(4+k;j1X!17K;me6N@u(8>VwePN^s!w%%ZbPq4#~YDv2X_F= zdpEL#1MqjBgSc?KxavjOZaMN14+#3>>rA2!4l;rDHwRfl zpZV+d7TkAo+H_4gTM3IAdG_MM2Nyv>@Mx<5c_YN>syB<%Y! z;Zz&@OC|^QpNo7UxENUbFGH5_AEnoS#roc(zunmXGWOZ{A2fxzG+-34_K!i9a3Jx& zoEnX~EhO{nBYbq_X6E#{i6!j(Z~rs#+FO}h=`2-z>*2L_eGB;x@Ev1Izt53W{{Q!^ znd3y}IQ|@`+3#TvV?x?+f#%3_P=LMVb#g|HeD5; zCy}24&l#Kgjh~e>|6{98bRs7@{)x(tYGX&q)WD7z$OnUkz{b;|$P)U=KlU~}s&3PA zPT)`n(^uW99!o#tp#XR&tTjW+Nl*LVf?n(Yoygw>KLD2Z$H)@;yzhEt{faz}Cd=dK z*DwQ^cX%Z<$KoN)8!HcZk3;?fI0;zZRmc+h@i&!2dwCw!tXZ=~S6?z3N{04-)YDa`iVcAa!ldb zuz9Vlb$pun%c{Hk`{b8@-OhR%dAcwxQ4ZcRBJkU>C4_Uq_bEpMTQ=#=@$7dM?$^ zole8I7k!rRQ{?EJkdp;0UmmiAzWqyM>&L&AOzqza^jW^m$XmfSVEN8Mme8Mn(+|ME zc$VgS9DSDWHRRuc_kiVlA6Y`*{-v??<6pbstC$<`9gX}sumV`VmB& z{o9Q`>)*r3KL<|&%l9m@gueYtW9!GiF2h$cFW{SjJP#}YmhTW`2?tWn$X0}UQg|;D z@01qmGdbGN7W7&_??k>2JP0iB9%KpoFK5zO_bq4I44-pwz&9Lu3@8JZZz8gU1Mriv zs@ghg`fAI?zN&7?Tb25P9oK%ZN3Z3*5cx`Q4Y0h|AxqeAdiP+hKGaqkT1arc&Z-L(d8;|cIOX#n>>TPDh|IW(3`)L~n z>hw=83GBWU`Eqb2kkD^@_Bs#Ze`jra|80k{@8vZ6{(}4o_zc*14K3Yo{0ra6>t_KzIxxHA&OBH%;dTv183eE(U_Z(yi`@J92SidQ~x2H+H=02u- z0GO|HIr4pq?HxejAkE)_e#>9Aj5Y~430VGWWC{P)eJN||WLNIgAc&0`wc75C^>v%2 zS1JAOG)M3D{v&-XZ}2m9`xaO2RFQiJkqdCq)F_m>PMh&>H}+fq#vDdn9ZUog`ptLy z-pBuMc(u%lEOY#27&lm_PXo4E`~QmkDfkT7^zjbYzVvs$a~_zq9J^0=Qc2N!e2b$& zYzIZ?zn@5jRn<}%I?M6Tk|W$Er@DomX5-&7?6>|siTn(B&iK@C`mFpv=hX%$vcd5; zs65nV{3tmh@MAV|C0GP(IxRt#(9eBjZ<4k3TWagp)k-O%8%e$OwN;hs{LzA58-Mp8 zKLox9Ebqg}682ku?8CZm8(8$T8Q$2D0q^n1E5Rwi^41_r=*QoEvg8&z7gNt`+wT`- zKV9)G-~Zf3;Y|+F@zaJKHhw-v4j&bAGJv%+2U$X&@$|B8z*3NGuw}JbCweull3H{&aX+xSeH~j~Z+S@%_Jygf1b97+mF~}>yDq!ubMV8QK zJB|DHzhPx@^#iF%jsFjI?;T%9akT;O%!@m2O{&h;eYuJ^UNYhY;_j$FDZmtlHMozc?+!VSOv2Lv8tQ z-ZglB-Euhqy;ZsFs?xPffF?kd%ax!h9sP6h|C3VbxmnY~d9uE=LvK|s{{gKZ3mXWa z%Ebek(h=&5dh)PB3RBZUj5E5}ddBb^m_95g7x*>1e3v3$#dkC4Gl51x@jVYTrC#qx z4_vFuVf-jO5ym~a*?w)O4b$Pc)VB@!D!zw6{{#3Jp!og>n$nTloslCtHXd}=d3jH+ z8%-|X%K1sYYd~)XwgHOoX`m_f-j4LhHCBHGQ%fn&pjiO4Q#)-t(5myL-UpDs()%;e zUjyF)ivM?@DIH1gA)`9 zK6o~q82<>x0c|5+(J|m}Es%P*B7dd#N1(p|4g!k*H=rpUN$+7DYIiZV^|+=~UMTsF zUYO*&6!aQk1EBcUf~M5F-o0>z>W?H<{|u@FS{<*Iswavh|9!|mj{Ipq(X*gm1>OJ@ z|93%C+I{94=NfL5*P6|n>o#vGn_EMHeN)Pho5aeqCV90z3>%(PbNL41Qo?0ar= z`NbC{^_>8^9GC`BqH%5a@^$%?lsd!$XJxQ|S;uZzFpOy>F~kLS^Ka~w|HYth0Pg9O ze^IwM87Hr7SXTxU$PO6`t_qR4uA(!tC@9=@>>S2zge|ieR+9S#O;hNm*NEyAJUo-x zW>MVEGvZdR#|ZEMqVkwliXFEoW{M4%E1_Z+KQh=J31_~qWje#5kqd>%K$JlmKMK%o!hXHwa>yZrXJ`O*Eo1M~yH zLxAG5@J5LYT9%{IMfn()e zb+yJ~sc*&-sSoil1YHJ<1Qh=X?)QqXx_0oV>J{&k$Ku2DZ0%Myg@+Keuxv_7C^eUM zKM!-KPKR86J7j)NoSa>tF9a@ec@WR0f6MyoZt4i>4}oj6nqXO&T+2u2-o zi%O&(ZJqLc5A=t?UpwVn-8oD5Tje_^j;j-pmEL!P^S%3C{hEH~=AtMBU@Hl!X!kQ`;i1vZH@qy_t`>uy2uuZ(9;-l8QtfKX7FjR1)~;Vwx4LHV)`m5s z%PO|wkom1n94sSzG9JJ}0O9Gvsq%`wV9zt{6@;@5nkn3C=i$cLJjjF*v4bM$u|&`c zYTE7CpzkolOVt2ZZ}3;=m%IS_Ti|;@$v5_RDPPlBQm!85n^r@zc1U;~wGk%(31Bdg z2^0fyV5EExkuNv2hj5Tb$b_ie6OJO@WE%Hp8wFG!vY0TvW)MLUO$02qd6qH6vh@BU zOSklVkEP>kd3bRoOVfVEjgLuOC)E#4;g{>G>FjM_>xD2-pNz5cc<6 zYY~2&ZWG~AMlqg!JcQtNQDGrSqcG_m9ugk4EDLc$gYv!eiO15k(Z(gzNFlWhlXCBd zTyeao`ri!t9^e5$mG_UJDIKxAsa8y_+geL5ZAN$+L_NeH>uQ$tsfE@^eS|0yh|`_f-x|p+TnFPSEc#jBC$Ypno1I^$1rd??Vyja$q{3^f(7Jr6b;l#aI@mn50H{0`9@<)Vxy5 zPsj!+P-zRpp|clRek0;^;JOgQgT<&H2z?kZi+R3b=KFb|Acnh;-k%Q)GD~+s6!i`- zG2e-jC3osdDffHsd_eUJFbA%xtKC-S9M(6}vE58v=|n0v z!W*TmB)9e;4W*0xJY+^NF2L9W)yPYs-6M9E(`5x9(pg5DQ#g1jA1&po2H!Z|Q@uU~ z^ew=hfRgKPpec1PPbF6}j99FhUCR)EwVBOvUSrPdBIosT`Nj3}GT>%}BYlv)CbZf4 z=#V0&$MyvDJ|-W?OWDX`J&`t8_ow*>M!lgp8yn@B1GBs_P+8n3_`p0-P-=M4S@AsG zNTVk4R9?+bVAXsm(9EPiO?;fxul%H>eoH~03Y-Nf{W4Zb{l0VOU){^Sq;xf+vSE$4 ze;GnAJ9XxL43#@Z3+13kxbGiEMS@rqF zJ!ACQS-4LgJB=F~t!;T1GJXZiz(XF;ZEqSXScn8TM9doABWi#LpJY z3I)gMvqf5PP|zPVqC8TJFXEUs@W>EQ1(pW~&2ei4+Bcj+Y3UXYNyOwSh&phH8*OOY z+9$a8ANs3$xdrr9z_oxXpINJA`E+lO)%~Y9;uYkK;uOu7R5T^P0AL9)6DR_HBa3Fg zsXf8{UZ+@6(gq5&%HFa1C^J*s#Pkc9JsL$bL9gm4nypqNE54HP8(5B8HnvH@e04Mb zamJruJkU2{iN48FIvf8$#nhLIX|(PUgROZw&QTg8()teRi?Z@@eUL~M1@g31!_qhC zOuwGtqYNWztU+$Bpv)8dn5x$Qx@#PM9vbMpx3-vciK zs@!(g9Cf{Ne0kiBzOXLbW{_d!S$?(`b?HJ&+hyc?)1s+nAdfE=g?=N(EjyhDLg)et z{Y4_=H?ksDP6~Yz7NK;5r+U0ueovZ}otKeQ*1oMgvWb5^8|?c4NaD@2)tLIGXU8#O_p05%0<<;Pe8LZuy+Eg z+(v_@bl+)me5~fJs=lpks9Q5~c+HNLt7MIPni_9v#peN8KngJ2c@BSzohHK13(SaR z;fxNy8T1A*_AO$T9W+w)pgk&JA@Z`9k2O*YQv;cnZKT3q3#TnYnEDDSZzJT1Lms-% zSA+gF@Ccyf{Twu0a?mxv20+RC31~{;yQRG0d*!ur`8tQ=7Bq$~=RXHoW9T8>xg3=5-j|o* zKL@D||GQ87+8oM<*r9=gcmlP|$hLA)d6DUoy(=w zEuYTi;`rMYG>5L{H-}g=%Eh^SCEvX-FNvE&R4(87v?nZCE{RU%68V2!E=~?dDwiR$ zTz=W5T&|Pla#^QxSt!e;dOhODL2;_z4WQ2kb^@wgt^iHxKi%f5s$8m8Zr)O(I)GU9 zGRzhxW47=hLwwl#?0mE`CA^O@#eIx zFOu~%adX%DT2eZ9>&cGUGHJccYvWh(R}uF7A@&s4$_DfEaZrw?Rq`SHV#Wv4d`e3! zcJ)X8qw${f-vasH<&g=Izzdp+ME44)B9_xL@212YxxIK31z^SPzI z;4Ev!HM}r5##$kU1YrhziisH*)rCa>uYMtdFr?zMc~%PSO+n$oiI~DVQLpx(X?HU5 zSmQiqB*jSe;{;H7HzmvWT+q(%f8&<#Lp_x5Os9CW8u<_WXT}abnZHOEzTYw(s?TZn97$Y#4 z@r*%}tl^iiVb<_dY{5jpZ;ByS*(D5JM$drqfL5*dB?L6)*~!9o=p&Q#Dgq4o`vYA7>}=%<#h<76je5W-kN+_3Di|FqF@v#$!1+*| z=NLJ9nvsf`C-*^y3Indn#m>V)@|+~)X#_v@d|nUwLEuq9$-`=;Je5sSp50e;y?>p? z&kH)XAGNaQ^!<#rvP%u;V(*8HkFcLDtt{U$fz#Qwra9V7Gs6aqaK>?bdrnohA5$y* z1wBRrYnleXk_B-~bc=<83BG}bA}my#hhJbEqG_x6UdFfavHWcPcE z7nY`-WZ*?>clnO4ORk430DU5`8c=+%0Zr+}VJ^#y&iv+cp_hydEoLg>X~8U`DRf2^?B0%fB6R zgdqo&|97B`dicu#O3qV3A4$&5>({PpSg>yW8m9q{|BYisV=Q3jk&tZ&*2VJuxHFI} zhx;=;nMRi2o@_m?=kY8n&ExgqD_!?R(~R&SeYhV+EIPg;&C+4U@c8_xg8T6vD&P!u z%hY3bhDGmEFd{*Fj!|(gtS*I^#|+nV#Q>;yn(;DE_H(W4rJe_%hw5iP0{t!Uzkt%y zbBfgS<6in%I+t|)j+t9#*KFCcP{v<2!gEk3LI4>69%0+Hb1~`6hIK1!+2NoFlO=-c z1x@Nq~nK7`vEr42&^kUswzw{pB)T)19W(ZdLJ=(K15o`i_ycBV)~6YRVPdN z+Q46x|CgZu3H$^o`Es@#wS4noNhB*)ERhTO<^VGt8Q)|$>m?uM?PU?OFDwb(5a!ER zehb3jkV5TWgRxZA&_u12YaRG1xpslR9Jm@#a@`I3D9g=}Yg*lQYBEydxp)`{Vu|q) zR-=6&a-~=h#(9c-mZr@!LRjQ%cI7w(K1vRM1NMIbaX`sY4*LHh$D(?t^(0eSOg=4; zWDg^QE6?`Yc({db;_*Y*S($-5&C!p+vjl@N?`s#MhL-Z5oH4r=-YoUew!v2%@=`z1AM_w# zC_st&X}{ZUcDEOF)CV2T6ty2uGOqt(;+kuW*XcQ-1 z>VC9X{;&rVRKt$>A^Sia@2LxC(HMLaTcmu=kVVyx{h*%#4s?=l?@^TV+`7#$G$IB9 zr1~|3RCu{U_hZP0J{7iHw5h$kLL$?`kk-`oVrMX?9dhLwy**hE7K1(xSPoD+()gxx zxy{+SsbPKnCfY@KCZsx3dk5!((dlZInaxuS8;v1cGn_27`UY7Z`@kcCkLZ5A3;H|Y zpMa`=H9MpXd(Q58+|!xAyl>N_9Tq~sNVbi-onJbgPmsuK7`mW+>`y|w)F`n{!x||D z2XM1&GY_{kq`Jj`E+4$1lNI2M>zamNr1eXF*+`a?f8ZvGSK_koW9 zrTwpoBB2t$Nzyn3vRxY2(U z1Z!r-N~ejh-XZ0wJT+MlmV@31)B{SMouDZ-Uo7v(=kB_>lE;-{&dOS<2Dk&yIZjZP zQ|#X`?IZL!x#;;}HsynPD#q#b6dToi9FJ3%Q+2A8qYZrG;6wG|e?W&$!?~S+lH+aA zl;Sr?ITF{)tCFL0xm2v*QL{Q(E%KW9$2cDsBhzB%wU6_90ly5EfPL(JTl-!>GJgcO zHr)uJ9r9xu6w1}(7Dm#T5_v6;IY1vDF|xU5fIiUXUVjnVV4ItL^js73L9EweM1`?S zo*j(9YGv>^GYUk$iN+Z=dQ>PZC@#QU-LO_#tJ8GL@8OxKet0@@UMuGNSw_)d&h1o= z38y~;EaoB+|32O5vT`L`Q8WG`TgaxT(5HPw<_P2t2b=j(m+eX z(`bg{6fxcKCiVvg^HCF<K}rs&oT#znN&|cVaBO^CeK4fX*^r%@dM;k^WfYwupbVX1SmbC zXG%T(2a=S`jK$%1utn;UANQL+VTV;AeMGS-H(w4KX(=k=^tu`sod-RRZsf$1vZ zuQjp_>Ig(o_jyrS)bvIK;Zl*0nLdok)H4@ygLyC;voWf{VSF?n6KExhJVq8z$ERuZ zYUW}{8^P*xCXbpX{7&@6R$Nv*+hcCkcQSDvqgV8(Ve~|%k?PaqB1QL$n2i%}Q4{A` zD=gHp9IS&`Hkvh`$nc;Rda*WC7O{$HG-I1HA~ZU-W)}NxUtkNvoDETgYLh?QMSl4!PZB1>>=Jl&88tPU;?}9e-JpEOZwVCh8%URBw zD=p`;i#eCA&g+GELnU*2RI43oM^O>2FpWJ6X#&QwY#j@d*|cKIgZ^ExZKZR}FkpJY zO25Erl5v`SGS;B&kX>L#x!Dg3diY19$WHT4`tBtMT?mohzFqyc?BhM>>J@P%S#3181g^SH2WBgIY?0_%YQT4Ota zRwq0bqj@JMJd8}7&d+6hf{w)>d#E3t6@q8XqK}4QH8gTB%e{bE+kCK;)`|z1$+Iw@ z7h*mcHvhuS>AXz;mfL^jtVM7vj@`h`Jote&H_7|62j#EEqj!UT4A>8-`!oF@6#@?~CeS9b%iB=;U>UcQH*NkC|W#(X# zQf!w-({0^50-ugwVw8`u$5!L`H?vqT<=Iw&J<1*(v~69apx6u#eX55C*=3$6J{xEI z6WohCr3aT_kc;)#QZdLWpMvNBDxYvadlbsI5CsGS3Rc#yWBd~ax8tu}n?~bRuKv(( z2kI+57x#nyBk&fW^zVPJ)W6ZS*SB^bPdLw|)5p*t9Jbvjr8V~_d3i`));bp6|KJTh zGyk@Dp zqWoqy&L#&+Q&>Yiw)Z${7H?+ee++gb<73G7*|ZKmmk>Uii0Y|T1P?9XDYS^0;({+c--4c(vRD*2*5)QI#;iu%CM3w`8X%E)Y?Nj*XF#482w#YFsj*ZN;XA8gQGA8yg&j53v`Aa66 z7+EK9r{PP4;cz-1lQJ!AMR^AT9_LrW#^U*9j5je+XcqZx@k@rt#NtGIqM0Qkc*wIw z1{UBKg-c8ugC0}oVnn#o9)%`-L<(|434X!&dyIdL)dh|MZM;F2=K++LsxNPX{tP$> zsPepQr!3F5`{Z*{?b?&oxMa=A4bx>kd0Tht#77=7^gqVh1KJ)@hB0veuq`5F)JAIn zDi~cl%t{d)DMEm<=rXLu=$9oKYlBk3#RwhQyslmR13bIoLy?E5ddwrf+ zC}+^#MrQiNv5`smA&h;7NSo>z#n53PJ7G0oeIX4#=_5?rX^2vFTOVcEdLYZrpNS?B z*@tF_bE!qS(y$*fL=)%zV6Qq00Sl)-{6ogt*^A;sr+jX;wO!@_lutjutw(~9K6V<0A$b_Qcx{g` z`eJo1ii!bO33?wbuts?TFy+DlA_uOAIl?!IlufmBr~1`m<;`<12h>jMaa_>IYlGCXuF1cS$|lpoi+$J^=j<@ExG^?6XVi z*?x!AulsWaJ*SYKt!yuM)(*aAw0Q6s+h=G896jUqG&9}ogI>pj`)(NHjRI>VgMrqt z1Cs+4b}D)EpMkCM#v-yb~@J?{NSzHz)KzW)YoTmU;bp!h~XQ#vwV zxljhSoA#r@e1cts?G?FvHuys4W#Eg8Ozke;YUG=NkBDzA=&iu1fa2Q-no?0O_KTTv zfFT2CJ;9FChUW4Sq~2ic|Hq~LUa8*!m`%dsK2HE%vq!U8FMbJc;|(__jt6^2J>`pk|-L*=zL-L$qq-A-qw90 zNRz*`lliSokBEHyY>|aUT%6+V@$oRcYGMu_5q5rd0mJX?O#F&roi%PBFJklQe%zv) zOIR6O%fHhNn)*2D&;zo(en5Gs`H$~HT}uP9099TEpegm{mvzck>=RwGzF{3bEY0lC zjC}5%V*g}XPCkFd8Ff}+x;|HpI}f!;zV*nr68TbnxCr$1Kr^8D{s`LP+spI0(i!g_ zOWap0_HFEO%b8#Og1w3w_!Rrx)&}PD0X&`&jbU(T1mJ|5gSF=cd|+fiMkE%Bj*8e( zG9_fN$!LCZ*@yrf@4dE#rYHahH}A}t9ftiWBCs4|XJlCz+k^wWfKAV(L!HPjbAX|` zPk`^mNIr-?#EoP00{W)+DpCftS7m}DqWk|>nLhC zLEgx3c65bT{z6QRd9Jw_U2qZI+vGZS8*SfHPB=H5*NBV z@8@Xi@-e_F)Zs71{ZTZehDTsv<@eZ_+Iua11x+bshsx*RNpL&Y)Pe|g2K{wwlr?%F zeCwi^9b0DiUz_qjv4rOSda^ZTIDYMooyZsSqPQ<_4y(XiBb8bGt;p2$e>icFCe;=|doX=RvB7qA&@ z8YB=jHr&PeH5^{1*Xek9ouh6I0fAlM12C&oFZXm%7&^IM{7DCOt#gape=qOvTeyF5 z)GvC@J_G$V@IQdMzyAVFsW-n{=Ly5Jol-sPL>o74jn>X``4nn$#~X#z&B#>soa9$| z34EpT5%F6NdJV7&SnZI@w-x!u zkuULm6ZHGQUjW7T3(%B~sOQ4E$qS~=oY_U)e|1&2`gy5m;?ks^vq3KcmH~?2NuVhm zg`P>SUDVwL`^;hL!WTyJZ$bW}kw5AC0_fL(Hvz@}1JIOuv!`?_XZNX1X=H1$%l0XD zK7&h3uH0ig*TA%m@@aDUmRy$PTM4=fSOh4(%Ry5*O1??mJF|cDF!oyf1*!L5#m6x-TL2@tQX5c-vHbKDEYp zts~mhbt@?XbFAtC4w1@T%y6&A;`&dLn?Be{#N+fcdbi%aN-Z7?Xdl2E2lIOq1`@B= zHh9d4HnHdcY@c8zJiV^LkR*&58?1jmGaTdgy^Oc9viu+)76QedHQ&Qu+^BJ<6wDSBY4gdb160?A}dT~!hN_{3{&N+&OgktXM^6)L@N`s@XsO3 zgI5v6f206nt+~!mjA-HAD?*~!8ZD0F%V3VVn3)-Rnt0U7<~AlU61tg*K_tZ;OgByV zbHl58h0h_IqyQH*3ZSuaCUy-yQ9t*k|xC2o4{n#tz zeGj|q4fWmD8{GSjdk(L{=Z#l6Yvb4I&Skmt`YdxUOPtr~on9}IznanMquCCPS9+We zM6{>GU?XaVPz%Nwo_NrVdlMP`JbXGf2>4)#3C8qPPYQh0?TSEUz|Mf9 zALcV~yNL*FKA8fSiBJkYg*O)raSN=46@k$?D<%vNS*fN$&VtxAgqQ?oR0t8N3{;4U zyttV#M&OCTD1^2bVcP-BV3;k9(#c?q)e7$lqcT>3ErJ!y5*74Jy}&ST5+1_(6pOTUMzW2yP>@!^ABH@92XaY9tb1=bw4XXQ|fJ8eA1Shm77;Ema5tPR>#= zxmEm3-ju1GUN4kpw+rOu4tcpwUPd^-vwn64iFcUVJysF?L~Yw=|~lryo6 z`V{T*zs}A#eD+X2I)D{Eco>2ELcT}}fqW0Sa_n~bP`$ne^qs&XfRdxl{a*PWsH?JH z(UyM{daSAsI)dw|YoOy!o?^2++q@A^8r)7|UN1bRXI*WNGsiXAk<09~CYxVvrGe*Rw2j{uJYitm2Vls@m)k4nBZr;Il4|AC-~0iyuLe=KN9N1^xXj^#jUy=aB?!Z;2Qsf}c~94-8j zP3gbt-I*)J25MzXHDf7p&7e_xz0295F|XdT8_pP|EQI9J$6}Zb@`TGpX9p&^h%%xphW$0?{RQ?K9SeFgFda~ORD%9*ddL&moch+~DRx3?b$^mRm-;jzU!_kA z=qG^R0gCVMK~w7edFq90to~BwMiOhql7@zz5t_EOBa~RH%RhW`az8;4=pn#JK=HpB zG^M8QzqR%V%0ZNP{XImr|fBl)y)<8Mm7Z?$`D?}5yASf zzYHGTSa`Ngy;vU@7$BIL;AUWq(0MxMAQj&H%tA3xOT z#9){6VDl-wRV@syu~{J7OS?^Q+-Wo@0N9ny~2w z(=)JF8-ZiE7Y^<*zK~-@6pMhIo#rdZGL^;krGUh zb_UkA^HF8JIaqczQ?W+Fv1ODO$KZ=5uq(x5dSN#3`tfZfBPz(n&i1E7O>Eo3#xLxs zBd_DhyxhoRbFpNY3Wo}~RX9peIesJcXo8$dk2^s>0z3{VJ-z}>sokA_wO`YN9&2kF z7Hq1c2yd_~p3iTl^@6puT<{!&dGJ0&m%zLVAUC>PEY6ld{9G>l!IbQP(JwVXv#g-k z?}G|f23$t8QN~%YMz4btKtI4yoZ~1M>`a2)=a^NID$=d*$(qa36I@go>^^Pxp zq5_`Zg@dVz>}J|~5DA8N*q8(_HJnB6Tt0yp$uetm`L`l}_58dE`fK3tfZ{*kcFDiW zwZBwd-9veSzbdbGc8grCXpxt5u!KPZeQ#(#@Ih#CVpwYl!e@rW8fJLx7%zi;BM3Jj z%QFtnLct)mvg<-D!QQa}kuVk4AY(EcXN1w}RpFSeFkb>=6wD^hy|4OCmg8<$PHLa7 z1AQ;h0w_J~JER_Jz1n|4Cq3%%v`yVqv$A$8miXzO-wIow!ihyQ%J~pup z!~WnX+Jb)Ak)QCTWB@+-eH*{>`CeG;$+Q2e%lrqoNnGJlEN zW6pQG%#?TuHnfBgWamXTUppq(n-=!^0`P1E|7lpnQVN&1784& zKfmiJ`FC_}DT(9p7-kIiLIMPZtk3nMeKRtJ@Q0NshO_^47UHQm-3STN?#fdIeoCG- zpicp|0!p3>KvVi}<Ph02Kd>y+_Btqc~z!+h9y7f-&Vq_5{=3Wckqy7^_2As)vIcLkL9#RLR7~5)3_Z z@jNWSxGH1zeG0G*Q2g%% zO{x7h$zSa+2LJgrD_2i$m|X+kaB9U`*jLh(_7=yZ^%eGOU3(9s#dKz*>sX}s27<#e#;g9Y}Guuk*l&?^9q>HfoY!i*|7Ia#tjQ`}`e>XqkcM9lp zfvW(;?``*cb>Gz${JNO-t~O8`Uu39`ZEO~{NAguH4I`!-82nS3^jUx6lgvrMN%kb~ zq!-OeeB6cBxUYHSE1vc>=QkK>7g~I`g~$0NGwnrF{LxJFib$F*($az=1yO<8kO>Td z9|$!{#a(7}H}Ra^E6aoA9|QUrU>>04Kg<1I?d!;J{RZ4K7RpxD)t_2ZyNzyaJ9|O) zt&Qkgy%;zD4cX;mF=8mXR3Echae+4v{fxIHI5AD6N7KCNmM_(3`3GWeCWNQ^I)k?| zz5-fScs{^0Nxq^F#aKqZ1`r(=V?Omq z1w8?Nvs^ynjy%;k&x6wFUnSSQmV#ahtO1n#r-P<+nBTlS{G<#=;P#*ZiQI^VXf!!* zu)CNx9~;22UWAZBa)+MjyuQaey^$Zu*EIDx>2X_B+fd7g zVS>;Xn-hkbBY8eNbV}`M*}M{)zJ^CbV`=h$;F-sxGxLn%6Sv`a_%$L)gp2||c5~#7 z$&7}x1}3nrvBEw+Gm&S-E6hY+t6zmL6c>fZc#aWP%*q&!P6*Km^)tmWkz=f5M7n+q zHGJ4=I-dg^nuJH$w?c@Z| zbAbgwN4bKgRPWBGv}@J46s|#=HkCQ?OWeYpgT3V|*V698yhHq#;v3Em@f+DUSgm}6 zeQ0W5GTJ|fHXy9~LjI`Fi_V2M&U(x`ehhqKF-HmLejmK!EX<>+R$y9%O~|MnSP}9% zG<>@BY5E}S$d7WYv4zXYH}(bHTf}Cvk;Zz_=!S38np32HT1&DX=Ybvtj0co{4}qqn z)^FRd>s>$RQJmb+Kr8sr@Eob(ozM`9B65qP=o_|n4<8I)@&NYzVHOsRI;xIjdd$p% z54G8!&%#KWoB%DFPhyl2fNC5nlDZODL`4yhs(w_ZxTCJ!SI@$*K2?Ov3+Ztggps>* zMcgjS*q(xdxJ5U@<~+7oufqlicCK@`Gh{i~=v~#kGaYmxPy(oO7zUcsVSbwK^SoaA zY2xYKLi;8A;R$||#!F$^C|+$8Q}Z{JH#$p9luxV6w-Na&zL$Z%8Mqx#e18v`Qg3{> zD#k7BuX4B$q@6c!vMagPCm$Py$;;2ge8G#IB}Le93y*dzzhMs?N%R)uLu6CZo+-;A z{9v*j83cL)Fa=QZECEevyz7^r=$MDe`ab1UjG;EIUsY4Fx$flTV5$Y4i4QQ=!q(I7 zoVVD!Tw9GDVAvvPd&lExp9-(N8hTbwgn?iqo8gS9h);R8lxr{emf$`07terh1O5ak zx&8{8(qZeu?)@RTsv0(Tm8y|d)6FWx&3cRB9G6R3KF0LI9E4C4kY%{Bu0xJPt{jQq zB+F+a=o!FlK*_NHG^NA*fLuA|VY?C@kCZ01_A->jJLGk=#&tTHg)lZ?>!ijUsdqE- zE5|3K_k*Ax2U-Ee?|IOa;@$W8y8LKRN!=vzY-Xp@VC@}vB5G&l@_M@SOWd(qJlDPd z4<*Za80d+>R6y}N5j3UV%DJR;0W5?oSFheYv$m#TIHEebZy`Xe`fOO{jy;h?_&d|~ zU@#jo$wwI5>U`Mnj1hzfn@t?&-G`as3}EAZ-1`r{>i)k3`p>|7fRgK9ppRazk=^7v zpUkvUFnI7j)LAfCV|myWEyWS-aaS~lUp!CBSNU*Kz73$a0;d5=zGl!zC*Pvl^{^lx zR%|Ca#dZ$YUWask17W5yC&$24fb!MMyGS)1HEp_f0G4#@GR9v&tB!muly; zv*Z(hj-|axrBmh|g#FvFi@|uW3nMy}SHN;kk3iOfC0W=Wi;dD{VL1PqaA7LPm=FFF zx|QQS#fzQvh&&FRoRY<>^WYR>Pq3@!pmiO&a`QNTf?M(z&=WtGwq}$g2qQ!oN-G9|v6w3;-0rVW27X*8a`e ziUUi@3Yk*BsLlqvdhMzpwuq3GqN0=IaCNa;?~&h9d9|JyTnX?Pn41O74lqv7bDE zPB^Z|uvu{}uV9!OA%LBgeT;8A^+bo5v6hdA+tEsF#LmR_jB#u@y6SY?tJYE}fB9p{ z@#FEJ&jWS?O8&<{Q)+YLV3xc4PkNGH6&;?Xt33b&2?ejqFS~(oT(4BMq?&8!_L(E zvTRt@V=N3K3J}5%D1`?}{o;=&$7drzR|0bYrQeC5DfKo!L+HfXy5zYpjWCqZkRyd& z1eRCcW3MonGH5J>)jNB+NHv|MlKFhIQ!(3JIrf5&n%_MF`YGUPK*{kkXiAB0_8L{r zG!CFz*~pfkZG-C$?OCiZjLXQBhSfpJuv%Rv_0D)A$*&mnU|<-a_)P$PBz}%Dtt-Qi zd9FP!n3;wrVH(`4aY1T#`Rzu2C3sKI!8M?70qz78zlT6OsTcjGte3HxoCUz)=qulY z{aPV?g5Gc`W(IMf_H7rj#b=3DT;}2?9hI%(d z%C!f4iK6n@3;I#u2|&s9B4|p7Tsxw&V=B28U{`#Dvn<-oWQ_2WXzceMdk4)QMi7Hg zDp|%VDwQ!tE$^=kgoj-I8BZmj>%pK$0}}wne->y;z1cSw$bO)%zQNry*TiZrV^s4R znRdH@r7fO|#(xM^gT-!-__niwJF+6%s_K0E>X55VhylIx$KDOI`gJ)7P2K2;wmjyTN&lx+7(*=UW7Wcwb` zs~p+vh<9y|(jgw7k`V6mkPw^pQF{`jqxdgxhWe6@AkE40!UtX_4&`)yy&5zi|M+Mr&s*SU<2}`%PeFeT z{12ey`44DHZKuiSy8F0c`VPmR6z%1Bw3i>SC5UL2i`aY4%G>1RLRh2Aukv?E{f`H| z0jL8Mze_+<>P`O&I`EwqJJ68yPzEgs|8i7iP(Q}iAN=CrNBVyT`g`EtfRZQkX(^9d z|Ld+lLX$~Hk0!RU^Zoc6)1HMagL}Up6bp)NA?l zUN&zXZP`%%RpX>QKY*X=Pt9j^Egi@PlsuC_Q|hfhrRRxmRWtSgJ8R9GX{q@G8sJ{x zhkt>01SVzaMjmRcfR_Lz&ljL6y?35`p1aT2D(H|^Sw2{?!q{MiykGx|b*q$o#6Ib@eW@~* z@M)@h)EXyAc}D*}DbFm>%YYLBCC{0lDfL!96*#}Uc9lF48qa(8B6<)q9n~{dUoPc2 z0Dk4*N9FTp(4PSZ0VPlPIVn#@_c%lDysb)A=r-8tUZu!Qn`tlc2kaTH-Is=loZf{_ zg)Zo=LT@&nrwZLVS<15%{FFTFK<@y~1e83tfTq-|JRKFf2Z3JsKM3S-!MJLwlID7mUY zQ%dc{-guHb4sT*7ckVX6V%qM^d<2N^^)ah7uBZCbR3YWq13s!fybtsf!0!Mh$A_RP zHJ;J)xEzPckR1Z!PkQKEv5R;=LqO~m`<+UCHP^m|I13zcI+qVVkfVwX#w||!+%iMT zQ}RNx-i!u41DFjcc{YHi)LXqFVdQx9@S1aO*3r})Cwr~6Qp&Rr{7Uc<)t^6rejoS< zQ1WOmN_qCW_W2)n%W_iVLAc0uveUrX;5=!cUqPz}A28HsMAAV-4Z2^kP8F!5fQ~no zb!ry1wwY3{D)3eInv+0p2DSrAuIoWls&?Zxb(f3I$ad#b2>0*C`QQAFBh)8cdn1dQ zqHRZRimqZt9bYP&?DAPsuFt`jC@QZXK-(|j*$0$dLqJn{xtDp~mX7&UE4xkBr46z! zJ;1f^Ayv@ZLv2D}I>fV-J^l{kS5A#`*l6{$rCg2RtK_;A^i9BRfRgKXpeeoA*z-7* ztUpx4+t~fG*I1qAm;xwy zR=D4*@uIq_dZnB-s{6pA?sz|!o#@5h`KrKBd$Ji3*lra_gE7{tUE!;G*E{s(z~pau zb{Rf$yHM7SYncg zSj6fVz%yVvJOe&rkHH-rz~rlA!KZPaTONOK@@=H@$ORn-isWYw@78~HeXek3J8lQl za9o2HMV3u&K1=aGsy$l|dJ|CJDW8`Abj@dh?3a;OjrJ+Loe*kC{vp(o<9mq!{y1ZR zg1?a`CLKshuO6bDf~b=6w}FRx9zO#83GhWHzTqExDXwQKPo@(k?H5&PYMJMlC=Pf5m*fV3aLCvLI&vr#95aI^UwOQo6tXlvXp3iBnu7UZY&dlU5gz+V8x?_)aRw07D71x%^v@ztaD8 z&~F3p1B!n;Xi7(+zqieGLN}CtI?7B-6 z?WW7O8Tl%Ge+T*i@G_wIz6zSs|3P0`V0F}8<}j997!z()4=G)6MVRO`iWr56 zin^WlS0+A3s1t{B|3$^)q2h63MU6Sn zDF|yIWJi>fizvGbse)Z%n6EN@hcS+w$$#+ZXBz+Gao;_sD??7xI$8g;KPTr=e$bgf zE}-h)DA1I;pBwAcKSVxWwGK^*5nd%DG2>|DgNWb1n-0H#Ukg0+uxSsw1rSpNXV%hb z9NXM*6XEr4{YU<4e0B-w8-ZH^#s4wTl-9ZN`oiu!z~R5Cu5P2;^3nwFFK51e4EY!w zL=Y8iFZPbXUd^!gjfLPh$Bk-p77hHj8z>$199D0Ta@cPr?KK&o`vYZwlH+{PlxFXe z<3;87<;Xz`(6w~n2Fe0a;(yXFqbTuh>@p1H53(PG)`~zZ5lExk+3*E{%TJabBZo9Z z3{2Ovb-(UI@H5nc9NWfWG)@pe%ZYqxQ}kg3)Wx9lO$OH%D}};k21+yX1g+G*%drY! zjK`k10dST)1~QZ%ci;uj5O7+(W*a7)4-*Psb4F zHRm$t`9w_XpG3YIhqTCvK7;*j2tJEwY`j0tsJB@eFGZ+PXf~dTRE)B8G$J@hiq-^Q;O0n_ z>TekjN(BzpOZgM;B+GRQ=wpDnfRcYPXiEFsdaCvfIOV#K8to3JK&-8tfVGu_80frZ z=JEy9AZpDZHqI)mt(d!lY1`Zi3_;LpEVp`j1hhCIz1PME=2S6`07pg zVc0&iQKYu4dv9`WoRmDZ}Y@ zo?T#XvP*GvAIF#88<_qY(_d!;U|5L2-^gbp81M7Udp|plhp+`DJk}nZF-yd4M62qY z!A|D6oFi*d=H-EBnD+o%yg*b&>Gs22et0RfCyF%t1pRn1KEh`&cU3z~ zu8iZwMC&VNea(uU-+afy@5_vk!ykzy6~G#?T;Jk-kNGa=`W4uT>u7HWzF^*i3@04( z6gHYq+uk#e5;1$!ha}~>-2R))Iw7_qIBWdEHa7kAo_|y#E@6Qj zNahVq)2AZZGNP%KPwDx$4%?O19Bc021!7@ff^+AkiVN+rsFmLBzpU54sOF#Yd#Le$EkwU>o2@A^x`K%23K{{0$e-NCFoS#cWu z@IDsCYv(NchzK}sI|8Rn>uP3Q!-@rEa03gU-!+3EIBlkXzld4aGV3~4?4chvv+#vo ze;5^>5%>ZPUANYtL<|a`VN2Nbe?5I&m@s<#YCyu@+gFz`M0c2Pk9S(*n5gOUZfjp# zE&Db5qvZUr z0Q4|mG@$ymZJ;T&-YWaEy-#)O*GfvAZ7$u82`*?gZxs7Y)@nY(_M0>+z0}ga_YCDY z6xDC}G60;YfK!1ofKr}gW3xQ~3P-4B0J*FHThMH{#csnUh8Yz39KMSiv7d1h-_Ll1 zRplK_16oI}JyMSYkh2^g(D>?4px*{QaAha^-$UK}h@E~Jiy^gJ$%ShVhm?5Pi&M*o zu&`-jmjvenjd2#XlB6O)s@8t3I}Z43a{YG_=qW%2K#BNhJ@Hw!wP8#B%2i|`o&ZJ@ zw5Po>?B^6HocMJz-zMZyj(;cluLpe}@M}Qbhqpmfs_ZHMEgRQ6ivd-4VJ_qZ_Pm(Q zqk=yd&O%=7M2V(G1P_D*i2avtc_X4vKhMBW&@A8u2it1UdmPS zadO-`9P~tBDxl<=4VqGmJ5T8{?sIAfl*T&TwT>6=LH0P)Uh(B4MmVurWpu>JuD?O@ z+k^a;B0nmJ+d=;uNc|+q@6sB<-u79fgUec|Xb^UGKdPmp)rt1gwzPIS%TlHm6>NBxTx`d5|ccRA( zhWoyOz$6JwjbiWeA#?3H_)WwVcj@-6I)aXfTXh?+Db`c^&+JJZmjiU!r@zA=rOUHy zau!0!3>aItnCx3AW-I(=l^8F92UnE{t#690~{y#YW$ny`*f5N)5kBbw)Z#?nSU4AcO^+8|C z5h0VWDl*b=5S)#}9lWUyj~|nH?&SS*gQ;G>^ZA9OvEs(`{Q%$8?o+Ae%iu|M~J-4x0Bos(MfZV%=%~YSB-ixA9;=r&TTxy49q~; zc<$r+y*zL(4&X5_pl_s1yY=+n>AX!(m^d-!#-9G;Cd^~4tMvfF_gE!3;kmTpUmRuL zU*%9%@qL%~iAXpw$r_9EP$o|Pl)mZUHD&TgUEU8(U}}PasdXD4NRoz4+*KWN?m)@w z?>TpLcz9UOw8&H|%PF4Rj=XYwIF%>LO1SqY$`k)D^{GIMgQ|uz)NW$dHz*~&=X~de z=Wy6|P`IKa&tQ}lLn3?@8S32k9mv_0BOQnRF6N8GQu>88$;!rm`R!+WlzCbBxM+36 z8(1$kLBrFm?N%Lr9k*M0{B>>kWO0&H5;KpO>+0|-(GVHv$b4J!_TR%|cA5}|`2Z_K zmG{YFyPs?#x_K|-`paGIWG`Z-A7d)(3f9*s)>F*Bg*Kw8>&WQ>+#4LMei!q!=vFWT=P*QH)2%o3AK4%2 z@;qZxv-O<9OSr(Te}-AlGLMb8{{<0VZyt-q!xV1kS#j~a!4Ke!FbtLRtdem!PxM#p z96sq>URLZaF@R$1x)pC5{2lrcOGixh++tCZeh$ZcW>c{!D1~(~3`r0iA$l#FS&uWT z$Kq`2)VmD6m;Ocf_`hdwv+{S?$%rN|er@mvWlr$582vUA@32#RgZu?~mov|-;rcLp zxc;!g&o%7fVi*owirQc4{7YTONs>BjX?BD^jH9qx5SiL;W7b=`um+}Jb&g;@_V8?URp4_N#KhPasgX~zEI zH(p|VLumQ57T$kSSp`1M+rZyvdErd~JSzWE;{8#=yPJ=1W1!BMeU?DKoeV;#x#sUu++Nao+8nTz!eImRM zqL7&>mIqthOrD`*1G1T+XZR2>87AQj)JVh?^O^mPfrv4klEEy5(Z+xHtO&M>crr|H zAcO2f-*Mv+Y3XWuRqC}Aa;x==wV*Ept^$-^Pl2X%*t!jwh#b9U%vnf7h9)>RIM%l! z=QVoRt0k>+4|DA)$FGo1iwq))8jkQoNFN+Rin+NT0dr%a6bpYkjys?&;T$0&oVeDG z7+PDKlso)Ya{N^cdJ-@VP;zeqO{sev^W^;?^W2siM7?uPzl~M@k@m$60!jgjUuj|S z=ODXQ*S>_jdG;dH6ZGfuI2{5f%mESFuv=gafLTAt2TN&p7{63I)9YWCa_)m1$}aW- z=y!p3K*`C!mU4FAhw8|QP)Vz?DkKfIM)+C=>-7|196$!SJGgd3lp>{bSd9e?*a0(z z&VNg>`&5eYp78<9WSt#`7Z5uqHUCk{RRz8Yd_v>4HK6N&20+PmJ7`M(>E?&nS+0uB zD_1qFucLjkMtD19nh%+m+jQ4_~Qm0~z*njQo>!};&tTm-_8V28cOi{aZj%)E-}XNOONrN_-0I|K2=Bm#>s zWY$G&s`FazTYRQ<)>NR}v}21mTAQW<<$6Tly2@HT6(~m-^TkW7rBi|O0ODm)%&bhY zKrCH6$wKR6m6r!n5WdiFh1djm2`vS70ZQ=Rnf$P)yqZp;h@Gs+Jv%Oiaxs-CJtP4{<>jqWHnzfq2WH64) zO2y`UG$(ZdCe}HD}?y-aC0&lhf8uDJekDnsF_@BmoRWgRVB_(DzIW<^K+P#eiM6S zsePQ0$Yn)wADg?v08Y? ze$BRayOnG#Ww}M%P3N39QR=h8i1^|aZnD~@9o;A2)_UxK$MokLknaZ%1Ea@xkR|Ou z;<+9dl)6=UMyoPjtHJ^8bFM^x$s($2pbF~-C!Wg!FE^8Wmu^-$9v}w=Y7w|Ii1btO zSFKm_pQ-sv1@cfZ0vNp}AWLdJ;`!z*eW?QvA4}xI<2&|d+_sf*DLJsDn;PDHZ4LRF z$*+R^q&-@Y?*k73!}k=jq$9V-G6HT$7i_U-Xuh+o1MpSj9E?$9s&TgePT2nBXXa=2 zLHu5WEMWMGkR=_teB9L2H^UlUkj=$+?4J|lAyTQH33}TU_tsz`&>8YIlAr1K7a`vQ z?f`~w^1n3SVf($AYNd7kPWugg=p6=CyTy@H?{|oRXMNtUBo1=m=pm95=Sbd7aF^Qm z)bRLBZ`QCNDn{kh=taDPR0iARe#D!Oudf0k;Z^z-{KP@dfP^>MtHI4eu2(*&%A4mk zjN$F+2%?T%aJsjo6uTM;4o+mljLamzTji}TjeAU4Wa^c%+1pmRK6()=q;*l8EycXP z{xU5L@fSGpz$^fdV(%LlbFJ^`cG*KcnCIbc5{>sk9@>U}#Ec{Z2_jGo((B^~yCi=Jl9u^lakq2&{{buh|OBT8`C z1Uh6o$#}Mt?9W=C{~T-Wg>~8}!AEnv8aopwI!{iZai)?K2eo3mV@K>#;rvHf{(q;Q*D1)ez#L%8 z-+(OXu+Qsh>u^^s&#JzK{|>kCAB>l&#qzr6GQJ)mfTpQnLdA3HUEA)m6LO*A9s6}|dBiL6!8TES9@_$@I*LG7 zb@KM;{6Lqt;-l1hxE6T=m;wy{EM!T^UVi#g^~}ZApv+BMFa~@FV;bu%%DhfqO%v1h z{r{=?TFB3gPkWJ{11|u>SNR{!*ZZDLz{mR_EUKIQf7T`qU9wMoeADVXSz7c9b|C#B)}pr=2e%;a1eXI-uIrE`9d;aC z82GZztDV6l;~nBcd>t(_)o>Z#%hUS9B#Sua1Sf}y?FzkxO=@foBplK*+za<-Erq@ZM>_6L!M# zHuZY!d1be$-zhn|eaHTP32R?+B<@#mXiV>GjNXRRT&zb{vPYGP1zVhp^|_hxgrjOR z<5>eT++<#Ue1L;ryj%j#<C6!q+8|SYvwl*3+NG ze&1No+Fy&RA1n1mn;4$7J*i2_X()aZEVp~UzXW+DI1iY5B3w%F@18!~y1A+vH^;$d z%Fr6lU}a>it-<;7#E}`+2jUs+PJ&R;AV0`8=>57~UTu zOFHa6VLEThhO_nwMcG?yKIVYMK_y_#_Xbn@VmBwZDz{=NZ^s!446pK)SK^ds=i}&x z&dYn#9g^WQ|7W@}l(Rbd9gc9EXx^y!==_m!oSqV`mGRAu42i@m{dlPpXB>;GY&le~ zcH4;cY^!c#MfC3Ubp2MSRQt|AUINYprkqzHOX}_4K6nleE$8fYTefa9yVbSdkg{fl zs0hl-{rUIt&)+vbfl?IMv1GJdRp1iSj%DS=va?wkbJ~_Cov@m1dsQi2B1pd0_hs}+ z@(URk4j}&pyc_B$f!O^+N)R~TzO=Wx7YC%U8MS#=>_o#S?oduJhE z09R0>MPukU6Pw_1mj$1X=^y-0==vYnzx1qcI|Eg} zWGqMJ%8*gwWEIASs49^Qovh^0jG?#@CLp_`A`=}y&-~;?7T~B?{~r%)GZn3&GO58@ zw?(OQd9rXyaH1GJSQYWG{oPc3jzOLQP6noYjmVM)-k`_99`^ZF)x7*y4y`$N-T7mw z%A&e0)9kuhaOJePbcnn@tbcqWIIB=1r6Cb+&u1 z^sTyt=B@Hl?K~NIH@FcP-uEJ!ci$IvJv{z$+CJHaO)FPRr{}$}l6vUh8o8<9;fUQD z`L_zb>VnV3!6)|*n3WN0PDJ+-38yPn$g}a{3}_e12wR#Top3DnFmW-$c~X z;>fb->1#L@-H;hQ{X&8`Y|C_W3uj(uv!#$TA$npK=E2d(KzHH8Hvjy7JNITBiK$i` z*2UDqM{F{A+RkO8E{E^3NK;ux!fEi%>@#@g^ET7Vob}NyI)}b$IB_JhR5`m$_TkC6Z{iTWxJy?OA04qJddw=+{MP(`^Ph^3<6qKenw#y zzf*wl@6)5vg6uK^cDi21B+gJKpd_en(5>4BkG!k<(& z$*cG0_>*LL=PmS3@#cG{W=tA3$(|pZWS=72#ou+@&-u9N{=4Izq`t4*E$T%TYlyFO zsxfA>AF|cQZep*U(-9oibd>3S)9Ab1^RcbSE#NL-`ps96B~3Z(c}UoA!adfaPWw%5 z>OC{C`+iRU&`(yt2kpCDYp+wOHWKj`SGj7iJ1b)mmSf8zIN4*Z%Nh_Ls}$pNw)<;y zn#BHMxz;lpP3c*Jd?siFM$a2#TF*V9UGs_`9HxIS56q9~-ZwizAN@dg@2|yzpLX^5 z<$f>t<#oC@-=u#U_b{eV2ko2tTYq-WmGG>pRk?!-2a2CqJV>8Lgz`Eto51rJF!<4E zA621dxfxt59?)pzyX_1$WkSY8u@@Q<6OWYy$5O+=H+{lp9(+Y;zn1x?uCvWy*)x}G4hS=4SuiCL8iPO9x z_QcrY{JEJ!3Qx-(V&A3`8*|p>&&{dMUy?b*9_I{?jPb5>OHRuhf{jF>92`g*rTa;3 zT=xTczt$ly17`!%Pwoo;zquD~zJvFjTn?8RpM(zJz~c5`fA>t;+^<>L!00;{SyD%MzEK<6HwOC3xNT;rsLa)tAF1GK%Wt^a!VQ;`ZpC@l zhxP-Wbw9ql3mkk};%7PTC)M;wHkJz!F0(k1K`fghJ|++12^CFi8Q%POEb^M|43}FX zEw=lPt>&wNm^Mx{_Kcn5wEnH3ep26`MScl%0;B)Xgx24z`+M9EGMDjN?S2p2cB|dx z2464OvQPSU~{4ej8tbz^RXJZBJQSYHd!5fbEkPfW+ zqEgH38+5}ooS@6K1HH|>{WjzW!6U$w>j`8@N0_&pok7`wHvv1kFZ6#T7y27|Ug%Fw z(!5>dYk0A{w{k!sFuWzmN8t^2;*U(ayeBCcb%eZY$=C2+fqX5v9vI%6kPpkdvuRCD z&Dxb)*VY7G@)B+7q2q799md}@msiQ4VX`jge)2PXZzKN`d;|=im8JQPc%L(!t*CJ^ zb_=7b;`!Rx^A{T5l$5%1@AmoLR87m?rYbrHEe+R@se)588wzJ~Wb809>?A3_>cyV{W3fa$I_T0*|3$Fxy% zU!eAoZ!P(m@?4I*2iyz{-)+c}j?#W3DM<01g}fGA2n^q5WJyOUUmDwy%hx(vmv0~WnezPv`B&f#VEEodmehM3 z-?WucykX_GwY@Iuu(td%%gGGuV@!1|%yKPjJcH^`v%l7SvgWNVO!3Y|UJRB2!+RF; z5qU!oKfS574^5$dmUyiI>UuRGpst;xd7ma<-eT-;_?w>Ah2-yHHpi(IRMd}O{|Dl!-ZB*}A^=(Uec{@XXM zUbAJxP6lf8etMJ};x-?**dvmD_HfV#5I@k#%Sa>@W~g$W>2cbc%Xd`rZmZYjY=O&^ z^I_y?!1KVAb04y#!<2JfdO3?4SMaWy%B!lG`(jrAO11_!N{xTxti}F`5C@g zv1=tj5=fHr_I^Hs{v-PlLusLf#3k0Hz$*Axkp- z^Yt*UZ;-!uB$&!v)YVx zXQaR`wYPCUQk~UZkdB4A9IfbChn`Z77m!~CzW}Bj!%D((Jfq9e@EQHxs~pqia0R=e z*PNe-Z_lf>`A|*p!^iv}C3)P(?UX4Akx?=9l6cM@k(|e4N`rwv5$Y0oUed|Is-Tab zyEDhH7?PQn<&~@4vEH~$x4%~=rIbiRT;$7RD=jGHbGCSC$W@=yCB1?xoZTgDK2?`< z59KiJbwBdw!Iyz4=ZDCWI-UyK>(FuM)J^Jfo1~w_+a}n!q+??p9s#mya zNMa+DjMMMqkx}J->CV1fhoHeIQ0dq*Q=Hz7cCk9oore`&&}{YTg+afz({*{4_D!|h z2IOnN9$?DzD`ZKnM{c*EJf`8kts8D$rW$K@ukt0A>GDl1P3?y_ATI~!08_s6ktNlI_Nwh+oXxa; z8I&)zlxQdDu|(*&8cQNVIaaDG+-~P+4pOUix=&{@M4)5UhGmocdfyd><3L$3m7#pK2XubM(=j)vMp-{QAO9` zn)K^-q|7e2vqQVZ6)N`}F zPCkO56d#MZR_#ZIUkh?Ef@!kzVnbJRfXqzZ-w?Z^fRnj&4zswe(da~S)4KLR(Km(i(zeq zE6lZoS;4~AE^~sD%t>6yyi45J^bZf$$+uyZ)}s|3Q*X~Be-(Ta7(ITBEa~lD_L}Ii zrfFT%npJDp1lD?a$%WX$L@}b;tv0je*cX@Ao*VOUA}L4Pi-{>4oN#x9yu}r%@pusO zcrY0l-nqz$ zYvma`QbK1R5*ZtAfOf12%MXt!|L2jv0lo!{9zQ~sWabfOA2e;8F`)(W>ZWq^DE8L7 z)g?UtVp>q`^p|qixF_l2TMg%h?O&PVtwx>>W&^`}A+jXXU+cnp2zbv6=0|~*w+sSp z_E|w4T%}#?{*JFWI&dq!h0!~Y&EozsRh;Q3Fu3lQvCHNHMIJ%NJ*R-f&`PP0QxijC zXGUwhn{2nlu9aR=w^r-fjvnT{`6}|Sz#G8m`DbKFZN2;?r`3-bhodG&X%}DszgrP| zp4c$a**xrhHyZV|9eQ6Z@y$Z*!4P151J7U5zYhY%e?6G~U1}U5H!kOT=r{ zZgsD1?T5Jm=5k?P>`pQhqNa7aylv!b%KH-XYv7l_@csu`Qs>pWKbrICG~RB{;_bFf z;+WC-GL_q{o>JDIu|3Ge>@Pd+*%OFK7meqss)A^tPY7GZ%}Ly7$vMOM?s=HZAXu#z zXuakPNY%%g$g9CRVD#FKEa_60RIOJ??Gfq zdwSXDQ6J~7Y$T*6RU9LW~O%Ho*1*?x>i*1)p(XwG_w z>MZ`!LcdT}(}uA9$xjwc!uJ*AZ-bYC;rk`Bq~7-~;4>jTDh6{)Cqaby8`J{pTt;txlo|&nBA*220>k$RvZSSl)-R*L1{nv%ReKP3a%W&T-|(8k zIm34)g!N78tL(Z|5@IW=24R=D7K5#vEW9rzG4yh~F^u07t8#qUsAxVn2Km>~Qm;HB z#*CTB31ZW8H0}+MaH-gTaQ}d=IoAD%sNjKe^07(RUl;nC`I9}EvVk&S$}<63Qb#zS z=}gUQs;Z?lviqweDYW1z<5uyG_LLobjgg1=7Iilrl8YLVB-Rvh&hcaF-?m$&MrQ}{ z9L3|o2yS!*ljqTq_2zi7Vzbt-1%6{kcpvgJ;CW#5`xdgK+At1Untn#FR{KWvux+=p zn;;>NZc)F+T}37DSUECmR&IYaPFRQI#c724AN}GP9+?zsvQ_I*JS5f6s*p#5F~I0C z9$C_1`WYecnh5i|b=@U_-D^cEid8yAx-)lZ0xc@G1!9I*`Y2&Li^bG$&|oi77-HGU+SHPow~i4*e-t_J#k1s?h2hAKwoINS+u*{sUkf8Q47+eRLy-oAtUGI%8|-^1=(oEJWg-Fp{BbWlYBF+v6JF=sQ9%bZRW=$+3--a;X{p3->&+?u)fc!4_ zJ221HN634c5qSl>i6ECKOpPbc~$9I(W$t-{09`el@ zrt=fNMabuZ8-U^aN%;TG{In&syN1u4(l_;Et?)gMk4F`2n!D9GMPE}T)12iwU$pZJ z^9u4+-l*Jy94~hurUqU?L5bIAZE@UMe9i$OGi~Vd;nTQDFuAO-UqP8FVf z$dZmY|CXNBTP!# z^glC#3}x?E4Ql1%~fQWJyOnH%Mb^JUu+6 zKY-&4%at;6^|nN|QLOfmuZ#Q)U!umf@<0(Vd?m<|j$Xd>jeN?PSGR~&)d72hP{+l}+t;y%DM-f{sq z{zF&VT_JBL`5NAT3CBp+!WnHhZwy(|(aYO?U=kGeLe8EK*f&B6DDFhlsN~apr7rJM z@-@7hkS_sO0#n{=kR=_hyy>h(joT>fWkF$YSC$K`hvn#bcF??5YqRF~xC4DWViNk=Ph z57x$em@1iPAPHw)ta}Rd`)@xBX@#70K@wyWJyOauX%w7&+G$o zt?_{U4T=jW?s=)=TFuvJ-if19ybF<+gL8o4U4<;^Xyr|3ZQLcrJufKjO_UaJ%HfW& z`{?#<*`;~g$hVGshg(TJzTak6!;ahTmJ(oVQ`ks%a>I5Rq;QM-2Pbfg`(wQ0#;pg{Z#*VjBUOGP8SRUSIiEHDh!}TPvLdC4Y4#~u zGu)GMM&WG{liQ3uJKncc$82Axb}-9swMc7xJ>fj|_TIfo3p;{fP zn!G{lSv)q?&xRsT0@Hxe^Fibwh3l}6@EoIC&ovi^=Y!mW`m+<=!-Z~=cSn|*T$F)3v+-1Kwwl~0qe4Z?yn<;yCa+O!VfimFqk?l& zEpvS;8uN^VwKv9{9aZg~CEHjl)N1_@lV9sCntuoR zo9Ez8Ua$7BBp3V`7)LzZOvpP8>3-m2;?@=6|BBM;;$=P}6e_8-IBf3I3-eV2=! zcpQ=a)G%y}Rd=f{?^^OTyjLS%4{ipA_b%k);uZGZygxpaw|p%B!m69O>%6v8~r|s5Wb2fpUpv>uJ{ znEJRF`4VtN$bDS(5w3i*AkDJg%*YC~=A19g|K+s&e~bJscpsQ@#!t}Y+;*dWFWwp2 z8yr&38SAzM+jQ;riNW4*2XjjqwAz&QM@ovL5snQCozplD8{r3cBbU3YF;@vTteKbG zuFKm1pDFKJ@vsKarUclw5P=gUppY`C+nk1}MfPwEKsZ%fPnN5~!EXP+kj+3VJ9 zSlyGPIgxF3hWRHarSuuAio~{I5s83AB8g z{JWnH>4q8BO^J+vAsObspS&vgjm(oiM9!IvjTLX5F6{$t#Te{BBGxfnH6O? zCAHC!xi;?jBcqE{NkJsn8^udFL!Id5M=-94oJm0T%z6GStP�dVg;HJbz)#9p~ZT z24{`_>`5*clxE{y1y2@U4mKsRNpdtaNv+1BVWqoGT`8t83+ajz)I58VeOhEYSNpo| z(e-_R@|ynWPGQ{#ih-$*Dr8AVdf#-9OAEJOsH=jS$ZMFuR(2`KWy-u)abx#=uBPYm zQqOb6Yb*Ml;trR=p!wdg-Qj73N806j#2Q=%H(!S1=tR!8!6abX;UZ*7 zb)kJj+rFc=!;GEb6a<%etxn+0?z7sp-QwVftN1~BNJqr_appOyPw-?^F~LjH04uy4 zB2(n$Mf;ETM{&n+a^Gm_7@Lh|95nhl(X7$_92#u2^rp+yMG7~Z+Z66h`H}h5_q@8he>bG&){Xbci>_|~QU33?^+6_c>j?Ac$a<&L z=N7ePO~BVFe)Ixu(B}!Q&r}jycZ?>$Rxv63)nmvJl^^zRSh< zEO`~>adDRZ6>)qoF)`-H0)57~*LQ1!o!^sMp9Aoj=U>&iRwl>=MxTDjlFaje#CgEX zwJSI3J+-{18kQa6BVsS+3)bhe2Z*5~21 zlJOxwk2eGVCYIyp=J#<+6pPsyeuVPN-3leo>bGq71=EzZpV9T$hMqgnQ^wDik@th& z08@^?B1=k!_6QB(_aWnF@cx&#S(o#={jOtoIrHD86Yo{8DeI%Gvv@>Li$&wZy!q0z zG2eSs`+jJ7M(Z(g2KH>B9%mq*4>ka!$7RTp_O#9V%kUX}{)qem_%|^6WX$|@`g9Lx z?!g}F{1exxfjVnZXS5fn!$$I#Lv^f{|Izv^g|C_NOFLbHd;_=@7=0c_mel^(@zsy$ zGn+Mmv{+9L_44%S~dfwlC|9wsdjk}oX-OfV- z0M8hfL(BoLog;C-$*^|2<(4s@0jHT9ts8JXt5EhTd9Z~;I zCOCmEY--Qyel*&?p!K;IKJ#3(A%73N0*pSL$dZnv4^Y(g?!5U!nxfxkfb2wjI9oj{v z-aG3yZd!2eUn>PpTL?_72f&g$?6gR78e zVmj`c;yJuWV`6%+IFj85WpPHe-8~trRB6&6wSHOay&t_y|N02|6X4WqU5~zw?WJ$} zx<{|c@6KUO-WKxAA!$bNkLM{gbfYEydvZQ@S*dJ$GX#1*di&vgsgV_rMFjj=8T`9YP8?6s= z%Gkrrm+i+{Caj-T`&G@mgM25FuhiG=$e#hv0mF+UzJRym8eLDupRMUnDc<>MK`=kj z21(awgQVfN20J&evb&I58D+&SVNr>K7t2%?Wr19X`OENV$soU`4=zm{S0>U5r_JSV zd_m&uf!Tu>#20!CRKpP5;CfzZwx5HO!VF?0_Q5(c;)&~==bgxC`#hPI1gYigx_nE~ zpZQEszU|1n!HvL_?|aCSe)eTuzN)YE?hjja%?1yP8QHNXzsGr3Jow$smpmmuiC7=z zo}otKgJqDKr;@ojiBg;w7Uj-R@d5ZrP|N#8i?aKas6LTViok(oQ7=2z59gIJJ@`DW zqO;XW&R1=0g6_5><)Qhl)%l_>N5%ZqylNKmVz3ODa$JKfDL>Tz*+cf#4k<@!vd5*K ze>p!lpi@=i1JR z(aIsN-%s5vvDD=E85hLXIaO+~GmikCvr8}{^al@*=0u9e_+y8R@yCyg=6qIs_&>+V zO1-*xy5t&L=Up&%Ty#wIg5v3F#>;{HnC@tHG%C5l;3h6+hPf z;sEV#)(07(??|X}89F>>x zDHK%=KvjH66>>I+{jiSOa`U}sEnzn6O zEa7X*TbxHDw>oxVwZ8>K}&Q8ob^95x1Tx9I5i+?2)k_7t8c>*&ZeI;b;ON ztWYCy7n>;T%O=ti_iW{7)w})N=vn^RC$98Y$5aJ-YSA_7>_WGoZ;6{(#D0Cvy3+5@Ndfe+({C0BR?x=ij!azt;nvH!F+*wn>j^%VSM%C2@H@*;3LkRmDDgDktUJsgp(Qgm3 zq|Rf_-=}Zg%7Mqqb2qFBx<^qki{B-ed-kepl=a;}J6zL=2U3C!jj&6dK)1zs0XnsN z`fRoTO6#>B-U@i7-VP!=r|~WTMz2z2NypS{=BAAot=Y0|T}rVfOzhVLdU5*o3-pRh zoIvy%WprxbL?~EYu+I6l)~69ZGY`ESxf$#VbvXJwG<}{@x9~ z2BrO~D3JM-S72L))m3yV8xWZleahXzSOnXB*#3%fF*nD3-X^3k!AzKXRWh<*Oye;P zix>NTvX~vrSaiV2?p*nkOy2t?>QC~|WB7K%Ur_J|E6g9@7>hs2BR1r;Vm+yS%XVK; z7;!IB1N>*~_#YI~V0DTZUo>~>dhev%rd~cm&N!WV0j6FCB1`IRr(^16^|~#X&1~42 z>Yh}8QNtOWc?<$o!MVrFw)My2N;f-EOIW4BF(PbdWXt$GmS?7tkpr>ecUqq&_-f&k zet9GEqu?oE^!Z<8Np*MWcB%;DBN%helOju0u05D|PAALmwbao%w~{!{biL<9 z{3GxhFnZp1hSu}WFKIoSzTI=Y@1f`E-8bYzjmz7euQ)F{cDwVY9efoX^0_|v&0{L~ zniqV2$qT+-*T0(-{P3AW|9(*LKW^6lV`T7y&i)Sls|R}hiB#3Q#n#?F(t~}KO!O!E zC;oALw_haEKQaKPZuH-%?cpduani$&S#EKpxTtuKUHp(;9G^T{O?kkMU1Q_;xj1vo zAT{^_wry8rMK~y)s%B-0S5Eb7JF@rzJN~F0i42M)%D7yO$HKfx#eH}L)QUtLqaD88 z+5vbg99?WjhDC=*M{wnOIkZ-*$(o6N#e6r+tn7;g?FiYrDif;1>2ZwqK*h+Nji&&)ijDTQvJ~; z2E6+p+pV)3gBZB2f7j)UE_1v6tQRBCl%Ihq-(Q#O@+HFcLh{v~{auy^!90q1?tAls zc<#43!Pj@};A?yEIV<>l)RRc>dsQ<=@#TwEBra2!{5Y=T!v8XvAhH*qmY2_O$&1;a1SIEfh>C9Vo5(5n zO_0xp{zme_dvpRP=?Uds8Nb?ADiKYpae;&BGJ={8*E6;JSe{=vNF@vW(we7ig-=lV ze_2(kjLq_W`lsYd+B`bVuUil1o#3BX;}o8tCRMr7nO@zj?C40pc0HIk)E{1B7YU^@!o<=b*eqt=BeY_8y)BOcBE6qXWQ%T z^CL6x!W)?yS;g7l;>addkLBGwHJ9Lw_3CoM)h8MiS{*YWz{bV`f!2bA#un<;>Lk>JjA6gBOA6hfl50{qWo2 zJp0*jy<*-Ea&3W!jJE>E1TSTOBF6;3ar8OCFL5GnpANFEw<|{SrtGJEM6W?x*9`u5*O~L1z_9t-eRsYPRO~i2FCeM0*E_S@3VGvv9~mOhF4gbQIII$T{vWW#ubrB z1djyK#gSy37@cmuQx&O5Y{Z!^;n)+C9+SB4F`Rnzf6Vr7x3hAS8J^cKH=0v$tL@)p zPjVSd?hq-9ou><2uPAFfudrx#rtiD)of%hnL;e3$`5#viM&%Dx{vWG6e-&{+$Jwz_ z&O~nl*UM&kWBg=HHRfPhqZ%`o(HU#?;oCM zTq++RPnRSj~_#R0qg@tk4|JsU7;WKvAxb22(P~WBspc!^WqJ`y!Z=D zhyx`QHwd`k9nDo)@mN;8#8Z6+_Mr;ui?bq(Q;c4o%oR8(9KuDah1$%->a5iI z)viqSlLg3UgH^!j*Muy|oL3%dKO59kFYiWN+`NVxn_S#{l&=ix>t$u_!#O~f+TikV zq0bg~gnd!UA6M-Ftxr3AW?lI+2w;b-zHJu zcH(W~B7vG>xiG{D%o_)(Rq{5J)DiO6otxr69eE`<4;cQf$dcw?ulvoM>w1lg8#p?+ zaQoJ6GlCXt8ioSb$*RAV@XCQ37=p|?*9B$}GjaDj(=Kom4D4+K!}61Vl>DW?{08~2 z;5}gY-Bp^uJ@n79p24>4C3UH+o1RtFF95rV-u_=MgaC^U-; z59Rg%cZO3yaFn2CDh6x4mcncFx)}L7a1$_kJ&7!-?mn$g^8O?0)nn<258_#Y@8K^v zx3Xp4svhO}a0n^FwoNpWbXEnsHuu=R)^K&8;SRUl84#J_6__Y^tVgS~p4RHrbDxjg z7nB2|=TKxxN7_Hs&;5)|o5ZJcUhR17&s)`^z_Sj4#^vm1WN@RtE#zw=KePV57P$r7 z1q|O~$dYaf{h1tooSA_m|G-MOX=nEc^OkLWL=zRM+UQWPUf%sgR3JyvE}MWt9m|Sy&0RsI50A zU#&;C5!=;br7!}#E5i6-+$B2S-B`Nkxbad9((qmGMPn|Zv7B6{i`f}O#L3+}! zLz!qM+9yiyBt+sJm@3rV<&U-IMz6IO?jNacsmNfh}Jr1^n z<8@EHyU#(}>^r&GgI}S4^CcbQa}I9ND+xW{H-b%M+-2i2N<=;adZ?13u?kDOYz%FO z)cadxJYZs2t5E@k(9UtuSe1CYqa3z-i-%r2K_Ls8fgEW~*GkV6s1DL}JS#iuN7b{gSO%`v-NcPnK&Z z>+c7?JR3 zsp908yrM|NjqsZyr^qRmZO{$0K(}E;^AxRL@%og0W09wUS-|MmfP8HIX0F_birVZ& zrWJM781ZgqdP$Yr*4-G1#v?_}X6cd(+~rCpHesrps`Y4v$IOSng4_1W}6 zn$BB#&R;H)+oe6q-flm}Rhn-9nd1YwS;_61U>5TwF=@8r(X2!wS{f~jkMsv8CzMZ* zcp3E>K@DB5wzx~2ne--VO3$`9znP}%>1Fh(K%Zb9i2OJ30WkWOTzEX~g{#h7sLrJXLZ^#&E9_iZY zTE9m4jegsZF9w%}IvwqNR<~bxnI;=8vaMfdV|P>+=G&f@?@y8c0=j@HckagHDYrIW zENa@yOW=C*N+{w736IpO9(Sy_Ov!DGnboxXEk(uh91$8(wxy@ZbF|teAkfveJw&>5 z*Nm{-@SFM04&*z*eZc7V60)R@=XC$sa6`|2q|3ixWs@1o2#xi9=MxEyH6-{vA^6Pv zB!!l9;fjxKMsDb+tKk!!&?V9I+EvZSMr$LU6LMR;1a>q@%^yti!Y*EuraWd)am zf=9Z+y&@d+I_k9^E$~#pBhT^E$j^fpfYIX{$dZn}9!WQbC7PfNcc)qR=9aPdQ0xV3 zk}?_hNVRjr@^4P@mLpF9Q-I-Ji!8~MzwxmBv>~=y+3t_bIU#{X*1{&`wpvxkGiZ|K?7cs-fAOW`k_(U>`4UgS)k zp?o*)uyyB`MY*yQ_2lYNwc1X{8etUcny>Y0fVTo>X}|N4H-as|=+%rY>FDi;UfoN| zSwZuiW8I5Cn=GE?go^vL-C#9Zny_Jk=6#ubO?`ACzYYEd46nac^A?Bg*4vI)k2AvC zy|lbd2Ewz0De-N}db&U=gwCXyL^ls-$ooHVDy=cEXnlm!>?bc zA2a2e&x`R@{bGEPD;mVdWyE5WI5R&^gi+3flB#G+oS!*EiEu*1Zan+?fe}-+TE^u2 zjG*guG-&Z{kl&W^8$Ab1tVpw#ZSv0i*)y? z(5)wJHyB4I#sg5}BCSVqd&=*@AmpiF1~7W;MV54DXh-qwZyxS_b=rn?!4713D>w5V zRyO;2PVm)XKO7AHH%G05MI#gWQ7R>xQ0^40y^6goZ_u##sHpUDPYue-#brZrW>!{$ zP*UPf+aFMX3DbxX^Rpt64EdWuUQXPd5SgzgvZnRDf^xrN#E>o76z$7)1iPh;YCeI+ z@b(=aujkbQBeJUwdCgWX2^dUPVcwlz8j|cl`(c_C=?9M^e+zsU7<~>R2m0Kp>%I1# z!_~hrjA*m3(*xUA^w*YP&A3^Qa^G{U))Mi^o5+gE#xx6`!ajaUkyoGKmR6)#6|oOe zM8MGkc1%VL7~pS~9(%EDfH)`NT4I5-9N&3ijdm^7`Zrvhdd^lOH-l?|(f_l^l8*kI zoxUzy*qq8!7A$OJQDYW21;OIx9c8_V@5o?rPF=Rx!^<5O}6I)g#L=s6l$Qd?+;(*8itdJfL>7qD-;VCA+|YlD3#wI=A|x6|R} znR|r5(;Vy1W>fO^Al~5lxEvnE{Y^$oQ)}E)TcP#Y1D{#%-i`becorCa{)Q~6G4wOs z9NwEU@3Wbkn&kcu&TM|8o!LCbm#FcKZ@piNvk}~lL?SUJ>q$QG@~Nhl#|B5@d1bND z+1Y$Y2-sJfDDP8S6dRqK?&nVCR^G^r7zW{)u^rOzE7iKl_icBMKPPgEUE`ds@|^xy zS_FnZ*!7>I%h9kiRgP82+rUm>%JCUwNfn`Ap0~ct7-^!`L&-s$V ze3=8m@=7%{lEZ(oD9-3g7jpJ2zNAaN0yG}s6>v7lXUcf*1j5R3NI#i_k5TO6$$x2n zd797FdPgrwJ$HSO2Z3r}^qzt&sW`M_H0KGX{)6{tU;t6naILJww*{S)SPh*ObkgK- zcbQY-7UtB*;()-t^^`|a>nhE^hy2ZRe>d{8;B&z6{}5SHdwA~C*lQnu`I;?aRa(@- z$aAYWC7l?2*54Y`Tf4G$SE7al&E^D~y>eW?o#mEghUSek*iT#-xNzuPt@SCsG^NiV zg4`JAeFZlJ?tXK4d zvPeHCU+}G$D|t@h^OD2F39UbiXJiPQrg_o0Guq9}E=+id-Kvr)DjsGdsyJ_cl*2N) zl6{qIq3*DkW0O>+F2j`MDLXTCTV=Jc)8$x;p2iOEQsf_lp8`{k&6n$Pj1A9;jNfKc zj#b(W^OPp3)yAL8#q0u*3;rZOl!w2NUkc`?{k$+uo`w7c^VgvuZ>X=tttb1-o!ue`C9Y=f0@1Xjo%S6-hSH)1Do!5haX7N7nl(KyZ-;(3MV7drfx6_=^0Y~e2U z7WMp1yv~~%{APB1Lh!G~dZP+U;wrb$E2u8a#-|H0+Hg*xGZwF@& z;J0T`&)3>&w7bf|qu*HjH<9r1!LP5b-fjMQb|K#a?f^!Q$B-p8hWpF!hwWva18Jx9+1B?0ThCU^X069j zVyPN}hxk19VX20(?)ex_AV_{&G=CTQ&*5j`cbd5y19E}k?~g30F5Fi>9Dnx`snz~j zNdE!%|Dit>!MD$)~th&gofST>ydPR?)&0oWPxjd3565F9xUUA9ony-=k z>c~&{HX~mGt^|hfI%G*l;WLxLbi%iK6SjwZ9pqO>e!}+$N^Hy-1gH&ebX2vynG|&A{+pf_yx@slwhLyf}-4 z7bm6w2VwtA$UaNWkvf*taIxlpnf&YcS<3wzDY z1e^&B?`q^@@TLu?E%rTBc<>&!tyZXS=`QgYUE;<|G;bUE){(K4_q)g);OD^bzJYuU zUfMY|g0|Stgv_tl)-y0a5;8AR0dwu8nz!oO6z??Tdaw`}-ZPMo!7J^21mZ6oN_?5- zZ6)72GM4i0Lw*T-4;bDKc2;M|U$HyIKM{Eb zI2joJ2IOP#YwEO@#<#+k#_w(GW%&1X^N%;ZoAZFn!}61V9Rxx7kzWGe1BSl?`564c z>*5IIf9*)+Z@WVCS6r9kpNKpIoD2+q1M)HWHFercE3N#mAF2GUSBB*$|2hby{4XGX z6Z|hQ{J%n$)Do_XT6(REcwgbIhbt_>yt$Ft@4RzlDMGl@KMtyN+5YgI!a*?(N8D@| zYfqUx&Bh3#LM9NTre>{2)t;0d6Orq|LSXdRfGnxi>=*R1XF`v~qcOFY%PQ;;*fvob z=mw(7i;lHxaHSfFwcQ{!FuFu`x|}SQv7^{^F3(7y5(gPItXogvs!F)yQhT-5s~z4t zc%^p9&@fwt#39XUj~|i(PI~~q$Aq}ZtZ>FTi-iQIihbIM(Yhc z$H$uV0_)>~3oPplmw@v@wpK@|M+ZDfekJwsXXL+ue*mM$e~=}a^}C73V&<1AJLME{ zVAZu3tFF7TU>z#E?t?ft)5NvA!t&ps^A+AD$mfCe!0=ud{(r+~z74N&g5TJWLUNtO zZX6Tz(_3**F=YAoOXmKd#Q%Ot;SWl3zF$)CgA(=qlF}cP&>9oz$@C(t?pm!!2Rvq- z`4{95z`udf;}c{_M{bAEb4CxJ^`~(XAU^9KRRnmS(Id$F?y&qfrg$5X*MlZtc()-R zomb9yk4!qJ2Pyj?A@4q&Z?n|miqdu=b$t?+xL%sc&sZ7VO&0#N>(xGqZNe zNEQ)lt~GiD=02Pu@*g#;Q}Q}p&f1$&RrFGUl_)*H!5HeA9y$o zH*0lB^e5F7mV1R9&JGHk$hU;Nt>kOk^+n{Dz;{C~Dd&b>_iHsDe&dh8HoAgOvst)ROXia!zU({6B-FKd{tp^E~gZWV^ z@<8(*U9Wq{*F3j-kv{{T1BUknP7LcwKVGdeJbeBI`Qst!Y1wBM-9yOw+n?={Fb zf)-$S??gTv?_r*sZu7{ZhTFxm>`C83S7ms9R6O%Psql5@0_z_*myvPUx<&IYC11n49r-fQ3=Hoz$dY>3^I^&> zucYoV;>1&;u;8sTdE%~L0$&V0+M80>K!jA)sGCpPy$Hnfsnr_;T2P2eQ1{i8Sv2=^0bnt zDc9GLUj+Y~#?w1a&f$2vyX*j123Q~21K6jyRkxRQd#W5I$Yr1sNIKqfgf5zO89vr! zs15UPOw0cg=Pw#`7rh6W}wSk|%ui=wj^F3~gcl2h#F)?<6iZ z$N-W57E97Y-&qkD%dCx1zKLI~Y z;~5^_ALu>LBv@BCoD8k$9@1)g9%`)?U{$o}=OKAl%AeP0_MJT3En)uq)AD~0`5)k4pECdO zc972eZZapehxt#uJJsH&BQFIjfTZJnE>bRKb!*>CYj=kE-ZJ2)}dF>!G>93a}UjeR8 z%RhP?{ngBKPM`=UunIhZ{F=i2+sSKBnE#u|e*k|<%fD&2UI!elzXtiIymM)q)_}%p z3wf&UP4Uzt&j$@alC<}y;0e3cbV{QUWOBQ1j~4Q5<`+_5Uqs#qzMjUj_IT^7hxabc z^EiABAwx`ssOsrqCqM1tiHkbbsnh%l{+fPk{5lr!I%~ z?x_jdgrGLezmB{rs1xb0%aB)q#|JJnp+mZhld@n8k_b)m2 z^WDP*lpY7aWX8efkSF?JsvOnGBfuyiN!t5(cv2S@1B(OAv`;g&hCEGaJa-`94etMx zJiT2rX`-(NMC~EZe)2TW$3f(OgHO_Uj_3K1gNkm~OPb{CrrtV3o;eStp7ZmOH-as| ztUInBTLtX-w14&087dQn;_XB&#;^*7J zb6XMe+)JLOd|yHSI%rShIr8|~i>KG(=eyza)e!Pn52wmgj@%y%2A{e-Jr+SPcMo(; zA{57DpYXI96B46MZCAo}tLYK`r>y<>|FZ`dP@7 zyjwp%P2_3%_3g-af&0>Uj=Nv?p8W6E9lI{%*`LPqPvj55$Nvpak43<*!>5P&UdU7T zXsX`MMP38eflpm;y%z(o>xyd$d7e(=`4Msl_}PEMbC^ZJ8w~1gAy4wLRQrrX9u39= zQ=a2)pB{^X&hC2a40(2t=MFNJdBeTP4}gc$c#ga-=rz9eTpYZqXYH0%agXkAo#biO z2ma&O|AQ=G%5&s-`{8(cFB0A|bXH@?*FfHe?;_-#;PU?;d_5Kme`Eq5rnZo;oxGd* zoz&x>k^c(*1|-S*=*a7Z!!*}HQUN641 z#lxTJ9kpTpE#zg!hv$$#2fmn=|8e)f^u@#5-QCY>40#TcrZ3iw7E&vEy&^u@&oseX{W zPq&Ztbc$yXaupa3OnHtx@9)(Q4ztMkka4v(b1U-g;O_s1=dg>6kIb~(Y6$uE zr}0^zVa*48@Ttpn_{GM@hOjB*n?v5FpI?aF1h%E|9ryEem_JZ)(_9mqcg zzdSCUbUTAXCf|FU@Z_N_OrECR z9z=c^JeJ0DfZUn18b^bjk+bs~(h55Ip<^K}$cfj{Qb^eE$WZ$k^yfNg7KAS4X|3})D07g-y z-LC4c>7GfZGr7YNm~ez}4>&Vi0^tT_H3%wr5sn}z$8ZU*u0&Ks1&ucP+7PFh}Dh~+zrLZOQ ze;N1{z)FYx#PaW4%xUCxv=klGHSmVd;~BC zkmZw@{YHz|ZL&dC3Z2ysorl0T0h?Q*<5;{t4UrmQ|A@oBYa5<_0K7obemEDc+oczn z&xKA2Z2Do8k5?Ci&j%JcbP{V%&P8jrRo}jQ?e<#bu)iPtAHe$#`^~RcW7@0pt@mPQ z*Y0-#p_BJi)Q^+FhXNx2Szd|hG`U#a#g$5gPPs$pA@EJW=A?C+UZmDQC?a%@z^3dc zo~KdwKsq4(Nvs_=u{hmrms^Fd{Nmx=rT28*%V+m4#`!?9^!{yi9DQm|D68;6&$8) z;@HsZyq^pEwXh}q{R;dT@V&!+^W$xU{fY8j?e-n1H?96xFYE`lNAo`pd^}JB@RVTw zV|L2-i6O*ypIu)S4*QRSZw9K8vmdiquNC$K!hXHOzUNu=10WqpBLA_A_5HR$iLhS+ zTe5x^fG+|rNzQ%~i}m+}7ua_dI@J!Hcfj8R4ko7)vsgbM6e@)Myy~bQCxM57fj|=F z6t`Iaz*49Z_Ln>C-vNFXaBp(<8!ys7ZYU$+Ajd_1QY>0op}A<;781&{Bvv6z_=&u&xS48FRli^7P!G-zxny6 z!G8Rr{0Oh@8exC0!~PfGM}cF>*>7Soe$<}aPzH5EC-7XfoW_BV2TFh>$|+_s{bu{tSWUvrv^65@hx6nhrz!9 zzH;a^zyBZa57&v=`Tv1y1s<@=t?2padT=QCa9}jR6EC;s*R>5gjv(nLQR}#$FYK>| zE!n>-!5;)3aoA6we>;Pu<5HkP*gpbWvi~W&um=X{08a_d+s+{A7dg^a3HxJVOWH33 zpAF1S&VHjH={Jbf3j3QJ_IHE70=$;AeMfNghwVYVuy4E&&3{MmLZBOvMEM~9&futA z<6Ek}2krJV8@Bwo=Iyi`{3_sDhy4WFk25G*sfnG`Vqt%;!~PfGM}cDw`_0EI(e~Lm zC|ae-ajU^2iHZ$}B}G#M1F7E0wpXPrZ52l(^Ai^=IU9TZ(}3snjo z<;7^dw+HV46avzpMCPT&$As22lv|C^iNL1p-?xI_4Qv1qAz0;hKR8b(h>K(lBo8u= zp0m7cW)Qy~8w5qq3UPbI8^yQ}`%*uBx2CiO3IM6!8JwqPk5O zX?`4y*NF>*wlJ&5l?a{wFGc;C41O*!72qj3e`3O+D((wU5usD*(5V4`33#ot__Uh^xQ$YwQx2OET=RKx6Zqr6R)#yOb)SGaEK#JX8UGD{!Ynr}?<6NuBucYrl|F>V@7xhu)vy^mRM~3P`__){6>ZVY?jP%RrX;uimYS{J*y#wIy10Ol` znqN=H>p8-*gR*sCUqR^j--x!uq2R-T(Ev}$jTg@F?1KiOdZDu#Hf2A41pF~zi$f>z ze(Vg>K9tjx;(OGtr+SA@)|+_d1!x0Ee-hVe6s~>D#R5WSGHgnJE(O0FC~v8bBW$Y^ z9+e248i&py@XvrRTdLy>-wxSA5usD`RN6`C9cu|^+08d z^qLOuzLtWI+3md!wq-kXy^Z^xfESSdCEnhfxc7BTiXr|GdXr&W&Rds(uLM>BGS0dV zoTp^ty#5$&P88==3jKqyFZF*0*J|N2AoacAJS7+BarG0&d8LorjoF9R+U znn|n^`Zp2h{la@>xzMSGP3h+c;2!~>I&>0TA3!HA&il>ol2t;-|4!7OV(<~b7=Wkb z{E3P4{t&~MQY&;;J9IXIKMrhdkxopUSMCz=WWCU-cj%<=$Nn#n2PE%LY@D}J2>CYK z?O-x&%64!C_?5slEz)Ts&bwNAh51J4?RDrK0sjj4wncg|ao#GaR3dZ&??(MP1N=;2 z3XpvH#l?Bo+e#6kv(BOOJa`T8a*K2t$9XqGszT@}?`aM9$2x#_2D$>$p9JGP^rN^q zufi4JHfn^@g8`nB8}FKk^X_&v#CerMuN<~z`Bj2H2t4A@OT3<9;=J{; z{Az{H5!hS~A9(w7|5H;^0Usd!N-)kt`NhV08(emr=i4IYKiHIU-g5BEfE5m%1miBL z6CdYQ3OS`j=+!v%z5qW89Q*(1#l(3JxMZAHDf9vdqjBE3;1>YX0a=a-#(7cy8pU}V zEzNqNR|(sG80Yo23;adk6^CAe>u%^d;=G4t>%h8gt6gu#`_XpT1-u*33y^*#-VU8{ z-lhhj5}^};P1%oc0>1^g!=aOSKX%4>kI89Di3pv84xQh?{{++zqW&bV(f$J3I#d9q^+=FY)%?M4Y!% zdWZN!=oNny9WQ2rUkoe&WSq4KoTp^tyguRo5$HW>x1So=m-FT!@Na980S_9Ir1miv4pW*_(kF9{u|CHUICc|b#=v)bYHL%*DlVH3T)rkxE>O{a- zD)jckwj3wE2LBfLk3%nsaUwq8JH!Wy3ZWDDcT{Hr_#|L5Aj>ZaotS{{uvj6~2%UAX zDf`t<@E3rW96AZkXT1F41HR9BtEdw?%HgO^7w~RCFF^W}giaFy-;wCV`Lx|GBCsv% z>1OcTfOQVNB+4%);5#bHFCcUd!sc=~!Q1&S;J*Xpv#4JQ#(TW{VgtUf?FcL)bc$h9 z#(Q(X=K>LjPJ;1XgHC+FcT5C)RYI@Ip?47cU%)5-FTI$6uigs2c;!E1*O&iuO(_@U zI3E0TU?RX1pXU>d_Zj>LodPgH`j9nd_RcRp(y1- z=QwQ2c9{1C?tuaA0iL*DNwh;}!1t3BsuDV-uqpd-Irvq;wGN#m`j<1{J1$4|TA{Po zq4N!RJ@7-zbQ%SGzd)>B=md^L{W$~tOkfHi%Pk3ipyLSmezQIDZMWOqI)~14;Jbj` zE!J@ce1BL%0imOO8EtQV@Qy$iK>CwJdvgYSWU-Wgfy#E4T0!#vUN+RAn zsc#eU-W@vLcOY~sU{m_}6!>;vheId9ahdDH#e3_lE*TLz$6-^ppH|=CJS^Y`THsGi zymvQz;i*FCl)|Rexf1+pV0FuMV&c8^LZ?dT>~-iI1^)*4u4Ov0@!keos8;9%jz#@B z8~hyL0)VF^+d&iYUZwB~?>`WFl@7fZ!CwaUwoET3-g`hO`TlOVZ{ypjU){lb0eyiM z_!SrLJ!~ljgigeva|ifcz`ZTgX&mo8)=+#(iO{Qq?NT_w$7Qu1XTSgtApJ@(-sAl# zF5cU$2VkUJ=!}KUh|pOGz64nA&`B`fi|WM1ds}q-249WPtA=ekPJ9Ud3Gi=+UJ~O( ze7sl12a0;3`6U?dHR#00 zdpm78#rK@uE-D>*d%@oT-u{2-#l(BN^kG)kl~SSS`ym?doeVw{7y(HC5{&m8{xypC zYPe>V&?|>+KaBHwyAS*U;9-Yeg6nUt=ZN=qi`IdC4xw`dHf1|Be#GBC0MY>IR}$^e z8SlL;g?u~h`YM4<*^eXOi-Bbhoh15~Gv3=HNA`fwsdngm1YQRmZkbM_cyBMnN`#L8 zr>H-}!AAk(09kHH_!ArNy>5FH5jv|KI*)^I0k*YR#~JUvX$e&boqE{xBlEny`TmRh zU_dS){Yj#|Ipe*3vK`b2oyo8%byk3{1Xek85{$pBcHKDM+utzG)(O464!!Tde*liR zOs~m!?>(vbyxq?GACLMs9lQ*f1IThr!oQ~Dy#uzOU+8UuZP~Bh2Hy`HaOfq`4x5Pg z4odHoVxi~%IXYg91V0rx9UyR!uXE1;=PB8EFZ@3q*sBrxm9Q_ztKHyl0s8@|e*m1P zF0ys4+D=mbP^nw zxlUZX_qo+2YlY4c*p%(Z{VUG@06w4v{=~$4N9z|=`@b_ zjyDvaQYG|iVY?Jg@b>o~@SlKR9C``Hd%Qoz#e2V4@m`(K>HkMG-kSzK6POLi@=Gw@ zi|WM1d%uZz&tGG=_f4=Z$B8$=-v-`w=p`{u#K(Jo@PVR4==lDO>hu8*0{sE$R}wlg z@m{$B5u|dVvm7>MyI2o?AMl_I&>0@_jvim#(S#` zE8YvdXtz5*VGZ~9#(|FqN&s1Y3C4R3I`Q$|^|qW65qcF4y=w61fEWH>dNJ|d8e^E1 zb)`n=DU>PY_!b{8dVu!^P6Bx1?IXc>&*5LAc<)B8>Dz6WX9TwWu*>ys0>1^g!=abp z`kU)H;=KydIuxZ?=p2Mi*$$6`{|fx+&`F{lI^(@tq)ALgk-=xlQ6yaiqhyw@_FM)BSq5UUb8J}v4`U+@qx0N^P}e`4dkb+$*fLT9-{ z=N|A4zymGTamIUhTSE0hrw%s#$UARu3S){2=m1aLpCsCwGu~S-+kyWjyIqfkO+U=oPJ<*+UNT@QXA@SsC4!SUJBiwpdo=6y3Dbn0MJwj=6h z3Ip6gOZ8aRKv9Z?P9T*v+~+$7{Cr>boxX+;z7x=wySU390gir@V&sB z4!vZ?iTJ?pO$-!OLdWn%b-ID~1o{BduVi#$0>6FsN}*2ZL|{|4i`&810qY$)3C?R) z`Nao*wY*ilYPW}j4jskBx(Cn!=}$5`O$2`X2ML;OF0Kw~ynnT`tP8vyUl7Ko3CrmtfrI^siCi z_aQVRLT@%~`-R?W@Ed@e9C`_^!!12W;Pk-c8%R62C_fWHR3)k2*{f#2bVX+-h8X15Dp zM%1s9z{9{mpe26A27sSiVgaGE+@Z4`{665pmg_hJz$09!MCjDPrXQK-;|0lNiUt^f z^e35i=L`UkiuO=0bjHG_)QNyE29`N=5{!@R_T4xDJSNB6N}*Tn&^rYF8SrHb^_mO- z>utpvp;wd@^=~5hS-?4fEXQR0YdQe@-V&@6dh1|Y&XYCZF9EMQ^pfdcP2BMNL6)cT zy4~)L?5JKB@NPgaK>F9b-r~7)W|TGaX8zwAI+$PRL|{{nPiw&|fZH58&5utGow$JK z546P+VZRo(WVw9>ehm2DVLu^1Vgj9VH{Xhi2>XGYsQpvHPXo>Xk}9W|0B5CTze3or zaM<4rz7=>XS^Kep&DC6>O4zS=*iX-8N*0g@B$fXr0-9Bp7kKZa(3uRIvK|(LUjqC! zS)G_bX0@eIFYH%4?EeG&An;+b_TvJWHBj)qVfTl;ylDRWgAW3R0!fuq{7I#1?753|3D^C2eILa$F5UF(I4pfz} zUkO|C`LdV5_W-Xu>^C2W#M_S#Kpx;SO1;oA+D3J{f%gRZ06g(}Pevyu@Yv`c#%&b8 zWw);gY?kAim)9NOcLDc0befMl8vD~I;CR^9;(8TAuMW2TLhonr-?&zO)UW2(e-1rI zz_Cem$r@q57`9~lItToGV4A~zLhZ{LXgp>M)C>ESuqEe_9pKLcFFNceG@m;IjLmjm z^zF0jLunVa-yXaJPzdmpaDQ(USZrzN@ByJS+o5wc__e?dEzq&5!u~s-Ra~S**x&20 z{~7oZ;OiFHcLoyMAP^Dui`qxq(Qxolz&JpbQ$p>?89+R3*K?(?zuIB{QSi+`mBW7X z>uYB_Z5%jMi}A2V=+rxOGW|@+0a^pnkA!rZ3>bD;N_9eKGHm)`l=t(?!B+rRC9BhP zps>>tdfRTlHLxlB$EVL z<|_}Jr)KXPwJ2Am!>zw_rsI|W<#^>kpv=MFInx!zUu)M(DRgDNmVsXZtOR7ft^wyM zetcYlKXKNp*X(JFXZJd{Z@=@AJN&6P6me$Bd8ZqYTc&8s6lEmsK_G@yDfDV#PwIUJ zUJv{TNWGuId769KEbFs!vHfZ5l`V`_%Z;p9KqBUX6ew1~K|q;Bi-|`mdB^szxMQ^4 zO##0MSO7@9C%}2?biJ*!?i%}Z*1RRXin`%z*IvsO%~?`bGHvEe+r!){@(9^VNEO+F zj}&DSJx-OCq=1^PJk71SQ$5t>Dkz|x7}bd3%A+1)QtH;-E)Pv_M-9@7w$H%rEh9^3 zI!p8LKfkb-xO%I_v>)eos@-qrU+EO>pFZ#+peG>ne-SuOlb^KneOP=t@*kNt6BX0C z9DnuUPeRJ+m(=?B6(1ht{zYBcPCC(i{3SfN2DXecan^8dQaB`?`oor)ci!Jg=`p^kvdEb(C#V1qsjxeKefoO ztpCr!{{Ym^QGbfTd0M{pME*1c)={rMjP>eiUHKs1t9~u;YUByM!gIqP*nVw7zUBB< z1O5i^HX!Ti6L6k>_?zulm1x(FdIFuw2b!{J^La-q9y*j1cOI&vidHCpz!yq88XmQy zMpMwGMruLcjg>l~UsM>?F9x3g%m$=>u*?5!=Ujj3{5dlg%q)X`ZXNlJenLncc~JYr zYAAPWR3{%0eDMOUfE$QXK?`U~YI~PPJ(;FItq1GefvIg>RKxdGs_AN~n&L{;Xltr! z=nyoGsxCE!;X5g~O3~c-8lYb4Nzqjuodo~2N-t)eSt@JC3RsHKh8b>}Nqxtt{tY$g zVCtq>_#IDxbu~2AfYo-aCu8_+RVS>K-r5UfTL0Q>e=X2EFpDvwXTYAjtB)13?ySA( z(Q{aP-LGcjvj7eCIHhg1Lh>`APZD(^oW}b8W4nG=qx=H6=JRAFcs1}mAj|j1BD;K* z3cG&&H`h$Ft-5w3EfR7FR&Z~ zUqig8RlSvtqQv)nG)*uMbL*z6vfes=qn4;%6s6&Exd?2)PRif89j2p@pAkQQQG9m6 zFy_^JYHewO+Q|c}*;KRgh1$;=calq2Jszr4&s4Qkr+NG*=d0&YmyY4ko2%xzv{d9C zzS+KXGdk;oc-}I2PBm2ZP&ynXk;Ss}C>@}l#{L2f?wZ4Tvu>VNUS|5ySOWAU#;fa) zifrtmG(!GHR**^fR?WZd`WxF7W2dOU^T8JYO8{AacYyQM_By-XY8v-XEDPq(n6|{~ z9OY!*3Q|t~!oTP%_%M2yDBo)ZG#y#jDI@u4{Y*7n`794tX_Th=Gm*h-h%1{EW07^roi zX`EOo@R_YU8Fq{D9p0Yjf?ox!2Bhve-ECdpsuSx@Uv7^TyD>;$toVXiA6@Mc<42Ej zH!IN6J%vUF`YmtBx{IB`2DCRasi_S*NgasZoA0K%S{|+orl{w5GFXa>=6FucSKF!i z)=xX+X{}ryHC>}_Q%lwRU2H629Z}uwd~U;&@7A@}s^P&1kkW5TiuDtg$6UVj+$ri@ zBe&l~{Of#7w0SJW$2=49y^Dd4{l?f<7-OA$9Wy#*p3REV2jP2tF!H3Z_Fn4NwDFjk z3fU+F>KPc&4BhKR9e%E9J{nM`({st$v=7-&Xm@fUZEMfnRY&detw#CD_Vxz&d%!_J zmhT~Op0Y%}HZvbA=Ea*?L1x}Wc-5{@Hn{TX1m1=DN-oWs0xUa$uWa2wkLWlx0(?9$ z0g$@qg7XylAM=pVEwgpYiLwd8XV}6QIfSc(?k3ok?RW?H8$c}}b?d=-`XB9hq1~GH z5UUwoi3x}=u#T$Ac2@z$fpo)#b~FLg-~^3k=K6fPhb^HV9knu&PDPvVjl;1%bt&ad z9^b^e^BcQd#`cWPkLQ5T0xkw*{#JnVbb@st?`Jc3{vy{BtUC1tyxU{NdB9bGhRw7L z+6g)E5S=%YsahYJgDjLBv-S7FzFZ&t3;avq7$EhvUbg=KSRX93GEh#g!tln2AD)Hp ziE>P2AqB(wsVJROF$yCSrN~cLln91k%Q<{0`PR9sQJkLP;GhSFMlj_Em{>G3XP@Gy1k$S)=#nW4h}+%ucOR zhkLS6otl=3RkDxz+-}-Rqh3#**VTpg$2@|W%SUps0G*;v(hN*ROf|89?%=^c&vd(3 z)=AWN66PcWlb6@+!lxID6TalUiO}_`>sF$jiIwRY>MexaPpm@l{~-MD9j%Xr;MW3c z0O@}XI8RNthv`da%_>{ewb$7^G&p1F{4(AwY6)BYRx({414WV5zhxd)BV0-{@)fL-5z?R>0*j?Bj<@TY;l12P})fb+C&wXJ_#eA?|N z66xA&)}k`2*h(u2g4A(Sc}8xa%6eqPi~c(ppB}XkZ8rn+7&7uGapjRbQe@}Ef85ST zUZ3c=(-pi25CC}M@qT>V8r460&depVdA&h5S9uKJsaV*JIP6{nz8YAQklm6+Wi#e1 zp0j{2;%(bo@L4MC?seEb2>v1PX+m~K&z*K5Ox{kAUwnC*rkGe7dMNc`Ih~T~(oMIE zdUa-`VD@vlsA{H}aOh{doW}NLN`GAPb~6Qh4lo~(^|b<=r@c4Z^>t)TwA~bSRRMu4lqc3m9r|}xPM7tR6sE~>3!gGmsK5C&;BJ%MO z_!q#}fXv5l;5=14Ve20j>uFwZqa(ca;`=-g$B>5+s2-HnF2J@mx`?w)qKuc(t zcBNrHG1#f(S6jd2r0BZmJn&h-#emdb0?w0vg{|+Lm#xlY$yXut;j#Z_`UFvagZxUu zot~$K8%EmSY`q%TljZ&v_&vwl4Q~V$|PC@-o5$F8Db?c)LWzC8{*Gf-kzy-qEl$9UB-34+x}L;ZZYigcD56I5AX&cb^is<)73(+asArW z`<|%YpU~VbcY8XkH{4LYb${5pMWN_?76cyxi~ywWL~x!ovA%Cy&Rn;WJSK|yO``0x zbh}u^+|DlM0E)SzwXmrA)7Gto-D23~{%!%U2A&6`?pxqIHSh0SYoMqh4v)V+k;j%f zrAj%~BK~l6z1I^w3=9IK{s?fMe!If1=SJ<>lE(`3;+w4IbsbSwYWZ|JZ_a0EJsX;H zF|qY3U{AK^4d7dVrvRzRv{jVNg#S%nziQ{B z5;}h9@cMrid>`;GAoHR0xAReXhg}{uciNx4JnV6G>HLf5FIYC8pG@IRu#Qw?)r(N- z8`b)_fQM3>>BG8G$HPmbD}94dKUN9LG1y|Usq4llG6AciF6?r#ju^*F>r(A9?K1Te zSD`vy-AY`eX;0P>->-Gq`JRk?$@S>P;Fkke0y5uq;5?O!aky%8e7>hon|W5*qUp$U z`%3znb{{2`^vaa`u+rO1e@Ih)(E4HLU=_h`O%E-d?jcwmck~ruQt+uO(yzoJFRX^J z+v6FF?Fqx>^<04+fK1KHHz!&T(O=_E;=u;D{Fmu^##rwPmH*aw?%$o*Y$OY`nc6b- zFol=55p^WVNG(j+LFhGvJWf&z>FM5be54ej1Zz#(?~(ygzh{8Y2NnU+?^WPDHN6h! z^B`(&ICkmacV=KfZxU$JTZhLBlnpE&yIJ{$$IVxEh!?$x(S~T<>=>;$&DO7leHkbH z8~iJv9+3LVKwH20bqn+Z%k9?_l#_)k_?&PPmIDa+y;%L9%(qQ=$C*Q|N!b_zBwx_cEFg%D^HLkt9Ym+~?zpgDb6AGIBAouPT!jA~2u zb_S-TbhQKGpv-o8tjnk(Hpp!0by3>SNBLF&wy0PxbGbDGOL@1-GHBYMEY=FS zEYohLJeQ?ecK&LhFXOBO;9me=12TUdPqy>dNzD5J$NX=P4=8tj-)nB!ay~rNk^>l{ z5M`ED&1T=-^-CNKgx}dYiq&p0yY3L-}}LN`a#4O&UvLF-woUJ zxuqwgU|+Kf_7PRt&kHt(Wvi{J3(Z9@GHA-+RGRHhK@*?_?O3aV)-0WwEM>5dW#UX@ zXJmJjcF-zXOSdXd)c@e}LKK~2O)7WkH_;sH6jA_@yFI`f`chK6`s86vM zR8phfsahX3DKDT0KWZ<*eu=Xf?y=YrEjCiMA!?4t&>5N3wo@D0t`N2uEzm-G zwq@#UH54Shc$O~yA3hCl3b}9;K7fJn| zxW1vlpIsEmb{qTNp2l!^-NkEpzZ{R!?Z?Maw?%w!$5?jVI zW|vIEjTN*o+^;JBli!4U(y%_J{b_aL<8Ec0(TR2&=qqiO6ZJp-lhg<9XUe{zrWC-@eh*}ifs2aSF-*D%h|Cj@<2c|Pj) zi*8gAyOIeB{iz;?{raGj4~4!1Mfcvyi^tPc$ov%&b8HW>3zPA30X{rPXX zb9hBxOc%Mjs~6KYYEM@Qn`^YecG2Z*uBVN=&~=GxC>tpw$l{aia;iW%_)%`WJ!}N8 z1^xlZa@sZAE+@YjXGX@{kLB}?71Rw|#AA81hM(+vvK#G>do`<7tVyvx23lY5z>oMC zv@=WD;qFBH(Gi-vbttXf`kX z8xw3Fs|CRIfKnhE6(l3=AAX2<>z*@%(;8y4rlXb zPiNzD&tmi3!PW!uPyKC9WAi-jQPkT$m3A<^*7C@!(ey&ia2YwqboMvKa$JUL_`$Cv z)+GNvF$(E=q6d8=*p-y;EnxrdQ@5)ho6GXZRJ)I&8kF+EcD)phh{i!fz!w6S0J2^# z8Ex0g&Kl8v--&O(R=u1xZSK-C)J%su{TA0JI;qotWY))bsn*9mIo8J`_SLiPt*g$T zpp|TpogL_yWttSnj?`EYIy+!nWWZ-9n9wF)UBBB|F-pasD zc3<`_B#Y$^%)^O*cAajgbR8XsUC|!eWqPVL5uAgsJvFaZROsuxl6bEnZGIp$!{~Gs zrK_xe`XJG+B6^DTk8}76`a7b3PkQ4zoBvvW)(^jSJqi;K&)w570ewdF&&fzJ1?is> z{ScYdTca*4!?QFN@!)PVQ}Z-btY=25?;fHJo=T^mjGX1rdx&QewwCWAnFI2&sDB?} zZy}u1{I3)C8b}KM&+&NO`ssQ}7nbMCbLVRXE`y!z24^9cHyiUFW2!zvAK4|x$o6S@ zs@MA=q5X{_Q^lQ}6^?8U&<8eTGNgwm&Fp|IWEr=THH6(ja;&fVLqva=jASU6TM6FG zaTCe0zUucA{Q)u(TgV7C?jw37nUp$c6=Ba(&mGitJ~FFrp)`wS=4W+IFU6$Om10L( zJ%?tKo+^sM*EtP0RlgygAs(9Q>U;yCHeSpw)2y0wdkv6Gqja);`&$*u1 zV%HJ{&+Zh^U0r8X3kw<7(o2o-me?Vwl<9po!_$J(1?C24~ENJ$a7@EDhu7U6gjo`;kyYXOnVI z${3;@B5nSu`c{&(^;FwP)a!`0P`!a*E?P_Ych}O4b5nYH2B%?)YQ2WEx|@)h>N_NL zEg@HE9})T}#hk1bYM)RypTv$5ZKnEw<9FyODCdlllz`_Dp$hcAmlb9PDnRwj&=>49iN%#rF8KX-sq-S`Gdx@FpO~pNz5g_|w#W z1Qtu97cH1)&k4EZXxS@BIoU&ScL$*~Rd#v{v`pG2sGo#e;DmMa_11c+sclkd0qz#0 zdT^TwF^Gp^?aVUssL_^3)wFA#n{}hTbyq6W26_e{tJ{cHZQlgJxLG^b&UY#DCF7GN z;5Pxc0W#lDgY#6;+&&6&jbo+L?RyFp1UC%P1E*MD+go3|*c(faQf0M?bsz3Y>xPHA zi8rIb+Y?bsf#%1OxqvT7ZX?j3iJYG{!RhssYI;5V(;7Y z`F5H!gQa1_A$Ri|4t_wl0=;{v^0bLNG_)PTp$lyO1Zlb}m3C$YDb{U|n~8QQ)y0Cz zzrfDdI_S#%lPAD;0WSeEUx&bXYWn^W&lmPj?6SjjgZ=DH^aZ}B{xbGGd9~k&KOKrp ztwy9l<-QJ&83yr5oQ&g5Z<#iPOvG}gr&_EPsvY^au=HDK=db@M(fpkTJ{6b=$oyRe z&QtUGn>T0iVw`vrt+J^Me$avp7B9B*cM$pk=<|C08vJ*Fo*K>Hu)o;(JN$Qho<46! z{CqugL5aK_(7sAtV{TPRmHJ7mtyaKxdy(?FInYQ`=@x1{gfhf#9`3cZ!EqUn3wPa8 zT^Tu8Xm~K@d$Mq7rIq)TF|M8+!d>)k6#G$>>Z=L+TPTcsbNJOUv}f!7)Mc`SReKS3cX)dO&C2oe^j5yMxKSK3QbQoV3VL_zdPxS|=j482da%bSMQ;zEM z;NKGc9;&a$PZ`V`T6XVqekSY}62PGf#0*#_YaD56PA}@d9YH9=jF6^hV;3gV`zNuk zJzc!N3Kr7!JIN5w;2c1IpXeWuE<@Phe0`*We~Hzz=3$*DVvoTx>ouMu^lPFPvoS39 zPEyK7sa=^br?oMfPSu|!dNt`?%BE(g<4{&-z5AIOO?4xl(WsVd^irQ7bTh@;uk)Q` zBf%=eaAQ?)H=z#_eX+izH@^2E$#&}6l=3UpoT_oQAKX z>^^FAGTI;=zhCr^l+&1!4YUSi|1AOMX`?tl(j(^FDj#1&|G?*eIk)h`!+}&IcD#EN9=9ya!vU# zy#RN6+_X?@qvvQ7)C`<&=&E_N&KL(HJe*%oTm#A5M4P~4wbC2J_;-4A{2K>e0!#vA zz9xh7bU5yuG2a)uaPETXy?V{UX|FygJ-*9pU__pztOS%I+L<3|t`Rzw!VdTUG4LJ0 ztANxwDt<1{G0RV`GiUxBes&_av>oQ6n<>7G#f0=2ok`CpIAxbj(v+VvX5Ma`|F}Ac z4ys8>e<3BiCWXG3l1=GjYWCwQ+s&i>{`8==6tVm%T`T-AiN^Ee!6yP|12SLdfb$f; z-|INn&9eybA}E=GL)}~G6^eF+q71-}L@Rmns7~l@f<3vvyaW6d;B`Ri?E~kj+4JpD zwcL^*P9~g%lL=esW*q7Ulvy~InZsweiW_bJ@+L&}I)nEC!hqBp2hP)Nf3@cgS?-G$ zEW(Y|vT2KESoi)T*YKk}IoQUo!d*>ec}F9Qw$pN1hpe=eG_0VZIE|hG;gXwd-3r+C z!!EDyjo?oJ+W@Ki1~^ZtaqY^|oil%N*`g&l8ZZ&L;5A=P-X++<-$s8VN`D-{z{XS& z_Od)Uet|tJlIijA3SK}jw;Ytcz5wT`$#R)pHZ3BHq>@}u`JL`rZzfh)t+k#<38 zAYycTFsOH+A(fYn2WS6~ljZa=Do)C!%o-EFFu1OzKYew9TNdQyFH{u14ya*gehF%Cv?b zr?Pxc+kUiXE3d|~*qQmgXg4-t_!*ut!&|4c!uX%Yd`6prsrZULZMB`J-^m(wY|?19 zT4G7fkgd>imAAoKqcI8V#3w8tTNpTw$Pk@d{T0zAR84L4(y z?P@-4M~B!ao_fCY#b4Xb14b&pXA>XO_;qY0F2JMXb|Ke(3m> zz5L`jmW3+8jBovJt*{?~EmUzFKe zXSpL;Cv>Y}SC-@3;Qs>Z0IB;KI8R5!`D%GSu95Dsn1IH*yoN((#t^??h<} zDA*voh$}}PuyvJlqV?DsygLv8q;3$Lr}M=5%AMk~DP7r=YH+vL+HAPS+HBZP4^yQb zpnPmMr}5b9sC&@XFNb|OzTFPK9;gJQ{)6B=HB;VVM37~j85oDP^maN^DZ(>pW3(K( zj8sZC+Isb{C)bg#bD81=(gCTL1UbgBrI?nR3FEcR4D%9ypFPz31B?|RnTc`NEsDBf|&jBs~q|P*O zp5pK0$LKT^<^-!S=PCglf0<$xW<=<0f*m>Dy#W3OPzy+%Kf!q_73UkSmggLBsuc&J z_;YX8y%+p>h%#$w96198`L2P^QB7ZUTW6??@SqU3V`!FYg5i`6!FB;7w-cPDUW<)U zem9%Z53KdzdV*6iTA1J{&_DT_qxf;VJjR|ME%)i*WxyPOCqCaaI(O4JfAUe+5ONk$ zUMBW?5QY6suqFG;9`M(Iw;cB4=jU0C?2lW_j~9v4zAk9E_~W5g2Jxjr=;U1xE$?37 zVPGI2%X>69Po?quwzeL&oMVa`!}|po-mB@Q%27PKGyr=mS^Sxy;ab4%F}}@q`BlKK zY`2esR{>80QnwnMr}+LU{B-EbV$3Y=k5*MpCn~>?iHg!y>&O)&LQk0*^)nCL4|D>g zUI3h@=KTx@oAdNWJoFmxX}!>04!hFNTfy%JHULuh0dSt0_cN;7;AzP)tcR-UdCCSr z>1%sxnNdofu*O0bBjZQL)>aa961ny0c+d`nwYR zI$$jzb#DgesTqHrx{cl49d$Rb#rE?c>`6br1OFNL9guqNY5&vDXaUE2dZ4kVRYJD} zcBP+l!50I|0I7Q!`2X-Ts@vGp&!e7NW)$C6+uyygEB*Zx{A-{dkh*_>^Ax|X7X8M4 zzCN}g2S(xaVKz=5R@0@*FL2q9BY!x6&%4isSie~7rV627JU#07dEiq4+}pP_PcZJq z>PmleA(^YJR`JM0m9W1FwxoZ%!CwR30;GTMgY(o(yS1JpiWaP0p^>u}@b0omS&yj5 zy6?(|qybuAxE83g%hf+4>epcKk-%6$>W&BJshM^grz;)Ij7+ek=i=}=rn=$Lo?0n% z*TJsz_bKolz%D@Qz7Eb)Gycw8x@a2T2#T%I((zNd!xt(waJY*cg9CC5=JtF~+J5KF zjQSl09}Elwr2Z&yo|^GHUcbTdhQYX2jSj}J6A`)3D54&hIdijniDFb+XH2;AtQ) z^>s?o&C`h2mBI{aB5=jQOx&9(O2heV?3rP!pINu-CS(8fe!f*t7t#JYHnOZccg0WJ zey04{QFZ63+-w*q|{0@P8W?_s6r2b%Vo_dIN{2KY(6xW}# z_?)su3#>N7bt}mS*eb&lz^Yq-ICet$Y zJ|^}!jWoCJN=qv=Jt=9di^jZGzAx4~(zUn^r6~Sq?Q&aL5sD>ZnKF&9fb zlNfC?h}o`No0PVCo3?E|{b*bK*QN)qSX)oNZsKfkn=Jb(#Y|;wd^XojBQ2j%75|pQ z)0VX!CZId=2swhWvKJ3&eO< zBTLB$t7X;iu*+u?{5M3sz6!n%*bm6^IRwtr8u46SK&;Ee_}-n^OU#$=8i+h$K41}jR9>Y~ip0o22m~HFu_B9gxRN!<#=3|QZxs1Q% zr)gU+9?Kh;Rb33s1{Q%|@vid*80_q64>XJ4wGPxGzb z2Epg;@+h7Y-Tyfa{4C&HK<2LuoTo<5L-YLch4@+1_}dz=jGArr@l`}QZsgN5Q5I00 zhbq7aQiaf~g1!E@=H*`l{uZzwka{13^YojDe`*#x%ER8BuoW??T)qN@&>E*es%bSI zGxHSCIk@N58pXliBaly0p}_GgQC zsMH=-@6$-7_Ly;>#xwAHin2bnuZH7meQ}69-BpOAr+CzwuQ&4byb;)KHZ@OnHeQ@z zoQVS-7t+=^gc2Z`>J-!vR`l8;jiqPeG=DbXPu2JZtiyh%V1IT$F)pAd<17On^W2Af zc{t~I2VsvBJwW(>?Pax=ylnfMcX6~{JAiisdI8ek{@^^#7X3}`6IkuMp-!h-G0$I> z+SGhH-frGA?Os(Ybjo3;7CTU4R28CLPAxwX(trsq@MAmDWnRw=d1d$(;ft4ey-jLpyki3-ls9U_y)xbp&2I zGKCJu`Es9UkcK}6vY6o-N@t#{pBDgL#XCD( z9mnWn`{LdJo<<+1j}+}az3-X&S&xvEeAlo+Y_t~#7#L1%^ahz(H*Dw@pKI9%32>Fs;&p2fR{z3;e9lj0X@Lm!dlgs zuiivlQ|S!4M7xWmZYT6wLZ{Q7IEr9S#mJCdfIAa+5sDv7!#xDLg3ipI-)SoC*X0X& zm`YJ9-?iIO$^2-)xe$CAa5*6BaT7RC#qsY!i5ss=_%n38J(s*jaF47FkbgRF&l~Xw zH_ip&DHN?Wc4%~ipDDoc7R{AQ4K<^U>dn?Ovdp#}Gtt`M-?`cuI5IIs45Lczdv-pL zi+u3*rY*o43CIFuKK zRr~9ya!Xo)Ym9aZRtY8?ZjYC^pq6{!@$7}PJ(1I;68NW`k2;~l^YJ}6U5I;tfXqh@ zxRnnvPgaQgXqNx62Q@IXK5GxHx;?bk5j<5XQX2*`YV3C>esyFISe?rnN}i&;W7oFQpnuhy||RZ_41Tl*GG9m^RH-i6Vh z-iwFkaYr(XhEs>qfbSa8Q|}c3F62|IH`~N(EwqA;dZ)XI$7BUv^rE|oi)Dv3mVF9N zSX)PKFVdFL3lVhmQ@0Wm=LIiyV|W|$wf-tqwx!Lv*&MpxJEk~iXm&9js=wpS-tT3_DD(dG zn&|nI+K=sg927b{AIf6XIgkR#e58T%B=zN|l@G^!R%Cs{xq9r{a~6NHH`DL8)~)?uq*xD5B?Ew2#~s;gY$HP_dLd{Mql>0gTHpi@v=wQDLrKS8(13E z9S=ScI2(|<=YaEcB7aYcS3ZHibwYO&>`H%kgTDpr2c+%+aGsj?w~^`z{jK=7?XUlm z=zc~Y@RNaIfYcoi&Qtt-2l1l6UgH*9BNngJ(h%Czkf|xkPI?PbX654zeFfT3K7vH> zWP;tSl)zzIcOC4?{eX?&TY;wmsrxcGPaEUjL(`yZ-MK2A2}#qEyqPF#aOVNf50fk{ z&6Q>ys?qqX(yUY~bbZUBy6wRG0Ve}ecRn~z@#od0?wrMa!f;meoq4MxL40lh3e!(_Y{? z!1(gHT|U*whb*5x;GY180h!ON<^L<6C-t@R`4{A^K;-ixeEI>N&j+dUo0U%=@`;z} zS^4bB-&4?#%UqoCWFnVEJeNzft#&T4zWc(?XDRX_+wENN6~NVi%;yGhp5n(rS)Swg zCPi-PEYxFHpc~-BsI-fIL-3^ln+9F5B2RIpsonJMSPg1;b_7*gL9~fh)dr5(`8Wcd z0Cf0#@B_GUDenCOG9UfGd8&*%w*Cd{=%*dJ8PToZ$$}w#0j^`8688p|LkE(>u5!jLU4SxpL{)#dHq)r|< zPtEn?Nej-5M68D}GK;&z_YOn3;2h;R1o>%gRWr4Y{EY;s+QR;$qW)o5>MjJo94H5* zZUy*>b;mDQ)`aejIPuezZiUc22)k1EYjEu{{Jlp&>W08iq&smAeW>&5!C<^_9QDC=JwZE0UcyKSWe z;p=0>`h2(RRvhE2p^y9n@AFx9&S#f|aLQ4~qp3Jnqak3$_J0>V;cVhWKNxmYOvI#M z*i|ug!vIUsQ%$@85ezTlHB*dKFr3mey@m;f*JYS+8w~I6HPej@Fudl}%rvsVa`ikj z+sFaK%QnnhBM%H4I%X@QHCVph&TM0}1;dlZX1>u53@=eN+Z%o`tVYcOqXSrHz0mAv zbOOV|)a+~&f_2rqnO%$`Fa*_RSECyk*0W}JqX$@TJz(}UdV%%P`l>_rQn59+&uAzJW4P_GH%W&(=4;KiW6 zJBa5GQQ!qH1@)JMCeFiyzY^5<1Wh~`0RC!F-y1aXmgC^ca z3jS75-xoA-bQ1jSpk5m^(;14t;GLkpKWJt$R6xPILH)g;iQpgnA3^;<(9C71go1wt z^@BmP6+<-?ydTs*2%6aL2LD%3|1fCceVE`M1@(`EW_yOpDEK6(*9FZ2hUzHzG^ig6 znjIM`q~PB{{czC4+bh983+kT-%`Oa;Qt(AkKN2*%GE_^!mqGn#(Cp4oF$G@*^{<0w zPll=~_$H_y;{ziqr{LS5UXSWwsGfrFg8KJC^CX4}D)>)O{~>6G7^c@lT0ETKR_&KQm5;O-fR8+yQLH)O&IhdiU3Vsjje+12;43$;zXHYK>nZp>W ztKiCzzA|KvV5qQyt3vwKA#)T%l@(kQ(pQDdF>EaOwIO|V$Q;K`0lzM!Umr40W#hqb z2qlbr>Adq}?{ zWS-3?gWnm_*M-a}>>TjBLi*hy^IUcw_&p(geaJkYT>yS>NZ$}Lr?OJ;`$BqU$ehNe zgWn(09|)N<*i7&TL;A*$S;l68KNQj*4w)CS+2D_a^i3gi4!a2a(UAUF$h?@%1%EuG zZw{IB*nIFOLi(1FxqwB$w}$kpkhzd80)H~3Zwr}=*%I)lLi*Dob1Az7{F#uxJ!CFp z%fX)w>D3|gQubHyzlZc4A@eeJIrwuSeP_u08@mGh`H;RVWUgT41Q#!a^qP=~r> zs~1E1?vQyE!Fwuj^-@TGIb>c#@CYWZUJ2=YLguxEt>#y+hV;E5^E$$==U1fMn3 zUdX(iusitGKSKI}ka;Iz>-g0_L;Asxc^6@K^Q-qm`UfHN9>Ui1tAB;`4@2g?gl*tg zABFUfL%1WxD*4qXA-yhS-cQ&A{OZ$?ekf!!@%tr}(j9+~j(vODB#|hiauf7WDUx&;m2;0K1z6t5aLgrS&s`%BnA-z6i z;{6)i_|~Keh=w?gv=KRtKnCFhV=5V`66Mv`PG$SeP!5uiLjUX z)m35r>ah6=VSD)1HDP^K*nE|+z5MFhu)aEMzDC&V{OY=}etp<{gRnRG)eT{NP1t;k zuzmb$ZCJlCY`#rcEx)=ctXG81cL>|huWk;S*IJ*?jm zHvdW3L4I{-SYH=5-zN+Yl%Z>d^}EC7zXYd*N4rI2>X~{-5b_7gmFiZ)$yzQ z!g^)c{FJam{ObO&{y^CLH(`hQ)q`PuW7zzRu+RC`Lt*{lu=xdHNBGqvVSQ8B{F1Pv z{OZxL{#e-jim9F}DVL$P!XTtjSu=!uYj`OQ$!+Letw4S`f)!)PVjZP#$a@f4)|JZx; z_^PVw@Bf^Arh9Lao0~a6fSUjzAS7XwNr->~4iEz>&S40HGQ=>5Lp9Dg$JzGl5Um5% zR;kt2s;#ND*4flf)>@^uwboiqskPKv{k_-OXXl0}1i#Po$MeT;=e6!xH-WQ0d!E*S z3AB9s$;9C4iOGwVw^hFVbYk$##N;K)yHvhCJ27}}V)8QOT`u3ApBTI_F?ogZu9R;t zP7Gd}n7m4PZG7whGP!MF0(_t$*xtYd`0a+^!G>r8{7ysgP(w5UKHLy|w;`GUzt<2v z(hyC6-){&WZHOko#~Omi8=?vD2Mxgw8=?vDiH4w~A({Yx)DS$`5KVwTZU~-gh$g_F zGz3pKL=)go8-iyVq6zTXhTyq|Xaan`A$Xx7ngCyH2wrN4Ccu{)g3g9$0{mG+@Jd5c zPk=vf2!7EJO@O~_2!7QNO@O~{2wrW7Ccxh`1g|wj6X0(fg4Y|O3GjCf!5aQywwm*fPZKR{@4&rfPZQT-foB{z&|$x?=(ac;9nYocN?M!@UIQQdkxV9 z__v1O{f1}){GcJ|YKSJlzc&Os8}tO&{~ry(1ufLgg)PBFE!54$Ey327sBSK42`+7k z>gKYR;PRHJZmwtvu55|w=Bk#UttG0Pt6PF=TB5qSwk5c(C90e2TY?)}blnu+*b=<9 zc}jLkR#CQk(d~a@i+4i{$`sg*?3Jz^3{r1rLm&UFuh;zF`upz((5StaCjLJH=l@o= z{{Q#vy%qj%%IBZs`p@&`{y)}G-rCH@^DsHDKYx&Yh`)1{cSz!b{_#VS@B2BMQ*YY2 zrP<%}vr1!c_6thgSN!NAy#1)d!u@gSrI~$n4g6SWA|y%l`g+Gz(h7YWP`PesTC!Yx zSZf2CVb+ssm^EHJ)`SK@ozeTZ^mu<8{I$@HU+Vo)kkVWPS?S2vQDYCu& zWSf7H?baE+tfO@~u0l>4IfCN?_^Y7nAcNyBcuAkL0|+(edX}f)5QlPLaZ~l2){Vlk zC{S$cY;n;iu9*Wh*a@6U%R15>9ln+OnZ+7M7jn#bQ}S}p>IV&i4327eNygs8=%;7wPqzxHD>m4h*a3QI2OoQXJ!0l|mWqqEVuTWpUbpBRIg^ zXRBFiW_V86eyqlox*~HG7DtjcmV1Vy4cPxVi+X;0-9p;UVk_RfJC6nBfgJU_|r6J@bfj>ka(Ms#RQ zD7>|~Ha3vBG{WtGlVhWgrYhVDRATaQXBx*}1DTnk+HLiiLdm6(tLM__X0Gi7ov$6> zHue5@_z$67QC_}CKiA|(B5*C-C@M!_2B-On0x#DoqxE2Rnn?La zIR*CM+}fzYuTf`8gYRn8IIXsf|C@aH5l}T`aNY|qsXp@4`$^<4-PF^{rgaOO*Mxos z@HY3j|Cw#K;yE;Y)P9DY^;7DtnDq;1D9s*^7}-89MRMIqMSg#pcea;1jp$6r`d-|{ zMJutKay_@y&!M5mQeG}#@RtkfoLqccY1utp(=B@jg|0qHhp8VGs!(Un&%pubUDPX&dd`f@M&lm zWXfSAyrgNp>|IPbm_jIMw>OD-`BON{vL12yu#R%ag+omE|E(2T-WJ|x=B10^zX9D3 z8F~MOmsES59$#7`|IS9Qm~zI3|@f zIE#zhuJ0EQQ23oL3%hV^I^{ZKI7ZpnEqnGbb=YX9dXie@l;A_gBXClQe_T9waE((% zwV@B~+++u5iM=%gXOsIYTYW`M^tQT^yX`0IeAQo*>Gvz(PlYx^CSMo8OIm)u&R6gG zc2UdfwTCsW*myABF=V!F+`x@b1vhw4iH_oRs9TJp&(Cnmr2b~Pb0c@@R`V%ZekboY z^U9y$cS8SyjQqT7`dv@i__=pQqGciBbcAF?c(4+;qGOAGq0^lH=e+ zrZ@pJ%pRl)!j{#zM&oHjp24#L{(NXFWboV%FKJKX;A$BMOkp%%W&@@GniB%rN^FAI z5W0RYs!u2^dxQLBUT!fb^4_Qf{%u{Hx8lhZaLc6Si&{$aT8(QLat*HB>pW{PG!!zp zrorzG*P108aM#=u+g8DrghU_eDb-oyQ@c*% z*@`^VA8v)e7kU6Pczy~mskeVK(;wC@Ii=~qg|p_((@H~b>PlN*Y64{&JuzMzUbuRG zKCa9L#^cE(E2N}l5yGWN-n%2hk-9!JPgcRthUP&A$7*;ow{4~JXALGjG+bL3~?lAy!2Ud88TW#UYA0G8_oE|JdiH{~4yU+f0>o~5vk z#AD7v6oN~FrbJ1+Db)I~tn{h6+&aKx?loV5{~h!eWbp2Umz0kD_w1>^g?()leeJ}s zuYHS%E$9O$R6o2LD0iW>p%dK-)7!{@B){&4jQoZ0Cqm00BYy*YU-HBL_IUs|?+rj} zOO*fU{W8yX!v7X}6EgDOkN$4-d(6|cn~Z8*dOs9ab5K})8dJdv@phhtC!j1H4soEW z39nPF9g*BgH)i_J9QfOzyCEZY?M*u0d+OI=-;q3b+P`MLL|?Zl{M-_LKB#|nYWSrn z{2Um5UZ54w=Joi)tRDOUhR-4wPi0x-%l$lD871+>lsc@^%|At*Ob{d7KrDv7Us?IAC2>nu9LLHgn8veO6}!c8Tv$ufI~5ahLZQv2D@#1It+su+QI!&?%Etd%DiwwjOexhJO+I8D#SJOL$3N zLf$y!71Y;->)7M0_v5%jn23);$sPNyNN)OT`n}S>s^KR?2S7${UG#U;uguew>u#1gefsqDq=)unMYY74#D3Dpo5e5Gl?c=E*=t zKu6AIU>d)o^ViCI&A4?vd^>a(WaNGyUec;aKe{Wj8;s;OG_72{0o_TFFSAMWTtqj8 zqKP!~D5A6ck*J7E+^oO}1GlVmC#i087pwMcjU#remLug{1V0oS0T~>VqraQ-HO~k~ zRMI8QgOD#Vvr9q@zqavvcI54L{T+7R?RL=}cDAVN;!vTxo>S*&`CECvDTiC&w?W^6 zjQnrIOX}?hB$8h>Qc3{l4y(^-3d><07{upFr>JuJ61RJT&k};uwy+|#8R87o!Ma{9w1`;+GU2qxSLWST|tIl5|?~Cz1 zk@pq&R_KCAhRhRfz4W_!%BdQ;eD%tv4OoRXG_kNGf0Gb4$y$`ftgV0WIH?4>RUgTF zm3N!+{0n>+^iRm-4_`*|&p$U`^puMlzDyCdr=aWfiXw8;s)3wxj#UF>hf}4FmRj5q z$*bdiM&9x8Cqc_18DBIH_LP&!UsQbw#3iha(nz|Z_qX?W|Bv9Gf}Z)(@1MD5Jr2Ee z8_`0xn3j01uBX)PnSID;`03Cr$duc8@RF{J{3@Av?q8gr?wEFM_JbJN;JNrR`zng< z74@cTomK7@vC5o`?@%e%L~NYfj|Et{8jm8`{_cpuL7BqjIPi%^;SE#7;>(gSE7@r$ zH@^hf_`s$o-Gk$F{8fhgVQ@8`uk-OLIL&_QAMnl{v_Ht?qaVDaj>vAZF*?`z;(RO& zgIN*2gs6B9;Y${XN%br0&&s+NKk#gb)eLl;@TU)~x9Q04{+)ssD4b8G<%`Sa|f{8 zOsXQZtV(eV8^hHTu19U(&qn{L%q`*=ByX6i%prDoArZiH(Q+Fpg@-oXL&D`)+wV` z|rmq0ue;)!OyIx;M5-ruz~s{cry zl=r*v|AhVx89dgV8jl&*%(EvRGkvB9u``;EwZkve7HjTd!*i{xH7>9zHt^Hs!Y2?^n`Ai1ql7N<7jesXY0?*)AHi zMD^A`F2?(Q=36z#hkN;Pr>i=CW)Pf1|4fUX@=f@u;rH&}x(9JkXnusB9e&IFHsZqf zeZl_^-`PVJXbo=311jA(7&5=3?x?Sub@^?%D^q?~!M8(qL6W5W+V@y~M=h3(Lq%Kh zgYm11?Y81qYp*I!P>SE1Vm(wm7AJi2Bc&LGXk0$QBA;B&u^^zT9(_5b;NJ%+vUK#gNKl80M6i-XXUl6X^62*H$EPfu23BxeinH0$3R z;ctcRfK2vC>h zvT;?-iq&hHgsGmjrfErd?Az}A(!I^G+ns+E+~#Ciud08QTHEZJSY9$WbyTiX=&O0d zf`c8DK8Yjd7P{Qe2-lFK=J~fMZ>;Yv369@t&&x%_x1T>Acb-{H>{)gW+PFieIx|I= z`4EikW~$g2ul4}NEH&x08jjt|iI`TKXHQk${=vl4Mn}J?&U41O-h^Q6X(OWFjLhrT zZ?to4sX7Gzst4kWdYY{c4d$O_r%-0}_VcQXg9Ci;(BRyo`O|bvv6a7gYFCUBK<5$YQ(N-sNN5Wm0 z&8F)Bw??kUNVU)CdU%I&PV-&r!TtvK!B7m6BMO zr26Rn^}NfRt1gE>1zHc8dOi(aQtx}s-Q`55`vrt8jv;0_QBen~IvH=Lh_O5Wzax^@ z!TXH7U%&7_XLY&Gy;sYTay=e?4b%!59AAz8Zsr;D+&$lB8&NL?fcJ_4VD*B8^}0G% zP4%X7*+~R1=5w6HTlvT4PwjH2p6lhE=M|mnsr;fYSDh;h(@E;rJ@ywno{Q=o`KI4n z_hAbNr67ZE0KBB$L!8e8jx8>@A0 zxX}vVxBYo7zft7z8!4Yn@LQm>BAL?edh1d2maDZWiV;?9omI^FYxLfZ9`Ah({!h@m zkjag`9MHy*RoDX1OE)@p}3$oi&zkY&{v zpCnz8ybj)H>h)Lfe}>+JjJ!$T((=lp^}5k#=q+z$%X-=D;I8_AaO}rI{Z1ZI0>5{y z?@|IqZqg_IraLe}Ot68@$RZWP-3{g)9t#z@s3$UfZfrj_&y|DBLWd}8%1=Ax$ubU6 zM-V8X(i;{!a(>!YYcamfC*3uPN+HNLFNuMNDD_%7|_9{BG-k3c3rKY^FD zJvxUlei(Y^r+ep7e~)ydY`W17g)K-M`->cmR4%louS`>mvFjE2b)8y%>i*1m{%H8g z&~(ViKNMb4Z-3HXC_mF#dZD;u4=5}v{WFc@Cgh}%BjxZ7_=llKA%o*-_%QXlkJUKj zG&gj@8aC%E2?5SAMUF1y5F5@;hC6_A;FlikUMWzg2w-%^%`S(4i-cGaH|%Ef7zdXli64_zoN^b9XV!v ze+>So&z8*TeX8DgN4%fg^@l+t7sych zva;ITu!*K-vnlrIX65nhEcC|IFn2%Mh+Rl*3^r^h$zGH6OO5Lp?YCMBo;Tq^r?&#>v%4)^3%XeM{4d z)mvy%xKdgni>)dR zT(2L0(!ab(e=7?AG%)=9n*P;_@QeOKV-LRG@LAR$)$=*#0x>VVKpf|m?!yHl!OXcp z+`vU4!GRot32}w!$rYj#WX+8(5c$2nK$PExSBQg0_|X+&S^mn*72?oXUaZ$8;uZ#l z%q8OZo|lO7ubF*wqHDxscpe&FBOalz5zi$|fP<-qh_d z_Hbq#DS__~4T2z^nC$o`$5L*`TCdwjlYeZwyPon7>XKK*YE zSLcnt*ZJSV`^|ds8u;s>uSPPZynCOEOG($PShtxa`G!qvCyrl|ITSCj-cbeC83kbm zTch{C%Dc?Ednf!qp?~*yfA4ko7rdWy#_)tH$@`Pm1vXkE;ELWq>3f-e+yH+hbPOa( z@Gt6huKxw^H%qm}yniu4H)32MNSHXh6gsgOQ5)r5U6H(PyxZjGNAOQU&-9Sj`~LR} zpM7}$?uYCmGu+o3f z`P>z~U;16}eb35=iXkJvKfEN<-p#XHzBwH2jw$dCcZ=6R-26l_1?2y?M)FqizFNME zyi?)Ng3g7Eyi4FERYiJn#((*m^((9OJxod6nM|zXnONTy73;Ih)!kuF8l^V5{X<`U z^8XwEsPp$K?~{fj^4@~q3H=K)@+u$I@)kws|K=V;G*Dtohnp!+2U4+tHz_)C5Fx{JCwTsr+c-o_L9nZ z@!L_qM}A#|?>hLqpnD;M?}*1VzO%OLb>yPxDfp^J9=3kvO0g|ivA$*Pl8tlCh5z6# z^{D@Wvb)q1c^`z3zh25E=uGv1%_@6p|Gc6cm6M-WMlgG>T1xB~!EA8xK9s;nL|jXu zbH$nZ!eG&X&c#uj)x(4NM`R7;)`dHPWKqq2{L4|SlZE=l2+iXijYev%SEVLP#98m? z>{!+~??T%-&o1iuZ>wCKvDM_EQgfc|gnv$!4J@7?JJhoeLSwf?`p0)|_gp7&x>{y0 zCRp^(ZLd-t$6dpB1Nlb@>0nJ&$^eWxzJM<^fDo?e1~6Z#`$%5VJRy8O09{-i#P z&J%YpzXh8%HgA#(Mf?Y}yP@NNr=17T8huw?9kcFa*isJ5YrLX`aLJ(J=UOdTGSM@8FwdfqTnoA;oC9W6! zGBv?F5-*JDAU{?ajCJOzaoNQZ2u`Ptk90oU$%o13cj12s{TMR&d=XyKb-nz_?Viuj z2MrBL7Ka--+j>_#(7eI5)e^>9WX^Z@Q@P=iwDDhBZs`v)>wwYljO3orXal~lRy ze^>p%wjTGE-{T&>&CR>VE!yU0%W2&0;V9MoZ!Nbudaua60RAfITFA(~A^N+KXPz8S zZCt&!sb+c8(oNk6bU>GJD0aN3PPQsfma%uNoRU(mk-Qze&y0iW34FdlMUat~hL_a) z+;8RTjjJ{-t;Pdh&C>O2HZETpKB`wNU$Sw@hSNjcuS}9?0PMBfO-o(fGeBvPaqz4s%u5Zoj8zy#e9e z*AjjXkr}W{bvV|ba^=T{x=9CD9z=8wVyu_l0g0Sp1%nEmvZ29nMz(A(uUs4yqwZHh zpi7<}4zi`c-fsJM+V*@qiv241QlIGjOzOy#>tgt2&`QYUrv+ZpzLx8zby1EA>JMif z8D9{Pfm5x;1J&&8AS*1<>AFP2*II26jt=Cc`IWS%-@*SI`V=xa%73JB%)T-@kBH7C z_E4_)J8Y)EqO|)R6)Ng#rQN2G&laWKF7;#AS~}F-f?K`))Y-8yoZt}5SAtYC2o|W4 zf`QmEPo@8kncfx4SQpQ`X_3 z+|nmAPE`h`8Lj1XVLCd zqCc7pitB9(>san$OS?}AtQ`@q?Z`F#=r{0P&_5xAYtWB1u5@Id)q1n8_dVc}gZ*Wv zh{JXL1R#rui=A*0u_XMwQGLLKxKrKdTb%^ND@vkC-{j9%WwFT$2VLGt#AN<}icNR@ELE0r3W>M}{E9zF{aztf3oLWoES&qcacbtz!b{r} zcS@?-8>QqTeWc$qJT~&I#2|O6^rGBY%@jv|$ob{ARQQcb-9dPFbpdysYL5LATaK7@ zYR=L5ZYEzQ-}l1*2znYa`F;ytlF=_R@wUEHzUQr&zkcIEThI&)y{B!rFSQ?#$b}=q z&s+E+87A`k&7Axm!eZD{mF~!Rjoe+xX^nlHbiBE;p2wyt?1WuOjlcHk%(!q8{Ke4a zkiq{vyrhnMbiIv#Y#-b0?4~tMJ?pLAxy=u6xK9W_M}N_$654 zkfe*BszS!-ulPfWnjN1Sn>pRB;vAXC&MGH2J)qjD&V!`#&Xl_QtIctcn&lo$gvm?z ze_<||zYBD}tA3iPxB2kPq1BMd_gU~^iu|s3MbAF#ZBD4r$NKw17T!4U8fQKwb2qw# zsjE?cxBaZdEPsDze0;nhTPD`rn-v~n3{0!JNaO4T$6SEOeE1Rk&}Z1gLk8zj@RAzu z*Y%RVY#-~VUhfk+)ji(J%I;JX!q3rr{uKOw3kb~^^(i;UEz(ugkXVx!D?H1s@?wFm z1gVIyD((;a(JyW3LeDCW_#6A_d~E}F8r+hvSK!}){sx(RdCx}qiu7{-7(M$e|AW`J z9JFNFDw&x&?Ps;!MZcHDAY=H;VK@1fBhf7|^4`R@Zz7ftqY@Qfe?oUs_9v+$)IY-G zh139zvmP9&2=P$jUBOvTh>Q8!z_H){z?sV7>0A(lBgY|w;qsID`ev-kJ_!nxjQ&yVFVqcDp*a9qR%LapaE^1k8 zIHXnO(JhbFHc*%EcJP^X)2r|wLH~ga{-dAQ_;*Eq@;3frAMtN!UL8hTspyQq>%1Jd zJL7*>;bVCC`G>5R<5JMq7g)E(4sy5JiDI_E>GApfiiTGlQbcIiNq#@ycdLR{g^#-0 zAnE7Cu@UUYYGHr&%yZP)KFT(!tJQ(t^gC=^@6~#DIK$Gok@r-;isX)2yeKHa`D9>B*7OM_CUw4gK`TidHN-d3=s!6of+8~h{C4-;`KeqvF6--Le``T#Qd4PMsyjYWDAwUM4cpY^dq zhvqJ*AHv`|FC1Jiv#sZFv`>5*-&OsyU0gB}L0u)J-z~%HpNG|0qjA+E*WfxE{z~Xt z$l$sMUXsy&xoKb9GbT+x}7pXJt^nV5*bbVS%x%EQn5 zRrvTCA(>>DK=b{Ata87QfFN--$gPM!Y3Ju8@3gaOvJ>$^GWvhd#^wCwQuhaVQ)FL3 z+CEm}-!7Q>F8E)C{{Z?BGWh%dOylp2@V7?#lzYTKYf}qh!$wpeyt-vW=x|~Ob5#g< za`^dsU?&Li{T}DlvO+Idee*k(2GWmE4UQ%y+=RWf>ziCUDjW)I)SBWCi z$g3#!57jlwx{iJJeAJ}_tPA#&q3&eVYpLX znTk{T)51b*o1}3*0uIy9cEEQ*|AY+AvY$uo_$EEhZU0&y-D>CiiHQf#d=?3sM z7nR6ze~=oK?W@7DVd@yn2rBy}`d?zl19uR6r^Enmxdr8wwraIwr9rhz-8&63Ky06) zaW{jjE-K#};lBkv2pQb3!Am-;mtT}V%XeLOy$^|Ogvoko$4Tm+Wd78#u^^44T#S!r9pbe10y$xPc zd*mm?{oy{A_lBk=E#dMTR~B!p(2!$x_&Fo|`~=$$X&_uje8M(wf-3Z@)H(h@g7ZyK zDeNIqd9^C#^z$l9(a4EmN$edZTyBkbqmsHfRNbwTkK1-B#}LP>Ma0Bl@*HfIl~!Aw z&R^`8nfy(FKL|PmGWlzUmsAyu&UlJk^N( z3o+NEAm^gkGN&Kq1Sy+t8m3PMy>)sRJS|UOKy!jgp-34Ku)-{2ziBnIHyP5$Oq<2 zGwKYnA1v70XKCD9z?BA<;JyR?`_K;|Q{L~wOG-uOwXNUW$M&=?)1cbbMd~(Xw_}AF zK7!jq?0<2rPuZ02$8;Xg&r_#j5#ixMBUh#3Im*jho%x;@o<#oFb|19W2u{Sn-*%A3 zKk3(*e!L8RGjt|o@ZSh8=}Y(HQ<_dU0T|uX`8L+)XF#Dhi!l`Zj~$%3WOJid!U0o% zd^6;!`OG@~)K^N-BDAdYmD?d08s})7JHTP~1Hr54HbE7T!MO-tQd=}Wwng)1pY6k} z3p?yPohNL&!#*_p44w$v^;caMpt3lekiZX^KM=p@T#yF&s!o-1c7|)B*fdob51e5{ zX~MwDj=YpSZ=;)f0++QFL1Anl3z*hY4&|D!~X_)12XyeGrS~o-_XZ-dDY0- zGe=aM7g0fw}0b;l0&-cTG4D)*qsA)cz)e<4E|EpyiOku@?SI zxW;$2d{ZnHe_&I4=<@K8i(EI_S%0IaB3X(b7yDlD#vbf zw%Ot1TK)Kseq5j*)5AZly^4bQNL`e|{Zx$_>gV}*p+R$tA3xg-Y+SxLBi)lr7i6#W zN4ll%(6Mv;1O5H8-?LSNKM6y-B+)PH;)FMs^)a3aJkfi@h|(xKqbcf1TYc&z8R7@3P0mGjA{8GJ zOWOndxjBQfh9r)N&-AN_+Pc=QES;fd4;XE0?PvDS3w61sew!JW#=)#(#|rsN{^_|WYPXJCwvSKKTirjE5gqM!_QUWXZ~klbG#{Tz2{6r@nF0= zjuj_|lq2cxdHzVYTcwGzM0KKyf=uw+ax#q$x>uE(WWyB}aC`_qIr&~ZCy#kQcS%-( zwC1C5gf|dX1b;B@=*GvNQ`uwG?40~mDz_pzJ!g3G5H;AY6kS_}?xS_NRK1>Q_lLuu z04;?~xvYnmWcr`cOW)%-5|&H%tyPEpxc!8TA_JZXGyO4kfXs{K+|#>dGVYGVrb?i9 zE{@ti^31&VCj3t5Uy#8w;CC8NZ~fZ63gNfzB(OVYt zoq*4#zYZM`cOBcC;!VvR%EgYG#pVoyD}RDNQ1$mKvij!)SwVTI&r`1cgOfqq?(d$X zS0Y`<>-^1qBa^>1@U75=kjdX|@RCwr*Zrn7@|(2R{LNakenXR-;WXaLRa#?iH%V=D zp(*ZZ9yU&Oo8* zkiokJUeeq)jkhX_zqwbu%M9KQ`#}{p=SAV?k96B!sN41v-1KswTo?=7w4e6N68Ua! zsthfz0c-8s>nC>?a1yG-D9 zL^u{BCyg9g-<=JA6?7eB%J(Pml5YNvF5mZ}=U&Tqso+?&MUd>U-`B?qABM*YAE^t` zn+?iiWt_woCi|-b{}@gplYW0Lf3gY1Qd5FkUUX7D`+U0~$-Z~I*iKKvhG(cf(A_}u zsZ}$BacUups-&7+pi7nepXIt-tA3x!Pd$7SbTVY}vkhKSeRN-&zFX(3@BB0zt#j1; zmcl6GLb1%qg=*JJDL?O8JA-L%VRliBM(!69N3}pza>5mn7r93u~Hh{FGWVk!-4J;GFruQw-85bQ>0Q-r)b4jZs|Vy_Wmhrj1KwwUAFflLJcOA!*+m(72K8LH(j8|=IHBReKnelQs z{A_3*WN@AZFR3nS_odN%uveT*)}YK3wUF)hWvHKW`F^{;h1fs*a{L1!=0CXBC)wpJ zoXcy2np7;wkTo_@g56U*S?mtYEm!B-3CT*L-_Upvl(~2Yk!9ITb)@^5tyVg7BkMr` zHtYO!f;Y`qX*d6XPrZ%48)Wh`6<(6@v$4Fda|~Ih8RN(fdr3H--KFQVoAhI%p4R^D zSdZt>r?c}4ao>t6?ckCu?#Rm37ACtbvE0Gv01pf;M!9WYp~l%O+!OQ~A_UZ;@wb7` z%*)@0e*yX#Wbpq5UQ+M)ihHaNX)`0LH!oSU+Vt7ld7)XCU0cqxyhgg}2e$PPrCorD zYuqpM%6#Qigg+E^69-1oB#Ydx2#JYKtF5fP2nSNRP4s8V*1{vIA;3XM*;Xd@bszz$up)H2)n&&dKNSS`! zwmzmzMe(ds>Uk9Rnfa7*^EEDRYRpk!+i4n4>Mxn{nG9bC&4vt~ zBj6?V_CvJ?JXIs*K4}e_I3ubzXum@RwbQX^-ldMQCdy?e9P81pUy~5s~+6y z5+S3iF1$YH`R^`eh2 z!l9}x5sUk_pN*+eBA(?G7Ze5PtU5*B%zowEz>HSY5^9u<&m=S#(Cmv96(v(4e}Ff3 zvl@y~l6QbNKCrX<;r*B>b6I&$+F25g*t$!ptCc#D;b)TU3ar|5biP-SFO%=9;qQR% zflR*Nf|nHgwyvK$BmIqi=vPt#Qb}#j-@Nc->Q5X~CCKb27{Q6gW@5TZC3ABM+=+== zRgA*(fL#2f5KQmjpn`~o=Rmc|K}0W{#wrr?mBF3i_^?*3QqAfp=NKP_iv}V*)QINA zVDUaezRuVAs{31}f2@H&3py7v`Fa>$Qd=|+e2Mngf=1kuaQ|D;?r!yObM1CFbsN4f zcB!BE*fxz-b*esA9!%gcXqFm4RdPiXW04?&`tUdXdgg>itZ94uGEn9R`{FG{Q?7+RJWeAL^-P{hBpPmuL@H z?e?F-)7D+;Vr6Z^l!R58U70AAOsIscab{EGizA~9{gxcN?AK~Owg<)dmW zQ802a@l)=>eo-vWWll1d7)`DYbGXKu5Eon;8*H=#{QnUPaY3H z8=421d~Sl5G$~qtbVc`^`%oV(O`#L_a2|2~sD0H9kXy}N>Km^0Hn*CKQQN~GxjTT( zZp<$9m*Dn*rIL(PcBNgGNac}XshAV+9kK=WgK73CCqG=2*0yQ<&w$VLi@(9|f*y+VQNF38-p)tWLDX4#cE?phH8KB|}xXWN3?U%temD zu@=4=+8D|1sefkddiGd;T7I-Z?bm2r?;zKdPr--SwL^m-gR2T&lJW05DbkzjqkckM#v4IF^9fkFeXO=vcM=rk zAQ=g{cy>cS!|7`^j%MVT_Hi@(eb9Eu;CLEd(mt=Rb@_<)!@|`|QB_7W%@8MbOSzlEA~ql=Irc@i6L9Iv!Ck4BQ$)n2(N1Z&Nqscjq+X)jbC{D< zr9aFrbUtK*jnVWNVzw8m8L`9EYBe`pYss2Lr}Y0s`6qvAeih~){ypgLkja1UzjXdP zBK^k3JNlT9bpDq&h3ouI^_u;%Xt#gN=^YQ;?K4h)tj_nXJ5&v`hhM~EYDwZEg(hGs zD8M+j5%n2RK5e^9R&UtuV(h&tohfdpO2azwR*icVxJarQ2h93xv4#Aa^0*cLVdzoFl*fdB>+-0J z*3E5w?b~#Dn6*zum;0081J~|yi^If2>|Wqre%9AG3l)o{s@k;-CUm%r$Ds zVQMb7Uj4Ws%VK=U?k}gc*<%O}j?di!%#^EC?g9DJ2TX|JND-T;B5!(tolL@x1;G$e zzZk^-%25Xv@%Lhk!o-TQAgE5w34&DCeH_dC;lbS>6h_wWiS{G5Jwk19CrcyWKRlpm zyGNHx8~HZ(H{XSS8hRcw9U{E9$+?p5H^%Il=YEQ z&PLEf|323qsb=`ZXi>@HiXy7i%k`CaAkWaCpx*te?ar`A$q`Q1HjTIL<4k{C4c`h~ z2pPPu!b__ChVF-r(LTJ7c_qZV=(P1Rn0MKeKM)r;&pYAcZC4||B5vL3mizfQQX7o# zy%ZtUT&_V1V@2G^HsI&70Y$1(x4&G3XM1r}OfYcE_ZDNSH;Sg7Z>NJhrDYbxVi>A7 z74^^d%E{PL^_Y{L;zcR!-;P)PotZp0+oePgNZXmfVy)lO`JeQkO#YX_H$$5sNwVHC z{v@}au}|Yrm~S(m;u07A3(?{9Xu7x9)-IPdZNM66s53B+Xe_z0+#I*mDRBnj=Veeo z5tqJS<9ZbgX1@Ove#j@ZE6CK#J@As+BE71|f3T1Ew3P&=9WS9Li)qKd-SBZ}_<5_R zf5)F>-u-pb+UC`WfoxI&4wTthZaPuv*V5vJ@wAf{AL}JzF}sM}uIJ^$3}lDexyj z%OO*4ZJ+9L%YIy!*L6SNr*iA5nQ6&x#Gl8AGuXo8pb|-JDa@nqyQUzA9?%qI@rJK>nX? zOc(~Mfy;vB+;vtlX^lbk)1JVvKOzU$ZfXv?l1VRSd$Hpvx3S!xc~X9*MVHxVUUPN2 zHdq(FEH`Ek$lq!Y4$_BnL)u@Jo^J=Zz`^p>%jG}W0e>0Arlp+MR_NDCLgX+q;tP+C+FsTYL|Wsb)~EdlzOWOT|l$3(m&Si zA^llqo;nPEDYOzY?V%N3(#ETGJLuCs#mw7sGdfFF^^6l7*B$qnjb6~-^l9Cu&%&|! z4_KbXhH~uW*?HMH!S8LVP`s-&O2fWg`A6VcMYmq=4S%BXc7i7c9$6oK0-s~~Rz76# zZiJWA5sky`ecg9zyt`W;4DM8qd*K4<->j2lUd0OYrWm&qM2A+avMXE?V|A^veih^Ti1QP?^m_|sLxIM6nOoMaU)J`V z#zig_BTJ(BY(?=^^u|oSH-v`Gtz4>}W4GEtSPP)IBZTrb+pUx;kW}}A z#_Nv)r23CB}%(}%x&U&>S_)(c?{b9Gt2r! zy{oKxbbc@{&%*8cVD}nEPDg&gNg#)3jlS6S7d75C@T9>b<@O-_!_fC5j9;Ri2+B-5 z`Gj`zDE9!Qj!2H>X4=UR_-bezWXfd{yrg|>CtBX;+Q}!;@WY@H zkfbkD-YZux-@UwVqRb_|tn=B-J59g57XD_a9Wwd66JF9j>Sr~F@}lx~Q`4h-9%6k> z9U>tqyYpEe$?xL*rko3W-ztOBkdZ$WUedmnbClnxoa-X_hgml({G1$=k>76e&->@{ zektec;O~VVfQc3@cT>!z~_A8xVi(}Lj-=#i=z>kL}Lngmx!b@t7?5G}!*1dbEkE)T2wu~?iqKFss zZTAU>cro`n5-{ddbz#gpmeV9P7{$%WJ}N9TRf!)E>-S)l>ne|{pDa1)=D5N>g9RSJ zFh!x9ID#IF1NLbFsxX$tGJd=|*JbCkQk~!|u=_Lnx4)+I^9*=Re*OyoKD0B+gY;u# z|J=v?s`C-)0#|^%f(gBX|KAzOnH10T;}hVQL#rTDZq4wL>Z11B$GoQHb$cx-Xk38f z|4-G))^nVs9xQkBhv;+Ey5H)2KEnGa@qVed_u)T+K8B2Zwoak^-hRUOT5mmlr|j-S z1ixv^&JjdsTW^EtSd9qvlTZjB9TBd2+*ROIcC29FZ`4&-ZhHcKEnlKlJbPCvm{}SFQRFqp$L^z!6|u>pQ@ioYgHRPhqEoV%aqd_0W#{wYB$wjWxc zN4d#t`M+_00D4u|**K=RN5!i8<*C}7$L(?+1v9w2_p;#fAPgyLy*xW8;hA%2KKi5m zs-4iRY$F;q;RdXK5tF+q)ghv+bz_8UwGjjT; zP8xWjc0$tmCtdFK*_m=b4gP#+D`d+3CU{9^owZN>qM^sladWF^$d;oW`>9y!yoCpw z+3XSHs?4j9LA{aVhFN+{7dh>3Yh3Rj*X##!b9`$6l!gqhN$`^Pc|RcIT+bWrx(OWT z-(qv$@TvNzZG8wXw79v5Oauef3ZiIW;Uuu8`@@|QwZP7GL#yESKWltjk#F#Q6aEL# zlaRs3XflWu+V9rnZio3@QM5ubIw9js#B@r?7?i?8&RW9h-$hs7#H=ZD1}IJ%Hya1`dU&Vxom2FD-ZC0!8BbI-i8BK*GBaUl$VBolmR zyfrs;7xGJdhscC?UcU8-H&*;LWD^7%=NNVw=Q5-5n>E~*GmQO$e(o@ib-qc2q*#oo z&znUP3m+e2sSz}b+*t}IE^diBf`2s4&L-l7QrYl>?U5%8A`*bL{-3&>7pF4w z<9YDcKsQ3BoWBPzY0JgBd~4hHwVb;rNt}_44Q*0y!8BE>|6^r6>DRag94oG?${+4k zQ7EIG>g5R+C3zb79P;$K&Baquv`IyN=SLcEEH8t%27W432N}G_!b{o}`AylU_Sr)t ztEBm7GHy)_$E|xYT?xuLPm3p}`ze)n%d-ly@w%8ZP=HNhRdl!64_do4zHP`i^VtjV z??N9y2H)xV8sDVv=yI%jVIRt~`?jRb`(+SLR5$2}>PIU4R&f=0K2`tCvK|b^a;sdA zX8uqV!}1b^K{AFWxSD4Nu{oT$sr*W=KyW1~HwjsVi9$7*po&+_K!#>>yqkU;rx>K9?D6zI}u3n!^+Dw0)-Ww}UUucUk8>2mdPcJILVw zH@u{|7wG!lC;UBJHOa226(6EsMH2Ca~H`aF?n?)%P%Wuvs~`M!2>j*UU?g z!9NdmLI&3kcu6MyaG&Fk@n@0oKhTX1`;Rt#uM}KGEqbo{aP37vcaAkH5 z%9c^hwt2d|Vx<{e`@v6ura%VQOn6DA{k7!r7)_e~itkbvK@cE$cMhs@noxUv>R6cus~t z4LS=lc+Q3YU*JI>sV9)`9`>>HuupA1qV81}(>R_%jwzR&@Si~#)OO>D!~ZXEpck}f z9Cr(t2uD|hqaHa1$La9rK^H-$JT8U*5;!vFhutuGo@Rf@iMDm9qP^C~bvbnMej}g5 zT`LbNhK&5p@RC0H-iq*f^NaeqhkhLGBW0hZC%SGJ9D)2(uM*#l>1E>O*;c1NQMvXo z4m1kbRHV?3EC_h2ze0?y|ODAkULKvO~G@v8lIW&8*_De>>$5& zQWkCYb0Or-2#6<^i#;-n>k41Gv}4&xd(j4BS08H^QJi0bPqY))3M>V zg9V9q0-Kw6c97>g@uGydY<@j)v3*G*b!FC!=d)(S!XKZ{WXL6F_~vJ7V(Lrrycgp| zFU8fb`M)Z+$oH~(Q303tMMWqEKv;}~d=CF6C;FZI{;8~@=d-+L5){WI^?bIOhOEwF zT^?=Z*R4F);5@7>AF>|O_o#b?y2~S~ zm&R@!FWFWKvbOZZ(G}r%205nR{0)8=^k2x}uq(c7y~xe+9_pp=^YzkRrpu!qIi_AV z!(R+t4jCM6@RIhq--I{0BdSfkd{MtC{(^q9W1z;f19@rWNx$)jFdst2kipX*UednT zk13a^epYnX54)36$U3`c{d5e{I94HNQiS6i_^r?tkil^cyrka#9@k6o;e(0)J)-(( z@o0PC#?dR*%8_TAy;|GZ5=rzthY#y;w>Hy0>jy{q=e?#rvWB7y1QkO@Za;WQz55A@ z4NcY6678yb4@1a;=8db@uM<5C9drEx=WNS8n*}uLWueM{_}+GE`HeL%5-=`O}>cY$*`V><+vdC?5hnAYXdg&fmQK7n_J`BnfK97%Xdy~nSU zmaSZWQuC5^tCx{sw|?dV2_!qmIzGvvuFPd_ZusAxPin+nv#w2mBP zS!iBhyGh=+J(6EnnW@(%`1R06$jCnnUQ+#8E5fJItJzKdymg^{{!GH;9@NsZzNI?+ z1P{)ew{d5Y1t4@s7MF9EE%mu5a>~XVTPt)qJcAsgSMWRdozTA^gJbM)jl<{_n03Q$ zIA%9R+{KOGR>5|i>&UVdpgdec}z z#HKh&ep>*s@Fl|7!OrYpKk1m~Dfj8{a$X8z$54&C6cRLyaKTf_w z2FD@rlFqtZ*W*Li>gR4aboq6Av%`tOJt}l!aKsZF&|gX<4(udqh$%4_T~ANVb{j+? zp~0Q2j>IfAJiBcjuJPOy$&+%q5B^c;3CQ4iIr_U<51Z$1cy?P2oA8vEI#0?W#F76{ zQ$JLB|4>CAs%%+|YA+A^j+YpMVJnFY zq+0F!!o#6?91dOS+@P#Q5&{~9YdkW0*ihoC#?JN=G;~q9jrqC#!jSgdOHoceRK-ZE5GfJi;YX1lsM`JzvOzq=muZi=CiFTfb!Vt-0Rc07vL=o zbqNd!?4dGrb&S&GwFMleUT=ZF6WRuu^12URQt$TFV_xnJ*%X}=SN-$_Qe4Ma?lE$t zm6?yzqqY29yx+(lFv_f&R z)X(|wS3=i7M(z#K-%a~4&u($eO>2#Qkq-YhDK}=dIqR*RF4iJrFdGQlL{}tlNAy0C z_aVG9+P88cBX2OgBqPT>m$jVUym5WavenJ2np%v&l5kty#4Rt%(}suY7H7lXiEwqdW5gDx*{Aqw488V z;#8v-3?(2*f~D?1T7H!O&&y>=i0JwAXk~@gO-`Xz$^=Mq!ykD?m{K)5-;L3`rTkBY zZ-v?*lkeN2znlD;XC!|K+N-;b;v1vF|C$s&riWrlAd~9+`qh!z= zil+CNPOR;s_?Go10qJZXz^N6d-S@b%(PQH-LGp z&GN~8iH$v4Ory7~^cXGg)#%-l-@n5DN50o)@>>D_Mfr`&UF1r+hr!LcZTqUMyxQ$R z&MNM3p5%&gRn8yQCS$A%a8ch72J}VBY7RX+w5mL;eQSN7BcyJ z8(vcH`+y#Db$H=|+T~&9&aqYvq*d*w21tO?Dy?3JyeSZNo9<2VzB zMnb0CR>Mm&aoEhdyGOZY@)PdN$v+pX4?0(g!QN%uTT1o_c5xQYS6Q-54jjB27h$P5 z4ujk{#<@6iBM`%g!9kglt(70k3Aj4MfCQ6MFDn}biF`3d!aCr3o2wV1IgN0`fQ^Ey zd7>__4se=$yaxX+^Z{h@VU5@M=(u!+{5PwyO+UXdA4EDQ7lYfK*X%Id+Jf6Cy1Sj9 zE6&|(2rE^fW?+JKbGTAJ)?I>8UbR!sKOuGQukq9)&#Wuf!?!{gLI%&T;U$^#pRNn` zf+y6gia>R#?al`h+W7(d19seZJC_hF$eu&|=>cpdlIZk!erYxaMrr^GQI75V*~Dik zbBpk#fn8T+4n}9<5ik#%vVl_G@)K|97r1$72bGGe$y{>s9b4U^*dh(KYf+5K91J&3 z(fO;Ipz%w)nF>D}niu^}+P@jE%(F*1hvTVi_ubkSylG@x+nn=lt11cP6n7a3SvFW* zk(`@)$oU5RL(n6TDaXg6zZ*H`*-IYMGOMI}Sta%Fxky4@<5ZomUA!;Ncga^`qHiUk z0!Wg`Y~A&_dRiJyNN?s@-*osGs!u9d2)I;${&7)3^E15DKaH!CJ^u{W|8r0!XAaca z9)5<&zbYMwvTDztvfaOlWaac9f;!ute=7J_;ZG>H8!4k~-E3Vh>HRb9c>?@2s17pq za45VabG~8r6NDvSRnxL$-E!G^EnL5;Wtp6>6x1CxBWB(2oN6`TTAB7p1Wg%a2V$Zq zvk3cxNbXI%*Yu-%;J*hw4jH-6!b^H6>d)J*)%CNRTqH7ge?wn1jF-9le*A#3b|}X` z`xrX1^xZl&RGs1yK|Z{3=r~B{yL3`!oUetS0nLVt{6=_5z0b)q@~cKRkbO>Wo0>wm zN_9t~5>pA~%@7<9uwr5jQABj#1h&Bmtnb-vI!-(rLwaDH=$7OACLCKtPV>PU*LLKZ z`R-ZxPUshq!SyP4K`RZ zmJ7HD7ckWV3^Co*5Sj%c2@nE;Kw`Qe6ep0NBqU)sSrAzkyo7+4u!+O6oBx|T_e!#` zf&BkJ(s^_4EBBl!cgmSlw(cBRquQjZhKcVX^jq!~&=_Xrs-|cQ=#`A=qBjHf_g`#}#f`qxrMxzAr}p1@mCoYN`Tc{4BrWJJ=MW1v zCbu9(#Q+n=_JGMLUFWN9vov3|W4q*Tb>ORjdLZQMT5y$C?^*BX;W*XBSLni`Y8Qjz zkV@4zej<1&RqGud;tXkdk%$?$Byl^H2C^(orwI*&WpNfpGL}@s_N}O-`JH9|Y|Yo3 z&<*>^-xUwz&<6lQzH-4;`m%na#<#|G`r#cow6nj|p5{Np=Nfy_HBO;!j+zvGH(P0s zRQMXlAgMW;k9z2Yd|U#41#k@z@^JwCpW~ymA7ynia>I!k*&pz67&;*z-gx%FKo$`4 zQ40Rg@ew@NSyfB@$7dU6Y^pj+0X6`-Dtr$>{(X(Px;~nq6OL;)g5L(*1%!M&1g_H2 zKwccmX}bDL#h_!`g}_ql>bCjk5LK&vR?aaV3RqDyYc%3BGe)~3Y7Y1~3Y}TdQS)8? z1mqt;IS}$O5?rN{d)E7Tzu>t#F&{xc#+Lg^shlk`#7W~>yC0+c_XID))$?7g91jeW zV>%zC)_J;KnxPlA&z<1k10D=`Q0t1Gc1zv)*uHf`*hzy%u}Z#WqT)0ZH)^k$#!Un# z$Iri&!4kBTp6Vjrb3GSL4HR^7uQr|tEoyr)PPi5kWf1=jXYNd5kHyxW&-q>^r(w9AN-O3R@Y*y+L6#~blAlC}x z7iL^u!X3ZCk-dL6p0kCT{vqxk*5CW!M}YqZLi&kG{}lbshs;V{5YXR;@*(sysHrH< zDr}ta4p1vkHCtej7BJKj@Ut?Yr~21M@QZ*Ofsmip;PbW}x_{k!na;b~H57a77sdXT z;!j!?a+um!JW4FYJk%DxEvz)Y?^x$xLU@;`ds5~-A>Aj@OL{`4pOiUINcp5Je8NAW zk{ji6vB=WXykRWT^=8y|?N@t)_XWyBhm%!<{0DJ5OWf&( z!Fiw-%5k5%fbMSY8}5_834RxF4-nG*F8Ei_)qQ^C@L*^TNmu%$=NK>8a}47o3?}@R zX$j~a;lAPc6Pt_-2*?9My1l?v`VzToSJBl1N39_0&R!TJ3iVBh@d2YsP7cjZjM~Mz zo;PyeknY9cR|D4rA>Et7RXXAM=NG8v)ox@mBgzE*j=54?W4Pg$s$-IIF#9Litrm;XA-4;W`z*}>AOZfQ_{?jO?6o9Yohmz00U z&h5KS-&t~g$&8X+tl^q=ZXZ{&xTK4(upgFO_$77H9`Mryy^x>pfVTpV10g?8fU9)E z`uOL#sh>(6_4Vs$FLeYMXIRQ#O8v6n`JdJ`ZYIHVfC3=orxaYJo^l<(_-i+97`k=y zd8*h|)jW1TGUwxQw@40D&)fj~B{6OXbT)FIu-un`-vE3Q2^VwfHfK-NIA}g3jIE`3kRk@I;zae!Ih+LfPbXu< z3e86|bi#S-dhlC;JAjanZ-c9J!un@>Nrk8;sGZKb^q^U9Tu_9AP+EY+s2=?I{r-U7 z5$;#QwVIdg8R&uly?~J3EO3>2H?Q~eW7c1)y@Pg`yw2a$b%-~yC=?yy7v|d(?Vx$c z#>9%VL;|qv6S-M3GcTFzCT7W7@zfJb#$EeXfwUSQKDZh4T@v3atb2smjRlAQ*ZGXD1igT=MTW21%3jAd>#Q;>8to$vTH4ML%5hP@_9LH)&JLgR-LN(tex4#=Q8j{ z;0z$-a}T&mpPr}d^O*flxB8sFYqR3BUHn?Su3Q%syzW=$wbE#nrO}%OLX1px(1PnF zU$}m$z|B8jsXa~eaR@pk&{6gEZ{U9hJ^?~L+*z8B&o9<|oTyzFH~J#LR{6PjSc+EJ z`(YLj2bIMC9-?}v-j6f+Q&oOOVO!G|3j%6qo z|3i3KZV#2K>~9F+zXKn2>ongjichW;-;aa80K5W(e7^&((#i`pzb9(fsau*<|7sSa z)ChI5KSDh!R6MhIE^B_*W2?OD&};JSGC|%fti3x zC)}rWYuC=fvJbtgkMS!zljg%iN>yy`1$YAp%ljF)N}pb>%X>J;d$tqv zM5i7KGO#~r8Q47k6l;Y4TBPJ*2hCHM4qK$9I`fAZ$c*{Dm3qq><&8#+T*;{>0(W*s z8Fnu->-SdlUs+}o$YL$()Up=CxUjWYAFmJk|J<%~zB9nj1NHzR|JQ-5RDY4?|3vKt z|4JRocXQOjae~isj%Jy|#(hpHzUjM7EvH$h_>I-FLG$q@bV{J3`pw7S{{XCcU3_GK zs}#n83C}lr)?+6Vt>RTQiZF2WO&bs5v(>l-CZ^+$OA($b7a=w8GGJ`ksQIXePS~Ei zz;6J)2ZZ(Uz4@At_7`-0Sa0gQCm%DXPNRe2I-yI{)s#QYM-*cN z@gUDIKEj1wZFbr_t(V#RLb)Du0a?70AV5p3C2|NkkmKcgwwLw_z2RO>LRRN^NiX$; zDDp~r$;?tuMa0YV@*fkH*URhukh%jF^W|Pew47*{{jl2ZkCdU>tFeo}D+cn`5JXd> z+|dIR-Y?VjD&4A~DQ~dXJJTFI*c~#In`LI38FtLW6&^!Y%*#>~GY7|JNLh)^>;#;n zmIqGHLSD1^Da%?cM2!=AF6vpw9;bx)7gR{^Iboyo~8)m}EJuiqScTO1>s;VYP4(gu6 zLvs9A()x~Yb`$q~tXpH=B`{R3k~5sqc{Sz=QDZKRo+H-q&OCXZwbrb{E1s(8BYSi` z@24J1xK_{YgWyjC&jVpS{~lbW*8;h}an14TnRyD`v&QW^)Ug9DR9m#y*KHsBgWe<3 z_|zN9wA5b?^D>-FvzHak!NDn063pBnobhsw9^9%f4%)x2i?0db^MS=c$k$qMmEz}X zeonN`nYUx3VyG4WdH!gU^RUkl_69$SmC6fHKXKr?F{FRQyF!lj1VYhJZt`3 z7{jq9cFxtVos9x_cVh0acuKl+-77_6#3~Hp%#&q3L3h{=#tH}EL_E!E%Z^)- zLi|COT`#O3;dI-MjHcI3loJpmO^~Vn{WuYdumj*Th9i?`<+h3N6=%mIvhmsaxR5M9 zf2=_17ChXzar&N8r#vP-P zRYQooo9gQp@ud|*^1=JKrQnmmM(M9?sbPq$0#1>sKHO)iy~0#$$$9qVHYrni%7vL* zr{2Viw1_CBQuW|GDxzn|3+2s{GF~haV^bsT!!q_)kv&abl(kNtA1E03-Nfj)R=4YY zv|DY^uFrzM0sIRPw(IBMDz#jy+cWep(AmF&c17oYE3HbbsfToI__=;)_zf!V)U)Q* zmhmn=;)dav<3WLNces^pjgBQzyH}R+%(@Xjs?jXDO@1htH>1Xp{hGg7%ewmiD)9Bd znLxpC!OyI%A2CiKE_;6w1g0sjMp{CLYXKPMaqwl?e>dO87!w!=_XRS{=% z1(mMRW-e0E!lGDp=5c1gXn>DFH5!!Mpy}3e-*CNmI{0Rw2?*(42(D63|AL+Mpy+Pp z;e)J|TJBpTw3(ZX>X@2Tg$1N=|G-++*=yF%0L zXsxz>!VJENwv4@@*IZWuz!38?w;%zaUd*DEx1ZO?PQK= zm(%@Cw3WJ$ZaEUjfc-<9;N!PEKifiEMV*i372x68mIZDJra`#)f#DpJ!)q6Z+q_yF z1!l8TX0RUxz0@6=zkSeO$+hag2f!Z(o&!Su-UnBy?FYJ^-?;WT^}S`+X5?}!R;V$g zU99vMHt*>5%?h=!X+z0j_@6NFUF@&CCB}<&1ARkLKWgm_h-Ty zZLSNPsnp%2`5k>q*ZJvO@Kr!P5b}F2xX3^JhmhZzbLzJXoQYsagxoJIKd%nU#1T?3;Um#@?Xiso5G*9dK`P(&RBDmWe*%4RhAW= z%d}$pJ^4W_hs`|oq$uLExYVfo$#SLxHsb-BWG#m@4b z*|5D~Cl6!;Jw)}7R`GY1SM2ALY6aeA-Y<<0sq-dzHUq6vj-&C37~L$S@060< z>MlNJg0BEp10f%q!M`3Kfn@eLe0=sLd>G%=d>n*Mcz*vH_`AS=0wEuZPSt#*Uexum z`A0hcVtr5U~q8EXqx+9*6lsyNu77LyINl`PO4VlZyiZoXNmpRyVB3@ zH2rLx|9U`NXT@OV^Bm(|f-)CanN~EuK7%%0km#Q(%=OY#&0?15S#m*ffmiKjvC17N z#xr8YkW5b|{D>FNk10rFsgRbDxn|v1)hi~;79p3~`ZL>cEmJwRb=~~c{oS)-8}ZNA zpDtk%R|fG={&a7n*T*)A^^V8z{``2gIf9clJ2oT3PT_^El#oe7y*?_Ba)sl=Aqbl^ z7GdNZZ|W)k6X9HCSsPL8{&&A`Zj|S;)Si;{ys#FS+j9HooXY8-`I~S@+xnDl*OL0K zd8r0`5wIKx>w7P_N)?akdTzV@IQ6}5)7ffHV$uDgUcx+}*WOp?t9b|f;gyJopWt;g zjSflyD$wKPR56LDQ|SV;Fi*}wYi2~2oAlQ)_N>@EwO+YHIO_$fUr1z;vp9Wlx!Cfo z=KD?f+8^|j55TgK| ze?!X|z{Nrx0$d|F1!yx{rE$nBwfZLA7+W;wB(~ScI>b2iO6*8)8w)@c)@catrsJXn z=RbI+giig7ny=cmU3wggz*hpRfsn8D;41a>*VOqu;^{~8m4#ZQ2R}=V4ix1FX!DAR zR-i)G7SLOliKj#0? z(_{WY_Il1C_43OMbjmL^jiX+*RUBQPkOwUJnAP7ZWO85slqFj%v+N|9<<$~UGoL_b z`E$I57a+VXaLTN#!R8P%!p@hFL)Zx8l+vDWFYtAvF|Z^h&5XQ4mgz{8Bk@5~Ei4C9 z5!+7BO7jHF<2fI0t;`_W3wusi?f!eAZv@H;BDp~>z)vS)W_O4)%pGbEW)`uNkzy39 zXF8sfGsl~4=P=jM-3Byyz4FK87ufcUr!4zv%T0Mjh_VKFIVz8q5SA@zmoR*2%pG3E z;6apA7Au?%r)&lo;^d|h333J%4NCO#zVLo8tT%=Axs<;alE6^?Q84N+n{X_AgGi1@ zZ1;A`%1F6$hp;ae$VNqjzfWp;UH6;a>$>DL*MQ#&+zEv3ct5yGCzO+^c3it@r=B&k zYL}u?TYyS!o3j1CE2<)EPqMPqATib7p;fhOx`(-M_#Byy*uMc$K&3C8r*>{{*rdV> zp3=B|+muZ^)xpd#s0}kdj1J?sO~L)^xK|0+>N(v8ejcy~2+MUdxJqAIuH(?ks%@l% zDx6`Pd5bVUr-U>U8q-NO9cgc1B1={8G;5Y$%j_$Dsmt2|y}E#(Pr%LfJg-2=PdT_s zRl)x4xciD78~wxS4)O2uZ6P|u?c!|&b8Y6`mT^mrjRee8sUxv60{9Vai#S7t$en7` z{JT$M$K1taL$qau;%X=z8ZHoDYZyR6uJj8KUPub{zLfLvpQ=w{j2%@Yoq^4 zR5pLbc`E`y=X%q2oFY5!97clXv?Z87K9oiqlgBzC-;Y>-jg-gJ@qTgJV&gx?99s(H zB~LAlmpM7HTqjwk3(w5kW*@wIRm|kkqL?HtHmVO% z8M?pB3;IiQ`-%F?3ZevWJIA+`C_55;DF5TAI1=6YF`ly8%-0KyeW~hXF;Ts$kR21H z`E+w*WQkXoZ{;tEVq4}#n<5@#!5b_t7^G|Qi%X1%3B1^LKvz@H` z?9>u>_!PWL7t2dU->iOP}89hXhDOywnSE01slwbo|BiEkH7t#x#j{d zS&~o|0#^%(RGI&qg!O_*#FLp;oTFS14FoThPuR0aJTIMH%&u};@3k>@3e%!R?w!Iz z=Dx~ZN}qSpxL)Wk7=RXuoyVEwV0RGfVb6=$xv}h2mR;ng-Hgd{NYbk=nq)_aEtODC zx&KR8XQLj8MKn`1Z35SAru>!+xOq^BH-xxTdh6r}L}#*rW-=$)Q_Rw6Mb@J1zIjXJ zJ;E&amwn8g3svtoMsM!gcg_P}4y*#gcDfW?r7xAItqn9BtW>ko@=nq$HwxqB%s6VC zw&j_oh#>cT{GEs&kShX~5JD#Q757*%^a(_Vg zDEAHNI$Iqh0we&H)OzTI^qPEPBOo)vI4z2L0^L_z{zXvkV<6S#s^?x!+((sb2l(T_ zlR#Lm9Zi~6^Ygk~pFgVeW9HNF(5Ay|v)?vFhxw57vuAbow0`q`eMN`^^_BN^_N2~! z%V$w|JzRjjRV5AOBnQe!I#%pBULOY3v%R=A)?1&tUz9`>V?BI!oX4Y(x?Y+WA>~Om z+I7kqQ~q@#{}$mzQ+twBb2{lt(}_&+KN-`jSE_fvm^V8**3;j0_}&VlBNWHI)oxA7 zEAzkSctkw=NHCRI`Hsy|TI4@P?1;$z6Sf!bXJYBa(&P!X#t^8|WuuT|MKKIcxrxk( zQ|3gim~%$fjwF3An#!;%i*lw4dnTb3S9_;>NJY<+Hwb%K;cy~hC~g%8qwJ|s1QG1v zh@V3TMD94T7Op(P_15KIBkoY2lAepHX{RPKFfr$zx<>P&~Oh zQJKuKH?N6SI|JP+gqNe-i5zEIL#I=NGt8%iceXva-g4&4v+bJb7Kp|1o~6VU3}WGI*+~4B}$8tZ=hnu@dQFrcAGAwi>ob%Fa;wY8wmGYd}4~6r-u%9uNmCY)D$=Q~n`{7~w+327j{tviy z7JVHE`(YYfr7t}n+O>0A1CIs1*BY-A9^I)~7#)OOU9FDAXXAd&HEL6u-b(IQ%l%Zp zKNI{C;2S_lZ}4_aujPK--%B1iPQTxz=^=n2h<)T?$tF?YY;y(EpB!Yrz!?o2$y9DI{!t(GL4AE2 z{4wAOAgr%FJ9K^R{c%uVcO9p`PT!_fUUsh7wtb!2pY`c5Z;APX!4HGS|1SwFvMQ}K z_B;7V7MQ$9pvq0(F!S$~KCzVuA_5mH9CUR}O&?J7`E-vI2kj3Z;q!Sr_=CVBK*;B`U7F91^7uZM)y@ zZRQ(VQg?IoIRX*CVBVB4J|QwlY1Ga2va;!^2u)oAkIG(_ndPS3_^5I@G{Mi7XzyaQD!r6()6qtU8~lc+lQkZr9PNDf%USA zjGlvl<}8_)Ok^ZY&tZNv-Msh|dzc$@t$|*mzpu8!{ofZTBCr~iTg1)6Y?L#JW;PZh zH-W^2Dl_)?*Y$H>P<}O@{22TN;1wXOpI3v=!*xNJcg~}MIhpnbFfSu!yl7r7jD7$< zOy=sv9rQ{DXnNk+etkD9dimhJfl~dRPqY2=9`(;T!t&)jbT_boQ{Dp?Fa@bUj>yn+ z!Hpni==z;6*J6?S$p*S&%UN(8TFQ^=hs*L7x>z^dHFK~Wc9nZ4_-^1r{hnX$BR%QsGyUcM_=`!=%gU~3AF+bMKmW1u{JQq( zD*CG2s;`_F*DgAkY$yP|Ca?SNsYdis1AbHIb@AH|yaG5$zvuH?+mm0$0Z#Ro`+ew} zieFxugLd*)cs_5`;jDmmK^JX>L4A^+Qv%(GEI8D)s;~XMj3maFs@eU6biE$z#^+DL zUjy2^@!8RnPjx2cGg%Ff)y9XNEZPKV@hgRhls-Ft1GWcrO3v@9k73}$fzkRszdl<2 zXTAUZ&T+R>M%^1ay^R}OM|YZ_V;%|ayHDMRU#ju;e(;xop8?_c{ugkS#_!el59etN z618Kv9p|!3+Pt}P*VawDht6!=scciXDJ?2a`d`r}{R92;{>A?5NlLZyka?47j4kz& z4%!u*QrH$6WjLW_N+*0bl|W3o@-Wq%!&PQQ>e7=vFr21ue#?Q=EM(!##MfFu{Z2DzD_aOK6xK?z30sbf82oTa8 zdZFg4=~7)^p`W3(yVh^oh7p_cg3-8r;L!D(Hv6(|)DRGRpbk;szxMH8Z=v3z#%t!E zEaN^=%EEdn>K&ewj^-dFi8v|zHkm0&RC7}#d-uZMx09Z*%{ZdczeyfJ8B$7+cC{@1DmBhxzS2Eo0TsBPTxH191fVuIV-}# z0T=#uuJS&%!TV!8bT z5obTwWX}-&d`+|c!-MiuzLKCFZv%e-co+!F|0=jjp`A(?r~G*3S27#b;p=V`cnO>U z6faceyj~h_n5CTDC)mhD+)SmC%OAdX++~Ux^!cp0BJDR!>j=$P{+=$m$Z+tSRr=i#^z=9=%&2ZHZ+^H!S{{XapI{=%#ipGoe_JOVawfg+Uya*1?qw_el9ltaC4XS&Y?Pb$g$capvE0@wyxp7wh^}6POExL=)OrY`9!XFu>t zpauxbSsQ#FmM_e^)Ah@#9G!KQ^H-F!@Ob5H59sa-?yKte9`Hwi$AOUU%faU%y)f@i zw`tSqXJWU|u(NT4Qs6^OQ-7VWS#cdT`YUsfF{CISl|z*iKDBbopqgid9wTv>OD(W( zzO-vR8Uj8Rm;{7;EC%<}`Ro1cczmF0p=aNDo3`%Stwy9~p<{7n?uo(3Q^J^1inoNA zGeVZeP;;{VIbyUtS3OEPr6y^9S^|2iULFH~4tNm=`T2G5d1yx%>V0&t7r#Af6d$!4 zIYh3R6lFYo1_$q@-ZGT^l>ZQP{gsZ#`7$0nzwH72lD%E?(~3W&T)RXNvviFD*aI@n4@6ewMfnHr_CAju`c8@P?Snk^^G{%w^t1ZeetY z{3YJ2B6BdLlzsgLOw%-7zs6-<@{uy|YG4!)mTxY&N~tS!xx#U^d-*nQTGu#vL&K)6 zx{SE*)E>54Ir{R~5u?;H;tlh#Fm4s4SmLFfGP@9M4jIi=>#C&~@#kBhUf|op+{*k-jJ1duh`5D?OT4P2$3<6ozL>Jw4Vt3M-fo6>In8J8Gv^4reC%ilT^8e*s`MX1G|S5qes;h44@m#3xlJ}l z#9g*h*^q6j4?G&(_Dy%9@*N?Qya$GiE6L^n49Rd3rKst05HxP&eQeWhztIt9Jg~qMrJRoPSK0)5LUZ znmOH>W>5E~xznT5BGcp3VndVD64O(Q(?7B0qrSaz(<0r@#uZ)TeSh$ifMGybzr(>* z>Zz~O=@+_T$JSv(nRRdxvuk_9=40bmWHpOZ_jtxz=5AvF6TyNm%ef-~{buf8!u?hI z-VJ^~@B<*E-wLkMSI|Fq>&}MVC#1c)i+0muUGAgYw<@5Uc_s5aFdPW!UIMPt-fMJ! zdiP45A6xFG1`JF){jqc!b#C!Ty)ysxU;RDQTjuvIKMqB{uuw8&?5<@T%;v-p!65P7 zip*k!11O9jgv}|Z4-v&X(w9SLHvb}Xan7QC9C>%c)I;)#@SYduGU;1EwJg=;YKQNz zTpxfZuEPEg2+K7CT&3o3>GHJS_GRU&QL7kCDc%yVE2kV4{%gN(um8daQQG%4%Xp8W zozk&Gssub)POqP04UF`6`-}2^Ieq&%wwitJL%S?b!Z?;+-~39lChahK)NXZw?IR zn#B$NPNqt2XIwTiZ<#1ebx<5MsJ(&8Y!cIXE1HQ)M=r)21v1C*up^RMaRcOv+FU=a}V+X${wPyL2t`CYj7jK)e7BkANV`)cYybR zkT2(2&DXw5b$@94hR(l&uTFDcI{Q`fb!0s$8!n11UUEntYw*n!5N5EC;xJvU?f8+7^^T(B*m8TxX zBjP{IkA*lQ7Wl6>YOD5rWQyaz;QyM9emXfmK8t5C%C0qv4sN+Du-t4rlJ-3v=10)C zp${O`h@_KIwE;keF*%EEmy;`#nW(7osa?SKR=Barz2*|`o|4W**}p@gw=UJe zm$&x1uJWz{KN~n72+R90xJubUc{iW9yi_l!2>M5{#Ss4xX?) zGaI)yGNW%guW?;hxn9@h+Ve2yif@^Jw~bcLlV@3Lz1eWj6GC(-JKG(ls$B8AUh#WW zh>hwEm1;L>K6k@MI3C^s{zKp(5c2s~aFs%N@4?GY$YW%5fU_R$vDZmg6e$uUU@SlSgzf!DXE#P&IwK^xe&9)}1c4)w9?LQ)=v1 zscN(4>rLo}_4_w)`$qJOJ=HI-0RJ8E2O#9<#+x)h@fUPE9|_j+ z$Khvb!-mOQ*P-~nVdqBmu(fmA{kkdI%?E^^{p6VJXZq@(&R*5oWBLb6{qG;p@AZBi zp5HQGNf}3-O0NL7`6jC|UcG1^b3dL7>=L_A#ET)Kj7Ax6<~u7<`SKj*GAoh5J+mnz z*c6y$W~E(am)gaV_^e2Ifs5FuJ_`v)ZVelP5?P-|w{uRB^)Yt<--^_nobFy~|n0ty`6Iqty+9Q>pJB*=nv`;jq&=-Y^ zuE{ps?ma22^X$dm6(aGVNc}`aT17n0jMchJx5rWHyFO?Sf;SmcfmuM<9xsBcH2!Jb z9<4vo`ElA~N#j|&c)M{S-;ia^_NV4QEYWPY3O~D8XYc4YNBQsF$$P5z5Ha~CubLf} zlf-S|EH5`TJI#R2%!P8l8z17u$Jk?u2az^Q%{flFndwpVX=avPGt8|nk<&OjQ&Hxk z(KNoWIk-tot6C__oWx{nUMhwxS)}Dzw&#?yU5d+C)QRLH)2(wxui!4Kx6ZZxE+xK! zjtV@+$^)icqD(vd)ONnEr;=NU;lMkp-;M?E^G(O-2ZZ(X-0ixaHvdl7&%U=$SWh!H zHEvd>r)4cg-?a`DiI$?vOh5af@Uy4%)zzMVb-Dh^f9f~?DE&8IwEgS}$ImADub=7n z9@SsGL4WbDIt#9D(N}*AZt42JdsV-AvCh7&c{rl8CH^<=)F0ih-@7}*e{-Dw`idsH zUw@?EyF_2CIZ&jYqqlH~9ocM6_Y$HYl`89f8m%mUC1jPeg9gsDGO@e963dMN(m`up zH)xePO1YYFs$^{z-Qa>gaqlCMdX9$>QIU++nuF7K3irFpKFjkpkG?0}A4wN$n@N?7pt!eiv?``J|c*e)~ME_!%pP9qu$s(TV^-EQH zB`H+hQ~eWG&D+xLz#6KGz#mR-;Q`BPwNeGxHBr{#I9^(fN@c1b7G)8bkwS0&EzGzD zLCFj3WL3Pj|7QF;VZ|j^iIaGSVkoy^!R-zj9mO)w_No|%GSlbEs;5l%Y4aRe`wcNF z+uN8r72jMq9$4Z{_4Wxb;yHz4^DG((xVEG^PTUD1RkJj)1xZ9oK#7V8$2Qs zF~3&1LzR=+f1Hykr((EOW#{>IcMirLQ!TstI6r+(B+AFh#y?5-Ls`NzjuWaoh4mQ< zPl}zA>!iD1^7F_R^pO7`=6vCM_JZTw^j}1xXjJ_dKKPCB-V@&YB9Yjv=p?++cGdq1 z_y5E>P9l$y{HN0WnQ99&yH8)sx=Ok&(k@L{Xd~V$&G$|BJ*@lfh`M;)qBq+k=p87t zr)upniDb$Aic+(X8KZdU+rsN$d#U<&&1`oL{drgoG2^-O5}eFjDPo_A)Zc~uO;NF> z{51Py^_1mYE1YXY#Fd%OJS(e!(~b&rg;f-(7!$!HH#;+$wsIX=bG7V64b+!x3F>L< zir%TX7fbdkzFOK>$&po7Wxp?c$L<}=wp@E~LrE%b7ogN#!1?e1yYEbd7bX38ukZQ! zyyi`c^ExRiS*1r&dn_M`;H+dkzZ|!wR0;MSd|`h4U~^^(kn{pR0Vm)p8D7!^|6eKW6}D z$fc-WUL~sVcjzysZxFH`zaIk@%I)Ph$w3=?%_!bD_*Hqq?*(ht|COlEO}M~3OD?b$ zjoB;4PZ+mu;?${)r*w#{yOs5DY5zVq$^m!D;!}#w?T6wqR;;JUXOttN!Eeiw1{s~7 zx4Kp?UvaBAWs1ZSwn1(kbG_)lY3*z|b;2#e-s*6*SFEp{G^hXdqN+jG4!chbz(j%7 za)Z2G)GV&Td7m&|NaB>A4Rx-QVfJTXmErnsCC|0`vmmQ`O!IRe^y;9e z=HchTUj^EMke`16S83Xp^0RE~79@5XeGvpZ{qG>XQcS#po=!$7hR3QNwpex0EqOec z|L^KrCrt%k0;~i=x|_gNYI;=HL(6gHX`OU+RL|`VTYNpu7W1Haz!WX!oCE%L3b$*& z%BZA`4>8a>7nuGcWtO#p9>E|i=dy{a`?2QhAarY?tLozq;C}`_0YbjsI-vP#3*>wy zw`l&3Z6AMq@2^YhaF4O25nUR^7-EKI=?fU1i+xO;beQiXj30@qa-GG)%IbHpjOXPp zjZUzvJ~EC=$*46!#`~g}ROS%2C}LVEhgfuxURK3m=}odTtt#2q8Y<`7^M*)oe#I1C zWny}E(jA*SQx->xGUi3cSXJyKHT1DEM=}ud`Ji0sjbS%0h78NdwJYqHeUjC0p0o#M z4=Iw~NfNc>A^kJTY^FuK)G9j$+#xdFr*BzC3>hjKf>;a7cvj!sjD$};mYpn0q%%})GyLL=dud!J>!gr2LIB3~734cDRgGSIxiBp93@LzsH6eO9+aZA+K@x*q&n zz+FJt4oAUN`m|Zs|M8y_PE40=-K5+VHf&x>BuRI=?3wgbie-+|xQ#~!sFX(!hb+<03>W{0zcL0|GVLiMaeE#MRT@Q87 z>HOIK7@XL#r5ogL%?`VM_C7nbsPRX0w|TE?<@pD;?Mx@eebL?D@yd@n48METAbTqE z5%3*yUW>>(AaYuSyj!VAD5Zwu!QY*nqmKQMD#tu!@3ugUv>MFUg}UJmxgfG9T8KJw zA=RPssQO;(E4sX+@98?9TMNDg*bao{JsVu5p67$dmbYS1Paz*3-ghF;*r0kqQ)3Vz z`CaohVI%PGYCfd-XoF5Z*Q(wRga0@184&XEf8Z*86(3OTeuC32PII$3Pwn@o zBUOIae1~&7fOEQlkEWjn?f>mAJ~o4&3tR+*d|U$lwfN{d$@vl8S5b|*oxJqBM9*)PwR2C6c zXhXeaUQe$C;AKjvz)|~}u8$7rgnWDsZhjZvXF$kD6kMgAaSpoG$Ep#hB4BLXzP{n~ z#**`Okc-uR4V+_GSR781LzKpnPHh3*mE1R^yB+*O;1VFDdpWpDCp^FZBGtU6J&XrQ z+#(`(qr`x*9``E#c+m9op#8aTiu&Kz$6BgXNY>g2d%elvb~cwOxcv#XZtb8+ZZa-Xv{f_~)IWlZH6bo5l|=04miM+)3&N8vqDo(?a$NQACc8#( z1nOt!>JRs+4{sD=nz;-W54tss8y5@Ed?zfUtkw7JMG+^Mv^q z`e(3I(Dpn-QI&qrY$W14OQ&J-q^{?2e?a$ea9>6DD7g6m;{XuSje)Ba(hKuV+bTD0 z+qHAk=1`496PyXb!{$ZC8-gKln4Hl`F!cvr&N}WFK8NRkp9fqN(2&sS8P6;zU*qP@ zo0@iRI-SRF>aOi)H~Itbj)6mU&V#2+9%IHCL=4cWB%pVQdzbK*D&HsIp9A9iUF9nT zSLw)O`nkX01)YBd-Pt=9ZuJ>a&wQKw5C@iugIg@4sS+3R#nv25$QA%aMA7VPjYafl z?7+D~EwjQjpoqY(`Lf)1@$J*EeM{HRZukku$D6u6IoUQ*(}mm5?JI#ukoyr> zhTv#xtzKg(`l+`yzZDO5=_9NHKMS}B2>JakxJo5I*7aKT;@7I*2A_2`zRqblecRei zp>y6nzQfZSOh4ua;Z}%r?_r>G`4t{V`i#+P@bFVrfmgk zVpxu|rY2^^LfS%wSslUa0_8=o=^b4z;|E>mME$^r0yRKbu3B)F#_!kV3FA$CMZXE0 zEVhaNM7u)un5(4m3#z}2Y2bF>gkm_H)X5=opc2Hhp8ccdXFv49eg4zne+2R#>f-0r zhc!R-ztQ|0{a2lT1wUBjbgSU9_ShB9>oL(Dd&cv#_j3L0GwEk{k*Ny*bwyC&qk?== z*Z|}n5XM;u^9#3DH~Hb8O^>Nt6Phrl*jG>!TjV8Mq*`}miHLJzJ7ShYoi&vZA>QtW38 zKGi*K0Ov1dNfj<&o9XUA4!IC0DYkIgvjyvS1qHOaZ3QCAw{YZ9XP3Hg zYb%K1T$}AXpk|B-bk!nB%8uW7$SUN7Anq^)0L#TJ$umr8f9wDqg)zwhrxCC3chV2+4Di{8Jnyt63f3R%$Kn0CIipzvL+)ntK?`2qTVt9|I<_r@T88MI5 zIJSl;IWa8h&qT~yf+s{fb51V`-DG_(@X#tN^{|cFmM+JvA9l@;=YTf@mjPipt^rr+ z>OGqOaNqkC41yjb`_KPb}|LEUmIMKW{=Wd_MjH9(jzt5D@Y+ z3|yrnfn2mcklXg;r&DsPp3xR@i+Mm0OGHOdsyN_JZQrzvOVBDAB(t4Dr&-8GImGE# zz{HCNl53VJP-9w+{Fy+9s){-I??*kqLLVlkPJ`dNWVcwHp zwJe_OoAhO+lmX!f<|N|*yBEev`Y)m!2lbLg;evI4K;L^@*N38C20jcJ354`F2A_xR zcB1u|qF+}t+K*4zEPie&(b3Jy(dGx{UNn3V&@Pp0IkLo=JlfLeGI+~~5EjMGPDO&S zm7X=)H~GF{Qy(<|4w28;`bu(%YZ9@kl!1@ReJaMb~T;r-MZ=#BjGixYG$Qs+_lCB zgnI5R%ajCWxH7Nw?_wAw2~D?y`-XJ?3jV)}=8wDR#=yT8UEQW#bU!;j-TeXGmE1R^ zyA^yFa4ry*_fqh$MOU{?7u_ovWRFu`BdN>V9^6;e^9SI62mTKT>5e$~PxOoG>YyM0 zz*hbER@IL`GT&#UJ8m~-xuO1u^N6_l1fBUFM|b9?wC1-Ne!_aX1^iCnZXo3M0r0O? zPny@Px-|TWTqvs)NP0=h@IZxc6G^_2MpaZiB)Kqa+5-Fwk`A3xDJ z(*!+#W7vIb`Vn(XeXupn)a9$^p3U4z(YXx#X5cm;EZ^V2RjT`rrgx%sQy0BswxrG0 zP0Vbf*~(M%+ehYaEn|J9oKMtao1^Waa-d`>ivEPhfd<|pGwc+enD8UT>OIHKH8~r{ zacqHIh@aUMpJw(-+u6xJc0c?x7DoFb4nkkr!SQb-ns4VI!v*amV&gMtHZaMW9s;t9)(s|n!9rmN*ZK!@^UdF7VHm?|{ z;&co^+HuTvhH;OmmftpUedeLjTOwl-FPWS0Qn@k*J(`H}h*)S*Ky-WomG=ZHq`>QK z5%A6KW%nK)N&CNpSlnf&f}>=>RuI7qR$zdZBY_BDD^Szhd#2ogQ7mh1zpk3|bv-pv z5Bq|8x&izS;BFwSr{99B^w`5+x1Kte(0z`We>Ok%y8%=3%WRRaltCS^0f}31%=saJ zJ1`$m+=+Qfzk|?8hG)R_&!kn1!}reSHChTa-xW_gMhkqY_FVwJ5;zqI`Mv>MrK_LN zd>=l+`oF6mAG1U&Yq7p<9Y87WBeUHy{y_WPcr5RV=VN&v=JQTajga@>D&EhREBuw& zk=~l`4*1$1@Ev`|F|vUIAmqCiT&0e?HQ(WU*>hddlkaXzvOX>5H#o*tygy=Ml~PH3 z0Cu*XL);Q@~jNU5#%hwzK$h=YFVW!j>NL*gULScd}ab5~5*px|U_U++aj!8Q) zgwiZV#?U2JqEXVh{4m=4Xnw1n?UG;32A>Di0V=8S^YD4PKEG`I)K7Rd^;T^hVK0;x z5l59*rBsQg)6$L36W}iZF9Tt{yaBG#hkG==FKa&?al%Ti^8F)zgfa9@W*oYMp&L;% zMZFa+AB^UJe#vuPa>X&=(}6iaNPjc9O5P=3O`j#aYLu#P39P?eM$?Z>LU|s-Vj+P} zHYy;v!NV0EaRkbhRdzg!!OD+deUIQd)+26RsjioU&<*8>Z-93I{{e)2Wwrei^@35# zc7GGDS*!F}`#|^sK{RUwYxY^g-6ad@JR2v$1b2>RxK=(xBYptXh7dL1P3CByY(oV(Wm@#E|kzq_DYFY4!^lfa~`)Yo@=ezuh^aHN| zP6AX?{d)iTn$Ium*P2hhf17|gUOuptB6VCb5kZFWRxPy%3(kY`1T9%4X!JMI-#6<8f%mPA0a4@X$+_aa8T@|XA z*c348MF?;j6yx);v;r`t24Q@v?XyeY?OypfTa z-Yh;D=8cZr2b=PvZ>qGROv*aWW@m&;4}rW5DaD59TYukcpV zfTz;=e~cgeh}!=_Ipvc;~QUN{F;hKat^mT|39D*GeFkjO4lx|iW>Eru6ON5--w4}fyxk+N}pf{(~!zJd0BY?7?+ z{6?X>#oiiaNrQ=I*Ia;%6bWxQN1&`8;j>8aM^pm;Dn)NrZab9=6AsgUqonVXtshvy zfY5T1u8$_lJBxm<#)Ip@zXv=Bg!NJRvaXNKPwRf&@g?gB=8t0}bzV#6bDn7P8vNJ3 z&k+>(BlA~T#;3%RJ!&F&EOg# z&9N$Twi_i7a4u5bXdkbi|6LAXqkX*r75%+Ic=8)$1JQxr5W4EnH0$b=h^UUFI*@uK z#&~o@Z=$V0Js1@L+be83A-<|Nd1nwQcv^In9M1?NB5UmR z)(&rHMx(tkBID}M9#M_id-eUtA*X@t%s;mBDb#*-nD}JSOXYt!@tzB#WFR=I^AB2OTE51(hoZed?y)0Et8ot}>S?Ul5y>!g*{L*}CC;E_G|SGWg3@+A zBU@owZI;*@M0$DX?a@Wl_=dkws$Y#^GOfI7;;BF?&9 z%WI_^>B#78Zw~jL=`H9r->Zu(v=`F_>Y|h66ap+RvzPPP68jW>y~899aX=+Cul3Z!I9|O@-PUw2 zW6-)yJ2!3H>g$k>p+?6TS2L)aRwe<_y4G*40o{6NgwK03_?5tQK-jKtf~!<@qki5` zBv(`G?_+ihth(>F^{V^Vws8m1>rjC!(Swp5i&rw?mhpJ|GYXIRN;EdTeA^s=JHR;m zJ*H!JcA2pVj$m^fOg;r3)caDGzmwJ{{z0hEma%`5uD^<(cAbCB0AB&D2EuZDA6%u5 zZ|QOzxmoAOtH-6=I!|oN+O40<*DcX*{f10+(01E+Ia;lP01ZWidJ6mVT=wRc+PSNV zSEf1KwAIwhPCY``w3&W+SB+w7ykQi}EwFp%(miwOo+JBEqrCOn|Qx1pi6T4RZ72@s`|U%Y8vhZOrGEJ=)83He+^?5 zslq|l%R2Z&)pX6z=vTY=Spt44uoejUxer{Wud`oUN;B5Cg4y<*s=07}w`omfs4bbP`92cxrRp*I8hc@&7zp`Z2(D7t z&L?^veL1(5#U3j+{!q!e7aUhU_)mzrjjB1C-&^4)Z1*R@p8=i^cvR!oSLu;7!Q&U? zbRV)=U$5nKwE-RP=Uw}}Qt%_!%h2GbVGo>h+e@s){&8oW%6r6@J-ho3Hs>3H@5?LABpS z;QN4UfRMjOz*X9Rk8ZcRJ9Yk5`~}B=IP>|P^$&)M56#al&O!RY+Z1>k#|hgixr+T} zlBElt-kIcj%Mof8xKeOlJB1+XKN4b%H6&Oe)YfT!z4os4!D#R)z)T?IcPqF`;~&#} z?tlFF{8kK7Ph8zLG)4yw?L@oHczuq@_q>nMqWaL>A2Igh2LKf+#2=+-O3lC#;}W^T z8cy)D`8aEsEoWFy2{kLvlT*=ce@V)AAC+*9mjAZT^r!j8(=c6>TrAJB=E$+>?Cg_O zuKs#u7dKdQ`pZEvLcwPB%^t*6jU4G;os>76t4VU2f8{i={7&$#9OvXEa;1Ln{n|150u?}5?%TjsT78Kw?}^5XFZA#3g5Y-fL-%zl z+9j{58s2q{H_$}tjd6FD8M96@U0KV_jjsg@LzLhVEwb2f;&a%G;dvPMD#RQ}dy?f| z8hHxN@=a@09M^69ZYjSjO~>OA0tnz{!oolhSD{f4clM|(xT(}+f2f`zFR`u1g*a6W zn5}09<)?flluwmE=MBf`4-5jr@*f6QspBDC{?;JxIUaqX{KqcJkH~BLd@RKgIp<@) z1}-TvT8QacBsVzOcEZWSPEY@-Kvw)&C!-Q`GCmpk^ZU2T8}vJ!*Z&W5ZvtOcasF|i zGw0kTH`^s4Bm#j8f~-PVR6v#hf`B5COU(OKq#s zYD-(IY3)L-)znr?t<}`3MeASR?{nr%&do|d-}m!Q^1J7`H#hVA=9xLOotbC+Z>04K zPY6ZT7&gR5&f>h1S)rM+rn_TY3eLvVtV}1Kn=!#*)4b{%l6~|gYN=YK(g(%l+Xd!c z8plB@6PVL%`Mvm9yqV>2 z_?@<&*!LXdm0%4p_Fd=y-OL-BYfJmeeZ?&mEbD!rCB1J%xy|&l-hzv@zFj)LD$)0I z%d`@bat!ewW37b1 zUxugXe4X)z!wXwYy>%ZPJHvD@NcOBi&rK|BeN2=bGRPnMK zPhpZS?-eO*G<(IK%286y-;=6AZVK~l{grmc^O!# zKl6Ae4$50PRB-=NxbyNzOmj1A0`ARu3rkalOLd?0Urq1KZEpU`6AP0PoeI*iMW@61 zbC8ZM$X!96{!Ef^+Z8ZbBobx~NKV>N%<<&e+uvOyjtgX;_cvh&Sd11 zKoKzcUC^2Q);V1t`&as_G0ExMGpzf2`#IfF9t(GmzvR4cF*mC1=-Im|$9U(-d^^Y; zFBi>Un&p|!tK`?NUVP>geLZ+yCg-9o>PWJu%VDAnCkt-Xc3kn-V4i9l@-5&FVC-mh z&`x^yjef|fZ<Dt z2YsiuQ_bIkdC9%VuY%Wr)Gadq|9fN!9qi|CIRy5mdz&_tW*42oisAR14VJq>CYpQd z-TXy&`Q`ncK>u{)Q^7)D^q+w&!R*sC&rO>A8FZ{Yw|EIYOpaVE`vV?gPdi}qR}ri7 zC@WsLTl3h39?as+-~0;s4e%FWc)Wuw!OXjFxn{ZdzNLDZzwuWtC+(_bYwP*XDZ5Th zdyYc-k@JpibpvegmB#`SQKQeJ;N4&zX%X@Yum%_&>yRbPxLoTu_UMpDvn9>d>Lz_k z(KI=w=p$#dvhsk1|ElFpR`lrD_2*G{&| z_m$NhSWn_w(l9B!NAsA$s`!EEk@=W4$d`c4!0@;VS;ECthhUdrX>Sc@-Fkarr^#N} zk7PM#PasCw=us)YSM#VxPa%4Q$7jeX``Pyc438{i3EK~aNAo$pdbQ8?W;v(HEaykg z&y>{*SU*WJi&cA{=2MKm0-w)y$ajHzf#LHYvV?>0i%KfDtsd2IFzHkFW6G{o(;o9U z-KVSsuyz_w4fkt4`_Y#`pV%k<4}3#_Tp)q(TOVJj^QXP}IX(aBRUw0hC70V=ERkys z%=Kd8s4DjL6ucMILkp0LK`Ai#xe{4|sfRkc|NSSkN%c@}`SG~;m{umm>R#I# z4XhiR>L7_X{-Cz&9`u-U^$v0)_yiappCL==Ou1^}(W+eKmal8#vyTIFfVJFn{nP04 zDEwz|zpX^R09*kAWJw{{Vd}h{aiG;kY^Xor?LFVDYGWBzPyODZdpO=h2mXW ze-ZJU@?M6#5nK$6J*to;9IQSL^y@;;NgC_f9{iC!N}mF(Wo&trmg!-wcQ5gp^8X(4 zzriQK=skce;b8S|pttEJ$Sz*ISQ34qHT^fua7bKI<0h(&AgLJX$E&t$CM!5Y!)6AYTKn2gY8vBTHzwc)53NvHry8e@ZES zhg5dqX_KPRu3+Xo9|sR9a-^SS4P=ishtzrhZq@pF_Y-fNkHlW;L)t}<4vgL-kR=>c zFWI%&-)q*SzPerYR>7k>-7ARS=--TdHMkBK{kI`^UccT0*`)vO_Vw5L`u7vR(f=iK zs1X|gqdy0^Q~LdVkWIRGx2?P2yE@&Ah}Y;nANc}siLXn_X*=t8T9wmzxZx+ur<2{& zt!ES~(Ia7o{H*a$1>BFmzP(BM{)zkn_$WzVJNrvp>6@~;jKk!#(ilo()^F%oa9{a) z#{4^|=T1Xj0oDLx&qt9ZY`Z#j;U?F{U3h=ls9IFCpjHcX`@oXo6T zXy0eM_t^HMwmSh2Q9WfnPyBJ6Kb(u+RA1*KPXQ+ala8y9CDdJ`(@|WlukEE{-Ue?L zrz%{hz6#k@;eXi4m$&r0IbT8HW2Z4{iC=^?R#bP#XMU9B!7R5`lh`iB@<#+# z$Yhb(alFP%$Qlu|x)Vr$+1xR1GZt=nKfhKmTYEMh(A6fvyr zL4q<=9;=J<@NW`T{cYyx@a!NfP;h}6%?@o0A?q~!^b^17H$Q~@7SJ1ErhAna>x_ z{k9bbR;7EC*ITy=ztDO&5wGd5-;R6_cn}!9k048EufN_py-EG`a~F&5D{U(ZtTT0r zz38lZU;hE(FXSUhckXAbfd)qcqkjOhgrdtjmF^_vr3@Cn5brE8V4aR~>53NppH6o< z@g{gLdT&O)6Vw2s_da9^?Tyb`r@Q(1OdNB5!Es_~bdb+DS)a51 z8{`9{KY=WvwsYxju3TnPzu-2@U?%l+t-R< z`NCOZWi7F+X<8{U6nv%AyNGxTcrWSQjC?h?9vHpfMwZat{6y>Ywwj#CW^zKx`3<(! z6cDTp-8>hDR>4gniYWN`D(9Dm)U^%oqb}sXr_)vQG8lEhhd# zB(cL)$kpIxVD#UHETO&mk@oD+d~!t0@ThI&0qYW7)!15p1Mx5N^*jH^m=9zDqrV%n zgg3r@2FzHPBQm50j z#9`h-s<@@3!(VEBB?|GVK~uB;pP7E}yhj}!3KrOP?taYbcw-=pHz zsmeXmdfPrzI-W;*&Ryz#z4d;)qW2Bt_rbq`(fg(UcjKSpPJdjpwp45JW?|SQ@uc1) z(Oou4Y<53n9g5pW)i5d%N9f{*yq}urtDt^A2e|~40tu4emS4}9 z^orgk7tAhMze*qIHH-`2Ohsv`^$hSsy&r!qahdw;XUMOCeZZve&&U$?w-|S}(lc*k zNjZvgi@zft^$Y2qY<90xtZnDTdYRL3?1b``6KetuA)USgE7DZ2orpXSECNRV3SIiSdgQd^pOy3c@?;!Ekg*A^o z=rQ-zPmzBQ{sat9;o1W6*GDvuLQ0?EA+Fd~fpTDYT#PKCUmN+p zqHKNT$z^4$Hk8k)SjOR?f#>@gdy(g7?R?n{w#EIoZM_oiBS+S_8%6sRT(tPNTzypY zs6$U2Jzlv-ehd87*Dd9)*vm0JcC22ODhHq(^ssLYF$OitLADo`0?Wk zv?-lakWU2*fl243$P!vU2W?BwX(g*=kVn__Ti#K6zfzaQ(DcvrNmrvEe*v8flixFu7lJc^vBNUtgW18?6PRJVc-NZm8Q}?zV!;TwmnN0R zvZt5xOC`SARGq$E#Bb79hx`-pGhgSy(l>iitHizGC64&({P^RzKr!h%3VAdb3rzZ^ zAWP^dpG8lQxG9pjUE(_IDtDW*-X?W_@l#hu9_npxR(+aI-&W!`>8nA$4?N`SJXrcp znb#_PpPKYF`0+Oqmq{OQ2Tc0<$PDs9(kFU?^fk}CFWSmH;;Tv5>03ekCViJ9 zZvk6>7;!4@z)cVN#Ea*KL(!xlRh@sdf)FT|2#eICGZyZ!L=%# zwEG!4eKUyPq^|^d8Cc=#JXreX&6(UPeNX%8tMcQoB`%Y`pCSJaybetI5|M+a&(jm6 zuTl!=tFBi--w9biB7uFH>Y%V!2Zd#O0H$L)MKSLh;}t((8O%q{ibTS*LlJkjUpGZK zBS-u?aqn^%+Nt)_-YGHIr;DHe@H6(g9C-`a>T^DredaHk-^xC38vFS1*Athq&)<=q zXvD&cMU#DoAxl{8x6kJJN^(8z=`r@HvAdu)P_vB!AwN_+u#03nnCVdsi8^8s=&V#0J^5oV@d|f9o?#Ew8 zTqb?{koSXs0h7K@ktOWDTKE47uL$~qrvHPQq$Jkb;~$d~x36OaAZ-@A0vbqVo!@3H zV83db^auTrtJ66nHQ;du@+wdc43E2zB{Xc+`m3%CcuZeia_;)1-e0|a54}-3r5xxB zg{|(tlvTljR-9q)aE@j#yIUNu(p@6mdUpwhhoofUuO}2fHk27-_aKMB!tHH4JjWg> z)lhk!=C>dH3G_?<5YL5HA8-^f{I(%WXt-1Jdih5Izk!2SmY;v@8D(orrIGZ%c8;+JMSDlGqGxzchUIux)e*T_X-+INC)BSneFWugX8%avOYl~|gag{ij(&+z zk?194-4ZE%Q?bJ1w%glIIM1r+r^+p~kH(20A7rsz{&73AcUG1>ypvGdPupWF={4ip zn~`^d`+>2?hsYA*{{4HvzmFt;)|PHOdF5JfNKwlZxW^bXUE}`Rwa)K@Kdu5dHHJqk z744Fe74H&0Dh2k@jP5v6&xnPN4rO-1`v_}PdxXYBNO(F{q$;j{uh;!G!b7erFK7QOA7{S9(&P~K#!EC-y^>b z{tgTeE3SDowlNMB9x?;r74NI1c=u#DzRmraZB_Q+IFK}-g&vdhEK+m0O!QlWwEh{y zZ}M*;@=CB482!7DCG5UX+aY=WL&oApe-)>4O8a__y!7K4!Z!D9Wo^SfKyElUnri2A z*h7rImvqQd6g!u)j!2J0L+ty-oi@(taAT)frji!P=^v8wGp&o%pQYw5AFO%qherY) zVy91#4}dRxZqgpLH9xb`^QS4Z6-PtoXzLC9E=6rl>FEX=e*!(iDBoy5xGjBt{pgEHCn-z{R``|Cf#YNFbSFt!JRUPN{$8E2-`l%Sd z7z@3+rEZ8{4$zZ8kEHK4rjxn?G!|IDby&1*b6Pm5W8CY?3Y$Y3@w>AM73LcbRC$Z~&@z94&l?nus#ke6|ExwpB0aPgJfhZ6&iaxViM;e?mc zt~n0Qf_m7|Fn$9fL!3;ShzN(s^C}Y{rRoc%R!hQ*hWY76zbSuzK>h@L4h+BBvo*i! z2X*-?`iZ{!{FJ2O&`JyFd_JJC4>Cr#P12cs)an4OGi*(qJ6;l>TC ze4fWFLgsPtxP0Qo*zA@OanjN`2;BQ5EyVf;#C-|NZ!gx03%qvFyBrO<9%DI%8BY8TMhO~DgE+ewEj)R zZ}eY_d<(b(82t|+x2Jz)`81guZ{m<$Je(=aaXj?f=5EDv44&CzI9)hijB%#_JfhLp z+eo})h*<8AFOhR|B34ge^o~K6u)D?jXuq6H!&R#1#MSeLP8t52S6gkA;ylBvtr}cw zKQ_n?cU6lRDQ;vH$f8UY-{@v$&J-JP@N%VEXIH9Ko<)krXnSl$ui>==`62KfV0b-; z+#atb7gUz6H_Y7lT%2yDgRYr22D#AMjQ7S&=-}ckmJ!OppHGH7EXwiXtM~Osy9M<| zFXW@aNMQ7zgDhd|CHlTG&&k9t>sPKRUtJo^VN;d3@e^Qh66oTwc*wRM45xAA2EOz% zS(9M1@zMzm&BzxgsLJ82wlKz`45z59NEVNM-65Vjt7@#a&o1lsjsY`Y7pnPw{wdpBZ^U|N3m?4d6mxcvd4z zXt={KKeq<;@4&$`i%uzJF>2Et&3gXrdOiRD^ySA~geLAz-;K!mEipBO!%t%BceeYi z-3405xd(O7&?6KbK2=8^Uc@>U73RzXrJ~CC*FLq=mM|+19uJ7DIoI;X0l)Y;a3Phskgq5>~@b>DZudm zAF_n{9onw(TLSwU{&H{zM_a!i`p~u;?FHWJsov{}Nw4R4@*h;vNBYmD-X|w}ul%#L z-8W}iKO(7|!HNIOI5R&y2#q~y58#kuMtTu^5?&Zjgl@BAoLH0ki29L4f zBk+561YL}j4UzLRRYnxge}kNHv5TAw!wDxES{j=W!bNCrPP}9QBJ*y!^aa?;NZ);O zDo%1DGqM=#Iy3sr$epp&xzI_3@kVJpR8wLol`|2ZKa9-Ee8djD zBo)I%+=sfKJMKr0&587{I-#Te!iN0|XX^Y~)FUWwrN|e8%YezRTahKSRbQ~kK+2os zR<*t023ZU`&U-yZ9yV`t_v6?k)`w0g+Y70+qFD^a7?m6=cjra!Qjbi*EX|_|tDPU}%WKMeH{}M@ZFAp^ zS#`MJJQ`yk#af67F6G{dWaQfUIHJYLe0HSUHajQMZHb+m9qK-uDkOb?o9@PO5gp2m zIGi~J_t}iG@E~4iXZ5y^OId&y#@9K*%0fpTDYT#hVZPaEy$EWD)&jiRy&Z;GMLeg?mDcAb4E zmsH4nrsPO8+_zn2+XKk+by8o9h`}@x{psITyMMN=L?3kw$1G&p-CY&VbmB~OIIL;S zko=pbu5X&(t(&X)6r<1ZsYJdOR0G4O4p~Cob-LU&JQ|cg!{=DThf{Yya^7<62Iqa- zyJX7YyVdRv*04=VJC4Uo4A|9CsT?sCa=P{%mfN3arb86thHgjYr1Xs73@_59+we@u z#(Aoc%JwbJDdg`>&ArvIK=aP)Ezh;J9S0*X1ZM)n`%z>GyoTbE(|NDarCZWoo~PT_VMh-<79 z?Uc}coKBw+>&C~?AL2BUvkmz?l>>xBV>v%?9a!SzkD`>03#H7D<;SOtjf`6dmdqrv zoZ7){CNcG=en7Sb9i&=V{kT_f0A(05`v9ZWA!70Gl;W}gq zZLK$$QBtvNBPR>65;6JVcD?;y_f?tR?DHz6``hjhLss`bjQU10Nt4NP=3F{~UEIlP za0&x@MiApuGGo-$_*pzoh44Dx%Nb7}GVDzz7H0RA;y+vc$5xY>otX+2s*|KN>d>%Q zr(?g*Q|^n8k^cw20wx`)eRMj^yo9+*`!8!_hK(dAvlHWcN3HGdX`HT-PZif)jy|xg zd^O6}|4sd0to1D-zC0+1zIDhKfhu71U5PBAt@%claY_p?t)ilgr}ExKYNtB;Dz84+ zE=x$aM`a!9MSgFQak{U!o_LMk{mB0XUjU;w-nS#Yl2fhK9`98~8>BAU?!IPQ_tNCE z|3amQyE+T-73!T+b{j>Etf(*X(~ll=->*Wh0Ote4;{s#}+b-7kP4akR;NayeS2NAL zbak2M3MRX-ANzc6aVJ>?lbCRFGvyih60N6>coM`TcK$Q+f4~7?^o%-E>#6tqoz*u7 z_o>l??_%Z;OT`_~2_=;!V(SKb<6E}fU_U?&!DY}})DXA0`yFd^A9lpcngn_xc^UaM z!Hyc-CvucZ&kgnB)CspBj1PD@RZ`?>W{o zjtL0&=$fZ`bXmYH*2~S~!Jy3VrbNba+cDFS#%pE|xuFJAaW1!iX1jguq4M5pEY&;< z`UUmDIOJJi4lq2=L6#7|SKGN^XJGHLa&K)D1^EhC*>(2mn%h@Q8!*8)6e?fX&XIES zj^;?oB4*Cr?)FH}RORPt{k6nz`tdIy{{p-UjQ)QiOL(!3_HAj|hP9QG*IqD%@v_*c zyvkyn#Y*_!MJP|@)=+; zFg%_|mQe4nEBwNr7nA(*`W=%ig@(5Ts@{H0SBPWfanCL8cS9_|>O(n!NZiSWM?93B zL5^f|oGV)(Qr)i7^g3YMsKCwxkcWd&z@+auWC?BcU%8*AuPj}? zOcKYw&2ui3oA(0iW1GeJ)5HrV|5vn1>)Av+CO@qE#hGt&BsmkV@dGZn2;GB{~Wu2G0ruh!`+9uU;W=OJ$d7XxF*t;iDES|7Hu zvaCePX%$;vnO{1J`K4RjA91D(Q^GM-><*9)|43COovxxaT3*p=G`mx zj&(1y$7yT_%w*pf$8E8FDn$(ndCrjZCuw~{lleU4=7&Pg<=)`>zno01Hrc&BuA;xF zT=R_&3hLqR$VY+!!0{kOaI-CPi5YVDNT0{lj&(3(3`=-0v3y~s^8WB zO+D`Gt0F$rPVPXi1>XZk-y6sh-uK(d%M9maM>q~I?syNkCenfKX8&Ev zRiZ-MW#HhTTunk=0L}o0=W1jLMgF`)VtY{U4;(yyYLRp;l4f{lVQsek4+wUz( z+U@R-9c!G|7v%VcXKnZFRPPzi3|i6>+J_Oer>97v=e}OAdDWrUjQ{?K{15N}FuXoP zmeAJtFNxRspu0} zvx#_2dag#U2HSzrvjh3ydX8zPXLFLCqVu)g8i>c}`8VtfM=lM;|$B@@Gqu zo?2he4B|0*PDd^V%Yf0d0{P(SIj&iHu1eAq->B15OFTx;^T>O_%fRTVM?Sb7YUHGH zur*0fxvwX0SfFPRase0(jGi&b2iG&UnVxHs^wj%$s))y==iA7)fxCdwa}V;t^^7QJ zrf6HBs9=+}+kQVDxqm)FP8rTRBw+N68lm-=bA<~1{;S-lW^Y8J-OHQ&yr-vk`DKbs zg5K?J>hViQ{nS>UhSW=r`-I~}@`iDed#~I`-VU1=^JZJ}o9%Y$|D0HllpN+apS07u zbMn-z>>T=>ciK)49nU*$_C$y5_iTL)C@LOk4%ZAWuSFrDl2N(Ts<;9 z63?K&I5IPmmBAM4L8|*-S*_v!yvQp2X+N|lD(~lSS{N1ir5bj3Sltxv^@55#ug0pJ zv}07x6Dsn!8nz{@E)VyrRguTkv8;_87tYzOBHvNNz6`0qhI)NlMQ&7M`#=e51A29T z-;EzTDLg6asoQQ(f7U*J`S2g4^mryE=Lae3x6z#C>OPh8tR4C_dr9rk&0-G+q~x&R zDJL9yC`1&Yt3%nnLPv7KWp++lXurxC6&mS(?;ShmZ+3`R{crNG&)7LXwB=QWUQ#(P zdauD>cQAodR*PbFcd{`<4LvSyp(%JgZ=v)|WRj&^HWuESLz4zA4BZ z>62$o?d$B}_X+B8aPm%?LH<^n-16~F$-U3E z76Ngb5u~-u9Z48FUrgpwqpT_!Go0_0zq`kAf$F(f>5Egtq#fE%i5Tty$ZY@ZZ_i8Gtig zyi)-fpI2+W*61MJy^#ll;lSt}g)E`%a@Ar7OS250*QERz+gbwX{rZKB`09QARm5+~ z_07mN-~nLtKZ4x8esASu`&##?mTIl)8+E!55Uk?hU@){lshZI>$z=43G_s-dtn}E!ROe?Qd^GYi{v)o@38hEL*qOc`2ZP^|obe zd-Y8^y~V_9^j?m<6>I}W?+wTjT9&UC=`Al~H~$6RddF!Tf~j})Pn;7)^XV49>`~Es z`Wt<{`-s=*{V(#DKphw84IxYDFuiSRo#1I*WVwq(tMPzUv|XpShSyQ?jJ$z0z}BqAWG-M;#*tp;5>M65I=zKs0=;J;F9qiUqxU>y2?t59F3;Y^sE$+I= zye7TBLH;v%8yLOsB1`Bnz0I}e7N1Uv#TVyh_ij=QtkK37XZ0;Qy#-?fy)%&KfO){^ zU5G59Q|X=D{;eCoRqLxEK9kO;k)H=I0i$m(vV?a1QUv#{r>$@{XUVveB1z@x7#U|) z`TFAH0)0b}M}lL4(Ki-ZLg&)Q!us};=*460(COStye6IZAnyi`1EcqQ$Pzk{pR%0a z(>ji)xdn41J6RPb;O3d4SjS8})xKWq_&{%WO8-dYx5we6% zq|?)OkZgsx*1MN@jo!DB-vb{4qxV0^5;~PmHpr3C+@f#WUe2->Le@ig_SL8G@x0#G zTR1V$y9l`yoCl2Fwa5}WkzQYG@n+eOUTu3>`;juOJurG-N0!j3^s=$-U^j5BuXkW!ptlhDBv1s5-ucK9I+0$jH5ad%cJV?l zm;XQk1LX2THJUSH$>i!9o!%PaHR=5!@(bXn!07!svV?=AH+Z0aunfLO>&=@S=pBJP z9!v&C?=)ly9j3RL){Z+=b-vze;x*}g3i*fNIbig@fGnY<-;kvK@|k1LmPWtL&a1cw z+U#z$__a=8HeE+Xe1-SwbVsKI`UfK)4MqS7@;t8Hen$IR&p_iD7QYf|d_9}|IAy$h zHS!K{7cl93)c?C#hheV1|FKry$4dQ`Tlc#^wyoc~MOV7VU*&eW(#^TbO_Q0Ii~O3S z_&%M^1AhFXKVvFwAUFaT{r!+VzU%dKj28Ow7m0&hy)tBk6sdw~Ox{1}78|#%93w8y zNd_7V*ZF!^5U+XO^DX3SLA9?-?AyNIR?)|f#TI^Bujjd>%gg!c-O}9*??;Zyu>1S( zx=EyjqWg8a8_{LvSDX{r3kx!UNq2W-3GMqq6&}X_>d6dD9(2#O9%P+gcOJX>{#UaD z|EqPr-W9}a^j?a5CAb}X#GPv zUpB$hq~m7f-QaOx((wwig!cW8Hcy9k#o4>j`Ih?7u^XMYZ0|DXL$c{XmrWU)SyeYe z9mU$5N!~0wW1vvf^DZh2JeIjzv>VYR*P)*Nf=4vpfhPv*6lNix35tQ?`y*rtX8m|; z|DnzKCixF#ec%?oBJhW-2o$>i2;m83F^k}O@Psx)fr_pZgvdxU7i_g$_lh4p2BHgsF&@N2*H~9)>)yE$d=LGk*3yiPO#G^W$@fkWD zQoi~j4+o=wN$0Wt-%WjJuFcDHD?g#T+!lU9t9^at#FxNsqVG!NJHb7^4$)bAK-a&` z<8Sg4S{J>0&T~<_F8WGe?~?x<&VV0rzh7bfEjp6L3Q86%up-NI7uuoo&`PzTqaU}% zR)_R^pRM?1$yf64!#30XZT#-G)nkYD+X?5N;wlyApI+*t_z9MiSHiezkYk8s*_taq zQU8b~!PrY**ly_3!@sE8G9OcMMV3 zi-nVY6)R7@y(Q-$m#9(}G{J-Kc*i#(OYATQa*7R->x9qp|F7wPBwzU(`P$ZhuyQIX zU8LRnaU++j(1WBrenbl^jKZUt9$D1CtM7xnlY)NGSmZ)*0x8DT5mP+n*QHo$WMc3fYJM7WC`u|JKNPN^Og@XY1w?EYWJ=ukYOgs&klxpq9 zW3#o}$yf340B4}Iq9fEve(%h(68p6scA#$s`lMcX9{K-(njP?&k1U~Jx2_+GzT2#x z@c6I}tu-ZCyh-@-;?z#pGy+n#XS}$JD4BNFB-cpPrF9+-@o~6E9XFr#J1*k*t{tMN8dM_v~oT zP*10)iiNq^A9tQR$DO0H-Rwv< zixQ!`MBU52Qr!=#`cU&Mf`?hpSBAU|+z1TMhmj?;TsN4^b8X3*(q-P^6V1r|$0OH6 z$n{Bj5r((A*55pa^Ms}9>-LQFb@nW=mDgzctST@Gv~{<{*Qkf#Ep;S;B!9 z`}UK0;-?V@!wc4zoa?O}_N`dQ;vsMOP%l|NwA-yxR$WRTmYa>UkBaqTR}q%G(stKr zyVZQ8`Bb6L^i#i!{5bfY&!L0;DY<-`V%WCzek|noRm3xo# zm19@&#M8U{+4e5C=*vRy%_Q&jBmL29`g_mo%lrDGzjvJXz5nQs?$lquL0`U?9N$Lo zd%eHHuDjh=vs8q;Fv5oUwy&>ooSyfEPn7jjyj+~&W{ruBkI_NQXQ=~gqA!SCJnN#! z#gp7Z-r*M`t;%*MIo;U8I{julvdx}#t-Ma+b&Eag3VEHBK4xIys($+4kB>~8H6b!_ z50#6Lb3kh3 zu8hdt86odAtrK!+UZiN&oJi56(3mb`#xCN_053_=JT}s$gwyjQiCMiPiAk|I=1HeZ ziCYebv*(YFbf0xZr28a0@|X0;+vy?wnj6WQ)g_WeT&cI((pO%J@4cz4#k+)+(sNmv z_mUk>*hkv=DVM13_9d(;&X}b}bh$(oW=&P|b1qTmcjX&-b`SeSJNFX4t%|#sdTTYzZgd-?-sLfUIoEshs_k7K!Qrl1eP{GZ=@IGGO(l9ndd{MtaCnN#4=0es)Z%bKpOm5TA)&r` zePTT`dSnfar{sqw$u+aLEys~B91$5ghP{ZRBBK*_H?^QosOxQZwtTM;F(V_7*VCQb z>`eJ+MxRhTBa4sXr$=h-ek&$SP^;M$lVAZ$dT5(HfSj3t>&zSM?mtwyQ`LV|Y?Zwt zbhi4!R-5hcyS6*iUSNMdq?L7?aNWf?}C2#qMZywRnXgWi@Kb+#deq!&;l8WT}r&;gC zM{*Aj#U0Bi`EkqKFNq^Pfoz0;f-SSnhf;mpn zOkA}@@dt2{%6m%1o}|+q9vym@>5^*uAr?kC_7SyCK_ufLCr=z8?Q)hN?Q#~}>Wo(u zyI6FBJ29-{lT=~oq{u08hhtyaE}uCl&sFz2q01eI1-z#cOXh^g=!q1hNzTyks?q#w zC_MRBikO`H9Qo#H8D~Tva#WAVyK3S)idVk)KRY%FN48m^^nvmZ(KtH{QdPz@9ryE2 zWZ^`qtDK?TcF}{0_R9%PiW8x&9&n-$I-z@HBvCY!ssry6>?H}=y+pF7dawDDV+&&o zWZbkebd@cPQlh#4w$(@W`EI(?_ca@CQO)fo=5Xd@WcA4Jb(ftV>Xq@d9evFX^?Jlk zANrLYdC#8s4|#>h%zQ7JKGDo4ZBBe+#|V$}dfuEA)y*oBHamJY3)(W$^D?4bmvEh( zJ^wp) z3|sP^v8rdv&{rz*xtjQyyz<}O3!hY;-T8*L`_aBJG2Z>oB3AkJBwi;}?VQEXGBrOf zqZ=Ev(sto?s%w<$;yZR$s7ppxdY4D-$DPQX&cr+9m6$(MaY|;)v))c86j}m}F(GnO z3Sx+cCpQwCNU7$lDMKR};b^yLZYVV=zcVx3^hk!ABj1&V%0Rj}6I88I4?AutEyX%q ze@zefPkkUfcP7=D>N{zLx?H7PVXNukVrDO$?vZus%<%m1Ry%#2DhXffqz$pB+80NP zGj37TY3HdQh}Vo$davUjW_G6#Jz|GvI^y2MnRVnkRT?htM`Ul?s!aXHR%eC!9xdN2 z9(KKbv_y?q@KdD*jE#@UKW?2`6Mn!R{cWWt%h?|lsw6Z^v88gO>N|CvS`?mXU#t?D zGotHMdCD9$#D3oEIyR2g^<=^6!G7vF$jiYhVCu;qBTGp5SJ~)4QK_i%PmL##(uufq@v^Bj2^!|uggt&IotEpzY{rcM%AM!IYpt560jSicKO~k znHQX-dDg+hjF;a-{sepu49_o-CA1u;C-WRQxb-lx*{UwHlfNY`iqF) z=--HZA-L4nDdU-TpCcVa>ku>!v5a>Zo>Tbx_9p532XZ6$7?||_7x@s1-}3$ zeZNAM(9v_j5yzfQ{^3_2YS~5dDDdf4j{*y)>U8Cu6Qt{C;=|xaT{Va`uesKpD8a-ApaP=0F1tU$P(uJ{`$>%YUeV|v|-7x zrDbb|uU@%?cO!?(%eiI47EhI(HH)V_tWWDY*&7&4Q#!i1iejB_C437_xCA6&XI>DpKP}zmY@NjL9TSU`C z$5)6P#YS^4;$ol2nBri(unc(>C>SD{c{K9vAm*GHVJ1JO`*{AWF}@0TUejz(U-k*sXY9{ z{Y45fk9UWQYevf|oUZey2z_QAXAANTU^_5;?njnT*5)X<}8fj8Jgdir2)S(`+A``4 zkPi&MsmKyec)_>d6Z+bzeD>|P6o&);PWsv8^W)0P=NiX)v)>3YU|uXo=QHl`*oB0v z{b)A1K8gNos0aCelArJTOY(Y_@*E|=t9q8Ua}7LAIrtrN19%6RbbNv=;p>!xH5^64 z9BykXU(>(cf{-{#^D8V3_+5a!1zZgbzuS<%A%2T1O1x8Vi<%YI``hOzdTV{2`{7~Q zjo!=I=K+QT!*epSgz?`x{QHUdw$ingi&t_A7q|XN6p4jiiTH_az0rTTl!$07BzL_^ zCHH4?Q%#nUq8F-8*7mH1hsp1sBmWls5g4BTK$dV=^`~EMHBZkQgqP>dD$xV|+pk2? z8=tLtjyX55=XuB*z=go@+=eV+-`B8brEY?9y;}a*IZ}z@s$%z1UM1?8l2%AesVh*= z*=C*3Zy)+iyBJ-;UJsB948H-$5)Qdtl=^eo%H_)!x7k2e4{xV|EIdWqtsK3E*FDI) zK`k)6>W~kc*UGiaN;kDltp3<`h z6vD-ooc7LoVBuNhl|#Hx+&Tg%cvjNkTv&qy`Z^er=-xcsN`MwkRLGTDL zc6|z2LQ6jfoobK#p8w+Iv`0LC)}zx&Uf1yqYtLBh8TK4Co#43+^7NGZysT9LuTjY3 zz(inp%|QOzyv%Z#BEzY^6{mWiPc{0+piuJl1>{%2YrydN5LrUeL%NdHru=nZ!yXSX2pE22 zktG~fedzORvqt=KVuuw^e4ggF75%2&+k^ZQuooD9`;a9ZRzJt*=QYgP&ASgfCbiqe z@$}XB{06QK#tmm7uK;U+;dceHgu@y)`25-(H#{-P%j1s54K=d$hENX=V@Fknze|t> z49~vE5)P~W_Ib)2S?i9&HH973+XV|WzjE}Oa`*`H=B`FWsqjG2kb6PGt$LWMxxJbDq~e{vIE3r!=pH=zM23YZ)VW zsw+HQ^IZfVlke9c-wbXChVLWDU&Eej%IKQ4ZOl*SwQEci*8BVppx@j#!z%Ib044y# zZ#J@o!@O_G%huyetm1;UJLA7t*zS!}bcVLy4)mMx>MO{91aAVvuMt_oVf7~}N}Ko@ zpM=fFSo;=r*r^c3XKJ2>8-jAV9{Eym1u#5sLzZxu z+z*cgJmmiAbv}I`Fbo);Q;;Pb)_9?!)aR)W?QNpkG*-CkERSjjV}+Wtv^}fgVanxC zkY5460fy(>$Px~-T%Ny?vq#%5l=q+2ZlOe9;%v>YU}I1&mmseJ6~OS@f-K=M%cbVW zfksU>Z0hLlKD(nbS?}|!N58pmoK5WQ0olOt>yP{m@JlL>O$7ILM6l`{ZNGB#8-Dj8 ze-}In48NCwiP5d+i?;4P5XB} z@@?R5VEEM{OE}DakG@aV<1k(KadXS3G)*`1eE#0WN41=8EM&5Ia?>(%D^a3(S{DU& zJO;TCoB#~Z`N$Fu%Z}^Kg7~&;oYxn(Z^#;-Uk&;T&@c7&Z;{^ye+P!&SI80yeE;c( zG|v<8^J|WvOZqymBx%%sy8FR@ftj{5hwg+qNmE%Gd&GUv^|S1 z4)Xm<yc1c%VdZ-g&$i|;ZeP`I zwp&G|+K&6tZ|vCXGWtJY7%==MB7YP7+U}D-)h@#ZpWjyW8-C9s{~Wvm48J##C4Aj{ zZhP+Hm3H&Ee7UyYz^b60T#S4kSPKllOOYiURy`^CyJW-4)to}#c1^i?b$c~sqt9C2dhv z@_@U^>$??Sq3v1)uLQiLK6)DYdGJ$Uc)yM;;jrr?W7p(9Wm9eRtmfQ7zr5b(IdF5( zFDgb}1PbE44lA;bHnkUm}ODz}F`*JhPD{ z7(dG9+L?KR(u#`3zK`eZqC)TS!kO0gHB>(O@xrv=@q*Rh^C?E3xvy_Tz7yO744)^F zC2aNm`X97eD5(~p?e&@C%wmnR?T_ZUK~JfCD1SB zZxHfmFcuhovyml45A`|Hn$k5(%VqtXeiB?!COwL`Y$mn6C&3gso-nBK`mvEb3+}F_ z(v_%MrFrc@uNfyigZw;r2^e0lB1A0UV3g>>8A3GaQA)Lt*QG8Pdh%Cx=qp(nw6DPO&=;dv(*1PqT6 z$P&JR`l~IL*+pjM=I=3{NsN5cm!-{Jw`Qp;P55iNTE4wfwtn z*{Q+jVO<;8X*%+3a4Il7PDhq7(NzMssQJ$*G+NiK#Y01@+Zh|q4F!R_}fwoAJGtQwzZ;)cL(Q;}zZQ-I;Q z2w6g>>{hmHiC>+!xb>6- z3!otAh!*+$3abNttB@Z$P&JR_O2b4L0S5!MOhNP@k*Va<-(2k!gD9`gWwThcs_+Jp;Pu+zj9gW5?nvD z(X$JB?wiZosMf7=pO5wJz;3gV=YvJS@F_-?@D13l1Gd>k;+u4%TF=i>qronv%a ztM_^Cf`_r&uaWnGH-O>!F0zD9*^PC;99Uk7gN!z7t~=YXSiuIJe+4%MJT@X<3N{17 z;~HcMi@t$=ds{5C3rBf-b55}y#8QLBQp19~lJSMlb00j6z0`K*KtMV$JadsHbk1HC zrOTMsURkob?V--otqs=T^C(7->9_AfehfSb438foOIYFW&-oht2G$m}!7{sip4V+( zYt><}S-RVsuR*_-lPW zJJ4tH?;Yg#K_f7H4j@bT2I~C|*amID>lm+D8?aH^t?-tB=St*qPzemrOOYjX%5EFV zm$9K_{>t*Ui`jc^SghFRu@^n2|CM=b#OemR1H+>)vV?D-f7&L?pcnQrmP#H;dupwE zpJzEdOup_!eh@qY49};KC3MPOO9NjUQ&*HOUDal7wq;#g^?$)8oqyJjz;3gV=YvJS z@F_-?@S|_w{%oIZcJYbcJj4>~`gQqgqTHlYbgfq7^V|gwW4G6kUk7gj!*f5fgihH_ zTJR3<&AVIM>;k|3zb$AlFF>vWTY%xQ4Ozko{{FtNQJ=NLGP`K1*H)fm?ZQ^$#8wl7 z7NFSYxep%3Ua7b9ECh4|hGzm{o2Pfc?gc{R#v7B`(zYoOefHzgftqf(5|vU5qTD)An27)opXl zO4v4U)!(!-pH=1a*@eCY`ow+*kiP=XodKUzWC`EEcu7{zw9hu^=DvaXl7~#5{sy1# zBKVl{cLnk_;Cf)}w*y&1r|h@Bl5=k+mzS@;py{q{J}!U1mEj66()rkc9>ZhMUGzo3 zXkd7ZN0#sn^w-*98T8mb#b7OaY}G!`t?)2BA4Pr&>;Z=73&;{WZ!bnrrA!>Q7-?Qr z(Y!Ti^z}#Y4%&f}kmrJh!00~*Swdrrb6O8$oaxyqnO)F!R#&uaJBu&Y`M3-H#y+ni z{~o*!48Ol2OX!q+=9zUQ3s-u}RGU2%s%c>%FIub4=TWdTxDPiVUks{%;jtB2!Z&aq zw!tzOCq06tym8VvJqMk*MBAwz{l-q8BLAOos|om}B1`C$oygqzCFdq*RWPi4rn#A_ zeEmhlpCEpzr?w;C0d@jopNEhod;|7r%`T{$Uc@}j>ZS&tUnBaBeY)Snc`u+pF#Lui zOX!q+OeKCIc47&`X{;@6R+N6*+(r^_;iWpCHlZiMd$Cg;^3T98f#LBQvV?EIPHnRc ziqe}cijt?d#^;&1H+X(M19=`;1Psp=$P%jj=X;%ae$8{x#Y@-lkg;qj*3v!XVNEd*{BAolbmcjQ{LBZ)_e=@51#ifN8Sv+1q|OukR@#K{RzDIw(`?!5^xwjf$ zd?Qsfe248!jF^PPWpQGWJ4g*sFWBw?))-87dy$|a;X$d{?B0mW)%MiNKRM5Z?7C17@AVq>TqxCg)_p8&{nQ?* zx`c_2k1-A&gq@VkXuL;SJQ7MtNr}dKWW`hQ-jwaikAKQJ@ApBW|@N9OPlkN1BwYtZWrDN1I zSr>A(=2;65GoRFe{BQ6nFgyo6qSj}f7*H6+qd4WabI=qdiU@4t2hU* zbDs)Zt4HGIs=w;t4sd7oisY|XbHfANJhyu+Hzgw$Nq54Ls0y+EAT0;Cc}M5>lWnpS zUHO+0xRCt296EoRI*BvorsntsuWp-8*H(C&`HLrze*k_AOuAk~mT+;W=M|@VPELl+ z4xC#QPG#!w1@|0ls6TEz${pe8XsyI`e)-=O@R)#n0+;~|k2%PP#ba*C#Vt9 zeBt)%kCr^9mTg!o>qD~(h7Fh7ZKkyYD*c7Z;HKk3tp=Y@75c{bd>%%A66^tn&u@_> z%=gzH?Dgm2+UMgvK4-Ov_)ecHCB4r63l7Ostry)Zl(oe!bj3GzSG-A%31@JCLP{!! zBc$a^RW)1nU_VK9rL4SQdwdM z_N{ZjERn#9ngEAk@eI19~pZR=&bFs)xo zZw|*v;U_z#$%YH?rb*LPvt9ElMz7&@HS$eh2Qc=lMLu+1vMwTt*GoRHzuQ)$&nu%f zudTwX`ex1R0D8@RkoYe502l!buW85<%za?iSGJ$8EHFMn)+?D}SG+~e@f*5W4E7pM zweTpB5gQslT6K+Nha>6PQq0ET+;zHF-pX&$ysFV_>WMwbFM^)~!|N?%35QZo2(3ZG zru!9t(H7|okK<&+7u~d!@Q?fKE?4SE-b~LTEnTz6T)`->P{Hd@QI(7a*?z z6~OR%2w6h?J-S@wJ=dA??{@Kt_elv>S4z$_i~$Ls#(tLu#7tzZu9dWz6toseciv7 zy}w`zFzGoTSwhWyIvwSHf2#fb_v#(JSgmOhR_{8Fhj~ufb?P2{d76u)=Qh{6J2c!& zkBp%Ds1(w(oaFTIlaozy0LclZg-DJ+iaOD~*xhO4qIsg18VKI0)3X=8rvLN_a_Zxh zZ(!0>fb50sIz7vtI)wabT87lSMtxxKRCbLT;=L}|sZ--vFH36jA~}+pk{})7o?V)l zAFFP+)oeAy+XPT^m*!msFT;Bm@-M)v!0?Vfp?R;U)qGF*S!Z}BEf4Bj6S~pa8M13a zL%i3;-s>vw^_-n_TwZjyhpqdgBf|rRMg~dYVwe$q!*n zvV?lSJ~n=Y+b?I+lbrk{`t*)kKXu1j$L8Zs9|v=mm9O%oskQFW`WyWCMZbEI{tw6l zMt=dag#G?Gef<>pmo-(# zo(I+*cwpTtCnVNV>%};(W}@n9r*NJN1dmk-b+%U*i=Oy>npfhfpnOh2J_jrXhF2A` zgvQ%-xs3b!YueAhQ%X0&OYB!`uk(iUFVK83!e8&b9xqMoUiT{3+6Tu}bwRj0=eDIp zrP5=37`obyB&38L=PpsXPT%l_&K5g7v}t2a;sMQjAG}OEVt{61qa z&x{sxoTDZ6WB)qV9}ap~darTe`I;7L`;xxAII`zII)4*(7P^Ea*TVK6(V+H#Vi=DmT~MU)5(g}zD4qE0gniHP(FSP z`Ags%K=Dl2>hiqDt&i^Oq3h#e+#^v#pOJNQ_G8fTE24#Kmx?^z+q8@jUoR#bK5E*A z!seNeJ143*jWA>gJt+Csf{*Ionjqf;JOC)ZyC75OaOdyc&*O_qCety0#bwUbl{B57 z<(y8}@EC_ZsUHvohQO}$ig;efU9h8Ip7rZqu?VyJQfF3Q8lBbCFoVvY$EMwdSpLX?HUAGn|y~mCxtQdfK>?>l5 zw$03u7uw=3PsOO&)d>ZNooacg@38c6Ttd zf-gnB_v54W5|N)!>C3QOn>X>TdQ9p&@|#$DHWl&=U=Bcm+RuaU#XEF;o9-NDHw$No z#cs#j$+R|s$1w@G)zCC>flzWdF;&NZUc48$!qITvp*?SL^B-}m{BMW+f56`XrSC5w zQ#g|Rm&}UGq$Q6Tk7{Q=g&g`V?sNtej}ee5T;-1YTf05)7^e+Ng@6K9 zgIa1#>OX%A`9xY&= zUIVNH6u%20Q|S5m?-VRydsb(9HHK%sSzb1t+un~+IpzD_NS%Z8W4X3@l*eOJLCs| zM*+p}S;!QQPH%BEJ8ABdLu#(+*OHgr8tdN%LLLr`1{AN!kSQEV|EBV@QwP_E4(=`I zKCP}hxUFvaM|>(Dw?lpzXaf|Vk04Wc_;T5gTzpw~{fSflqcu9M_8O`I!<-thA4k*c zc_x;c1&mX;N+m~@{ZqtPx%!FmiOZ|vcQIabA+G=$0L7~bGKJ7hl27Zc-SIkT+XZgn ze1Op*Ecx`9je}U;5WnZJ>tWcHZlwj#8I(Ep1+*)io8iRhAZ!qB)1Ba&7qqHvQjhK6 z69FG8Z=vTctq|x3D85r6QwX^{yXSj|?GG4_zbMD!`Oc_(HjT>P5`W>^$3#8b${^E7 zp(u(cpW+%vhGLL*W{f=ewERZ$Zw9{_yeIzeK>m)n|31clC}aw6{Z8un$!_gBG_G)u zqa43x0#PVS(IxNMqxT&J^a zwOiC7E$*^av0R&NaCvM&Jj#ytHstq!c0lp?2V@FI(mu!W=+s2-Miag95Oa`rmrvyj zF}*BNvk;z=K5sEb%m(5h`PU8}5%8e)Bl(Y()*C1W6wfh`DSX#szlOtXV@j)S zqE00V$VSJqht?Oi>B_IcHY2>mhugA={hyhHMB0v}cHpM(4=@CKmx?t@IB z=l-gTyV^#SR#Oj+CINJN%pUPH(_RD7-mU{iLCgW;XHuuNe~|ntcE;>Tiy*HD&IS~} z+aObDckK=hw|Ce7b-ir|t?&ihX?aVWr?njweUEsXYwh6K7u|FK-Z1%aU7CarB~2vZ z>O?D;s$2M)He8HA0hx&LVX-nuw7wwucYvSLZ|@gz-a9Y`Q2ggWrf`+(&(`YNg%90s z9cKFsmOom!v;2|eJS|%M*dxA&nOMhi0hCQHJ?}Gk@z4$7U_MEF!uU9hKB{&~zRlpH z<~6TD{uuZhp!n)9Nxlv4I!#-*=Q4M>eFe7cc4^B_x`Qm*78$hnh}*c-d90>3fKlH-rCEOxAurEA2r>s8y{w~OIkZ? z_>dt5DbDkH?!27nJRfAvi}j(Cpcf2n3lc=C58&EXA5X=?Ssyc#hmt+q5*A$E28EIa z`34V8D1hN5z*GBJSl%$ax!FcmAlsW|S*ZnX89N=T3rVYKbZfM5YV<>BC*7a!Lc9*C9N{nX}=R|a< zSQX>j^s3bBR`7{{5b5erUXYz|n_IrR9fu!&+XIHTJLK>-$r*T9H1OCX zHel}TvPOBb&w`fSsxcHT5GsaRm}q)U@@@bx)&AT9`A*PtdU{2Ms3n zh&pYj)p;;MKfFuw_!{vj`%&R*I0q4^1Qd@IkSQqpQIFRDV~(7$0p{1#Bi_%@9qtvs z)3s@N82_eYt)2c$!p-9}EIP!_CTY67ytx^E}1yiVEs91L$}|@;?*&)OhYb$d3Sz1B(A|AyYWA z@tiu=I_m8pjmmp5pu3{$Id|=wl8@aM>(@s?o(0SU6rXb-Q)qSd*b_T_Oq<1J@@@y$ zqK7%|vz(^4$I>H6k0F@o?iHWt+G{vtR8FS`I;uUC2Oce&bm4(l^R`US9`IG=!}mIT z-hgaCrKbckg{mI=Q+BpTOFw00r)rpwLQ>%rkVl#J1;(Zoj-6@%^^2p$sj>D;+wJB* z;#d40h5QWg9H98U0{MUE7qbU-W_U5iP+c=@arvdc5o=$Mg?tjQ2vGbkfJ`BDl;y$Q zE0I?Fz`<^qd&Qr0?PDzkJNKJcs771^%JRY!j=Hc z22?tpflT2&*RSF#_w~@@z0T#pJcwMG~Xauf3>2KuJ;RHMepqd=V|_;YH4r@2iqE$ZzR_X};e8NaAE&>RSN-M$Pq3(pWkIqY^` z+AHHfBhP=4&pJEoM%rb%?6+g>UlruJz{!A0*CmiCw7BVN?{>V}xtz>&kH|j(=T)zC z9FRA#Zx3n%C!C+4y(hK`?G`4x7+C{~yQ~3@If*(NT;tupb1kq#!DznKek9YkAN(u9 zpXx!*Zp?Xr34lspBV-D%JSFpO?$h$Mr}?JRH&LDp-@>jFkC9WyT<3YL^OT!6CXj>2 zd*T68dzMXedeS_%!5_qJ+i#z5%(EuZ4vv`HwZ}K^gluyBnH z{%2{&V3R7=Rq(STL?yjAq2d$Cr(#d6{x5)hF>pDc_-unrq0}u$gS%a4i@SZjxNO}T z*JXK=*iI(c0nSsJVB?>skRA2|@h?NG9>W8+tSG%PD#Kn2aWX1Qr8&?aGVmV@BpE>% z{*rKPxu=Xe;<;q{o6L{HKC^MCIDPmz3F&NLK<)*q_*AAd{hio2y&CdKz#>4U^8&~e zeC|G&dp31fUkXG1^8gw}i7lTmahhYoMB;JqKLb0$Sd2a--2;Nfr^d#gR zz>9$5{TIj-np}HQ=$GB;yNm6!n8ZCRCvlB5efvnX;o>Q1xLITL8UV%jY{(RjWF8k~e9%B2sFU&iVJX216=i(YKcyZwfR}3Dwm{wr{1#BWcSEMo z;rd;Ly7jw4J57U#iF6D<4I!G@_tLU8m~2}6#G723k_T6xLf8)LF|hLB?sr^u$TMlG zUV>pU{ozU`GMNvbG=C|17QG+yZw23p)c>ed|7@xLdtt#vmCHBdsvNaoC8CVW z%H}wcg}#F^c;``>uDy$9c>Msi(Qco3O4klxo*(ne%f$?4h*?Tz6ld7idGIc0 zd7b?7s=kxyXa!GYPumaqOW+$orNjGYw|uzv{O5o{0eEs z_mbCK#H-5f#gMNAt^pLU&5$V^Nx8)so0t`s%~bdDM0&&jeZLr^Rp*euAdS|FcfyUAt8K43*0~w_H-$><1&|ez8-B9~Uu?U|)G&j6Dq{sdBmeBk=U1G|Z3p7KD9F zJHg>M_b)NMUj+GjU^Af7@g!sl?LEGaB2Mqq)O~OtlHU6Rw55N)*vqviQLP-M3t@+h zY?CX?B+>p2sXfB8SO$7LIiiVh$=Cik#&;;>X}}49;(H}z3K7@8wR?MT9N)>NppJj+owFlQjz6H1)P<$SQOyQ{7gHEgW`_YHp zpy#07M~h(LS37wSH@JMhMtsU1&}W~e4FN^~iqCk+6jr+Pn}=OL{X^HYxbrj0mabpD z*xe#?C%=Oh6w|5q-zMJW*x>m+!?9cWnl=O8?Y;SIhFKd^TVmP_sjtn5U*+FRkY5Mh z1{A+{AX7M!{Of!!MwDc@cHtr$$4Q(8Co7B?r()GFdaS!vV@f_n{};=@C6HGDYXHS( zEo2HumVYsOef+r>am?m8%ud%{;HOJw$`!oL<<*LKReSjzWbb}U3j&H)GGq$>aQ!g4 zKcA(u-ReiY2Fh{jRn9my9rM*^#S2_(<9KKTke&0`A`yw2F|>&7mVfY2`MDYL9l+gy z;&~rr3O&zHY1>xk8^r0X7CL)goTHVUBUR=c_Sx+6=s-M*N5S7Ltpq3o6psOrkBUd^ ze1k5i42`Ga{C>nE^|Ar+sqxDrkbeWT0*cQL$P_AjoPVxfoasfh9>Un@I2BTcJujX_ z-we3m#>-R04YcvOD90r?%^ zeL(SOhkR5#q?*t%bwOoaCo0bG*Ct54RQx@bUrQjb02%6l1RAT2C#4%b1 z-{Y_D^KZyM0Q?^@J|<)eJZJQ2i0MdC>|}4DfIjtj_CfOxP4G@gs|kEfL%K;GMMJ@0HYJpt$~pY zwE@XXI}ppSa>zr05rE<~4l;!!$uD;w5sgZsgu=CyVXq*=o;SM6uy&VE6XH|l`Hzra z1Kt1>pWTot97%cZVqa4nFDlQkpgcco#&`a;L8+g}XR&e8Nsvzi)&PpnI>;1u_PBlS z+`q>5HAN}GWb$7bZ#RfNs>nm;!!*{K)wvP5>Wcu1o>!rID4j4mnKJTZOFKl z@%h&5^4NoTRKKc!j&E;M!o7U*de-AtvxLD(|~wY z``8Tme&8WM@%j~H3P)1kR6cc4;o4B)c6Zf6)+S3n+843*aVX@`z&JqhnFN_a&)dhY z_6NjN<}{RVQA7C!>(o%DNIp%7Pw8hD#c$Nv6NVzPbO4RtN- zG}7MS@+$ggjMu4&4Pu(zEgZA@@f(`Wi%2fM#}I+{|vbXy@9wfZIm>Of^xpX_DtM@KE{M4EcWGAwcnb z3^IkI%GbF40$pV25Ak!Sc9+lBh)<0RD*lD@{(Jub!rS=ksw#Qfic=Le>budX?*W_% zaP)$N7MD-aSF!w?5BU^eDWLeQhD_lo^RJ7hi|XPPKN>4kWJ>*PMSQ9}9f15V;2S{k z`5y9-@ri0DZvR1?ifH&klzuQf)x#E-PxZfJ<>^Ammjjys#pim+6nfr{9?IW2%1I77 z_fT8<5c@E3VE$JUR zCA~i;n|s8gIu`1mVf;j_v8`pj$y`^&=kXDIHkL2)^%PwiB6B3)Ch$>wUxK^`cpp%F zKY{!c@*O0t83*xg@1Accum@#vzxdHm zx*}Kd+Jksi`(b~JegOyridPzB3P;v{#Qcn-rBIFtso{9ZifcStTpqQEN7d6N$TtDE z0*c4&kSX+BKb`$_<9JXF-3zTW#8=RYh}6e^#G}T8>Hon#NT45}c$7n?(DU(N7d+h3 z|2xOjl7iB|SA5O1a{;HBpUu+I%sZz6YZZBt*9OF^^z$U--vHYI#p{odDfC=Fo#z)_ zG_0hfs}3F$wzzyk-^JRo;~>ukP6ia8Qy^0~T6<#54>+207)HmeiF?VKxc5-jL_}O5 z^|lo}RDS*g^0&Z$0mV~%f28@@S#Pw^7SAv?(BDe~{V(X@_T8QAXH~r=zqyECKlyjfDJ@@`?>& ziC6Q%ysG+0eQiX%iq{UvF9W*(#p_MTKPj(4(Uz2W?KqfMtII3$-x#k2kQW1|0*coP z$UiBsSPM_Q+79MbRp^#~#5)%eQ@{Qt&nqBP_+Rx0zv3>G*VNj~W! z#^*T5Gl1EE;xiZWPrxVEI}o2GovMQK`^_$&Er?Ie3-&_(1o#Y4eEtcU!bbNzke=8% zy3o%cYUP^P`_fA^owD%*aTC{;0qz)XaHn>pwOs0}+OVVJ?QplDfa1{`^8d(# z%8s;3?}Jr(R=iaj<1d#-1L9FUZijp?@BpBAJPi4Ns8UIAfkLzz4M~Qm3 z{pj7U(r5Ar!xWr6W61lXVYt-K9>hm6QagkjlC%(z3@AR?kSQEh`RT%_M%8OG$T)|O z$GM_(xO|qm@e!YmkT(O50E*8G?%&n<%j)&e^AS3SoJOlPz2N`*CvpTXgA?#4;zHJE zq!^i>nwNsz0V#s#W77+}kUeOQywx1(PYtB_`GaQ4ttKbe*-CyfC(mH5YNXU#C=@GK zRgk9uGXTYNHe?D%;@>3Kr)l**?)dC9Y&c{M&oX%b{zE*=wQ+#<5Xa$rj*rTQQIbzH z;#1}PeaIgJ`vJx0?~uFVvyRSJEn9|rL(2}W!bRihYm3&dYh1s0-6DK%(YocUoFhkT zj+svP(a+QHKaLZME{AFDF0YEj7_SwOR|Aaz1tdgUdC+;?GBx4uy-=Ojlt>ou_+%EA3{G4*IoF25SY zukx)4^7X(?E~lSNKk=-Nhmwxh@V^Z0E|2y&9_e9Q%LNJmrKdv36n+9dEm|~)W&kyd z9qs&F6F(>I^pV=BJx1nR1L9M9xexN=z|(-@vkfwZgZq&qEKLLi(I(VJPl){zBVIXrLQ+3?*{g| zTz;~0k(5~cb0IGR76VEzOCkS6dReq+z@b$Vsgn9=L3~Od`yhV~d<7^z z-$JJF6OR`2kRV#>L7{tIMl8HOA`#$QyyH0mbWD$P|8p@&i3NL!_FY zO;13vz5%oV(5iHOV=126u~J{{h*#+=EzQ>Qfxdv^)eka-pF&^Ge57VF6gJIK*fU@T zXrr-%xG(cL{cL2MI=hFl{S@pX)TyTy%vV_f{dgS-=X1yK6f1)0K6qmN;StY{VEW&WgR#Pl&8@=3r# zK=G-AOyQ>}H;1_!_;f1;4}a@w2Li88ga@izr*FD<;3_@KpqB+0u-Mr$P|uBFVO`CQcTsVG1OgM2|9pQ(W$%AHcXQG zX+nHTKhHsa3D^ZFK5s&%a1`^4cs6OZ7t*fE}v$^M=_H9U?=34 zfn6?#Bh3dQ5Iy)n=0bza1w?S1oBl{F{ne1C1G4~?{<)AT992G0O?9pSbsCJr4db+C zm(Lc&r^>}{$bSa*0gBHjkSQERe#Em$>t^_-)gCYPQ<)dzb1LN3KqH{|tcOhDsP#j4 zC_3tiFQ&1{cDu`?74ay&dv7d z20*586#Yvai?rI=C@%w?^0Ecx1<*D!9_xO!4wugc#HaW?0(mR&TR`!79x{c4^>Vm= zMiD8FUQw6UFagHKiEGH#h=Y-LFg&ne99qL0;2%MXEtOC2cN&* zSbu8$nGNM@&sx2%?#!}=x^;_}(Zz34LcWO5^dJi*Y6nEUHp<5nu^eRM&=z5t$sP-@ ze$HXVUMQqD8SH#Dl20?@iy%H~_gf+F0^R}?pKl;jC_3mI(?jv8YrrwLWO@;yr680G zgn|sTZe!XUAGb~0Yb5gILM~WB2uF9(eR_gt;7&bedHe>ti8DkW#Mk2Tt167~I}!3S zU=^VF-3pmPn|uCpZ}+^t&it?gwn2^`bDQ+L#Wgx>(%zq(SsyI8)v!TnIa+$sP0d-5y$<;x?M z^JDMe9jWhwVcH99ATRWKc#6(FBGvHP9uNN+j;gS|!osbt-T@vIzCf>(JN3-@eQ@%I zY4UsY4Q%E`tVG9wqqqR%6llC1|C+z6i+A;rNeetUJUwF`er~1Twk;oy{OYBr*uwJL z({ZwTukamusz-#@;|m*D2v^41d=f*6XMVF+pQ{++zlw>g*gVfM&QCf&{k|@mIJN{N zun?}$;vs{Z!x`u0Y&ibiYLrJmkk2eujQ6Jlzxm z9b`?nk4-)|s~?-3eLjvst!j|vr=mDk-ls!830MTE@^d<53L6hv-#$$FsiS3_a8>yj zR#k;5!U5bwsBOXl9yafVqRzcISA@=Otrxi{+-)w8t%xUrc&J_Y6XXNHKLN#~utf5B z(%tv<)+ODQO{j7v0 zKlgI;6n!XPE|;OS=Jk?qQNI}9YRL0|g@EFF8RR45i*pqlN#V`>S?(Mm`i66a=m9za z_G8d}gz=m>x_y5{w=dCck#v{3bhY*~B;P&Y69FMAA74ZMFQAvk_$EN6(DQQIuyXxc zDyTKb!4N~;*an={GnUp~$Dm}Yeyiq88UI}TzVZV(6Y}N2CP3-yKaeR@yZ63sy{5bJ z*|^>r_~o{6-2KQ|3x5?al)V>Q+AnZU;}Z-Qs^HK*G$Ewqr>6xI z(Ro;2ZWVIN?Du3E8Ad{?&!AW5Gds=D4=N(p3-f-)^Nd(2 z!8uOn$aL5AkM%FBA)g7H2dH#k0-3_W-aTG;;yDlL6j-l66bPX z{PQ+9p31UVI_E%M2b=|{bnb^tA^BRFueI(uLY?C)Dsh~n(TmdU3n*PUV)CEzh{?~n zbH?Ns@}2z{lG`CJ#AaX|9$4Os`+WhPfQ~1@_L;c25VypeH~~tS={e>&I?xe^?rvbY zMVzM_X{BO_*T!W7L7(BbJUHtS8ERR*y*OJ6(<6*=JT|%&D_DqoHu0@8qujzh4tg&m z7plcDV~N?1)#$qzABd4gA)U>vY8%EC8>HT=%VYXj1^G~hfY7czy~yQMzb-Tiil z(#NX0vrehUHLNhk%2xSYr!~G^wrm&3ws|*Rs7Tyy;xxc=9Qf$9vvDJV4KIW&?~Tk1 z;wrBoE;&g@f&)C@&BXh3I*}Duds$&RV{b^Z9rh+035J!N02LVN)M($x&HI=cV&`Cf zmn>4C)>%ULVG0xy*Dck9|ekiv@@QiE$Mv4fD(VbNuMp7~T0Hgmg5AIQ})Qd-3&l4m=3 zD1XcUKsE>1S^}VW_J>U2G3$SH{cOokr<$|QqCQch^Nivbtd9fyl#fv4BP`KUXMbiaInA3q4c*hs=RR3 ziN(G0c`Z1fSt>S)V{l+ znws~97wP!F0Fds!dNC>Q5D#h*6~nBQzm!3@A^s4d&0_nMpj2B|$UE-k=fm z7`VbYm=MhL=7H|bOkD1aEo-ioyxYJ_)vFH3)(~6s0g87qWD1+z^FV95Dc6gmO>jGZ zjep2lJKuqGS@Dwcp;N@)5V+;CoJY(wUTpTmbzUC6iJP|@7IJhH zRPuYv!hOA=eJ9Et!Xvof_TWHB^rHM1+&mSc@@wIDBdlQDOCMJ*3agfyQ-&)SJv099_vgzaEDjqLxwxNZpAnUFKeCW zUAW4N%Ey;NYr#EBm|OJr=2f8^%jY^;He88e_KlPMrkNo!%?vBE2Ax|vFe59BQxHLX zqPUZ>KQMC=uha*`HsG{vmg%vF#m1{8kVgVlfJ#pXWD2!gWjZ##)Kz+7`LGyQi`F%) zrEJJ=6<6!q1#1<}-tB@qjd%Up$HqXOWd4Hj!3MYUkqaX|891#z-9H}}li9oijX=P} ztw=~h&@}uQ(Ru`he9xVOyyO6 zG2ujgZd$fpVAugnE9{Z*mzt6kHhCzCXAPrIYlja3V>K-26BFH^tE3+*NU>9s5_!@Dy!u%n>^_snhwbE*fS=`a zJ8UOqIZr>TE3yyoF-Oq@n0g~?xn-o96pf*e6@J}LN=mSeB)!D;8z^edJHMXgyi1{X zsYY%}r@ztgHwV`xc$|w9tTbKM1!sDL;V~DBX?!Z*#Oxv?U?-(d@&rttK3%V|(L8*rk4PT)IAqR|G;vxt(rDkjNx^l2PqV8zw)oVHO%J-X8I7WYli?=x1A3lWXFcBJ|B5N!%D}Xtd-=2nQ5`wYNFsygb9;4;BO&2?uSj}qL z|1s~ijQ>|y)u|&{0UOWi*h~yza)TjXCI&)j2_@e3`ZmUEtTrC0Wz%ye=3im3X`y4{ zzuYI3pP3iReu8Jc$p_c4aRbgBd;*?-WtGo!eLfqBp1NdssPZ^AZ^*CsG5EsBF|uzC zJuBO<^wF_-^hC%f1E&D0{c43wp}{>Lz3IWjw_lC*tJeIieoB4a5?lau!n#I0X*|@% zo@TokYhwrG%SU{d)89Q{YTG<{yw^a3H()%en@JvDe;s#G^hI8cph=L>d0}!=I4Rjm zG+~VG?K2VrJ_|4s5=Ax7KnFtChZwkf+Q4)e<8556XGDx#j5ui~hYiL<&60#Sm^oFX zu!XD;8IsS2dM$DbN58#Y>LGGWOb=5b*8`^kN)Ov1Q)qffroX}+mmg|;(n$|9okbHG zsWj`a@H=#DpM6PpUYgk*$d3;3XPlJiE$4k0ruKZCI2SD`w80B~=?O_bug9dW61^KP z5CjZ8DM+t&$PUtHww{y>$>Ys8d8KG)_{gsp2!CIs@V|_oE#@QT*&^gA;5Tz$xt_wa z5*(u%(o^w!H~pAPMev^bvC)vH0Ve<|{Z~V#Fu~ntztue_xpVs6*;zEb80`F64s+gc z2RLtI80pQ!LDoLpC|bc2y%`DqP>Mb$!H*Gu;p=aV^%|bA*Biu5FwDkhUQ8Pdfoe!I z_EP>2#;?ZBu`n4F@T+k7{|oZcDqC9tDE?{V-E#b#%)jc_x+=#tw1u5I z-wtE1_{?A(#`Vm3d6_#ezm)GjHss%Q=jB`Zw~g|{cjZ^UlrQ__-=383cFK3_oPTzQ z{A|%@26gU_6lvdi(YYt*_!4+Yftk&-^rG;k%qR>!#5`vDv0i8_&n_%8E@7w~kK$T0 za~li&m77)e7-LpI@EMp(@SFfm&>zwNmil3iLIa6!n8x&Uv*@_!znoe+ zzjuWzG?CO*24b04O6gY1Wx+0N`iMoOt4 zqY5)rW1nbW=6rTy*m)oNkQo~pKEo3eclySM^6y5yRZ&}RRh;4p@V=9y>8r%M;n8=q zyeZ}=Gk}JP_dPHAX%*g$jlMf+0PlM_=S9H-(A-dHEal(Ke}JWY>S$DD)#}oOfjswb zOh3TPPnrD*nd{CgT~10@U&$!#?`G7f=x1Y)QOA1g&0HfN*)S{m`H7{=$}q{y;DreW z`Wh-WMz6m18Bhp%?Pr~AEGjjAU=QPdm|h|xu$INWzhTyMY}s$=d5Rbmw1of9JavLS zCe+t3`}0y!OU>$ZzK!A9WSn^JJ>R;}3@x=w*?DPWytA#W&~vzqgWb*a>zTir-@xFH zmZjgQ+vE6)jA#4L;`>?V(2Q3(zm5Kc5s?3Mb{q5NrcMm@@sDInLnE*Z)cTIB*IQ9< ztK541K4jkn?C%Cty*?E(g$eGtr0O2)&h1iczT((RZ~%xjmS79~6z3p=hvY{1o80s0~A7Tulo(Q_w%&{IQS8=gU|DKzEq_5IVe>>#diLhY- zD*gY2Orgr{pWD0XpPlsA)Hkj?c4ghEYpF|W;veab&2^hJw*FPVTq-|ok?+vudJSj-24|BQUd>IC$#d^A) z1mo>uZ-p^9`(|d{!d5%a#q;%1CQM9z)0(KyG%$Wj;FUDIcPvGGhCb7pVPs=i@5OS( zG-JN*HMyPb$j9T;R7aZV;kXKd{=TTP)?Q@|$>N?sCb}7cOvy3(c*D4zHiUa2PC;|V z^Q19rfq}cDd?P1L&7#Q6IRbHPS_5$8{m#c7i0izX1lEX=oS zKbHAadu+^(bRpzxfnNYBpSD7#u;;M$*X3*H)U8~;WPDu%?LnGW=WNnSt6cymlK@bI z4W%9812}es@_5M1z;xQM1T)B9#ApQUXN9<6-8psRA;ya_#H#wM5Tuc!oy;9}7swsY-+kdGJHrls4-9y2K!9x;Y5 zAxA`TMYk?|fdo4gfnAX&T8YIL_IvGPwEv94hJBK63-~Cz?Te5<2L1*pzG>Bxud>T^ z&36^~r?}Q^5n2s~ejpj>1LOdy4&%?6wk46gRSb9qpvBb5Q6-ZldILs)S;>KnLafqb zsa_aZeF^AknsxybWWLol{GXfu;G_6n0r^JYWBp zRmVBzcnc~%TWd?q;Q?P7Y5`{FDOi>)sQMkqkAuJG~|j^v#EWN2*YMCj~Es3 zS~_p!E6_Gl`$%gtK`caBd3wmiwCyykIR*erEK4;~0;xu^p?k`VJ_X$FZ45yD!=&d- zF%E|<)*dJ`tYNMFkVsgHJ~SCv1{@#rUj-hk4_ddQAGTsv@;d%xVF^dbAn z<)7cDB)LdUV>EO?rWCB z8ok-fXGGlBL>l->BZ0&SFrTe6*GTj^9b@!`W`|@GaJ#p>g zx(1pD;2^NQY&&DE>~ikByd&S;B418+J{#;jtK;PVlV2X?d~{>{cbCR}Oa43gC2PAg z9o`nwwuQ0oi^k?H>}}v4Z&JQT=)*1aj<7)3KA!3^1H*HDBFSgm#WMcHtUc^!&hw<- zv*a`*9o7Zo88+O5<@|L2gUon@>2Mf$gc&Vth(6>oW<1S|rx@84o?^yU`pkrn(GKm%dVwONFHiDT+ha!; zj4loFe)x8%!YDolUL4Nf(SdVgv>qYz%%ssjM|^)|qp<{wEUd#}u6(fmxQ^AOpnj*$ zzA@2&QK3eNd@J*JEAp=f?X|enbL#9yc`r9?%(AB&yR?nSs?X+UloKY4x zvrFW~eRJ-h3w(Yl-wdaFd^*J2x^`CzO1IC?>&z1q|KzN}OvkK--{~wqId#w>@SWtl z41DI|1LFG&$d3R|0IEE`2$@2STMoPKw+`Y<<28qKe8F7k6s5al>3R?^G&Xn*7t4ch z5E~rQ(T^PiE5fnx1Pwx~Sm58n_^Gaf+rF24)2G9i(d9c9@tI`T=jBt}s)~0@K641)ZE2s7g84$0!MQmG1uT=7v0*$J z>yKYC@dWc&#zGn)zt1q`;H{+gIbsE`cb4h34Q!UfuN^#<-i;dc2S65}(lH(~g=W`& z)19A&^dFtnxMn@NdFt-&mJS-X>$3g-i_kWu=3zkT=W~1IXUxsyVH+l6tk>g{Dz9Nw znMN?cy(wUR2@|g~hN-N6YINbgLzlcagO}3(?;(FjoM*&%{~9udW$u0L5C5hI<$Lz( z<%{9mqH+M2wO_(Mqs!W#7S78z^5rhmd3P~)UYg}s<~whEpE-m3Yg4rSspaU=maxG- zv;ixPQ^Oce0op0j2ohQG`ta4O<6L^E3W4_36EBc_siM)=j z7ROoT=uE}UjP*_ajQ+5jW#FG_O#zuN6*FVwG+l5BgjeKsuL7r-#6H|pi~V6^k*24ihe%*V7b2_)Ehs4Vq_NLn{6akh7(~HDdCrK4-RHC@XfPrqc=uP z={#Weg2TZ?9V>oDzA!w2fFDcVFu7a)tJ%B-_H-CwCS!#Ji!fKSAwIJYB@n!w*SlH3 z@cHaaJHyWO`)#j%DYI|IIz&Dec->F)Y(~qyv3H&SM*axM?=M8sZryV?^PXyLajX&I z6^3mB)KnV2Ew!-;5p!Va$A#rOoTMNKKfhAdf5=FW=QO&cNq9JmNj<>Xh8DIDJa z&{-c=)itf+DOS!ZPAsPe{V}d>%g8e`VVFtx8Ju#&%hQCxg~!vY4;+l)Eu6+vQ3c@O zX(eP(OF5L^#Q0p<(6?kup4#kKdCq}c0+a)a=SavDdLMK@Q0I1Dwu&(aCY(fi8eQQ# z`+Va15!1fTfEj?#5p$?xoGmVj`olKoNFEyzPbK1^{_$?e&j8N>ipPG)J>?O-;+z$n14S3he4AZo1DDdAfy>h|Ub^O8(6F zLY}IIADWgc`Bu(}@tp_xXTUjt;=3JkPx+E-RsE7U)}L{Q@4J%xEa#0!l7HFIUdqf9 zId(D@4$Y!qP{0!~gcB`7B8Xa!SIoJ62L2Wdg|aisyf8`>8R5~U$iQpXY-_ggP_mjC zzh1{mrb<{_o=jKhL|dx{amt5&kVgVlfJ)a~$P_Bvd&s-CtI6^ZEx1i=i%g0o6Y)CJ znzHgZ$7CnShoaras|n8_BGZT^R!dpCFptTXytW`-#p^}L?*JbFiq}_=d&*1d`*7@< zyJgo@AbC~Ijqy4KawBjCpm^O6xu?9Q)t?H-mDm6&I_Nw{4m!7S?TM^BtVQ$GU^vKe z7bxnyt;5UC6Aai;V42|leg^q<8nh%yTHM9V{;YpYqiww<@2|m2)wl3G%n5;FK=EDy znS$;5%~xO6)%Zf@^Q^j4oW0L!9qdIpmcy{ZscIcUdjqOW%}>t@Q$KHec@8Y3LDLQg zeZhpxWPccYZQwXapZj>wFF(!qml}!w(tsUKrpEX_CVt2GF2*WUX@y<0uS`cPc&c=K z1o@x9*MLgL!js%|xa(8uoZGJ2FIWF@$+?ApMq|>)kt*tCKQ*+Av-3nMj5RP>H((PRO8wP{; z8>T^`pBJAbCDPFF6%M=kZyD|mcavOEBGcP~^i&{UsD8c-`CXtLQ0a}#m+AfPu|Ch33(t1iaIVo(w~87!7#nH-;!1BRI_vi0MI zkzjey+2|HE@^JbZz_X(n*3?h(ZvelD%l}HqHvpRf#s5CY6b|1nHqs@=Ys;q8J4PoF znhc9w88YZx?YbQDK(t{^u=#XNJ01Q;P6(CC`1j-Ym3@dWz!?dE2cSUy;ad)ChmFQd zhL3DSn62HFlTH7&!u|ak{8l>NQ~s=gybd@MQ0cn@GKIt2``ma=fbj_t$*pQ+-fPsh zQ2May>w){m0F)}&^;XcPxfVD6HvE1BzfbZ14e~d@4}gk4Uxs*9J>3BLTHqIe;&m@%3g2BJ+nKI;t;WH8uGu!N_7b9XEj@-iyuRStE8vv} zRI?S1oY6Qz&q5~w)$fB5@j)6P{m<=dBoeG)4f`jh=>)gH;mDDt@IW_+DyAA9< z=a!JP^SxmH2gU=;hx>{8Ez6J+lPX;^`;)w0Y?NbtvZ!JHLVU%c zr{UVeDC7~dANDh(z)cL^_dJ&wXsj>BcsK9>hjx+_*MOU268K~15o^4flT4>?I_(5x^`W0 z+0?l8o^aLhF*caZ(k{jRfC_3s%VHb2B15Ep(oc!SKML{!pbk*+KLq(G;;&h=mU6dh zFWmmC0zes%0nm<$BnJuL_O6b@G^ru;=8Ixp65xsO>Gh=`V$S1Pd?HrC zZ5GZ9B@Fc&$wnepsXZeF2JZ~kFpo1ES}yKpW|lS4TdOZ%ySTgyi1}ekvc| zguEB{08sq*L8fr{er)|9I=d}gGX~buFT_bWMHM?|sAg2~0(yboN6Ppr>SOw zNLXsDv_sZPZ&}V5e504M@uGda)JN6QnEn?*ei(QhQ2NL`RqA7zyWgUs%Xt*ttwHA} zV8i3->zyrN@Ibjz&Y1(w^gqRU_II8U=lQTS639Q~IUoJpdCqX2Vdv>gxW5!%nA*?t zc(xfZJ@7A1K@)-Q_L$&sYCeKNL!?jR$HR5-I1aN>5Ux&~Eyaw)N`Z?Z#+#{ro}9{y zP6eICtS?wdQK5!=0_%Bae<=pV4hbllDJ$CSqq-IrolnzkQj zCKLu>S}+T-VxIylW2Wi-h{2_+u$}S0vqIsA6G-76X1tCuQ-&zW;zLt;3g*;)R8^l5 zwljDE9Sji4XlBMASVo@JyBGZhuG%Rq0W-D$zR{Pyfk_Yi?@ok|Fg)n#PF&-2R`>-o z{>2KvV#fE(s5N-uZOpid6>et6jad3Bynz|lu)-$#YtmjAKtdP+y@1h=ADha1@j@%# zmzuzn@Hw_M(2h^TOto@x3~!36LLfFnT?1-6BYb;KMPpGBihzcwN7Ri5ahor|s zFK>y_H>1dyn33(x&4_q2P$N=}a0XmxQ+yf1kKILy7#Ws%;r<-XNcRs2d$C!W#tfE8ZIj4N5;Rm?aK)Xz1}C_K~nFHOv08a;y-=~G27{W~Ux>$@4+Iqa9Y zNr$)pXN=EJI8S6@y*o=^5a{J!hOceX#ebZUdBq8`JZwOItM;oI@}t170977ZAyeqC zA5!(F>z?RK@gdXxfgY7cmvH9;_k#wOp;?ko=(Je*EQCB77zZdmw?L+#_D^+PpX;Lw z#ZBy0S&grxO3}m;$O87IxYX3X1D%Wzw$p_?Sh+Tn$U(C|Hg~26yoss8XBP00yg(Sm z1tmsaLB27dU?6;#gXkS#IWH(Q`WKWLIR(9p@g+PJ8@s(&BB#+5QdUG>pb=iKFXRt$ zHbh=d6**C+uLJy5{R^$IwQL{{Q0bclnSvVkb=}X#+N-H`XTmE9l`ySgBg5jqz~cXx z;!(PiGY`HpLik}o@WQLjMlYNMH+^!|=iVT8C1DjC`6{ZN2BOX7*M#^Zh@Zv*Pe6Va z_#L45y$YFv8rOHn59Dao(HV6$!=3OBtS){jo@2P1AdgQ&CsRZ!E8!>0>*}?pxl&K* zD`PxHK&}R+0*c4!kSXkN@7w9R9K`grIF82#_L?*Isl?ppORKF?#i30m>iLLqROnzzYm5wV#g;XJR)9wsd3|$$_Aqism(W zVbBf@OvvHId>~eNvGXEDPxaH%AvY$%zn%6)`t^LcBBu)(l*V$}i zjt=lu#?pWY%`>KqpU)Q@4;bUE3BO_EjR~AE-rqx53<$3dn|``K%hYw_UdHcX zQ%xN+LiwXtvD4rxiPLDX?Kahf4-R%c*hcV5W?aQ|=gIG8M!I!2lywoqSSOPYJ6K&l z8_R|MET{zS=<4)gR)4Focn}UDNN|jOH?dJ$nQthoH*&G3!#q__9$9wGc(#7@W+u+W zrPyiu5_X*T*NkIddl|O1pd-XlI1!eHT?x-J-#YqA+H)**oed%DW>!?qw{jCl=HM#@ zeJlF0A!tPVl?^S^=ks5&MEu(#mS0e8Kf%&(W8{(po8`L%rOWTJ1_f9vI~C&Z?vzASR#fQoWEk?lPCD1 zZ_w}#$53GgAFf*>048QGBGApR^1r(-kF|1Vt2 zGW~|{5D|VwL#Rsl5b}SR>=bin#7MF4F|2glU=cNUY3-NEa=ZoQRE?8%LVgq21E_NR z9%KqVv4>2@JR>$vYB&kq_EL1)-_k-YhRC=Sgo!C`O={aH<1bnpi~o4YbAb7PihmL0 zp2QzLVWks=37|ly(|t>))A`~Lr`vG3n|}O$H2siw0dE2-{@swfia+kYht5+_hX{JP zaMcW$gARz58ve(8*S*c5!;LqxE*9@GkS7Dv02S{{$Q1S;blz3;zJjh}O{<*&yY&>< ztq+LpI3N(v&PCf7Jt45=3YqR^{C)(#Pwm%pkY5B|162HPK&GI^Lx=JklPe0vYRM$6 z;WVgxt)ue)GA#gT_cBovZ9iMCl<`N_$Ho_uws(D1)Df%dLC z|GvYGuL-}W(t9uD7T_sB#rF(k3Wq$OvQunn4d)}30bCGDpyF$UOrdN2mKBwpvV7eM>#%HHT-I2>wtk&66WC6={hUL&-wB)#u^AIs zY&|q>%xV0l9~bYy4k5^}X<#aCn_es>T6#5h$p&mIoaDt^M#sH7!9d8$sqy+f@EfNC z;Qqu=L000rqvxHopB!46cCAduPVkK2BdRBVhWrDdpBYO>K4c2bm&*RV^LV{eI$}pL z{f#|FzUoI8WJJE&%d629@zUoot$W(g_#_AiWN!q|RdtJ(;Rx8`vUQDTjjLO{VqGI1 z(0Xn=|BuHxm?O=3ULjBEc+U6`M*i>}~{@j~;leA5rw533R0;Pfk z%A+8Upr{qZMMbHK8ihWg8rs?iFQay>qGD83=3_=ht1 z`|` zfu32)H0xLl+c+-~A1}eI*rnzvd$ky^D`GP(;ix;L6XfwMF6MVxvRIXuZc~arlGJ^y z-Yd{L6O-w~PP5tnAQ=IS$qdT5IW`_2hdwFWpOPoo?9a&Za~K0m`-!Z+AQz<-WlU#p ztK%72-O0ull@6`_Nm&icasl)5AJX?vdzC(yeVT~BcJc*|Wra+%+gD?}PbfPkb9MpU zvdNdHm89jWjGBn8SN7Ybp3~)vZcY2=^nQB}-;EI8UDxCBdy;*%eKhrVmt6W5 zYa=b}r+ZnpO|#Bor8YZ?%H?YLRK|nlbyAQ~Mzzu5Vc)!bns}lU$BO&(dT}G=Zq|!O zaqmI?h?w=_q^tFM(QT|(Uvb2KjK1}vx=*EGo%-wgn)B;**?E&$43Lpm?wG7*=A|tbHqLCtA4Cgzs*i*W)S{t{R$D+M2GdKwxld|SU-`H z6wcSmZf05;7+l5>TBj_AxS0U5Vhof$KDHuRJb#W@$bhij@>~$KclxCk*|H)9c}NF$lPu6ZMFy5=_&tIeULWhYvuC{ zUejGh8` zXQ6xn>p;h4rLlrhUF?{OomPHh9m6xzO!b^u;~h?AhI}ET22%PY)*UP7+eR{mN~nu$ z)73HKM`>msc(OG@Tx6S~4)dVZ5SFBrXBlT_*ru>dL}qt+>Byz{m^r>cO)qyS3n=5I zcDrT?j+z>l6SUp?Y z>cn^-i^m_y`BW?S-{xSiRg`-%*Ac^d6#hA~m-{vrSu#~QJFA)%2$@;swhSeUm0r2y zxA%R9}kg67?j<>@t<~iBDr4v($-mCR?X) z4a(=!syLkF1Pe9`XJF7K9Rpy?RI6jWQ>i}Uvq~PRN|_Z)RPyu_>?b=i^G?JcZ~N75 z8C?Iv$IB&r%2lwHIIKvEON2BHQ#LctpJ0HgWc4J1$nQ~ci@o2kJH4db=HCu@IC(fnAgUAM8W!MzSv7e#?*{hVZDwCBsvbBb}D95xhto@f5wQ4LquN1o?h0L#FfygFojM&`j#8D?Kw%dn|8=hJ1 z7(tv(CvkI`CeLTuGy|&*)_OzTk?Pr{=MeIGyE@*luBGYh#CV^|sFmJ$va9GWtMWRF zCFzRFS8zWVE&W@TN~Au`s3qrDdU@VRd36}&*@gQz$eV~+p67NN*MnhS<({Ljhx3gI z)Y_&q*45Rt>jvPq%MY+p9$UE)-7MpMI({Z=U)}>mr{IeW%Pw0Pd73L%(4yLhGcKE( zpPn`X>w$TNvM2po?2(L@M#u{mDW_pOH)B5Y8KdnZ}VaLI$Vwd*)}W3%E+}nN6j9Q!8h6R5H5gujAlB^lV^zog7#xqX?n+n6?HC9Iy#CrF3cFO1-R9odbT>HG_Bain-oHPR_w>`P-g zbip|+wJAYzF=E=G@;Z;Zc$gbWQJu)76;_k8QKp)#!?akzxU{ZK%t>LQ@NS!CoA774rNRR3!(w5mutSZdSt9aU z8fnIs9j7Ua8ADEYVvZ{Z8(LZ8={}9%83)5$g$@R69fiyTTA4CX7Rat~j*<*VT7g>B zth!EcOvvCyX_rcb)hvErGQ#0&)+B4kmfz{+G5dzze$TnMS0HtWnGcWR7Kh8|Prhr|4K(sW+t||He6C*o zL`H10K99{KEFgV>1tgL9cT~$ZYZ>OBFxzA;%+JZhhCbul?0j}oV;puXwl(BRc?MZ= z7KZJ{W@_JO*`>UU^sJ$hwp0cqT%+W>WoZ%Hj73cS zpTaGUwwv{GbpP^*`-f4VPH$?~X39Ej?<+}F>agvyCW)j&eS?`x>vUTV9dlN9^Ps$r z%v9xiX*k!1nAmq=?L$?{RT7jnOL30RyrgJ`>MY_K$z&22s{-jP<3CUKJJ;gwKspgKpKru1j^nRaKO!Dut@nIweP)Nc*s@buY_XgsRzF)T#edY( zvzzcH@L8niAnwCRH)6*3C2nzSIqv%SKJoRey`F2tx6tyEvQQX%*Wzn7;#;t}w;omE zu0yUs%=q5HEshRj9gEwr_h_~URae&aUIb%VTr-d3h7Bh%kv zRVTgGX~;aDSTCf5a7wy^8Pu^O9itr7e_=4Nn5H4;Yu*wf=0fN5uhi(c-D0mfvCAeLi!H^6j$hm;WkBBb4{Fox&m= zIUgF=|INMWJ{R{|B!HOd{yA=OY`>PKNZ3yco@-Qx8pE!*EjE#qp>|tv0 zu%TEIO&^A(30~B!4igu_v$DKc8PB#P^NMKxvz{(Tu=hSQ26qWE0TG9|9*!R8HPX{( z0^JCBC4 zv*ku^TwXDZ>`^B7+WGj4o}RsgXI_7YaocafRuW>yw-mQH_HNh9>D42j`+8sQGQ30n zg_4w{4*4fm4HJ?qrP!#x%zT7gBC|o87RimFi;-B@8Dbl%?39#znFlUxx1E78E|sxA zd-h00Oxur2E20NA(va~56SF6Zx_1_jClwgVD3T9Ij+?E#>}0I8Nz&IXFFBy6XFK|u z?e;6U-$vd;%=G*hw>XN8dE5o}9MNv~meWdOtonK}R$YS(XSjN!`l!rZhoy2X{HB5B z-jlBlSYnrgTZm>?U)&03D_*hxLA}($s%9;|j)S^>OK$DeuO9bWB!HOu-HuxvhmGfw z1xL&`GtP6q(T{CzZ==RBfOo673Gb9107AhxWGr(F1~}#-eTs04WAA->KJ7Ke)r@+5c6%%9x_e$uv`wzjMtlxy zuj<&S{#UlV%{}@gM#PG&hqYEl6^cdXqH)){8iUu74Z}kkEr)+aBo6xMoc~K z#x0KH&tpxws=Z0;(X%f8PU%5mk71@*$+J=Yo1`tI8Y4F-vqU$hoaiqm{R{qPq@Qq$ z30K6Mz@4#$@62qTjBfh?1Tscp69%icobp6v90N|YcWHSFy*!?Gw86P{<#ZY} zy}7VV{kyJT2k{pZzsR5aa6g4SgP8jL3b#1=ub-!_Z>wwVt)45+LbZj+7z~4LRR6%^ z4aUQVQ$1~%<5^@@&l{ya_489*AIF`&^>Z@rsYp2@j)Ci^p+}19`2(tGu@TQY!Zgd} z9^BiIF2qcC7`Hh3ua`!AM^wuWX*uJX8`TY#9qLH=LQy9#Rd@r47Mx|95&xHjU(8n` z-}AT9_eV}Z%=o9`7DxZ}(um)zmh67msIBa?v$Ag^6HS%~`QD*TS7I1U)XgP_^?Y7O z_-6X=!u>GvIAX^C8g6m)UoXx4?yZ*1FNynEsdg{h%&kHlqnscYr}LyIPwT0cb}NfW z#kjnvjmzb88BjHf)BX1lrK zaw_Fm+8tpvr^Z*Tr5*R)Af3Sc+K|n4cxy& z{$S`baQ!s(Nl`&J*?QW~1x9>DclDOj9NZpc0U{0&-|_cV9G(8Y6;yAkZ#AM?V#L!y zn8k!A>f`;mw;^49;yFC1d^RhhsD0^{yKLAYG{WCYSY~}o;+F5`T`-6^2A>Yz24QSC z)Kl?5Plh!c@hlECyIQ>;Mb*K9MhFOW; z6-$SukC_<}E!)j(Mde{&wsIDu{1=NpmG+?2x98< zbKK(C@sfW3Idt?mv8fNQ@-Xxv!$u#rZqEADDjl|Nvwli+8`V9zmUr!C3>)U8jd41x zBZsk!|H8D39LtI?%9Sx3nKm?Itc{1NGmB=H$)}!_;V&x7$5j4#4%Zy(vf>M{TYqxe ze092={xL)2L!2`+7FtWQX4-S-=jF(}oS_7h@VUYQdjT)`t0-92EQ&Z%vvh57}6zt;2W9?JYFBZd-mK6y-Kd0W?TaUcBFG75XnV)UA z#St^sMIUJ&V#*QYUsLMa8*8SKokORN#<0nnGBI-U6UnlNF-9jQJxk?M_N?Y9VvnG< zvi%Opmd}iV(5Lvnx;{IJub9u`x{2Zb9QhJ4^(p?Iu20CA&vYL-|8}fCVj~m}qj$?6 ziign$bPW5DhNwgR2XCh1RVH5Br94@(JA(J-tx?aTz^vTmQ4<3Nc|3P&#`)fm9c!ek zr0GV>x-F^e+l)Tub+{S#L&#%@sc*~uy1qeU|5V})y0xgw3F+!<8NGmr_H_MEEG*5dC< zIF{&IP;>7+R*PIUD=XWcQzkS?x7Vm_v0)|jdG_;9trPA~q_kNKYfMltvM-w;kFv4c zXp()F*!^mg-6&V2@?tbPW)qkpFH&XsbcW zKt7zUo@LKIDK95C-+8Js(kd>cGFy&1a*=(?Me@@1;z!qIt(Vt{*NWM#Zfe1zcIz69 zB5~rPw5e%1>Yv3@7gbxOs%gg>-Y%*1M-paZAK|rjd@z*who*vhqzV+mqms&^Uv0Us zM{++TJ}vr07=vaXlZa-#sx7g_qT(O4&m+g&E>@72J|Y%?-!0YH>%CaA#^bQ84<-2n zsjx<^&AL-~@kom3$J@RIE;oO8bjXc7UHs_UF%)l%i$w9A!C zscUxmcarm>+{=hBA?e<<_|&s)*ElcZ`v&`^ToCEJdFC8jD?T5Uie8Y0UN-y|Y1r3B zv?APd)Kc4Fmc7wVtr&9we=U}E5A@C>Jc0Xpa%>LZHxVw-i z5i_2raf>76x|p7kXtB0cUt8*-2P{?-cdCy_7PdxUDYa*9>9%ot`o1LGV!{>a%iG5I zKQb0E<1NK4j+D<`N5re!zHPpYh{cl9PW5%kG90nAn+vI%OZ0e~3Ad;H$NgR8dx#nD z1GvSJvftk)-k!CrVgSo>2S>%aqLPQlX^i_M6eewjSlDLVvud7kp9y;W?-ITle`c4%l8+Q2 zX8a>?i=&@(vu3-!rmgtu;)TWS4UKKhZ7uVPjoK+528#7H-Nn~vWqgTtHMColc5yWr zn+OPhr=ia(5kH?rdvhP|$B^$MrasT$7RS-!9Xsmp(o$`h5jjx|uxO!k z-!}AFL43u0C(3;j?z@ot5L2Ibaf@TSF+aA%u%kPmK3CR>#)Z54?W%TnUn=hIo77D< z%N1i}uUM$d^Wn+PiR>y<=sGV@axt|wBHNy)6xa(-%eCh#^vh4To|u05Fgq_$va@hV z6|3ysEM>ixZ3&eaX_POK&$a7IAeyJ@`8)OT-t^Sqz7lCh%=BD~TO8)N*=*zae!%qf z!L z!zYa(x9-HYxlyc#4ZXGz?`+}~*UxU;e?mS)OufFqEspI*JqsA?oCdEK<*Mxt-z)u| zezM59ZV5BNV;GL~QQgw=F>;rmu1pidCcNikmagF88G61gc&fKtufn|!2_U9^n{kW7 zY;UF-^SXoAub%hLuM#Co_mX)tb)Dsh%(0Ghu?WO9VI=L%IenTPOLMud*So}9OuQoB zEZ^taKnf63uTtFN@EZAL+Pxl7uce~Z7cCFfjBaN(GK~F2H;S1!-wYnNRUW^mOF7oz zVmNN0GK;2Yn02mEtd6zj-}8jr(QfH;Ad|^`O<#Jcc)t6guY1vdyWu?B{0;W$5XAyEY_# zlKgXtws4W$ZtB0}Bwhd6;okP95%+rJTEx`EspGw4 zT2r`S6|2>Eq4@sv(BlgZPt6k*PL9X9lPm-x;0(D^iL{Sg;p>NgSh z|D}GXxA3y0<7szRO6_P5XB*{D{5|E5`+4L=#MJLMxW(~5l)ssO740omZ4FJ@GvR_3 zvTvD|eV<5{WhZLcca@%fGZ`mpFw3`Nj;>$P4|?-&G44v_V#L(19=A9m*X!-HInFtV z`f2KC-c61y+WI3ikM)qn;zBB(tLwF$c+GO%kNYsvjhK3=&**xEzwNfQ( z24;ts*{OEdSz1PtZKJr`iDd^YI1{EuPEau1O0Q>|q2ChX7aE9m=LX!jB6lFBeh=an zN6=`m|A*_Mp|Pe<)hj-Ev;*xfwp=T;%fZUDX6cKKTKWs$=jr)&h_N|mN==qLA)}$3MbuuE)nKMitYn#fe zcd`mbW@To$GqQ%b8KY)391D?D)o?rbl&fOzi1E%LtQ(tSFSGFiR~2u(c+8%=DBYSv zl)}QY-OXEi^qRIwgtbow1oGwk4rb-heb0Nvj3cXyOC*RHX z^JCoI$XAG2E@?l~%jJJ)KU?+fyuHskC)0LLrtJ*!Dj2#zBYC`4<$NVic8O=Q6EQA1 z#%w+B3n)|&|@8v2?2A}pmXzfG7{suO+k zpn6cUyh68fyrUq;m02b;?2k2ktXvi33niz>wJhz*#Uzzh%Pk8Q>iRl%^y)hYcQvvS zG4*{6w>T=E)9d$=mj_wTd-T;Fmql&gE&oK{QWDd#P}@eL?=LCP-24?Od57JY^gZ%0 z@gnwq(K{Ybrl+y12#YV6?hsp>923$onlVZqV#{V1)T!!do19symd+^5C={3UB9?BF z-dQphSI%QJf2wt;;$fjup}C-Y+hQaAKkjXR=HfmNxezha--ufruG{o<$Bq4LgDk%d2#|dApIkg-J`$DY1^wE#AK|MPA1|%@uNm zG)-@wI=-dry%W7ApqFSjyKzr?j^`M})O$Z}aWotIM&A9y|5R@0*R7%G#_qLsW`Agt z_S)uafBzzB_*};v?ZY(f@0r@)S2>YRLH?@Ha)>3n1q!PqwL27su`#8RH?%~qmDtKW zRF$&|^M=audA6YiEcK^V%AxtmmFJDHyPoDPgPIwj38U@BwYFJGhII^UtY`q;x;G~q zYK51QOy1x=VTQfD);3eThQ%>n8S1FTHI#L-Hpd0>blb_9nYQ7XMff=n>vilI7@{iE z)6QceZM`isqtH4xZTcxgY_qJq<}fpxY_C_=%MVD(0u~`E=ZY8XwoxXTA4oa#Fb*X9 zd9z&2u!~D(^1@ypZG$w=F*f5exjp?&i8UoPavl@9yD!wsY1L19%c%?ZPUL08ET{Ky zi(_g?FQ3ET{l?|gUftGGSGTaKg$0YN^=FiA(jk4d;APsH!EEjCSn>E7RPVD|x~(48 zE~eQ|;IjIb?edHq-fvH;FX0k732SV;ep^1>Sl`*aOi#zu=X;+=>v0E=ZzEYw<>8Qx`ssxwYIgd>p(k3$)1tZOu&$N2 z&1R{msO8f}(0~`KBi&iNGRWaRdFo<{2kSJfTyx{8j<=T?>9zRu^zJ4-=D4Qq1?n6! z88Oql7`HeUJf){|iNV3QW7?8|N(#xaDR+l%r+JZ9w`%&-v+;U8yGvoP`V@xb(rn{- zC(k7Aou#%jvuo8HYpGDah1vN+X2r|s(3DE2$m6Aj+*XS(*VD5NeP^SuD8Kh`TYpAB z7BSPa5Vtrc7~{0AXTNFrv42!wMq1et@MzgOpjCSDNF=yFqec>QTIc$@rLmqhy_ARN-*&*f6AM!n6E{^?U zrSfixTL!L+*bcrV*KKq(re3L+XY-4__kl3(H;}gwvphe=EsiC|y7(Mpo&4ah&$gy! zQIC(f4{VX{mv0k&#BA;F*dyJd$R4#?5;hMvGI2K$>)FRCbE%}`?8ZG|Dffg)(rj)N zW7IYD9ryb6^ep&!?>zn*+(G1a#7xhhaf_pSr(Q2ty!5}+&z?IPHW_!PJtJ%~>ZTUY zeMS)-j6}L6WS`CgpVL{sbvdhWm{d_SiZ4k$b z7Cj%%{6%m7xdZnj$Phuhd^(rs|?<=Wm{%WzX=6>pr?#vc!3A^%fhCSkPp zcdhpKB^Czq)d`^(z8-fPI+2)kaZcd%EMw%;Y^psc7lXK><;ui1 z-URVTaIvyZs!S2k@&tR1(GOVBuBUhQ&ffm=Rk*K4IuJ9xn{kU{ z!cptm2cKR)?`Wx6e>Sf;samPE%G-DyyM9Yy-RzB|;9MFOR6a$yzGoYgW$GGTzjukh znE1tg!}&|z>5O;~Q@=*s+F`!G@f$zS2s24^i;bK9+md#pe^$Tucj%v%_WiCv?*qKa zJ6{}&6xyD27k50GCSH5{6&-!%PiBdaw#p%Ml#)z)Rx$FpG_FwGBroE1Yg3d-@&>t) z$C*(XbF(I<4No5-kIvvbr}(ZgSM%7h!AL*pGt+N>iSbXwg_!A|h+7<$hCS|pF$i^h&3?+`xSvN}L`?mZU+Ma7H=eU1#`>QD_0z`Z`_!79SjPT^#1q%`lGs3WtNONL znLP&Es%7ctXXH$H0Npact?*+rgcW4zfLL zY-(A}JJ2`Oo!io|vZ3)b47$~<5}lRp(qr;7Vwd^`?QgdBcdW3|b*uV?)w1p!`jc5U zZk4oV*n=OVoK3r)rleVtjH{gWN!RJ=Dc;rFuAPVbV&pQ! zOiw*-aeU)(7IU7wXQ39eolCD16FiL;FEc1&;~B#Z=G@MT4qcz^#AlAHe2n{ZTuV(d+sl~kw7o!Y*El}d$trCcUP8926o z+bDnHH}$&-_xF$o5mUeCaEqhkF}>WUK0e6u@6peghwasGul%g6nLN1@I}>6K{O?xF zHpWeOF|2BvV6A1j;V7}>P+Wtnm9yA5S4kCLAm@s!bK7@xy&bRg>OCL#*~s~bsrM?} z;wU!W-%>o-dHTM3_vlQk@qNA3xb{sd>L&Gd-nhlfZC9c3XzMaoJr|i8U&52lne_Cg z$+=>*?Qo~A@AK$m=JO}GzecRT?$viZZgH$I^voIjbDgoyf%)1VeKGd4S@~4FDfR~G zQ>`jQRLkF`OL>1RZ=z!Clh;5m9AeL($y!dy$6^9CTbs3D)5}*9wwli2QSE%K4cvZ% zuKzmpGxh%g?q49g5Hr6I;1-9O-`gJkAL>bKZvwW3HA<#d2J&QUVp09mkZ@>b{p?w zaT)dz{};W)Qh&BJKP@N4w&pVJ?>0V&=YdC5-e9+chjO=)pMEAgfrs<-!xC?s>KLI8 z#rjT`Q%y@xdroqsXAYsWJw)_}Ta?RfbxNI7tezvcN$C#l?K@iXEGur+^L-Wio9XMq z{W$V{BTZtx-_h^=8hpBXpJRJ6J(GlFTB0`A&B!)gk7h%UFO4`wK97FgVVRCBK+Jr; z47WJU`8m_h{($3#3a#rs_xW7CryAqnFuk?8E&x9rZW ziS_iWyWLmOK%s49-v(}T* zOwojGH}Zc8`D^C?TAp>TMK&U4{$Gz<94YI=|Ihutt4WWO`}5BgxxdV!EEBnJZtTsu z!>Iq{ubKbW-K=#+au75B^Kpx#pZY&w{nT!7;?ZNtPKia(^d-0&h28Y|@_6ol=NvcCOz!B$aNY4wxJ8Z;B@`MuJA~wcca> z&?@b<{y^1`^C8i`Ab&f}GPMj#Hp3N+<`t%A=4V>7hAX+&VQhV3E11}?^`ewEDLpT9 zsO?tkP+5`1Tdah}mtlt9@l(lGD*9Msd6|MdTmF(a(6g|!<6b=5bz+~*)m z5i=bv#(8sJj7cpY#XWM0w(+q;de^4q+rMpW4Prj+TqX*<{5{3^r@PX{9B8$Ct9ZGD zaon%#vD1i0=yw{C8R{{EiV6K~E{7Of6j^tBw&mLC zY>~@O=Ut)0uSmPrc24?m+bCWu#HwrtY0krrcNXTCi!eZS&Pw~LrM&z1F8Nz_FN12C zjBAh25MDG|?5={EaWALITU`4Tbn#lA<+mo3J6nuI~Ee6&C2=2S6XZ+(-8o)_dlTP-h1Wtb#; zfG1#Ej_6#svIjwav1b;_vgI*7{$)n^qFiclHzF;F8UGsNyjd?y_S6r`Mc+MjS~eDt z<@J_si3Q)&WOmev8j$n2QT~KuUe7VyA0Y=3GoHWV7RS;1V*2!lE-k-|?G1G;^=!8; zzFObTAdJ+%ARld{o^ZAp@y`B3Z@lN@z6_~G%y{c@iz8*bc5JM@#_C^Sk$+!f^@OvC zfY)ZESuQ{(AU5Q~^fb$lkXw)%#Dfe&;%RA?SCEI14akMaG{lJ_(nKzJpwh%s{e{zp2E9Y(q96=O8B_R^&qk`+dk= zNE319gH#~Jh>U#jrNiKH#DyF_Nc_k>$V$Y6IFNrGa9El%pW3; zBR3&eBHuzv5e12TM1CR{X3FJoP5@Z@ujCB8*aVX?o#E;BJa*=&| z9hRRWn~@dBbi{`I=|j?qdI(7zatm?^Qi^=`C(0KIB4sO^%351$#Pdg+Zz0>Q&u)v z2LBVSulvn@!h1kizy8gBgJBWY?0>`Gh{s9oC!VVIwx*SJjdd*euB$znS7A^-**w_X;7?I>eJb&h&;4b~o2suU zTVAuWX*o%4YDrncj{2Eccc`m%>}7J4SFx07uwJWD*4Co}ZEde!-BjCdq}QyEsgubS z*SczuTC_H-Y^-W)ZyBuCjEM9prUCPVZLUqN4PvHqkovULt;SB@pgq^uwbV6YLpDW= zbW}z*^J0_g_69!|r3U$nrrPSk`mDZ!DcwPO)>eQG(ywNbX^?(bRW;W7>ryt*M`Z^! zXprI7vrmUQGT4A?8|v!^88TNgD=i1>*-y(lSii!$VN?5HgRa(Qg9jOQwZBQP7OAhn z-lk?{lXy}})dbhHtZ!~>DqA;m>YTEgx|X)(&5ROiY7F9*)c411^x~zfdIFBQ<@EK~ zT(^38ZJqYbV0>R$(>iSs{zL-$_tv_qYWmDsWje^gnk$!At*)I_K85uk$KGuXjgRvq zbk{Rza6jr_soK`6GDPz@RqQC&Nd7#CAznM!|Cs&Ii|3DprrPUKJ*h> zZDZ@|)>Iu4k?nY>@i$-&V|jaHzvaVvS2`;Gp633T+||@+r0dw)(74iHSMP6FxvK4m z4=MCCtmBm#)O-!1S{fHiU5%*D+TT>+>#Yq})y!$r#iaN2q|Lc zb!@B3svD?DEj<4Bcain@Xz$PYz7LPrwm%PHG}XrkQdTAn2>mqAEdWI zL^zNaE$jO8BucWZZk^t5IJPO!a#r)Rp`qF6J0Ejf>GjmonCeE>#}6^4(8#FUt7~VL zA%ndE9N~T7roXTELFv)Ir`oz!aa(Ln)n_r%B)n+}N)cL5`&Ql1SkUW0}P!Z)&fWzFgoI`r`O^Y4HbhD?IjhW&ndph3>a( zz(g4S)-@SV)W=lXo($)?gCVI@dD7#px~jEqR(Y8YEdvM90qXhns=9S$NQ#Wd@?BfQ z>bf#UfCkFMzFtL>EXLweKK@oW`P*u%%LKGPeKPo1<&PaR>HG7#mX@ZLK}FPNq_Y3; znpyg<=SKhj8mWkb@mJ3Pm%qWh3i}T;_1H<@6xX!3w3@Z2|M05YYpyh(SqAV)N%ZLn z48n7NT>-N$)YetEuPkeAYp+gq$@-gC@_d-8ZN`T8sE?baC50K1{ROG&X4rjx_&h|dS#z77~luu z=ikhC3XP4%mEQ0)@qjaJuy?oP{^0mMzN4eiG&%M{KPJV-?{uV4U#lbHPm1$;XG`1) zSMz*tT(ZZ+Wco5F#(Ppd8yxMmzXzeC{0^XEzqObiF3&G@Wo=c}Jp-1P+I`4fNoJ%|V4RQj=QOAL9G)z;ND z*Im_~@?q2TcSJ8`5cz2SZcUZHJypFn{b*}Xj$eMJ7h&gI6v|+Wv8k2rd0kC^Z4h48 zRyDLO7k?U3^{tI?+O>+koVSVB)Tg>z;8hzM9w5&ChK~tC%&!g*g65^aI~>6XO;glN zadv>_886~4F@PSLm;OdSjbKvip>>Z2h(+@=*kafEgBzGuXlSf&>M!6UJ&Lw1g_cKn z?9UHFTgJ5FF%6#=vmbI&S z!*c43BpjpL-Crm@lV!(te_4D`Q`XcoH+;+`rk(Fshqe|mepFV~W=!@SCl14l_HMaU zdK!M11lPwtQwLK&uovDwT<>p6d5@-prs+(7uYtX;1E@sG8V2@~YBb91ceS_G&t`X`Y$-YZy#F)20sSi|5mI%>(;l63-mWIc`&=#Yj#IU#+ReEHqE; zjjdJnsjd~xM|0EKX;b^l98y1^2V)t+G1XXCR3th@4ElgVS>JJmV*)WBaA_ZoXb_K^ zHKym5wyA^nytXEMF_bMcv8m`SLq6JuBd#H{%n$PYtk19;)_ zpZ@Pap86R`G4ZA6W}^ReN3PhYz!;#gZw1e>cz`?RB4ot1rwM zsNA*1Sbn{lrn)uugk85f)&0cuVsQEZ*=Kl5HPLreXafY+&trrcP=61pJ$|Yf9~dC2 zCZn+$z#AQ-<|e;?IV;ipsqTnow1(dSLR{V2c4c+dK!u5~s*erANL$*)v5*d9Nt z>Z($;?md21)~s!68R+U>y|SitEe{OLMGlli!{@->n0X#B+WLld456odzBCij-&4JD z?X9k7+Ge0q=-D0HRA0k14pPCJQygf>V~$}0~aI}tED03U{{aogUL^A zja7X=-E1>7e?4_|z}(ib2N57^#QJZz=@r+tq#AcK z6WKc~aBL5}#}5xi{f$qU{|Tepe5CC7|K}0rC8@x}k;w)22EH^6XDFEu%dN>R}x@ zD`>G`J-ko%@WiIyO?xb&sWGVdl?qr--N3RsbPa?Q4DNHN-ZrPU% zz&MPG&$sSNIxpmRuo8N2+n4NwVHkm~E&GxQ7=)gS_#JG6p4;~&yI=^$U;^eZBzUgmD;xuBQkedSLQjehr=3{j`04rb+ z`d|bGVFE^=`-kKQ^g$OR2O;Q%F&KbxxD~p7gdWfbyI~NPV2?2ZD`6aVLe~!TfL^!{ z24H?W{$K@+!#3#pG5G*}aE~|-U28}OEQikL$Oq_!TVW9H66ayJIR6vkU(0z|34^c` zM&S;afcv2HdCCKNpnDzqKpzalAdJBXbpMoap%0dg% z+yT8X3Ii|!!_a*V{-F=Leoi`}4@O`J#>IK)x|Z;MfgaEWYoQNrg(0{L#$Y#e?nIC4 z@CQB62mLSzLofoPFb)&Y^-J{Vz#sI%APm9~?1FI^gRYmj&c98%VF~oXN*IKlFameL z1l$MRzaqakl0UElhF}{E!yt^o2z2fuozMea-@!lh!VnC=C=A0G+yz}PlTPS`C7r|% zD`5n7!Z_RkU9X@A^uqk>@dqnl6t=+x?1G+OQ?H>PDx1&`mcux#g|1i0XXu5yU;uW* zAave9ywC&V&<|a&ka{f2uGxWhA48aJD!Z?gUC9JunEB?-33xhjCa7T^|rX^uk>*1QRd@-S?5s52@GC1A{OC zBQOl(Fa}*A{Ou)Qp$7(_ABJHF#$XIO@5kSt$yexse&~lG7=}?8g9+&T3-LdIKj?#g z7=$4hfnm4@#-Z{c>G+6rK`*R@J{W*O7={rTgK_BGhW~x&0lm-<126=`FbZQZ0iFBN z<015bKInyQ&J762#i4Y zLBfMx7>9nSJVLsl3x;61_5| z4-CM#_#T!#PP+erKj?vN&`!(=Z#w5;6n4W{#{Oi<5767WKUo2zFaTYd z`;$AMKWBeZc?LalIS-xr`;%Lt2kwA=xCaJc9C{0gZ#$o1B@9D9jKdK07w%8SU2+aQp`pqLNlUa&tIhTbK74+H1%yPuMOOZgu9;Vu~S5&jE=dl~70&dc{FgU}7TU;sv7 z6m|S6E)}`!Cx)q3PUgegLRZYjKT!;)uaE5=;Nn8Kp#|ojvmkj1F#$h zp%;c=Eeyi|jKHlh3d1l4cfkaVL2o1V^%wYW;&(6t1JKz*xI0M?^uhq_gs#^8$$ik@ z#`$03e+}Qm&|1<7UF%8bON0x3&<_JJ0(U^?2GRjtQ27=9UCdBu5QeLl;4p;%B z&E1B_YZUa4Zepy7>7X^eFQzBr;BvGNjbp)^gM=M;`8HNXS>O-CkPjM z;11}6QRs*JU=Su?2*;f_sPuCg2_zej9&(B)#tt9*n^t^uJ5IFa*0{7&`w%e6R$%{z$wq z@E-XGy)pcW^U(Po;lEFKF!mw&41*t&Z_x8s@-0UA&pWvVkr3m-9^NA zfb*~%x`uHcx<_yxdZBWV@Sqz;U4#RjBhf>Ah6(5ybs*_I#Ag_U2^fK%(c}~K!#Iq? z@{iHC_&~B2hQ=I7?tp=@#Pe6;9mjdW67mHm;0_o&fpq znf!s#Y54nubWEolpdVJk2=qhm4D^OExDWcu45kN6%s|Hbd22f8;CFZ97q z7=j@fgFB$>X5tkL5+97hk}t_GSOML)QjXAd8|i|6xKDiEg1@iO=MK^h<1h@}cj6C5 z?&A0VCLCA`op%#I3_e7@!5Hj@ahU%f^nHZ#fxa&46O2Aax}f`qq$9!aoe@XQJIr_rH zPV|NDUvj-bFH|fNw*3%d3Yp2{oVVF~m@4-CLc7=(V9fL+k{4(Sr-VZM#;VI}mvi$C%CPv{BV z?-8yYeV_}5W1JVC-zOaC{DAlcKP0~$_=hFX13l0SD`60}!N^|92PR;C8u{`U(gWQe zkv}j5!!QDOiSsZf&hJBC=!Yfgr1xX|L+@WHcNps?{tWW*3(5(G|A~IkmEe0P@yiF3 ze!=vE$v6x_B@=&z2a}c1GxT6`2MoYCjKY#E&KDg_24Dnkh5lg&lY3wcI%FA!~;Vx27|>1ljXU@1HFP{h)=NOU~(6Xz!;3e zZWx2kJn~~a`av)Bz$o;I?@JFRgD?OiFb?-Y-$e9ep4|^Sq5DMi5TD^5=$&*h>B=XZ zDdZFMmk~dVPd%8-FCc%Wp(l($Ka5T%eb6}r{h%M_7n0xQqyze4CydM_KcR0H`8||) zPeNblolQ8;JnP5gcYzlSaufL<7fozUM*eu~dfapC_e z^n#vN>V;rC-;X3;){rjfUx$7$zMk(#5#9#M3r1iCbX|=;&;x_e2fM_17=dxP2f6~3 zI}AY2Xu^kW(A7ctK<7sEC??-J(F4X|7`m_L_b>s=$MF3P=p}d)@xbV2^cqY3yP5Ma z3Vq^p5Pe_-c0tcA#4pZ6_c(Yj^%Hu(M>#-G7x@SMkD^}*@j)L9Jcd6QegZwA?+4V6 z@%V#o7}(Bv7=&A4>{-s2a()NjL)T9!f9Qt$VDJTgcLM&P54wMbo-hEz;&bF+G6AE| zGXecxB%fdihG7Ekf}Wp~9vFx2iNv>)_+SEVh0$N)Uwr>E;lVJ>KN0?k`UgGlQ?Agx zm;9SV{(r>xFtDHSq3;0Sy9xgg^$tej7e*XQI1^uT?BU+}v!^5dV>7wGwtdOMYTN>I)){9odQe#@bxG7W#w4V}`V zqz{JWL&>1{9_|p|TMs3pFaQ%U4&Bqq7gzzE3crIM*ap2Y2z{^%hF}Cn;2s!-ap+Qs ze+K?+hmw^r0lT0#?NHKH&iV91NiU2;KMZ6LF7!ALCBx7QcR?SFK|kz<0qC4bdSM9+ zK@W_=TIkF?l|S%_bfgokKh@4tK!>j6vsI(gnTHIT!!1 z1O}l8hF~QOLqCknBfnt+c8l*%rhMj6e@-F)VC;PKfPtmtvj=|{@;m5X#_yo#V&a+4 z?_eeLU&8O8=ThncO!$cRWPX1c>4HJH6^39K#^EmLzMS}>7dlTtZ&(7u&r~U~~obY60h~2p=Y@$#>|jC%;bR_plRsSE4WU!#ywxmD30Zx}awjdcq*|!*B!T z0|Qs!A4YCNpVQ&()LR&ZLFl}LaG?wCfo>RwG3cov{3r1T6R=D0*Q67=UqkOR(Cc;b z1BT%a=!$Y4dSL!S^no7e{4Mza{jgJf54)i2ZTv&`yZBqgdFY4EKcN?Ny+{3lK3H-l z>46^Te4lW{XSfGOU;-v!{$hUj0reF|pbz>!q`Y7VMqwE46X&6F7U_g8n1JQbwU_*d zZdeN=Fbv}`3VnY@Zy1L8-{SLM$PXC$i2Q`>mSrp=!XHAfIFb)GxUPaasQZCR9Bi;Ce&M(jd z`k`|P`43BA0(znApQKZKhC86|U&IUj(0Lx|fF;oXCGkVgSELVy;U4JzH|aZ{aA5_E zK_3hxsOQl2U-D@w;X@B}eoZ*g1^qArgW_|N^urj8!Z_Rq-IkA&32|QfIO(lK59o(( z+sCYvB)w3%fbXFT24Oi2K`)HKTIjNW%sNWW!(A`|ofq;u$Hz$z3_>3a!8Y+Z1Aj0A zW6Hl|jc8a@B(KIchJK2FDp|NMU4mE6z$+|T`df1Hm&-$~>{ zcqV>bN<26S<8Tc6&U#);h#aP11WrTG+2rRk$^(u=kN5~e*0SD}AB@m6COMqmu)VG8$tiul&@1y9T@!`>A)nMmhj(GUN8)sHewI@VHAd7K1(}<{u%NI(|^G3 z{rI&XdocbyjjLi}L9{hlP!lUF1`u@f5P3XZ9n1@N2_&4POqxA2k`G@q!0Zs#~zGAPaM0i zAU+KH@E_*k9E_fNfcy3E0|sCYhN1s7(uH9-2BRV2gCUrIBk93l+X3$9!_I$Ee;+2j^RW*TFb0!v!Veg~06QPS zuL~&$7=>dnypr;R3FsOp9q5NS7=r#)2ed&LfiVe(Ntl6C(6^d;fidX&DCxlvOu-1u z!x;4S;wOy2DHw$rn1HU25fA!c3I{-1`{v=lWR+{2ZPs9FCXVOjKT~YgZ}H$gLya&6F1=JC#a{J(1Uq6 z3Bxy&5153WPm=yE_zm;75+9~+JD_D@W|({>uzNe@2|ahvPhj+J^8G2oVIPdd@E^uu z68i3?J%5_;`zS}4+erCA|GTmG8OjHSg`<=U^o`*!^urtsLf1C@ggzLD0T_J`?FXje zBn)mMAM$$(_5WGYgCUrM5g7as>BA@-hyD+fFOkDMjKHSPQBE)beILai7=8#pU}P(P zexCSn5T@W5%)kWneGWe-(1QUOgMBa!qc8)A+T)gh3d8hH{qQd#HDq{u$*4bJLVV zl6b$uj&LvG(DQ5Te+~YIaG3aC?8ESHvHx|_-G@CG`90+Y(^>q4iCN-3OuRo34@O`V zrePfV_S0@*98SRu%m@$AE_UD#3_;I9>_a~s5jmWK@f_s`!-vStlnwtkaxfPFA{1b<*0PKzAoU>dr~_q48s_V z!Eu;_Q_%Nk$^)k7h&PEJFbs2W5awYFdj3K@=z~eJGcXM2U<7);O}=0&jKLs` z!#W$PB z^tTZXBQOV(&@)ATVJnRP7wN(VW>%5k-Q;&Q;V=bbFxgAE$k&h$7>BMO zp$~m9w)UVFgr0TOJB-6PO!iUV^7~@)^JDzGl=6dVI08MFV;A~i21Z~WMq$%WunYY# z4nr^vM_>+)!#qsFScG(7@+#Uz8a>ztlLNF1n7JCeFnA5&Pg9<-4+gKLzU4QZ77mi$ zGo*Jt`G!e24m~&EC-lP%jKVqS8^YdCu@6UJ@J8|t<1hu&Fb8wcvj_c~s81M%VVHzt zFb`8Obu;DpGt!AtPB03`Vfq&G2XnWQ5BYr??cnF=4^yu&4YM!<^Durpe*FSFcaRPY z!a*3l6MdM2S?GB?=}n^#gD?X}U=GHi?=H#*hG7cEVFpItNjW_W@1~q!22Q}#J(LSf zL(eY>--sO;g%dCZQ!sx&>HdoHemCjD*eH514kw^*6Xmp*-|xjAnEyEC55u3N-Te># z!7vPentFqYZRr0R{m(L9z|xZVH!?A|1RReAawl>f1nRWU;xHo7$)E#Ou`sU z!*Q5_NtlOI(DOLu0R3as&@HxU~NDqc!;`jIq(=&v_$Smp1qW3(0z+?{n zKVTmQVf2rb6O6$L`TZyI1LLr1Kl(5LGcXKOe@0(^!zA>~QJ*jj^Dqs=&(kj8AWZxP zf1vNL$RDE43;W?<~^qM%;R?seHel9e=#1w zG@OJPn3iyug|UB=|3iesF!X8Ig?=~&!!QB!FatfD;Lk}oY&uLh48SPtgK;VS`>PY%W_m%~2v{Rue?!mt~Cn1C_)?a67AFa@(P_!9E-XTo6s=3$@E zOZw2?Ncu4TQtZu<&PmvV85oD*mtjxjFb(}pr2iMn_hj-1^DqTH&6EcWzAC4+{uO&L z41=d&2S#BMCSY2ApGtZC4L@NR`cEUjFb)$i{F6 zk)OZAGl>TiXAuu(&L%(qpuGIVgYk1n7Y5&m|NkT$j=;ouIqrAE{{ZEb$IkiaL*E7H z!xZ%Yi+24M7>KW!?Q=OyE*G2j;2tzOeBQOR>Uq&56}napdWfpBpn!n85n^%I0B>hq6bsZ(}>=E_zxo+Ne5=` zryUB%kiQhZhkU{KCh7|&VHT!g9tJm)&Pn7Oj=<>q7++u$Rj02Vs66;n4qk%KvrL$Mck9E5GN^hiMo%o%;9-c473dlp~D&jc}OBQ!Zx^ z{x8CzACAE!oP=qZh8dWJ(SMVFk!$4h_1LL9q>aE7jKgsKAuS_x9MS@dC@&a>X*dWo zCm+(9&Ln@$gu@gZfw5N}($X*qvoQCnLz@3A{5j>27J`ve4`~S)hm$Y|)6n-i?4M2i z(+_Fm(0}G3Ef140>?fT!q7UQek={Af^ZEDz(-$Cz@%BSn4o2UMUvD5B`e6o!VEjVt z!Zb`mU+|DN1(VATX~8$5*NOiy)pbalfU%xKnx~C$=!d?QghM}!!yuf15txEeI1OVk zC%;!6;yyR(b?qT727T*D9|mC(hWid_bI^Y&{+-M3%g7H*4PXyOuOt2Q@C&xW==Jz1 zyx|b{t&zW>L)sWj!UT-pNI3|H4{;wGc5kPgVERtVPkxVJA4cIAjEv(ijKLgCLD%`D z2YoOP12FP&^kEz(U;<9U*jK3^n1oGlLjE=Ug1)blU+8(5e84Eo$?qN5y8!)fU=Jp~ zg&amFNv|C_48Z)iNe6nqLpm_{2^!7JU=mKi9GrsD@6z5Rd>3{u#BUge zc^HGq$MFXSpCDbB`XS}{7V-=GU>-)He>eWY2u#2joP-ZzDczg^8cz7fiw^j8CH{ayTt= zn1ea!xd=PY(oSIt4#GSf6ZtRk2j*Z#e*cPg2gA_UfxX{hANu|eyU?G-&&Bu;!!Q9y zU>e3@d=@+M8|GmS`j#O71OCD^jKK^XhyMN44~)Vbj6v5@{D(f6d7k=&IXD9IFb+Kj zs9)%VDfxYne1@nO*a~AX1T%0%i>a9Vgg;VVe*gu~h(OnMG$X&CVy z)_h^=wehev24g3o593YfuSD;4hqVzHYdx%Gg{L3ZnpP3-4AOy77=d{hhl$r8)-o^$ zJ*z4IMc9E+7=&pUg}yVhX`LGsPL%OgJ#$XgC z;1~>Fh#i=MSqXp3VJ#1H(6^R&Z$%G!E+T)>2Xin5!|TxNIIJaLY%%2m{Y$U|qc9JX zu&EFE(!-h`CSeSw;W&(hNFPRF2FBnVOv0v%u@3{#w+#Pbtn;uoDe`XoTaW)2lOO0? zf0+0GVfPZ!mEZl8-z9`!N<86Z)GLf#j(^a9HU9Ub52G*x$6#_0yO$FGI_e3AVMKmk zkA2|{hc(w_=)o`y4pAR4b|d8iGqCA$?B78?VGxeP%$@iJWA7$jg!0@%xk3Mj$Ttka zIhca}D@fv%xq#VY{A54A}KcMd+?7%4WUxodx*nx2vhv83< z9!x;j0QNpf`NAaZgON{BPVyV3q3?5)$JLY*9E7RQAJ&r4{{`}S4ZmRw`oD-ACSV5U zVbisw`z7qc#Fr^Qn1@-I`YPoxNI4{l5B)G9zrRj;*YO($Vf10*!Q2ky*JI}!#Dgg~ z2$SC=K8$^f@`3S5@-N}A=?47%Hu;A+7=!WeP<|qZo+0GWFMNb{0P}DR#&?n*nD`#{ zpyyH2yAe4YgE=?_V~^3!ZlZo*5TA=Jfk>89QMqmbxK+kUUU;<9SBuv2+ zoQAOIp|MQ9=A|mFaU#3(@tO-PQg6Pi2NDq`Bvh=5RCs6d(g87 zdoTxEZ$tlQ#D|%m6CXx@K{_xpP5BIyJ`BU;v(ytz!Aa=(C3-Ld{kNkB`(Osfg%Oy8zPcB*zPqru@C9uGX5f_k_Pn5Z-a-7Ayuf?wNZ0#<7K1@J z4#OwDpe11hPQfV5zzl5N;HYb=Gd}h2T3c7Yp|SoH&v6Y~>W^y_xsSg)Z``AurE~<= z`gL`!go*y{fj!!h!^XOcUiFr<&TD-w(z*bDA^vt;kku{|!4hxd z1CAx$=D2gIw`G%Sv3Jqvf|cIhd%cSmds`NJn+adyZQ%ToXFU1aOT7D4ybnse2c02r z%LA?@-bL{RA#dBJg^RuIqsR4nx70f>@wPAawqbFJw*^gQNh0&SC4XuDn%lG5^&%kj zL9zFM*o%uFo5bGe!j;|u$5P!44i(Kv9z6ARb=}0jUBy49Kf{hLD|h_F?ZeJS>|Cqt z#2w^&la$A(tH;~xSfv-lV!a@w{KnAVg?=sNC;3egZ~uRoUy0B0UtRN?|FiNEzk?3S zi}cdI@h?NXoi)Z2|C*e2b^C1kC+#ML ze%*yx?G7OMd69P0Jzu+tW2YTEcFIMsfAss&|4-VxUjM}3{QnU@=%RdW#P7A}Z<2nD z`1}9E_)@ zh_|!G{7JlN;_a(3J!$uzg>`ie!L0UXzSl84ZIW?o)Y;{2=|92Sj9{_1VVPS3jd>%8 zelz+FhDiTcAODayB7c)e%>K=AJLbkj<| z%|d_3LO-wc_4%;E{xuf*e&#{R?>QFsudC3Pd_|OgA+Him{2W0p<#VnGD$>2F!j9-q zpfBZPr#wY}8vV8!?7MKV1N}Ex_;bC5KLMpLX;u0^XrVt?qyD(km$qDKKWbrr3jJRE zztBSe4h#J`^as$lTkoyM+t-(R?^F6DQ~XF-MUnTD?th82qTX+`@H2t_5c=m^=-*vrN#X+4TO zfP6=VT-;O_0Zc(LQTAt$P z81g;Xu{&;0Dt)`-VHW*;HvJ6XPt!{b{Z77D_S5UUi`YE$6=rK=5s#YWBTT%bq$A%e z<5`W1u^RQ0HR@+-)c1G||Lu-XLG&Bmn$_&i&rzj+mPPqk&9@1qZ?`|({L&)nW2WdN%^=>s^jiBF%zFj{jl)l|^o32sc)oA!**M6V|eJQs= zrC(WYG33&I?2b=K^qXtY&!E4k27S*<*?-lbA4I>q2K^}d{pj1R_k_~7JIO5d*i6#AR7Z&yEu{#NwQwea6+-R*lB^Evu< z%Rh|%&Km5;(BF-|-TF$_sGm{#cI($eXBB_!uA_tK@2x>UivIo@$|r&T(HivA=r_F0 ze*NarZ$|$di}p~tpOZPr|8o2Kn68T`{mOA~1bL%PKLgmAK)(h3H5PuZ)z>2{z3r>L z9m~Bfs|(u#@i#-fZsJ{F5%0EwqJ;4ge?6~Yd_up{-&W+k$nBO>pVGI}?j+qYrC*tD z0=f9#CJt8Ym#p^lX{B!`T`8Zu(tneM{mOF+z5Y)&%ExXwM3lb7t@Ph&Js7W1KUIUi zlygq$SC+G@*{EN;eg>5O`4;)I+LsQZKR`X&9aqNDAFe@v3jK}f+pWhr^taTY-}=hB zx^3v&oj3Z>-+}%a7UgqgMZc3WAFDxM>Ty!(d&Iu_h@CX@?WAj`{fnKv(ywd}O|LTY zYqvdwl)l~kjwpS*?PmggDbGcc*NSmqz@j{-mHvem`c~&bu2Z=FQbYX)(BEUToTUs0 zmA>71eq8C>ZEsWP@53LvLU{u)zJRYZ$#ftJCyPnt5JVa>D%q^S@c`* z$8PyIooeXYX+P4BLg=?)zp@`ikT0sC9O6pfZoX3Jx7T1lr}XXiYu{;xeY@>2jD9!% z*wL4Ai=p3dQEubNdy(6n_otNpdDyHRA8xi7ALh^>z`ot~(E94y^!t>)?e?$q?bgd= zjrOxO>Nm9*`L(;R3ZXw-LwSxUeY@o|q4e#vt56-+KhWQZKM}rHwud#|MQglmte2O1 zJC=I87khh`di$4p2TIq@5>48t?=|cfu~XTv1IV`^w=+KI<3IY_(6{5i=#QhnqXzvc z^mo33Q9bNw;Sspp8-hF^C2pOjx~tD#?6 zenI4mZ01kwM3sJ}oiXGs*sfTo#u!?cH4Uh{a*C#jt3*?51?*pN$ z!#2xb?6x<>uH(wDR<=X0y` zIse&)|8KU?zujv7NB=1KwPRoUbzJF}mU9641o9);>9k1qSl6R7#A{e=zx{e}RP;;J z7vEduADebWwXa6~u^RO!mA>6|SQh<8{HMCB>e=eLa}x_o(YHIUgwSuXSw2$FBTB!r zoa4xwZQ79{NGW~0`O4L(?_=N-f9%>1*Qg(>L0`%(sq`z$Z3=lU^)-jS-TIPpZhfPn zZ?`@4q2ETiNnAVQ%9zr}ttx%1`xYi^)X&!FPZI|(;=kSXR0#bJ^zDv|Bk1>{Z#Taa zO5g6hJ&pcA4dw45qoQwjJPDvbjJ{oe2GQSGgFoXn>Q5_;9N_y+uB zn5b%pR@Xy=HR?xe)K4gVQ00%+_4+i5oAKYSejdfG=-X|#ehwJ7qi?s~Bk1p}!Jjz# zyV1A1j!U7x7kxYZNa{VO^egM#6=3~nGhbpSfc`%8EA51l+x17r##oK|Nu_VMeP)!t zoqi$yc-VN<;(t)-+ih=A^!HP4cJ&kJA4T8pJd#%WcG`p3%qxAn<>RN}i$8Y#kD%YM z#J>OW8ue33A5@JGR@d)yC^qAdUH^R-aK2T8ei;3BoB3_R<(Seh?MEUXN8W}Vx8zHG zXv%d-< zKH^&lx%3yi^*)0BKn?XiQKSB}(zjb~uAt$M-Es@ms6VLm?T)+S=nqpqcH7Am`Ww-= zYkv;?Ej8%3zLo2D=-ZuV`q1BD)4sH;G4yw#|I$LEf+9~K-)$kEM7{_4aTWS$rC%zS zHjq{J?XH`e*a(R~cJ)Iw>W|c@KcV#Pw$Ev$Pxr1GH!AP{k#crjWRz#+eB?tejzpYDIk5is@^V_HN?Y4)p8tqRieY@+8EczYz zZ&$x5#CoO%{Sf*C=-VyN5%h=Ax7*$(l)hd6r_tYteY@?!wan1B>rX)G+ieenHR_Km zeLL+ZK>wOj`rUl5TqpBvKtE9Qx}m2$E>uK2kCwH6VeY@ootI>W^>Dz6m8KrNx-*{+1yD3k*^LemF{b-H)38inhJ*3g! zi~n}ZC$IGFwjcj;!@gbph|;&~PrL^EvVKV^{RZjx>Lb2QBi}6g~K$VZS%`>d45k<0kwmikg3(VsxR3;Br!AryHExs3lOSIDR5(a$OU zN;|HV?AI;q`;g0gSE(OBz76?F73qeRex-a++2>fM_-W-^47s%bRU!>}8#l;3BrUx8 zY>Brmtlp5L=O4YgP*(GZp8DwdM}Cy}g9RZJ`84ug^j}dS&mr%(kh^eTz(VdrK7_n9 z|2}L6l>R}n-{sv_@AyCEt&x5o;cd&xOFA#g`Bl-#C&BzxPgiz#@ z$Qvu<;#V4Z1M)LOpEom%@`|>Wi2m9l{atoBW$#BSy!d`2{(lOI?^#XzBmS+$_$$0E zjse|(r0XZVxl^43t?)KpPp&0i2zdu`sZ%4}D~shJ;e&+t5`KCy{MuqTOVzqD!UqU{ zr-U<3srQF1vv?2QYF;0=+Uosbdj7Gq6+0|*q&>A}w99I=z2&EDTpb|#EyDO`07kzWQ#r~+P z%X`G(_-N^y-9*WF$KV+8b`kF!5zr6T;&+eR=mAph6NK*}{G}4EJ|a&c-;2Do-O$DB zrj`Dc_53i)6F;inE4bFX#pyh={sgNc)pI8KYF)$p*qznHw%Ake@4}w>e#6@eZv-J+ z-fkuJ5h31D;$0%~^!6AfXT}?}q_jil=wngJTjXC0PCcfT2h_Bwer@xnreZqRHeS)6-K z2=R6kuX3CpLB6X(F69wNz7zS`Du1Q^U2AcFT}tWOIhPfGa>^f;1;vlllWQIS^r+{g z^?H(?v&_AodX#c+CA@|3k4da$#d6czwWE)ouvD+}W$r*D{<#vr zQ^uvMo-A}U8N0^_-$wXL%iF6}|6l3taBQ8YwO)z5v+DhrON{|Q@{uE*{uNp6+v0~= zk7hgO{g{r+Pw*~6Qfxb2W_*7i{f+n=Rs07X-SU1--o~lkugTjvM;AIGhJ_`CH*|)? zf}|fMesegheM!Zy>PJ1^jrEQ(qSGXc4j37b_K_t1X5znF;+x}9m$&0x#o=g$;clIj zYX<%O=<|Bo(s975Tzk9&PM`HK(Cv0?n!jXaEDc@E{h6z>+Bn~(TvfZ(+lLe>O+>PT z$Fz)P?y{fV%3r7HYx9& z)mLZgy|YW)4CZZ1%Z1EZ*zJ>na$Q#Azb}08cDKdh`1CRIE%}!hCjzxugJ9TT-cW8D`REViADfXi11y6KO*5~|5xw(?Qq;y-v32Qj~63e_mx>~u?Vcj;~sC@ zI`5*DC4-?}{*%NTAl_=H5l@vr<4x82rpLR@vCgvedyIic#%0%K*t$qjIYJS;cO_xj_b62F8jvIqO5Al=nFHh6l6S>-lb!x6%Hj zyd`{+@Qs9@Sqx{Lf0f?Jjr|YdTL>>*7s@!DL%tdLGZK&Tw(jqp-hnmM-Ca$idisIO z>0j4b``3i&KEhiF*Z1L)79VMMQRMB&FA#y*PV{-=nqoIL`k~ZI0{w3E?^gO%{kX^5 zfvaWHb*Y~j;%`2NpLxQ!60WaHBn>`NPE8ToGx9%(VBT`-@(wVQRSt`)S?J{y!Oqb2 z^OsYM@C}5QrZ4?z9Qiinw@LcuJkPwwh_Bv5+vQ$eoNi=}lXjRU-d^Ip8U*iD2ay zeL?xv<2~YZ`mD!Gy?=;bli2Hhr)ozbZ|@!S3u#|z*V z`Oj!yQqFnw_o831p5pmvhq-|0bgwK->teQ*zrdBu5ARa@A$@$M|J`CFqlOh-FM?h_ zdJjoNU2l!IWrLwtx-J<*Zx4E<{Z;arK)xIKDH30Oq=7 zZpp{LdF%|`%{VF&df`1x5{32~MC7}Q`X~I{`NqZNB=Jt`aZ&t_Nc>p&d6tyl2=Xn+ zKfw38HL@R&db*WrDsBt(@=Kt16g`e}OZx%4yn71WKwno+q1SRxRy!bil!qE8%=hoF z_U>>xZp6{jO`);!ly=}6p!|vdn2KLIANF|n)Jq;)iVN5!`otmaEl9lnd)0c(?5DlV z7A(qCM>VEpeO!s6zZLyIs&uOQr`ZpBy~B>DtTyFRu9Mj5y|4WK7pbo_@^0iK<@Lon zskl!cb|fq6%jgbzd3&y=|86wr6?HyD<^p>i0RC(#^G1*9*Szl6I z=*vgSD@wfW_h+?>C7xMcAlU+o`EMJXBl@!CNv6D~IHFB+ zQu{Pp+-Gp;r?R;0^)@{DRQl;>eu^<;K8jpR|J{_;>dWiTYX8aqkm0z*ayl})n?AoK zvA6TRS#95mBw)4&)1K+?O7E_E=SN(Y7MDv0j`EksUiU+sw}^kMi}|;1UjvRmh_!jL zACgwa5u#<;VBOgN57IuiX0=CEc~p&4^aNIVWxEn%lrqkJlf>Wr@vQb*F{nOaIE8#0 za(TaYNx4|%qtiPq%i-$XL*c+i+C>uwY`Z>})s8Q(H!FM6%0Fva%3bc5RXWlSMzBBp z`Kz?!s)J* z*BtTo5bw_t&#E1np6?{*GZcQ``com|)0<+!xGqlgVYlKwPycVPEI5s)$m zyPe+lZf{4(+f9Sj)0cLTM{hTJQnr@q^Izo*dxyf_;pN^9i#eMMc{kU0@jvmbuTDCF ziSQ8p`^#DF&;rAr8c)rBW45avtT?ZkuOT=?)+^v1x8pa|Y4suJVz=z@rBQJpLwd!t z$3nN(`%w=6`oCVi&UD?#dcs2PL*8v64H2<<_#HdgmzCsyQu2?y9eMc0$BmV8GWO zqt9-y@1g&$C$QVHuZQH2&SJFZOm_vwmRT6PSlanK##FrpZf5-aMtOM$2n!?Mi=4}> zdVeZiN2?2F`T=msGNw-En=#@YA>K9>uWB9B$qKP@VqE49SFCJ8ZVI7niBId7exAjC z+c&e?lJa&?an9+u-KfH1-|2EY-diOSdx0qSzQw-8PQCRy-fdZ$YNLgzx-qf$?W~qj z`9H?KK*kM6AN9Y6`oA15Mz9_(;rAu#H-laE^dh$Ti2rk>w~h4fnr|NAxLxhXrQJEt zwjQVSu|@iE=oZ?;chvbH>&Uh0oGOBRKXSca>hr{d(&J4MukI0b&R{d1_?aVKGx3fWL+T^*nTreFjmS?IneHb`Q7&Pvz}q0A zR>E5d-y`AXJZ1KOuE03HO;bTq901hFJ4lp4;_o2-kPM9Gdc&L-%ylb+kz=Q2d+ByN zU+pA>v8H0-pr<5$rb%b#V_B`Ie4H}p)3xje4p#W7_J0!Ja~t#FE_EJY=F^PNYKV&* zW!WsOPea5H6Mrx9?q+V_iM#>1 zM-m>3Hvq08nbm$P0_weV+;)7>$O!|tK4OXe0Qx)7 zXZfVk=lpBPIM?cOv-UPRu7v9A<3aR~pnsZNcsq9c?_wCc!?OJ^bvr+7Jr3zDxE0fB z(%Jr_tj4rz`bC2kcM9ji0fOelAM`E}y^8#DJSP=Lc01|+>MLqe?tTii`N!&hTfN*l z0B%^Jj}uZ~VZs*?&bG4nk@6Zuz7csuq{K7#DeB@C{^^@if<=EE{T=9sMgJK7NwDN+ z3jICka|~9cA1mgkrz$^r;vFU4N{OfE2Y)E32#ra~)5nFxML$vhzZ~so)N$PjoX{Hvjl8*XF`WdDFdXeer(>8HmuA_*(JmHeQSHjgt_=S&&>X!Uw@Pv##k1b6{FT&(zo)&+d#Z? zoJPK@_G{+6+{O8qOj;JxuTdi*OoZ7G_wUJSpW?feqxJQ*Fdng(t-N%u8iKT!aqR5C z&I++Zdr|FRwYTjZg=V0y<5KADMemjKt>a4fn|m7OImj^lZz3trI~YHIRz8pRA#X*# z4f(YAW0o(I_o$1#sNC?R!wjkE`6&d1hCH{3UUOv6veT|Mgz55$i zdXF?-2Nxr-zHn?bd?}aU2FmLf=Jm;AtlN9Ny_b6Xmv{%dyhEH-_j`NSS})RN+#1L3 z9_+qM@@<@-6mEyr=Z8rZ-fx6Aa%F>28%17xaIszjp~7-NKWE9JUpKAptD*kv`+3PR z{R~nui?BPNpAi+VkC)sf!zjj`DqY^@)!vqM6@Er=F^+ye_V!7>j_oIB@eTKQ_cnBT z_cdGs7xSBoqZZw>>X{!8-n;_1uvs6C`_b@X%}^6CTSW!x@fIK)AN z>{8i$kfyZnk-J$h{7U`5X?nk>ORM`A^!88q@I2v7#GfR5BjKm=U9MZKQuBEl`DWy$ z>vYl2&ZD27N56^6v9j++Ze>3-kAB2LKZrjgN`Kz_lVk_+S?0Ua%av-M<|F{gBS*filg2ru3DNc+tp-;Vs@`Rd!8??N0aIhUI2ZT5i0jha4&%X%ev z5B=fSS?ylF8{>CBo^-k8-){Bq6>21sdWfRmkA7wSj3MtuuCGJoN?y0OLG%;IHzO}y zpGmrt$TuRtfbWuSah=q{&6{doP}97=Zp)&-1$}*8WzJvZY1BohQj2^kLG=~0QeHkX zwv~8HBcc4co(Cc`@ za=cOFsjPQ`_p$!OUS6d?-+0QA)!wQBRpRjR@i&H@Z5i&r5&`$+%PL)MoAq`21mU{~ zm$gyh6X#0``CjC!Jp4HJe9`0G<#cvBy}O;uynCEs?_TcO-RJBT>1ht6OORfyq$@-^ zBD!mlESf4Q_nSz2iW1)Zd{+Cnn;)jX z<~dMl`R{W%d#zK`o3_|XVQ=>wy&-YYFVGqSNV#vF;2yZ*Fd~;bcykgwD)o3Eyzpv zDI!lIUxeIMp+BYcEB8Se-S-@cqr{ZT(;V@ zKtC^Y#El`QIQ}lz&$&xSWcCiyAJgLhQLdjl_(A(BwZ~!GrUi`eqYLGT@t4)dZ|ZTreMs{ctj#);qk@2vJ7iBEe_ z`Q|!>iqD|Vo}}zLQ@4AhLSj4tAoZ2O-e&B*M(nAN$mfu6L;jM25Q^MG!dolklCM_e zTaaHW`epO2?7fWJ-@D~+>?N?*?wZk(vS1>gRsG7e*X7;laD3IW z+>Du2?B%ex^(8aK=hGhKT6)>@E5>-kc3w)ZINo%-7b9UUT9jbYhrQr?S$|;fEWXP* z^Qhy};thO$L=nOpyfemqdHQ|koDytu>gyB7Ps&G7u@^^wH~JqJd;0vzO_gf?Y(80 zWhKpSLRN#FZj$B}UOAaIKBAvOzxh=&+BG7g8<(zEu9W$@FhjFrk#fqR-;e%&(bwzE z@dMo~KPBAre%2SK%oz7q>EQ##^rSxhgtrrZvNRyt`v>I#r3YC}R^R8pR-XIFJLr(r zJ7azSB=s4?Uc+n3+n3~P9C;n`t3b(k%O=@DPgJX@lJmkT^xM$it@KA74z?v6bj$Kn zwZ{NqIrR3T*IRD4hlhlVWA_T~<5S0JqNSgswSIv00PzlsfN`j*e)V;Q<8!o*(p5>w zeFc)zktD-UQ(tgdZp2>LcnuM!Q7>*#{hg@&3R`WOO9J$V1I@EB76UPc=Cn9=3lKf6#Z{Um><9cUVe$8{@ z6>j5=xTX7#y!cN%u~GO8@}=oP&R>y#qP#s>-DldxlVm;C%}HMo&DZ_)dXJG#!=f4O z)snbg@8VU2f;O5>h=9vC{Bk+Vw%|<1F&acS)yo z94%bQ<}gBU;8Ior^n1@{oRso0%X=NYbbE1pTI^;FQX>iTL@TOM;&uCHjPn#dzdS-2 zGp0?oeAnB}IC|UAlj*ha5kHg2w<7<82z5WXH)NBOaf0UnQ%1`Ap$Wm#ZZqijpEFan zUz|hUi@emn=zF%{Uxi%Sc`Nb`yG8mV$lH)hS#rML zaU0eme2pU)e;dRxv%VR3s-7cT%LwFrq~5!m8#(uIkd=XWXqdhqSYNrK)yUMtjI%zdcaC zE|hlZ`Y`p2{B7ch*`B$Y!dr`t?Tx<9@uSy|-bM4RbLe5C3s-u#-S2WXP!pAx_~gh$ z>U;z{z30yq-%nJvzvZ<5it@=tKfg;#`o#Ob_(}V)h&SxGzhabJ%tf)XVN)WrSK%*@ zz1`T0ionVq4|A}pEt}=K-8_+5x+;{oe1iOiKf?YOd$N2Hd)D>GqXdo{s}_OM4&%gc zf0JsT#4jC(h;^Ah`%^#kalJjKl>T{=p880?n?^o>o!1wHFvMRD`3B^AJI8+2ev0;0 zyzi}pjbS?r2UaW$xW%oH_!$^yKE%#-V&7~pTqAxvgOJf+3Jp)nc@X_0=wCSBd}5~C z%l$8U+p$Pm-^hu*N$l;rU`E?3>6_(5t&F<3znSYXEi99af?De41up%|yaQZ*RImxm+)#4$M>q2 z`^EusfT%I-Y=85N_LQ=t>RZo8pS&;S3nkZ;MTbw6ze(bCTsWisLX8v0s7JY5+p(Yf zBD*NqAt<-JIv%y$C@*ubQi>bYjg+J{$Y1NnsPEv6=6mt^4_dcDvq`#XzP7IJepw1r$> zZ5iWq;33N6q8aTi^QB|9XL){Nm!-Xs`|aNL6;=H!PCmx5zolbFd&tEPv!7bcgO_kZ z?|inNGx`C}==&j8f}M_pWs-~8+w5h#w$FJrlp}vfQVFh9f?@T00E#7joN3+4dL%Ss zJZBR1Hm+0SPZ0TD3wa;%#%1ODQom8;-N^6fd);Nlb@_U4%iZ)cb&$wzY}C0)PG$<{ zjH0d28%g4CEyUNK6Qi3K&QmxTl%C4i*zGoM0+3 zcn&r}IxVYMFO{#0%ydfkcN-nfZ_2*Adg#_qxW(@|>@}{NDc;Yo#t+k;>9?$_Wl?Kk zj^}lFHqW9z>*I7Q=|osiH}uU^-uKtbI+>dwjA2#A^D*=~(EEFNe=_$Qravp$Z=7nq zm^a2%X=l^eJ907W9A&R+ozN?}`bx#jE~^v9I{unCz}~ZdMq4KWb3VZDdkb#s<6;oK zhD#WSMbGS~*5x=LM?V(DxWdih!+fP^j5iacvypV>RDP`26)c*Z$H}Uz;*6ow?f7Q( zTFf{VHP%6{1nuk68STHz%b)dM)w+8%t8M2gQUTTNOCKR+e(J;Cw#!&2N_*v8>X`G> zu;XIyhGkSpuiP#%?3na!kVZEsPaF+9J|!tVNuDeoxzy*4CX$#Uz2U3WxsE)M$BpYg zPH)!uy$XVSWVhuqH1F7JMa;{&W6 zF6RsPa5==^EcScvo6+jZ>(|=fZS{_4t!fuL@(J-5_%#1)oYB540&_gYUv>SV*E?{p zcZj~a&O5Z&J8)C^&?>R?aXE&aA?yr@06V4YU3sxkVK^^+m%Iy5#ILTjK=nYA8b$M z+|_VTk3UHGj(NhR|Beyf_Q4tBJ%jv~kH{0-=)cHM5`p@Nd~zH1kT(~EP~>UkJCRE< z6h0!)ZZq^{`C9mhJipDb|FVJ*N`9I?Yv}9yd%b!_v+E7ovLx2akq56D|a6JsCrmuW5YEI+3%O0 zFso8G$|HmQh7XtT_a)zR$Qvu<;=ku}oX;Y^kMHIFJC>0FPW)N;sCBT+lR@-{(0`}W zAC*VQXc+7Qi_aTKc@Cnt3%%DA^~%qW#t7d-_**4heZaEtbF1pn*ArueZzO!=gfjoF#%~@3cRC}ok*HpO=|v^&VH$fo zzF2x)f=!D`P{QX3-$%HWKhj>BzDR#0{0FK%TaQcnI=t+HmpCAG(?|T??W(=qRov$> z4)SPIaih0F?pE(oyFR@f;>6ocyqo50XXZXfZsPfZWhs=r-y?&){a=~UE|rzNRl6|l zt&sNxJi_z;w{VQSLcIsTStknv>w1r1GWaFze|tu|%*Btpi|bsoUzqmgxz+2bw0V}Y zO9>u5Zqvf}f(Kj=IzLGMWgJL|{qI)opSXLRE~4g>((49k^qap|J}*hX$s+GSeiq*g zAE~E2@_yv{_|1M?t-tj9z37L$4ygr)i&v5LErYb500YT3;$0-hZj|=Cy11^E^!fv}la1bH#oh$*I=)|iT~7Q+A#X>1lcb^F zf8n^K;E2>uhVadVXC$0`NYy@2-fPENrRq$+)7{5NSaDF#YjsB#Y;wh&4@mQj@fTzP z+>qjWO!>HPRsXbC=Smqxs@HML<%OUY-I=TXmaWei5%v6&{)Qi@>t~GGbTD2*BbhbY zPez67_ebjE4#S`0HvRVaPJLz0-T7)x93hT}1JDhR&KUQ{QeM{kOewSpS&uwP89l|( zaGEO|Pg7mb$Q=r@Cb0?$72l7;!%U+KH!X;}9&kSBFvdU9ZF_7+J9oZ*U%GxB*5Afj zJ^HB)t+bbE?6o{TW4uRL3WJZxbI99~zgz?yQ%hk_dH@a!XRO6#S8k9?fch6KlFUDFVR=6CYpX=n%Ykv_vX(vrzV?BZ16_URC zNIUQ&-;TUXWP15>1B~i#5-&{nUcx&iTzw?oAo9i^ndeE|pR%S9PwHcg@Ls|z&XcXy zFUNXMl=MoA@x|yEdiy7xML(V~-jA#N3qjY{S)U;PvB=E!rq>f2+Lk+IA}F-CW$wGJ z>P_+)#!mB3X0$%B!*gt-j{d@MtoO4h;r)caR>Jl250`kZC^m5Z?!rKQ*Z!_-$=?VA`U@%G$U@$Syrn`eq>L>p{8Ct@J(T z3|_qFTz8 zK&)oK%Pm{F-f+aP9O*YqSI>*CZ&F{#W&2e4NV)rvHzU8ge0^iKTXS9(f4^kul{zob z>mPgV&(0LzPg)$;J2)CwRlY*MZN{j6S=&l`o*>>9;!TNj=J=#vCzVrmiOOQJcz@0` z`fa~7ug{kDQyC{UF6WbXIO@oSY_PyLQ%!E&y@*s2*wqQ*KRLppm&=Pe?j zj8u7ZAEmljMt2L#P5i~)X7snFN%n`td+x>SUG`z$$Gz%ht-1j~%3~0F!~dhkE7D^A z>tJZnKdt;bM))?uuN8^uC+A??gP`swka|d>w;#Qiik|w2dk3Ymfv!}hAMB>UiI~!bgW;L&c7x1eWr-F`8n2cCt$>!2hH)s?4LaU<#0ZGoMl7O z7YNedJ>Oxy_WX=?gzsWctz*fjI@jk3e8<;izof4R(4f~XX1XgANMxoR{vy~LI>7S) zBCzt$Z0FLB9<^#l(qAU9Q+JSk-hz4TnE90Z9h^PZ+xEq7=Px9r`sjxekb3rT!)U`1 z+TlWe@I0#eVZ&XS9DF_oDfb{h~{pt?pRd3EDkR zJvvX3C{{CrvHv0ct^X?DM@zlCcGCWkJ3aIGW!97aRKjEP_(g2J9Q&}>d;F~N{E*p> z7~fPo;&9>Wiv1AJ?^iUeko#tRgT(k`v@|iVufry>zY+Tvih!`v@twm*HN3AZJx0*u z<%qYLc#`Lmafb1bJMGnTdVMk;GG@zKQ$BtCwSJfJiFnf@AU*4SF_*jKWkHoUy@j}| zrt*{?Gfn)(u)FAl*|PV!$e1*ayahSS_0oQ5mLID`{eM|0?T01jtJB2aLj0)2H^);- zz3?_&a;Lu*)Xb=iL!R%^|B3exiC0msYl+Mnx23obPzO(vj}Y;;xM!>G&yFD9Tp{

    wchg%0_$-ED}40=1!o8|lb?N)|f?h}`FX6b5{{XI7{SN#7bM!OB9NdLsyvUQTw zYZ!Sy@;^y>J;n8gTu=EC^LXK?S3>pqA%^~<##yaSo!gi8V;(ki{)Ba|+2A_eJR@%Y zRM$(S{Y_zK-$}D&&-;r!gM6=rd=B{@>#1KL0Gr6OeiT6nKQEAqOR&6eHA z??V(s-hliaqOY%O*0SBaMjt$+JR*b-5gt+D#r1C6wY2i$Ed>&)uS??SZ$)1}U#RGR za`HhEOt{8_e9{h5=XALc5JkFw5*EFl$ruH4y;};KSIv=OR zD;vTxH%n|@U0c>VROuV-A@nHg*;mY#{Xc=?Uj+Gvul&>)r_FZCICguXnd9 zXElcBs&PkN;#)c(NV!j*xiQRx6d~|n&XZ94_l@0wO|Y_-rB2=kW#))yXYUMsCGzg zakYW#xyJcnfbam}b-r2S9N(;09&oGYm{ZD;`DK~B07Er$hH{A)C0;l2jw@g1lESEq zR}s`Zwv={oV*?@aCWzN^>a5nmcd74UKWdRTMHu~PvHSAESJBeb%j}~5h&Lbt#v?Vp z==;V?yu)v2G%2~fAxcKPrpFoIh^NoL70=bNkgnHX_*5E|!$|QnOuXI1E1VB1KY2b* zE^g34DVF8>8*z*xl0G^}yfNbKlXy}tT!*plpEBuxo)OvNjAN;Hz&uiS6kbH%T`FzD zbWZ#`ZPxhzIQT6e@!RzT`F-`Q_TM6?=r0Z#s&JQqX9YL>6~62JHb}hv#Cx^)T~;sL z!d-aIN^J6p@fSsZZ_BLaQsezG=0&*=Tz^i!dNJGMc3x)P(Ku6ox8-C?%MOx$j`W9K zH>>?k9IDLc4dipVp3g3~xrkJ&24fucKS_IPr5!qq_z!SdwK*=&^Qv{NRMB|V!dCu^ z9%fcnPNYdWE_cf~UAAZHaf^R(>^Gc2{mf@yPBU4Am045!>Qc(-|+e(U`p&r3abymz~Yci?zd!Nut6?ZiLDdTtf|Nqtw8pIrEVS84ZE zB`57`ka$N{Ge4_*mCo}#xLxl!P#sa)Yl3*Y*ObreKID_gcOict-}UP?4j!~rH|Wc} zJ56}o+F9+CqMxkk3(rZ772C5uMM^p@8h*>V@^nP*L*9)19KIJml70Yr8}bW9cy;wT zcOT)sg>e1+=lbILkJud{e3VuC9T}zbrr6J6r=f4wI6q-Hk_%iScRj`YT_Klp^dWCX9^iXP|L*a&aFtK( zm(=l|G5(>y2>pulU0(KBdfi5xH1-`5S8R_FZ-99EI;x^w75--w@)TkUDje78<&q-a zcH-S9{?T_!+m++;lA&FnVKzDA4xY#=zQjZ#vA5&T^+U#A>?{(2IgYU}WV|z8-=dGx ze)RUE_iELSRsUKm{cD+bQC!|HqV6l?O$o)<8?c5hoo2bP$RJgH2w{|D6c@%xXWM%A zVXFOFpLf&aoH1FiRonvBE%qygJ?`5q7W1Sv$e)V~1#SKGCzW2+xM8jzxcmuybC*;htMW47sZGxM}i{N}za+Pc;<7DXrv`h|9R*bqbbV`4AaiMYF<+H~9hh5%%^^W%zjwki-R>FHD zs$b#`_qi3rrJsZdA0~Vq-(@_|pI#W{?Mf}INmwV8{=dr7-$u~ihW;x>UwuR#N4_2T zDFq=E`2_ME$k$ZJQ^=1ZuNpeOY=LcCt$h0E6gR{MG0MOE(% zIxJ^(edd$)J0Vr*2S{D_`Z)%3l(BJMzN5N3Aaz-QKR3u$)=RI$#>TUi2Q9 zh}7>f)>+b1xDIcTZFyazML(B%52TrYv7amUV|uN64yO}?vY%R7sB_~OM<3^-#M^NF ztnr=#y&pL@Gl0=DSt7AvFj^_y9!cRzaLLaE@j8ag^EZ_rv)s*bSML6QXrBD6u{vk* zW8d{O`N2NhsH*-TE6QRgAXw@lfPU|dvz71P<5jy?7N$0ReH=k=2tBr=rSl5&r=!EL zN{y+Fy3~6d{iEogF8b;dh7-seZ<^Ka5gGMaHQq_9=GnTkbzzA2V3w^h4TDmDbJ**^ z-spVx%naQYv{Muw}+_w%D5ZDUiV#UAE}R1jvERK zB}p$q_;$j7cRW9io!%w<$2d;+0&2c`!=Sf7v6qwdHnQ%TZ{AoVSKEGFQIMVPYb**< z{15(=_0IjO9Lc-fkX^VxTEZiQZzcRrzH>g)CUX+2fBB`4!!g2-5`KmnPpam5;*2iT zFKNiD4XO`jup{}J!p^=?_Nxo{VO36M|B&~Ov1zvK??g7{o2EUqkN1_YhxPhL-j00X zeB+;)&MK~ta6R6tI*g+uY40)Y9escKIb00+IPxRN_5ZI#e}0H%z=J%nSlGvy?Tnkr z_z#lWxsBBF5uv5rYgTewC3~lNZ^2YI6v;T>^fShT56o&?B%icPHQum}Rr@G2pK?Rp zBbM3ZI{ih~1)!%S&=|E%yhU%;-$`etmi>};V9*q#$NY_%g^CL z$g{{hkoQZwzoK}4!n|>-+!!JEd-BAkw9euoEwdqyu@oP{>~{N!>i;?Gw~x$P{D0$v z#oD)xzngvk`ix(czcM~E9sI?GoE=JO200z_8y`p^_wK#e&Y3sKz*cMrjWON zbXI$l$V_{**VR&o`ngkK{VeIvq2Gc2XGNcKEZsM8lN}c%%w@QmzV&g&Kh1eF@e2RH zN!2_ghX8-67(SP|d4|4XW+GY1PYiqeKQ?Rp|Fhx?ACZqEA9zTuUv#N4&LxpIZ=KaX zQNC_8`-?d)td!^E=6O!Bct1=Ydqba`HSPo8GRQk1*pFr9!XhSx5kG&$kFn>z zcK_Q)6J1nuVq=yyY}7tI@SB{)pBk4_-}oi>SGL=)*9}9JZyJ6zC+`dPhot)59@#B( zi2_=Gg7oSV@yot(U*YL|S-r{v2s?k|(HH-U1^5&Gc7=!ffac_0A?MLI6FH3#=ofxF zE6(=UcH;LF|2c~9KI%Gs;0M7UUj+Hq_&N-J1pG2*hq>|9civc=&Hsw(PS2Kj*A_hO zMv2Tf7D=b$oA(uNQTj2xsPW4BvVB`zVhnM5vETb@!DaYvMVKaMsLoMPRFVH3Xe1?+kb}nS_1C|FZz>QeTVWG z+8LyuZStEfTcyZ78SBV(RQK+!?!U%du=3^yR`+&c;`Whl-%pt@{{#9uUT%N7`1?Q1 zdw#ljy_4@PS^&7go1mHZi~lVAYrlmbKExMsiU1 zGx(pz-YI3DMaP@bO!gzHIIx6bFbtdFHz&>;lM&DKZ0{#De?4VNpD3tR~bxTaVi}sry_?7+OzQTKy zerP}W^ryBrvc15=&dKL6ET-Yt4ZqGy+dG<%y;Vn>hC0mwrxJG&v3K^1q*`+Hu<~2? zOXdeZyf3(CIcg_sx7U{|*t7G{pMkz;@3?vn{RHN=&{jsESWTM= z)&NOt`VIE`BI`lfSpGx1CDez;uE6Esxyh?b@0fVXW#@59XM}W4{PMm+ztUk{H)WTF z>-FsAkefbTOKfWXGff}T2C@|#^`j-yIsWVW>^mv^Umvy81@Hy%Aq^nDb_(snU95^_ zC;a|ZQy}&8t|k0=zef+L-HjcA570SqjQkUx|DXGU^CT(xm;XQ)E_(L0svO6NUt6|p z?~CRC`UpP-UJsrePZu5i0}Q48NA%~xYoPygK{wiQPrrp{7=J&7eW*_=hGHcWF#Xg)T=%7Q&-c>Tz{=1L*$u1X01cdq1 z`Uj?WEeJNQ?dE2m^#t^Xq5te3LT~)O?60|#7i)@sm*_njN6NETJWyTYZZhDx9m?s= zW>_u3_uRvl3m=W=16Nn()j>YCxnp}|Nn~oTx@GkH!W)p7aEq=4`JNl^Qz&>&MBdo75fB54wcY3qu z4E%QZRpqgF>Xw7?$3EjwgLVGM_%=bj z1>&(xW8!)B!#fgM+r=Lw${g|cKYF=v!qup5vJ&?Z|m{L2u1nmzp^#cV?Vv zT|s|8W;ximlFG04YvF>8jWSN&rEf-vzd`)V3`hHq@I&C|z>|9G71Oq zAG>V*m|;Kbsjg?n?z&mgVI%(Mp>Klzp%Fg9t5(r};FS@)ncofIqTeDsGd z6Vo%&_kG0cARgwXY0p%9Furk)l66AWP_PfxxDFeLGDZA6@pmeIm@a-3PHEX&+^znH zuBJYo?*XDLf>(l{Rs4(hU*4ybhtSh~JB;5Yt^OkVrF{*1hjji<>4f=I>%X$PV{3JH zM|H=R>NXa+U1Km}N?u2ZSNXW*z%P_q|3e>WUO%Ku$fXCOwZsYyjYw2BGwl?$?{ui)%Ba4G?E9Z3-a+C$Lg~3rBj5Ajli)8D#y;z@ z3`;WX@2p|(EW6|+IkEXi#XmEjfL>-$@l(f-I`GrrMY$i#u%YOH9ZQu?E8!c2oB6cK zH+{hEGkm>~P^Jrxp~^W3eeDyM3lDMn$(55<9joAwQ08#7oUX$vooV8gJ!#pV&)*-c z7vZGIOomH#HlZ%Q=Al0V{d1nce?qwr+c_K;c2=LuX5Qx&e5hY{ zL#dm`+G2{XBZmtqhG-<*1ixYUwOtw4Zz|^mcnkRR_#KxYxx}o$)=j4jpIPWTpns6) z-ADZA9slYg$hXR|?)V=SPQ9ecp-pJ7v6&90d)fyRD}^Fkey#tCy+Znx4+rqob2y$e zPsn6<=DZbcG>P&(0l(gt#>WHYdm6kO{C^%DOD7!X!*uY^WV4^ugdlA>m~_PNJp9VW zmXq)1h5SPKF#eu#Z?>%=Dt_(fwEqCRJg_H?-4@DQm_OF#%B?|}&YuxD^}9pxJN~w1 z`#wGTbWEz5JwXJSad(FBbA;a@!1TLt{}DzVGl=@Yyx7U|Z}>mE-|sx}>+e{$esaUV zC+MddcQ*Z-4eu8JP@l^;Z~0;)Dxa;;b--uX(T!;+a~nLwr;qTXgkS5zoqwPcDeEi_ z1>!Rf-C5`!6Yz=OFE{PN$E8d{ISbb#!}^t+`45!Y>a+X*;8%awa-rI_mm7EB=k8N5 z<1$xPRb)TvHI&FkBY&;GWqh7ow)>S6?GU}QQ^k^;3_`yFz3~T!v#|S#p%=3_z6Gki+d9Gg%Mn}&jsSwzIQo!-v~!iw{W=bx(L>Aj{5$oM(n|>SYbgW` zg#1Cku+oXWdwn(8B!1I23)rEe}kccMr~x!ypzgl{^JJc2(& z@xgUlo!Yw*JP-bU;bD85^E8q=%`=M*GPQRf^u6y}4&H-z0C zG23sC!S5*io+H5Q7n2{6jo)J#lkYjgPZM6FaPrMHz-IsM68K5*D&eNTcM@VhoA|2u z5A+S;Pjr~Rgx7(KUy-(mH-n3xsULxSMBnA;qxQVyWWdqCLxj{@$__Si%2Fr$lajVu zalDhBI0m1}_b&(g)VcRID2L>Ej__K-Z&o^CyK9eB@G!jioQJL-x~-0GOpRB0wYi5! z?Y!wf8Se@IxWdD8oVt&J3$WAYINPDG`M`4FPvUlsSr^iL?|V^&yiMoA!tJ5adC3HP zDi6oUKh^6rco}%qK2yEUI{HaZx`@`kXtHb~V9#ZkuABDS{olW1eEr~Zu&;J3gA3(W zYv)Oh8wejFyv3!H>YucqxX0w!9Gi?GM(>QkZy0|4A6hPa=yLvpJf!B?=ndx|8x|**)a|NX|3s|on?ne@;vE}9%0;a z<#FkU<4LH8b>6>^*L7aZ;^MaI1^&+Rm*?*se;fRb;s-d$-z1k>o-8+aQ2A2d4U-)( z>43>@m~4f~R+zkqNMy;h!^8&j_m3^xeM$0wy$Z36*!#x_-yqx=0*b^(@_GvV9QdGs zeewCjP0@Gos0580=b>-<_;O)J^r0Rz@|r2N0baCx)PI`)3w=R+qc4m;8Hn}69>Px& zZszG>KcxQ*7tL7XzZ-!r58YeE*yIC0+#OjaE9|>)JA~1vyLd@n6GwhpJu^eRwokZm zS8@5MTyx<2!M`COQ7)>|@!;Nm?M_2~!mzka$CRt;zp39M-@Q_+{lPp*{h*QX+Ue!O zK&gJ9tBSv$>Id}q*hvf{ipuW@{8~P_Z1)qQ##8-@8~69ptM0C@?~FX7q|zCCVwU(F z#5d~{l-I9UQL5^OfqOyALNUPblb)&i-;7uAd!#|^KhmoW;Qin?3A$4Cay3%LLeQ;2 z^;rE6-BIZN&_*@?s@?{`kAweI$ey6ThjveBzja|_exCkY!l`N7c?N!MpIWx}(}m@R zU-aJS%#K9CgL%ezm52Drc~jK|$`5{x$+`VU{i^}|2>5#iCFF|6b#i4lRH?i@(ARu= zxp1$eFJYIln@DmIGz^QfZ0U(L&33czbQ*q>@OyzKppntW1u>Uc| zmXQL0{qD?R({Cz%k3D?U)hFJ83AAZ(9{*bDkK()6J9G%UmP6R_cdy%t-$wlHO3!^p z`0fKg0RH~Cp7qVM*rCS#Y%OWc*{RzbTgZCC3f`K_{sG?iv|q}l-^}+S=^y^gvOVt` z)&n=Rzm$5wK%yRSBk81|{SUfU^1kVR_~*0B_TC=q!_8YV-^7JN6k~v^zqCSk0=lTZ zBfJOvIC#`ue{7ZG1`%{R|lqL zg089hSttFLFUIwg@QSkXvNjK12j1bqo58!mqwOm`U5@@w`CZmy?^hK*06qkL6mJI~ z0Y3~rB>IG2q3tD<3{g8HM_ISW?p9PZ@i_&blm8$2NN-e?mzU+?GbqMkf9b5Qmo9aE z#GT(zd$&Tr`Abnhf^JN-ACUkj1}3gb1uSf0e&Nwu4lbt z`XY5JUx(9uAs*FiY$vsII~zsMeI-2~>;vBb7ftcg$d6%dEIr}uKK8Xm{oR=x8DZMP z5k~aW(Dy_CAu%!Uh*Q|&yH~fx>7~Etp+5ut4WdVm$J7)kN^YS*d3P8YRefK8uJ)_T zh2K7m|Ag)78=pEc-8s_Pf<{aXL~bBe8M`XV%TC`LFR%K^0Qed3-Tb!s(S(VN@nDPM zjT2sWW;yo$hvH3v9{|^HJKygK^r_;_y6{IR+R0?8&GN}q&2 z@s6HPF0`{AvGVke?KzAs$qSW;h6t=YZV|!o^F**ykpa>_MEY&tUoPAkx0`%=M)%q1 zbrcW3U3&i8)1R&XQ1WwuboT!s?)Oo@*u(`jqu}4-x9ayI`dMpythjlScQY&T8_tCSKr46Sg8m@%k5T%xsm?H~&IiCJ!PkXfT%Ob%EFyU12?v%AJov=o z79YLR;?u|9k~U;5EC>7K{dR!4*@(2I;G^?pZo1nGn%Goc^e0Ik+aC!3pDZWe4bnSm zTWmEkYj6%X)zdKa-OxwvBHTxBrynCI|W#YF; z_)4x>G0{@IXYe20F&=xOvof9eW*NkLdVBZocE zH~nv zeu;tFh_%rN=f!UkKaLVe$aU0D#O)RIdQ<{rs?SC?t{o(v+?K_U+MykM6g<=u;W*t& z_yFOPgeUv~KE;Vm;H+MbcJJ|_kv4q`@n0#6X%nB^>5bM z*Srm|Mdk7cwDq?sol~S!^K14^mTKp)f0*~6?|@%=9O=C1!^eH3(^!K%{bsrFPx1Q1 zj*0eT9l_vyU2+(~?R+?mI_a|G)CBzVOUs4%QsoHkB+W-SFSfvY)@RGFt`Ca^o?>u-L_(uhX;}06mjXzh? z+pkH?Myxm)dEWF;`Wx|+<8UMR;RLSnv>kjByv?N-osY0nFJ_M_f5VRd4;_7~+AiWv`w4%cj0skxtFpa^Vv$ooM|RcUm*J?9$#qH=-ApT}?hKHZgt^|5Uu+`Q|6O z*X)tC9i{|lV4BI7skQQg4>!?A*{VI1-<|t?Kf)Q8SpdU+y8+7 zg!SsnFYA}t?Eg}R(-mt5e&ws;kKp$o@pOdOfu9C{0>6tN;mzP@!Jk?L`5xx43w#6o zahJB!I+5^2Z>~CWFS73;^Q9M%cY3Lc+X75~Jw>|5f9L$G-0!gu8Ehs$i{K03Z&5y@ za@!;mQIdePCN}PB+}!jq?AMLu!cr+cN#l=QZcNSZrgfrSupNOp{3mQD z-}tvv=YX(fJk7+i&=D56JD3^o<$H^6`gvrQU)(X2x!xhW_~x!K9_Bp3rJNjWP&+M> z{^tK#PMtqL58eiTCf-gy`7!S~eAzEQSdD(Xza?i^-2Z(qF^iC&A4; z(byBXhB#6$&z$t>As24uC*l4J?f3j3>NMuC5&bFXyUX*1Z}L0R&e}Nq5!%^mB_}be zm-En{gFe~cs%q(<;13WV_Yr*q_}K)mbX&m}z~3rb+SlnFrZsxst3RU)c8k`T$~_2u zOC}%LXCVvQD)t`2CkXE)oNbzhpI>ixNmYJ6Eq7aT`%*@SwLh2Odk(&N$2T?JnD^je z8Jm%Xexe2p$RpW&?0#$2ODp){1TKBt13n4PG}DwLm0lN>b7vws*FMs3hlt-_kuTiJ zZ`Erm{w`jkPYjP2n?EkWZ}k61e$9`hKH&G^c)t$&PiSv;@)UXY@BRJ9c*tbGj>GR< zWxnvM`1s?~6VjV+^maNM|cGn#SVcd<-QJlKlp=- z#C(gs8N44n>VFd6<>;g1mGA*a|A+i8e$*dE9Q`*0>P%whgY*aMIP3wMBD^-2xA$Nn z2mbz`DK9gGq`i&Wobeo8QGK6>Z%tLc@TpSu9c{n1%s+eUn+FQmXzQtOyCAB5&{s!) zeo(&jy)2#Bw@lz--7eA(rii~m{P|1g^Ga$j`vSk5nU1V}wGO|756&095ZC)YIb%F3 z&-VJaQkfj8U0WZGzI;eNW+yA19`Li^y%L0Q+zb0hIFHeNKiThRy)|sok)EA~-?@k7 zgMEEtT=A_V6&k+j_xxZc8o5_)9{Q$-=L>HkuG06*jkX2iDoM(XThD1HYTaY#FYtML zDL$-*k6o@M0MFFOTm5)dM_ z=cjQw_sNU7zrV!AdPdGAFZ1xLc|tzvr(!lGualjx6#Z06zoH&{2>QNDr@u$%9DiS0 zT#en?1HbMk=I#3=w0CSia;vpS%zOmvpy*(fyiE}ADDiIQcWJq0D+ZgPlVa<(37Yzx zhtC=Kyfog=!}<*6O-^reo1yaL@{>ZG2&G|)7e|bZq$M}QPlrCp_f7sF(2i7 z5&HemvkfR!pB>ek@6dhK?2rG1H6?<1@0Q%F;wu1(E`8T{1>@15IlGm4x7If_jWT(@KM4)9d8d`|JS=(P5$a*Io8|3!ujPK>6~t%os5 zQgW_#YV#MG=L6pAFZ52m;Nz(b^Fpx)*OHOiZ<>7dZ%xlvX2E;GqxPBPejdCVygptI z^k1qRSF?>e`-lE^HRFx+Qo|FF@9p`*3*z#d;J1%0(AjxPF4cq#1^vnRIGf=!2%nan z`GR<=ol|zb-S5ia9xMyl@)NI{cz>jL?$gNkEO;;Yi-loR^i;Q8Tiw=STA3|8?45gl zpbtd94*fys2Sjh@oz*QIJJ@Yvu#7ML;q;#Dx4I|NpP+AZB9#PnpJR?K`W zjw=ns?^FDa{6+UcD_`T#orBKU8KFMJIz*Agr>{otXQ1!il`p(G-o8G4V$PfWT;hnX zOSDU1$5lKD{nV9@z1u7~ssld(z7ii7!*oJBZV&t5v+ub`I^s77zuqhJg`by_qi|f( zp`j6Pu3dkX-kpVCzB_OCE3;)4p|gusgekp67yjNV{^QecVg9*aHk18XW$6?p4~?6V z-xuYB_ft~xtNS}x3X2JZ8<9=spCUW7)@uMhfxsT)@iksnI_hjr}_&ip8+(-JT z8GIDn?5By~UEoK-A73QqTl53qC&8os!bb2B@CEP=(T8%6USU!sw|Uqd?f4J<2K3Jr zefSQDSqHQ)YEeB3jQ_#D3@^5c_# zwfxmc4-%E=Wp3Tyv_Jd~!|$57{QLMZ&$ssw!jPQ@QFUrZK;?TDen)S}7h04*_ffg$ z!Owt?3*#IE`+zWy(1qM7@d`DgB%@96B_=n=@`RtZjd}NK;mlV1%srs`DW&A0upu(N3YpTp@EN%fEX7S z29>{Q;+-WPYTuu~P;ctiwNHBUw=I|1bCC?HUaOvlJnhdH68nc(-%r^Ma&OLf*+ts1 z4}QJ3T|9?#TL;q)@cONtUgXh7`zEhvQ(gVk~gu-_A zLl1oVh~M$@ynRpfpauUk1^wpBL{n~TPE#*(6qdg7?!t& z-#g4cv}45UxGit@$A|mY7(Y2LxHr0QZF^2~xCs3T=)WBwCw${A@9kxD6x&nZR$#oOHOSWJgVNHE zt;Aa(-nUEjvuhZQzDysYWrG=AWPBJQ{{A=R?YmC&Voc}a^vl%G6yZk+pLO~2`*Dje z0tP~8I*9bfBJnrBIbYZpl#5)ra|1eh-xfI!ExlUROnpMH?o|8;ZvgKGkFJlH@`HDP z8^2H3enyVPpVhsv{kF3`tsXhI!fo51_y>vqMI}c3l%A4n`SygKa^sfDH%t7=QRd}} z4_`OVapasigA!txv)Y2Tf@B@~7U(}MdS7~Si6{5lxbaN&(D+Q+gZSEZQ2c0IZU;XC zZq6GTd+ntL+Z~L2tP{r+4wqzuRmYId^Dp2An9qeo#2UI z*Pl_pZ_gJ#qx8t9^G6{MDf?-k&WgX@$4+tih~E_a4#RK#()xyVgG}~|eg$uOoa%X9 z`Flq`c#l~3T(@DD=m6p{;Z+Qny@bEw(&=@ho_<7iq=&5?IW`t~tLYjata6T%ZudL$ zg&X4SfWAuA8~*po?9=`0BSAUm;Wuj|od^Msd8lAglZuh?H* z$*E-gKNy7y-_$~W2situ7=Xr%L${M-=ytzjGvSkjNBvQX*9CqUyg0A6_ezB8uY-i2 zAiP%Tx{vzBIQU5qJ_UXn{0T*3zGdglfS(0_$EDke2KF}xn>W7YZNI4h>(9|I@5vX6 zcAV2s%(tEYt4Es-@wCMp9#+AtTz$kpO8n${^Dy`k@Tfi&{RH@7@H_ck{511p8ocJc z`QV~r&{NM+`lm7T&@FDQ1zd`ad;plg&@J3&~KBljZ5q^|-e;c>=eEQ{Tq(1vo zzhBoVtX7h^0KeM5%m?QgQ{#`ugZCxI@5sEV^*P8h@uT}B)m}Z|$H9y1Y0>pBZD3&H z5sr(_p|ARyAl|}MyuMT~)8J>o$M`KjZ}gop#XCiK+lTXoNrj_TwE;}{BKQgLr2L%+ zKMr0kdiN21RV(!i9&InB-vE9D+?=yxSRG@sRvgzF32%4dHR_MyIIKC=dxL@4ssS@D z4MRWrk$iCP(wLS`d5>f}TnAxsNc;%@U#@@q?H;kGZ#Us@;-pDn{dDLVL4o)T1CY%j zZi$+~EkI=(NdH!l(9lO&M~U|n-#ExV%}nNVUIlLpD0`p>ekVVkx9>uk`a(n*Jd1r3 z664Psfv)xw`9hT|XH-ry?5uOPl2Is<*JIFcK>rgl2;cF-uF7bw&>6PuP1o!hrGEE4 zEG6hSOMjhq^M&yKU7x-%`y={w{qNmWw&(g? zHsO^=pI(!E4Z=VFDay<5;z#vA4t^H=huTmR+6}(?=aGv{w#?tJO;2is#XS6mzUtOl zLV3hPjGQ^U(5ZRjC#`rM;~Dgum8p=vlT8*y^=jrDjnEy2E~&TL!H1f{%>tw8HihR&+%ZCv{xRrlzZUP$lDAXfHQ>e%8sl?IvA9Ow z)}h-BUE=%-c7{&d6OpmQxj9U|)Uoi>3;olQ`Kz}V(m-zV)ec=hbjfo;eJ;N7lf!;Y z@1DC9R4*fhA0XbN#NT~XFNeTK!He;N@s4xeP4+fMdrXE5h|ekLC!vq(In~P|_(AYL z7Vl`iaCpNN*W|xqOFF*z)`2U2l&|_xGr00+)-iVKMGOv5I{QlTdI coV0w@TlGuJ_Wu3pC~RpFyr`horCEwsd0qv7PpXKCxfOSHF7Kw83A!*ccSK zB|SklD`2YkLDD&VZ@B*9w`=s6?^}E(j7nql@(g_1&V=g#PCv4QBL9|YCQ}cK(Cvq= zUlF7FuL--!5jykJoL8*cLH?ls+fsHHvt8}?J6Eo&faETX+E})sC9gg3srf$p4==4> zcIdq7Td6k8+Qh=4^((Z(ZyJ8xKgbu1zm)d$=sUBOF*Xg0tUE6e{|xaTSt>ta|B>I) zZ{E3eOvzXCPR9Fr=dTIt75jp5z}2fu-n?rt0R2hmjon86{q4RBdzJ$_TJDTj>y1_z zqDPaq<)n9J;oI>;{9kfNg?i4XcX-h`yX==+HYp8UUVY$t#*7{2$O+7>->I$x{=dlE z`*3{qZv15?yMY>3d-V`+lz49zqf+sD6T?$vUUi80Cy8&yPqg;S(F5wI$G{iB$K&l7 zmN&Yt(4Xz_m)9uTv`=4o<)d^q?IMA*`NEf7Ifl0&BCQ;aqrnppZ^gmij;g&#oagmNU;DO+;jZ9PWvyE&<9=WtN1-55X=eFphE z1)us~=k5Dlq1_(pujsoO{h8lLOO-I&cjvfj;l6yJKivHb+AsUf(%G=`HwC{1_?h)bQ$NO!&*hxjxa_KA zi_T>_#|J7%Wjf09mO#E}iH~Y52a$$#GM^S9^c9~+?-x4NQTC4wwU-M7cTgp>ZZtAs) z3cxt6_E?0j7rMJ-z=rxE+|L*4J>5HjGs&Zd-GHz9XzXHq_}8@GpdEZNf!9Ib2YwLT ztiw=*!D=QBZek>UBZQwI{Biu2AF?P%hrrK(e@VDce{@ziG1SJ)KYKk!Y^B9aos`ZJ z{Myc??d}WUE#PK<4<69HWKQ|sw8zpvPwCSH_`jGWUum)~{m@K!Kk*J++TN9%<3aKm zc3iwSr;eB!_v}EU_M0M|1HYwy;^~C?E^I&ZqSftEcM8<28{lHu?AX&HHeDz2YkR)Bm79Ni)))nE$gP>iUx#o{W4nLthWQksG?3?B3{n zzsH4}^TOiENA)uZ-b=g+gV=wBkAruEN9TFMr@%Wr_zZX(_!AR+<{ba1U#|h0CC5ME z-$?BPtLnD-i_XU-hYjHUq?b647S6|zIpYRL0|tgbi34ea@EeBTDE$7nD832r0VwqcqMqT?I5+||6XNmrEqVlei!DC%`4d} z{dNW$j&AVwAme(He2)0@a9lr!<93*i_BCnqbXr~P!hG{*z|4qE`AO$U)k6AJ+ zQQ+B(VUjWS#~kUjJb0z>U-9yU^%>Wf=Dc9KLak$?5w>;L;IFJ%@!u2uPOBQ2NSX+u z?}GloLskk`D@&|jxOo}l`fHQNc1^vEKz|ha3YXv1yZ|ee^BGeNb~mYWTEWH~j0D@~2f$Kbcouu`av z*Lye)VHav+R?G@?enIJ>b>c5PVWsdW*AMR0JI$c`E+SSRABE4FbA z+O4B3u{oXVanb`lFTft&OuMMup?%JSD&?7zfkk06)&R*k^hchuV)xaD^g7)2>!STJ z4&5>64m@?G@PoMAhwUBJZ}?g9;CTdjTgi9aGXp%lzJrCEm$(PmZ{%AmJ;evv$%ERx zxfl6wT(SE)ZM(~{Z)!mG+(Y>Br>)$-{m}i{5Bb#%wf-s!kQNAIAWObxNoV2dE6M#P zKKa^LJ$iZOHeYqXM<4O4x|Z>yX{GRl`y;Qc{4??NC_OuVNM8HkSNn{W;9O_S5BZ5; z{6KyF8~w!|amf&;t znJa~VxU}5hKfWycDu08R_BHK)9roa}RthhNH}j+J%vIIBIL^%36X}Z{!jBW)T?}U{ zlj046=fQ6(;@eF;U6*C_%mm>rEi3jt0P)>r<4uDPf#2Zby}?9#k+Hdz-YLRQ67J>~ z-I-1|{{`Ow|6RP?p?rk>h4=2tvyWD}({_ik*OX4<3mLDU9k&;Sw}T%6kM4&N-sk9} zxY}bF{5bR%o8PA1f!7!dZsAjU z=K}E#67O#mk9n@yCbTn$zp=PG-1?gv`rzNXl3X86%^$j;+YDWFy-fKVaPf`*KGbi_ zuQFqSI^3D#(IvZoMcGmPO%d+|{G$6SgwKE<2fsyx?xXU|fmi;o6}!$Fri1+zdd(W4 zI}cqAbXycRq+>HZCV{F6|B3Czc0HltMa)m3?+`un6=&B$e_hJ1Q~UNn-wpji(T9GQ zQ0~HUS@+8C^J+Pl0p)iZev|O)bo`?23xnZE>zaC-hyFP9QMpsSt%INN;1$=?f56Q; zsnXyh`a19haN~zHsKuMX&w-nD>j>Tj-tpX(*#0H)84!PPv+oNzlP5*^2>5C6$2%VS zQh5)7p9LQj5VjAyJcfhzDe6h-l~d5yKW`6jB_VeHk;B6kf6}-iR_kcHnC-XB1z8O53pK% zz$-oY5_lPSGCvozf5OS`aJtkq|>Q#4ai3Rp>Nu#o6o9=ToH9vS-Ea z4-fSK`aJW=qMmMs?i6%qpxevuh`xaC#ne^AhmMaI)h;Tde=ZPjgLscHi2X-UFcRo9w>)6xIftM>4*fforFgkJ zg93G!MR_||b+T&X%BlL8SN`{|*nRP#J;0P^tirAQVhHe;XAN)41St&d_E+@Wm(A>baa*>KuxsJgv-;){_c30PP6Ok+bRdSBF zF3emsFo&bz>mf*X4wlsmk_V-+_knl(Vj3z!|UxCE4BB$3*T3&|5E2}9kN^dgiG8HWac}~@N2l4^7gLSb0cAYd_H|Z zOS44>O%=&|%sDCn+{b+{Sg zj}rgEitj$EuQ~7o;L&kT`CkGb0yqApuwAI@u?jt4fKpL9lq{Sds2=O~)1JheRT{p0 zvP7-h*kbwY)gE2$B*-*9Jh+aF7AI+yB{Nd2l1~EL$g0TZs*Mr z-b?uJ?@zyEzV~kbJlAw|Q~q19C;C*ZHk|`b#IhxRTE^dvpa*{}_bdVfgin zUnob+qqKM5s`BFgDy2UK{b}g`C@#n0I2)ZuaL-ie#eV~Df*a0^K5c#(_ScJ73U4h{&*8jUcToQG#p*@!IS#+>{uR5w-6t2C zCEXI2i$3Db67MMSUKjZD&>&HN9`&R5cX4U!3J^IKqi#JEFj~JU@fx6;cd5SWUQYer zxMKI!hwX*y1s8G9UKuUg+s11*W3tr;Mtj)tX8=Am1I!0Y)mO9~@!S22x57fd(hU5% zU%F!NE1|wp>jtLWH&$wTY%r+iJ!k8ogA$& zFK9>68l?^Ulrf8MfE7lt1BnCwngLnt3T@R@x1O5r=D^3jE| zaXY4h@y+e8Q@b4^e*NG|a(@el8NzUVIw#2VM_u>Lrv@w98OYOpRXYg02I)sJ*7T9sq9x z|Evra>Mu2pM#l^8i+y+&1(=>unT(3x4E&C~X{E5IBF4`*E^_)YlYN%op<{+xmAm3q z@Ox|AZfXRt13wJj!|zD{q(30Msy+H)alDq?c0qp{di{>mOKz=ibC>#U=;k#3u5sd> zAzrv2j9xL8y^8HpK{{3ntiG9nzHBU>U!^$*z5$>9c>1&x_rtpUcIIAM{3$9UpB1mB zec|^z0pWOpzKizzJq+as)7{=FLe*Cnd=}u7IFHS~*jq{8>a*fJS8_W7edW0G<0kqQ zJ`5+HdvaTX-|c$igjqbjO?l-bc{l~1Ciwi!>8;fKPAZE{T(RjK_v5mDvl(M9P(dn+ z>T%O+m=E2Nnm-#mNh`9pyYI|xEB+*oDL?V@#4Cp1BA*rMgLiNA_r<`W5A`mzrE1o(SJsB4B_ioSG$sCsH8yyYD$g$ad+dO`jfX+qoJ zyK`3tzo}rQH%z=q;+gr6;_~U?ZvuP+ygsfcLpe12Avgk^$$ULsA3Jg{OBr)ke=WiH zd$f2bUU`V={e>eF4g4_;8czoUBSMb-PaRQKbz zN}5zVasw$$Jo&WpH%mHs^6?}mM=8D6!@TJyi3zov->5z>5P#v&ioI9J)F*|xBTGKV zDz2^G+*jSiEwNbt+=gQ7lsKmR2T1UJEB0OyBUf5wWKeVaK6(gmBm9HVtNf{a$>~62 z#U}c??>45O71`?5Y4}aTuU7!cID4FNST=w0+^Yhu9+`*!B=r9+;3b~)b^p

  • @endsection -@section('message', __('Sorry, you are forbidden from accessing this page.')) +@section('message', __($exception->getMessage() ?: 'Sorry, you are forbidden from accessing this page.')) From a481780f1b4c6517fadef11e333d6f7f1948c55e Mon Sep 17 00:00:00 2001 From: Dmitry Ivanov Date: Fri, 2 Nov 2018 15:31:57 +0200 Subject: [PATCH 0751/2459] [5.7] Add `missing()` method to the Cache (#26351) * [5.7] Added `missing()` method to the Cache\Repository and its Facade * [5.7] Removed the `missing()` method from the `Cache\Repository` contract --- src/Illuminate/Cache/Repository.php | 11 +++++++++++ src/Illuminate/Support/Facades/Cache.php | 1 + tests/Cache/CacheRepositoryTest.php | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index 7b117d141d4f..03eb26f0f86a 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -70,6 +70,17 @@ public function has($key) return ! is_null($this->get($key)); } + /** + * Determine if an item doesn't exist in the cache. + * + * @param string $key + * @return bool + */ + public function missing($key) + { + return ! $this->has($key); + } + /** * Retrieve an item from the cache by key. * diff --git a/src/Illuminate/Support/Facades/Cache.php b/src/Illuminate/Support/Facades/Cache.php index 6be6f13d52d6..67022817cf01 100755 --- a/src/Illuminate/Support/Facades/Cache.php +++ b/src/Illuminate/Support/Facades/Cache.php @@ -5,6 +5,7 @@ /** * @method static \Illuminate\Contracts\Cache\Repository store(string|null $name = null) * @method static bool has(string $key) + * @method static bool missing(string $key) * @method static mixed get(string $key, mixed $default = null) * @method static mixed pull(string $key, mixed $default = null) * @method static void put(string $key, $value, \DateTimeInterface|\DateInterval|float|int $minutes) diff --git a/tests/Cache/CacheRepositoryTest.php b/tests/Cache/CacheRepositoryTest.php index 4be76ad9bf59..b88cafec0f45 100755 --- a/tests/Cache/CacheRepositoryTest.php +++ b/tests/Cache/CacheRepositoryTest.php @@ -71,6 +71,16 @@ public function testHasMethod() $this->assertFalse($repo->has('foo')); } + public function testMissingMethod() + { + $repo = $this->getRepository(); + $repo->getStore()->shouldReceive('get')->once()->with('foo')->andReturn(null); + $repo->getStore()->shouldReceive('get')->once()->with('bar')->andReturn('bar'); + + $this->assertTrue($repo->missing('foo')); + $this->assertFalse($repo->missing('bar')); + } + public function testRememberMethodCallsPutAndReturnsDefault() { $repo = $this->getRepository(); From 7daaa46e6a8606ba16754380c182b25409d85c14 Mon Sep 17 00:00:00 2001 From: Dimitrios Psarrou Date: Fri, 2 Nov 2018 14:36:40 +0100 Subject: [PATCH 0752/2459] [5.7] Adds missing logging options to slack log driver (#26360) * Adds missing logging options to slack log driver * change to snake case for config values --- src/Illuminate/Log/LogManager.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index ac5942b22bb4..f0ddfc5618a5 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -270,7 +270,9 @@ protected function createSlackDriver(array $config) $config['emoji'] ?? ':boom:', $config['short'] ?? false, $config['context'] ?? true, - $this->level($config) + $this->level($config), + $config['bubble'] ?? true, + $config['exclude_fields'] ?? [] )), ]); } From 12f3b94c564f174b338c8ed089fc1df89aaa64d8 Mon Sep 17 00:00:00 2001 From: Jonathan Reinink Date: Fri, 2 Nov 2018 10:57:34 -0400 Subject: [PATCH 0753/2459] Make View Factory macroable (#26361) --- src/Illuminate/View/Factory.php | 4 +++- tests/View/ViewFactoryTest.php | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/View/Factory.php b/src/Illuminate/View/Factory.php index 7918155df30e..201486034ce6 100755 --- a/src/Illuminate/View/Factory.php +++ b/src/Illuminate/View/Factory.php @@ -5,6 +5,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Str; use InvalidArgumentException; +use Illuminate\Support\Traits\Macroable; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Contracts\Support\Arrayable; use Illuminate\View\Engines\EngineResolver; @@ -13,7 +14,8 @@ class Factory implements FactoryContract { - use Concerns\ManagesComponents, + use Macroable, + Concerns\ManagesComponents, Concerns\ManagesEvents, Concerns\ManagesLayouts, Concerns\ManagesLoops, diff --git a/tests/View/ViewFactoryTest.php b/tests/View/ViewFactoryTest.php index c52bd7b72c13..bd717340da62 100755 --- a/tests/View/ViewFactoryTest.php +++ b/tests/View/ViewFactoryTest.php @@ -653,6 +653,15 @@ public function testIncrementingLoopIndicesOfUncountable() $this->assertNull($factory->getLoopStack()[0]['last']); } + public function testMacro() + { + $factory = $this->getFactory(); + $factory->macro('getFoo', function () { + return 'Hello World'; + }); + $this->assertEquals('Hello World', $factory->getFoo()); + } + protected function getFactory() { return new Factory( From f96e2460100bfd9c0f5dc2a88661e0b1053a1b03 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Fri, 2 Nov 2018 16:28:26 +0100 Subject: [PATCH 0754/2459] Support useCurrent() on dateTime columns (#26349) --- .../Database/Schema/Grammars/MySqlGrammar.php | 4 +++- .../Schema/Grammars/PostgresGrammar.php | 4 ++-- .../Schema/Grammars/SQLiteGrammar.php | 2 +- .../Schema/Grammars/SqlServerGrammar.php | 4 ++-- .../Database/DatabaseSchemaBlueprintTest.php | 21 +++++++++++++++++++ 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 2e5ec247ddfc..0d02d33e63b8 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -630,7 +630,9 @@ protected function typeDate(Fluent $column) */ protected function typeDateTime(Fluent $column) { - return $column->precision ? "datetime($column->precision)" : 'datetime'; + $columnType = $column->precision ? "datetime($column->precision)" : 'datetime'; + + return $column->useCurrent ? "$columnType default CURRENT_TIMESTAMP" : $columnType; } /** diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index e26be4f5f4e9..114580de9c99 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -638,7 +638,7 @@ protected function typeDate(Fluent $column) */ protected function typeDateTime(Fluent $column) { - return "timestamp($column->precision) without time zone"; + return $this->typeTimestamp($column); } /** @@ -649,7 +649,7 @@ protected function typeDateTime(Fluent $column) */ protected function typeDateTimeTz(Fluent $column) { - return "timestamp($column->precision) with time zone"; + return $this->typeTimestampTz($column); } /** diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index d6ef59db42f1..ac825e7342c3 100755 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -614,7 +614,7 @@ protected function typeDate(Fluent $column) */ protected function typeDateTime(Fluent $column) { - return 'datetime'; + return $this->typeTimestamp($column); } /** diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 995344bbbba2..33758251edea 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -522,7 +522,7 @@ protected function typeDate(Fluent $column) */ protected function typeDateTime(Fluent $column) { - return $column->precision ? "datetime2($column->precision)" : 'datetime'; + return $this->typeTimestamp($column); } /** @@ -533,7 +533,7 @@ protected function typeDateTime(Fluent $column) */ protected function typeDateTimeTz(Fluent $column) { - return $column->precision ? "datetimeoffset($column->precision)" : 'datetimeoffset'; + return $this->typeTimestampTz($column); } /** diff --git a/tests/Database/DatabaseSchemaBlueprintTest.php b/tests/Database/DatabaseSchemaBlueprintTest.php index d0ffb240127b..cb36af722516 100755 --- a/tests/Database/DatabaseSchemaBlueprintTest.php +++ b/tests/Database/DatabaseSchemaBlueprintTest.php @@ -102,6 +102,27 @@ public function testDropIndexDefaultNamesWhenPrefixSupplied() $this->assertEquals('prefix_geo_coordinates_spatialindex', $commands[0]->index); } + public function testDefaultCurrentDateTime() + { + $base = new Blueprint('users', function ($table) { + $table->dateTime('created')->useCurrent(); + }); + + $connection = m::mock(Connection::class); + + $blueprint = clone $base; + $this->assertEquals(['alter table `users` add `created` datetime default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new MySqlGrammar)); + + $blueprint = clone $base; + $this->assertEquals(['alter table "users" add column "created" timestamp(0) without time zone default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new PostgresGrammar)); + + $blueprint = clone $base; + $this->assertEquals(['alter table "users" add column "created" datetime default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new SQLiteGrammar)); + + $blueprint = clone $base; + $this->assertEquals(['alter table "users" add "created" datetime default CURRENT_TIMESTAMP not null'], $blueprint->toSql($connection, new SqlServerGrammar)); + } + public function testDefaultCurrentTimestamp() { $base = new Blueprint('users', function ($table) { From f89617cec13a41c64778cc2de2a7d22728df6b94 Mon Sep 17 00:00:00 2001 From: fkulakov Date: Fri, 2 Nov 2018 19:11:25 +0300 Subject: [PATCH 0755/2459] Issue-26357 Normalize view paths within FileViewFinder. --- src/Illuminate/View/FileViewFinder.php | 17 ++++++++++++++--- tests/View/ViewFileViewFinderTest.php | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index 4a380f9ce3f0..55a9acdda31c 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -53,7 +53,7 @@ class FileViewFinder implements ViewFinderInterface public function __construct(Filesystem $files, array $paths, array $extensions = null) { $this->files = $files; - $this->paths = $paths; + $this->paths = array_map([$this, 'normalizePath'], $paths); if (isset($extensions)) { $this->extensions = $extensions; @@ -158,7 +158,7 @@ protected function getPossibleViewFiles($name) */ public function addLocation($location) { - $this->paths[] = $location; + $this->paths[] = $this->normalizePath($location); } /** @@ -169,7 +169,7 @@ public function addLocation($location) */ public function prependLocation($location) { - array_unshift($this->paths, $location); + array_unshift($this->paths, $this->normalizePath($location)); } /** @@ -295,4 +295,15 @@ public function getExtensions() { return $this->extensions; } + + /** + * Replace unnecessary relative fragments from the absolute view path. + * + * @param string $path + * @return string + */ + protected function normalizePath($path) + { + return realpath($path) ?: $path; + } } diff --git a/tests/View/ViewFileViewFinderTest.php b/tests/View/ViewFileViewFinderTest.php index ea237772f394..469c032c763f 100755 --- a/tests/View/ViewFileViewFinderTest.php +++ b/tests/View/ViewFileViewFinderTest.php @@ -145,6 +145,24 @@ public function testPassingViewWithFalseHintReturnsFalse() $this->assertFalse($finder->hasHintInformation('::foo.bar')); } + public function pathsProvider() + { + return [ + ['incorrect_path', 'incorrect_path'], + ]; + } + + /** + * @dataProvider pathsProvider + */ + public function testNormalizedPaths($originalPath, $exceptedPath) + { + $finder = $this->getFinder(); + $finder->prependLocation($originalPath); + $normalizedPath = $finder->getPaths()[0]; + $this->assertSame($exceptedPath, $normalizedPath); + } + protected function getFinder() { return new FileViewFinder(m::mock(Filesystem::class), [__DIR__]); From 4a4249ccfc78f4b43a4f6de988f61a2554572080 Mon Sep 17 00:00:00 2001 From: Derek MacDonald Date: Fri, 2 Nov 2018 21:18:15 -0400 Subject: [PATCH 0756/2459] Don't run TransformsRequest twice on ?query= (#26366) For HTTP methods GET/HEAD, Laravel assigns the Request@query ParameterBag instance to Request@request. So TransformsRequest middleware will run the same transforms twice on Request@query parameters. Instead setup tests to form a Request object in the same manner the framework does before interacting with middleware ConvertEmptyStringsToNull and TrimStrings. Illuminate\Http\Request@capture() calls createFromBase() - do the same here and explicitly test manipulations are run once per parameter. --- .../Http/Middleware/TransformsRequest.php | 2 +- .../Http/Middleware/TransformsRequestTest.php | 37 +++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php index 4c1c4920ac8e..9c30fdcccf1e 100644 --- a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php +++ b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php @@ -43,7 +43,7 @@ protected function clean($request) if ($request->isJson()) { $this->cleanParameterBag($request->json()); - } else { + } elseif ($request->request !== $request->query) { $this->cleanParameterBag($request->request); } } diff --git a/tests/Foundation/Http/Middleware/TransformsRequestTest.php b/tests/Foundation/Http/Middleware/TransformsRequestTest.php index 6bd555d314cb..f73dd7b8f8fd 100644 --- a/tests/Foundation/Http/Middleware/TransformsRequestTest.php +++ b/tests/Foundation/Http/Middleware/TransformsRequestTest.php @@ -5,19 +5,38 @@ use Illuminate\Http\Request; use PHPUnit\Framework\TestCase; use Illuminate\Foundation\Http\Middleware\TransformsRequest; +use Symfony\Component\HttpFoundation\Request as SymfonyRequest; class TransformsRequestTest extends TestCase { - public function testLowerAgeAndAddBeer() + public function testTransformOncePerKeyWhenMethodIsGet() + { + $middleware = new TruncateInput; + $symfonyRequest = new SymfonyRequest([ + 'bar' => '123', + 'baz' => 'abc', + ]); + $symfonyRequest->server->set('REQUEST_METHOD', 'GET'); + $request = Request::createFromBase($symfonyRequest); + + $middleware->handle($request, function (Request $request) { + $this->assertEquals('12', $request->get('bar')); + $this->assertEquals('ab', $request->get('baz')); + }); + } + + public function testTransformOncePerKeyWhenMethodIsPost() { $middleware = new ManipulateInput; - $request = new Request( + $symfonyRequest = new SymfonyRequest( [ 'name' => 'Damian', 'beers' => 4, ], ['age' => 28] ); + $symfonyRequest->server->set('REQUEST_METHOD', 'POST'); + $request = Request::createFromBase($symfonyRequest); $middleware->handle($request, function (Request $request) { $this->assertEquals('Damian', $request->get('name')); @@ -26,10 +45,10 @@ public function testLowerAgeAndAddBeer() }); } - public function testAjaxLowerAgeAndAddBeer() + public function testTransformOncePerKeyWhenContentTypeIsJson() { $middleware = new ManipulateInput; - $request = new Request( + $symfonyRequest = new SymfonyRequest( [ 'name' => 'Damian', 'beers' => 4, @@ -41,6 +60,8 @@ public function testAjaxLowerAgeAndAddBeer() ['CONTENT_TYPE' => '/json'], json_encode(['age' => 28]) ); + $symfonyRequest->server->set('REQUEST_METHOD', 'GET'); + $request = Request::createFromBase($symfonyRequest); $middleware->handle($request, function (Request $request) { $this->assertEquals('Damian', $request->input('name')); @@ -64,3 +85,11 @@ protected function transform($key, $value) return $value; } } + +class TruncateInput extends TransformsRequest +{ + protected function transform($key, $value) + { + return substr($value, 0, -1); + } +} From 8ca164168dace92527a298f6cb54802e2690e97e Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sat, 3 Nov 2018 13:55:48 +0200 Subject: [PATCH 0757/2459] [5.7] Update changelog; --- CHANGELOG-5.7.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index 0dc30f8a6e97..908db4625a29 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -1,5 +1,24 @@ # Release Notes for 5.7.x +## Unreleased + +### Added +- Added ability to return an array of messages in a custom validation rule ([#26327](https://github.com/laravel/framework/pull/26327)) +- Added `whenEmpty`/ `whenNotEmpty` / `unlessEmpty` / `unlessNotEmpty` methods to `Collection` ([#26345](https://github.com/laravel/framework/pull/26345)) +- Added `Illuminate\Cache\Repository::missing` method ([#26351](https://github.com/laravel/framework/pull/26351)) +- Added `Macroable` trait to `Illuminate\View\Factory` ([#26361](https://github.com/laravel/framework/pull/26361)) + +### Changed +- Updated `AbstractPaginator::appends` to handle null ([#26326](https://github.com/laravel/framework/pull/26326)) +- Added "guzzlehttp/guzzle": "^6.3", to `composer.json` ([#26328](https://github.com/laravel/framework/pull/26328)) +- Showed exception message on 403 error page when message is available ([#26356](https://github.com/laravel/framework/pull/26356)) +- Don't run TransformsRequest twice on ?query= parameters ([#26366](https://github.com/laravel/framework/pull/26366)) +- Added missing logging options to slack log driver ([#26360](https://github.com/laravel/framework/pull/26360)) + +### Changed realization +- Used `Request::validate` macro in Auth traits ([#26314](https://github.com/laravel/framework/pull/26314)) + + ## [v5.7.12 (2018-10-30)](https://github.com/laravel/framework/compare/v5.7.11...v5.7.12) ### Added From c2cbdc0951a8dddc1bb774c3d52d3f35aabf2592 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Sun, 4 Nov 2018 00:29:09 +1100 Subject: [PATCH 0758/2459] mix testing (#26369) --- tests/Foundation/FoundationHelpersTest.php | 169 ++++++++++++++++++++- 1 file changed, 161 insertions(+), 8 deletions(-) diff --git a/tests/Foundation/FoundationHelpersTest.php b/tests/Foundation/FoundationHelpersTest.php index 441ccba4b3be..3539a5af4c21 100644 --- a/tests/Foundation/FoundationHelpersTest.php +++ b/tests/Foundation/FoundationHelpersTest.php @@ -65,22 +65,175 @@ public function testUnversionedElixir() public function testMixDoesNotIncludeHost() { - $file = 'unversioned.css'; + $manifest = $this->makeManifest(); + + $result = mix('/unversioned.css'); + + $this->assertSame('/versioned.css', $result->toHtml()); + + unlink($manifest); + } + + public function testMixCachesManifestForSubsequentCalls() + { + $manifest = $this->makeManifest(); + mix('unversioned.css'); + unlink($manifest); + + $result = mix('/unversioned.css'); + + $this->assertSame('/versioned.css', $result->toHtml()); + } + + public function testMixAssetMissingStartingSlashHaveItAdded() + { + $manifest = $this->makeManifest(); + + $result = mix('unversioned.css'); + + $this->assertSame('/versioned.css', $result->toHtml()); + + unlink($manifest); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage The Mix manifest does not exist. + */ + public function testMixMissingManifestThrowsException() + { + mix('unversioned.css', 'missing'); + } + + public function testMixWithManifestDirectory() + { + mkdir($directory = __DIR__.'/mix'); + $manifest = $this->makeManifest('mix'); + + $result = mix('unversioned.css', 'mix'); + + $this->assertSame('/mix/versioned.css', $result->toHtml()); + + unlink($manifest); + rmdir($directory); + } + + public function testMixManifestDirectoryMissingStartingSlashHasItAdded() + { + mkdir($directory = __DIR__.'/mix'); + $manifest = $this->makeManifest('/mix'); + + $result = mix('unversioned.css', 'mix'); + + $this->assertSame('/mix/versioned.css', $result->toHtml()); + + unlink($manifest); + rmdir($directory); + } + + public function testMixHotModuleReloadingGetsUrlFromFileWithHttps() + { + $path = $this->makeHotModuleReloadFile('https://laravel.com/docs'); + + $result = mix('unversioned.css'); + + $this->assertSame('//laravel.com/docs/unversioned.css', $result->toHtml()); + + unlink($path); + } + public function testMixHotModuleReloadingGetsUrlFromFileWithHttp() + { + $path = $this->makeHotModuleReloadFile('http://laravel.com/docs'); + + $result = mix('unversioned.css'); + + $this->assertSame('//laravel.com/docs/unversioned.css', $result->toHtml()); + + unlink($path); + } + + public function testMixHotModuleReloadingGetsUrlFromFileWithManifestDirectoryAndHttps() + { + mkdir($directory = __DIR__.'/mix'); + $path = $this->makeHotModuleReloadFile('https://laravel.com/docs', 'mix'); + + $result = mix('unversioned.css', 'mix'); + + $this->assertSame('//laravel.com/docs/unversioned.css', $result->toHtml()); + + unlink($path); + rmdir($directory); + } + + public function testMixHotModuleReloadingGetsUrlFromFileWithManifestDirectoryAndHttp() + { + mkdir($directory = __DIR__.'/mix'); + $path = $this->makeHotModuleReloadFile('http://laravel.com/docs', 'mix'); + + $result = mix('unversioned.css', 'mix'); + + $this->assertSame('//laravel.com/docs/unversioned.css', $result->toHtml()); + + unlink($path); + rmdir($directory); + } + + public function testMixHotModuleReloadingUsesLocalhostIfNoHttpScheme() + { + $path = $this->makeHotModuleReloadFile(''); + + $result = mix('unversioned.css'); + + $this->assertSame('//localhost:8080/unversioned.css', $result->toHtml()); + + unlink($path); + } + + public function testMixHotModuleReloadingWithManifestDirectoryUsesLocalhostIfNoHttpScheme() + { + mkdir($directory = __DIR__.'/mix'); + $path = $this->makeHotModuleReloadFile('', 'mix'); + + $result = mix('unversioned.css', 'mix'); + + $this->assertSame('//localhost:8080/unversioned.css', $result->toHtml()); + + unlink($path); + rmdir($directory); + } + + protected function makeHotModuleReloadFile($url, $directory = '') + { + app()->singleton('path.public', function () { + return __DIR__; + }); + + $path = public_path(str_finish($directory, '/').'hot'); + + // Laravel mix when run 'hot' has a new line after the + // url, so for consistency this "\n" is added. + file_put_contents($path, "{$url}\n"); + + return $path; + } + + protected function makeManifest($directory = '') + { app()->singleton('path.public', function () { return __DIR__; }); - touch(public_path('mix-manifest.json')); + $path = public_path(str_finish($directory, '/').'mix-manifest.json'); - file_put_contents(public_path('mix-manifest.json'), json_encode([ - '/unversioned.css' => '/versioned.css', - ])); + touch($path); - $result = mix($file); + // Laravel mix prints JSON pretty and with escaped + // slashes, so we are doing that here for consistency. + $content = json_encode(['/unversioned.css' => '/versioned.css'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); - $this->assertEquals('/versioned.css', $result); + file_put_contents($path, $content); - unlink(public_path('mix-manifest.json')); + return $path; } } From cec34795780a0e208e9f9f5e6e99d90d0d580354 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Sat, 3 Nov 2018 19:54:24 +0530 Subject: [PATCH 0759/2459] Added any method to Collection as an alias to contains --- src/Illuminate/Support/Collection.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index c12961d2433d..dbb697eb8274 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -261,6 +261,19 @@ public function contains($key, $operator = null, $value = null) return $this->contains($this->operatorForWhere(...func_get_args())); } + /** + * Alias for the "contains" method. + * + * @param mixed $key + * @param mixed $operator + * @param mixed $value + * @return bool + */ + public function any($key, $operator = null, $value = null) + { + return $this->contains($key, $operator, $value); + } + /** * Determine if an item exists in the collection using strict comparison. * From 5e47cb61e390e6aa24d05ed41e52996f200ce350 Mon Sep 17 00:00:00 2001 From: Paras Malhotra Date: Sun, 4 Nov 2018 12:34:20 +0530 Subject: [PATCH 0760/2459] renamed to some in line with other popular libraries --- src/Illuminate/Support/Collection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index dbb697eb8274..20814457f211 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -269,7 +269,7 @@ public function contains($key, $operator = null, $value = null) * @param mixed $value * @return bool */ - public function any($key, $operator = null, $value = null) + public function some($key, $operator = null, $value = null) { return $this->contains($key, $operator, $value); } From 76c0c1a43b3bd985c749a50fd309c7f8052e48b9 Mon Sep 17 00:00:00 2001 From: Albert Date: Sun, 4 Nov 2018 19:15:51 +0800 Subject: [PATCH 0761/2459] feat(TestResponse): Change implementation --- .../Foundation/Testing/TestResponse.php | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/TestResponse.php b/src/Illuminate/Foundation/Testing/TestResponse.php index 3ea14605f1bb..952fb7006b47 100644 --- a/src/Illuminate/Foundation/Testing/TestResponse.php +++ b/src/Illuminate/Foundation/Testing/TestResponse.php @@ -58,31 +58,42 @@ public static function fromBaseResponse($response) } /** - * Merge stdClass array and assoc array recursively. - * @param array $arrayStdClass - * @param array $arrayAssoc - * @return array + * JSON decode assoc and keep the empty object. + * @param string $json + * @link https://github.com/laravel/framework/issues/25769 + * @return mixed */ - public static function normalizingArraysObjects(array $arrayStdClass, array $arrayAssoc): array + public static function jsonDecodeKeepEmptyObject(string $json) { - $merged = $arrayStdClass; - - // If arrayAssoc key has in $arrayStdClass and value is not empty, replace here. - // This converts stdClass to accos array and leaves the empty stdClass - - foreach ($arrayAssoc as $key => $value) { - if (empty($value)) { - continue; + $patchEmptyObject = function ($array) use (&$patchEmptyObject) { + + // If it is an empty class,it is reserved. + // Otherwise converted into an associative array. + if (is_object($array)) { + return empty((array) $array) + ? $array + : $patchEmptyObject((array) $array); } - if (is_array($value)) { - $value = self::normalizingArraysObjects((array) $merged[$key], $value); + foreach ($array as $key => $item) { + // We recursively deal with each of these terms. + if (is_array($item) + || is_object($item) + ) { + $array[$key] = $patchEmptyObject($item); + } } - $merged[$key] = $value; + return $array; + }; + + $stdClass = json_decode($json); + + if ($stdClass === false) { + return $stdClass; } - return $merged; + return $patchEmptyObject($stdClass); } /** @@ -713,9 +724,9 @@ public function assertJsonMissingValidationErrors($keys) */ public function decodeResponseJson($key = null) { - $decodedResponseStdClass = (array) json_decode($this->getContent()); + $decodedResponse = static::jsonDecodeKeepEmptyObject($this->getContent()); - if (is_null($decodedResponseStdClass) || $decodedResponseStdClass === false) { + if (is_null($decodedResponse) || $decodedResponse === false) { if ($this->exception) { throw $this->exception; } else { @@ -723,10 +734,6 @@ public function decodeResponseJson($key = null) } } - $decodedResponseAssoc = json_decode($this->getContent(), true); - - $decodedResponse = static::normalizingArraysObjects($decodedResponseStdClass, $decodedResponseAssoc); - return data_get($decodedResponse, $key); } From bdfc993c0a5e547d01f76818e439d715a345a1e9 Mon Sep 17 00:00:00 2001 From: Hamid Alaei Varnosfaderani Date: Mon, 5 Nov 2018 03:06:25 +0330 Subject: [PATCH 0762/2459] fix redis job php doc (#26381) --- src/Illuminate/Queue/Jobs/RedisJob.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Jobs/RedisJob.php b/src/Illuminate/Queue/Jobs/RedisJob.php index d7059fd9753a..34e4fea0aef7 100644 --- a/src/Illuminate/Queue/Jobs/RedisJob.php +++ b/src/Illuminate/Queue/Jobs/RedisJob.php @@ -120,7 +120,7 @@ public function getJobId() /** * Get the underlying Redis factory implementation. * - * @return \Illuminate\Contracts\Redis\Factory + * @return \Illuminate\Queue\RedisQueue */ public function getRedisQueue() { From 996eeef6208bc7ca8d9e09feec202947014cb14e Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Mon, 5 Nov 2018 00:38:11 +0100 Subject: [PATCH 0763/2459] [5.8] Add ArrayAccess to Container contract (#26378) --- src/Illuminate/Container/Container.php | 3 +-- src/Illuminate/Contracts/Container/Container.php | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index d04acba61a7d..927760f42180 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -4,7 +4,6 @@ use Closure; use Exception; -use ArrayAccess; use LogicException; use ReflectionClass; use ReflectionParameter; @@ -12,7 +11,7 @@ use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Contracts\Container\Container as ContainerContract; -class Container implements ArrayAccess, ContainerContract +class Container implements ContainerContract { /** * The current globally available container (if any). diff --git a/src/Illuminate/Contracts/Container/Container.php b/src/Illuminate/Contracts/Container/Container.php index c2079080d1e5..9fa2114658c2 100644 --- a/src/Illuminate/Contracts/Container/Container.php +++ b/src/Illuminate/Contracts/Container/Container.php @@ -3,9 +3,10 @@ namespace Illuminate\Contracts\Container; use Closure; +use ArrayAccess; use Psr\Container\ContainerInterface; -interface Container extends ContainerInterface +interface Container extends ArrayAccess, ContainerInterface { /** * Determine if the given abstract type has been bound. From 9c737f819dc2926af312c3c2afe364c06aa09da2 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 5 Nov 2018 00:40:48 +0100 Subject: [PATCH 0764/2459] Support UNION aggregate queries (#26365) --- .../Database/Query/Grammars/Grammar.php | 19 +++++++++++++ .../Database/Query/Grammars/MySqlGrammar.php | 4 +++ .../Database/Query/Grammars/SQLiteGrammar.php | 4 +++ tests/Database/DatabaseQueryBuilderTest.php | 27 +++++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index 29b08be0619f..a9f11d25ac01 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -46,6 +46,10 @@ class Grammar extends BaseGrammar */ public function compileSelect(Builder $query) { + if ($query->unions && $query->aggregate) { + return $this->compileUnionAggregate($query); + } + // If the query does not have any columns set, we'll set the columns to the // * character to just get all of the columns from the database. Then we // can build the query and concatenate all the pieces together as one. @@ -735,6 +739,21 @@ protected function compileUnion(array $union) return $conjunction.$union['query']->toSql(); } + /** + * Compile a union aggregate query into SQL. + * + * @param \Illuminate\Database\Query\Builder $query + * @return string + */ + protected function compileUnionAggregate(Builder $query) + { + $sql = $this->compileAggregate($query, $query->aggregate); + + $query->aggregate = null; + + return $sql.' from ('.$this->compileSelect($query).') as '.$this->wrapTable('temp_table'); + } + /** * Compile an exists statement into SQL. * diff --git a/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php index 9bc33286a4b6..50af2276f3a5 100755 --- a/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/MySqlGrammar.php @@ -43,6 +43,10 @@ class MySqlGrammar extends Grammar */ public function compileSelect(Builder $query) { + if ($query->unions && $query->aggregate) { + return $this->compileUnionAggregate($query); + } + $sql = parent::compileSelect($query); if ($query->unions) { diff --git a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php index 2d8e101ab6ec..43ddec98443d 100755 --- a/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/SQLiteGrammar.php @@ -46,6 +46,10 @@ class SQLiteGrammar extends Grammar */ public function compileSelect(Builder $query) { + if ($query->unions && $query->aggregate) { + return $this->compileUnionAggregate($query); + } + $sql = parent::compileSelect($query); if ($query->unions) { diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 952eafd20d4f..299381af32b0 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -827,6 +827,33 @@ public function testMySqlUnionLimitsAndOffsets() $this->assertEquals('(select * from `users`) union (select * from `dogs`) limit 10 offset 5', $builder->toSql()); } + public function testUnionAggregate() + { + $expected = 'select count(*) as aggregate from ((select * from `posts`) union (select * from `videos`)) as `temp_table`'; + $builder = $this->getMySqlBuilder(); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getProcessor()->shouldReceive('processSelect')->once(); + $builder->from('posts')->union($this->getMySqlBuilder()->from('videos'))->count(); + + $expected = 'select count(*) as aggregate from (select * from "posts" union select * from "videos") as "temp_table"'; + $builder = $this->getPostgresBuilder(); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getProcessor()->shouldReceive('processSelect')->once(); + $builder->from('posts')->union($this->getPostgresBuilder()->from('videos'))->count(); + + $expected = 'select count(*) as aggregate from (select * from (select * from "posts") union select * from (select * from "videos")) as "temp_table"'; + $builder = $this->getSQLiteBuilder(); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getProcessor()->shouldReceive('processSelect')->once(); + $builder->from('posts')->union($this->getSQLiteBuilder()->from('videos'))->count(); + + $expected = 'select count(*) as aggregate from (select * from [posts] union select * from [videos]) as [temp_table]'; + $builder = $this->getSqlServerBuilder(); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getProcessor()->shouldReceive('processSelect')->once(); + $builder->from('posts')->union($this->getSqlServerBuilder()->from('videos'))->count(); + } + public function testSubSelectWhereIns() { $builder = $this->getBuilder(); From 536de225b1d61ccb0bff6a55f20c324026dd6adb Mon Sep 17 00:00:00 2001 From: Nguyen Xuan Quynh Date: Mon, 5 Nov 2018 10:47:43 +0700 Subject: [PATCH 0765/2459] Call a fully string command line --- src/Illuminate/Console/Application.php | 19 ++++++++++++++----- tests/Console/ConsoleApplicationTest.php | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index d57236582b19..9acbbd439535 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -9,6 +9,7 @@ use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\ConsoleOutput; @@ -172,20 +173,28 @@ public static function forgetBootstrappers() public function call($command, array $parameters = [], $outputBuffer = null) { if (is_subclass_of($command, SymfonyCommand::class)) { + $callingClass = true; $command = $this->laravel->make($command)->getName(); } + if (! isset($callingClass) && empty($parameters)) { + $command = $this->getCommandName( + $input = new StringInput($command) + ); + } else { + array_unshift($parameters, $command); + $input = new ArrayInput($parameters); + } + if (! $this->has($command)) { throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $command)); } - array_unshift($parameters, $command); - - $this->lastOutput = $outputBuffer ?: new BufferedOutput; - $this->setCatchExceptions(false); - $result = $this->run(new ArrayInput($parameters), $this->lastOutput); + $result = $this->run( + $input, $this->lastOutput = $outputBuffer ?: new BufferedOutput + ); $this->setCatchExceptions(true); diff --git a/tests/Console/ConsoleApplicationTest.php b/tests/Console/ConsoleApplicationTest.php index c19947e64994..e6460df41a46 100755 --- a/tests/Console/ConsoleApplicationTest.php +++ b/tests/Console/ConsoleApplicationTest.php @@ -50,6 +50,26 @@ public function testResolveAddsCommandViaApplicationResolution() $this->assertEquals($command, $result); } + public function testCallFullyStringCommandLine() + { + $app = new Application( + $app = m::mock(ApplicationContract::class, ['version' => '5.8']), + $events = m::mock(Dispatcher::class, ['dispatch' => null, 'fire' => null]), + 'testing' + ); + + $outputOfCallArrayInput = $app->call('help', [ + '--raw' => true, + '--format' => 'txt', + '--no-interaction' => true, + '--env' => 'testing', + ]); + + $outputOfCallStringInput = $app->call('help --raw --format=txt --no-interaction --env=testing'); + + $this->assertSame($outputOfCallArrayInput, $outputOfCallStringInput); + } + protected function getMockConsole(array $methods) { $app = m::mock(ApplicationContract::class, ['version' => '5.8']); From e2970e8752a7372109b05023e1bfa67ef89f830c Mon Sep 17 00:00:00 2001 From: Pablo Reyes Date: Mon, 5 Nov 2018 10:38:29 -0300 Subject: [PATCH 0766/2459] originalIsEquivalent is public now (#26391) --- src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php index 60e1ee4911f9..a9916f164e93 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php @@ -1129,7 +1129,7 @@ public function getChanges() * @param mixed $current * @return bool */ - protected function originalIsEquivalent($key, $current) + public function originalIsEquivalent($key, $current) { if (! array_key_exists($key, $this->original)) { return false; From 39237e5e962a69bc4bb3aa18c1c8cdd5d199e8d2 Mon Sep 17 00:00:00 2001 From: Roni Yusuf Manalu Date: Mon, 5 Nov 2018 20:41:54 +0700 Subject: [PATCH 0767/2459] Using cascade when truncating table in PostgreSQL (#26389) --- src/Illuminate/Database/Query/Grammars/PostgresGrammar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php index d9350ef7bca0..be5b882d6ac6 100755 --- a/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Query/Grammars/PostgresGrammar.php @@ -360,7 +360,7 @@ protected function compileDeleteWithJoins($query, $table) */ public function compileTruncate(Builder $query) { - return ['truncate '.$this->wrapTable($query->from).' restart identity' => []]; + return ['truncate '.$this->wrapTable($query->from).' restart identity cascade' => []]; } /** From 0095eadf99b987956b967567a9bb016188685446 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 5 Nov 2018 07:49:12 -0600 Subject: [PATCH 0768/2459] formatting. extract method --- src/Illuminate/Console/Application.php | 40 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index 9acbbd439535..3183a7309fe7 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -172,19 +172,7 @@ public static function forgetBootstrappers() */ public function call($command, array $parameters = [], $outputBuffer = null) { - if (is_subclass_of($command, SymfonyCommand::class)) { - $callingClass = true; - $command = $this->laravel->make($command)->getName(); - } - - if (! isset($callingClass) && empty($parameters)) { - $command = $this->getCommandName( - $input = new StringInput($command) - ); - } else { - array_unshift($parameters, $command); - $input = new ArrayInput($parameters); - } + [$command, $input] = $this->parseCommand($command, $parameters); if (! $this->has($command)) { throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $command)); @@ -201,6 +189,32 @@ public function call($command, array $parameters = [], $outputBuffer = null) return $result; } + /** + * Parse the incoming Artisan command and its input. + * + * @param string $command + * @param array $parameters + * @return array + */ + protected function parseCommand($command, $parameters) + { + if (is_subclass_of($command, SymfonyCommand::class)) { + $callingClass = true; + + $command = $this->laravel->make($command)->getName(); + } + + if (! isset($callingClass) && empty($parameters)) { + $command = $this->getCommandName($input = new StringInput($command)); + } else { + array_unshift($parameters, $command); + + $input = new ArrayInput($parameters); + } + + return [$command, $input ?? null]; + } + /** * Get the output for the last run command. * From cfee902511d2e97996cc71343a746f7797121108 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Mon, 5 Nov 2018 14:53:53 +0100 Subject: [PATCH 0769/2459] [5.7] Fix event dispatcher contract violations (#26379) --- src/Illuminate/Cache/Console/ClearCommand.php | 4 ++-- src/Illuminate/Console/Application.php | 4 ++-- src/Illuminate/Foundation/Application.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Cache/Console/ClearCommand.php b/src/Illuminate/Cache/Console/ClearCommand.php index c70f459a2587..4feeb17d0797 100755 --- a/src/Illuminate/Cache/Console/ClearCommand.php +++ b/src/Illuminate/Cache/Console/ClearCommand.php @@ -60,7 +60,7 @@ public function __construct(CacheManager $cache, Filesystem $files) */ public function handle() { - $this->laravel['events']->fire( + $this->laravel['events']->dispatch( 'cache:clearing', [$this->argument('store'), $this->tags()] ); @@ -72,7 +72,7 @@ public function handle() return $this->error('Failed to clear cache. Make sure you have the appropriate permissions.'); } - $this->laravel['events']->fire( + $this->laravel['events']->dispatch( 'cache:cleared', [$this->argument('store'), $this->tags()] ); diff --git a/src/Illuminate/Console/Application.php b/src/Illuminate/Console/Application.php index d57236582b19..f8b9ca4202ef 100755 --- a/src/Illuminate/Console/Application.php +++ b/src/Illuminate/Console/Application.php @@ -80,7 +80,7 @@ public function run(InputInterface $input = null, OutputInterface $output = null $input = $input ?: new ArgvInput ); - $this->events->fire( + $this->events->dispatch( new Events\CommandStarting( $commandName, $input, $output = $output ?: new ConsoleOutput ) @@ -88,7 +88,7 @@ public function run(InputInterface $input = null, OutputInterface $output = null $exitCode = parent::run($input, $output); - $this->events->fire( + $this->events->dispatch( new Events\CommandFinished($commandName, $input, $output, $exitCode) ); diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index c1973acda573..bc1a47b163ff 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -201,11 +201,11 @@ public function bootstrapWith(array $bootstrappers) $this->hasBeenBootstrapped = true; foreach ($bootstrappers as $bootstrapper) { - $this['events']->fire('bootstrapping: '.$bootstrapper, [$this]); + $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]); $this->make($bootstrapper)->bootstrap($this); - $this['events']->fire('bootstrapped: '.$bootstrapper, [$this]); + $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]); } } From 76aaaada59d75ebeef81fae08672da7764ca25dd Mon Sep 17 00:00:00 2001 From: Dimitrios Psarrou Date: Mon, 5 Nov 2018 14:55:32 +0100 Subject: [PATCH 0770/2459] allows custom formatters for slack driver (#26377) --- src/Illuminate/Log/LogManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index f0ddfc5618a5..bd3718810279 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -273,7 +273,7 @@ protected function createSlackDriver(array $config) $this->level($config), $config['bubble'] ?? true, $config['exclude_fields'] ?? [] - )), + ), $config), ]); } From 8f7e647dcee5fe13d7fc33a1e0e1ce531ea9f49e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 5 Nov 2018 07:58:00 -0600 Subject: [PATCH 0771/2459] formatting. add proxy --- src/Illuminate/Support/Collection.php | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 20814457f211..f3449cb83ac3 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -58,7 +58,7 @@ class Collection implements ArrayAccess, Arrayable, Countable, IteratorAggregate protected static $proxies = [ 'average', 'avg', 'contains', 'each', 'every', 'filter', 'first', 'flatMap', 'groupBy', 'keyBy', 'map', 'max', 'min', 'partition', - 'reject', 'sortBy', 'sortByDesc', 'sum', 'unique', + 'reject', 'some', 'sortBy', 'sortByDesc', 'sum', 'unique', ]; /** @@ -238,6 +238,19 @@ public function collapse() return new static(Arr::collapse($this->items)); } + /** + * Alias for the "contains" method. + * + * @param mixed $key + * @param mixed $operator + * @param mixed $value + * @return bool + */ + public function some($key, $operator = null, $value = null) + { + return $this->contains($key, $operator, $value); + } + /** * Determine if an item exists in the collection. * @@ -261,19 +274,6 @@ public function contains($key, $operator = null, $value = null) return $this->contains($this->operatorForWhere(...func_get_args())); } - /** - * Alias for the "contains" method. - * - * @param mixed $key - * @param mixed $operator - * @param mixed $value - * @return bool - */ - public function some($key, $operator = null, $value = null) - { - return $this->contains($key, $operator, $value); - } - /** * Determine if an item exists in the collection using strict comparison. * From 573cc964a0a70d50a7855b0185e8a0e2170b8c08 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Mon, 5 Nov 2018 19:54:24 +0100 Subject: [PATCH 0772/2459] [5.8] Add terminate method to the console Kernel contract (#26393) --- src/Illuminate/Contracts/Console/Kernel.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Illuminate/Contracts/Console/Kernel.php b/src/Illuminate/Contracts/Console/Kernel.php index 79889e6f6c71..a7423af3a6c1 100644 --- a/src/Illuminate/Contracts/Console/Kernel.php +++ b/src/Illuminate/Contracts/Console/Kernel.php @@ -45,4 +45,13 @@ public function all(); * @return string */ public function output(); + + /** + * Terminate the application. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param int $status + * @return void + */ + public function terminate($input, $status); } From 090e406cc790ea9bac0fd0e505a70af90d75b9d5 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 5 Nov 2018 12:55:15 -0600 Subject: [PATCH 0773/2459] [5.8] Remove `fire` method (#26392) * remove `fire` methods these are aliases to the `dispatch()` method. * fix events dispatcher tests update to use `dispatch()` method, as dictated by the contract. --- src/Illuminate/Events/Dispatcher.php | 13 --------- .../Support/Testing/Fakes/EventFake.php | 13 --------- tests/Events/EventsDispatcherTest.php | 28 +++++++++---------- 3 files changed, 14 insertions(+), 40 deletions(-) diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php index 8fb73bac39a8..95826c0d827e 100755 --- a/src/Illuminate/Events/Dispatcher.php +++ b/src/Illuminate/Events/Dispatcher.php @@ -169,19 +169,6 @@ public function until($event, $payload = []) return $this->dispatch($event, $payload, true); } - /** - * Fire an event and call the listeners. - * - * @param string|object $event - * @param mixed $payload - * @param bool $halt - * @return array|null - */ - public function fire($event, $payload = [], $halt = false) - { - return $this->dispatch($event, $payload, $halt); - } - /** * Fire an event and call the listeners. * diff --git a/src/Illuminate/Support/Testing/Fakes/EventFake.php b/src/Illuminate/Support/Testing/Fakes/EventFake.php index 57e47c89f378..8fd018d5ad1a 100644 --- a/src/Illuminate/Support/Testing/Fakes/EventFake.php +++ b/src/Illuminate/Support/Testing/Fakes/EventFake.php @@ -183,19 +183,6 @@ public function flush($event) // } - /** - * Fire an event and call the listeners. - * - * @param string|object $event - * @param mixed $payload - * @param bool $halt - * @return array|null - */ - public function fire($event, $payload = [], $halt = false) - { - return $this->dispatch($event, $payload, $halt); - } - /** * Fire an event and call the listeners. * diff --git a/tests/Events/EventsDispatcherTest.php b/tests/Events/EventsDispatcherTest.php index 5dc334e7aa13..c73ebc39483e 100755 --- a/tests/Events/EventsDispatcherTest.php +++ b/tests/Events/EventsDispatcherTest.php @@ -26,7 +26,7 @@ public function testBasicEventExecution() $d->listen('foo', function ($foo) { $_SERVER['__event.test'] = $foo; }); - $d->fire('foo', ['bar']); + $d->dispatch('foo', ['bar']); $this->assertEquals('bar', $_SERVER['__event.test']); } @@ -51,7 +51,7 @@ public function testContainerResolutionOfEventHandlers() $container->shouldReceive('make')->once()->with('FooHandler')->andReturn($handler = m::mock(stdClass::class)); $handler->shouldReceive('onFooEvent')->once()->with('foo', 'bar'); $d->listen('foo', 'FooHandler@onFooEvent'); - $d->fire('foo', ['foo', 'bar']); + $d->dispatch('foo', ['foo', 'bar']); } public function testContainerResolutionOfEventHandlersWithDefaultMethods() @@ -60,7 +60,7 @@ public function testContainerResolutionOfEventHandlersWithDefaultMethods() $container->shouldReceive('make')->once()->with('FooHandler')->andReturn($handler = m::mock(stdClass::class)); $handler->shouldReceive('handle')->once()->with('foo', 'bar'); $d->listen('foo', 'FooHandler'); - $d->fire('foo', ['foo', 'bar']); + $d->dispatch('foo', ['foo', 'bar']); } public function testQueuedEventsAreFired() @@ -104,7 +104,7 @@ public function testWildcardListeners() $d->listen('bar.*', function () { $_SERVER['__event.test'] = 'nope'; }); - $d->fire('foo.bar'); + $d->dispatch('foo.bar'); $this->assertEquals('wildcard', $_SERVER['__event.test']); } @@ -116,13 +116,13 @@ public function testWildcardListenersCacheFlushing() $d->listen('foo.*', function () { $_SERVER['__event.test'] = 'cached_wildcard'; }); - $d->fire('foo.bar'); + $d->dispatch('foo.bar'); $this->assertEquals('cached_wildcard', $_SERVER['__event.test']); $d->listen('foo.*', function () { $_SERVER['__event.test'] = 'new_wildcard'; }); - $d->fire('foo.bar'); + $d->dispatch('foo.bar'); $this->assertEquals('new_wildcard', $_SERVER['__event.test']); } @@ -134,7 +134,7 @@ public function testListenersCanBeRemoved() $_SERVER['__event.test'] = 'foo'; }); $d->forget('foo'); - $d->fire('foo'); + $d->dispatch('foo'); $this->assertFalse(isset($_SERVER['__event.test'])); } @@ -147,7 +147,7 @@ public function testWildcardListenersCanBeRemoved() $_SERVER['__event.test'] = 'foo'; }); $d->forget('foo.*'); - $d->fire('foo.bar'); + $d->dispatch('foo.bar'); $this->assertFalse(isset($_SERVER['__event.test'])); } @@ -181,14 +181,14 @@ public function testEventPassedFirstToWildcards() $this->assertEquals('foo.bar', $event); $this->assertEquals(['first', 'second'], $data); }); - $d->fire('foo.bar', ['first', 'second']); + $d->dispatch('foo.bar', ['first', 'second']); $d = new Dispatcher; $d->listen('foo.bar', function ($first, $second) { $this->assertEquals('first', $first); $this->assertEquals('second', $second); }); - $d->fire('foo.bar', ['first', 'second']); + $d->dispatch('foo.bar', ['first', 'second']); } public function testQueuedEventHandlersAreQueued() @@ -205,7 +205,7 @@ public function testQueuedEventHandlersAreQueued() }); $d->listen('some.event', TestDispatcherQueuedHandler::class.'@someMethod'); - $d->fire('some.event', ['foo', 'bar']); + $d->dispatch('some.event', ['foo', 'bar']); } public function testClassesWork() @@ -215,7 +215,7 @@ public function testClassesWork() $d->listen(ExampleEvent::class, function () { $_SERVER['__event.test'] = 'baz'; }); - $d->fire(new ExampleEvent); + $d->dispatch(new ExampleEvent); $this->assertSame('baz', $_SERVER['__event.test']); } @@ -227,7 +227,7 @@ public function testInterfacesWork() $d->listen(SomeEventInterface::class, function () { $_SERVER['__event.test'] = 'bar'; }); - $d->fire(new AnotherEvent); + $d->dispatch(new AnotherEvent); $this->assertSame('bar', $_SERVER['__event.test']); } @@ -242,7 +242,7 @@ public function testBothClassesAndInterfacesWork() $d->listen(SomeEventInterface::class, function () { $_SERVER['__event.test2'] = 'baar'; }); - $d->fire(new AnotherEvent); + $d->dispatch(new AnotherEvent); $this->assertSame('fooo', $_SERVER['__event.test1']); $this->assertSame('baar', $_SERVER['__event.test2']); From b3c75ce2854c66f54ff301f6e2f612202b7fd65c Mon Sep 17 00:00:00 2001 From: Toni Peric Date: Mon, 5 Nov 2018 22:46:54 +0100 Subject: [PATCH 0774/2459] Add human-friendly message to MethodNotAllowedHttpException Closes #26355 --- src/Illuminate/Routing/RouteCollection.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Routing/RouteCollection.php b/src/Illuminate/Routing/RouteCollection.php index 265d2823e9eb..36c4bb198704 100644 --- a/src/Illuminate/Routing/RouteCollection.php +++ b/src/Illuminate/Routing/RouteCollection.php @@ -239,20 +239,28 @@ protected function getRouteForMethods($request, array $methods) }))->bind($request); } - $this->methodNotAllowed($methods); + $this->methodNotAllowed($methods, $request->method()); } /** * Throw a method not allowed HTTP exception. * * @param array $others + * @param string $method * @return void * * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException */ - protected function methodNotAllowed(array $others) + protected function methodNotAllowed(array $others, $method) { - throw new MethodNotAllowedHttpException($others); + throw new MethodNotAllowedHttpException( + $others, + sprintf( + 'Method %s is not allowed. Allowed methods: %s.', + $method, + implode(', ', $others) + ) + ); } /** From b87d53f9bc27d5b7ce04bca1bc27bc00ea5d9e4b Mon Sep 17 00:00:00 2001 From: Lucas Leandro Date: Tue, 6 Nov 2018 14:18:38 -0200 Subject: [PATCH 0775/2459] allow pass absolute parameter in has valid signature request macro (#26397) --- .../Foundation/Providers/FoundationServiceProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index b12c1799aed7..ce31986a51e9 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -49,8 +49,8 @@ public function registerRequestValidation() */ public function registerRequestSignatureValidation() { - Request::macro('hasValidSignature', function () { - return URL::hasValidSignature($this); + Request::macro('hasValidSignature', function ($absolute = true) { + return URL::hasValidSignature($this, $absolute); }); } } From d05f93e6e2402c5ae8c33e6cb4e2fe305c712318 Mon Sep 17 00:00:00 2001 From: Rodrigo Azevedo Date: Tue, 6 Nov 2018 14:22:44 -0200 Subject: [PATCH 0776/2459] Fix SoftDeletes Query (#26396) --- src/Illuminate/Database/Eloquent/SoftDeletes.php | 4 ++-- tests/Database/DatabaseSoftDeletingTraitTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/SoftDeletes.php b/src/Illuminate/Database/Eloquent/SoftDeletes.php index d8b736306813..b97573cd30a9 100644 --- a/src/Illuminate/Database/Eloquent/SoftDeletes.php +++ b/src/Illuminate/Database/Eloquent/SoftDeletes.php @@ -49,7 +49,7 @@ protected function performDeleteOnModel() if ($this->forceDeleting) { $this->exists = false; - return $this->newModelQuery()->where($this->getKeyName(), $this->getKey())->forceDelete(); + return $this->setKeysForSaveQuery($this->newModelQuery())->forceDelete(); } return $this->runSoftDelete(); @@ -62,7 +62,7 @@ protected function performDeleteOnModel() */ protected function runSoftDelete() { - $query = $this->newModelQuery()->where($this->getKeyName(), $this->getKey()); + $query = $this->setKeysForSaveQuery($this->newModelQuery()); $time = $this->freshTimestamp(); diff --git a/tests/Database/DatabaseSoftDeletingTraitTest.php b/tests/Database/DatabaseSoftDeletingTraitTest.php index 9f328db1c858..9eb30354523b 100644 --- a/tests/Database/DatabaseSoftDeletingTraitTest.php +++ b/tests/Database/DatabaseSoftDeletingTraitTest.php @@ -19,7 +19,7 @@ public function testDeleteSetsSoftDeletedColumn() $model = m::mock(DatabaseSoftDeletingTraitStub::class); $model->shouldDeferMissing(); $model->shouldReceive('newModelQuery')->andReturn($query = m::mock(stdClass::class)); - $query->shouldReceive('where')->once()->with('id', 1)->andReturn($query); + $model->shouldReceive('setKeysForSaveQuery')->once()->with($query)->andReturn($query); $query->shouldReceive('update')->once()->with([ 'deleted_at' => 'date-time', 'updated_at' => 'date-time', From 17163b46d0a1d88160dab681d699f9e694d8c1c8 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 6 Nov 2018 10:23:33 -0600 Subject: [PATCH 0777/2459] Revert "Fix SoftDeletes Query (#26396)" (#26406) This reverts commit d05f93e6e2402c5ae8c33e6cb4e2fe305c712318. --- src/Illuminate/Database/Eloquent/SoftDeletes.php | 4 ++-- tests/Database/DatabaseSoftDeletingTraitTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/SoftDeletes.php b/src/Illuminate/Database/Eloquent/SoftDeletes.php index b97573cd30a9..d8b736306813 100644 --- a/src/Illuminate/Database/Eloquent/SoftDeletes.php +++ b/src/Illuminate/Database/Eloquent/SoftDeletes.php @@ -49,7 +49,7 @@ protected function performDeleteOnModel() if ($this->forceDeleting) { $this->exists = false; - return $this->setKeysForSaveQuery($this->newModelQuery())->forceDelete(); + return $this->newModelQuery()->where($this->getKeyName(), $this->getKey())->forceDelete(); } return $this->runSoftDelete(); @@ -62,7 +62,7 @@ protected function performDeleteOnModel() */ protected function runSoftDelete() { - $query = $this->setKeysForSaveQuery($this->newModelQuery()); + $query = $this->newModelQuery()->where($this->getKeyName(), $this->getKey()); $time = $this->freshTimestamp(); diff --git a/tests/Database/DatabaseSoftDeletingTraitTest.php b/tests/Database/DatabaseSoftDeletingTraitTest.php index 9eb30354523b..9f328db1c858 100644 --- a/tests/Database/DatabaseSoftDeletingTraitTest.php +++ b/tests/Database/DatabaseSoftDeletingTraitTest.php @@ -19,7 +19,7 @@ public function testDeleteSetsSoftDeletedColumn() $model = m::mock(DatabaseSoftDeletingTraitStub::class); $model->shouldDeferMissing(); $model->shouldReceive('newModelQuery')->andReturn($query = m::mock(stdClass::class)); - $model->shouldReceive('setKeysForSaveQuery')->once()->with($query)->andReturn($query); + $query->shouldReceive('where')->once()->with('id', 1)->andReturn($query); $query->shouldReceive('update')->once()->with([ 'deleted_at' => 'date-time', 'updated_at' => 'date-time', From 9859d173d59701d7afe558362d8ef7aa25b85284 Mon Sep 17 00:00:00 2001 From: Ilya Sakovich Date: Tue, 6 Nov 2018 19:12:19 +0200 Subject: [PATCH 0778/2459] Session persisting fix. --- .../Session/Middleware/StartSession.php | 48 +++++-------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index b47fde27aaac..5626d799d334 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -20,13 +20,6 @@ class StartSession */ protected $manager; - /** - * Indicates if the session was handled for the current request. - * - * @var bool - */ - protected $sessionHandled = false; - /** * Create a new session middleware. * @@ -47,45 +40,30 @@ public function __construct(SessionManager $manager) */ public function handle($request, Closure $next) { - $this->sessionHandled = true; - - // If a session driver has been configured, we will need to start the session here - // so that the data is ready for an application. Note that the Laravel sessions - // do not make use of PHP "native" sessions in any way since they are crappy. if ($this->sessionConfigured()) { + // First of all, we need to start the session here so that the data + // is ready for an application. Note that the Laravel sessions do not + // make use of PHP "native" sessions in any way since they are crappy. $request->setLaravelSession( $session = $this->startSession($request) ); $this->collectGarbage($session); - } - $response = $next($request); - - // Again, if the session has been configured we will need to close out the session - // so that the attributes may be persisted to some storage medium. We will also - // add the session identifier cookie to the application response headers now. - if ($this->sessionConfigured()) { $this->storeCurrentUrl($request, $session); - $this->addCookieToResponse($response, $session); - } + $response = $next($request); - return $response; - } + // Then we need to add the session identifier cookie + // to the application response headers. + $this->addCookieToResponse($response, $session); - /** - * Perform any final actions for the request lifecycle. - * - * @param \Illuminate\Http\Request $request - * @param \Symfony\Component\HttpFoundation\Response $response - * @return void - */ - public function terminate($request, $response) - { - if ($this->sessionHandled && $this->sessionConfigured() && ! $this->usingCookieSessions()) { + // And finally we need to persist the session attributes + // to some storage medium. $this->manager->driver()->save(); } + + return $response ?? $next($request); } /** @@ -168,10 +146,6 @@ protected function storeCurrentUrl(Request $request, $session) */ protected function addCookieToResponse(Response $response, Session $session) { - if ($this->usingCookieSessions()) { - $this->manager->driver()->save(); - } - if ($this->sessionIsPersistent($config = $this->manager->getSessionConfig())) { $response->headers->setCookie(new Cookie( $session->getName(), $session->getId(), $this->getCookieExpirationDate(), From 3d42a87fe3f459cb92dbece9040addf9a950dbec Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Tue, 6 Nov 2018 17:26:32 +0000 Subject: [PATCH 0779/2459] Fixed formatting --- src/Illuminate/Routing/RouteCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/RouteCollection.php b/src/Illuminate/Routing/RouteCollection.php index 36c4bb198704..ca8f241f0a7a 100644 --- a/src/Illuminate/Routing/RouteCollection.php +++ b/src/Illuminate/Routing/RouteCollection.php @@ -246,7 +246,7 @@ protected function getRouteForMethods($request, array $methods) * Throw a method not allowed HTTP exception. * * @param array $others - * @param string $method + * @param string $method * @return void * * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException From 64662b94a72c8d6060f15b317bbf87a7aae8bc0b Mon Sep 17 00:00:00 2001 From: Ilya Sakovich Date: Tue, 6 Nov 2018 22:41:28 +0200 Subject: [PATCH 0780/2459] Removed extra comments. --- src/Illuminate/Session/Middleware/StartSession.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index 5626d799d334..b5569edf7df4 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -41,9 +41,6 @@ public function __construct(SessionManager $manager) public function handle($request, Closure $next) { if ($this->sessionConfigured()) { - // First of all, we need to start the session here so that the data - // is ready for an application. Note that the Laravel sessions do not - // make use of PHP "native" sessions in any way since they are crappy. $request->setLaravelSession( $session = $this->startSession($request) ); @@ -54,12 +51,8 @@ public function handle($request, Closure $next) $response = $next($request); - // Then we need to add the session identifier cookie - // to the application response headers. $this->addCookieToResponse($response, $session); - // And finally we need to persist the session attributes - // to some storage medium. $this->manager->driver()->save(); } From 3a550a14d4ff6d3cb0d13d0bc515ddc7573c131b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 6 Nov 2018 15:51:56 -0500 Subject: [PATCH 0781/2459] formatting --- src/Illuminate/Routing/RouteCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Routing/RouteCollection.php b/src/Illuminate/Routing/RouteCollection.php index ca8f241f0a7a..1c7879d562f3 100644 --- a/src/Illuminate/Routing/RouteCollection.php +++ b/src/Illuminate/Routing/RouteCollection.php @@ -256,7 +256,7 @@ protected function methodNotAllowed(array $others, $method) throw new MethodNotAllowedHttpException( $others, sprintf( - 'Method %s is not allowed. Allowed methods: %s.', + 'The %s method is not supported for this route. Supported methods: %s.', $method, implode(', ', $others) ) From 4195a640183d0ded69892ad961dceadb8d39678c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 6 Nov 2018 16:04:45 -0500 Subject: [PATCH 0782/2459] formatting --- src/Illuminate/View/FileViewFinder.php | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index 55a9acdda31c..bfd3b9e62cb8 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -53,7 +53,7 @@ class FileViewFinder implements ViewFinderInterface public function __construct(Filesystem $files, array $paths, array $extensions = null) { $this->files = $files; - $this->paths = array_map([$this, 'normalizePath'], $paths); + $this->paths = array_map([$this, 'resolvePath'], $paths); if (isset($extensions)) { $this->extensions = $extensions; @@ -158,7 +158,7 @@ protected function getPossibleViewFiles($name) */ public function addLocation($location) { - $this->paths[] = $this->normalizePath($location); + $this->paths[] = $this->resolvePath($location); } /** @@ -169,7 +169,18 @@ public function addLocation($location) */ public function prependLocation($location) { - array_unshift($this->paths, $this->normalizePath($location)); + array_unshift($this->paths, $this->resolvePath($location)); + } + + /** + * Resolve the path. + * + * @param string $path + * @return string + */ + protected function resolvePath($path) + { + return realpath($path) ?: $path; } /** @@ -295,15 +306,4 @@ public function getExtensions() { return $this->extensions; } - - /** - * Replace unnecessary relative fragments from the absolute view path. - * - * @param string $path - * @return string - */ - protected function normalizePath($path) - { - return realpath($path) ?: $path; - } } From 2ee18923eaff142a89439f0adf0d3f15c30db85b Mon Sep 17 00:00:00 2001 From: wang Date: Wed, 7 Nov 2018 06:05:52 +0900 Subject: [PATCH 0783/2459] [5.8] `BelongsTo` method name consistency refactoring (#26374) * Add `getChild` public method. * add `Name` as the suffix. --- .../Database/Eloquent/Relations/BelongsTo.php | 20 ++++++++++++++----- tests/Database/DatabaseEloquentModelTest.php | 12 +++++------ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php index 3259bdcd1499..a46f7db84c3b 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php @@ -253,7 +253,7 @@ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, } return $query->select($columns)->whereColumn( - $this->getQualifiedForeignKey(), '=', $query->qualifyColumn($this->ownerKey) + $this->getQualifiedForeignKeyName(), '=', $query->qualifyColumn($this->ownerKey) ); } @@ -274,7 +274,7 @@ public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder $query->getModel()->setTable($hash); return $query->whereColumn( - $hash.'.'.$this->ownerKey, '=', $this->getQualifiedForeignKey() + $hash.'.'.$this->ownerKey, '=', $this->getQualifiedForeignKeyName() ); } @@ -310,12 +310,22 @@ protected function newRelatedInstanceFor(Model $parent) return $this->related->newInstance(); } + /** + * Get the child of the relationship. + * + * @return \Illuminate\Database\Eloquent\Model + */ + public function getChild() + { + return $this->child; + } + /** * Get the foreign key of the relationship. * * @return string */ - public function getForeignKey() + public function getForeignKeyName() { return $this->foreignKey; } @@ -325,7 +335,7 @@ public function getForeignKey() * * @return string */ - public function getQualifiedForeignKey() + public function getQualifiedForeignKeyName() { return $this->child->qualifyColumn($this->foreignKey); } @@ -335,7 +345,7 @@ public function getQualifiedForeignKey() * * @return string */ - public function getOwnerKey() + public function getOwnerKeyName() { return $this->ownerKey; } diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 762c79976763..236501326e39 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -1071,14 +1071,14 @@ public function testBelongsToCreatesProperRelation() $model = new EloquentModelStub; $this->addMockConnection($model); $relation = $model->belongsToStub(); - $this->assertEquals('belongs_to_stub_id', $relation->getForeignKey()); + $this->assertEquals('belongs_to_stub_id', $relation->getForeignKeyName()); $this->assertSame($model, $relation->getParent()); $this->assertInstanceOf(EloquentModelSaveStub::class, $relation->getQuery()->getModel()); $model = new EloquentModelStub; $this->addMockConnection($model); $relation = $model->belongsToExplicitKeyStub(); - $this->assertEquals('foo', $relation->getForeignKey()); + $this->assertEquals('foo', $relation->getForeignKeyName()); } public function testMorphToCreatesProperRelation() @@ -1088,7 +1088,7 @@ public function testMorphToCreatesProperRelation() // $this->morphTo(); $relation = $model->morphToStub(); - $this->assertEquals('morph_to_stub_id', $relation->getForeignKey()); + $this->assertEquals('morph_to_stub_id', $relation->getForeignKeyName()); $this->assertEquals('morph_to_stub_type', $relation->getMorphType()); $this->assertEquals('morphToStub', $relation->getRelation()); $this->assertSame($model, $relation->getParent()); @@ -1096,19 +1096,19 @@ public function testMorphToCreatesProperRelation() // $this->morphTo(null, 'type', 'id'); $relation2 = $model->morphToStubWithKeys(); - $this->assertEquals('id', $relation2->getForeignKey()); + $this->assertEquals('id', $relation2->getForeignKeyName()); $this->assertEquals('type', $relation2->getMorphType()); $this->assertEquals('morphToStubWithKeys', $relation2->getRelation()); // $this->morphTo('someName'); $relation3 = $model->morphToStubWithName(); - $this->assertEquals('some_name_id', $relation3->getForeignKey()); + $this->assertEquals('some_name_id', $relation3->getForeignKeyName()); $this->assertEquals('some_name_type', $relation3->getMorphType()); $this->assertEquals('someName', $relation3->getRelation()); // $this->morphTo('someName', 'type', 'id'); $relation4 = $model->morphToStubWithNameAndKeys(); - $this->assertEquals('id', $relation4->getForeignKey()); + $this->assertEquals('id', $relation4->getForeignKeyName()); $this->assertEquals('type', $relation4->getMorphType()); $this->assertEquals('someName', $relation4->getRelation()); } From 87ef35362234c47e868fb19e4f7fad5371f0fe42 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Wed, 7 Nov 2018 23:29:47 +1100 Subject: [PATCH 0784/2459] add mix intergration tests (#26416) --- .../Foundation/FoundationHelpersTest.php | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/Integration/Foundation/FoundationHelpersTest.php b/tests/Integration/Foundation/FoundationHelpersTest.php index 8ba83ad9ef59..95d614c8452b 100644 --- a/tests/Integration/Foundation/FoundationHelpersTest.php +++ b/tests/Integration/Foundation/FoundationHelpersTest.php @@ -4,6 +4,7 @@ use Exception; use Orchestra\Testbench\TestCase; +use Illuminate\Contracts\Debug\ExceptionHandler; /** * @group integration @@ -37,4 +38,77 @@ public function test(int $a) $testClass->test([]); }, 'rescued!'), 'rescued!'); } + + public function testMixReportsExceptionWhenAssetIsMissingFromManifest() + { + $handler = new FakeHandler; + $this->app->instance(ExceptionHandler::class, $handler); + $manifest = $this->makeManifest(); + + mix('missing.js'); + + $this->assertInstanceOf(Exception::class, $handler->reported); + $this->assertSame('Unable to locate Mix file: /missing.js.', $handler->reported->getMessage()); + + unlink($manifest); + } + + public function testMixSilentlyFailsWhenAssetIsMissingFromManifestWhenNotInDebugMode() + { + $this->app['config']->set('app.debug', false); + $manifest = $this->makeManifest(); + + $path = mix('missing.js'); + + $this->assertSame('/missing.js', $path); + + unlink($manifest); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Undefined index: /missing.js + */ + public function testMixThrowsExceptionWhenAssetIsMissingFromManifestWhenInDebugMode() + { + $this->app['config']->set('app.debug', true); + $manifest = $this->makeManifest(); + + try { + mix('missing.js'); + } catch (\Exception $e) { + throw $e; + } finally { // make sure we can cleanup the file + unlink($manifest); + } + } + + protected function makeManifest($directory = '') + { + $this->app->singleton('path.public', function () { + return __DIR__; + }); + + $path = public_path(str_finish($directory, '/').'mix-manifest.json'); + + touch($path); + + // Laravel mix prints JSON pretty and with escaped + // slashes, so we are doing that here for consistency. + $content = json_encode(['/unversioned.css' => '/versioned.css'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + + file_put_contents($path, $content); + + return $path; + } +} + +class FakeHandler +{ + public $reported; + + public function report($exception) + { + $this->reported = $exception; + } } From b70ec729f8459140505bae0f6a5699c2fc813ef7 Mon Sep 17 00:00:00 2001 From: Sjors Date: Wed, 7 Nov 2018 13:30:30 +0100 Subject: [PATCH 0785/2459] Fix multi-word models with irregular plurals --- src/Illuminate/Database/Eloquent/Model.php | 10 +- .../Eloquent/Relations/BelongsToMany.php | 2 +- .../Foundation/Console/ModelMakeCommand.php | 2 +- src/Illuminate/Support/Str.php | 16 +++ .../DatabaseEloquentIrregularPluralTest.php | 117 ++++++++++++++++++ tests/Support/SupportPluralizerTest.php | 24 ++++ 6 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 tests/Database/DatabaseEloquentIrregularPluralTest.php diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 6cbfd4e18f65..3a4e7a97a6e7 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1277,13 +1277,9 @@ public static function unsetConnectionResolver() */ public function getTable() { - if (! isset($this->table)) { - return str_replace( - '\\', '', Str::snake(Str::plural(class_basename($this))) - ); - } - - return $this->table; + return isset($this->table) + ? $this->table + : Str::snake(Str::pluralStudly(class_basename($this))); } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index d1a1242df69f..e24bad8aff32 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -766,7 +766,7 @@ protected function touchingParent() */ protected function guessInverseRelation() { - return Str::camel(Str::plural(class_basename($this->getParent()))); + return Str::camel(Str::pluralStudly(class_basename($this->getParent()))); } /** diff --git a/src/Illuminate/Foundation/Console/ModelMakeCommand.php b/src/Illuminate/Foundation/Console/ModelMakeCommand.php index c44038a97650..cbe5332df0d2 100644 --- a/src/Illuminate/Foundation/Console/ModelMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ModelMakeCommand.php @@ -82,7 +82,7 @@ protected function createFactory() */ protected function createMigration() { - $table = Str::plural(Str::snake(class_basename($this->argument('name')))); + $table = Str::snake(Str::pluralStudly(class_basename($this->argument('name')))); if ($this->option('pivot')) { $table = Str::singular($table); diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 752a82de421e..2f1c13ad6519 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -280,6 +280,22 @@ public static function plural($value, $count = 2) return Pluralizer::plural($value, $count); } + /** + * Pluralize the last word of an English, studly caps case string. + * + * @param string $value + * @param int $count + * @return string + */ + public static function pluralStudly($value, $count = 2) + { + $parts = preg_split('/(.)(?=[A-Z])/u', $value, -1, PREG_SPLIT_DELIM_CAPTURE); + + $lastWord = array_pop($parts); + + return implode('', $parts).self::plural($lastWord, $count); + } + /** * Generate a more truly "random" alpha-numeric string. * diff --git a/tests/Database/DatabaseEloquentIrregularPluralTest.php b/tests/Database/DatabaseEloquentIrregularPluralTest.php new file mode 100644 index 000000000000..bb1385563d50 --- /dev/null +++ b/tests/Database/DatabaseEloquentIrregularPluralTest.php @@ -0,0 +1,117 @@ +addConnection([ + 'driver' => 'sqlite', + 'database' => ':memory:', + ]); + + $db->bootEloquent(); + $db->setAsGlobal(); + $this->createSchema(); + } + + public function createSchema() + { + $this->schema()->create('irregular_plural_humans', function ($table) { + $table->increments('id'); + $table->string('email')->unique(); + $table->timestamps(); + }); + + $this->schema()->create('irregular_plural_tokens', function ($table) { + $table->increments('id'); + $table->string('title'); + }); + + $this->schema()->create('irregular_plural_human_irregular_plural_token', function ($table) { + $table->integer('irregular_plural_human_id')->unsigned(); + $table->integer('irregular_plural_token_id')->unsigned(); + }); + } + + public function tearDown() + { + $this->schema()->drop('irregular_plural_tokens'); + $this->schema()->drop('irregular_plural_humans'); + $this->schema()->drop('irregular_plural_human_irregular_plural_token'); + } + + protected function schema() + { + $connection = Model::getConnectionResolver()->connection(); + + return $connection->getSchemaBuilder(); + } + + /** @test */ + function it_pluralizes_the_table_name() + { + $model = new IrregularPluralHuman(); + + $this->assertSame('irregular_plural_humans', $model->getTable()); + } + + /** @test */ + function it_touches_the_parent_with_an_irregular_plural() + { + Carbon::setTestNow('2018-05-01 12:13:14'); + + IrregularPluralHuman::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); + + IrregularPluralToken::insert([ + ['title' => 'The title'], + ]); + + $human = IrregularPluralHuman::query()->first(); + + $tokenIds = IrregularPluralToken::pluck('id'); + + Carbon::setTestNow('2018-05-01 15:16:17'); + + $human->irregularPluralTokens()->sync($tokenIds); + + $human->refresh(); + + $this->assertSame('2018-05-01 12:13:14', (string) $human->created_at); + $this->assertSame('2018-05-01 15:16:17', (string) $human->updated_at); + } +} + +class IrregularPluralHuman extends Model +{ + protected $guarded = []; + + public function irregularPluralTokens() + { + return $this->belongsToMany( + IrregularPluralToken::class, + 'irregular_plural_human_irregular_plural_token', + 'irregular_plural_token_id', + 'irregular_plural_human_id' + ); + } +} + +class IrregularPluralToken extends Model +{ + protected $guarded = []; + + public $timestamps = false; + + protected $touches = [ + 'irregularPluralHumans', + ]; +} diff --git a/tests/Support/SupportPluralizerTest.php b/tests/Support/SupportPluralizerTest.php index 2461bcc5b224..5b128217f81f 100755 --- a/tests/Support/SupportPluralizerTest.php +++ b/tests/Support/SupportPluralizerTest.php @@ -38,6 +38,9 @@ public function testIfEndOfWordPlural() $this->assertEquals('MatrixFields', Str::plural('MatrixField')); $this->assertEquals('IndexFields', Str::plural('IndexField')); $this->assertEquals('VertexFields', Str::plural('VertexField')); + + // This is expected behavior, use "Str::pluralStudly" instead. + $this->assertSame('RealHumen', Str::plural('RealHuman')); } public function testPluralWithNegativeCount() @@ -47,4 +50,25 @@ public function testPluralWithNegativeCount() $this->assertEquals('test', Str::plural('test', -1)); $this->assertEquals('tests', Str::plural('test', -2)); } + + public function testPluralStudly() + { + $this->assertPluralStudly('RealHumans', 'RealHuman'); + $this->assertPluralStudly('Models', 'Model'); + $this->assertPluralStudly('VortexFields', 'VortexField'); + $this->assertPluralStudly('MultipleWordsInOneStrings', 'MultipleWordsInOneString'); + } + + public function testPluralStudlyWithCount() + { + $this->assertPluralStudly('RealHuman', 'RealHuman', 1); + $this->assertPluralStudly('RealHumans', 'RealHuman', 2); + $this->assertPluralStudly('RealHuman', 'RealHuman', -1); + $this->assertPluralStudly('RealHumans', 'RealHuman', -2); + } + + private function assertPluralStudly($expected, $value, $count = 2) + { + $this->assertSame($expected, Str::pluralStudly($value, $count)); + } } From e8f31f149948cad5b3e42aeb5ff3ce1e1ab5514e Mon Sep 17 00:00:00 2001 From: TSURU Date: Wed, 7 Nov 2018 16:01:55 +0900 Subject: [PATCH 0786/2459] Fix validate method --- .../Contracts/Validation/Validator.php | 7 +++++ .../Foundation/Http/FormRequest.php | 2 +- src/Illuminate/Validation/Validator.php | 16 ++++++++++ tests/Validation/ValidationValidatorTest.php | 31 +++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Contracts/Validation/Validator.php b/src/Illuminate/Contracts/Validation/Validator.php index b69942b5f013..10396df28b49 100644 --- a/src/Illuminate/Contracts/Validation/Validator.php +++ b/src/Illuminate/Contracts/Validation/Validator.php @@ -13,6 +13,13 @@ interface Validator extends MessageProvider */ public function validate(); + /** + * Return validated value. + * + * @return array + */ + public function validated(); + /** * Determine if the data fails the validation rules. * diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 53a4ec83bd5a..22883d4b78ac 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -172,7 +172,7 @@ protected function failedAuthorization() */ public function validated() { - return $this->getValidatorInstance()->validate(); + return $this->getValidatorInstance()->validated(); } /** diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 21387d9908a2..1671f81b4abf 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -306,6 +306,22 @@ public function validate() throw new ValidationException($this); } + return $this->validated(); + } + + /** + * Return validated value. + * + * @return array + * + * @throws \Illuminate\Validation\ValidationException + */ + public function validated() + { + if ($this->invalid()) { + throw new ValidationException($this); + } + $results = []; $missingValue = Str::random(10); diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 501afa4eadf6..e4c8717778aa 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -4254,6 +4254,37 @@ public function testValidateReturnsValidatedDataNestedArrayRules() $this->assertEquals(['nested' => [['bar' => 'baz'], ['bar' => 'baz2']]], $data); } + public function testValidateAndValidatedData() + { + $post = ['first' => 'john', 'preferred'=>'john', 'last' => 'doe', 'type' => 'admin']; + + $v = new Validator($this->getIlluminateArrayTranslator(), $post, ['first' => 'required', 'preferred'=> 'required']); + $v->sometimes('type', 'required', function () { + return false; + }); + $data = $v->validate(); + $validatedData = $v->validated(); + + $this->assertEquals(['first' => 'john', 'preferred' => 'john'], $data); + $this->assertEquals($data, $validatedData); + } + + public function testValidatedNotValidateTwiceData() + { + $post = ['first' => 'john', 'preferred'=>'john', 'last' => 'doe', 'type' => 'admin']; + + $validateCount = 0; + $v = new Validator($this->getIlluminateArrayTranslator(), $post, ['first' => 'required', 'preferred'=> 'required']); + $v->after(function () use (&$validateCount) { + $validateCount++; + }); + $data = $v->validate(); + $v->validated(); + + $this->assertEquals(['first' => 'john', 'preferred' => 'john'], $data); + $this->assertEquals(1, $validateCount); + } + /** * @dataProvider validUuidList */ From 5f0a8c0f27be25f6623bdfcebe47d597daf99ffb Mon Sep 17 00:00:00 2001 From: joostbaptist Date: Wed, 7 Nov 2018 13:34:41 +0100 Subject: [PATCH 0787/2459] [5.8] Unset relation when calling associate with ID on BelongsTo relationship (#26418) * Unset relation when calling associate with ID on BelongsTo relationship * Added integration tests * Rewording * Fixed parameter order * Update BelongsTo.php --- .../Database/Eloquent/Relations/BelongsTo.php | 2 ++ .../DatabaseEloquentBelongsToTest.php | 2 ++ .../Database/EloquentBelongsToTest.php | 33 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php index a46f7db84c3b..b6aad6eb059a 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php @@ -221,6 +221,8 @@ public function associate($model) if ($model instanceof Model) { $this->child->setRelation($this->relation, $model); + } elseif ($this->child->isDirty($this->foreignKey)) { + $this->child->unsetRelation($this->relation); } return $this->child; diff --git a/tests/Database/DatabaseEloquentBelongsToTest.php b/tests/Database/DatabaseEloquentBelongsToTest.php index 602aeaacea9d..f6d00615ccdb 100755 --- a/tests/Database/DatabaseEloquentBelongsToTest.php +++ b/tests/Database/DatabaseEloquentBelongsToTest.php @@ -148,6 +148,8 @@ public function testAssociateMethodSetsForeignKeyOnModelById() $parent->shouldReceive('getAttribute')->once()->with('foreign_key')->andReturn('foreign.value'); $relation = $this->getRelation($parent); $parent->shouldReceive('setAttribute')->once()->with('foreign_key', 1); + $parent->shouldReceive('isDirty')->once()->andReturn(true); + $parent->shouldReceive('unsetRelation')->once()->with($relation->getRelation()); $relation->associate(1); } diff --git a/tests/Integration/Database/EloquentBelongsToTest.php b/tests/Integration/Database/EloquentBelongsToTest.php index 059e1609c283..d68d31ffab09 100644 --- a/tests/Integration/Database/EloquentBelongsToTest.php +++ b/tests/Integration/Database/EloquentBelongsToTest.php @@ -39,6 +39,39 @@ public function test_has_self_custom_owner_key() $this->assertEquals(1, $users->count()); } + + public function test_associate_with_model() + { + $parent = User::doesntHave('parent')->first(); + $child = User::has('parent')->first(); + + $parent->parent()->associate($child); + + $this->assertEquals($child->id, $parent->parent_id); + $this->assertEquals($child->id, $parent->parent->id); + } + + public function test_associate_with_id() + { + $parent = User::doesntHave('parent')->first(); + $child = User::has('parent')->first(); + + $parent->parent()->associate($child->id); + + $this->assertEquals($child->id, $parent->parent_id); + $this->assertEquals($child->id, $parent->parent->id); + } + + public function test_associate_with_id_unsets_loaded_relation() + { + $child = User::has('parent')->with('parent')->first(); + + // Overwrite the (loaded) parent relation + $child->parent()->associate($child->id); + + $this->assertEquals($child->id, $child->parent_id); + $this->assertFalse($child->relationLoaded('parent')); + } } class User extends Model From 3ff3110ac14f2b4876acaff289bb55a1af74f02e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 7 Nov 2018 07:41:02 -0500 Subject: [PATCH 0788/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index bc1a47b163ff..7d3c086a4752 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.7.12'; + const VERSION = '5.7.13'; /** * The base path for the Laravel installation. From 2497ad869a689464e18549d2cf8558df6085f3a2 Mon Sep 17 00:00:00 2001 From: Sjors Date: Wed, 7 Nov 2018 13:42:08 +0100 Subject: [PATCH 0789/2459] Fix irregular plural in make:policy command --- src/Illuminate/Foundation/Console/PolicyMakeCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php index fba1e0ccc0c0..1d4f07ecb32c 100644 --- a/src/Illuminate/Foundation/Console/PolicyMakeCommand.php +++ b/src/Illuminate/Foundation/Console/PolicyMakeCommand.php @@ -104,7 +104,7 @@ protected function replaceModel($stub, $model) $stub = str_replace('DummyUser', $dummyUser, $stub); - return str_replace('DocDummyPluralModel', Str::snake(Str::plural($dummyModel), ' '), $stub); + return str_replace('DocDummyPluralModel', Str::snake(Str::pluralStudly($dummyModel), ' '), $stub); } /** From d1b51835733dbb982971d3ab7e700e883bf6e864 Mon Sep 17 00:00:00 2001 From: TSURU Date: Wed, 7 Nov 2018 21:45:32 +0900 Subject: [PATCH 0790/2459] fix comment --- src/Illuminate/Contracts/Validation/Validator.php | 2 +- src/Illuminate/Validation/Validator.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Contracts/Validation/Validator.php b/src/Illuminate/Contracts/Validation/Validator.php index 10396df28b49..c5536071c321 100644 --- a/src/Illuminate/Contracts/Validation/Validator.php +++ b/src/Illuminate/Contracts/Validation/Validator.php @@ -14,7 +14,7 @@ interface Validator extends MessageProvider public function validate(); /** - * Return validated value. + * Return validated values. * * @return array */ diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 1671f81b4abf..54e76e147aba 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -310,7 +310,7 @@ public function validate() } /** - * Return validated value. + * Return validated values. * * @return array * From 2fae6187a286b26fba876e0f60f14606efab4524 Mon Sep 17 00:00:00 2001 From: Sjors Ottjes Date: Wed, 7 Nov 2018 14:32:56 +0100 Subject: [PATCH 0791/2459] styleci --- tests/Database/DatabaseEloquentIrregularPluralTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Database/DatabaseEloquentIrregularPluralTest.php b/tests/Database/DatabaseEloquentIrregularPluralTest.php index bb1385563d50..5dec5ce1d9c4 100644 --- a/tests/Database/DatabaseEloquentIrregularPluralTest.php +++ b/tests/Database/DatabaseEloquentIrregularPluralTest.php @@ -57,7 +57,7 @@ protected function schema() } /** @test */ - function it_pluralizes_the_table_name() + public function it_pluralizes_the_table_name() { $model = new IrregularPluralHuman(); @@ -65,7 +65,7 @@ function it_pluralizes_the_table_name() } /** @test */ - function it_touches_the_parent_with_an_irregular_plural() + public function it_touches_the_parent_with_an_irregular_plural() { Carbon::setTestNow('2018-05-01 12:13:14'); From 0431c065ec491397097b8e14ed504b86d95dc6dd Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 7 Nov 2018 09:11:32 -0500 Subject: [PATCH 0792/2459] formatting --- src/Illuminate/Contracts/Validation/Validator.php | 2 +- src/Illuminate/Validation/Validator.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Contracts/Validation/Validator.php b/src/Illuminate/Contracts/Validation/Validator.php index c5536071c321..aff0f1e7fc57 100644 --- a/src/Illuminate/Contracts/Validation/Validator.php +++ b/src/Illuminate/Contracts/Validation/Validator.php @@ -14,7 +14,7 @@ interface Validator extends MessageProvider public function validate(); /** - * Return validated values. + * Get the attributes and values that were validated. * * @return array */ diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 54e76e147aba..a6e6830ed6b2 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -310,7 +310,7 @@ public function validate() } /** - * Return validated values. + * Get the attributes and values that were validated. * * @return array * From 9f81b623e3b4bc5bdd86116d4a718b14e349f75f Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 7 Nov 2018 20:38:29 +0200 Subject: [PATCH 0793/2459] [5.7] Update changelog; --- CHANGELOG-5.7.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index 908db4625a29..0a3570f7f1f1 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -1,12 +1,14 @@ # Release Notes for 5.7.x -## Unreleased +## [v5.7.13 (2018-11-07)](https://github.com/laravel/framework/compare/v5.7.12...v5.7.13) ### Added - Added ability to return an array of messages in a custom validation rule ([#26327](https://github.com/laravel/framework/pull/26327)) - Added `whenEmpty`/ `whenNotEmpty` / `unlessEmpty` / `unlessNotEmpty` methods to `Collection` ([#26345](https://github.com/laravel/framework/pull/26345)) +- Added `Illuminate\Support\Collection::some` method ([#26376](https://github.com/laravel/framework/pull/26376), [8f7e647](https://github.com/laravel/framework/commit/8f7e647dcee5fe13d7fc33a1e0e1ce531ea9f49e)) - Added `Illuminate\Cache\Repository::missing` method ([#26351](https://github.com/laravel/framework/pull/26351)) - Added `Macroable` trait to `Illuminate\View\Factory` ([#26361](https://github.com/laravel/framework/pull/26361)) +- Added support for UNION aggregate queries ([#26365](https://github.com/laravel/framework/pull/26365)) ### Changed - Updated `AbstractPaginator::appends` to handle null ([#26326](https://github.com/laravel/framework/pull/26326)) @@ -14,6 +16,8 @@ - Showed exception message on 403 error page when message is available ([#26356](https://github.com/laravel/framework/pull/26356)) - Don't run TransformsRequest twice on ?query= parameters ([#26366](https://github.com/laravel/framework/pull/26366)) - Added missing logging options to slack log driver ([#26360](https://github.com/laravel/framework/pull/26360)) +- Use cascade when truncating table in PostgreSQL ([#26389](https://github.com/laravel/framework/pull/26389)) +- Allowed pass absolute parameter in has valid signature request macro ([#26397](https://github.com/laravel/framework/pull/26397)) ### Changed realization - Used `Request::validate` macro in Auth traits ([#26314](https://github.com/laravel/framework/pull/26314)) From a4405e91af27429f9e879d8754769cb68eb208d6 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Thu, 8 Nov 2018 00:13:11 +0100 Subject: [PATCH 0794/2459] Improve eager loading performance on MySQL --- .../Eloquent/Relations/HasOneOrMany.php | 4 +++- src/Illuminate/Database/Query/Builder.php | 24 +++++++++++++++++++ .../Database/Query/Grammars/Grammar.php | 16 +++++++++++++ .../Database/DatabaseEloquentHasManyTest.php | 13 ++++++++++ tests/Database/DatabaseEloquentHasOneTest.php | 3 ++- tests/Database/DatabaseEloquentMorphTest.php | 4 +++- tests/Database/DatabaseQueryBuilderTest.php | 8 +++++++ 7 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index 64e16c2d31fe..7a93a6ed2777 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -81,7 +81,9 @@ public function addConstraints() */ public function addEagerConstraints(array $models) { - $this->query->whereIn( + $whereIn = in_array($this->parent->getKeyType(), ['int', 'integer']) ? 'whereInRaw' : 'whereIn'; + + $this->query->$whereIn( $this->foreignKey, $this->getKeys($models, $this->localKey) ); } diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index bd66993decbb..524163829406 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -948,6 +948,30 @@ protected function whereInExistingQuery($column, $query, $boolean, $not) return $this; } + /** + * Add a "where in raw" clause to the query. + * + * @param string $column + * @param array $values + * @param string $boolean + * @param bool $not + * @return $this + */ + public function whereInRaw($column, array $values, $boolean = 'and', $not = false) + { + $type = $not ? 'NotInRaw' : 'InRaw'; + + if ($values instanceof Arrayable) { + $values = $values->toArray(); + } + + $values = array_map('intval', $values); + + $this->wheres[] = compact('type', 'column', 'values', 'boolean'); + + return $this; + } + /** * Add a "where null" clause to the query. * diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index a9f11d25ac01..1b7e03ca4a2a 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -301,6 +301,22 @@ protected function whereNotInSub(Builder $query, $where) return $this->wrap($where['column']).' not in ('.$this->compileSelect($where['query']).')'; } + /** + * Compile a "where in raw" clause. + * + * @param \Illuminate\Database\Query\Builder $query + * @param array $where + * @return string + */ + protected function whereInRaw(Builder $query, $where) + { + if (! empty($where['values'])) { + return $this->wrap($where['column']).' in ('.implode(', ', $where['values']).')'; + } + + return '0 = 1'; + } + /** * Compile a "where null" clause. * diff --git a/tests/Database/DatabaseEloquentHasManyTest.php b/tests/Database/DatabaseEloquentHasManyTest.php index f2ce97b81dbd..6ede3f1ac1d7 100755 --- a/tests/Database/DatabaseEloquentHasManyTest.php +++ b/tests/Database/DatabaseEloquentHasManyTest.php @@ -200,6 +200,19 @@ public function testRelationIsProperlyInitialized() public function testEagerConstraintsAreProperlyAdded() { $relation = $this->getRelation(); + $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); + $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]); + $model1 = new EloquentHasManyModelStub; + $model1->id = 1; + $model2 = new EloquentHasManyModelStub; + $model2->id = 2; + $relation->addEagerConstraints([$model1, $model2]); + } + + public function testEagerConstraintsAreProperlyAddedWithStringKey() + { + $relation = $this->getRelation(); + $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string'); $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasManyModelStub; $model1->id = 1; diff --git a/tests/Database/DatabaseEloquentHasOneTest.php b/tests/Database/DatabaseEloquentHasOneTest.php index f7bc4d74533a..799580a9a2c4 100755 --- a/tests/Database/DatabaseEloquentHasOneTest.php +++ b/tests/Database/DatabaseEloquentHasOneTest.php @@ -163,7 +163,8 @@ public function testRelationIsProperlyInitialized() public function testEagerConstraintsAreProperlyAdded() { $relation = $this->getRelation(); - $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.foreign_key', [1, 2]); + $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); + $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasOneModelStub; $model1->id = 1; $model2 = new EloquentHasOneModelStub; diff --git a/tests/Database/DatabaseEloquentMorphTest.php b/tests/Database/DatabaseEloquentMorphTest.php index 92999f432a81..003db0c3f331 100755 --- a/tests/Database/DatabaseEloquentMorphTest.php +++ b/tests/Database/DatabaseEloquentMorphTest.php @@ -28,6 +28,7 @@ public function testMorphOneSetsProperConstraints() public function testMorphOneEagerConstraintsAreProperlyAdded() { $relation = $this->getOneRelation(); + $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string'); $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.morph_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent())); @@ -50,7 +51,8 @@ public function testMorphManySetsProperConstraints() public function testMorphManyEagerConstraintsAreProperlyAdded() { $relation = $this->getManyRelation(); - $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.morph_id', [1, 2]); + $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); + $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.morph_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent())); $model1 = new EloquentMorphResetModelStub; diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 299381af32b0..8ea54092cb3e 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -693,6 +693,14 @@ public function testEmptyWhereNotIns() $this->assertEquals([0 => 1], $builder->getBindings()); } + public function testWhereInRaw() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereInRaw('id', ['1a', 2]); + $this->assertEquals('select * from "users" where "id" in (1, 2)', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + } + public function testBasicWhereColumn() { $builder = $this->getBuilder(); From 5f2bf799a50bd6fbd8561c125db8d8b41a5af6fd Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Thu, 8 Nov 2018 11:03:27 +1100 Subject: [PATCH 0795/2459] fix mix missing asset exceptions (#26431) --- src/Illuminate/Foundation/helpers.php | 6 +++- .../Foundation/FoundationHelpersTest.php | 33 ++++++++++++++++--- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 1b200624a8ab..123df898f20d 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -609,10 +609,14 @@ function mix($path, $manifestDirectory = '') $manifest = $manifests[$manifestPath]; if (! isset($manifest[$path])) { - report(new Exception("Unable to locate Mix file: {$path}.")); + $exception = new Exception("Unable to locate Mix file: {$path}."); if (! app('config')->get('app.debug')) { + report($exception); + return $path; + } else { + throw $exception; } } diff --git a/tests/Integration/Foundation/FoundationHelpersTest.php b/tests/Integration/Foundation/FoundationHelpersTest.php index 95d614c8452b..a44d34e2bb1e 100644 --- a/tests/Integration/Foundation/FoundationHelpersTest.php +++ b/tests/Integration/Foundation/FoundationHelpersTest.php @@ -4,6 +4,7 @@ use Exception; use Orchestra\Testbench\TestCase; +use Illuminate\Support\Facades\Route; use Illuminate\Contracts\Debug\ExceptionHandler; /** @@ -47,8 +48,8 @@ public function testMixReportsExceptionWhenAssetIsMissingFromManifest() mix('missing.js'); - $this->assertInstanceOf(Exception::class, $handler->reported); - $this->assertSame('Unable to locate Mix file: /missing.js.', $handler->reported->getMessage()); + $this->assertInstanceOf(Exception::class, $handler->reported[0]); + $this->assertSame('Unable to locate Mix file: /missing.js.', $handler->reported[0]->getMessage()); unlink($manifest); } @@ -67,7 +68,7 @@ public function testMixSilentlyFailsWhenAssetIsMissingFromManifestWhenNotInDebug /** * @expectedException \Exception - * @expectedExceptionMessage Undefined index: /missing.js + * @expectedExceptionMessage Unable to locate Mix file: /missing.js. */ public function testMixThrowsExceptionWhenAssetIsMissingFromManifestWhenInDebugMode() { @@ -83,6 +84,23 @@ public function testMixThrowsExceptionWhenAssetIsMissingFromManifestWhenInDebugM } } + public function testMixOnlyThrowsAndReportsOneExceptionWhenAssetIsMissingFromManifestWhenInDebugMode() + { + $handler = new FakeHandler; + $this->app->instance(ExceptionHandler::class, $handler); + $this->app['config']->set('app.debug', true); + $manifest = $this->makeManifest(); + Route::get('test-route', function () { + mix('missing.js'); + }); + + $this->get('/test-route'); + + $this->assertCount(1, $handler->reported); + + unlink($manifest); + } + protected function makeManifest($directory = '') { $this->app->singleton('path.public', function () { @@ -105,10 +123,15 @@ protected function makeManifest($directory = '') class FakeHandler { - public $reported; + public $reported = []; public function report($exception) { - $this->reported = $exception; + $this->reported[] = $exception; + } + + public function render($exception) + { + // } } From 15161135ea7ca2a47ed07494479c878e99089d87 Mon Sep 17 00:00:00 2001 From: Sjors Date: Thu, 8 Nov 2018 09:19:02 +0100 Subject: [PATCH 0796/2459] correctly pluralize morphtomany table names --- .../Eloquent/Concerns/HasRelationships.php | 8 +++- .../DatabaseEloquentIrregularPluralTest.php | 42 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 2e2db841814d..3f48742a4d40 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -528,7 +528,13 @@ public function morphToMany($related, $name, $table = null, $foreignPivotKey = n // Now we're ready to create a new query builder for this related model and // the relationship instances for this relation. This relations will set // appropriate query constraints then entirely manages the hydrations. - $table = $table ?: Str::plural($name); + if (! $table) { + $words = preg_split('/(_)/', $name, -1, PREG_SPLIT_DELIM_CAPTURE); + + $lastWord = array_pop($words); + + $table = implode('', $words).Str::plural($lastWord); + } return $this->newMorphToMany( $instance->newQuery(), $this, $name, $table, diff --git a/tests/Database/DatabaseEloquentIrregularPluralTest.php b/tests/Database/DatabaseEloquentIrregularPluralTest.php index 5dec5ce1d9c4..37527b8e3a4c 100644 --- a/tests/Database/DatabaseEloquentIrregularPluralTest.php +++ b/tests/Database/DatabaseEloquentIrregularPluralTest.php @@ -40,6 +40,17 @@ public function createSchema() $table->integer('irregular_plural_human_id')->unsigned(); $table->integer('irregular_plural_token_id')->unsigned(); }); + + $this->schema()->create('irregular_plural_mottoes', function ($table) { + $table->increments('id'); + $table->string('name'); + }); + + $this->schema()->create('cool_mottoes', function ($table) { + $table->integer('irregular_plural_motto_id'); + $table->integer('cool_motto_id'); + $table->string('cool_motto_type'); + }); } public function tearDown() @@ -69,7 +80,7 @@ public function it_touches_the_parent_with_an_irregular_plural() { Carbon::setTestNow('2018-05-01 12:13:14'); - IrregularPluralHuman::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); + IrregularPluralHuman::create(['email' => 'taylorotwell@gmail.com']); IrregularPluralToken::insert([ ['title' => 'The title'], @@ -88,6 +99,18 @@ public function it_touches_the_parent_with_an_irregular_plural() $this->assertSame('2018-05-01 12:13:14', (string) $human->created_at); $this->assertSame('2018-05-01 15:16:17', (string) $human->updated_at); } + + /** @test */ + public function it_pluralizes_morph_to_many_relationships() + { + $human = IrregularPluralHuman::create(['email' => 'bobby@example.com']); + + $human->mottoes()->create(['name' => 'Real eyes realize real lies']); + + $motto = IrregularPluralMotto::query()->first(); + + $this->assertSame('Real eyes realize real lies', $motto->name); + } } class IrregularPluralHuman extends Model @@ -103,6 +126,11 @@ public function irregularPluralTokens() 'irregular_plural_human_id' ); } + + public function mottoes() + { + return $this->morphToMany(IrregularPluralMotto::class, 'cool_motto'); + } } class IrregularPluralToken extends Model @@ -115,3 +143,15 @@ class IrregularPluralToken extends Model 'irregularPluralHumans', ]; } + +class IrregularPluralMotto extends Model +{ + protected $guarded = []; + + public $timestamps = false; + + public function irregularPluralHumans() + { + return $this->morphedByMany(IrregularPluralHuman::class, 'cool_motto'); + } +} From 950a1972c7795f0ece6a3307c7a1e3b67e83c36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Em=C3=ADlio=20B=2E=20Pedrollo?= Date: Wed, 7 Nov 2018 12:29:00 -0200 Subject: [PATCH 0797/2459] Allow for explicit text parameters on Authorize middleware Otherwise the previous (before PR #25763) behaviour should take place and return a null value to the gate when there's no bind to the route with that key. --- src/Illuminate/Auth/Middleware/Authorize.php | 7 ++- tests/Auth/AuthorizeMiddlewareTest.php | 56 +++++++++++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Auth/Middleware/Authorize.php b/src/Illuminate/Auth/Middleware/Authorize.php index d1774d79116d..00d8c95497d0 100644 --- a/src/Illuminate/Auth/Middleware/Authorize.php +++ b/src/Illuminate/Auth/Middleware/Authorize.php @@ -72,7 +72,12 @@ protected function getGateArguments($request, $models) */ protected function getModel($request, $model) { - return $this->isClassName($model) ? trim($model) : $request->route($model, $model); + if ($this->isClassName($model)) { + return trim($model); + } else { + return $request->route($model, null) ?: + ((preg_match("/^['\"](.*)['\"]$/", trim($model), $matches)) ? $matches[1] : null); + } } /** diff --git a/tests/Auth/AuthorizeMiddlewareTest.php b/tests/Auth/AuthorizeMiddlewareTest.php index 281352ce3aec..84fa19ebf7bf 100644 --- a/tests/Auth/AuthorizeMiddlewareTest.php +++ b/tests/Auth/AuthorizeMiddlewareTest.php @@ -91,11 +91,11 @@ public function testSimpleAbilityAuthorized() public function testSimpleAbilityWithStringParameter() { $this->gate()->define('view-dashboard', function ($user, $param) { - return $param === 'true'; + return $param === 'some string'; }); $this->router->get('dashboard', [ - 'middleware' => Authorize::class.':view-dashboard,true', + 'middleware' => Authorize::class.':view-dashboard,"some string"', 'uses' => function () { return 'success'; }, @@ -106,6 +106,58 @@ public function testSimpleAbilityWithStringParameter() $this->assertEquals($response->content(), 'success'); } + public function testSimpleAbilityWithNullParameter() + { + $this->gate()->define('view-dashboard', function ($user, $param = null) { + $this->assertNull($param); + + return true; + }); + + $this->router->get('dashboard', [ + 'middleware' => Authorize::class.':view-dashboard,null', + 'uses' => function () { + return 'success'; + }, + ]); + + $this->router->dispatch(Request::create('dashboard', 'GET')); + } + + public function testSimpleAbilityWithOptionalParameter() + { + $post = new stdClass; + + $this->router->bind('post', function () use ($post) { + return $post; + }); + + $this->gate()->define('view-comments', function ($user, $model = null) use ($post) { + return true; + }); + + $middleware = [SubstituteBindings::class, Authorize::class.':view-comments,post']; + + $this->router->get('comments', [ + 'middleware' => $middleware, + 'uses' => function () { + return 'success'; + }, + ]); + $this->router->get('posts/{post}/comments', [ + 'middleware' => $middleware, + 'uses' => function () { + return 'success'; + }, + ]); + + $response = $this->router->dispatch(Request::create('posts/1/comments', 'GET')); + $this->assertEquals($response->content(), 'success'); + + $response = $this->router->dispatch(Request::create('comments', 'GET')); + $this->assertEquals($response->content(), 'success'); + } + public function testSimpleAbilityWithStringParameterFromRouteParameter() { $this->gate()->define('view-dashboard', function ($user, $param) { From 892b2cef309ea86cc110f7c153e81474eb1b2a35 Mon Sep 17 00:00:00 2001 From: Justin Nesselrotte Date: Thu, 8 Nov 2018 06:20:05 -0700 Subject: [PATCH 0798/2459] Fix #22951 permanently: Using shouldIgnoreMissing on dispatcher mock (#26437) --- .../Foundation/Testing/Concerns/MocksApplicationServices.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php b/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php index 1ad4be4d8ed0..a6e51d493e95 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php +++ b/src/Illuminate/Foundation/Testing/Concerns/MocksApplicationServices.php @@ -175,7 +175,7 @@ protected function doesntExpectJobs($jobs) */ protected function withoutJobs() { - $mock = Mockery::mock(BusDispatcherContract::class); + $mock = Mockery::mock(BusDispatcherContract::class)->shouldIgnoreMissing(); $mock->shouldReceive('dispatch', 'dispatchNow')->andReturnUsing(function ($dispatched) { $this->dispatchedJobs[] = $dispatched; From 3992140064307ef82d23328995e7c59045c231f2 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 8 Nov 2018 08:39:29 -0500 Subject: [PATCH 0799/2459] formatting --- src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php | 2 +- src/Illuminate/Database/Query/Grammars/Grammar.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index 7a93a6ed2777..5d134da2dd19 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -83,7 +83,7 @@ public function addEagerConstraints(array $models) { $whereIn = in_array($this->parent->getKeyType(), ['int', 'integer']) ? 'whereInRaw' : 'whereIn'; - $this->query->$whereIn( + $this->query->{$whereIn}( $this->foreignKey, $this->getKeys($models, $this->localKey) ); } diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index 1b7e03ca4a2a..3534a8a02748 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -304,6 +304,8 @@ protected function whereNotInSub(Builder $query, $where) /** * Compile a "where in raw" clause. * + * For safety, this method is only used with integer values as whereInRaw utilizes "intval". + * * @param \Illuminate\Database\Query\Builder $query * @param array $where * @return string From 63dd423e8c7d537d2774d9e4caf5ca16f005bc96 Mon Sep 17 00:00:00 2001 From: mattdfloyd Date: Thu, 8 Nov 2018 08:40:16 -0500 Subject: [PATCH 0800/2459] wip (#26411) wip --- src/Illuminate/Foundation/Exceptions/views/401.blade.php | 2 +- src/Illuminate/Foundation/Exceptions/views/403.blade.php | 2 +- src/Illuminate/Foundation/Exceptions/views/404.blade.php | 2 +- src/Illuminate/Foundation/Exceptions/views/419.blade.php | 2 +- src/Illuminate/Foundation/Exceptions/views/429.blade.php | 2 +- src/Illuminate/Foundation/Exceptions/views/500.blade.php | 2 +- src/Illuminate/Foundation/Exceptions/views/503.blade.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Foundation/Exceptions/views/401.blade.php b/src/Illuminate/Foundation/Exceptions/views/401.blade.php index 6da906216272..10f05b88c3e0 100644 --- a/src/Illuminate/Foundation/Exceptions/views/401.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/401.blade.php @@ -4,7 +4,7 @@ @section('title', __('Unauthorized')) @section('image') -
    +
    @endsection diff --git a/src/Illuminate/Foundation/Exceptions/views/403.blade.php b/src/Illuminate/Foundation/Exceptions/views/403.blade.php index bf544c91bb1b..199953a23993 100644 --- a/src/Illuminate/Foundation/Exceptions/views/403.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/403.blade.php @@ -4,7 +4,7 @@ @section('title', __('Forbidden')) @section('image') -
    +
    @endsection diff --git a/src/Illuminate/Foundation/Exceptions/views/404.blade.php b/src/Illuminate/Foundation/Exceptions/views/404.blade.php index 0398a98e0057..d2bae51f806f 100644 --- a/src/Illuminate/Foundation/Exceptions/views/404.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/404.blade.php @@ -4,7 +4,7 @@ @section('title', __('Page Not Found')) @section('image') -
    +
    @endsection diff --git a/src/Illuminate/Foundation/Exceptions/views/419.blade.php b/src/Illuminate/Foundation/Exceptions/views/419.blade.php index 1671bffb49df..1b00819f0b7c 100644 --- a/src/Illuminate/Foundation/Exceptions/views/419.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/419.blade.php @@ -4,7 +4,7 @@ @section('title', __('Page Expired')) @section('image') -
    +
    @endsection diff --git a/src/Illuminate/Foundation/Exceptions/views/429.blade.php b/src/Illuminate/Foundation/Exceptions/views/429.blade.php index a9f3caa53a81..2747654acf19 100644 --- a/src/Illuminate/Foundation/Exceptions/views/429.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/429.blade.php @@ -4,7 +4,7 @@ @section('title', __('Too Many Requests')) @section('image') -
    +
    @endsection diff --git a/src/Illuminate/Foundation/Exceptions/views/500.blade.php b/src/Illuminate/Foundation/Exceptions/views/500.blade.php index 8c5e2d5d6891..8868cf822bea 100644 --- a/src/Illuminate/Foundation/Exceptions/views/500.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/500.blade.php @@ -4,7 +4,7 @@ @section('title', __('Error')) @section('image') -
    +
    @endsection diff --git a/src/Illuminate/Foundation/Exceptions/views/503.blade.php b/src/Illuminate/Foundation/Exceptions/views/503.blade.php index 8272e0e98ef0..d75ae7e7e473 100644 --- a/src/Illuminate/Foundation/Exceptions/views/503.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/503.blade.php @@ -4,7 +4,7 @@ @section('title', __('Service Unavailable')) @section('image') -
    +
    @endsection From 2527f9a341e05111e1067caf6f3c1cd3640f6211 Mon Sep 17 00:00:00 2001 From: Caleb Porzio Date: Thu, 8 Nov 2018 12:18:23 -0500 Subject: [PATCH 0801/2459] [5.7] Make CookieJar macroable (#26445) * Make CookieJar macroable * Move use statement --- src/Illuminate/Cookie/CookieJar.php | 3 ++- tests/Cookie/CookieTest.php | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Cookie/CookieJar.php b/src/Illuminate/Cookie/CookieJar.php index abf23fd87933..5d28510e3937 100755 --- a/src/Illuminate/Cookie/CookieJar.php +++ b/src/Illuminate/Cookie/CookieJar.php @@ -3,13 +3,14 @@ namespace Illuminate\Cookie; use Illuminate\Support\Arr; +use Illuminate\Support\Traits\Macroable; use Illuminate\Support\InteractsWithTime; use Symfony\Component\HttpFoundation\Cookie; use Illuminate\Contracts\Cookie\QueueingFactory as JarContract; class CookieJar implements JarContract { - use InteractsWithTime; + use InteractsWithTime, Macroable; /** * The default path (if specified). diff --git a/tests/Cookie/CookieTest.php b/tests/Cookie/CookieTest.php index d37442e19f2b..8ee3bee5e716 100755 --- a/tests/Cookie/CookieTest.php +++ b/tests/Cookie/CookieTest.php @@ -88,6 +88,15 @@ public function testUnqueue() $this->assertEmpty($cookie->getQueuedCookies()); } + public function testCookieJarIsMacroable() + { + $cookie = $this->getCreator(); + $cookie->macro('foo', function () { + return 'bar'; + }); + $this->assertEquals('bar', $cookie->foo()); + } + public function getCreator() { return new CookieJar(Request::create('/foo', 'GET'), [ From 4528502420d7e3bbd85e3a819860a03c8b8b7b55 Mon Sep 17 00:00:00 2001 From: Jordan Hall Date: Thu, 8 Nov 2018 17:37:41 +0000 Subject: [PATCH 0802/2459] [5.7] Allow migration table name to be guessed without `_table` suffix (#26429) * Add missing test for 'foo_in_bar_table' syntax * Allow migration table name to be guessed without 'table' suffix * Style fixes * Alter basic create migration make command tests --- .../Console/Migrations/TableGuesser.php | 22 ++++++++++++++---- .../DatabaseMigrationMakeCommandTest.php | 6 ++--- tests/Database/TableGuesserTest.php | 23 +++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Console/Migrations/TableGuesser.php b/src/Illuminate/Database/Console/Migrations/TableGuesser.php index edcd706ff2d3..82dfbddbbceb 100644 --- a/src/Illuminate/Database/Console/Migrations/TableGuesser.php +++ b/src/Illuminate/Database/Console/Migrations/TableGuesser.php @@ -4,6 +4,16 @@ class TableGuesser { + const CREATE_PATTERNS = [ + '/^create_(\w+)_table$/', + '/^create_(\w+)$/', + ]; + + const CHANGE_PATTERNS = [ + '/_(to|from|in)_(\w+)_table$/', + '/_(to|from|in)_(\w+)$/', + ]; + /** * Attempt to guess the table name and "creation" status of the given migration. * @@ -12,12 +22,16 @@ class TableGuesser */ public static function guess($migration) { - if (preg_match('/^create_(\w+)_table$/', $migration, $matches)) { - return [$matches[1], $create = true]; + foreach (self::CREATE_PATTERNS as $pattern) { + if (preg_match($pattern, $migration, $matches)) { + return [$matches[1], $create = true]; + } } - if (preg_match('/_(to|from|in)_(\w+)_table$/', $migration, $matches)) { - return [$matches[2], $create = false]; + foreach (self::CHANGE_PATTERNS as $pattern) { + if (preg_match($pattern, $migration, $matches)) { + return [$matches[2], $create = false]; + } } } } diff --git a/tests/Database/DatabaseMigrationMakeCommandTest.php b/tests/Database/DatabaseMigrationMakeCommandTest.php index 3481c31d5f23..1e34388da41c 100755 --- a/tests/Database/DatabaseMigrationMakeCommandTest.php +++ b/tests/Database/DatabaseMigrationMakeCommandTest.php @@ -27,7 +27,7 @@ public function testBasicCreateDumpsAutoload() $app = new Application; $app->useDatabasePath(__DIR__); $command->setLaravel($app); - $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', null, false); + $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', 'foo', true); $composer->shouldReceive('dumpAutoloads')->once(); $this->runCommand($command, ['name' => 'create_foo']); @@ -42,7 +42,7 @@ public function testBasicCreateGivesCreatorProperArguments() $app = new Application; $app->useDatabasePath(__DIR__); $command->setLaravel($app); - $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', null, false); + $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', 'foo', true); $this->runCommand($command, ['name' => 'create_foo']); } @@ -56,7 +56,7 @@ public function testBasicCreateGivesCreatorProperArgumentsWhenNameIsStudlyCase() $app = new Application; $app->useDatabasePath(__DIR__); $command->setLaravel($app); - $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', null, false); + $creator->shouldReceive('create')->once()->with('create_foo', __DIR__.DIRECTORY_SEPARATOR.'migrations', 'foo', true); $this->runCommand($command, ['name' => 'CreateFoo']); } diff --git a/tests/Database/TableGuesserTest.php b/tests/Database/TableGuesserTest.php index 6a6aecaa97c2..0a8bd2434c91 100644 --- a/tests/Database/TableGuesserTest.php +++ b/tests/Database/TableGuesserTest.php @@ -17,8 +17,31 @@ public function test_migration_is_properly_parsed() $this->assertEquals('users', $table); $this->assertFalse($create); + [$table, $create] = TableGuesser::guess('change_status_column_in_users_table'); + $this->assertEquals('users', $table); + $this->assertFalse($create); + [$table, $create] = TableGuesser::guess('drop_status_column_from_users_table'); $this->assertEquals('users', $table); $this->assertFalse($create); } + + public function test_migration_is_properly_parsed_without_table_suffix() + { + [$table, $create] = TableGuesser::guess('create_users'); + $this->assertEquals('users', $table); + $this->assertTrue($create); + + [$table, $create] = TableGuesser::guess('add_status_column_to_users'); + $this->assertEquals('users', $table); + $this->assertFalse($create); + + [$table, $create] = TableGuesser::guess('change_status_column_in_users'); + $this->assertEquals('users', $table); + $this->assertFalse($create); + + [$table, $create] = TableGuesser::guess('drop_status_column_from_users'); + $this->assertEquals('users', $table); + $this->assertFalse($create); + } } From 96de5cc1753323f4a69ce72d5e7c2a549718670c Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 9 Nov 2018 00:38:40 +0100 Subject: [PATCH 0803/2459] Provide retry callback with the attempt count This provides the call back with a attempt count, this can be helpful for function that need to modify there behavior with each attempt, or log it some how. --- src/Illuminate/Support/helpers.php | 6 ++++-- tests/Support/SupportHelpersTest.php | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 05ea9da94c30..3b4f7bc73992 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -739,7 +739,7 @@ function preg_replace_array($pattern, array $replacements, $subject) * Retry an operation a given number of times. * * @param int $times - * @param callable $callback + * @param callable $callback First parameter is the number of attempt * @param int $sleep * @return mixed * @@ -747,11 +747,13 @@ function preg_replace_array($pattern, array $replacements, $subject) */ function retry($times, callable $callback, $sleep = 0) { + $attempt = 0; $times--; beginning: + $attempt++; try { - return $callback(); + return $callback($attempt); } catch (Exception $e) { if (! $times) { throw $e; diff --git a/tests/Support/SupportHelpersTest.php b/tests/Support/SupportHelpersTest.php index 6d1deae5f6f9..79b0087a4a51 100755 --- a/tests/Support/SupportHelpersTest.php +++ b/tests/Support/SupportHelpersTest.php @@ -868,6 +868,25 @@ public function something() })->present()->something()); } + public function testRetry() + { + $startTime = microtime(true); + + $attempts = retry(2, function ($attempts) { + if ($attempts > 1) { + return $attempts; + } + + throw new RuntimeException; + }, 100); + + // Make sure we made two attempts + $this->assertEquals(2, $attempts); + + // Make sure we waited 100ms for the first attempt + $this->assertTrue(microtime(true) - $startTime >= 0.1); + } + public function testTransform() { $this->assertEquals(10, transform(5, function ($value) { From 352e8abcf1354e73cbab6473d6467dd92960d38e Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Fri, 9 Nov 2018 03:03:39 +0100 Subject: [PATCH 0804/2459] Improve eager loading performance --- .../Database/Eloquent/Relations/BelongsTo.php | 4 +++- .../Eloquent/Relations/BelongsToMany.php | 4 +++- .../Eloquent/Relations/HasManyThrough.php | 4 +++- .../Database/Eloquent/Relations/HasOneOrMany.php | 2 +- .../Database/Eloquent/Relations/Relation.php | 15 +++++++++++++++ tests/Database/DatabaseEloquentBelongsToTest.php | 16 ++++++++++++---- tests/Database/DatabaseEloquentHasManyTest.php | 2 ++ tests/Database/DatabaseEloquentHasOneTest.php | 1 + tests/Database/DatabaseEloquentMorphTest.php | 2 ++ .../Database/DatabaseEloquentMorphToManyTest.php | 4 +++- 10 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php index 3259bdcd1499..9af168c1f1c9 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php @@ -111,7 +111,9 @@ public function addEagerConstraints(array $models) // our eagerly loading query so it returns the proper models from execution. $key = $this->related->getTable().'.'.$this->ownerKey; - $this->query->whereIn($key, $this->getEagerModelKeys($models)); + $whereIn = $this->whereInMethod($this->related, $this->ownerKey); + + $this->query->{$whereIn}($key, $this->getEagerModelKeys($models)); } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index d1a1242df69f..d38616ba8762 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -209,7 +209,9 @@ protected function addWhereConstraints() */ public function addEagerConstraints(array $models) { - $this->query->whereIn($this->getQualifiedForeignPivotKeyName(), $this->getKeys($models, $this->parentKey)); + $whereIn = $this->whereInMethod($this->parent, $this->parentKey); + + $this->query->{$whereIn}($this->getQualifiedForeignPivotKeyName(), $this->getKeys($models, $this->parentKey)); } /** diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 4ac8a3713e0c..2b69ca3694b4 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -146,7 +146,9 @@ public function throughParentSoftDeletes() */ public function addEagerConstraints(array $models) { - $this->query->whereIn( + $whereIn = $this->whereInMethod($this->farParent, $this->localKey); + + $this->query->{$whereIn}( $this->getQualifiedFirstKeyName(), $this->getKeys($models, $this->localKey) ); } diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index 5d134da2dd19..57295e625e93 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -81,7 +81,7 @@ public function addConstraints() */ public function addEagerConstraints(array $models) { - $whereIn = in_array($this->parent->getKeyType(), ['int', 'integer']) ? 'whereInRaw' : 'whereIn'; + $whereIn = $this->whereInMethod($this->parent, $this->localKey); $this->query->{$whereIn}( $this->foreignKey, $this->getKeys($models, $this->localKey) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 7c563c80b05c..671d21127a50 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -307,6 +307,21 @@ public function relatedUpdatedAt() return $this->related->getUpdatedAtColumn(); } + /** + * Get the name of the "where in" method for eager loading. + * + * @param \Illuminate\Database\Eloquent\Model $model + * @param string $key + * @return string + */ + protected function whereInMethod(Model $model, $key) + { + return $model->getKeyName() === last(explode('.', $key)) + && in_array($model->getKeyType(), ['int', 'integer']) + ? 'whereInRaw' + : 'whereIn'; + } + /** * Set or get the morph map for polymorphic relations. * diff --git a/tests/Database/DatabaseEloquentBelongsToTest.php b/tests/Database/DatabaseEloquentBelongsToTest.php index 602aeaacea9d..0d3c64d3f8dd 100755 --- a/tests/Database/DatabaseEloquentBelongsToTest.php +++ b/tests/Database/DatabaseEloquentBelongsToTest.php @@ -79,7 +79,9 @@ public function testUpdateMethodRetrievesModelAndUpdates() public function testEagerConstraintsAreProperlyAdded() { $relation = $this->getRelation(); - $relation->getQuery()->shouldReceive('whereIn')->once()->with('relation.id', ['foreign.value', 'foreign.value.two']); + $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); + $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); + $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', ['foreign.value', 'foreign.value.two']); $models = [new EloquentBelongsToModelStub, new EloquentBelongsToModelStub, new AnotherEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } @@ -87,7 +89,9 @@ public function testEagerConstraintsAreProperlyAdded() public function testIdsInEagerConstraintsCanBeZero() { $relation = $this->getRelation(); - $relation->getQuery()->shouldReceive('whereIn')->once()->with('relation.id', ['foreign.value', 0]); + $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); + $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); + $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', ['foreign.value', 0]); $models = [new EloquentBelongsToModelStub, new EloquentBelongsToModelStubWithZeroId]; $relation->addEagerConstraints($models); } @@ -154,7 +158,9 @@ public function testAssociateMethodSetsForeignKeyOnModelById() public function testDefaultEagerConstraintsWhenIncrementing() { $relation = $this->getRelation(); - $relation->getQuery()->shouldReceive('whereIn')->once()->with('relation.id', m::mustBe([null])); + $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); + $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); + $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', m::mustBe([null])); $models = [new MissingEloquentBelongsToModelStub, new MissingEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } @@ -170,7 +176,9 @@ public function testDefaultEagerConstraintsWhenIncrementingAndNonIntKeyType() public function testDefaultEagerConstraintsWhenNotIncrementing() { $relation = $this->getRelation(null, false); - $relation->getQuery()->shouldReceive('whereIn')->once()->with('relation.id', m::mustBe([null])); + $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); + $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); + $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', m::mustBe([null])); $models = [new MissingEloquentBelongsToModelStub, new MissingEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } diff --git a/tests/Database/DatabaseEloquentHasManyTest.php b/tests/Database/DatabaseEloquentHasManyTest.php index 6ede3f1ac1d7..71a979b3fd86 100755 --- a/tests/Database/DatabaseEloquentHasManyTest.php +++ b/tests/Database/DatabaseEloquentHasManyTest.php @@ -200,6 +200,7 @@ public function testRelationIsProperlyInitialized() public function testEagerConstraintsAreProperlyAdded() { $relation = $this->getRelation(); + $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasManyModelStub; @@ -212,6 +213,7 @@ public function testEagerConstraintsAreProperlyAdded() public function testEagerConstraintsAreProperlyAddedWithStringKey() { $relation = $this->getRelation(); + $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string'); $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasManyModelStub; diff --git a/tests/Database/DatabaseEloquentHasOneTest.php b/tests/Database/DatabaseEloquentHasOneTest.php index 799580a9a2c4..319919c26f7c 100755 --- a/tests/Database/DatabaseEloquentHasOneTest.php +++ b/tests/Database/DatabaseEloquentHasOneTest.php @@ -163,6 +163,7 @@ public function testRelationIsProperlyInitialized() public function testEagerConstraintsAreProperlyAdded() { $relation = $this->getRelation(); + $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasOneModelStub; diff --git a/tests/Database/DatabaseEloquentMorphTest.php b/tests/Database/DatabaseEloquentMorphTest.php index 003db0c3f331..ab84e85a890a 100755 --- a/tests/Database/DatabaseEloquentMorphTest.php +++ b/tests/Database/DatabaseEloquentMorphTest.php @@ -28,6 +28,7 @@ public function testMorphOneSetsProperConstraints() public function testMorphOneEagerConstraintsAreProperlyAdded() { $relation = $this->getOneRelation(); + $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string'); $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.morph_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent())); @@ -51,6 +52,7 @@ public function testMorphManySetsProperConstraints() public function testMorphManyEagerConstraintsAreProperlyAdded() { $relation = $this->getManyRelation(); + $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.morph_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent())); diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php index 761429aac6b4..95ab8a37c08e 100644 --- a/tests/Database/DatabaseEloquentMorphToManyTest.php +++ b/tests/Database/DatabaseEloquentMorphToManyTest.php @@ -18,7 +18,9 @@ public function tearDown() public function testEagerConstraintsAreProperlyAdded() { $relation = $this->getRelation(); - $relation->getQuery()->shouldReceive('whereIn')->once()->with('taggables.taggable_id', [1, 2]); + $relation->getParent()->shouldReceive('getKeyName')->andReturn('id'); + $relation->getParent()->shouldReceive('getKeyType')->andReturn('int'); + $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('taggables.taggable_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('taggables.taggable_type', get_class($relation->getParent())); $model1 = new EloquentMorphToManyModelStub; $model1->id = 1; From 680bd94986ad61e6905f2b78fa0eb4e33441780c Mon Sep 17 00:00:00 2001 From: Sjors Ottjes Date: Fri, 9 Nov 2018 09:13:53 +0100 Subject: [PATCH 0805/2459] utf-8 regex --- src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php index 3f48742a4d40..cb202f999aa9 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasRelationships.php @@ -529,7 +529,7 @@ public function morphToMany($related, $name, $table = null, $foreignPivotKey = n // the relationship instances for this relation. This relations will set // appropriate query constraints then entirely manages the hydrations. if (! $table) { - $words = preg_split('/(_)/', $name, -1, PREG_SPLIT_DELIM_CAPTURE); + $words = preg_split('/(_)/u', $name, -1, PREG_SPLIT_DELIM_CAPTURE); $lastWord = array_pop($words); From a40653328d830b92b464540bc1468b6f183b75d4 Mon Sep 17 00:00:00 2001 From: Victor Lap Date: Fri, 9 Nov 2018 09:54:58 +0100 Subject: [PATCH 0806/2459] Switch increments to use unsignedBigInteger --- src/Illuminate/Database/Schema/Blueprint.php | 15 +++++++++++++-- src/Illuminate/Database/Schema/Builder.php | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index de2bb13b84b8..fe0eb9f05348 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -526,14 +526,14 @@ public function foreign($columns, $name = null) } /** - * Create a new auto-incrementing integer (4-byte) column on the table. + * Create a new auto-incrementing integer column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function increments($column) { - return $this->unsignedInteger($column, true); + return $this->{Builder::$defaultIncrementsType}($column, true); } /** @@ -569,6 +569,17 @@ public function mediumIncrements($column) return $this->unsignedMediumInteger($column, true); } + /** + * Create a new auto-incrementing integer (4-byte) column on the table. + * + * @param string $column + * @return \Illuminate\Database\Schema\ColumnDefinition + */ + public function integerIncrements($column) + { + return $this->unsignedInteger($column, true); + } + /** * Create a new auto-incrementing big integer (8-byte) column on the table. * diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 2e25cf0cd9dc..6c378a6a0cc9 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -36,6 +36,13 @@ class Builder */ public static $defaultStringLength = 255; + /** + * The default increments type for migrations. + * + * @var string + */ + public static $defaultIncrementsType = 'unsignedBigInteger'; + /** * Create a new database Schema manager. * @@ -59,6 +66,16 @@ public static function defaultStringLength($length) static::$defaultStringLength = $length; } + /** + * Set the default increments type to a 4 byte integer. + * + * @return void + */ + public static function useIntegerIncrements() + { + static::$defaultIncrementsType = 'unsignedInteger'; + } + /** * Determine if the given table exists. * From fd6002feedcd99326d6a17966bb8d6d091a8c77a Mon Sep 17 00:00:00 2001 From: Victor Lap Date: Fri, 9 Nov 2018 10:10:08 +0100 Subject: [PATCH 0807/2459] Make tests use bigincrements as default Add test for 'integerIncrements' --- .../DatabaseMySqlSchemaGrammarTest.php | 28 +++++++++++++------ .../DatabasePostgresSchemaGrammarTest.php | 26 +++++++++++------ .../DatabaseSqlServerSchemaGrammarTest.php | 20 +++++++++---- 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index 11091f7b4375..be75c7af0330 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -31,7 +31,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); + $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); $blueprint = new Blueprint('users'); $blueprint->increments('id'); @@ -43,7 +43,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table `users` add `id` int unsigned not null auto_increment primary key, add `email` varchar(255) not null', $statements[0]); + $this->assertEquals('alter table `users` add `id` bigint unsigned not null auto_increment primary key, add `email` varchar(255) not null', $statements[0]); } public function testEngineCreateTable() @@ -61,7 +61,7 @@ public function testEngineCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); + $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); $blueprint = new Blueprint('users'); $blueprint->create(); @@ -76,7 +76,7 @@ public function testEngineCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); + $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); } public function testCharsetCollationCreateTable() @@ -94,7 +94,7 @@ public function testCharsetCollationCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'", $statements[0]); + $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'", $statements[0]); $blueprint = new Blueprint('users'); $blueprint->create(); @@ -109,7 +109,7 @@ public function testCharsetCollationCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) character set utf8mb4 collate 'utf8mb4_unicode_ci' not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); + $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) character set utf8mb4 collate 'utf8mb4_unicode_ci' not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); } public function testBasicCreateTableWithPrefix() @@ -127,7 +127,7 @@ public function testBasicCreateTableWithPrefix() $statements = $blueprint->toSql($conn, $grammar); $this->assertCount(1, $statements); - $this->assertEquals('create table `prefix_users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); + $this->assertEquals('create table `prefix_users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); } public function testCreateTemporaryTable() @@ -144,7 +144,7 @@ public function testCreateTemporaryTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create temporary table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); + $this->assertEquals('create temporary table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); } public function testDropTable() @@ -379,7 +379,7 @@ public function testAddingIncrementingID() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table `users` add `id` int unsigned not null auto_increment primary key', $statements[0]); + $this->assertEquals('alter table `users` add `id` bigint unsigned not null auto_increment primary key', $statements[0]); } public function testAddingSmallIncrementingID() @@ -392,6 +392,16 @@ public function testAddingSmallIncrementingID() $this->assertEquals('alter table `users` add `id` smallint unsigned not null auto_increment primary key', $statements[0]); } + public function testAddingIntegerIncrementingID() + { + $blueprint = new Blueprint('users'); + $blueprint->integerIncrements('id'); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertEquals('alter table `users` add `id` int unsigned not null auto_increment primary key', $statements[0]); + } + public function testAddingBigIncrementingID() { $blueprint = new Blueprint('users'); diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index da42ae4e5fea..2cb462e732f9 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -24,7 +24,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create table "users" ("id" serial primary key not null, "email" varchar(255) not null)', $statements[0]); + $this->assertEquals('create table "users" ("id" bigserial primary key not null, "email" varchar(255) not null)', $statements[0]); $blueprint = new Blueprint('users'); $blueprint->increments('id'); @@ -32,7 +32,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "id" serial primary key not null, add column "email" varchar(255) not null', $statements[0]); + $this->assertEquals('alter table "users" add column "id" bigserial primary key not null, add column "email" varchar(255) not null', $statements[0]); } public function testCreateTableAndCommentColumn() @@ -44,7 +44,7 @@ public function testCreateTableAndCommentColumn() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(2, $statements); - $this->assertEquals('create table "users" ("id" serial primary key not null, "email" varchar(255) not null)', $statements[0]); + $this->assertEquals('create table "users" ("id" bigserial primary key not null, "email" varchar(255) not null)', $statements[0]); $this->assertEquals('comment on column "users"."email" is \'my first comment\'', $statements[1]); } @@ -58,7 +58,7 @@ public function testCreateTemporaryTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create temporary table "users" ("id" serial primary key not null, "email" varchar(255) not null)', $statements[0]); + $this->assertEquals('create temporary table "users" ("id" bigserial primary key not null, "email" varchar(255) not null)', $statements[0]); } public function testDropTable() @@ -273,7 +273,7 @@ public function testAddingIncrementingID() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "id" serial primary key not null', $statements[0]); + $this->assertEquals('alter table "users" add column "id" bigserial primary key not null', $statements[0]); } public function testAddingSmallIncrementingID() @@ -296,6 +296,16 @@ public function testAddingMediumIncrementingID() $this->assertEquals('alter table "users" add column "id" serial primary key not null', $statements[0]); } + public function testAddingIntegerIncrementingID() + { + $blueprint = new Blueprint('users'); + $blueprint->integerIncrements('id'); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertEquals('alter table "users" add column "id" serial primary key not null', $statements[0]); + } + public function testAddingBigIncrementingID() { $blueprint = new Blueprint('users'); @@ -666,19 +676,19 @@ public function testAddingGeneratedAs() $blueprint->increments('foo')->generatedAs(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "foo" integer generated by default as identity primary key not null', $statements[0]); + $this->assertEquals('alter table "users" add column "foo" bigint generated by default as identity primary key not null', $statements[0]); // With always modifier $blueprint = new Blueprint('users'); $blueprint->increments('foo')->generatedAs()->always(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "foo" integer generated always as identity primary key not null', $statements[0]); + $this->assertEquals('alter table "users" add column "foo" bigint generated always as identity primary key not null', $statements[0]); // With sequence options $blueprint = new Blueprint('users'); $blueprint->increments('foo')->generatedAs('increment by 10 start with 100'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "foo" integer generated by default as identity (increment by 10 start with 100) primary key not null', $statements[0]); + $this->assertEquals('alter table "users" add column "foo" bigint generated by default as identity (increment by 10 start with 100) primary key not null', $statements[0]); // Not a primary key $blueprint = new Blueprint('users'); $blueprint->integer('foo')->generatedAs(); diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index c51722e8a40d..9c26eccb970a 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -24,7 +24,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create table "users" ("id" int identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); + $this->assertEquals('create table "users" ("id" bigint identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); $blueprint = new Blueprint('users'); $blueprint->increments('id'); @@ -32,7 +32,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add "id" int identity primary key not null, "email" nvarchar(255) not null', $statements[0]); + $this->assertEquals('alter table "users" add "id" bigint identity primary key not null, "email" nvarchar(255) not null', $statements[0]); $blueprint = new Blueprint('users'); $blueprint->create(); @@ -41,7 +41,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()->setTablePrefix('prefix_')); $this->assertCount(1, $statements); - $this->assertEquals('create table "prefix_users" ("id" int identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); + $this->assertEquals('create table "prefix_users" ("id" bigint identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); } public function testCreateTemporaryTable() @@ -54,7 +54,7 @@ public function testCreateTemporaryTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create table "#users" ("id" int identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); + $this->assertEquals('create table "#users" ("id" bigint identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); } public function testDropTable() @@ -273,7 +273,7 @@ public function testAddingIncrementingID() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add "id" int identity primary key not null', $statements[0]); + $this->assertEquals('alter table "users" add "id" bigint identity primary key not null', $statements[0]); } public function testAddingSmallIncrementingID() @@ -296,6 +296,16 @@ public function testAddingMediumIncrementingID() $this->assertEquals('alter table "users" add "id" int identity primary key not null', $statements[0]); } + public function testAddingIntegerIncrementingID() + { + $blueprint = new Blueprint('users'); + $blueprint->integerIncrements('id'); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertEquals('alter table "users" add "id" int identity primary key not null', $statements[0]); + } + public function testAddingBigIncrementingID() { $blueprint = new Blueprint('users'); From 22e1f7c8d54f04b916ef352f27f858c16b570c7f Mon Sep 17 00:00:00 2001 From: Victor Lap Date: Fri, 9 Nov 2018 10:17:28 +0100 Subject: [PATCH 0808/2459] Add tests for switching the default increments() method --- tests/Database/DatabaseMySqlSchemaGrammarTest.php | 11 +++++++++++ tests/Database/DatabasePostgresSchemaGrammarTest.php | 11 +++++++++++ tests/Database/DatabaseSqlServerSchemaGrammarTest.php | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index be75c7af0330..44fc51de6f48 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -5,6 +5,7 @@ use Mockery as m; use PHPUnit\Framework\TestCase; use Illuminate\Database\Connection; +use Illuminate\Database\Schema\Builder; use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Grammars\MySqlGrammar; @@ -380,6 +381,16 @@ public function testAddingIncrementingID() $this->assertCount(1, $statements); $this->assertEquals('alter table `users` add `id` bigint unsigned not null auto_increment primary key', $statements[0]); + + Builder::useIntegerIncrements(); + $blueprint = new Blueprint('users'); + $blueprint->increments('id'); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertEquals('alter table `users` add `id` int unsigned not null auto_increment primary key', $statements[0]); + + Builder::$defaultIncrementsType = 'unsignedBigInteger'; } public function testAddingSmallIncrementingID() diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 2cb462e732f9..2dc25bc45cd0 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -5,6 +5,7 @@ use Mockery as m; use PHPUnit\Framework\TestCase; use Illuminate\Database\Connection; +use Illuminate\Database\Schema\Builder; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Grammars\PostgresGrammar; @@ -274,6 +275,16 @@ public function testAddingIncrementingID() $this->assertCount(1, $statements); $this->assertEquals('alter table "users" add column "id" bigserial primary key not null', $statements[0]); + + Builder::useIntegerIncrements(); + $blueprint = new Blueprint('users'); + $blueprint->increments('id'); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertEquals('alter table "users" add column "id" serial primary key not null', $statements[0]); + + Builder::$defaultIncrementsType = 'unsignedBigInteger'; } public function testAddingSmallIncrementingID() diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index 9c26eccb970a..61a873e8ed6a 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -5,6 +5,7 @@ use Mockery as m; use PHPUnit\Framework\TestCase; use Illuminate\Database\Connection; +use Illuminate\Database\Schema\Builder; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Grammars\SqlServerGrammar; @@ -274,6 +275,16 @@ public function testAddingIncrementingID() $this->assertCount(1, $statements); $this->assertEquals('alter table "users" add "id" bigint identity primary key not null', $statements[0]); + + Builder::useIntegerIncrements(); + $blueprint = new Blueprint('users'); + $blueprint->increments('id'); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertEquals('alter table "users" add "id" int identity primary key not null', $statements[0]); + + Builder::$defaultIncrementsType = 'unsignedBigInteger'; } public function testAddingSmallIncrementingID() From cc188a561bc186ed4fc9811e8d60c71550ff8bbe Mon Sep 17 00:00:00 2001 From: Dick van der Heiden Date: Fri, 9 Nov 2018 14:27:42 +0100 Subject: [PATCH 0809/2459] Add ability to publish error views --- .../Providers/FoundationServiceProvider.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php index ce31986a51e9..fc0088542324 100644 --- a/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/FoundationServiceProvider.php @@ -17,6 +17,18 @@ class FoundationServiceProvider extends AggregateServiceProvider FormRequestServiceProvider::class, ]; + /** + * Boot the service provider. + */ + public function boot() + { + if ($this->app->runningInConsole()) { + $this->publishes([ + __DIR__.'/../Exceptions/views' => $this->app->resourcePath('views/errors/'), + ], 'laravel-errors'); + } + } + /** * Register the service provider. * From 831e4eb85da59279fc75cfd1f2426b61fb59ea1b Mon Sep 17 00:00:00 2001 From: Luca Andrea Rossi Date: Fri, 9 Nov 2018 13:54:40 +0000 Subject: [PATCH 0810/2459] [5.7] Ability to disable password reset route (#26459) * Ability to disable password reset route * Check if password request route is enabled --- .../Auth/Console/stubs/make/views/auth/login.stub | 8 +++++--- src/Illuminate/Routing/Router.php | 10 ++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub index 47e3f53068ad..9ee63bfbadc7 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub @@ -57,9 +57,11 @@ {{ __('Login') }} -
    - {{ __('Forgot Your Password?') }} - + @if (Route::has('password.request')) + + {{ __('Forgot Your Password?') }} + + @endif
    diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index c3f08953405b..83dabfe4973e 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -1155,10 +1155,12 @@ public function auth(array $options = []) } // Password Reset Routes... - $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request'); - $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email'); - $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset'); - $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update'); + if ($options['reset'] ?? true) { + $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request'); + $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email'); + $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset'); + $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update'); + } // Email Verification Routes... if ($options['verify'] ?? false) { From ee8d17b775ed738f03d4543d65517a4c29a3b1fa Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 9 Nov 2018 08:01:26 -0600 Subject: [PATCH 0811/2459] formatting --- src/Illuminate/Database/Schema/Blueprint.php | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index fe0eb9f05348..afbc4e97fd52 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -536,6 +536,17 @@ public function increments($column) return $this->{Builder::$defaultIncrementsType}($column, true); } + /** + * Create a new auto-incrementing integer (4-byte) column on the table. + * + * @param string $column + * @return \Illuminate\Database\Schema\ColumnDefinition + */ + public function integerIncrements($column) + { + return $this->unsignedInteger($column, true); + } + /** * Create a new auto-incrementing tiny integer (1-byte) column on the table. * @@ -569,17 +580,6 @@ public function mediumIncrements($column) return $this->unsignedMediumInteger($column, true); } - /** - * Create a new auto-incrementing integer (4-byte) column on the table. - * - * @param string $column - * @return \Illuminate\Database\Schema\ColumnDefinition - */ - public function integerIncrements($column) - { - return $this->unsignedInteger($column, true); - } - /** * Create a new auto-incrementing big integer (8-byte) column on the table. * From bbe7c9c316cb91bc99403da569491a647f30da1c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 9 Nov 2018 08:10:55 -0600 Subject: [PATCH 0812/2459] formatting --- src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index d38616ba8762..5e6f327f9a36 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -211,7 +211,10 @@ public function addEagerConstraints(array $models) { $whereIn = $this->whereInMethod($this->parent, $this->parentKey); - $this->query->{$whereIn}($this->getQualifiedForeignPivotKeyName(), $this->getKeys($models, $this->parentKey)); + $this->query->{$whereIn}( + $this->getQualifiedForeignPivotKeyName(), + $this->getKeys($models, $this->parentKey) + ); } /** From 66c248eb3cc2959ef6fe9236c1287b1604525d0c Mon Sep 17 00:00:00 2001 From: Rod Elias Date: Fri, 9 Nov 2018 12:11:23 -0200 Subject: [PATCH 0813/2459] Add test case for array callable syntax and fix typo (#26452) --- tests/Auth/AuthAccessGateTest.php | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index 0a2cdd480846..f95b0b63400e 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -373,6 +373,24 @@ public function test_invokable_classes_can_be_defined() $this->assertTrue($gate->check('foo')); } + public function test_gates_can_be_defined_using_an_array_callback() + { + $gate = $this->getBasicGate(); + + $gate->define('foo', [new AccessGateTestStaticClass, 'foo']); + + $this->assertTrue($gate->check('foo')); + } + + public function test_gates_can_be_defined_using_an_array_callback_with_static_method() + { + $gate = $this->getBasicGate(); + + $gate->define('foo', [AccessGateTestStaticClass::class, 'foo']); + + $this->assertTrue($gate->check('foo')); + } + public function test_policy_classes_can_be_defined_to_handle_checks_for_given_type() { $gate = $this->getBasicGate(); @@ -480,7 +498,7 @@ public function test_for_user_method_attaches_a_new_user_to_a_new_gate_instance( * @dataProvider notCallableDataProvider * @expectedException \InvalidArgumentException */ - public function test_define_second_parametter_should_be_string_or_callable($callback) + public function test_define_second_parameter_should_be_string_or_callable($callback) { $gate = $this->getBasicGate(); @@ -638,6 +656,14 @@ public function hasAbilitiesTestDataProvider() } } +class AccessGateTestStaticClass +{ + public static function foo() + { + return true; + } +} + class AccessGateTestClass { public function foo() From ca7b1da9176bff88902903d8aba64700f9386c3c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 9 Nov 2018 08:13:36 -0600 Subject: [PATCH 0814/2459] formatting --- src/Illuminate/Support/helpers.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 3b4f7bc73992..408e9b197fe0 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -739,7 +739,7 @@ function preg_replace_array($pattern, array $replacements, $subject) * Retry an operation a given number of times. * * @param int $times - * @param callable $callback First parameter is the number of attempt + * @param callable $callback * @param int $sleep * @return mixed * @@ -747,13 +747,14 @@ function preg_replace_array($pattern, array $replacements, $subject) */ function retry($times, callable $callback, $sleep = 0) { - $attempt = 0; + $attempts = 0; $times--; beginning: - $attempt++; + $attempts++; + try { - return $callback($attempt); + return $callback($attempts); } catch (Exception $e) { if (! $times) { throw $e; From ddb907a25dfa590e6e5357357b8298b98ab378f5 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Sat, 10 Nov 2018 17:32:21 +0100 Subject: [PATCH 0815/2459] Fix UNION aggregate queries with columns (#26466) --- src/Illuminate/Database/Query/Builder.php | 10 ++++++---- tests/Database/DatabaseQueryBuilderTest.php | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 524163829406..4d6e8a6917ac 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2130,8 +2130,10 @@ public function getCountForPagination($columns = ['*']) */ protected function runPaginationCountQuery($columns = ['*']) { - return $this->cloneWithout(['columns', 'orders', 'limit', 'offset']) - ->cloneWithoutBindings(['select', 'order']) + $without = $this->unions ? ['orders', 'limit', 'offset'] : ['columns', 'orders', 'limit', 'offset']; + + return $this->cloneWithout($without) + ->cloneWithoutBindings($this->unions ? ['order'] : ['select', 'order']) ->setAggregate('count', $this->withoutSelectAliases($columns)) ->get()->all(); } @@ -2444,8 +2446,8 @@ public function average($column) */ public function aggregate($function, $columns = ['*']) { - $results = $this->cloneWithout(['columns']) - ->cloneWithoutBindings(['select']) + $results = $this->cloneWithout($this->unions ? [] : ['columns']) + ->cloneWithoutBindings($this->unions ? [] : ['select']) ->setAggregate($function, $columns) ->get($columns); diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 8ea54092cb3e..70b462b1331c 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -843,6 +843,12 @@ public function testUnionAggregate() $builder->getProcessor()->shouldReceive('processSelect')->once(); $builder->from('posts')->union($this->getMySqlBuilder()->from('videos'))->count(); + $expected = 'select count(*) as aggregate from ((select `id` from `posts`) union (select `id` from `videos`)) as `temp_table`'; + $builder = $this->getMySqlBuilder(); + $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); + $builder->getProcessor()->shouldReceive('processSelect')->once(); + $builder->from('posts')->select('id')->union($this->getMySqlBuilder()->from('videos')->select('id'))->count(); + $expected = 'select count(*) as aggregate from (select * from "posts" union select * from "videos") as "temp_table"'; $builder = $this->getPostgresBuilder(); $builder->getConnection()->shouldReceive('select')->once()->with($expected, [], true); @@ -1095,6 +1101,20 @@ public function testGetCountForPaginationWithColumnAliases() $this->assertEquals(1, $count); } + public function testGetCountForPaginationWithUnion() + { + $builder = $this->getBuilder(); + $builder->from('posts')->select('id')->union($this->getBuilder()->from('videos')->select('id')); + + $builder->getConnection()->shouldReceive('select')->once()->with('select count(*) as aggregate from (select "id" from "posts" union select "id" from "videos") as "temp_table"', [], true)->andReturn([['aggregate' => 1]]); + $builder->getProcessor()->shouldReceive('processSelect')->once()->andReturnUsing(function ($builder, $results) { + return $results; + }); + + $count = $builder->getCountForPagination(); + $this->assertEquals(1, $count); + } + public function testWhereShortcut() { $builder = $this->getBuilder(); From f546835092206037ce1d9b4103be204e2e9272cc Mon Sep 17 00:00:00 2001 From: Rod Elias Date: Sat, 10 Nov 2018 14:33:30 -0200 Subject: [PATCH 0816/2459] Add missing docblock (#26464) --- src/Illuminate/Foundation/Console/PresetCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Foundation/Console/PresetCommand.php b/src/Illuminate/Foundation/Console/PresetCommand.php index a63082ea16fe..9c7e6c1a886a 100644 --- a/src/Illuminate/Foundation/Console/PresetCommand.php +++ b/src/Illuminate/Foundation/Console/PresetCommand.php @@ -27,6 +27,8 @@ class PresetCommand extends Command * Execute the console command. * * @return void + * + * @throws \InvalidArgumentException */ public function handle() { From d10b0a57ce0f09163310e0f7d378e929f31e3cea Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Sat, 10 Nov 2018 16:22:36 +0100 Subject: [PATCH 0817/2459] Improve whereInRaw() --- .../Database/Eloquent/Relations/Relation.php | 2 +- src/Illuminate/Database/Query/Builder.php | 12 +++++++----- tests/Database/DatabaseEloquentBelongsToTest.php | 8 ++++---- tests/Database/DatabaseEloquentHasManyTest.php | 2 +- tests/Database/DatabaseEloquentHasOneTest.php | 2 +- tests/Database/DatabaseEloquentMorphTest.php | 2 +- tests/Database/DatabaseEloquentMorphToManyTest.php | 2 +- tests/Database/DatabaseQueryBuilderTest.php | 4 ++-- 8 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 671d21127a50..b2882a5a3a0f 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -318,7 +318,7 @@ protected function whereInMethod(Model $model, $key) { return $model->getKeyName() === last(explode('.', $key)) && in_array($model->getKeyType(), ['int', 'integer']) - ? 'whereInRaw' + ? 'whereInRawInt' : 'whereIn'; } diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 524163829406..6c81aab80c9f 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -949,15 +949,15 @@ protected function whereInExistingQuery($column, $query, $boolean, $not) } /** - * Add a "where in raw" clause to the query. + * Add a "where in raw" clause for integer values to the query. * * @param string $column - * @param array $values + * @param \Illuminate\Contracts\Support\Arrayable|array $values * @param string $boolean - * @param bool $not + * @param bool $not * @return $this */ - public function whereInRaw($column, array $values, $boolean = 'and', $not = false) + public function whereInRawInt($column, $values, $boolean = 'and', $not = false) { $type = $not ? 'NotInRaw' : 'InRaw'; @@ -965,7 +965,9 @@ public function whereInRaw($column, array $values, $boolean = 'and', $not = fals $values = $values->toArray(); } - $values = array_map('intval', $values); + foreach ($values as &$value) { + $value = (int) $value; + } $this->wheres[] = compact('type', 'column', 'values', 'boolean'); diff --git a/tests/Database/DatabaseEloquentBelongsToTest.php b/tests/Database/DatabaseEloquentBelongsToTest.php index 0d3c64d3f8dd..77efba013a34 100755 --- a/tests/Database/DatabaseEloquentBelongsToTest.php +++ b/tests/Database/DatabaseEloquentBelongsToTest.php @@ -81,7 +81,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', ['foreign.value', 'foreign.value.two']); + $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('relation.id', ['foreign.value', 'foreign.value.two']); $models = [new EloquentBelongsToModelStub, new EloquentBelongsToModelStub, new AnotherEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } @@ -91,7 +91,7 @@ public function testIdsInEagerConstraintsCanBeZero() $relation = $this->getRelation(); $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', ['foreign.value', 0]); + $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('relation.id', ['foreign.value', 0]); $models = [new EloquentBelongsToModelStub, new EloquentBelongsToModelStubWithZeroId]; $relation->addEagerConstraints($models); } @@ -160,7 +160,7 @@ public function testDefaultEagerConstraintsWhenIncrementing() $relation = $this->getRelation(); $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', m::mustBe([null])); + $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('relation.id', m::mustBe([null])); $models = [new MissingEloquentBelongsToModelStub, new MissingEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } @@ -178,7 +178,7 @@ public function testDefaultEagerConstraintsWhenNotIncrementing() $relation = $this->getRelation(null, false); $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('relation.id', m::mustBe([null])); + $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('relation.id', m::mustBe([null])); $models = [new MissingEloquentBelongsToModelStub, new MissingEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } diff --git a/tests/Database/DatabaseEloquentHasManyTest.php b/tests/Database/DatabaseEloquentHasManyTest.php index 71a979b3fd86..0f922e895179 100755 --- a/tests/Database/DatabaseEloquentHasManyTest.php +++ b/tests/Database/DatabaseEloquentHasManyTest.php @@ -202,7 +202,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]); + $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasManyModelStub; $model1->id = 1; $model2 = new EloquentHasManyModelStub; diff --git a/tests/Database/DatabaseEloquentHasOneTest.php b/tests/Database/DatabaseEloquentHasOneTest.php index 319919c26f7c..f60b42b83d42 100755 --- a/tests/Database/DatabaseEloquentHasOneTest.php +++ b/tests/Database/DatabaseEloquentHasOneTest.php @@ -165,7 +165,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]); + $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasOneModelStub; $model1->id = 1; $model2 = new EloquentHasOneModelStub; diff --git a/tests/Database/DatabaseEloquentMorphTest.php b/tests/Database/DatabaseEloquentMorphTest.php index ab84e85a890a..18bcc81436cf 100755 --- a/tests/Database/DatabaseEloquentMorphTest.php +++ b/tests/Database/DatabaseEloquentMorphTest.php @@ -54,7 +54,7 @@ public function testMorphManyEagerConstraintsAreProperlyAdded() $relation = $this->getManyRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.morph_id', [1, 2]); + $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('table.morph_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent())); $model1 = new EloquentMorphResetModelStub; diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php index 95ab8a37c08e..6a481b08422c 100644 --- a/tests/Database/DatabaseEloquentMorphToManyTest.php +++ b/tests/Database/DatabaseEloquentMorphToManyTest.php @@ -20,7 +20,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRaw')->once()->with('taggables.taggable_id', [1, 2]); + $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('taggables.taggable_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('taggables.taggable_type', get_class($relation->getParent())); $model1 = new EloquentMorphToManyModelStub; $model1->id = 1; diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 8ea54092cb3e..0e6398749b7c 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -693,10 +693,10 @@ public function testEmptyWhereNotIns() $this->assertEquals([0 => 1], $builder->getBindings()); } - public function testWhereInRaw() + public function testWhereInRawInt() { $builder = $this->getBuilder(); - $builder->select('*')->from('users')->whereInRaw('id', ['1a', 2]); + $builder->select('*')->from('users')->whereInRawInt('id', ['1a', 2]); $this->assertEquals('select * from "users" where "id" in (1, 2)', $builder->toSql()); $this->assertEquals([], $builder->getBindings()); } From 9811782b1c317d87a37e8d9a15d716a71148e7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Nabia=C5=82ek?= Date: Sun, 11 Nov 2018 13:09:56 +0100 Subject: [PATCH 0818/2459] Pass full array key when transforming request value --- .../Http/Middleware/TransformsRequest.php | 9 +++-- .../Http/Middleware/TransformsRequestTest.php | 37 +++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php index 9c30fdcccf1e..ca554f4cb407 100644 --- a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php +++ b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php @@ -63,12 +63,13 @@ protected function cleanParameterBag(ParameterBag $bag) * Clean the data in the given array. * * @param array $data + * @param string $keyPrefix * @return array */ - protected function cleanArray(array $data) + protected function cleanArray(array $data, $keyPrefix = '') { - return collect($data)->map(function ($value, $key) { - return $this->cleanValue($key, $value); + return collect($data)->map(function ($value, $key) use ($keyPrefix) { + return $this->cleanValue($keyPrefix.$key, $value); })->all(); } @@ -82,7 +83,7 @@ protected function cleanArray(array $data) protected function cleanValue($key, $value) { if (is_array($value)) { - return $this->cleanArray($value); + return $this->cleanArray($value, $key.'.'); } return $this->transform($key, $value); diff --git a/tests/Foundation/Http/Middleware/TransformsRequestTest.php b/tests/Foundation/Http/Middleware/TransformsRequestTest.php index f73dd7b8f8fd..041aad7e73e8 100644 --- a/tests/Foundation/Http/Middleware/TransformsRequestTest.php +++ b/tests/Foundation/Http/Middleware/TransformsRequestTest.php @@ -45,6 +45,28 @@ public function testTransformOncePerKeyWhenMethodIsPost() }); } + public function testTransformOncePerArrayKeysWhenMethodIsPost() + { + $middleware = new ManipulateArrayInput; + $symfonyRequest = new SymfonyRequest( + [ + 'name' => 'Damian', + 'beers' => [4, 8, 12], + ], + [ + 'age' => [28, 56, 84] + ] + ); + $symfonyRequest->server->set('REQUEST_METHOD', 'POST'); + $request = Request::createFromBase($symfonyRequest); + + $middleware->handle($request, function (Request $request) { + $this->assertEquals('Damian', $request->get('name')); + $this->assertEquals([27, 55, 83], $request->get('age')); + $this->assertEquals([5, 9, 13], $request->get('beers')); + }); + } + public function testTransformOncePerKeyWhenContentTypeIsJson() { $middleware = new ManipulateInput; @@ -86,6 +108,21 @@ protected function transform($key, $value) } } +class ManipulateArrayInput extends TransformsRequest +{ + protected function transform($key, $value) + { + if (str_contains($key, 'beers')) { + $value++; + } + if (str_contains($key, 'age')) { + $value--; + } + + return $value; + } +} + class TruncateInput extends TransformsRequest { protected function transform($key, $value) From 35dfd4de258a25f70c64a32b558d6301213d492e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Nabia=C5=82ek?= Date: Sun, 11 Nov 2018 13:16:40 +0100 Subject: [PATCH 0819/2459] Code style fix --- tests/Foundation/Http/Middleware/TransformsRequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Foundation/Http/Middleware/TransformsRequestTest.php b/tests/Foundation/Http/Middleware/TransformsRequestTest.php index 041aad7e73e8..898393660767 100644 --- a/tests/Foundation/Http/Middleware/TransformsRequestTest.php +++ b/tests/Foundation/Http/Middleware/TransformsRequestTest.php @@ -54,7 +54,7 @@ public function testTransformOncePerArrayKeysWhenMethodIsPost() 'beers' => [4, 8, 12], ], [ - 'age' => [28, 56, 84] + 'age' => [28, 56, 84], ] ); $symfonyRequest->server->set('REQUEST_METHOD', 'POST'); From 5d12eaa7a3a1bd7c0e523a0a2c4fa8eb2bfd4110 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 11 Nov 2018 14:40:58 +0200 Subject: [PATCH 0820/2459] [5.7] Update changelog - 11/11/2018 --- CHANGELOG-5.7.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index 0a3570f7f1f1..dfc6879475da 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -1,5 +1,21 @@ # Release Notes for 5.7.x +## Unreleased + +### Added +- Added `Macroable` trait to `Illuminate\Cookie\CookieJar` ([#26445](https://github.com/laravel/framework/pull/26445)) + +### Fixed +- Fixed `UNION` aggregate queries with columns ([#26466](https://github.com/laravel/framework/pull/26466)) +- Allowed migration table name to be guessed without `_table` suffix ([#26429](https://github.com/laravel/framework/pull/26429)) + +### Changed +- Improved eager loading performance ([#26434](https://github.com/laravel/framework/pull/26434), [#26453](https://github.com/laravel/framework/pull/26453), [3992140](https://github.com/laravel/framework/commit/3992140064307ef82d23328995e7c59045c231f2)) +- Adjusted `mix` missing asset exceptions ([#26431](https://github.com/laravel/framework/pull/26431)) +- Used `asset` helper to generate full path urls in exception views ([#26411](https://github.com/laravel/framework/pull/26411)) +- Changed `Illuminate\Foundation\Testing\Concerns\MocksApplicationServices::withoutJobs` method ([#26437](https://github.com/laravel/framework/pull/26437)) + + ## [v5.7.13 (2018-11-07)](https://github.com/laravel/framework/compare/v5.7.12...v5.7.13) ### Added From abd59621b6b077ea54103a61a79ee87e79be128b Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 11 Nov 2018 14:47:20 +0200 Subject: [PATCH 0821/2459] [5.7] Update changelog - 11/11/2018 - added missed commit --- CHANGELOG-5.7.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index dfc6879475da..fd18ecc7d25a 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -4,6 +4,7 @@ ### Added - Added `Macroable` trait to `Illuminate\Cookie\CookieJar` ([#26445](https://github.com/laravel/framework/pull/26445)) +- Added ability to disable password reset route ([#26459](https://github.com/laravel/framework/pull/26459)) ### Fixed - Fixed `UNION` aggregate queries with columns ([#26466](https://github.com/laravel/framework/pull/26466)) From d52298af424f0a5751a3748dc8d8c8330b4c8a77 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Sun, 11 Nov 2018 14:46:39 +0100 Subject: [PATCH 0822/2459] [5.8] Fix Application contract violations --- src/Illuminate/Auth/AuthManager.php | 4 +- .../Auth/Passwords/PasswordBrokerManager.php | 4 +- .../Broadcasting/BroadcastManager.php | 4 +- src/Illuminate/Cache/CacheManager.php | 4 +- .../Contracts/Container/Container.php | 7 + .../Contracts/Foundation/Application.php | 181 ++++++++++++++++++ src/Illuminate/Database/DatabaseManager.php | 4 +- .../Foundation/Console/RouteCacheCommand.php | 2 +- .../Http/Middleware/VerifyCsrfToken.php | 6 +- .../Foundation/Testing/PendingCommand.php | 4 +- .../Foundation/Testing/TestCase.php | 2 +- src/Illuminate/Foundation/helpers.php | 2 +- src/Illuminate/Log/LogManager.php | 4 +- src/Illuminate/Queue/QueueManager.php | 4 +- src/Illuminate/Redis/RedisManager.php | 4 +- src/Illuminate/Support/Facades/App.php | 2 +- src/Illuminate/Support/Manager.php | 4 +- src/Illuminate/Support/ServiceProvider.php | 4 +- tests/Foundation/Http/KernelTest.php | 2 +- tests/Integration/Events/EventFakeTest.php | 2 +- 20 files changed, 219 insertions(+), 31 deletions(-) diff --git a/src/Illuminate/Auth/AuthManager.php b/src/Illuminate/Auth/AuthManager.php index 05fefe172d67..3a46c20ccb4b 100755 --- a/src/Illuminate/Auth/AuthManager.php +++ b/src/Illuminate/Auth/AuthManager.php @@ -13,7 +13,7 @@ class AuthManager implements FactoryContract /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -43,7 +43,7 @@ class AuthManager implements FactoryContract /** * Create a new Auth manager instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) diff --git a/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php b/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php index 1d943bd64f89..6294716aa012 100644 --- a/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php +++ b/src/Illuminate/Auth/Passwords/PasswordBrokerManager.php @@ -14,7 +14,7 @@ class PasswordBrokerManager implements FactoryContract /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -28,7 +28,7 @@ class PasswordBrokerManager implements FactoryContract /** * Create a new PasswordBroker manager instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index 864b32010507..368d48b89c3b 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -21,7 +21,7 @@ class BroadcastManager implements FactoryContract /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -42,7 +42,7 @@ class BroadcastManager implements FactoryContract /** * Create a new manager instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) diff --git a/src/Illuminate/Cache/CacheManager.php b/src/Illuminate/Cache/CacheManager.php index 6c2e6d8f9d01..1bd292d9f978 100755 --- a/src/Illuminate/Cache/CacheManager.php +++ b/src/Illuminate/Cache/CacheManager.php @@ -16,7 +16,7 @@ class CacheManager implements FactoryContract /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -37,7 +37,7 @@ class CacheManager implements FactoryContract /** * Create a new Cache manager instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) diff --git a/src/Illuminate/Contracts/Container/Container.php b/src/Illuminate/Contracts/Container/Container.php index 9fa2114658c2..6bb7456b2c5f 100644 --- a/src/Illuminate/Contracts/Container/Container.php +++ b/src/Illuminate/Contracts/Container/Container.php @@ -107,6 +107,13 @@ public function when($concrete); */ public function factory($abstract); + /** + * Flush the container of all bindings and resolved instances. + * + * @return void + */ + public function flush(); + /** * Resolve the given type from the container. * diff --git a/src/Illuminate/Contracts/Foundation/Application.php b/src/Illuminate/Contracts/Foundation/Application.php index 622381a3ab17..7633ae9e3dbf 100644 --- a/src/Illuminate/Contracts/Foundation/Application.php +++ b/src/Illuminate/Contracts/Foundation/Application.php @@ -2,6 +2,7 @@ namespace Illuminate\Contracts\Foundation; +use Closure; use Illuminate\Contracts\Container\Container; interface Application extends Container @@ -20,6 +21,52 @@ public function version(); */ public function basePath(); + /** + * Get the path to the bootstrap directory. + * + * @param string $path Optionally, a path to append to the bootstrap path + * @return string + */ + public function bootstrapPath($path = ''); + + /** + * Get the path to the application configuration files. + * + * @param string $path Optionally, a path to append to the config path + * @return string + */ + public function configPath($path = ''); + + /** + * Get the path to the database directory. + * + * @param string $path Optionally, a path to append to the database path + * @return string + */ + public function databasePath($path = ''); + + /** + * Get the path to the environment file directory. + * + * @return string + */ + public function environmentPath(); + + /** + * Get the path to the resources directory. + * + * @param string $path + * @return string + */ + public function resourcePath($path = ''); + + /** + * Get the path to the storage directory. + * + * @return string + */ + public function storagePath(); + /** * Get or check the current application environment. * @@ -74,6 +121,14 @@ public function register($provider, $force = false); */ public function registerDeferredProvider($provider, $service = null); + /** + * Resolve a service provider instance from the class name. + * + * @param string $provider + * @return \Illuminate\Support\ServiceProvider + */ + public function resolveProvider($provider); + /** * Boot the application's service providers. * @@ -97,6 +152,50 @@ public function booting($callback); */ public function booted($callback); + /** + * Run the given array of bootstrap classes. + * + * @param array $bootstrappers + * @return void + */ + public function bootstrapWith(array $bootstrappers); + + /** + * Determine if the application configuration is cached. + * + * @return bool + */ + public function configurationIsCached(); + + /** + * Detect the application's current environment. + * + * @param \Closure $callback + * @return string + */ + public function detectEnvironment(Closure $callback); + + /** + * Get the environment file the application is using. + * + * @return string + */ + public function environmentFile(); + + /** + * Get the fully qualified path to the environment file. + * + * @return string + */ + public function environmentFilePath(); + + /** + * Get the path to the configuration cache file. + * + * @return string + */ + public function getCachedConfigPath(); + /** * Get the path to the cached services.php file. * @@ -110,4 +209,86 @@ public function getCachedServicesPath(); * @return string */ public function getCachedPackagesPath(); + + /** + * Get the path to the routes cache file. + * + * @return string + */ + public function getCachedRoutesPath(); + + /** + * Get the current application locale. + * + * @return string + */ + public function getLocale(); + + /** + * Get the application namespace. + * + * @return string + * + * @throws \RuntimeException + */ + public function getNamespace(); + + /** + * Get the registered service provider instances if any exist. + * + * @param \Illuminate\Support\ServiceProvider|string $provider + * @return array + */ + public function getProviders($provider); + + /** + * Determine if the application has been bootstrapped before. + * + * @return bool + */ + public function hasBeenBootstrapped(); + + /** + * Load and boot all of the remaining deferred providers. + * + * @return void + */ + public function loadDeferredProviders(); + + /** + * Set the environment file to be loaded during bootstrapping. + * + * @param string $file + * @return $this + */ + public function loadEnvironmentFrom($file); + + /** + * Determine if the application routes are cached. + * + * @return bool + */ + public function routesAreCached(); + + /** + * Set the current application locale. + * + * @param string $locale + * @return void + */ + public function setLocale($locale); + + /** + * Determine if middleware has been disabled for the application. + * + * @return bool + */ + public function shouldSkipMiddleware(); + + /** + * Terminate the application. + * + * @return void + */ + public function terminate(); } diff --git a/src/Illuminate/Database/DatabaseManager.php b/src/Illuminate/Database/DatabaseManager.php index cb0f3bc9c1c5..f28493e5feaa 100755 --- a/src/Illuminate/Database/DatabaseManager.php +++ b/src/Illuminate/Database/DatabaseManager.php @@ -16,7 +16,7 @@ class DatabaseManager implements ConnectionResolverInterface /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -44,7 +44,7 @@ class DatabaseManager implements ConnectionResolverInterface /** * Create a new database manager instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Database\Connectors\ConnectionFactory $factory * @return void */ diff --git a/src/Illuminate/Foundation/Console/RouteCacheCommand.php b/src/Illuminate/Foundation/Console/RouteCacheCommand.php index 3c85b877fc84..9d86f16fd70c 100644 --- a/src/Illuminate/Foundation/Console/RouteCacheCommand.php +++ b/src/Illuminate/Foundation/Console/RouteCacheCommand.php @@ -85,7 +85,7 @@ protected function getFreshApplicationRoutes() /** * Get a fresh application instance. * - * @return \Illuminate\Foundation\Application + * @return \Illuminate\Contracts\Foundation\Application */ protected function getFreshApplication() { diff --git a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php index 2c21bcfb7464..04d946bd551a 100644 --- a/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php +++ b/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php @@ -3,11 +3,11 @@ namespace Illuminate\Foundation\Http\Middleware; use Closure; -use Illuminate\Foundation\Application; use Illuminate\Support\InteractsWithTime; use Symfony\Component\HttpFoundation\Cookie; use Illuminate\Contracts\Encryption\Encrypter; use Illuminate\Session\TokenMismatchException; +use Illuminate\Contracts\Foundation\Application; use Illuminate\Cookie\Middleware\EncryptCookies; class VerifyCsrfToken @@ -17,7 +17,7 @@ class VerifyCsrfToken /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -45,7 +45,7 @@ class VerifyCsrfToken /** * Create a new middleware instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Contracts\Encryption\Encrypter $encrypter * @return void */ diff --git a/src/Illuminate/Foundation/Testing/PendingCommand.php b/src/Illuminate/Foundation/Testing/PendingCommand.php index 2a40aed1c789..5beb03c458f5 100644 --- a/src/Illuminate/Foundation/Testing/PendingCommand.php +++ b/src/Illuminate/Foundation/Testing/PendingCommand.php @@ -22,7 +22,7 @@ class PendingCommand /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -58,7 +58,7 @@ class PendingCommand * Create a new pending console command run. * * @param \PHPUnit\Framework\TestCase $test - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @param string $command * @param array $parameters * @return void diff --git a/src/Illuminate/Foundation/Testing/TestCase.php b/src/Illuminate/Foundation/Testing/TestCase.php index 08c150b6f1d9..01e2d2361676 100644 --- a/src/Illuminate/Foundation/Testing/TestCase.php +++ b/src/Illuminate/Foundation/Testing/TestCase.php @@ -24,7 +24,7 @@ abstract class TestCase extends BaseTestCase /** * The Illuminate application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index a3c40e78854e..45f29d11e4c6 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -110,7 +110,7 @@ function action($name, $parameters = [], $absolute = true) * * @param string $abstract * @param array $parameters - * @return mixed|\Illuminate\Foundation\Application + * @return mixed|\Illuminate\Contracts\Foundation\Application */ function app($abstract = null, array $parameters = []) { diff --git a/src/Illuminate/Log/LogManager.php b/src/Illuminate/Log/LogManager.php index 92507e461e11..c89afbed7e8f 100644 --- a/src/Illuminate/Log/LogManager.php +++ b/src/Illuminate/Log/LogManager.php @@ -23,7 +23,7 @@ class LogManager implements LoggerInterface /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -44,7 +44,7 @@ class LogManager implements LoggerInterface /** * Create a new Log manager instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) diff --git a/src/Illuminate/Queue/QueueManager.php b/src/Illuminate/Queue/QueueManager.php index f9bb7f6aec89..30f349e02fd8 100755 --- a/src/Illuminate/Queue/QueueManager.php +++ b/src/Illuminate/Queue/QueueManager.php @@ -15,7 +15,7 @@ class QueueManager implements FactoryContract, MonitorContract /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -36,7 +36,7 @@ class QueueManager implements FactoryContract, MonitorContract /** * Create a new queue manager instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) diff --git a/src/Illuminate/Redis/RedisManager.php b/src/Illuminate/Redis/RedisManager.php index 969c4dbe3cce..b8111d4f1429 100644 --- a/src/Illuminate/Redis/RedisManager.php +++ b/src/Illuminate/Redis/RedisManager.php @@ -14,7 +14,7 @@ class RedisManager implements Factory /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -49,7 +49,7 @@ class RedisManager implements Factory /** * Create a new Redis manager instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @param string $driver * @param array $config * @return void diff --git a/src/Illuminate/Support/Facades/App.php b/src/Illuminate/Support/Facades/App.php index 0e9e6370f2f0..cf33283af9fb 100755 --- a/src/Illuminate/Support/Facades/App.php +++ b/src/Illuminate/Support/Facades/App.php @@ -15,7 +15,7 @@ * @method static void booted(mixed $callback) * @method static string getCachedServicesPath() * - * @see \Illuminate\Foundation\Application + * @see \Illuminate\Contracts\Foundation\Application */ class App extends Facade { diff --git a/src/Illuminate/Support/Manager.php b/src/Illuminate/Support/Manager.php index f759f0a7037d..38e9308f7120 100755 --- a/src/Illuminate/Support/Manager.php +++ b/src/Illuminate/Support/Manager.php @@ -10,7 +10,7 @@ abstract class Manager /** * The application instance. * - * @var \Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -31,7 +31,7 @@ abstract class Manager /** * Create a new manager instance. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) diff --git a/src/Illuminate/Support/ServiceProvider.php b/src/Illuminate/Support/ServiceProvider.php index 09c35fcab08f..109e32826d08 100755 --- a/src/Illuminate/Support/ServiceProvider.php +++ b/src/Illuminate/Support/ServiceProvider.php @@ -9,7 +9,7 @@ abstract class ServiceProvider /** * The application instance. * - * @var \Illuminate\Contracts\Foundation\Application|\Illuminate\Foundation\Application + * @var \Illuminate\Contracts\Foundation\Application */ protected $app; @@ -37,7 +37,7 @@ abstract class ServiceProvider /** * Create a new service provider instance. * - * @param \Illuminate\Contracts\Foundation\Application|\Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct($app) diff --git a/tests/Foundation/Http/KernelTest.php b/tests/Foundation/Http/KernelTest.php index e3f2d68203ff..94032a27c396 100644 --- a/tests/Foundation/Http/KernelTest.php +++ b/tests/Foundation/Http/KernelTest.php @@ -18,7 +18,7 @@ public function testGetMiddlewareGroups() } /** - * @return \Illuminate\Foundation\Application + * @return \Illuminate\Contracts\Foundation\Application */ protected function getApplication() { diff --git a/tests/Integration/Events/EventFakeTest.php b/tests/Integration/Events/EventFakeTest.php index cd1c09f6a917..55be86cd9670 100644 --- a/tests/Integration/Events/EventFakeTest.php +++ b/tests/Integration/Events/EventFakeTest.php @@ -13,7 +13,7 @@ class EventFakeTest extends TestCase /** * Define environment setup. * - * @param \Illuminate\Foundation\Application $app + * @param \Illuminate\Contracts\Foundation\Application $app * * @return void */ From 74c5730070f4f510993dce843d004903e4b49889 Mon Sep 17 00:00:00 2001 From: Simon Svensson Date: Sun, 11 Nov 2018 14:50:44 +0100 Subject: [PATCH 0823/2459] [5.8] Revert #26454 and change default to bigIncrements in the migration stub (#26472) * Revert "Add tests for switching the default increments() method" This reverts commit 22e1f7c8d54f04b916ef352f27f858c16b570c7f. * Revert "Make tests use bigincrements as default" This reverts commit fd6002feedcd99326d6a17966bb8d6d091a8c77a. * Revert "Switch increments to use unsignedBigInteger" This reverts commit a40653328d830b92b464540bc1468b6f183b75d4. * Use bigIncrements --- .../Database/Migrations/stubs/create.stub | 2 +- src/Illuminate/Database/Schema/Blueprint.php | 4 +- src/Illuminate/Database/Schema/Builder.php | 17 --------- .../DatabaseMySqlSchemaGrammarTest.php | 37 ++++--------------- .../DatabasePostgresSchemaGrammarTest.php | 35 ++++-------------- .../DatabaseSqlServerSchemaGrammarTest.php | 29 ++------------- 6 files changed, 22 insertions(+), 102 deletions(-) diff --git a/src/Illuminate/Database/Migrations/stubs/create.stub b/src/Illuminate/Database/Migrations/stubs/create.stub index a98c4749cb1f..08e171bc558f 100755 --- a/src/Illuminate/Database/Migrations/stubs/create.stub +++ b/src/Illuminate/Database/Migrations/stubs/create.stub @@ -14,7 +14,7 @@ class DummyClass extends Migration public function up() { Schema::create('DummyTable', function (Blueprint $table) { - $table->increments('id'); + $table->bigIncrements('id'); $table->timestamps(); }); } diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index afbc4e97fd52..6ff1af22a2c3 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -526,14 +526,14 @@ public function foreign($columns, $name = null) } /** - * Create a new auto-incrementing integer column on the table. + * Create a new auto-incrementing integer (4-byte) column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function increments($column) { - return $this->{Builder::$defaultIncrementsType}($column, true); + return $this->unsignedInteger($column, true); } /** diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 6c378a6a0cc9..2e25cf0cd9dc 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -36,13 +36,6 @@ class Builder */ public static $defaultStringLength = 255; - /** - * The default increments type for migrations. - * - * @var string - */ - public static $defaultIncrementsType = 'unsignedBigInteger'; - /** * Create a new database Schema manager. * @@ -66,16 +59,6 @@ public static function defaultStringLength($length) static::$defaultStringLength = $length; } - /** - * Set the default increments type to a 4 byte integer. - * - * @return void - */ - public static function useIntegerIncrements() - { - static::$defaultIncrementsType = 'unsignedInteger'; - } - /** * Determine if the given table exists. * diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index 44fc51de6f48..11091f7b4375 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -5,7 +5,6 @@ use Mockery as m; use PHPUnit\Framework\TestCase; use Illuminate\Database\Connection; -use Illuminate\Database\Schema\Builder; use Illuminate\Database\Query\Expression; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Grammars\MySqlGrammar; @@ -32,7 +31,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); + $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); $blueprint = new Blueprint('users'); $blueprint->increments('id'); @@ -44,7 +43,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table `users` add `id` bigint unsigned not null auto_increment primary key, add `email` varchar(255) not null', $statements[0]); + $this->assertEquals('alter table `users` add `id` int unsigned not null auto_increment primary key, add `email` varchar(255) not null', $statements[0]); } public function testEngineCreateTable() @@ -62,7 +61,7 @@ public function testEngineCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); + $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); $blueprint = new Blueprint('users'); $blueprint->create(); @@ -77,7 +76,7 @@ public function testEngineCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); + $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8 collate 'utf8_unicode_ci' engine = InnoDB", $statements[0]); } public function testCharsetCollationCreateTable() @@ -95,7 +94,7 @@ public function testCharsetCollationCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'", $statements[0]); + $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'", $statements[0]); $blueprint = new Blueprint('users'); $blueprint->create(); @@ -110,7 +109,7 @@ public function testCharsetCollationCreateTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals("create table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) character set utf8mb4 collate 'utf8mb4_unicode_ci' not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); + $this->assertEquals("create table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) character set utf8mb4 collate 'utf8mb4_unicode_ci' not null) default character set utf8 collate 'utf8_unicode_ci'", $statements[0]); } public function testBasicCreateTableWithPrefix() @@ -128,7 +127,7 @@ public function testBasicCreateTableWithPrefix() $statements = $blueprint->toSql($conn, $grammar); $this->assertCount(1, $statements); - $this->assertEquals('create table `prefix_users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); + $this->assertEquals('create table `prefix_users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); } public function testCreateTemporaryTable() @@ -145,7 +144,7 @@ public function testCreateTemporaryTable() $statements = $blueprint->toSql($conn, $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create temporary table `users` (`id` bigint unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); + $this->assertEquals('create temporary table `users` (`id` int unsigned not null auto_increment primary key, `email` varchar(255) not null)', $statements[0]); } public function testDropTable() @@ -379,18 +378,8 @@ public function testAddingIncrementingID() $blueprint->increments('id'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertEquals('alter table `users` add `id` bigint unsigned not null auto_increment primary key', $statements[0]); - - Builder::useIntegerIncrements(); - $blueprint = new Blueprint('users'); - $blueprint->increments('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); $this->assertEquals('alter table `users` add `id` int unsigned not null auto_increment primary key', $statements[0]); - - Builder::$defaultIncrementsType = 'unsignedBigInteger'; } public function testAddingSmallIncrementingID() @@ -403,16 +392,6 @@ public function testAddingSmallIncrementingID() $this->assertEquals('alter table `users` add `id` smallint unsigned not null auto_increment primary key', $statements[0]); } - public function testAddingIntegerIncrementingID() - { - $blueprint = new Blueprint('users'); - $blueprint->integerIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - - $this->assertCount(1, $statements); - $this->assertEquals('alter table `users` add `id` int unsigned not null auto_increment primary key', $statements[0]); - } - public function testAddingBigIncrementingID() { $blueprint = new Blueprint('users'); diff --git a/tests/Database/DatabasePostgresSchemaGrammarTest.php b/tests/Database/DatabasePostgresSchemaGrammarTest.php index 2dc25bc45cd0..da42ae4e5fea 100755 --- a/tests/Database/DatabasePostgresSchemaGrammarTest.php +++ b/tests/Database/DatabasePostgresSchemaGrammarTest.php @@ -5,7 +5,6 @@ use Mockery as m; use PHPUnit\Framework\TestCase; use Illuminate\Database\Connection; -use Illuminate\Database\Schema\Builder; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Grammars\PostgresGrammar; @@ -25,7 +24,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create table "users" ("id" bigserial primary key not null, "email" varchar(255) not null)', $statements[0]); + $this->assertEquals('create table "users" ("id" serial primary key not null, "email" varchar(255) not null)', $statements[0]); $blueprint = new Blueprint('users'); $blueprint->increments('id'); @@ -33,7 +32,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "id" bigserial primary key not null, add column "email" varchar(255) not null', $statements[0]); + $this->assertEquals('alter table "users" add column "id" serial primary key not null, add column "email" varchar(255) not null', $statements[0]); } public function testCreateTableAndCommentColumn() @@ -45,7 +44,7 @@ public function testCreateTableAndCommentColumn() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(2, $statements); - $this->assertEquals('create table "users" ("id" bigserial primary key not null, "email" varchar(255) not null)', $statements[0]); + $this->assertEquals('create table "users" ("id" serial primary key not null, "email" varchar(255) not null)', $statements[0]); $this->assertEquals('comment on column "users"."email" is \'my first comment\'', $statements[1]); } @@ -59,7 +58,7 @@ public function testCreateTemporaryTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create temporary table "users" ("id" bigserial primary key not null, "email" varchar(255) not null)', $statements[0]); + $this->assertEquals('create temporary table "users" ("id" serial primary key not null, "email" varchar(255) not null)', $statements[0]); } public function testDropTable() @@ -273,18 +272,8 @@ public function testAddingIncrementingID() $blueprint->increments('id'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "id" bigserial primary key not null', $statements[0]); - - Builder::useIntegerIncrements(); - $blueprint = new Blueprint('users'); - $blueprint->increments('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); $this->assertEquals('alter table "users" add column "id" serial primary key not null', $statements[0]); - - Builder::$defaultIncrementsType = 'unsignedBigInteger'; } public function testAddingSmallIncrementingID() @@ -307,16 +296,6 @@ public function testAddingMediumIncrementingID() $this->assertEquals('alter table "users" add column "id" serial primary key not null', $statements[0]); } - public function testAddingIntegerIncrementingID() - { - $blueprint = new Blueprint('users'); - $blueprint->integerIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - - $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "id" serial primary key not null', $statements[0]); - } - public function testAddingBigIncrementingID() { $blueprint = new Blueprint('users'); @@ -687,19 +666,19 @@ public function testAddingGeneratedAs() $blueprint->increments('foo')->generatedAs(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "foo" bigint generated by default as identity primary key not null', $statements[0]); + $this->assertEquals('alter table "users" add column "foo" integer generated by default as identity primary key not null', $statements[0]); // With always modifier $blueprint = new Blueprint('users'); $blueprint->increments('foo')->generatedAs()->always(); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "foo" bigint generated always as identity primary key not null', $statements[0]); + $this->assertEquals('alter table "users" add column "foo" integer generated always as identity primary key not null', $statements[0]); // With sequence options $blueprint = new Blueprint('users'); $blueprint->increments('foo')->generatedAs('increment by 10 start with 100'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add column "foo" bigint generated by default as identity (increment by 10 start with 100) primary key not null', $statements[0]); + $this->assertEquals('alter table "users" add column "foo" integer generated by default as identity (increment by 10 start with 100) primary key not null', $statements[0]); // Not a primary key $blueprint = new Blueprint('users'); $blueprint->integer('foo')->generatedAs(); diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index 61a873e8ed6a..c51722e8a40d 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -5,7 +5,6 @@ use Mockery as m; use PHPUnit\Framework\TestCase; use Illuminate\Database\Connection; -use Illuminate\Database\Schema\Builder; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Grammars\SqlServerGrammar; @@ -25,7 +24,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create table "users" ("id" bigint identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); + $this->assertEquals('create table "users" ("id" int identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); $blueprint = new Blueprint('users'); $blueprint->increments('id'); @@ -33,7 +32,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add "id" bigint identity primary key not null, "email" nvarchar(255) not null', $statements[0]); + $this->assertEquals('alter table "users" add "id" int identity primary key not null, "email" nvarchar(255) not null', $statements[0]); $blueprint = new Blueprint('users'); $blueprint->create(); @@ -42,7 +41,7 @@ public function testBasicCreateTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()->setTablePrefix('prefix_')); $this->assertCount(1, $statements); - $this->assertEquals('create table "prefix_users" ("id" bigint identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); + $this->assertEquals('create table "prefix_users" ("id" int identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); } public function testCreateTemporaryTable() @@ -55,7 +54,7 @@ public function testCreateTemporaryTable() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('create table "#users" ("id" bigint identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); + $this->assertEquals('create table "#users" ("id" int identity primary key not null, "email" nvarchar(255) not null)', $statements[0]); } public function testDropTable() @@ -273,18 +272,8 @@ public function testAddingIncrementingID() $blueprint->increments('id'); $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add "id" bigint identity primary key not null', $statements[0]); - - Builder::useIntegerIncrements(); - $blueprint = new Blueprint('users'); - $blueprint->increments('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - $this->assertCount(1, $statements); $this->assertEquals('alter table "users" add "id" int identity primary key not null', $statements[0]); - - Builder::$defaultIncrementsType = 'unsignedBigInteger'; } public function testAddingSmallIncrementingID() @@ -307,16 +296,6 @@ public function testAddingMediumIncrementingID() $this->assertEquals('alter table "users" add "id" int identity primary key not null', $statements[0]); } - public function testAddingIntegerIncrementingID() - { - $blueprint = new Blueprint('users'); - $blueprint->integerIncrements('id'); - $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); - - $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add "id" int identity primary key not null', $statements[0]); - } - public function testAddingBigIncrementingID() { $blueprint = new Blueprint('users'); From a3738cf4e133a4475c56b51f521a12db78e2ecbb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 11 Nov 2018 08:07:04 -0600 Subject: [PATCH 0824/2459] formatting --- src/Illuminate/Database/Eloquent/Relations/Relation.php | 2 +- src/Illuminate/Database/Query/Builder.php | 2 +- tests/Database/DatabaseEloquentBelongsToTest.php | 8 ++++---- tests/Database/DatabaseEloquentHasManyTest.php | 2 +- tests/Database/DatabaseEloquentHasOneTest.php | 2 +- tests/Database/DatabaseEloquentMorphTest.php | 2 +- tests/Database/DatabaseEloquentMorphToManyTest.php | 2 +- tests/Database/DatabaseQueryBuilderTest.php | 4 ++-- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index b2882a5a3a0f..e16ade9981a9 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -318,7 +318,7 @@ protected function whereInMethod(Model $model, $key) { return $model->getKeyName() === last(explode('.', $key)) && in_array($model->getKeyType(), ['int', 'integer']) - ? 'whereInRawInt' + ? 'whereIntegerInRaw' : 'whereIn'; } diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 4189e169ae31..3ad96bb06e31 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -957,7 +957,7 @@ protected function whereInExistingQuery($column, $query, $boolean, $not) * @param bool $not * @return $this */ - public function whereInRawInt($column, $values, $boolean = 'and', $not = false) + public function whereIntegerInRaw($column, $values, $boolean = 'and', $not = false) { $type = $not ? 'NotInRaw' : 'InRaw'; diff --git a/tests/Database/DatabaseEloquentBelongsToTest.php b/tests/Database/DatabaseEloquentBelongsToTest.php index 77efba013a34..5f92c683ca09 100755 --- a/tests/Database/DatabaseEloquentBelongsToTest.php +++ b/tests/Database/DatabaseEloquentBelongsToTest.php @@ -81,7 +81,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('relation.id', ['foreign.value', 'foreign.value.two']); + $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('relation.id', ['foreign.value', 'foreign.value.two']); $models = [new EloquentBelongsToModelStub, new EloquentBelongsToModelStub, new AnotherEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } @@ -91,7 +91,7 @@ public function testIdsInEagerConstraintsCanBeZero() $relation = $this->getRelation(); $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('relation.id', ['foreign.value', 0]); + $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('relation.id', ['foreign.value', 0]); $models = [new EloquentBelongsToModelStub, new EloquentBelongsToModelStubWithZeroId]; $relation->addEagerConstraints($models); } @@ -160,7 +160,7 @@ public function testDefaultEagerConstraintsWhenIncrementing() $relation = $this->getRelation(); $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('relation.id', m::mustBe([null])); + $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('relation.id', m::mustBe([null])); $models = [new MissingEloquentBelongsToModelStub, new MissingEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } @@ -178,7 +178,7 @@ public function testDefaultEagerConstraintsWhenNotIncrementing() $relation = $this->getRelation(null, false); $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('relation.id', m::mustBe([null])); + $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('relation.id', m::mustBe([null])); $models = [new MissingEloquentBelongsToModelStub, new MissingEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } diff --git a/tests/Database/DatabaseEloquentHasManyTest.php b/tests/Database/DatabaseEloquentHasManyTest.php index 0f922e895179..96fd019cb137 100755 --- a/tests/Database/DatabaseEloquentHasManyTest.php +++ b/tests/Database/DatabaseEloquentHasManyTest.php @@ -202,7 +202,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('table.foreign_key', [1, 2]); + $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasManyModelStub; $model1->id = 1; $model2 = new EloquentHasManyModelStub; diff --git a/tests/Database/DatabaseEloquentHasOneTest.php b/tests/Database/DatabaseEloquentHasOneTest.php index f60b42b83d42..3238058c9641 100755 --- a/tests/Database/DatabaseEloquentHasOneTest.php +++ b/tests/Database/DatabaseEloquentHasOneTest.php @@ -165,7 +165,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('table.foreign_key', [1, 2]); + $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasOneModelStub; $model1->id = 1; $model2 = new EloquentHasOneModelStub; diff --git a/tests/Database/DatabaseEloquentMorphTest.php b/tests/Database/DatabaseEloquentMorphTest.php index 18bcc81436cf..02517ec3a48f 100755 --- a/tests/Database/DatabaseEloquentMorphTest.php +++ b/tests/Database/DatabaseEloquentMorphTest.php @@ -54,7 +54,7 @@ public function testMorphManyEagerConstraintsAreProperlyAdded() $relation = $this->getManyRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('table.morph_id', [1, 2]); + $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('table.morph_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent())); $model1 = new EloquentMorphResetModelStub; diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php index 6a481b08422c..af60b5167a2a 100644 --- a/tests/Database/DatabaseEloquentMorphToManyTest.php +++ b/tests/Database/DatabaseEloquentMorphToManyTest.php @@ -20,7 +20,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->andReturn('id'); $relation->getParent()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereInRawInt')->once()->with('taggables.taggable_id', [1, 2]); + $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('taggables.taggable_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('taggables.taggable_type', get_class($relation->getParent())); $model1 = new EloquentMorphToManyModelStub; $model1->id = 1; diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 4fd235088a54..c3e9f3b77f90 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -693,10 +693,10 @@ public function testEmptyWhereNotIns() $this->assertEquals([0 => 1], $builder->getBindings()); } - public function testWhereInRawInt() + public function testwhereIntegerInRaw() { $builder = $this->getBuilder(); - $builder->select('*')->from('users')->whereInRawInt('id', ['1a', 2]); + $builder->select('*')->from('users')->whereIntegerInRaw('id', ['1a', 2]); $this->assertEquals('select * from "users" where "id" in (1, 2)', $builder->toSql()); $this->assertEquals([], $builder->getBindings()); } From 6d81739d1b0d62c724215f78b5415725d3808b3b Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Sun, 11 Nov 2018 12:09:55 -0200 Subject: [PATCH 0825/2459] [5.7] Documentation fixes (#26476) * Add missing $absolute param to URL facade * Fix phpDocs - Remove nonexistent parameters - Add missing parameters variables - Fix array syntax - Wrong return or param types --- src/Illuminate/Auth/Access/Gate.php | 1 - src/Illuminate/Contracts/Filesystem/Filesystem.php | 2 +- .../Database/Eloquent/Relations/Concerns/AsPivot.php | 2 +- src/Illuminate/Database/Eloquent/Relations/MorphPivot.php | 2 +- src/Illuminate/Database/Seeder.php | 2 +- .../Foundation/Testing/Concerns/InteractsWithContainer.php | 4 ++-- src/Illuminate/Queue/CallQueuedClosure.php | 2 +- src/Illuminate/Support/Collection.php | 4 ---- src/Illuminate/Support/Facades/URL.php | 2 +- 9 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index e7a3f9cc6596..214bc8b80bb5 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -385,7 +385,6 @@ protected function methodAllowsGuests($class, $method) * Determine if the callback allows guests. * * @param callable $callback - * @param array $arguments * @return bool */ protected function callbackAllowsGuests($callback) diff --git a/src/Illuminate/Contracts/Filesystem/Filesystem.php b/src/Illuminate/Contracts/Filesystem/Filesystem.php index df5679bb731a..d77274be1684 100644 --- a/src/Illuminate/Contracts/Filesystem/Filesystem.php +++ b/src/Illuminate/Contracts/Filesystem/Filesystem.php @@ -61,7 +61,7 @@ public function put($path, $contents, $options = []); * * @param string $path * @param resource $resource - * @param mixed $options + * @param array $options * @return bool * * @throws \InvalidArgumentException If $resource is not a file handle. diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php index ea9727420333..58f5430ed0ea 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/AsPivot.php @@ -247,7 +247,7 @@ public function getQueueableId() /** * Get a new query to restore one or more models by their queueable IDs. * - * @param array|int $ids + * @param array $ids * @return \Illuminate\Database\Eloquent\Builder */ public function newQueryForRestoration($ids) diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php b/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php index a8a9210f0e45..ade59535241f 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphPivot.php @@ -124,7 +124,7 @@ public function newQueryForRestoration($ids) /** * Get a new query to restore multiple models by their queueable IDs. * - * @param array|int $ids + * @param array $ids * @return \Illuminate\Database\Eloquent\Builder */ protected function newQueryForCollectionRestoration(array $ids) diff --git a/src/Illuminate/Database/Seeder.php b/src/Illuminate/Database/Seeder.php index e4d300968d9e..f8675ea3cd90 100755 --- a/src/Illuminate/Database/Seeder.php +++ b/src/Illuminate/Database/Seeder.php @@ -108,7 +108,7 @@ public function setCommand(Command $command) /** * Run the database seeds. * - * @return void + * @return dynamic * * @throws \InvalidArgumentException */ diff --git a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithContainer.php b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithContainer.php index 9f275b0d19a8..907760194c74 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/InteractsWithContainer.php +++ b/src/Illuminate/Foundation/Testing/Concerns/InteractsWithContainer.php @@ -37,7 +37,7 @@ protected function instance($abstract, $instance) * Mock an instance of an object in the container. * * @param string $abstract - * @param \Closure|null $instance + * @param \Closure|null $mock * @return object */ protected function mock($abstract, Closure $mock = null) @@ -49,7 +49,7 @@ protected function mock($abstract, Closure $mock = null) * Spy an instance of an object in the container. * * @param string $abstract - * @param \Closure|null $instance + * @param \Closure|null $mock * @return object */ protected function spy($abstract, Closure $mock = null) diff --git a/src/Illuminate/Queue/CallQueuedClosure.php b/src/Illuminate/Queue/CallQueuedClosure.php index 79aaae15e600..616e7ed14d5a 100644 --- a/src/Illuminate/Queue/CallQueuedClosure.php +++ b/src/Illuminate/Queue/CallQueuedClosure.php @@ -29,7 +29,7 @@ class CallQueuedClosure implements ShouldQueue /** * Create a new job instance. * - * @param \Illuminate\Queue\SerializableClosure + * @param \Illuminate\Queue\SerializableClosure $closure * @return void */ public function __construct(SerializableClosure $closure) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index f3449cb83ac3..a4dc2a792445 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -517,7 +517,6 @@ public function when($value, callable $callback, callable $default = null) /** * Apply the callback if the collection is empty. * - * @param bool $value * @param callable $callback * @param callable $default * @return static|mixed @@ -530,7 +529,6 @@ public function whenEmpty(callable $callback, callable $default = null) /** * Apply the callback if the collection is not empty. * - * @param bool $value * @param callable $callback * @param callable $default * @return static|mixed @@ -556,7 +554,6 @@ public function unless($value, callable $callback, callable $default = null) /** * Apply the callback unless the collection is empty. * - * @param bool $value * @param callable $callback * @param callable $default * @return static|mixed @@ -569,7 +566,6 @@ public function unlessEmpty(callable $callback, callable $default = null) /** * Apply the callback unless the collection is not empty. * - * @param bool $value * @param callable $callback * @param callable $default * @return static|mixed diff --git a/src/Illuminate/Support/Facades/URL.php b/src/Illuminate/Support/Facades/URL.php index e1d781fa1bbe..6915928f3895 100755 --- a/src/Illuminate/Support/Facades/URL.php +++ b/src/Illuminate/Support/Facades/URL.php @@ -14,7 +14,7 @@ * @method static \Illuminate\Contracts\Routing\UrlGenerator setRootControllerNamespace(string $rootNamespace) * @method static string signedRoute(string $name, array $parameters = [], \DateTimeInterface|int $expiration = null) * @method static string temporarySignedRoute(string $name, \DateTimeInterface|int $expiration, array $parameters = []) - * @method static string hasValidSignature(\Illuminate\Http\Request $request) + * @method static string hasValidSignature(\Illuminate\Http\Request $request, bool $absolute) * @method static void defaults(array $defaults) * * @see \Illuminate\Routing\UrlGenerator From eb6544973f5afab453d942f5845a82f335c6e0db Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 11 Nov 2018 08:51:13 -0600 Subject: [PATCH 0826/2459] add test --- .../Session/Middleware/StartSession.php | 34 +++++++---- src/Illuminate/Session/SessionManager.php | 8 +-- .../Session/SessionPersistenceTest.php | 60 +++++++++++++++++++ 3 files changed, 85 insertions(+), 17 deletions(-) create mode 100644 tests/Integration/Session/SessionPersistenceTest.php diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index 1594811552a7..ea8dc7f984e7 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -41,23 +41,31 @@ public function __construct(SessionManager $manager) */ public function handle($request, Closure $next) { - if ($this->sessionConfigured()) { - $request->setLaravelSession( - $session = $this->startSession($request) - ); + if (! $this->sessionConfigured()) { + return next($request); + } - $this->collectGarbage($session); + // If a session driver has been configured, we will need to start the session here + // so that the data is ready for an application. Note that the Laravel sessions + // do not make use of PHP "native" sessions in any way since they are crappy. + $request->setLaravelSession( + $session = $this->startSession($request) + ); - $this->storeCurrentUrl($request, $session); + $this->collectGarbage($session); - $response = $next($request); + $this->storeCurrentUrl($request, $session); - $this->addCookieToResponse($response, $session); + $this->addCookieToResponse( + $response = $next($request), $session + ); - $this->manager->driver()->save(); - } + // Again, if the session has been configured we will need to close out the session + // so that the attributes may be persisted to some storage medium. We will also + // add the session identifier cookie to the application response headers now. + $this->manager->driver()->save(); - return $response ?? $next($request); + return $response; } /** @@ -168,7 +176,9 @@ protected function getCookieExpirationDate() { $config = $this->manager->getSessionConfig(); - return $config['expire_on_close'] ? 0 : Date::instance(Carbon::now()->addRealMinutes($config['lifetime'])); + return $config['expire_on_close'] ? 0 : Date::instance( + Carbon::now()->addRealMinutes($config['lifetime']) + ); } /** diff --git a/src/Illuminate/Session/SessionManager.php b/src/Illuminate/Session/SessionManager.php index 2ab50830d2de..77364cd68623 100755 --- a/src/Illuminate/Session/SessionManager.php +++ b/src/Illuminate/Session/SessionManager.php @@ -162,11 +162,9 @@ protected function createCacheHandler($driver) */ protected function buildSession($handler) { - if ($this->app['config']['session.encrypt']) { - return $this->buildEncryptedSession($handler); - } - - return new Store($this->app['config']['session.cookie'], $handler); + return $this->app['config']['session.encrypt'] + ? $this->buildEncryptedSession($handler) + : new Store($this->app['config']['session.cookie'], $handler); } /** diff --git a/tests/Integration/Session/SessionPersistenceTest.php b/tests/Integration/Session/SessionPersistenceTest.php new file mode 100644 index 000000000000..d4f6e30131af --- /dev/null +++ b/tests/Integration/Session/SessionPersistenceTest.php @@ -0,0 +1,60 @@ +assertFalse($handler->written); + + Session::extend('fake-null', function () use ($handler) { + return $handler; + }); + + Route::get('/', function () { + throw new TokenMismatchException; + })->middleware('web'); + + $response = $this->get('/'); + $this->assertTrue($handler->written); + } + + protected function getEnvironmentSetUp($app) + { + $app->instance( + ExceptionHandler::class, + $handler = Mockery::mock(ExceptionHandler::class)->shouldIgnoreMissing() + ); + + $handler->shouldReceive('render')->andReturn(new Response); + + $app['config']->set('app.key', str_random(32)); + $app['config']->set('session.driver', 'fake-null'); + $app['config']->set('session.expire_on_close', true); + } +} + +class FakeNullSessionHandler extends NullSessionHandler +{ + public $written = false; + + public function write($sessionId, $data) + { + $this->written = true; + return true; + } +} From d3df6d855d2d98ac1ffb05b0d90e2f153f34ae28 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 11 Nov 2018 08:51:48 -0600 Subject: [PATCH 0827/2459] Apply fixes from StyleCI (#26478) --- tests/Integration/Session/SessionPersistenceTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Integration/Session/SessionPersistenceTest.php b/tests/Integration/Session/SessionPersistenceTest.php index d4f6e30131af..38a06c5f7b0e 100644 --- a/tests/Integration/Session/SessionPersistenceTest.php +++ b/tests/Integration/Session/SessionPersistenceTest.php @@ -55,6 +55,7 @@ class FakeNullSessionHandler extends NullSessionHandler public function write($sessionId, $data) { $this->written = true; + return true; } } From 463bb87662143734251923b36a473f5b4cdb5440 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 11 Nov 2018 08:55:54 -0600 Subject: [PATCH 0828/2459] remove unused method --- src/Illuminate/Session/Middleware/StartSession.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index ea8dc7f984e7..1d7739108172 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -203,18 +203,4 @@ protected function sessionIsPersistent(array $config = null) return ! in_array($config['driver'], [null, 'array']); } - - /** - * Determine if the session is using cookie sessions. - * - * @return bool - */ - protected function usingCookieSessions() - { - if ($this->sessionConfigured()) { - return $this->manager->driver()->getHandler() instanceof CookieSessionHandler; - } - - return false; - } } From be79e7625c55526db900f4e2105ac5d15a6b4633 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 11 Nov 2018 08:56:31 -0600 Subject: [PATCH 0829/2459] Apply fixes from StyleCI (#26479) --- src/Illuminate/Session/Middleware/StartSession.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index 1d7739108172..e1642f5cbb0b 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -8,7 +8,6 @@ use Illuminate\Support\Facades\Date; use Illuminate\Session\SessionManager; use Illuminate\Contracts\Session\Session; -use Illuminate\Session\CookieSessionHandler; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Response; From 835f1120ec3b74ed96cbe1461446399b9f754abd Mon Sep 17 00:00:00 2001 From: TSURU Date: Mon, 12 Nov 2018 18:57:57 +0900 Subject: [PATCH 0830/2459] Fix FormRequest validate not twlice. --- .../Foundation/Http/FormRequest.php | 26 ++++++++++++-- .../Foundation/FoundationFormRequestTest.php | 36 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 22883d4b78ac..b5fcaab6abae 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -58,6 +58,13 @@ class FormRequest extends Request implements ValidatesWhenResolved */ protected $errorBag = 'default'; + /** + * The validator instance. + * + * @var \Illuminate\Contracts\Validation\Validator + */ + protected $validator; + /** * Get the validator instance for the request. * @@ -77,7 +84,9 @@ protected function getValidatorInstance() $this->withValidator($validator); } - return $validator; + $this->setValidator($validator); + + return $this->validator; } /** @@ -172,7 +181,7 @@ protected function failedAuthorization() */ public function validated() { - return $this->getValidatorInstance()->validated(); + return $this->validator->validated(); } /** @@ -195,6 +204,19 @@ public function attributes() return []; } + /** + * Set the Validator instance. + * + * @param \Illuminate\Contracts\Validation\Validator $validator + * @return $this + */ + public function setValidator(Validator $validator) + { + $this->validator = $validator; + + return $this; + } + /** * Set the Redirector instance. * diff --git a/tests/Foundation/FoundationFormRequestTest.php b/tests/Foundation/FoundationFormRequestTest.php index 8bc0505479ea..e39b8e2bdbfe 100644 --- a/tests/Foundation/FoundationFormRequestTest.php +++ b/tests/Foundation/FoundationFormRequestTest.php @@ -10,6 +10,7 @@ use Illuminate\Routing\UrlGenerator; use Illuminate\Http\RedirectResponse; use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Contracts\Validation\Validator; use Illuminate\Contracts\Translation\Translator; use Illuminate\Validation\Factory as ValidationFactory; use Illuminate\Contracts\Validation\Factory as ValidationFactoryContract; @@ -67,6 +68,18 @@ public function test_validated_method_returns_the_validated_data_nested_array_ru $this->assertEquals(['nested' => [['bar' => 'baz'], ['bar' => 'baz2']]], $request->validated()); } + public function test_validated_method_not_validate_twice() + { + $payload = ['name' => 'specified', 'with' => 'extras']; + + $request = $this->createRequest($payload, FoundationTestFormRequestTwiceStub::class); + + $request->validateResolved(); + $request->validated(); + + $this->assertEquals(1, FoundationTestFormRequestTwiceStub::$count); + } + /** * @expectedException \Illuminate\Validation\ValidationException */ @@ -246,6 +259,28 @@ public function authorize() } } +class FoundationTestFormRequestTwiceStub extends FormRequest +{ + public static $count = 0; + + public function rules() + { + return ['name' => 'required']; + } + + public function withValidator(Validator $validator) + { + $validator->after(function ($validator) { + self::$count++; + }); + } + + public function authorize() + { + return true; + } +} + class FoundationTestFormRequestForbiddenStub extends FormRequest { public function authorize() @@ -253,6 +288,7 @@ public function authorize() return false; } } + class FoundationTestFormRequestHooks extends FormRequest { public function rules() From a86012cad444a89c8092d18d5e0e54c4a1a0664f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 12 Nov 2018 08:25:41 -0600 Subject: [PATCH 0831/2459] formatting --- .../Foundation/Http/FormRequest.php | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index b5fcaab6abae..e2dfec3c245a 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -72,6 +72,10 @@ class FormRequest extends Request implements ValidatesWhenResolved */ protected function getValidatorInstance() { + if ($this->validator) { + return $this->validator; + } + $factory = $this->container->make(ValidationFactory::class); if (method_exists($this, 'validator')) { @@ -84,9 +88,7 @@ protected function getValidatorInstance() $this->withValidator($validator); } - $this->setValidator($validator); - - return $this->validator; + return $this->validator = $validator; } /** @@ -181,7 +183,7 @@ protected function failedAuthorization() */ public function validated() { - return $this->validator->validated(); + return $this->getValidatorInstance()->validated(); } /** @@ -204,19 +206,6 @@ public function attributes() return []; } - /** - * Set the Validator instance. - * - * @param \Illuminate\Contracts\Validation\Validator $validator - * @return $this - */ - public function setValidator(Validator $validator) - { - $this->validator = $validator; - - return $this; - } - /** * Set the Redirector instance. * From e6ebc8d239e53e6daf16c869de3897ffbce6c751 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 12 Nov 2018 08:41:01 -0600 Subject: [PATCH 0832/2459] formatting and cleanup --- .../Foundation/Testing/TestResponse.php | 81 ++++++++++--------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/TestResponse.php b/src/Illuminate/Foundation/Testing/TestResponse.php index 0528f7cec9a2..2fbba571b45f 100644 --- a/src/Illuminate/Foundation/Testing/TestResponse.php +++ b/src/Illuminate/Foundation/Testing/TestResponse.php @@ -58,45 +58,6 @@ public static function fromBaseResponse($response) return new static($response); } - /** - * JSON decode assoc and keep the empty object. - * @param string $json - * @link https://github.com/laravel/framework/issues/25769 - * @return mixed - */ - public static function jsonDecodeKeepEmptyObject(string $json) - { - $patchEmptyObject = function ($array) use (&$patchEmptyObject) { - - // If it is an empty class,it is reserved. - // Otherwise converted into an associative array. - if (is_object($array)) { - return empty((array) $array) - ? $array - : $patchEmptyObject((array) $array); - } - - foreach ($array as $key => $item) { - // We recursively deal with each of these terms. - if (is_array($item) - || is_object($item) - ) { - $array[$key] = $patchEmptyObject($item); - } - } - - return $array; - }; - - $stdClass = json_decode($json); - - if ($stdClass === false) { - return $stdClass; - } - - return $patchEmptyObject($stdClass); - } - /** * Assert that the response has a successful status code. * @@ -725,7 +686,7 @@ public function assertJsonMissingValidationErrors($keys) */ public function decodeResponseJson($key = null) { - $decodedResponse = static::jsonDecodeKeepEmptyObject($this->getContent()); + $decodedResponse = $this->jsonDecodeKeepEmptyObject($this->getContent()); if (is_null($decodedResponse) || $decodedResponse === false) { if ($this->exception) { @@ -738,6 +699,46 @@ public function decodeResponseJson($key = null) return data_get($decodedResponse, $key); } + /** + * Decode the JSON string while preserving empty objects. + * + * @param string $json + * @return mixed + */ + public function jsonDecodeKeepEmptyObject(string $json) + { + $payload = json_decode($json); + + if ($payload === false) { + return $payload; + } + + return $this->parseJsonWhilePreservingEmptyObjects($payload); + } + + /** + * Parse the given JSON object while preserving empty objects. + * + * @param StdClass|array $payload + * @return + */ + protected function parseJsonWhilePreservingEmptyObjects($payload) + { + if (is_object($payload)) { + return ! empty((array) $payload) + ? $this->parseJsonWhilePreservingEmptyObjects((array) $payload) + : $payload; + } + + foreach ($payload as $key => $item) { + if (is_array($item) || is_object($item)) { + $payload[$key] = $this->parseJsonWhilePreservingEmptyObjects($item); + } + } + + return $payload; + } + /** * Validate and return the decoded response JSON. * From 621d91d802016ab4a64acc5c65f81cb9f5e5f779 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 12 Nov 2018 08:42:54 -0600 Subject: [PATCH 0833/2459] formatting --- src/Illuminate/Foundation/Testing/TestResponse.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/TestResponse.php b/src/Illuminate/Foundation/Testing/TestResponse.php index 2fbba571b45f..959515e9b599 100644 --- a/src/Illuminate/Foundation/Testing/TestResponse.php +++ b/src/Illuminate/Foundation/Testing/TestResponse.php @@ -686,7 +686,9 @@ public function assertJsonMissingValidationErrors($keys) */ public function decodeResponseJson($key = null) { - $decodedResponse = $this->jsonDecodeKeepEmptyObject($this->getContent()); + $decodedResponse = $this->decodeJsonWhilePreservingEmptyObjects( + $this->getContent() + ); if (is_null($decodedResponse) || $decodedResponse === false) { if ($this->exception) { @@ -705,7 +707,7 @@ public function decodeResponseJson($key = null) * @param string $json * @return mixed */ - public function jsonDecodeKeepEmptyObject(string $json) + public function decodeJsonWhilePreservingEmptyObjects(string $json) { $payload = json_decode($json); From 559d4ed200daabd2e27bcd4c51b7f191a42e4773 Mon Sep 17 00:00:00 2001 From: artz Date: Tue, 13 Nov 2018 01:51:18 +0200 Subject: [PATCH 0834/2459] Added ability to set notifcation tries and timeout --- .../Notifications/SendQueuedNotifications.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/Illuminate/Notifications/SendQueuedNotifications.php b/src/Illuminate/Notifications/SendQueuedNotifications.php index c795de446393..109650b1ce57 100644 --- a/src/Illuminate/Notifications/SendQueuedNotifications.php +++ b/src/Illuminate/Notifications/SendQueuedNotifications.php @@ -31,6 +31,20 @@ class SendQueuedNotifications implements ShouldQueue */ public $channels; + /** + * The number of times the job may be attempted. + * + * @var int + */ + public $tries; + + /** + * The number of seconds the job can run before timing out. + * + * @var int + */ + public $timeout; + /** * Create a new job instance. * @@ -44,6 +58,8 @@ public function __construct($notifiables, $notification, array $channels = null) $this->channels = $channels; $this->notifiables = $notifiables; $this->notification = $notification; + $this->tries = property_exists($notification, 'tries') ? $notification->tries : null; + $this->timeout = property_exists($notification, 'timeout') ? $notification->timeout : null; } /** From b45eb76901d35187591aebfd5e2f91e83f410354 Mon Sep 17 00:00:00 2001 From: Stan Angeloff Date: Tue, 13 Nov 2018 16:13:40 +0200 Subject: [PATCH 0835/2459] [5.8] Tag RedisStore as implementing LockProvider (#26499) * Tag RedisStore as implementing LockProvider This follows `MemcachedStore` and was missed in https://github.com/laravel/framework/commit/4e6b2e4ecbbec5a4b265f4d5a57ad1399227cf12#diff-2264a8010d8f05fa1e9b160c1b9431f4. * fixup! Tag RedisStore as implementing LockProvider --- src/Illuminate/Cache/RedisStore.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/RedisStore.php b/src/Illuminate/Cache/RedisStore.php index b4ac0a95c386..4d3c43cfe24b 100755 --- a/src/Illuminate/Cache/RedisStore.php +++ b/src/Illuminate/Cache/RedisStore.php @@ -2,9 +2,10 @@ namespace Illuminate\Cache; +use Illuminate\Contracts\Cache\LockProvider; use Illuminate\Contracts\Redis\Factory as Redis; -class RedisStore extends TaggableStore +class RedisStore extends TaggableStore implements LockProvider { /** * The Redis factory implementation. From b12feabda70f136cb2d7081af41441a0bf22edc7 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 13 Nov 2018 15:14:53 +0100 Subject: [PATCH 0836/2459] [5.6] Fix cache repository (#26496) * Fix a bug with PHP 7.2.12 PHP 7.2.12 broke the way Carbon's diffInSeconds method works. Using diffInRealSeconds instead fixes the problem. See https://github.com/briannesbitt/Carbon/issues/1503 * Clean up diff check in cache repository We can pass the duration here directly. Signed-off-by: Dries Vints * Upgrade mimum Carbon version This fixes a problem with working with DateTimeImmutable instances in the cache repository. Signed-off-by: Dries Vints --- composer.json | 2 +- src/Illuminate/Cache/Repository.php | 2 +- src/Illuminate/Support/composer.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 2942e7a4eb39..331c7032f4e7 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "erusev/parsedown": "~1.7", "league/flysystem": "^1.0.8", "monolog/monolog": "~1.12", - "nesbot/carbon": "1.25.*", + "nesbot/carbon": "1.26.*", "psr/container": "~1.0", "psr/simple-cache": "^1.0", "ramsey/uuid": "^3.7", diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index 46ab4fba083e..97a44c535592 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -552,7 +552,7 @@ protected function getMinutes($duration) $duration = $this->parseDateInterval($duration); if ($duration instanceof DateTimeInterface) { - $duration = Carbon::now()->diffInSeconds(Carbon::createFromTimestamp($duration->getTimestamp()), false) / 60; + $duration = Carbon::now()->diffInRealSeconds($duration, false) / 60; } return (int) ($duration * 60) > 0 ? $duration : null; diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index a81da4f6b7b6..16e2137909fe 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -18,7 +18,7 @@ "ext-mbstring": "*", "doctrine/inflector": "~1.1", "illuminate/contracts": "5.6.*", - "nesbot/carbon": "1.25.*" + "nesbot/carbon": "1.26.*" }, "conflict": { "tightenco/collect": "<5.5.33" From f5cfcb91d8567a06d98f5bfa272aea3fe16eab91 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 13 Nov 2018 15:15:03 +0100 Subject: [PATCH 0837/2459] [5.7] Fix cache repository (#26495) * Fix a bug with PHP 7.2.12 PHP 7.2.12 broke the way Carbon's diffInSeconds method works. Using diffInRealSeconds instead fixes the problem. See https://github.com/briannesbitt/Carbon/issues/1503 * Clean up diff check in cache repository We can pass the duration here directly. Signed-off-by: Dries Vints --- src/Illuminate/Cache/Repository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/Repository.php b/src/Illuminate/Cache/Repository.php index 03eb26f0f86a..afb0d2e598c0 100755 --- a/src/Illuminate/Cache/Repository.php +++ b/src/Illuminate/Cache/Repository.php @@ -565,7 +565,7 @@ protected function getMinutes($duration) $duration = $this->parseDateInterval($duration); if ($duration instanceof DateTimeInterface) { - $duration = Carbon::now()->diffInSeconds(Carbon::createFromTimestamp($duration->getTimestamp()), false) / 60; + $duration = Carbon::now()->diffInRealSeconds($duration, false) / 60; } return (int) ($duration * 60) > 0 ? $duration : null; From 5d8508f67fbc66938ad15c3dad9dc6ea214b3e28 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Tue, 13 Nov 2018 15:52:41 +0100 Subject: [PATCH 0838/2459] Allow 7.3 to fail for now PHP 7.3 builds are failing atm for an unknown reason: https://travis-ci.org/laravel/framework/jobs/454514866 Might be related to the latest RC5 release which was released around the same time the failures started to happen. Signed-off-by: Dries Vints --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index ba4311d2b258..f7de86f43a33 100755 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,8 @@ matrix: - php: 7.3 - php: 7.3 env: setup=lowest + allow_failures: + - php: 7.3 sudo: false From 41e5b582c905b8801df4a661eb23f60d328a5850 Mon Sep 17 00:00:00 2001 From: Arjan Date: Tue, 13 Nov 2018 21:18:07 +0100 Subject: [PATCH 0839/2459] Cache distinct values --- .../Concerns/ValidatesAttributes.php | 44 ++++++++++++++----- tests/Validation/ValidationValidatorTest.php | 11 +++++ 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 58c4eb189e74..44ce81b73a88 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -20,6 +20,13 @@ trait ValidatesAttributes { + /** + * The cached data for distinct rules. + * + * @var array + */ + protected $distinctValues = []; + /** * Validate that an attribute was "accepted". * @@ -561,23 +568,38 @@ protected function failsRatioCheck($parameters, $width, $height) */ public function validateDistinct($attribute, $value, $parameters) { - $attributeName = $this->getPrimaryAttribute($attribute); + $data = $this->getDistinctValues($attribute); - $attributeData = ValidationData::extractDataFromPath( - ValidationData::getLeadingExplicitAttributePath($attributeName), $this->data - ); + if (in_array('ignore_case', $parameters)) { + return empty(preg_grep('/^' . preg_quote($value, '/') . '$/iu', $data)); + } - $pattern = str_replace('\*', '[^.]+', preg_quote($attributeName, '#')); + return !in_array($value, array_values($data)); + } - $data = Arr::where(Arr::dot($attributeData), function ($value, $key) use ($attribute, $pattern) { - return $key != $attribute && (bool) preg_match('#^'.$pattern.'\z#u', $key); - }); + /** + * Get the values to distinct between. + * + * @param string $attribute + * @return array + */ + protected function getDistinctValues($attribute) + { + $attributeName = $this->getPrimaryAttribute($attribute); - if (in_array('ignore_case', $parameters)) { - return empty(preg_grep('/^'.preg_quote($value, '/').'$/iu', $data)); + if (!array_key_exists($attributeName, $this->distinctValues)) { + $attributeData = ValidationData::extractDataFromPath( + ValidationData::getLeadingExplicitAttributePath($attributeName), $this->data + ); + + $pattern = str_replace('\*', '[^.]+', preg_quote($attributeName, '#')); + + $this->distinctValues[$attributeName] = Arr::where(Arr::dot($attributeData), function ($value, $key) use ($attribute, $pattern) { + return (bool)preg_match('#^' . $pattern . '\z#u', $key); + }); } - return ! in_array($value, array_values($data)); + return Arr::except($this->distinctValues[$attributeName], $attribute); } /** diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 501afa4eadf6..4010a253cc6a 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1790,6 +1790,17 @@ public function testValidateDistinct() $v = new Validator($trans, ['cat' => ['sub' => [['prod' => [['id' => 2]]], ['prod' => [['id' => 2]]]]]], ['cat.sub.*.prod.*.id' => 'distinct']); $this->assertFalse($v->passes()); + $v = new Validator($trans, ['foo' => ['foo', 'foo'], 'bar' => ['bar', 'baz']], ['foo.*' => 'distinct', 'bar.*' => 'distinct']); + $this->assertFalse($v->passes()); + $this->assertCount(2, $v->messages()); + + $v = new Validator($trans, ['foo' => ['foo', 'foo'], 'bar' => ['bar', 'bar']], ['foo.*' => 'distinct', 'bar.*' => 'distinct']); + $this->assertFalse($v->passes()); + $this->assertCount(4, $v->messages()); + + $v = new Validator($trans, ['foo' => ['foo', 'bar'], 'bar' => ['foo', 'bar']], ['foo.*' => 'distinct', 'bar.*' => 'distinct']); + $this->assertTrue($v->passes()); + $v = new Validator($trans, ['foo' => ['foo', 'foo']], ['foo.*' => 'distinct'], ['foo.*.distinct' => 'There is a duplication!']); $this->assertFalse($v->passes()); $v->messages()->setFormat(':message'); From 64563827d82f6e7e6a2297f2fe3433e98cd11dd2 Mon Sep 17 00:00:00 2001 From: Arjan Date: Tue, 13 Nov 2018 22:01:17 +0100 Subject: [PATCH 0840/2459] Style changes --- src/Illuminate/Validation/Concerns/ValidatesAttributes.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 44ce81b73a88..f88785598ccc 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -574,7 +574,7 @@ public function validateDistinct($attribute, $value, $parameters) return empty(preg_grep('/^' . preg_quote($value, '/') . '$/iu', $data)); } - return !in_array($value, array_values($data)); + return ! in_array($value, array_values($data)); } /** @@ -587,7 +587,7 @@ protected function getDistinctValues($attribute) { $attributeName = $this->getPrimaryAttribute($attribute); - if (!array_key_exists($attributeName, $this->distinctValues)) { + if (! array_key_exists($attributeName, $this->distinctValues)) { $attributeData = ValidationData::extractDataFromPath( ValidationData::getLeadingExplicitAttributePath($attributeName), $this->data ); @@ -595,7 +595,7 @@ protected function getDistinctValues($attribute) $pattern = str_replace('\*', '[^.]+', preg_quote($attributeName, '#')); $this->distinctValues[$attributeName] = Arr::where(Arr::dot($attributeData), function ($value, $key) use ($attribute, $pattern) { - return (bool)preg_match('#^' . $pattern . '\z#u', $key); + return (bool) preg_match('#^'.$pattern.'\z#u', $key); }); } From 6ea332b642f480faf3ea9931057506e2c7a5ba25 Mon Sep 17 00:00:00 2001 From: Arjan Date: Tue, 13 Nov 2018 22:17:28 +0100 Subject: [PATCH 0841/2459] Reset distinctValues after each check --- src/Illuminate/Validation/Validator.php | 1 + tests/Validation/ValidationValidatorTest.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 21387d9908a2..ef8551ab16fe 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -257,6 +257,7 @@ public function after($callback) public function passes() { $this->messages = new MessageBag; + $this->distinctValues = []; // We'll spin through each rule, validating the attributes attached to that // rule. Any error messages will be added to the containers with each of diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 4010a253cc6a..4d01e0e874b6 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1798,7 +1798,7 @@ public function testValidateDistinct() $this->assertFalse($v->passes()); $this->assertCount(4, $v->messages()); - $v = new Validator($trans, ['foo' => ['foo', 'bar'], 'bar' => ['foo', 'bar']], ['foo.*' => 'distinct', 'bar.*' => 'distinct']); + $v->setData(['foo' => ['foo', 'bar'], 'bar' => ['foo', 'bar']]); $this->assertTrue($v->passes()); $v = new Validator($trans, ['foo' => ['foo', 'foo']], ['foo.*' => 'distinct'], ['foo.*.distinct' => 'There is a duplication!']); From d9ad6863ebdc3b4c1edafad3e4046e0822b0bf46 Mon Sep 17 00:00:00 2001 From: Arjan Date: Tue, 13 Nov 2018 22:21:08 +0100 Subject: [PATCH 0842/2459] Apply style fixes --- src/Illuminate/Validation/Concerns/ValidatesAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index f88785598ccc..bb35e460617c 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -571,7 +571,7 @@ public function validateDistinct($attribute, $value, $parameters) $data = $this->getDistinctValues($attribute); if (in_array('ignore_case', $parameters)) { - return empty(preg_grep('/^' . preg_quote($value, '/') . '$/iu', $data)); + return empty(preg_grep('/^'.preg_quote($value, '/').'$/iu', $data)); } return ! in_array($value, array_values($data)); From 5ff17b497a23ee4a0ab4333a05246a5cc879ab89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nikolaou?= Date: Wed, 14 Nov 2018 04:51:31 +0200 Subject: [PATCH 0843/2459] Make the channel for `log` mail driver configurable Allows users to specify the channel the log the emails when using the `log` driver. --- src/Illuminate/Mail/TransportManager.php | 6 ++- tests/Mail/MailLogTransportTest.php | 50 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/Mail/MailLogTransportTest.php diff --git a/src/Illuminate/Mail/TransportManager.php b/src/Illuminate/Mail/TransportManager.php index bc1f893831b3..49ca8c2b65b9 100644 --- a/src/Illuminate/Mail/TransportManager.php +++ b/src/Illuminate/Mail/TransportManager.php @@ -160,7 +160,11 @@ protected function createSparkPostDriver() */ protected function createLogDriver() { - return new LogTransport($this->app->make(LoggerInterface::class)); + $channel = $this->app['config']['mail.log_channel']; + + return new LogTransport( + $this->app->make(LoggerInterface::class)->channel($channel) + ); } /** diff --git a/tests/Mail/MailLogTransportTest.php b/tests/Mail/MailLogTransportTest.php new file mode 100644 index 000000000000..77e51e76de38 --- /dev/null +++ b/tests/Mail/MailLogTransportTest.php @@ -0,0 +1,50 @@ +app['swift.transport']; + + $transport = $manager->driver('log'); + $this->assertInstanceOf(LogTransport::class, $transport); + + $logger = $this->readAttribute($transport, 'logger'); + $this->assertInstanceOf(LoggerInterface::class, $logger); + + $this->assertInstanceOf(Logger::class, $monolog = $logger->getLogger()); + $this->assertCount(1, $handlers = $monolog->getHandlers()); + $this->assertInstanceOf(RotatingFileHandler::class, $handlers[0]); + } + + public function testGetLogTransportWithConfiguredChannel() + { + $this->app['config']->set('mail.log_channel', 'mail'); + $this->app['config']->set('logging.channels.mail', [ + 'driver' => 'single', + 'path' => 'mail.log', + ]); + + $manager = $this->app['swift.transport']; + + $transport = $manager->driver('log'); + $this->assertInstanceOf(LogTransport::class, $transport); + + $logger = $this->readAttribute($transport, 'logger'); + $this->assertInstanceOf(LoggerInterface::class, $logger); + + $this->assertInstanceOf(Logger::class, $monolog = $logger->getLogger()); + $this->assertCount(1, $handlers = $monolog->getHandlers()); + $this->assertInstanceOf(StreamHandler::class, $handler = $handlers[0]); + $this->assertEquals('mail.log', $handler->getUrl()); + } +} From 94ae7fb9788b173825e069d8a44f2b2f7241ed4c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 14 Nov 2018 07:46:46 -0600 Subject: [PATCH 0844/2459] formatting. remove test --- tests/Mail/MailLogTransportTest.php | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/Mail/MailLogTransportTest.php b/tests/Mail/MailLogTransportTest.php index 77e51e76de38..186be4023f07 100644 --- a/tests/Mail/MailLogTransportTest.php +++ b/tests/Mail/MailLogTransportTest.php @@ -11,21 +11,6 @@ class MailLogTransportTest extends TestCase { - public function testGetLogTransportWithDefaultChannel() - { - $manager = $this->app['swift.transport']; - - $transport = $manager->driver('log'); - $this->assertInstanceOf(LogTransport::class, $transport); - - $logger = $this->readAttribute($transport, 'logger'); - $this->assertInstanceOf(LoggerInterface::class, $logger); - - $this->assertInstanceOf(Logger::class, $monolog = $logger->getLogger()); - $this->assertCount(1, $handlers = $monolog->getHandlers()); - $this->assertInstanceOf(RotatingFileHandler::class, $handlers[0]); - } - public function testGetLogTransportWithConfiguredChannel() { $this->app['config']->set('mail.log_channel', 'mail'); @@ -45,6 +30,5 @@ public function testGetLogTransportWithConfiguredChannel() $this->assertInstanceOf(Logger::class, $monolog = $logger->getLogger()); $this->assertCount(1, $handlers = $monolog->getHandlers()); $this->assertInstanceOf(StreamHandler::class, $handler = $handlers[0]); - $this->assertEquals('mail.log', $handler->getUrl()); } } From 618b49a38bfc88717ea61869284c2254aca5bbfb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 14 Nov 2018 07:47:23 -0600 Subject: [PATCH 0845/2459] Apply fixes from StyleCI (#26512) --- tests/Mail/MailLogTransportTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Mail/MailLogTransportTest.php b/tests/Mail/MailLogTransportTest.php index 186be4023f07..c435b64584fb 100644 --- a/tests/Mail/MailLogTransportTest.php +++ b/tests/Mail/MailLogTransportTest.php @@ -6,7 +6,6 @@ use Psr\Log\LoggerInterface; use Orchestra\Testbench\TestCase; use Monolog\Handler\StreamHandler; -use Monolog\Handler\RotatingFileHandler; use Illuminate\Mail\Transport\LogTransport; class MailLogTransportTest extends TestCase From ae0491875e272fb13a513bc1d5b22d0bf325767e Mon Sep 17 00:00:00 2001 From: vlakoff Date: Wed, 14 Nov 2018 14:48:45 +0100 Subject: [PATCH 0846/2459] [5.7] Code improvements for TestResponse::parseJsonWhilePreservingEmptyObjects (#26508) * Store object-to-array cast to not do it twice * Rewrite to avoid nested calls of parseJsonWhilePreservingEmptyObjects() --- src/Illuminate/Foundation/Testing/TestResponse.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/TestResponse.php b/src/Illuminate/Foundation/Testing/TestResponse.php index 959515e9b599..92608c66d0aa 100644 --- a/src/Illuminate/Foundation/Testing/TestResponse.php +++ b/src/Illuminate/Foundation/Testing/TestResponse.php @@ -727,9 +727,13 @@ public function decodeJsonWhilePreservingEmptyObjects(string $json) protected function parseJsonWhilePreservingEmptyObjects($payload) { if (is_object($payload)) { - return ! empty((array) $payload) - ? $this->parseJsonWhilePreservingEmptyObjects((array) $payload) - : $payload; + $originalPayload = $payload; + + $payload = (array) $payload; + + if (empty($payload)) { + return $originalPayload; + } } foreach ($payload as $key => $item) { From c071123617c02d5cf9db082015ad10f81029cb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leo=20Sj=C3=B6berg?= Date: Wed, 14 Nov 2018 13:51:05 +0000 Subject: [PATCH 0847/2459] Use a library for email validation (#26503) --- composer.json | 1 + .../Validation/Concerns/ValidatesAttributes.php | 4 +++- src/Illuminate/Validation/composer.json | 1 + tests/Validation/ValidationValidatorTest.php | 10 ++++++++-- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index b8e647d99914..ac055e4fb3f5 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "ext-openssl": "*", "doctrine/inflector": "^1.1", "dragonmantank/cron-expression": "^2.0", + "egulias/email-validator": "~2.0", "erusev/parsedown": "^1.7", "league/flysystem": "^1.0.8", "monolog/monolog": "^1.12", diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index a8999c6f0b6f..2011db22eea4 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -16,7 +16,9 @@ use Illuminate\Validation\Rules\Exists; use Illuminate\Validation\Rules\Unique; use Illuminate\Validation\ValidationData; +use Egulias\EmailValidator\EmailValidator; use Symfony\Component\HttpFoundation\File\File; +use Egulias\EmailValidator\Validation\RFCValidation; use Symfony\Component\HttpFoundation\File\UploadedFile; trait ValidatesAttributes @@ -590,7 +592,7 @@ public function validateDistinct($attribute, $value, $parameters) */ public function validateEmail($attribute, $value) { - return filter_var($value, FILTER_VALIDATE_EMAIL) !== false; + return (new EmailValidator)->isValid($value, new RFCValidation); } /** diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index e3f570def4bb..f263d956a2de 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -16,6 +16,7 @@ "require": { "php": "^7.1.3", "ext-json": "*", + "egulias/email-validator": "~2.0", "illuminate/container": "5.8.*", "illuminate/contracts": "5.8.*", "illuminate/support": "5.8.*", diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index e4c8717778aa..e427dc20eab1 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -386,10 +386,10 @@ public function testInputIsReplaced() { $trans = $this->getIlluminateArrayTranslator(); $trans->addLines(['validation.email' => ':input is not a valid email'], 'en'); - $v = new Validator($trans, ['email' => 'a@s'], ['email' => 'email']); + $v = new Validator($trans, ['email' => 'a@@s'], ['email' => 'email']); $this->assertFalse($v->passes()); $v->messages()->setFormat(':message'); - $this->assertEquals('a@s is not a valid email', $v->messages()->first('email')); + $this->assertEquals('a@@s is not a valid email', $v->messages()->first('email')); $trans = $this->getIlluminateArrayTranslator(); $trans->addLines(['validation.email' => ':input is not a valid email'], 'en'); @@ -1969,6 +1969,12 @@ public function testValidateEmail() $this->assertTrue($v->passes()); } + public function testValidateEmailWithInternationalCharacters() + { + $v = new Validator($this->getIlluminateArrayTranslator(), ['x' => 'foo@gmäil.com'], ['x' => 'email']); + $this->assertTrue($v->passes()); + } + /** * @dataProvider validUrls */ From c24e9042b16e9dd01319157eede01f233c8a0362 Mon Sep 17 00:00:00 2001 From: Arjan Date: Wed, 14 Nov 2018 21:35:26 +0100 Subject: [PATCH 0848/2459] Only cache when distinctValues property exists --- .../Concerns/ValidatesAttributes.php | 42 +++++++++++-------- src/Illuminate/Validation/Validator.php | 7 ++++ 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index bb35e460617c..5cb76d50757a 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -20,13 +20,6 @@ trait ValidatesAttributes { - /** - * The cached data for distinct rules. - * - * @var array - */ - protected $distinctValues = []; - /** * Validate that an attribute was "accepted". * @@ -568,7 +561,7 @@ protected function failsRatioCheck($parameters, $width, $height) */ public function validateDistinct($attribute, $value, $parameters) { - $data = $this->getDistinctValues($attribute); + $data = Arr::except($this->getDistinctValues($attribute), $attribute); if (in_array('ignore_case', $parameters)) { return empty(preg_grep('/^'.preg_quote($value, '/').'$/iu', $data)); @@ -587,19 +580,34 @@ protected function getDistinctValues($attribute) { $attributeName = $this->getPrimaryAttribute($attribute); + if(! property_exists($this, 'distinctValues')){ + return $this->extractDistinctValues($attributeName); + } + if (! array_key_exists($attributeName, $this->distinctValues)) { - $attributeData = ValidationData::extractDataFromPath( - ValidationData::getLeadingExplicitAttributePath($attributeName), $this->data - ); + $this->distinctValues[$attributeName] = $this->extractDistinctValues($attributeName); + } - $pattern = str_replace('\*', '[^.]+', preg_quote($attributeName, '#')); + return $this->distinctValues[$attributeName]; + } - $this->distinctValues[$attributeName] = Arr::where(Arr::dot($attributeData), function ($value, $key) use ($attribute, $pattern) { - return (bool) preg_match('#^'.$pattern.'\z#u', $key); - }); - } + /** + * Extract the distinct values from the database. + * + * @param string $attribute + * @return array + */ + protected function extractDistinctValues($attribute) + { + $attributeData = ValidationData::extractDataFromPath( + ValidationData::getLeadingExplicitAttributePath($attribute), $this->data + ); - return Arr::except($this->distinctValues[$attributeName], $attribute); + $pattern = str_replace('\*', '[^.]+', preg_quote($attribute, '#')); + + return Arr::where(Arr::dot($attributeData), function ($value, $key) use ($pattern) { + return (bool) preg_match('#^'.$pattern.'\z#u', $key); + }); } /** diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index ef8551ab16fe..1801283c0c14 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -97,6 +97,13 @@ class Validator implements ValidatorContract */ protected $after = []; + /** + * The cached data for distinct rules. + * + * @var array + */ + protected $distinctValues = []; + /** * The array of custom error messages. * From 5c7b3600a7de03d0d4e63886d543614a68571cf5 Mon Sep 17 00:00:00 2001 From: Arjan Date: Wed, 14 Nov 2018 21:36:05 +0100 Subject: [PATCH 0849/2459] Style fix --- src/Illuminate/Validation/Concerns/ValidatesAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 5cb76d50757a..c68f615fcf6a 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -580,7 +580,7 @@ protected function getDistinctValues($attribute) { $attributeName = $this->getPrimaryAttribute($attribute); - if(! property_exists($this, 'distinctValues')){ + if (! property_exists($this, 'distinctValues')){ return $this->extractDistinctValues($attributeName); } From 9172a67b783952c1d3e15452d9c8646dc0b3eb6d Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 14 Nov 2018 14:36:20 -0600 Subject: [PATCH 0850/2459] allow asset root urls to be configurable --- src/Illuminate/Routing/RoutingServiceProvider.php | 2 +- src/Illuminate/Routing/UrlGenerator.php | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Routing/RoutingServiceProvider.php b/src/Illuminate/Routing/RoutingServiceProvider.php index 1297a73256e6..8eea5ca5ecea 100755 --- a/src/Illuminate/Routing/RoutingServiceProvider.php +++ b/src/Illuminate/Routing/RoutingServiceProvider.php @@ -59,7 +59,7 @@ protected function registerUrlGenerator() $url = new UrlGenerator( $routes, $app->rebinding( 'request', $this->requestRebinder() - ) + ), $app['config']['app.asset_url'] ); // Next we will set a few service resolvers on the URL generator so it can diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index f3d593a1b4e7..e9e19d04bc95 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -31,6 +31,13 @@ class UrlGenerator implements UrlGeneratorContract */ protected $request; + /** + * The asset root URL. + * + * @var string + */ + protected $assetRoot; + /** * The forced URL root. * @@ -106,11 +113,13 @@ class UrlGenerator implements UrlGeneratorContract * * @param \Illuminate\Routing\RouteCollection $routes * @param \Illuminate\Http\Request $request + * @param string $assetRoot * @return void */ - public function __construct(RouteCollection $routes, Request $request) + public function __construct(RouteCollection $routes, Request $request, $assetRoot = null) { $this->routes = $routes; + $this->assetRoot = $assetRoot; $this->setRequest($request); } @@ -229,7 +238,9 @@ public function asset($path, $secure = null) // Once we get the root URL, we will check to see if it contains an index.php // file in the paths. If it does, we will remove it since it is not needed // for asset paths, but only for routes to endpoints in the application. - $root = $this->formatRoot($this->formatScheme($secure)); + $root = $this->assetRoot + ? $this->assetRoot + : $this->formatRoot($this->formatScheme($secure)); return $this->removeIndex($root).'/'.trim($path, '/'); } From af114e10a05b349f14e1d812eefdfeeda4a14441 Mon Sep 17 00:00:00 2001 From: Arjan Date: Wed, 14 Nov 2018 21:36:36 +0100 Subject: [PATCH 0851/2459] Style fix --- src/Illuminate/Validation/Concerns/ValidatesAttributes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index c68f615fcf6a..bc164f00b9a7 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -580,7 +580,7 @@ protected function getDistinctValues($attribute) { $attributeName = $this->getPrimaryAttribute($attribute); - if (! property_exists($this, 'distinctValues')){ + if (! property_exists($this, 'distinctValues')) { return $this->extractDistinctValues($attributeName); } From 1e61e429e50ab1099105329524d72396310b68aa Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Thu, 15 Nov 2018 14:27:02 +0100 Subject: [PATCH 0852/2459] Uses composer default version constraint ^ (caret) (#26523) Uses composer default version constraint ^ (caret) in the new package `egulias/email-validator`. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ac055e4fb3f5..cf983c2ce0a5 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "ext-openssl": "*", "doctrine/inflector": "^1.1", "dragonmantank/cron-expression": "^2.0", - "egulias/email-validator": "~2.0", + "egulias/email-validator": "^2.0", "erusev/parsedown": "^1.7", "league/flysystem": "^1.0.8", "monolog/monolog": "^1.12", From bf02037b77fc4075a067ca08d565349d391557bb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 15 Nov 2018 07:27:44 -0600 Subject: [PATCH 0853/2459] update validation component --- src/Illuminate/Validation/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index f263d956a2de..d8c950da0bf8 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -16,7 +16,7 @@ "require": { "php": "^7.1.3", "ext-json": "*", - "egulias/email-validator": "~2.0", + "egulias/email-validator": "^2.0", "illuminate/container": "5.8.*", "illuminate/contracts": "5.8.*", "illuminate/support": "5.8.*", From 9a2912403435c0ffd6a8648dcbf84f9bccbb56f7 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 15 Nov 2018 14:33:43 +0100 Subject: [PATCH 0854/2459] Move comment to correct line (#26520) The comment is meant for the if statement and not the dropStaleInstances call above it. Signed-off-by: Dries Vints --- src/Illuminate/Container/Container.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 9538b993c62f..850a2a2ba396 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -221,11 +221,11 @@ public function isAlias($name) */ public function bind($abstract, $concrete = null, $shared = false) { + $this->dropStaleInstances($abstract); + // If no concrete type was given, we will simply set the concrete type to the // abstract type. After that, the concrete type to be registered as shared // without being forced to state their classes in both of the parameters. - $this->dropStaleInstances($abstract); - if (is_null($concrete)) { $concrete = $abstract; } From 81d3931be8131bc9c4e27740950c0f2a51ce7f60 Mon Sep 17 00:00:00 2001 From: vlakoff Date: Thu, 15 Nov 2018 14:34:10 +0100 Subject: [PATCH 0855/2459] whereInRaw PHPDoc: fix method name and tweak sentence (#26516) --- src/Illuminate/Database/Query/Grammars/Grammar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index 3534a8a02748..b15e51e62d25 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -304,7 +304,7 @@ protected function whereNotInSub(Builder $query, $where) /** * Compile a "where in raw" clause. * - * For safety, this method is only used with integer values as whereInRaw utilizes "intval". + * For safety, whereIntegerInRaw ensures this method is only used with integer values. * * @param \Illuminate\Database\Query\Builder $query * @param array $where From 0cabe24593e9959593faeefecdce9c9233704eca Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 15 Nov 2018 07:48:20 -0600 Subject: [PATCH 0856/2459] formatting --- .../Validation/Concerns/ValidatesAttributes.php | 2 +- src/Illuminate/Validation/Validator.php | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index bc164f00b9a7..be610a77d502 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -592,7 +592,7 @@ protected function getDistinctValues($attribute) } /** - * Extract the distinct values from the database. + * Extract the distinct values from the data. * * @param string $attribute * @return array diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index 1801283c0c14..d3094025b529 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -91,18 +91,18 @@ class Validator implements ValidatorContract protected $implicitAttributes = []; /** - * All of the registered "after" callbacks. + * The cached data for the "distinct" rule. * * @var array */ - protected $after = []; + protected $distinctValues = []; /** - * The cached data for distinct rules. + * All of the registered "after" callbacks. * * @var array */ - protected $distinctValues = []; + protected $after = []; /** * The array of custom error messages. @@ -264,6 +264,7 @@ public function after($callback) public function passes() { $this->messages = new MessageBag; + $this->distinctValues = []; // We'll spin through each rule, validating the attributes attached to that From 5f06f87c8de35d776700501c4419363ad816d220 Mon Sep 17 00:00:00 2001 From: Patrick Brouwers Date: Thu, 15 Nov 2018 14:49:08 +0100 Subject: [PATCH 0857/2459] Add callable docblock to route registrar methods (#26524) --- .../Contracts/Routing/Registrar.php | 14 ++++++------- src/Illuminate/Routing/Router.php | 20 +++++++++---------- src/Illuminate/Support/Facades/Route.php | 16 +++++++-------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Illuminate/Contracts/Routing/Registrar.php b/src/Illuminate/Contracts/Routing/Registrar.php index 38e188b5f080..522b2b567d3a 100644 --- a/src/Illuminate/Contracts/Routing/Registrar.php +++ b/src/Illuminate/Contracts/Routing/Registrar.php @@ -8,7 +8,7 @@ interface Registrar * Register a new GET route with the router. * * @param string $uri - * @param \Closure|array|string $action + * @param \Closure|array|string|callable $action * @return \Illuminate\Routing\Route */ public function get($uri, $action); @@ -17,7 +17,7 @@ public function get($uri, $action); * Register a new POST route with the router. * * @param string $uri - * @param \Closure|array|string $action + * @param \Closure|array|string|callable $action * @return \Illuminate\Routing\Route */ public function post($uri, $action); @@ -26,7 +26,7 @@ public function post($uri, $action); * Register a new PUT route with the router. * * @param string $uri - * @param \Closure|array|string $action + * @param \Closure|array|string|callable $action * @return \Illuminate\Routing\Route */ public function put($uri, $action); @@ -35,7 +35,7 @@ public function put($uri, $action); * Register a new DELETE route with the router. * * @param string $uri - * @param \Closure|array|string $action + * @param \Closure|array|string|callable $action * @return \Illuminate\Routing\Route */ public function delete($uri, $action); @@ -44,7 +44,7 @@ public function delete($uri, $action); * Register a new PATCH route with the router. * * @param string $uri - * @param \Closure|array|string $action + * @param \Closure|array|string|callable $action * @return \Illuminate\Routing\Route */ public function patch($uri, $action); @@ -53,7 +53,7 @@ public function patch($uri, $action); * Register a new OPTIONS route with the router. * * @param string $uri - * @param \Closure|array|string $action + * @param \Closure|array|string|callable $action * @return \Illuminate\Routing\Route */ public function options($uri, $action); @@ -63,7 +63,7 @@ public function options($uri, $action); * * @param array|string $methods * @param string $uri - * @param \Closure|array|string $action + * @param \Closure|array|string|callable $action * @return \Illuminate\Routing\Route */ public function match($methods, $uri, $action); diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 83dabfe4973e..9988e9914610 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -133,7 +133,7 @@ public function __construct(Dispatcher $events, Container $container = null) * Register a new GET route with the router. * * @param string $uri - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function get($uri, $action = null) @@ -145,7 +145,7 @@ public function get($uri, $action = null) * Register a new POST route with the router. * * @param string $uri - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function post($uri, $action = null) @@ -157,7 +157,7 @@ public function post($uri, $action = null) * Register a new PUT route with the router. * * @param string $uri - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function put($uri, $action = null) @@ -169,7 +169,7 @@ public function put($uri, $action = null) * Register a new PATCH route with the router. * * @param string $uri - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function patch($uri, $action = null) @@ -181,7 +181,7 @@ public function patch($uri, $action = null) * Register a new DELETE route with the router. * * @param string $uri - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function delete($uri, $action = null) @@ -193,7 +193,7 @@ public function delete($uri, $action = null) * Register a new OPTIONS route with the router. * * @param string $uri - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function options($uri, $action = null) @@ -205,7 +205,7 @@ public function options($uri, $action = null) * Register a new route responding to all verbs. * * @param string $uri - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function any($uri, $action = null) @@ -216,7 +216,7 @@ public function any($uri, $action = null) /** * Register a new Fallback route with the router. * - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function fallback($action) @@ -275,7 +275,7 @@ public function view($uri, $view, $data = []) * * @param array|string $methods * @param string $uri - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function match($methods, $uri, $action = null) @@ -436,7 +436,7 @@ public function getLastGroupPrefix() * * @param array|string $methods * @param string $uri - * @param \Closure|array|string|null $action + * @param \Closure|array|string|callable|null $action * @return \Illuminate\Routing\Route */ public function addRoute($methods, $uri, $action) diff --git a/src/Illuminate/Support/Facades/Route.php b/src/Illuminate/Support/Facades/Route.php index 0a0c4fded0a4..0e7a0dde193f 100755 --- a/src/Illuminate/Support/Facades/Route.php +++ b/src/Illuminate/Support/Facades/Route.php @@ -3,14 +3,14 @@ namespace Illuminate\Support\Facades; /** - * @method static \Illuminate\Routing\Route get(string $uri, \Closure|array|string|null $action = null) - * @method static \Illuminate\Routing\Route post(string $uri, \Closure|array|string|null $action = null) - * @method static \Illuminate\Routing\Route put(string $uri, \Closure|array|string|null $action = null) - * @method static \Illuminate\Routing\Route delete(string $uri, \Closure|array|string|null $action = null) - * @method static \Illuminate\Routing\Route patch(string $uri, \Closure|array|string|null $action = null) - * @method static \Illuminate\Routing\Route options(string $uri, \Closure|array|string|null $action = null) - * @method static \Illuminate\Routing\Route any(string $uri, \Closure|array|string|null $action = null) - * @method static \Illuminate\Routing\Route match(array|string $methods, string $uri, \Closure|array|string|null $action = null) + * @method static \Illuminate\Routing\Route get(string $uri, \Closure|array|string|callable|null $action = null) + * @method static \Illuminate\Routing\Route post(string $uri, \Closure|array|string|callable|null $action = null) + * @method static \Illuminate\Routing\Route put(string $uri, \Closure|array|string|callable|null $action = null) + * @method static \Illuminate\Routing\Route delete(string $uri, \Closure|array|string|callable|null $action = null) + * @method static \Illuminate\Routing\Route patch(string $uri, \Closure|array|string|callable|null $action = null) + * @method static \Illuminate\Routing\Route options(string $uri, \Closure|array|string|callable|null $action = null) + * @method static \Illuminate\Routing\Route any(string $uri, \Closure|array|string|callable|null $action = null) + * @method static \Illuminate\Routing\Route match(array|string $methods, string $uri, \Closure|array|string|callable|null $action = null) * @method static \Illuminate\Routing\RouteRegistrar prefix(string $prefix) * @method static \Illuminate\Routing\RouteRegistrar where(array $where) * @method static \Illuminate\Routing\PendingResourceRegistration resource(string $name, string $controller, array $options = []) From 8f42b814b989441005134d720ab6b3be4b1bb674 Mon Sep 17 00:00:00 2001 From: Yohanan Baruchel Date: Fri, 16 Nov 2018 00:07:34 +0200 Subject: [PATCH 0858/2459] Add verify of current user id on email verification --- .../Foundation/Auth/VerifiesEmails.php | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index 25c642b3319b..30fd141f0ce8 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation\Auth; +use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\Request; use Illuminate\Auth\Events\Verified; @@ -22,18 +23,22 @@ public function show(Request $request) : view('auth.verify'); } - /** - * Mark the authenticated user's email address as verified. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - */ + /** + * Mark the authenticated user's email address as verified. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + * @throws AuthorizationException + */ public function verify(Request $request) { - if ($request->route('id') == $request->user()->getKey() && - $request->user()->markEmailAsVerified()) { - event(new Verified($request->user())); - } + if ($request->route('id') != $request->user()->getKey()) { + throw new AuthorizationException(); + } + + if ($request->user()->markEmailAsVerified()) { + event(new Verified($request->user())); + } return redirect($this->redirectPath())->with('verified', true); } From 920d6b354e2979b45e414bfe36e2036ba3c9a39b Mon Sep 17 00:00:00 2001 From: Yohanan Baruchel Date: Fri, 16 Nov 2018 00:12:03 +0200 Subject: [PATCH 0859/2459] Style fix --- .../Foundation/Auth/VerifiesEmails.php | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index 30fd141f0ce8..64b3a6229672 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -13,32 +13,32 @@ trait VerifiesEmails /** * Show the email verification notice. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function show(Request $request) { return $request->user()->hasVerifiedEmail() - ? redirect($this->redirectPath()) - : view('auth.verify'); + ? redirect($this->redirectPath()) + : view('auth.verify'); } - /** - * Mark the authenticated user's email address as verified. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - * @throws AuthorizationException - */ + /** + * Mark the authenticated user's email address as verified. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + * @throws AuthorizationException + */ public function verify(Request $request) { - if ($request->route('id') != $request->user()->getKey()) { - throw new AuthorizationException(); - } + if ($request->route('id') != $request->user()->getKey()) { + throw new AuthorizationException(); + } - if ($request->user()->markEmailAsVerified()) { - event(new Verified($request->user())); - } + if ($request->user()->markEmailAsVerified()) { + event(new Verified($request->user())); + } return redirect($this->redirectPath())->with('verified', true); } @@ -46,7 +46,7 @@ public function verify(Request $request) /** * Resend the email verification notification. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function resend(Request $request) From d96d6bd686e711f5d8e6a51c46d480fdeee7848a Mon Sep 17 00:00:00 2001 From: Yohanan Baruchel Date: Fri, 16 Nov 2018 00:13:11 +0200 Subject: [PATCH 0860/2459] Style fix --- src/Illuminate/Foundation/Auth/VerifiesEmails.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index 64b3a6229672..31991000cc60 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -2,9 +2,9 @@ namespace Illuminate\Foundation\Auth; -use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\Request; use Illuminate\Auth\Events\Verified; +use Illuminate\Auth\Access\AuthorizationException; trait VerifiesEmails { From 1fcb3e5272e7aca7737f6512f66f7085846c80c9 Mon Sep 17 00:00:00 2001 From: Yohanan Baruchel Date: Fri, 16 Nov 2018 00:15:20 +0200 Subject: [PATCH 0861/2459] Style fix --- .../Foundation/Auth/VerifiesEmails.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index 31991000cc60..22cd2dc7751b 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -13,23 +13,23 @@ trait VerifiesEmails /** * Show the email verification notice. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function show(Request $request) { return $request->user()->hasVerifiedEmail() - ? redirect($this->redirectPath()) - : view('auth.verify'); + ? redirect($this->redirectPath()) + : view('auth.verify'); } - /** - * Mark the authenticated user's email address as verified. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - * @throws AuthorizationException - */ + /** + * Mark the authenticated user's email address as verified. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + * @throws AuthorizationException + */ public function verify(Request $request) { if ($request->route('id') != $request->user()->getKey()) { @@ -46,7 +46,7 @@ public function verify(Request $request) /** * Resend the email verification notification. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function resend(Request $request) From 36dc1707e84e79bfc721ae3d76f1959ffdea8311 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Fri, 16 Nov 2018 02:08:05 +0200 Subject: [PATCH 0862/2459] [5.7] Update changelog - 16/11/2018 --- CHANGELOG-5.7.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index fd18ecc7d25a..2f1db3573305 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -5,16 +5,23 @@ ### Added - Added `Macroable` trait to `Illuminate\Cookie\CookieJar` ([#26445](https://github.com/laravel/framework/pull/26445)) - Added ability to disable password reset route ([#26459](https://github.com/laravel/framework/pull/26459)) +- Added ability to publish error views ([#26460](https://github.com/laravel/framework/pull/26460)) +- Added ability to set notifcation tries and timeout ([#26493](https://github.com/laravel/framework/pull/26493)) +- Added `mail.log_channel` config for make `log` for mail driver configurable ([#26510](https://github.com/laravel/framework/pull/26510)) +- Allowed `asset` root urls to be configurable via `app.asset_url` ([9172a67](https://github.com/laravel/framework/commit/9172a67b783952c1d3e15452d9c8646dc0b3eb6d)) ### Fixed - Fixed `UNION` aggregate queries with columns ([#26466](https://github.com/laravel/framework/pull/26466)) - Allowed migration table name to be guessed without `_table` suffix ([#26429](https://github.com/laravel/framework/pull/26429)) +- Fixed `TestResponse::assertExactJson` for empty JSON objects ([#26353](https://github.com/laravel/framework/pull/26353), [e6ebc8d](https://github.com/laravel/framework/commit/e6ebc8d239e53e6daf16c869de3897ffbce6c751), [621d91d](https://github.com/laravel/framework/commit/621d91d802016ab4a64acc5c65f81cb9f5e5f779), [#26508](https://github.com/laravel/framework/pull/26508)) +- Fixed cache repository for PHP from 7.2.12v ([#26495]( https://github.com/laravel/framework/pull/26495)) ### Changed -- Improved eager loading performance ([#26434](https://github.com/laravel/framework/pull/26434), [#26453](https://github.com/laravel/framework/pull/26453), [3992140](https://github.com/laravel/framework/commit/3992140064307ef82d23328995e7c59045c231f2)) +- Improved eager loading performance ([#26434](https://github.com/laravel/framework/pull/26434), [#26453](https://github.com/laravel/framework/pull/26453), [3992140](https://github.com/laravel/framework/commit/3992140064307ef82d23328995e7c59045c231f2), [#26471](https://github.com/laravel/framework/pull/26471), [a3738cf](https://github.com/laravel/framework/commit/a3738cf4e133a4475c56b51f521a12db78e2ecbb)) - Adjusted `mix` missing asset exceptions ([#26431](https://github.com/laravel/framework/pull/26431)) - Used `asset` helper to generate full path urls in exception views ([#26411](https://github.com/laravel/framework/pull/26411)) - Changed `Illuminate\Foundation\Testing\Concerns\MocksApplicationServices::withoutJobs` method ([#26437](https://github.com/laravel/framework/pull/26437)) +- Cached `distinct` validation rule data ([#26509](https://github.com/laravel/framework/pull/26509)) ## [v5.7.13 (2018-11-07)](https://github.com/laravel/framework/compare/v5.7.12...v5.7.13) From 4e6995389568a7eb3cc720f11917b4cc0d37e999 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Fri, 16 Nov 2018 02:11:47 +0200 Subject: [PATCH 0863/2459] [5.7] Fixed phpDoc - Fixed PhpDoc for Foundation/Testing/TestResponse.php `parseJsonWhilePreservingEmptyObjects` method --- src/Illuminate/Foundation/Testing/TestResponse.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Testing/TestResponse.php b/src/Illuminate/Foundation/Testing/TestResponse.php index 92608c66d0aa..123e0763e73c 100644 --- a/src/Illuminate/Foundation/Testing/TestResponse.php +++ b/src/Illuminate/Foundation/Testing/TestResponse.php @@ -721,8 +721,8 @@ public function decodeJsonWhilePreservingEmptyObjects(string $json) /** * Parse the given JSON object while preserving empty objects. * - * @param StdClass|array $payload - * @return + * @param \stdClass|array $payload + * @return \stdClass|array */ protected function parseJsonWhilePreservingEmptyObjects($payload) { From 315c291b954c6bcd113d7fd3a66c3f9ce37d480d Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 16 Nov 2018 12:38:27 +0100 Subject: [PATCH 0864/2459] Fix StyleCI failures --- src/Illuminate/Foundation/Auth/VerifiesEmails.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index 22cd2dc7751b..287c19828a96 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -23,13 +23,13 @@ public function show(Request $request) : view('auth.verify'); } - /** - * Mark the authenticated user's email address as verified. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - * @throws AuthorizationException - */ + /** + * Mark the authenticated user's email address as verified. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\Response + * @throws AuthorizationException + */ public function verify(Request $request) { if ($request->route('id') != $request->user()->getKey()) { From a71a3bdd3fa874df665b966cdb80b0a33d21127d Mon Sep 17 00:00:00 2001 From: Yohanan Baruchel Date: Fri, 16 Nov 2018 15:49:27 +0200 Subject: [PATCH 0865/2459] Styling fix --- src/Illuminate/Foundation/Auth/VerifiesEmails.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index 287c19828a96..e41d999aebfe 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -26,9 +26,9 @@ public function show(Request $request) /** * Mark the authenticated user's email address as verified. * - * @param \Illuminate\Http\Request $request + * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response - * @throws AuthorizationException + * @throws \Illuminate\Auth\Access\AuthorizationException */ public function verify(Request $request) { From 67e6746e49d2d63dffa735f8f6464f54450d6a48 Mon Sep 17 00:00:00 2001 From: vlakoff Date: Fri, 16 Nov 2018 15:03:35 +0100 Subject: [PATCH 0866/2459] [5.7] Fix whereIntegerInRaw() with "not" argument and add whereIntegerNotInRaw() (#26531) * Correct test name * Add missing grammar for whereIntegerInRaw() with "not" argument * Add whereIntegerNotInRaw() method For completeness, and to ease up testing. * Add tests for whereInteger[Not]InRaw() with empty values parameter --- src/Illuminate/Database/Query/Builder.php | 13 ++++++++++ .../Database/Query/Grammars/Grammar.php | 18 +++++++++++++ tests/Database/DatabaseQueryBuilderTest.php | 26 ++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 3ad96bb06e31..f1248c113adc 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -974,6 +974,19 @@ public function whereIntegerInRaw($column, $values, $boolean = 'and', $not = fal return $this; } + /** + * Add a "where not in raw" clause for integer values to the query. + * + * @param string $column + * @param \Illuminate\Contracts\Support\Arrayable|array $values + * @param string $boolean + * @return $this + */ + public function whereIntegerNotInRaw($column, $values, $boolean = 'and') + { + return $this->whereIntegerInRaw($column, $values, $boolean, true); + } + /** * Add a "where null" clause to the query. * diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index b15e51e62d25..7aa237d23049 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -277,6 +277,24 @@ protected function whereNotIn(Builder $query, $where) return '1 = 1'; } + /** + * Compile a "where not in raw" clause. + * + * For safety, whereIntegerInRaw ensures this method is only used with integer values. + * + * @param \Illuminate\Database\Query\Builder $query + * @param array $where + * @return string + */ + protected function whereNotInRaw(Builder $query, $where) + { + if (! empty($where['values'])) { + return $this->wrap($where['column']).' not in ('.implode(', ', $where['values']).')'; + } + + return '1 = 1'; + } + /** * Compile a where in sub-select clause. * diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index c3e9f3b77f90..414a8dcdd340 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -693,7 +693,7 @@ public function testEmptyWhereNotIns() $this->assertEquals([0 => 1], $builder->getBindings()); } - public function testwhereIntegerInRaw() + public function testWhereIntegerInRaw() { $builder = $this->getBuilder(); $builder->select('*')->from('users')->whereIntegerInRaw('id', ['1a', 2]); @@ -701,6 +701,30 @@ public function testwhereIntegerInRaw() $this->assertEquals([], $builder->getBindings()); } + public function testWhereIntegerNotInRaw() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereIntegerNotInRaw('id', ['1a', 2]); + $this->assertEquals('select * from "users" where "id" not in (1, 2)', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + } + + public function testEmptyWhereIntegerInRaw() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereIntegerInRaw('id', []); + $this->assertEquals('select * from "users" where 0 = 1', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + } + + public function testEmptyWhereIntegerNotInRaw() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->whereIntegerNotInRaw('id', []); + $this->assertEquals('select * from "users" where 1 = 1', $builder->toSql()); + $this->assertEquals([], $builder->getBindings()); + } + public function testBasicWhereColumn() { $builder = $this->getBuilder(); From f88917adc292e7e2960e9336a0d89206b41155fe Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 16 Nov 2018 08:05:21 -0600 Subject: [PATCH 0867/2459] formatting --- src/Illuminate/Foundation/Auth/VerifiesEmails.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Auth/VerifiesEmails.php b/src/Illuminate/Foundation/Auth/VerifiesEmails.php index e41d999aebfe..4b252343630e 100644 --- a/src/Illuminate/Foundation/Auth/VerifiesEmails.php +++ b/src/Illuminate/Foundation/Auth/VerifiesEmails.php @@ -33,7 +33,7 @@ public function show(Request $request) public function verify(Request $request) { if ($request->route('id') != $request->user()->getKey()) { - throw new AuthorizationException(); + throw new AuthorizationException; } if ($request->user()->markEmailAsVerified()) { From 690424d78e848628f9a00ba41ad874ce18b53420 Mon Sep 17 00:00:00 2001 From: ARCANEDEV Date: Fri, 16 Nov 2018 23:08:34 +0100 Subject: [PATCH 0868/2459] [5.7] Adding `RouteRegistrar` mixin to Router (#26542) --- src/Illuminate/Routing/Router.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 9988e9914610..32c3d3e14037 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -23,6 +23,9 @@ use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory; use Symfony\Component\HttpFoundation\Response as SymfonyResponse; +/** + * @mixin \Illuminate\Routing\RouteRegistrar + */ class Router implements RegistrarContract, BindingRegistrar { use Macroable { From 06cad013bc2289ff3091a976ff1d75b1348358df Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Sun, 18 Nov 2018 11:45:25 +0100 Subject: [PATCH 0869/2459] [5.8] ContextualBindingBuilder should not depend on concrete container implementation --- src/Illuminate/Container/ContextualBindingBuilder.php | 5 +++-- src/Illuminate/Contracts/Container/Container.php | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Container/ContextualBindingBuilder.php b/src/Illuminate/Container/ContextualBindingBuilder.php index e4220dab63e6..ac280dba54ab 100644 --- a/src/Illuminate/Container/ContextualBindingBuilder.php +++ b/src/Illuminate/Container/ContextualBindingBuilder.php @@ -3,6 +3,7 @@ namespace Illuminate\Container; use Illuminate\Support\Arr; +use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Container\ContextualBindingBuilder as ContextualBindingBuilderContract; class ContextualBindingBuilder implements ContextualBindingBuilderContract @@ -10,7 +11,7 @@ class ContextualBindingBuilder implements ContextualBindingBuilderContract /** * The underlying container instance. * - * @var \Illuminate\Container\Container + * @var \Illuminate\Contracts\Container\Container */ protected $container; @@ -31,7 +32,7 @@ class ContextualBindingBuilder implements ContextualBindingBuilderContract /** * Create a new contextual binding builder. * - * @param \Illuminate\Container\Container $container + * @param \Illuminate\Contracts\Container\Container $container * @param string|array $concrete * @return void */ diff --git a/src/Illuminate/Contracts/Container/Container.php b/src/Illuminate/Contracts/Container/Container.php index 6bb7456b2c5f..bbb19ae1052b 100644 --- a/src/Illuminate/Contracts/Container/Container.php +++ b/src/Illuminate/Contracts/Container/Container.php @@ -158,4 +158,14 @@ public function resolving($abstract, Closure $callback = null); * @return void */ public function afterResolving($abstract, Closure $callback = null); + + /** + * Add a contextual binding to the container. + * + * @param string $concrete + * @param string $abstract + * @param \Closure|string $implementation + * @return void + */ + public function addContextualBinding($concrete, $abstract, $implementation); } From c8b30977ed2d80cef53beab28a45384fa8d7462b Mon Sep 17 00:00:00 2001 From: Mark van den Broek Date: Sun, 18 Nov 2018 17:19:39 +0100 Subject: [PATCH 0870/2459] Fix $routes should be filtered before passing it to pluckColumns() (#26553) --- src/Illuminate/Foundation/Console/RouteListCommand.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index b8869933e47c..35d939a7cdb7 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -91,7 +91,7 @@ protected function getRoutes() { $routes = collect($this->routes)->map(function ($route) { return $this->getRouteInformation($route); - })->all(); + })->filter()->all(); if ($sort = $this->option('sort')) { $routes = $this->sortRoutes($sort, $routes); @@ -101,9 +101,7 @@ protected function getRoutes() $routes = array_reverse($routes); } - $routes = $this->pluckColumns($routes); - - return array_filter($routes); + return $this->pluckColumns($routes); } /** From 0247f2550b3e2abab00e37daaf3ff18eb2055af8 Mon Sep 17 00:00:00 2001 From: Eric Horstmanshof Date: Sun, 18 Nov 2018 17:20:48 +0100 Subject: [PATCH 0871/2459] Improved DNS Prefetching in view files (#26552) * Improved DNS Prefetching > It is equivalent (but unnecessary) to use a full URL From: https://www.chromium.org/developers/design-documents/dns-prefetching * Added DNS Prefetching * Added DNS Prefetching --- src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub | 2 +- .../Foundation/Exceptions/views/illustrated-layout.blade.php | 1 + src/Illuminate/Foundation/Exceptions/views/layout.blade.php | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub b/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub index dc245d980572..32bf5f6c7346 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub @@ -13,7 +13,7 @@ - + diff --git a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php index 49d45bf43276..3730d05ae79b 100644 --- a/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/illustrated-layout.blade.php @@ -7,6 +7,7 @@ + diff --git a/src/Illuminate/Foundation/Exceptions/views/layout.blade.php b/src/Illuminate/Foundation/Exceptions/views/layout.blade.php index 90d4ad247934..2c51d4f355b5 100644 --- a/src/Illuminate/Foundation/Exceptions/views/layout.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/layout.blade.php @@ -7,6 +7,7 @@ @yield('title') + From 3c42f707cdfdaee6c6d0f71a658b0b358bf2dfa7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Sun, 18 Nov 2018 10:22:46 -0600 Subject: [PATCH 0872/2459] formatting --- .../Contracts/Container/Container.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Contracts/Container/Container.php b/src/Illuminate/Contracts/Container/Container.php index bbb19ae1052b..7cb77a71af69 100644 --- a/src/Illuminate/Contracts/Container/Container.php +++ b/src/Illuminate/Contracts/Container/Container.php @@ -91,6 +91,16 @@ public function extend($abstract, Closure $closure); */ public function instance($abstract, $instance); + /** + * Add a contextual binding to the container. + * + * @param string $concrete + * @param string $abstract + * @param \Closure|string $implementation + * @return void + */ + public function addContextualBinding($concrete, $abstract, $implementation); + /** * Define a contextual binding. * @@ -158,14 +168,4 @@ public function resolving($abstract, Closure $callback = null); * @return void */ public function afterResolving($abstract, Closure $callback = null); - - /** - * Add a contextual binding to the container. - * - * @param string $concrete - * @param string $abstract - * @param \Closure|string $implementation - * @return void - */ - public function addContextualBinding($concrete, $abstract, $implementation); } From 2cd50f4be13533847ee238bdbadbf523f67a5175 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 19 Nov 2018 14:52:25 +0100 Subject: [PATCH 0873/2459] [5.7] Various improvements (#26555) * Simplify whereIn() * Remove duplicate @mixin PHPDoc * Simplify Carbon::setTestNow() uses --- .../Database/Eloquent/Relations/BelongsTo.php | 3 --- .../Database/Eloquent/Relations/MorphTo.php | 3 --- src/Illuminate/Database/Query/Builder.php | 6 +---- .../Database/EloquentBelongsToManyTest.php | 24 +++++-------------- .../Mail/SendingMailWithLocaleTest.php | 2 +- .../SendingNotificationsWithLocaleTest.php | 2 +- 6 files changed, 9 insertions(+), 31 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php index 9af168c1f1c9..4cd1f3325429 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsTo.php @@ -7,9 +7,6 @@ use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Relations\Concerns\SupportsDefaultModels; -/** - * @mixin \Illuminate\Database\Eloquent\Builder - */ class BelongsTo extends Relation { use SupportsDefaultModels; diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php index ac28ad3f2df7..3a14973c6407 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphTo.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphTo.php @@ -7,9 +7,6 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; -/** - * @mixin \Illuminate\Database\Eloquent\Builder - */ class MorphTo extends BelongsTo { /** diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index f1248c113adc..7a02a12d987c 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -857,11 +857,7 @@ public function whereIn($column, $values, $boolean = 'and', $not = false) // Finally we'll add a binding for each values unless that value is an expression // in which case we will just skip over it since it will be the query as a raw // string and not as a parameterized place-holder to be replaced by the PDO. - foreach ($values as $value) { - if (! $value instanceof Expression) { - $this->addBinding($value, 'where'); - } - } + $this->addBinding($this->cleanBindings($values), 'where'); return $this; } diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index 6623294f1bf8..aed50f04c574 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -43,9 +43,7 @@ public function setUp() public function test_basic_create_and_retrieve() { - Carbon::setTestNow( - Carbon::createFromFormat('Y-m-d H:i:s', '2017-10-10 10:10:10') - ); + Carbon::setTestNow('2017-10-10 10:10:10'); $post = Post::create(['title' => str_random()]); @@ -110,9 +108,7 @@ public function test_refresh_on_other_model_works() public function test_custom_pivot_class() { - Carbon::setTestNow( - Carbon::createFromFormat('Y-m-d H:i:s', '2017-10-10 10:10:10') - ); + Carbon::setTestNow('2017-10-10 10:10:10'); $post = Post::create(['title' => str_random()]); @@ -431,9 +427,7 @@ public function test_touching_parent() $this->assertNotEquals('2017-10-10 10:10:10', $post->fresh()->updated_at->toDateTimeString()); - Carbon::setTestNow( - Carbon::createFromFormat('Y-m-d H:i:s', '2017-10-10 10:10:10') - ); + Carbon::setTestNow('2017-10-10 10:10:10'); $tag->update(['name' => $tag->name]); $this->assertNotEquals('2017-10-10 10:10:10', $post->fresh()->updated_at->toDateTimeString()); @@ -451,9 +445,7 @@ public function test_touching_related_models_on_sync() $this->assertNotEquals('2017-10-10 10:10:10', $post->fresh()->updated_at->toDateTimeString()); $this->assertNotEquals('2017-10-10 10:10:10', $tag->fresh()->updated_at->toDateTimeString()); - Carbon::setTestNow( - Carbon::createFromFormat('Y-m-d H:i:s', '2017-10-10 10:10:10') - ); + Carbon::setTestNow('2017-10-10 10:10:10'); $tag->posts()->sync([$post->id]); @@ -470,9 +462,7 @@ public function test_no_touching_happens_if_not_configured() $this->assertNotEquals('2017-10-10 10:10:10', $post->fresh()->updated_at->toDateTimeString()); $this->assertNotEquals('2017-10-10 10:10:10', $tag->fresh()->updated_at->toDateTimeString()); - Carbon::setTestNow( - Carbon::createFromFormat('Y-m-d H:i:s', '2017-10-10 10:10:10') - ); + Carbon::setTestNow('2017-10-10 10:10:10'); $tag->posts()->sync([$post->id]); @@ -513,9 +503,7 @@ public function test_can_touch_related_models() ['post_id' => $post->id, 'tag_id' => 400, 'flag' => ''], ]); - Carbon::setTestNow( - Carbon::createFromFormat('Y-m-d H:i:s', '2017-10-10 10:10:10') - ); + Carbon::setTestNow('2017-10-10 10:10:10'); $post->tags()->touch(); diff --git a/tests/Integration/Mail/SendingMailWithLocaleTest.php b/tests/Integration/Mail/SendingMailWithLocaleTest.php index 54f14125b61e..e0d896c0f259 100644 --- a/tests/Integration/Mail/SendingMailWithLocaleTest.php +++ b/tests/Integration/Mail/SendingMailWithLocaleTest.php @@ -71,7 +71,7 @@ public function test_mail_is_sent_with_selected_locale() public function test_mail_is_sent_with_locale_updated_listeners_called() { - Carbon::setTestNow(Carbon::parse('2018-04-01')); + Carbon::setTestNow('2018-04-01'); Event::listen(LocaleUpdated::class, function ($event) { Carbon::setLocale($event->locale); diff --git a/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php b/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php index 95f5028dc63b..d555d1f4050e 100644 --- a/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php +++ b/tests/Integration/Notifications/SendingNotificationsWithLocaleTest.php @@ -132,7 +132,7 @@ public function test_mailable_is_sent_with_selected_locale() public function test_mail_is_sent_with_locale_updated_listeners_called() { - Carbon::setTestNow(Carbon::parse('2018-07-25')); + Carbon::setTestNow('2018-07-25'); Event::listen(LocaleUpdated::class, function ($event) { Carbon::setLocale($event->locale); From b0e9acc4cde931a1acb8deffddcd5833b8aa0358 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Mon, 19 Nov 2018 14:57:02 +0100 Subject: [PATCH 0874/2459] Add another case to causedByLostConnection() (#26560) "Error while sending QUERY packet" is seen when either sending larger packages then MySQL will handle or when the connection was silently closed by the database. --- src/Illuminate/Database/DetectsLostConnections.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Database/DetectsLostConnections.php b/src/Illuminate/Database/DetectsLostConnections.php index 05fd87607e11..60ec032c3abf 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -36,6 +36,7 @@ protected function causedByLostConnection(Throwable $e) 'TCP Provider: Error code 0x68', 'Name or service not known', 'ORA-03114', + 'Error while sending QUERY packet', ]); } } From 292f685b36be86dc1aa132b9bb4c6690ce7665b8 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 19 Nov 2018 14:57:22 +0100 Subject: [PATCH 0875/2459] [5.7] Add ForeignKeyDefinition meta class (#26554) * Improve ColumnDefinition * Add ForeignKeyDefinition meta class --- src/Illuminate/Database/Schema/Blueprint.php | 2 +- .../Database/Schema/ColumnDefinition.php | 15 ++++++++------- .../Database/Schema/ForeignKeyDefinition.php | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 src/Illuminate/Database/Schema/ForeignKeyDefinition.php diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index de2bb13b84b8..7b6a73b0d46d 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -518,7 +518,7 @@ public function spatialIndex($columns, $name = null) * * @param string|array $columns * @param string $name - * @return \Illuminate\Support\Fluent + * @return \Illuminate\Support\Fluent|\Illuminate\Database\Schema\ForeignKeyDefinition */ public function foreign($columns, $name = null) { diff --git a/src/Illuminate/Database/Schema/ColumnDefinition.php b/src/Illuminate/Database/Schema/ColumnDefinition.php index 5a57d6cdf3ad..d6feac71bfea 100644 --- a/src/Illuminate/Database/Schema/ColumnDefinition.php +++ b/src/Illuminate/Database/Schema/ColumnDefinition.php @@ -5,24 +5,25 @@ use Illuminate\Support\Fluent; /** - * Class ColumnDefinition. * @method ColumnDefinition after(string $column) Place the column "after" another column (MySQL) + * @method ColumnDefinition always() Used as a modifier for generatedAs() (PostgreSQL) * @method ColumnDefinition autoIncrement() Set INTEGER columns as auto-increment (primary key) + * @method ColumnDefinition change() Change the column * @method ColumnDefinition charset(string $charset) Specify a character set for the column (MySQL) * @method ColumnDefinition collation(string $collation) Specify a collation for the column (MySQL/SQL Server) * @method ColumnDefinition comment(string $comment) Add a comment to the column (MySQL) * @method ColumnDefinition default(mixed $value) Specify a "default" value for the column * @method ColumnDefinition first() Place the column "first" in the table (MySQL) - * @method ColumnDefinition nullable($value = true) Allow NULL values to be inserted into the column - * @method ColumnDefinition storedAs($expression) Create a stored generated column (MySQL) + * @method ColumnDefinition generatedAs(string $expression) Create a SQL compliant identity column (PostgreSQL) + * @method ColumnDefinition index() Add an index + * @method ColumnDefinition nullable(bool $value = true) Allow NULL values to be inserted into the column + * @method ColumnDefinition primary() Add a primary index + * @method ColumnDefinition spatialIndex() Add a spatial index + * @method ColumnDefinition storedAs(string $expression) Create a stored generated column (MySQL) * @method ColumnDefinition unique() Add a unique index * @method ColumnDefinition unsigned() Set the INTEGER column as UNSIGNED (MySQL) * @method ColumnDefinition useCurrent() Set the TIMESTAMP column to use CURRENT_TIMESTAMP as default value * @method ColumnDefinition virtualAs(string $expression) Create a virtual generated column (MySQL) - * @method ColumnDefinition generatedAs($expression) Create a SQL compliant identity column (PostgreSQL) - * @method ColumnDefinition always() Used as a modifier for generatedAs() (PostgreSQL) - * @method ColumnDefinition index() Add an index - * @method ColumnDefinition change() Change the column */ class ColumnDefinition extends Fluent { diff --git a/src/Illuminate/Database/Schema/ForeignKeyDefinition.php b/src/Illuminate/Database/Schema/ForeignKeyDefinition.php new file mode 100644 index 000000000000..7811b0333620 --- /dev/null +++ b/src/Illuminate/Database/Schema/ForeignKeyDefinition.php @@ -0,0 +1,18 @@ + Date: Tue, 20 Nov 2018 01:00:14 +1100 Subject: [PATCH 0876/2459] [5.8] from() testing helper to set previous url in session (#26548) * from sets session data * Update MakesHttpRequests.php * Update MakesHttpRequests.php --- .../Foundation/Testing/Concerns/MakesHttpRequests.php | 4 +++- .../Foundation/Testing/Concerns/MakesHttpRequestsTest.php | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php b/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php index 0afbdac43d11..fc96f564bf68 100644 --- a/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php +++ b/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php @@ -144,13 +144,15 @@ public function followingRedirects() } /** - * Set the referer header to simulate a previous request. + * Set the referer header and previous URL session value in order to simulate a previous request. * * @param string $url * @return $this */ public function from(string $url) { + $this->app['session']->setPreviousUrl($url); + return $this->withHeader('referer', $url); } diff --git a/tests/Foundation/Testing/Concerns/MakesHttpRequestsTest.php b/tests/Foundation/Testing/Concerns/MakesHttpRequestsTest.php index c8af278315e6..012b56e39956 100644 --- a/tests/Foundation/Testing/Concerns/MakesHttpRequestsTest.php +++ b/tests/Foundation/Testing/Concerns/MakesHttpRequestsTest.php @@ -6,6 +6,14 @@ class MakesHttpRequestsTest extends TestCase { + public function testFromSetsHeaderAndSession() + { + $this->from('previous/url'); + + $this->assertSame('previous/url', $this->defaultHeaders['referer']); + $this->assertSame('previous/url', $this->app['session']->previousUrl()); + } + public function testWithoutAndWithMiddleware() { $this->assertFalse($this->app->has('middleware.disable')); From 53548a1b4a560ca93f58ca4b4251085df35b9e1f Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 19 Nov 2018 23:32:17 +0200 Subject: [PATCH 0877/2459] [5.7] Added changelog for 2018-11-19 --- CHANGELOG-5.7.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index 2f1db3573305..aec6fc86886d 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -9,19 +9,22 @@ - Added ability to set notifcation tries and timeout ([#26493](https://github.com/laravel/framework/pull/26493)) - Added `mail.log_channel` config for make `log` for mail driver configurable ([#26510](https://github.com/laravel/framework/pull/26510)) - Allowed `asset` root urls to be configurable via `app.asset_url` ([9172a67](https://github.com/laravel/framework/commit/9172a67b783952c1d3e15452d9c8646dc0b3eb6d)) +- Added `Error while sending QUERY packet` string to `DetectsLostConnections` trait ([#26233](https://github.com/laravel/framework/pull/26560)) ### Fixed - Fixed `UNION` aggregate queries with columns ([#26466](https://github.com/laravel/framework/pull/26466)) - Allowed migration table name to be guessed without `_table` suffix ([#26429](https://github.com/laravel/framework/pull/26429)) - Fixed `TestResponse::assertExactJson` for empty JSON objects ([#26353](https://github.com/laravel/framework/pull/26353), [e6ebc8d](https://github.com/laravel/framework/commit/e6ebc8d239e53e6daf16c869de3897ffbce6c751), [621d91d](https://github.com/laravel/framework/commit/621d91d802016ab4a64acc5c65f81cb9f5e5f779), [#26508](https://github.com/laravel/framework/pull/26508)) - Fixed cache repository for PHP from 7.2.12v ([#26495]( https://github.com/laravel/framework/pull/26495)) +- Fixed user authorization check for Email Verification ([#26528](https://github.com/laravel/framework/pull/26528)) ### Changed -- Improved eager loading performance ([#26434](https://github.com/laravel/framework/pull/26434), [#26453](https://github.com/laravel/framework/pull/26453), [3992140](https://github.com/laravel/framework/commit/3992140064307ef82d23328995e7c59045c231f2), [#26471](https://github.com/laravel/framework/pull/26471), [a3738cf](https://github.com/laravel/framework/commit/a3738cf4e133a4475c56b51f521a12db78e2ecbb)) +- Improved eager loading performance ([#26434](https://github.com/laravel/framework/pull/26434), [#26453](https://github.com/laravel/framework/pull/26453), [3992140](https://github.com/laravel/framework/commit/3992140064307ef82d23328995e7c59045c231f2), [#26471](https://github.com/laravel/framework/pull/26471), [a3738cf](https://github.com/laravel/framework/commit/a3738cf4e133a4475c56b51f521a12db78e2ecbb), [#26531](https://github.com/laravel/framework/pull/26531)) - Adjusted `mix` missing asset exceptions ([#26431](https://github.com/laravel/framework/pull/26431)) - Used `asset` helper to generate full path urls in exception views ([#26411](https://github.com/laravel/framework/pull/26411)) - Changed `Illuminate\Foundation\Testing\Concerns\MocksApplicationServices::withoutJobs` method ([#26437](https://github.com/laravel/framework/pull/26437)) - Cached `distinct` validation rule data ([#26509](https://github.com/laravel/framework/pull/26509)) +- Improved DNS Prefetching in view files ([#26552](https://github.com/laravel/framework/pull/26552)) ## [v5.7.13 (2018-11-07)](https://github.com/laravel/framework/compare/v5.7.12...v5.7.13) From 3c52ad480c2efa7864bc5979743c37145ff79707 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 20 Nov 2018 00:47:54 +0200 Subject: [PATCH 0878/2459] [5.7] Delete of Illuminate/Database/Schema/ForeignKeyDefinition.php (#26563) - the main difference between `ForeignKeyDefinition` and `ColumnDefinition`, that `ColumnDefinition` is actually created https://github.com/laravel/framework/pull/24444/files#diff-0a0682dbb89567dbcd7c4f50d4d1ece5R1260 So, as for me it is not ok, that we will have return type, which never will be returned. cc: @staudenmeir --- src/Illuminate/Database/Schema/Blueprint.php | 2 +- .../Database/Schema/ForeignKeyDefinition.php | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 src/Illuminate/Database/Schema/ForeignKeyDefinition.php diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index 7b6a73b0d46d..de2bb13b84b8 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -518,7 +518,7 @@ public function spatialIndex($columns, $name = null) * * @param string|array $columns * @param string $name - * @return \Illuminate\Support\Fluent|\Illuminate\Database\Schema\ForeignKeyDefinition + * @return \Illuminate\Support\Fluent */ public function foreign($columns, $name = null) { diff --git a/src/Illuminate/Database/Schema/ForeignKeyDefinition.php b/src/Illuminate/Database/Schema/ForeignKeyDefinition.php deleted file mode 100644 index 7811b0333620..000000000000 --- a/src/Illuminate/Database/Schema/ForeignKeyDefinition.php +++ /dev/null @@ -1,18 +0,0 @@ - Date: Tue, 20 Nov 2018 16:00:31 +0100 Subject: [PATCH 0879/2459] Re-use query method to build new query (#26569) This re-uses existing code and prevents unnecessary code duplication. --- src/Illuminate/Database/Eloquent/Model.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 3a4e7a97a6e7..b386d3f2e2fa 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -457,7 +457,7 @@ public static function onWriteConnection() */ public static function all($columns = ['*']) { - return (new static)->newQuery()->get( + return static::query()->get( is_array($columns) ? $columns : func_get_args() ); } @@ -470,7 +470,7 @@ public static function all($columns = ['*']) */ public static function with($relations) { - return (new static)->newQuery()->with( + return static::query()->with( is_string($relations) ? func_get_args() : $relations ); } From 4523fed312e6ccf601449634429e05d794e3703a Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Tue, 20 Nov 2018 16:04:44 +0100 Subject: [PATCH 0880/2459] Fix nested JOINs on SQLite (#26567) --- src/Illuminate/Database/Query/Grammars/Grammar.php | 4 +++- tests/Database/DatabaseQueryBuilderTest.php | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index 7aa237d23049..aaa7eaf399ca 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -163,7 +163,9 @@ protected function compileJoins(Builder $query, $joins) $nestedJoins = is_null($join->joins) ? '' : ' '.$this->compileJoins($query, $join->joins); - return trim("{$join->type} join {$table}{$nestedJoins} {$this->compileWheres($join)}"); + $tableAndNestedJoins = is_null($join->joins) ? $table : '('.$table.$nestedJoins.')'; + + return trim("{$join->type} join {$tableAndNestedJoins} {$this->compileWheres($join)}"); })->implode(' '); } diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 414a8dcdd340..ef21d6a0504a 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -1448,7 +1448,7 @@ public function testJoinsWithNestedJoins() $builder->select('users.id', 'contacts.id', 'contact_types.id')->from('users')->leftJoin('contacts', function ($j) { $j->on('users.id', 'contacts.id')->join('contact_types', 'contacts.contact_type_id', '=', 'contact_types.id'); }); - $this->assertEquals('select "users"."id", "contacts"."id", "contact_types"."id" from "users" left join "contacts" inner join "contact_types" on "contacts"."contact_type_id" = "contact_types"."id" on "users"."id" = "contacts"."id"', $builder->toSql()); + $this->assertEquals('select "users"."id", "contacts"."id", "contact_types"."id" from "users" left join ("contacts" inner join "contact_types" on "contacts"."contact_type_id" = "contact_types"."id") on "users"."id" = "contacts"."id"', $builder->toSql()); } public function testJoinsWithMultipleNestedJoins() @@ -1466,7 +1466,7 @@ public function testJoinsWithMultipleNestedJoins() }); }); }); - $this->assertEquals('select "users"."id", "contacts"."id", "contact_types"."id", "countrys"."id", "planets"."id" from "users" left join "contacts" inner join "contact_types" on "contacts"."contact_type_id" = "contact_types"."id" left join "countrys" inner join "planets" on "countrys"."planet_id" = "planet"."id" and "planet"."is_settled" = ? and "planet"."population" >= ? on "contacts"."country" = "countrys"."country" on "users"."id" = "contacts"."id"', $builder->toSql()); + $this->assertEquals('select "users"."id", "contacts"."id", "contact_types"."id", "countrys"."id", "planets"."id" from "users" left join ("contacts" inner join "contact_types" on "contacts"."contact_type_id" = "contact_types"."id" left join ("countrys" inner join "planets" on "countrys"."planet_id" = "planet"."id" and "planet"."is_settled" = ? and "planet"."population" >= ?) on "contacts"."country" = "countrys"."country") on "users"."id" = "contacts"."id"', $builder->toSql()); $this->assertEquals(['1', 10000], $builder->getBindings()); } @@ -1486,7 +1486,7 @@ public function testJoinsWithNestedJoinWithAdvancedSubqueryCondition() ->where('planet.population', '>=', 10000); }); }); - $this->assertEquals('select "users"."id", "contacts"."id", "contact_types"."id" from "users" left join "contacts" inner join "contact_types" on "contacts"."contact_type_id" = "contact_types"."id" on "users"."id" = "contacts"."id" and exists (select * from "countrys" inner join "planets" on "countrys"."planet_id" = "planet"."id" and "planet"."is_settled" = ? where "contacts"."country" = "countrys"."country" and "planet"."population" >= ?)', $builder->toSql()); + $this->assertEquals('select "users"."id", "contacts"."id", "contact_types"."id" from "users" left join ("contacts" inner join "contact_types" on "contacts"."contact_type_id" = "contact_types"."id") on "users"."id" = "contacts"."id" and exists (select * from "countrys" inner join "planets" on "countrys"."planet_id" = "planet"."id" and "planet"."is_settled" = ? where "contacts"."country" = "countrys"."country" and "planet"."population" >= ?)', $builder->toSql()); $this->assertEquals(['1', 10000], $builder->getBindings()); } From 0973092309548463424c21f862abf1de64d57153 Mon Sep 17 00:00:00 2001 From: Rod Elias Date: Tue, 20 Nov 2018 13:04:57 -0200 Subject: [PATCH 0881/2459] add docblock for \InvalidArgumentException (#26566) --- src/Illuminate/Database/Query/JsonExpression.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Database/Query/JsonExpression.php b/src/Illuminate/Database/Query/JsonExpression.php index 3718a7c2f255..3d68ee61262e 100644 --- a/src/Illuminate/Database/Query/JsonExpression.php +++ b/src/Illuminate/Database/Query/JsonExpression.php @@ -24,6 +24,8 @@ public function __construct($value) * * @param mixed $value * @return string + * + * @throws \InvalidArgumentException */ protected function getJsonBindingParameter($value) { From 94ba71d8e2a510b75e54f861c1cb0009153f2010 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 20 Nov 2018 21:34:39 -0600 Subject: [PATCH 0882/2459] remove spacing --- src/Illuminate/Foundation/Application.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 7d3c086a4752..4b2f54d170af 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -184,9 +184,7 @@ protected function registerBaseBindings() protected function registerBaseServiceProviders() { $this->register(new EventServiceProvider($this)); - $this->register(new LogServiceProvider($this)); - $this->register(new RoutingServiceProvider($this)); } From a36906ab8a141f1f497a0667196935e41970ae51 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 20 Nov 2018 21:42:53 -0600 Subject: [PATCH 0883/2459] add env override for running in console --- src/Illuminate/Foundation/Application.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 4b2f54d170af..5b7299251e19 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -515,7 +515,10 @@ public function detectEnvironment(Closure $callback) */ public function runningInConsole() { - return php_sapi_name() === 'cli' || php_sapi_name() === 'phpdbg'; + return env( + 'LARAVEL_RUNNING_IN_CONSOLE', + php_sapi_name() === 'cli' || php_sapi_name() === 'phpdbg' + ); } /** From 19f2245c6d7c87daf784f94b169f0dd4d98f0ca4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 20 Nov 2018 22:00:03 -0600 Subject: [PATCH 0884/2459] use env super global --- src/Illuminate/Foundation/Application.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 5b7299251e19..f2e832c3cbae 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -515,10 +515,11 @@ public function detectEnvironment(Closure $callback) */ public function runningInConsole() { - return env( - 'LARAVEL_RUNNING_IN_CONSOLE', - php_sapi_name() === 'cli' || php_sapi_name() === 'phpdbg' - ); + if (isset($_ENV['APP_RUNNING_IN_CONSOLE'])) { + return $_ENV['APP_RUNNING_IN_CONSOLE'] === 'true'; + } + + return php_sapi_name() === 'cli' || php_sapi_name() === 'phpdbg'; } /** From 4866ff10edf5ed3002971240748a51f22f5ed2ad Mon Sep 17 00:00:00 2001 From: Carl Olsen Date: Wed, 21 Nov 2018 08:39:39 -0500 Subject: [PATCH 0885/2459] Update Kernel.php (#26575) --- src/Illuminate/Foundation/Http/Kernel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/Kernel.php b/src/Illuminate/Foundation/Http/Kernel.php index 720e315a8c64..a44214a760a9 100644 --- a/src/Illuminate/Foundation/Http/Kernel.php +++ b/src/Illuminate/Foundation/Http/Kernel.php @@ -66,7 +66,7 @@ class Kernel implements KernelContract /** * The priority-sorted list of middleware. * - * Forces the listed middleware to always be in the given order. + * Forces non-global middleware to always be in the given order. * * @var array */ From ad6c1fe1e455c0f73a431928282704879ccbd856 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 21 Nov 2018 07:46:08 -0600 Subject: [PATCH 0886/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index f2e832c3cbae..e8d06a71749f 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.7.13'; + const VERSION = '5.7.14'; /** * The base path for the Laravel installation. From 09c075bbfe5aadcb1acac7bb4cb44214592b8639 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 21 Nov 2018 20:12:37 +0200 Subject: [PATCH 0887/2459] [5.7] Added changelog for 2018-11-19 --- CHANGELOG-5.7.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index aec6fc86886d..3f2fe39840e6 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -1,6 +1,6 @@ # Release Notes for 5.7.x -## Unreleased +## [v5.7.14 (2018-11-21)](https://github.com/laravel/framework/compare/v5.7.13...v5.7.14) ### Added - Added `Macroable` trait to `Illuminate\Cookie\CookieJar` ([#26445](https://github.com/laravel/framework/pull/26445)) @@ -10,6 +10,7 @@ - Added `mail.log_channel` config for make `log` for mail driver configurable ([#26510](https://github.com/laravel/framework/pull/26510)) - Allowed `asset` root urls to be configurable via `app.asset_url` ([9172a67](https://github.com/laravel/framework/commit/9172a67b783952c1d3e15452d9c8646dc0b3eb6d)) - Added `Error while sending QUERY packet` string to `DetectsLostConnections` trait ([#26233](https://github.com/laravel/framework/pull/26560)) +- Added env override for running in console ([a36906a](https://github.com/laravel/framework/commit/a36906ab8a141f1f497a0667196935e41970ae51), [19f2245](https://github.com/laravel/framework/commit/19f2245c6d7c87daf784f94b169f0dd4d98f0ca4)) ### Fixed - Fixed `UNION` aggregate queries with columns ([#26466](https://github.com/laravel/framework/pull/26466)) @@ -17,6 +18,7 @@ - Fixed `TestResponse::assertExactJson` for empty JSON objects ([#26353](https://github.com/laravel/framework/pull/26353), [e6ebc8d](https://github.com/laravel/framework/commit/e6ebc8d239e53e6daf16c869de3897ffbce6c751), [621d91d](https://github.com/laravel/framework/commit/621d91d802016ab4a64acc5c65f81cb9f5e5f779), [#26508](https://github.com/laravel/framework/pull/26508)) - Fixed cache repository for PHP from 7.2.12v ([#26495]( https://github.com/laravel/framework/pull/26495)) - Fixed user authorization check for Email Verification ([#26528](https://github.com/laravel/framework/pull/26528)) +- Fixed nested JOINs on SQLite ([#26567](https://github.com/laravel/framework/pull/26567)) ### Changed - Improved eager loading performance ([#26434](https://github.com/laravel/framework/pull/26434), [#26453](https://github.com/laravel/framework/pull/26453), [3992140](https://github.com/laravel/framework/commit/3992140064307ef82d23328995e7c59045c231f2), [#26471](https://github.com/laravel/framework/pull/26471), [a3738cf](https://github.com/laravel/framework/commit/a3738cf4e133a4475c56b51f521a12db78e2ecbb), [#26531](https://github.com/laravel/framework/pull/26531)) From ef89ad7dd1890206f2ab6f28ab6331619990edbc Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Wed, 21 Nov 2018 23:05:25 +0100 Subject: [PATCH 0888/2459] Add date_equals validation message (#26584) --- .../Validation/Concerns/ReplacesAttributes.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php index 3594dd9b3540..3dad17f823f6 100644 --- a/src/Illuminate/Validation/Concerns/ReplacesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ReplacesAttributes.php @@ -434,6 +434,20 @@ protected function replaceAfterOrEqual($message, $attribute, $rule, $parameters) return $this->replaceBefore($message, $attribute, $rule, $parameters); } + /** + * Replace all place-holders for the date_equals rule. + * + * @param string $message + * @param string $attribute + * @param string $rule + * @param array $parameters + * @return string + */ + protected function replaceDateEquals($message, $attribute, $rule, $parameters) + { + return $this->replaceBefore($message, $attribute, $rule, $parameters); + } + /** * Replace all place-holders for the dimensions rule. * From 239025207bb43320cbe7eabc41b7cc176e9ca20e Mon Sep 17 00:00:00 2001 From: Michael Dyrynda Date: Thu, 22 Nov 2018 21:56:53 +1030 Subject: [PATCH 0889/2459] Make ResourceCollection countable such that it works with count() --- .../Http/Resources/Json/ResourceCollection.php | 13 ++++++++++++- tests/Integration/Http/ResourceTest.php | 13 +++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Resources/Json/ResourceCollection.php b/src/Illuminate/Http/Resources/Json/ResourceCollection.php index d7a917000a0e..30421c3f14da 100644 --- a/src/Illuminate/Http/Resources/Json/ResourceCollection.php +++ b/src/Illuminate/Http/Resources/Json/ResourceCollection.php @@ -2,11 +2,12 @@ namespace Illuminate\Http\Resources\Json; +use Countable; use IteratorAggregate; use Illuminate\Pagination\AbstractPaginator; use Illuminate\Http\Resources\CollectsResources; -class ResourceCollection extends JsonResource implements IteratorAggregate +class ResourceCollection extends JsonResource implements IteratorAggregate, Countable { use CollectsResources; @@ -37,6 +38,16 @@ public function __construct($resource) $this->resource = $this->collectResource($resource); } + /** + * Return the count of items in the resource collection. + * + * @return int + */ + public function count() + { + return $this->collection->count(); + } + /** * Transform the resource into a JSON array. * diff --git a/tests/Integration/Http/ResourceTest.php b/tests/Integration/Http/ResourceTest.php index 5f395615c240..48c95e9de635 100644 --- a/tests/Integration/Http/ResourceTest.php +++ b/tests/Integration/Http/ResourceTest.php @@ -576,6 +576,19 @@ public function test_original_on_response_is_collection_of_model_when_collection }); } + public function test_collection_resources_are_countable() + { + $posts = collect([ + new Post(['id' => 1, 'title' => 'Test title']), + new Post(['id' => 2, 'title' => 'Test title 2']), + ]); + + $collection = new PostCollectionResource($posts); + + $this->assertCount(2, $collection); + $this->assertSame(2, count($collection)); + } + public function test_leading_merge__keyed_value_is_merged_correctly() { $filter = new class { From e294f05894610d5c5451db56aff37dfa371789bd Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 22 Nov 2018 08:26:35 -0600 Subject: [PATCH 0890/2459] formatting --- src/Illuminate/Http/Resources/Json/ResourceCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Resources/Json/ResourceCollection.php b/src/Illuminate/Http/Resources/Json/ResourceCollection.php index 30421c3f14da..44ccc56cdfd9 100644 --- a/src/Illuminate/Http/Resources/Json/ResourceCollection.php +++ b/src/Illuminate/Http/Resources/Json/ResourceCollection.php @@ -7,7 +7,7 @@ use Illuminate\Pagination\AbstractPaginator; use Illuminate\Http\Resources\CollectsResources; -class ResourceCollection extends JsonResource implements IteratorAggregate, Countable +class ResourceCollection extends JsonResource implements Countable, IteratorAggregate { use CollectsResources; From a64a900607f110bd365a0265dddd8278badfbed8 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 23 Nov 2018 15:30:55 +0100 Subject: [PATCH 0891/2459] Fix duplicate validation issue (#26604) This will prevent validation from happening twice. Fixes https://github.com/laravel/framework/issues/25736 --- .../Foundation/Http/FormRequest.php | 2 +- src/Illuminate/Validation/Validator.php | 16 ++++++++++ tests/Validation/ValidationValidatorTest.php | 31 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Http/FormRequest.php b/src/Illuminate/Foundation/Http/FormRequest.php index 53a4ec83bd5a..22883d4b78ac 100644 --- a/src/Illuminate/Foundation/Http/FormRequest.php +++ b/src/Illuminate/Foundation/Http/FormRequest.php @@ -172,7 +172,7 @@ protected function failedAuthorization() */ public function validated() { - return $this->getValidatorInstance()->validate(); + return $this->getValidatorInstance()->validated(); } /** diff --git a/src/Illuminate/Validation/Validator.php b/src/Illuminate/Validation/Validator.php index d3094025b529..4bde9dd1013d 100755 --- a/src/Illuminate/Validation/Validator.php +++ b/src/Illuminate/Validation/Validator.php @@ -315,6 +315,22 @@ public function validate() throw new ValidationException($this); } + return $this->validated(); + } + + /** + * Return validated value. + * + * @return array + * + * @throws \Illuminate\Validation\ValidationException + */ + public function validated() + { + if ($this->invalid()) { + throw new ValidationException($this); + } + $results = []; $missingValue = Str::random(10); diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 4d01e0e874b6..ed5a33fafbd4 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -4265,6 +4265,37 @@ public function testValidateReturnsValidatedDataNestedArrayRules() $this->assertEquals(['nested' => [['bar' => 'baz'], ['bar' => 'baz2']]], $data); } + public function testValidateAndValidatedData() + { + $post = ['first' => 'john', 'preferred'=>'john', 'last' => 'doe', 'type' => 'admin']; + + $v = new Validator($this->getIlluminateArrayTranslator(), $post, ['first' => 'required', 'preferred'=> 'required']); + $v->sometimes('type', 'required', function () { + return false; + }); + $data = $v->validate(); + $validatedData = $v->validated(); + + $this->assertEquals(['first' => 'john', 'preferred' => 'john'], $data); + $this->assertEquals($data, $validatedData); + } + + public function testValidatedNotValidateTwiceData() + { + $post = ['first' => 'john', 'preferred'=>'john', 'last' => 'doe', 'type' => 'admin']; + + $validateCount = 0; + $v = new Validator($this->getIlluminateArrayTranslator(), $post, ['first' => 'required', 'preferred'=> 'required']); + $v->after(function () use (&$validateCount) { + $validateCount++; + }); + $data = $v->validate(); + $v->validated(); + + $this->assertEquals(['first' => 'john', 'preferred' => 'john'], $data); + $this->assertEquals(1, $validateCount); + } + /** * @dataProvider validUuidList */ From 86526a8da4a0015d3744d944a2a1ac632fd3818a Mon Sep 17 00:00:00 2001 From: Rod Elias Date: Sat, 24 Nov 2018 01:13:12 -0200 Subject: [PATCH 0892/2459] fix docblock (#26606) --- src/Illuminate/Database/Schema/Blueprint.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index de2bb13b84b8..089fcd2279dc 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -134,6 +134,8 @@ public function toSql(Connection $connection, Grammar $grammar) * * @param \Illuminate\Database\Connection $connection * @return void + * + * @throws \BadMethodCallException */ protected function ensureCommandsAreValid(Connection $connection) { From 5564b6599cfe5d3a68d953395efa578ab4ba19ea Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 25 Nov 2018 15:36:30 +0200 Subject: [PATCH 0893/2459] [5.7] Added changelog --- CHANGELOG-5.7.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index 3f2fe39840e6..1082454b0ec7 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -1,5 +1,15 @@ # Release Notes for 5.7.x +## Unreleased + +### Added +- Added `date_equals` validation message ([#26584](https://github.com/laravel/framework/pull/26584)) +- Make `ResourceCollection` countable ([#26595](https://github.com/laravel/framework/pull/26595)) + +### Fixed +- Fixed duplicate validation issue in `FormRequest::validated` method ([#26604](https://github.com/laravel/framework/pull/26604)) + + ## [v5.7.14 (2018-11-21)](https://github.com/laravel/framework/compare/v5.7.13...v5.7.14) ### Added From f769989694cdcb77e53fbe36d7a47cd06371998c Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 25 Nov 2018 16:35:07 +0200 Subject: [PATCH 0894/2459] [5.7] Refactoring: moved registration of the typical reset password routes to the separate method; (#26616) - moved registration of the typical reset password routes to the separate method, like it is for `emailVerification` routes; --- src/Illuminate/Routing/Router.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 32c3d3e14037..17fdff0dd435 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -1159,10 +1159,7 @@ public function auth(array $options = []) // Password Reset Routes... if ($options['reset'] ?? true) { - $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request'); - $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email'); - $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset'); - $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update'); + $this->resetPassword(); } // Email Verification Routes... @@ -1171,6 +1168,19 @@ public function auth(array $options = []) } } + /** + * Register the typical reset password routes for an application. + * + * @return void + */ + public function resetPassword() + { + $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request'); + $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email'); + $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset'); + $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update'); + } + /** * Register the typical email verification routes for an application. * From 5f6d9a431c4fcedcbae969ba95d266604be54060 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Mon, 26 Nov 2018 01:37:05 +1100 Subject: [PATCH 0895/2459] add starts with validation (#26612) --- .../Validation/Concerns/ValidatesAttributes.php | 13 +++++++++++++ tests/Validation/ValidationValidatorTest.php | 15 +++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index be610a77d502..e10d6943f8c1 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1504,6 +1504,19 @@ public function validateSometimes() return true; } + /** + * Validate the attribute starts with a given substring. + * + * @param string $attribute + * @param mixed $value + * @param array $parameters + * @return bool + */ + public function validateStartsWith($attribute, $value, $parameters) + { + return Str::startsWith($value, $parameters); + } + /** * Validate that an attribute is a string. * diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index ed5a33fafbd4..282ccb63a17f 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1198,6 +1198,21 @@ public function testValidateAccepted() $this->assertTrue($v->passes()); } + public function testValidateStartsWith() + { + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['x' => 'hello world'], ['x' => 'starts_with:hello']); + $this->assertTrue($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['x' => 'hello world'], ['x' => 'starts_with:world']); + $this->assertFalse($v->passes()); + + $trans = $this->getIlluminateArrayTranslator(); + $v = new Validator($trans, ['x' => 'hello world'], ['x' => 'starts_with:world,hello']); + $this->assertTrue($v->passes()); + } + public function testValidateString() { $trans = $this->getIlluminateArrayTranslator(); From 1ca55a1e5c2c0d3ba853998f1781cfa23bb9a646 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Sun, 25 Nov 2018 15:43:07 +0100 Subject: [PATCH 0896/2459] Add relationship getters (#26607) --- .../Eloquent/Relations/BelongsToMany.php | 20 ++++++++++ .../Eloquent/Relations/HasManyThrough.php | 40 +++++++++++++++++++ .../Eloquent/Relations/HasOneOrMany.php | 10 +++++ .../Eloquent/Relations/MorphToMany.php | 10 +++++ 4 files changed, 80 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 5e6f327f9a36..d50289751072 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -1021,6 +1021,16 @@ public function getQualifiedRelatedPivotKeyName() return $this->table.'.'.$this->relatedPivotKey; } + /** + * Get the parent key for the relationship. + * + * @return string + */ + public function getParentKeyName() + { + return $this->parentKey; + } + /** * Get the fully qualified parent key name for the relation. * @@ -1031,6 +1041,16 @@ public function getQualifiedParentKeyName() return $this->parent->qualifyColumn($this->parentKey); } + /** + * Get the related key for the relationship. + * + * @return string + */ + public function getRelatedKeyName() + { + return $this->relatedKey; + } + /** * Get the intermediate table for the relationship. * diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 2b69ca3694b4..ad86d832c653 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -536,6 +536,16 @@ public function getQualifiedFarKeyName() return $this->getQualifiedForeignKeyName(); } + /** + * Get the foreign key on the "through" model. + * + * @return string + */ + public function getFirstKeyName() + { + return $this->firstKey; + } + /** * Get the qualified foreign key on the "through" model. * @@ -546,6 +556,16 @@ public function getQualifiedFirstKeyName() return $this->throughParent->qualifyColumn($this->firstKey); } + /** + * Get the foreign key on the related model. + * + * @return string + */ + public function getForeignKeyName() + { + return $this->secondKey; + } + /** * Get the qualified foreign key on the related model. * @@ -556,6 +576,16 @@ public function getQualifiedForeignKeyName() return $this->related->qualifyColumn($this->secondKey); } + /** + * Get the local key on the far parent model. + * + * @return string + */ + public function getLocalKeyName() + { + return $this->localKey; + } + /** * Get the qualified local key on the far parent model. * @@ -565,4 +595,14 @@ public function getQualifiedLocalKeyName() { return $this->farParent->qualifyColumn($this->localKey); } + + /** + * Get the local key on the intermediary model. + * + * @return string + */ + public function getSecondLocalKeyName() + { + return $this->secondLocalKey; + } } diff --git a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php index 57295e625e93..ffcbb962a3be 100755 --- a/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php @@ -422,4 +422,14 @@ public function getQualifiedForeignKeyName() { return $this->foreignKey; } + + /** + * Get the local key for the relationship. + * + * @return string + */ + public function getLocalKeyName() + { + return $this->localKey; + } } diff --git a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php index f97c465dd68b..e487af04aff3 100644 --- a/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/MorphToMany.php @@ -181,4 +181,14 @@ public function getMorphClass() { return $this->morphClass; } + + /** + * Get the indicator for a reverse relationship. + * + * @return bool + */ + public function getInverse() + { + return $this->inverse; + } } From 231fda5aeaae2bd07599a7e6d23eebc5b7a5f605 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 26 Nov 2018 14:47:24 +0100 Subject: [PATCH 0897/2459] Prevent breaking eager loading with string keys (#26622) --- src/Illuminate/Database/Eloquent/Relations/Relation.php | 2 +- tests/Database/DatabaseEloquentBelongsToTest.php | 3 +-- tests/Database/DatabaseEloquentHasManyTest.php | 4 ++-- tests/Database/DatabaseEloquentHasOneTest.php | 2 +- tests/Database/DatabaseEloquentMorphTest.php | 4 ++-- tests/Database/DatabaseEloquentMorphToManyTest.php | 2 +- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index e16ade9981a9..9ba744376ef5 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -317,7 +317,7 @@ public function relatedUpdatedAt() protected function whereInMethod(Model $model, $key) { return $model->getKeyName() === last(explode('.', $key)) - && in_array($model->getKeyType(), ['int', 'integer']) + && $model->getIncrementing() ? 'whereIntegerInRaw' : 'whereIn'; } diff --git a/tests/Database/DatabaseEloquentBelongsToTest.php b/tests/Database/DatabaseEloquentBelongsToTest.php index 5f92c683ca09..4fc7ec7a5fcc 100755 --- a/tests/Database/DatabaseEloquentBelongsToTest.php +++ b/tests/Database/DatabaseEloquentBelongsToTest.php @@ -177,8 +177,7 @@ public function testDefaultEagerConstraintsWhenNotIncrementing() { $relation = $this->getRelation(null, false); $relation->getRelated()->shouldReceive('getKeyName')->andReturn('id'); - $relation->getRelated()->shouldReceive('getKeyType')->andReturn('int'); - $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('relation.id', m::mustBe([null])); + $relation->getQuery()->shouldReceive('whereIn')->once()->with('relation.id', m::mustBe([null])); $models = [new MissingEloquentBelongsToModelStub, new MissingEloquentBelongsToModelStub]; $relation->addEagerConstraints($models); } diff --git a/tests/Database/DatabaseEloquentHasManyTest.php b/tests/Database/DatabaseEloquentHasManyTest.php index 96fd019cb137..a860665f7d44 100755 --- a/tests/Database/DatabaseEloquentHasManyTest.php +++ b/tests/Database/DatabaseEloquentHasManyTest.php @@ -201,7 +201,7 @@ public function testEagerConstraintsAreProperlyAdded() { $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); - $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); + $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(true); $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasManyModelStub; $model1->id = 1; @@ -214,7 +214,7 @@ public function testEagerConstraintsAreProperlyAddedWithStringKey() { $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); - $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string'); + $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(false); $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasManyModelStub; $model1->id = 1; diff --git a/tests/Database/DatabaseEloquentHasOneTest.php b/tests/Database/DatabaseEloquentHasOneTest.php index 3238058c9641..1260e3f706b1 100755 --- a/tests/Database/DatabaseEloquentHasOneTest.php +++ b/tests/Database/DatabaseEloquentHasOneTest.php @@ -164,7 +164,7 @@ public function testEagerConstraintsAreProperlyAdded() { $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); - $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); + $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(true); $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasOneModelStub; $model1->id = 1; diff --git a/tests/Database/DatabaseEloquentMorphTest.php b/tests/Database/DatabaseEloquentMorphTest.php index 02517ec3a48f..6b78779ab61e 100755 --- a/tests/Database/DatabaseEloquentMorphTest.php +++ b/tests/Database/DatabaseEloquentMorphTest.php @@ -29,7 +29,7 @@ public function testMorphOneEagerConstraintsAreProperlyAdded() { $relation = $this->getOneRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); - $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string'); + $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(false); $relation->getQuery()->shouldReceive('whereIn')->once()->with('table.morph_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent())); @@ -53,7 +53,7 @@ public function testMorphManyEagerConstraintsAreProperlyAdded() { $relation = $this->getManyRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); - $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); + $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(true); $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('table.morph_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent())); diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php index af60b5167a2a..058407fba032 100644 --- a/tests/Database/DatabaseEloquentMorphToManyTest.php +++ b/tests/Database/DatabaseEloquentMorphToManyTest.php @@ -19,7 +19,7 @@ public function testEagerConstraintsAreProperlyAdded() { $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->andReturn('id'); - $relation->getParent()->shouldReceive('getKeyType')->andReturn('int'); + $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(true); $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('taggables.taggable_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('taggables.taggable_type', get_class($relation->getParent())); $model1 = new EloquentMorphToManyModelStub; From e0dbd6ab143286d81bedf2b34f8820f3d49ea15f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 26 Nov 2018 08:10:57 -0600 Subject: [PATCH 0898/2459] verison --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index e8d06a71749f..dc2fdb93d9eb 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.7.14'; + const VERSION = '5.7.15'; /** * The base path for the Laravel installation. From 1e5d38148e3892c275854a213bac489c9b19e02f Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 26 Nov 2018 20:45:36 +0200 Subject: [PATCH 0899/2459] [5.7] update changelog; --- CHANGELOG-5.7.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index 1082454b0ec7..c4fa5d9eee0f 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -1,14 +1,16 @@ # Release Notes for 5.7.x -## Unreleased +## [v5.7.15 (2018-11-26)](https://github.com/laravel/framework/compare/v5.7.14...v5.7.15) ### Added - Added `date_equals` validation message ([#26584](https://github.com/laravel/framework/pull/26584)) +- Added `starts_with` validation rule ([#26612](https://github.com/laravel/framework/pull/26612)) +- Added Add relationship getters `BelongsToMany::getParentKeyName`, `BelongsToMany::getRelatedKeyName`, `HasManyThrough::getFirstKeyName`, `HasManyThrough::getForeignKeyName`, `HasManyThrough::getSecondLocalKeyName`, `HasOneOrMany::getLocalKeyName`, `MorphToMany::getInverse` ([#26607](https://github.com/laravel/framework/pull/26607)) - Make `ResourceCollection` countable ([#26595](https://github.com/laravel/framework/pull/26595)) ### Fixed - Fixed duplicate validation issue in `FormRequest::validated` method ([#26604](https://github.com/laravel/framework/pull/26604)) - +- Prevent breaking eager loading with string keys ([#26622](https://github.com/laravel/framework/pull/26622)) ## [v5.7.14 (2018-11-21)](https://github.com/laravel/framework/compare/v5.7.13...v5.7.14) From b982b524d17dc0ab57e8872d5c7c0a3ab078fb21 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 26 Nov 2018 20:53:54 +0200 Subject: [PATCH 0900/2459] [5.7] update changelog --- CHANGELOG-5.7.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index c4fa5d9eee0f..5fc549c474e5 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -5,13 +5,14 @@ ### Added - Added `date_equals` validation message ([#26584](https://github.com/laravel/framework/pull/26584)) - Added `starts_with` validation rule ([#26612](https://github.com/laravel/framework/pull/26612)) -- Added Add relationship getters `BelongsToMany::getParentKeyName`, `BelongsToMany::getRelatedKeyName`, `HasManyThrough::getFirstKeyName`, `HasManyThrough::getForeignKeyName`, `HasManyThrough::getSecondLocalKeyName`, `HasOneOrMany::getLocalKeyName`, `MorphToMany::getInverse` ([#26607](https://github.com/laravel/framework/pull/26607)) +- Added relationship getters `BelongsToMany::getParentKeyName`, `BelongsToMany::getRelatedKeyName`, `HasManyThrough::getFirstKeyName`, `HasManyThrough::getForeignKeyName`, `HasManyThrough::getSecondLocalKeyName`, `HasOneOrMany::getLocalKeyName`, `MorphToMany::getInverse` ([#26607](https://github.com/laravel/framework/pull/26607)) - Make `ResourceCollection` countable ([#26595](https://github.com/laravel/framework/pull/26595)) ### Fixed - Fixed duplicate validation issue in `FormRequest::validated` method ([#26604](https://github.com/laravel/framework/pull/26604)) - Prevent breaking eager loading with string keys ([#26622](https://github.com/laravel/framework/pull/26622)) + ## [v5.7.14 (2018-11-21)](https://github.com/laravel/framework/compare/v5.7.13...v5.7.14) ### Added From b0013a2006a5bff60b845a72ba66e9dd994aa846 Mon Sep 17 00:00:00 2001 From: Michael Babker Date: Tue, 27 Nov 2018 08:14:58 -0600 Subject: [PATCH 0901/2459] Add Model to sync & syncWithoutDetaching docblocks (#26633) Both methods internally use the `parseIds` method which, unless extended by a model, handles a `Model`. Since these methods list out all of the supported argument types, list this alternative as well. --- .../Eloquent/Relations/Concerns/InteractsWithPivotTable.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index 87ec260135b2..a1c3ae6a40f6 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -64,7 +64,7 @@ public function toggle($ids, $touch = true) /** * Sync the intermediate tables with a list of IDs without detaching. * - * @param \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|array $ids + * @param \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|array|Model $ids * @return array */ public function syncWithoutDetaching($ids) @@ -75,7 +75,7 @@ public function syncWithoutDetaching($ids) /** * Sync the intermediate tables with a list of IDs or collection of models. * - * @param \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|array $ids + * @param \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|array|Model $ids * @param bool $detaching * @return array */ From f2e14602e9601e2ddce3d597a72a2bcfb445b587 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 28 Nov 2018 15:05:20 +0100 Subject: [PATCH 0902/2459] Fix return type --- src/Illuminate/Auth/Access/Gate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 214bc8b80bb5..19db50765153 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -451,7 +451,7 @@ protected function callBeforeCallbacks($user, $ability, array $arguments) * @param string $ability * @param array $arguments * @param bool $result - * @return void + * @return bool|null */ protected function callAfterCallbacks($user, $ability, array $arguments, $result) { From 837bed387ae759deb6c1e738b0fc50aeeaed4e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Est=C3=A9vez?= Date: Wed, 28 Nov 2018 11:10:25 -0300 Subject: [PATCH 0903/2459] Fixed a Bootstrap inconsistent class on auth stub view (#26648) --- src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub index 9ee63bfbadc7..9edb920ecec0 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub @@ -12,7 +12,7 @@ @csrf
    - +
    From b41a3f0b3f9ee9fb1a5051a8f31a496f752b2fbb Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Wed, 28 Nov 2018 15:14:26 +0100 Subject: [PATCH 0904/2459] [5.8] Deprecate Container makeWith method (#26644) * [5.8] Deprecate Container makeWith method * Update Container.php --- src/Illuminate/Container/Container.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index 264155239a21..dde749d3ab34 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -590,6 +590,8 @@ public function factory($abstract) * @param string $abstract * @param array $parameters * @return mixed + * + * @deprecated The make() method should be used instead. Will be removed in Laravel 5.9. */ public function makeWith($abstract, array $parameters = []) { From c4b13bfd115bcfd54588ad2a5809fea2222d1cdb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 28 Nov 2018 08:23:06 -0600 Subject: [PATCH 0905/2459] formatting --- src/Illuminate/Database/Migrations/Migrator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index 58a0c30e3c5d..5ff37bccea05 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -428,7 +428,7 @@ public function resolve($file) public function getMigrationFiles($paths) { return Collection::make($paths)->flatMap(function ($path) { - return ends_with($path, '.php') ? [$path] : $this->files->glob($path.'/*_*.php'); + return Str::endsWith($path, '.php') ? [$path] : $this->files->glob($path.'/*_*.php'); })->filter()->sortBy(function ($file) { return $this->getMigrationName($file); })->values()->keyBy(function ($file) { From 2f3f0ff70172314eaea629df2456cdc1f270845e Mon Sep 17 00:00:00 2001 From: Ralph Schindler Date: Wed, 28 Nov 2018 08:24:31 -0600 Subject: [PATCH 0906/2459] Further fix naming of scheme for schema, deprecated for 5.7, to be renamed in 5.8 (#26640) --- src/Illuminate/Routing/UrlGenerator.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Routing/UrlGenerator.php b/src/Illuminate/Routing/UrlGenerator.php index e9e19d04bc95..9409af12b1d9 100755 --- a/src/Illuminate/Routing/UrlGenerator.php +++ b/src/Illuminate/Routing/UrlGenerator.php @@ -46,7 +46,7 @@ class UrlGenerator implements UrlGeneratorContract protected $forcedRoot; /** - * The forced schema for URLs. + * The forced scheme for URLs. * * @var string */ @@ -60,8 +60,9 @@ class UrlGenerator implements UrlGeneratorContract protected $cachedRoot; /** - * A cached copy of the URL schema for the current request. + * A cached copy of the URL scheme for the current request. * + * @deprecated In 5.8, this will change to $cachedScheme * @var string|null */ protected $cachedSchema; @@ -578,14 +579,14 @@ public function getDefaultParameters() /** * Force the scheme for URLs. * - * @param string $schema + * @param string $scheme * @return void */ - public function forceScheme($schema) + public function forceScheme($scheme) { $this->cachedSchema = null; - $this->forceScheme = $schema.'://'; + $this->forceScheme = $scheme.'://'; } /** From a3965d1007f7493c3e31dc34af9a109408addaa4 Mon Sep 17 00:00:00 2001 From: Anton Komarev <1849174+antonkomarev@users.noreply.github.com> Date: Wed, 28 Nov 2018 17:24:52 +0300 Subject: [PATCH 0907/2459] Use FQCN in sync methods DocBlocks (#26639) --- .../Eloquent/Relations/Concerns/InteractsWithPivotTable.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index a1c3ae6a40f6..1984ec690611 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -64,7 +64,7 @@ public function toggle($ids, $touch = true) /** * Sync the intermediate tables with a list of IDs without detaching. * - * @param \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|array|Model $ids + * @param \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $ids * @return array */ public function syncWithoutDetaching($ids) @@ -75,7 +75,7 @@ public function syncWithoutDetaching($ids) /** * Sync the intermediate tables with a list of IDs or collection of models. * - * @param \Illuminate\Database\Eloquent\Collection|\Illuminate\Support\Collection|array|Model $ids + * @param \Illuminate\Support\Collection|\Illuminate\Database\Eloquent\Model|array $ids * @param bool $detaching * @return array */ From ff85a26c08b790a627bcccb50370454f88f89844 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 28 Nov 2018 15:44:02 +0100 Subject: [PATCH 0908/2459] Update comment for on method (#26650) This clarifies that connection will be set for any retrieved relation without a custom connection name. See https://github.com/laravel/framework/issues/24944#issuecomment-439912177 --- src/Illuminate/Database/Eloquent/Model.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 6cbfd4e18f65..6faf855a3650 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -427,9 +427,9 @@ public function newFromBuilder($attributes = [], $connection = null) */ public static function on($connection = null) { - // First we will just create a fresh instance of this model, and then we can - // set the connection on the model so that it is be used for the queries - // we execute, as well as being set on each relationship we retrieve. + // First we will just create a fresh instance of this model, and then we can set the + // connection on the model so that it is used for the queries we execute, as well + // as being set on every relation we retrieve without a custom connection name. $instance = new static; $instance->setConnection($connection); From 453317f5b2c93b5312392f36e0574d5be9755d0e Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Wed, 28 Nov 2018 17:23:17 +0100 Subject: [PATCH 0909/2459] Revert #26560 --- src/Illuminate/Database/DetectsLostConnections.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Illuminate/Database/DetectsLostConnections.php b/src/Illuminate/Database/DetectsLostConnections.php index 60ec032c3abf..05fd87607e11 100644 --- a/src/Illuminate/Database/DetectsLostConnections.php +++ b/src/Illuminate/Database/DetectsLostConnections.php @@ -36,7 +36,6 @@ protected function causedByLostConnection(Throwable $e) 'TCP Provider: Error code 0x68', 'Name or service not known', 'ORA-03114', - 'Error while sending QUERY packet', ]); } } From bd086a3ea1fee6dcc2169917a27ca0a20685b0b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Aur=C3=A9lio=20Deleu?= Date: Wed, 28 Nov 2018 21:05:12 -0200 Subject: [PATCH 0910/2459] Don't deprecate makeWith (#26660) --- src/Illuminate/Container/Container.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Illuminate/Container/Container.php b/src/Illuminate/Container/Container.php index dde749d3ab34..264155239a21 100755 --- a/src/Illuminate/Container/Container.php +++ b/src/Illuminate/Container/Container.php @@ -590,8 +590,6 @@ public function factory($abstract) * @param string $abstract * @param array $parameters * @return mixed - * - * @deprecated The make() method should be used instead. Will be removed in Laravel 5.9. */ public function makeWith($abstract, array $parameters = []) { From 2ffac1635a473a45ff14e138b84f06edd11e76ef Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Thu, 29 Nov 2018 14:04:10 +0100 Subject: [PATCH 0911/2459] Fix self-referencing HasManyThrough existence queries (#26662) --- src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php | 2 +- tests/Integration/Database/EloquentHasManyThroughTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index ad86d832c653..93f781dcd007 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -503,7 +503,7 @@ public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder { $query->from($query->getModel()->getTable().' as '.$hash = $this->getRelationCountHash()); - $query->join($this->throughParent->getTable(), $this->getQualifiedParentKeyName(), '=', $hash.'.'.$this->secondLocalKey); + $query->join($this->throughParent->getTable(), $this->getQualifiedParentKeyName(), '=', $hash.'.'.$this->secondKey); if ($this->throughParentSoftDeletes()) { $query->whereNull($this->throughParent->getQualifiedDeletedAtColumn()); diff --git a/tests/Integration/Database/EloquentHasManyThroughTest.php b/tests/Integration/Database/EloquentHasManyThroughTest.php index 633da206bc70..06ce0acc2729 100644 --- a/tests/Integration/Database/EloquentHasManyThroughTest.php +++ b/tests/Integration/Database/EloquentHasManyThroughTest.php @@ -33,7 +33,7 @@ public function test_basic_create_and_retrieve() { $user = User::create(['name' => str_random()]); - $team1 = Team::create(['owner_id' => $user->id]); + $team1 = Team::create(['id' => 10, 'owner_id' => $user->id]); $team2 = Team::create(['owner_id' => $user->id]); $mate1 = User::create(['name' => str_random(), 'team_id' => $team1->id]); @@ -127,5 +127,5 @@ class Team extends Model { public $table = 'teams'; public $timestamps = false; - protected $guarded = ['id']; + protected $guarded = []; } From 76dd0c70cac9bdc575b1738fd6a3609a02c0ad51 Mon Sep 17 00:00:00 2001 From: Rob Taylor Date: Thu, 29 Nov 2018 13:10:29 +0000 Subject: [PATCH 0912/2459] Release cache lock if callback fails (#26654) --- src/Illuminate/Cache/Lock.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index f117246c08e2..c8def3b5e293 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -62,9 +62,11 @@ public function get($callback = null) $result = $this->acquire(); if ($result && is_callable($callback)) { - return tap($callback(), function () { + try { + return $callback(); + } finally { $this->release(); - }); + } } return $result; From 41cd2f53dca792cdf8d711b0369493d764c5baab Mon Sep 17 00:00:00 2001 From: Luke Noble Date: Thu, 29 Nov 2018 22:25:01 +0000 Subject: [PATCH 0913/2459] Adding pull function to the docblocks (#26675) --- src/Illuminate/Support/Facades/Session.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Session.php b/src/Illuminate/Support/Facades/Session.php index 3b0be943f8c5..4df35ce95b19 100755 --- a/src/Illuminate/Support/Facades/Session.php +++ b/src/Illuminate/Support/Facades/Session.php @@ -12,6 +12,7 @@ * @method static bool exists(string|array $key) * @method static bool has(string|array $key) * @method static mixed get(string $key, $default = null) + * @method static mixed pull(string $key, $default = null) * @method static void put(string|array $key, $value = null) * @method static string token() * @method static mixed remove(string $key) From d0e1331227e8acd68177760d85b4bac399bef757 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 29 Nov 2018 23:26:53 +0100 Subject: [PATCH 0914/2459] Remove container naming and use consistent naming (#26670) I removed the container namings in the Fluent and MessageBag classes because they don't make sense here. I think these are leftovers from a previous refactor. I also made sure that the other namings are consistent in these classes. --- src/Illuminate/Support/Fluent.php | 16 ++++++++-------- src/Illuminate/Support/MessageBag.php | 24 ++++++++++++------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Illuminate/Support/Fluent.php b/src/Illuminate/Support/Fluent.php index c34a5d760dad..0873bcaebf24 100755 --- a/src/Illuminate/Support/Fluent.php +++ b/src/Illuminate/Support/Fluent.php @@ -10,16 +10,16 @@ class Fluent implements ArrayAccess, Arrayable, Jsonable, JsonSerializable { /** - * All of the attributes set on the container. + * All of the attributes set on the fluent instance. * * @var array */ protected $attributes = []; /** - * Create a new fluent container instance. + * Create a new fluent instance. * - * @param array|object $attributes + * @param array|object $attributes * @return void */ public function __construct($attributes = []) @@ -30,7 +30,7 @@ public function __construct($attributes = []) } /** - * Get an attribute from the container. + * Get an attribute from the fluent instance. * * @param string $key * @param mixed $default @@ -46,7 +46,7 @@ public function get($key, $default = null) } /** - * Get the attributes from the container. + * Get the attributes from the fluent instance. * * @return array */ @@ -56,7 +56,7 @@ public function getAttributes() } /** - * Convert the Fluent instance to an array. + * Convert the fluent instance to an array. * * @return array */ @@ -76,7 +76,7 @@ public function jsonSerialize() } /** - * Convert the Fluent instance to JSON. + * Convert the fluent instance to JSON. * * @param int $options * @return string @@ -132,7 +132,7 @@ public function offsetUnset($offset) } /** - * Handle dynamic calls to the container to set attributes. + * Handle dynamic calls to the fluent instance to set attributes. * * @param string $method * @param array $parameters diff --git a/src/Illuminate/Support/MessageBag.php b/src/Illuminate/Support/MessageBag.php index 41672fe7640c..72fe683edb0b 100755 --- a/src/Illuminate/Support/MessageBag.php +++ b/src/Illuminate/Support/MessageBag.php @@ -51,7 +51,7 @@ public function keys() } /** - * Add a message to the bag. + * Add a message to the message bag. * * @param string $key * @param string $message @@ -81,7 +81,7 @@ protected function isUnique($key, $message) } /** - * Merge a new array of messages into the bag. + * Merge a new array of messages into the message bag. * * @param \Illuminate\Contracts\Support\MessageProvider|array $messages * @return $this @@ -140,7 +140,7 @@ public function hasAny($keys = []) } /** - * Get the first message from the bag for a given key. + * Get the first message from the message bag for a given key. * * @param string $key * @param string $format @@ -156,7 +156,7 @@ public function first($key = null, $format = null) } /** - * Get all of the messages from the bag for a given key. + * Get all of the messages from the message bag for a given key. * * @param string $key * @param string $format @@ -164,9 +164,9 @@ public function first($key = null, $format = null) */ public function get($key, $format = null) { - // If the message exists in the container, we will transform it and return - // the message. Otherwise, we'll check if the key is implicit & collect - // all the messages that match a given key and output it as an array. + // If the message exists in the message bag, we will transform it and return + // the message. Otherwise, we will check if the key is implicit & collect + // all the messages that match the given key and output it as an array. if (array_key_exists($key, $this->messages)) { return $this->transform( $this->messages[$key], $this->checkFormat($format), $key @@ -201,7 +201,7 @@ protected function getMessagesForWildcardKey($key, $format) } /** - * Get all of the messages for every key in the bag. + * Get all of the messages for every key in the message bag. * * @param string $format * @return array @@ -220,7 +220,7 @@ public function all($format = null) } /** - * Get all of the unique messages for every key in the bag. + * Get all of the unique messages for every key in the message bag. * * @param string $format * @return array @@ -261,7 +261,7 @@ protected function checkFormat($format) } /** - * Get the raw messages in the container. + * Get the raw messages in the message bag. * * @return array */ @@ -271,7 +271,7 @@ public function messages() } /** - * Get the raw messages in the container. + * Get the raw messages in the message bag. * * @return array */ @@ -344,7 +344,7 @@ public function any() } /** - * Get the number of messages in the container. + * Get the number of messages in the message bag. * * @return int */ From a4936b9b41dd15326b023717914188669860e907 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 29 Nov 2018 23:28:01 +0100 Subject: [PATCH 0915/2459] [5.8] Remove attributes property from TransformsRequest (#26669) * Remove attributes property from TransformsRequest This served no purpose in the middleware. If people realy need it they could add it in their own class. * Cleanup tests --- .../Foundation/Http/Middleware/TransformsRequest.php | 12 +----------- .../Http/Middleware/TransformsRequestTest.php | 2 ++ 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php index ca554f4cb407..a61a1bd72013 100644 --- a/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php +++ b/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php @@ -7,25 +7,15 @@ class TransformsRequest { - /** - * The additional attributes passed to the middleware. - * - * @var array - */ - protected $attributes = []; - /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next - * @param array ...$attributes * @return mixed */ - public function handle($request, Closure $next, ...$attributes) + public function handle($request, Closure $next) { - $this->attributes = $attributes; - $this->clean($request); return $next($request); diff --git a/tests/Foundation/Http/Middleware/TransformsRequestTest.php b/tests/Foundation/Http/Middleware/TransformsRequestTest.php index 898393660767..d2a43b18f7f4 100644 --- a/tests/Foundation/Http/Middleware/TransformsRequestTest.php +++ b/tests/Foundation/Http/Middleware/TransformsRequestTest.php @@ -100,6 +100,7 @@ protected function transform($key, $value) if ($key === 'beers') { $value++; } + if ($key === 'age') { $value--; } @@ -115,6 +116,7 @@ protected function transform($key, $value) if (str_contains($key, 'beers')) { $value++; } + if (str_contains($key, 'age')) { $value--; } From 28b8cb91251f0643f2aa61072c0554edeabce21b Mon Sep 17 00:00:00 2001 From: Jan-Oliver Pantel Date: Wed, 28 Nov 2018 01:03:06 +0100 Subject: [PATCH 0916/2459] Add option for scoped Cache locks Before this change out of order releases of the same cache lock could lead to situation where client A acquired the lock, took longer than the timeout, which made client B successfully acquire the lock. If A now finishes while B is still holding the lock A will release the lock that does not belong to it. This fix introduces a unique value that is written as the cache value to stop A from deleting B's lock. --- src/Illuminate/Cache/Lock.php | 71 +++++++++++++++++++ src/Illuminate/Cache/MemcachedLock.php | 16 ++++- src/Illuminate/Cache/RedisLock.php | 16 ++++- src/Illuminate/Contracts/Cache/Lock.php | 7 ++ .../Cache/MemcachedCacheLockTest.php | 41 +++++++++++ .../Integration/Cache/RedisCacheLockTest.php | 41 +++++++++++ 6 files changed, 188 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index c8def3b5e293..0eb25ac0df51 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -24,6 +24,13 @@ abstract class Lock implements LockContract */ protected $seconds; + /** + * A (usually) random string that acts as scope identifier of this lock. + * + * @var string + */ + protected $scope; + /** * Create a new lock instance. * @@ -51,6 +58,13 @@ abstract public function acquire(); */ abstract public function release(); + /** + * Returns the value written into the driver for this lock. + * + * @return mixed + */ + abstract protected function getValue(); + /** * Attempt to acquire the lock. * @@ -101,4 +115,61 @@ public function block($seconds, $callback = null) return true; } + + /** + * Secures this lock against out of order releases of expired clients. + * + * @return Lock + */ + public function safe() + { + return $this->scoped(uniqid()); + } + + /** + * Secures this lock against out of order releases of expired clients. + * + * @param string $scope + * @return Lock + */ + public function scoped($scope) + { + $this->scope = $scope; + + return $this; + } + + /** + * Determines whether this is a client scoped lock. + * + * @return bool + */ + protected function isScoped() + { + return ! is_null($this->scope); + } + + /** + * Returns the value that should be written into the cache. + * + * @return mixed + */ + protected function value() + { + return $this->isScoped() ? serialize($this->scope) : 1; + } + + /** + * Determines whether this lock is allowed to release the lock in the driver. + * + * @return bool + */ + protected function canRelease() + { + if (! $this->isScoped()) { + return true; + } + + return unserialize($this->getValue()) === $this->scope; + } } diff --git a/src/Illuminate/Cache/MemcachedLock.php b/src/Illuminate/Cache/MemcachedLock.php index c0db841d7973..bcafa70ec6d7 100644 --- a/src/Illuminate/Cache/MemcachedLock.php +++ b/src/Illuminate/Cache/MemcachedLock.php @@ -34,7 +34,7 @@ public function __construct($memcached, $name, $seconds) public function acquire() { return $this->memcached->add( - $this->name, 1, $this->seconds + $this->name, $this->value(), $this->seconds ); } @@ -45,6 +45,18 @@ public function acquire() */ public function release() { - $this->memcached->delete($this->name); + if ($this->canRelease()) { + $this->memcached->delete($this->name); + } + } + + /** + * Returns the value written into the driver for this lock. + * + * @return mixed + */ + protected function getValue() + { + return $this->memcached->get($this->name); } } diff --git a/src/Illuminate/Cache/RedisLock.php b/src/Illuminate/Cache/RedisLock.php index 6ce5afe59427..227f358f4121 100644 --- a/src/Illuminate/Cache/RedisLock.php +++ b/src/Illuminate/Cache/RedisLock.php @@ -33,7 +33,7 @@ public function __construct($redis, $name, $seconds) */ public function acquire() { - $result = $this->redis->setnx($this->name, 1); + $result = $this->redis->setnx($this->name, $this->value()); if ($result === 1 && $this->seconds > 0) { $this->redis->expire($this->name, $this->seconds); @@ -49,6 +49,18 @@ public function acquire() */ public function release() { - $this->redis->del($this->name); + if ($this->canRelease()) { + $this->redis->del($this->name); + } + } + + /** + * Returns the value written into the driver for this lock. + * + * @return string + */ + protected function getValue() + { + return $this->redis->get($this->name); } } diff --git a/src/Illuminate/Contracts/Cache/Lock.php b/src/Illuminate/Contracts/Cache/Lock.php index ee7dddc18765..01b54a90aa40 100644 --- a/src/Illuminate/Contracts/Cache/Lock.php +++ b/src/Illuminate/Contracts/Cache/Lock.php @@ -27,4 +27,11 @@ public function block($seconds, $callback = null); * @return void */ public function release(); + + /** + * Secures this lock against out of order releases of expired clients. + * + * @return mixed + */ + public function safe(); } diff --git a/tests/Integration/Cache/MemcachedCacheLockTest.php b/tests/Integration/Cache/MemcachedCacheLockTest.php index 5d230d57a884..51737efab17a 100644 --- a/tests/Integration/Cache/MemcachedCacheLockTest.php +++ b/tests/Integration/Cache/MemcachedCacheLockTest.php @@ -80,4 +80,45 @@ public function test_locks_throw_timeout_if_block_expires() return 'taylor'; })); } + + public function test_memcached_locks_are_released_safely() + { + Cache::store('memcached')->lock('bar')->release(); + + $firstLock = Cache::store('memcached')->lock('bar', 1)->safe(); + $this->assertTrue($firstLock->acquire()); + sleep(2); + + $secondLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $this->assertTrue($secondLock->acquire()); + + $firstLock->release(); + + $this->assertTrue(Cache::store('memcached')->has('bar')); + } + + public function test_safe_memcached_locks_are_exclusive() + { + Cache::store('memcached')->lock('bar')->release(); + + $firstLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $this->assertTrue($firstLock->acquire()); + + $secondLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $this->assertFalse($secondLock->acquire()); + } + + public function test_safe_memcached_locks_can_be_released_by_original_owner() + { + Cache::store('memcached')->lock('bar')->release(); + + $firstLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $this->assertTrue($firstLock->acquire()); + + $secondLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $this->assertFalse($secondLock->acquire()); + + $firstLock->release(); + $this->assertFalse(Cache::store('memcached')->has('bar')); + } } diff --git a/tests/Integration/Cache/RedisCacheLockTest.php b/tests/Integration/Cache/RedisCacheLockTest.php index e5747a5ca26e..363d727a934b 100644 --- a/tests/Integration/Cache/RedisCacheLockTest.php +++ b/tests/Integration/Cache/RedisCacheLockTest.php @@ -51,4 +51,45 @@ public function test_redis_locks_can_block_for_seconds() Cache::store('redis')->lock('foo')->release(); $this->assertTrue(Cache::store('redis')->lock('foo', 10)->block(1)); } + + public function test_redis_locks_are_released_safely() + { + Cache::store('redis')->lock('bar')->release(); + + $firstLock = Cache::store('redis')->lock('bar', 1)->safe(); + $this->assertTrue($firstLock->acquire()); + sleep(2); + + $secondLock = Cache::store('redis')->lock('bar', 10)->safe(); + $this->assertTrue($secondLock->acquire()); + + $firstLock->release(); + + $this->assertTrue(Cache::store('redis')->has('bar')); + } + + public function test_safe_redis_locks_are_exclusive() + { + Cache::store('redis')->lock('bar')->release(); + + $firstLock = Cache::store('redis')->lock('bar', 10)->safe(); + $this->assertTrue($firstLock->acquire()); + + $secondLock = Cache::store('redis')->lock('bar', 10)->safe(); + $this->assertFalse($secondLock->acquire()); + } + + public function test_safe_redis_locks_can_be_released_by_original_owner() + { + Cache::store('redis')->lock('bar')->release(); + + $firstLock = Cache::store('redis')->lock('bar', 10)->safe(); + $this->assertTrue($firstLock->acquire()); + + $secondLock = Cache::store('redis')->lock('bar', 10)->safe(); + $this->assertFalse($secondLock->acquire()); + + $firstLock->release(); + $this->assertFalse(Cache::store('redis')->has('bar')); + } } From 2b9e8215a460f406c691fd25d172d4dcd436d3f3 Mon Sep 17 00:00:00 2001 From: Jan-Oliver Pantel Date: Wed, 28 Nov 2018 16:42:22 +0100 Subject: [PATCH 0917/2459] Use Str::random instead of uniqid --- src/Illuminate/Cache/Lock.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index 0eb25ac0df51..43abd8d99494 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -5,6 +5,7 @@ use Illuminate\Support\InteractsWithTime; use Illuminate\Contracts\Cache\Lock as LockContract; use Illuminate\Contracts\Cache\LockTimeoutException; +use Illuminate\Support\Str; abstract class Lock implements LockContract { @@ -123,7 +124,7 @@ public function block($seconds, $callback = null) */ public function safe() { - return $this->scoped(uniqid()); + return $this->scoped(Str::random()); } /** From 5e3c61a2f6af7ae2bab5f2e1c5b5bb330d37c047 Mon Sep 17 00:00:00 2001 From: Jan-Oliver Pantel Date: Wed, 28 Nov 2018 17:37:51 +0100 Subject: [PATCH 0918/2459] Use locks for check in test to eliminate need for serialization --- src/Illuminate/Cache/Lock.php | 4 ++-- tests/Integration/Cache/RedisCacheLockTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index 43abd8d99494..ee63c9b46473 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -157,7 +157,7 @@ protected function isScoped() */ protected function value() { - return $this->isScoped() ? serialize($this->scope) : 1; + return $this->isScoped() ? $this->scope : 1; } /** @@ -171,6 +171,6 @@ protected function canRelease() return true; } - return unserialize($this->getValue()) === $this->scope; + return $this->getValue() === $this->scope; } } diff --git a/tests/Integration/Cache/RedisCacheLockTest.php b/tests/Integration/Cache/RedisCacheLockTest.php index 363d727a934b..cd027fab7c46 100644 --- a/tests/Integration/Cache/RedisCacheLockTest.php +++ b/tests/Integration/Cache/RedisCacheLockTest.php @@ -65,7 +65,7 @@ public function test_redis_locks_are_released_safely() $firstLock->release(); - $this->assertTrue(Cache::store('redis')->has('bar')); + $this->assertFalse(Cache::store('redis')->lock('bar')->get()); } public function test_safe_redis_locks_are_exclusive() From 66e01440b217186173ae8d55a826431598cea28c Mon Sep 17 00:00:00 2001 From: Jan-Oliver Pantel Date: Wed, 28 Nov 2018 17:45:09 +0100 Subject: [PATCH 0919/2459] Style fixes --- src/Illuminate/Cache/Lock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index ee63c9b46473..2bdcee9fe64f 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -2,10 +2,10 @@ namespace Illuminate\Cache; +use Illuminate\Support\Str; use Illuminate\Support\InteractsWithTime; use Illuminate\Contracts\Cache\Lock as LockContract; use Illuminate\Contracts\Cache\LockTimeoutException; -use Illuminate\Support\Str; abstract class Lock implements LockContract { From 200dd569e85dff2e803d29e366561cd47a78a028 Mon Sep 17 00:00:00 2001 From: Jan-Oliver Pantel Date: Wed, 28 Nov 2018 22:11:38 +0100 Subject: [PATCH 0920/2459] Renamed scoped to owned --- src/Illuminate/Cache/Lock.php | 28 +++++++++---------- src/Illuminate/Cache/MemcachedLock.php | 2 +- src/Illuminate/Cache/RedisLock.php | 2 +- src/Illuminate/Contracts/Cache/Lock.php | 4 +-- .../Cache/MemcachedCacheLockTest.php | 18 ++++++------ .../Integration/Cache/RedisCacheLockTest.php | 18 ++++++------ 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index 2bdcee9fe64f..dc701da46153 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -30,7 +30,7 @@ abstract class Lock implements LockContract * * @var string */ - protected $scope; + protected $owner; /** * Create a new lock instance. @@ -118,24 +118,24 @@ public function block($seconds, $callback = null) } /** - * Secures this lock against out of order releases of expired clients. + * Secures this lock against out of order releases of expired clients via assigning an owner. * * @return Lock */ - public function safe() + public function owned() { - return $this->scoped(Str::random()); + return $this->setOwner(Str::random()); } /** - * Secures this lock against out of order releases of expired clients. + * Secures this lock against out of order releases of expired clients via assigning an owner. * - * @param string $scope + * @param string $owner * @return Lock */ - public function scoped($scope) + public function setOwner($owner) { - $this->scope = $scope; + $this->owner = $owner; return $this; } @@ -145,9 +145,9 @@ public function scoped($scope) * * @return bool */ - protected function isScoped() + protected function isOwned() { - return ! is_null($this->scope); + return ! is_null($this->owner); } /** @@ -157,7 +157,7 @@ protected function isScoped() */ protected function value() { - return $this->isScoped() ? $this->scope : 1; + return $this->isOwned() ? $this->owner : 1; } /** @@ -165,12 +165,12 @@ protected function value() * * @return bool */ - protected function canRelease() + protected function isOwnedByCurrentProcess() { - if (! $this->isScoped()) { + if (! $this->isOwned()) { return true; } - return $this->getValue() === $this->scope; + return $this->getValue() === $this->owner; } } diff --git a/src/Illuminate/Cache/MemcachedLock.php b/src/Illuminate/Cache/MemcachedLock.php index bcafa70ec6d7..ac6193011b93 100644 --- a/src/Illuminate/Cache/MemcachedLock.php +++ b/src/Illuminate/Cache/MemcachedLock.php @@ -45,7 +45,7 @@ public function acquire() */ public function release() { - if ($this->canRelease()) { + if ($this->isOwnedByCurrentProcess()) { $this->memcached->delete($this->name); } } diff --git a/src/Illuminate/Cache/RedisLock.php b/src/Illuminate/Cache/RedisLock.php index 227f358f4121..764e2969d7b7 100644 --- a/src/Illuminate/Cache/RedisLock.php +++ b/src/Illuminate/Cache/RedisLock.php @@ -49,7 +49,7 @@ public function acquire() */ public function release() { - if ($this->canRelease()) { + if ($this->isOwnedByCurrentProcess()) { $this->redis->del($this->name); } } diff --git a/src/Illuminate/Contracts/Cache/Lock.php b/src/Illuminate/Contracts/Cache/Lock.php index 01b54a90aa40..a452f390ba66 100644 --- a/src/Illuminate/Contracts/Cache/Lock.php +++ b/src/Illuminate/Contracts/Cache/Lock.php @@ -29,9 +29,9 @@ public function block($seconds, $callback = null); public function release(); /** - * Secures this lock against out of order releases of expired clients. + * Secures this lock against out of order releases of expired clients via assigning an owner. * * @return mixed */ - public function safe(); + public function owned(); } diff --git a/tests/Integration/Cache/MemcachedCacheLockTest.php b/tests/Integration/Cache/MemcachedCacheLockTest.php index 51737efab17a..d020933b14c1 100644 --- a/tests/Integration/Cache/MemcachedCacheLockTest.php +++ b/tests/Integration/Cache/MemcachedCacheLockTest.php @@ -81,15 +81,15 @@ public function test_locks_throw_timeout_if_block_expires() })); } - public function test_memcached_locks_are_released_safely() + public function test_owned_memcached_locks_are_released_safely() { Cache::store('memcached')->lock('bar')->release(); - $firstLock = Cache::store('memcached')->lock('bar', 1)->safe(); + $firstLock = Cache::store('memcached')->lock('bar', 1)->owned(); $this->assertTrue($firstLock->acquire()); sleep(2); - $secondLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $secondLock = Cache::store('memcached')->lock('bar', 10)->owned(); $this->assertTrue($secondLock->acquire()); $firstLock->release(); @@ -97,25 +97,25 @@ public function test_memcached_locks_are_released_safely() $this->assertTrue(Cache::store('memcached')->has('bar')); } - public function test_safe_memcached_locks_are_exclusive() + public function test_owned_memcached_locks_are_exclusive() { Cache::store('memcached')->lock('bar')->release(); - $firstLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $firstLock = Cache::store('memcached')->lock('bar', 10)->owned(); $this->assertTrue($firstLock->acquire()); - $secondLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $secondLock = Cache::store('memcached')->lock('bar', 10)->owned(); $this->assertFalse($secondLock->acquire()); } - public function test_safe_memcached_locks_can_be_released_by_original_owner() + public function test_owned_memcached_locks_can_be_released_by_original_owner() { Cache::store('memcached')->lock('bar')->release(); - $firstLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $firstLock = Cache::store('memcached')->lock('bar', 10)->owned(); $this->assertTrue($firstLock->acquire()); - $secondLock = Cache::store('memcached')->lock('bar', 10)->safe(); + $secondLock = Cache::store('memcached')->lock('bar', 10)->owned(); $this->assertFalse($secondLock->acquire()); $firstLock->release(); diff --git a/tests/Integration/Cache/RedisCacheLockTest.php b/tests/Integration/Cache/RedisCacheLockTest.php index cd027fab7c46..a4ca7289a2ab 100644 --- a/tests/Integration/Cache/RedisCacheLockTest.php +++ b/tests/Integration/Cache/RedisCacheLockTest.php @@ -52,15 +52,15 @@ public function test_redis_locks_can_block_for_seconds() $this->assertTrue(Cache::store('redis')->lock('foo', 10)->block(1)); } - public function test_redis_locks_are_released_safely() + public function test_owned_redis_locks_are_released_safely() { Cache::store('redis')->lock('bar')->release(); - $firstLock = Cache::store('redis')->lock('bar', 1)->safe(); + $firstLock = Cache::store('redis')->lock('bar', 1)->owned(); $this->assertTrue($firstLock->acquire()); sleep(2); - $secondLock = Cache::store('redis')->lock('bar', 10)->safe(); + $secondLock = Cache::store('redis')->lock('bar', 10)->owned(); $this->assertTrue($secondLock->acquire()); $firstLock->release(); @@ -68,25 +68,25 @@ public function test_redis_locks_are_released_safely() $this->assertFalse(Cache::store('redis')->lock('bar')->get()); } - public function test_safe_redis_locks_are_exclusive() + public function test_owned_redis_locks_are_exclusive() { Cache::store('redis')->lock('bar')->release(); - $firstLock = Cache::store('redis')->lock('bar', 10)->safe(); + $firstLock = Cache::store('redis')->lock('bar', 10)->owned(); $this->assertTrue($firstLock->acquire()); - $secondLock = Cache::store('redis')->lock('bar', 10)->safe(); + $secondLock = Cache::store('redis')->lock('bar', 10)->owned(); $this->assertFalse($secondLock->acquire()); } - public function test_safe_redis_locks_can_be_released_by_original_owner() + public function test_owned_redis_locks_can_be_released_by_original_owner() { Cache::store('redis')->lock('bar')->release(); - $firstLock = Cache::store('redis')->lock('bar', 10)->safe(); + $firstLock = Cache::store('redis')->lock('bar', 10)->owned(); $this->assertTrue($firstLock->acquire()); - $secondLock = Cache::store('redis')->lock('bar', 10)->safe(); + $secondLock = Cache::store('redis')->lock('bar', 10)->owned(); $this->assertFalse($secondLock->acquire()); $firstLock->release(); From fdc00c15df3e6aad1c9c4d5ad5d954f09dad6e34 Mon Sep 17 00:00:00 2001 From: Rod Elias Date: Fri, 30 Nov 2018 11:40:12 -0200 Subject: [PATCH 0921/2459] fix docblock (#26678) --- src/Illuminate/Database/Eloquent/FactoryBuilder.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/FactoryBuilder.php b/src/Illuminate/Database/Eloquent/FactoryBuilder.php index 150f2ef312ba..87bb0d878bd2 100644 --- a/src/Illuminate/Database/Eloquent/FactoryBuilder.php +++ b/src/Illuminate/Database/Eloquent/FactoryBuilder.php @@ -306,6 +306,8 @@ protected function makeInstance(array $attributes = []) * @param array $definition * @param array $attributes * @return array + * + * @throws \InvalidArgumentException */ protected function applyStates(array $definition, array $attributes = []) { From d0cf02d23dc2da792c784fabd2f8f1269a79d99a Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Fri, 30 Nov 2018 14:42:04 +0100 Subject: [PATCH 0922/2459] Fix HasManyThrough existence queries with same parent and through parent table (#26676) --- .../Eloquent/Relations/HasManyThrough.php | 29 +++++++++++- .../Database/EloquentHasManyThroughTest.php | 46 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php index 93f781dcd007..96a5420de3e8 100644 --- a/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php +++ b/src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php @@ -480,10 +480,14 @@ protected function prepareQueryBuilder($columns = ['*']) */ public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*']) { - if ($parentQuery->getQuery()->from == $query->getQuery()->from) { + if ($parentQuery->getQuery()->from === $query->getQuery()->from) { return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns); } + if ($parentQuery->getQuery()->from === $this->throughParent->getTable()) { + return $this->getRelationExistenceQueryForThroughSelfRelation($query, $parentQuery, $columns); + } + $this->performJoin($query); return $query->select($columns)->whereColumn( @@ -516,6 +520,29 @@ public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder ); } + /** + * Add the constraints for a relationship query on the same table as the through parent. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param \Illuminate\Database\Eloquent\Builder $parentQuery + * @param array|mixed $columns + * @return \Illuminate\Database\Eloquent\Builder + */ + public function getRelationExistenceQueryForThroughSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*']) + { + $table = $this->throughParent->getTable().' as '.$hash = $this->getRelationCountHash(); + + $query->join($table, $hash.'.'.$this->secondLocalKey, '=', $this->getQualifiedFarKeyName()); + + if ($this->throughParentSoftDeletes()) { + $query->whereNull($hash.'.'.$this->throughParent->getDeletedAtColumn()); + } + + return $query->select($columns)->whereColumn( + $parentQuery->getQuery()->from.'.'.$this->localKey, '=', $hash.'.'.$this->firstKey + ); + } + /** * Get a relationship join table hash. * diff --git a/tests/Integration/Database/EloquentHasManyThroughTest.php b/tests/Integration/Database/EloquentHasManyThroughTest.php index 06ce0acc2729..67164c473bcb 100644 --- a/tests/Integration/Database/EloquentHasManyThroughTest.php +++ b/tests/Integration/Database/EloquentHasManyThroughTest.php @@ -4,6 +4,7 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Tests\Integration\Database\DatabaseTestCase; /** @@ -27,6 +28,17 @@ public function setUp() $table->integer('owner_id')->nullable(); $table->string('owner_slug')->nullable(); }); + + Schema::create('categories', function ($table) { + $table->increments('id'); + $table->integer('parent_id')->nullable(); + $table->softDeletes(); + }); + + Schema::create('products', function ($table) { + $table->increments('id'); + $table->integer('category_id'); + }); } public function test_basic_create_and_retrieve() @@ -83,6 +95,21 @@ public function test_has_self_custom_owner_key() $this->assertEquals(1, $users->count()); } + + public function test_has_same_parent_and_through_parent_table() + { + Category::create(); + Category::create(); + Category::create(['parent_id' => 1]); + Category::create(['parent_id' => 2])->delete(); + + Product::create(['category_id' => 3]); + Product::create(['category_id' => 4]); + + $categories = Category::has('subProducts')->get(); + + $this->assertEquals([1], $categories->pluck('id')->all()); + } } class User extends Model @@ -129,3 +156,22 @@ class Team extends Model public $timestamps = false; protected $guarded = []; } + +class Category extends Model +{ + use SoftDeletes; + + public $timestamps = false; + protected $guarded = []; + + public function subProducts() + { + return $this->hasManyThrough(Product::class, self::class, 'parent_id'); + } +} + +class Product extends Model +{ + public $timestamps = false; + protected $guarded = []; +} From 0e4e522547351aa229786f1c00f874ef5375ea33 Mon Sep 17 00:00:00 2001 From: Denis Golubkov Date: Fri, 30 Nov 2018 16:53:18 +0300 Subject: [PATCH 0923/2459] removed recalculation of decoded path in loop (#26686) --- src/Illuminate/Http/Request.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 09b49c75591c..350471ec8b8f 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -184,8 +184,10 @@ public function segments() */ public function is(...$patterns) { + $path = $this->decodedPath(); + foreach ($patterns as $pattern) { - if (Str::is($pattern, $this->decodedPath())) { + if (Str::is($pattern, $path)) { return true; } } From 9ee5fc680285b21afa241dab6baebfe517ab4088 Mon Sep 17 00:00:00 2001 From: Antonio Pauletich Date: Fri, 30 Nov 2018 14:53:58 +0100 Subject: [PATCH 0924/2459] [5.8] Bump min Symfony version to 4.2 (#26685) --- composer.json | 16 ++++++++-------- src/Illuminate/Console/composer.json | 4 ++-- src/Illuminate/Cookie/composer.json | 4 ++-- src/Illuminate/Filesystem/composer.json | 2 +- src/Illuminate/Http/composer.json | 4 ++-- src/Illuminate/Queue/composer.json | 4 ++-- src/Illuminate/Routing/composer.json | 8 ++++---- src/Illuminate/Session/composer.json | 4 ++-- src/Illuminate/Support/composer.json | 4 ++-- src/Illuminate/Validation/composer.json | 2 +- src/Illuminate/View/composer.json | 2 +- 11 files changed, 27 insertions(+), 27 deletions(-) diff --git a/composer.json b/composer.json index cf983c2ce0a5..8311ad5ef9e9 100644 --- a/composer.json +++ b/composer.json @@ -31,14 +31,14 @@ "psr/simple-cache": "^1.0", "ramsey/uuid": "^3.7", "swiftmailer/swiftmailer": "^6.0", - "symfony/console": "^4.1", - "symfony/debug": "^4.1", - "symfony/finder": "^4.1", - "symfony/http-foundation": "^4.1", - "symfony/http-kernel": "^4.1", - "symfony/process": "^4.1", - "symfony/routing": "^4.1", - "symfony/var-dumper": "^4.1", + "symfony/console": "^4.2", + "symfony/debug": "^4.2", + "symfony/finder": "^4.2", + "symfony/http-foundation": "^4.2", + "symfony/http-kernel": "^4.2", + "symfony/process": "^4.2", + "symfony/routing": "^4.2", + "symfony/var-dumper": "^4.2", "tijsverkoyen/css-to-inline-styles": "^2.2.1", "vlucas/phpdotenv": "^2.2" }, diff --git a/src/Illuminate/Console/composer.json b/src/Illuminate/Console/composer.json index 3337a351280b..d7fc3372b783 100755 --- a/src/Illuminate/Console/composer.json +++ b/src/Illuminate/Console/composer.json @@ -17,8 +17,8 @@ "php": "^7.1.3", "illuminate/contracts": "5.8.*", "illuminate/support": "5.8.*", - "symfony/console": "^4.1", - "symfony/process": "^4.1" + "symfony/console": "^4.2", + "symfony/process": "^4.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Cookie/composer.json b/src/Illuminate/Cookie/composer.json index 185fe15b09a2..e6c6b9a9cabc 100755 --- a/src/Illuminate/Cookie/composer.json +++ b/src/Illuminate/Cookie/composer.json @@ -17,8 +17,8 @@ "php": "^7.1.3", "illuminate/contracts": "5.8.*", "illuminate/support": "5.8.*", - "symfony/http-foundation": "^4.1", - "symfony/http-kernel": "^4.1" + "symfony/http-foundation": "^4.2", + "symfony/http-kernel": "^4.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Filesystem/composer.json b/src/Illuminate/Filesystem/composer.json index 98826965342c..2bafd57d644e 100644 --- a/src/Illuminate/Filesystem/composer.json +++ b/src/Illuminate/Filesystem/composer.json @@ -17,7 +17,7 @@ "php": "^7.1.3", "illuminate/contracts": "5.8.*", "illuminate/support": "5.8.*", - "symfony/finder": "^4.1" + "symfony/finder": "^4.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Http/composer.json b/src/Illuminate/Http/composer.json index f252a4bd1820..ed8be0bba62e 100755 --- a/src/Illuminate/Http/composer.json +++ b/src/Illuminate/Http/composer.json @@ -18,8 +18,8 @@ "ext-json": "*", "illuminate/session": "5.8.*", "illuminate/support": "5.8.*", - "symfony/http-foundation": "^4.1", - "symfony/http-kernel": "^4.1" + "symfony/http-foundation": "^4.2", + "symfony/http-kernel": "^4.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Queue/composer.json b/src/Illuminate/Queue/composer.json index 7c9f9404214c..20795f749b50 100644 --- a/src/Illuminate/Queue/composer.json +++ b/src/Illuminate/Queue/composer.json @@ -23,8 +23,8 @@ "illuminate/filesystem": "5.8.*", "illuminate/support": "5.8.*", "opis/closure": "^3.1", - "symfony/debug": "^4.1", - "symfony/process": "^4.1" + "symfony/debug": "^4.2", + "symfony/process": "^4.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Routing/composer.json b/src/Illuminate/Routing/composer.json index 4506ca3383b0..d0fefaa9eaa0 100644 --- a/src/Illuminate/Routing/composer.json +++ b/src/Illuminate/Routing/composer.json @@ -22,10 +22,10 @@ "illuminate/pipeline": "5.8.*", "illuminate/session": "5.8.*", "illuminate/support": "5.8.*", - "symfony/debug": "^4.1", - "symfony/http-foundation": "^4.1", - "symfony/http-kernel": "^4.1", - "symfony/routing": "^4.1" + "symfony/debug": "^4.2", + "symfony/http-foundation": "^4.2", + "symfony/http-kernel": "^4.2", + "symfony/routing": "^4.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Session/composer.json b/src/Illuminate/Session/composer.json index 120e5f89fdeb..b916d037e5e5 100755 --- a/src/Illuminate/Session/composer.json +++ b/src/Illuminate/Session/composer.json @@ -19,8 +19,8 @@ "illuminate/contracts": "5.8.*", "illuminate/filesystem": "5.8.*", "illuminate/support": "5.8.*", - "symfony/finder": "^4.1", - "symfony/http-foundation": "^4.1" + "symfony/finder": "^4.2", + "symfony/http-foundation": "^4.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/Support/composer.json b/src/Illuminate/Support/composer.json index 1989a000646a..73df9be6bc57 100644 --- a/src/Illuminate/Support/composer.json +++ b/src/Illuminate/Support/composer.json @@ -41,8 +41,8 @@ "illuminate/filesystem": "Required to use the composer class (5.8.*).", "moontoast/math": "Required to use ordered UUIDs (^1.1).", "ramsey/uuid": "Required to use Str::uuid() (^3.7).", - "symfony/process": "Required to use the composer class (^4.1).", - "symfony/var-dumper": "Required to use the dd function (^4.1)." + "symfony/process": "Required to use the composer class (^4.2).", + "symfony/var-dumper": "Required to use the dd function (^4.2)." }, "config": { "sort-packages": true diff --git a/src/Illuminate/Validation/composer.json b/src/Illuminate/Validation/composer.json index d8c950da0bf8..986bcbe21e1a 100755 --- a/src/Illuminate/Validation/composer.json +++ b/src/Illuminate/Validation/composer.json @@ -21,7 +21,7 @@ "illuminate/contracts": "5.8.*", "illuminate/support": "5.8.*", "illuminate/translation": "5.8.*", - "symfony/http-foundation": "^4.1" + "symfony/http-foundation": "^4.2" }, "autoload": { "psr-4": { diff --git a/src/Illuminate/View/composer.json b/src/Illuminate/View/composer.json index 69f14d211e28..d5c729bc0773 100644 --- a/src/Illuminate/View/composer.json +++ b/src/Illuminate/View/composer.json @@ -21,7 +21,7 @@ "illuminate/events": "5.8.*", "illuminate/filesystem": "5.8.*", "illuminate/support": "5.8.*", - "symfony/debug": "^4.1" + "symfony/debug": "^4.2" }, "autoload": { "psr-4": { From 86131d61b511deacf23f8596e8b7bb2f07dbf46a Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Fri, 30 Nov 2018 23:26:13 +0100 Subject: [PATCH 0925/2459] Prevent breaking eager loading with "incrementing" string keys (#26688) --- src/Illuminate/Database/Eloquent/Relations/Relation.php | 1 + tests/Database/DatabaseEloquentHasManyTest.php | 1 + tests/Database/DatabaseEloquentHasOneTest.php | 1 + tests/Database/DatabaseEloquentMorphTest.php | 1 + tests/Database/DatabaseEloquentMorphToManyTest.php | 1 + 5 files changed, 5 insertions(+) diff --git a/src/Illuminate/Database/Eloquent/Relations/Relation.php b/src/Illuminate/Database/Eloquent/Relations/Relation.php index 9ba744376ef5..522d763aedd9 100755 --- a/src/Illuminate/Database/Eloquent/Relations/Relation.php +++ b/src/Illuminate/Database/Eloquent/Relations/Relation.php @@ -318,6 +318,7 @@ protected function whereInMethod(Model $model, $key) { return $model->getKeyName() === last(explode('.', $key)) && $model->getIncrementing() + && in_array($model->getKeyType(), ['int', 'integer']) ? 'whereIntegerInRaw' : 'whereIn'; } diff --git a/tests/Database/DatabaseEloquentHasManyTest.php b/tests/Database/DatabaseEloquentHasManyTest.php index a860665f7d44..8c5d79d9a472 100755 --- a/tests/Database/DatabaseEloquentHasManyTest.php +++ b/tests/Database/DatabaseEloquentHasManyTest.php @@ -202,6 +202,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(true); + $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasManyModelStub; $model1->id = 1; diff --git a/tests/Database/DatabaseEloquentHasOneTest.php b/tests/Database/DatabaseEloquentHasOneTest.php index 1260e3f706b1..1816646ad80f 100755 --- a/tests/Database/DatabaseEloquentHasOneTest.php +++ b/tests/Database/DatabaseEloquentHasOneTest.php @@ -165,6 +165,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(true); + $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('table.foreign_key', [1, 2]); $model1 = new EloquentHasOneModelStub; $model1->id = 1; diff --git a/tests/Database/DatabaseEloquentMorphTest.php b/tests/Database/DatabaseEloquentMorphTest.php index 6b78779ab61e..6b390e6b06dd 100755 --- a/tests/Database/DatabaseEloquentMorphTest.php +++ b/tests/Database/DatabaseEloquentMorphTest.php @@ -54,6 +54,7 @@ public function testMorphManyEagerConstraintsAreProperlyAdded() $relation = $this->getManyRelation(); $relation->getParent()->shouldReceive('getKeyName')->once()->andReturn('id'); $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(true); + $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('table.morph_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent())); diff --git a/tests/Database/DatabaseEloquentMorphToManyTest.php b/tests/Database/DatabaseEloquentMorphToManyTest.php index 058407fba032..c2c2a7add483 100644 --- a/tests/Database/DatabaseEloquentMorphToManyTest.php +++ b/tests/Database/DatabaseEloquentMorphToManyTest.php @@ -20,6 +20,7 @@ public function testEagerConstraintsAreProperlyAdded() $relation = $this->getRelation(); $relation->getParent()->shouldReceive('getKeyName')->andReturn('id'); $relation->getParent()->shouldReceive('getIncrementing')->once()->andReturn(true); + $relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int'); $relation->getQuery()->shouldReceive('whereIntegerInRaw')->once()->with('taggables.taggable_id', [1, 2]); $relation->getQuery()->shouldReceive('where')->once()->with('taggables.taggable_type', get_class($relation->getParent())); $model1 = new EloquentMorphToManyModelStub; From ef164c60004c16a1a947dbfd4934097f947ed6bc Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 2 Dec 2018 12:33:30 +0200 Subject: [PATCH 0926/2459] [5.7] update changelog --- CHANGELOG-5.7.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG-5.7.md b/CHANGELOG-5.7.md index 5fc549c474e5..cc2bc8f87c13 100644 --- a/CHANGELOG-5.7.md +++ b/CHANGELOG-5.7.md @@ -1,5 +1,16 @@ # Release Notes for 5.7.x +## Unreleased + +### Fixed +- Fixed self-referencing HasManyThrough existence queries ([#26662](https://github.com/laravel/framework/pull/26662)) +- Fixed HasManyThrough existence queries with same parent and through parent table ([#26676](https://github.com/laravel/framework/pull/26676)) +- Fixed breaking eager loading with "incrementing" string keys ([#26688](https://github.com/laravel/framework/pull/26688)) + +### Changed +- Changed markdown on auth stub view (`Auth/Console/stubs/make/views/auth/login.stub`) ([#26648](https://github.com/laravel/framework/pull/26648)) + + ## [v5.7.15 (2018-11-26)](https://github.com/laravel/framework/compare/v5.7.14...v5.7.15) ### Added From 79cd45d19839679f3b229615dff07091e21e54f6 Mon Sep 17 00:00:00 2001 From: Mark van den Broek Date: Sun, 2 Dec 2018 17:37:20 +0100 Subject: [PATCH 0927/2459] Adds missing array typehint. (#26711) --- src/Illuminate/Foundation/Console/RouteListCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Console/RouteListCommand.php b/src/Illuminate/Foundation/Console/RouteListCommand.php index 35d939a7cdb7..5738b6527ee8 100644 --- a/src/Illuminate/Foundation/Console/RouteListCommand.php +++ b/src/Illuminate/Foundation/Console/RouteListCommand.php @@ -129,7 +129,7 @@ protected function getRouteInformation(Route $route) * @param array $routes * @return array */ - protected function sortRoutes($sort, $routes) + protected function sortRoutes($sort, array $routes) { return Arr::sort($routes, function ($route) use ($sort) { return $route[$sort]; @@ -142,7 +142,7 @@ protected function sortRoutes($sort, $routes) * @param array $routes * @return array */ - protected function pluckColumns($routes) + protected function pluckColumns(array $routes) { return array_map(function ($route) { return Arr::only($route, $this->getColumns()); From 5465780451f6e52c431d05d41df8b20ba5ac74c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C5=BEuris?= Date: Sun, 2 Dec 2018 18:40:46 +0200 Subject: [PATCH 0928/2459] Update app.stub (#26708) Remove li (instead of leaving it empty) if the register route is not defined. --- .../Auth/Console/stubs/make/views/layouts/app.stub | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub b/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub index 32bf5f6c7346..ee7767c46f9e 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/layouts/app.stub @@ -43,11 +43,11 @@ - + + @endif @else
    + @endif diff --git a/src/Illuminate/Pagination/resources/views/default.blade.php b/src/Illuminate/Pagination/resources/views/default.blade.php index e59847a3f553..0db70b56275c 100644 --- a/src/Illuminate/Pagination/resources/views/default.blade.php +++ b/src/Illuminate/Pagination/resources/views/default.blade.php @@ -1,44 +1,46 @@ @if ($paginator->hasPages()) - + @endif diff --git a/src/Illuminate/Pagination/resources/views/simple-bootstrap-4.blade.php b/src/Illuminate/Pagination/resources/views/simple-bootstrap-4.blade.php index cc30c9b25b5e..4bb491742a3d 100644 --- a/src/Illuminate/Pagination/resources/views/simple-bootstrap-4.blade.php +++ b/src/Illuminate/Pagination/resources/views/simple-bootstrap-4.blade.php @@ -1,25 +1,27 @@ @if ($paginator->hasPages()) - + @endif diff --git a/src/Illuminate/Pagination/resources/views/simple-default.blade.php b/src/Illuminate/Pagination/resources/views/simple-default.blade.php index bdf2fe883cb2..36bdbc18c655 100644 --- a/src/Illuminate/Pagination/resources/views/simple-default.blade.php +++ b/src/Illuminate/Pagination/resources/views/simple-default.blade.php @@ -1,17 +1,19 @@ @if ($paginator->hasPages()) - + @endif From c443c83c11a3ba93867e7fa0a2b31af026032a59 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Thu, 14 Mar 2019 09:35:18 -0400 Subject: [PATCH 1623/2459] Adds even and odd flags to the Loop variable --- src/Illuminate/View/Concerns/ManagesLoops.php | 4 ++++ tests/View/ViewFactoryTest.php | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Illuminate/View/Concerns/ManagesLoops.php b/src/Illuminate/View/Concerns/ManagesLoops.php index 5f50b247efd9..edd6363ec7d3 100644 --- a/src/Illuminate/View/Concerns/ManagesLoops.php +++ b/src/Illuminate/View/Concerns/ManagesLoops.php @@ -33,6 +33,8 @@ public function addLoop($data) 'count' => $length, 'first' => true, 'last' => isset($length) ? $length == 1 : null, + 'odd' => false, + 'even' => true, 'depth' => count($this->loopsStack) + 1, 'parent' => $parent ? (object) $parent : null, ]; @@ -51,6 +53,8 @@ public function incrementLoopIndices() 'iteration' => $loop['iteration'] + 1, 'index' => $loop['iteration'], 'first' => $loop['iteration'] == 0, + 'odd' => ! $loop['odd'], + 'even' => ! $loop['even'], 'remaining' => isset($loop['count']) ? $loop['remaining'] - 1 : null, 'last' => isset($loop['count']) ? $loop['iteration'] == $loop['count'] - 1 : null, ]); diff --git a/tests/View/ViewFactoryTest.php b/tests/View/ViewFactoryTest.php index b3d7af197f7e..f6271fdf9a56 100755 --- a/tests/View/ViewFactoryTest.php +++ b/tests/View/ViewFactoryTest.php @@ -539,6 +539,8 @@ public function testAddingLoops() 'count' => 3, 'first' => true, 'last' => false, + 'odd' => false, + 'even' => true, 'depth' => 1, 'parent' => null, ]; @@ -554,6 +556,8 @@ public function testAddingLoops() 'count' => 4, 'first' => true, 'last' => false, + 'odd' => false, + 'even' => true, 'depth' => 2, 'parent' => (object) $expectedLoop, ]; @@ -597,6 +601,8 @@ public function testAddingUncountableLoop() 'count' => null, 'first' => true, 'last' => null, + 'odd' => false, + 'even' => true, 'depth' => 1, 'parent' => null, ]; @@ -612,11 +618,19 @@ public function testIncrementingLoopIndices() $factory->incrementLoopIndices(); + $this->assertEquals(1, $factory->getLoopStack()[0]['iteration']); + $this->assertEquals(0, $factory->getLoopStack()[0]['index']); + $this->assertEquals(3, $factory->getLoopStack()[0]['remaining']); + $this->assertTrue($factory->getLoopStack()[0]['odd']); + $this->assertFalse($factory->getLoopStack()[0]['even']); + $factory->incrementLoopIndices(); $this->assertEquals(2, $factory->getLoopStack()[0]['iteration']); $this->assertEquals(1, $factory->getLoopStack()[0]['index']); $this->assertEquals(2, $factory->getLoopStack()[0]['remaining']); + $this->assertFalse($factory->getLoopStack()[0]['odd']); + $this->assertTrue($factory->getLoopStack()[0]['even']); } public function testReachingEndOfLoop() From a32792233dd7db53a0177ac5a9ae3f3a13d53662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20S=C3=B8gaard?= Date: Thu, 14 Mar 2019 18:14:29 +0100 Subject: [PATCH 1624/2459] =?UTF-8?q?Add=20replacement=20for=20lower=20dan?= =?UTF-8?q?ish=20"=C3=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Illuminate/Support/Str.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 3746a43bb964..3183214262bc 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -723,8 +723,8 @@ protected static function languageSpecificCharsArray($language) ['h', 'H', 'sht', 'SHT', 'a', 'А', 'y', 'Y'], ], 'da' => [ - ['ø', 'å', 'Æ', 'Ø', 'Å'], - ['oe', 'aa', 'Ae', 'Oe', 'Aa'], + ['æ', 'ø', 'å', 'Æ', 'Ø', 'Å'], + ['ae', 'oe', 'aa', 'Ae', 'Oe', 'Aa'], ], 'de' => [ ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü'], From c633f22b5cba192663d9835d33938d1567ffa3fa Mon Sep 17 00:00:00 2001 From: Olga Strizhenko Date: Fri, 15 Mar 2019 15:39:44 +0100 Subject: [PATCH 1625/2459] [5.8] Path of the view in compiled template causes regression with declare(strict_types=1) in templates + test on declare(strict_types=1) --- tests/View/ViewBladeCompilerTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index 833b6597e192..9e32b7d21400 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -101,6 +101,14 @@ public function testIncludePathToTemplate() $compiler->compile('foo'); } + public function testShouldStartFromStrictTypesDeclaration() + { + $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); + $strictTypeDecl = "assertTrue(substr($compiler->compileString(" Date: Fri, 15 Mar 2019 18:45:34 +0100 Subject: [PATCH 1626/2459] Restore maintenance message on error page --- src/Illuminate/Foundation/Exceptions/views/503.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Exceptions/views/503.blade.php b/src/Illuminate/Foundation/Exceptions/views/503.blade.php index c5a9dde14e48..acd38100a745 100644 --- a/src/Illuminate/Foundation/Exceptions/views/503.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/503.blade.php @@ -2,4 +2,4 @@ @section('title', __('Service Unavailable')) @section('code', '503') -@section('message', __('Service Unavailable')) +@section('message', __($exception->getMessage() ?: 'Service Unavailable')) From f87950b2746a1f8f9588a1447d9ed4f6f71426a8 Mon Sep 17 00:00:00 2001 From: Liviu Roman Date: Sat, 16 Mar 2019 17:46:08 +0200 Subject: [PATCH 1627/2459] Added romanian specific transliteration to Str class --- src/Illuminate/Support/Str.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index 3183214262bc..d536aa94c1e1 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -730,6 +730,10 @@ protected static function languageSpecificCharsArray($language) ['ä', 'ö', 'ü', 'Ä', 'Ö', 'Ü'], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], ], + 'ro' => [ + ['ă', 'â', 'î', 'ș', 'ț', 'Ă', 'Â', 'Î', 'Ș', 'Ț'], + ['a', 'a', 'i', 's', 't', 'A', 'A', 'I', 'S', 'T'], + ], ]; } From 8181c03c0e7567aa96c8308e359bdf62639ede0c Mon Sep 17 00:00:00 2001 From: Ankur Kumar Date: Sat, 16 Mar 2019 22:20:15 +0530 Subject: [PATCH 1628/2459] [5.8] Restore exception message on 403 error page Restore the v5.7 behaviour, see https://github.com/laravel/framework/pull/26356 --- src/Illuminate/Foundation/Exceptions/views/403.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Exceptions/views/403.blade.php b/src/Illuminate/Foundation/Exceptions/views/403.blade.php index 11af8d1b5294..a5506f01f215 100644 --- a/src/Illuminate/Foundation/Exceptions/views/403.blade.php +++ b/src/Illuminate/Foundation/Exceptions/views/403.blade.php @@ -2,4 +2,4 @@ @section('title', __('Forbidden')) @section('code', '403') -@section('message', __('Forbidden')) +@section('message', __($exception->getMessage() ?: 'Forbidden')) From 567bb48274b060022becb12e00867b341848991d Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 17 Mar 2019 13:23:33 +0200 Subject: [PATCH 1629/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 75b4a1366d4d..61b3f2fa201b 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -2,6 +2,21 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v5.8.4...5.8) +### Added +- Added `Illuminate\Database\DatabaseManager::setReconnector()` ([#27845](https://github.com/laravel/framework/pull/27845)) +- Added `Illuminate\Auth\Access\Gate::none()` ([#27859](https://github.com/laravel/framework/pull/27859)) +- Added `OtherDeviceLogout` event ([#27865](https://github.com/laravel/framework/pull/27865), [5e87f2d](https://github.com/laravel/framework/commit/5e87f2df072ec4a243b6a3a983a753e8ffa5e6bf)) + +### Changed +- Add replacement for lower danish `æ` ([#27886](https://github.com/laravel/framework/pull/27886)) + +### Fixed +- Fixed seeding logic in `Arr::shuffle()` ([#27861](https://github.com/laravel/framework/pull/27861)) + +### TODO: +- https://github.com/laravel/framework/pull/27878 +- https://github.com/laravel/framework/pull/27883 +- https://github.com/laravel/framework/pull/27893, https://github.com/laravel/framework/pull/27902 ## [v5.8.4 (2019-03-12)](https://github.com/laravel/framework/compare/v5.8.3...v5.8.4) From ad3bdfe0a7eeeacec18c1a6a73bcfe873e1c1edc Mon Sep 17 00:00:00 2001 From: Yurii Prudskyi Date: Sun, 17 Mar 2019 20:49:42 +0200 Subject: [PATCH 1630/2459] Fix updateOrInsert method for Query Builder Now it correctly works with empty values array. Before it created syntactically wrong SQL, now it simply returns 'true'. --- src/Illuminate/Database/Query/Builder.php | 4 +++ tests/Database/DatabaseQueryBuilderTest.php | 28 +++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 737288456b14..59eb358e0556 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -2678,6 +2678,10 @@ public function updateOrInsert(array $attributes, array $values = []) return $this->insert(array_merge($attributes, $values)); } + if (empty($values)) { + return true; + } + return (bool) $this->take(1)->update($values); } diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 87b76cb82170..125f7c1ecd43 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2003,6 +2003,34 @@ public function testUpdateOrInsertMethod() $this->assertTrue($builder->updateOrInsert(['email' => 'foo'], ['name' => 'bar'])); } + public function testUpdateOrInsertMethodWorksWithEmptyUpdateValues() + { + $builder = m::mock(Builder::class.'[where,exists,insert]', [ + m::mock(ConnectionInterface::class), + new Grammar, + m::mock(Processor::class), + ]); + + $builder->shouldReceive('where')->once()->with(['email' => 'foo'])->andReturn(m::self()); + $builder->shouldReceive('exists')->once()->andReturn(false); + $builder->shouldReceive('insert')->once()->with(['email' => 'foo', 'name' => 'bar'])->andReturn(true); + + $this->assertTrue($builder->updateOrInsert(['email' => 'foo'], ['name' => 'bar'])); + + $builder = m::mock(Builder::class.'[where,exists,update]', [ + m::mock(ConnectionInterface::class), + new Grammar, + m::mock(Processor::class), + ]); + + $builder->shouldReceive('where')->once()->with(['email' => 'foo'])->andReturn(m::self()); + $builder->shouldReceive('exists')->once()->andReturn(true); + $builder->shouldReceive('take')->andReturnSelf(); + $builder->shouldNotReceive('update')->with([]); + + $this->assertTrue($builder->updateOrInsert(['email' => 'foo'])); + } + public function testDeleteMethod() { $builder = $this->getBuilder(); From 8199ff302df8607dd284d7e5fbfe97a164f87ca8 Mon Sep 17 00:00:00 2001 From: Yurii Prudskyi Date: Sun, 17 Mar 2019 21:42:58 +0200 Subject: [PATCH 1631/2459] Fix test for updateOrInsert method for Query Builder Now it checks for `update` method not being called, if updateOrInsert update values array is empty. --- tests/Database/DatabaseQueryBuilderTest.php | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 125f7c1ecd43..ec8946d5bd43 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2005,19 +2005,7 @@ public function testUpdateOrInsertMethod() public function testUpdateOrInsertMethodWorksWithEmptyUpdateValues() { - $builder = m::mock(Builder::class.'[where,exists,insert]', [ - m::mock(ConnectionInterface::class), - new Grammar, - m::mock(Processor::class), - ]); - - $builder->shouldReceive('where')->once()->with(['email' => 'foo'])->andReturn(m::self()); - $builder->shouldReceive('exists')->once()->andReturn(false); - $builder->shouldReceive('insert')->once()->with(['email' => 'foo', 'name' => 'bar'])->andReturn(true); - - $this->assertTrue($builder->updateOrInsert(['email' => 'foo'], ['name' => 'bar'])); - - $builder = m::mock(Builder::class.'[where,exists,update]', [ + $builder = m::spy(Builder::class.'[where,exists,update]', [ m::mock(ConnectionInterface::class), new Grammar, m::mock(Processor::class), @@ -2025,10 +2013,9 @@ public function testUpdateOrInsertMethodWorksWithEmptyUpdateValues() $builder->shouldReceive('where')->once()->with(['email' => 'foo'])->andReturn(m::self()); $builder->shouldReceive('exists')->once()->andReturn(true); - $builder->shouldReceive('take')->andReturnSelf(); - $builder->shouldNotReceive('update')->with([]); $this->assertTrue($builder->updateOrInsert(['email' => 'foo'])); + $builder->shouldNotHaveReceived('update'); } public function testDeleteMethod() From 56462b53f421196fea86a7886d758f59ab3ae687 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 17 Mar 2019 22:11:05 +0200 Subject: [PATCH 1632/2459] Revert "Wrap pagination menus in nav element instead of placing navigation role un ULs" This reverts commit b7f572b1 (https://github.com/laravel/framework/pull/27878 pr) As for me will be better to implement this changes in the 5.9 release... Since we can break some app, since of amy people can style `nav` element in any way. --- CHANGELOG-5.8.md | 1 - .../resources/views/bootstrap-4.blade.php | 80 +++++++++---------- .../resources/views/default.blade.php | 80 +++++++++---------- .../views/simple-bootstrap-4.blade.php | 46 +++++------ .../resources/views/simple-default.blade.php | 30 ++++--- 5 files changed, 114 insertions(+), 123 deletions(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 61b3f2fa201b..157644772c79 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -14,7 +14,6 @@ - Fixed seeding logic in `Arr::shuffle()` ([#27861](https://github.com/laravel/framework/pull/27861)) ### TODO: -- https://github.com/laravel/framework/pull/27878 - https://github.com/laravel/framework/pull/27883 - https://github.com/laravel/framework/pull/27893, https://github.com/laravel/framework/pull/27902 diff --git a/src/Illuminate/Pagination/resources/views/bootstrap-4.blade.php b/src/Illuminate/Pagination/resources/views/bootstrap-4.blade.php index 63c6f56b59e0..044bbaa4a541 100644 --- a/src/Illuminate/Pagination/resources/views/bootstrap-4.blade.php +++ b/src/Illuminate/Pagination/resources/views/bootstrap-4.blade.php @@ -1,46 +1,44 @@ @if ($paginator->hasPages()) - + @endforeach + + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
  • + +
  • + @else +
  • + +
  • + @endif + @endif diff --git a/src/Illuminate/Pagination/resources/views/default.blade.php b/src/Illuminate/Pagination/resources/views/default.blade.php index 0db70b56275c..e59847a3f553 100644 --- a/src/Illuminate/Pagination/resources/views/default.blade.php +++ b/src/Illuminate/Pagination/resources/views/default.blade.php @@ -1,46 +1,44 @@ @if ($paginator->hasPages()) - + @endforeach + + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
  • + +
  • + @else +
  • + +
  • + @endif + @endif diff --git a/src/Illuminate/Pagination/resources/views/simple-bootstrap-4.blade.php b/src/Illuminate/Pagination/resources/views/simple-bootstrap-4.blade.php index 4bb491742a3d..cc30c9b25b5e 100644 --- a/src/Illuminate/Pagination/resources/views/simple-bootstrap-4.blade.php +++ b/src/Illuminate/Pagination/resources/views/simple-bootstrap-4.blade.php @@ -1,27 +1,25 @@ @if ($paginator->hasPages()) - + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
  • + +
  • + @else +
  • + @lang('pagination.next') +
  • + @endif + @endif diff --git a/src/Illuminate/Pagination/resources/views/simple-default.blade.php b/src/Illuminate/Pagination/resources/views/simple-default.blade.php index 36bdbc18c655..bdf2fe883cb2 100644 --- a/src/Illuminate/Pagination/resources/views/simple-default.blade.php +++ b/src/Illuminate/Pagination/resources/views/simple-default.blade.php @@ -1,19 +1,17 @@ @if ($paginator->hasPages()) - + {{-- Next Page Link --}} + @if ($paginator->hasMorePages()) +
  • + @else +
  • @lang('pagination.next')
  • + @endif + @endif From 9b5b6d54cf0b0360434b6a1ef5cfd1203d9b838b Mon Sep 17 00:00:00 2001 From: Quynh Xuan Nguyen Date: Mon, 18 Mar 2019 19:28:10 +0700 Subject: [PATCH 1633/2459] getNamespace is independent --- src/Illuminate/Foundation/Application.php | 4 ++-- tests/Foundation/FoundationApplicationTest.php | 9 +++++++++ tests/Foundation/fixtures/laravel1/composer.json | 7 +++++++ tests/Foundation/fixtures/laravel2/composer.json | 7 +++++++ 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 tests/Foundation/fixtures/laravel1/composer.json create mode 100644 tests/Foundation/fixtures/laravel2/composer.json diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index b61a20958fe1..5edaefd3ff06 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -1174,11 +1174,11 @@ public function getNamespace() return $this->namespace; } - $composer = json_decode(file_get_contents(base_path('composer.json')), true); + $composer = json_decode(file_get_contents($this->basePath('composer.json')), true); foreach ((array) data_get($composer, 'autoload.psr-4') as $namespace => $path) { foreach ((array) $path as $pathChoice) { - if (realpath(app_path()) == realpath(base_path().'/'.$pathChoice)) { + if (realpath($this->path()) === realpath($this->basePath($pathChoice))) { return $this->namespace = $namespace; } } diff --git a/tests/Foundation/FoundationApplicationTest.php b/tests/Foundation/FoundationApplicationTest.php index 3ad5ad8d8eb2..292214d7e409 100755 --- a/tests/Foundation/FoundationApplicationTest.php +++ b/tests/Foundation/FoundationApplicationTest.php @@ -309,6 +309,15 @@ public function testBootedCallbacks() $this->assertEquals(4, $counter); } + + public function testGetNamespace() + { + $app1 = new Application(realpath(__DIR__.'/fixtures/laravel1')); + $app2 = new Application(realpath(__DIR__.'/fixtures/laravel2')); + + $this->assertSame('Laravel\\One\\', $app1->getNamespace()); + $this->assertSame('Laravel\\Two\\', $app2->getNamespace()); + } } class ApplicationBasicServiceProviderStub extends ServiceProvider diff --git a/tests/Foundation/fixtures/laravel1/composer.json b/tests/Foundation/fixtures/laravel1/composer.json new file mode 100644 index 000000000000..a0ee8154c7b9 --- /dev/null +++ b/tests/Foundation/fixtures/laravel1/composer.json @@ -0,0 +1,7 @@ +{ + "autoload": { + "psr-4": { + "Laravel\\One\\": "app/" + } + } +} diff --git a/tests/Foundation/fixtures/laravel2/composer.json b/tests/Foundation/fixtures/laravel2/composer.json new file mode 100644 index 000000000000..81ef5ca3c3f4 --- /dev/null +++ b/tests/Foundation/fixtures/laravel2/composer.json @@ -0,0 +1,7 @@ +{ + "autoload": { + "psr-4": { + "Laravel\\Two\\": "app/" + } + } +} From be3c8ba92f197aefda39fe7d276bc7090c400bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vencel=20K=C3=A1tai?= Date: Tue, 19 Mar 2019 15:02:27 +0100 Subject: [PATCH 1634/2459] Fixing previous url --- src/Illuminate/Session/Middleware/StartSession.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index 49f02f27520a..b6f1cef6ae3b 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -53,12 +53,12 @@ public function handle($request, Closure $next) $this->collectGarbage($session); - $this->storeCurrentUrl($request, $session); - $this->addCookieToResponse( $response = $next($request), $session ); + $this->storeCurrentUrl($request, $session); + // Again, if the session has been configured we will need to close out the session // so that the attributes may be persisted to some storage medium. We will also // add the session identifier cookie to the application response headers now. From da4d4a468eee174bd619b4a04aab57e419d10ff4 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 19 Mar 2019 07:14:53 -0700 Subject: [PATCH 1635/2459] remove commas from values --- src/Illuminate/Validation/Rules/Unique.php | 8 ++++---- tests/Validation/ValidationUniqueRuleTest.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Validation/Rules/Unique.php b/src/Illuminate/Validation/Rules/Unique.php index bce18d8d0871..425d690b7bf3 100644 --- a/src/Illuminate/Validation/Rules/Unique.php +++ b/src/Illuminate/Validation/Rules/Unique.php @@ -35,8 +35,8 @@ public function ignore($id, $idColumn = null) return $this->ignoreModel($id, $idColumn); } - $this->ignore = $id; - $this->idColumn = $idColumn ?? 'id'; + $this->ignore = str_replace(',', '', $id); + $this->idColumn = str_replace(',', '', $idColumn ?? 'id'); return $this; } @@ -50,8 +50,8 @@ public function ignore($id, $idColumn = null) */ public function ignoreModel($model, $idColumn = null) { - $this->idColumn = $idColumn ?? $model->getKeyName(); - $this->ignore = $model->{$this->idColumn}; + $this->idColumn = str_replace(',', '', $idColumn ?? $model->getKeyName()); + $this->ignore = str_replace(',', '', $model->{$this->idColumn}); return $this; } diff --git a/tests/Validation/ValidationUniqueRuleTest.php b/tests/Validation/ValidationUniqueRuleTest.php index d6b64b727d4f..d955e189a7cf 100644 --- a/tests/Validation/ValidationUniqueRuleTest.php +++ b/tests/Validation/ValidationUniqueRuleTest.php @@ -17,7 +17,7 @@ public function testItCorrectlyFormatsAStringVersionOfTheRule() $rule = new Unique('table', 'column'); $rule->ignore('Taylor, Otwell', 'id_column'); $rule->where('foo', 'bar'); - $this->assertEquals('unique:table,column,"Taylor, Otwell",id_column,foo,bar', (string) $rule); + $this->assertEquals('unique:table,column,"Taylor Otwell",id_column,foo,bar', (string) $rule); $rule = new Unique('table', 'column'); $rule->ignore(null, 'id_column'); From 644bdfaa3a4ed5d6f704aad7796dcb273cc161fb Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 19 Mar 2019 07:17:16 -0700 Subject: [PATCH 1636/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 5edaefd3ff06..5ad487fe24a4 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.8.4'; + const VERSION = '5.8.5'; /** * The base path for the Laravel installation. From 791992e20efdf043ac3c2d989025d48d648821de Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 19 Mar 2019 07:20:36 -0700 Subject: [PATCH 1637/2459] formatting --- src/Illuminate/Session/Middleware/StartSession.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Session/Middleware/StartSession.php b/src/Illuminate/Session/Middleware/StartSession.php index b6f1cef6ae3b..dc44e9468f3b 100644 --- a/src/Illuminate/Session/Middleware/StartSession.php +++ b/src/Illuminate/Session/Middleware/StartSession.php @@ -53,12 +53,12 @@ public function handle($request, Closure $next) $this->collectGarbage($session); - $this->addCookieToResponse( - $response = $next($request), $session - ); + $response = $next($request); $this->storeCurrentUrl($request, $session); + $this->addCookieToResponse($response, $session); + // Again, if the session has been configured we will need to close out the session // so that the attributes may be persisted to some storage medium. We will also // add the session identifier cookie to the application response headers now. From 811434cc1943a23b7ab5f55df093af98d77137d0 Mon Sep 17 00:00:00 2001 From: Xiaohui Lam Date: Tue, 19 Mar 2019 23:34:40 +0800 Subject: [PATCH 1638/2459] view function actually supports `Arrayable` type --- src/Illuminate/Foundation/helpers.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 45f29d11e4c6..0dc0a6dbcd5c 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -951,9 +951,9 @@ function validator(array $data = [], array $rules = [], array $messages = [], ar /** * Get the evaluated view contents for the given view. * - * @param string $view - * @param array $data - * @param array $mergeData + * @param string $view + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory */ function view($view = null, $data = [], $mergeData = []) From ccafde5a9330acc87f72d8bc79d10cfa3a958f04 Mon Sep 17 00:00:00 2001 From: Xiaohui Lam Date: Tue, 19 Mar 2019 23:53:38 +0800 Subject: [PATCH 1639/2459] Revert 1st/3rd param to original doc --- src/Illuminate/Foundation/helpers.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 0dc0a6dbcd5c..9816a91fda2c 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -951,9 +951,9 @@ function validator(array $data = [], array $rules = [], array $messages = [], ar /** * Get the evaluated view contents for the given view. * - * @param string $view - * @param \Illuminate\Contracts\Support\Arrayable|array $data - * @param array $mergeData + * @param string $view + * @param \Illuminate\Contracts\Support\Arrayable|array $data + * @param array $mergeData * @return \Illuminate\View\View|\Illuminate\Contracts\View\Factory */ function view($view = null, $data = [], $mergeData = []) From 5015a79f4e27ed80623c7d7919ed49250f67932e Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 19 Mar 2019 21:47:15 +0200 Subject: [PATCH 1640/2459] strip slashes for unique rule helper --- .../Validation/Concerns/ValidatesAttributes.php | 2 ++ src/Illuminate/Validation/Rules/Unique.php | 8 ++++---- tests/Validation/ValidationUniqueRuleTest.php | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 47edb440d714..b186f95541fc 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -711,6 +711,8 @@ public function validateUnique($attribute, $value, $parameters) if (isset($parameters[2])) { [$idColumn, $id] = $this->getUniqueIds($parameters); + + $id = stripslashes($id); } // The presence verifier is responsible for counting rows within this store diff --git a/src/Illuminate/Validation/Rules/Unique.php b/src/Illuminate/Validation/Rules/Unique.php index 425d690b7bf3..0c210d31bf7f 100644 --- a/src/Illuminate/Validation/Rules/Unique.php +++ b/src/Illuminate/Validation/Rules/Unique.php @@ -35,8 +35,8 @@ public function ignore($id, $idColumn = null) return $this->ignoreModel($id, $idColumn); } - $this->ignore = str_replace(',', '', $id); - $this->idColumn = str_replace(',', '', $idColumn ?? 'id'); + $this->ignore = addslashes($id); + $this->idColumn = $idColumn ?? 'id'; return $this; } @@ -50,8 +50,8 @@ public function ignore($id, $idColumn = null) */ public function ignoreModel($model, $idColumn = null) { - $this->idColumn = str_replace(',', '', $idColumn ?? $model->getKeyName()); - $this->ignore = str_replace(',', '', $model->{$this->idColumn}); + $this->idColumn = addslashes($idColumn ?? $model->getKeyName()); + $this->ignore = $model->{$this->idColumn}; return $this; } diff --git a/tests/Validation/ValidationUniqueRuleTest.php b/tests/Validation/ValidationUniqueRuleTest.php index d955e189a7cf..d6b64b727d4f 100644 --- a/tests/Validation/ValidationUniqueRuleTest.php +++ b/tests/Validation/ValidationUniqueRuleTest.php @@ -17,7 +17,7 @@ public function testItCorrectlyFormatsAStringVersionOfTheRule() $rule = new Unique('table', 'column'); $rule->ignore('Taylor, Otwell', 'id_column'); $rule->where('foo', 'bar'); - $this->assertEquals('unique:table,column,"Taylor Otwell",id_column,foo,bar', (string) $rule); + $this->assertEquals('unique:table,column,"Taylor, Otwell",id_column,foo,bar', (string) $rule); $rule = new Unique('table', 'column'); $rule->ignore(null, 'id_column'); From 5a0c4fe75ebf273e488bf65a6b0d528d86c88542 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Mar 2019 21:47:40 +0200 Subject: [PATCH 1641/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 157644772c79..e21e44ad8c24 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -1,21 +1,26 @@ # Release Notes for 5.8.x -## [Unreleased](https://github.com/laravel/framework/compare/v5.8.4...5.8) +## [Unreleased](https://github.com/laravel/framework/compare/v5.8.5...5.8) + + +## [v5.8.5 (2019-03-19)](https://github.com/laravel/framework/compare/v5.8.4...v5.8.5) ### Added - Added `Illuminate\Database\DatabaseManager::setReconnector()` ([#27845](https://github.com/laravel/framework/pull/27845)) - Added `Illuminate\Auth\Access\Gate::none()` ([#27859](https://github.com/laravel/framework/pull/27859)) - Added `OtherDeviceLogout` event ([#27865](https://github.com/laravel/framework/pull/27865), [5e87f2d](https://github.com/laravel/framework/commit/5e87f2df072ec4a243b6a3a983a753e8ffa5e6bf)) +- Added `even` and `odd` flags to the `Loop` variable in the `blade` ([#27883](https://github.com/laravel/framework/pull/27883)) ### Changed - Add replacement for lower danish `æ` ([#27886](https://github.com/laravel/framework/pull/27886)) +- Show error message from exception, if message exist for `403.blade.php` and `503.blade.php` error ([#27893](https://github.com/laravel/framework/pull/27893), [#27902](https://github.com/laravel/framework/pull/27902)) +- Changed `Validation\Rules\Unique.php` ([da4d4a4](https://github.com/laravel/framework/commit/da4d4a468eee174bd619b4a04aab57e419d10ff4)) ### Fixed - Fixed seeding logic in `Arr::shuffle()` ([#27861](https://github.com/laravel/framework/pull/27861)) - -### TODO: -- https://github.com/laravel/framework/pull/27883 -- https://github.com/laravel/framework/pull/27893, https://github.com/laravel/framework/pull/27902 +- Fixed `Illuminate\Database\Query\Builder::updateOrInsert()` with empty `$values` ([#27906](https://github.com/laravel/framework/pull/27906)) +- Fixed `Application::getNamespace()` method ([#27915](https://github.com/laravel/framework/pull/27915)) +- Fixed of store previous url ([#27935](https://github.com/laravel/framework/pull/27935), [791992e](https://github.com/laravel/framework/commit/791992e20efdf043ac3c2d989025d48d648821de)) ## [v5.8.4 (2019-03-12)](https://github.com/laravel/framework/compare/v5.8.3...v5.8.4) From 2c128289db85782446e11a1a2f40c22015572b43 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 19 Mar 2019 22:02:38 +0200 Subject: [PATCH 1642/2459] [5.8] Update changelog --- CHANGELOG-5.8.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index e21e44ad8c24..13d0bba0f869 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -14,7 +14,6 @@ ### Changed - Add replacement for lower danish `æ` ([#27886](https://github.com/laravel/framework/pull/27886)) - Show error message from exception, if message exist for `403.blade.php` and `503.blade.php` error ([#27893](https://github.com/laravel/framework/pull/27893), [#27902](https://github.com/laravel/framework/pull/27902)) -- Changed `Validation\Rules\Unique.php` ([da4d4a4](https://github.com/laravel/framework/commit/da4d4a468eee174bd619b4a04aab57e419d10ff4)) ### Fixed - Fixed seeding logic in `Arr::shuffle()` ([#27861](https://github.com/laravel/framework/pull/27861)) @@ -22,6 +21,9 @@ - Fixed `Application::getNamespace()` method ([#27915](https://github.com/laravel/framework/pull/27915)) - Fixed of store previous url ([#27935](https://github.com/laravel/framework/pull/27935), [791992e](https://github.com/laravel/framework/commit/791992e20efdf043ac3c2d989025d48d648821de)) +### Security +- Changed `Validation\Rules\Unique.php` ([da4d4a4](https://github.com/laravel/framework/commit/da4d4a468eee174bd619b4a04aab57e419d10ff4)). You can read more [here](https://blog.laravel.com/unique-rule-sql-injection-warning) + ## [v5.8.4 (2019-03-12)](https://github.com/laravel/framework/compare/v5.8.3...v5.8.4) From 34759cc0e0e63c952d7f8b7580f48144a063c684 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 19 Mar 2019 21:37:05 -0700 Subject: [PATCH 1643/2459] formatting' --- src/Illuminate/Validation/Rules/Unique.php | 6 +++--- tests/Validation/ValidationUniqueRuleTest.php | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Validation/Rules/Unique.php b/src/Illuminate/Validation/Rules/Unique.php index 0c210d31bf7f..64e910240382 100644 --- a/src/Illuminate/Validation/Rules/Unique.php +++ b/src/Illuminate/Validation/Rules/Unique.php @@ -35,7 +35,7 @@ public function ignore($id, $idColumn = null) return $this->ignoreModel($id, $idColumn); } - $this->ignore = addslashes($id); + $this->ignore = $id; $this->idColumn = $idColumn ?? 'id'; return $this; @@ -50,7 +50,7 @@ public function ignore($id, $idColumn = null) */ public function ignoreModel($model, $idColumn = null) { - $this->idColumn = addslashes($idColumn ?? $model->getKeyName()); + $this->idColumn = $idColumn ?? $model->getKeyName(); $this->ignore = $model->{$this->idColumn}; return $this; @@ -66,7 +66,7 @@ public function __toString() return rtrim(sprintf('unique:%s,%s,%s,%s,%s', $this->table, $this->column, - $this->ignore ? '"'.$this->ignore.'"' : 'NULL', + $this->ignore ? '"'.addslashes($this->ignore).'"' : 'NULL', $this->idColumn, $this->formatWheres() ), ','); diff --git a/tests/Validation/ValidationUniqueRuleTest.php b/tests/Validation/ValidationUniqueRuleTest.php index d6b64b727d4f..ebf15d2d048f 100644 --- a/tests/Validation/ValidationUniqueRuleTest.php +++ b/tests/Validation/ValidationUniqueRuleTest.php @@ -19,6 +19,13 @@ public function testItCorrectlyFormatsAStringVersionOfTheRule() $rule->where('foo', 'bar'); $this->assertEquals('unique:table,column,"Taylor, Otwell",id_column,foo,bar', (string) $rule); + $rule = new Unique('table', 'column'); + $rule->ignore('Taylor, Otwell"\'..-"', 'id_column'); + $rule->where('foo', 'bar'); + $this->assertEquals('unique:table,column,"Taylor, Otwell\"\\\'..-\"",id_column,foo,bar', (string) $rule); + $this->assertEquals('Taylor, Otwell"\'..-"', stripslashes(str_getcsv('table,column,"Taylor, Otwell\"\\\'..-\"",id_column,foo,bar')[2])); + $this->assertEquals('id_column', stripslashes(str_getcsv('table,column,"Taylor, Otwell\"\\\'..-\"",id_column,foo,bar')[3])); + $rule = new Unique('table', 'column'); $rule->ignore(null, 'id_column'); $rule->where('foo', 'bar'); From 7a7cacc3fd02d7d4c596c1a0f8af3c5b7a2990b4 Mon Sep 17 00:00:00 2001 From: Richard Keep Date: Thu, 21 Mar 2019 16:25:20 +0300 Subject: [PATCH 1644/2459] Use Null coalescing operator to refactor --- src/Illuminate/Http/Concerns/InteractsWithInput.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Http/Concerns/InteractsWithInput.php b/src/Illuminate/Http/Concerns/InteractsWithInput.php index b1e9b830ba37..61995d26f3ec 100644 --- a/src/Illuminate/Http/Concerns/InteractsWithInput.php +++ b/src/Illuminate/Http/Concerns/InteractsWithInput.php @@ -309,9 +309,7 @@ public function allFiles() { $files = $this->files->all(); - return $this->convertedFiles - ? $this->convertedFiles - : $this->convertedFiles = $this->convertUploadedFiles($files); + return $this->convertedFiles = $this->convertedFiles ?? $this->convertUploadedFiles($files); } /** From 7d58526aa403a398d7122670fabe2b7bd0dfbadd Mon Sep 17 00:00:00 2001 From: Dan Howe Date: Thu, 21 Mar 2019 23:33:23 +1000 Subject: [PATCH 1645/2459] Align the releasing behavior of block() with that of get(). Previously if the callback passed to block() threw an exception, the lock would only be released when it expired. Add integration test. --- src/Illuminate/Cache/Lock.php | 6 ++++-- tests/Integration/Cache/RedisCacheLockTest.php | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index 9a85d99faf58..37b2a7bd3390 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -115,9 +115,11 @@ public function block($seconds, $callback = null) } if (is_callable($callback)) { - return tap($callback(), function () { + try { + return $callback(); + } finally { $this->release(); - }); + } } return true; diff --git a/tests/Integration/Cache/RedisCacheLockTest.php b/tests/Integration/Cache/RedisCacheLockTest.php index 546234be76db..1e3aa22e00ec 100644 --- a/tests/Integration/Cache/RedisCacheLockTest.php +++ b/tests/Integration/Cache/RedisCacheLockTest.php @@ -72,6 +72,24 @@ public function test_concurrent_redis_locks_are_released_safely() $this->assertFalse(Cache::store('redis')->lock('foo')->get()); } + public function test_redis_locks_with_failed_block_callback_are_released() + { + Cache::store('redis')->lock('foo')->forceRelease(); + + $firstLock = Cache::store('redis')->lock('foo', 10); + try { + $firstLock->block(1, function () { + throw new \Exception("failed"); + }); + } catch (\Exception $e) { + // Not testing the exception, just testing the lock + // is released regardless of the how the exception + // thrown by the callback was handled. + } + $secondLock = Cache::store('redis')->lock('foo', 1); + $this->assertTrue($secondLock->get()); + } + public function test_redis_locks_can_be_released_using_owner_token() { Cache::store('redis')->lock('foo')->forceRelease(); From bb0d17957af2b63118a39b8b2361501003b57c23 Mon Sep 17 00:00:00 2001 From: Dan Howe Date: Fri, 22 Mar 2019 00:09:27 +1000 Subject: [PATCH 1646/2459] Fix styling. --- tests/Integration/Cache/RedisCacheLockTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/Cache/RedisCacheLockTest.php b/tests/Integration/Cache/RedisCacheLockTest.php index 1e3aa22e00ec..2bd08318d59a 100644 --- a/tests/Integration/Cache/RedisCacheLockTest.php +++ b/tests/Integration/Cache/RedisCacheLockTest.php @@ -79,7 +79,7 @@ public function test_redis_locks_with_failed_block_callback_are_released() $firstLock = Cache::store('redis')->lock('foo', 10); try { $firstLock->block(1, function () { - throw new \Exception("failed"); + throw new \Exception('failed'); }); } catch (\Exception $e) { // Not testing the exception, just testing the lock From 5e63a8987416f543748c42d8159968da08956ab5 Mon Sep 17 00:00:00 2001 From: Dan Howe Date: Fri, 22 Mar 2019 00:34:03 +1000 Subject: [PATCH 1647/2459] Style cleanup for readability. --- tests/Integration/Cache/RedisCacheLockTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Integration/Cache/RedisCacheLockTest.php b/tests/Integration/Cache/RedisCacheLockTest.php index 2bd08318d59a..2ea9651e0eb2 100644 --- a/tests/Integration/Cache/RedisCacheLockTest.php +++ b/tests/Integration/Cache/RedisCacheLockTest.php @@ -77,6 +77,7 @@ public function test_redis_locks_with_failed_block_callback_are_released() Cache::store('redis')->lock('foo')->forceRelease(); $firstLock = Cache::store('redis')->lock('foo', 10); + try { $firstLock->block(1, function () { throw new \Exception('failed'); @@ -86,7 +87,9 @@ public function test_redis_locks_with_failed_block_callback_are_released() // is released regardless of the how the exception // thrown by the callback was handled. } + $secondLock = Cache::store('redis')->lock('foo', 1); + $this->assertTrue($secondLock->get()); } From 2edeb3ac8d840d26948df7f1a4362d11f0fb11a2 Mon Sep 17 00:00:00 2001 From: Dan Howe Date: Fri, 22 Mar 2019 00:34:37 +1000 Subject: [PATCH 1648/2459] Add use Exception. --- tests/Integration/Cache/RedisCacheLockTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Cache/RedisCacheLockTest.php b/tests/Integration/Cache/RedisCacheLockTest.php index 2ea9651e0eb2..a44e51d42e8b 100644 --- a/tests/Integration/Cache/RedisCacheLockTest.php +++ b/tests/Integration/Cache/RedisCacheLockTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Integration\Cache; +use Exception; use Illuminate\Support\Carbon; use Orchestra\Testbench\TestCase; use Illuminate\Support\Facades\Cache; @@ -80,9 +81,9 @@ public function test_redis_locks_with_failed_block_callback_are_released() try { $firstLock->block(1, function () { - throw new \Exception('failed'); + throw new Exception('failed'); }); - } catch (\Exception $e) { + } catch (Exception $e) { // Not testing the exception, just testing the lock // is released regardless of the how the exception // thrown by the callback was handled. From c37702cbdedd4e06eba2162d7a1be7d74362e0cf Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 21 Mar 2019 09:31:52 -0700 Subject: [PATCH 1649/2459] add put env adapter --- .../Foundation/Bootstrap/LoadEnvironmentVariables.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php b/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php index cdea6f9aabad..b39bbf83e8d6 100644 --- a/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php +++ b/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php @@ -5,6 +5,7 @@ use Dotenv\Dotenv; use Dotenv\Environment\DotenvFactory; use Dotenv\Exception\InvalidFileException; +use Dotenv\Environment\Adapter\PutenvAdapter; use Symfony\Component\Console\Input\ArgvInput; use Dotenv\Environment\Adapter\EnvConstAdapter; use Illuminate\Contracts\Foundation\Application; @@ -88,7 +89,7 @@ protected function createDotenv($app) return Dotenv::create( $app->environmentPath(), $app->environmentFile(), - new DotenvFactory([new EnvConstAdapter, new ServerConstAdapter]) + new DotenvFactory([new EnvConstAdapter, new ServerConstAdapter, new PutenvAdapter]) ); } From 03e73f82ac951d863c2a6bfc5fabef0064296cda Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 21 Mar 2019 09:32:21 -0700 Subject: [PATCH 1650/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 5ad487fe24a4..09432c3984e1 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.8.5'; + const VERSION = '5.8.6'; /** * The base path for the Laravel installation. From b82fd704d987e91c11d1a44228ab699e82b9413e Mon Sep 17 00:00:00 2001 From: Matt Allan Date: Thu, 21 Mar 2019 12:11:18 -0400 Subject: [PATCH 1651/2459] Test env variables are loaded into $_ENV, $_SERVER, and getenv --- tests/Foundation/Bootstrap/LoadEnvironmentVariablesTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/Foundation/Bootstrap/LoadEnvironmentVariablesTest.php b/tests/Foundation/Bootstrap/LoadEnvironmentVariablesTest.php index da65d1000fbb..bbc21270f6de 100644 --- a/tests/Foundation/Bootstrap/LoadEnvironmentVariablesTest.php +++ b/tests/Foundation/Bootstrap/LoadEnvironmentVariablesTest.php @@ -37,6 +37,9 @@ public function testCanLoad() (new LoadEnvironmentVariables)->bootstrap($this->getAppMock('.env')); $this->assertSame('BAR', env('FOO')); + $this->assertSame('BAR', getenv('FOO')); + $this->assertSame('BAR', $_ENV['FOO']); + $this->assertSame('BAR', $_SERVER['FOO']); } public function testCanFailSilent() From be22b61865f013adab4c70db64a537f29cd2cb4d Mon Sep 17 00:00:00 2001 From: Matt Allan Date: Thu, 21 Mar 2019 12:24:10 -0400 Subject: [PATCH 1652/2459] Allow retrieving env variables with getenv from env helper function --- src/Illuminate/Support/helpers.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index d3312cfc73e9..4cea4963bed1 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -8,6 +8,7 @@ use Dotenv\Environment\DotenvFactory; use Illuminate\Contracts\Support\Htmlable; use Illuminate\Support\HigherOrderTapProxy; +use Dotenv\Environment\Adapter\PutenvAdapter; use Dotenv\Environment\Adapter\EnvConstAdapter; use Dotenv\Environment\Adapter\ServerConstAdapter; @@ -642,7 +643,7 @@ function env($key, $default = null) static $variables; if ($variables === null) { - $variables = (new DotenvFactory([new EnvConstAdapter, new ServerConstAdapter]))->createImmutable(); + $variables = (new DotenvFactory([new EnvConstAdapter, new PutEnvAdapter, new ServerConstAdapter]))->createImmutable(); } return Option::fromValue($variables->get($key)) From f12c7baf9ceee80b131e06a01d3221d9a2488670 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 21 Mar 2019 09:54:38 -0700 Subject: [PATCH 1653/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 09432c3984e1..0d02218cc40f 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.8.6'; + const VERSION = '5.8.7'; /** * The base path for the Laravel installation. From 30a61e74f7a42434c18a727bf8ae35980e893d81 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Fri, 22 Mar 2019 00:22:59 +0200 Subject: [PATCH 1654/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 13d0bba0f869..ae70a4b76fab 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -1,6 +1,19 @@ # Release Notes for 5.8.x -## [Unreleased](https://github.com/laravel/framework/compare/v5.8.5...5.8) +## [Unreleased](https://github.com/laravel/framework/compare/v5.8.7...5.8) + + +## [v5.8.6-v5.8.7 (2019-03-21)](https://github.com/laravel/framework/compare/v5.8.5...v5.8.7) + +### Fixed +- Fix: Locks acquired with block() are not immediately released if the callback fails ([#27957](https://github.com/laravel/framework/pull/27957)) + +### Changed +- Allowed retrieving `env` variables with `getenv()` ([#27958](https://github.com/laravel/framework/pull/27958), [c37702c](https://github.com/laravel/framework/commit/c37702cbdedd4e06eba2162d7a1be7d74362e0cf)) +- Used `stripslashes` for `Validation\Rules\Unique.php` ([#27940](https://github.com/laravel/framework/pull/27940), [34759cc](https://github.com/laravel/framework/commit/34759cc0e0e63c952d7f8b7580f48144a063c684)) + +### Refactoring +- Refactoring of `Illuminate\Http\Concerns::allFiles()` ([#27955](https://github.com/laravel/framework/pull/27955)) ## [v5.8.5 (2019-03-19)](https://github.com/laravel/framework/compare/v5.8.4...v5.8.5) From beb61000b4db9d19eae056acd660011cea789fc2 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Fri, 22 Mar 2019 01:31:28 +0200 Subject: [PATCH 1655/2459] [5.8] Change `PutEnvAdapter` to `PutenvAdapter` - change `PutEnvAdapter` to `PutenvAdapter` since the class is a `PutenvAdapter` --- src/Illuminate/Support/helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/helpers.php b/src/Illuminate/Support/helpers.php index 4cea4963bed1..1c95f63245a1 100755 --- a/src/Illuminate/Support/helpers.php +++ b/src/Illuminate/Support/helpers.php @@ -643,7 +643,7 @@ function env($key, $default = null) static $variables; if ($variables === null) { - $variables = (new DotenvFactory([new EnvConstAdapter, new PutEnvAdapter, new ServerConstAdapter]))->createImmutable(); + $variables = (new DotenvFactory([new EnvConstAdapter, new PutenvAdapter, new ServerConstAdapter]))->createImmutable(); } return Option::fromValue($variables->get($key)) From 7faec5b75618940ea3309bd3dbc03e17112cbd34 Mon Sep 17 00:00:00 2001 From: mammut Date: Fri, 22 Mar 2019 11:37:02 +0200 Subject: [PATCH 1656/2459] Correct Str tests --- tests/Support/SupportStrTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 9860979ca49c..e8812079d25a 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -191,6 +191,9 @@ public function testIs() $this->assertTrue(Str::is('foo/bar/baz', $valueObject)); $this->assertTrue(Str::is($patternObject, $valueObject)); + + //empty patterns + $this->assertFalse(Str::is([], 'test')); } public function testKebab() @@ -228,6 +231,7 @@ public function testLimit() public function testLength() { $this->assertEquals(11, Str::length('foo bar baz')); + $this->assertEquals(11, Str::length('foo bar baz', 'UTF-8')); } public function testRandom() From 4c602efed68afda401b8678b3c07ffaaade342aa Mon Sep 17 00:00:00 2001 From: Olga Strizhenko Date: Fri, 22 Mar 2019 15:21:26 +0100 Subject: [PATCH 1657/2459] [5.8] don't add the path if it's null or empty --- .../View/Compilers/BladeCompiler.php | 7 ++++--- tests/View/ViewBladeCompilerTest.php | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 08bb14b7fb31..645795ccb623 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -118,9 +118,10 @@ public function compile($path = null) } if (! is_null($this->cachePath)) { - $contents = $this->compileString($this->files->get($this->getPath())). - "\ngetPath()} */ ?>"; - + $contents = $this->compileString($this->files->get($this->getPath())); + if (! empty($this->getPath())) { + $contents .= "\ngetPath()} */ ?>"; + } $this->files->put($this->getCompiledPath($this->getPath()), $contents); } } diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index 9e32b7d21400..bea15f627ae9 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -101,6 +101,24 @@ public function testIncludePathToTemplate() $compiler->compile('foo'); } + public function testDontIncludeEmptyPath() + { + $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); + $files->shouldReceive('get')->once()->with('')->andReturn('Hello World'); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('').'.php', "Hello World"); + $compiler->setPath(""); + $compiler->compile(); + } + + public function testDontIncludeNullPath() + { + $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); + $files->shouldReceive('get')->once()->with(null)->andReturn('Hello World'); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1(null).'.php', "Hello World"); + $compiler->setPath(null); + $compiler->compile(); + } + public function testShouldStartFromStrictTypesDeclaration() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); From f17c34a75fd02c2aa0f29abe135d45d4b2832a10 Mon Sep 17 00:00:00 2001 From: Olga Strizhenko Date: Fri, 22 Mar 2019 15:34:04 +0100 Subject: [PATCH 1658/2459] [5.8] don't add the path if it's null or empty + fix code style issues --- tests/View/ViewBladeCompilerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index bea15f627ae9..67720dcc5cf1 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -105,8 +105,8 @@ public function testDontIncludeEmptyPath() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('').'.php', "Hello World"); - $compiler->setPath(""); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('').'.php', 'Hello World'); + $compiler->setPath(''); $compiler->compile(); } @@ -114,7 +114,7 @@ public function testDontIncludeNullPath() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with(null)->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1(null).'.php', "Hello World"); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1(null).'.php', 'Hello World'); $compiler->setPath(null); $compiler->compile(); } From 883e07a6128d7e79b93e5c51a90368ba9c27cbac Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 22 Mar 2019 16:11:26 +0100 Subject: [PATCH 1659/2459] Styling --- src/Illuminate/View/Compilers/BladeCompiler.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 645795ccb623..0f084b06ffec 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -118,11 +118,17 @@ public function compile($path = null) } if (! is_null($this->cachePath)) { - $contents = $this->compileString($this->files->get($this->getPath())); + $contents = $this->compileString( + $this->files->get($this->getPath()) + ); + if (! empty($this->getPath())) { $contents .= "\ngetPath()} */ ?>"; } - $this->files->put($this->getCompiledPath($this->getPath()), $contents); + + $this->files->put( + $this->getCompiledPath($this->getPath()), $contents + ); } } From 09688074dc2dd611cbf494c1dad0d336453ee0f8 Mon Sep 17 00:00:00 2001 From: Mohammad Mahdi Sadegh-Zadeh <44808170+owlpro@users.noreply.github.com> Date: Sat, 23 Mar 2019 19:25:18 +0430 Subject: [PATCH 1660/2459] Update Schema.php add Doc for disableForeignKeyConstraints & enableForeignKeyConstraints --- src/Illuminate/Support/Facades/Schema.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index 31748e15029b..12809a4362de 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -8,6 +8,8 @@ * @method static \Illuminate\Database\Schema\Builder dropIfExists(string $table) * @method static \Illuminate\Database\Schema\Builder table(string $table, \Closure $callback) * @method static void defaultStringLength(int $length) + * @method static \Illuminate\Database\Schema\Builder disableForeignKeyConstraints() + * @method static \Illuminate\Database\Schema\Builder enableForeignKeyConstraints() * * @see \Illuminate\Database\Schema\Builder */ From 4eab5feeff77e46fa95780a928f42619e018da45 Mon Sep 17 00:00:00 2001 From: Oliver Matla Date: Sat, 23 Mar 2019 16:45:21 +0100 Subject: [PATCH 1661/2459] [Fix] (View) fix return types of render() and renderSections(). --- src/Illuminate/View/View.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/View/View.php b/src/Illuminate/View/View.php index b888860e1c5e..be00482d5343 100755 --- a/src/Illuminate/View/View.php +++ b/src/Illuminate/View/View.php @@ -80,7 +80,7 @@ public function __construct(Factory $factory, Engine $engine, $view, $path, $dat * Get the string contents of the view. * * @param callable|null $callback - * @return string + * @return array|string * * @throws \Throwable */ @@ -163,7 +163,7 @@ protected function gatherData() /** * Get the sections of the rendered view. * - * @return string + * @return array * * @throws \Throwable */ From 93abbf579b18b28b70ba18db7468c1dc500b60da Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Sat, 23 Mar 2019 21:46:35 +0100 Subject: [PATCH 1662/2459] Fix unique validation without ignored column --- src/Illuminate/Validation/Concerns/ValidatesAttributes.php | 4 +++- tests/Validation/ValidationValidatorTest.php | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index b186f95541fc..28371530e633 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -712,7 +712,9 @@ public function validateUnique($attribute, $value, $parameters) if (isset($parameters[2])) { [$idColumn, $id] = $this->getUniqueIds($parameters); - $id = stripslashes($id); + if (! is_null($id)) { + $id = stripslashes($id); + } } // The presence verifier is responsible for counting rows within this store diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 68a23607b0f5..bea82017deaf 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1889,7 +1889,9 @@ public function testValidateUnique() $v = new Validator($trans, ['email' => 'foo'], ['email' => 'Unique:users,email_addr,NULL,id_col,foo,bar']); $mock = m::mock(PresenceVerifierInterface::class); $mock->shouldReceive('setConnection')->once()->with(null); - $mock->shouldReceive('getCount')->once()->with('users', 'email_addr', 'foo', null, 'id_col', ['foo' => 'bar'])->andReturn(2); + $mock->shouldReceive('getCount')->once()->withArgs(function () { + return func_get_args() === ['users', 'email_addr', 'foo', null, 'id_col', ['foo' => 'bar']]; + })->andReturn(2); $v->setPresenceVerifier($mock); $this->assertFalse($v->passes()); } From 647352040fd914406b7a56bce36d7eec1480cad6 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 25 Mar 2019 00:30:53 +0200 Subject: [PATCH 1663/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index ae70a4b76fab..b77923dca764 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -2,6 +2,13 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v5.8.7...5.8) +### Refactoring +- Refactoring of `env()` helper ([#27965](https://github.com/laravel/framework/pull/27965)) + +### TODO +- https://github.com/laravel/framework/pull/27976 +- https://github.com/laravel/framework/pull/27987 + ## [v5.8.6-v5.8.7 (2019-03-21)](https://github.com/laravel/framework/compare/v5.8.5...v5.8.7) From 2efbb5b7ec17d28b72b2a6b21fa07a71cf81ee75 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 25 Mar 2019 02:15:04 +0100 Subject: [PATCH 1664/2459] Fix BelongsToMany::detach() with custom pivot class --- .../Eloquent/Relations/Concerns/InteractsWithPivotTable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php index eec606ec2706..c8b3ae2c15ca 100644 --- a/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php +++ b/src/Illuminate/Database/Eloquent/Relations/Concerns/InteractsWithPivotTable.php @@ -403,7 +403,7 @@ protected function hasPivotColumn($column) */ public function detach($ids = null, $touch = true) { - if ($this->using && ! empty($ids)) { + if ($this->using && ! empty($ids) && empty($this->pivotWheres) && empty($this->pivotWhereIns)) { $results = $this->detachUsingCustomClass($ids); } else { $query = $this->newPivotQuery(); From 64e0f8aea6fc3d20db3c15b9c02f205764f447e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20V=C4=83n=20Ti=E1=BA=BFn?= Date: Mon, 25 Mar 2019 09:53:12 +0700 Subject: [PATCH 1665/2459] [5.8] Fix some docblocks --- src/Illuminate/Http/RedirectResponse.php | 2 +- src/Illuminate/Notifications/NotificationSender.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Http/RedirectResponse.php b/src/Illuminate/Http/RedirectResponse.php index 228a1e69ce64..1a7ec144acd1 100755 --- a/src/Illuminate/Http/RedirectResponse.php +++ b/src/Illuminate/Http/RedirectResponse.php @@ -68,7 +68,7 @@ public function withCookies(array $cookies) /** * Flash an array of input to the session. * - * @param array $input + * @param array|null $input * @return $this */ public function withInput(array $input = null) diff --git a/src/Illuminate/Notifications/NotificationSender.php b/src/Illuminate/Notifications/NotificationSender.php index 0e1e8de40576..41cd5476f54d 100644 --- a/src/Illuminate/Notifications/NotificationSender.php +++ b/src/Illuminate/Notifications/NotificationSender.php @@ -82,7 +82,7 @@ public function send($notifiables, $notification) * * @param \Illuminate\Support\Collection|array|mixed $notifiables * @param mixed $notification - * @param array $channels + * @param array|null $channels * @return void */ public function sendNow($notifiables, $notification, array $channels = null) From 3eae3dd11f94405e41f992355ac16c5e1e61afb0 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 25 Mar 2019 09:55:55 +0200 Subject: [PATCH 1666/2459] Corrected test for support optional --- tests/Support/SupportOptionalTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/Support/SupportOptionalTest.php b/tests/Support/SupportOptionalTest.php index 343cc457a1f6..9f5560ab5d08 100644 --- a/tests/Support/SupportOptionalTest.php +++ b/tests/Support/SupportOptionalTest.php @@ -79,6 +79,7 @@ public function testIssetExistItemOnArray() $optional = new Optional($targetArr); $this->assertTrue(isset($optional['item'])); + $this->assertTrue(isset($optional->item)); } public function testIssetNotExistItemOnArray() @@ -88,5 +89,15 @@ public function testIssetNotExistItemOnArray() $optional = new Optional($targetArr); $this->assertFalse(isset($optional['item'])); + $this->assertFalse(isset($optional->item)); + } + + public function testIssetExistItemOnNull() + { + $targetNull = null; + + $optional = new Optional($targetNull); + + $this->assertFalse(isset($optional->item)); } } From 19f4a104587a60302e3bb9e4f4e5f48e02d39a73 Mon Sep 17 00:00:00 2001 From: Clayton Stone Date: Mon, 25 Mar 2019 13:23:16 -0500 Subject: [PATCH 1667/2459] Fix incorrect event namespace in generated listener. --- src/Illuminate/Foundation/Console/ListenerMakeCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/ListenerMakeCommand.php b/src/Illuminate/Foundation/Console/ListenerMakeCommand.php index c13bfbb92c71..7fed4e67597b 100644 --- a/src/Illuminate/Foundation/Console/ListenerMakeCommand.php +++ b/src/Illuminate/Foundation/Console/ListenerMakeCommand.php @@ -52,7 +52,7 @@ protected function buildClass($name) ); return str_replace( - 'DummyFullEvent', $event, $stub + 'DummyFullEvent', trim($event, '\\'), $stub ); } From b36316323d7ec30f4ed578883b686c73713b4b23 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Mon, 25 Mar 2019 23:15:15 +0200 Subject: [PATCH 1668/2459] [5.8] update type-hint for src/Illuminate/Support/Facades/Crypt.php - add encryptString - add decryptString fixed https://github.com/laravel/framework/issues/27999 --- src/Illuminate/Support/Facades/Crypt.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Support/Facades/Crypt.php b/src/Illuminate/Support/Facades/Crypt.php index 84317c372c6e..33da563652c9 100755 --- a/src/Illuminate/Support/Facades/Crypt.php +++ b/src/Illuminate/Support/Facades/Crypt.php @@ -3,8 +3,10 @@ namespace Illuminate\Support\Facades; /** - * @method static string encrypt(string $value, bool $serialize = true) - * @method static string decrypt(string $payload, bool $unserialize = true) + * @method static string encrypt($value, bool $serialize = true) + * @method static string encryptString(string $value) + * @method static string decrypt($payload, bool $unserialize = true) + * @method static string decryptString(string $payload) * * @see \Illuminate\Encryption\Encrypter */ From a5e1bd19b9ae5854a5444367a3e722343a932407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20V=C4=83n=20Ti=E1=BA=BFn?= Date: Tue, 26 Mar 2019 08:27:43 +0700 Subject: [PATCH 1669/2459] [5.8] Add missing null type hint docblock --- src/Illuminate/Auth/Access/Gate.php | 2 +- src/Illuminate/Database/Capsule/Manager.php | 2 +- src/Illuminate/Database/Query/Builder.php | 4 ++-- .../Foundation/Http/Exceptions/MaintenanceModeException.php | 6 +++--- src/Illuminate/Redis/Connections/PhpRedisConnection.php | 4 ++-- src/Illuminate/Routing/Router.php | 2 +- src/Illuminate/Validation/Factory.php | 2 +- src/Illuminate/View/FileViewFinder.php | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index b5e79be1958c..78946ea94ecf 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -80,7 +80,7 @@ class Gate implements GateContract * @param array $policies * @param array $beforeCallbacks * @param array $afterCallbacks - * @param callable $guessPolicyNamesUsingCallback + * @param callable|null $guessPolicyNamesUsingCallback * @return void */ public function __construct(Container $container, callable $userResolver, array $abilities = [], diff --git a/src/Illuminate/Database/Capsule/Manager.php b/src/Illuminate/Database/Capsule/Manager.php index b82a792ce7d2..f2525aaa6ac9 100755 --- a/src/Illuminate/Database/Capsule/Manager.php +++ b/src/Illuminate/Database/Capsule/Manager.php @@ -78,7 +78,7 @@ public static function connection($connection = null) * Get a fluent query builder instance. * * @param string $table - * @param string $connection + * @param string|null $connection * @return \Illuminate\Database\Query\Builder */ public static function table($table, $connection = null) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 59eb358e0556..f3cb56d19f4d 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -198,8 +198,8 @@ class Builder * Create a new query builder instance. * * @param \Illuminate\Database\ConnectionInterface $connection - * @param \Illuminate\Database\Query\Grammars\Grammar $grammar - * @param \Illuminate\Database\Query\Processors\Processor $processor + * @param \Illuminate\Database\Query\Grammars\Grammar|null $grammar + * @param \Illuminate\Database\Query\Processors\Processor|null $processor * @return void */ public function __construct(ConnectionInterface $connection, diff --git a/src/Illuminate/Foundation/Http/Exceptions/MaintenanceModeException.php b/src/Illuminate/Foundation/Http/Exceptions/MaintenanceModeException.php index d9df3452165e..45c76b2201b6 100644 --- a/src/Illuminate/Foundation/Http/Exceptions/MaintenanceModeException.php +++ b/src/Illuminate/Foundation/Http/Exceptions/MaintenanceModeException.php @@ -34,9 +34,9 @@ class MaintenanceModeException extends ServiceUnavailableHttpException * Create a new exception instance. * * @param int $time - * @param int $retryAfter - * @param string $message - * @param \Exception $previous + * @param int|null $retryAfter + * @param string|null $message + * @param \Exception|null $previous * @param int $code * @return void */ diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index a2f33793832d..ec12e1a40f69 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -292,7 +292,7 @@ public function zunionstore($output, $keys, $options = []) /** * Execute commands in a pipeline. * - * @param callable $callback + * @param callable|null $callback * @return \Redis|array */ public function pipeline(callable $callback = null) @@ -307,7 +307,7 @@ public function pipeline(callable $callback = null) /** * Execute commands in a transaction. * - * @param callable $callback + * @param callable|null $callback * @return \Redis|array */ public function transaction(callable $callback = null) diff --git a/src/Illuminate/Routing/Router.php b/src/Illuminate/Routing/Router.php index 5a7219a13b82..68648cf9c012 100644 --- a/src/Illuminate/Routing/Router.php +++ b/src/Illuminate/Routing/Router.php @@ -122,7 +122,7 @@ class Router implements RegistrarContract, BindingRegistrar * Create a new Router instance. * * @param \Illuminate\Contracts\Events\Dispatcher $events - * @param \Illuminate\Container\Container $container + * @param \Illuminate\Container\Container|null $container * @return void */ public function __construct(Dispatcher $events, Container $container = null) diff --git a/src/Illuminate/Validation/Factory.php b/src/Illuminate/Validation/Factory.php index 7660ea5cc681..4b9a01c3c53a 100755 --- a/src/Illuminate/Validation/Factory.php +++ b/src/Illuminate/Validation/Factory.php @@ -77,7 +77,7 @@ class Factory implements FactoryContract * Create a new Validator factory instance. * * @param \Illuminate\Contracts\Translation\Translator $translator - * @param \Illuminate\Contracts\Container\Container $container + * @param \Illuminate\Contracts\Container\Container|null $container * @return void */ public function __construct(Translator $translator, Container $container = null) diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index 9a80a586f75c..25e3adef7df5 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -47,7 +47,7 @@ class FileViewFinder implements ViewFinderInterface * * @param \Illuminate\Filesystem\Filesystem $files * @param array $paths - * @param array $extensions + * @param array|null $extensions * @return void */ public function __construct(Filesystem $files, array $paths, array $extensions = null) From 70918d60c8923ffa03b29856a6ba4bf6b9575b0a Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Tue, 26 Mar 2019 12:38:09 +1100 Subject: [PATCH 1670/2459] add forPageBeforeId method to query builder --- src/Illuminate/Database/Query/Builder.php | 20 +++++++++++++++++++ .../DatabaseEloquentIntegrationTest.php | 14 +++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 59eb358e0556..20d15794b2eb 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1938,6 +1938,26 @@ public function forPage($page, $perPage = 15) return $this->skip(($page - 1) * $perPage)->take($perPage); } + /** + * Constrain the query to the previous "page" of results before a given ID. + * + * @param int $perPage + * @param int|null $lastId + * @param string $column + * @return \Illuminate\Database\Query\Builder|static + */ + public function forPageBeforeId($perPage = 15, $lastId = 0, $column = 'id') + { + $this->orders = $this->removeExistingOrdersFor($column); + + if (! is_null($lastId)) { + $this->where($column, '<', $lastId); + } + + return $this->orderBy($column, 'desc') + ->take($perPage); + } + /** * Constrain the query to the next "page" of results after a given ID. * diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index ba92c0444e0c..d73f49ab9d37 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -1090,6 +1090,20 @@ public function testGlobalScopeCanBeRemovedByOtherGlobalScope() $this->assertNotNull(EloquentTestUserWithGlobalScopeRemovingOtherScope::find($user->id)); } + public function testForPageBeforeIdCorrectlyPaginates() + { + EloquentTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); + EloquentTestUser::create(['id' => 2, 'email' => 'abigailotwell@gmail.com']); + + $results = EloquentTestUser::forPageBeforeId(15, 2); + $this->assertInstanceOf(Builder::class, $results); + $this->assertEquals(1, $results->first()->id); + + $results = EloquentTestUser::orderBy('id', 'desc')->forPageBeforeId(15, 2); + $this->assertInstanceOf(Builder::class, $results); + $this->assertEquals(1, $results->first()->id); + } + public function testForPageAfterIdCorrectlyPaginates() { EloquentTestUser::create(['id' => 1, 'email' => 'taylorotwell@gmail.com']); From 3e146d54b978b773258c2e320a850caa576ec0ef Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Tue, 26 Mar 2019 05:36:53 -0300 Subject: [PATCH 1671/2459] check for preserveKeys when serializing a collection from a resource --- .../Http/Resources/Json/JsonResource.php | 6 +++- tests/Integration/Http/ResourceTest.php | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Resources/Json/JsonResource.php b/src/Illuminate/Http/Resources/Json/JsonResource.php index 832607a9dabd..f41c45435354 100644 --- a/src/Illuminate/Http/Resources/Json/JsonResource.php +++ b/src/Illuminate/Http/Resources/Json/JsonResource.php @@ -75,7 +75,11 @@ public static function make(...$parameters) */ public static function collection($resource) { - return new AnonymousResourceCollection($resource, static::class); + $collection = new AnonymousResourceCollection($resource, static::class); + + $collection->preserveKeys = property_exists(static::class, 'preserveKeys') && (new static([]))->preserveKeys === true; + + return $collection; } /** diff --git a/tests/Integration/Http/ResourceTest.php b/tests/Integration/Http/ResourceTest.php index 01a845e8f1a8..0f4ebdc791a1 100644 --- a/tests/Integration/Http/ResourceTest.php +++ b/tests/Integration/Http/ResourceTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Integration\Http; use Orchestra\Testbench\TestCase; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Route; use Illuminate\Http\Resources\MergeValue; use Illuminate\Http\Resources\MissingValue; @@ -629,6 +630,39 @@ public function test_keys_are_preserved_if_the_resource_is_flagged_to_preserve_k $response->assertJson(['data' => $data]); } + public function test_keys_are_preserved_in_an_anonymous_colletion_if_the_resource_is_flagged_to_preserve_keys() + { + $data = Collection::make([ + [ + 'id' => 1, + 'authorId' => 5, + 'bookId' => 22, + ], + [ + 'id' => 2, + 'authorId' => 5, + 'bookId' => 15, + ], + [ + 'id' => 3, + 'authorId' => 42, + 'bookId' => 12, + ], + ])->keyBy->id; + + Route::get('/', function () use ($data) { + return ResourceWithPreservedKeys::collection($data); + }); + + $response = $this->withoutExceptionHandling()->get( + '/', ['Accept' => 'application/json'] + ); + + $response->assertStatus(200); + + $response->assertJson(['data' => $data->toArray()]); + } + public function test_leading_merge_keyed_value_is_merged_correctly() { $filter = new class { From 502492e63ee19cc5f7cdfa07fa0d90f6cf3a567d Mon Sep 17 00:00:00 2001 From: Rodrigo Pedra Brum Date: Tue, 26 Mar 2019 05:40:19 -0300 Subject: [PATCH 1672/2459] use tap --- src/Illuminate/Http/Resources/Json/JsonResource.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Http/Resources/Json/JsonResource.php b/src/Illuminate/Http/Resources/Json/JsonResource.php index f41c45435354..1228c9babe38 100644 --- a/src/Illuminate/Http/Resources/Json/JsonResource.php +++ b/src/Illuminate/Http/Resources/Json/JsonResource.php @@ -75,11 +75,11 @@ public static function make(...$parameters) */ public static function collection($resource) { - $collection = new AnonymousResourceCollection($resource, static::class); - - $collection->preserveKeys = property_exists(static::class, 'preserveKeys') && (new static([]))->preserveKeys === true; - - return $collection; + return tap(new AnonymousResourceCollection($resource, static::class), function ($collection) { + if (property_exists(static::class, 'preserveKeys')) { + $collection->preserveKeys = (new static([]))->preserveKeys === true; + } + }); } /** From 194614de4d8edac9325d9558cf4d3bea7f2a048d Mon Sep 17 00:00:00 2001 From: yamenarahman Date: Tue, 26 Mar 2019 17:18:47 +0200 Subject: [PATCH 1673/2459] added `params` argument to `resolve` helper --- src/Illuminate/Foundation/helpers.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 9816a91fda2c..943312383c17 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -722,11 +722,12 @@ function rescue(callable $callback, $rescue = null) * Resolve a service from the container. * * @param string $name + * @param array $params * @return mixed */ - function resolve($name) + function resolve($name, array $params = []) { - return app($name); + return app($name, $params); } } From ae53a4d94244e63a9ce5e5e7d1d37ba062e8f1a9 Mon Sep 17 00:00:00 2001 From: yamenarahman Date: Tue, 26 Mar 2019 17:24:47 +0200 Subject: [PATCH 1674/2459] updated argument name --- src/Illuminate/Foundation/helpers.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index 943312383c17..fca478b680d1 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -722,12 +722,12 @@ function rescue(callable $callback, $rescue = null) * Resolve a service from the container. * * @param string $name - * @param array $params + * @param array $parameters * @return mixed */ - function resolve($name, array $params = []) + function resolve($name, array $parameters = []) { - return app($name, $params); + return app($name, $parameters); } } From 3f0a5744a866ae3ae0ca84f47080501714af01ba Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 26 Mar 2019 10:19:10 -0700 Subject: [PATCH 1675/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 0d02218cc40f..aa6e1c1e7355 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.8.7'; + const VERSION = '5.8.8'; /** * The base path for the Laravel installation. From 7d912aa94dc58b96815cac87a8cf7240fc03a36a Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 27 Mar 2019 00:28:27 +0200 Subject: [PATCH 1676/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index b77923dca764..b42950388d77 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -1,14 +1,25 @@ # Release Notes for 5.8.x -## [Unreleased](https://github.com/laravel/framework/compare/v5.8.7...5.8) +## [Unreleased](https://github.com/laravel/framework/compare/v5.8.8...5.8) + + +## [v5.8.8 (2019-03-26)](https://github.com/laravel/framework/compare/v5.8.7...v5.8.8) + +### Added +- Added `Illuminate\Database\Query\Builder::forPageBeforeId()` method ([#28011](https://github.com/laravel/framework/pull/28011)) + +### Fixed +- Fixed `BelongsToMany::detach()` with custom pivot class ([#27997](https://github.com/laravel/framework/pull/27997)) +- Fixed incorrect event namespace in generated listener by `event:generate` command ([#28007](https://github.com/laravel/framework/pull/28007)) +- Fixed unique validation without ignored column ([#27987](https://github.com/laravel/framework/pull/27987)) + +### Changed +- Added `parameters` argument to `resolve` helper ([#28020](https://github.com/laravel/framework/pull/28020)) +- Don't add the path only if path is `empty` in compiled view ([#27976](https://github.com/laravel/framework/pull/27976)) ### Refactoring - Refactoring of `env()` helper ([#27965](https://github.com/laravel/framework/pull/27965)) -### TODO -- https://github.com/laravel/framework/pull/27976 -- https://github.com/laravel/framework/pull/27987 - ## [v5.8.6-v5.8.7 (2019-03-21)](https://github.com/laravel/framework/compare/v5.8.5...v5.8.7) From 5df3cff39a6a3c1515f78ee6d8bb10f0368a3c1a Mon Sep 17 00:00:00 2001 From: Hamid Alaei V Date: Wed, 27 Mar 2019 12:08:07 +0430 Subject: [PATCH 1677/2459] move test classes to their own files --- tests/Database/DatabaseEloquentIntegrationTest.php | 4 ++-- .../Database/EloquentCollectionFreshTest.php | 7 +------ tests/Integration/Database/EloquentDeleteTest.php | 6 +----- tests/Integration/Database/Fixtures/Post.php | 10 ++++++++++ tests/Integration/Database/Fixtures/User.php | 10 ++++++++++ 5 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 tests/Integration/Database/Fixtures/Post.php create mode 100644 tests/Integration/Database/Fixtures/User.php diff --git a/tests/Database/DatabaseEloquentIntegrationTest.php b/tests/Database/DatabaseEloquentIntegrationTest.php index ba92c0444e0c..e4123af3ac8a 100644 --- a/tests/Database/DatabaseEloquentIntegrationTest.php +++ b/tests/Database/DatabaseEloquentIntegrationTest.php @@ -14,13 +14,13 @@ use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Pagination\LengthAwarePaginator; -use Illuminate\Tests\Integration\Database\Post; -use Illuminate\Tests\Integration\Database\User; use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Database\Eloquent\Model as Eloquent; use Illuminate\Database\Eloquent\SoftDeletingScope; use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Tests\Integration\Database\Fixtures\Post; +use Illuminate\Tests\Integration\Database\Fixtures\User; use Illuminate\Pagination\AbstractPaginator as Paginator; class DatabaseEloquentIntegrationTest extends TestCase diff --git a/tests/Integration/Database/EloquentCollectionFreshTest.php b/tests/Integration/Database/EloquentCollectionFreshTest.php index 719093c067cd..71016727e5f3 100644 --- a/tests/Integration/Database/EloquentCollectionFreshTest.php +++ b/tests/Integration/Database/EloquentCollectionFreshTest.php @@ -3,8 +3,8 @@ namespace Illuminate\Tests\Integration\Database; use Illuminate\Support\Facades\Schema; -use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Tests\Integration\Database\Fixtures\User; /** * @group integration @@ -35,8 +35,3 @@ public function test_eloquent_collection_fresh() $this->assertEmpty($collection->fresh()->filter()); } } - -class User extends Model -{ - protected $guarded = []; -} diff --git a/tests/Integration/Database/EloquentDeleteTest.php b/tests/Integration/Database/EloquentDeleteTest.php index f32901445d4a..5a1019bb0b0d 100644 --- a/tests/Integration/Database/EloquentDeleteTest.php +++ b/tests/Integration/Database/EloquentDeleteTest.php @@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Tests\Integration\Database\Fixtures\Post; /** * @group integration @@ -80,11 +81,6 @@ public function testForceDeletedEventIsFired() } } -class Post extends Model -{ - public $table = 'posts'; -} - class Comment extends Model { public $table = 'comments'; diff --git a/tests/Integration/Database/Fixtures/Post.php b/tests/Integration/Database/Fixtures/Post.php new file mode 100644 index 000000000000..a7693e60b10a --- /dev/null +++ b/tests/Integration/Database/Fixtures/Post.php @@ -0,0 +1,10 @@ + Date: Wed, 27 Mar 2019 11:17:08 +0100 Subject: [PATCH 1678/2459] Fix comment (#28030) [5.8] Fix comment --- src/Illuminate/Broadcasting/BroadcastManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Broadcasting/BroadcastManager.php b/src/Illuminate/Broadcasting/BroadcastManager.php index c8d6ed6a642d..2005eaab4f64 100644 --- a/src/Illuminate/Broadcasting/BroadcastManager.php +++ b/src/Illuminate/Broadcasting/BroadcastManager.php @@ -165,7 +165,7 @@ protected function get($name) } /** - * Resolve the given store. + * Resolve the given broadcaster. * * @param string $name * @return \Illuminate\Contracts\Broadcasting\Broadcaster From 5681fdb9aa1ae1a8958a0bc8f7ed5761f0bdab0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nikolaou?= Date: Wed, 27 Mar 2019 23:49:30 +0200 Subject: [PATCH 1679/2459] Accept throwable in report helper typehint --- src/Illuminate/Foundation/helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/helpers.php b/src/Illuminate/Foundation/helpers.php index fca478b680d1..068f48a169da 100644 --- a/src/Illuminate/Foundation/helpers.php +++ b/src/Illuminate/Foundation/helpers.php @@ -659,7 +659,7 @@ function redirect($to = null, $status = 302, $headers = [], $secure = null) /** * Report an exception. * - * @param \Exception $exception + * @param \Throwable $exception * @return void */ function report($exception) From 375f73e8ae67b86944b1733a4c7fd945fbbc7eae Mon Sep 17 00:00:00 2001 From: Inani El Houssain Date: Thu, 28 Mar 2019 09:45:24 +0000 Subject: [PATCH 1680/2459] Update Collection.php --- src/Illuminate/Support/Collection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index c6b8d2dd6f48..278038a0b29b 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -184,7 +184,7 @@ public function median($key = null) $count = $values->count(); - if ($count == 0) { + if ($count === 0) { return; } From 86f5714e26b88940452a0d9df9db860309fbb597 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 28 Mar 2019 13:53:25 +0200 Subject: [PATCH 1681/2459] Corrected test for supports --- tests/Support/SupportCollectionTest.php | 15 +++++++++++++++ tests/Support/SupportMessageBagTest.php | 1 + tests/Support/SupportPluralizerTest.php | 1 + 3 files changed, 17 insertions(+) diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index 7fcd3eae5488..d075d7051f2f 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -1862,6 +1862,21 @@ public function testKeyByClosure() ], $result->all()); } + public function testKeyByObject() + { + $data = new Collection([ + ['firstname' => 'Taylor', 'lastname' => 'Otwell', 'locale' => 'US'], + ['firstname' => 'Lucas', 'lastname' => 'Michot', 'locale' => 'FR'], + ]); + $result = $data->keyBy(function ($item, $key) { + return new Collection([$key, $item['firstname'], $item['lastname']]); + }); + $this->assertEquals([ + '[0,"Taylor","Otwell"]' => ['firstname' => 'Taylor', 'lastname' => 'Otwell', 'locale' => 'US'], + '[1,"Lucas","Michot"]' => ['firstname' => 'Lucas', 'lastname' => 'Michot', 'locale' => 'FR'], + ], $result->all()); + } + public function testContains() { $c = new Collection([1, 3, 5]); diff --git a/tests/Support/SupportMessageBagTest.php b/tests/Support/SupportMessageBagTest.php index 8e543cd2d15a..bfd63b97bfe8 100755 --- a/tests/Support/SupportMessageBagTest.php +++ b/tests/Support/SupportMessageBagTest.php @@ -133,6 +133,7 @@ public function testHasAnyIndicatesExistence() { $container = new MessageBag; $container->setFormat(':message'); + $this->assertFalse($container->hasAny()); $container->add('foo', 'bar'); $container->add('bar', 'foo'); $container->add('boom', 'baz'); diff --git a/tests/Support/SupportPluralizerTest.php b/tests/Support/SupportPluralizerTest.php index 5b128217f81f..5f3e09e013c0 100755 --- a/tests/Support/SupportPluralizerTest.php +++ b/tests/Support/SupportPluralizerTest.php @@ -30,6 +30,7 @@ public function testCaseSensitiveSingularPlural() $this->assertEquals('Children', Str::plural('Child')); $this->assertEquals('CHILDREN', Str::plural('CHILD')); $this->assertEquals('Tests', Str::plural('Test')); + $this->assertEquals('children', Str::plural('cHiLd')); } public function testIfEndOfWordPlural() From 33d9ba9623eec4e36b5832401c4008d283bc605c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ba=CC=81lint=20Szekeres?= Date: Thu, 28 Mar 2019 13:51:26 +0100 Subject: [PATCH 1682/2459] added `env()` default value tests --- tests/Support/SupportHelpersTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Support/SupportHelpersTest.php b/tests/Support/SupportHelpersTest.php index 4c50240f8d8d..20a2992c9465 100755 --- a/tests/Support/SupportHelpersTest.php +++ b/tests/Support/SupportHelpersTest.php @@ -572,6 +572,21 @@ public function testEnvNull() $this->assertNull(env('foo')); } + public function testEnvDefault() + { + $_SERVER['foo'] = 'bar'; + $this->assertEquals('bar', env('foo', 'default')); + + $_SERVER['foo'] = ''; + $this->assertEquals('', env('foo', 'default')); + + unset($_SERVER['foo']); + $this->assertEquals('default', env('foo', 'default')); + + $_SERVER['foo'] = null; + $this->assertEquals('default', env('foo', 'default')); + } + public function testEnvEscapedString() { $_SERVER['foo'] = '"null"'; From adee424af38e82c7de18a9e4ff47d069a04e8c34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristijan=20Novakovi=C4=87?= Date: Thu, 28 Mar 2019 14:55:40 +0100 Subject: [PATCH 1683/2459] Changes cache duration in forever method for database driver to be in line with 5.7 --- src/Illuminate/Cache/DatabaseStore.php | 2 +- tests/Cache/CacheDatabaseStoreTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Cache/DatabaseStore.php b/src/Illuminate/Cache/DatabaseStore.php index e5c7cd146748..a7de61bb1e86 100755 --- a/src/Illuminate/Cache/DatabaseStore.php +++ b/src/Illuminate/Cache/DatabaseStore.php @@ -202,7 +202,7 @@ protected function getTime() */ public function forever($key, $value) { - return $this->put($key, $value, 5256000); + return $this->put($key, $value, 315360000); } /** diff --git a/tests/Cache/CacheDatabaseStoreTest.php b/tests/Cache/CacheDatabaseStoreTest.php index 70de8175ebf5..608be4a6b241 100755 --- a/tests/Cache/CacheDatabaseStoreTest.php +++ b/tests/Cache/CacheDatabaseStoreTest.php @@ -106,7 +106,7 @@ public function testValueIsInsertedOnPostgres() public function testForeverCallsStoreItemWithReallyLongTime() { $store = $this->getMockBuilder(DatabaseStore::class)->setMethods(['put'])->setConstructorArgs($this->getMocks())->getMock(); - $store->expects($this->once())->method('put')->with($this->equalTo('foo'), $this->equalTo('bar'), $this->equalTo(5256000))->willReturn(true); + $store->expects($this->once())->method('put')->with($this->equalTo('foo'), $this->equalTo('bar'), $this->equalTo(315360000))->willReturn(true); $result = $store->forever('foo', 'bar'); $this->assertTrue($result); } From 4aeb89235e594f3b942fc6c136b76de4de7d65cc Mon Sep 17 00:00:00 2001 From: Ivan Kuzmin Date: Fri, 29 Mar 2019 12:57:33 +0200 Subject: [PATCH 1684/2459] Fix missed type declaration from base class --- src/Illuminate/Http/Request.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Http/Request.php b/src/Illuminate/Http/Request.php index 0e1ffa2ff6b6..611c6728607f 100644 --- a/src/Illuminate/Http/Request.php +++ b/src/Illuminate/Http/Request.php @@ -269,7 +269,7 @@ public function secure() /** * Get the client IP address. * - * @return string + * @return string|null */ public function ip() { From c277c21ba64c14f956b0dcb1ee937994497514b0 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2019 09:11:15 -0500 Subject: [PATCH 1685/2459] initial pass at event discovery on the fly --- .../Providers/EventServiceProvider.php | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 5b2664771a85..b505d985d2ef 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -4,6 +4,7 @@ use Illuminate\Support\Facades\Event; use Illuminate\Support\ServiceProvider; +use Illuminate\Foundation\Events\DiscoverEvents; class EventServiceProvider extends ServiceProvider { @@ -46,6 +47,34 @@ public function boot() */ public function listens() { - return $this->listen; + return array_merge($this->discoverEvents(), $this->listen); + } + + /** + * Discover the events and listeners for the application. + * + * @return array + */ + protected function discoverEvents() + { + return collect($this->discoverEventsWithin()) + ->reduce(function ($discovered, $directory) { + return array_merge( + $discovered, + DiscoverEvents::within($directory, base_path()) + ); + }, []); + } + + /** + * Get the listener directories that should be used to discover events. + * + * @return array + */ + protected function discoverEventsWithin() + { + return [ + app_path('Listeners'), + ]; } } From 098bad7e0a62bd2272b0f07260367d11bdbcddcd Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2019 09:11:22 -0500 Subject: [PATCH 1686/2459] add files --- .../Foundation/Events/DiscoverEvents.php | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/Illuminate/Foundation/Events/DiscoverEvents.php diff --git a/src/Illuminate/Foundation/Events/DiscoverEvents.php b/src/Illuminate/Foundation/Events/DiscoverEvents.php new file mode 100644 index 000000000000..126b95d7225d --- /dev/null +++ b/src/Illuminate/Foundation/Events/DiscoverEvents.php @@ -0,0 +1,78 @@ +files() + ->in($listenerPath), $basePath)); + + return $listenerEvents->values() + ->zip($listenerEvents->keys()->all()) + ->reduce(function ($carry, $listenerEventPair) { + $carry[$listenerEventPair[0]][] = $listenerEventPair[1]; + + return $carry; + }, []); + } + + /** + * Get all of the listeners and their corresponding events. + * + * @param iterable $listeners + * @param string $basePath + * @return array + */ + protected static function getListenerEvents($listeners, $basePath) + { + $listenerEvents = []; + + foreach ($listeners as $listener) { + $listener = new ReflectionClass( + static::classFromFile($listener, $basePath) + ); + + foreach ($listener->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + if (! Str::is('handle*', $method->name) || + ! isset($method->getParameters()[0])) { + continue; + } + + $listenerEvents[$listener->name.'@'.$method->name] = + optional($method->getParameters()[0]->getClass())->name; + } + } + + return array_filter($listenerEvents); + } + + /** + * Extract the class name from the given file path. + * + * @param \SplFileInfo $file + * @param string $basePath + * @return string + */ + protected static function classFromFile(SplFileInfo $file, $basePath) + { + $class = trim(str_replace($basePath, '', $file->getRealPath()), DIRECTORY_SEPARATOR); + + return str_replace(DIRECTORY_SEPARATOR, '\\', ucfirst(Str::replaceLast('.php', '', $class))); + } +} From b92769273351eef9d534a5edf8c76376b872ea0c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2019 09:11:36 -0500 Subject: [PATCH 1687/2459] formatting --- .../Foundation/Support/Providers/EventServiceProvider.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index b505d985d2ef..97563dc412ce 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -47,7 +47,10 @@ public function boot() */ public function listens() { - return array_merge($this->discoverEvents(), $this->listen); + return array_merge( + $this->discoverEvents(), + $this->listen + ); } /** From d5b80d727b6e426ce424be79b6016838c368504c Mon Sep 17 00:00:00 2001 From: Caleb Porzio Date: Fri, 29 Mar 2019 11:56:40 -0400 Subject: [PATCH 1688/2459] Add @error blade directive --- .../View/Compilers/BladeCompiler.php | 1 + .../View/Compilers/Concerns/CompilesError.php | 34 +++++++++++++++++++ tests/View/Blade/BladeErrorTest.php | 24 +++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 src/Illuminate/View/Compilers/Concerns/CompilesError.php create mode 100644 tests/View/Blade/BladeErrorTest.php diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 0f084b06ffec..1180a9114f9d 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -13,6 +13,7 @@ class BladeCompiler extends Compiler implements CompilerInterface Concerns\CompilesComponents, Concerns\CompilesConditionals, Concerns\CompilesEchos, + Concerns\CompilesError, Concerns\CompilesHelpers, Concerns\CompilesIncludes, Concerns\CompilesInjections, diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesError.php b/src/Illuminate/View/Compilers/Concerns/CompilesError.php new file mode 100644 index 000000000000..ec6a22126686 --- /dev/null +++ b/src/Illuminate/View/Compilers/Concerns/CompilesError.php @@ -0,0 +1,34 @@ +stripParentheses($expression); + + return 'has('.$expression.')) : +if (isset($message)) { $messageCache = $message; } +$message = $errors->first('.$expression.'); ?>'; + } + + /** + * Compile the enderror statements into valid PHP. + * + * @param string $expression + * @return string + */ + protected function compileEnderror($expression) + { + return ''; + } +} diff --git a/tests/View/Blade/BladeErrorTest.php b/tests/View/Blade/BladeErrorTest.php new file mode 100644 index 000000000000..2c5fed7b6bd7 --- /dev/null +++ b/tests/View/Blade/BladeErrorTest.php @@ -0,0 +1,24 @@ +{{ $message }} +@enderror'; + $expected = ' +has(\'email\')) : +if (isset($message)) { $messageCache = $message; } +$message = $errors->first(\'email\'); ?> + +'; + + $this->assertEquals($expected, $this->compiler->compileString($string)); + } +} From 057b770776d6eacf4f535d78f9b262d03dd27042 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2019 11:33:52 -0500 Subject: [PATCH 1689/2459] clean up event caching --- src/Illuminate/Foundation/Application.php | 20 ++++++ .../Foundation/Console/EventCacheCommand.php | 61 +++++++++++++++++++ .../Foundation/Console/EventClearCommand.php | 58 ++++++++++++++++++ .../Providers/ArtisanServiceProvider.php | 28 +++++++++ .../Providers/EventServiceProvider.php | 37 +++++++++-- 5 files changed, 198 insertions(+), 6 deletions(-) create mode 100644 src/Illuminate/Foundation/Console/EventCacheCommand.php create mode 100644 src/Illuminate/Foundation/Console/EventClearCommand.php diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index aa6e1c1e7355..0f403493dc20 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -936,6 +936,26 @@ public function getCachedRoutesPath() return $_ENV['APP_ROUTES_CACHE'] ?? $this->bootstrapPath().'/cache/routes.php'; } + /** + * Determine if the application events are cached. + * + * @return bool + */ + public function eventsAreCached() + { + return $this['files']->exists($this->getCachedEventsPath()); + } + + /** + * Get the path to the events cache file. + * + * @return string + */ + public function getCachedEventsPath() + { + return $_ENV['APP_EVENTS_CACHE'] ?? $this->storagePath().'/framework/cache/events.php'; + } + /** * Determine if the application is currently down for maintenance. * diff --git a/src/Illuminate/Foundation/Console/EventCacheCommand.php b/src/Illuminate/Foundation/Console/EventCacheCommand.php new file mode 100644 index 000000000000..8f6a05a83caf --- /dev/null +++ b/src/Illuminate/Foundation/Console/EventCacheCommand.php @@ -0,0 +1,61 @@ +call('event:clear'); + + file_put_contents( + $this->laravel->getCachedEventsPath(), + 'getEvents(), true).';' + ); + + $this->info('Events cached successfully!'); + } + + /** + * Get all of the events and listeners configured for the application. + * + * @return array + */ + protected function getEvents() + { + $events = []; + + foreach ($this->laravel->getProviders(EventServiceProvider::class) as $provider) { + $providerEvents = array_merge($provider->discoverEvents(), $provider->listens()); + + $events = array_merge_recursive($events, $providerEvents); + } + + return $events; + } +} diff --git a/src/Illuminate/Foundation/Console/EventClearCommand.php b/src/Illuminate/Foundation/Console/EventClearCommand.php new file mode 100644 index 000000000000..c87d8bc400c7 --- /dev/null +++ b/src/Illuminate/Foundation/Console/EventClearCommand.php @@ -0,0 +1,58 @@ +files = $files; + } + + /** + * Execute the console command. + * + * @return void + * + * @throws \RuntimeException + */ + public function handle() + { + $this->files->delete($this->laravel->getCachedEventsPath()); + + $this->info('Cached events cleared!'); + } +} diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index eaddeb605077..b8b1b6e2dd9a 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -25,6 +25,8 @@ use Illuminate\Foundation\Console\ViewCacheCommand; use Illuminate\Foundation\Console\ViewClearCommand; use Illuminate\Session\Console\SessionTableCommand; +use Illuminate\Foundation\Console\EventCacheCommand; +use Illuminate\Foundation\Console\EventClearCommand; use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Foundation\Console\PolicyMakeCommand; use Illuminate\Foundation\Console\RouteCacheCommand; @@ -89,6 +91,8 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'ConfigClear' => 'command.config.clear', 'Down' => 'command.down', 'Environment' => 'command.environment', + 'EventCache' => 'command.event.cache', + 'EventClear' => 'command.event.clear', 'KeyGenerate' => 'command.key.generate', 'Migrate' => 'command.migrate', 'MigrateFresh' => 'command.migrate.fresh', @@ -402,6 +406,30 @@ protected function registerEnvironmentCommand() }); } + /** + * Register the command. + * + * @return void + */ + protected function registerEventCacheCommand() + { + $this->app->singleton('command.event.cache', function () { + return new EventCacheCommand; + }); + } + + /** + * Register the command. + * + * @return void + */ + protected function registerEventClearCommand() + { + $this->app->singleton('command.event.clear', function ($app) { + return new EventClearCommand($app['files']); + }); + } + /** * Register the command. * diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 97563dc412ce..28d1b4f07378 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -29,7 +29,9 @@ class EventServiceProvider extends ServiceProvider */ public function boot() { - foreach ($this->listens() as $event => $listeners) { + $events = array_merge($this->discoveredEvents(), $this->listens()); + + foreach ($events as $event => $listeners) { foreach ($listeners as $listener) { Event::listen($event, $listener); } @@ -47,10 +49,33 @@ public function boot() */ public function listens() { - return array_merge( - $this->discoverEvents(), - $this->listen - ); + return $this->listen; + } + + /** + * Get the discovered events and listeners for the application. + * + * @return array + */ + protected function discoveredEvents() + { + if ($this->app->eventsAreCached()) { + return require $this->app->getCachedEventsPath(); + } + + return $this->shouldDiscoverEvents() + ? $this->discoverEvents() + : []; + } + + /** + * Determine if events and listeners should be automatically discovered. + * + * @return bool + */ + public function shouldDiscoverEvents() + { + return false; } /** @@ -58,7 +83,7 @@ public function listens() * * @return array */ - protected function discoverEvents() + public function discoverEvents() { return collect($this->discoverEventsWithin()) ->reduce(function ($discovered, $directory) { From fd53bf979f46e5c9841e07a44a49c7893be58f5c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2019 09:34:30 -0700 Subject: [PATCH 1690/2459] Apply fixes from StyleCI (#28063) --- src/Illuminate/Foundation/Console/EventCacheCommand.php | 3 --- src/Illuminate/Foundation/Console/EventClearCommand.php | 1 - src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Illuminate/Foundation/Console/EventCacheCommand.php b/src/Illuminate/Foundation/Console/EventCacheCommand.php index 8f6a05a83caf..3fc076009aa1 100644 --- a/src/Illuminate/Foundation/Console/EventCacheCommand.php +++ b/src/Illuminate/Foundation/Console/EventCacheCommand.php @@ -3,9 +3,6 @@ namespace Illuminate\Foundation\Console; use Illuminate\Console\Command; -use Illuminate\Support\Collection; -use Symfony\Component\Finder\Finder; -use Symfony\Component\Finder\SplFileInfo; use Illuminate\Foundation\Support\Providers\EventServiceProvider; class EventCacheCommand extends Command diff --git a/src/Illuminate/Foundation/Console/EventClearCommand.php b/src/Illuminate/Foundation/Console/EventClearCommand.php index c87d8bc400c7..a5fe4e67c187 100644 --- a/src/Illuminate/Foundation/Console/EventClearCommand.php +++ b/src/Illuminate/Foundation/Console/EventClearCommand.php @@ -2,7 +2,6 @@ namespace Illuminate\Foundation\Console; -use RuntimeException; use Illuminate\Console\Command; use Illuminate\Filesystem\Filesystem; diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index b8b1b6e2dd9a..9ea9bb08987f 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -25,9 +25,9 @@ use Illuminate\Foundation\Console\ViewCacheCommand; use Illuminate\Foundation\Console\ViewClearCommand; use Illuminate\Session\Console\SessionTableCommand; +use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Foundation\Console\EventCacheCommand; use Illuminate\Foundation\Console\EventClearCommand; -use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Foundation\Console\PolicyMakeCommand; use Illuminate\Foundation\Console\RouteCacheCommand; use Illuminate\Foundation\Console\RouteClearCommand; From b9de404ce384611e477e4fc5d8fca2a24f2ad562 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2019 11:45:35 -0500 Subject: [PATCH 1691/2459] change cache path --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 0f403493dc20..69d057af3e53 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -953,7 +953,7 @@ public function eventsAreCached() */ public function getCachedEventsPath() { - return $_ENV['APP_EVENTS_CACHE'] ?? $this->storagePath().'/framework/cache/events.php'; + return $_ENV['APP_EVENTS_CACHE'] ?? $this->bootstrapPath().'/cache/events.php'; } /** From dd60e0dcc8059f700cc4c3c0679b1a13d0fae252 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2019 11:48:13 -0500 Subject: [PATCH 1692/2459] use method on app --- .../Foundation/Support/Providers/EventServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 28d1b4f07378..da84e223f329 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -102,7 +102,7 @@ public function discoverEvents() protected function discoverEventsWithin() { return [ - app_path('Listeners'), + $this->app->path('Listeners'), ]; } } From e44d7867abf22cfe2da46adeb9a0219641454a5b Mon Sep 17 00:00:00 2001 From: Caleb Porzio Date: Fri, 29 Mar 2019 14:03:10 -0400 Subject: [PATCH 1693/2459] Pluralize filename --- src/Illuminate/View/Compilers/BladeCompiler.php | 2 +- .../Concerns/{CompilesError.php => CompilesErrors.php} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/Illuminate/View/Compilers/Concerns/{CompilesError.php => CompilesErrors.php} (97%) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 1180a9114f9d..3f1bd7a38619 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -13,7 +13,7 @@ class BladeCompiler extends Compiler implements CompilerInterface Concerns\CompilesComponents, Concerns\CompilesConditionals, Concerns\CompilesEchos, - Concerns\CompilesError, + Concerns\CompilesErrors, Concerns\CompilesHelpers, Concerns\CompilesIncludes, Concerns\CompilesInjections, diff --git a/src/Illuminate/View/Compilers/Concerns/CompilesError.php b/src/Illuminate/View/Compilers/Concerns/CompilesErrors.php similarity index 97% rename from src/Illuminate/View/Compilers/Concerns/CompilesError.php rename to src/Illuminate/View/Compilers/Concerns/CompilesErrors.php index ec6a22126686..252871d7bce9 100644 --- a/src/Illuminate/View/Compilers/Concerns/CompilesError.php +++ b/src/Illuminate/View/Compilers/Concerns/CompilesErrors.php @@ -2,7 +2,7 @@ namespace Illuminate\View\Compilers\Concerns; -trait CompilesError +trait CompilesErrors { /** * Compile the error statements into valid PHP. From e1288870ea5e4fd6f1739e075d4fb0a325398867 Mon Sep 17 00:00:00 2001 From: Elvijs Ostrovskis Date: Fri, 29 Mar 2019 17:59:48 -0500 Subject: [PATCH 1694/2459] Let Exception class be more Organized. --- src/Illuminate/Foundation/Console/stubs/exception-report.stub | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Console/stubs/exception-report.stub b/src/Illuminate/Foundation/Console/stubs/exception-report.stub index 72080e205c26..8db5c4f3c2b2 100644 --- a/src/Illuminate/Foundation/Console/stubs/exception-report.stub +++ b/src/Illuminate/Foundation/Console/stubs/exception-report.stub @@ -11,8 +11,8 @@ class DummyClass extends Exception * * @return void */ - public function report() - { + public function report() + { // } } From 9fc6ed1ea72546ef480fad4384b39ae6d0652129 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2019 21:17:17 -0500 Subject: [PATCH 1695/2459] unique listeners --- .../Foundation/Support/Providers/EventServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index da84e223f329..7be751f440bd 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -32,7 +32,7 @@ public function boot() $events = array_merge($this->discoveredEvents(), $this->listens()); foreach ($events as $event => $listeners) { - foreach ($listeners as $listener) { + foreach (array_unique($listeners) as $listener) { Event::listen($event, $listener); } } From f8db9d97411c3d6f1472c071d72ebbd1d1bbda5c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 29 Mar 2019 21:18:07 -0500 Subject: [PATCH 1696/2459] recursive merge --- .../Foundation/Support/Providers/EventServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 7be751f440bd..44086dee34a7 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -29,7 +29,7 @@ class EventServiceProvider extends ServiceProvider */ public function boot() { - $events = array_merge($this->discoveredEvents(), $this->listens()); + $events = array_merge_recursive($this->discoveredEvents(), $this->listens()); foreach ($events as $event => $listeners) { foreach (array_unique($listeners) as $listener) { From a7e91c828f021d6044681cb8d8f081171f3387aa Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 31 Mar 2019 00:30:38 +0200 Subject: [PATCH 1697/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index b42950388d77..7a8934bce6d6 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -2,6 +2,12 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v5.8.8...5.8) +### Fixed +- Fixed serializing a collection from a `Resource` with `preserveKeys` property ([#27985](https://github.com/laravel/framework/pull/27985)) + +### Changed +- Update forever cache duration for database driver from minutes to seconds ([#28048](https://github.com/laravel/framework/pull/28048)) + ## [v5.8.8 (2019-03-26)](https://github.com/laravel/framework/compare/v5.8.7...v5.8.8) From 7d24f9183fcd2bb7159470a9454fe74fd88e12f5 Mon Sep 17 00:00:00 2001 From: jerguslejko Date: Sun, 31 Mar 2019 11:45:14 +0100 Subject: [PATCH 1698/2459] add replicating model event --- .../Database/Eloquent/Concerns/HasEvents.php | 13 ++++++++++++- src/Illuminate/Database/Eloquent/Model.php | 2 ++ tests/Database/DatabaseEloquentModelTest.php | 12 ++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php b/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php index a8d65f734443..3c9d2a1d5f85 100644 --- a/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php +++ b/src/Illuminate/Database/Eloquent/Concerns/HasEvents.php @@ -96,7 +96,7 @@ public function getObservableEvents() return array_merge( [ 'retrieved', 'creating', 'created', 'updating', 'updated', - 'saving', 'saved', 'restoring', 'restored', + 'saving', 'saved', 'restoring', 'restored', 'replicating', 'deleting', 'deleted', 'forceDeleted', ], $this->observables @@ -303,6 +303,17 @@ public static function created($callback) static::registerModelEvent('created', $callback); } + /** + * Register a replicating model event with the dispatcher. + * + * @param \Closure|string $callback + * @return void + */ + public static function replicating($callback) + { + static::registerModelEvent('replicating', $callback); + } + /** * Register a deleting model event with the dispatcher. * diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index e0b9c011e439..6c1d3da58b9d 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1175,6 +1175,8 @@ public function replicate(array $except = null) $instance->setRawAttributes($attributes); $instance->setRelations($this->relations); + + $instance->fireModelEvent('replicating', false); }); } diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 1fd6654aad2f..5b768f6d1212 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -1507,6 +1507,18 @@ public function testReplicateCreatesANewModelInstanceWithSameAttributeValues() $this->assertNull($replicated->updated_at); } + public function testReplicatingEventIsFiredWhenReplicatingModel() + { + $model = new EloquentModelStub; + + $model->setEventDispatcher($events = m::mock(Dispatcher::class)); + $events->shouldReceive('dispatch')->once()->with('eloquent.replicating: '.get_class($model), m::on(function ($m) use ($model) { + return $model->is($m); + })); + + $model->replicate(); + } + public function testIncrementOnExistingModelCallsQueryAndSetsAttribute() { $model = m::mock(EloquentModelStub::class.'[newQueryWithoutRelationships]'); From 909d059e321f5d32f3510069a5acd315ed9d1f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nikolaou?= Date: Mon, 1 Apr 2019 03:51:58 +0300 Subject: [PATCH 1699/2459] Simplify the arguments passed to the before callbacks This commit removes some legacy code that was laying around since #12305 was merged. Before that PR, the arguments were spread out before being passed to the callbacks, so the user and the ability were merged with the other arguments, before being passed to the callback. Since then, the arguments are being passed as an array, so instead of merging the user and the ability with the array of arguments, which is superfluous, we can directly pass the user, the ability, and the arguments directly to the callback. This commit doesn't change the existing functionality, and it keeps backwards compatibility. I have also added some assertions to the tests, since the arguments in the before callbacks were never tested. --- src/Illuminate/Auth/Access/Gate.php | 4 +--- tests/Auth/AuthAccessGateTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Auth/Access/Gate.php b/src/Illuminate/Auth/Access/Gate.php index 78946ea94ecf..20506daa98f3 100644 --- a/src/Illuminate/Auth/Access/Gate.php +++ b/src/Illuminate/Auth/Access/Gate.php @@ -462,14 +462,12 @@ protected function callAuthCallback($user, $ability, array $arguments) */ protected function callBeforeCallbacks($user, $ability, array $arguments) { - $arguments = array_merge([$user, $ability], [$arguments]); - foreach ($this->beforeCallbacks as $before) { if (! $this->canBeCalledWithUser($user, $before)) { continue; } - if (! is_null($result = $before(...$arguments))) { + if (! is_null($result = $before($user, $ability, $arguments))) { return $result; } } diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index 175b7401df8d..b19994f967c5 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -342,6 +342,11 @@ public function test_a_single_argument_can_be_passed_when_checking_abilities() $dummy = new AccessGateTestDummy; + $gate->before(function ($user, $ability, array $arguments) use ($dummy) { + $this->assertCount(1, $arguments); + $this->assertSame($dummy, $arguments[0]); + }); + $gate->define('foo', function ($user, $x) use ($dummy) { $this->assertEquals($dummy, $x); @@ -358,6 +363,11 @@ public function test_multiple_arguments_can_be_passed_when_checking_abilities() $dummy1 = new AccessGateTestDummy; $dummy2 = new AccessGateTestDummy; + $gate->before(function ($user, $ability, array $arguments) use ($dummy1, $dummy2) { + $this->assertCount(2, $arguments); + $this->assertSame([$dummy1, $dummy2], $arguments); + }); + $gate->define('foo', function ($user, $x, $y) use ($dummy1, $dummy2) { $this->assertEquals($dummy1, $x); $this->assertEquals($dummy2, $y); From 7ea01d451274e7851e6f3292a84d078cdd06a12a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nikolaou?= Date: Mon, 1 Apr 2019 04:00:28 +0300 Subject: [PATCH 1700/2459] Improve tests for arguments in ability checks Use `assertSame` because `assertEquals` doesn't compare object references. Add assertions that the arguments are passed to the after callbacks. --- tests/Auth/AuthAccessGateTest.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/Auth/AuthAccessGateTest.php b/tests/Auth/AuthAccessGateTest.php index b19994f967c5..35da87779851 100644 --- a/tests/Auth/AuthAccessGateTest.php +++ b/tests/Auth/AuthAccessGateTest.php @@ -348,11 +348,16 @@ public function test_a_single_argument_can_be_passed_when_checking_abilities() }); $gate->define('foo', function ($user, $x) use ($dummy) { - $this->assertEquals($dummy, $x); + $this->assertSame($dummy, $x); return true; }); + $gate->after(function ($user, $ability, $result, array $arguments) use ($dummy) { + $this->assertCount(1, $arguments); + $this->assertSame($dummy, $arguments[0]); + }); + $this->assertTrue($gate->check('foo', $dummy)); } @@ -369,12 +374,17 @@ public function test_multiple_arguments_can_be_passed_when_checking_abilities() }); $gate->define('foo', function ($user, $x, $y) use ($dummy1, $dummy2) { - $this->assertEquals($dummy1, $x); - $this->assertEquals($dummy2, $y); + $this->assertSame($dummy1, $x); + $this->assertSame($dummy2, $y); return true; }); + $gate->after(function ($user, $ability, $result, array $arguments) use ($dummy1, $dummy2) { + $this->assertCount(2, $arguments); + $this->assertSame([$dummy1, $dummy2], $arguments); + }); + $this->assertTrue($gate->check('foo', [$dummy1, $dummy2])); } From dcc840f86976bcc9dba1553e6ccfd86c8703ece6 Mon Sep 17 00:00:00 2001 From: Elnur Ibrahimzade Date: Mon, 1 Apr 2019 09:04:37 +0400 Subject: [PATCH 1701/2459] Fixed: SoftDelete::runSoftDelete and SoftDelete::performDeleteOnModel did not take into account overwrite Model::setKeysForSaveQuery --- src/Illuminate/Database/Eloquent/SoftDeletes.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/SoftDeletes.php b/src/Illuminate/Database/Eloquent/SoftDeletes.php index 1cd27c1c0991..232a41f6aa28 100644 --- a/src/Illuminate/Database/Eloquent/SoftDeletes.php +++ b/src/Illuminate/Database/Eloquent/SoftDeletes.php @@ -59,7 +59,7 @@ protected function performDeleteOnModel() if ($this->forceDeleting) { $this->exists = false; - return $this->newModelQuery()->where($this->getKeyName(), $this->getKey())->forceDelete(); + return $this->setKeysForSaveQuery($this->newModelQuery())->forceDelete(); } return $this->runSoftDelete(); @@ -72,7 +72,7 @@ protected function performDeleteOnModel() */ protected function runSoftDelete() { - $query = $this->newModelQuery()->where($this->getKeyName(), $this->getKey()); + $query = $this->setKeysForSaveQuery($this->newModelQuery()); $time = $this->freshTimestamp(); From 63280620f3144fba2cafc74afbf3d7599cbbd271 Mon Sep 17 00:00:00 2001 From: Elnur Ibrahimzade Date: Mon, 1 Apr 2019 15:45:53 +0400 Subject: [PATCH 1702/2459] Adding DatabaseSoftDeletingTraitStub::setKeysForSaveQuery method to DatabaseSoftDeletingTraitTest --- tests/Database/DatabaseSoftDeletingTraitTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Database/DatabaseSoftDeletingTraitTest.php b/tests/Database/DatabaseSoftDeletingTraitTest.php index d3614dc01d2a..3ed8087fe6ad 100644 --- a/tests/Database/DatabaseSoftDeletingTraitTest.php +++ b/tests/Database/DatabaseSoftDeletingTraitTest.php @@ -104,4 +104,16 @@ public function getUpdatedAtColumn() { return defined('static::UPDATED_AT') ? static::UPDATED_AT : 'updated_at'; } + + public function setKeysForSaveQuery($query) + { + $query->where($this->getKeyName(), '=', $this->getKeyForSaveQuery()); + + return $query; + } + + protected function getKeyForSaveQuery() + { + return 1; + } } From 5c70c9232a2cf6883e0559d38988ec6887b16f9d Mon Sep 17 00:00:00 2001 From: Elnur Ibrahimzade Date: Mon, 1 Apr 2019 15:50:38 +0400 Subject: [PATCH 1703/2459] missed equal sign --- tests/Database/DatabaseSoftDeletingTraitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Database/DatabaseSoftDeletingTraitTest.php b/tests/Database/DatabaseSoftDeletingTraitTest.php index 3ed8087fe6ad..f7a7b2e37c6c 100644 --- a/tests/Database/DatabaseSoftDeletingTraitTest.php +++ b/tests/Database/DatabaseSoftDeletingTraitTest.php @@ -19,7 +19,7 @@ public function testDeleteSetsSoftDeletedColumn() $model = m::mock(DatabaseSoftDeletingTraitStub::class); $model->makePartial(); $model->shouldReceive('newModelQuery')->andReturn($query = m::mock(stdClass::class)); - $query->shouldReceive('where')->once()->with('id', 1)->andReturn($query); + $query->shouldReceive('where')->once()->with('id', '=', 1)->andReturn($query); $query->shouldReceive('update')->once()->with([ 'deleted_at' => 'date-time', 'updated_at' => 'date-time', From a2c408a038c60f7ab1525c704e0ea50e661091d7 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 1 Apr 2019 11:56:13 -0500 Subject: [PATCH 1704/2459] add tests --- tests/Foundation/DiscoverEventsTest.php | 29 +++++++++++++++++++ .../EventDiscovery/Events/EventOne.php | 5 ++++ .../EventDiscovery/Events/EventTwo.php | 5 ++++ .../EventDiscovery/Listeners/Listener.php | 24 +++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 tests/Foundation/DiscoverEventsTest.php create mode 100644 tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php create mode 100644 tests/Foundation/Fixtures/EventDiscovery/Events/EventTwo.php create mode 100644 tests/Foundation/Fixtures/EventDiscovery/Listeners/Listener.php diff --git a/tests/Foundation/DiscoverEventsTest.php b/tests/Foundation/DiscoverEventsTest.php new file mode 100644 index 000000000000..03c9163ecb99 --- /dev/null +++ b/tests/Foundation/DiscoverEventsTest.php @@ -0,0 +1,29 @@ +assertEquals([ + EventOne::class => [ + Listener::class.'@handle', + Listener::class.'@handleEventOne', + ], + EventTwo::class => [ + Listener::class.'@handleEventTwo', + ], + ], $events); + } +} diff --git a/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php b/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php new file mode 100644 index 000000000000..77c74cb36da8 --- /dev/null +++ b/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php @@ -0,0 +1,5 @@ + Date: Mon, 1 Apr 2019 09:57:13 -0700 Subject: [PATCH 1705/2459] Apply fixes from StyleCI (#28084) --- tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php | 4 +++- tests/Foundation/Fixtures/EventDiscovery/Events/EventTwo.php | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php b/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php index 77c74cb36da8..fbd2d849e6b7 100644 --- a/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php +++ b/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php @@ -2,4 +2,6 @@ namespace Illuminate\Tests\Foundation\Fixtures\EventDiscovery\Events; -class EventOne {} +class EventOne +{ +} diff --git a/tests/Foundation/Fixtures/EventDiscovery/Events/EventTwo.php b/tests/Foundation/Fixtures/EventDiscovery/Events/EventTwo.php index 88eb5d650314..4bcb495938eb 100644 --- a/tests/Foundation/Fixtures/EventDiscovery/Events/EventTwo.php +++ b/tests/Foundation/Fixtures/EventDiscovery/Events/EventTwo.php @@ -2,4 +2,6 @@ namespace Illuminate\Tests\Foundation\Fixtures\EventDiscovery\Events; -class EventTwo {} +class EventTwo +{ +} From 688018ab3695aad3f6e945ead7c4515af9069b98 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 1 Apr 2019 12:03:58 -0500 Subject: [PATCH 1706/2459] formatting --- .../Foundation/Support/Providers/EventServiceProvider.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 44086dee34a7..091bea466679 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -29,7 +29,10 @@ class EventServiceProvider extends ServiceProvider */ public function boot() { - $events = array_merge_recursive($this->discoveredEvents(), $this->listens()); + $events = array_merge_recursive( + $this->discoveredEvents(), + $this->listens() + ); foreach ($events as $event => $listeners) { foreach (array_unique($listeners) as $listener) { @@ -87,7 +90,7 @@ public function discoverEvents() { return collect($this->discoverEventsWithin()) ->reduce(function ($discovered, $directory) { - return array_merge( + return array_merge_recursive( $discovered, DiscoverEvents::within($directory, base_path()) ); From 1301afced05f9810342c1ff9055a42bf441d80e8 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Mon, 1 Apr 2019 20:28:16 +0200 Subject: [PATCH 1707/2459] add event:list command --- .../Foundation/Console/EventListCommand.php | 53 +++++++++++++++++++ .../Providers/ArtisanServiceProvider.php | 14 +++++ 2 files changed, 67 insertions(+) create mode 100644 src/Illuminate/Foundation/Console/EventListCommand.php diff --git a/src/Illuminate/Foundation/Console/EventListCommand.php b/src/Illuminate/Foundation/Console/EventListCommand.php new file mode 100644 index 000000000000..e3d590a4c891 --- /dev/null +++ b/src/Illuminate/Foundation/Console/EventListCommand.php @@ -0,0 +1,53 @@ +table(['Event', 'Listeners'], $this->getEvents()); + } + + /** + * Get all of the events and listeners configured for the application. + * + * @return array + */ + protected function getEvents() + { + $events = []; + + foreach ($this->laravel->getProviders(EventServiceProvider::class) as $provider) { + $providerEvents = array_merge($provider->discoverEvents(), $provider->listens()); + + $events = array_merge_recursive($events, $providerEvents); + } + + return collect($events)->map(function ($value, $key) { + return ['Event' => $key, 'Listeners' => implode("\n", $value)]; + })->values()->toArray(); + } +} diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index 9ea9bb08987f..5c50d1942f81 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation\Providers; +use Illuminate\Foundation\Console\EventListCommand; use Illuminate\Support\ServiceProvider; use Illuminate\Queue\Console\TableCommand; use Illuminate\Auth\Console\AuthMakeCommand; @@ -93,6 +94,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid 'Environment' => 'command.environment', 'EventCache' => 'command.event.cache', 'EventClear' => 'command.event.clear', + 'EventList' => 'command.event.list', 'KeyGenerate' => 'command.key.generate', 'Migrate' => 'command.migrate', 'MigrateFresh' => 'command.migrate.fresh', @@ -430,6 +432,18 @@ protected function registerEventClearCommand() }); } + /** + * Register the command. + * + * @return void + */ + protected function registerEventListCommand() + { + $this->app->singleton('command.event.list', function () { + return new EventListCommand(); + }); + } + /** * Register the command. * From 0885282b1eacf4fd7e3bcd559b31ec4b7a71036f Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Mon, 1 Apr 2019 20:30:33 +0200 Subject: [PATCH 1708/2459] style fix --- src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php index 5c50d1942f81..110d5e89a663 100755 --- a/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php +++ b/src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php @@ -2,7 +2,6 @@ namespace Illuminate\Foundation\Providers; -use Illuminate\Foundation\Console\EventListCommand; use Illuminate\Support\ServiceProvider; use Illuminate\Queue\Console\TableCommand; use Illuminate\Auth\Console\AuthMakeCommand; @@ -20,6 +19,7 @@ use Illuminate\Foundation\Console\OptimizeCommand; use Illuminate\Foundation\Console\RuleMakeCommand; use Illuminate\Foundation\Console\TestMakeCommand; +use Illuminate\Foundation\Console\EventListCommand; use Illuminate\Foundation\Console\EventMakeCommand; use Illuminate\Foundation\Console\ModelMakeCommand; use Illuminate\Foundation\Console\RouteListCommand; From c46bb9fdfdf617b0bd3c31990a26fc8dee500af8 Mon Sep 17 00:00:00 2001 From: Chris Morbitzer Date: Mon, 1 Apr 2019 14:08:55 -0500 Subject: [PATCH 1709/2459] DateTimeInterface allowed with CronExpression since v2.3 --- src/Illuminate/Console/Scheduling/Event.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 46fea27c28b1..758d688eaa0c 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -696,7 +696,7 @@ public function getSummaryForDisplay() /** * Determine the next due date for an event. * - * @param \DateTime|string $currentTime + * @param \DateTimeInterface|string $currentTime * @param int $nth * @param bool $allowCurrentDate * @return \Illuminate\Support\Carbon From 3bb5c5afa886d8f1a805be286246161fe5207233 Mon Sep 17 00:00:00 2001 From: freek Date: Tue, 2 Apr 2019 15:50:31 +0200 Subject: [PATCH 1710/2459] make notification fake macroable --- src/Illuminate/Support/Testing/Fakes/NotificationFake.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php index b2fab7a35449..e0f098159832 100644 --- a/src/Illuminate/Support/Testing/Fakes/NotificationFake.php +++ b/src/Illuminate/Support/Testing/Fakes/NotificationFake.php @@ -4,6 +4,7 @@ use Illuminate\Support\Str; use Illuminate\Support\Collection; +use Illuminate\Support\Traits\Macroable; use PHPUnit\Framework\Assert as PHPUnit; use Illuminate\Contracts\Translation\HasLocalePreference; use Illuminate\Contracts\Notifications\Factory as NotificationFactory; @@ -11,6 +12,8 @@ class NotificationFake implements NotificationFactory, NotificationDispatcher { + use Macroable; + /** * All of the notifications that have been sent. * From 2455d21938e9072e5a8ecef64ae162a1825d336b Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 2 Apr 2019 09:11:17 -0500 Subject: [PATCH 1711/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 69d057af3e53..5848b1c96e4b 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.8.8'; + const VERSION = '5.8.9'; /** * The base path for the Laravel installation. From 343775115722ed0e6c3455b72ee7204aefdf37d3 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 2 Apr 2019 18:25:32 +0200 Subject: [PATCH 1712/2459] sort events in event:list command --- src/Illuminate/Foundation/Console/EventListCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/EventListCommand.php b/src/Illuminate/Foundation/Console/EventListCommand.php index e3d590a4c891..15880e9a0bdf 100644 --- a/src/Illuminate/Foundation/Console/EventListCommand.php +++ b/src/Illuminate/Foundation/Console/EventListCommand.php @@ -48,6 +48,6 @@ protected function getEvents() return collect($events)->map(function ($value, $key) { return ['Event' => $key, 'Listeners' => implode("\n", $value)]; - })->values()->toArray(); + })->sortBy('Event')->values()->toArray(); } } From 6a5357a5f02fc5664bc89cfe8651e344550ce1d6 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 3 Apr 2019 01:26:42 +0300 Subject: [PATCH 1713/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 7a8934bce6d6..459033a5ecb9 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -1,13 +1,23 @@ # Release Notes for 5.8.x -## [Unreleased](https://github.com/laravel/framework/compare/v5.8.8...5.8) +## [Unreleased](https://github.com/laravel/framework/compare/v5.8.9...5.8) + + +## [v5.8.9 (2019-04-02)](https://github.com/laravel/framework/compare/v5.8.8...v5.8.9) + +### Added +- Added Event Discovery ([#28064](https://github.com/laravel/framework/pull/28064), [#28085](https://github.com/laravel/framework/pull/28085)) ### Fixed - Fixed serializing a collection from a `Resource` with `preserveKeys` property ([#27985](https://github.com/laravel/framework/pull/27985)) +- Fixed: `SoftDelete::runSoftDelete` and `SoftDelete::performDeleteOnModel` with overwritten `Model::setKeysForSaveQuery` ([#28081](https://github.com/laravel/framework/pull/28081)) ### Changed - Update forever cache duration for database driver from minutes to seconds ([#28048](https://github.com/laravel/framework/pull/28048)) +### Refactoring: +- Refactoring of `Illuminate\Auth\Access\Gate::callBeforeCallbacks()` ([#28079](https://github.com/laravel/framework/pull/28079)) + ## [v5.8.8 (2019-03-26)](https://github.com/laravel/framework/compare/v5.8.7...v5.8.8) From 186bb41b4a499b75713c516f07b9c3f5a4f1fcaa Mon Sep 17 00:00:00 2001 From: Mohammad ALTAWEEL Date: Wed, 3 Apr 2019 11:58:07 +0300 Subject: [PATCH 1714/2459] Correct return type of get method --- src/Illuminate/Cache/Lock.php | 2 +- src/Illuminate/Contracts/Cache/Lock.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Cache/Lock.php b/src/Illuminate/Cache/Lock.php index 37b2a7bd3390..ccbfbaf18644 100644 --- a/src/Illuminate/Cache/Lock.php +++ b/src/Illuminate/Cache/Lock.php @@ -76,7 +76,7 @@ abstract protected function getCurrentOwner(); * Attempt to acquire the lock. * * @param callable|null $callback - * @return bool + * @return mixed */ public function get($callback = null) { diff --git a/src/Illuminate/Contracts/Cache/Lock.php b/src/Illuminate/Contracts/Cache/Lock.php index 516f6ef38960..4f98d68d9301 100644 --- a/src/Illuminate/Contracts/Cache/Lock.php +++ b/src/Illuminate/Contracts/Cache/Lock.php @@ -8,7 +8,7 @@ interface Lock * Attempt to acquire the lock. * * @param callable|null $callback - * @return bool + * @return mixed */ public function get($callback = null); From 09154971d9f0f80e491ff534825ff0569ed6cf89 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Wed, 3 Apr 2019 14:09:41 +0200 Subject: [PATCH 1715/2459] exclude non-existing directories from event discovery --- .../Foundation/Support/Providers/EventServiceProvider.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php index 091bea466679..60d292bf0556 100644 --- a/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php +++ b/src/Illuminate/Foundation/Support/Providers/EventServiceProvider.php @@ -89,6 +89,9 @@ public function shouldDiscoverEvents() public function discoverEvents() { return collect($this->discoverEventsWithin()) + ->reject(function ($directory) { + return ! is_dir($directory); + }) ->reduce(function ($discovered, $directory) { return array_merge_recursive( $discovered, From 33ce7bbb6a7f536036b58b66cc760fbb9eda80de Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 4 Apr 2019 08:32:40 -0500 Subject: [PATCH 1716/2459] remove path hint --- src/Illuminate/View/Compilers/BladeCompiler.php | 4 ---- tests/View/ViewBladeCompilerTest.php | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 0f084b06ffec..e2612358cdeb 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -122,10 +122,6 @@ public function compile($path = null) $this->files->get($this->getPath()) ); - if (! empty($this->getPath())) { - $contents .= "\ngetPath()} */ ?>"; - } - $this->files->put( $this->getCompiledPath($this->getPath()), $contents ); diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index 67720dcc5cf1..c315dc9b4af5 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -49,7 +49,7 @@ public function testCompileCompilesFileAndReturnsContents() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World\n"); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World"); $compiler->compile('foo'); } @@ -57,7 +57,7 @@ public function testCompileCompilesAndGetThePath() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World\n"); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World"); $compiler->compile('foo'); $this->assertEquals('foo', $compiler->getPath()); } @@ -73,7 +73,7 @@ public function testCompileWithPathSetBefore() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World\n"); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World"); // set path before compilation $compiler->setPath('foo'); // trigger compilation with null $path @@ -97,7 +97,7 @@ public function testIncludePathToTemplate() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World\n"); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World"); $compiler->compile('foo'); } From 621ca8a3fd8fe9ea35ed97d80ae7d2a0de79d08a Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 4 Apr 2019 08:33:10 -0500 Subject: [PATCH 1717/2459] Apply fixes from StyleCI (#28114) --- tests/View/ViewBladeCompilerTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index c315dc9b4af5..3fa24de30d1c 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -49,7 +49,7 @@ public function testCompileCompilesFileAndReturnsContents() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World"); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); $compiler->compile('foo'); } @@ -57,7 +57,7 @@ public function testCompileCompilesAndGetThePath() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World"); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); $compiler->compile('foo'); $this->assertEquals('foo', $compiler->getPath()); } @@ -73,7 +73,7 @@ public function testCompileWithPathSetBefore() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World"); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); // set path before compilation $compiler->setPath('foo'); // trigger compilation with null $path @@ -97,7 +97,7 @@ public function testIncludePathToTemplate() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', "Hello World"); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); $compiler->compile('foo'); } From 11776a7a3a1f07da2ba8f62aca15247eb31283a9 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 4 Apr 2019 08:39:36 -0500 Subject: [PATCH 1718/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 5848b1c96e4b..a2a3b4e33b8c 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.8.9'; + const VERSION = '5.8.10'; /** * The base path for the Laravel installation. From 82ded9a28621b552589aba66e4e05f9a46f46db6 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 4 Apr 2019 11:22:41 -0500 Subject: [PATCH 1719/2459] realpath app during string replacement --- src/Illuminate/Foundation/Console/Kernel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Console/Kernel.php b/src/Illuminate/Foundation/Console/Kernel.php index e6ec50f10eb7..8b7745a49b4f 100644 --- a/src/Illuminate/Foundation/Console/Kernel.php +++ b/src/Illuminate/Foundation/Console/Kernel.php @@ -224,7 +224,7 @@ protected function load($paths) $command = $namespace.str_replace( ['/', '.php'], ['\\', ''], - Str::after($command->getPathname(), app_path().DIRECTORY_SEPARATOR) + Str::after($command->getPathname(), realpath(app_path()).DIRECTORY_SEPARATOR) ); if (is_subclass_of($command, Command::class) && From 6dd859397c614349f87fda660827900ab4363522 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Thu, 4 Apr 2019 18:32:21 +0200 Subject: [PATCH 1720/2459] Add view path to end of compiled blade view This re-adds the functionality that was added in https://github.com/laravel/framework/pull/27544 and https://github.com/laravel/framework/pull/27976 and removed again in https://github.com/laravel/framework/commit/33ce7bbb6a7f536036b58b66cc760fbb9eda80de. The main difference with this approach is that it takes into account the issue from https://github.com/laravel/framework/issues/27996. By not introducing a newline it doesn't changes anything to the rendered view itself. The path is now applied as the final piece of code. This doesn't allows IDE's to rely on it being the last line though. Instead we use /**PATH and ENDPATH**/ to make sure we have an easy way for the IDE to pick up the path it needs. --- src/Illuminate/View/Compilers/BladeCompiler.php | 4 ++++ tests/View/ViewBladeCompilerTest.php | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index e2612358cdeb..1dc4c180a211 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -122,6 +122,10 @@ public function compile($path = null) $this->files->get($this->getPath()) ); + if (! empty($this->getPath())) { + $contents .= "getPath()} ENDPATH**/ ?>"; + } + $this->files->put( $this->getCompiledPath($this->getPath()), $contents ); diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index 3fa24de30d1c..5344f2372299 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -49,7 +49,7 @@ public function testCompileCompilesFileAndReturnsContents() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); $compiler->compile('foo'); } @@ -57,7 +57,7 @@ public function testCompileCompilesAndGetThePath() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); $compiler->compile('foo'); $this->assertEquals('foo', $compiler->getPath()); } @@ -73,7 +73,7 @@ public function testCompileWithPathSetBefore() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); // set path before compilation $compiler->setPath('foo'); // trigger compilation with null $path @@ -97,7 +97,7 @@ public function testIncludePathToTemplate() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); $compiler->compile('foo'); } From f735b3d5ee81b59984da1a652f2665313a6fdb69 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Thu, 4 Apr 2019 23:02:35 +0300 Subject: [PATCH 1721/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 459033a5ecb9..1f586edfbd79 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -1,6 +1,20 @@ # Release Notes for 5.8.x -## [Unreleased](https://github.com/laravel/framework/compare/v5.8.9...5.8) +## [Unreleased](https://github.com/laravel/framework/compare/v5.8.10...5.8) + + +## [v5.8.10 (2019-04-04)](https://github.com/laravel/framework/compare/v5.8.9...v5.8.10) + +### Added +- Added `replicating` model event ([#28077](https://github.com/laravel/framework/pull/28077)) +- Make `NotificationFake` macroable ([#28091](https://github.com/laravel/framework/pull/28091)) + +### Fixed +- Exclude non-existing directories from event discovery ([#28098](https://github.com/laravel/framework/pull/28098)) + +### Changed +- Sorting of events in `event:list` command ([3437751](https://github.com/laravel/framework/commit/343775115722ed0e6c3455b72ee7204aefdf37d3)) +- Removed path hint in compiled view ([33ce7bb](https://github.com/laravel/framework/commit/33ce7bbb6a7f536036b58b66cc760fbb9eda80de)) ## [v5.8.9 (2019-04-02)](https://github.com/laravel/framework/compare/v5.8.8...v5.8.9) From 1bf41e9c994f7c04b054e021d5231131f178b892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nikolaou?= Date: Fri, 5 Apr 2019 21:43:47 +0300 Subject: [PATCH 1722/2459] Refactor DiscoverEvents::within() The pairs of listeners and events can be mapped to groups of listeners keyed by the event name. By using `mapToDictionary` we can void zipping the pairs and then unzipping them while reducing. --- .../Foundation/Events/DiscoverEvents.php | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/Illuminate/Foundation/Events/DiscoverEvents.php b/src/Illuminate/Foundation/Events/DiscoverEvents.php index 126b95d7225d..cdc03e57e03b 100644 --- a/src/Illuminate/Foundation/Events/DiscoverEvents.php +++ b/src/Illuminate/Foundation/Events/DiscoverEvents.php @@ -19,17 +19,12 @@ class DiscoverEvents */ public static function within($listenerPath, $basePath) { - $listenerEvents = collect(static::getListenerEvents((new Finder) - ->files() - ->in($listenerPath), $basePath)); - - return $listenerEvents->values() - ->zip($listenerEvents->keys()->all()) - ->reduce(function ($carry, $listenerEventPair) { - $carry[$listenerEventPair[0]][] = $listenerEventPair[1]; - - return $carry; - }, []); + return collect(static::getListenerEvents((new Finder) + ->files() + ->in($listenerPath), $basePath)) + ->mapToDictionary(function ($event, $listener) { + return [$event => $listener]; + })->all(); } /** From c05b7188134083830dc0a7f9f7983746aa9c67d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nikolaou?= Date: Sat, 6 Apr 2019 00:45:11 +0300 Subject: [PATCH 1723/2459] Allow lock to be configured in local filesystems --- src/Illuminate/Filesystem/FilesystemManager.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Filesystem/FilesystemManager.php b/src/Illuminate/Filesystem/FilesystemManager.php index 7897352c89b2..449216a62da8 100644 --- a/src/Illuminate/Filesystem/FilesystemManager.php +++ b/src/Illuminate/Filesystem/FilesystemManager.php @@ -159,8 +159,10 @@ public function createLocalDriver(array $config) ? LocalAdapter::SKIP_LINKS : LocalAdapter::DISALLOW_LINKS; + $lock = $config['lock'] ?? LOCK_EX; + return $this->adapt($this->createFlysystem(new LocalAdapter( - $config['root'], LOCK_EX, $links, $permissions + $config['root'], $lock, $links, $permissions ), $config)); } From 7621ba1ea9ab21a80812cf147f706f5422aac3ea Mon Sep 17 00:00:00 2001 From: KyleK Date: Sat, 6 Apr 2019 22:45:22 +0200 Subject: [PATCH 1724/2459] Allow to call macros directly on Date --- src/Illuminate/Support/DateFactory.php | 3 ++- tests/Support/DateFacadeTest.php | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/DateFactory.php b/src/Illuminate/Support/DateFactory.php index 4a8e9de23aff..f3ec06298046 100644 --- a/src/Illuminate/Support/DateFactory.php +++ b/src/Illuminate/Support/DateFactory.php @@ -212,7 +212,8 @@ public function __call($method, $parameters) $dateClass = static::$dateClass ?: $defaultClassName; // Check if date can be created using public class method... - if (method_exists($dateClass, $method)) { + if (method_exists($dateClass, $method) || + method_exists($dateClass, 'hasMacro') && $dateClass::hasMacro($method)) { return $dateClass::$method(...$parameters); } diff --git a/tests/Support/DateFacadeTest.php b/tests/Support/DateFacadeTest.php index 4eb836e57a3b..2ba45bcf25ee 100644 --- a/tests/Support/DateFacadeTest.php +++ b/tests/Support/DateFacadeTest.php @@ -92,4 +92,13 @@ public function testUseInvalidHandler() { DateFactory::use(42); } + + public function testMacro() + { + Date::macro('returnNonDate', function () { + return 'string'; + }); + + $this->assertSame('string', Date::returnNonDate()); + } } From 58360ffe7094be96e57c7c2628e3c080222867d0 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 7 Apr 2019 11:37:50 +0300 Subject: [PATCH 1725/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 1f586edfbd79..d0f697727e73 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -2,6 +2,12 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v5.8.10...5.8) +### Changed +- Added view path to end of compiled blade view (in case if path is not empty) ([#28117](https://github.com/laravel/framework/pull/28117)) + +### TODO +- https://github.com/laravel/framework/commit/82ded9a28621b552589aba66e4e05f9a46f46db6 + ## [v5.8.10 (2019-04-04)](https://github.com/laravel/framework/compare/v5.8.9...v5.8.10) From 200ce88b6bc9105a59b96a8bc84768311e7d8db6 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 8 Apr 2019 07:56:11 -0500 Subject: [PATCH 1726/2459] formatting --- src/Illuminate/Filesystem/FilesystemManager.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Filesystem/FilesystemManager.php b/src/Illuminate/Filesystem/FilesystemManager.php index 449216a62da8..36f9b89e6351 100644 --- a/src/Illuminate/Filesystem/FilesystemManager.php +++ b/src/Illuminate/Filesystem/FilesystemManager.php @@ -159,10 +159,8 @@ public function createLocalDriver(array $config) ? LocalAdapter::SKIP_LINKS : LocalAdapter::DISALLOW_LINKS; - $lock = $config['lock'] ?? LOCK_EX; - return $this->adapt($this->createFlysystem(new LocalAdapter( - $config['root'], $lock, $links, $permissions + $config['root'], $config['lock'] ?? LOCK_EX, $links, $permissions ), $config)); } From 006f999d8c629bf87ea0252447866a879d7d4a6e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 8 Apr 2019 07:59:49 -0500 Subject: [PATCH 1727/2459] formatting --- src/Illuminate/Foundation/Events/DiscoverEvents.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Foundation/Events/DiscoverEvents.php b/src/Illuminate/Foundation/Events/DiscoverEvents.php index cdc03e57e03b..fbef40d9d4ca 100644 --- a/src/Illuminate/Foundation/Events/DiscoverEvents.php +++ b/src/Illuminate/Foundation/Events/DiscoverEvents.php @@ -19,12 +19,11 @@ class DiscoverEvents */ public static function within($listenerPath, $basePath) { - return collect(static::getListenerEvents((new Finder) - ->files() - ->in($listenerPath), $basePath)) - ->mapToDictionary(function ($event, $listener) { - return [$event => $listener]; - })->all(); + return collect(static::getListenerEvents( + (new Finder)->files()->in($listenerPath), $basePath + ))->mapToDictionary(function ($event, $listener) { + return [$event => $listener]; + })->all(); } /** From dc8e71e174952f6810a9846a208395a17eee7569 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Mon, 8 Apr 2019 10:19:49 -0400 Subject: [PATCH 1728/2459] track the exit code of scheduled event commands --- src/Illuminate/Console/Scheduling/Event.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 758d688eaa0c..add567003610 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -143,6 +143,13 @@ class Event */ public $mutex; + /** + * The command exit status code. + * + * @var int + */ + public $exitCode; + /** * Create a new event instance. * @@ -208,7 +215,7 @@ protected function runCommandInForeground(Container $container) { $this->callBeforeCallbacks($container); - Process::fromShellCommandline($this->buildCommand(), base_path(), null, null, null)->run(); + $this->exitCode = Process::fromShellCommandline($this->buildCommand(), base_path(), null, null, null)->run(); $this->callAfterCallbacks($container); } From 95e451fcc434f9d555dec9bc65e366b2d0ce6d08 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 8 Apr 2019 16:38:01 -0500 Subject: [PATCH 1729/2459] Update Event.php --- src/Illuminate/Console/Scheduling/Event.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index add567003610..47f51124072d 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -144,9 +144,9 @@ class Event public $mutex; /** - * The command exit status code. + * The exit status code of the command. * - * @var int + * @var int|null */ public $exitCode; From c03f62ed499d7c1175923b929e82f6e361d85505 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 9 Apr 2019 12:37:57 +0200 Subject: [PATCH 1730/2459] configure application namespace while discovering events --- src/Illuminate/Foundation/Events/DiscoverEvents.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Events/DiscoverEvents.php b/src/Illuminate/Foundation/Events/DiscoverEvents.php index fbef40d9d4ca..c82ffc50c80d 100644 --- a/src/Illuminate/Foundation/Events/DiscoverEvents.php +++ b/src/Illuminate/Foundation/Events/DiscoverEvents.php @@ -67,6 +67,10 @@ protected static function classFromFile(SplFileInfo $file, $basePath) { $class = trim(str_replace($basePath, '', $file->getRealPath()), DIRECTORY_SEPARATOR); - return str_replace(DIRECTORY_SEPARATOR, '\\', ucfirst(Str::replaceLast('.php', '', $class))); + return str_replace( + [DIRECTORY_SEPARATOR, 'App\\'], + ['\\', app()->getNamespace()], + ucfirst(Str::replaceLast('.php', '', $class)) + ); } } From b1b10ec46e5657a4c1d15a7b449bf99424b2cdf1 Mon Sep 17 00:00:00 2001 From: Mohamed Said Date: Tue, 9 Apr 2019 13:05:20 +0200 Subject: [PATCH 1731/2459] fix tests --- .../EventDiscovery/Events/EventOne.php | 7 ------ .../EventDiscovery/Events/EventTwo.php | 7 ------ .../EventDiscovery/Listeners/Listener.php | 24 ------------------- .../Foundation/DiscoverEventsTest.php | 12 +++++----- .../EventDiscovery/Events/EventOne.php | 7 ++++++ .../EventDiscovery/Events/EventTwo.php | 7 ++++++ .../EventDiscovery/Listeners/Listener.php | 24 +++++++++++++++++++ 7 files changed, 44 insertions(+), 44 deletions(-) delete mode 100644 tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php delete mode 100644 tests/Foundation/Fixtures/EventDiscovery/Events/EventTwo.php delete mode 100644 tests/Foundation/Fixtures/EventDiscovery/Listeners/Listener.php rename tests/{ => Integration}/Foundation/DiscoverEventsTest.php (55%) create mode 100644 tests/Integration/Foundation/Fixtures/EventDiscovery/Events/EventOne.php create mode 100644 tests/Integration/Foundation/Fixtures/EventDiscovery/Events/EventTwo.php create mode 100644 tests/Integration/Foundation/Fixtures/EventDiscovery/Listeners/Listener.php diff --git a/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php b/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php deleted file mode 100644 index fbd2d849e6b7..000000000000 --- a/tests/Foundation/Fixtures/EventDiscovery/Events/EventOne.php +++ /dev/null @@ -1,7 +0,0 @@ - Date: Mon, 8 Apr 2019 15:41:14 +0200 Subject: [PATCH 1732/2459] Fix appending path to inline Blade views When appending the view path to Blade views with only one line and opening tags we should take into consideration for closing the PHP tag first before appending the path. I've addeded tests which should cover quite a few situations. Thanks to Sisve for making me aware of this: https://github.com/laravel/framework/pull/28117#issuecomment-480473139 --- .../View/Compilers/BladeCompiler.php | 24 ++++++++ tests/View/ViewBladeCompilerTest.php | 60 +++++++++++++++++-- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index 1dc4c180a211..a687c17f5dd0 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -123,6 +123,15 @@ public function compile($path = null) ); if (! empty($this->getPath())) { + $tokens = $this->getOpenAndClosingPHPTokens($contents); + + // If the tokens we retrieved from the compiled contents have at least + // one opening tag and if that last token isn't the closing tag, we + // need to close the statement before adding the path at the end. + if ($tokens->isNotEmpty() && $tokens->last() !== T_CLOSE_TAG) { + $contents .= ' ?>'; + } + $contents .= "getPath()} ENDPATH**/ ?>"; } @@ -132,6 +141,21 @@ public function compile($path = null) } } + /** + * Returns the open and closing PHP tag tokens which are present in the compiled contents. + * + * @param string $contents + * @return \Illuminate\Support\Collection + */ + protected function getOpenAndClosingPHPTokens($contents) + { + return collect(token_get_all($contents)) + ->pluck($tokenNumber = 0) + ->filter(function ($token) { + return in_array($token, [T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_CLOSE_TAG]); + }); + } + /** * Get the path currently being compiled. * diff --git a/tests/View/ViewBladeCompilerTest.php b/tests/View/ViewBladeCompilerTest.php index 5344f2372299..7e4df27e504d 100644 --- a/tests/View/ViewBladeCompilerTest.php +++ b/tests/View/ViewBladeCompilerTest.php @@ -76,7 +76,7 @@ public function testCompileWithPathSetBefore() $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); // set path before compilation $compiler->setPath('foo'); - // trigger compilation with null $path + // trigger compilation with $path $compiler->compile(); $this->assertEquals('foo', $compiler->getPath()); } @@ -93,14 +93,66 @@ public function testRawTagsCanBeSetToLegacyValues() }}')); } - public function testIncludePathToTemplate() + /** + * @param string $content + * @param string $compiled + * + * @dataProvider appendViewPathDataProvider + */ + public function testIncludePathToTemplate($content, $compiled) { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); - $files->shouldReceive('get')->once()->with('foo')->andReturn('Hello World'); - $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', 'Hello World'); + $files->shouldReceive('get')->once()->with('foo')->andReturn($content); + $files->shouldReceive('put')->once()->with(__DIR__.'/'.sha1('foo').'.php', $compiled); + $compiler->compile('foo'); } + /** + * @return array + */ + public function appendViewPathDataProvider() + { + return [ + 'No PHP blocks' => [ + 'Hello World', + 'Hello World', + ], + 'Single PHP block without closing ?>' => [ + '', + ], + 'Ending PHP block.' => [ + 'Hello world', + 'Hello world', + ], + 'Ending PHP block without closing ?>' => [ + 'Hello world', + ], + 'PHP block between content.' => [ + 'Hello worldHi There', + 'Hello worldHi There', + ], + 'Multiple PHP blocks.' => [ + 'Hello worldHi ThereHello Again', + 'Hello worldHi ThereHello Again', + ], + 'Multiple PHP blocks without closing ?>' => [ + 'Hello worldHi ThereHi There', + ], + 'Short open echo tag' => [ + 'Hello world', + ], + 'Echo XML declaration' => [ + '\';', + '\'; ?>', + ], + ]; + } + public function testDontIncludeEmptyPath() { $compiler = new BladeCompiler($files = $this->getFiles(), __DIR__); From e62dff85bacd09f106a4a447680620a3f3157e0e Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 10 Apr 2019 00:25:57 +0300 Subject: [PATCH 1733/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index d0f697727e73..f1051ca9e42b 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -2,11 +2,20 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v5.8.10...5.8) +### Added +- Allowed to call `macros` directly on `Illuminate\Support\Facades\Date` ([#28129](https://github.com/laravel/framework/pull/28129)) +- Allowed `lock` to be configured in `local filesystems` ([#28124](https://github.com/laravel/framework/pull/28124)) + ### Changed - Added view path to end of compiled blade view (in case if path is not empty) ([#28117](https://github.com/laravel/framework/pull/28117)) +### Refactoring +- Refactoring of `Illuminate\Foundation\Events\DiscoverEvents::within()` ([#28122](https://github.com/laravel/framework/pull/28122), [006f999](https://github.com/laravel/framework/commit/006f999d8c629bf87ea0252447866a879d7d4a6e)) + ### TODO - https://github.com/laravel/framework/commit/82ded9a28621b552589aba66e4e05f9a46f46db6 +- https://github.com/laravel/framework/pull/28140 +- https://github.com/laravel/framework/pull/28145 ## [v5.8.10 (2019-04-04)](https://github.com/laravel/framework/compare/v5.8.9...v5.8.10) From be1896cbeb2e413615fb61791101f8b199e1bf3d Mon Sep 17 00:00:00 2001 From: Brent Roose Date: Wed, 10 Apr 2019 11:39:39 +0200 Subject: [PATCH 1734/2459] Correctly escape single quotes in json paths --- .../Database/Query/Grammars/Grammar.php | 2 ++ tests/Database/DatabaseQueryBuilderTest.php | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index 2554d80ede29..51d10042e776 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -1119,6 +1119,8 @@ protected function wrapJsonFieldAndPath($column) */ protected function wrapJsonPath($value, $delimiter = '->') { + $value = preg_replace("/([\\\\]+)?\\'/", "\\'", $value); + return '\'$."'.str_replace($delimiter, '"."', $value).'"\''; } diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index ec8946d5bd43..556e0f87711c 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2252,6 +2252,25 @@ public function testMySqlWrappingJsonWithBooleanAndIntegerThatLooksLikeOne() $this->assertEquals('select * from `users` where json_extract(`items`, \'$."available"\') = true and json_extract(`items`, \'$."active"\') = false and json_unquote(json_extract(`items`, \'$."number_available"\')) = ?', $builder->toSql()); } + public function testJsonPathEscaping() + { + $expectedJsonEscape = <<getMySqlBuilder(); + $builder->select("json->'))#"); + $this->assertEquals($expectedJsonEscape, $builder->toSql()); + + $builder = $this->getMySqlBuilder(); + $builder->select("json->\'))#"); + $this->assertEquals($expectedJsonEscape, $builder->toSql()); + + $builder = $this->getMySqlBuilder(); + $builder->select("json->\\\'))#"); + $this->assertEquals($expectedJsonEscape, $builder->toSql()); + } + public function testMySqlWrappingJson() { $builder = $this->getMySqlBuilder(); From ea41e9092e906328ce944e808a825bde5433a565 Mon Sep 17 00:00:00 2001 From: Brent Roose Date: Wed, 10 Apr 2019 12:43:22 +0200 Subject: [PATCH 1735/2459] Improve naming --- tests/Database/DatabaseQueryBuilderTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 556e0f87711c..37e774cb6549 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2254,21 +2254,21 @@ public function testMySqlWrappingJsonWithBooleanAndIntegerThatLooksLikeOne() public function testJsonPathEscaping() { - $expectedJsonEscape = <<getMySqlBuilder(); $builder->select("json->'))#"); - $this->assertEquals($expectedJsonEscape, $builder->toSql()); + $this->assertEquals($expectedWithJsonEscaped, $builder->toSql()); $builder = $this->getMySqlBuilder(); $builder->select("json->\'))#"); - $this->assertEquals($expectedJsonEscape, $builder->toSql()); + $this->assertEquals($expectedWithJsonEscaped, $builder->toSql()); $builder = $this->getMySqlBuilder(); $builder->select("json->\\\'))#"); - $this->assertEquals($expectedJsonEscape, $builder->toSql()); + $this->assertEquals($expectedWithJsonEscaped, $builder->toSql()); } public function testMySqlWrappingJson() From 93f59c4244698c59f7b419008bce5767168d70d1 Mon Sep 17 00:00:00 2001 From: Brent Roose Date: Wed, 10 Apr 2019 12:44:04 +0200 Subject: [PATCH 1736/2459] Extra test --- tests/Database/DatabaseQueryBuilderTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 37e774cb6549..ef1b3c871641 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -2266,6 +2266,10 @@ public function testJsonPathEscaping() $builder->select("json->\'))#"); $this->assertEquals($expectedWithJsonEscaped, $builder->toSql()); + $builder = $this->getMySqlBuilder(); + $builder->select("json->\\'))#"); + $this->assertEquals($expectedWithJsonEscaped, $builder->toSql()); + $builder = $this->getMySqlBuilder(); $builder->select("json->\\\'))#"); $this->assertEquals($expectedWithJsonEscaped, $builder->toSql()); From 06d6b7218312742358568058d9c4a4d604ed7b52 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 10 Apr 2019 07:42:07 -0500 Subject: [PATCH 1737/2459] Update BladeCompiler.php --- src/Illuminate/View/Compilers/BladeCompiler.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/View/Compilers/BladeCompiler.php b/src/Illuminate/View/Compilers/BladeCompiler.php index a687c17f5dd0..f5bc484c1eb4 100644 --- a/src/Illuminate/View/Compilers/BladeCompiler.php +++ b/src/Illuminate/View/Compilers/BladeCompiler.php @@ -123,7 +123,7 @@ public function compile($path = null) ); if (! empty($this->getPath())) { - $tokens = $this->getOpenAndClosingPHPTokens($contents); + $tokens = $this->getOpenAndClosingPhpTokens($contents); // If the tokens we retrieved from the compiled contents have at least // one opening tag and if that last token isn't the closing tag, we @@ -142,12 +142,12 @@ public function compile($path = null) } /** - * Returns the open and closing PHP tag tokens which are present in the compiled contents. + * Get the open and closing PHP tag tokens from the given string. * * @param string $contents * @return \Illuminate\Support\Collection */ - protected function getOpenAndClosingPHPTokens($contents) + protected function getOpenAndClosingPhpTokens($contents) { return collect(token_get_all($contents)) ->pluck($tokenNumber = 0) From a2cf7a7983329d63edc6fde43142b232bb61aa0a Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 10 Apr 2019 08:05:18 -0500 Subject: [PATCH 1738/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index a2a3b4e33b8c..ac1db13b9e78 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.8.10'; + const VERSION = '5.8.11'; /** * The base path for the Laravel installation. From f8c0ce7fc1ff93ddfcc1f7064fea420338ad2ed8 Mon Sep 17 00:00:00 2001 From: kauanslr Date: Wed, 10 Apr 2019 10:35:51 -0300 Subject: [PATCH 1739/2459] Fixed circular dependency --- .../Support/Testing/Fakes/QueueFake.php | 15 +++++++++++++++ tests/Support/SupportTestingQueueFakeTest.php | 12 ++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/Illuminate/Support/Testing/Fakes/QueueFake.php b/src/Illuminate/Support/Testing/Fakes/QueueFake.php index bfb02158bbb9..d8dbe56cd0b8 100644 --- a/src/Illuminate/Support/Testing/Fakes/QueueFake.php +++ b/src/Illuminate/Support/Testing/Fakes/QueueFake.php @@ -2,6 +2,7 @@ namespace Illuminate\Support\Testing\Fakes; +use BadMethodCallException; use Illuminate\Queue\QueueManager; use Illuminate\Contracts\Queue\Queue; use PHPUnit\Framework\Assert as PHPUnit; @@ -357,4 +358,18 @@ public function setConnectionName($name) { return $this; } + + /** + * Override the parent to prevent circular dependency + * + * @param string $method + * @param array $parameters + * @return mixed + */ + public function __call($method, $parameters) + { + throw new BadMethodCallException(sprintf( + 'Call to undefined method %s::%s()', static::class, $method + )); + } } diff --git a/tests/Support/SupportTestingQueueFakeTest.php b/tests/Support/SupportTestingQueueFakeTest.php index 86f296ba009c..22f48d91f94d 100644 --- a/tests/Support/SupportTestingQueueFakeTest.php +++ b/tests/Support/SupportTestingQueueFakeTest.php @@ -2,6 +2,7 @@ namespace Illuminate\Tests\Support; +use BadMethodCallException; use Illuminate\Bus\Queueable; use PHPUnit\Framework\TestCase; use Illuminate\Foundation\Application; @@ -227,6 +228,17 @@ public function testAssertPushedWithChainErrorHandling() $this->assertThat($e, new ExceptionMessage('The expected chain was not pushed')); } } + + public function testCallUndefinedMethodErrorHandling() + { + try { + $this->fake->undefinedMethod(); + } catch (BadMethodCallException $e) { + $this->assertThat($e, new ExceptionMessage(sprintf( + 'Call to undefined method %s::%s()', get_class($this->fake), 'undefinedMethod' + ))); + } + } } class JobStub From 000d5e817a684cc1ee55a9e5c0afb9cf454b748c Mon Sep 17 00:00:00 2001 From: kauanslr Date: Wed, 10 Apr 2019 10:46:55 -0300 Subject: [PATCH 1740/2459] StyleCI fix --- src/Illuminate/Support/Testing/Fakes/QueueFake.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Testing/Fakes/QueueFake.php b/src/Illuminate/Support/Testing/Fakes/QueueFake.php index d8dbe56cd0b8..d9044641926b 100644 --- a/src/Illuminate/Support/Testing/Fakes/QueueFake.php +++ b/src/Illuminate/Support/Testing/Fakes/QueueFake.php @@ -360,7 +360,7 @@ public function setConnectionName($name) } /** - * Override the parent to prevent circular dependency + * Override the parent to prevent circular dependency. * * @param string $method * @param array $parameters From db6ccede39af84d96bc2dbc7f628167ac4677e07 Mon Sep 17 00:00:00 2001 From: kauanslr Date: Wed, 10 Apr 2019 14:14:11 -0300 Subject: [PATCH 1741/2459] Changed docblock --- src/Illuminate/Support/Testing/Fakes/QueueFake.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Testing/Fakes/QueueFake.php b/src/Illuminate/Support/Testing/Fakes/QueueFake.php index d9044641926b..dbe73ddf7d22 100644 --- a/src/Illuminate/Support/Testing/Fakes/QueueFake.php +++ b/src/Illuminate/Support/Testing/Fakes/QueueFake.php @@ -360,7 +360,7 @@ public function setConnectionName($name) } /** - * Override the parent to prevent circular dependency. + * Override the QueueManager to prevent circular dependency. * * @param string $method * @param array $parameters From e81aa77c8440875bd7434fee19cba5c0692c28e4 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Wed, 10 Apr 2019 14:49:23 -0400 Subject: [PATCH 1742/2459] add schedule event helpers to deal with successful/failed commands --- src/Illuminate/Console/Scheduling/Event.php | 76 +++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index 47f51124072d..c0ea965e47ae 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -662,6 +662,82 @@ public function then(Closure $callback) return $this; } + /** + * Register a callback to be called after the operation if it was successful. + * + * @param \Closure $callback + * @return $this + */ + public function onSuccess(Closure $callback) + { + return $this->then(function (Container $container) use ($callback) { + if (0 === $this->exitCode) { + $container->call($callback); + } + }); + } + + /** + * Register a callback to be called after the operation if it failed. + * + * @param \Closure $callback + * @return $this + */ + public function onFailure(Closure $callback) + { + return $this->then(function (Container $container) use ($callback) { + if (0 !== $this->exitCode) { + $container->call($callback); + } + }); + } + + /** + * Register a callback to ping a given URL after the job runs if it was successful. + * + * @param string $url + * @return $this + */ + public function pingOnSuccess($url) + { + return $this->onSuccess(function () use ($url) { + (new HttpClient)->get($url); + }); + } + + /** + * Register a callback to ping a given URL after the job runs if it failed. + * + * @param string $url + * @return $this + */ + public function pingOnFailure($url) + { + return $this->onFailure(function () use ($url) { + (new HttpClient)->get($url); + }); + } + + /** + * E-mail the results of the scheduled operation if it failed. + * + * @param array|mixed $addresses + * @return $this + */ + public function emailOnFailure($addresses) + { + $this->ensureOutputIsBeingCaptured(); + + $addresses = Arr::wrap($addresses); + + return $this->onFailure(function (Mailer $mailer) use ($addresses) { + $oldDescription = $this->description; + $this->description = '[FAILURE] '.$this->getEmailSubject(); + $this->emailOutput($mailer, $addresses, false); + $this->description = $oldDescription; + }); + } + /** * Set the human-friendly description of the event. * From 064012f0763de553193cf80804be727f324c39ff Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Wed, 10 Apr 2019 22:30:10 +0300 Subject: [PATCH 1743/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index f1051ca9e42b..7fb2d9285f96 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -1,22 +1,26 @@ # Release Notes for 5.8.x -## [Unreleased](https://github.com/laravel/framework/compare/v5.8.10...5.8) +## [Unreleased](https://github.com/laravel/framework/compare/v5.8.11...5.8) + + +## [v5.8.11 (2019-04-10)](https://github.com/laravel/framework/compare/v5.8.10...v5.8.11) ### Added - Allowed to call `macros` directly on `Illuminate\Support\Facades\Date` ([#28129](https://github.com/laravel/framework/pull/28129)) - Allowed `lock` to be configured in `local filesystems` ([#28124](https://github.com/laravel/framework/pull/28124)) +- Added tracking of the exit code in scheduled event commands ([#28140](https://github.com/laravel/framework/pull/28140)) + +### Fixed +- Fixed of escaping single quotes in json paths in `Illuminate\Database\Query\Grammars\Grammar` ([#28160](https://github.com/laravel/framework/pull/28160)) +- Fixed event discovery with different Application Namespace ([#28145](https://github.com/laravel/framework/pull/28145)) ### Changed -- Added view path to end of compiled blade view (in case if path is not empty) ([#28117](https://github.com/laravel/framework/pull/28117)) +- Added view path to end of compiled blade view (in case if path is not empty) ([#28117](https://github.com/laravel/framework/pull/28117), [#28141](https://github.com/laravel/framework/pull/28141)) +- Added `realpath` to `app_path` during string replacement in `Illuminate\Foundation\Console\Kernel::load()` ([82ded9a](https://github.com/laravel/framework/commit/82ded9a28621b552589aba66e4e05f9a46f46db6)) ### Refactoring - Refactoring of `Illuminate\Foundation\Events\DiscoverEvents::within()` ([#28122](https://github.com/laravel/framework/pull/28122), [006f999](https://github.com/laravel/framework/commit/006f999d8c629bf87ea0252447866a879d7d4a6e)) -### TODO -- https://github.com/laravel/framework/commit/82ded9a28621b552589aba66e4e05f9a46f46db6 -- https://github.com/laravel/framework/pull/28140 -- https://github.com/laravel/framework/pull/28145 - ## [v5.8.10 (2019-04-04)](https://github.com/laravel/framework/compare/v5.8.9...v5.8.10) From c19c04e383778f7a94e9f770d7a85ff45d4dd372 Mon Sep 17 00:00:00 2001 From: Joao Pedro Henrique Date: Wed, 10 Apr 2019 18:05:07 -0300 Subject: [PATCH 1744/2459] Added SET datatype on MySQL Grammar --- src/Illuminate/Database/Schema/Blueprint.php | 12 ++++++++++++ .../Database/Schema/Grammars/MySqlGrammar.php | 11 +++++++++++ tests/Database/DatabaseMySqlSchemaGrammarTest.php | 13 +++++++++++++ 3 files changed, 36 insertions(+) diff --git a/src/Illuminate/Database/Schema/Blueprint.php b/src/Illuminate/Database/Schema/Blueprint.php index d2442fbbd309..1a0192d08c31 100755 --- a/src/Illuminate/Database/Schema/Blueprint.php +++ b/src/Illuminate/Database/Schema/Blueprint.php @@ -856,6 +856,18 @@ public function enum($column, array $allowed) return $this->addColumn('enum', $column, compact('allowed')); } + /** + * Create a new set column on the table. + * + * @param string $column + * @param array $allowed + * @return \Illuminate\Database\Schema\ColumnDefinition + */ + public function set($column, array $allowed) + { + return $this->addColumn('set', $column, compact('allowed')); + } + /** * Create a new json column on the table. * diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 7d476c171cbc..7137b3edffc6 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -590,6 +590,17 @@ protected function typeEnum(Fluent $column) return sprintf('enum(%s)', $this->quoteString($column->allowed)); } + /** + * Create the column definition for a set enumeration type. + * + * @param \Illuminate\Support\Fluent $column + * @return string + */ + protected function typeSet(Fluent $column) + { + return sprintf('set(%s)', $this->quoteString($column->allowed)); + } + /** * Create the column definition for a json type. * diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index 22c206a3b5c8..dcbffb865129 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -9,6 +9,9 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Grammars\MySqlGrammar; +/** + * @group setTest + */ class DatabaseMySqlSchemaGrammarTest extends TestCase { protected function tearDown(): void @@ -620,6 +623,16 @@ public function testAddingEnum() $this->assertEquals('alter table `users` add `role` enum(\'member\', \'admin\') not null', $statements[0]); } + public function testAddingSet() + { + $blueprint = new Blueprint('users'); + $blueprint->set('role', ['member', 'admin']); + $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); + + $this->assertCount(1, $statements); + $this->assertEquals('alter table `users` add `role` set(\'member\', \'admin\') not null', $statements[0]); + } + public function testAddingJson() { $blueprint = new Blueprint('users'); From 1d348b1a7956242f439d56077f881675cddad94d Mon Sep 17 00:00:00 2001 From: Jonathan Gawrych Date: Wed, 10 Apr 2019 12:42:48 -0600 Subject: [PATCH 1745/2459] Make inequality validation fail on different types rather than 500 There are four types of inequality validators: lt, lte, gt, gte. If these validators reference another attribute, the attribute must be of the same type. Before this change, if the payload has different types, a 500 error is given. However, the type is not determine by the rule configuration, but rather the HTTP request. Instead of throwing an error, just fail the validation. --- .../Concerns/ValidatesAttributes.php | 28 +++++++++++-------- tests/Validation/ValidationValidatorTest.php | 24 ++++++++++++++++ 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 28371530e633..98eda67680aa 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -891,7 +891,9 @@ public function validateGt($attribute, $value, $parameters) return $this->getSize($attribute, $value) > $parameters[0]; } - $this->requireSameType($value, $comparedToValue); + if (! $this->isSameType($value, $comparedToValue)) { + return false; + } return $this->getSize($attribute, $value) > $this->getSize($attribute, $comparedToValue); } @@ -916,7 +918,9 @@ public function validateLt($attribute, $value, $parameters) return $this->getSize($attribute, $value) < $parameters[0]; } - $this->requireSameType($value, $comparedToValue); + if (! $this->isSameType($value, $comparedToValue)) { + return false; + } return $this->getSize($attribute, $value) < $this->getSize($attribute, $comparedToValue); } @@ -941,7 +945,9 @@ public function validateGte($attribute, $value, $parameters) return $this->getSize($attribute, $value) >= $parameters[0]; } - $this->requireSameType($value, $comparedToValue); + if (! $this->isSameType($value, $comparedToValue)) { + return false; + } return $this->getSize($attribute, $value) >= $this->getSize($attribute, $comparedToValue); } @@ -966,7 +972,9 @@ public function validateLte($attribute, $value, $parameters) return $this->getSize($attribute, $value) <= $parameters[0]; } - $this->requireSameType($value, $comparedToValue); + if (! $this->isSameType($value, $comparedToValue)) { + return false; + } return $this->getSize($attribute, $value) <= $this->getSize($attribute, $comparedToValue); } @@ -1721,19 +1729,15 @@ public function requireParameterCount($count, $parameters, $rule) } /** - * Require comparison values to be of the same type. + * Check if the parameters are of the same type. * * @param mixed $first * @param mixed $second - * @return void - * - * @throws \InvalidArgumentException + * @return bool */ - protected function requireSameType($first, $second) + protected function isSameType($first, $second) { - if (gettype($first) != gettype($second)) { - throw new InvalidArgumentException('The values under comparison must be of the same type'); - } + return gettype($first) == gettype($second); } /** diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index bea82017deaf..a615df2e37db 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1085,6 +1085,12 @@ public function testGreaterThan() $v = new Validator($trans, ['lhs' => 15, 'rhs' => 10], ['lhs' => 'numeric|gt:rhs']); $this->assertTrue($v->passes()); + $v = new Validator($trans, ['lhs' => 15, 'rhs' => 'string'], ['lhs' => 'numeric|gt:rhs']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['lhs' => 15], ['lhs' => 'numeric|gt:rhs']); + $this->assertTrue($v->fails()); + $v = new Validator($trans, ['lhs' => 'longer string', 'rhs' => 'string'], ['lhs' => 'gt:rhs']); $this->assertTrue($v->passes()); @@ -1108,6 +1114,12 @@ public function testLessThan() $v = new Validator($trans, ['lhs' => 15, 'rhs' => 10], ['lhs' => 'numeric|lt:rhs']); $this->assertTrue($v->fails()); + $v = new Validator($trans, ['lhs' => 15, 'rhs' => 'string'], ['lhs' => 'numeric|lt:rhs']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['lhs' => 15], ['lhs' => 'numeric|lt:rhs']); + $this->assertTrue($v->fails()); + $v = new Validator($trans, ['lhs' => 'longer string', 'rhs' => 'string'], ['lhs' => 'lt:rhs']); $this->assertTrue($v->fails()); @@ -1131,6 +1143,12 @@ public function testGreaterThanOrEqual() $v = new Validator($trans, ['lhs' => 15, 'rhs' => 15], ['lhs' => 'numeric|gte:rhs']); $this->assertTrue($v->passes()); + $v = new Validator($trans, ['lhs' => 15, 'rhs' => 'string'], ['lhs' => 'numeric|gte:rhs']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['lhs' => 15], ['lhs' => 'numeric|gte:rhs']); + $this->assertTrue($v->fails()); + $v = new Validator($trans, ['lhs' => 'longer string', 'rhs' => 'string'], ['lhs' => 'gte:rhs']); $this->assertTrue($v->passes()); @@ -1154,6 +1172,12 @@ public function testLessThanOrEqual() $v = new Validator($trans, ['lhs' => 15, 'rhs' => 15], ['lhs' => 'numeric|lte:rhs']); $this->assertTrue($v->passes()); + $v = new Validator($trans, ['lhs' => 15, 'rhs' => 'string'], ['lhs' => 'numeric|lte:rhs']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['lhs' => 15], ['lhs' => 'numeric|lte:rhs']); + $this->assertTrue($v->fails()); + $v = new Validator($trans, ['lhs' => 'longer string', 'rhs' => 'string'], ['lhs' => 'lte:rhs']); $this->assertTrue($v->fails()); From 89d635410bb3cc45a0fe7af75421e9fabf140ee5 Mon Sep 17 00:00:00 2001 From: Michael Tsang Date: Thu, 11 Apr 2019 10:27:45 +0800 Subject: [PATCH 1746/2459] fix enum definition not producing N-quoted string on Sql Server --- .../Database/Schema/Grammars/SqlServerGrammar.php | 15 +++++++++++++++ .../DatabaseSqlServerSchemaGrammarTest.php | 12 +++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index 8d057f5bdf9b..7cc861e5b521 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -824,4 +824,19 @@ public function wrapTable($table) return parent::wrapTable($table); } + + /** + * Quote the given string literal. + * + * @param string|array $value + * @return string + */ + public function quoteString($value) + { + if (is_array($value)) { + return implode(', ', array_map([$this, __FUNCTION__], $value)); + } + + return "N'$value'"; + } } diff --git a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php index 7e4c9b224dc8..685c23791947 100755 --- a/tests/Database/DatabaseSqlServerSchemaGrammarTest.php +++ b/tests/Database/DatabaseSqlServerSchemaGrammarTest.php @@ -472,7 +472,7 @@ public function testAddingEnum() $statements = $blueprint->toSql($this->getConnection(), $this->getGrammar()); $this->assertCount(1, $statements); - $this->assertEquals('alter table "users" add "role" nvarchar(255) check ("role" in (\'member\', \'admin\')) not null', $statements[0]); + $this->assertEquals('alter table "users" add "role" nvarchar(255) check ("role" in (N\'member\', N\'admin\')) not null', $statements[0]); } public function testAddingJson() @@ -793,6 +793,16 @@ public function testGrammarsAreMacroable() $this->assertTrue($c); } + public function testQuoteString() + { + $this->assertSame("N'中文測試'", $this->getGrammar()->quoteString('中文測試')); + } + + public function testQuoteStringOnArray() + { + $this->assertSame("N'中文', N'測試'", $this->getGrammar()->quoteString(['中文', '測試'])); + } + protected function getConnection() { return m::mock(Connection::class); From be0893949c4d844f23628164dca369982bd71032 Mon Sep 17 00:00:00 2001 From: Quynh Xuan Nguyen Date: Thu, 11 Apr 2019 10:30:28 +0700 Subject: [PATCH 1747/2459] Improve event list command --- .../Foundation/Console/EventListCommand.php | 68 +++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Foundation/Console/EventListCommand.php b/src/Illuminate/Foundation/Console/EventListCommand.php index 15880e9a0bdf..4b5b9c2b2cd6 100644 --- a/src/Illuminate/Foundation/Console/EventListCommand.php +++ b/src/Illuminate/Foundation/Console/EventListCommand.php @@ -2,6 +2,7 @@ namespace Illuminate\Foundation\Console; +use Illuminate\Support\Str; use Illuminate\Console\Command; use Illuminate\Foundation\Support\Providers\EventServiceProvider; @@ -12,7 +13,7 @@ class EventListCommand extends Command * * @var string */ - protected $signature = 'event:list'; + protected $signature = 'event:list {--event= : The event name}'; /** * The console command description. @@ -21,6 +22,13 @@ class EventListCommand extends Command */ protected $description = "List the application's events and listeners"; + /** + * The table headers for the command. + * + * @var array + */ + protected $headers = ['Event', 'Listeners']; + /** * Execute the console command. * @@ -28,7 +36,17 @@ class EventListCommand extends Command */ public function handle() { - $this->table(['Event', 'Listeners'], $this->getEvents()); + $events = $this->getEvents(); + + if (empty($events)) { + if ($this->isSearching()) { + return $this->error('Your application doesn\'t have any events matching the given criteria.'); + } + + return $this->error('Your application doesn\'t has any events, listeners.'); + } + + $this->displayEvents($events); } /** @@ -46,8 +64,50 @@ protected function getEvents() $events = array_merge_recursive($events, $providerEvents); } - return collect($events)->map(function ($value, $key) { - return ['Event' => $key, 'Listeners' => implode("\n", $value)]; + if ($this->isSearching()) { + $events = $this->filterEvents($events); + } + + return collect($events)->map(function ($listeners, $event) { + return ['Event' => $event, 'Listeners' => implode(PHP_EOL, $listeners)]; })->sortBy('Event')->values()->toArray(); } + + /** + * Determine whether the user is searching event. + * + * @return bool + */ + protected function isSearching() + { + return $this->input->hasParameterOption('--event'); + } + + /** + * Filter the given events. + * + * @param array $events + * @return array + */ + protected function filterEvents(array $events) + { + return collect($events)->filter(function ($listeners, $event) { + if ($this->option('event')) { + return Str::contains($event, $this->option('event')); + } + + return true; + })->toArray(); + } + + /** + * Display the event listeners information on the console. + * + * @param array $events + * @return void + */ + protected function displayEvents(array $events) + { + $this->table($this->headers, $events); + } } From dc4d98966c4ab4cce090b4feba5cb7f61d5b3f79 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Thu, 11 Apr 2019 16:46:10 +1000 Subject: [PATCH 1748/2459] add duplicates method to collection --- src/Illuminate/Support/Collection.php | 43 ++++++++++++++++++++ tests/Support/SupportCollectionTest.php | 54 +++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 278038a0b29b..9440d6907a46 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -407,6 +407,49 @@ public function diffKeysUsing($items, callable $callback) return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback)); } + /** + * Retrieve duplicate items from the collection. + * + * @param callable|null $callback + * @param bool $strict + * @return static + */ + public function duplicates($callback = null, $strict = false) + { + $items = $this->map($this->valueRetriever($callback)); + + $uniqueItems = $items->unique(null, $strict); + + $compare = $strict ? function ($a, $b) { + return $a === $b; + } : function ($a, $b) { + return $a == $b; + }; + + $duplicates = new static; + + foreach ($items as $key => $value) { + if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) { + $uniqueItems->shift(); + } else { + $duplicates[$key] = $value; + } + } + + return $duplicates; + } + + /** + * Retrieve duplicate items from the collection using strict comparison. + * + * @param callable|null $callback + * @return static + */ + public function duplicatesStrict($callback = null) + { + return $this->duplicates($callback, true); + } + /** * Execute a callback over each item. * diff --git a/tests/Support/SupportCollectionTest.php b/tests/Support/SupportCollectionTest.php index d075d7051f2f..24e0472ced61 100755 --- a/tests/Support/SupportCollectionTest.php +++ b/tests/Support/SupportCollectionTest.php @@ -745,6 +745,60 @@ public function testDiffAssocUsing() $this->assertEquals(['b' => 'brown', 'c' => 'blue', 'red'], $c1->diffAssocUsing($c2, 'strcasecmp')->all()); } + public function testDuplicates() + { + $duplicates = Collection::make([1, 2, 1, 'laravel', null, 'laravel', 'php', null])->duplicates()->all(); + $this->assertSame([2 => 1, 5 => 'laravel', 7 => null], $duplicates); + + // does loose comparison + $duplicates = Collection::make([2, '2', [], null])->duplicates()->all(); + $this->assertSame([1 => '2', 3 => null], $duplicates); + + // works with mix of primitives + $duplicates = Collection::make([1, '2', ['laravel'], ['laravel'], null, '2'])->duplicates()->all(); + $this->assertSame([3 => ['laravel'], 5 => '2'], $duplicates); + + // works with mix of objects and primitives **excepts numbers**. + $expected = new Collection(['laravel']); + $duplicates = Collection::make([new Collection(['laravel']), $expected, $expected, [], '2', '2'])->duplicates()->all(); + $this->assertSame([1 => $expected, 2 => $expected, 5 => '2'], $duplicates); + } + + public function testDuplicatesWithKey() + { + $items = [['framework' => 'vue'], ['framework' => 'laravel'], ['framework' => 'laravel']]; + $duplicates = Collection::make($items)->duplicates('framework')->all(); + $this->assertSame([2 => 'laravel'], $duplicates); + } + + public function testDuplicatesWithCallback() + { + $items = [['framework' => 'vue'], ['framework' => 'laravel'], ['framework' => 'laravel']]; + $duplicates = Collection::make($items)->duplicates(function ($item) { + return $item['framework']; + })->all(); + $this->assertSame([2 => 'laravel'], $duplicates); + } + + public function testDuplicatesWithStrict() + { + $duplicates = Collection::make([1, 2, 1, 'laravel', null, 'laravel', 'php', null])->duplicatesStrict()->all(); + $this->assertSame([2 => 1, 5 => 'laravel', 7 => null], $duplicates); + + // does strict comparison + $duplicates = Collection::make([2, '2', [], null])->duplicatesStrict()->all(); + $this->assertSame([], $duplicates); + + // works with mix of primitives + $duplicates = Collection::make([1, '2', ['laravel'], ['laravel'], null, '2'])->duplicatesStrict()->all(); + $this->assertSame([3 => ['laravel'], 5 => '2'], $duplicates); + + // works with mix of primitives, objects, and numbers + $expected = new Collection(['laravel']); + $duplicates = Collection::make([new Collection(['laravel']), $expected, $expected, [], '2', '2'])->duplicatesStrict()->all(); + $this->assertSame([2 => $expected, 5 => '2'], $duplicates); + } + public function testEach() { $c = new Collection($original = [1, 2, 'foo' => 'bar', 'bam' => 'baz']); From b86a42445422a5fe25da88e9c1f31fb03e77a7f2 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Thu, 11 Apr 2019 17:28:45 +1000 Subject: [PATCH 1749/2459] style fix --- src/Illuminate/Support/Collection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 9440d6907a46..0262fe1acce3 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -422,7 +422,8 @@ public function duplicates($callback = null, $strict = false) $compare = $strict ? function ($a, $b) { return $a === $b; - } : function ($a, $b) { + } + : function ($a, $b) { return $a == $b; }; From 73e63ed88ab1fdd39d24f3f2a2b5d32d9eb3b30d Mon Sep 17 00:00:00 2001 From: Oliver Sarfas Date: Thu, 11 Apr 2019 11:01:06 +0100 Subject: [PATCH 1750/2459] Fix issue #28184 --- src/Illuminate/Database/Query/Builder.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 0b63446e982b..dacf672b5d28 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -1198,6 +1198,8 @@ public function whereDay($column, $operator, $value = null, $boolean = 'and') $value = $value->format('d'); } + $value = str_pad($value, 2, '0', STR_PAD_LEFT); + return $this->addDateBasedWhere('Day', $column, $operator, $value, $boolean); } @@ -1237,6 +1239,8 @@ public function whereMonth($column, $operator, $value = null, $boolean = 'and') $value = $value->format('m'); } + $value = str_pad($value, 2, '0', STR_PAD_LEFT); + return $this->addDateBasedWhere('Month', $column, $operator, $value, $boolean); } From 039a9745315f50e69d41b96a18e5b6131e8e164a Mon Sep 17 00:00:00 2001 From: Oliver Sarfas Date: Thu, 11 Apr 2019 11:08:07 +0100 Subject: [PATCH 1751/2459] add unit tests --- tests/Integration/Database/QueryBuilderTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Integration/Database/QueryBuilderTest.php b/tests/Integration/Database/QueryBuilderTest.php index abd27439fdb5..b6238cc0a313 100644 --- a/tests/Integration/Database/QueryBuilderTest.php +++ b/tests/Integration/Database/QueryBuilderTest.php @@ -36,12 +36,14 @@ public function testWhereDate() public function testWhereDay() { $this->assertSame(1, DB::table('posts')->whereDay('created_at', '02')->count()); + $this->assertSame(1, DB::table('posts')->whereDay('created_at', 2)->count()); $this->assertSame(1, DB::table('posts')->whereDay('created_at', new Carbon('2018-01-02'))->count()); } public function testWhereMonth() { $this->assertSame(1, DB::table('posts')->whereMonth('created_at', '01')->count()); + $this->assertSame(1, DB::table('posts')->whereMonth('created_at', 1)->count()); $this->assertSame(1, DB::table('posts')->whereMonth('created_at', new Carbon('2018-01-02'))->count()); } From eabf73c99cd4d7fc8c767cd707884608e70215f7 Mon Sep 17 00:00:00 2001 From: Mark Walet Date: Thu, 11 Apr 2019 13:36:13 +0200 Subject: [PATCH 1752/2459] Add static `rename` method to facade docblocks This method is statically accessible from the schema facade. But IDE's are not recognizing it. --- src/Illuminate/Support/Facades/Schema.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index 12809a4362de..434667aed131 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -7,6 +7,7 @@ * @method static \Illuminate\Database\Schema\Builder drop(string $table) * @method static \Illuminate\Database\Schema\Builder dropIfExists(string $table) * @method static \Illuminate\Database\Schema\Builder table(string $table, \Closure $callback) + * @method static \Illuminate\Database\Schema\Builder rename(string $from, string $to) * @method static void defaultStringLength(int $length) * @method static \Illuminate\Database\Schema\Builder disableForeignKeyConstraints() * @method static \Illuminate\Database\Schema\Builder enableForeignKeyConstraints() From cde1c5d8b38a9b040e70c344bba82781239a0bbf Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 11 Apr 2019 07:50:00 -0500 Subject: [PATCH 1753/2459] various fixes and formatting --- .../Foundation/Console/EventListCommand.php | 50 ++++++------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/src/Illuminate/Foundation/Console/EventListCommand.php b/src/Illuminate/Foundation/Console/EventListCommand.php index 4b5b9c2b2cd6..ece9f88fcead 100644 --- a/src/Illuminate/Foundation/Console/EventListCommand.php +++ b/src/Illuminate/Foundation/Console/EventListCommand.php @@ -13,7 +13,7 @@ class EventListCommand extends Command * * @var string */ - protected $signature = 'event:list {--event= : The event name}'; + protected $signature = 'event:list {--event= : Filter the events by name}'; /** * The console command description. @@ -22,13 +22,6 @@ class EventListCommand extends Command */ protected $description = "List the application's events and listeners"; - /** - * The table headers for the command. - * - * @var array - */ - protected $headers = ['Event', 'Listeners']; - /** * Execute the console command. * @@ -39,14 +32,10 @@ public function handle() $events = $this->getEvents(); if (empty($events)) { - if ($this->isSearching()) { - return $this->error('Your application doesn\'t have any events matching the given criteria.'); - } - - return $this->error('Your application doesn\'t has any events, listeners.'); + return $this->error("Your application doesn't have any events matching the given criteria."); } - $this->displayEvents($events); + $this->table(['Event', 'Listeners'], $events); } /** @@ -64,7 +53,7 @@ protected function getEvents() $events = array_merge_recursive($events, $providerEvents); } - if ($this->isSearching()) { + if ($this->filteringByEvent()) { $events = $this->filterEvents($events); } @@ -74,40 +63,29 @@ protected function getEvents() } /** - * Determine whether the user is searching event. - * - * @return bool - */ - protected function isSearching() - { - return $this->input->hasParameterOption('--event'); - } - - /** - * Filter the given events. + * Filter the given events using the provided event name filter. * * @param array $events * @return array */ protected function filterEvents(array $events) { - return collect($events)->filter(function ($listeners, $event) { - if ($this->option('event')) { - return Str::contains($event, $this->option('event')); - } + if (! $eventName = $this->option('event')) { + return $events; + } - return true; + return collect($events)->filter(function ($listeners, $event) use ($eventName) { + return Str::contains($event, $eventName); })->toArray(); } /** - * Display the event listeners information on the console. + * Determine whether the user is filtering by an event name. * - * @param array $events - * @return void + * @return bool */ - protected function displayEvents(array $events) + protected function filteringByEvent() { - $this->table($this->headers, $events); + return ! empty($this->option('event')); } } From 0bdb0126e4c74f46076a306e5d192aae5e67e2ba Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 11 Apr 2019 07:56:07 -0500 Subject: [PATCH 1754/2459] Update DatabaseMySqlSchemaGrammarTest.php --- tests/Database/DatabaseMySqlSchemaGrammarTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/Database/DatabaseMySqlSchemaGrammarTest.php b/tests/Database/DatabaseMySqlSchemaGrammarTest.php index dcbffb865129..9464e99564b7 100755 --- a/tests/Database/DatabaseMySqlSchemaGrammarTest.php +++ b/tests/Database/DatabaseMySqlSchemaGrammarTest.php @@ -9,9 +9,6 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Grammars\MySqlGrammar; -/** - * @group setTest - */ class DatabaseMySqlSchemaGrammarTest extends TestCase { protected function tearDown(): void From aa9fdd411f7a9cb168e09c0a968586354972bf99 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 11 Apr 2019 08:00:36 -0500 Subject: [PATCH 1755/2459] formatting --- src/Illuminate/Console/Scheduling/Event.php | 93 ++++++++++----------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/src/Illuminate/Console/Scheduling/Event.php b/src/Illuminate/Console/Scheduling/Event.php index c0ea965e47ae..1e8e8531aab8 100644 --- a/src/Illuminate/Console/Scheduling/Event.php +++ b/src/Illuminate/Console/Scheduling/Event.php @@ -417,6 +417,23 @@ public function emailWrittenOutputTo($addresses) return $this->emailOutputTo($addresses, true); } + /** + * E-mail the results of the scheduled operation if it fails. + * + * @param array|mixed $addresses + * @return $this + */ + public function emailOutputOnFailure($addresses) + { + $this->ensureOutputIsBeingCaptured(); + + $addresses = Arr::wrap($addresses); + + return $this->onFailure(function (Mailer $mailer) use ($addresses) { + $this->emailOutput($mailer, $addresses, false); + }); + } + /** * Ensure that the command output is being captured. * @@ -514,6 +531,32 @@ public function thenPingIf($value, $url) return $value ? $this->thenPing($url) : $this; } + /** + * Register a callback to ping a given URL if the operation succeeds. + * + * @param string $url + * @return $this + */ + public function pingOnSuccess($url) + { + return $this->onSuccess(function () use ($url) { + (new HttpClient)->get($url); + }); + } + + /** + * Register a callback to ping a given URL if the operation fails. + * + * @param string $url + * @return $this + */ + public function pingOnFailure($url) + { + return $this->onFailure(function () use ($url) { + (new HttpClient)->get($url); + }); + } + /** * State that the command should run in background. * @@ -663,7 +706,7 @@ public function then(Closure $callback) } /** - * Register a callback to be called after the operation if it was successful. + * Register a callback to be called if the operation succeeds. * * @param \Closure $callback * @return $this @@ -678,7 +721,7 @@ public function onSuccess(Closure $callback) } /** - * Register a callback to be called after the operation if it failed. + * Register a callback to be called if the operation fails. * * @param \Closure $callback * @return $this @@ -692,52 +735,6 @@ public function onFailure(Closure $callback) }); } - /** - * Register a callback to ping a given URL after the job runs if it was successful. - * - * @param string $url - * @return $this - */ - public function pingOnSuccess($url) - { - return $this->onSuccess(function () use ($url) { - (new HttpClient)->get($url); - }); - } - - /** - * Register a callback to ping a given URL after the job runs if it failed. - * - * @param string $url - * @return $this - */ - public function pingOnFailure($url) - { - return $this->onFailure(function () use ($url) { - (new HttpClient)->get($url); - }); - } - - /** - * E-mail the results of the scheduled operation if it failed. - * - * @param array|mixed $addresses - * @return $this - */ - public function emailOnFailure($addresses) - { - $this->ensureOutputIsBeingCaptured(); - - $addresses = Arr::wrap($addresses); - - return $this->onFailure(function (Mailer $mailer) use ($addresses) { - $oldDescription = $this->description; - $this->description = '[FAILURE] '.$this->getEmailSubject(); - $this->emailOutput($mailer, $addresses, false); - $this->description = $oldDescription; - }); - } - /** * Set the human-friendly description of the event. * From 1300902eb65763cddccbed71d959d0154f00382c Mon Sep 17 00:00:00 2001 From: Paul Klimov Date: Thu, 11 Apr 2019 16:43:42 +0300 Subject: [PATCH 1756/2459] Enh: `FactoryMakeCommand` updated to generate more IDE friendly code --- .../Console/Factories/FactoryMakeCommand.php | 16 +++++++++++++--- .../Console/Factories/stubs/factory.stub | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php b/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php index 86341594d133..725a69ccceeb 100644 --- a/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php +++ b/src/Illuminate/Database/Console/Factories/FactoryMakeCommand.php @@ -46,12 +46,22 @@ protected function getStub() */ protected function buildClass($name) { - $model = $this->option('model') + $namespaceModel = $this->option('model') ? $this->qualifyClass($this->option('model')) - : 'Model'; + : trim($this->rootNamespace(), '\\').'\\Model'; + + $model = class_basename($namespaceModel); return str_replace( - 'DummyModel', $model, parent::buildClass($name) + [ + 'NamespacedDummyModel', + 'DummyModel', + ], + [ + $namespaceModel, + $model, + ], + parent::buildClass($name) ); } diff --git a/src/Illuminate/Database/Console/Factories/stubs/factory.stub b/src/Illuminate/Database/Console/Factories/stubs/factory.stub index 9e3f90b60f34..4a754cc84c49 100644 --- a/src/Illuminate/Database/Console/Factories/stubs/factory.stub +++ b/src/Illuminate/Database/Console/Factories/stubs/factory.stub @@ -1,6 +1,9 @@ define(DummyModel::class, function (Faker $faker) { return [ From bc32756649d7e81362eb01075790e63c6c9e533d Mon Sep 17 00:00:00 2001 From: jerguslejko Date: Thu, 11 Apr 2019 19:11:54 +0100 Subject: [PATCH 1757/2459] in/not in as strings --- src/Illuminate/Database/Query/Builder.php | 11 +++++++++++ tests/Database/DatabaseQueryBuilderTest.php | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index dacf672b5d28..58d8cf7fdd93 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -616,6 +616,17 @@ public function where($column, $operator = null, $value = null, $boolean = 'and' return $this->whereNested($column, $boolean); } + // If the operator is a literal string 'in' or 'not in', we will assume + // the developer wants to use the corresponding 'in' or 'not in' SQL + // operators. We will simply proxy to the query builder methods. + if ($operator == 'in') { + return $this->whereIn($column, $value, $boolean); + } + + if ($operator == 'not in') { + return $this->whereNotIn($column, $value, $boolean); + } + // If the given operator is not found in the list of valid operators we will // assume that the developer is just short-cutting the '=' operators and // we will set the operators to '=' and set the values appropriately. diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index ef1b3c871641..38f91732c8bd 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -644,6 +644,11 @@ public function testBasicWhereIns() $this->assertEquals('select * from "users" where "id" in (?, ?, ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2, 2 => 3], $builder->getBindings()); + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('id', 'in', [1, 2, 3]); + $this->assertEquals('select * from "users" where "id" in (?, ?, ?)', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2, 2 => 3], $builder->getBindings()); + $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('id', '=', 1)->orWhereIn('id', [1, 2, 3]); $this->assertEquals('select * from "users" where "id" = ? or "id" in (?, ?, ?)', $builder->toSql()); @@ -657,6 +662,11 @@ public function testBasicWhereNotIns() $this->assertEquals('select * from "users" where "id" not in (?, ?, ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2, 2 => 3], $builder->getBindings()); + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->where('id', 'not in', [1, 2, 3]); + $this->assertEquals('select * from "users" where "id" not in (?, ?, ?)', $builder->toSql()); + $this->assertEquals([0 => 1, 1 => 2, 2 => 3], $builder->getBindings()); + $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('id', '=', 1)->orWhereNotIn('id', [1, 2, 3]); $this->assertEquals('select * from "users" where "id" = ? or "id" not in (?, ?, ?)', $builder->toSql()); From 4b9d3e78e6de2d7439eeecb3f1115e8048e64f90 Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Fri, 12 Apr 2019 09:19:34 +1000 Subject: [PATCH 1758/2459] handle duplicates method in eloquent collections --- .../Database/Eloquent/Collection.php | 13 ++++++++++ src/Illuminate/Support/Collection.php | 26 ++++++++++++++----- .../DatabaseEloquentCollectionTest.php | 22 ++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index ca8cf852dc00..3720a140436d 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -305,6 +305,19 @@ public function diff($items) return $diff; } + /** + * Get the comparison function to detect duplicates. + * + * @param bool $strict + * @return \Closure + */ + protected function duplicateComparator($strict) + { + return function ($a, $b) { + return $a->is($b); + }; + } + /** * Intersect the collection with the given items. * diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index 0262fe1acce3..ca3fba0a9894 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -420,12 +420,7 @@ public function duplicates($callback = null, $strict = false) $uniqueItems = $items->unique(null, $strict); - $compare = $strict ? function ($a, $b) { - return $a === $b; - } - : function ($a, $b) { - return $a == $b; - }; + $compare = $this->duplicateComparator($strict); $duplicates = new static; @@ -451,6 +446,25 @@ public function duplicatesStrict($callback = null) return $this->duplicates($callback, true); } + /** + * Get the comparison function to detect duplicates. + * + * @param bool $strict + * @return \Closure + */ + protected function duplicateComparator($strict) + { + if ($strict) { + return function ($a, $b) { + return $a === $b; + }; + } + + return function ($a, $b) { + return $a == $b; + }; + } + /** * Execute a callback over each item. * diff --git a/tests/Database/DatabaseEloquentCollectionTest.php b/tests/Database/DatabaseEloquentCollectionTest.php index eb6fbd13882e..adf76f6d0f57 100755 --- a/tests/Database/DatabaseEloquentCollectionTest.php +++ b/tests/Database/DatabaseEloquentCollectionTest.php @@ -245,6 +245,28 @@ public function testCollectionDiffsWithGivenCollection() $this->assertEquals(new Collection([$one]), $c1->diff($c2)); } + public function testCollectionReturnsDuplicateBasedOnlyOnKeys() + { + $one = new TestEloquentCollectionModel(); + $two = new TestEloquentCollectionModel(); + $three = new TestEloquentCollectionModel(); + $four = new TestEloquentCollectionModel(); + $one->id = 1; + $one->someAttribute = '1'; + $two->id = 1; + $two->someAttribute = '2'; + $three->id = 1; + $three->someAttribute = '3'; + $four->id = 2; + $four->someAttribute = '4'; + + $duplicates = Collection::make([$one, $two, $three, $four])->duplicates()->all(); + $this->assertSame([1 => $two, 2 => $three], $duplicates); + + $duplicates = Collection::make([$one, $two, $three, $four])->duplicatesStrict()->all(); + $this->assertSame([1 => $two, 2 => $three], $duplicates); + } + public function testCollectionIntersectsWithGivenCollection() { $one = m::mock(Model::class); From 08c72116855a265e930dadf5ac4e15b43a39224a Mon Sep 17 00:00:00 2001 From: Tim MacDonald Date: Fri, 12 Apr 2019 09:28:24 +1000 Subject: [PATCH 1759/2459] add eloquent collection strict unique test --- .../DatabaseEloquentCollectionTest.php | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/Database/DatabaseEloquentCollectionTest.php b/tests/Database/DatabaseEloquentCollectionTest.php index eb6fbd13882e..66d8d78debb6 100755 --- a/tests/Database/DatabaseEloquentCollectionTest.php +++ b/tests/Database/DatabaseEloquentCollectionTest.php @@ -275,6 +275,28 @@ public function testCollectionReturnsUniqueItems() $this->assertEquals(new Collection([$one, $two]), $c->unique()); } + public function testCollectionReturnsUniqueStrictBasedOnKeysOnly() + { + $one = new TestEloquentCollectionModel(); + $two = new TestEloquentCollectionModel(); + $three = new TestEloquentCollectionModel(); + $four = new TestEloquentCollectionModel(); + $one->id = 1; + $one->someAttribute = '1'; + $two->id = 1; + $two->someAttribute = '2'; + $three->id = 1; + $three->someAttribute = '3'; + $four->id = 2; + $four->someAttribute = '4'; + + $uniques = Collection::make([$one, $two, $three, $four])->unique()->all(); + $this->assertSame([$three, $four], $uniques); + + $uniques = Collection::make([$one, $two, $three, $four])->unique(null, true)->all(); + $this->assertSame([$three, $four], $uniques); + } + public function testOnlyReturnsCollectionWithGivenModelKeys() { $one = m::mock(Model::class); From f4b4844682f05c0740b1c8f94e16c332b8cd5933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20=C3=96sterlund?= Date: Fri, 12 Apr 2019 09:09:35 +0200 Subject: [PATCH 1760/2459] Add getViews method to return views --- src/Illuminate/View/FileViewFinder.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index 25e3adef7df5..5eadcbced97c 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -319,4 +319,14 @@ public function getExtensions() { return $this->extensions; } + + /** + * Get registered views. + * + * @return array + */ + public function getViews() + { + return $this->views; + } } From 8fcdd63e80be2be35c4c75c4121e4dc2fab8cb3f Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Fri, 12 Apr 2019 14:37:19 +0200 Subject: [PATCH 1761/2459] Add missing LockProvider interface on DynamoDbStore --- src/Illuminate/Cache/DynamoDbStore.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Cache/DynamoDbStore.php b/src/Illuminate/Cache/DynamoDbStore.php index d7464f912c53..3585240d767b 100644 --- a/src/Illuminate/Cache/DynamoDbStore.php +++ b/src/Illuminate/Cache/DynamoDbStore.php @@ -8,9 +8,10 @@ use Aws\DynamoDb\DynamoDbClient; use Illuminate\Contracts\Cache\Store; use Illuminate\Support\InteractsWithTime; +use Illuminate\Contracts\Cache\LockProvider; use Aws\DynamoDb\Exception\DynamoDbException; -class DynamoDbStore implements Store +class DynamoDbStore implements Store, LockProvider { use InteractsWithTime; From e24878ae8eff19c87b9532672b2bbc081b8201ec Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 12 Apr 2019 08:10:10 -0500 Subject: [PATCH 1762/2459] formatting --- src/Illuminate/Database/Query/Builder.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 58d8cf7fdd93..1276c11a4dde 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -616,9 +616,9 @@ public function where($column, $operator = null, $value = null, $boolean = 'and' return $this->whereNested($column, $boolean); } - // If the operator is a literal string 'in' or 'not in', we will assume - // the developer wants to use the corresponding 'in' or 'not in' SQL - // operators. We will simply proxy to the query builder methods. + // If the operator is a literal string 'in' or 'not in', we will assume that + // the developer wants to use the "whereIn / whereNotIn" methods for this + // operation and proxy the query through those methods from this point. if ($operator == 'in') { return $this->whereIn($column, $value, $boolean); } From 0f4ea978fb243ccbf11bd02f149a7373a82005ef Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 12 Apr 2019 08:13:03 -0500 Subject: [PATCH 1763/2459] formatting' --- .../Database/Eloquent/Collection.php | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Collection.php b/src/Illuminate/Database/Eloquent/Collection.php index 3720a140436d..9e6e76387df1 100755 --- a/src/Illuminate/Database/Eloquent/Collection.php +++ b/src/Illuminate/Database/Eloquent/Collection.php @@ -305,19 +305,6 @@ public function diff($items) return $diff; } - /** - * Get the comparison function to detect duplicates. - * - * @param bool $strict - * @return \Closure - */ - protected function duplicateComparator($strict) - { - return function ($a, $b) { - return $a->is($b); - }; - } - /** * Intersect the collection with the given items. * @@ -506,6 +493,19 @@ public function pad($size, $value) return $this->toBase()->pad($size, $value); } + /** + * Get the comparison function to detect duplicates. + * + * @param bool $strict + * @return \Closure + */ + protected function duplicateComparator($strict) + { + return function ($a, $b) { + return $a->is($b); + }; + } + /** * Get the type of the entities being queued. * From 158ed5ceb1b7b02ce70c97018a0c9116062994a9 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 12 Apr 2019 08:14:04 -0500 Subject: [PATCH 1764/2459] formatting --- src/Illuminate/View/FileViewFinder.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Illuminate/View/FileViewFinder.php b/src/Illuminate/View/FileViewFinder.php index 5eadcbced97c..0985165634a5 100755 --- a/src/Illuminate/View/FileViewFinder.php +++ b/src/Illuminate/View/FileViewFinder.php @@ -301,32 +301,32 @@ public function getPaths() } /** - * Get the namespace to file path hints. + * Get the views that have been located. * * @return array */ - public function getHints() + public function getViews() { - return $this->hints; + return $this->views; } /** - * Get registered extensions. + * Get the namespace to file path hints. * * @return array */ - public function getExtensions() + public function getHints() { - return $this->extensions; + return $this->hints; } /** - * Get registered views. + * Get registered extensions. * * @return array */ - public function getViews() + public function getExtensions() { - return $this->views; + return $this->extensions; } } From c53a0831df83d41b8577708480051a0b8d702536 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 12 Apr 2019 08:20:58 -0500 Subject: [PATCH 1765/2459] formatting --- src/Illuminate/Database/Console/Factories/stubs/factory.stub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Console/Factories/stubs/factory.stub b/src/Illuminate/Database/Console/Factories/stubs/factory.stub index 4a754cc84c49..909af66b642f 100644 --- a/src/Illuminate/Database/Console/Factories/stubs/factory.stub +++ b/src/Illuminate/Database/Console/Factories/stubs/factory.stub @@ -2,8 +2,8 @@ /* @var $factory \Illuminate\Database\Eloquent\Factory */ -use Faker\Generator as Faker; use NamespacedDummyModel; +use Faker\Generator as Faker; $factory->define(DummyModel::class, function (Faker $faker) { return [ From b54a849d61a1afe6345b50de570d3f021e15c49c Mon Sep 17 00:00:00 2001 From: ShawnCZek Date: Sat, 13 Apr 2019 12:00:28 +0200 Subject: [PATCH 1766/2459] [5.8] Change session's user_id to unsigned big integer In the session database table, user_id should be an unsigned big integer due to the recent change (#26472). --- src/Illuminate/Session/Console/stubs/database.stub | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Session/Console/stubs/database.stub b/src/Illuminate/Session/Console/stubs/database.stub index c213297d174a..3c8ebbdc8937 100755 --- a/src/Illuminate/Session/Console/stubs/database.stub +++ b/src/Illuminate/Session/Console/stubs/database.stub @@ -15,7 +15,7 @@ class CreateSessionsTable extends Migration { Schema::create('sessions', function (Blueprint $table) { $table->string('id')->unique(); - $table->unsignedInteger('user_id')->nullable(); + $table->unsignedBigInteger('user_id')->nullable(); $table->string('ip_address', 45)->nullable(); $table->text('user_agent')->nullable(); $table->text('payload'); From 1b6089e7e1f892112968de4433cb85cb1364422f Mon Sep 17 00:00:00 2001 From: Max Sky Date: Sun, 14 Apr 2019 13:44:06 +0800 Subject: [PATCH 1767/2459] Update Queue.php, update all $data vars datatype $data var should support multi datatype, not only string. --- src/Illuminate/Support/Facades/Queue.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Illuminate/Support/Facades/Queue.php b/src/Illuminate/Support/Facades/Queue.php index 521d2eb21441..114f7b249978 100755 --- a/src/Illuminate/Support/Facades/Queue.php +++ b/src/Illuminate/Support/Facades/Queue.php @@ -6,12 +6,12 @@ /** * @method static int size(string $queue = null) - * @method static mixed push(string|object $job, string $data = '', $queue = null) - * @method static mixed pushOn(string $queue, string|object $job, $data = '') + * @method static mixed push(string|object $job, mixed $data = '', $queue = null) + * @method static mixed pushOn(string $queue, string|object $job, mixed $data = '') * @method static mixed pushRaw(string $payload, string $queue = null, array $options = []) - * @method static mixed later(\DateTimeInterface|\DateInterval|int $delay, string|object $job, $data = '', string $queue = null) - * @method static mixed laterOn(string $queue, \DateTimeInterface|\DateInterval|int $delay, string|object $job, $data = '') - * @method static mixed bulk(array $jobs, $data = '', string $queue = null) + * @method static mixed later(\DateTimeInterface|\DateInterval|int $delay, string|object $job, mixed $data = '', string $queue = null) + * @method static mixed laterOn(string $queue, \DateTimeInterface|\DateInterval|int $delay, string|object $job, mixed $data = '') + * @method static mixed bulk(array $jobs, mixed $data = '', string $queue = null) * @method static \Illuminate\Contracts\Queue\Job|null pop(string $queue = null) * @method static string getConnectionName() * @method static \Illuminate\Contracts\Queue\Queue setConnectionName(string $name) From 17a1cfb2ed27efa8ac9d0725c3c2fadf5224b047 Mon Sep 17 00:00:00 2001 From: JacksonIV Date: Sun, 14 Apr 2019 10:41:46 +0200 Subject: [PATCH 1768/2459] Add the ability to register custom DBAL types in the schema builder. --- src/Illuminate/Database/Schema/Builder.php | 25 ++++++++ .../Database/Schema/MySqlBuilder.php | 17 +++++ .../Database/Schema/Types/TinyInteger.php | 64 +++++++++++++++++++ src/Illuminate/Support/Facades/Schema.php | 1 + .../Database/SchemaBuilderTest.php | 9 +++ 5 files changed, 116 insertions(+) create mode 100644 src/Illuminate/Database/Schema/Types/TinyInteger.php diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 2e25cf0cd9dc..eb33b2a86c06 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -3,6 +3,7 @@ namespace Illuminate\Database\Schema; use Closure; +use Doctrine\DBAL\Types\Type; use LogicException; use Illuminate\Database\Connection; @@ -317,4 +318,28 @@ public function blueprintResolver(Closure $resolver) { $this->resolver = $resolver; } + + /** + * Register your own Doctrine mapping type. + * + * @param string $class + * @param string $name + * @param string $type + * @return void + * + * @throws \Doctrine\DBAL\DBALException + */ + public function registerCustomDBALType($class, $name, $type) + { + if (! $this->connection->isDoctrineAvailable()) { + return; + } + if (! Type::hasType($name)) { + Type::addType($name, $class); + $this->connection + ->getDoctrineSchemaManager() + ->getDatabasePlatform() + ->registerDoctrineTypeMapping($type, $name); + } + } } diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index 85f3e92c25f7..a6f4aa184b4e 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -2,8 +2,25 @@ namespace Illuminate\Database\Schema; +use Illuminate\Database\Connection; +use Illuminate\Database\Schema\Types\TinyInteger; + class MySqlBuilder extends Builder { + /** + * MySqlBuilder constructor. + * + * @param Connection $connection + * + * @throws \Doctrine\DBAL\DBALException + */ + public function __construct(Connection $connection) + { + parent::__construct($connection); + + $this->registerCustomDBALType(TinyInteger::class, TinyInteger::NAME, 'TINYINT'); + } + /** * Determine if the given table exists. * diff --git a/src/Illuminate/Database/Schema/Types/TinyInteger.php b/src/Illuminate/Database/Schema/Types/TinyInteger.php new file mode 100644 index 000000000000..6801c5441cbe --- /dev/null +++ b/src/Illuminate/Database/Schema/Types/TinyInteger.php @@ -0,0 +1,64 @@ +assertTrue(true); } + + public function test_register_custom_DBAL_type() + { + Schema::registerCustomDBALType(TinyInteger::class, TinyInteger::NAME, 'TINYINT'); + + $this->assertArrayHasKey(TinyInteger::NAME, Type::getTypesMap()); + } } From eb5de12c443b10c8eb4936a5d09977adc43a2a54 Mon Sep 17 00:00:00 2001 From: JacksonIV Date: Sun, 14 Apr 2019 10:43:37 +0200 Subject: [PATCH 1769/2459] Fix a styling issue. --- src/Illuminate/Database/Schema/Builder.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index eb33b2a86c06..1e3ca3c00952 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -334,6 +334,7 @@ public function registerCustomDBALType($class, $name, $type) if (! $this->connection->isDoctrineAvailable()) { return; } + if (! Type::hasType($name)) { Type::addType($name, $class); $this->connection From 7c0d0f6baea9c89255e5da5a7df5ec0a0c5d9b82 Mon Sep 17 00:00:00 2001 From: JacksonIV Date: Sun, 14 Apr 2019 10:46:40 +0200 Subject: [PATCH 1770/2459] Fix a styling issue. --- src/Illuminate/Database/Schema/Builder.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 1e3ca3c00952..5dacb85d6145 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -334,9 +334,10 @@ public function registerCustomDBALType($class, $name, $type) if (! $this->connection->isDoctrineAvailable()) { return; } - + if (! Type::hasType($name)) { Type::addType($name, $class); + $this->connection ->getDoctrineSchemaManager() ->getDatabasePlatform() From c97a8572eca62441705d7d39af3ecae000c35386 Mon Sep 17 00:00:00 2001 From: JacksonIV Date: Sun, 14 Apr 2019 11:05:14 +0200 Subject: [PATCH 1771/2459] Fix a styling issue. --- src/Illuminate/Database/Schema/Builder.php | 4 ++-- src/Illuminate/Database/Schema/Types/TinyInteger.php | 2 +- tests/Integration/Database/SchemaBuilderTest.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 5dacb85d6145..6460277691ce 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -3,8 +3,8 @@ namespace Illuminate\Database\Schema; use Closure; -use Doctrine\DBAL\Types\Type; use LogicException; +use Doctrine\DBAL\Types\Type; use Illuminate\Database\Connection; class Builder @@ -337,7 +337,7 @@ public function registerCustomDBALType($class, $name, $type) if (! Type::hasType($name)) { Type::addType($name, $class); - + $this->connection ->getDoctrineSchemaManager() ->getDatabasePlatform() diff --git a/src/Illuminate/Database/Schema/Types/TinyInteger.php b/src/Illuminate/Database/Schema/Types/TinyInteger.php index 6801c5441cbe..ad3b9ed0c261 100644 --- a/src/Illuminate/Database/Schema/Types/TinyInteger.php +++ b/src/Illuminate/Database/Schema/Types/TinyInteger.php @@ -2,8 +2,8 @@ namespace Illuminate\Database\Schema\Types; -use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; +use Doctrine\DBAL\Platforms\AbstractPlatform; class TinyInteger extends Type { diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index da20b59786d9..54a1a095fefd 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -3,10 +3,10 @@ namespace Illuminate\Tests\Integration\Database\SchemaTest; use Doctrine\DBAL\Types\Type; -use Illuminate\Database\Schema\Types\TinyInteger; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Types\TinyInteger; use Illuminate\Tests\Integration\Database\DatabaseTestCase; /** From de5d0c4830edf3ac3c697e6c7d31e63c9309e4da Mon Sep 17 00:00:00 2001 From: JacksonIV Date: Sun, 14 Apr 2019 11:09:18 +0200 Subject: [PATCH 1772/2459] Fix a styling issue. --- src/Illuminate/Database/Schema/Types/TinyInteger.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Schema/Types/TinyInteger.php b/src/Illuminate/Database/Schema/Types/TinyInteger.php index ad3b9ed0c261..3e6123f07710 100644 --- a/src/Illuminate/Database/Schema/Types/TinyInteger.php +++ b/src/Illuminate/Database/Schema/Types/TinyInteger.php @@ -61,4 +61,4 @@ public function getName() { return self::NAME; } -} \ No newline at end of file +} From 7379fc13db7cd007f3a6eccaeacad58fb0c5e68b Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 14 Apr 2019 13:52:47 +0300 Subject: [PATCH 1773/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 7fb2d9285f96..19fdd1cc57c1 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -2,6 +2,24 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v5.8.11...5.8) +### Added +- Added `Illuminate\Support\Collection::duplicates()` ([#28181](https://github.com/laravel/framework/pull/28181)) +- Added `Illuminate\Database\Eloquent\Collection::duplicates()` ([#28194](https://github.com/laravel/framework/pull/28194)) +- Added `Illuminate\View\FileViewFinder::getViews()` ([#28198](https://github.com/laravel/framework/pull/28198)) + +### TODO: +- Fixed circular dependency - fix #28165 ([#28164](https://github.com/laravel/framework/pull/28164)) +- Add schedule event helpers to deal with successful/failed commands ([#28167](https://github.com/laravel/framework/pull/28167)) +- Added SET datatype on MySQL Grammar ([#28171](https://github.com/laravel/framework/pull/28171)) +- Make inequality validation fail on different types rather than 500 ([#28174](https://github.com/laravel/framework/pull/28174)) +- Fix enum definition not producing N-quoted string on Sql Server ([#28176](https://github.com/laravel/framework/pull/28176)) +- Improve event list command ([#28177](https://github.com/laravel/framework/pull/28177), [cde1c5d](https://github.com/laravel/framework/commit/cde1c5d8b38a9b040e70c344bba82781239a0bbf)) +- `whereDay` and `whereMonth` inconsistent when passing `int` values ([#28185](https://github.com/laravel/framework/pull/28185)) +- Enh: `FactoryMakeCommand` updated to generate more IDE friendly code ([#28188](https://github.com/laravel/framework/pull/28188)) +- in/not in operators ([#28192](https://github.com/laravel/framework/pull/28192)) +- Add missing LockProvider interface on DynamoDbStore ([#28203](https://github.com/laravel/framework/pull/28203)) +- Change session's user_id to unsigned big integer ([#28206](https://github.com/laravel/framework/pull/28206)) + ## [v5.8.11 (2019-04-10)](https://github.com/laravel/framework/compare/v5.8.10...v5.8.11) From ed7a05116e93f7af4e273b0b8c0a4012c24657a6 Mon Sep 17 00:00:00 2001 From: Jonas Staudenmeir Date: Mon, 15 Apr 2019 13:05:08 +0200 Subject: [PATCH 1774/2459] Fix memory leak in JOIN queries --- src/Illuminate/Database/Query/JoinClause.php | 50 +++++++++++++++++--- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Database/Query/JoinClause.php b/src/Illuminate/Database/Query/JoinClause.php index 267854e74df2..e09cf2008b6f 100755 --- a/src/Illuminate/Database/Query/JoinClause.php +++ b/src/Illuminate/Database/Query/JoinClause.php @@ -21,11 +21,32 @@ class JoinClause extends Builder public $table; /** - * The parent query builder instance. + * The connection of the parent query builder. * - * @var \Illuminate\Database\Query\Builder + * @var \Illuminate\Database\ConnectionInterface */ - private $parentQuery; + protected $parentConnection; + + /** + * The grammar of the parent query builder. + * + * @var \Illuminate\Database\Query\Grammars\Grammar + */ + protected $parentGrammar; + + /** + * The processor of the parent query builder. + * + * @var \Illuminate\Database\Query\Processors\Processor + */ + protected $parentProcessor; + + /** + * The class name of the parent query builder. + * + * @var string + */ + protected $parentClass; /** * Create a new join clause instance. @@ -39,10 +60,13 @@ public function __construct(Builder $parentQuery, $type, $table) { $this->type = $type; $this->table = $table; - $this->parentQuery = $parentQuery; + $this->parentConnection = $parentQuery->getConnection(); + $this->parentGrammar = $parentQuery->getGrammar(); + $this->parentProcessor = $parentQuery->getProcessor(); + $this->parentClass = get_class($parentQuery); parent::__construct( - $parentQuery->getConnection(), $parentQuery->getGrammar(), $parentQuery->getProcessor() + $this->parentConnection, $this->parentGrammar, $this->parentProcessor ); } @@ -95,7 +119,7 @@ public function orOn($first, $operator = null, $second = null) */ public function newQuery() { - return new static($this->parentQuery, $this->type, $this->table); + return new static($this->newParentQuery(), $this->type, $this->table); } /** @@ -105,6 +129,18 @@ public function newQuery() */ protected function forSubQuery() { - return $this->parentQuery->newQuery(); + return $this->newParentQuery()->newQuery(); + } + + /** + * Create a new parent query instance. + * + * @return \Illuminate\Database\Query\Builder + */ + protected function newParentQuery() + { + $class = $this->parentClass; + + return new $class($this->parentConnection, $this->parentGrammar, $this->parentProcessor); } } From dafef793ea07390a274355eea7f39d675a9e0e04 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Mon, 15 Apr 2019 08:11:55 -0500 Subject: [PATCH 1775/2459] formatting --- src/Illuminate/Database/Query/JoinClause.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Database/Query/JoinClause.php b/src/Illuminate/Database/Query/JoinClause.php index e09cf2008b6f..4e17842b5dac 100755 --- a/src/Illuminate/Database/Query/JoinClause.php +++ b/src/Illuminate/Database/Query/JoinClause.php @@ -60,10 +60,10 @@ public function __construct(Builder $parentQuery, $type, $table) { $this->type = $type; $this->table = $table; - $this->parentConnection = $parentQuery->getConnection(); + $this->parentClass = get_class($parentQuery); $this->parentGrammar = $parentQuery->getGrammar(); $this->parentProcessor = $parentQuery->getProcessor(); - $this->parentClass = get_class($parentQuery); + $this->parentConnection = $parentQuery->getConnection(); parent::__construct( $this->parentConnection, $this->parentGrammar, $this->parentProcessor From daeee63b558617e8c3fdaa9849d771031cbc0450 Mon Sep 17 00:00:00 2001 From: jackson Date: Mon, 15 Apr 2019 22:32:54 +0200 Subject: [PATCH 1776/2459] Remove unnecessary method overrides and make a slight modification to the registration of the DBAL types. --- src/Illuminate/Database/Schema/Builder.php | 14 +++++----- .../Database/Schema/MySqlBuilder.php | 18 ++++++++++++- .../Database/Schema/Types/TinyInteger.php | 26 ------------------- 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 6460277691ce..ba41ee1a4341 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -331,17 +331,15 @@ public function blueprintResolver(Closure $resolver) */ public function registerCustomDBALType($class, $name, $type) { - if (! $this->connection->isDoctrineAvailable()) { + if (Type::hasType($name)) { return; } - if (! Type::hasType($name)) { - Type::addType($name, $class); + Type::addType($name, $class); - $this->connection - ->getDoctrineSchemaManager() - ->getDatabasePlatform() - ->registerDoctrineTypeMapping($type, $name); - } + $this->connection + ->getDoctrineSchemaManager() + ->getDatabasePlatform() + ->registerDoctrineTypeMapping($type, $name); } } diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index a6f4aa184b4e..ba183a1e3b9d 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -18,7 +18,7 @@ public function __construct(Connection $connection) { parent::__construct($connection); - $this->registerCustomDBALType(TinyInteger::class, TinyInteger::NAME, 'TINYINT'); + $this->registerCustomDBALTypes(); } /** @@ -128,4 +128,20 @@ protected function getAllViews() $this->grammar->compileGetAllViews() ); } + + /** + * Register custom DBAL types for the MySQL builder. + * + * @return void + * + * @throws \Doctrine\DBAL\DBALException + */ + private function registerCustomDBALTypes() + { + if (! $this->connection->isDoctrineAvailable()) { + return; + } + + $this->registerCustomDBALType(TinyInteger::class, TinyInteger::NAME, 'TINYINT'); + } } diff --git a/src/Illuminate/Database/Schema/Types/TinyInteger.php b/src/Illuminate/Database/Schema/Types/TinyInteger.php index 3e6123f07710..cad5f1db1b83 100644 --- a/src/Illuminate/Database/Schema/Types/TinyInteger.php +++ b/src/Illuminate/Database/Schema/Types/TinyInteger.php @@ -26,32 +26,6 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla return 'TINYINT'; } - /** - * Converts a value from its database representation to its PHP representation - * of this type. - * - * @param mixed $value - * @param AbstractPlatform $platform - * @return mixed - */ - public function convertToPHPValue($value, AbstractPlatform $platform) - { - return $value; - } - - /** - * Converts a value from its PHP representation to its database representation - * of this type. - * - * @param mixed $value - * @param AbstractPlatform $platform - * @return mixed - */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) - { - return $value; - } - /** * The name of the custom type. * From 0c1f39c7ddc58705b6457878008a2304d3aa8dab Mon Sep 17 00:00:00 2001 From: jackson Date: Tue, 16 Apr 2019 00:16:52 +0200 Subject: [PATCH 1777/2459] Add a test to verify the column type and the syntax. --- .../Database/SchemaBuilderTest.php | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index 54a1a095fefd..8c09988c7ed1 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Integration\Database\SchemaTest; use Doctrine\DBAL\Types\Type; +use Illuminate\Database\Schema\Grammars\SQLiteGrammar; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; @@ -44,6 +45,28 @@ public function test_register_custom_DBAL_type() { Schema::registerCustomDBALType(TinyInteger::class, TinyInteger::NAME, 'TINYINT'); + Schema::create('test', function (Blueprint $table) { + $table->string('test_column'); + }); + + $blueprint = new Blueprint('test', function (Blueprint $table) { + $table->tinyInteger('test_column')->change(); + }); + + $expected = [ + 'CREATE TEMPORARY TABLE __temp__test AS SELECT test_column FROM test', + 'DROP TABLE test', + 'CREATE TABLE test (test_column TINYINT NOT NULL COLLATE BINARY)', + 'INSERT INTO test (test_column) SELECT test_column FROM __temp__test', + 'DROP TABLE __temp__test' + ]; + + $statements = $blueprint->toSql($this->getConnection(), new SQLiteGrammar()); + + $blueprint->build($this->getConnection(), new SQLiteGrammar()); + $this->assertArrayHasKey(TinyInteger::NAME, Type::getTypesMap()); + $this->assertEquals('tinyinteger', Schema::getColumnType('test', 'test_column')); + $this->assertEquals($expected, $statements); } } From db8419641c6ccdc7d6e4673267027aba92868b53 Mon Sep 17 00:00:00 2001 From: jackson Date: Tue, 16 Apr 2019 00:18:59 +0200 Subject: [PATCH 1778/2459] Fix a styling issue. --- tests/Integration/Database/SchemaBuilderTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index 8c09988c7ed1..df790b6d2e14 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -3,11 +3,11 @@ namespace Illuminate\Tests\Integration\Database\SchemaTest; use Doctrine\DBAL\Types\Type; -use Illuminate\Database\Schema\Grammars\SQLiteGrammar; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Types\TinyInteger; +use Illuminate\Database\Schema\Grammars\SQLiteGrammar; use Illuminate\Tests\Integration\Database\DatabaseTestCase; /** @@ -58,7 +58,7 @@ public function test_register_custom_DBAL_type() 'DROP TABLE test', 'CREATE TABLE test (test_column TINYINT NOT NULL COLLATE BINARY)', 'INSERT INTO test (test_column) SELECT test_column FROM __temp__test', - 'DROP TABLE __temp__test' + 'DROP TABLE __temp__test', ]; $statements = $blueprint->toSql($this->getConnection(), new SQLiteGrammar()); From df1a91641c2757f87ed5d5ecb03009d0ab678d32 Mon Sep 17 00:00:00 2001 From: Anas Date: Tue, 16 Apr 2019 02:21:45 +0100 Subject: [PATCH 1779/2459] [5.8] add autocomplete attributes to the stubs --- .../Auth/Console/stubs/make/views/auth/login.stub | 4 ++-- .../Console/stubs/make/views/auth/passwords/email.stub | 2 +- .../Console/stubs/make/views/auth/passwords/reset.stub | 6 +++--- .../Auth/Console/stubs/make/views/auth/register.stub | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub index 9edb920ecec0..3e9d6f7791b7 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub @@ -15,7 +15,7 @@
    - + @if ($errors->has('email')) @@ -29,7 +29,7 @@
    - + @if ($errors->has('password')) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub index ccbee595c03a..15ee4e4245f0 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub @@ -21,7 +21,7 @@
    - + @if ($errors->has('email')) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub index bf27f4c85688..f0cc401a08b5 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub @@ -17,7 +17,7 @@
    - + @if ($errors->has('email')) @@ -31,7 +31,7 @@
    - + @if ($errors->has('password')) @@ -45,7 +45,7 @@
    - +
    diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub index ad95f2cfd98c..92c416ea2cf0 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub @@ -15,7 +15,7 @@
    - + @if ($errors->has('name')) @@ -29,7 +29,7 @@
    - + @if ($errors->has('email')) @@ -43,7 +43,7 @@
    - + @if ($errors->has('password')) @@ -57,7 +57,7 @@
    - +
    From 852806178f40b582c4a265ce36bbad53e75a36fe Mon Sep 17 00:00:00 2001 From: xy2z Date: Tue, 16 Apr 2019 14:47:20 +0200 Subject: [PATCH 1780/2459] Corrected phpdoc for Filesystem append() and prepend() --- src/Illuminate/Contracts/Filesystem/Filesystem.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Contracts/Filesystem/Filesystem.php b/src/Illuminate/Contracts/Filesystem/Filesystem.php index d77274be1684..399b62761594 100644 --- a/src/Illuminate/Contracts/Filesystem/Filesystem.php +++ b/src/Illuminate/Contracts/Filesystem/Filesystem.php @@ -91,7 +91,7 @@ public function setVisibility($path, $visibility); * * @param string $path * @param string $data - * @return int + * @return bool */ public function prepend($path, $data); @@ -100,7 +100,7 @@ public function prepend($path, $data); * * @param string $path * @param string $data - * @return int + * @return bool */ public function append($path, $data); From 6dd75b67811a265c57144ab15f25a8061ed4721f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 16 Apr 2019 08:47:32 -0500 Subject: [PATCH 1781/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index ac1db13b9e78..9f7739090fac 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.8.11'; + const VERSION = '5.8.12'; /** * The base path for the Laravel installation. From 08d33b1fd56ac7cc8c676f5450f3d264f8776196 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 16 Apr 2019 21:45:44 +0300 Subject: [PATCH 1782/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 19fdd1cc57c1..f7635d95321c 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -1,24 +1,31 @@ # Release Notes for 5.8.x -## [Unreleased](https://github.com/laravel/framework/compare/v5.8.11...5.8) +## [Unreleased](https://github.com/laravel/framework/compare/v5.8.12...5.8) + + +## [v5.8.12 (2019-04-16)](https://github.com/laravel/framework/compare/v5.8.11...v5.8.12) ### Added - Added `Illuminate\Support\Collection::duplicates()` ([#28181](https://github.com/laravel/framework/pull/28181)) - Added `Illuminate\Database\Eloquent\Collection::duplicates()` ([#28194](https://github.com/laravel/framework/pull/28194)) - Added `Illuminate\View\FileViewFinder::getViews()` ([#28198](https://github.com/laravel/framework/pull/28198)) +- Added helper methods `onSuccess()` \ `onFailure()` \ `pingOnSuccess()` \ `pingOnFailure()` \ `emailOnFailure()` to `Illuminate\Console\Scheduling\Event` ([#28167](https://github.com/laravel/framework/pull/28167)) +- Added `SET` datatype on MySQL Grammar ([#28171](https://github.com/laravel/framework/pull/28171)) +- Added possibility for use `in` / `not in` operators in the query builder ([#28192](https://github.com/laravel/framework/pull/28192)) -### TODO: -- Fixed circular dependency - fix #28165 ([#28164](https://github.com/laravel/framework/pull/28164)) -- Add schedule event helpers to deal with successful/failed commands ([#28167](https://github.com/laravel/framework/pull/28167)) -- Added SET datatype on MySQL Grammar ([#28171](https://github.com/laravel/framework/pull/28171)) -- Make inequality validation fail on different types rather than 500 ([#28174](https://github.com/laravel/framework/pull/28174)) -- Fix enum definition not producing N-quoted string on Sql Server ([#28176](https://github.com/laravel/framework/pull/28176)) -- Improve event list command ([#28177](https://github.com/laravel/framework/pull/28177), [cde1c5d](https://github.com/laravel/framework/commit/cde1c5d8b38a9b040e70c344bba82781239a0bbf)) -- `whereDay` and `whereMonth` inconsistent when passing `int` values ([#28185](https://github.com/laravel/framework/pull/28185)) -- Enh: `FactoryMakeCommand` updated to generate more IDE friendly code ([#28188](https://github.com/laravel/framework/pull/28188)) -- in/not in operators ([#28192](https://github.com/laravel/framework/pull/28192)) -- Add missing LockProvider interface on DynamoDbStore ([#28203](https://github.com/laravel/framework/pull/28203)) -- Change session's user_id to unsigned big integer ([#28206](https://github.com/laravel/framework/pull/28206)) +### Fixed +- Fixed memory leak in JOIN queries ([#28220](https://github.com/laravel/framework/pull/28220)) +- Fixed circular dependency in `Support\Testing\Fakes\QueueFake` for undefined methods ([#28164](https://github.com/laravel/framework/pull/28164)) +- Fixed exception in `lt` \ `lte` \ `gt` \ `gte` validations with different types ([#28174](https://github.com/laravel/framework/pull/28174)) +- Fixed `string quoting` for `SQL Server` ([#28176](https://github.com/laravel/framework/pull/28176)) +- Fixed `whereDay` and `whereMonth` when passing `int` values ([#28185](https://github.com/laravel/framework/pull/28185)) + +### Changed +- Added `autocomplete` attributes to the html stubs ([#28226](https://github.com/laravel/framework/pull/28226)) +- Improved `event:list` command ([#28177](https://github.com/laravel/framework/pull/28177), [cde1c5d](https://github.com/laravel/framework/commit/cde1c5d8b38a9b040e70c344bba82781239a0bbf)) +- Updated `Illuminate\Database\Console\Factories\FactoryMakeCommand` to generate more IDE friendly code ([#28188](https://github.com/laravel/framework/pull/28188)) +- Added missing `LockProvider` interface on `DynamoDbStore` ([#28203](https://github.com/laravel/framework/pull/28203)) +- Change session's user_id to unsigned big integer in the stub ([#28206](https://github.com/laravel/framework/pull/28206)) ## [v5.8.11 (2019-04-10)](https://github.com/laravel/framework/compare/v5.8.10...v5.8.11) From 4a2568613b817e28cab4415d32ee58039ec2bc0a Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Tue, 16 Apr 2019 23:40:09 +0300 Subject: [PATCH 1783/2459] [5.8] Fix fake dispatcher issue Description: Integration tests proof that it will work with both built-in session guard or any other custom guard whether it has a dispatcher or not. Note : some build-in guards like Token guard does dispatch any events, hence there is no `setDispatcher ` method or any dispatcher on it. So there are 2 types of guards. which I think a contract (interface) is missing here, in order to mark the SessionGuard class or any other custom guard as an event dispatching guard, and enforce `setDispatcher` and `getDispatcher` methods on them.) So the clunky `method_exists` check won't be needed. Re-submit: https://github.com/laravel/framework/pull/28131 fixed: https://github.com/laravel/framework/issues/27451 --- src/Illuminate/Auth/AuthServiceProvider.php | 17 ++++ tests/Integration/Auth/AuthenticationTest.php | 77 +++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/src/Illuminate/Auth/AuthServiceProvider.php b/src/Illuminate/Auth/AuthServiceProvider.php index 2820beb48a9e..93ed6c29c63f 100755 --- a/src/Illuminate/Auth/AuthServiceProvider.php +++ b/src/Illuminate/Auth/AuthServiceProvider.php @@ -23,6 +23,8 @@ public function register() $this->registerAccessGate(); $this->registerRequestRebindHandler(); + + $this->registerEventRebindHandler(); } /** @@ -87,4 +89,19 @@ protected function registerRequestRebindHandler() }); }); } + + /** + * Register a resolver for the 'events' rebinding. + * + * @return void + */ + protected function registerEventRebindHandler() + { + $this->app->rebinding('events', function ($app, $dispatcher) { + $guard = $app['auth']->guard(); + if (method_exists($guard, 'setDispatcher')) { + $guard->setDispatcher($dispatcher); + } + }); + } } diff --git a/tests/Integration/Auth/AuthenticationTest.php b/tests/Integration/Auth/AuthenticationTest.php index 022da68ed1fa..96bfdc5c2231 100644 --- a/tests/Integration/Auth/AuthenticationTest.php +++ b/tests/Integration/Auth/AuthenticationTest.php @@ -4,9 +4,12 @@ use Illuminate\Support\Str; use Illuminate\Auth\Events\Login; +use Illuminate\Auth\SessionGuard; +use Illuminate\Events\Dispatcher; use Orchestra\Testbench\TestCase; use Illuminate\Auth\Events\Failed; use Illuminate\Auth\Events\Logout; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Event; use Illuminate\Auth\Events\Attempting; use Illuminate\Support\Facades\Schema; @@ -14,6 +17,7 @@ use Illuminate\Auth\Events\Authenticated; use Illuminate\Database\Schema\Blueprint; use Illuminate\Auth\Events\OtherDeviceLogout; +use Illuminate\Support\Testing\Fakes\EventFake; use Illuminate\Tests\Integration\Auth\Fixtures\AuthenticationTestUser; /** @@ -245,4 +249,77 @@ public function test_auth_via_attempt_remembering() $this->assertNull($provider->retrieveByToken($user->id, $token)); } + + public function test_dispatcher_changes_if_there_is_one_on_the_auth_guard() + { + $this->assertInstanceOf(SessionGuard::class, $this->app['auth']->guard()); + $this->assertInstanceOf(Dispatcher::class, $this->app['auth']->guard()->getDispatcher()); + + Event::fake(); + + $this->assertInstanceOf(SessionGuard::class, $this->app['auth']->guard()); + $this->assertInstanceOf(EventFake::class, $this->app['auth']->guard()->getDispatcher()); + } + + public function test_dispatcher_changes_if_there_is_one_on_the_custom_auth_guard() + { + $this->app['config']['auth.guards.myGuard'] = [ + 'driver' => 'myCustomDriver', + 'provider' => 'user', + ]; + + Auth::extend('myCustomDriver', function () { + return new MyCustomGuardStub(); + }); + + $this->assertInstanceOf(MyCustomGuardStub::class, $this->app['auth']->guard('myGuard')); + $this->assertInstanceOf(Dispatcher::class, $this->app['auth']->guard()->getDispatcher()); + + Event::fake(); + + $this->assertInstanceOf(MyCustomGuardStub::class, $this->app['auth']->guard('myGuard')); + $this->assertInstanceOf(EventFake::class, $this->app['auth']->guard()->getDispatcher()); + } + + public function test_has_no_problem_if_there_is_no_dispatching_the_auth_custom_guard() + { + $this->app['config']['auth.guards.myGuard'] = [ + 'driver' => 'myCustomDriver', + 'provider' => 'user', + ]; + + Auth::extend('myCustomDriver', function () { + return new MyDispatcherLessCustomGuardStub(); + }); + + $this->assertInstanceOf(MyDispatcherLessCustomGuardStub::class, $this->app['auth']->guard('myGuard')); + + Event::fake(); + + $this->assertInstanceOf(MyDispatcherLessCustomGuardStub::class, $this->app['auth']->guard('myGuard')); + } +} + +class MyCustomGuardStub +{ + protected $events; + + public function __construct() + { + $this->setDispatcher(new Dispatcher()); + } + + public function setDispatcher(Dispatcher $events) + { + $this->events = $events; + } + + public function getDispatcher() + { + return $this->events; + } +} + +class MyDispatcherLessCustomGuardStub +{ } From 1bcad051b668b06ba3366560242d4f112e3a1860 Mon Sep 17 00:00:00 2001 From: jackson Date: Wed, 17 Apr 2019 13:24:53 +0200 Subject: [PATCH 1784/2459] Fix a styling issue. --- src/Illuminate/Database/Schema/Builder.php | 2 +- src/Illuminate/Database/Schema/MySqlBuilder.php | 3 +-- src/Illuminate/Database/Schema/Types/TinyInteger.php | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index ba41ee1a4341..86d09741da03 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -324,7 +324,7 @@ public function blueprintResolver(Closure $resolver) * * @param string $class * @param string $name - * @param string $type + * @param string $type * @return void * * @throws \Doctrine\DBAL\DBALException diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index ba183a1e3b9d..2d1290bab1d1 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -10,8 +10,7 @@ class MySqlBuilder extends Builder /** * MySqlBuilder constructor. * - * @param Connection $connection - * + * @param \Illuminate\Database\Connection $connection * @throws \Doctrine\DBAL\DBALException */ public function __construct(Connection $connection) diff --git a/src/Illuminate/Database/Schema/Types/TinyInteger.php b/src/Illuminate/Database/Schema/Types/TinyInteger.php index cad5f1db1b83..37e9b9575868 100644 --- a/src/Illuminate/Database/Schema/Types/TinyInteger.php +++ b/src/Illuminate/Database/Schema/Types/TinyInteger.php @@ -18,7 +18,7 @@ class TinyInteger extends Type * Gets the SQL declaration snippet for a field of this type. * * @param array $fieldDeclaration - * @param AbstractPlatform $platform + * @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform * @return string */ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform) From be89773c52e7491de05dee053b18a38b177d6030 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 17 Apr 2019 09:02:33 -0500 Subject: [PATCH 1785/2459] check if resolved --- src/Illuminate/Auth/AuthServiceProvider.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Illuminate/Auth/AuthServiceProvider.php b/src/Illuminate/Auth/AuthServiceProvider.php index 93ed6c29c63f..dfc554b278b4 100755 --- a/src/Illuminate/Auth/AuthServiceProvider.php +++ b/src/Illuminate/Auth/AuthServiceProvider.php @@ -17,13 +17,9 @@ class AuthServiceProvider extends ServiceProvider public function register() { $this->registerAuthenticator(); - $this->registerUserResolver(); - $this->registerAccessGate(); - $this->registerRequestRebindHandler(); - $this->registerEventRebindHandler(); } @@ -77,7 +73,7 @@ protected function registerAccessGate() } /** - * Register a resolver for the authenticated user. + * Handle the re-binding of the request binding. * * @return void */ @@ -91,15 +87,18 @@ protected function registerRequestRebindHandler() } /** - * Register a resolver for the 'events' rebinding. + * Handle the re-binding of the event dispatcher binding. * * @return void */ protected function registerEventRebindHandler() { $this->app->rebinding('events', function ($app, $dispatcher) { - $guard = $app['auth']->guard(); - if (method_exists($guard, 'setDispatcher')) { + if (! $app->resolved('auth')) { + return; + } + + if (method_exists($guard = $app['auth']->guard(), 'setDispatcher')) { $guard->setDispatcher($dispatcher); } }); From 91a6afe1f9f8d18283f3ee9a72b636a121f06da5 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 17 Apr 2019 09:12:16 -0500 Subject: [PATCH 1786/2459] formatting --- src/Illuminate/Database/Schema/Builder.php | 48 +++++++++---------- .../Database/Schema/MySqlBuilder.php | 18 +++---- .../Database/SchemaBuilderTest.php | 4 +- 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 86d09741da03..d80f375b7ac0 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -285,6 +285,30 @@ protected function createBlueprint($table, Closure $callback = null) return new Blueprint($table, $callback, $prefix); } + /** + * Register a custom Doctrine mapping type. + * + * @param string $class + * @param string $name + * @param string $type + * @return void + * + * @throws \Doctrine\DBAL\DBALException + */ + public function registerCustomDoctrineType($class, $name, $type) + { + if (Type::hasType($name)) { + return; + } + + Type::addType($name, $class); + + $this->connection + ->getDoctrineSchemaManager() + ->getDatabasePlatform() + ->registerDoctrineTypeMapping($type, $name); + } + /** * Get the database connection instance. * @@ -318,28 +342,4 @@ public function blueprintResolver(Closure $resolver) { $this->resolver = $resolver; } - - /** - * Register your own Doctrine mapping type. - * - * @param string $class - * @param string $name - * @param string $type - * @return void - * - * @throws \Doctrine\DBAL\DBALException - */ - public function registerCustomDBALType($class, $name, $type) - { - if (Type::hasType($name)) { - return; - } - - Type::addType($name, $class); - - $this->connection - ->getDoctrineSchemaManager() - ->getDatabasePlatform() - ->registerDoctrineTypeMapping($type, $name); - } } diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index 2d1290bab1d1..bdd64d680c8b 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -8,16 +8,18 @@ class MySqlBuilder extends Builder { /** - * MySqlBuilder constructor. + * Create a new builder instance. * * @param \Illuminate\Database\Connection $connection + * @return void + * * @throws \Doctrine\DBAL\DBALException */ public function __construct(Connection $connection) { parent::__construct($connection); - $this->registerCustomDBALTypes(); + $this->registerCustomDoctrineTypes(); } /** @@ -129,18 +131,18 @@ protected function getAllViews() } /** - * Register custom DBAL types for the MySQL builder. + * Register the custom Doctrine mapping types for the MySQL builder. * * @return void * * @throws \Doctrine\DBAL\DBALException */ - private function registerCustomDBALTypes() + protected function registerCustomDoctrineTypes() { - if (! $this->connection->isDoctrineAvailable()) { - return; + if ($this->connection->isDoctrineAvailable()) { + $this->registerCustomDoctrineType( + TinyInteger::class, TinyInteger::NAME, 'TINYINT' + ); } - - $this->registerCustomDBALType(TinyInteger::class, TinyInteger::NAME, 'TINYINT'); } } diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index df790b6d2e14..6eea5f94e9de 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -41,9 +41,9 @@ public function test_drop_all_views() $this->assertTrue(true); } - public function test_register_custom_DBAL_type() + public function test_register_custom_doctrine_type() { - Schema::registerCustomDBALType(TinyInteger::class, TinyInteger::NAME, 'TINYINT'); + Schema::registerCustomDoctrineType(TinyInteger::class, TinyInteger::NAME, 'TINYINT'); Schema::create('test', function (Blueprint $table) { $table->string('test_column'); From 3f086cee0bf7bbc8b275e1cd5566966038b9b8b5 Mon Sep 17 00:00:00 2001 From: Nuno Maduro Date: Thu, 18 Apr 2019 14:39:01 +0200 Subject: [PATCH 1787/2459] Removes non-needed comment in Collection class --- src/Illuminate/Support/Collection.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Illuminate/Support/Collection.php b/src/Illuminate/Support/Collection.php index ca3fba0a9894..beec31935a7b 100644 --- a/src/Illuminate/Support/Collection.php +++ b/src/Illuminate/Support/Collection.php @@ -36,8 +36,6 @@ * @property-read HigherOrderCollectionProxy $sortByDesc * @property-read HigherOrderCollectionProxy $sum * @property-read HigherOrderCollectionProxy $unique - * - * Class Collection */ class Collection implements ArrayAccess, Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable { From 2d40c94d4db099df09fec943ef3bbced03b97b78 Mon Sep 17 00:00:00 2001 From: ahinkle Date: Thu, 18 Apr 2019 08:21:18 -0500 Subject: [PATCH 1788/2459] Add wherePivot Tests --- .../Database/EloquentBelongsToManyTest.php | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index 88e3f138df5d..413350b3c13e 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -518,6 +518,38 @@ public function test_can_touch_related_models() $this->assertNotEquals('2017-10-10 10:10:10', Tag::find(300)->updated_at); } + public function test_where_pivot_on_string() + { + $tag = Tag::create(['name' => Str::random()]); + $post = Post::create(['title' => Str::random()]); + + DB::table('posts_tags')->insert([ + ['post_id' => $post->id, 'tag_id' => $tag->id, 'flag' => 'empty'], + ]); + + $relationTag = $post->tags()->wherePivot('flag', 'empty')->first(); + $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); + + $relationTag = $post->tags()->wherePivot('flag', '=', 'empty')->first(); + $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); + } + + public function test_where_pivot_on_boolean() + { + $tag = Tag::create(['name' => Str::random()]); + $post = Post::create(['title' => Str::random()]); + + DB::table('posts_tags')->insert([ + ['post_id' => $post->id, 'tag_id' => $tag->id, 'flag' => true], + ]); + + $relationTag = $post->tags()->wherePivot('flag', true)->first(); + $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); + + $relationTag = $post->tags()->wherePivot('flag', '=', true)->first(); + $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); + } + public function test_can_update_existing_pivot() { $tag = Tag::create(['name' => Str::random()]); From e9831b3b683c2135834ba5650f81ac531af7a244 Mon Sep 17 00:00:00 2001 From: ahinkle Date: Thu, 18 Apr 2019 08:35:20 -0500 Subject: [PATCH 1789/2459] Add wherePivotIn Test --- .../Database/EloquentBelongsToManyTest.php | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php index 413350b3c13e..c421ec505a69 100644 --- a/tests/Integration/Database/EloquentBelongsToManyTest.php +++ b/tests/Integration/Database/EloquentBelongsToManyTest.php @@ -524,13 +524,13 @@ public function test_where_pivot_on_string() $post = Post::create(['title' => Str::random()]); DB::table('posts_tags')->insert([ - ['post_id' => $post->id, 'tag_id' => $tag->id, 'flag' => 'empty'], + ['post_id' => $post->id, 'tag_id' => $tag->id, 'flag' => 'foo'], ]); - $relationTag = $post->tags()->wherePivot('flag', 'empty')->first(); + $relationTag = $post->tags()->wherePivot('flag', 'foo')->first(); $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); - $relationTag = $post->tags()->wherePivot('flag', '=', 'empty')->first(); + $relationTag = $post->tags()->wherePivot('flag', '=', 'foo')->first(); $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); } @@ -550,6 +550,19 @@ public function test_where_pivot_on_boolean() $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); } + public function test_where_pivot_in_method() + { + $tag = Tag::create(['name' => Str::random()]); + $post = Post::create(['title' => Str::random()]); + + DB::table('posts_tags')->insert([ + ['post_id' => $post->id, 'tag_id' => $tag->id, 'flag' => 'foo'], + ]); + + $relationTag = $post->tags()->wherePivotIn('flag', ['foo'])->first(); + $this->assertEquals($relationTag->getAttributes(), $tag->getAttributes()); + } + public function test_can_update_existing_pivot() { $tag = Tag::create(['name' => Str::random()]); From 04a547ee25f78ddd738610cdbda2cb393c6795e9 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Apr 2019 10:23:45 -0500 Subject: [PATCH 1790/2459] revert not in pr --- src/Illuminate/Database/Query/Builder.php | 11 ----------- tests/Database/DatabaseQueryBuilderTest.php | 10 ---------- 2 files changed, 21 deletions(-) diff --git a/src/Illuminate/Database/Query/Builder.php b/src/Illuminate/Database/Query/Builder.php index 1276c11a4dde..dacf672b5d28 100755 --- a/src/Illuminate/Database/Query/Builder.php +++ b/src/Illuminate/Database/Query/Builder.php @@ -616,17 +616,6 @@ public function where($column, $operator = null, $value = null, $boolean = 'and' return $this->whereNested($column, $boolean); } - // If the operator is a literal string 'in' or 'not in', we will assume that - // the developer wants to use the "whereIn / whereNotIn" methods for this - // operation and proxy the query through those methods from this point. - if ($operator == 'in') { - return $this->whereIn($column, $value, $boolean); - } - - if ($operator == 'not in') { - return $this->whereNotIn($column, $value, $boolean); - } - // If the given operator is not found in the list of valid operators we will // assume that the developer is just short-cutting the '=' operators and // we will set the operators to '=' and set the values appropriately. diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 38f91732c8bd..ef1b3c871641 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -644,11 +644,6 @@ public function testBasicWhereIns() $this->assertEquals('select * from "users" where "id" in (?, ?, ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2, 2 => 3], $builder->getBindings()); - $builder = $this->getBuilder(); - $builder->select('*')->from('users')->where('id', 'in', [1, 2, 3]); - $this->assertEquals('select * from "users" where "id" in (?, ?, ?)', $builder->toSql()); - $this->assertEquals([0 => 1, 1 => 2, 2 => 3], $builder->getBindings()); - $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('id', '=', 1)->orWhereIn('id', [1, 2, 3]); $this->assertEquals('select * from "users" where "id" = ? or "id" in (?, ?, ?)', $builder->toSql()); @@ -662,11 +657,6 @@ public function testBasicWhereNotIns() $this->assertEquals('select * from "users" where "id" not in (?, ?, ?)', $builder->toSql()); $this->assertEquals([0 => 1, 1 => 2, 2 => 3], $builder->getBindings()); - $builder = $this->getBuilder(); - $builder->select('*')->from('users')->where('id', 'not in', [1, 2, 3]); - $this->assertEquals('select * from "users" where "id" not in (?, ?, ?)', $builder->toSql()); - $this->assertEquals([0 => 1, 1 => 2, 2 => 3], $builder->getBindings()); - $builder = $this->getBuilder(); $builder->select('*')->from('users')->where('id', '=', 1)->orWhereNotIn('id', [1, 2, 3]); $this->assertEquals('select * from "users" where "id" = ? or "id" not in (?, ?, ?)', $builder->toSql()); From 837e3823e2274d22b8e281d093391b5d9c23029a Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Apr 2019 10:28:45 -0500 Subject: [PATCH 1791/2459] version --- src/Illuminate/Foundation/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Foundation/Application.php b/src/Illuminate/Foundation/Application.php index 9f7739090fac..396688eb234a 100755 --- a/src/Illuminate/Foundation/Application.php +++ b/src/Illuminate/Foundation/Application.php @@ -29,7 +29,7 @@ class Application extends Container implements ApplicationContract, HttpKernelIn * * @var string */ - const VERSION = '5.8.12'; + const VERSION = '5.8.13'; /** * The base path for the Laravel installation. From 8e1aafeb3319206036b2604b03bbe3a037a312b1 Mon Sep 17 00:00:00 2001 From: Shannon Warren Date: Thu, 18 Apr 2019 11:10:37 -0500 Subject: [PATCH 1792/2459] Fix keyType doc block to be more accurate. Only integers are auto-incrementing, strings and UUIDs are not auto incrementing. Therefore, it's not proper for the doc block to say "The "type" of the auto-incrementing ID." when reality it's just asking to define the primary key "type" and this property is only used for the primary key --- src/Illuminate/Database/Eloquent/Model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 6c1d3da58b9d..5202e6368fab 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -50,7 +50,7 @@ abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializab protected $primaryKey = 'id'; /** - * The "type" of the auto-incrementing ID. + * The "type" of primary key ID. * * @var string */ From 3adc11fa6a41591d267cab5bf0c3ea2d388f3185 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Apr 2019 15:41:09 -0500 Subject: [PATCH 1793/2459] initial pass at job based delays --- src/Illuminate/Queue/Jobs/Job.php | 10 ++++++++++ src/Illuminate/Queue/Queue.php | 2 ++ src/Illuminate/Queue/Worker.php | 6 +++++- tests/Queue/QueueBeanstalkdQueueTest.php | 4 ++-- tests/Queue/QueueDatabaseQueueUnitTest.php | 8 ++++---- tests/Queue/QueueRedisQueueTest.php | 10 +++++----- 6 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/Illuminate/Queue/Jobs/Job.php b/src/Illuminate/Queue/Jobs/Job.php index 836cd539ea83..4e06a4176727 100755 --- a/src/Illuminate/Queue/Jobs/Job.php +++ b/src/Illuminate/Queue/Jobs/Job.php @@ -233,6 +233,16 @@ public function maxTries() return $this->payload()['maxTries'] ?? null; } + /** + * Get the number of seconds to delay a failed job before retrying it. + * + * @return int|null + */ + public function delaySeconds() + { + return $this->payload()['delay'] ?? null; + } + /** * Get the number of seconds the job can run. * diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index 91911935a090..8754b80a1fec 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -124,6 +124,7 @@ protected function createObjectPayload($job, $queue) 'displayName' => $this->getDisplayName($job), 'job' => 'Illuminate\Queue\CallQueuedHandler@call', 'maxTries' => $job->tries ?? null, + 'delay' => $job->delay ?? null, 'timeout' => $job->timeout ?? null, 'timeoutAt' => $this->getJobExpiration($job), 'data' => [ @@ -184,6 +185,7 @@ protected function createStringPayload($job, $queue, $data) 'displayName' => is_string($job) ? explode('@', $job)[0] : null, 'job' => $job, 'maxTries' => null, + 'delay' => null, 'timeout' => null, 'data' => $data, ]); diff --git a/src/Illuminate/Queue/Worker.php b/src/Illuminate/Queue/Worker.php index 50bb71fff8c1..e2b5188c9407 100644 --- a/src/Illuminate/Queue/Worker.php +++ b/src/Illuminate/Queue/Worker.php @@ -367,7 +367,11 @@ protected function handleJobException($connectionName, $job, WorkerOptions $opti // so it is not lost entirely. This'll let the job be retried at a later time by // another listener (or this same one). We will re-throw this exception after. if (! $job->isDeleted() && ! $job->isReleased() && ! $job->hasFailed()) { - $job->release($options->delay); + $job->release( + method_exists($job, 'delaySeconds') && ! is_null($job->delaySeconds()) + ? $job->delaySeconds() + : $options->delay + ); } } diff --git a/tests/Queue/QueueBeanstalkdQueueTest.php b/tests/Queue/QueueBeanstalkdQueueTest.php index 9308869ac6b5..bf75167837a9 100755 --- a/tests/Queue/QueueBeanstalkdQueueTest.php +++ b/tests/Queue/QueueBeanstalkdQueueTest.php @@ -23,7 +23,7 @@ public function testPushProperlyPushesJobOntoBeanstalkd() $pheanstalk = $queue->getPheanstalk(); $pheanstalk->shouldReceive('useTube')->once()->with('stack')->andReturn($pheanstalk); $pheanstalk->shouldReceive('useTube')->once()->with('default')->andReturn($pheanstalk); - $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data']]), 1024, 0, 60); + $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data']]), 1024, 0, 60); $queue->push('foo', ['data'], 'stack'); $queue->push('foo', ['data']); @@ -35,7 +35,7 @@ public function testDelayedPushProperlyPushesJobOntoBeanstalkd() $pheanstalk = $queue->getPheanstalk(); $pheanstalk->shouldReceive('useTube')->once()->with('stack')->andReturn($pheanstalk); $pheanstalk->shouldReceive('useTube')->once()->with('default')->andReturn($pheanstalk); - $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data']]), Pheanstalk::DEFAULT_PRIORITY, 5, Pheanstalk::DEFAULT_TTR); + $pheanstalk->shouldReceive('put')->twice()->with(json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data']]), Pheanstalk::DEFAULT_PRIORITY, 5, Pheanstalk::DEFAULT_TTR); $queue->later(5, 'foo', ['data'], 'stack'); $queue->later(5, 'foo', ['data']); diff --git a/tests/Queue/QueueDatabaseQueueUnitTest.php b/tests/Queue/QueueDatabaseQueueUnitTest.php index a6eaf92f4a63..bd7abe013f1d 100644 --- a/tests/Queue/QueueDatabaseQueueUnitTest.php +++ b/tests/Queue/QueueDatabaseQueueUnitTest.php @@ -24,7 +24,7 @@ public function testPushProperlyPushesJobOntoDatabase() $database->shouldReceive('table')->with('table')->andReturn($query = m::mock(stdClass::class)); $query->shouldReceive('insertGetId')->once()->andReturnUsing(function ($array) { $this->assertEquals('default', $array['queue']); - $this->assertEquals(json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data']]), $array['payload']); + $this->assertEquals(json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data']]), $array['payload']); $this->assertEquals(0, $array['attempts']); $this->assertNull($array['reserved_at']); $this->assertIsInt($array['available_at']); @@ -44,7 +44,7 @@ public function testDelayedPushProperlyPushesJobOntoDatabase() $database->shouldReceive('table')->with('table')->andReturn($query = m::mock(stdClass::class)); $query->shouldReceive('insertGetId')->once()->andReturnUsing(function ($array) { $this->assertEquals('default', $array['queue']); - $this->assertEquals(json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data']]), $array['payload']); + $this->assertEquals(json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data']]), $array['payload']); $this->assertEquals(0, $array['attempts']); $this->assertNull($array['reserved_at']); $this->assertIsInt($array['available_at']); @@ -96,14 +96,14 @@ public function testBulkBatchPushesOntoDatabase() $query->shouldReceive('insert')->once()->andReturnUsing(function ($records) { $this->assertEquals([[ 'queue' => 'queue', - 'payload' => json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data']]), + 'payload' => json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data']]), 'attempts' => 0, 'reserved_at' => null, 'available_at' => 'available', 'created_at' => 'created', ], [ 'queue' => 'queue', - 'payload' => json_encode(['displayName' => 'bar', 'job' => 'bar', 'maxTries' => null, 'timeout' => null, 'data' => ['data']]), + 'payload' => json_encode(['displayName' => 'bar', 'job' => 'bar', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data']]), 'attempts' => 0, 'reserved_at' => null, 'available_at' => 'available', diff --git a/tests/Queue/QueueRedisQueueTest.php b/tests/Queue/QueueRedisQueueTest.php index 40b3665184c6..85a807695d9e 100644 --- a/tests/Queue/QueueRedisQueueTest.php +++ b/tests/Queue/QueueRedisQueueTest.php @@ -22,7 +22,7 @@ public function testPushProperlyPushesJobOntoRedis() $queue = $this->getMockBuilder(RedisQueue::class)->setMethods(['getRandomId'])->setConstructorArgs([$redis = m::mock(Factory::class), 'default'])->getMock(); $queue->expects($this->once())->method('getRandomId')->will($this->returnValue('foo')); $redis->shouldReceive('connection')->once()->andReturn($redis); - $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0])); + $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0])); $id = $queue->push('foo', ['data']); $this->assertEquals('foo', $id); @@ -33,7 +33,7 @@ public function testPushProperlyPushesJobOntoRedisWithCustomPayloadHook() $queue = $this->getMockBuilder(RedisQueue::class)->setMethods(['getRandomId'])->setConstructorArgs([$redis = m::mock(Factory::class), 'default'])->getMock(); $queue->expects($this->once())->method('getRandomId')->will($this->returnValue('foo')); $redis->shouldReceive('connection')->once()->andReturn($redis); - $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data'], 'custom' => 'taylor', 'id' => 'foo', 'attempts' => 0])); + $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data'], 'custom' => 'taylor', 'id' => 'foo', 'attempts' => 0])); Queue::createPayloadUsing(function ($connection, $queue, $payload) { return ['custom' => 'taylor']; @@ -50,7 +50,7 @@ public function testPushProperlyPushesJobOntoRedisWithTwoCustomPayloadHook() $queue = $this->getMockBuilder(RedisQueue::class)->setMethods(['getRandomId'])->setConstructorArgs([$redis = m::mock(Factory::class), 'default'])->getMock(); $queue->expects($this->once())->method('getRandomId')->will($this->returnValue('foo')); $redis->shouldReceive('connection')->once()->andReturn($redis); - $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data'], 'custom' => 'taylor', 'bar' => 'foo', 'id' => 'foo', 'attempts' => 0])); + $redis->shouldReceive('eval')->once()->with(LuaScripts::push(), 2, 'queues:default', 'queues:default:notify', json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data'], 'custom' => 'taylor', 'bar' => 'foo', 'id' => 'foo', 'attempts' => 0])); Queue::createPayloadUsing(function ($connection, $queue, $payload) { return ['custom' => 'taylor']; @@ -76,7 +76,7 @@ public function testDelayedPushProperlyPushesJobOntoRedis() $redis->shouldReceive('zadd')->once()->with( 'queues:default:delayed', 2, - json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0]) + json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0]) ); $id = $queue->later(1, 'foo', ['data']); @@ -94,7 +94,7 @@ public function testDelayedPushWithDateTimeProperlyPushesJobOntoRedis() $redis->shouldReceive('zadd')->once()->with( 'queues:default:delayed', 2, - json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0]) + json_encode(['displayName' => 'foo', 'job' => 'foo', 'maxTries' => null, 'delay' => null, 'timeout' => null, 'data' => ['data'], 'id' => 'foo', 'attempts' => 0]) ); $queue->later($date, 'foo', ['data']); From 46dd880e745421afb5e5f3a703096c3346e56b0f Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Apr 2019 15:55:36 -0500 Subject: [PATCH 1794/2459] implement method support --- src/Illuminate/Queue/Queue.php | 20 +++++++++++++++++++- tests/Queue/QueueWorkerTest.php | 23 +++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Queue/Queue.php b/src/Illuminate/Queue/Queue.php index 8754b80a1fec..2fce64003256 100755 --- a/src/Illuminate/Queue/Queue.php +++ b/src/Illuminate/Queue/Queue.php @@ -124,7 +124,7 @@ protected function createObjectPayload($job, $queue) 'displayName' => $this->getDisplayName($job), 'job' => 'Illuminate\Queue\CallQueuedHandler@call', 'maxTries' => $job->tries ?? null, - 'delay' => $job->delay ?? null, + 'delay' => $this->getJobRetryDelay($job), 'timeout' => $job->timeout ?? null, 'timeoutAt' => $this->getJobExpiration($job), 'data' => [ @@ -153,6 +153,24 @@ protected function getDisplayName($job) ? $job->displayName() : get_class($job); } + /** + * Get the retry delay for an object-based queue handler. + * + * @param mixed $job + * @return mixed + */ + public function getJobRetryDelay($job) + { + if (! method_exists($job, 'retryAfter') && ! isset($job->retryAfter)) { + return; + } + + $delay = $job->retryAfter ?? $job->retryAfter(); + + return $delay instanceof DateTimeInterface + ? $this->secondsUntil($delay) : $delay; + } + /** * Get the expiration timestamp for an object-based queue handler. * diff --git a/tests/Queue/QueueWorkerTest.php b/tests/Queue/QueueWorkerTest.php index 374b5d42e259..0d4f7157fed1 100755 --- a/tests/Queue/QueueWorkerTest.php +++ b/tests/Queue/QueueWorkerTest.php @@ -243,6 +243,23 @@ public function test_job_based_max_retries() $this->assertNull($job->failedWith); } + + public function test_job_based_failed_delay() + { + $job = new WorkerFakeJob(function ($job) { + throw new \Exception('Something went wrong.'); + }); + + $job->attempts = 1; + $job->delaySeconds = 10; + + $worker = $this->getWorker('default', ['queue' => [$job]]); + $worker->runNextJob('default', 'queue', $this->workerOptions(['delay' => 3])); + + $this->assertEquals(10, $job->releaseAfter); + } + + /** * Helpers... */ @@ -353,6 +370,7 @@ class WorkerFakeJob implements QueueJobContract public $releaseAfter; public $released = false; public $maxTries; + public $delaySeconds; public $timeoutAt; public $attempts = 0; public $failedWith; @@ -389,6 +407,11 @@ public function maxTries() return $this->maxTries; } + public function delaySeconds() + { + return $this->delaySeconds; + } + public function timeoutAt() { return $this->timeoutAt; From c7a46f0c13b7f6b764c55bb741672bc557eada80 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Thu, 18 Apr 2019 16:00:55 -0500 Subject: [PATCH 1795/2459] Apply fixes from StyleCI (#28264) --- tests/Queue/QueueWorkerTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Queue/QueueWorkerTest.php b/tests/Queue/QueueWorkerTest.php index 0d4f7157fed1..9b8b31c2b928 100755 --- a/tests/Queue/QueueWorkerTest.php +++ b/tests/Queue/QueueWorkerTest.php @@ -243,7 +243,6 @@ public function test_job_based_max_retries() $this->assertNull($job->failedWith); } - public function test_job_based_failed_delay() { $job = new WorkerFakeJob(function ($job) { @@ -259,7 +258,6 @@ public function test_job_based_failed_delay() $this->assertEquals(10, $job->releaseAfter); } - /** * Helpers... */ From ec7d7aeb0850ec317546d4dd54bf70bdaabde55d Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Fri, 19 Apr 2019 00:09:32 +0300 Subject: [PATCH 1796/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index f7635d95321c..49efa4e2b782 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -1,6 +1,19 @@ # Release Notes for 5.8.x -## [Unreleased](https://github.com/laravel/framework/compare/v5.8.12...5.8) +## [Unreleased](https://github.com/laravel/framework/compare/v5.8.13...5.8) + + +## [v5.8.13 (2019-04-18)](https://github.com/laravel/framework/compare/v5.8.12...v5.8.13) + +### Added +- Added `@error` blade directive ([#28062](https://github.com/laravel/framework/pull/28062)) +- Added the ability to register `custom Doctrine DBAL` types in the schema builder ([#28214](https://github.com/laravel/framework/pull/28214), [91a6afe](https://github.com/laravel/framework/commit/91a6afe1f9f8d18283f3ee9a72b636a121f06da5)) + +### Fixed +- Fixed: [Event::fake() does not replace dispatcher for guard](https://github.com/laravel/framework/issues/27451) ([#28238](https://github.com/laravel/framework/pull/28238), [be89773](https://github.com/laravel/framework/commit/be89773c52e7491de05dee053b18a38b177d6030)) + +### Reverted +- Reverted of [`possibility for use in / not in operators in the query builder`](https://github.com/laravel/framework/pull/28192) since of [issue with `wherePivot()` method](https://github.com/laravel/framework/issues/28251) ([04a547ee](https://github.com/laravel/framework/commit/04a547ee25f78ddd738610cdbda2cb393c6795e9)) ## [v5.8.12 (2019-04-16)](https://github.com/laravel/framework/compare/v5.8.11...v5.8.12) From 137640d233b440c4a866c464fec442259de9197c Mon Sep 17 00:00:00 2001 From: Douwe de Haan Date: Fri, 19 Apr 2019 10:26:46 +0200 Subject: [PATCH 1797/2459] Fixed a typo --- src/Illuminate/Database/Migrations/Migrator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Migrations/Migrator.php b/src/Illuminate/Database/Migrations/Migrator.php index 5ff37bccea05..9689da90ee36 100755 --- a/src/Illuminate/Database/Migrations/Migrator.php +++ b/src/Illuminate/Database/Migrations/Migrator.php @@ -580,7 +580,7 @@ public function setOutput(OutputStyle $output) } /** - * Write a note to the conosle's output. + * Write a note to the console's output. * * @param string $message * @return void From 5d0228b584a7b007338303c5abe00d9cc1ba7b3e Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Fri, 19 Apr 2019 08:25:47 -0500 Subject: [PATCH 1798/2459] Update Model.php --- src/Illuminate/Database/Eloquent/Model.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 5202e6368fab..871a477a4481 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -50,7 +50,7 @@ abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializab protected $primaryKey = 'id'; /** - * The "type" of primary key ID. + * The "type" of the primary key ID. * * @var string */ From e83ae1de159776599d2c8d4f63a40bf5188472f4 Mon Sep 17 00:00:00 2001 From: Nikolay Nizruhin Date: Fri, 19 Apr 2019 18:01:01 +0300 Subject: [PATCH 1799/2459] Update auth stubs with @error blade directive --- .../Console/stubs/make/views/auth/login.stub | 16 ++++++------- .../make/views/auth/passwords/email.stub | 8 +++---- .../make/views/auth/passwords/reset.stub | 16 ++++++------- .../stubs/make/views/auth/register.stub | 24 +++++++++---------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub index 3e9d6f7791b7..c12b97e57731 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/login.stub @@ -15,13 +15,13 @@
    - + - @if ($errors->has('email')) + @error('email') - {{ $errors->first('email') }} + {{ $message }} - @endif + @enderror
    @@ -29,13 +29,13 @@
    - + - @if ($errors->has('password')) + @error('password') - {{ $errors->first('password') }} + {{ $message }} - @endif + @enderror
    diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub index 15ee4e4245f0..1fea98456d83 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/email.stub @@ -21,13 +21,13 @@
    - + - @if ($errors->has('email')) + @error('email') - {{ $errors->first('email') }} + {{ $message }} - @endif + @enderror
    diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub index f0cc401a08b5..989931d3a20f 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/passwords/reset.stub @@ -17,13 +17,13 @@
    - + - @if ($errors->has('email')) + @error('email') - {{ $errors->first('email') }} + {{ $message }} - @endif + @enderror
    @@ -31,13 +31,13 @@
    - + - @if ($errors->has('password')) + @error('password') - {{ $errors->first('password') }} + {{ $message }} - @endif + @enderror
    diff --git a/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub b/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub index 92c416ea2cf0..d236a48ecb6d 100644 --- a/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub +++ b/src/Illuminate/Auth/Console/stubs/make/views/auth/register.stub @@ -15,13 +15,13 @@
    - + - @if ($errors->has('name')) + @error('name') - {{ $errors->first('name') }} + {{ $message }} - @endif + @enderror
    @@ -29,13 +29,13 @@
    - + - @if ($errors->has('email')) + @error('email') - {{ $errors->first('email') }} + {{ $message }} - @endif + @enderror
    @@ -43,13 +43,13 @@
    - + - @if ($errors->has('password')) + @error('password') - {{ $errors->first('password') }} + {{ $message }} - @endif + @enderror
    From 221456076137234000d83c0d8aae07cba47b1821 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Fri, 19 Apr 2019 19:03:42 -0300 Subject: [PATCH 1800/2459] [5.8] Fix the usage of unused private property --- .../SupportTestingNotificationFakeTest.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/Support/SupportTestingNotificationFakeTest.php b/tests/Support/SupportTestingNotificationFakeTest.php index daf7b37012e4..49172efdc7f9 100644 --- a/tests/Support/SupportTestingNotificationFakeTest.php +++ b/tests/Support/SupportTestingNotificationFakeTest.php @@ -65,22 +65,20 @@ public function testAssertNotSentTo() public function testResettingNotificationId() { - $notification = new NotificationStub; + $this->fake->send($this->user, $this->notification); - $this->fake->send($this->user, $notification); + $id = $this->notification->id; - $id = $notification->id; + $this->fake->send($this->user, $this->notification); - $this->fake->send($this->user, $notification); + $this->assertSame($id, $this->notification->id); - $this->assertSame($id, $notification->id); + $this->notification->id = null; - $notification->id = null; + $this->fake->send($this->user, $this->notification); - $this->fake->send($this->user, $notification); - - $this->assertNotNull($notification->id); - $this->assertNotSame($id, $notification->id); + $this->assertNotNull($this->notification->id); + $this->assertNotSame($id, $this->notification->id); } public function testAssertTimesSent() From 479d7ee3ab2d8e79a054119f13ac2e902278b22e Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Fri, 19 Apr 2019 19:08:30 -0300 Subject: [PATCH 1801/2459] [5.8] Remove unused variables passed to closures --- tests/Auth/AuthorizeMiddlewareTest.php | 2 +- tests/Database/DatabaseEloquentModelTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Auth/AuthorizeMiddlewareTest.php b/tests/Auth/AuthorizeMiddlewareTest.php index 6d8783433e6a..643bb0c13c7d 100644 --- a/tests/Auth/AuthorizeMiddlewareTest.php +++ b/tests/Auth/AuthorizeMiddlewareTest.php @@ -134,7 +134,7 @@ public function testSimpleAbilityWithOptionalParameter() return $post; }); - $this->gate()->define('view-comments', function ($user, $model = null) use ($post) { + $this->gate()->define('view-comments', function ($user, $model = null) { return true; }); diff --git a/tests/Database/DatabaseEloquentModelTest.php b/tests/Database/DatabaseEloquentModelTest.php index 5b768f6d1212..8a07eeabecb1 100755 --- a/tests/Database/DatabaseEloquentModelTest.php +++ b/tests/Database/DatabaseEloquentModelTest.php @@ -1866,7 +1866,7 @@ public function testWithoutTouchingCallback() $called = false; - EloquentModelStub::withoutTouching(function () use (&$called, $model) { + EloquentModelStub::withoutTouching(function () use (&$called) { $called = true; }); @@ -1879,7 +1879,7 @@ public function testWithoutTouchingOnCallback() $called = false; - Model::withoutTouchingOn([EloquentModelStub::class], function () use (&$called, $model) { + Model::withoutTouchingOn([EloquentModelStub::class], function () use (&$called) { $called = true; }); From bb0b8e4e635a67801a26d28a5d285bea2d157c45 Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Fri, 19 Apr 2019 19:14:31 -0300 Subject: [PATCH 1802/2459] [5.8] Remove unused imports --- tests/Database/DatabaseEloquentBelongsToManyChunkByIdTest.php | 1 - .../DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php | 1 - tests/Filesystem/FilesystemTest.php | 1 - tests/Integration/Cache/MemcachedCacheLockTest.php | 1 - tests/Integration/Cache/MemcachedTaggedCacheTest.php | 1 - 5 files changed, 5 deletions(-) diff --git a/tests/Database/DatabaseEloquentBelongsToManyChunkByIdTest.php b/tests/Database/DatabaseEloquentBelongsToManyChunkByIdTest.php index 9e1bfbfe6348..bd928f386ea4 100644 --- a/tests/Database/DatabaseEloquentBelongsToManyChunkByIdTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManyChunkByIdTest.php @@ -3,7 +3,6 @@ namespace Illuminate\Tests\Database; use PHPUnit\Framework\TestCase; -use Illuminate\Database\Connection; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Eloquent\Model as Eloquent; diff --git a/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php b/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php index 9d0f96729cdb..953f874c3bc5 100644 --- a/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php +++ b/tests/Database/DatabaseEloquentBelongsToManySyncReturnValueTypeTest.php @@ -3,7 +3,6 @@ namespace Illuminate\Tests\Database; use PHPUnit\Framework\TestCase; -use Illuminate\Database\Connection; use Illuminate\Database\Capsule\Manager as DB; use Illuminate\Database\Eloquent\Model as Eloquent; diff --git a/tests/Filesystem/FilesystemTest.php b/tests/Filesystem/FilesystemTest.php index 2a0af10dafbb..84d09bf01462 100755 --- a/tests/Filesystem/FilesystemTest.php +++ b/tests/Filesystem/FilesystemTest.php @@ -5,7 +5,6 @@ use SplFileInfo; use Mockery as m; use PHPUnit\Framework\TestCase; -use League\Flysystem\Adapter\Ftp; use Illuminate\Filesystem\Filesystem; use Illuminate\Foundation\Application; use Illuminate\Filesystem\FilesystemManager; diff --git a/tests/Integration/Cache/MemcachedCacheLockTest.php b/tests/Integration/Cache/MemcachedCacheLockTest.php index 8e9c895f2329..d076f8b187d2 100644 --- a/tests/Integration/Cache/MemcachedCacheLockTest.php +++ b/tests/Integration/Cache/MemcachedCacheLockTest.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Integration\Cache; -use Memcached; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Cache; use Illuminate\Contracts\Cache\LockTimeoutException; diff --git a/tests/Integration/Cache/MemcachedTaggedCacheTest.php b/tests/Integration/Cache/MemcachedTaggedCacheTest.php index 8d387c6359e4..e2a3faa7cfc2 100644 --- a/tests/Integration/Cache/MemcachedTaggedCacheTest.php +++ b/tests/Integration/Cache/MemcachedTaggedCacheTest.php @@ -2,7 +2,6 @@ namespace Illuminate\Tests\Integration\Cache; -use Memcached; use Illuminate\Support\Facades\Cache; /** From 049145313d42471e13170cf7d9a823bed2eadf2f Mon Sep 17 00:00:00 2001 From: Gabriel Caruso Date: Fri, 19 Apr 2019 19:22:58 -0300 Subject: [PATCH 1803/2459] [5.8] Use coalesce operator --- src/Illuminate/Database/Eloquent/Model.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 871a477a4481..79282e19e884 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -1287,9 +1287,7 @@ public static function unsetConnectionResolver() */ public function getTable() { - return isset($this->table) - ? $this->table - : Str::snake(Str::pluralStudly(class_basename($this))); + return $this->table ?? Str::snake(Str::pluralStudly(class_basename($this))); } /** From bc71036081f936b9bd6e856a3e97da27aeb35712 Mon Sep 17 00:00:00 2001 From: Tetiana Blindaruk Date: Sun, 21 Apr 2019 00:42:45 +0300 Subject: [PATCH 1804/2459] [5.8] update changelog --- CHANGELOG-5.8.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG-5.8.md b/CHANGELOG-5.8.md index 49efa4e2b782..2eb6007ddb01 100644 --- a/CHANGELOG-5.8.md +++ b/CHANGELOG-5.8.md @@ -2,6 +2,12 @@ ## [Unreleased](https://github.com/laravel/framework/compare/v5.8.13...5.8) +### Changed +- Update auth stubs with `@error` blade directive ([#28273](https://github.com/laravel/framework/pull/28273)) + +### TODO: +- Job Based Retry Delay ([#28265](https://github.com/laravel/framework/pull/28265)) +- Use Null Coalesce Operator ([#28280](https://github.com/laravel/framework/pull/28280)) ## [v5.8.13 (2019-04-18)](https://github.com/laravel/framework/compare/v5.8.12...v5.8.13) From 41576bdc5fe0ecaeead70ca171639e2d923ce076 Mon Sep 17 00:00:00 2001 From: anas bouzid Date: Sun, 21 Apr 2019 17:31:26 +0100 Subject: [PATCH 1805/2459] [5.8] convert email tables to layout tables --- src/Illuminate/Mail/resources/views/html/button.blade.php | 6 +++--- src/Illuminate/Mail/resources/views/html/footer.blade.php | 2 +- src/Illuminate/Mail/resources/views/html/layout.blade.php | 6 +++--- src/Illuminate/Mail/resources/views/html/panel.blade.php | 4 ++-- .../Mail/resources/views/html/promotion.blade.php | 2 +- .../Mail/resources/views/html/promotion/button.blade.php | 4 ++-- src/Illuminate/Mail/resources/views/html/subcopy.blade.php | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Illuminate/Mail/resources/views/html/button.blade.php b/src/Illuminate/Mail/resources/views/html/button.blade.php index 9d14d9b1619b..512c1d8c777d 100644 --- a/src/Illuminate/Mail/resources/views/html/button.blade.php +++ b/src/Illuminate/Mail/resources/views/html/button.blade.php @@ -1,10 +1,10 @@ - +