Так как тема реверс инжиниринга довольно популярна на хабре, решил поделиться своими наработками по этой теме. Мне, как и многим любителям визуальных новелл, знакома такая программа, как AGTH (Anime-Game-Text-Hooker). Она позволяет извлекать текст из новелл для последующего перевода(большинство игр – японские). Разработка этой программы, судя по всему, была прекращена ещё в 2011м году, исходников найти не удалось, а так как душа хотела дополнительных фич, было принято решение отреверсить эту программу и на основе полученных данных воссоздать альтернативную оболочку со всеми недостающими мне функциями.
Сергей @HSerg
Разработчик
Вся правда о битых пикселях
7 min
332KБитые пиксели — один из самых острых вопросов, нередко становящийся поводом для бурного выяснения отношений с поставщиками ЖК-мониторов, планшетов и смартфонов. От этой проблемы зачастую спешат откреститься менеджеры фешенебельных магазинов, ссылаясь на регламент официальных производителей. На том, что такое «битые» пиксели, и как с ними бороться «один на один», мы остановимся в этой статье.


+31
Компромиссы микросервисов
16 min
33KTranslation
От переводчика: с момента выхода популярной статьи Мартина Фаулера «Микросервисы» (перевод на Хабре) прошло уже достаточно времени, чтобы автор смог дополнить свои наблюдения свежим опытом проектирования и разработки микросервисов в различных компаниях, и рассказать о нем в новом посте, чей перевод представляется вашему вниманию.
Многие команды разработчиков нашли архитектурный стиль микросервисов подходом, превосходящим монолитную архитектуру; другие команды выяснили, что для них микросервисы — лишняя обуза, подрывающая производительность разработки. Как и у любого стиля архитектуры, у микросервисов есть свои плюсы и минусы. Для того, чтобы делать осознанный выбор, вы должны понимать эти свойства и уметь рассматривать их на фоне собственных конкретных условий.

Микросервисы дают преимущества… | …ценою издержек |
---|---|
Жесткие границы модулей Strong Module Boundaries Микросервисы усиливают модульную структуру, что особенно важно для больших команд разработчиков. |
Распределённость Distribution Распределенные системы тяжелее программировать, поскольку удаленные вызовы медленные и всегда рискуют неудачей-отказом. |
Независимый деплоймент Independent Deployment Простые сервисы проще деплоить, и, поскольку они автономны, меньше вероятность отказа системы в случае, если что-то идет не так. |
Консистентность в конечном счете Eventual Consistency Поддержка cтрогой консистентности чрезвычайно сложна для распределённых систем, и это означает, что придется иметь дело с консистентностью в конечном счете. |
Технологическое разнообразие Technology Diversity С микросервисами вы можете смешивать несколько языков, фреймворков и технологий хранения данных. |
Эксплуатационная сложность Operational Complexity Вам потребуется опытная команда эксплуатации для управления множеством сервисов, которые будут регулярно редеплоиться. |
+22
Как реализовать конвертацию из растра в черно-белый вектор на сайте
3 min
26KВсе графические файлы делятся на два глобальных типа — растровые и векторные. Иногда нужно сделать конвертацию из растра в черно-белый вектор. Например, для трассировки черно-белых иконок, QR-кодов, штрих-кодов, картинок с растровыми надписями, чеков или картинок в блоге.


