Author Archive

FastScanner — ускоряем чтение данных

Стандартный класс Scanner из пакета java.util очень хорош для чтения небольшого кол-ва данных, но если кол-во данных большое и скорость чтения критична, то нужно самостоятельно реализовать более быстрый сканер. Ниже приведен пример такого сканера.
import java.io.*;
import java.util.StringTokenizer;

public class FastScanner {
	BufferedReader br;
	StringTokenizer st;
	
	public FastScanner(){
		init();
	}
	
	public FastScanner(String name) {
		init(name);
	}
	
	public FastScanner(boolean isOnlineJudge){
		if(!isOnlineJudge || System.getProperty("ONLINE_JUDGE") != null){
			init();
		}else{	
			init("input.txt");			
		}
	}
	
	private void init(){
		br = new BufferedReader(new InputStreamReader(System.in));
	}
	
	private void init(String name){
		try {
			br = new BufferedReader(new FileReader(name));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	public String nextToken(){
		while(st == null || !st.hasMoreElements()){
			try {
				st = new StringTokenizer(br.readLine());
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return st.nextToken();
	}
	
	public int nextInt(){
		return Integer.parseInt(nextToken());
	}
	
	public long nextLong(){
		return Long.parseLong(nextToken());
	}
	
	public double nextDouble(){
		return Double.parseDouble(nextToken());
	}
	
}
Примеры использования Объявление FastScanner'а для чтения из консоли:
FastScanner scan = new FastScanner();
Объявление FastScanner'а для чтения из указанного файла:
FastScanner scan = new FastScanner("A.in");
Объявление FastScanner'а для чтения из консоли или из файла input.txt в зависимости от установленного свойства ONLINE_JUDGE
FastScanner scan = new FastScanner(true);
Чтение данных:
int i = scan.nextInt();
long l = scan.nextLong();
double d = scan.nextDouble();
String token = scan.nextToken();
Быстрый вывод в консоль Наряду с быстрым чтением входных данных, также важен быстрый вывод данных в консоль. Для ускорения вывода будем не сразу выводить данные в консоль с помощью System.out, а с помощью PrintWriter будем накапливать, и лишь потом сбрасывать данные в консоль командой flush (что эффективнее). Сбрасывать данные лучше порциями среднего размера, чтобы соблюсти баланс между скорость и потребляемой памятью.
PrintWriter out = new PrintWriter(System.out);
out.println(result);
out.flush();
Сравним вывод одинаковых данных через обычный System.out и через PrintWriter. Код ниже у меня отработал примерно за 2 секунды:
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        System.out.println(i * j);
    }
}
А следующий код с буферизацией отработал существенно быстрее, за менее чем 0,7 секунды:
PrintWriter out = new PrintWriter(System.out);
for (int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        out.println(i * j);
    }
    out.flush();
}

Заготовка HTML-страницы

Заготовка HTML-страницы с указание кодировки UTF-8, подключенным файлом стилей и скриптом:




Заголовок		




	

	

Команды для изучения нового Linux-сервера

Очень часто требуется настроить сервер, который вы видите в первые, а настраивали его до вас. С Windows-серверами проблем мало, а вот с Linux-серверами настройка может затянуться, если вы не знаете необходимых команд. Ниже будет приведен список самых необходимых команд.
  1. Узнать какой перед нами Linux и его версия
    cat /etc/issue
    
  2. Просмотреть историю последних выполненных команд
    history
    
  3. Узнать кол-во свободного места в файловой системе
    df -h
    
    Опция -h показывает данные в килобайтах, мегабайтах и гигабайтах
  4. Возможно, в системе имеются неразмеченные разделы, которые вам не видны. Следующая команды выведет полный список разделов жестких дисков
    fdisk -l
    
  5. Вывести информацию о состоянии всех активных сетевых интерфейсах:
    ifconfig
    
  6. Перезагрузка сервера
    reboot
    
  7. Выключить сервер
    shutdown -h 0
    
