<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>deadlime</title>
	
	<link>http://deadlime.hu</link>
	<description>unexpected terminator</description>
	<lastBuildDate>Mon, 14 May 2012 20:38:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/deadlime" /><feedburner:info uri="deadlime" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>PHP syntax ellenőrzés Sublime-ban</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/YRCDHumkP2k/</link>
		<comments>http://deadlime.hu/2012/05/13/php-syntax-ellenorzes-sublime-ban/#comments</comments>
		<pubDate>Sun, 13 May 2012 19:40:58 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Sublime]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=446</guid>
		<description><![CDATA[A minap eszembe jutott, hogy milyen jó is lenne, ha a Sublime jelezné, ha van valami elgépelés az éppen szerkesztett fájlba. És bár létezik elég sok megoldás a problémára, ami ráadásul még több nyelvet is (Python, CSS, JavaScript, stb.) támogat, de azért mégis csak sokkal mókásabb egy sajátot írni.]]></description>
			<content:encoded><![CDATA[<p>A minap eszembe jutott, hogy milyen jó is lenne, ha a <a href="http://www.sublimetext.com/2">Sublime</a> jelezné, ha van valami elgépelés az éppen szerkesztett fájlba. És bár <a href="https://www.google.hu/search?q=sublime+lint">létezik elég sok megoldás</a> a problémára, ami ráadásul még több nyelvet is (Python, CSS, JavaScript, stb.) támogat, de azért mégis csak sokkal mókásabb egy sajátot írni.<p>

<p>A megoldás lényege, hogy valahol a vinyón van egy PHP bináris, amit megfuttatunk a <code>-l</code> kapcsolóval, ami nem futtatja a fájlt, hanem csak szintaxisra ellenőriz. A válasz a PHP szokásos "parse error" szövege lesz, ami azt írja ki, hogy hol hasalt el a fordító, ami nem feltétlen esik egybe azzal, hogy hol van a hiba. A kódot többféleképpen meg lehetne valósítani (pl. parancsként, amit menüből, vagy billentyűkombinációra lehet futtatni), én azt választottam, hogy mentés eseményre automatikusan fusson le, ha megfelelő a fájl kiterjesztése:</p>

<pre class="code prettyprint lang-python">import sublime, sublime_plugin, os, subprocess, re

class PhpLintEventListener(sublime_plugin.EventListener):
    key = &quot;php_lint_syntax_error&quot;
    
    def on_post_save(self, view):
        if not view.settings().has(&quot;php_lint&quot;):
            return
        
        config = view.settings().get(&quot;php_lint&quot;)
        
        bin_path = config.get(&quot;binary&quot;, &quot;&quot;)
        name, ext = os.path.splitext(view.file_name())
        
        if not bin_path or ext not in config.get(&quot;extensions&quot;, []):
            return
        
        view.erase_regions(self.key)
        view.erase_status(self.key)
        
        shell = sublime.platform() == &quot;windows&quot;
        p = subprocess.Popen([bin_path, &quot;-l&quot;,  view.file_name()], shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (stdout, stderr) = p.communicate()
        
        if &quot;&quot; == stderr:
            data = stdout
        else:
            data = stderr
        
        result = re.match(r&quot;(.+?) in (.+?) on line ([0-9]+).*&quot;, data, re.M | re.S)
        if result:
            error = result.group(1)
            line = result.group(3)
            
            view.add_regions(self.key, [view.full_line(view.text_point(int(line) - 1, 0))], &quot;markup.deleted&quot;, &quot;dot&quot;)
            view.set_status(self.key, error + &quot; on line &quot; + line)</pre>

<p>Nem egy bonyolult jószág, ha létezik a config és a fájl kiterjesztése benne van a configban megadott listában, akkor megfuttatjuk a PHP binárist és megkeressük a kimenetében, hogy hányadik sorban volt a hiba. A hibás sort kiemeljük és a hiba szövegét a státuszba ki is írjuk. A szükséges config pedig valahogy így néz ki:</p>

<pre class="code prettyprint lang-javascript">&quot;php_lint&quot; : {
    &quot;binary&quot; : &quot;d:\\php\\5.2\\php.exe&quot;,
    &quot;extensions&quot; : [&quot;.php&quot;]
}</pre>

<p>Ezt lehet pakolni a <code>Preferences > Settings - User</code> részbe vagy akár a projekt beállításai közé is (a <code>.sublime-project</code> fájlon belül a <code>"settings"</code> blokkba).</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=YRCDHumkP2k:y5nua-1eD3Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=YRCDHumkP2k:y5nua-1eD3Q:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=YRCDHumkP2k:y5nua-1eD3Q:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=YRCDHumkP2k:y5nua-1eD3Q:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/YRCDHumkP2k" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2012/05/13/php-syntax-ellenorzes-sublime-ban/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2012/05/13/php-syntax-ellenorzes-sublime-ban/</feedburner:origLink></item>
		<item>
		<title>deadlime: unexpected terminator</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/fKTVqD3-mIQ/</link>
		<comments>http://deadlime.hu/2012/04/24/deadlime-unexpected-terminator/#comments</comments>
		<pubDate>Tue, 24 Apr 2012 20:12:06 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[siteinfo]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=435</guid>
		<description><![CDATA[Több, mint 5 és fél év után elérkezett az idő, hogy nyugdíjba vonuljon a régi oldal és megszülessen az 5.0-s verzió. Mivel egyébként nagyjából 8 év magasságában járunk, elég nagy bizonyossággal állíthatom, hogy ilyen sokáig még egy design se bírta. Sok mindent nem is tudnék hozzátenni, az eredmény jól látható (ha csak nem rss olvasóban nézi a kedves olvasó a bejegyzést).]]></description>
			<content:encoded><![CDATA[<p>Több, mint 5 és fél év után elérkezett az idő, hogy nyugdíjba vonuljon a régi oldal és megszülessen az 5.0-s verzió. Mivel egyébként nagyjából 8 év magasságában járunk, elég nagy bizonyossággal állíthatom, hogy ilyen sokáig még egy design se bírta. Sok mindent nem is tudnék hozzátenni, az eredmény jól látható (ha csak nem rss olvasóban nézi a kedves olvasó a bejegyzést). Néhány dolog, ami változott:</p>

<ul>
    <li>A modern kor elvárásaihoz némiképp igazodva az oldal valamivel <a href="http://en.wikipedia.org/wiki/Responsive_Web_Design">reszponzívabb</a> lett.</li>
    <li>A kommentelési lehetőség kikerült, a továbbiakban a bejegyzéshez kapcsolódó Google+ postban lehet majd megjegyezni dolgokat.</li>
    <li>Like/+1 gombok sincsenek, csak hogy letisztultabbak és egyszerűbbek legyünk.</li>
    <li>Bár még mindig nem vittem túlzásba a tartalmat, de már nem csak "Folyamatban..." van az Archívum oldalon. :)</li>
</ul>

<p>Ééés nagyjából ennyi... Nem vittem túlzásba. :) Aztán biztos maradt egy rakat hiba és hiányosság benne, amit majd az elkövetkezendő évek során bőven lesz időm javítani.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=fKTVqD3-mIQ:b2tfuyQNExc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=fKTVqD3-mIQ:b2tfuyQNExc:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=fKTVqD3-mIQ:b2tfuyQNExc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=fKTVqD3-mIQ:b2tfuyQNExc:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/fKTVqD3-mIQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2012/04/24/deadlime-unexpected-terminator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2012/04/24/deadlime-unexpected-terminator/</feedburner:origLink></item>
		<item>
		<title>Anylist</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/aBmXBSwpqhk/</link>
		<comments>http://deadlime.hu/2012/03/19/anylist/#comments</comments>
		<pubDate>Mon, 19 Mar 2012 19:52:40 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=412</guid>
		<description><![CDATA[Szóval, már egy ideje foglalkoztat a mobil fejlesztés. Annak is főleg a zöld robotos ágazata. Gondoltam ideje lenne valami maradandóbbat alkotni a gépen heverő sok teszt projektnél, úgyhogy bele is vágtam egy listás alkalmazás elkészítésébe, annak ellenére, hogy listás alkalmazásokkal Dunát lehetne rekeszteni (vagy ha már itt tartunk, lassan már bármilyen típusú alkalmazásokkal... :)).]]></description>
			<content:encoded><![CDATA[<p>Szóval, már egy ideje foglalkoztat a mobil fejlesztés. Annak is főleg a <a href="http://www.android.com/">zöld robotos</a> ágazata. Gondoltam ideje lenne valami maradandóbbat alkotni a gépen heverő sok teszt projektnél, úgyhogy bele is vágtam egy listás alkalmazás elkészítésébe, annak ellenére, hogy listás alkalmazásokkal Dunát lehetne rekeszteni (vagy ha már itt tartunk, lassan már bármilyen típusú alkalmazásokkal... :)). A végeredmény (vagy inkább az első verzió) megtekinthető a Google Play-en:</p>

<p style="text-indent: 0; text-align: center;"><a href="https://play.google.com/store/apps/details?id=hu.deadlime.anylist"><img src="http://deadlime.hu/wp-content/uploads/2012/03/ic_market.png" alt="" /></a></p>

<p>Vagy mobilosoknak egy kényelmesebb market alkalmazás linken:</p>

<p style="text-indent: 0; text-align: center;"><a href="market://details?id=hu.deadlime.anylist"><img src="http://deadlime.hu/wp-content/uploads/2012/03/anylist_qr.png" alt="" /></a></p>

<p>Amit tud:</p>

<ul>
    <li>Listákat kezelni! :)</li>
    <li>Külső alkalmazás segítségével QR kódot beolvasni és azt elmenteni listaelemként az egyszerű és gyors felvitel érdekében.</li>
    <li>Ha linket kap listaelemnek, azt feldolgozza és a meta adatokkal együtt jeleníti meg (<a href="http://ogp.me/">a Facebook-os Open Graph</a> tagek hozzák igazán lázba, mással nem nagyon foglalkozik :)).</li>
    <li>Megosztani egy listát (pl. e-mailben elküldeni).</li>
</ul>

<p>Nagyjából ennyi, nem egy bonyolult jószág. Az elkészítésében az <a href="http://actionbarsherlock.com/">ActionBarSherlock</a> volt a segítségemre, ami remekül valósítja meg a 4.0-s Action Bar-t 4.0 előtti készülékeken is. Kellemes listázást. :)</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=aBmXBSwpqhk:59AzOxhYFYc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=aBmXBSwpqhk:59AzOxhYFYc:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=aBmXBSwpqhk:59AzOxhYFYc:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=aBmXBSwpqhk:59AzOxhYFYc:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/aBmXBSwpqhk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2012/03/19/anylist/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2012/03/19/anylist/</feedburner:origLink></item>
		<item>
		<title>Projektépítés a távolból</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/o9PSIBkB0vI/</link>
		<comments>http://deadlime.hu/2012/01/18/projektepites-a-tavolbol/#comments</comments>
		<pubDate>Wed, 18 Jan 2012 21:08:48 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[CoffeeScript]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[Phing]]></category>
		<category><![CDATA[Sass]]></category>
		<category><![CDATA[Sublime]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=348</guid>
		<description><![CDATA[Most, hogy már van egy virtuális szerverünk, kellene kezdeni vele valami mókás dolgot. Lehetne mondjuk egy távolról is vezérelhető build rendszerünk (a "távolról" mondjuk ebben az esetben talán egy kicsit túlzás :)), amit a kedvenc szövegszerkesztőnk automatikusan tudna vezérelni. Az úgy kellőképp mókásan hangzik ahhoz, hogy belevágjunk. :)]]></description>
			<content:encoded><![CDATA[<p style="text-indent: 0;"><img src="http://deadlime.hu/wp-content/uploads/2012/01/projektepites-a-tavolbol.jpg" alt="" width="450" height="200" /></p>

<p>Most, hogy már <a href="http://deadlime.hu/2011/12/20/gep-a-gepben/">van egy virtuális szerverünk</a>, kellene kezdeni vele valami mókás dolgot. Lehetne mondjuk egy távolról is vezérelhető build rendszerünk (a "távolról" mondjuk ebben az esetben talán egy kicsit túlzás :)), amit a kedvenc szövegszerkesztőnk automatikusan tudna vezérelni. Az úgy kellőképp mókásan hangzik ahhoz, hogy belevágjunk. :)</p>

<p>Ahhoz, hogy legyen értelme a build rendszernek, nem árt, ha van mit build-elni. Tegyük fel mondjuk a példa kedvéért, hogy CSS helyett szeretnénk Sass-t, JavaScript helyett pedig CoffeeScript-et használni. Természetesen a rendszer képességei nem merülnek ki ennyiben, lehetne mondjuk olyat is csinálni, hogy a sablon fájlokat fordítsa le PHP-ra, vagy a konfigurációs XML-ekből gyártson tömböket, esetleg minden unit tesztet lefuttasson. A lehetőségek száma, ahogy mondani szokás, végtelen, de maradjunk az eredeti kettőnél, a többi a kedves olvasó fantáziájára van bízva. Kezdjük is rögtön a telepítéssel:</p>

<h3>Sass</h3>

<pre class="code">sudo apt-get install ruby rubygems
sudo gem install sass</pre>

<p><small>A <a href="http://sass-lang.com/">Sass</a> [Syntactically Awesome Stylesheets] nevezetű előfeldolgozó néhány hasznos kiegészítéssel segít ráncba szedni az elvadult CSS kóddzsungelt.</small></p>

<h3>CoffeeScript</h3>

<pre class="code">sudo apt-get install nodejs npm
sudo npm install coffee-script</pre>

<p><small>A <a href="http://coffeescript.org/">CoffeeScript</a> a funkcionális programozási nyelvekre és talán egy csöppet a Ruby-ra emlékeztető nyelv a JavaScript egy komolyabb újragondolása (a Sass-CSS viszonylathoz képest), de mentségére legyen mondva, hogy egy az egyben valid JavaScript-re fordul.</small></p>

<h3>Építkezzünk</h3>

<p>A build-elésben segítségünkre lesz a vicces nevű PHP-s build eszköz, a <a href="http://www.phing.info/">Phing</a>. A következő módon érhetjük el, hogy feltelepüljön:</p>

<pre class="code">sudo apt-get install php-pear
sudo pear channel-discover pear.phing.info
sudo pear install phing/phing</pre>

<p>A példához a következő minimális projekt könyvtárszerkezetet fogjuk használni:</p>

<ul>
    <li>
        assets/
        <ul>
            <li>coffee/</li>
            <li>sass/</li>
        </ul>
    </li>
    <li>
        www/
        <ul>
            <li>css/</li>
            <li>js/</li>
        </ul>
    </li>
    <li>build.xml</li>
</ul>

<p>Az <code>assets/</code> könyvtárban vannak a nyers fájlok, a <code>www/</code> könytárba mennek a generált fájlok, amiket nem árt kívülről is elérni. A kulcs pedig a <code>build.xml</code>, ami a Phing számára tartalmaz utasításokat. Kezdetnek valami ilyesmi például megteszi:</p>

