Friday, August 12, 2005

Bash History

เมื่อก่อนสมัยยังไม่มี bash ก็มักจะใช้ set -o vi
เพื่อให้ใช้ vi command ในการ access history command ได้

ปัจจุบัน มี bash ก็ไม่ค่อยได้ set -o vi แล้ว (จริงๆแล้วไม่ค่อยได้ใช้ shell เท่าไรแล้วด้วย)
ใช้แต่ลูกศรขึ้นลง scroll ไปมา
พึ่งมารู้วันนี้เองว่า history ของ bash ทำอะไรได้เยอะเหมือนกัน

เริ่มด้วย สมมติว่าเราพึ่งสั่ง ls -l | head ไป
และต้องการสั่งซ้ำอีก แทนที่จะใช้ลูกศรขึ้นไปหา
เราสามารถใช้คำสั่ง !l แทนได้ โดยมันจะหาคำสั่งล่าสุดที่ขึ้นต้นด้วยตัว l ให้เอง

หรือถ้าใช้ !?head แทนก็ได้ โดยมันจะหาคำสั่งล่าสุด
ที่มีคำว่า head

ส่วนการ search ก็สามารถใช้ ^r เพื่อเข้าสุ่ reverse incremental history search mode
เมื่อหา command ที่ต้องการเจอแล้ว ก็สั่งทำงานด้วยการ enter
หรือจะสัง ^j เพื่อ edit command ก่อน (กรณียกเลิกค้นหาใช้ ^c)

ถ้าสั่ง ^head^tail ก็เป็นการเรียกใช้ command ก่อนหน้า แต่
แทนที่คำว่า head ด้วยคำว่า tail

สั่ง history | grep -i 'head' เพื่อ list คำสั่ง
ที่มีคำว่า head จากนั้นก็ใช้ !linenumber เพื่อเลือกคำสั่งที่ต้องการ

ถ้าเราดูใน history จะเห็นว่ามันมีคำสั่งพื้นๆ เช่น ls, edit อยู่เต็มไปหมด
กรณีที่เราไม่ต้องการเก็บคำสั่งเหล่านี้ใน history ก็ใช้
export HISTIGNORE="&:ls:[bf]g:exit"
มี trick หนึ่งก็คือ ถ้าเราใช้ [ \t]* ใน HISTIGNORE
กรณีที่เราสั่งคำสั่งที่ไม่ต้องการให้เก็บใน history
ก็เพียงแต่เติม space ไปข้างหน้าคำสั่ง

Related link from Roti

DSL with Ruby

Martin Fowler เขียนบทความ Using the Rake Build Language
มีประเด็นที่น่าสนใจอยู่อันก็คือ Domain Specific Language

The basic idea of a domain specific language (DSL) is a computer language that's targeted to a particular kind of problem, rather than a general purpose language that's aimed at any kind of software problem.

ที่สนใจประเด็นนี้ เพราะว่า Ruby language มันมีความยืดหยุ่นมาก
ทำให้เราสามารถสร้าง Domain Language เพื่อให้เหมาะกับงานของเราได้
อย่างเช่น Rake ที่ออกแบบมาสำหรับ build process
หรือ ActiveRecord ที่ออกแบบมาสำหรับ ORM

ตัวอย่าง Rakefile
task :codeGen do
# do the code generation
end

task :compile => :codeGen do
#do the compilation
end

task :dataLoad => :codeGen do
# load the test data
end

task :test => [:compile, :dataLoad] do
# run the tests
end


ตัวอย่าง ActiveRecord
class Item < ActiveRecord::Base
belongs_to :category
validates_associated :categoory
validates_format_of :done_before_type_case
,:with=>/[01]/,
,:message=>"must be 0 or 1"
validates_presence_of :description
validates_length_of :description
,:maximum=>40

end


