рд╣рдо Symfony2 рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдЕрдкрдирд╛ рдврд╛рдВрдЪрд╛ рдмрдирд╛рддреЗ рд╣реИрдВред (рднрд╛рдЧ 4)



рдЗрд╕рд╕реЗ рдкрд╣рд▓реЗ рдХрд┐ рд╣рдо рдЖрдЬ рдХреЗ рд╡рд┐рд╖рдп рдкрд░ рдЖрдЧреЗ рдмрдврд╝реЗрдВ, рд╣рдо рдЕрдкрдиреЗ рдврд╛рдВрдЪреЗ рдХреЛ рдереЛрдбрд╝рд╛ рдмрджрд▓ рджреЗрдВрдЧреЗ рддрд╛рдХрд┐ рдЯреЗрдореНрдкреНрд▓рдЯрд┐рдВрдЧ рдХреЛ рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдмрдирд╛рдпрд╛ рдЬрд╛ рд╕рдХреЗ:

<?php // example.com/web/front.php require_once __DIR__.'/../src/autoload.php'; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; $request = Request::createFromGlobals(); $map = array( '/hello' => 'hello', '/bye' => 'bye', ); $path = $request->getPathInfo(); if (isset($map[$path])) { ob_start(); extract($request->query->all(), EXTR_SKIP); include sprintf(__DIR__.'/../src/pages/%s.php', $map[$path]); $response = new Response(ob_get_clean()); } else { $response = new Response('Not Found', 404); } $response->send(); 


рдЪреВрдВрдХрд┐ рд╣рдо рдХреНрд╡реЗрд░реА рд╕рд░рдгреА рд╕реЗ рдЪрд░ рдХреЛ рд╡рд░реНрддрдорд╛рди рдкреНрд░рддреАрдХ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдЖрдпрд╛рдд рдХрд░рддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдо рд╣реЗрд▓реЛ . php рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд╕рд░рд▓ рдХрд░рддреЗ рд╣реИрдВ:

 <!-- example.com/src/pages/hello.php --> Hello <?php echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?> 


рдЕрдм рдирдИ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╣ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реЛрдЧрд╛ред
рдХрд┐рд╕реА рднреА рд╕рд╛рдЗрдЯ рдХрд╛ рдПрдХ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдкрд╣рд▓реВ рдЙрд╕рдХреЗ рд▓рд┐рдВрдХ рдХрд╛ рд░реВрдк рд╣реИред рд▓рд┐рдВрдХ рдорд╛рдирдЪрд┐рддреНрд░ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рд╣рдордиреЗ рдЙрдиреНрд╣реЗрдВ рдЙрд╕ рдХреЛрдб рд╕реЗ рдЕрд▓рдЧ рдХрд░ рджрд┐рдпрд╛ рдЬрд┐рд╕рдиреЗ рд╕рд╛рд╣рдЪрд░реНрдп рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдЙрддреНрдкрдиреНрди рдХреА, рд▓реЗрдХрд┐рди рдпрд╣ рдЕрднреА рднреА рдкрд░реНрдпрд╛рдкреНрдд рд▓рдЪреАрд▓рд╛ рдирд╣реАрдВ рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рд╣рдо рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рдмрдЬрд╛рдп рдЧрддрд┐рд╢реАрд▓ рд░реВрдк рд╕реЗ рдЙрддреНрдкрдиреНрди рдкрде рд╕реЗ рдбреЗрдЯрд╛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ:

 # Before /hello?name=Fabien # After /hello/Fabien 


рдЗрд╕ рд╕реБрд╡рд┐рдзрд╛ рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо Symfony2 рдШрдЯрдХ - рд░реВрдЯрд┐рдВрдЧ (Symfony2 "рд░реВрдЯрд┐рдВрдЧ" рдШрдЯрдХ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рд╣рдореЗрд╢рд╛ рдХреА рддрд░рд╣, рдХрдВрдкреЛрдЬрд╝рд░ рдХреЛ рдХрдВрдкреЛрдЬрд╝рд░ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред рдЗрд╕реЗ рдЗрдВрд╕реНрдЯреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП php composer.phar update рдХрдорд╛рдВрдб рдХреЛ рд░рди рдХрд░реЗрдВ:

 { "require": { "symfony/class-loader": "2.1.*", "symfony/http-foundation": "2.1.*", "symfony/routing": "2.1.*" } } 


рдЕрдм рд╕реЗ, рд╣рдо рдЕрдкрдиреЗ рдСрдЯреЛрд▓реЛрдб.рдлрдкреА рдХреЗ рдмрдЬрд╛рдп рд╕рдВрдЧреАрддрдХрд╛рд░ рджреНрд╡рд╛рд░рд╛ рдЙрддреНрдкрдиреНрди рдСрдЯреЛрд▓реИрдбрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рдСрдЯреЛрд▓реИрдб.рдлрдкреА рдлрд╛рдЗрд▓ рдХреЛ рдбрд┐рд▓реАрдЯ рдХрд░реЗрдВ рдФрд░ рд▓рд┐рдВрдХ рдХреЛ рд╕рд╛рдордиреЗ рдХреА рдУрд░ рдмрджрд▓ рджреЗрдВред

 <?php // example.com/web/front.php require_once __DIR__.'/../vendor/.composer/autoload.php'; // ... 


рд░рд╛рдЙрдЯрд┐рдВрдЧ рдШрдЯрдХ "рд░реВрдЯрдХреЙрд▓рд┐рдиреЗрд╢рди" рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ, рдореИрдЪреЛрдВ рдХреА рдПрдХ рд╕рд░рдгреА (рд▓рд┐рдВрдХ рдореИрдкреНрд╕) рдХреЗ рдмрдЬрд╛рдпред

 use Symfony\Component\Routing\RouteCollection; $routes = new RouteCollection(); 


рдЖрдЗрдП рдПрдХ рд▓рд┐рдВрдХ рдХреЗ рд▓рд┐рдП рдПрдХ рдорд╛рд░реНрдЧ рдЬреЛрдбрд╝реЗрдВ рдЬреИрд╕реЗ / hello / SOMETHING рдФрд░ рдПрдХ рдЕрдиреНрдп рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рд░рд▓ / рдЕрд▓рд╡рд┐рджрд╛ :

 use Symfony\Component\Routing\Route; $routes->add('hello', new Route('/hello/{name}', array('name' => 'World'))); $routes->add('bye', new Route('/bye')); 


рд╕рдВрдЧреНрд░рд╣ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рддрддреНрд╡ рдХреЛ рдПрдХ рдирд╛рдо (рд╣реИрд▓реЛ) рдФрд░ рдорд╛рд░реНрдЧ рд╡рд░реНрдЧ рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреНрд╡рд╛рд░рд╛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬреЛ рдмрджрд▓реЗ рдореЗрдВ рдорд╛рд░реНрдЧ рдкреИрдЯрд░реНрди (/hello/{name}) рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреА рдПрдХ рд╕рд░рдгреА (array('name' => 'World')) рджреНрд╡рд╛рд░рд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдЗрд╕ рдШрдЯрдХ рдХреЗ рд▓рд┐рдП рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝реАрдХрд░рдг рдореЗрдВ, рдЖрдкрдХреЛ рдЗрд╕рдХреЗ рдЕрдиреНрдп рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдорд┐рд▓реЗрдЧреА, рдЬреИрд╕реЗ рдХрд┐ URL рдЙрддреНрдкрдиреНрди рдХрд░рдирд╛, рд╡рд┐рд╢реЗрд╖рддрд╛ рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдБ, HTTP рд╡рд┐рдзрд┐рдпреЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рдирд╛, YAML рдпрд╛ XML рдлрд╝рд╛рдЗрд▓реЗрдВ рд▓реЛрдб рдХрд░рдирд╛, рдмреЗрд╣рддрд░ рдкреНрд░рджрд░реНрд╢рди рдХреЗ рд▓рд┐рдП PHP рдпрд╛ Apache рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдирд╛, рдФрд░ рдмрд╣реБрдд рдХреБрдЫред
рд░реВрдЯрдХреЙрд▓рд┐рдиреЗрд╢рди рдХреНрд▓рд╛рд╕ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рдЖрдзрд╛рд░ рдкрд░, UrlMatcher рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдкрдереЛрдВ рдХреЛ рдмрд╛рдВрдз рджреЗрдЧрд╛:

 use Symfony\Component\Routing\RequestContext; use Symfony\Component\Routing\Matcher\UrlMatcher; $context = new RequestContext(); $context->fromRequest($request); $matcher = new UrlMatcher($routes, $context); $attributes = $matcher->match($request->getPathInfo()); 


рдореИрдЪ () рд╡рд┐рдзрд┐ рдЕрдиреБрд░реЛрдзрд┐рдд рдкрде рдХреЛ рдПрдХ рд╕рд░рдгреА рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд░рддрд╛ рд╣реИ (рдзреНрдпрд╛рди рджреЗрдВ рдХрд┐ рдорд┐рд▓рд╛рди рдкрде рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ _route рд╡рд┐рд╢реЗрд╖ рдХреБрдВрдЬреА рдХреЗ рддрд╣рдд рд╕рд╣реЗрдЬреЗ рдЬрд╛рддреЗ рд╣реИрдВ):

 print_r($matcher->match('/bye')); array ( '_route' => 'bye', ); print_r($matcher->match('/hello/Fabien')); array ( 'name' => 'Fabien', '_route' => 'hello', ); print_r($matcher->match('/hello')); array ( 'name' => 'World', '_route' => 'hello', ); 


рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЕрдЧрд░ рдЕрдиреБрд░реЛрдз рдкреИрд░рд╛рдореАрдЯрд░ рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИрдВ, рддреЛ рдЙрдирдХрд╛ рдЙрдкрдпреЛрдЧ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдкрд░рд┐рдпреЛрдЬрдирд╛рдУрдВ рдкрд░ рддрд░реАрдХреЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реА рддрд░рд╣ред
рдпрджрд┐ рдЖрдкрдХреЛ рдХрд┐рд╕реА рднреА рдкрде рдХреЗ рд╕рд╛рде рдореЗрд▓ рдирд╣реАрдВ рдорд┐рд▓ рд░рд╣рд╛ рд╣реИ, рддреЛ рдПрдХ рдЕрдкрд╡рд╛рдж рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:

 $matcher->match('/not-found'); // throws a Symfony\Component\Routing\Exception\ResourceNotFoundException 


рдЕрдм, рдЕрд░реНрдЬрд┐рдд рдЬреНрдЮрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдпрд╣ рд╣рдорд╛рд░реЗ рдврд╛рдВрдЪреЗ рдХреЗ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рд▓рд┐рдЦрдиреЗ рдХрд╛ рд╕рдордп рд╣реИ:

 <?php // example.com/web/front.php require_once __DIR__.'/../vendor/.composer/autoload.php'; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing; $request = Request::createFromGlobals(); $routes = include __DIR__.'/../src/app.php'; $context = new Routing\RequestContext(); $context->fromRequest($request); $matcher = new Routing\Matcher\UrlMatcher($routes, $context); try { extract($matcher->match($request->getPathInfo()), EXTR_SKIP); ob_start(); include sprintf(__DIR__.'/../src/pages/%s.php', $_route); $response = new Response(ob_get_clean()); } catch (Routing\Exception\ResourceNotFoundException $e) { $response = new Response('Not Found', 404); } catch (Exception $e) { $response = new Response('An error occurred', 500); } $response->send(); 


рдирдпрд╛ рдХреЛрдб рдкрд░рд┐рд╡рд░реНрддрди:
тАв рдкрде рдирд╛рдореЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдЯреЗрдореНрдкрд▓реЗрдЯ рдирд╛рдореЛрдВ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
тАв рддреНрд░реБрдЯрд┐ 500 тАЛтАЛрдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ
тАв рдХреНрд╡реЗрд░реА рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рд╕рд░рд▓ рд░рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЕрд▓рдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ
 <!-- example.com/src/pages/hello.php --> Hello <?php echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?> 

тАв рд░реВрдЯ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рдХреЛ рдПрдХ рдЕрд▓рдЧ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд▓реЗ рдЬрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ:

 <?php // example.com/src/app.php use Symfony\Component\Routing; $routes = new Routing\RouteCollection(); $routes->add('hello', new Routing\Route('/hello/{name}', array('name' => 'World'))); $routes->add('bye', new Routing\Route('/bye')); return $routes; 


рд╣рдордиреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди (рд╕рдм рдХреБрдЫ, рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдХреА рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ - app.php рдореЗрдВ ) рдФрд░ рдлреНрд░реЗрдорд╡рд░реНрдХ (рдмрд╛рдХреА рдХреЛрдб рдЬрд┐рд╕ рдкрд░ рд╣рдорд╛рд░рд╛ рдЖрд╡реЗрджрди рдЖрдзрд╛рд░рд┐рдд рд╣реИ - front.php рдореЗрдВ ) рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрд▓рдЧ рдХрд░ рджрд┐рдпрд╛ред
рдХреЛрдб рдХреА рд▓рдЧрднрдЧ 30 рдкрдВрдХреНрддрд┐рдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реБрдП, рд╣рдореЗрдВ рдПрдХ рдирдпрд╛ рдврд╛рдВрдЪрд╛ рдорд┐рд▓рд╛ - рдкрд┐рдЫрд▓реЗ рдПрдХ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЕрдзрд┐рдХ рдЙрддреНрдкрд╛рджрдХ, рдЕрдзрд┐рдХ рд▓рдЪреАрд▓рд╛ред рдЗрд╕рдХрд╛ рдЖрдирдВрдж рд▓реЗрдВ!
рд░реВрдЯрд┐рдВрдЧ рдШрдЯрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдФрд░ рдмрдбрд╝рд╛ рдлрд╛рдпрджрд╛ рд╣реИ: рд░реВрдЯ рдкрд░рд┐рднрд╛рд╖рд╛рдУрдВ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ URL рдЙрддреНрдкрдиреНрди рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ред рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдЕрдкрдиреЗ рдХреЛрдб рдореЗрдВ URL рдорд┐рд▓рд╛рди рдФрд░ URL рдкреАрдврд╝реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп, URL рдХрд╛ рд░реВрдк рдмрджрд▓рддреЗ рд╕рдордп рдХреЛрдИ рдкрд░рд┐рдгрд╛рдо рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рдПрдХ рдЬрдирд░реЗрдЯрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░рдирд╛ рд╕реАрдЦрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ? рдмрд┐рд▓рдХреБрд▓ рд╕рд░рд▓:

 use Symfony\Component\Routing; $generator = new Routing\Generator\UrlGenerator($routes, $context); echo $generator->generate('hello', array('name' => 'Fabien')); // outputs /hello/Fabien 


рдХреЛрдб рдмрд┐рд▓реНрдХреБрд▓ рд╕реНрдкрд╖реНрдЯ рд╣реИ, рд╣рдо рддреАрд╕рд░реЗ рдкреИрд░рд╛рдореАрдЯрд░ рдХреЛ рд╕рд╣реА рдЬреЛрдбрд╝рдХрд░ рдирд┐рд░рдкреЗрдХреНрд╖ рдкрде рдЙрддреНрдкрдиреНрди рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

 echo $generator->generate('hello', array('name' => 'Fabien'), true); // outputs something like http://example.com/somewhere/hello/Fabien 


рдкреНрд░рджрд░реНрд╢рди рдХреЛ рд▓реЗрдХрд░ рдЪрд┐рдВрддрд┐рдд рд╣реИрдВ? рдЕрдкрдиреА рд░реВрдЯ рдкрд░рд┐рднрд╛рд╖рд╛рдУрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП, рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдпреВрдЖрд░рдПрд▓ рдпреВрдЖрд░рдПрд▓ рдХреЛ рдмрджрд▓рдиреЗ рд╡рд╛рд▓рд╛ рдПрдХ рдЕрдиреБрдХреВрд▓рд┐рдд URL рдореИрдЪ рдХреНрд▓рд╛рд╕ рдмрдирд╛рдПрдВ :

 $dumper = new Routing\Matcher\Dumper\PhpMatcherDumper($routes); echo $dumper->dump(); 


рдФрд░ рднреА рдЕрдзрд┐рдХ рдкреНрд░рджрд░реНрд╢рди рдЪрд╛рд╣рддреЗ рд╣реИрдВ? Apache рдХреЗ рд▓рд┐рдП mod_rewrite рдирд┐рдпрдореЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдЕрдкрдиреЗ рдорд╛рд░реНрдЧреЛрдВ рдХреЛ рдирд┐рд░реНрдпрд╛рдд рдХрд░реЗрдВ:

 $dumper = new Routing\Matcher\Dumper\ApacheMatcherDumper($routes); echo $dumper->dump(); 


рдлреЛрдЬреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдФрд░ рдореИрдВ рдЗрд╕ рдЪрдХреНрд░ рдХрд╛ рдПрдХ рд╕рд╛рде рдЕрдиреБрд╡рд╛рдж рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд╣рдордд рд╣реБрдПред

Source: https://habr.com/ru/post/In136656/


All Articles