Автор: vit

  • Scala и пустота

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

    Null

    Null – это trait. Объект null (с маленькой буквы) — это как раз и есть объект типа Null. Он находится внизу иерархии типов в Scala, в противовес AnyRef.
    Благодаря этому вы всегда можете как-бы “занулить” любую ссылку, т.е. присвоить ссылки значение null:

    scala> var x = "String"
    x: java.lang.String = String
    scala> var i = List(3)
    i: List[Int] = List(3)
    scala> i = null
    i: List[Int] = null
    scala> x = null
    x: java.lang.String = null
    

    Null работает только для ссылочных типов, для более общего случая, есть “ничто (Nothing)” .

    Nothing

    Nothing – это тоже trait. Nothing находится на самом дне иерархии типов, в противовес Any. Соответственно, это более общий тип, чем Null и подходит даже для AnyVal объектов (числа, буквы, правда/ложь и т.д.).

    В отличие от Null, Nothing не может иметь экземпляров (на то оно и ничто).
    Другими словами нет аналога null для Nothing.

    Возникает вопрос, где такое самое “нижнее ничто” может использоваться?
    В документации по API можно найти несколько примеров:

    // пакет scala.sys
    def error(message: String): Nothing = throw new RuntimeException(message)
    

    Этот метод никогда ничего не возвращает, поэтому возвращаемый тип Nothing.

    Unit

    Unitкласс, чем-то похоже на void, который используется в Java. В Scala тип Unit применяется тогда, когда нужно показать, что функция возвращает пустое значение (но все-таки что-то возвращает, хоть и пустое).

    Если открыть документацию, то можно увидеть что:

    class Unit extends Any with AnyVal
    

    Внимание! AnyVal, а не AnyRef. Это значит, что Unit это не ссылочный тип ( в отличие от Null). Можно сказать, что Unit-у как бы “ближе по родству” будут числа, буквы и другие примитивные типы (которые тоже AnyVal).

    В отличие от Nothing, Unit повезло больше. Он может иметь свой объект, правда в единственном экземпляре. Он обозначается двумя круглыми скобками: (). Например:

    scala> val u = ()
    u: Unit = ()
    

    Другими словами Nothing уместен тогда, когда функция в принципе ничего не возвращает, а Unit – это когда возвращает, но оно пустое.
    Это отличие существенно. Например результат вызова функции с Unit может быть присвоено (в Java с void такой фокус не выйдет).

    scala> def foo():Unit = {}
    foo: ()Unit
    scala> val u = foo()
    u: Unit = ()
    

    Nil

    Nilобъект, пустой список (extends List[Nothing]).
    Поскольку Nil – это список, хоть и пустой, у него как у любого списка есть метод :: (два двоеточия), с помощью которого удобно создавать списки:

    scala> var x = 1 :: 2 :: Nil
    x: List[Int] = List(1, 2)
    

    Это возможно благодаря тому, что название метода заканчивается на : (двоеточие), в таком случае метод применяется к правому операнду (работает для операторной нотации вызова метода).

    Другими словами, это аналогично вызову: (Nil.::(2)).::(1)

    None

    None – это такой хитрый объект (extends Option[Nothing]) , который используется в случае, если мы хотим получить что-то, например, из Map, а его там нет.

    Например:

    scala> var m = Map(1->2)
    m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2)
    scala> val n = m.get(100)// ну нет такого элемента
    n: Option[Int] = None
    

    None примечателен тем, что:

    • это объект (т.е. синглтон)
    • это кейс-объект
    • наследуется от Option[Nothing]

    В случае попытки получить значение (вызвав метод n.get()), мы получим исключение:java.util.NoSuchElementException.

    Если у None вызывать метод isEmpty() – мы получим true.

    Поскольку None – объект кейс-класса, то мы можем его “матчить” (сопоставлять по шаблону).

    scala> n match { 
     case Some(x) => println("x:" + x) 
     case None => println("none") 
    }
    

    Если у None вызвать метод toList – мы получим пустой список (т.е. Nil).

    scala> n.toList() == Nil
    res21: Boolean = true
    

    Поскольку None объявлен как extends Option[Nothing], а Nothing – “самое нижнее ничто”, то None может работать с любыми типами (как с ссылочными так и с примитивными).

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

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

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

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

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

    Для этого: (далее…)

  • Main args, netbeans

    Пара простых вещей (про аргументы командной строки + Java/Scala и чуть-чуть про 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;iSnippet: Match Arguments.
    Что-то очень сложное – подключаем сторонние библиотеки для разбора аргументов командной строки (ту же апачевскую или jopt).
    В том случае, если что-то среднее, то можно написать на чистой 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)
       }
    }
    

    Пару слов про reduceLeft. По сути этот тот же foldLeft, только начинается с первого элемента коллекции. Подробнее можно почитать в Scala API по работе с коллекциями.

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

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

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

  • Немного карри

    Использовать карринг в Scala одно удовольствие.
    Само определение каррирования(или карринга, названо в честь Хаскелла Карри):

    Для функции h типа h : (A × B) → C оператор каррирования Λ выполняет преобразование
    Λ(h) : A → (B → C)

    Отметим, что Λ – это оператор, то есть “функция над функциями”.
    Например берем функцию foo(x,y), каррируем и получаем moo(x)(y) – функцию от x которая возвращает функцию от y. (далее…)

  • Java + Excel файлы (Apache POI)


    С периодичностью раз в два-три года сталкиваюсь с проектами, в которых опять нужно работать с Excel файлами.
    Наверно это у меня что-то кармическое…
    Сейчас, в очередной раз приходиться реализовать полуавтоматический разбор сотен excel-файлов с прайсами.
    В прошлых своих проектах использовал JExcelApi.
    Ничего плохого про эту библиотеку сказать не могу, но хочется какого-то разнообразия в жизни поэтому в этот раз с товарищем решили попробовать Apache POI.

    Apache POI поддерживает как формат для обычных *.xls файлов (HSSF) так и *.xlsx файлы (XSSF).

    Кстати, формат для *.xls файлы в Apache POI они обзывают “HSSF – Horrible SpreadSheet Format”, то есть “Вселяющий ужас формат для электронных таблиц”.
    Для того, чтобы приступить к работе, как обычно прописываем зависимости в pom.xml:

      
            
                org.apache.poi
                poi
                
                3.7
            
        
    

    Для примера, приведу очень простой файл – список ФИО, сумма + Итог:

    Если нужно просто вытащить текст, можно использовать “класс-извелкатель”: ExcelExtractor (далее…)

  • Календари и даты

    Постоянно наталкиваюсь на людей, которые утверждают, что “Date – deprecated, нужно использовать Calendar”.
    Это не верно! Вариаций на тему “почему это не верно” где-только уже не написано, но все-равно появляются люди которые мне доказывают, что правильней использовать Calendar (аргументеруя именно “устареванием” Date).

    На самом деле в классе Date просто много deprecated методов. Но если почитать внимательно документацию, то видно, что устарел не сам класс, а просто часть функций этого класса еще во времена выхода Java 1.1 была вынесена в другой класс. Вот и всё!

    Целевое назначение объектов класса Date сохранилось. Это простой и легкий класс для обозначения времени (например 2010-01-01T12:00:00). Он сериализуется, и если вам нужно хранить именно дату (и время) в каком-то классе, то в большинстве случаев, разумнее всего использовать именно Date.

    Что касается класса Calendar , то это в первую очередь календарик. Он нужен для того, чтобы узнать например какой день недели был на указанную дату, сколько дней прошло с начало года и т.д.. Такой своеобразный аналог обычного настенного календаря с курсором. И гонять его между разными слоями/тирами приложения в составе трансферных объектов или делать его атрибутом какого-то класса для обозначения даты-времени не логично (в большинстве случаев).

    Если вам нужно отформатировать или распарсить дату, вы можете использовать например SimpleDateFormat.

    Кстати о SimpleDateFormat. Многие его тоже используют не правильно. Постоянно наталкиваюсь в чужих исходниках на конструкции типа:

    // так лучше не делать!
    private final static SimpleDateFormat DDMMYYYY = new SimpleDateFormat("dd.MM.yyyy");
    

    Конечно дело не в том, что он статик! Просто SimpleDateFormat он в общем-то не потокобезопасен. Как написано в документации:

    Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

    То есть по хорошему, если это статик поле будут конкурентно использоваться, то можно нарваться на неприятности. Как правило такие баги (когда игнорируют многопоточное выполнение) не ловятся юнит-тестами, зато в продакшене могут создавать проблемы.

    P.S.: Интересно, но использование Calendar вместо Date можно встретить даже в таком матёром API как JCR. Вот не знаю, почему они используют Calendar, а не Date…

  • Apache HTTPD, mod_jk, Apache Tomcat, Linux

    1. Начало.

    Если Вы ставите Tomcat как-то так: (от рута) aptitude install tomcat6 tomcat6-admin tomcat6-examples,
    то прежде чем двигаться дальше, вам возможно стоит обратить внимание на настройки URIEncoding в server.xml.

      
      
    

    Здесь и далее: Томкат => Apache Tomcat, Апач => Apache HTTPD.

    2. Вяжем.

    Классическая схема работы Томката (Apache Tomcat) в продакшене, это связка его с Apache (Apache HTTP Server) через mod_jk. Так делают уже много-много лет и это проверенное на практики и рекомендованное многими решение.
    Связка делается через протокол AJP (Apache JServ Protocol). Это специальный бинарный протокол для прокидки запросов от web-сервера в глубину к другим серверам (например Tomcat-у).

    Зачем такое нужно?
    1. Снижаем нагрузку с томката. Статику (картинки, html-ки и т.д.) пусть лучше отдает апач, а запросы к сервлетами и jsp-кам прокидываются томкату.

    2. Возможна балансировка нагрузки. Например один апач – несколько томкатов.

    Кстати, можно связывать апач не только с томкатом, а например с Jetty (через mod_proxy), и наоборот томкат прикручивать например к nginix. Мы здесь такие варианты не будем рассматривать.

    Итак, допустим у вас убунта с апачем и томкатом. На других линуксовых дистрибутивах аналогично.
    Ставим mod_jk: (от рута) aptitude install libapache2-mod-jk или скачаем и ставим отсюда : http://tomcat.apache.org/download-connectors.cgi

    Из общего правила структуры линуксовой файловой структуры мы знаем, что настройки должны находиться в папке /etc/.
    Легко видеть, что:
    – настройки томката будут в папке /etc/tomcat6
    – настройки mod_jk в /etc/libapache2-mod-jk
    – настройки апача в /etc/apache2

    Внимание! Дальше приводится упрощенная схема для работы в лабораторных условиях.
    На реальных серверах ввод в эксплуатацию без тщательного изучения документации по mod_jk, веб-серверу и томкату крайне опасен!
    Нужно обратить особое внимание на настройки безопасности.

    Теперь приступим. Начнем от фронта.
    В настройках сайта (например: /etc/apache2/sites-available/default) указываем какие запросы куда перенаправлять и кто должен делать обработку таких запросов.
    Например:

     
    ... 
        JkAutoAlias /usr/share/tomcat6-examples/
        JkMount /examples/* ajp13_worker
    
    

    ajp13_worker – название “ажп-работника”, он задается в файле workers.properties (в Убунте: /etc/libapache2-mod-jk/workers.properties):

      # список работников...
      worker.list=ajp13_worker
    

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

    Где находится файл workers.properties прописано в настройках mod_jk (в /etc/apache2/mods-available файл jk.load)
    Например, что-то типа этого:

    LoadModule jk_module /usr/lib/apache2/modules/mod_jk.so
    
    JkWorkersFile /etc/libapache2-mod-jk/workers.properties
    
    JkLogFile     /var/log/apache2/mod_jk.log
    JkLogLevel    info
    JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
    JkRequestLogFormat     "%w %V %T"
    
    JkOptions +ForwardURICompatUnparsed
    

    На что обратить внимание!
    Параметр JkWorkersFile указывает именно на правильный workers.properties
    Параметр JkOptions имеет значение “+ForwardURICompatUnparsed”, это нужно для нормальной обработки кодировок.

    Значение других параметров следует посмотреть в документации.

    Далее в настройках томката (/etc/tomcat6/server.xml) нужно проверить,
    что НЕ ЗАКОММЕНТИРОВАН AJP Connector (port 8009, URIEncoding=”UTF-8″):

    
     
       
    
    

    Общая схема конфигурационных файлов выглядит так:

    Не смотря на то, что в документации все хорошо описано, и есть такие полезные параметры как “JkAutoAlias”, которые сильно упрощают жизнь.
    Рекомендую, после того как завершите настройку тщательно проверить надежность и безопасность вашей конфигурации.

    По-крайне мере нужно проверить правильно ли будут работать ваши security-constraint и различные фильтры.
    Также проверить ограничение доступа к служебным ресурсам, работу в разных режимах (отключен томкат, реальные запросы из внешней сети и т.д.).

  • Java one, Day #2

    Java One, День Второй. Москва.

    По просьбе друзей выкладываю фотографии с конференции Java One. Фотки не мои, так что вопросы где взять исходные фотографии не ко мне.

    Как я туда попал. Вначале идти не очень хотелось – дел по работе выше крыши. Но поскольку Java One мероприятия последнее время проводились в Питере, то я их постоянно пропускал, в итоге стало уж больно любопытно посмотреть что изменилось… Плюс  товарищ со старой работы сказал, что тоже пойдет, в общем в итоге любопытство взяло вверх.

    Что изменилось?

    На первое что обратил внимание – платный вход. Тарифы были такие:
    Super Saver с 24 февраля по 20 марта, 2011: 500 руб
    Early Bird с 21 марта по 31 марта, 2011 : 1000 руб
    с 1 апреля по 11 апреля, 2011: 1500 руб
    (правда для студентов потом открыли бесплатную регистрацию, но я уже давно не студент )

    Само объявление о Java One увидел в твиттере, тогда еще был тариф Super Saver, так что прошел по минимальному прайсу. Правда с системой оплаты были какие-то глючки, но в итоге я свой билет получил.
    Конференция проходила в здании Академии Наук, м. Ленинский проспект. Такое интересное здание с часиками.

    По ходу были расставлены указатели куда идти.

    На входе дежурили полицейские и проверяли сумки, рюкзаки. На редкость не хамоватые, наверно влияет аура здания Академии Наук.

    Там же рядом сидела девушка с красным платочком на шее, помогала ориентироваться куда двигаться дальше.

    Т.к. я пришел позже открытия, то к гардеробу очереди уже не было.

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

    человек-дюк

    Главный зал конференции конечно смотрелся мощно:

    На входе стояли девушки в фирменной одежде и сканировали бейджики. Устройство для сканирования смутно видно внизу на фото:

    Когда начался перерыв на кофе всю еду смели моментом. Вода в термосах закончилась почти сразу.

    Еще можно было сходить на мастер классы. Тоже записывала девушка с красным платочком.

    В этом помещении мастер-классы. Ноутбуки кажется DELL-ы.

    Обед был в пластиковых наборах. В первый день некоторым еда не досталась, а на второй день видел как один парень съел две порции… Вот такой “культур-мультур”, кто-то ходит голодный, кто-то хомячит за двоих )

    Зато были организованы такие приятные места с красными пуфиками,  где был WiFi и можно было посидеть с ноутбуком.

    Из чисто оракловых фишек, был занятный докладчик с очень красивым английским. Рассказывал про то как можно апгрейдить на живую оракловую БД (используя силу фичи – Edition). Грубо говоря как это делают сейчас у нас – когда наступает день Икс, отрубают всех пользователей и гонят ДБА-шников с программистами на работу на выходных (или в ночь), чтобы выложили новую версию в продакшн. Так вот, чтобы всем жилось легче, иногда ЭТО можно с помощью хитрых манипуляций делать постепенно и на живую. Главное знать когда это применимо и как это делать. Вот фото докладчика:

    Ну и конечно же самое главное это всегда не сами доклады… В общем-то я считаю вся соль таких тусовок это возможность пообщаться с другими программерами. Посплетничать о тенденциях,  посмотреть в глаза разработчикам API, помучить разные девайсы.

  • Уменьшение изображения на Java

    Довольно рутинная операция. Есть несколько способов.
    Возьмём исходное изображение:

    1. Самый простой.

    Первый на stackoverflow.
    Суть метода очень проста – создаем BufferedImage меньшего размера, затем прорисовываем в него исходное изображение.
    Далее сохраняем обычным ImageIO.write()

            BufferedImage scaled = new BufferedImage(scaledWidth, scaledHeight,
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D g = scaled.createGraphics();
            g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
            g.dispose();
    
            ImageIO.write(scaled, "JPEG", new File("1.jpg"));

    Результат:

    Недостатки:
    – Алгоритм сжатия хоть и быстрый, но результат неприятный.
    – Реализация сохранения JPEG ImageIO по-умолчанию не радует.

    2. Улучшаем качество JPEG-картинки.

    Для этого делаем так:

       /* код приведён только в учебных целях! не использовать в продакшн */
       public static void saveAsJPEG(BufferedImage scaledImage, OutputStream out) throws IOException {
    
            ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(scaledImage);
            Iterator iter = ImageIO.getImageWriters(type, "JPEG");
            // берем первый попавшийся для JPEG
            ImageWriter writer = (ImageWriter) iter.next();
            ImageOutputStream ios = ImageIO.createImageOutputStream(out);
            writer.setOutput(ios);
    
            JPEGImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
            iwparam.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
            // Вот здесь выкручиваем качество на максимум!
            iwparam.setCompressionQuality(1.0F);
            IIOImage iioimage = new IIOImage(scaledImage, null, null);
            writer.write(null, iioimage, iwparam);
            ios.flush();
            writer.dispose();
            ios.close();
        }

    Результат:

    Недостатки:
    – Сильно вырастает размер файла. Это известный баг. Подробности здесь: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5028259.
    – Алгоритм уменьшения картинки всё равно оставляет желать лучшего.

    3. Используем хинты.

    У Graphics2D есть так называемые RenderingHints, которые позволяют улучшить качество относительно настроек по умолчанию:

    g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
    RenderingHints.VALUE_INTERPOLATION_BICUBIC);
    g.setRenderingHint(RenderingHints.KEY_RENDERING,
    RenderingHints.VALUE_RENDER_QUALITY);
    

    Результат:

    Недостатки:
    Качество стало лучше, но не сильно.

    4. Уменьшаем постепенно.

    Суть алгоритма – сжимать не сразу, а в несколько итераций.
    Код можно посмотреть здесь: http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html (очень позновательная и интересная статья, подробно расписано про уменьшение размера картинок).

    Результат:

    5. Метод из JDK 1.1.

    Впринципе также можно воспользоваться методом из JDK 1.1:
    Image.getScaledInstance(width,height, Image.SCALE_SMOOTH)

    Image scaled = originalImage.getScaledInstance(scaledWidth,
                    scaledHeight, Image.SCALE_SMOOTH);
    g.drawImage(scaled, 0, 0, null);
    g.dispose();

    Результат:

    Недостатки:
    Реализация метода может различаться на конкретных платформах.

  • Простые хаки и 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);