LINUX.ORG.RU

Сообщения upcFrost

 

Ищу ПМ-софт для реальной жизни

Форум — Talks

Сабж. Я понимаю что project management и реальность связаны только в фантазии ПМа, но мало ли.

От софта нужно два основных режима: план времени/ресурсов и их трекинг.

В плане помимо прочего нужны:

  • прямые зависимости (без А нет Б и поставить его в план нельзя)
  • обратные зависимости (если Б сильно позже А - будет веселый мерж на пару дней)
  • процент времени на задаче (тестировщик чихнул, разработка переделывает, хотя уже начата другая задача)
  • оценка в днях (без минут как в жире)
  • коэффициент «реальности» и планирование ресурсов (один хрен никто не даст 100% времени работать)
  • гантт для тех кто не умеет читать
  • автоплан был бы збс

В трекинге нужно по сути иметь ответ на два вопроса - когда будет и почему опять поздно.

  • Нужно иметь возможность добавлять вечно приходящий со стороны пиндец (задачи) и на основе этого сдвигать проектные тайминги
  • соответственно нужен «break out», когда задача встаёт чтоб разработка переключилась тушить новый пожар
  • нужна сверка план-реальность и проекция плана, соответственно
  • Трек реального времени на задаче не нужен - его один хрен никто не заполняет, только примерно (30% дня, например).
  • Очень нужна графа «просрано на невероятно полезные митинги», чтоб не выглядело что 25% времени разработка репу чешет.

Основная проблема с первым пунктом. По плану все збс но вечно приходят задачи типа «мне срочно тебе легко», и нужно чётко показывать чем это «легко» грозит (мне не жалко, время оплачено, но потом не надо удивляться что тайминги поплыли)

Смотрел жиру и её плагины типа bigpicture, везде очуменный оверхед, я по факту код вообще писать перестану чтоб это всё настроить и поддерживать. В итоге пока нафигачил на гуглотаблице, но там понятно, как на бумажке рисовать. Да и на 10 человек я потяну, а дальше жопа.

Не обязательно попенсорц, можно за деньги (адекватные), можно онлайн, пофиг. Интеграция с жирой плюс но можно и без неё. Возможность ставить трекинг с телефона на стендапе очень большой плюс.

Падскажите короче, шпасибо

 , , ,

upcFrost
()

Добавить кастомную фичу к spandsp и freeswitch

Форум — Job

Привет. Ищем кого-нибудь кто может добавить небольшую кастомную фичу к spandsp и freeswitch. Spandsp это soft-dsp, который часто используется asterisk и подобными атс для отправки факсов, грубо говоря берет картинку в tiff и делает из нее например сигнал для T.30-факса. Ну а freeswitch это собственно атс.

Суть фичи - при приеме факса spandsp построчно (и постранично) пишет его в tiff, после чего получаем один толстый файл. Хочется две вещи:

  • Часть в spandsp - чтоб помимо этого файла он также писал страницы отдельными файлами (и основной файл тоже, одно другого не отменяет)
  • Часть в freeswitch
    • чтоб это поведение контролировалось конфигом (вкл/выкл)
    • чтоб после приема страницы когда уходит эвент что страничка принята (это кусок mod_spandsp) в этом эвенте также опционально прилетал путь к страничке на диске (который потом консьюмер эвента будет обрабатывать, то это не относится к задаче)

Язык - сишка (spandsp) и кресты (freeswitch).

Ценник, сроки, приемка, оплата и прочее обсуждаемы, пишите в телегу, ник тот же. Один небольшой нюанс - очень желательно знать английский, по-русски в компании кроме меня никто не говорит. Но в целом могу переводить, не проблема

Upd: Мде, и тишина. А я думал крестоеды тут ещё не вымерли.

 , , ,

upcFrost
()

Формирование ответа на мутацию в graphql

Форум — Development

Подскажите, как правильно задать ответ на мутацию в gql? Суть - есть некий объект User

type User {
  address: Address
  status: Status
  inventory: Inventory 
}

Все поля - комплексные типы, например в каждом есть поля x и y. Вложенность может быть уровней на 10-15, полей в жизни тоже не 3, а 33.

Есть мутация, которая изменяет например поля x и y из Address и поле x.x из Status.

type Mutation {
  updateAddress(...): ????
}

Как правильно написать тип ответа чтоб для фронтенда было очевидно что именно поменялось в объекте?

В плане я понимаю что можно просто вернуть объект и фронт может сам запросить что угодно, но запрашивать сразу 100500 полей чтоб понять что там поменялось им самим нафиг не надо. Хз, например указывать типом ответа интерфейс с нужным набором полей и потом указывать что User его имплементит? Или как-то вручную формировать ответ, но при этом на клиенте может влет сломаться кеш из-за несоответствия типов.

С интерфейсом вроде красиво, но плодить по интерфейсу на каждую мутацию и потом дружно пихать их в implements это как-то хз

В чатгпт пока не ходил, но в доке и best practices явного ответа не нашёл

Апд; потыкал чатгпт, он традиционно несёт чушь с передачей списка изменений в ответе прям текстовым полем, и на призывы что мутация блин меняет всегда один и тот же сабсет он не реагирует.

Пока самым логически корректным выглядит вариант с интерфейсами типа

Mutation updateAddress(...): UserWithAddressAndStatus

type User implements UserWithAddressAndStatus {
  ...
}

Из интерфейса сходу видно что именно поменялось, ну и понятен родитель. Но количество таких интерфейсов немного пугает. Да и перечислять в имени интерфейса изменения как-то больно

 ,

upcFrost
()

Почему люди все время пытаются изобрести велосипед

Форум — Talks

Tl;dr прежде чем героически писать свой велосипед на пару дней желательно просто немного почитать код и подумать

У меня прям пичот от этой хрени. Суть - есть либца, есть разраб которому её нужно заюзать. Либца уже используется в хвост и в гриву, нужно добавить один флаг чтоб строка в выводе была зачеркнута. Разраб ставит флаг и… и нихрена, не зачеркивает. Вот не зачеркивает и все.

Разраб начинает чесать репу и изобретать велосипед через функции рисования. Почему, почему блин так сложно открыть исходник либы и посмотреть что именно для этого варианта метода вывода текста зачеркивание не определено, а для всех остальных восьми вариантов оно работает. Ну забыли его блин, ctrl+c, ctrl+v, там 5 строк, неужели так сложно? Не, это для слабых, лучше просрать пару дней сношаясь с рисованием и метриками шрифта.

Все, выдохнул

 ,

upcFrost
()

Ищу анализатор для Т.30 факсов

Форум — Admin

Собственно ищу сабж. Именно Т.30, не Т.38 (его и wireshark умеет). Суть - есть pcap с записью сессии (либо 2-channel wav можно достать), нужно разобрать его по командам Т.30 чтоб понять почему в конце что-то резко пошло не так (например Б-номер начал слать команды управления пока А-номер все еще слал данные).

На попенсорц и халяву особо не рассчитываю, так что коммерческий софт welcome. fax_decode из набора spandsp пробовал, но он может расшифровать только А-номер и там на вид все ок.

Гуглить гуглил, писал в gl, ngcom, zoltes, короче везде где видел подобный софт, но меня все проигнорили (по крайней мере пока).

Апд: получил ответ от gl, кому интересно - 4500 нерублей. Но там коробка (в плане физический блок-дешифратор), и только под win. Если остальные так и будут молчать - видимо на безрыбье и водолаз рыба, но блин коробку прям ппц как не хочется, это масса геморроя

Адп2: вернулся QualityLogic, 15500 нерублей софт. Ок, на это я начальника уже вряд ли продавлю

 , , ,

upcFrost
()

Подскажите либу чтоб формировать multipart email

Форум — Development

Сабж. Нужно следующее: что оно формировалось потоком и собирало файл который можно также потоком читать. Без засасывания аттачей в память и прочего ужаса. Аттачи тоже на диске лежат.

Язык - пистон, кресты, сишка (прокладку напишу, не первый раз).

Суть: Штатный email/smtplib питона так не может (он сосёт в память все что есть), писать под него кастомный генератор ещё больнее чем просто захардкодить темплейт сообщения. Плюс нет asyncio. Aiosmtplib работает через email и тоже не может. Проще всего отодрать от него протокол, обернуть в сабкласс и пихать туда файл потоком

 , , ,

upcFrost
()

Минутка ненависти

Форум — Talks

Чтение байт-потока в autoresizable буфер целиком без всякого контроля над размером, а также реализацию такой возможности в языке без варнингов для особо невнимательных, нужно приравнивать к госизмене

tl;dr file.read() = расстрел

У меня все, продолжаю наблюдение

 

upcFrost
()

Ищу s3-compat сервер для тестовых окружений

Форум — Development

Сабж. Основные требования - возможность быстро развернуть/убрать (в идеале helm chart), минимум потребления памяти, не более 128 метров, в идеале ещё меньше. Ну и собственно upload/download.

Что не нужно - мегапроизводительность, отказоустойчивость, life cycles, репликация, персистентность, гуец, вот это все.

Суть: Тестовая ветка живёт пару дней, максимум 3 недели если qa в отпуске или в завале. Юзер по сути один, максимум два. Веток бывает много, плодить пачками тот же minio не очень (жирноват). Разные бакеты на одном сервере держать тоже не круто т.к. начинаются проблемы с чисткой, названиями бакетов и уходом от модели данных в проде.

 ,

upcFrost
()

Посоветуйте лёгкую в плане поддержки и ресурсов MQ

Форум — Development

Сабж. Клиент будет на питоне. Основная цель - минимум геморроя в плане поддержки и, желательно, в плане ресурсов. Как доп условие - нужна нормальная поддержка cross-dc, ввиду чего redis streams к сожалению отлетает.

Пример того что точно не нужно (имхо) - кафка. Жрёт ресурсы, вечный геморрой с настройкой-донастройкой, требует выделенного админа (которого нет)

Хороший пример (опять же имхо) - redis streams, но между цодами там есть проблемы и тормоза, редис всё-таки не для этого существует

Гарантия доставки нужна, объем сообщений где-то 20-40 штук в секунду, не особо много

 ,

upcFrost
()

Объясните тупому как «корректно» юзать grpc в питоне

Форум — Development

Сабж. Суть - нигде нет нормального примера, как и в большинстве питонодоков. Разбор что и как все время идет на неком сферическом хелловорлде в вакууме, который запускается через if __name__ == "__main__" и живет 5 секунд. И по итогу нифига не понятно как, например, корректно использовать клиент во взаимодействии между серверами.

Пример: есть 3 сервиса (А, Б, В). Для простоты пусть А - гейт, а Б и В содержат бизнес-логику. У каждого сервиса есть несколько нод. Ноды внезапно могут упасть, затупить, пойти в отказ и т.д. Как правильно написать скажем ручку для фласка на А чтоб она ходила в Б и В?

Что значит «правильно»:

  • например дока говорит «канал нужно переиспользовать как можно дольше»; можно ли его скажем держать в статической переменной, или threadlocal, или когда вообще его нужно закрывать; также канал - это p2p или разные субканалы могут подключаться к разным конечным нодам (в случае если одна например приляжет)?
  • какие у канала есть опции и как их предполагается использовать? это про тот жирный жсон в котором например идет grpc.service_config. Предполагается ли что разработчик сервиса А должен знать что там происходит в Б или все-таки разработчик сервиса Б это должен как-то донести, например опциями?
  • как корректно сделать retry?
  • как правильно передать кастомную ошибку и какой код при этом юзать?
  • как правильно передавать хедеры и например отслеживать время исполнения запроса, особенно для stream-stream? как вообще предполагается делать distributed tracing?
  • как черт возьми корректно распространять протобуфную спеку?

Кто-нибудь знает где есть хоть какая-то адекватная документация по всем параметрам, практикам и прочему? желательно с примерами. А то тот же methodConfig и как его готовить приходится кусками собирать по исходникам и разным сайтам типа SO, при том часто оказывается что то что есть в доке, в спеке и в жизни - сильно разные вещи. Например тот же hedged call в доке есть, и даже структура под него есть, а реализации этого добра нема.

p.s. если что все написанное у меня реализовано, вопрос не в том «как сделать», а в том «как сделать правильно».

 ,

upcFrost
()

Many-to-many в одной коллекции в монге

Форум — Development

Подскажите как можно удобно в монге реализовать такую штуку: если пачка объектов (на уровне бизнес-логики, не базы), которые имеют поля to и from. Поля - массивы id таких же объектов, при этом связанные: добавление нового ID в to объекта A должно быть зеркально отражено в from объекта Б. По частоте запросов поле to нужно сильно чаще, поле from видят не все.

В данный момент сделал так: каждый элемент в базе имеет только поле to, а from считается агрегацией через поля to других записей. Плюсы - просто, консистентно. Минусы - хз как в один запрос к базе сделать update+get чтоб вернуть from, и вот как раз в update его возвращать нужно на уровне API. Пока сделано так - update+get достаёт to, дальше from приходит сбоку перед отправкой фронтенду. Плюс в апдейте идут два запроса - update+get на объект плюс bulk update на связанные объекты (добавление+удаление). Можно конечно все сделать в один update, но он значение не возвращает, и имхо мутирующий метод для одного элемента должен возвращать изменённый объект.

Подскажите как сделать лучше? В целом update не так чтоб часто использовали, так что может быть over-engineering. Думал про aggregate+merge, но это выглядит диким костылем

 ,

upcFrost
()

Protobuf для запросов с большим числом вариантов

Форум — Development

Привет, подскажите как лучше всего реализовать схему для сабжа. Суть - запрос для отправки уведомлений. Язык - питон+proto3. Уведомлений много разных, на один запрос может идти несколько разных вариантов разным адресатам. Уведомление внутри это некая общая база плюс пачка специфичных параметров. Пока нашёл следующие варианты:

  • разбить на разные запросы. Вариант так себе, часто надо отправить сразу Х уведомлений на одно действие разным адресатам. Делать ради этого Х round-trip так себе идея

  • сделать базу плюс жирный oneof. Выглядит убого и нечитабельно, любой code completion будет тормозить, плюс их надо два - на отправку и на геттер. Да и классы видимо разные надо будет.

  • сделать базу плюс юзать any. Поддержка его есть только в ванильной либе которую писали впервые увидевшие питон сишные нарки. Плюс это убивает на корню любой code completion и проверку типов и добавляет головняк с использованием.

  • передавать кишки уведомления строкой-жсоном. Нет, спасибо.

  • сделать базу и юзать extension типы. Да, но не в proto3, к сожалению.

Есть ещё какие-то варианты? Пока самым нормальным выглядит oneof, но тогда будет что-то типа (внутри repeated).

message SendNotification {
  string from = 1;
  google.protobuf.Timestamp when = 2;
  oneof data {
    SayA sayA = 10;
    SayB sayB = 11;
    ...
    SayXYZ sayXyz = 100500;
  }

  message SayA {
    string toEmail = 1;
    string name = 2;
    ...
  }
}

Простыню с парой сотен вариантов читать будет неудобно мягко говоря.

 , ,

upcFrost
()

Почему все так любят vscode

Форум — Talks

Сабж. Попробовал поюзать когда пичарм опять сожрал 12 гиг памяти из-за helm плагина. Юзал три дня, какой-то блокнот с косталями-плагинами от васяна. Хочешь pytest - можно, но fixture распознавать не будет. Поставил плагин на них - збс, но навигации по ним не будет. Хочешь sast - ок, но конфиг читать мы не умеем, все тесты подчеркнуты. Хочешь кастомных опций к тесту - иди долби pytest.ini вместо удобного сохранения конфигурации. Хочешь несколько предварительно созданных конфигураций запуска - они обязательно начнут подсирать при дебаге тестов. Хочешь просто блин workspace scope хоткеи - хрен, они per-folder. Хочешь посмотреть список изменений перед коммитом - ищи плагин либо ходи руками по всем файлам смотри что там как.

Не, я конечно ниосилятор, но ощущения как от какого-нибудь notepad++ или sublime. Типа вроде основное есть а вроде нихрена нет и ты плотно обмазан левыми кривыми плагинами

Объясните почему люди так любят эту шнягу? Потому что бесплатно? Пичарм стоит как две шаурмы. Или потому что идея жрёт больше памяти? Так отрубить часть плагинов и жрать будет не сильно больше, а все равно удобнее.

 

upcFrost
()

Апгрейд или облако для игор

Форум — Talks

Собственно сабж. Есть домашний комп который немного устарел. Там стоит мать на AM2, 6 гиг DDR2 и соответствующий проц. В целом тянет, но иногда проседает. Используется только под игры, при том в основном под парадоксовские CK/EU/HOI, под всякие файтинги и прочее на реакцию типа соулс есть хбокс. Ну и используется не особо часто ввиду наличия полугодовалого ребёнка

