ข้อผิดพลาด VS 2010 Test Runner“ กระบวนการตัวแทนหยุดลงในขณะที่กำลังดำเนินการทดสอบ”


101

ใน Visual Studio 2010 ฉันมีการทดสอบหน่วยจำนวนหนึ่ง เมื่อฉันทำการทดสอบหลายรายการพร้อมกันโดยใช้รายการทดสอบบางครั้งฉันก็พบข้อผิดพลาดต่อไปนี้สำหรับการทดสอบอย่างน้อยหนึ่งรายการ:

กระบวนการตัวแทนหยุดทำงานในขณะที่กำลังดำเนินการทดสอบ

ไม่มีการทดสอบเดิมที่ล้มเหลวและถ้าฉันพยายามเรียกใช้การทดสอบอีกครั้งมันก็สำเร็จ

ฉันพบรายงานข้อบกพร่องนี้ใน Connectซึ่งดูเหมือนว่าจะเป็นปัญหาเดียวกัน แต่ไม่มีวิธีแก้ไข

มีใครเห็นพฤติกรรมนี้อีกหรือไม่? ฉันจะหลีกเลี่ยงได้อย่างไร?

แก้ไข

ฉันยังคงพบข้อบกพร่องนี้และเพื่อนร่วมงานหลายคนก็ใช้การตั้งค่าซอฟต์แวร์ / ฮาร์ดแวร์เดียวกัน ฉันได้ประเมินคำตอบแล้ว แต่ยังไม่สามารถแก้ปัญหาได้ ฉันกำลังเริ่มต้นความโปรดปรานสำหรับการแก้ปัญหานี้


ฉันได้รับสิ่งเดียวกัน ฉันกำลังขุดคุ้ย แต่ก็ยังไม่มีทางแก้
มาระโก

มีข่าวเกี่ยวกับเรื่องนี้ไหม ปัญหาเดียวกันที่นี่ ...
Peter Gfader

@ ปีเตอร์ดูความคิดเห็นของฉันด้านล่างคำตอบที่ยอมรับ นั่นเป็นวิธีแก้ปัญหาของฉัน แต่ฉันไม่รู้ว่าปัญหาของคุณคล้ายกันหรือไม่
ฝนตก

ฉันมีพฤติกรรมเดียวกันโดยไม่มีข้อยกเว้น ข้อยกเว้นสามารถมองเห็นได้สำหรับฉันเมื่อฉันเรียกใช้ Visual Studio บนเซิร์ฟเวอร์การสร้างและได้รับ Assert-Window เนื่องจากหน้าต่างยืนยันการทดสอบไม่สามารถดำเนินต่อไปได้

คำตอบ:


41

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

ตอนนี้ฉันไม่รู้ว่าจะเอาชนะสิ่งนี้ได้อย่างไร


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

6
ฉันไม่มีตัวสุดท้าย / ตัวทำลายในรหัสของฉัน ... ~ MyClass () และได้รับข้อผิดพลาดเดียวกัน การทดสอบด้วย Resharper เป็นสีเขียวทั้งหมด
Peter Gfader

6
ปัญหาเกี่ยวกับข้อยกเว้นที่ไม่สามารถจับได้ใน Finalizers เป็นกรณีพิเศษของข้อยกเว้นที่ไม่ถูกจับได้ในงานเบื้องหลังซึ่งสามารถเริ่มต้นหรือกำหนดเวลาได้ (อาจโดยปริยาย) โดยการทดสอบบางอย่างและสามารถดำเนินการต่อได้แม้ว่าการทดสอบจะเสร็จสิ้นแล้วก็ตาม
satorg

1
เช่นเดียวกับปีเตอร์นักวิ่งทดสอบ Resharper ให้สีเขียวทั้งหมดแก่ฉัน นักวิ่งทดสอบ VS 2010 ล้มเหลวในชั้นเรียนด้วยตัวทำลาย
RyBolt

1
ฉันได้เข้ารหัสการวนซ้ำแบบไม่สิ้นสุดโดยไม่ได้ตั้งใจในเมธอด Dispose () ของฉันซึ่งทำให้เกิดสิ่งนี้เช่นกัน
Robert

88

ข้อความนี้เกิดจากข้อยกเว้นบนเธรดที่แตกต่างจากเธรดทดสอบการรันข้อยกเว้นในการที่แตกต่างกันด้ายจากหัวข้อการทดสอบการดำเนินการคำตอบทั้งหมดจนถึงตอนนี้คำอธิบายง่ายๆนี้ เป็นข้อบกพร่องที่ทราบแล้วใน Visual Studio ที่จะไม่แสดงข้อมูลที่สมเหตุสมผลในกรณีนั้น

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


สิ่งเดียวกันก็เกิดขึ้นกับฉันเช่นกัน - การทดสอบของฉันกำลังวางไข่เธรดแยกต่างหากซึ่งได้รับข้อยกเว้น การจับข้อยกเว้นภายในเธรดอย่างน้อยก็ทำให้ฉันสามารถพิมพ์ได้และรู้ว่าเกิดอะไรขึ้น อย่างไรก็ตามระวังอย่าใส่ Assert.Fail () ในบล็อก catch ของเธรดซึ่งทำให้เกิดข้อยกเว้นแยกต่างหากซึ่งจะทำให้คุณกลับไปที่จุดเริ่มต้น
Kyle Krull

4
สิ่งเดียวกันสำหรับฉันยกเว้น stack overflow ซึ่งยากกว่ามากในการติดตามใน C # เมื่อเทียบกับ java ...
John Gardner

อันที่จริงฉันสังเกตเห็นสิ่งนี้เกิดขึ้นเมื่อฉันเริ่มใช้วัตถุ Thread และเรียก Abort () เพื่อหยุดสิ่งเหล่านี้
espaciomore

1
นอกจากนี้ยังเกิดขึ้นเมื่อasync voidวิธีการที่เรียกในระหว่างการทดสอบมีข้อยกเว้น
Mathias Becher

1
โปรดทราบว่า trx อาจมีข้อมูลข้อผิดพลาดคุณสามารถดูได้โดยการเปิดในโปรแกรมแก้ไขข้อความหรือใน Visual Studio แล้วคลิกไฮเปอร์ลิงก์ทดสอบการรันข้อผิดพลาดในหน้าต่างผลการทดสอบ
Ohad Schneider

16

ฉันประสบปัญหานี้และกลายเป็นปัญหาในโค้ดของฉันซึ่ง Test Framework ไม่สามารถตรวจจับได้อย่างถูกต้อง การปรับโครงสร้างใหม่โดยบังเอิญเล็กน้อยทำให้ฉันมีรหัสนี้:

public void GetThingy()
{
    this.GetThingy();
}

แน่นอนว่านี่เป็นการเรียกซ้ำที่ไม่สิ้นสุดและทำให้เกิด StackOverflowException (ฉันเดา) สิ่งนี้ทำให้เกิดความกลัว: "กระบวนการตัวแทนหยุดลงในขณะที่กำลังดำเนินการทดสอบ"

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


3
นี่ไม่ใช่ปัญหา (ฉันรู้เพราะมันเป็นการทดสอบที่แตกต่างกันซึ่งล้มเหลวในแต่ละครั้ง) แต่ขอขอบคุณที่สละเวลาตอบ
แห้ง

6
+1 เนื่องจากนี่เป็นหนึ่งในคำตอบที่ถูกต้องสำหรับปัญหานี้ ข้อยกเว้น SO ในเมธอด sstatic บนหนึ่งในคลาสของฉันทำให้เกิดปัญหานี้
Peter T. LaComb Jr.

6
+1 ผมก็เคยเห็นเช่นกัน การดีบักการทดสอบ (ใน VS 11) พบปัญหาได้อย่างรวดเร็ว
Jeremy McGee

เห็นด้วยกับ Jeremy หากคุณดีบักการทดสอบหน่วยควรหยุดเมื่อเกิดข้อยกเว้น อย่างไรก็ตามหากคุณเรียกใช้การทดสอบหน่วยทั้งหมดจะมีไฟสีเขียว แปลกมาก
Andrew Stephens

8

ฉันสามารถค้นหาต้นตอของปัญหาของฉันได้โดยดูในไฟล์ผลการทดสอบ (/TestResults/*.trx) ซึ่งให้รายละเอียดทั้งหมดของข้อยกเว้นที่เกิดขึ้นในเธรดพื้นหลังและเมื่อฉันแก้ไขข้อยกเว้นดังกล่าวแล้ว "ตัวแทนดำเนินการ หยุด ... "ข้อผิดพลาดหายไป

ในกรณีของฉันฉันเปิดตัว GUI โดยไม่ได้ตั้งใจในการทดสอบหน่วยของฉันซึ่งในที่สุดก็ทำให้เกิด System.ComponentModel.InvalidAsynchronousStateException

ดังนั้นไฟล์. trx ของฉันจึงมี:

   <RunInfo computerName="DT-1202" outcome="Error" timestamp="2013-07-29T13:52:11.2647907-04:00">
    <Text>One of the background threads threw exception: 
System.ComponentModel.InvalidAsynchronousStateException: An error occurred invoking the method.  The destination thread no longer exists.
at System.Windows.Forms.Control.WaitForWaitHandle(WaitHandle waitHandle)
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.Invoke(Delegate method)
...
</Text>
  </RunInfo>

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


5

โดยทั่วไปข้อความนี้จะถูกสร้างขึ้นเมื่อกระบวนการทดสอบหยุดทำงานและอาจเกิดขึ้นได้เมื่อมีข้อยกเว้นที่ไม่สามารถจัดการได้บนเธรดพื้นหลังเกิดสแตกล้นหรือมีการเรียกProcess.GetCurrentProcess().Kill()หรือEnvironment.Exitหรือสาเหตุที่เป็นไปได้อีกประการหนึ่งคือการละเมิดการเข้าถึงในโค้ดที่ไม่มีการจัดการ

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


4

ในกรณีของการแก้ปัญหาได้รับการแก้ไขโดยการตรวจสอบหน้าต่างออก

'QTAgent32.exe' (จัดการ (v4.0.30319)): โหลด 'C: \ TestResults \ bdewey_XXXXXX072 2011-01-11 17_00_40 \ Out \ MyCode.dll', โหลดสัญลักษณ์แล้ว E, 9024, 9, 2011/01/11, 17: 00: 46.827, XXXXX072 \ QTAgent32.exe, Unhandled Exception Caught, การรายงานผ่านวัตสัน: [ข้อความยกเว้น]

ในกรณีของฉันฉันมี FileSystemWatcher ที่ส่งข้อผิดพลาดในเธรดแยกต่างหาก


คุณแก้ปัญหาอย่างไร ฉันใช้โค้ดตัวอย่างจาก M $ ที่รวม FileSystemWatcher ในบริการและสร้างเวิร์กโฟลว์ WF รอบ ๆ นั้น ฉันได้รับสิ่งเหล่านี้มากมาย ...
ekkis

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

3

ฉันพบปัญหาเดียวกันและแก้ไขได้ในขณะที่นำออก

Environment.Exit(0);

ดังนั้นฉันค่อนข้างแน่ใจว่าข้อผิดพลาดนี้เกิดขึ้นในขณะที่การทดสอบหรือวิธีการของคุณอยู่ระหว่างการทดสอบทำให้กระบวนการดำเนินการสิ้นสุดลง


2

ขอบคุณที่โพสต์คำถาม ฉันเพิ่งพบปัญหานี้และหาสาเหตุที่คุณอาจพบเจอ

อาจเกิดข้อยกเว้นแบบอะซิงโครนัส

ในระหว่างการตั้งค่าการทดสอบของฉันฉันสร้างอ็อบเจ็กต์ที่จัดคิวเธรดผู้ปฏิบัติงานในเธรดพูล หากฉันทำงานผ่านการดีบักเร็วพอที่รหัสของฉันจะผ่านไป

หากเธรดผู้ปฏิบัติงานเริ่มต้นและมีข้อผิดพลาดก่อนที่การตั้งค่าการทดสอบจะเสร็จสิ้นฉันจะได้รับผลลัพธ์ของการยกเลิกโดยไม่มีเหตุผล

หากเธรดผู้ปฏิบัติงานเริ่มต้นและมีข้อผิดพลาดหลังจากการทดสอบเริ่มขึ้นฉันจะได้รับผลลัพธ์ของ: ข้อผิดพลาด - กระบวนการตัวแทนหยุดลงในขณะที่กำลังดำเนินการทดสอบ

สิ่งสำคัญที่ควรทราบ: นี่เป็นส่วนประกอบที่ฉันใช้ตลอดการทดสอบหลายครั้ง หากกรอบการทดสอบพบข้อผิดพลาดเหล่านี้มากเกินไปก็จะยกเลิกการทดสอบที่เหลือ

หวังว่านี่จะช่วยได้


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

2

ฉันเพิ่มบล็อก try / catch ให้กับ descructor ~ ClassName () {} ที่กำหนดไว้ในคลาสใด ๆ ที่เกี่ยวข้องกับการทดสอบของฉัน สิ่งนี้ช่วยแก้ปัญหาให้ฉันได้

~MyClass()
{
    try
    {
        // Some Code
    }
    catch (Exception e)
    {
        // Log the exception so it's not totally hidden
        // Console.WriteLine(e.ToString());
    }
}

2

หากต้องการทราบว่ามีข้อยกเว้นเกิดขึ้นที่ใดให้คลิกที่ไฮเปอร์ลิงก์ "Test Run Error" ถัดจากไอคอนอัศเจรีย์ในหน้าต่างผลการทดสอบ หน้าต่างที่มีการติดตามสแต็กถูกเปิดขึ้น

สิ่งนี้ช่วยได้มากในการติดตามข้อผิดพลาด!


1

ฉันมีปัญหาเดียวกันและเกิดจากโปรแกรมปิดท้ายสำหรับทรัพยากรที่ไม่มีการจัดการ (ตัวเขียนไฟล์ที่ไม่ได้รับการกำจัดอย่างเหมาะสมด้วยเหตุผลบางประการ)

หลังจากตัดรหัส Finalizer ในการลองจับที่กลืนข้อยกเว้นปัญหาก็หายไป ฉันไม่แนะนำให้กลืนข้อยกเว้นเช่นนั้นดังนั้นจึงเป็นการฉลาดที่จะหาสาเหตุที่ข้อยกเว้นเกิดขึ้นตั้งแต่แรก


1

ฉันมีเหตุการณ์นี้เกิดขึ้นในโอกาสแปลก ๆ และผู้ร้ายมักจะกลายเป็นเธรด

การทดสอบทั้งหมดน่าแปลกมากพอที่จะทำงานได้ดีบนเครื่องพัฒนาจากนั้นสุ่มล้มเหลวในเซิร์ฟเวอร์บิลด์

จากการตรวจสอบอย่างใกล้ชิดปรากฎว่าแม้ว่าการทดสอบจะถูกระบุว่าส่งผ่านในกล่อง dev แต่ก็มีข้อยกเว้นที่เกิดขึ้น มีการโยนข้อยกเว้นในเธรดแยกต่างหากซึ่งไม่ได้รับเป็นข้อผิดพลาด

รายละเอียดข้อยกเว้นถูกบันทึกเทียบกับการติดตามการทดสอบดังนั้นเราจึงสามารถระบุได้ว่าโค้ด / การทดสอบใดที่ต้องแก้ไข

หวังว่านี่จะช่วยใครบางคนได้


0

ในกรณีของฉันฉันมีการทดสอบหน่วยสำหรับบริการ WCF บริการ WCF นี้เริ่มต้นขึ้น 2 ตัวจับเวลา
ตัวจับเวลาเหล่านั้นก่อให้เกิดผลข้างเคียง
-> ฉันปิดใช้งานตัวจับเวลาเหล่านี้โดยค่าเริ่มต้นและทุกอย่างเรียบร้อยดี!

BTW: ฉันใช้WCFMockเพื่อปลอมบริการ WCF ดังนั้นฉันจึงมีการทดสอบหน่วย "จริง" ในบริการ WCF ของฉัน


0

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


0

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

ฉันสงสัยว่าปัญหาอาจเกิดจาก dll จากโปรเจ็กต์อื่นของฉันมาจากโปรเจ็กต์ Visual Studio 2012 และฉันกำลังเรียกใช้การทดสอบของฉันในโปรเจ็กต์ VS2010 และ / หรืออาจเป็นไปได้ว่าเวอร์ชัน dll ของ UnitTestFramwork จาก 2 โปรเจ็กต์ไม่ตรงกัน



0

เนื่องจากข้อผิดพลาดนี้อาจมีสาเหตุหลายประการฉันจึงต้องการเพิ่มอีกข้อเพื่อความสมบูรณ์ของเธรดนี้

หากการทดสอบทั้งหมดของคุณล้มเหลวตามที่ OP อธิบายไว้สาเหตุอาจเกิดจากการกำหนดค่าโครงการไม่ถูกต้อง ในกรณีของฉันกรอบงานเป้าหมายถูกตั้งค่าเป็น. NET Framework 3.5 การตั้งค่าเป็นเวอร์ชันที่สูงขึ้นผ่านหน้าคุณสมบัติโครงการ (แท็บแอปพลิเคชัน ) ช่วยแก้ปัญหาได้


0

ผมสามารถที่จะตรวจสอบสิ่งที่ก่อให้เกิดปัญหาของฉันโดยการมองในแฟ้มบันทึกของ Windows > แอพลิเคชันรายการบันทึกในเหตุการณ์ของ Windows มองหารายการในขณะที่การทดสอบระเบิดออก ฉันมีรายการข้อผิดพลาดคล้ายกับด้านล่าง:

QTAgent32_40.exe, PID 10432, Thread 2) AgentProcess:CurrentDomain_UnhandledException: IsTerminating : System.NullReferenceException: Object reference not set to an instance of an object.
   at XXX.YYY.ZZZ.cs:line 660
   at XXX.YYY.AAA.Finalize() in C:\JenkinsSlave\workspace\XXX.YYY.AAA.cs:line 180

มันเป็นข้อยกเว้นการอ้างอิงที่เป็นโมฆะภายในเมธอดที่เรียกจากคลาส Finalizer


0

สำหรับใครก็ตามที่เกิดคำถามเก่า ๆ นี้และสงสัยว่ามีอะไรถูกโยนออกไปจากกระทู้ของพวกเขานี่คือเคล็ดลับ การใช้ Task.Run (ซึ่งตรงข้ามกับการพูด Thread.Start) จะรายงานข้อยกเว้นเธรดย่อยที่น่าเชื่อถือมากขึ้น ในระยะสั้นแทนที่จะเป็นสิ่งนี้:

Thread t = new Thread(FunctionThatThrows);
t.Start();
t.Join();

ทำเช่นนี้:

Task t = Task.Run(() => FunctionThatThrows());
t.Wait();

และบันทึกข้อผิดพลาดของคุณน่าจะมีประโยชน์มากกว่านี้

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