Posts

Showing posts from October, 2009

Полнотекстовый поиск: первое приближение

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

SQLite и ICU

В течении достаточно продолжительного времени я использовал легковесную реализацию базового юникода для SQLite взамен апстримовской ICU-зависимой. Но некоторое время назад перешел на ICU, поскольку на современном оборудовании, к примеру, core quad, овчинка не стоит выделки. Кроме того, в дебиане наконец-то положительно решили вопрос, по которому я давно пинал мантейнера пакета sqlite: sqlite3: Case-insensitive matching of Unicode characters does not work because ICU extension not compiled. Теперь в debian стало возможным разрабатывать интернациональные проекты с использованием SQLite. Возможно, еще стоит потрясти мантейнера на предмет добавления пакета с анализатором, который давно есть в моей сборке. Насчет патчей расширения функциональности надеяться не приходится - тут мантейнер сразу "посылает" в апстрим, а вот патч - решение проблемы с биндингом переменных в tcl-интерфейсе было бы полезным добавить. Что интересно, апстрим рекомендует всем заинтересованным пользователям и

Работа с GeoIP с помощью SQLite

Воспользуемся известной базой ip-адресов от MaxMind. Описание формата и технологии преобразования ip адреса к целому числу и обратно смотреть по ссылке. There is popular geoip database provided by the MaxMind company. http://www.maxmind.com/app/csv Кроме того, можно найти уже готовую базу в формате SQLite здесь http://alt.textdrive.com/nanoki/ На момент написания статьи актуальная база доступна по ссылке ниже. The MaxMind dataset in SQLite database format is available by link below. http://alt.textdrive.com/assets/public/Nanoki/IPLocation.20090201.tar.bz2 Воспользовавшись функцией ip2int() из моего расширения INET , легко получить простой запрос определения местоположения по ip-адресу. The geolocation query can be writed easy by using the ip2int() function from my extension INET select location.start as start, location.end as end, city.name as city, region.name as region, region.code as region_code,

Конфигурация tclsh шелла .tclshrc

За конфиг спасибо Данилову Александру, который когда-то поделился им со мной. Если я правильно ошибаюсь, то исходник был найден в вики и допилен по месту. Поддерживается история команд и вызов внешних утилит. При желании можно автоматически загружать нужные пакеты расширений и проч. .tclshrc if {$tcl_interactive == 1} { # set pglib_path "/usr/lib/libpgtcl1.5/libpgtcl1.5.so" # load $pglib_path # set sqlitelib_path "/usr/lib/sqlite3/libtclsqlite3.so.0" # load $sqlitelib_path lappend auto_path /usr/local/lib puts "auto_path: $auto_path" interp alias {} printenv {} parray env if {$tcl_platform(platform) eq "unix"} { proc help {command} { exec xterm -e man -S 3tcl:3tk $command & return } } proc lspackages {{pattern *}} { # Force the package loader to do its thing: # NOTE: this depends on a side effect of the # built-in [package unknown]. Other [package

Пакет webcam

Описание можно найти и в документации, а вот свой конфиг я как-то безуспешно пытался найти. Пока снова не потерял, выкладываю. .webcamrc [grab] # http://www.astro.ku.dk/~norup/webcam/readme.txt device = /dev/video0 text = webcam %Y-%m-%d %H:%M:%S fg_red = 255 fg_green = 255 fg_blue = 255 width = 640 height = 480 delay = 1 wait = 0 norm = pal rotate = 0 top = 0 left = 0 bottom = -1 right = -1 quality = 75 trigger = 100 once = 0 archive = /tmp/webcam/%Y-%m-%d/%H:%M:%S.jpg

Преобразование координат

Разбираясь в своих архивах, нашел много всего почти позабытого. В том числе утилитки для преобразования координат из WGS84 в Пулково 1942 и "морских" координат. Разумеется, эти преобразования можно выполнить с помощью универсальных библиотек, но они огромны и не всегда эффективны, не говоря уж про зависимости. Так что любителям минимализма и встраиваемых решений посвящается. #include <stdio.h> #include <math.h> #include <stdlib.h> double pifact = 0.017453292519943295; // PI/180 - перевод градусов в радианы // параметры референц-эллипсоида Красовского double aval = 6378245.0; // полуось эллипсоида double f = 298.3; // величина сжатия // параметры системы координат 42 года (СК Пулково 42) double cmlon = 45; // центральный меридиан 8-й зоны double orglat = 0; // центральная параллель (экватор) double scale = 1; // масштабный коэффициент double fe = 500000; // восточное смещение (без номера зоны) double fn = 0

Преобразование справочника КЛАДР в формат SQLite

Статья перемещена по адресу http://sqlite.mobigroup.ru/wiki?name=sqlite3-kladr

Tcl-обертка rapi.tcl для библиотеки rapi.dll (ActiveSync)

Работает с любой версией ActiveSync, не требует компиляции и настройки. Написана несколько лет назад и с тех пор используется в продакшене. За отсутствием хидеров к библиотеке константы были найдены в дизассемблерном листинге на просторах интернет. Комментарии там тоже были - иероглифами, так что, вероятно, надо сказать "спасибо" неизвестным китайским хакерам. Переделывая знаменитые строки: "и на руинах $софта напишут наши имена". Здесь подразумеваются закрытые программные продукты, если кто не понял :-) Но, поскольку я не хакер, получив моральное удовлетворение от лицезрения вышеописанных руин, я продолжил заниматься своим делом, реализовав предлагаемую вашему вниманию библиотечку. # Copyright 2009, Mobile Business Group # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any

