Я безумен

2010-08-1

Samba и симлинки

Filed under: Linux — thekillerfox @ 2:00 пп

Проблема и решение

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

Необходимо добавить в [global] секцию файла smb.conf (для убунты он лежит в /etc/samba/smb.conf) три строки:

  follow symlinks = yes
  wide links = yes
  unix extensions = no

После этого перезапускаем samba /etc/init.d/samba restart и вуаля симлинки теперь отображаются и доступны.

Источник

Обсуждение на форуме Ubuntu

Реклама

2010-07-25

Плагин для Smarty для склонения существительных с числительными

Filed under: PHP — thekillerfox @ 6:27 пп

Тему склонения я уже как то поднимал в Новости на сайте посредством twitter’a, теперь же всплыла задача когда необходимо было реализовать данное склонение в качестве плагина для Smarty. И обертка готова, кому нужно может пользоваться.

Нужно сохранить код приведенный ниже в файл function.decliner.php в каталоге с плагинами Smarty

<?php
/**
 * Smarty {decliner} function plugin
 *
 * Type:     function<br>
 * Name:     decliner<br>
 * Purpose:  handle word declines based on quantity number<br>
 * @author   Dmitriy Soloduhin <darkomen86 at gmail dot com>(credits to http://mcaizer.habrahabr.ru/blog/11555/)
 * @param array $params
 * <pre>
 * Params:  qty: number of items to choose correct declining form
 *          word: declining forms of word. Ex: день, дня, дней.
 * </pre>
 * @param Smarty
 * @return string
 */
function smarty_function_decliner($params, &$smarty)
{
    // be sure equation parameter is present
    if (empty($params['qty']))
	$params['qty']=0;
    if (empty ($params['word'])) {
        $smarty->trigger_error("decliner: missing required parameter");
        return;
    }
    $forms=explode(',',$params['word']);
    $params['qty'] = abs($params['qty']) % 100;
    $n1 = $params['qty'] % 10;
    if ( $params['qty'] > 10 &&  $params['qty'] < 20) return $forms[2];
    else if ($n1 > 1 && $n1 < 5) return $forms[1];
    else if ($n1 == 1) return $forms[0];
    return $forms[2];

}

/* vim: set expandtab: */

?>

Затем в шаблонах можно использовать вот так.

{decliner qty=4 word='письма, письма, писем'}

2010-03-1

Сохранение файлов с другим именем в 1C-Bitrix

Filed under: PHP — thekillerfox @ 8:10 пп
Tags: , ,

Введение

Недавно мне пришлось опять связаться с так не любимой мной CMS’кой 1С-Bitrix. При этом встала своеобразная задача, было множество файлов которые необходимо было отдавать с именами отличными от исходных. Было решено использовать описание файла как имя. Для этого был написан небольшой скриптик который принимает в качестве аргумента идентификатор файла.

Здесь я попробую рассмотреть те особенности с которыми пришлось столкнуться. Для начала рассмотрим что основной кодировкой ресурса является cp1251. И большинство описаний составлено на русском языке.

Реализация

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

Copy Source | Copy HTML

  1. if (!isset($_REQUEST['file_id']) || !((int)$_REQUEST['file_id']) )
  2.     die();
  3. $file_id=(int)$_REQUEST['file_id'];

Затем определим функцию для определения по юзер-агенту браузера(взял из комментов на сайте php). Эта функция нам понадобится посколько у IE как всегда все не как у людей, и надо будет под него подстраиваться, as usually.

