কৌণিক সংকেত দিয়ে শুরু করা

১. শুরু করার আগে

কালো কৌণিক লোগো

অ্যাঙ্গুলার সিগন্যালস আপনার পরিচিত ও পছন্দের অ্যাঙ্গুলারে তিনটি রিঅ্যাক্টিভ প্রিমিটিভ যুক্ত করে, যা আপনার ডেভেলপমেন্টকে সহজ করে এবং স্বাভাবিকভাবেই আপনাকে আরও দ্রুত অ্যাপ তৈরি করতে সাহায্য করে।

আপনি যা তৈরি করবেন

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

ভিন্টেজ সবুজ গেমিং কনসোলের স্টাইলে তৈরি একটি অ্যাঙ্গুলার সাইফার গেম, যার স্ক্রিনে 'Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!' এই গোপন বার্তাটি রয়েছে।

পূর্বশর্ত

  • অ্যাঙ্গুলার এবং টাইপস্ক্রিপ্ট সম্পর্কে জ্ঞান
  • সুপারিশকৃত: অ্যাঙ্গুলার সিগন্যালস লাইব্রেরি সম্পর্কে জানতে “Rethinking Reactivity with Signals” দেখুন।

২. কোডটি নিন

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

স্ট্যাকব্লিটজ খুলুন এবং অ্যাপটি চালান।

শুরু করার জন্য, আপনার পছন্দের ওয়েব ব্রাউজারে Stackblitz লিঙ্কটি খুলুন:

  1. একটি নতুন ব্রাউজার ট্যাব খুলুন এবং https://stackblitz.com/edit/io-signals-codelab-starter?file=src%2Fcipher%2Fservice.cipher.ts,src%2Fsecret-message%2Fservice.message.ts&service.massage.ts -এ যান।
  2. আপনার নিজস্ব সম্পাদনাযোগ্য ওয়ার্কস্পেস তৈরি করতে Stackblitz ফর্ক করুন। Stackblitz স্বয়ংক্রিয়ভাবে অ্যাপটি চালু করে দেবে, এবং আপনি কাজ শুরু করার জন্য প্রস্তুত!

বিকল্প: রিপোজিটরি ক্লোন করুন এবং অ্যাপটি পরিবেশন করুন।

এই কোডল্যাবটি সম্পন্ন করার জন্য ভিএসকোড (VSCode) বা স্থানীয় কোনো আইডিই (IDE) ব্যবহার করা একটি বিকল্প পদ্ধতি:

  1. একটি নতুন ব্রাউজার ট্যাব খুলুন এবং https://github.com/angular/codelabs/tree/signals-get-started -এ যান।
  2. রিপোজিটরিটি ফর্ক ও ক্লোন করুন এবং রিপোজিটরিতে প্রবেশ করতে cd codelabs/ কমান্ডটি ব্যবহার করুন।
  3. git checkout signals-get-started কমান্ডটি ব্যবহার করে স্টার্টার কোড ব্রাঞ্চটি চেক আউট করুন।
  4. VSCode বা আপনার পছন্দের IDE-তে কোডটি খুলুন।
  5. সার্ভার চালানোর জন্য প্রয়োজনীয় ডিপেন্ডেন্সিগুলো ইনস্টল করতে npm install কমান্ডটি ব্যবহার করুন।
  6. সার্ভারটি চালু করতে ng serve কমান্ডটি ব্যবহার করুন।
  7. ব্রাউজারে http://localhost:4200 ট্যাবটি খুলুন।

৩. একটি ভিত্তি স্থাপন করুন

আপনার সূচনা বিন্দু হলো একটি অ্যাঙ্গুলার সাইফার গেম, কিন্তু এটি এখনও কাজ করছে না। অ্যাঙ্গুলার সিগন্যালস গেমটির কার্যকারিতা চালনা করবে।

ভিন্টেজ সবুজ গেমিং কনসোলের স্টাইলে তৈরি একটি অ্যাঙ্গুলার সাইফার গেম, যার স্ক্রিনে 'Anqnxaa Lpcnaxl aaf pn jfafxyofa aofapfm pn a16 wyjak!' এই গোপন বার্তাটি রয়েছে।