<pre class="code prettyprint lang-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project name=&quot;MyProject&quot; default=&quot;assets&quot;&gt;
    &lt;property name=&quot;sass_dir&quot; value=&quot;${project.basedir}/assets/sass/&quot; /&gt;
    &lt;property name=&quot;coffee_dir&quot; value=&quot;${project.basedir}/assets/coffee/&quot; /&gt;
    
    &lt;property name=&quot;css_target&quot; value=&quot;${project.basedir}/www/css/&quot; /&gt;
    &lt;property name=&quot;js_target&quot; value=&quot;${project.basedir}/www/js/&quot; /&gt;
    
    &lt;target name=&quot;sass&quot;&gt;
        &lt;exec command=&quot;sass --no-cache --update &amp;quot;${sass_dir}:${css_target}&amp;quot;&quot; /&gt;
    &lt;/target&gt;
    
    &lt;target name=&quot;coffee&quot;&gt;
        &lt;exec command=&quot;coffee -o &amp;quot;${js_target}&amp;quot; &amp;quot;${coffee_dir}&amp;quot;&quot; /&gt;
    &lt;/target&gt;
    
    &lt;target name=&quot;assets&quot;&gt;
        &lt;phingcall target=&quot;sass&quot; /&gt;
        &lt;phingcall target=&quot;coffee&quot; /&gt;
    &lt;/target&gt;
&lt;/project&gt;</pre>

<p>A projekt könyvtárában (egy szinten a <code>build.xml</code>-lel) állva ki tudjuk adni a következő három parancsot, amivel a Sass-t, CoffeeScript-et és mindkettőt egyszerre lefordíthatjuk (ha nem adunk meg semmit a <code>phing</code> után, akkor a default <code>assets</code> fog lefutni):</p>

<pre class="code">phing sass</pre>
<pre class="code">phing coffee</pre>
<pre class="code">phing assets</pre>

<h3>Az alkalmazás</h3>

<p>Már csak azt kellene elérni, hogy a fájlok módosítása után a megfelelő parancs automatikusan lefusson. Bár mind a Sass, mind a CoffeeScript rendelkezik megoldással a problémára (<code>--watch</code>), a későbbiekre is gondolva inkább valami általánosabb megoldásra lenne szükség. Mondjuk egy webes minialkalmazás, ami a kapott paraméterek függvényében meghívja a megfelelő parancsot. A kódszerkesztő alkalmazásunk pedig ezt a paraméterezett URL-t hívogathatná. Mondjuk valami ilyesmit:</p>

<pre class="code">http://builder.vbox/index.php?project=projektneve&#038;target=target</pre>

<p>Az a bizonyos <code>index.php</code> pedig valami ilyen kis egyszerű dolog lenne (az egyszerűség ára az, hogy élünk azzal a feltételezéssel, hogy az egyes projektek a <code>/var/www/projektneve.vbox/</code> könyvtárban vannak és eltekintünk az olyan dolgoktól, mint például a <code>target</code> valódiságának az ellenőrzése):</p>

<pre class="code prettyprint lang-php">$dir = '/var/www/' . get('project') . '.vbox/';
if (!file_exists($dir . 'build.xml')) {
    exit('invalid_project');
}

$target = get('target');
if (!$target) {
    exit('no_target');
}

chdir($dir);
shell_exec('phing ' . escapeshellcmd($target));
exit('ok');

function get($name) {
    if (empty($_GET[$name])) {
        return '';
    }
    return preg_replace('/[^a-z0-9\-\.]/i', '', $_GET[$name]);
}</pre>

<h3>A plugin</h3>

<p>Ezzel meg is van a távolról is vezérelhető egyszerű kis build rendszerünk. A kedvenc szerkesztőnkhöz írhatunk egy plugin-t, ami mentésre meghívja a megfelelő URL-t, hogy legenerálódjanak a CSS/JS fájlok (vagy akár tetszőleges billentyűkombinációra tetszőleges build parancsot meghívhatunk). <a href="http://www.sublimetext.com/2">Sublime Text 2</a> esetén valahogy így nézne ki a dolog:</p>

<pre class="code prettyprint lang-python">import sublime, sublime_plugin
import urllib, urllib2
import os, threading

class BuilderThread(threading.Thread):
    def __init__(self, project, target):
        threading.Thread.__init__(self)
        self.project = project
        self.target = target
    def run(self):
        try:
            data = urllib.urlencode({
                'project': self.project,
                'target': self.target,
            })
            request = urllib2.Request('http://builder.vbox/index.php?' + data)
            response = urllib2.urlopen(request).read()
            return
        except (urllib2.HTTPError) as (e):
            err = '%s: HTTP error %s contacting API' % (__name__, str(e.code))
        except (urllib2.URLError) as (e):
            err = '%s: URL error %s contacting API' % (__name__, str(e.reason)) 
        
        sublime.error_message(err)

class BuilderEventListener(sublime_plugin.EventListener):
    def __init__(self):
        sublime_plugin.EventListener.__init__(self)
    
    def on_post_save(self, view):
        name, ext = os.path.splitext(view.file_name())
        project = view.settings().get('builder_project_name', False)
        
        if (False == project):
            return
        
        if (ext == '.coffee'):
            BuilderThread(project, 'coffee').start()
        elif (ext == '.scss' or ext == '.sass'):
            BuilderThread(project, 'sass').start()</pre>

<p>A plugin használ egy <code>builder_project_name</code> nevű beállítást, amit az éppen aktuális projekt <code>.sublime-project</code> fájljában érdemes megadni:</p>

<pre class="code prettyprint lang-json">{
    &quot;settings&quot;: {
        &quot;builder_project_name&quot;: &quot;test-project&quot;
    }
}</pre>

<p>Ezzel meg is volnánk, kellemes építkezést.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=o9PSIBkB0vI:-qtnJkozl1Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=o9PSIBkB0vI:-qtnJkozl1Q:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=o9PSIBkB0vI:-qtnJkozl1Q:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=o9PSIBkB0vI:-qtnJkozl1Q:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/o9PSIBkB0vI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2012/01/18/projektepites-a-tavolbol/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2012/01/18/projektepites-a-tavolbol/</feedburner:origLink></item>
		<item>
		<title>Gép a gépben</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/gCheFMw2NVs/</link>
		<comments>http://deadlime.hu/2011/12/20/gep-a-gepben/#comments</comments>
		<pubDate>Tue, 20 Dec 2011 21:07:35 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[fejlesztés]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[VirtualBox]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=298</guid>
		<description><![CDATA[Épp a sorozatos oldal második verziójának fejlesztésébe készülök komolyabban belevágni. Ennek kapcsán eszembe jutott, hogy milyen jó bejegyzést lehetne ebből kanyarítani. Mármint abból, hogy milyen módjai vannak a kényelmes otthoni projekt fejlesztésnek.]]></description>
			<content:encoded><![CDATA[<p style="text-indent: 0;"><img src="http://deadlime.hu/wp-content/uploads/2011/12/gep-a-gepben.jpg" alt="" width="450" height="200" /></p>

<p>Épp a <a href="http://s01e01.hu/">sorozatos oldal</a> második verziójának fejlesztésébe készülök komolyabban belevágni. Ennek kapcsán eszembe jutott, hogy milyen jó bejegyzést lehetne ebből kanyarítani. Mármint abból, hogy milyen módjai vannak a kényelmes otthoni projekt fejlesztésnek.</p>

<p>Összepiszkíthatnánk például a jelenlegi operációs rendszerünket mindenféle web- és egyéb szerverekkel, de ez nem egy szép megoldás. Telepíthetnénk egy extra operációs rendszert egy külön partícióra, de az, hogy a jelenlegiből ki kell lépni, oda pedig be... esélytelenné teszi a fejlesztést egy kellően lusta ember számára (én :)). A legjobb lenne egy külön gép, amit hálózaton keresztül elérünk. Ennek a legköltséghatékonyabb változata a virtuális gép, így ezen a vonalon fogunk tovább haladni. Hozzávalók egy személyre:</p>

<ul>
    <li><a href="https://www.virtualbox.org/wiki/Downloads">VirtualBox</a></li>
    <li><a href="http://www.ubuntu.com/download/server/download">Ubuntu Server</a></li>
    <li>némi sör és pár napra elegendő hideg élelem</li>
</ul>

<p><small>Pro tipp: az Ubuntu szerver iso-ját ne a VirtualBox telepítése közben töltsük le, mert a VirtualBox telepítés közben hajlamos időlegesen megkavarni az internet kapcsolatot és jól meg fog szakadni a letöltés.</small></p>

<h3>Telepítés</h3>

<p>A letöltések és a szokásos next-next-finish telepítés befejeztével hozzáadhatunk egy új Linux / Ubuntu típusú virtuális gépet és egy új virtuális merevlemezt a varázsló segítségével. Még mielőtt elindítanánk, a Settings / Shared Folders részben érdemes hozzáadni egy könyvtárat a saját gépünkről, amiben a projekteket fogjuk tárolni, hogy ne kelljen később Samba-t telepíteni. Az Auto-mount részt ne pipáljuk be, azt később kézzel beállítjuk majd. A Settings / Network részbe se árthat benézni és az Adapter 1-et ízlés szerint megpiszkálgatni. Nálam a Bridged Adapter volt a nyerő az Attached to részben.  A VirtualBox elég okos és az első indításnál felajánlja, hogy etessünk meg a géppel egy CD-t. Ajánlatos itt beadagolni a korábban letöltött Ubuntu szerver iso-ját, mert az nagyban megkönnyíti a telepítést. :)</p>

<p style="text-indent: 0;"><a href="http://deadlime.hu/wp-content/uploads/2011/12/virtualbox_mount_media.jpg"><img src="http://deadlime.hu/wp-content/uploads/2011/12/virtualbox_mount_media_small.jpg" alt="" title="VirtualBox Mount Media" width="450" /></a></p>

<p>Az Ubuntu nem egy bonyolult jószág, így valószínűleg a telepítéssel se lesznek problémák. Amíg fut, tetszés szerint lehet fogyasztani a bespájzolt hideg élelmet illetve sört. Hogy, hogy nem előbb-utóbb eljutunk egy ilyen képernyőhöz:</p>

<p style="text-indent: 0;"><a href="http://deadlime.hu/wp-content/uploads/2011/12/ubuntu_software_selection.jpg"><img src="http://deadlime.hu/wp-content/uploads/2011/12/ubuntu_software_selection_small.jpg" alt="" title="Ubuntu Software Selection" width="450" /></a></p>

<p>Itt a LAMP server-t az Apache-PHP-MySQL szentháromság miatt erősen ajánlott bepipálni, mert valószínűleg szükségünk lesz rá. Én telepíteni szoktam OpenSSH server-t is, mert már annyira hozzászoktam a <a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html">PuTTy</a> használatához. :)<br />
Ha ezzel megvagyunk, az első belépés után rögtön érdemes is nyomni egy frissítést:</p>

<pre class="code">sudo apt-get update
sudo apt-get upgrade</pre>

<p>Valamint telepíteni a VirtualBox Guest csomagját a jobb támogatás érdekében:</p>

<pre class="code">sudo apt-get install virtualbox-guest-utils</pre>

<h3>A projekt könyvtárak beállítása</h3>

<p>A fejlesztés a <code>/var/www/</code> könyvtárban fog történni a virtuális gép nézőpontjából. Hogy kényelmes legyen, érdemes ezt kivezetni valahova a gazda gép merevlemezére. Ezért állítottuk be korábban a Shared Folders részt. A művelet elvégzéséhez a következő sorokat kell felvenni az <code>/etc/fstab</code> fájl végére (na jó, a komment nem kötelező :)):</p>

<pre class="code"># VirtualBox Shared Folder
projects /var/www vboxsf auto,rw,uid=1000,gid=33 0 0</pre>

<p>A <code>projects</code> helyére a Shared Folder felvitelénél megadott nevet kell írni. Az <code>uid=1000</code> a rendszer telepítése során létrehozott felhasználó, a <code>gid=33</code> a <code>www-data</code> csoport. A módszernek az az előnye is megvan a Samba-féle megoldással szemben, hogy nem kell futnia a virtuális gépnek ahhoz, hogy a fájlokat módosítani tudjuk. Az uid és gid értékeként megadható számok után az <code>/etc/passwd</code> és <code>/etc/group</code> fájlokban lehet érdeklődni.</p>

<h3>Szerver elérés</h3>

<p>Ha minden jól ment, az <code>ifconfig eth0</code> által kidobott ip címen el tudjuk érni a gépet. Ha nem, akkor a VirtualBox beállítások Network részénél érdemes a lehetőségeket végigpróbálgatni, hogy melyik jön be (ahány hálózat, annyi beállítás).<br />
Az egyszerűséget szem előtt tartva érdemes valami egyedi, egyébként nem létező domain-el felruházni a gépet, hogy ne ip címeket kelljen mindig írogatni. Nálam a <code>*.vbox</code> domain-ek vannak erre fenntartva. A legegyszerűbb, ha a hosts fájlba felvesszük őket (Windows: <code>c:\Windows\System32\drivers\etc\hosts</code>, Linux: <code>/etc/hosts</code>), pl.:</p>

<pre class="code">192.168.1.117 default.vbox
192.168.1.117 projektneve.vbox
192.168.1.117 subdomain.projektneve.vbox</pre>

<h3>Apache, PHP, MySQL beállítás</h3>

<p>Az egyes projektek a <code>/var/www/projektneve.vbox/</code> könyvtárban kapnak helyet. Az alap Apache confignak csinálunk egy <code>default.vbox</code> nevet/könyvtárat:</p>

<pre class="code">mkdir /var/www/default.vbox
sudo mcedit /etc/apache2/sites-available/default</pre>

<p>A megnyíló fájlban a <code>DocmentRoot</code> és a <code>Directory</code> résznél szereplő <code>/var/www/</code> után kell még egy <code>default.vbox/</code>-ot írni. Aztán pedig</p>

<pre class="code">sudo service apache2 reload</pre>

<p>A <code>/etc/apache2/httpd.conf</code>-ba esetleg még érdemes egy <code>ServerName default.vbox</code> sort beledobni és újraindítani az Apache-ot, hogy megszűnjön a <em>"Could not reliably determine the server's fully qualified domain name"</em> hibaüzenet.</p>

<p>A projekt VirtualHost beállításai a <code>/etc/apache2/sites-available/projektneve.conf</code> fájlba kerülnek. Egy egyszerű példa, hogy nagyjából mit is tartalmaz egy ilyen:</p>

