त्रुटियों को "अपवाद" के रूप में क्यों नहीं बल्कि प्रोग्रामिंग भाषाओं में "त्रुटि" के रूप में नामित किया जाता है?


45

मैं उस बारे में काफी समय से सोच रहा था। मैं खुद एक देशी अंग्रेजी वक्ता नहीं हूं लेकिन फिर भी मेरे पास वर्षों का प्रोग्रामिंग अनुभव है और मैंने हमेशा मुझसे यह पूछा। इसका नाम अपवाद के रूप में क्यों रखा गया है, लेकिन त्रुटि नहीं है क्योंकि वे त्रुटियां हैं।

इसके PageNotFoundErrorबजाय हो सकता है PageNotFoundException


41
सभी असाधारण स्थितियां त्रुटियां नहीं हैं।
एंड्रयू टी फिनेल

15
यह कार को घुमाने और कार को दुर्घटनाग्रस्त करने के बीच का अंतर है।
वर्ल्ड इंजीनियर

6
क्या आप केवल विशिष्ट अपवाद वर्गों के नामकरण के बारे में बात कर रहे हैं? तो ध्यान दें कि कुछ पारिस्थितिक तंत्र में, उन कर रहे हैं कहा जाता है XYError- उदाहरण के लिए, पायथन में।

6
आपका ध्यान रखें, जावा में एक त्रुटि वर्ग है, जो कि थ्रोबेबल से विरासत में मिला है। अधिक विवरण के लिए docs.oracle.com/javase/1.4.2/docs/api/java/lang/Error.html देखें । आप "डायरेक्ट ज्ञात उपवर्ग" श्रेणी की जांच करना भी पसंद कर सकते हैं।
ल्यूसुबैल

मैं यह कहना चाहूंगा कि इस पहेली का अंग्रेजी से कोई लेना-देना नहीं है। यह जिस भी भाषा में आप प्रवीण होना चाहते हैं, उसमें तार्किक वर्गीकरण अधिक तार्किक है।
שגינתיא אבישנת

जवाबों:


59

उन्हें त्रुटियों की आवश्यकता नहीं है। तथ्य यह है कि पृष्ठ नहीं है, वास्तविक त्रुटि के बजाय सिर्फ एक दिलचस्प तथ्य हो सकता है। मुझे लगता है कि वे लगभग हर समय त्रुटियों के रूप में उपयोग किए जाते हैं। लेकिन कभी-कभी उनका उपयोग छोरों को तोड़ने के लिए किया जाता है, या आपको बता दें कि एक स्ट्रिंग एक वैध संख्या नहीं है। उनका उपयोग उपयोगी डेटा की विशाल मात्रा को पकड़ने और वापस करने के लिए किया जा सकता है - काफी सामान्य रिटर्न के हिस्से के रूप में। (कुछ भाषाएं उनके अपवादों से थोड़ी धीमी होती हैं, उस स्थिति में उन्हें बार-बार फेंकना एक बुरा विचार है।) सिद्धांत में, वैसे भी, केवल एक अपवाद का अर्थ है "सामान्य वापसी न करें, तब तक कॉल स्टैक पर जाएं जब तक आपको कोई दिलचस्पी न मिले। इसमें।"

यहां तक ​​कि एक अशक्त सूचक अपवाद भी आपके लिए बहुत मायने नहीं रखता। आप किसी और के कोड को कॉल करते हैं, और फिर एक शून्य पॉइंटर अपवाद को पकड़ते हैं क्योंकि आप जानते हैं कि यह उड़ाने के लिए उपयुक्त है, यह कहते हुए एक संदेश प्रिंट करें कि यह किसकी गलती है, और आगे बढ़ें और अपना काम पूरा करें।


27
हालांकि नियंत्रण प्रवाह के रूप में अपवाद तंत्र का उपयोग भ्रामक हो सकता है और मुझे लगता है कि आम तौर पर पर आधारित है।
ChaosPandion

11
@ChaosPandion: भाषा / संस्कृति पर निर्भर करता है।
अमारा

