কোনও প্রতিশ্রুতি বাতিল করা কি কেবল ত্রুটিযুক্ত মামলার জন্য?


25

আসুন আমরা এই ফাংশনটি প্রমাণীকরণ করি যা প্রতিশ্রুতি দেয় Let's প্রতিশ্রুতি তখন ফলাফলটি সমাধান করে। মিথ্যা এবং সত্য প্রত্যাশিত ফলাফল, যেমনটি আমি এটি দেখছি এবং প্রত্যাখ্যানগুলি কেবল একটি ত্রুটির ক্ষেত্রে হওয়া উচিত। অথবা, প্রমাণীকরণে ব্যর্থতা এমন কোনও বিষয় হিসাবে বিবেচিত যা আপনি প্রতিশ্রুতি প্রত্যাখ্যান করবেন?


তাহলে প্রমাণীকরণ ব্যর্থ হয়েছে, আপনি উচিত rejectএবং মিথ্যা ফিরে না, কিন্তু আপনি যদি মান আশা করছি একটি হতে Bool, তাহলে আপনি ছিলেন সফল এবং আপনি bool সঙ্গে মান নির্বিশেষে সমাধান করা উচিত নয়। প্রতিশ্রুতি মানগুলির জন্য এক প্রকারের প্রক্সি - তারা প্রত্যাবর্তিত মান সংরক্ষণ করে, তাই কেবল যদি মানটি পাওয়া যায় না তবে আপনার উচিত reject। অন্যথায় আপনার উচিত resolve

এটা একটা ভালো প্রশ্ন। এটি প্রতিশ্রুতি নকশার একটি ব্যর্থতার ছোঁয়া দেয়। দুটি ধরণের ত্রুটি রয়েছে, প্রত্যাশিত ব্যর্থতা যেমন কোনও ব্যবহারকারী যখন খারাপ ইনপুট সরবরাহ করে (যেমন লগ ইন করতে ব্যর্থ হয়) এবং অপ্রত্যাশিত ব্যর্থতা, যা কোডে বাগ রয়েছে। প্রতিশ্রুতি নকশা দুটি ধারণাকে একক প্রবাহের সাথে একীভূত করেছে এবং পরিচালনা করার জন্য দুটি পার্থক্য করা কঠিন করে তোলে।
zzzzBov

1
আমি বলব যে সমাধানের অর্থ প্রতিক্রিয়া ব্যবহার করা এবং আপনার প্রয়োগ চালিয়ে যাওয়া, যখন প্রত্যাখ্যান করার অর্থ বর্তমান অপারেশন বাতিল করা (এবং সম্ভবত আবার চেষ্টা করুন বা অন্য কিছু করুন)।

4
এটি নিয়ে চিন্তা করার অন্য উপায় - যদি এটি একটি সিঙ্ক্রোনাস মেথড কল হত তবে আপনি কি নিয়মিত প্রমাণীকরণ ব্যর্থতা (খারাপ ব্যবহারকারীর নাম / পাসওয়ার্ড) হিসাবে ফিরে আসবেন falseবা কোনও ব্যতিক্রম ছোঁড়া হিসাবে ব্যবহার করবেন?
wrschneider

2
পান এপিআই এই একটি ভাল উদাহরণ। thenসার্ভার প্রতিক্রিয়া জানালে এটি সর্বদা ট্রিগার করে - এমনকি কোনও ত্রুটি কোডটি ফিরে পাওয়া গেলেও - এবং আপনাকে অবশ্যই এটি পরীক্ষা করতে হবে response.okcatchহ্যান্ডলারটি কেবল অপ্রত্যাশিত ত্রুটির জন্য ট্রিগার করা হয়েছে ।
কোডিংইন্ট্রিগ

উত্তর:


22

ভাল প্রশ্ন! কোন শক্ত উত্তর নেই। এটা আপনি কি হতে বিবেচনা উপর নির্ভর করে ব্যতিক্রমীপ্রবাহ যে নির্দিষ্ট বিন্দু

একটি প্রত্যাখ্যান Promiseএকই ব্যতিক্রম উত্থাপন। সমস্ত অনাকাঙ্ক্ষিত ফলাফল ব্যতিক্রমী নয় , ত্রুটির ফলাফল । আপনি উভয় উপায়ে আপনার ক্ষেত্রে তর্ক করতে পারেন:

  1. ব্যর্থ প্রমাণীকরণ উচিত , কারণ আহ্বানকারী একটি আশা করছে বিনিময়ে বস্তু, এবং অন্য কিছু এই প্রবাহ একটি ব্যতিক্রম নয়।rejectPromiseUser

  2. ব্যর্থ প্রমাণীকরণ উচিত , এর যদিও , যেহেতু ভুল প্রমাণপত্রাদি প্রদান সত্যিই একটি নয় ব্যতিক্রমী মামলা, এবং কলার সর্বদা প্রবাহ একটি স্থাপিত আশা করা উচিত নয় ।resolvePromisenullUser

নোট করুন যে আমি কলারের পক্ষ থেকে সমস্যাটি দেখছি । তথ্যের প্রবাহে, কলকারী কি তার ক্রিয়াগুলি কোনও User(এবং অন্য কোনও কিছুর ত্রুটি হিসাবে) ফলাফলের প্রত্যাশা করে, বা এই বিশেষ আহ্বানকারীকে অন্যান্য ফলাফলগুলি পরিচালনা করার জন্য এটি কী বোঝায়?

বহু-স্তরযুক্ত সিস্টেমে, তথ্য স্তরগুলির মধ্য দিয়ে প্রবাহিত হওয়ার সাথে সাথে উত্তরটি পরিবর্তন হতে পারে। উদাহরণ স্বরূপ:

  • এইচটিটিপি স্তরটি পুনর্বিবেচনা বলে! অনুরোধটি প্রেরণ করা হয়েছে, সকেটটি পরিষ্কারভাবে বন্ধ হয়ে গেছে এবং সার্ভারটি একটি বৈধ প্রতিক্রিয়া প্রেরণ করেছে। পান এপিআই এই আছে।
  • প্রোটোকল স্তর তারপরে বলে! প্রতিক্রিয়াটির স্থিতি কোডটি 401 ছিল, যা HTTP- র জন্য ঠিক আছে, তবে প্রোটোকলের জন্য নয়!
  • প্রমাণীকরণ স্তরটি বলে, না, পুনরায় সমাধান করুন! এটি ত্রুটিটি ধরা দেয়, যেহেতু 401 একটি ভুল পাসওয়ার্ডের জন্য প্রত্যাশিত স্থিতি এবং কোনও nullব্যবহারকারীকে সমাধান করে ol
  • ইন্টারফেস কন্ট্রোলার কিছুই বলে না, প্রত্যাখ্যান! স্ক্রিনে মডেল প্রদর্শনটি একটি ব্যবহারকারীর নাম এবং অবতারের প্রত্যাশা করেছিল এবং সেই তথ্য ব্যতীত অন্য কোনও কিছু এই মুহুর্তে একটি ত্রুটি।

এই 4-দফা উদাহরণটি স্পষ্টতই জটিল, তবে এটি 2 দফার বর্ণনা দেয়:

  1. কিছু ব্যতিক্রম / প্রত্যাখ্যান কিনা তা আশেপাশের প্রবাহ এবং প্রত্যাশার উপর নির্ভর করে
  2. আপনার প্রোগ্রামের বিভিন্ন স্তর একই ফলাফলকে আলাদাভাবে আচরণ করতে পারে, কারণ তারা প্রবাহের বিভিন্ন পর্যায়ে রয়েছে

আবার, কোন শক্ত উত্তর। ভাবনা ও ডিজাইনের সময়!


6

সুতরাং প্রতিশ্রুতিগুলির একটি দুর্দান্ত সম্পত্তি রয়েছে যা তারা জেএসকে কার্যকরী ভাষা থেকে নিয়ে আসে, যা হ'ল তারা এই Eitherটাইপ-কনস্ট্রাক্টরকে বাস্তবায়িত করে যা যুক্তিসঙ্গতকে একটি শাখা বা অন্যটি নিতে বাধ্য করে অন্য দুটি প্রকার, Leftপ্রকার এবং প্রকারকে একত্রিত Rightকরে শাখা।

data Either x y = Left x | Right y

এখন আপনি সত্যিই লক্ষ্য করছেন যে বাম-হাতের প্রকারটি প্রতিশ্রুতির পক্ষে অস্পষ্ট; আপনি কিছু দিয়ে প্রত্যাখ্যান করতে পারেন। এটি সত্য কারণ জেএস দুর্বলভাবে টাইপ করা হয়েছে তবে আপনি যদি আত্মরক্ষামূলকভাবে প্রোগ্রামিং করেন তবে আপনি সতর্ক হতে চান

কারণটি হ'ল জেএস throwপ্রতিশ্রুতি-পরিচালনা কোড থেকে বিবৃতি নেবে এবং এটিকেও Leftপাশেই বান্ডিল করবে । প্রযুক্তিগতভাবে জেএসে আপনি throwসত্য / মিথ্যা বা একটি স্ট্রিং বা একটি সংখ্যা সহ সমস্ত কিছু করতে পারেন : তবে জাভাস্ক্রিপ্ট কোড ছাড়াও জিনিস ছুঁড়ে দেওয়া হয়throw (যখন আপনি নালাগুলিতে বৈশিষ্ট্য অ্যাক্সেস করার চেষ্টা করার মতো জিনিস করেন) এবং এর জন্য একটি নিষ্পত্তি API আছে ( Errorঅবজেক্ট) । সুতরাং যখন আপনি প্রায় কাছাকাছি পেতে, সাধারণত এই ভুল ত্রুটি Errorবস্তু যে অনুমান করতে সক্ষম হতে দুর্দান্ত । এবং যেহেতু rejectপ্রতিশ্রুতিটির জন্য উপরের বাগগুলি থেকে যে কোনও ত্রুটি বৃদ্ধি পাবে throw, তাই আপনার catchবক্তব্যটির একটি সহজ, সামঞ্জস্যপূর্ণ যুক্তি রাখতে আপনি সাধারণত অন্যান্য ত্রুটিগুলি করতে চান ।

অতএব যদিও আপনি নিজের মধ্যে একটি শর্তযুক্ত রাখতে পারেন এবং মিথ্যা ত্রুটিগুলি সন্ধান করতে পারেনcatch , সেক্ষেত্রে সত্য ঘটনাটি তুচ্ছ,

Either (Either Error ()) ()

আপনি সম্ভবত যুক্তি কাঠামোটিকে পছন্দ করবেন, অন্তত প্রমাণীকরণের সাথে সাথে সরল বুলিয়ান থেকে অবিলম্বে যা আসে তার জন্য :

Either Error Bool

প্রকৃতপক্ষে প্রমাণীকরণের যুক্তির পরবর্তী স্তরটি সম্ভবত Userপ্রমাণীকৃত ব্যবহারকারীযুক্ত কোনও ধরণের অবজেক্টকে ফিরিয়ে দেবে , যাতে এটি হয়ে যায়:

Either Error (Maybe User)

এবং এটি আমি কমবেশি প্রত্যাশা করব: nullব্যবহারকারীর সংজ্ঞা না থাকলে সে ক্ষেত্রে ফিরে আসুন, অন্যথায় ফিরে আসুন {user_id: <number>, permission_to_launch_missiles: <boolean>}। আমি আশা করতে চাই যে লগইন নেই হচ্ছে সাধারণ ক্ষেত্রে উদ্ধারযোগ্য, উদাহরণস্বরূপ, যদি আমরা "নতুন গ্রাহকদের ডেমো" মোড কিছু বাছাই মধ্যে, এবং বাগ যেখানে আমি ঘটনাক্রমে নামক দিয়ে মিশ্র করা উচিত হবে না object.doStuff()যখন object.doStuffছিল undefined

এখন যা বলেছে, আপনি যা করতে চাইতে পারেন তা হ'ল একটি NotLoggedInবা PermissionErrorব্যতিক্রম সংজ্ঞা দেওয়া Error। তারপরে যে বিষয়গুলিতে সত্যই এটি প্রয়োজন তা আপনি লিখতে চান:

function launchMissiles() {
    function actuallyLaunchThem() {
        // stub
    }
    return getAuth().then(auth => {
        if (auth === null) {
            throw new PermissionError('Cannot launch missiles without permission, cannot have permission if not logged in.');
        } else if (auth.permission_to_launch_missiles) {
            return actuallyLaunchThem();
        } else {
            throw new PermissionError(`User ${auth.user_id} does not have permission to launch the missiles.`);
        }
    });
}

3

ত্রুটি

এর ত্রুটি সম্পর্কে কথা বলা যাক।

দুটি ধরণের ত্রুটি রয়েছে:

  • প্রত্যাশিত ত্রুটি
  • অপ্রত্যাশিত ত্রুটি
  • একের পর এক ত্রুটি

প্রত্যাশিত ত্রুটি

প্রত্যাশিত ত্রুটিগুলি এমন রাষ্ট্রগুলিতে হয় যেখানে ভুল জিনিসটি ঘটে তবে আপনি জানেন যে এটি হতে পারে, তাই আপনি এটি মোকাবেলা করেন।

এগুলি ব্যবহারকারীর ইনপুট বা সার্ভারের অনুরোধগুলির মতো জিনিস। আপনি জানেন যে ব্যবহারকারীর কোনও ভুল হতে পারে বা সার্ভারটি ডাউন হয়ে যেতে পারে, তাই আপনি প্রোগ্রামটি আবার ইনপুট চেয়েছে কিনা তা নিশ্চিত করার জন্য আপনি কিছু চেকিং কোড লিখেছেন বা কোনও বার্তা প্রদর্শন করেন বা অন্য যে কোনও আচরণ যথাযথ is

এগুলি হ্যান্ডেল করার পরে পুনরুদ্ধারযোগ্য। যদি হাতছাড়া হয়ে যায় তবে এগুলি অপ্রত্যাশিত ত্রুটি হয়ে যায়।

অপ্রত্যাশিত ত্রুটি

অপ্রত্যাশিত ত্রুটিগুলি (বাগগুলি) এমন রাষ্ট্রগুলিকে বলা হয় যেখানে কোডটি ভুল হওয়ার কারণে ভুল জিনিস ঘটে। আপনি জানেন যে এগুলি শেষ পর্যন্ত ঘটবে, তবে তাদের সাথে কোথায় বা কীভাবে আচরণ করা যায় তা জানার উপায় নেই কারণ সংজ্ঞা অনুসারে তারা অপ্রত্যাশিত।

এগুলি সিনট্যাক্স এবং লজিক ত্রুটির মতো জিনিস। আপনার কোডটিতে একটি টাইপও থাকতে পারে, আপনি ভুল পরামিতিগুলির সাহায্যে কোনও ফাংশন ডাকতে পারেন। এগুলি সাধারণত পুনরুদ্ধারযোগ্য নয়।

try..catch

এর সম্পর্কে কথা বলা যাক try..catch

জাভাস্ক্রিপ্টে, throwসাধারণত ব্যবহৃত হয় না। কোডের উদাহরণগুলির জন্য যদি আপনি ঘুরে দেখেন তবে সেগুলি খুব কম এবং খুব দূরত্বের হতে চলেছে এবং সাধারণত এর লাইনের সাথে কাঠামোযুক্ত হয়

function example(param) {
  if (!Array.isArray(param) {
    throw new TypeError('"param" should be an array!');
  }
  ...
}

এ কারণে, try..catchনিয়ন্ত্রণ প্রবাহের জন্য ব্লকগুলি সমস্ত সাধারণ নয়। প্রত্যাশিত ত্রুটিগুলি এড়ানোর জন্য পদ্ধতিগুলি কল করার আগে কিছু চেক যুক্ত করা সাধারণত বেশ সহজ।

জাভাস্ক্রিপ্টের পরিবেশগুলিও বেশ ক্ষমাশীল, তাই অপ্রত্যাশিত ত্রুটিগুলি প্রায়শই ভালভাবে ফেলে রাখা হয়।

try..catchঅস্বাভাবিক হতে হবে না। কিছু দুর্দান্ত ব্যবহারের কেস রয়েছে যা জাভা এবং সি # এর মতো ভাষাতে বেশি দেখা যায়। জাভা এবং সি # তে টাইপড catchকন্সট্রাক্টসের সুবিধা রয়েছে , যাতে আপনি প্রত্যাশিত এবং অপ্রত্যাশিত ত্রুটির মধ্যে পার্থক্য করতে পারেন:

সি # :
try
{
  var example = DoSomething();
}
catch (ExpectedException e)
{
  DoSomethingElse(e);
}

এই উদাহরণটি অন্যান্য অপ্রত্যাশিত ব্যতিক্রমগুলি প্রবাহিত হতে এবং অন্য কোথাও হ্যান্ডেল করার অনুমতি দেয় (যেমন লগ হওয়া এবং প্রোগ্রামটি বন্ধ করে দিয়ে)।

জাভাস্ক্রিপ্টে, এই নির্মাণটি এর মাধ্যমে প্রতিরূপ করা যেতে পারে:

try {
  let example = doSomething();
} catch (e) {
  if (e instanceOf ExpectedError) {
    DoSomethingElse(e);
  } else {
    throw e;
  }
}

হিসাবে মার্জিত না, এটি অস্বাভাবিক কারণ কারণ অংশ।

ক্রিয়াকলাপ

আসুন ফাংশন সম্পর্কে কথা বলা যাক।

আপনি যদি একক দায়িত্বের নীতিটি ব্যবহার করেন তবে প্রতিটি শ্রেণি এবং ফাংশনটির একক উদ্দেশ্যে কাজ করা উচিত।

উদাহরণস্বরূপ authenticate()কোনও ব্যবহারকারীর প্রমাণীকরণ হতে পারে।

এটি হিসাবে লিখিত হতে পারে:

const user = authenticate();
if (user == null) {
  // keep doing stuff
} else {
  // handle expected error
}

বিকল্পভাবে এটি লিখিত হতে পারে:

try {
  const user = authenticate();
  // keep doing stuff
} catch (e) {
  if (e instanceOf AuthenticationError) {
    // handle expected error
  } else {
    throw e;
  }
}

উভয়ই গ্রহণযোগ্য।

অঙ্গীকার

প্রতিশ্রুতি সম্পর্কে কথা বলা যাক।

প্রতিশ্রুতি একটি অ্যাসিনক্রোনাস ফর্ম হয় try..catch। কলিং new Promiseবা Promise.resolveআপনার tryকোড শুরু । কল করে throwবা Promise.rejectআপনাকে catchকোডে প্রেরণ করে ।

Promise.resolve(value)   // try
  .then(doSomething)     // try
  .then(doSomethingElse) // try
  .catch(handleError)    // catch

কোনও ব্যবহারকারীর অনুমোদনের জন্য আপনার যদি অ্যাসিক্রোনাস ফাংশন থাকে তবে আপনি এটি লিখতে পারেন:

authenticate()
  .then((user) => {
    if (user == null) {
      // keep doing stuff
    } else {
      // handle expected error
    }
  });

বিকল্পভাবে এটি লিখিত হতে পারে:

authenticate()
  .then((user) => {
    // keep doing stuff
  })
  .catch((e) => {
    if (e instanceOf AuthenticationError) {
      // handle expected error
    } else {
      throw e;
    }
  });

উভয়ই গ্রহণযোগ্য।

পাখির

বাসা বাঁধার কথা বলি।

try..catchনেস্টেড হতে পারে। আপনার authenticate()পদ্ধতি অভ্যন্তরীণভাবে একটি try..catchব্লক থাকতে পারে যেমন:

try {
  const credentials = requestCredentialsFromUser();
  const user = getUserFromServer(credentials);
} catch (e) {
  if (e instanceOf CredentialsError) {
    // handle failure to request credentials
  } else if (e instanceOf ServerError) {
    // handle failure to get data from server
  } else {
    throw e; // no idea what happened
  }
}

তেমনি প্রতিশ্রুতি বাসা বাঁধতে পারে। আপনার অ্যাসিঙ্ক authenticate()পদ্ধতিটি অভ্যন্তরীণভাবে প্রতিশ্রুতিগুলি ব্যবহার করতে পারে:

requestCredentialsFromUser()
  .then(getUserFromServer)
  .catch((e) => {
    if (e instanceOf CredentialsError) {
      // handle failure to request credentials
    } else if (e instanceOf ServerError) {
      // handle failure to get data from server
    } else {
      throw e; // no idea what happened
    }
  });

তাহলে উত্তর কী?

ঠিক আছে, আমি মনে করি আসলে এই প্রশ্নের উত্তর দেওয়ার সময় এসেছে:

প্রমাণীকরণে ব্যর্থতা এমন কোনও বিষয় হিসাবে বিবেচিত যা আপনি প্রতিশ্রুতি প্রত্যাখ্যান করবেন?

আমি যে সহজ উত্তর দিতে পারি তা হ'ল যে কোনও প্রতিশ্রুতি আপনি যে কোনও জায়গায় প্রত্যাখ্যান করতে পারেন অন্যথায় throwযদি আপনি এটির সিঙ্ক্রোনাস কোড হয় তবে কোনও ব্যতিক্রম চান ।

ifআপনার thenবিবৃতিতে কয়েকটি পরীক্ষা করে যদি আপনার নিয়ন্ত্রণ প্রবাহ সহজ হয় তবে কোনও প্রতিশ্রুতি প্রত্যাখ্যান করার দরকার নেই।

যদি আপনার নিয়ন্ত্রণ প্রবাহ কোনও প্রতিশ্রুতি প্রত্যাখ্যান করে এবং তারপরে আপনার ত্রুটি পরিচালনার কোডে ত্রুটিগুলির প্রকারগুলি পরীক্ষা করে যদি সহজ হয় তবে তার পরিবর্তে এটি করুন।


0

আমি jQuery UI ডায়ালগ বাক্সগুলির "বাতিল" ক্রিয়াকে প্রতিনিধিত্ব করতে একটি প্রতিশ্রুতির "প্রত্যাখ্যান" শাখা ব্যবহার করেছি। এটি "সমাধান" শাখাটি ব্যবহার করার চেয়ে প্রাকৃতিক বলে মনে হয়েছিল, কমপক্ষে নয় কারণ ডায়ালগ বাক্সে প্রায়শই একাধিক "বন্ধ" বিকল্প রয়েছে।


আমি জানি বেশিরভাগ পিউরিস্ট আপনার সাথে একমত নন।

0

প্রতিশ্রুতি সামলানো কম-বেশি "যদি" শর্তের মতো। প্রমাণীকরণ ব্যর্থ হলে আপনি "সমাধান" করতে বা "প্রত্যাখ্যান" করতে চান তা আপনার বিষয়।


1
প্রতিশ্রুতি একটি অ্যাসিনক্রোনাস try..catch, না if
zzzzBov

@ZzBox সুতরাং সেই যুক্তি অনুসারে আপনার একটি প্রতিশ্রুতি অ্যাসিঙ্ক্রোনাস হিসাবে ব্যবহার করা উচিত try...catchএবং সহজভাবে বলা উচিত যে আপনি যদি ফলাফলটি সম্পন্ন করতে এবং ফলাফল পেতে সক্ষম হয়েছিলেন তবে আপনি যে মানটি পেয়েছিলেন তা নির্বিশেষে সমাধান করা উচিত, অন্যথায় আপনাকে প্রত্যাখ্যান করা উচিত?

@ কিছু না কিছু, আপনি আমার যুক্তিটি ভুল ধারণা দিয়ে গেছেন। try { if (!doSomething()) throw whatever; doSomethingElse() } catch { ... }পুরোপুরি সূক্ষ্ম, তবে যে কনস্ট্রাক্টটি Promiseপ্রতিনিধিত্ব করে তা হ'ল try..catchঅংশ, অংশ নয় if
zzzzBov

@zzzzBov আমি পেয়েছি সমস্ত ন্যায্যতার সাথে :) আমি সাদৃশ্যটি পছন্দ করি। তবে আমার যুক্তিটি হ'ল যদি doSomething()ব্যর্থ হয় তবে তা ছোঁড়াবে, তবে এটিতে আপনার প্রয়োজনীয় মানটি থাকতে পারে না (আপনার ifউপরেরটি আপনার ধারণার অংশ না হিসাবে এটি কিছুটা বিভ্রান্তিকর :))। যদি কেবল নিক্ষেপ করার কোনও কারণ থাকে (সাদৃশ্যতে) তবে আপনাকে পরীক্ষা বাতিল করতে হবে, যদি পরীক্ষাটি ব্যর্থ হয়। যদি পরীক্ষাটি সফল হয় তবে তার মান ইতিবাচক কিনা তা নির্বিশেষে আপনার সর্বদা সমাধান করা উচিত?

@ যে কোনও জায়গায়, আমি একটি উত্তর লেখার সিদ্ধান্ত নিয়েছি (এটি ধরে নেওয়া দীর্ঘ সময় যথেষ্ট উন্মুক্ত থাকে), কারণ মন্তব্যগুলি আমার মত প্রকাশের জন্য যথেষ্ট নয়।
zzzzBov
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.