Mart 2010

You are currently browsing the monthly archive for Mart 2010.

Diğer programlama dillerinin PHP’yi küçük görmek isteyen takipçilerinin dayandıkları en öne çıkan argümanlardan biri de PHP yorumlayıcısının loosely typed yapıyı ele alış biçimi. Gerçekten de bir değişkeni integer olarak kullanmaya başlayıp, daha sonra kod içinde bir yerlerde tür dönüşümü yapmaksızın string’e çevirip, nihayeten aynı değişkeni array olarak kullanmak yalnız PHP’de mümkün değilse de, genellikle PHP programcılarının sahip olduğu bir kötü alışkanlık.

Doğal olarak böylesi alışkanlık beklenmedik hataları da beraberinde getirmeye amade. PHP yorumlayıcısının nelere kadir olduğunu(!) görmek açısından şu örneğe göz atalım:

1
2
3
4
5
6
7
8
9
10
<?php

header('Content-Type: text/html; charset=utf-8');
$kunk = 'Künk';
$sifir = 0;

if ($kunk == TRUE && $sifir == FALSE && $kunk == $sifir)
{
echo 'Benim adım da bundan sonra Maykıl Ceksın olsun!';
}

Yukarıdaki kodu üşenmeden kopyalayıp çalıştırın. Bakalım ne oluyor? Ne, $kunk TRUE, $sifir FALSE ve buna rağmen $kunk ile $sifir birbirine eşit, öyle mi? PHP yorumlayıcısı öyle diyor!

Tabii burada

1
if ($kunk == TRUE && $sifir == FALSE && $kunk == $sifir)

ile eşitlik kontrol etmek yerine

1
if ($kunk == TRUE && $sifir == FALSE && $kunk === $sifir)

ile özdeşlik kontrol ederek bu dertten kurtulabiliriz, ancak bu tür sorunlar deneyimsiz ya da kötü alışkanlıklar edinmiş PHP programcılarının başına çok sık gelir ve bu arkadaşlar sorunun kaynağını bulana kadar gereksiz vakit yitirirler.
Öte taraftan, kişisel fikrimce kullandığım programlama dili, bana kullandığım değişkenlerin türleri üstünde de tam hakimiyet sağlayabilmeli.
PHP5′ten itibaren, nesneler ve array’ler üstünde bu hakimiyete sahibiz. PHP6 yol haritası bu konuda daha umut verici görünüyor, ancak geliştiriciler bir türlü kendi aralarında anlaşamadıklarından (http://news.php.net/php.internals/47120) PHP6, gün itibarıyla trunk deposundan kaldırılmış durumda ve bir daha ne zaman geri konulacağı ya da ne zaman kararlı PHP6 sürümü çıkacağı meçhul.

Öyleyse, değişkenlerimizi belirli bir türden (integer, string, float vb) olmaya zorlamak için ne yapabiliriz?
Bildiğim bir-iki yöntem var: İlki, Ilia Alshanetski’nin yayınladığı bir yamayı kullanarak PHP’yi yeniden derlemek.

İkincisi ve bu yazının konusu, PECL deposunda bulunan SPL_Types eklentisi. Bu eklenti sayesinde PHP ile değişkenleri istediğimiz türden olmaya zorlayabiliyoruz.

Önce SPL_Types eklentisini kurmamız gerekiyor. Aşağıda anlattığım kurulum Ubuntu 9.10 için geçerli ancak adam gibi işletim sistemlerinin hemen hepsinde adımlar çok benzer olmalı.

Konsola geçiyoruz. Önce iki satır “export” yapmamız gerekiyor:

1
2
export LC_ALL="C"
export LANG="C"

Üstteki iki satır olmadan pecl sorun çıkarıyor. Şimdi eklentiyi kurabiliriz:

1
sudo pecl install http://pecl.php.net/get/SPL_Types-0.3.0.tgz

…ve Apache’yi yeniden başlatıyoruz.

1
sudo service apache2 restart

Artık yeni eklentimizi deneyebiliriz:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

$int = new SplInt(42);

try
{
    $int = 'Değişkeni stringe çevirmeyi deneyelim';
}
catch (UnexpectedValueException $uve)
{
    echo $uve->getMessage() . PHP_EOL;
}

var_dump($int);
echo $int;

Bu kodu çalıştırdığımızda aldığımız çıktı şöyle:

1
2
3
4
5
6
Value not an integer
object(SplInt)#1 (1) {
  ["__default"]=>
  int(42)
}
42

SPL_Types, SplInt yanında SplFloat, SplEnum, SplBool ve SplString nesneleriyle float, enum, boolean ve string değişken türlerini de destekliyor. Biz de kullandığımız, sevdiğimiz, ayrılmak istemediğimiz güzel PHP’mize biraz daha hakim olmanın verdiği tatmin hissiyle kodumuzu yazmaya devam ediyoruz.

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , ,

Sudo ilk kez Bob Coggeshall ve Cliff Spencer tarafından, SUNY/Bufalo’da Bilgisayar Bilimlieri Bölümü’nde 1980 yılı civarında tasarlandı.4.1BSD kullanan bir VAX-11/750 üstünde çalışıyordu. Phil Betchel, Cliff Spencer, Gretchen Phillips, John LoVerso ve Don Gworek tarafından 1985 Aralık ayında, güncellenmiş bir sürümü net.sources Usenet haber grubuna gönderildi.

1986 yazında, Garth Snyder sudo’nun genişletilmiş bir sürümünü yayınladı. Sonraki beş yıl boyunca sudo, CU-Boulder’da Bob Coggeshall, Bob Manchek ve Trent Hein’in aralarında bulunduğu bir kaç kişi tarafından beslenip büyütüldü.

