Saturday, December 19, 2009

pySLAM

Peter Mawhorter et al. tarafindan yazilmis "Mapping for All" adli makale Python ile SLAM kodlamasi hakkinda. Makale, robotik ogretiminde guzel, pedagojik bir yaklasim, Fastslam algoritmasinin Python ile kodlanmasi ele aliyor. Bu kodlar pySLAM olarak adlandirilmis, fakat referans verilen adresin calismadigini farkettik. Biz biraz "arkeolojik kazi" yaparak bu kodlari kurtardik, zip olarak buradan paylasiyoruz. Isletmek icin zip'i actiktan sonra slam/pySLAM/test.py programi isletilebilir. slam/pySLAM altinda farkli FastSlam kodlarini denemek icin test.py icindeki gerekli sys.path.append komutunu comment out edebiliriz. UDA harfleri 'unknown data association' kelimelerine tekabul ediyor.

English: You can try out different Fastslam implementations by commenting out the necessary sys.path.append line in test.py. This was not there in the original code, we added it during clean-up.

pySLAM Indir (Download)

Wednesday, December 16, 2009

Latex ile Prezentasyon

Powerpoint benzeri prezentasyonlari Latex uzerinden uretmek icin gerekli dosyalar. Script build.py cagrisi ornegi derlemek icin yeterli, derle.sh icine de bakilabilir.

Baglanti

Tuesday, December 15, 2009

Dinamik Resource Erisimi

Android'de referans bilgilerini bir dosya icinde tutabiliriz; bu dosyalara erismek icin onlari res/raw altinda tutuyoruz. Eger erisilecek dosya ismi dinamik bir sekilde uretiliyor ise, o zaman String tipinden bir sekilde R.java dosyasi icinde static olarak tanimli int ogelere esleme yapmamiz lazim. Bnnun icin Java Reflection kullanacagiz:
import java.lang.reflect.Field;
import java.io.InputStream;

Field id = R.raw.class.getDeclaredField([string tipinde dinamik oge ismi]);
R.raw rr = new R.raw();
int i = id.getInt(rr);
InputStream in = getResources().openRawResource(i);
...

Asagi Kaydirilabilen (Scroll) TextView

Cep telefonu uygulamizda bir TextView duz metin basabilmemizi saglar. Ekrana sigmayacak kadar buyuk metinleri gosterebilmek icin asagi dogru gitme destegi lazim. Bu destek soyle eklenir:
  public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ScrollView sv = new ScrollView(this);
TextView tv = new TextView(this);
sv.addView(tv);
..
}

Icon

Uygulamamiz icin icon kullanmak icin gelistirme dizininde res/drawable/ altinda 48x48 boyutlarinda bir PNG imaji koymamiz, ve bu imaja AndroidManifest.xml dosyasinda

<application android:label="@string/app_name" android:icon="@drawable/[dosya]">

olarak referans vermemiz yeterli.

Not: [dosya] ismi png soneki olmadanki dosya ismi olmali.

Aktiviteler Arasi Gecis

Android kodlamasinda bir ekran bir Activity objesine tekabul eder. Bir Activity'den otekine gecis su sekilde oluyor;

Intent myIntent = new Intent();
myIntent.setClassName("[paket]", "[tum paketle beraber gecis yapilan class]");
startActivity(myIntent);

Peki gecis yaparken bir yandan bilgi aktarmak istersek ne yapariz? En basit isleyecek cozum, ya kaynak Activity'ye ya da hedef Activity'ye bir "public static" oge eklemek ve gecis yapmadan once gereken veriyi bu ogeye statik olarak set etmek. Gecis sonrasi gidilen Activity ayni statik erisimi yaparak gereken bilgiyi alacaktir.

Static erisimin kullanilmasi cok kullanicili bir ortam olan Web kodlamasi icin uygun olmayabilirdi. Fakat unutmayalim, cep telefonu kodlamasinda tek kullanicili bir ortamdayiz, ve uygulamada donen her turlu islem, veri atamasi tek kullanici icin yapiliyor. Bu yuzden static kullanimin tehlikesi yok.

Sunday, December 13, 2009

Testler, Loglamak

Android ortaminda loglamak icin Log.d ve Log.e cagrilari kullaniliyor. Bu cagrilari once sarmaliyoruz ve gelistirme ortaminda TestNG altinda calismasi icin ufak bir takla atiyoruz; System objesinden islem aninda hangi isletim sistemi tip ve mimarisinde oldugumuza bakariz (bizim icin) bu Linux ve i386 ise System.out kullanilir. Artik uygulamamiz Util.Loge ve Util.Logd kullanabilir.
import android.util.Log;
public class Util {

private static String osname = System.getProperty("os.name");
private static String osarch = System.getProperty("os.arch");

public static void Loge(String s) {
if (osarch.equals("i386") && osname.equals("Linux")){
System.out.println(s);
} else {
Log.e(TAG, s);
}
}

public static void Logd(String s) {
if (osarch.equals("i386") && osname.equals("Linux")){
System.out.println(s);
} else {
Log.d(TAG, s);
}
}
}
TestNG icin gereken build.xml ekleri su dosyada. Uretilen ana build.xml dosyasindan <import file="build-add.xml"/> ile dahil edilebilir.

Android ve Statik Dosyalari Okumak

Android uygulamamiz, pek cok diger program gibi, bazi referans verilerine erismek isteyebilir. Android isletim sistemi bir sqllite adinda SQL tabani iceriyor, bu taban uzerinde db, tablolar yaratip o tablolara statik veriler yuklemek mumkun. Fakat ihtiyaclarimiz o kadar sofistike SQL erisimi gerektirmiyorsa, o zaman verileri pur dosyalar olarak cep telefonunda saklayabiliriz.

Daha onceki yazida gelistirme dizininin iskeletini yaratabildigimizi gorduk. Bu dizin ile beraber res/ adli bir dizin yaratiliyor, bu dizin altinda ./raw/[dosya] olarak yaratacagimiz her dosyaya Java kodundan su sekilde erismek mumkun.

import android.content.res.Resources;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.InputStream;

InputStream in = getResources().openRawResource(R.raw.[dosya]);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = "";
while((line=br.readLine())!=null){
 ...
}

Bu kod Activity class'indan miras alan bir class icinde olmali - getResources() oradan erisilebiliyor (ama getResources() ile alinan obje parametre olarak istenen yere set edilebilir tabii).

Ustteki ornekte res/raw/[dosya]'yi actik ve her satiri bir String icine atadik.

Uygulamamizi telefona gonderirken paketleme islemleri res/ altindaki kaynaklarin, dosyalarin paketlenip kod ile beraber gitmesini saglayacak. Yani "ant install" "ant reinstall" komutlari gerekli her seyi telefona gondermekte.

Friday, December 11, 2009

Android Gelistirme Ortami

Google'in cep telefonlari icin one surdugu Android etrafinda bayagi hareketlenme var. G1 telefonu bir suredir piyasada. Simdi de HTC Hero adli bir telefon cikti, telefon hakkindaki yorumlar iyi. Android gelistirme ortami kurmaya gelelim: Su adresi ziyaret edin.

http://developer.android.com/sdk/index.html

Isletim sisteminiz icin olani indirin (bizim icin Linux). Paketi acin, ve [DIZIN]/tools dizinine girin. Burada "android" adindaki programi calistirin. Available Packages secenegine bakin, listelenen sitenin sol ok tusuna basinca normalde indirme baslamali. Fakat bu site bizde https uzerinden baglanti problemi verdi, o yuzden Settings altinda "Force https .. " diye baslayan secenegi sectik, "Save and Apply" dugmesine basip programi kapatip tekrar baslattik. Ikinci sefer liste indirildi. Listede ne varsa secin ve "install" deyin. Is bittikten sonra UI programindan cikin ve tools dizini altinda komut satirindan

android list targets

komutunu isletin. Onceden liste bos gelecekti, simdi install ettiginiz seyleri goruyor olmaniz lazim. Artik Hello World ornegini yazabiliriz. Alttaki sayfaya bakalim:

http://developer.android.com/guide/tutorials/hello-world.html

Bir "cep telefon" hedefi yaratalim:

android create avd --target 2 --name my_avd

Eger Android grafik arayuzu uzerinden target yaratmak istiyorsak, o zaman tools/android komutu ile programi baslatiriz, "Available packages" seceneginden bir SDK seceriz ve kurariz. Sonra Settings altinda "Force https .." diye giden secenegi seceriz, ve "Virtual Devices" bolumune gideriz. Oradan artik "New" ile yeni bir avd ekleyebiliriz. Burada kullandigimiz isim ile "emulator -avd myavd" komutu isleyecektir.



Eclipse kullanicilari ustteki sayfadaki gerekli olanlari takip edebilir. Biz build.xml bazli calisiyoruz, o durumda iskelet dizin, build.xml yaratmak soyle:

android create project --package com.android.helloandroid --activity HelloAndroid --target 2 --path [GELISTIRME DIZINI]

Diger IDE'ler hakkinda daha fazla detay

http://developer.android.com/guide/developing/other-ide.html

Uretilen HelloWorld.java koduna gidip sunlari yazabilirsiniz:
package com.android.helloandroid;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText("Hello, Android");
setContentView(tv);
}
}
Simdi emulatoru baslatialm: emulator -avd my_avd

Emulator arka planda isliyor iken, gelistirme dizinine gidip

ant install

ile uygulamayi derleyip emulasyon aletine install edelim. Eger kod degistirilirse, ant reinstall ile tekrar kod gonderilebilir. Kod isleyisi hakkinda problemleri gormek icin tools altinda "adb logcat" faydali.

Bu kadar. Simdi emulator'den menuyu acip HelloAndroid uygulamasina gidin ve uzerine tiklayin. Ustteki resim gibi bir cikti gelmesi lazim.

Wednesday, December 9, 2009

Matplotlib, Pylab ve hareketli plot, animasyonlar

Bir kordinat sistemi uzerinde canli olarak bir hesabin sonucunu seyretmek istersek, Pylab icin faydali bir ornek kod altta. Kod arka arkaya 10 tane x,y degeri uretiyor, sayilar 0..1 arasi, ve eksenlerin sabit kalmasi icin set_xlim, set_ylim cagrilarini yapmak lazim.
from pylab import *
from random import *
from time import *

ion()

fig = plt.figure()
ax = fig.add_subplot(111)

for i in xrange(10):
sleep(0.5)
ax.plot([random()], [random()], 'd')
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
hold(False)
draw()

Simulatorden Deger Toplamak

Simbad adli robot simulatorunden bahsetmistik. Bu simulatorde isleyen robotun aninda (online) Sci/Numpy hesaplarini yapacak kodlarla iletisiminde SrPy tavsiye etmistik. Fakat, aslinda test amacli olarak, Jython uzerinden simulatoru bir kez isletip, olcum verilerini bir dosyada toplamak, sonra ayri anlik olmayan (offline) bir sekilde o dosya uzerinde Python hesap kodlari isletmek te olabilir. Boylece SrPy'a gerek kalmaz.

Ustte ornek bir Simbad dunyasi (kodu altta). Sol ust kosedeki robot uzerinde 12 tane sonar algilayicisi var, bu algilayicilar 0'incisi en onde olmak uzere saat yonu tersine dogru artan sekilde esit araliklarla robotun uzerine takili ve verileri her '10 sayac degerinde bir' olmak uzere okunup dosyaya yaziliyor. Ayrica her 'ileri' ve 'sola don' komutlari ayni dosyaya tek bir satir olmak uzere yazilmakta. Ekte verilen cikti dosyasinda 'Inf' degerleri goruluyor, bu sonar algilayicisinin 'sonsuz (infinity)' degerini dondurdugu anlamina geliyor, yani onunde buyuk bir bosluk var, ve algilanabilecek bir engel varsa bile, cok uzakta. Bu durum gercek dunyadaki sonar verileriyle uyusuyor aslinda, cogunlukla Inf degerleri islenmeden gecilir (discard).

Bizim makinada her saniye basina 20 sayac degeri dusuyor, ona gore kinematik hesaplari yapabilirsiniz.

Jython ile dunyayi baslatip "Run" tusuna basinca, robot dunya cevresinde tam bir tur atacak, sonra ilk asagi gidisi bir daha tekrarlayacak, bu sirada verileri toplayacak. Ornek veri dosyasi da ekte bulunabilir.

Kod, Veri

Friday, December 4, 2009

C'den Python Cagrisi

C main() fonksiyonundan Python'a iki liste parametresi gonderen ornek kod. Derlemek icin main_simple.sh komutu gerekli. gcc komutu C tarafinda opencv kullanima da hazir.

Kaynak

OpenCV 2.0

