<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>gedex&#039;s blog</title>
	<atom:link href="http://gedex.web.id/feed/" rel="self" type="application/rss+xml" />
	<link>http://gedex.web.id</link>
	<description>Writing about web technology, electronic, and daily stuff</description>
	<lastBuildDate>Wed, 16 May 2012 01:42:09 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>LaTeX Beautiful Math from Jetpack</title>
		<link>http://gedex.web.id/archives/2012/05/16/latex-beautiful-math-from-jetpack/</link>
		<comments>http://gedex.web.id/archives/2012/05/16/latex-beautiful-math-from-jetpack/#comments</comments>
		<pubDate>Tue, 15 May 2012 18:53:47 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[webservices]]></category>
		<category><![CDATA[wp]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=536</guid>
		<description><![CDATA[I just installed Jetpack and interested with the LaTeX feature it offers. Let see how it works. Uhm.. I&#8217;m going to type recurrence relation for secant method: Nice, isn&#8217;t it? If we&#8217;re looking at the inspector, it renders image from http://wp.com/latex.php?latex=your_latex_code. &#8230; <a href="http://gedex.web.id/archives/2012/05/16/latex-beautiful-math-from-jetpack/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I just installed <a href="http://jetpack.me/">Jetpack</a> and interested with the LaTeX feature it offers. Let see how it works. Uhm.. I&#8217;m going to type recurrence relation for <a href="http://en.wikipedia.org/wiki/Secant_method">secant method</a>:</p>
<p style="text-align: center;"><img src='http://s0.wp.com/latex.php?latex=x_n+%3D+x_%7Bn-1%7D+-+f%28x_%7Bn-1%7D%29+%5Ccfrac%7Bx_%7Bn-1%7D+-+x_%7Bn-2%7D%7D%7Bf%28x_%7Bn-1%7D%29+-+f%28x_%7Bn-2%7D%29%7D+&#038;bg=ffffff&#038;fg=000&#038;s=0' alt='x_n = x_{n-1} - f(x_{n-1}) &#92;cfrac{x_{n-1} - x_{n-2}}{f(x_{n-1}) - f(x_{n-2})} ' title='x_n = x_{n-1} - f(x_{n-1}) &#92;cfrac{x_{n-1} - x_{n-2}}{f(x_{n-1}) - f(x_{n-2})} ' class='latex' /></p>
<p>Nice, isn&#8217;t it? If we&#8217;re looking at the inspector, it renders image from http://wp.com/latex.php?latex=<strong>your_latex_code</strong>. So the math expression you type between <strong>$latex</strong> and <strong>$</strong> will be passed as <strong>your_latex_code</strong>. I don&#8217;t know if wp.com/latex.php is implementing <a href="http://code.google.com/p/common-latex-service-interface/">CLSI</a> or not. There&#8217;s no information about its web service so far. The problem with passing the equation in the query string leads to very long, long URL that is <a href="http://www.boutell.com/newfaq/misc/urllength.html">extremely a mistake</a>. Ok, let&#8217;s forget that. Let&#8217;s try another equation, non-linear equation this time:</p>
<p style="text-align: center;"><img src='http://s0.wp.com/latex.php?latex=f%28x%29+%3D+%5Ccfrac%7B3%7D%7B2%7Dx%5E2%C2%A0%2B+%5Ccfrac%7B1%7D%7B2%7Dx+-+%5Ccfrac%7B4%7D%7B3%7D&#038;bg=ffffff&#038;fg=000&#038;s=0' alt='f(x) = &#92;cfrac{3}{2}x^2 + &#92;cfrac{1}{2}x - &#92;cfrac{4}{3}' title='f(x) = &#92;cfrac{3}{2}x^2 + &#92;cfrac{1}{2}x - &#92;cfrac{4}{3}' class='latex' /></p>
<p>Uhmm.. Why it doesn&#8217;t render correctly? The same equation renders correctly in <a href="http://frog.isima.fr/bruno/share/tex2png/">Tex2PNG CGI</a> and Google Chart API (it seems \cfrac is not supported by Google Chart API, so replace it with \frac). Try it by yourself by pasting <strong>f(x) = \cfrac{3}{2}x^2 + \cfrac{1}{2}x &#8211; \cfrac{4}{3}</strong>.</p>
<p><img class="aligncenter" src="http://frog.isima.fr/cgi-bin/bruno/tex2png--10.cgi?f(x)%20=%20\cfrac{3}{2}x^2%A0+%20\cfrac{1}{2}x%20-%20\cfrac{4}{3}" alt="" width="250" height="60" /></p>
<p>Ok, let&#8217;s try again with quadratic formula for univariate polynomial equation of the second degree:</p>
<p style="text-align: center;"><img src='http://s0.wp.com/latex.php?latex=x+%3D+%5Ccfrac%7B-b+%5Cpm+%5Csqrt%7Bb%5E2+-+4ac%7D%7D%7B2a%7D+&#038;bg=ffffff&#038;fg=000&#038;s=0' alt='x = &#92;cfrac{-b &#92;pm &#92;sqrt{b^2 - 4ac}}{2a} ' title='x = &#92;cfrac{-b &#92;pm &#92;sqrt{b^2 - 4ac}}{2a} ' class='latex' /></p>
<p>Weird, it renders correctly this time. You know, I tried the formula in another post before and it didn&#8217;t render as expected. Well, based on my experience I thought the web service of latex from WP is not stable enough. It&#8217;s waste of time to test the latex code in other latex services to make sure my code is correct.</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2012/05/16/latex-beautiful-math-from-jetpack/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Belajar Menjadi Touch Typist</title>
		<link>http://gedex.web.id/archives/2011/09/24/belajar-menjadi-touch-typist/</link>
		<comments>http://gedex.web.id/archives/2011/09/24/belajar-menjadi-touch-typist/#comments</comments>
		<pubDate>Sat, 24 Sep 2011 05:48:51 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[just FYI]]></category>
		<category><![CDATA[my opinion]]></category>
		<category><![CDATA[touch]]></category>
		<category><![CDATA[typist]]></category>
		<category><![CDATA[wpm]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=484</guid>
		<description><![CDATA[Seriously. Saya baru, sekitar, satu bulan ini berusaha menjadi touch typist. Saya seorang programmer, tentunya mengetik merupakan hal yang sering dilakukan. Selama bertahun-tahun saya belajar mengetik otodidak, dan saya (pikir) cukup cepat mengetik. Tapi ada beberapa karakter yang saya harus &#8230; <a href="http://gedex.web.id/archives/2011/09/24/belajar-menjadi-touch-typist/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><em>Seriously</em>. Saya baru, sekitar, satu bulan ini berusaha menjadi <em>touch typist</em>. Saya seorang <em>programmer</em>, tentunya mengetik merupakan hal yang sering dilakukan. Selama bertahun-tahun saya belajar mengetik otodidak, dan saya (pikir) cukup cepat mengetik. Tapi ada beberapa karakter yang saya harus melihat dulu ke <em>keyboard</em> untuk mengetiknya. Kebanyakan orang yang belajar mengetik otodidak, tanpa memahami letak jari kanan dan kiri pada <em>layout keyboard</em> QWERTY, akan melihat <em>keyboard</em> untuk karakter yang sulit (seperti angka dan simbol). Istri saya yang sudah bertahun-tahun menggunakan <em>keyboard</em> QWERTY hanya dapat mengetik di bawah 30 WPM (Words Per Minute) dan sambil melihat. Saya yang mulai membiasakan diri sebagai <em>touch typist</em> sudah dapat mencapai 70 WPM. Dan tentunya seiring saya berlatih dan sering mengetik, kecepatan saya bisa naik menjadi 100 WPM.</p>
<p>Menjadi <em>touch typist</em> memang membutuhkan kesabaran berlatih. Sama halnya Anda melatih jari Anda di guitar atau piano. Anda harus mulai dari tempo yang lambat, tapi akurat mengenai karakter. Latihan saja selama 1 jam dalam satu hari (dan tanpa melihat keyboard). Dulu waktu saya bercita-cita menjadi <em><a href="http://en.wikipedia.org/wiki/Shred_guitar">shred</a></em>, saya melatih <em>fingering</em> menggunakan metronome, mulai dari 100 bpm (beat per minute) sampai 180 bpm, mulai dari 1/4 sampai 1/16. Setelah mencoba tempo lambat, saya mulai menaikkan tempo. Lalu saya paksa naik lagi, sampai akurasi saya berkurang. Saat itu saya mulai menurunkan tempo, dan tangan saya terasa ringan bergerak dan lambat sekali tempo ini. Jika kita menopang tas dengan bobot 10kg selama 1 jam, lalu kita kurangi bobotnya menjadi 5 kg maka terasa sangat ringan bukan? Jadi ritme berlatih adalah dengan tempo lambat, sedang, cepat, sangat cepat (dengan sedikit paksaan), lalu kembali lagi ke sedang. Dan pada saat itu tempo sedang akan menjadi tempo yang terasa lambat, dan tempo cepat menjadi tempo sedang. Untuk berlatih, saya menggunakan GNU Typist (gtypist) di Linux. Di web, saya sering mencoba <a href="www.keyhero.com">keyhero</a> dan <a href="http://play.typeracer.com">typeracer</a>.</p>
<p>Okay, selamat berlatih untuk yang tertarik <img src='http://gedex.web.id/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2011/09/24/belajar-menjadi-touch-typist/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Mendapatkan Visa Amerika</title>
		<link>http://gedex.web.id/archives/2011/09/24/mendapatkan-visa-amerika/</link>
		<comments>http://gedex.web.id/archives/2011/09/24/mendapatkan-visa-amerika/#comments</comments>
		<pubDate>Sat, 24 Sep 2011 04:58:43 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[just FYI]]></category>
		<category><![CDATA[tips & tricks]]></category>
		<category><![CDATA[amerika]]></category>
		<category><![CDATA[visa]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=474</guid>
		<description><![CDATA[Saya akan berbagi pengalaman bagaimana cara mendapatkan visa Non-Immigrant Amerika, yang &#8220;katanya&#8221; terkenal sulit. Pengalaman saya adalah mendapatkan visa jenis B1/B2 (business dan pleasure). Untuk mengetahui jenis visa, lihat halaman disini. Saat apply visa, harap sesuaikan jenis visa dengan maksud/tujuan &#8230; <a href="http://gedex.web.id/archives/2011/09/24/mendapatkan-visa-amerika/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Saya akan berbagi pengalaman bagaimana cara mendapatkan visa <em>Non-Immigrant</em> Amerika, yang &#8220;katanya&#8221; terkenal sulit. Pengalaman saya adalah mendapatkan visa jenis B1/B2 (<em>business</em> dan <em>pleasure</em>). Untuk mengetahui jenis visa, lihat halaman <a href="http://jakarta.usembassy.gov/nonimmigrant-visas.html" title="jenis visa">disini</a>. Saat <em>apply</em> visa, harap sesuaikan jenis visa dengan maksud/tujuan Anda ke Amerika. Visa B1/B2 dapat digunakan untuk keperluan bisnis, konferensi, pengobatan, kunjungan keluarga, turis, rekreasi dan lainnya. Pada kasus saya, tujuan datang ke Amerika adalah untuk menghadiri developer meeting. Prosedur pembuatan visa Amerika sekarang agak sedikit berbeda dengan prosedur beberapa tahun yang lalu, dan sekarang terasa lebih mudah karena semua form dapat kita isi secara online dan pembayaran MRV (biaya <em>visa application</em>) dapat dilakukan kapan saja setelah form terisi lengkap. Okay, langkah-langkah berikutlah yang membuat saya mendapatkan kertas putih bertuliskan &#8220;<em>&#8230;Your U.S visa application is approved&#8230;</em>&#8220;:</p>
<ul>
<li>
Harap baca halaman &#8220;<a href="http://indonesian.jakarta.usembassy.gov/id/visas/mengajukan_visa.html" title="cara mendapatkan visa">cara mendapatkan visa</a>&#8221; di situs kedutaan Amerika. Harap baca sampai paragraf terkahir agar Anda mengetahui prosedur dan hal-hal yang perlu dihindari.
</li>
<li>Cari studio foto yang bisa mencetak foto ukuran visa, yaitu 5&#215;5. Atau cukup bilang untuk foto visa saja. Minta juga dalam bentuk file (biasanya dikasih dalam bentuk CD), karena nantinya dapat dipakai saat Anda mengisi form DS-160.
</li>
<li>
Mengisi form <a href="https://ceac.state.gov/genniv/" title="DS-160">DS-160</a> secara online. Data pribadi yang cukup detail akan diinput di form ini. Anda perlu menyediakan passport, file photo Anda (yang tentunya sudah dilakukan pada langkah sebelumnya), KTP (nomor KTP akan diinput), ijazah semua pendidikan Anda dari SD sampai kuliah (karena saya yakin Anda tidak ingat tanggal masuk dan keluar saat Anda SD, SMP, dan SMA), dan tanggal lahir orang tua Anda. Form DS-160 ini terdiri dari beberapa bagian, dan cukup panjang. Harap <em>save</em> secara berkala atau ingat nomor ID-nya (pojok kanan atas). Dan isi jangan sampai ada error. Setelah semua terisi, Anda akan diberi kesempatan untuk me-<em>review</em> form tersebut. Jika Anda sudah yakin, lalu masuk ke bagian <em>sign</em>. Setelah <em>sign</em>, cetak halaman konfirmasi DS-160 yang ada foto Anda dan tulisan barcode. Jika printer tidak terjangkau saat itu, gunakan opsi kirim ke email Anda dan cetak dari email jika printer sudah tersedia.
</li>
<li>
Setelah mendapatkan cetakan konfirmasi DS-160, Anda perlu membayar MRV Fee sebesar $140 (nilai IDR tergantung dari kurs saat Anda melakukan pembayaran). Pembayaran MRV Fee dapat dilakukan di bank Standard Chartered dan bank Permata. Saat itu, saya melakukan pembayaran di Menara Standard Chartered lantai dasar. Jadi datang saja, lalu di pintu depan bilang ke petugas keamanan mau bayar visa Amerika untuk, misal keperluan bisnis (sesuaikan dengan tujuan Anda). Nanti isi form yang diberikan, lalu masukkan nama dan nomor passport. Tunggu nomor antri dipanggil, lalu bayar sesuai yang diminta kasir (dalam IDR). Nanti akan diberikan kopian bukti pembayaran yang sudah ada nomor slip (di pojok kanan atas). Harap simpan bukti pembayaran tersebut.
</li>
<li>
Buat janji interview secara online di <a href="http://www.ustraveldocs.com/id/">http://www.ustraveldocs.com/id/</a>. Masuk ke bagian <em>Schedule My Appointment</em>. Nanti akan di redirect ke situs <a href="https://cgifederal.secure.force.com/">https://cgifederal.secure.force.com/</a>. Buat profil dengan alamat email yang Anda gunakan sehari-hari. Isi data di setiap langkah sampai pada langkah masukkan <em>receipt number</em>. Masukkan slip no. dari bukti pembayaran MRV Fee (formatnya adalah USXXXXXXXXXX, dimana X adalah digit. Masukkan 10 digitnya saja tanpa kata US). Perlu diingat slip no. dapat digunakan setelah 4 jam melakukan pembayaran, jadi harap bersabar. Jika langkah slip no. berhasil maka langkah berikutnya adalah pilihan tanggal (dengan kalendar) untuk menjadwalkan interview. Pilih tanggal lalu cetak konfirmasi jadwal tersebut, yang isinya berupa profil, tanggal interview, dan tulisan barcode.
</li>
<li>
Sampai saat ini Anda hanya tinggal menunggu sampai tanggal interview. Harap persiapkan semua dokumen seperti konfirmasi DS-160, konfirmasi jadwal interview, passport, dan foto 5&#215;5 sebanyak 1 buah (untuk amannya bawa beberapa buah). Jika Anda mempunyai passport lama, harap membawanya. Berkas lainnya yang mungkin membantu Anda disana adalah <em>invitation letter</em> (jika ada yang mengundang/mensponsori), buku tabungan atau rekening koran, KK (Kartu Keluarga). Saat itu saya membawa dokumen yang sangat lengkap mulai dari KK, Ijazah, buku nikah dan buku tabungan. Tapi pada kenyataannya hanya berkas konfirmasi DS-160, konfirmasi jadwal interview, foto 1 buah, dan passport saja yang dibutuhkan. Tapi untuk berjaga-jaga tak ada salahnya Anda membawa lengkap dokumen Anda. Jika visa Anda ditolak, maka Anda akan rugi $140. Ya, biaya MRV Fee itu tidak dikembalikan jika visa Anda ditolak dan Anda harus mengulangi semua prosedur di atas, termasuk membayar MRV Fee lagi.
</li>
<li>
Pada saat tanggal interview tiba, datang ke kedubes Amerika lebih awal, ya kurang lebih 30 menit sebelum jadwal Anda. Datang saja dengan membawa map yang berisi dokumen-dokumen Anda tadi. Saya tidak membawa ponsel, karena saya tahu itu akan dititipkan di gerbang awal. Tidak perlu membawa tas banyak-banyak, jaket, alat elektronik lainnya, makanan dan minuman.
</li>
</ul>
<p>Saat tiba di kedutaan, Anda akan mengantri di depan kedutaan Amerika. Petugas di luar kedutaan akan mengecek kelengkapan dokumen Anda, seperti berkasi konfirmasi DS-160, konfirmasi jadwal interview, passport dan foto Anda. Saat masuk gerbang pertama, semua alat elektronik, makanan dan minuman akan dititipkan. Anda akan masuk lalu mengantri lagi di loket awal, dimana berkas konfirmasi akan diserahkan. Selesai loket pertama Anda akan diberikan kartu bertuliskan nomor kelompok. Anda akan menunggu lagi sampai nomor kelompok Anda dipanggil. Saat nomor kelompok dipanggil Anda akan masuk ke ruangan untuk <em>finger printing</em> dan interview. Anda akan menunggu lagi sebentar sebelum <em>finger printing</em>. Selesai jari Anda di <em>finger printing</em>, Anda akan menunggu lagi untuk interview di loket. Ada empat atau lima loket interview. Dan interview ini dilakukan perkelompok. Waktu itu yang menginterview semuanya perempuan bule dan dapat berbahasa Indonesia. Saya kaget (dan sekaligus senang), semua kelompok sebelum saya melakukan interview dalam bahasa Indonesia. Jika ada peserta yang selesai interview mendapatkan kertas merah maka peserta tersebut gagal mendapatkan visa. Kertas putih maka visa-nya diterima. Alhamdulillah, saya dapat kertas putih. Okay berikut interview antara saya (S) dan si bule perempuan (B):</p>
<p>B: &#8220;Selamat Pagi&#8221;<br />
S: &#8220;Pagi&#8221;<br />
B: &#8220;Name?&#8221;<br />
S: &#8220;Akeda Bagus Jully Setiasgi&#8221;.<br />
B: <em>*mengecek komputer</em><br />
B: &#8220;Ape keperluan datang ke Amerika?&#8221; (serious, bukan typo, dia bilang &#8220;ape&#8221;)<br />
S: &#8220;Saya diundang Google untuk developer meeting&#8221;<br />
B: &#8220;Oh, ape Anda kerja di Google?&#8221;<br />
S: &#8220;Nope, saya kontributor di proyek open source Google.&#8221;<br />
B: &#8220;Siape yang membayari perjalan Anda?&#8221;<br />
S: &#8220;Google will take care my travel and stay&#8221; <em>*sambil memberikan invitation letter</em><br />
B: &#8220;Pekerjaan Anda sekarang?&#8221;<br />
S: &#8220;Mahasiswa dan laboratory assistant&#8221;<br />
B: &#8220;S1 or S2?&#8221;<br />
S: &#8220;S2&#8243;<br />
B: &#8220;Majoring?&#8221;<br />
S: &#8220;Electrical Engineering&#8221;<br />
B: &#8220;Pekerjaan ayah?&#8221;<br />
S: &#8220;retired&#8221;<br />
B: &#8220;Ape?&#8221;<br />
S: &#8220;retired&#8221;<br />
B: &#8220;Sorry??&#8221;<br />
S: &#8220;Pensiun!!&#8221;<br />
B: &#8220;Oh, sebelumnya?&#8221;<br />
S: &#8220;Karyawan swasta&#8221;<br />
B: &#8220;Dimana?&#8221;<br />
S: &#8220;Krakatau Steel&#8221;<br />
B: &#8220;Bagian ape?&#8221;<br />
S: <em>*mikir, mampus gw lupa</em><br />
S: &#8220;Eh, supervisor purchasing&#8221;<br />
B: &#8220;Kalau ibu?&#8221;<br />
S: &#8220;Fisioterapi&#8221;<br />
B: &#8220;Punya saudara?&#8221;<br />
S: &#8220;Ya, satu&#8221;<br />
B: &#8220;Pekerjaannya?&#8221;<br />
S: &#8220;Well Engineer di Conoco Philips&#8221;<br />
B: &#8220;Punya saudara di Amerika?&#8221;<br />
S: &#8220;Nope&#8221;<br />
B: <em>*mengetik</em><br />
B: &#8220;Ok, visa kamu diterima. Selamat melakukan perjalanan!&#8221;<br />
B: <em>*memberikan secarik kertas putih</em><br />
S: &#8220;Thanks!&#8221;</p>
<p>Pada saat saya mengantri ada dua peserta yang mendapatkan kertas merah, alias ditolak. Yang satu adalah sepasang suami-istri yang ingin mengunjungi anaknya yang baru saja melahirkan. Si ibu sudah pernah ke Amerika sebelumnya, tapi kali ini akan melakukannya berdua dengan sang suami. Saat menerima kertas merah dan si bule mengatakan &#8220;Sorry&#8221;, si ibu kaget dan bilang &#8220;Kenapa??&#8221;. Sang bule tidak berkomentar apa-apa dan mempersilahkan peserta berikutnya untuk diinterview. Satu peserta gagal lainnya yang saya perhatikan adalah seorang wanita yang ingin berkunjung ke Amerika, tapi juga memiliki teman di Las Vegas. Jadi dua peserta yang gagal tersebut justru mempunyai kerabat atau teman di sana. Ini karena Amerika khawatir pendatang ini tidak akan pulang lagi atau menjadi imigran gelap disana. Saat abang saya bertolak ke Amerika untuk training, abang saya juga tidak menyebutkan mempunyai saudara, walaupun sebenarnya ada dan abang saya berkunjung ke tempat saudara kami yang berada di Woodland. Tapi abang saya toh pulang kembali ke Indonesia selesai training. Mungkin wanita yang sebelumnya gagal itu, sedang tidak terikat pekerjaan di Indonesia atau tidak dapat meyakinkan si bule bahwa dia akan pulang kembali ke Indonesia.</p>
<p>Beberapa peserta juga dicek buku tabungan atau rekening korannya. Ini biasanya untuk pelajar, turis, dan orang yang akan melakukan perjalanan dengan biaya sendiri. Pada kasus saya dan abang saya, perjalanan disponsori. Jadi mereka tidak perlu mengecek duit yang kita punya.</p>
<p>Okay, semoga membantu dan semoga berhasil mendapatkan visa Amerika <img src='http://gedex.web.id/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2011/09/24/mendapatkan-visa-amerika/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Menggunakan Beanstalkd dan Gammu</title>
		<link>http://gedex.web.id/archives/2011/04/23/menggunakan-beanstalkd-dan-gammu/</link>
		<comments>http://gedex.web.id/archives/2011/04/23/menggunakan-beanstalkd-dan-gammu/#comments</comments>
		<pubDate>Sat, 23 Apr 2011 09:21:38 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[beanstalkd]]></category>
		<category><![CDATA[gammu]]></category>
		<category><![CDATA[pybeanstalk]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=443</guid>
		<description><![CDATA[Gammu menyediakan SMS Daemon, gammu-smsd, yang akan men-scan sms yang diterima (inbox) dan menempatkan pengiriman sms ke dalam antrian. gammu-smsd menggunakan storage (baik files maupun database) untuk menyimpan pesan di inbox ataupun antrian outbox. Jika menggunakan SMS daemon untuk mengirim &#8230; <a href="http://gedex.web.id/archives/2011/04/23/menggunakan-beanstalkd-dan-gammu/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Gammu menyediakan SMS Daemon, <code>gammu-smsd</code>, yang akan men-<em>scan</em> sms yang diterima (inbox) dan menempatkan pengiriman sms ke dalam antrian. <code>gammu-smsd</code> menggunakan <em>storage</em> (baik files maupun database) untuk menyimpan pesan di inbox ataupun antrian outbox. Jika menggunakan SMS daemon untuk mengirim sms kita tidak perlu khawatir akan kondisi <em>concurrent</em>, karena pesan sms akan di-<em>enqueue</em> dulu di storage. Jika kita hanya menggunakan perintah <code>gammu</code> saja, yaitu misal dengan : <code>gammu --sendsms TEXT 081315528932 -text "test"</code>, maka jika ada dua proses yang waktunya hampir bersamaan, salah satu proses akan mendapatkan <em>device</em> dalam keadaan <em>busy</em>, dan gagal pengiriman sms untuk proses yang telat waktu bacanya.<br />
<span id="more-443"></span><br />
Menggunakan SMS Daemon sudah cukup jika dalam sistem dibutuhkan suatu antrian, dan kondisi balapan antar proses tidak begitu besar. Tapi sayangnya SMS Daemon menggunakan <em>storage</em> untuk antrian pesan, dan lagi terlalu memakan <em>cost</em> CPU dan <em>storage</em> jika pesan sms digunakan hanya untuk konfirmasi. Jika diinginkan sistem antrian yang lebih cepat, menggunakan memory, maka kita dapat menggunakan utility <code>gammu</code> saja dan mengimplementasikan proses queue sendiri yang hanya menggunakan memory. Beruntung ada <a href="http://kr.github.com/beanstalkd/">Beanstalkd</a> yang merupakan queue sederhana. Instalasi beanstalkd cukup mudah, silahkan baca berkas README-nya. Beanstalkd memiliki banyak <a href="https://github.com/kr/beanstalkd/wiki/Client-Libraries">pustaka client</a>, kali ini saya akan menggunakan <a href="http://code.google.com/p/pybeanstalk/">pybeanstalk</a>. Gammu menyediakan python-gammu API, cukup memudahkan untuk menggunakan fitur-fitur Gammu dalam Python. Sebagai ilustrasi penggunaan, saya akan membuat dua buah berkas, yaitu <code>producer_send_sms_job.py</code> dan <code>consumer_to_send_sms_job.py</code>. Berkas <code>producer_send_sms_job.py</code> adalah <em>producer</em> yang akan terus-menerus mengirimkan job ke beanstalkd. Job yang dibuat berisi string &#8220;nomor tujuan||pesan sms&#8221;. Data string dari producer akan di split oleh <em>consumer</em> sehingga didapatkan pesan sms yang akan dikirim serta nomor tujuannya.</p>
<p>Isi berkas <code>producer_send_sms_job.py</code> :</p>
<pre lang="python">
# stdlib imports
import sys
import time

# pybeanstalk imports
from beanstalk import serverconn
from beanstalk import job

def producer_main(connection):
    i = 0
    number = '0813155289xx' # nomor tujuan
    msg = 'Test'

    while True:
        data = '%s||%s' % (number,msg)
        print data
        data = job.Job(data=data, conn=connection)
        data.Queue()
        time.sleep(1)

def main():
    try:
        print 'handling args'
        server = sys.argv[1]
        try:
            port = int(sys.argv[2])
        except:
            port = 11300

        print 'setting up connection'
        connection = serverconn.ServerConn(server, port)
        connection.job = job.Job
        producer_main(connection)
    except Exception, e:
        print "usage: example.py server [port]"
        raise
        sys.exit(1)

if __name__ == '__main__':
    main()
</pre>
<p>Isi berkas <code>consumer_to_send_sms_job.py</code> :</p>
<pre lang="python">
# stdlib imports
import sys
import time

# pybeanstalk imports
from beanstalk import serverconn
from beanstalk import job

# gammu
import gammu

def consumer_main(connection):
    print 'Init phone...'
    sm = gammu.StateMachine()
    sm.ReadConfig(Filename = '/root/.gammurc')
    sm.Init()

    i = 0
    while True:
        j = connection.reserve()
        data = j.data.split('||')
        number = data[0]
        msg = data[1]
        print 'got job! number is: %s, message is: %s' % (number, msg)
        smsinfo = {
            'Class': 1,
            'Unicode': False,
            'Entries': [{
                'ID': 'ConcatenatedTextLong',
                'Buffer': 'Pesan SMS : "' + msg + '", urutan ke-' + str(i)
            }]
        }
        encoded = gammu.EncodeSMS(smsinfo)
        for message in encoded:
            message['SMSC'] = {'Location': 1}
            message['Number'] = number
            sm.SendSMS(message)

        j.Finish()
        print 'Succesfully send sms..'
        i += 1

def main():
    try:
        print 'handling args'
        server = sys.argv[1]
        try:
            port = int(sys.argv[2])
        except:
            port = 11300

        print 'setting up connection'
        connection = serverconn.ServerConn(server, port)
        connection.job = job.Job
        consumer_main(connection)
    except Exception, e:
        print "usage: example.py server [port]"
        raise
        sys.exit(1)

if __name__ == '__main__':
    main()
</pre>
<p>Untuk menguji program di atas maka jalankan terlebih dahulu beanstalkd dengan : <code>beanstalkd -d -p 11300</code>. Dimana <code>-p</code> adalah parameter port, Anda dapat menggantinya. Lalu jalankan <code>producer_send_sms_job.py</code> dengan <code>python producer_send_sms_job.py localhost 11300</code> (pastikan port yang digunakan sama dengan beanstalkd yang digunakan). Lalu mulai jalankan <code>consumer_to_send_sms_job.py</code> dengan <code>python consumer_to_send_sms_job.py localhost 11300</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2011/04/23/menggunakan-beanstalkd-dan-gammu/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Upgrading and Cleaning</title>
		<link>http://gedex.web.id/archives/2011/04/19/upgrading-and-cleaning/</link>
		<comments>http://gedex.web.id/archives/2011/04/19/upgrading-and-cleaning/#comments</comments>
		<pubDate>Tue, 19 Apr 2011 16:53:06 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[just FYI]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=441</guid>
		<description><![CDATA[Howdy. It&#8217;s been a while I didn&#8217;t write any post. So in this idle time I try to write a post &#8212; not tech one. I upgraded my blog to 3.1.1 and used the default theme. The old theme that &#8230; <a href="http://gedex.web.id/archives/2011/04/19/upgrading-and-cleaning/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Howdy. It&#8217;s been a while I didn&#8217;t write any post. So in this idle time I try to write a post &#8212; not tech one. I upgraded my blog to 3.1.1 and used the default theme. The old theme that I created manually just a bit hackish. So here they are my new looks, hope you enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2011/04/19/upgrading-and-cleaning/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Design Pattern Dalam PHP (Bagian I)</title>
		<link>http://gedex.web.id/archives/2010/06/13/design-pattern-dalam-php/</link>
		<comments>http://gedex.web.id/archives/2010/06/13/design-pattern-dalam-php/#comments</comments>
		<pubDate>Sun, 13 Jun 2010 13:57:48 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[adapter]]></category>
		<category><![CDATA[design pattern]]></category>
		<category><![CDATA[observer]]></category>
		<category><![CDATA[oop]]></category>
		<category><![CDATA[php php5]]></category>
		<category><![CDATA[registry]]></category>
		<category><![CDATA[singleton]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=333</guid>
		<description><![CDATA[Design Pattern? Mungkin bagi yang pernah mendengarnya tentu familiar dengan bukunya Gang of Four &#8220;Design Patterns: Elements of Reusable Object-Oriented Software&#8221;. Lalu apa itu design pattern? Konsep sederhana dibalik design pattern adalah solusi untuk masalah umum yang didokumentasikan oleh seorang &#8230; <a href="http://gedex.web.id/archives/2010/06/13/design-pattern-dalam-php/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Design Pattern? Mungkin bagi yang pernah mendengarnya tentu familiar dengan bukunya Gang of Four &#8220;Design Patterns: Elements of Reusable Object-Oriented Software&#8221;. Lalu apa itu design pattern? Konsep sederhana dibalik design pattern adalah solusi untuk masalah umum yang didokumentasikan oleh seorang yang berpengalaman dalam pengembangan aplikasi. Umumnya masalah yang ada sering ditemui dalam beberapa proses pengembangan sehingga dinamai pola (<em>pattern</em>). Sedangkan desain yang digunakan untuk mengatasi pola masalah tersebut umumnya digunakan agar kode menjadi <em>less-coupled</em> (tidak terlalu mempengaruhi kode lainnya jika ada perubahan ke depannya), mudah dimantain, portabel, mudah dibaca, dapat diterapkan dalam tim yang dinamis dan untuk skala proyek yang kompleks. Design Pattern dapat digunakan dalam bahasa pemrograman apa saja, khususnya bahasa pemrograman yang OOP, tak terkecuali PHP. Ada banyak design pattern, saya akan bahas empat design pattern (Singleton, Registry, Adapter dan Observer) terlebih dahulu dan akan saya lanjutkan pattern lainnya di tulisan lainnya.<br />
<span id="more-333"></span><br />
==Singleton==</p>
<p>Singleton digunakan jika hanya diperbolehkan satu obyek terinisialisasi dari sebuah class. Misalnya sebuah class database, dimana objek yang dibuat dari class tersebut akan menginisialisasi koneksi ke database server. Untuk memastikan hanya ada satu koneksi saja yang tercipta (tentunya agar menghemat pemakaian memori) maka dapat digunakan pendekatan singleton. Berikut pseudo code dari pengimplementasian singleton pattern:</p>
<pre line="1" lang="php">
<?php
class SingletonDB {
  // digunakan untuk menyimpan obyek
  // dari SingletonDB.
  private static $__instance; 

  // dengan membuat konstruktor private
  // maka penciptaan obyek tidak dapat dilakukan
  // di luar class.
  private function __construct($param = '') {
    echo "{$param}: Object diinisialisasi...\n";
  }

  // untuk memungkin penciptaan satu objek saja
  // diperlukan method publik yang menginisialisasi
  // SingletonDB jika belum terinisialisasi lalu simpan
  // di properti class yang private. Selanjutnya obyek
  // tidak akan diinsialisasi lagi.
  public static function getInstance($param = '') {
    if ( is_null(self::$__instance) ) {
      self::$__instance = new SingletonDB($param);
      echo "{$param}: Object selesai diinisialisasi.\n";
    }

    return self::$__instance;
  }
}

// sekarang kita test
$db1 = SingletonDB::getInstance('DB1');
$db2 = SingletonDB::getInstance('DB2');
$db3 = SingletonDB::getInstance('DB3');
?>
</pre>
<p>Oke, save kode di atas dengan nama file singleton.php, lalu coba jalankan:</p>
<pre lang="bash">
akeda@akeda-laptop:~/www/design_pattern$ php singleton.php
DB1: Object diinisialisasi...
DB1: Object selesai diinisialisasi.
akeda@akeda-laptop:~/www/design_pattern$
</pre>
<p>Dapat dilihat $db2 dan $db3 tidak menginisialisasi obyek baru. Penggunaan singleton tidak hanya terbatas pada class database tapi dapat digunakan untuk situasi apapun yang membutuhkan hanya satu saja inisialisasi obyek.</p>
<p>==Registry==</p>
<p>Registry mempunyai konsep seperti <em>phonebook</em> di HP Anda. Untuk mencari no HP Budi, Anda tinggal ketik Budi maka dapatlah nomornya (dan juga informasi lainnya). Untuk memasukkan kontak baru, Anda tinggal masukkan kata kuncinya (dalam hal ini nama teman Anda) dan juga nilai yang ingin disimpan (dalam hal ini no HP teman Anda). Jika Anda familiar dengan <em>setter</em> dan <em>getter</em>, maka Anda akan mudah memahami Registry. Situasi serupa dapat diterapkan dalam konfigurasi sistem. Konfigurasi sistem meyimpan properti aplikasi seperti nama aplikasi, koneksi database, <em>theme</em> yang digunakan, dsb. Kita akan membuat sebuah class Configure yang digunakan untuk men-<em>set</em> dan men-<em>get</em> properti dari konfigurasi, berikut kode-nya:</p>
<pre lang="php"><?php
class Configure {
  private $__config;
  private static $__instance;

  private function __construct($config) {
    $this->__config = $config;
  }

/**
 * Dapatkan objek dari Configure yang juga Singleton
 * @param array $config Array konfigurasi
 * @return object Obyek dari Configure
 */
  public function getInstance($config) {
    if ( is_null(self::$__instance) ) {
      self::$__instance = new Configure($config);
    }

    return self::$__instance;
  }

/**
 * Dapatkan nilai dari $key
 * @param mixed $key Key dari array konfigurasi yang ingin di
 *                   dapatkan nilainya
 * @return mixed
 */
  public function get($key) {
    $val = null;
    if ( isset($this->__config[$key]) ) {
      $val = $this->__config[$key];
    }

    return $val;
  }

/**
 * Menset nilai $val dengan key $key ke konfigurasi
 * @param mixed $key
 * @param mixed $val
 * @return bool Selalu true
 */
  public function set($key, $val) {
    $this->__config[$key] = $val;
    return TRUE;
  }
}

// test configure
$conf_array = array(
  'app_name' => 'Aplikasi Ku', 'theme' => 'biru_muda', 'debug' => FALSE
);
$config = Configure::getInstance($conf_array);
echo $config->get('app_name') . "\n";
echo $config->get('theme') . "\n";
$config->set('debug', TRUE);
echo 'debug:' . $config->get('debug') . "\n";
?>
</pre>
<p>Sekarang test jalankan:</p>
<pre lang="bash">
akeda@akeda-laptop:~/www/design_pattern$ php registry.php
Aplikasi Ku
biru_muda
debug:1
</pre>
<p>Pada contoh class Configure di atas dapat kita lihat bahwa kita juga menerapkan Singleton. Ini dilakukan agar data konfigurasi konsisten, jadi diperlukan hanya ada satu obyek dari Configure.</p>
<p>==Adapter==</p>
<p>Misalkan Anda sedang membangun sebuah sistem CMS dimana ada fitur plugin. Anda menyediakan sebuah interface plugin dimana para developer plugin harus mengikutinya. Di core CMS Anda memiliki PluginManager yang akan mengeksekusi setiap plugin. Dalam pengembangan ke depan Anda perlu mengubah core CMS dan PluginManager pun ikut berubah. Anda tentunya tidak ingin kan setiap plugin menjadi tidak berfungsi kembali? Nah karena tidak mungkin menyentuh semua plugin yang di buat oleh developer di luar pengembang inti, Anda dapat membuat sebuah Adapter disini untuk menjembatani API dari core sebelumnya untuk kompatibel dengan API yang baru. Ini merupakan cara yang banyak digunakan proyek open source yang merilis API baru dan ingin mempertahankan kompabilitas dengan API lama. Disaat API baru dirilis mereka akan melabelkan beberapa method sebagai usang (<em>deprecated</em>), barulah diversi stabil setelahnya mereka membuang method yang usang tersebut.</p>
<p>Oke contoh yang akan kita buat adalah PluginManager sederhana yang fungsinya mengeksekusi semua plugin yang ada di dalam direktori plugins. Konvensi penamaan file plugin adalah plugin_nama_plugin.php, maka di dalam nya perlu didefinisikan sebuah class dengan nama PluginNamaPlugin yang mengimplementasi interface PluginInterface. Untuk mempermudah mengikuti contoh gunakan struktur seperti ini:</p>
<pre lang="bash">
plugins.php
plugins\plugin_a.php
plugins\plugin_b.php
plugins\plugin_akeda_b.php
</pre>
<p>Buka file plugins.php yang masih kosong. Berikut adalah interface PluginManager yang akan diimplementasi oleh class BackendPluginManager di core plugin Anda :</p>
<pre lang="php" line="1"><?php
interface PluginManager {
  public function executeAllPlugins();
}
</pre>
<p>Dan class BackendPluginManager yang mengimplementasi PluginManager (masih dalam file plugins.php) :</p>
<pre lang="php" line="5">
class BackendPluginManager implements PluginManager {
  private $__author;
  private $__content;
  private $__plugins;

  public function __construct($author_info, $content) {
    $this->__author = $author_info;
    $this->__content = $content;

    $plugin_directory = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'plugins'
                      . DIRECTORY_SEPARATOR;
    if ( empty($this->__plugins) ) {
      if ($handle = opendir($plugin_directory)) {
        while ( false !== ($file = readdir($handle)) ) {
          if ( $file != "." &#038;&#038; $file != ".." &#038;&#038; strstr($file, 'plugin_') ) {
            require_once $plugin_directory . $file;
            $plugin_name  = substr($file, 7);
            $plugin_name  = substr($plugin_name, 0, -4);
            $plugin_names = explode('_', $plugin_name);
            $plugin_name_class_name = 'Plugin';
            foreach ( $plugin_names as $w ) {
              $plugin_name_class_name .= ucfirst($w);
            }
            if ( class_exists($plugin_name_class_name) ) {
              $this->__plugins[$plugin_name_class_name] = new $plugin_name_class_name;
            }
          }
        }
        closedir($handle);
      }
    }
  }

  public function executeAllPlugins() {
    foreach ($this->__plugins as $plugin) {
      echo $plugin->filterAuthorInfo($this->__author);
      echo $plugin->filterContent($this->__content);
    }
  }
}</pre>
<p>Yang dilakukan BackendPluginManager saat method <code>__construct</code> (konstruktor) dipanggil adalah mencek semua file di direktori plugins dengan prefix nama file 'plugin_'. Lalu cek di file tersebut apakah ada class plugin yang sesuai dengan konvensi penamaan plugin. Jika terdapat class tersebut maka inisialisasi menjadi obyek dan kumpulkan dalam properti array yang <code>private</code>. Method <code>executeAllPlugins()</code> akan mengeksekusi method <code>filterAuthorInfo</code> dan <code>filterContent</code> dari obyek plugin yang telah dikumpulkan di konstruktor. Untuk membuat plugin mengikuti arsitektur plugin core, Anda perlu mendefinisikan interface yang perlu diikuti oleh pengembang plugin. Berikut adalah interface PluginInterface (masih dalam file plugins.php):</p>
<pre lang="php">
interface PluginInterface {
  public function filterContent($content);
  public function filterAuthorInfo($author_info);
}</pre>
<p>Sedangkan berikut adalah salah satu contoh plugin dengan nama plugin 'PluginA' (berarti nama filenya adalah 'plugin_a.php') :</p>
<pre lang="php" line="1"><?php
class PluginA implements PluginInterface {
  public function filterContent($content) {
    return "Plugin A - Content: {$content}\n";
  }

  public function filterAuthorInfo($author_info) {
    return "Plugin A - Author : {$author_info}\n";
  }
}
?>
</pre>
<p>Dalam contoh saya buat 3 contoh plugin, yaitu PluginA (plugins/plugin_a.php), PluginB (plugins/plugin_b.php) dan PluginAkedaB (plugins/plugin_akeda_b.php). Ok sekarang contoh implementasi-nya (dalam file plugins.php):</p>
<pre lang="php">
// Misalkan data ini telah ditarik dari db
$content = "Ini adalah content yang di filter dari setiap plugin";
$author  = "Akeda Bagus; admin@gedex.web.id";

// pseudo code di core CMS..
$plugin_manager = new BackendPluginManager($author, $content);
$plugin_manager->executeAllPlugins();
?>
</pre>
<p>Kita jalankan untuk mengetes semua plugin dan plugin manager nya bekerja seperti apa:</p>
<pre lang="bash">
akeda@akeda-laptop:~/www/design_pattern$ php plugins.php
Plugin Akeda B - Author : Akeda Bagus; admin@gedex.web.id
Plugin Akeda B - Content: Ini adalah content yang di filter dari setiap plugin
Plugin A - Author : Akeda Bagus; admin@gedex.web.id
Plugin A - Content: Ini adalah content yang di filter dari setiap plugin
Plugin B - Author : Akeda Bagus; admin@gedex.web.id
Plugin B - Content: Ini adalah content yang di filter dari setiap plugin
</pre>
<p>Dalam pengembangan Anda perlu mengubah BackendPluginManager dan PluginInterface. Apa yang harus dilakukan sementara banyak plugin diluar kendali kita? Berikut adalah interface plugin yang baru:</p>
<pre lang="php">
interface NewPluginInterface {
  public function filterContent($content);
  public function filterAuthorEmail($author_email);
  public function filterAuthorName($author_name);
}
</pre>
<p>Jika sebelumnya hanya ada method <code>filterAuthorInfo($author_info)</code>, kini plugin perlu mengimplementasi method <code>filterAuthorEmail($author_email)</code> dan <code>filterAuthorName($author_name)</code>. Di BackendPluginManager kini hanya menerima dua method tersebut. Berikut adalah class NewBackendPluginManager:</p>
<pre lang="php">class NewBackendPluginManager extends BackendPluginManager {
  private $__author_email;
  private $__author_name;
  private $__plugins;

  public function __construct($author_info, $content) {
    parent::__construct($author_info, $content);
    $author = explode(';', $author_info);
    $this->__author_email = trim($author[0]);
    $this->__author_name = trim($author[1]);
    $this->__content = $content;

    $plugin_directory = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'plugins'
                      . DIRECTORY_SEPARATOR;
    if ( empty($this->__plugins) ) {
      if ($handle = opendir($plugin_directory)) {
        while ( false !== ($file = readdir($handle)) ) {
          if ( $file != "." &#038;&#038; $file != ".." &#038;&#038; strstr($file, 'plugin_') ) {
            require_once $plugin_directory . $file;
            $plugin_name  = substr($file, 7);
            $plugin_name  = substr($plugin_name, 0, -4);
            $plugin_names = explode('_', $plugin_name);
            $plugin_name_class_name = 'Plugin';
            foreach ( $plugin_names as $w ) {
              $plugin_name_class_name .= ucfirst($w);
            }
            if ( class_exists($plugin_name_class_name) ) {
              $this->__plugins[$plugin_name_class_name] = new $plugin_name_class_name;
            }
          }
        }
        closedir($handle);
      }
    }
  }

  public function executeAllPlugins() {
    foreach ($this->__plugins as $plugin) {
      $interfaces = class_implements($plugin);

      // jika interface yang digunakan bukan
      // interface yang baru
      if ( !array_key_exists('NewPluginInterface', $interfaces) ) {
        $plugin = new PluginAdapter($plugin);
      }

      echo $plugin->filterAuthorEmail($this->__author_email);
      echo $plugin->filterAuthorName($this->__author_name);
      echo $plugin->filterContent($this->__content);
    }
  }
}</pre>
<p>Anda menginginkan plugin baru mengikuti interface ini tapi plugin lama tetap dapat berjalan. Solusi mudah adalah dengan Adapter. Berikut adalah contoh Adapter yang menjadi jembatan antara plugin dan NewBackendPluginManager:</p>
<pre lang="php">class PluginAdapter implements NewPluginInterface {
  private $__plugin;

  function __construct($plugin) {
    $this->__plugin = $plugin;
  }

  public function filterContent($content) {
    return $this->__plugin->filterContent($content);
  }

  public function filterAuthorEmail($author_email) {
    return $this->__plugin->filterAuthorInfo($author_email);
  }

  public function filterAuthorName($author_name) {
    return $this->__plugin->filterAuthorInfo($author_name);
  }
}</pre>
<p>Sekarang kita test plugin manager dan Adapter tersebut :</p>
<pre lang="php">
$plugin_manager = new NewBackendPluginManager($author, $content);
$plugin_manager->executeAllPlugins();
?>
</pre>
<p>Berikut hasilnya:</p>
<pre lang="bash">
akeda@akeda-laptop:~/www/design_pattern$ php plugins.php
Plugin A - Author : Akeda Bagus
Plugin A - Author : admin@gedex.web.id
Plugin A - Content: Ini adalah content yang di filter dari setiap plugin
Plugin Akeda B - Author : Akeda Bagus
Plugin Akeda B - Author : admin@gedex.web.id
Plugin Akeda B - Content: Ini adalah content yang di filter dari setiap plugin
Plugin B - Author : Akeda Bagus
Plugin B - Author : admin@gedex.web.id
Plugin B - Content: Ini adalah content yang di filter dari setiap plugin
</pre>
<p>Selain untuk menjadi jembatan antara API yang tidak saling kompatibel, Adapter juga dapat digunakan untuk jembatan antara model (tabel dalam bentuk objek) dan database. Karena banyaknya jenis database yang perlu disupport Anda dapat menggunakan pendekatan Adapter dalam hal ini.</p>
<p>==Observer==</p>
<p>Observer mempunyai konsep seperti notifikasi di Facebook dan notifikasi layanan SMS. Di facebook pada saat kita mengomentari <em>posting</em> di <em>wall</em> seseorang maka kita secara tidak langsung akan mendaftarkan diri kita menerima notifikasi jika ada komentar baru. Dalam layanan content di SMS, pada saat kita mendaftarkan diri kita ke suatu layanan via REG DAFTAR, maka kita akan mendapatkan notifikasi/balasan SMS jika ada suatu event berkaitan dengan layanan SMS tersebut. Design pattern Observer terdiri dari dua entitas, yaitu subyek yang di observasi dan <em>observer</em> yang mendaftarkan diri untuk diberitahu jika suatu event terjadi terhadap subyek yang diobservasi. Dalam kasus Facebook, <em>wall posting</em> seseorang disebut sebagai subyek yang di observasi, sedangkan observer-nya adalah teman yang berkomentar di <em>wall posting</em> tersebut. Kita akan ambil contoh class WallPost sebagai subyek yang diobservasi. Pertama kita buat dahulu interface ObservableSubject agar setiap class yang ingin terobservasi harus mengimplementasi interface ini:</p>
<pre lang="php" line="1"><?php
interface ObservableSubject {
  public function reg($key, $obj);
  public function unreg($key);
  public function notify();
}
</pre>
<p>Pada interace ObservableSubject, method <code>reg($key, $obj)</code> digunakan oleh <em>observer</em> yang tertarik mendapatkan notifikasi. Method <code>unreg($key)</code> digunakan jika <em>observer</em> sudah tidak tertarik lagi mendapatkan notifikasi. Sedangkan method <code>notify()</code> digunakan untuk mem-<em>broadcast</em> notifikasi ke semua <em>observer</em> yang telah mendaftar. Sekarang kita perlu membuat interface Observer untuk class yang tertarik menjadi <em>observer</em>:</p>
<pre lang="php" line="8">interface Observer {
  public function getNotification($wall_owner, $username, $act);
}
</pre>
<p>Berikut contoh class WallPost yang mengimplementasikan ObservableSubject:</p>
<pre lang="php" line="12">
class WallPost implements ObservableSubject {
  private $__owner;
  private $__username;
  private $__act;
  private $__observers = array();

  public function __construct($owner) {
    $this->__owner = $owner;
  }

  public function reg($key, $obj) {
    $this->__observers[$key] = $obj;
  }

  public function unreg($key) {
    unset($this->__observers[$key]);
  }

  public function notify() {
    foreach ($this->__observers as $observer) {
      $observer->getNotification($this->__owner, $this->__username, $this->__act);
    }
  }

  public function fav($username) {
    $this->__username = $username;
    $this->__act = 'favorites';
    $this->notify();
  }

  public function comment($username) {
    $this->__username = $username;
    $this->__act = 'comments';
    $this->notify();
  }
}
</pre>
<p>Pada class WallPost terdapat method <code>reg($key, $obj)</code>, <code>unreg($key)</code> dan <code>notify()</code> yang merupakan hasil kontrak dengan interface ObservableSubject. Semua obyek yang mendaftar melalui method <code>reg($key, $obj)</code> akan dikumpulkan dalam properti array <code>$__observers</code>. Method <code>fav($username)</code> dan <code>comment($username)</code> merupakan aksi (<code>$__act</code>) yang terjadi di WallPost. Jika aksi tersebut terjadi di WallPost, maka method <code>notify()</code> akan dipanggil untuk memberi notifikasi ke semua <em>obervser</em> yang telah terdaftar. Sekarang kita perlu membuat class yang mengimplementasikan Observer. Pada contoh saya akan buat tiga class dengan tujuan yang berbeda-beda, yaitu class UserNotification (untuk menotifikasi pengguna via dashboard), MailerNotification (untuk menotifikasi pengguna via email) dan SystemLog (untuk menotifikasi system logger). Berikut class-class tersebut:</p>
<pre lang="php" line="49">
class UserNotification implements Observer {
  private $__my_name;
  public function __construct($my_name) {
    $this->__my_name = $my_name;
  }

  public function getNotification($wall_owner, $username, $act) {
    echo "UserNotification: Hi {$this->__my_name}! {$username} {$act} on {$wall_owner}'s wall\n";
  }
}

class MailerNotification implements Observer {
  private $__my_name;
  public function __construct($my_name) {
    $this->__my_name = $my_name;
  }

  public function getNotification($wall_owner, $username, $act) {
    echo "MailerNotification: Hi {$this->__my_name}! {$username} {$act} on {$wall_owner}'s wall\n";
  }
}

class SystemLog implements Observer {
  public function getNotification($wall_owner, $username, $act) {
    echo "SystemLog: {$username} {$act} on {$wall_owner}'s wall\n";
  }
}
</pre>
<p>Sekarang kita tes jalankan :</p>
<pre lang="php" line="77">
// inisialisasi subyek yang akan diobservasi
$my_wall = new WallPost("Akeda Bagus");

// daftarkan notifikasi ke semua teman
$my_friends = array('Budi', 'Eko', 'Paul');
foreach ( $my_friends as $friend ) {
  ${$friend . '_dashboard'} = new UserNotification($friend);
  ${$friend . '_mail'} = new MailerNotification($friend);
  $my_wall->reg($friend . '_dashboard', ${$friend . '_dashboard'});
  $my_wall->reg($friend . '_mail', ${$friend . '_mail'});
}
// notifikasikan juga sistem log
$sys_log = new SystemLog();
$my_wall->reg('system_log', $sys_log);

// Yuli memfavoritkan postingan di wall Akeda Bagus
$my_wall->fav('Yuli');

// Jono mengomentari postingan di wall Akeda Bagus
$my_wall->comment('Jono');

// Budi dan Eko tidak tertarik lagi mendapatkan notifikasi
$my_wall->unreg('Budi_dashboard');
$my_wall->unreg('Budi_mail');
$my_wall->unreg('Eko_dashboard');
$my_wall->unreg('Eko_mail');

// John berkomentar, tapi kini hanya Paul dan SystemLog yang
// akan menerima notifikasi
$my_wall->comment('John');
</pre>
<p>Dan berikut adalah hasilnya:</p>
<pre lang="bash">
akeda@akeda-laptop:~/www/design_pattern$ php observer.php
UserNotification: Hi Budi! Yuli favorites on Akeda Bagus's wall
MailerNotification: Hi Budi! Yuli favorites on Akeda Bagus's wall
UserNotification: Hi Eko! Yuli favorites on Akeda Bagus's wall
MailerNotification: Hi Eko! Yuli favorites on Akeda Bagus's wall
UserNotification: Hi Paul! Yuli favorites on Akeda Bagus's wall
MailerNotification: Hi Paul! Yuli favorites on Akeda Bagus's wall
SystemLog: Yuli favorites on Akeda Bagus's wall
UserNotification: Hi Budi! Jono comments on Akeda Bagus's wall
MailerNotification: Hi Budi! Jono comments on Akeda Bagus's wall
UserNotification: Hi Eko! Jono comments on Akeda Bagus's wall
MailerNotification: Hi Eko! Jono comments on Akeda Bagus's wall
UserNotification: Hi Paul! Jono comments on Akeda Bagus's wall
MailerNotification: Hi Paul! Jono comments on Akeda Bagus's wall
SystemLog: Jono comments on Akeda Bagus's wall
UserNotification: Hi Paul! John comments on Akeda Bagus's wall
MailerNotification: Hi Paul! John comments on Akeda Bagus's wall
SystemLog: John comments on Akeda Bagus's wall
</pre>
<p>==Kesimpulan==<br />
Kita sudah membahas tentang Singleton, Registry, Adapter dan Observer. Singleton digunakan untuk situasi dimana dibutuhkan satu obyek saja yang terinisialisasi dari sebuah class (seperti class Database). Registry diibaratkan seperti sebuah phonebook HP, dimana dibutuhkan sebuah class yang dapat menyimpan dan mendapatkan nilai berdasarkan kunci tertentu. Adapter digunakan sebagai jembatan antara dua buah API yang sudah tidak kompatibel atau jembatan antara API yang beragam. Dan yang terakhir adalah Observer yang mempunyai konsep seperti wall post di Facebook, dimana subyek yang menjadi sentral pemberi notifikasi ke obyek yang tertarik terhadap notifikasi subyek tersebut. Di tulisan lain, saya akan bahas design pattern lainnya. Happy Coding!</p>
<p>==Referensi==<br />
* E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley, Reading, MA, 1995.<br />
* Steve Holzner. Design Patterns. VTC Videos, 2007.</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2010/06/13/design-pattern-dalam-php/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Quick Tips to Help You get Accepted on Google Summer of Code</title>
		<link>http://gedex.web.id/archives/2010/06/01/quick-tips-to-help-you-get-accepted-on-google-summer-of-code/</link>
		<comments>http://gedex.web.id/archives/2010/06/01/quick-tips-to-help-you-get-accepted-on-google-summer-of-code/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 11:55:23 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[Google Summer of Code 2010]]></category>
		<category><![CDATA[GSoC]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=328</guid>
		<description><![CDATA[I&#8217;ve great news that, AFAIK, there are two students from Indonesia that have been accepted on Google Summer of Code 2010. They are (drum roll please) Akeda and Dwi. I&#8217;ve been posted a message on gsoc student mailing list to &#8230; <a href="http://gedex.web.id/archives/2010/06/01/quick-tips-to-help-you-get-accepted-on-google-summer-of-code/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve great news that, AFAIK, there are two students from Indonesia that have been accepted on Google Summer of Code 2010. They are (drum roll please) <a href="http://docs.google.com/View?id=dd78s8mr_5cs8x3shh">Akeda</a> and <a href="http://wiki.github.com/ginatrapani/thinktank/dwi-widiastuti-installation-simplification-and-auto-updates">Dwi</a>. I&#8217;ve been posted a message on gsoc student mailing list to alert other Indonesian students, but no one replying. So, I guess there&#8217;s only me and dwi get accepted this year. Since, I&#8217;ve accepeted I&#8217;ll give my own tips on how to get accepted as a student of Google Summer of Code. The key is write a good proposal and communicate with your mentoring project oftenly. A good proposal is not your first try proposal. When you writing your proposal for the first time oftenly it&#8217;s just a draft proposal. You need to ask your mentoring project some feedbacks and iterate the process by rewrite and ask again until the mentoring project says okay. This year is a little bit different, some mentoring organisations posts some bugs tagged for applicants and each applicant should work, on bug(s) by submitting patch for that bug. I did this. Doing this means your chance to get attentions from mentoring organisation is higher. So, you need to touch the codebase of the project which you have interest on it. Because of this you shouldn&#8217;t have to submit a proposal as much as you think to get accepted. The increased quantity of your proposals may even decreased overall proposal qualities, since you have to split your focus. </p>
<p>Okay, you&#8217;ve got the picture? Alright, how about the content of good proposal? Some mentoring organisations were kind enough to give us templates of proposal to work on. The templates are general as it should have a brief description about the project you have interested in, implementation plans, timeline and short biography about yourself. You should focus (IMHO) on writing your implementation plans and timeline. A google summer of code project is around 3 or 4 months duration, so it can be said as a medium project for a single developer. The key is how good you describe the problem and its solution. When you touched the codebase of a project for submitting patch, you get the benefits on how you&#8217;ll describe the software on your proposal. Use the name of the classes, methods, libraries that related to your project and how you&#8217;ll using it to solve the problem. Mentoring organisations will pick up student that already familiar with their codebase. Don&#8217;t write too much, use screenshots if available. If your project is a complex one, divide your project into three or four subprojects then define the timeline of each subprojects. Well, that&#8217;s my own quick tips. I hope Indonesian students will aware about this event on the next year <img src='http://gedex.web.id/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  .</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2010/06/01/quick-tips-to-help-you-get-accepted-on-google-summer-of-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hari Baru yang Perlu Diingat</title>
		<link>http://gedex.web.id/archives/2010/05/20/hari-baru-yang-perlu-diingat/</link>
		<comments>http://gedex.web.id/archives/2010/05/20/hari-baru-yang-perlu-diingat/#comments</comments>
		<pubDate>Thu, 20 May 2010 09:31:02 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[etc]]></category>
		<category><![CDATA[family]]></category>
		<category><![CDATA[my life]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=326</guid>
		<description><![CDATA[Hari itu adalah 16 Mei, dan perlu saya ingat agar &#8220;Nyonya&#8221; juga tidak mengkencangkan otot mata. Sebenarnya saya juga bingung mau menulis apa, ini hanya tulisan asal agar blog ini terlihat terkini. Btw, komentar di blog ini tetap saja ada &#8230; <a href="http://gedex.web.id/archives/2010/05/20/hari-baru-yang-perlu-diingat/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Hari itu adalah 16 Mei, dan perlu saya ingat agar &#8220;Nyonya&#8221; juga tidak mengkencangkan otot mata. Sebenarnya saya juga bingung mau menulis apa, ini hanya tulisan asal agar blog ini terlihat terkini. Btw, komentar di blog ini tetap saja ada yang masuk dan paling banyak ke tulisan saya mengenai <a href="http://gedex.web.id/archives/2008/03/24/penipuan-berkedok-undian-motor-telkomsel/">penipuan undian telkomsel</a>. Hal ini membuktikan modus penipuan seperti ini masih menjamur.</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2010/05/20/hari-baru-yang-perlu-diingat/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Pergeseran Waktu dalam Perjuangan</title>
		<link>http://gedex.web.id/archives/2010/03/05/pergeseran-waktu-dalam-perjuangan/</link>
		<comments>http://gedex.web.id/archives/2010/03/05/pergeseran-waktu-dalam-perjuangan/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 23:58:12 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[my life]]></category>
		<category><![CDATA[belajar]]></category>
		<category><![CDATA[engineer]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=317</guid>
		<description><![CDATA[Beberapa bulan ini saya merasakan pergeseran waktu kembali. Yup, hari terasa begitu cepat berlalu tahun ini, siang kini terasa semakin cepat dan malam menjelang pagi terasa begitu lama. Beberapa bulan ini saya kembali menjadi kalong, tidur dikala para pekerja terjebak &#8230; <a href="http://gedex.web.id/archives/2010/03/05/pergeseran-waktu-dalam-perjuangan/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Beberapa bulan ini saya merasakan pergeseran waktu kembali. Yup, hari terasa begitu cepat berlalu tahun ini, siang kini terasa semakin cepat dan malam menjelang pagi terasa begitu lama. Beberapa bulan ini saya kembali menjadi kalong, tidur dikala para pekerja terjebak macet menuju kantor mereka dan bangun dikala pekerja hendak makan siang. Well, sejak kuliah (dan bahkan sejak SMA) saya sudah terinfeksi dengan pola hidup seperti ini. Belajar dan bekerja disaat semua orang terlelap bagi saya mempunyai nuansa tersendiri. Kadang jika kita ingin meraih sesuatu ada hal yang harus kita korbankan, entah itu kebersamaan atau waktu tidur. Dan sayangnya saya selalu ingin meraih sesuatu sehingga ada saja yang harus dikorbankan. Apa yang ingin saya raih saat ini? Hmm.. hanya satu, yaitu ilmu (saya bohong, plus uang tentunya). Berbicara tentang keinginan yang diraih, saya jadi teringat percakapan dengan teman saya malam kemarin, seseorang yang ingin bekerja dibidang yang disukai (tapi dengan <em>salary</em> yang setimpal). <span id="more-317"></span>Sebenarnya itu mudah, bahkan kita tidak perlu mencari pekerjaan itu. Jika memang ingin bekerja dibidang yang kita sukai plus gaji yang setimpal atau berlebih maka bekerjalah di bidang tersebut terlebih dahulu karena kecintaan terhadap bidang yag digeluti. Bangun <em>experience</em> di bidang tersebut sehingga orang dapat langsung menilai kualitas Anda karena experience. Tentunya experience perlu pengorbanan terlebih dahulu, baik waktu dan uang. Saya senang melihat profil Software Engineer di Facebook, Google dan Yahoo. Mereka benar-benar engineer yang mencintai pekerjaannya dan menginsparasi orang lain. Terkadang <a href="http://www.catonmat.net/blog/my-job-interview-at-google/" rel="external nofollow">proses udangan <em>interview</em> di Google</a> adalah dengan mencari di internet atau karena nama kita cukup terdengar di internet. Jadi membangun portfolio di internet sangat membantu mengenalkan diri Anda ke perusahaan yang Anda incar.</p>
<p>Well, membangun portfolio di internet tidak dapat instan. Mungkin kita bisa lihat perjalanan Guido van Rossum&mdash;mengembangkan Python&mdash;bekerja sebagai <em>engineer</em> di Google,  Rasmus Lerdorf&mdash;mengembangkan PHP&mdash;yang menjadi <em>Distinguished Engineer</em> Yahoo, dan banyak engineer lainnya. Oh ya, mempunyai <em>influence</em> merupakan <em>starting point</em> untuk dapat menjadi sukses seperti mereka. Oh ya, tentunya siap dengan pergeseran waktu.</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2010/03/05/pergeseran-waktu-dalam-perjuangan/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>ls direktori dalam format tree</title>
		<link>http://gedex.web.id/archives/2010/03/04/ls-direktori-dalam-format-tree/</link>
		<comments>http://gedex.web.id/archives/2010/03/04/ls-direktori-dalam-format-tree/#comments</comments>
		<pubDate>Wed, 03 Mar 2010 22:40:07 +0000</pubDate>
		<dc:creator>gedex</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[tips & tricks]]></category>
		<category><![CDATA[ls]]></category>
		<category><![CDATA[tree]]></category>

		<guid isPermaLink="false">http://gedex.web.id/?p=304</guid>
		<description><![CDATA[Apabila kita bekerja dengan konsol dan ingin mengetahui struktur direktori tertentu biasanya kita melakukannya dengan perintah ls nama_direktori, lalu kita ls lagi direktori di dalamnya. Jika kita bekerja di desktop, kita dapat mengetahui struktur direktori tertentu dengan membuka penjelajah berkas &#8230; <a href="http://gedex.web.id/archives/2010/03/04/ls-direktori-dalam-format-tree/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Apabila kita bekerja dengan konsol dan ingin mengetahui struktur direktori tertentu biasanya kita melakukannya dengan perintah <code>ls nama_direktori</code>, lalu kita <code>ls</code> lagi direktori di dalamnya. Jika kita bekerja di desktop, kita dapat mengetahui struktur direktori tertentu dengan membuka penjelajah berkas (<em>file browser</em>). Sebenarnya di konsol, ada perintah <code>tree</code> untuk melihat senarai direktori dalam format <em>tree</em>.</p>
<blockquote><p>tree &#8211; list contents of directories in a tree-like format.</p></blockquote>
<p>Saya menggunakan ubuntu, cukup mudah menginstalnya jika perintah <code>tree</code> belum tersedia.</p>
<p><code>sudo apt-get install tree</code></p>
<p>Lalu kita lihat seperti apa keluarannya:</p>
<pre>
akeda@akeda-desktop:~$ tree ~/www/keuangan/app/models
/home/akeda/www/keuangan/app/models
|-- activity.php
|-- activity_child.php
|-- behaviors
|   |-- empty
|   |-- formatable.php
|   `-- money.php
|-- budget.php
|-- budget_detail.php
|-- budget_detail_description.php
|-- city.php
|-- datasources
|   `-- empty
|-- funding_source.php
|-- group.php
|-- groups_module_action.php
|-- journal_bank.php
|-- journal_cash.php
|-- journal_tax.php
|-- menu.php
|-- menu_type.php
|-- module.php
|-- module_action.php
|-- province.php
|-- site_setting.php
|-- tax_type.php
|-- transaction.php
|-- transaction_revision.php
|-- unit.php
|-- unit_code.php
|-- user.php
|-- user_log.php
`-- volume.php

2 directories, 30 files
</pre>
<p></p>
<p>Sebernarnya keluaran hasil <code>tree</code> di atas berwarna tergantung tipe berkas dan ekstensinya (yang terdefinsi dalam <code>dircolors</code>). Untuk penggunaan lebih lanjut silahkan coba-coba dan baca <code>man tree</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://gedex.web.id/archives/2010/03/04/ls-direktori-dalam-format-tree/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

