ภาษาเฉพาะโดเมนคืออะไร? ใครใช้บ้าง? และด้วยวิธีใด?


107

ฉันเดาว่าฉันกำลังมองหาคำแนะนำบางอย่างและดูว่ามีใครใช้มันบ้าง มีข้อดีพิเศษในการใช้งานหรือไม่?

วิกิพีเดีย:

ภาษาเฉพาะโดเมน (DSL)เป็นภาษาโปรแกรมหรือภาษาข้อกำหนดเฉพาะสำหรับโดเมนปัญหาเฉพาะเทคนิคการแสดงปัญหาเฉพาะและ / หรือเทคนิคการแก้ปัญหาเฉพาะ

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


ภาษาเฉพาะโดเมนจริงๆแล้วเป็นคำที่มีความหมายที่ชัดเจนในการเขียนโปรแกรม - ตรวจสอบบทความวิกิพีเดีย
1800 ข้อมูล

ตามที่ระบุไว้ด้านล่าง DSL ไม่ใช่ภาษาเดียว แต่เป็นชื่อของภาษาวัตถุประสงค์พิเศษทั้งคลาส
dmckee --- อดีตผู้ดูแลลูกแมว

ดังนั้นฉันสามารถพูดว่า R เป็น DSL ได้หรือไม่?
Srikar Doddi

2
ที่ขอบ แต่ฉันจะไม่ทำ R มีโครงสร้างสำหรับวัตถุประสงค์ทั่วไปทั้งหมดและใช้สำหรับการคำนวณที่หลากหลาย การคำนวณตัวเลขและสถิติไม่ใช่โดเมน nrrow มันเป็นการทดสอบคำจำกัดความที่ดี
Charlie Martin

คำตอบ:


114

ภาษาเฉพาะของโดเมนคือภาษาที่เขียนขึ้นเพื่อจัดการกับโดเมนเฉพาะหรือชุดข้อกังวล มีหลายอย่างอยู่รอบตัวเช่น make, ant และ rake สำหรับอธิบายการสร้างซอฟต์แวร์หรือ lexx และ yacc สำหรับการสร้างภาษา ในช่วงไม่กี่ปีที่ผ่านมาพวกเขาได้รับความนิยมเนื่องจากบางสิ่งได้รวมเข้าด้วยกันเพื่อให้ง่ายต่อการสร้าง สิ่งที่ยิ่งใหญ่คือความนิยมที่เพิ่มขึ้นของ Ruby ซึ่งมีคุณสมบัติหลายอย่างที่ช่วยให้สร้าง DSL ใหม่ได้ง่าย

ฟาวเลอร์มาร์ตินเป็นผู้แสดงใหญ่ของความคิดที่เป็นที่นี่


4
Ruby มีคุณสมบัติอะไรบ้างที่ทำให้การสร้าง DSL ใหม่ง่ายขึ้น?
Lernkurve

2
@Lernkurve - Ruby มีโปรแกรม metaprogramming ซึ่งช่วยได้ rubylearning.com/blog/2010/11/23/…
James Black

@CharlieMartin โปรดแจ้งให้เราทราบเกี่ยวกับ "groovy" ได้ไหม? มันเป็นภาษาประเภทไหนกันแน่? ฉันอยากรู้โปรดช่วยที่นี่ ..
G dangi

2
Groovy เป็นภาษาสคริปต์ที่ทำงานใน JVM โดยพื้นฐานแล้วตั้งใจให้เป็นคำตอบ Java สำหรับ Ruby เป็นภาษาสำหรับวัตถุประสงค์ทั่วไป แต่สามารถใช้ในการเขียน DSL ได้ docs.groovy-lang.org/docs/latest/html/documentation/…
Charlie Martin

1
ฉันต้องการเพิ่ม Groovy ของ Gradle ถ้าจำไม่ผิดพวกเขามีภาษาของตัวเองอธิบายงานสร้าง
Neon Warge

67

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