Open CV 1.1 versiyonunda bazi problemler var; en son versiyona yukseltilmesi tavsiye edilir. Kurmak icin gerekli baz paketler:
sudo apt-get install libavformat-dev libgtk2.0-dev pkg-config cmake libswscale-dev bzip2
Sonra Open CV paketi indirilir:
wget http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/2.0/OpenCV-2.0.0.tar.bz2
Paketi acip dizine girilir ve su dizinler yaratilir:
mkdir release; cd release
Ve
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_PYTHON_SUPPORT=ON ..
sudo make install
.bashrc ya da cevre degiskenlerinin set edildigi yerde su ibareler eklenmeli:
export LD_LIBRARY_PATH=/usr/local/lib/:$LD_LIBRARY_PATH
Kaynak

Thursday, December 3, 2009

Piksel Takibi, OpenCV, cvCalcOpticalFlowPyrLK, optflow

Iki imaj arasinda, birinci imajda secilen piksellerin ikinci imajda nereye gitmis oldugu, yani piksel eslestirme problemi (image registration) genelde Lukas-Kanade adli matematiksel yontem, ve OpenCV ozelinde CalcOpticalFlowPyrLK cagrisi ile cozuluyor. Alttaki ornekte arka arkaya iki imaj gosteriliyor, ve bu imajlarin ilkinde eslestirilmesini istedigimiz 3 tane pikseli biz rasgele sectik. Bu piksel noktalari sonra bir sonraki imajda buluyoruz, ve onlari da isaretleyerek gosteriyoruz.
import cv

seq = [cv.LoadImage("flow%d.png" % (i+1), 0) for i in range(2)]
crit = (cv.CV_TERMCRIT_ITER, 100, 0.1)
crit = (cv.CV_TERMCRIT_EPS, 0, 0.001)

pts = [(142,190), (139,110), (160,60)]

color = (100,100,255)

r = cv.CalcOpticalFlowPyrLK(seq[0], seq[1], None, None,
                    pts, (100,100), 0, crit, 0)
for pt in pts:
cv.Circle(seq[0], pt, 5, color, 0, cv.CV_AA, 0)
a = cv.CreateImage((400,300), 8, 1)
cv.Resize(seq[0], a, cv.CV_INTER_NN)
cv.ShowImage('First', a)
cv.WaitKey()
cv.DestroyAllWindows()

for pt in r[0]:
cv.Circle(seq[1], (int(pt[0]), int(pt[1])), 5, color, 0, cv.CV_AA, 0)
b = cv.CreateImage((400,300), 8, 1)
cv.Resize(seq[1], b, cv.CV_INTER_NN)

cv.ShowImage('Second', b)
cv.WaitKey()
cv.DestroyAllWindows()

Alternatif bir paket optflow paketi. CImg kutuphanesi kullanilarak yazilmis, once Ubuntu uzerinde apt-get ile libboost-program-options-dev kurulmasi lazim. Sonra program indirilir, ana dizinde "cmake ." isletilir, ve make komutu verilir. Simdi bin altinda cikti gorulecek. Dizin examples altina gidin ve

../bin/extractmotion --image1 complex1.png --image2 complex2.png --algorithm lucaskanade --outprefix out

isletin.

Baglanti

Sunday, November 29, 2009

cvFindChessboardCorners

Piksel bazli kamerra goruntusu kullanarak OpenCV kullanarak uzaklik hesaplari yapabilmek icin kamera hakkinda bazi detaylarin bilinmesi gerekiyor. Goruntuden uzaklik hesaplamak icin baz alinan model pinhole kamera modelidir. Yani tum goruntulerin tek bir noktaya odaklandigi turden bir yapi. Bu konu hakkinda pek cok detay var, fakat pikselden uzaklik hesaplayabilmek istiyorsak, oncelikle (bilinen) uzakliktan piksele olan izdusumu hesaplamis olmamiz lazim. Bu oranlar bir kez hesaplanip bir kenarda tutuluyor.

Bilinen yontem sudur: Bir satranc tahtasi gibi kareler iceren bir goruntuyu alip, koselerini saptiyoruz (imajdan hangi acida durursa dursun kose bulmak kolay). Simdi, bu satranc tahtasinin 'duz' oldugunu biliyoruz, karelerin 'esit' boyda oldugunu biliyoruz. O zaman bu goruntunun kamera uzerindeki her egilme bukulme sekli, bize kameranin icsel yapisi hakkinda bir seyler soyleyecektir. Iste bu hesaplari aklimizda tutarak ileride tersine cevirip uzaklik hesabi icin kullanabiliriz.

Muhakkak, bazi limitasyonlar var. Ekrandaki x, y noktasindaki bir 'uzaklik' hakkinda 'derinlik' hesabi yapmamiz imkansiz. Ama ayni noktayi birkac kez degisik acilardan goruyorsak, bu mumkun olabilir.

Surada verilen kod, bir goruntudeki satranc tahtasi seklini bulup, koselerini ayni goruntu uzerinde isaretliyor. Isletmek icin python chess.py [dosya]. Eger kare sayisi degisik ise, chessboard_dim parametresi buna gore degismeli. Dikkat: Eger boyutlar 8 x 8 ise, chessboard_dim 7, 7 olmali.

Eger etrafta ustu kareli bir esya yok ise, suradaki PDF dosyasini yazicidan tek sayfaya basip, duz bir satih uzerinde yapistirarak kamera onunde tutabilirsiniz.

Sunday, November 22, 2009

Harris, OpenCv, Python

OpenCV Python ornek kodlari icinde olan canli kamera goruntusu isleyen Harris kose detektor kodlarini sadelestirdik, ve ustune bazi isaretleyici kodlari ekledik. Python script surada bulunabilir. Ornekte en fazla 100 tane kose bulmasi icin ayarlama yapildi.


Sunday, November 15, 2009

Video Kirpmak

Bir AVI video'nun parcasini kesip cikartmak icin

mencoder -ss 00:09:00 -endpos 00:02:00 -oac copy -ovc copy kaynak.avi -o parca.avi

Ustteki komut kaynak.avi dosyasinin 9'uncu dakikasindan 2 dakikalik parca cikartip parca.avi dosyasina kaydediyor. Dikkat: Ustteki seceneklerde "endpos" ibaresinin tercumesi "bitis noktasi" olmasina ragmen komut "reklam edildigi gibi" islemiyor.

Thursday, November 12, 2009

SrPy

Java JVM icinde Python kodu isletebilen Jython, C kodlari kullanan Python kutuphaneleri ne yazik ki isletemedigi icin Scipy, Numpy gibi icinde C kodu iceren kutuphanelere erismek icin, ayri sureclerde (process) isleyen Python kodlari lazim. Bu baglanti Python -> Python iletisimi olacak; Client tarafindaki Python, Jython ile isleyecek, server tarafi ise bildigimiz komut satirindan "python" komutu ile baslattigimiz kodlar olacak. Bu kodlar her turlu C bazli kutuphaneye erisebilecek, sonucu baglanan tarafa dondurecek.

SrPy, Simple Remote Python paketi iki surec (process) arasinda uzak cagri (remote procedure call) yapilabilmesini sagliyor. Kurmak icin

http://code.google.com/p/srpy/

adresinden kodu indirin, actiktan sonra python ez_install.py ile kodlari kurabilirsiniz.

Deneme icin server.py adli bir dosyada
from pylab import *

def doit():
return normal(0,sqrt(10))
Simdi srpy kurulan dizine girerek: python srpy/srpyapp.py isletelim. Bu bir server sureci baslatacak. Soyle bir ekran geliyor:
SRPy Server - Simple Remote Python, Network Server
http://code.google.com/p/srpy/ - updates, documentation, examples and support
Starting Basic Server...
URI info:
PYRO://127.0.1.1:7766/[BIR SAYI]
Client tarafi ise suna benzer:
import sys
sys.path.append('[SRPY DIZINI]')
import srpy

pyeng=srpy.PythonEngine("[PYRO IBARESINI ICEREN URL TAMAMEN]")
pyeng.imp("sys")
pyeng.eval("sys.path.append('[SERVER.PY KODUNUN DIZINI]')")
pyeng.exe("from server import doit");
pyeng.exe("x = doit()")
print pyeng.get('x')
pyeng.exe("x = doit()")
print pyeng.get('x')
pyeng.exe("x = doit()")
print pyeng.get('x')
Ustteki kodu Jython ile islettigimizde Numpy uzerinden uretilmis bir rasgele sayinin ekrana basildigini gorecegiz.

Simbad, Sensor, Python

Simbad kodlari icinde az sayida Python ornegi var; sensor ekleyen bir ornek yoktu. Java kodlarini Jython uzerinden Python'a aktarirken biraz takla atmak gerekiyor, mesela bir class'in static metotlarini tum class'i import edip fonksiyonel cagri yaparak isletiyorsunuz.

Alttaki kod bir Robot'a 12 tane sonar sensoru ekleyerek sifirinci sensor'un degerini belli araliklarla ekrana basmanin ornegini gosteriyor.
from simbad.gui import *
from simbad.sim import *
from simbad.sim.RobotFactory import addSonarBeltSensor
from javax.vecmath import *

# a very simple robot controller
class MyRobot(Agent):
def __init__(self, vector, name):
Agent.__init__(self, vector, name)
self.sonars = addSonarBeltSensor(self, 12)
def initBehavior(self):
# nothing to do
pass

def performBehavior(self):
if self.collisionDetected():
self.setTranslationalVelocity(0)
else:
self.setTranslationalVelocity(0.2)
if self.getCounter() % 100 == 0:
print "Sonar num 0 = " + str(self.sonars.getMeasurement(0))


# description of the environment
class MyEnv(EnvironmentDescription):
def __init__(self):
# put a robot
self.add(MyRobot(Vector3d(0,0,0),"robot with python"))
# put a box
self.add(Box(Vector3d(3, 0, 0), Vector3f(1, 1, 1),self))

# launch simbad
simbad = Simbad(MyEnv(),0)

Sunday, November 8, 2009

Simbad

Robot simulatorlerinden Simbad Java bazli ve kullanimi ve kod yapisi temiz bir yazilim. Kurmak icin alttaki adimlari takip etmek lazim.

Java 3D icin https://java3d.dev.java.net/binary-builds.html dizininden j3d-1_5_2-linux-i586.bin indirin. Sonra

cd $JAVA_HOME/jre
sudo sh /dizin/yeri/j3d-1_5_2-linux-i586.bin

ftp://ftp.freedesktop.org/pub/mesa/current/ adresinden 2.4 uzeri olmasi lazim, alttan kaynaklari indirin, sonra configure, sudo make install.

http://packages.ubuntu.com/source/jaunty/libdrm adresinden ayni hareket.

http://xorg.freedesktop.org/releases/individual/proto/ 1.99 sonrasi versiyon lazim.

Ardindan komut satirindan sunlari isletin:
sudo apt-get build-dep libdrm mesa
sudo apt-get install linux-headers-`uname -r`
sudo apt-get install libxi-dev libxmu-dev x11proto-xf86vidmode-dev
sudo apt-get install git-core autoconf automake libtool
Simdi eger robot kodlamamizi Python uzerinden yapmak istiyorsak, Java JVM icinde Python isletme yetenegine sahip olan Jython kodlarini indirmemiz lazim. http://www.jython.org/Project/download.html adresinden installer programi indirelim, java -jar [installer] ile kuralim. Guzel. Artik Simbad kodlarini indirebiliriz http://simbad.sourceforge.net. Kodu actiktan sonra o dizine cd komut ile girelim ve en ust seviyeden alttaki komutu uygulayalim:

java -cp lib/simbad.jar:[JYTHON DIZINI]/jython.jar org.python.util.jython python/simple_plan.py

Sonuc olarak alttaki gibi bir ekranda robotumuzu goruyor olmamiz lazim. "Run" dugmesine tiklayarak robotun otonom olarak hareket ettigini gorebiliriz. Robotun uzerindeki olcum aletleri ayni anda degerlerini sol ust kosedeki ekranda gostermeye baslayacaktir.

Not: Jython pur Java ortaminda calistigi icin bazi Python kutuphanelerini isletemiyor. Numpy, Scipy bu kutuphanelerinden bazilari. Biz bu kutuphaneleri bir client -> server mimarisi uzerinden isletecegiz; boylece server tarafi "pur Python" olabilecek ve her tur temel Python kodu isletebilecek, client tarafi ise Simbad iliskilerini halledip agir hesaplamalar icin server'a baglanacak. Niye pur Python illa lazim? Cunku Numpy, Scipy aleminden faydali onemli kodlar var, ve bilimsel hesaplama baglaminda bu kutuphanelerde bir standardizasyona gidiyoruz, bu sebeple o kodlar kullanimda olmali. Bu konuyu ileriki yazilarda isleyebiliriz.

Wednesday, November 4, 2009

Pyrobot

