Genel

Para Yönelimli Programlama (PYP)

Para Yönelimli Programlama (PYP)Para Yönelimli Programlama, programlama eyleminin para ekseninde gerçekleştirildiği yazılım geliştirme faaliyetidir. Geliştiriciler arasında “Dark Side”, “Para Çokomel”, “Parasıyla değil mi ?” sözleriyle de ifade edilen bu yaklaşımı, bu yazıda birlikte irdeleyeceğiz.

PYP, aslında hepimizin bildiği algülüm vergülüm esasına dayanan ticari bir faaliyetten başka birşey değildir. İşverenin, yazılım geliştirme ihtiyaçlarının karşılanması doğrultusunda aylık periyodlarla yaptığı maaş ödemesine istinaden, geliştiricinin işveren beklentilerini makul sürelerde karşılaması esasına dayanır.

Adından da anlaşılacağı üzere programlama faaliyeti asla mantık ekseninde gerçekleştirilmez. İşin içeriği, yaratacağı prestij kaybı, görsel/mantıksal/fonksiyonel problemler geliştiriciyi ilgilendirmez. Ödemeler düzgün gerçekleştiği sürece müşteri her zaman haklıdır. Ödemenin aksaması, rakip veya farklı sektördeki firmanın yapacağı X+1 lik ücret teklifi mevcut firmayla olan ilişkilerin aynı gün sonlanmasına neden olabilir. (Mevcut firmanın x-1 lik personeli temin edebilmesi durumunda mevcut personelin işine aynı gün sonverebildiği gibi.)

PYP uygulayan geliştiricinin egosu ve fikri olmaz. Şayet fikri varsa ısrarcı olmaz. Tartışmaya girmez. Alınacak nihayi cevap her zaman için “Ok o zaman o şekilde yapalım.” şeklindedir. Kıdeme bağlı olarak “parasıyla değil mi ?” gibi türlü varyasyonların da duyulması mümkündür.

Para Yönelimli Programlama (PYP)Bu tip geliştiriciler, yedi köyle barışık denilecek cinsten insanlardır. Sistemcisinden, proje yöneticisine ve diğer tüm ekip arkadaşlarıyla tam anlamıyla uyum içindedir. Asla laf taşımaz. İşinin yürümesi için herşeyi yapar. Nabza göre şerbet verir. İtin köpeğin önde gidenidir. İş bitiricidir. Üretimin süreci ve sonucu göz önünde bulundurulduğunda aslında her PYP geliştiricisi DGYP ve GGYP yaklaşımlarını da benimser. (Bkz. Daya Geç Yönelimli Programlama (DGYP). Bkz. Goygoy Yönelimli Programlama (GGYP)) Projedeki mevcut özellik defalarca kaldırılıp eklense de asla üşenmez, yorum getirmez. İşverenin kendisine bunun için para ödediğinin bilincindedir.

PYP uygulayan geliştirci, bir projenin öyle veya böyle yayına çıkabilmesi adına her firmada en az birkaç tane bulunması gereken geliştirici tipidir. Ego tatminin yaşanacağı yer işyeri olmadığından işverenin yazılım geliştiricinin egosunun tatmin etmek için iş beğendirmek veya her an yeni bir challange yaratmak gibi bir mecburiyeti yoktur. İşveren para karşılığında geliştiricinin bilgisini ve zamanını satın alır.

Pahalıdır. Standart bir yazılım geliştiriciyi X liraya, bir rockstar ı X+1 liraya çalıştırabilirsiniz. Deneyimli bir PYP geliştiricisini X+2 liraya çalıştıramazsınız. Şayet anlaşsanız bile daha iyi şartları sağlayan başka bir firma bulduğu gün yerinde yeller eser.

Sadakat ancak hayvanlarla insanlar arasında yaşanabilecek bir duygudur. Bu nedenle firmanın geliştiriciden sadakat beklentisi son derece yersizdir. PYP geliştiricisi, yukarıda belirtilen ücret politikası nedeniyle asla herhangibir projede tek adam olarak konumlandırılmamalıdır. Çünkü her an herşey olabilir :)

Genel

CSV verisinin MySQL Shell Üzerinden Veritabanına Aktarılması

MySQL shell arabirimi ile satır adedi yüksek verilerinizi ekstra bir betik yazmaksızın SQL komutları ile hızlıca içeri alabilirsiniz.

Aşağıdaki örnekde görülen dosyada 1 başlık, 8022 veri satırı bulunmaktadır.

