Category Archive: Без рубрики

Установка ESPnet

Устанавливать ESPnet будем на Ubuntu 22.04, где по умолчанию Python версии 3.10.12.

Скачиваем espnet из репозитория https://github.com/espnet/espnet/ или отсюда

Установите библиотеки

sudo apt install python3.10-venv
sudo apt install python3-pip
pip install parallel-wavegan

Откройте директорию espnet/tools с установочными скриптами

cd espnet/tools/

Установите miniconda

./setup_anaconda.sh miniconda espnet 3.8

Установите виртульную среду Python

./setup_venv.sh $(command -v python3)

Настройте Python

./setup_python.sh $(command -v python3)

Соберите и установить ESPnet c PyTorch версии 1.12.1

make TH_VERSION=1.12.1

Выполнить скрипт activate_python.sh

export PYTHONUSERBASE="{YOUR_ESPNET_PATH}/tools/python_user_base"
export PATH="{YOUR_ESPNET_PATH}/tools/python_user_base/bin":${PATH}
export PATH=/usr/bin:${PATH}

Во сколько раз Base64 увеличивает размер в байтах

Base64 — стандарт кодирования байтов при помощи только 64 символов (A-Z, a-z и 0-9 (62 знака) и 2 дополнительных символа, зависящих от системы реализации).

Одним байтом можно закодировать 256 значений (28 бит), в то время как Base64 только 64 (26 бит).

Из этого следует соотношение 28 + 28 + 28 = 26 + 26 + 26 + 26, т.е. каждые 3 исходных байта кодируются в 4 байта.

Можно вывести формулу:

[Кол-во байт в Base64] = ([Исходное кол-во байт] / 3) * 4
или
[Кол-во байт в Base64] = 4 * [Исходное кол-во байт] / 3
или
[Кол-во байт в Base64] = 4/3 * [Исходное кол-во байт]

Например: Файл размером 1500 байт в Base64 будет занимать 2000 байт (т.е. на 1/3 больше).

Рассмотрим обратную задачу: есть Base64-строка и нужно понять сколько это будет байтов при раскодировке. Из формул выше можно выразить исходное кол-во байт:

[Исходное кол-во байт] = 3/4 * [Кол-во байт в Base64] 
или
[Исходное кол-во байт] = 0.75 * [Кол-во байт в Base64] 

Например: Base64-строка размером 2000 байт, декодируется в 1500 байт (т.е. на 1/4 меньше);

Степени двойки

Список степени двойки.

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

Степень двойки (2x) Значение
01
12
24
38
416
532
664
7128
8256
9512
101 024
112 048
124 096
138 192
1416 384
1532 768
1665 536
17131 072
18262 144
19524 288
201 048 576
212 097 152
224 194 304
238 388 608
2416 777 216
2533 554 432
2667 108 864
27134 217 728
28268 435 456
29536 870 912
301 073 741 824
312 147 483 648
324 294 967 296
338 589 934 592
3417 179 869 184
3534 359 738 368
3668 719 476 736
37137 438 953 472
38274 877 906 944
39549 755 813 888
401 099 511 627 776
412 199 023 255 552
424 398 046 511 104
438 796 093 022 208
4417 592 186 044 416
4535 184 372 088 832
4670 368 744 177 664
47140 737 488 355 328
48281 474 976 710 656
49562 949 953 421 312
501 125 899 906 842 624
512 251 799 813 685 248
524 503 599 627 370 496
539 007 199 254 740 992
5418 014 398 509 481 984
5536 028 797 018 963 968
5672 057 594 037 927 936
57144 115 188 075 855 872
58288 230 376 151 711 744
59576 460 752 303 423 488
601 152 921 504 606 846 976
612 305 843 009 213 693 952
624 611 686 018 427 387 904

Сборка и установка турника 3 в 1

Выложим на ровную поверхность компоненты турника:

Распакуем все детали:

Наденем ручки. Половину ручек нужно разрезать пополам. Чтобы дело пошло быстрее смачиваем ручки водой, а сам турник мыльным раствором:

В сборке турник выглядит следующим образом: <<<тут будет фото>>>

Размечаем на стене отверстия для креплений гвоздем или чем-то еще, чтобы была выемка для точного высверливания отверстия. Вcего четыре крепления, каждое крепится двумя анкерами. Расстояние между центрами креплений 45см (желательно пользоваться уровнем(ватерпасом)):