Python dili kullanarak simulatorde robot kodlari isletmek icin Pyrobot adli bir paket kullanilabilir. Kurmak icin CVS kaynaklarindan indirmek en iyisi. Derleme yapmadan once alttaki paketleri apt-get ile almak lazim (oldukca buyuk bir liste evet).
sudo apt-get install swig python-numpy python-imaging python-imaging-tk
python-tk tix libjpeg62-dev libgtk2.0-dev libtool autoconf g++ util-linux
python-setuptools robot-player robot-player-dev stage
Ardindan pyrobots dizinine girip "make" isletilebilir, sorulan tum sorulara olagan deger ile (enter'e basip) cevap vermek yeterli.

Derleme sonrasi ufak bir hata (bug) manuel olarak tamir edilmeli. bin/pyrobot ve system/version.py dosyalarina girip en bastaki "-e[bosluk]" ibaresini silin. Bu kadar. Artik bin/pyrobot ile programi baslatabilirsiniz.

Suradaki flash bazli video faydali. Ilk deneme (sol ustteki dugmeler uzerinden) server icin PyrobotSimulator, dunya icin Tutorial, robot icin Pyrobot60000.py ve robot beyni icin Avoid.py uzerinden yapilabilir. Pyrobot daha cetrefil dunyalari ve robot sekillerini de paylasiyor.

Kaynak

Regresyon, Least Squares

Dogrusal / lineer regresyon, risk fonksiyonu

Baglanti

Saturday, October 17, 2009

OpenCv -> Numpy

OpenCv uzerinden okunan bir imaji Numpy ile isleyebilmek icin veriyi Numpy'in isleyebilecegi bir array tipine cevirmek gerekiyor. Bu ceviriyi yapmak icin gereken kod OPENCV/interfaces/swig/python dizini altindaki adaptors.py kodu icinde. Once, eger yapmadiysaniz, tum bu dizini "make; sudo make install" ile derleyip kurmak lazim. Adaptor kodunu soyle kullaniyoruz
from opencv import adaptors

def dotrack(img):
..
numpy_arr = adaptors.Ipl2NumPy(img)
Geri gelen numpy_arr uc boyutlu bir vektor. X ve Y kordinatlar ve bu indislerin kullanimiyla gelen 3 elemanli "ufak array" icinde ise sirasiyla R, G, B degerleri olacak, yani kirmizi (red), yesil (green) ve mavi (blue) renklerinin degerleri olacak. Bu array uzerinde degisim yapilirsa geri OpenCv imajina cevirmek icin NumPy2Ipl cagrisi kullanilabilir. Array boyutlarina print len(numpy_arr..) ile bakabilirsiniz, erisim normal array erisimi, numpy_arr[100][100][0] kullanimi 100x100 kordinatindaki kirmizi degeri verecek mesela. Kamera goruntusu indislere [y][x][renk] olarak yansiyor.

Friday, October 16, 2009

OpenCV ile Piksel Boyamak

Obje takibi icin bazi objenin saptindigi pikselleri farkli bir renkle boyamak gerekecek. Bunun icin yesil renk kullanilabilir, ve OpenCv kutuphanesinde cvSet2D fonksiyonu renk set etmek icin kullanilabilir. Kod organizasyonu acisindan ise OpenCv baslatan, kameraya baglanan, dongu icinde imaj alip ekrana basan kodlari kodun ic mantigindan ayirmak mantikli. track.py ve dotrack.py dosyalarinda bu yapiyi gorebilirsiniz. Fonksiyon dotrack() icinde 10x10 boyutlarinda 100 tane pikseli yesile boyuyoruz.
def dotrack(img):
color = CV_RGB(0, 255, 0)
for i in xrange(10):
for j in xrange(10):
cvSet2D(img, 100+i, 100+j, color)
return img

Tuesday, October 6, 2009

Stephen Marsland - Yapay Ogrenim Kitabi

Stephen Marsland'in yapay ogrenim kitabini tavsiye ediyoruz. Kitabin iyi taraflari yapay ogrenimde son zamanlarda sikca gorulen simulasyon, ornekleme vurgusunu kitapta yansitmasi, ayrica tum orneklerin Python uzerinden verilmesi. Hem ogrenim hem gercek uygulamalarda bilimsel hesaplama icin Matlab'den Python'a bir gecis var - Matlab'in ticari bir urun olmasi ve dilinin Python kadar genel kullanimda olan bir dil olmamasi bu gecisi tetikleyen ana sebeplerden. Kitabin sitesi surada, tum Python ornek kodlari oradan indirilebilir.

Saturday, September 26, 2009

OpenCV Python, Baz Kod, Canny

Webcam'e sahip bir Ubuntu bazli bir bilgisayarda gercek zamanli (real-time) goruntu islemek icin OpenCV kurulumundan bahsettik. En az gereken test kodu surada bulabilirsiniz. En basit goruntu isleme orneklerinden objelerin sinirlarini gosterip geri kalan her seyi siyahlastirmak, yani Canny islemi icin gereken kod ise suradadir.

Thursday, September 10, 2009

Pocketbudda.com

Simdiye kadar yazilan pek cok Seam, JBoss, EC2, anahtar/deger tabanlari, mimariler hakkindaki yazilarimiz ustunde calistigimiz bir projeden ortaya cikan yazilardi. Proje tamamlandi, ilk hali su anda kullanima acik.

http://pocketbudda.appspot.com.

Herkes davetlidir.

Wednesday, September 9, 2009

Enum, Seam ve Map Kullanimi

Enum degerleri Seam sayfalarina donduruldugunde bu degerlerin String'e otomatik olarak cevrildigini soylemistik. Peki ters yonde gidersek ne olur? Mesela elimizde, anahtari "enum tipi olan" bir HashMap var ve bu enum tiplerinden birinin String karsiligini anahtar olarak kullanarak bir degere ulasmaya ugrasiyoruz.

Bu kullanim ne yazik ki biraz takla atmadan islemiyor. Seam forumlarinda biraz gezindik ve en temiz cozumun enum tipleri iceren HashMap istendiginde o anda (on the fly) onun kopyasi ama anahtari String bazli bir alternatif HashMap olusturmak ve xhtml sayfalara bunu dondurmek olduguna karar verdik. Anahtar String olunca xhtml duzgun calisacak, Java servis kodu tarafinda guclu tip bazli Enum kullanabilecegiz, sayfa tarafinda String kullanarak istedigimiz veriye erisebilecegiz. Guzel. Ornek, diyelim ki
enum Permission {NORMAL, ADMIN}

private Map<Permission, Boolean> permissions = new HashMap<Permission, Boolean>();

public Map<Permission, Boolean> getPermissions() ...

public void setPermission(Map<Permission, Boolean> arg) ...

public Map<String, Boolean> getStringPermissions() {
Map<String, Boolean> map = new HashMap<String, Boolean>();
for (Permission p : permissions.keySet()) {
map.put(p.toString(), permissions.get(p));
}
return map;
}
Sayfa tarafinda artik #{obj.stringPermissions['ADMIN']} gibi bir kullanim mumkun olacaktir.

Burada odenen ek bedel gecici olarak olusturulan yeni Map objesi, ve o objenin doldurulmasidir. Tabii bu cozum cok buyuk Map objeleri icin iyi olmaz; fakat ustteki "izinler listesi" kullanimi cogunlukla birkac tane obje icerir, performans problemi cikartmaz.

Sunday, September 6, 2009

Git ve Branch Kavrami

Bazen koda deney amacli bazi uzatmalar eklemek, iyilestirmeler gerekebiliyor, ve/fakat bu kodlama eklerinin uzun zaman almasi da mumkun, ayrica bu ek kodlar ozelliklerin ana koluna hemen de lazim olmayabiliyor. O zaman bu "paralel" gelisme kendine has bir ritmde, "en gerekli" gelistirme safhasindan kismen ayri bir sekilde ilerleyebilir.

Bu en son Schemafree'ye zlib sıkıstırma (compression) destegi eklerken basimiza geldi. Bir gunluk bir calisma sonrasi hala yapilacak is vardi, bu calismayi kaybetmek istemedik, kodlari commit etmek istiyorduk, ama bu ek kodlar uygulama ana kodlari icin kritik degildi, SF ana kodunu simdilik degistirmemek istiyorduk. Iste branch kavrami tam bu noktada ise yariyor.

O ana kadar ekledigimiz tum dosyalari (daha hicbir git komutu kullanmadan eklemek tabii, sadece dosya sistemi bazli eklemekten bahsediyoruz) yeni bir branch'e yazmak istiyorsak, hemen o anda bir

git checkout -b [BRANCH ISMI]

komutu uygulariz. Bu noktada artik o belirttigimiz isimdeki branch uzerindeyiz. Daha once "master" adli bir branch'te idik, bu Git'in siz hicbir branch belirtmezseniz olagan olarak kullandigi branch ismidir (evet, master'in kendisi de bir branch'tir). Yeni branch yarattiktan sonra yapilan her turlu commit islemi bizi bu yeni branch ismi uzerinde tutacaktir. Eger master branch'e geri donmek istersek

git checkout master

komutu yeterli. Uzaktaki bir Git deposuna yeni branch'i gondermek icin

git push ssh://[isim]@[makina]/bir/dizin/proje [BRANCH ISMI]

gibi bir komut lazim. Eger push sirasinda branch ismi belirtmezsek olagan deger olan master kullanilir.

Simdi biraz daha derinlere inelim (gerci branch kavramini kullanmak icin takip edecek bilgilere gerek yok); Su onemli bir nokta, Git uzerinde yapilan her commit, nerede olursak olalalim, o anda depodaki tum kodu temsil eden tekil (unique) bir SHA1 hash kimligi uretilmesini saglar; git log komutunu kullaninca bu kimlikleri goruyorsunuz. Yani herhangi bir branch'te commit noktalarinin kimliklendirilme mekanizmasi aynidir.

O zaman branch isimleri nedir? Bu isimler aslinda surekli hareket eden "isaretlerden" ibaret. Mesela "master" isminin isaret ettigi SHA1 kimligi aslinda surekli degisiyor, her commit komutu uyguladiginizda "kayiyor". Her zaman en son noktayi gostermek icin bu yapiliyor. Aslinda sadece SHA1 kimliklerini kullanarak ta git ile calisabilirdiniz, ama bu rahat olmazdi. git checkout -b, o zaman, aslinda yeni bir isaret yaratmaktan baska bir sey yapmiyor.

Ilginctir: Eger istersek, git log'da gorulen listedeki herhangi bir noktaya SHA1 kimligi kullanip "zamanda geriye giderek" donebilir, ve o noktadan baslayarak yeni commit'ler yapmaya baslayabilirdik. Sadece bu bile bizi degisik bir branch yonunde hareket ettirmeye baslardi.. Git, hangi SHA1'den gelip hangisine gittigini surekli kontrol eder, ve bu "oncesi / sonrasi" zinciri, bir branch olusturmak yeterlidir. VE sonradan, istersek, bu branch'e git checkout -b ile bir isim koyabiliriz, ve o andan itibaren, artik o ismi kullanarak o yeni branch'in, SHA1 degisim zincirinin "sonuna" da otomatik olarak gidebilmeye baslariz.

Wednesday, September 2, 2009

Link Verilebilen Uygulamalar

Internet siteleri hakkinda verilen bir tavsiye onlari 'linklenebilir' hale getirmektir, yani site icerigi dinamik bir sekilde (veri tabanindaki veriye dayanarak) uretiliyor olsa bile, bir baglantinin belli bir icerige direk erisebilmesinin saglanmasidir. Bir diger tarif "konum bilgisinin servis tarafinda degil, baglanan tarafinda tutulmasi" diye gider. Ornek su: Bir forum icerisinde hosunuza giden bir yorum gordunuz ve bu yorumu direk bir linki kopyala/yapistir yaparak bir arkadasiniza email uzerinden gondermek istiyorsunuz. Baglanti site.com/yorum?id=323423 gibi olabilir. Iste bu uygulama linklenebilir bir uygulamadir. Insanlar yeni yorum, yorum listele fonksiyonlarini kullaniyor olsalar bile, ozgun (unique) bir baglanti onu takip edeni bir yoruma direk goturebilir.

Bu isi Seam ile nasil beceririz? Seam linkleme kavramina direk destek sagliyor. Diyelim ki view.xhtml sayfasi ile bir yorum gosteriyoruz. Bu sayfayi linklenebilir hale getirmek icin CommentsHandler class'imizda bir get/set ikilisi eklememiz lazim. ID selectedCommentId olsun mesela. Bu ID ile bir yorumun yuklenmesi load() metodunda olsun. Simdi pages.xml dosyasinda
 <page view-id="/view.xhtml" ... >
<param name="commentId" value="#{commentsHandler.selectedCommentId}"/>
<action execute="#{commentsHandler.load}"/>
</page>
tanimi yapalim. Boylece bir yoruma, view.xhtml sayfasina nasil gelirsek gelelim, URL'e baktigimizda commentId=.... seklinde kimligin artik URL'in parcasi haline geldigini gorecegiz. Seam otomatik olarak selectedCommentId degiskeninin URL uzerindeki commentId degerine eslenmesini idare edecektir. Bu idare iki yonludur, iki degerden biri degisirse bu degisi otekine otomatik olarak yansitilir. Daha sonra action execute ile belirttigimiz metot cagirilacaktir ve bu metot biraz once selectedCommentId'ye eslenmis bilgiyi kullanarak veri tabanina baglanarak gerekli objeyi oradan alabilir.

Tuesday, September 1, 2009

Genel Hata Ekrani

Servis tarafinda bir hata ortaya cikinca, yani Java tarafindan Exception atilinca, ya da kullanici tarayiciya anlamsiz (sitemizde olmayan) bir sayfa ismi girdiginde sitenin gorselligini bozmayan uygun bir hata ekrani gostermek gerekir. Olagan haliyle bu ekranlar gorsel olarak uygunsuz ekranlardir. Uygun bir sayfa cogunlukla tepe logosu, renkleri uygulamanizin olan sadece ici bos bir ekranda tek bir hata mesaji iceren bir sayfadir.

Bunu elde etmek icin iki yerde degisiklik lazim. Birincisi olmayan sayfa isimlerine, yani pur 404 hatalarina ekran gostermek icin Apache tarafinda.

/etc/apache2/sites-available/default dosyasina girelim ve <VirtualHost> etiketi kapanmadan once
ErrorDocument 404 /error.seam
ibaresini ekleyelim. Sayfa error.xhtml, ustte bahsettigimiz gibi logosu yerinde, guzel ve bos bir ekrani tanimlayacak. Bu sayfa tabii ki /var/www altinda mevcut olmali. Tamam. Artik Apache tekrar baslatilinca 404 hatalari icin bu sayfa gosterilecek.

Seam tarafinda ise, eger hic kimsenin caresine bakmadigi, tutmadigi (handle) Exception'lar JVM'de en ust seviyesine cikmis ise, bu hatayi guzel ekrana yonlendirmek icin WEB-INF/pages.xml icinde
  <exception>
<end-conversation/>
<redirect view-id="/error.xhtml">
<message>Unexpected failure</message>
</redirect>
</exception>
Bu kadar. pages.xml icinde aslinda daha detayli tip bazinda Exception yakalayip kullaniciyi daha ozel sayfalara yonlendirmek mumkun; ust gosterdigimiz eger o diger tum yakalayicilar bir sey yapamamissa devreye girecek olan "genel yakaliyici (catch-all)" tanimidir. Hic planda olmayan hatalar icin gereklidir.

Saturday, August 29, 2009

JBoss'a Ne Kadar Bellek Ayirmak Lazim?

EC2 makinamizi baslattik, ve JBoss app server'i kosturmak istiyoruz. JBoss'a ne kadar hafiza ayirmak lazim?

Komut satirina gidelim ve tum servis programlarini durduralim. Ne varsa. MySql, Apache, JBoss; makina ilk acildigi, kuruldugu anki gibi olmali. Bu durumdaki makinada "free -m" komutunu isletelim. Geriye gelen "used" yani makina hicbir sey yapmazken kullanilan bellek miktarini ikiyle carpalim. Sonra bu sayiyi "free" sayisindan cikartalim. Geri kalan JBoss'a ayirilabilecek hafiza miktaridir.

Bu hesabin mantigi nerede? Oncelikle makina hicbir sey yapmazken kullanilan hafizaya bakiyoruz, bu hafiza inaktif haldeyken bile gereken miktar, demek ki "en az" bu kadar gerekiyor. Sonra, ikiyle carparak makina kullanim halindeyken isletim sisteminin biraz daha fazla hafizaya ihtiyac duyabilecegini varsayiyoruz. Eh bundan arta kalan artik JBoss'a verilebilir.

Nasil verilecek? JBOSS/bin/run.conf icinde JAVA_OPTS icin -Xms[EN AZ]m ve -Xmx[EN FAZLA]m tanimlarini yaparak. Burada bir tavsiye; ustteki aritmetikten elimize gecen sayiyi hem en az, hem en fazla icine set edelim. JBoss baslar baslamaz eldeki tum hafizaya alsin yani, boylece hafizayi "arttirmaya" ugrasmakla vakit kaybetmesin.

Kaynak

Wednesday, August 26, 2009

Cookie, ab ve Yuk Testleri

Apache ab ile bir kullaniciyi taklit etmek icin URL uzerinden bilgi gonderilebilecegi gibi cookie uzerinden de uygulamaya bilgi gonderebilir.
ab -kc 1 -n 1 -C [COOKIE ISMI]=[COOKIE DEGERI] http://www.site.com/sayfa.seam
Cogu Web uygulamasi kullanici kimligini bir cookie uzerinde tutarak, bu cookie servis tarafina gelince kullaniciyi otomatik olarak sisteme giris yaptirir. Bu kavrami test amacli olarak kullanamaz miyiz? Hatta yuk testleri icin, pek cok kullaniciyi taklit etmek icin diyelim ki bir girdi text dosyasi icinde kimlik degerlerini tutuyoruz (kimlikleri uygulamanin veri tabanindan cikarttik) ve bir Python script bu idleri oradan okuyup, id sayisi kadar Thread baslatip (cunku kullanicilarin sisteme eszamanli girmesini simule ediyoruz) kullanici basina bir sayga istegini N kadar arka arkaya isletebilir.

Script cookied_page_load.py suna benzer:
import threading, re, os, sys

times = int(sys.argv[1])

class Caller(threading.Thread):
def __init__(self, userId):
threading.Thread.__init__(self)
self.userId = userId
def run(self):
url = "http://www.site.com/sayfa.seam"
cmd = "ab -kc 1 -n " + str(times) + " -C userId=" + self.userId + " " + url
print cmd
os.system(cmd)

ts = []
f = open ("[ID DOSYASI]")
for id in f.readlines():
id = id.replace("\n","")
a = Caller(id)
a.start()
ts.append(a)

for t in ts:
t.join()

Bu script
python cookied_page_load.py 10
ile [ID DOSYASI] icinde buldugu kimlikleri userId adli Cookie'ye koyup sistemin belirttigimiz bir sayfasina kullanici basina 10 kere girmeye calisacaktir.

HProf

"Fakir adamin Profiler araci" Java kutuphanesinin icinden cikan HProf araci. Bu arac cok sukseli bir cikti vermiyor fakat ciddi problemleri ilk bastan gormek, saptamak icin kullanilabilir. Kurumsal Java kitabinda bu aractan bahsetmistik. Profiler'i kullanmak icin bir uygulamayi o aracin kontrolunde baslatmak lazim; sonra uygulama bitince (CTRL-C, kill -9 ile durdurulunca) size java.hprof.txt adli bir dosya uretiliyor. Bu dosya icinde uygulamamizin kullanimi ile alakali bir suru istatistik mevcut.

Kullanmak icin JBoss bin/run.sh dosyasini bin/run_with_hprof.sh diye kopyalayalim. Sonra satir #60'a gidip JAVA_OPTS diyen satiri
JAVA_OPTS="-agentlib:hprof=cpu=samples,depth=7 ... "
olarak diye degistirelim. Bu sekilde JBoss'u run_with_hprof.sh script'i ile baslatinca, kullanildigi anda profile edilen bir uygulamamiz olacak. Secenekler ne diyor? CPU kullanimina bak, sadece orneklem yaparak olc (her seyi olcme) ve metot cagrilari zincirini 7 seviye derine gidecek sekilde kayitla. Rapor dosyasi uretilince en altta uygulamamizin en coktan aza dogru sayida, yuzdede cagrilan metotlarinin listesini goreceksiniz. En cok cagrilanlar performans iyilestirmesi icin bir aday olabilir elbette.

Yuk yaratmak icin ise, daha once Selenium ve Python temelli bir aractan bahsettik. Cok basit yuk ihtiyaclari icin Apache ab adli arac kullanilabilir. Diyelim ki uygulamamiz URL uzerinden parametre kabul edebiliyor, bu durumda bu parametreleri /tmp/params adli bir dosyaya yazariz, "anahtar1=deger1&anahtar2=deger2" gibi.. Bu parametreleri ab ile uygulamaya gondermek icin
ab -kc [KAC PARALEL] -n [KAC TANE] -p /tmp/params -T application/x-www-form-urlencoded 
http://www.bizimsite.com/sayfa.seam
Ustteki komut [KAC PARALEL] tane sanal kullanici (thread) yaratacak, ve bu kullanicilari [KAC TANE] kadar en sonda verilen URL adresine saldirtacak. Bu sekilde uygulamamiz uzerinde iyi bir yuk yaratabiliriz. java.hprof.txt dosyasinda ise text editorumuz ile kendi uygulamamizin Java paket ismini arariz, en alttaki metot listesine bakariz, problem noktalarini saptamaya calisiriz.

Sunday, August 23, 2009

Yourkit Java Profiler

Kurumsal Java kitabi icin 2006 senesinde profiler araclarini incelemistik. O zamandan beri piyasa pek degismemis; halen Profiler piyasasi open source baglaminda genis secenekler sunmuyor. Eger para verilecek bir alan varsa, Profiler bunu verecek yegane yerlerden biri herhalde. Bizim sahsi kullanimimiz birkac gunun otesine gecmiyor, o sebeple ticari bir urunu deneme lisansi altinda alarak para vermeden kullaniyoruz. Daha uzun sureli ve sirket temelli kullanimlar icin durum daha degisik olabilir.

Halen Profiler'lar arasinda en iyi urun Yourkit Java Profiler. Kurulumu en son versiyonunda daha da basitlesmis. Indirip unzip ettikten sonra dizine girip lib altina bakin, ve

java -jar yjp.jar -integrate

komutunu isletin. Bu komut bir menu getiriyor, YJP'yi entegre edecek app server listesi secenek olarak sunuluyor. Biz 2) sectik, yani JBoss 2.x/3.x/4.x. Daha sonra JBoss'un kullandigi run.sh dosyasinin yeri size soruluyor, bu dosyanin tam dizinli yerini veriyoruz, ve diger sorulara olagan (default) degerleri giriyoruz. Sonuc olarak bu entegrasyon programi JBoss bin dizini altinda bir run_with_yjp.sh dosyasi yaratiyor. Bu script'in ne yaptigi bariz; program JBoss'u YJP kontrolu altinda baslatiyor ve boylece Profiler GUI ile bu JVM'e baglanip bilgi toplayabilmeye basliyoruz. Her turlu cetrefil PATH ayari vs otomatik olarak bu script icinde yapilmis. Bizim ek secenekler sokusturmamiza gerek yok. Ayrica normal run.sh script'i temiz birakilmis, o hala normal ihtiyaclar icin kullanilabilir.

GUI malum, YJP kontrolundeki herhangi bir JVM belli bir port uzerinden bilgi paylasir (olagan deger 10000); Eger JBoss'u sonuc ortamindaki bir makinada ise, bu makinaya her port acik olmayabilir, o zaman SSH tunelleme gerekir. Makinaya

ssh -L10000:localhost:10000 kullanici@makina

ile baglanirsak, artik "bizim makinamizadaki" 10000 port degeri uzaktaki makinaya tunellenir, ve sonuc ortamini bu sekilde profillememiz mumkun olur. JBoss YJP ile baslatilinca, YJP/bin altindaki yjp.sh ile GUI baslatilir ve gerekli servise baglanip bilgi toplanmaya baslanabilir.

Saturday, August 22, 2009

JBoss'u Zayiflatmak

JBoss server dizini altinda belli "kurulus tipleri" oldugunu biliyoruz. Bunlar minimal, default gibi kurulus duzenleridir; run.sh -c minimal diyerek mesela JBoss'u minimal haliyle, o dizin altindaki tanimlari kullanarak baslatabiliriz. Biz default ayarlarini kullaniyoruz; fakat bu dizin altinda hala isimize yaramayan, fazla bazi ekler var. Bu yazida bu gereksiz ekleri cikartarak JBoss'u "zayiflatma (slimming)" teknigini gorecegiz.

Bundan once kullanim amacimizi ortaya koyalim: Hedefimiz JBoss'un sadece Web sayfalarini dinamik olarak ureten, veri erisimini Schemafree (ya da diger bir anahtar/deger paketini -demek istedigimiz kap servislerini kullanmadan-) yapan bir Seam uygulamasini barindirmasidir. Bu kadar. Seam arka planda local EJB kullanir, onlar da bir sekilde dahil olacak. Bu durumda ise yaramayanlar JMS, takvimleme (scheduling) gibi ekler.. Bu, uygulamaniz JMS'e hic ihtiyac duymayacak anlamina gelmez; sadece standart tipik bir Web JBoss'u hazirlamak icin (ki bizim ihtiyacimiz buydu) gerekenlere isaret ediyoruz.

Alttaki Python script bir default kurulusu alip, gereksiz bilesenleri otomatik olarak siliyor ve onu inceltiyor. Kullandigimiz JBoss versiyonu 4.2.2 GA. Kaynak bolumundeki yazida silinecekler listesi vardi, orada bazi degisiklikler yapmak gerekti; yani alttaki script en guncel zayiflatma script'i su anda.
import os

a = '''
/server/default/deploy/jms
/server/default/deploy/jmx-console.war
/server/default/deploy/snmp-adaptor.sar
/server/default/deploy/management
/server/default/deploy/mail-service.xml
/server/default/deploy/monitoring-service.xml
/server/default/deploy/schedule-manager-service.xml
/server/default/deploy/scheduler-service.xml
/server/default/deploy/hibernate-deployer-service.xml
/server/default/deploy/http-invoker.sar
'''

JB = "[JBOSS DIZININIZ]"

for token in a.split():
f = JB + token
os.system("rm -rf " + f)
Kaynak

Java Enum Tipleri

Enum tipleri program baslamadan belli sayida olan ve bir sabit "kod" ile eslenmesi programlama acisindan rahat olacak degerleri listesini temsil etmek icin kullanilir. Atanan kodlarin "tip guvenlikli" olmasi guclu tipleme iceren dillerin ikili muhasebesini / kontrolunu devreye sokabilmis olur. Yanlislikla bir String tipini sabitiniz ile esleyemezsiniz, tipler uymaz, derleyici hata verir. Bu kontrol iyidir.

Bir Web ortaminda bu yapilardan ek olarak beklediklerimiz programciya bir sekilde "hepsini gezme" ozelligi saglamasi, bir sayi degeri olan "sirasini" verebilmesidir. Birinci ozellik bize kullaniciya bir listeden onceden tanimli bazi secenekleri sectirme baglaminda lazim oldu, ikinci ise, rasgele olarak bir listeden belli bir "sey" secmek gerektiginde gundeme geldi. Rasgele sayi dogal olarak bir numaradir ve bunu onceden tanimli listemiz ile bir sekilde ilintilendirmemiz gerekiyordu.

Java Enum tipleri burada yardimci olabilir. Bizim kullandigimiz kalip (pattern) suna benziyor.
public static enum EnumType {
A("Bu bir A"), B("Bu bir B");
private String name;
EnumType(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getOrdinal() {
return ordinal();
}
}
Artik A, B birer "tip" olarak tanimlanmistir. Soyle bir kullanim mumkundur.
EnumType a = EnumType.A;

log.debug("a.getName()=" + a.getName());
log.debug("a.getOrdinal()=" + a.getOrdinal());
Tum listeyi gezmek icin
for (EnumType t : EnumType.values()) {
log.debug("t.getName()=" + t.getName());
}
Ustteki liste rahatlikla Seam uzerinden @Out ile de-enjekte edilebilir ve kullaniciya icinden sebebilecegi bir secenek sunulabilir. Son bir nokta; Enum tiplerini Seam tarafinda == isareti ile esitlik testing tutmak gerekirsa, o zaman tiplerin String karsiligi kullanilmali, mesela yukaridaki ornekte kullanim .. == 'A' olacaktir.

Tuesday, August 18, 2009

S3 ve Yedeklemek

Bir EC2 makinasi kapandiginda bir imaja yakilmamis her verisini kaybeder. O zaman bir MySql tabanini EC2 uzerinde isletiyorsak, dinamik olarak surekli guncellenen verisini kaybetmemenin bir yolunu bulmamiz lazim. S3 servisi buyuk dosyalarinizi Amazon sistemi icinde depolamanizi sagliyor. O zaman EC2 makinasindan rutin olarak (cron uzerinden mesela) MySql'in yedegini alip, bu yedegi S3'e gondermek bir cozum olabilir.

S3'e script ortamindan erisebilmek icin Ubuntu EC2 makinanizda

sudo apt-get install s3cmd

komutunu isletin. Bu komut s3cmd adli bir yardimci programi kuracak. Bu programi sc3cmd --configure ile isletin; sorulan sorular EC2 acik ve gizli anahtarlariniz. Bu anahtarlar girildikten sonra s3cmd onlari hep hatirlayacak ve bundan sonra isletilen tum s3cmd komutlari o anahtarlar uzerinden gerceklestirilecek, yani tum islemler ayni hesabin isaret ettigi kullanici uzerinden yapilacak. Bu kullanicinin kullanmasi icin yeni bir dizin yaratmak;

s3cmd mb s3://[BUCKET ISMI]

Herhangi bir dosyayi oraya kopyalamak icin

s3cmd put /tmp/test s3://[BUCKET ISMI]

[BUCKET ISMI] isminin "global" bir isim oldugunu belirtmistik, yani yeterince tekil olan bir isim secelim.

Bu kadar; artik

mysqldump -u root --quick [DB] | gzip > /vs/vs/db-backup.gz

gibi bir komutla rutin olarak yaratilan yedek dosyasini (db-backup.gz yani) s3cmd ile S3 hesabimiza gonderebiliriz.

Kaynak

Sunday, August 16, 2009

Mysql Sorgu Onbellegi (Query Cache)

MySql birbirinin aynisi olan, ardi ardina yapilan sorgulari onbellege alip tekrar servis etme yetenegine sahiptir. Ubuntu Server uzerinden kurulacak mysql-server paketinde (versiyon 5) bu ozellik otomatik olarak aktif durumdadir. Kontrol etmek icin bir mysql komut satirindan
mysql> show status like 'qc%';
isletmek, sorgu onbelleginin nasil kullanildigini gosterecektir. Eger test ettiginiz islem sonrasi (web sayfalarindan hemen test edilebilir) Qcache_hits sayisi artiyorsa, o zaman onbellek devrede demektir.

Hibernate kullananlar icin bir not: Eger PreparedStatement kullanimi devrede ise (ki paketten ciktigi haliyle Hibernate'de bu aktif) o zaman MySql sorgu onbellegi islemiyor. Kullanabilmek icin "useServerPrepStmts=false" ibaresini jdbc url olustururken url icinde Hibernate'e vermek gerekiyor. Schemafree bu ayari artik otomatik olarak yapiyor.

Aslinda biz SF icinde zaten memcached ile tekil objeleri onbellege aliyorduk. O zaman MySql cozumu gereksiz olmaz mi? Soyle soyleyelim: IdentiferCollection, yani bir obje listesi dondurdugumuz zamanlarda memcached kullanamiyorduk, cunku bir listenin onbellekte olan baska bir tekil objeyi, birden fazla kez, icerme olasiligi mevcuttur, ve tekil obje degisirse listedeki obje(ler) eskimis olacaktir - bu tur uyumsuzluklar veri dogrulugu mekanizmasini zedeler, bu yuzden listelerde onbellek kullanimi mumkun degildi.. Fakat bu noktada pur MySql mekanizmalarini kullanmak hala mumkun (veri butunlugunu tabanin kendisinden kim daha iyi idare edebilir?) iste sorgu onbellegi burada devreye giriyor.

Kaynak

EC2 Elastik Ip Adresi

Amazon EC2 "elastik IP adresi" diye bir servis sunuyor. Aslinda bu servisle elde ettiginiz bir "statik IP" (yani servisin sundugu kabiliyetin tam yaptigi sey elastik kelimesi ile bir tezat olusturuyor olabilir) ama bu adres makinadan makinaya esnek bir sekilde "baglanabildigi (associate)" icin elastik bir kullanim sunmakta.. Sonuc olarak tek bir IP adresini istediginiz kadar elinizde tutabiliyorsunuz, ve bu adresi istediginiz EC2 makinasina baglayabiliyorsunuz. Baglantinin etki etmesi saniyeler aliyor; ve arkasindan hic degismeyen IP adresiniz yeni makinaya baglanabilmeye basliyor. EC2 ortaminda makinalarin (instance) ne kadar rahat acilip, kapatilabilecegini bildigimize gore, boyle bir ortamda elastik IP adresinin cok faydali bir servis olacagi acik. Teorik olarak eski siteniz islemeye devam ederken, yeni bir EC2 kumesnde yeni kodunuzu, yapinizi test edebilirsiniz, ve tatmin olunca, ana adresi, elastik IP adresini yeni makinaniza degistirdiginiz anda sitenizin trafigi hemen yeni makinalara akmaya baslayacaktir.

Elastik IP adresleri bir makinaya bagli oldugu zaman ucret odenmiyor, fakat rezerv edilmis ama "baglanmamis" halde ise Amazon sizden bir ucret kesiyor. Bunun sebebi Internet'te IP adreslerinin kisitli bir kaynak (precious resource) olmasidir; bu sebeple Amazon eger bir IP adresini rezerve ettiyseniz onu kullanmanizi istiyor. Bu sayede bir adresi "kapip" onu hic kullanmayan kisilerin tesvik edilmesi engelleniyor.

Adres nasil alinir? Cok basit:
ec2-allocate-address
Bu komut bir IP adresi geri dondurecektir ve bu adres iptal etmediginiz surece artik sizin EC2 hesabiniza bagli olacaktir. Adresi bir EC2 makinasina baglamak icin
ec2-associate-address -i [MAKINA ISMI] [IP]
komut yeterli. [MAKINA ISMI] ec2-describe-instances komutundan gelen listede "i-" ile baslayan makina ismi olacak, [IP] reserve edilmis olan IP adresiniz. Makina dogal olarak daha once ec2-run-instances ile baslattiginiz bir EC2 makinasidir. Herhangi bir anda reserve ettiginiz IP adreslerini gormek icin
ec2-describe-addresses
komutu yeterlidir.

WWW ile baslayan site ismini IP adresi ile baglamak, site ismini aldiginiz sirketle halledilecek bir sey; elastik IP adresinizi bu sirkete bildirdiginiz anda site isminiz ile IP adresiniz arasindaki baglanti da kurulmus olur, ve bu baglantinin bir daha degistirilmesi gerekmez. Makinalar degistikce ec2-associate-address ile ayni adres yeni makinalara baglanabilir, ve ayni isim ayni adres ile calismaya devam eder. Site ismi -> IP adresi baglantisi genelde surekli degistirilen bir sey degildir (etki etmesi uzun suruyor) o sebeple fazla olabilecek degisimi EC2 tarafinda yapabilerek optimal bir cozumu bulmus oluyoruz.

Monday, August 10, 2009

Sabitler

Web uygulamasi sabit degerleri (constants) nasil almali? Bir properties dosyasindan, muhakkak, fakat bu dosya EAR icinde mi disinda mi olsa daha iyi?

Disinda olmasi daha iyi; boylece bu dosyanin set edilmesi tamamen derleme sistemi disinda, gelistirme ile alakali degil, sonuca gonderme (deployment) ile ilgili. Sonuc ortaminda "ant" olmasa bile, properties dosyasinda degisim yapabiliriz. Alttaki class sabitleri okumak icin yazildi. Uygulamamizin sabitleri, diyelim ki app.properties dosyasi, her zaman $HOME/etc/ altinda aranir. Mesela JBoss baslatan "ubuntu" adli bir kullanici ise, /home/ubuntu/etc/app.properties okunacak.
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.FileInputStream;
import java.util.Properties;

public class Constants {

transient Logger log = Logger.getLogger("logger");

private static Constants _instance = null;

Properties properties = new Properties();

public static Constants instance() {
if (_instance == null) {
_instance = new Constants();
}
return _instance;
}
public Constants() {
String userHome = System.getProperty("user.home").toLowerCase();
try {
log.debug("userHome =" + userHome + "/etc/pocketbudda.properties");
properties.load(new FileInputStream(userHome + "/etc/app.properties"));
} catch (IOException e) {
Util.log(e);
}
}
public String getString(String arg) {
return properties.getProperty(arg);
}
public int getInt(String arg) {
return new Integer(properties.getProperty(arg)).intValue();
}
public String[] getList(String arg) {
String s = properties.getProperty(arg);
return s.split(",");
}
}
Sabit degerleri okumak icin uygulamamizin herhangi bir yerinde Constants.instance().getString("anahtar") gibi bir cagri yeterli. Dosya
anahtar1=deger1
anahtar2=deger2
formatinda... Constants class'i listeler, sayilari "tip guvenlikli (type safe)" bir sekilde okuyabilecek halde.

Sabitleri Seam'e vermek mumkun; uygulama baslayinca muhakkak islemesi garanti bir Action class'i icine:
@Out
String showAds = Constants.instance().getString("showAds");
gibi bir tanim "showAds" sabitini dis dunyaya de-enjekte edecektir. Artik
<s:div rendered="#{showAds == 'false'}">
<img src="[imaj]"/>
</s:div>
gibi tanimlar xhtml sayfalari icinde kullanilabilir.

Sunday, August 9, 2009

Apache 2, mod_jk, Ubuntu ve Seam

JBoss onunde bir Apache Web Server programi hem yuk dagiticisi olarak hem statik icerik saglayici olarak gorev yapsin istiyorsak, Ubuntu Server uzerinde hem Apache 2 hem de mod_jk kurmak apt-get ile mumkun. Kurmak ve ayar icin sunlar gerekli:

Once

sudo apt-get install apache2 libapache2-mod-jk

Sonra
/etc/apache2/conf.d/jk.conf dosyasi yaratin, sunlar olsun:

JkWorkersFile /etc/apache2/jk-workers.properties
JkLogFile /var/log/apache2/mod_jk.log
JkShmFile /var/log/apache2/mod_jk.shm
JkLogLevel warn
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"
JkMount /*seam* ajp13
JkMountCopy all

Yukarida *seam* ibaresine dikkat. Sadece *.seam demiyoruz, *seam* diyoruz cunku Ajax cagrisi amaciyla EJB js kodlari dahil ederken bunu seam/remoting/../remote.js gibi bir kelime kullanarak yapariz, ve bu js dosyasi dinamik olarak "uretilen" bir dosya oldugu icin bu cagrinin app server'a gitmesi lazim, Apache o isi halledemez. Eger sadece *.seam deseydik, bu tur cagrilar JBoss'a gitmeyecekti.

Simdi /etc/apache2/jk-workers.properties dosyasi yaratin, sunlar olsun:

worker.list=ajp13
worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
worker.ajp13.lbfactor=1

Statik iceriklerinizin (imaj, css, html dosyalari gibi) hepsini /var/www altina kopyalamaniz gerekiyor. Artik

sudo /etc/init.d/apache2 restart

ve JBoss run.sh ile baslatin (-b [IP ADRESI] ibaresine gerek yok cunku Apache arka planda JBoss ile localhost uzerinden konusuyor zaten).

Artik Seam sayfalarini gorebiliyor olmaniz lazim.

Kaynak:

Saturday, August 8, 2009

EC2 Imajlari, Ubuntu Server

Uygulamamizi sonuc ortamina (production) gondermeye karar verdik; diyelim ki barindirma servisi olarak Amazon EC2 servisini sectik. Daha onceki su yazida genel EC2 komutlarini tanidik.

Simdi bir Ubuntu bazli servis makinasini nasil yaratacagimiza gelelim:

Bildigimiz gibi, EC2 "makina imajlari (machine image)" kavramiyla isliyor. Bir makinayi sifirdan yaratmak icin gerekecek tum dosyalar (bunlar oldukca buyuk yer tutuyor dogal olarak) yine Amazon'un buyuk olcekli dosyalari tutmak icin sundugu S3 servisi uzerinden herkese sunuluyor. Bu servisteki tum Ubuntu AMI (makina imajlarini) gormek icin
ec2-describe-instances -a | grep ubuntu
isletmek yeterli. Soyle bir liste geri gelecek:
...
IMAGE ami-5059be39 canonical-cloud-us/ubuntu-intrepid-20090422-i386.manifest.xml
099720109477 available public i386machine aki-714daa18 ari-6a5bbc03 I
...
Ustteki imaj bizim sectigimiz imajlardan biri. Canonical Ubuntu sistemini yaratan sirket zaten, bu sebeple "kaynaktan" gelecek imajin saglam olacagi dusuncesinden hareketle onu seciyoruz. Bu konuyu onceki yazida isledigimiz icin daha fazla detaya girmiyoruz. Simdi, ek olarak yine diyelim ki, "sudo apt-get install" ile bu imajdan yaratilan makinaya bir suru yeni program ekledik. Bu programlari kaybetmek istemiyoruz, cunku ec2-terminate-instances ile biraz onceki yarattigimiz makinayi kapatinca imaja dahil olmayan her turlu yeni dosya kaybolacaktir. O zaman bu makinanin son halini yeni bir imaj olarak "yakmamiz" gerekecek. Bunu yapmak icin EC2 makinasinda sunlari isletebiliriz.
sudo ec2-bundle-vol -d /mnt -k /mnt/[ACIK SSH ID DOSYASI] -c /mnt/[CERT DOSYASI] -u [KULLANICI ISMI] -r i386 -p [IMAJ ISMI]
[] icindeki dosyalari EC2 hesabinizda anahtarlarinizi gosteren yerden ya indirebilir, ya da kopyalayarak yapistirabilirsiniz. Acik ssh id dosyasi kisisel bilgisayarinizda EC2 sistemlerine erismek icin surekli kullandigimiz dosya aslinda. Tum bu dosyalari alip EC2 makinanizdaki /mnt/ altina kopyalayin. Niye /mnt? Cunku yakma islemi sirasinda /mnt altindaki dosyalar imaja yazilmiyor ve bu "gizli" dosyalarin imaj icinde olmamasi daha iyi.

Imaji yarattiktan sonra onu alip S3 depolama sisteminize yazmaniz lazim, kaybolmamasi icin. EC2 hesabi olan herkes bir S3 hesabi acabilir. Bunu yaptiktan sonra;
ec2-upload-bundle -b [BUCKET ISMI] -m /mnt/[IMAJ ISMI].manifest.xml -a [ACCESS KEY] -s [SECRET KEY]
Bucket ismi, sizin sececeginiz bir "dizin" ismi olacak. S3 bu isimleri "global" isimler olarak aliyor, yani "mybundle" gibi isimler cok genel isimler secilirse cakisma olur, projenize ozel bir isim olmasi daha iyi olur.

S3 dosyalarinizi gormek icin S3 Organizer iyi bir Firefox eklentisi.

Bunun ertesinde, artik EC2 makinanizi kapatsaniz bile, yarattiginiz imaj dosyalarini baz alarak hemen ayni makinayi sifirdan yaratabilirsiniz. Bunu yapmadan once imaji EC2 hesabinizdan "kayit etmis olmaniz (register image)" lazim. [IMAJ ISMI].manifest.xml ile bunu hemen yapabilirsiniz, ardindan komut satirinde ec2-describe-images komutunu isletirseniz, kayit ettigimiz imajin "i-" ile baslayan kimligini alabilirsiniz, bundan sonra ec2-run-instances komutu ile bildigimiz islemleri gerceklestirebiliriz.

Bir kaynak:

Wednesday, August 5, 2009

Seam, Selenium ve Yuk Testleri

Web uygulamamiz uzerinde yuk testleri isletmek icin Kurumsal Java kitabinda jMeter aracini tavsiye etmistik. Fakat Seam uzerinde JMeter'in islemedigini farkedince alternatif bir arac bulmak gerekti. Web egitim slaytlarimizda kabul testleri (acceptance test) icin Selenium adli bir arac gosteriliyordu; Bu arac bir Firefox eklentisidir, ve kaydetmeye baslayinca Firefox uzerinden yaptiginiz tum aksiyonlari, girilen verileri alip tekrar geri calma (replay) gibi servisler saglamaktadir. Tek kullanici, tek test icin guzel bir ortamdir. Kurmak icin indirme sayfasindan Selenium IDE xpi eklentili dosyaya tiklayin, Firefox otomatik olarak programi kuracaktir.

Fakat simdi bizim istedigimiz Selenium ile bir testi kaydedip, N tane sanal kullanicinin ayni testi uygulama uzerinde isletebilmesi. Selenium, herhangi bir testi Python script olarak kaydedebiliyor. Bu iyi, scriptleme isleri bu sayede kolaylasabilir.

Test kaydetmek icin Firefox Tools | Selenium IDE menusunden uygulamayi aciyoruz, kayit isleminiz bittiginde ise File | Save Test Case As .. | Python secimini yapiyoruz, bir dosya ismi giriyoruz. Uretilen kod suna benziyor:
from selenium import selenium
import unittest, time, re

class exploretest(unittest.TestCase):
def setUp(self):
self.verificationErrors = []
self.selenium = selenium("[makina]", [PORT], "*chrome", "http://[site.ismi]")
self.selenium.start()

def test_exploretest(self):
sel = self.selenium
sel.open("/home.seam?conversationId=708")
sel.click("link=Explore")
sel.wait_for_page_to_load("30000")
sel.type("j_id4:day", "3")
...

def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
unittest.main()
Bu kodu komut satiri ortamindan geri caldirmak icin, cunku paralel sekilde test isletmek icin once geri caldirma islemini scriptleyebilmemiz lazim, Selenium indirme sayfasindan Selenium RC adli paketi aliyoruz ve bir dizinde aciyoruz. Actiktan sonra dizinde selenium-server-x ve selenium-python-client-driver-x gibi dizinler goreceksiniz. Bunlardan birincisi Python scriptlerini geri isletirken konusulan servis, ikincisi ise uretilen Python kodlarinin import ettigi kodlarin oldugu yer. Bu kodlari uretilen Python scriptine tanitmak icin "import sys" ve "sys.path.append('[SELENIUM RC DIZINI]')" kodlarini en basa koymaniz gerekecek (ya da Python cevre degiskenleriyle biraz takla lazim). Bu olduktan sonra Sel RC baslatmak icin server dizinine gidip
java -jar selenium-server.jar -port [PORT]
girip servisi baslatabilirsiniz. [PORT] icin buyuk bir rakam iyi olabilir, 12000 mesela. Bu arada, uzerinden kayit yaptiginiz Seam programiniz isliyor olacak tabii. Artik uretilen test scriptine gidip direk python komutu ile isletirseniz, arka planda bir Firefox baslatildigini, kaydettiginiz hareketlerin aynen orada yapildigini, ve sonra Firefox'un kapatilip testin bitirildigini goreceksiniz. Testin basarili olup olmadigi python programi tarafindan text bazli olarak ekrana basilacaktir.

Buraya kadar basit. Fakat paralel testler soz konusu olunca problem surada: Yuk testleri icin bu testlerden 100 tane isletmemiz gerekebilir. O zaman 100 tane Firefox programi ekrana cikacaktir! Bu hem performans acisindan kotu hem de gereksiz cunku biz otomize bir sekilde bu testleri isletirken gorsel hicbir seyi umursamiyoruz. Bizi tek ilgilendiren bildigimiz bir senaryo uzerinden bir yuk yaratmak ve programin performansina bakmak. Programin "dogrulugunu" zaten Selenium IDE ile tekil geri calma yaptigimizda goruyorduk. Ayrica paralel testler genelde (her zaman) hicbir gorsel birimi olmayacak bir Linux server makinasi uzerinde isletilecek, o zaman isin GUI tarafini iptal etmek / kapatabilmek onemli bir ihtiyac.

Bunu nasil yapacagiz? Gorsel olmadan (headless) sekilde Selenium isletmek icin guzel bir teknik bulduk. Bu arkadas xvfb diye bir program kullanarak Selenium'dan gelen tum X komutlarini monitora gondermeden yakalattiriyor, ve iptal ediyor. Selenium X var zannediyor ama aslinda yok. Kurmak icin "apt-get install xvfb". Isletmek icin iki tane xterm acin: birinde "Xvfb :99 -ac" komutunu isletin. Ikinci xterm icinde "export DISPLAY=:99" deyip, arkasindan ayni xterm icinde hemen ustteki gibi Selenium RC server baslatin. Artik python ile kaydedilen testi geri caldigimizda hicbir Firefox acilmadigini gorecegiz.

Simdi paralelizasyona gelelim. Bundan sonraki basamak, bizim ekimiz. Birden fazla, paralel sekilde ayni testi isletmenin bir teknigi. Bu amacla RC server sureclerinden N tane baslatacagiz ve test isletici program, tek surec ama N thread icinden bu ayri sureclere baglanacak, ve testleri paralel sekilde isletecek. Isin temiz olmasi icin, tum bunlari tek Python script'i icinden yaptirtacagiz. Ama ilk once Selenium IDE tarafindan urettirdigimiz test programina gidelim; burada ufak bazi degisiklikler lazim. Diyelim ki uretilen ustteki exploretest.py script'i icindeki exploretest class'i olsun. Bu class'in ustteki hali suna cevrilmeli:
class exploretest(unittest.TestCase):
def __init__ (self, port):
self.port = port
def setUp(self):
self.selenium = selenium("[makina]", self.port, "*chrome", "http://[site]")
self.selenium.start()
...
Degisen ne? setUp ile class tanimi arasina bir kurucu method (constructor) eklemisiz. Bu lazim cunku pek cok Thread pek cok exploretest objesi yaratacak ve bu objelerin her birinin ayri bir RC server portuna isaret ediyor olmasi lazim. Ikinci degisimle, selenium() cagrisi artik disaridan verilen self.port parametresini kullaniyor.

Bu script disinda runselserver.sh adli bir script lazim. runselserver.sh suna benzer:
#!/bin/bash
export DISPLAY=:99
cd [SELENIUM RC SERVER DIZINI]
java -jar selenium-server.jar -port $1
Tamam. Bu programi chmod u+x ile isletilebilir hale getirmeyi unutmayin. Simdi gelelim esas okkali programa. testrunner.py adli bu programi server sureclerini, threadleri baslatma, isletme islerinin hepsini gerceklestiren ana program.
import os
import subprocess
import time
import threading
from exploretest import exploretest
import unittest

class Caller(threading.Thread):
def __init__(self, port):
threading.Thread.__init__(self)
self.port = port
def run(self):
print "Calling"
a = exploretest(self.port)
a.setUp()
a.test_exploretest()
a.tearDown()

# number of parallel test
testnumber = 4

# start port
port = 12000

for i in range(testnumber):
print str(port+i)
cmd = ['[DIZIN]/runselserver.sh %s' % str(port+i)]
p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

time.sleep(2)
print "running tests"

ts = []
for i in range(testnumber):
a = Caller(port+i)
a.start()
ts.append(a)

for t in ts:
t.join()
Bu programi kullanarak yeni urettiginiz kendi testlerinizi cagirttirmak icin exploretest yazan her yerde kendi test isminizi koyabilirsiniz. testnumber parametresi ile kac tane paralel test isletilecegini kontrol edebilirsiniz. Bu kadar!

Notlar:

o N surec N thread icin sadece bir tane Xvfb isletmek yeterli. Bu komut ayri bir xterm icinde bir kere isletilir.
o Bir potansiyel problem: Xvfb programi pek stabil degil, her isletim sonrasi Segmentation Fault ile cokuyor, ama ondan once isi basariyla tamamliyor. O zaman her test oncesi bu programi yeniden baslatmak lazim. Biraz hammaliye (ki zaten otomize edilebilir), bu da aklimizda olsun.
o Yuk testleri isleten makinanin guclu bir makina olmasi iyi olur cunku bu makinanin N tane firefox programini baslatmasi gerekecektir. Her ne kadar firefox'un gorselligini Xvfb ile iptal etmis olsak bile, sonucta firefox isler kodu yine de calisacak, ve bu pek ufak bir program degil.

Friday, July 31, 2009

serialVersionUID

Java Serilestirme mekanizmasi bir Java objesini alip onu bir byte[] dizisine cevirebilememizi sagliyor. Bu bayt serisini alip dosyaya yazabiliyor, network uzerinden gonderebiliyor, database'e yazabiliyoruz. Hatta Schemafree ile yaptigimiz zaten tami tamina bu aslinda; herhangi bir objeyi alip, serilestirip onu bir kimlik ile bagdastirarak o bayt serisini SFEntitiy kap objesi icine gomulmus bir sekilde veri tabanina yaziyoruz (bu class 'Serializable' arayuzunu implement ediyor olmali tabii ki).

Yanliz eger ek bazi tanimlar yapilmazsa, serilestirme ve deserilestirme islemleri, objemizin class tanimi degistiginde hata verir. Ornek: Class A icinde iki tane alan tanimladik. Bu sekilde veri tabanina yazdik. Sonra ek bir alan koymamiz gerekti, bunu yaptik, yeni kodu derledik, ama sonra hala eski tanimda olan bir onceki objeyi geri okumaya kaltik, ve hata mesaji gorduk. Niye? Cunku baytkod tanimlari artik birbiri ile uyusmuyordu.

Aslinda Java Serilestirme kutuphanesi "hala birbirine uyan" yani "okuyabilecegi kadarina okuyabilecek" "eski" alanlari cevirebilecek mekanizmalara sahiptir. Ama bu ozelligi kullanmak icin bean class icinde serialVersionUID diye bir oge tanimlamiz gerekli. Tanim soyle:
static final long serialVersionUID = [SAYI];
[SAYI] ile taninlanmis rakam nereden gelecek? Bu rakami JDK araclarinden serialver adli program uretebilir.
serialver -classpath [CLASSPATH] [paket.Class]
komutu ile gerekli sayiyi urettirmek mumkundur. Hatta bazi editorler bu rakami otomatik olarak Java kodunun icine koyabilirler. Bu rakamin onemi surada: Eger rakam degismemis ve objenizin onceki hali ile mevcut tanimi birbirine uyumlu (compatible) ise, Java Serilestirme kutuphanesi okuyabilecegi kadar alani okumaya ugrasir, ve bu okuma basari ile isler. Uyumlu olmak ne demek? Eski alanlarin taniminda "degisiklik yapilmamis" sadece yeni alanlar "eklenmis" demek. O zaman onceki ve sonraki class tanimlari birbiri ile uyumludur ve okuma islemi basari ile isleyecektir.

Gelistirme sirasinda eger class iceriginiz cok fazla degistiyse, ve uzerinde calistiginiz kod sonuc ortaminda kullanilmiyorsa, serialVersionUID'yi (tekrar) uretmek akillica olabilir. Ozellikle inner class iceren cok fazla bazi degisiklik sonrasi class'imizin uyumsuz hale geldigini bir kez gozlemledik ve problemi yeni ID ureterek tamir ettik.

Seam ve Hata Mesajlari

Seam ile validasyon (veri dogruluk kontrolu), hata bulunca hata mesajlari yazma / gosterme mekanizmasi soyle kurulabilir.

Hata kontrolu yapan her aksiyon,
  @Out
private transient List errors = new ArrayList();
ile bir hata listesi tanimlar. Validasiyon sirasinda tum hatalar errors.add("mesaj") ibaresi ile bu listeye yazilir. Bu hatalar aksiyon sonrasi ustteki @Out ile de-enjekte edilecektir ve uygulamanin geri kalani artik bu listeye erisebilir. Bu noktada eger hatalarin olup olmadigina bagli olarak bir navigasyon yapmak istiyorsak, rule-if ile bunu yapmak artik cok basittir.
  <page view-id="/page.xhtml" conversation-required="false"
login-required="true">
<navigation from-action="#{userHandler.someAction}">
<rule if="#{errors.size() == 0}">
<redirect view-id="/home.xhtml"/>
</rule>
</navigation>
</page>
Dikkat edelim: Hata olmadigi durumda hangi sayfaya gidilecegini tanimlamadik, cunku bunu tanimlamadiysak, Seam otomatik olarak bizi ayni sayfaya yonlendirir. Bu bizim icin uygun, zaten hata varsa o sayfayi terk etmek istemiyorduk. Simdi, bu ayni sayfada hatalari basmak icin bir JSF kodu soyle yazilabilir.
  <font color="#FF0000">
<s:div rendered="#{errors.size() > 0}">
#{errors}
</s:div>
</font>
Bu sayfayi bir errors.xhtml diye tanimladik ve gereken her sayfadan include ile dahil ediyoruz.

Tabii bu kodu surekli kullanabilmek icin hata verebilecek her aksiyonumuzun errors adli ayni degisken ismini kullanmasi gerekiyor.

Sayfa Oncesi Aksiyon

Seam'in kullandigi sayfa -> aksiyon -> sayfa modelinden bahsettik. pages.xml adli bir dosyada tum navigasyon kurallari tanimlanmaktadir, ve X sayfasinda iken 'a' aksiyonu alinca Y sayfasina yonlendir gibi kurallar burada tanimlanabilir.

Yanliz bazi durumlarda sayfa yuklenmeden once bir aksiyon isletmek gerekebilir. Bu durum icin view-id tanimladigimiz ayni satirda bir aksiyon tanimlamamiz mumkundur.
<page view-id="/main.xhtml" conversation-required="false"
login-required="false" action="#{userHandler.someAction}">
<rule if="#{user == null}">
<redirect view-id="/home.xhtml"/>
</rule>
...
</page>
Bu ornekte main.xhtml sayfasi icin (aslinda boyle bir sayfanin mevcut olmasi bile gerekli degil, tarayiciya main.seam girince ustteki navigasyon kurallari isler) userHandler.someAction komutu isletilsin istiyorsak, tanim yukaridaki gibidir... Ayrica, diger her tur navigasyon kurali icin de, bu isletimden sonraki yonlendirmeyi "eger kuralina" baglayabiliriz. Mesela, bir aksiyondan @Out ile de-enjekte edilmis bir user objesinin olup olmadigina bagli bir karar almak istiyorsak, rule-if ile bunu yapariz. Ustte, eger user null ise, "home.xhtml adli bir sayfaya yonlendir" diye bir tanim yapmisiz.

Tuesday, July 28, 2009

Facebook Import

Bir kullanicinin arkadas listesini, onlarin bilgisini kendi uygulamaniza yuklemek istiyorsaniz, alttaki kodlar yardimci olabilir. Once temel kodlar:
  public Collection<String> getFriendIds() throws FacebookException, IOException {
Collection<String> userIds = new LinkedList<String>();

JSONArray friends = _client.friends_get();
if (friends == null || friends.length() == 0) {
return userIds;
}

/* Walk the list of result elements; each one's contents is a user ID. */
for (int i = 0; i < friends.length(); i++) {
try {
userIds.add(friends.getString(i));
}
catch (JSONException e) {
throw new IOException("friend list can't be extracted");
}
}

return userIds;
}

public JSONArray getInfo(Collection <String> userIds) {
Object result = null;
try {
// two fields
Set<ProfileField> fields = new HashSet<ProfileField>(2);
fields.add(ProfileField.UID);
fields.add(ProfileField.BIRTHDAY);
fields.add(ProfileField.FIRST_NAME);
fields.add(ProfileField.LAST_NAME);
fields.add(ProfileField.PIC_SMALL);
fields.add(ProfileField.SEX);
fields.add(ProfileField.RELATIONSHIP_STATUS);
fields.add(ProfileField.SIGNIFICANT_OTHER_ID);
fields.add(ProfileField.ACTIVITIES);
fields.add(ProfileField.INTERESTS);
fields.add(ProfileField.MUSIC);
fields.add(ProfileField.TV);
fields.add(ProfileField.MOVIES);

Collection<Long> longUserIds = new ArrayList<Long>(userIds.size());
for (String uid : userIds) {
longUserIds.add(Long.valueOf(uid));
}
result = _client.users_getInfo(longUserIds, fields);

} catch (Exception e) {
Util.log(e);
}

return (JSONArray)result;

}
Bu kodlari su sekilde cagirabiliriz (uid degiskeni kullanicinin facebook kimligini tasiyor olsun):
  public void importUsers() {
try {
Collection<String> plist = new LinkedList<String>();
plist.add(uid);
JSONArray parr = getInfo(plist);
importUsers(parr);

Collection<String> list = getFriendIds();
JSONArray arr = getInfo(list);
importUsers(arr);
} catch (Exception e) {
Util.log(e);
}
}

public void importUsers(JSONArray arr) {
..
for (int i = 0; i < arr.length(); i++) {
JSONObject obj = (JSONObject)arr.get(i);
...
value = ""+obj.get(ProfileField.BIRTHDAY.toString());
...
}
}
Session id uzerinden facebook kimliginin nasil alinacagini bir onceki yazida islemistik.

Thursday, July 23, 2009

Google Aramasi ve Urllib

Google aramalarina scriptlemek istiyorsak, wget, hatta urllib ile ilk denememiz basarisiz olabilir. Anlasiliyor ki wget ve urllib baglantilari, kullanicilari Google'in izin verdigi robotlardan degil. O zaman baglananin 'kim oldugunu' degistirerek, yani Google'i yaniltarak, izin verilen bir robot ortaya cikartabiliriz. Alttaki 'version' tanimi bunu yapiyor. Sanki bir Windows makinasindan baglanan Firefox tarayicisi gibi gozukuyoruz.
from urllib import FancyURLopener

class MyOpener(FancyURLopener):
version = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; it; ' + \
'rv:1.8.1.11) Gecko/20071127 Firefox/2.0.0.11'

myopener = MyOpener()
page = myopener.open('http://www.google.com.tr/search?q=tomatoes')
content = page.read()
print content
Bu kadar!

Detexify

Bazen bir Latex sembolunun komutunu hatirlayamiyor olabiliriz; boyle durumlar icin Detefixy web programi faydali oluyor. Elle cizdiginiz sembol oruntu eslestirme algoritmasi ile arka planda size bir Latex sembolu bulup gosteriyor. Altta bizim theta icin yaptigimiz arama..

Wednesday, July 22, 2009

HTML Toplamak (Scraping)

Baska bir sitenin icerigini otomize olarak (bir script yardimiyla) alip diskte saklamak istiyorsak, bu tekrar yayin amacli, baglantisiz bakma amacli vs. olabilir, o zaman HTML toplama tekniklerini bilmek gerekli. Bu gibi isler icin biz Unix wget komutunu kullaniriz; fakat eger wget herhangi bir sebeple ise yaramazsa, bir alternatifi bilmekte yarar var. Python kutuphanelerinden urllib. Alttaki ornekte Google Insights for Search sayfalarindan Google'da son 7 gun icinde en cok aranan kelimelerin listesini almak icin kullandigimiz kodlar bulunabilir. Ayni sayfalar uzerinde wget ise yaramadi, urllib FancyURLopener calisti.
from urllib import FancyURLopener

myopener = FancyURLopener()
insightsURL = 'http://www.google.com/insights/search/overviewReport'
page = myopener.open(insightsURL + '?q=&date=today+7-d&cmpt=q')
print page.read()

Saturday, July 18, 2009

Ajax, Seam ve Facebook Connect

Facebook Connect mekanizmasini Java servis tarafi kodlarina baglama cabasinin iyilestirmeleri suruyor. Bir onceki yazida, Facebook FQL sorgusunu Javascript'e yaptirarak gelen verileri servis tarafina aktarmistik. Buradaki bir problem, Uzun suren Ajax cagrilarinin geri donuste problem yasamasi. Bu tur uzun sureli islem kodlarini servis tarafina gondermek daha iyi.

Ek olarak, simdiye kadar Javascript -> FB baglantisini kurmak icin kullanici UID (yani Facebook kullanici kimligi) Ajax ile set etmek bir cozum gorulebilirdi. Fakat bu cozum FB Connect kullanan uygulama acisindan guvenli bir cozum olmayacaktir - Facebook UID cok gizli bir bilgi degildir, 1'den baslayarak birer birer artan bir tam sayi sadece (kuruculari 1,2,3,4 diye kimlikler almislar mesela!), o zaman sadece Facebook tarafindan "uretilen", ve hem client hem servis tarafinda ayri ayri kontrol edilebilen, ve rutin olarak degisen bir kimlige ihtiyacimiz var.

Oturum kimligi (session id) bu isi basarabilir. Eger Facebook'a login edilmis haldeyseniz, ki degilseniz bir ziplama ekrani sonrasi login edilmis olursunuz, artik Facebook size bir session id uretebilir. Bu id Java servis kodlarina Ajax ya da form post uzerinden gonderilir, ve arka planda tekrar kontrol edilir. Bunun icin servis tarafinda FB cagrisi yapabilmek lazim tabii. Servis tarafi bunu yapiyorsa, User objesinin set edilmesi @Out ile de-enjente edilmesi, vs. gerceklestirilmis olur. O noktadan sonra isler tamamen Seam'in kontrolunde olacaktir.

Servis tarafinda Facebook baglantisi yapmak icin REST arayuzu var.

FB Session id almak icin Javascript kullanacagiz. Javascript illa ki biraz oluyor, cunku baska turlu FB ile ilk baglantiyi kurmak mumkun degil. Ama bu kod cok az olacak.

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:fb="http://www.facebook.com/2008/fbml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">

<head>
<script type="text/javascript" src="seam/resource/remoting/resource/remote.js"></script>
<script type="text/javascript" src="seam/resource/remoting/interface.js?userHandler"></script>
</head>

<script type="text/javascript">
FB_RequireFeatures(["XFBML"], function()
{
FB.Facebook.init("[API KEY BURAYA]",
"xd_receiver.htm");
});

function flogin() {
sessionKey = FB.Facebook.apiClient.get_session().session_key ;
Seam.Component.getInstance("userHandler").facebookLogin(sessionKey);
}
</script>

<body>
<h:form>
<a href="#" onclick="flogin()">Login</a>
</h:form>
</body>

</html>
Ustteki HTML gosterilip Login baglantisina tiklaninca userHandler objesi uzerinde facebookLogin cagrisi yapilacaktir. Servis tarafi kodlari soyle:
import javax.ejb.Local;
import org.jboss.seam.annotations.remoting.WebRemote;
import com.google.code.facebookapi.FacebookException;
@Local
public interface UserHandler {
@WebRemote
public void facebookLogin(String sessionKey) ;
}


import com.google.code.facebookapi.FacebookJsonRestClient;
import com.google.code.facebookapi.FacebookException;
import java.util.LinkedList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

@Stateful
@Scope(SESSION)
@Name("userHandler")
public class UserHandlerBean implements UserHandler {

protected FacebookJsonRestClient _client;

public void facebookLogin(String sessionKey) {
try {
_client = new FacebookJsonRestClient("[APP KEY BURAYA]",
"[GIZLI APP KEY BURAYA]",
sessionKey);

Collection list = getFriendIds();
log.debug("list=" + list);
} catch (Exception e) {
Util.log(e);
}
}

public Collection getFriendIds() throws FacebookException, IOException {
Collection userIds = new LinkedList();

JSONArray friends = _client.friends_get();
if (friends == null || friends.length() == 0) {
return userIds;
}

for (int i = 0; i < friends.length(); i++) {
try {
userIds.add(friends.getString(i));
}
catch (JSONException e) {
log.debug("Can't fetch friend " + i + " from list");
throw new IOException("friend list can't be extracted");
}
}

return userIds;
}

Ustteki kodlar facebook-java-api kodlarina ihtiyac duyuyor. Kodlari indirip kurun. Ayrica MoochSpot sitesinin ornek kodlari java-api kodlarini sarmalayan yardimci bazi kodlar sunmakta.

Bu konu hakkinda ek yazilar gelebilir; Sonuc olarak bir kere java-api uzerinden baglanti kurulunca, _client uzerinden Facebook uid gibi bilgiler alinarak, Seam User objesini set etmek icin kullanilabilir.

Lineer Cebir Karikaturu

Tuesday, June 30, 2009

Seam ve Cookie Idaresi

Seam uygulamamizin cookie (cerez) uzerinden kullanici makinasina bilgi birakmasi gerekiyorsa (kullanici kimligi gibi), o zaman javax.servlet paketlerini kullanarak cookie arayuzlerini kullanmak gerekiyor. Import edilmesi gereken kodlar
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.faces.context.FacesContext;
Bu kodlar Seam action class'inizda bulunmali, ya da FacesContext'e erisebildiginiz herhangi bir yerde. Simdi cookie yazmak icin soyle bir kod gerekli
FacesContext context = FacesContext.getCurrentInstance();
Cookie cookie = new Cookie("[cookie id]", "[deger]");
cookie.setMaxAge(3 * 30 * 24 * 60 * 60);
cookie.setPath("/");
HttpServletResponse res = (HttpServletResponse)context.getExternalContext().getResponse();
res.addCookie(cookie);
Ustte [cookie id] yazan yer programci tarafindan secilen bir cookie kimligidir. Mesela "userId" gibi bir isim secilebilir, daha sonra [deger] yazan yere veri tabanindan, vs. gelen deger yazilacaktir. Boylece kullanicinin her zaman kim oldugunun hatirlanmasi saglanacaktir. Yazdigimiz degere sonradan erismek istiyorsak soyle bir kod lazim
FacesContext context = FacesContext.getCurrentInstance();
String cookieName = null;
Cookie[] cookies = ((HttpServletRequest)context.getExternalContext().getRequest()).getCookies();
if(cookies != null && cookies.length > 0) {
for (int i = 0; i < cookies.length;i++) {
Cookie c = cookies[i];
...
}
}
getCookies() ile tum cookie'leri almisiz, ve teker teker onlara bakiyoruz; c.getName() ile cookie ismi, c.getValue() ile degerini okuyabilecegiz. Aradigimiz ismi bu notada filtreleyerek bulmamiz mumkun. Degeri aldiktan sonra @Out ile de-enjekte ederek (mesela) Seam uygulamamizin diger kisimlarinin da ayni degere erismesini saglayabiliriz.

Firefox eklentisi olarak Web Developer eklentisini tavsiye ederim; Cookie'lere, CSS'leri incelemek gibi pek cok guzel ozelligi var.

Friday, June 26, 2009

Android Scriptleme Ortami

Google'in cep telefonlari icin yazdigi ve artik Netbook bilgisayarlarda bile kullanilmaya baslanan Android isletim sistemi scriptleme ortami cikartti. Bu ortamda Lua ve Python gibi dilleri kullanarak telefonda API cagrilari yapabiliyorsunuz; Okkali Java programlamaya dalmaniz gerekmiyor. Python ve scriptleme ortami kullanarak Twitter client yazan, garaj kapisini actirabilen, barkod okutturabilen uygulamalar var.

Saturday, June 20, 2009

Amazon Fiziksel Veri Transferi

Andrew Tanenbaum'un unlu sozu soyledir: "Teypler ile yuklu yolda giden bir kamyonun bant genisligini hicbir zaman hafife almayin". Burada teyp kelimesini sabit disk ile degistirirsek, soz tam gunumuze uyarlanmis olacak. Gunumuzde bazi veri setleri o kadar buyuk boyutlardadir ki, eger bu veriyi veri depolama isini outsource ettiginiz bir baska sirketin veri ambarinda muhafaza etmek istiyorsaniz, Internet uzerinden bu transferi yapmak gunlerinizi alabilirdi. Amazon yeni bir servis baslatti; verisini Amazon uzerinde tutan sirketler artik posta uzerinden bir diski yollayabilecekler, ve Amazon bu veriyi alinca o sirket icin ayirdigi veri server makinlarina bu veriyi yukleyecek.

Thursday, June 11, 2009

MayaVi

3 boyutlu grafikleri Python ile olusturmak icin MayaVi adli bir paket var. Paketi kaynaklarindan kurabiliriz; once apt-get ile python-vtk yani vtk paketini kurmak lazim. MayaVi sitesinden indiriyoruz setup.py build ve install ile kuruyoruz. Alttaki orneklerden bir tanesi, maya grafiklerini ya komut satirindan mayavi2 ya da bilinen python komutu ile isletmek mumkun. Mouse sag dugmesi zoom sol dugmesi imaji 3 boyutlu olarak evirip cevirmek icin kullanilabiliyor. Ornekler examples altinda bulunabilir.

Tuesday, June 9, 2009

OpenCV, Python ile Yuz Takip Etme

OpenCV ve Python ile dinamik olarak yuz takibi kodlamak oldukca basit. Onceki kurulum paketlerine iki tane ek var, bunlar libcv-dev ve CVtypes adli ek kodlar. Bunlardan birincisini apt-get ile kurun, ikincisini indirin ve o dizini ayri tutmak istiyorsaniz sys.path.append('[CVTYPES DIZINI]') ile path eklemesi yapin (ya da test kodunuzla ayni yere koyun, size kalmis). Bundan sonra, ayrica, Haar Cascade dosyasi denen bir dosyayi alin, bunu test kodunuz ile ayni dizine koyun.

Guzel; simdi su kodu isletebilirsiniz.
import sys
sys.path.append('[benim cvtypes dizini]')
from CVtypes import cv

def detect(image):
image_size = cv.GetSize(image)

# create grayscale version
grayscale = cv.CreateImage(image_size, 8, 1)
cv.CvtColor(image, grayscale, cv.BGR2GRAY)

# create storage
storage = cv.CreateMemStorage(0)
cv.ClearMemStorage(storage)

# equalize histogram
cv.EqualizeHist(grayscale, grayscale)

# detect objects
cascade = cv.LoadHaarClassifierCascade('haarcascade_frontalface_alt.xml', cv.Size(1,1))
faces = cv.HaarDetectObjects(grayscale, cascade, storage, 1.2, 2, cv.HAAR_DO_CANNY_PRUNING, cv.Size(50, 50))

if faces:
print 'face detected!'
for i in faces:
cv.Rectangle(image, cv.Point( int(i.x), int(i.y)),
cv.Point(int(i.x + i.width), int(i.y + i.height)),
cv.RGB(0, 255, 0), 3, 8, 0)

if __name__ == "__main__":
print "OpenCV version: %s (%d, %d, %d)" % (cv.VERSION,
cv.MAJOR_VERSION,
cv.MINOR_VERSION,
cv.SUBMINOR_VERSION)

print "Press ESC to exit ..."

# create windows
cv.NamedWindow('Camera', cv.WINDOW_AUTOSIZE)

# create capture device
device = 0 # assume we want first device
capture = cv.CreateCameraCapture(0)
cv.SetCaptureProperty(capture, cv.CAP_PROP_FRAME_WIDTH, 640)
cv.SetCaptureProperty(capture, cv.CAP_PROP_FRAME_HEIGHT, 480)

# check if capture device is OK
if not capture:
print "Error opening capture device"
sys.exit(1)

while 1:
# do forever

# capture the current frame
frame = cv.QueryFrame(capture)
if frame is None:
break

# mirror
cv.Flip(frame, None, 1)

# face detection
detect(frame)

# display webcam image
cv.ShowImage('Camera', frame)

# handle events
k = cv.WaitKey(10)

if k == 0x1b: # ESC
print 'ESC pressed. Exiting ...'
break


Kaynak: