Saturday, June 03, 2006

CellMode

CellMode เป็น emacs mode ที่หน้าตาดูเหมือน spreadsheet



concept การทำงานของมัน ก็คือ value ที่อยู่ใน cell จะ flow ไปในทิศทาง ขวา และ ล่าง
และมี cell พิเศษที่เป็น processing ซึ่งรับ input จาก cell ที่อยู่บน หรือ ซ้าย ของมัน
ผลลัพท์ที่ได้ ก็ feed ให้กับ cell ด้านล่าง และ ด้านขวา ของตน

ผมก็เลยลองเขียน hello world ฉบับ cellmode ขึ้นมา



โดยถ้าเรา click ที่ cell click จะเกิดการ
run คำสั่ง echo 'helloworld' > /tmp/pok.txt
ให้สังเกตว่ามีการส่งข้อมูลผ่านตัวแปร greeting ด้วย
Note: ส่วนที่เป็นสีเทา ก็คือการ print cell value ออกมาดู,
ส่วนคำสั่ง cons ก็คือการ append item กับ array

สนุกดี จากการพยายามทำความเข้าใจว่ามันคืออะไร
และใช้อย่างไร (มั่วอยู่นาน)

Related link from Roti

TestNG in Maven2

ช่วงนี้อยู่ในช่วง kickoff project ตัวใหม่อยู่
โปรเจคนี้ผมตัดสินใจใช้ Framework, Library Release ใหม่ทั้งหมด
รวมทั้งขยับขึ้นไปใช้ jdk1.5

ศึกแรกที่ต้องเจอ ก็คือ Maven2 กับ TestNG
ตัว TestNG เคยเขียนไปแล้วที่ post นี้ Link
(ผ่านมาปีหนึ่งแล้ว พึ่งได้ใช้จริงๆจังๆ)

ใน maven2 เราสามารถใช้ TestNG ได้เลย (Out of a box)
โดยมีสิ่งที่ต้องทำดังนี้
  • เพิ่ม dependency เข้าไปดังนี้
        <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>4.7</version>
    <scope>test</scope>
    <classifier>jdk15</classifier>
    </dependency>

  • ระบุว่าต้องการใช้ Jdk1.5 ในการ compile
     <build> 
    <plugins>
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.0</version>
    <configuration>
    <source>1.5</source>
    <target>1.5</target>
    </configuration>
    </plugin>
    </plugins>
    </build>



จากนั้นเมื่อต้องการ run test ก็แค่
mvn test


ดูง่ายๆเลย
ทลลอง run ดู ปรากฎว่า run test ไม่ผ่าน
เปลี่ยนไป run ใน eclipse ด้วย plugin ของ TestNG
อ้าว ผ่านแฮะ

error ที่ปรากฎ

-------------------------------------------------------
T E S T S
-------------------------------------------------------
[surefire] Running pok.MyTest
[surefire] Tests run: 1, Failures: 1, Errors: 0, Time elapsed: 0.072 sec <<<<<<<< FAILURE !!

Results :
[surefire] Tests run: 1, Failures: 1, Errors: 0

ที่หนักว่านั้นก็คือ เมื่อทดลอง copy ไป run บน Linux box บ้าง
(เดิม run บน Mac)
ผลที่ได้

-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running pok.MyTest
Tests run: 0, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.056 sec

Results :
Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

ไม่ error แต่ ไม่ run
อย่างนี้ก็แสดงว่า Surefire
(plugin ของ Maven ที่รับผิดชอบในเรื่่อง Testing)
ต้องการให้เราระบุ สิ่งที่ต้องการจะ run ด้วย
ซึ่งทำได้โดยการเพิ่ม Suite file เข้าไปอีก 1 file
เพื่อระบุสิ่งที่ต้องการ run
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="Suite1" verbose="1" >
<test name="Domain" >
<packages>
<package name="pok.*" />
</packages>
</test>
</suite>

และระบุเพิ่มใน pom ดังนี้
      <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>


ส่วนใน Mac ผมลองลบ repository ของ maven ทิ้ง
สั่งทำงานใหม่ (มันก็จะ load repository มาให้ใหม่)
อาหารหายเป็นปลิดท้ิง
แสดงว่ามีปัญหาเรื่อง version ของ jar file ที่ download มา

เฮ้อ เกือบถอดใจหันกลับไปใช้ JUnit กับ maven1.x เหมือนเดิมแล้วสิ

Related link from Roti

Thursday, June 01, 2006

ปัญหาการเปลี่ยน user ใน subclipse

Subclipse เป็น Plugin ที่ integrate Subversion เข้ากับ Eclipse
วันนี้น้องใหม่ที่บริษัทดันไปใช้ user กับ password ของคนอื่น commit งานเข้าไป
แล้วดันเลือก choice "remember password" ไว้
แต่ปัญหาก็คือ Subclipse ไม่มี menu หรือ dialog ที่ไว้ใช้เปลี่ยน user

ผมก็เริ่มด้วยการมองหา file ที่เก็บ password ก่อน
หลังจากเดาว่า file .keyring นี่แหล่ะ ชื่อมันเหมาะดี ลบทิ้งซะ
ไม่หายแฮะ
เปลี่ยน workspace ใหม่, checkout ออกมาใหม่
มันก็ยังจำ password ตัวเก่าอยู่
ลบ configuration ทั้งหมดใน eclipse installation ทิ้ง
เอ๊ะ มันก็ยังดันจำได้อีก

เข้าไปค้นใน window registry ก็หาไม่เจอ

หลังจากค้นใน net อยู่พักใหญ่
ก็เลยได้ความมาว่า Subclipse มัน delegate งานไปให้
Client Adapter ทำงาน ซึ่ง Adapter มีอยู่ 2 แบบคือ
  • JavaSVN อันนี้เป็น pure Java
  • JavaHL อันนี้ใช้ Native Library ทำงาน

ตามไปอ่านเอกสารของทั้งสองอันแล้ว ก็ยังไม่ได้เรื่อง
เกือบจะ download source code มานั่งไล่แล้ว
แต่นึกวิธีง่ายสุดๆขึ้นมาได้เสียก่อน

วิธีที่ง่ายที่สุดก็คือไปเปลี่ยน password บน server เสีย
พอ subclipse เจอว่ามีการเปลี่ยน password
มันก็จะ prompt ขึ้นมาให้ใส่ user, password ใหม่

เฮ้อ..

Related link from Roti

Wednesday, May 31, 2006

Yaws vs. Apache

วันก่อนที่พูดถึง Erlang ไป
ซึ่งได้ยกตัวอย่างการ implement server push
โดยใช้ Yaws เป็น Web Server
และได้บอกไว้ว่า performance ของ Yaws สูสี กับ apache

ที่ตอนนั้นบอกเช่นนั้น ก็เพราะได้ทดลองทำ load testing ง่ายๆ เทียบกันระหว่าง apache กับ yaws
แต่เนื่องจากมีเครื่องเดียว ก็เลย simulate load ได้ไม่เยอะ
ก็เลยไม่เห็นความแตกต่าง

วันนี้อ่านเจอ บทความที่เขา test Apache vs. Yaws
แบบจริงๆจังๆ ใช้เครื่อง 16 เครื่อง simulate load
ก็เลยรู้ว่า Yaws รับ load ได้มากกว่า apache เยอะเลย

ตรง comment เขาบอกไว้ว่า
The problem with Apache is not related to the Apache code per se but is due to the manner in which the underlying operating system (Linux) implements concurrency. We believe that any system implemented using operating system threads and processes would exhibit similar performance. Erlang does not make use of the underlying OS's threads and processes for managing its own process pool and thus does not suffer from these limitations.

Related link from Roti

Ice Lens

Matthew Wheeler
photographing the natural beauty of his surroundings through the ice lenses he made.


Related link from Roti

Operator And, Or -- Haskell vs. Java

ผมชอบความรู้สึกประหลาดใจ เวลาเรียนรู้ Haskell
หรือพวก Functional Language ทั้งหลาย
ก็คือเราจะเจอแนวคิดบางอย่างที่เราไม่เคยคิดมาก่อน
อย่างวันนี้เจอ วิธีการ define operator && (and)
กับ operator || (or) ของ Haskell
-- define Type --
-- operator นี้รับ parameter เป็น boolean, boolean
-- และ return เป็น type boolean
(&&), (||) :: Bool -> Bool -> Bool

False && x = False
True && x = x
False || x = x
True || x = True

จะเห็นว่ามีการใช้ Pattern Matching เข้ามาใช้
x ก็คือ Any Value

เทียบกับพวก imperative language
ในที่นี้จะยกตัวอย่าง Java แล้วกัน
เวลานึกถึง operator พวกนี้ (and ,or) ว่า compiler จะแปลงมันอย่างไร
มันจะลงเอยไปที่ระดับ assembly
ที่จะมี compare กับการ jump
ลองดูประโยคนี้ข้อง java
return x && y;

เมื่อแปลงเป็น byte code
   L0 (0)
LINENUMBER 5 L0
ILOAD 1: x # load ค่าใน local var ขึ้น operand stack
IFEQ L1 # ถ้าเป็น 0 กระโดดไป L1
ILOAD 2: y
IFEQ L1
ICONST_1 # return true
IRETURN
L1 (7)
ICONST_0 # return false
IRETURN

Related link from Roti

Monday, May 29, 2006

Conkeror

Conkeror คือ Firefox extension
ที่จะช่วยให้เราใช้ Firefox โดยไม่ต้องแตะ mouse เลย
ลองดู www.google.com ที่ load ขึ้นมาด้วย Conkeror



อยากกด link ไหน ก็ใส่ตัวเลขลงไปได้เลย

keyboard binding ของ Conkeror เดินตามรอย Emacs ทุกอย่าง
ไม่ว่าจะเป็น C-x,C-f เพื่อเปิด url
C-x-b เพื่อ switch buffer

ใครเบื่อ mouse ก็ลองเอาไปเล่นดู

Related link from Roti

Sunday, May 28, 2006

Rails Memo #3

ความเดิม


วันนี้จะว่าด้วยเรื่อง Ruby บ้าง
(เนื่องจาก Rails ใช้ Ruby ดังนั้นจึงหลีกไม่พ้น ที่เราต้องเรียนรู้ syntax ของ ruby)

หัวข้อที่หลายคนสับสนในตอนเรียน Rails
ก็คือ การเรียกใช้ method ของ Model จาก controller
เช่น สมมติเรามีหน้าจอที่แสดงสินค้าทั้งหมดที่เรามี

ในฝั่ง controller ก็จะเขียนประมาณนี้
def index
@products = Product.find(:all)
end

Product ที่เห็นใน code ก็คือ ชื่อของ Class ที่เราประกาศเป็น model ไว้
ส่วน find ก็คือ class method ของ Product

class method ก็คือ method ที่เรียกใด้จาก Class ตรงๆ
ส่วน instance method ก็คือ method ที่เรียกจาก object
ลองดูตัวอย่าง
class Dog  
def initialize(name)
@name = name
end

def say
"hong"
end

def Dog.myDog()
Dog.new("bogy")
end
end

ในตัวอย่างข้างบน method say ก็คือ instance method
ส่วน method myDog ก็คือ class method
เวลา run ก็จะเป็นแบบนี้
irb(main):033:0> d = Dog.myDog
#<Dog:0x58f14 @name="bogy">
irb(main):034:0> d.say
"hong"


Syntax ของ ruby กำหนดไว้ว่า
ชื่อ class ต้องขึ้นต้นด้วยตัวใหญ่
ส่วนชื่อ method ไม่ได้บังคับ แต่ส่วนใหญ่นิยมใช้ตัวเล็ก

ส่วน Syntax ของการประกาศ class method
มีทั้งหมด 4 แบบใหญ่ๆ
อ่านได้ในเอกสาร ClassMethods
(อ่านถึงตรงนี้ แฟนๆ python คงโห่กันใหญ่แล้ว
อะไรกัน simple แค่นี้ ทำไมต้องเขียนได้ตั้ง 4 วิธี)

Related link from Roti

Erlang

หนึ่งในคำแนะนำของบทความ Teach Yourself Programming in Ten Years
ก็คือ
Learn at least a half dozen programming languages. Include one language that supports class abstractions (like Java or C++), one that supports functional abstraction (like Lisp or ML), one that supports syntactic abstraction (like Lisp) ...

เนื่องจากผมยังรู้ไม่ครบ 6 ภาษา
Erlang ก็เลยเป็นหนึ่งในภาษาที่ผมสนใจ
เพราะคิดว่าน่าจะสามารถนำมาประยุกต์กับงานที่ทำอยู่ได้ (server side)
เนื่องจาก Erlang มีชื่อเสียงในด้าน Concurrency, Distribution, Soft real-time
(อ่านโฆษณาของเขาได้ใน White Paper)

