рдЗрд╡реЗрдВрдЯ рдорд╢реАрди рдЬреАрд╡рди рдЪрдХреНрд░ рдХреА рд░рдХреНрд╖рд╛ рдХрд░рддреА рд╣реИ

рдЕрд╕реНрд╡реАрдХрд░рдг: рдпрд╣ рд▓реЗрдЦ рдЧреИрд░-рд╕реНрдкрд╖реНрдЯ рд╕рдорд╕реНрдпрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рдЧреИрд░-рд╕реНрдкрд╖реНрдЯ рд╕рдорд╛рдзрд╛рди рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИред рджреМрдбрд╝рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдЕрдВрдбреЗ рдЗрд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ рд▓рд╛рдПрдВ, рдореИрдВ рд▓реЗрдЦ рдХреЛ рдЕрдВрдд рддрдХ рдкрдврд╝рдиреЗ рдФрд░ рджреЛ рдмрд╛рд░ рд╕реЛрдЪрдиреЗ рдХреА рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред

but_why


рд╕рднреА рдХреЛ рдирдорд╕реНрдХрд╛рд░! рдХреЛрдб рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╕рдордп, рд╣рдореЗрдВ рдЕрдХреНрд╕рд░ рд░рд╛рдЬреНрдп рд╕реЗ рдирд┐рдкрдЯрдирд╛ рдкрдбрд╝рддрд╛ рд╣реИ ред рдРрд╕рд╛ рд╣реА рдПрдХ рдорд╛рдорд▓рд╛ рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдЬреАрд╡рди рдЪрдХреНрд░ рд╣реИред рдХрдИ рд╕рдВрднрд╛рд╡рд┐рдд рд░рд╛рдЬреНрдпреЛрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╡рд╕реНрддреБ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдПрдХ рдмрд╣реБрдд рд╣реА рдЧреИрд░-рддреБрдЪреНрдЫ рдХрд╛рд░реНрдп рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдпрд╣рд╛рдВ рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдирд┐рд╖реНрдкрд╛рджрди рдЬреЛрдбрд╝реЗрдВ рдФрд░ рдХрд╛рд░реНрдп рдкрд░рд┐рдорд╛рдг рдХреЗ рдХреНрд░рдо рд╕реЗ рдЬрдЯрд┐рд▓ рд╣реИред рдПрдХ рдкреНрд░рднрд╛рд╡реА рдФрд░ рдкреНрд░рд╛рдХреГрддрд┐рдХ рд╕рдорд╛рдзрд╛рди рд╣реИред рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдИрд╡реЗрдВрдЯ рдорд╢реАрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реВрдВрдЧрд╛ рдФрд░ рдЗрд╕реЗ рдЧреЛ рдореЗрдВ рдХреИрд╕реЗ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПред


рд░рд╛рдЬреНрдп рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХреНрдпреЛрдВ?


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


рд░рд╛рдЬреНрдп рдХреЗ рд╕рд╛рде рдореБрдЦреНрдп рд╕рдорд╕реНрдпрд╛ рдЬрдЯрд┐рд▓рддрд╛ рд╣реИред рдХреЛрдИ рднреА рд░рд╛рдЬреНрдп рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдХреЛрдб рдХреЛ рдЬрдЯрд┐рд▓ рдХрд░рддрд╛ рд╣реИред рдЖрдкрдХреЛ рд╕реНрдореГрддрд┐ рдореЗрдВ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдкрд░рд┐рдгрд╛рдореЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ рдФрд░ рддрд░реНрдХ рдХреЗ рд▓рд┐рдП рд╡рд┐рднрд┐рдиреНрди рдЬрд╛рдВрдЪреЛрдВ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ред рдпрд╣реА рдХрд╛рд░рдг рд╣реИ рдХрд┐ рд╕реНрдЯреЗрдЯрд▓реЗрд╕ рдЖрд░реНрдХрд┐рдЯреЗрдХреНрдЪрд░ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░реНрд╕ рдХреЗ рд▓рд┐рдП рдмрд╣реБрдд рдЖрдХрд░реНрд╖рдХ рд╣реИрдВ - рдХреЛрдИ рднреА рдирд╣реАрдВ рдЪрд╛рд╣рддрд╛ рд╣реИ рдореБрд╕реАрдмрдд рдЬрдЯрд┐рд▓рддрд╛рдУрдВред рдпрджрд┐ рдЖрдкрдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдкрд░рд┐рдгрд╛рдо рдирд┐рд╖реНрдкрд╛рджрди рддрд░реНрдХ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рд░рд╛рдЬреНрдп рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред


рд╣рд╛рд▓рд╛рдВрдХрд┐, рдПрдХ рдРрд╕реА рд╕рдВрдкрддреНрддрд┐ рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рдХрдард┐рдирд╛рдЗрдпреЛрдВ рд╕реЗ рд░реВрдмрд░реВ рдХрд░рд╛рддреА рд╣реИред рдПрдХ рд░рд╛рдЬреНрдп рдХреЛ рдЖрдкрдХреЛ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХреНрд░рдо рдХрд╛ рдкрд╛рд▓рди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдРрд╕реА рд╕реНрдерд┐рддрд┐рдпреЛрдВ рд╕реЗ рдмрдЪрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рд▓реЗрдХрд┐рди рдпрд╣ рд╣рдореЗрд╢рд╛ рд╕рдВрднрд╡ рдирд╣реАрдВ рд╣реИред рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХрд╛рд░реНрдпрдХреНрд░рдо рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдЬреАрд╡рди рдЪрдХреНрд░ рд╣реИред рдЕрдЪреНрдЫреЗ рд░рд╛рдЬреНрдп рдкреНрд░рдмрдВрдзрди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдПрдХ рдЬрдЯрд┐рд▓ рдЬреАрд╡рди рдЪрдХреНрд░ рдХреЗ рд╕рд╛рде рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдЕрдиреБрдорд╛рдирд┐рдд рд╡реНрдпрд╡рд╣рд╛рд░ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реИред


рдЕрдм рдЖрдЗрдП рдЬрд╛рдиреЗрдВ рдХрд┐ рдЗрд╕реЗ рдХреИрд╕реЗ рдардВрдбрд╛ рдХрд┐рдпрд╛ рдЬрд╛рдП ред


рд╕рдорд╕реНрдпрд╛рдУрдВ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рдХреЗ рд░реВрдк рдореЗрдВ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд


AK74


рдЬрдм рд▓реЛрдЧ рд░рд╛рдЬреНрдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рд░рд╛рдЬреНрдп рдХреА рдорд╢реАрдиреЗрдВ рддреБрд░рдВрдд рджрд┐рдорд╛рдЧ рдореЗрдВ рдЖ рдЬрд╛рддреА рд╣реИрдВред рдпрд╣ рддрд╛рд░реНрдХрд┐рдХ рд╣реИ, рдХреНрдпреЛрдВрдХрд┐ рдПрдХ рдСрдЯреЛрдореЗрдЯрди рдПрдХ рд░рд╛рдЬреНрдп рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рдкреНрд░рд╛рдХреГрддрд┐рдХ рддрд░реАрдХрд╛ рд╣реИред


рдореИрдВ рдСрдЯреЛрдореЗрдЯрд╛ рдХреЗ рд╕рд┐рджреНрдзрд╛рдВрдд рдореЗрдВ рдирд╣реАрдВ рдЙрддрд░реВрдВрдЧрд╛ , рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ рдкрд░реНрдпрд╛рдкреНрдд рдЬрд╛рдирдХрд╛рд░реА рд╕реЗ рдЕрдзрд┐рдХ рд╣реИред

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


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


  • рд░рд╛рдЬреНрдпреЛрдВ - рдЬреАрд╡рди рдЪрдХреНрд░;
  • рдШрдЯрдирд╛рдУрдВ - рдХреНрдпрд╛ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рд░рд╛рдЬреНрдп рдХреЗ рд▓рд┐рдП рд╕рдВрдХреНрд░рдордг рдХрд╛ рдХрд╛рд░рдг рдмрдирддрд╛ рд╣реИ;
  • рдХрд╛рд░реНрдп рдкрд░рд┐рдгрд╛рдо - рдЖрдЙрдЯрдкреБрдЯ рдбреЗрдЯрд╛;
  • рдирд┐рд╖реНрдкрд╛рджрди рдореЛрдб (рд╕рд┐рдВрдХреНрд░реЛрдирд╕ / рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕);
  • рдореБрдЦреНрдп рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЗред

рд▓реЗрдХреНрд╕рд░ рд╕реБрдВрджрд░ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдХреЗрд╡рд▓ рдбреЗрдЯрд╛ рдХреА рд╡рдЬрд╣ рд╕реЗ рд░рд╛рдЬреНрдп рдХреЛ рдмрджрд▓рддрд╛ рд╣реИ рдЬреЛ рдЗрд╕реЗ рд╕реНрд╡рдпрдВ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдЙрд╕ рд╕реНрдерд┐рддрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд╕рдВрдХреНрд░рдордг рдХреЛ рдЖрдордВрддреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реИ? рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдВ рдЗрд╡реЗрдВрдЯ рдорд╢реАрди рдорджрдж рдХрд░ рд╕рдХрддреА рд╣реИред


рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЙрджрд╛рд╣рд░рдг


рдЗрд╕реЗ рд╕реНрдкрд╖реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ phono рд▓рд╛рдЗрдмреНрд░реЗрд░реА рд╕реЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдХрд░реВрдВрдЧрд╛ред


рд╕рдВрджрд░реНрдн рдореЗрдВ рдПрдХ рдкреВрд░реНрдг рд╡рд┐рд╕рд░реНрдЬрди рдХреЗ рд▓рд┐рдП, рдЖрдк рдкрд░рд┐рдЪрдпрд╛рддреНрдордХ рд▓реЗрдЦ рдкрдврд╝ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╣ рдЗрд╕ рд╡рд┐рд╖рдп рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдмреЗрд╣рддрд░ рд╕рдордЭрдиреЗ рдореЗрдВ рдорджрдж рдХрд░реЗрдЧрд╛ рдХрд┐ рд╣рдо рдХреНрдпрд╛ рдкреНрд░рдмрдВрдз рдХрд░ рд░рд╣реЗ рд╣реИрдВред

рдФрд░ рд╣рдо рдХреНрдпрд╛ рдкреНрд░рдмрдВрдз рдХрд░ рд░рд╣реЗ рд╣реИрдВ?


phono рдбреАрдПрд╕рдкреА рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдкрд░ рдЖрдзрд╛рд░рд┐рдд рд╣реИред рдЗрд╕рдореЗрдВ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рддреАрди рдЪрд░рдг рд╣реЛрддреЗ рд╣реИрдВред рдкреНрд░рддреНрдпреЗрдХ рдЪрд░рдг рдореЗрдВ рдПрдХ рд╕реЗ рд▓реЗрдХрд░ рдХрдИ рдШрдЯрдХ рд╢рд╛рдорд┐рд▓ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ:


pipe_diagram


  1. pipe.Pump (рдЕрдВрдЧреНрд░реЗрдЬреА рдкрдВрдк) рдзреНрд╡рдирд┐ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдЕрдирд┐рд╡рд╛рд░реНрдп рдЪрд░рдг рд╣реИ, рд╣рдореЗрд╢рд╛ рдХреЗрд╡рд▓ рдПрдХ рдШрдЯрдХред
  2. pipe.Processor (рдЕрдВрдЧреНрд░реЗрдЬреА рд╣реИрдВрдбрд▓рд░) - 0 рд╕реЗ рдПрди рдШрдЯрдХреЛрдВ рдХреЗ рд▓рд┐рдП рдзреНрд╡рдирд┐ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд╛ рдПрдХ рд╡реИрдХрд▓реНрдкрд┐рдХ рдЪрд░рдгред
  3. pipe.Sink рд╕рд┐рдВрдХ (рдЕрдВрдЧреНрд░реЗрдЬреА рд╕рд┐рдВрдХ) - 1 рд╕реЗ рдПрди рдШрдЯрдХреЛрдВ рддрдХ рдзреНрд╡рдирд┐ рд╕рдВрдЪрд░рдг рдХрд╛ рдПрдХ рдЕрдирд┐рд╡рд╛рд░реНрдп рдЪрд░рдгред

рджрд░рдЕрд╕рд▓, рд╣рдо рдХрдиреНрд╡реЗрдпрд░ рдЬреАрд╡рди рдЪрдХреНрд░ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдХрд░реЗрдВрдЧреЗред


рдЬреАрд╡рди рдЪрдХреНрд░


рдпрд╣ рд╡рд╣реА рд╣реИ рдЬреЛ pipe.Pipe ред pipe.Pipe рд░рд╛рдЬреНрдп рдЖрд░реЗрдЦ рдЬреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИред


pipe_lifecycle


рдЗрдЯреИрд▓рд┐рдХ рдЖрдВрддрд░рд┐рдХ рдирд┐рд╖реНрдкрд╛рджрди рддрд░реНрдХ рдХреЗ рдХрд╛рд░рдг рд╕рдВрдХреНрд░рдордг рдХрд╛ рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВред рдмреЛрд▓реНрдб - рдШрдЯрдирд╛рдУрдВ рдХреЗ рдХрд╛рд░рдг рд╕рдВрдХреНрд░рдордгред рдЖрд░реЗрдЦ рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рд░рд╛рдЬреНрдпреЛрдВ рдХреЛ 2 рдкреНрд░рдХрд╛рд░реЛрдВ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:


  • рдореМрди рд░рд╛рдЬреНрдпреЛрдВ - ready рдФрд░ paused , рдЖрдк рдХреЗрд╡рд▓ рдШрдЯрдирд╛ рд╕реЗ рдЙрди рд╕реЗ рдХреВрдж рд╕рдХрддреЗ рд╣реИрдВ
  • рд╕рдХреНрд░рд┐рдп рд╕реНрдерд┐рддрд┐ - running рдФрд░ pausing , рдШрдЯрдирд╛ рд╕реЗ рд╕рдВрдХреНрд░рдордг рдФрд░ рдирд┐рд╖реНрдкрд╛рджрди рддрд░реНрдХ рдХреЗ рдХрд╛рд░рдг

рдХреЛрдб рдХреЗ рд╡рд┐рд╕реНрддреГрдд рд╡рд┐рд╢реНрд▓реЗрд╖рдг рд╕реЗ рдкрд╣рд▓реЗ, рд╕рднреА рд░рд╛рдЬреНрдпреЛрдВ рдХреЗ рдЙрдкрдпреЛрдЧ рдХрд╛ рдПрдХ рд╕реНрдкрд╖реНрдЯ рдЙрджрд╛рд╣рд░рдг:


 // PlayWav  .wav    portaudio  -. func PlayWav(wavFile string) error { bufferSize := phono.BufferSize(512) //      w, err := wav.NewPump(wavFile, bufferSize) //  wav pump if err != nil { return err } pa := portaudio.NewSink( //  portaudio sink bufferSize, w.WavSampleRate(), w.WavNumChannels(), ) p := pipe.New( //  pipe.Pipe    ready w.WavSampleRate(), pipe.WithPump(w), pipe.WithSinks(pa), ) p.Run() //    running   p.Run() errc := p.Pause() //    pausing   p.Pause() err = pipe.Wait(errc) //     paused if err != nil { return err } errc = p.Resume() //    running   p.Resume() err = pipe.Wait(errc) //     ready if err != nil { return err } return pipe.Wait(p.Close()) //      } 

рдЕрдм, рдкрд╣рд▓реЗ рдЪреАрдЬреЗрдВ рдкрд╣рд▓реЗред


рд╕рднреА рд╕реНрд░реЛрдд рдХреЛрдб рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдореЗрдВ рдЙрдкрд▓рдмреНрдз рд╣реИрдВред

рд░рд╛рдЬреНрдпреЛрдВ рдФрд░ рдШрдЯрдирд╛рдУрдВ


рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд╛рдд рдХреЗ рд╕рд╛рде рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред


 // state      . type state interface { listen(*Pipe, target) (state, target) //    transition(*Pipe, eventMessage) (state, error) //   } // idleState  .        . type idleState interface { state } // activeState  .         //   . type activeState interface { state sendMessage(*Pipe) state //    } //  . type ( idleReady struct{} activeRunning struct{} activePausing struct{} idlePaused struct{} ) //  . var ( ready idleReady running activeRunning paused idlePaused pausing activePausing ) 

рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж, рдкреНрд░рддреНрдпреЗрдХ рд░рд╛рдЬреНрдп рдХреЗ рд▓рд┐рдП рд╕рдВрдХреНрд░рдордг рднреА рдЕрд▓рдЧ-рдЕрд▓рдЧ рдШреЛрд╖рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдЗрд╕рд╕реЗ рд╡рд┐рд╢рд╛рд▓ рдмрдЪ рдЬрд╛рддрд╛ рд╣реИ рд╕реЙрд╕ рдиреЗрд╕реНрдЯреЗрдб switch рд╕рд╛рде рд╕рдВрдХреНрд░рдордг рдХрд╛рд░реНрдп рдХрд░рддрд╛ рд╣реИред рд░рд╛рдЬреНрдпреЛрдВ рдХреЗ рдкрд╛рд╕ рд╕реНрд╡рдпрдВ рдХреЛрдИ рдбреЗрдЯрд╛ рдпрд╛ рддрд░реНрдХ рдирд╣реАрдВ рд╣реИред рдЙрдирдХреЗ рд▓рд┐рдП, рдЖрдк рдкреИрдХреЗрдЬ рд╕реНрддрд░ рдкрд░ рдЪрд░ рдШреЛрд╖рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рдЖрдк рд╣рд░ рдмрд╛рд░ рдРрд╕рд╛ рди рдХрд░реЗрдВред рдмрд╣реБрд░реВрдкрддрд╛ рдХреЗ рд▓рд┐рдП state рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред activeState рдереЛрдбрд╝реА рджреЗрд░ рдмрд╛рдж idleState рдФрд░ idleState рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд idleState ред


рд╣рдорд╛рд░реА рдорд╢реАрди рдХрд╛ рджреВрд╕рд░рд╛ рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд╣рд┐рд╕реНрд╕рд╛ рдШрдЯрдирд╛рдУрдВ рд╣реИред


 // event  . type event int //  . const ( run event = iota pause resume push measure cancel ) // target      . type target struct { state idleState //   errc chan error //   ,     } // eventMessage   ,    . type eventMessage struct { event //   params params //   components []string // id  target //      } 

рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ target рдкреНрд░рдХрд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ, рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЙрджрд╛рд╣рд░рдг рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдВред рд╣рдордиреЗ рдПрдХ рдирдпрд╛ рдХрдиреНрд╡реЗрдпрд░ рдмрдирд╛рдпрд╛ рд╣реИ, рдпрд╣ ready ред рдЕрдм рдЗрд╕реЗ p.Run() рд╕рд╛рде p.Run() ред run рдЗрд╡реЗрдВрдЯ рдХреЛ рдорд╢реАрди рдореЗрдВ рднреЗрдЬрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдкрд╛рдЗрдкрд▓рд╛рдЗрди running рд╕реНрдЯреЗрдЯ рдореЗрдВ рдЬрд╛рддреА рд╣реИред рдЬрдм рдХрдиреНрд╡реЗрдпрд░ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЧрдпрд╛ рд╣реИ рддреЛ рдХреИрд╕реЗ рдкрддрд╛ рдХрд░реЗрдВ? рдпрд╣ рд╡рд╣ рдЬрдЧрд╣ рд╣реИ рдЬрд╣рд╛рдБ target рдкреНрд░рдХрд╛рд░ рд╣рдорд╛рд░реА рдорджрдж рдХрд░реЗрдЧрд╛ред рдпрд╣ рдЗрдВрдЧрд┐рдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдШрдЯрдирд╛ рдХреЗ рдмрд╛рдж рдЖрд░рд╛рдо рдХрд░рдиреЗ рдХреА рдХреНрдпрд╛ рд╕реНрдерд┐рддрд┐ рд╣реИред рд╣рдорд╛рд░реЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдХрд╛рдо рдкреВрд░рд╛ рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж, рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдлрд┐рд░ рд╕реЗ ready рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░реЗрдЧреАред рдЖрд░реЗрдЦ рдореЗрдВ рдПрдХ рд╣реА рдмрд╛рдд:



рдЕрдм рд░рд╛рдЬреНрдпреЛрдВ рдХреЗ рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЕрдзрд┐рдХред рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рд░реВрдк рд╕реЗ, idleState рдФрд░ idleState activeState рдмрд╛рд░реЗ рдореЗрдВред рдЪрд▓реЛ рд╡рд┐рднрд┐рдиреНрди рдкреНрд░рдХрд╛рд░ рдХреЗ рдЪрд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП listen(*Pipe, target) (state, target) рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рджреЗрдЦреЗрдВ:


 // listen     ready. func (s idleReady) listen(p *Pipe, t target) (state, target) { return p.idle(s, t) } // listen     running. func (s activeRunning) listen(p *Pipe, t target) (state, target) { return p.active(s, t) } 

рдПрдХ рд╕рдВрдХреНрд░рдордг рдХреЗ рд▓рд┐рдП рдкреНрд░рддреАрдХреНрд╖рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП pipe.Pipe рдХреЗ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдХрд╛рд░реНрдп рд╣реИрдВ! рд╡рд╣рд╛рдБ рдХреНрдпрд╛ рд╣реИ?


 // idle     .    . func (p *Pipe) idle(s idleState, t target) (state, target) { if s == t.state || s == ready { t = t.dismiss() //  ,  target } for { var newState state var err error select { case e := <-p.events: //   newState, err = s.transition(p, e) //    if err != nil { e.target.handle(err) } else if e.hasTarget() { t.dismiss() t = e.target } } if s != newState { return newState, t // ,    } } } // active     .     , //   . func (p *Pipe) active(s activeState, t target) (state, target) { for { var newState state var err error select { case e := <-p.events: //   newState, err = s.transition(p, e) //    if err != nil { //  ? e.target.handle(err) // ,    } else if e.hasTarget() { // ,  target t.dismiss() //   t = e.target //   } case <-p.provide: //     newState = s.sendMessage(p) //    case err, ok := <-p.errc: //   if ok { //   ,  interrupt(p.cancel) //   t.handle(err) //    } //    ,  return ready, t //    ready } if s != newState { return newState, t // ,    } } } 

рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рд╡рд┐рднрд┐рдиреНрди рд░рд╛рдЬреНрдпреЛрдВ рдореЗрдВ рд╡рд┐рднрд┐рдиреНрди рдЪреИрдирд▓реЛрдВ рдХреЛ рд╕реБрди рд╕рдХрддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрд╣ рдЖрдкрдХреЛ рдПрдХ рдард╣рд░рд╛рд╡ рдХреЗ рджреМрд░рд╛рди рд╕рдВрджреЗрд╢ рдирд╣реАрдВ рднреЗрдЬрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ - рд╣рдо рд╕рд┐рд░реНрдл рд╕рдВрдмрдВрдзрд┐рдд рдЪреИрдирд▓ рдХреЛ рдирд╣реАрдВ рд╕реБрдирддреЗ рд╣реИрдВред


рдорд╢реАрди рдХрд╛ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдФрд░ рд╕реНрдЯрд╛рд░реНрдЯ



 // New      . //      ready. func New(sampleRate phono.SampleRate, options ...Option) *Pipe { p := &Pipe{ UID: phono.NewUID(), sampleRate: sampleRate, log: log.GetLogger(), processors: make([]*processRunner, 0), sinks: make([]*sinkRunner, 0), metrics: make(map[string]measurable), params: make(map[string][]phono.ParamFunc), feedback: make(map[string][]phono.ParamFunc), events: make(chan eventMessage, 1), //    cancel: make(chan struct{}), //     provide: make(chan struct{}), consume: make(chan message), } for _, option := range options { //   option(p)() } go p.loop() //    return p } 

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


 // loop ,     nil . func (p *Pipe) loop() { var s state = ready //   t := target{} for s != nil { s, t = s.listen(p, t) //      p.log.Debug(fmt.Sprintf("%v is %T", p, s)) } t.dismiss() close(p.events) //    } // listen     ready. func (s idleReady) listen(p *Pipe, t target) (state, target) { return p.idle(s, t) } // transition       . func (s idleReady) transition(p *Pipe, e eventMessage) (state, error) { switch e.event { case cancel: interrupt(p.cancel) return nil, nil case push: e.params.applyTo(p.ID()) p.params = p.params.merge(e.params) return s, nil case measure: for _, id := range e.components { e.params.applyTo(id) } return s, nil case run: if err := p.start(); err != nil { return s, err } return running, nil } return s, ErrInvalidState } 

рдХрдиреНрд╡реЗрдпрд░ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рдШрдЯрдирд╛рдУрдВ рдХреА рдкреНрд░рддреАрдХреНрд╖рд╛ рдореЗрдВ рдЬрдо рдЧрдпрд╛ рд╣реИред


рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рд╕рдордп


p.Run() рдХреЙрд▓ рдХрд░реЗрдВ!



 // Run   run  . //     pipe.Close  . func (p *Pipe) Run() chan error { runEvent := eventMessage{ event: run, target: target{ state: ready, //    errc: make(chan error, 1), }, } p.events <- runEvent return runEvent.target.errc } // listen     running. func (s activeRunning) listen(p *Pipe, t target) (state, target) { return p.active(s, t) } // transition       . func (s activeRunning) transition(p *Pipe, e eventMessage) (state, error) { switch e.event { case cancel: interrupt(p.cancel) err := Wait(p.errc) return nil, err case measure: e.params.applyTo(p.ID()) p.feedback = p.feedback.merge(e.params) return s, nil case push: e.params.applyTo(p.ID()) p.params = p.params.merge(e.params) return s, nil case pause: return pausing, nil } return s, ErrInvalidState } // sendMessage   . func (s activeRunning) sendMessage(p *Pipe) state { p.consume <- p.newMessage() return s } 

running рд╕рдВрджреЗрд╢ рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ рдФрд░ рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдХреЗ рдкреВрд░рд╛ рд╣реЛрдиреЗ рддрдХ рдЪрд▓рддрд╛ рд╣реИред


рдХреЙрдлреА рдмреНрд░реЗрдХ


рдХрдиреНрд╡реЗрдпрд░ рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рджреМрд░рд╛рди, рд╣рдо рдЗрд╕реЗ рд░реЛрдХ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕ рд╕реНрдерд┐рддрд┐ рдореЗрдВ, рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдирдП рд╕рдВрджреЗрд╢ рдЙрддреНрдкрдиреНрди рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, p.Pause() рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░реЗрдВред



 // Pause   pause  . //     pipe.Close  . func (p *Pipe) Pause() chan error { pauseEvent := eventMessage{ event: pause, target: target{ state: paused, //    errc: make(chan error, 1), }, } p.events <- pauseEvent return pauseEvent.target.errc } // listen     pausing. func (s activePausing) listen(p *Pipe, t target) (state, target) { return p.active(s, t) } // transition       . func (s activePausing) transition(p *Pipe, e eventMessage) (state, error) { switch e.event { case cancel: interrupt(p.cancel) err := Wait(p.errc) return nil, err case measure: e.params.applyTo(p.ID()) p.feedback = p.feedback.merge(e.params) return s, nil case push: e.params.applyTo(p.ID()) p.params = p.params.merge(e.params) return s, nil } return s, ErrInvalidState } // sendMessage   .   -, //      .    //    ,      .  , // ,   , : // 1.     // 2.      func (s activePausing) sendMessage(p *Pipe) state { m := p.newMessage() if len(m.feedback) == 0 { m.feedback = make(map[string][]phono.ParamFunc) } var wg sync.WaitGroup //     wg.Add(len(p.sinks)) //   Sink for _, sink := range p.sinks { param := phono.ReceivedBy(&wg, sink.ID()) // - m.feedback = m.feedback.add(param) } p.consume <- m //   wg.Wait() // ,     return paused } 

рдЬреИрд╕реЗ рд╣реА рд╕рднреА рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ, рдкрд╛рдЗрдкрд▓рд╛рдЗрди paused рд╕реНрдерд┐рддрд┐ рдореЗрдВ paused рдЬрд╛рдПрдЧреАред рдпрджрд┐ рд╕рдВрджреЗрд╢ рдЕрдВрддрд┐рдо рд╣реИ, рддреЛ ready рд╕реНрдерд┐рддрд┐ рдореЗрдВ рд╕рдВрдХреНрд░рдордг рд╣реЛрддрд╛ рд╣реИред


рд╡рд╛рдкрд╕ рдХрд╛рдо рдкрд░!


paused рдЕрд╡рд╕реНрдерд╛ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рдиреЗ рдХреЗ рд▓рд┐рдП p.Resume() рдХреЙрд▓ рдХрд░реЗрдВред



 // Resume   resume  . //     pipe.Close  . func (p *Pipe) Resume() chan error { resumeEvent := eventMessage{ event: resume, target: target{ state: ready, errc: make(chan error, 1), }, } p.events <- resumeEvent return resumeEvent.target.errc } // listen     paused. func (s idlePaused) listen(p *Pipe, t target) (state, target) { return p.idle(s, t) } // transition       . func (s idlePaused) transition(p *Pipe, e eventMessage) (state, error) { switch e.event { case cancel: interrupt(p.cancel) err := Wait(p.errc) return nil, err case push: e.params.applyTo(p.ID()) p.params = p.params.merge(e.params) return s, nil case measure: for _, id := range e.components { e.params.applyTo(id) } return s, nil case resume: return running, nil } return s, ErrInvalidState } 

рдпрд╣рд╛рдВ рд╕рдм рдХреБрдЫ рддреБрдЪреНрдЫ рд╣реИ, рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдлрд┐рд░ рд╕реЗ running рд╣реИред


рдКрдкрд░ рдХрд░реНрд▓ рдХрд░реЗрдВ


рдХрдиреНрд╡реЗрдпрд░ рдХреЛ рдХрд┐рд╕реА рднреА рд░рд╛рдЬреНрдп рд╕реЗ рд░реЛрдХрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЗрд╕рдХреЗ рд▓рд┐рдП p.Close() ред



 // Close   cancel  . //      . //    ,   . func (p *Pipe) Close() chan error { resumeEvent := eventMessage{ event: cancel, target: target{ state: nil, //   errc: make(chan error, 1), }, } p.events <- resumeEvent return resumeEvent.target.errc } 

рдЗрд╕рдХреА рдЬрд░реВрд░рдд рдХрд┐рд╕реЗ рд╣реИ?


рд╣рд░ рдХрд┐рд╕реА рдХреЗ рд▓рд┐рдП рдирд╣реАрдВред рд░рд╛рдЬреНрдп рдХреЛ рдХреИрд╕реЗ рдкреНрд░рдмрдВрдзрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдП, рдпрд╣ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЕрдкрдиреЗ рдХрд╛рд░реНрдп рдХреЛ рд╕рдордЭрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдРрд╕реА рджреЛ рдкрд░рд┐рд╕реНрдерд┐рддрд┐рдпрд╛рдБ рд╣реИрдВ рдЬрд┐рдирдореЗрдВ рдЖрдк рдПрдХ рдШрдЯрдирд╛-рдЖрдзрд╛рд░рд┐рдд рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдорд╢реАрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:


  1. рдЬрдЯрд┐рд▓ рдЬреАрд╡рди рдЪрдХреНрд░ - рдЧреИрд░-рд░реИрдЦрд┐рдХ рд╕рдВрдХреНрд░рдордг рд╡рд╛рд▓реЗ рддреАрди рдпрд╛ рдЕрдзрд┐рдХ рд░рд╛рдЬреНрдп рд╣реИрдВред
  2. рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдирд┐рд╖реНрдкрд╛рджрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

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


рд╕рдВрджрд░реНрдн


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


All Articles