Блог о программировании

Январь 22, 2012

 

Про интерфейс: Map<K,V>

Недавно от товарища пришел вопрос на засыпку: "Почему в интерфейсe java.util.Map метод get в качестве ключа принимает Object, а метод put использует женерики?"

V get(Object key); V put(K key, V value);

Сходу ответить не смог, пришлось разбираться.
Сразу пришло на ум несколько гипотез:

  • раздолбайство
  • легаси-код
  • "так специально задумано"

Не смотря на то, что первые две гипотезы вполне правдоподобны, думаю самый интересный это третий вариант ("так специально задумано"). Если поискать в интернете,то можно найти следующее объяснение.

По "контракту" Map должен работать с ключами по следующему правилу:

key==null ? k==null : key.equals(k)

Легко видеть, что т.к. в при вызове метода key.equals(k) объекты key и k потенциально могут быть абсолютно разных классов, то в итоге мы не имеем право вводить ограничение на тип в сигнатуре метода.

Конечно большинство java-программистов знают, что если нужно переопределить метод equals, то по хорошему надо сделать проверку типа проверяемого объекта, но в жизни всякое случается...

В качестве примера к объяснению, в интернете можно встретить пример на списках.

Суть очень простая. Мы предполагаем, что списки равны тогда, когда равны все их элементы. При этом по большому счету не так уж и важно какой именно это список (ArrayList, LinkedList и т.д.).
В итоге если использовать список в качестве ключа, то возникнет следующая (вполне реальная) ситуация.

Map<LinkedList, Integer> m = new HashMap<LinkedList, Integer>(); LinkedList a = new LinkedList(); a.add("1"); a.add("2"); m.put(a, a.size());   // конечно здесь мы явно создаем ArrayList, // но впринципе нам может вернуться какой-то непонятный список // из какого-то непонятного метода: // например List b = doVeryStrangeMethod(); List b = new ArrayList(a); // Этот вызов метода нормально компилируется и вернет результат: System.out.println(m.get(b)); // А вот этот вызов приведет к ошибке компиляции, т.к. put с generic-ом // m.put(b, b.size());

P.S.: Лично я в жизни не сталкивался с ситуацией, когда нужно было использовать список в качестве ключа.

Блог о программировании

Декабрь 15, 2011

 

Немного об OAuth, Android и Facebook

OAuth авторизация

OAuth - по определению означает Open Authorization. Поскольку в английском языке слова аутентификация (authentication) и авторизация (authorization) имеют одинаковое начало auth, то сокращение oauth очень неоднозначное. Эти понятия (авторизацию и аутентифакцию) очень часто путают друг с другом.
Например OpenID - это система для аутентификации.

Очень кратко опишу про аутентификацию и авторизацию (т.к. это простые и занудные понятия).

Если примитивно, то аутентификация - это, например, когда на вахте человек показывает пропуск или удостоверение, а вахтер смотрит и соображает "пропуск настоящий или нет? правильная печать? фотка совпадает? и т.д. ".
Другими словами проверяет валидный пропуск или нет.
Аутентификация может быть простой (логин/пароль), а может быть и очень замысловатой. Например бывалые вахтеры часто используют Face Recognition Authentication.

На веб-сайтах за вахтера эту работу осуществляет модуль аутентификации, который заставляет нас вводить логин и пароль, а затем проверяет их правильность.

После успешной аутентификации, наступает процесс авторизации.
Например, вахтер понял - пропуск настоящий, а вот можно ли пускать этого человека в здание или нет?

Например вполне может быть следующая ситуация - в выходной день в здание можно попасть только боссу или охраннику, а предъявитель пропуска - обычный человек, которого даже нет в списках работающих по выходным (или после 22-00)! Так что успешно пройденная аутентификация еще не значит, что человек сможет пройти туда, куда хотел.

Другими словами, мы при авторизации "даем добро" на определенные действия, при этом на момент авторизации (как правило) самого пользователя мы уже отаутентифицировали.
Например, в нашем случае с вахтером успешной "авторизации" человеку выдают например пенал с ключами и он пойдет по своим делам.
При этом, важно то, что в результате проделанной вахтером авторизации, человеку выдаются только определенные permissions.

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

Другими словами, если открытая аутентификация - это когда мы отдаем на сторону проверка логина+пароля,
то при открытой авторизации мы уже можем делать больше - управлять разрешениями.

Facebook

