<?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"
	>

<channel>
	<title>Barg the Blog</title>
	<atom:link href="http://barg.hitoridake.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://barg.hitoridake.com</link>
	<description>Worsen the Internet Since 1998</description>
	<pubDate>Wed, 12 Nov 2008 02:11:12 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>Hazel—Droplets—and You</title>
		<link>http://barg.hitoridake.com/2008/10/hazel-droplets-and-you/</link>
		<comments>http://barg.hitoridake.com/2008/10/hazel-droplets-and-you/#comments</comments>
		<pubDate>Wed, 29 Oct 2008 13:09:50 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Wired]]></category>

		<category><![CDATA[Mac OS X]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=109</guid>
		<description><![CDATA[นั่งเล่น Hazel ตัว 14-day Trial อยู่ซักพักหนึ่ง เริ่มประทับใจในความสามารถของมัน เลยลองนั่งทำ droplet สำหรับอัพโหลดไฟล์ลง WebDAV สำหรับ instant file hosting ส่วนตัว ดู ดูเหมือนว่าจะทำได้ง่ายกว่าที่คิดไว้เยอะ วิธีการทำคือ สร้างไดเรคทอรี่เปล่าๆ ขึ้นมาหนึ่งอัน และเพิ่ม Rule ลงไป (ตั้งชื่อไว้ว่า &#8220;Upload file(s) to WebDAV server&#8221;)


Date Added: is in the last 10 minutes
Run shell script: embedded script
Send Growl notification: with pattern &#8220;File(s) has been successfully uploaded.&#8221;


โค้ดสำหรับใช้อัพโหลดเป็นแค่ shell script ง่ายๆ เรียกหา curl [...]]]></description>
			<content:encoded><![CDATA[<p>นั่งเล่น <a href="http://www.noodlesoft.com/hazel.php">Hazel</a> ตัว 14-day Trial อยู่ซักพักหนึ่ง เริ่มประทับใจในความสามารถของมัน เลยลองนั่งทำ droplet สำหรับอัพโหลดไฟล์ลง <a href="http://en.wikipedia.org/wiki/WebDAV">WebDAV</a> สำหรับ <a href="http://temp.hitoridake.com/">instant file hosting ส่วนตัว</a> ดู ดูเหมือนว่าจะทำได้ง่ายกว่าที่คิดไว้เยอะ วิธีการทำคือ สร้างไดเรคทอรี่เปล่าๆ ขึ้นมาหนึ่งอัน และเพิ่ม Rule ลงไป (ตั้งชื่อไว้ว่า &#8220;Upload file(s) to WebDAV server&#8221;)</p>

<ul>
<li>Date Added: is in the last 10 minutes</li>
<li>Run shell script: embedded script</li>
<li>Send Growl notification: with pattern &#8220;File(s) has been successfully uploaded.&#8221;</li>
</ul>

<p>โค้ดสำหรับใช้อัพโหลดเป็นแค่ shell script ง่ายๆ เรียกหา <code>curl</code> แค่นั้น หน้าตาแบบนี้</p>


<div class="wp_syntax"><div class="code"><pre class="bash bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/bash</span>
<span style="color: #000000; font-weight: bold;">for</span> <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #ff0000;">&quot;$@&quot;</span>; <span style="color: #000000; font-weight: bold;">do</span>
    curl <span style="color: #660033;">-u</span> user:pass <span style="color: #660033;">-T</span> <span style="color: #ff0000;">&quot;$file&quot;</span> http:<span style="color: #000000; font-weight: bold;">//</span>temp.hitoridake.com<span style="color: #000000; font-weight: bold;">/</span>
    <span style="color: #c20cb9; font-weight: bold;">mv</span> <span style="color: #ff0000;">&quot;$file&quot;</span> ~<span style="color: #000000; font-weight: bold;">/</span>.Trash<span style="color: #000000; font-weight: bold;">/</span>
<span style="color: #000000; font-weight: bold;">done</span></pre></div></div>


<p>ก่อนหน้านี้เกือบเสียเวลานั่งเขียนโค้ดเล็กๆ สำหรับอัพโหลดลง WebDAV เอาเองเสียแล้ว เพิ่งได้รู้ทีหลังว่าจริงๆ มันแค่ สั่ง <code>curl -T file URL</code> เอาก็ได้ พอเสร็จแล้วก็ลากไดเรคทอรี่เปล่าๆ ที่สร้างไปยัง Dock เวลาต้องการจะอัพโหลดไฟล์ไหนก็แค่โยนไฟล์ลงไดเรคทอรี่นั้นใน Dock ก็เป็นอันเสร็จเรียบร้อย</p>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/10/hazel-droplets-and-you/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Transmission, Clutch, Gear</title>
		<link>http://barg.hitoridake.com/2008/10/transmission-clutch-gear/</link>
		<comments>http://barg.hitoridake.com/2008/10/transmission-clutch-gear/#comments</comments>
		<pubDate>Sat, 11 Oct 2008 23:19:57 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Wired]]></category>

		<category><![CDATA[BitTorrent]]></category>

		<category><![CDATA[FreeBSD]]></category>

		<category><![CDATA[Problem Solving]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=102</guid>
		<description><![CDATA[Transmission ตั้งแต่เวอร์ชั่น 1.3 เป็นต้นมา เพิ่มฟีเจอร์สั่งงานผ่านหน้าเว็บ ถึงแม้มันจะหน้าตาเหมือนกันกับ Clutch เด๊ะๆ แต่เอาเข้าจริงแล้ว มันคือการเขียนใหม่หมด และเรียกใช้งาน JSON-RPC Interface ใหม่ที่ถูกเพิ่มมาในเวอร์ชั่นเดียวกัน โดยไม่ต้องผ่าน PHP เหมือนที่เคย

การติดตั้งบนลินุกซ์น่าจะเป็นไปได้ง่ายๆ เพียงแค่ลงแพคเกจ transmission-daemon (หรือ transmission-cli ใน Debian-based distro) แต่สำหรับในกรณีของ FreeBSD นั้น ตัวเว็บมันถูกแยกออกไปเป็นแพคเกจ  transmission-web อีกต่อ ดังนั้นจึงต้องลงด้วยกันสองแพคเกจ


/usr/ports/net-p2p/transmission-daemon
/usr/ports/www/transmission-web


หลังจากลงเสร็จเรียบร้อย เนื่องจากว่า transmission-daemon นั้นไม่แถม init-script มาให้ จึงจำเป็นต้องเขียนเอง โชคดีที่บน FreeBSD นั้น การเขียน init-script ให้เป็นไปตามต้องการนั้นง่ายมาก ที่ผมเขียนไว้มีหน้าตาแบบนี้ (โยนลง /usr/local/etc/rc.d/transmission)




#!/bin/sh
#
# PROVIDE: transmission
# REQUIRE: DAEMON
#
# Add the following lines [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.transmissionbt.com/"><strong><em>Transmission</em></strong></a> ตั้งแต่เวอร์ชั่น 1.3 เป็นต้นมา เพิ่มฟีเจอร์สั่งงานผ่านหน้าเว็บ ถึงแม้มันจะหน้าตาเหมือนกันกับ <a href="http://clutchbt.com/"><em>Clutch</em></a> เด๊ะๆ แต่เอาเข้าจริงแล้ว มันคือการเขียนใหม่หมด และเรียกใช้งาน JSON-RPC Interface ใหม่ที่ถูกเพิ่มมาในเวอร์ชั่นเดียวกัน โดยไม่ต้องผ่าน PHP เหมือนที่เคย</p>

<p>การติดตั้งบนลินุกซ์น่าจะเป็นไปได้ง่ายๆ เพียงแค่ลงแพคเกจ <code>transmission-daemon</code> (หรือ <code>transmission-cli</code> ใน Debian-based distro) แต่สำหรับในกรณีของ <a href="http://www.freebsd.org/">FreeBSD</a> นั้น ตัวเว็บมันถูกแยกออกไปเป็นแพคเกจ  <code>transmission-web</code> อีกต่อ ดังนั้นจึงต้องลงด้วยกันสองแพคเกจ</p>

<ol>
<li><code>/usr/ports/net-p2p/transmission-daemon</code></li>
<li><code>/usr/ports/www/transmission-web</code></li>
</ol>

<p>หลังจากลงเสร็จเรียบร้อย เนื่องจากว่า <code>transmission-daemon</code> นั้นไม่แถม init-script มาให้ จึงจำเป็นต้องเขียนเอง โชคดีที่บน FreeBSD นั้น การเขียน init-script ให้เป็นไปตามต้องการนั้นง่ายมาก ที่ผมเขียนไว้มีหน้าตาแบบนี้ (โยนลง <code>/usr/local/etc/rc.d/transmission</code>)</p>

<p><span id="more-102"></span></p>


<div class="wp_syntax"><div class="code"><pre class="bash bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #666666; font-style: italic;">#</span>
<span style="color: #666666; font-style: italic;"># PROVIDE: transmission</span>
<span style="color: #666666; font-style: italic;"># REQUIRE: DAEMON</span>
<span style="color: #666666; font-style: italic;">#</span>
<span style="color: #666666; font-style: italic;"># Add the following lines to /etc/rc.conf to run transmission:</span>
<span style="color: #666666; font-style: italic;">#</span>
<span style="color: #666666; font-style: italic;">#transmission_enable=&quot;YES&quot;</span>
&nbsp;
. <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>rc.subr
&nbsp;
<span style="color: #007800;">name</span>=<span style="color: #ff0000;">&quot;transmission&quot;</span>
<span style="color: #007800;">rcvar</span>=<span style="color: #800000;">${name}</span>_enable
&nbsp;
load_rc_config <span style="color: #800000;">${name}</span>
&nbsp;
: <span style="color: #800000;">${transmission_enable=&quot;NO&quot;}</span>
: <span style="color: #800000;">${transmission_user=&quot;nobody&quot;}</span>
: <span style="color: #800000;">${transmission_args=&quot;&quot;}</span>
&nbsp;
<span style="color: #007800;"><span style="color: #7a0874; font-weight: bold;">command</span></span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span><span style="color: #7a0874; font-weight: bold;">local</span><span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>transmission-daemon
<span style="color: #007800;">command_args</span>=<span style="color: #ff0000;">&quot;-g /usr/local/etc/transmission $transmission_args&quot;</span>
&nbsp;
run_rc_command <span style="color: #ff0000;">&quot;$1&quot;</span></pre></div></div>


<p>หลังจากนั้นก็ไป enable transmission ใน <code>/etc/rc.conf</code> ด้วยการเพิ่มบรรทัด <code>transmission_enable="YES"</code> พร้อมปรับแต่ง arguments อีกเล็กน้อยผ่านทาง <code>transmission_args</code> สำหรับ arguments ที่ใช้ได้ทั้งหมดก็เปิด <code>man transmission-daemon</code> เอา</p>

<p>อ้อ ก่อนหน้านั้นต้องทำการสร้างไดเรคทอรี่ <code>/usr/local/etc/transmission</code> ก่อนด้วย เอาไว้เก็บพวกข้อมูลเช่นพวกไฟล์ torrent ต่างๆ (น่าจะมีที่เก็บที่ดีกว่านี้นะ เช่นใน <code>var</code>?) แล้วก็เริ่มโหลดได้อย่างสบายใจ</p>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/10/transmission-clutch-gear/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Fix for once</title>
		<link>http://barg.hitoridake.com/2008/09/fix-for-once/</link>
		<comments>http://barg.hitoridake.com/2008/09/fix-for-once/#comments</comments>
		<pubDate>Sat, 27 Sep 2008 21:55:09 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Wired]]></category>

		<category><![CDATA[Mac OS X]]></category>

		<category><![CDATA[MPlayer]]></category>

		<category><![CDATA[Problem Solving]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=97</guid>
		<description><![CDATA[ปัญหาตลกๆ ที่เกิดกับ MPlayer บน Mac OS X มานานแสนนานก็คือเมื่อปรับการแสดงผลเป็น CoreVideo แบบฝังติดกับตัว player มันจะมีปัญหาว่าไม่สามารถเปิดวีดีโอใดๆ ได้เลย (อย่างน้อยที่สุดบนเครื่องผม) จริงๆ เรื่องนี้เคยเขียนทางแก้ไปแล้วเมื่อประมาณบล็อกเก่าเมื่อปีถึงสองปีก่อน วันนี้มารื้อฟื้นกันอีกหน่อย

ปัญหานี้ดูสาเหตุได้จากการบังคับเปิด mplayer ด้วย -vo macosx:shared_buffer ในกรณีที่เจอ มันเกิดจากค่า shmall ที่ใช้สำหรับจำกัดขนาดของ shared-memory ที่จะถูก allocate เซ็ทไว้ต่ำไป ที่ 1024 bytes ทางแก้ไขก็ง่ายมาก สั่ง sysctl -w kern.sysv.shmall=4096 เป็นอันเสร็จสิ้น

ถ้าหากอยากให้ค่านี้อยู่ถาวรใน Leopard ก็ทำการเพิ่ม /etc/sysctl.conf ไปว่า


kern.sysv.shmall=4096


เท่านี้ก็หมดปัญหาเรื่องเปิดวีดีโอไม่ได้ไปเปราะหนึ่ง ของแถมอีกอันหนึ่งที่เพิ่งเจอสดๆ ร้อนๆ เลยก็คือ MPlayer OSX Extended ที่เป็น fork ของ MPlayer OSX อีกที เพิ่มฟีเจอร์และปรับปรุงอินเตอร์เฟส [...]]]></description>
			<content:encoded><![CDATA[<p>ปัญหาตลกๆ ที่เกิดกับ <a href="http://mplayerhq.hu/">MPlayer</a> บน Mac OS X มานานแสนนานก็คือเมื่อปรับการแสดงผลเป็น CoreVideo แบบฝังติดกับตัว player มันจะมีปัญหาว่าไม่สามารถเปิดวีดีโอใดๆ ได้เลย (อย่างน้อยที่สุดบนเครื่องผม) จริงๆ เรื่องนี้เคยเขียนทางแก้ไปแล้วเมื่อประมาณบล็อกเก่าเมื่อปีถึงสองปีก่อน วันนี้มารื้อฟื้นกันอีกหน่อย</p>

<p>ปัญหานี้ดูสาเหตุได้จากการบังคับเปิด mplayer ด้วย <code>-vo macosx:shared_buffer</code> ในกรณีที่เจอ มันเกิดจากค่า <code>shmall</code> ที่ใช้สำหรับจำกัดขนาดของ shared-memory ที่จะถูก allocate เซ็ทไว้ต่ำไป ที่ 1024 bytes ทางแก้ไขก็ง่ายมาก สั่ง <code>sysctl -w kern.sysv.shmall=4096</code> เป็นอันเสร็จสิ้น</p>

<p>ถ้าหากอยากให้ค่านี้อยู่ถาวรใน Leopard ก็ทำการเพิ่ม <code>/etc/sysctl.conf</code> ไปว่า</p>

<p><code>
kern.sysv.shmall=4096
</code></p>

<p>เท่านี้ก็หมดปัญหาเรื่องเปิดวีดีโอไม่ได้ไปเปราะหนึ่ง ของแถมอีกอันหนึ่งที่เพิ่งเจอสดๆ ร้อนๆ เลยก็คือ <a href="http://mplayerosx.sttz.ch/">MPlayer OSX Extended</a> ที่เป็น fork ของ MPlayer OSX อีกที เพิ่มฟีเจอร์และปรับปรุงอินเตอร์เฟส แถมด้วย build ของ MPlayer ที่ใหม่และครบพอสมควร</p>

<p>ว่างๆ อยากจะเรียน Objective-C กับ Cocoa มั่ง อยากจะเอา <a href="http://sourceforge.net/projects/xchataqua/">X-Chat Aqua</a> มาทำต่อเอง</p>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/09/fix-for-once/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Secure Your Account!</title>
		<link>http://barg.hitoridake.com/2008/09/secure-your-account/</link>
		<comments>http://barg.hitoridake.com/2008/09/secure-your-account/#comments</comments>
		<pubDate>Tue, 16 Sep 2008 02:17:21 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Wired]]></category>

		<category><![CDATA[Online shopping]]></category>

		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=79</guid>
		<description><![CDATA[จากเรื่อง On the phone โดนถามมาหลายทีว่ามันผิดแปลกอะไรตรงไหน คำตอบก็คือเรื่องความปลอดภัยของข้อมูลสมาชิกในเว็บไซต์ร้านค้าแห่งนั้น ที่ผมคงจะไม่ซื้ออะไรอีกแล้ว

ย้อนความกันก่อนว่าร้านค้าแห่งนี้ มีระบบหนึ่งที่ให้คุณโอนเงินจากธนาคาร (หรือหักจากบัตรเครดิต) ไปเก็บไว้ใน account เพื่อใช้ซื้อของต่อๆ ไป จะได้ไม่ต้องมาลำบากในการโอนเงินบ่อยๆ ซึ่งนั่นก็ดูเป็นเรื่องที่อำนวยความสะดวกสำหรับผู้ที่ไม่มีบัตรเครดิตได้ดี

ปัญหามันอยู่ที่ว่า ร้านค้าแห่งนี้ไม่มีการป้องกันความปลอดภัยของบัญชีสมาชิกผู้ใช้ที่ยินดีจะฝากเงินจำนวนนั้นไปทิ้งไว้ใน account ที่ดีพอนอกจากการใช้ SSL (สำหรับเข้ารหัสข้อมูลที่ส่งระหว่างบราวเซอร์กับเว็บเซิฟเวอร์) ดังนั้นก็หมายถึง นั่นก็คือรหัสผ่านที่ถูกตั้งไว้ในเว็บฯ ไม่มีการเข้ารหัสใดๆ และยังให้พนักงานของร้านเปิดดูได้ตามสะดวกอีกต่างหาก

แล้วปัญหามันคืออะไร ปัญหามันอยู่ที่ว่า ในกรณีที่คุณมีรหัสผ่านเพียงชุดเดียว&#8211;ซึ่งเป็นเรื่องที่ไม่ควร&#8211;และสมัครสมาชิกกับเว็บไซต์แห่งนี้ พนักงานในร้านค้าสามารถเปิดดูอีเมลล์สำคัญๆ ของคุณได้ ผ่านทางรหัสผ่านและอีเมลล์ที่คุณสมัครสมาชิกไว้



หรือถ้าเกิดให้คิดกรณีที่เลวร้ายกว่านั้น สมมติมีคนสามารถเจาะเข้าฐานข้อมูลของร้านค้าแห่งนี้ได้ด้วยวิธีใดก็ตาม เขาจะมีรหัสผ่านของคนนับพันที่เป็นสมาชิกของเว็บไซต์แห่งนี้โดยไม่ต้องลำบากมานั่งแกะรหัสผ่านเอาทีละอัน (ไม่ว่าจะด้วย brute force หรือ rainbow hash)

ในตอนที่สมัคร ผมสารภาพว่าผมไม่ได้อ่านนโยบายด้านความเป็นส่วนตัวของเว็บไซต์แห่งนี้เลย (ไม่มีการพูดถึงตอนที่สมัครด้วยซ้ำ!) ซึ่งหลังจากอ่านแล้วก็พบว่าไม่มีการพูดถึงการเข้ารหัสข้อมูลสมาชิกเลยแม้แต่น้อย หนำซ้ำยังไม่มีการบอกถึงการนำข้อมูลนี้ไปใช้ด้วยซ้ำ ยกเว้นข้อความที่ว่า &#8220;เราจะใช้ข้อมูลนี้เพื่ออำนวยความสะดวกให้แก่สมาชิก&#8221; ซึ่งโดยส่วนตัวก็ยังคิดว่ามันยัง &#8220;ไม่ใช่&#8221; (กรณีว่า ถ้าหากเปิดอ่านอีเมลล์สมาชิก จะถือว่า &#8220;อำนวยความสะดวก&#8221; ได้หรือเปล่า?)

การเก็บรหัสผ่านลงฐานข้อมูลเป็นความบกพร่องด้านความปลอดภัยอย่างรุนแรง ถึงแม้มันจะช่วยเพิ่มความสะดวกให้แก่ลูกค้าในการกู้รหัสผ่านในภายหลัง หนทางเลือกที่สมควรคือใช้ SHA1, MD5 หรืออะไรก็ตาม [...]]]></description>
			<content:encoded><![CDATA[<p>จากเรื่อง <a href="http://barg.hitoridake.com/2008/09/on-the-phone/">On the phone</a> โดนถามมาหลายทีว่ามันผิดแปลกอะไรตรงไหน คำตอบก็คือเรื่องความปลอดภัยของข้อมูลสมาชิกในเว็บไซต์ร้านค้าแห่งนั้น ที่ผมคงจะไม่ซื้ออะไรอีกแล้ว</p>

<p>ย้อนความกันก่อนว่าร้านค้าแห่งนี้ มีระบบหนึ่งที่ให้คุณโอนเงินจากธนาคาร (หรือหักจากบัตรเครดิต) ไปเก็บไว้ใน account เพื่อใช้ซื้อของต่อๆ ไป จะได้ไม่ต้องมาลำบากในการโอนเงินบ่อยๆ ซึ่งนั่นก็ดูเป็นเรื่องที่อำนวยความสะดวกสำหรับผู้ที่ไม่มีบัตรเครดิตได้ดี</p>

<p>ปัญหามันอยู่ที่ว่า ร้านค้าแห่งนี้ไม่มีการป้องกันความปลอดภัยของบัญชีสมาชิกผู้ใช้ที่ยินดีจะฝากเงินจำนวนนั้นไปทิ้งไว้ใน account ที่ดีพอนอกจากการใช้ SSL (สำหรับเข้ารหัสข้อมูลที่ส่งระหว่างบราวเซอร์กับเว็บเซิฟเวอร์) ดังนั้นก็หมายถึง นั่นก็คือรหัสผ่านที่ถูกตั้งไว้ในเว็บฯ ไม่มีการเข้ารหัสใดๆ และยังให้พนักงานของร้านเปิดดูได้ตามสะดวกอีกต่างหาก</p>

<p>แล้วปัญหามันคืออะไร ปัญหามันอยู่ที่ว่า ในกรณีที่คุณมีรหัสผ่านเพียงชุดเดียว&#8211;ซึ่งเป็นเรื่องที่ไม่ควร&#8211;และสมัครสมาชิกกับเว็บไซต์แห่งนี้ พนักงานในร้านค้าสามารถเปิดดูอีเมลล์สำคัญๆ ของคุณได้ ผ่านทางรหัสผ่านและอีเมลล์ที่คุณสมัครสมาชิกไว้</p>

<p><span id="more-79"></span></p>

<p>หรือถ้าเกิดให้คิดกรณีที่เลวร้ายกว่านั้น สมมติมีคนสามารถเจาะเข้าฐานข้อมูลของร้านค้าแห่งนี้ได้ด้วยวิธีใดก็ตาม เขาจะมีรหัสผ่านของคนนับพันที่เป็นสมาชิกของเว็บไซต์แห่งนี้โดยไม่ต้องลำบากมานั่งแกะรหัสผ่านเอาทีละอัน (ไม่ว่าจะด้วย brute force หรือ rainbow hash)</p>

<p>ในตอนที่สมัคร ผมสารภาพว่าผมไม่ได้อ่านนโยบายด้านความเป็นส่วนตัวของเว็บไซต์แห่งนี้เลย (ไม่มีการพูดถึงตอนที่สมัครด้วยซ้ำ!) ซึ่งหลังจากอ่านแล้วก็พบว่าไม่มีการพูดถึงการเข้ารหัสข้อมูลสมาชิกเลยแม้แต่น้อย หนำซ้ำยังไม่มีการบอกถึงการนำข้อมูลนี้ไปใช้ด้วยซ้ำ ยกเว้นข้อความที่ว่า &#8220;เราจะใช้ข้อมูลนี้เพื่ออำนวยความสะดวกให้แก่สมาชิก&#8221; ซึ่งโดยส่วนตัวก็ยังคิดว่ามันยัง &#8220;ไม่ใช่&#8221; (กรณีว่า ถ้าหากเปิดอ่านอีเมลล์สมาชิก จะถือว่า &#8220;อำนวยความสะดวก&#8221; ได้หรือเปล่า?)</p>

<p>การเก็บรหัสผ่านลงฐานข้อมูลเป็นความบกพร่องด้านความปลอดภัยอย่างรุนแรง ถึงแม้มันจะช่วยเพิ่มความสะดวกให้แก่ลูกค้าในการกู้รหัสผ่านในภายหลัง หนทางเลือกที่สมควรคือใช้ <a href="http://en.wikipedia.org/wiki/SHA1">SHA1</a>, <a href="http://en.wikipedia.org/wiki/MD5">MD5</a> หรืออะไรก็ตาม (ยกเว้น <a href="http://en.wikipedia.org/wiki/CRC">CRC</a>!) บวกด้วย <a href="http://en.wikipedia.org/wiki/Salt_(cryptography)">salt</a> &#8211;หรือถ้าให้ดีกว่านั้น ใช้ตัวเลือกที่ดีกว่าอย่าง <a href="http://bcrypt.sourceforge.net/">Bcrypt</a> จะทำให้มั่นใจได้ว่าข้อมูลที่อยู่ในฐานข้อมูลไม่มีใครสามารถอ่านได้</p>

<p>กรณีฐานข้อมูลโดนเจาะเหมือนจะดูเป็นเรื่องไกลตัว แต่ในขณะเดียวกันบางครั้งมันอาจจะอยู่<a href="http://web.archive.org/web/20070109023445/http%3A//reddit.com/blog/theft">ใกล้กว่าที่คิด</a> ถ้าหากต้องการจะ<a href="http://www.reddit.com/comments/usqe/reddits_streak_of_bad_luck_continues/cuugl">แลกความปลอดภัยกับความสะดวก</a> แล้วล่ะก็ยังไงก็ไม่คุ้มกัน ฐานข้อมูลที่รั่วไปครั้งหนึ่งแล้วมันเอากลับมาไม่ได้ โดยเฉพาะเมื่อคุณต้องกุมเงินของสมาชิกทั้งหลายอยู่ในมือ</p>

<p>สำหรับกรณีนี้ ถึงมันจะช่วยให้ผมล็อคอินได้ แต่ผมก็คงไม่ซื้อของจากร้านนี้อีกเด็ดขาด ขนาดรหัสผ่านยังละเลยขนาดนี้ ผมคงไม่เชื่อใจร้านค้าแห่งนี้พอที่จะมอบข้อมูลบัตรเครดิตให้เหมือนกัน</p>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/09/secure-your-account/feed/</wfw:commentRss>
		</item>
		<item>
		<title>On the phone</title>
		<link>http://barg.hitoridake.com/2008/09/on-the-phone/</link>
		<comments>http://barg.hitoridake.com/2008/09/on-the-phone/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 03:04:55 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Social]]></category>

		<category><![CDATA[Journal]]></category>

		<category><![CDATA[Online shopping]]></category>

		<category><![CDATA[What]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=75</guid>
		<description><![CDATA[บทสนทนากับ operator ของเว็บไซต์ร้านค้าออนไลน์ชื่อดังแห่งหนึ่ง


  ร้าน: สวัสดีค่ะ ____ ค่ะ
  ผม: สวัสดีครับ เอ่อ account ผมโดน lock เพราะรหัสผ่านผิดอ่ะครับ
  ร้าน: ขอทราบชื่อ account ด้วยค่ะ
  ผม: ______ ครับ
  ร้าน: เรียบร้อยแล้วค่ะ
  ผม: คือ ผมลืมรหัสผ่าน มีวิธีไหนที่จะ reset ได้บ้างครับ?
  ร้าน: ค่ะ รหัสผ่านที่กรอกไปคืออะไรคะ?
  ผม: (&#8230;?) เอ่อ ผมมีรหัสผ่านอยู่ 7 ชุด แล้วพยายามลองอยู่น่ะครับ ว่าอันไหนใช้สมัคร
  ร้าน: ค่ะ ที่คุณกรอกไปผิดหมดเลย
  ผม: พอมีวิธี [...]]]></description>
			<content:encoded><![CDATA[<p>บทสนทนากับ operator ของเว็บไซต์ร้านค้าออนไลน์ชื่อดังแห่งหนึ่ง</p>

<blockquote>
  <p><strong>ร้าน:</strong> สวัสดีค่ะ ____ ค่ะ<br />
  <strong>ผม:</strong> สวัสดีครับ เอ่อ account ผมโดน lock เพราะรหัสผ่านผิดอ่ะครับ<br />
  <strong>ร้าน:</strong> ขอทราบชื่อ account ด้วยค่ะ<br />
  <strong>ผม:</strong> ______ ครับ<br />
  <strong>ร้าน:</strong> เรียบร้อยแล้วค่ะ<br />
  <strong>ผม:</strong> คือ ผมลืมรหัสผ่าน มีวิธีไหนที่จะ reset ได้บ้างครับ?<br />
  <strong>ร้าน:</strong> ค่ะ รหัสผ่านที่กรอกไปคืออะไรคะ?<br />
  <strong>ผม:</strong> (&#8230;?) เอ่อ ผมมีรหัสผ่านอยู่ 7 ชุด แล้วพยายามลองอยู่น่ะครับ ว่าอันไหนใช้สมัคร<br />
  <strong>ร้าน:</strong> ค่ะ ที่คุณกรอกไปผิดหมดเลย<br />
  <strong>ผม:</strong> พอมีวิธี reset มั๊ยครับ?<br />
  <strong>ร้าน:</strong> รหัสผ่านคุณขึ้นต้นด้วย __ ค่ะ<br />
  <strong>ผม:</strong> (!?) ขอบคุณมากครับ</p>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/09/on-the-phone/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Drupal, Inline and Contemplate</title>
		<link>http://barg.hitoridake.com/2008/09/drupal-inline-and-contemplate/</link>
		<comments>http://barg.hitoridake.com/2008/09/drupal-inline-and-contemplate/#comments</comments>
		<pubDate>Wed, 03 Sep 2008 21:18:21 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Wired]]></category>

		<category><![CDATA[Code]]></category>

		<category><![CDATA[Drupal]]></category>

		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=68</guid>
		<description><![CDATA[ช่วงสัปดาห์ที่ผ่านมา มั่วแต่วุ่นๆ อยู่กับการเปิดเว็บข่าวอนิเมะเอามันส์ หลังจากที่มัวลังเลอยู่หลายเดือน ในที่สุดก็ออกมาเป็นรูปเป็นร่าง ซอฟท์แวร์ที่ใช้ในขณะนี้ก็คือ Drupal พอลองเอามาใช้ดูกับงานแบบนี้แล้วค่อนข้างถูกใจในความยืดหยุ่นของมัน

Plugin ที่ใช้ในการทำหน้าเนื้อหาข่าว หลักๆ ก็คือ Content Template กับตระกูล CCK ทั้งหลาย พร้อมด้วย CSS แบบเถื่อนๆ ลงไปบน template อีกนิดหน่อย (เพราะธีมยังไม่เสร็จดี) ซึ่งผลที่ได้ออกมาก็เป็นที่ค่อนข้างพอใจ

ทีนี้ ปัญหามันก็เกิดขึ้น ปัญหาที่ว่าก็คือเมื่อต้องการจะทำ inline image ลงในบทความ ตัวเลือกโมดูลแรกที่จะมองหาก็คือ Inline โดยที่มันจะสร้าง tag เล็กๆ เช่น [inline:hello.jpg] และจะแทนแทคนี้ด้วยภาพที่เราอัพโหลดลงไป

จุดที่เป็นปัญหาคือส่วน &#8220;แทนภาพ&#8221; ที่ว่านี่ เมื่อมันใช้การเรียกหา $node-&#62;body เพื่อมาแทนภาพ แต่การใช้งาน Content template เราจะไม่ได้ใช้ในส่วนนั้น แต่จะเป็น $node-&#62;content['body']['#value'] แทน เลยเป็นผลทำให้สิ่งที่แสดงออกมาเลยกลายเป็น raw text [inline:hello.jpg] แทนที่จะเป็นภาพ



เมื่อไปขุดคุ้ยโค้ดดู ก็พบว่าการแทนภาพนั่น [...]]]></description>
			<content:encoded><![CDATA[<p>ช่วงสัปดาห์ที่ผ่านมา มั่วแต่วุ่นๆ อยู่กับการเปิด<a href="http://anime.in.th/">เว็บข่าวอนิเมะ</a>เอามันส์ หลังจากที่มัวลังเลอยู่หลายเดือน ในที่สุดก็ออกมาเป็นรูปเป็นร่าง ซอฟท์แวร์ที่ใช้ในขณะนี้ก็คือ <a href="http://drupal.org/">Drupal</a> พอลองเอามาใช้ดูกับงานแบบนี้แล้วค่อนข้างถูกใจในความยืดหยุ่นของมัน</p>

<p>Plugin ที่ใช้ในการทำหน้า<a href="http://anime.in.th/news/2008/09/bakemonogatari-first-anime-illustration-revealed">เนื้อหาข่าว</a> หลักๆ ก็คือ <a href="http://drupal.org/project/contemplate">Content Template</a> กับตระกูล <a href="http://drupal.org/project/cck">CCK</a> ทั้งหลาย พร้อมด้วย CSS แบบเถื่อนๆ ลงไปบน template อีกนิดหน่อย (เพราะธีมยังไม่เสร็จดี) ซึ่งผลที่ได้ออกมาก็เป็นที่ค่อนข้างพอใจ</p>

<p>ทีนี้ ปัญหามันก็เกิดขึ้น ปัญหาที่ว่าก็คือเมื่อต้องการจะทำ inline image ลงในบทความ ตัวเลือกโมดูลแรกที่จะมองหาก็คือ <a href="http://drupal.org/project/inline">Inline</a> โดยที่มันจะสร้าง tag เล็กๆ เช่น <code>[inline:hello.jpg]</code> และจะแทนแทคนี้ด้วยภาพที่เราอัพโหลดลงไป</p>

<p>จุดที่เป็นปัญหาคือส่วน &#8220;แทนภาพ&#8221; ที่ว่านี่ เมื่อมันใช้การเรียกหา <code>$node-&gt;body</code> เพื่อมาแทนภาพ แต่การใช้งาน Content template เราจะไม่ได้ใช้ในส่วนนั้น แต่จะเป็น <code>$node-&gt;content['body']['#value']</code> แทน เลยเป็นผลทำให้สิ่งที่แสดงออกมาเลยกลายเป็น raw text <code>[inline:hello.jpg]</code> แทนที่จะเป็นภาพ</p>

<p><span id="more-68"></span></p>

<p>เมื่อไปขุดคุ้ยโค้ดดู ก็พบว่าการแทนภาพนั่น ทำผ่านฟังก์ชั่นที่ชื่อ <code>_inline_substitute_tags</code> นั่นก็หมายความว่าสามารถเรียกผ่าน Content template ได้เช่นกัน หากแต่เจ้า <code>_inline_substitute_tags</code> นี่มันดันรับเพียงแค่ชื่อ field ที่เป็น <code>string</code> ดังนั้นจึงไม่สามารถเรียกหา <code>content['body']['#value']</code> ได้</p>

<p>ทางแก้แบบป่าเถื่อนที่ใช้จึงกลายเป็น มากำหนดค่าให้แก่ <code>$node-&gt;body_value</code> ให้เป็น <code>$node-&gt;content['body']['#value']</code> เสียก่อน แล้วค่อยเรียก <code>_inline_substitute_tags($node, 'body_value')</code> เอาอีกที ซึ่งผลที่ได้ออกมาก็ได้ตรงตามที่ต้องการ แต่ถ้ามีเวลาอยากจะลองหาทางอื่นที่ไม่ hack-ish แบบนี้ดู น่าจะดีกว่า</p>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/09/drupal-inline-and-contemplate/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mollom meets Pylons, the Mollom Decorator</title>
		<link>http://barg.hitoridake.com/2008/08/mollom-meets-pylons-the-mollom-decorator/</link>
		<comments>http://barg.hitoridake.com/2008/08/mollom-meets-pylons-the-mollom-decorator/#comments</comments>
		<pubDate>Mon, 18 Aug 2008 14:52:53 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Wired]]></category>

		<category><![CDATA[Code]]></category>

		<category><![CDATA[Pylons]]></category>

		<category><![CDATA[Python]]></category>

		<category><![CDATA[Snippets]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=63</guid>
		<description><![CDATA[ทุกวันนี้เรื่องสแปมนับว่าเป็นปัญหาใหญ่มากบนเว็บ การแก้ไขปัญหาที่ดีต้องทำให้มัน transparent ที่สุดเท่าที่จะเป็นได้—ก็คือต้องให้ผู้ใช้สามารถใช้งานเว็บได้ปกติ โดยไม่จำเป็นต้องสนใจว่ามีระบบป้องกันอะไรอยู่ ทางเลือกที่เหลืออยู่จึงกลายเป็นการใช้บริการต่อต้านสแปมอย่าง Akismet หรือ Mollom ที่จะทำให้ผู้ใช้มีส่วนเกี่ยวข้องน้อยที่สุดในกระบวนการ

ส่วนตัวแล้วผมเลือกใช้ Mollom ส่วนหนึ่งเพราะลิมิท API call ไว้สูงที่ 100,000 calls ต่อเดือน และเป็นบริการโดยผู้สร้าง Drupal ส่วนอีกเหตุผลหลักอีกอันหนึ่งก็คือจะใช้สแปมฟิลเตอร์ผสม CAPTCHA อยู่แล้ว ก็เลยไม่ลำบาก ใช้อันที่มีอยู่แล้วไปเลยดีกว่า



เนื่องจากว่าในเว็บ จำเป็นต้องเรียกใช้ Mollom หลายที่มาก ในหลายๆ ส่วนที่ structure ภายในค่อนข้างต่างกันพอสมควร เลยคิดว่าเป็นไอเดียที่ดี ถ้าหากจะทำ Mollom Decorator ขึ้นมาใช้ในกรณีนี้ในรูปแบบนี้


1
2
3
4
5
6
7
@checkspam&#40;content_field='comment'&#41;
def comment_save&#40;self, id&#41;:
    comment = Comment&#40;&#41;
    comment.post_id = id
    comment.content [...]]]></description>
			<content:encoded><![CDATA[<p>ทุกวันนี้เรื่องสแปมนับว่าเป็นปัญหาใหญ่มากบนเว็บ การแก้ไขปัญหาที่ดีต้องทำให้มัน transparent ที่สุดเท่าที่จะเป็นได้—ก็คือต้องให้ผู้ใช้สามารถใช้งานเว็บได้ปกติ โดยไม่จำเป็นต้องสนใจว่ามีระบบป้องกันอะไรอยู่ ทางเลือกที่เหลืออยู่จึงกลายเป็นการใช้บริการต่อต้านสแปมอย่าง <a href="http://akismet.com">Akismet</a> หรือ <a href="http://mollom.com/">Mollom</a> ที่จะทำให้ผู้ใช้มีส่วนเกี่ยวข้องน้อยที่สุดในกระบวนการ</p>

<p>ส่วนตัวแล้วผมเลือกใช้ <a href="http://mollom.com/">Mollom</a> ส่วนหนึ่งเพราะลิมิท API call ไว้สูงที่ 100,000 calls ต่อเดือน และเป็นบริการโดยผู้สร้าง <a href="http://drupal.org/">Drupal</a> ส่วนอีกเหตุผลหลักอีกอันหนึ่งก็คือจะใช้สแปมฟิลเตอร์ผสม <a href="http://en.wikipedia.org/wiki/Captcha">CAPTCHA</a> อยู่แล้ว ก็เลยไม่ลำบาก ใช้อันที่มีอยู่แล้วไปเลยดีกว่า</p>

<p><span id="more-63"></span></p>

<p>เนื่องจากว่าในเว็บ จำเป็นต้องเรียกใช้ Mollom หลายที่มาก ในหลายๆ ส่วนที่ structure ภายในค่อนข้างต่างกันพอสมควร เลยคิดว่าเป็นไอเดียที่ดี ถ้าหากจะทำ Mollom Decorator ขึ้นมาใช้ในกรณีนี้ในรูปแบบนี้</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="python python" style="font-family:monospace;">@checkspam<span style="color: black;">&#40;</span>content_field=<span style="color: #483d8b;">'comment'</span><span style="color: black;">&#41;</span>
<span style="color: #ff7700;font-weight:bold;">def</span> comment_save<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #008000;">id</span><span style="color: black;">&#41;</span>:
    comment = Comment<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
    comment.<span style="color: black;">post_id</span> = <span style="color: #008000;">id</span>
    comment.<span style="color: black;">content</span> = request.<span style="color: black;">POST</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'comment'</span><span style="color: black;">&#41;</span>
    Session.<span style="color: black;">save</span><span style="color: black;">&#40;</span>comment<span style="color: black;">&#41;</span>
    Session.<span style="color: black;">commit</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>


<p>โชคดีที่มี <a href="http://itkovian.net/base/python-wrapper-mollom">Mollom wrapper บน Python</a> อยู่แล้วโดย <a href="http://www.itkovian.net/">Andy Georges</a> ดังนั้นก็พอจะเอามาใช้งานทำ Mollom Decorator ได้เลย โดยไม่ต้องไปวุ่นวายกับ API call อะไรต่อมิอะไรเอง</p>

<p>ก่อนอื่นก็ import Mollom wrapper และสร้าง <code>mollom</code> instance ก่อน ส่วนตัวแล้วผมโยนมันไว้ใน <code>appname/lib/util.py</code></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Mollom wrapper by Andy Georges</span>
<span style="color: #808080; font-style: italic;"># http://itkovian.net/base/python-wrapper-mollom</span>
<span style="color: #ff7700;font-weight:bold;">import</span> Mollom
mollom = MollomAPI<span style="color: black;">&#40;</span>publicKey=<span style="color: #483d8b;">&quot;yourkeyhere&quot;</span>, privateKey=<span style="color: #483d8b;">&quot;yourkeyhere&quot;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>


<p>แล้วก็โยนโค้ดนี่ลงไปที่ไหนซักแห่ง เช่นว่า <code>appname/lib/decorators.py</code></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</pre></td><td class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> decorator <span style="color: #ff7700;font-weight:bold;">import</span> decorator
<span style="color: #ff7700;font-weight:bold;">from</span> pylons <span style="color: #ff7700;font-weight:bold;">import</span> c, request, session
<span style="color: #ff7700;font-weight:bold;">from</span> pylons.<span style="color: black;">templating</span> <span style="color: #ff7700;font-weight:bold;">import</span> render
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> appname.<span style="color: black;">lib</span>.<span style="color: black;">util</span> <span style="color: #ff7700;font-weight:bold;">import</span> mollom
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> checkspam<span style="color: black;">&#40;</span>content_field=<span style="color: #008000;">None</span>, title_field=<span style="color: #008000;">None</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">def</span> wrapper<span style="color: black;">&#40;</span>func, <span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>:
        <span style="color: #ff7700;font-weight:bold;">if</span> mollom:
            session_id = <span style="color: #008000;">None</span>
            title = request.<span style="color: black;">POST</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>title_field, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
            content = request.<span style="color: black;">POST</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span>content_field, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">'HTTP_X_FORWARDED_FOR'</span> <span style="color: #ff7700;font-weight:bold;">in</span> request.<span style="color: black;">environ</span>:
                ipaddr = request.<span style="color: black;">environ</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'HTTP_X_FORWARDED_FOR'</span>, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">else</span>: ipaddr = request.<span style="color: black;">environ</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'REMOTE_ADDR'</span>, <span style="color: #008000;">None</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;mollom_session&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> session:
                session_id = session<span style="color: black;">&#91;</span><span style="color: #483d8b;">'mollom_session'</span><span style="color: black;">&#93;</span>
                <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #483d8b;">&quot;solution&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> request.<span style="color: black;">POST</span>:
                    solution = request.<span style="color: black;">POST</span>.<span style="color: black;">get</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'solution'</span>, <span style="color: #483d8b;">''</span><span style="color: black;">&#41;</span>
                    <span style="color: #ff7700;font-weight:bold;">if</span> mollom.<span style="color: black;">checkCaptcha</span><span style="color: black;">&#40;</span>sessionID=session_id,
                                           solution=solution<span style="color: black;">&#41;</span> == <span style="color: #008000;">True</span>:
                        <span style="color: #ff7700;font-weight:bold;">return</span> func<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
            result = mollom.<span style="color: black;">checkContent</span><span style="color: black;">&#40;</span>sessionID=session_id, authorIP=ipaddr,
                                         postTitle=title, postBody=content<span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #ff7700;font-weight:bold;">not</span> <span style="color: #483d8b;">&quot;mollom_session&quot;</span> <span style="color: #ff7700;font-weight:bold;">in</span> session:
                session_id = result<span style="color: black;">&#91;</span><span style="color: #483d8b;">'session_id'</span><span style="color: black;">&#93;</span>
                session<span style="color: black;">&#91;</span><span style="color: #483d8b;">'mollom_session'</span><span style="color: black;">&#93;</span> = result<span style="color: black;">&#91;</span><span style="color: #483d8b;">'session_id'</span><span style="color: black;">&#93;</span>
                session.<span style="color: black;">save</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> result<span style="color: black;">&#91;</span><span style="color: #483d8b;">'spam'</span><span style="color: black;">&#93;</span> <span style="color: #66cc66;">!</span>= <span style="color: #ff4500;">1</span>:
                <span style="color: #ff7700;font-weight:bold;">if</span> result<span style="color: black;">&#91;</span><span style="color: #483d8b;">'spam'</span><span style="color: black;">&#93;</span> == <span style="color: #ff4500;">3</span>:
                    captcha = mollom.<span style="color: black;">getImageCaptcha</span><span style="color: black;">&#40;</span>sessionID=session_id<span style="color: black;">&#41;</span>
                    c.<span style="color: black;">chance</span> = <span style="color: #008000;">True</span>
                    c.<span style="color: black;">contents</span> = request.<span style="color: black;">POST</span>
                    c.<span style="color: black;">captcha</span> = captcha<span style="color: black;">&#91;</span><span style="color: #483d8b;">'url'</span><span style="color: black;">&#93;</span>
                <span style="color: #ff7700;font-weight:bold;">return</span> render<span style="color: black;">&#40;</span><span style="color: #483d8b;">&quot;/spam.mako&quot;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">return</span> func<span style="color: black;">&#40;</span><span style="color: #008000;">self</span>, <span style="color: #66cc66;">*</span>args, <span style="color: #66cc66;">**</span>kwargs<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">return</span> decorator<span style="color: black;">&#40;</span>wrapper<span style="color: black;">&#41;</span></pre></td></tr></table></div>


<p>แล้วก็สร้าง <code>spam.mako</code> ไว้ใน <code>appname/templates/</code> หน้าตาประมาณนี้</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td class="code"><pre class="mako" style="font-family:monospace;">% if c.chance:
  &lt;form method=&quot;post&quot;&gt;
    &lt;img src=&quot;${c.captcha}&quot; alt=&quot;CAPTCHA&quot; width=&quot;110&quot; height=&quot;50&quot; /&gt;
    ${h.text_field('solution')}
    ${h.submit('Proceed', name='proceed')}
    % for r in c.contents:
      ${h.hidden_field(r, value=c.contents[r])}
    % endfor
  &lt;/form&gt;
% else:
  &lt;p&gt;You're blocked&lt;/p&gt;
% endif</pre></td></tr></table></div>


<p>สุดท้ายก็ไป import มันใน <code>lib/base.py</code></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> appname.<span style="color: black;">lib</span>.<span style="color: black;">decorators</span> <span style="color: #ff7700;font-weight:bold;">import</span> checkspam</pre></td></tr></table></div>


<p>แล้วก็จะสามารถเรียกใช้ใน controller ได้ทันที โดยไม่ต้องเขียนซ้ำไปซ้ำมา พร้อมจัดการเรื่องส่ง IP address กลับไปยัง Mollom ให้เสร็จสรรพ เท่านี้ก็น่าจะ OK</p>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/08/mollom-meets-pylons-the-mollom-decorator/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Sunburst for Emacs</title>
		<link>http://barg.hitoridake.com/2008/08/sunburst-for-emacs/</link>
		<comments>http://barg.hitoridake.com/2008/08/sunburst-for-emacs/#comments</comments>
		<pubDate>Sun, 17 Aug 2008 18:36:17 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Wired]]></category>

		<category><![CDATA[Design]]></category>

		<category><![CDATA[Emacs]]></category>

		<category><![CDATA[English]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=59</guid>
		<description><![CDATA[One of the reasons why I really like TextMate is its exquisite color themes. Nothing else come close. When I first switched to Emacs, I feel everything looks so dull and hard to read.

Half a year passed. I know I can no longer continue to stare on this dull and gloomy window. Fine, let&#8217;s port [...]]]></description>
			<content:encoded><![CDATA[<p>One of the reasons why I really like <a href="http://macromates.com/">TextMate</a> is its exquisite color themes. Nothing else come close. When I first switched to Emacs, I feel everything looks so dull and hard to read.</p>

<p>Half a year passed. I know I can no longer continue to stare on this dull and gloomy window. Fine, let&#8217;s port Sunburst to Emacs.</p>

<p><span id="more-59"></span></p>

<p><img src="http://temp.hitoridake.com/sunburst-emacs-20080818-060404.png" alt="Sunburst-Emacs" /></p>

<p>Nice, isn&#8217;t it? Well, at least to my eyes. Here&#8217;s the code.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="code"><pre class="lisp lisp" style="font-family:monospace;"><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">defun</span> color<span style="color: #66cc66;">-</span>theme<span style="color: #66cc66;">-</span>sunburst <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
  <span style="color: #66cc66;">&#40;</span>interactive<span style="color: #66cc66;">&#41;</span>
  <span style="color: #66cc66;">&#40;</span>color<span style="color: #66cc66;">-</span>theme<span style="color: #66cc66;">-</span>install
   '<span style="color: #66cc66;">&#40;</span>color<span style="color: #66cc66;">-</span>theme<span style="color: #66cc66;">-</span>sunburst
     <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>background<span style="color: #66cc66;">-</span>color . <span style="color: #ff0000;">&quot;#000000&quot;</span><span style="color: #66cc66;">&#41;</span>
      <span style="color: #66cc66;">&#40;</span>foreground<span style="color: #66cc66;">-</span>color . <span style="color: #ff0000;">&quot;#FFFFFF&quot;</span><span style="color: #66cc66;">&#41;</span>
      <span style="color: #66cc66;">&#40;</span>cursor<span style="color: #66cc66;">-</span>color . <span style="color: #ff0000;">&quot;#DAD085&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>default <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">nil</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>modeline <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">background</span> <span style="color: #ff0000;">&quot;DarkRed&quot;</span> :<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;white&quot;</span>
                                :<span style="color: #555;">box</span> <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">line</span><span style="color: #66cc66;">-</span>width <span style="color: #cc66cc;">1</span> :<span style="color: #555;">style</span> released<span style="color: #66cc66;">-</span>button<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>builtin<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#3E87E3&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>comment<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">italic</span> t :<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#AEAEAE&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>constant<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#3387CC&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>doc<span style="color: #66cc66;">-</span>string<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#65B042&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>string<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#99CF50&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>function<span style="color: #66cc66;">-</span>name<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#89BDFF&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>keyword<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#E28964&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>type<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">underline</span> t :<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#89BDFF&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>variable<span style="color: #66cc66;">-</span>name<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#3E87E3&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>font<span style="color: #66cc66;">-</span>lock<span style="color: #66cc66;">-</span>warning<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">bold</span> t :<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#FD5FF1&quot;</span>
                                        :<span style="color: #555;">background</span> <span style="color: #ff0000;">&quot;#562D56&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>py<span style="color: #66cc66;">-</span>decorators<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#3387CC&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>py<span style="color: #66cc66;">-</span>builtins<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#99CF50&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#40;</span>py<span style="color: #66cc66;">-</span>pseudo<span style="color: #66cc66;">-</span>keyword<span style="color: #66cc66;">-</span>face <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>t <span style="color: #66cc66;">&#40;</span>:<span style="color: #555;">foreground</span> <span style="color: #ff0000;">&quot;#3E87E3&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#41;</span>
   <span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></pre></td></tr></table></div>


<p>Put it somewhere in your <code>load-path</code>. I tried to make it look as close as possible, but this is the limit of where I can go for now. At least it&#8217;s usable!</p>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/08/sunburst-for-emacs/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Thailand Next Web Apps 2008</title>
		<link>http://barg.hitoridake.com/2008/08/thailand-next-web-apps-2008/</link>
		<comments>http://barg.hitoridake.com/2008/08/thailand-next-web-apps-2008/#comments</comments>
		<pubDate>Sat, 16 Aug 2008 07:47:12 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Social]]></category>

		<category><![CDATA[Wired]]></category>

		<category><![CDATA[Pylons]]></category>

		<category><![CDATA[Rails]]></category>

		<category><![CDATA[Speak]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=56</guid>
		<description><![CDATA[ไปเป็น speaker ใน Thailand Next Web Apps เป็น session แรกในห้อง 2 ด้วยความที่พูดครั้งแรกเลยประหม่าพอสมควร แต่โดยรวมแล้วก็เป็นไปได้ด้วยดี ไม่เกินเวลา ขอบคุณคุณ Sikachu มากที่ให้โอกาสในการพูดครั้งนี้

เรื่องที่พูดก็เป็นเรื่อง Ruby on Rails กับ Pylons กับปัญหาที่เจอตอนเปิด Akibakko สำหรับคนที่อยากรู้ว่าพูดอะไร น่าจะมีวีดีโอออกมาในภายหลัง

เนื่องจากตื่นเต้นพอสมควร การเตรียมพร้อมอะไรเลยมีปัญหาเล็กน้อย ตั้งแต่ไปเป๋อนั่งในห้อง 1 อยู่พักนึงกว่าจะได้รู้ว่านั่งผิดห้อง หรือลืมพกเอา DVI converter มา (ขอบคุณท่านที่ให้ผมยืมมาก!) และสาย projector เสียบไม่แน่น เสียเวลาไปกว่า 10 นาที

สำหรับสไลด์ที่ใช้ อัพโหลดเป็น PDF ไว้เรียบร้อยแล้ว สามารถโหลดได้: from Rails to Pylons ขอบคุณทุกท่านที่ให้ความสนใจฟังมากครับ!
]]></description>
			<content:encoded><![CDATA[<p>ไปเป็น speaker ใน <a href="http://nextwebapps.com/th">Thailand Next Web Apps</a> เป็น session แรกในห้อง 2 ด้วยความที่พูดครั้งแรกเลยประหม่าพอสมควร แต่โดยรวมแล้วก็เป็นไปได้ด้วยดี ไม่เกินเวลา ขอบคุณคุณ <a href="http://sikachu.com/">Sikachu</a> มากที่ให้โอกาสในการพูดครั้งนี้</p>

<p>เรื่องที่พูดก็เป็นเรื่อง Ruby on Rails กับ Pylons กับปัญหาที่เจอตอนเปิด <a href="http://akibakko.net/">Akibakko</a> สำหรับคนที่อยากรู้ว่าพูดอะไร น่าจะมีวีดีโอออกมาในภายหลัง</p>

<p>เนื่องจากตื่นเต้นพอสมควร การเตรียมพร้อมอะไรเลยมีปัญหาเล็กน้อย ตั้งแต่ไปเป๋อนั่งในห้อง 1 อยู่พักนึงกว่าจะได้รู้ว่านั่งผิดห้อง หรือลืมพกเอา DVI converter มา (ขอบคุณท่านที่ให้ผมยืมมาก!) และสาย projector เสียบไม่แน่น เสียเวลาไปกว่า 10 นาที</p>

<p>สำหรับสไลด์ที่ใช้ อัพโหลดเป็น PDF ไว้เรียบร้อยแล้ว สามารถโหลดได้: <a href="http://temp.hitoridake.com/rails-pylons.pdf">from Rails to Pylons</a> ขอบคุณทุกท่านที่ให้ความสนใจฟังมากครับ!</p>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/08/thailand-next-web-apps-2008/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Declarative again</title>
		<link>http://barg.hitoridake.com/2008/08/declarative-again/</link>
		<comments>http://barg.hitoridake.com/2008/08/declarative-again/#comments</comments>
		<pubDate>Sat, 09 Aug 2008 09:44:59 +0000</pubDate>
		<dc:creator>Sirn</dc:creator>
		
		<category><![CDATA[Wired]]></category>

		<category><![CDATA[Code]]></category>

		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://barg.hitoridake.com/?p=49</guid>
		<description><![CDATA[เขียนเรื่อง declarative plugins ไปเมื่อ entry ก่อน หลังจากผ่านไปหลายสัปดาห์ ในที่สุด model ใหม่ที่ใช้งาน declarative plugins ก็ถูกใช้งานจริงอย่างไม่มีปัญหาใดๆ แต่การเปลี่ยนจากวิธี mapper ปกติไปเป็น declarative ไม่ได้ราบรื่นอย่างที่คิด (ถ้าหากใช้แต่แรกคงสบาย)

ปัญหาที่เจอส่วนหนึ่งคือ circular import ใน Python (คือ import class ก่อนที่มันจะถูกสร้างขึ้น) ที่ถึงแม้การรับ string ใน relation() จะช่วยเรื่องนี้ได้พอสมควร แต่ก็ไม่ช่วยในทุกกรณี เช่นกรณีที่ต้องทำตารางแบบ Many-to-Many หรือการสร้าง UNIQUE constraint กับสองคอลัมน์



Many-to-Many

การทำ Many-to-Many นั้น จำเป็นต้องสร้างตารางใหม่เพื่อเป็นจุดเชื่อมต่อระหว่างตาราง A และ B ใน สำหรับ SQLAlchemy เราจะระบุ secondary ลงไปที่ relation() เพื่อบอกว่าจะใช้ตารางไหนในการเชื่อม จากตัวอย่าง user [...]]]></description>
			<content:encoded><![CDATA[<p>เขียนเรื่อง <a href="http://www.sqlalchemy.org/docs/04/plugins.html#plugins_declarative">declarative plugins</a> ไปเมื่อ <a href="/2008/07/declarative-declarative/">entry ก่อน</a> หลังจากผ่านไปหลายสัปดาห์ ในที่สุด model ใหม่ที่ใช้งาน declarative plugins ก็ถูกใช้งานจริงอย่างไม่มีปัญหาใดๆ แต่การเปลี่ยนจากวิธี mapper ปกติไปเป็น declarative ไม่ได้ราบรื่นอย่างที่คิด (ถ้าหากใช้แต่แรกคงสบาย)</p>

<p>ปัญหาที่เจอส่วนหนึ่งคือ circular import ใน Python (คือ import class ก่อนที่มันจะถูกสร้างขึ้น) ที่ถึงแม้การรับ string ใน <code>relation()</code> จะช่วยเรื่องนี้ได้พอสมควร แต่ก็ไม่ช่วยในทุกกรณี เช่นกรณีที่ต้องทำตารางแบบ <a href="http://en.wikipedia.org/wiki/Many-to-many_(data_model)">Many-to-Many</a> หรือการสร้าง <code>UNIQUE constraint</code> กับสองคอลัมน์</p>

<p><span id="more-49"></span></p>

<h3>Many-to-Many</h3>

<p>การทำ <a href="http://en.wikipedia.org/wiki/Many-to-many_(data_model)">Many-to-Many</a> นั้น จำเป็นต้องสร้างตารางใหม่เพื่อเป็นจุดเชื่อมต่อระหว่างตาราง A และ B ใน สำหรับ <a href="http://www.sqlalchemy.org/">SQLAlchemy</a> เราจะระบุ <code>secondary</code> ลงไปที่ <code>relation()</code> เพื่อบอกว่าจะใช้ตารางไหนในการเชื่อม จากตัวอย่าง user table ในคราวที่แล้ว เปลี่ยนจาก group เป็น roles จะออกมาหน้าตาแบบนี้</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> User<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    __tablename__ = <span style="color: #483d8b;">'users'</span>
&nbsp;
    <span style="color: #008000;">id</span> = Column<span style="color: black;">&#40;</span>Integer<span style="color: black;">&#41;</span>
    name = Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#41;</span>
    password = Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#41;</span>
    group_id = Column<span style="color: black;">&#40;</span>Integer, ForeignKey<span style="color: black;">&#40;</span><span style="color: #483d8b;">'groups.id'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Role<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    __tablename__ = <span style="color: #483d8b;">'roles'</span>
&nbsp;
    <span style="color: #008000;">id</span> = Column<span style="color: black;">&#40;</span>Integer<span style="color: black;">&#41;</span>
    name = Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#41;</span>
&nbsp;
    users = relation<span style="color: black;">&#40;</span><span style="color: #483d8b;">'User'</span>, secondary=UserRole.__table__<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> UserRole<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    __tablename__ = <span style="color: #483d8b;">'users_roles'</span>
&nbsp;
    user_id = Column<span style="color: black;">&#40;</span>Integer, primary_key=<span style="color: #008000;">True</span>, ForeignKey<span style="color: black;">&#40;</span><span style="color: #483d8b;">'users.id'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    role_id = Column<span style="color: black;">&#40;</span>Integer, primary_key=<span style="color: #008000;">True</span>, ForeignKey<span style="color: black;">&#40;</span><span style="color: #483d8b;">'roles.id'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>


<p>จากตัวอย่างนี้แก้เรื่อง circular import ง่ายๆ ด้วยการย้าย <code>UserRole</code> ขึ้นไปไว้ข้างบนสุด แต่วิธีนี้ก็ใช้ไม่ได้เสมอไป โดยเฉพาะสำหรับตารางที่ซับซ้อนกว่านี้ ในกรณีนั้น เราสามารถสร้าง <code>relation</code> หลังจากสร้าง class แล้วก็ได้</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> User<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    __tablename__ = <span style="color: #483d8b;">'users'</span>
&nbsp;
    <span style="color: #008000;">id</span> = Column<span style="color: black;">&#40;</span>Integer<span style="color: black;">&#41;</span>
    name = Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#41;</span>
    password = Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#41;</span>
    group_id = Column<span style="color: black;">&#40;</span>Integer, ForeignKey<span style="color: black;">&#40;</span><span style="color: #483d8b;">'groups.id'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> Role<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    __tablename__ = <span style="color: #483d8b;">'roles'</span>
&nbsp;
    <span style="color: #008000;">id</span> = Column<span style="color: black;">&#40;</span>Integer<span style="color: black;">&#41;</span>
    name = Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">class</span> UserRole<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    __tablename__ = <span style="color: #483d8b;">'users_roles'</span>
&nbsp;
    user_id = Column<span style="color: black;">&#40;</span>Integer, primary_key=<span style="color: #008000;">True</span>, ForeignKey<span style="color: black;">&#40;</span><span style="color: #483d8b;">'users.id'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    role_id = Column<span style="color: black;">&#40;</span>Integer, primary_key=<span style="color: #008000;">True</span>, ForeignKey<span style="color: black;">&#40;</span><span style="color: #483d8b;">'roles.id'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
User.<span style="color: black;">roles</span> = relation<span style="color: black;">&#40;</span>Role, secondary=UserRole.__table__<span style="color: black;">&#41;</span>
Role.<span style="color: black;">users</span> = relation<span style="color: black;">&#40;</span>User, secondary=UserRole.__table__<span style="color: black;">&#41;</span></pre></td></tr></table></div>


<p>ถึงแม้วิธีนี้จะใช้งานได้กับทุกกรณี แต่ก็จะมีปัญหาใหม่มาว่าโค้ดจะไม่อยู่ที่เดียวกัน เพิ่มความยุ่งยากในการดูแลขึ้นไปอีกเล็กน้อย แต่ถ้าจะให้ยกตัวอย่างกรณีที่การย้าย <code>UserRole</code> ไม่สามารถทำได้ ก็น่าจะเป็นกรณีการใช้งาน <code>column_property</code> ประเภทนี้</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
</pre></td><td class="code"><pre class="python python" style="font-family:monospace;">count = column_property<span style="color: black;">&#40;</span><span style="color: #dc143c;">select</span><span style="color: black;">&#40;</span><span style="color: black;">&#91;</span>func.<span style="color: black;">count</span><span style="color: black;">&#40;</span>User.__table__.<span style="color: black;">c</span>.<span style="color: #008000;">id</span><span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>


<p>ของจริงน่าจะยุ่งยากกว่านี้อีกนิดหนึ่ง แต่ถ้าหากต้องสร้าง <code>count</code> แบบนี้ทั้งใน <code>User</code> และ <code>Role</code> ก็เป็นที่แน่นอนว่าไม่สามารถสลับที่อยู่ของทั้งสอง class สำหรับกรณีนี้ได้</p>

<h3>Constraint</h3>

<p>ปัญหาต่อมา เนื่องจากว่าเจ้า declarative เนี่ย มันถูกสร้างมาเพื่อทำงานพื้นฐานที่ค่อนข้างจะซ้ำซาก ในกรณีที่ตารางมีความซับซ้อนขึ้นมาอีกนิด เช่นการสร้าง <code>UNIQUE</code> constraint บนหลายคอลัมน์ ที่จะต้องใช้ <code>UniqueConstraint</code> ก็จะไม่สามารถใช้งาน declarative ตามวิธีปกติได้ จากตัวอย่าง</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
</pre></td><td class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Product<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    __tablename__ = <span style="color: #483d8b;">'products'</span>
&nbsp;
    <span style="color: #008000;">id</span> = Column<span style="color: black;">&#40;</span>Integer, primary_key=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>
    name = Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#40;</span><span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
    manufacturer = Column<span style="color: black;">&#40;</span>String<span style="color: black;">&#40;</span><span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    UniqueConstraint<span style="color: black;">&#40;</span><span style="color: #483d8b;">'name'</span>, <span style="color: #483d8b;">'manufacturer'</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>


<p>ในกรณีนี้ <code>UniqueConstraint</code> จะไม่ทำงาน เพราะข้อจำกัดของ declarative ดังนั้นจึงต้องกลับไปใช้ table construct แบบเดิม แต่ในกรณีนี้ เราไม่จำเป็นต้องไปสร้าง mapper ให้วุ่นวาย เพราะสามารถเรียกใช้ <code>Table()</code> บน <code>__table__</code> ใน class ได้เลย</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="python python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">class</span> Product<span style="color: black;">&#40;</span>Base<span style="color: black;">&#41;</span>:
    __table__ = Table<span style="color: black;">&#40;</span><span style="color: #483d8b;">'products'</span>, Base.<span style="color: black;">metadata</span>,,
                      Column<span style="color: black;">&#40;</span><span style="color: #483d8b;">'id'</span>, Integer, primary_key=<span style="color: #008000;">True</span><span style="color: black;">&#41;</span>,
                      Column<span style="color: black;">&#40;</span><span style="color: #483d8b;">'name'</span>, String<span style="color: black;">&#40;</span><span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
                      Column<span style="color: black;">&#40;</span><span style="color: #483d8b;">'manufacturer'</span>, String<span style="color: black;">&#40;</span><span style="color: #ff4500;">255</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
&nbsp;
                      UniqueConstraint<span style="color: black;">&#40;</span><span style="color: #483d8b;">'name'</span>, <span style="color: #483d8b;">'manufacturer'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span></pre></td></tr></table></div>


<p>และยังได้รับผลประโยชน์อีกเล็กน้อยจากการใช้ declarative ตามปกติ</p>

<hr />

<p>ส่วนตัวผมคิดว่า SQLAlchemy นี่มันทรงพลังมาก และอาจจะมากเกินไป จนทำให้ learning curve มันชันจนน่ากลัว หลายๆ คนอาจจะชอบวิธีที่ ActiveRecord ทำงานมากกว่า และผมก็เห็นด้วยว่ามันสะอาดกว่าจริงๆ ดังนั้นการใช้งาน <a href="http://elixir.ematia.de/">Elixir</a> ก็คงจะเป็นตัวเลือกที่ไม่เลวเหมือนกัน</p>
]]></content:encoded>
			<wfw:commentRss>http://barg.hitoridake.com/2008/08/declarative-again/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