Модуль ns_userkey для AOL Server

Описание модуля приведено в комментарии в коде. # Copyright 2009, Mobile Business Group # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/. package require json # store and/or calculate limits and messages proc ns_userkey_settings {name} { switch -exact -- $name { keylength {return 100} valuelength {return 1024} maxcount {ret

Модуль проверки прав ns_perm для AOL Server

Пример 1. В случае, когда у пользователя нет права stats, следующая строка прервет выполнение скрипта и отправит клиенту сообщение о том, что доступ запрещен (Forbidden). ns_perm stats Пример 2. Если у пользователя есть право stats, будет выведено сообщение Hello!. Выполнение скрипта продолжится. ns_perm stats { ns_html::puts Hello! } Пример 3. Если у пользователя есть право stats, будет выведено сообщение Hello!, а иначе - сообщение Forbidden. Выполнение скрипта продолжится. Собственно, такое "изощренное" применение требуется достаточно редко. if {[ns_perm stats { ns_html::puts Hello! }] == 0} { ns_html::puts Forbidden } А вот и сама реализация: # Copyright 2009, Mobile Business Group # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program

HTTP Cookie Library for AOLserver

Реализация таит в себе одну небольшую хитрость - кукисы, отправленные в текущей HTTP-сессии, также засчитываются как полученные от клиента. Такое усовершенствование позволяет существенно упростить код, в частности, авторизации. # HTTP Cookie Library for AOLserver # Copyright 2009, Mobile Business Group # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/. proc ns_cookiegetall {} {

Кластер AOL Server с единой точкой входа под управлением HAProxy

При построении кластера с единой точкой входа возникает необходимость определенной настройки узлов кластера. Например, редирект должен отправлять пользователя не на хост, заданный в конфиг-файле AOL Server, а на тот хост, который указан в хидерах клиента. Имя точки входа и соответствующие веб-сервера определяются на уровне балансировщика, например, в HAProxy, таким образом, в конфиге AOL Server вовсе не должно быть имени точки входа; кроме того, точек входа может быть более одной. Задача решается с помощью приведенных ниже врапперов для встроенных функций. # Copyright 2009, Mobile Business Group # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warrant

Вывод хидеров запроса в AOL Server

Для отладки и не только бывает полезной возможность вывода хидеров, посылаемых клиентом. Для этого можно воспользоваться предложенной функцией. ns_register_proc GET /showheaders ad_showheaders_proc ns_register_proc POST /showheaders ad_showheaders_proc proc ad_showheaders_proc {ignore} { set result {} set headers [ns_conn headers] for {set i 0} {$i < [ns_set size $headers]} {incr i} { set key [ns_set key $headers $i] set value [ns_set value $headers $i] append result "$key: $value\n" } ns_return 200 text/plain $result } Теперь достаточно обратиться по следующему адресу, например, из браузера: http://mobigroup.ru/showheaders/

Создание файлов формата MS Excel 2003 в Tcl

В основу положена реализация, приведенная в вики wiki.tcl.tk Во-первых, выполнена "доработка напильником", во-вторых, реализован интерфейс в лисп-стиле. # Copyright 2009, Mobile Business Group # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/. #package provide excel 1.0 namespace eval ::excel:: { variable styles variable columnDefault variable rowCounter var

Модуль ns_captionkey для AOL Server

Описание модуля приведено в комментарии в коде. # Copyright 2009, Mobile Business Group # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/. package require json # простой интерфейс для управления заголовками # проверки аргументов убраны, т.к. это лишний оверхед, а функции вызываются очень часто proc ns_captionkey {action args} { if {$action eq {exists}} { return [nsv_exist

Модуль ns_defaultkey для AOL Server

