Страницы: 1
RSS
Извлечь дополнительные данные из функции пользователя
 
Доброго времени суток, уважаемые форумчане. Пытаюсь использовать функцию пользователя, взятую с сайта:https://excelvba.ru
Код
Function ArrAutofilterNew(ByRef arr, ParamArray args() As Variant) As Variant    ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru
    ' Получает по ссылке массив ARR для фильтрации
    ' и список критериев фильтрации в формате "3=маска текста" (номер столбца, "=", искомое значение)
    ' Возвращает двумерный массив с подходящими строками
    
    On Error Resume Next
    ArrAutofilterNew = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args) + 1, 1 To 2)
 
    Dim i&, ColumnToCheck&, FiltersCount&, j&, ro&, RowsCount&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function
 
    For i& = LBound(args) To UBound(args)    ' перебираем все параметры фильтрации
        If Not IsMissing(args(i&)) Then
            If args(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function
 
    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
    
    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = newarr ' возвращаем результат
    Erase arrCheck
End Function

Привел весь код, а не ссылку, т.к. вопрос именно по нему. Функция замечательная, работает верно, но можно ли из нее, не затрагивая ничего, извлечь еще один параметр? Поясню: по ходу выполнения кода, при проверке массива на соответствие ключам, он находит положение первой подходящей строки:

Код
If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
...

ну и далее. Так вот, как можно в некую переменную передать в этот момент значение i ? Так-то понятно, дописать типа: if r=empty then r=i, но как и что нужно написать, чтобы наряду с полученным значением функции ArrAutofilterNew = newarr иметь доступ к этому дополнительному значению r? Фактически, мне необходимо знать положение отфильтрованного массива (в моем случае он непрерывный) в исходном массиве и я надеюсь получить это значение вышеописанным методом.

P.S. Заранее спасибо всем откликнувшимся

Изменено: OlegO - 14.02.2026 19:31:10
 
Вообще нет желания лезть в чужой СЛОЖННЫЙ код. Однако
1. Вывод результата работы функции располагается в одной ячейке (с)ДжонУокенбах , но это не правда, и об этом будет второй пункт.
Соответственно задача - вывести несколько данных из функции. Решается выводом массива (внезапно).
Т.е. код
Код
Public Function test(a, b)
Dim rez(1 To 4) As Double
rez(1) = a + b
rez(2) = a - b
rez(3) = a / b
rez(4) = a * b
test = rez
End Function
выдаст вам массив. В новых вериях он будет динамическим, и чтобы вызвать только первое значение надо вызывать с собачкой, а в старых версиях эксель доп.элементы (кроме первого) надо вызывать через ИНДЕКС.


2. А вот теперь 2, или "не всё у Уокенбаха правда, или во всём виноваты переводчики"
Результат работы функции действительно выводится (выводился) в ячейку вызова функции. Но был(есть) вариант замены значения в другой ячейке, при условии что там ранее было значение (если значения не было - будет ошибка). Т.е. заменить значение новым из сторонней функции. И в ячейке об этом будет тишина...

Например вот функция, в ячейке в которой она вызвана будет выведен результат работы функции, а в ячейках rez1 rez2 значения будут заменены.

Код
Function Fun_3(a#, b#, rez1 As Range, rez2 As Range) As Variant
    rez1.Replace rez1, a + b    
    rez2.Replace rez2, a - b    
    Fun_3 = "сумма в " & rez1.Address(0, 0) & ", разница в " & rez2.Address(0, 0)
End Function

 
Добрый вечер. В код особо не вникал, но эта функция возвращает двухмерный массив, а значит можно увеличить второй индекс на единицу, типа
ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)+1)
и вставить туда нужные вам данные. А в вызывающем макросе их извлечь. Это теоретически, а так нужно смотреть не конкретном примере
 
Да, приложите пример с массивом и что Вы хотите получить на выходе. Так поинтереснее будет
Согласие есть продукт при полном непротивлении сторон
 
Ещё можно создать и использовать свой объект DTO
 
Спасибо всем откликнувшимся, прошу прощения за запоздалый отклик - не было доступа к ПК, а со смарта не наотвечаешься 8-0 . По просьбе уважаемого Sanja прилагаю пример и описываю задачу более подробно. Итак, есть диапазон с данными по реестрам за достаточно длинный период, номера реестров ежегодно обнуляются, это важно. Необходимо при выполнении условия (не относящегося к задаче) окрасить ячейки определенного реестра. Сейчас это реализовано приблизительно так:
Код
x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    With Cells(i, 1).Resize(UBound(ArrAutofilterNew(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)), 10).Interior
    'раскраска ячеек
    End With
