Building Blue: bd2.in.th

ผมเป็นคนนึงครับที่ชอบอ่านเรื่องเบื้องหลังเว็บไซต์ต่างๆ มาก ใน Feed reader ผมจะมี Facebook Engineering, Twitter Engineering, Github blog ไว้เลยเพื่อจะอ่านเรื่องพวกนี้ ก็เลยว่าอยากลองมาเขียนเองบ้าง

สำหรับวันนี้โปรเจกท์ที่นำเสนอคือ bd2.in.th ครับ เป็นโปรเจกท์นึงที่ผมภูมิใจมากเพราะระบบมันค่อนข้างจะล้ำสมัยกว่าเว็บไซต์อื่นๆ เลยนะครับ

หน้า bd2.in.th ในปัจจุบัน

ในยุคแรกนั้นมีเว็บไซต์ dek-bd2.com ของ @ntklp ครับ เป็นเว็บประกาศข่าว แล้ว @icedrummer ก็ยืมวิทยุออนไลน์ของผมที่อยู่บนเซิร์ฟเวอร์ผมไปจัดเป็นวิทยุ ซึ่งก็จัดนานๆ ครั้ง ผมเองไม่ได้เกี่ยวกับโครงการนั้นก็ไม่ได้เข้าไปดูครับ ต่อมา @ntklp @ByakkoHD และคนอื่นๆ ก็ได้รวมกันทำเว็บบอร์ดขึ้นมาใหม่ให้เป็นรูปเป็นร่าง โดยตอนนั้นอยู่ที่ dek-bd2.whsgroup.ath.cx และแน่นอนว่ามันเครื่องผม ถึงผมจะไม่ค่อยอยากยุ่งแต่ก็ต้องเข้าไปดู maintain ต่างๆ จนกลายมาเป็น coder นิดๆ หน่อยๆ ครับ จนมาวันนึงเราคิดว่าขี้เกียจเมนเทน hosted sites แล้ว เลยผลักดันให้เว็บต่างๆ ออกไปข้างนอก ก็จะกลายมาเป็น bd2.in.th ครับ (ค่าโดเมนปีแรกสนับสนุนโดย @2DaDream) โดยใช้โฮสต์ clnox ที่ผมซื้อเอาไว้ทำ thaifedora.com มาก่อน (ตอนหลังมีคนรับไปอุปการะครับ แต่ผมเองไม่ค่อยว่างจะไปดูเว็บนั้น) และก็ได้พัฒนามาหลายรุ่นเลยครับ

– dek-bd2.com ใช้ WordPress เว็บบอร์ดผมไม่แน่ใจว่ามีไหม
– dek-bd2.whsgroup.ath.cx ใช้ SMF
– bd2.in.th ใช้ Drupal เป็นหน้าแรก และมี SMF เป็นบอร์ด รุ่นนี้มีธีมหลายตัวเลยครับ ตัวแรกสุดที่ผมทำจะเป็นหน้าเหมือน wordpress.org และตัวต่อมาเป็นตัวสุดท้ายที่มีพื้นเป็นก้อนเมฆ​ (จริงๆ มีรูปเมือง รูปก้อนเมฆ และรูปใต้ดิน) และบอร์ดก็จะใช้ธีมนี้ด้วยครับ​ โดยธีมนี้ได้แรงบันดาลใจจาก f0nt.com

ธีม bd2.in.th บนเซิร์ฟเวอร์ทดสอบ
ธีม FunBD2 บนเซิร์ฟเวอร์ทดสอบ

– ยุคต่อมา @ntklp ได้ตัดสินใจใช้ WordPress ผมเองก็ไม่ค่อยอยากยุ่งกับตรงนั้นแล้ว (ผลจากที่ผมเบื่อที่จะต้องมาทำธีมหลายๆ ที) เลยปล่อยให้ไปทำเอาเอง
– @ntklp ขอผมใช้วิทยุอีกครั้งนึงและได้เปิดเป็น Blue Wave Radio โดยรุ่นแรกใช้หน้าเว็บพื้นๆ เป็น HTML file เดียว ฟังได้อย่างเดียว ไม่มีชื่อเพลงไม่มีอะไรทั้งนั้น
– รุ่นต่อมาของ Blue Wave Radio ผมได้พัฒนาเป็นหน้าเว็บเต็มรูปแบบ รุ่นแรกๆ มีการแสดงชื่อเพลง และมีการดึง cover art โดยใช้ Covershare API

Bluewave รุ่นแรกๆ บนเซิร์ฟเวอร์ทดสอบ (ไอเดียจากหน้า ไก่คุ้ยตุ่ยเขี่ย เว็บ Green Wave)
Bluewave รุ่นสอง ใช้ช่วงปีใหม่ 2554 (ใช้ Blueprint CSS)

– รุ่นต่อมาอีกมีการแชทครับ แรกๆ ใช้ irc.freenode.net ห้อง #dekbd2 ผมได้ปรับ @willwillBot รุ่น IRC ให้มีความสามารถรองรับการขอเพลงต่างๆ โดยอาศัยว่าระบบขอเพลงนั้นยังอยู่บนเครื่องผมเลยทำให้ sync ข้อมูลกันได้โดยง่าย
– ต่อมามันมีคนมาฟลัชประจำ ผมจะแบนก็ไม่ได้เพราะใช้ webchat กัน เลยตัดสินใจเปลี่ยนมาเขียนแชทเองโดย integrate กับ SMF, Facebook, ฐานข้อมูลนักเรียน ใช้เวลาเขียนระบบแชทครึ่งวันครับ! (โมโหมาก) และก็แก้บั๊กมหาศาลอีกวันนึงก็เข้าขั้นพอใช้ได้แล้ว
– นอกจากนี้บลูเวฟยังมีการปรับหน้าตาอีกหลายครั้งครับ รุ่นสุดท้ายก่อนมาใช้โทนมืดในปัจจุบันจะมีรายการเพลงที่ขอให้คนดูดูด้วยครับ

รุ่นนี้ออกมาได้วันเดียวก็เลิกใช้เพราะคนฟังบอกว่ารกมาก

– ต่อมาเปิดเทอม 1/2554 เราได้จัดตั้งเป็นชมรม bd2.in.th (ชื่อชมรมชื่อนี้) ในโรงเรียนครับ มีสมาชิกประมาณ 25 คนในระดับม. 3, 5, 6
– ประชุมชมรมแรกๆ ผมได้เสนอและได้ทำการเปลี่ยนเว็บบอร์ดให้เป็น Vanilla ครับ เนื่องด้วยว่า @ntklp ให้ดูตัวอย่างจากเว็บอื่นๆ เช่นสวนบอร์ดและบดินทรโซน ซึ่งจะเน้นบอร์ดน้อย และมีหน้ารวมกระทู้ โดย Vanilla เองสามารถทำแบบนั้นได้ หรือจะแยกบอร์ดก็ได้
– @ntklp ได้หาเทมเพลทมาให้ผมทำ Blue wave UI ใหม่ และก็ได้มาเป็นบลูเวฟรุ่นในปัจจุบันครับ​ ซึ่งตัดฟีเจอร์ออกไปจำนวนมากเลยเพื่อให้มันครบถ้วนในหน้าเดียว
– ผมได้เขียน Plugin ของ Vanilla ให้มีการทำ notify แบบ Google+ ได้ครับ

