ফাইলগুলি ইতিমধ্যে দু'দিকে থাকলে ডিরেক্টরি কাঠামো সিঙ্ক করার কোনও উপায়?


24

আমার একই ফাইলগুলির সাথে দুটি ড্রাইভ রয়েছে তবে ডিরেক্টরি কাঠামো সম্পূর্ণ আলাদা।

গন্তব্য পাশে থাকা সমস্ত ফাইলকে 'সরানোর' কোনও উপায় আছে যাতে তারা উত্সের কাঠামোর সাথে মেলে? একটি স্ক্রিপ্ট দিয়ে সম্ভবত?

উদাহরণস্বরূপ, ড্রাইভ এ রয়েছে:

/foo/bar/123.txt
/foo/bar/234.txt
/foo/bar/dir/567.txt

যেখানে ড্রাইভ বি রয়েছে:

/some/other/path/123.txt
/bar/doo2/wow/234.txt
/bar/doo/567.txt

প্রশ্নযুক্ত ফাইলগুলি বিশাল (800 গিগাবাইট), তাই আমি সেগুলি পুনরায় অনুলিপি করতে চাই না; আমি কেবল প্রয়োজনীয় ডিরেক্টরিগুলি তৈরি করে এবং ফাইলগুলি সরিয়ে নিয়ে কাঠামোটি সিঙ্ক করতে চাই।

আমি একটি পুনরাবৃত্ত স্ক্রিপ্টের কথা ভাবছিলাম যা গন্তব্যটিতে প্রতিটি উত্স ফাইল খুঁজে পেতে পারে, তারপরে এটি একটি ম্যাচিং ডিরেক্টরিতে সরিয়ে নিয়ে প্রয়োজনে এটি তৈরি করে creating তবে - এটাই আমার যোগ্যতার বাইরে!

এখানে আরেকটি মার্জিত সমাধান দেওয়া হয়েছিল: /superuser/237387/any-way-to-sync-directory-st संरचना-when-the-files-are-already-on-both-sides/ 238086


আপনি কি নিশ্চিত যে নামটি কোনও ফাইলের বিষয়বস্তু অনন্যভাবে নির্ধারণ করে, অন্যথায় আপনার চেকসাম দ্বারা ফাইলের তুলনা করা বিবেচনা করা উচিত।
কাস্টারমা

উত্তর:


11

আমি গিলসের সাথে যাব এবং হেসেন জে-র পরামর্শ অনুসারে ইউনিসনকে নির্দেশ করব । ইউনিসন ড্রপবক্সের 20 বছর আগে ড্রপবক্স ছিল। রক সলিড কোড যা প্রচুর লোক (আমার অন্তর্ভুক্ত) প্রতিদিন ব্যবহার করে - শিখতে খুব সার্থক। তবুও, joinএটি পেতে পারে এমন সমস্ত প্রচার দরকার :)


এটি কেবলমাত্র অর্ধেক উত্তর, তবে আমাকে কাজে ফিরে যেতে হবে :)

মূলত, আমি স্বল্প-পরিচিত joinইউটিলিটিটি প্রদর্শন করতে চেয়েছিলাম যা কেবল এটি করে: কিছু ক্ষেত্রে দুটি টেবিলের সাথে যোগ দেয়।

প্রথমে স্পেস সহ ফাইলের নাম সহ একটি পরীক্ষার কেস সেট আপ করুন:

for d in a b 'c c'; do mkdir -p "old/$d"; echo $RANDOM > "old/${d}/${d}.txt"; done
cp -r old new

(কিছু ডিরেক্টরি এবং / অথবা ফাইলের নাম সম্পাদনা করুন new)।

এখন, আমরা প্রতিটি ডিরেক্টরিতে একটি মানচিত্র: হ্যাশ -> ফাইলের নাম তৈরি করতে চাই এবং তারপরে joinএকই হ্যাশ দিয়ে ফাইলগুলি মেলানোর জন্য ব্যবহার করতে চাই। মানচিত্রটি তৈরি করতে, নিম্নলিখিতগুলিতে রাখুন makemap.sh:

find "$1" -type f -exec md5 -r "{}" \; \
  | sed "s/\([a-z0-9]*\) ${1}\/\(.*\)/\1 \"\2\"/" \

makemap.sh 'হ্যাশ "ফাইলের নাম"' ফর্মের লাইনগুলি সহ একটি ফাইলকে ছড়িয়ে দেয়, তাই আমরা কেবল প্রথম কলামে যোগদান করি:

join <(./makemap.sh 'old') <(./makemap.sh 'new') >moves.txt

এটি এর moves.txtমতো দেখতে উত্পন্ন করে :

49787681dd7fcc685372784915855431 "a/a.txt" "bar/a.txt"
bfdaa3e91029d31610739d552ede0c26 "c c/c c.txt" "c c/c c.txt"

পরবর্তী পদক্ষেপটি আসলে চালগুলি করা হবে, তবে আমার প্রচেষ্টা উদ্ধৃতিতে আটকে গেল ... mv -iএবং এটি কার্যকর mkdir -pহওয়া উচিত।


দুঃখিত, আমি এর কোন কিছুই বুঝতে পারছি না!
ড্যান

1
joinসত্যিই আকর্ষণীয়। আমার মনোযোগ এটি আনয়ন করার জন্য ধন্যবাদ।
স্টিভেন ডি

@Dan। দুঃখিত। সমস্যাটি হ'ল আমি জানি না যে আপনার ফাইলের নাম সম্পর্কে আমি কী অনুমান করতে পারি। অনুমান ছাড়াই স্ক্রিপ্ট করা মজাদার নয়, বিশেষত এই ক্ষেত্রে যেখানে আমি ফাইলের নাম dwheeler.com/essays/fixing-unix-linux-filenames.html এ ফাইলের আউটপুট বেছে নিয়েছি
জানুস

1
এটি সম্ভবত অনেক সময় নষ্ট করে (এবং সিপিইউ লোড) কারণ এই বিশাল ফাইলগুলি এমডি 5 হ্যাশগুলি তৈরি করার জন্য পুরোপুরি পড়তে হবে। যদি ফাইলের নাম এবং ফাইলের আকারের মিল মেলে তবে সম্ভবত ফাইলগুলি হ্যাশ করার জন্য ওভারকিল। হ্যাশিং দ্বিতীয় ধাপে করা উচিত এবং কেবলমাত্র ফাইল বা ফাইলের জন্য যা নাম বা আকারে কমপক্ষে একটি (একই ডিস্কে) মেলে।
Hauke ​​Lage

আপনি যে ফাইলগুলি joinইনপুট হিসাবে ব্যবহার করেন সেগুলি সাজানোর দরকার নেই ?
সিজেএম

8

একত্রীকরণ নামে একটি ইউটিলিটি রয়েছে:

http://www.cis.upenn.edu/~bcpierce/unison/

সাইট থেকে বিবরণ:

ইউনিসন হ'ল ইউনিক্স এবং উইন্ডোজের ফাইল-সিঙ্ক্রোনাইজেশন সরঞ্জাম। এটি ফাইল এবং ডিরেক্টরিগুলির সংগ্রহের দুটি প্রতিলিপি বিভিন্ন হোস্টে (বা একই হোস্টের বিভিন্ন ডিস্ক) সংরক্ষণ করার অনুমতি দেয়, পৃথকভাবে সংশোধন করা হয় এবং তারপরে প্রতিটি প্রতিরূপের পরিবর্তনগুলি অপরটিতে প্রচারের মাধ্যমে আপডেট করে আনা হয়।

নোট করুন যে ইউনিসন কমপক্ষে একটি শিকড়ের দূরবর্তী থেকে দূরে থাকলে প্রথমে চালিত ফাইলগুলি সনাক্ত করে, সুতরাং আপনি স্থানীয় ফাইলগুলি সিঙ্ক্রোনাইজ ssh://localhost/path/to/dirকরলেও মূলগুলির মধ্যে একটি হিসাবে ব্যবহার করুন ।