ตัวอย่างของ DSL ได้แก่ ภาษาแบบสอบถามทั้งหมด (SQL, XPath, ... ), ภาษาเทมเพลตทั้งหมด (Django, Smarty, ... ), เชลล์สคริปต์โดยเฉพาะรวมถึงสิ่งต่างๆเช่นสิ่งทอลายทแยงเว็บเบราว์เซอร์ที่ขับเคลื่อนด้วยคำสั่ง (ส่วนใหญ่ใช้สำหรับการทดสอบอัตโนมัติ ), การจัดเก็บข้อมูลและการแลกเปลี่ยนภาษา (XML, YAML, ... ) และภาษาเอกสารเช่น LaTex, HTML หรือ CSS

บางภาษาที่มีไวยากรณ์ที่ยืดหยุ่นมากเช่น TCL และ Lisp จะสร้าง DSL ลงในภาษาโดยตรง ... เมื่อเป็นไปได้ ภาษาส่วนใหญ่ใช้สตริงซึ่งมักจะโหลดจากไฟล์ภายนอก

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

ฉันจะกล้าบอกว่ามี DSL เพียงพอสำหรับแอปพลิเคชันทุกประเภทที่คุณต้องการ คุณแทบไม่จำเป็นต้องเรียนรู้วิธีการเขียนของคุณเอง


1
ตลกพอตัวอย่างหนึ่งที่คุณไม่ได้ระบุไว้คือตัวอย่างแรกที่ฉันนึกถึง: regex
CoffeeTableEspresso

12

(กล่าวถึงประเด็นสำคัญของคำถาม)

ฉันคิดว่าครั้งแรกที่ฉันเห็นDSLที่ไหนสักแห่งและคำจำกัดความของมันเป็น "ภาษาเฉพาะโดเมน" ฉันยังคิดว่ามันเป็นภาษาเฉพาะที่เป็นรูปธรรมซึ่งฉันไม่เคยได้ยินมาก่อน - แต่ไม่มันเป็นคำทั่วไปสำหรับภาษาที่ ปรับแต่งให้เหมาะกับพื้นที่การใช้งานเฉพาะ

แดกดันถ้าคุณเพิ่งเคยได้ยินเกี่ยวกับTCLว่าเป็น "ภาษาคำสั่งเครื่องมือ" คุณอาจคิดว่าเช่น DSL จะมีTCLจำนวนมากสำหรับเครื่องมือต่างๆ แต่ไม่เป็นชื่อเฉพาะของภาษาสคริปต์เฉพาะ


10

ฉันคิดว่าเป็นภาษาที่เหมาะสำหรับการแก้ปัญหาสำหรับโดเมนเฉพาะ อาจเป็นภาษาประมวลผลกฎหรือภาษาคำอธิบายบริการ

สิ่งที่ตรงกันข้ามกับภาษาเฉพาะโดเมน (DSL) คือภาษาที่ใช้งานทั่วไป


10

ทุกอย่างเป็น DSL ...

Assembler: MOV R1 ถึง R2
คอมไพเลอร์: Assignment Statements - A = A + 1, Conditionals - IF (TRUE) ... , Branch - RETURN
HTML: ... อธิบายโครงสร้างที่ซ้อนกัน
TCP / IP: อธิบายถึง / จาก ที่อยู่
PDF: อธิบายตำแหน่งข้อความ / รูปภาพบนกระดาษ
แบบอักษร: อธิบายอักขระ

ภาษาใด ๆ ที่เราใช้เพื่ออธิบายกระบวนการเฉพาะคือ DSL น่าเสียดายที่ไม่มีภาษาเฉพาะโดเมนที่จะอธิบายถึงกระบวนการพื้นฐานที่สุดของเราดังนั้นเราจึงใช้ภาษาไม่กี่ภาษาที่เรามีเพื่ออธิบายทุกสิ่งที่เราทำ "บีบอัดไฟล์ html ทั้งหมดในเว็บไซต์ของฉัน" ต้องใช้ 3 หรือ 4 ภาษาที่แตกต่างกัน 300 บรรทัดจึงจะเสร็จสมบูรณ์

ในการสร้าง DSL ให้กำหนดจำนวนอักขระขั้นต่ำที่จำเป็นเพื่ออธิบายกระบวนการที่คุณจำได้และไม่ต้องใช้เอกสารประกอบ โปรดจำไว้ว่าความเร็วและความสะดวกในการใช้งานเป็นเกณฑ์การออกแบบหลัก การแยกวิเคราะห์นั้นรวดเร็วมากจนไวยากรณ์ที่คุณใช้นั้นใช้ได้ดีฉันชอบภาษาที่เป็นธรรมชาติมากกว่าไวยากรณ์ของฉันในกรณีส่วนใหญ่ "จ่ายเงินให้พนักงานในช่วงแรกของเดือน" แต่เฉพาะโดเมนนั้นเป็นเพียงแค่นั้นโดยเฉพาะโดเมนคุณจะกำหนดไวยากรณ์ที่ดีที่สุด เหมาะกับปัญหา

ฉันจะหลีกเลี่ยงการใช้โซลูชันอื่นที่อาจสะดวก แต่ไม่เหมาะกับปัญหาเช่น HTML ที่ใช้ในการกำหนดข้อมูล (XML) CSV มีประโยชน์มากเหมาะกับปัญหาส่วนใหญ่ JSON ไม่พอดีกับส่วนที่ใช้งานง่ายมันเกินความจำเป็นที่จะเพิ่มความยุ่งยากที่ไม่จำเป็นเพราะ CSV ใช้ได้กับปัญหาส่วนใหญ่ เราใช้ EXCEL เป็นจำนวนมากสำหรับ DSL ซึ่งใช้งานได้ดีในการอธิบายปัญหาเล็ก ๆ น้อยกว่า 65K ถึง 1M แถวเช่นโครงสร้างต้นไม้หรือเมนูคอลัมน์ A คือระดับคอลัมน์อื่น ๆ คือไอคอนสีป้ายกำกับและอื่น ๆ (EXCEL คือ CSV ที่แก้ไขได้)

ฉันพบว่า HTML ไม่สามารถแก้ปัญหาของเค้าโครงหน้าได้จริงๆดังนั้นฉันจึงกำจัดมันและกำหนด DSL ที่เหมาะสม ฉันกำหนดพื้นที่ 6 ภูมิภาคบนหน้า HEADER, BODY, FOOTER, LEFT / RIGHT MARGINS และ LEFT / RIGHT FULL MARGINS จากนั้นฉันสามารถบอกตัวสร้างเพจให้เพิ่ม TITLE BAR, STATUS BAR, MENUS, TABLE, FORMS, ... จากนั้นแต่ละเซลล์เหล่านี้สามารถแบ่งออกเป็นแถวและคอลัมน์ตามความลึกใดก็ได้ เค้าโครงหน้าใช้เวลาไม่กี่วินาทีสำหรับรูปแบบใด ๆ

BODY มีตาราง
หัวหน้าพนักงานของฉันมีคำบรรยายแถบชื่อเรื่อง 'Hello World' พร้อมล็อกอินเข้าสู่ซอฟต์แวร์ Collins

DSL เมนูไม่พอดีกับ DSL เค้าโครงหน้าดังนั้นฉันจึงสร้าง DSL เฉพาะสำหรับเมนู

ทรัพยากรเมนูหลักของฉัน
* กำหนด: เมนู, m, ระดับ, ฉลาก, ไอคอน, การกระทำ;
m, 0, ไฟล์;
m, 1, เปิด, open.gif, Dialog Open File;

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


8

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


5

ดี! มีหลายสิ่งที่อธิบายไว้ข้างต้น ฉันจะพยายามอธิบายเรื่องนี้ให้ง่ายขึ้นเพราะบางคนอย่างฉันจะเข้าใจ

เนื่องจากภาษาวัตถุประสงค์ทั่วไปถูกใช้เพื่อจุดประสงค์มากมาย DSL จึงถูกสร้างขึ้นสำหรับโดเมนเฉพาะเท่านั้น เช่น HTML หรือ CSS

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

I onces ได้สร้าง Switch board สำหรับผู้ใช้ซึ่งสามารถสั่งงานผ่าน Serial port ของคอมพิวเตอร์และผู้ใช้ต้องการโปรแกรมสำหรับบอร์ดนั้นซึ่งสามารถใช้งานได้บนบอร์ดนั้นและสวิตช์ Relay จะเปิดและปิดตามนั้น ดังนั้นฉันจึงเขียนคำแนะนำและบอกให้ผู้ใช้ตั้งโปรแกรมบอร์ดนั้นตามคำแนะนำเหล่านี้ นี่คือตัวอย่างของ DSL ฉันไม่ได้คิดค้นภาษาใหม่ แต่จากนั้นฉันเพิ่งสร้างสตริงจำนวนมากที่ไมโครคอนโทรลเลอร์สามารถอ่านจาก EEPROM และสามารถแยกวิเคราะห์ตามนั้นและสามารถทำงานเฉพาะได้


4

ฉันได้เขียนโพสต์บล็อกสั้น ๆ เกี่ยวกับสาเหตุที่ฉันชอบใช้ DSL:

ฉันต้องการให้เราใช้ภาษาเฉพาะโดเมน (DSL) เพิ่มเติม

ในนั้นฉันกำหนด DSL เป็น:

ภาษาโปรแกรมขนาดเล็กที่ออกแบบมาโดยเฉพาะเพื่อสื่อสารการแก้ปัญหาสำหรับโดเมนเฉพาะของปัญหา

ในแง่ของการใช้งานหากคุณเคยใช้ Ant, Structured Query Language (SQL) หรือ Cascading Style Sheets (CSS) แสดงว่าคุณเคยใช้ DSL

ฉันชอบใช้ DSL เพราะพวกเขามุ่งเน้นไปที่การอำนวยความสะดวกในการสื่อสารวิธีแก้ปัญหาไปยังช่องว่างของปัญหาที่เฉพาะเจาะจงและพวกเขาทำในลักษณะที่ส่งเสริมการรวมผู้เชี่ยวชาญด้านโดเมน


3

ตัวอย่างง่ายๆสำหรับภาษาเฉพาะโดเมน (DSL) คือ HTML ซึ่งใช้สำหรับโดเมนเฉพาะที่เรียกว่าแอปพลิเคชันบนเว็บ


3

ฉันเพิ่งได้ยิน DSL เมื่อไม่นานมานี้ แต่พบตัวอย่างที่เป็นประโยชน์มาก: LUNA (อดีต lunascript)

เป็นภาษา / เฟรมเวิร์กการเขียนโปรแกรมที่สร้างขึ้นเองโดยทีมงาน Asana สำหรับแพลตฟอร์มของตนเอง

ตามที่ฉันพบเพิ่มเติม บริษัท หลายแห่งสร้างกรอบและภาษาของตนเองเพื่อสร้างความได้เปรียบในการแข่งขันที่เหมาะสมตัวอย่างบางส่วน ได้แก่ :

  • SAP กับ AbAp
  • PeopleSoft กับ PeopleCode
  • Apple กับ Objective-C
  • Facebook มีสิ่งต่างๆเช่น FBML และ FQL

โดเมนเหล่านี้เป็นโดเมนเฉพาะเนื่องจากคุณจะใช้เกือบเฉพาะสำหรับการทำงานบนแพลตฟอร์มเหล่านี้

ฉันหวังว่าคำตอบนี้จะช่วยให้คุณกระจ่างเกี่ยวกับแนวคิดนี้


3
Objective-C ไม่ใช่ภาษาเฉพาะของโดเมน
boraseoksoon

นอกจากนี้ยังไม่ได้ผลิตโดย (และสำหรับ) Apple
Alexander Rossa

2

ตัวอย่างของ DSL ที่ใช้ใน Machine Learning นั้นเป็น patsy ใน python: https://patsy.readthedocs.io/en/latest/formulas.html#

ซึ่งอ้างอิงจากสูตร DSL จาก R: https://stat.ethz.ch/R-manual/R-devel/library/stats/html/formula.html

https://cran.r-project.org/web/packages/Formula/vignettes/Formula.pdf