Прикупил CK3, который не взлетел ввиду нехватки памяти, а купить сейчас ddr2 довольно сложно и странно, потому тупо юзал бесплатную облачную GFNow, но очереди по 10-15 минут немного подзадолбали

Короче, встал перед дилеммой что лучше - апгрейд или оплата подписки. Апгрейд надо проц+мать+память+бп, в сумме около 500-600фр если брать low-mid amd, и это еще если монитор не покупать (лыжи бородатого года с dsub). Подписка 10фр в месяц, то есть стоимость апгрейда выйдет в ноль лет так за 5. Из минусов я живу в стране просранных интернетов, где 25mbit ADSL норма, сам сижу на 4/5г свистке. Но для игорей с околонулевыми требованиями к скорости реакции это не критично.

Кто бы что выбрал в такой ситуации? Может вообще пойти ограбить музей старых компов, добыть ещё пару планок ddr2 и забить?

 ,

upcFrost
()

Вариант системы распределения задач на Redis Streams

Форум — Development

Вопрос в продолжение Redis streams кто-нибудь юзал?. Пришла в голову идея как сделать очередь на редисе на стримах вместо пачки zset так чтоб было красиво и органично. Вернее не очередь, а скорее распределенное выполнение задач.

Дальше идёт стена текста, но если не лень - попинайте если видите явный косяк

Что нужно:

  • потребитель закидывает задачу через grpc в сервис с воркерами
  • задача идёт в очередь, один из воркеров берет задачу, делает
  • потребитель получает результат.
  • если задача не выполнена за N (отличается в зависимости от задачи) секунд - скорее всего воркер сдох или затупил и её надо выдать другому воркеру
  • нагрузка небольшая, от силы 10рпс. Но таски бывают очень разные по стоимости выполнения
  • таски в целом не критичные, пролюбить пару-тройку при смене мастера в редисе можно

По факту вызов синхронный с точки зрения потребителя, он почти всегда ждёт результат.

Что есть: редис с двумя zset, прям как по манам про reliable queue. Описание задачи в виде строки атомарно через луа переходит из одного сета в другой когда её берет воркер. Есть монитор, который смотрит второй сет и пинает просроченные таски. Результат задачи обычно файл (исторически), идёт на s3, потребитель поллит его ожидая результат.

Что не нравится:

  • сериализация в строку это треш, лучше hash, но тогда нужно отдельно писать в хеш задачу и отдельно пихать её ключ в очередь
  • в задаче появляется служебная информация типа номера попытки
  • если результат не файл - надо что-то где-то извращать, например давать какой-то ключ и поллить его потребителем либо юзать пабсаб
  • луа, без него такое не сделать
  • кастомный код, много
  • монитор должен магическим образом знать через какое время задача считается зафейленной либо это информация опять же пихается в описание задачи (например скором в zset)
  • сложно корректно вернуть ошибку
  • поллить s3 это не очень весело

Что думаю сделать: Очередь на стримах по типу кассы в маке (который самозапретился в рф).

  • Потребитель кидает таск в интерфейс/распределитель/оркестратор. Для простоты - в кассу. Касса кидает его в стрим в виде хеша, и в ответ получает талон с номером в стриме, отдает консьюмеру. Консьюмер открывает пабсаб и и ждёт «возле экрана с номерами над кассой».
  • воркер берет таск и начинает утюжить. Когда он его завершает, он отдает его в кассу.
  • Касса кидает в пабсаб клич с номером на талоне N раз с небольшим интервалом проверяя что таск не закоммичен. Если на выдачу никто не пришёл - пожимает плечами и убирает заказ (коммитит в стрим)
  • Консьюмер идёт к кассе, берет заказ, смотрит что там бургер вместо эксепшена, коммитит в стрим и идёт с подносом обратно в вызывающий сервис. Ну либо берет экспепшн, как повезёт.
  • Монитора нет, но раз в N секунд потребитель тихо спрашивает на кассе где его картоха, и на этом запросе таск перераспределяется другому воркеру (тут видимо +1 очередь и клейм, не нашёл метода как сказать стриму что таск свободен). Это в целом исключение, таймаут заведомо больше типового времени работы таска

Плюсы:

  • нативно хеш вместо велосипеда для сериализации и двойных ключей
  • нет служебной информации в таске, номер попытки и уник идут автоматом из стрима
  • таск коммитит тот кто его заказал, а не так что воркер сделал и дальше хоть потоп
  • нет кастомного монитора, поддержка разных таймаутов идёт весьма органично
  • почти нет кастомного кода
  • тип результата может быть любым без геморроя, можно нормально вернуть исключение (ну, почти нормально, таки с сериализацией)
  • если сдохла касса - можно тем же потребителем с тем же талоном пойти на соседнюю. Результат в пабсаб идёт несколько раз с интервалом, заведомо превышающим время запроса внутри цода. Тут правда не все так просто ибо номер нужно будет сначала вернуть в вызывающий сервис, либо делать второй запрос либо извращаться с partial response. Проще имхо второй запрос.

Пните кто видит какие проблемы у этого подхода.

П.с. почему не кролик/кафка/зеро/актив: редис уже есть и его поддерживает провайдер, с бэкапами, sla и вот этим всем. Брать ради одной-двух очередей ещё три сервака и пачку софта на поддержу я не буду. Да и оно немного не для того, тут скорее распределение при некой синхронности для консьюмера

 , , ,

upcFrost
()

Redis streams кто-нибудь юзал?

Форум — Development

Сабж. Как ощущения? Хочу на него перетащить пачку очередей на sorted set и кастомном коде. Inb4 из mq была кафка, сейчас старательно пытаемся её убрать ибо поддерживать некому и она тяжёлая шопесец, а редис все равно остаётся.

Нужен минимум - асинхронно раскидать жобы (мало, десятки от силы) по воркерам, иногда ждать результат (видимо на соседнем стриме), ну и retry если воркер сдох/затупил.

 

upcFrost
()

Робопса для госинспекции уже обсудили?

Форум — Talks

Сабж. Мелькала новость что инспекция по недвижимости решила вместо инспекторов закупить кетайских робособак фирмы UniTree чтоб те гуляли по городу и фиксировали самострой. и судя по голосованию на АГ таки закупила

Особенно радует «дружелюбная улыбка» как на этом фото. Я б честно подосрал если б ко мне так подошли.

Но вообще имхо идея прикольная, плюс робота вряд ли научат брать взятки, по крайней мере точно не сразу. Спионерить правда могут только так

 

upcFrost
()

Новый вид гуглопочты

Форум — Talks

Мне одному показалось что новый вид гуглопочты слизали с Я.Почты примерно на 99%?

Линукс не при чем, жж, танцпол, -20

 

upcFrost
()

Автомобили и электроника

Форум — Talks

Суп лор. Дальше будет жж и многобукв, если лень - пропускайте следующий абзац

Такая тема - есть у меня ситроен С4 2006 года, на котором уже 200к пробега. Как у любой французской машины с таким стажем, гбц решила отправиться в страну бесплатного бензина, а машина соответственно в ремонт за новой гбц. Чтоб не ехать с еврочернью на трамвае по местному полумиллионнику решил взять прокат на замену, и в итоге получил С4 2020 года, т.е. на два поколения новее.

Короче в чем суть - на новой машине сцатая тонна электроники. На старой управление было плюс-минус механическое (вернее аналоговое, без цифры), т.е. нажимая на тормоз ты ногой чувствуешь как колодка трёт диск. На новой - вместо тормоза прям какой-то рычаг с двумя положениями вкл/выкл, при том ещё и тупящий полсекунды прежде чем переключить режим. Аналогично короб - на старом стоит кошерный гидроавтомат, и сколько бы говна не лили на AL4, по сравнению с новым «умным» роботом это прям бомбезный короб был, разве что пары передач ему не хватало. Руль вообще пластиковая игрушка, которая типа пытается имитировать сопротивление дороги (спойлер: не получается).

Собственно хочу узнать кто как к этому относится? После старой тачки пересесть на электронную прям реально странно и неудобно. То тупит, то делает хрень (тот же старт-стоп), то игнорит силу нажатия

П.с. если что у арендной машины пробег 14к, за такое время даже жигуль не дохнет

 ,

upcFrost
()

Apple изобрёл комп в форм-факторе клавиатуры

Форум — Talks

Сабж https://www.patentlyapple.com/patently-apple/2022/02/apple-invents-a-new-mac-computer-device-that-takes-on-the-form-factor-of-their-magic-keyboard-.html

Скоро перейдут с грязных ссд на эко-кассеты и заживём

 ,

upcFrost
()

RSS подписка на новые темы