1991 yılında, Dave Hieb ve Jeff Nieusma, “The Root Group” adında bir danışmanlık firmasıyla sözleşmeleri kapsamında, sudoers formatı daha da genişletilmiş bir sudo sürümü yazdılar. Bu sürüm daha sonra GNU kamu lisansı altında yayınlandı.

1994 yılında, sudo’yu gayrıresmi olarak CU-Boulder bünyesinde bir süredir geliştirmiş olan Todd Miller, “CU sudo”nun hata düzeltmeleri ve daha fazla işletim sistemi desteği içeren, herkese açık bir sürümünü yayınladı (sürüm 1.3). “CU”, “The Root Group” sürümünden farklılaşmak için eklenmişti.

1995 yılında, Chris Jepeway, sudoers dosyası için yazdığı yeni bir ayrıştırıcıyla katkıda bulundu. Yeni ayrıştırıcının grameri (eskisinin aksine) düzgündü ve hem sudo, hem de visudo ile çalışabiliyordu. (önceleri ayrıştırıcıları birbirinden biraz farklıydı).

1996 yılında, uzun yıllardır boş zamanlarında sudo’yu geliştiren Todd, sudo dağıtımını CU-Boulder ftp sitesinden, kendi domaini olan courtesan.com (“fahişe.com”) adresine taşıdı.

1999′da, “The Root Group” tarafından 1991 yılından beri resmi bir sudo sürümü yayınlanmamış olduğu için (asıl programcılar artık farklı yerlerde çalışıyordu), “CU” öneki düşürüldü. 1.6 sürümünden beri, Sudo’da artık özgün “Root Group” kodundan eser kalmadı ve ISC stili bir lisans altında yayınlanıyor.

2001′de, sudo web sitesi, ftp sitesi ve e-posta listeleri courtesancom’dan sudo.ws adresine taşındı (sudo.org daha öne başkası tarafından tescillenmişti).

2005′te Todd, son on yılda eklenen özellikleri daha iyi destekleyebilmek için sudoers ayrıştırıcısını yeniden yazdı. Yeni sürüm eskisinin bazı sınırlamalarını, sıralama kısıtlamalarını kaldırıyor ve birden çok sudoers dosyası için destek ekliyor.

Sudo, şimdiki haliyle Todd Miller tarafından yönetiliyor.

Todd sudo’yu genişletmeyi ve hataları gidermeyi sürdürüyor.

Özgün Metin:
A Brief History of Sudo

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: ,

Web hizmeti genel olarak “ağ üzerinden erişilebilen ve istenen hizmeti sunan makinede çalıştırılan bir API” olarak tanımlanabilir.

Web hizmetlerini kabaca ikiye ayırmak olası:

  1. Simple Object Access Protocol (SOAP) kullanan geleneksel yöntem.
  2. REpresentational State Transfer (REST) kullanan görece yeni yöntem.

RESTful web hizmetlerini başka bir yazıya bırakarak, bu yazıda SOAP kullanarak basit birer web hizmet sunucusu ve istemcisi geliştirmeyi inceleyeceğiz. Yapacağımız iş, sunucuya e-posta adresi gönderip, sunucudan o e-posta adresiyle kayıtlı kullanıcıyı almaktan ibaret.

SOAP bir çok PHP prorgramcısının “öcü” gibi gördüğü bir protokol. Öyle ki, pek çok deneyimli ve gözüpek programcının bile “SOAP” adını duyunca irkildiklerine, hatta iş uygulamaya geldiğinde bazı durumlarda düpedüz “beceremediklerine” çok tanık oldum. Gerçekten de, bazı gereksiz işletim sistemleri üstünde çalışan bazı web hizmetlerinden GNU/Linux – PHP ikilisiyle hizmet almak, WSDL dosyalarını düzgün oluşturmak her zaman o kadar kolay olmayabiliyor.

Ancak tüm bu dertler sizin için bu yazıyı okuduktan sonra geçmişte kalmış olacak, sayın okur!

Öncelikle buradan NuSOAP kütüphanesini indiriyoruz. NuSOAP, bizim için WSDL oluşturma dahil hemen her işi halledecek.

İndirdiğimiz zip dosyasından iki klasör çıkıyor: lib ve samples. Bizim samples’a ihtiyacımız olmayacak, ancak örnekleri incelemenizde fayda var. Basit uygulamamız için webrootumuz altına yeni bir dizin oluşturup (örneğin Ubuntu ile “/var/www/soapTest”) lib’i bu dizine kopyalıyoruz.

/var/www/soapTest dizini altında üç dosya oluşturacağız:

  1. config.php : ayar dosyası
  2. service.php: SOAP sunucusu
  3. client.php: SOAP istemcisi

Ayrıca uygulamamız büsbütün yavan olmasın diye bir de veri çekeceğimiz MySQL veritabanı bağlantımız olacak. Benim veritabanımın adı “yazboz” ve bu veritabanında “users” isimli örnek basit bir tablom var.

Yapı ve tek satırlık kullanıcı verisi şöyle:

1
2
3
4
5
6
7
8
9
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`email` varchar(100) COLLATE utf8_turkish_ci NOT NULL,
`name` varchar(100) COLLATE utf8_turkish_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_turkish_ci AUTO_INCREMENT=2 ;

INSERT INTO `users` (`id`, `email`, `name`) VALUES
(1, 'test@mailinator.com', 'Georges Moustaki');

Yukarıdaki kodu konsol ya da phpMyAdmin marifetiyle veritabanımıza aktardıktan sonra ayar dosyamızı oluşturalım ve “config.php” ismiyle kaydedelim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

class Config
{
    public $wwwroot , $host , $db , $username , $password;
   
    public function __construct()
    {
        //URL
        $this->wwwroot = 'http://localhost/nusoap';
       
        //MySQL sunucusu
        $this->host = 'localhost';
       
        //veritabanı
        $this->db = 'yazboz';
       
        //MySQL kullanıcı adı
        $this->username = 'root';
       
        //MySQL şifresi
        $this->password = 'sifre';
    }
}

