Ярлыки

.htaccess (4) тестирование (8) шаблоны проектирования (3) css (5) Debian (6) docker (2) Doctrine2 (6) Git (6) html (4) java (6) javascript (13) jquery (11) LFS (3) linux (23) mac os (4) mod_rewrite (2) MSSQL (4) MySQL (18) ORM Doctrine (17) patterns (3) PDO (3) perl (7) PHP (64) PHPUnit (8) Python (15) SEO (2) Silex (1) SimpleXML (1) SQL (14) ssh (4) Ubuntu (24) Yii1 (1) Zend Framework (19) ZendFramework2 (8)

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

Ubuntu. Управление скоростью вентилятора процессора.

Определяем наличие сенсоров на мат плате

leon@Berta:~$ sudo sensors-detect
...
# sensors-detect revision 5946 (2011-03-23 11:54:44 +0100)
# System: System manufacturer System Product Name
# Board: ASUSTeK Computer INC. M4A88T-M/USB3

This program will help you determine which kernel modules you need
to load to use lm_sensors most effectively. It is generally safe
and recommended to accept the default answers to all questions,
unless you know what you're doing.

Some south bridges, CPUs or memory controllers contain embedded sensors.
Do you want to scan for them? This is totally safe. (YES/no): 
Module cpuid loaded successfully.
Silicon Integrated Systems SIS5595...                       No
VIA VT82C686 Integrated Sensors...                          No
VIA VT8231 Integrated Sensors...                            No
AMD K8 thermal sensors...                                   No
AMD Family 10h thermal sensors...                           Success!
    (driver `k10temp')
AMD Family 11h thermal sensors...                           No
AMD Family 12h and 14h thermal sensors...                   No
Intel digital thermal sensor...                             No
Intel AMB FB-DIMM thermal sensor...                         No
VIA C7 thermal sensor...                                    No
VIA Nano thermal sensor...                                  No

Some Super I/O chips contain embedded sensors. We have to write to
standard I/O ports to probe them. This is usually safe.
Do you want to scan for Super I/O sensors? (YES/no): 
Probing for Super-I/O at 0x2e/0x2f
Trying family `National Semiconductor'...                   No
Trying family `SMSC'...                                     No
Trying family `VIA/Winbond/Nuvoton/Fintek'...               No
Trying family `ITE'...                                      Yes
Found `ITE IT8712F Super IO Sensors'                        Success!
    (address 0x290, driver `it87')
Probing for Super-I/O at 0x4e/0x4f
Trying family `National Semiconductor'...                   No
Trying family `SMSC'...                                     No
Trying family `VIA/Winbond/Nuvoton/Fintek'...               No
Trying family `ITE'...                                      No

Some systems (mainly servers) implement IPMI, a set of common interfaces
through which system health data may be retrieved, amongst other things.
We first try to get the information from SMBIOS. If we don't find it
there, we have to read from arbitrary I/O ports to probe for such
interfaces. This is normally safe. Do you want to scan for IPMI
interfaces? (YES/no): 
Probing for `IPMI BMC KCS' at 0xca0...                      No
Probing for `IPMI BMC SMIC' at 0xca8...                     No

Some hardware monitoring chips are accessible through the ISA I/O ports.
We have to write to arbitrary I/O ports to probe them. This is usually
safe though. Yes, you do have ISA I/O ports even if you do not have any
ISA slots! Do you want to scan the ISA I/O ports? (yes/NO): 

Lastly, we can probe the I2C/SMBus adapters for connected hardware
monitoring devices. This is the most risky part, and while it works
reasonably well on most systems, it has been reported to cause trouble
on some systems.
Do you want to probe the I2C/SMBus adapters now? (YES/no): 
Using driver `i2c-piix4' for device 0000:00:14.0: ATI Technologies Inc SB600/SB700/SB800 SMBus
Module i2c-dev loaded successfully.

Next adapter: SMBus PIIX4 adapter at 0b00 (i2c-0)
Do you want to scan it? (YES/no/selectively): 
Client found at address 0x50
Probing for `Analog Devices ADM1033'...                     No
Probing for `Analog Devices ADM1034'...                     No
Probing for `SPD EEPROM'...                                 Yes
    (confidence 8, not a hardware monitoring chip)
Probing for `EDID EEPROM'...                                No
Client found at address 0x51
Probing for `Analog Devices ADM1033'...                     No
Probing for `Analog Devices ADM1034'...                     No
Probing for `SPD EEPROM'...                                 Yes
    (confidence 8, not a hardware monitoring chip)
Client found at address 0x52
Probing for `Analog Devices ADM1033'...                     No
Probing for `Analog Devices ADM1034'...                     No
Probing for `SPD EEPROM'...                                 Yes
    (confidence 8, not a hardware monitoring chip)
Client found at address 0x53
Probing for `Analog Devices ADM1033'...                     No
Probing for `Analog Devices ADM1034'...                     No
Probing for `SPD EEPROM'...                                 Yes
    (confidence 8, not a hardware monitoring chip)

Now follows a summary of the probes I have just done.
Just press ENTER to continue: 

Driver `it87':
  * ISA bus, address 0x290
    Chip `ITE IT8712F Super IO Sensors' (confidence: 9)

Driver `k10temp' (autoloaded):
  * Chip `AMD Family 10h thermal sensors' (confidence: 9)

To load everything that is needed, add this to /etc/modules:
#----cut here----
# Chip drivers
it87
#----cut here----
If you have some drivers built into your kernel, the list above will
contain too many modules. Skip the appropriate ones!

Do you want to add these lines automatically to /etc/modules? (yes/NO)YES
Successful!

Monitoring programs won't work until the needed modules are
loaded. You may want to run 'service module-init-tools start'
to load them.

Unloading i2c-dev... OK
Unloading cpuid... OK

Из этого ясно, что мат плата - ASUS M4A88T-M/USB3, которая позволяет управлять скоростью вращения кулера, необходимо лишь включить некоторые модули ядра. А именно - it87.

Загрузка модуля
leon@Berta:~$ sudo service module-init-tools start
...
module-init-tools stop/waiting

Настраиваем датчики для "pulse width modulation (pwm)"
leon@Berta:~$ sudo pwmconfig 
# pwmconfig revision 5857 (2010-08-22)
This program will search your sensors for pulse width modulation (pwm)
controls, and test each one to see if it controls a fan on
your motherboard. Note that many motherboards do not have pwm
circuitry installed, even if your sensor chip supports pwm.

We will attempt to briefly stop each fan using the pwm controls.
The program will attempt to restore each fan to full speed
after testing. However, it is ** very important ** that you
physically verify that the fans have been to full speed
after the program has completed.

Found the following devices:
   hwmon0 is atk0110
   hwmon1/device is k10temp
   hwmon2/device is it8712

Found the following PWM controls:
   hwmon2/device/pwm1
   hwmon2/device/pwm2
   hwmon2/device/pwm3

Giving the fans some time to reach full speed...
Found the following fan sensors:
   hwmon0/fan1_input     current speed: 3292 RPM
   hwmon0/fan2_input     current speed: 0 ... skipping!
   hwmon0/fan3_input     current speed: 0 ... skipping!
   hwmon2/device/fan1_input     current speed: 3260 RPM
   hwmon2/device/fan2_input     current speed: 0 ... skipping!
   hwmon2/device/fan3_input     current speed: 0 ... skipping!

Warning!!! This program will stop your fans, one at a time,
for approximately 5 seconds each!!!
This may cause your processor temperature to rise!!!
If you do not want to do this hit control-C now!!!
Hit return to continue: 

Testing pwm control hwmon2/device/pwm1 ...
  hwmon0/fan1_input ... speed was 3292 now 1008
    It appears that fan hwmon0/fan1_input
    is controlled by pwm hwmon2/device/pwm1
Would you like to generate a detailed correlation (y)? 
Note: If you had gnuplot installed, I could generate a graphical plot.
    PWM 255 FAN 3260
    PWM 240 FAN 3199
    PWM 225 FAN 3154
    PWM 210 FAN 3125
    PWM 195 FAN 3000
    PWM 180 FAN 2872
    PWM 165 FAN 2710
    PWM 150 FAN 2528
    PWM 135 FAN 2335
    PWM 120 FAN 2191
    PWM 105 FAN 2156
    PWM 90 FAN 2156
    PWM 75 FAN 1854
    PWM 60 FAN 1730
    PWM 45 FAN 1679
    PWM 30 FAN 1614
    PWM 28 FAN 1577
    PWM 26 FAN 1516
    PWM 24 FAN 1461
    PWM 22 FAN 1403
    PWM 20 FAN 1347
    PWM 18 FAN 1290
    PWM 16 FAN 1240
    PWM 14 FAN 1186
    PWM 12 FAN 1147
    PWM 10 FAN 1142
    PWM 8 FAN 1134
    PWM 6 FAN 1126
    PWM 4 FAN 1117
    PWM 2 FAN 1106
    PWM 0 FAN 1022

  hwmon2/device/fan1_input ... speed was 3260 now 1018
    It appears that fan hwmon2/device/fan1_input
    is controlled by pwm hwmon2/device/pwm1
/usr/sbin/pwmconfig: строка 474: hwmon2/device: превышен предел рекурсии выражения (error token is "device")
Testing is complete.
Please verify that all fans have returned to their normal speed.

The fancontrol script can automatically respond to temperature changes
of your system by changing fanspeeds.
Do you want to set up its configuration file now (y)? 
What should be the path to your fancontrol config file (/etc/fancontrol)? 
Loading configuration from /etc/fancontrol ...

Select fan output to configure, or other action:
1) hwmon2/device/pwm1  3) Just quit       5) Show configuration
2) Change INTERVAL     4) Save and quit
select (1-n): 1

Devices:
hwmon0 is atk0110
hwmon1/device is k10temp
hwmon2/device is it8712

Current temperature readings are as follows:
hwmon0/temp1_input 37
hwmon0/temp2_input 36
hwmon1/device/temp1_input 22
hwmon2/device/temp1_input 37
hwmon2/device/temp2_input 36
hwmon2/device/temp3_input -128

Select a temperature sensor as source for hwmon2/device/pwm1:
1) hwmon0/temp1_input
2) hwmon0/temp2_input
3) hwmon1/device/temp1_input
4) hwmon2/device/temp1_input
5) hwmon2/device/temp2_input
6) hwmon2/device/temp3_input
7) None (Do not affect this PWM output)
select (1-n): 1

Enter the low temperature (degree C)
below which the fan should spin at minimum speed (20): 40

Enter the high temperature (degree C)
over which the fan should spin at maximum speed (60): 

Enter the PWM value (0-255) to use when the temperature
is over the high temperature limit (255): 


Select fan output to configure, or other action:
1) hwmon2/device/pwm1  3) Just quit       5) Show configuration
2) Change INTERVAL     4) Save and quit
select (1-n): 5

Common Settings:
INTERVAL=10

Settings of hwmon2/device/pwm1:
  Depends on hwmon0/temp1_input
  Controls hwmon0/fan1_input
  MINTEMP=40
  MAXTEMP=60
  MINSTART=150
  MINSTOP=0


Select fan output to configure, or other action:
1) hwmon2/device/pwm1  3) Just quit       5) Show configuration
2) Change INTERVAL     4) Save and quit
select (1-n): 4

Saving configuration to /etc/fancontrol...
Configuration saved

Смотрим конфиг файл, который получился
leon@Berta:~$ cat /etc/fancontrol 
# Configuration file generated by pwmconfig, changes will be lost
INTERVAL=10
DEVPATH=hwmon0=devices/LNXSYSTM:00/device:00/PNP0A03:00/device:12/ATK0110:00 hwmon2=devices/platform/it87.656
DEVNAME=hwmon0=atk0110 hwmon2=it8712
FCTEMPS=hwmon2/device/pwm1=hwmon0/temp1_input
FCFANS= hwmon2/device/pwm1=hwmon0/fan1_input
MINTEMP=hwmon2/device/pwm1=40
MAXTEMP=hwmon2/device/pwm1=60
MINSTART=hwmon2/device/pwm1=150
MINSTOP=hwmon2/device/pwm1=0

Запускаем службу управления вентиляторами
leon@Berta:~$ sudo /etc/init.d/fancontrol start
 * Starting fan speed regulator fancontrol

В итоге имеем вместо > 2500 оборотов, скромные 1025 и это при обычном режиме работы (netbeans, skype, pidgin, firefox)


среда, 16 ноября 2011 г.

CSS. Один блок поверх другого.

<div style='position: relative; width: 100px; height: 100px; z-index: 1;' >div1</div>
<div style='top: -100px; position: relative; width: 100px; height: 100px; z-index: 2;'>div2</div>

CSS. Затемнение экрана.

<div id='mydiv' style="position: fixed; top: 0px; left: 0px; margin: 0px;
            padding: 0px; width: 100%; height: 100%;
            background: black; opacity: 0.5; z-index: 100; "></div>

воскресенье, 13 ноября 2011 г.

Ubuntu. KVM-свитч и разрешение.

Поставил себе kvm - d-link 121 разрешение в ubuntu стало доступно в режиме CRT. Максимум 1600x1600.

Смотрим xrandr
leon@Berta:~$ xrandr
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 1920 x 1920
DFP1 disconnected (normal left inverted right x axis y axis)
CRT1 connected 1366x768+0+0 (normal left inverted right x axis y axis) 0mm x 0mm
   1600x1200      60.0  
   1400x1050      60.0  
   1280x1024      60.0     47.0     43.0  
   1440x900       59.9  
   1280x960       60.0  
   1366x768       59.9  
   1360x768       60.0  
   1280x800       60.0  
   1152x864       60.0     47.0     43.0  
   1280x768       59.9     56.0  
   1280x720       60.0     50.0  
   1024x768       60.0     43.5  
   800x600        60.3     56.2     47.0  
   720x480        60.0  
   640x480        60.0

Генерируем нужный modeline
leon@Berta:~$ cvt 1920 1080
# 1920x1080 59.96 Hz (CVT 2.07M9) hsync: 67.16 kHz; pclk: 173.00 MHz
Modeline "1920x1080_60.00"  173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync

Добавляем новый режим
leon@Berta:~$ xrandr --newmode "1920x1080_60.00"  173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync

leon@Berta:~$ xrandr --addmode CRT1 --mode 1920x1080_60.00

Выставлять режим с помощью xrandr бессмысленно. Мне помог AMD Catalyst Control Center.
Там удалось выбрать необходимый режим и после перезагрузки все заработало.

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

ibook. OSX Leopard необходимый софт.

XAMPP для OSX
http://www.apachefriends.org/en/xampp-macosx.html
Netbeans 6.5.1 работает довольно шустро на ppc 1.42 GHZ, 1.5G RAM
http://netbeans.org/downloads/6.5.1/index.html
iTerm2 замена стандартного терминала, есть вкладки
http://www.iterm2.com/#/section/home

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

ibook. Debian Squeeze настройка wifi.

ibook имеет вот такую карту wifi

# lspci | grep Broadcom

Broadcom Corporation BCM4318 [AirForce One 54g] 802.11g

Добавляем в /etc/apt/sources.list
deb http://ftp.us.debian.org/debian squeeze main contrib non-free

Ставим, если надо
# apt-get install wireless-tools
# apt-get install wpasupplicant

Обновляем списки apt
# apt-get update

Ставим firmaware
# apt-get install firmware-b43-installer

Если модуль ядра не загрузился, делаем ручками
# modprobe b43

Проверяем доступный интерфейс
# iwconfig

Открываем конфигурацию сетевых интерфейсов
# nano /etc/network/interfaces

У меня wpa2 c DHCP
auto wlan0
iface wlan0 inet dhcp
    wpa-ssid mynetworkname
    wpa-psk mysecretpassphrase

Подключаемся
# ifup wlan0

среда, 2 ноября 2011 г.

ibook. Debian 6 эмуляция клавиш мыши.

ibook имеет тот самый однокнопочный трекпад.
Делаем так, что
fn + ctrl = средняя кнопка мыши
fn + alt = левая кнопка мыши

Открываем /etc/sysctl.conf, и добавляем строки:
dev.mac_hid.mouse_button_emulation = 1
dev.mac_hid.mouse_button2_keycode = 97
dev.mac_hid.mouse_button3_keycode = 100

jQuery. Установка значения radio.

var myradio = $('input:radio[name=myradio]');
myradio.filter('[value=myval]').attr('checked', true);

jQuery. Сброс значений формы.

$(':text, :password, :file, SELECT', '#myform').val(''); 
$(':input', '#myform').removeAttr('checked').removeAttr('selected')

понедельник, 31 октября 2011 г.

jQuery. Выбрать все опции в мультиселекте.

Длинный способ
$(document).ready(function() {
    $("#selectall").click(function() {
        $("#mylist").each(function(){
            $("#mylist option").attr("selected", "selected"); });
    }) ;
 
    $("#unselectall").click(function() {
        $("#mylist").each(function(){
            $("#mylist option").removeAttr("selected"); });
    }) ;
 
});
Короткий способ
// выбрать все
(function($){
   $('form select option').prop('selected',true);
})(jQuery)

// отменить все
 
(function($){
   $('form select option').prop('selected',false);
})(jQuery)

Linux. cdrecord.

Узнаем адрес устройства
leon@Berta:~$ cdrecord -scanbus
scsibus1:
 1,0,0 100) *
 1,1,0 101) 'HL-DT-ST' 'DVDRAM GH22NS50 ' 'TN03' Removable CD-ROM
 1,2,0 102) *
 1,3,0 103) *
 1,4,0 104) *
 1,5,0 105) *
 1,6,0 106) *
 1,7,0 107) *
Очищаем перезаписываемый cd
leon@Berta:~$ cdrecord -v dev=1,1,0 blank=fast
Пишем iso-образ
leon@Berta:~$ cdrecord -v dev=1,1,0 /home/leon/debian-6.0.3-powerpc-netinst.iso

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

Ubuntu. Обновился до 11.10 Oneiric Ocelot.

Все что сделано в сторону Unity и Gnome Shell не прет вообще.
Возвращаем старый добрый gnome, насколько это возможно ...
Выбираем в настройках системы автовход для своего пользователя.
sudo apt-get install gnome-session-fallback
sudo /usr/lib/lightdm/lightdm-set-defaults -s gnome-classic

На панели все двигаем придерживая alt и нажимая среднюю кнопку
alt + правая кнопка - добавить на панель

В итоге получилось вот так

Ubuntu. Глюк c редактированием меню GNOME.

Пробовал отредактировать меню, удалить приложения wine из секции Прочие - меню слетело полностью.
Оказалось, что файл меню ~/.config/menus/gnome-applications.menu - абсолютно пуст.
Запускаю alacarte (утилита редактирования меню) из консоли, результат:
Traceback (most recent call last):
File "/usr/bin/alacarte", line 37, in 
main()
File "/usr/bin/alacarte", line 33, in main
app = MainWindow(datadir, version, sys.argv)
File "/usr/share/alacarte/Alacarte/MainWindow.py", line 49, in __init__
self.editor = MenuEditor()
File "/usr/share/alacarte/Alacarte/MenuEditor.py", line 36, in __init__
self.__loadMenus()
File "/usr/share/alacarte/Alacarte/MenuEditor.py", line 48, in __loadMenus
self.applications.dom = xml.dom.minidom.parse(self.applications.path)
File "/usr/lib/python2.6/xml/dom/minidom.py", line 1918, in parse
return expatbuilder.parse(file)
File "/usr/lib/python2.6/xml/dom/expatbuilder.py", line 924, in parse
result = builder.parseFile(fp)
File "/usr/lib/python2.6/xml/dom/expatbuilder.py", line 211, in parseFile
parser.Parse("", True)
xml.parsers.expat.ExpatError: no element found: line 1, column 0

В итоге почистил в ~/.local/share/applications/ все что связано с wine, удалил ~/.config/menus/gnome-applications.menu
Завершил сеанс. Меню вернулось к своему первоначальному состоянию.

понедельник, 24 октября 2011 г.

Flash Media Server. Запись потока.

Возникла у меня идея - сохранять трансляции на стороне сервера, так, чтобы при каждой публикации потока создавался новый файл с unix timestamp в имени. И важно чтобы имя потока не менялось, оно прописано в клиенте трансляции. Я как человек практически незнакомый с actionscript, flex, fms и тд, полез в документацию по серверному as и не обнаружил никаких способов получить текущее время на стороне сервера. Допускаю, что такие методы таки есть ...
Но до лучших времен пришлось писать вот такого динозавра с запросом к клиентской части:

клиент app.mxml
<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"    
layout="absolute" creationComplete="init()"> 
<mx:Script>

...

private function init():void
{ 
      // Объект подключения к серверу
      nc = new NetConnection();
      // Клиент - текущий объект приложения
      nc.client = this;

      ...
}

// метод приложения возвращающий timestamp
public function getCurTime():Number
{
      var now:Date = new Date();
      return now.time;
}

...


сервер main.asc
// Разрешаем отладку
// Отладку смотрим в логах fms, ...logs/_defaultVHost_/webcast/_definst_/
application.allowDebug = true;

// Обработчик результата вызова метода клиента
TimeHandler = function()
{
    // Обработчик получения результата
    this.onResult = function(curTimestamp)
    {
        // Формируем имя файла потока
        file = "cast" + curTimestamp;
        trace('Attempt to save the file: ' + file);
        // Пишем поток
        // По-умолчанию все пишется в каталог streams/_definst_ приложения
        // Это можно изменить, создав файл Application.xml
        // и прописав там пути в определенных секциях
        stream = Stream.get(file);
        stream.play("webcast");
        stream.record();
    }
 
    this.onStatus = function(info)
    { 
        trace("Failed with code:" + info.code); 
    } 
};

// Обработчик события публикации потока
application.onPublish = function (clientObj, streamObj)
{
    // Вызываем клиентский метод, передаем обработчик, как параметр
    // обязательно должен быть метод свойства NetConnection.client
    clientObj.call("getCurTime", new TimeHandler());
};

Витиевато одним словом получилось, кто-бы подсказал способ попроще, был бы рад ;-)

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

Javascript. Работа с cookie.

function createCookie(name,value,days)
{
    if (days)
    {
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        var expires = "; expires="+date.toGMTString();
    }
    else var expires = "";
    document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name)
{
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++)
    {
        var c = ca[i];
        while (c.charAt(0)==' ') c = c.substring(1,c.length);
        if (c.indexOf(nameEQ) == 0)
            return c.substring(nameEQ.length,c.length);
    }
    return null;
}

function eraseCookie(name)
{
    createCookie(name,"",-1);
}

суббота, 15 октября 2011 г.

Flash Media Server. Хостинг.

Для своего небольшого flex-приложения для трансляции звука и видео с веб-камеры и микрофона я нашел вот этот хостинг http://www.influxis.com.
Для тестирования идеален тариф Intro за 20$ в месяц. Количество соединений ограничено - 20.
Поддержка мне понравилась, отвечают быстро, очень вежливы.
Если учесть, что хостинг нужен будет время от времени, лучшего варианта я не нашел. Учитывая что подписка adobe 65$/мес + расходы на выделенный сервер + установка и настройка fms на сервере.
Про покупку лицензии я промолчу ;-).

Оплата картой visa, регистрация заняла минуты 2 и все, сервер готов к использованию.

Географическое расположение сервера на выбор: штаты, Англия, Голландия.

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

Flex. Flash Media Server живая трансляция c помощью веб-камеры и микрофона.

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

Выводим живое изображение с камеры ... app.mxml

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"    
layout="absolute" creationComplete="init()"> 
<mx:Script>

    import mx.controls.Alert;
    import mx.core.UIComponent;
    import flash.net.NetConnection;
    import flash.media.Microphone; 
    
    private var nc:NetConnection;
    private var ns:NetStream;
 
    private function init():void
    { 
        // Подключение к медиа-серверу
        nc = new NetConnection();
        nc.client = this;
        nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
        nc.connect("rtmp:/webcast");
    }
 
   // Fix for AS3
   public function onBWDone():void {} 
 
   private function onNetStatus(event:NetStatusEvent):void
   { 
        if (event.info.code != "NetConnection.Connect.Success")
        {
            Alert.show(event.info.code);
            return;
        }
        
        var vContainer:UIComponent = new UIComponent();
        
        var mic:Microphone = Microphone.getMicrophone();
        
        var camWidth:int = 640;
        var camHeight:int = 480;
        
        var cam:Camera = new Camera();
        cam = Camera.getCamera();
        cam.setMode(camWidth, camHeight, 24);
        
        var localvid:Video = new Video(camWidth, camHeight);
        localvid.attachCamera(cam);
        vContainer.addChild(localvid);
        
        canvasVideoIn.addChild(vContainer);
        ns = new NetStream(nc);
        ns.attachCamera(cam);
        ns.attachAudio(mic);
        ns.publish("webcast");
    }
 
 </mx:Script>

 <mx:Canvas width="700" 
               height="550" 
               y="50" 
               horizontalScrollPolicy="off"
               verticalScrollPolicy="off" 
               x="20" 
               backgroundColor="0xcccccc" 
               id="canvasVideoIn">

 </mx:Canvas>
 
 </mx:Application>

Клиентский скрипт client.mxml

<?xml version="1.0" encoding="utf-8"?> 
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"    
layout="absolute" creationComplete="init()"> 
<mx:Script>

    import mx.controls.Alert;
    import mx.core.UIComponent;
    import flash.net.NetConnection;
    
    private var nc:NetConnection;
    private var streamIn:NetStream;  
    private var videoIn:Video;
 
    private function init():void
    { 
        nc = new NetConnection();
        nc.client = this;
        nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
        nc.connect("rtmp:/webcast");
    }
 
   // Fix for AS3
   public function onBWDone():void {} 
 
   private function onNetStatus(event:NetStatusEvent):void
   {         
        if (event.info.code != "NetConnection.Connect.Success")
        {
            //Alert.show(event.info.code );
            return;
        }
        
        videoIn = new Video(320, 240);
        var videoHolder:UIComponent = new UIComponent();
        videoHolder.addChild(videoIn);
        canvasVideoIn.addChild(videoHolder);
        streamIn = new NetStream(nc);
        videoIn.attachNetStream(streamIn);
        streamIn.play("webcast");
    }  
 
 </mx:Script>

<mx:Canvas width="320" 
              height="240" 
              y="50" 
              horizontalScrollPolicy="off" 
              verticalScrollPolicy="off" 
              x="20" 
              backgroundColor="0xcccccc" 
              id="canvasVideoIn" />

 </mx:Application>

Flex. Событие click.

<mx:Script>
...
private function clickHandler(event:MouseEvent):void
{
    Alert.show('hello!');
}
</mx:Script>
...
<mx:Button id="Record" label="Record" y="500" click="clickHandler(event)"></mx:Button>
...

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

PHP. Запуск процессов сервера из браузера без ожидания загрузки страницы.

Как писалось тут PHP. Как послать браузеру ответ и продолжить выполнение, так вот когда такое делаем, то не забываем послать вывод скрипта в /dev/null или еще куда в файл.

Adobe Media Server. Настройка.

Для того чтобы зайти в административную консоль сервера надо отредактировать файл конфигурации.
Хотя я указал пароль администратора при установке, но зайти все равно не мог !!!
Файлы конфигурации лежат в каталоге /opt/adobe/fms/conf/, все действия от суперпользователя.
leon@Berta:/opt/adobe/fms$ sudo ls /opt/adobe/fms/conf/
_defaultRoot_  fms.ini Logger.xml  Server.xml Users.xml
leon@Berta:/opt/adobe/fms$ sudo gedit /opt/adobe/fms/conf/fms.ini

В файл добавляем строку ...
...

SERVER.ADMIN_PASSWORD = xxxxxxxx
...

Перезапускаем админ сервер ...
leon@Berta:/opt/adobe/fms$ sudo ./fmsmgr adminserver restart
Admin server:fmsadmin command:restart
Stopping Adobe Flash Media Admin Server (please check /var/log/messages)
Admin Server has shutdown...

Starting Adobe Flash Media Admin Server (please check /var/log/messages)

Аллилуйя !!! Можно зайти в админ консоль, которая лежит тут:
file:///opt/adobe/fms/tools/fms_adminConsole.htm
Так что просто открываем в браузере.

воскресенье, 2 октября 2011 г.

Adobe Flash. Отключаем кэширование swf в firefox.

В firefox есть неприятный момент, даже если мы перекомпилируем as браузер загружает swf из кэша и мы не видим никаких перемен ...
1. Открываем новую вкладку
2. Переходим about:config в url
3. Соглашаемся быть очень осторожными и слушаться маму
4. Ставим browser.cache.disk.enable в false
browser.cache.memory.enable в false

Adobe Flash. Установка flash player debug в Ubuntu 64 bit.

К сожалению не существует debug версии для 64bit от adobe. Но есть и хорошие новости, если устанавливаем через apt то получаем 32bit версию с враппером, позволяющим запустить в 64bit браузере. После этого наша задача подменить плагин отладочной версией.

Установка для последнего на данный момент firefox 7.0.1.

1. Удаляем любые установленные плагины flash
leon@Berta:~/Soft/flashplayer_10_plugin_debug$ aptitude search flash
p   flashbake                                                              - automated snapshots with git                                                     
i A flashplugin-installer                                                  - Adobe Flash Player plugin installer                                              
i   flashplugin-nonfree                                                    - Adobe Flash Player plugin installer (transitional package)                       
p   flashplugin64-installer                                                - Adobe Flash Player plugin 64 bit alpha installer                                 
p   flashrom                                                               - Рапознавание, чтение, запись, очистка и проверка BIOS/ROM/FLASH чипов            
p   flashybrid                                                             - automates use of a flash disk as the root filesystem                             
p   m16c-flash                                                             - Flash programmer for Renesas M16C and R8C microcontrollers                       
p   python-webflash                                                        - Portable flash messages for Python WSGI applications                             
p   tvflash                                                                - Mellanox firmware update utility                                                 
p   vrflash                                                                - tool to flash kernels and romdisks to Agenda VR 

...

leon@Berta:sudo apt-get purge flashplugin-nonfree
leon@Berta:sudo apt-get autoremove


2. Устанавливаем плагин:
leon@Berta:sudo apt-get install flashplugin-nonfree

3. Качаем отладочную версию
http://download.macromedia.com/pub/flashplayer/updaters/10/flash_player_10_linux_dev.tar.gz

или http://kb2.adobe.com/cps/142/tn_14266.html

4. Заменяем установленный плагин отладочным
leon@Berta:cd ~/Soft/flashplayer_10_plugin_debug
leon@Berta:~/Soft/flashplayer_10_plugin_debug$ sudo mv libflashplayer.so /usr/lib/flashplugin-installer/
leon@Berta:~/Soft/flashplayer_10_plugin_debug$ sudo cp -r usr /

И что важно !!! копируем каталог usr в корень, без этого не работало.

5. Перезапуск firefox

Отладочный плеер стоит !!! При этом flashbug работает !!!

суббота, 1 октября 2011 г.

Flash Media Server. Установка.

1. Качаем сервер с сайта adobe http://www.adobe.com/products/flashmediaserver/
для linux

2. Качаем flex sdk http://opensource.adobe.com/wiki/display/flexsdk/Flex+SDK

3. Устанавливаем сервер.
Распаковываем архив, читаем readme, секцию про установку для linux.
По умолчанию сервер ставится в /opt/adobe/fms.
Код серверной части будет лежать в /opt/adobe/fms/applications.
Там будем создавать приложения, каждое в отдельном каталоге.

4. Устанавливаем sdk (инструметы разработки flex)
Распаковываем архив в любое удобное место (/home/leon/dev/flexsdk).
Настраиваем окружение:
echo "PATH=\${PATH}:~/dev/flexsdk/bin" >> ~/.bashrc
Перезапуск терминала ...

leon@Berta:~$ mxmlc
Загрузка файла конфигурации /home/leon/dev/flexsdk/frameworks/flex-config.xml
Adobe Flex Compiler (mxmlc)
Version 4.5.1 build 21328
Copyright (c) 2004-2011 Adobe Systems, Inc. All rights reserved.

Ошибка: Необходимо указать целевой файл

См. справку "mxmlc для получения информации об использовании командной строки.

5. Проверяем подключение к серверу.
Код клиентской части лежит на хосте веб-сервера (apache) /var/www/fmstest.
Веб-сервер настроен так что доступ по http такой http://localhost/fmstest.
В fmstest создаем файл FMS3Connect.as
В который копипастим код из одной ценной книги ...
package
{
      import flash.net.NetConnection;
      import flash.display.Sprite;
      import flash.text.TextField;
      import flash.events.NetStatusEvent;
    
      public class FMS3Connect extends Sprite
      {
            private var nc:NetConnection;
            private var rtmpNow:String;
            private var msg:String;
            private var connectText:TextField;
            private var posX:Number;
    
            function FMS3Connect ()
            {
    
                 nc=new NetConnection();
                 nc.addEventListener (NetStatusEvent.NET_STATUS,checkConnect);
                 //rtmpNow="rtmpe://192.168.0.11/connect";
                 rtmpNow="rtmpe:/connect";
                 nc.connect (rtmpNow);
            }
            private function checkConnect (event:NetStatusEvent):void
            {
                 connectText=new TextField();
                 msg=event.info.code;
                 connectText.width=250;
                 connectText.text=msg;
                 addChild (connectText);
                 posX=connectText.stage.stageWidth;
                 connectText.x=(posX/2)-((msg.length/2)*(6));
                 connectText.y=175;
            }
      }
}




Для редактирования кода использую Komodo Edit.

Компилирую скрипт:
mxmlc -static-link-runtime-shared-libraries=true -optimize=false -omit-trace-statements=false /var/www/fmstest/FMS3Connect.as

Результат - файл /var/www/fmstest/FMS3Connect.swf

Создаем каталог серверной части приложения /opt/adobe/fms/applications/connect

В браузере переходим http://localhost/fmstest/FMS3Connect.swf

Должны увидеть NetConnection.Connect.Success

Запуск сервера ./fmsmgr server fms start

четверг, 29 сентября 2011 г.

понедельник, 26 сентября 2011 г.

Zend Framework. Фильтр Rename с сохранением расширения файла.

// Создаем объект формы
$form = new Zend_Form();

// Создаем элемент загрузки файла
$file = new Zend_Form_Element_File('as_file');
$file->setLabel('Загрузить файл(PDF, MSWORD)');
$file->setDestination('/path/to/upload/dir');
$file->addValidator('Extension', false, 'pdf,doc,docx');
$file->addValidator('Count', false, 1);
$file->addValidator('Size', false, 5000000);
$form->addElement($file);

...

if($this->_request->isPost() && $form->isValid($this->_request->getParams()))
{
    // Получаем массив - информация о загружаемом файле
    $file = $form->as_file->getFileInfo();
    // Ищем расширение файла
    $ext = preg_match('#\.\w+$#', $file['as_file']['name'], $m) ? $m[0] : '';
    // Новое имя
    $new_name = 'myfile' . uniqid() . $ext;
    // Добавляем фильтр к элементу
    $form->as_file->addFilter('Rename', '/path/to/upload/dir/'. $new_name);
    // Загружаем файл на сервер
    $form->as_file->receive();
}

пятница, 9 сентября 2011 г.

Автоматизируем распознавание капчи своими руками при помощи PHP .

Сразу оговорюсь, цель была довольна невинна, заходить под своим аккаунтом на один известный сервис, который периодически просит ввести капчу для процедуры авторизации. Описанный ниже способ подходит для распознавания очень простых картинок, без особых искажений. В моем случае он оказался достаточно эффективным. Для реализации мне понадобилась система оптического распознавания символов (OCR) для Linux.

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

Нам будут нужны следующие утилиты:

  • convert из пакета imagemagick (преобразование форматов графических файлов)
  • djpeg - восстановление файла jpeg в bmp
  • tesseract - open source ocr от google (лучшая на данный момент из бесплатных

// recognize.sh
#!/bin/sh 

TMP=`dirname $0`/tmp

convert $1 $TMP/tmp.jpg
djpeg -greyscale -bmp $TMP/tmp.jpg > $TMP/tmp.bmp
tesseract $TMP/tmp.bmp $TMP/output -l eng
cat $TMP/output.txt && rm $TMP/tmp.bmp $TMP/tmp.jpg $TMP/output.txt

Tут конвертируем файл, имя которого передается в скрипт в качестве первого параметра, в jpeg (у меня капча была в gif), затем преобразуем в черно-белый bmp и распознаем при помощи tesseract. В финале, чистим каталог от временных файлов


class Tesseract {

    /**
     *
     * @var string
     */
    protected $scriptPath;

    /**
     *
     * @var string $path Path to shell-script
     */
    function __construct($path) {

        $this->scriptPath = $path;
    }

    /**
     *
     * Recognize CAPTCHA
     *
     * @var string $imageFile Path to image file
     * @return string|null Recognized captcha or null
     */
    function recognize($imageFile) {

        if(! is_readable($imageFile)) {

            throw new Exception ('Image file isn\'t readable.');
        }

        $output = shell_exec(sprintf('sh %s %s', $this->scriptPath, $imageFile));
        
        return preg_match('/\d{4}/', $output, $m) ? $m[0] : null; 
    }
}

$tesseract = new Tesseract('/path/to/shell/script');
$captcha = $tesseract->recognize('/path/to/image/file');

четверг, 1 сентября 2011 г.

PHP. json_encode и кириллица.

function json_encode_cyr($str) {
    $arr_replace_utf = array('\u0410', '\u0430', '\u0411', '\u0431', '\u0412', '\u0432',
        '\u0413', '\u0433', '\u0414', '\u0434', '\u0415', '\u0435', '\u0401', '\u0451', '\u0416',
        '\u0436', '\u0417', '\u0437', '\u0418', '\u0438', '\u0419', '\u0439', '\u041a', '\u043a',
        '\u041b', '\u043b', '\u041c', '\u043c', '\u041d', '\u043d', '\u041e', '\u043e', '\u041f',
        '\u043f', '\u0420', '\u0440', '\u0421', '\u0441', '\u0422', '\u0442', '\u0423', '\u0443',
        '\u0424', '\u0444', '\u0425', '\u0445', '\u0426', '\u0446', '\u0427', '\u0447', '\u0428',
        '\u0448', '\u0429', '\u0449', '\u042a', '\u044a', '\u042d', '\u044b', '\u042c', '\u044c',
        '\u042d', '\u044d', '\u042e', '\u044e', '\u042f', '\u044f');
    $arr_replace_cyr = array('А', 'а', 'Б', 'б', 'В', 'в', 'Г', 'г', 'Д', 'д', 'Е', 'е',
        'Ё', 'ё', 'Ж', 'ж', 'З', 'з', 'И', 'и', 'Й', 'й', 'К', 'к', 'Л', 'л', 'М', 'м', 'Н', 'н', 'О', 'о',
        'П', 'п', 'Р', 'р', 'С', 'с', 'Т', 'т', 'У', 'у', 'Ф', 'ф', 'Х', 'х', 'Ц', 'ц', 'Ч', 'ч', 'Ш', 'ш',
        'Щ', 'щ', 'Ъ', 'ъ', 'Ы', 'ы', 'Ь', 'ь', 'Э', 'э', 'Ю', 'ю', 'Я', 'я');
    $str1 = json_encode($str);
    $str2 = str_replace($arr_replace_utf, $arr_replace_cyr, $str1);
    return $str2;
}

воскресенье, 10 июля 2011 г.

Ubuntu. Удаление драйвера ATI (fglrx) .

  sudo apt-get remove --purge xorg-driver-fglrx fglrx*
  sudo apt-get install --reinstall libgl1-mesa-glx libgl1-mesa-dri fglrx-modaliases
  sudo dpkg-reconfigure xserver-xorg
  sudo apt-get install --reinstall xserver-xorg-core

Если есть, удаляем xorg.conf, для radeon он не нужен

пятница, 1 июля 2011 г.

PHP. HTML в PDF.

Отличная библиотека: http://www.mpdf1.com/mpdf/

Пример:
require_once 'mpdf.php';

$strHTML = '<html><body><h1 class="my-title">Hello PDF!</h1></body></html>';
        
$objPDF = new mPDF('utf-8', 'A4', '8', '', 10, 10, 7, 7, 10, 10); /*задаем формат, отступы и.т.д.*/
$objPDF->charset_in = 'cp1251'; /*кодировка*/
        
$strCSS = 'body 
{ 
    font-family: Helvetica 
},
            
.my-title
{ 
    background-color: #7E54A7;
    padding: 10px;
    color: #FFF;
    font-weight: bold; 
}';
        
$objPDF->WriteHTML($strCSS, 1);

$objPDF->list_indent_first_level = 0;
$objPDF->WriteHTML($strHTML, 2); /*формируем pdf*/
$objPDF->Output('output_file' . '.pdf', 'I');

четверг, 16 июня 2011 г.

MySQL.Ошибка при удаление внешнего ключа INNODB.

При попытке удалить или изменить поле таблицы получаем что-то вроде этого
ERROR 1025 (HY000): Error on rename of './test/#sql-2fa8_1' to './test/test2' (errno: 150)
...
mysql> SET FOREIGN_KEY_CHECKS=0;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW CREATE TABLE my_table;
...
KEY `my_index` (`my_column`),
  CONSTRAINT `bla_bla_bla` FOREIGN KEY (`my_column`) REFERENCES `another_table` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=212608 DEFAULT CHARSET=utf8 | 
+-------+-------------------------------------------------------------------------------
----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------
-----------------------------------------------------------+
1 row in set (0.00 sec)
mysql> ALTER TABLE my_table DROP FOREIGN KEY bla_bla_bla;
Query OK, 205474 rows affected (7.88 sec)
Records: 205474  Duplicates: 0  Warnings: 0
mysql> ALTER TABLE `my_table` DROP INDEX `my_index`
mysql> SET FOREIGN_KEY_CHECKS=1;
Query OK, 0 rows affected (0.00 sec)

MySQL. Удаление таблицы INNODB.

Не можете удалить пустую таблицу с внешними ключами ;-))))
Ошибка: 1217 - Cannot delete or update a parent row: a foreign key constraint fails

...
Database changed
mysql> SET FOREIGN_KEY_CHECKS=0;
Query OK, 0 rows affected (0.00 sec)

mysql> DROP TABLE innodb_table;
Query OK, 0 rows affected (0.05 sec)

mysql> SET FOREIGN_KEY_CHECKS=1;
Query OK, 0 rows affected (0.00 sec)

mysql> exit
Bye
...

HTML. JQuery. Кликабельный flash-баннер.

Библиотеку swfobject можно скачать тут http://code.google.com/p/swfobject/

<html>

    <head>
        <script type="text/javascript" src="jquery-1.8.0.js"></script>
        <script type="text/javascript" src="swfobject.js"></script>
    </head>

    <body>
        <script type="text/javascript">
            $(document).ready(function () { 
                $('#myBanner').click(function () { 
                    window.location.href = 'http://google.com' 
                }) 
            })

            var flashvars = {};
            var params = {};
            params.wmode = 'transparent';
            var attributes = {};
            var width = "swf width";
            var height = "swf height";
            swfobject.embedSWF("/path/to/swf", "myContent",
                width, height, "9.0.0", false, flashvars, params); 
        </script>

        <div id="myBanner" style="cursor: pointer;">
             <div id="myContent">Banner</div>
        </div>

   </body>

</html>

четверг, 2 июня 2011 г.

Ubuntu. Драйвера ATI.

После обновления с 10.10 до 11.04 слетели дрова ATI
$ sudo apt-get purge fglrx*
$ sudo rm /etc/X11/xorg.conf
$ sudo apt-get install fglrx
$ sudo aticonfig --initial -f
$ sudo reboot

вторник, 31 мая 2011 г.

Ubuntu. Обновление до Natty Narwhal 11.04.


Без приколов не обошлось (amd64)

1. Слетели драйвера видео (проприетарные), как следствие, X вообще не запустились,
пришлось делать X -configure и подключать open source драйвер 'radeon'
Пока на нем и живу, вроде все ок

$ lspci
...
01:05.0 VGA compatible controller: ATI Technologies Inc RS880 [Radeon HD 4250]
...

2. VirtualBox отказался запускать мой Windows 7 Professional, пришлось его обновить
Создать новую вирт машину и подключить вирт диски.

В остальном вроде все ок. Unity даже не предлагал, так и остался Gnome.

пятница, 27 мая 2011 г.

PHP. MSSQL DATETIME в UNIX TIMESTAMP.

Пробовал выставлять часовой пояс, но strtotime так и не заработал, пришлось написать функцию:

$textime = 'Apr 30 2011 09:47:08:580AM';

echo date('r', datetimeToTimestamp($texttime));

//Sat, 30 Apr 2011 09:47:08 +0300

function datetimeToTimestamp($texttime) 
{
    if (! $texttime || $texttime == '') return null;

    list($month, $day, $year, $time) = explode(' ', $texttime);
    list($hour, $minute, $second) = explode(':', $time);
        
    $month = date('m', strtotime($month));

    return mktime($hour, $minute, $second, $month, $day, $year);
}

вторник, 3 мая 2011 г.

PHP. Netbeans, PHPUnit, xdebug и отладка с модульными тестами.

Раньше я писал об организации тестов для Doctrine в связке Netbeans + PHPUnit тут и тут.

Теперь как можно делать дебаггинг ...

ставим брекпойнт ...














 запускаем отладку для MySuite.php ...














смотрим результат ...

понедельник, 2 мая 2011 г.

Ubuntu. Баг PEAR PHP 5.3.3

По-умолчанию в Ubuntu 10.10 идет PHP версии 5.3.3 в поставке PEAR которого наблюдается баг.

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=619307

При попытке установить пакет (например PHPUnit) появляется сообщение об ошибке:
$ sudo pear install --alldeps phpunit/PHPUnit
PHP Fatal error:  Call to undefined method PEAR::raiseErro() in /usr/share/php/PEAR/REST.php on line 165

Лечится обновлением php, который ставится из репозитория:
deb http://ppa.launchpad.net/nginx/php5/ubuntu maverick main
deb-src http://ppa.launchpad.net/nginx/php5/ubuntu maverick main

$ sudo apt-get update
$ sudo apt-get dist-upgrade

Теперь имеем PHP 5.3.5 и все ок.

вторник, 12 апреля 2011 г.

MySQL. Настройка производительности INNODB.

8G оперативной памяти

# Очень важно для таблиц MyISAM
# 30-40% от доступной памяти
key_buffer_size = 3072M

# Очень важный параметр для INNODB
# 70-80% доступной оперативной памяти
innodb_buffer_pool_size = 5120M

# Очень важно при больших нагрузках
# рекомендуется 64M-512M, но можно увеличить
# При изменении этого параметра надо остановить сервер MySQL
# удалить файлы лога INNODB (для ubuntu /var/lib/mysql/ib_logfile*) от root
# запустить сервер
innodb_log_file_size = 512M

innodb_log_buffer_size = 16MB

# Если отключаем, то возникает опасность потери данных
# но вырастает производительность
# при 1 каждая транзакция пишется в лог (рекомендуется)
# при 2 потеря данных возможна только при полном коллапсе операционной системы
# Крайне не рекомендую отключать при загрузке больших дампов
innodb_flush_log_at_trx_commit = 0

понедельник, 11 апреля 2011 г.

PHP. Работа с соединением (посылаем ответ и продолжаем выполнение).

Если надо, например, показать страницу, закрыть соединение после запроса пользователя и продолжить выполнение длительного процесса на сервере, то можно использовать такой код ...
ignore_user_abort(true); // скрипт продолжит выполнение
                         // даже если пользователь нажмет стоп в браузере
// начинаем буфферизацию вывода
ob_start();
echo "Ваш запрос принят ...";

// размер ответа
$size = ob_get_length();

// посылаем заголовки браузеру, что соединение закрыто
header("Content-Length: $size");
header("Content-Encoding: none"); // если включен zlib, 
                                  //не отдает контент пока не закончится вывод
header("Connection: close");

// вывод
ob_end_flush();
ob_flush();
flush();

// закрываем текущую сессию, если запущена
if (session_id()) session_write_close();

/******** процесс начинает свое выполнение ********/

sleep(50);
...

PHP. Определяем, существует ли процесс php-скрипта (unix).

Тестировалось на unbuntu.
Файл лежит в каталоге веб-сервера, выставлены права на исполнение.

Скрипт

#!/usr/bin/php
<?php

...
if(processExists()) {
    die('Уже запущен');
}
...

// скрипт исполняется значительное время

Функция

function processExists($file = false) {
    if(!$file) $file = basename (__FILE__);

    exec("ps -C $file -o pid=", $pids);
    
    return count($pids) > 1 ? true : false;
}

PHP. realpath доступ к каталогам верхнего уровня.

// На два каталога выше
$path = realpath(dirname(__FILE__) . '/../..');

MySQL. Архивирование дампа.

Для bz2 - bunzip2
mysqldump < mysqldump options> | gzip > outputfile.sql.gz
gunzip -v outputfile.sql.gz
gunzip < outputfile.sql.gz | mysql -udbuser -pdbpwd dbname

// Дамп выборки (разделение - символ табуляции)
mysql -e "SET NAMES 'utf8'; SELECT * FROM mytable" -umyuser -pmypwd mydb > mydump.txt

// Только данные (INSERT), одна строка
mysqldump -uDBUSER -pDBPWD DBNAME TABLENAME --skip-triggers --compact --no-create-info --where='id LIMIT 1' > mydump.sql

воскресенье, 10 апреля 2011 г.

PHP. Аналог mysql_real_escape_string для расширения mssql.

function mssql_escape($data) {
    if(is_numeric($data))
        return $data;
    $unpacked = unpack('H*hex', $data);
    return '0x' . $unpacked['hex'];
}

SQL. MySQL Выборка дубликатов.

// Doctrine
$emails = Doctrine_Query::create()->select('email')->from('User')
            ->groupBy('email')->having('COUNT(email) > 1')
            ->setHydrationMode(Doctrine::HYDRATE_ARRAY)->execute()

// SQL
SELECT email FROM user GROUP BY email HAVING COUNT(email) > 1

пятница, 8 апреля 2011 г.

Transact-SQL. Преобразование типа поля при выборке.

Используем команды CAST и CONVERT

Подробно - http://msdn.microsoft.com/ru-ru/library/aa226054%28v=sql.80%29.aspx

Допустим есть поле типа uniqueidentifier. При выборке средствами php (mssql_connect ...) получим мусор, а нам нужна строка.

Транслируем новый тип поля в запросе
SELECT... CAST(F_CITIZENSHIP AS VARCHAR(255)) AS CITIZENSHIP ... FROM ...
и получаем на выходе строку.

C#. Работа с датой и временем.

// Сегодня 0 часов
DateTime today = DateTime.Today;

// 8.04.2011 14:30:0
DateTime myDate = DateTime(2011, 4, 8, 14, 30, 0);

// Через 2 дня 8 часов и 20 минут
DateTime newDate = myDate.AddDays(2).AddHours(8).AddMinutes(20); 

// Месяц назад
DateTime myDate = today.AddDays(-30);

// Строка
String strMyDate = myDate.Date.ToString();


//В Transact-SQL - на 30 дней раньше текущей даты
... WHERE my_date < GETDATE() - 30 ...

среда, 6 апреля 2011 г.

C#. Блокировка важной части кода (lock).

// using System.Threading;

    class Account
    {
        private Object thisLock = new Object();
        int balance;

        Random r = new Random();

        public Account(int initial)
        {
            balance = initial;
        }

        int Withdraw(int amount)
        {
            // Состояние никогда не будет true пока работает lock
            if (balance < 0)
            {
                throw new Exception("Negative Balance");
            }

            // Закомментируем следующую строку и смотрим что будет
            lock (thisLock)
            {
                if (balance >= amount)
                {
                    Console.WriteLine("Balance before Withdrawal :  " + balance);
                    Console.WriteLine("Amount to Withdraw        : -" + amount);
                    balance = balance - amount;
                    Console.WriteLine("Balance after Withdrawal  :  " + balance);
                    return amount;
                }
                else
                {
                    return 0; // транзакция отклонена
                }
            }
        }

        public void DoTransactions()
        {
            for (int i = 0; i < 100; i++)
            {
                Withdraw(r.Next(1, 100));
            }
        }
    }

    class Test
    {
        static void Main()
        {
            Thread[] threads = new Thread[10];
            Account acc = new Account(1000);
            for (int i = 0; i < 10; i++)
            {
                Thread t = new Thread(new ThreadStart(acc.DoTransactions));
                threads[i] = t;
            }
            for (int i = 0; i < 10; i++)
            {
                threads[i].Start();
            }
        }
    }

вторник, 5 апреля 2011 г.

OSX. Установка PHP с поддержкой mssql в Leopard.

Недавно решился обновиться до Leopard, до этого сидел на Tiger. Мак у меня довольно старый - powerbook g4 1.5GHz 1G RAM.

Ставил MAMP, но там с расширениями все скучно. Поэтому ставлю macports и php5 из портов ...

PHP. Подключение к MSSQL (удаленно).

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

Есть админ доступ на сервер через удаленный рабочий стол Windows.

Как настроить SQL Server 2005 для удаленных подключений - читаем тут
http://support.microsoft.com/kb/914277

Вкратце:

a. Разрешите удаленные подключения к SQL Server 2005
  • 1. Нажмите кнопку Пуск, выберите Программы, Microsoft SQL Server 2005, перейдите к пункту Средства настройки, затем выберите Настройка контактной зоны SQL Server.
  • 2. На странице Настройка контактной зоны SQL Server 2005 выберите Настройка контактной зоны для служб и соединений.
  • 3. На странице Настройка контактной зоны для служб и соединений разверните Database Engine, выберите Удаленные соединения, затем Локальные и удаленные соединения, выберите нужный протокол для вашей сетевой среды и нажмите кнопку Применить. Примечание. Нажмите кнопку OK при появлении следующего сообщения Изменения в настройках соединений вступят в силу только после перезапуска службы компонента Database Engine.
  • 4. На странице Настройка контактной зоны для служб и соединений разверните Database Engine, выберите Службы, нажмите кнопку Стоп, дождитесь остановки службы MSSQLSERVER, затем нажмите кнопку Пуск для повторного запуска службы MSSQLSERVER.

b. Включите службу SQL Server Browser

Об обозревателе подробно читаем тут - http://msdn.microsoft.com/ru-ru/library/ms165724%28v=sql.90%29.aspx

  • 1. Нажмите кнопку Пуск, выберите Программы, Microsoft SQL Server 2005, перейдите к пункту Средства настройки, затем выберите Настройка контактной зоны SQL Server.
  • 2. На странице Настройка контактной зоны SQL Server 2005 выберите Настройка контактной зоны для служб и соединений.
  • 3. На странице Настройка контактной зоны для служб и соединений выберите SQL Server Browser, выберите Авто для Тип запуска, затем нажмите кнопку Применить. Примечание. При выборе параметра Авто служба SQL Server Browser запускается автоматически при каждом запуске Microsoft Windows.
  • 4. Нажмите кнопку Пуск, затем нажмите кнопку OK.

c. Создание исключений в брандмауэре Windows

SQL Server 2005 использует идентификатор экземпляра в качестве части пути установки файлов программы. Для создания исключения для всех экземпляров SQL Server необходимо определить верные идентификаторы экземпляров. Для получения идентификатора экземпляра выполните следующие действия.

  • 1. Нажмите кнопку Пуск, выберите Программы, Microsoft SQL Server 2005, перейдите к пункту Средства настройки, затем выберите Диспетчер конфигурации SQL Server.
  • 2. На правой панели диспетчера конфигурации SQL Server щелкните службу средства просмотра SQL Server, в главном окне правой кнопкой мыши щелкните название экземпляра, затем щелкните Свойства.
  • 3. На странице SQL Server Browser Properties (Свойства SQL Server Browser) щелкните вкладку Дополнительно, в списке свойств выберите идентификатор экземпляра, затем нажмите кнопку OK.

Для открытия брандмауэра Windows выберите в меню Пуск пункт Выполнить, введите команду firewall.cpl и нажмите кнопку ОК.

Создание исключения для SQL Server 2005 в брандмауэре Windows

Для создания исключения для SQL Server 2005 в брандмауэре Windows выполните следующие действия.

  • 1. В брандмауэре Windows щелкните вкладку Исключения, затем щелкните Добавить программу.
  • 2. В окне добавления программы нажмите кнопку Обзор.
  • 3. Щелкните исполняемую программу C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn\sqlservr.exe, щелкните Открыть, затем нажмите кнопку OK.

Примечание. В зависимости от места установки SQL Server 2005 путь может отличаться. MSSQL.1 — это идентификатор экземпляра, полученный на этапе 3 предыдущей процедуры.

Создание исключения для службы SQL Server Browser в брандмауэре Windows

Для создания исключения для службы SQL Server Browser в брандмауэре Windows выполните следующие действия.

  • 1. В брандмауэре Windows щелкните вкладку Исключения, затем щелкните Добавить программу.
  • 2. В окне добавления программы нажмите кнопку Обзор.
  • 3. Щелкните исполняемую программу C:\Program Files\Microsoft SQL Server\90\Shared\sqlbrowser.exe, щелкните Открыть, затем нажмите кнопку OK.

Примечание. В зависимости от места установки SQL Server 2005 путь может отличаться.

Лезем на сервер и смотрим имя экземпляра сервера бд, к которому требуется удаленное подключение.
Делаем это в SQL Server Cofiguration Manager.
Смотрим список служб - SQL Server (MSSQLSERVER). В моем случае это MSSQLSERVER.

Далее с нашей машины пытаемся подключиться к серверу при помощи sqlcmd (утилиты для работы с сервером из командной строки, аналог mysql). Подробно читаем тут - http://msdn.microsoft.com/ru-ru/library/ms165724%28v=sql.90%29.aspx или вызываем sqlcmd /? для справки.
sqlcmd -S tcp:xx.x.xx.xxx\MSSQLSERVER

В ответ:
Login failed for user ''. The user is not associated with a trusted SQL Server connection.

Оно и понятно - доступ закрыт. На сервере используется авторизация Windows (учетные записи ос).
Мы хотим авторизацию сервера бд. Придется создать пользователя и добавить его к конкретной базе.
А также задать ему роль (у меня db_datareader, читатель).

1. Создание имени входа SQL Server с использованием проверки подлинности SQL Server (среда SQL Server Management Studio)

Подробно - http://msdn.microsoft.com/ru-ru/library/aa337562%28v=SQL.90%29.aspx

2. Создание пользователя базы данных в среде SQL Server Management Studio

Подробно - http://msdn.microsoft.com/ru-ru/library/aa337545%28v=SQL.105%29.aspx

Ну и задаем ему необходимые права в свойствах.

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

sqlcmd -S tcp:xx.x.xx.xxx\MSSQLSERVER -U my_user -P my_pwd
1> SELECT name FROM sys.databases
2> GO
name

---------------------------------
my_db

Мы на сервере. Все ок.

Теперь для php-скрипт из пред поста меняем данные подключения:

$serverName = "xx.x.xx.xxx\MSSQLSERVER";
$connectionInfo = array (
    'Database' => 'my_db',
    'UID'  => 'my_user',
    'PWD'  => 'my_pwd'
);

PHP. Подключение к MSSQL (локально).

Установлен MSSQL Server 2005 на Windows 7 Professional ...

Смотрим список процессов:
C:\Users\leon>tasklist
Имя образа                     PID Имя сессии          № сеанса       Память
========================= ======== ================ =========== ============
...
sqlservr.exe                  2408 Services                   0 1 505 316 КБ
...

C:\Users\leon>netstat -ano
 Имя    Локальный адрес        Внешний адрес          Состояние       PID
...
TCP    127.0.0.1:1434         0.0.0.0:0              LISTENING       2408
...

Таким образом убеждаемся, что сервер запущен и слушает порт 1434

Проверяем разрешен ли TCP/IP для SQL-сервера:

SQL Server Configuration Manager -> Network Configuration -> Protocols -> TCP/IP enabled

Документация драйвера MSSQL для PHP от Microsoft тут - http://msdn.microsoft.com/ru-ru/library/ee229547%28v=SQL.10%29.aspx

Качаю и ставлю драйвер MSSQL для PHP тут -
http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=ccdf728b-1ea0-48a8-a84a-5052214caad9

Системные требования для установки драйвера - http://msdn.microsoft.com/ru-ru/library/cc296170%28v=SQL.90%29.aspx

Для PHP 5.3.x в php.ini добавляю следующее (dll положил в ext):

...
[PHP_SQLSRV]
extension=php_sqlsrv_53_nts_vc9.dll
...

Далее пытаюсь подключиться (подробности http://msdn.microsoft.com/ru-ru/library/cc296161%28v=sql.90%29.aspx):

/*
Connect to the local server using Windows Authentication and specify
the AdventureWorks database as the database in use. To connect using
SQL Server Authentication, set values for the "UID" and "PWD"
 attributes in the $connectionInfo parameter. For example:
$connectionInfo = array("UID" => $uid, "PWD" => $pwd)); 
*/
$serverName = "(local)";
$connectionInfo = array("Database" => "MyMSDb");
$conn = sqlsrv_connect($serverName, $connectionInfo);

if( $conn )
{
     echo "Connection established.\n";
}
else
{
     echo "Connection could not be established.\n";
     die(print_r( sqlsrv_errors(), true));
}

//-----------------------------------------------
// Perform operations with connection.
//-----------------------------------------------

/* Close the connection. */
sqlsrv_close($conn);

Получаю ошибку:

The SQL Server Driver for PHP requires the SQL Server 2008 Native Client ODBC Driver (SP1 or later) to communicate with SQL Server. That ODBC Driver is not currently installed. Access the following URL to download the SQL Server 2008 Native Client ODBC driver for x86: http://go.microsoft.com/fwlink/?LinkId=163712

Клиент стоял для MSSQL Server 2005, значит качаем и ставим для 2008
http://download.microsoft.com/download/0/E/6/0E67502A-22B4-4C47-92D3-0D223F117190/sqlncli.msi

Запускаю скрипт - ошибка:
...
[Microsoft][SQL Server Native Client 10.0][SQL Server]Login failed for user 'leon-PC\leon'
...
Клиент работает - это хорошо, авторизация не проходит ...
Вместо MyMSDb ставим имя реальной базы данных и на локальной машине подключение проходит.

Connection established.

понедельник, 4 апреля 2011 г.

C#. Visual Studio 2008 отладка dll.

Создаем проект типа Class Library (библиотека), который компилируется в dll и используется в клиентском коде.

Пример:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyClassLib
{
    public class MyClass
    {
        public int DoIt(int a, int b)
        {
            return a + b;
        }
    }
}

Вызываем Immediate Window: Alt + Ctrl + I и набираем:
MyClassLib.MyClass obj = new MyClassLib.MyClass();
obj.DoIt(10, 15);
25

Таким образом можем добавить точки останова.

Transact-SQL. Примеры.

Переменные


USE TestDatabase
-- Объявление переменных
DECLARE @EmpID INT, @EmpName VARCHAR(40)
-- Задание значения переменной @EmpID
SET @EmpID = 1
-- Задание значения переменной @EmpName
SELECT @EmpName = UserName FROM Users WHERE UserID = @EmpID
-- Вывод переменной @EmpName в результат запроса
SELECT @EmpName AS [Employee Name]
GO

-- Примечание. В этом примере используется группировка слов в переменную — конструкция [Employee Name] 
-- воспринимается как одна переменная, так как слова заключены в квадратные скобки


Системные функции


USE TestDatabase
-- Использование агрегативной функции для подсчета средней зарплаты
SELECT AVG(BaseSalary) AS [Average salary] FROM Positions
GO
-- Использование скалярной функции для получения имени базы данных
SELECT DB_NAME() AS [DATABASE name]
GO
-- Использование скалярной функции для получения имени текущего пользователя
DECLARE @MyUser CHAR(30)
SET @MyUser = USER_NAME()
SELECT 'The current user''s database username is: '+ @MyUser
GO
-- Использование функции-указателя для получения данных с другого сервера
SELECT * FROM OPENQUERY(OracleSvr, 'SELECT name, id FROM owner.titles')
GO


Выражения


USE TestDatabase
-- Использование DDL
CREATE TABLE TempUsers (UserID INT, UserName NVARCHAR(40), DepartmentID INT)
GO
-- Использование DCL
GRANT SELECT ON Users TO PUBLIC
GO
-- Использование DML
SELECT UserID, UserName + ' ' + UserSurname AS [USER FULL Name] FROM Users
GO
-- Использование DDL
DROP TABLE TempUsers
GO


Динамическое конструирование выражений

USE master
-- Задание динамических данных
DECLARE @dbname varchar(30), @tablename varchar(30)
SET @dbname = 'TestDatabase'
SET @tablename = 'Positions'
SET @column = 'BaseSalary'
-- Использование динамических данных
EXECUTE ('USE ' + @dbname + ' SELECT AVG(' + @column + ')
  AS [Average salary] FROM @tablename ' + @tablename)
GO

Выборка


В строке сравнения разрешается использовать подстановочные символы:
% - любое количество символов;
_ - один символ;
[] – любой символ, указанный в скобках;
[^] – любой символ, не указанный в скобках.
-- Выбрать все записи из таблицы Users, у кого в имени вторая буква не V
SELECT * FROM Users WHERE UserName LIKE '_[^v]%'

-- Выбрать записи колонок UserName и UserSurname из таблицы Users, у кого 
-- PositionID между 2 и 3, результирующую колонку назвать Full name.
SELECT [UserName] + ' ' + [UserSurname] AS 'Full name' FROM Users
  WHERE PositionID BETWEEN 2 AND 3

-- Сосчитать суммарную зарплату отдела с идентификатором 1
DECLARE @DepID int
SET @DepID = 1
SELECT DepartmentName AS 'Department name',
    (SELECT SUM(Positions.BaseSalary) FROM Positions
       INNER JOIN Users ON Users.PositionID = Positions.PositionID
       WHERE Users.DepartmentID = @DepID
    ) AS 'Summary salary'
  FROM Departments
  WHERE DepartmentID = @DepID

Аналог LIMIT в MySQL

SELECT TOP 10 * FROM MY_TABLE
-- аналогично
SELECT * FROM MY_TABLE LIMIT 10

среда, 30 марта 2011 г.

Python. Apache CGI.

Подключаем модули apache cgi, cgid

$ sudo a2enmod имя_модуля

В каталоге для cgi-скриптов создаем файл .htaccess

Allow from all

Options +ExecCGI
AddHandler cgi-script .py

В этом каталоге создаем cgi-скрипт hello.py

#!/usr/bin/python
print "Content-Type: text/plain\n\n"

print "Hello, cgi world!"

Будет работать, если хостинг позволяет (зависит от настроек apache).
Подробно читать тут http://httpd.apache.org/docs/2.0/howto/htaccess.html

Права на каталог должны быть не ниже 755 (права выставляем в консоли сервера с chmod), а права на файл 777

вторник, 29 марта 2011 г.

Johnny Cash - Solitary Man

Python. Работа со временем.

from datetime import datetime, timedelta
import time

# дата час назад от текущего момента
past_hour = datetime.now() + timedelta(hours = -1)

# дата неделю назад от текущего момента
past_week = datetime.now() + timedelta(weeks = -1)

# unix timestamp
timestamp =  time.mktime(past_week.timetuple())

year = 1979
month = 3
day = 31
timestamp = time.mktime((year, month, day, 0, 0, 0, -1, -1, -1))

Python. Объединение списка в строку с разделителем.

tmp = ['a', 'b', 'c']
str = ",".join(tmp)
'a,b,c'

Python. Форматирование даты (аналог date() в php)

>>> import time
>>> timestamp = 1284375159
>>> time.strftime("%m %d %Y",time.localtime(timestamp))
'09 13 2010'

Python. Работа с MySQL.

Установка модуля python в Ubuntu:

sudo apt-get install python-mysqldb

import MySQLdb

conn = MySQLdb.connect (host = "localhost",
                           user = "db_user",
                           passwd = "db_pwd",
                           db = "db_name")
cursor = conn.cursor ()
cursor.execute ("SELECT VERSION()")
row = cursor.fetchone ()
print "server version:", row[0]
cursor.close ()
conn.close ()


Если получаем ошибку вида:
...
ImportError: No module named MySQLdb
чаще всего это значит, что в системе несколько версий пайтон и скрипт использует ту для которой не установлен модуль ...

Обработка исключений:

try:
    conn = MySQLdb.connect (host = "localhost",
                             user = "testuser",
                             passwd = "testpass",
                             db = "test")
except MySQLdb.Error, e:
    print "Error %d: %s" % (e.args[0], e.args[1])
    sys.exit (1)


Выборка:

cursor.execute ("SELECT row1, row2 FROM my_table")
while (1):
    row = cursor.fetchone ()
    if row == None:
        break
    print "%s, %s" % (row[0], row[1])
print "Number of rows returned: %d" % cursor.rowcount


Вставка:

cursor.execute ("""
    INSERT INTO animal (name, category)
    VALUES
        ('snake', 'reptile'),
        ('frog', 'amphibian'),
        ('tuna', 'fish'),
        ('racoon', 'mammal')
""")

понедельник, 28 марта 2011 г.

Python. Обработка исключений (пример).

import sys
import traceback

...

try:
    resumes.append(resume.get_data())

# В методе get_data() возникает исключение
except Exception:
    registry = Registry()

    log = open(registry.get('error_log') , 'a')
    log.write("\nresume #" + resume_id + " error\n")

    # Пишем трассировку исключения в лог
    print traceback.print_exc(file = log)

    if(registry.is_debug_mode()):
        print traceback.print_exc(file = sys.stdout)

    log.close()

...


Класс Registry (упрощенный, для реальной работы не подходит)
По поводу реализации singletone в python см. http://code.activestate.com/recipes/66531/

class Registry:
    __shared_state = {}

    vars = {}

    def __init__(self):
        self.__dict__ = self.__shared_state

    def set(self, key, value):
        self.vars[key] = value

    def get(self, key):
        return self.vars[key]

    def is_debug_mode(self):
        if(self.vars['mode'] == 'debug'):
            return True
        return False

Python. Удаление дубликатов значений из списка (аналог array_unique в php).

mylist = list(set(mylist))

Python. Регулярные выражения и группировка результата.

re.findall(r"\w","abcdefg")

# Возвращает список
# ('a','b','c','d','e','f','g',)

вторник, 22 марта 2011 г.

Python. Регулярные выражения. Нежадный поиск с учетом служебных символов.

html = '<div><span>hello</span><span>goodbay</span></div>'

# (?=...) - соотв, если ... соотв тому, что идет следом, но не включает ...
# (?<=...) - соотв, если ... предшествует искомой позиции, но не включает ...
# .*? - нежадный поиск, произвольная последовательность символов
# re.DOTALL - включить в поиск служебные символы (перенос строк, пробелы и тд)

match = re.search('(?<=<span>).*?(?=</span>)', html, re.DOTALL).group(0)
print match
'hello'
Поиск в строке с кодировкой utf-8
m = re.search('some string'.decode('utf-8'), 'some string and something else'.decode('utf-8'), re.UNICODE|re.IGNORECASE)

понедельник, 21 марта 2011 г.

Python. Парсер HTML BeautifulSoup. Поиск по атрибуту CSS class.

soup.find("b", { "class" : "lime" })

Python. Сериализация объектов.

import pickle

def serialize(output, obj):
    file = open(output, 'wb')
    pickle.dump(obj, file)
    file.close()

def unserialize(output):
    file = open(output, 'rb')
    obj = pickle.load(file)
    file.close()

    return obj
obj = ['a', 'b', 'c']
output = 'dump.txt'
serialize(output, obj)

obj = unserialize(output)

Python. Работа со строками в utf-8.

Локализация системы (Ubuntu) - UTF-8. Во всех модулях указываем кодировку в начале файла:
# -*- coding: utf-8 -*- 

# Строка в кодировке windows-1251
str = ' привет '
# Кодируем в юникод
str = str.decode('windows-1251')

# strip - Удаляем начальный и завершающий пробел
# replace - Ищем и заменяем строку (u'' - строка в юникод)
# encode - кодируем в набор байт перед выводом на печать, в файл и тд
str = str.strip().replace(u'пр', '').encode('utf8')

'ивет'

воскресенье, 20 марта 2011 г.

Python. Подключение модуля из произвольного каталога.

dirFoo\
    Foo.py
    dirBar\
        Bar.py 
 
import sys
sys.path.append( <path to dirFoo> )
import Bar
 

Mac OS. Установка Python 3.2 в Tiger 10.4.11.

Качаем и устанавливаем пакет для соотв. версии Mac OS X с сайта python, в моем случае это

Python 3.2 Mac OS X 32-bit i386/PPC Installer (for Mac OS X 10.3 through 10.6)

$ which python
/usr/bin/python
$ which python3.2
/Library/Frameworks/Python.framework/Versions/3.2/bin/python3.2
$ echo $PATH
/Library/Frameworks/Python.framework/Versions/3.2/bin:/bin:/sbin:/usr/bin:/usr/sbin

Далее настраивает ide, в моем случает это Netbeans 6.8
Добавляем новый путь к Python в свойствах проекта

пятница, 18 марта 2011 г.

PHP. ucfirst и utf-8.

function ucfirst_utf8($string, $e ='utf-8') {
    if (function_exists('mb_strtoupper') && function_exists('mb_substr') && !empty($string)) {
        $string = mb_strtolower($string, $e);
        $upper = mb_strtoupper($string, $e);
        preg_match('#(.)#us', $upper, $matches);
        $string = $matches[1] . mb_substr($string, 1, mb_strlen($string, $e), $e);
    } else {
        $string = ucfirst($string);
    }
    return $string;
}

Python. Для чего нужно 'if __name__ == "__main__"' ?

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

Пример, есть два файла:

$ cat mymath.py
def square(x):
    return x * x

if __name__ == '__main__':
    print "test: square(42) ==", square(42)

$ cat mygame.py
import mymath

print "this is mygame."
print mymath.square(17)

$ python mymath.py
test: square(42) == 1764

$ python mygame.py
this is mygame.
289

четверг, 17 марта 2011 г.

MySQL. Настройка и оптимизация MySQL сервера.

В этой статье будут описаны различные настройки MySQL, преимущественно те, которые влияют на производительность. Для удобства все переменные разделены по разделам (базовые настройки, ограничения, настройки потоки, кэширование запросов, тайминги, буферы, InnoDB). Сначала уточним имена некоторых переменных, которые изменились в версии 4 MySQL, а в сети продолжают встречаться и старые и новые варианты имен, что вызывает вопросы.

Итак, в 4 версии у ряда переменных появилось окончание _size. Это касается переменной thread_cache_size и переменных из раздела Буферы. А переменная read_buffer_size до версии 4 называлась record_buffer. Также переменная skip_external_locking из раздела Базовые настройки до версии 4 называлась skip_locking.
Переменные делятся на две основных категории: переменные со значениями и переменные-флаги. Переменные со значениями записываются в конфигурационном файле в виде variable = value, а переменные-флаги просто указываются. Также вы наверное заметили, что в некоторых случаях в названиях переменных используется "-", а в некоторых "_". Переменные с дефисом являются стартовыми опциями сервера и их нельзя изменить при работе сервера (при помощи SET); переменные с подчеркиванием являются опциями работы сервера и их возможно изменять на лету. Если речь идет о «переменной состояния» или рекомендуется наблюдать за значением переменной, название которой записано в виде Variable_Name, то следует выполнять запрос SHOW STATUS LIKE "Variable_Name" для получения значения этой переменной, либо заглянуть на вкладку состояние в phpMyAdmin, где дополнительно будут комментарии по значению этой переменной.
А теперь займемся описанием переменных и их возможными значениями.

Базовые настройки


  • low-priority-updates — эта опция снижает приоритет операций INSERT/UPDATE по сравнению с SELECT. Актуально, если данные важно быстрее прочитать, чем быстрее записать.
  • skip-external-locking — опция установлена по умолчанию, начиная с версии 4. Указывает MySQL-серверу не использовать внешние блокировки при работе с базой. Внешние блокировки необходимы в ситуациях, когда несколько серверов работают с одними и теми же файлами данных, т.е. имеют одинаковую datadir, что на практике не используется.
  • skip-name-resolve — не определять доменные имена для IP-адресов подключающихся клиентов. При этом пользовательские разрешения нужно настраивать не на хосты, а на IP-адреса (за исключением localhost). Если вы соединяетесь с сервером только с локальной машины, то особого значения не имеет. Для внешних соединений ускорит установку соединения.
  • skip-networking — не использовать сеть, т.е. вообще не обрабатывать TCP/IP соединения. Общение с сервером при этом будет происходить исключительно через сокет. Рекомендуется, если у вас нет ПО, которое использует только TCP/IP для связи с сервером.

Ограничения


  • bind-address — интерфейс, который будет слушать сервер. В целях безопасности рекомендуется установить здесь 127.0.0.1, если вы не используете внешние соединения с сервером.
  • max_allowed_packet — максимальный размер данных, которые могут быть переданы за один запрос. Следует увеличить, если столкнетесь с ошибкой «Packet too large».
  • max_connections — максимальное количество параллельных соединений к серверу. Увеличьте его, если сталкиваетесь с проблемой «Too many connections».
  • max_join_size — запрещает SELECT операторы, которые предположительно будут анализировать более указанного числа строк или больше указанного числа поисков по диску. Используется для защиты от кривых запросов, которые пытаются считать миллионы строк. Значение по умолчанию более 4 миллиардов, поэтому вы скорее всего захотите его значительно уменьшить.
  • max_sort_length — указывает, сколько байт из начала полей типа BLOB или TEXT использовать при сортировке. Значение по умолчанию 1024, если вы опасаетесь некорректно спроектированных таблиц или запросов, то следует его уменьшить.

Настройки потоков


  • thread_cache_size — указывает число кэшируемых потоков. После обработки запроса сервер не будет завершать поток, а разместит его в кэше, если число потоков, находящих в кэше меньше, чем указанное значение. Значение по умолчанию 0, увеличьте его до 8 или сразу до 16. Если наблюдается рост значения переменной состояния Threads_Created, то следует еще увеличить thread_cache_size.
  • thread_concurrency — актуально только для Solaris/SunOS вопреки тому, что пишут в сети. «Подсказывает» системе сколько потоков запускать одновременно, выполняя вызов функции thr_setconcurrency. Рекомендованное значение — двойное или утроенное число ядер процессора.

Кэширование запросов


  • query_cache_limit — максимальный размер кэшируемого запроса.
  • query_cache_min_res_unit — минимальный размер хранимого в кэше блока.
  • query_cache_size — размер кэша. 0 отключает использование кэша. Для выбора оптимального значения необходимо наблюдать за переменной состояния Qcache_lowmem_prunes и добиться, чтобы ее значение увеличивалось незначительно. Также нужно помнить, что излишне большой кэш будет создавать ненужную нагрузку.
  • query_cache_type — (OFF, DEMAND, ON). OFF отключает кэширование, DEMAND – кэширование будет производиться только при наличии директивы SQL_CACHE в запросе, ON включает кэширование.
  • query_cache_wlock_invalidate — определяет будут ли данные браться из кеша, если таблица, к которым они относятся, заблокирована на чтение.

Кэш запросов можно представить себе как хэш-массив, ключами которого являются запросы, а значениями — результаты запросов. Кроме результатов, MySQL хранит в кэше список таблиц, выборка из которых закэширована. Если в любой из таблиц, выборка из которой есть в кэше, проиcходят изменения, то MySQL удаляет из кэша такие выборки. Также MySQL не кеширует запросы, результаты которых могут измениться.
При запуске MySQL выделяет блок памяти размером в query_cache_size. При выполнении запроса, как только получены первые строки результата сервер начинает кэшировать их: он выделяет в кэше блок памяти, равный query_cache_min_res_unit, записывает в него результат выборки. Если не вся выборка поместилась в блок, то сервер выделяет следующий блок и так далее. В момент начала записи MySQL не знает о размере получившейся выборки, поэтому если записанный в кэш размер выборки больше, чем query_cache_limit, то запись прекращается и занятое место освобождается, следовательно, если вы знаете наперед, что результат выборки будет большим, стоит выполнять его с директивой SQL_NO_CACHE.

Тайминги


  • interactive_timeout — время в секундах, в течение которого сервер ожидает активности со стороны интерактивного соединения (использующего флаг CLIENT_INTERACTIVE), прежде чем закрыть его.
  • log_slow_queries — указывает серверу логировать долгие («медленные») запросы (выполняющиеся дольше long_query_time). В качестве значения передается полное имя файла (например /var/log/slow_queries).
  • long_query_time — если запрос выполняется дольше указанного времени (в секундах), то он будет считаться «медленным».
  • net_read_timeout — время в секундах, в течение которого сервер будет ожидать получения данных, прежде чем соединение будет прервано. Если сервер не обслуживает клиентов с очень медленными или нестабильными каналами, то 15 секунд здесь будет достаточно.
  • net_write_timeout — время в секундах, в течение которого сервер будет ожидать получения данных, прежде чем соединение будет прервано. Если сервер не обслуживает клиентов с очень медленными или нестабильными каналами, то 15 секунд здесь будет достаточно.
  • wait_timeout — время в секундах, в течение которого сервер ожидает активности соединения, прежде чем прервет его. В общем случае 30 секунд будет достаточно.

Буферы


У всех буферов есть общая черта — если из-за установки большого размера буфера данные будут уходить в файл подкачки, то от буфера будет больше вреда, чем пользы. Поэтому всегда ориентируйтесь на доступный вам объем физической ОЗУ.
  • key_buffer_size — размер буфера, выделяемого под индексы и доступного всем потокам. Весьма важная настройка, влияющая на производительность. Значение по умолчанию 8 МБ, его однозначно стоит увеличить. Рекомендуется 15-30% от общего объема ОЗУ, однако нет смысла устанавливать больше, чем общий размер всех .MYI файлов. Наблюдайте за переменными состояния Key_reads и Key_read_requests, отношение Key_reads/Key_read_requests должно быть как можно меньше (< 0,01). Если это отношение велико, то размер буфера стоит увеличить.
  • max_heap_table_size — максимальный допустимый размер таблицы, хранящейся в памяти (типа MEMORY). Значение по умолчанию 16 МБ, если вы не используете MEMORY таблиц, то установите это значение равным tmp_table_size.
  • myisam_sort_buffer_size — размер буфера, выделяемого MyISAM для сортировки индексов при REPAIR TABLE или для создания индексов при CREATE INDEX, ALTER TABLE. Значение по умолчанию 8 МБ, его стоит увеличить вплоть до 30-40% ОЗУ. Выигрыш в производительности соответственно будет только при выполнении вышеупомянутых запросов.
  • net_buffer_length — объем памяти, выделяемый для буфера соединения и для буфера результатов на каждый поток. Буфер соединения будет указанного размера и буфер результатов будет такого же размера, т.е. на каждый поток будет выделен двойной размер net_buffer_length. Указанное значение является начальным и при необходимости буферы будут увеличиваться вплоть до max_allowed_packet. Размер по умолчанию 16 КБ. В случае ограниченной памяти или использования только небольших запросов значение можно уменьшить. В случае же постоянного использования больших запросов и достаточного объема памяти, значение стоит увеличить до предполагаемого среднего размера запроса.
  • read_buffer_size — каждый поток при последовательном сканировании таблиц выделяет указанный объем памяти для каждой таблицы. Как показывают тесты, это значение не следует особо увеличивать. Размер по умолчанию 128 КБ, попробуйте увеличить его до 256 КБ, а затем до 512 КБ и понаблюдайте за скоростью выполнения запросов типа SELECT COUNT(*) FROM table WHERE expr LIKE "a%"; на больших таблицах.
  • read_rnd_buffer_size — актуально для запросов с "ORDER BY", т.е. для запросов, результат которых должен быть отсортирован и которые обращаются к таблице, имеющей индексы. Значение по умолчанию 256 КБ, увеличьте его до 1 МБ или выше, если позволяет память. Учтите, что указанное значение памяти также выделяется на каждый поток.
  • sort_buffer_size — каждый поток, производящий операции сортировки (ORDER BY) или группировки (GROUP BY), выделяет буфер указанного размера. Значение по умолчанию 2 МБ, если вы используете указанные типы запросов и если позволяет память, то значение стоит увеличить. Большое значение переменной состояния Sort_merge_passes указывает на необходимость увеличения sort_buffer_size. Также стоит проверить скорость выполнения запросов вида SELECT * FROM table ORDER BY name DESC на больших таблицах, возможно увеличение буфера лишь замедлит работу (в некоторых тестах это так).
  • table_cache (table_open_cache с версии 5.1.3) — количество кэшированных открытых таблиц для всех потоков. Открытие файла таблицы может быть достаточно ресурсоемкой операцией, поэтому лучше держать открытые таблицы в кэше. Следует учесть, что каждая запись в этом кэше использует системный дескриптор, поэтому возможно придется увеличивать ограничения на количество дескрипторов (ulimit). Значение по умолчанию 64, его лучше всего увеличить до общего количества таблиц, если их количество в допустимых рамках. Переменная состояния Opened_tables позволяет отслеживать число таблиц, открытых в обход кэша, желательно, чтобы ее значение было как можно ниже.
  • tmp_table_size — максимальный размер памяти, выделяемой для временных таблиц, создаваемых MySQL для своих внутренних нужд. Это значение также ограничивается переменной max_heap_table_size, поэтому в итоге будет выбрано минимальное значение из max_heap_table_size и tmp_table_size, а остальные временные таблицы будут создаваться на диске. Значение по умолчанию зависит от системы, попробуйте установить его равным 32 МБ и понаблюдать за переменной состояния Created_tmp_disk_tables, ее значение должно быть как можно меньше.

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

InnoDB


  • innodb_additional_mem_pool_size — размер памяти, выделяемый InnoDB для хранения различных внутренних структур. Если InnoDB будет недостаточно этой памяти, то будет запрошена память у ОС и записано предупреждение в лог ошибок MySQL.
  • innodb_buffer_pool_size — размер памяти, выделяемый InnoDB для хранения и индексов и данных. Значение — чем больше, тем лучше. Можно увеличивать вплоть до общего размера всех InnoDB таблиц или до 80% ОЗУ, в зависимости от того, что меньше.
  • innodb_flush_log_at_trx_commit — имеет три допустимых значения: 0, 1, 2. При значении равном 0, лог сбрасывается на диск один раз в секунду, вне зависимости от происходящих транзакций. При значении равном 1, лог сбрасывается на диск при каждой транзакции. При значении равном 2, лог пишется при каждой транзакции, но не сбрасывается на диск никогда, оставляя это на совести ОС. По умолчанию используется 1, что является самой надежной настройкой, но не самой быстрой. В общем случае вы можете смело использовать 2, данные могут быть утеряны лишь в случае краха ОС и лишь за несколько секунд (зависит от настроек ОС). 0 — самый быстрый режим, но данные могут быть утеряны как при крахе ОС, так и при крахе самого сервера MySQL (впрочем данные лишь за 1-2 секунды).
  • innodb_log_buffer_size — размер буфера лога. Значение по умолчанию 1 МБ, увеличивать его стоит, если вы знаете, что будет большое количество транзакций InnoDB или если значение переменной состояния Innodb_log_waits растет. Вам вряд ли придется увеличивать его выше 8 МБ.
  • innodb_log_file_size — максимальный размер одного лог-файла. При достижении этого размера InnoDB будет создавать новый файл. Значение по умолчанию 5 МБ, увеличение размера улучшит производительность, но увеличит время восстановления данных. Установите это значение в диапазоне 32 МБ — 512 МБ в зависимости от размера сервера (оценив его субъективно).

Также для мониторинга работы сервера удобно использовать phpMyAdmin, интерес представляют вкладки Состояние и Переменные. Дополнительно phpMyAdmin дает советы по тюнингу тех или иных переменных в зависимости от параметров работы сервера.

оригинал