শুরু করার জন্য, আপনি যা তৈরি করবেন তার চূড়ান্ত সংস্করণটি দেখে নিন: Angular Signals Cypher

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

অ্যাঙ্গুলার সাইফার গেমের একটি জিআইএফ, যেখানে স্ক্রিনে একটি লুকানো বার্তা ডিকোড করে লেখা হচ্ছে 'অ্যাঙ্গুলার সিগন্যাল আজ v16-এ ডেভেলপার প্রিভিউতে এসেছে!'

৪. আপনার প্রথম সিগন্যাল() সংজ্ঞায়িত করুন।

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

কোন কম্পোনেন্টগুলোর পরিবর্তন শনাক্ত করতে হবে অথবা আপনার সংজ্ঞায়িত এফেক্ট ফাংশনগুলো কার্যকর করতে হবে, তা জানার জন্য অ্যাঙ্গুলার সিগন্যাল থেকে প্রাপ্ত নোটিফিকেশনগুলো ব্যবহার করতে পারে।

superSecretMessage signal() এ রূপান্তর করুন

superSecretMessage হলো MessageService এর একটি ভ্যালু, যা প্লেয়ারের ডিকোড করা গোপন বার্তাটি নির্ধারণ করে। বর্তমানে, এই ভ্যালুটি কোনো পরিবর্তনের বিষয়ে অ্যাপকে অবহিত করে না, ফলে Customize বাটনটি কাজ করে না। আপনি একটি সিগন্যাল ব্যবহার করে এর সমাধান করতে পারেন।

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

আপনার প্রথম সিগন্যাল সংজ্ঞায়িত করতে, প্রতিটি ফাইলে TODO(1): Define your first signal() কমেন্টের অধীনে নিম্নলিখিত ধাপগুলি সম্পাদন করুন:

  1. service.message.ts ফাইলে, superSecretMessage রিঅ্যাক্টিভ করার জন্য Signals লাইব্রেরি ব্যবহার করুন:

src/app/secret-message/service.message.ts

superSecretMessage = signal(
  'Angular Signals are in developer preview in v16 today!'
);

এটি স্বয়ংক্রিয়ভাবে আপনাকে @angular/core থেকে signal ইম্পোর্ট করতে বলে। আপনি যদি পৃষ্ঠাটি রিফ্রেশ করেন, তাহলে সম্ভবত সেইসব জায়গায় ত্রুটি দেখতে পাবেন যেখানে আপনি আগে superSecretMessage ব্যবহার করেছিলেন। এর কারণ হলো, আপনি superSecretMessage এর টাইপ string থেকে SettableSignal<string> এ পরিবর্তন করেছেন। আপনি superSecretMessage এর সমস্ত রেফারেন্স Signals API ব্যবহার করার জন্য পরিবর্তন করে এটি ঠিক করতে পারেন। যেখানেই আপনি মানটি পড়বেন, সেখানে Signal getter superSecretMessage() কল করুন। এবং যেখানেই আপনি মানটি লিখবেন, সেখানে মেসেজের জন্য নতুন মান সেট করতে SettableSignal উপর .set API ব্যবহার করুন।

  1. secret-message.ts এবং service.message.ts ফাইলগুলিতে, superSecretMessage এর সমস্ত রেফারেন্সকে superSecretMessage() এ আপডেট করুন:

src/app/secret-message/secret-message.ts

// Before
this.messages.superSecretMessage
this.messages.superSecretMessage = message;

// After
this.messages.superSecretMessage()
this.messages.superSecretMessage.set(message);

src/app/secret-message/service.message.ts

// Before
this.superSecretMessage

// After
this.superSecretMessage()

অন্য দুটি সংকেত অন্বেষণ করুন

  • লক্ষ্য করুন যে আপনার অ্যাপে আরও দুটি সংকেত রয়েছে:

src/app/cipher/service.cipher.ts

cipher = signal(this.createNewCipherKey());
decodedCipher = signal<CipherKey[]>([]);

CipherService একটি cipher সিগন্যাল নির্ধারণ করে, যা হলো বর্ণমালার একটি অক্ষরের সাথে একটি নতুন cipher অক্ষরের কী-ভ্যালু জোড়ের একটি এলোমেলোভাবে তৈরি ম্যাপিং। বার্তাটিকে এলোমেলো করতে এবং প্লেয়ার কীবোর্ডে একটি সফল মিল খুঁজে পায় কিনা তা নির্ধারণ করতে এটি ব্যবহার করা হয়।

এছাড়াও আপনার কাছে সফলভাবে ডিকোড করা কী-ভ্যালু পেয়ারগুলোর একটি decodedCipher সিগন্যাল থাকবে, যা প্লেয়ার সাইফারটি সমাধান করার সাথে সাথে যুক্ত হতে থাকবে।

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

পরিবর্তনগুলি যাচাই করুন

  • অ্যাপটি কাজ করার আগে আপনাকে আরও একটি ধাপ সম্পন্ন করতে হবে। আপাতত, আপনার নতুন superSecretMessage কীভাবে সেট হচ্ছে তা দেখতে আপনার অ্যাপের বিভিন্ন অংশে console.log() যোগ করে দেখুন।

একটি Stackblitz যেখানে console.log() মেসেজের মাধ্যমে দেখানো হচ্ছে যে superSecretMessage নতুন মেসেজটি সঠিকভাবে লগ করছে।

৫. আপনার প্রথম computed() ফাংশনটি সংজ্ঞায়িত করুন।

অনেক পরিস্থিতিতে আপনি বিদ্যমান মান থেকে স্টেট নির্ধারণ করতে পারেন। নির্ভরশীল মান পরিবর্তিত হলে নির্ধারিত স্টেটটিও আপডেট হওয়া শ্রেয়।

computed() সাহায্যে, আপনি এমন একটি সিগন্যালকে ঘোষণামূলকভাবে প্রকাশ করতে পারেন যা অন্য সিগন্যাল থেকে তার মান গ্রহণ করে।

solvedMessage computed() এ রূপান্তর করুন

solvedMessage decodedCipher সিগন্যাল ব্যবহার করে secretMessage ভ্যালুটিকে এনকোডেড থেকে ডিকোডেড অবস্থায় রূপান্তর করে।

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

বর্তমানে, আপনি যখন secretMessage , decodedCipher , বা superSecretMessage পরিবর্তন করেন, তখন solvedMessage আপডেট হয় না। ফলে, প্লেয়ার যখন সাইফারটি সমাধান করে, তখন আপনি স্ক্রিনে কোনো আপডেট দেখতে পান না।

solvedMessage একটি কম্পিউটেড ভেরিয়েবল বানানোর মাধ্যমে আপনি একটি রিঅ্যাক্টিভ কনটেক্সট তৈরি করেন, যার ফলে যখন আপনি মেসেজ আপডেট করেন বা সাইফার সমাধান করেন, তখন ট্র্যাক করা ডিপেন্ডেন্সিগুলো থেকে স্টেট আপডেট ডিরাইভ করতে পারেন।

solvedMessage computed() -এ রূপান্তর করতে, TODO(2): Define your first computed() :

  1. service.message.ts ফাইলে, solvedMessage রিঅ্যাক্টিভ করতে Signals লাইব্রেরি ব্যবহার করুন:

src/app/secret-message/service.message.ts

solvedMessage = computed(() =>
  this.translateMessage(
    this.secretMessage(), 
    this.cipher.decodedCipher()
  )
);

এটি স্বয়ংক্রিয়ভাবে আপনাকে @angular/core থেকে computed ইম্পোর্ট করতে বলবে। আপনি যদি পৃষ্ঠাটি রিফ্রেশ করেন, তাহলে সম্ভবত সেইসব জায়গায় ত্রুটি দেখতে পাবেন যেখানে আপনি আগে solvedMessage উল্লেখ করেছিলেন। এর কারণ হলো, আপনি superSecretMessage এর টাইপ string থেকে Signal<string> (একটি ফাংশন)-এ পরিবর্তন করেছেন। solvedMessage এর সমস্ত রেফারেন্স solvedMessage() এ পরিবর্তন করে আপনি এটি ঠিক করতে পারেন।

  1. secret-message.ts ফাইলে, solvedMessage এর সমস্ত রেফারেন্সকে solvedMessage() এ আপডেট করুন:

