рд╣рд╛рдореА PVS-Studio рдХреЛ рдкреНрд░рдпреЛрдЧрд▓рд╛рдИ рдЕрдЭ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдмрдирд╛рдЙрди рдЬрд╛рд░реА рд░рд╛рдЦреНрдЫреМрдВред рд╣рд╛рдореНрд░реЛ рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЕрдм Chocolatey рдорд╛ рдЙрдкрд▓рдмреНрдз рдЫ, Windows рдХреЛ рд▓рд╛рдЧрд┐ рдкреНрдпрд╛рдХреЗрдЬ рдкреНрд░рдмрдиреНрдзрдХред рд╣рд╛рдореА рд╡рд┐рд╢реНрд╡рд╛рд╕ рдЧрд░реНрдЫреМрдВ рдХрд┐ рдпрд╕рд▓реЗ PVS-Studio рдХреЛ рддреИрдирд╛рддреА рдХреЛ рд╕реБрд╡рд┐рдзрд╛ рджрд┐рдиреЗрдЫ, рд╡рд┐рд╢реЗрд╖ рдЧрд░реА, рдХреНрд▓рд╛рдЙрдб рд╕реЗрд╡рд╛рд╣рд░реВрдорд╛ред рдЯрд╛рдврд╛ рдЬрд╛рди рдирджрд┐рдирдХреЛ рд▓рд╛рдЧрд┐, рдЙрд╣реА рдЪрдХрд▓реЗрдЯрдХреЛ рд╕реНрд░реЛрдд рдХреЛрдб рдЬрд╛рдБрдЪ рдЧрд░реМрдВред Azure DevOps рд▓реЗ CI рдкреНрд░рдгрд╛рд▓реАрдХреЛ рд░реВрдкрдорд╛ рдХрд╛рдо рдЧрд░реНрдиреЗрдЫред
рдпрд╣рд╛рдБ рдХреНрд▓рд╛рдЙрдб рдкреНрд░рдгрд╛рд▓реАрд╣рд░реВрд╕рдБрдЧ рдПрдХреАрдХрд░рдгрдХреЛ рд╡рд┐рд╖рдпрдорд╛ рд╣рд╛рдореНрд░рд╛ рдЕрдиреНрдп рд▓реЗрдЦрд╣рд░реВрдХреЛ рд╕реВрдЪреА рдЫ:
PVS-рд╕реНрдЯреБрдбрд┐рдпреЛ рдХреНрд▓рд╛рдЙрдбрд╣рд░реВрдорд╛ рдЬрд╛рдиреНрдЫ: Azure DevOps PVS-рд╕реНрдЯреБрдбрд┐рдпреЛ рдХреНрд▓рд╛рдЙрдбрд╣рд░реВрдорд╛ рдЬрд╛рдиреНрдЫ: рдЯреНрд░рд╛рднрд┐рд╕ CI PVS-рд╕реНрдЯреБрдбрд┐рдпреЛ рдХреНрд▓рд╛рдЙрдбрдорд╛ рдЬрд╛рдиреНрдЫ: CircleCI PVS-рд╕реНрдЯреБрдбрд┐рдпреЛ рдХреНрд▓рд╛рдЙрдбрд╣рд░реВрдорд╛ рдЬрд╛рдиреНрдЫ: GitLab CI/CD
рдо рддрдкрд╛рдИрдВрд▓рд╛рдИ Azure DevOps рд╕рдБрдЧ рдПрдХреАрдХрд░рдгрдХреЛ рдмрд╛рд░реЗрдорд╛ рдкрд╣рд┐рд▓реЛ рд▓реЗрдЦрдорд╛ рдзреНрдпрд╛рди рджрд┐рди рд╕рд▓реНрд▓рд╛рд╣ рджрд┐рдиреНрдЫреБ, рдХрд┐рдирдХрд┐ рдпрд╕ рдЕрд╡рд╕реНрдерд╛рдорд╛ рдХреЗрд╣реА рдмрд┐рдиреНрджреБрд╣рд░реВ рдореЗрдЯрд┐рдПрдХрд╛ рдЫрдиреН рддрд╛рдХрд┐ рдирдХреНрдХрд▓ рд╣реБрди рдирджрд┐рдиред
рддреНрдпрд╕реЛрднрдП, рдпрд╕ рд▓реЗрдЦрдХрд╛ рдирд╛рдпрдХрд╣рд░реВ:
Chocolatey рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреЗ рдмрд╛рд░реЗ
рддрдкрд╛рдИрд▓реЗ рдкреНрдпрд╛рдХреЗрдЬ рдкреНрд░рдмрдиреНрдзрдХрд▓рд╛рдИ рдпрд╕рдорд╛ рдХрд╕рд░реА рд╕реНрдерд╛рдкрдирд╛ рдЧрд░реНрдиреЗ рднрдиреЗрд░ рд╣реЗрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫ
рд╡рд┐рд╢реНрд▓реЗрд╖рдХрдХреЛ рдирд╡реАрдирддрдо рд╕рдВрд╕реНрдХрд░рдг рд╕реНрдерд╛рдкрдирд╛ рдЧрд░реНрди рдЖрджреЗрд╢:
choco install pvs-studio
PVS-рд╕реНрдЯреБрдбрд┐рдпреЛ рдкреНрдпрд╛рдХреЗрдЬрдХреЛ рд╡рд┐рд╢рд┐рд╖реНрдЯ рд╕рдВрд╕реНрдХрд░рдг рд╕реНрдерд╛рдкрдирд╛ рдЧрд░реНрди рдЖрджреЗрд╢:
choco install pvs-studio --version=7.05.35617.2075
рдкреВрд░реНрд╡рдирд┐рд░реНрдзрд╛рд░рд┐рдд рд░реВрдкрдорд╛, рд╡рд┐рд╢реНрд▓реЗрд╖рдХрдХреЛ рдХреЛрд░ рдорд╛рддреНрд░, рдХреЛрд░ рдХрдореНрдкреЛрдиреЗрдиреНрдЯ рд╕реНрдерд╛рдкрдирд╛ рд╣реБрдиреНрдЫред рдЕрдиреНрдп рд╕рдмреИ рдлреНрд▓реНрдпрд╛рдЧрд╣рд░реВ (рд╕реНрдЯреНрдпрд╛рдиреНрдбрдЕрд▓реЛрди, JavaCore, IDEA, MSVS2010, MSVS2012, MSVS2013, MSVS2015, MSVS2017, MSVS2019) --package-parameters рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рдкрд╛рд╕ рдЧрд░реНрди рд╕рдХрд┐рдиреНрдЫред
рднрд┐рдЬреБрдЕрд▓ рд╕реНрдЯреБрдбрд┐рдпреЛ 2019 рдХреЛ рд▓рд╛рдЧрд┐ рдкреНрд▓рдЧрдЗрдирдХреЛ рд╕рд╛рде рдПрдХ рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рд╕реНрдерд╛рдкрдирд╛ рдЧрд░реНрдиреЗ рдЖрджреЗрд╢рдХреЛ рдЙрджрд╛рд╣рд░рдг:
choco install pvs-studio --package-parameters="'/MSVS2019'"
рдЕрдм Azure DevOps рдЕрдиреНрддрд░реНрдЧрдд рд╡рд┐рд╢реНрд▓реЗрд╖рдХрдХреЛ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рдкреНрд░рдпреЛрдЧрдХреЛ рдЙрджрд╛рд╣рд░рдг рд╣реЗрд░реМрдВред
рд╕рдорд╛рдпреЛрдЬрди
рдо рддрдкрд╛рдИрдВрд▓рд╛рдИ рд╕рдореНрдЭрд╛рдЙрди рдЪрд╛рд╣рдиреНрдЫреБ рдХрд┐ рдЦрд╛рддрд╛ рджрд░реНрддрд╛ рдЧрд░реНрдиреЗ, рдмрд┐рд▓реНрдб рдкрд╛рдЗрдкрд▓рд╛рдЗрди рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрдиреЗ рд░ GitHub рднрдгреНрдбрд╛рд░рдорд╛ рдЕрд╡рд╕реНрдерд┐рдд рдкрд░рд┐рдпреЛрдЬрдирд╛рд╕рдБрдЧ рддрдкрд╛рдИрдВрдХреЛ рдЦрд╛рддрд╛ рд╕рд┐рдЩреНрдХреНрд░реЛрдирд╛рдЗрдЬ рдЧрд░реНрдиреЗ рдЬрд╕реНрддрд╛ рдореБрджреНрджрд╛рд╣рд░реВрдХреЛ рдмрд╛рд░реЗрдорд╛ рдЫреБрдЯреНрдЯреИ рдЦрдгреНрдб рдЫред
рдкрд╣рд┐рд▓реЗ, рдПрдЙрдЯрд╛ рд▓рдиреНрдЪ рдЯреНрд░рд┐рдЧрд░ рд╕реЗрдЯ рдЕрдк рдЧрд░реМрдВ, рд╣рд╛рдореАрд▓реЗ рдкрд░рд┐рд╡рд░реНрддрдирд╣рд░реВрдХрд╛ рд▓рд╛рдЧрд┐ рдорд╛рддреНрд░ рд╕реБрд░реБрд╡рд╛рдд рдЧрд░реНрдЫреМрдВ рднрдиреЗрд░ рд╕рдВрдХреЗрдд рдЧрд░реНрджреИ рдорд╛рд╕реНрдЯрд░ рд╕рд╛рдЦрд╛:
trigger:
- master
рдЕрд░реНрдХреЛ рд╣рд╛рдореАрд▓реЗ рднрд░реНрдЪреБрдЕрд▓ рдореЗрд╕рд┐рди рдЪрдпрди рдЧрд░реНрди рдЖрд╡рд╢реНрдпрдХ рдЫред рдЕрд╣рд┐рд▓реЗрдХреЛ рд▓рд╛рдЧрд┐ рдпреЛ Windows рд╕рд░реНрднрд░ 2019 рд░ рднрд┐рдЬреБрдЕрд▓ рд╕реНрдЯреБрдбрд┐рдпреЛ 2019 рд╕рдБрдЧ Microsoft-рд╣реЛрд╕реНрдЯ рдЧрд░рд┐рдПрдХреЛ рдПрдЬреЗрдиреНрдЯ рд╣реБрдиреЗрдЫ:
pool:
vmImage: 'windows-latest'
рдХрдиреНрдлрд┐рдЧрд░реЗрд╕рди рдлрд╛рдЗрд▓рдХреЛ рдореБрдЦреНрдп рднрд╛рдЧрдорд╛ рдЬрд╛рдФрдВ (рдмреНрд▓рдХ рдХрджрдо)ред рддрдкрд╛рдИрдВрд▓реЗ рднрд░реНрдЪреБрдЕрд▓ рдореЗрд╕рд┐рдирдорд╛ рдордирдорд╛рдиреА рд╕рдлреНрдЯрд╡реЗрдпрд░ рд╕реНрдерд╛рдкрдирд╛ рдЧрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрди рднрдиреНрдиреЗ рддрдереНрдпрдХреЛ рдмрд╛рд╡рдЬреБрдж, рдореИрд▓реЗ рдбрдХрд░ рдХрдиреНрдЯреЗрдирд░ рдердкреЗрдХреЛ рдЫреИрдиред рд╣рд╛рдореА Azure DevOps рдХреЛ рд╡рд┐рд╕реНрддрд╛рд░рдХреЛ рд░реВрдкрдорд╛ Chocolatey рдердкреНрди рд╕рдХреНрдЫреМрдВред рдпреЛ рдЧрд░реНрдирдХреЛ рд▓рд╛рдЧрд┐, рдЬрд╛рдФрдВ
рдпрд╣рд╛рдБ рддрдкрд╛рдИрдБрд▓реЗ рд╣рд╛рдореА рд╡рд┐рд╕реНрддрд╛рд░ рдердкреНрдиреЗ рдард╛рдЙрдБ рдЪрдпрди рдЧрд░реНрди рдЖрд╡рд╢реНрдпрдХ рдЫ рд░ рдмрдЯрди рдХреНрд▓рд┐рдХ рдЧрд░реНрдиреБрд╣реЛрд╕реН рд╕реНрдерд╛рдкрдирд╛.
рд╕рдлрд▓ рд╕реНрдерд╛рдкрдирд╛ рдкрдЫрд┐, рдХреНрд▓рд┐рдХ рдЧрд░реНрдиреБрд╣реЛрд╕реН рд╕рдВрдЧрдардирдорд╛ рдЕрдЧрд╛рдбрд┐ рдмрдвреНрдиреБрд╣реЛрд╕реН:
рддрдкрд╛рдИрдВрд▓реЗ рдЕрдм рд╕рдЮреНрдЭреНрдпрд╛рд▓рдорд╛ Chocolatey рдХрд╛рд░реНрдпрдХреЛ рд▓рд╛рдЧрд┐ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рд╣реЗрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫ рдХрд╛рд░реНрдпрд╣рд░реВ рдХрдиреНрдлрд┐рдЧрд░реЗрд╕рди рдлрд╛рдЗрд▓ рд╕рдореНрдкрд╛рджрди рдЧрд░реНрджрд╛ azure-pipelines.yml:
Chocolatey рдорд╛ рдХреНрд▓рд┐рдХ рдЧрд░реНрдиреБрд╣реЛрд╕реН рд░ рдХреНрд╖реЗрддреНрд░рд╣рд░реВрдХреЛ рд╕реВрдЪреА рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН:
рдпрд╣рд╛рдБ рд╣рд╛рдореАрд▓реЗ рдЪрдпрди рдЧрд░реНрди рдЖрд╡рд╢реНрдпрдХ рдЫ рд╕реНрдерд╛рдкрд┐рдд рдЧрд░реНрдиреБрд╣реЛрд╕реН рдЯреЛрд▓реАрд╣рд░реВрд╕рдБрдЧ рдореИрджрд╛рдирдорд╛ред IN Nuspec рдлрд╛рдЗрд▓ рдирд╛рдо рдЖрд╡рд╢реНрдпрдХ рдкреНрдпрд╛рдХреЗрдЬрдХреЛ рдирд╛рдо рд╕рдВрдХреЗрдд рдЧрд░реНрдиреБрд╣реЛрд╕реН - pvs-studioред рдпрджрд┐ рддрдкрд╛рдИрдВрд▓реЗ рд╕рдВрд╕реНрдХрд░рдг рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЧрд░реНрдиреБрднрдПрди рднрдиреЗ, рдирд╡реАрдирддрдо рд╕реНрдерд╛рдкрдирд╛ рд╣реБрдиреЗрдЫ, рдЬреБрди рд╣рд╛рдореАрд▓рд╛рдИ рдкреВрд░реНрдг рд░реВрдкрдорд╛ рдЙрдкрдпреБрдХреНрдд рдЫред рдмрдЯрди рдерд┐рдЪреМрдВ рдердк рд░ рд╣рд╛рдореА рдХрдиреНрдлрд┐рдЧрд░реЗрд╕рди рдлрд╛рдЗрд▓рдорд╛ рдЙрддреНрдкрдиреНрди рдХрд╛рд░реНрдп рджреЗрдЦреНрдиреЗрдЫреМрдВред
steps:
- task: ChocolateyCommand@0
inputs:
command: 'install'
installPackageId: 'pvs-studio'
рдЕрд░реНрдХреЛ, рд╣рд╛рдореНрд░реЛ рдлрд╛рдЗрд▓рдХреЛ рдореБрдЦреНрдп рднрд╛рдЧрдорд╛ рдЬрд╛рдиреБрд╣реЛрд╕реН:
- task: CmdLine@2
inputs:
script:
рдЕрдм рд╣рд╛рдореАрд▓реЗ рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рд▓рд╛рдЗрд╕реЗрдиреНрд╕рдХреЛ рд╕рд╛рде рдлрд╛рдЗрд▓ рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрди рдЖрд╡рд╢реНрдпрдХ рдЫред рдпрд╣рд╛рдБ PVSNAME ╨╕ PVSKEY - рдЪрд░рд╣рд░реВрдХреЛ рдирд╛рдо рдЬрд╕рдХреЛ рдорд╛рдирд╣рд░реВ рд╣рд╛рдореАрд▓реЗ рд╕реЗрдЯрд┐рдЩрд╣рд░реВрдорд╛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЧрд░реНрдЫреМрдВред рддрд┐рдиреАрд╣рд░реВрд▓реЗ PVS-рд╕реНрдЯреБрдбрд┐рдпреЛ рд▓рдЧрдЗрди рд░ рдЗрдЬрд╛рдЬрддрдкрддреНрд░ рдХреБрдЮреНрдЬреА рднрдгреНрдбрд╛рд░рдг рдЧрд░реНрдиреЗрдЫрдиреНред рддрд┐рдиреАрд╣рд░реВрдХреЛ рдорд╛рдирд╣рд░реВ рд╕реЗрдЯ рдЧрд░реНрди, рдореЗрдиреБ рдЦреЛрд▓реНрдиреБрд╣реЛрд╕реН рдЪрд░->рдирдпрд╛рдБ рдЪрд░ред рдЪрд░ рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реМрдВ PVSNAME рд▓рдЧрдЗрди рд░ PVSKEY рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдХреБрдЮреНрдЬреАрдХреЛ рд▓рд╛рдЧрд┐ред рдмрдХреНрд╕ рдЬрд╛рдБрдЪ рдЧрд░реНрди рдирдмрд┐рд░реНрд╕рдиреБрд╣реЛрд╕реН рдпреЛ рдореВрд▓реНрдп рдЧреЛрдкреНрдп рд░рд╛рдЦреНрдиреБрд╣реЛрд╕реН рд▓рд╛рдЧрд┐ PVSKEYред рдЖрджреЗрд╢ рдХреЛрдб:
╤Бall "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe" credentials
тАУu $(PVSNAME) тАУn $(PVSKEY)
рднрдгреНрдбрд╛рд░рдорд╛ рдЕрд╡рд╕реНрдерд┐рдд рдмреНрдпрд╛рдЯ рдлрд╛рдЗрд▓ рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдирд┐рд░реНрдорд╛рдг рдЧрд░реМрдВ:
╤Бall build.bat
рдПрдЙрдЯрд╛ рдлреЛрд▓реНрдбрд░ рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реМрдВ рдЬрд╣рд╛рдБ рд╡рд┐рд╢реНрд▓реЗрд╖рдХрдХреЛ рдирддрд┐рдЬрд╛рд╣рд░реВ рднрдПрдХрд╛ рдлрд╛рдЗрд▓рд╣рд░реВ рднрдгреНрдбрд╛рд░ рдЧрд░рд┐рдиреЗрдЫрдиреН:
╤Бall mkdir PVSTestResults
рдкрд░рд┐рдпреЛрдЬрдирд╛рдХреЛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рд╕реБрд░реБ рдЧрд░реМрдВ:
╤Бall "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
тАУt .srcchocolatey.sln тАУo .PVSTestResultsChoco.plog
рд╣рд╛рдореАрд▓реЗ рд╣рд╛рдореНрд░реЛ рд░рд┐рдкреЛрд░реНрдЯрд▓рд╛рдИ PlogSonverter рдЙрдкрдпреЛрдЧрд┐рддрд╛ рдкреНрд░рдпреЛрдЧ рдЧрд░реЗрд░ html рдврд╛рдБрдЪрд╛рдорд╛ рд░реВрдкрд╛рдиреНрддрд░рдг рдЧрд░реНрдЫреМрдВ:
╤Бall "C:Program Files (x86)PVS-StudioPlogConverter.exe"
тАУt html тАУo PVSTestResults .PVSTestResultsChoco.plog
рдЕрдм рддрдкрд╛рдИрдВрд▓реЗ рдПрдЙрдЯрд╛ рдХрд╛рд░реНрдп рд╕рд┐рд░реНрдЬрдирд╛ рдЧрд░реНрди рдЖрд╡рд╢реНрдпрдХ рдЫ рддрд╛рдХрд┐ рддрдкрд╛рдИрдВ рд░рд┐рдкреЛрд░реНрдЯ рдЕрдкрд▓реЛрдб рдЧрд░реНрди рд╕рдХреНрдиреБрд╣реБрдиреНрдЫред
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: PVSTestResults
artifactName: PVSTestResults
condition: always()
рдкреВрд░реНрдг рдХрдиреНрдлрд┐рдЧрд░реЗрд╕рди рдлрд╛рдЗрд▓ рдпрд╕реНрддреЛ рджреЗрдЦрд┐рдиреНрдЫ:
trigger:
- master
pool:
vmImage: 'windows-latest'
steps:
- task: ChocolateyCommand@0
inputs:
command: 'install'
installPackageId: 'pvs-studio'
- task: CmdLine@2
inputs:
script: |
call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
credentials тАУu $(PVSNAME) тАУn $(PVSKEY)
call build.bat
call mkdir PVSTestResults
call "C:Program Files (x86)PVS-StudioPVS-Studio_Cmd.exe"
тАУt .srcchocolatey.sln тАУo .PVSTestResultsChoco.plog
call "C:Program Files (x86)PVS-StudioPlogConverter.exe"
тАУt html тАУo .PVSTestResults .PVSTestResultsChoco.plog
- task: PublishBuildArtifacts@1
inputs:
pathToPublish: PVSTestResults
artifactName: PVSTestResults
condition: always()
рдХреНрд▓рд┐рдХ рдЧрд░реМрдВ Save->Save->Run рдХрд╛рд░реНрдп рд╕рдЮреНрдЪрд╛рд▓рди рдЧрд░реНрдиред рдХрд╛рд░реНрдпрд╣рд░реВ рдЯреНрдпрд╛рдмрдорд╛ рдЧрдПрд░ рд░рд┐рдкреЛрд░реНрдЯ рдбрд╛рдЙрдирд▓реЛрдб рдЧрд░реМрдВред
Chocolatey рдкрд░рд┐рдпреЛрдЬрдирд╛рд▓реЗ C# рдХреЛрдбрдХреЛ 37615 рд▓рд╛рдЗрдирд╣рд░реВ рдорд╛рддреНрд░ рд╕рдорд╛рд╡реЗрд╢ рдЧрд░реНрджрдЫред рдлреЗрд▓рд╛ рдкрд░реЗрдХрд╛ рдХреЗрд╣реА рддреНрд░реБрдЯрд┐рд╣рд░реВ рд╣реЗрд░реМрдВред
рдкрд░реАрдХреНрд╖рдг рдкрд░рд┐рдгрд╛рдорд╣рд░реВ
рдЪреЗрддрд╛рд╡рдиреА N1
рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЪреЗрддрд╛рд╡рдиреА:
public abstract class CrytpoHashProviderSpecsBase : TinySpec
{
....
protected CryptoHashProvider Provider;
....
public override void Context()
{
Provider = Provider = new CryptoHashProvider(FileSystem.Object);
}
}
рд╡рд┐рд╢реНрд▓реЗрд╖рдХрд▓реЗ рдЪрд░рдХреЛ рдПрдХ рдЕрд╕рд╛рдЗрдирдореЗрдиреНрдЯ рдкрддреНрддрд╛ рд▓рдЧрд╛рдпреЛ, рдЬреБрди рдЕрд░реНрде рдЫреИрдиред рд╕рдореНрднрд╡рддрдГ, рдпреА рдЪрд░рд╣рд░реВ рдордзреНрдпреЗ рдПрдЙрдЯрд╛рдХреЛ рдард╛рдЙрдБрдорд╛ рддреНрдпрд╣рд╛рдБ рдЕрд░реНрдХреЛ рдПрдЙрдЯрд╛ рд╣реБрдиреБрдкрд░реНрдЫред рдареАрдХ рдЫ, рд╡рд╛ рдпреЛ рдПрдХ рдЯрд╛рдЗрдкреЛ рд╣реЛ, рд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдЕрд╕рд╛рдЗрдирдореЗрдиреНрдЯ рд╕рдЬрд┐рд▓реИ рд╣рдЯрд╛рдЙрди рд╕рдХрд┐рдиреНрдЫред
рдЪреЗрддрд╛рд╡рдиреА N2
рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЪреЗрддрд╛рд╡рдиреА:
public static PlatformType get_platform()
{
switch (Environment.OSVersion.Platform)
{
case PlatformID.MacOSX:
{
....
}
case PlatformID.Unix:
if(file_system.directory_exists("/Applications")
& file_system.directory_exists("/System")
& file_system.directory_exists("/Users")
& file_system.directory_exists("/Volumes"))
{
return PlatformType.Mac;
}
else
return PlatformType.Linux;
default:
return PlatformType.Windows;
}
}
рдЕрдкрд░реЗрдЯрд░ рднрд┐рдиреНрдирддрд╛ & рдЕрдкрд░реЗрдЯрд░рдмрд╛рдЯ && рдпрджрд┐ рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдХреЛ рдмрд╛рдпрд╛рдБ рддрд░реНрдл рд╣реЛ рднрдиреЗ рдЭреВрдЯрд╛, рддреНрдпрд╕рдкрдЫрд┐ рджрд╛рдпрд╛рдБ рдкрдХреНрд╖ рдЕрдЭреИ рдкрдирд┐ рдЧрдгрдирд╛ рдЧрд░рд┐рдиреЗрдЫ, рдЬреБрди рдпрд╕ рдЕрд╡рд╕реНрдерд╛рдорд╛ рдЕрдирд╛рд╡рд╢реНрдпрдХ рд╡рд┐рдзрд┐ рдХрд▓рд╣рд░реВ рд╕рдВрдХреЗрдд рдЧрд░реНрджрдЫ system.directory_exists.
рд╡рд┐рдЪрд╛рд░ рдЧрд░рд┐рдПрдХреЛ рдЯреБрдХреНрд░рд╛рдорд╛, рдпреЛ рд╕рд╛рдиреЛ рддреНрд░реБрдЯрд┐ рд╣реЛред рд╣реЛ, рдпрд╕ рдЕрд╡рд╕реНрдерд╛рд▓рд╛рдИ && рдЕрдкрд░реЗрдЯрд░рд╕рдБрдЧ & рдЕрдкрд░реЗрдЯрд░ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрди рдЧрд░реЗрд░ рдЕрдиреБрдХреВрд▓рд┐рдд рдЧрд░реНрди рд╕рдХрд┐рдиреНрдЫ, рддрд░ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рджреГрд╖реНрдЯрд┐рдХреЛрдгрдмрд╛рдЯ, рдпрд╕рд▓реЗ рдХреБрдиреИ рдкрдирд┐ рдХреБрд░рд╛рд▓рд╛рдИ рдЕрд╕рд░ рдЧрд░реНрджреИрдиред рдпрджреНрдпрдкрд┐, рдЕрдиреНрдп рдЕрд╡рд╕реНрдерд╛рдорд╛, & рд░ && рдмреАрдЪрдХреЛ рднреНрд░рдорд▓реЗ рдЧрдореНрднреАрд░ рд╕рдорд╕реНрдпрд╛рд╣рд░реВ рдирд┐рдореНрддреНрдпрд╛рдЙрди рд╕рдХреНрдЫ рдЬрдм рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐рдХреЛ рджрд╛рдпрд╛рдБ рдкрдХреНрд╖рд▓рд╛рдИ рдЧрд▓рдд/рдЕрдорд╛рдиреНрдп рдорд╛рдирд╣рд░реВрд╕рдБрдЧ рд╡реНрдпрд╡рд╣рд╛рд░ рдЧрд░рд┐рдиреНрдЫред рдЙрджрд╛рд╣рд░рдг рдХреЛ рд▓рд╛рдЧреА, рд╣рд╛рдореНрд░реЛ рддреНрд░реБрдЯрд┐ рд╕рдВрдЧреНрд░рд╣ рдорд╛,
if ((k < nct) & (s[k] != 0.0))
рд╕реВрдЪрдХрд╛рдВрдХ рднрдП рдкрдирд┐ k рдЧрд▓рдд рдЫ, рдпреЛ array рддрддреНрд╡ рдкрд╣реБрдБрдЪ рдЧрд░реНрди рдкреНрд░рдпреЛрдЧ рдЧрд░рд┐рдиреЗрдЫред рдирддрд┐рдЬрд╛рдХреЛ рд░реВрдкрдорд╛, рдПрдХ рдЕрдкрд╡рд╛рдж рдлреНрдпрд╛рдБрдХрд┐рдиреЗрдЫ IndexOutOfRangeException.
рдЪреЗрддрд╛рд╡рдиреА N3, N4
рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЪреЗрддрд╛рд╡рдиреА:
рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЪреЗрддрд╛рд╡рдиреА:
public static string
prompt_for_confirmation(.... bool shortPrompt = false, ....)
{
....
if (shortPrompt)
{
var choicePrompt = choice.is_equal_to(defaultChoice) //1
?
shortPrompt //2
?
"[[{0}]{1}]".format_with(choice.Substring(0, 1).ToUpperInvariant(), //3
choice.Substring(1,choice.Length - 1))
:
"[{0}]".format_with(choice.ToUpperInvariant()) //0
:
shortPrompt //4
?
"[{0}]{1}".format_with(choice.Substring(0,1).ToUpperInvariant(), //5
choice.Substring(1,choice.Length - 1))
:
choice; //0
....
}
....
}
рдпрд╕ рдЕрд╡рд╕реНрдерд╛рдорд╛, рддрд┐рд░рдВрдЧреА рдЕрдкрд░реЗрдЯрд░ рдХреЛ рд╕рдЮреНрдЪрд╛рд▓рди рдкрдЫрд┐ рдПрдХ рдЕрдЬреАрдм рддрд░реНрдХ рдЫред рдирдЬрд┐рдХрдмрд╛рдЯ рд╣реЗрд░реМрдВ: рдпрджрд┐ рдореИрд▓реЗ рдирдореНрдмрд░ рез рдорд╛ рдЪрд┐рдиреНрд╣ рд▓рдЧрд╛рдПрдХреЛ рд╕рд░реНрдд рдкреВрд░рд╛ рднрдпреЛ рднрдиреЗ, рд╣рд╛рдореА рд╕рд░реНрдд реи рдорд╛ рдЬрд╛рдиреНрдЫреМрдВ, рдЬреБрди рд╕рдзреИрдВ рд╣реБрдиреНрдЫред рд╕рд╛рдБрдЪреЛ, рдЬрд╕рдХреЛ рдорддрд▓рдм рд▓рд╛рдЗрди 3 рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реБрдиреЗрдЫред рдпрджрд┐ рд╕рд░реНрдд 1 рдЧрд▓рдд рд╣реЛ рднрдиреЗ, рддреНрдпрд╕рдкрдЫрд┐ рд╣рд╛рдореА рдирдореНрдмрд░ 4 рдорд╛ рдЪрд┐рдиреНрд╣ рд▓рдЧрд╛рдЗрдПрдХреЛ рд▓рд╛рдЗрдирдорд╛ рдЬрд╛рдиреЗрдЫреМрдВ, рдЬреБрди рд╕рд░реНрдд рдкрдирд┐ рд╕рдзреИрдВ рд╣реБрдиреНрдЫред рд╕рд╛рдБрдЪреЛ, рдЬрд╕рдХреЛ рдорддрд▓рдм рдкрдЩреНрдХреНрддрд┐ 5 рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реБрдиреЗрдЫред рдпрд╕рд░реА, рдЯрд┐рдкреНрдкрдгреА 0 рдорд╛ рдЪрд┐рдиреНрд╣ рд▓рдЧрд╛рдЗрдПрдХрд╛ рд╕рд░реНрддрд╣рд░реВ рдХрд╣рд┐рд▓реНрдпреИ рдкреВрд░рд╛ рд╣реБрдиреЗ рдЫреИрдирдиреН, рдЬреБрди рдкреНрд░реЛрдЧреНрд░рд╛рдорд░рд▓реЗ рдЕрдкреЗрдХреНрд╖рд╛ рдЧрд░реЗрдХреЛ рдХрд╛рд░реНрдпрдХреЛ рддрд░реНрдХ рдареАрдХ рдирд╣реБрди рд╕рдХреНрдЫред
рдЪреЗрддрд╛рд╡рдиреА N5
рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЪреЗрддрд╛рд╡рдиреА:
private static string GetArgumentName (...., string description)
{
string[] nameStart;
if (maxIndex == 1)
{
nameStart = new string[]{"{0:", "{"};
}
else
{
nameStart = new string[]{"{" + index + ":"};
}
for (int i = 0; i < nameStart.Length; ++i)
{
int start, j = 0;
do
{
start = description.IndexOf (nameStart [i], j);
}
while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);
....
return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
}
}
рдбрд╛рдпрдЧреНрдиреЛрд╕реНрдЯрд┐рдХрд▓реЗ рд▓рд╛рдЗрдирдХреЛ рд▓рд╛рдЧрд┐ рдХрд╛рдо рдЧрд░реНрдпреЛ:
while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false)
рдЪрд░ рджреЗрдЦрд┐ j рдорд╛рдерд┐рдХрд╛ рдХреЗрд╣реА рд░реЗрдЦрд╛рд╣рд░реВ рд╢реВрдиреНрдпрдорд╛ рдкреНрд░рд╛рд░рдореНрдн рдЧрд░рд┐рдПрдХреЛ рдЫ, рддрд┐рд░рдВрдЧреА рдЕрдкрд░реЗрдЯрд░рд▓реЗ рдорд╛рди рдлрд┐рд░реНрддрд╛ рдЧрд░реНрдиреЗрдЫ рдЭреВрдЯрд╛ред рдпрд╕ рдЕрд╡рд╕реНрдерд╛рдХреЛ рдХрд╛рд░рдг, рд▓реВрдкрдХреЛ рд╢рд░реАрд░ рдПрдХ рдкрдЯрдХ рдорд╛рддреНрд░ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реБрдиреЗрдЫред рдорд▓рд╛рдИ рд▓рд╛рдЧреНрдЫ рдХрд┐ рдХреЛрдбрдХреЛ рдпреЛ рдЯреБрдХреНрд░рд╛рд▓реЗ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░рд▓реЗ рдЪрд╛рд╣реЗрдХреЛ рд░реВрдкрдорд╛ рдХрд╛рдо рдЧрд░реНрджреИрдиред
рдЪреЗрддрд╛рд╡рдиреА N6
рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЪреЗрддрд╛рд╡рдиреА:
private void remove_nuget_cache_for_package(....)
{
if (!config.AllVersions && installedPackageVersions.Count > 1)
{
const string allVersionsChoice = "All versions";
if (installedPackageVersions.Count != 1)
{
choices.Add(allVersionsChoice);
}
....
}
....
}
рдпрд╣рд╛рдБ рдПрдЙрдЯрд╛ рдЕрдиреМрдареЛ рдиреЗрд╕реНрдЯреЗрдб рдЕрд╡рд╕реНрдерд╛ рдЫ: InstallPackageVersions.Count != 1рдЬреБрди рд╕рдзреИрдВ рд╣реБрдиреЗрдЫ рд╕рд╛рдБрдЪреЛред рдкреНрд░рд╛рдп: рдпрд╕реНрддреЛ рдЪреЗрддрд╛рд╡рдиреАрд▓реЗ рдХреЛрдбрдорд╛ рддрд╛рд░реНрдХрд┐рдХ рддреНрд░реБрдЯрд┐рд▓рд╛рдИ рд╕рдВрдХреЗрдд рдЧрд░реНрджрдЫ, рд░ рдЕрдиреНрдп рдЕрд╡рд╕реНрдерд╛рдорд╛ рдпрд╕рд▓реЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдЬрд╛рдБрдЪрд▓рд╛рдИ рд╕рдВрдХреЗрдд рдЧрд░реНрджрдЫред
рдЪреЗрддрд╛рд╡рдиреА N7
рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЪреЗрддрд╛рд╡рдиреА:
public static bool arguments_contain_sensitive_information(string
commandArguments)
{
return commandArguments.contains("-install-arguments-sensitive")
|| commandArguments.contains("-package-parameters-sensitive")
|| commandArguments.contains("apikey ")
|| commandArguments.contains("config ")
|| commandArguments.contains("push ")
|| commandArguments.contains("-p ")
|| commandArguments.contains("-p=")
|| commandArguments.contains("-password")
|| commandArguments.contains("-cp ")
|| commandArguments.contains("-cp=")
|| commandArguments.contains("-certpassword")
|| commandArguments.contains("-k ")
|| commandArguments.contains("-k=")
|| commandArguments.contains("-key ")
|| commandArguments.contains("-key=")
|| commandArguments.contains("-apikey")
|| commandArguments.contains("-api-key")
|| commandArguments.contains("-apikey")
|| commandArguments.contains("-api-key");
}
рдХреЛрдбрдХреЛ рдпреЛ рдЦрдгреНрдб рд▓реЗрдЦреНрдиреЗ рдкреНрд░реЛрдЧреНрд░рд╛рдорд░рд▓реЗ рдЕрдиреНрддрд┐рдо рджреБрдИ рд▓рд╛рдЗрдирд╣рд░реВ рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдЧрд░реЗрд░ рдЯрд╛рдБрд╕реНрдпреЛ рд░ рддрд┐рдиреАрд╣рд░реВрд▓рд╛рдИ рд╕рдореНрдкрд╛рджрди рдЧрд░реНрди рдмрд┐рд░реНрд╕рдиреБрднрдпреЛред рдпрд╕ рдХрд╛рд░рдг, рдЪрдХрд▓реЗрдЯ рдкреНрд░рдпреЛрдЧрдХрд░реНрддрд╛рд╣рд░реВрд▓реЗ рдкреНрдпрд╛рд░рд╛рдорд┐рдЯрд░ рд▓рд╛рдЧреВ рдЧрд░реНрди рдЕрд╕рдорд░реНрде рдерд┐рдП apikey рдХреЗрд╣реА рдердк рддрд░рд┐рдХрд╛рд╣рд░реВред рдорд╛рдерд┐рдХрд╛ рдкреНрдпрд╛рд░рд╛рдорд┐рдЯрд░рд╣рд░реВ рдЬрд╕реНрддреИ, рдо рдирд┐рдореНрди рд╡рд┐рдХрд▓реНрдкрд╣рд░реВ рдкреНрд░рд╕реНрддрд╛рд╡ рдЧрд░реНрди рд╕рдХреНрдЫреБ:
commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");
рдкреНрд░рддрд┐рд▓рд┐рдкрд┐ рдЯрд╛рдБрд╕реНрдиреЗ рддреНрд░реБрдЯрд┐рд╣рд░реВ рд╕реНрд░реЛрдд рдХреЛрдбрдХреЛ рдареВрд▓реЛ рдорд╛рддреНрд░рд╛рдХреЛ рд╕рд╛рде рдХреБрдиреИ рдкрдирд┐ рдкрд░рд┐рдпреЛрдЬрдирд╛рдорд╛ тАЛтАЛрдврд┐рд▓реЛ рд╡рд╛ рдкрдЫрд┐ рджреЗрдЦрд╛ рдкрд░реНрдиреЗ рдЙрдЪреНрдЪ рд╕рдореНрднрд╛рд╡рдирд╛ рд╣реБрдиреНрдЫ, рд░ рддрд┐рдиреАрд╣рд░реВрд╕рдБрдЧ рд▓рдбреНрдирдХреЛ рд▓рд╛рдЧрд┐ рдПрдХ рдЙрддреНрддрдо рдЙрдкрдХрд░рдг рд╕реНрдерд┐рд░ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рд╣реЛред
PS рд░ рд╕рдзреИрдВрдХреЛ рд░реВрдкрдорд╛, рдпреЛ рддреНрд░реБрдЯрд┐ рдмрд╣реБ-рд▓рд╛рдЗрди рдЕрд╡рд╕реНрдерд╛рдХреЛ рдЕрдиреНрддреНрдпрдорд╛ рджреЗрдЦрд╛ рдкрд░реНрджрдЫ :)ред рдкреНрд░рдХрд╛рд╢рди рд╣реЗрд░реНрдиреБрд╣реЛрд╕реН "
рдЪреЗрддрд╛рд╡рдиреА N8
рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдЪреЗрддрд╛рд╡рдиреА:
public virtual ConcurrentDictionary<string, PackageResult> get_outdated(....)
{
....
var pinnedPackageResult = outdatedPackages.GetOrAdd(
packageName,
new PackageResult(installedPackage,
_fileSystem.combine_paths(
ApplicationParameters.PackagesLocation,
installedPackage.Id)));
....
if ( installedPackage != null
&& !string.IsNullOrWhiteSpace(installedPackage.Version.SpecialVersion)
&& !config.UpgradeCommand.ExcludePrerelease)
{
....
}
....
}
рдХреНрд▓рд╛рд╕рд┐рдХ рдЧрд▓реНрддреА: рдкрд╣рд┐рд▓реЛ рд╡рд╕реНрддреБ рд╕реНрдерд╛рдкрдирд╛ рдкреНрдпрд╛рдХреЗрдЬ рдкреНрд░рдпреЛрдЧ рдЧрд░рд┐рдиреНрдЫ рд░ рддреНрдпрд╕рдкрдЫрд┐ рдЬрд╛рдБрдЪ рдЧрд░рд┐рдиреНрдЫ рд╢реВрдиреНрдпред рдпреЛ рдбрд╛рдпрдЧреНрдиреЛрд╕реНрдЯрд┐рдХрд▓реЗ рд╣рд╛рдореАрд▓рд╛рдИ рдХрд╛рд░реНрдпрдХреНрд░рдордорд╛ рджреБрдИ рдордзреНрдпреЗ рдПрдЙрдЯрд╛ рд╕рдорд╕реНрдпрд╛рдХреЛ рдмрд╛рд░реЗрдорд╛ рдмрддрд╛рдЙрдБрдЫ: рдпрд╛ рдд рд╕реНрдерд╛рдкрдирд╛ рдкреНрдпрд╛рдХреЗрдЬ рдХрд╣рд┐рд▓реНрдпреИ рдмрд░рд╛рдмрд░ рд╢реВрдиреНрдп, рдЬреБрди рд╢рдВрдХрд╛рд╕реНрдкрдж рдЫ, рд░ рддреНрдпрд╕рдкрдЫрд┐ рдЪреЗрдХ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдЫ, рд╡рд╛ рд╣рд╛рдореАрд▓реЗ рд╕рдореНрднрд╛рд╡рд┐рдд рд░реВрдкрдорд╛ рдХреЛрдбрдорд╛ рдЧрдореНрднреАрд░ рддреНрд░реБрдЯрд┐ рдкреНрд░рд╛рдкреНрдд рдЧрд░реНрди рд╕рдХреНрдЫреМрдВ - рдПрдХ рд╢реВрдиреНрдп рд╕рдиреНрджрд░реНрдн рдкрд╣реБрдБрдЪ рдЧрд░реНрдиреЗ рдкреНрд░рдпрд╛рд╕ред
рдирд┐рд╖реНрдХрд░реНрд╖рдорд╛
рддреНрдпрд╕реИрд▓реЗ рд╣рд╛рдореАрд▓реЗ рдЕрд░реНрдХреЛ рд╕рд╛рдиреЛ рдХрджрдо рдЪрд╛рд▓реЗрдХрд╛ рдЫреМрдВ - рдЕрдм PVS-Studio рдкреНрд░рдпреЛрдЧ рдЧрд░реНрди рдЕрдЭ рд╕рдЬрд┐рд▓реЛ рд░ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рднрдПрдХреЛ рдЫред рдо рдпреЛ рдкрдирд┐ рднрдиреНрди рдЪрд╛рд╣рдиреНрдЫреБ рдХрд┐ Chocolatey рдХреЛрдбрдорд╛ рддреНрд░реБрдЯрд┐рд╣рд░реВрдХреЛ рд╕рд╛рдиреЛ рд╕рдВрдЦреНрдпрд╛ рднрдПрдХреЛ рд░рд╛рдореНрд░реЛ рдкреНрдпрд╛рдХреЗрдЬ рдкреНрд░рдмрдиреНрдзрдХ рд╣реЛ, рдЬреБрди PVS-Studio рдкреНрд░рдпреЛрдЧ рдЧрд░реНрджрд╛ рдкрдирд┐ рдХрдо рд╣реБрди рд╕рдХреНрдЫред
рд╣рд╛рдореА рддрдкрд╛рдИрдВрд▓рд╛рдИ рдирд┐рдордиреНрддреНрд░рдгрд╛ рдЧрд░реНрджрдЫреМрдВ
PS
рдкреНрд░рдХрд╛рд╢рди рдЕрдШрд┐, рд╣рд╛рдореАрд▓реЗ рд▓реЗрдЦ рдЪрдХрд▓реЗрдЯ рд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛рд╣рд░реВрд▓рд╛рдИ рдкрдард╛рдпреМрдВ, рд░ рддрд┐рдиреАрд╣рд░реВрд▓реЗ рдпрд╕рд▓рд╛рдИ рд░рд╛рдореНрд░реЛрд╕рдБрдЧ рдкреНрд░рд╛рдкреНрдд рдЧрд░реЗред рд╣рд╛рдореАрд▓реЗ рдХреЗрд╣рд┐ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдлреЗрд▓рд╛ рдкрд╛рд░реЗрдиреМрдВ, рддрд░ рддрд┐рдиреАрд╣рд░реВрд▓реЗ, рдЙрджрд╛рд╣рд░рдгрдХрд╛ рд▓рд╛рдЧрд┐, рд╣рд╛рдореАрд▓реЗ "рдПрдкреАрдЖрдИ-рдХреБрдЮреНрдЬреА" рдХреБрдЮреНрдЬреАрд╕рдБрдЧ рд╕рдореНрдмрдиреНрдзрд┐рдд рдмрдЧ рдорди рдкрд░рд╛рдПред
рдпрджрд┐ рддрдкрд╛рдЗрдБ рдпреЛ рд▓реЗрдЦ рдЕрдВрдЧреНрд░реЗрдЬреА рдмреЛрд▓реНрдиреЗ рджрд░реНрд╢рдХрд╣рд░реВрд╕рдБрдЧ рд╕рд╛рдЭрд╛ рдЧрд░реНрди рдЪрд╛рд╣рдиреБрд╣реБрдиреНрдЫ рднрдиреЗ, рдХреГрдкрдпрд╛ рдЕрдиреБрд╡рд╛рдж рд▓рд┐рдЩреНрдХ рдкреНрд░рдпреЛрдЧ рдЧрд░реНрдиреБрд╣реЛрд╕реН: Vladislav Stolyarovред
рд╕реНрд░реЛрдд: www.habr.com