|
|
10 months ago | |
|---|---|---|
| .. | ||
| README.md | 10 months ago | |
| assignment.md | 12 months ago | |
README.md
बैंकिङ एप निर्माण भाग ३: डेटा प्राप्त गर्ने र प्रयोग गर्ने विधिहरू
प्रि-लेक्चर क्विज
परिचय
प्रत्येक वेब एप्लिकेसनको केन्द्रमा डेटा हुन्छ। डेटा विभिन्न प्रकारका हुन सक्छ, तर यसको मुख्य उद्देश्य सधैं प्रयोगकर्तालाई जानकारी देखाउनु हो। वेब एपहरू बढ्दो अन्तरक्रियात्मक र जटिल हुँदै गइरहेको अवस्थामा, प्रयोगकर्ताले जानकारी कसरी पहुँच गर्छ र अन्तरक्रिया गर्छ भन्ने कुरा वेब विकासको महत्त्वपूर्ण भाग बनेको छ।
यस पाठमा, हामीले कसरी सर्भरबाट डेटा असिंक्रोनस रूपमा प्राप्त गर्ने र HTML पुनः लोड नगरी वेब पृष्ठमा जानकारी देखाउने भन्ने कुरा सिक्नेछौं।
पूर्व-आवश्यकता
यस पाठको लागि तपाईंले वेब एपको लगइन र रजिस्ट्रेसन फारम भाग निर्माण गरिसक्नुपर्छ। तपाईंले Node.js स्थापना गर्नुपर्छ र सर्भर API चलाउनुहोस् ताकि तपाईंले खाता डेटा प्राप्त गर्न सक्नुहुन्छ।
तपाईं सर्भर ठीकसँग चलिरहेको छ कि छैन भनेर जाँच गर्न टर्मिनलमा यो कमाण्ड चलाउन सक्नुहुन्छ:
curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result
AJAX र डेटा प्राप्ति
परम्परागत वेब साइटहरूले प्रयोगकर्ताले लिंक चयन गर्दा वा फारम प्रयोग गरेर डेटा पेश गर्दा HTML पृष्ठ पुनः लोड गरेर देखाइएको सामग्री अपडेट गर्छ। नयाँ डेटा लोड गर्न प्रत्येक पटक, वेब सर्भरले ब्राउजरले प्रक्रिया गर्नुपर्ने नयाँ HTML पृष्ठ फर्काउँछ, जसले हालको प्रयोगकर्ता क्रियाकलापलाई अवरोध पुर्याउँछ र पुनः लोडको क्रममा अन्तरक्रियालाई सीमित बनाउँछ। यस वर्कफ्लोलाई मल्टि-पेज एप्लिकेसन वा MPA भनिन्छ।
जब वेब एप्लिकेसनहरू जटिल र अन्तरक्रियात्मक हुँदै गइरहेका थिए, AJAX (Asynchronous JavaScript and XML) नामक नयाँ प्रविधि देखा पर्यो। यस प्रविधिले वेब एपहरूलाई HTML पृष्ठ पुनः लोड नगरी सर्भरबाट असिंक्रोनस रूपमा डेटा पठाउन र प्राप्त गर्न अनुमति दिन्छ, जसले छिटो अपडेट र सहज प्रयोगकर्ता अन्तरक्रिया प्रदान गर्दछ। सर्भरबाट नयाँ डेटा प्राप्त भएपछि, हालको HTML पृष्ठलाई DOM API प्रयोग गरेर जाभास्क्रिप्टको माध्यमबाट पनि अपडेट गर्न सकिन्छ। समयसँगै, यो दृष्टिकोण विकसित हुँदै सिंगल-पेज एप्लिकेसन वा SPA मा परिणत भएको छ।
AJAX पहिलो पटक परिचय गराइएपछि, असिंक्रोनस रूपमा डेटा प्राप्त गर्न उपलब्ध एकमात्र API XMLHttpRequest थियो। तर आधुनिक ब्राउजरहरूले अब Fetch API पनि कार्यान्वयन गर्छन्, जुन प्रतिज्ञा (promises) प्रयोग गर्छ र JSON डेटा हेरफेर गर्नका लागि अझ सुविधाजनक र शक्तिशाली छ।
सबै आधुनिक ब्राउजरहरूले
Fetch APIसमर्थन गर्छन्, तर यदि तपाईंको वेब एप्लिकेसन पुरानो ब्राउजरहरूमा काम गर्न चाहन्छ भने, caniuse.com मा अनुकूलता तालिका पहिले जाँच गर्नु सधैं राम्रो विचार हो।
कार्य
अघिल्लो पाठमा हामीले खाता सिर्जना गर्न रजिस्ट्रेसन फारम कार्यान्वयन गरेका थियौं। अब हामीले विद्यमान खाताको प्रयोग गरेर लगइन गर्ने र यसको डेटा प्राप्त गर्ने कोड थप्नेछौं। app.js फाइल खोल्नुहोस् र नयाँ login फंक्शन थप्नुहोस्:
async function login() {
const loginForm = document.getElementById('loginForm')
const user = loginForm.user.value;
}
यहाँ हामीले getElementById() प्रयोग गरेर फारम तत्व प्राप्त गरेर सुरु गर्छौं, र त्यसपछि हामी loginForm.user.value प्रयोग गरेर इनपुटबाट प्रयोगकर्ता नाम प्राप्त गर्छौं। प्रत्येक फारम नियन्त्रणलाई फारमको गुणको रूपमा HTML मा सेट गरिएको name एट्रिब्युटद्वारा पहुँच गर्न सकिन्छ।
रजिस्ट्रेसनको लागि हामीले गरेको जस्तै, हामी अर्को फंक्शन सिर्जना गर्नेछौं जसले सर्भर अनुरोध प्रदर्शन गर्छ, तर यस पटक खाता डेटा प्राप्त गर्नका लागि:
async function getAccount(user) {
try {
const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user));
return await response.json();
} catch (error) {
return { error: error.message || 'Unknown error' };
}
}
हामी fetch API प्रयोग गरेर सर्भरबाट डेटा असिंक्रोनस रूपमा अनुरोध गर्छौं, तर यस पटक हामीलाई URL बाहेक अन्य कुनै अतिरिक्त प्यारामिटरहरू आवश्यक छैनन्, किनकि हामी केवल डेटा सोध्दैछौं। डिफल्ट रूपमा, fetch ले GET HTTP अनुरोध सिर्जना गर्छ, जुन हामीलाई यहाँ चाहिएको छ।
✅ encodeURIComponent() एउटा फंक्शन हो जसले URL का विशेष क्यारेक्टरहरूलाई एस्केप गर्छ। यदि हामीले यो फंक्शनलाई कल नगरीकन user मानलाई URL मा सिधै प्रयोग गर्यौं भने हामीलाई के समस्या हुन सक्छ?
अब हामीले हाम्रो login फंक्शनलाई getAccount प्रयोग गर्न अपडेट गरौं:
async function login() {
const loginForm = document.getElementById('loginForm')
const user = loginForm.user.value;
const data = await getAccount(user);
if (data.error) {
return console.log('loginError', data.error);
}
account = data;
navigate('/dashboard');
}
पहिले, किनकि getAccount असिंक्रोनस फंक्शन हो, हामीले सर्भर परिणामको प्रतीक्षा गर्न await कीवर्डसँग मेल गर्नुपर्छ। कुनै पनि सर्भर अनुरोधमा जस्तै, हामीले त्रुटि केसहरू पनि सामना गर्नुपर्छ। अहिलेको लागि, हामी केवल त्रुटि देखाउनको लागि एक लग सन्देश थप्नेछौं, र पछि यसमा फर्कनेछौं।
त्यसपछि हामीले डेटा कतै भण्डारण गर्नुपर्छ ताकि हामी पछि ड्यासबोर्ड जानकारी देखाउन प्रयोग गर्न सकौं। किनकि account भेरिएबल अझै अवस्थित छैन, हामीले हाम्रो फाइलको शीर्षमा यसको लागि एक ग्लोबल भेरिएबल सिर्जना गर्नेछौं:
let account = null;
प्रयोगकर्ता डेटा भेरिएबलमा सुरक्षित भएपछि, हामीले navigate() फंक्शन प्रयोग गरेर लगइन पृष्ठबाट ड्यासबोर्ड मा जान सक्छौं।
अन्ततः, हामीले लगइन फारम पेश गर्दा हाम्रो login फंक्शनलाई कल गर्न आवश्यक छ, HTML संशोधन गरेर:
<form id="loginForm" action="javascript:login()">
सबै कुरा ठीकसँग काम गरिरहेको छ कि छैन भनेर नयाँ खाता रजिस्टर गरेर र सोही खाताको प्रयोग गरेर लगइन प्रयास गरेर जाँच गर्नुहोस्।
अर्को भागमा अघि बढ्नु अघि, हामीले register फंक्शनलाई यसलाई थपेर पूरा गर्न सक्छौं:
account = result;
navigate('/dashboard');
✅ के तपाईंलाई थाहा छ कि डिफल्ट रूपमा, तपाईंले हेर्दै गरेको वेब पृष्ठको समान डोमेन र पोर्ट बाट मात्र सर्भर API कल गर्न सक्नुहुन्छ? यो ब्राउजरहरूले लागू गरेको सुरक्षा संयन्त्र हो। तर, हाम्रो वेब एप localhost:3000 मा चलिरहेको छ भने सर्भर API localhost:5000 मा चलिरहेको छ, यो किन काम गर्छ? Cross-Origin Resource Sharing (CORS) नामक प्रविधि प्रयोग गरेर, यदि सर्भरले प्रतिक्रिया मा विशेष हेडरहरू थप्छ भने, विशिष्ट डोमेनहरूको लागि अपवादहरू अनुमति दिन सम्भव छ।
API को बारेमा थप जान्नको लागि यो पाठ लिनुहोस्।
HTML अपडेट गरेर डेटा देखाउनुहोस्
अब हामीसँग प्रयोगकर्ता डेटा छ, हामीले यसलाई देखाउनको लागि अवस्थित HTML अपडेट गर्नुपर्छ। हामीले पहिले नै document.getElementById() जस्ता विधिहरू प्रयोग गरेर DOM बाट तत्व प्राप्त गर्ने तरिका थाहा पाइसकेका छौं। तपाईंले आधारभूत तत्व प्राप्त गरेपछि, यहाँ केही API हरू छन् जसको प्रयोग गरेर तपाईं यसलाई परिवर्तन गर्न वा यसमा नयाँ बच्चा तत्वहरू थप्न सक्नुहुन्छ:
-
textContentगुण प्रयोग गरेर तपाईंले तत्वको पाठ परिवर्तन गर्न सक्नुहुन्छ। यो मान परिवर्तन गर्दा तत्वका सबै बच्चाहरू (यदि कुनै छ भने) हटाइन्छ र प्रदान गरिएको पाठले प्रतिस्थापन गरिन्छ। यसरी, यो कुनै दिइएको तत्वका सबै बच्चाहरू हटाउनको लागि खाली स्ट्रिङ''असाइन गरेर कुशल विधि पनि हो। -
document.createElement()रappend()विधि प्रयोग गरेर तपाईंले नयाँ बच्चा तत्वहरू सिर्जना र संलग्न गर्न सक्नुहुन्छ।
✅ तत्वको HTML सामग्री परिवर्तन गर्न innerHTML गुण प्रयोग गर्न पनि सम्भव छ, तर यो क्रस-साइट स्क्रिप्टिङ (XSS) आक्रमणहरूको लागि संवेदनशील छ।
कार्य
ड्यासबोर्ड स्क्रिनमा अघि बढ्नु अघि, लगइन पृष्ठमा हामीले एउटा कुरा गर्नुपर्छ। हाल, यदि तपाईंले अवैध प्रयोगकर्ता नामको साथ लगइन प्रयास गर्नुभयो भने, सन्देश कन्सोलमा देखिन्छ तर सामान्य प्रयोगकर्ताका लागि केही परिवर्तन हुँदैन र तपाईंलाई के भइरहेको छ थाहा हुँदैन।
हामीले लगइन <button> भन्दा ठीक अगाडि लगइन फारममा त्रुटि सन्देश देखाउनको लागि एउटा प्लेसहोल्डर तत्व थपौं:
...
<div id="loginError"></div>
<button>Login</button>
...
यो <div> तत्व खाली छ, जसको अर्थ स्क्रिनमा केही देखाइने छैन जबसम्म हामी यसमा केही सामग्री थप्दैनौं। हामीले यसलाई id पनि दिएको छ ताकि हामीले यसलाई सजिलैसँग जाभास्क्रिप्टको साथ प्राप्त गर्न सकौं।
app.js फाइलमा फर्केर नयाँ सहायक फंक्शन updateElement सिर्जना गर्नुहोस्:
function updateElement(id, text) {
const element = document.getElementById(id);
element.textContent = text;
}
यो एकदम सरल छ: दिइएको तत्व id र text को आधारमा, यो मिल्दो id भएको DOM तत्वको पाठ सामग्री अपडेट गर्नेछ। अब हामीले यस विधिलाई login फंक्शनमा अघिल्लो त्रुटि सन्देशको सट्टा प्रयोग गरौं:
if (data.error) {
return updateElement('loginError', data.error);
}
अब यदि तपाईंले अवैध खाताको साथ लगइन प्रयास गर्नुभयो भने, तपाईंले यस्तो देख्नुहुनेछ:
अब हामीसँग त्रुटि पाठ छ जसले दृश्य रूपमा देखाउँछ, तर यदि तपाईंले स्क्रिन रिडरको साथ प्रयास गर्नुभयो भने तपाईंले देख्नुहुनेछ कि केही पनि घोषणा गरिएको छैन। पृष्ठमा गतिशील रूपमा थपिएको पाठ स्क्रिन रिडरहरूले घोषणा गर्नको लागि, यसले Live Region नामक केही प्रयोग गर्न आवश्यक छ। यहाँ हामीले अलर्ट नामक लाइभ क्षेत्रको विशिष्ट प्रकार प्रयोग गर्न गइरहेका छौं:
<div id="loginError" role="alert"></div>
register फंक्शन त्रुटिहरूको लागि पनि समान व्यवहार कार्यान्वयन गर्नुहोस् (HTML अपडेट गर्न नबिर्सनुहोस्)।
ड्यासबोर्डमा जानकारी देखाउनुहोस्
हामीले भर्खरै देखेका समान प्रविधिहरू प्रयोग गरेर, हामीले ड्यासबोर्ड पृष्ठमा खाता जानकारी देखाउने काम पनि गर्नेछौं।
सर्भरबाट प्राप्त खाता वस्तु यस प्रकार देखिन्छ:
{
"user": "test",
"currency": "$",
"description": "Test account",
"balance": 75,
"transactions": [
{ "id": "1", "date": "2020-10-01", "object": "Pocket money", "amount": 50 },
{ "id": "2", "date": "2020-10-03", "object": "Book", "amount": -10 },
{ "id": "3", "date": "2020-10-04", "object": "Sandwich", "amount": -5 }
],
}
नोट: तपाईंको जीवनलाई सजिलो बनाउनको लागि, तपाईंले पहिले नै डेटा भरिएको
testखाता प्रयोग गर्न सक्नुहुन्छ।
कार्य
हामीले HTML मा "Balance" सेक्सनलाई प्लेसहोल्डर तत्वहरू थप्न प्रतिस्थापन गरेर सुरु गरौं:
<section>
Balance: <span id="balance"></span><span id="currency"></span>
</section>
हामीले खाता विवरण देखाउनको लागि नयाँ सेक्सन पनि थप्नेछौं:
<h2 id="description"></h2>
✅ किनकि खाता विवरणले यसको तलको सामग्रीको लागि शीर्षकको रूपमा काम गर्छ, यसलाई शीर्षकको रूपमा अर्थपूर्ण रूपमा मार्कअप गरिएको छ। शीर्षक संरचना कसरी महत्त्वपूर्ण छ भन्ने बारे थप जान्नुहोस्, र पृष्ठलाई आलोचनात्मक रूपमा हेर्नुहोस् कि अरू के शीर्षक हुन सक्छ।
अब, हामीले app.js मा नयाँ फंक्शन updateDashboard() सिर्जना गर्नेछौं:
function updateDashboard() {
if (!account) {
return navigate('/login');
}
updateElement('description', account.description);
updateElement('balance', account.balance.toFixed(2));
updateElement('currency', account.currency);
}
पहिले, हामीले आवश्यक खाता डेटा छ कि छैन भनेर जाँच गर्छौं। त्यसपछि हामीले पहिले सिर्जना गरेको updateElement() फंक्शन प्रयोग गरेर HTML अपडेट गर्छौं।
ब्यालेन्स प्रदर्शनलाई अझ राम्रो बनाउन, हामीले
toFixed(2)विधि प्रयोग गरेर मानलाई दशमलव बिन्दु पछि २ अंक देखाउन बाध्य बनाउँछौं।
अब हामीले ड्यासबोर्ड लोड हुँदा हरेक पटक हाम्रो updateDashboard() फंक्शनलाई कल गर्नुपर्छ। यदि तपाईंले पाठ १ असाइनमेन्ट पूरा गरिसक्नुभएको छ भने यो सरल हुनुपर्छ, अन्यथा तपाईंले निम्न कार्यान्वयन प्रयोग गर्न सक्नुहुन्छ।
updateRoute() फंक्शनको अन्त्यमा यो कोड थप्नुहोस्:
if (typeof route.init === 'function') {
route.init();
}
र रुट्स परिभाषालाई यससँग अपडेट गर्नुहोस्:
const routes = {
'/login': { templateId: 'login' },
'/dashboard': { templateId: 'dashboard', init: updateDashboard }
};
यस परिवर्तनसँग, हरेक पटक ड्यासबोर्ड पृष्ठ देखाइन्छ, updateDashboard() फंक्शन कल गरिन्छ। लगइन पछि, तपाईंले खाता ब्यालेन्स, मुद्रा र विवरण देख्न सक्षम हुनुहुनेछ।
HTML टेम्प्लेटहरू प्रयोग गरेर तालिका पङ्क्तिहरू गतिशील रूपमा सिर्जना गर्नुहोस्
पहिलो पाठमा हामीले HTML टेम्प्लेटहरू र appendChild() विधि प्रयोग गरेर हाम्रो एपमा नेभिगेसन कार्यान्वयन गरेका थियौं। टेम्प्लेटहरू साना पनि हुन सक्छन् र पृष्ठको पुनरावृत्त भागहरू गतिशील रूपमा जनाउन प्रयोग गर्न सकिन्छ।
हामीले HTML तालिकामा लेनदेनहरूको सूची देखाउन समान दृष्टिकोण प्रयोग गर्नेछौं।
कार्य
HTML <body> मा नयाँ टेम्प्लेट थप्नुहोस्:
<template id="transaction">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</template>
यो टेम्प्लेटले एकल तालिका पङ्क्ति प्रतिनिधित्व गर्दछ, जसमा हामीले भरपर्दा तीन स्तम्भहरू छन्: मिति, वस्तु र रकम।
त्यसपछि, ड्यासबोर्ड टेम्प्लेट भित्रको तालिकाको <tbody> तत्वमा यो id गुण थप्नुहोस् ताकि जाभास्क्रिप्ट प्रयोग गरेर सजिलैसँग फेला पार्न सकियोस्:
<tbody id="transactions"></tbody>
हाम्रो HTML तयार छ, अब जाभास्क्रिप्ट कोडमा स्विच गरौं र नयाँ फंक्शन createTransactionRow सिर्जना गरौं:
function createTransactionRow(transaction) {
const template = document.getElementById('transaction');
const transactionRow = template.content.cloneNode(true);
const tr = transactionRow.querySelector('tr');
tr.children[0].textContent = transaction.date;
tr.children[1].textContent = transaction.object;
tr.children[2].textContent = transaction.amount.toFixed(2);
return transactionRow;
}
यो फंक्शनले ठीक त्यसै गर्छ जुन यसको नामले संकेत गर्छ: हामीले पहिले सिर्जना गरेको टेम्प्लेट प्रयोग गरेर, यो नयाँ तालिका पङ्क्ति सिर्जना गर्छ र लेनदेन डेटा प्रयोग गरेर यसको सामग्री भर्छ। हामीले यसलाई हाम्रो updateDashboard() फंक्शनमा तालिका जनाउन प्रयोग गर्नेछौं:
const transactionsRows = document.createDocumentFragment();
for (const transaction of account.transactions) {
const transactionRow = createTransactionRow(transaction);
transactionsRows.appendChild(transactionRow);
}
updateElement('transactions', transactionsRows);
यहाँ हामीले विधि document.createDocumentFragment() प्रयोग गर्छौं जसले नयाँ DOM फ्र्यागमेन्ट सिर्जना गर्छ जसमा हामी काम गर्न सक्छौं, अन्ततः यसलाई हाम्रो HTML तालिकामा संलग्न गर्नु अघि।
यो कोड काम गर्न सक्ने सुनिश्चित गर्नका लागि हामीले अझै एउटा कुरा गर्नुपर्छ, किनकि हाम्रो updateElement() फंक्शन हाल केवल पाठ सामग्रीलाई समर्थन गर्छ। यसको कोडलाई अलिकति परिवर्तन गरौं:
function updateElement(id, textOrNode) {
const element = document.getElementById(id);
element.textContent = ''; // Removes all children
element.append(textOrNode);
}
हामी append() मेथड प्रयोग गर्छौं किनभने यसले पाठ वा DOM Nodes लाई अभिभावक तत्वमा जोड्न अनुमति दिन्छ, जुन हाम्रो सबै प्रयोगका लागि उपयुक्त छ।
यदि तपाईंले test खाता प्रयोग गरेर लगइन गर्न प्रयास गर्नुभयो भने, अब तपाईं ड्यासबोर्डमा लेनदेन सूची देख्न सक्नुहुन्छ 🎉।
GitHub Copilot Agent Challenge 🚀
Agent मोड प्रयोग गरेर निम्न चुनौती पूरा गर्नुहोस्:
विवरण: बैंकिङ एपलाई सुधार गरेर लेनदेन खोजी र फिल्टर गर्ने सुविधा कार्यान्वयन गर्नुहोस् जसले प्रयोगकर्ताहरूलाई मिति दायरा, रकम, वा विवरणद्वारा विशिष्ट लेनदेनहरू खोज्न अनुमति दिन्छ।
प्रेरणा: बैंकिङ एपको लागि खोजी सुविधा बनाउनुहोस् जसमा समावेश छ: 1) मिति दायरा (देखि/सम्म), न्यूनतम/अधिकतम रकम, र लेनदेन विवरण कुञ्जीशब्दहरूको लागि इनपुट क्षेत्रहरू भएको खोजी फारम, 2) filterTransactions() नामक एक फङ्सन जसले account.transactions array लाई खोजी मापदण्डको आधारमा फिल्टर गर्छ, 3) updateDashboard() फङ्सनलाई अपडेट गरेर फिल्टर गरिएको नतिजा देखाउनुहोस्, र 4) "Clear Filters" बटन थप्नुहोस् जसले दृश्यलाई रिसेट गर्छ। आधुनिक JavaScript array मेथडहरू जस्तै filter() प्रयोग गर्नुहोस् र खाली खोजी मापदण्डका लागि किनारा केसहरूलाई ह्यान्डल गर्नुहोस्।
🚀 चुनौती
ड्यासबोर्ड पृष्ठलाई वास्तविक बैंकिङ एपजस्तो देखिने बनाउन सँगै काम गर्नुहोस्। यदि तपाईंले पहिले नै आफ्नो एपलाई स्टाइल गर्नुभएको छ भने, media queries प्रयोग गरेर responsive design बनाउने प्रयास गर्नुहोस् जसले डेस्कटप र मोबाइल उपकरणहरूमा राम्रोसँग काम गर्छ।
यहाँ स्टाइल गरिएको ड्यासबोर्ड पृष्ठको उदाहरण छ:
पोस्ट-व्याख्यान क्विज
असाइनमेन्ट
तपाईंको कोडलाई पुनःसंरचना र टिप्पणी गर्नुहोस्
अस्वीकरण:
यो दस्तावेज़ AI अनुवाद सेवा Co-op Translator प्रयोग गरेर अनुवाद गरिएको छ। हामी शुद्धताको लागि प्रयास गर्छौं, तर कृपया ध्यान दिनुहोस् कि स्वचालित अनुवादहरूमा त्रुटिहरू वा अशुद्धताहरू हुन सक्छ। यसको मूल भाषा मा रहेको दस्तावेज़लाई आधिकारिक स्रोत मानिनुपर्छ। महत्वपूर्ण जानकारीको लागि, व्यावसायिक मानव अनुवाद सिफारिस गरिन्छ। यस अनुवादको प्रयोगबाट उत्पन्न हुने कुनै पनि गलतफहमी वा गलत व्याख्याको लागि हामी जिम्मेवार हुने छैनौं।



