[Информационная безопасность, Совершенный код, Управление продуктом, Софт] Строим безопасную разработку в ритейлере. Итоги одного большого проекта
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Эта статья — завершающая в цикле материалов о нашем опыте выстраивания процесса безопасной разработки для крупного ритейлера. Если пропустили, можете прочитать первые части: о безопасной разработке порталов и мобильных приложений, о безопасной разработке в группе приложений SAP и о встраивании в процесс разработки кассового ПО. Настало время собрать шишки, которые мы набили подвести итоги.
Все было классно. И на этом мы могли бы закончить, если бы не одно «но». При планировании мы некорректно оценили время интеграции. Спойлер: многое пошло не так, в результате внедрение усложнилось, сроки сдвинулись. Спойлер 2: учесть все факторы риска было невозможно. И вот с этого момента давайте поподробнее.
Lessons to Be Learned
1. Учитываем регламенты и бюрократию
Чем больше заказчик, тем больше у него регламентов и бюрократии, которые созданы облегчить все, но на деле — только усложняют. О первый камень мы споткнулись на этапе конкурса. Нас попросили подготовить генеральный план еще до того, как мы успели ознакомиться со всеми внутренними требованиями и нюансами, а также устройством компании изнутри, которые впоследствии на многое повлияли. Это было требованием директората, без которого внедрение не случилось бы. Мы согласились и, оценив риски, подписались под довольно свободные сроки, как нам тогда показалось.
На старте заказчик предупредил нас, что у него есть регламент, согласно которому внедрения должны проходить через три стандартных этапа: разработка, тестирование и продакшн. Расскажем на примере, почему эти правила на самом деле ничего не облегчают.
Нам нужно было внедриться в большое количество репозиториев мобильных приложений, но не во всех из них был настроен CI, и поэтому не везде можно было посмотреть, как собирается код. Поэтому мы сначала получали доступ к исходному коду (к сожалению, только на чтение). Доступа к инфраструктуре сборки и тестирования у нас не было, поэтому мы пытались собрать его у себя локально, писали внутренние инструкции для воспроизводимости и страховки от бас-фактора, пытались автоматизировать сборку и запуск анализа, постоянно консультировались с разработчиками ритейлера. Наконец, когда мы локально прогнали все анализы исходного (или собранного кода) в Solar appScreener, все финализировали и пришли к заказчику с готовым планом, выяснилось непредвиденное. Некоторые репозитории изменились (соответственно, наши подходы устарели), а часть тимлидов просто отказалась давать доступ к коду, потребовав инструкции по интеграции, чтобы внедрить все самостоятельно.
Получилось, что какую-то работу мы проделали зря, какую-то — передали на сторону заказчика. И если бы мы миновали бюрократический процесс, существенно сэкономили бы время. Как мы увидели на примере внутренних разработчиков позже, избежать его было можно. Ближе к концу проекта мы убедились, что могли бы так же игнорировать эти требования без какого-либо ущерба проекту и репутации. Но к тому моменту интеграция уже перешла в финальную фазу отладки. Мы сделали вывод, что в будущем будем договариваться, чтобы с нас снимали требования о жестком соответствии регламентам, если их несоблюдение никак не влияет на проект. Также мы поняли, что необходимо было настаивать на большем вовлечении со стороны ритейлера. Так мы могли узнать о значимых изменениях раньше и более гибко на них отреагировать. И самый главный вывод: при планировании сроков обязательно нужно оценивать зарегламентированность крупных организаций как веский фактор риска.
2. Текучка – существенный тормоз процесса
В большой компании большая текучка кадров — еще одна причина, по которой нас периодически отбрасывало назад по временной петле. Мы несколько раз достигали договоренностей с ответственными лицами, которые впоследствии уходили из компании. Поэтому нам приходилось либо заново договариваться с новым сотрудником о соблюдении ранее утверждённых договорённостей, либо общаться с вышестоящим руководителем (в тех случаях, когда замену ему еще не нашли).
Однажды нас застали врасплох категоричным ответом: «Я считаю, что это решение будет неверным. Мы так делать не будем». Это случилось, когда мы уже договорились о полной передаче поддержки баз данных MariaDB с руководителем отдела администрирования баз данных. Перед самой сдачей проекта, когда мы все согласовали, выяснилось, что в отделе сменился руководитель. И хотя все договоренности с прежним сотрудником были запротоколированы, согласно регламенту, нам пришлось пойти на компромисс и взять администрирование на себя в рамках техподдержки всего продукта. Оказалось, что заказчик не берет на поддержку MariaDB, хотя в проектной документации не было упоминаний об этом.
От таких случаев полностью не застрахуешься, поэтому чтобы выйти из ситуации, нужно, с одной стороны, уметь жестко фиксировать решения и следовать им, с другой стороны, искать точки соприкосновения и идти навстречу друг другу.
3. Погружение в специфику избавит от множества проблем
На этапе внедрения мы нередко сталкивались с недочетами в планировании. Поскольку менеджмент ритейлера попросил подготовить генеральный план до утверждения проекта, а после утверждения мы были вынуждены идти четко по намеченному курсу, возникали сложности. На старте мы ожидали, что внутри компании все будет устроено плюс-минус единообразно (не считая SAP), но это оказалось совсем не так. Отличались инфраструктура и способы ее развертывания, регламенты по разработке, уставы, ограничения в приобретении продуктов и т.д. Мы прекрасно понимали, что столкнемся с различными технологиями в разработке, но надеялись на единые подходы к процессам и единые концепции, и вот в этом мы ошиблись.
Завершив проект, мы пришли к выводу, что теперь на этапе разведки и анализа мы будем рассматривать каждое подразделение enterprise как отдельную компанию и глубоко погружаться в его специфику. Определять, какие черты общие, а какие нет. После этого внедрения мы сформировали общий опросник, который позволяет понять, как происходит процесс разработки, как разработчики пишут свой код, как они применяют и выкатывают изменения, какая у них инфраструктура для продакшн-среды и др.
Интеграция такого масштаба — это партнерские отношения, в которых все стороны должны договариваться и уметь гибко реагировать на изменения. Тем не менее, чтобы получить более или менее четкий план, лучше выбрать итеративный подход в его составлении.
Изменения в продукте по результатам проекта
1. Интеграция с AD
До этого проекта интеграция Solar appScreener с Active Directory не была оптимизирована под высокие нагрузки. Она начинала тормозить при подключении к каталогам с тысячами пользователей, с ней было не очень удобно работать. В процессе развития проекта систему доработали так, что никаких нареканий к ней уже не возникало. Теперь мы сможем интегрироваться с любой подобной системой, и проблем с производительностью у нас не будет.
2. Jira
Мы также серьезно улучшили все нюансы, связанные с Jira. До проекта мы полагались на дефолтную реализацию Jira, но у данной ритейловой компании Jira была очень серьезно переписана: добавлены различные поля, изменена дефолтная механика создания задач, все изначальные шаблоны. Поэтому мы внедрили в Solar appScreener инструмент, который позволяет подстраиваться под любой вид интеграции, потому что имеет возможность редактировать тело создаваемой задачи, которая посылается в Jira по API из Solar appScreener. Это очень гибкий инструмент.
Например, когда мы настраивали интеграцию с SAP, то столкнулись с тем, что наша старая интеграция с Jira выгружает какие-то дефолтные поля задачи, ты пытаешься создать задачу, и это не получается. Думаешь, «что происходит?». Открываешь Jira, а там все не так, Jira по API выдает абсолютно не те дефолтные поля, не того типа данных, которые на самом деле должны содержаться. Но поскольку на эту реализацию у заказчика были завязаны процессы, то проблемы надо было решать на стороне Solar appScreener.
В результате в SAP нужно было заранее определить поля estimation time to do this task. Estimation time приходит как string, заходишь и видишь в нем два поля. А если открыть XML, то обнаруживается, что в этих полях данные должны быть описаны определенным образом. То есть это уже, по сути, словарь со множеством значений, где нужно сразу прописать время, например, one day в формате именно «1d». Ты это исправляешь, пытаешься запустить интеграцию… и опять что-то не работает. Смотришь и понимаешь: какое-то поле, которое выгрузилось как обязательное, действительно числится как обязательное. Но при этом в самом интерфейсе его заполнять не нужно. Пару раз вот так потыкавшись, ты в итоге реализуешь интеграцию, но если бы у нас не было возможности гибкой настройки любого вида полей, то мы бы не смогли настроить интеграцию с такой кастомной версией Jira.
3. Изменение архитектуры приложения
Параллельно с этим проектом мы серьезно модернизировали архитектуру нашего приложения. Это потребовало существенных трудозатрат, так как необходимо было перейти от парадигмы цельного монолита, нагрузка от работы которого полностью ложилась на сервер, на классическую модель backend-frontend. Из-за чего пришлось применять другие подходы во всей разработке, проектировании, создании своего API и изменении стека технологий. В итоге это решение существенно упростило создание автоматизации – так как именно наш новый API стал её основным инструментом и точкой входа.
Для себя мы выяснили, что есть очень много запросов на переход с MariaDB/MySQL, функционала которой было достаточно для работы приложения, на PostreSQL. Особенно со стороны крупного бизнеса, для которого эта база данных является одной из наиболее распространенных благодаря широкому функционалу и хорошей поддержке. Так, заказчик в определенный момент отказался от поддержки MariaDB, и их подразделение баз данных перешло на работу исключительно с PostgreSQL. Поэтому нам пришлось внедрять поддержку этой базы данных.
Резюме
В целом, этот заказчик, будучи крупной компанией, очень сильно помог развитию нашего продукта. Это серьезный боевой кейс, который привнес много понимания, как должно эволюционировать решение. По итогам внедрения мы сформулировали подходы к оценке рисков и планированию проекта в сегменте enterprise и задекларировали опросник для сбора информации об инфраструктуре заказчика.
Проект выявил узкие места, и мы осознали, как с ними бороться в будущем. Наша команда поняла для себя, как должна выглядеть архитектура Solar appScreener через год, чтобы продукт улучшался, расширялись его варианты поставки. Многое для себя выяснили с точки зрения улучшения пользовательского опыта работы с продуктом. В некоторых местах не хватало поиска по пользователям. Нужно было дать возможность добавить пользователя в локальную группу из LDAP и других протоколов сразу в нескольких, связанных с панелью администрирования местах (в настройках конкретного проекта, в настройках пользователя и т.п.).
Все участники этого проекта с нашей стороны сейчас занимаются развитием продукта, и у них есть общее понимание, как он должен масштабироваться на крупные внедрения процесса безопасной разработки. Мы работаем над очередной ещё более глобальной модернизацией архитектуры всего приложения, которое позволит его масштабировать и изменять более гибко, сделает более универсальной развёртку и проще взаимодействие для пользователей.
Это заключительная часть цикла статей о построении процесса безопасной разработки в крупном ритейлере. Будем рады ответить на вопросы и узнать о вашем опыте реализации практик безопасной разработки в комментариях!
Автор: Иван Старосельский, руководитель отдела эксплуатации и автоматизации информационных систем
===========
Источник:
habr.com
===========
Похожие новости:
- [Системное администрирование, Софт, IT-компании] Microsoft выкатила хотфикс для проблемы с ChkDsk
- [Информационная безопасность, Машинное обучение, Интернет вещей] Информационная безопасность устройств IoT c использованием аппаратной поддержки
- [Информационная безопасность, Программирование, Софт] Антирекорд 2020: в ПО выявили уязвимостей больше, чем в любой другой год
- [Информационная безопасность] Security Week 52: управление атакой SunBurst через DNS-запросы
- [Информационная безопасность, Интернет вещей] Уязвимости IoT-систем на примере LoRaWAN
- [Информационная безопасность, Разработка мобильных приложений, Разработка под Android, Аналитика мобильных приложений] Как правильно идентифицировать Android-устройства
- [Информационная безопасность, IT-инфраструктура, Исследования и прогнозы в IT, Сетевое оборудование] Китай vs США — особенности противостояния ИТ-гигантов
- [Информационная безопасность, Сетевые технологии] VPN: ещё раз просто о сложном
- [Развитие стартапа, Управление продуктом, Краудсорсинг] Чему НКО могут поучиться у стартапов (перевод)
- [Информационная безопасность, Карьера в IT-индустрии] Сдать OSCE: вызов принят
Теги для поиска: #_informatsionnaja_bezopasnost (Информационная безопасность), #_sovershennyj_kod (Совершенный код), #_upravlenie_produktom (Управление продуктом), #_soft (Софт), #_bezopasnaja_razrabotka (безопасная разработка), #_analiz_koda (анализ кода), #_ujazvimosti (уязвимости), #_gitlab, #_jira, #_ci/cd, #_activedirectory, #_sap, #_devsecops, #_postgresql, #_blog_kompanii_rostelekomsolar (
Блог компании Ростелеком-Солар
), #_informatsionnaja_bezopasnost (
Информационная безопасность
), #_sovershennyj_kod (
Совершенный код
), #_upravlenie_produktom (
Управление продуктом
), #_soft (
Софт
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 09:07
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Эта статья — завершающая в цикле материалов о нашем опыте выстраивания процесса безопасной разработки для крупного ритейлера. Если пропустили, можете прочитать первые части: о безопасной разработке порталов и мобильных приложений, о безопасной разработке в группе приложений SAP и о встраивании в процесс разработки кассового ПО. Настало время собрать шишки, которые мы набили подвести итоги. Все было классно. И на этом мы могли бы закончить, если бы не одно «но». При планировании мы некорректно оценили время интеграции. Спойлер: многое пошло не так, в результате внедрение усложнилось, сроки сдвинулись. Спойлер 2: учесть все факторы риска было невозможно. И вот с этого момента давайте поподробнее. Lessons to Be Learned 1. Учитываем регламенты и бюрократию Чем больше заказчик, тем больше у него регламентов и бюрократии, которые созданы облегчить все, но на деле — только усложняют. О первый камень мы споткнулись на этапе конкурса. Нас попросили подготовить генеральный план еще до того, как мы успели ознакомиться со всеми внутренними требованиями и нюансами, а также устройством компании изнутри, которые впоследствии на многое повлияли. Это было требованием директората, без которого внедрение не случилось бы. Мы согласились и, оценив риски, подписались под довольно свободные сроки, как нам тогда показалось. На старте заказчик предупредил нас, что у него есть регламент, согласно которому внедрения должны проходить через три стандартных этапа: разработка, тестирование и продакшн. Расскажем на примере, почему эти правила на самом деле ничего не облегчают. Нам нужно было внедриться в большое количество репозиториев мобильных приложений, но не во всех из них был настроен CI, и поэтому не везде можно было посмотреть, как собирается код. Поэтому мы сначала получали доступ к исходному коду (к сожалению, только на чтение). Доступа к инфраструктуре сборки и тестирования у нас не было, поэтому мы пытались собрать его у себя локально, писали внутренние инструкции для воспроизводимости и страховки от бас-фактора, пытались автоматизировать сборку и запуск анализа, постоянно консультировались с разработчиками ритейлера. Наконец, когда мы локально прогнали все анализы исходного (или собранного кода) в Solar appScreener, все финализировали и пришли к заказчику с готовым планом, выяснилось непредвиденное. Некоторые репозитории изменились (соответственно, наши подходы устарели), а часть тимлидов просто отказалась давать доступ к коду, потребовав инструкции по интеграции, чтобы внедрить все самостоятельно. Получилось, что какую-то работу мы проделали зря, какую-то — передали на сторону заказчика. И если бы мы миновали бюрократический процесс, существенно сэкономили бы время. Как мы увидели на примере внутренних разработчиков позже, избежать его было можно. Ближе к концу проекта мы убедились, что могли бы так же игнорировать эти требования без какого-либо ущерба проекту и репутации. Но к тому моменту интеграция уже перешла в финальную фазу отладки. Мы сделали вывод, что в будущем будем договариваться, чтобы с нас снимали требования о жестком соответствии регламентам, если их несоблюдение никак не влияет на проект. Также мы поняли, что необходимо было настаивать на большем вовлечении со стороны ритейлера. Так мы могли узнать о значимых изменениях раньше и более гибко на них отреагировать. И самый главный вывод: при планировании сроков обязательно нужно оценивать зарегламентированность крупных организаций как веский фактор риска. 2. Текучка – существенный тормоз процесса В большой компании большая текучка кадров — еще одна причина, по которой нас периодически отбрасывало назад по временной петле. Мы несколько раз достигали договоренностей с ответственными лицами, которые впоследствии уходили из компании. Поэтому нам приходилось либо заново договариваться с новым сотрудником о соблюдении ранее утверждённых договорённостей, либо общаться с вышестоящим руководителем (в тех случаях, когда замену ему еще не нашли). Однажды нас застали врасплох категоричным ответом: «Я считаю, что это решение будет неверным. Мы так делать не будем». Это случилось, когда мы уже договорились о полной передаче поддержки баз данных MariaDB с руководителем отдела администрирования баз данных. Перед самой сдачей проекта, когда мы все согласовали, выяснилось, что в отделе сменился руководитель. И хотя все договоренности с прежним сотрудником были запротоколированы, согласно регламенту, нам пришлось пойти на компромисс и взять администрирование на себя в рамках техподдержки всего продукта. Оказалось, что заказчик не берет на поддержку MariaDB, хотя в проектной документации не было упоминаний об этом. От таких случаев полностью не застрахуешься, поэтому чтобы выйти из ситуации, нужно, с одной стороны, уметь жестко фиксировать решения и следовать им, с другой стороны, искать точки соприкосновения и идти навстречу друг другу. 3. Погружение в специфику избавит от множества проблем На этапе внедрения мы нередко сталкивались с недочетами в планировании. Поскольку менеджмент ритейлера попросил подготовить генеральный план до утверждения проекта, а после утверждения мы были вынуждены идти четко по намеченному курсу, возникали сложности. На старте мы ожидали, что внутри компании все будет устроено плюс-минус единообразно (не считая SAP), но это оказалось совсем не так. Отличались инфраструктура и способы ее развертывания, регламенты по разработке, уставы, ограничения в приобретении продуктов и т.д. Мы прекрасно понимали, что столкнемся с различными технологиями в разработке, но надеялись на единые подходы к процессам и единые концепции, и вот в этом мы ошиблись. Завершив проект, мы пришли к выводу, что теперь на этапе разведки и анализа мы будем рассматривать каждое подразделение enterprise как отдельную компанию и глубоко погружаться в его специфику. Определять, какие черты общие, а какие нет. После этого внедрения мы сформировали общий опросник, который позволяет понять, как происходит процесс разработки, как разработчики пишут свой код, как они применяют и выкатывают изменения, какая у них инфраструктура для продакшн-среды и др. Интеграция такого масштаба — это партнерские отношения, в которых все стороны должны договариваться и уметь гибко реагировать на изменения. Тем не менее, чтобы получить более или менее четкий план, лучше выбрать итеративный подход в его составлении. Изменения в продукте по результатам проекта 1. Интеграция с AD До этого проекта интеграция Solar appScreener с Active Directory не была оптимизирована под высокие нагрузки. Она начинала тормозить при подключении к каталогам с тысячами пользователей, с ней было не очень удобно работать. В процессе развития проекта систему доработали так, что никаких нареканий к ней уже не возникало. Теперь мы сможем интегрироваться с любой подобной системой, и проблем с производительностью у нас не будет. 2. Jira Мы также серьезно улучшили все нюансы, связанные с Jira. До проекта мы полагались на дефолтную реализацию Jira, но у данной ритейловой компании Jira была очень серьезно переписана: добавлены различные поля, изменена дефолтная механика создания задач, все изначальные шаблоны. Поэтому мы внедрили в Solar appScreener инструмент, который позволяет подстраиваться под любой вид интеграции, потому что имеет возможность редактировать тело создаваемой задачи, которая посылается в Jira по API из Solar appScreener. Это очень гибкий инструмент. Например, когда мы настраивали интеграцию с SAP, то столкнулись с тем, что наша старая интеграция с Jira выгружает какие-то дефолтные поля задачи, ты пытаешься создать задачу, и это не получается. Думаешь, «что происходит?». Открываешь Jira, а там все не так, Jira по API выдает абсолютно не те дефолтные поля, не того типа данных, которые на самом деле должны содержаться. Но поскольку на эту реализацию у заказчика были завязаны процессы, то проблемы надо было решать на стороне Solar appScreener. В результате в SAP нужно было заранее определить поля estimation time to do this task. Estimation time приходит как string, заходишь и видишь в нем два поля. А если открыть XML, то обнаруживается, что в этих полях данные должны быть описаны определенным образом. То есть это уже, по сути, словарь со множеством значений, где нужно сразу прописать время, например, one day в формате именно «1d». Ты это исправляешь, пытаешься запустить интеграцию… и опять что-то не работает. Смотришь и понимаешь: какое-то поле, которое выгрузилось как обязательное, действительно числится как обязательное. Но при этом в самом интерфейсе его заполнять не нужно. Пару раз вот так потыкавшись, ты в итоге реализуешь интеграцию, но если бы у нас не было возможности гибкой настройки любого вида полей, то мы бы не смогли настроить интеграцию с такой кастомной версией Jira. 3. Изменение архитектуры приложения Параллельно с этим проектом мы серьезно модернизировали архитектуру нашего приложения. Это потребовало существенных трудозатрат, так как необходимо было перейти от парадигмы цельного монолита, нагрузка от работы которого полностью ложилась на сервер, на классическую модель backend-frontend. Из-за чего пришлось применять другие подходы во всей разработке, проектировании, создании своего API и изменении стека технологий. В итоге это решение существенно упростило создание автоматизации – так как именно наш новый API стал её основным инструментом и точкой входа. Для себя мы выяснили, что есть очень много запросов на переход с MariaDB/MySQL, функционала которой было достаточно для работы приложения, на PostreSQL. Особенно со стороны крупного бизнеса, для которого эта база данных является одной из наиболее распространенных благодаря широкому функционалу и хорошей поддержке. Так, заказчик в определенный момент отказался от поддержки MariaDB, и их подразделение баз данных перешло на работу исключительно с PostgreSQL. Поэтому нам пришлось внедрять поддержку этой базы данных. Резюме В целом, этот заказчик, будучи крупной компанией, очень сильно помог развитию нашего продукта. Это серьезный боевой кейс, который привнес много понимания, как должно эволюционировать решение. По итогам внедрения мы сформулировали подходы к оценке рисков и планированию проекта в сегменте enterprise и задекларировали опросник для сбора информации об инфраструктуре заказчика. Проект выявил узкие места, и мы осознали, как с ними бороться в будущем. Наша команда поняла для себя, как должна выглядеть архитектура Solar appScreener через год, чтобы продукт улучшался, расширялись его варианты поставки. Многое для себя выяснили с точки зрения улучшения пользовательского опыта работы с продуктом. В некоторых местах не хватало поиска по пользователям. Нужно было дать возможность добавить пользователя в локальную группу из LDAP и других протоколов сразу в нескольких, связанных с панелью администрирования местах (в настройках конкретного проекта, в настройках пользователя и т.п.). Все участники этого проекта с нашей стороны сейчас занимаются развитием продукта, и у них есть общее понимание, как он должен масштабироваться на крупные внедрения процесса безопасной разработки. Мы работаем над очередной ещё более глобальной модернизацией архитектуры всего приложения, которое позволит его масштабировать и изменять более гибко, сделает более универсальной развёртку и проще взаимодействие для пользователей. Это заключительная часть цикла статей о построении процесса безопасной разработки в крупном ритейлере. Будем рады ответить на вопросы и узнать о вашем опыте реализации практик безопасной разработки в комментариях! Автор: Иван Старосельский, руководитель отдела эксплуатации и автоматизации информационных систем =========== Источник: habr.com =========== Похожие новости:
Блог компании Ростелеком-Солар ), #_informatsionnaja_bezopasnost ( Информационная безопасность ), #_sovershennyj_kod ( Совершенный код ), #_upravlenie_produktom ( Управление продуктом ), #_soft ( Софт ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 09:07
Часовой пояс: UTC + 5