  8. Распаковка tar-архива сжатого gzip'ом
    tar xvfz archive.tar.gz
    
  9. Распаковка tar-архива сжатого bzip'ом
    tar xvfj archive.tar.bz2
    
  10. Перемещение файла (директории)
    mv from_file to_file
    

Unable to execute dex: java.nio.BufferOverflowException

Снова при запуске импортированного приложения повторилась следующая ошибка:
[2014-05-09 23:36:21 - Dex Loader] Unable to execute dex: java.nio.BufferOverflowException. 
Check the Eclipse log for stack trace.
[2014-05-09 23:36:21 - HelloJni] Conversion to Dalvik format failed: 
Unable to execute dex: java.nio.BufferOverflowException. 
Check the Eclipse log for stack trace.
И снова решение проблемы плохо гуглиться: в основном предлагают откатить или обновить версию SDK. После гугления вспомнил, как решается проблема. Нужно чтобы целевая версия SDK совпадала в манифесте приложения (AndroidManifest.xml) и в свойствах проекта (project.properties) Например, в представленных ниже фрагментах указана 19-я версия SDK. AndroidManifest.xml:

project.properties:
# Project target.
target=android-19

Вывод числа с точностью до заданного количества цифр после запятой

Иногда требуется вывести определенное количество цифр после запятой, даже если цифры - концевые нули. Данную задачу решает класс DecimalFormat, которому в конструктор класса необходимо передать шаблон числа. Рассмотрим несколько вариантов использования: 1) Пример округления до трех знаков
DecimalFormat df = new DecimalFormat("0.000");
System.out.println(df.format(13.6784));//результат 13,678
System.out.println(df.format(13.6785));//результат 13,678
System.out.println(df.format(13.67851));//результат 13,679
System.out.println(df.format(13));//результат 13,000
Разделителем между целой и дробной частью в данном случае выступает запятая, но это зависит от текущей локализации. Если в качестве разделителя требуется точка, то можем это сделать, указав американскую локализацию. 2) Округление до двух знаков и американская локализация
DecimalFormat df = new DecimalFormat("0.00",DecimalFormatSymbols.getInstance(Locale.US));
System.out.println(df.format(13.6749));//результат 13.67
System.out.println(df.format(13.6750));//результат 13.68
System.out.println(df.format(13.6751));//результат 13.68
System.out.println(df.format(13));//результат 13.00
3) Если вы были внимательны, то могли заменить, что округление работает странным образом. Например,
System.out.println(df.format(13.6785));//результат 13,678
Хотя ожидаемый ответ: 13,679. Все дело в том, что по умолчанию используется округление HALF_EVEN, где округление идет в сторону ближайшего четного. Это так называемое "Округление банкиров", которое используется главным образом в США. Такой способ округления позволяет снизить накопление ошибок при округлении. Рассмотрим пример: дробные части .49 и .51 уравновешивают друг друга, одно число округляется в меньшую, а второй в большую строну. Но как быть с дробной частью .50, которая, допустим, всегда увеличивается в большую строну. Для этого придумали следующую систему: смотрим соседнее число, если число нечетно, то округляем в большую сторону; если четное, то округляем в меньшую сторону. Или проще говоря, округляем половину до ближайшего четного числа. Рассмотрим два случая:
1) Число 13.6785 после округления будет 13.678, 
т.к. цифре 5 предшествует четная цифра 8 (округляем вниз).
2) Число 13.6795 после окгруления будет 13.680. 
т.к. цифре 5 предшествует нечетная чифра 9 (округляем вверх).
Пример кода, описывающего эту ситуацию (HALF_EVEN):
DecimalFormat df = new DecimalFormat("0.000");
System.out.println(df.format(13.6785));//результат 13,678
System.out.println(df.format(13.6795));//результат 13,680
Если вас не устраивает такое округление, то можно переключиться на округление, более привычное нам - округление в большую сторону (HALF_UP):
DecimalFormat df = new DecimalFormat("0.000");
df.setRoundingMode(RoundingMode.HALF_UP);
System.out.println(df.format(13.6785));//результат 13,679
System.out.println(df.format(13.6795));//результат 13,680