@ গিলস: আপনি কি নিশ্চিত? আমি সমস্ত কিছুর জন্য একত্রীকরণ ব্যবহার করি এবং প্রায়শই এটিকে এমন ফাইলগুলিতে স্পট করতে দেখি যা পুনরায় নামকরণ এবং / অথবা অনেক দূরে সরিয়ে নেওয়া হয়েছে। আপনি কি বলছেন যে এটি ইতিমধ্যে সিঙ্ক হওয়া ফাইলগুলির জন্যই কাজ করে যেখানে একযোগে ইনড নম্বরগুলি রেকর্ড করার সুযোগ ছিল (বা এটি যে কোনও কৌশল ব্যবহার করে)?
জানুস

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

@Gilles। জেনে রাখা ভাল - বেশ কয়েকটি জায়গা এমন মনে হয়েছে যেখানে অ্যালগরিদম স্থানীয় এবং দূরবর্তী সিঙ্কগুলির মধ্যে পার্থক্য করে। আমি আসলে ভাবিনি যে এটি প্রথম সিঙ্কের জন্য কাজ করবে। একীকরণের জন্য +1!
জানুস

4

একসাথে ব্যবহার করুন হেসেন জে দ্বারা প্রস্তাবিত হিসাবে । আমি এই উত্তরটি একটি সম্ভাব্য দরকারী স্ক্রিপ্টিং উদাহরণ হিসাবে বা কেবলমাত্র প্রাথমিক ইউটিলিটিগুলি ইনস্টল করা একটি সার্ভারে ব্যবহারের জন্য রেখে দিচ্ছি।


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

  1. প্রথমে উত্স পাশের ফাইলের নাম সংগ্রহ করুন।

    (cd /A && find . \! -type d) >A.find
  2. তারপরে ফাইলগুলি গন্তব্যের পাশে রেখে দিন। প্রথমে গন্তব্যের পাশে ফাইলগুলির একটি সমতল গাছ তৈরি করুন। আপনি যদি পুরানো শ্রেণিবিন্যাসের চারপাশে শক্ত লিঙ্কগুলি রাখতে চান তবে lnতার পরিবর্তে ব্যবহার করুন mv

    mkdir /B.staging /B.new
    find /B.old -type f -exec sh -c 'mv -- "$@" "$0"' /B.staging {} +
    
  3. গন্তব্যে কিছু ফাইল নিখোঁজ হতে পারে, একইভাবে সমতল তৈরি করুন /A.stagingএবং উত্স থেকে গন্তব্যে ডেটা অনুলিপি করতে আরএসসিএন ব্যবহার করুন।

    rsync -au /A.staging/ /B.staging/
  4. এখন জায়গায় জায়গায় ফাইলগুলির নাম পরিবর্তন করুন।

    cd /B.new &&
    <A.find perl -l -ne '
      my $dir = '.'; s!^\./+!!;
      while (s!^([^/]+)/+!!) {  # Create directories as needed
        $dir .= "/$1";
        -d $dir or mkdir $dir or die "mkdir $dir: $!"
      }
      rename "/B.staging/$_", "$dir/$_" or die "rename -> $dir/$_: $!"
    '
    

    সমতুল্যভাবে:

    cd /B.new &&
    <A.find python -c '
    import os, sys
    for path in sys.stdin.read().splitlines():
        dir, base = path.rsplit("/", 2)
        os.rename(os.path.join("/B.new", base), path)
    '
  5. অবশেষে, আপনি যদি ডিরেক্টরিগুলির মেটাডেটা সম্পর্কে চিন্তা করেন তবে ইতিমধ্যে উপস্থিত ফাইলগুলির সাথে rsync কল করুন।

    rsync -au /A/ /B.new/