Yeni bir dosya daha oluşturalım ve “service.php” adı ile config.php ile aynı dizine kaydedelim.
Sonra, yeni service.php dosyamızda config sınıfını çağırıp veritabanı bağlantısını yapalım:

1
2
3
4
5
6
<?php

require 'config.php';
$config = new Config();

$conn = new mysqli($config->host , $config->username , $config->password , $config->db);

Artık e-posta adresinden kullanıcı adını döndüren fonksiyonu yazabiliriz:

1
2
3
4
5
6
7
8
9
10
11
function getUserNameByEmail($email)
{
    global $conn;
    $userNameQuery = $conn->query("SELECT name
                                FROM users
                                WHERE `email` = '$email' LIMIT 1"
);

    $fetch = $userNameQuery->fetch_array();
    if(!is_array($fetch)) return 'böyle bir kullanıcı yok';
    return $fetch['name'];
}

Gördüğünüz gibi normalden farklı hiç bir şey yapmıyoruz. Sıradaki iş SOAP server’ı içeri alıp ilklendirmek. Bu da çok basit ve sıradan:

1
2
3
4
5
6
7
8
9
require('lib/nusoap.php');

$server = new soap_server();

//aşağıdaki iki satır Türkçe karakter için gerekli
$server->soap_defencoding = 'UTF-8';
$server->decode_utf8 = false;

$server->configureWSDL('testnamespace', 'urn:testnamespace');

Son olarak yukarıda tanımladığımız fonksiyonu sunucuya kaydedip sunucuyu çalıştıracağız:

1
2
3
4
5
6
7
8
9
10
11
//string olarak email gönderip, sonucu yine string döndüreceğiz.
$server->register("getUserNameByEmail",
                array('email' => 'xsd:string'),
                array('return' => 'xsd:string'),
                'urn:testnamespace',
                'urn:testnamespace#getUserNameByEmail');

// aşağıdaki satır $HTTP_RAW_POST_DATA verisi ile aynı işi görür
$postData = file_get_contents("php://input");

$server->service($postData);

Sunucuyu kodlamayı bitirdik bile!
Sunucu kodumuzun tamamı:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php

require 'config.php';
$config = new Config();

$conn = new mysqli($config->host , $config->username , $config->password , $config->db);

function getUserNameByEmail($email)
{
    global $conn;
    $userNameQuery = $conn->query("SELECT name
                                FROM users
                                WHERE `email` = '$email' LIMIT 1"
);

    $fetch = $userNameQuery->fetch_array();
    if(!is_array($fetch)) return 'böyle bir kullanıcı yok';
    return $fetch['name'];
   
}

require('lib/nusoap.php');

$server = new soap_server();

//aşağıdaki iki satır Türkçe karakter için gerekli
$server->soap_defencoding = 'UTF-8';
$server->decode_utf8 = false;

$server->configureWSDL('testnamespace', 'urn:testnamespace');

//string olarak email gönderip, sonucu yine string döndüreceğiz.
$server->register("getUserNameByEmail",
                array('email' => 'xsd:string'),
                array('return' => 'xsd:string'),
                'urn:testnamespace',
                'urn:testnamespace#getUserNameByEmail');

// aşağıdaki satır $HTTP_RAW_POST_DATA verisi ile aynı işi görür
$postData = file_get_contents("php://input");

$server->service($postData);

Hepsi bu kadar. service.php dosyasını çağırdığınızda (örneğimizde http://localhost/nusoap/service.php) sizin için küçük bir belgelendirmeyi bile otomatik olarak oluşturduğunu göreceksiniz.
Kodu http://localhost/nusoap/service.php?wsdl şeklinde çağırdığınızda da WSDL dosyanız hazır!

Tamam, sunucuyu kodlamak gerçekten kolaymış. İstemci kısmı nasıl olacak pekiyi? Çok daha kısa ve basit olacak!
Boş bir dosya daha açalım ve onu da “client.php” ismiyle, aynı dizine kaydedelim. Ardından sunucu için yaptığımız şekilde config dosyasını çağırıp config nesnesini ilklendirelim:

1
2
3
4
ini_set("soap.wsdl_cache_enabled", "0"); //WSDL cache devre dışı kalsın
require_once 'lib/nusoap.php';
require 'config.php';
$config = new Config();

Bundan sonra yapmamız gereken tek şey, SOAP sınıfını ilklendirip, service.php’de tanımladığımız metodu çağırmak:

1
2
3
4
5
6
$soapClient = new SoapClient($config->wwwroot . '/service.php?wsdl' , array(
    "trace"      => 1,
    "exceptions" => 0));

$name = $soapClient->getUserNameByEmail('test@mailinator.com');
echo $name;

Hepsi bu! İstemci kodunun tamamı:

1
2
3
4
5
6
7
8
9
10
11
<?php
ini_set("soap.wsdl_cache_enabled", "0"); //WSDL cache devre dışı kalsın
require_once 'lib/nusoap.php';
require 'config.php';
$config = new Config();
$soapClient = new SoapClient($config->wwwroot . '/service.php?wsdl' , array(
    "trace"      => 1,
    "exceptions" => 0));

$name = $soapClient->getUserNameByEmail('test@mailinator.com');
echo $name;

http://localhost/nusoap/client.php kodunu çağırdığımızda “Georges Moustaki” yazısını görüyorsak işimiz bitmiş demektir.

Böylece NuSOAP kullanarak bir SOAP sunucusu ve bir de SOAP istemcisi yazmış olduk.
Kolay gelsin!

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , ,

VBulletin en çok beğenilen ve kullanılan forum yazılımlarından biri olma özelliğinin yanında, veri madencilerini de oldukça fazla uğraştıran bir forum olmasıyla da biliniyor.

Bu makalede LF’in cURL tabanlı NetClient kütüphanesini kullanarak VBulletin forumlarından veri çekmeyi inceleyeceğiz.

Not1: NetClient kütüphanesinin çalışabilmesi için sisteminizde php-curl eklentisinin kurulu olması gerekir. Çok kullanılan bir eklenti olduğundan genellikle kuruludur.

Not2: Siz kodun içinde görmeyecek olsanız da, cookie kullanacağımız için LF kurulum ana dizinine apache kullanıcısının yazma izni olmalı.

Örneğimizde VB Forumundan bir alt-forum sayfası içeriğini okumayı amaçlıyoruz. Akış diagramımız kabaca aşağıdaki gibi olacak:

  1. VB forumuna kullanıcı adı ve şifre ile giriş yap
  2. VB security token’ı al.
  3. VB sub-forum sayfasını çağır

Önce Controllerımızı oluşturalım, kullanacağımız private değişkenleri deklare edelim. Daha sonra constructor’ımızda NetClient kütüphanesini yükleyelim ve forum kullanıcı adı, şifre ve  sayfa içeriğini edinmek istediğimiz alt-forum ID’sini belirlediğimiz bir ayar metodu yazalım.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Vbulletin extends LogikitController
{
    private $_forum , $_username , $_password , $_loginUrl , $_loginPageContent , $_securityToken , $_subForumId;
   
    public function __construct()
    {
        parent::__construct();
       
        //NetClient kütüphanesini yükle
        $this->load->systemLibrary('NetClient');
       
        //ayarları yükle
        $this->_config();
       
        //VBulletin forumları için login sayfası
        $this->_loginPage = 'login.php?do=login';
    }
   
   
    private function _config()
    {
        $this->_forum = 'http://www.vbforumumuz.org/'; //hedef forum. sondaki bölü işaretini unutmayalım.
        $this->_username = 'kullaniciAdi'; //forum kullanıcı adı
        $this->_password = 'kullaniciSifresi'; // şifre
        $this->_subForumId = 22; //post listesini almak istediğimiz sub-forumun ID'si
    }
   
}

Yukarıdaki kodu application/controller altına Vbulletin.php adıyla kaydedelim.
Ardından, login işlemini gerçekleştirerek loginden sonra yönlendirileceğimiz sayfanın içeriğini alan private metodu yazalım:

1
2
3
4
5
    private function _doLogin()
    {
        $this->_loginPageContent = $this->NetClient->fetchUrl($this->_forum . $this->_loginUrl , "vb_login_username=" . $this->_username . "&vb_login_password=" . $this->_password . "&s=&do=login&vb_login_md5password=" . $passwordMD5 . "&vb_login_md5password_utf=" . $passwordMD5);
        sleep(1);
    }

Şimdi $this->_loginPageContent içinde login işleminden sonra yönlendirildiğimiz ana sayfanın HTML içeriği var.
Dikkatinizi çekmiştir; işlemden sonra bir saniye bekliyoruz. Bunu yapmadığımız zaman Vbulletin sorun çıkarabiliyor.
Artık Vbulletin forumunda yapacağımız tüm işlemler için bize gerekecek olan security token’ı, anasayfa içeriğindeki
var SECURITYTOKEN = “timestamp-md5token”;
biçiminde bulunan javascriptten çekebiliriz. Bunun için regEx kullanacağız. Yeri gelmişken belirtmekte fayda var: regEx bilmeden olmuyor. Ya iyice regEx öğrenin, ya da benim gibi sürekli cheatsheetlerden kopya çekin!

1
2
3
4
5
    private function _getSecurityToken($content)
    {
        preg_match('%(?:var\sSECURITYTOKEN\s\=\s\")(.*?)(\";)%', $content , $result , PREG_OFFSET_CAPTURE , 3);
        $this->_securityToken = $result[1][0];
    }

Böylece ana sayfa HTML kodundan
var SECURITYTOKEN = ”
ile başlayıp
“;
ile biten kısımda bulacağımız security token’ı da elde etmiş olduk.

Kullanacağımız son araç alt-forum sayfasının içeriğini alan metod olacak:

1
2
3
4
5
    private function _getSubForumContent($subForumId , $page = 1)
    {
        $subForumUrl = $this->_forum . "forumdisplay.php?f=$subForumId&order=desc&page=$page";
        return $this->NetClient->fetchUrl($subForumUrl , 'securitytoken=' . $this->_securityToken);
    }

Artık ana metodumuzu yazabilir ve kodumuzu hazır hale getirebiliriz:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    public function scrapeVBCategory()
    {

        //login işlemini yap ve login sayfası içeriğini $this->__loginPageContent stringine at
        $this->_doLogin();
       
        //security token'ı al
        $this->_getSecurityToken($this->_loginPageContent);
       
        //seçtiğimiz alt forumun birinci sayfasını yükle.
        $subForumPage = $this->_getSubForumContent($this->_subForumId);

        echo $subForumPage;

        //template ve view yüklemeden çık.
        exit;
    }

Gördüğünüz gibi oldukça derli-toplu ve gerçekten çok basit. Kodumuzun tamamlanmış hali:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?php

/**
 * Logikit::Framework
 *
 * Open source development framework for PHP 5
 *
 * @package     Logikit Framework
 * @author      Can Ince
 * @copyright           Copyright (c) 2010, Logikit / Can Ince.
 * @license     http://www.opensource.org/licenses/mit-license.php

 * @link        http://framework.logikit.net
 */


class Vbulletin extends LogikitController
{
    private $_forum , $_username , $_password , $_loginUrl , $_loginPageContent , $_securityToken , $_subForumId;
   
    public function __construct()
    {
        parent::__construct();
       
        //NetClient kütüphanesini yükle
        $this->load->systemLibrary('NetClient');
       
        //ayarları yükle
        $this->_config();
       
        //VBulletin forumları için login sayfası
        $this->_loginPage = 'login.php?do=login';
    }
   
   
    private function _config()
    {
        $this->_forum = 'http://www.vbforumumuz.org/'; //hedef forum. sondaki bölü işaretini unutmayalım.
        $this->_username = 'kullaniciAdi'; //forum kullanıcı adı
        $this->_password = 'kullaniciSifresi'; // şifre
        $this->_subForumId = 22; //post listesini almak istediğimiz sub-forumun ID'si
    }

    public function index()
    {
        //scrapeVBCategory metoduna yönlen.
        $this->scrapeVBCategory();
    }
   
    public function scrapeVBCategory()
    {

        //login işlemini yap ve login sayfası içeriğini $this->__loginPageContent stringine at
        $this->_doLogin();
       
        //security token'ı al
        $this->_getSecurityToken($this->_loginPageContent);
       
        //seçtiğimiz alt forumun birinci sayfasını yükle.
        $subForumPage = $this->_getSubForumContent($this->_subForumId);

        echo $subForumPage;

        //template ve view yüklemeden çık.
        exit;
    }
   
    private function _doLogin()
    {
        //ilk parametre URL, ikinci parametre POST verisi
        $this->_loginPageContent = $this->NetClient->fetchUrl($this->_forum . $this->_loginUrl , "vb_login_username=" . $this->_username . "&vb_login_password=" . $this->_password . "&s=&do=login&vb_login_md5password=" . $passwordMD5 . "&vb_login_md5password_utf=" . $passwordMD5);
        sleep(1);
    }
   
    private function _getSecurityToken($content)
    {
        preg_match('%(?:var\sSECURITYTOKEN\s\=\s\")(.*?)(\";)%', $content , $result , PREG_OFFSET_CAPTURE , 3);
        $this->_securityToken = $result[1][0];
    }
   
    private function _getSubForumContent($subForumId , $page = 1)
    {
        $subForumUrl = $this->_forum . "forumdisplay.php?f=$subForumId&order=desc&page=$page";
        return $this->NetClient->fetchUrl($subForumUrl , 'securitytoken=' . $this->_securityToken);
    }
   
}

// END Vbulletin class

/* End of file Vbulletin.php
   Location: ./system/application/controller/Vbulletin.php */

Kodun tamamlanmış hali yorumlar ve boş satırlar hariç 40-45 satır civarında.
NetClient kütüphanesi, bizim için gerekli cURL ayarlarını yaptı. HTTP yönlendirmelerini takip etti, cookie oluşturdu ve bize yalnız “git şu adrese, şunları post et ve gelen veriyi al” demek kaldı.

Veri madencisi arkadaşların işine yaraması dileğiyle.

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , , , , ,

Futbolla ilgisiz bir 1-0

Bugün bir futbol maçı oynanmış ve Fenerbahçe Galatasaray’ı 1-0 yenmiş. Bir arkadaşım da bunu Facebook durumuna “1-0″ şeklinde taşımış.

Futboldan hemen hiç anlamam. Ara-sıra “Berezilya” milli takımının maçlarını izlerim, o kadar. Bu “1-0″ aklıma müteveffa “Hoca”nın(*) aktardığı bir öyküyü getirdi:

Hoca’nın bir arkadaşı bir satranç turnuvasında oynamaktadır. Ertesi gün oynanacak turda beyazdır ve geceden sabaha kadar, annesinin yorulmak bilmeden taşıdığı çay ve kahvelerin desteğiyle rakibine hazırlanır(*). Saati geldiğinde maça gider ve bir kaç saat sonra eve döndüğünde annesi sorar: “Evladım ne oldu maçın?”

Bizimki gururla “Bir-sıfır!” der.

Anne soruyla yanıtlar: “Evladım bütün gece o kadar çalıştın da ancak bir-sıfır mı yenebildin?” !

Not: Satranç notasyonunda beraberlik “½-½”, beyazların kazancı “1-0″ ve siyahların kazancı “0-1″ şeklinde ifade edilir.

½

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler:

Mongo DB, yeni yeni serpilen fakat şimdiden bir çok kişinin gözdesi haline gelmeyi başarmış bir veritabanı. PHP için de eklentisi mevcut: http://www.php.net/manual/en/intro.mongo.php

Buradan AMD 64 bit için derlediğim Mongo DB .deb paketini edinebilirsiniz.

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , , ,

Düşünmeye Nereden Başlamalı?

Bundan sonra genellikle bir önermenin doğru ve kesin olması için gereken şeyi inceleyecektim; çünkü böyle olduğunu bildiğim bir önerme bulduğuma göre, bu kesinliğin neye dayandığını da bilmem gerektiğini düşündüm. O düşünüyorum öyleyse varım’da düşünmek için varolmak gerektiğini çok açık görmemden başka bana doğruyu söylediğime güvenmemi sağlayan hiçbir şeyin olmadığını görerek, çok açık ve çok seçik kavradığım şeylerin hep doğru olduğunu, ama yalnızca seçik olarak kavradığımız şeylerin neler olduğunu iyi belirlemekte bazı güçlükler bulunduğunu genel kural olarak alabileceğim yargısına vardım.

Rendekar(*), “Zagon üzerine öttürme”(*)

Rendekar, su katılmamış bir kuşkucu yöntem izleyerek “kesin ve doğru” bir önerme arar ve yanıtı “Düşünüyorum öyleyse varım” önermesinde bulduğunu düşünür.

(Konuya girmeden hemen Kahraman Olgaç patentli bir dedikoduyu aktarayım (“Siz yaparsınız ‘dedikodu’ olur, biz yaparız ‘biyografi’ olur” Murat Bardakçı) : Olgaç’a göre Rendekar “Bu Fransız milleti çok disiplinsiz. Kimse şeyinin keyfinden başka şey düşünmüyor. Böyle ortamda fikir üretmem olanaksız.” diyerek savaşmakta olan orduya yazılır. Ancak orada da “Savaşta çok gürültü  oluyor; kafamı toplayamıyorum” şeklinde ifadesini bulan bir dertten musdarip olur ve son çare olarak İsveç Kraliçesi Kristina’nın(*) daveti üstüne İsveç’e, kraliçeye felsefe dersleri vermeye gider.

İsveç Kraliçesi Kristina ve Rendekar. Wikipedia arşivinden.

İsveç adetlerine göre gece sarayda kraliyet ailesi mensubu olmayan kimse kalamamaktadır ve Rendekar da istisna değildir. Dertler bununla bitmez: Kraliçe şımarık bir tiptir ve dersleri sabahın dördü gibi tuhaf saatlerde almak ister. Saray ile kenti ayıran büyük vadinin üstüne bir asma köprü kurulmuştur ve Rendekar bu köprüyü sabaha karşı dörtte geçmek zorundadır. Gel zaman-git zaman, İsveç soğuğunda asma köprüyle mücadele eden Rendekar, sonunda zaturree olur ve bu hastalıktan kurtulamayarak yaşamını yitirir. (Ben Olgaç’ın yalancısıyım, elçiye zeval olmaz!)

Diğer bir dedikodu da Rendekar’ın aslında hastalıktan ölmediği, Stokholm’de çalışan bir misyoner olan Jacques Viogué tarafından, filozofun radikal görüşlerinden fazlaca etkilenen protestan kralın en sonunda din değiştireceği korkusuyla, aldığı komünyona arsenik katmak yoluyla zehirlendiği şeklinde.

Bir sayfa yazdığım halde hala konuya giremediğime göre, en azından düşünmeye bu şekilde başlamamak gerektiğini anlamış oluyoruz! Konuya dönelim.

Rendekar’ın “Cogito Ergo Sum”a nasıl vardığını görmek için önce izlediği yöntemi kısaca anımsamak yerinde olur:

1. Yalnız emin olduğun şeyleri kabul et.

2. Sorunu gerektiği kadar küçük parçalara böl.

3. Çözümlemeye en kolay parçalardan başla.

4. Parçaların çözümlerinin mümkün olduğu kadar tam bir listesini yaparak sorunun tamamını çöz.

Bu Rendekar’ın yolu. Ben de “düşünmeye nereden başlamalı?” sorusunu sorarken dahi, aynı zamanda bir düşünme yöntemine gereksinim duyduğumu da söylemiş oluyorum ve böylece bu sorunun yanıtını da vermiş oluyorum:

Düşünmeye, bir düşünme yöntemi belirleyerek başlamalı.

Elimde bir referans noktası olmadan fikirlerimin doğru ve yöntemlerimin sağlıklı olup olmadığını bilemem. Kesin olarak bilebildiğim tek şey, tüm bunları kendime söylerken bir dil kullanıyor olduğum. Dil ise kavramların, anlam alanlarının bir araya gelmesi sonucunda oluşuyor. Anlam alanlarının herkes için, ya da farklı zamanlarda kendim için hep aynı olduğunu nereden bilebilirim, ya da bilebilir miyim? Bu kesinliği sağlayamazsam, çözümlerimi üstüne oturtacağım temelden yoksun kalmış olacağım. Başkalarına ya da kendime bir şey anlatırken, anlattığımın anlattığım gibi anlaşıldığını nasıl bilebilirim?

Yine Rendekar’a başvurayım:

Sağduyu dünyanın en iyi paylaşılmış şeyidir: çünkü her kişi ondan çok iyi pay almış olduğunu düşünür, her şeyden çok güç hoşnut olanlar bile kendilerinde bulunan sağduyudan daha çoğunu istemeye alışık değildirler. Bu konuda herkesin yanılması olası değildir: ama bu daha çok aslında sağduyu ya da us denilen iyi yargılama ve doğruyla yanlışı ayırt edebilme gücünün doğal olarak tüm insanlarda eşit olduğuna tanıklık eder; böylece görüşlerimizdeki çeşitlilik kimilerinin öbürlerinden daha ussal olmasından gelmez, düşüncemizi değişik yollardan götürüyor ve aynı şeyleri düşünmüyor olmamızdan gelir. Çünkü iyi bir zihne sahip olmak yetmez, önemli olan onu iyi kullanmaktır. En büyük ruhlar en büyük erdemlere olduğu kadar en büyük kötülüklere yatkındırlar; ancak çok yavaş yürüyenler her zaman doğru yolu izliyorlarsa koşanlardan ve doğru yoldan uzaklaşanlardan daha çok ilerleyebilirler.

Kendi payıma ben zihnimin başkalarının zihninden daha yetkin olabileceğini düşünmedim, hatta çok zaman düşüncem başkalarınınki kadar keskin, imgelemim başkalarınınki kadar açık ve seçik, belleğim başkalarınınki kadar geniş ve aydınlık olsun istedim. Zihnin yetkinliğini sağlayan daha başka nitelikler bilmiyorum; çünkü usun ya da sağduyunun bizi insan kılan ve hayvanlardan ayıran tek şey olduğu kadar onun tümüyle her kişide varolduğuna inanmak ve bu yolda aynı türün bireylerinin biçimleri ya da doğaları arasında değil, ancak raslantıları arasında çokluk ve azlık bulunduğunu söyleyen filozofların ortak görüşünü izlemek istiyorum.

Rendekar bana referans sorunuyla uğraşabilmek için bir silah sağlamış gibi görünüyor: Sağduyu. Yine de “inanmak … istiyorum” ifadesinde vücut bulduğu şekliyle, kendi bile bu silahın yeterince kudretli olup olmadığından emin değil. Sağduyu, güvenilir olduğu kesinleşirse, oldukça güçlü bir referans oluşturabilir. Acaba Rendekar’ın fikrini destekleyecek bir şeyler bulabilir miyim?

- Rendekar’ın “sağduyuya inanmak istediğini” anladığımı ve yukarıdaki ifadesini bir kez daha okursam yine aynı şekliyle ve aynı şekilde anlayacağımı biliyorum. Bu ifadeye α diyelim.

- Bu yazıyı okuyan bir kişi (ya da bizzat ben) “α ifadesinin senin için doğru olduğu yönündeki düşüncen yanlış” şeklinde bir eleştiri getirse bile, bu eleştiriyi yapabilmek için en azından benim α ifademi anlamış olacaktır.

- Böylece, artık başkalarının ya da benim farklı zamanlardaki hallerimin, (şimdilik kaydıyla) bazı önermeleri anlayabildiğimizi kesin olarak biliyorum. ve bu kesinliğin nedeninin sağduyu olduğuna da emin olabilmiş oluyorum.

Demek ki, şimdi elimde en azından anlam alanları, anlam alanlarını kullanarak oluşturabileceğim ya da karşılaşacağım önermeler, ve bu önermeleri yargılayabilmek için de sağduyu var.

Düşünmeye bu yöntemi kullanarak, anlam alanlarını incelemekten başlayabilirim.

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Georges Moustaki – Giriş

Yıllarımı bir anlamda beraber geçirdiğim adam Georges Moustaki ya da Jorj Baba. Gençlik günlerimde Gündoğan’da gitar çaldığım barda, CD’den çalan müziği duyup, elimdeki kadehi bırakıp CD kapağına bakmak için sahildeki barın küçük kulübesinden içeri girdiğim günden bu yana hesapça onaltı yıl geçmiş.

Tanıştığım anın bende bıraktığı izden olacak; en neşeli şarkısı bile, ıssız bir sahilin yalnız hüznünün ve sakin rüzgarlarının bir kadeh şaraba dolup bedenime akması gibi gelir. O gün çalan parça “Ma liberté” idi.

Bu şarkının sözleri ve Türkçe çevirisi burada var.

O günlerde bana öğretilen ve o vakitlere kadar yaşamam istenilen hayattan yeni çıkmış, yaşamayı istediğim hayatı öğreniyordum ve Jorj Baba’nın şarkıları bana “işte böyle yaşayacaksın!” diyordu. Düşlediğim günleri düşlemiş, geceleri geçirmiş ve şimdi bana anlatıyordu. Farilya’nın sessiz koyunda öyle saatler oluyordu ki, bir Jorj’un bir de benim sesimiz duyuluyordu kıyıyı bebeğini sever gibi okşayan dalga sesleri dışında. Bir an “Fugue En La Mineure” ile irkiliyordum, sonra bir vakit geçiyordu bir bakıyordum kayıklar, uzun yolculuktan yıpranmış, hala dalgakıranın sakin sularında dinleniyorlardı.

Şarkılarının bazıları daha ilk günden tanıdık gelmişti. Tanju Okan’ın söylediği şarkılardan bir-ikisinin de “ilk hallerini” böylece öğrenmiş oldum:

Nasıl da geçti yıllar o günlerin arasından…

Zamanın iki katmanı var. Biri ağır ağır ilerlerken, diğeri anıların hızla geçmesini izleyerek arka arkaya çekilmiş bir kaç kare fotoğraf gibi. Bir ay öncesi çok uzak gelirken Jorj Baba’yı ilk duyduğum gün o kadar yakın ki.
Zamanın ağır geçen katmanında yavaş yavaş “saz arkadaşlarını” da tanımak fırsatı buldum: Manos Hadjidakis, Georges Dalaras, Mikis Theodorakis ve diğerleri. Hepsi başka yazıların konusu olmaya amade.

Jorj Baba hakkında söylenecek her söz “devamı var” diye bitirilmeli. Bu yazı bir gün devam etmeli.

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler:

Logikit::Framework yazılarımı LF blogunda yayınlıyorum ancak Türkçe belgelendirmeye de gereksinim duyuluyor. Bu nedenle LF’le ilgili Türkçe makaleleri bu blogda yayınlıyorum.

Bu makalede “Selectbox bileşen seçeneklerini veritabanından gelen veriyle doldurmak” üstüne çalışacağız.
LF ve MVC örüntüsü üstüne deneyimli kişiler için “Özet” bölümü yeterli olmakla birlikte, “yeni ısınan” arkadaşlar için ayrıntılı açıklamaları da bulacaksınız.

Özet:
Aşağıdaki metodu Controller’ımıza ekliyoruz. Çağırılan model, form ve view ile kullanılan veritabanı tablo yapısını “Ayrıntılar” kısmında bulabilirsiniz.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public function mySelectBoxTest()
{
//formu ilklendir
$this-&gt;load-&gt;form('MySelectBoxTestForm');

//modeli ilklendir
$this-&gt;load-&gt;model('TestModel');

//modelden kategorileri id =&gt; name yapısında bir array olarak al
$categoryNames = $this-&gt;UploaderModel-&gt;getCategories();

//formda category ismiyle tanımlanmış selectbox'ın içini veriyle doldur
foreach($categoryNames as $key =&gt; $val)
{
$optArray = array($key =&gt; $val);
$this-&gt;CategorySelectForm-&gt;addOption('category' , $optArray);
}

//id'si 1 olan kategoriyi seçili getir
$this-&gt;CategorySelectForm-&gt;setSelected('category' , '1');

//formu oluştur
$viewData['formItems'] = $this-&gt;MySelectBoxTestForm-&gt;renderAll();

// form verisini view'a geç ve view'u çağır
$viewData = array();
$this-&gt;load-&gt;view('categoryselect' , $viewData);
}

Ayrıntılar:

MySQL kullandığımızı varsayarak veritabanı yapımız:

1
2
3
4
CREATE TABLE `categories` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 100 ) NOT NULL
) ENGINE = MYISAM ;

Controller’ımızın adı “Test” olsun:

1
2
3
4
5
6
7
8
class Test extends LogikitController
{
public function __construct()
{
parent::__construct();
}

}

Yukarıdaki kodu application/controller altına “Test.php” adıyla kaydedelim.

Sırasıyla modelimizi ve formumuzu oluşturalım.

1
2
3
4
5
6
7
class TestModel extends LogikitModel
{
public function __contruct()
{
parent::__contruct();
}
}

Bu modelimiz. Yukarıdaki kodu /application/model altına “TestModel.php” adıyla kaydedelim ve formumuza geçelim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MySelectBoxTestForm extends LogikitForm
{
public function __construct()
{

$this-&gt;addItem(array(
'name' =&gt; 'category' ,
'type' =&gt; 'selectBox' ,
'value' =&gt; NULL ,
'validation' =&gt; array('notNull') ,
'properties' =&gt; ''));

$this-&gt;addItem(array(
'name' =&gt; 'Go' ,
'type' =&gt; 'submit' ,
'value' =&gt; 'Gönder' ,
'validation' =&gt; NULL ,
'properties' =&gt; 'class="submit1"'));
}
}

Böylece bir selectbox ve bir submit butonundan oluşan formumuzu tanımlamış olduk. Yukarıdaki kodu da application/form/Test altında “MySelectBoxTestForm.php” adıyla kaydedelim.
Böylece view hariç, gerekli dosya ve nesnelerin tamamını hazırlamış olduk.

Bir sonraki adımda, controller’ımıza dönelim (application/controllers/Test.php) ve kullanacağımız metodu yazalım:

1
2
3
4
public function mySelectBoxTest()
{

}

Şimdi de yukarıda oluşturduğumuz form ve modelimizi yükleyelim:

1
2
3
4
5
6
public function mySelectBoxTest()
{
$this-&gt;load-&gt;form('MySelectBoxTestForm');

$this-&gt;load-&gt;model('TestModel');
}

Bu andan itibaren form ve model nesneleri ile bu nesnelere bağlı metodlar, controller’ımız içinden $this->TestModel->method() ve $this->MySelectBoxTestForm->method() şeklinde çağırılabilir durumda.

Modelimize (application/model/TestModel.php) geri dönelim ve selectbox’ımızı doldurmak için gerekli veriyi array olarak veritabanından çeken metodu yazalım:

1
2
3
4
public function getCategories()
{
return $this-&gt;result("SELECT id , name FROM categories");
}

Controller’ımızdaki mySelectBoxTest() metoduna dönelim ve selectbox’ı veriyle dolduran kodu ekleyelim:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public function mySelectBoxTest()
{
$this-&gt;load-&gt;form('MySelectBoxTestForm');

$this-&gt;load-&gt;model('TestModel');

$categoryNames = $this-&gt;UploaderModel-&gt;getCategories();
foreach($categoryNames as $key =&gt; $val)
{
$optArray = array($key =&gt; $val);
$this-&gt;CategorySelectForm-&gt;addOption('category' , $optArray);
}

//id'si 1 olan kategoriyi seçili getir
$this-&gt;CategorySelectForm-&gt;setSelected('category' , '1');
}