Под местом сверления вешаем пакет на скотч, чтобы меньше пылить и мусорить:

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

В итоге решил вешать турник на анкера 12x100, но перед этим залить в отверстия "жидкие гвозди" (строительный/монтажный клей). Как выяснилось, применение "жидких гвоздей" значительно усиливает соединение анкера со стеной, заполняя микрополости.

Далее возникла следующая проблема: в строй-магазине были только анкера 12x120, что даже лучше (чем длинне анкер, тем больше площадь соприкосновения со стеной), но продавец положил шурупы к анкеру длинной 100мм. Обнаружив это только дома, пришлось искать шурупы под анкера на 120, не найдя таких, решил укоротить анкера до 100мм, отрезав верхнюю часть:

После высверливания 8 отверстий 12x100, обязательно выскабливаем остатки пыли ершиком или как я - шляпкой шурупа меньшего диаметра:

Дополнительно, можно пройтись пылесосом:

Все отверстия готовы:

Далее по очереди работаем над каждым креплением: заливаем клей в два отверстия, забиваем два анкера и на два шурупа прикручиваем крепление.

Отверстие лучше заполнять клеем на половину, иначе избыток клея заполнит все пространство, сочясь из середины анкера, и будет очень мешать забить анкер.

Все крепления прикручены:

Ждем 3-5 суток до полного отвердевания клея...

Удаление числа из строки

Иногда мы пользуемся трюком, сохраняя числа (ID из базы данных) в строке через запятую. Например: "1024,15,8,0,55". И теперь, допустим, какое-то число из этого списка не нужно, и его необходимо убрать из исходной строки. Как это реализовать? Первый вариант: 1) разбить строку по запятой 2) отфильтровать удаляемое число 3) собрать строку заново Второй вариант (допустим, удаляем число 55): 1) вырезать из строки подстроки вида: ,55, 2) удаляем подстроки вида 55, и ,55 Реализация 1-го варианта (Java):
String val = "55";
String collect = Arrays.stream(
        "55,1024,55,15,8,0,55".split(","))
        .filter(v -> !v.equals(val))
        .collect(Collectors.joining(","));
System.out.println(collect);//1024,15,8,0
Реализация 2-го варианта (Java):
int del = 55;
String result = "55,1024,55,15,8,0,55"
        .replaceAll("," + del + ",", ",")
        .replaceAll(",?" + del + ",?", "");
System.out.println(result);//1024,15,8,0

Некоторые вещи про закачку файлов

В любом web-проекте в определенное время возникает вопрос как загружать/скачивать файлы. В этой статье рассмотрим важные аспекты этих процедур:
  • Можно загружать файлы не только в виде байт, но и формате base64.
  • Файл загружается на веб-сервер и сохраняется как временный файл
  • При передаче файла на сервер используется кодирование multipart/form-data
  • Из временного файла можно получить оригинальное название файла, байты файла, тип содержимого(ContentType), размер.
  • На основе байтов можно рассчитать хэш. Например, алгоритмом MD5, SHA-1 или SHA-256.
  • Хэш файла может пригодиться при отдаче файла, чтобы проверить целостность.
  • При отдаче файла следует указать HTTP-заголовок Content-Disposition. Параметр inline сообщает браузеру, что файл можно открыть непосредственно в браузере, если конечно позволяет тип файла. Параметр attachment сообщает, что файл должен скачиваться. Также в Content-Disposition передается наименование файла, которое лучше кодировать с помощью URL Encoding.
  • Если в браузере вы хотите отобрать процесс загрузки файла, например, в процентах, то проще всего это сделать через javascript, который может отслеживать кол-во отправленных байтов.

Бинарный алгоритм вычисления НОД

