Friday, May 26, 2006

Climbing

สาวน้อยน่ารักคนนี้ อายุแค่ 16
แต่ปีน overhang เหมือนเป็นของเล่นๆ
ภาพจากการแข่งขัน bouldering เมื่อวันอาทิตย์ที่ผ่านมา



ผมลองเล่นกีฬานี้ครั้งแรก เมื่อนานมาแล้ว อาจจะ 8-9 ปีมาแล้ว
เริ่มจากไปเที่ยว Railay กระบี่ แหล่งปีนเขาที่ติด 10 อับดับแรกของโลก
ไปทดลองเล่น โดยมีอาจารย์เจ้าถิ่น สาวสวย หุ่นดี ชื่อรำพึง เป็นคนสอนให้

ผมเป็นคนกลัวความสูง
ยิ่งปีนสูงก็ยิ่งเสียว
ยังจำการปีนแบบ multi-pitch ซึ่งเป็นการปีนระยะที่สูงเกินกว่าความยาวเชือก
เลยต้องมีการสลับปลายเชือกกันกลางทาง
เหงื่อนี่ไหลเป็นน้ำเลย กลัวผิด
clip ผิด แกะผิด มันจะล่วงลงมาตายเอาได้

Related link from Roti

ติดตั้ง Maven-Proxy

วันนี้นั่งติดตั้ง Maven-Proxy
link เอกสารการ config ก็ดัน error 404 อีก
ก็เลยต้องมองหาตัวอย่างจาก testcase ของเขาแทน

สรุปขั้นตอนการติดตั้ง
1. download Maven-Proxy ซึ่งเลือกได้ 2 แบบคือ
เป็น War file กับ Stand-alone application
ผมเลือกใช้แบบ Stand-alone
2. สร้าง configuration file หน้าตาประมาณนี้
Link
3. สั่ง start server ด้วยคำสั่ง
java -jar maven-proxy-standalone-0.2-app.jar maven-proxy.properties


ในฝั่ง client ก็ให้ไป set ใน file
~/.m2/settings.xml
เพิ่มส่วน Mirrors เข้าไป
<settings>
.
.
<mirrors>
<mirror>
<id>maven-proxy</id>
<name>maven proxy</name>
<url>http://myserver:8888/repository</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
.
.
</settings>


Note: maven1 กับ maven2 มี repository structure คนละแบบกัน
เวลา config server ก็ต้องเลือก repository ให้ถูก version ด้วย

Related link from Roti

Thursday, May 25, 2006

Solve Sudoku Puzzle with Python

เคยเขียนเรื่องการ solve Sudoku ด้วย Oz
กับ Solve ด้วย java ไปแล้ว

Peter Norvig ปล่อยบทความว่าด้วยการใช้
Solving Every sudoku Puzzle ออกมา
โดย implement ด้วย python

แค่เริ่มต้น declare ตัวแปรต่างๆ ผมก็ร้องว้าวแล้ว
rows = 'ABCDEFGHI'
cols = '123456789'
digits = '123456789'
squares = [r+c for r in rows for c in cols]
unitlist = ([[r+c for r in rows] for c in cols] +
[[r+c for c in cols] for r in rows] +
[[rows[r+dr]+cols[c+dc] for dr in (0,1,2) for dc in (0,1,2)]
for r in (0,3,6) for c in (0,3,6)])
units = dict((s, [u for u in unitlist if s in u])
for s in squares)
peers = dict((s, set(s2 for u in units[s] for s2 in u if s2 != s))
for s in squares)


วิธีการที่ใช้ solve ก็คือ constraint propagation กับ search
จำนวนบรรทัด ใช้ไปแค่ 100 บรรทัด

ผมชอบวิธีที่เขาเขียน code
ติดใจมาจากหนังสือ "Artificial Intelligence Programming" ที่เขาเขียน

Related link from Roti

Sunday, May 21, 2006

Hibernate Validator

Feature หนึ่งของ Rails ที่ผมชอบก็คือส่วนของ validation มันเป็นส่วนเดียวกับ Model
ใน Hibernate version 3.x นี้ ก็ได้มี Feature นี้ใส่เข้ามาเหมือนกัน
แต่แยกอยู่ใน package Hibernate Annotations

การ config validation จะใช้ Annotation เข้ามาช่วย
@Entity
public class Province {

private Long id;
private String name;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

@Column
@NotNull
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

}


ประเด็นที่น่าสนใจ ก็คือ แล้วเราจะ check validate ตอนไหน
(ตอน submit form, ตอน save)
และด้วยวิธีใด

เอาวิธีแรกสุดก่อน ก็คือทำเป็น constrains ใน Database
กรณีนี้ ถ้าเราใช้ Schema Tool ของ Hibernate ทำการ generate sql
ตัว Schema Tool ก็จะสร้าง constrains ให้เป็นไปตามที่เรากำหนด
เช่นตัวอย่างของเรา มี @NotNull อยู่ ดังนั้น column name นี้ใน database
ก็ต้องเป็น not null ด้วย

วิธีถัดมา ก็คือระบุให้ Hibernate Throw Exception
ถ้ามีการพยายาม save Entity นี้
วิธีนี้ทำได้โดย ระบุ ValidateXXEventListener ใน Configuration
<event type="pre-update">
<listener
class="org.hibernate.validator.event.ValidatePreUpdateEventListener" />
</event>
<event type="pre-insert">
<listener
class="org.hibernate.validator.event.ValidatePreInsertEventListener" />
</event>

เขียน TestCase สำหรับกรณีนี้ได้แบบนี้
public void testValidate() throws Exception {
Province p = new Province();
try {
session.save(p);
fail("shold not be here");
} catch (PropertyValueException e) {

}
}


วิธีสุดท้าย ก็คือเราสามารถดึงเอาส่วน validate ไปทำที่ส่วน Presentation ก็ได้
โดยใช้ ClassValidator เข้ามาช่วย
ลองดูตัวอย่างของ TestCase กรณีนี้
public void testAppValidate() {
Province p = new Province();
ClassValidator<Province> pv = new ClassValidator<Province>(Province.class);
try {
pv.assertValid(p);
fail("fail");
} catch (InvalidStateException e) {
InvalidValue[] iv = pv.getInvalidValues(p);
assertEquals(1, iv.length);
assertEquals("name", iv[0].getPropertyName());
}
}

เราสามารถ override Validate Message ได้โดย
provide file ที่ชื่อ ValidatorMessages.properties
ตัวอย่าง file
validator.notNull=Hey. not null please

Related link from Roti

Rails Memo #2

ครั้งก่อนพูดถึงการตั้งชื่อ Controller, View ไป
คราวนี้ลองมาดูกฎการตั้งชื่อ Model บ้าง

Model จะมาคู่กับ Database Table เสมอ
โดยชื่อ Model ต้องเป็นเอกพจน์ ส่วนชื่อ Table ต้องเป็นพหูพจน์

class Property < ActiveRecord::Base

ชื่อ table ที่ประกบกับ model นี้ ก็ต้องเป็น properties

ที่น่าสนใจก็คือ Rails ใช้กฎอะไรในการแปลง เอกพจน์ เป็น พหูพจน์
class ที่เกี่ยวข้องในเรื่องนี้ อยู่ใน package ActiveSupport
มีชื่อว่า Inflections กับ Inflector
ลองดูตัวอย่าง ตารางการแปลงของ Rails ดู
  inflect.plural(/$/, 's')
inflect.plural(/s$/i, 's')
inflect.plural(/(ax|test)is$/i, '\1es')
inflect.plural(/(octop|vir)us$/i, '\1i')
inflect.plural(/(alias|status)$/i, '\1es')
...

inflect.irregular('person', 'people')
inflect.irregular('man', 'men')
inflect.irregular('child', 'children')
...

inflect.uncountable(%w(equipment information rice money species series fish sheep))


ถ้าอยากรู้ว่าอะไรแปลงเป็นอะไร ก็สามารถใช้ script/console ทดสอบดูได้
~/projects/rail/akando_dev $ script/console
Loading development environment.
>> "person".pluralize
=> "people"
>> "mouse".pluralize
=> "mice"
>>


ทีนี้กระโดดไปที่ scaffold บ้าง
เวลาที่เราสั่ง generate scaffold เราใช้คำสั่งต่อไปนี้
script/generate scaffold modelName
แน่นอน modelName ที่ระบุใน scaffold อยู่ในรูปเอกพจน์
แต่ชื่อของ controller ที่ scaffold generate ให้นี้จะอยู่ในรูป พหูพจน์
เช่น
script/generate scaffold Property

จะได้
class PropertiesController ใน file properties_controller.rb

เรื่องการใช้เอกพจน์ หรือพหูพจน์นี้ จริงๆพอใช้ไปสักพัก ก็จะเริ่มรู้สึก
เป็นธรรมชาติขึ้น (ฝรั่งคงไม่มีปัญหา เพราะเป็นภาษาเขา)
ซึ่งมันก็สื่อดีเหมือนกัน เช่น

Project.find(1)
ย่อมดีกว่า
Projects.find(1)
----
project = Project.find(1)
project.milestones.each {|milestone|
...
}
ดูดีกว่า
project.milestone.each {|milestone|
...
}

Related link from Roti