LOAD DATA LOCAL INFILE 'hede-ticaret.csv'
INTO TABLE catalog_stock 
FIELDS TERMINATED BY ',' ENCLOSED BY '\"' 
LINES TERMINATED BY '\n' STARTING BY ''
IGNORE 1 LINES
(@ignore, code, name, @ignore, @ignore, brand, status, @ignore, provider)
SET status = 0, `provider`='hede'; 

Dilerseniz yukarıdaki örneği birlikte satır satır inceleyelim.

LOAD DATA LOCAL INFILE 'hede-ticaret.csv'

Verilerin hangi dosyadan okunacağını belirttik.

INTO TABLE catalog_stock 

Okunan verilerin hangi tabloya yazılacağını belirttik.

FIELDS TERMINATED BY ',' ENCLOSED BY '\"' 

Yukarıdaki TERMINATED BY ifadesi ile her bir alanın hangi karakter ile sonlandığını (bunu alan ayracı olarak da ifade edebiliriz.), ENCLOSED BY ifadesi ile alanın kapsayıcı karakterini tanımlıyoruz. Bu tanımlama herhangibir alanın içeriğinde alan ayracını içeren bir veri varsa parser ın bunun aslında alanın içeriğine dahil olduğunu anlamasını sağlıyor.

LINES TERMINATED BY '\n' STARTING BY ''

Her bir satırın \n karakteri ile sonlandığını boş metin ile başladığını belirttik.

IGNORE 1 LINES

Örnekde kullandığım dosyanın ilk satırının başlık/alan isimlerini içerdiğini belirtmiştim. Yukarıdaki tanımlama ile ilk satırı yok sayıyoruz.

(@ignore, code, name, @ignore, @ignore, brand, status, @ignore, provider)
SET status = 0, `provider`='hede'; 

Verdiğim örnekde veritabanındaki alan sayısı ve sırası csv dosyasınınkinden farklı olduğu için yukarıdaki tanımlamayla csv dosyasının ilk kolonundan başlayarak veritabanındaki hangi alanla eşleşeceği bilgisini tanımlıyoruz. Ayrıca SET komutu ile de status ve provider alanları için varsayılan bir değer yazdırıyoruz.
Yukarıda gördüğünüz @ignore ifadesi csv dosyasında bulunan, ancak veritabanında karşılığı olmayan alanlar için csv satırından gelen veriyi ignore isimli bir değişkene göndererek sıradaki alanla ilgili eşleştirmenin pas geçilmesini sağlıyor.

Son olarak yukarıdaki komutların çıktısı aşağıda görüldüğü gibidir.

Query OK, 8022 rows affected, 8022 warnings (0.16 sec)
Records: 8022  Deleted: 0  Skipped: 0  Warnings: 8022

Gerçekleştirdğiniz içe alım işlemi ile ilgili hataları görmek için SHOW WARNINGS komutunu kullanabilirsiniz.

SHOW WARNINGS LIMIT 0,10;

Sonuç:

+---------+------+----------------------------------------------------------------------------+
| Level   | Code | Message                                                                    |
+---------+------+----------------------------------------------------------------------------+
| Warning | 1262 | Row 1 was truncated; it contained more data than there were input columns  |
| Warning | 1262 | Row 2 was truncated; it contained more data than there were input columns  |
| Warning | 1262 | Row 3 was truncated; it contained more data than there were input columns  |
| Warning | 1262 | Row 4 was truncated; it contained more data than there were input columns  |
| Warning | 1262 | Row 5 was truncated; it contained more data than there were input columns  |
| Warning | 1262 | Row 6 was truncated; it contained more data than there were input columns  |
| Warning | 1262 | Row 7 was truncated; it contained more data than there were input columns  |
| Warning | 1262 | Row 8 was truncated; it contained more data than there were input columns  |
| Warning | 1262 | Row 9 was truncated; it contained more data than there were input columns  |
| Warning | 1262 | Row 10 was truncated; it contained more data than there were input columns |
+---------+------+----------------------------------------------------------------------------+

Yukarıdaki örnekde kullandığım csv dosyası veritabanındaki tabloda yeralan alan sayısından daha fazla alan içeriyordu. Bu nedenle her bir satır için “Row N was truncated; it contained more data than there were input columns” hatasını aldım.

Karşılaşılabilecek Problemler:

ERROR 1148 (42000): The used command is not allowed with this MySQL version

LOAD DATA komutu metin dosyasını istemci makinede arayacaktır. Ancak bu durum bazı güvenlik sorunlarına neden olabileceği için mysql client, –local-infile=1 parametresi ile çalıştırılmalıdır.

LOAD DATA komutu ile ilgili diğer detaylar için bu dökümanı inceleyebilirsiniz.