+14
StorIO — человеческий API для работы с SQLiteDatabase и ContentResolver
3 min
14KНе секрет, что API SQLiteDatabase и ContentResolver — отстой, поэтому многие стараются от них абстрагироваться. Кто-то выбирает ORM, кто-то DAO, кто-то пишет своё.
За долгие годы Android разработки мы прошли через все эти этапы: ORM часто становится узким местом в критический для проекта момент, своё DAO требует тестирования и разработки, что отнимает много времени, которое можно было тратить на другие детали реализации приложения, готовые DAO в принципе решают вопрос, но различные библиотеки имеют свои плюсы и минусы (15стандартов.jpg), посмотрите, что предлагаем мы:
1. API для людей: удобные билдеры (помните 5-7 nullов в запросах?), читаемые и очевидные конструкции, Immutability и Thread-safety.
2. Упрощенный набор операций: вместо стандартного CRUD (Create-Read-Update-Delete или Insert-Select-Update-Delete) мы предлагаем три операции — Put, Get, Delete, при этом вы имеете полный контроль над их реализацией, можете, например, упороться и хранить один объект в нескольких таблицах и так далее.
3. Опциональный Type-Safe Object Mapping без Reflection, но если вы хотите работать с Cursor или ContentValues — пожалуйста.
4. Некая схожесть с Retrofit: вы можете выполнить любую операцию как блокирующий вызов либо как rx.Observable, мы можем добавить callback модель выполнения операций в будущем.
5. Reactive — Observable из Get операции будет получать уведомления об изменении таблиц в случае SQLite или Uri в случае ContentResolver, это позволяет полностью заменить лоадеры, API которых просто отвратителен.
За долгие годы Android разработки мы прошли через все эти этапы: ORM часто становится узким местом в критический для проекта момент, своё DAO требует тестирования и разработки, что отнимает много времени, которое можно было тратить на другие детали реализации приложения, готовые DAO в принципе решают вопрос, но различные библиотеки имеют свои плюсы и минусы (15стандартов.jpg), посмотрите, что предлагаем мы:
1. API для людей: удобные билдеры (помните 5-7 nullов в запросах?), читаемые и очевидные конструкции, Immutability и Thread-safety.
2. Упрощенный набор операций: вместо стандартного CRUD (Create-Read-Update-Delete или Insert-Select-Update-Delete) мы предлагаем три операции — Put, Get, Delete, при этом вы имеете полный контроль над их реализацией, можете, например, упороться и хранить один объект в нескольких таблицах и так далее.
3. Опциональный Type-Safe Object Mapping без Reflection, но если вы хотите работать с Cursor или ContentValues — пожалуйста.
4. Некая схожесть с Retrofit: вы можете выполнить любую операцию как блокирующий вызов либо как rx.Observable, мы можем добавить callback модель выполнения операций в будущем.
5. Reactive — Observable из Get операции будет получать уведомления об изменении таблиц в случае SQLite или Uri в случае ContentResolver, это позволяет полностью заменить лоадеры, API которых просто отвратителен.
+12
Приручаем JMeter
6 min
162K
+24
Разбор форматов: упакованные хешированные ресурсы
9 min
19K
В прошлых двух статьях я рассказал об особенностях форматов данных звуковой подсистемы современных игр. Чтобы не утомлять читателей, перейду к несколько другой теме. Какой бы движок не использовала игра, ей нужно где-то хранить ресурсы и извлекать их оттуда в нужный момент. Иногда ресурсы в архиве имеют как идентификатор, так и читабельное имя файла. Но существует довольно много движков, где имён у файлов нет, а есть только хеш. Как же в таком случае можно что-то разобрать в ресурсах?
Рассмотрим это на примере довольно редкого движка bitsquid. Он простой и компактный, но, тем не менее, имеет все необходимые для современных игр возможности. В прошлом году bitsquid вместе с его разработчиком был куплен компанией Autodesk, и теперь они собираются скрестить его с Maya и сделать свой собственный игровой движок, который, как они обещают, будет чем-то невероятным.
+22
Разбираемся с поддержкой x64 в WPE Pro
9 min
54K
Думаю, что большинство из местных обитателей знакомы с понятием сниффера. Несмотря на то, что конечная цель у них одна и та же (перехват пакетов, соответствующих определённым критериям), достигают они её совершенно разным образом. Какой-то софт слушает указанный сетевой интерфейс (например, Wireshark, где это реализовано при помощи библиотеки Pcap), а какой-то — перехватывает вызовы ответственных за взаимодействие с сетью WinAPI-функций. И у того, и у другого метода есть свои плюсы и минусы, однако если по задаче необходим перехват пакетов от конкретного заранее известного приложения, то второй вариант, как правило, банально удобнее. В этом случае нет нужды узнавать IP-адреса и порты, которые использует данная программа (особенно учитывая тот факт, что их может быть довольно много), и можно просто сказать «я хочу перехватывать все пакеты вот этого приложения». Удобно, не правда ли?
Пожалуй, самым популярным на сегодняшний день сниффером, работающим по принципу перехвата вызовов определённых WinAPI-функций, является WPE Pro. Возможно, многие из вас слышали о нём на различных форумах, посвящённых онлайн-играм, ведь именно для получения преимуществ в различных играх этот сниффер в большинстве случаев и используется. Свою задачу он выполняет прекрасно, однако у него есть один неприятный недостаток — он не умеет работать с 64-битными приложениями. Так уж вышло, что по одной из возникших задач мне как раз понадобилось перехватывать пакеты от 64-битного приложения, и я посмотрел в сторону Wireshark. К сожалению, использовать его в данной ситуации было не очень удобно — исследуемое приложение отправляло данные на разные IP-адреса, каждый раз открывая новый порт. Погуглив немного, я обнаружил, что готовых аналогов WPE Pro с поддержкой x64 нет (если они всё же есть, буду признателен за ссылки в комментариях — обратите внимание, что речь идёт о Windows). Автор WPE Pro не оставил никаких контактных данных на официальном сайте и в самом сниффере, так что я принял решение разобраться в этом вопросе самостоятельно.
Как протекал процесс и что из этого вышло, читайте под катом.
+26
+7
Почему я не преподаю SOLID и «принцип устранения зависимостей»
5 min
65KTranslation
Статья 1. Почему я не преподаю SOLID
Если вы разговариваете с кем-то, кому небезразлично качество кода, уже достаточно скоро в разговоре всплывёт SOLID — аббревиатура, помогающая разработчикам запомнить пять важных принципов объектно-ориентированного программирования:

SOLID полезен. Его разработали знатоки в нашей области. Он помогает людям рассуждать о дизайне. Помогает создавать системы, устойчивые к изменениям.
Раньше SOLID был краеугольным камнем моего набора средств проектирования. Я делал все возможное, чтобы сделать мой код как можно более SOLID. Я учил других поступать так же.
Сегодня SOLID остается для меня важным, но я больше не пытаюсь сделать мой код SOLID. Я редко упоминаю его, когда говорю про дизайн. И тем более я не учу пользоваться им разработчиков, которым хочется почерпнуть хорошие дизайнерские методы проектирования. Он больше не находится у меня под рукой в моем «ящике для инструментов». Он лежит в пыльной коробке на чердаке. Я храню его, потому что он важен, но редко им пользуюсь.
+37
Howto Qemu-kvm Debian 8
4 min
52KВ этом howto мы с вами просто и быстро, шаг за шагом, запустим гипервизор Qemu-KVM в debian 8.

Будем запускать виртуальную машину в qemu-kvm от пользователя username, используя spice, qxl и virtio.
Предполагается, что установлен Debian 8 amd64, с выбранными в tasksel стандартными утилитами и SSH сервером. Доустановим.
Будем запускать виртуальную машину в qemu-kvm от пользователя username, используя spice, qxl и virtio.
Предполагается, что установлен Debian 8 amd64, с выбранными в tasksel стандартными утилитами и SSH сервером. Доустановим.
aptitude install -y firmware-linux bridge-utils etckeeper
+12
Как считается Load Average
7 min
103KПостановка вопроса
Недавно, во время собеседования в одну крупную компанию мне задали простой вопрос, что такое Load Average. Не знаю, на сколько правильно я ответил, но лично для себя пришло осознание, что точного ответа я на самом деле и не знаю.
Большинство людей наверняка знают, что Load Average — это среднее значение загрузки системы за некоторый период времени (1, 5 и 15 минут). Так же можно узнать некоторые подробности из данной статьи, про то, как этим пользоваться. В большинстве случаев этих знаний достаточно для того, что бы по значению LA оценивать загрузку системы, но я по специальности физик, и когда я вижу «среднее за промежуток времени» мне сразу становится интересна частота дискретизации на данном промежутке. А когда я вижу термин «ожидающие ресурсов», становится интересно, каких именно и сколько времени надо ждать, а так же сколько тривиальных процессов надо запустить, что бы получить за короткий промежуток времени высокий LA. И главное, почему ответы на эти вопросы не дает 5 минут работы с гуглом? Если вам данные тонкости так же интересны, добро пожаловать под кат.
+62
DDoS атака в обход Qrator. Как защититься?
4 min
27KЕсть сервисы, защищающие нас от DDoS атак. Они работают по принципу прокси: в DNS прописывается их IP, они фильтруют трафик и проксируют на ваш сервер. Все они настоятельно рекомендуют прятать свой IP и в публичном доступе давать только IP прокси-защитника. Вполне здравый подход, достаточный для успешной защиты. А я расскажу на чем можно проколоться и как от этого защитится.
+33
Чтобы сайт не падал: экономный метод
5 min
45K
Сайты падают. Я работаю в хостинге 7 лет и последние 5 лет (кроме всего прочего) предоставляю услуги по географически-распределённым кластерам, чтобы при аварии в одном из дата-центров сайт продолжил работу в другом. На выходе такое решение стоит минимум от 4 тысяч рублей в месяц за 1 виртуальный сервер. Небольшому интернет-магазину это может оказаться дорого для «страховки», которая потребуется 1-3 раза в год, а если повезет — не потребуется совсем. Соответственно, многим нужен вариант дешевле, подходящий для малого и среднего бизнеса. Сейчас расскажу, как это решить очень и очень просто.
+26
О возможностях RAW для новичков
9 min
115KКамеры и разнообразнейшие мобильные гаджеты, умеющие фотографировать, уже стали привычными предметами повседневности. Кому сейчас придёт в голову, например, переписывать какой-то нужный текст, когда можно просто достать смартфон и отщёлкать нужные страницы? Зачем пытаться объяснить на словах, как выглядит что-то, если можно это что-то отснять и потом просто предъявить фото на планшете? Сегодня фотографировать не умеют разве что пылесосы — и то не факт, что скоро производители не научат делать это и их тоже. Вон, камеры, не требующие питания, уже сделали.