Copy Source | Copy HTML

  1. function browser_info($agent=null) {
  2.   // Declare known browsers to look for
  3.   $known = array('msie', 'firefox', 'safari', 'webkit', 'opera', 'netscape',
  4.     'konqueror', 'gecko');
  5.  
  6.   // Clean up agent and build regex that matches phrases for known browsers
  7.   // (e.g. "Firefox/2.0" or "MSIE 6.0" (This only matches the major and minor
  8.   // version numbers.  E.g. "2.0.0.6" is parsed as simply "2.0"
  9.   $agent = strtolower($agent ? $agent : $_SERVER['HTTP_USER_AGENT']);
  10.   $pattern = '#(?<browser>' . join('|', $known) .
  11.     ')[/ ]+(?<version>[0-9]+(?:\.[0-9]+)?)#';
  12.  
  13.   // Find all phrases (or return empty array if none found)
  14.   if (!preg_match_all($pattern, $agent, $matches)) return array();
  15.  
  16.   // Since some UAs have more than one phrase (e.g Firefox has a Gecko phrase,
  17.   // Opera 7,8 have a MSIE phrase), use the last one found (the right-most one
  18.   // in the UA).  That's usually the most correct.
  19.   $i = count($matches['browser'])-1;
  20.   return array($matches['browser'][$i] => $matches['version'][$i]);
  21. }

Теперь о логике работы, для того чтобы браузер решил что у файла что мы передаем совсем другое имя вы должны ему передать заголовок Content-Disposition: attachment; FILENAME="имя файла";size="размер файла в байтах"
Ну и до кучи некоторые другие стандартные заголовки типа Content-Type и Content-Length. Имя файла мы сформируем из описания, его, а также размер файла и путь к нему необходимо будет получить, так что мы подключаем битриксовые библиотеки:

Copy Source | Copy HTML

  1. require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

И получаем путь к файлу, и массив с информацией о файле:

Copy Source | Copy HTML

  1. $arr = CFile::MakeFileArray($file_id);
  2. $path = CFile::GetPath($file_id);

Теперь получим расширение файла так как оно нам понадобится при формировании имени.

Copy Source | Copy HTML

  1. $ext = explode('.', $path);
  2. if (count($ext)>1)
  3.    $ext = $ext[count($ext)-1];
  4. else
  5.    $ext='';

Теперь займемся формированием имени файла.

Copy Source | Copy HTML

  1. $description=$arr['description'];
  2. //укорачиваем название если оно слишком длинное()
  3. if (mb_strlen($description)>150)
  4.     $description=mb_substr($description, 0,150).'...';

Описание файла необходимо очистить от символов которые не могут использоваться в именах файлов.
У FAT32,UFS,HFS+ ограничений особых нет, у ext2-3-4 нельзя использовать в названии файла символ ‘/’, но больше всего ограничений накладывается при использовании файловой системы NTFS, где запрещено использовать символов ‘ » / \ * ? | : ‘, что сильно огорчает 😦 Так что будем рассматривать худший случай, и поэтому преобразуем все встречные символы из этого списка в пробелы. Также в имени не может использоваться NUL, во всех из вышеперечисленных файловых систем.

Copy Source | Copy HTML

  1. $pattern = array('"', '/', '\\', '*','?','<','>','|',':');
  2.     for ($i= 0; $i<sizeof($pattern); $i++) {
  3.         $description = mb_ereg_replace($pattern[$i], ' ', $description);
  4.     }

Как выяснилось с кодировками в которых надо отдавать названия тоже проблема. Так Firefox,Opera,Chrome,Safari понимают если им передать название в кодировке UTF-8, в то время как IE просто жаждет cp-1251.
При этом необходимо не забывать что в случае если описание отсутствует стоит воспользоваться исходным именем файла.

Copy Source | Copy HTML

  1. $ua=browser_info();
  2. if ($description)
  3. {
  4.     $fname=mb_convert_encoding($description,"UTF-8", "Windows-1251" ).'.'.$ext;
  5.         if (isset($ua['msie']))
  6.         $fname=$description.'.'.$ext;
  7. }
  8. else $fname=basename($arr['tmp_name']);

Теперь отдаем необходимые заголовки и содержимое файла

Copy Source | Copy HTML

  1. header('Content-Type: '.$arr['type']);
  2. header('Content-Length: '.$arr['size']);
  3. header('Content-Disposition: attachment; FILENAME="'.$fname.'"; size="'.$arr['size'].'"');
  4. echo file_get_contents($arr['tmp_name']);

