फ्लक्स ऐप में अजाक्स अनुरोध कहां किया जाना चाहिए?


194

मैं फ्लक्स आर्किटेक्चर के साथ एक react.js एप्लिकेशन बना रहा हूं और मैं यह पता लगाने की कोशिश कर रहा हूं कि सर्वर से डेटा के लिए अनुरोध कहां और कब किया जाना चाहिए। क्या इसके लिए कोई उदाहरण है। (TODO ऐप नहीं!)

जवाबों:


127

मैं एक्शन रचनाकारों में async लिखने के संचालन और दुकान में async रीड ऑपरेशन डालने का एक बड़ा प्रस्तावक हूँ। लक्ष्य स्टोर राज्य संशोधन कोड को पूरी तरह से सिंक्रोनस एक्शन हैंडलर में रखना है; यह उन्हें सरल और इकाई परीक्षण के लिए सरल कारण बताता है। एक ही समापन बिंदु (उदाहरण के लिए, डबल-रीडिंग) के लिए एक साथ कई अनुरोधों को रोकने के लिए, मैं वास्तविक अनुरोध प्रसंस्करण को एक अलग मॉड्यूल में स्थानांतरित करूँगा जो कई अनुरोधों को रोकने के लिए वादों का उपयोग करता है; उदाहरण के लिए:

class MyResourceDAO {
  get(id) {
    if (!this.promises[id]) {
      this.promises[id] = new Promise((resolve, reject) => {
        // ajax handling here...
      });
    } 
    return this.promises[id];
  }
}

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

उदाहरण के लिए, एक घटक यह कर सकता है:

getInitialState() {
  return { data: myStore.getSomeData(this.props.id) };
}

स्टोर में एक विधि लागू होगी, शायद, कुछ इस तरह से:

class Store {
  getSomeData(id) {
    if (!this.cache[id]) {
      MyResurceDAO.get(id).then(this.updateFromServer);
      this.cache[id] = LOADING_TOKEN;
      // LOADING_TOKEN is a unique value of some kind
      // that the component can use to know that the
      // value is not yet available.
    }

    return this.cache[id];
  }

  updateFromServer(response) {
    fluxDispatcher.dispatch({
      type: "DATA_FROM_SERVER",
      payload: {id: response.id, data: response}
    });
  }

  // this handles the "DATA_FROM_SERVER" action
  handleDataFromServer(action) {
    this.cache[action.payload.id] = action.payload.data;
    this.emit("change"); // or whatever you do to re-render your app
  }
}

क्या आपने कार्रवाई पेलोड के अंदर वादे करने की कोशिश की है? मुझे कई कार्यों को
निपटाने की

@SebastienLorber मेरे लिए फ्लक्स का बड़ा ड्रॉ सभी स्टेट्स अपडेट को सिंक्रोनस कोड पाथ में रखा गया है, और स्पष्ट रूप से केवल एक्शन डिस्पैच के परिणामस्वरूप है, इसलिए मैं स्टोर्स के अंदर एसिंक्रोनसी से बचता हूं।
मिशेल टाइली

1
@ फ़ेडरिको यह मेरे लिए अभी भी स्पष्ट नहीं है कि "सर्वश्रेष्ठ" समाधान क्या है। मैं इस रणनीति के साथ प्रयोग कर रहा हूँ कि डेटा लोडिंग के लिए संयुक्त रूप से बकाया async अनुरोधों की संख्या की गणना की गई है। दुर्भाग्य fluxसे निर्माण के बाद दुकानों में इंजेक्ट किया जाता है, इसलिए प्रारंभिक विधि में कार्रवाई करने का कोई शानदार तरीका नहीं है। आपको याहू के आइसोमोर्फिक फ्लक्स लिबास से कुछ अच्छे विचार मिल सकते हैं; यह कुछ है Fluxxor v2 बेहतर समर्थन करना चाहिए। यदि आप इस बारे में अधिक चैट करना चाहते हैं, तो मुझे ईमेल करें।
मिशेल टिली

1
data: resultहोना चाहिए data : data, है ना? नहीं है result। शायद पेलोड या ऐसा कुछ करने के लिए डेटा परम का नाम बदलने के लिए बेहतर है।
ऑलिगॉफ्रेन

