Перенос создания фрейма CreateChildElementFrame в тесты
parent
a8b8dccfc7
commit
35401be507
|
|
@ -1,5 +1,6 @@
|
|||
"""Модуль компонента панели навигации. Содержит класс для работы с элементами навигации."""
|
||||
|
||||
import re
|
||||
from playwright.sync_api import Page, Locator
|
||||
from tools.logger import get_logger
|
||||
from locators.navigation_panel_locators import NavigationPanelLocators
|
||||
|
|
@ -51,6 +52,9 @@ class NavigationPanelComponent(BaseComponent):
|
|||
node_content = node.locator('div.v-treeview-node__content')
|
||||
if node_content.count() > 0:
|
||||
node_text = node_content.first.inner_text().strip()
|
||||
node_texts = node_text.splitlines()
|
||||
if len(node_texts) > 1:
|
||||
node_text = node_texts[1]
|
||||
if item_name == node_text:
|
||||
node_attr = node.get_attribute('class')
|
||||
if "v-treeview-node--leaf" not in node_attr:
|
||||
|
|
|
|||
|
|
@ -2,21 +2,20 @@
|
|||
|
||||
from playwright.sync_api import Page
|
||||
from components.toolbar_component import ToolbarComponent
|
||||
from components_derived.frames.create_child_element_frame import (
|
||||
CreateChildElementFrame
|
||||
)
|
||||
from components_derived.frames.create_child_element_frame import CreateChildElementFrame
|
||||
from pages.base_page import BasePage
|
||||
|
||||
|
||||
# =============== Локаторы ================================================
|
||||
PANEL_HEADER = "//span[text()='Объекты']/following-sibling::i"
|
||||
CREATE_BUTTON_ANCESTOR_DIV3 = "xpath=/ancestor::div[3]//button"
|
||||
# =========================================================================
|
||||
|
||||
|
||||
class LocationPage(BasePage):
|
||||
"""Класс для работы со страницей локации."""
|
||||
|
||||
# Константы локаторов
|
||||
TOOLBAR_BUTTONS_LOCATOR = "//div[contains(@class, 'layout class--')]//span[@class='v-tooltip v-tooltip--bottom']//button"
|
||||
|
||||
# Индексы кнопок
|
||||
CREATE_BUTTON_INDEX = 0 # Первая кнопка
|
||||
EDIT_BUTTON_INDEX = 1 # Вторая кнопка
|
||||
|
||||
def __init__(self, page: Page) -> None:
|
||||
"""
|
||||
Инициализирует страницу локации.
|
||||
|
|
@ -29,49 +28,59 @@ class LocationPage(BasePage):
|
|||
# Инициализация тулбара
|
||||
self.toolbar = ToolbarComponent(page, "")
|
||||
|
||||
panel_header_locator = self.page.locator(PANEL_HEADER)
|
||||
# Кнопка "Создать" - первая кнопка
|
||||
create_button_locator = self.page.locator(
|
||||
self.TOOLBAR_BUTTONS_LOCATOR
|
||||
).nth(self.CREATE_BUTTON_INDEX)
|
||||
|
||||
# Кнопка "Создать" - первая кнопка в тулбаре
|
||||
create_button_locator = panel_header_locator.locator(
|
||||
CREATE_BUTTON_ANCESTOR_DIV3
|
||||
).nth(0)
|
||||
# Кнопка "Изменить" - вторая кнопка
|
||||
edit_button_locator = self.page.locator(
|
||||
self.TOOLBAR_BUTTONS_LOCATOR
|
||||
).nth(self.EDIT_BUTTON_INDEX)
|
||||
|
||||
# Инициализация кнопки
|
||||
# Инициализация кнопок
|
||||
self.toolbar.add_tooltip_button(create_button_locator, "create")
|
||||
self.toolbar.add_tooltip_button(edit_button_locator, "edit")
|
||||
|
||||
# Инициализация фреймов (ленивая загрузка)
|
||||
self._create_child_frame = None
|
||||
|
||||
def click_create_button(self) -> CreateChildElementFrame:
|
||||
def click_create_button(self) -> None:
|
||||
"""
|
||||
Кликает на кнопку 'Создать' и возвращает фрейм создания.
|
||||
Кликает на кнопку 'Создать'.
|
||||
|
||||
Returns:
|
||||
CreateChildElementFrame: Фрейм создания дочернего элемента
|
||||
None
|
||||
"""
|
||||
|
||||
# Используем метод тулбара для клика
|
||||
self.toolbar.click_button("create")
|
||||
|
||||
self.wait_for_timeout(3000)
|
||||
|
||||
# Создаем и возвращаем фрейм
|
||||
self._create_child_frame = CreateChildElementFrame(self.page)
|
||||
return self._create_child_frame
|
||||
|
||||
def is_create_button_visible(self) -> bool:
|
||||
def click_edit_button(self) -> None:
|
||||
"""
|
||||
Проверяет видимость кнопки 'Создать'.
|
||||
Кликает на кнопку 'Изменить'.
|
||||
|
||||
Returns:
|
||||
bool: True если кнопка видима
|
||||
None
|
||||
"""
|
||||
button = self.toolbar.get_button_by_name("create")
|
||||
self.toolbar.click_button("edit")
|
||||
self.wait_for_timeout(2000)
|
||||
|
||||
if button is None:
|
||||
return False
|
||||
def should_be_toolbar_buttons(self) -> None:
|
||||
"""
|
||||
Проверяет наличие и функциональность кнопок тулбара.
|
||||
|
||||
return button.is_present(timeout=5000) and button.locator.is_visible()
|
||||
Raises:
|
||||
AssertionError: Если кнопки недоступны или подсказки неверны.
|
||||
"""
|
||||
# Проверяем кнопку "Создать"
|
||||
self.toolbar.check_button_visibility("create")
|
||||
self.toolbar.check_button_tooltip("create", "Создать")
|
||||
|
||||
# Проверяем кнопку "Изменить"
|
||||
self.toolbar.check_button_visibility("edit")
|
||||
self.toolbar.check_button_tooltip("edit", "Изменить")
|
||||
|
||||
self.wait_for_timeout(2000)
|
||||
|
||||
def wait_for_timeout(self, timeout: int) -> None:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -50,15 +50,18 @@ class TestCreateRackElement:
|
|||
# Создаем экземпляр страницы локации
|
||||
self.location_page = LocationPage(browser)
|
||||
|
||||
#@pytest.mark.develop
|
||||
@pytest.mark.develop
|
||||
def test_create_rack_content(self, browser: Page) -> None:
|
||||
"""Тест создания дочернего элемента типа 'Стойка'."""
|
||||
|
||||
# Проверяем что кнопка "Создать" доступна
|
||||
assert self.location_page.is_create_button_visible(), "Create button is not visible on the page"
|
||||
self.location_page.should_be_toolbar_buttons()
|
||||
|
||||
# Нажимаем кнопку "Создать" на тулбаре
|
||||
create_child_frame = self.location_page.click_create_button()
|
||||
self.location_page.click_create_button()
|
||||
|
||||
# Создаем фрейм создания дочернего элемента
|
||||
create_child_frame = CreateChildElementFrame(browser)
|
||||
|
||||
# Нажимаем на плашку "Класс объекта учета"
|
||||
create_child_frame.open_object_class_combobox()
|
||||
|
|
@ -82,7 +85,10 @@ class TestCreateRackElement:
|
|||
"""Тест создания дочернего элемента типа 'Стойка'."""
|
||||
|
||||
# Нажимаем кнопку "Создать" на тулбаре
|
||||
create_child_frame = self.location_page.click_create_button()
|
||||
self.location_page.click_create_button()
|
||||
|
||||
# Создаем фрейм создания дочернего элемента
|
||||
create_child_frame = CreateChildElementFrame(browser)
|
||||
|
||||
# Нажимаем на плашку "Класс объекта учета"
|
||||
create_child_frame.open_object_class_combobox()
|
||||
|
|
@ -131,7 +137,7 @@ class TestCreateRackElement:
|
|||
# Проверяем, существует ли уже стойка с таким именем
|
||||
if not self._check_rack_exists(browser, rack_name):
|
||||
logger.info(f"Rack with name '{rack_name}' not found. Creating first rack.")
|
||||
create_child_frame = self._create_rack(browser, rack_name)
|
||||
self._create_rack(browser, rack_name)
|
||||
logger.info(f"First rack with name '{rack_name}' created successfully")
|
||||
else:
|
||||
logger.info(f"Rack with name '{rack_name}' already exists, proceeding to create second one")
|
||||
|
|
@ -144,7 +150,10 @@ class TestCreateRackElement:
|
|||
self.main_page.wait_for_timeout(2000)
|
||||
|
||||
# Нажимаем кнопку "Создать" на тулбаре
|
||||
create_child_frame = self.location_page.click_create_button()
|
||||
self.location_page.click_create_button()
|
||||
|
||||
# Создаем фрейм создания дочернего элемента
|
||||
create_child_frame = CreateChildElementFrame(browser)
|
||||
|
||||
# Нажимаем на плашку "Класс объекта учета"
|
||||
create_child_frame.open_object_class_combobox()
|
||||
|
|
@ -179,23 +188,76 @@ class TestCreateRackElement:
|
|||
|
||||
logger.info("System prevented creating rack with duplicate name")
|
||||
|
||||
def _perform_required_fields_test(self, create_child_frame, rack_maker, test_data):
|
||||
"""Выполняет один тест валидации обязательных полей.
|
||||
|
||||
Args:
|
||||
create_child_frame: Фрейм создания дочернего элемента
|
||||
rack_maker: Объект для работы со стойкой
|
||||
test_data: Словарь с данными теста
|
||||
"""
|
||||
# Распаковываем данные теста
|
||||
name_value = test_data["name"]
|
||||
height_value = test_data["height"]
|
||||
depth_value = test_data["depth"]
|
||||
expected_alert_height = test_data["expected_alert_height"]
|
||||
expected_alert_depth = test_data["expected_alert_depth"]
|
||||
|
||||
# Очистить поля
|
||||
create_child_frame.clear_combobox_field("Глубина (мм)")
|
||||
create_child_frame.clear_combobox_field("Высота в юнитах")
|
||||
|
||||
# Заполняем данные
|
||||
rack_maker.fill_rack_data(
|
||||
name=name_value,
|
||||
height=height_value,
|
||||
depth=depth_value
|
||||
)
|
||||
|
||||
# Нажимаем кнопку создания
|
||||
create_child_frame.click_add_button()
|
||||
create_child_frame.wait_for_timeout(3000)
|
||||
|
||||
# Проверяем подсветку полей
|
||||
if height_value:
|
||||
create_child_frame.check_field_not_highlighted_error("Высота в юнитах")
|
||||
else:
|
||||
create_child_frame.check_field_highlighted_error("Высота в юнитах")
|
||||
|
||||
if depth_value:
|
||||
create_child_frame.check_field_not_highlighted_error("Глубина (мм)")
|
||||
else:
|
||||
create_child_frame.check_field_highlighted_error("Глубина (мм)")
|
||||
|
||||
# Обрабатываем alert-окна
|
||||
if not height_value:
|
||||
create_child_frame.alert.check_alert_presence(expected_alert_height)
|
||||
create_child_frame.alert.close_alert_by_text(expected_alert_height)
|
||||
|
||||
if not depth_value:
|
||||
create_child_frame.alert.check_alert_presence(expected_alert_depth)
|
||||
create_child_frame.alert.close_alert_by_text(expected_alert_depth)
|
||||
|
||||
# Проверяем, что остались на той же странице
|
||||
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||||
|
||||
def test_required_fields_validation(self, browser: Page) -> None:
|
||||
"""
|
||||
Тест проверки обязательных полей при создании стойки.
|
||||
|
||||
Проверяет, что система корректно валидирует обязательные поля:
|
||||
- Поле 'Имя' должно быть заполнено
|
||||
- Поле 'Высота в юнитах' должно быть заполнено
|
||||
- Поле 'Глубина (мм)' должно быть заполнено
|
||||
"""
|
||||
|
||||
# Текст сообщения alert-окна
|
||||
expected_alert_text_name = "поле Имя должно быть заполнено"
|
||||
expected_alert_text_height = "поле Высота в юнитах должно быть заполнено"
|
||||
expected_alert_text_depth = "поле Глубина (мм) должно быть заполнено"
|
||||
|
||||
# Нажимаем кнопку "Создать" на тулбаре
|
||||
create_child_frame = self.location_page.click_create_button()
|
||||
self.location_page.click_create_button()
|
||||
|
||||
# Создаем фрейм создания дочернего элемента
|
||||
create_child_frame = CreateChildElementFrame(browser)
|
||||
|
||||
# Нажимаем на плашку "Класс объекта учета"
|
||||
create_child_frame.open_object_class_combobox()
|
||||
|
|
@ -209,136 +271,57 @@ class TestCreateRackElement:
|
|||
# Проверяем наличие полей стойки
|
||||
rack_maker.check_rack_fields_presence()
|
||||
|
||||
# 1. Тест: Попытка создания стойки поля - default
|
||||
logger.info("Test 1: Creating rack with default field values")
|
||||
# Тестовые данные
|
||||
test_cases = [
|
||||
{
|
||||
"name": "Test 1: Creating rack with default field values",
|
||||
"data": {
|
||||
"name": "",
|
||||
"height": "",
|
||||
"depth": "",
|
||||
"expected_alert_height": expected_alert_text_height,
|
||||
"expected_alert_depth": expected_alert_text_depth
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Test 2: Required fields are not filled",
|
||||
"data": {
|
||||
"name": "",
|
||||
"height": "",
|
||||
"depth": "",
|
||||
"expected_alert_height": expected_alert_text_height,
|
||||
"expected_alert_depth": expected_alert_text_depth
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Test 3: Only 'Height in units' field is filled",
|
||||
"data": {
|
||||
"name": "",
|
||||
"height": "42",
|
||||
"depth": "",
|
||||
"expected_alert_height": expected_alert_text_height,
|
||||
"expected_alert_depth": expected_alert_text_depth
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Test 4: Only 'Depth (mm)' field is filled",
|
||||
"data": {
|
||||
"name": "",
|
||||
"height": "",
|
||||
"depth": "1000",
|
||||
"expected_alert_height": expected_alert_text_height,
|
||||
"expected_alert_depth": expected_alert_text_depth
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
# Нажимаем кнопку создания без заполнения данных
|
||||
create_child_frame.click_add_button()
|
||||
create_child_frame.wait_for_timeout(2000)
|
||||
|
||||
# Проверяем подсветку обязательных полей цветом ошибки
|
||||
create_child_frame.check_field_highlighted_error("Высота в юнитах")
|
||||
create_child_frame.check_field_highlighted_error("Глубина (мм)")
|
||||
|
||||
logger.info("Validation for 'Name' field temporarily disabled - waiting for developer fix")
|
||||
|
||||
# Проверяем наличие alert-окна с сообщением о заполнении Высота в юнитах
|
||||
create_child_frame.alert.check_alert_presence(expected_alert_text_height)
|
||||
# Закрываем alert-окно Высота в юнитах
|
||||
create_child_frame.alert.close_alert_by_text(expected_alert_text_height)
|
||||
|
||||
# Проверяем наличие alert-окна с сообщением о заполнении Глубины (мм)
|
||||
create_child_frame.alert.check_alert_presence(expected_alert_text_depth)
|
||||
# Закрываем alert-окно Глубины (мм)
|
||||
create_child_frame.alert.close_alert_by_text(expected_alert_text_depth)
|
||||
|
||||
# Проверяем, что остались на той же странице
|
||||
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||||
logger.info("System prevented creating rack without height and depth")
|
||||
create_child_frame.wait_for_timeout(2000)
|
||||
|
||||
# 2. Тест: Обязательные поля не заполнены
|
||||
logger.info("Test 2: Required fields are not filled")
|
||||
|
||||
rack_maker.fill_rack_data(
|
||||
name="",
|
||||
height="",
|
||||
depth=""
|
||||
)
|
||||
|
||||
# Нажимаем кнопку создания без заполнения данных
|
||||
create_child_frame.click_add_button()
|
||||
create_child_frame.wait_for_timeout(2000)
|
||||
|
||||
# Проверяем подсветку всех обязательных полей цветом ошибки
|
||||
create_child_frame.check_field_highlighted_error("Высота в юнитах")
|
||||
create_child_frame.check_field_highlighted_error("Глубина (мм)")
|
||||
|
||||
logger.info("Validation for 'Name' field temporarily disabled - waiting for developer fix")
|
||||
|
||||
# Проверяем наличие alert-окна с сообщением о заполнении Высота в юнитах
|
||||
create_child_frame.alert.check_alert_presence(expected_alert_text_height)
|
||||
# Закрываем alert-окно Высота в юнитах
|
||||
create_child_frame.alert.close_alert_by_text(expected_alert_text_height)
|
||||
|
||||
# Проверяем наличие alert-окна с сообщением о заполнении Глубины (мм)
|
||||
create_child_frame.alert.check_alert_presence(expected_alert_text_depth)
|
||||
# Закрываем alert-окно Глубины (мм)
|
||||
create_child_frame.alert.close_alert_by_text(expected_alert_text_depth)
|
||||
|
||||
# Проверяем, что остались на той же странице
|
||||
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||||
logger.info("System prevented creating rack without name, height and depth")
|
||||
create_child_frame.wait_for_timeout(2000)
|
||||
|
||||
# 3. Тест: Заполняем только поле 'Высота в юнитах'
|
||||
logger.info("Test 3: Only 'Height in units' field is filled")
|
||||
|
||||
# Очистить поля
|
||||
create_child_frame.clear_combobox_field("Глубина (мм)")
|
||||
create_child_frame.clear_combobox_field("Высота в юнитах")
|
||||
|
||||
# Очистить поля через заполнение пустыми значениями
|
||||
rack_maker.fill_rack_data(
|
||||
name="",
|
||||
height="42",
|
||||
depth=""
|
||||
)
|
||||
|
||||
# Нажимаем кнопку создания без заполнения данных
|
||||
create_child_frame.click_add_button()
|
||||
create_child_frame.wait_for_timeout(2000)
|
||||
|
||||
# Проверяем подсветку полей 'Имя' и 'Глубина (мм)' цветом ошибки
|
||||
create_child_frame.check_field_not_highlighted_error("Высота в юнитах")
|
||||
create_child_frame.check_field_highlighted_error("Глубина (мм)")
|
||||
|
||||
# Проверяем, что НЕТ alert-окна для поля 'Высота в юнитах'
|
||||
create_child_frame.alert.check_alert_absence(expected_alert_text_height, 1000)
|
||||
|
||||
# Проверяем наличие alert-окна с сообщением о заполнении Глубины (мм)
|
||||
create_child_frame.alert.check_alert_presence(expected_alert_text_depth)
|
||||
# Закрываем alert-окно Глубины (мм)
|
||||
create_child_frame.alert.close_alert_by_text(expected_alert_text_depth)
|
||||
|
||||
# Проверяем, что остались на той же странице
|
||||
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||||
logger.info("System prevented creating rack without name and depth")
|
||||
create_child_frame.wait_for_timeout(2000)
|
||||
|
||||
# 4. Тест: Заполняем только поле 'Глубина (мм)'
|
||||
logger.info("Test 4: Only 'Depth (mm)' field is filled")
|
||||
|
||||
create_child_frame.clear_combobox_field("Глубина (мм)")
|
||||
create_child_frame.clear_combobox_field("Высота в юнитах")
|
||||
|
||||
rack_maker.fill_rack_data(
|
||||
name="",
|
||||
height="",
|
||||
depth="1000"
|
||||
)
|
||||
|
||||
create_child_frame.wait_for_timeout(5000)
|
||||
|
||||
# Нажимаем кнопку создания
|
||||
create_child_frame.click_add_button()
|
||||
create_child_frame.wait_for_timeout(3000)
|
||||
|
||||
# Проверяем подсветку полей 'Имя' и 'Высота в юнитах' цветом ошибки
|
||||
create_child_frame.check_field_highlighted_error("Высота в юнитах")
|
||||
create_child_frame.check_field_not_highlighted_error("Глубина (мм)")
|
||||
|
||||
logger.info("Validation for 'Depth' field alert absence temporarily disabled")
|
||||
|
||||
# Проверяем наличие alert-окна с сообщением о заполнении Высота в юнитах
|
||||
create_child_frame.alert.check_alert_presence(expected_alert_text_height)
|
||||
# Закрываем alert-окно Высота в юнитах
|
||||
create_child_frame.alert.close_alert_by_text(expected_alert_text_height)
|
||||
|
||||
# Проверяем, что остались на той же странице
|
||||
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||||
logger.info("System prevented creating rack without name and height")
|
||||
create_child_frame.wait_for_timeout(2000)
|
||||
# Выполняем тестовые случаи
|
||||
for test_case in test_cases:
|
||||
logger.info(test_case["name"])
|
||||
self._perform_required_fields_test(
|
||||
create_child_frame, rack_maker, test_case["data"]
|
||||
)
|
||||
logger.info("System prevented creating rack with invalid required fields")
|
||||
|
||||
# 5. Тест: Заполняем все обязательные поля
|
||||
logger.info("Test 5: All required fields are filled")
|
||||
|
|
@ -364,7 +347,6 @@ class TestCreateRackElement:
|
|||
create_child_frame.wait_for_timeout(3000)
|
||||
|
||||
# Проверяем, что НЕТ alert-окон для всех обязательных полей
|
||||
create_child_frame.alert.check_alert_absence(expected_alert_text_name, 1000)
|
||||
create_child_frame.alert.check_alert_absence(expected_alert_text_height, 1000)
|
||||
create_child_frame.alert.check_alert_absence(expected_alert_text_depth, 1000)
|
||||
logger.info("No alert windows for required fields appeared - all fields filled correctly")
|
||||
|
|
@ -373,7 +355,7 @@ class TestCreateRackElement:
|
|||
try:
|
||||
create_child_frame.check_toolbar_title('Создать дочерний элемент в')
|
||||
logger.warning("Rack creation may not have completed successfully")
|
||||
except Exception as e:
|
||||
except AssertionError:
|
||||
logger.info("Creation page closed - rack successfully created")
|
||||
|
||||
logger.info("Required fields validation test completed successfully")
|
||||
|
|
@ -397,11 +379,11 @@ class TestCreateRackElement:
|
|||
if element.is_visible():
|
||||
logger.info(f"Rack with name '{rack_name}' found")
|
||||
return True
|
||||
else:
|
||||
logger.info(f"Rack with name '{rack_name}' not found")
|
||||
return False
|
||||
|
||||
def _create_rack(self, browser: Page, rack_name: str) -> CreateChildElementFrame:
|
||||
logger.info(f"Rack with name '{rack_name}' not found")
|
||||
return False
|
||||
|
||||
def _create_rack(self, browser: Page, rack_name: str) -> None:
|
||||
"""Создает стойку."""
|
||||
logger.info(f"Creating rack with name '{rack_name}'")
|
||||
|
||||
|
|
@ -410,7 +392,10 @@ class TestCreateRackElement:
|
|||
self.main_page.wait_for_timeout(2000)
|
||||
|
||||
# Нажимаем кнопку "Создать" на тулбаре
|
||||
create_child_frame = self.location_page.click_create_button()
|
||||
self.location_page.click_create_button()
|
||||
|
||||
# Создаем фрейм создания дочернего элемента
|
||||
create_child_frame = CreateChildElementFrame(browser)
|
||||
|
||||
# Нажимаем на плашку "Класс объекта учета"
|
||||
create_child_frame.open_object_class_combobox()
|
||||
|
|
@ -431,5 +416,3 @@ class TestCreateRackElement:
|
|||
# Нажимаем кнопку создания
|
||||
create_child_frame.click_add_button()
|
||||
create_child_frame.wait_for_timeout(2000)
|
||||
|
||||
return create_child_frame
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ class TestNavigationPanel:
|
|||
mp.wait_for_timeout(5000)
|
||||
|
||||
|
||||
mp.click_subpanel_item("Физические устройства с опросом")
|
||||
mp.click_subpanel_item("test-zone")
|
||||
mp.wait_for_timeout(3000)
|
||||
|
||||
# Переходим Здание ЦОД 4
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue