แปะ embed ง่าย ด้วย oEmbed

oEmbed is a format for allowing an embedded representation of a URL on third party sites. The simple API allows a website to display embedded content (such as photos or videos) when a user posts a link to that resource, without having to parse the resource directly.

ไอเดียแก่นของ social media หรือ สื่อทางสังคม ก็คือมัน(ต้อง) share หรือ แบ่งปัน ได้ง่าย การบอกต่อมันถึงจะไปได้ไกล

oEmbed เป็นข้อตกลงสำหรับรูปแบบการ แปะ สื่อ embed (เช่น วิดีโอ เสียง แฟลช) ที่ทำให้ผู้ใช้แปะเพียง url ไม่ต้องแปะโค้ด html ยาว ๆ ซึ่งนอกจากจะงงแล้ว ยังมีโอกาสผิดพลาดด้วย

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

  1. ผู้ใช้แปะลิงก์รูป http://www.flickr.com/photos/bees/2341623661/ ในเว็บบอร์ด
  2. เว็บบอร์ดพบว่า ลิงก์ดังกล่าว เข้าแก๊ป URL scheme: http://*.flickr.com/photos/* ซึ่งแปลว่าเป็น embed representation ซึ่งเชื่อมอยู่กับ API endpoint: http://www.flickr.com/services/oembed/
  3. เว็บบอร์ดจึงถามข้อมูลของ embed ตัวนี้ ไปที่ API endpoint โดยใช้ request ดังนี้ http://www.flickr.com/services/oembed/?url=http%3A//www.flickr.com/photos/bees/2341623661/
  4. ตัว API ส่งข้อมูลกลับมาให้เว็บบอร์ด เป็น XML หรือ JSON เช่น
    {
     "version": "1.0",
     "type": "photo",
     "width": 240,
     "height": 160,
     "title": "ZB8T0193",
     "url": "http://farm4.static.flickr.com/3123/2341623661_7c99f48bbf_m.jpg",
     "author_name": "Bees",
     "author_url": "http://www.flickr.com/photos/bees/",
     "provider_name": "Flickr",
     "provider_url": "http://www.flickr.com/"
    }
    
  5. ตัวเว็บบอร์ด ก็จะเอาข้อมูลตรงนี้ ไปสร้างโค้ด embed ให้เอง

ในมุมมองของผู้ใช้แล้ว แบบนี้ง่ายกว่าเยอะ

ในมุมมองของนักพัฒนาเว็บ แบบนี้ก็ปลอดภัยกว่าด้วย เนื่องจากการได้ข้อมูลของสื่อ embed ผ่าน oEmbed API ทำให้เราไม่ต้องเดาข้อมูลต่าง ๆ เอง หรือ parse ข้อมูลแบบ hack ๆ กันเอาเอง ซึ่งแม้จะใช้งานได้ แต่ถ้าเมื่อไหร่ url หรือ html ของหน้าสื่อนั้นเปลี่ยน ก็จะเกิด dead link ทันที

มีบริการรับฝากสื่อออนไลน์หลายแห่งใช้ oEmbed แล้ว เช่น Flickr สำหรับภาพ และ Vimeo สำหรับภาพเคลื่อนไหว

Providers (ตอบ request oEmbed ได้):
Flickr, Viddler, Qik, Pownce, Revision3, Hulu, Vimeo, oohEmbed — ตัวหลังสุดนี้ มันเป็นประมาณ wrapper ของหลาย ๆ บริการอีกทีนึง เช่น Amazon (Ars Technica ใช้บริการจาก oohEmbed ตัวนี้)

Consumers (แสดงลิงก์ oEmbed ได้): Pownce, Buckybase , 280 Slides, Dumble

สำหรับ WordPress มีปลั๊กอินสำหรับ oEmbed แล้วหนึ่งตัว คือ NFB Video Plugin ใช้งานได้กับ NFB (National Film Board of Canada) และ Vimeo (เป็นวิดีโอทั้งคู่)

Drupal มีก็มีโมดูล oEmbed

ถ้าอยากจะเขียนเล่นเอง ก็มีไลบรารีอำนวยความสะดวกสำหรับหลายภาษา:

น่าเอาไปใช้กะโปรเจกต์ของโอเพ่นดรีมมั่ง

technorati tags:
,
,

NLTK corpus readers for NECTEC BEST and ORCHID corpora

ความเดิมจากตอนที่แล้ว ทดลองสร้าง corpus reader ใน NLTK

ตอนนี้แก้การ encode ให้ใช้ได้กับ nltk.Text() แล้ว (แทนที่จะเก็บเป็น unicode ก็เก็บเป็น utf-8 encoded str แทน)

พร้อมกับเพิ่มตัวอ่านสำหรับคลังข้อความ BEST และ ORCHID ด้วย

ตัวอ่านคลัง BEST ในรุ่น 0.3 นี้ เรียกดูเป็นหมวดได้ (ข่าว วรรณกรรม สารานุกรม บทความ) เรียกดูข้อมูลกำกับขอบเขตคำ (word boundaries) ได้ แต่ยังไม่รองรับ <NE>named-entities</NE> กับ <AB>คำย่อ</AB> เนื่องจาก BEST ไม่มีข้อมูลขอบเขตประโยค ตัวอ่านคลังจะสร้างขึ้นเอง โดยสมมติ \n เป็นขอบเขตประโยค

ส่วนตัวอ่านคลัง ORCHID ในรุ่น 0.3 นี้ เรียกดูข้อมูลกำกับขอบเขตคำและชนิดคำ (Part-of-Speech) ได้ แต่ยังไม่รองรับขอบเขตย่อหน้า และยังเรียกดูเป็นรายเอกสารไม่ได้ (รุ่นนี้ทำงานกับคลัง ORCHID แบบที่ถูกเอา document-related metadata ออกไป)

ดาวน์โหลด & ติดตั้ง

แพ็คเกจ rotic รุ่น 0.3 ซอร์สโค้ดเผยแพร่ด้วยสัญญาอนุญาต GNU GPLv2 ตาม NLTK – ดาวน์โหลด rotic-0.3.tar.gz

วิธีติดตั้ง อ่าน README.TXT และ INSTALL.TXT – อย่าลืมดาวน์โหลดคลังข้อความมาติดตั้งด้วย รายละเอียดและสัญญาอนุญาตของข้อมูลแต่ละชุด อยู่ใน CORPORA.TXT

มีคำแนะนำอะไร เขียนมาบอกกันได้ครับ อยากจะลองทำให้มันเอาไปใช้ในการเรียนการสอนได้ – ไม่เฉพาะสำหรับนักเรียนคอมพิวเตอร์เท่านั้น แต่สำหรับนักเรียนภาษาศาสตร์ ฯลฯ ด้วย

ตอนนี้ความเร็วไม่ค่อยดีเท่าไหร่ โดยเฉพาะการโหลดตัว ORCHID ซึ่งใหญ่มาก ส่วนหนึ่งเป็นเพราะโค้ดยังซ้ำซ้อนอยู่หลายจุด เช่นตรงการแปลง utf-8 ที่น่าจะทำได้ตั้งแต่ระดับแรก ๆ ที่อ่านเข้ามาเลย ไม่ใช่มาแปลงเอาตอนหลัง-ต้องวนลูปอีกหนึ่งครั้งแบบขณะนี้ โค้ดยัง refactor ได้อีกเยอะ ใครคล่อง Python ก็ช่วยดูหน่อยนะครับ ผมแค่พอเขียนไถ ๆ ได้ ขอบคุณครับ 🙂

ตัวอย่างจาก example.py

1. พิมพ์ข้อความมั่ว ๆ ขึ้นมาจากตัวแบบ n-gram ที่สร้างจากคำในคลัง foosci :


foosci_text = nltk.Text(foosci.words())
foosci_text.generate()

ผลลัพธ์ :

… ซึ่ง ทฤษฎี สรุป ความรู้ ของ เรา เอา ไส้เดือน ไป ปล่อย ใน พื้นที่ ๆ มี ความ สงสัย ระหว่าง ความ เชื่อ เรื่อง มิติ ใหม่ นี้ …

2. พิมพ์ คำ/ชนิดคำ จาก 5 ประโยค แรกของคลัง ORCHID
โปรดสังเกตว่า เราใช้ชุดชนิดคำ (POS/tagset) แบบง่าย สามารถสลับชุดชนิดคำได้โดยสลับค่า simplify_tags :


for sent in orchid.tagged_sents(simplify_tags=True)[0:5]:
    print "[",
    for (word, tag) in sent:
        print word + "/" + tag,
    print "]"

ผลลัพธ์ :

[ การ/FIX ประชุม/V ทาง/N วิชาการ/N /PUNC ครั้ง/C ที่_1/DETN ]
[ โครงการวิจัยและพัฒนา/N อิเล็กทรอนิกส์/N และ/CONJ คอมพิวเตอร์/N ]
[ ปีงบประมาณ/N /PUNC 2531/N ]
[ เล่ม/C /PUNC 1/DETN ]
[ ศูนย์เทคโนโลยีอิเล็กทรอนิกส์และคอมพิวเตอร์แห่งชาติ/N ]

3. หาค่าการกระจายของสองคำ การ และ ความ ใน 4 หมวดของคลัง BEST
โปรดสังเกตว่า ตรงคำที่เราจะป้อนเข้าไปให้ฟังก์ชั่นต่าง ๆ ของ NLTK เราจะแปลงมันเป็น utf-8 encoded str ก่อน :


cfd = nltk.ConditionalFreqDist(
        (genre, word)
        for genre in best.categories()
        for word in best.words(categories=genre))

genres = ['news', 'encyclopedia', 'novel', 'article']
prefixs = [w.encode("utf-8") for w in [u'การ', u'ความ']]
cfd.tabulate(conditions=genres, samples=prefixs)

ผลลัพธ์ :

             การ ความ
        news 29567 11186
encyclopedia 25477 8541
       novel 4258 9097
     article 33200 16651

เล่นต่อเอง จากตัวอย่างในหนังสือ NLTK

เดี๋ยวอาจจะให้น้องฝึกงานที่โอเพ่นดรีมเอาไปทำต่อ เช่นทำให้มันใช้ AB, NE หรือขอบเขตประโยค/ย่อหน้าได้ .. เห็นนั่งเล่นเกมมาหลายวันละ :p

technorati tags:,,,

playing around Thai blog corpus with NLTK

อยากจะลองเล่น NLTK กับข้อมูลภาษาไทยดู คิดไปคิดมา เอาข้อมูลจาก foosci.com มาลองดูละกัน เขาเปิดให้ใช้ เป็น ครีเอทีฟคอมมอนส์ แสดงที่มา-อนุญาตแบบเดียวกัน (CC by-sa)

แต่ไม่อยากไปดึงมาเอง ขี้เกียจ เห็นว่าโครงการโรตี (อัลฟ่า) โดย Opendream ดูดบล็อกไทยจำนวนหนึ่งมาเก็บไว้ได้ระยะหนึ่งแล้ว เพื่อใช้ในการแนะนำลิงก์ (ดูตัวอย่างที่ keng.ws ที่ท้ายแต่ละโพสต์) ก็เลยเอาจากตรงนั้นมาใช้ละกัน

ข้อมูลที่มีเป็น XML ที่ dump มาจาก MySQL เราก็เขียนสคริปต์ก๊อก ๆ แก๊ก ๆ ดึงเฉพาะที่อยากได้ออกมา ด้วย xml.etree.cElementTree (ตอนแรกใช้ ElementTree แตน ๆ แต่อืดเกิน เนื่องจากแฟ้มมันใหญ่)
เอา HTML tags ออกด้วย Beautiful Soup แล้วตัดคำด้วย python-libthai ตัดประโยคแบบถึก ๆ ด้วย .split(‘\n’) จะได้ข้อมูลออกมาหน้าตาประมาณนี้ (จะเห็นว่าข้อมูลมันไม่ได้สมบูรณ์มาก มีแท็ก HTML โผล่มาด้วย-อันนี้เป็นที่ข้อมูลป้อนเข้าที่ dump มา) :


<?xml version="1.0" encoding="utf-8"?>
<roti>
  <entry id="4947" url="http://www.foosci.com/node/401" ...>
    <tags> <tag>LHC</tag> <tag>quantum physics</tag> ... </tags>
    <title> <w>บิดา</w> <w>ของ</w> <w>อนุภาค</w> ... </title>
    <content>
      <s> <w>p</w> <w>นัก</w> <w>วิทยาศาสตร์</w> ... </s>
      <s> <w>pcenter</w> <w space="1"> </w> <w>ภาพ</w> ... </s>
      ...
    </content>
  </entry>
  <entry>
    ...
</roti>

ใน w คือ คำ, ใน s คือ ประโยค

ดาวน์โหลดข้อมูล : foosci-20090424.tar.bz2 (สัญญาอนุญาต CC by-sa เช่นเดียวกับเนื้อหาใน foosci.com)
ข้างในจะมีสองแฟ้ม foosci00.xml และ foosci01.xml ให้ก๊อปปี้ไปใส่ในไดเรกทอรีข้อมูลของ NLTK (NLTK_DATA) $NLTK_DATA/corpora/rotibc ตัวโมดูลที่จะพูดถึงต่อจากนี้จะวิ่งมาหาที่ตำแหน่งนี้

ได้ข้อมูลมาแล้ว จะเอาเข้าไปใช้ใน NLTK ยังไง ? ก็ต้องเขียนตัว corpus reader ขึ้นมาก่อน ซึ่งกรณนี้ เราจะทำต่อมาจาก XMLCorpusReader (เรียกว่า inherit ไหม?) โดยไอเดียไม่มีอะไรมาก ก็ implement ตัวฟังก์ชั่น .words() เพื่อส่งกลับรายการคำ และฟังก์ชั่น .sents() เพื่อส่งกลับรายการประโยค โดยดูตัวอย่างจาก BNCCorpusReader

ที่ต้องทำเพิ่มเติมก็คือ สร้างแฟ้ม __init__.py ใส่ไว้ใน package เพื่อที่ว่าตอนโหลด มันจะได้โหลดเอาตัวข้อมูลขึ้นมาให้เราอัตโนมัติเลย (ซึ่งไม่ต้องกลัวอึด เพราะว่าโหลดแบบ lazy คือยังไม่ได้โหลดข้อมูลจริง ๆ จนกว่าจะใช้)

ตอนทำ __init__.py นี้ ทำให้รู้ว่า ทุกไดเรกทอรีที่เราจะใส่โมดูลอะไรลงไป จะต้องมีแฟ้มนี้ ไม่งั้นตอน build มันจะไม่นับไดเรกทอรีนั้นเป็น package จะข้ามไป เพราะงั้นถึงไม่ได้จะโหลดจะทำอะไร ก็ต้องใส่แฟ้มว่าง ๆ ไว้ (ดูเอกสาร Python Tutorial – Modules)

ใน __init__.py ไม่มีอะไรมาก แค่โหลดข้อมูลเฉย ๆ :
foosci = LazyCorpusLoader('rotibc', RotiCorpusReader, r'foosci\d+\.xml')

ดาวน์โหลดแพคเกจ roti.corpus : rotibc-0.1.tar.gz
แตกออกมาแล้ว ก็ลงด้วยคำสั่ง :
sudo python setup.py install
(ดูวิธีสร้าง setup.py มาจากเอกสาร Distutils – Creating a Source Distribution)

โอเค ครบละ ข้อมูล โปรแกรมอ่าน คราวนี้มาเล่นกัน ลองใน interpreter shell ของ Python ก็ได้


>>> from roti.corpus import foosci
>>> foosci.fileids() #แสดงรายชื่อแฟ้มในคลังข้อความ
['foosci00.xml', 'foosci01.xml']
>>> foosci.words() #แสดงรายการคำ
['p', u'\u0e19\u0e31\u0e01', ...]
>>> for w in foosci.words()[0:5]: #พิมพ์คำจากรายการ ตำแหน่ง 0-5
...     print w,
...
p นัก วิทยาศาสตร์ อังกฤษ ที่
>>>
>>> foosci.sents() #แสดงรายการประโยค
[['p', u'\u0e19\u0e31\u0e01', ...],
['pcenterimg', ' ', 'src=http://', ...], ...]
>>>

จะเห็นว่า เราพอจะเล่นอะไรกับมันได้ละ ถ้าจะเล่นมากกว่านี้ ลองดูตัวอย่างที่ Getting Started (NLTK)

ตัวอย่างหนึ่งจาก NLTK Book บทที่ 2 Accessing Text Corpora and Lexical Resources เขาลองเล่นกับ conditional frequency distribution เอามาสร้างประโยคมั่ว ๆ เล่น จากโมเดลไบแกรม ด้วยโค้ดด้านล่างนี้ :


def generate_model(cfdist, word, num=15):
    for i in range(num):
        print word,
        word = cfdist[word].max()

words = foosci.words()
bigrams = nltk.bigrams(words)
cfd = nltk.ConditionalFreqDist(bigrams)

ลองใส่คำอะไรสักคำให้มันดู มันจะสร้างประโยคมาให้


>>> generate_model(cfd, u'คอมพิวเตอร์')
คอมพิวเตอร์ ที่ มี ความ เสี่ยง มะเร็ง เต้า นม   href=http:// www. physorg. com/ ~r/ foosci/

การสร้างประโยคนั้น generate_model() ใช้วิธีเลือกเอาคำที่น่าจะเกิดต่อจากคำข้างหน้ามากที่สุด มาเรียงต่อกัน

ลองเล่นต่ออีกนิดหน่อยกับติวอันนี้ Working with corpora: Character Ngrams

ถ้ามีคลังข้อความที่น่ารัก ๆ กว่านี้ ก็น่าจะใช้ NLTK นี้ไปใช้เรียนสอน NLP หรือภาษาศาสตร์คลังข้อมูลง่าย ๆ ได้

ปัญหาอย่างนึงที่เจอตอนนี้คือ nltk.text.Text() ใช้กับ unicode ไม่ได้ คือมันจะพยายามแปลงข้อความไปเป็น ascii ซึ่งแปลงไม่ได้ แล้วก็จะตาย nltk.text.Text() นี่มีฟังก์ชั่นน่าใช้สำหรับการเรียนรู้เรื่องภาษาศาสตร์เยอะพอดู เช่น .concordance() .collocations() .similar()

<อัปเดต 2009.04.25> ใช้กับ nltk.Text() ได้แล้ว (แก้ตามคำแนะนำจากเมลกลุ่ม nltk-users) โดยต้องให้คำใน list เป็น str (“”) ที่ encode ด้วย utf-8 แทนที่จะใส่เป็นสตริงแบบ unicode (u””) ทำได้โดยแก้สองฟังก์ชั่น _elt_to_words() และ _elt_to_sents() ในแฟ้ม roti/corpus/rotibc.py ตรง .append(w.text) ให้เป็น.append(w.text.encode("utf-8", "replace")) เดี๋ยวจะปรับตัวแพคเกจใหม่ </อัปเดต>

ลองเล่นดูครับ เอาไปโมต่อตามสบาย โค้ดทั้งหมดเป็น public domain

ใช้ NLTK แล้วพบปัญหา คุยกับผู้ใช้รายอื่น ๆ ได้ที่เมลกลุ่ม nltk-users หรือถ้าอยากคุยกับคนไทย ลองกลุ่ม THLTA


แถม : Open License และคลังข้อมูลภาษา

ในงาน NAC 2009 โดยสวทช.ที่ผ่านมา ได้มีโอกาสแลกเปลี่ยนประเด็น open content, open license และ คลังข้อมูลภาษา กับคนในวงการ NLP จำนวนหนึ่ง ซึ่งก็มีความคิดเห็นหลาย ๆ อย่าง หลาย ๆ มุมก้นไป

เกือบทุกคนเห็นด้วยว่า เป็นเรื่องสำคัญที่ควรจะมีอะไรที่มันแชร์กันได้ ที่มัน open แต่ความหมายของคำว่า open สำหรับแต่ละคนก็ดูจะไม่เท่ากัน บางคนบอกว่า คลังอันนั้นอันนี้ฟรี ตัวนั้นตัวนี้โอเพ่นซอร์ส แต่พอไปดูเอาจริง ๆ ในรายละเอียด ก็พบว่า จำเป็นต้องลงทะเบียนก่อนบ้างหรือไม่ได้อัปเดตนานแล้วบ้าง (พจนานุกรม Lexitron) หรือลิงก์ดาวน์โหลดหายไปบ้าง (ORCHID Corpus – ดาวน์โหลดได้ที่ backup site) หรือก่อนหน้านี้เรื่องของฟอนต์หลาย ๆ ตัว ที่เอามาใช้ได้ฟรี แต่ไม่รู้ว่าจะโมได้ไหม redistribute ได้ไหม

ความเห็นของผมก็คือ จะเปิดหรือจะปิด อย่างไรก็ได้ เป็นสิทธิของเจ้าของข้อมูลที่เขาลงแรงลงเวลาไป
แต่ถ้าจะบอกว่าเปิด ก็ขอให้บอกให้ชัดเจนหน่อย ว่าในเงื่อนไขอะไร แล้วจะเอามาใช้จริง ๆ ได้ยังไง การบอกว่า เปิด เฉย ๆ โดยไม่ได้ให้รายละเอียดอะไรเลย ในทางปฏิบัติก็แทบจะเหมือนการไม่เปิด หน้า การแลกเปลี่ยนทรัพยากรและเครื่องมือ ที่ THLTA ก็อาจจะเป็นความพยายามหนึ่งที่จะทำให้เรื่องพวกนี้เคลียร์

สิ่งที่ผมคิดว่าน่าสนใจ และเป็นคุณสมบัติสำคัญของ open licenses ทั้งหลาย ไม่ว่าจะเป็น copyleft, GNU หรือ Creative Commons ก็คือ การไม่ต้องขออนุญาต ผมคิดว่าการไม่ต้องขออนุญาตนี้ทำให้ ข้อมูล โค้ด ไอเดีย ต่าง ๆ มันไหลเวียนได้อย่างอิสระ-ทันที ใครอยากจะเล่นอะไรก็เอา เต็มที่ ตามเงื่อนไขที่ประกาศไว้ชัดเจนล่วงหน้า ไม่ต้องรอไปรอมา ไม่ต้องตกอยู่ในภาวะไม่แน่ใจ

ซึ่งจริง ๆ แล้วเรื่องของความชัดเจนนี้ แม้จะเป็น closed content, closed source หรืออะไรก็ตาม ก็สามารถจะชัดเจนเรื่องนี้ได้ เพียงประกาศให้ชัดเจน — ไม่ใช่แค่บอกเฉย ๆ ว่า เปิด แล้วก็ทิ้งให้งง ให้เดาใจกันเล่น ๆ ว่า ตกลงจะเปิดแบบไหน เปิดยังไง

technorati tags:,,,

XMLHttpRequest with "lese-majeste" in the url got blocked as well – Holy CS Loxinfo

อัปเดตต่อจากกรณี Mashable.com got blocked – ความมั่วของ CS Loxinfo กับการบล็อคเว็บ

จากการทดลองเพิ่มเติม พบว่า web api request (ซึ่งทำผ่าน url) ก็จะใช้ไม่ได้เช่นกัน

เช่น ผมลองใช้บริการย่อลิงก์ ของ bit.ly โดยใช้ url :

http://klongofconsciousness.wordpress.com/2009/01/23/dozing-german-arrested-for-lese-majeste/*

ปรากฎว่า bit.ly มันเงียบครับ ไม่แสดงผลลัพธ์อะไร (ตามปกติมันจะแสดงผลลัพธ์ลิงก์ที่ถูกย่อ ในช่อง “Shortened URL”)

เมื่อตรวจสอบดูก็พบว่า เมื่อกดปุ่ม “Shorten” ตัวหน้าเว็บ จะส่ง XMLHttpRequest ไปที่ http://bit.ly/api เรียกใช้บริการที่เซิร์ฟเวอร์ของ bit.ly เพื่อรับผลลัพธ์ (ตามลักษณะการเขียนโปรแกรมแบบ AJAX ซึ่งปัจจุบันนี้นิยมทั่วไป)

โดยในการส่ง request ที่ว่านี้ ก็จะทำในรูปของการเรียก url ปกติ ซึ่งกรณีนี้ ก็จะเป็นในรูปแบบนี้ :

http://bit.ly/api?method=shorten&long_url=http%3A%2F%2Fklongofconsciousness.wordpress.com%2F2009%2F01%2F23%2Fdozing-german-arrested-for-lese-majeste%2F&keyword=&history=1&t=1233903997567

method=shorten นั้นคือระบุว่า ใช้เรียกใช้เมธทอดที่ชื่อ shorten; long_url=… ก็ระบุว่าจะย่อลิงก์อะไร; ที่เหลือก็เป็นพารามิเตอร์ต่าง ๆ

จะเห็นว่าปัญหาอยู่ตรงที่ว่า long_url นั้นไม่ได้เข้ารหัส ดังนั้นถ้าใส่ลิงก์ที่มีคำว่า “lese-majeste” เข้าไปให้ bit.ly ย่อให้หน่อย
คำเดียวกันนี้ก็จะปรากฏอยู่ในพารามิเตอร์ที่จะส่ง XMLHttpRequest ซึ่งก็จะไปปรากฏอยู่ใน url — แล้วก็จะถูกบล็อคทันที (อย่างน้อยที่ทราบโดยไอเอสพีหนึ่งแห่ง คือ CS Loxinfo)

ดังนั้นสิ่งที่ request ดัง url ข้างต้น (หรือ url ใด ๆ ที่มีคำว่า “lese-majeste” หรือ “lesemajeste”)
จะได้รับ respond กลับมา
ก็จะเป็นหน้า “404 หลอก” ซึ่งไม่ใช่รูปแบบข้อมูลอย่างที่โปรแกรมคาดหวังไว้ (เช่น XML หรือ JSON) โปรแกรมจึงทำงานต่อไม่ได้ … ก็เลยเงียบ

เจ๋งไหม ?

(* เป็นข่าวเมื่อ 22 ม.ค. 2552 Klaus Brehmer ชายชาวเยอรมันคนหนึ่งนั่งในโรงหนังที่เวิลด์เทรด แล้วในขณะนั้นมีเพลงสรรเสริญบรรเลง คนในโรงหนังเลยโห่ ตะโกน และเอาน้ำราดหัวเขา จากนั้นตำรวจก็มาจับเขาไป – โอ้ อารยะประเทศ)


ใครที่เขียนโปรแกรมบนเว็บ/โปรแกรมที่ทำงานกับเว็บ แล้วมีผู้ใช้บริการหรือลูกค้า แจ้งมาว่าโปรแกรมทำงานผิดปกติ ลองเช็คเรื่องการบล็อคเว็บด้วย ถ้าคุณทำ request ใด ๆ ผ่านเว็บ ก็มีโอกาสจะโดนบล็อคได้เสมอ (หลายครั้งเกิดจากความมั่ว ๆ – Mashable.com ยังโดนได้เลย) ลองถามผู้ใช้บริการของคุณ ว่าใช้เน็ตยี่ห้อไหน ถ้าเป็นไปได้ ก็แนะนำให้เขาเปลี่ยนยี่ห้อไอเอสพีไปเลย ตัดปัญหา

ส่วนใครที่บล็อคเว็บแบบเหมารวม-มักง่ายแบบนี้ ไม่ว่าจะเป็นรัฐ หน่วยงานราชการ สถานศึกษา หรือไอเอสพี ก็ขอความกรุณาปรับปรุงการทำงานด้วย ถ้ามีคำสั่งศาลมาให้บล็อคก็บล็อคตาม url ที่ศาลสั่งมาไป ไม่ใช่ใช้ keyword filtering แบบนี้ มันกระทบกับคนอื่นเว็บอื่นที่ไม่ได้เกี่ยวข้องด้วย

อย่ามักง่าย


อัปเดต : ผมดันไปตั้งชื่อหัวข้อของโพสต์นี้มีคำว่า “lese majeste”, ใน url ของโพสต์นี้ ก็เลยมีคำนั้นไปด้วย ใครใช้ CS Loxinfo ก็จะกดเข้ามาดูโพสต์นี้ตรง ๆ ไม่ได้นะครับ. ถ้าใช้โปรแกรมอ่าน feed ที่ทำงานที่ฝั่งไคลเอนต์ก็อาจจะไม่ได้ด้วย – เพราะใน feed ของโพสต์นี้ ซึ่งใช้ Feedburner มันก็มีชื่อหัวข้ออยู่ด้วย (http://feeds.feedburner.com/%7Er/bact/%7E3/533175999/xmlhttprequest-with-lese-majeste-in-url.html). อย่างไรก็ตาม ยังสามารถอ่านได้ในหน้ารวมของบล็อก หรืออ่านผ่าน feed reader ที่ทำงานฝั่งเซิร์ฟเวอร์ อย่าง Google Reader. ลุ่มลึกดีครับ อารยะประเทศ.

technorati tags:
,
,
,

Robocode Thailand Contest 2009

Robocode Thailand Contest 2009 การแข่งขันการเขียนโปรแกรมจาวาเพื่อควบคุมหุ่นยนต์รถถัง

Robocode เป็นเกมที่แต่ละทีมจะพัฒนาโปรแกรมด้วยภาษาจาวา เพื่อควบคุมหุ่นยนต์รถถังให้ต่อสู้กันแบบอัตโนมัติ โดยแต่ละทีมไม่สามารถควบคุมหุ่นยนต์ของตัวระหว่างการแข่งขันได้ จึงเป็นเกมที่ฝึกทักษะการเขียนโปรแกรมและการนำอัลกอริทึม (algorithm) หรือวิธีการต่าง ๆ รวมถึง ปัญญาประดิษฐ์ (artificial intelligence – AI) มารวมกันเพื่อทำให้หุ่นยนต์มีประสิทธิภาพมากที่สุด เว็บไซต์วิชาการ.คอม เล็งเห็นประโยชน์ของเกม Robocode นี้ว่าจะช่วยฝึกทักษะต่าง ๆ ให้กับเยาวชนและผู้ที่สนใจ จึงร่วมกับศูนย์เทคโนโลยีอิเล็กทรอนิกส์และคอมพิวเตอร์แห่งชาติ (เนคเทค) และสถาบันเทคโนโลยีนานาชาติสิรินธร มหาวิทยาลัยธรรมศาสตร์ จัดการแข่งขัน Robocode Thailand Contest 2009 เพื่อค้นหาสุดยอดทีมกับสุดยอดหุ่นยนต์ประจำปีนี้ โดยการแข่งขันในรอบคัดเลือก จะดำเนินการผ่านเว็บไซต์วิชาการ.คอม ส่วนการแข่งขันในรอบสุดท้าย ซึ่งเป็นการชิงชนะเลิศระดับประเทศ จะจัดการแข่งขันในช่วงต้นปี 2009 ภายในงานมหกรรมการแข่งขันด้านไอซีที ซึ่งดำเนินการเป็นประจำทุกปีโดยเนคเทค

ผู้ที่สนใจสามารถดาวน์โหลดโปรแกรม Robocode ได้ที่ robocode.sf.net ศึกษาวิธีการพัฒนาหุ่นยนต์ได้จากบทความติว และส่งซอฟต์แวร์หุ่นยนต์ที่พัฒนาขึ้นเข้าแข่งขันได้ตั้งแต่วันนี้ โดยจะปิดรับสมัครและปิดให้อัปโหลดหุ่นยนต์ในวันที่ 20 มกราคม 2552

ที่มา : http://www.vcharkarn.com/robocode/

technorati tags:
,
,
,

download attachments from Gmail using FTP/script

(เอ เรามี Python66 ป่าวหว่า ? แบบอันนี้เขียนลง Django66 ได้ป่ะ ?)
สรุปว่าเอาไปลง Pylons66 ครับ

ดาวน์โหลดแฟ้มจาก Gmail ด้วย FTP (หรือสคริปต์)

ง่าย ๆ ไม่ซับซ้อน แค่เรียกตัว ftp daemon (Gmail-FTP proxy) ให้ทำงาน, แล้วก็ใช้โปรแกรม FTP อะไรก็ได้ไปดึงแฟ้มมา.
โดยแฟ้มที่จะดึงมาได้นั้น จะต้องเป็นแฟ้มแนบ (attachment) ที่อยู่ในจดหมายที่ติดป้ายว่า ‘ftp’.

ตัวโปรแกรม ftp daemon ที่ว่านี้ คือสคริปต์ไพธอน (Python) เล็ก ๆ ที่ชื่อว่า gmailftpd.py
มันอยู่ในแพคเกจ libgmail-docs ของ libgmail.

ก่อนจะใช้งาน gmailftpd นี้ เราจำเป็นต้องมี libgmail กับ mechanize ลงอยู่ในเครื่องก่อน.
ถ้าใช้ Ubuntu/Debian ก็สั่ง sudo apt-get install python-libgmail python-mechanize ได้เลย.

วิธีใช้งาน เราก็เรียก ftp daemon ขึ้นมาก่อน ให้มันทำหน้าที่เป็นเซิร์ฟเวอร์.
เรียกใช้ gmailftpd.py โดยสั่ง python gmailftpd.py ได้เลย.

หลังเรียกให้ ftp daemon ทำงานแล้ว หน้าจอจะประมาณด้านล่าง – จะเห็นว่ามันจะไม่ทำอะไรต่อ จนกว่าจะมี client ติดต่อเข้ามา:

หน้าจอฝั่งแม่ข่าย (ftp daemon – gmailftpd)

bact@edin:~/libgmail$ python demos/gmailftpd.py
FTPServer started at Sun Sep 21 12:32:39 2008
        Local addr: ('127.0.0.1', 8021)

ทีนี้ถ้าเราอยากจะได้แฟ้มอะไรจาก Gmail ก็ใช้โปรแกรม FTP เรียกไปที่ไอพี 127.0.0.1 (localhost) พอร์ต 8021.

ในทีนี้จะใช้ wget เพราะสะดวกดี. วิธีใช้ wget คร่าว ๆ ก็คือ wget –user=ชื่อผู้ใช้ –password=รหัสผ่าน -c โปรโตคอล://ที่อยู่:พอร์ต/ชื่อแฟ้ม เจ้า -c นี่ใส่ไปให้มันโหลดต่อให้ กรณีหลุดกลางทาง จะได้ไม่ต้องเริ่มใหม่หมด.

หลังจากเรียก wget มันก็จะทำอะไรไปตามเรื่องตามราว ประมาณหน้าจอนี้:

หน้าจอฝั่งลูกข่าย (ftp client – wget)

bact@edin:~/test$ wget --user=uabc --password=pxyz -c ftp://127.0.0.1:8021/anthro.txt
--12:35:55--  ftp://127.0.0.1:8021/anthro.txt
           => `anthro.txt'
Connecting to 127.0.0.1:8021... connected.
Logging in as uabc ... Logged in!
==> SYST ... 
Server error, can't determine system type.
==> PWD ... done.
==> TYPE I ... done.  ==> CWD not needed.
==> PASV ... done.    ==> RETR anthro.txt ... done.

    [     < =>                             ] 375           94.27B/s             

12:36:03 (94.25 B/s) - `anthro.txt' saved [375]

bact@edin:~/test$ 

ลอง ls ดู ก็จะเห็นว่าได้แฟ้มมาตามที่ต้องการแล้ว:

bact@edin:~/test$ ls -la anthro.txt 
-rw-r--r-- 1 arthit arthit 375 2008-09-21 12:36 anthro.txt

ทีนี้ฝั่งเซิร์ฟเวอร์แม่ข่าย เขาทำอะไรกัน ลองไปดู:

หน้าจอฝั่งแม่ข่าย (ftp daemon – gmailftpd) ระหว่างที่ลูกข่าย (ftp client) ติดต่อเข้ามา

bact@edin:~/libgmail$ python demos/gmailftpd.py
FTPServer started at Sun Sep 21 12:32:39 2008
        Local addr: ('127.0.0.1', 8021)

Incoming connection from ('127.0.0.1', 57054)
Peer: ('127.0.0.1', 57054)
Data: 'USER uabc'
Data: 'PASS pxyz'
Data: 'SYST'
Data: 'PWD'
Data: 'TYPE I'
Data: 'PASV'
DataChannel started at Sun Sep 21 12:35:59 2008
        Local addr: ('127.0.0.1', 9021)

Data: 'RETR anthro.txt'
Reading `anthro.txt`.

จะเห็นว่าตัวแม่ข่ายหรือ gmailftpd มันได้รับชื่อผู้ใช้รหัสผ่านจากลูกข่ายหรือ wget, ซึ่ง gmailftpd มันจะเอาข้อมูลนี้ไปล็อกอิน — ตาม API คือใช้ ga.login() โดย ga เป็นออบเจกต์ของคลาส GmailAccount ที่สร้างโดย ga = libgmail.GmailAccount(username, password) ) — จากนั้นก็หาแฟ้มที่ร้องขอ, และส่งไปให้ลูกข่าย

อยากรู้ว่ามันหาแฟ้มได้ยังไง ก็ต้องไปดูในโค้ด gmailftpd.py ตรงเมธอด get_filelist().

    def get_filelist(self):
        r = self.ga.getMessagesByLabel('ftp')
        for th in r:
            for m in th:
                for a in m.attachments:
                    self.filenames[a.filename] = a

คือมันใช้เมธอด getMessagesByLabel() ของคลาส GmailAccount เพื่อหาเฉพาะอีเมลฉบับที่ติดป้ายว่า ‘ftp’, พอได้ผลลัพธ์มาแล้วก็วนลูป for ไปเพื่อเก็บชื่อแฟ้มทั้งหมด

ในโค้ด: r คือ ออบเจกต์ของ GmailSearchResult ซึ่งจะประกอบด้วยชุดของ threads, th คือ thread, m คือ message, a คือ attachment

ถ้าอยากให้มันไปดึงจากที่อื่นมาด้วย ก็แก้ตรงนี้ได้ เช่นเอาจากโฟลเดอร์ก็ใช้ getMessagesByFolder() แต่ระวังมันเยอะเกินละกัน.

เท่าที่ลองกับสองแฟ้ม พบว่า แฟ้มเล็ก ๆ น่าจะสบาย ๆ, แต่กับแฟ้มขนาดใหญ่ (6.4 MB) จะมีปัญหา โหลดไม่ได้ คือ gmailftpd มันจะฟ้อง exception ซะเฉย ๆ แล้วก็ไม่ทำอะไรต่อ — ไม่แน่ใจว่าเป็นเพราะตัวแฟ้มไม่ดีเองรึเปล่า error message มันฟ้องเกี่ยวกับ decode อะไรซักอย่าง อ่านไม่รู้เรื่อง :p

