Author Archive

Установка Kubuntu c установочной флешки

Делаем на Kubuntu установочную флешку для установки Kubuntu (простите за тавтологию). Для начала устанавливаем UNetbootin на странице https://unetbootin.github.io/linux_download.html можно его скачать, там же есть инструкция по установке. Вот так выглядит главное окно программы: Записываемый на флешку образ можно скачать либо по сети, либо выбрать iso на вашем компьютере. Первая проблема, которую можно поймать: /dev/sdb1 не смонтирован
Необходимо сначала примонтировать USB-накопитель /dev/sdb1 к точке монтирования. 
Большинство дистрибутивов делают это автоматически после переподключения USB-накопителя.
По началу я думал, что надо что-то примонтировать или перемонтировать, но оказалось все проще. После того как вы вставите флешку в компьютер / ноутбук, нужно открыть ее содержимое и она примонтируется. Также, желательно, чтобы в названии флешки были только латинские буквы. После того, как вы успешно записали флешку, вставили ее компьютер, отключили в BIOS режим UEFI, можете поймать ошибку
(initramfs) Unable to find a medium containing a live file system
Проблема заключается в использовании USB 3.0. У меня на ноутбуке HP все три USB-порта версии 3.0. Советуют в BIOS отключить поддержку 3.0 в пользу 2.0. Но на этом ноуте нет такой опции в BIOS. А флешка у меня 16 GB USB 3.0. С флеш-картой USB 2.0 загружался установщик, но где-то посередите он падал с ошибкой. В конце концов записал ISO на компакт-диск и установил с переносного DVD-ROM.

Target lists can have at most 1664 entries в PostgreSQL

Давно не писал... На прошлой неделе поймал такую ошибку:
ERROR: target lists can have at most 1664 entries
Данная ошибка возникла из-за того, что появилось много зависимостей между сущностями(Entity). Когда идет запрос данных через Hibernate, то JOIN'ится много таблиц, и общее количество получаемых полей начинает превышать 1664. В нашем случае это было около 1700 полей. Такое разумное ограничение есть у PostgreSQL. Решить можно такими путями: 1) Переписать запросы, взяв только используемые поля; 2) Сделать некоторые поля Lazy. Скорее всего, такая проблема и у вас решится вторым путем.

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

