рдпрд╣ рдкрдврд╝рдиреЗ рдХреЗ рдмрд╛рдж рдХрд┐ рд╕рд░реНрд╡рд░ рд╕рд╛рдорд╛рдиреНрдп рд╢рдмреНрджреЛрдВ рдореЗрдВ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ, рдореИрдВ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдмреИрда рдЧрдпрд╛ред рдкреНрд░реЛрдЯреЛрдХреЙрд▓, рд╡реИрд╕реЗ, рдмрд╣реБрдд рд╕рд░рд▓ рд╣реИред рдХреНрд▓рд╛рдЗрдВрдЯ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рдЪрд╛рдмрд┐рдпрд╛рдБ рднреЗрдЬрддрд╛ рд╣реИ, рдЬрд╡рд╛рдм рдореЗрдВ рд╕рд░реНрд╡рд░ рдХрдиреЗрдХреНрд╢рди рдХреА рдкреБрд╖реНрдЯрд┐ рдХрд░рддрд╛ рд╣реИ, рдЗрди рдЪрд╛рдмрд┐рдпреЛрдВ рдХреЗ рд╕рдВрдпреЛрдЬрди рд╕реЗ md5 рднреЗрдЬ рд░рд╣рд╛ рд╣реИред рдФрд░ рдлрд┐рд░ рд╡реЗ рдПрдХ-рджреВрд╕рд░реЗ рдХреЛ рдмрд╛рдЗрдирд░реА рдпрд╛ рдЯреЗрдХреНрд╕реНрдЯ рдбреЗрдЯрд╛ рднреЗрдЬрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХреЗ рджреНрд╡рд╛рд░рд╛ рдФрд░ рдмрдбрд╝реЗ рдЕрд▓рдЧ рдирд╣реАрдВ рд╣реЛрддреЗ рд╣реИрдВред
рд╣рд╛рде рдорд┐рд▓рд╛рдирд╛
рдбреНрд░рд╛рдлреНрдЯ рдЦреЛрд▓реЗрдВ рдФрд░ рд╣реИрдВрдбрд╢реЗрдХ рдлреЙрд░реНрдореЗрдЯ рдХрд╛ рд╡рд┐рд╡рд░рдг рджреЗрдЦреЗрдВ:
field = 1*name-char colon [ space ] *any-char cr lf
colon = %x003A ; U+003A COLON (:)
space = %x0020 ; U+0020 SPACE
cr = %x000D ; U+000D CARRIAGE RETURN (CR)
lf = %x000A ; U+000A LINE FEED (LF)
name-char = %x0000-0009 / %x000B-000C / %x000E-0039 / %x003B-10FFFF
; a Unicode character other than U+000A LINE FEED (LF), U+000D CARRIAGE RETURN (CR), or U+003A COLON (:)
any-char = %x0000-0009 / %x000B-000C / %x000E-10FFFF
; a Unicode character other than U+000A LINE FEED (LF) or U+000D CARRIAGE RETURN (CR)
рдареАрдХ рд╣реИ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдЗрд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВ:
field = ( many1 nameChar <& colon <& spaces ) <&> ( many anyChar <& cr <& lf ) where <br>
spaces = ignore ( many space ) [ () ] <br>
colon = lit ':' char<br>
space = lit ' ' char<br>
cr = lit '\r' char<br>
lf = lit '\n' char<br>
unicodeChar = optIf ( <= '\x10FFFF' ) char<br>
nameChar = optIf ( `notElem` ": \r\n" ) unicodeChar<br>
anyChar = optIf ( `notElem` "\r\n" ) unicodeChar<br>
рдореИрдВ рд╕рдордЭрд╛рдКрдВрдЧрд╛ рдХрд┐ рдкрд╣рд▓реА рдкрдВрдХреНрддрд┐ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдкрд░ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИред
field = ( many1 nameChar <& colon <& spaces ) <&> ( many anyChar <& cr <& lf ) where <br>
spaces = ignore ( many space ) [ () ] <br>
many1
рдПрдХ рдорд╛рди рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ рдЬреЛ 1 рдпрд╛ рдЕрдзрд┐рдХ рдмрд╛рд░ рд╣реЛрддрд╛ рд╣реИ,
many
- 0 рдпрд╛ рдЕрдзрд┐рдХред рдСрдкрд░реЗрдЯрд░
&>
рдФрд░
<&
рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рджреЛ рдирд┐рдпрдореЛрдВ рдХреЛ рдЬреЛрдбрд╝рддреЗ рд╣реИрдВ, рдЬрдмрдХрд┐ рдпрд╣ рджрд░реНрд╢рд╛рддрд╛ рд╣реИ рдХрд┐ рд╣рдо рдХреЗрд╡рд▓ рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рдХреЗ рдЕрд░реНрде рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдЬреЛ рдореВрд▓реНрдп
colon
рдФрд░
spaces
рдХреЗ рдирд┐рдпрдореЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░рддреЗ рд╣реИрдВ, рд╡реЗ рд╣рдореЗрдВ рд░реБрдЪрд┐ рдирд╣реАрдВ рджреЗрддреЗ рд╣реИрдВред рдСрдкрд░реЗрдЯрд░
<&>
рдЖрдкрдХреЛ рдЯреБрдкрд▓ рдХреЗ рд░реВрдк рдореЗрдВ рджреЛрдиреЛрдВ рдорд╛рди рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред
lit
рдлрд╝рдВрдХреНрд╢рди рд╕рд╛рдордирд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдард┐рди рдорд╛рди рд╕реЗрдЯ рдХрд░рддрд╛ рд╣реИ, рдФрд░
optIf
рдПрдХ рдмрд╛рдзрд╛
optIf
рд╣реИред
рд╕рдВрджреЗрд╢ рдореЗрдВ рд╣реЗрдбрд░ рд▓рд╛рдЗрди, рдлрд╝реАрд▓реНрдб рдФрд░ рдлрд╝реАрд▓реНрдб рдХреЗ рдмрд╛рдж рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд▓рдВрдмрд╛рдИ рдХрд╛ рдбреЗрдЯрд╛ рд╢рд╛рдорд┐рд▓ рд╣реЛрддрд╛ рд╣реИред
рдпрд╣ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд▓рд┐рдЦрд╛ рд╣реИ:
message = ( toMessage , fromMessage ) `wrap` ( leadingLine <&> many field ) where <br>
toMessage ( ll , fs ) = Message { <br>
messageLeadingLine = ll , <br>
messageFields = fs } <br>
fromMessage ( Message { messageLeadingLine = ll , messageFields = fs } ) = ( ll , fs ) <br>
<br>
body len = cr &> lf &> times len unicodeChar<br>
<br>
leadingLine = many anyChar <& cr <& lf<br>
leadingLine
рдФрд░
body
рд╕рдм рдХреБрдЫ рд╕рд░рд▓ рд╣реИ, рд▓реЗрдХрд┐рди
wrap
рдлрд╝рдВрдХреНрд╢рди
message
рдкрд░рд┐рднрд╛рд╖рд╛ рдореЗрдВ рджрд┐рдЦрд╛рдИ рджреЗрддрд╛ рд╣реИред рддрдереНрдп рдпрд╣ рд╣реИ рдХрд┐ рдирд┐рдпрдо
a <&> b
рдЯрдкрд▓ рдХреЗ рд▓рд┐рдП рдирд┐рдпрдо рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╣рдореЗрдВ рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЗрд╕рд▓рд┐рдП, рд╣рдо рдПрдХ рдЯреНрдпреВрдкрд▓ рд╕реЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рджреЛ рдХрд╛рд░реНрдп рдкреНрд░рджрд╛рди рдХрд░рддреЗ рд╣реИрдВред
рдареАрдХ рд╣реИ, рд╣рдордиреЗ рд╕реАрдЦрд╛ рдХрд┐ рдЦреЗрддреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╕рд╛рд░ рд╕рдВрджреЗрд╢ рдХреЛ рдкрд╛рд░реНрд╕ рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рдП, рдЕрдм рдЖрдк
Opening
(рдХреНрд▓рд╛рдЗрдВрдЯ рд╕реЗ) рдФрд░
Response
(рд╕рд░реНрд╡рд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛) рдХреА рджрд┐рд╢рд╛ рдореЗрдВ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред
рдЙрджреНрдШрд╛рдЯрди рдореЗрдВ рдХреБрдЫ рдлрд╝реАрд▓реНрдбреНрд╕ рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдП (рдХреБрдЫ рд╡реИрдХрд▓реНрдкрд┐рдХ рд╣реИрдВ), рдЗрд╕рд▓рд┐рдП рд╣рдо
optIf
рдореЗрдВ
message
рдирд┐рдпрдо рдХреЛ
optIf
; рдФрд░ рд▓рдВрдмрд╛рдИ рдореЗрдВ 8 рдмрд╛рдЗрдЯреНрд╕ рд╡рд╛рд▓рд╛ рд╢рд░реАрд░ рднреА рд╢рд╛рдорд┐рд▓ рд╣реИред
opening = ( toOpening , fromOpening ) `wrap` ( optIf hasFields message <&> body 8 ) where <br>
рдХрд╛рд░реНрдп
toOpening
, рдореИрдВ рдирд╣реАрдВ рджреВрдВрдЧрд╛ред
Response
рд╕рд╛рде
Response
рдпрд╣ рдмрд┐рд▓реНрдХреБрд▓ рд╡реИрд╕рд╛ рд╣реА рд╣реИред
рдлреНрд░реЗрдореНрд╕
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рд╛рдереЛрдВ рд╕реЗ рд╣рд┐рд▓рд╛ рдХреЗ рд╕рд╛рде, рдЕрдм рдпрд╣ рд╕рдВрджреЗрд╢ рд▓реЗрдиреЗ рдХреЗ рд▓рд╛рдпрдХ рд╣реИред
рдПрдХ рд╣реА рдбреНрд░рд╛рдлреНрдЯ рдЕрдиреБрднрд╛рдЧ рдореЗрдВ, рдЖрдк рдлреНрд░реЗрдо рдкреНрд░рд╛рд░реВрдк рдХрд╛ рд╡рд┐рд╡рд░рдг рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:
frames = *frame
frame = text-frame / binary-frame
text-frame = (%x00-7F) *(%x00-FE) %xFF
binary-frame = (%x80-FF) length < as many bytes as given by the length >
length = *(%x80-FF) (%x00-7F)
рд╣рдо рдПрдХрдорд╛рддреНрд░ рдЕрдкрд╡рд╛рдж рдХреЗ рд╕рд╛рде рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрддреЗ рд╣реИрдВ рдЬреЛ рд╣рдо
closing-frame
рдЫреЛрдбрд╝ рджреЗрддреЗ рд╣реИрдВ:
frames = ( takeWhile ( not . isClosing ) , takeWhile ( not . isClosing ) ) `wrap` many frame<br>
frame = optIf isText textFrame <|> optIf isBinary binaryFrame <|> optIf isClosing closingFrame<br>
<|>
рдСрдкрд░реЗрдЯрд░ рдПрдХ рд╡рд┐рдХрд▓реНрдк рд╣реИред рдкрд╣рд▓реЗ рдмрд╛рдПрдВ рдирд┐рдпрдо рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИ, рдЕрдЧрд░ рдпрд╣ рд╡рд┐рдлрд▓ рд╣реЛрддрд╛ рд╣реИ, рддреЛ рд╕рд╣реАред
рдЦреБрдж рдлреНрд░реЗрдо:
textFrame = ( TextFrame , \ ( TextFrame s ) -> s ) `wrap` ( textFlag &> many frameChar <& frameFF ) where <br>
textFlag = ignore ( optIf ( <= 0x7F ) word8 ) 0x00 <br>
binaryFrame = ( BinaryFrame , \ ( BinaryFrame s ) -> s ) `wrap` ( binaryFlag &> byteSourceLength frameLength ) where <br>
binaryFlag = ignore ( optIf ( liftM2 ( && ) ( > 0x7F ) ( /= 0xFF ) ) word8 ) 0xF0 <br>
closingFrame = check ( 0xFF , 0x00 ) ( word8 <&> word8 ) ClosingFrame <br>
ignore
рдлрд╝рдВрдХреНрд╢рди рд╕рдВрдмрдВрдзрд┐рдд рдорд╛рди рдХреЛ
ignore
рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд▓рд┐рдЦрддреЗ рд╕рдордп, рджреВрд╕рд░реЗ рддрд░реНрдХ рджреНрд╡рд╛рд░рд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдореВрд▓реНрдп рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддрд╛ рд╣реИред рдпрд╛рдиреА
textFrame
рдкрдврд╝рддреЗ рд╕рдордп
textFrame
рд╣рдо рдЯреЗрдХреНрд╕реНрдЯ рдХреЛ рд╕рднреА рдлреНрд░реЗрдо рдорд╛рдирддреЗ рд╣реИрдВ
textFrame
рдЬрд┐рд╕рдХрд╛ рдЭрдВрдбрд╛ 0x7F рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐, рд╕рдВрджреЗрд╢ рдХреЛ
textFrame
рдХрд░рддреЗ рд╕рдордп, рд╣рдо рд╣рдореЗрд╢рд╛ 0 рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред
byteSourceLength
рдмрд╛рдЗрдЯреНрд╕ рдХреЗ рдПрдХ рдмрд╛рджрд▓ рдХреЛ рд▓реЛрдб / рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ, рдЗрд╕реЗ рдЗрди рдмрд╛рдЗрдЯреНрд╕ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд╕рд╛рде
byteSourceLength
рдХрд░рддрд╛ рд╣реИ, рдЬреЛ рдХрд┐ рдкрд╛рд░рд┐рдд рдирд┐рдпрдо (
frameLength
) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓реЛрдб / рд╕рд╣реЗрдЬрд╛ рдЬрд╛рдПрдЧрд╛ред
WebSocket рдореЗрдВ рд▓рдВрдмрд╛рдИ рдмрд╛рдЗрдЯреНрд╕ рдореЗрдВ рдПрдХ рдЪрд░ рдЖрдХрд╛рд░ рд╣реИред рдЕрдВрддрд┐рдо рдмрд╛рдЗрдЯ рдХрд╛ рд╕рдВрдХреЗрдд рдкрд░реЗрд╢рд╛рди рдЙрдЪреНрдЪ рдмрд┐рдЯ рд╣реИред
frameLength = ( \ ( hs , l ) -> toLength ( hs ++ [ l ] ) , ( init &&& last ) . fromLength ) `wrap` ( many highWord <&> lowWord ) where <br>
toLength
,
fromLength
,
highWord
рдФрд░
lowWord
рдЫреЛрдбрд╝ рджреВрдВрдЧрд╛ред
рд╕рд░реНрд╡рд░
рдЕрдм рдЖрдк рд╕рд░реНрд╡рд░ рдЬреИрд╕рд╛ рдХреБрдЫ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
start port onAccept = do <br>
sock <- S . socket S . AF_INET S . Stream S . defaultProtocol<br>
S . bindSocket sock $ S . SockAddrInet port S . iNADDR_ANY<br>
S . listen sock S . maxListenQueue<br>
let <br>
-- . ( ), <br>
-- "" . <br>
canDie e = if fromException e == Just ThreadKilled then throwIO ThreadKilled else return () <br>
-- . <br>
th <- fork $ forever $ canDie `handle` acceptClient sock onAccept<br>
return $ Server th<br>
рдХрдиреЗрдХреНрд╢рди рдкреНрд░рддреАрдХреНрд╖рд╛рд░рдд рд╕рдорд╛рд░реЛрд╣:
acceptClient socket onAccept = ignore $ accept socket onReceived where <br>
accept
рдХрдиреЗрдХреНрд╢рди рдХреЛ
accept
рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЖрд▓рд╕реА рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рд░реВрдк рдореЗрдВ
onReceived
рдлрд╝рдВрдХреНрд╢рди рдХреЛ рд╕рдВрдкреВрд░реНрдг рдЗрдирдкреБрдЯ рд╕реНрдЯреНрд░реАрдо рдкрд╛рд╕ рдХрд░рддрд╛ рд╣реИред
onReceived sock income = do <br>
-- . , anything ( ), <br>
-- , opening. <br>
( o , tailData ) <- letFail $ decode ( opening <&> anything ) income<br>
-- . <br>
r <- letFail ( responseTo o >>= mapException show . encode response ) <br>
-- . <br>
send sock r<br>
let con = connection ( openingChannel o ) ( openingHost o ) ( openingOrigin o ) ( openingProtocol o ) sock<br>
let <br>
-- . callback. <br>
onConnect ClosingFrame = close con `finally` acceptOnClose handlers con<br>
-- . <br>
onConnect f = acceptOnMessage handlers con f<br>
-- callback "". <br>
fork $ acceptOnOpen handlers con<br>
<br>
-- - , . <br>
switch ( const $ return () ) ( mapM_ onConnect ) $ decode frames tailData<br>
рдЖрд▓рд╕реА рд╕реВрдЪрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рд╕рдордЭ рдХреЗ рд▓рд┐рдП рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ: рд╕рдВрджреЗрд╢реЛрдВ рдХреА рдПрдХ рд╕реВрдЪреА рд╣реИ, рд╣рдо рдкреНрд░рддреНрдпреЗрдХ рдХреЗ рд▓рд┐рдП рд╕рдВрдмрдВрдзрд┐рдд
callback
рдХрд╣рддреЗ рд╣реИрдВ; рд▓реЗрдХрд┐рди рд╡рд╣рд╛рдБ рдПрдХ рдЪреЗрддрд╛рд╡рдиреА рд╣реИред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рд╣рдо рдЖрд▓рд╕реА
ByteString
рд░реВрдк рдореЗрдВ рд╕рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдирдкреБрдЯ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред
рдЕрдЧрд░ рд╣рдо рдЗрд╕реЗ рдЗрд╕ рддрд░рд╣ рд▓рд┐рдЦрддреЗ рд╣реИрдВ:
input <- fix $ \ loop -> unsafeInterleaveIO $ liftM2 ( : ) getLine loop<br>
let byteString = pack $ map charToByte input<br>
рдлрд┐рд░ рдПрдХ рдЖрд▓рд╕реА
ByteString
рдХреЛ рдкреНрд░рд┐рдВрдЯ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ
ByteString
, рд╣рдо рдкреНрд░рднрд╛рд╡ рдХреА рдХрдореА рдкрд░ рдмрд╣реБрдд рдЖрд╢реНрдЪрд░реНрдпрдЪрдХрд┐рдд рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рдорд╛рдорд▓рд╛
pack
рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдХрдареЛрд░рддрд╛ рдореЗрдВ рдкреНрд░рд╛рдердорд┐рдХ рд╣реИ, рдЗрд╕реЗ рдПрдХ рд╣реА рдмрд╛рд░ рдореЗрдВ рдкреВрд░реА рд▓рд╛рдЗрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред
рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рд╕рднреА рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрдирдкреБрдЯ рдХреА рдПрдХ рдЖрд▓рд╕реА рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЕрдзрд┐рдХ рд╕рд╣реА рд╣реЛрдЧрд╛, рдФрд░ рдлрд┐рд░
fromChunks
рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВред рдлрд┐рд░ рдЬреИрд╕реЗ рд╣реА рдЖрдк рдЯрд╛рдЗрдк рдХрд░рддреЗ рд╣реИрдВ, рд╣рдорд╛рд░рд╛
ByteString
рдЕрдм рдПрдХ рдЦрд╛рд▓реА рд╡рд╛рджрд╛ рдирд╣реАрдВ
ByteString
, рд▓реЗрдХрд┐рди рдИрдорд╛рдирджрд╛рд░реА рд╕реЗ рдкреВрд░реЗ рдЗрдирдкреБрдЯ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣реЛрдЧрд╛ред
рдирд┐рд╖реНрдХрд░реНрд╖
рдореИрдВрдиреЗ рдпрд╣ рд╕рдм рдХреНрдпреЛрдВ рд▓рд┐рдЦрд╛? рдЦреИрд░, рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рдХреЗ рдкрд╛рд╕ рд╣рд╛рд╕реНрдХреЗрд▓ рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рд░реБрдЪрд┐ рд╣реИ, рдпрд╛ рдХрд╛рд░реНрдпрд╛рддреНрдордХ рдХреНрд╖рдп рдХреА рдирд┐рд░рд░реНрдердХрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХрдо, рд╕рдВрджреЗрд╣ рд╣реИред