Create HTTPClientFactory and introduce ImageTest

This commit is contained in:
Philipp Holzer 2021-08-23 00:14:18 +02:00
parent 73e8db24f9
commit 52c7948526
No known key found for this signature in database
GPG Key ID: 9A28B7D4FF5667BD
7 changed files with 278 additions and 134 deletions

View File

@ -407,11 +407,11 @@ abstract class DI
//
/**
* @return Network\IHTTPRequest
* @return Network\IHTTPClient
*/
public static function httpRequest()
{
return self::$dice->create(Network\IHTTPRequest::class);
return self::$dice->create(Network\IHTTPClient::class);
}
//

View File

@ -0,0 +1,87 @@
<?php
namespace Friendica\Factory;
use Friendica\App;
use Friendica\BaseFactory;
use Friendica\Core\Config\IConfig;
use Friendica\Network\HTTPClient;
use Friendica\Network\IHTTPClient;
use Friendica\Util\Profiler;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
use Psr\Log\LoggerInterface;
class HTTPClientFactory extends BaseFactory
{
/** @var IConfig */
private $config;
/** @var Profiler */
private $profiler;
/** @var App\BaseURL */
private $baseUrl;
public function __construct(LoggerInterface $logger, IConfig $config, Profiler $profiler, App\BaseURL $baseUrl)
{
parent::__construct($logger);
$this->config = $config;
$this->profiler = $profiler;
$this->baseUrl = $baseUrl;
}
public function createClient(): IHTTPClient
{
$proxy = $this->config->get('system', 'proxy');
if (!empty($proxy)) {
$proxyuser = $this->config->get('system', 'proxyuser');
if (!empty($proxyuser)) {
$proxy = $proxyuser . '@' . $proxy;
}
}
$logger = $this->logger;
$onRedirect = function (
RequestInterface $request,
ResponseInterface $response,
UriInterface $uri
) use ($logger) {
$logger->notice('Curl redirect.', ['url' => $request->getUri(), 'to' => $uri]);
};
$guzzle = new Client([
RequestOptions::ALLOW_REDIRECTS => [
'max' => 8,
'on_redirect' => $onRedirect,
'track_redirect' => true,
'strict' => true,
'referer' => true,
],
RequestOptions::HTTP_ERRORS => false,
// Without this setting it seems as if some webservers send compressed content
// This seems to confuse curl so that it shows this uncompressed.
/// @todo We could possibly set this value to "gzip" or something similar
RequestOptions::DECODE_CONTENT => '',
RequestOptions::FORCE_IP_RESOLVE => ($this->config->get('system', 'ipv4_resolve') ? 'v4' : null),
RequestOptions::CONNECT_TIMEOUT => 10,
RequestOptions::TIMEOUT => $this->config->get('system', 'curl_timeout', 60),
// by default we will allow self-signed certs
// but you can override this
RequestOptions::VERIFY => (bool)$this->config->get('system', 'verifyssl'),
RequestOptions::PROXY => $proxy,
]);
$userAgent = FRIENDICA_PLATFORM . " '" .
FRIENDICA_CODENAME . "' " .
FRIENDICA_VERSION . '-' .
DB_UPDATE_VERSION . '; ' .
$this->baseUrl->get();
return new HTTPClient($logger, $this->profiler, $this->config, $userAgent, $guzzle);
}
}

View File

@ -23,23 +23,22 @@ namespace Friendica\Network;
use DOMDocument;
use DomXPath;
use Friendica\App;
use Friendica\Core\Config\IConfig;
use Friendica\Core\System;
use Friendica\Util\Network;
use Friendica\Util\Profiler;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\FileCookieJar;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\TransferException;
use Psr\Http\Message\RequestInterface;
use GuzzleHttp\RequestOptions;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
use Psr\Log\LoggerInterface;
/**
* Performs HTTP requests to a given URL
*/
class HTTPRequest implements IHTTPRequest
class HTTPClient implements IHTTPClient
{
/** @var LoggerInterface */
private $logger;
@ -48,31 +47,20 @@ class HTTPRequest implements IHTTPRequest
/** @var IConfig */
private $config;
/** @var string */
private $baseUrl;
private $userAgent;
/** @var Client */
private $client;
public function __construct(LoggerInterface $logger, Profiler $profiler, IConfig $config, App\BaseURL $baseUrl)
public function __construct(LoggerInterface $logger, Profiler $profiler, IConfig $config, string $userAgent, Client $client)
{
$this->logger = $logger;
$this->profiler = $profiler;
$this->config = $config;
$this->baseUrl = $baseUrl->get();
$this->logger = $logger;
$this->profiler = $profiler;
$this->config = $config;
$this->userAgent = $userAgent;
$this->client = $client;
}
/** {@inheritDoc}
*
* @throws HTTPException\InternalServerErrorException
*/
public function head(string $url, array $opts = [])
{
$opts['nobody'] = true;
return $this->get($url, $opts);
}
/**
* {@inheritDoc}
*/
public function get(string $url, array $opts = [])
protected function request(string $method, string $url, array $opts = [])
{
$this->profiler->startRecording('network');
@ -105,19 +93,13 @@ class HTTPRequest implements IHTTPRequest
return CurlResult::createErrorCurl($url);
}
$curlOptions = [];
$conf = [];
if (!empty($opts['cookiejar'])) {
$curlOptions[CURLOPT_COOKIEJAR] = $opts["cookiejar"];
$curlOptions[CURLOPT_COOKIEFILE] = $opts["cookiejar"];
$jar = new FileCookieJar($opts['cookiejar']);
$conf[RequestOptions::COOKIES] = $jar;
}
// These settings aren't needed. We're following the location already.
// $curlOptions[CURLOPT_FOLLOWLOCATION] =true;
// $curlOptions[CURLOPT_MAXREDIRS] = 5;
$curlOptions[CURLOPT_HTTPHEADER] = [];
if (!empty($opts['accept_content'])) {
array_push($curlOptions[CURLOPT_HTTPHEADER], 'Accept: ' . $opts['accept_content']);
}
@ -126,74 +108,17 @@ class HTTPRequest implements IHTTPRequest
$curlOptions[CURLOPT_HTTPHEADER] = array_merge($opts['header'], $curlOptions[CURLOPT_HTTPHEADER]);
}
$curlOptions[CURLOPT_RETURNTRANSFER] = true;
$curlOptions[CURLOPT_USERAGENT] = $this->getUserAgent();
$range = intval($this->config->get('system', 'curl_range_bytes', 0));
if ($range > 0) {
$curlOptions[CURLOPT_RANGE] = '0-' . $range;
}
// Without this setting it seems as if some webservers send compressed content
// This seems to confuse curl so that it shows this uncompressed.
/// @todo We could possibly set this value to "gzip" or something similar
$curlOptions[CURLOPT_ENCODING] = '';
$curlOptions[CURLOPT_USERAGENT] = $this->userAgent;
if (!empty($opts['headers'])) {
$this->logger->notice('Wrong option \'headers\' used.');
$curlOptions[CURLOPT_HTTPHEADER] = array_merge($opts['headers'], $curlOptions[CURLOPT_HTTPHEADER]);
}
if (!empty($opts['nobody'])) {
$curlOptions[CURLOPT_NOBODY] = $opts['nobody'];
}
$curlOptions[CURLOPT_CONNECTTIMEOUT] = 10;
if (!empty($opts['timeout'])) {
$curlOptions[CURLOPT_TIMEOUT] = $opts['timeout'];
} else {
$curl_time = $this->config->get('system', 'curl_timeout', 60);
$curlOptions[CURLOPT_TIMEOUT] = intval($curl_time);
}
// by default we will allow self-signed certs
// but you can override this
$check_cert = $this->config->get('system', 'verifyssl');
$curlOptions[CURLOPT_SSL_VERIFYPEER] = ($check_cert) ? true : false;
if ($check_cert) {
$curlOptions[CURLOPT_SSL_VERIFYHOST] = 2;
}
$proxy = $this->config->get('system', 'proxy');
if (!empty($proxy)) {
$curlOptions[CURLOPT_HTTPPROXYTUNNEL] = 1;
$curlOptions[CURLOPT_PROXY] = $proxy;
$proxyuser = $this->config->get('system', 'proxyuser');
if (!empty($proxyuser)) {
$curlOptions[CURLOPT_PROXYUSERPWD] = $proxyuser;
}
}
if ($this->config->get('system', 'ipv4_resolve', false)) {
$curlOptions[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
}
$logger = $this->logger;
$onRedirect = function(
RequestInterface $request,
ResponseInterface $response,
UriInterface $uri
) use ($logger) {
$logger->notice('Curl redirect.', ['url' => $request->getUri(), 'to' => $uri]);
};
$onHeaders = function (ResponseInterface $response) use ($opts) {
if (!empty($opts['content_length']) &&
$response->getHeaderLine('Content-Length') > $opts['content_length']) {
@ -201,20 +126,11 @@ class HTTPRequest implements IHTTPRequest
}
};
$client = new Client([
'allow_redirect' => [
'max' => 8,
'on_redirect' => $onRedirect,
'track_redirect' => true,
'strict' => true,
'referer' => true,
],
'on_headers' => $onHeaders,
'curl' => $curlOptions
]);
try {
$response = $client->get($url);
$response = $this->client->$method($url, [
'on_headers' => $onHeaders,
'curl' => $curlOptions,
]);
return new GuzzleResponse($response, $url);
} catch (TransferException $exception) {
if ($exception instanceof RequestException &&
@ -228,6 +144,23 @@ class HTTPRequest implements IHTTPRequest
}
}
/** {@inheritDoc}
*
* @throws HTTPException\InternalServerErrorException
*/
public function head(string $url, array $opts = [])
{
return $this->request('head', $url, $opts);
}
/**
* {@inheritDoc}
*/
public function get(string $url, array $opts = [])
{
return $this->request('get', $url, $opts);
}
/**
* {@inheritDoc}
*
@ -262,7 +195,7 @@ class HTTPRequest implements IHTTPRequest
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_USERAGENT, $this->getUserAgent());
curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
if ($this->config->get('system', 'ipv4_resolve', false)) {
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
@ -376,7 +309,7 @@ class HTTPRequest implements IHTTPRequest
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $this->getUserAgent());
curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
curl_exec($ch);
$curl_info = @curl_getinfo($ch);
@ -421,7 +354,7 @@ class HTTPRequest implements IHTTPRequest
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $this->getUserAgent());
curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent);
$body = curl_exec($ch);
curl_close($ch);
@ -485,17 +418,4 @@ class HTTPRequest implements IHTTPRequest
]
);
}
/**
* {@inheritDoc}
*/
public function getUserAgent()
{
return
FRIENDICA_PLATFORM . " '" .
FRIENDICA_CODENAME . "' " .
FRIENDICA_VERSION . '-' .
DB_UPDATE_VERSION . '; ' .
$this->baseUrl;
}
}