Genel

__getattr__ vs. __getattribute__

__getattr__ Kullanımı:
__getattr__, uygulamada bir sınıfın varolmayan bir özelliğine ulaşılmak istendiğinde çağırılen bir magic metoddur.

class Order(object):
    def __init__(self, order_id=None, amount=None, currency=None, *args, **kwargs):
        self.order_id = None
        self.amount = amount
        self.currency = currency

    def __getattr__(self, attr):
        print "%s is called" % attr


order = Order(order_id='00001', amount=100, currency='TRL')
print order.amount
print order.original_amount


Çıktı:

100
original_amount is called
None

__getattribute__ Kullanımı:
__getattribute__, uygulamada bir sınıfın herhangibir özelliğine ulaşılmak istendiğinde çağırılen bir magic metoddur.

class Order(object):
    def __init__(self, order_id=None, amount=None, currency=None, *args, **kwargs):
        self.order_id = None
        self.amount = amount
        self.currency = currency

    def __getattribute__(self, attr):
        print "%s is called" % attr


order = Order(order_id='00001', amount=100, currency='TRL')
print order.amount
print order.original_amount

Çıktı:

amount is called
None
original_amount is called
None
Genel

Symfony2 Kullanıcıları İçin Twig Eklentisi Geliştirme

Bu yazıda Symfony2 ile bundle olarak gelen TWIG template motoru için basitce nasıl eklenti geliştirebileceğimizi inceleyeceğiz.

Eklentiler Ne İşe Yarar ?

TWIG Eklentileri template içerisinde özel olarak geliştirdiğiniz fonksiyonlar, filtreler ve global değişkenleri kullanabilmenize olanak sağlar.

Ne Zaman Eklentiye İhtiyaç Duyulur ?

Eklentiler sıklıkla önyüzde göstermek istediğiniz bilgiler, template context’ ine değişken gönderek yapmak zorunda olduğunuz kontrolleri ve bundan kaynaklanan kod tekrarlarını önlemek için kullanılır. Aşağıda twig eklentisi kullanımına örnek durumlardan biri görülmektedir.

Örnek Durum:

Ekrana fiyat bastırmamız gereken her durumda sistem kurunu çekip önyüzde göstermemiz gerekiyor.

Hatalı Çözüm 1:

Hardcoded olarak kuru template’de belirtir, kur değişiminde tüm templateleri güncelleriz :)

...
{{ product.price }} TL
...

Hatalı Çözüm 2:

İlgili controller aksiyonunda sistem kurunu çeker, template context’ine iletiriz. Ancak bu işlemi fiyat geçen her aksiyonda yapmamız gerekir.
company/CatalogBundle/Controller/ProductController.php:

	<?php
	class ProductController extends Controlller
	{
		//...
		public function detailAction($productId)
		{
			//...
			// $product = ...
			// $configuration = ...
			//..
			$currencySymbol = $configuration->system->currencySymbol;
			return $this->render('CompanyCatalogBundle:Product:detail.html.twig', array(
				'product' => $product,
				'currencySymbol' = $currencySymbol
			));
		}
		//...
	}

company/CatalogBundle/Resources/views/Product/detail.html.twig:

...
{{ product.price }} {{ currencySymbol }}
...

Eklenti Kullanarak Gerçekleştirebileceğiniz Doğru Çözüm:

Aşağıda gördüğünüz üzere kendi geliştirdiğimiz twig eklentisindeki price filtresini kullanarak ekrana “25.00 TL” şeklinde biçimlendirilmiş ve güncel sistem kurunu içeren bir çıktı basmak son derece basit.

...
{{ product.price | price }}
...

TWIG Eklentisi Geliştirmek

TWIG Eklentileri, aşağıdaki arayüzden görebildiğiniz üzere template tarafında kullanabileceğiniz fonksiyonlar, global değişkenler ve filtreler içerebilmektedir.

interface Twig_ExtensionInterface
{
    /**
     * Initializes the runtime environment.
     *
     * This is where you can load some file that contains filter functions for instance.
     *
     * @param Twig_Environment $environment The current Twig_Environment instance
     */
    function initRuntime(Twig_Environment $environment);

    /**
     * Returns the token parser instances to add to the existing list.
     *
     * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
     */
    function getTokenParsers();

    /**
     * Returns the node visitor instances to add to the existing list.
     *
     * @return array An array of Twig_NodeVisitorInterface instances
     */
    function getNodeVisitors();

    /**
     * Returns a list of filters to add to the existing list.
     *
     * @return array An array of filters
     */
    function getFilters();