Совершенно закономерным этапом совершенствования цифровой техники стал тот факт, что формат RAW вырвался из рамок профессиональных зеркальных фотоаппаратов и стал появляться и в «мыльницах», компактах и даже в смартфонах/планшетах. И если вы являетесь обладателем девайса, поддерживающего функцию съёмки в RAW, но не знаете, что это и с чем это едят — вам под кат. Формат RAW — довольно интересная и дающая массу творческих возможностей штука, хотя и требующая умения с собой обращаться…
Пост расчитан на новичков и тех, кто совершенно не в теме RAW-файлов. Любители фотографии вряд ли найдут здесь для себя что-либо новое, но могут помочь новичкам в комментариях. ;)
Achtung! Под катом тяжеловесные GIF'ки.

Совершенно закономерным этапом совершенствования цифровой техники стал тот факт, что формат RAW вырвался из рамок профессиональных зеркальных фотоаппаратов и стал появляться и в «мыльницах», компактах и даже в смартфонах/планшетах. И если вы являетесь обладателем девайса, поддерживающего функцию съёмки в RAW, но не знаете, что это и с чем это едят — вам под кат. Формат RAW — довольно интересная и дающая массу творческих возможностей штука, хотя и требующая умения с собой обращаться…
Пост расчитан на новичков и тех, кто совершенно не в теме RAW-файлов. Любители фотографии вряд ли найдут здесь для себя что-либо новое, но могут помочь новичкам в комментариях. ;)
Achtung! Под катом тяжеловесные GIF'ки.
+60
9 анти-паттернов, о которых должен знать каждый программист
9 min
151KTranslation
В программировании самокритика – это умение распознать контрпродуктивные решения в дизайне, коде, процессах и поведении. Знание о вредных шаблонах решений полезно для программиста. В этой статье я опишу анти-паттерны, которые я встречал на своём личном опыте время от времени.
Некоторые из них напрямую или косвенно связаны с когнитивными искажениями человеческого сознания – в этих случаях я даю ссылки на соответствующие вики-статьи. Также интересен список известных когнитивных искажений.
Оптимизация, проводимая до того, как у вас есть вся информация, необходимая для принятия взвешенных решений по поводу того, где и как нужно её проводить.
На практике сложно предсказать, где встретится узкое место. Попытки навести оптимизацию до получения эмпирических результатов приведут к усложнению кода и появлению ошибок, а пользы не принесут.
Сначала пишите чистый, читаемый, работающий код, используя известные и проверенные алгоритмы и инструменты. При необходимости используйте инструменты для профилирования для поиска узких мест. Полагайтесь на измерения, а не на догадки и предположения.
Некоторые из них напрямую или косвенно связаны с когнитивными искажениями человеческого сознания – в этих случаях я даю ссылки на соответствующие вики-статьи. Также интересен список известных когнитивных искажений.
1 Преждевременная оптимизация
В 97% случаев надо забыть об эффективности малых частей программы: преждевременная оптимизация – корень всех зол. Но в 3% случаев об оптимизации забывать не нужно.
Дональд Кнут
Хотя никогда зачастую лучше, чем прямо сейчас
Тим Питерс, Зен языка Python
Что это
Оптимизация, проводимая до того, как у вас есть вся информация, необходимая для принятия взвешенных решений по поводу того, где и как нужно её проводить.
Почему плохо
На практике сложно предсказать, где встретится узкое место. Попытки навести оптимизацию до получения эмпирических результатов приведут к усложнению кода и появлению ошибок, а пользы не принесут.
Как избежать
Сначала пишите чистый, читаемый, работающий код, используя известные и проверенные алгоритмы и инструменты. При необходимости используйте инструменты для профилирования для поиска узких мест. Полагайтесь на измерения, а не на догадки и предположения.
+77
Сравнение Security Enhanced NGINX и Hiawatha Web Server при отражении атак 7 уровня (BOTS/SQL/XSS etc.)
5 min
17KДобрый день.
В завершение «недели NGINX», мы решили рассказать об очень интересной сборке «безопасной» версии NGINX китайской компании Neusoft, о которой не было замечено ни одной статьи на Хабре, а именно — SeNginx. В дополнение к этому, мы также расскажем вам о втором веб сервере, которому не уделяется так много внимания, как Nginx — Hiawatha Web Server, и постараемся сравнить Hiawatha с SeNginx в плане использования их для обеспечения безопасности вашего сайта или web приложения.

