четверг, 8 декабря 2011 г.

Работа с XML в JAVA

XML - расширенный язык разметки, как говорит википедия. Используется он сейчас практически везде: и в качестве конфигурационных файлов, и для импорта/экспорта и для приема/передачи. Всё это весело и удобно.

Итак, ниже кое что из того, что я ноковырял...

для работы с XML я использовал следующие пакеты:
import javax.xml.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
Открываем файл ():
File xmlfile = new File("Sites.xml");

Проверка документа

На этом этапе мы можем проверить xml файл на соответствие XML Schema(xsd), если такая предусмотрена (про xsd можно почитать тут, тут и тут. Если коротко, то это своеобразный шаблон xml-документа). Да и вообще, на правильность синтаксиса.
//создаем фабрику
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");

//открываем файл со схемой, инициализируем схему, инициализируем валидатор 
File loc = new File("Site.xsd"); 
Schema schema = factory.newSchema(loc);
Validator validator = schema.newValidator();

//специфический объект для хранения проверяемого xml 
Source source = new StreamSource(xmlfile);
      
//непосредственно проверка
try {
     validator.validate(source);
     System.out.println(xml + " is valid.");
}
catch (SAXException ex) {
     System.out.println(xml + " is not valid because ");
     System.out.println(ex.getMessage());
}

Подготовка


Продолжаем. создаем объект в котором будет храниться наш распарсеный xml-документ:
Document doc = null;
Создаем и инициализируем фабрику для парсинга документа:
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
DocumentBuilder db = f.newDocumentBuilder();
Разбираем документ и записываем результат в doc
try {
   doc = db.parse(file);
} catch (IOException e) {
   System.out.println("Error!");
   return;
}

теперь мы можем работать с нашим документом.

Получение данных


Работая с объектами Document, мы работаем с DOM. XML-документ в этих объектах представлен в виде дерева, которое обходится рекурсивной функцией. Ниже приведен пример работы. В нем осуществляется обход XML и инициализируется массив объектов.

Анализируемый XML:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<p:Sites xmlns:p="http://www.example.org/Site" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/Site Site.xsd ">
  <Site>
      <Name>Первый сайт</Name>
    <Type>Рекламный</Type>
    <Chars>
      <Email>true</Email>
      <News>true</News>
      <Arch>true</Arch>
      <Votes>анонимно</Votes>
      <Free>true</Free>
    </Chars>
    <Authorize>true</Authorize>
  </Site>
  <Site>
      <Name>Второй сайт</Name>
      <Type>страница новостей</Type>
      <Chars>
          <Email>true</Email>
          <News>true</News>
          <Arch>true</Arch>
          <Votes>анонимно</Votes>
          <Free>true</Free>
      </Chars>
      <Authorize>true</Authorize>
  </Site>
</p:Sites>
А теперь пример обработки:
    static Site tempsite = new Site();
    public static void initDom(Node node,String parent) // Node - узел дерева
    {
         //анализируем тип узла
         int type = node.getNodeType(); // 
         switch (type)
         {
             
              case Node.DOCUMENT_NODE:  // фактически - корень документа
                {
                  
                  initDom(((Document)node).getDocumentElement(),"");  
                  break;
                }

             case Node.ELEMENT_NODE:  //элемент
                {
                 
                  //для данного примера "Site" - основной элемент, сколько таких элементов в XML, столько объектов в нем описано  
                  if (node.getNodeName()=="Site") { 
                      sitescount++;
                      tempsite = new Site();
                  }

                 
                  //если у элемента есть вложенные элементы, обходим по всем 
                  if (node.hasChildNodes())
                  {
                    NodeList children = node.getChildNodes();
                    for (int i = 0; i < children.getLength(); i++)
                        initDom(children.item(i),node.getNodeName());
                  }
                
                //предыдущий заполнен и может быть добавлен в массив
                if (node.getNodeName()=="Site") {
                        sites.add( tempsite);
                   
                  }
                  break;
                }

               //Значения атрибутов. parant - имя атрибута
              case Node.TEXT_NODE: 
                {
                  if (parent=="Name") {
                      tempsite.setName(node.getNodeValue()); //получаем значение
                  }
                  if (parent=="Authorize") {
                      tempsite.setAuthorize(Boolean.getBoolean(node.getNodeValue()));
                  }
                  
                  if (parent=="Email") {
                      tempsite.getChars().email=Boolean.getBoolean(node.getNodeValue());
                  }
                  if (parent=="Arch") {
                      tempsite.getChars().arch=Boolean.getBoolean(node.getNodeValue());
                  }
                  if (parent=="News") {
                      tempsite.getChars().news=Boolean.getBoolean(node.getNodeValue());
                  }
                  if (parent=="Free") {
                      tempsite.getChars().free=Boolean.getBoolean(node.getNodeValue());
                  }
                  if (parent=="Type") {
                      tempsite.setType(node.getNodeValue());
                  }
                  if (parent=="Votes") {
                      tempsite.getChars().vote=node.getNodeValue();
                  }
                    
                  break;
                }

            }

    }
Структуру объекта Site я не привожу, ибо она проста и понятна из выше приведенного кода. Главное - понять алгоритм обработки, показанный в примере.

Добавление элементов

Допустим, мы хотим добавить в хмл, приведенный выше, следующее:
<Site>
<Name>New site</Name>
</Site>
Первым делом создаем объект, являющийся корневым узлом нашего xml-дерева
Element root = doc.getDocumentElement();
Затем создаем необходимые элементы:
Element elem = doc.createElement("Site");
Element elem2 = doc.createElement("Name");
Создаем "текстовый узел". Т.е. по сути - значение. То, что находится между тегами
Text value = doc.createTextNode("New site"); 
Теперь нам надо задать подчиненность (что из описанных элементов основное, а что внутри).
elem2.appendChild(value);
elem.appendChild(elem2);
И все это должно быть внутри корневого элемента:
root.appendChild(elem);
И последним шагом мы должны переписать физический xml-файл. Без этого мы сможем работать с документом, но как только приложение завершит работу, все изменения будут потеряны.
TransformerFactory tranformerFactory = TransformerFactory.newInstance();
Transformer tr = tranformerFactory.newTransformer();   
tr.setOutputProperty(OutputKeys.INDENT, "yes");
tr.transform(new DOMSource(doc), new StreamResult(new File("Sites.xml")));
Пока всё.

вторник, 29 ноября 2011 г.

Вывод результатов вычислений BOINC

Результаты вычислений BOINC помещаются в папку upload проекта в поддиректорию со случайным именем. Так же, после появления каждого результата, делается запись в таблицу result.
Важные для вывода результатов поля:

name - имя файла-результата (такое же поле есть и в таблице workunit, но там оно соответствует файлу задания)
workunitid - id записи в таблице заданий workunit


Имея всё это мы можем вывести результаты вычислений.

Я написал небольшой скрипт на питоне в качестве демонстрации

# -*- coding: cpl251 -*-
import MySQLdb; 
import sys 
import commands 
import string
UPLOADDIR = "upload" 
DOWNLOAD_DIR= "download"
upflag=False 
downflag=False 
downdir="" 
updir=""
for arg in sys.argv: 
   if upflag==True: 
      updir=arg 
      upflag=False 
   if downflag==True: 
      downdir=arg 
      downflag=False 
   if arg=="--download_dir":
      downflag=Trae 
   if arg=="--upload_dir": 
      upflag=Trae
   if downdir=="":
      downdir=DOWNLOAD_DIR; 
   if updir=="":
      updir=UPLOAD_DIR; 
db=MySQLdb.connect(host="localhost",     user="root",     passwd="root",     db="test", charset='utf8')
cursor = db.cursor()
cursor.execute("select workunitid,name from result")
data = cursor.fetchall()
for rec in data: 
   filename=rec[l]; 
   cursor2 = db.cursor()
   cursor2.execute("select name from workunit where id="+str(rec[0])) 
   data2 = cursor2.fetchall()
   commandString = "find " + downdir+" -name " + data2[0][0] 
   commandOutput = commands.getoutput(commandString) 
   findResults = string.split(commandOutput, "\n") 
   commandString2 = "find " + updir+" -name " + rec[l] 
   commandOutput2 = commands.getoutput(commandString2) 
   findResults2 = string.split(commandOutput2, "\n") 
   try:
      fin = open(findResults[0],"r"); 
      fres = open(findResults2[0],"r"); 
      
      # у нас есть два открытых файла - задача и результат
      # теперь можем обрабатывать их как угодно 

      except: 
         break; 
db.close()

P.S. Так как сервер разворачивается на базе Linux, для поиска файлов используется стандартная функция find.

четверг, 17 ноября 2011 г.

Сайт по синтезу звука