error: uncaptured python exception, closing channel <__main__ .FTPChannel connected 127.0.0.1:43982 at 0xb7d102ec> (:’utf8′ codec can’t decode byte 0xac in position 11: unexpected code byte [/usr/lib/python2.5/asyncore.py|read|68] [/usr/lib/python2.5/asyncore.py|handle_read_event|390] [/usr/lib/python2.5/asynchat.py|handle_read|137] [demos/gmailftpd.py|found_terminator|106] [demos/gmailftpd.py|ftp_RETR|181] [demos/gmailftpd.py|handle_RETR|313] [/home/arthit/dev/libgmail/libgmail.py|_getContent|1507] [/home/arthit/dev/libgmail/libgmail.py|_retrievePage|358] [/usr/lib/python2.5/encodings/utf_8.py|decode|16])

การประยุกต์ใช้ ทำได้หลากหลายมาก แล้วแต่จินตนาการเลย
เช่น อาจเขียนสคริปต์ให้มันดาวน์โหลดแฟ้มแนบใหม่ ๆ มาเก็บไว้ในเครื่องเราไว้
หรือให้ดาวน์โหลดแฟ้มแนบ .pdf จากอีเมลหรือหัวข้อที่กำหนด (เช่นโจทย์การบ้านจากอาจารย์) หรือเอาเฉพาะ .mp3

วิธีทำ อาจจะใช้เชลล์สคริปต์ไปเรียก ftp ผ่าน gmailftpd ก็ได้, หรือจะเขียนไพธอนไปเลยก็ได้ เท่าที่ดู API ของ libgmail มันก็น่าเล่นอยู่.
ทั้งนี้ยังสามารถผสมกับการตั้งค่า filter ใน Gmail ได้ด้วย, คือถ้าคิดว่าแก้สคริปต์มันยุ่งเกิน ก็ไปตั้งค่า filter ใน Gmail ก็ได้ แล้วก็ให้มันติดป้ายอัตโนมัติ, จากนั้นก็ไปแก้เมธอด get_filelist() นิดหน่อย ให้มันดึงจากป้ายที่เราอยากได้.

และ libgmail นี่ทำได้มากกว่าดาวน์โหลดแฟ้มแนบนะ ลองเล่นดู มีอะไรน่าสนก็บอกกันมั่ง 🙂

(สุดท้ายก็ยังหาวิธีดาวน์โหลดเจ้าแฟ้ม 6.4 MB นั่นออกมาไม่ได้ ทำไงดีเนี่ย…. เน็ตก็ห๊วยห่วย – -“)

technorati tags:
,
,

Developers’ Quick References

สำหรับนักพัฒนา

search them all at: QuickRef.org (find as you type)

want handy ones on your wall ? try these quick reference cards/cheat sheets:

technorati tags:
,
,

Fund raise for APC 2008

APC 2008 (Associated Programming Contest 2008) เป็นการแข่งขันเขียนโปรแกรมคอมพิวเตอร์ ภาษา C/C++ ออนไลน์ ลักษณะประมาณ Google Code Jam หรือโจทย์คอมพิวเตอร์โอลิมปิก งานนี้น้อง ๆ ทีมงานเขาจัดกันเอง ไม่ได้มีสปอนเซอร์อะไร ทำไปเพราะใจรักล้วน ๆ ก็เลยไม่ได้มีของรางวัลอะไร

sugree, mk, kengggg และหลาย ๆ คนเลยคิดว่า น่าจะสนับสนุนน้อง ๆ เขาหน่อย เลยจะแจกเสื้อยืดสวย ๆ เป็นที่ระลึกความภูมิใจ ให้กับ 50 คนแรก (ดูประกาศที่ Blognone)

ทีนี้จะหาเงินจากไหนดี เราก็ลงขันกันละกัน คนละนิดละหน่อย

ใครอยากช่วย ก็ลงขันกันทาง Chipin ได้ครับ เท่าไหนก็ได้ (หรือจะช่วยบอกต่อก็ได้ โดยกดที่ปุ่ม ‘Copy’ ข้างล่างนี้ แล้วลอกโค้ดไปแปะที่บล็อก/เว็บบอร์ด)

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

technorati tags:
,
,

Processing.js – Processing in JavaScript

From the creator of jQuery, Processing.js brings Processing visualization language to JavaScript/DHTML platform.

And for jQuery developers, try this Visual jQuery, an easy access jQuery API documentation.

ลองเล่นดูนะครับ Processing บน JavaScript ตอนรันพวกเดโมต่าง ๆ นี่ ซีพียูอาจจะพุ่งกว่าปกติซะหน่อย แต่ก็เหมือนกับพวกเว็บ AJAX ทั่วไปครับ — ผมว่า JavaScript/DOM engine ของเว็บเบราว์เซอร์ในปัจจุบัน มันถูกใช้งานจนเกินขีดจำกัดของมันแล้ว คือตอนนั้นที่ออกแบบไม่ได้มีใครคิดว่ามันจะถูกนำมาใช้สำหรับงาน Rich Internet Application ที่มีภาพออบเจกต์ มีการโต้ตอบเยอะขนาดนี้ โครงการเว็บเบราว์เซอร์รุ่นใหม่ ๆ ก็เห็นจุดนี้และพยายามปรับปรุงประสิทธิภาพของ JavaScript engine และเพิ่มฟังก์ชันที่ถูกเรียกใช้บ่อย ๆ (เช่นการค้น/เลือก element ด้วย class) เข้าไปเป็น API มาตรฐาน (แบบเป็น native ไม่ต้องไปอิมพลีเมนต์เองด้วย JavaScript ซึ่งก็จะทำให้ประสิทธิภาพดีขึ้น)

และสำหรับคนที่สนใจ Processing แนะนำบล็อกนี้ครับ Pongpan Suriyapat มีเรื่อง Processing และ new media art / interaction design น่าสนใจอยู่เรื่อย ๆ

technorati tags:
,
,

generatedata.com – data generator

Generate test data instantly, just clicks.

GenerateData.com by Benjamin Keen

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

technorati tags:
,
,