Еще в ходе экспериментов всплыло то что добавление require($_SERVER[«DOCUMENT_ROOT»].»/bitrix/modules/main/include/prolog_after.php»); является чреватым, и инклудить этот файл в конце скрипта не стоит.

Листинг

Полный листинг приведен снизу.

Copy Source | Copy HTML

  1. <?
  2. if (!isset($_REQUEST['file_id']) || !((int)$_REQUEST['file_id']) )
  3.     die();
  4. function browser_info($agent=null) {
  5.   // Declare known browsers to look for
  6.   $known = array('msie', 'firefox', 'safari', 'webkit', 'opera', 'netscape',
  7.     'konqueror', 'gecko');
  8.  
  9.   // Clean up agent and build regex that matches phrases for known browsers
  10.   // (e.g. "Firefox/2.0" or "MSIE 6.0" (This only matches the major and minor
  11.   // version numbers.  E.g. "2.0.0.6" is parsed as simply "2.0"
  12.   $agent = strtolower($agent ? $agent : $_SERVER['HTTP_USER_AGENT']);
  13.   $pattern = '#(?<browser>' . join('|', $known) .
  14.     ')[/ ]+(?<version>[0-9]+(?:\.[0-9]+)?)#';
  15.  
  16.   // Find all phrases (or return empty array if none found)
  17.   if (!preg_match_all($pattern, $agent, $matches)) return array();
  18.  
  19.   // Since some UAs have more than one phrase (e.g Firefox has a Gecko phrase,
  20.   // Opera 7,8 have a MSIE phrase), use the last one found (the right-most one
  21.   // in the UA).  That's usually the most correct.
  22.   $i = count($matches['browser'])-1;
  23.   return array($matches['browser'][$i] => $matches['version'][$i]);
  24. }
  25. $file_id=(int)$_REQUEST['file_id'];
  26. require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
  27. $arr = CFile::MakeFileArray($file_id);
  28.  
  29. $path = CFile::GetPath($file_id);
  30. $ext = explode('.', $path);
  31. $ext = $ext[count($ext)-1];
  32.  
  33. $description=$arr['description'];
  34.  
  35. if (mb_strlen($description)>200)
  36.     $description=mb_substr($description, 0,200).'...';
  37. $pattern = array('"', '/', '\\', '*','?','<','>','|',':');
  38. for ($i= 0; $i<sizeof($pattern); $i++) {
  39.      $description = mb_ereg_replace($pattern[$i], ' ', $description);
  40. }
  41. $ua=browser_info();
  42. if ($description)
  43. {
  44.     $fname=mb_convert_encoding($description,"UTF-8", "Windows-1251" ).'.'.$ext;
  45.         if (isset($ua['msie']))
  46.         $fname=$description.'.'.$ext;
  47. }
  48. else $fname=basename($arr['tmp_name']);
  49.  
  50.     header('Content-Type: '.$arr['type']);
  51.     header('Content-Length: '.$arr['size']);
  52.  
  53.     header('Content-Disposition: attachment; FILENAME="'.$fname.'"; size="'.$arr['size'].'"');
  54.     echo file_get_contents($arr['tmp_name']);
  55. ?>

Ссылки по теме

Тесты на поддержку Content-Disposition в разных браузерах
Проблемы которые всплывают в различных версиях IE
Сравнение_файловых_систем — смотрим на ограничения 🙂
Еще одно сравнение касательно IE
Ну и конечно же RFC 1806 🙂

2009-07-29

Небольшая доработка jTip

Filed under: Разработка,JS — thekillerfox @ 11:11 дп
Tags: , ,

Была поставлена задача сделать tooltip на сайте. Причем нужен он был только в одном месте, правда зная подход сегодня не нужно завтра нужно ,решил не заморачиваться, да и в верстке я не особо крут, поэтому решил воспользоваться плагином для jquery — jTip. Выглядит все симпатично, работает без нареканий, а так как на сайте уже использовался jQuery, то вообще все хорошо, вот только подгружает он страницы только извне. А меня бы вполне устроил функционал показать содержимое какого то скрытого блока как tooltip’a. И решил допилить.
Открываем jtip.js и находим там function JT_show(url,linkId,title)
Переходим к последней строчке $(‘#JT_copy’).load(url);
И заменяем ее на такую конструкцию

if (params['element_id']!==undefined)
$('#JT_copy').html($('#'+params['element_id']).html());
else
$('#JT_copy').load(url);

Вуаля, теперь чтобы загрузить не содержимое страницы, а содержимое блока, надо всего лишь передать id блока как параметр element_id в любом урле. Я делал вот так

Warning

Авось кому нибудь это поможет.

2009-07-15

Мотиваторы

Filed under: Разное — thekillerfox @ 9:28 пп
Tags: ,

На работе сделали и повесили пару мотиваторов.
Один с «Ты коммитил перед уходом ?» повесили на дверь.

и
мотиватор «Все ошибки в коде и странности в работе функций — чаще всего из-за своих КРИВЫХ РУК», который пришел в голову после убиения кучи времени и переписывания регекспов, когда выяснилось что они работали, но я не так проверял их работу.

2009-07-9

Синтез русской речи в Linux

Filed under: Linux — thekillerfox @ 10:48 дп

Кросспост моей статьи с хабра
Прочитал статью про SAPI и Powershell (Учим PowerShell разговаривать), и мне стало интересно как же с синтезом русскоязычной речи в родной для меня операционке, Linux’e. Как выяснилось все далеко не так радужно, да и качество синтеза далеко до голоса Алены, но все же.

Для синтеза речи в linux’e по традиции используется Festival последняя стабильная версия 1.95, но в поставке нет русского голоса, немного порыскав я набрел на проект по синтезу русской речи посредством Festival, где написано что для работы с русским языком понадобится как минимум версия 1.96 бета. Ну ничего в Ubuntu 9.04 как раз такая и стоит. Дальше есть два варианта, либо собрать пакет самостоятельно, либо для пользователей Debian’a или Ubuntu поставить отдельный пакет, весит данное чудо ~190 метров, не хило так я бы сказал. Так как у меня Ubuntu решил поставить пакет.
Пакет называется Festvox-ru, и будет доступен в ubuntu начиная с версии 9.10, так как на руках 9.04, то скачиваем пакет и устанавливаем его в ручную. И тут вскрылась маленькая проблема.
При попытке попросить festival произнести что то по русски он просто молчал, если же указывался язык
echo "Проверка" | festival --tts --language russian, то вываливался c ошибкой:
«Unsupported language, using English»
SIOD ERROR: unbound variable: voice_rab_diphone
festival: fatal error exiting.

Дамс, попробуем сделать так как в мануале, запускаем festival в интерактивном режиме, указываем голос принудительно (voice_msu_ru_nsh_clunits) и просим сказать что нибудь (SayText “Проверка”), вуаля все нормально работает, оформляем это в виде bash script’a и получаем

#!/bin/sh
festival -b "(begin (voice_msu_ru_nsh_clunits) (SayText \"$1\" nil))"

Теперь сохраняем это в файл sayit.sh, назначаем права на запуск chmod a+x sayit.sh и проверяем
./sayit.sh «Проверка»
Ура! все работает.
Если хотим прочить файл используем:

#!/bin/sh
festival -b "(begin (voice_msu_ru_nsh_clunits) (tts_file \"$1\" nil))"

Но все же почему же у нас не заработал русский язык по умолчанию, копаем дальше.
Немного гугления и мы находим багрепорт к debian’овцам от Сергея Кирпичева, вот этот багрепорт. Похоже нам нужно подправить файл languages.scm/
Так что идем в каталог /usr/share/festival где находим этот файл и вносим изменения.
Дописываем вначале:

(define (language_russian)
"(language_russian)
Set up language parameters for Russian."
(set! male1 voice_msu_ru_nsh_clunits)
(male1)
(Parameter.set 'Language 'russian)
)

и в define(select_language language). добавляем пару строчек

((equal? language 'russian)
(language_russian))

Все теперь русский язык поддерживается.
Пробуем прочитать файл.
festival —language russian -tts festival.txt
Ну что же все даже не так уж и плохо, единтвенное «но» это то что Festival достаточно заметно думает перед тем как начать произносить, и иногда ему не нравиться текст, например вместо того чтобы пропускать то что он не может произнести он вываливается с сообщением о
LTS_Ruleset russian_downcase: no rule matches:
LTS_Ruleset: # *here* <a #
Ну что же значит надо поубивать из текст ссылки.
Пока что результат меня не особо радует, в принципе синтез русской речи под Linux с одной стороны возможен, с другой качество этого синтеза оставляет желать лучшего. А у меня появилось два новых шелл скрипта. sayit.sh и readit.sh ^_^
Примеры озвучивания можно посмотреть в статье Учим iPod Shuffle G3 говорить по-русски

Используемые источники:

Искусство программирования на языке сценариев командной оболочки
Русский в Festival
Новая база для синтеза речи, и голос для festival
Debian Bug report logs — #516262 festival: Please add support for —language russian
P.S. по совету rengel_system лучше вместо установки пакета ручками подключить этот репозиторий
P.P.S по совету eugenex15 решил попробовать espeak. устанавливается очень просто, русский язык сразу из коробки, для сохранения образца голоса можно всего лишь добавить один параметр, но вот качество мне показалось просто ужасным. Наверно можно под строить произношение чтобы получить более менее цивильный результат, но у меня не получилось.
P.P.P.S выложил два примера синтезируемой фразы при дефолтных параметрах в espeak и в festival
espeak
festival
(если кто может предложить другое место куда будет удобней положить wav’ки с удовольствием воспользуюсь)
UPD: Ответ от хабраюзера vk2 голос Алены

Новости на сайте посредством twitter’a

Filed under: Идеи,Разработка,JS — thekillerfox @ 8:55 дп
Tags: ,

Twitter становится достаточно популярным, но немного не понятно для чего его стоит использовать большинству людей. Сообщать знакомым различные новости это интересно, но возможно можно придумать что то еще.
Предположим у нас есть сайт. На котором что то постоянно происходит (пользователи добавляют новые ссылки, какие то небольшие изменения функционала), как на таком сайте должны выглядеть новости на главной странице или в боковом блоке? Небольшое описание новости, и если нужно ссылка на более подробный текст. Будет неплохо если про эти новости смогут прочитать в twitter аккаунте вашего сайта, или подпишутся на rss ленту. Так зачем же делать все это у себя, пусть twitter возьмет на себя хранение всех новостей на вашем сайте. Соответственно они будут в твиттере, и rss к ним будет предоставлен. Как мне кажется это удобно. Да и добавлять новость на сайт можно будет почти мгновенно, и при этом даже если сайт ляжет, сообщение об этом можно будет быстро послать в твиттер. Минус данного подхода в ограничение в 140 символов, которое налагает твиттер. Но зато новостям придется быть краткими и ясными. А для более подробного разъяснения можно поместить ссылку.
Теперь рассмотрим несколько вариантов каким образом на главную страницу вашего сайта можно будет привнести твиттер.
Тут можно различать два подхода:
1) При формирование главной страницы скрипт получит список сообщений и выведет их.
2) При открытии страницы пользователь ява скрипт подгрузит новости сам, и покажет их пользователю.
Рассмотрим для начала первый вариант, он удобен тем что пользователь получает уже сформированную страницу, со всеми новостями, минус это то что мы должны устанавливать соединение и постоянно получать новости, что замедляет генерацию страниц, да и траффик дополнительные получается. Если мы реализуем серверную часть на php, то чтобы не разбираться самим с парсингом вывода twitter’a (а там очень много различных вариант на выбор, вот как надо реализовывать API) мы идем на phpclasses.
Больше всего мне понравился My Twitter класс, даже не потребовалось допиливание. К тому же устанавливать статус все равно понадобится, например если какой либо пользователь добавил статью. Но что делать если у нас нет backend’a (мифический случай), или же задержка генерации страницы нас не устраивает. Тут мы переходим к способу номер 2.

Этот способ хорош тем что всю работу получения новостей берет на себя браузер пользователя, к тому же если задать интервал обновления то можно сделать так что новые новости пользователь увидет даже если не будет обновлять страницу. Минус в том что если у пользователя выключен js он не увидет новостей. Да и их загрузка через некоторое время после открытия главной страницы тоже может не понравится пользователю, но ведь этот способ можно использовать и для другого, например если у нас есть пользователь с указанным в профиле твиттер аккаунтом, мы можем подгрузить в профиль последние обновления twitter’а этого пользователя.
Так как в последнее время я немного шаманю с jquery то первым делом я полез искать плагин работы с twitter’ом для него. Как никак у twitter’a есть json api и соответственно ничто не мешает реализовать твиттер клиент на js. Так как все придуманно до нас, то решение быстро нашлось, это jquery.twitter,причем новая версия вышла вчера. Как удачно. Скачиваем и смотрим что внутри. Рисунок загрузчика, css’ка, jquery, плагин к нему и страничка с демо.
Для формирования вывода используется Twitter HTML Badge Customizer, для этого в коде подключается внешний js файл.

$.getScript("http://twitter.com/javascripts/blogger.js");

там определенны две функции twitterCallback2 которая собственно и формирует HTML код, и relative_time для формирования относительного времени (это запись в виде 5 days ago), я подумал что относительно время это хорошо, но надо пожалуй как то это дело руссифицировать. Встала проблема, так как в русском языке существительные принято склонять. И тут вспомнилась одна статья на хабре: Склонение существительных с числительными , косметические изменения и у нас есть такая же функция, но только переписанная на JavaScript.

