Friday, March 17, 2006

Hibernate(3.2) Transformer

ได้ข่าวมาจาก blog.hibernate.org
Hibernate 3.2 มี Helper ดีๆที่ช่วย convert object[]
เป็น pojo หรือ java.util.Map แล้ว

เดิมเวลาที่เรา select partial column ใน hibernate
Object ที่ return กลับมาก็คือ Object[]
List list = s.createQuery(
"select e.student.name as studentName, " +
" e.course.desription as courseDescription " +
"from Enrollment as e")
.list();
Object[] row1 = (Object[]) list.get(0) // return => object[]


แต่ถ้ามี Transformer ช่วยเราสามารถเขียนแบบนี้ได้เลย
List list = s.createQuery(
"select e.student.name as studentName," +
" e.course.description as courseDescription" +
"from Enrolment as e")
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
.list();

StudentDTO dto = (StudentDTO) list.get(0);


นอกจากใช้ได้กับ createQuery แล้ว ยังใช้ได้กับ createCriteria
และ createSQLQuery อีกด้วย

สุดท้าย ก็คือสามารถแปลงเป็น Map object แทนที่จะเป็น bean
.setResultTransformer( Transformers.ALIAS_TO_MAP )

Related link from Roti

Thursday, March 16, 2006

การ debug ruby ด้วย emacs

ปกติใน ruby เราสามารถสั่ง debug ด้วยคำสั่ง
ruby -r debug filename.rb

ซึ่ง ruby จะเข้าสู่ mode debug

ข้อเสียของการ debug แบบนี้ ก็อาจจะเป็นเรื่องมุมมองที่จำกัด (การดู source code)
กับความสะดวกในการ set break point

วันนี้ผมก็เลยลองเอา emacs มาช่วย debug
ก่อนอื่น เราต้องมี file ที่ชื่อ rubydb3x.el หรือ rubydb2x ก่อน
เจ้าตัวที่ชื่อ 3x ใช้กับ emacs ที่ version >= 19.3x ขึ้นไป



ปกติใน emacs มันจะมีโปรแกรมสำหรับใช้ในการ debug อยู่แล้ว
เรียกว่า gud , rubydb ก็ extend จาก gud นี่แหล่ะ

ก่อนจะใช้ก็ต้องมีการ load ขึ้นมาก่อน โดยใช้คำสั่ง
M-x load-library rubydb3x.el
M-x rubydb

หลังจากสั่งมันจะ prompt ขึ้นมาถาม

Run rubydb (like this):

กรณีเครื่องผม ผมมี ruby หลายตัว ก็เลยใส่ path เต็มดังนี้
/usr/local/bin/ruby -r debug filename.rb

filename คือ ruby file ที่ต้องการ debug

เมื่อ start ขึ้นมาแล้ว emacs จะเปิด buffer ใหม่ที่ชื่อ gdb-filename ขึ้นมา
พร้อมกับเปิด buffer แสดง ruby file ที่เราระบุ
และ process จะไปหยุดรออยู่ที่บรรทัดที่ 1 ของ ruby file ที่ระบุ

note: แต่ถ้า shell environment variable ของเรามีการ set ค่า
RUBYOPT=rubygems ไว้
มันก็จะไปหยุดในโปรแกรม rubygems.rb แทน

จากนั้นเราก็สามารถสั่ง debug command ได้จาก buffer ที่แสดง source code
หรือจาก buffer ของ gdb ก็ได้
keyboard binding ที่มาพร้อม rubydb3x ก็มี
  • "\C-b" "Set breakpoint at current line."
  • "\C-s" "Step one source line with display."
  • "\C-n" "Step one line (skip functions)."
  • "\C-r" "Continue with display."
  • "\C-f" "Finish executing current function."
  • "<" "Up N stack frames (numeric arg)."
  • ">" "Down N stack frames (numeric arg)."
  • "\C-p" "Evaluate ruby expression at point."

note: คำสั่งข้างบน ต้องมี prefix key นำด้วย
อย่างกรณีเครื่องผม ต้องกด C-x,C-a นำหน้าก่อน

ที่นี้ก็มาถึงการ customize rubydb เพิ่ม binding หรือคำสั่งที่ต้องการ
อย่างคำสั่งที่ผมใช้บ่อยๆ ตอนใล่ทำความเข้าใจ source code ก็คือ
คึำสั่ง v[ar] l[ocal] ที่ใช้แสดง local variables
เราสามารถเพิ่ม binding เข้าไปได้โดยเขียน elisp แบบนี้