11
@DocBrown: मैंने एक बार एक सुडोकू सॉल्वर लिखा था जो पुनरावर्ती खोज करता है जो वर्तमान प्रयास में समाधान खोजने में विफल रहता है और एक अलग मूल्य के साथ पुन: प्रयास करता है; और जब कोई समाधान मिल जाता है, तो यह समाधान युक्त अपवाद को फेंक देता है। यहां विफलता "सामान्य" स्थिति है, और सफलता एक "असाधारण" स्थिति है; और चूंकि सॉल्वर में कई बिंदु होते हैं, जहां यह खुद को कॉल करता है, अपवाद का उपयोग किए बिना आपको यह जांचने के लिए बहुत सारे बॉयलरप्लेट लिखना होगा कि क्या एक कॉल एक सफल खोज से या एक असफल खोज से वापस आ रही है।
रेयान

5
@ फाल्कन: हाँ, आप केवल एक 'समाप्त' मान वापस कर सकते हैं, इसका मतलब है कि हर बार जब आप पुनरावृत्ति करते हैं, तो आप करने जा रहे हैं: for (...) { if (func() == finished) { return finished; } else { itfailedsocheckanother(); }}लेकिन यह देखते हुए कि कोड में कई बिंदु हैं जहां यह func () आवर्ती है, हर बार जब आप अधिक पुनरावर्तन जोड़ते हैं, तो अपवाद-कम समाधान बदसूरत हो जाता है। यही यह अनिवार्य रूप से एक भाषा में अपवाद का अनुकरण किया जाता है कि एक है पहले से ही है क्योंकि पंथ नेता कहते हैं, "तेरा अपवाद उपयोग नहीं करेगा" क्या मैं एक मालवाहक-पंथ प्रोग्रामिंग कहते हैं,।
रेयान

8
@ फाल्कन: आह ... स्टॉक "यह गोटो जैसा दिखता है" तर्क, यह कहने के लिए तर्क काम करता है कि आपको लूप का उपयोग नहीं करना चाहिए या यदि कथन या फ़ंक्शन कॉल करते हैं, क्योंकि "वे सभी गोटो की तरह दिखते हैं"। अपवाद के साथ सफलता लौटना केवल एक डब्ल्यूटीएफ है यदि आप अपवाद को त्रुटियों के साथ जोड़ रहे हैं। मेरे लिए, जब इस तरह से उपयोग किया जाता है, तो एक ट्राइ-कैच ब्लॉक "लंबी यात्रा के बाद यहां लौटने का वादा करता है" जैसा होता है, कोशिश-अपवाद + फेंक का व्यवहार फ़ंक्शन-कॉल + रिटर्न के समान है, सिवाय इसके जब आप समाधान के लिए खोज समाप्त कर लेते हैं तो बहुत लंबी यात्रा जिसमें बहुत गहरी कॉल स्टैक शामिल हो सकता है।
रेयान

21

अपवादों के तंत्र का उपयोग हमेशा त्रुटियों को इंगित करने के लिए नहीं किया जाता है। अपवादों को उन सामान्य स्थितियों से बाहर निकाल दिया जाता है जिनमें त्रुटियों सहित प्रक्रिया के लिए एक अलग कोड पथ की आवश्यकता होती है। उदाहरण के लिए, एक उपयोगकर्ता जो एक फ़ाइल का नाम प्रदान करता है जो मौजूद नहीं है, या एक संख्यात्मक क्षेत्र में एक अंक के बजाय एक पत्र में प्रवेश कर रहा है, विशेष परिस्थितियों में विशेष हैंडलिंग की आवश्यकता होती है, लेकिन ये त्रुटियां नहीं हैं।

कुछ प्रोग्रामिंग वातावरणों में, जैसे कि जावा, Error"सही त्रुटियों" की रिपोर्ट करने के लिए विशेष ऑब्जेक्ट प्रदान किए जाते हैं, ऐसी परिस्थितियां जो एक उचित एप्लिकेशन को संभालने का प्रयास नहीं करना चाहिए। इन वस्तुओं को उसी तंत्र का उपयोग करके वितरित किया जाता है जो अपवादों को वितरित करने के लिए उपयोग किया जाता है, लेकिन उनके पास अपरिवर्तनीय स्थितियों के संकेतों का एक विशेष अर्थ है।


6

