Я придумал аудиосообщения в телеграм
Когда я учился в 7-8 классе школы, я оооочень активно переписывался смсками. Тогда у Теле2 был классный тариф, в котором смски стоили то ли 5, то ли 10 копеек, что позволяло продолжительно чатиться.
Одни вечером я гостил у соседа, общался и пил чай. Телефон без конца вибрировал сообщениями, отвечая на которые можно было бы потратить кучу времени (все помнят клавиатуры с Т9?).
И мне тогда пришла в голову мысль, которую я озвучил вслух. Мне показалось, что было бы классно иметь возможность записать голос и отправить его как сообщение. Сосед посмотрел на меня как дебила и сказал: "Так просто позвони..."
И где мы сейчас находимся? 😲
Не знаю, как Паша выудил у меня из ума эту мысль, но жаль, что я не запатентовал ее тогда.
А лет 5 назад, кстати, я подумал о том, как меня достали проводные мышки, клавы и наушники. Как было бы круто сделать все беспроводным, но при этом не иметь необходимости это всё заряжать. Например, мышки и клавиатуры могли бы заряжаться от коврика (типа MagSafe). То есть, пока периферия на коврике - она заряжается, не надо пихать в нее никакие провода. В любой момент можно ее взять с коврика и работать уже от аккумулятора.
Подобным образом с наушниками. Представим, что на мониторе закреплен специальный крюк, на который они вешаются и начинают заряжаться.
Прикольно было увидеть, что идею с ковриком реализовали. Про наушники не знаю, но раз я об этом подумал, значит скоро появится. 😎
А вас посещали передовые идеи?
#telegram #wireless #idea
Когда я учился в 7-8 классе школы, я оооочень активно переписывался смсками. Тогда у Теле2 был классный тариф, в котором смски стоили то ли 5, то ли 10 копеек, что позволяло продолжительно чатиться.
Одни вечером я гостил у соседа, общался и пил чай. Телефон без конца вибрировал сообщениями, отвечая на которые можно было бы потратить кучу времени (все помнят клавиатуры с Т9?).
И мне тогда пришла в голову мысль, которую я озвучил вслух. Мне показалось, что было бы классно иметь возможность записать голос и отправить его как сообщение. Сосед посмотрел на меня как дебила и сказал: "Так просто позвони..."
И где мы сейчас находимся? 😲
Не знаю, как Паша выудил у меня из ума эту мысль, но жаль, что я не запатентовал ее тогда.
А лет 5 назад, кстати, я подумал о том, как меня достали проводные мышки, клавы и наушники. Как было бы круто сделать все беспроводным, но при этом не иметь необходимости это всё заряжать. Например, мышки и клавиатуры могли бы заряжаться от коврика (типа MagSafe). То есть, пока периферия на коврике - она заряжается, не надо пихать в нее никакие провода. В любой момент можно ее взять с коврика и работать уже от аккумулятора.
Подобным образом с наушниками. Представим, что на мониторе закреплен специальный крюк, на который они вешаются и начинают заряжаться.
Прикольно было увидеть, что идею с ковриком реализовали. Про наушники не знаю, но раз я об этом подумал, значит скоро появится. 😎
А вас посещали передовые идеи?
#telegram #wireless #idea
❤🔥1🔥1🤯1
Важность понимания сложности алгоритмов
Сейчас на проекте поддерживаем ужасное легаси, доставшееся от бывшего подрядчика. Баги валятся со всех сторон, а в контексте расширения бизнеса и появления новых требований к продукту зачастую валится и базовый функционал. На выходных столкнулись с хрестоматийной проблемой неэффективности алгоритма.
В какой-то момент стали поступать жалобы от пользователей на то, что приложение вылетает на андроид-устройствах. Сами устройства довольно старые: RFID-считыватели на Android 6 и Android 14. После диагностики поняли, что суть в том, что тупо кончается оперативная память и приложение падает. Сразу оговорюсь, что к падению приложения причастен был и ряд других проблем, но в рамках темы рассмотрим только алгоритм.
Суть: в приложении есть функционал выгрузки части базы данных на устройство для оффлайн работы. При выгрузке из БД (у нас couchdb 1.7.2 😢) тянется 130000 документов. Пару секунд приложение пыжится, потом ломается. Предлагаю рассмотреть изначальный код:
Как мы видим, внутри цикла forEach на каждой итерации вызывается filter, который проходит по тому же массиву. У нас квадратичная сложность вычисления O(n²).
Для тех, кто не в теме, приведу пример: представим, что у нас есть массив, в котором 1000 элементов. Проходя по нему одним циклом мы имеем линейную сложность вычисления O(n), потому что мы пройдем по всем элементам без исключения один раз. В данном случае n - количество элементов в массиве (1000). Количество операций равно количеству элементов.
А теперь представим, что проходя по одному элементу, мы вызываем еще один цикл, который проходится по тому же массиву (цикл в цикле). Сколько будет операций? На каждую операцию будет тоже O(n) вычислений. То есть, 1000 * 1000 = 1000000 операций. То есть, O(n * n) = O(n²).
Однако, если мы не будем вызывать цикл в цикле, а найдем способ вытащить один цикл из другого (а еще лучше, воспользуемся хеш-таблицами 😉), то наша сложность снова станет линейной. И вместо миллиона операций на массив мы вернемся к 1000, что является тысячекратным упрощением.
В общем, решили мы это так:
По сути, разбили одну операции на две, но в сумме своей они дают более эффективную работу. Мы в одном цикле проходимся по данным, делаем подсчет, к примеру, а потом в новом цикле уже с данными что-то делаем. В результате даже хиленький девайс на андроиде 6 справляется с повторяемой выгрузкой данных, ничего не падает, пользователи довольны. Конечно, скорее всего можно сделать это еще более эффективно, как мы знаем, предел редко виден в причесывании кода, но самое главное, что мы решили проблему.
#javascript #algo #android
Сейчас на проекте поддерживаем ужасное легаси, доставшееся от бывшего подрядчика. Баги валятся со всех сторон, а в контексте расширения бизнеса и появления новых требований к продукту зачастую валится и базовый функционал. На выходных столкнулись с хрестоматийной проблемой неэффективности алгоритма.
В какой-то момент стали поступать жалобы от пользователей на то, что приложение вылетает на андроид-устройствах. Сами устройства довольно старые: RFID-считыватели на Android 6 и Android 14. После диагностики поняли, что суть в том, что тупо кончается оперативная память и приложение падает. Сразу оговорюсь, что к падению приложения причастен был и ряд других проблем, но в рамках темы рассмотрим только алгоритм.
Суть: в приложении есть функционал выгрузки части базы данных на устройство для оффлайн работы. При выгрузке из БД (у нас couchdb 1.7.2 😢) тянется 130000 документов. Пару секунд приложение пыжится, потом ломается. Предлагаю рассмотреть изначальный код:
obj_arr.forEach(obj => {
if (obj.m_type === OT_BAG) {
obj.art_count = obj_arr
.filter(x => (x.m_type === OT_ART) && (x.container === obj.id))
.length;
}
});Как мы видим, внутри цикла forEach на каждой итерации вызывается filter, который проходит по тому же массиву. У нас квадратичная сложность вычисления O(n²).
Для тех, кто не в теме, приведу пример: представим, что у нас есть массив, в котором 1000 элементов. Проходя по нему одним циклом мы имеем линейную сложность вычисления O(n), потому что мы пройдем по всем элементам без исключения один раз. В данном случае n - количество элементов в массиве (1000). Количество операций равно количеству элементов.
А теперь представим, что проходя по одному элементу, мы вызываем еще один цикл, который проходится по тому же массиву (цикл в цикле). Сколько будет операций? На каждую операцию будет тоже O(n) вычислений. То есть, 1000 * 1000 = 1000000 операций. То есть, O(n * n) = O(n²).
Однако, если мы не будем вызывать цикл в цикле, а найдем способ вытащить один цикл из другого (а еще лучше, воспользуемся хеш-таблицами 😉), то наша сложность снова станет линейной. И вместо миллиона операций на массив мы вернемся к 1000, что является тысячекратным упрощением.
В общем, решили мы это так:
let bag_art_count = {};
rows.forEach(r => {
const value = r.value || {};
if (value.m_type === OT_ART && value.container) {
bag_art_count[value.container] =
(bag_art_count[value.container] || 0) + 1;
}
});
let obj_arr = rows.map(r => {
const obj = Object.assign(
{ _id: r.value.tag.substr(0, 24), id: r.id },
r.value
);
if (obj.m_type === OT_BAG) {
obj.art_count = bag_art_count[obj.id] || 0;
obj.is_suited = (obj.art_count === 0);
}
return obj;
});По сути, разбили одну операции на две, но в сумме своей они дают более эффективную работу. Мы в одном цикле проходимся по данным, делаем подсчет, к примеру, а потом в новом цикле уже с данными что-то делаем. В результате даже хиленький девайс на андроиде 6 справляется с повторяемой выгрузкой данных, ничего не падает, пользователи довольны. Конечно, скорее всего можно сделать это еще более эффективно, как мы знаем, предел редко виден в причесывании кода, но самое главное, что мы решили проблему.
#javascript #algo #android
🔥3❤1
У нас довольно непростая история с доступами во внешнюю сеть на работе. Если еще в рамках ежедневной работы что-то можно погуглить, но если нужно посветить виртуалкой в инет для простоты работы, то тут начинаются разнообразные этапы согласований, которые могут отнять время и желание вообще что-либо делать.
Очередная такая ситуация возникла, когда мы запустили виртуальную машину, чтобы развернуть на ней копию прода для тестов. У нас очень много чего завязано на SSL-сертификатах, но в нашей ситуации получать домен и светить айпишником в инет не было реализуемым вариантом. Я до этого с подобным не сталкивался, потому начал думать, как решить, чем сейчас и поделюсь.
Если кратко, то мы выпустили самописный сертификат на айпи адрес в локальной сети. По сути, работает точно так же, как сертификат от Let's Encrypt. Отличие лишь в том, что нужно вручную устанавливать этот сертификат в операционную систему. Вот процедура:
1) Создаем чистую папку для работы, чтобы не запутаться в файлах.
2) Создаем «Главный ключ» и «Главный сертификат». Этим сертификатом мы будем подписывать все остальные.
Итог: Появятся
3) Создается файл настройки с расширением .conf примерно такого содержания:
В
4) Генерим ключ сервера и запрос на подпись:
Появятся файлы
5) Подписываем запрос нашим корневым сертификатом:
Появится
6) На этом этапе я добавил созданные сертификаты
По сути с сертификатами всё. Теперь просто берем
#ssl #dev #debian
Очередная такая ситуация возникла, когда мы запустили виртуальную машину, чтобы развернуть на ней копию прода для тестов. У нас очень много чего завязано на SSL-сертификатах, но в нашей ситуации получать домен и светить айпишником в инет не было реализуемым вариантом. Я до этого с подобным не сталкивался, потому начал думать, как решить, чем сейчас и поделюсь.
Если кратко, то мы выпустили самописный сертификат на айпи адрес в локальной сети. По сути, работает точно так же, как сертификат от Let's Encrypt. Отличие лишь в том, что нужно вручную устанавливать этот сертификат в операционную систему. Вот процедура:
1) Создаем чистую папку для работы, чтобы не запутаться в файлах.
mkdir -p /root/certs
cd /root/certs
2) Создаем «Главный ключ» и «Главный сертификат». Этим сертификатом мы будем подписывать все остальные.
openssl genrsa -aes256 -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.crt
Итог: Появятся
rootCA.key (секретный, никому не давать) и rootCA.crt (публичный, его будем ставить на устройства, которые будут ходить на наш сервер).3) Создается файл настройки с расширением .conf примерно такого содержания:
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req
[req_distinguished_name]
C = RU
ST = Moscow
L = Moscow
O = CompanyGroup
CN = 101.148.223.60
[req_ext]
subjectAltName = @alt_names
[v3_req]
subjectAltName = @alt_names
[alt_names]
# List all DNS names and IPs here
DNS.1 = app.mycompany.ru
IP.1 = 101.148.223.60
IP.2 = 190.118.127.12
IP.3 = 127.0.0.1
В
[alt_names] мы прописываем адреса, по которым будем ходить на сервер, для которого выпускается сертификат. Нас интересует IP.1 - адрес сервера в локальной сети.4) Генерим ключ сервера и запрос на подпись:
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/server.key \
-out /etc/nginx/ssl/server.crt \
-config cert_config.cnf
Появятся файлы
server.key (секретный ключ) и server.csr (запрос).5) Подписываем запрос нашим корневым сертификатом:
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial \
-out server.crt -days 3650 -sha256 -extfile server.conf -extensions req_ext
Появится
server.crt.6) На этом этапе я добавил созданные сертификаты
server.crt и server.key в nginx и перезапустил службу.По сути с сертификатами всё. Теперь просто берем
rootCA.crt и устанавливаем его на устройства, с которых планируется работа с сервером. Я устанавливал на Android и на Windows 11. #ssl #dev #debian
👏3🔥2❤🔥1💯1
Сегодня расскажу про проброс портов в VScode. Удобная фишка, когда разрабатываешь сайт и его нужно показать кому-то. Позволяет не делать никакой деплой, все делается в рамках среды разработки.
Через сервера Microsoft Azure делается туннель, который ведет на вашу машину и ваша разработка становится доступны из внешней сети.
Делается просто:
Например, допустим, у нас просто вёрстка HTML-файлов с помощью встроенного Live Server на порту 5500.
В VScode в терминале жмем Порты. Если терминал закрыт, можно открыть с помощью
Жмем Перенаправить порт. Вводим порт 5500. Расширение попросит залогиниться - делаем.
После того, как служба отработает, вы увидите ссылку на вашу разработку, которой можно делиться.
Видимость проброса может быть частной и общедоступной. Частная - каждый, кто заходит, должен будет проходить авторизацию, а общедоступный - ссылка напрямую проксирует на вашу машину, потому держим в уме безопасность.
На скринах можно посмотреть как это все выглядит.
#vscode #portforwarding
Через сервера Microsoft Azure делается туннель, который ведет на вашу машину и ваша разработка становится доступны из внешней сети.
Делается просто:
Например, допустим, у нас просто вёрстка HTML-файлов с помощью встроенного Live Server на порту 5500.
В VScode в терминале жмем Порты. Если терминал закрыт, можно открыть с помощью
Ctrl + `, либо Вид - Терминал.Жмем Перенаправить порт. Вводим порт 5500. Расширение попросит залогиниться - делаем.
После того, как служба отработает, вы увидите ссылку на вашу разработку, которой можно делиться.
Видимость проброса может быть частной и общедоступной. Частная - каждый, кто заходит, должен будет проходить авторизацию, а общедоступный - ссылка напрямую проксирует на вашу машину, потому держим в уме безопасность.
На скринах можно посмотреть как это все выглядит.
#vscode #portforwarding
❤2
Когда я был молод, 10 лет назад, я уехал работать преподом английского в Таиланд. Такой поворот судьбы стал результатом хронической усталости от работы, на которой количество получаемого не совпадает с количеством отданного. То был, пожалуй, один из первых важных уроков, предоставленных мне жизнью.
Урок заключался в том, что изменения, которые мы ждем увидеть, находятся гораздо ближе, чем нам кажется, и вся сложность лишь в том, чтобы договориться с самим с собой оставить проигрышные условия и начать заново. В своем отчаянии я бросился в гугл искать все частные школы Таиланда и закидывать их имейлами со своим резюме. Через месяц я нашел школу. Через 2 месяца я уже был там. Настолько сильно я хотел поменять что-то, лишь бы было не так, как сейчас.
Из Таиланда я вернулся полным решимости вносить изменения дальше и, как только получил диплом, собрал вещи и уехал в Москву, откуда начался весь мой профессиональный рост.
#personal #thailand
Урок заключался в том, что изменения, которые мы ждем увидеть, находятся гораздо ближе, чем нам кажется, и вся сложность лишь в том, чтобы договориться с самим с собой оставить проигрышные условия и начать заново. В своем отчаянии я бросился в гугл искать все частные школы Таиланда и закидывать их имейлами со своим резюме. Через месяц я нашел школу. Через 2 месяца я уже был там. Настолько сильно я хотел поменять что-то, лишь бы было не так, как сейчас.
Из Таиланда я вернулся полным решимости вносить изменения дальше и, как только получил диплом, собрал вещи и уехал в Москву, откуда начался весь мой профессиональный рост.
#personal #thailand
❤2