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

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

11
คุณจะทำอย่างไรเมื่อคุณไม่สามารถเข้าใจบางส่วนของการเขียนโปรแกรม [ปิด]
ตามที่เป็นอยู่ในปัจจุบันคำถามนี้ไม่เหมาะสำหรับรูปแบบคำถาม & คำตอบของเรา เราคาดหวังว่าคำตอบจะได้รับการสนับสนุนจากข้อเท็จจริงการอ้างอิงหรือความเชี่ยวชาญ แต่คำถามนี้อาจเรียกร้องให้มีการอภิปรายโต้แย้งโต้แย้งหรือการอภิปรายเพิ่มเติม หากคุณรู้สึกว่าคำถามนี้สามารถปรับปรุงและเปิดใหม่ได้โปรดไปที่ศูนย์ช่วยเหลือเพื่อขอคำแนะนำ ปิดให้บริการใน8 ปีที่ผ่านมา ฉันกำลังเรียนรู้ภาษาใหม่เมื่อฉันไปฉันเขียนโค้ดสำหรับโปรแกรมขั้นพื้นฐานในหลายภาษาและไปที่ชั้นเรียน ฉันอ่านหนังสือบทความบทเรียนวิดีโอคุณชื่อมัน แต่ฉันดูเหมือนจะไม่ติดอะไรบางอย่าง ตัวอย่างเช่นฉันไม่เคยเข้าใจพอยน์เตอร์ - สิ่งที่พวกเขาทำได้ดี (ไม่ใช่ส่วนหนึ่งของคำถาม - ไม่จำเป็นต้องติดแท็ก "Pointers" ... ) อย่างไรก็ตามคำถามของฉันไม่ใช่สิ่งที่พอยน์เตอร์ทำ แต่ฉันจะเข้าใจสิ่งต่าง ๆ เช่นนั้นได้อย่างไร หากหลังจากอ่านหนังสือหรือบทความเกี่ยวกับการเขียนโปรแกรมบางส่วนแล้วและฉันไม่เข้าใจฉันต้องทำอย่างไร การเขียนโค้ดในคุณสมบัติบางอย่างของการเขียนโปรแกรมช่วยได้อย่างแน่นอน แต่ก็ไม่ได้ช่วยให้เข้าใจได้มากนัก ส่วนทางทฤษฎีมีความสำคัญในการทำความเข้าใจ

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

5
ฉันควรใช้โครงสร้างข้อมูลใดสำหรับกลยุทธ์การแคชนี้
ฉันกำลังทำงานกับแอปพลิเคชั่น. NET 4.0 ซึ่งทำการคำนวณค่อนข้างแพงในสองครั้งที่ส่งคืนเป็นสองเท่า การคำนวณนี้จะดำเนินการอย่างใดอย่างหนึ่งหลายพันในแต่ละรายการ การคำนวณเหล่านี้ดำเนินการในTaskเธรดพูลเธรด การทดสอบเบื้องต้นบางอย่างแสดงให้เห็นว่ามีการคำนวณแบบเดียวกันซ้ำแล้วซ้ำอีกดังนั้นฉันต้องการแคชผลลัพธ์n เมื่อแคชเต็มฉันต้องการที่จะโยนรายการที่ใช้บ่อยที่สุด ( แก้ไข:ฉันรู้น้อยที่สุด - ไม่สมเหตุสมผลเพราะเมื่อแคชเต็มและฉันจะแทนที่ผลลัพธ์ด้วยการคำนวณใหม่หนึ่งรายการนั้นจะใช้อย่างน้อยบ่อยครั้งและแทนที่ทันทีในครั้งถัดไปที่มีการคำนวณผลลัพธ์ใหม่ และเพิ่มลงในแคช) เพื่อที่จะนำสิ่งนี้ไปใช้ฉันคิดว่าจะใช้ a Dictionary<Input, double>(ซึ่งInputจะเป็น mini-class ที่เก็บค่าสองค่าสองอินพุต) เพื่อเก็บอินพุตและผลลัพธ์ที่แคชไว้ อย่างไรก็ตามฉันจะต้องติดตามเมื่อมีการใช้ผลลัพธ์ครั้งล่าสุด สำหรับสิ่งนี้ฉันคิดว่าฉันต้องการคอลเล็กชันที่สองที่จัดเก็บข้อมูลฉันจะต้องลบผลลัพธ์ออกจาก dictonary เมื่อแคชเริ่มเต็ม ฉันกังวลว่าการเรียงลำดับรายการนี้อย่างสม่ำเสมอจะส่งผลเสีย มีวิธีที่ดีกว่า (เช่นมีประสิทธิภาพมากกว่า) ในการทำเช่นนี้หรืออาจเป็นโครงสร้างข้อมูลทั่วไปที่ฉันไม่รู้จัก? ฉันควรทำโปรไฟล์ / การวัดประเภทใดเพื่อกำหนดประสิทธิภาพสูงสุดของการแก้ปัญหาของฉัน

2
ภาษาของแบบสอบถามสำหรับ JSON
ฉันมีเซิร์ฟเวอร์ที่ส่งคืนข้อความ JSON ที่มีขนาดใหญ่มากและแอปพลิเคชันไคลเอนต์ของฉันขึ้นอยู่กับการตอบสนองนี้เป็นส่วนหนึ่งเท่านั้น แอปพลิเคชันไคลเอนต์ต้องตรวจสอบว่ามี "xyz" คุณสมบัติอยู่ในข้อความ JSON และขึ้นอยู่กับผลการเรียกใช้ usecase เฉพาะ สำหรับความต้องการนี้การแปลงข้อความ JSON ทั้งหมดเป็นวัตถุที่ฟังดูแพงไปหน่อยสำหรับฉันและด้วยเหตุนี้คำถามนี้ มีภาษาแบบสอบถาม JSON มาตรฐานเหมือนที่เรามีสำหรับ XML หรือไม่ ถ้าใช่สิ่งที่ดีที่สุดรู้การใช้ภาษาแบบสอบถามนี้ในจาวา FYI: การเปลี่ยนหรือเพิ่มบริการใหม่ทางฝั่งเซิร์ฟเวอร์ไม่ใช่ตัวเลือก
11 java  json 

2
ผู้ควบคุมควรส่งผ่านข้อมูลไปยังมุมมองในรูปแบบ MVC หรือไม่
ฉันทำงานกับ ASP.NET MVC (และการใช้งาน MVC บนเว็บอื่น ๆ ) ค่อนข้างบ่อย แต่นี่เป็นสิ่งที่ฉันไม่เคยแน่ใจ: คอนโทรลเลอร์และดูการสื่อสารควรหรือไม่ แน่นอนว่าผู้ควบคุมควรเลือกมุมมองที่จะใช้ แต่สิ่งที่ฉันหมายความว่าผู้ควบคุมควรส่งผ่านข้อมูลไปยังมุมมอง? ในความคิดของฉันหากมุมมองคาดหวังว่าข้อมูลจากคอนโทรลเลอร์จะถูกเชื่อมโยงเข้าด้วยกันเป็นคู่ (คอนโทรลเลอร์, มุมมอง) อย่างมีประสิทธิภาพ แต่ฉันมักจะมีมุมมองการสื่อสารกับรูปแบบของตัวเองและเป็นอิสระจากตัวควบคุมใด ๆ ฉันมีแนวทางที่ถูกต้องหรือเป็นกรณีที่ไม่มีคำตอบที่ถูกต้องหรือไม่ คำตอบเปลี่ยนไปเมื่อทำงานในเว็บกับสภาพแวดล้อมอื่น ๆ หรือไม่? คำตอบเปลี่ยนไปหรือไม่เมื่อคุณมีแนวคิดเกี่ยวกับมุมมองที่พิมพ์ออกมาอย่างรุนแรง (เช่นใน ASP.NET MVC) หรือไม่?
11 architecture  mvc 

4
ตัววนซ้ำมีสัญญาโดยนัยแบบไม่ทำลายหรือไม่?
สมมติว่าฉันกำลังออกแบบโครงสร้างข้อมูลที่กำหนดเองเช่นสแต็กหรือคิว (ตัวอย่างเช่น - อาจเป็นคอลเลกชันที่สั่งโดยพลการอื่น ๆ ที่มีตรรกะเทียบเท่าpushและpopวิธีการ - นั่นคือวิธีการเข้าถึงแบบทำลายล้าง) หากคุณกำลังใช้ตัววนซ้ำ (ใน. NET โดยเฉพาะIEnumerable<T>) กับคอลเล็กชันนี้ที่ปรากฏในแต่ละการวนซ้ำนั่นจะเป็นการผิดIEnumerable<T>สัญญาโดยนัยหรือไม่? ไม่IEnumerable<T>ได้มีการทำสัญญานี้โดยนัย? เช่น: public IEnumerator<T> GetEnumerator() { if (this.list.Count > 0) yield return this.Pop(); else yield break; }

3
มีไลบรารี JavaScript แบบโอเพ่นซอร์สที่ระบุหลายแท็บเบราว์เซอร์และสถานะไคลเอ็นต์สำหรับเบราว์เซอร์ใหม่หรือไม่ [ปิด]
ปิด. คำถามนี้เป็นคำถามปิดหัวข้อ ไม่ยอมรับคำตอบในขณะนี้ ต้องการปรับปรุงคำถามนี้หรือไม่ อัปเดตคำถามเพื่อให้เป็นหัวข้อสำหรับ Software Engineering Stack Exchange ปิดให้บริการใน5 ปีที่ผ่านมา มีคุณสมบัติใหม่ ๆ บางอย่างของ HTML5 ที่ทำให้มันกลายเป็นเบราว์เซอร์รุ่นล่าสุดที่อนุญาตให้แชร์สถานะระหว่างแท็บหน้าต่างเบราว์เซอร์หน้าต่างโดเมนเดียวกัน ฯลฯ ดังนั้นจึงอาจเป็นเรื่องง่ายขึ้นเล็กน้อยที่จะเขียนแอปพลิเคชันเว็บ ไคลเอนต์และยังจัดการสถานะอย่างชาญฉลาดระหว่างแท็บและ / หรือหน้าต่าง ขณะนี้มีไลบรารีเช่น Backbone.js ที่สามารถช่วยจัดการสถานะในแท็บเดียวหรือหน้าต่างเดียว มีอะไรอีกบ้างที่ช่วยในการจัดการแท็บหลาย ๆ แท็บ (หรือหน้าต่าง) ทั่วโลกสถานะเฉพาะของแท็บและการจัดกิจกรรมข้ามแท็บโดยไม่ต้องอาศัยเซิร์ฟเวอร์เพื่อซิงค์ข้อมูลทั้งหมด

3
เหตุใดแพลตฟอร์มโทรศัพท์มือถือจึงไม่สนับสนุนการรวบรวมขยะทั่วไป
ทั้ง Windows Phone / Xbox และ Android ขาดการสนับสนุนสำหรับการรวบรวมขยะทั่วไป นี่น่าผิดหวังสำหรับโปรแกรมเมอร์จำนวนมาก ดูเหมือนจะมีเหตุผลทางวิศวกรรมที่ถูกต้องตามกฎหมาย แต่ฉันไม่สามารถเข้าใจได้ โทรศัพท์ปัจจุบันมีหน่วยความจำเพิ่มขึ้นและอาจมี CPU ที่ดีกว่าเดสก์ท็อป / แล็ปท็อปที่ใช้. NET 1.1 กับ generational GC ย้อนกลับไปในปี 2544 และฉันไม่สามารถคิดได้ว่าเหตุผลใดที่โปรเซสเซอร์ ARM จะแย่กว่ารุ่นทั่วไป นอกจากนี้ยังมีความต้องการน้อยลงสำหรับการทำมัลติทาสก์บนโทรศัพท์และคอนโซลดังนั้นจึงมีพื้นที่ว่างมากขึ้น แล้วอะไรล่ะ แก้ไข:สองสามจุดเพื่อชี้แจง: แพลตฟอร์มเหล่านี้ใช้การรวบรวมขยะสำหรับแอปโดยเฉพาะดังนั้นคำถามของฉันไม่เกี่ยวกับสาเหตุที่ GC ไม่รองรับ คำถามของฉันเกี่ยวกับสาเหตุที่generationalเก็บขยะไม่ได้ เหตุผลที่ผู้คนรู้สึกหงุดหงิดเกี่ยวกับการขาด GC generational นั่นคือ GC ที่ไม่ใช่เชิงพันธุกรรมนั้นไม่มีประสิทธิภาพอย่างมาก (นั่นหมายความว่าอายุการใช้งานแบตเตอรี่ไม่ใช่เหตุผล) ฉันเชื่อว่ามีเหตุผลทางเทคนิคที่ซื่อสัตย์สำหรับการขาดการสนับสนุน GC generational นี่ไม่ใช่คำถามเชิงโวหาร

6
เราจะใช้กฎ 80/20 อย่างมีประสิทธิภาพสำหรับเวลาของนักพัฒนาได้อย่างไร
ฉันเป็นนักพัฒนาที่ธนาคารที่มีการใช้กฎ 80/20 80% ของเวลาที่คุณทำงานในโครงการที่ได้รับมอบหมายและ 20% ที่คุณทำงานในสิ่งที่คุณสนใจ อย่างไรก็ตามฉันไม่แน่ใจจริงๆว่าจะทำอย่างไร ฉันหวังว่าจะมีคนอื่นที่สามารถให้คำแนะนำกับฉันได้ ปัญหาของฉันคือเมื่อฉันได้ 'อยู่ในโซน' สิ่งที่ฉันคิดได้ก็คืองานที่ทำ ถ้านี่เป็น 20% สิ่งสุดท้ายที่ฉันต้องการคือหยุดและไปเสียโมเมนตัมและกลับไปทำงานในโครงการหลักของฉัน ฉันควรทำงาน 4 วันกับบางอย่างและอีก 1 วันทำอย่างอื่น หรือ 4 สัปดาห์และ 1 สัปดาห์ ฉันรู้ว่าสิ่งนี้ขึ้นอยู่กับ บริษัท แต่ฉันหวังว่าจะได้รับความรู้สึกว่าอุตสาหกรรมนี้ดำเนินไปได้อย่างไร