Экранирование символов в названии файла

Всем нам известно, что нельзя использовать некоторые символы в названиях файлов. И на разных операционных системах эти запрещенные символы различны. Например, в Windows это следующие символы: \ / : * ? < > | invalid_characters Если в вашем приложении названия файлов генерируются автоматически, то нужно подстраховаться, заменив запрещенные символы на какой-нибудь разрешенный. Ниже будет представлена функция, которая заменяет перечисленные выше символы на символ подчеркивания "_":
public static String screeningFileName(String fileName){
	return fileName.replaceAll("[\\\\/:*?\"<>|]","_");
}
Пример использования:
System.out.println(screeningFileName("report*2014-04-29 17:46:00.pdf"));
//результат выполнения функции: report_2014-04-29 17_46_00.pdf 

Номера версий Android

Номера версий Android:
Кодовое название Версия Уровень API
-1.0API level 1
-1.1API level 2
Cupcake1.5API level 3, NDK 1
Donut1.6API level 4, NDK 2
Eclair2.0API level 5
Eclair2.0.1API level 6
Eclair2.1API level 7, NDK 3
Froyo2.2.xAPI level 8, NDK 4
Gingerbread2.3 - 2.3.2API level 9, NDK 5
Gingerbread2.3.3 - 2.3.7API level 10
Honeycomb3.0API level 11
Honeycomb3.1API level 12, NDK 6
Honeycomb3.2.xAPI level 13
Ice Cream Sandwich4.0.1 - 4.0.2API level 14, NDK 7
Ice Cream Sandwich4.0.3 - 4.0.4API level 15, NDK 8
Jelly Bean4.1.xAPI level 16
Jelly Bean4.2.xAPI level 17
Jelly Bean4.3.xAPI level 18
KitKat4.4 - 4.4.2API level 19
Оригинальная версия: https://source.android.com/source/build-numbers.html

Отправка письма через SMTP c NTLM-аутентификацией

Однажды, придя к заказчику, я не смог подключиться к их заранее заведенному электронному адресу для рассылок. Назовем его noreply@sample.com. Пришлось демонстрировать систему с ящиком yandex.ru. Основное предположение было то, что дело в домене. Так и оказалось, для подключения к SMTP нужно было пройти NTLM-аутентификацию (Статья о NTLM в Википедии). Сперва у меня не получалось, т.к. использовал старую библиотеку mail.jar (версия: 1.4, размер: 379 КБ), потом скачал новую версию библиотеки, которая поддерживает NTLM: javax.mail.jar (версия: 1.5, размер: 533 КБ). Эту версию можно скачать отсюда: javax.mail.jar В этот статье вы встретите две реализации: одна реализация с обычным подключением к SMTP, а другая реализация с NTLM-авторизацией. Для начала рассмотрим обычное подключение, чтобы потом увидеть разницу. Созданим класс MailHelper, в конструкторе этого класса будут задаваться все необходимые параметры для подключения к почтовому ящику, а метод send будет отвечать за отправку писем согласно переданным в этот метод параметрам:
import javax.mail.*;
import javax.mail.internet.*;
import java.util.*;

public class MailHelper {
		
	private Properties properties;
	private Session session;
	private String currentEmail;
	
	public MailHelper(String host,String port,final String user,final String password){
		properties = new Properties();
		properties.setProperty("mail.smtp.auth","true");
		properties.setProperty("mail.smtp.host", host);
		properties.setProperty("mail.smtp.port",port);
		currentEmail = user;
		session = Session.getInstance(properties,
		  new javax.mail.Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(user,password);
      			}
      		  });
	}
	
	public void send(String email,String subject,String body) throws Exception{
		MimeMessage msg = new MimeMessage(session);
		msg.setFrom(new InternetAddress(currentEmail));
		msg.setRecipient(Message.RecipientType.TO, new InternetAddress(email));
		msg.setSubject(subject);
		msg.setContent(body, "text/html; charset=utf-8");
		Transport.send(msg);
	}
}
Пример использования этого класса:
MailHelper mailHelper = new MailHelper(
		"smtp.sample.com","25",
		"noreply@sample.com","password123");