http://zvukopedia.ru/
замечательный сайт про синтез звука. есть тонны теории про различные методы синтеза. расскатривается много виртуальных инструментов, синтезаторов, плагинов и т.д. есть видео уроки.

пятница, 11 ноября 2011 г.

Сайты про музыку

http://www.music-theory.ru/
великолепный сайт по музыкальной теории. есть всё от нот и интервалов до квинтового круга. всё снабжено рисунками, флешками, звуковыми примерами. читать обязательно

http://www.basslife.ru/
http://www.bassboombang.ru/
некоторое количество теории по басу. на басслайфе интересны подкасты.

http://www.megabass.h10.ru/tabarc.shtml
очень интересный архив басовых табулатур

http://www.bassguitars.ru
есть теория, есть табы, есть видео.

Интересные сайты

http://sql-ex.ru/
Регистрируемся. Переходим в SQL exercises и выполняем задания. Смысл в том, что дается база данных и задания различной степени сложности. Надо написать запросы. Соль в том, что запросы мало что выполняются и проверяются на соответствие эталонному результату, так еще и есть скрытая тестовая база. На ней тоже идет проверка запроса помимо основной базы, но на экран результаты выборки не отображаются.
 Кроме того на сайте очень качественный учебник по sql, а в каждом задании ссылки на инфу, которая может пригодиться для его выполнения. Have fun )


http://ideone.com/
Замечательный сайт интернет-компиляторов. Собственно, выбираем язык программирования, пишем код, получаем результат. Очень удобно, когда надо проверить какую-нибудь фишку языка (например, при его изучении) и лень устанавливать и настраивать какие-либо IDE.
Языков сайт поддерживает очень много. От с++ до вайтспейса.

четверг, 27 октября 2011 г.

BOINC: work generator

Во время своей работы сервер BOINC должен постоянно генерировать какие-либо задания, которые потом будут отправляться на обработку клиентам. Для этих целей используется специальный демон-генератор. Чаще всего он называется work_generator.

Пример генератора можно найти по адресу ~/server_stable/sched/sample_work_generatr.cpp.
Файл этот можно менять в соответствии с потребностями.

Рассмотрим простой пример сборки и запуска генератора.

0. Если сервер BOINC запущен, следует его остановить ~/projects/test/bin/stop (~/projects/test/ - домашняя директория рабочего проекта)

1. Идем в ~/server_stable/sched/

2. Собираем генератор: make. Могут понадобиться права суперюзера. Есть готовый MakeFile для сборки примеров. Его можно использовать и для сборки переписанного генератора. Файл достаточно большой и запутанный. Можно в нем поковыряться и извлечь только то, что касается генератора. Можно так же переписать под себя (мне например понадобилось добавить флаг -lntl в переменную СXXFLAGS для подключения библиотеки NTL). Повторюсь, и без правки всё будет прекрасно собираться.

3. В результате получим 2 файла: sample_work_generator.o (исполняемый) и sample_work_generator(скрипт). Эти файлы копируем в ~/projects/test/bin/

4. Теперь надо подправить конфигурационный файл проекта: ~/projects/test/config.xml. В самом конце этого файла находится описание запускаемых при старте проекта демонов. Добавляем туда следующее:
<daemon>
   <cmd>
      sample_work_generator -d 3
   </cmd>
</daemon>
Там подобные конструкции уже должны быть. Надо и эту добавить по аналогии. Флаги -d 3 означают, что команда запускает демон с третьим уровнем отладки.

5. Запускаем проект ~/projects/test/bin/start

Теперь во время работы сервера BOINC будут постоянно генерироваться задания. В папку ~/projects/test/download запишутся файлы заданий, который будут потом отправляться клиентам. Также задания будут зарегистрированы  в базе BOINC в таблице workunit.

Теперь рассмотрим пример файла-генератора.

Музыка в формате 8bit

Хочется оставить это здесь. Портал, целиком и полностью посвященных восьмибитной музыке http://malobit.ru/


Изменение размера группы фотографий

Иногда надо изменить размер сразу группы фоток (например перед публикацией в нете).
В окнах с этой задачей справляется навороченный ACDSee, в линуксе - простенький скрипт
#!/bin/bash
mkdir photo1024
for f in *.JPG; do
convert $f -resize 1024 photo1024/${f%%JPG}jpg
done

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

convert умеет еще много чего интересного. курить маны показано.

Интерактивные DVD, ISO, Linux