4
คำว่า "อินเตอร์เฟส" ใน C ++
Java ทำให้ความแตกต่างที่ชัดเจนระหว่างและclass interface(ฉันเชื่อว่า C # ทำเช่นนั้น แต่ฉันไม่มีประสบการณ์ด้วย) เมื่อเขียน C ++ อย่างไรก็ตามไม่มีภาษาบังคับให้แยกความแตกต่างระหว่างคลาสและส่วนต่อประสาน ดังนั้นฉันมักจะดูอินเตอร์เฟซเป็นวิธีแก้ปัญหาสำหรับการขาดการสืบทอดหลายใน Java การทำให้ความแตกต่างดังกล่าวให้ความรู้สึกโดยพลการและไร้ความหมายใน C ++ ฉันมักจะไปกับวิธีการ "เขียนสิ่งต่าง ๆ ในวิธีที่ชัดเจนที่สุด" ดังนั้นใน C ++ ฉันมีสิ่งที่เรียกว่าส่วนติดต่อใน Java เช่น: class Foo { public: virtual void doStuff() = 0; ~Foo() = 0; }; และฉันก็ตัดสินใจว่าผู้ดำเนินการส่วนใหญ่Fooต้องการแบ่งปันฟังก์ชั่นทั่วไปบางอย่างที่ฉันอาจจะเขียน: class Foo { public: virtual void doStuff() = 0; ~Foo() …

5
การเขียนรหัสที่สามารถทดสอบได้เทียบกับการหลีกเลี่ยงความเอนเอียงแบบเก็งกำไร
ฉันอ่านข้อความในบล็อกเมื่อเช้านี้และพบสิ่งนี้ : ถ้าคลาสเดียวที่ใช้อินเทอร์เฟซลูกค้าคือ CustomerImpl คุณไม่มีความหลากหลายและความสามารถในการสับเปลี่ยนได้จริง ๆ เนื่องจากไม่มีวิธีใดที่จะทดแทน runtime ได้เลย มันเป็นเรื่องธรรมดาทั่วไป นั่นเป็นเหตุผลสำหรับฉันเมื่อการใช้งานอินเทอร์เฟซเพิ่มความซับซ้อนและหากมีเพียงการใช้เพียงครั้งเดียวอย่างใดอย่างหนึ่งอาจยืนยันว่ามันเพิ่มความซับซ้อนที่ไม่จำเป็น การเขียนโค้ดที่มีความเป็นนามธรรมมากกว่าที่ควรจะเป็นมักจะถูกพิจารณาว่าเป็นกลิ่นของรหัสที่เรียกว่า "การเก็งกำไรทั่วไป" (หรือที่กล่าวถึงในโพสต์) แต่ถ้าฉันติดตาม TDD ฉันไม่สามารถสร้างการทดสอบเป็นสองเท่าได้อย่างง่ายดายโดยไม่ต้องคำนึงถึงการเก็งกำไรไม่ว่าจะอยู่ในรูปแบบของการใช้อินเทอร์เฟซหรือตัวเลือก polymorphic อื่น ๆ ของเรา ดังนั้นเราจะคืนดีการแลกเปลี่ยนนี้ได้อย่างไร มันคุ้มค่าหรือไม่ที่จะเป็นการเก็งกำไรโดยทั่วไปเพื่ออำนวยความสะดวกในการทดสอบ / TDD? หากคุณใช้การทดสอบเป็นสองเท่าให้นับเป็นการนำไปใช้ครั้งที่สองและทำให้ความคิดทั่วๆไปไม่เป็นการเก็งกำไรอีกต่อไป? คุณควรพิจารณากรอบการเยาะเย้ยเฮฟวี่เวทที่ช่วยให้ผู้เยาะเย้ยเป็นรูปธรรมมากขึ้น (เช่นโมลเทียบกับ Moq ใน C # โลก) หรือไม่ หรือคุณควรทดสอบกับชั้นเรียนที่เป็นรูปธรรมและเขียนสิ่งที่อาจพิจารณาว่าเป็นการทดสอบ "การรวม" จนกว่าจะถึงเวลาที่การออกแบบของคุณต้องมีความหลากหลาย ฉันอยากรู้อยากเห็นที่จะอ่านคนอื่นจะใช้เวลาในเรื่องนี้ - ขอบคุณล่วงหน้าสำหรับความคิดเห็นของคุณ

3
การนำ Java ไปใช้กับรูปแบบ Blackboard?
มีที่ว่างสำหรับแอปพลิเคชั่นที่ใช้งานได้จริงใน Java ของรูปแบบ Blackboard ที่มีรายละเอียดใน"The Pragmatic Programmer"หรือไม่? มีห้องสมุดใดที่พยายามช่วยเหลือในการนำแนวคิดนี้ไปใช้หรือไม่? ฉันทามติทั่วไปเกี่ยวกับรูปแบบนี้ในชุมชนซอฟต์แวร์ปัจจุบัน (โดยเฉพาะ Java) คืออะไร? แม้ว่าความคิดจะน่าสนใจ แต่ฉันก็รู้สึกว่าหนังสือเล่มนี้อาจล้าสมัย ในกรณีที่คุณไม่คุ้นเคยกับแนวคิดนี้: http://flylib.com/books/en/1.315.1.55/1/
11 java 

3
คำถามเกี่ยวกับการใช้คำว่า 'porting' ในการเขียนโปรแกรม
ขณะนี้ฉันกำลังทำการแก้ไขรหัส C ++ ที่เขียนขึ้นสำหรับระบบ UNIX เพื่อให้ทำงานได้โดยรวบรวมจาก Visual Studio ฉันต้องเปลี่ยนชื่อฟังก์ชันในตัวและฉันต้องเปลี่ยนวิธีการกำหนดอาร์เรย์แบบไดนามิก คำถามของฉันคือฉันจะบอกได้ไหมว่าฉัน 'ย้าย' รหัสนี้จาก UNIX เป็น Windows / Visual Studio หรือ 'porting' ใช้เฉพาะเมื่อเปลี่ยนจากภาษาโปรแกรมหนึ่งไปเป็นอีกภาษาหนึ่ง (เปลี่ยนจาก C ++ เป็น Java)

6
จำเป็นต้องทำให้โค้ดของฉันอ่านได้ง่ายขึ้นสำหรับโปรแกรมเมอร์คนอื่น ๆ ในทีมของฉัน
ฉันกำลังทำงานโครงการในเดลฟายและฉันกำลังสร้างตัวติดตั้งสำหรับแอปพลิเคชันมีสามส่วนหลัก การติดตั้ง / ถอนการติดตั้งPostgreSQL myapplication (การตั้งค่า myapplication ถูกสร้างขึ้นโดยใช้ nsi) การติดตั้ง / ถอนการติดตั้ง การสร้างตารางใน Postgres ผ่านสคริปต์ (แบตช์ไฟล์) ทุกสิ่งทำงานได้อย่างราบรื่นและราบรื่น แต่หากสิ่งที่ล้มเหลวฉันได้สร้าง LogToFileger ซึ่งจะ LogToFile ทุกขั้นตอนของกระบวนการ เช่นนี้ LogToFileToFile.LogToFile('[DatabaseInstallation] : [ACTION]:Postgres installation started'); ฟังก์ชั่นLogToFileToFile.LogToFile()นี้จะเขียนเนื้อหาไปยังไฟล์ มันใช้งานได้ดี แต่ปัญหาก็คือมันทำให้โค้ดยุ่งเหยิงเพราะมันยากที่จะอ่านโค้ดเพราะคนคนหนึ่งเห็นการLogToFileToFile.LogToFile()เรียกใช้ฟังก์ชั่นได้ทุกที่ในโค้ด ตัวอย่าง if Not FileExists(SystemDrive+'\FileName.txt') then begin if CopyFile(PChar(FilePathBase+'FileName.txt'), PChar(SystemDrive+'\FileName.txt'), False) then LogToFileToFile.LogToFile('[DatabaseInstallation] : copying FileName.txt to '+SystemDrive+'\ done') else …

6
ฉันจะเขียน HTML, CSS และ JavaScript เพื่อให้นักพัฒนาซอฟต์แวร์ส่วนหลังทำงานได้ง่ายขึ้นได้อย่างไร
เมื่อฉันได้รับการออกแบบจากนักออกแบบฉันจะได้มันเป็นไฟล์ PSD (Photoshop) ฉันคาดหวังว่าชื่อเลเยอร์และโฟลเดอร์ที่เหมาะสมมักจะเป็น PSD ที่สะอาดและมีการจัดการ จาก desigbn นี้ฉันพัฒนา HTML, CSS และ JavaScript และส่งมอบให้กับนักพัฒนาส่วนหลัง เพื่อให้ง่ายสำหรับพวกเขาที่จะเข้าใจฉัน เขียนรหัสความหมาย เก็บ JavaScript และ CSS ไว้ในไฟล์ภายนอก เพิ่มความคิดเห็นที่เป็นประโยชน์ในไฟล์ HTML, CSS และ JS ใช้สไปรต์ CSS (แม้ว่านักพัฒนาจะไม่ชอบ) ใช้แผ่นหม้อไอน้ำ HTML5 ใช้ jQuery สำหรับ JavaScript พยายามใช้แท็ก HTML5 และ CSS3 ใหม่ทุกครั้งที่ทำได้และ ส่งไฟล์ Zip ที่มี HTML, CSS, JS และรูปภาพ ฉันคาดหวังว่าหากจำเป็นต้องทำการเปลี่ยนแปลงเล็กน้อยในเค้าโครงนักพัฒนาสามารถจัดการกับสิ่งนั้นได้ ฉันต้องการรับฟังจากนักพัฒนาแบ็คเอนด์และนินจา CSS …
11 javascript  html  css  jquery 

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