วิธีที่ดีที่สุดในการเรียนรู้ภาษาใหม่ก็คือ
การหาตัวอย่างการใช้งานจริง ที่เรารู้วิธี implement อยู่ก่อนแล้ว
ตัวอย่างที่ผมใช้สำหรับการเรียน Erlang ครั้งแรกก็คือ
Pushing events to the browser via Ajax
จาก blog BLUISH CODER
ซึ่งเป็นตัวอย่างการของใช้ long-lived ajax connection
มา implement server push

ตัวอย่างของเขา เขาใช้ yaws เป็น server
yaws ย่อมาจาก "Yet Another WebServer"
เป็น server ที่เขียนด้วย Erlang
โดยออกแบบมา เพื่อให้ serve dynamic page ที่เขียนด้วย Erlang
แต่การตอบสนองต่อ static page ก็ทำได้ดีมากเลย
(ไม่แพ้ apache)

มาลองดูตัว code กัน
(ขอแนะนำว่าให้ใช้ เอกสาร document-part-1 อ่านประกอบไปด้วย)
ในตัวอย่างที่ download มา เขาจะเริ่มต้นด้วยการ start process ขึ้นมา 2 process
process แรกทำหน้าที่ generate random page id เพื่อใช้จำแนก page ที่ต่อเข้ามายัง server
ส่วน process ที่สอง ทำหน้าที่เป็น register process
ที่ใช้ลงทะเบียนว่า ตอนนี้มี page ไหนกำลังต่อมาที่ server อยู่บ้าง
%% Start all processes used by this module.
start() ->
register(page_registry, spawn(html_rpc, page_registry, [[]])),
register(random_name, spawn(html_rpc, random_name, [])).

Note: คำสั่ง spawn ก็คือการแตก process ออกมา
ผลลัพท์ที่ได้จากคำสั่ง spawn ก็คือ pid (process id)
จะถูก map เข้ากับ naming ผ่านทางคำสั่ง register
การที่เราต้อง map เลข pid เข้ากับ name ก็เพื่อให้สะดวกต่อการ
ติดต่อกับ process นั้นๆ


การทำงานเริ่มจาก user request ขอหน้าจอหลักเข้ามา
เราก็จะทำการ generate page_id แปะกลับไปด้วย
<html>
<head>
<title>html_rpc Test1</title>
<script type="text/javascript" src="html_rpc.js"></script>
</head>
<body>
<script type="text/javascript">
<erl>
# out เป็นชื่อ function ที่ใช้ output ผลลัพท์ (เหมือนพวก System.out, Writer, หรือพวก output stream ใน java)
# แต่อันนี้เขียนใน style ของ callback
# ก็คือ yaws จะเรียกใช้ out เมื่อต้องการผลลัพท์
out(A) ->
Name = html_rpc:get_random_name(),
# เก็บตัวแปรไว้ใน scope ของ Page
# เพื่อที่ dynamic block อื่นๆ จะสามารถใช้ ตัวแปรนี้ได้
put(page_name, Name),
{html, "var page = '" ++ Name ++ "';"}.
</erl>
function process_message(message) {
message()
}
html_rpc_receive("ajax1.yaws?page="+page, process_message);
</script>

Note: วิธีการเขียน dynamic html page
ของ yaws ก็เหมือนด้วย jsp หรือ rhtml
นั่นคือมีลักษณะเป็น template


เมื่อ browser ได้รับ page แล้ว ก็จะเกิดการ evaluate javascript
ซึ่งจะทำการ call กลับมายัง browser ผ่านทาง XmlHttpRequest
โดยมีการ pass ค่า page id มาด้วย

ที่ฝั่ง server เมื่อได้รับ request ของ ajax มา
ก็จะแตก process ออกมาอีก เพื่อรองรับ request นั้นๆ

<erl>
out(A) ->
# เริ่มด้วยการ get request parameter ที่ pass มาจาก browser
# เก็บไว้ในตัวแปรชื่อ Page
{ok,Page} = queryvar(A, "page"),
# เรียกใช้ function start_ajax_handler ใน module html_rpc
# โดย pass function handler ไปด้วย (callback function)
html_rpc:start_ajax_handler(Page, fun(A,B,C) -> handler(A,B,C) end).