মনে রাখবেন যে আমি এই পোস্টে স্নিপেট পরীক্ষা করিনি। আপনার নিজের ঝুঁকিতে ব্যবহার করুন। একটি মন্তব্যে কোন ত্রুটি রিপোর্ট করুন।


2

বিশেষত যদি চলমান সিঙ্কটি কার্যকর হয় তবে আপনি গিট-এনেেক্স বের করার চেষ্টা করতে পারেন ।

এটি তুলনামূলকভাবে নতুন; আমি নিজে এটি ব্যবহার করার চেষ্টা করিনি।

আমি এটি সুপারিশ করতে সক্ষম হলাম কারণ এটি ফাইলগুলির দ্বিতীয় অনুলিপি রাখা এড়ায় ... এর অর্থ এটি নির্দিষ্ট কিছু নন-গিট সংস্করণ নিয়ন্ত্রণ সিস্টেমের মতো ফাইলগুলি কেবল পঠনযোগ্য ("লকড") হিসাবে চিহ্নিত করতে হবে।

ফাইলগুলি sha256sum + ফাইল এক্সটেনশান দ্বারা চিহ্নিত করা হয় (ডিফল্টরূপে)। সুতরাং এটি লেখার সম্পাদন না করেই অভিন্ন ফাইল সামগ্রীর সাথে ভিন্ন ভিন্ন ফাইলের নামের সাথে দুটি রেপ সিঙ্ক করতে সক্ষম হওয়া উচিত (এবং লো-ব্যান্ডউইথ নেটওয়ার্কের উপর, যদি ইচ্ছা হয়)। চেকসাম করার জন্য অবশ্যই এটি অবশ্যই সমস্ত ফাইল পড়তে হবে।


1

কিভাবে ভালো কিছু সম্পর্কে:

src=/mnt/driveA
dst=/mnt/driveB

cd $src
find . -name <PATTERN> -type f >/tmp/srclist
cd $dst
find . -name <PATTERN> -type f >/tmp/dstlist

cat /tmp/srclist | while read srcpath; do
    name=`basename "$srcpath"`
    srcdir=`dirname "$srcpath"`
    dstpath=`grep "/${name}\$" /tmp/dstlist`

    mkdir -p "$srcdir"
    cd "$srcdir" && ln -s "$dstpath" "$name"
done

এটি ধরে নিয়েছে যে আপনি যে ফাইলগুলি সিঙ্ক করতে চান তার নামগুলি পুরো ড্রাইভ জুড়েই অনন্য otherwise অন্যথায় এটি সম্পূর্ণরূপে স্বয়ংক্রিয়ভাবে চালিত হওয়ার উপায় নেই (তবে, ব্যবহারকারীরা কোনও ফাইলটি বেছে নেওয়ার জন্য একটি অনুরোধ জানাতে পারেন যে আরও একটি ফাইল আছে কিনা))

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


এটি আশাব্যঞ্জক দেখায় - তবে এটি ফাইলগুলি সরিয়ে দেয়, বা কেবল সিমলিংক তৈরি করে?
ড্যান

আমি মনে করি আমি এর বেশিরভাগটাই বুঝতে পারি; কিন্তু grepলাইনটি কি করে? এটি কি কেবল মেলানো ফাইলটির পুরো পথ খুঁজে পাবে dstlist?
ড্যান

@ ড্যান: স্পষ্টতই lnএটির ব্যবহারের মাধ্যমে দ্যুতিগুলি তৈরি হয়। আপনি mvফাইলগুলি সরানোর জন্য নিয়োগ করতে পারেন , তবে বিদ্যমান ফাইলগুলি ওভাররাইটিং থেকে সাবধান থাকবেন। এছাড়াও, আপনি ফাইলগুলি সরিয়ে নিয়ে যাওয়ার পরে খালি ডায়ারগুলি পরিষ্কার করতে চাইবেন। হ্যাঁ, এই grepকমান্ডটি এমন একটি লাইন অনুসন্ধান করে যা ফাইলনামে শেষ হয়, সুতরাং এটি গন্তব্য ড্রাইভে সম্পূর্ণ পথটি প্রকাশ করে aling
অ্যালেক্স

