Π Π°Π±ΠΎΡ‚Π° с MS SQL ΠΎΡ‚ Powershell Π½Π° Linux

Π’Π°Π·ΠΈ статия Π΅ чисто практичСска ΠΈ Π΅ посвСтСна Π½Π° моята Ρ‚ΡŠΠΆΠ½Π° история

ΠŸΠΎΠ΄Π³ΠΎΡ‚Π²ΡΠΌ сС Π·Π° Zero Touch PROD Π·Π° RDS (MS SQL), Π·Π° ΠΊΠΎΠΉΡ‚ΠΎ всички Π½ΠΈ Π±Ρ€ΡŠΠΌΡ‡Π°Ρ…Π° Π² ΡƒΡˆΠΈΡ‚Π΅, Π½Π°ΠΏΡ€Π°Π²ΠΈΡ… прСзСнтация (POC - Proof Of Concept) Π½Π° автоматизацията: Π½Π°Π±ΠΎΡ€ ΠΎΡ‚ скриптовС Π½Π° powershell. Π‘Π»Π΅Π΄ прСзСнтацията, ΠΊΠΎΠ³Π°Ρ‚ΠΎ Π±ΡƒΡ€Π½ΠΈΡ‚Π΅, ΠΏΡ€ΠΎΠ΄ΡŠΠ»ΠΆΠΈΡ‚Π΅Π»Π½ΠΈ аплодисмСнти стихнаха, ΠΏΡ€Π΅Π²Ρ€ΡŠΡ‰Π°ΠΉΠΊΠΈ сС Π² нСпрСстанни аплодисмСнти, Ρ‚Π΅ ΠΌΠΈ ΠΊΠ°Π·Π°Ρ…Π° - всичко Ρ‚ΠΎΠ²Π° Π΅ Π΄ΠΎΠ±Ρ€Π΅, Π½ΠΎ само ΠΏΠΎ идСологичСски ΠΏΡ€ΠΈΡ‡ΠΈΠ½ΠΈ, всички наши Ρ€ΠΎΠ±ΠΈ Π½Π° ДТСнкинс работят Π½Π° Linux!

Π’ΡŠΠ·ΠΌΠΎΠΆΠ½ΠΎ Π»ΠΈ Π΅ Ρ‚ΠΎΠ²Π°? Π’Π·Π΅ΠΌΠ΅Ρ‚Π΅ Ρ‚Π°ΠΊΡŠΠ² Ρ‚ΠΎΠΏΡŠΠ», Π»Π°ΠΌΠΏΠΎΠ² DBA ΠΎΡ‚ ΠΏΠΎΠ΄ Windows ΠΈ Π³ΠΎ ΠΏΡŠΡ…Π½Π΅Ρ‚Π΅ Π² самата Ρ‚ΠΎΠΏΠ»ΠΈΠ½Π° Π½Π° powershell ΠΏΠΎΠ΄ Linux? Π’ΠΎΠ²Π° Π½Π΅ Π΅ Π»ΠΈ ТСстоко?

Π Π°Π±ΠΎΡ‚Π° с MS SQL ΠΎΡ‚ Powershell Π½Π° Linux
Π’Ρ€ΡΠ±Π²Π°ΡˆΠ΅ Π΄Π° сС потопя Π² Ρ‚Π°Π·ΠΈ странна комбинация ΠΎΡ‚ Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ. Π Π°Π·Π±ΠΈΡ€Π° сС, всичкитС ΠΌΠΈ Π½Π°Π΄ 30 скрипта спряха Π΄Π° работят. Π—Π° моя ΠΈΠ·Π½Π΅Π½Π°Π΄Π° успях Π΄Π° оправя всичко Π·Π° Π΅Π΄ΠΈΠ½ Ρ€Π°Π±ΠΎΡ‚Π΅Π½ Π΄Π΅Π½. Пиша ΠΏΠΎ Π³ΠΎΡ€Π΅Ρ‰ΠΈ слСди. И Ρ‚Π°ΠΊΠ°, ΠΊΠ°ΠΊΠ²ΠΈ ΠΊΠ»ΠΎΠΏΠΊΠΈ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° срСщнСтС, ΠΊΠΎΠ³Π°Ρ‚ΠΎ ΠΏΡ€Π΅Ρ…Π²ΡŠΡ€Π»ΡΡ‚Π΅ Powershell скриптовС ΠΎΡ‚ Windows към Linux?

sqlcmd срСщу Invoke-SqlCmd

НСка Π²ΠΈ напомня Π·Π° основната Ρ€Π°Π·Π»ΠΈΠΊΠ° ΠΌΠ΅ΠΆΠ΄Ρƒ тях. Π”ΠΎΠ±Ρ€Π°Ρ‚Π° стара ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠ° sqlcmd Π Π°Π±ΠΎΡ‚ΠΈ ΠΈ ΠΏΠΎΠ΄ Linux, с ΠΏΠΎΡ‡Ρ‚ΠΈ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ‡Π½Π° функционалност. ΠŸΡ€Π΅Π΄Π°Π²Π°ΠΌΠ΅ заявката Π·Π° изпълнСниС Π½Π° -Q, входния Ρ„Π°ΠΉΠ» ΠΊΠ°Ρ‚ΠΎ -i ΠΈ изходния ΠΊΠ°Ρ‚ΠΎ -o. Но ΠΈΠΌΠ΅Π½Π°Ρ‚Π° Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅Ρ‚Π΅, Ρ€Π°Π·Π±ΠΈΡ€Π° сС, са чувствитСлни към ΠΌΠ°Π»ΠΊΠΈ ΠΈ Π³Π»Π°Π²Π½ΠΈ Π±ΡƒΠΊΠ²ΠΈ. Ако ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ -i, Ρ‚ΠΎΠ³Π°Π²Π° във Ρ„Π°ΠΉΠ»Π° Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π² края:

GO
EXIT

Ако няма Π˜Π—Π₯ΠžΠ” Π² края, Ρ‚ΠΎΠ³Π°Π²Π° sqlcmd Ρ‰Π΅ ΠΏΡ€ΠΎΠ΄ΡŠΠ»ΠΆΠΈ Π΄Π° ΠΈΠ·Ρ‡Π°ΠΊΠ²Π° въвСТданС ΠΈ Π°ΠΊΠΎ ΠΏΡ€Π΅Π΄ΠΈ EXIT няма GO, Ρ‚ΠΎΠ³Π°Π²Π° послСдната ΠΊΠΎΠΌΠ°Π½Π΄Π° няма Π΄Π° Ρ€Π°Π±ΠΎΡ‚ΠΈ. Π˜Π·Ρ…ΠΎΠ΄Π½ΠΈΡΡ‚ Ρ„Π°ΠΉΠ» ΡΡŠΠ΄ΡŠΡ€ΠΆΠ° цСлия ΠΈΠ·Ρ…ΠΎΠ΄, сСлСкции, ΡΡŠΠΎΠ±Ρ‰Π΅Π½ΠΈΡ, ΠΏΠ΅Ρ‡Π°Ρ‚ ΠΈ Ρ‚.Π½.

Invoke-SqlCmd ΠΏΡ€ΠΎΠΈΠ·Π²Π΅ΠΆΠ΄Π° Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚Π° ΠΊΠ°Ρ‚ΠΎ DataSet, DataTables ΠΈΠ»ΠΈ DataRows. Π‘Π»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»Π½ΠΎ, Π°ΠΊΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΈΡ‚Π΅ Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚Π° ΠΎΡ‚ ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ ΠΈΠ·Π±ΠΎΡ€, ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ sqlcmd, слСд ΠΊΠ°Ρ‚ΠΎ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€Π° ΠΈΠ·Ρ…ΠΎΠ΄Π° си, Π΅ ΠΏΠΎΡ‡Ρ‚ΠΈ нСвъзмоТно Π΄Π° сС ΠΈΠ·Π²Π»Π΅Ρ‡Π΅ Π½Π΅Ρ‰ΠΎ слоТно: Π·Π° Ρ‚ΠΎΠ²Π° ΠΈΠΌΠ° ИзвикванС-SqlCmd. Но Ρ‚ΠΎΠ·ΠΈ ΠΎΡ‚Π±ΠΎΡ€ ΠΈΠΌΠ° ΠΈ свои собствСни шСги:

  • Ако ΠΏΡ€Π΅Ρ…Π²ΡŠΡ€Π»ΠΈΡ‚Π΅ Ρ„Π°ΠΉΠ» към нСя Ρ‡Ρ€Π΅Π· -Π’Ρ…ΠΎΠ΄Π΅Π½ Ρ„Π°ΠΉΠ», Π’ΠΎΠ³Π°Π²Π° EXIT Π½Π΅ Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ, освСн Ρ‚ΠΎΠ²Π° създава синтактична Π³Ρ€Π΅ΡˆΠΊΠ°
  • -Π˜Π·Ρ…ΠΎΠ΄Π½ΠΈΡ Ρ„Π°ΠΉΠ» Π½Π΅, ΠΊΠΎΠΌΠ°Π½Π΄Π°Ρ‚Π° Π²ΠΈ Π²Ρ€ΡŠΡ‰Π° Ρ€Π΅Π·ΡƒΠ»Ρ‚Π°Ρ‚Π° ΠΊΠ°Ρ‚ΠΎ ΠΎΠ±Π΅ΠΊΡ‚
  • Има Π΄Π²Π° синтаксиса Π·Π° ΡƒΠΊΠ°Π·Π²Π°Π½Π΅ Π½Π° ΡΡŠΡ€Π²ΡŠΡ€: -ServerInstance -ΠŸΠΎΡ‚Ρ€Π΅Π±ΠΈΡ‚Π΅Π»ΡΠΊΠΎ ΠΈΠΌΠ΅ -ΠŸΠ°Ρ€ΠΎΠ»Π° -Π‘Π°Π·Π° Π΄Π°Π½Π½ΠΈ ΠΈ Ρ‡Ρ€Π΅Π· -ConnectionString. ΠšΠΎΠ»ΠΊΠΎΡ‚ΠΎ ΠΈ Π΄Π° Π΅ странно, Π² ΠΏΡŠΡ€Π²ΠΈΡ случай Π½Π΅ Π΅ възмоТно Π΄Π° посочитС ΠΏΠΎΡ€Ρ‚, Ρ€Π°Π·Π»ΠΈΡ‡Π΅Π½ ΠΎΡ‚ 1433.
  • тСкстов ΠΈΠ·Ρ…ΠΎΠ΄, Ρ‚ΠΈΠΏ PRINT, ΠΊΠΎΠΉΡ‚ΠΎ просто сС β€žΡ…Π²Π°Ρ‰Π°β€œ sqlcmdΠ·Π° ИзвикванС-SqlCmd Π΅ ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ
  • И Π½Π°ΠΉ-Π²Π°ΠΆΠ½ΠΎΡ‚ΠΎ: Най-вСроятно Π²Π°ΡˆΠΈΡΡ‚ Linux няма Ρ‚Π°Π·ΠΈ ΠΊΠΎΠΌΠ°Π½Π΄Π°!

И Ρ‚ΠΎΠ²Π° Π΅ основният ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ. Π‘Π°ΠΌΠΎ ΠΏΡ€Π΅Π· ΠΌΠ°Ρ€Ρ‚ Ρ‚ΠΎΠ·ΠΈ cmdlet стана Π΄ΠΎΡΡ‚ΡŠΠΏΠ΅Π½ Π·Π° ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠΈ, Ρ€Π°Π·Π»ΠΈΡ‡Π½ΠΈ ΠΎΡ‚ Windows, ΠΈ Π½Π°ΠΉ-накрая ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π° ΠΏΡ€ΠΎΠ΄ΡŠΠ»ΠΆΠΈΠΌ Π½Π°ΠΏΡ€Π΅Π΄!

ΠŸΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΎ замСстванС

sqlcmd ΠΈΠΌΠ° замСстванС Π½Π° ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²Π° с ΠΏΠΎΠΌΠΎΡ‰Ρ‚Π° Π½Π° -v, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ Ρ‚Π°ΠΊΠ°:

# $conn содСрТит Π½Π°Ρ‡Π°Π»ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ sqlcmd
$cmd = $conn + " -i D:appsSlaveJobsKillSpid.sql -o killspid.res 
  -v spid =`"" + $spid + "`" -v age =`"" + $age + "`""
Invoke-Expression $cmd

Π’ SQL скрипта ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°ΠΌΠ΅ замСствания:

set @spid=$(spid)
set @age=$(age)

И Ρ‚Π°ΠΊΠ°, Π΅Ρ‚ΠΎ Π³ΠΎ. Π’ *nix замСстванията Π½Π° ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ Π½Π΅ работят... ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚ΡŠΡ€ -v ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€Π°Π½. U ИзвикванС-SqlCmd ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€Π°Π½ -ΠŸΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ. Π’ΡŠΠΏΡ€Π΅ΠΊΠΈ Ρ‡Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚ΡŠΡ€ΡŠΡ‚, ΠΊΠΎΠΉΡ‚ΠΎ ΡƒΠΊΠ°Π·Π²Π° самитС ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ, сС ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€Π°, самитС замСствания работят - ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄Π° ΠΈΠ·ΠΏΠΎΠ»Π·Π²Π°Ρ‚Π΅ всякакви ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈ ΠΎΡ‚ Shell. ΠžΠ±Π°Ρ‡Π΅ сС ΠΎΠ±ΠΈΠ΄ΠΈΡ… ΠΎΡ‚ ΠΏΡ€ΠΎΠΌΠ΅Π½Π»ΠΈΠ²ΠΈΡ‚Π΅ ΠΈ Ρ€Π΅ΡˆΠΈΡ… ΠΈΠ·ΠΎΠ±Ρ‰ΠΎ Π΄Π° Π½Π΅ завися ΠΎΡ‚ тях ΠΈ дСйствах Π³Ρ€ΡƒΠ±ΠΎ ΠΈ ΠΏΡ€ΠΈΠΌΠΈΡ‚ΠΈΠ²Π½ΠΎ, Ρ‚ΡŠΠΉ ΠΊΠ°Ρ‚ΠΎ SQL скриптовСтС са ΠΊΡ€Π°Ρ‚ΠΊΠΈ:

# prepend the parameters  
"declare @age int, @spid int" | Add-Content "q.sql"
"set @spid=" + $spid | Add-Content "q.sql"
"set @age=" + $age | Add-Content "q.sql"

foreach ($line in Get-Content "Sqlserver/Automation/KillSpid.sql") { 
  $line | Add-Content "q.sql" 
  }
$cmd = "/opt/mssql-tools/bin/" + $conn + " -i q.sql -o res.log"

Π’ΠΎΠ²Π°, ΠΊΠ°ΠΊΡ‚ΠΎ Ρ€Π°Π·Π±ΠΈΡ€Π°Ρ‚Π΅, Π΅ тСст Π²Π΅Ρ‡Π΅ ΠΎΡ‚ вСрсията Π½Π° Unix.

ΠšΠ°Ρ‡Π²Π°Π½Π΅ Π½Π° Ρ„Π°ΠΉΠ»ΠΎΠ²Π΅

Π’ΡŠΠ² вСрсията Π½Π° Windows всяка опСрация бСшС ΠΏΡ€ΠΈΠ΄Ρ€ΡƒΠΆΠ΅Π½Π° ΠΎΡ‚ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°: стартирахмС sqlcmd, ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ…ΠΌΠ΅ някаква Π·Π»ΠΎΡƒΠΏΠΎΡ‚Ρ€Π΅Π±Π° Π² изходния Ρ„Π°ΠΉΠ», ΠΏΡ€ΠΈΠΊΠ°Ρ‡ΠΈΡ…ΠΌΠ΅ Ρ‚ΠΎΠ·ΠΈ Ρ„Π°ΠΉΠ» към Ρ‚Π°Π±Π»ΠΎΡ‚ΠΎ Π·Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°. Π—Π° щастиС SQL ΡΡŠΡ€Π²ΡŠΡ€ΡŠΡ‚ Ρ€Π°Π±ΠΎΡ‚Π΅ΡˆΠ΅ Π½Π° ΡΡŠΡ‰ΠΈΡ ΡΡŠΡ€Π²ΡŠΡ€ ΠΊΠ°Ρ‚ΠΎ Jenkins, бСшС Π½Π°ΠΏΡ€Π°Π²Π΅Π½ΠΎ Π½Π΅Ρ‰ΠΎ ΠΏΠΎΠ΄ΠΎΠ±Π½ΠΎ:

CREATE procedure AuditUpload
  @id int, @filename varchar(256)
as
  set nocount on
  declare @sql varchar(max)

  CREATE TABLE #multi (filer NVARCHAR(MAX))
  set @sql='BULK INSERT #multi FROM '''+@filename
    +''' WITH (ROWTERMINATOR = '' '',CODEPAGE = ''ACP'')'
  exec (@sql)
  select @sql=filer from #multi
  update JenkinsAudit set multiliner=@sql where ID=@id
  return

По Ρ‚ΠΎΠ·ΠΈ Π½Π°Ρ‡ΠΈΠ½ Π½ΠΈΠ΅ ΠΏΠΎΠ³Π»ΡŠΡ‰Π°ΠΌΠ΅ BCP Ρ„Π°ΠΉΠ»Π° изцяло ΠΈ Π³ΠΎ ΠΏΡŠΡ…Π°ΠΌΠ΅ Π² ΠΏΠΎΠ»Π΅Ρ‚ΠΎ nvarchar(max) Π½Π° Ρ‚Π°Π±Π»ΠΈΡ†Π°Ρ‚Π° Π·Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ°. Π Π°Π·Π±ΠΈΡ€Π° сС, цялата Ρ‚Π°Π·ΠΈ систСма сС Ρ€Π°Π·ΠΏΠ°Π΄Π½Π°, Π·Π°Ρ‰ΠΎΡ‚ΠΎ вмСсто SQL ΡΡŠΡ€Π²ΡŠΡ€ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ… RDS, Π° BULK INSERT ΠΈΠ·ΠΎΠ±Ρ‰ΠΎ Π½Π΅ Ρ€Π°Π±ΠΎΡ‚ΠΈ Ρ‡Ρ€Π΅Π· UNC ΠΏΠΎΡ€Π°Π΄ΠΈ ΠΎΠΏΠΈΡ‚ Π·Π° Сксклузивно Π·Π°ΠΊΠ»ΡŽΡ‡Π²Π°Π½Π΅ Π½Π° Ρ„Π°ΠΉΠ», Π° с RDS Ρ‚ΠΎΠ²Π° ΠΎΠ±ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΎ Π΅ ΠΎΠ±Ρ€Π΅Ρ‡Π΅Π½ΠΎ самото Π½Π°Ρ‡Π°Π»ΠΎ. Π—Π°Ρ‚ΠΎΠ²Π° Ρ€Π΅ΡˆΠΈΡ… Π΄Π° промСня Π΄ΠΈΠ·Π°ΠΉΠ½Π° Π½Π° систСмата, ΡΡŠΡ…Ρ€Π°Π½ΡΠ²Π°ΠΉΠΊΠΈ ΠΎΠ΄ΠΈΡ‚Π° Ρ€Π΅Π΄ ΠΏΠΎ Ρ€Π΅Π΄:

CREATE TABLE AuditOut (
  ID int NULL,
  TextLine nvarchar(max) NULL,
  n int IDENTITY(1,1) PRIMARY KEY
  )

И Π½Π°ΠΏΠΈΡˆΠ΅Ρ‚Π΅ Π² Ρ‚Π°Π·ΠΈ Ρ‚Π°Π±Π»ΠΈΡ†Π° Ρ‚Π°ΠΊΠ°:

function WriteAudit([string]$Filename, [string]$ConnStr, 
     [string]$Tabname, [string]$Jobname)
{
  # get $lastid of the last execution  -- проскипано для ΡΡ‚Π°Ρ‚ΡŒΠΈ
	
  #create grid and populate it with data from file
  $audit =  Get-Content $Filename
  $DT = new-object Data.DataTable   

  $COL1 =  new-object Data.DataColumn; 
  $COL1.ColumnName = "ID"; 
  $COL1.DataType =  [System.Type]::GetType("System.Int32") 

  $COL2 =  new-object Data.DataColumn; 
  $COL2.ColumnName = "TextLine"; 
  $COL2.DataType =  [System.Type]::GetType("System.String") 
  
  $DT.Columns.Add($COL1) 
  $DT.Columns.Add($COL2) 
  foreach ($line in $audit) 
    { 
    $DR = $dt.NewRow()   
    $DR.Item("ID") = $lastid
    $DR.Item("TextLine") = $line
    $DT.Rows.Add($DR)   
    } 

  # write it to table
  $conn=new-object System.Data.SqlClient.SQLConnection 
  $conn.ConnectionString = $ConnStr
  $conn.Open() 
  $bulkCopy = new-object ("Data.SqlClient.SqlBulkCopy") $ConnStr
  $bulkCopy.DestinationTableName = $Tabname 
  $bulkCopy.BatchSize = 50000
  $bulkCopy.BulkCopyTimeout = 0
  $bulkCopy.WriteToServer($DT) 
  $conn.Close() 
  }  

Π—Π° Π΄Π° ΠΈΠ·Π±Π΅Ρ€Π΅Ρ‚Π΅ ΡΡŠΠ΄ΡŠΡ€ΠΆΠ°Π½ΠΈΠ΅, трябва Π΄Π° ΠΈΠ·Π±Π΅Ρ€Π΅Ρ‚Π΅ ΠΏΠΎ ID, ΠΊΠ°Ρ‚ΠΎ ΠΈΠ·Π±Π΅Ρ€Π΅Ρ‚Π΅ Π² Ρ€Π΅Π΄ n (идСнтичност).

Π’ слСдващата статия Ρ‰Π΅ Ρ€Π°Π·Π³Π»Π΅Π΄Π°ΠΌ ΠΏΠΎ-ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎ ΠΊΠ°ΠΊ всичко Ρ‚ΠΎΠ²Π° взаимодСйства с ДТСнкинс.

Π˜Π·Ρ‚ΠΎΡ‡Π½ΠΈΠΊ: www.habr.com

ДобавянС Π½Π° Π½ΠΎΠ² ΠΊΠΎΠΌΠ΅Π½Ρ‚Π°Ρ€