จริงๆแล้วพวก syntax ที่เราเห็นนั้น มันก็คือ method ธรรมดานี่แหล่ะ
อย่างเช่น
task :name => [:prereq1, :prereq2]

จริงๆแล้ว ถ้าเขียนให้ดูเป็นขั้นเป็นตอนหน่อย ก็เขียนได้ดังนี้
hash = Hash.new
hash[:name] = [:prereq1, :prereq2]
task(hash)

ถ้าเราไปเปิด source code ของ rake ดูจะเห็นว่า
เขา define method task ไว้ดังนี้
# Declare a basic task.
#
# Example:
# task :clobber => [:clean] do
# rm_rf "html"
# end
#
def task(args, &block)
Task.define_task(args, &block)
end

จะเห็นได้ว่า block do...end ถูก pass เป็น object ไปไว้ในตัวแปร block
เมื่อต้องการ execute ก็เพียงแต่สั่ง block.call

ใน Rake มี feature Multiple Definitions
ซึ่งเปิดโอกาสให้เราเขียน definition กระจายแบบนี้ได้
task :name
task :name => [:prereq1]
task :name => [:prereq2]
task :name do |t|
# actions
end


feature ที่ทำให้เขียนแบบนี้ได้ มันเป็นคุณสมบัติของ ruby language เลย เช่น
class Person 
def initialize(name)
@name = name
end
end

p1 = Person.new("polawat")

class Person
def sayhi
puts "Hello #{@name}."
end
end

p1.sayhi

เห็นได้ว่า เราสามารถ extend class Person
ด้วยการประกาศ definition class ใหม่อีกรอบ
(ไม่มีข้อจำกัดเรื่อง scope เราสามารถ extend class
ของ ruby เช่น String ก็ได้)


อ่านเพิ่มเติม

Related link from Roti

ห้องน้ำ

อ่านเจอใน Roumen 's weblog

อันไหนคือห้องน้ำชาย อันไหนคือห้องนำ้หญิง
ใครรู้ภาษาจีน ช่วยเฉลยด้วย
Roumen เขายังไม่เฉลยเลย
(พยายามเดาอักษรภาพแล้ว ดูไม่เห็นออกเลย
ว่าตัวอักษรตัวไหนเหมือนผู้ชาย)

Related link from Roti

Unsigned char in C <--> Signed byte in Java

ช่วงนี้ได้มีโอกาสใล่ดู algorithm ที่เกี่ยวกับการ encrypt, decrypt
ที่เขียนด้วย C แล้วต้องแปลงให้เป็น java เลยนั่งค้นหาดูว่ามีประเด็นอะไรบ้าง
ที่อาจเป็นปัญหา

ประเด็นแรกก็คือ เรื่อง byte ของ Java เป็น signed byte
แต่ใน c จะเป็น unsigned char
ปัญหาจะเห็นชัด กรณีที่เรา shift bit
เช่น
byte b1 = (byte) 0x80;          // in binary -> 10000000
byte b2 = b1 >> 4;
System.out.println(b2); // print -> -8

byte b1 = (byte) 0x80;
int b2 = b1 >>> 4;
System.out.println(b2); // print 268435448

ปัญหาของกรณีนี้ก็คือ 0x80 พอแปลงเป็น byte แล้ว มันก็คือ -128 (มี sign bit เป็น 1)
พอ shift bit แล้วก็ได้เรื่องเลย
ทางแก้ก็คือ ให้เรา & 0xff กับ byte ก่อน shift
byte b1 = (byte) 0x80;
byte b2 = (byte) ((b1 & 0xff) >> 4);
System.out.println(b2); // print -> 8

byte b1 = (byte) 0x80;
int b2 = (b1 & 0xff) >> 4;
System.out.println(b2); // print -> 8

การแปลง byte เป็น int ก็ใช้กฎเดียวกัน
byte b1 = (byte) 0x80 ;
int i1 = b1 & 0xff;
int i2 = b1;
System.out.println(i1); // print 128
System.out.println(i2); // (wrong for unsigned byte) print -128