Отметим, что за 5 лет существования нашей хостинговой компании нам довелось повидать целый спектр атак различных уровней и типов на сайты и web приложения наших клиентов, а также поработать с London Metropolitan Police в поиске и поимке одного управляющего ботнетом. Сегодня DDoS атаки стали настолько частыми, что только за вчерашний день Arbor в одном из наших датацентров зафиксировал 49 DDoS атак 3/4 уровней мощностью до 20-25 Gbit/s (график 1 и график 2). И, хотя Arbor девайсы и могут при определенной настройке неплохо справляться с атаками 3 и 4 уровня, они практически бесполезны при атаках 7 уровня, целью которых является перегрузка ресурсов сервера, а также поиск уязвимостей в вашем приложении.
Самым бюджетным вариантом отражения атак 7 уровня являются различные варианты с использованием DNS RoundRobin + HaProxy, Nginx, Varnish Cache и т.д., которые либо позволяют рассредоточить атаку между несколькими серверами клиента, либо дают возможность обработать запросы ботов «в лоб» с помощью отдачи кешированной версии страницы. Данный подход, к сожалению, часто требует ручной настройки, постоянного мониторинга и редко эффективен при меняющихся типах атак.
Наглядное представление DNS RoundRobin + Nginx (источник):

После длительных поисков нами был найден отличный модуль к NGINX, написанный русскими программистами на Perl в 2012 году и позволяющий фильтровать ботов, которые заходят на ваш сайт в автоматическом режиме — Roboo (статья на Хабре). Модуль показал себя с наилучшей стороны, позволяя фильтровать сотни тысяч запросов от ботов с помощью NGINX с минимальной нагрузкой на сервер.
В завершение «недели NGINX», мы решили рассказать об очень интересной сборке «безопасной» версии NGINX китайской компании Neusoft, о которой не было замечено ни одной статьи на Хабре, а именно — SeNginx. В дополнение к этому, мы также расскажем вам о втором веб сервере, которому не уделяется так много внимания, как Nginx — Hiawatha Web Server, и постараемся сравнить Hiawatha с SeNginx в плане использования их для обеспечения безопасности вашего сайта или web приложения.


Отметим, что за 5 лет существования нашей хостинговой компании нам довелось повидать целый спектр атак различных уровней и типов на сайты и web приложения наших клиентов, а также поработать с London Metropolitan Police в поиске и поимке одного управляющего ботнетом. Сегодня DDoS атаки стали настолько частыми, что только за вчерашний день Arbor в одном из наших датацентров зафиксировал 49 DDoS атак 3/4 уровней мощностью до 20-25 Gbit/s (график 1 и график 2). И, хотя Arbor девайсы и могут при определенной настройке неплохо справляться с атаками 3 и 4 уровня, они практически бесполезны при атаках 7 уровня, целью которых является перегрузка ресурсов сервера, а также поиск уязвимостей в вашем приложении.
Самым бюджетным вариантом отражения атак 7 уровня являются различные варианты с использованием DNS RoundRobin + HaProxy, Nginx, Varnish Cache и т.д., которые либо позволяют рассредоточить атаку между несколькими серверами клиента, либо дают возможность обработать запросы ботов «в лоб» с помощью отдачи кешированной версии страницы. Данный подход, к сожалению, часто требует ручной настройки, постоянного мониторинга и редко эффективен при меняющихся типах атак.
Наглядное представление DNS RoundRobin + Nginx (источник):

