Apple প্ল্যাটফর্মে ডেটার তালিকা নিয়ে কাজ করা

FIRDatabaseReference পান

ডেটাবেস থেকে ডেটা পড়তে বা লিখতে, আপনার FIRDatabaseReference-এর ইনস্ট্যান্স প্রয়োজন:

Swift

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
var ref: DatabaseReference!

ref = Database.database().reference()

Objective-C

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
@property (strong, nonatomic) FIRDatabaseReference *ref;

self.ref = [[FIRDatabase database] reference];

পড়া ও লেখার তালিকা

ডেটার তালিকায় যোগ করুন

মাল্টিইউজার অ্যাপ্লিকেশনে কোনও তালিকায় ডেটা যোগ করতে childByAutoId পদ্ধতি ব্যবহার করুন। নির্দিষ্ট Firebase রেফারেন্সে নতুন চাইল্ড যোগ করা হলে, childByAutoId পদ্ধতিটি প্রতিবার একটি অনন্য কী তৈরি করে। তালিকার প্রতিটি নতুন এলিমেন্টের জন্য এইসব অটোমেটিক জেনারেট করা 'কী' ব্যবহার করে, একাধিক ক্লায়েন্ট একই সময়ে একই লোকেশনে চাইল্ড যোগ করতে পারবেন এবং এর ফলে লেখার ক্ষেত্রে কোনও বিরোধ হবে না। childByAutoId-এর মাধ্যমে তৈরি করা অনন্য কী টাইমস্ট্যাম্পের উপর ভিত্তি করে তৈরি করা হয়, তাই তালিকার আইটেমগুলি অটোমেটিক কালানুক্রমিকভাবে সাজানো হয়।

আপনি childByAutoId পদ্ধতি দ্বারা রিটার্ন করা নতুন ডেটার রেফারেন্স ব্যবহার করতে পারেন যাতে চাইল্ডের অটোমেটিক জেনারেট করা কী-এর ভ্যালু পাওয়া যায় বা চাইল্ডের জন্য ডেটা সেট করা যায়। childByAutoId রেফারেন্সে getKey কল করলে অটোমেটিক জেনারেট হওয়া কী রিটার্ন করে।

আপনার ডেটা স্ট্রাকচার ফ্ল্যাটেন করার প্রসেস সহজ করতে, আপনি এইসব অটোমেটিক জেনারেট করা কী ব্যবহার করতে পারেন। আরও তথ্যের জন্য, ডেটা ফ্যান-আউট উদাহরণ দেখুন।

চাইল্ড ইভেন্টের জন্য শুনুন

কোনও নোডের চাইল্ডে হওয়া নির্দিষ্ট অপারেশনের উত্তরে চাইল্ড ইভেন্ট ট্রিগার হয়, যেমন childByAutoId পদ্ধতির মাধ্যমে নতুন চাইল্ড যোগ করা বা updateChildValues পদ্ধতির মাধ্যমে চাইল্ড আপডেট করা।

ইভেন্টের প্রকার সাধারণ ব্যবহার
FIRDataEventTypeChildAdded আইটেমের তালিকা ফিরিয়ে আনা বা আইটেমের তালিকায় নতুন কিছু যোগ করা হয়েছে কিনা তা শোনা। এই ইভেন্টটি প্রতিটি বিদ্যমান চাইল্ডের জন্য একবার ট্রিগার করা হয় এবং তারপরে আবার প্রতিবার নির্দিষ্ট পাথে একটি নতুন চাইল্ড যোগ করা হয়। লিসনারকে নতুন চাইল্ডের ডেটা সহ স্ন্যাপশট পাস করা হয়।
FIRDataEventTypeChildChanged তালিকায় থাকা আইটেমে পরিবর্তন করা হলে তা শোনে। চাইল্ড নোড যেকোনও সময় পরিবর্তন করা হলে এই ইভেন্ট ট্রিগার করা হয়। এর মধ্যে চাইল্ড নোডের ডিসেন্ড্যান্টে করা যেকোনও পরিবর্তন অন্তর্ভুক্ত। ইভেন্ট লিসনারে পাস করা স্ন্যাপশটে চাইল্ডের জন্য আপডেট করা ডেটা থাকে।
FIRDataEventTypeChildRemoved তালিকা থেকে আইটেম সরিয়ে দেওয়ার সময় শুনুন। এই ইভেন্টটি ট্রিগার হয় যখন একটি ইমিডিয়েট চাইল্ড সরানো হয়। কলব্যাক ব্লকে পাস করা স্ন্যাপশটে সরানো চাইল্ডের ডেটা থাকে।
FIRDataEventTypeChildMoved ক্রমানুসারে সাজানো তালিকায় আইটেমের ক্রম পরিবর্তন হলে তা শুনুন। আপডেটের কারণে চাইল্ডের ক্রম পরিবর্তন হলে এই ইভেন্ট ট্রিগার হয়। এটি queryOrderedByChild বা queryOrderedByValue দ্বারা অর্ডার করা ডেটার সাথে ব্যবহার করা হয়।

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