मेरे पास उस की उत्पत्ति के बारे में एक व्युत्पत्ति संबंधी शोध नहीं है, लेकिन मैं समझ सकता हूं कि "त्रुटि" शब्द का उपयोग करना सभी स्थितियों में सटीक नहीं हो सकता है; जैसा कि लगभगShareShareMaster ने उल्लेख किया है, त्रुटि और अपवाद को अलग-अलग संस्थाओं के रूप में फेंकना बेहतर है।

जब आप एक उच्च-स्तरीय प्रोग्रामिंग भाषा में होते हैं, तो यह समझ में आता है कि एक अपवाद हमेशा एक त्रुटि के कारण होता है, हालांकि मैं इस बात से भी सहमत हूं कि दासब्लिंकलाइट भी एक अपवाद है, फिर भी हमेशा एक त्रुटि का परिणाम नहीं होता है। उदाहरण के लिए, मैं अपवादों का उपयोग सहयोगात्मक रूप से सूत्र समाप्त करने के लिए करता हूं।

पहली बार मैंने देखा कि "अपवाद" शब्द 80386 विधानसभा मैनुअल में था। मुझे याद है कि जब मैंने देखा तो यह सहज ही मुझे स्वाभाविक लगा। यह कहने के लिए कि एक त्रुटि सही नहीं होगी, क्योंकि विधानसभा में कोई त्रुटि नहीं है; वहाँ बस स्थितियों प्रोसेसर के साथ सौदा नहीं कर सकते हैं (यदि यह एक त्रुटि है - प्रोग्रामर, उपयोगकर्ता या सिस्टम से - ठीक है, प्रोसेसर पूरी तरह से अज्ञेय है)। मुझे नहीं पता कि इंटेल वास्तव में इस शब्द की उत्पत्ति हुई है या नहीं, लेकिन शायद ...


3

सामान्य रूप से अपवाद का उपयोग किसी ऐसी घटना को नाम देने के लिए किया जाता है जो सही नहीं है, लेकिन out_of_rangeC ++ में एक अपवाद की तरह से इसे पुनर्प्राप्त किया जा सकता है, जिसे किसी वेक्टर या सरणी में एक तत्व तक पहुंचने पर फेंक दिया जाता है जो मौजूद नहीं है। स्पष्ट रूप से ऐसी घटना सही नहीं है, लेकिन ऐसा होने का मतलब यह नहीं होना चाहिए कि आपका पूरा कार्यक्रम क्रैश हो जाए।

दूसरी ओर त्रुटियों का उपयोग आमतौर पर कुछ ऐसा करने के लिए किया जाता है जो सब कुछ दुर्घटनाग्रस्त कर दे, जैसे कि स्टैक ओवरफ्लो एक घटना का एक उदाहरण है जिसे प्रोग्राम को समाप्त करना चाहिए क्योंकि प्रोग्राम इसे आंतरिक रूप से नहीं संभाल सकता है। दूसरे शब्दों में: एक त्रुटि प्रमुख है, जबकि एक अपवाद तुलनात्मक रूप से मामूली है।


3

मुझे लगता है कि यह त्रुटि से निपटने के "विकास" के साथ अधिक है। C / C ++ के साथ (अपवाद हैंडलिंग से पहले) भाषाओं को जोड़ा गया था, यदि कोई फ़ंक्शन विफल हो गया, तो बताने का एकमात्र तरीका रिटर्न वैल्यू (जैसे HRESULTwin32) के माध्यम से था । इसलिए आमतौर पर आपने प्रत्येक फ़ंक्शन कॉल के एक्जिट कोड को पकड़ लिया और एक चेक किया। यह दृष्टिकोण कोड को गड़बड़ बनाता है। और बहुत बार डेवलपर्स इन चेकों को आलस्य से जोड़ने से बचेंगे।

अपवाद से निपटने की शुरुआत के साथ, डेवलपर्स के पास अब त्रुटि उठाने के दो विकल्प थे । इसलिए "अपवाद" शब्द का उपयोग त्रुटियों को "निकास स्थिति" त्रुटियों से अलग करने के लिए किया गया था। समय की अवधि के बाद, अपवाद हैंडलिंग त्रुटियों को प्रचारित करने का एक लोकप्रिय तरीका बन गया है क्योंकि कोड को पढ़ना, रखरखाव करना बहुत आसान है और एक ही स्थान हो सकता है जहां आपको तर्क से निपटने में त्रुटि हो सकती है।