    /**
     * Returns a list of tests to add to the existing list.
     *
     * @return array An array of tests
     */
    function getTests();

    /**
     * Returns a list of functions to add to the existing list.
     *
     * @return array An array of functions
     */
    function getFunctions();

    /**
     * Returns a list of operators to add to the existing list.
     *
     * @return array An array of operators
     */
    function getOperators();

    /**
     * Returns a list of global variables to add to the existing list.
     *
     * @return array An array of global variables
     */
    function getGlobals();

    /**
     * Returns the name of the extension.
     *
     * @return string The extension name
     */
    function getName();
}

Kullanıcılar tarafından geliştirilecek olan eklentiler, Twig’in bu arayüzü uyarlayan Twig_Extension sınıfını extend eden bir sınıf şeklindedir. Yapılacak geliştirmeye bağlı olarak arayüzdeki ilgili metodlar ezilerek template tarafında kullanacağımız fonksiyon, filtre veya global değişken ile ilgili geliştirmeyi yapabiliriz.

Örnek twig eklentisi sınıfı:

<php
class CatalogExtension extends \Twig_Extension
{
	public function getFilters()
	{
		return array(
			//...
		);
	}
}

Arayüzde görülen her bir metod, filtre, fonksiyon veya global değişkenin adını ve çalıştıracağı callback ile ilgili bilgileri içeren bir dizi dönmelidir.
Company/CatalogBundle/Twig/Extension/CatalogExtension.php:

<php
namespace Company\CatalogBundle\Twig\Extension;

class CatalogExtension extends \Twig_Extension
{
	public function getName()
	{
		return 'catalog_extension';
	}

	public function getFilters()
	{
		return array(
			new \Twig_SimpleFilter('price', array($this, 'priceFilter')),
		);
	}

	public function priceFilter($price)
	{
		//..
		// $configuration = ...
		$currencySymbol = $configuration->system->currencySymbol;
		return sprintf("%s %s"
			number_format($price, 2, ".", ","),
			currencySymbol);
	}
}

Eklentimizi kullanabilmek için servis olarak kaydediyoruz.
Company\CatalogBundle\Resources\config\services.yml:

services:
	comapny.catalog.twig.extension.catalog:
		class: Company\CatalogBundle\Twig\Extension\CatalogExtension
        tags:
            - { name: twig.extension }

Son olarak geliştirdiğimiz eklentideki filtreyi nasıl kullandığımızı tekrar hatırlayalım.

...
{{ product.price | price }}
...

Diğer kullanım şekilleri ile ilgili detaylı bilgi için bu sayfayı ziyaret edebilirsiniz.

Genel

Symfony2 Projelerinde Hata Ayıklama İşleminin PHPStorm Üzerinde Gerçekleştirilmesi

Symfony2 projenizin hata ayıklama işlemlerini PHPStorm IDE üzerinde yürütmek için aşağıdaki işlemleri gerçekleştirmelisiniz.

  • Tarayıcı XDebug eklentisinin yüklenmesi (Google Chrome için)
  • Geliştirme ortamında XDebug eklentisinin kurulması ve konfigüre edilmesi
  • PHPStorm IDE’nin konfigüre edilmesi
  • Uygulamada Gerekli Değişikliklerin Gerçekleştirilmesi
  • Hata Ayıklama Moduna Geçiş

Tarayıcı XDebug Eklentisinin Yüklenmesi

https://chrome.google.com/webstore/detail/xdebug-helper/eadndfjplgieldjbigjakmdgkmoaaaoc adresini ziyaret ederek Google Chrome için XDebug eklentisinin kurulumunu gerçekleştirebilirsiniz.

Geliştirme ortamında XDebug eklentisinin kurulması ve konfigüre edilmesi

  • Aşağıdaki komutu çalıştırarak PHP için XDebug eklentisinin kurulumunu gerçekleştirin.

                $ sudo apt-get install php5-xdebug
            
  • /etc/php5/cli/conf.d/xdebug.ini isimli bir ini doesyası oluşturarak aşağıdaki içeriği kaydedin.

                xdebug.remote_enable = 1
                ;PHP-FPM 9000 portunu kullandigi icin 9009 portunu belirledik.
                xdebug.remote_port = 9009
                xdebug.idekey = PHPSTORM
            