Contoller’daki son işimiz, form verisini view’a aktarmak olacak ve bu işlemden sonra controller’ın son hali aşağıdaki gibi olmalı:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public function mySelectBoxTest()
{
$this-&gt;load-&gt;form('MySelectBoxTestForm');

$this-&gt;load-&gt;model('TestModel');

$categoryNames = $this-&gt;UploaderModel-&gt;getCategories();
foreach($categoryNames as $key =&gt; $val)
{
$optArray = array($key =&gt; $val);
$this-&gt;CategorySelectForm-&gt;addOption('category' , $optArray);
}

//id'si 1 olan kategoriyi seçili getir
$this-&gt;CategorySelectForm-&gt;setSelected('category' , '1');

//formu oluştur
$viewData['formItems'] = $this-&gt;MySelectBoxTestForm-&gt;renderAll();

// form verisini view'a geç ve view'u çağır
$viewData = array();
$this-&gt;load-&gt;view('categories' , $viewData);
}

ve son olarak view dosyasını oluşturarak işimizi bitirelim:

1
2
3
4
5
6
<div id="formDiv" style="display: none;">echo formOpenMultipart('form1' , siteUri(getController() . '/formIslemeMetodu') , 'POST', 'onsubmit="return false;"');
echo $secondFormItems['category'] . "
"
;
echo $secondFormItems['Go'] . "
"
;
formClose();</div>

Bu dosyayı da application/view/categories.php adıyla kaydedince işimiz bitmiş oluyor.

Artık kodu çalıştırabiliriz:

http://www.testsunucunuz.com/LFDizini/Test/mySelectBoxTest

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , , ,

zurih 1953

Kendi de turnuvada oynamış olan GM David Bronstein’in yazdığı “Zürih 1953″ kitabı geçtiğimiz ay içinde TSF yayınlarından Büyük Üstat Abdullah Sözen (BÜAS) çevirisiyle çıktı. Turnuva BÜAS yorumuyla “Tüm zamanların gelmiş geçmiş en iyi turnuvası” ve kitapta turnuvada oynanmış partilerin tamamı analizli şekilde yer alıyor.

Hediyesi 20 TL olan kitabı edinmek için Türkiye Satranç Federasyonu Web Sitesi‘nden iletişime geçebilirsiniz.

Paylaş:
  • Print
  • FriendFeed
  • Twitter
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • Blogplay
  • DZone
  • LinkedIn
  • MySpace
  • Ping.fm
  • Reddit
  • StumbleUpon
  • Technorati

Etiketler: , , ,

« Older entries