2

पायथन में, उन्हें एबीसीसीआरआर एजी: कीइरोर, इंडेक्सइर्र नाम दिया गया है

http://docs.python.org/library/exceptions.html

इसलिए मुझे लगता है कि यह उस भाषा पर निर्भर करता है जिसका आप उपयोग करते हैं।


4
VB (क्लासिक, नॉट नेट) को न भूलें। त्रुटि पर गोटो का उपयोग किया गया था। और सभी समय का सबसे अद्भुत आविष्कार "ऑन एरर
रिज्यूमे

1
पायथन में, त्रुटियां अपवादों का एक सबसेट हैं। चार मानक अपवाद हैं जो अपवाद से प्राप्त होते हैं, लेकिन StandardError से विरासत में नहीं मिलते हैं: StopIteration, GeneratorExit, KeyboardInterrupt और SystemExit।
डिर्क होलस्पॉप

1

जब कोई त्रुटि उत्पन्न होती है, तो सिस्टम या वर्तमान में अनुप्रयोग को निष्पादित करने वाले त्रुटि के बारे में जानकारी वाले अपवाद को फेंककर इसकी रिपोर्ट करते हैं। एक बार फेंक दिए जाने पर, एक अपवाद अनुप्रयोग या डिफ़ॉल्ट अपवाद हैंडलर द्वारा नियंत्रित किया जाता है।

एक त्रुटि एक अपवाद को छोड़ती है जो त्रुटि का विवरण देती है, इसलिए सब कुछ एक त्रुटि नहीं है जो एक अपवाद है यदि यह समझ में आता है;), उदाहरण के लिए, कोई भी अनइम्प्लेमेटेक्सेप्शन एक त्रुटि नहीं होनी चाहिए, लेकिन एक अपवाद है।

http://msdn.microsoft.com/en-us/library/system.exception.aspx


0

IOS / Mac प्रोग्रामिंग में, हमारे पास एक ही भाषा में अपवाद और त्रुटियां दोनों हैं।

कम से कम उस माहौल में एक अपवाद "गैर-वसूली योग्य" है, जबकि एक त्रुटि "पुनर्प्राप्त करने योग्य" है।

उदाहरण के लिए:

  • यदि आपके पास 10 आइटमों के साथ एक सरणी है, और आप आइटम को इंडेक्स 30 पर एक्सेस करने का प्रयास करते हैं - तो यह एक अपवाद होगा। आपने अपनी प्रोग्रामिंग में गलती की।
  • यदि आप URL डाउनलोड करने का प्रयास करते हैं, लेकिन कोई इंटरनेट कनेक्शन नहीं है, तो यह अपेक्षित है और आपको उपयोगकर्ता को किसी प्रकार का संदेश प्रस्तुत करना चाहिए।

अपवाद आमतौर पर आपके एप्लिकेशन को क्रैश करते हैं, जबकि त्रुटियां आम तौर पर वापस आती हैं nilऔर एक त्रुटि ऑब्जेक्ट (संदर्भ विधि पैरामीटर द्वारा लौटाया जाता है)। आप एक कोशिश / कैच / आखिर ब्लॉक के साथ अपवादों को पकड़ सकते हैं, लेकिन यह कभी भी इस भाषा की विशेषता का उपयोग करने की अनुशंसा नहीं की जाती है - यदि किसी भी तरह से अपवाद से उबरना संभव है, तो आपको बिल्कुल अपवाद नहीं फेंकना चाहिए (आपको वापस लौटना चाहिए इसके बजाय एक त्रुटि वस्तु)।


2
ठीक है, यह पूरी तरह से अलग है कि अपवाद और त्रुटियां अन्य डेवलपर्स के लिए क्या हैं!
तारिक

हर भाषा अलग है मुझे लगता है। उद्देश्य-सी / कोको सक्रिय उपयोग में सबसे पुरानी भाषाओं में से एक है (1983 के आसपास से), इसलिए शायद यह थोड़ा पुराना है। फिर भी, यदि परिभाषा एक समुदाय से दूसरे समुदाय में बदलती है, तो यह जानना महत्वपूर्ण है।
अभि बेकर्ट

0

एक त्रुटि कुछ है जो कार्यक्रम के निष्पादन में गलत हो गई है। अक्सर यह एक अपवाद को उठाकर किया जाता है , लेकिन

  • ऐसा कुछ भी नहीं है जो एक प्रोग्रामर को एक अपवाद को बढ़ाकर त्रुटि को संभालने के लिए मजबूर करता है, और
  • ऐसा कुछ भी नहीं है जो एक प्रोग्रामर को केवल एक त्रुटि के मामले में अपवाद जुटाने के लिए मजबूर करता है।

त्रुटि एक सिमेंटिक अवधारणा है: यह प्रोग्रामर या उपयोगकर्ता द्वारा लागू किया जाता है, जो अपनी अपेक्षाओं और वास्तविकता के बीच के अंतर का वर्णन करने के लिए अपेक्षाओं के साथ कार्यक्रम में आता है। केवल एक व्यक्ति यह कह सकता है कि एक त्रुटि एक त्रुटि स्थिति में है या नहीं।

एक अपवाद एक वाक्यात्मक अवधारणा है: यह कार्यक्रम में ही कुछ है, जो उस कार्यक्रम को करने के बारे में किसी की अपेक्षाओं से स्वतंत्र है। एक रुटीन या तो कोई अपवाद नहीं करता है, चाहे कोई भी सोचता हो।


0

अपवाद और त्रुटियां अलग हैं।

अपवाद एक ऐसी स्थिति है जिसे कोई प्रोग्राम दूर कर सकता है, जैसे कि आप किसी फ़ाइल को खोलने का प्रयास करते हैं और यह मौजूद नहीं है, जबकि त्रुटियां ऐसी परिस्थितियां हैं जिनके बारे में प्रोग्राम डिस्क डिस्क या RAM विफलता की तरह कुछ भी नहीं कर सकता है।


0

अपवादों को उठाना और संभालना नियंत्रण प्रवाह की विशेषताएं हैं और अपवाद के नाम का इरादा उपयोग करना चाहिए। कोड और एपीआई के डिजाइनर को अच्छी और सुसंगत नामकरण योजनाएं ढूंढनी चाहिए।

तो आपके प्रश्न का उत्तर है: यह संदर्भ और परिप्रेक्ष्य पर निर्भर करता है।


0

अपवाद त्रुटियों के सामान्यीकरण के रूप में विकसित हुए। एक अपवाद तंत्र को शामिल करने वाली पहली प्रोग्रामिंग भाषा 1970 के दशक की शुरुआत में लिस्प थी। गेब्रियल और स्टील द्वारा ए पैटर्न ऑफ़ लैंग्वेज इवोल्यूशन में एक अच्छा सारांश है। यदि कोई त्रुटि होती है, तो प्रोग्राम के व्यवहार को निर्दिष्ट करने की आवश्यकता से अपवाद (जिसे अभी तक अपवाद नहीं कहा गया था) उत्पन्न हुआ। एक संभावना कार्यक्रम को रोकना है, लेकिन यह हमेशा मददगार नहीं है। लिस्प क्रियान्वयन परंपरागत रूप से एक त्रुटि पर डिबगर में प्रवेश करने का एक तरीका रहा है, लेकिन कभी-कभी प्रोग्रामर अपने कार्यक्रम में त्रुटि हैंडलिंग को शामिल करना चाहते थे। इसलिए 1960 के दशक के लिस्प कार्यान्वयन को यह कहने का एक तरीका था कि "ऐसा करें, और यदि कोई त्रुटि होती है, तो इसके बजाय ऐसा करें"। मूल रूप से त्रुटियों को आदिम कार्यों से आया था, लेकिन प्रोग्रामर ने प्रोग्राम के कुछ हिस्से को छोड़ने और त्रुटि हैंडलर पर कूदने के लिए जानबूझकर त्रुटि को ट्रिगर करना सुविधाजनक पाया।

1972 में, लिस्प में अपवाद से निपटने का आधुनिक रूप MacLisp में दिखाई दिया: throwऔर catchसॉफ्टवेयर संरक्षण समूह सहित जल्दी लिस्प कार्यान्वयन, पर सामग्री का एक बहुत कुछ को सूचीबद्ध डेविड मून द्वारा MACLISP संदर्भ मैनुअल संशोधन 0 । आदिम catchऔर throwitives5.3 p.43 में प्रलेखित हैं।

catchसंरचित गैर-स्थानीय निकास करने के लिए LISP फ़ंक्शन है। (catch x)मूल्यांकन करता है xऔर इसके मूल्यों को लौटाता है, सिवाय इसके कि अगर मूल्यांकन के दौरान मूल्यांकन किया x (throw y)जाना चाहिए, तो catchतुरंत yआगे के मूल्यांकन के बिना वापस आ जाता है x

catchएक एक्वाड तर्क के साथ भी इस्तेमाल किया जा सकता है, मूल्यांकन नहीं किया जाता है, जिसका उपयोग नेस्टेड कैच के बीच अंतर करने के लिए टैग के रूप में किया जाता है। (...)

throwका उपयोग catchएक संरचित गैर-बाहर निकलने वाले तंत्र के रूप में किया जाता है।

(throw x)मूल्यांकन करता है xऔर मूल्य को सबसे हाल ही में वापस फेंकता है catch

(throw x <tag>)xसबसे हाल ही में catchलेबल किए गए <tag>या बिना लेबल वाले बैक के मान को फेंकता है ।

ध्यान गैर- नियंत्रण नियंत्रण प्रवाह पर है। यह गोटो का एक रूप है (ऊपर की ओर केवल गोटो), जिसे जंप भी कहा जाता है । रूपक यह है कि कार्यक्रम का एक हिस्सा अपवाद हैंडलर पर वापस जाने के लिए मान फेंकता है, और अपवाद हैंडलर उस मान को पकड़ता है और उसे वापस करता है।

अधिकांश प्रोग्रामिंग लैंग्वेज आज टैग और वैल्यू को एक अपवाद ऑब्जेक्ट में पैक करती हैं, और एक हैंडलिंग मैकेनिज्म के साथ कैचिंग मैकेनिज्म को जोड़ती हैं।

अपवाद जरूरी त्रुटियां नहीं हैं। वे कोड के एक ब्लॉक से और आसपास के ब्लॉक से बाहर निकलने का एक तरीका हैं, अपवाद के लिए एक हैंडलर तक भागने से। क्या इस तरह की बात को सहज अर्थ में "त्रुटि" माना जाता है।

कुछ भाषाएं "त्रुटि" और "अपवाद" शब्दों के बीच अंतर करती हैं। उदाहरण के लिए, कुछ लिस्प बोलियों में throwएक अपवाद को बढ़ाने के लिए है (उपयोगकर्ताओं के लिए नियंत्रण प्रवाह, एक गैर-स्थानीय निकास को एक तरह से निष्पादित करने का मतलब है कि यह इंगित नहीं करता है कि कुछ भी "गलत" हुआ) और signalएक त्रुटि उठाने के लिए (जो इंगित करता है कि कुछ "गलत" चला गया और एक डिबग घटना को ट्रिगर कर सकता है)।


-1

आप इसे अलग-अलग प्रोग्रामिंग भाषा कार्यान्वयन में अलग-अलग व्याख्या करेंगे। जैसा कि dasblinkenlight ने कहा कि त्रुटि और अपवाद के बीच सीमांकन होने का एक जावा बिंदु है। कई प्रोग्रामिंग भाषाओं में अपवाद उल्लंघन हैं जिन्हें संभाला जा सकता है या उच्चतम संभव कोड मॉड्यूल पर पारित करने के लिए बुदबुदाया जा सकता है। त्रुटियां आम तौर पर ऐसी परिस्थितियां होती हैं, जहां आपकी भाषा के रनटाइम कंटेनर (और कई मामलों में निष्पादन को रोक दिया जाता है)।


-1

एक त्रुटि हमेशा एक त्रुटि होती है। अपवाद वर्तमान संदर्भ में एक त्रुटि है। यही है, एक अपवाद संदर्भ संवेदनशील है। एक अपवाद का एक उदाहरण एक एएससी "ए" को पूर्णांक "1" में जोड़ना होगा। "+!" जैसे अपरिभाषित ऑपरेटर का उपयोग करने में त्रुटि हो सकती है! अधिकांश भाषाओं में।

कुछ लैंगुग आपको स्थिति से बाहर अपना रास्ता निर्धारित करने की अनुमति देंगे यदि वास्तव में आप क्या करना चाहते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.