Swift

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
// Listen for new comments in the Firebase database
commentsRef.observe(.childAdded, with: { (snapshot) -> Void in
  self.comments.append(snapshot)
  self.tableView.insertRows(
    at: [IndexPath(row: self.comments.count - 1, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})
// Listen for deleted comments in the Firebase database
commentsRef.observe(.childRemoved, with: { (snapshot) -> Void in
  let index = self.indexOfMessage(snapshot)
  self.comments.remove(at: index)
  self.tableView.deleteRows(
    at: [IndexPath(row: index, section: self.kSectionComments)],
    with: UITableView.RowAnimation.automatic
  )
})

Objective-C

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
// Listen for new comments in the Firebase database
[_commentsRef
              observeEventType:FIRDataEventTypeChildAdded
              withBlock:^(FIRDataSnapshot *snapshot) {
                [self.comments addObject:snapshot];
                [self.tableView insertRowsAtIndexPaths:@[
                  [NSIndexPath indexPathForRow:self.comments.count - 1 inSection:kSectionComments]
                ]
                                      withRowAnimation:UITableViewRowAnimationAutomatic];
              }];
// Listen for deleted comments in the Firebase database
[_commentsRef
 observeEventType:FIRDataEventTypeChildRemoved
 withBlock:^(FIRDataSnapshot *snapshot) {
   int index = [self indexOfMessage:snapshot];
   [self.comments removeObjectAtIndex:index];
   [self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:kSectionComments]]
                         withRowAnimation:UITableViewRowAnimationAutomatic];
 }];

ভ্যালু ইভেন্ট শুনুন

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

ডেটার তালিকায় FIRDataEventTypeValue অবজারভার অ্যাটাচ করলে, সিঙ্গেল DataSnapshot হিসেবে ডেটার সম্পূর্ণ তালিকা রিটার্ন করবে, যা আপনি পরে লুপ ওভার করে প্রতিটি চাইল্ড অ্যাক্সেস করতে পারবেন।

এমনকি কোয়েরির জন্য শুধুমাত্র একটি ম্যাচ থাকলেও, স্ন্যাপশটটি এখনও একটি তালিকা; এটিতে শুধুমাত্র একটি আইটেম রয়েছে। আইটেম অ্যাক্সেস করতে, আপনাকে ফলাফলের উপর লুপ করতে হবে:

Swift

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
_commentsRef.observe(.value) { snapshot in
  for child in snapshot.children {
    ...
  }
}

Objective-C

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
[_commentsRef
              observeEventType:FIRDataEventTypeValue
              withBlock:^(FIRDataSnapshot *snapshot) {
                // Loop over children
                NSEnumerator *children = [snapshot children];
                FIRDataSnapshot *child;
                while (child = [children nextObject]) {
                  // ...
                }
              }];

এই প্যাটার্নটি তখন উপযোগী হতে পারে যখন আপনি একটি তালিকায় সমস্ত চাইল্ডকে একটি অপারেশনে আনতে চান, অতিরিক্ত চাইল্ড যোগ করা ইভেন্টগুলি শোনার পরিবর্তে।

ডেটা সাজানো এবং ফিল্টার করা

আপনি Realtime Database FIRDatabaseQuery ক্লাস ব্যবহার করে কী, ভ্যালু বা চাইল্ডের ভ্যালু অনুযায়ী সাজানো ডেটা ফিরিয়ে আনতে পারবেন। এছাড়াও, আপনি সাজানো ফলাফলকে নির্দিষ্ট সংখ্যক ফলাফল বা কী বা মানের রেঞ্জে ফিল্টার করতে পারেন।

ডেটা সাজান

সাজানো ডেটা ফিরিয়ে আনতে, ফলাফল কীভাবে সাজানো হবে তা নির্ধারণ করতে অর্ডার-বাই মেথডের মধ্যে একটি নির্দিষ্ট করে শুরু করুন:

পদ্ধতি ব্যবহার
queryOrderedByKey চাইল্ড কী অনুযায়ী ফলাফল সাজান।
queryOrderedByValue চাইল্ড ভ্যালু অনুযায়ী ফলাফল সাজান।
queryOrderedByChild নির্দিষ্ট চাইল্ড কী বা নেস্টেড চাইল্ড পাথের ভ্যালু অনুযায়ী ফলাফল সাজান।

আপনি একবারে শুধুমাত্র একটি অর্ডার-বাই মেথড ব্যবহার করতে পারবেন। একই কোয়েরিতে একাধিকবার অর্ডার-বাই মেথড কল করলে সমস্যা হয়।

নিম্নলিখিত উদাহরণে দেখানো হয়েছে যে কীভাবে আপনি কোনও ব্যবহারকারীর সেরা পোস্টের তালিকা স্টার সংখ্যার ভিত্তিতে সাজিয়ে দেখতে পারেন:

Swift

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
// My top posts by number of stars
let myTopPostsQuery = ref.child("user-posts").child(getUid()).queryOrdered(byChild: "starCount")

Objective-C

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
// My top posts by number of stars
FIRDatabaseQuery *myTopPostsQuery = [[[self.ref child:@"user-posts"]
                                      child:[super getUid]]
                                     queryOrderedByChild:@"starCount"];

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

queryOrderedByChild মেথডে কল করার মাধ্যমে চাইল্ড কী নির্দিষ্ট করা হয় যার ভিত্তিতে ফলাফল সাজানো হয়। এই উদাহরণে, প্রতিটি পোস্টে "starCount" চাইল্ডের ভ্যালু অনুযায়ী পোস্টগুলি সাজানো হয়েছে। আপনার কাছে যদি এই ধরনের ডেটা থাকে, তাহলে নেস্টেড চিলড্রেন অনুযায়ীও কোয়েরি সাজানো যেতে পারে:

"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},

এই ক্ষেত্রে, আমরা আমাদের লিস্টের এলিমেন্টগুলিকে metrics কী-এর অধীনে নেস্ট করা ভ্যালু অনুযায়ী সাজাতে পারি, যার জন্য আমাদের queryOrderedByChild কলে নেস্ট করা চাইল্ডের রিলেটিভ পাথ উল্লেখ করতে হবে।

Swift

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
 
let postsByMostPopular = ref.child("posts").queryOrdered(byChild: "metrics/views")

Objective-C

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
 
FIRDatabaseQuery *postsByMostPopular = [[ref child:@"posts"] queryOrderedByChild:@"metrics/views"];

অন্যান্য ধরনের ডেটা কীভাবে সাজানো হয় সেই সম্পর্কে আরও জানতে, কোয়েরি ডেটা কীভাবে সাজানো হয় দেখুন।

ডেটা ফিল্টার করা হচ্ছে

ডেটা ফিল্টার করতে, কোয়েরি তৈরি করার সময় আপনি সীমা বা রেঞ্জ মেথডের যেকোনও একটির সাথে অর্ডার-বাই মেথড একত্রিত করতে পারেন।

পদ্ধতি ব্যবহার
queryLimitedToFirst ফলাফলের ক্রমানুসারে সাজানো তালিকার শুরু থেকে সর্বাধিক কতগুলি আইটেম দেখানো হবে তা সেট করে।
queryLimitedToLast ফলাফলের ক্রমানুসারে সাজানো তালিকার শেষ থেকে সর্বাধিক কতগুলি আইটেম ফেরত দেওয়া হবে তা সেট করে।
queryStartingAtValue বেছে নেওয়া অর্ডার-বাই মেথডের উপর নির্ভর করে, নির্দিষ্ট করা কী বা ভ্যালুর চেয়ে বড় বা সমান আইটেম ফেরত পাঠায়।
queryStartingAfterValue বেছে নেওয়া অর্ডার-বাই মেথডের উপর নির্ভর করে, নির্দিষ্ট কী বা ভ্যালুর থেকে বেশি আইটেম ফিরিয়ে দিন।
queryEndingAtValue বেছে নেওয়া অর্ডার-বাই মেথডের উপর নির্ভর করে, নির্দিষ্ট করা কী বা ভ্যালুর থেকে কম বা সমান আইটেম ফেরত দেয়।
queryEndingBeforeValue বেছে নেওয়া অর্ডার-বাই মেথডের উপর নির্ভর করে, নির্দিষ্ট কী বা ভ্যালুর থেকে কম আইটেম রিটার্ন করে।
queryEqualToValue বেছে নেওয়া অর্ডার-বাই মেথডের উপর নির্ভর করে নির্দিষ্ট কী বা ভ্যালুর সমান আইটেম ফেরত দেয়।

অর্ডার-বাই মেথডের মতো নয়, আপনি একাধিক সীমা বা রেঞ্জ ফাংশন একত্রিত করতে পারেন। যেমন, আপনি queryStartingAtValue এবং queryEndingAtValue পদ্ধতি একসাথে ব্যবহার করে ফলাফলকে নির্দিষ্ট রেঞ্জের মধ্যে সীমাবদ্ধ করতে পারেন।

ফলাফলের সংখ্যা সীমিত করুন

আপনি queryLimitedToFirst এবং queryLimitedToLast পদ্ধতি ব্যবহার করে প্রদত্ত কলব্যাকের জন্য সিঙ্ক করা হবে এমন চাইল্ডের সর্বাধিক সংখ্যা সেট করতে পারবেন। যেমন, আপনি যদি queryLimitedToFirst ব্যবহার করে ১০০-এর সীমা সেট করেন, তাহলে প্রাথমিকভাবে আপনি সর্বাধিক ১০০টি FIRDataEventTypeChildAdded কলব্যাক পাবেন। আপনার Firebase ডেটাবেসে ১০০টির কম আইটেম স্টোর করা থাকলে, প্রতিটি আইটেমের জন্য একটি FIRDataEventTypeChildAdded কলব্যাক ফায়ার হয়।

আইটেম পরিবর্তন হওয়ার সাথে সাথে, আপনি কোয়েরিতে প্রবেশ করা আইটেমের জন্য FIRDataEventTypeChildAddedটি কলব্যাক এবং কোয়েরি থেকে বাদ পড়া আইটেমের জন্য FIRDataEventTypeChildRemovedটি কলব্যাক পাবেন যাতে মোট সংখ্যা ১০০ থাকে।

নিম্নলিখিত উদাহরণ থেকে বোঝা যায় যে কীভাবে একটি ব্লগিং অ্যাপের উদাহরণ সব ব্যবহারকারীর করা ১০০টি সবচেয়ে সাম্প্রতিক পোস্টের তালিকা উদ্ধার করতে পারে:

Swift

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
let recentPostsQuery = (ref?.child("posts").queryLimited(toFirst: 100))!

Objective-C

মনে রাখবেন: এই Firebase প্রোডাক্ট অ্যাপ ক্লিপ টার্গেটে উপলভ্য নয়।
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
FIRDatabaseQuery *recentPostsQuery = [[self.ref child:@"posts"] queryLimitedToFirst:100];

'কী' বা ভ্যালু অনুযায়ী ফিল্টার করুন

আপনি queryStartingAtValue, queryStartingAfterValue, queryEndingAtValue, queryEndingBeforeValue, এবং queryEqualToValue ব্যবহার করে কোয়েরির জন্য ইচ্ছামতো শুরু, শেষ এবং সমতুল্য পয়েন্ট বেছে নিতে পারেন। এটি ডেটা পেজিনেট করার জন্য বা নির্দিষ্ট ভ্যালু আছে এমন চাইল্ড সহ আইটেম খুঁজে পাওয়ার জন্য উপযোগী হতে পারে।

কোয়েরি ডেটা কীভাবে সাজানো হয়

এই বিভাগে ব্যাখ্যা করা হয়েছে যে কীভাবে FIRDatabaseQuery ক্লাসে প্রতিটি অর্ডার-বাই মেথড অনুযায়ী ডেটা সাজানো হয়।

queryOrderedByKey

আপনার ডেটা সাজাতে queryOrderedByKey ব্যবহার করার সময়, ডেটা 'কী' অনুযায়ী ঊর্ধ্বক্রমে ফেরত দেওয়া হয়।

  1. যেসব চিলড্রেনকে ৩২-বিট ইন্টিজার হিসেবে পার্স করা যায়, সেগুলি প্রথমে আসে এবং ছোট থেকে বড় হিসেবে সাজানো হয়।
  2. এর পরে স্ট্রিং ভ্যালু কী হিসেবে আছে এমন চাইল্ড আসে, যা লেক্সিকোগ্রাফিক্যালি ছোট থেকে বড় হিসেবে সাজানো থাকে।

queryOrderedByValue

queryOrderedByValue ব্যবহার করার সময়, বাচ্চাদের তাদের ভ্যালু অনুযায়ী সাজানো হয়। ক্রমের মাপকাঠি queryOrderedByChild-এর মতোই, তবে নির্দিষ্ট চাইল্ড কী-এর মানের পরিবর্তে নোডের মান ব্যবহার করা হয়।

queryOrderedByChild

queryOrderedByChild ব্যবহার করার সময়, নির্দিষ্ট চাইল্ড কী সহ ডেটা নিম্নলিখিত ক্রমে সাজানো হয়:

  1. নির্দিষ্ট চাইল্ড কী-এর জন্য nil ভ্যালু সহ চিলড্রেন প্রথমে আসে।
  2. নির্দিষ্ট চাইল্ড কী-এর জন্য false ভ্যালু সহ চাইল্ড এর পরে আসে। একাধিক চাইল্ডের ভ্যালু false হলে, সেগুলি কী অনুযায়ী লেক্সিকোগ্রাফিক্যালি সাজানো হয়।
  3. নির্দিষ্ট চাইল্ড কী-এর জন্য true ভ্যালু সহ চাইল্ড এর পরে আসে। একাধিক চাইল্ডের ভ্যালু true হলে, সেগুলি কী অনুযায়ী লেক্সিকোগ্রাফিক্যালি সাজানো হয়।
  4. এরপরে সংখ্যাবাচক মান সহ চাইল্ড আসে, যা ছোট থেকে বড় ক্রমে সাজানো থাকে। যদি একাধিক চাইল্ড নোডের জন্য একই সংখ্যাসূচক মান থাকে, তাহলে সেগুলি কী অনুসারে সাজানো হয়।
  5. স্ট্রিং সংখ্যার পরে আসে এবং ছোট থেকে বড় ক্রমে অভিধানের ক্রম অনুযায়ী সাজানো হয়। একাধিক চাইল্ডের জন্য নির্দিষ্ট চাইল্ড নোডের ভ্যালু একই হলে, সেগুলিকে কী অনুযায়ী লেক্সিকোগ্রাফিক্যালি সাজানো হয়।
  6. অবজেক্ট শেষে আসে এবং কী অনুযায়ী ছোট থেকে বড় ক্রমে সাজানো হয়।

লিসনার ডিটাচ করুন

আপনি কোনও ViewController থেকে বেরিয়ে গেলে, পর্যবেক্ষকরা অটোমেটিক ডেটা সিঙ্ক করা বন্ধ করেন না। কোনও অবজারভার সঠিকভাবে সরানো না হলে, এটি লোকাল মেমরিতে ডেটা সিঙ্ক করা চালিয়ে যায় এবং ইভেন্ট হ্যান্ডলার ক্লোজারে ক্যাপচার করা যেকোনও অবজেক্ট ধরে রাখে, যার ফলে মেমরি লিক হতে পারে। পর্যবেক্ষকের আর প্রয়োজন না থাকলে, removeObserverWithHandle পদ্ধতিতে সংশ্লিষ্ট FIRDatabaseHandle পাস করে এটি সরিয়ে দিন।

আপনি কোনও রেফারেন্সে কলব্যাক ব্লক যোগ করলে, একটি FIRDatabaseHandle রিটার্ন করা হয়। কলব্যাক ব্লক সরাতে এইসব হ্যান্ডেল ব্যবহার করা যেতে পারে।

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

কোনও লিসেনারে removeObserverWithHandle বা removeAllObservers কল করলে তার চাইল্ড নোডে রেজিস্টার করা লিসেনার অটোমেটিক মুছে যায় না; সেগুলি মুছে দেওয়ার জন্য আপনাকে সেইসব রেফারেন্স বা হ্যান্ডেল ট্র্যাক করতে হবে।

পরবর্তী ধাপ