Иногда мы пользуемся трюком, сохраняя числа (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 обратиться к сервису по протоколу HTTPS

Это юбилейная 100-я статья!!!

Уже не знаю в какой раз приходится обращаться к сервису по протоколу HTTPS, и каждый раз уходит время, чтобы воспроизвести шаги. Сегодня решил все-таки написать шпаргалку и больше не тратить время на такую проблему. Для начала открываем сайт в браузере: В адресной строке браузера рядом с текстом https:// есть иконка, нажав на которую появится возможность просмотреть / скачать / экспортировать сертификат. Нужно экспортировать сертификат в файл test.crt Файл будет иметь примерно такое содержание:
-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIUGyZeQnd4LMFso5FQwrzjHmrNWVswDQYJKoZIhvcNAQEF
utCwINC/0L7QtNC70LjQvdC90L7RgdGC0Lgg0YHQtdGA0LLQtdGA0LAwMgYDVR0f
KqOTBEhH50jwo6WaQIUrD54ElD5gVO3VIT+eAMZm0HzXF+NKpkNaiR1b
-----END CERTIFICATE-----
Далее необходимо выполнить следующую команду:
sudo keytool -import -alias yourname -file test.crt
 -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
-alias - произвольное уникальное название -file - путь к файлу -keystore - путь к хранилищу сертификатов Java $JAVA_HOME - путь к домашней директории Java, которую вы используете для запуска вашего приложения -storepass - пароль к хранилищу, по умолчанию changeit

Получение содержимого текстового файла (Spring Boot)

Вот уже несколько месяцев последние два проекта делаю с использованием Spring Boot. Бывает так, что нужно интегрироваться с внешней системой, но эта система не готова по каким-то причинам, а нужно показать свой функционал, в этом случае пишем заглушку. Т.к. в моем случае внешний сервис давал данные в формате JSON, я решил положить пример ответа сервиса в ресурсы (resource) по пути files/cities.json. Далее встал вопрос как его вытянуть. Погуглил, в итоге собрал такую функцию (сперва получаем контекст приложения, из которого получаем ресурс):
private static String getFileContent(String filePath) throws IOException {
    ApplicationContext appContext =
        new ClassPathXmlApplicationContext(new String[] {});
 
    Resource resource = appContext.getResource(filePath);
 
    StringBuilder sb = new StringBuilder();
    BufferedReader br = null;
    try{
        br = new BufferedReader(
            new InputStreamReader(resource.getInputStream(), "UTF-8"));
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
    }finally {
        if(br != null) try {
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return sb.toString();
}
Пример вызова функции:
try {
    String text = getFileContent("files/cities.json");
} catch (IOException e) {
    e.printStackTrace();
}
Я использовал чтение файла для временной заглушки, но можно использовать и для других целей. p.s. Обратите внимание, что в функции указана кодировка UTF-8. Можно её не указывать, тогда возьмется кодировка системы. Кодировку можно указать и при запуске приложения:
java -Dfile.encoding=UTF8
Совет: лучше в функции явно прописать UTF-8, если, конечно, она вам нужна.

Замер времени (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. Можете придумать и сделать свою версию, здесь простор для творчества.

$(…).size is not a function

Второй раз за последние месяцы прикручиваю тему Metronic и ловлю такую ошибку:
$(...).size is not a function
В первый раз я потратил достаточно времени, чтобы понять в чем причина, а во второй раз было дело техники. Всё дело в том, что Metronic использует 1-ю версию jQuery (v1.12.4), а в проекте bower брал последную 3-ю версию jQuery (v3.1.0). В 3-ей версии почему-то убрали эту функцию. Все решается использованием 1-й версии jQuery. В bower.json я исправил версию так:
"jquery": "1.12.4"

Запустил платное приложение Bilemin Cards в Google Play

Наконец-то, 31 октября 2016 я запустил своё первое платное приложение в Google Play под названием "Bilemin Cards". Вот ссылка на приложение: https://play.google.com/store/apps/details?id=kz.bilemin.cards. Стоимость приложения 3$, что составляет 990 тенге. Вообще, я настроен скептически, кажется, я вообще не заработаю денег на этом приложении, но посмотрим... В этой статье я буду через определенные промежутки времени писать о всём, что касается приложения, и что я буду делать для продвижения приложения. Ноябрь, 2016 В ноябре я начал рекламировать приложение через adwords. Кампания длилась неделю, бюджет был 1$/день.
Показы 24 894
Взаимодействия 437 кликов
Коэффициент взаимодействия 1,76 % CTR
Средн. цена 0,02 $ за клик
Стоимость 9,60 $
Итого за 7 дней взяли 9,60$. Почему не 7$ спросите вы? Показ рекламы не может сразу остановиться, поэтому каждый день уходило более 1$. Вывод: Реклама не сработала, никто не купил приложение. Любой бюджет можно скликать 🙂 01.12.2016 Отправил приложение на конкурс award.kz в номинацию "Мобильные приложения". Было более 350 просмотров и один лайк. Предварительные результаты голосования: p.s. пока 11-е место, даже не в первой десятке 🙂 p.p.s. организаторы запросили 7 промо-кодов для оценки приложения, я же им передал 10 кодов! При своей оценке они не активировали ни одного кода!! Вообще, до этого я сгенерил 500 промо-кодов, теперь думаю как их распространить. 13.12.2016 Запустил бесплатную версию приложения: https://play.google.com/store/apps/details?id=kz.bilemin.freecards p.s. Не пощупав, никто ничего не купит, по крайней мере, наши люди 🙂 15.12.2016 Состоялась первая покупка приложения. Неожиданно, если честно 🙂 20.12.2016 Освежил группу вконтакте по новогоднему: https://vk.com/bilemin Создал запись: https://vk.com/bilemin?w=wall-44243064_8 и начал её рекламу через VK: 25.12.2016 На прошлой неделе я запускал рекламу ВКонтакте. Сперва рекламировал запись в сообществе: Статистика следующая: В итоге показы почему-то упали. Далее замутил схему с промо-кодами, но рекламу не приняли модераторы. В итоге решил рекламировать приложения напрямую: Тут уже надо было платить не за показы, а за переходы. В итоге всего 8 человек на сегодняшний день установили бесплатное приложение. Короче, реклама в VK не дала результатов. 25.12.2016 Решил рекламировать своими силами. Взял базу пользователей сайта bilemin.kz, что примерно 1100 человек и начал делать рассылку. 03.01.2017 Год завершился с такими показателями: Если с 1000 отправок писем целевой аудитории будет хотя бы одна установка, то можно отправлять миллионы писем. Сегодня с mail.ru выудил 438 email'ов из Казахстана и сделал рассылку. 05.01.2017 Разослал еще 4000 писем. Статистика еще не обновилась, что-то Google Play запаздывает. Наконец-то, обновилась статистика: 14.01.2017 Что-то застопорились скачивания. Прошло более недели, а прирост мизерный. 24.01.2017 Прошло 10 дней. Несколько дней назад вновь запускал рассылку по 4000 адресам (другая выборка) и ждал пока обновиться статистика. p.s. Уныло ждем 50 установок 🙂