4 September 2016

bact

Forensic Service Act 2016 and the protection of personal data

Forensic Service Act of 2016

The Forensic Service Act B.E. 2559 (2016) (พระราชบัญญัติการให้บริการด้านนิติวิทยาศาสตร์ พ.ศ. 2559) has been announced on the Royal Gazette on 3 August 2016, after the National Legislative Assembly passed it on 10 June 2016. As the regulations about the handling of forensic data are yet to be announced, we don’t have an exact idea yet on how the process and conditions will look like. What we know at the moment is who is going to responsible for the making of those regulations.

Read the Act from NLA website, also comments from the Review Subcommittee of the NLA.

พ.ร.บ.การให้บริการด้านนิติวิทยาศาสตร์ พ.ศ. 2559 ประกาศในราชกิจจานุเบกษาแล้ว อ่านตัวกฎหมายและความเห็นของคณะกรรมาธิการวิสามัญพิจารณาร่างฯ

มีสามเรื่องหลักที่กฎหมายที่กำหนด คือ

  1. ขยายหน้าที่ของ สถาบันนิติวิทยาศาสตร์ กระทรวงยุติธรรม (หมวด 1) เช่น มาตรา 5 (5) “ส่งเสริมและพัฒนาการให้บริการด้านนิติวิทยาศาสตร์ของเอกชน”
  2. กำหนดให้ข้อมูลจากบริการนิติวิทยาศาสตร์ต้องเป็นความลับ กำหนดวิธีการเก็บรักษา การทำลาย และการเปิดเผย (หมวด 2)
  3. ตั้ง คณะกรรมการกำกับการให้บริการด้านนิติวิทยาศาสตร์ เพื่อกำกับดูแลเรื่องมาตรฐาน ค่าบริการ การอุทธรณ์ และการแลกเปลี่ยนข้อมูล (หมวด 3)หมวด 2 เรื่องข้อมูล มีสองมาตรา ว่าด้วยการจัดเก็บและทำลายข้อมูล (มาตรา 8) และการเปิดเผยข้อมูล (มาตรา 9) แต่รายละเอียดยังไม่มี ต้องรอคณะกรรมการฯประกาศ

Three main things this Act is doing are:

  1. Expanding duties of Ministry of Justice’s Central Institute of Forensic Science (สถาบันนิติวิทยาศาสตร์) (Chapter 1)
  2. Specifying how the forensic data should be handled (Chapter 2)
  3. Establishing Forensic Service Oversight Committee (คณะกรรมการกำกับการให้บริการด้านนิติวิทยาศาสตร์) who will regulating forensic standards, fees, appeal process, and the exchange of forensic data. (Chapter 3)

According to Section 3 of the Act, “data” in this Act means Any data that comes from the forensic service.

The “Data Chapter” or Chapter 2 of the Act is solely about the confidentially, preservation, and disclosure of data.

Section 8 Data is confidential. Central Institute of Forensic Science has duty to preserve and destroy the data, according to the criteria, methods, and conditions that the Committee will specify by announcing in the Royal Gazette.

Section 9 Data will only be disclose to the person who request for the forensic service. This should be done according to the criteria, methods, and conditions specified by the Committee. Exception is possible if it is a disclosure according to Court Order or Committee Resolution for the purpose of justice.

This means the details on conditions and process about the preservation and disclosure, or, in general, the life cycle of these potentially sensitive personal data are yet to be announced. All of them will be decided by the Forensic Service Oversight Committee, using the power given to them in Section 15 (4) [Preservation] and Section 15 (4/1) [Disclosure].

According to Section 10, the Committee will consist of

The Director of CIFS will also appointed no more than two officers from CIFS to act as Assistant Secretary for the Committee.

An expert committee member must be of Thai national and must be at least 35 years old (Section 11). He or she will serve for a period of 4 years and cannot serve for more than two terms (Section 12).

Noted that, if the [forensic] data is handled by a State agency, its privacy will be under the protection of the Official Information Act B.E. 2540 (1997). Yet, as you can see from Section 5 (5), the forensic service can be also come from private sector. But Thailand at the moment doesn’t have the law for general data protection outside the public sector yet.

The Data Protection Bill, which will fill the gap, has been proposed in different versions since more than a decade ago, but it is yet to be passed. The latest version of the Bill from July 2015, which has been reviewed by the Council of the State. It is expected to be submitted to NLA for hearing by the end of 2016.

So, keeps your eyes on the Forensic Service Oversight Committee and the forensic data regulations that they going to make. We hope they are going to have public consultations for that.

โดย bact ณ 4 September 2016 16:22 GMT

31 August 2016

MrChoke

Laravel 5.2: ใช้ Username และ Email login

ใช้ Laravel Framework มาได้สักพัก ก็เกือบปีละมั้ง ตอนนี้ออก 5.3 แล้วยังไม่ได้ลอง dev อยู่บน 5.2 และก็เพิ่งรู้ว่ามันมี LTS ด้วยรุ่นก่อนหน้าก็ 5.1 อะเข้าหัวเรื่องกันเลยดีกว่า ผมใช้ระบบ auth ของ laravel ซึ่งค่าเริ่มต้นให้มาจะใช้ email ในการ login อย่างเดียวก่อนหน้านี้ผมได้แก้ไขให้ user สมัครโดยกรอกชื่อ และ อื่นๆ รวมทั้ง username ไว้โดยยังไม่ได้ใช้ประโยนช์กับมันจนมาถึงวัน present ให้ user ใช้ตอนสมัครก็มีช่อง username ให้กรอกแต่ไม่ได้ใช้ประโยชน์ตอนที่กำลังแนะนำตัวผมเองก็รู้สึกว่า แล้วจะใส่มาทำไมในเมื่อไม่ใส่มา ก็เลยมานั่งไล่ code ในส่วน auth ใหม่พบว่าไม่ยากเท่าไหร่เพราะมีคนแนะนำไว้ เลยเอามาประยุกต์เข้ากับระบบ นั่ง debug อยู่ทั้งบ่าย ฮาๆ (ไหนว่าไม่ยาก) เลยบันทึกเอาไว้เดี๋ยววันหลังใช้อีก แก้แค่ที่เดียวคือ app/Http/Controllers/Auth/AuthController.php โดยไป Override [...]

โดย MrChoke ณ 31 August 2016 09:48 GMT

17 August 2016

Ott

อ่านผลตรวจเลือดด้วยตนเอง

แปะเก็บไว้


อ่านผลตรวจเลือดด้วยตนเอง (ควรจัดพิมพ์เก็บเอาไว้อ่านเทียบกับผลตรวจสุขภาพประจำปีนะครับ)

โดย นพ.สันต์ ใจยอดศิลป์

วันนี้ผมจะรวบยอดสอนการแปลผลการตรวจเคมีในเลือดให้ฟัง ท่านที่ถามมาคล้ายกันแต่ว่าผมไม่ได้ตอบก็ขอให้เอาวิธีแปลผลที่คุยกันวันนี้ไปแปลผลการตรวจของท่านเอาเองก็แล้วกัน

1. Blood chemistry แปลตรงๆว่าเคมีของเลือด หมายถึงระดับของสารต่างๆที่อยู่ในเลือดซึ่งก่อปฏิกิริยาเคมีได้ ซึ่งการเพิ่มขึ้นหรือลดลงของสารเหล่านี้ บ่งบอกไปถึงว่าจะมีโรคอะไรเกิดขึ้นในร่างกายบ้าง

 2. FBS = ย่อมาจาก fasting blood sugar แปลว่าระดับน้ำตาลในเลือดหลังการอดอาหารมาอย่างน้อย 8 ชั่วโมง เป็นการตรวจสถานะของโรคเบาหวานโดยตรง คือคนปกติค่านี้จะต่ำกว่า 100 mg/dL ถ้าของใครสูงเกิน 125 ก็ถือว่าเป็นเบาหวานแล้วอย่างบริบูรณ์

3. HbA1C = ย่อมาจาก hemoglobin A1C แปลว่าระน้ำตาลสะสมเฉลี่ยสามเดือนในเม็ดเลือดแดง มีความหมายคล้ายๆกับค่า FBS คือโดยคำนิยาม ถ้าน้ำตาลสะสมเฉลี่ยของของใครสูงกว่า 6.5% ก็ถือว่าเป็นโรคเบาหวานไปแล้วอย่างบริบูรณ์ ค่า HbA1C นี้ดีกว่าค่า FBS ในสองประเด็น คือ
3.1 ทำให้เราตรวจคัดกรองเบาหวานได้ทุกเมื่อ โดยไม่ต้องอดอาหารมาล่วงหน้า
3.2 การที่มันสะท้อนค่าน้ำตาลในเลือดในช่วงเวลาสามเดือนย้อนหลัง จึงตัดปัญหาระดับน้ำตาลวูบวาบในช่วงหนึ่งวันก่อนการตรวจ คือคนไข้บางคนที่จะทำตัวดีเฉพาะสองสามวันก่อนไปหาหมอเพื่อให้น้ำตาลในเลือดดูดี พอคล้อยหลังหมอตรวจเสร็จก็ออกมาสั่งไอติมมากินเป็นกะละมังให้หายอยาก คนไข้แบบนี้การตรวจ HbA1C จะทำให้ทราบสถานะที่แท้จริงของเบาหวานดีกว่า

4. BUN =  ย่อมาจาก blood urea nitrogen แปลว่าไนโตรเจนในรูปของยูเรีย  ตัวยูเรียนี้เป็นเศษของเหลือจากการเผาผลาญโปรตีนที่ตับ ซึ่งต้องถูกกำจัดทิ้งโดยไต การวัดระดับค่าของ BUN เป็นตัวบ่งบอกว่าเลือดไหลไปกรองที่ไตมากพอหรือไม่ ในภาวะที่เลือดไหลไปกรองที่ไตน้อยลง เช่นในภาวะร่างกายขาดน้ำ หรือสูญเสียเลือดไปทางอื่นเช่นเลือดออกในทางเดินอาหาร หรือในภาวะช็อก ระดับของ BUN จะสูงขึ้นอย่างรวดเร็ว ค่าปกติของ BUN คือ 8-24 

5. Cr = เขียนเต็มว่า Creatinine แปลว่าเศษเหลือจากการสลายตัวของกล้ามเนื้อ คือกล้ามเนื้อของคนเรานี้มันสลายตัวและสร้างใหม่อยู่ตลอดเวลา คนมีกล้ามมากก็สลายตัวมากสร้างมาก Cr ซึ่งเป็นเศษซากที่สลายตัวออกมาจะถูกไตขับทิ้งไป แต่ในกรณีที่ไตเสียการทำงาน เช่นเป็นโรคไตเรื้อรัง ไตจะขับ Cr ออกทิ้งไม่ทันกับที่กล้ามเนื้อสลายออกมา ทำให้ระดับ Cr ในเลือดสูงผิดปกติ ค่าปกติของมันคือ 0.7-1.2 mg/dL 

6. eGFR = เรียกสั้นๆว่า จีเอฟอาร์. ย่อมาจาก estimated glomerular filtration rate แปลว่าอัตราการไหลของเลือดผ่านตัวกรองของไตในหนึ่งนาที ค่านี้ได้จากการคำนวณเอาจาก Cr กับอายุ และชาติพันธุ์ของเจ้าตัว ห้องแล็บที่ยังไม่ทันสมัยจะไม่รายงานค่านี้ ถ้าเจ้าตัวอยากทราบค่านี้ต้องเอาค่า Cr ที่ได้ไปอาศัย GFR calculator ตามเว็บในเน็ทคำนวณให้ ค่าจีเอฟอาร์.นี้มีประโยชน์มากในแง่ที่ใช้แบ่งระดับความรุนแรงของคนที่ Cr ผิดปกติอย่างคุณนี้ว่ามีความรุนแรงเป็นโรคไตเรื้อรังระยะไหนของ 5 ระยะ กล่าวคือ 
ระยะที่ 1 ตรวจพบพยาธิสภาพที่ไตแล้ว แต่ไตยังทำงานปกติ (จีเอฟอาร์ 90 มล./นาที ขึ้นไป) 
ระยะที่ 2 ตรวจพบพยาธิสภาพที่ไตแล้ว และไตเริ่มทำงานผิดปกติเล็กน้อย (จีเอฟอาร์ 60-89 มล./นาที)
ระยะที่ 3 ไตทำงานผิดปกติปานกลาง ไม่ว่าจะตรวจพบพยาธิสภาพที่ไตหรือไม่ก็ตาม (จีเอฟอาร์ 30-59 มล./นาที
)ระยะที่ 4 ไตทำงานผิดปกติมาก (จีเอฟอาร์ 15-29 มล./นาที)
ระยะที่ 5. ระยะสุดท้าย (จีเอฟอาร์ต่ำกว่า 15 หรือต้องล้างไต)    

 7. Uric acid ก็คือกรดยูริกที่เป็นต้นเหตุของโรคเก้าท์นั่นแหละ ค่าปกติของกรดยูริกในเลือดคือ 3.4-7.0 

8. Triglyceride คือไขมันไตรกลีเซอไรด์ ซึ่งเป็นไขมันก่อโรคชนิดหนึ่งในร่างกายเรา ระดับที่สูงจนต้องใช้ยาคือเกิน 200 mg/dl 

9. HDL-cholesterol เรียกสั้นๆว่าเอ็ช.ดี.แอล. เรียกอีกอย่างว่า “ไขมันดี” เพราะมันเป็นไขมันที่ดึงไขมันที่พอกหลอดเลือดออกไปจากหลอดเลือด ดังนั้นยิ่งมีเอ็ช.ดี.แอล.มากก็ยิ่งดี คนปกติควรมีเอ็ชดีแอล.เกิน 40 mg/dl ขึ้นไป 

10. LDL-cholesterol เรียกสั้นๆว่าแอลดีแอล. หรือเรียกอีกอย่างว่า “ไขมันเลว” เพราะมันเป็นตัวไขมันที่พอกอยู่ที่ผนังหลอดเลือดและเป็นไขมันก่อโรคโดยตรง การจะตัดสินว่าคนไข้คนไหนควรกินยาลดไขมันเมื่อไหร่ก็ตัดสินกันจากระดับแอลดีแอล.นี่แหละ โดยเทียบกับความเสี่ยงในการเป็นโรคที่แต่ละคนมีเป็นทุนอยู่แล้ว  กล่าวคือ
- ถ้ามีความเสี่ยงต่ำ จะให้เริ่มทานยาลดไขมันเมื่อ LDL มากกว่า 160
- ถ้ามีความเสี่ยงปานกลาง จะให้เริ่มทานยาลดไขมัน
เมื่อ LDL มากกว่า 130
- ถ้ามีความเสี่ยงสูง หรือเป็นโรคหัวใจ หรือเบาหวาน หรืออัมพาตแล้ว จะให้เริ่มทานยาลดไขมันเมื่อ LDL มากกว่า 100   

11. Total Cholesterol หมายถึงโคเลสเตอรอลรวมในร่างกาย เป็นค่ารวมของไขมันสามอย่าง กล่าวคือ    
โคเลสเตอรอลรวม = ไขมันดี (HDL) + ไขมันเลว (LDL) + หนึ่งในห้าของไขมันไตรกลีเซอไรด์      สมัยก่อนเราใช้ค่าโคเลสเตอรอลรวมตัวนี้ตัวเดียวในการประเมินไขมันในเลือด จึงได้กำหนดค่าปกติไว้ว่าถ้าสูงเกิน 240 mg/dl จึงจะถือว่าสูงและเริ่มใช้ยา 
แต่สมัยนี้เราไม่ค่อยจะดูค่าโคเลสเตอรอลรวมกันเท่าไหร่แล้ว เราดูเจาะลึกลงไปถึงไขมันแต่ละชนิด และตัดสินใจใช้หรือไม่ใช้ยาจากระดับไขมันเลว (LDL) โดยไม่สนใจโคเลสเตอรอลรวมแล้ว เพราะค่านี้มักชักนำให้เข้าใจผิด ยกตัวอย่างเช่นถ้าดูค่าโคเลสเตอรอลรวมได้ 214 ซึ่งก็แค่สูงเกินพอดีไปบ้างแต่ไม่สูงถึงกับต้องใช้ยา แต่ว่าจริงๆแล้วเป็นความเข้าใจผิด เพราะค่าโคเลสเตอรอลรวมดูต่ำอยู่ได้เพราะมีไขมันดี (HDL) ต่ำกว่าปกติ เลยพลอยทำให้ค่าโคเลสเตอรอลรวมต่ำไปด้วย ทั้งๆที่เป็นคนมีไขมันเลวอยู่ในระดับสูงถึงขั้นต้องใช้ยาแล้ว 

12. AST(SGOT) = ย่อมาจาก aspartate transaminase หรือชื่อเก่าว่า serum glutamic oxaloacetic transaminase เป็นเอ็นไซม์ที่ปกติอยู่ในเซลของตับ ซึ่งจะไม่ออกมาในเลือด หากมีเอ็นไซม์ตัวนี้ออกมาในเลือดมากก็แสดงว่าเซลตับกำลังได้รับความเสียหาย เช่นอาจจะมีตับอักเสบจากการติดเชื้อหรือจากสารพิษ หรือแม้กระทั้งจากแอลกอฮอล์ และไขมันแทรกเนื้อตับ ค่าปกติของ AST คือไม่เกิน 40 IU/L 

13. ALT (SGPT) = ย่อมาจาก alamine amintransferase หรือชื่อเก่าว่า serum glutamic pyruvic transaminase เป็นเอ็นไซม์ที่ปกติอยู่ในเซลของตับเช่นเดียวกับ AST และจะออกมาในเลือดเมื่อเซลตับได้รับความเสียหายเช่นกัน โดยเฉพาะอย่างยิ่งในกรณีที่มีเนื้องอกอุดตันทางเดินน้ำดี ค่าปกติของ ALT คือไม่เกิน 34 IU/L 

14. Alkaline Phosphatase = เป็นเอ็นไซม์ที่อยู่ในเซลของตับ ทางเดินน้ำดี และของกระดูกเป็นส่วนใหญ่ ความหมายของเอ็นไซม์ตัวนี้หากมันสูงขึ้นคืออาจจะมีปัญหาที่ทางเดินน้ำดี ตับ หรือกระดูก ค่าปกติในผู้ชายผู้ใหญ่ไม่เกิน 128 U/L

15. GTT = ย่อมาจาก gamma glytamyl transpeptidase เป็นเอ็นไซม์ในเซลตับและทางเดินน้ำดีเช่นเดียวกับ ALT มีความไวต่อความเสียหายของเซลตับมากกว่า แต่ขาดความจำเพาะเจาะจง หมายความว่าเมื่อ GTT สูงจะเกิดจากอะไรก็ได้ที่อาจจะไม่ใช่เรื่องของตับ เช่นอาจมีปัญหาที่ตับอ่อน ที่หัวใจ ที่ปอด หรือแม้กระทั่งเป็นเบาหวาน อ้วน หรือดื่มแอลกอฮอล์ ก็ทำให้ GTT สูงได้ สารตัวนี้จึงไม่มีประโยชน์ในการคัดกรองโรคเลย 

16. HBs Ag = ย่อมาจาก hepatitis B surface antigen แปลว่าตัวไวรัสตับอักเสบบี.ซึ่งตรวจจากโมเลกุลที่ผิวของมัน ถ้าตรวจได้ผลบวกก็แปลว่ามีเชื้อไวรัสตับอักเสบบี.อยู่ในตัว หากตรวจได้ผลลบ ก็แปลว่าไม่มีเชื้อไวรัสตับอักเสบบี

17. Anti HBs = ย่อมาจาก antibody to hepatitis B surface antigen แปลว่าภูมิต้านทานต่อไวรัสตับอักเสบบี. หากตรวจได้ผลบวกก็แปลว่าคุณมีภูมิคุ้มกันต่อไวรัสบี.แล้ว ไม่ต้องไปแสวงหาการฉีดวัคซีน

โดย Pattara Kiatisevi (noreply@blogger.com) ณ 17 August 2016 14:35 GMT

13 August 2016

Kitt

do-release-upgrade and PHP7

16.04.1 ออกมาได้ประมาณหนึ่งสัปดาห์ 14.04 ก็เริ่มจะ upgrade กันได้ วันนี้สั่ง do-release-upgrade เรียบร้อยดี ลง PHP7 เพิ่ม / เอา PHP5 ออก / แก้ไข socket path = เว็บกลับมาปกติ ง่ายเกินไปนะ :P

โดย kitty ณ 13 August 2016 14:08 GMT

2 July 2016

Kitt

ceph

วันนี้ ceph เดี้ยง สืบพบว่ามาจาก monitor node 2 ใน 3 ตัว ..  ทั้งสองตัว เป็น VM connect ได้ daemon running  แต่ disk ของตัว host เป็น read-only .. พอ monitor พยายามบันทึกข้อมูลลง disk ไม่ได้มันก็ค้าง พอ monitor ค้าง ceph cluster ทั้งก้อนหยุดทำงาน ได้ใช้ท่า troubleshooting: stop monitor / dump monmap / ลบ monitor node ที่ใช้งานไม่ได้ออกไปจาก monmap / inject monmap ตัวใหม่เข้า monitor node ที่ใช้งานได้ restart monitor … Continue reading ceph

โดย kitty ณ 2 July 2016 05:06 GMT

30 June 2016

Kitt

Password authentication must die .. soon.

Password authentication depends on user input. To make it safe, one of the requirement is that you need to do it safely and quickly enough and hope that nobody could catch what you type on the keyboard. Nowadays, we can’t hope such. With naked eyes, we can simply read gestures, types, presses most of people … Continue reading Password authentication must die .. soon.

โดย kitty ณ 30 June 2016 07:39 GMT

29 June 2016

Thep

LibThai 0.1.25 : More on Thread-safety

LibThai 0.1.25 ออกแล้ว ความเปลี่ยนแปลงหลักของรุ่นนี้อยู่ที่เรื่อง API ใหม่ที่ thread-safe กว่าเดิม และเรื่องย่อย ๆ คือการแก้ปัญหาการคอมไพล์ด้วย GCC 6 และการปรับพจนานุกรมตัดคำตามปกติ

Thread Safety

ในรุ่น 0.1.23 ได้ทำเรื่อง thread safety ไปแล้วส่วนหนึ่ง จากประเด็นที่พบใน Pango เมื่อมีหลายเธรดพยายามเรียกฟังก์ชันตัดคำพร้อมกัน ทำให้เกิดการแย่งใช้ free list ดังที่เคยอธิบายไว้ใน blog เก่า แต่ก็ยังแก้ไม่หมดจดพอ ดังที่คุณ Mark Brown ได้รายงานมาใน กลุ่มเมล Thai Linux/FOSS developers ว่ายังเหลืออีกจุดหนึ่ง คือขณะเปิดพจนานุกรมเป็นการภายในในการเรียกครั้งแรก เพราะจะยังมีการแย่งกันเปิดพจนานุกรมจนเกิดออบเจกต์พจนานุกรมหลายชุด แม้สุดท้ายจะใช้งานแค่ชุดเดียวและโปรแกรมก็ไม่แครช แต่ออบเจกต์ชุดที่เหลือก็เปลืองเนื้อที่ในหน่วยความจำ และจะไม่ถูกทำลายเมื่อจบโปรแกรมอีกด้วย

วิธีแก้ปัญหาได้พัฒนามาเป็นขั้นเป็นตอนดังนี้ :-

  1. ใช้ mutex ขณะเปิดพจนานุกรม เพื่อให้มีเพียงเธรดเดียวที่เปิด เธรดที่เหลือแค่รอใช้ แต่ปัญหาคือ mutex ของแต่ละ OS จะเรียกไม่เหมือนกัน (บน Linux และ Unix-like OS ทั้งหลาย ใช้ POSIX thread ส่วนวินโดวส์ใช้ Mutex Object ของตัวเอง แม้จะมี pthreads-win32 เป็น wrapper ให้ใช้ แต่ก็ยังต้องสร้างระบบ build และทดสอบขึ้นมาอีก) การจะใช้ mutex ใน libthai จะต้องสร้าง layer ใหม่เพื่อให้ยังคงทำงานข้ามแพลตฟอร์มได้ เป็นงานที่ใหญ่พอสมควรเมื่อเทียบกับปัญหาที่แก้
  2. แยกฟังก์ชันเปิดพจนานุกรมออกมาต่างหาก เป็นแนวคิดที่คุณ Mark Brown ปิ๊งขึ้นมาระหว่างทำอีกประเด็นหนึ่ง คือ การอนุญาตให้ระบุแฟ้มพจนานุกรมที่จะโหลด สำหรับใช้ในกรณีที่ผู้ใช้ไม่ต้องการใช้พจนานุกรมมาตรฐานของ libthai ซึ่งเมื่อกำหนดฟังก์ชันนี้ขึ้นมาแล้ว ก็จะเกิดขั้นตอนใหม่เพิ่มขึ้นก่อนที่ผู้ใช้จะตัดคำ คือการเช็กและเปิดพจนานุกรม ซึ่งผู้ใช้สามารถเรียกใช้ใน critical region ที่มีการล็อคด้วย mutex เองได้ กลายเป็นการยิงปืนนัดเดียวได้นกสองตัว ดังที่คุณ Mark Brown ได้อธิบายมาใน อีกกระทู้หนึ่ง
  3. กำหนด type ThBrk ผมชอบแนวคิดของคุณ Mark Brown ที่ทำให้สามารถเลี่ยงการสร้าง portability layer เพิ่มได้ จึงได้ generalize ออกมาเป็น API ชุดใหม่ คือให้ผู้ใช้สร้างออบเจกต์ชนิด ThBrk (ซึ่งภายในเก็บพจนานุกรมที่เปิดแล้ว) ภายใต้การปกป้องด้วย mutex ในตอนต้น แล้วจึงเรียกฟังก์ชันตัดคำต่าง ๆ แบบขนานตามต้องการ ดังที่ผมได้แสดงความเห็นต่อมาในกระทู้ดังกล่าว คลาส ThBrk นี้ สามารถซ่อนรายละเอียดเพื่อรองรับ implementation แบบอื่นในอนาคตได้ถ้าต้องการ เช่น การใช้สถิติ tri-gram ฯลฯ แต่ในขณะนี้เราจะใช้พจนานุกรมเพียงอย่างเดียวก่อน

API นี้มีการเปลี่ยนชื่อไปมาเพื่อความชัดเจน ในแบบสุดท้าย สรุปว่าตัวอย่างการใช้งานจะเป็นแบบนี้ :-

  // mutex lock here
  ThBrk *brk = th_brk_new (dictpath);
  // mutex unlock here

  // works in parallel
  int pos[N];
  int res = th_brk_find_breaks (brk, str, pos, N);

  // mutex lock here
  th_brk_delete (brk);
  // mutex unlock here

API เดิมจะยังคงมีอยู่เพื่อ backward compatibility โดยจะเป็น wrapper ที่แอบเปิดพจนานุกรมเป็นการภายในเช่นเดิม (ซึ่งไม่ thread-safe) ก่อนเรียก API ชุดใหม่ แต่จะเริ่ม deprecate API เก่าตั้งแต่รุ่นนี้เป็นต้นไป เพื่อให้ผู้ใช้เปลี่ยนไปใช้ API ชุดใหม่แทน ดังนี้ :-

โดยผู้ใช้ต้องสร้างออบเจกต์ชนิด ThBrk ต่างหากเพื่อส่งให้ฟังก์ชันเหล่านี้ และทำลายเมื่อใช้งานเสร็จ

GCC 6

การปรับโค้ดอีกส่วนหนึ่งเป็นส่วนที่สะสมมาตั้งแต่ช่วงที่ Debian กำหนดให้ใช้ GCC 6 เป็นรุ่น default ที่จะใช้ใน Stretch และได้รับรายงานจากคุณ Martin Michlmayr ใน Debian #811690 ว่าแพกเกจ scim-thai มีปัญหาในการคอมไพล์ด้วย GCC 6 ซึ่งต้นเหตุอยู่ที่ header file หนึ่งของ libthai จึงปรับแก้เสีย

Word Break Dictionary

ก็เป็นปกติเหมือน libthai ทุกรุ่น ที่จะมีการปรับพจนานุกรมตัดคำตามคำที่พบใหม่อยู่เสมอ ที่ผ่านมาผมไม่เคยรีวิวเลยว่ามีคำแบบไหนบ้างที่เพิ่มเข้ามา คิดว่านำเสนอบ้างก็น่าจะดี

คำที่น่าสนใจที่เพิ่มมาในรุ่นนี้:

และเช่นเคย ส่งเข้า Debian เรียบร้อยแล้วครับ

โดย Thep (noreply@blogger.com) ณ 29 June 2016 05:08 GMT

14 June 2016

bact

Quick notes on Thailand’s new cybercrime law amendment (26 Apr 2016 rev)

Quick points for my international friends who want to get some gists about the development of Thailand’s new amendment of Computer-related Crime Act, as of 14 June 2016. Here I discussed the timeline, small notes on two different revisions on April 2016, and points of concerns regarding freedom of expression, privacy, and encryption.

If you don’t have much time, look at Section 14 (1) [online defamation], 14 (2) [“public safety”], 15 para. 3 [burden of proof to the intermediary], 17/1 [Settlement Commission], 18 (7) [investigative power to access encrypted data-at-rest], 20 (4) [Computer Data Screening Committee can block content that is totally legal], and 20 para. 5 [will be used to circumvent data-in-transit encryption].

Thai Netizen Network also made some recommendations to the Bill (updated 28 June 2016).

Timeline

Read the Bill (in English)

Points of Concerns

1. Criminalisation of Speech and Computer Data

2. Disproportionate Intermediary Liability

3. Unpredicability of Law — Judicial Process

4. Expanded Investigative Power — Access to Encrypted Data-at-Rest

5. Expanded Information Control

6. Disintegrity of Secured Communication

Stop This

Don’t agree with the Amendment proposal?
Sign the Petition: https://change.org/singlegatewayreturn
and keep spread it around.

Follow more updates and actions from Thai Netizen Network website at https://thainetizen.org and its Facebook page at https://www.facebook.com/thainetizen.

โดย bact ณ 14 June 2016 09:35 GMT

Thep

Fonts-TLWG 0.6.3

Fonts-TLWG 0.6.3 ออกแล้ว เมื่ออาทิตย์ที่แล้ว แต่เพิ่งจะได้เขียน blog บันทึกหลังจากที่เตรียมแพกเกจเพื่ออัปโหลดในที่ต่าง ๆ เสร็จ คือที่ Debian และ CTAN

รุ่นนี้เป็นรุ่นแรกที่ ออกรุ่นจาก GitHub หลังจากที่ ประกาศย้าย repository ของ TLWG ไปที่ GitHub เมื่อเดือนที่แล้ว แต่ยังคงใช้ linux.thai.net เป็นที่ประกาศหลักตามเดิม เพื่อความต่อเนื่องกับรุ่นก่อน ๆ

ความเปลี่ยนแปลงหลักที่เกิดขึ้นในรุ่นนี้ คือการเปลี่ยนให้ฟอนต์ Loma เป็นฟอนต์ UI หลักแทน Waree อันเนื่องมาจาก รายงานบั๊กของพี่สัมพันธ์ พร้อม follow-up ว่าฟอนต์ Waree นั้นตัวสูงเกินไปจนถูกขริบในบางเว็บ เช่น Facebook แต่ Loma นั้นเตี้ยพอที่จะเล็ดรอดมาได้ (เหตุผลก็คือ Waree นั้นออกแบบเพื่อเตรียมเพิ่มอักษรไทยให้กับฟอนต์ DejaVu Sans จึงมี glyph ละตินของ DejaVu Sans ซึ่งตัวสูงอยู่แล้วเป็นตัวตั้ง ส่วน Loma นั้น เข้าใจว่าออกแบบโดยอิสระของตัวเอง) หลังจากทดสอบและฟังความเห็นของหลาย ๆ ท่านที่มาคอมเมนต์ ก็เห็นว่าควรเลื่อนอันดับของฟอนต์ Loma ขึ้นมาสูงกว่า Waree ในการเลือกฟอนต์ sans-serif ของ fontconfig

ในการเลื่อนขั้นนั้น ตามหลักแล้วควรจะทำได้ง่าย ๆ ด้วยการเปลี่ยนลำดับแฟ้ม config ของ fontconfig ให้ Loma ขึ้นก่อน Waree เช่น เปลี่ยนชื่อแฟ้ม /etc/fonts/conf.d/64-12-tlwg-loma.conf ในรุ่น 0.6.2 ให้เป็น 64-10-tlwg-loma.conf แต่ทำแค่นั้นไม่ได้ช่วยให้ Loma มาก่อน Waree ได้ เพราะยังมีกฎชุด synthetic อีกชุดหนึ่งเข้ามามีส่วนด้วย ดังผลลัพธ์หลังเปลี่ยนชื่อแฟ้มดังกล่าว ก็ยังคง match sans-serif ได้ Waree เช่นเดิม (ในรุ่น 0.6.2):

$ cd /etc/fonts/conf.d
$ sudo mv 64-12-tlwg-loma.conf 64-10-tlwg-loma.conf
$ fc-match sans-serif
Waree.otf: "Waree" "Regular"

สาเหตุคือฟอนต์ Waree มีการจำลองตัวเองเพื่อทดแทนฟอนต์ Tahoma ด้วยการห้อยชื่อตัวเองในลำดับต่อจาก Tahoma (ในไฟล์ 89-tlwg-waree-synthetic.conf) แต่ด้วยความที่ Tahoma ได้ถูกกำหนดให้เป็น preferred font ตัวหนึ่งของละติน (ในไฟล์ 60-latin.conf) ซึ่งมาก่อนภาษาอื่น ๆ การจำลอง Tahoma ของ Waree จึงทำให้ Waree กลายเป็นฟอนต์ละตินตัวหนึ่งที่มาก่อนภาษาอื่น ๆ ไปด้วย!

รายละเอียดทางเทคนิคของการตรวจสอบ ผู้ที่สนใจสามารถอ่านได้ที่ส่วนท้ายของ blog

ฉะนั้น การจะเลื่อนขั้น Loma ขึ้น จึงติดที่กฎชุด synthetic ของ Waree นี้

แล้วกฎ synthetic นี้มาจากไหน? มันเริ่มมาจากแนวคิดการจำลองฟอนต์ที่ผู้ใช้นิยมใช้ในเอกสารต่าง ๆ บนวินโดวส์ด้วยฟอนต์ที่มีในชุด Fonts-TLWG เช่น จำลอง Angsana ด้วย Kinnari, จำลอง Browallia ด้วย Garuda ฯลฯ ดังมีบันทึกไว้ใน blog เก่าเมื่อปี 2550 ซึ่งฟอนต์ต่าง ๆ ก็มีเค้าหน้าตาให้จำลองกันได้ จนกระทั่งมาเจอกรณีการใช้ฟอนต์ MS Sans Serif และ Tahoma ในเว็บ จึงได้พยายามทดแทนด้วยฟอนต์ Loma และ Waree ตามลำดับ ดังอ้างถึงใน blog เก่าเมื่อปี 2552 โดยที่ทั้งสองฟอนต์นี้ไม่ได้มีเค้าของฟอนต์ที่จำลองเลย เพียงแต่ต้องการอุดช่องว่างของการแสดงหน้าเว็บเท่านั้น

กฎนี้เคยถูกรายงานว่าสร้างปัญหาให้กับภาษาอื่น เพราะ Waree จะโผล่มาแทน Tahoma ทั้ง ๆ ที่ตัวใหญ่กว่า Tahoma (LP #434054) ทำให้เคยตัดกฏนี้ออกไปชั่วระยะหนึ่ง แต่ก็เพิ่มกลับเข้ามาพร้อมกับการตรวจสอบภาษาเพิ่มเติมเพื่อให้ apply กับภาษาไทยเท่านั้น (LP #539008) ดังบันทึกใน thaifonts-scalable 0.4.14 แต่ในเมื่อมันมารบกวนการจัดอันดับฟอนต์ sans-serif ไทยทั้งระบบ ก็เห็นควรว่าควรตัดกฎ synthetic นี้ออก แล้วปล่อยให้ฟอนต์ sans-serif ที่ได้อันดับสูงสุดมาอุด Tahoma เอา

เมื่อตัดกฎ synthetic ออก ฟอนต์ Loma ก็ได้อันดับสูงกว่า Waree แล้ว

อีกประเด็นหนึ่งที่พบระหว่างทดลองใช้ Loma เป็นฟอนต์ UI หลัก นอกเหนือจากขนาดที่เล็กลงถนัดตาที่ใช้เวลาสักพักก็จะชินแล้ว ก็มีเรื่องความกว้างของอักขระเว้นวรรค (space) ที่กว้างเกินพอดี และเมื่อเทียบกับฟอนต์ทั่วไปก็ยิ่งยืนยันได้ จึงได้ปรับลดความกว้างของอักขระเว้นวรรคให้แคบลง ซึ่งก็ทำให้ย่อหน้าภาษาอังกฤษไม่ดูโหรงเหรงจนเกินไป

ก่อนปรับ:

Loma spacing in 0.6.2

หลังปรับ:

Loma spacing in 0.6.3

ทั้งหมดนั้น เสิร์ฟถึงคุณแล้วในรุ่น 0.6.3 ครับ!


ต่อไปนี้เป็นวิธีตรวจสอบการ apply กฎของ fontconfig ด้วยตัวเอง ซึ่งทำให้เห็นว่ากฎ synthetic ใน 0.6.2 ทำให้ Waree ล้ำหน้าฟอนต์ไทยอื่น ๆ ได้อย่างไร

วิธีตรวจสอบตามที่ เอกสาร fontconfig ได้อธิบายไว้ คือกำหนดตัวแปร environment FC_DEBUG โดยในที่นี้เราสนใจการ edit match pattern ในกฎต่าง ๆ ก็กำหนดค่าเป็น 4 แล้วเรียก fc-match ดังนี้:

$ FC_DEBUG=4 fc-match sans-serif

มันจะพ่นข้อความแสดงการ edit match pattern ในแต่ละขั้นออกมายืดยาว ก็อาจจะ redirect ลงแฟ้มแล้วมาตรวจสอบดู ก็จะพบขั้นตอนที่น่าสนใจคือ:

...

FcConfigSubstitute test pattern any family Equal(ignore blanks) "sans-serif"
Substitute Edit family Prepend "Bitstream Vera Sans" Comma "DejaVu Sans" Comma "
Verdana" Comma "Arial" Comma "Albany AMT" Comma "Luxi Sans" Comma "Nimbus Sans L
" Comma "Helvetica" Comma "Lucida Sans Unicode" Comma "BPG Glaho International" 
Comma "Tahoma"

Prepend list before  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) 
[marker] "sans-serif"(s) "sans-serif"(w)
Prepend list after  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "
Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w)
 "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG 
Glaho International"(w) "Tahoma"(w) "sans-serif"(s) "sans-serif"(w)

...

กฎนี้มาจาก 60-latin.conf ของ fontconfig เอง ที่เพิ่ม prefer list ของ sans-serif โดยมี Tahoma พ่วงอยู่ด้วย

จากนั้น ก็มีการ edit match pattern ต่อ ๆ มา จนมาถึงตรงนี้:

...

FcConfigSubstitute test pattern any family Equal(ignore blanks) "sans-serif"
Substitute Edit family Prepend "Loma"

Prepend list before  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) 
"Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w
) "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG
 Glaho International"(w) "Tahoma"(w) [marker] "sans-serif"(s) "sans-serif"(w)
Prepend list after  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "
Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w)
 "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG 
Glaho International"(w) "Tahoma"(w) "Loma"(w) "sans-serif"(s) "sans-serif"(w)

...

FcConfigSubstitute test pattern any family Equal(ignore blanks) "sans-serif"
Substitute Edit family Prepend "Waree"

Prepend list before  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) 
"Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w
) "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG
 Glaho International"(w) "Tahoma"(w) "Loma"(w) [marker] "sans-serif"(s) "sans-se
rif"(w)
Prepend list after  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "
Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w)
 "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG 
Glaho International"(w) "Tahoma"(w) "Loma"(w) "Waree"(w) "sans-serif"(s) "sans-s
erif"(w)

...

ซึ่งก็ดูเรียบร้อยดี Loma น่าจะ match ก่อน Waree แล้ว จนกระทั่งมาถึงตรงนี้:

...

FcConfigSubstitute test pattern any lang Contains "th"
FcConfigSubstitute test pattern any family Equal "Tahoma"
Substitute Edit family Append "Waree"

Append list before  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "
Bitstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w)
 "Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG 
Glaho International"(w) "Tahoma"(w) [marker] "Loma"(w) "Waree"(w) "Garuda"(w) "U
mpush"(w) "Laksaman"(w) "Meera"(w) "Khmer OS"(w) "Nachlieli"(w) "Lucida Sans Uni
code"(w) "Yudit Unicode"(w) "Kerkis"(w) "ArmNet Helvetica"(w) "Artsounk"(w) "BPG
 UTF8 M"(w) "Waree"(w) "Loma"(w) "Garuda"(w) "Umpush"(w) "Saysettha Unicode"(w) 
"JG Lao Old Arial"(w) "GF Zemen Unicode"(w) "Pigiarniq"(w) "B Davat"(w) "B Comps
et"(w) "Kacst-Qr"(w) "Urdu Nastaliq Unicode"(w) "Raghindi"(w) "Mukti Narrow"(w) 
"padmaa"(w) "Hapax Berbère"(w) "MS Gothic"(w) "UmePlus P Gothic"(w) "SimSun"(w) 
"PMingLiu"(w) "WenQuanYi Zen Hei"(w) "WenQuanYi Bitmap Song"(w) "AR PL ShanHeiSu
n Uni"(w) "AR PL New Sung"(w) "MgOpen Moderna"(w) "MgOpen Modata"(w) "MgOpen Cos
metica"(w) "VL Gothic"(w) "IPAMonaGothic"(w) "IPAGothic"(w) "Sazanami Gothic"(w)
 "Kochi Gothic"(w) "AR PL KaitiM GB"(w) "AR PL KaitiM Big5"(w) "AR PL ShanHeiSun
 Uni"(w) "AR PL SungtiL GB"(w) "AR PL Mingti2L Big5"(w) "MS ゴシック"(w) "ZYSo
ng18030"(w) "NanumGothic"(w) "UnDotum"(w) "Baekmuk Dotum"(w) "Baekmuk Gulim"(w) 
"KacstQura"(w) "Lohit Bengali"(w) "Lohit Gujarati"(w) "Lohit Hindi"(w) "Lohit Ma
rathi"(w) "Lohit Maithili"(w) "Lohit Kashmiri"(w) "Lohit Konkani"(w) "Lohit Nepa
li"(w) "Lohit Sindhi"(w) "Lohit Punjabi"(w) "Lohit Tamil"(w) "Meera"(w) "Lohit M
alayalam"(w) "Lohit Kannada"(w) "Lohit Telugu"(w) "Lohit Oriya"(w) "LKLUG"(w) "F
reeSans"(w) "Arial Unicode MS"(w) "Arial Unicode"(w) "Code2000"(w) "Code2001"(w)
 "sans-serif"(s) "Arundina Sans"(w) "Roya"(w) "Koodak"(w) "Terafik"(w) "sans-ser
if"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-ser
if"(w) "sans-serif"(w) "sans-serif"(w)
Append list after  "DejaVu Sans"(w) "DejaVu LGC Sans"(w) "DejaVu LGC Sans"(w) "B
itstream Vera Sans"(w) "DejaVu Sans"(w) "Verdana"(w) "Arial"(w) "Albany AMT"(w) 
"Luxi Sans"(w) "Nimbus Sans L"(w) "Helvetica"(w) "Lucida Sans Unicode"(w) "BPG G
laho International"(w) "Tahoma"(w) "Waree"(w) "Loma"(w) "Waree"(w) "Garuda"(w) "
Umpush"(w) "Laksaman"(w) "Meera"(w) "Khmer OS"(w) "Nachlieli"(w) "Lucida Sans Un
icode"(w) "Yudit Unicode"(w) "Kerkis"(w) "ArmNet Helvetica"(w) "Artsounk"(w) "BP
G UTF8 M"(w) "Waree"(w) "Loma"(w) "Garuda"(w) "Umpush"(w) "Saysettha Unicode"(w)
 "JG Lao Old Arial"(w) "GF Zemen Unicode"(w) "Pigiarniq"(w) "B Davat"(w) "B Comp
set"(w) "Kacst-Qr"(w) "Urdu Nastaliq Unicode"(w) "Raghindi"(w) "Mukti Narrow"(w)
 "padmaa"(w) "Hapax Berbère"(w) "MS Gothic"(w) "UmePlus P Gothic"(w) "SimSun"(w)
 "PMingLiu"(w) "WenQuanYi Zen Hei"(w) "WenQuanYi Bitmap Song"(w) "AR PL ShanHeiS
un Uni"(w) "AR PL New Sung"(w) "MgOpen Moderna"(w) "MgOpen Modata"(w) "MgOpen Co
smetica"(w) "VL Gothic"(w) "IPAMonaGothic"(w) "IPAGothic"(w) "Sazanami Gothic"(w
) "Kochi Gothic"(w) "AR PL KaitiM GB"(w) "AR PL KaitiM Big5"(w) "AR PL ShanHeiSu
n Uni"(w) "AR PL SungtiL GB"(w) "AR PL Mingti2L Big5"(w) "MS ゴシック"(w) "ZYS
ong18030"(w) "NanumGothic"(w) "UnDotum"(w) "Baekmuk Dotum"(w) "Baekmuk Gulim"(w)
 "KacstQura"(w) "Lohit Bengali"(w) "Lohit Gujarati"(w) "Lohit Hindi"(w) "Lohit M
arathi"(w) "Lohit Maithili"(w) "Lohit Kashmiri"(w) "Lohit Konkani"(w) "Lohit Nep
ali"(w) "Lohit Sindhi"(w) "Lohit Punjabi"(w) "Lohit Tamil"(w) "Meera"(w) "Lohit 
Malayalam"(w) "Lohit Kannada"(w) "Lohit Telugu"(w) "Lohit Oriya"(w) "LKLUG"(w) "
FreeSans"(w) "Arial Unicode MS"(w) "Arial Unicode"(w) "Code2000"(w) "Code2001"(w
) "sans-serif"(s) "Arundina Sans"(w) "Roya"(w) "Koodak"(w) "Terafik"(w) "sans-se
rif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-serif"(w) "sans-se
rif"(w) "sans-serif"(w) "sans-serif"(w)

...

กลายเป็นว่า Waree กลับมาแซงหน้า Loma อีกครั้งหลังจากกฎใน 89-tlwg-waree-synthetic.conf ผลก็คือ ไม่ว่าฟอนต์ไทยตัวไหนจะพยายามลิสต์ตัวเองขึ้นก่อนอย่างไรก็ตาม ก็จะแพ้ฟอนต์ที่ fallback ให้ Tahoma อยู่วันยังค่ำ และการสังเคราะห์ฟอนต์ Tahoma ด้วย Waree ก็ทำให้ Waree ไม่ยอมลงให้กับใคร!

โดย Thep (noreply@blogger.com) ณ 14 June 2016 09:29 GMT

6 June 2016

Kitt

VMware: Hot add a new disk to Linux VM without rebooting

You can always do this. Edit setting of VM hardware, add a new disk In Linux VM, # echo "- - -" > /sys/class/scsi_host/host#/scan where host# can be host0, host1 … Linux will re-scan SCSI, and your new disk should be recognized.

โดย kitty ณ 6 June 2016 10:19 GMT

5 June 2016

bact

เสรีภาพการแสดงออกในมหาวิทยาลัยสหราชอาณาจักร

Gary Slapper ผู้อำนวยการของมหาวิทยาลัยนิวยอร์ก วิทยาเขตลอนดอน เขียนถึงประเด็นเสรีภาพการแสดงออกที่ถูกจำกัดในมหาวิทยาลัยในสหราชอาณาจักร โดยอ้างอิงรายงาน Free Speech University Rankings ที่จัดอันดับเสรีภาพในการพูดของมหาวิทยาลัยยูเค 115 แห่งเป็นปีที่สองแล้ว และในรายงานปีที่สองนี้ พบมหาวิทยาลัยที่มีการเซ็นเซอร์การแสดงออก 90% เพิ่มขึ้นจากปีที่แล้วที่มี 80%

เขายกตัวอย่าง LSE ที่มีปัญหานี้มาก จนนักศึกษาต้องตั้งสมาคม Speakeasy Society ขึ้นมาเพื่อสนับสนุนการโต้เถียงอย่างเสรีและเปิดกว้าง แต่ไม่นานก็มีการเสนอในที่ประชุมของสหภาพนักศึกษา LSE Student Union ว่าให้แบนสมาคมนี้ซะ สุดท้ายก็รอดไป มีคนโหวตให้แบน 57 เสียง โหวตว่าไม่แบน 226 เสียง ได้อยู่ต่อ

ปัญหาอันหนึ่งก็คือ การยกข้องอ้างเรื่องการหมิ่นศาสนาหรือคำพูดที่สร้างความเกลียดชัง ขึ้นมาเพื่อห้ามหรือจำกัดการแสดงออก

ปัจจุบันกฎหมายที่เกี่ยวกับเรื่องนี้โดยตรงคือ Racial and Religious Hatred Act 2006 (แก้ไขเพิ่มเติม Public Order Act 1986) ซึ่ง Gary ก็บอกว่า ในกฎหมายก็เขียนไว้อย่างชัดเจนว่าไม่ได้ห้ามการวิพากษ์วิจารณ์ หรือกระทั่งประชดเสียดสีเยาะเย้ย (ridicule) ศาสนา ความเชื่อ และวิธีปฏิบัติของผู้ที่มีความเชื่อเหล่านั้น

กฎหมายเขาว่างี้

Part 3A — Hatred against persons on religious grounds

29A — Meaning of “religious hatred”

In this Part “religious hatred” means hatred against a group of persons defined by reference to religious belief or lack of religious belief.

[…]

29J — Protection of freedom of expression

Nothing in this Part shall be read or given effect in a way which prohibits or restricts discussion, criticism or expressions of antipathy, dislike, ridicule, insult or abuse of particular religions or the beliefs or practices of their adherents, or of any other belief system or the beliefs or practices of its adherents, or proselytising or urging adherents of a different religion or belief system to cease practising their religion or belief system.

กล่าวคือความหมายของ “ความเกลียดชังทางศาสนา” นี่ มันต้องเป็นความเกลียดชังต่อกลุ่มบุคคล ซึ่งอ้างอิงกับความเชื่อทางศาสนา (29A) สิ่งที่เขาต้องการปกป้อง คือปกป้องคน ส่วนการจะไปวิพากษ์วิจารณ์หรือเอาตัวศาสนาความเชื่อมาล้อเลียนอะไรนั้น เป็นเรื่องที่กฎหมายไม่ได้ห้าม และเขียนย้ำไว้เลยในกฎหมายว่า ไม่ได้ห้ามนะ (29J)

แต่ก็ดูเหมือนว่าข้ออ้างพวกนี้จะถูกเอามาใช้ปิดปากการแสดงออก คือพอวิพากษ์วิจารณ์ความคิด บอกว่าไม่เห็นด้วยกับอะไร ก็ถูกตีความไปว่าไปโจมตีบุคคลที่เชื่อเรื่องนั้น

เขาปิดท้ายบทความว่า คำว่า “university” ในภาษาอังกฤษนั้น มาจากคำละตินว่า “universtas” ซึ่งแปลว่า “ทั้งหมด จำนวนทั้งหมด ผลรวมทั้งหมดของสรรพสิ่ง” มหาวิทยาลัยควรจะเป็นที่ถกเถียงของแนวคิดทุกอย่าง ไม่ใช่แค่บางอย่าง

อ่านบทความเต็มที่ Milkround “The best way to defeat harmful ideas is by debate — not a ban”

ภาพจาก Wikimedia Commons

โดย bact ณ 5 June 2016 14:49 GMT

13 May 2016

LookHin

10 Package ที่ควรติดตั้งบน ATOM Text Editor

คราวที่แล้วเราได้ทำการสร้าง Code Snippet เพื่อช่วยให้เราเขียนโค้ดได้เร็วขึ้นไปแล้ว วันนี้เรามาแนะนำ Package ที่ควรติดตั้งไว้เป็นเครื่องทุนแรงอีกสัก 10 ตัว เพื่อช่วยให้งานเขียนโปรแรกมของเรามีสีสันและคล่องตัวมากขึ้น โดยขึ้นตอนการติดตั้ง package ของ ATOM ให้เราเข้าไปที่เมนู File -> Settings -> Install จากนั้นพิมพ์ชื่อ package ที่เราต้องการจะติดตั้ง หรือถ้าอยากรู้ว่ามี package อะไรบ้างที่น่าสนใจให้เขาไปที่ https://atom.io/packages

Emmet
https://atom.io/packages/emmet
Emmet จะช่วยให้เราเขียน HTML ต่างๆ ได้อย่างรวดเร็วด้วยคีย์ลัดต่างๆ ที่มีให้ โดยเราสามารถดูคำสั่งต่างๆ ได้ที่ http://docs.emmet.io/cheat-sheet/
atom-snippet

atom-beautify
https://atom.io/packages/atom-beautify
atom-beautify จะช่วยให้เราจัดฟอร์แมตของโค้ดให้สวยงามง่ายๆ เพียงกด Ctrl-Alt-B
atom-snippet

autoclose-html
https://atom.io/packages/autoclose-html
autoclose-html ช่วยให้เราพิมพ์แทก HTML แล้วมันจะปิดแทกให้เอง แต่ปกติถ้าเราใช้ Emmet จนคล่องแล้วก็คงแทบไม่ต้องใช้ตัวนี้ก็ได้ แต่ติดตั้งไว้หน่อยก็ดี
atom-snippet

color-picker
https://atom.io/packages/color-picker
color-picker ตัวช่วยที่จะทำให้เราเลือกสีได้อย่างง่ายดายโดยไม่ต้องจำโค้ดสีเอง เพียงแค่กด CTRL-ALT-C
atom-snippet

jquery-snippets
https://atom.io/packages/jquery-snippets
jquery-snippets เป็น snippets ของ jQuery เราไม่ต้องสร้าง snippet เองทั้งหมด มีคนทำให้แล้ว สบายเลย
atom-snippet

line-ending-converter
https://atom.io/packages/line-ending-converter
line-ending-converter อันนี้ตัวแปลงรหัสการขึ้นบรรทัดใหม่ EOL บางทีโค้ดที่เราเปิดดูอาจจะสร้างมาจาก UNIX/Linux/MAC หรือ Windows ซึ่งมี EOL ที่ต่างกัน ตัวนี้ช่วยได้
atom-snippet

minimap
https://atom.io/packages/minimap
minimap เอาไว้แสดงโค้ดอย่างย่อด้านขวามือ จะทำให้เราเลือนหาโค้ดในตำแหน่งที่ต้องการได้เร็วขึ้น
atom-snippet

script
https://atom.io/packages/script
script เป็นตัวช่วยที่จะทำให้เราสามารถ run code ของเราได้ภายในตัว ATOM เลย จะได้เห็น output ทันทีที่กด CTRL+SHIFT+B
atom-snippet

linter
https://atom.io/packages/linter
https://atom.io/packages/linter-php
linter และ linter-php เป็นตัวช่วยในการ debug code php ช่วยให้เราเห็นได้ง่ายขึ้นว่าเราเขียนโค้ดผิดหรือเปล่า
atom-snippet

snake
https://atom.io/packages/snake
เกมงู //อันนี้ไร้สาระหละ
atom-snippet

โดย LookHin ณ 13 May 2016 05:58 GMT

6 May 2016

LookHin

การสร้าง Code Snippet บน ATOM Text Editor

เวลาเขียนโปรแกรมเราก็มักจะมีคำสั่งที่ต้องพิมพ์บ่อยๆ ซึ่งก็มักจะหลายๆ บรรทัด ครั้นจะให้เปิดไฟล์เก่าขึ้นมาเพื่อ copy ก็ยังไงอยู่ บางทีก็หาโค้ดเก่าๆ ไม่เจอก็มี บน Text Editor ที่ใช้สำหรับเขียนโปรแกรมส่วนใหญ่ก็มักจะมีฟังชั่นให้เราสร้าง snippet ซึ่งก็คือการสร้างคำสั่งลัดเอาไว้ใช้งาน ผมเรียกถูกหรือเปล่าไม่แน่ใจ แต่ก็ประมาณว่าถ้าเราพิมพ์ keyword ที่กำหนดไว้มันก็จะสร้างโค้ดที่กำหนดไว้ขึ้นมาให้เราเลย บน ATOM Text Editor ก็มีฟังชั่นนี้ให้ใช้งานเช่นกัน อธิบายอาจจะไม่เห็นภาพ ไปลองทำกันจริงๆ เลยดีกว่า

ถ้ายังไม่ได้ติดตั้ง ATOM หรือยังไม่เคยลองใช้ก็ติดตั้งและลองเล่นสักพักหนึ่งก่อนนะครับ https://atom.io/ ผมเองเคยใช้มาทั้ง Edit Plus, Sublime และตอนนี้มาจบที่ ATOM เหตผลเพราะมัน Open Source เลยอยากแนะนำให้ทุกๆ คนลองใช้ดู

มาเริ่มสร้าง code snippet ของเรากันต่อ ให้เลือกไปที่เมนู File -> Snippets (ถ้าเมนูไม่ขึ้นให้กด ALT ข้างไว้นะครับ)

atom-snippet

ATOM จะเปิดไฟล์ snippets.cson ขึ้นมาให้เราแก้ไข โดยรูปแบบการเขียนจะเป็น CoffeeScript Object Notation (CSON) คล้ายๆ กับ JSON แต่ไม่มีวงเล็บเปิดปิด ใช้ tab อย่างเดียว แต่เราก็ไม่ต้องสนใจอะไรมาก เราใช้อยู่ไม่กี่คำสั่งครับ

atom-snippet

ตรง comment ด้านบนที่เขาให้มาด้วย เขาแนะนำว่าถ้าเราจะสร้าง snippet ของตัวเองได้โดยแค่พิมพ์ snip แล้วกด tab เดียวมันจะสร้าง template ขึ้นมาให้เรา ซึ่งจะได้ code ออกมาประมาณนี้ ซึ่งเป็นตัวอย่างของการทำ snippet สำหรับไฟล์ .js โดย Snippet name คือชื่อคำอธิบายที่จะแสดงตอนที่มีคำสั่งขึ้นมาให้เลือก ส่วน prefix คือ keyword ที่เรากำหนดว่าเมื่อพิมพ์คำนี้แล้วให้แสดง snippet ตัวนี้ขึ้นมา และ body คือส่วนของโค้ดที่เราต้องการ จะเห็นว่าส่วนของ boby ถ้าเราใส่แค่บรรทัดเดียว ให้ใส่เครื่องหมาย ‘ ครอบคำสั่งได้ แต่ถ้ามีหลายๆ บรรทัดเราต้องใช้ “”” ครอบคำสั่งแทน และเราสามารถใส่ $1 เพื่อกำหนดตำแหน่งของ cursor ได้ เดียวเราลองดูจากตัวอย่างหละกัน จะได้เห็นภาพ

1
2
3
4
'.source.js':
  'Snippet Name':
    'prefix': 'Snippet Trigger'
    'body': 'Hello World!'

แต่ของเรา เราจะสร้าง snippet สำหรับ php และเพิ่ม snippet เข้าไปสัก 2 ตัว ให้แก้ตามตัวอย่างนี้ครับ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'.source.php':
  'Copyright by LookHin':
    'prefix': 'lookhin'
    'body': '//Copyright by LookHin khwanchai@gmail.com$1'
 
  'MySQL Select':
    'prefix': 'sqls'
    'body': """
    //Select Data
    $query = "SELECT * FROM `table_name` ORDER BY `ID` ASC";$1
    $result = mysql_query($query);
    while($line = mysql_fetch_array($result)){
      echo $line['ID'];
    }
    """

atom-snippet

หลังจากสร้าง snippet เสร็จแล้ว ให้ลองสร้างไฟล์ test.php และใช้ ATOM เปิดไฟล์นี้ขึ้นมา จากนั้นพิมพ์คำว่า sqls เราจะเห็นว่ามี snippet ของเราขึ้นมาให้ใช้งานแล้วครับ

atom-snippet

โดย LookHin ณ 6 May 2016 08:32 GMT

4 May 2016

Thep

From C++ to Python (2)

ใน blog ที่แล้ว ผมได้พูดถึงประเด็นต่าง ๆ ที่ผมสะดุดเมื่อเรียนภาษาไพธอนด้วยพื้นฐานความรู้ C/C++ ที่มี ซึ่งเป็นการปรับโหมดคิดพื้นฐานให้เพียงพอสำหรับใช้เขียนไพธอนได้ ใน blog นี้จะขอเขียนส่วนที่เป็น กำไร ที่ได้จากภาษาไพธอนบ้าง

Container สำเร็จรูป

ภาษาไพธอนมาตรฐานมาพร้อมกับ container สำเร็จรูป คือ list, dictionary และ set โดยสามารถเก็บข้อมูลหลายชนิดปนกันได้ตามธรรมชาติของภาษา dynamic type (heterogeneous list ที่ต้องอาศัย polymorphism หรือ generic programming ใน C++ กลายเป็นเรื่องที่แสนธรรมดาเมื่อมาเขียนไพธอน) การมี container สำเร็จรูปทำให้เขียนโปรแกรมได้สะดวกขึ้นมาก

list (และ tuple ที่เป็น immutable list) นั้น มีแนวคิดเหมือนลิสต์ของภาษา Lisp ที่สามารถบรรจุข้อมูลหลากชนิดคละกันได้ รวมทั้งเก็บลิสต์ในลิสต์ กลายเป็น tree ก็ยังได้ (ยังมีอิทธิพลของภาษา Lisp ในไพธอนอีกอย่าง คือ lambda expression) แต่ implement ด้วย dynamic array เพื่อรองรับ syntax ในการเข้าถึงสมาชิกในแบบแอร์เรย์อย่างมีประสิทธิภาพ แลกกับ cost ในการเพิ่ม/ลบสมาชิกเล็กน้อย list ของไพธอนจึงทำให้สามารถทำงานกับ collection ของข้อมูลได้สะดวกโดยไม่ต้องคิดเรื่องวิธีจองหน่วยความจำ

dictionary ทำให้การใช้งาน associative array ที่พบบ่อยในโปรแกรมต่าง ๆ กลายเป็นเรื่องง่าย (กลไกภายในคือ hash table) แม้แต่ตัว interpreter ของไพธอนเองก็ยังใช้ dictionary เป็นกลไกในการทำงานหลายส่วน เช่น ใช้ในการเก็บ attribute และ method ของออบเจกต์ต่าง ๆ แบบ dynamic, การทำ symbol table ของโปรแกรม ฯลฯ

set เป็นการ implement แนวคิดของ ทฤษฎีเซ็ต ในทางคณิตศาสตร์นั่นเอง การใช้เซ็ตในโปรแกรมได้ ทำให้สามารถเขียนโปรแกรมได้ใกล้เคียงกับนิพจน์คณิตศาสตร์มากขึ้น

การมีเครื่องมือแบบนี้ พร้อม syntax ที่เรียบง่ายในการเข้าถึงในระดับตัวภาษาเอง ทำให้เขียนโปรแกรมได้สั้นกระชับ

else ในที่ต่าง ๆ

นอกจาก else ใน if แล้ว ไพธอนยังมี else ในลูป while, for, และใน exception handling ด้วย ซึ่งคนที่เขียนโปรแกรม C/C++ มาเยอะหน่อยอาจเคยพบกรณีที่ else เหล่านี้ช่วยลดขั้นตอนลงได้

สมมุติว่ามีการค้นหาสมาชิกในลิสต์ที่สอดคล้องกับเงื่อนไขที่กำหนด

for (const Elm* p = students.first(); p; p = p->next()) {
  log_visited (p);
  if (p->id() == id) {
    report_matched (p);
    break;
  }
  mark_unmatched (p);
}

if (!p) {
  // search exhausted
  report_no_match();
}

เราไม่จำเป็นต้องเช็กค่า p อีกครั้งหลังจบลูปถ้าเราใช้ else หลัง for แบบนี้ในไพธอน:

for s in students:
  log_visited (s)
  if (s.id == id):
    report_matched (s)
    break
  mark_unmatched (s)
else:
  # search exhausted
  report_no_match()

หรือจะเป็นโปรแกรมให้ผู้ใช้ทายตัวเลข โดยให้ผู้ใช้หยุดทายได้ด้วยการป้อนค่า 0 หรือเลขลบ:

guess = 0;
while (guess != secret) {
  std::cout << "Guess the number: ";
  std::cin >> guess;

  if (guess <= 0) {
    std::cout << "Sorry that you're giving up!" << std::endl;
    break;
  }

  if (guess > secret)
    std::cout << "The number is too large." << std::endl;
  else if (guess < secret)
    std::cout << "The number is too small." << std::endl;
}

if (guess == secret)
  std::cout << "Congratulations. You made it!" << std::endl;

ด้วย else ในไพธอน คุณก็ไม่ต้องเช็กค่า guess ซ้ำหลังจบลูป:

guess = 0
while guess != secret:
  guess = int (input ("Guess the number: "))

  if guess <= 0:
    print ("Sorry that you're giving up!")
    break

  if guess > secret:
    print ("The number is too large.")
  elif guess < secret:
    print ("The number is too small.")
else: 
  print ("Congratulations. You made it!")

โค้ดแบบนี้ผมเจอค่อนข้างบ่อยใน C/C++ บางทีคิด ๆ เหมือนกันว่าถ้าใช้ goto แทน break ซะก็อาจไม่ต้องมาเช็กซ้ำ พอมาเจอ else ของลูปในไพธอนก็เข้าใจได้ทันที

List Comprehension

list comprehension เป็นสิ่งที่ pythonic เอามาก ๆ ทำให้โค้ดกระชับและดูคล้ายนิพจน์คณิตศาสตร์

เช่น ถ้าต้องการหารายการข้อมูลในลิสต์ data ที่สูงกว่าค่าเฉลี่ย:

avg = sum(data)/len(data)
print([x for x in data if x > avg])

หรือแม้กระทั่งจะหาจำนวนเฉพาะทั้งหมดที่น้อยกว่าจำนวนที่กำหนด:

from math import sqrt
def primes(n):
  sqrt_n = int(sqrt(n))
  no_primes = {j for i in range(2, sqrt_n) for j in range(i*2, n, i)}
  return [i for i in range(2, n) if i not in no_primes]

พี่จะสั้นไปไหนครับ!

ในบทที่ว่าด้วย Lambda operator, map, filter, reduce บอกไว้ที่ส่วนต้นว่า Guido van Rossum ผู้สร้างและดูแลภาษาไพธอนได้แสดงความประสงค์ที่จะ ตัด lambda, map, filter, reduce ออกใน Python 3 เพราะ list comprehension ทำสิ่งเดียวกันได้ชัดเจนและเข้าใจง่ายกว่า แต่สุดท้ายก็ทนแรงต้านจากผู้นิยม Lisp, Scheme ไม่ไหว จำเป็นต้องคงไว้ ตัดออกเฉพาะ reduce() โดยย้ายไปไว้ในมอดูล functools

เทียบกันแล้ว list comprehension ถอดแบบมาจาก set-builder notation ในทฤษฎีเซ็ต ส่วน lambda นั้น ถอดแบบมาจาก lambda calculus เห็นได้ชัดว่าทฤษฎีเซ็ตเป็นที่คุ้นเคยและเข้าใจง่ายกว่า สิ่งที่ lambda ทำได้มากกว่า list comprehension ก็คือ reduce() ซึ่งในความเห็นของผู้สร้างไพธอนแล้ว ทำให้โค้ดซับซ้อนเกินไป ยอมเขียนเป็นลูปเพื่อความชัดเจนเสียจะดีกว่า

ไหนลองเขียนด้วย lambda ดูซิ:

หาข้อมูลที่สูงกว่าค่าเฉลี่ย:

avg = sum(data)/len(data)
print(list(filter(lambda x : x > avg, data)))

หาจำนวนเฉพาะ:

from math import sqrt
from functools import reduce
def primes(n):
  sqrt_n = int(sqrt(n))
  np_series = list(map(lambda i : set(range(i*2, n, i)), list(range(2,sqrt_n))))
  np_set = reduce(lambda a, b : a | b, np_series)
  return list(filter(lambda i : i not in np_set, list(range(2,n))))

จะเห็นว่า lambda ยาวและเข้าใจยากกว่า list comprehension

Generator

ลูป for ในไพธอนจะไม่มีรูปแบบการใช้ตัวนับเหมือนภาษาทั่วไป แต่จะใช้ iterator ล้วน ๆ คือเป็นลูป foreach นั่นเอง

เช่น ลูปหาผลรวมของกำลังสองของจำนวนเต็มบวก n ตัวแรกที่เขียนในภาษา C++ อาจเป็นแบบนี้:

int sum_sq (int n)
{
  int sum = 0;
  for (int i = 1; i <= n; i++)
    sum += i*i;
  return sum;
}

แต่ลูป for ในไพธอนจะใช้ฟังก์ชัน range() สร้าง iterator สำหรับไล่เรียง:

def sum_sq (n):
  sum = 0
  for i in range (1, n+1):
    sum += i*i
  return sum

หรือจะให้ pythonic จริง ๆ ก็ใช้ list comprehension:

def sum_sq (n):
  return sum([i*i for i in range (1, n+1)])

iterable object ต่าง ๆ เช่น list, tuple, dictionary, set สามารถใช้เป็น iterator ได้ทันที นอกจากนี้ ยังสามารถสร้าง iterator ขึ้นเองได้ โดยทำตามโพรโทคอลที่กำหนด (สร้างคลาสที่มีเมธอด __iter__(), next() โดย next() คืนค่าตัววิ่งแต่ละขั้น และ raise StopIteration exception เมื่อวิ่งสุดแล้ว) แต่เพื่ออำนวยความสะดวกยิ่งขึ้น ไพธอนได้บัญญัติสิ่งที่เรียกว่า generator ที่ใช้วิ่งลูปได้เหมือน iterator แต่เขียนง่ายกว่า

ตัวอย่างเช่น ถ้าจะเขียน generator สำหรับไล่ลำดับ Fibonacci:

def fibo (n):
  a, b = 0, 1
  for i in range(n):
    yield a
    a, b = b, a + b

(yield ทำหน้าที่คล้าย return สำหรับแต่ละรอบ และรอบต่อไปก็จะเริ่มทำงานต่อจากบรรทัดที่ yield ไว้)

จากนั้นก็สามารถไล่ลำดับ Fibonacci ได้ตามต้องการ:

>>> list(fibo(10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
>>> for x in fibo(5):
...   print (x)
... 
0
1
1
2
3
>>> [x for x in fibo(10) if x % 2 == 0]
[0, 2, 8, 34]

การมี construct แบบ generator ก็ทำให้มีความยืดหยุ่นของการเขียน iterator เช่น สามารถเขียน generator แบบ recursive ได้ หรือกระทั่งเขียน generator ซ้อน generator ได้ อ่านเพิ่มเติม

เมื่อมองย้อนกลับไปถึงตอนแรกที่เราพบว่าไพธอนมีแต่ลูป foreach เท่านั้น ก็ไม่ได้ทำให้ความสามารถด้อยไปกว่าภาษาที่มีลูปตัวนับแต่อย่างใด (ในเมื่อมีฟังก์ชัน range()) แต่กลับมีความยืดหยุ่นสูงมากในการวนลูปที่ซับซ้อน

Decorator

ข้อนี้ไม่แน่ใจนักว่าชอบหรือเปล่า แต่ก็เป็นสิ่งที่น่าจะมีประโยชน์ในบางโอกาส คือสิ่งที่ไพธอนเรียกว่า decorator ซึ่งหลังจากที่ทำความเข้าใจแล้ว อยากจะเรียกว่า wrapper มากกว่า

สมมุติว่าเราต้องการนับจำนวนการเรียกฟังก์ชันต่าง ๆ ในโปรแกรมของเรา เราสามารถเขียน wrapper function มาดักการเรียกของผู้ใช้แล้วแอบเพิ่มตัวนับก่อนเรียกฟังก์ชันตัวจริง และไพธอนมีวิธีการสร้าง wrapper ที่ว่านี้อย่างแนบเนียน

def call_counter (func):
  def wrapper (*args, **kwargs):
    wrapper.calls += 1
    return func (*args, **kwargs)
  wrapper.calls = 0
  wrapper.__name__ = func.__name__
  return wrapper

@call_counter
def square (x):
  return x*x

print (square.calls)
for i in range (10):
  print (square (i))
print (square.calls)

บรรทัด @call_counter คือ syntax ของไพธอนในการ decorate ฟังก์ชัน โดยโค้ดนี้:

@call_counter
def square (x):
  return x*x

มีความหมายเทียบเท่ากับ:

def square (x):
  return x*x
square = call_counter (square)

กล่าวคือ เป็นการส่งออบเจกต์ของฟังก์ชัน square() ให้กับฟังก์ชัน call_counter() แล้ว call_counter() คืนค่า wrapper() ซึ่งเป็นฟังก์ชันภายในมา จากนั้น ก็ใช้ค่าที่คืนมานี้ assign ค่าทับลงไปใน symbol square() เสีย ทำให้การเรียก square() หลังจากนี้ไปจะเป็นการเรียกตัวฟังก์ชัน wrapper() ที่ได้แอบเพิ่มตัวนับก่อนเรียกฟังก์ชัน square() ตัวจริงที่ได้ส่งมาก่อนหน้านี้ในพารามิเตอร์ชื่อ func

(คำอธิบายค่อนข้างซับซ้อนวนเวียนสักหน่อย หากงงก็ขอแนะนำให้อ่านรายละเอียดจาก บทเรียน นอกจากนี้ยังมี blog ที่ artima และ blog ของ Simeon Franklin ที่ให้คำอธิบายอย่างละเอียด)

อีกวิธีหนึ่งคือเขียน wrapper เป็นคลาสที่ callable ซึ่งดูสะอาดกว่า:

class call_counter:

  def __init__ (self, func):
    self.func = func
    self.calls = 0

  def __call__ (self, *args, **kwargs):
    self.calls += 1
    return self.func (*args, **kwargs)

ประโยชน์ที่พอมองเห็นได้คือ ไพธอนมีวิธีสร้าง wrapper ที่แนบเนียน wrapper มีประโยชน์ที่ไหนก็ใช้ได้ที่นั่น (เช่น การ cache ผลการคำนวณครั้งก่อน ๆ ของฟังก์ชัน, การเพิ่มการตรวจสอบอาร์กิวเมนต์ ฯลฯ)

Library

นอกจากตัวภาษาเองแล้ว ไพธอนยังมาพร้อมกับไลบรารีมาตรฐานอีกเพียบ ซึ่งผมคงต้องศึกษาเพิ่มเติมไปเรื่อย ๆ เท่าที่ได้ผ่านมาก็คือเรื่องการใช้ regular expression

ดูยังมีอะไรอีกเยอะให้ศึกษาข้างหน้า ที่สำคัญคือการฝึกฝนให้เกิด pythonic way ในการเขียนโค้ด และการใช้แพกเกจต่าง ๆ ให้เหมาะกับงาน

Update (2016-05-04): แก้เนื้อหาเรื่อง implementation ของ list หลังจากที่คุณวีร์ทักท้วงมาใน facebook ว่า list ของไพธอน implement ด้วย array ไม่ใช่ linked list เหมือนใน Lisp

โดย Thep (noreply@blogger.com) ณ 4 May 2016 05:36 GMT

2 May 2016

MrChoke

AUDAX 300 RAYONG CHAN

AUDAX เป็นรายการการปั่นจักยานทางไกลที่ผู้เข้าร่วมต้องช่วยเหลือตัวเองทุกอย่าง ในไทยมีตั้งแต่ 200 300 400 600 และ 1000 กิโลเมตร มีบางรายการเปืด 100 กม. แต่ไม่ได้ record เคยปั่น 200 และ 400 มาสองรายการความเหี้ยมโหดและความบันเทิงของแต่ละรายการไม่เหมือนกันขึ้นกับเส้นทาง ครั้งนี้เข้าร่วม 300 เส้นทางระยอง จันทบุรี ต้องยอมรับเลยว่าพังมากขึ้นๆลงๆเนินตลอดเส้นทาง คือเบื่อเนินไปเลย แถมอากาศร้อนอีก ปล่อยตัวตั้งแต่ตีห้าที่ลาดหินขาว หาดแม่รำพึง ประสบการณ์จาก 400 สอนว่าไม่ควรเอาอะไรแบกไปให้มากมายเพราะทุกอย่างคือภาระ โหลดของใส่กระเป๋าเสื้อจักรยานเต็มพอดี ไม่มีเป้นอก โหลดอะไรไปบ้าง? 1. สูบพก 2. น้ำยาอุดรูรั่ว ขวดครึ่ง 3. ปะแจแอลหนึ่งชุด 4. เลนส์แว่นกลางคืน 5.ถุงตังและบัตรประชาชน 6. Power bank 7. สายชาร์จ usb ทั้ง มือถือ และการ์มิน 8. [...]

โดย MrChoke ณ 2 May 2016 10:56 GMT

27 April 2016

Thep

From C++ to Python (1)

ภาษาไพธอน เป็นภาษาที่ผมอยากหาโอกาสเรียนมานานแล้ว แต่ด้วยงานส่วนใหญ่ที่ผมทำยังวนเวียนอยู่แถว ๆ ระบบระดับล่างซึ่งใช้ C/C++ เป็นหลัก ก็เลยยังปล่อยมือมาเรียนภาษาอื่นไม่ถนัดถนี่ จนกระทั่งระบบภาษาไทยเริ่มจะอยู่ตัวแล้ว ถึงเริ่มเรียนภาษาอื่น ๆ เพื่อเพิ่มโอกาสในการทำงานแขนงอื่นบ้าง

ในการเรียนครั้งนี้ ผมได้อาศัยบทเรียนจาก python-course.eu (และไปอ่านทบทวนกับ บทเรียนที่ debianclub ที่คุณวิทยาเคยลงไว้)

บทเรียนที่ python-course.eu นับว่าเหมาะกับคนที่มีพื้นฐาน C/C++ มาแล้วมาก เพราะเขาอธิบายบนพื้นฐานของคนเคยเขียนโปรแกรมมาแล้ว ไม่ใช่เริ่มต้นจากศูนย์ ยกตัวอย่างเปรียบเทียบกับ C/C++ และเน้นประเด็นที่เป็นหลุมพรางของผู้ที่ย้ายมาจาก C/C++

เท่าที่ได้ตั้งโจทย์ฝึกหัดให้กับตัวเอง ด้วยการทดลองพอร์ตโค้ดภาษา C/C++ ของตัวเองที่เคยเขียนไว้ให้เป็นไพธอน พร้อมกับทำ unit test ไปด้วย ทำให้ได้พบเจอประเด็นต่าง ๆ ที่โปรแกรมเมอร์ภาษา C/C++ จะสะดุด ผมเองก็พบว่าต้องก้าวข้ามสิ่งเหล่านี้ถึงจะเริ่มจับทางไพธอนได้ จึงเขียนบันทึกไว้สักหน่อย

Indentation

ข้อนี้ดูเหมือนเป็นเรื่องเล็ก แต่กลับเป็นสาเหตุหลักข้อหนึ่งที่ทำให้ผมยี้ไพธอนก่อนหน้านี้ เพราะโปรแกรมเมอร์ภาษา C/C++ จะคุ้นกับ free-form syntax และพบเจอการ indent แบบตามใจฉันมาแล้วมากมาย บางคนใช้ tab บางคนใช้ space 2, 4 หรือ 8 ช่อง บางคนใช้ปนกันทั้ง tab ทั้ง space ซึ่งซอร์สจะเละทันทีเมื่อมีการเปลี่ยนขนาดของ tab stop นี่ยังไม่นับคนที่ไม่สนใจ style ใด ๆ ทั้งสิ้นอีกนะ แต่ไม่ว่าอย่างไรโปรแกรมก็ยังคอมไพล์ผ่าน แล้วถ้ามันกลายเป็นการกำหนด syntax ของภาษา มันจะเละเทะขนาดไหน

เมื่อพยายามนึกถึงตัวอย่างอื่นที่กำหนดอะไรทำนองนี้ ผมก็นึกถึง Makefile ที่ใช้ tab ในการกำหนดขอบเขตของ rule แต่มันก็แค่ระดับเดียว ไม่ได้ซ้อนกันหลายชั้น จึงดูไม่มีอะไรมาก และอีกตัวอย่างหนึ่งคือ Fortran 77 ที่เคยเขียนในสมัยเรียน ซึ่งอาศัยตำแหน่งคอลัมน์เป็นส่วนหนึ่งของ syntax อันเป็นมรดกตกทอดมาจากสมัยใช้บัตรเจาะรู (ตอนที่เรียน Fortran 77 รู้สึกอึดอัดตรงนี้มาก เพราะตอนนั้นผ่านภาษา Pascal มาแล้ว แม้แต่ภาษา BASIC [AppleSoft, GW] ที่ว่าไม่ค่อยมีโครงสร้างก็ยังไม่ทำอะไรโลว์เทคเยี่ยงนี้) แต่ละอย่างที่นึกถึงก็ไม่ได้ชวนพิสมัยเอาเสียเลย

นั่นคือ mindset ของผมก่อนเรียน แต่ คำอธิบาย ในบทเรียนก็ทำให้ผมเข้าใจและยอมรับ ทำให้เรียนไพธอนต่อไปได้อย่างผ่อนคลาย มันคือการกำหนดขอบเขตของบล็อคคำสั่งโดยเปลี่ยนจาก style ให้เป็น syntax เสีย คนที่เขียนโปรแกรมภาษา C/C++ โดยเคร่งครัดกับ style อยู่แล้วจึงยอมรับตรงนี้ได้ไม่ยาก ส่วนประเด็นเรื่องการใช้ tab กับ space ปนกัน ไพธอนก็มีข้อกำหนดที่ชัดเจนที่ทำให้แยกแยะออกจากกันได้ คือถือเป็น indentation คนละระดับไปเลย ไม่นับปนกัน

มันคือการกำจัดวิจิกิจฉานิวรณ์ครับ ผ่านตรงนี้ไปได้ก็ลื่นไหลขึ้นเยอะ

Public, Protected, Private

ภาษา C++ จะมีการกำหนด access specifier สำหรับ member ต่าง ๆ ของคลาสเป็น public, protected, private จากนั้น โปรแกรมเมอร์แต่ละคนก็จะมีวิธีการต่าง ๆ ในการตั้งชื่อ member ให้สามารถแยกแยะ access ได้ บางคนใช้ตัวพิมพ์เล็ก-พิมพ์ใหญ่ต้นชื่อ บางคนใช้ prefix บางคนใช้ suffix บางคนไม่แยกเลย (อันนี้ยุ่ง)

แต่ไพธอนไม่มี access specifier แต่จะใช้การตั้งชื่อแยกแยะทันที โดยชื่อปกติจะถือเป็น public ชื่อที่ขึ้นต้นด้วย _ ถือเป็น protected และชื่อที่ขึ้นต้นด้วย __ ถือเป็น private นับว่าเป็นการเปลี่ยน style ให้เป็น syntax อีกหนึ่งเรื่อง

Dynamic Type & Scope

การย้ายจากภาษาที่เป็น static typing มาเป็น dynamic typing จะต้องปรับโหมดความคิดสักหน่อย ซึ่งพื้นฐานภาษา BASIC สมัยเก่า บวกกับความรู้จากวิชา Compilers & Programming Languages พอช่วยได้ ไม่เป็นปัญหาสำหรับผมนัก สิ่งที่ต้องปรับเปลี่ยนแนวคิดก็เช่น:

Call by Value หรือ Call by Reference?

ภาษาไพธอนไม่มีพอยน์เตอร์เหมือน C/C++ แต่กลไกภายในกลับใช้พอยน์เตอร์เต็มไปหมด แม้แต่ตัวแปรกับค่าของมันก็เชื่อมกันด้วยพอยน์เตอร์ การ assign ตัวแปรก็เป็นการ assign พอยน์เตอร์ไปยังออบเจกต์ที่เป็นค่า ดังสามารถตรวจสอบได้ดังนี้:

>>> x = 1
>>> y = x
>>> id(x)
10861696
>>> id(y)
10861696

จะเห็นว่า หลัง assignment แล้ว x กับ y ชี้ไปยังออบเจกต์เดียวกัน ไม่ใช่แค่มีค่าเท่ากัน! อย่างไรก็ดี ถ้าเรา assign ค่าใหม่ให้กับ y จะไม่ได้ทำให้ค่าของ x เปลี่ยน แต่เป็นการกำหนดให้ y ชี้ไปยังออบเจกต์ใหม่:

>>> y = 2
>>> id(y)
10861728
>>> x
1

ก็น่าจะปลอดภัยดี แถมยังเป็นการประหยัดหน่วยความจำด้วยถ้าค่าเป็นออบเจกต์ใหญ่ ๆ ที่ไม่ใช่ integer เรื่องประหยัดน่ะใช่ แต่แน่ใจหรือเรื่องความปลอดภัย?

>>> p = [1, 2, 3]
>>> q = p
>>> q[1] = 'x'
>>> p
[1, 'x', 3]

จะเห็นว่าลิสต์ p เปลี่ยนตาม q หลัง assignment ทั้งนี้เพราะทั้ง p และ q ชี้ไปยังออบเจกต์เดียวกันตลอดเวลา และการ assign q[1] ก็เป็นการเปลี่ยนพอยน์เตอร์ q[1] จากที่ชี้ไปยัง integer 2 ให้ชี้ไปยัง string 'x' แทน แต่ในเมื่อ q ชี้ไปยังออบเจกต์เดียวกันกับ p การเปลี่ยนพอยน์เตอร์ q[1] จึงเป็นการเปลี่ยนพอยน์เตอร์ p[1] ด้วย!

พฤติกรรมแบบนี้ เกิดกับออบเจกต์ที่เป็น complex data structure ทั้งหมด ไม่ว่าจะเป็น list, dictionary หรือ class instance ซึ่งหากอธิบายในภาษาของ C/C++ ด้วยคำว่า พอยน์เตอร์ (จากชื่อตัวแปรไปยังค่า) ก็จะสามารถทำความเข้าใจได้ รวมถึงประโยชน์ของ deepcopy ด้วย

ความสนุกเกิดขึ้นเมื่อเราส่งอาร์กิวเมนต์ให้กับฟังก์ชัน

แบบนี้พฤติกรรมจะเหมือน call by value:

>>> def f(x):
...   x = x + [1]
... 
>>> p = [1, 2, 3]
>>> f(p)
>>> p
[1, 2, 3]

แต่แบบนี้กลับเหมือน call by reference:

>>> def g(x):
...   x += [1]
... 
>>> p = [1, 2, 3]
>>> g(p)
>>> p
[1, 2, 3, 1]

คำอธิบายก็คือ x ซึ่งเป็นพารามิเตอร์ของ f() และ g() นั้น จะก็อปปี้พอยน์เตอร์ไปยังค่าของ p มาทั้งคู่ จากนั้น x ใน f() ถูก assign ให้ชี้ไปยังออบเจกต์ใหม่ที่เป็นผลลัพธ์ของการบวก x กับลิสต์ [1] ในขณะที่ x ใน g() ถูกเพิ่มอิลิเมนต์ใหม่ต่อท้ายโดยตรงในออบเจกต์เดิม ซึ่งเป็นออบเจกต์เดียวกับที่ p ของผู้เรียกชี้อยู่ ผลจึงเป็นการเปลี่ยนค่าของ p ของผู้เรียกไปด้วย

คำถามที่ว่า การเรียกฟังก์ชันของไพธอนเป็น call by value หรือ call by reference จึงตอบได้แค่ว่า ไม่ใช่ทั้งสองอย่าง ผู้ที่ย้ายมากจากภาษา C/C++ ต้องระวังให้ดี ภาษาไพธอนไม่มีพอยน์เตอร์ก็จริง แต่เวลาเขียนไพธอนให้นึกถึงพอยน์เตอร์เข้าไว้

Function Overloading?

ฟังก์ชันในภาษา C++ สามารถโอเวอร์โหลดเพื่อรับพารามิเตอร์หลายแบบได้ ถึงแม้มันจะเพิ่มความยุ่งยากในการลิงก์จากโค้ดภายนอกอันเนื่องมาจาก symbol mangling แต่มันก็ไม่ได้สร้างขึ้นมาเท่ ๆ มี use case ที่ได้ประโยชน์จากการโอเวอร์โหลดฟังก์ชัน เช่น:

แต่ไพธอนไม่สามารถโอเวอร์โหลดฟังก์ชันได้ มีให้อย่างมากก็แค่การใช้ default argument แต่ถ้ากำหนดฟังก์ชันชื่อเดียวกันหลายครั้ง มันก็จะเอาอันหลังสุดเท่านั้น ถือว่าทับอันแรก ๆ ไป

ด้วยความเป็น dynamic typing ของภาษาไพธอน ทำให้พอเข้าใจได้ว่าการโอเวอร์โหลดฟังก์ชันสามารถทำให้เกิดความยุ่งยากได้ กรณีทั่วไปเราอาจเลี่ยงได้ด้วยการตั้งชื่อฟังก์ชันหลบกันเสีย แต่สำหรับกรณีของ magic methods ทั้งหลายของคลาส เราไม่สามารถตั้งชื่อหลบได้ ซึ่งกรณีของ constructor และ operator overloading ก็เข้าข่าย magic methods ทั้งสิ้น

แล้วจะจัดการกับ use case ข้างต้นได้อย่างไร?

การโอเวอร์โหลด constructor

กรณีที่สามารถใช้ default argument ได้ ก็ใช้ default argument เช่น:

class Time:
  def __init__ (self, h=0, m=0, s=0):
    self.h, self.m, self.s = h, m, s

t1 = Time()
t2 = Time(8)
t3 = Time(8, 20)
t4 = Time(8, 20, 45)

หากโอเวอร์โหลดโดยใช้อาร์กิวเมนต์ต่างชนิดกัน ก็ไม่สามารถใช้ default argument ได้ ก็อาจใช้วิธีพิเศษ เช่น การใช้ argument tuple หรือ argument dict:

class Time:
  def __init__ (self, *args):
    if len (args) == 1 and type (args[0]) == str:
      h, m, s = args[0].split(":")
      self.h, self.m, self.s = int(h), int(m), int(s)
    else:
      self.h, self.m, self.s = 0, 0, 0
      if len (args) >= 1:
        self.h = int(args[0])
      if len (args) >= 2:
        self.m = int(args[1])
      if len (args) >= 3:
        self.s = int(args[2])

t1 = Time()
t2 = Time(8)
t3 = Time(8, 20)
t4 = Time(8, 20, 45)
t5 = Time("8:20:50")

หรือใช้ factory method ซะเลย:

class Time:
  @classmethod
  def from_str (cls, s):
    h, m, s = s.split(":")
    return cls (int(h), int(m), int(s))

  @classmethod
  def from_hms (cls, h=0, m=0, s=0):
    return cls (h, m, s)

  def __init__ (self, h, m, s):
    self.h, self.m, self.s = h, m, s

t1 = Time.from_hms()
t2 = Time.from_hms(8)
t3 = Time.from_hms(8, 20)
t4 = Time.from_hms(8, 20, 45)
t5 = Time.from_str("8:20:50")

(ดัดแปลงจาก กระทู้ Stack Overflow)

การโอเวอร์โหลด operator

สมมุติว่าเรามีคลาส Date (วันที่) ซึ่งต้องการโอเวอร์โหลดเครื่องหมายลบดังนี้:

d1 = Date("2016-04-26")
d2 = Date("2016-05-03")
assert d2 - d1 == 7
assert d2 - 7 == d1

กล่าวคือ:

กรณีนี้ดูจะไม่มีทางอื่น นอกจากตรวจสอบชนิดของตัวลบเอา:

class Date:
  # ...

  def __sub__ (self, other):
    if type (other) == int:
      # ... subtract days from self ...
    elif type (other) == Date:
      # ... subtract two Dates ...
    else:
      raise TypeError ("Invalid operand type")

ซึ่งออกจะดูอัปลักษณ์ถ้าเป็นโค้ด C++ แต่นี่คือไพธอนมาตรฐาน

อย่างไรก็ดี เท่าที่ลองค้นดู ดูเหมือนจะมีแพกเกจ overload และ multimethod เพื่อการนี้ และดูจะมี PEP 3124 เพื่อเพิ่มการรองรับการโอเวอร์โหลดฟังก์ชันอย่างเป็นทางการ แต่ยังอยู่ในสถานะ Deferred อยู่

Polymorphism?

หนึ่งในเครื่องมือที่ใช้กันมากของ OOP ก้คือ polymorphism ซึ่งในภาษา C++ จะใช้ virtual function ประกอบกันกับ class hierarchy ซึ่ง implementation ภายในคือ pointer to function ใน v-table ของคลาส

แต่พอมาเขียนไพธอน คุณจะหา keyword หรือ naming convention ที่เทียบเคียงกับ virtual function ไม่ได้เลย ทั้งนี้เพราะไพธอนเป็น polymorphic โดยธรรมชาติอยู่แล้ว!

เวลาที่เขียนฟังก์ชันแบบนี้ใน C++:

inline int max (int x, int y) { return (x > y) ? x : y; }
inline int max (double x, double y) { return (x > y) ? x : y; }

หรือจะใช้ generic programming ด้วย template ซึ่ง implementation ภายในเทียบเท่ากัน แต่ใช้กับชนิดใดก็ได้ที่รองรับ operator > :

template <class T>
inline int max (T x, T y) { return (x > y) ? x : y; }

แต่ในไพธอนคุณเขียนแค่นี้ก็ทำงานได้กับทุกชนิดแล้ว:

def max (x, y):
  return x if x > y else y

เพราะ dynamic typing นั่นเอง ทำให้สามารถส่งออบเจกต์ชนิดไหนก็ได้ แล้วไปว่ากันที่ run-time ถ้าชนิดนั้น ๆ รองรับ operation ที่เรียกใช้ ก็เป็นอันใช้ได้ ตามแนวคิดที่เรียกว่า duck-typing ซึ่งกล่าวว่า If it looks like a duck and quacks like a duck, it must be a duck.

คุณจึงสามารถใช้ polymorphism ได้ ไม่ว่าจะเขียนโค้ดแบบนี้:

class Animal:
  def cry (self):
    pass

class Cat (Animal):
  def cry (self):
    print ("Meow!")

class Duck (Animal):
  def cry (self):
    print ("Quack!")

farm = []
farm.append (Cat())
farm.append (Duck())

for i in farm:
  i.cry()

หรือแบบนี้:

class Cat:
  def cry (self):
    print ("Meow!")

class Duck:
  def cry (self):
    print ("Quack!")

farm = []
farm.append (Cat())
farm.append (Duck())

for i in farm:
  i.cry()

คงพอเห็นภาพนะครับ

blog นี้เขียนถึงสิ่งที่สะดุด ก็ชักจะยาวแล้ว เดี๋ยว blog หน้าค่อยเขียนถึงสิ่งที่ผมชอบในไพธอนต่อนะครับ

หมายเหตุ: ด้วยความที่ผมยังเตาะแตะกับไพธอนอยู่ ที่เขียนไปอาจมีข้อผิดพลาดจากความไม่เข้าใจ ก็ยินดีรับข้อชี้แนะจากผู้รู้ครับ

โดย Thep (noreply@blogger.com) ณ 27 April 2016 08:16 GMT

22 April 2016

MrChoke

สิ่งที่ควรรู้กับ Garmin Edge รุ่น ไทย

ผมเป็นลูกค้า Garmin มาสักระยะ ตั้งแต่ผมปั่นจักรยานและมองหาตัวเก็บสถิติดีๆ สักตัว เริ่มตั้งแต่ Edge 810 ตัวแรก และ ต่อมาโชคดีได้จับรางวัลได้ Edge 1000 สิ่งแตกต่างของ 810 กับ 1000 คือ ตัว 1000 เป็นรุ่น Thai bundle มาส่วน 810 มีแค่ภาษาอังกฤษ ตอนแรกผมก็ไม่รู้ว่า Garmin จัดการเรื่อง Firmware ยังไง จนมาถึงการ update ครั้งใหญ่ความสามารถใหม่ๆ เพิ่มมาเพียบใน Edge 1000 ผมตั้งตารอคอยมานานติดตามข่าวตั้งแต่เค้ายังออกรุ่นทดสอบกัน และ เมื่อไม่นานก็มีการปล่อยออกมาจริงๆ แต่ต้องพบกับความผิดหวัง เมื่อ firmware ไทยไม่ update ตามรุ่น inter เมื่อไล่เรียงกลับไปพบว่าปัจจุบัน firmware edge 1000 ไทยยังอยู่ที่ รุ่น 5.2 ส่วนรุ่น [...]

โดย MrChoke ณ 22 April 2016 05:09 GMT

17 April 2016

Kitt

Using docker-machine to deploy multi-manager docker swarm

Of course, HA is a must in production environment. So, you gonna need multi-manager docker swarm. It is super easy when you know how. First, you cannot use token, you need a discovery service (consul, etcd, zookeeper). So, create one if you don’t have, e.g. $ docker-machine create -d virtualbox consul $ docker-machine ssh consul docker@consul:~$ docker run -d … Continue reading Using docker-machine to deploy multi-manager docker swarm

โดย kitty ณ 17 April 2016 05:29 GMT

11 April 2016

Kitt

สงกรานต์ 2559

สงกรานต์ปี 2559 เป็นปี จ.ศ. (2559 – 1181) = 1378 วันเถลิงศก ตรงกับ (1378 * 0.25875) + floor(1378 / 100 + 0.38) - floor(1378 / 4 + 0.5) - floor(1378 / 400 + 0.595) - 5.53375 = 356.5575 + 14 - 345 - 4 - 5.53375 = 16.02375 = วันที่ 16 เมษายน 2559 เวลา 00:34:12 วันสงกรานต์ ตรงกับ … Continue reading สงกรานต์ 2559

โดย kitty ณ 11 April 2016 06:02 GMT

7 April 2016

Neutron

LAB: Overlay Network across multiple cloud providers

หลังจากทำ Lab เรื่อง
Manage VPN clients to route over multiple data centers
เมื่อคราวก่อน ซึ่งแต่ละโหนด อยู่บน cloud providers จากหลาย ๆ data center (Thailand, Singapore, Japan, USA) และเราสามารถเชื่อมต่อทุก node เข้าหากัน ด้วย OpenVPN และ OSPF แล้ว นั่นหมายความว่า เรามี Unicast Routing ที่ใช้งานได้แล้ว

ขั้นต่อไป คือ การเตรียม Multicast Routing และเชื่อมต่อ Overlay Network ด้วย VXLAN

ทดสอบ


จะเห็นได้ว่า จาก 172.30.0.1 ไปหา 172.30.0.2 เสมือนต่อกันตรง ๆ และนั่นก็คือ Overlay Network

โดย neutron ณ 7 April 2016 04:10 GMT

2 April 2016

Neutron

Manage VPN clients to route over multiple data centers

Network เป็นเรื่องที่ผมให้ความสนใจเป็นอันดับต้น ๆ ในชีวิตการทำงาน และเป็นเครื่องมือใช้ประกอบอาชีพในปัจจุบัน

มีกรณีศึกษา ที่ผมคิดว่าเป็นโจทย์ที่น่าสนใจ เลยครุ่นคิด และลงมือทำ LAB เพื่อหาคำตอบ ว่าถ้ามีความต้องการแบบนี้ จะสามารถทำได้ไหม

ผมค่อย ๆ คิด และเริ่มหาทางไปทีละปัญหา

  1. เนื่องจากแต่ละ Data Center ไม่มี direct link จึงไม่เอื้อให้นำ routing protocol มาใช้งานโดยตรง ทางที่จะไปก็น่าจะต้องสร้าง L2 VPN ซึ่งผมเลือกเป็น OpenVPN ด้วยเหตุผลจากการทดลอง ในเครื่องจำลอง Linux KVM - 1 CPU, RAM 512 MB ได้ผลเป็นที่น่าพอใจ
    • สามารถทำ Throughput ขึ้นไปถึง 700-750 Mbps
    • Cipher: AES-128-CBC
    • การทดลองนี้ ผมเปรียบเทียบกับ default cipher ของ OpenVPN คือ Blowfish (BF-CBC) แล้ว AES-128-CBC ทำงานได้เร็วกว่า เหตุผลน่าจะมาจาก Linux KVM รองรับ AES-NI ซึ่งเป็นความสามารถหนึ่งที่มากับ CPU รุ่นใหม่ ๆ โดยเครื่องที่ใช้ทดสอบเป็น Core i5 แต่อย่างไรก็ตาม 700 - 750 Mbps ก็แลกมาด้วย CPU (1 core) 95 - 100%

  2. หลังจากได้ L2 connection ที่เสมือน router แต่ละ data center เชื่อมต่อกันโดยตรงได้แล้ว ก็สามารถนำ dynamic routing protocol มาใช้งานได้ ผมเลือกใช้ OSPF ผ่าน Open Source Router Software คือ Quagga และนี่เป็นครั้งแรกที่ผมได้ลงมือ และใช้งาน Quagga ไม่เคยใช้งานมาก่อนหน้านี้เลย แต่ที่ได้เจอ คือ คำสั่งเหมือน หรือใกล้เคียงกับ Cisco Router ก็เลยใช้เวลาศึกษาไม่นานนัก

ผมทดลองตัด VPN connection ก็ได้ผลเป็นไปตามที่ต้องการคือ client สามารถที่จะไปถึงปลายทาง โดยผ่าน backup route ได้ และวิ่งเส้นทางที่ใกล้ที่สุดเหมือนเดิม หลังจากที่ VPN connection กลับมาเชื่อมต่อปกติ

จาก LAB นี้ เราได้เส้นทางที่เชื่อมต่อกันระหว่าง data center และรองรับ dynamic routing แล้ว ขั้นถัดไปก็สามารถ

โดย neutron ณ 2 April 2016 10:32 GMT

19 March 2016

Kitt

AlphaGo and the future of AI.

The Go match between AI and pro is very interesting. I’m a fan of igo/weiqi/baduk. I used to play constantly, and was rated SDK (single-digit kyu). Also, as a computer scientist, Go is the only board game that the best human can defeat the best AI. Well, not anymore. AlphaGo, with deep/machine learning, was well-trained, and … Continue reading AlphaGo and the future of AI.

โดย kitty ณ 19 March 2016 13:38 GMT

26 February 2016

Udomsak

ว่างงานอีกครั้ง - Back to Available state again. ( Unemployed )

ตอนนี้กลับมาว่างงานอีกครั้ง หลังจาก Project  Capistrano ได้จบลง. ตอนนี้ก็วางแผนเอาไว้ คือ รับงาน แบบ Freelance

Back to Available state again ( Un-employed ) After Project Capistrano deployment end.  However my plan are below and I decide to do in Freelance and Contract way.

ระหว่างนั้นก็จะทำ , So  mean while i decide to do below too.

สนใจติดต่อ udomsak.chundang@gmail.com ขอบคุณครับ  // If you have job please contact me  :  udomsak.chundang@gmail.com 


โดย udomsakc (noreply@blogger.com) ณ 26 February 2016 18:17 GMT

22 February 2016

Kitt

Graylog Extractor for Fortigate Firewall

I’ve been using Graylog in production for awhile. It’s a great log analysis tool, backed by elasticsearch. Conceptually, graylog is pretty much like splunk. I consolidate approximately 170-200 million log messages to graylog everyday. So, I need to optimize them well enough. Few days ago, I started to use Fortigate extractors from a git repo. It … Continue reading Graylog Extractor for Fortigate Firewall

โดย kitty ณ 22 February 2016 10:08 GMT

bact

Sunset Provision – กำหนดวันหมดอายุให้กฎหมาย

เมื่อวันพฤหัสที่ 18 ก.พ. ที่ผ่านมา ระหว่างเสวนา “การเมืองบนใยแก้ว” #‎คิดนะแต่ไม่แสดงออก‬ ที่ องค์การนักศึกษามหาวิทยาลัยธรรมศาสตร์ ท่าพระจันทร์ จัด มีหัวข้อหนึ่งที่ถูกยกขึ้นมาคุย คือการสอดส่องโดยรัฐ ก็เลยคุยกันต่อถึง USA Patriot Act (แน่นอนว่าเป็นชื่อย่อ ชื่อเต็มคือ Uniting and Strengthening America by Providing Appropriate Tools Required to Intercept and Obstruct Terrorism Act – กูยอมใจ)

เลยได้มีโอกาสพูดถึงการรีวิว การต่ออายุ การต่ออายุอีกครั้งซึ่งที่ไม่สำเร็จ และการหมดอายุลงของบางมาตราใน Patriot Act เนื่องจากพบหลักฐานเชิงประจักษ์ในระหว่างที่กฎหมายบังคับใช้ว่ามันไม่ได้ทำงานได้อย่างที่มันอ้าง นอกจากนี้ในทางปฏิบัติยังนำไปสู่การละเมิดสิทธิหลายกรณี

การหมดอายุลงของบางมาตราในกฎหมายเช่นนี้ เป็นแนวคิดที่เรียกว่า “Sunset” (อาทิตย์อัสดง) ซึ่งเหตุผลในการกำหนดให้กฎหมายหมดอายุลงก็มีหลายเหตุผล บางเหตุผลก็เป็นเรื่องไม่ดีซะเท่าไหร่ เช่นกำหนดให้กฎหมายที่รัฐบาลนี้ออกหมดอายุลงเมื่อหมดอายุรัฐบาล เพื่อไม่ให้รัฐบาลหน้าเอากฎหมายเดียวกันกลับมาเล่นงานรัฐบาลเก่าได้

แต่ในกรณีอื่น มันก็มีเหตุผลที่ดีอยู่ เช่น การออกกฎหมายเพื่อรับมือกับสถานการณ์ฉุกเฉิน ที่สังคมมีแนวโน้มจะตื่นตระหนก panic กับสิ่งรอบตัว คนออกกฎหมายก็อาจจะใส่ sunset provision เข้าไป บอกว่าให้กฎหมายนี้เป็น “มาตรการชั่วคราว” นะ เช่น มีอายุ 5 ปีนะ พอจะครบ 5 ปี ถ้าเห็นว่ากฎหมายนี้ยังโอเคอยู่ ก็ให้ทำการต่ออายุมันซะ แต่ถ้าไม่ก็ปล่อยมันหมดอายุไป ตกลับขอบฟ้าไป เมื่อทำแบบนี้ ก็จะเป็นการบังคับให้ในอนาคตถ้ายังต้องการจะใช้กฎหมายต่อ ก็จะต้องมีการรีวิวทบทวนกฎหมายนั้นๆ ในสถานการณ์ที่เป็นปัจจุบัน ในภาวะที่คนหายตกใจกันแล้ว และด้วยข้อมูลเชิงประจักษณ์จากการใช้กฎหมายจริงในช่วงที่ผ่านมา (ซึ่งในสมัยออกกฎหมายตอนแรก ยังไม่มีข้อมูลแบบนี้)

Sunset provision ยังเป็นเหมือนการประนีประนอมด้วย ในข้อกฎหมายที่มีแนวโน้มจะละเมิดสิทธิพลเมืองสูง ที่ในภาวะปกติคงจะผ่านเป็นกฎหมายลำบาก แต่ในภาวะพิเศษ ผู้แทนในสภาฝั่งสิทธิพลเมืองก็คงจะไปทัดทานอะไรต้านกระแสสังคมไม่ได้นัก การยอมให้มีกฎหมายที่อาจละเมิดสิทธิแต่จำเป็นต้องใส่ sunset provision ก็เลยเหมือนเป็นการยอมถอย แต่ใส่เงื่อนไขไว้ว่า จะไม่ถอยตลอดไปนะ ถอยแค่เวลาจำกัดเท่านั้น

Sunset Provision ใน USA Patriot Act

กรณีของ Patriot Act มาตราที่เป็น Sunset provision คือมาตราที่เกี่ยวข้องกับการดักฟังและดักรับข้อมูล ซึ่งกฎหมายในตอนแรกกำหนดให้หมดอายุลงเมื่อวันที่ 31 ธันวาคม 2005 หลังจากนั้นก็มีการต่ออายุมาเรื่อยๆ รวมถึงออกกฎหมายให้บางมาตราที่เดิมเป็น Sunset provision หรือ “มาตราชั่วคราว” ให้กลายเป็น “มาตราถาวร” – ดู https://en.wikipedia.org/wiki/Sunset_provision#USA_PATRIOT_Act และ https://en.wikipedia.org/wiki/Patriot_Act#Reauthorizations

ส่วนตัวเลขงานวิจัยที่อ้างระหว่างการเสวนา ที่ว่าการดักฟัง-ดักรับข้อมูลแบบเหมารวมทีละเยอะๆ (bulk) ป้องกันการก่อการร้ายได้จริงๆ หรือ เอามาจากงานของ New American Foundation ซึ่งระบุว่า การใช้อำนาจตาม Section 215 ของ Patriot Act เพื่อเก็บข้อมูลพฤติกรรมการโทร (เบอร์ไหนโทรหาเบอร์ไหน เมื่อไหร่ ใช้เวลาแค่ไหน แต่ไม่มีเนื้อหาการคุย) นำไปสู่การเริ่มต้นการต่อต้านการก่อการร้ายที่สำเร็จเพียงอย่างมาก 1.8% ส่วนการใช้อำนาจสอดส่องคนที่ไม่ใช่พลเมืองสหรัฐตาม Section 702 ของกฎหมาย FISA นำไปสู่การสืบทราบเพียง 4.4% ในขณะที่โดยเปรียบเทียบแล้ว ในเคสที่ประสบความสำเร็จ มีการใช้อำนาจของ NSA ที่ไม่ได้เกี่ยวข้องกับ Section 215 หรือ 702 – อันหมายถึงการสืบหาข่าวด้วยวิธีการข่าวกรองแบบดั้งเดิม – อยู่ 21%

ซึ่งตีความได้ว่า ใช่การดักฟังการสื่อสารอาจจะช่วยต่อต้านการก่อการร้ายอยู่นิดหน่อย แต่มันมีวิธีอื่นที่ได้ผลกว่า-และละเมิดสิทธิบุคคลทั่วไปน้อยกว่า

ผลการศึกษาโดย New American Foundation ดังกล่าวมีชื่อว่า Do NSA’s Bulk Surveillance Programs Stop Terrorists? – เอกสารนี้เป็นส่วนหนึ่งของผลการศึกษาและข้อเสนอแนะจากหลายที่ ที่ถูกส่งให้คณะกรรมการรีวิวกฎหมาย Patriot Act รอบล่าสุด ที่สุดท้ายสภาคองเกรสตัดสินใจไม่ต่ออายุมาตราพวกนั้นใน Patriot Act (ไม่ได้แปลว่าทั้ง Patriot Act หมดอายุนะครับ เฉพาะบางมาตราเท่านั้น) แล้วออกกฎหมาย USA Freedom Act มาใช้แทน (ย่อมาจาก Uniting and Strengthening America by Fulfilling Rights and Ending Eavesdropping, Dragnet-collection and Online Monitoring Act – มึงเก่งมาก) ซึ่งยังอนุญาตให้หน่วยงานความมั่นคงสามารถเข้าถึงข้อมูลของบุคคลได้ แต่ต้องให้ศาลกลางอนุญาตก่อน

ผลการศึกษาอีกชิ้นที่พูดถึงในวันงานคือ Surveillance Costs: The NSA’s Impact on the Economy, Internet Freedom & Cybersecurity ซึ่งพูดถึงราคาที่สังคมต้องจ่ายจากโครงการข่าวกรองของ NSA

—-
ภาพประกอบ “sunset” โดย Matthias Bachmann – สัญญาอนุญาตครีเอทีฟคอมมอนส์แบบแสดงที่มา-อนุญาตแบบเดียวกัน

โดย bact ณ 22 February 2016 02:51 GMT

19 February 2016

Kitt

Quote for (belated) St.Valentine’s Day

… damn ..  5555+

โดย kitty ณ 19 February 2016 09:34 GMT

Make a bootable USB for Ubuntu Server Installation

Well, there are basically 3 tools. start-up disk creator unetbootin dd For most of the cases, the first one would work well – boot from USB drive, then you have a go. For some other cases, unetbootin could do the job. And in some rare cases, like mine – yesterday – with Ubuntu Server 14.04.3 … Continue reading Make a bootable USB for Ubuntu Server Installation

โดย kitty ณ 19 February 2016 09:28 GMT

Sort file alphabetically in Samba

It looks like samba sending a list of file names in random order. Of course, you could make it sort alphabetically and make your life easier. For Debian/Ubuntu # apt-get install samba-vfs-modules then edit /etc/samba/smb.conf [global] vfs objects = dirsort Restart your samba, and tada !

โดย kitty ณ 19 February 2016 09:28 GMT

F5 อ่อนว่ะ

ไปร่วมงานสัมมนา “F5 อ่อนว่ะ” ได้ข้อสรุปอย่างหนึ่งที่พี่โดมอาจจะไม่ได้พูดถึง แต่ผมคิดว่าเป็น success factor ของ large scale web นอกเหนือไปจาก design pattern ที่พี่โดมพูดไว้ในงานไปแล้ว นั่นคือ “ทีม” พี่โดมมีทีมที่ทำงานด้วยกันตั้งแต่ออกแบบ วาง infra ยัน software dev นอกจากจะเป็นทีมที่เทคนิคแข็งแกร่ง ประสบการณ์สูงแล้ว ยังเชื่อมต่อพูดคุย product เป็นเนื้อเดียวตั้งแต่ต้นจนจบ อย่างที่ ดีน กับ ไมเคิล พูดในงาน DevOps Meetup #1 ไว้ว่า DevOps ไม่ใช่ job position ที่ไว้ประสาน / เป็นกันชนระหว่างฝั่ง developers กับฝั่ง IT operations DevOps มันคือ “mindsets ในการสลาย developer silo กับ IT … Continue reading F5 อ่อนว่ะ

โดย kitty ณ 19 February 2016 09:28 GMT

IBM AMM USB keyboard issue

Many admin faced an issue when using a USB keyboard on IBM Advanced Management Module (AMM) with Linux. It seems that some Linux distros do not recognize USB device on IBM AMM and then power off the USB port, disconnect a device plugged in. The solution is quite straightforward: always supply the power to the … Continue reading IBM AMM USB keyboard issue

โดย kitty ณ 19 February 2016 09:28 GMT