ที่นี้บางครั้งที่เราต้องการแปลง byte array ให้เป็น int value หรือ long value
ก็ใช้การ & 0xff เช่นเดียวกัน
ตัวอย่างเช่น
public static int toInt(byte[] bs) {
return ((bs[3] & 0xFF) << 0) +
((bs[2] & 0xFF) << 8) +
((bs[1] & 0xFF) << 16) +
((bs[0] & 0xFF) << 24);
}

เราสามารถดูตัวอย่าง source code ของ Java
ได้ที่ class java.io.Bits ซึ่งถูกเรียกใช้จาก
ObjectInputStream, ObjectOutputStream
น่าเสียดายที่ class นี้ไม่ได้ประกาศเป็น public class
ทำให้ไม่สามารถเรียกใช้งานในโปรแกรมเราได้

Related link from Roti

Thursday, August 11, 2005

Struts Ti

Struts Ti เป็น derivative ของ struts 1.x
rewrite framework เพื่อให้ง่ายต่อการ develop
(idea หลายๆส่วนมาจาก ruby on rails)

Controller

  • No configuration - everything done through annotations
  • ใช้ XDoclet กรณีที่เป็น JDK1.4
  • จะใช้หรือไม่ใช้ Form object ก็ได้
  • controller เขียนแบบ POJO
  • มี annotation สำหรับทำ Validation
  • Result forwards view ไม่ต้อง define ก็ได้ มี default เป็นค่าเดียวกับ action name

Action Mapping URL จะอยู่ในรูป

http://HOST/ACTION_NAME/PARAM_VALUE1/PARAM_NAME2/PARAM_VALUE2


FormValidation
ออกแบบใหม่

Jsp Tag
ใช้แนวทางของ WebWork2
Note: ในส่วน tag นี้ jsp กับ rails จะไม่ต่างกันนัก
แต่ rails จะ integrate template กับ controller
เป็นเนื้อเดียวกันกว่า (template mix เข้ากับ controller
ทำให้มองเหมือนกันว่า ตัวเองเป็น controller)


เพิ่มเรื่อง Page Flow State Management เข้ามา
โดยใช้แนวทางจาก Beehive Page Flow

Related link from Roti

Wednesday, August 10, 2005

Dependency Injection is Ruby

วันนี้อ่านเจอ Presentation ใน OSCon 2005 ของ Jim Weirich
ซึ่งพูดถึงเรื่อง Dependency Injection กับ ruby

มีภาพตัวอย่างการเปรียบเทียบ Java Class กับ Ruby Class ที่โดนใจ
ก็เลย copy มาให้ชม



ชอบที่พูดถึงตรงนี้
DI really becomes useful in really large projects
There aren’t that many really large Ruby projects


Dependency Injection Frameworks for Ruby

Note: DIM กับ Matz มี link ไปหา source code ใน Presentation

หลังจากดูตัวอย่าง source code ของ DIM กับ Matz
แล้วรู้สึกมืน ชอบวิธีการที่พวก spring, hivemind
ใช้ xml เป็น descriptor มากกว่า

Related link from Roti

Newbie in Linux Server Installation

ปกติทำงานด้าน Development ไม่ได้ยุ่งกับการติดตั้ง Server มานานแล้ว
ช่วงนี้ได้กลับมาปัดฝุ่น นั่ง config Linux Server ได้ความรู้ขึ้นอีกเยอะเลย
เริ่มด้วยการ resize ขนาดของ ​LVM
ก็สั่ง lvresize เพื่อเพิ่มเนื้อทีี่ของ volumn
่ปรากฎว่าเนื้อที่ใน Logical Volume เพิ่มขึ้นแล้ว
แต่เนื้อที่ใน file system ที่ mount เข้ามายังขนาดเดิมอยู่
ก็เลยนั่งค้น net ปรากฎว่ามีจดหมายที่เขียนถามเรื่องนี้เหมือนกัน
แต่ไม่มีใครตอบเลย สุดท้ายหลังจากงมเข็มไปมาพักใหญ่ ก็ฟลุ๊คไปเจอคำสั่ง
resize_reiserfs ก็เลย bingo
นึกเห็นใจพวก newbie ขึ้นมาทันทีเลย
โถเขียนจดหมายไปถามแล้วก็ไม่มีใครตอบ