Описание модуля приведено в комментарии в коде. # Copyright 2009, Mobile Business Group # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/. package require json # простой интерфейс для управления значениями по умолчанию # проверки аргументов убраны, т.к. это лишний оверхед, а функции вызываются очень часто # позволяет установить дефолтовые значения сразу для всех пользователей и сесси

Автоматическое подключение collation для русского языка в расширении ICU для SQLite

Для удобства работы с русским текстом в SQLite можно сделать автоматическое подключение нужного collation. Это позволит проводить сортировку и регистронезависимый поиск для русскоязычных текстов. В рассылке sqlite-users периодически пробегает вопрос, как же сделать такое для того или иного языка, а уж в рунете и вовсе этот вопрос "притча во языцех". При этом сразу после открытия базы мы увидим следующее: $ sqlite3 sqlite> pragma collation_list; 0|russian 1|NOCASE 2|RTRIM 3|BINARY Таким образом, получаем встроенную поддержку руссого языка, достаточно лишь для поля таблицы указать "collate russian". Для дебиана можно брать пакеты из моего репозитория . Для виндоус можно взять не сильно свежую версию SQLite с ICU здесь (вот только не обещаю, что коллэйшен russian там автоматически грузится, поскольку сборку делал отнюдь не для русскоговорящих пользователей). Так что лучше взять последнюю версию SQLite с офсайта, пропатчить и скомпилировать с ICU, который я уже собр

Реализация counter() для SQLIte

В заметке Счетчики в SQLite я уже упоминал про функцию counter(), позволяющую генерировать последовательные номера для возвращаемых запросом записей. В апстрим эта функция не включена и поныне, потому полагаю небесполезным привести здесь соответствующий патч. Полагаю описание функции в комментарии к коду исчерпывающим. --- sqlite3-3.6.19.orig/src/func.c +++ sqlite3-3.6.19/src/func.c @@ -1397,6 +1397,35 @@ } /* +** Implementation of the counter(X) function. If X is an integer +** constant, then the first invocation will return X. The second X+1. +** and so forth. Can be used (for example) to provide a sequence number +** in a result set. +*/ +static void counterFunc( + sqlite3_context *pCtx, /* Function context */ + int nArg, /* Number of function arguments */ + sqlite3_value **argv /* Values for all function arguments */ +){ + int i; + int *pCounter; + + pCounter = (int*)sqlite3_get_auxdata(pCtx, 0); + if( pCounter==0 ){ + pCounter = sqlite3_malloc(

Использование таблиц из приаттаченных баз в SQLite view

В одном из релизов была изменена логика работы с приаттаченными базами. Теперь можно создавать только временные виды, которые обращаются к таблицам из других баз. Конечно, так надежнее, но для многих систем анализа нереально копировать огромные таблицы в целевую базу, так что приходится идти на то, чтобы позволять создавать view с использованием приаттаченных баз. Разумеется, база с такими view может быть некорректна, если не приаттачены дополнительные базы. Представленный ниже патч решает вопрос в нашу пользу. --- sqlite3-3.6.19.orig/src/attach.c +++ sqlite3-3.6.19/src/attach.c @@ -447,10 +447,11 @@ if( pItem->zDatabase==0 ){ pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb); }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){ - sqlite3ErrorMsg(pFix->pParse, +/* sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", pFix->zType, pFix->pName, pItem->zDatabase); -

Две цифры номера года в SQLite функции strftime

При импорте данных из внешних источников часто встречается номер года из двух цифр, но встроенной поддержки в функции strftime для этого случая не предусмотрено. Впрочем, несложно и добавить. Патч приведен ниже, а также его можно взять из сырцового деб-пакета моей сборки SQLite. --- sqlite3-3.6.19.orig/src/date.c +++ sqlite3-3.6.19/src/date.c @@ -844,6 +844,7 @@ ** %w day of week 0-6 sunday==0 ** %W week of year 00-53 ** %Y year 0000-9999 +** %y year 00-99 ** %% % */ static void strftimeFunc( @@ -883,6 +884,9 @@ case 'Y': n += 8; break; + case 'y': + n += 4; + break; case 's': case 'J': n += 50; @@ -968,6 +972,10 @@ sqlite3_snprintf(5,&z[j],"%04d",x.Y); j+=sqlite3Strlen30(&z[j]); break; } + case 'y': { + sqlite3_snprintf(3,&z[j],"%02d",x.Y % 100); j+=sqlite3Strlen

Релиз SQLite 3.6.19

Знаменательное событие, но я как-то совсем позабыл о нем рассказать. Анонс здесь: SQLite Release 3.6.19 On 2009 Oct 14 (3.6.19) Как обычно, множество багфиксов и улучшений, но самое главное - добавлена поддержка foreign key constraints . Проблема с биндингом переменных, к сожалению, осталась, так что патч все еще нужен. Пришлось его подправить, поскольку код интерфейса tclsqlite существенно изменился. Заявлена поддержка Non-Recursive Engine (NRE) для TCL 8.6 и выше. --- sqlite3-3.6.19.orig/src/tclsqlite.c +++ sqlite3-3.6.19/src/tclsqlite.c @@ -757,6 +757,8 @@ Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); int n; u8 *data; + Tcl_WideInt v; + double r; const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); char c = zType[0]; if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ @@ -764,18 +766,10 @@ ** has no string representation. */ data = Tcl_GetByteArrayFromO

Менеджер очереди для микроконтроллеров

Возникло желание упростить себе написание программ для микроконтроллеров, в частности atmega8. Прежде чем заняться изобретением собственного велосипеда, я нашел и осмотрел несколько уже представленных в интернет реализаций менеджера очереди. Как обычно, все оказалось довольно печально - авторы усиленно втискивают менеджер очереди в прерывания. "И втискивал, и всовывал, и плотно утрамбовывал." (с). Самые продвинутые даже понимают, какие проблемы они себе этим создают и начинают с ними бороться путем создания мьютексов и прочих костылей. Ну, ладно, пусть их себе борются, мне-то что. Понятно, что в итоге было решено потратить часок времени на свою собственную реализацию, которая не будет отличаться неестественным интеллектом. Рассмотрим свои потребности. Динамическое выделение памяти менеджером очереди совершенно не оправдано, поскольку существующие процедуры известны на момент компиляции. Вполне хватит инициализированного при объявлении массива. Очередность запуска процеду

Телефонный биллинг: тариф "Направление посекундно"

Публикация имеет двоякий смысл - привести пример задачи, которую удобно выполнять именно на Tcl, а также обеспечить легкий доступ к этой информации для всех разработчиков и пользователей. Система MBG Billing позволяет администратору системы определять собственные скрипты тарификации, причем они могут хранить правила тарификации непосредственно в своем коде или вызывать любые функции системы, в том числе для обращения к БД. При старте веб-сервера AOL Web Server загружаются все скрипты тарифов, расположенные в определенной директории. Таким образом, для добавления нового скрипта достаточно положить его в поддиректорию tcl/telephony и перезапустить веб-сервер следующей командой sudo sv restart billing Здесь предполагается, что сервис имеет имя billing и управляется супервизором runit. После этого в веб-интерфейсе можно будет назначать вновь добавленный тариф и устанавливать его параметры. Скрипт биллингования также грузит все скрипты тарифов из вышеназванной директории. При следующем запу

Подготовка sql-запроса для SQLite в tcl

При создании видов биндинг переменных невозможен, потому приходится генерировать sql-строку с уже подставленными значениями переменных. Для того, чтобы это сделать безопасно, SQLite предоставляет функцию quote(). При использовании несуществующих переменных приведенная ниже функция ::dataset::prepare выдаст ошибку, в то время как стандартный механизм биндинга переменных в таком случае подставляет значение NULL. Пример использования: package require sqlite3 sqlite3 db :memory: set i 1 set j a1 array set info {1 a b 2} puts [::dataset::prepare db {create view view_test as select $i union select $j union select $info(1) union select $info(b)} i j info] create view view_test as select 1 union select 'a1' union select 'a' union select 2 Реализация: proc ::dataset::prepare {handler sql args} { foreach arg $args { upvar 0 $arg name if {[uplevel 1 [list array exists $arg]]} { foreach {key val} [uplevel 1 [list array get $arg]] { se

Решение проблемы с типизацией переменных при биндинге в Tclsqlite

Выполняем скрипт с нижеприведенным кодом: $ cat /tmp/test package require sqlite3 sqlite3 db :memory: db eval {create table test(a int);insert into test values (1);} proc test {label sql result} { global i j puts -nonewline $label\t set _result [db eval $sql] if { $_result eq $result} { puts OK } else { puts ERROR\t$result!=$_result } } set i 1 test 1.0 {select typeof($i)} integer ;# it doesn't work in orig sqlite test 1.1 {select * from test where a=$i} 1 test 1.2 {select * from test where 1=$i} 1 ;# it doesn't work in orig sqlite test 1.3 {select a from test where a IN (cast($i AS INT), 160)} 1 test 1.4 {select a from test where 1 IN (cast($i AS INT), 160)} 1 $ tclsh8.5 /tmp/test 1.0 ERROR integer!=text 1.1 OK 1.2 ERROR 1!= 1.3 OK 1.4 OK А теперь тот же самый код запускаем в tclsh8.5 шелле: $ tclsh8.5 % package require sqlite3 sqlite3 db :memory: db eval {create table test(a int);insert into test values (1);} pro