2
मुझे यह पुराना धागा बहुत मददगार लगा - विशेषकर बिल फिशर और जिंग चेन की टिप्पणी। यह बहुत ही करीब है @BinaryMuse मामूली अंतर के साथ प्रस्ताव कर रहा है कि प्रेषण निर्माता में होता है।
फिलिपीपेव

37

Fluxxor में API के साथ async संचार का एक उदाहरण है।

इस ब्लॉग पोस्ट में इसके बारे में बातचीत है और इसे रिएक्ट के ब्लॉग पर चित्रित किया गया है।


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

क्या JSX घटकों में API अनुरोध किया जाना चाहिए? स्टोर? अन्य जगह?

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

मेरे मामले में, मैंने क्यू वादों को कार्यों के पेलोड के रूप में रखना बहुत आसान पाया है क्योंकि:

  • मेरे कार्यों को क्रमबद्ध होने की आवश्यकता नहीं है (मैं इवेंट लॉग नहीं रखता, मुझे इवेंट सोर्सिंग के इवेंट रिप्ले की आवश्यकता नहीं है)
  • यह अलग-अलग कार्यों / घटनाओं (अनुरोध निकाल दिया / अनुरोध पूरा / अनुरोध विफल) करने की आवश्यकता को हटाता है और सहसंबंध आईडी का उपयोग करके उनका मिलान करना होता है जब समवर्ती अनुरोधों को निकाल दिया जा सकता है।
  • यह स्टोर के बीच किसी भी निर्भरता को प्रस्तुत किए बिना, एक ही अनुरोध को पूरा करने के लिए कई स्टोर में जाने की अनुमति देता है (हालांकि कैशिंग परत को पेश करना बेहतर हो सकता है?)

Ajax EVIL है

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

इसके बारे में सोचो। स्केलेबिलिटी के लिए अब हम स्टोरेज इंजन के रूप में अंतिम स्थिरता के साथ वितरित सिस्टम का उपयोग करते हैं (क्योंकि हम कैप प्रमेय को हरा नहीं सकते हैं और अक्सर हम उपलब्ध होना चाहते हैं)। ये प्रणालियां एक-दूसरे को मतदान करने के माध्यम से सिंक नहीं करती हैं (शायद सर्वसम्मति के संचालन को छोड़कर?) बल्कि वितरित प्रणाली के सभी सदस्यों को सुसंगत बनाने के लिए CRDT और इवेंट लॉग जैसी संरचनाओं का उपयोग करें (सदस्य एक ही डेटा में कनवर्ट करेंगे, पर्याप्त समय दिया गया) ।

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

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

मुझे लगता है कि हमें वास्तव में खुद को प्रेरित करना चाहिए कि डेटाबेस हमारे सीमांत अनुप्रयोगों को कैसे काम कर रहे हैं। ध्यान देने वाली एक बात यह है कि ये ऐप एक-दूसरे को डेटा भेजने के लिए POST और PUT और GET ajax अनुरोध नहीं करते हैं, बल्कि अंतिम स्थिरता सुनिश्चित करने के लिए इवेंट लॉग और CRDT का उपयोग करते हैं।

तो ऐसा क्यों नहीं किया गया? ध्यान दें कि बैकेंड पहले से ही उस दिशा में आगे बढ़ रहा है, जिसमें काफ्का जैसे उपकरण बड़े खिलाड़ियों द्वारा बड़े पैमाने पर अपनाए गए हैं। यह किसी तरह इवेंट सोर्सिंग / CQRS / DDD से भी संबंधित है।

खुद को समझाने के लिए काफ्का लेखकों के इन भयानक लेखों की जाँच करें:

हो सकता है कि हम सर्वर को कमांड भेजकर शुरू कर सकते हैं, और अजाक्स अनुरोधों को हटाने के बजाय सर्वर घटनाओं की एक धारा प्राप्त कर सकते हैं (छूट के लिए वेबस्कैट के माध्यम से)।

