क्या संकलन के दौरान एक पुस्तकालय पर एक कार्यक्रम निर्भर हो सकता है लेकिन रनटाइम नहीं?


110

मैं रनटाइम और संकलन-समय के बीच के अंतर को समझता हूं और दोनों के बीच अंतर कैसे करता हूं, लेकिन मुझे अभी संकलन-समय और रनटाइम निर्भरता के बीच अंतर करने की आवश्यकता नहीं है ।

मैं इस पर घुट रहा हूं: एक कार्यक्रम रनटाइम के दौरान किसी चीज पर निर्भर नहीं हो सकता है कि यह संकलन के दौरान निर्भर था? यदि मेरा जावा ऐप log4j का उपयोग करता है, तो उसे संकलन करने के लिए log4j.jar फ़ाइल की आवश्यकता है (मेरा कोड log4j के अंदर से सदस्य विधियों को एकीकृत करने और इनवॉइस करने के लिए) और साथ ही रनटाइम (मेरा कोड log4j के अंदर क्या कोड है, इस पर कोई नियंत्रण नहीं है। .जर भाग गया)।

मैं आईवी और मावेन जैसे निर्भरता रिज़ॉल्यूशन टूल पर पढ़ रहा हूं, और ये उपकरण स्पष्ट रूप से इन दो प्रकार की निर्भरताओं के बीच अंतर करते हैं। मुझे अभी इसकी आवश्यकता समझ में नहीं आई है।

क्या कोई सरल, "किंग्स इंग्लिश" -प्रश्न स्पष्टीकरण दे सकता है, अधिमानतः एक वास्तविक उदाहरण के साथ जो मेरे जैसा एक गरीब भी समझ सकता है?


2
आप प्रतिबिंब का उपयोग कर सकते हैं, और उन कक्षाओं का उपयोग कर सकते हैं जो संकलन समय पर उपलब्ध नहीं थे। "प्लगइन" सोचो।
प्रति अलेक्जेंडरसन

जवाबों:


64

एक संकलन-समय निर्भरता आम तौर पर रनटाइम पर आवश्यक है। मावेन में, एक compileस्कोप की निर्भरता रनटाइम पर क्लासपाथ में जोड़ दी जाएगी (उदाहरण के लिए युद्धों में उन्हें WEB-INF / lib में कॉपी किया जाएगा)।

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

फ्रिंज मामले हो सकते हैं जहां परियोजना को संकलित करने के लिए एक निश्चित निर्भरता की आवश्यकता होती है, लेकिन फिर संबंधित कोड की वास्तव में आवश्यकता नहीं होती है, लेकिन ये दुर्लभ होंगे।

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

प्रतिबिंब का उपयोग करके संकलन-समय की निर्भरता से बचा जा सकता है। उदाहरण के लिए, एक JDBC ड्राइवर को एक लोड किया जा सकता है Class.forNameऔर वास्तविक फ़ाइल लोड की जाने वाली कॉन्फ़िगरेशन फ़ाइल के माध्यम से कॉन्फ़िगर की जा सकती है।


17
जावा ईई एपीआई के बारे में - क्या "प्रदान की गई" निर्भरता गुंजाइश नहीं है?
केविन

15
एक उदाहरण जहां एक निर्भरता को संकलित करने की आवश्यकता होती है लेकिन रनटाइम पर आवश्यक नहीं है lombok (www.projectlombok.org)। जार का उपयोग संकलन समय पर जावा कोड को बदलने के लिए किया जाता है, लेकिन रनटाइम के दौरान इसकी आवश्यकता नहीं होती है। निर्दिष्ट गुंजाइश "प्रदान" जार को युद्ध / जार में शामिल नहीं करने का कारण बनता है।
केविन

2
@ केविन हां, अच्छी बात है, providedगुंजाइश इस उम्मीद पर एक रनटाइम निर्भरता को जोड़े बिना एक संकलन समय निर्भरता को जोड़ती है कि निर्भरता को अन्य साधनों (जैसे कंटेनर में एक साझा पुस्तकालय) द्वारा रनटाइम पर प्रदान किया जाएगा। runtimeदूसरी ओर यह एक संकलन समय निर्भरता बनाए बिना एक रनटाइम निर्भरता जोड़ता है।
अर्टफेक्टो