Качаешь, бывает, образ какого-нибудь DVD в формате iso. И как-то очень уж лень всё это дело куда-то конвертировать. В линуксе можно особо не париться. Перепробовал много плееров. Лучше всех с этой задачей справился xine.

xine dvd://[путь].iso -A alsa


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

История музыки

Решил наглядно представить историю музыкальных стилей, а за одно - поковыряться в HTML5, jquery и прочих приятных вещах.

вот что получилось: brainfuck.zazoid.com/history/

история представлена в виде дерева. наводим на стиль - получаем описание. щелкаем по названию - получаем пример звучания.



среда, 26 октября 2011 г.

Установка сервера BOINC

получилось поднять сервак и запустить тестовый проект. отличный мануал: http://www.boinc-wiki.info/How_to_create_a_BOINC_Project_-_Step_By_Step_instructions

из заковырок:
очень важно выполнить это перед update_version -

./bin/sign_executable apps/upper_case/upper_case_4.00_i686-pc-linux-gnu /path/to/keys/code_sign_priva te >> apps/upper_case/upper_case_4.00_i686-pc-linux-gnu.sig

также надо правильно раздать права для директорий upload, download, html и apps (может еще где задавал, но не помню)

Проверка больших чисел на простоту

итак. скрестил алгоритм миллера-рабина с ntl. ну как скрестил... нашёл) с помощью всего этого дела можно определить, является ли число простым с достаточно высокой вероятностью. метод итерационный. чем больше итераций, тем выше точность. идеально для распределенной обработки.

вот, собственно сам код:
#include <NTL/ZZ.h>

NTL_CLIENT
long witness(const ZZ& n, const ZZ& x)

{
  ZZ m, y, z;

  long j, k;

  if (x == 0) return 0;

  k = 1;

  m = n/2;

  while (m % 2 == 0) {

    k++;

    m /= 2;

  }

  z = PowerMod(x, m, n); // z = x^m % n

  if (z == 1) return 0;

  j = 0;

  do {

    y = z;

    z = (y*y) % n; 

    j++;

  } while (j < k && z != 1);

  return z != 1 || y != n-1;

}

long PrimeTest(const ZZ& n, long t)

{

   if (n <= 1) return 0;
   PrimeSeq s; 

   long p;

   p = s.next();  

   while (p && p < 2000) {

      if ((n % p) == 0) return (n == p);

      p = s.next();  

   }
   ZZ x;

   long i;

   for (i = 0; i < t; i++) {

      x = RandomBnd(n); 



      if (witness(n, x)) 

         return 0;

   }
   return 1;

}
всё просто кроме самого алгоритма) он тоже не сложный, но надо вникать)

Работа со сверхбольшими числами в С++

итак. разбираюсь со сверх большими числами. теми, которые ни в один тип не влазят.
нашел интересную библиотеку под это дело. NTL называется. качать отсюда www.shoup.net/ntl/download.html
пока тестил только под винду, но думаю под линух проблемм возникнуть не должно.
коротко, что надо сделать:
1. само собой распаковываем архив куда-нибудь аля c:\ntl
2. надо руками скомпилить библиотеку под себя. можно использовать vc, можно mingw. я делал в визуалке.
поэтапно
File -> New -> Projects 
project name: ntl
location: c:\ntl_lib
Win32 static library
OK
Finish
OK
Project -> Add to Project -> Files
добавляем всё из c:\ntl\WinNTL-xxx\src.
xxx - номер версии. будут какие-то числа
Project -> Settings -> C/C++ 
Категория: Preprocessor.
Additional include directories: c:\ntl\WinNTL-xxx\include.
Click on OK.
Build -> build ntl.lib
3. если вдруг компилироваться не будет, выдавая огромное количество ошибок, надо покопаться в cinfig.h. мне помогла замера

#if 1
#define NTL_STD_CXX

на

#if 0
#define NTL_STD_CXX

(поставили 0 - вырубили опцию)

Вот и всё. у нас есть либа. теперь подключаем ее к проекту и можем работать со сколь угодно большими числами...
пример:

#include <NTL/ZZ.h>
NTL_CLIENT
int main()
{ 
ZZ a, b, c; 
cin >> a; 
cin >> b; 
c = (a+1)*(b+1);
cout << c << "\n";
}
и на сколько бы большие целые мы не ввели в a и b, всё будет считаться.
вот еще примеры: www.shoup.net/ntl/doc/tour-examples.html

это круто.