PHPStorm IDE’nin konfigüre edilmesi

  • Run menüsünden Edit Configuration seçeneğine tıklayın.
  • Yeni bir debugger profili oluşturmak için pencerenin sol üst kısmındaki + işaretine tıklayarak açılan menüden PHP Remote Debug seçeneğine tıklayın.
  • name alanına yeni oluşturduğunuz profil için bir isim tanımlayın ve ide key (session id) alanına xdebug konfigürasyonunda xdebug.idekey için tanımladığınız PHPSTORM değerini girin.
  • Servers isimli dropdown listenin yanındaki butona basınız.
  • Symfony2 development sunucunuzu sunucu listesine eklemek için pencerenin sol üst kısmındaki + işaretine tıklayın.
  • Sağ taraftaki name alanına yeni sunucu profilinin adını, host alanına 127.0.0.1, port alanına 8000 girin ve OK butonuna basın.
  • Bir önceki penceredeki servers isimli dropdown listeden yeni tanımladığınız sunucu profilini seçin ve OK butonuna basın.
  • File menüsünden Settings seçeneğine tıklayın.
  • Sol taraftaki menü ağacından PHP -> Debug seçeneğine tıklayın. Ekranın sağ tarafındaki bölümden Debug port alanında yazan 9000 değerini daha önce xdebug konfigürasyonunda belirttiğimiz 9009 olarak girin ve OK butonuna basın.

Uygulamada Gerekli Değişikliklerin Gerçekleştirilmesi

Normal şartlar altında yüklenen sınıflar önbelleğe alındığı ve gerektiğinde buradan sağlandığı için, Symfony2nin hata ayıklama sırasında önbelleğe müracat etmesini önlemelisiniz. Bu işlemi gerçekleştirmek için web/app_dev.php dosyasında $kernel->loadClassCache(); satırının başına yorum imi eklemelisiniz.

...
$kernel = new AppKernel('dev', true);
# $kernel->loadClassCache();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
...