तो क्या यह कहना सुरक्षित है कि आमतौर पर आपके प्रोजेक्ट रूट के तहत "मॉड्यूल कॉन्फ़िगरेशन" (आइवीवाई शर्तों का उपयोग करके) और प्रमुख निर्देशिका के बीच 1: 1 सहसंबंध है? उदाहरण के लिए, मेरे सभी JUnit परीक्षण जो JUnit JAR पर निर्भर करते हैं, परीक्षण / रूट आदि के तहत होंगे। मैं यह नहीं देखता कि समान स्रोत रूट के तहत पैक की गई समान कक्षाएं, अलग-अलग पर निर्भर करने के लिए "कॉन्फ़िगर" कैसे हो सकती हैं। किसी भी समय जार। यदि आपको log4j की आवश्यकता है, तो आपको log4j की आवश्यकता है; 1 कॉन्‍फ़‍िगर के तहत log4j कॉल को इन्वाइट करने के लिए समान कोड बताने का कोई तरीका नहीं है, लेकिन कुछ "नॉन-लॉगिंग" कॉन्‍फ़िगरेशन के तहत log4j कॉल्‍स को नजरअंदाज करने के लिए, सही?
IAmYourFaja

30

प्रत्येक मावेन निर्भरता में एक गुंजाइश होती है जो निर्भर करती है कि कौन सी क्लासपैथ निर्भरता पर उपलब्ध है।

जब आप किसी प्रोजेक्ट के लिए JAR बनाते हैं, तो निर्भरताएँ उत्पन्न की गई कलाकृतियों से नहीं बाँधी जाती हैं; उनका उपयोग केवल संकलन के लिए किया जाता है। (हालांकि, आप अभी भी मावेन को निर्मित जार में निर्भरता शामिल कर सकते हैं, देखें: मावेन के साथ जार में निर्भरता शामिल करें )

जब आप WAR या EAR फ़ाइल बनाने के लिए मावेन का उपयोग करते हैं, तो आप मावेन को उत्पन्न की गई कलाकृतियों के साथ निर्भरता को बंडल करने के लिए कॉन्फ़िगर कर सकते हैं, और आप इसे दिए गए दायरे का उपयोग करके WAR फ़ाइल से कुछ निर्भरता को बाहर करने के लिए भी कॉन्फ़िगर कर सकते हैं।

सबसे आम स्कोप - कंपाइल स्कोप - यह दर्शाता है कि कंपाइल क्लासपाथ, यूनिट टेस्ट कंपाइल और एक्ज़ीक्यूशन क्लासपाथ पर आपके प्रोजेक्ट के लिए डिपेंडेंसी उपलब्ध है, और जब आप अपने एप्लिकेशन को निष्पादित करते हैं तो अंतिम रनटाइम क्लासपाथ। एक जावा ईई वेब एप्लिकेशन में, इसका मतलब है कि निर्भरता को आपके तैनात एप्लिकेशन में कॉपी किया जाता है। हालाँकि .jar फ़ाइल में, निर्भरता को कंपाइल स्कोप के साथ शामिल नहीं किया जाएगा।

रनटाइम स्कोप इंगित करता है कि इकाई परीक्षण निष्पादन और रनटाइम निष्पादन क्लासपैथ पर आपकी परियोजना के लिए निर्भरता उपलब्ध है, लेकिन संकलन गुंजाइश के विपरीत यह तब उपलब्ध नहीं होता है जब आप अपने आवेदन या इसके इकाई परीक्षणों का संकलन करते हैंआपके पोस्ट किए गए एप्लिकेशन में एक रनटाइम डिपेंडेंसी की नकल की जाती है, लेकिन यह संकलन के दौरान उपलब्ध नहीं है! यह सुनिश्चित करने के लिए अच्छा है कि आप गलती से किसी विशिष्ट पुस्तकालय पर निर्भर नहीं हैं।

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


@ कोरे तुगे उत्तर अधिक सटीक है :) मेरे पास त्वरित प्रश्न है कि मेरे पास एक भरोसेमंद जार w / रन समय की गुंजाइश है। क्या मावेन संकलन समय पर जार की तलाश करेगा?
gks

@ नहीं, यह संकलन समय में इसकी आवश्यकता नहीं है।
कोरय तुगय

9

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

कई पुस्तकालयों, बदले में अन्य पुस्तकालयों की जरूरत है। इन पुस्तकालयों को संकलन के समय की आवश्यकता नहीं है, लेकिन रनटाइम पर इनकी आवश्यकता है। जब कोड वास्तव में चलाया जाता है।


क्या आप हमें ऐसे पुस्तकालयों के उदाहरण दे सकते हैं, जिन्हें संकलन की आवश्यकता नहीं है, लेकिन रनटाइम पर इसकी आवश्यकता होगी?
क्रिस्टियानो

1
@ क्रिसटन सभी JDBC लाइब्रेरी इस तरह से हैं। साथ ही पुस्तकालय जो एक मानक एपीआई को लागू करते हैं।
पीटर लॉरी

4

आम तौर पर आप सही हैं और संभावित रूप से यह आदर्श स्थिति है यदि रनटाइम और संकलन समय निर्भरता समान हैं।

यह नियम गलत होने पर मैं आपको 2 उदाहरण दूंगा।

यदि क्लास A क्लास B पर निर्भर करता है जो क्लास C पर निर्भर करता है जो क्लास D पर निर्भर करता है, जहाँ A आपकी क्लास है और B, C और D अलग-अलग थर्ड पार्टी लाइब्रेरी से क्लासेस हैं, तो आपको केवल संकलन के समय B और C की आवश्यकता होती है और आपको D की भी आवश्यकता होती है क्रम। अक्सर प्रोग्राम डायनामिक क्लास लोडिंग का उपयोग करते हैं। इस मामले में आपको लाइब्रेरी द्वारा गतिशील रूप से लोड की गई कक्षाओं की आवश्यकता नहीं है जो आप संकलन समय पर उपयोग कर रहे हैं। इसके अलावा अक्सर पुस्तकालय चुनता है कि रनटाइम में किस कार्यान्वयन का उपयोग करना है। उदाहरण के लिए SLF4J या कॉमन्स लॉगिंग रनटाइम पर लक्ष्य लॉग कार्यान्वयन को बदल सकते हैं। आपको संकलन समय पर केवल SSL4J की आवश्यकता है

जब आप रनटाइम की तुलना में संकलन समय पर अधिक निर्भरता की आवश्यकता के विपरीत उदाहरण देते हैं। यह सोचें कि आप ऐसा एप्लिकेशन विकसित कर रहे हैं जिसे विभिन्न वातावरणों या ऑपरेटिंग सिस्टम पर काम करना है। आपको संकलित समय पर सभी प्लेटफ़ॉर्म विशिष्ट पुस्तकालयों की आवश्यकता है और रनटाइम पर वर्तमान वातावरण के लिए केवल पुस्तकालयों की आवश्यकता है।

मुझे आशा है कि मेरे स्पष्टीकरण से मदद मिलेगी।


क्या आप इस बात पर विस्तृत चर्चा कर सकते हैं कि आपके उदाहरण में संकलन समय पर C की आवश्यकता क्यों है? मुझे आभास मिलता है ( stackoverflow.com/a/7257518/6095334 से ) कि संकलन के समय C की आवश्यकता है या नहीं, यह निर्भर करता है कि क्या तरीके और फ़ील्ड (B से) A संदर्भित है।
२३:१६ पर हर्वियन

3

आमतौर पर, स्थिर निर्भरता ग्राफ गतिशील एक का उप-ग्राफ होता है, उदाहरण के लिए ND निर्भर के लेखक से यह ब्लॉग प्रविष्टि देखें

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


2

बस एक मुद्दे में भाग गया जो आपके प्रश्न का उत्तर देता है। servlet-api.jarमेरी वेब परियोजना में एक क्षणिक निर्भरता है और संकलन समय और क्रम दोनों पर इसकी आवश्यकता है। लेकिन servlet-api.jarमेरी टॉमकैट लाइब्रेरी में भी शामिल है।

यहाँ समाधान servlet-api.jarकेवल संकलन के समय मावेन में उपलब्ध कराना है और मेरी युद्ध फाइल में पैक नहीं किया गया है ताकि यह servlet-api.jarमेरी टॉमकैट लाइब्रेरी में निहित न हो ।

मुझे उम्मीद है कि यह संकलन समय और रनटाइम निर्भरता की व्याख्या करता है।


3
आपका उदाहरण वास्तव में दिए गए प्रश्न के लिए गलत है, क्योंकि यह बीच compileऔर providedस्कोप के बीच का अंतर बताता है और न कि बीच compileका runtimeCompile scopeसंकलन के समय दोनों की आवश्यकता होती है और इसे आपके ऐप में पैक किया जाता है। Provided scopeकेवल संकलन के समय की आवश्यकता होती है, लेकिन आपके एप्लिकेशन कारण में इसे पैक नहीं किया जाता है क्योंकि यह अन्य माध्यमों द्वारा प्रदान किया जाता है, उदाहरण के लिए यह पहले से ही टॉमटैट सर्वर में है।
MJar

1
खैर, मुझे लगता है कि यह एक अच्छा उदाहरण है क्योंकि सवाल संकलन-समय और रनटाइम निर्भरता के बारे में था compileऔर runtime स्कोप के बारे में नहीं । providedगुंजाइश रास्ता maven हैंडल मामले में जहां एक संकलन समय निर्भरता क्रम पैकेज में शामिल नहीं किया जाना चाहिए है।
क्रिश्चियन गाव्रोन

1

मैं रनटाइम और संकलन-समय के बीच के अंतर को समझता हूं और दोनों के बीच अंतर कैसे करता हूं, लेकिन मुझे अभी संकलन-समय और रनटाइम निर्भरता के बीच अंतर करने की आवश्यकता नहीं है।

सामान्य संकलन-समय और रनटाइम अवधारणाएं और मावेन विशिष्ट compileऔर runtimeगुंजाइश निर्भरताएं दो बहुत अलग चीजें हैं। आप सीधे उनकी तुलना नहीं कर सकते क्योंकि इनमें समान फ्रेम नहीं है: सामान्य संकलन और रनटाइम अवधारणाएं व्यापक हैं, जबकि मावेन compileऔर runtimeगुंजाइश अवधारणाएं समय के अनुसार विशेष रूप से निर्भरता उपलब्धता / दृश्यता के बारे में हैं: संकलन या निष्पादन।
मत भूलो कि मावेन सभी एक javac/ javaआवरण से ऊपर है और जावा में आपके पास एक संकलन समय क्लासपाथ है जिसे आप निर्दिष्ट करते हैं javac -cp ... और एक रनटाइम क्लासपैथ जिसे आप निर्दिष्ट करते हैं java -cp ...। जावा कंपाइल और रनटाइम टेंपरेचर (दोनों में एक निर्भरता जोड़ने के तरीके के रूप
में मावेन compileगुंजाइश पर विचार करना गलत नहीं होगा )javacऔर java) जबकि मावेन runtimeगुंजाइश को केवल जावा रनटाइम क्लासपैथ ( javac) में एक निर्भरता जोड़ने के तरीके के रूप में देखा जा सकता है ।

मैं इस पर मज़ाक कर रहा हूं: कोई प्रोग्राम रनटाइम के दौरान किसी चीज़ पर निर्भर नहीं रह सकता है जो कि संकलन के दौरान उस पर निर्भर था?

आप जो वर्णन करते हैं उसका कोई संबंध नहीं है runtimeऔर compileगुंजाइश नहीं है।
यह उस providedदायरे की तरह दिखता है जो आप एक निर्भरता के लिए निर्दिष्ट करते हैं कि वह संकलन के समय पर निर्भर हो लेकिन रनटाइम पर नहीं।
आप इसे संकलन के लिए निर्भरता की आवश्यकता के रूप में उपयोग करते हैं लेकिन आप इसे पैक किए गए घटक (JAR, WAR या किसी अन्य) में शामिल नहीं करना चाहते हैं क्योंकि निर्भरता पहले से ही पर्यावरण द्वारा प्रदान की जाती है: इसे सर्वर या किसी भी में शामिल किया जा सकता है जावा अनुप्रयोग के रूप में निर्दिष्ट क्लासपाथ का पथ।

यदि मेरा जावा ऐप log4j का उपयोग करता है, तो उसे संकलन करने के लिए log4j.jar फ़ाइल की आवश्यकता है (मेरा कोड log4j के अंदर से सदस्य विधियों को एकीकृत करने और इनवॉइस करने के लिए) और साथ ही रनटाइम (मेरा कोड log4j के अंदर क्या कोड है, इस पर कोई नियंत्रण नहीं है। .जर भाग गया)।

इस मामले में हाँ। लेकिन मान लीजिए कि आपको एक पोर्टेबल कोड लिखने की ज़रूरत है जो log4j के सामने फीके के रूप में slf4j पर निर्भर करता है जो बाद में किसी अन्य लॉगिंग कार्यान्वयन (log4J 2, लॉगबैक या किसी अन्य) पर स्विच करने में सक्षम हो।
इस स्थिति में, पोम में आपको slf4j को एक compileनिर्भरता के रूप में निर्दिष्ट करना होगा (यह डिफ़ॉल्ट है) लेकिन आप एक runtimeनिर्भरता के रूप में log4j निर्भरता को निर्दिष्ट करेंगे :

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>...</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>...</version>
    <scope>runtime</scope>
</dependency>