После длительных поисков нами был найден отличный модуль к NGINX, написанный русскими программистами на Perl в 2012 году и позволяющий фильтровать ботов, которые заходят на ваш сайт в автоматическом режиме — Roboo (статья на Хабре). Модуль показал себя с наилучшей стороны, позволяя фильтровать сотни тысяч запросов от ботов с помощью NGINX с минимальной нагрузкой на сервер.
+16
Когда правила повышения конверсии не работают: 7 грандиозных провалов
5 min
8.7K
Существуют десятки способов повышения конверсии. Некоторые из них считаются чуть ли не «священными»:
— Избавляйтесь от слайдеров — они отвлекают;
— Делайте посадочную страницу как можно более короткой — пользователи не любят «портянки»;
— Просто увеличьте размер кнопки CTA, и будет вам счастье.
И еще много-много «правил», «законов», «стратегий».
Да, они взяты не из воздуха, а на основании практики и тестирования. Но то, что работает у большинства, может не сработать у вас. При этом мы настолько привыкли к каким-то положениям, что обратный результат воспринимается как сенсация.
В этой статье мы сделали перевод подборки от экспертов ConversionXL — это разрыв шаблона, 7 невероятных примеров, когда результаты a/b тестов опровергают самые «железные» приемы увеличения конверсии.
+10
NGINX изнутри: рожден для производительности и масштабирования
8 min
149KTranslation

Инфографика Inside NGINX сверху вниз проведет вас по азам устройства процессов к иллюстрации того, как NGINX обрабатывает множество соединений в одном процессе. Данная статья рассмотрит всё это чуть более детально.
+93
Как связать Docker-контейнеры, не заставляя приложение читать переменные окружения
5 min
53KDocker, если кто умудрился об этом ещё не слышать — фреймворк с открытым исходным кодом для управления контейнерной виртуализацией. Он быстрый, удобный, продуманный и модный. По сути он меняет правила игры в благородном деле управления конфигурацией серверов, сборки приложений, выполнения серверного кода, управления зависимостями и много ещё где.
Архитектура, которую поощряет Docker — это изолированные контейнеры, каждый из которых выполняет одну команду. Эти контейнеры должны знать только как друг друга найти — другими словами, о контейнере нужно знать его fqdn и порт, или ip и порт, то есть, не более, чем о любой внешней службе.
Рекомендованный способ сообщить такие координаты внутрь процесса, выполняемого в Docker — переменные окружения. Типичный пример этого подхода, не применительно к докеру —
И вот переменные окружения позволяют приложению внутри контейнера удобно и непринуждённо найти базу данных. Но для этого, человек, который пишет приложение, должен об этом знать. И хотя конфигурация приложения с помощью переменных окружения — это хорошо и правильно, иногда приложения написаны плохо, а запускать их как-то надо.
Архитектура, которую поощряет Docker — это изолированные контейнеры, каждый из которых выполняет одну команду. Эти контейнеры должны знать только как друг друга найти — другими словами, о контейнере нужно знать его fqdn и порт, или ip и порт, то есть, не более, чем о любой внешней службе.
Рекомендованный способ сообщить такие координаты внутрь процесса, выполняемого в Docker — переменные окружения. Типичный пример этого подхода, не применительно к докеру —
DATABASE_URL
, принятый во фреймворке Rails или NODE_ENV
принятый в фрейворке Nodejs.И вот переменные окружения позволяют приложению внутри контейнера удобно и непринуждённо найти базу данных. Но для этого, человек, который пишет приложение, должен об этом знать. И хотя конфигурация приложения с помощью переменных окружения — это хорошо и правильно, иногда приложения написаны плохо, а запускать их как-то надо.
+10
Information
- Rating
- 5,890-th
- Registered
- Activity
Specialization
Specialist
Lead