<pre class="code prettyprint lang-xml">&lt;VirtualHost *:80&gt;
    ServerName projektneve.vbox
    ServerAlias www.projektneve.vbox

    DocumentRoot /var/www/projektneve.vbox/www
    &lt;Directory /&gt;
        Options FollowSymLinks
        AllowOverride All
    &lt;/Directory&gt;
    &lt;Directory /var/www/projektneve.vbox/www/&gt;
        Options FollowSymLinks
        AllowOverride All
    &lt;/Directory&gt;

    ErrorLog /var/www/projektneve.vbox/log/apache_www_error.log
    CustomLog /var/www/projektneve.vbox/log/apache_www_access.log combined

    LogLevel warn
&lt;/VirtualHost&gt;</pre>

<p>A kész site beállításokat a következő parancsokkal tudjuk engedélyezni:</p>

<pre class="code">sudo a2ensite projektneve.conf
sudo service apache2 reload</pre>

<p>A MySQL-en nincs sok beállítani való, telepítéskor elkérte a root felhasználójához az új jelszót, mást meg nem nagyon kell piszkálni. A vizuálisabb típusoknak esetleg egy phpmyadmin telepítése még nem árthat:</p>

<pre class="code">sudo apt-get install phpmyadmin</pre>

<p>Ha kértük, a csomagból telepítés során be is köti magát az Apache-ba a <code>/etc/apache2/conf.d/phpmyadmin.conf</code> segítségével és a <code>http://ipcím/phpmyadmin/</code> címen el is érhető az oldal. Ehelyett, ha kedvünk tartja létrehozhatunk neki egy saját VirtualHost-ot is akár.</p>

<p>A PHP beállításánál érdemes arra törekedni, hogy minél jobban hasonlítson az éles rendszerre, így ezzel kapcsolatban nem sokat tudok mondani.</p>

<p>Első körben ennyi, kellemes telepítgetést. :)</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=gCheFMw2NVs:goIuULTN3uM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=gCheFMw2NVs:goIuULTN3uM:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=gCheFMw2NVs:goIuULTN3uM:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=gCheFMw2NVs:goIuULTN3uM:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/gCheFMw2NVs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2011/12/20/gep-a-gepben/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2011/12/20/gep-a-gepben/</feedburner:origLink></item>
		<item>
		<title>deadlime+</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/daRiUGUu5rw/</link>
		<comments>http://deadlime.hu/2011/11/08/deadlime/#comments</comments>
		<pubDate>Tue, 08 Nov 2011 20:47:33 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[siteinfo]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=289</guid>
		<description><![CDATA[Szóval van ez a Google+. Mindenki nagy örömére, most már lehet rajta Google+ Page-eket is csinálni. És most már van a deadlime-nak is egy.]]></description>
			<content:encoded><![CDATA[<p>Szóval van ez a <a href="https://plus.google.com/">Google+</a>. Mindenki nagy örömére, most már lehet rajta <del>Facebook Page-eket</del> Google+ Page-eket is csinálni. És most már <a href="https://plus.google.com/111692804354332408387">van a deadlime-nak is egy</a>.</p>

<p>Jelenleg még üres, de a terv az, hogy leváltja az oldalsávban a "Linkek" rész alatt használt <a href="http://www.google.hu/reader/shared/12202729755445268545">Google Reader-ből jövő megosztás listát</a> és ezentúl ott lesznek megosztva az érdekesnek tűnő linkek.</p>

<p>Szóval <del>lájkoljatok</del> plusszoljatok! :)</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=daRiUGUu5rw:VxRXMIyaUKE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=daRiUGUu5rw:VxRXMIyaUKE:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=daRiUGUu5rw:VxRXMIyaUKE:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=daRiUGUu5rw:VxRXMIyaUKE:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/daRiUGUu5rw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2011/11/08/deadlime/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2011/11/08/deadlime/</feedburner:origLink></item>
		<item>
		<title>A zöldcitromok ereje</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/5CUR3i_swtk/</link>
		<comments>http://deadlime.hu/2011/06/19/a-zoldcitromok-ereje/#comments</comments>
		<pubDate>Sat, 18 Jun 2011 22:57:31 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Sublime]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=233</guid>
		<description><![CDATA[Érdekes módon a deadlime kedvenc kódszerkesztő alkalmazása a Sublime. Egyrészt azért, mert a többszörös kijelölés az bizony hihetetlenül fantasztikus egy találmány. Másrészt pedig Python-ban lehet hozzá plugin-eket írni.]]></description>
			<content:encoded><![CDATA[<p style="text-indent: 0;"><img src="http://deadlime.hu/wp-content/uploads/2011/06/lime.jpg" alt="" width="450" height="190" /></p>

<p>Érdekes módon a deadlime kedvenc kódszerkesztő alkalmazása a <a href="http://www.sublimetext.com/">Sublime</a>. Egyrészt azért, mert a <a href="http://sublime.akalias.net/gettingstarted/concepts-multiple-selections.html">többszörös kijelölés</a> az bizony hihetetlenül fantasztikus egy találmány. Másrészt pedig Python-ban lehet hozzá plugin-eket írni.</p>

<p>Kedves kollégám említette a minap, hogy egyik régebben használt szerkesztőjében volt valamiféle funkció, amivel a vágólap korábbi tartalmait lehetett újra felhasználni. Aztán elkezdtem gondolkodni rajta, hogy vajon lehetne-e egy ilyen plugin-t írni Sublime-hoz. Aztán megírtam. :)</p>

<p>Ha már így alakult, ragadjuk meg az alkalmat és nézzük meg kicsit, hogyan is néz ki egy Sublime plugin. A funkció meglepően kevés kódból megoldható: először is felül kell csapnunk a beépített copy és cut utasításokat sajáttal úgy, hogy megmaradjon az eredeti funkcionalitás is, de közbe mentsük egy tömbbe az adatokat.</p>

<pre class="code prettyprint lang-python">class ClipboardHistoryCopyCommand(sublimeplugin.TextCommand):
    def run(self, view, args):
        saveSelections(view)
        view.runCommand('copy');</pre>

<p>Egy kis XML-lel meg is mondjuk a proginak, hogy a mi parancsunkat használja a <kbd>Ctrl+C</kbd> nyomkodása esetén:</p>

<pre class="code prettyprint lang-xml">&lt;bindings&gt;
    &lt;binding key=&quot;ctrl+c&quot; command=&quot;clipboardHistoryCopy&quot; /&gt;
&lt;/bindings&gt;</pre>

<p>A cut nem túl meglepő módon elég hasonlóan néz ki (csak a beépített cut parancsot hívjuk meg a végén). A <code>saveSelections</code> végzi a munka javát. Végigmegy az összes kijelölésen és amelyik nem üres, azt elpakolja egy tömbbe, aminél még arra is figyelünk, hogy ne lehessen túl nagy:</p>

<pre class="code prettyprint lang-python">clipboardMaxSize = 100
clipboardData = []

def saveSelections(view):
    for region in view.sel():
        if region.begin() != region.end():
            clipboardData.insert(0, view.substr(region))
            if len(clipboardData) &gt; clipboardMaxSize:
                clipboardData.pop()</pre>

<p>Annyi maradt már csak, hogy valami kellően kézreálló billentyűkombinációra meg is jelenítse az előzményeket és tudjunk belőle kedvünkre válogatni. Legnagyobb szerencsénkre tudjuk használni a beépített lista ablakot, amiben még kereső is van (ugyanaz, ami a <kbd>Ctrl+P</kbd> vagy a <kbd>Ctrl+R</kbd> kombinációkra is bejön):</p>

<pre class="code prettyprint lang-python">class ClipboardHistoryPasteCommand(sublimeplugin.TextCommand):
    def pasteSelected(self, view, index):
        for region in view.sel():
            view.insert(region.begin(), clipboardData[index])
    
    def run(self, view, args):
        view.window().showSelectPanel(
            clipboardData,
            functools.partial(self.pasteSelected, view),
            None,
            sublime.SELECT_PANEL_MONOSPACE_FONT
        );</pre>

<p>És természetesen a hozzá tartozó kis XML részlet:</p>

<pre class="code prettyprint lang-xml">&lt;binding key=&quot;alt+shift+q&quot; command=&quot;clipboardHistoryPaste&quot; /&gt;</pre>

<p>Nem a legtökéletesebb megoldás, például plugin újratöltéseknél elveszik a clipboardData tömb tartalma (lehetne például fájlba menteni menet közben), de kezdetnek megteszi. A teljes csomagot <a href="http://knagy.hu/sublime/TheClipboardHistory.sublime-package">innen</a> le lehet rántani (érdekes módon ClipboardHistory.sublime-package fájlnévvel nem mentek volna a billentyűparancs felüldefiniálások, mivel az Sublime ABC sorrendben tölti be a plugineket és a Default később van... :)).</p>