(gud-def gud-view-local "v l" "\C-l" "show local variable")

คำสั่ง gud-def เป็น macro ที่ช่วยในการ define debug command
gud-view-local คือชื่อ command ของเรา (ตั้งชื่อขึ้นมาเอง)
คำสั่งนี้ map เข้ากับ คำสั่ง v l (command ของ ruby)
และ binding เข้ากับ key (C-x, C-a) C-l

มีคำสั่งอยู่หนึ่งคำสั่ง ที่ผมใช้แล้วไม่ work ก็คือ
gud-print ที่ใช้แสดง ruby expression ที่จุดที่ keyboard อยู่
ของผมสั่งแล้ว มันได้ expression กลับมาเป็น method ทั้งก้อนที่กำลังทำงานอยู่
ก็เลยต้อง customize ให้มันแสดงตัวแปรที่ cursor ชี้อยู่
โดย gdb เตรียม variable ตัวหนึ่งไว้ให้เราแล้ว
มีชื่อว่า gud-find-expr-function
โดยปกติมันจะชี้อยู่ที่ function gud-find-c-expr

;; Code for parsing expressions out of C or Fortran code. The single entry
;; point is gud-find-expr, which tries to return an lvalue expression from
;; around point.

(defvar gud-find-expr-function 'gud-find-c-expr)

เราสามารถเปลี่ยนไปชี้ custom function ของเราแทนได้
อย่างของผม ผมเปลี่ยนเป็นการ select inner most expr แทน

(defun gud-custom-find-expr()
(interactive)
(save-excursion
(let ((pos (gud-innermost-expr)))
(buffer-substring-no-properties (first pos) (cdr pos)))))

(setq gud-find-expr-function 'gud-custom-find-expr)

Related link from Roti

Wednesday, March 15, 2006

Native Leak?

App ที่ผมทำให้ลูกค้ารายหนึ่ง
เดิม run อยู่บน IBM P-series
ก็ใช้ได้ปกติดี ตายบ้างเป็นปกติ (ปีละ 2-3 ครั้ง)
เวลาล่ม ก็มีทั้ง user ทำล่ม
เช่น เรียก report ใหญ่ๆในเวลาที่ load online กำลัง peak
พอ report response ช้า ก็ submit เข้ามาใหม่
ส่วนกรณีที่เป็นที่ system ก็คือ
java มันเบื่อขึ้นมา มันก็ core dump ซะเฉยๆ

พอย้ายไปอยู่บน mainframe
คราวนี้ล่มรายอาทิตย์เลย
(โชคดีที่เขาจัดจ้าง team อื่นเข้ามาดูเรื่องนี้โดยเฉพาะ
ไม่ใช่หน้าที่ของบริษัทผม
ผมก็เลยไม่ต้องปวดหัวมากนัก)

ช่วงแรกๆ หลายๆคนที่เกี่ยวข้อง ก็ชี้นิ้วอย่างเดียว
เขียนโปรแกรมอย่างไง
ใช้ technique ถูกต้องหรือเปล่า
system ไม่มีปัญหา ล่มเพราะ app แหง๋ๆ
(แปลกที่ไม่มีใครย้อนไปดูเลยว่า app มัน run มาปีกว่าแล้ว)
ปากเปียกปากแฉะ อธิบายไป
พร้อมกับช่วยจำแนก อธิบายวิธีแก้ปัญหา

ปัญหาก็ค่อยๆแก้ไปเรื่อยๆ
ช่วงนี้เหลือ error หนักๆ ก็คือ
มันจะค่อยมี error out of memory ขึ้นมาอยู่เรื่อยๆ
(ไม่ถี่มาก แต่ก็ถือว่าเป็นปัญหา เพราะเป็นระบบ online
ที่ให้บริการ ณ counter ทั่วประเทศ)

วันนี้ได้ cc จดหมายจาก IBM

Javacore shows that both the Xms and Xmx have been set to 1280 m.
The heapdump shows that only 380 mb of heap is occupied.
Verbose GC shows that at least 80% heap is free when the oom occured.
This looks to be a case of native memory exhaustion.
...
Based on these facts we would reccomend the changing the Xmx and Xms
Heap Settigns as below to ensure that we have enough native memory
left with us for native allocation Reduce the Xmx value to 1024 mb
Reduce the Xms value to 256 mb


ตอนนี้ผู้ต้องสงสัยเบอร์ 1 คือ jdbc type 2
แต่โชคร้ายที่ jdbc type 4 มันก็มี known issue ของมันอยู่
ทำให้ไม่สามารถ switch ไปเฉยๆได้

Note: ข้อเตือนใจ
เขียน app run ใน type 2 ได้
อย่าคาดหวังว่าแค่เปลี่ยน driver type
แล้วมันจะ smooth run ต่อได้นะครับ

ลืมบอกไป
product ผู้สนับสนุน bug อย่างเป็นทางการ ก็คือ websphere 5 ครับ

Related link from Roti

วันนี้นั่งฝึกทำโจทย์ใน Ruby Quiz
มีโจทย์อยู่ข้อ ที่ต้องเขียน method ที่รับ parameter เป็น Number หรือ Range ก็ได้
โดยมีจำนวนไม่จำกัด
เช่น

build(1, 7, 11, 20..24, 32..78)
build(1..2)
build(8, 11..17)

ต้องการแปลงให้เป็น array ชุดเดียว ที่เก็บเลขที่เป็นไปได้ทั้งหมด
ผมก็นั่งเขียนทื่อๆเลย

def build(*args)
list = []
args.each {|arg|
case
when arg.class == Range:
arg.each {|n|
list << n
}
else
list << arg
end
}
list
end

ไปเห็น code ที่คนอื่นเขียนไว้
โจทย์เดียวกัน

def build(*args)
args = args.map {|arg| Array(arg) }.flatten
end


"เด็กเอ๋ยเด็กน้อย ความรู้เจ้ายังด้อยเร่งศึกษา.."

Related link from Roti

ติดตั้ง Ingres2006 บน Gentoo 2006.0

ca-openingres move ไปสังกัด Ingres Corporation อีกแล้ว
คราวนี้ใช้ชื่อเป็น ingres2006
ก็เลย load มาติดตั้งเสียหน่อย

file ที่ให้มาเป็นพวก rpm file
เครื่องผมไม่ได้ลงไว้
ก็เลยติดตั้ง package rpm โดยใช้คำสั่ง
emerge rpm

ในคู่มือของ Ingres กรณีที่ต้องการความสะดวกก็ให้เรียก program ingres_express_install.sh
แต่เครื่องผม มันฟ้อง error ของ rpm ว่าไม่สามารถลงได้ เพราะ /bin/sh ไม่มี
ก็เลยเข้าไปแก้ script ingres_express_install.sh
เพิ่ม --nodeps ลงไปในคำสั่ง rpm

หลังจากสั่ง install โปรแกรมจะฟ้อง error จำนวนหนึ่ง
ประมาณว่า
ingres: iisutm command not found
ingres: ii.... command not found
ให้จดไว้ มา run เองข้างนอก

ก่อน run ก็ให้ login เป็น user ingres (rpm มันสร้างให้แล้ว)
สั่ง setup
export II_SYSTEM=/opt/Ingres/IngresII
export PATH=$PATH:$II_SYSTEM/ingres/bin:$II_SYSTEM/ingres/utility
export LD_LIBRARY_PATH=$II_SYSTEM/ingres/lib


แล้วก็ใล่ run ii... ทั้งหลาย

Related link from Roti

Tuesday, March 14, 2006

เปลี่ยน Caps-lock key เป็น Control key

สำหรับพวกใช้นิ้วก้อยเยอะ
ใน linux console เราสามารถเปลี่ยน Caps-lock key ได้ดังนี้

dumpkeys > my_keymap

แก้ไข file ตรงตำแหน่ง

keycode 58 = Caps_Lock #=> เปลี่ยนเป็น Control

จากนั้นก็ load key โดยใช้คำสั่ง

loadkeys my_keymap

Related link from Roti

Sunday, March 12, 2006

ศึกษา Student (AI Program สมัยแรกๆ)

วันนี้ลองนั่งเขียนโปรแกรมที่ solve algebra equation ดู
พวกที่เป็นโจทย์แบบนี้ -> (x + 2)/ 10 = 8

ลอกวิธีการมาจาก code ในหนังสือ Paradigms of AI Programming
ของ Peter Norvig
โดยเนื้อหาที่เขาพูดถึง ก็คือวิธีการ implement program Student
ที่ Daniel Bobrow ทำ Research Project ไว้ในปี 1964
ตัวโปรแกรม Student ออกแบบมาให้ solve โจทย์แบบนี้


(student '(If the number of customers tom gets is twice the square of
20 % of the number of advertisements he run |.|
and then number of advertisements is 45 |.|
then what is the number of customers Tom gets ?))

;; ที่เขียนข้างบนนี้เป็นโปรแกรมจริงๆนะ run ได้ ไม่ใช่ description

ผมตัดมาให้ดูเฉพาะส่วน solve equation (เฉพาะที่มีตัวแปรเดียว)
หลักการ ก็คือ แปลงโจทย์ให้อยู่ในรูป tree structure ให้ได้ก่อน

=
/ \
(/) 8
/ \
+ 10
/ \
x 2

ตรงนี้ lisp ได้เปรียบในการ represent
เพราะพวก tree structure สามารถเขียนในรูป list ได้ตรงๆเลย
กรณีข้างบน ก็เขียนได้ดังนี้

'(= (/ (+ x 2) 10) 8)

ส่วน ruby ผมลองใช้ class ดู
ซึ่งเขียนแล้ว ก็รู้สึกเยิ่นเย้อนิดๆ (ขนาดมี attr_accessor ช่วย)

class Exp
include ExpHelper

attr_accessor :op, :lhs, :rhs
def initialize(lhs, op, rhs)
@lhs = lhs
@op = op
@rhs = rhs
end

...

end

ที่รู้สึกเยิ่นเย้อ ก็เพราะ lisp จะเขียนแค่นี้

(defstruct (exp (:type list)
(:constructor mkexp (lhs op rhs)))
op lhs rhs)


ขั้นถัดไป ก็คือก็ทำการย้ายข้างให้ ด้านซ้าย มีแต่ตัวแปรอย่างเดียว
กรณีโจทย์ข้างบน ก็จะถูกแปลงเป็น x = (8 * 10) - 2
ใน lisp ที่ norvig เขียน จะมีหน้าตาแบบนี้

(defun isolate (e x)
"Isolate the lone x in e on the left-hand side of e."
;; This assumes there is exactly one x in e
;; and that e is an equation.
(cond ((eq (exp-lhs e) x)
;; case I: X = A -> X = n
e)
((in-exp x (exp-rhs e))
;; case II: A = f(x) -> f(x) = A
(isolate (mkexp (exp-rhs e) '= (exp-lhs e)) x))
((in-exp x (exp-lhs (exp-lhs e)))
;; Case III: f(x) * A = B -> f(x) = B/A
(isolate (mkexp (exp-lhs (exp-lhs e)) '=
(mkexp (exp-rhs e)
(inverse-op (exp-op (exp-lhs e)))
(exp-rhs (exp-lhs e)))) x))
((commutative-p (exp-op (exp-lhs e)))
;; Case IV: A*f(x) = B -> f(x) = B/A
(isolate (mkexp (exp-rhs (exp-lhs e)) '=
(mkexp (exp-rhs e)
(inverse-op (exp-op (exp-lhs e)))
(exp-lhs (exp-lhs e)))) x))
(t ;; Case V: A/f(x) = B -> f(x) = A/B
(isolate (mkexp (exp-rhs (exp-lhs e)) '=
(mkexp (exp-lhs (exp-lhs e))
(exp-op (exp-lhs e))
(exp-rhs e))) x))))

ซึ่งผมชอบที่เขาเขียนตรงที่
  • เขียนแบบไม่มี side-effect (ไม่มี assign statement เลย)
  • Recursive สวยดี

อันนี้ตอนแปลงเป็น ruby ก็นึกอยู่ว่า
จะเขียนแบบ imperative ดีไหม จะได้เปรียบเทียบกันดู
แต่สุดท้าย ก็รู้สึกว่า โจทย์แบบนี้ไม่ควรเขียนแบบนั้น ก็เลยเขียนตาม lisp
โดยให้ method isolate เป็น method ของ class Exp

def isolate(var)
case
when @lhs == var
self
when var.in(@rhs)
Exp.new(@rhs, @op, @lhs).isolate(var)

when var.in(@lhs.lhs)
Exp.new(@lhs.lhs,
"=",
Exp.new(@rhs, self.inverse(@lhs.op), @lhs.rhs)).isolate(var)

when ["*", "+"].include?(@lhs.op)
Exp.new(@lhs.rhs,
"=",
Exp.new(@rhs, inverse(@lhs.op), @lhs.lhs)).isolate(var)

else
Exp.new(@lhs.rhs,
"=",
Exp.new(@lhs.lhs, @lhs.op, @rhs)).isolate(var)
end
end


ตรงเงื่อนไขที่ check ว่า ตัวแปรอยู่ผั่งไหน (จะได้สลับด้านได้ถูก)
ผมอาศัยว่า class ของ ruby เป็น class แบบเปิด (แก้ไขได้)
ก็เลยใช้วิธี modify Symbol Class (ผมใช้ Symbol represent variable)

class Symbol
def in(exp)
to_sym == exp ||
(exp.is_a?(Exp) &&
(to_sym.in(exp.lhs) || to_sym.in(exp.rhs)))
end
end


พอจัด tree เสร็จ
สุดท้ายก็ evaluate ด้านที่อยู่ด้านขวา
ใน ruby ก็ใช้คำสั่ง eval

def solve()
Exp.new(@lhs, '=', eval_equation(@rhs))
end

def eval_equation(exp)
return case
when exp.is_a?(Numeric): return exp
else
eval("#{eval_equation(exp.lhs)} #{exp.op} #{eval_equation(exp.rhs)}")
end
end


ตอน run ก็เขียนดังนี้ (ยังไม่ได้เขียน parser ก็เลยดูไม่ค่อยสวย)

e = Exp.new(Exp.new(Exp.new(:x, '+', 2), '/', 10), '=', 8)
puts "Equation -> #{e}"
puts "Solve -> #{e.isolate(:x).solve()}"

# output
# ------
# Equation -> x + 2 / 10 = 8
# Solve -> x = 78
#

Related link from Roti

upgrade glibc บน Gentoo

มีปัญหากับการลง SBCL(Steel Bank Common Lisp) ซึ่งต้องการใช้ NPTL
ก็เลย emerge glibc ใหม่
ซึ่งก็ไปเจอ message ว่าต้องใช้ USE="nptl nptlonly"
ก็เออออไปตามมัน
ซึ่งก็ไปตายขณะ build โดยฟ้องว่า gcc version เก่าไป
ด้วยความมักง่าย ไม่รู้จักอ่าน (จริงๆแล้วคือค้นใน google)
ก็เลยดุ่มๆไปเรื่อยๆ
upgrade gcc เสร็จ
ใช้ gcc-config switch ไปตัวใหม่ (3.4.5)
ทดสอบโปรแกรมดู พบว่า
โปรแกรม python เกิดปัญหากับ libstdc++.so.5 , run ไม่ได้
ก็เลยพยายาม switch gcc-config กลับ
ปรากฎว่าไม่สำเร็จ
ก็เลยมั่ว set /etc/env.d/xxgcc เอง
set ให้ ld path มันชี้ไปที่ libstdc++ ตัวเก่า
เพื่อให้มัน run python ให้ได้ก่อน (emerge ใช้ python)

จากนั้นก็เลยค้น google เจอ Gentoo Linux GCC Upgrade Guide
พยายามทำไปตามที่เขาว่า แต่ไปตายตรง revdep-rebuild
มันฟ้องว่า บาง ebuild มันหายไป

เมื่อไม่รู้ว่าจะทำอะไรต่อแล้ว
ก็เลยมั่วต่อ สั่ง emerge glibc ตัวใหม่จนสำเร็จ
ทดลอง run SBCL
สำเร็จแฮะ run ได้

แต่เมื่อทดลอง startx
ก็พบ error

x relocation error: X symbol --guard, version GLIBC.2.3.2 not defined in file libc.so.6
with link time reference]

ค้น google ดูพบ forum ที่อุทิศเพื่อเรื่องนี้ (5 หน้า)
x relocation error

หลังจากนั่่งอ่านอยู่พักใหญ่ พยายามทำความเข้าใจ
(ระหว่างนั้นก็สั่ง download Gentoo livecd-2006.0 ไว้ก่อนเลย)
สุดท้ายก็เลือกลงใหม่ดีกว่า
เพราะ คิดว่าถ้ามั่วไปเรื่อยๆ อาจจะเสียเวลามากกว่า ลงใหม่ทีเดียว

Related link from Roti