इस तरह, संकलित कोड में log4j वर्गों को संदर्भित नहीं किया जा सकता है, लेकिन आप फिर भी slf4j वर्गों को संदर्भित करने में सक्षम होंगे।
यदि आपने compileसमय के साथ दो निर्भरताएं निर्दिष्ट की हैं , तो कुछ भी आपको संकलित कोड में log4j कक्षाओं को संदर्भित करने से नहीं रोकेगा और आप लॉगिंग कार्यान्वयन के साथ अवांछनीय युग्मन बना सकते हैं:

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>...</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>...</version>
</dependency>

runtimeगुंजाइश का एक सामान्य उपयोग जेडीबीसी निर्भरता घोषणा है। पोर्टेबल कोड लिखने के लिए, आप नहीं चाहते हैं कि क्लाइंट कोड विशिष्ट DBMS निर्भरता (उदाहरण के लिए: PostgreSQL JDBC निर्भरता) की कक्षाओं को संदर्भित कर सकता है, लेकिन आप सभी इसे अपने आवेदन में शामिल करना चाहते हैं, क्योंकि रनटाइम के दौरान कक्षाओं को बनाने की आवश्यकता होती है JDBC API इस DBMS के साथ काम करता है।


0

संकलित समय पर आप अनुबंध / एपीआई को सक्षम करते हैं जो आपको अपनी निर्भरता से अपेक्षित हैं। (उदाहरण: यहां आप केवल ब्रॉडबैंड इंटरनेट प्रदाता के साथ अनुबंध के लिए हस्ताक्षर करते हैं) वास्तव में रन-टाइम पर आप निर्भरता का उपयोग कर रहे हैं। (उदाहरण: यहां आप वास्तव में ब्रॉडबैंड इंटरनेट का उपयोग कर रहे हैं)


0

प्रश्न का उत्तर देने के लिए "एक कार्यक्रम रनटाइम के दौरान किसी चीज पर निर्भर नहीं हो सकता है कि यह संकलन के दौरान निर्भर करता है?", आइए एक एनोटेशन प्रोसेसर के उदाहरण को देखें।

मान लीजिए कि आपने अपना एनोटेशन प्रोसेसर लिखा है, और मान लीजिए कि इसका संकलन समय पर निर्भर है com.google.auto.service:auto-serviceताकि इसका उपयोग किया जा सके @AutoService। यह निर्भरता केवल एनोटेशन प्रोसेसर को संकलित करने के लिए आवश्यक है, लेकिन इसे रनटाइम की आवश्यकता नहीं है: प्रसंस्करण एनोटेशन के लिए आपके एनोटेशन प्रोसेसर के आधार पर अन्य सभी परियोजनाओं को रनटाइम पर निर्भरता की आवश्यकता नहींcom.google.auto.service:auto-service है (न ही संकलन-समय पर और न ही किसी अन्य समय पर) ।

यह बहुत सामान्य नहीं है, लेकिन ऐसा होता है।


0

runtimeदायरे के बजाय कोड में कार्यान्वयन पुस्तकालयों के लिए प्रत्यक्ष निर्भरता जोड़ने कपोल-कल्पना या façades का उपयोग करने से प्रोग्रामर को रोकने के लिए है।

दूसरे शब्दों में, यह इंटरफेस का उपयोग करने के लिए लागू होता है।

ठोस उदाहरण:

1) आपकी टीम Log4j पर SLF4J का उपयोग कर रही है। आप चाहते हैं कि आपके प्रोग्रामर SLF4J API का उपयोग करें, न कि Log4j एक का। Log4j का उपयोग SLF4J द्वारा केवल आंतरिक रूप से किया जाना है। उपाय:

  • एक नियमित संकलन-समय निर्भरता के रूप में SLF4J को परिभाषित करें
  • Log4j-core और log4j-api को रनटाइम निर्भरता के रूप में परिभाषित करें।

2) आपका आवेदन JDBC का उपयोग करके MySQL तक पहुँच रहा है। आप चाहते हैं कि आपके प्रोग्रामर मानक JDBC अमूर्त के खिलाफ कोड करें, न कि सीधे MySQL ड्राइवर कार्यान्वयन के खिलाफ।

  • mysql-connector-javaएक रनटाइम निर्भरता के रूप में परिभाषित करें (MySQL JDBC ड्राइवर)।

संकलन के दौरान रनटाइम निर्भरताएँ छिपी होती हैं (यदि आपके कोड में "प्रत्यक्ष" पर निर्भरता है) तो संकलन-समय की त्रुटियों को फेंक दिया जाता है, लेकिन निष्पादन समय के दौरान और तैनाती योग्य कलाकृतियाँ बनाते समय शामिल किए जाते हैं (WAR फाइलें, SHADED जार फाइलें आदि)।

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