ระหว่างนั้นก็อ่านเจอพวกชุดคำสั่ง autofs, automount
ซึ่งช่วยจัดการ mount filesystem ให้เราอัติโนมัติ เมื่อเราต้องการใช้
(เช่นเมื่อเรา cd เข้าไปใน directory ที่เป็นจุด mount point นั้น
หรือเมื่อเราพยายาม access path ใน mount point นั้น)
น่าสนใจดีมาก โดยเฉพาะในส่วนที่ mountpoint นั้นจะ automatic unmount เอง
หลังจากที่เราไม่ได้ใช้งานในระยะเวลาหนึ่ง (ค่า default คือ 5 นาที)
ที่ชอบอีกจุดหนึ่งก็คือ AutoFS 's map สามารถกำหนด map ในลักษณะ
Wildcard Key ได้

Note: ใน suse มีปัญหาในกรณีที่เรากำหนด timeout ใน
auto.master เช่น
/auto /etc/auto.misc --timeout 30
ถ้าอยู่ใน suse ตัว "-" แรกจะหายไป ทำให้เราต้องใส่เป็น "---"
หรือไม่ก็เลี่ยงไปใช้ "-t 30" แทน

Related link from Roti

Monday, August 08, 2005

Config VPN with OpenVPN

ช่วงนี้กำลังหา solution ในการเชื่อมต่อ ระหว่าง
network ที่บ้าน กับ network ที่ทำงาน
เมื่อก่อนที่ใช้ windows ก็สามารถใช้ CIPE ในการทำ vpn ได้
เนื่องจากมีทั้ง version linux และ win32
(บน win32 ยังมีปัญหาในการติดตั้งบน XP อยู่บ้าง แต่ไม่ยากเกินไปนัก
สามารถหาวิธีแก้ใน mail-archive ได้)
มาตอนนี้เปลี่ยนไปใช้ OS X แล้ว ก็เลยต้องขวนขวายหา solution ใหม่

ตอนแรกก็ดู IPSec ไว้ เพราะว่ามีมาให้กับ Freebsd อยู่แล้ว
แถมใน Tiger ก็มี gui สำหรับ config และเรียกใช้งานด้วย
หลังจากปลุกปล้ำอยู่ 1 วันเต็มๆ ก็ถอดใจ
เนื่องจาก case ที่ config นี้เป็น case dynamic ip
ทั้งฝั่งที่บ้านและฝั่งที่ทำงาน ซึ่งน่าจะเป็น case ที่ config
ยากสุดสำหรับ IPSec

หลังจาก search net ไปมา ก็ไปเจอเข้ากับ OpenVPN
หลังจากอ่านคู่มืออยู่สักพัก ก็พบทางสว่างทันที
ก็เลย load เอา source มา build เอง
ตัว Server ที่ทำงานมี OS เป็น SuSE Enterprise 9
การ build ก็เลยไม่ยาก ขาดเหลือ lib อะไร
ก็เปิดแผ่นเอา
ส่วนการ build ที่ Mac ก็ใช้ fink
ในการ install library lzo เพิ่ม

การ Config ก็ไม่ยากเย็นอะไร เพราะใน distribution
มีตัวอย่าง config file มาให้พร้อมสรรพ
แถมยังมี document ที่อธิบายค่อนข้างละเอียดดีทีเดียว
เริ่มด้วยการ generate พวก Certificate ทั้งหลาย
เนื่องจากในการเชื่อมต่อระหว่าง client กับ server
จะมีการตรวจสอบ Certificate ของกันและกัน
โดยทั้งสองฝ่ายจะยอมรับ connection ต่อเมื่อ
certificate ของทั้งสองฝ่าย ถูก sign โดย
Root CA อันเดียวกัน
(ข้อดีของ OpenVPN ก็คือมันเตรียม shell script
ที่ใช้ในการสร้าง key หรือ sign key ไว้เสร็จสรรพ
ไม่ต้องทรมานไปนั่งอ่านวิธีใช้ openssl อีก)

ในส่วน Server ก็จะมี config เพิ่มในส่วนของ
Route table ที่จะ push ไปให้ Client
เพื่อที่จะกำหนดว่า client มีสิทธิ access subnet
อะไรได้บ้าง

ส่วนการ Config OpenVPN สำหรับ OS X
มีข้อแม้เพิ่มเติมจากพวก Unix ก็คือ
ต้องมีการติดตั้ง tun/tap driver for Mac OS X
ซึ่งเป็น kernel extension ด้วย
อันนี้แหล่ะที่ดูน่ากลัวเล็กน้อย
เพราะว่ากลัวว่าติดตั้งแล้ว จะทำให้ OS ไม่เสถียร
ก็เลยไปหาเอกสารมาอ่านทำความเข้าใจสักหน่อย
ว่าถ้ามีปัญหาแล้วจะ uninstall ยังไง

ในส่วนของ OS X ก็มีคนทำ gui สำหรับเรียกใช้ง่ายๆ
ชื่อ Tunnelblick

โดย download package ของ Tunnelblick มีให้เราครบหมดเลย
ทั้ง tun-tap, openvpn, gui

Note: ในกรณีที่เรา build openvpn เอง แล้วเลือก
install ใน path ที่ไม่ใช่ /usr/local/sbin
จะทำต้องทำ link มาไว้ที่นี่ด้วย เพราะเจ้า
TunnelBlick มันฝัง hardcode ไว้ใน source code
เลยว่า จะเปิด openvpn ได้จากตำแหน่งนี้เท่านั้น

Related link from Roti

Sunday, August 07, 2005

Java Puzzle

อ่านเจอในเอกสาร presentation ใน javaone 2005
ก็เลยลอกมาให้ดู
public class AnimalFarm{ 
public static void main(String[] args) {
final String pig = "length: 10";
final String dog = "length: " + pig.length();
System.out.println("Animalsare equal: " + pig == dog);
}
}


public class Assignment { 
public static void main(String[] a) throws Exception {
int tricky = 0;
for (int i = 0; i < 3; i++)
tricky += tricky++;
System.out.println(tricky);
}
}


public class Loop {
public static void main(String[] args) {
int[][] tests = { { 6, 5, 4, 3, 2, 1 }, { 1, 2 }, { 1, 2, 3 },
{ 1, 2, 3, 4 }, { 1 } };
int successCount = 0;
try {
int i = 0;
while (true) {
if (thirdElementIsThree(tests[i++]))
successCount++;
}
} catch (ArrayIndexOutOfBoundsException e) {
}
System.out.println(successCount);
}

private static boolean thirdElementIsThree(int[] a) {
return a.length >= 3 & a[2] == 3;
}
}


public class Mod {
public static void main(String[] args) {
final int MODULUS = 3;
int[] histogram = new int[MODULUS];
int i = Integer.MIN_VALUE;
// This loop iterates over all intvalues
do {
histogram[Math.abs(i) % MODULUS]++;
} while (i++ != Integer.MAX_VALUE);
for (int j = 0; j < MODULUS; j++)
System.out.print(histogram[j] + " ");
}
}


อันสุดท้ายนี่งงอยู่ตั้งนาน สุดท้ายเปิด javadoc ดูแล้วค่อยร้อง อ๋อ

Related link from Roti