কোনও প্রোগ্রাম চলাকালীন লাইভ আপডেট করা কীভাবে সম্ভব?


15

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



@डरবার্ট হুবহু নয়: এই থ্রেড এক্সিকিউটেবলের অদ্ভুততায় যায় না। এটি প্রাসঙ্গিক পটভূমি সরবরাহ করে তবে এটি সদৃশ নয় isn't
গিলস 'অশুভ হওয়া বন্ধ করুন'

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

আপনি যদি নিজের কোড দিয়ে সত্যিই এটি করতে চান তবে আপনি প্রোগ্রামিং ল্যাঙ্গুয়েজ ইরলংয়ের দিকে নজর দিতে চাইতে পারেন, যেখানে "হট" কোড আপডেটগুলি একটি মূল বৈশিষ্ট্য। learnyousomeerlang.com/relups
mattdm

1
@ গিলস বিটিডব্লিউ: আপনি প্রতিক্রিয়াতে রচনাটি যুক্ত করেছেন দেখে আমি আমার ঘনিষ্ঠ ভোট প্রত্যাহার করেছি। আপডেটগুলি কীভাবে কাজ করে তা জানতে চাইলে যে কেউ চিহ্নিত করতে আপনি এই প্রশ্নটিকে একটি ভাল জায়গায় পরিণত করেছেন।
ডারোবার্ট

উত্তর:


21

সাধারণভাবে ফাইলগুলি প্রতিস্থাপন করা হচ্ছে

