অ্যান্ড্রয়েড স্টুডিওতে অপ্রত্যাশিত ডিবাগিং ত্রুটিগুলি উন্মোচন করা
অ্যান্ড্রয়েড স্টুডিওতে ডিবাগিং সমস্যাগুলি কখনও কখনও একটি গোলকধাঁধা নেভিগেট করার মতো মনে হতে পারে, বিশেষত যখন রহস্যজনক ত্রুটি PEME ব্যতিক্রম: RSA প্রাইভেট কী-তে বিকৃত সিকোয়েন্স প্রদর্শিত এটি বিভ্রান্তিকর, বিশেষ করে যখন আপনার প্রকল্প স্পষ্টভাবে এনক্রিপশন-সম্পর্কিত উপাদান ব্যবহার করে না। এই ত্রুটি, তবে, আপনার বিল্ড পরিবেশে অপ্রত্যাশিত ভুল কনফিগারেশন বা নির্ভরতা থেকে উদ্ভূত হতে পারে। 🚀
শুক্রবার সন্ধ্যায় একটি সাধারণ ইউনিট পরীক্ষা চালানোর কল্পনা করুন, আত্মবিশ্বাসী যে এটি সপ্তাহের জন্য শেষ হওয়ার আগে শেষ কাজ। হঠাৎ, আপনার টার্মিনাল লগগুলি অনির্বচনীয় বার্তাগুলির সাথে প্লাবিত হয়, এবং আপনি ফোরাম অনুসন্ধান করতে আটকে গেছেন। অনেক ডেভেলপারদের জন্য, এটি শুধুমাত্র একটি উপদ্রব নয় বরং একটি উত্পাদনশীলতা ব্লকার যা সময়সীমা বিলম্বিত করতে পারে।
এই জাতীয় সমস্যাগুলি প্রায়শই নির্দিষ্ট লাইব্রেরি বা পুরানো গ্রেডল কনফিগারেশনগুলিতে ফিরে আসে যা আপনার প্রকল্পে এনক্রিপশন উপাদানগুলিকে পরোক্ষভাবে লুকিয়ে রাখে। ত্রুটির লগগুলি প্রথম নজরে অপ্রতিরোধ্য মনে হতে পারে, তবে তারা মূল কারণটি দক্ষতার সাথে নির্ণয় এবং সমাধানের মূল চাবিকাঠি। আসুন ধাপে ধাপে এই সমস্যাটি বোঝা এবং ঠিক করার জন্য ডুব দেওয়া যাক। 🛠️
আপনি ডিবাগিংয়ে নতুন বা একজন অভিজ্ঞ ডেভেলপার হোন না কেন, স্বচ্ছতা এবং কৌশল সহ সমস্যা সমাধান সব পার্থক্য করে। এই নির্দেশিকায়, আমরা এই ত্রুটির কারণ এবং ব্যবহারিক সমাধানগুলি ভেঙে দেব যাতে আপনি কিছুক্ষণের মধ্যেই নিরবিচ্ছিন্ন কোডিংয়ে ফিরে যেতে পারেন৷
আদেশ | ব্যবহারের উদাহরণ |
---|---|
PEMParser | PEM-এনকোডেড কী বা সার্টিফিকেট পার্স করতে ব্যবহৃত হয়। এই নিবন্ধে, এটি একটি PEM ফাইল থেকে তাদের গঠন পড়ার মাধ্যমে ত্রুটিপূর্ণ RSA প্রাইভেট কীগুলির সমস্যাগুলিকে যাচাই এবং নির্ণয় করতে সহায়তা করে৷ |
JcaPEMKeyConverter | PEM কী জোড়াকে জাভার কী-পেয়ার বস্তুতে রূপান্তর করে। এটি পার্স করা PEM ডেটা পরিচালনা করার জন্য এবং জাভা ক্রিপ্টোগ্রাফিক ফাংশনের সাথে সামঞ্জস্যতা নিশ্চিত করার জন্য অপরিহার্য। |
PEMException | PEM স্ট্রাকচারে কোনো সমস্যা হলে নির্দিষ্ট ব্যতিক্রম থ্রো করা হয়, যেমন একটি বিকৃত RSA প্রাইভেট কী বা অসমর্থিত এনক্রিপশন ফর্ম্যাট। |
exclude | অপ্রয়োজনীয় নির্ভরতা অপসারণের জন্য Gradle কমান্ড, যেমন বিল্ড প্রক্রিয়াটিকে স্ট্রীমলাইন করতে এবং দ্বন্দ্ব প্রতিরোধ করার জন্য সম্পর্কহীন বাউন্সি ক্যাসল মডিউলগুলি বাদ দেওয়া। |
tasks.withType(JavaCompile) | জাভা সংকলন কার্যগুলিতে নির্দিষ্ট সেটিংস প্রয়োগ করার জন্য গ্রেডল কনফিগারেশন কমান্ড, যেমন সামঞ্জস্য এবং ডিবাগিংয়ের জন্য UTF-8 এ এনকোডিং সেট করা। |
assertNotNull | একটি স্ট্রিং বা ফাইল থেকে পার্স করা PEM অবজেক্টটি শূন্য নয় তা যাচাই করতে ব্যবহৃত একটি JUnit দাবী, নিশ্চিত করে কীটি সফলভাবে পড়া হয়েছে। |
readObject | PEMParser এর পদ্ধতি যা একটি PEM ফাইলের পরবর্তী অবজেক্টটি পড়ে। যাচাইকরণের জন্য কী বা শংসাপত্রের বিষয়বস্তু বের করার জন্য এই কমান্ডটি অত্যন্ত গুরুত্বপূর্ণ। |
configuration.all.exclude | অপ্রয়োজনীয় এন্ট্রিগুলি এড়িয়ে বিল্ড কনফিগারেশনকে সরলীকরণ করে সমস্ত নির্ভরতা জুড়ে বিশ্বব্যাপী একটি মডিউল বাদ দেওয়ার জন্য গ্রেডল কনফিগারেশন। |
dispose | কী পার্সিং বা যাচাইকরণের কাজগুলি সম্পূর্ণ হওয়ার পরে পরিষ্কার-পরিচ্ছন্নতা নিশ্চিত করতে BouncyCastle বা অন্যান্য সম্পর্কিত পরিষেবাগুলির সাথে সংযুক্ত সংস্থানগুলি প্রকাশ করে৷ |
options.encoding | Gradle-এ জাভা সংকলন কাজের জন্য এনকোডিং নির্দিষ্ট করে। এটি অক্ষরগুলির সামঞ্জস্যপূর্ণ পরিচালনা নিশ্চিত করে, এনকোডিং অমিলের কারণে ক্রিপ্টোগ্রাফিক ত্রুটিগুলি এড়িয়ে যায়। |
সমাধান ব্রেকিং ডাউন: মূল স্ক্রিপ্ট বোঝা
উদাহরণের প্রথম স্ক্রিপ্টটি একটি জাভা-ভিত্তিক ইউটিলিটি যা যাচাই এবং পার্স করার জন্য ডিজাইন করা হয়েছে PEM-এনকোডেড কী. এটি বাউন্সি ক্যাসল লাইব্রেরি ব্যবহার করে, একটি শক্তিশালী ক্রিপ্টোগ্রাফি ফ্রেমওয়ার্ক, সম্ভাব্য সমস্যাগুলি যেমন RSA প্রাইভেট কীগুলিতে বিকৃত সিকোয়েন্সগুলি সনাক্ত করতে। মূল কমান্ড PEMParser PEM ফাইলের গঠন পড়ে এবং এতে বৈধ ডেটা আছে কি না তা সনাক্ত করে। এই স্ক্রিপ্টটি এমন পরিস্থিতিতে বিশেষভাবে উপযোগী যেখানে কীগুলি ম্যানুয়ালি আমদানি বা তৈরি করা হয় এবং তাদের বিন্যাসে কোনও লুকানো সমস্যা নেই তা নিশ্চিত করে। উদাহরণস্বরূপ, ওপেন-সোর্স সার্টিফিকেট ব্যবহারকারী বিকাশকারীরা এই স্ক্রিপ্ট সনাক্ত করতে পারে এমন ফর্ম্যাটিং ত্রুটির সম্মুখীন হতে পারে৷ 😊
এর অন্তর্ভুক্তি JcaPEMKeyConverter পার্স করা PEM ডেটাকে জাভা-এর নেটিভ কীপেয়ার অবজেক্টে রূপান্তর করতে সক্ষম করে। সুরক্ষিত যোগাযোগ প্রোটোকলের উপর নির্ভর করে এমন অ্যাপ্লিকেশনগুলিতে কীকে একীভূত করার জন্য এই পদক্ষেপটি অত্যন্ত গুরুত্বপূর্ণ। স্ক্রিপ্টটি কেবল কীগুলির অখণ্ডতা যাচাই করতে সহায়তা করে না বরং জাভা-ভিত্তিক ক্রিপ্টোগ্রাফিক ক্রিয়াকলাপগুলিতে অবিলম্বে ব্যবহারের জন্য প্রস্তুত তা নিশ্চিত করে। উদাহরণস্বরূপ, একটি API স্থাপন করার কল্পনা করুন যার জন্য SSL প্রয়োজন কিন্তু একটি অবৈধ কী এর কারণে ব্যর্থ হয়৷ এই স্ক্রিপ্টটি আগে থেকেই এই ধরনের সমস্যাগুলি ডিবাগ এবং ঠিক করতে ব্যবহার করা যেতে পারে, যা ডেভেলপারদের উল্লেখযোগ্য সময় এবং হতাশা বাঁচায়।
দ্বিতীয় স্ক্রিপ্টটি গ্রেডল কনফিগারেশন সমস্যাগুলি সমাধান করার উপর ফোকাস করে যা অসাবধানতাবশত অপ্রয়োজনীয় নির্ভরতা প্রবর্তন করতে পারে। ব্যবহার করে বাদ Gradle বিল্ড ফাইলে কমান্ড, এটি বিল্ড প্রক্রিয়া চলাকালীন বিরোধপূর্ণ মডিউলগুলিকে অন্তর্ভুক্ত করা থেকে বাধা দেয়। এই পদক্ষেপটি Android বিকাশে বিশেষভাবে গুরুত্বপূর্ণ, যেখানে ফুলে যাওয়া নির্ভরতা অপ্রত্যাশিত ত্রুটির কারণ হতে পারে। উদাহরণস্বরূপ, যদি একটি লাইব্রেরি অসাবধানতাবশত পুরানো ক্রিপ্টোগ্রাফি মডিউল যোগ করে, exclude কমান্ড ব্যবহার করে নিশ্চিত করে যে শুধুমাত্র প্রয়োজনীয় উপাদানগুলি সংকলিত হয়েছে। এই ধরনের অপ্টিমাইজেশন বিল্ড দক্ষতা উন্নত করে এবং রানটাইম ত্রুটির ঝুঁকি কমায়। 🚀
সবশেষে, JUnit টেস্টিং স্ক্রিপ্ট হল একটি নিরাপত্তা জাল যা ডেভেলপারদের জন্য তাদের PEM কীগুলিকে মূল অ্যাপ্লিকেশানে না ঢুকে যাচাই করার জন্য। এটা মত দাবী নিয়োগ assertNotNull পার্স করা কী ডেটা খালি বা বিকৃত নয় তা যাচাই করতে। এই পদ্ধতিটি স্বয়ংক্রিয় পরীক্ষার পাইপলাইনের জন্য আদর্শ যেখানে কী যাচাইকরণ একটি ঘন ঘন প্রয়োজন। উদাহরণস্বরূপ, একটি CI/CD পরিবেশে, এই স্ক্রিপ্টটি একটি পদক্ষেপ হিসাবে যোগ করা যেতে পারে যাতে নিশ্চিত করা যায় যে কোনও আপলোড করা কীগুলি স্থাপনের আগে প্রয়োজনীয় মানগুলি পূরণ করে। এই সরঞ্জামগুলিকে অন্তর্ভুক্ত করার মাধ্যমে, বিকাশকারীরা ক্রিপ্টোগ্রাফি-সম্পর্কিত বাগগুলিকে আত্মবিশ্বাসের সাথে মোকাবেলা করতে পারে এবং নিরবচ্ছিন্ন অ্যাপ্লিকেশন কার্যকারিতা বজায় রাখতে পারে।
অ্যান্ড্রয়েড স্টুডিওতে RSA মূল ত্রুটিগুলি বোঝা এবং সমাধান করা
ব্যাকএন্ড স্ক্রিপ্ট জাভা ব্যবহার করে PEM ফর্ম্যাট যাচাইকরণ এবং ডিবাগ RSA-সম্পর্কিত সমস্যাগুলি পরিচালনা করতে।
import org.bouncycastle.openssl.PEMParser;
import java.io.FileReader;
import java.io.IOException;
import org.bouncycastle.openssl.PEMException;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import java.security.KeyPair;
import java.security.PrivateKey;
public class PEMKeyValidator {
public static void main(String[] args) {
try (PEMParser pemParser = new PEMParser(new FileReader("key.pem"))) {
Object object = pemParser.readObject();
if (object instanceof PEMEncryptedKeyPair) {
throw new PEMException("Encrypted keys are not supported in this configuration.");
} else if (object instanceof PEMKeyPair) {
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
KeyPair keyPair = converter.getKeyPair((PEMKeyPair) object);
PrivateKey privateKey = keyPair.getPrivate();
System.out.println("Key validated successfully: " + privateKey.getAlgorithm());
} else {
throw new PEMException("Malformed key or unsupported format.");
}
} catch (IOException | PEMException e) {
System.err.println("Error validating PEM key: " + e.getMessage());
}
}
}
বিকল্প পদ্ধতি: গ্রেডলে নির্ভরতা তৈরি করা সমাধান করা
নির্মাণের সময় RSA নির্ভরতা বাদ দেওয়া হয়েছে তা নিশ্চিত করতে Gradle-এর জন্য কনফিগারেশন স্ক্রিপ্ট।
plugins {
id 'java'
}
dependencies {
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'
}
configurations {
all {
exclude group: 'org.bouncycastle', module: 'bcmail-jdk15on'
}
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
ইউনিট পরীক্ষা করা সমাধান
RSA প্রাইভেট কী পার্সিং যাচাই করার জন্য JUnit টেস্ট কেস।
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import java.security.KeyPair;
import java.security.PrivateKey;
import org.bouncycastle.openssl.PEMParser;
import java.io.StringReader;
public class PEMKeyValidatorTest {
@Test
public void testValidRSAKey() throws Exception {
String validKey = "-----BEGIN RSA PRIVATE KEY-----...";
PEMParser parser = new PEMParser(new StringReader(validKey));
Object object = parser.readObject();
assertNotNull(object, "Parsed key should not be null.");
}
}
লুকানো নির্ভরতা এবং ডিবাগিং ক্রিপ্টোগ্রাফিক সমস্যা সমাধান করা
যেমন ত্রুটি সম্মুখীন একটি উপেক্ষিত দিক PEME ব্যতিক্রম আপনার প্রকল্পে লুকানো নির্ভরতার ভূমিকা। অ্যান্ড্রয়েড স্টুডিওর মতো আধুনিক ডেভেলপমেন্ট ফ্রেমওয়ার্কগুলি প্রায়শই বিভিন্ন লাইব্রেরিগুলিকে একীভূত করে, যার মধ্যে কয়েকটিতে বাউন্সি ক্যাসলের মতো ক্রিপ্টোগ্রাফিক সরঞ্জাম অন্তর্ভুক্ত থাকতে পারে। এমনকি যদি আপনার প্রকল্পের জন্য স্পষ্টভাবে RSA কার্যকারিতার প্রয়োজন না হয়, তবে এই ধরনের লাইব্রেরির উপস্থিতি দ্বন্দ্ব সৃষ্টি করতে পারে বা বিভ্রান্তিকর ত্রুটি লগ তৈরি করতে পারে। এটি মোকাবেলা করার জন্য, আপনাকে আপনার বিল্ড কনফিগারেশনগুলি সাবধানে অডিট করতে হবে, যেমন কমান্ড ব্যবহার করে exclude অপ্রয়োজনীয় মডিউল এড়াতে Gradle-এ। এই পদক্ষেপটি অপ্রয়োজনীয় বৈশিষ্ট্য থেকে মুক্ত একটি পরিষ্কার বিল্ড পরিবেশ নিশ্চিত করে। 🛠️
অন্বেষণ করার জন্য আরেকটি গুরুত্বপূর্ণ ক্ষেত্র হ'ল সরঞ্জাম এবং লাইব্রেরির বিভিন্ন সংস্করণের মধ্যে সামঞ্জস্য। ত্রুটি পছন্দ বিকৃত ক্রম প্রায়শই বাউন্সিক্যাসল লাইব্রেরির সংস্করণ এবং প্রকল্পে ব্যবহৃত গ্রেডল সংস্করণের মধ্যে অসঙ্গতি থেকে উদ্ভূত হয়। উদাহরণস্বরূপ, নির্ভরশীল লাইব্রেরি আপডেট না করে Gradle আপগ্রেড করার ফলে কী পার্সিংয়ের সময় ভুল যোগাযোগ হতে পারে। নিয়মিতভাবে লাইব্রেরি আপডেট পরীক্ষা করা এবং বিচ্ছিন্ন পরিবেশে আপনার বিল্ড পরীক্ষা করা এই ধরনের সমস্যা প্রতিরোধ করতে পারে। একটি সক্রিয় পদ্ধতি সময় বাঁচায় এবং ব্যর্থতার পরবর্তী সমস্যা সমাধানের প্রয়োজনীয়তা দূর করে।
অবশেষে, ক্রিপ্টোগ্রাফিক ডিবাগিংয়ের ক্ষেত্রে বিকাশকারীর সচেতনতা অপরিহার্য। যদিও বাউন্সি ক্যাসলের মতো সরঞ্জামগুলি শক্তিশালী, তারা সাবধানে পরিচালনার দাবি রাখে, বিশেষ করে যখন উত্তরাধিকার ফর্ম্যাট বা কাস্টম একীকরণের সাথে কাজ করে। পূর্বে দেওয়া স্ক্রিপ্টগুলির মতো টেস্টিং স্ক্রিপ্টগুলি ব্যবহার করা নিশ্চিত করে যে প্রতিটি RSA কী স্থাপনার আগে বৈধতা পাস করে। একটি উত্পাদন পরিবেশ কল্পনা করুন যেখানে একটি অপরীক্ষিত PEM কী ব্যর্থ হয়, সমালোচনামূলক ক্রিয়াকলাপগুলিকে ব্যাহত করে। স্বয়ংক্রিয় পরীক্ষার কাঠামো, স্পষ্ট লগিং প্রক্রিয়ার সাথে মিলিত, একটি শক্তিশালী উন্নয়ন কর্মপ্রবাহ তৈরি করে এবং বিস্ময় হ্রাস করে। 🚀
ক্রিপ্টোগ্রাফিক ডিবাগিং সম্পর্কে প্রায়শই জিজ্ঞাসিত প্রশ্নাবলী
- কেন আমি একটি পাচ্ছি PEMException যখন এনক্রিপশন ব্যবহার করবেন না?
- BouncyCastle-এর মতো নির্ভরতা আপনার প্রকল্পে পরোক্ষভাবে অন্তর্ভুক্ত হওয়ার কারণে এই ত্রুটিটি প্রায়ই ঘটে। ব্যবহার করে অপ্রয়োজনীয় মডিউল বাদ দিন Gradle exclude দ্বন্দ্ব প্রতিরোধ করার জন্য আদেশ।
- আমি কিভাবে আমার RSA ব্যক্তিগত কী যাচাই করতে পারি?
- আপনি BouncyCastle এর মত টুল ব্যবহার করতে পারেন PEMParser অথবা ফরম্যাটিং সমস্যাগুলি পরীক্ষা করার জন্য অনলাইন যাচাইকারী। কীগুলির জন্য স্বয়ংক্রিয় ইউনিট পরীক্ষা যোগ করাও সাহায্য করে।
- Gradle আপগ্রেড করা কি এই ত্রুটির সাথে সম্পর্কিত?
- হ্যাঁ, গ্রেডল আপগ্রেডগুলি পুরানো ক্রিপ্টোগ্রাফি লাইব্রেরির সাথে অসঙ্গতি প্রবর্তন করতে পারে। নিশ্চিত করুন যে সমস্ত নির্ভরতা আপডেট করা হয়েছে এবং আপনার Gradle সংস্করণের সাথে সামঞ্জস্যপূর্ণ।
- কি করে malformed sequence এই প্রসঙ্গে মানে?
- এই ত্রুটিটি নির্দেশ করে যে PEM কী ফাইলের গঠন সঠিকভাবে পার্স করা হয়নি। সমস্যাটি একটি ভুল ফর্ম্যাট করা ফাইল বা অসমর্থিত এনক্রিপশন স্ট্যান্ডার্ড থেকে উদ্ভূত হতে পারে।
- আমি কিভাবে Gradle এ অপ্রয়োজনীয় নির্ভরতা বাদ দেব?
- ব্যবহার করুন configurations.all.exclude বিশ্বব্যাপী বিরোধপূর্ণ মডিউলগুলি সরাতে, আপনার বিল্ড প্রক্রিয়াকে স্ট্রিমলাইন করার এবং ত্রুটিগুলি হ্রাস করার জন্য কমান্ড।
ডিবাগিং ক্রিপ্টোগ্রাফিক ইস্যুতে চূড়ান্ত চিন্তাভাবনা
PEMException এর মতো ত্রুটির সম্মুখীন হওয়া কঠিন বোধ করতে পারে, কিন্তু কারণটি বোঝা প্রায়শই সহজ সমাধানের দিকে নিয়ে যায়। BouncyCastle এবং সঠিক Gradle ব্যবস্থাপনার মতো সরঞ্জামগুলি এই সমস্যাগুলি দক্ষতার সাথে সমাধান করতে সহায়তা করে। ধারাবাহিকভাবে আপনার কনফিগারেশন যাচাই করা গুরুত্বপূর্ণ। 😊
লুকানো নির্ভরতা এবং ভুল কনফিগারেশনের সমাধান করা একটি পরিষ্কার, ত্রুটি-মুক্ত উন্নয়ন পরিবেশ নিশ্চিত করে। সর্বোত্তম অনুশীলনগুলি অনুসরণ করে এবং স্বয়ংক্রিয় পরীক্ষাগুলি প্রয়োগ করে, বিকাশকারীরা ক্রিপ্টোগ্রাফিক ত্রুটিগুলি থেকে অপ্রত্যাশিত বাধা ছাড়াই শক্তিশালী অ্যাপ্লিকেশন তৈরিতে ফোকাস করতে পারে।
মূল উৎস এবং তথ্যসূত্র
- PEME ব্যতিক্রম এবং সম্পর্কিত ক্রিপ্টোগ্রাফিক ত্রুটিগুলি সমাধান করার বিষয়ে বিস্তারিত ডকুমেন্টেশন বাউন্সি ক্যাসল লাইব্রেরির অফিসিয়াল ডকুমেন্টেশনে পাওয়া যাবে। ভিজিট করুন বাউন্সি ক্যাসল ডকুমেন্টেশন .
- Gradle কনফিগারেশন এবং নির্ভরতা ব্যবস্থাপনার অন্তর্দৃষ্টি Gradle অফিসিয়াল ব্যবহারকারী গাইড থেকে নেওয়া হয়েছিল। এটি এখানে অন্বেষণ করুন: গ্রেডল ইউজার গাইড .
- অ্যান্ড্রয়েড স্টুডিওতে সাধারণ ডিবাগিং অনুশীলন, লগ বিশ্লেষণ এবং নির্ভরতা সমস্যা সমাধান সহ, জেটব্রেইনের অ্যান্ড্রয়েড স্টুডিও সহায়তা কেন্দ্রে ব্যাখ্যা করা হয়েছে। এটা চেক আউট অ্যান্ড্রয়েড স্টুডিও ডকুমেন্টেশন .
- রিয়েল-ওয়ার্ল্ড ডেভেলপার আলোচনা এবং অনুরূপ সমস্যার সমাধান স্ট্যাক ওভারফ্লো-এর থ্রেড থেকে উল্লেখ করা হয়েছে। এ প্রাসঙ্গিক বিষয় ব্রাউজ করুন স্ট্যাক ওভারফ্লো .