मैं अजाक्स अनुरोध के साथ बहुत सहज नहीं था। जैसा कि हम अभिकर्मक विकसित करते हैं वे कार्यात्मक प्रोग्रामर होते हैं। मुझे लगता है कि स्थानीय डेटा के बारे में तर्क करना मुश्किल है जो आपके सामने वाले एप्लिकेशन के "सत्य का स्रोत" माना जाता है, जबकि सच्चाई का वास्तविक स्रोत वास्तव में सर्वर डेटाबेस पर है, और आपका "स्थानीय" स्रोत सत्य का पुराना हो सकता है जब आप इसे प्राप्त करते हैं, और सत्य मूल्य के वास्तविक स्रोत तक कभी नहीं जुटाएंगे जब तक कि आप कुछ लंगड़ा ताज़ा नहीं करते हैं ... क्या यह इंजीनियरिंग है?

हालाँकि कुछ स्पष्ट कारणों के लिए इस तरह की चीज़ को डिज़ाइन करना थोड़ा कठिन है:

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

3
क्या आप क्रियाओं के साथ Q वादों का उपयोग करने का एक उदाहरण प्रदान कर सकते हैं?
मैट फॉक्सक्स डंकन

@MattFoxxDuncan यकीन नहीं होता कि यह इतना अच्छा विचार है क्योंकि यह "ईवेंट लॉग" को अपरिवर्तनीय बनाता है और स्टोर अपडेट को असंगत रूप से निकाल दिया जा रहा है, इसलिए इसमें कुछ कमियां हैं हालांकि यदि यह हमारे usecase के लिए ठीक है और आप इन कमियों को समझते हैं तो यह काफी आसान है और बॉयलरप्लेट को कम करें। फ्लक्सएक्सोर के साथ आप शायद कुछ ऐसा कर सकते हैंthis.dispatch("LOAD_DATA", {dataPromise: yourPromiseHere});
सेबेस्टियन लॉर्बर

अपने AJAX तर्क के बारे में पूरी तरह से असहमत हैं। वास्तव में इसे पढ़ना बहुत कष्टप्रद था। क्या आपने अपनी टिप्पणी पढ़ी है? स्टोर, गेम्स, ऐप्स के बारे में सोचें जो गंभीर पैसे कमाते हैं - सभी के लिए एपीआई और AJAX सर्वर कॉल की आवश्यकता होती है .. अगर आप "सर्वर रहित" या उस प्रकृति का कुछ चाहते हैं तो Firebase को देखें, लेकिन AJAX यहां यह कहने के लिए है कि मुझे उम्मीद है कि कम से कम कोई इससे सहमत नहीं है आपका तर्क
TheBlackBenzKid

@ TheBlackBenzKid मैं यह नहीं कह रहा हूँ कि अजाक्स वर्ष में पूरी तरह से गायब हो जाएगा (और मुझे यकीन है कि मैं अभी भी एक स्टार्टअप के सीटीओ के रूप में अजाक्स अनुरोधों के शीर्ष पर वेबसाइट बना रहा हूं), लेकिन मैं कह रहा हूं कि यह गायब होने की संभावना है क्योंकि यह एक प्रोटोकॉल नहीं है जो अंततः सुसंगतता को संभालने के लिए पर्याप्त है, जिसके लिए स्ट्रीमिंग की आवश्यकता होती है और मतदान की आवश्यकता नहीं होती है, और आखिरकार सुसंगतता है जो एप्स को ऑफ़लाइन तरीके से कार्य करने की अनुमति देता है (हाँ आप स्थानीय स्तर पर खुद से कुछ हैक कर सकते हैं, लेकिन आपके पास ऑफ़लाइन क्षमताएँ सीमित होंगी, या आपका ऐप बहुत सरल है)। समस्या कैशिंग नहीं है, यह उस कैश को अमान्य कर रहा है।
सेबेस्टियन लॉर्बर

@ TheBlackBenzKid Firebase, Meteor आदि के पीछे के मॉडल पर्याप्त अच्छे नहीं हैं। क्या आप जानते हैं कि ये प्रणालियाँ समवर्ती लिखों को कैसे संभालती हैं? अंतिम लेखन-कारण-कार्य-योग्यता / विलय की रणनीतियों के बजाय जीत? जब आप दोनों किसी अविश्वसनीय कनेक्शन पर काम कर रहे हों, तो क्या आप किसी ऐप में अपने सहयोगी के काम को ओवरराइड कर सकते हैं? यह भी ध्यान दें कि ये सिस्टम बहुत सारे स्थानीय और सर्वर के मॉडल को जोड़े रखते हैं। क्या आप किसी भी जाने-माने सहयोगी ऐप को जानते हैं जो काफी जटिल है, पूरी तरह से ऑफ़लाइन काम करता है, एक संतुष्ट फायरबेस उपयोगकर्ता होने की घोषणा करता है? मैं नहीं
सेबस्टियन लॉर्बर