циклом вычисляю начало диапазона (просто поиск номера не подойдет из-за ежегодного обнуления), далее с помощью искомой функции определяю размер массива (в данном случае только для этого) ну и далее по задаче. Подумал о том, что код функции, отрабатывая, вычисляет положение отфильтрованного массива в исходном и хорошо было бы иметь возможность вытащить эти данные. Ни для чего другого, просто для исключения цикла и все. Уфф, вроде объяснил. Собственно, пока не было доступа к ПК, 2 "кривых" способа решения я придумал: во-первых можно сделать копию функции (изменив, разумеется имя) и вместо ArrAutofilterNew = newarr написать что-то типа ArrAutofilterNew2 = r & " " & Ubound(newarr), где r это вычисленное значение i как в посте №1, а далее использовать через Split, но разве это дело "модифицировать" функцию под узкую задачу? Или объявить публичную переменную в коде функции и использовать ее, предварительно запустив функцию ad=ArrAutofilterNew (...) . Чуть лучше, но наверняка с точки зрения гуру не то 8-0. Надеюсь, объяснил понятно и подробно, если есть более красивый и, самое главное, более грамотный вариант, буду рад его увидеть
 
Вариант 1. Передать через аргумент функции.
Код
Private Sub CommandButton1_Click()
    x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    Dim rFirst As Long
                    
    With Cells(i, 1).Resize(UBound(ArrAutofilterNew(x, rFirst, "1=" & "ГНН-0001", "3=" & #1/1/2023#)), 10).Interior
    'раскраска ячеек
    End With
    Debug.Print rFirst
    
End Sub

Function ArrAutofilterNew(ByRef arr, rFirst As Long, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru
    ' Получает по ссылке массив ARR для фильтрации
    ' и список критериев фильтрации в формате "3=маска текста" (номер столбца, "=", искомое значение)
    ' Возвращает двумерный массив с подходящими строками
     
    On Error Resume Next
    ArrAutofilterNew = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args) + 1, 1 To 2)
  
    Dim i&, ColumnToCheck&, FiltersCount&, j&, ro&, RowsCount&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function
  
    For i& = LBound(args) To UBound(args)    ' перебираем все параметры фильтрации
        If Not IsMissing(args(i&)) Then
            If args(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function
  
    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
     
    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            If rFirst = 0 Then rFirst = i
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = newarr ' возвращаем результат
    Erase arrCheck
End Function
 
Вариант 2. Передать через глобальную переменную.
Код
Private Sub CommandButton1_Click()
    x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    With Cells(i, 1).Resize(UBound(ArrAutofilterNew(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)), 10).Interior
    'раскраска ячеек
    End With
    Debug.Print rFirst
    
End Sub

'---------------------------------------------
Public rFirst As Long
Function ArrAutofilterNew(ByRef arr, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru
    ' Получает по ссылке массив ARR для фильтрации
    ' и список критериев фильтрации в формате "3=маска текста" (номер столбца, "=", искомое значение)
    ' Возвращает двумерный массив с подходящими строками
     
    On Error Resume Next
    ArrAutofilterNew = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args) + 1, 1 To 2)
  
    Dim i&, ColumnToCheck&, FiltersCount&, j&, ro&, RowsCount&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function
  
    For i& = LBound(args) To UBound(args)    ' перебираем все параметры фильтрации
        If Not IsMissing(args(i&)) Then
            If args(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function
  
    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
     
    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            If rFirst = 0 Then rFirst = i
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = newarr ' возвращаем результат
    Erase arrCheck
End Function
 
Вариант 3. Вернуть массив из двух элементов.
Код
Private Sub CommandButton1_Click()
    x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    Dim arr As Variant
    arr = ArrAutofilterNew(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)
                    
    With Cells(i, 1).Resize(UBound(arr(0)), 10).Interior
    'раскраска ячеек
    End With
    Debug.Print arr(1)
    
End Sub

'---------------------------------------------
Function ArrAutofilterNew(ByRef arr, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru
    ' Получает по ссылке массив ARR для фильтрации
    ' и список критериев фильтрации в формате "3=маска текста" (номер столбца, "=", искомое значение)
    ' Возвращает двумерный массив с подходящими строками
     
    On Error Resume Next
    ArrAutofilterNew = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args) + 1, 1 To 2)
  
    Dim i&, ColumnToCheck&, FiltersCount&, j&, ro&, RowsCount&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function
  
    For i& = LBound(args) To UBound(args)    ' перебираем все параметры фильтрации
        If Not IsMissing(args(i&)) Then
            If args(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function
  
    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
     
    Dim rFirst As Long
     
    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            If rFirst = 0 Then rFirst = i
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = Array(newarr, rFirst) ' возвращаем результат
    Erase arrCheck
End Function
 
Вариант 4. Рефакторинг исходной функции.
Код
Private Sub CommandButton1_Click()
    x = Range("A1:J" & Cells(Rows.Count, 1).End(xlUp).Row).Value
    
    For i = 1 To UBound(x) 'расчет номера 1 строки реестра
        If x(i, 1) = "ГНН-0001" And CDate(x(i, 3)) = #1/1/2023# Then Exit For
    Next i
                    
    With Cells(i, 1).Resize(UBound(ArrAutofilterNew(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)), 10).Interior
    'раскраска ячеек
    End With
    
    Debug.Print ArrAutofilterNew_GetRfirst(x, "1=" & "ГНН-0001", "3=" & #1/1/2023#)
End Sub

Function ArrAutofilterNew_GetRfirst(ByRef arr, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru

    Dim RowsCount&, i As Long, j As Long, arrCheck As Variant

    arrCheck = GetArrCheck(arr, RowsCount, args)

    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ArrAutofilterNew_GetRfirst = i
            Exit Function
        End If
    Next i
End Function

Function ArrAutofilterNew(ByRef arr, ParamArray args() As Variant) As Variant   ' Новая версия функции ArrAutofilter, от января 2021 года.  © ExcelVBA.ru

    Dim RowsCount&, i As Long, j As Long, arrCheck As Variant, ro&

    arrCheck = GetArrCheck(arr, RowsCount, args)

    ReDim newarr(1 To RowsCount&, LBound(arr, 2) To UBound(arr, 2)) ' формируем новый массив
    For i = LBound(arr, 1) To UBound(arr, 1)    ' снова перебираем все строки массива
        If arrCheck(i) Then ' если строка ранее помечена как подходящая
            ro& = ro& + 1 ' вычисляем номер строки в новом массиве
            For j = LBound(arr, 2) To UBound(arr, 2)
                newarr(ro&, j) = arr(i, j) ' заполняем массив значениями из исходного
            Next j
        End If
    Next i
    ArrAutofilterNew = newarr ' возвращаем результат
End Function

Function GetArrCheck(ByRef arr, RowsCount&, ParamArray args() As Variant) As Variant
    On Error Resume Next
    GetArrCheck = False ' возвращаемое значение в случае ошибки
    If UBound(args) = -1 Then Debug.Print "Array filtering error: filters required": Exit Function
    ReDim Filters(1 To UBound(args(0)) + 1, 1 To 2)

    Dim i&, ColumnToCheck&, FiltersCount&, j&:  Err.Clear: i& = UBound(arr, 2)
    If Err.Number > 0 Then Debug.Print "Array filtering error: two dimensional array required": Exit Function

    For i& = LBound(args(0)) To UBound(args(0))    ' перебираем все параметры фильтрации
        If Not IsMissing(args(0)(i&)) Then
            If args(0)(i&) Like "#*=*" Then ' распознаем параметры фильтрации
                FiltersCount& = FiltersCount& + 1
                Filters(FiltersCount&, 1) = Val(Split(args(0)(i&), "=")(0)) ' столбец массива
                Filters(FiltersCount&, 2) = Split(args(0)(i&), "=", 2)(1) ' маска для значения
            Else ' неверно заданный фильтр
                Debug.Print "ArrAutofilterNew error: invalid filter «" & args(0)(i&) & "»"
            End If
        End If
    Next i&
    If FiltersCount& = 0 Then Debug.Print "Array filtering error: all filters are empty": Exit Function

    ReDim arrCheck(LBound(arr, 1) To UBound(arr, 1)) As Boolean ' для результатов проверки
    For i = LBound(arr, 1) To UBound(arr, 1)    ' перебираем все строки массива, и проверяем их
        arrCheck(i) = True
        For j& = 1 To FiltersCount&    ' перебираем все параметры фильтрации
            If Not (arr(i, Filters(j&, 1)) Like Filters(j&, 2)) Then arrCheck(i) = False: Exit For
        Next j&
        RowsCount& = RowsCount& - arrCheck(i) ' увеличиваем счётчик подходящих строк на 1
    Next i
    If RowsCount& = 0 Then Exit Function ' выход, если нет ни одной подходящей строки в массиве
    GetArrCheck = arrCheck
End Function
 
Спасибо, МатросНаЗебре за ваши варианты, буду посмотреть ;) , но скорее всего остановлюсь на варианте публичной переменной, ведь все прочие влияют (своей переделкой) на работу функции в других местах, надо будет там что-то изменять, верно ведь? Кстати, проверяя свое предложение из поста №6, додумался, что эту переменную еще стоит очищать где-либо выше, сама ведь она не очистится
 
Вариант 1 и 3 потребует переделки в других местах, где упоминается функция.
Вариант 2 и 4 - не потребует.
Обнулять переменные - хорошая практика.
Изменено: МатросНаЗебре - 16.02.2026 13:08:41
Страницы: 1
Читают тему
Наверх