src/app/secret-message/secret-message.ts

// Before
<span *ngFor="let char of this.messages.solvedMessage.split(''); index as i;" [class.unsolved]="this.messages.solvedMessage[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>

// After
<span *ngFor="let char of this.messages.solvedMessage().split(''); index as i;" [class.unsolved]="this.messages.solvedMessage()[i] !== this.messages.superSecretMessage()[i]" >{{ char }}</span>

উল্লেখ্য যে, superSecretMessage মতো solvedMessage একটি SettableSignal নয়—আপনি সরাসরি এর মান পরিবর্তন করতে পারবেন না। পরিবর্তে, যখনই এর নির্ভরশীল সিগন্যালগুলোর ( secretMessage এবং decodedCipher ) কোনো একটি আপডেট করা হয়, তখনই এর মানও হালনাগাদ থাকে।

অন্য দুটি computed() ফাংশন অন্বেষণ করুন

  • লক্ষ্য করুন যে আপনার অ্যাপে আরও দুটি গণনাকৃত মান রয়েছে:

src/app/secret-message/service.message.ts

secretMessage = computed(() => 
  this.translateMessage(
    this.superSecretMessage(),
    this.cipher.cipher()
  )
);

src/app/cipher/service.cipher.ts

unsolvedAlphabet = computed(() =>
  ALPHABET.filter(
    (letter) => !this.decodedCipher().find((guess) => guess.value === letter)
  )
);

MessageService একটি গণনাকৃত secretMessage এবং একটি cipher দ্বারা এনকোড করা superSecretMessage সংজ্ঞায়িত করে, যা প্লেয়াররা সমাধান করার জন্য কাজ করে।

CipherService একটি unsolvedAlphabet গণনা করে, যা হলো প্লেয়ারের সমাধান করতে না পারা সমস্ত অক্ষরের একটি তালিকা, এবং এটি decodedCipher এ থাকা সমাধান করা সাইফার কী-গুলির তালিকা থেকে উদ্ভূত হয়।

পরিবর্তনগুলি যাচাই করুন

এখন যেহেতু superSecretMessage একটি সিগন্যাল এবং solvedMessage একটি কম্পিউটেড, অ্যাপটি কাজ করার কথা! গেমটির কার্যকারিতাগুলো পরীক্ষা করে দেখুন:

  1. সাইফারটি সমাধান করতে এবং গোপন বার্তাটি ডিকোড করার জন্য, আপনার CipherComponent মধ্যে থাকা LetterKeyComponent এ একটি LetterGuessComponent ড্র্যাগ অ্যান্ড ড্রপ করুন।
  2. গোপন বার্তার আরও অংশ ডিকোড করার সাথে সাথে SecretMessageComponent টি কীভাবে আপডেট হয় তা দেখুন।
  3. প্রেরক এবং বার্তা পরিবর্তন করতে কাস্টমাইজ-এ ক্লিক করুন, এবং তারপর স্ক্রিনে মানগুলো ও URL-এর পরিবর্তন দেখতে ক্রিয়েট অ্যান্ড কপি URL-এ ক্লিক করুন।
  4. বোনাস: ইউআরএলটি কপি করে একটি নতুন ট্যাবে পেস্ট করুন, অথবা কোনো বন্ধুর সাথে শেয়ার করুন, এবং দেখুন কীভাবে প্রেরক ও বার্তাটি ইউআরএল-এ সংরক্ষিত থাকে।

অ্যাঙ্গুলার সাইফার গেমের একটি জিআইএফ, যেখানে স্ক্রিনে একটি লুকানো বার্তা ডিকোড করে লেখা হচ্ছে 'অ্যাঙ্গুলার সিগন্যাল আজ v16-এ ডেভেলপার প্রিভিউতে এসেছে!'