OAuth поддерживает Facebook и Twitter.

Общая схема работы следующая:

1. Отсылаем браузер на страницу аутентификации (допустим на Facebook или Twitter).
2. Пользователь видит родную фейсбучную страничку и не боясь вводит логин/пароль.

(картинка с сайта facebook-а)
3. Если все ОК. показывает страничку в которой спрашивает: "Дать право доступа к функции X?"

4. Если все ОК, браузер редиректит обратно, на URL нашего веб-сайта (какой именно URL мы указываем в п.1).
5. Обрабатываем редирект. В параметре редирект запроса к нам приходит "код доступа".
6. С кодом доступа и секретом, отправляем запрос на получение токена (ACCESS_TOKEN).
7. Отправляем прикладные запросы с токеном (например получить информацию о пользователе: https://graph.facebook.com/me?access_token=ACCESS_TOKEN ).

На фейсбуке всё очень подробно показано и рассказано: http://developers.facebook.com/docs/authentication/

Схема работы:

Android

В случае если вы разрабатываете приложение под Андроид, то засада на редиректе (шаг 4).

Например, в случае приложения под Android:
0. Нажимаете кнопку авторизовать.
1. Стартуем Activity для обработки Intent-а с нужным URL-ом для авторизации.
2. Открывается встроенный браузер.
3. Вводим логин/пароль и ....

Дальше возникает вопрос, как нам вернуться назад, в наш исходный Activity?
Основная хитрость redirect URL. Мы придумываем его в виде, вроде myapp://success и настраиваем наше Activity
так, что именно оно должно уметь отлавливать такие урлы:

<intent-filter> ... <data android:scheme="myapp" android:host="success" /> </intent-filter>

В итоге, после успешной авторизации браузер поймет, что нужно запустить Activity, которое может обработать этот странный URL "myapp://success".

А теперь вся правда в деталях.
1. Обязательно нужно указать в intent-filter, что бы Activity отлавливала запросы от браузера.

Подробнее читать здесь: http://developer.android.com/reference/android/content/Intent.html#CATEGORY_BROWSABLE

<intent-filter> ... <category android:name="android.intent.category.BROWSABLE" /> ... <intent-filter>

2. Чтобы не мучится, можно указать что Activity - singleInstance.

<activity ... android:launchMode="singleInstance">

Тогда обработку запроса можно будет безболезненно сделать в переопределенном методе onNewIntent.

3. Важно! Facebook не даст вставлять какие попало URL-ы!
Так что придется брать строчку из примера: REDIRECT_URI = "fbconnect://success"

Еще раз, указывать надо не "myapp://", а именно "fbconnect://".

4. Далее с Facebook, ситуация такая. Использовать библиотеки signpost смысла нет, замучаетесь прикручивать.
Для Twitter-а signpost работает нормально, примеры использования растиражированы на многих блогах.

Самый правильный способ - использовать готовое Facebook API для андроида.

Очень подробная инструкция в картинках есть на сайте Facebook-а: https://developers.facebook.com/docs/mobile/android/build/

Если все-таки этот путь вам не подходит или вы слишком упрямый, нужно учесть еще следующее:

5. В случае с Facebook лучше указывать параметр display=touch.

Т.е. что-то вроде:
http://www.facebook.com/dialog/oauth?client_id=APP_ID&redirect_uri=fbconnect://success&display=touch

Тогда сразу будет компактная и удобная форма для аутентификации.

Блог о программировании

Июль 24, 2011

 

Выложил на GitHub число прописью

Выложил под GPL-лицензией свою версию на Java число прописью.
Это например когда из BigDecimal("777.77") надо сделать "Семьсот семьдесят семь рублей 77 копеек".
В прошлом несколько раз искал такую штуку для разных проектов, а нормальной свободной реализации не было.
Поскольку я сейчас являются независимым разработчиком и не связан никакими обязательствами,
выкладываю свою версию под GPL.

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

Ссылка на github: numerals.

Блог о программировании

Июль 4, 2011

 

EncryptableProperties и защита от дурака

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

С учетом того, что довольно часто пароли придумывают люди, то запомнить их бывает очень просто.
Более того, некоторые пароли настолько поражают воображение, что их очень сложно забыть. Как правило они выглядят так: 123456, sa, manager и т.д...
Конечно это личное дело каждого, но выставлять на обозрения такие свои пароли, как-то не совсем прилично.

Если все-таки нет желания сильно напрягаться и прятать пароли в действительно укромные места, можно довольно просто сделать "защиту от дурака" (чтобы пароль явно не читался).

Как вариант можно использовать Jasypt. Этот довольно большой проект и его можно использовать и в других целей, но мы будем разбирать простой и конкретный случай: предотвратить хранение паролей в открытом виде в properties файле.
Главное, что нужно понимать, мы не строим защиту от серьезного злобного хакера, а делаем простую защиту от дурака!

Для этого:
Прописываем в pom.xml зависимость:

<dependency> <groupId>org.jasypt</groupId> <artifactId>jasypt</artifactId> <version>1.7.1</version> </dependency>

Если не maven, то можно просто скачать и подключить библиотеку с сайта. В любом случае, Jasypt удобен тем, что дополнительные зависимости не тянутся. Конечно, если нужна серьезная криптография, нужно будет кое-что доставить, но в нашем простом случае она нам не нужна. Мы просто хотим сделать так, чтобы пароль не смогли "тупо прочитать".

Дальше читаем учебник: http://www.jasypt.org/encrypting-configuration.html

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

jasypt-1.7.1\bin>encrypt.bat input=manager password=trololo ... ----OUTPUT---------------------- R+1ZbGFUdbNYXLJHdqgzVw== ...

Зашифрованное значение свойства, которое нужно спрятать оборачивается в ENC(). Пример:

# Допустим сохраняем в файл /tmp/a.properties username=system password=ENC(R+1ZbGFUdbNYXLJHdqgzVw==)

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

import java.util.Properties; import java.io.FileInputStream; import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.properties.EncryptableProperties; public class PropApp { public static void main(String[] args) throws Exception { StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); // выставляем пароль для всего нашего EncryptableProperties: trololo encryptor.setPassword("trololo"); Properties props = new EncryptableProperties(encryptor); props.load(new FileInputStream("/tmp/a.properties")); // логин не замаскирован String datasourceUsername = props.getProperty("username"); // system System.err.println("datasourceUsername = " + datasourceUsername); // пароль будет расшифрован на лету String datasourcePassword = props.getProperty("password"); // manager System.err.println("datasourcePassword = " + datasourcePassword); } }

Важно:

  • Легко видеть, что jasypt-овый EncryptableProperties является наследником обычного Properties. Таким образом, вы можете обращаться с ним как с обычным Properties.
  • EncryptableProperties меняет только метод getPropertу(), но не метод get(), который достался от Hashtable. Например, если в приведенном выше примере, вы вызовите метод props.get("password"), то получите ENC(R+1ZbGFUdbNYXLJHdqgzVw==)

Блог о программировании

Июнь 29, 2011

 

Main args, netbeans

Пара простых вещей (про Java/Scala + CLI и NetBeans)

Самый популярный и набивший оскомину пример HelloWorld встречается, наверное, уже во всех учебниках по программированию:

// Пример из туториала: http://download.oracle.com/javase/tutorial/getStarted/application/index.html class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); // Display the string. } }

Здесь String[] args — аргументы командной строки.
Например:
java HelloWorldApp 1 2 означает, что args будет равно {"1", "2"}.

Если передается всего один аргумент (например, "debug"), то все очень просто — можно подсмотреть пример из туториала: cmdLineArgs.

В случае, если аргументов много (как в гнусных линуксовых командах), то можно использовать какую-нибудь готовую библиотеку:

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

В том случае, если аргументы не такие сложные и не слишком простые, а что-то среднее, то тянуть для этих целей дополнительную библиотеку нет никакого смысла. Например, если нужно передать что-то вроде: "-x -size 1024 -v". Обычно это бывает, когда требуется небольшая, почти "одноразовая" программа...

Многие настолько не любят писать разбор таких аргументов, что лепят все параметры в системные свойства (java ... -Dfoo="some string"), чтобы потом дергать их через System.getProperty().
Это конечно удобно, но не всегда нормально.

Проще написать разбор обычными стандартными средствами:

public class App {   public static void main(String[] args) { boolean v = false, x = false; int size = 0; for (int i=0;i<args.length;++i) { String arg = args[i]; if (arg.equals("-v")) { v = true; } else if (arg.equals("-size")) { size = Integer.parseInt(args[++i]);//да, здесь может быть ArrayIndexOutOfBoundsException } else if (arg.equals("-x")) { x = true; } } System.err.println("v = " + v); System.err.println("x = " + x); System.err.println("size = " + size); } }

В Scala все то же самое.
Тривиальный случай – делаем как в примере на официальном сайте: Snippet: Match Arguments.
Что-то очень сложное – подключаем сторонние библиотеки (ту же апачевскую или jopt), что и в Java случае.
В том случае, если что-то среднее, то можно написать на чистой Scala:

object App { def main(args:Array[String]) = { var v = false; var x = false; var size = 0 ("" +: args :+ "") reduceLeft ( (i, j) => { i match { case "-v" => v = true case "-size" => size = j.toInt case "-x" => x = true case _ => }; j }) println("v =" + v ) println("x = " + x) println("size = " + size) } }

Про другую известную многим фишку, о которой хотел рассказать — макросы в NetBeans-ах.
Точнее, про самый популярный макрос - debug-var. Вызывается по нажатию: Ctrl-J D.
Вообще макросы в нетбинсах есть уже много лет, по-крайне мере, когда я только начинал использовать нетбинс (3.* версии), они уже там были.
Например, для Scala можно сделать макрос, который будет вставлять в код: println("var=" + var)

Настроить можно здесь:
Tools -> Option -> Editor -> Macros

Про другие полезные макросы можно почитать здесь

Блог о программировании

Март 11, 2011

 

Простые хаки и Greasemonkey


Недавно обратил внимание на то, что шрифты на сайте java.net какие-то неприятные – мутные и плохо читаются. Может они всегда были такими, а я стал чуть-более придирчивым, а может быть стали такими после перезагрузки.
На самом деле не столь важно почему, важно понять как подправить...

Могу предложить два способа из разряда "быстрых хаков".

Способ 1. Простой и скучный (и только для только для пользователей Firefox-а).
Нужно в файле: C:\Documents and Settings\\Application Data\Mozilla\Firefox\Profiles\\chrome\userContent.css
добавить настройку для конкретного домена:

@-moz-document domain(java.net) { body { font-family: Arial,Helvetica,sans-serif !important; } }

Способ 2. Простые хитрости Greasemonkey.

Greasemonkey (замасленная обезьяна, "механик") - удобная тулза для различного рода кастомизации, переделавание и допиливания страничек. Один из моих любимых инструментов для подобного рода экспериментов.
Если кратко, используя Greasemonkey вы сможете запускать какие-то свои скрипты на JavaScript-е у себя в браузере для определенных сайтов.

Приведу несколько очень полезных ссылок:

Кстати Greasemonkey сейчас работает в Google Chrome "из коробки". Для установки вы просто драг-анд-дропаете в окно браузера ваш файлик (что-то типа sitefix.user.js) и он будет воспринят как обычное расширение.
Для Firefox, как и раньше нужно поставить плагин https://addons.mozilla.org/ru/firefox/addon/greasemonkey/.

Примерный скрипт для подмены шрифтов выглядит следующим образом:

// ==UserScript== // @name FontFix // @namespace programmisty // @include http://*.java.net/* // ==/UserScript== var head = document.getElementsByTagName("head")[0]; var style = document.createElement("style"); style.setAttribute("type", 'text/css'); style.innerHTML = " body { font-family: arial,helvetica,sans-serif} "; head.appendChild(style);

Блог о программировании

Март 6, 2011

 

Удобный небезопасный кастинг

Удобный автоматический кастинг

Вещь не новая, но для тех, кто начинал программировать на Java в 90-ые и не очень привык к Generics-ам, это может быть интересно.

Пример использования. Вам нужен метод, который возвращает объекты разных классов. Это могут быть обычные объекты – String, Integer, List, а могут быть и какие-то "свои" сложные бизнес-объекты вроде – ABController, XYZComponent, QWERTYHelper, FooManager (название зависит от возраста и предпочтений программиста).

Так писали некоторые до Java 5.

Helper helper = ....; // Какой-то вспомогательный класс, который хранит всякую ерунду   String path = (String) helper.get("storage.path"); // да, я знаю, хардкодить константы плохо. Integer maxSize = (Integer) helper.get("max.size"); MyAwesomeDocumentManager manager = (MyAwesomeDocumentManager) helper.get("manager");

Сейчас можно писать попроще. Конечно это сахар, но код выглядит полегче:

String  path = helper.get("storage.path"); Integer maxSize  = helper.get("max.size"); MyAwesomeDocumentManager manager = helper.get("manager");

Как это делается:

public class Helper {   public <T> T get(String key) {   Object result = null; // Здесь должа быть спрятана какая-то страшная внутренняя реализация // например: result = map.get(key); return (T) result; } }

Принципиально ничего не меняется, только кастинг перешел во внутрь.
Если нужен статик, то можно написать так:

public static <T> T get(String key) { Object result; // опять какая-то страшная логика // типа: result = map.get(key); return (T) result; }

Блог о программировании

Февраль 14, 2011

 

Netbeans Scala Maven

Если вам приходилось работать в связке Netbeans 6.9.1 + Scala + Maven, то вы могли заметить, что компиляция происходит сильно медленнее, чем если бы вы НЕ использовали maven-scala-plugin.
Дело в том, что по умолчанию компиляция запускается в режиме "компилировать все классы". Такое поведение можно изменить, указав в настройках для recompileMode значение modified-only (компилировать только измененные). По-умолчанию оно all.
В некоторых случаях перевод в режим modified-only удобен, например если ваша задача не выпуск финальной версии продукта, а работа над определенным куском кода в режиме "написал, нажал Shift-F6, посмотрел что получилось...".
Внимание! Перевод recompileMode в режим modified-only может привести к нежелательным последствиям и побочным эффектам. Как говорится, не уверен - не обгоняй (а уверен - обгоняй).

Пример возможной (но далеко не оптимальной) модификации pom.xml.

<plugin> <groupId>org.scala-tools</groupId> <artifactId>maven-scala-plugin</artifactId> <configuration> <recompileMode>modified-only</recompileMode> </configuration> </plugin>

Блог о программировании

Февраль 12, 2011

 

Работа с видео и аудио в Java. Xuggle

Первый раз мне пришлось столкнуться с обработкой видео на Java лет 10-12 назад. Я еще был студентом и работал над проектом, в котором мы пытались сделать видео проигрыватель в виде апплета.
В те времена, для перекодирования видео мы пробовали использовать JMF (Java Media Framework). Нам нужно было сделать хитрую предварительную обработку видео, т.к. показ видео осуществлялся апплетом с помощью самописного алгоритма. В итоге пришлось отказаться от JMF в пользу приложения написанного на С++, т.к. JMF оказался не особо функциональным...

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


Говорят история развивается по спирали. В прошлом году взялся за проект, в котором опять-таки требуется работа с видео/аудио потоками. Небольшие исследования показали, что JMF с тех пор особо не прогрессировал. Нельзя сказать, что этот фреймворк стоял на месте, но прогресс шел явно медленней, чем развитие технологий работы с видео в целом.
К счастью спасение пришло от проекта
Xuggle!:

Оказалось, что это очень мощный и неплохо написанный проект для работы с мультимедийными данными. Причем позволяет осуществляет работу с "живыми" потоками в реальном-времени. По большому счету он представляет собой обёртку к ffmpeg (в xuggle используют специальную сборку ffmpeg).

Что мне особо понравилось:

  • Проект содержит высокоуровневое API которое позволяет осуществлять довольно сложные операции над различными видео и аудио данными.
  • Имеется очень неплохой Tutorial, Wiki и несколько скринкастов, в которых доходчиво объясняется как работать с этой библиотекой.
  • В Xuggle есть возможность получить стандартный BufferedImage. Над которым настоящий java программист может осуществлять практические любые действия! При этом полученный BufferedImage можно опять таки использовать дальше и с помощью средств Xuggle формировать новый видео-поток.
  • Конечно же работает под windows и под linux.

Вот пример их демки :

Единственно настораживает то, что давно не было никаких обновлений. Но текущая версия вполне стабильная.

В качестве примера, приведу примитивный пример - получить изображения из видео с 6 по 12 секунду с шагом в 500 милисекунд и сохранить их в PNG.
Здесь я модифицирую их стандартный пример из библиотеке, который выводит видео на экран. Единственное нужно - убрать синхронизацию, убрать показ видео, добавить сохранение в PNG. Понятно что в реальных приложениях программный код будет более аккуратный, здесь просто демонстрируются возможности.

Исходник:

import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import com.xuggle.xuggler.ICodec; import com.xuggle.xuggler.IContainer; import com.xuggle.xuggler.IPacket; import com.xuggle.xuggler.IStream; import com.xuggle.xuggler.IStreamCoder; import com.xuggle.xuggler.IVideoPicture; import com.xuggle.xuggler.Utils;   public class Foo {   public static void main(String a[]) throws Exception { String filename = "C:/temp/1.avi"; File outdir = new File("c:/temp/pictures"); IContainer container = IContainer.make();   if (container.open(filename, IContainer.Type.READ, null) < 0) throw new IllegalArgumentException("could not open file: " + filename); int numStreams = container.getNumStreams(); int videoStreamId = -1; IStreamCoder videoCoder = null;   // нужно найти видео поток for (int i = 0; i < numStreams; i++) { IStream stream = container.getStream(i); IStreamCoder coder = stream.getStreamCoder(); if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) { videoStreamId = i; videoCoder = coder; break; } } if (videoStreamId == -1) // кажись не нашли throw new RuntimeException("could not find video stream in container: " + filename);   // пытаемся открыть кодек if (videoCoder.open() < 0) throw new RuntimeException( "could not open video decoder for container: " + filename);   IPacket packet = IPacket.make(); // с 3-ей по 5-ую микросекунду long start = 6 * 1000 * 1000; long end = 12 * 1000 * 1000; // с разницей в 100 милисекунд long step = 500 * 1000;   END: while (container.readNextPacket(packet) >= 0) { if (packet.getStreamIndex() == videoStreamId) { IVideoPicture picture = IVideoPicture.make( videoCoder.getPixelType(), videoCoder.getWidth(), videoCoder.getHeight()); int offset = 0; while (offset < packet.getSize()) { int bytesDecoded = videoCoder.decodeVideo(picture, packet, offset); // Если что-то пошло не так if (bytesDecoded < 0) throw new RuntimeException("got error decoding video in: " + filename); offset += bytesDecoded; // В общем случае, нужно будет использовать Resampler. См. // tutorials! if (picture.isComplete()) { IVideoPicture newPic = picture; // в микросекундах long timestamp = picture.getTimeStamp(); if (timestamp > start) { // Получаем стандартный BufferedImage BufferedImage javaImage = Utils .videoPictureToImage(newPic); String fileName = String.format("%07d.png", timestamp); ImageIO.write(javaImage, "PNG", new File(outdir, fileName)); start += step; } if (timestamp > end) { break END; } } } } } if (videoCoder != null) { videoCoder.close(); videoCoder = null; } if (container != null) { container.close(); container = null; }   } }

Результат:

Блог о программировании

Октябрь 20, 2010

 

Читерство в NetBeans. Ввод и использования мат. символов и букв греческого алфавита .

Оригинальная идея взята из поста Gabriel's software development blog. Статья в довольно старая, еще в прошлом году опубликованная.

Если коротко:

val Π = Math.Pi
def √(x:Double)=Math.sqrt(x)
val x= √(9*Π)
def ∑(r:Range)(f:Int =>Int)=r.reduceLeft(_+ f(_))
def ∏(r:Range)(f:Int =>Int)=r.reduceLeft(_* f(_))

val s= ∑(1 to 100)(x=>x^2)

Выглядит супер, идея классная! Но как сделать так, чтобы было удобно вводить эти символы для меня было загадкой.

В итоге случайно недавно придумал как это можно сделать просто и удобно средствами IDE, а точнее в NetBeans.

Просто я вбил все нужные мне символы в Code Templates (Tools → Options → Editor → Code Templates) и сделал два макроса для [Alt+<] = "→" и [Alt+<] = "⇒".

Как это работает можно посмотреть здесь:

http://www.youtube.com/watch?v=mVz6DyZrzms

То есть вы вводите например alpha и жмете [Tab] и затем вставляется α. Самое главное, это настраивается только например для Scala, таким образом это не мешает при работе на других языках. Также если вы хотите написать просто alpha, вы просто не нажимайте [Tab] и всё!

P.S.: На самом вбивать весь греческий алфавит довольно скучное занятие, можно найти файл вроде этого:

C:\Documents and Settings\<USER_NAME>\.netbeans\6.9\config\Editors\text\x-scala\CodeTemplates\org-netbeans-modules-editor-settings-CustomCodeTemplates.xml

и сгенерить все аббревиатуры.

Вот пример моего файла - CustomCodeTemplates.zip. Внимание! Это только пример, возможно он Вам не подойдет.

Будьте аккуратны, перед обновлением сделайте резервную копию!

 
<< < 1 из 2 > >>