View File

@ -24,7 +24,7 @@ namespace Friendica\Network;
/**
* Interface for calling HTTP requests and returning their responses
*/
interface IHTTPRequest
interface IHTTPClient
{
/**
* Fetches the content of an URL
@ -114,11 +114,4 @@ interface IHTTPRequest
* @todo Remove the $fetchbody parameter that generates an extraneous HEAD request
*/
public function finalUrl(string $url, int $depth = 1, bool $fetchbody = false);
/**
* Returns the current UserAgent as a String
*
* @return string the UserAgent as a String
*/
public function getUserAgent();
}

View File

@ -220,8 +220,11 @@ return [
['getBackend', [], Dice::CHAIN_CALL],
],
],
Network\IHTTPRequest::class => [
'instanceOf' => Network\HTTPRequest::class,
Network\IHTTPClient::class => [
'instanceOf' => Factory\HTTPClientFactory::class,
'call' => [
['createClient', [], Dice::CHAIN_CALL],
],
],
Factory\Api\Mastodon\Error::class => [
'constructParams' => [
@ -232,5 +235,5 @@ return [
'constructParams' => [
[Dice::INSTANCE => Util\ReversedFileReader::class],
]
]
],
];

View File

@ -0,0 +1,81 @@
<EFBFBD>PNG

<EFBFBD><EFBFBD><EFBFBD>Bh[ <0C>]\<1F><>|<7C>;?<3F>[<5B><><EFBFBD><EFBFBD>8<EFBFBD>h <09>p&<26>&Xw^<5E>v<EFBFBD><76>ނ<EFBFBD><DE82><EFBFBD><EFBFBD><<3C><><EFBFBD><EFBFBD>W<EFBFBD><57><EFBFBD><EFBFBD>oBk<42>%X<<3C>W<EFBFBD><57><EFBFBD>M<EFBFBD>z<EFBFBD><7A><EFBFBD>g<EFBFBD><1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'OǦ<4F>ȖʹK<CDB4> <1E><>.x<>U
<EFBFBD><EFBFBD><EFBFBD><17><><EFBFBD>O?<3F>؎dA<10>,<2C><>ú<EFBFBD><C3BA><EFBFBD><EFBFBD><EFBFBD> <0C>u<EFBFBD> P<>*8z<38>}y<>W<EFBFBD><57><13>ZfG<66><47>A h<>`1pO)x<><78>+<2B>:1#1<07><><EFBFBD>><3E><>'<27><><EFBFBD><EFBFBD><EFBFBD>K<07>=<3D>E<EFBFBD>Ah<41><68><EFBFBD> <20>|<7C><>B<EFBFBD><03>A <04>l<>s<EFBFBD><73><EFBFBD><EFBFBD><EFBFBD>o}<7D><><EFBFBD><EFBFBD>!<02>x<EFBFBD><78> <20>Q<EFBFBD> n<>z<EFBFBD>u<EFBFBD><75><EFBFBD>kud@fd@Ȍ<05> <20><><EFBFBD>=v<><76><EFBFBD><EFBFBD><EFBFBD>i<>U<04>#hc <01><>w<EFBFBD><77>ڰ)dd&f@f0<66>D<EFBFBD>]x~<7E><>7<EFBFBD><37><EFBFBD><EFBFBD>o<EFBFBD>,<2C># <20>x<EFBFBD> ,e<>_<EFBFBD><5F><EFBFBD>7\;<3B>ߥ#M<><4D>L<EFBFBD>Ā<EFBFBD><C480><EFBFBD><EFBFBD>X<EFBFBD>#c<><63>_<EFBFBD><5F><EFBFBD><EFBFBD><EFBFBD>?<3F>qDFa)<29>~<7E><>|<7C><><EFBFBD>o<EFBFBD>X<EFBFBD><58>Ȭ<EFBFBD><C8AC><19><>00 <03>A$<24>
<EFBFBD><EFBFBD>~<7E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><13><>’<EFBFBD><C292><EFBFBD> ?<3F>S7"1X<31>
0<>` ƂE<><45><EFBFBD>͓w<CD93><77>/<>!<21>%N<> ,:B<><42>t<EFBFBD><74>VG<><10><><EFBFBD> <20>٤<>e<EFBFBD><65><EFBFBD><10><>v}<7D><>}<7D>_}<7D>ɩZ<C9A9><5A><04><>v<EFBFBD>b<06><>.<2E><><EFBFBD>Vk!#C<bh<62>+ `<60><>X<EFBFBD>[ <f<><66>_<EFBFBD><5F><1F><>W_<(Q-AX:<3A>]<5D>\<5C><><EFBFBD><EFBFBD>rc_w<5F>5<04><><EFBFBD><EFBFBD>t*<2A>,v"<22> ]<5D><><EFBFBD>O<EFBFBD><4F><0F><>˟<EFBFBD><CB9F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>h<EFBFBD>X<>DAX<41><58>]<5D><1C>n\q<>-<2D><><EFBFBD>2<>1<04><><EFBFBD><EFBFBD><EFBFBD>
!<21>1 <20>-
<04><>ܽ<EFBFBD><DCBD>o<EFBFBD>z<EFBFBD><7A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><05><>,, X<><58><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԝ<EFBFBD><D49C>.<2E>!<21><> OY#+<2B>'<27><><EFBFBD><01>ǿ<EFBFBD><C7BF><EFBFBD><EFBFBD>ݏ><3E><>ݟI<10> F' 3 |<7C><><EFBFBD><EFBFBD>t٘<>c<EFBFBD>`l<>ݖ<EFBFBD>0<EFBFBD>X<EFBFBD>L<1A>f<><66><EFBFBD>XTG'f><3E>W<EFBFBD><57><EFBFBD>'<27><>p<EFBFBD>x<EFBFBD>=:Ȣ<04><>$<24>B<04><><EFBFBD><1C><>M<EFBFBD>J<EFBFBD><4A><11><18>0<EFBFBD><30><EFBFBD>'<27><14>1q$ˤ=<3D><><EFBFBD>%<25>
<EFBFBD>@?x<><78><1B><><EFBFBD>}i<><69><EFBFBD>*Hk-A<>3<EFBFBD>$X <20><><EFBFBD><EFBFBD>р2<D180>L<EFBFBD>6<EFBFBD><36>T<EFBFBD>$<24>T<EFBFBD>S <20>R <0B>Af Td<54>G<EFBFBD><47><EFBFBD><EFBFBD>?z<><7A>O<EFBFBD>XX<58><58>W:M<> <1E>}<7D><6D>W<06><>f<EFBFBD>0<><30><EFBFBD>H<1C><>lb; 2<><32><EFBFBD>*<02><><EFBFBD>d<EFBFBD>C<EFBFBD><43>t<EFBFBD><74>><3E><>]<5D>C<EFBFBD><43>@c<>?<3F>g<EFBFBD><67> <20>W<EFBFBD><57><EFBFBD><EFBFBD> <0C>1ȆL\<0E>$<24><>jd=<3D><><EFBFBD>rv<16><>x<EFBFBD>a <20><><EFBFBD><EFBFBD>3<EFBFBD><33>'<27><><EFBFBD>G_y<5F><79> <0C>M<EFBFBD>`<60>3<15><> <20>o<EFBFBD>m<EFBFBD><1C><>1h<31>C<>Li<>GI<47>2<><32>? ><01><><}<7D><>?}<7D><>w<7F>X%D<><44><EFBFBD> <20>N,<06>.<2E>x<><1D>zH<7A><48> <05><><EFBFBD><EFBFBD>I|op<6F>\h<><68>><3E>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>$<24> <20><><EFBFBD><EFBFBD><EFBFBD><1E><><EFBFBD>}y<><79><EFBFBD>'<27><>+K<><4B><EFBFBD>a<EFBFBD><10><>T<EFBFBD><54>_<EFBFBD><5F><EFBFBD>cS"1R<31>(D<><18><>(!*P<><50> <20><>s<EFBFBD><73>d)<72><N<15>r#<23><><EFBFBD>MȀ|ߚ<>ߺe<DFBA><65>=<3D>1 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>J<EFBFBD><4A><EFBFBD><EFBFBD>W+u2L<32>
t<EFBFBD>/<2F><> <20>$E
mc><04>6 Ǒ&<26>d<04>><3E><>_<EFBFBD>*<2A>[<5B><14>2<EFBFBD>;<3B>z<EFBFBD><7A><EFBFBD><02>S<EFBFBD>w<EFBFBD><77><EFBFBD>{<7B>5<EFBFBD><EFBFBD><E681A0>p<EFBFBD>U<10>M^,,@<40><><EFBFBD>o|<7C>;O<>,<2C><>l<EFBFBD>{DM<1C><02>D<EFBFBD>\<5C><>
<EFBFBD><EFBFBD><EFBFBD><10><><EFBFBD><EFBFBD><w<><77>m<EFBFBD><6D><1D>
Az契<EFBFBD>3bs <20>Z^<5E><><EFBFBD><EFBFBD><7F>}A<><41><EFBFBD> <20><YX<59><58><EFBFBD>R-4<>||{<7B><>3"2 #rAo<41><6F>-<2D>$О.d<>iz- <20>a<EFBFBD>̞ <0B>F<EFBFBD><15><><0E><><EFBFBD><EFBFBD>ȶ<EFBFBD><C8B6>W<EFBFBD>><3E><><EFBFBD>}go13.\ A<><ZX 0Y<30><59><EFBFBD>}l<><6C><EFBFBD>^<5E><><EFBFBD>"<22>0)֡<> <09><><03>8<15>\<5C><>'m><3E><>@;<3B>z<EFBFBD>mj<6D> b ز<><D8B2>+<2B>~fsߵC<DFB5>v_EA<45><1F>,}<7D><><EFBFBD><EFBFBD><EFBFBD>¿<EFBFBD><C2BF>BWA[<5B><>P+<2B>e<EF8FAD>t'<27>1<>.<2E>=\'<27>[!S^<12>G<EFBFBD>8[`xW9I*<2A><18>)<29><><EFBFBD>Vu<56><75><EFBFBD><><DFBD>o<EFBFBD><15>ܐ?<3F><>Y <0C><><EFBFBD><7F><EFBFBD>|<7C><>^<5E><>@<11>Qd<51>!)<29>Y<EFBFBD><59><EFBFBD><14><>g<>f!Ʃ <0C> <09><$b<>X[<5B><> "<06><>^<5E><><EFBFBD>=<3D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>%<25><>3<EFBFBD><33>: BǑG<C791>{?<3F><><EFBFBD><EFBFBD><1F><><EFBFBD>H<EFBFBD><48>٦<EFBFBD><11>!<21>#<23>6<><36><EFBFBD>5(<28><>J<EFBFBD>)<0E><18>JT<4A>f<EFBFBD>ݓ<EFBFBD>w<EFBFBD><q^=$6 <03>><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>{<7B><>Ҫ<1E><><04>5<EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD>><3E>'<27><>ӗY<><15><><EFBFBD>2*elԼ刡s<15>8c+)<29>AJ<41>s<EFBFBD>T<>M{q<><71>><3E>
4XT<58>%<25><>DCEo<45><6F><EFBFBD><02><><EFBFBD>'<27><1E><>=<3D><>IJ<17><><EFBFBD>K<EFBFBD><4B> X <20><1F>x߿z$(x<>W<EFBFBD>T<EFBFBD><54><EFBFBD><EFBFBD>,"<22><><EFBFBD>Z<EFBFBD><12>
e<><65>T<EFBFBD>_<EFBFBD><5F><EFBFBD>'<27>R!tiY<69><59><EFBFBD><EFBFBD> <09>9<EFBFBD>A!<11>"Ac-'W<><57>=<3D>5<EFBFBD>
L<14><>ZT33z^<5E> /(BO!<13>g<EFBFBD><67> <20>>0y#<23><><EFBFBD><EFBFBD> <20><>!)J<>灧Py蹧<79>y񂏁<79><F1828F81><0F>G<EFBFBD><07><>J<EFBFBD><4A> <0B><>{T<><54><14>9<EFBFBD>Q,)<16>`<60>z<EFBFBD>o<<3C><><EFBFBD><EFBFBD><EFBFBD>I<15>F<EFBFBD><46>e9<65>!e<>ALC$7!<21>fP
<EFBFBD><01><><EFBFBD><EFBFBD><EFBFBD>Vt<>v?t<>HW<48>_=ҷq<D2B7><71><10>K<EFBFBD> ec_<17><>8<EFBFBD><38>Z<EFBFBD>ku<6B>׹V7<56>:<3A>j<EFBFBD>^3<>:<3A>j\<5C><>j<EFBFBD>T+<2B>R<EFBFBD><52>\<5C><>j<EFBFBD>T<EFBFBD>P<EFBFBD><50>j̈́!<21>!<21><>&
8<><><C4B8>><18>/<2F>kvK<76>e#!" 9EC<45>G<EFBFBD><03><><EFBFBD>G<EFBFBD>oR7 <02> *<16>X<EFBFBD>B
*<16>T<EFBFBD>b<EFBFBD>J%*<15>T<EFBFBD>R }<1F> <03>

Hn,Fw1<11>J72c<32>F+<2B>nnL<><4C><EFBFBD>_<EFBFBD><5F>Jc|<7C><>Y!<21>r<EFBFBD>ZM)T
<EFBFBD><EFBFBD>
 <09>E<EFBFBD><45>W<EFBFBD><57>aO<61>Z<EFBFBD><5A>/<1F><>/<2F><><0F><>e<EFBFBD><65>_<EFBFBD><5F><EFBFBD><EFBFBD>^<5E><><EFBFBD>n<EFBFBD>x>,1<>u<14>D<EFBFBD><44><EFBFBD><EFBFBD><EFBFBD>؃<EFBFBD><D883><EFBFBD><13>+<2B><><EFBFBD>׬<1E><><EFBFBD><EFBFBD>w_<77><5F>u˯[7|<7C><><02>,<2C>3<EFBFBD><33>9 M<>Ƨ<EFBFBD><C6A7><EFBFBD>x4><3E><>'<27><18><>&<26><>D4><3E><>O<EFBFBD><EFBFBD><E9B299>J<EFBFBD>T<EFBFBD>z<EFBFBD> <0C><><EFBFBD>( D7<44>"<22><>ζ<EFBFBD>V<EFBFBD><56>+y<14><04>ZF <20>3<EFBFBD><33> 0<11>T<EFBFBD>R KEohп<68>2o<32>
<1B>6o6n,\<5C>1X<31><58>XF<58>s<EFBFBD><73><EFBFBD>Q1<51>ώ<EFBFBD> X<><58>D<EFBFBD><0E>G^<5E><><EFBFBD>=<3D>O<1C>ӧM<D3A7>€F@H˖a-<2D><7A>Z<EFBFBD>k<>[<5B><06><>Ѱ<EFBFBD>{<7B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<22><><01><>i<13><> 
<EFBFBD>U*<2A>[<5B>^l<>X<EFBFBD>r<EFBFBD><72>yC<79>fM<66>r<14><><EFBFBD><EFBFBD>-<2D>]%,<2C><>/X\<5C>M~<7E><><EFBFBD><EFBFBD>;L<><4C><EFBFBD>:3<><33><EFBFBD>
<0F>Y<EFBFBD>'<>.!<21>_<EFBFBD> <20>x<EFBFBD><78><EFBFBD><EFBFBD><03>mO<6D><4F><19><><EFBFBD><EFBFBD><EFBFBD>23<03>)֞bf<03><>l@[5s<35><73>&<26>Ő<EFBFBD>м0<D0BC><30>`<60>Hsrd <20><><EFBFBD>U<EFBFBD><55>(\<5C><>p<EFBFBD><70><EFBFBD>k<EFBFBD><14><><EFBFBD><1C><><EFBFBD><EFBFBD><38>^~.!KB<4B> <20><><EFBFBD><0F><><07><><EFBFBD><05>@<40><>l<<3C><><EFBFBD><EFBFBD><EFBFBD><1A> (6<><36> S\<5C><> \׳jY<6A>'<1E> C <20>B<EFBFBD> ֯+]{M<>u<EFBFBD><15><><EFBFBD><EFBFBD>q<EFBFBD><71>_<EFBFBD><5F>'<27>x<EFBFBD>Y
<EFBFBD><EFBFBD><EFBFBD>_@<40><><EFBFBD>1`<60><>54/6<><36>J;
<EFBFBD><06> N<><4E>~<7E>tA<> s<>O<EFBFBD>
5<>lX_<58>fK<66>u<EFBFBD>u<EFBFBD><75><EFBFBD>`<60>o<><6F><EFBFBD>E<EFBFBD><45><EFBFBD>R,d<06><><EFBFBD><EFBFBD>?<3F>?<3F>y&6<><36><EFBFBD>x<EFBFBD><78><EFBFBD>><3E>I <20>k<EFBFBD><12><>3ل5<D984><1D>5G<35><47>NI<4E><49>1<EFBFBD>8 <01>J%<><7F><15>K7<4B>X<EFBFBD><58>ҵ<EFBFBD>x#+Пs<D09F>!<11><1C> <0B><><EFBFBD><EFBFBD>5<EFBFBD>FS<46><53><EFBFBD>~<7E><18><><EFBFBD>L 3<> P<><<3C><>#`<60>tj`<60><>#<23>
=<3D><><15>Y<EFBFBD><59><EFBFBD>˵]<5D>,Y<><59>!<21><><EFBFBD>w<EFBFBD><77>Lxp<04>M 5<>F<EFBFBD>)<29><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2q<<3C><53><11>FS<><53>adE<64><45><EFBFBD><EFBFBD>{<7B>=<3D><><EFBFBD>\6k?Q|<7C>K^<5E> <20>z<><EFBFBD><7F><EFBFBD>=bN<1D> 0I<30>s<EFBFBD>
0<02>&<26>Yˋ<59><CB8B><EFBFBD>VE<56>6K<36>]<5D><>ZK<5A>zhj55<35><35>{<7B><>}ok<7F>V<EFBFBD>nxIClj<6C>^:a>D<> To<6F><03>9<EFBFBD><0F>1<EFBFBD>)<29>}ÜN<C39C><4E>h^ig^<5E>Sԥ#<23>6{ <20><><10>g-<2D>i<03>l W<> P<><50><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0F><><EFBFBD><EFBFBD><EFBFBD>Β<EFBFBD> <20>,<2C><>|eߛ~<7E><EFBFBD>2<EFBFBD>>3W<> <0C>hV<68>u<EFBFBD><75><EFBFBD>-<2D><>/`X⾡<58>^3\<5C>b1<62><31>e<EFBFBD><65>s<EFBFBD>oy0izgm<>(<28>lYR<59>P<EFBFBD>`td<74><64>7>k*Ӡ<><D3A0><EFBFBD><10><1C>&
!<21>8 MqX<71>zdta<><61>Ȅ<1A><><EFBFBD>״<>k<EFBFBD>j<EFBFBD>i<EFBFBD><1A><19>40.<2E>Txct<63><74><0F>i<EFBFBD><69><EFBFBD><EFBFBD>}<7D><>ًܸg<DCB8>XX <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>u<EFBFBD>۟<EFBFBD>z<EFBFBD><02>u<EFBFBD>;<3B><><EFBFBD>@
jt;<3B><10>C~<7E>ߥ<EFBFBD>zz<7A>t<EFBFBD>U#<23><><EFBFBD><EFBFBD>=<3D><>v<EFBFBD><76><11>j<EFBFBD>*J<><4A><EFBFBD>9 <0C>?<3F>* <20>Y<EFBFBD>q[<06>4<EFBFBD>e BN<>ߜ<EFBFBD><DF9C>G<EFBFBD><47><EFBFBD>m<EFBFBD>D<EFBFBD>Y<EFBFBD>f].<0F><><EFBFBD>F<46>#<23><>a<EFBFBD>
d<EFBFBD>" <20>5 (n<><6E><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߓ<EFBFBD><DF93>?<3F>{e0<><30>7Btb<74>4<EFBFBD>C$D<><44><1D><>:Xߐk;@3S^<5E>k<EFBFBD><6B><EFBFBD><EFBFBD>^<5E>V<EFBFBD>J<EFBFBD><4A><EFBFBD>`<60><02>]P<><50><0E><><EFBFBD>S<EFBFBD>$<24>3q<33>P<EFBFBD>7<EFBFBD><1B><><EFBFBD>v="r<><72>D !0<>B<><42>;<3B> F<><46>R<EFBFBD>y<EFBFBD><1D><><EFBFBD><EFBFBD>v͢Sd<53>S<10><>MR<4D>]7ލ<37><DE8D>'<27><><EFBFBD>ǜ<EFBFBD><C79C><EFBFBD>y<EFBFBD>l<EFBFBD>1$F&D<><44><EFBFBD> <20><04>H<EFBFBD>mf<17>5<EFBFBD>Ev?#<23>A<EFBFBD><41>_<EFBFBD>e<EFBFBD>=<3D><>.*"X<> P<><50>.6f<EFBFBD><EFBFBD>o<EFBFBD><EFBFBD>DB<44>[##X*<0E>'<27><><EFBFBD><EFBFBD><EFBFBD><11>v&$D<>Gqf<71><66><EFBFBD><EFBFBD><EFBFBD>6<EFBFBD><36><EFBFBD><EFBFBD><EFBFBD>o]$G<>`D<><44>]3<01><><EFBFBD><EFBFBD><01><>S<EFBFBD>F/<2F><><<3C>qGD<47>T)n<><6E><EFBFBD>\<5C> 0"<22>FDm <0B>v<76> <06><><EFBFBD><EFBFBD>Q58<35><38>3?"X<> ̌<>]7܍<37>/?<3F><0F> }<7D><>F<EFBFBD><46><EFBFBD><EFBFBD>BDD D<>^<5E>ls <11> <02>Ǥ]&<26>M+]<14><><EFBFBD><12>~<7E>ODX<44><58>`<60>Gb:@<40><><EFBFBD><EFBFBD><1F>g;<3B>[R<18>"2<>ޢ5<DEA2>00<>:<3A><><EFBFBD><1A>f<EFBFBD>J<EFBFBD>" D<1A><06><><EFBFBD>p<EFBFBD>0"X<><58>80<38>ūoF<6F>8<EFBFBD><38><EFBFBD>5<EFBFBD>۫<17>p!0<12><><EFBFBD>A{<7B><><EFBFBD>k<>"X#<23><>S<EFBFBD>P<EFBFBD><50><EFBFBD><EFBFBD>+LJOM<4F>jUI<55>b<EFBFBD>"#<23><>p<10> <0B><><EFBFBD>ba<62>ۏr<DB8F>  ""<1A>!<21><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1B><>!<21>tB<>qN)0 rM<72>k<><6B><EFBFBD>Ę>u*<2A>m<16><>D<EFBFBD><44><EFBFBD>_Zl<5A><01>_<EFBFBD><5F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>^$B? <20>C<EFBFBD>G/@<40><07>G<EFBFBD>#<23>ߧ<>W<EFBFBD><57>A@<40><><EFBFBD><07><><EFBFBD><EFBFBD>
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>JE<>E)<29>j <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=<3D>>a<>#<23><>@<40><> <20>Ⱥ<EFBFBD><C8BA>~<7E><><EFBFBD><EFBFBD><18> }}=?<3F>,<2C><><1A><EFBFBD>G<EFBFBD><47><EFBFBD><EFBFBD><EFBFBD><EFBFBD>v<EFBFBD><76><EFBFBD><EFBFBD>a<EFBFBD><61>A<><41><EFBFBD><EFBFBD> c<>Fl<46><6C>=<3D>k<EFBFBD>P<EFBFBD>U<EFBFBD> \c|A<>8<EFBFBD>Kx<4B>x<EFBFBD><78><EFBFBD>{<7B>/<2F><>Σz<CEA3>$d<><64><EFBFBD><EFBFBD><EFBFBD><EFBFBD>l<EFBFBD>9 `<60>v<> "`HhP3"*<2A><><EFBFBD>PCR<43><52><EFBFBD>O<EFBFBD><10>Q<EFBFBD><51>OƗ@.<16><>%:o<>H<EFBFBD>[<5B><><EFBFBD>j#<23><> @<40>C<EFBFBD>C<EFBFBD><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>5<EFBFBD>|<1F><><18>x<>{<10><><EFBFBD>
<(<12><>J
<EFBFBD><EFBFBD>E<EFBFBD><EFBFBD><17><><EFBFBD>r<EFBFBD>3 B<>W<EFBFBD>1<r4^<11><>z<EFBFBD><7A><EFBFBD><EFBFBD>
<1B>c6<63><0F><0F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>{<7B>{<7B><><18><><EFBFBD>K>|JCZ <09>
<EFBFBD>K<EFBFBD>O<EFBFBD><EFBFBD>;@<40><><EFBFBD><EFBFBD><EFBFBD><1F><><EFBFBD>'#,rD<72><44><17> <0B>ozO<7A><4F>0<EFBFBD>^zG߇<47>j<EFBFBD><0F><><EFBFBD>O6<4F><04>$<24>#<23><><EFBFBD><EFBFBD><EFBFBD>%’<>]
K
K><3E><><11><0E>,<2C><>5<EFBFBD>w_<77><5F><05> 1<> *<2A><><EFBFBD><EFBFBD>ʋ?`<60><>I<EFBFBD><49>K<EFBFBD><4B>Y.<2E>0$F<><46><EFBFBD><EFBFBD> i7!zP<7A><1C>tN<74><4E><06><><EFBFBD>=Vm<6D>nm<6E><6D>EX<45><58><EFBFBD>uA`@<40><>M=<3D><<3C><>G<EFBFBD>a<10><>^<5E><>C<EFBFBD><t!<21><><EFBFBD>YA<59><41><EFBFBD><EFBFBD><02><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><02>t,zP"(**(P<>[t6<74>H?1<><31><EFBFBD><EFBFBD>w<EFBFBD><04><><10><> 8<13>x<EFBFBD>M<EFBFBD><0F><07>%"T<>MwpI<04>{<7B><><EFBFBD>}<0F> <03>}+[
<EFBFBD><15><14>zɌa<C98C>|<7C>#<23><><EFBFBD><EFBFBD>dj<64><6A><EFBFBD><EFBFBD>"&\:D<>.$ \<5C>xM<78>[<5B><>a <02>D<EFBFBD>\<5C><>w<EFBFBD><16>ZF<5A>OI<4F>V<EFBFBD>c<EFBFBD><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>a)<0E><>*<2A>ձP<D5B1>Py<50><79><EFBFBD>o}w<><77>Z<EFBFBD><0F>MHڃp^<5E><><7F><EFBFBD>><3E>Ń<EFBFBD>=<3D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><13><><EFBFBD>z
<EFBFBD><EFBFBD>;<3B>6<EFBFBD><19>~<7E><>s[_y<04>d<EFBFBD><64><EFBFBD>K<EFBFBD>?<3F><>W<1E>~<7E>X<EFBFBD>7<EFBFBD> x*<2A>f<EFBFBD>D<EFBFBD><11><><EFBFBD><EFBFBD>J<EFBFBD><4A><EFBFBD>
l%}<7D><>vxh<78><68>َ<1B>}<7D><>sWa<57><55>tj<74>> <09><78><D5AA>p<EFBFBD><70>Ĵ<EFBFBD><C4B4><EFBFBD>
h <<3C><>W<EFBFBD><57>_|<7C><>#?<3F><><EFBFBD><EFBFBD>F V<>wM5d<35><64><EFBFBD>!\2D<32>.vop<6F><70>zs4~<7E>OO<4F><4F><EFBFBD><EFBFBD><05><><EFBFBD>"L<>Ԇx<D486>%7<><37>.<2E>Lv*jBL"<22><><EFBFBD>1D<31>q<EFBFBD><71><EFBFBD>ܽ<EFBFBD><67><DF83>{\xÃ}_<>֋<EFBFBD><D68B><18>4h<34>K a<>!<21><>_}r<>_<<3C><><EFBFBD><EFBFBD>}<7D>+<2B>u<EFBFBD><75>C ֥<19><>7<EFBFBD>p<EFBFBD><70>9<EFBFBD>'<27><>"<22>
]<5D>
֯'Vn<18>ƫV<C6AB><56><EFBFBD><EFBFBD>< p<-<2D>-<2D><><EFBFBD>Z<EFBFBD>28<><38>Wlx<6C><78><EFBFBD>/=<3D><><EFBFBD><EFBFBD><EFBFBD>w`|f<><66><EFBFBD>r<EFBFBD> b<17><>_<EFBFBD>p<EFBFBD><10>j?<14><>[((F'<0E><>CzG@d<><64> qX<71><58> tr<74>2N<32><4E>l<18>&=XS<58>*<2A>-<2D>6&<26><>u<EFBFBD>?q<>^ݹs<DDB9>{<7B>M~ v<>lD<>m<><<3C><>ן<37>81<03><01><><EFBFBD><EFBFBD>Ɋ<1A><>S<EFBFBD><53><EFBFBD>t<EFBFBD><74><EFBFBD>G?<3F><><EFBFBD><EFBFBD><EFBFBD>8<EFBFBD>VvuҖr<D296>"<22><>^0q`<60><><EFBFBD><EFBFBD>ek<65><6B>q.O<>K.<2E><><EFBFBD><EFBFBD>\<5C><12><EFBFBD>E<EFBFBD><45>r<EFBFBD><72><EFBFBD> <09>Y[<5B>lYS˾i<CBBE><69><EFBFBD>0<EFBFBD><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>s<EFBFBD>vE<76><45><EFBFBD>ryo<79><6F><EFBFBD>Ƕ<02><>H<EFBFBD>) <20><>Q<EFBFBD>fl<66>4<EFBFBD>A!<21><><19>=<3D><><EFBFBD>|<7C><><03>O<EFBFBD><4F><EFBFBD><EFBFBD>5<EFBFBD>%<25>ka<6B>ٵ8<D9B5><38>{<7B><> h<><68><EFBFBD>c_<7F><5F><<3C>c8<63><1C><><EFBFBD><EFBFBD>"<22>B<EFBFBD>4GGGt<><1C><>&<26>8<EFBFBD>`c<>f<EFBFBD><66><EFBFBD><1A>i<EFBFBD><1B>1<EFBFBD><31><>u<EFBFBD><1A>qQ<><51><EFBFBD><1F><><78><CD96>\ <0B><><EFBFBD>ڟ?<3F>ҾbwQ#E<04><>F<EFBFBD>
<20><>r<EFBFBD>o\<5C><>Ϡ<EFBFBD><<3C><><EFBFBD><EFBFBD><EFBFBD><1F><><EFBFBD>TY|M<><4D>4<EFBFBD>&<26>Dq*<2A> `<60><><4D><11><02>qJ<71>&B@?<3F><>t̀4<CD80><34><EFBFBD><EFBFBD>W,<><7F><EFBFBD>=<3D>i<EFBFBD>'<27><><EFBFBD><EFBFBD> <1D> <20>7l<><16>?
<EFBFBD><EFBFBD>I|<7C><>/<2F><>Ɍ&<26>"<22>ZH<5A><48>ie<1B> Q<><1B>I_<49><5F><13><><EFBFBD> <03><>u<EFBFBD>74<37>u<EFBFBD>͙<EFBFBD>w <20>e<EFBFBD><65>գ˾<D5A3><CBBE></<2F>M̫8y+<2B><>6[+<2B><><15>VS|<7C><1A> <20>H xUB<55><42><EFBFBD>Ͻt<CFBD>ѭ'<27>O<EFBFBD><07><><EFBFBD><EFBFBD>A|<7C>W<>8D<38>r z~<7E><>
<EFBFBD>63<><33><>ҷ^<5E><><EFBFBD>J 2<02>-<2D><>D<EFBFBD><44><EFBFBD>bc<62><63>\<07><>0|<7C>H"<22>[6"<22>f<EFBFBD><66><EFBFBD><EFBFBD>n?<3F><><EFBFBD>N<w<>Jkz<6B>`<60><><EFBFBD>uI<11><> <0B><>z<>+
o1<6F><16><19> )gt2<74>$<24>B<EFBFBD>I<04><02>e<><65><>6<EFBFBD><36><EFBFBD>J-<2D><15>^op<6F>
<EFBFBD><EFBFBD><11><>ѐ<EFBFBD>A!X<58>74<1A>3<>iT&1,$$dW4<57><34><EFBFBD>ڌȬISLm)5(D"T<><04><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <0B>$<24><>T_z<5F><7A>z<EFBFBD>o<EFBFBD>-<2D><> <20><>w<EFBFBD><77><EFBFBD><EFBFBD>[/V+<2B><><EFBFBD><EFBFBD>A;cc<1C><><EFBFBD><15>%<25><EFBFBD>CCZ<43><5A>8Ws<57>i<EFBFBD>4<EFBFBD><34>C<1E>#<23><>d<EFBFBD>owM=<3D>}ꩣ<><EAA9A3>yyIe2<65><32>1<EFBFBD>%<25><>Fk1<6B><06> <0B><><07>z<EFBFBD><03>M<EFBFBD>@.<2E><>b<EFBFBD><62><EFBFBD>L<>=d<12><>T<<3C>F<EFBFBD>ʙZH<5A>OL+<2B><05>mܣ<><1F><>`<60><><EFBFBD><EFBFBD><EFBFBD>u<EFBFBD><06><><EFBFBD>_"<04>i<EFBFBD> <20><>C<1A><>Giܽ<69><DCBD>j6<6A><36>p{<7B>t<EFBFBD>-<2D>ɔ+B<>](<04><>:<3A>z<EFBFBD><7A><EFBFBD><EFBFBD><1F>1<EFBFBD><31><EFBFBD><EFBFBD>f<1E><><EFBFBD><<3C><><EFBFBD><EFBFBD>L<EFBFBD><4C><EFBFBD><EFBFBD>Xl<58>`-<18><?X<><58>Y<><59><EFBFBD>x<EFBFBD>z
g<EFBFBD>`f0 <03>P<EFBFBD>w<EFBFBD><77><EFBFBD>Ûz߸<7A>kC_ ¹"<22><><EFBFBD><EFBFBD>j<EFBFBD><6A><EFBFBD>+<2B><e<>e t<>Ell<6C>:<3A>{<$
.
қx<EFBFBD>۲<>x<EFBFBD>8nY<6E>q<EFBFBD><71><EFBFBD><EFBFBD>M<EFBFBD>T<>c굵<1F><><EFBFBD><EFBFBD>{<7B><><18><><EFBFBD><EFBFBD>04<30>m?<3F><><EFBFBD><EFBFBD>X<EFBFBD><58><EFBFBD>WN<>ԧ*<2A><>S3<53><33><EFBFBD><EFBFBD>D<02><03><03>Qi<<3C>F<EFBFBD>2<EFBFBD>,<2C>s<><73><EFBFBD><EFBFBD>+<2B><>ԭWil<69><6C><EFBFBD>Y<EFBFBD><19><01>e=ޭ<><DEAD>\<5C><>Ƶ]<5D><16><>"<22><><EFBFBD><EFBFBD>ҥ~`w<><77><EFBFBD>G<EFBFBD><47>l*;<3B>hmt<6D>V<EFBFBD>R<EFBFBD>r}<7D><><EFBFBD><EFBFBD>H<EFBFBD>ֱr<D6B1><72>"Ñ6<C391><36><EFBFBD>@<40>94<1A>d<EFBFBD>!4<>u<EFBFBD>n<EFBFBD><6E>ۍ<EFBFBD><1A><>6~<7E>]<5D><><EFBFBD>r<EFBFBD>\<5C><><EFBFBD>;Uy<55><79><EFBFBD>z]<5D>rx<72>]GÈw<1E><>sr<73>0C<04><10><><EFBFBD><EFBFBD>!x*bT<62>!<21>d1;D<><44><EFBFBD>e<02>*n<><1C>s<EFBFBD>@ à cA]?T<>ou<6F>-<2D>{n<><6E>8\Z<>sĊ`-M<>ݘ<EFBFBD>*/<2F>(?
.<2E>!<21>-<2D>:<3A><>t<01><>L<EFBFBD>~<7E>Ư<<1A>];<3B>IF<49><46>T<EFBFBD><54>jxl<78><6C><EFBFBD><EFBFBD><EFBFBD><EFBFBD>N<EFBFBD><4E><<3C>w<EFBFBD><77>f<r<>
<EFBFBD><EFBFBD>ɐR<EFBFBD><04>O<01><>P)<29><>':8<>L<EFBFBD>Ita
<EFBFBD>"<22><>OtI[1G&<26><>7筥<37>&<07><><EFBFBD><7F><EFBFBD><13>\$NU<4E>C<EFBFBD>Uü{l<><03><>Ȝ<EFBFBD><C89C>'NO<4E>"4V<34>1 <20><> <09><><EFBFBD>[<5B>hz<68><7A><EFBFBD> b`<06><><EFBFBD><EFBFBD><EFBFBD><15><07><76><DDBB><EFBFBD>B<EFBFBD><42>T $<24>%,.<2E>?Ty<54><79><EFBFBD><EFBFBD>8
F<EFBFBD>өdJDgmY<17><16>deˆ<65>b<EFBFBD><62>9<EFBFBD><39>Բ<EFBFBD><D4B2>v0<76>f<EFBFBD>;<3B>nkf<6B><S[<5B>_>2<><32>_m<5F><6D>iͮS<CDAE><53><EFBFBD>f<EFBFBD><> ́<><CD81>X9::<1D><>qJϤG<CFA4>}<7D><>? <20> <06><>X,<2C><><EFBFBD>
mx<EFBFBD><EFBFBD><EFBFBD><1B><>Λc<CE9B>ž<EFBFBD>LdfB<66>͉<>>><1D><>3щJtlF<1F><><EFBFBD>U<EFBFBD>TM<54>#.<2E>f&4H&<26>ĸ<EFBFBD>ACv~"^
<EFBFBD>u<EFBFBD><EFBFBD>w<>v<EFBFBD>1R<31>iEaM<61>O-x<>v<EFBFBD>E<EFBFBD><45>c*3<>m?<3F>l}ZO<5A>!<21>a+=<3D><><EFBFBD><EFBFBD><18>t<EFBFBD><06>b<EFBFBD>j<12>49^<5E>8<EFBFBD>˰<EFBFBD><CBB0><EFBFBD>4<EFBFBD>&<26><>s*<2A>k9<6B>\ ֯<><D6AF><EFBFBD><EFBFBD>6o<36><6F><EFBFBD><EFBFBD>R<EFBFBD>̩<EFBFBD><CCA9><EFBFBD>񩚞<EFBFBD><F1A99A9E><EFBFBD>>6<><36>τ<EFBFBD>+<2B>DE<44><45><EFBFBD>Su3Uӓu3]7u+Uk<>{j<>#U<> 7<><>t<EFBFBD><74><EFBFBD>U<EFBFBD>
\8{<7B>j<EFBFBD>9;<3B>t94Su<53><75><EFBFBD>S<1D>CK<>4<EFBFBD>3c<33>\<5C><><0F><>z!<<3C><>T I<>4<1B>&b<>`<60><06><><EFBFBD><EFBFBD>a<EFBFBD><61>j<EFBFBD><4B><D7AA><EFBFBD><EFBFBD><EFBFBD>n<EFBFBD>Mw<4D><77>l{<7B>.<2E>#<23><<3C><>.5"XB><3E>Ǝ<EFBFBD>v<EFBFBD>T<EFBFBD><54><EFBFBD>>u<><75>$0 <0C>6&<26><>L<>*p<06><><EFBFBD> hlL<6C>
<EFBFBD><18>N<EFBFBD>a<EFBFBD>D<EFBFBD><06>uS<75><53><><D3BB><EFBFBD>W<EFBFBD><1C>l<11>r'5<>}j<><6A>wkm<6B>+<2B>ɣ<1C> s<12>2<EFBFBD>&<26><1B>TP[Q<><51>.O<><4F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*<2A><><EFBFBD>%<25>"XB<58>1&<<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>N=}
d<EFBFBD>K<EFBFBD><EFBFBD>k<EFBFBD><EFBFBD>-<2D><><EFBFBD><EFBFBD><EFBFBD><14>:<3A><><EFBFBD>EKX<12><><EFBFBD><EFBFBD>}<7D>£<EFBFBD><C2A3><EFBFBD>cs!]<5D>R<13><>t<EFBFBD><74>ʁw<CA81>S<EFBFBD>7<EFBFBD>93<39> M<>` <09><><59><<1E>]<5D><>Jt<4A>)O<>a@<40><><EFBFBD><EFBFBD>:<3A>z<EFBFBD><7A><1E><>¦k<C2A6>}<7D>BkD<6B><44>%<25><><EFBFBD><EFBFBD><1F>S߿#:<3A>_<EFBFBD><5F>l<EFBFBD>
<EFBFBD>ud<EFBFBD><EFBFBD><EFBFBD>]<5D><> ;R<7F><52><EFBFBD><EFBFBD><EFBFBD>h<EFBFBD><68>L<EFBFBD>t<EFBFBD><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><03>|
"X<> <20>,Ar<><72>5,Qr<51>'<27><><EFBFBD>,<2C>8<EFBFBD>3.<2E><><EFBFBD><EFBFBD>_<EFBFBD><5F>!R"|<7C>C<04><><EFBFBD><EFBFBD><EFBFBD>?<3F><>.<2E><><EFBFBD>lE<6C><EJ4<4A><34><EFBFBD>`]<14><>.<2E>U<EFBFBD><55>Í<EFBFBD>]<5D><><EFBFBD><1D><><EFBFBD><EFBFBD><EFBFBD>:<07>]<5D>H<EFBFBD>`<60>#<23>).<2E>l<EFBFBD>P<EFBFBD><50>ٺ8<D9BA><38>FQ@<40><><EFBFBD> O<><4F><EFBFBD>\Gk
<EFBFBD><EFBFBD>s<EFBFBD><EFBFBD>O<><4F>B<EFBFBD>
<01><><EFBFBD><1C><> k<><6B>&}Dl<44><6C>M<EFBFBD><4D>=<3D>G;æ<>O<EFBFBD>ʬ<EFBFBD>k<EFBFBD>a)
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>f<EFBFBD><11> "e<>&i<>g-\<5C>ZM<><4D>Dd<44><64>2F<> rO<72>R
<EFBFBD>,<2C>D<EFBFBD><44><EFBFBD>L <09><><EFBFBD>%!XM2<4D>H<EFBFBD><48>:<3A>/[<5B>j<EFBFBD><6A><EFBFBD> <20>L<EFBFBD>3 @<40><> [ZU<5A>.x<><78>Y<EFBFBD><59>zbq<>\<5C>h<EFBFBD>c<EFBFBD>uA<1A>☹3<E298B9>\<5C><>fA<66><1A><><EFBFBD><EFBFBD>VU<12>r<EFBFBD>Et0<><14><>ZM<5A><0E>M_<4D><5F><EFBFBD> Vw<56><77><EFBFBD>dU)<29>D<EFBFBD>D<EFBFBD>Y<>
<EFBFBD>N%<25>]b<>%FwG~w<17>%!X<><58><19><0E>X<EFBFBD>6<EFBFBD><13>h<EFBFBD><68><EFBFBD>`<60>,<2C>
<EFBFBD>= ȊKf<1A><><EFBFBD><18>^ <20><><EFBFBD><EFBFBD><43><C496><10><>L<12> <20><>ٸ<EFBFBD><D9B8>6<EFBFBD><36><EFBFBD><04><>E<12><><EFBFBD><EFBFBD>J t<><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>&<26><><EFBFBD><EFBFBD><EFBFBD>Y֢<>4<EFBFBD><34>Z<EFBFBD><5A>zEDJ)E<><45>BR<42><01>3<EFBFBD>
<EFBFBD>L!<21><<3C><0E>-0y<30>),M<><4D>4<><34>u<>nžmr<19>p<EFBFBD>s<EFBFBD><73><EFBFBD>:9Nl<4E>"<22>a<EFBFBD><61>z<EFBFBD><7A>gl<15>J<EFBFBD><4A>+<2B><>G<EFBFBD>5]c<><0F><><EFBFBD>$[<5B><>KBTJ)"2<>"c<>R<1A>P<><50>^e<><65>{.)<29>ZB<5A><05>\<5C><>Ί<EFBFBD><06>J<EFBFBD><4A>V<EFBFBD><56>XT<58>1<EFBFBD>X<EFBFBD><58>U<EFBFBD><55>x<11><>cI<63><49><05>;'9H<39>& <20><><EFBFBD>7{υ^<5E>vgK<67><13><>.m<>tI
<EFBFBD><EFBFBD><EFBFBD>Y{"4 <20>B<EFBFBD>]<5D>g<EFBFBD>{<7B>z<EFBFBD>A <20><><EFBFBD>0"2"h<><1C><>c<EFBFBD><63>ye<79><65><18>J13<31><33>hIkC<6B>̔<EFBFBD><CC94>-<1D><><EFBFBD>&X<>Ėf6i<10>9<EFBFBD><39>F<EFBFBD>"X<><01><1F>̝<EFBFBD><CC9D>iUqh<<3C>[<5B>a<EFBFBD>pc <20><><EFBFBD>P<EFBFBD>Κ<EFBFBD>?c6<63><36><EFBFBD><EFBFBD><EFBFBD><EFBFBD>5x͉<78><CD89>]<5D><>C<EFBFBD>S<EFBFBD><53>
Rl<>o<EFBFBD><6F>e<>6<EFBFBD>i<>'" <20>8J<38>q<EFBFBD>zZg<5A><67><15><><14><02>x<EFBFBD>D<EFBFBD><44>,<2C><> <09> <0B><><EFBFBD>f<EFBFBD>jQ<6A>3۞J6<4A>{<7B><>6<EFBFBD><1A>Y<EFBFBD><59>]H<>YY<59>j:<3A>E<EFBFBD>R<EFBFBD><52><EFBFBD>$-<2D>A<EFBFBD><41>d<EFBFBD>Tf2{B<><42>7<EFBFBD><37><18>W<EFBFBD>汰ZJ<5A><4A><1D>o<EFBFBD>)<29>><3E>w<EFBFBD><77><06>#d"<22><1C>
2<EFBFBD><EFBFBD>9<EFBFBD><1B>L<EFBFBD>deb<65>$S"7Y<37>
g[OMO<4D>#X<>BA<42>N<EFBFBD>v<EFBFBD><76>e-%`<60> :7̲<37><1A><><EFBFBD>}<7D>>m<>E<><1B><>b<1E>ԧ<EFBFBD>N<EFBFBD><4E>[<5B>#<23>D <0B><><EFBFBD>[<5B><05>\-<2D>C<EFBFBD><43><EFBFBD><EFBFBD>Eι<45>Y<EFBFBD><59>e<EFBFBD><65><EFBFBD>/w<><77><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˳<EFBFBD><CBB3>tEK<01><>1<EFBFBD><31><EFBFBD>ZS<><53>_<EFBFBD>T<EFBFBD> <20><>܊<EFBFBD><DC8A>W<EFBFBD> <0B><><48>fd<>+<2B>hYB<59>s<><73>g<EFBFBD><67>摘Vv<13>>@<40><>mJ;<3B>f<EFBFBD>ø<EFBFBD>BR<42>ó<EFBFBD>s<EFBFBD>GH<47><48>gvrͥqM<71><4D>I<EFBFBD><49>L\<5C><>k<EFBFBD>F<EFBFBD><46><EFBFBD><EFBFBD><EFBFBD>܂<EFBFBD><DC82>c<>lm<10>D<EFBFBD>2<EFBFBD><32>v<EFBFBD><14>{<7B>p<1B>O<EFBFBD><12>B9LJZ
,-<2D><>,<2C>H<EFBFBD>%<25>$<24><><z<17><><EFBFBD><EFBFBD><EFBFBD>\<5C><>$Y <0B>E<EFBFBD>a<EFBFBD><61><EFBFBD><EFBFBD>L<0E>؜<EFBFBD><D89C>)4<>]ƿ<>o<EFBFBD>`<60>͕7<CD95><37><EFBFBD>K<EFBFBD><4B><EFBFBD> <0B><><EFBFBD><EFBFBD>N<EFBFBD>O)<29><><EFBFBD><06><><EFBFBD><EFBFBD>i<EFBFBD><69>v<EFBFBD><76><EFBFBD><EFBFBD><EFBFBD>=<3D>6h<36><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>+p<>e<EFBFBD>J<EFBFBD>f?<3F>e<EFBFBD>%<25>MMcZ<07><>T<EFBFBD><54><EFBFBD><05><><EFBFBD>jXnR1<52>[<5B>f?<3F><>Mk<4D>?6<>LV<4C><56><EFBFBD>$|<7C>8 `<60>ex5<78><35>9<EFBFBD><15><>
"X<> <20>,Ar<><72><EFBFBD><EFBFBD>Mֱ%<25><>I IEND<4E>B`<60>

View File

@ -0,0 +1,60 @@
<?php
namespace Friendica\Test\src\Network;
use Dice\Dice;
use Friendica\App\BaseURL;
use Friendica\Core\Config\IConfig;
use Friendica\DI;
use Friendica\Network\HTTPRequest;
use Friendica\Network\IHTTPRequest;
use Friendica\Test\MockedTest;
use Friendica\Util\Images;
use Friendica\Util\Profiler;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\Psr7\Response;
use Psr\Log\NullLogger;
require_once __DIR__ . '/../../../static/dbstructure.config.php';
class HTTPRequestTest extends MockedTest
{
public function testImageFetch()
{
$mock = new MockHandler([
new Response(200, [
'Server' => 'tsa_b',
'Content-Type' => 'image/png',
'Cache-Control' => 'max-age=604800, must-revalidate',
'Content-Length' => 24875,
], file_get_contents(__DIR__ . '/../../datasets/curl/image.content'))
]);
$config = \Mockery::mock(IConfig::class);
$config->shouldReceive('get')->with('system', 'curl_range_bytes', 0)->once()->andReturn(null);
$config->shouldReceive('get')->with('system', 'verifyssl')->once();
$config->shouldReceive('get')->with('system', 'proxy')->once();
$config->shouldReceive('get')->with('system', 'ipv4_resolve', false)->once()->andReturnFalse();
$config->shouldReceive('get')->with('system', 'blocklist', [])->once()->andReturn([]);
$baseUrl = \Mockery::mock(BaseURL::class);
$baseUrl->shouldReceive('get')->andReturn('http://friendica.local');
$profiler = \Mockery::mock(Profiler::class);
$profiler->shouldReceive('startRecording')->andReturnTrue();
$profiler->shouldReceive('stopRecording')->andReturnTrue();
$httpRequest = new HTTPRequest(new NullLogger(), $profiler, $config, $baseUrl);
self::assertInstanceOf(IHTTPRequest::class, $httpRequest);
$dice = \Mockery::mock(Dice::class);
$dice->shouldReceive('create')->with(IHTTPRequest::class)->andReturn($httpRequest)->once();
$dice->shouldReceive('create')->with(BaseURL::class)->andReturn($baseUrl);
$dice->shouldReceive('create')->with(IConfig::class)->andReturn($config)->once();
DI::init($dice);
print_r(Images::getInfoFromURL('https://pbs.twimg.com/profile_images/2365515285/9re7kx4xmc0eu9ppmado.png'));
}
}