function plural(n, form1, form2, form5)
{
	n = Math.abs(n) % 100;
                n1 = n % 10;
                if (n > 10 && n < 20) return form5;
                else if (n1 > 1 && n1 < 5) return form2;
                else if (n1 == 1) return form1;

        return form5;
}

Теперь правим функцию relative_time и вуаля у нас теперь все как надо.

function relative_time(time_value) {
  var values = time_value.split(" ");
  time_value = values[1] + " " + values[2] + ", " + values[5] + " " + values[3];
  var parsed_date = Date.parse(time_value);
  var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
  var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
  delta = delta + (relative_to.getTimezoneOffset() * 60);

  if (delta < 60) {
    return 'меньше минуты назад';
  } else if(delta < 120) {
    return 'около минуты назад';
  } else if(delta < (60*60)) {
    return (parseInt(delta / 60)).toString() + '  ' + plural((parseInt(delta / 60)).toString(),'минута','минуты','минут')+ ' назад';
  } else if(delta < (120*60)) {
    return 'около часа назад';
  } else if(delta < (24*60*60)) {
    return 'около ' + (parseInt(delta / 3600)).toString() + '  ' + plural((parseInt(delta / 3600)).toString(),'час','часа','часов')+ ' назад';
  } else if(delta < (48*60*60)) {
    return '1 день назад';
  } else {
    return (parseInt(delta / 86400)).toString() + ' ' + plural((parseInt(delta / 86400)).toString(),'день','дня','дней') +'  назад';
  }
}

Теперь у нас на повестке дня ссылка на rss. Что же идем на FeedIcons и скачиваем подходящие нам иконки. И делаем небольшую поправку в самом плагине.

if (o.showProfileLink) {
	var profileLinkHTML = "<p class=\"profileLink\"><a href=\"http://twitter.com/"+o.userName+"\">http://twitter.com/"+o.userName+"</a>&nbsp;<a href='http://twitter.com/statuses/user_timeline/"+o.userName+".rss'><img src='feed-icon.png'/></a></p>";
	c.append(profileLinkHTML);
}

Кстати чтобы не подгружать каждый раз blogger.js, да ведь мы и не можем ему менять, я просто закомментировал строку с его загрузкой, а исправленные функции, записал в конец jquery.twitter.js плагина.
Ниже можно скачать то что у меня получилось.
Скачать поправленный для себя jquery.twitter

Пользователям может не понравится такой способ предоставления новостей, но мне кажется есть ресурсы где это может пригодиться, к тому же так можно оживить даже статичный сайт. Мы же живем в эпоху mash-up’a, так почему бы и нет.
UPD: еще можно использовать Juitter , тоже очень интересный плагин, автоматическое обновление в случае появления новых твиттов, реплаи, показ аватаров, поиск. Но мне почему то jquery.twitter нравится больше, он менее нагружен как мне кажется.

2009-05-9

Структуризация информации. Контрольная точка 1

Filed under: Идеи — thekillerfox @ 9:35 пп

Как я писал мне хотелось бы чтобы вся информация на винте была структурированна, но как это сделать? У меня есть несколько задумок и я потихоньку реализую их. В плане СУБД планирую использовать MySQL, конечно по прикидкам база получается просто огого, мама не горюй, но вроде мускул должен вытянуть, пока не полностью ясно со структурой базы, то есть есть структура, и ее даже можно юзать, но вот что то там не так. Не знаю даже, слишком много кода надо чтобы с ней работать, библиотеки конечно писал начал, но не хочется в конце выяснить что фигня получилась. Пока что для импорта информации парсеры делаю, парсер для кинопоиска чтобы фильмы добавлять готов, парсер fb2 тоже.
Есть простенькая библиотека для работы с базой, простой веб интерфейс и небольшая адресная книга накиданная с использованием его. Так что идем в верном направлении.

2009-04-26

Организация данных на локальной машине. Мечты.

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

У Сэмми Джэнкиса была такая же проблема, но у него не было настоящей системы.
Фильм «Помни»(Memento)

Объем жестких дисков растет, и вам требуется способ организовать большое количество данных. Если не следовать какому либо принципу, системе, то у вас будет всего лишь большущая свалка. И что с ней делать. И однажды наступит момент что вам будет проще найти то что вы ищете в интернете или у друзей чем у себя на винтах или на дисках. И вот тут приходится придумать способ организовывать данные. Если вы не собираетесь использовать никакого специализированного ПО, то возможно стоит постоить систему каталогов, верную для вас и с вашей точки зрения. Например я каталогизирую софт очень просто, у меня в корне лежат папки:

_distrs — здесь лежат различные дистибьютивы windows, linux, reactos и других операционок
_linux — здесь софт под linux
_macos — здесь под маки
_pocket pc — Windows Mobile — прошивки под разные устройства, софт и игры.
_windows — тут под винду
_other — а тут под то что не подпадает в категории выше

Пока были только папки _windows и _linux все было просто. в них шли софт и игры для каждой из осей. Потом дистры решено было вынести и теперь структура усложнилась. Софт разбит по категориям(уровень вложенности бывает очень велик например _net/_messaging/_irc/_client/mIRC)
В папке с программой лежат подпапки версий, скриншоты и описания. Я стараюсь для всех программ поддерживаться этой системы. То что программы могут быть в нескольких категориях одновременно решается посредством симлинков. Но вот _pocket pc каталог это уже небольшой отделение от правил. Ибо прошивки, софт и игры там лежат в одной системе категория, хотя для винды и линукса это все вынесенно отдельно. (Игры лежат на отдельном разделе отсортированные тоже по осям.)

Такая система была достаточно удобно на ранних порах. Но чем сложнее становяться запросы, и чем больше становиться программ, тем менее удобной становится такая система. Получается что надо выдумывать какую то более гибкую структуру. Симлинки конечно помогут, но как быть с удаленнием данных. Надо же будет после этого обновлять все симлинки. Либо писать скрипт который будет оббегать каталоги в поисках симлинков и грохать их.
Еще один подход для хранения использовать папку с кучей файлов, отсортированных как угодно, но для обращения и операциями с ними использовать специальные программы каталогизаторы. Например для фильмов это Personal Video Database. А что вроде бы все удобно. Но вот что вам делать если вам нужно использовать эту программу например под Linux’ом. У меня под вайном она идет как то не стабильно. Да и повлиять на ее развитие никак не получится. Но это уже шаг к лучшей системе.