try {
	mailHelper.send("target@sample.com", "Проверка", "Привет, Target!");
} catch (Exception e) {
	e.printStackTrace();
}
В конструктор передаются: адрес SMTP-сервера, порт, логин и пароль. В метод send передаются: электронный адрес получателя, заголовок и содержимое письма. Теперь рассмотрим реализацию с NTLM. Практически тоже самое, только при создании объекта класса PasswordAuthentication нужно указать имя учетной записи в домене, а адрес электронной почты передается отдельным параметром.
import javax.mail.*;
import javax.mail.internet.*;
import java.util.*;

public class MailHelper {
		
	private Properties properties;
	private Session session;
	private String currentEmail;
	
	public MailHelper(String host,String port,
		final String user,final String password,String email){
		properties = new Properties();
		properties.setProperty("mail.smtp.auth","true");
		properties.setProperty("mail.smtp.host", host);
		properties.setProperty("mail.smtp.port",port);
		currentEmail = email;
		session = Session.getInstance(properties,
      		  new javax.mail.Authenticator() {
      			protected PasswordAuthentication getPasswordAuthentication() {
      				return new PasswordAuthentication(user,password);
      			}
      		  });
	}
	
	public void send(String email,String subject,String body) throws Exception{
		MimeMessage msg = new MimeMessage(session);
		msg.setFrom(new InternetAddress(currentEmail));
		msg.setRecipient(Message.RecipientType.TO, new InternetAddress(email));
		msg.setSubject(subject);
		msg.setContent(body, "text/html; charset=utf-8");
		Transport.send(msg);
	}
}

Пример использования:
MailHelper mailHelper = new MailHelper("192.168.0.2","25",
	"noreply","password123","noreply@sample.com");
try {
	mailHelper.send("target@sample.com", "Проверка", "Привет, Target!");
} catch (Exception e) {
	e.printStackTrace();
}
Конструктор принимает следующий параметры: Адрес и порт SMTP-сервера, доменную учетную запись и пароль, а также адрес электронной почты, от имени которой будут уходить письма. Метод send принимает те же параметры, что и в предыдущем примере: адрес получателя, тема и содержимое письма. В итоге на указанный ящик должно прийти сообщение:
Привет, Мир! 

Шпаргалка по MySQL (Утилиты)

Запуск MySQL-клиента:
mysql -uroot -p
Запуск MySQL-клиента c указанием хоста:
mysql -h192.168.0.2 -uroot -p
Запуск MySQL-клиента c указанием хоста и порта:
mysql -h192.168.0.2 -P3307 -uroot -p
Создание резервной копии:
mysqldump -uroot -p test > test.sql
Создание резервной копии c указанием максимального размера пакета:
mysqldump -uroot -p --max_allowed_packet=128M test > test.sql
Восстановление резервной копии:
mysql -uroot -p < test.sql test
Смена пароля:
mysqladmin -uroot -p password mynewpass

Биржевая диаграмма на Flot

Как-то мне дали задание:
Сделать рандомно растущий график используя любые инструменты. 
Образцом была следующая gif-ка: graph Просмотрев несколько инструментов для рисования графиков, остановился на Flot. Flot - JavaScript библиотека для jQuery для рисования графиков. Скачать Flot с примерами можно с официального сайта http://www.flotcharts.org. Стоит отметить наличие хороших примеров использования Flot для построения различных графиков и диаграмм. За вечерок смог реализовать на Flot задание. В статике это выглядит так: stock_chart В динамике это выглядит так: http://kesh.kz/stock_chart/. Кстати, мне так и не ответили справился ли я с заданием. Не пропадать же потраченному времени зря, поэтому выкладываю весь пример целиком, может кому пригодится: Скачать 🙂