Hata Ayıklama Moduna Geçiş

  • Run menüsünden Start Listen for PHP Debug Connection seçeneğine tıklayın.
  • Run menüsünden oluşturduğunuz hata ayıklama profili ile ilgili Debug “Yeni Profil Adı” seçeneğini çalıştırın.
  • Tarayıcıdan uygulamanızı çalıştırın.
  • Hata ayıklama işlemini başlatmak için adres satırın sağ tarafında yeralan gri renkli böcek şeklindeki simgeye tıklayın ve açılan menüden Debug seçeneğine tıklayın.
  • Geliştirme ortamınız artık hata ayıklama işlemi için hazır durumda. Projenizin herhangibir yerine break-point ekleyerek hata ayıklama işlemine başlayabilirsiniz.

    Genel

    Zenginlik İyidir

    tas-arabaKabarık bir banka hesabına sahipseniz, yeni araç satın almak için ne bir nedene, ne de ay sonu gibi parasal sorunları düşünmeye ihtiyacınız olmayabilir.

    Ancak…

    Aynı araçla kaza yapmanız durumunda kabarık bir dost listesine sahip değilseniz, yardımınıza koşacak birilerini bulamayabilirsiniz.

    ***

    Geçtiğimiz hafta geçirdiğim operasyonda yanımda olan, arayan/soran, selam ileten, gelip ziyaret eden ve hatta aklından geçiren tüm dostlarıma sonsuz teşekkür ederim. Planlı ancak acil bir operasyon olduğu için haber veremediğim dostlarımdan özür diliyorum.

    Dün itibarıyla taburcu olduk. Şu an herşey yolunda.
    Sevgiler
    İbrahim Gündüz

    Genel

    Python ile Web Crawling

    Aslında üstüne pek de yazı yazılası bir konu değil ama yine de belki meraklısının işine yarar :)

    Herhangibir dille web sitesi crawle etmek için bilinmesi gereken 3 şey

    1- Nasıl http isteği gönderebilirim ?
    2- Nasıl xpath sorgusu gerçekleştirebilirim ?
    3- Elde ettiğim elemanların özelliklerine nasıl ulaşabilirim ?

    Dilerseniz konuyu bu başlıklar altında inceleyelim.

    1- Nasıl http isteği gönderebilirim ?

    Python ile http request gönderebilmek için requests veya urllib2 kütüphanelerini kullanabilirsiniz.

    Ben bu yazıdaki örneklerde urllib2 kullanacağım.

    Örnek GET isteği:

    	url = 'http://edition.cnn.com/'
    	try:
    		request = urllib2.Request(url)
    		response = urllib2.urlopen(request).read()
    	except urllib2.URLError:
    		print "Connection failed. Url: %s" % url
    

    2- Nasıl xpath sorgusu gerçekleştirebilirim ?

    Python ile xpath sorgusu gerçekleştirmek için xml.ElementTree veya lxml kullanabilirsiniz.

    Ben bu yazıdaki örneklerde lxml kullanacağım.

    Aşağıdaki örnekde, CNN.com sitesindeki haber kategorilerini sorguluyoruz.
    Örnek Xpath sorgusu:

    	from lxml import html
    	query = '//*[@id="intl-menu"]/li/a'
    	root = html.fromstring(response)
    	categories = root.xpath(query)
    

    3- Elde ettiğim elemanların özelliklerine nasıl ulaşabilirim ?

    Bir önceki örnde kullandığım lxml kütüphanesini kullanıyorsanız, xpath sorgusu sonuncunda dönen elemanın DOM özelliklerine ulaşmak için get() metodunu, içindeki metne ulaşmak için text özelliğini, alt elemanlarına ulaşmak için getchildren() metodunu kullanabilirsiniz.

    for category in categories:
    	children = category.getchildren()
    	text = children and children[0].text or category.text
    	print text, category.get('href')
    

    Son olarak herşeyi bir araya getirelim.

    from lxml import html
    import urllib2
    
    url = 'http://edition.cnn.com/'
    try:
    	request = urllib2.Request(url)
    	response = urllib2.urlopen(request).read()
    except urllib2.URLError:
    	print "Connection failed. Url: %s" % url
    
    query = '//*[@id="intl-menu"]/li/a'
    root = html.fromstring(response)
    categories = root.xpath(query)
    
    for category in categories:
    	children = category.getchildren()
    	text = children and children[0].text or category.text
    	print text, category.get('href')
    

    Elde edeceğimiz sonuç aşağıdaki biçimde olacaktır.

    Home /
    Video /video/
    World /WORLD/
    U.S. /US/
    Africa /AFRICA/
    Asia /ASIA/
    Europe /EUROPE/
    Latin America /LATINAMERICA/
    Middle East /MIDDLEEAST
    Money http://money.cnn.com/INTERNATIONAL/
    World Sport /SPORT/
    Entertainment /SHOWBIZ/
    Tech /TECH/
    Travel http://travel.cnn.com/
    iReport http://ireport.cnn.com/
    
    Genel

    Mutlu Bayramlar!




    Bayramların farklı bir manevi havası var benim için. Eskiden gezme-dolaşma, yeme-içme, kavurma-pilav gibi beni mutlu eden ikilileri ifade ederken şimdi kendileri benim için anlamsız bir hüzün vesilesi oluyor. Mesela kaybettiklerimi daha çok özlüyorum… Zaten onlar olmadan da geri kalan hiçbirşeyin anlamı kalmıyor.

    Sevdiklerimizle birlikte yaşayacağımız nice güzel bayramlara…

    Genel

    Raspberry PI İle Müzik Keyfi

    Bayram arefesi boşluğu ile evde bir süredir “LCD ye yazı yazmaktan başka bir işe yaramayan” Raspberry PI cihazını * değerlendirmeye karar verdim. Aslında bu işler için uzun süredir benim emektar IBM makineyi dedike etmiştim ancak kendisi yaşı itibarıyla kaynakları yetersiz, yedek parçasını bulmak neredeyse imkansız, çok ısınıyor ve çok yer kaplıyordu. Ben de Raspberry PI’mi ağa bağlayıp kolları sıvadım.

    – İlk olarak aşağıdaki komutu çalıştırarak ses modülünün işletimm sistemindeki durumunu kontrol ettim.

    $ sudo lsmod | grep snd_bcm2835
    

    Eğer herşey yolundaysa aşağıdaki çıktının alınması gerekiyormuş.

    snd_bcm2835            18169  0 
    snd_pcm                81518  3 snd_bcm2835,snd_soc_core,snd_pcm_dmaengine
    snd                    61518  7 snd_bcm2835,snd_soc_core,snd_timer,snd_pcm,snd_seq,snd_seq_device,snd_compress
    

    Eğer snd_bcm2835 modülü yüklü değilse modprobe komutu ile snd_bcm2835 modülünü çalışır hale geitrmeliymişiz. Ancak bende gerek olmadı.

    $ sudo modprobe snd_bcm2835
    

    – Ben Raspberry PI’yi miksere analog ses çıkışından bağladığım için sesin bu bağlantı noktasından alınması için aşağıdaki komutu çalıştırdım.

    $ amixer cset numid=3 1
    

    Buradaki 3, raspberry pi mikserdeki kontrolün kimliği, 1 ise bu kontrol için atadığım değeri temsil ediyor.
    Kontrol listesini görmek için aşağıdaki komutu kullanabilirsiniz.

    $ amixer controls
    
    numid=3,iface=MIXER,name='PCM Playback Route'
    numid=2,iface=MIXER,name='PCM Playback Switch'
    numid=1,iface=MIXER,name='PCM Playback Volume'
    numid=5,iface=PCM,name='IEC958 Playback Con Mask'
    numid=4,iface=PCM,name='IEC958 Playback Default'
    

    İlgili kontrolün alabileceği değerleri görmek için ise aşağıdaki komutu çalıştırabilirsiniz.

    $ amixer cset numid=3
    numid=3,iface=MIXER,name='PCM Playback Route'
      ; type=INTEGER,access=rw------,values=1,min=0,max=2,step=0
      : values=0
    

    Gördüğünüz üzere ben 3 nolu kontrol için 0=otomatik, 1=anaolug çıkış, 2=hdmi değerlerini temsil eder.

    – Sıra geldi medya oynatıcı uygulamayı yüklemeye. Açıkcası bu konuda çok derinlemesine araştırma yaptığımı söyleyemem. Benim için uygulamanın herhangibir medya dosyasını shellden çalabilmesi yeterliydi. mpg321 uygulamasını tercih ettim. Kurulum için aşağıdaki komutu çalıştırdım.

    $ sudo apt-get -y install mpg321
    

    – SSH bağlantısı kesildiğinde uygulama kapandığından screen yükleyerek uygulamanın bağlantı kesilsede müziği çalmaya devam etmesini sağladım.

    $ sudo apt-get install screen
    

    – Son olarak ben evde yatan usb sabit disklerden birini içine mp3 doldurduktan sonra cihaza mount ettim. Siz dilerseniz müziklerinize ağ ve/veya. vs farklı kaynaklardan erişebilirsiniz.

    Kurulum işleri bu kadar.

    – Müzik çalmaya başlamadan önce screen i çalıştırmanızı öneririm. Bilgisayarınızı kapattığınızda müzik zevkiniz bölünmesin :)

    $ screen
    

    – Cihazın müzikleri çalmaya başlaması için aşağıdaki komutu çalıştırdım.

    $ find /media/myusbdisk/ -name "*.mp3"|mpg321 -@ -
    

    – Ses kontrolü için farklı bir screen oturumunda ** aşağıdaki komutlarla volüm kontrolü sağlayabilirsiniz.

    $ amixer cset numid=1 (0-100 arası bir değer)%
    $ amixer cset numid=1 mute
    

    Ve… müzik keyfi…
    20141003_175733_1

    Edit 04.10.2014:
    Ne yaptıysanız ses çıkmadıysa ve amixer yazdığınızda aşağıdaki ekran çıktısını alıyorsanız master volume mute durumundadır.

    Simple mixer control 'PCM',0
      Capabilities: pvolume pvolume-joined pswitch pswitch-joined penum
      Playback channels: Mono
      Limits: Playback -10239 - 400
      Mono: Playback -10239 [0%] [-99999.99dB] [off]
    

    Sorunu gidermek için aşağıdaki komutu çalıştırarak sorunu giderebilirsiniz:

    $ amixer set PCM unmute
    

    *: Raspberry Type B 700 MHz CPU ve 512 MB Ram belleğe sahip yaklaşık 100 küsür TL ye alabileceğiniz bir cihaz. Deneysel amaçlar dışında Raspberry PI bu işler için hem çok gelişmiş hem de çok pahalı. 5 TL lik bir PIC mikro denetleyicinin üzerine yazacağınız küçücük bir program kodu ile bu tarz işleri kolayca daha ucuza yapabilirsiniz.

    **: Screen’de farklı oturum açmak için CTRL + a + c, oturumlar arasında gezmek için CTRL + a + (“) yapabilirsiniz.

    Kaynaklar:
    http://www.raspberrypi-spy.co.uk/2013/06/raspberry-pi-command-line-audio/
    http://alexpb.com/notes/articles/2012/11/14/error-when-playing-audio-on-raspbian-on-a-raspberry-pi/
    http://jeffskinnerbox.wordpress.com/2012/11/15/getting-audio-out-working-on-the-raspberry-pi/
    http://www.raspberrypi.org/documentation/configuration/audio-config.md

    Genel

    Apache2’den Nginx’e Geçiş

    Merhaba Arkadaşlar,
    Uzunca bir süredir ibrahimgunduz.net’i nginx’e geçirmeyi planlıyordum. Her ne kadar bazı istisnai durumlar dışında blog, yüksek trafiğe sahip olmasa da, geçişi kesintisiz olarak gerçekleştirmek istediğim için düzgün bir planlama olmadan bu işlemi gerçekleştirmek istemedim. Daha önce yaptığım bir iki deneme önyüzde olmasa da baackend tarafında hızlıca çözemediğim bazı sıkıntılara neden olduğundan kısa sürede tekrar geri dönmek zorunda kalmıştım.

    Bugün bu geçiş işlemini tekrar gerçekleştirip siteyi nginx üstünde çalışr hale getirerek edindiğim tecrübeyi sizlerle paylaşmak istedim.

    Gerekli Paketlerin Kurulumu:

    * Nginx son sürümünün barındırıldığı repoyu apt paket yöneticisine bildirmek için birazdan kullanacağım komutu çalıştırabilmek için python-softwareproperties paketini yükledim.

    $ sudo apt-get install python-software-properties
    

    * Nginx paketinin bulunduğu repoyu tanımladım.

    $ sudo add-apt-repository ppa:nginx/stable
    

    * Paket listesini güncelledim ve nginx paketini kurdum.

    $ sudo apt-get update
    $ sudo apt-get install nginx
    

    * Aslında biraz önce de belirttiğim gibi uygulama sunucuma çok fazla trafik gelmiyor ancak yine de sonuçlarını görebilmek adına PHP proseslerini yönetmesi için PHP FPM kurulumunu gerçekleştirdim.

    $ sudo apt-get install php5-fpm
    

    Artık yavaştan sunucu konfigüre etmeye başlayabiliriz.

    PHP-FPM Konfigürasyonu:

    * Dilediğiniz metin düzenleyicisi ile /etc/php5/fpm/php.ini dosyasını açın ve cgi.fix_pathinf=1 şeklindeki satırı aşağıdaki biçimde değiştirin.

    cgi.fix_pathinfo=0
    

    * Yine dilediğiniz metin düzenleyici ile /etc/php5/fpm/pool.d/www.conf dosyasını açın ve aşağıdaki değişiklikleri gerçekleştirin.

    listen = /var/run/php5-fpm.sock
    listen.group = www-data
    

    Nginx Konfigürasyonu:

    * Öncelikle web sitemiz için nginx in varsayılan konfigürasyonunu kopyalayarak yeni bir sanal sunucu oluşturalım.

    $ cd /etc/nginx/sites-available
    $ sudo cp default ibrahimgunduz.net
    

    * Oluşturduğumuz sanal sunucu konfigürasyonunu aşağıdaki biçimde düzenleyin.

    server {
            listen 80 default_server;
            listen [::]:80 default_server ipv6only=on;
    
            root /path/to/ibrahimgunduznet/httpdocs;
            index index.php index.html index.htm;
    
            server_name www.ibrahimgunduz.net ibrahimgunduz.net;
    
            location / {
                    try_files $uri $uri/ /index.php?q=$uri&$args;
            }
    
            error_page 404 /404.html;
    
            error_page 500 502 503 504 /50x.html;
            location = /50x.html {
                    root /usr/share/nginx/html;
            }
    
            location ~ \.php$ {
                    try_files $uri =404;
                    fastcgi_pass unix:/var/run/php5-fpm.sock;
                    fastcgi_index index.php;
                    include fastcgi_params;
                    fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
            }
    
            error_log  /var/log/nginx/ibrahimgunduznet-error.log  error;
            access_log /var/log/nginx/ibrahimgunduznet-access.log;
    }
    

    * Nginx in sanal makine konfigürasyonunu işlemesi için apache de olduğu gibi sites-enabled klasörü altında konfigürasyonun sembolik bağlantısını oluşturuyoruz.

    $ sudo ln -s /etc/nginx/sites-available/ibrahimgunduz.net /etc/nginx/sites-enabled/
    

    Artık hazırız. Şimdi mevcut apache servisini durdurup nginix ve php-fpm ile ilgili yaptığımız değişiklikleri yayına almaya hazırız. Aşağıdaki komutları çalıştırıp apache servisini durup nginx ve php-fpm servislerini yeniden başlatalım.

    $ sudo service apache2 stop
    $ sudo service php5-fpm restart
    $ sudo service nginx restart
    

    Herhangibir sorunla karşılaştığınızda nginx servisini durdurup, apache2 servisini başlatarak geri dönüş yapabilirsiniz.

    Referanslar:

    https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-on-debian-7

    https://www.digitalocean.com/community/tutorials/how-to-install-the-latest-version-of-nginx-on-ubuntu-12-10

    https://www.digitalocean.com/community/tutorials/how-to-install-wordpress-with-nginx-on-ubuntu-14-04

    http://stackoverflow.com/a/22334781

    http://stackoverflow.com/questions/1706111/where-can-i-find-the-error-logs-of-nginx-using-fastcgi-and-django