Вам нужна действительно хорошая система,если Вы хотите заставить её работать.
Фильм «Помни»(Memento)

Перейдем к хранению музыки. Например для этого будем использовать плейер с поддержкой медиа библиотек. Amarok, Windows Media Player, Banshee,Songbird, iTunes и т.д. ибо имя им легион, их очень много, но при этом я не могу привязать какую то песню к какому то фильму из коллекции, я не могу посмотрев фильм нажатием кнопки перенести его содержимое в плейер. Да я понимаю что я хочу невозможного. Я хочу систему где все данные будут взаимосвязанны, где не будет понятия файл, а будет понятие фильм, песня, программа. Где все будет связанно между собой. Я хочу иметь возможность создавать сложные выборки на манер того чтобы получить список всех программ у меня на винте под определенной лицензии и в определенной категории, а затем записать их на диск.

Единственный способ на лету менять условия поиска, это если данные будут занесенны в какую либо систему, где они будут связанны между собой, где будут описаны все их свойства. Похожий подход исповедует проект Nepomuk(Под сенью KDE хранилищу дали более красивое имя Soprano). Интересное решение, к тому же для хранения используется RDF. Но чем то оно мне не нравится(Может потому что на текущий момент это концепт который непонятно как использовать).

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

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

На хабре проскакивала статья про Gimao. Интересная программа, я думал что возможно будет использовать ее. Но бета есть бета, к тому же если ей удобно организовывать большие объемы информации формировать запросы типо тех что мне хотелось пока сложно если не сказать невозможно. Правда она и не позицинионируется как хранилище данных. Это PIM.

Кстати PIM это вообще отдельный разговор. Как я представляю себе идеальную адресную книгу. В ней есть что то от социальных сетей(куча заполненных данных, связи между записями), она синхронизирует свои данные с интернетом (с аккаунтами в различных социальных сетях), она хранит в себе логи разговоров, время и даты звонков. А еще мне бы хотелось чтобы она интегрировалась с общей системой хранения данных. Я хочу открыв адресную книгу и увидя там знакомого Васю, посмотреть фотки с его последнего отпуска, узнать что у него есть друг Витя, которому нравиться фильм Генетическая опера, увидеть что этот фильм есть у меня, посмотреть трейлер, почитать отзывы, после чего узнав что там неплохая музыка, открыть OST к фильму если он есть у меня на машине и скинуть его на плейер чтобы послушать в дороге. Мне нужно чтобы он автоматом искал его и скачивал, но я хочу чтобы любая информация которая у меня есть лежала по полочкам.

2009-02-2

.Net CF программное управление bluetooth

Filed under: .NET,Разработка,Windows Mobile — thekillerfox @ 1:56 пп
Tags: , , , ,

Для начала нам нужно подключить пространство имен System.Runtime.InteropServices

using System.Runtime.InteropServices;

Теперь создаем свой класс :

public class Network
{
     public enum BluetoothMode
     {
          Off=0,
          Connectable=1,
          Discoverable=2
     }
     [DllImport("BthUtil.dll")]
     private static extern int BthGetMode(out BluetoothMode dwMode);
     [DllImport("BthUtil.dll")]
     public static extern int BthSetMode(BluetoothMode dwMode);
     public static String GetBthMode()
     {
          BluetoothMode mode;
          int ret = BthGetMode(out mode);
          return mode.ToString();
     }
}

Теперь мы можем попробовать переключить статусы. Например вот так :

if (Network.GetBthMode() == "Off")  //Проверяем текущее состояние
    Network.BthSetMode(Network.BluetoothMode.Connectable); //Переводим в состояние Connectable
else Network.BthSetMode(Network.BluetoothMode.Off); // или же выключаем
Следующая страница →

Создайте бесплатный сайт или блог на WordPress.com.