มาดูเบื้องหลังเว็บดีกว่าครับ ว่าอะไรอยู่กับอะไร เริ่มแรกที่ส่วนหัวเว็บก่อนนะครับ หัวเว็บ bd2.in.th จะมีแถบ ซึ่งผมเรียกมันว่า Dickbar ตามชื่อของ UIDickbar ใน Twitter for iPhone (แต่ UIDickbar หน้าตาเหมือนแผ่นประกาศเที่ยวบินตามสนามบินนะครับ ไม่ใช่แถบแบบนี้) โดยผมบอกสมาชิกชมรมว่า เว็บไซต์จะใช้ธีมอะไรก็ได้ ใช้ CMS อะไรก็ได้ ไม่จำเป็นต้องเหมือนกันหมด แต่ต้องมีสิ่งหนึ่งบอกว่าเรายังอยู่ในเว็บ bd2.in.th นะ ไม่ได้หลุดไปที่อื่น เลยโค้ดออกมาเป็นตัวนี้ครับ

ตัว dickbar นี้ใช้ WordPress API ครับ หน้าที่จะมี Dickbar ทุกหน้าจะต้องเรียก WordPress เข้าไปก่อนแล้วค่อย include file เข้าไป ซึ่งไฟล์นี้ไฟล์เดียวเรียกปุ๊บจะได้ทั้งแถบเลยครับ โดยประกอบด้วยแถบเมนูที่ดึงมาจาก menu ของ WordPress และ CSS, JavaScript ประกอบ (เมนู drop down ที่เห็นนั่น Pure CSS นะครับ ส่วน JavaScript จะใช้ในส่วนของ unread notify และเดิมจะมีระบบ notify ของบอร์ดด้วยครับ แต่ถูกถอดไปแล้วเพราะแทนด้วยระบบ unread notify นอกจากนี้ยังเคยมี countdown ไปวันสอบ (ไม่มีแล้วเพราะใช้ปฎิทินแทน))

Dickbar

ส่วนต่อมานะครับ คือ unread notify ของบอร์ด ตัวนี้ผมใช้ iframe เข้าไปในบอร์ดครับ โดยผมเขียน module เองเพื่อมาแสดง notify และใช้ parent.window เพื่อบอกให้ JavaScript ของ Dickbar ทราบว่ามี unread เท่าไร แม้ไม่ต้องคลิกก็สามารถรู้ตัวเลขได้ (อันนี้ต้องใช้ทริกนิดหน่อยครับเพื่อให้สามารถข้าม subdomain ได้) สำหรับตัวนี้ ตอนแรกวางแผนจะใช้ WebSocket ครับ แต่เปลี่ยนใช้ให้มัน reload หน้า iframe เอาดีกว่าเพราะข้อความไม่ได้เร่งด่วน

อ้อ สำหรับเว็บบอร์ดนั้นผมลองดึง WordPress เข้าไปแล้วครับ แน่นอนว่าพังครับ ฉะนั้น Dickbar ของบอร์ดนั้นผม copy markup จากหน้าอื่นเข้าไปใส่ในธีมเอาครับ

สำหรับส่วนสุดท้ายนะครับ มีความซับซ้อนที่สุดคือระบบบลูเวฟครับ ผมเคยลองเขียนไดอะแกรมแสดงการทำงานแล้วพบว่าเขียนยากอยู่เหมือนกันเพราะมันซับซ้อนครับ

– เมื่อเปิดเข้าไปหน้า [live.bd2.in.th](http://live.bd2.in.th) นะครับ โปรแกรมจะโหลด WordPress มาแสดง Bar และก็แสดงหน้าให้เรียบร้อย
– จะมีการยิง AJAX request เข้าไปสองที่ครับ ที่แรกเพื่อดูสถานะว่ากำลังเล่นเพลงอะไร และที่ที่สองเพื่อดึงว่าขณะนี้ DJ ตั้งค่าระบบอย่างไร (มีสามค่าครับ คือข้อความประกาศข้างบน การเปิดปิด request และเวลาที่ห้ามขอหลังจากขอไปแล้ว)
– หลังจากนั้นแล้วหากมี DJ จัดปกติ โปรแกรมจะเปิดวิทยุครับ โดยตอนแรกผมใช้ [flowplayer ](http://flowplayer.org) แต่ด้วยข้อจำกัดด้านเนื้อที่เลยมาใช้ [SoundManager](http://www.schillmania.com/projects/soundmanager2/) + [jQuery UI](http://jqueryui.com) แทน
– นอกจากนั้นแล้วโปรแกรมยังจะเปิด​ WebSocket ไปด้วยครับ​​ โดยผมเลือกใช้ [Faye](http://faye.jcoglan.com/) เป็น server ครับเพราะมีลักษณะเป็นห้องๆ และยังสามารถใช้วิธีอื่นๆ ได้หากเครื่องไม่รองรับ WebSocket ด้วยครับ
– ขณะเล่นเพลงอยู่ WebSocket server จะ poll มาหาเพลงที่กำลังเล่นครับ (ไฟล์เดียวกับที่ request ไปตอนเปิดหน้านั่นแหละครับ ผมขี้เกียจ port ลง JavaScript ด้วยปัญหา encoding ต่างๆ) แล้วก็จะปาเข้าไปใน stream ด้วย ทำให้ client ไม่ต้อง poll server เองพร้อมกันหลายๆ คน ส่วน state นั้นเมื่อดีเจอัพเดตข้อมูล โปรแกรมจะส่งเข้ามาใน faye อยู่แล้วครับ ไม่จำเป็นต้อง poll
– Faye สามารถรับส่งได้สองทางครับ เพื่อป้องกันไม่ให้ client ส่งข้อความเข้าไป ผมได้มีการยึนยันด้วย Shared secret ครับ โดยมีรหัสผ่านนึงที่ทั้งสองฝั่งจะทราบและต้องส่งไปด้วย ถ้าไม่มีหรือไม่ถูกแปลว่าปลอมแน่นอนครับ ยกเว้นห้อง user online ผมอนุญาตให้ client ส่งเข้าไปได้เลย แต่จะมี shared secret อีกอันหนึ่งที่จะ sign กำกับข้อมูลที่ส่ง ซึ่ง server generate ให้ ดังนั้นหากมีการเปลี่ยนแปลงข้อมูลไม่ตรงกับที่ server กำหนดมาให้ ถึงจะส่งเข้าไปได้แต่เซิร์ฟเวอร์ก็ไม่รับครับ

สำหรับด้าน backend ของ DJ นะครับ เดิมทีผมจะใช้ htdigest authentication ฉะนั้นดีเจทุกคนจึงมีรหัสเดียวกัน (ผมขี้เกียจครีหลายอัน) ก็จะมีปัญหาตอนจะเอาดีเจออกเพราะมันต้องเปลี่ยนรหัส จนตอนเขียนแชทใหม่ผมเลยได้รื้อ backend ครับ (โค้ดเดิมมันเน่ามากเพราะเขียนแบบ Quick & Dirty ปัจจุบันโค้ดมันก็ก๊อปแปะจากตรงนั้นมาบางส่วนก็ยังเน่าๆ อยู่ครับ) โดยให้ยึนยันตัวด้วย WordPress แทน และใช้ Permission ของ WordPress ไปเลย และ Request ที่ขอมาจะเก็บลง Redis server ครับ และยังจะ push ไปยัง websocket ของ DJ ด้วยนะครับ (DJ มีห้อง websocket ต่างหาก) หลังจากดีเจเปิดเพลงให้แล้วมันจะพุชมาทาง websocket ครับและ client จะหาว่าใช่ของตัวเองมั้ย ถ้าใช่ก็ให้แสดงข้อความว่าเปิดเพลงให้แล้วนะ (ข้อมูลนี้ไม่ใช่ความลับครับ ฉะนั้นจึงให้วิ่งกระจายไปได้เลย) และด้านเซิร์ฟเวอร์ก็จะเซฟลง MySQL เพื่อใช้เป็นข้อมูลในการ Autocomplete ต่อไป

ระบบขอเพลง

ส่วนสุดท้ายในเว็บครับ คือส่วนของออโต้บอทจัดเพลง โดยผมใช้โปรแกรม ices ครับ ที่ผมแพทช์ไว้นิดนึงให้มันไม่ปิดตัวเองเมื่อต่อไม่ได้หลายครั้ง เพราะว่าเมื่อดีเจเตะบอททิ้งแล้วบอตจะหลุด และพอต่อไม่ได้บอตจะปิดตัวเองทำให้เมื่อดีเจจัดเสร็จแล้วบอตไม่กลับมา วิธีนี้ทำให้บอตกลับมาได้เอง โดยไม่ต้องกดเปิดบอตครับ​ (ผมยังคิดวิธีเปิดบอตที่ปลอดภัยไม่ได้เลยนะครับ เพราะบอตมันรันคนละ user กันด้วย) โดย ices อนุญาตให้เขียนสคริปต์ควบคุมได้ครับ ผมใช้ Python เขียนควบคุม โดยมีหลายโค้ดดังนี้ครับ

– ทุกเพลงจะสุ่ม 25% มีโอกาสเปิดจิงเกิ้ล​​ (ตอนหลังผมแก้ไว้ว่าห้ามเปิดจิ้งเกิ้ลต่อเนื่อง เพราะเคยมีบั๊กเปิดต่อกันห้ารอบแล้วนะครับ)
– เวลาแปดโมงเช้า หกโมงเย็น จะเปิดเพลงชาติไทย และเปิดจิ้งเกิ้ลตาม (ID3 Tag ของเพลงชาติและจิ้งเกิ้ลผม hard code ไว้ครับ เพลงอื่นมันจะดึง ID3 เองได้)
– บอตจะไม่เปิดเพลงศิลปินเดิมติดกัน (เพราะเคยมีบอตเปิดเฉลียงซ้ำๆ จนคนฟังเบื่อ)
– ก่อนจะเข้าระบบ playlist บอตจะดึงข้อมูลจาก redis ว่ามีเพลง request ใหม่หรือไม่ ถ้ามีก็จะเปิดให้ พร้อมแสดงชื่อคนขอให้เสร็จสรรพครับ
– การเตะบอตทำที่หน้า DJ Backend โดยมันจะเตะที่ shoutcast ครับ ไม่ได้เตะโพรเซสบอต เมื่อเตะแล้ว​ DJ จึงต้องรีบเข้ามาจัดต่อทันที

สำหรับ caching ในเว็บ ผมไม่แน่ใจว่าใน CMS ผมเซตอะไรบ้างนะครับ (ใช้ W3 Total Cache ด้วยนะครับ บล็อคผมที่ท่านอ่านอยู่นี้ก็ใช้) แต่ว่าสำหรับใน Blue wave เดิมทีไม่มีแคชครับ (มันเคยบั๊กเลยปลด ก่อนหน้านี้เป็น memcached) ปัจจุบันแคชเพลงที่กำลังเปิดใช้ Redis ครับ

ITKMITL PHP Competition

สำหรับบล็อควันนี้ @Fantasier request มาครับว่าอยากให้ blog เกี่ยวกับการแข่ง PHP ในงาน openhouse ที่คณะ IT ลาดกระบัง

ก็ไปถึงรถติดในม. โคตรๆ ครับ ผมนึกว่าจะไม่ทันอยู่แล้ว เข้าไปเค้าบอกอีกสิบนาทีเริ่ม แต่เอ๊ะ ลงชื่อแล้วแฟนต้าเสี่ยยังไม่เห็นมา ไม่เป็นไร รีบลงรีบเข้าแข่ง

มาถึงโจทย์นะครับ โจทย์นี้จะประกาศเมื่อเริ่มแข่ง ผมเลยต้อง skim อ่านอย่างไวได้ความประมาณว่าแพนด้าอยากคุยกัน เลยให้ทำ Panda chat lnw โดยมีแชทรูทต่างๆ ให้เข้าไปแชทได้ จะต้องมีการแสดง user online มีระบบกรองคำหยาบและ emoticon

แข่งอันนี้ดีอย่างครับ เค้าจะมีภาพกราฟฟิคต่างๆ ให้เลย คือไม่ต้องไปนั่งทำเองเหมาะสำหรับคนทำกราฟฟิคไม่เก่งแบบผม ให้ใช้เวลาโฟกัสกับโค้ดได้เลย

สำหรับชั่วโมงแรกนะครับ ผมปั่น register ก่อนเป็นอย่างแรก​โดยออกแบบฐานข้อมูลตามโจทย์ให้มาเป๊ะ แล้วก็ form ตามโจทย์เลย แต่โค้ดสำหรับการสมัครนี่สิครับนั่งเขียนยาวมาก โดยทำ design ที่ว่าไปก่อนนี้ประมาณ 20 นาทีส่วนอีก 40 นาทีเป็นโค้ดสมัครครับ โดยจะต้องมี input validation แทบทุกช่อง และผมเองลืม print regular expression มา​​ ฉะนั้นเดาสดครับ ก็โชคดึว่ามันไม่ค่อยบั๊กเลยสามารถเสร็จได้ทัน ส่วนการ login นั้นแค่ดึงมาเช็คอยู่แล้วครับเขียนไม่นาน และการตรวจสอบ user ผมจะแยกเป็น function ไว้อยู่แล้ว ซึ่งจะเขียนเป็นลำดับแรกๆ (แนวนี้ผมได้ไอเดียจากฟังก์ชั่น is_user_logged_in ของ WordPress ครับ และ project Sora เองก็มีฟังค์ชั่นนี้)

ต่อมาครับเป็นรายการแชท ถึงตรงนี้ผมเองว่าน่าจะเริ่มออกแบบฐานข้อมูลได้แล้ว เลยทำทีเดียวให้เสร็จครับ บังเอิญว่าโจทย์ตรงกับแชทที่ผมเคยทำมาก่อน เลยออกแบบตามของ bd2.in.th อันเก่าไปเลย (อันเก่าผมเขียนด้วยอารมณ์โมโหครับ ทำเสร็จในวันเดียวได้ แต่เห็นโจทย์วันนี้ตอนแรกผมเองยังว่าไม่น่าจะเสร็จทัน AJAX) ก็จะมีตารางสำหรับเก็บห้องแชท เก็บข้อความในแชท เก็บ user online ครับ เสร็จแล้วการ list ก็ไม่ยากครับดึงมาใส่ตัวแปร แล้วผมจะแยกส่วนของ template (view) ไปอีกไฟล์เลย (คือแยก view-controller ชัดเจน ส่วนถ้าจะมี model ใน PHP layer คงไม่ทันครับ)

ถัดมาของห้องแชทครับ ตรงนี้ผมก็ทำ layout ให้เสร็จก่อน จากนั้นจึงเริ่มที๋โค้ด ผมตัดสินใจว่าจะไม่ gratefully degrade (project sora ถ้าปิด javascript จะเห็นข้อความเก่าแต่ทำอะไรไม่ได้ครับ) แต่จะดึงข้อความด้วย javascript 100% เลย (คือถ้าปิด javascript จะไม่เห็นข้อความ) จากนั้นก็เขียน chat server ขึ้นมาครับ โดยเป็นไฟล์ที่จะไปเรียกเอารายการแชทล่าสุดมาทำ JSON ให้แล้วส่งกลับ จากนั้น JavaScript จะหาว่า ID ล่าสุดที่เคยประมวลผลไปคือเลขอะไร แล้วก็จะไม่ประมวลผล ID ที่น้อยกว่าเลขนั้นทำให้ข้อความไม่ซ้ำถึง server จะส่งมาซ้ำ ต่อมาครับก็จะเป็นการส่ง ส่งไปแล้วจริงๆถ้าให้ไวมันจะต้องคืนข้อความมาให้เราประมวลผลใน client ได้ครับ แต่ด้วยความขี้เกียจผมเลยไม่คืนอะไรมา แล้วให้ client ดึงแชทใหม่อีกรอบไปเลย จบ

ถึงตรงนี้ได้ผมก็เหลือแต่ส่วนเดียวแล้วแหละครับ คือ user online ตรงนี้อัลกอรึธึมยาก ผมเชื่อว่ามีวิธีง่ายกว่านี้ (เพราะโจทย์กำหนด และแชทอื่นๆ เค้าทำได้) แต่ผมไม่รู้ครับ วิธีที่ผมใช้คือ client จะ poll server เป็นระยะ ตัว server จะเก็บเวลาที่ poll ไว้ แล้วคืนไปว่าใน 5 วิเนี่ยมีใครติดต่อมาบ้าง จากนั้น client จะเปรียบเทียบจากข้อมูลเก่ากับข้อมูลใหม่ว่ามีใครหายไปหรือเข้ามาบ้างครับแล้วก็จะทำการแสดงข้อความ (แชทของ bd2 อันเก่าใช้วิธีนี้ แต่จะวาด list ใหม่เลยไม่มีการถอด user ออกทีละคนได้ ส่วนแชทปัจจุบันวิธีเก็บ user online ซับซ้อนกว่านี้ครับเพราะใช้ websocket ไว้ถ้ามีโอกาสจะมาเล่า) แล้วก็สำหรับ user online ในหน้าแรกครับ บังเอิญนึกถึง GROUP BY ที่อยากเล่นอยู่ เลยลองเขียนไปดูว่า `SELECT room, COUNT(*) cnt FROM online WHERE room=1 AND time >= ‘time()-5’ GROUP BY room` แล้วมันก็ได้ผลครับ ทำให้มันดึงทีเดียวหลายห้องได้ใน query เดียว​ (bluewavechat ยังต้องนั่งดึงทีละเพลงเลยครับ)

ที่เหลือก็เก็บรายละเอียดครับ พวกกรองคำหยาบ และ emote และที่สำคัญมากคือเวลาอ่านแชทข้างบนอยู่มันจะไม่ autoscroll

สำหรับการ present นะครับ ผมพูดตาม slide ที่เตรียมไป กรรมการเองยังงงๆ กับเรื่อง salt ที่ผมเน้นย้ำด้วยแหละครับ (ผมรู้จัก salt จาก SMF น่ะครับ — กรรมการก็ถามเรื่องนี้) แล้วก็ที่โดนท้วงมาก็จะมี IE ที่ผมพลาดลืมเช็ค แล้วก็เรื่อง autoscroll บั๊กนิดหน่อยครับ นอกจากนี้ผมยังพูดเรื่อง WebSocket ที่เป็นชื่อทีมไปด้วยว่าถ้าได้ใช้แชทคงจะเจ๋งกว่านี้ (ถ้าทันเวลา) นะครับ เค้าก็เลยถามถึงเรื่องตรงนี้หน่อยซึ่งผมก็อธิบายแชทของ bd2.in.th ไปให้ฟัง

สำหรับผลการแข่งขัน ได้ที่ 1 ครับ ทุนการศึกษา 4,000 บาทและโควต้า งานนี้ต้องขอบคุณ bd2.in.th นี่แหละครับที่ทำให้ผมได้เขียนแชทสองตัวฝึกประสบการณ์

ปล. ผมว่าโจทย์มันเน้นที่ AJAX ไปนะครับ คือแชทที่เขียนไม่ใช้ AJAX นี่มันจะแบบว่าไม่เร้าใจเลยแล้ว present ไม่มัน มันมีอีกหลายๆ อย่างนะครับที่ไม่มี AJAX ก็ได้ บางอย่างใช้ AJAX แล้วมันจะเป็นส่วนเกินด้วยซ้ำ