และ Hadley มีส่วนที่ดีในหนังสือ R ขั้นสูงของเขาที่อธิบายวิธีการสร้าง DSL w / R: http://adv-r.had.co.nz/dsl.html

เมื่อฟิลด์การเรียนรู้เชิงลึกคงที่ (หรือแม้แต่ตอนนี้) ฉันก็อยากเห็นสิ่งที่คล้ายกันเกิดขึ้นในโครงการ Apache MXnet แต่ผมยังไม่เห็นข้อเสนอใด ๆ ที่เกี่ยวกับหน้าข้อเสนอเลยว่า


1

ภาษาเฉพาะโดเมนแสดงกระบวนการและความรู้ของโดเมนของคุณในภาษาที่ใช้แนวคิดและตรรกะจากสาขาเฉพาะของคุณโดยตรง

ชุมชนมีการเติบโตอย่างแน่นอน แต่ยังไม่อยู่ในระดับของเทคโนโลยี "กระแสหลัก" อื่น ๆ

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

นี่คือการประชุมที่วิทยากรยกตัวอย่าง DSL โดยใช้JetBrains MPSพร้อมเทคโนโลยีการตัดต่อแบบ Projectional: https://vimeo.com/197381453


1

DSL - ภาษาเฉพาะโดเมน มาเริ่มกันเลยว่าโดเมนคืออะไร - โดเมนคือพื้นที่ขอบเขตที่กำหนด โดเมนนี้สามารถเป็นรูปลักษณ์ของเว็บไซต์และคุณมี CSS และโดเมนที่สองอาจเป็นโครงสร้างเว็บไซต์และที่นี่คุณมี HTML

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

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

cookie = async getCookie(cookieId)
user = async getUser(userId)
result async user.buy(cookie)
if (result.isError()) {
  error.showAlert("User has not enough money")
} else {
  confirmation.showSuccess("Cookie was bought")
}

GPL (ภาษาวัตถุประสงค์ทั่วไป) จากด้านบนเป็นเท่าใดและคำศัพท์เฉพาะโดเมนและเครื่องมือเท่าใด นี่เป็นการผสมผสานระหว่างสองคำสั่ง แต่คำสั่งทั้งหมดอยู่ที่นี่เฉพาะโดเมน ที่กล่าวว่าเราสามารถพูดได้ว่าข้างบนเขียนด้วย DSL โดยที่โดเมนคือแอปพลิเคชัน x

จากตัวอย่างนี้ฉันสามารถสร้างเครื่องมือที่เป็นนามธรรมได้มากขึ้นและส่วนใหญ่ดำเนินการตามขั้นตอนการควบคุมโดยเครื่องมือเหล่านั้นลองพิจารณา (นี่คือ FP มากกว่า แต่หวังว่าคุณจะได้รับสิ่งที่ฉันหมายถึง):

waitForMany(getCookie(cookieId), getUser(userId)
  .andThen([cookie, user] -> user.buy(cookie))
  .andThen(showSuccess("Cookie was bought"))
  .whenError(showError("User has not enough money"))

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

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

DSL คืออะไรหลาย ๆ อย่างเช่นกรอบงานที่กำหนดชุดของกฎคือ DSL หากคุณเห็นใครบางคนอ้างว่าเขาเป็นผู้พัฒนา React คุณจะรู้ว่าเขาเป็นนักพัฒนาเฉพาะโดเมนเนื่องจาก React เป็น DSL ซึ่งเป็นทางเลือกสำหรับการใช้แพลตฟอร์มเว็บแบบเนทีฟ หากคุณสามารถเขียนฟังก์ชันจากเครื่องมือเฉพาะโดเมนที่มีอยู่แสดงว่าคุณกำลังเขียนโดยใช้ DSL ยิ่งไปกว่านั้นใน React ขออภัยทุกคนที่ไม่ได้มาจาก DSL: D นี้คุณสามารถสร้างชุดของส่วนประกอบและเขียนเป็นหน่วยการสร้างและ Hurra! ตอนนี้คุณทำ DSL เหนือ DSL แล้ว

ใช่ DSL ซ้ำหลายครั้งเกินไปที่นี่ขออภัย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.