1

ধরে নিচ্ছি যে গাছের মধ্যে বেস ফাইলের নামগুলি অনন্য, এটি মোটামুটি সোজা:

join <(cd A; find . -type f | while read f; do echo $(basename $f) $(dirname $f); done | sort) \
     <(cd B; find . -type f | while read f; do echo $(basename $f) $(dirname $f); done | sort) |\
while read name to from
do
        mkdir -p B/$to
        mv -v B/$from/$name B/$to/
done

আপনি যদি পুরানো খালি ডিরেক্টরিগুলি পরিষ্কার করতে চান তবে ব্যবহার করুন:

find B -depth -type d -delete

1

আমিও এই সমস্যার মুখোমুখি হয়েছি। Md5sum- ভিত্তিক সমাধানটি আমার পক্ষে কার্যকর হয়নি, কারণ আমি আমার ফাইলগুলিকে একটি webdavমাউন্টে সিঙ্ক করি । webdavগন্তব্যটিতে এমডি 5সাম অঙ্কের গণনা করা মানে বড় ফাইল অপারেশনগুলিও বোঝানো হবে।

আমি একটি ছোট স্ক্রিপ্ট তৈরি করেছি reorg_Remote_Dir_detect_moves.sh (গিথুবে) যা সর্বাধিক সরানো ফাইলগুলি সনাক্ত করার চেষ্টা করছে এবং তারপরে দূরবর্তী ডিরেক্টরিটি সামঞ্জস্য করতে বেশ কয়েকটি কমান্ড সহ একটি নতুন অস্থায়ী শেল-স্ক্রিপ্ট তৈরি করে। যেহেতু আমি কেবল ফাইলের নামগুলির যত্ন নিই, তাই স্ক্রিপ্টটি কোনও সঠিক সমাধান নয়।

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

স্কিপ করা ফাইলগুলি আপনার পছন্দসই সিঙ্ক সরঞ্জাম (যেমন rsync, unison, ...) দ্বারা পরিচালিত হবে , যা আপনাকে অস্থায়ী শেল-স্ক্রিপ্ট চালানোর পরে ব্যবহার করতে হবে।

তাহলে হয়তো আমার স্ক্রিপ্ট কারওর জন্য কাজে লাগবে? যদি তাই হয় (এটি আরও স্পষ্ট করতে) তিনটি পদক্ষেপ রয়েছে:

  1. শেল স্ক্রিপ্ট চালাও reorg_Remote_Dir_detect_moves.sh (গিথুবে)
  2. এটি অস্থায়ী শেল-লিপি তৈরি করবে /dev/shm/REORGRemoteMoveScript.sh=> চালগুলি চালানোর জন্য এটি চালান (মাউন্টে দ্রুত হবে webdav)
  3. আপনার পছন্দের সিঙ্ক সরঞ্জামটি চালান (যেমন rsync, unison, ...)

1

একটি উত্তরে আমার চেষ্টা এখানে। পূর্বনির্ধারিত হিসাবে, আমার সমস্ত স্ক্রিপ্টিং অভিজ্ঞতা বাশ থেকে আসে, সুতরাং আপনি যদি অন্য শেল ব্যবহার করেন তবে কমান্ডের নাম বা বাক্য গঠন আলাদা হতে পারে।

এই সমাধানের জন্য দুটি পৃথক স্ক্রিপ্ট তৈরি করা দরকার।

গন্তব্য ড্রাইভে ফাইলগুলি সরানোর জন্য এই প্রথম স্ক্রিপ্ট দায়ী।

md5_map_file="<absolute-path-to-a-temporary-file>"

# Given a single line from the md5 map file, list
# only the path from that line.
get_file()
{
  echo $2
}

# Given an md5, list the filename from the md5 map file
get_file_from_md5()
{
  # Grab the line from the md5 map file that has the
  # md5 sum passed in and call get_file() with that line.
  get_file `cat $md5_map_file | grep $1`
}