# function นี้จะทำการ generate javascript ส่งกลับไปยัง browser
handler(Yaws_Pid, Page, Message) ->
case Message of
{alert, Value} ->
"function() { alert('" ++ Value ++ "'); }"
end.

</erl>

ตามไปดู function start_ajax_handler
start_ajax_handler(Page, Callback) ->
# เก็บค่า pid ของตัวเองไว้ใน variable Yaws_Pid
Yaws_Pid = self(),
# แตก process อีกแล้ว โดยเรียกใช้ anonymous function
spawn(fun() ->
# ส่ง message ไปยัง process ที่ register ไว้ในชื่อ page_registry
# โดย pass tuple ที่มี name 'add' , process id ของตัวเอง
# เครื่องหมาย ! เป็น syntax ที่ใช้ในการส่ง message ไปยัง process
page_registry ! {add, Page, self()},
# เรียกใช้ function ที่ทำหน้าที่รับ message ที่ส่งมาให้ process นี้
ajax_handler(Yaws_Pid, Page, Callback)
end),
# อันนี้คือ ผลลัพท์ที่ตอบกลับไปยัง browser เลยทันที (เนื่องจากคำสั่ง spawn มันจะ return กลับมาทันที
[{header, {cache_control, "no-cache"}},
{streamcontent, "text/html", "[ "}].

หน้าตาของ function ajax_handler ที่ทำหน้ารอรับ message ที่จะ push กลับไปยัง browser
ajax_handler(Yaws_Pid, Page, Callback) ->
# receive เป็นการ lookup message queue ของตัวเอง
receive
# ถ้ามี message ที่ชื่อ stop ก็ให้หยุดการทำงาน
# โดยการ close stream ที่เปิดมาจาก browser
%% Stop the iframe handler and inform the HTML page we are
%% finished streaming.
stop ->
yaws_api:stream_chunk_deliver(Yaws_Pid, "true, true ]"),
yaws_api:stream_chunk_end(Yaws_Pid),
page_registry ! {remove, {pid, self()}};
# X แทน any message
# ลักษณะการทำงาน จะเป็นการ delegate message ต่อไปยัง Callback function
# เสร็จแล้วก็ให้จบ process และ unregister page id
X ->
Result = Callback(Yaws_Pid, Page, X),
yaws_api:stream_chunk_deliver(Yaws_Pid, "false, " ++ Result ++ " ]"),
yaws_api:stream_chunk_end(Yaws_Pid),
page_registry ! {remove, {pid, self()}}
# อันนี้สิ สุดยอด
# เพื่อให้รักษา long-lived connection ไว้
# ถ้าครบ 5 วินาที แล้วยังไม่มี message มา
# ก็ให้ส่ง newline กลับไปยัง browser
# after เป็น syntax ที่ใช้ระบุพวก timeout
after 5000 ->
case yaws_api:stream_chunk_deliver_blocking(Yaws_Pid, "\n") of
ok -> ajax_handler(Yaws_Pid, Page, Callback);
{error,{ypid_crash,_}} -> page_registry ! {remove, {pid, self()}}
end
end.

หลังจากที่ browser load page ไป แล้วทำการเปิด connection รอ server push แล้ว
ถ้า server ต้องการ push ข้อมูลกลับ ก็จะเรียกใช้คำสั่งนี้
html_rpc:send("443584617445720273715201", {alert, "Hello World"}).

ตัวเลขยาวๆนั่นคือ page id
การทำงานของ send ก็คือ

%% Send a message to the page.
send(Page, Message) ->
# เรียกขอ process id ที่รอรับ messagae จาก page_registry
# ให้สังเกตุว่า ไม่มีการ return ค่ากลับ แต่ใช้วิธี รอรับ message ที่ตอบกลับมาจาก page_registry
page_registry ! {self(), get, Page},
# รอรับ messagae จาก page_registry
receive
{result, {_, Pid}} ->
# หลังจากได้ pid จาก page_registry
# ก็จะ dispatch ส่ง message ไปยัง process นั้น
Pid ! Message
end.


โอยอธิบายยากจริงๆ
10 ปากว่า ไม่เท่าลงมือทำ
ลอง run ดูแล้วจะเห็นการทำงานของมันครับ

Related link from Roti