প্রথমত, একটি ফাইল প্রতিস্থাপনের জন্য বেশ কয়েকটি কৌশল রয়েছে:

  1. লেখার জন্য বিদ্যমান ফাইলটি খুলুন , এটি 0 দৈর্ঘ্যে কেটে নিন এবং নতুন সামগ্রী লিখুন। (একটি কম সাধারণ বৈকল্পিক হ'ল বিদ্যমান ফাইলটি খোলার জন্য, নতুন সামগ্রীর সাথে পুরানো সামগ্রীটি ওভাররাইট করা, ফাইলটি যদি ছোট হয় তবে নতুন দৈর্ঘ্যে কেটে ফেলা)) শেল পদে:

    echo 'new content' >somefile
    
  2. পুরানো ফাইল সরান , এবং একই নামে একটি নতুন ফাইল তৈরি করুন। শেল পদে:

    rm somefile
    echo 'new content' >somefile
    
  3. একটি অস্থায়ী নামে একটি নতুন ফাইল লিখছি তারপর সরানো বিদ্যমান নাম নতুন ফাইল। সরানো পুরানো ফাইল মোছা। শেল পদে:

    echo 'new content' >somefile.new
    mv somefile.new somefile
    

আমি কৌশলগুলির মধ্যে সমস্ত পার্থক্য তালিকা করব না, আমি এখানে কিছু গুরুত্বপূর্ণ উল্লেখ করব। রাজ্য 1 এর সাথে, বর্তমানে যদি কোনও প্রক্রিয়া ফাইলটি ব্যবহার করে থাকে তবে প্রক্রিয়াটি নতুন সামগ্রীটিকে আপডেট হওয়ার সাথে সাথে দেখবে। প্রক্রিয়াটি যদি ফাইল সামগ্রীতে একই থাকে বলে আশা করে তবে কিছু বিভ্রান্তি ঘটতে পারে। দ্রষ্টব্য যে এটি কেবল সেই প্রক্রিয়াগুলির বিষয়ে যা ফাইলটি উন্মুক্ত থাকে (যেমন উপস্থিত lsofবা এতে প্রদর্শিত হয় ; ইন্টারেক্টিভ অ্যাপ্লিকেশনগুলিতে ডকুমেন্ট খোলা থাকে (যেমন সম্পাদকের মধ্যে একটি ফাইল খোলার) সাধারণত ফাইলটি খোলা রাখে না, তারা ফাইলের সময় সামগ্রীটি লোড করে "ওপেন ডকুমেন্ট" অপারেশন এবং তারা "সংরক্ষণ করুন নথি" অপারেশন চলাকালীন (উপরের কৌশলগুলির মধ্যে একটির ব্যবহার করে) ফাইলটি প্রতিস্থাপন করে।/proc/PID/fd/

কৌশল 2 এবং 3 এর সাথে, যদি কোনও প্রক্রিয়াতে ফাইলটি somefileখোলা থাকে তবে সামগ্রী আপগ্রেড করার সময় পুরানো ফাইলটি উন্মুক্ত থাকে। কৌশল 2 সহ, প্রকৃতপক্ষে ফাইলটি সরানোর পদক্ষেপটি কেবলমাত্র ডিরেক্টরিতে ফাইলের প্রবেশ সরিয়ে দেয়। ফাইলটি কেবল তখনই সরিয়ে ফেলা হয় যখন এতে কোনও ডিরেক্টরি এন্ট্রি না থাকে (সাধারণ ইউনিক্স ফাইল সিস্টেমে একই ফাইলের জন্য একাধিক ডিরেক্টরি এন্ট্রি থাকতে পারে ) এবং কোনও প্রক্রিয়াতে এটি খোলা থাকে না। এটি পর্যবেক্ষণ করার জন্য এখানে একটি উপায় - sleepপ্রক্রিয়াটি মারা যাওয়ার পরে কেবল ফাইলটি সরানো হয় ( rmকেবলমাত্র এটির ডিরেক্টরি এন্ট্রি সরিয়ে দেয়)।

echo 'old content' >somefile
sleep 9999999 <somefile &
df .
rm somefile
df .
cat /proc/$!/fd/0
kill $!
df .

কৌশল 3 এর সাথে নতুন ফাইলটিকে বিদ্যমান নামে স্থানান্তরিত করার পদক্ষেপটি পুরাতন সামগ্রীর দিকে পরিচালিত ডিরেক্টরি এন্ট্রি সরিয়ে দেয় এবং নতুন সামগ্রীর দিকে পরিচালিত ডিরেক্টরি এন্ট্রি তৈরি করে। এটি একটি পারমাণবিক অপারেশনে করা হয়, সুতরাং এই কৌশলটির একটি বড় সুবিধা রয়েছে: কোনও প্রক্রিয়া যে কোনও সময় ফাইলটি খুললে এটি পুরানো সামগ্রী বা নতুন সামগ্রী দেখতে পাবে - মিশ্র সামগ্রী বা ফাইলটি না পাওয়ার কোনও ঝুঁকি নেই বিদ্যমান।

এক্সিকিউটেবলগুলি প্রতিস্থাপন করা হচ্ছে

যদি আপনি লিনাক্সে চলমান এক্সিকিউটেবলের সাথে কৌশল 1 ব্যবহার করে দেখেন তবে আপনি একটি ত্রুটি পাবেন।

cp /bin/sleep .
./sleep 999999 &
echo oops >|sleep
bash: sleep: Text file busy

একটি "পাঠ্য ফাইল" অর্থ অস্পষ্ট historicalতিহাসিক কারণে নির্বাহযোগ্য কোডযুক্ত এমন একটি ফাইল । অন্যান্য অনেক ইউনিক্স রূপের মতো লিনাক্স চলমান প্রোগ্রামের কোডটি ওভাররাইট করতে অস্বীকার করে; কয়েকটি ইউনিক ভেরিয়েন্ট এটির অনুমতি দেয়, পুরানো কোডটি যদিও খুব ভালভাবে বহির্মুখী পরিবর্তন না করে নতুন কোডটি ক্রাশ হয়ে যায়।

লিনাক্সে, আপনি গতিশীল লোড লাইব্রেরির কোডটি ওভাররাইট করতে পারেন। এটি সম্ভবত এটির যে প্রোগ্রামটি ব্যবহার করছে তাতে ক্রাশ হতে পারে। (আপনি sleepএটি এটির সাথে পর্যবেক্ষণ করতে সক্ষম হবেন না কারণ এটি শুরু হওয়ার সাথে সাথে এটি প্রয়োজনীয় সমস্ত লাইব্রেরি কোড লোড করে দেয় sleeping ঘুমানোর পরে দরকারী কিছু কার্যকর করার মতো আরও জটিল প্রোগ্রাম চেষ্টা করুন like perl -e 'sleep 9; print lc $ARGV[0]')

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

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

একটি অ্যাপ্লিকেশন আপগ্রেড

উপরে উল্লিখিত সর্বাধিক সুবিধার কারণে বেশিরভাগ প্যাকেজ ম্যানেজার ফাইল 3 প্রতিস্থাপনের জন্য কৌশল ব্যবহার করেন - সময় সময়ে যে কোনও সময় ফাইলটি খোলার ফলে এটির বৈধ সংস্করণ দেখা যায়।

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

  1. অ্যাপ্লিকেশনটির একটি উদাহরণ শুরু হয়েছে।
  2. অ্যাপ্লিকেশনটি আপগ্রেড করা হয়েছে।
  3. চলমান উদাহরণ অ্যাপ্লিকেশন এর একটি ডেটা ফাইল খুলবে।

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

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

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


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

@डरবার্ট আমি "লিঙ্কমুক্ত" টার্মিনোলজির উপর ভারী হতে চাই না। আমি ডিরেক্টরি এন্ট্রি, একটি সূক্ষ্মতা যা পরে ব্যাখ্যা করা হয়েছে প্রসঙ্গে "মুছুন" ব্যবহার করছি। এটি কি এই পর্যায়ে বিভ্রান্তিকর?
গিলস 16'15

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

3

প্রোগ্রামটি চলাকালীন আপগ্রেড চালানো যেতে পারে তবে আপনি যে চলমান প্রোগ্রামটি দেখেন এটি আসলে এটির পুরানো সংস্করণ। আপনি প্রোগ্রামটি বন্ধ না করা পর্যন্ত পুরানো বাইনারি ডিস্কে থাকে।

ব্যাখ্যা: লিনাক্স সিস্টেমগুলিতে, একটি ফাইল কেবল একটি ইনোড হয়, যার সাথে এর বেশ কয়েকটি লিঙ্ক থাকতে পারে। যেমন। /bin/bashআপনি দেখতে শুধু একটি লিংক inode 3932163আমার সিস্টেমে। লিঙ্কটি জারি করে কোন ইনড কোনও লিঙ্ক করে তা আপনি দেখতে পারেন ls --inode /path। কোনও ফাইল (আইনোড) কেবল তখনই সরিয়ে ফেলা হবে যদি সেখানে শূন্য লিঙ্কগুলি নির্দেশ করে এবং কোনও প্রোগ্রামের দ্বারা ব্যবহৃত না হয়। যখন প্যাকেজ ম্যানেজার আপগ্রেড করে। /usr/bin/firefoxএটি প্রথমে আনলিংক করে (হার্ড লিঙ্কটি সরিয়ে দেয় /usr/bin/firefox), তারপরে একটি নতুন ফাইল তৈরি করে /usr/bin/firefoxযা একটি ভিন্ন ইনোডের হার্ডলিঙ্ক (যা নতুন firefoxসংস্করণ ধারণ করে )। পুরানো ইনোডটি এখন ফ্রি হিসাবে চিহ্নিত হয়েছে এবং নতুন ডেটা সংরক্ষণ করার জন্য এটি পুনরায় ব্যবহার করা যেতে পারে তবে ডিস্কে থেকে যায় (আইওডগুলি কেবল তখনই তৈরি হয় যখন আপনি আপনার ফাইল সিস্টেমটি তৈরি করেন এবং কখনই মোছা হয় না)। এর পরের শুরুতেfirefox, নতুন ব্যবহার করা হবে।

আপনি যদি এমন কোনও প্রোগ্রাম লিখতে চান যা চলতে চলতে নিজেই "আপগ্রেড হয়", তবে আমি কেবলমাত্র তার নিজস্ব বাইনারি ফাইলের টাইমস্ট্যাম্পটি পর্যায়ক্রমে পরীক্ষা করতে পারি এবং এটি যদি প্রোগ্রামের শুরু সময়ের চেয়ে নতুন হয় তবে নিজেই পুনরায় লোড করুন possible


1
প্রকৃতপক্ষে, এটি ইউনিক্সে ফাইলগুলি মুছে ফেলার (লিঙ্কমুক্ত) কাজ করে বলেই; unix.stackexchange.com/questions/49299/… দেখুন , কমপক্ষে লিনাক্সে, আপনি আসলে একটি চলমান বাইনারি লিখতে পারবেন না, আপনি একটি "টেক্সট ফাইল ব্যস্ত" ত্রুটি পাবেন।
ডারোবার্ট

অদ্ভুত ... তারপর যেমন কিভাবে। দেবিয়ানের aptআপগ্রেডের কাজ? Iceweasel( Firefox) সহ সমস্যা ছাড়াই যে কোনও চলমান প্রোগ্রামকে আমি আপগ্রেড করতে পারি ।
psimon

2
এপিটি (বা, বরং dpkg) ফাইলগুলি ওভাররাইট করে না। পরিবর্তে এটি তাদের লিঙ্কমুক্ত করে এবং একই নামে নতুন একটি রাখে। ব্যাখ্যাটির জন্য আমি সংযুক্ত প্রশ্ন ও উত্তর দেখুন।
ডারোবার্ট

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

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

0

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

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

আমি যখন একটি প্রোগ্রাম লিখতে চাই তখন আমার কী করতে হবে যেটি চলমান অবস্থায় নিজেই আপডেট হয়? ইতিমধ্যে আপনার প্রশ্নের উত্তর প্রচুর আছে are এটি দেখুন: /programming/232347/how-should-i-implement-an-auto-updater উপায় দ্বারা, প্রোগ্রামিং সম্পর্কে প্রশ্নগুলি স্ট্যাকওভারফ্লোতে আরও ভাল।


2
এক্সিকিউটেবলগুলি আসলে চাহিদাযুক্ত পৃষ্ঠাগুলি (অদলবদল) হয়। এগুলি পুরোপুরি মেমরিতে লোড হয় না এবং যখনই সিস্টেম অন্য কোনও কিছুর জন্য র‌্যাম চায় তখন মেমরি থেকে বাদ দেওয়া যেতে পারে। পুরানো সংস্করণটি আসলে ডিস্কে অবশিষ্ট রয়েছে; unix.stackex بدل . com দেখুন / প্রশ্নগুলি / 49299/… দেখুন । লিনাক্সে অন্তত, আপনি চলমান এক্সিকিউটেবলের পক্ষে আসলে লিখতে পারবেন না, আপনি "পাঠ্য ফাইল ব্যস্ত" ত্রুটি পাবেন get এমনকি রুট এটি করতে পারে না। (যদিও আপনি ফায়ারফক্স সম্পর্কে যথেষ্ট সঠিক)।
ডারোবার্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.