<p style="text-indent: 0; font-size: 10px; color: #808080;">[a képet köszönjük <a href="http://www.flickr.com/photos/snakphotography/5483168387/">ShutterBugChef</a>-nek]</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=5CUR3i_swtk:fU4vdWWjGh8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=5CUR3i_swtk:fU4vdWWjGh8:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=5CUR3i_swtk:fU4vdWWjGh8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=5CUR3i_swtk:fU4vdWWjGh8:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/5CUR3i_swtk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2011/06/19/a-zoldcitromok-ereje/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2011/06/19/a-zoldcitromok-ereje/</feedburner:origLink></item>
		<item>
		<title>A névtelenbe és tovább</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/rHNuYyw43Cs/</link>
		<comments>http://deadlime.hu/2011/05/30/a-nevtelenbe-es-tovabb/#comments</comments>
		<pubDate>Mon, 30 May 2011 21:31:26 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[closure]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=203</guid>
		<description><![CDATA[Bár nem tegnap történt, hogy az 5.3-as sorozat első verziója kijött, gondoltam kicsit körbejárom a névtelen függvények témakörét az ősidőktől napjainking.]]></description>
			<content:encoded><![CDATA[<p style="text-indent: 0;"><img src="http://deadlime.hu/wp-content/uploads/2011/05/buzz1.jpg" alt="" title="Buzz Lightyear" width="450" height="190" /></p>

<p>Bár nem tegnap történt, hogy az 5.3-as sorozat első verziója kijött, gondoltam kicsit körbejárom a névtelen függvények témakörét az ősidőktől napjainking. Az ősidő alatt itt természetesen a 4-es verziót értem, amikor még csak a <code>call_user_func</code> állt a rendelkezésünkre. Lássuk, hogyan is ment ez.</p>

<p>A <code>create_function</code> módszer (attól tekintsünk el, hogy a <code>__FUNCTION__</code> varázskonstans csak a 4.3-as verzióban jelent meg):</p>

<pre class="code prettyprint lang-php">$f = create_function('', 'echo __FUNCTION__ . &quot;\n&quot;;');
call_user_func($f);</pre>

<p>A függvény neve stringként módszer:</p>

<pre class="code prettyprint lang-php">$f = 'myFunction';
call_user_func($f);</pre>

<p>Az osztály és a statikus metódus neve tömbként:</p>

<pre class="code prettyprint lang-php">$f = array('MyClass', 'myStaticFunction');
call_user_func($f);</pre>

<p>Az objektum és a metódus neve tömbként:</p>

<pre class="code prettyprint lang-php">$c = new MyClass();
$f = array($c, 'myFunction');
call_user_func($f);</pre>

<p>Az osztály és a statikus metódus neve stringként (5.2.3-as PHP-tól):</p>

<pre class="code prettyprint lang-php">$f = 'MyClass::myStaticFunction';
call_user_func($f);</pre>

<p>Az objektum meghívása (5.3.0-s PHP-tól):</p>

<pre class="code prettyprint lang-php">$c = new MyClass();
call_user_func($c);</pre>

<p>És ezzel el is érkeztünk a jelenhez. Az 5.3.0-s verzióval megjelentek a closure-ök (az újfajta névtelen függvények), amolyan JavaScript-es definiálással:</p>

<pre class="code prettyprint lang-php">$f = function () {
};</pre>

<p>Természetesen a teljes visszafelé kompatibilitásról ne is álmodjunk ezért kezdjük is el végignézni az előző módokat, hogy mi működik továbbra is:</p>

<p>A <code>create_function</code> módszer megy továbbra is (emlékeim szerint 5.3 előtt is működött így, ezért ez nem túl meglepő):</p>

<pre class="code prettyprint lang-php">$f = create_function('', 'echo __FUNCTION__ . &quot;\n&quot;;');
$f();</pre>

<p>A függvény neve stringként módszer (működik):</p>

<pre class="code prettyprint lang-php">$f = 'myFunction';
$f();</pre>

<p>Itt sajnos meg is állhatunk. A tömbös rendszerek (<em>PHP Fatal error: Function name must be a string</em>) és az osztály+statikus metódus neve stringként (<em>PHP Fatal error: Call to undefined function MyClass::myStaticFunction()</em>) nem működik.</p>

<p>Maradt még az objektum direkt meghívása, ami működik, de ez sem túl nagy meglepetés, mivel az 5.3.0-s verzióbal vezették be hozzá az új varázsmetódust:</p>

<pre class="code prettyprint lang-php">$c = new MyClass();
$c();</pre>

<p>Ilyenkor (és a <code>call_user_func</code>-os esetben is) az osztály <code>__invoke()</code> metódusa hívódik meg.</p>

<p>Ezzel azt hiszem nagyjából ki is veséztük a különböző callback típusok és névtelen függvények hívhatóságát. Maradt még némi scope kérdés, de az házi feladat (annyit megsúgok, hogy a <code>use</code> a kulcsszó). Egy kis segítség hozzá:</p>

<ul>
    <li><a href="http://www.php.net/manual/en/functions.anonymous.php">Anonymous functions</a> [php.net]</li>
    <li><a href="http://www.php.net/manual/en/language.pseudo-types.php#language.types.callback">Callback pseudo-type</a> [php.net]</li>
    <li><a href="https://wiki.php.net/rfc/closures">RFC: Lambda functions and closures</a> [wiki.php.net]</li>
</ul><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=rHNuYyw43Cs:fCwXtHW6myA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=rHNuYyw43Cs:fCwXtHW6myA:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=rHNuYyw43Cs:fCwXtHW6myA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=rHNuYyw43Cs:fCwXtHW6myA:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/rHNuYyw43Cs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2011/05/30/a-nevtelenbe-es-tovabb/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2011/05/30/a-nevtelenbe-es-tovabb/</feedburner:origLink></item>
		<item>
		<title>Valósághű (?) sorbanállás szimulátor</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/7FIHMve-f_o/</link>
		<comments>http://deadlime.hu/2011/02/03/valosaghu-sorbanallas-szimulator/#comments</comments>
		<pubDate>Thu, 03 Feb 2011 21:03:17 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=186</guid>
		<description><![CDATA[Az úgy volt, hogy elgondolkoztam azon, hogy vajon miért jó az, ha a kiszolgálás folyamatát több részre bontják. Ha egyáltalán jó az. Offline, bolti kiszolgálásról van szó, mielőtt bárki - a blog témáját figyelembe véve - jogosan másra gondolna.]]></description>
			<content:encoded><![CDATA[<p>Az úgy volt, hogy elgondolkoztam azon, hogy vajon miért jó az, ha a kiszolgálás folyamatát több részre bontják. Ha egyáltalán jó az. Offline, bolti kiszolgálásról van szó, mielőtt bárki - a blog témáját figyelembe véve - jogosan másra gondolna.</p>

<p>Ha vesszük az értékesítő-pénztáros-árukiadó modellt, érzésre úgy tűnik, hogy a több sor végigjárása miatt többet is várunk. De a sorbanállás pszichológiája fura egy dolog. Jó példa erre a hipermarket, ahol N pénztárnak van N sora azért, mert az N pénztár 1 sor felállás zavaró lehet az embereknek a hosszú sor miatt, holott a várakozási idő úgy kevesebb lenne.</p>

<iframe title="YouTube video player" width="450" height="275" src="http://www.youtube.com/embed/F5Ri_HhziI0" frameborder="0" allowfullscreen></iframe>

<p>Itt az ideje szimulálni. Két eset lesz (meg talán egy bónusz :)). Az egyikben van 4 ember, aki értékesít, 1 kezeli a pénzt és 1 kiadja a vásárolt árut. A másikban 6 ember, aki a teljes vásárlási folyamatért felelős. Mindkét esetben ahány ember van, annyi sor is, valamint hirtelen nagyobb mennyiségű vásárló esik be a boltba, akik mindig a legrövidebb sort célozzák meg. A helyek közötti közlekedésre szánt időt figyelmen kívül hagyjuk. Nincsenek kezelve az olyan vásárlók, akik az értékesítés után "feladják" és hazamennek (csak érdeklődni jöttek be a boltba). Az egyes helyeken töltött időt random generáltam a következő intervallumokat használva:</p>

<dl>
	<dt>Értékesítés:</dt>
	<dd>30 és 300 másodperc között</dd>
	<dt>Pénztár:</dt>
	<dd>15 és 30 másodperc között</dd>
	<dt>Árukiadás:</dt>
	<dd>30 és 120 másodperc között</dd>
</dl>

<p>Az első változat eredményei 4 különböző adathalmazra, 25 egyszerre érkező vásárlóval (az eredmények percben vannak):</p>

<table width="100%" style="background-color: #FFF; border: 1px solid #ABC9AB;">
	<tr>
		<th>&nbsp;</th>
		<th>A1</th>
		<th>A2</th>
		<th>A3</th>
		<th>A4</th>
	</tr>
	<tr>
		<td>Átlagos sorbanállással töltött idő</td>
		<td align="right">14.37</td>
		<td align="right">14.58</td>
		<td align="right">12.57</td>
		<td align="right">12.36</td>
	</tr>
	<tr>
		<td>Az összes ember kiszolgálása</td>
		<td align="right">33.79</td>
		<td align="right">34.44</td>
		<td align="right">32.15</td>
		<td align="right">30.46</td>
	</tr>
</table>

<p>A kettes számú verzió a 6 eladóval, aki nem specializálódott:</p>

<table width="100%" style="background-color: #FFF; border: 1px solid #ABC9AB;">
	<tr>
		<th>&nbsp;</th>
		<th>A1</th>
		<th>A2</th>
		<th>A3</th>
		<th>A4</th>
	</tr>
	<tr>
		<td>Átlagos sorbanállással töltött idő</td>
		<td align="right">7.28</td>
		<td align="right">6.90</td>
		<td align="right">6.91</td>
		<td align="right">7.61</td>
	</tr>
	<tr>
		<td>Az összes ember kiszolgálása</td>
		<td align="right">24.28</td>
		<td align="right">22.12</td>
		<td align="right">27.27</td>
		<td align="right">23.65</td>
	</tr>
</table>

<p>Ezzel úgy tűnik el is dőlt, hogy a többszörös sorbanállás nem csak lassabbnak érződik, de lassabb is. Már amennyire meg lehet bízni az általam írt szimulációkban. :)</p>

<p>A bónusz eset megegyezik a kettes verzióval annyi különbséggel, hogy nem eladónként van egy sor, hanem egy sor van összesen:</p>

<table width="100%" style="background-color: #FFF; border: 1px solid #ABC9AB;">
	<tr>
		<th>&nbsp;</th>
		<th>A1</th>
		<th>A2</th>
		<th>A3</th>
		<th>A4</th>
	</tr>
	<tr>
		<td>Átlagos sorbanállással töltött idő</td>
		<td align="right">7.05</td>
		<td align="right">6.80</td>
		<td align="right">6.43</td>
		<td align="right">7.45</td>
	</tr>
	<tr>
		<td>Az összes ember kiszolgálása</td>
		<td align="right">21.61</td>
		<td align="right">23.75</td>
		<td align="right">18.89</td>
		<td align="right">21.80</td>
	</tr>
</table>

<p>A különbség nem annyira látványos, de azért még sikerült lefaragni valamennyit az időkből (az A2 idejét leszámítva, az valamilyen rejtélyes oknál fogva több lett).</p>

<p>A kód egyébként Python-ban készült és <a href="http://kriz.deadlime.hu/shop_simulator.zip">a használt adathalmazokkal együtt letölthető itt</a>. Kellemes szimulálást. :)</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=7FIHMve-f_o:oRSuyU8kWvQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=7FIHMve-f_o:oRSuyU8kWvQ:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=7FIHMve-f_o:oRSuyU8kWvQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=7FIHMve-f_o:oRSuyU8kWvQ:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/7FIHMve-f_o" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2011/02/03/valosaghu-sorbanallas-szimulator/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2011/02/03/valosaghu-sorbanallas-szimulator/</feedburner:origLink></item>
		<item>
		<title>Mit nézel?</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/KK7mV0J8_2Q/</link>
		<comments>http://deadlime.hu/2010/06/04/mit-nezel/#comments</comments>
		<pubDate>Fri, 04 Jun 2010 18:51:52 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=179</guid>
		<description><![CDATA[Úgy tűnik tartom magamat az elmúlt években már megszokott kontent mennyiséghez. Most is csak azért írok, hogy hírt adjak arról, hogy összedobtam egy kis oldalt, aminek segítségével nyomon lehet követni ismerőseink és saját magunk sorozatnézési szokásait. Használjátok egészséggel. :) Ja... a cím: s01e01.hu]]></description>
			<content:encoded><![CDATA[<p>Úgy tűnik tartom magamat az elmúlt években már megszokott kontent mennyiséghez. Most is csak azért írok, hogy hírt adjak arról, hogy összedobtam egy kis oldalt, aminek segítségével nyomon lehet követni ismerőseink és saját magunk sorozatnézési szokásait. Használjátok egészséggel. :)</p>

<p>Ja... a cím: <a href="http://s01e01.hu/">s01e01.hu</a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=KK7mV0J8_2Q:qcurUPDtbZo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=KK7mV0J8_2Q:qcurUPDtbZo:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=KK7mV0J8_2Q:qcurUPDtbZo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=KK7mV0J8_2Q:qcurUPDtbZo:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/KK7mV0J8_2Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2010/06/04/mit-nezel/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2010/06/04/mit-nezel/</feedburner:origLink></item>
		<item>
		<title>PDO móka: l33t SQL</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/PJvwMMWXC-4/</link>
		<comments>http://deadlime.hu/2009/09/05/pdo-moka-l33t-sql/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 19:58:07 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[PDO]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=169</guid>
		<description><![CDATA[Már lassan egy éve nem volt új bejegyzés, gondoltam ideje írni valamit. :) Régebben már volt szó a PHP objektum-orientált adatbázis elérési felületéről, a PDO-ról. Mivel utóbb inkább csak a használatára tértem ki, nem lett megemlítve, hogy ezekből az osztályokból származtathatjuk saját osztályainkat is, ami alapvetően egy jó dolog tud lenni. Vegyünk is egy egyszerű [...]]]></description>
			<content:encoded><![CDATA[<p>Már lassan egy éve nem volt új bejegyzés, gondoltam ideje írni valamit. :) Régebben már volt szó <a href="http://deadlime.hu/2006/02/11/mi-is-az-a-pdo/">a PHP objektum-orientált adatbázis elérési felületéről</a>, a PDO-ról. Mivel utóbb inkább csak a használatára tértem ki, nem lett megemlítve, hogy ezekből az osztályokból származtathatjuk saját osztályainkat is, ami alapvetően egy jó dolog tud lenni.</p>

<p>Vegyünk is egy egyszerű példát. Tegyük fel azt, hogy már annyira jók vagyunk, hogy az SQL szerverrel is csak <a href="http://en.wikipedia.org/wiki/Leet">l33t nyelven</a> vagyunk hajlandóak kommunikálni. Persze a mysqld (vagy egyéb tetszőleges daemon) nem ilyen megértő, és folyamatosan panaszkodik, hogy nem ért meg minket. A probléma elsimítása érdekében származtatunk a beépített PDO osztályból egy sajátot:</p>

<pre class="code prettyprint lang-php">class L33tPDO extends PDO {
	private static $from = array(
		's3l3ct', 'fr0m', 'wh3r3', 's3t', '1ns3rt', '1nt0', 'upd4t3', '0rd3r', '4sc', 'd3sc', 'l3ft', 'r1ght', '1nn3r', 'j01n'
	);
	private static $to = array(
		'SELECT', 'FROM', 'WHERE', 'SET', 'INSERT', 'INTO', 'UPDATE', 'ORDER', 'ASC', 'DESC', 'LEFT', 'RIGHT', 'INNER', 'JOIN'
	);
	public function query($statement, $type = false, $param1 = false, $param2 = false) {
		$statement = $this-&gt;convertStatement($statement);
		
		if ($type &amp;&amp; $param1 &amp;&amp; $param2) {
			return parent::query($statement, $type, $param1, $param2);
		}
		if ($type &amp;&amp; $param1) {
			return parent::query($statement, $type, $param1);
		}
		if ($type) {
			return parent::query($statement, $type);
		}
		
		return parent::query($statement);
	}
	public function prepare($statement, $driver_options = array()) {
		$statement = $this-&gt;convertStatement($statement);
		parent::prepare($statement, $driver_options);
	}
	private function convertStatement($statement) {
		return str_ireplace(self::$from, self::$to, $statement);
	}
}</pre>

<p>Hogy takarékoskodjunk a hellyel, a kulcsszavak listája nem teljes. Nézzünk is egy példát a  használatra:</p>

<pre class="code prettyprint lang-php">$conn = new L33tPDO('pgsql:host=localhost port=5432 dbname=test user=test password=test');

$stmt = $conn-&gt;query(&quot;s3l3ct * fr0m users wh3r3 id &gt; 1 0rd3r by login_name 4sc&quot; );

var_dump($stmt-&gt;fetchAll());</pre>

<p>Bár a felhozott példa nem igényli, a PDOStatement osztályból is származtathatunk sajátot, csak meg kell mondanunk a saját PDO osztályunknak, hogy az általunk írt PDOStatement-tet adja vissza a megfelelő függvényei. Ehhez bővítsük ki a L33tPDO osztályunkat egy konstruktorral:</p>

<pre class="code prettyprint lang-php">function __construct($dsn, $username = null, $password = null, $driver_options = array()) {
	parent::__construct($dsn, $username, $password, $driver_options);
	
	$this-&gt;setAttribute(PDO::ATTR_STATEMENT_CLASS, array('L33tPDOStatement', array($this)));
}</pre>

<p>És egy hozzá passzoló statement osztály:</p>

<pre class="code prettyprint lang-php">class L33tPDOStatement extends PDOStatement {
	private $dbh;
	protected function __construct($dbh) {
		$this -&gt; dbh = $dbh;
	}
}</pre>

<p>Ennyit mára. További kellemes kódolást.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/deadlime?a=PJvwMMWXC-4:T1vFcyR0U8Q:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=PJvwMMWXC-4:T1vFcyR0U8Q:7Q72WNTAKBA"><img src="http://feeds.feedburner.com/~ff/deadlime?d=7Q72WNTAKBA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/deadlime?a=PJvwMMWXC-4:T1vFcyR0U8Q:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/deadlime?i=PJvwMMWXC-4:T1vFcyR0U8Q:D7DqB2pKExk" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/PJvwMMWXC-4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2009/09/05/pdo-moka-l33t-sql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2009/09/05/pdo-moka-l33t-sql/</feedburner:origLink></item>
		<item>
		<title>Debuggolás, jól átsütve</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/RtPFQzoo23A/</link>
		<comments>http://deadlime.hu/2008/12/15/debuggolas-jol-atsutve/#comments</comments>
		<pubDate>Mon, 15 Dec 2008 20:51:06 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[Doctrine]]></category>
		<category><![CDATA[Firebug]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[FirePHP]]></category>
		<category><![CDATA[logolás]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=137</guid>
		<description><![CDATA[Talán nem túlzás azt állítani, hogy a Firebug a legjobb dolgok közé tartozik, ami manapság egy JavaScript fejlesztővel történhetnek. A több mint 10 millió letöltés, valamint a tény, hogy - bár maga is kiegészítő - kiegészítőket fejlesztenek hozzá elég bizonyítékul is szolgálhat ennek alátámasztására. Egy ilyen kiegészítőbe futottam bele még valamikor a múlt héten, ami [...]]]></description>
			<content:encoded><![CDATA[<p>Talán nem túlzás azt állítani, hogy a Firebug a legjobb dolgok közé tartozik, ami manapság egy JavaScript fejlesztővel történhetnek. A több mint 10 millió letöltés, valamint a tény, hogy - bár maga is kiegészítő - kiegészítőket fejlesztenek hozzá elég bizonyítékul is szolgálhat ennek alátámasztására. Egy ilyen kiegészítőbe futottam bele még valamikor a múlt héten, ami a FirePHP nevet viseli (a nevével ellentétben bármely más szerver oldali nyelvvel használható, ami képes header-öket kiküldeni). Nincs is másra szükségünk csak egy <a href="http://www.mozilla-europe.org/hu/firefox/">Firefox</a>-ra (ez remélhetőleg már mindenkinek van :)), egy <a href="http://getfirebug.com/">Firebug</a>-ra (ez is esélyes lehet, hogy akad a közelben) és a <a href="http://www.firephp.org/">FirePHP</a>-ra. Meg egy kis szerveroldali scriptre, ami szintén a FirePHP oldaláról tölthető le.</p>

<p style="text-align: center;"><img src="http://deadlime.hu/wp-content/uploads/2008/12/firephp.png" alt="FirePHP" title="FirePHP" width="310" height="120" class="size-full wp-image-140" /></p>

<p>A kiterjesztés mögött rejlő ötlet rettentően egyszerű (és talán éppen ezért olyan fantasztikus): küldjünk ki pár speciális fejlécet valamiféle JSON tartalommal, amit kliens oldalon a kiegészítő feldolgoz és a Firebug segítségével szépen meg is jelenít. Ezek lehetnek több prioritásba sorolható egyszerű szöveges üzenetek (hasonlóak a Firebug beépített üzeneteihez), táblázatok, szépen formázott backtrace-ek vagy akár <a href="http://php.net/print_r">print_r()</a>-hez hasonló információk változókról.</p>

<p>Nézzünk is egy példát a felhasználásra: jelenítsük meg az oldal legenerálása során küldött SQL lekérdezéseket, külön kiemelve azokat, amik lassabban futnak, mint szeretnénk (a példához <a href="http://www.doctrine-project.org/">Doctrine</a> van használva):</p>

<pre class="code prettyprint lang-php">class My_Doctrine_Logger extends Doctrine_EventListener {
    private $queryTime;
    public function preQuery(Doctrine_Event $event) {
        $this-&gt;queryTime = microtime(true);
    }
    public function preStmtExecute(Doctrine_Event $event) {
        $this-&gt;queryTime = microtime(true);
    }
    public function postQuery(Doctrine_Event $event) {
        $this-&gt;logQuery($event-&gt;getQuery());
    }
    public function postStmtExecute(Doctrine_Event $event) {
        $this-&gt;logQuery($event-&gt;getQuery());
    }
    private function logQuery($queryString) {
        $t = microtime(true) - $this-&gt;queryTime;
        
        $msg = '['.str_pad(round($t, 5), 7, '0').']: '.$queryString;
        
        if ($t &gt; 0.01) {
            FB::warn('Slow SQL Query: '.$msg);
        }
        else {
            FB::info('SQL Query: '.$msg);
        }
    }
}</pre>

<p>És ehhez még nem árt valami ilyesmit is hozzácsapni, hogy a Doctrine tudjon a mi kis osztályunkról:</p>

<pre class="code prettyprint lang-php">$conn = Doctrine_Manager::connection( $dsn );
$conn-&gt;addListener(new My_Doctrine_Logger());</pre>

<p>Az egészből az <code>FB::</code> kezdetű sorok érdekesek csak. A működésükhöz szükség lehet az output buffering bekapcsolására vagy kellő önuralomra, hogy az utolsó <code>FB::</code>-s hívásig nem nyomunk ki semmit a kimenetre. :)<br/>
Ami még érdekes lehet, hogy Ajax-os kérések és Location fejléccel átirányított oldalak hasonló üzenetei is megjelennek a Firebug ablakában, szépen csoportosítva, ezzel végtelenül egyszerűvé téve az Ajaxos kérések és a rájuk érkező válaszok hibamentesítését, sok-sok órát megspórolva ezzel szegény fejlesztőknek. Mindezt természetesen anélkül, hogy az eredeti tartalmat teleszemetelnénk mindenféle nem odavaló dologgal (csúnyán is nézne ki a JSON válasz közepén egy méretes <a href="http://php.net/var_dump">var_dump()</a> kimenet, arról nem is beszélve, hogy a kliens oldalon se tudna vele túl sokat kezdeni a JavaScript).</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/deadlime?a=HXEOsc6q"><img src="http://feeds.feedburner.com/~f/deadlime?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=w46BsLJq"><img src="http://feeds.feedburner.com/~f/deadlime?d=50" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=WHf7RCyw"><img src="http://feeds.feedburner.com/~f/deadlime?i=WHf7RCyw" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/RtPFQzoo23A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2008/12/15/debuggolas-jol-atsutve/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2008/12/15/debuggolas-jol-atsutve/</feedburner:origLink></item>
		<item>
		<title>A kivétel erősíti a... kódot</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/OGiCKJW5Eps/</link>
		<comments>http://deadlime.hu/2008/09/22/a-kivetel-erositi-a-kodot/#comments</comments>
		<pubDate>Mon, 22 Sep 2008 19:15:29 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[hibakezelés]]></category>
		<category><![CDATA[kivételek]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=131</guid>
		<description><![CDATA[A szokásos "napi" php.net böngészgetésem során bukkantam rá a lentebb olvasható kódrészletre (bár nem egy bonyolult dolog, de mégsem jutott volna magamtól eszembe), amit szerintem kötelezővé kellene tenni minden egyes PHP alapú alkalmazás fejlesztési időszaka alatt. A kód nem csinál mást, mint hogy minden hibát kivétellé alakít át, így ha nincsenek elkapva, akkor egy egyszerű [...]]]></description>
			<content:encoded><![CDATA[<p>A szokásos "napi" <a href="http://php.net/">php.net</a> böngészgetésem során bukkantam rá a lentebb olvasható kódrészletre (bár nem egy bonyolult dolog, de mégsem jutott volna magamtól eszembe), amit szerintem kötelezővé kellene tenni minden egyes PHP alapú alkalmazás fejlesztési időszaka alatt. A kód nem csinál mást, mint hogy minden hibát kivétellé alakít át, így ha nincsenek elkapva, akkor egy egyszerű <code>E_NOTICE</code>-tól is lehal az oldal fatal error-ral, az <code>error_reporting</code> beállítástól függetlenül. :)</p>

<pre class="code prettyprint lang-php">function error_handler($errno, $errstr, $errfile, $errline)
{
    throw new ErrorException(
        $errstr, 0, $errno,
        $errfile, $errline
    );
}
set_error_handler('error_handler');</pre>

<p>Egyéni ízlés kérdése, de én még az alábbi kóddal kiegészíteném, hogy fatal error-ok helyett inkább valami olvasható dolgot kapjak:</p>

<pre class="code prettyprint lang-php">function exception_handler($ex)
{
	print('&lt;pre&gt;'.$ex.'&lt;/pre&gt;');
}
set_exception_handler('exception_handler');</pre>

<p>És hogy miért is lenne hasznos? Elég sokan kikapcsolják az <code>E_NOTICE</code>-ok jelzését még fejlesztés alatt is, mondván hogy az nem számít. Pedig elég sok kisebb hibára (pl. változó név vagy tömb kulcs elgépelésekre) hívhatná fel a figyelmet, amik így csak a tesztelési időszakban derülnek ki (ha kiderülnek). Emellett biztonsági haszna is van, mint az <a href="http://www.php.net/manual/en/security.errors.php">a php.net-en is olvasható</a>.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/deadlime?a=ZAMAjsEl"><img src="http://feeds.feedburner.com/~f/deadlime?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=J0ju67Eo"><img src="http://feeds.feedburner.com/~f/deadlime?d=50" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=5fMcArcd"><img src="http://feeds.feedburner.com/~f/deadlime?i=5fMcArcd" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/OGiCKJW5Eps" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2008/09/22/a-kivetel-erositi-a-kodot/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2008/09/22/a-kivetel-erositi-a-kodot/</feedburner:origLink></item>
		<item>
		<title>A kígyó esete a parancssorral I.</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/M-xnuA0EiMw/</link>
		<comments>http://deadlime.hu/2008/09/21/a-kigyo-esete-a-parancssorral-1/#comments</comments>
		<pubDate>Sun, 21 Sep 2008 13:05:01 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[parancssor]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=127</guid>
		<description><![CDATA[Mostanság parancssori scripteket írogatok Python-ban, ha éppen nincs jobb dolgom (ritka). Gondoltam hát, hogy ezzel kapcsolatos tapasztalataimat és a nyelvvel való ismerkedésemet megosztom egy - egyelőre még nem tudni hány részes - bejegyzéssorozatban. Az első rész témája az alkalmazásnak átadott paraméterek feldolgozása a getopt és az optparse modulok segítségével. A programunk egy egyszerű "Hello World!" [...]]]></description>
			<content:encoded><![CDATA[<p>Mostanság parancssori scripteket írogatok Python-ban, ha éppen nincs jobb dolgom (ritka). Gondoltam hát, hogy ezzel kapcsolatos tapasztalataimat és a nyelvvel való ismerkedésemet megosztom egy - egyelőre még nem tudni hány részes - bejegyzéssorozatban. Az első rész témája az alkalmazásnak átadott paraméterek feldolgozása a <code>getopt</code> és az <code>optparse</code> modulok segítségével.</p>

<p>A programunk egy egyszerű "Hello World!" alkalmazás lesz parancssori stílusban. Két fajta bemenő paramétert fogad el. Az egyik a név, akinek köszönni fog, a másikra pedig megjeleníti a súgót, hogy hogyan is kell paraméterezni ezt a rettentő bonyolult programot.</p>

<h3>A getopt</h3>

<p>A legkézenfekvőbb módszer a paraméterek feldolgozására a <a href="http://docs.python.org/lib/module-getopt.html"><code>getopt</code> modul</a> <code>getopt()</code> függvénye. Szükségünk lesz ezen kívül még a <a href="http://docs.python.org/lib/module-sys.html"><code>sys</code> modulra</a>, hogy a feldolgozandó lista is a birtokunkba kerüljön (mellesleg a <a href="http://hu2.php.net/getopt"><code>getopt()</code> függvény</a> PHP-ban is létezik):</p>

<pre class="code prettyprint lang-python">from getopt import getopt, GetoptError
import sys</pre>

<p>A feldolgozás során a <code>getopt()</code> egy <code>GetoptError</code> kivételt dob, ha nem talál rendben valamit. A függvény első paramétere a bemenő adatok tömbje (az első indextől, mivel a nulladik index az a meghívott fájl neve), a második paraméter a rövid kapcsolók listája (kettőspont van a betűk mögött, amik paramétert várnak), a harmadik paraméter pedig a hosszú kapcsolók listája (egyenlőségjellel a név mögött, ha paramétert várnak). A visszatérési értéke két tömb, az első paraméternév-érték párokat tartalmaz, a második pedig a fel nem dolgozott parancssori argumentumokat.</p>

<pre class="code prettyprint lang-python">try:
    opts, args = getopt(sys.argv[1:], 'hn:', ['help', 'name='])
except GetoptError:
    print 'Parameterezesi hiba'
    sys.exit(1)</pre>

<p>Ha nem szállt el a program hibával, akkor megadjuk a változóinknak (jelen esetben csak a name-nek) az alapértelmezett értékeket és végigmegyünk az <code>opts</code> tömbön, hogy feltölthessük őket valós adatokkal.</p>

<pre class="code prettyprint lang-python">name = False

for opt, arg in opts:
    if opt in ('-h', '--help'):
        print 'usage: %s --name=NAME' % sys.argv[0]
        sys.exit(0)
    elif opt in ('-n', '--name'):
        name = arg</pre>

<p>Nem maradt más hátra, mint a <code>name</code> változó ellenőrzése és siker esetén a köszöntés kiiratása:</p>

<pre class="code prettyprint lang-python">if not name:
    print 'Add meg a nevet!'
    sys.exit(2)

print 'Hello, ' + name + '!'</pre>

<p>Ha a <code>name</code> változó kezdőértéke például <code>'World'</code> lenne, akkor a feldolgozás utáni ellenőrzést el is hagyhatnánk és a programunk működése úgy módosulna, hogy a világot köszöntené, ha nem kap más paramétert.</p>

<h3>Az optparse</h3>

<p>A Python 2.3-as verziója óta rendelkezésre áll az <a href="http://docs.python.org/lib/module-optparse.html"><code>optparse</code> modul</a> is, ami még egy pár gondot levesz a vállunkról méghozzá objektum-orientált módon. Ez esetben a <code>sys</code> modulra nem lesz szükségünk, a parancssori paraméterek begyűjtését az <code>optparse</code> végzi.</p>

<pre class="code prettyprint lang-python">from optparse import OptionParser</pre>

<p>Beállítjuk, hogy milyen paramétereket várunk és azt is, hogy mik lesznek ezeknek az alapértelmezett értékei. Ezek után feldolgozzuk a bejövő adatokat.</p>

<pre class="code prettyprint lang-python">parser = OptionParser()
parser.add_option(
    '-n', '--name',
    dest = 'name',
    help = 'a koszontendo neve',
    metavar = 'NAME'
)
parser.set_defaults(name = False)
opts, args = parser.parse_args()</pre>

<p>Ami azonnal feltűnhet, hogy a <code>-h</code> és <code>--help</code> kapcsolókat nem adtuk meg. Ezt az <code>optparser</code> automatikusan megteszi és még a segítség szövegét is legenerálja nekünk (az <code>add_option()</code> <code>help</code> és  <code>metavar</code> paramétere alapján). A feldolgozás után kapott értékeket az <code>opts</code> tömbben érjük el az <code>add_option()</code>-nak megadott <code>dest</code> paraméter nevű kulcsként.</p>

<pre class="code prettyprint lang-python">if not opts.name:
    parser.error('Add meg a nevet!')

print 'Hello ' + opts.name + '!'</pre>

<p>Ezzel meg is lennénk. Nem tűnik sokkal rövidebbnek a kód, de több paraméter esetén szembetűnőbb lenne a <code>getopt</code> esetén a kód közepén az a hatalmas <code>if-elif</code> erdő. Ezen kívül ugye egy elég szép súgó kimenetet generál nekünk és bizonyos fokig kezeli a hibákat is (üres paraméter, nem numerikus paraméter - ha az van beállítva) egy kulturált hibakimenetet mutatva.</p>

<h3>Példafájlok</h3>

<ul>
    <li><a href="http://kriz.deadlime.hu/python/hello_world_getopt.py"><code>getopt</code> példafájl</a></li>
    <li><a href="http://kriz.deadlime.hu/python/hello_world_optparse.py"><code>optparse</code> példafájl</a></li>
</ul>

<p>A következő részben előreláthatólag különböző konfigurációs fájlok feldolgozásának módjáról lesz szó. Addig is kellemes paraméterezést.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/deadlime?a=SZe8iexr"><img src="http://feeds.feedburner.com/~f/deadlime?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=pdMkvvTQ"><img src="http://feeds.feedburner.com/~f/deadlime?d=50" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=PJEoaNkZ"><img src="http://feeds.feedburner.com/~f/deadlime?i=PJEoaNkZ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/M-xnuA0EiMw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2008/09/21/a-kigyo-esete-a-parancssorral-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2008/09/21/a-kigyo-esete-a-parancssorral-1/</feedburner:origLink></item>
		<item>
		<title>Kígyóbűvölés alapfokon</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/IjBknlzWmJ8/</link>
		<comments>http://deadlime.hu/2008/07/27/kigyobuvoles-alapfokon/#comments</comments>
		<pubDate>Sat, 26 Jul 2008 23:46:39 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=114</guid>
		<description><![CDATA[Néha a lustaságomon felül kerekedik az a vágy, hogy új programozási nyelveket ismerjek meg. Ennek lett a legfrissebb áldozata a Python. Bár már volt vele dolgom régebben is, de körülbelül csak egy Fibonacci-számokat számoló rekurzív függvény megvalósításáig jutottam (az is nagy valószínűséggel valami példakód volt valamelyik segédletből). Magáról a nyelvről azt lehet elmondani, hogy feltűnően [...]]]></description>
			<content:encoded><![CDATA[<p>Néha a lustaságomon felül kerekedik az a vágy, hogy új programozási nyelveket ismerjek meg. Ennek lett a legfrissebb áldozata a <a href="http://www.python.org/">Python</a>. Bár már volt vele dolgom régebben is, de körülbelül csak egy Fibonacci-számokat számoló rekurzív függvény megvalósításáig jutottam (az is nagy valószínűséggel valami példakód volt valamelyik segédletből).</p>

<p>Magáról a nyelvről azt lehet elmondani, hogy feltűnően szépnek mondható ahhoz képest, hogy a Pascal-stílusú nyelvek közé tartozik. És nem csak egyszerűen szép, hanem törekszik arra, hogy a benne írt kód is szép legyen (ahogy az a <a href="http://wiki.python.org/moin/PythonPhilosophy">Python filozófiáinak listájában</a> is szerepel: <em>"Beautiful is better than ugly."</em>). Persze ehhez az is kell, hogy ne csak Python nyelven, de Python stílusban is programozunk.<br/>
A kinézetet tekintve legszembetűnőbb különbség más nyelvekhez képest a kód kötelező indentálása. Nincsenek sorvégi pontok, pontosvesszők, if-eket és egyéb blokkszerkezeteket lezáró hullámos zárójelek vagy kulcsszavak. Minden az új sor karakterek és az indentálás alapján dől el. De mivel kódolás közben a nagy többség amúgy is szokott új sorokat és tabokat használni (és mivel a kötelező indentálás az esetek közel 100%-ában megegyezik azzal, amúgy is használnánk), ezért elég gyorsan hozzá lehet szokni ahhoz, hogy tulajdonképpen kevesebbet kell gépelni. Persze ez még kevés ahhoz, hogy használható is legyen valamire. Mivel napjaim nagy részét a webprogramozás teszi ki, ezért a szintaktikai ismerkedés után első dolgom az volt, hogy utánanézzek, mire is képes a kígyó a weben...</p>

<p>Itt már kezdődtek a gondok. Mutatkoztak annak a jelei, hogy a Python egy általános scriptnyelv, nem webre teremtették, mint a PHP-t. Ha mindenféle keretrendszer nélkül szeretnénk benne webprogramozni, csupán a megfelelő Apache beállítások elvégzésével és egy mod_python betöltésével... hát... nem lesz egy könnyű dolgunk (arról nem is beszélve, hogy a mod_python mellett van számos más alternatíva is és akkor még el sem jutottunk odáig, hogy keretrendszert válasszunk). Persze egy nagyon minimális keretrendszert össze lehet dobni pár tíz perc és 50-60 sor kód alatt (amit meg is tettem, just for fun), de végső soron arra jutottam, hogy ha webprogramozás, akkor egyelőre maradok a PHP-nél.</p>

<p>A gond ez után már csak az volt, hogy ha nem webprogramozásra, akkor mégis mi a fenére használjak egy scriptnyelvet? Mivel egy általános nyelvről van szó, elég sok dologra lehetne használni. Ennek okán úgy döntöttem, hogy ha valami nem webprogramozással kapcsolatos, de programozást igénylő problémába ütközöm, akkor azt Python-ban próbálom majd megoldani, ahelyett, hogy a jól bevált PHP-t használnám. Így ha épp egy random, 8 betűből álló stringre van szükségem, akkor nem azt írom, hogy:</p>

<pre class="code prettyprint lang-php">$str = '';
for ($i = 0; $i &lt; 8; ++$i) {
	$str .= chr(mt_rand(97, 122));
}
print $str;</pre>

<p>Hanem inkább ezt:</p>

<pre class="code prettyprint lang-python">from random import randint
print ''.join([chr(randint(97, 122)) for x in range(8)])</pre>

<p>Valószínűleg így egyes problémákat tovább tart megoldani, mivel kénytelen vagyok utánanézni olyan dolgoknak, amiknek PHP-ban nem kellene, viszont ha sosem használom a nyelvet valós problémák megoldására, akkor egyrészt nem lesz benne gyakorlatom, másrészt pedig elfelejtem. Végeredményben tehát a Python egy szép nyelv (és nem csak külalakra, hanem működését és megoldásait tekintve is), amivel érdemes foglalkozni. Már csak azért is, hogy új szemléletmódokat szedjen magára az ember. Ezt pedig jól segíti <a href="http://www.diveintopython.org/">ez az online is olvasható könyv</a>.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/deadlime?a=m7hhESYA"><img src="http://feeds.feedburner.com/~f/deadlime?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=cQu3umMe"><img src="http://feeds.feedburner.com/~f/deadlime?d=50" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=8GivbKxm"><img src="http://feeds.feedburner.com/~f/deadlime?i=8GivbKxm" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/IjBknlzWmJ8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2008/07/27/kigyobuvoles-alapfokon/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2008/07/27/kigyobuvoles-alapfokon/</feedburner:origLink></item>
		<item>
		<title>Firefox 3 - Download Day</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/0eVAnp-j-O8/</link>
		<comments>http://deadlime.hu/2008/06/17/firefox-3-download-day/#comments</comments>
		<pubDate>Tue, 17 Jun 2008 07:38:42 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[Firefox]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=112</guid>
		<description><![CDATA[Segítsetek Vuknak Firefoxnak a kis rókának! :)]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><a href="http://www.spreadfirefox.com/node&#038;id=15940&#038;t=264"><img alt="Download Day" title="Download Day" src="http://deadlime.hu/wp-content/uploads/2008/06/dday_badge_fox.png" style="border: 2px solid #CCC;"/></a></p>

<p>Segítsetek <del>Vuknak</del> Firefoxnak a kis rókának! :)</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/deadlime?a=oD893T9t"><img src="http://feeds.feedburner.com/~f/deadlime?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=RtreRtzd"><img src="http://feeds.feedburner.com/~f/deadlime?d=50" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=pa3zeqLK"><img src="http://feeds.feedburner.com/~f/deadlime?i=pa3zeqLK" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/0eVAnp-j-O8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2008/06/17/firefox-3-download-day/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2008/06/17/firefox-3-download-day/</feedburner:origLink></item>
		<item>
		<title>Kliens oldali XSLT</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/PNmylavTHN8/</link>
		<comments>http://deadlime.hu/2008/04/03/kliens-oldali-xslt/#comments</comments>
		<pubDate>Thu, 03 Apr 2008 08:48:12 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[XSLT]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=111</guid>
		<description><![CDATA[Avagy az oldal összerakásával terheljük inkább a látogató böngészőjét a szerver helyett. Néha egész érdekes dolgokat lehet látni, ha az ember - szakmai ártalomból, vagy csak egyszerű kíváncsiságból - beleles egyes oldalak forrásába. Az ilyen oldalak közé tartozik a The World of Warcraft Armory is. Az első pillantásra elég bonyolultnak tűnő oldal mögött meglepően kicsi [...]]]></description>
			<content:encoded><![CDATA[<p><em>Avagy az oldal összerakásával terheljük inkább a látogató böngészőjét a szerver helyett.</em></p>

<p>Néha egész érdekes dolgokat lehet látni, ha az ember - szakmai ártalomból, vagy csak egyszerű kíváncsiságból - beleles egyes oldalak forrásába. Az ilyen oldalak közé tartozik a <a href="http://eu.wowarmory.com/">The World of Warcraft Armory</a> is. Az első pillantásra elég bonyolultnak tűnő oldal mögött meglepően kicsi (5 soros) XML fájl van. Legalábbis látszólag. Természetesen az XSLT áll a dolog mögött, aminek a szerver oldali alkalmazásáról már <a href="http://deadlime.hu/2006/03/03/xslt-a-gyakorlatban/">réges-régen ejtettem pár szót</a>. Nézzük akkor most meg, hogy kliens oldalon mit művelhetünk vele:</p>

<h3>Az alapok</h3>

<p>Amire szükségünk lesz az egy XML és egy XSL fájl. A rendszerben valószínűleg az XSL fájlok statikusak lesznek, az XML-ek pedig szerver oldalon fognak generálódni. Nézzünk egy egyszerű blog példát kezdésnek:</p>

<pre class="code prettyprint lang-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;?xml-stylesheet type=&quot;text/xsl&quot; href=&quot;index.xsl&quot;?&gt;
&lt;page&gt;
    &lt;post url=&quot;http://example.com/&quot;&gt;
        &lt;name&gt;A bejegyzés címe #1&lt;/name&gt;
        &lt;content&gt;
            &lt;p&gt;A bejegyzés tartalma #1&lt;/p&gt;
        &lt;/content&gt;
        &lt;author url=&quot;http://example.com/&quot;&gt;író #1&lt;/author&gt;
        &lt;tags&gt;
            &lt;tag url=&quot;http://example.com/&quot;&gt;tag #1&lt;/tag&gt;
            &lt;tag url=&quot;http://example.com/&quot;&gt;tag #2&lt;/tag&gt;
        &lt;/tags&gt;
    &lt;/post&gt;
    &lt;post url=&quot;http://example.com/&quot;&gt;
        &lt;name&gt;A bejegyzés címe #2&lt;/name&gt;
        &lt;content&gt;
            &lt;p&gt;A bejegyzés tartalma #2&lt;/p&gt;
        &lt;/content&gt;
        &lt;author url=&quot;http://example.com/&quot;&gt;író #1&lt;/author&gt;
        &lt;tags&gt;
            &lt;tag url=&quot;http://example.com/&quot;&gt;tag #3&lt;/tag&gt;
            &lt;tag url=&quot;http://example.com/&quot;&gt;tag #4&lt;/tag&gt;
            &lt;tag url=&quot;http://example.com/&quot;&gt;tag #5&lt;/tag&gt;
        &lt;/tags&gt;
    &lt;/post&gt;
&lt;/page&gt;</pre>

<p>Gyakorlatilag bármilyen XML-t használhatunk, az oldal akár lehetne egy RSS feed is, amit a megfelelő XSL fájllal formálunk weboldal alakúvá. Esetünkben ez a fájl valahogyan így néz ki:</p>

<pre class="code prettyprint lang-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
    &lt;xsl:output method=&quot;html&quot; doctype-system=&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot; doctype-public=&quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;/&gt;
    &lt;xsl:template match=&quot;page&quot;&gt;
        &lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
            &lt;head&gt;
                &lt;title&gt;XSL teszt&lt;/title&gt;
            &lt;/head&gt;
            &lt;body&gt;
                &lt;div id=&quot;container&quot;&gt;
                    &lt;xsl:apply-templates/&gt;
                &lt;/div&gt;
            &lt;/body&gt;
        &lt;/html&gt;
    &lt;/xsl:template&gt;
    &lt;xsl:template match=&quot;post&quot;&gt;
        &lt;div class=&quot;post&quot;&gt;
            &lt;h2&gt;&lt;a href=&quot;{@url}&quot;&gt;&lt;xsl:value-of select=&quot;name/text()&quot;/&gt;&lt;/a&gt;&lt;/h2&gt;
            &lt;ul class=&quot;post-tags&quot;&gt;
                &lt;xsl:for-each select=&quot;tags/tag&quot;&gt;
                    &lt;li&gt;&lt;a href=&quot;{@url}&quot;&gt;&lt;xsl:value-of select=&quot;text()&quot;/&gt;&lt;/a&gt;&lt;/li&gt;
                &lt;/xsl:for-each&gt;
            &lt;/ul&gt;
            &lt;div class=&quot;post-content&quot;&gt;&lt;xsl:copy-of select=&quot;content&quot;/&gt;&lt;/div&gt;
        &lt;/div&gt;
    &lt;/xsl:template&gt;
&lt;/xsl:stylesheet&gt;</pre>

<p>A transzformáció az első illeszkedő <code>&lt;xsl:template&gt;</code> blokk végrehajtása után leáll (esetünkben ez az <code>&lt;xsl:template match="page"&gt;</code> kezdetű blokk). Ahhoz, hogy további template blokkokat hajthassunk végre a jelenlegi elemen (esetünkben ez az XML <code>&lt;page&gt;</code> tagje), vagy annak gyerekein, az <code>&lt;xsl:apply-templates/&gt;</code> taget kell használni (ennek van egy <code>select=""</code> tulajdonsága, amivel még szűkíthetjük a node-okat, amin szeretnénk végrehajtani transzformációt).</p>

<p>A <code>&lt;post&gt;</code> tagre illeszkedő template-ben látható példa arra, hogy hogyan tudunk egy tulajdonságnak értéket adni (<code>{@url}</code>), hogyan lehet sima szöveget kinyerni az eredeti XML-ből (<code>&lt;xsl:value-of select="name/text()"/&gt;</code>) valamint arra, hogyan lehet egy XML részt egy az egyben átmásolni az eredeti XML-ből (<code>&lt;xsl:copy-of select="content"/&gt;</code>). Hosszasan lehetne magyarázni, hogy akkor most ez hogy is van és egyébként is milyen eszközök állnak még a rendelkezésre, de mivel már születtek erről leírások <a href="http://www.stud.u-szeged.hu/Vizhanyo.Andor/">erre</a> és <a href="http://www.zvon.org/xxl/XSLTutorial/Output_hun/contents.html">erre</a> (meg még sok egyéb helyen is biztos), ezért ugorjuk át az unalmas részleteket, és nézzünk valami izgalmasabb dolgot, nevezetesen azt, hogy mire is lehet ezt az XSLT dolgot használni?</p>

<h3>Többnyelvűsítés</h3>

<p>Hogyan is többnyelvűsítünk olyan adatokat a weboldalon, amik statikusan bele vannak írva a sablonba? Például ez a dolog valahogy úgy történhet meg, hogy van egy (optimális esetben minél rövidebb nevű) függvényünk, ami megkapja paraméterként a szöveget és ha van hozzá az adott nyelven fordítás, akkor megjelenítni, ha nincs, akkor pedig kiírja az eredetileg kapott szöveget (vagy bármi más feltűnő szöveget, hogy szegény fordító lássa, hogy ott még hiány van). A függvény maga meg valószínűleg adatbázisból dolgozik, esetleg az adatbázisból generálódik egy PHP, XML vagy egyéb szöveges formátumú fájl cache-elési szándékkal.</p>

<p>Ha már mindenképpen generálunk mondjuk egy XML fájlt ezekből az adatokból, akkor miért ne lehetne azt csinálni, hogy az XSLT-t segítségül hívva rakjuk be a megfelelő helyre a megfelelő nyelvű szöveget? Nézzük is az új XML fájlunkat:</p>

<pre class="code prettyprint lang-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;?xml-stylesheet type=&quot;text/xsl&quot; href=&quot;multilang.xsl&quot;?&gt;
&lt;page lang=&quot;hu&quot;/&gt;</pre>

<p>A felesleget kiszórtam belőle, mivel valószínűleg az XML-be csak dinamikus adatok kerülnek már a megfelelő nyelven, úgyhogy az a része minket most nem érdekel. Emellett kapott egy extra tulajdonságot a <code>&lt;page&gt;</code> tag (<code>lang="hu"</code>). Szükségünk lesz még egy második XML fájlra, ami az oldal megjelenítéséhez szükséges statikus szövegeket tartalmazza:</p>

<pre class="code prettyprint lang-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;strings&gt;
    &lt;string id=&quot;text-1&quot;&gt;Valami szöveg&lt;/string&gt;
    &lt;string id=&quot;text-2&quot;&gt;Valami másik szöveg&lt;/string&gt;
&lt;/strings&gt;</pre>

<p>...és természetesen egy XSL fájlra, a megfelelő kimenet érdekében:</p>

<pre class="code prettyprint lang-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
    &lt;xsl:output method=&quot;html&quot; doctype-system=&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot; doctype-public=&quot;-//W3C//DTD XHTML 1.0 Strict//EN&quot;/&gt;
    &lt;xsl:variable name=&quot;lang&quot; select=&quot;/page/@lang&quot;/&gt;
    &lt;xsl:variable name=&quot;data&quot; select=&quot;document(concat('data_',$lang,'.xml'))&quot;/&gt;
    &lt;xsl:template match=&quot;page&quot;&gt;
        &lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;
            &lt;head&gt;
                &lt;title&gt;XSL teszt&lt;/title&gt;
            &lt;/head&gt;
            &lt;body&gt;
                &lt;h1&gt;&lt;xsl:value-of select=&quot;$data/strings/string[@id='text-1']&quot;/&gt;&lt;/h1&gt;
                &lt;p&gt;&lt;xsl:value-of select=&quot;$data/strings/string[@id='text-2']&quot;/&gt;&lt;/p&gt;
            &lt;/body&gt;
        &lt;/html&gt;
    &lt;/xsl:template&gt;
&lt;/xsl:stylesheet&gt;</pre>

<p>Az előző kódhoz képest lett pár új dolog. Az <code>&lt;xsl:variable&gt;</code> segítségével adhatunk változóknak értéket, amiket később a $változónév formában érhetünk el. Ezen kívül megjelent pár XSL függvény is, a <code>document()</code> és a <code>concat()</code>. A <code>concat()</code> egyszerű string összefűzés, a <code>document()</code> segítségével pedig egy külső XML-t tölthetünk be (így a változón keresztül elérhetjük a benne lévő adatokat).</p>

<h3>És a <acronym title="Search Engine Optimization">SEO</acronym>?</h3>

<p>Persze, szép dolog szétválasztani a nyers adatokat, a statikus, többnyelvű szöveget a megjelenítéstől, és mintezt kliens oldalon össszerakni, de mit sem ér, ha a keresők nem tudnak vele mit kezdeni. Nem látok bele a keresőrobotok lelki világába, de abból kiindulva, hogy az "armory" szóra a bevezetőben említett oldal amerikai párja jön fel a <a href="http://www.google.hu/search?q=armory">Google-ben első találatként</a>, arra lehet következtetni, hogy különösebben nem viseli meg őket a dolog. Ha az oldal tárolt változatát is megnézzük, észre lehet venni, hogy a forrásban már az XSL transzformáció utáni állapotot mutatja (és mellesleg a <a href="http://search.yahoo.com/search?p=armory">Yahoo!</a>-val és a <a href="http://search.msn.com/results.aspx?q=armory">Live Search</a>-el kapcsolatban is hasonló a helyzet), azaz szerintem az XML+XSLT oldalak (amiknek a kimenete HTML) ugyanúgy viselkednek kereső-optimalizációs szempontból nézve, mint a sima HTML oldalak.</p>

<p>Ennyit mára. <em>Folyt. köv.</em></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/deadlime?a=q5QAcAeF"><img src="http://feeds.feedburner.com/~f/deadlime?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=dENgeqcr"><img src="http://feeds.feedburner.com/~f/deadlime?d=50" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=nX89YKJT"><img src="http://feeds.feedburner.com/~f/deadlime?i=nX89YKJT" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/PNmylavTHN8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2008/04/03/kliens-oldali-xslt/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2008/04/03/kliens-oldali-xslt/</feedburner:origLink></item>
		<item>
		<title>A Google Reader hasznosítása</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/v5VCXqfU1pc/</link>
		<comments>http://deadlime.hu/2007/11/09/a-google-reader-hasznositasa/#comments</comments>
		<pubDate>Fri, 09 Nov 2007 18:40:24 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[Feed]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JSON]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2007/11/09/a-google-reader-hasznositasa/</guid>
		<description><![CDATA[A Google Reader egy rettentő addiktív dolog, ha az ember a feedolvasást választja a hírek beszerzésének kényelmes formájaként. De mi van akkor, ha az itt olvasott dolgokat szeretnénk másokkal is megosztani a saját honlapunkon? És ha a feliratkozásainkból szeretnénk egy blogrollt csinálni az oldalunkon? Természetesen a Google is gondolt erre, ezért mindkettőre van lehetőségünk. Az [...]]]></description>
			<content:encoded><![CDATA[<p>A <a href="http://www.google.com/reader/">Google Reader</a> egy rettentő addiktív dolog, ha az ember a feedolvasást választja a hírek beszerzésének kényelmes formájaként. De mi van akkor, ha az itt olvasott dolgokat szeretnénk másokkal is megosztani a saját honlapunkon? És ha a feliratkozásainkból szeretnénk egy blogrollt csinálni az oldalunkon? Természetesen a Google is gondolt erre, ezért mindkettőre van lehetőségünk.</p>

<p>Az alábbiakban szeretném bemutatni, hogy hogyan is valósíthatjuk meg ezeket a dolgokat, valamint mit tehetünk, ha nem elégszünk meg az alap lehetőségekkel.</p>

<h3>Blogroll készítése</h3>

<ol>
<li>A Reader felületén kattintsunk az egyik feedünkre és a "Feed settings..." alatt adjunk hozzá egy új könyvtárat (New folder...). Legyen a neve mondjuk "blogroll".</li>
<li>Kellő óvatossággal kattintsuk meg a jobb felső sarokban található "Settings" linket és azon belül is a "Subscriptions" fülecskét.</li>
<li>Jelöljük ki azokat az oldalakat, amiket meg szeretnénk jeleníteni a blogrollunkban és a "More options..." lenyitható űrlapelem segítségével adjuk hozzá a "blogroll" taget.</li>
<li>Menjünk át a "Tags" fülre. A "blogroll" neveztű tag sorában kattintsuk meg azt a kis feed ikonocskát, mire megjelenik egy csomó minden egyéb link is abban a sorban.</li>
<li>A minket érdeklő dolog az "add a blogroll to your site" link. A megkattintás után előjön egy popup, ahol be tudjuk állítani a blogroll dobozunk stílusát.</li>
<li>Most már csak az van hátra, hogy a személyre szabott kódunkat, amit alatta egy textarea-ban legenerált nekünk, kimásoljuk és beillesszük a blogunkra egy megfelelő helyre.</li>
</ol>

<p>De tényleg csak ennyi lenne? Nem tudom, de nekem nem igazán sikerült olyan színsémát találnom, ami igazán passzolt volna a bloghoz, szóval ideje valami alternatív megoldást keresni. A popupban két <code>&lt;script&gt;</code> tag található. Az első egy olyan JavaScript fájl, ami a megjelenítésért felelős, ezért minket nem is érdekel különösebben. Ám a második egy aranyos JSON fájl, ami egy callback függvénynek átadja a nekünk szükséges adatokat. Ennek a linknek is csak az első fele érdekes számunkra a "callback" részig. A callback utáni részt pedig írjuk át nemes egyszerűséggel updateBlogroll-ra. Ezek után valahogy így fog kinézni:</p>

<pre class="code">http://www.google.com/reader/public/javascript-sub/user/AZONOSÍTÓ/label/blogroll?callback=updateBlogroll</pre>

<p>Így egy olyan JavaScript kódot fog legenerálni nekünk a Google, ami meghívja az updateBlogroll függvényt és átadja neki a Reader-ünkből származó adatokat. Így már csak annyi a dolgunk, hogy ezt az <code>updateBlogroll</code> függvényt megírjuk, az őt tartalamzó JS fájt betöltsük a honlapunk <code>&lt;head&gt;</code> részében, a fent említett, Reader által generált JS-t pedig az után a tag után, ahova a blogrollt be szeretnénk szúrni. Egy példa az <code>updateBlogroll</code> függvényre (a kód <a href="http://www.prototypejs.org/">prototype.js</a>-t használ):</p>

<pre class="code prettyprint lang-javascript">function updateBlogroll(data)
{
	var parent = $('blogroll-list');
	parent.innerHTML = '';
	var len = data.items.length;
	for (var i = 0; i &lt; len; ++i)
	{
		parent.insert('&lt;li&gt;&lt;a href=&quot;'+data.items[i].alternate.href+'&quot;&gt;'+data.items[i].title+'&lt;/a&gt;&lt;/li&gt;');
	}
}</pre>

<p>Ha ezt a függvényt mondjuk egy <code>update.js</code> fájlba mentjük el, akkor a HTML kódunk valahogy így nézhet ki:</p>

<pre class="code prettyprint lang-html">...
&lt;script language=&quot;JavaScript&quot; type=&quot;text/javascript&quot; src=&quot;update.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
...
&lt;ul id=&quot;blogroll-list&quot;&gt;Blogroll betöltése...&lt;/ul&gt;
&lt;script language=&quot;JavaScript&quot; type=&quot;text/javascript&quot; src=&quot;http://www.google.com/reader/public/javascript-sub/user/AZONOSÍTÓ/label/blogroll?callback=updateBlogroll&quot;&gt;&lt;/script&gt;
...</pre>

<h3>Feed elemek megosztása</h3>

<p>Hasonló módon érhetjük el azt is, ha szeretnénk az általunk érdekesnek talált linkeket megosztani a blogunk látogatóival. A Reader beállításainál a "Tags" fülön található egy "Your shared items" (ide úgy kerülnek bele az elemek, ha "Expanded view"-ban Shift+S-t nyomunk egy bejegyzésen vagy megnyomjuk a "Share" linket az elem alján. "List view"-ban csak az utóbbira van lehetőségünk, ha már kinyitottunk egy elemet). Ennek a sorában kattintsuk meg az "add a clip to your site" linket. Egy hasonló popup ugrott fel, mint a blogroll esetében is. Ha nem szeretnénk saját formázást használni akkor a megfelelő beállítások elvégzése után a textarea-ban található kód beillesztésével végeztünk is. Ellenkező esetben ismét a második <code>&lt;script&gt;</code> tagben lévő linket kell kimásolnunk. A callback után most írjuk az <code>updateLinks</code> függvénynevet, valahogy így:</p>

<pre class="code">http://www.google.com/reader/public/javascript/user/AZONOSÍTÓ/state/com.google/broadcast?n=15&amp;callback=updateLinks</pre>

<p>Az <code>n</code> utáni szám átírásával tudjuk meghatározni, hogy hány darab elemet kapjunk vissza. Az <code>updateLinks</code> függvény is hasonlóan fog kinézni, mint az előző <code>updateBlogroll</code>:</p>

<pre class="code prettyprint lang-javascript">function updateLinks(data)
{
	var parent = $('link-list');
	parent.innerHTML = '';
	var len = data.items.length;
	for (var i = 0; i &lt; len; ++i)
	{
		parent.insert('&lt;li&gt;&lt;a href=&quot;'+data.items[i].alternate.href+'&quot;&gt;'+data.items[i].title+'&lt;/a&gt;&lt;/li&gt;');
	}
}</pre>

<p>Természetesen nem csak ennyi adatot kapunk meg az elemekről. Nézzünk pár fontosabbat a teljesség igénye nélkül (a továbbiakért érdemes a kapott fájlba belenézni):</p>

<ul>
<li><code>data.items[i].published</code><br/>
A bejegyzés publikálásának időpontja Unix timestamp formában.</li>
<li><code>data.items[i].summarySnippet</code><br/>
A bejegyzés rövid, összefoglaló szövege.</li>
<li><code>data.items[i].origin.title</code><br/>
Az oldal neve, ahol megjelent ez a bejegyzés.</li>
<li><code>data.items[i].origin.htmlUrl</code><br/>
Az oldal címe.</li>
</ul>

<p>Körülbelül ennyi lenne a Google Reader pár hasznos felhasználási módjáról. A jobb oldali sáv "Linkek" és "Blogroll" részében látható a működő példa.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/deadlime?a=RWd6LpVD"><img src="http://feeds.feedburner.com/~f/deadlime?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=kaa0m34Y"><img src="http://feeds.feedburner.com/~f/deadlime?d=50" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=5sxkcT3s"><img src="http://feeds.feedburner.com/~f/deadlime?i=5sxkcT3s" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/v5VCXqfU1pc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2007/11/09/a-google-reader-hasznositasa/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2007/11/09/a-google-reader-hasznositasa/</feedburner:origLink></item>
		<item>
		<title>Szükségesek-e a sablonnyelvek?</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/oo0yNVTlHgI/</link>
		<comments>http://deadlime.hu/2007/10/14/szuksegesek-e-a-sablonnyelvek/#comments</comments>
		<pubDate>Sun, 14 Oct 2007 12:41:09 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[sablonok]]></category>
		<category><![CDATA[Smarty]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2007/10/14/szuksegesek-e-a-sablonnyelvek/</guid>
		<description><![CDATA[Régebben írtam a PHP sablonnyelvként való használatáról. Lehet szépíteni a dolgokat, de hosszú távon ennek a használata (főleg megfelelő szerkesztőprogrambeli makrók nélkül) kényelmetlen, hosszadalmas és még a makrók használatával együtt is csúnya, olvashatatlan. A Smarty egyetlen pozitívuma az, hogy egyszerűen és gyorsan lehet írni, kényelmesen lehet használni. Persze ez nem vigasz azoknak, akik nem akarnak [...]]]></description>
			<content:encoded><![CDATA[<p>Régebben írtam a PHP sablonnyelvként való használatáról. Lehet szépíteni a dolgokat, de hosszú távon ennek a használata (főleg megfelelő szerkesztőprogrambeli makrók nélkül) kényelmetlen, hosszadalmas és még a makrók használatával együtt is csúnya, olvashatatlan. A Smarty egyetlen pozitívuma az, hogy egyszerűen és gyorsan lehet írni, kényelmesen lehet használni. Persze ez nem vigasz azoknak, akik nem akarnak egy több ezer kódsorból álló sablon kezelőt használni csak emiatt a kényelem miatt.</p>

<p>Nagyrészt így vagyok vele én is. Gyakorlatilag a szintaktikájának az alapjait leszámítva nem lenne szükségem semmire a Smarty-ból. Nem érdekel, hogy korlátozni lehet a sablon íróját, hogy a PHP eszköztár csak egy részét használhassa (minek is korlátoznám magam...). Nem érdekel, hogy könnyen és gyorsan lehet hozzá plugineket írni (ha az egész PHP használható lenne, erre nincs is túl nagy szükség). Nincs szükségem semmi ilyesmire.<br/>
Sokkal inkább vonz az, ha a nyelvet gyorsan lehet gépelni (pl. mert rövid, minimális speciális karaktert használ és logikus a szerkezete). Az se egy hátrány, ha az elkészült sablon valamilyen szinten olvasható lesz. Nem lenne rossz még, ha egy elfogadható minőségű PHP kódot generálna az én sablonomból, ami aztán elfogadható (a lehető leggyorsabb) sebességgel futna. Az első kettőt még csak-csak teljesíti, de az utolsóval eléggé hadilábon áll a Smarty. Így itt az idő valami más után nézni...</p>

<p>A legkézenfekvőbb dolog a PHP használata lenne erre a célra, ami az első két ponton totálisan megbukik. Kiindulási alapnak viszont jó lesz:</p>

<pre class="code prettyprint lang-php">&lt;h1&gt;Valami sablon&lt;/h1&gt;

&lt;?php if (5 &gt; 6): ?&gt;
	&lt;p&gt;&lt;?php print('5 nagyobb mint 6'); ?&gt;&lt;/p&gt;
&lt;?php else: ?&gt;
	&lt;p&gt;&lt;?php print('5 nem nagyobb, mint 6'); ?&gt;&lt;/p&gt;
&lt;?php endif; ?&gt;</pre>

<p>Mi lenne, ha első körbe a <code>&lt;?php</code> és a <code>?&gt;</code> helyett a jól megszokott <code>{</code> és <code>}</code> lenne használva?</p>

<pre class="code prettyprint lang-php">&lt;h1&gt;Valami sablon&lt;/h1&gt;

{ if (5 &gt; 6): }
	&lt;p&gt;{ print('5 nagyobb mint 6'); }&lt;/p&gt;
{ else: }
	&lt;p&gt;{ print('5 nem nagyobb, mint 6'); }&lt;/p&gt;
{ endif; }</pre>

<p>Haladunk, esetleg még a <code>print()</code> helyett bevezethetnénk a PHP rövid tag <code>&lt;?=</code> szerkezetéhez hasonlóan egy <code>{=</code> szerkezetet:</p>

<pre class="code prettyprint lang-php">&lt;h1&gt;Valami sablon&lt;/h1&gt;

{ if (5 &gt; 6): }
	&lt;p&gt;{= '5 nagyobb mint 6' }&lt;/p&gt;
{ else: }
	&lt;p&gt;{= '5 nem nagyobb, mint 6' }&lt;/p&gt;
{ endif; }</pre>

<p>Pár kényelmességet elősegítő lépés múlva (szóközök, kettőspontok, felesleges zárójelek, pontosvesszők eltűntetése) sikerült eljutnom a végleges formáig:</p>

<pre class="code prettyprint lang-php">&lt;h1&gt;Valami sablon&lt;/h1&gt;

{if 5 &gt; 6}
	&lt;p&gt;{='5 nagyobb mint 6'}&lt;/p&gt;
{else}
	&lt;p&gt;{='5 nem nagyobb, mint 6'}&lt;/p&gt;
{if}</pre>

<p>Rémisztően hasonlít a Smarty-ra (ez valamilyen szinten cél is volt :)), viszont az ebből fordított PHP kód gyakorlatilag egy az egyben megegyezik az általunk írt sablon kód szerkezetével. Most, hogy megvan az alapvető szintaxis, jöhet a sablonkezelő osztály, ami a fentebb említett több ezer sorhoz képest megvalósult úgy 170 sorból (milyen csodákra képes, ha kihagyunk minden "szemetet", amire nincs szükségünk :)), ami már tartalmaz pár extra funkciót is (mint például a lefordított sablonok újrafordítási szükségességének ellenőrzését). A bemenete egy <a href="http://kriz.deadlime.hu/lighty/template.html" target="_blank">ilyen template</a>, amiből ezt a <a href="http://kriz.deadlime.hu/lighty/template.phps" target="_blank">PHP kódot</a> generálja, valami ilyesmi kóddal:</p>

<pre class="code prettyprint lang-php">&lt;?php
	include('lighty.php');
	
	$l = new Lighty();
	
	$l-&gt;assign('list', array('a', 'b', 'c', 'd'));
	$l-&gt;display('teszt.tpl');
?&gt;</pre>

<p>Amit érdemes ezzel kapcsolatban megemlíteni, hogy a lefordított forrás első sorának elején ott van egy kommentben a fordítás ideje, ami az újrafordítás-ellenőrző számára fontos. Valamint az egész fájl egyetlen egy PHP kódblokkot tartalmaz (ami emlékeim szerint optimálisabb, mint sok-sok kis PHP kódblokk egy sablonon belül). Emiatt vannak felesleges, csak whitespace karaktereket kiíró <code>print()</code> hívások, de ezek megszüntethetőek. És végül, de nem utolsó sorban, a Lighty névre keresztelt sablonrendszer első publikus verziója <a href="http://kriz.deadlime.hu/lighty/lighty.zip">letölthető innen</a>. A csomagban megtalálható egy teszt.php is, ami a fentebb felvázolt példakódot tartalmazza, valamint az általa használt template fájlok és szükséges könyvtárak is.</p>

<p>És hogy így a végén még a címben említett kérdést is megválaszoljam: szerintem szükség van a sablonnyelvekre, mert nagyban meg tudják könnyíteni az ember életét az által, hogy meggyorsítják a sablonírás folyamatát.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/deadlime?a=8k6FUo2H"><img src="http://feeds.feedburner.com/~f/deadlime?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=RW1549xz"><img src="http://feeds.feedburner.com/~f/deadlime?d=50" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=DlYUwj1C"><img src="http://feeds.feedburner.com/~f/deadlime?i=DlYUwj1C" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/oo0yNVTlHgI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2007/10/14/szuksegesek-e-a-sablonnyelvek/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2007/10/14/szuksegesek-e-a-sablonnyelvek/</feedburner:origLink></item>
		<item>
		<title>Prototype események</title>
		<link>http://feedproxy.google.com/~r/deadlime/~3/zEU9hI-4qCs/</link>
		<comments>http://deadlime.hu/2007/03/28/prototype-esemenyek/#comments</comments>
		<pubDate>Wed, 28 Mar 2007 07:18:43 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[prototype.js]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2007/03/28/prototype-esemenyek/</guid>
		<description><![CDATA[Mivel az "esemény" és annak kezelése a JavaScript-ben az egyik legfontosabb dolog, ezért nem teljesen mindegy, hogy mégis hogyan csináljuk. Vagy méginkább az, hogy hogyan kell csinálnunk. Értem itt ezalatt azt, hogy minden egyes alkalommal egy kisebb fajta regényt kell írnunk, amikor egy objektum egy eseményét akarjuk figyelni, vagy elég egy Event.observe() hívás, ami elvégez [...]]]></description>
			<content:encoded><![CDATA[<p>Mivel az "esemény" és annak kezelése a JavaScript-ben az egyik legfontosabb dolog, ezért nem teljesen mindegy, hogy mégis hogyan csináljuk. Vagy méginkább az, hogy hogyan <em>kell</em> csinálnunk. Értem itt ezalatt azt, hogy minden egyes alkalommal egy kisebb fajta regényt kell írnunk, amikor egy objektum egy eseményét akarjuk figyelni, vagy elég egy <code>Event.observe()</code> hívás, ami elvégez számunkra minden piszkos munkát.</p>

<p>Az "<a href="http://deadlime.hu/2007/03/20/objektum-orientalt-javascript/">Objektum-orientált JavaScript</a>" című bejegyzésem utolsó példájával kapcsolatban felmerült, hogy kicsit jobban is kifejthettem volna az ott történteket. Mivel ott nem az eseményeken volt a hangsúly, ezért gondoltam egy külön bejegyzésben teszem ezt meg.<br/>
A <a href="http://www.prototypejs.org/">prototype.js</a> az események téren is képes a dolgunkat a végtelenségig leegyszerűsíteni. Egészen addig, amíg mi magunk nem akarjuk a dolgokat "bonyolítani", és bele nem fogunk az objektum-orientáltságban. Ilyenkor kezdődnek a problémák. Tegyük fel, hogy szeretnénk egy olyasmi dolgot megoldani, hogy két gomb segítségével egy harmadik gombra tudunk eseményt tenni, majd azt az eseményt levenni a gombról. Objektumok nélkül nem lenne különösebben nehéz dolgunk:</p>

<pre class="code prettyprint lang-JavaScript">function add_event(event)
{
	Event.observe('myButton_1', 'click', alert_me);
}
function remove_event(event)
{
	Event.stopObserving('myButton_1', 'click', alert_me);
}

var text = 'Ez a \'text\' tartalma';
function alert_me(event) {
	if (text != null) {
		alert('A \'text\' tartalma: '+text);
	}
	else {
		alert('A \'text\' nincs definiálva!');
	}
}

Event.observe(window, 'load', function(event) {
	Event.observe('myButton_2', 'click', add_event);
	Event.observe('myButton_3', 'click', remove_event);
});</pre>

<p>A dolog persze kezd bonyolódni, ha nem csak egy, hanem mondjuk n darab ilyen gomb trióra kell ráhúznunk ezeket az eseményeket, így joggal merül fel az OO-ra az igény. Hirtelen felindulásból a fenti mintájára összedobunk valami ilyet:</p>

<pre class="code prettyprint lang-JavaScript">var Teszt = Class.create();
Teszt.prototype = {
	initialize : function(alert_button, event_add_button, event_remove_button, text)
	{
		this.alert_object = $(alert_button);
		this.add_object = $(event_add_button);
		this.remove_object = $(event_remove_button);

		this.text = text;

		Event.observe(this.add_object, 'click', this.add_event);
		Event.observe(this.remove_object, 'click', this.remove_event);
	},

	add_event : function(event)
	{
		Event.observe(this.alert_object, 'click', this.alert_me);
	},
	remove_event : function(event)
	{
		Event.stopObserving(this.alert_object, 'click', this.alert_me);
	},

	alert_me : function(event)
	{
		if (this.text != null) {
			alert('A \'text\' tartalma: '+this.text);
		}
		else {
			alert('A \'text\' nincs definiálva!');
		}
	}
};

Event.observe(window, 'load', function(event) {
	var gombok = new Teszt('myButton_1', 'myButton_2', 'myButton_3', 'Ez a \'text\' tartalma');
});</pre>

<p>Kódunk több sebből vérzik, gyakorlatilag a halálán van, és a hirtelen támadt pánikban lövésünk sincs, hogy mi a franc baja lehet ennek a látszólag működőképes kódnak. Miközben a prototype.js összes fejlesztőjének rokonságát végigszidjuk, lelünk rá a dokumentációban pár érdekes részletre, valami <code>bind()</code> függvénnyel kapcsolatban.<br/>
A probléma az, hogy amikor megnyomjuk az "Esemény hozzáadása" gombot, és lefut az <code>add_event()</code> függvény, az abban a függvényben lévő "this" az nem éppen az lesz, mint amire mi gondolunk. Ahhoz, hogy ez a "this" ugyanaz legyen, mint ami az <code>initialize()</code> függvényben a "this", pár változtatást kell eszközölnünk:</p>

<pre class="code prettyprint lang-JavaScript">Event.observe(this.add_object, 'click', this.add_event.bind(this));
Event.observe(this.remove_object, 'click', this.remove_event.bind(this));</pre>

<p>Ami azt illeti, a dolog működik, csak éppen az <code>alert_me()</code> folyamatosan azt mondja nekünk, hogy a text nincs megadva, pedig de. Mielőtt ismét elővennénk a fejlesztők rokonságát, látjuk, hogy talán az <code>add_event()</code> részbe se ártana egy <code>bind()</code>, hátha ugyanaz a probléma:</p>

<pre class="code prettyprint lang-JavaScript">Event.observe(this.alert_object, 'click', this.alert_me.bind(this));</pre>

<p>És csodák csodájára működik... izé... öhm... majdnem. Hozzáadjuk az eseményt az egyik gombbal, megnyomjuk a gombot, kiírja a megfelelő szöveget, majd levesszük az eseményt, megnyomjuk a gombot, és látjuk, hogy az esemény még mindig rajta van. Ennek az oka az, hogy az <code>Event.stopObserving()</code> segítségével csak elnevezett függvényeket tudunk a megfigyelésből kivonni. De hát ez el van nevezve, az a neve, hogy <code>this.alert_me</code>. Azaz, hogy majdnem az a neve. Mert a mi <code>alert_me()</code> függvényünkön meghívtuk a <code>bind()</code>-et, ami egy névtelen függvénnyel tér vissza, így szivatva meg minket.<br/>
Még mielőtt rátérnénk a megoldásra, nézzük meg mi is az a névtelen függvény, hogy biztosan teljesen képben legyünk:</p>

<pre class="code prettyprint lang-JavaScript">Event.observe(window, 'load', function(event) {
	alert('Névtelen függvény vagyok!');
});

var myFunction = function(event) {
	alert('Én nem vagyok névtelen függvény!');
};
Event.observe(window, 'load', myFunction);</pre>

<p>Tehát, az <code>Event.stopObserving()</code> csak a második esetben használható, amikor tudjuk annak a függvénynek a nevét, amit le akarunk állítani. Nincs más dolgunk, mint az <code>initialize()</code> végére fűzni egy sort...</p>

<pre class="code prettyprint lang-JavaScript">this.alert_event = this.alert_me.bind(this);</pre>

<p>...valamint a következőképpen módosítani az <code>add_event()</code> és <code>remove_event()</code> függvényeket:</p>

<pre class="code prettyprint lang-JavaScript">add_event : function(event)
{
	Event.observe(this.alert_object, 'click', this.alert_event);
},
remove_event : function(event)
{
	Event.stopObserving(this.alert_object, 'click', this.alert_event);
},</pre>

<p>A megoldás már csak annyiban kifogásolható, hogy a <code>bind()</code> helyett a prototype.js nyújt számunkra egy másik függvényt is, amit kifejezetten eseménykezelőkre lett kitalálva. Ez a gyönyörű nevű <code>bindAsEventListener()</code>. Miután lecseréltük az összes <code>bind()</code>-ünket erre a függvényre, készen is vagyunk. Egy - remélhetőleg - működő <a href="http://kriz.deadlime.hu/prototype-teszt/">példa megtekinthető itt</a>.</p><div class="feedflare">
<a href="http://feeds.feedburner.com/~f/deadlime?a=UTixVqfs"><img src="http://feeds.feedburner.com/~f/deadlime?d=41" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=ZgAtfxiB"><img src="http://feeds.feedburner.com/~f/deadlime?d=50" border="0"></img></a> <a href="http://feeds.feedburner.com/~f/deadlime?a=1E0bBuE3"><img src="http://feeds.feedburner.com/~f/deadlime?i=1E0bBuE3" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/deadlime/~4/zEU9hI-4qCs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2007/03/28/prototype-esemenyek/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://deadlime.hu/2007/03/28/prototype-esemenyek/</feedburner:origLink></item>
	</channel>
</rss>

