Что нового

Дополнительная проверка сбивает работу функции

DyadyaGenya

Новичок
Сообщения
106
Репутация
0
Доброго времени суток. Продолжаю мучать смарт диска. Что-то получается. Но столкнулся с очередной проблемой. Захотел сделать проверку на соответствие буквы диска диску, чтобы получать инфу по смарту в зависимости от буквы диска. Сама проверка работает. Создаю массив, в котором в одной строке буква и номер диска (название, идентификатор, вендор). В варианте без такой сортировки, только с массивом из списка вендоров, все работает, показывает смарт только тех дисков, которые имеют смарт (без учета nvme). В варианте с проверкой на букву диска происходит что-то типа сдвига на одну позицию, или возможно добавление позиции из промежуточного массива, где есть все диски, в том числе и те, у которых смарт не читается, например флэшки. И получается выводит инфу на один диск (букву) меньше.
Вот первый вариант без сортировки по буквам:
Код:
#include <Constants.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <GUIConstantsEx.au3>
#include <GUITab.au3>
#include <GUIListView.au3>
#include <GUIImageList.au3>
#include <String.au3>
#include <Array.au3>
#include <Math.au3>

;Opt("MustDeclareVars", 1)
Global    $sSMARTCodeTxt = "1*1*Raw Read Error Rate*Частота ошибок при чтении данных с диска;" & _
                        "2*2*Throughput Performance*Общая производительность диска.;" & _
                        "3*3*Spin-Up Time*Время раскрутки пакета дисков из состояния покоя до рабочей скорости.;" & _
                        "4*4*Start/Stop Count*Полное число циклов запуск-остановка шпинделя. В поле raw value хранится общее количество запусков/остановок диска;" & _
                        "5*5*Reallocated Sectors Count*Число операций переназначения секторов.;" & _
                        "6*6*Read Channel Margin*Запас канала чтения. Назначение этого атрибута не документировано. В современных накопителях не используется.;" & _
                        "7*7*Seek Error Rate*Частота ошибок при позиционировании блока магнитных головок.;" & _
                        "8*8*Seek Time Performance*Средняя производительность операции позиционирования магнитными головками.;" & _
                        "194*C2*HDA temperature*Температура. Здесь хранятся показания встроенного термодатчика для механической части диска — банки (HDA — Hard Disk Assembly).;" & _
                        "254*FE*Free Fall Protection*Защита от падения"


Const $wbemFlagReturnImmediately = 0x10
Const $wbemFlagForwardOnly = 0x20
Global $Index[0], $Smart[0][12]
Global $aArray = DriveGetDrive("ALL")
Global $sTemp, $sTemp231, $sTemp1, $i, $j, $p, $sPark, $Item[0]
Global $strVendorSpecific[0], $strVendorSpecificA[0], $Specific[0][12], $diskVendors[0][2], $Threshold[0], $ThresholdAll[0], $Threshold[0], $Porog[0]
Global $STR1[0][4]

$TTT = _StringExplode($sSMARTCodeTxt, ";")
ConsoleWrite('TTT  ' & UBound($TTT) & @CR)
;_ArrayDisplay($TTT, 'TTT')
For $s = 0 To UBound($TTT)-1
   _ArrayAdd($STR1, $TTT[$s], 0, "*")

Next

$objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\WMI")
$colItems = $objWMIService.ExecQuery("SELECT * FROM MSStorageDriver_ATAPISmartData", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
For $diskVendor In $colItems
                 ConsoleWrite ("InstanceName: " & $diskVendor.InstanceName&@CR)
                 ConsoleWrite ("InstanceNameFor: " & StringReplace($diskVendor.InstanceName, '\','\\') &@CR)
                 ;ConsoleWrite(Ubound($diskVendor) & @CR)
                 _ArrayAdd($diskVendors, $diskVendor.InstanceName &'|'&StringReplace($diskVendor.InstanceName, '\','\\'))

Next
_ArrayDisplay($diskVendors, 'массив вендоров')

ConsoleWrite('STR1  ' & UBound($STR1) & @CR)

For $zzzzz=0 To UBound($diskVendors)-1
   ConsoleWrite('Число вендоров        ' & UBound($diskVendors)-1 & @CR)
   ConsoleWrite('Перед вызовом функции    ' & $diskVendors[$zzzzz][1] & @CR)
_Smart($diskVendors[$zzzzz][1])
Next

Func _Smart($zzz)
   ConsoleWrite('Уже в функции        ' & $diskVendors[$zzzzz][1] & @CR)
            $colThreshold = $objWMIService.ExecQuery('SELECT * FROM MSStorageDriver_FailurePredictThresholds Where InstanceName="' & $zzz &'"', "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)

        For $objThreshold In $colThreshold
          $VendorSpecific2 = $objThreshold.VendorSpecific
         _arrayDisplay($VendorSpecific2,"$VendorSpecific2")
       ;   ConsoleWrite ("FailurePredictThresholds: " & _ArrayToString($VendorSpecific2,",")&@CR)
       Next

If IsObj($objThreshold) then
    For $zV = 2 to UBound($VendorSpecific2) - 1 Step 12
      _ArrayAdd($ThresholdAll, $VendorSpecific2[$zV])
   Next
;  _ArrayDisplay($ThresholdAll, 'Порог')
   For $j = 0 To UBound($STR1)-1
      For $zzV = 2 to UBound($VendorSpecific2) - 1 Step 12
Select
Case $VendorSpecific2[$zzV]=$STR1[$j][0]
   $Porog=$VendorSpecific2[$zzV+1]
   If StringStripWS($Porog, 8) <> '' Then _ArrayAdd($Threshold, $Porog)
;  ConsoleWrite($Porog)
   EndSelect

      Next
   Next
For $t = 0 To 30-UBound($Threshold)
   _ArrayAdd($Threshold, '0')
Next
  ; _ArrayDisplay($Threshold, 'Porog')
EndIf

$objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\WMI")
$colItems = $objWMIService.ExecQuery('SELECT * FROM MSStorageDriver_ATAPISmartData Where InstanceName="' & $zzz &'"', "WQL", 0x30)
       For $Item In $colItems
            $strVendorSpecific = $Item.VendorSpecific
  ;          _ArrayDisplay($strVendorSpecific,"Спецификация")
Next

   For $z = 2 to UBound($strVendorSpecific) - 1 Step 12
      $strSpecific = $strVendorSpecific[$z] & '|' & $strVendorSpecific[$z+1] & '|' & $strVendorSpecific[$z+2] & '|' & $strVendorSpecific[$z+3] & '|' & $strVendorSpecific[$z+4] & '|' & $strVendorSpecific[$z+5] & '|' & $strVendorSpecific[$z+6] & '|' & $strVendorSpecific[$z+7] & '|' & $strVendorSpecific[$z+8] & '|' & $strVendorSpecific[$z+9] & '|' & $strVendorSpecific[$z+10] & '|' & $strVendorSpecific[$z+11]
    ;  _ArrayAdd($kzz, $strVendorSpecific[$z])
      _ArrayAdd($Specific, $strSpecific)
   Next

  ; _ArrayDisplay($Specific, "массив спецификаций",  Default, '', Default, "ID|2|3|4|5|6|7|8|9|10|11|12")


Local $ks= UBound($STR1)-1

For $j = 0 To UBound($Specific)-1
   For $k = 0 To UBound($STR1)-1
   If Mod($Specific[$j][1],2) Then
      $p = 'Pre-Failure'
   Else
      $p = 'Advisory'
   EndIf
    Local $raw = ((((($Specific[$j][8] * 256 ) + $Specific[$j][7]) * 256) + $Specific[$j][6]) * 256) + $Specific[$j][5]
Select

Case $Specific[$j][0]=$STR1[$k][0]

   $sPark = $Specific[$j][0]& '|' & $STR1[$k][1]& '|' & $STR1[$k][2] & '|' & $p & '|' & $Specific[$j][1] & '|' & $Threshold[$j] & '|' & $Specific[$j][3] & '|' & $Specific[$j][4] & '|' & $Specific[$j][5] & '|' & $Specific[$j][6] & '|' & $raw
   If StringStripWS($sPark, 8) <> 0 Then _ArrayAdd($Smart, $sPark)

Case $Specific[$j][0] <> $STR1[$k][0]    And $k <> Mod($k, $ks) And $j <> UBound($Smart)-1

    $sPark = $Specific[$j][0]& '|' & '???' & '|' & 'Зарезервировано производителем' & '|' & $p & '|' & $Specific[$j][1] & '|' & $Threshold[$j] & '|' & $Specific[$j][3] & '|' & $Specific[$j][4] & '|' & $Specific[$j][5] & '|' & $Specific[$j][6] & '|' & $raw
   If StringStripWS($sPark, 8) <> 0 Then _ArrayAdd($Smart, $sPark)

Case Else
     $sPark=''
    ; ConsoleWrite('else  ' & $sPark & @CR)
EndSelect

   Next

;ConsoleWrite('aaaa  ' & $sPark & @CR)
   Next

;_ArrayDisplay($Smart, "Smart")
_ArrayDisplay($Smart, 'Smart', Default, '', Default, "ID|HEX|Attribute|Type|Flag|Threshold(Порог)|Текущее|Worst(Наихудший)|Значение|???|RAW|Status")
Global $Smart[0][12]
;Global $STR1[0][4]
Global $Specific[0][12]


EndFunc
Вот вариант с сортировкой по буквам:
Код:
#include <Constants.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>
#include <GUIConstantsEx.au3>
#include <GUITab.au3>
#include <GUIListView.au3>
#include <GUIImageList.au3>
#include <String.au3>
#include <Array.au3>
#include <Math.au3>

Global    $sSMARTCodeTxt = "1*1*Raw Read Error Rate*Частота ошибок при чтении данных с диска;" & _
                        "2*2*Throughput Performance*Общая производительность диска.;" & _
                        "3*3*Spin-Up Time*Время раскрутки пакета дисков из состояния покоя до рабочей скорости.;" & _
                        "4*4*Start/Stop Count*Полное число циклов запуск-остановка шпинделя. В поле raw value хранится общее количество запусков/остановок диска;" & _
                        "5*5*Reallocated Sectors Count*Число операций переназначения секторов.;" & _
                        "6*6*Read Channel Margin*Запас канала чтения. Назначение этого атрибута не документировано. В современных накопителях не используется.;" & _
                        "7*7*Seek Error Rate*Частота ошибок при позиционировании блока магнитных головок.;" & _
                        "8*8*Seek Time Performance*Средняя производительность операции позиционирования магнитными головками.;" & _
                        "194*C2*HDA temperature*Температура. Здесь хранятся показания встроенного термодатчика для механической части диска — банки (HDA — Hard Disk Assembly).;" & _
                        "254*FE*Free Fall Protection*Защита от падения"

Const $wbemFlagReturnImmediately = 0x10
Const $wbemFlagForwardOnly = 0x20
Global $Index[0], $Smart[0][12]
Global $aArray = DriveGetDrive("ALL")
Global $sTemp, $sTemp231, $sTemp1, $i, $j, $p, $sPark, $Item[0]
Global $strVendorSpecific[0], $strVendorSpecificA[0], $Specific[0][12], $diskVendors[0][2], $Threshold[0], $ThresholdAll[0], $Threshold[0], $Porog[0]
Global $STR1[0][4]
Global $DiskLeter[0][4]

Global $DiskPartArray[0], $DiskVendorArray[0], $deviceArray[0]
Global $DiskLeter[0][4], $LetterVendor[0][5]

$TTT = _StringExplode($sSMARTCodeTxt, ";")
ConsoleWrite('TTT  ' & UBound($TTT) & @CR)
;_ArrayDisplay($TTT, 'TTT')
For $s = 0 To UBound($TTT)-1
   _ArrayAdd($STR1, $TTT[$s], 0, "*")

Next
;Начало проблемного кода.
$objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\WMI")
$colItemsVendor = $objWMIService.ExecQuery("SELECT * FROM MSStorageDriver_ATAPISmartData", "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
For $diskVendor In $colItemsVendor
   ConsoleWrite($diskVendor.InstanceName & @CR)
   $disk = $diskVendor.InstanceName
   _ArrayAdd($DiskVendorArray, $disk)

Next
_ArrayDisplay($DiskVendorArray, 'массив вендоров')

$objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\cimv2")
$colDiskDrives = $objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive")

For $objDrive In $colDiskDrives

    ConsoleWrite(@CR & "Физический диск: " & $objDrive.Caption & " — " & $objDrive.DeviceID & @CR)
    ;ConsoleWrite("буква диска: " & $objDrive.Caption & " — " & $objDrive.DeviceID & @CR)

    $strDeviceID = StringReplace($objDrive.DeviceID, "\", "\\")
    ConsoleWrite('dev id  ' & $strDeviceID &  @CR)
    $colPartitions = $objWMIService.ExecQuery("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & $strDeviceID & """} WHERE AssocClass = " & "Win32_DiskDriveToDiskPartition")
ConsoleWrite('проверка $colPartitions  ' & $colPartitions & '  aaa' & @CR)
    For $objPartition In $colPartitions
        ConsoleWrite("Диск Partition: " & $objPartition.DeviceID & @CR)
    ;        ConsoleWrite('айди:  ' & $objDrive.PNPDeviceID &@CR)
       $colLogicalDisks = $objWMIService.ExecQuery("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & $objPartition.DeviceID & """} WHERE AssocClass = " & "Win32_LogicalDiskToPartition")

        For $objLogicalDisk In $colLogicalDisks
            ConsoleWrite("Logical Disk: " & $objLogicalDisk.DeviceID & "  Disk Partition: " & $objPartition.DeviceID & '  ' & $objDrive.PNPDeviceID & '  ' & StringReplace($objDrive.PNPDeviceID, '\','\\') & '  ' & @CR)
$Leter = $objLogicalDisk.DeviceID  & '|' & $objPartition.DeviceID  & '|' & $objDrive.PNPDeviceID  & '|' & StringReplace($objDrive.PNPDeviceID, '\','\\')
_ArrayAdd($DiskLeter, $Leter)
        Next
       ; ConsoleWrite($objLogicalDisk & @CR)
    Next
    ;ConsoleWrite($objLogicalDisk & @CR)
Next
_ArrayDisplay($DiskLeter, 'Буквы диска', Default, '', Default, "1|2|3|4")

For $ds = 0 To UBound($DiskVendorArray)-1
   For $dd = 0 To UBound($DiskLeter)-1
                 If StringLeft($DiskVendorArray[$ds],StringLen($DiskLeter[$dd][2])) = String($DiskLeter[$dd][2]) then
                    ConsoleWrite('ravno   ' & $DiskLeter[$dd][2] & @CR)
                    $ravno = $DiskLeter[$dd][0] & '|' & $DiskLeter[$dd][1] & '|' & $DiskLeter[$dd][2] & '|' & $DiskVendorArray[$ds] & '|' & StringReplace($DiskVendorArray[$ds], '\','\\')

                    _ArrayAdd($LetterVendor, $ravno)
                 Else
                    ConsoleWrite('ne ravno   ' & $DiskVendorArray[$ds] & '  <>  ' & $DiskLeter[$dd][2] &@CR)
                 EndIf
              Next
           Next

_ArrayDisplay($LetterVendor, 'Буквы vendor', Default, '', Default, "1|2|3|4|5")


ConsoleWrite('STR1  ' & UBound($STR1) & @CR)
;Вызов функции, в которой происходит сбой
For $zzzzz=0 To UBound($LetterVendor)-1
   ConsoleWrite('Перед вызовом функции смарт   ' & $LetterVendor[$zzzzz][4] & @CR)
   _Smart($LetterVendor[$zzzzz][4])
Next

Func _Smart($zzz)
;  ConsoleWrite($diskVendors[$zzzzz][1] & @CR)
      ConsoleWrite('уже в функции:  ' & $zzz & @CR)
            $colThreshold = $objWMIService.ExecQuery('SELECT * FROM MSStorageDriver_FailurePredictThresholds Where InstanceName="' & $zzz &'"', "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
      For $objThreshold In $colThreshold
          $VendorSpecific2 = $objThreshold.VendorSpecific
         _arrayDisplay($VendorSpecific2,"$VendorSpecific2")
          ConsoleWrite ("FailurePredictThresholds: " & _ArrayToString($VendorSpecific2,",")&@CR)
      Next

If IsObj($objThreshold) then
    For $zV = 2 to UBound($VendorSpecific2) - 1 Step 12
      _ArrayAdd($ThresholdAll, $VendorSpecific2[$zV])
   Next
   _ArrayDisplay($ThresholdAll, 'Порог')
   For $j = 0 To UBound($STR1)-1
      For $zzV = 2 to UBound($VendorSpecific2) - 1 Step 12
Select
Case $VendorSpecific2[$zzV]=$STR1[$j][0]
   $Porog=$VendorSpecific2[$zzV+1]
   If StringStripWS($Porog, 8) <> '' Then _ArrayAdd($Threshold, $Porog)
;  ConsoleWrite($Porog)
   EndSelect

Next
Next
For $t = 0 To 30-UBound($Threshold)
   _ArrayAdd($Threshold, '0')
Next
  ; _ArrayDisplay($Threshold, 'Porog')
EndIf

$objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\WMI")
$colItems = $objWMIService.ExecQuery('SELECT * FROM MSStorageDriver_ATAPISmartData Where InstanceName="' & $zzz &'"', "WQL", $wbemFlagReturnImmediately + $wbemFlagForwardOnly)
       For $Item In $colItems
            $strVendorSpecific = $Item.VendorSpecific
  ;          _ArrayDisplay($strVendorSpecific,"Спецификация")
Next

   For $z = 2 to UBound($strVendorSpecific) - 1 Step 12
      $strSpecific = $strVendorSpecific[$z] & '|' & $strVendorSpecific[$z+1] & '|' & $strVendorSpecific[$z+2] & '|' & $strVendorSpecific[$z+3] & '|' & $strVendorSpecific[$z+4] & '|' & $strVendorSpecific[$z+5] & '|' & $strVendorSpecific[$z+6] & '|' & $strVendorSpecific[$z+7] & '|' & $strVendorSpecific[$z+8] & '|' & $strVendorSpecific[$z+9] & '|' & $strVendorSpecific[$z+10] & '|' & $strVendorSpecific[$z+11]
      _ArrayAdd($Specific, $strSpecific)
   Next

  ; _ArrayDisplay($Specific, "массив спецификаций",  Default, '', Default, "ID|2|3|4|5|6|7|8|9|10|11|12")

Local $ks= UBound($STR1)-1
If UBound($Threshold)>1 Then
For $j = 0 To UBound($Specific)-1
   For $k = 0 To UBound($STR1)-1
   If Mod($Specific[$j][1],2) Then
      $p = 'Pre-Failure'
   Else
      $p = 'Advisory'
   EndIf
    Local $raw = ((((($Specific[$j][8] * 256 ) + $Specific[$j][7]) * 256) + $Specific[$j][6]) * 256) + $Specific[$j][5]
Select

Case $Specific[$j][0]=$STR1[$k][0]

   $sPark = $Specific[$j][0]& '|' & $STR1[$k][1]& '|' & $STR1[$k][2] & '|' & $p & '|' & $Specific[$j][1] & '|' & $Threshold[$j] & '|' & $Specific[$j][3] & '|' & $Specific[$j][4] & '|' & $Specific[$j][5] & '|' & $Specific[$j][6] & '|' & $raw
   If StringStripWS($sPark, 8) <> 0 Then _ArrayAdd($Smart, $sPark)

Case $Specific[$j][0] <> $STR1[$k][0]    And $k <> Mod($k, $ks) And $j <> UBound($Smart)-1

    $sPark = $Specific[$j][0]& '|' & '???' & '|' & 'Зарезервировано производителем' & '|' & $p & '|' & $Specific[$j][1] & '|' & $Threshold[$j] & '|' & $Specific[$j][3] & '|' & $Specific[$j][4] & '|' & $Specific[$j][5] & '|' & $Specific[$j][6] & '|' & $raw
   If StringStripWS($sPark, 8) <> 0 Then _ArrayAdd($Smart, $sPark)

Case Else
     $sPark=''
EndSelect

      Next
   Next
EndIf
_ArrayDisplay($Smart, 'Smart', Default, '', Default, "ID|HEX|Attribute|Type|Flag|Threshold(Порог)|Текущее|Worst(Наихудший)|Значение|???|RAW|Status")
Global $Smart[0][12]
Global $Specific[0][12]
EndFunc
Есть ещё один вариант проверки. Так сказать промежуточный. В нем чуток другой механизм проверки, и он не доделан. В нем в ручном режиме добавляется признак смарта от вендора (дописывается в конце "_0"). Зато в этом варианте работает более менее, как я хочу. Только там где диск не поддерживает смарт, напр, флэшка, просто показывает пустой массив. Но, к сожалению этот вариант не помещается. Присоединю чуть позже в сообщении, если нужно будет

Оставил кучу закомментированных строк, где проверял вывод промежуточных результатов.
Хотелось бы получать смарт по букве диска
Сообщение автоматически объединено:

Добавил ещё один отчет для проверки и оказалось, что не зависимо от того, подключены NVME и флэшка или нет, все равно не выводит смарт первого диска. Вот что выводит в консоли моего второго варианта в шапке темы:
Код:
Перед вызовом функции смарт   E:  SCSI\\Disk&Ven_Hitach_&Prod_HDS721050CLA362\\4&1f5e0e69&0&020000_0
уже в функции:  E:  SCSI\\Disk&Ven_Hitach_&Prod_HDS721050CLA362\\4&1f5e0e69&0&020000_0
Перед вызовом функции смарт   I:  SCSI\\Disk&Ven_Hitach_&Prod_HDS721050CLA362\\4&1f5e0e69&0&020000_0
уже в функции:  I:  SCSI\\Disk&Ven_Hitach_&Prod_HDS721050CLA362\\4&1f5e0e69&0&020000_0
FailurePredictThresholds: ; Тут длинный отчет, с данными смарта, его длина не пропускается форумом
Перед вызовом функции смарт   H:  SCSI\\Disk&Ven_Hitach_&Prod_HDS721050CLA362\\4&1f5e0e69&0&020000_0
уже в функции:  H:  SCSI\\Disk&Ven_Hitach_&Prod_HDS721050CLA362\\4&1f5e0e69&0&020000_0
FailurePredictThresholds: ; Тут длинный отчет, с данными смарта, его длина не пропускается форумом
Перед вызовом функции смарт   J:  SCSI\\Disk&Ven_LITEON&Prod_CV3-DE256\\4&1f5e0e69&0&030000_0
уже в функции:  J:  SCSI\\Disk&Ven_LITEON&Prod_CV3-DE256\\4&1f5e0e69&0&030000_0
FailurePredictThresholds: ; Тут длинный отчет, с данными смарта, его длина не пропускается форумом
Перед вызовом функции смарт   C:  SCSI\\Disk&Ven_ST310003&Prod_33AS\\4&1f5e0e69&0&040000_0
уже в функции:  C:  SCSI\\Disk&Ven_ST310003&Prod_33AS\\4&1f5e0e69&0&040000_0
FailurePredictThresholds: ; Тут длинный отчет, с данными смарта, его длина не пропускается форумом
Перед вызовом функции смарт   D:  SCSI\\Disk&Ven_ST310003&Prod_33AS\\4&1f5e0e69&0&040000_0
уже в функции:  D:  SCSI\\Disk&Ven_ST310003&Prod_33AS\\4&1f5e0e69&0&040000_0
FailurePredictThresholds: ; Тут длинный отчет, с данными смарта, его длина не пропускается форумом

Сообщение автоматически объединено:

Решил проблему ) Оказалось, что накладываются результаты команды
Код:
$objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\WMI")
и
$objWMIService = ObjGet("winmgmts:\\" & @ComputerName & "\root\cimv2")

Разделил на $objWMIServiceCIMV2 и $objWMIServiceWMI и все заработало )
 
Последнее редактирование:
Верх