file=$1

# Compute the md5
sum=`md5sum $file`

# Get the new path for the file
new_file=`get_file_from_md5 $sum`

# Make sure the destination directory exists
mkdir -p `dirname $new_file`
# Move the file, prompting if the move would cause an overwrite
mv -i $file $new_file

দ্বিতীয় স্ক্রিপ্টটি প্রথম স্ক্রিপ্ট দ্বারা ব্যবহৃত এমডি 5 মানচিত্র ফাইল তৈরি করে এবং তারপরে গন্তব্য ড্রাইভের প্রতিটি ফাইলে প্রথম স্ক্রিপ্টকে কল করে।

# Do not put trailing /
src="<absolute-path-to-source-drive>"
dst="<absolute-path-to-destination-drive>"
script_path="<absolute-path-to-the-first-script>"
md5_map_file="<same-absolute-path-from-first-script>"


# This command searches through the source drive
# looking for files.  For every file it finds,
# it computes the md5sum and writes the md5 sum and
# the path to the found filename to the filename stored
# in $md5_map_file.
# The end result is a file listing the md5 of every file
# on the source drive
cd $src
find . -type f -exec md5sum "{}" \; > $md5_map_file

# This command searches the destination drive for files and calls the first
# script for every file it finds.
cd $dst
find . -type f -exec $script_path '{}' \; 

মূলত, যা চলছে তা হ'ল দুটি স্ক্রিপ্টগুলি একটি এসোসিয়েটিভ অ্যারে সহ একত্র করে $md5_map_file। প্রথমে সোর্স ড্রাইভে থাকা ফাইলগুলির জন্য সমস্ত এমডি 5 গণনা করা এবং সংরক্ষণ করা হয়। এমডি 5 এর সাথে যুক্ত হ'ল ড্রাইভের মূল থেকে আপেক্ষিক পথ। তারপরে, গন্তব্য ড্রাইভে প্রতিটি ফাইলের জন্য, এমডি 5 গণনা করা হয়। এই এমডি 5 ব্যবহার করে সোর্স ড্রাইভে সেই ফাইলটির পথ সন্ধান করা হবে। গন্তব্য ড্রাইভে থাকা ফাইলটি সোর্স ড্রাইভে থাকা ফাইলটির সাথে মেলে যাবার জন্য সরানো হয়।

এই স্ক্রিপ্টের সাথে বেশ কয়েকটি ক্যাভেট রয়েছে:

  • এটি ধরে নেওয়া হয় যে file dst এর প্রতিটি ফাইল also src এও থাকে
  • এটি directories dst থেকে কোনও ডিরেক্টরি সরিয়ে দেয় না, কেবল ফাইলগুলিকে সরিয়ে দেয়। আমি স্বয়ংক্রিয়ভাবে এটি করার নিরাপদ উপায় সম্পর্কে ভাবতে অক্ষম

এমডি 5 এর গণনা করতে এটি অবশ্যই একটি দীর্ঘ সময় নিতে হবে: সমস্ত সামগ্রী অবশ্যই পড়তে হবে। যদিও ড্যান যদি নিশ্চিত হন যে ফাইলগুলি অভিন্ন, তবে কেবল তাদের ডিরেক্টরি কাঠামোয় সরানো খুব দ্রুত (কোনও পাঠ্য নেই)। সুতরাং, md5sumএখানে ব্যবহার করার জিনিস বলে মনে হয় না। (বিটিডাব্লু, rsyncএর একটি মোড রয়েছে যা এটি চেকসামগুলি গণনা করে না))
ইম্জ - ইভান জ্যাকারিয়াশেভ

এটি নির্ভুলতা এবং গতির মধ্যে একটি বাণিজ্য। আমি এমন একটি পদ্ধতি সরবরাহ করতে চেয়েছিলাম যা কেবল ফাইল নামগুলির চেয়ে উচ্চতর ডিগ্রি ব্যবহার করে।
ক্লেডাক্স
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.