วิศวกรรมซอฟต์แวร์

ถาม - ตอบสำหรับมืออาชีพนักวิชาการและนักเรียนที่ทำงานในวงจรการพัฒนาระบบ

5
ใน TDD ถ้าฉันเขียนกรณีทดสอบที่ผ่านไปโดยไม่แก้ไขโค้ดการผลิตหมายความว่าอย่างไร
นี่คือกฎของ Robert C. Martin สำหรับ TDD : คุณไม่ได้รับอนุญาตให้เขียนรหัสการผลิตใด ๆ เว้นแต่ว่าจะทำการทดสอบหน่วยที่ล้มเหลว คุณไม่ได้รับอนุญาตให้เขียนการทดสอบหน่วยเกินกว่าที่จะล้มเหลว และความล้มเหลวในการรวบรวมเป็นความล้มเหลว คุณไม่ได้รับอนุญาตให้เขียนรหัสการผลิตมากกว่าที่เพียงพอที่จะผ่านการทดสอบหน่วยที่ล้มเหลว เมื่อฉันเขียนการทดสอบที่ดูเหมือนว่าคุ้มค่า แต่ผ่านได้โดยไม่ต้องเปลี่ยนรหัสการผลิต: นั่นหมายความว่าฉันทำอะไรผิดหรือเปล่า? ฉันควรหลีกเลี่ยงการเขียนการทดสอบดังกล่าวในอนาคตหากสามารถช่วยได้หรือไม่? ฉันควรออกจากการทดสอบนั้นหรือลบออกหรือไม่ หมายเหตุ: ฉันพยายามถามคำถามนี้ที่นี่: ฉันสามารถเริ่มต้นด้วยการทดสอบหน่วยผ่านได้หรือไม่ แต่ฉันไม่สามารถที่จะพูดได้ชัดเจนพอถึงตอนนี้

5
คิวข้อความ ฐานข้อมูลเทียบกับ MQ โดยเฉพาะ
ฉันหลังจากคำแนะนำเกี่ยวกับการจัดคิวข้อความ เรามีข้อกำหนดสำหรับ "งาน" ที่จะโพสต์ในคิวข้อความ ข้อเสนอแนะดั้งเดิมคือเพียงใช้อินสแตนซ์ SQL Server และประมวลผลข้อความจากนั้น ทุกสิ่งที่ฉันได้อ่านบนอินเทอร์เน็ตแสดงให้เห็นว่าการใช้ฐานข้อมูลสำหรับ Message Queue ไม่ใช่วิธีที่ปรับขนาดได้ ด้วยเหตุนี้จึงแนะนำให้ใช้ความคิด RabbitMQ หรือบุคคลที่สามอื่น ๆ MQ อีกสิ่งที่ควรคำนึงถึงก็คือข้อกำหนดสำหรับ "การประมวลผลงาน" จะไม่ต่ำกว่า 30 วินาทีดังนั้นกระบวนการที่ทำหน้าที่จะสำรวจฐานข้อมูลทุก ๆ 30 วินาที สำหรับฉันแล้วมันไม่ได้เลวร้ายนักและอาจใช้ได้ดีโดยไม่ต้องเพิ่มการโหลดจำนวนมากในฐานข้อมูล เรามีฐานข้อมูลอยู่แล้วในลูกค้าของเราที่เราสามารถใช้สิ่งนี้ได้ดังนั้นมันจะไม่เพิ่มการสนับสนุนพิเศษที่จำเป็นสำหรับลูกค้าของเราในขณะที่ถ้าเราเพิ่ม MQ บุคคลที่สามจะมีการสนับสนุนพิเศษสำหรับการกำหนดค่าเครือข่าย ฯลฯ ซึ่งจะเป็น เป็นจำนวนมากเนื่องจากมีผู้ใช้จำนวนมาก ตัวเลือกอื่นที่ฉันกำลังพิจารณาคือให้ผู้ใช้เลือกระหว่างกัน หากพวกเขาเป็นผู้ใช้รายเล็กโซลูชันของ SQL Server จะใช้ได้ แต่ถ้าพวกเขาเป็นผู้ใช้ที่มีขนาดใหญ่ขึ้นเราอนุญาตให้พวกเขากำหนดค่าโซลูชัน MQ ของบุคคลที่สาม ฉันไม่ได้ขายในการแก้ปัญหาใด ๆ ฉันสงสัยว่าใครมีอะไรที่ฉันควรพิจารณาหรือคำแนะนำ