20

आप एक्शन क्रिएटर्स या स्टोर्स में डेटा के लिए कॉल कर सकते हैं। महत्वपूर्ण बात यह है कि प्रतिक्रिया को सीधे संभालना नहीं है, लेकिन त्रुटि / सफलता कॉलबैक में एक कार्रवाई बनाने के लिए। सीधे दुकान में प्रतिक्रिया को संभालने से अधिक भंगुर डिजाइन होता है।


9
क्या आप इसे और अधिक विवरण में बता सकते हैं? कहें कि मुझे सर्वर से प्रारंभिक डेटा लोड करने की आवश्यकता है। नियंत्रक दृश्य में मैं एक कार्रवाई INIT शुरू करता हूं, और स्टोर शुरू होता है यह इस गतिविधि को दर्शाती async आरंभीकरण है। अब, मैं इस विचार के साथ जाऊंगा कि जब स्टोर ने डेटा प्राप्त किया, तो यह केवल परिवर्तन का उत्सर्जन करेगा, लेकिन कार्रवाई शुरू नहीं करेगा। इसलिए इनिशियलाइज़ेशन के बाद एक बदलाव को छोड़ना उन विचारों को बताता है कि वे स्टोर से डेटा प्राप्त कर सकते हैं। सफल लोडिंग पर एक बदलाव का उत्सर्जन करने की आवश्यकता क्यों नहीं है, लेकिन एक और कार्रवाई शुरू कर रहा है ?! साभार
जिम-वाई

फिशरदेबदेव, डेटा के लिए कॉल करने वाली दुकानों के बारे में, ऐसा करने से, आप फ्लक्स प्रतिमान को नहीं तोड़ते हैं, केवल 2 उचित तरीके जिनसे मैं डेटा के लिए कॉल करने के बारे में सोच सकता हूं: 1 का उपयोग करके बूटस्ट्रैप क्लास का उपयोग करें। ।, डेटा को लोड करने के लिए फिर से क्रियाओं का उपयोग करते हुए
Yotam

4
डेटा प्राप्त करना डेटा प्राप्त करने के समान नहीं है। @ जिम-वाई: स्टोर में डेटा वास्तव में बदल जाने के बाद आपको केवल परिवर्तन का उत्सर्जन करना चाहिए। Yotam: नहीं, स्टोर में डेटा के लिए कॉल करने से प्रतिमान नहीं टूटता। डेटा केवल क्रियाओं के माध्यम से प्राप्त किया जाना चाहिए, ताकि सभी स्टोर को एप्लिकेशन में प्रवेश करने वाले किसी नए डेटा द्वारा सूचित किया जा सके। इसलिए हम एक स्टोर में डेटा के लिए कॉल कर सकते हैं, लेकिन जब प्रतिक्रिया वापस आती है, तो हमें सीधे इसे संभालने के बजाय एक नई कार्रवाई बनाने की आवश्यकता होती है। यह एप्लिकेशन को लचीला और नई सुविधा के विकास के लिए लचीला रखता है।
फिशरदेबदेव

2

मैं फ्लक्सएक्सोर अजाक्स उदाहरण से बाइनरी म्यूज़िक के उदाहरण का उपयोग कर रहा हूं । यहाँ एक ही दृष्टिकोण का उपयोग करके मेरा बहुत सरल उदाहरण है।

मेरे पास एक सरल उत्पाद स्टोर कुछ उत्पाद क्रियाएं और नियंत्रक-दृश्य घटक है जिसमें उप-घटक हैं जो सभी उत्पाद स्टोर में किए गए परिवर्तनों का जवाब देते हैं । उदाहरण के लिए उत्पाद-स्लाइडर , उत्पाद-सूची और उत्पाद-खोज घटक।

नकली उत्पाद ग्राहक

यहाँ नकली ग्राहक है जिसे आप एक वास्तविक समापन बिंदु लौटने वाले उत्पादों को कॉल करने के लिए स्थानापन्न कर सकते हैं।

var ProductClient = {

  load: function(success, failure) {
    setTimeout(function() {
      var ITEMS = require('../data/product-data.js');
      success(ITEMS);
    }, 1000);
  }    
};

module.exports = ProductClient;

उत्पाद की दुकान

यहाँ उत्पाद स्टोर है, जाहिर है यह एक बहुत ही न्यूनतम स्टोर है।

var Fluxxor = require("fluxxor");

var store = Fluxxor.createStore({

  initialize: function(options) {

    this.productItems = [];

    this.bindActions(
      constants.LOAD_PRODUCTS_SUCCESS, this.onLoadSuccess,
      constants.LOAD_PRODUCTS_FAIL, this.onLoadFail
    );
  },

  onLoadSuccess: function(data) {    
    for(var i = 0; i < data.products.length; i++){
      this.productItems.push(data.products[i]);
    }    
    this.emit("change");
  },

  onLoadFail: function(error) {
    console.log(error);    
    this.emit("change");
  },    

  getState: function() {
    return {
      productItems: this.productItems
    };
  }
});

module.exports = store;

अब उत्पाद क्रियाएं, जो AJAX अनुरोध करती हैं और सफलता पर LOAD_PRODUCS_SUCCESS एक्शन उत्पादों को स्टोर में वापस लाती हैं।

उत्पाद क्रियाएँ

var ProductClient = require("../fake-clients/product-client");

var actions = {

  loadProducts: function() {

    ProductClient.load(function(products) {
      this.dispatch(constants.LOAD_PRODUCTS_SUCCESS, {products: products});
    }.bind(this), function(error) {
      this.dispatch(constants.LOAD_PRODUCTS_FAIL, {error: error});
    }.bind(this));
  }    

};

module.exports = actions;

इसलिए this.getFlux().actions.productActions.loadProducts()इस स्टोर को सुनने वाले किसी भी घटक से कॉल करने से उत्पादों को लोड किया जाएगा।

आप विभिन्न कार्यों के होने की कल्पना कर सकते हैं, जो addProduct(id) removeProduct(id)एक ही पैटर्न का पालन करते हुए आदि जैसे उपयोगकर्ता की बातचीत का जवाब देंगे ।

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


2

मैंने यहां एक संबंधित प्रश्न का उत्तर दिया: फ्लक्स में नेस्टेड एप कॉल को कैसे संभालना है

क्रियाएँ ऐसी चीज़ें नहीं हैं जो बदलाव का कारण बनें। उन्हें एक अखबार की तरह माना जाता है जो बाहरी दुनिया में बदलाव के आवेदन की सूचना देता है, और फिर आवेदन उस समाचार पर प्रतिक्रिया देता है। स्टोर अपने आप में बदलाव का कारण बनते हैं। क्रियाएँ सिर्फ उन्हें सूचित करती हैं।

बिल फिशर, फ्लक्स के निर्माता https://stackoverflow.com/a/26581808/4258088

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

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

एक स्टोर कुछ इस तरह दिख सकता है:

class DataStore {
  constructor() {
    this.data = [];

    this.bindListeners({
      handleDataNeeded: Action.DATA_NEEDED,
      handleNewData: Action.NEW_DATA
    });
  }

  handleDataNeeded(id) {
    if(neededDataNotThereYet){
      api.data.fetch(id, (err, res) => {
        //Code
        if(success){
          Action.newData(payLoad);
        }
      }
    }
  }

  handleNewData(data) {
    //code that saves data and emit change
  }
}

0

यहाँ मेरा इस पर है: http://www.thedreaming.org/2015/03/14/react-ajax/

उम्मीद है की वो मदद करदे। :)


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

2
अच्छी पोस्ट, लेकिन प्रत्येक दृष्टिकोण के पेशेवरों / विपक्षों का एक छोटा सारांश जोड़ने से आपको उत्थान मिलेगा। SO पर, हमें आपके उत्तर की जानकारी प्राप्त करने के लिए एक लिंक पर क्लिक करने की आवश्यकता नहीं है।
कोरी हाउस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.