৬. আপনার প্রথম effect() যোগ করুন।

অনেক সময় এমন হতে পারে যে, কোনো সিগন্যালের মান নতুন হলে আপনি নির্দিষ্ট কোনো ঘটনা ঘটাতে চান। effect() সাহায্যে, আপনি সিগন্যালের পরিবর্তনের প্রতিক্রিয়ায় একটি হ্যান্ডলার ফাংশন শিডিউল করে তা চালাতে পারেন।

সাংকেতিক সংকেতটি সমাধান হয়ে গেলে কনফেটি যোগ করুন।

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

কনফেটি যোগ করতে, TODO(3): Add your first effect() -এর অধীনে নিম্নলিখিত ধাপগুলি সম্পাদন করুন:

  1. cipher.ts ফাইলে, মেসেজটি ডিকোড হলে কনফেটি যোগ করার জন্য একটি ইফেক্ট শিডিউল করুন:

src/app/cipher/cipher.ts

import * as confetti from 'canvas-confetti';

ngOnInit(): void {
  ...

  effect(() => {
    if (this.messages.superSecretMessage() === this.messages.solvedMessage()) {
      var confettiCanvas = document.getElementById('confetti-canvas');
      confetti.create()(confettiCanvas, { particleCount: 100 });
    }
  });
}

লক্ষ্য করুন কিভাবে এই প্রভাবটি একটি সংকেত এবং একটি গণনাকৃত মানের উপর নির্ভর করে: this.messages.superSecretMessage() এবং this.messages.solvedMessage()

Effect আপনাকে একটি রিঅ্যাক্টিভ কনটেক্সটের ভিতরে কনফেটি ফাংশনটি শিডিউল করতে সাহায্য করে, যাতে এর ডিপেন্ডেন্সিগুলো আপডেট হলে তা ট্র্যাক ও পুনঃমূল্যায়ন করা যায়।

পরিবর্তনগুলি যাচাই করুন

  • সাংকেতিক বার্তাটি সমাধান করার চেষ্টা করুন (ইঙ্গিত: দ্রুত পরীক্ষা করার জন্য আপনি বার্তাটি ছোট করে নিতে পারেন!)। আপনার প্রথম effect() সফল হলে একটি কনফেটি পপ আপনাকে অভিনন্দন জানাবে!

অ্যাঙ্গুলার সাইফার গেমের একটি জিআইএফ, যেখানে স্ক্রিনে একটি লুকানো বার্তা ডিকোড করে 'Confetti time!' লেখাটি ফুটিয়ে তোলা হচ্ছে এবং বার্তাটির সমাধান হলে কনফেটি পপারগুলো ফেটে যাচ্ছে।

৭. অভিনন্দন!

আপনার অ্যাঙ্গুলার সাইফার এখন গোপন বার্তা ডিকোড ও শেয়ার করার জন্য প্রস্তুত! অ্যাঙ্গুলার টিমের জন্য কোনো বার্তা আছে? আমাদের সোশ্যাল মিডিয়ায় @Angular-এ ট্যাগ করুন, যাতে আমরা তা ডিকোড করতে পারি! 🎉

স্ক্রিনে থাকা একটি লুকানো বার্তার মাধ্যমে অ্যাঙ্গুলার সাইফার গেমটি সমাধান করা হয়েছে, যেখানে লেখা ছিল: 'আজ থেকে v16-এ অ্যাঙ্গুলার সিগন্যালস ডেভেলপার প্রিভিউতে আসছে!'

আপনার ডেভেলপমেন্ট সহজ করতে এবং ডিফল্টভাবে আরও দ্রুত অ্যাপ তৈরি করতে, এখন আপনার অ্যাঙ্গুলার টুলবক্সে তিনটি নতুন রিঅ্যাক্টিভ প্রিমিটিভ যুক্ত হয়েছে।

আরও জানুন

এই কোডল্যাবগুলো দেখুন:

এই উপকরণগুলো পড়ুন: