рд▓рд┐рдирдХреНрд╕рдХреЛ рд▓рд╛рдЧрд┐ рдкрдиреНрдЯреЛ рд╕реНрд╡рд┐рдЪрд░рдХреЛ рдирдпрд╛рдБ рдПрдирд╛рд▓рдЧ: xswitcher

xneur рд╕рдорд░реНрдердирдХреЛ рдЕрдиреНрддреНрдпрд▓реЗ рдорд▓рд╛рдИ рд╡рд┐рдЧрдд рдЫ рдорд╣рд┐рдирд╛рдорд╛ рдХреЗрд╣реА рдкреАрдбрд╛ рджрд┐рдПрдХреЛ рдЫред (рдореЗрд░реЛ рдбреЗрд╕реНрдХрдЯрдкрдорд╛ OpenSUSE 15.1 рдХреЛ рдЖрдЧрдордирд╕рдБрдЧреИ: xneur рд╕рдХреНрд╖рдо рднрдПрдХреЛрд▓реЗ, рд╡рд┐рдиреНрдбреЛрдЬрд▓реЗ рдлреЛрдХрд╕ рдЧреБрдорд╛рдЙрдБрдЫ рд░ рдХрд┐рдмреЛрд░реНрдб рдЗрдирдкреБрдЯрдХреЛ рд╕рд╛рдердорд╛ рд╕рдордпрдореИ рд░рдорд╛рдЗрд▓реЛ рдЭрд┐рд▓рдорд┐рд▓ рд╣реБрдиреНрдЫ).

"рдУрд╣реЛ, рдзрд┐рдХреНрдХрд╛рд░ рдЫ, рдореИрд▓реЗ рдлреЗрд░рд┐ рдЧрд▓рдд рд▓реЗрдЖрдЙрдЯрдорд╛ рдЯрд╛рдЗрдк рдЧрд░реНрди рдерд╛рд▓реЗрдВ" - рдореЗрд░реЛ рдХрд╛рдордорд╛ рдпреЛ рдЕрдХреНрд╕рд░ рдЕрд╢реЛрднрдиреАрдп рд░реВрдкрдорд╛ рд╣реБрдиреНрдЫред рд░ рдпрд╕рд▓реЗ рдХреЗрд╣рд┐ рд╕рдХрд╛рд░рд╛рддреНрдордХ рдердкреНрджреИрдиред

рд▓рд┐рдирдХреНрд╕рдХреЛ рд▓рд╛рдЧрд┐ рдкрдиреНрдЯреЛ рд╕реНрд╡рд┐рдЪрд░рдХреЛ рдирдпрд╛рдБ рдПрдирд╛рд▓рдЧ: xswitcher
рдПрдХреИ рд╕рдордпрдорд╛, рдо (рдбрд┐рдЬрд╛рдЗрди рдЗрдиреНрдЬрд┐рдирд┐рдпрд░рдХреЛ рд░реВрдкрдорд╛) рдореИрд▓реЗ рдЪрд╛рд╣реЗрдХреЛ рдХреБрд░рд╛ рд╕реНрдкрд╖реНрдЯ рд░реВрдкрдорд╛ рддрдпрд╛рд░ рдЧрд░реНрди рд╕рдХреНрдЫреБред рддрд░ рдо рдЪрд╛рд╣рдиреНрдереЗрдВ (рдкрд╣рд┐рд▓реЛ рдкрдиреНрдЯреЛ рд╕реНрд╡рд┐рдЪрд░рдмрд╛рдЯ, рд░ рддреНрдпрд╕рдкрдЫрд┐, рд╡рд┐рдиреНрдбреЛрдЬ рднрд┐рд╕реНрдЯрд╛рд▓рд╛рдИ рдзрдиреНрдпрд╡рд╛рдж, рдЕрдиреНрддрдорд╛ xneur рдмрд╛рдЯ рд▓рд┐рдирдХреНрд╕рдорд╛ рд╕реНрд╡рд┐рдЪ рдЧрд░реНрджреИ) рдареНрдпрд╛рдХреНрдХреИ рдПрдЙрдЯрд╛ рдХреБрд░рд╛ред рд╕реНрдХреНрд░рд┐рдирдорд╛ рдлреЛрд╣реЛрд░ рдЧрд▓рдд рд▓реЗрдЖрдЙрдЯрдорд╛ рдЫ рднрдиреНрдиреЗ рдорд╣рд╕реБрд╕ рдЧрд░реЗрдкрдЫрд┐ (рдпреЛ рд╕рд╛рдорд╛рдиреНрдпрддрдпрд╛ рдирдпрд╛рдБ рд╢рдмреНрдж рдЯрд╛рдЗрдк рдЧрд░реНрджрд╛ рд╣реБрдиреНрдЫ), "рдкрдЬ/рдмреНрд░реЗрдХ" рдорд╛ рд╕реНрдЯрдореНрдк рдЧрд░реНрдиреБрд╣реЛрд╕реНред рд░ рддрдкрд╛рдИрдВрд▓реЗ рдЫрд╛рдкреЗрдХреЛ рдХреБрд░рд╛ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрдиреБрд╣реЛрд╕реНред

рдпрд╕ рд╕рдордпрдорд╛, рдЙрддреНрдкрд╛рджрдирд╕рдБрдЧ рдЗрд╖реНрдЯрддрдо (рдореЗрд░реЛ рджреГрд╖реНрдЯрд┐рдХреЛрдгрдмрд╛рдЯ) рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛/рдЬрдЯрд┐рд▓рддрд╛ рдЕрдиреБрдкрд╛рдд рдЫред рдпреЛ рд╕рд╛рдЭрд╛ рдЧрд░реНрдиреЗ рд╕рдордп рд╣реЛред

TL.DR

рддреНрдпрд╣рд╛рдБ рд╕рдмреИ рдкреНрд░рдХрд╛рд░рдХрд╛ рдкреНрд░рд╛рд╡рд┐рдзрд┐рдХ рд╡рд┐рд╡рд░рдгрд╣рд░реВ рдкрдЫрд┐ рд╣реБрдиреЗрдЫрдиреН, рддреНрдпрд╕реИрд▓реЗ рдкрд╣рд┐рд▓реЗ - рд▓рд┐рдЩреНрдХ "рдЫреЛрдЙрди" рдЕрдзреАрд░рдХрд╛ рд▓рд╛рдЧрд┐ред

рд╣рд╛рд▓ рдирд┐рдореНрди рд╡реНрдпрд╡рд╣рд╛рд░ рд╣рд╛рд░реНрдбрдХреЛрдб рдЧрд░рд┐рдПрдХреЛ рдЫ:

  • "рдкрдЬ/рдмреНрд░реЗрдХ": рдЕрдиреНрддрд┐рдо рд╢рдмреНрдж рдмреНрдпрд╛рдХрд╕реНрдкреЗрд╕ рдЧрд░реНрджрдЫ, рд╕рдХреНрд░рд┐рдп рд╕рдЮреНрдЭреНрдпрд╛рд▓рдорд╛ рд▓реЗрдЖрдЙрдЯ рд╕реНрд╡рд┐рдЪ рдЧрд░реНрджрдЫ (реж рд░ рез рдмреАрдЪ) рд░ рдлреЗрд░рд┐ рдбрд╛рдпрд▓ рдЧрд░реНрджрдЫред
  • "рдХреБрдиреИ рдкрдирд┐ рдмрд┐рдирд╛ Ctrl рдмрд╛рдпрд╛рдБ": рд╕рдХреНрд░рд┐рдп рд╕рдЮреНрдЭреНрдпрд╛рд▓рдорд╛ рд▓реЗрдЖрдЙрдЯ рд╕реНрд╡рд┐рдЪ рдЧрд░реНрджрдЫ (0 рд░ 1 рдмреАрдЪ)ред
  • "рдХреБрдиреИ рдкрдирд┐ рдмрд┐рдирд╛ рдмрд╛рдпрд╛рдБ рд╕рд┐рдлреНрдЯ": рд╕рдХреНрд░рд┐рдп рд╡рд┐рдиреНрдбреЛрдорд╛ рд▓реЗрдЖрдЙрдЯ рдирдореНрдмрд░ 0 рд▓рд╛рдИ рд╕рдХреНрд░рд┐рдп рдЧрд░реНрджрдЫред
  • "рдХреБрдиреИ рдкрдирд┐ рдмрд┐рдирд╛ рджрд╛рдпрд╛рдБ рд╕рд┐рдлреНрдЯ": рд╕рдХреНрд░рд┐рдп рд╡рд┐рдиреНрдбреЛрдорд╛ рд▓реЗрдЖрдЙрдЯ рдирдореНрдмрд░ 1 рдЦреЛрд▓реНрдЫред

рдЕрдм рджреЗрдЦрд┐ рдо рд╡реНрдпрд╡рд╣рд╛рд░ рдЕрдиреБрдХреВрд▓рд┐рдд рдЧрд░реНрдиреЗ рдпреЛрдЬрдирд╛ рдЧрд░реНрдЫреБред рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдмрд┐рдирд╛, рдпреЛ рд░реЛрдЪрдХ рдЫреИрди (рдо рдЬреЗ рднрдП рдкрдирд┐ рдпрд╕рдХреЛ рд╕рд╛рде рдареАрдХ рдЫреБ)ред рдорд▓рд╛рдИ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдЫ рдХрд┐ Habr├й рдорд╛ рд╕рдорд╛рди рд╕рдорд╕реНрдпрд╛ рднрдПрдХрд╛ рджрд░реНрд╢рдХрд╣рд░реВрдХреЛ рдкрд░реНрдпрд╛рдкреНрдд рдкреНрд░рддрд┐рд╢рдд рд╣реБрдиреЗрдЫред

рдПрдирдмреА рдХрд┐рдирднрдиреЗ рд╣рд╛рд▓рдХреЛ рд╕рдВрд╕реНрдХрд░рдгрдорд╛, keylogger "/dev/input/" рдорд╛ рдЬреЛрдбрд┐рдПрдХреЛ рдЫ, xswitcher рдореВрд▓ рдЕрдзрд┐рдХрд╛рд░рд╣рд░реВрд╕рдБрдЧ рд╕реБрд░реБ рдЧрд░реНрдиреБрдкрд░реНрдЫ:

chown root:root xswitcher
chmod +xs xswitcher

рдХреГрдкрдпрд╛ рдзреНрдпрд╛рди рджрд┐рдиреБрд╣реЛрд╕реН: suid рд╕рдБрдЧ рдлрд╛рдЗрд▓рдХреЛ рдорд╛рд▓рд┐рдХ рд░реВрдЯ рд╣реБрдиреБрдкрд░реНрдЫ, рдХрд┐рдирднрдиреЗ рдЬреЛ рдХреЛрд╣реА рдорд╛рд▓рд┐рдХ рд╣реЛ рд╕реНрдЯрд╛рд░реНрдЯрдЕрдкрдорд╛ suid рдорд╛ рдкрд░рд┐рдгрдд рд╣реБрдиреЗрдЫред

Paranoids (рдо рдХреБрдиреИ рдЕрдкрд╡рд╛рдж рдЫреИрди) рдмрд╛рдЯ рдХреНрд▓реЛрди рдЧрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫ GIT рд░ рд╕рд╛рдЗрдЯ рдорд╛ рднреЗрд▓рд╛ред рдЬрд╕реНрддреИ:

go get "github.com/micmonay/keybd_event"
go get "github.com/gvalkov/golang-evdev"

### X11 headers for OpenSUSE/deb-based
zypper install libX11-devel libXmu-devel
apt-get install libx11-dev libxmu-dev

cd "x switcher/src/"
go build -o xswitcher -ldflags "-s -w" --tags static_all src/*.go

рд╕реНрд╡рд╛рджрдорд╛ рдЕрдЯреЛрд╕реНрдЯрд╛рд░реНрдЯ рдердкреНрдиреБрд╣реЛрд╕реН (DE рдорд╛ рдирд┐рд░реНрднрд░ рдЧрд░реНрджреИ)ред

рдпрд╕рд▓реЗ рдХрд╛рдо рдЧрд░реНрдЫ, "рджрд┐рдпрд╛рдХреЛ рд▓рд╛рдЧрд┐ рд╕реЛрдзреНрджреИрди" (тЙИ30 рд╕реЗрдХреЗрдиреНрдб CPU рдкреНрд░рддрд┐ рджрд┐рди, RSS рдорд╛ тЙИ12 MB)ред

╨Я╨╛╨┤╤А╨╛╨▒╨╜╨╛╤Б╤В╨╕

рдЕрдм - рд╡рд┐рд╡рд░рдгред

рд╕рдореНрдкреВрд░реНрдг рднрдгреНрдбрд╛рд░ рдореВрд▓ рд░реВрдкрдорд╛ рдореЗрд░реЛ рдкрд╛рд▓реНрддреБ рдЬрдирд╛рд╡рд░ рдкрд░рд┐рдпреЛрдЬрдирд╛рдорд╛ тАЛтАЛрд╕рдорд░реНрдкрд┐рдд рдерд┐рдпреЛ, рд░ рдо рдЕрд░реНрдХреЛ рд╕реБрд░реБ рдЧрд░реНрди рдзреЗрд░реИ рдЕрд▓реНрдЫреА рдЫреБред рддреНрдпрд╕реЛрднрдП, рд╕рдмреИ рдЪреАрдЬрд╣рд░реВ рдвреЗрд░ рдЧрд░рд┐рдПрдХреЛ рдЫ (рдХреЗрд╡рд▓ рдлреЛрд▓реНрдбрд░рд╣рд░реВрдорд╛) рд░ AGPL ("рд░рд┐рднрд░реНрд╕ рдкреЗрдЯреЗрдиреНрдЯ") рджреНрд╡рд╛рд░рд╛ рдХрднрд░ рдЧрд░рд┐рдПрдХреЛ рдЫред

xswitcher рдХреЛрдб рдЧреЛрд▓рд╛рдЩрдорд╛ рд▓реЗрдЦрд┐рдПрдХреЛ рдЫ, C рдХреЛ рдиреНрдпреВрдирддрдо рд╕рдорд╛рд╡реЗрд╢рд╣рд░реВ рд╕рд╣рд┐рддред рдпреЛ рдЕрдиреБрдорд╛рди рдЧрд░рд┐рдПрдХреЛ рдЫ рдХрд┐ рдпреЛ рджреГрд╖реНрдЯрд┐рдХреЛрдгрд▓реЗ рдХрдо рд╕реЗ рдХрдо рдкреНрд░рдпрд╛рд╕рдХреЛ рдкрд░рд┐рдгрд╛рдо рджрд┐рдиреЗрдЫ (рдЕрд╣рд┐рд▓реЗрд╕рдореНрдо рдпреЛ рдЫ)ред cgo рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рдЫреБрдЯреЗрдХреЛ рдХреБрд░рд╛ рдЬрдбрд╛рди рдЧрд░реНрдиреЗ рдХреНрд╖рдорддрд╛ рдХрд╛рдпрдо рд░рд╛рдЦреНрджрд╛ред

рдкрд╛рдардорд╛ рдпреЛ рдХрд╣рд╛рдБрдмрд╛рдЯ рд░ рдХрд┐рди рдЙрдзрд╛рд░рд┐рдПрдХреЛ рдерд┐рдпреЛ рднрдиреНрдиреЗ рдЯрд┐рдкреНрдкрдгреАрд╣рд░реВ рдЫрдиреНред рдХрд┐рдирднрдиреЗ xneur рдХреЛрдб "рдорд▓рд╛рдИ рдкреНрд░реЗрд░рд┐рдд рдЧрд░реЗрди", рдореИрд▓реЗ рдпрд╕рд▓рд╛рдИ рд╕реБрд░реВрд╡рд╛рдд рдмрд┐рдиреНрджреБрдХреЛ рд░реВрдкрдорд╛ рд▓рд┐рдПрдБ рд▓реЛрд▓реЛрд╕реНрд╡рд┐рдЪрд░.

"/dev/input/" рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрдХрд╛ рджреБрдмреИ рдлрд╛рдЗрджрд╛рд╣рд░реВ рдЫрдиреН (рд╕рдмреИ рдХреБрд░рд╛ рджреЗрдЦрд┐рдиреЗ рдЫ, рдерд┐рдЪрд┐рдПрдХреЛ рд╕реНрд╡рдд: рджреЛрд╣реЛрд░рд┐рдиреЗ рдХреБрдЮреНрдЬреА рд╕рд╣рд┐рдд) рд░ рдмреЗрдлрд╛рдЗрджрд╛рд╣рд░реВред рдмреЗрдлрд╛рдЗрджрд╛рд╣рд░реВ рд╣реБрдиреН:

  • рд╕реНрд╡рддрдГ рджреЛрд╣реЛрд░рд┐рдиреЗ (рдХреЛрдб "реи" рднрдПрдХреЛ рдШрдЯрдирд╛рд╣рд░реВ) x рд╕рдБрдЧ рджреЛрд╣реЛрд░рд┐рдиреЗрд╕рдБрдЧ рд╕рдореНрдмрдиреНрдзрд┐рдд рд╣реБрдБрджреИрдиред
  • X11 рдЗрдиреНрдЯрд░рдлреЗрд╕рд╣рд░реВ рдорд╛рд░реНрдлрдд рдЗрдирдкреБрдЯ рджреЗрдЦрд┐рдБрджреИрди (рдЙрджрд╛рд╣рд░рдгрдХрд╛ рд▓рд╛рдЧрд┐ VNC рдХрд╕рд░реА рдХрд╛рдо рдЧрд░реНрджрдЫ)ред
  • рдЬрд░рд╛ рдЪрд╛рд╣рд┐рдиреНрдЫред

рдЕрд░реНрдХреЛрддрд░реНрдл, "XSelectExtensionEvent()" рдорд╛рд░реНрдлрдд X рдШрдЯрдирд╛рд╣рд░реВрдХреЛ рд╕рджрд╕реНрдпрддрд╛ рд▓рд┐рди рд╕рдореНрднрд╡ рдЫред рд╣реЗрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫ xinput рдХреЛрдбред рдореИрд▓реЗ рдЬрд╛рдиреЗрдХреЛ рд▓рд╛рдЧрд┐ рдпрд╕реНрддреЛ рдХреЗрд╣рд┐ рдлреЗрд▓рд╛ рдкрд╛рд░реЗрди, рд░ рдХреБрдиреИ рди рдХреБрдиреИ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдирд▓реЗ рддреБрд░реБрдиреНрддреИ рд╕реА рдХреЛрдбрдХреЛ рд╕рдп рд▓рд╛рдЗрдирд╣рд░реВ рд▓рд┐рдпреЛред рдпрд╕рд▓рд╛рдИ рдЕрд╣рд┐рд▓реЗрдХреЛ рд▓рд╛рдЧрд┐ рдЕрд▓рдЧ рд░рд╛рдЦреНрдиреБрд╣реЛрд╕реНред

"рд░рд┐рднрд░реНрд╕" рдЖрдЙрдЯрдкреБрдЯ рд╣рд╛рд▓ рднрд░реНрдЪреБрдЕрд▓ рдХрд┐рдмреЛрд░реНрдб рд╕реНрдХреНрд░реВ рдЧрд░реЗрд░ рдмрдирд╛рдЗрдПрдХреЛ рдЫред keybd_event рдХреЛ рд▓реЗрдЦрдХрд▓рд╛рдИ рдзрдиреНрдпрд╡рд╛рдж, рддрд░ рддреНрдпрд╣рд╛рдБ рдЕрдореВрд░реНрддрддрд╛ рдзреЗрд░реИ рдЙрдЪреНрдЪ-рд╕реНрддрд░рдХреЛ рдЫ рд░ рдердк рдкреБрди: рдЧрд░реНрдиреБрдкрд░реНрдиреЗрдЫред рдЙрджрд╛рд╣рд░рдгрдХрд╛ рд▓рд╛рдЧрд┐, рдо рддреЗрд╕реНрд░реЛ рдкрдЩреНрдХреНрддрд┐ рдЪрдпрди рдЧрд░реНрди рджрд╛рдпрд╛рдБ Win рдХреБрдЮреНрдЬреА рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдЫреБред рд░ рдХреЗрд╡рд▓ рдмрд╛рдпрд╛рдБ рд╡рд┐рди рдлрд┐рд░реНрддрд╛ рдкрдард╛рдЗрдПрдХреЛ рдЫред

рдЬреНрдЮрд╛рдд рдмрдЧрд╣рд░реВ

  • рд╣рд╛рдореАрд▓рд╛рдИ "рдХрдореНрдкреЛрдЬрд┐рдЯ" рдЗрдирдкреБрдЯрдХреЛ рдмрд╛рд░реЗрдорд╛ рдХреЗрд╣реА рдерд╛рд╣рд╛ рдЫреИрди (рдЙрджрд╛рд╣рд░рдг: ┬╜)ред рдпреЛ рдЕрд╣рд┐рд▓реЗ рдЖрд╡рд╢реНрдпрдХ рдЫреИрдиред
  • рд╣рд╛рдореАрд▓реЗ рд╕рд╣реА рд╡рд┐рди рдЧрд▓рдд рддрд░рд┐рдХрд╛рд▓реЗ рдЦреЗрд▓рд┐рд░рд╣реЗрдХрд╛ рдЫреМрдВред рдореЗрд░реЛ рдорд╛рдорд▓рд╛рдорд╛, рдпрд╕рд▓реЗ рдЬреЛрдб рддреЛрдбреНрдЫред
  • рддреНрдпрд╣рд╛рдБ рдХреБрдиреИ рд╕реНрдкрд╖реНрдЯ рдЗрдирдкреБрдЯ рдкрд╛рд░реНрд╕рд┐рдЩ рдЫреИрдиред рдпрд╕рдХреЛ рд╕рдЯреНрдЯрд╛, рддреНрдпрд╣рд╛рдБ рдзреЗрд░реИ рдкреНрд░рдХрд╛рд░реНрдпрд╣рд░реВ рдЫрдиреН: Compare(), CtrlSequence(), RepeatSequence(), SpaceSequence()ред ╨б╨┐╨░╤Б╨╕╨▒╨╛ nsmcan рддрдкрд╛рдИрдВрдХреЛ рд╣реЗрд░рдЪрд╛рд╣рдХреЛ рд▓рд╛рдЧрд┐: рдХреЛрдбрдорд╛ рд░ рдпрд╣рд╛рдБ рд╕рдЪреНрдпрд╛рдЗрдпреЛред рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕рдореНрднрд╛рд╡реНрдпрддрд╛ рд╕рдВрдЧ, рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдЧрд░реНрджрд╛ рддрдкрд╛рдИрдВ рдмрдЧрд╣рд░реВ рд╕рдорд╛рддреНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫред
    рдпрд╕ рдмрд┐рдиреНрджреБрдорд╛ рдорд▓рд╛рдИ "рдХрд╕рд░реА" рдерд╛рд╣рд╛ рдЫреИрди рд░ рдХреБрдиреИ рдкрдирд┐ рд╕реБрдЭрд╛рд╡рд╣рд░реВрдХреЛ рд╕реНрд╡рд╛рдЧрдд рдЧрд░реНрдиреЗрдЫреБред
  • (рд╣реЗ рднрдЧрд╡рд╛рди) рдЪреНрдпрд╛рдирд▓рд╣рд░реВрдХреЛ рдкреНрд░рддрд┐рд╕реНрдкрд░реНрдзрд╛рддреНрдордХ рдкреНрд░рдпреЛрдЧ (рдХрд┐рдмреЛрд░реНрдб рдШрдЯрдирд╛рд╣рд░реВ, рдорд╛рдЗрд╕ рдШрдЯрдирд╛рд╣рд░реВ)ред

рдирд┐рд╖реНрдХрд░реНрд╖рдорд╛

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

рд╢реБрднрдХрд╛рдордирд╛!

рд╕реНрд░реЛрдд: www.habr.com

рдПрдХ рдЯрд┐рдкреНрдкрдгреА рдердкреНрди