1
ฉันควรแยกการทดสอบหน่วยและการทดสอบการรวมเข้าด้วยกันหรือไม่
ฉันต้องเขียนการทดสอบหน่วยและการทดสอบการรวมสำหรับโครงการ ควรทำการทดสอบทั้งหมดในโฟลเดอร์การทดสอบเดียวหรือไม่? หรือการทดสอบหน่วยและการทดสอบการรวมเข้าด้วยกันควรอยู่ในโฟลเดอร์การทดสอบแยกกันหรือไม่? ฉันควรหรือแม้กระทั่งใส่ไว้ในโครงการแยก ? หากฉันรวมมันเข้าด้วยกันมีข้อดีหรือข้อเสียของวิธีการนี้หรือไม่?

3
เหตุใดจึงใช้ข้อยกเว้นเกิน (ทำเครื่องหมาย)
เมื่อไม่นานมานี้ฉันเริ่มใช้ Scala แทน Java ส่วนหนึ่งของกระบวนการ "แปลง" ระหว่างภาษาสำหรับฉันได้เรียนรู้การใช้งานEitherอัตโนมัติแทน (ตรวจสอบ) Exceptions ฉันได้รับการเข้ารหัสด้วยวิธีนี้มาระยะหนึ่งแล้ว แต่เมื่อไม่นานมานี้ฉันเริ่มสงสัยว่าเป็นวิธีที่ดีกว่าหรือไม่ ข้อEitherได้เปรียบที่สำคัญอย่างหนึ่งที่มากกว่าExceptionคือประสิทธิภาพที่ดีกว่า Exceptionความต้องการที่จะสร้างสแต็คร่องรอยและจะถูกโยน เท่าที่ฉันเข้าใจการขว้างปาExceptionไม่ใช่ส่วนที่เรียกร้อง แต่การสร้างสแต็กติดตามคือ แต่แล้วหนึ่งสามารถสร้าง / สืบทอดExceptions พร้อมด้วยscala.util.control.NoStackTraceและมากยิ่งขึ้นดังนั้นผมเห็นความอุดมสมบูรณ์ของกรณีที่ด้านซ้ายของEitherในความเป็นจริงException(ละทิ้งการเพิ่มประสิทธิภาพการทำงาน) ข้อดีอีกข้อหนึ่งEitherก็คือคอมไพเลอร์ - ความปลอดภัย คอมไพเลอร์ Scala จะไม่บ่นเกี่ยวกับExceptions ที่ไม่ได้จัดการ(ต่างจากคอมไพเลอร์ของ Java) แต่ถ้าฉันไม่เข้าใจผิดการตัดสินใจครั้งนี้มีเหตุผลด้วยเหตุผลเดียวกับที่กำลังคุยกันในหัวข้อนี้ดังนั้น ... ในแง่ของไวยากรณ์ฉันรู้สึกว่าExceptionสไตล์นั้นชัดเจนกว่า ตรวจสอบบล็อคโค้ดต่อไปนี้ (ทั้งการใช้ฟังก์ชันเดียวกัน): Either รูปแบบ: def compute(): Either[String, Int] = { val aEither: Either[String, String] = if (someCondition) Right("good") else Left("bad") …

5
เมื่อใดที่เราควรใช้ MongoDB
MongoDB เป็นฐานข้อมูล NoSQL ที่ฉันพบว่าใช้ง่าย เมื่อเร็ว ๆ นี้ฉันต้องพัฒนาแอพพลิเคชั่นที่ต้องการรวบรวมข้อมูลโดยใช้คำร้องขอ HTTP และเก็บผลลัพธ์บางอย่างหลังจากประมวลผลข้อมูลและฉันพยายามใช้ MongoDB จากประสบการณ์นี้ฉันพบว่ามันดีกว่าการใช้มากกว่าฐานข้อมูลเชิงสัมพันธ์แบบดั้งเดิมและเนื่องจากฉันเป็นนักพัฒนาไม่ใช่ DBA งานของฉันจึงง่ายขึ้นมาก ถึงกระนั้นบางครั้งฉันก็ไม่แน่ใจว่าเมื่อไหร่ที่ฉันควรใช้ MongoDB แทนที่จะเป็นฐานข้อมูลเชิงสัมพันธ์แบบดั้งเดิมเช่น SQL Server หรือ MySQL ในกรณีนี้เมื่อเราสามารถใช้ MongoDB แทนฐานข้อมูลเชิงสัมพันธ์ มีบาง trully ใหญ่ข้อแม้เกี่ยวกับ MongoDB ที่ทำให้มันไม่เหมาะสมสำหรับสถานการณ์บางอย่าง?

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

5
MVC: คอนโทรลเลอร์ทำลายหลักการความรับผิดชอบเดี่ยวหรือไม่?
หลักการความรับผิดชอบเดี่ยวระบุว่า "คลาสควรมีเหตุผลประการเดียวคือการเปลี่ยนแปลง" ในรูปแบบ MVC งานของผู้ควบคุมจะเป็นสื่อกลางระหว่างมุมมองและรูปแบบ มันมีอินเทอร์เฟซสำหรับมุมมองเพื่อรายงานการกระทำของผู้ใช้บน GUI (เช่นการอนุญาตให้ดูการโทรcontroller.specificButtonPressed()) และสามารถเรียกวิธีการที่เหมาะสมในตัวแบบเพื่อจัดการข้อมูลหรือเรียกใช้การดำเนินการ (เช่นmodel.doSomething()) . ซึ่งหมายความว่า: คอนโทรลเลอร์จำเป็นต้องรู้เกี่ยวกับ GUI เพื่อเสนอมุมมองอินเทอร์เฟซที่เหมาะสมเพื่อรายงานการกระทำของผู้ใช้ นอกจากนี้ยังจำเป็นต้องรู้เกี่ยวกับตรรกะในรูปแบบเพื่อที่จะสามารถเรียกใช้วิธีการที่เหมาะสมในรูปแบบ นั่นหมายความว่ามีสองเหตุผลในการเปลี่ยนแปลง : การเปลี่ยนแปลงใน GUI และการเปลี่ยนแปลงในตรรกะธุรกิจ หากมีการเปลี่ยนแปลง GUI เช่นมีการเพิ่มปุ่มใหม่ตัวควบคุมอาจต้องเพิ่มวิธีการใหม่เพื่อให้มุมมองรายงานผู้ใช้กดปุ่มนี้ และหากตรรกะทางธุรกิจในรูปแบบการเปลี่ยนแปลงผู้ควบคุมอาจต้องเปลี่ยนเพื่อที่จะเรียกใช้วิธีการที่ถูกต้องในรูปแบบ ดังนั้นการควบคุมมีสองเหตุผลที่เป็นไปได้ที่จะมีการเปลี่ยนแปลง มันทำลาย SRP หรือไม่

6
มาโครคืออะไร ความแตกต่างระหว่างแมโครและฟังก์ชั่น?
ฉันไม่เข้าใจแนวคิดมาโครอย่างดี มาโครคืออะไร ฉันไม่เข้าใจว่ามันแตกต่างจากฟังก์ชั่นอย่างไร ทั้งฟังก์ชั่นและมาโครมีบล็อกของรหัส ดังนั้นมาโครและฟังก์ชั่นต่างกันอย่างไร

3
GDB หยุดการดำเนินการชั่วคราวอย่างไร
อย่างที่คุณอาจทราบเราสามารถใช้ GDB และกำหนดจุดพักบนรหัสของเราเพื่อหยุดการประมวลผลชั่วคราวสำหรับการดีบัก คำถามของฉันคือ GDB หยุดกระบวนการอย่างไรและให้คุณดูเนื้อหาของการลงทะเบียนโดยใช้i rตัวอย่างเช่น การลงทะเบียนเหล่านั้นถูกใช้โดยกระบวนการ OS อื่น ๆ อย่างต่อเนื่องหรือ พวกเขาจะไม่ถูกเขียนทับได้อย่างไร? เป็นเพียงภาพรวมของเนื้อหาและไม่ใช่ข้อมูลจริง
16 c++  debugging 

4
เมื่อใดจึงจะย้ายเขตข้อมูลทั่วไปลงในคลาสพื้นฐานได้
ขณะนี้ฉันมีคลาสที่ได้รับสองคลาสAและBที่ทั้งสองมีเขตข้อมูลร่วมกันและฉันพยายามที่จะตรวจสอบว่ามันควรจะขึ้นไปในชั้นฐาน มันไม่เคยอ้างถึงจากชั้นฐานและบอกว่าในบางจุดลงมาที่ถนนอีกชั้นจะได้รับCที่ไม่ได้_field1แล้วจะไม่เป็นหลักของ "สิทธิพิเศษน้อย" (หรือบางสิ่งบางอย่าง) ถ้ามันถูกละเมิด เป็น? public abstract class Base { // Should _field1 be brought up to Base? //protected int Field1 { get; set; } } public class A : Base { private int _field1; } public class B : Base { private int _field1; } public class C …

2
การแปลงวิธี C ++ เป็นฟังก์ชัน C ด้วยอาร์กิวเมนต์ตัวชี้เป็นรูปแบบที่ยอมรับได้หรือไม่
ฉันใช้ C ++ กับ ESP-32 เมื่อลงทะเบียนตัวจับเวลาฉันต้องทำสิ่งนี้: timer_args.callback = reinterpret_cast<esp_timer_cb_t>(&SoundMixer::soundCallback); timer_args.arg = this; soundCallbackนี่โทรจับเวลา และสิ่งเดียวกันเมื่อลงทะเบียนงาน: xTaskCreate(reinterpret_cast<TaskFunction_t>(&SoundProviderTask::taskProviderCode), "SProvTask", stackSize, this, 10, &taskHandle); ดังนั้นวิธีการเริ่มต้นในงานที่แยกจากกัน GCC เตือนฉันเสมอเกี่ยวกับการแปลงเหล่านี้ แต่ทำงานได้ตามแผนที่วางไว้ เป็นที่ยอมรับในรหัสการผลิตหรือไม่ มีวิธีที่ดีกว่าในการทำเช่นนี้?
16 c++  c  functions 

1
โครงสร้างไดเร็กทอรีสำหรับ. NET Solution
เราไปเยี่ยมผู้รับเหมาเมื่อเร็ว ๆ นี้ซึ่งได้ถามวิธีการของเราในการจัดทำโครงการ โปรดทราบว่าฉันหมายถึงโครงสร้างไดเรกทอรีโดยเฉพาะ เขาแนะนำให้ใช้แนวทางของ Microsoft ฉันคิดว่าฉันจะสามารถใช้ Google "Microsoft แนวทาง. โครงสร้างไดเรกทอรีโครงการ NET." และพบสิ่งที่เป็นประโยชน์ แต่สิ่งนี้ได้พิสูจน์แล้วว่าไม่เป็นเช่นนั้น เนื่องจากเราทำสิ่งนี้: [Company.System.Feature] |-doc |Sandcastle project |-lib |Nuget packages |-src |-Project1 e.g. web |-Project2 e.g. business logic |-UnittestProject1 |-Specs โฟลเดอร์ doc มีโซลูชัน Sandcastle ตามที่อธิบายไว้ที่นี่: https://www.codeproject.com/Articles/15176/Sandcastle-Help-File-Builder (ดูที่: เส้นทางสัมบูรณ์และเส้นทางสัมพัทธ์) ดังนั้นโฟลเดอร์ doc มีโฟลเดอร์ช่วยเหลือซึ่งมีไฟล์ช่วยเหลือที่สร้างขึ้น โฟลเดอร์ lib มีแพ็คเกจ Nuget ทั้งหมด มีแนวทางของ Microsoft …
16 c#  visual-studio 

4
ไม่สามารถแก้ไขความลึกลับของฟังก์ชั่นใน Javascript ได้
ฉันกำลังพยายามที่จะเข้าใจเบื้องหลังม่าน Javascript และชนิดของการติดอยู่ในการทำความเข้าใจการสร้างสร้างขึ้นในวัตถุโดยเฉพาะวัตถุและฟังก์ชั่นและความสัมพันธ์ระหว่างพวกเขา เมื่อฉันอ่านว่าวัตถุในตัวทั้งหมดเช่น Array, String ฯลฯ เป็นส่วนขยาย (สืบทอด) จาก Object ฉันคิดว่า Object เป็นวัตถุแรกที่สร้างขึ้นในวัตถุที่สร้างขึ้นและส่วนที่เหลือของวัตถุสืบทอดมาจากมัน แต่มันก็ไม่สมเหตุสมผลเมื่อคุณรู้ว่า Object สามารถสร้างได้โดยฟังก์ชั่นเท่านั้น แต่ฟังก์ชั่นนั้นก็ไม่ได้มี แต่วัตถุของ Function มันเริ่มที่จะฟังดูลำบากเช่นไก่และไก่ สิ่งที่สับสนอย่างยิ่งคือถ้าฉันconsole.log(Function.prototype)พิมพ์ฟังก์ชั่น แต่เมื่อฉันพิมพ์console.log(Object.prototype)มันจะพิมพ์วัตถุ ทำไมFunction.prototypeฟังก์ชั่นเมื่อมันถูกหมายถึงเป็นวัตถุ? นอกจากนี้ตามเอกสาร Mozilla ทุก javascript functionเป็นส่วนขยายของFunctionวัตถุ แต่เมื่อคุณconsole.log(Function.prototype.constructor)เป็นอีกฟังก์ชั่น ตอนนี้คุณจะใช้บางสิ่งเพื่อสร้างมันเองได้อย่างไร (Mind = blown) สิ่งสุดท้ายFunction.prototypeคือฟังก์ชั่น แต่ฉันสามารถเข้าถึงconstructorฟังก์ชั่นที่ใช้Function.prototype.constructorหมายความว่าFunction.prototypeเป็นฟังก์ชั่นที่ส่งกลับprototypeวัตถุ

4
Java - มันเป็นความคิดที่ดีที่จะมีคลาสแบบคงที่?
ฉันกำลังทำงานในโครงการเดี่ยวขนาดใหญ่ขึ้นและตอนนี้และฉันมีหลายชั้นเรียนซึ่งฉันไม่เห็นเหตุผลที่จะสร้างตัวอย่างของ ตัวอย่างเช่นคลาสลูกเต๋าของฉันตอนนี้เก็บข้อมูลทั้งหมดของมันแบบสแตติกและวิธีการทั้งหมดของมันก็คงที่เช่นกัน Dice.roll()ผมไม่จำเป็นต้องเริ่มต้นมันเพราะเมื่อฉันต้องการที่จะม้วนลูกเต๋าและได้รับค่าใหม่ฉันเพียงแค่การใช้งาน ฉันมีหลายคลาสที่คล้ายกันซึ่งมีฟังก์ชั่นหลักเพียงอย่างเดียวเช่นนี้และฉันกำลังจะเริ่มทำงานกับคลาส "คอนโทรลเลอร์" ที่จะรับผิดชอบกิจกรรมทั้งหมด (เช่นเมื่อผู้เล่นเคลื่อนตัวและสิ่งที่เกิดขึ้นในปัจจุบัน) เป็น) และฉันพบว่าฉันสามารถทำตามแนวคิดเดียวกันสำหรับชั้นเรียนนี้ได้ ฉันไม่เคยวางแผนที่จะสร้างวัตถุหลายรายการสำหรับคลาสที่เฉพาะเจาะจงเหล่านี้ดังนั้นจึงเป็นความคิดที่ดีหรือไม่ที่จะทำให้พวกมันคงที่? ฉันสงสัยว่าสิ่งนี้ถือเป็น "การปฏิบัติที่ไม่ดี" เมื่อพูดถึงจาวา จากสิ่งที่ฉันได้เห็นชุมชนดูเหมือนจะแยกในหัวข้อนี้? ต่อไปฉันจะรักการอภิปรายเกี่ยวกับเรื่องนี้และการเชื่อมโยงไปยังแหล่งข้อมูลจะดีเช่นกัน!

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

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