Наибольшим общим делителем (НОД) для двух целых чисел называется наибольший из их общих делителей. Например: для чисел 8 и 12 наибольший общий делитель равен 4. Ранее мы уже рассматривали нахождение НОД с помощью Алгоритма Евклида:
long gcd(long a,long b){
	return b == 0 ? a : gcd(b,a % b);		
}
Сейчас рассмотрим Бинарный алгоритм Евклида, который быстрее обычного алгоритма Евклида. Бинарный алгоритм основан на следующих свойствах НОД:
НОД(2m, 2n) = 2 НОД(m, n),
НОД(2m, 2n+1) = НОД(m, 2n+1),
НОД(-m, n) = НОД(m, n)
Теперь реализуем этот алгоритм на Java:
static int gcd(int m, int n){
    if(m == 0) return n;
    if(n == 0) return m;
    if(n == m) return n;
    if(m == 1) return 1;
    if(n == 1) return 1;
    boolean em = (m & 1) == 0;
    boolean en = (n & 1) == 0;
    if(em && en) return gcd(m >> 1, n >> 1) << 1;
    if(em) return gcd(m >> 1, n);
    if(en) return gcd(m, n >> 1);
    if(n > m) return gcd((n - m) >> 1, m);
    return gcd((m - n) >> 1, n);
}
Для ускорения деления на два используется сдвиг битов на позицию вправо(>> 1), для умножения на два используется сдвиг на позицию влево (<< 1). Проверка четности числа осуществляется проверкой последнего бита числа (m & 1), если выражение равно 0, то число четно, иначе нечетно.

Замер времени (Java)

Иногда возникает потребность измерить время работы определенного фрагмента кода в вашем проекте. Можно, конечно, писать так:
long start = System.currentTimeMillis();
//тут замеряемый код
System.out.println(System.currentTimeMillis() - start);
Но такой подход быстро надоедает. Я выделил замер времени в отдельный класс TimeMeter, теперь можно удобно останавливать несколько раз таймер и измерять время, если нужно измерить промежуточные значения. Можно также использовать несколько экземпляров таймера. Реализация:
public class TimeMeter {
    private long start;
	private long stop;

    public TimeMeter(){
        start = now();
    }

    public void stop(){
        stop = now();
    }

    @Override
    public String toString() {
        return getDuration() + " msec";
    }

    public long getDuration(){
        return (stop == 0 ? now() : stop) - start;
    }

    private long now(){
        return System.currentTimeMillis();
    }
}
Самый простой вариант использования:
TimeMeter timeMeter = new TimeMeter();
//тут замеряемый код
System.out.println(timeMeter);
Таймер с несколькими остановками и замерами времени:
TimeMeter timeMeter = new TimeMeter();
//тут замеряемый код 1
timeMeter.stop();
System.out.println(timeMeter);
//тут замеряемый код 2
timeMeter.stop();
System.out.println(timeMeter);
Глобальный и внутренние таймеры:
TimeMeter totalTimeMeter = new TimeMeter();
for (int i = 0; i < 100; i++) {
    TimeMeter timeMeter = new TimeMeter();
    //тут замеряемый код
    System.out.println("time " + i + ": " + timeMeter);
}
System.out.println("total time: " + totalTimeMeter);
p.s. Можете придумать и сделать свою версию, здесь простор для творчества.

Тестовые ссылки с различными файлами

Часто бывает необходимо проверить какой-то функционал по получению файла через web. Мы либо ищем в интернете нужную ссылку, либо размещаем файлы где-то у себя на веб-сервере (который еще нужно поднять :-)). Сегодня пришла идея сделать страницу, на которой будут размешаться ссылки на тестовые файлы, причем файлы будут храниться на этом же домене, поэтому пока работает этот домен, файлы будут доступны!
Наименование файла Ссылка Размер MD5
fontan.mp4 http://kesh.kz/download/test/fontan.mp4 62080018 байт (59.2M) ee873149a67990babe3206c5d06356eb
Гимн Казахстана.txt http://kesh.kz/download/test/%D0%93%D0%B8%D0%BC%D0%BD%20%D0%9A%D0%B0%D0%B7%D0%B0%D1%85%D1%81%D1%82%D0%B0%D0%BD%D0%B0.txt 975 байт edbf47380c466f267511a6893e954693

Сортировка по убыванию в Java

На данный момент, к сожалению, в Java нет стандартной функции, которая бы могла сортировать массив из примитивных элементов (например, int[], long[]) по убыванию. Мы можем сортировать массив примитивов только по возрастанию:
int a[] = {17,4,85};
Arrays.sort(a);
System.out.println(Arrays.toString(a));//[4, 17, 85]
Как выход можно перевести массив примитивов в массив объектов (например, Integer[], Long[], String[]) и сортировать уже его:
Integer a[] = {17,4,85};
Arrays.sort(a,Collections.reverseOrder());
System.out.println(Arrays.toString(a));//[85, 17, 4]
Т.е. вторым параметром функции sort мы передали Collections.reverseOrder(), что обеспечило обратную сортировку.