تتوفَّر تَعْليمَتين للتَفْرِيع (branching statements) بلغة الجافا، وفي هذا القسم، سنتناول تَعْليمَة التَفْرِيع الأولى if
، والتي قد سبق وتَعرَّضنا لها بالفعل بالقسم ٣.١.
تُكتب تَعْليمَة التَفْرِيع الشَّرْطيّة if
بالصياغة التالية:
if ( <boolean-expression> ) <statement-1> else <statement-2>
تُسمى هذه الصياغة من if
بتَعْليمَة التَفْرِيع الثنائي (two-way branch)، وكما هو مُتوقَّع، يُمكِن للتعليمتين else
المُكوَّن من الكلمة else
والتعليمة
مشكلة تَّدَلِّي else
لمّا كانت تَعْليمَة if
هي بالنهاية مُجرَّد تَعْليمَة، فإنه من المُمكن لإحدى التعليمتين if
بذاتهما، ولكن قد يتَسبَّب ذلك بحُدوث مشاكل في بعض الأحيان.
فمثلًا، إذا اِستخدَمت تَعْليمَة if
بدون الجزء else
محل التعليمة
if ( x > 0 ) if (y > 0) System.out.println("First case"); else System.out.println("Second case");
قد يُعطيك اِستخدَامك للمسافات البادئة (indentation) -ببداية كل سطر من الشيفرة- انطباعًا خاطئًا بأن الجزء else
هو النصف الآخر من تَعْليمَة if (x > 0)
، لكن هذا غَيْر صحيح. لا يُعطِي الحاسوب في الواقع أيّ اعتبار لتلك المسافات، وإنما يَتبِّع -في هذه الحالة بالتَحْدِيد- قاعدة بسيطة، وهي ربْط الجزء else
بأقرب تَعْليمَة if
ليس لديها جزء else
خاص بها، مما يَعني أنه سيَربُط الجزء else
بتَعْليمَة if (y > 0)
؛ لأنها الأقرب. ولهذا يَقرأ الحاسوب التَعْليمَات بالأعلى كما لو كانت مُرَتَّبة على النحو التالي:
if ( x > 0 ) if (y > 0) System.out.println("First case"); else System.out.println("Second case");
تستطيع مع ذلك إجبار الحاسوب على اِستخدَام التفسير الآخر بتَضْمِين تَعْليمَة if
الداخلية داخل كُتلَة (block)، كالتالي:
if ( x > 0 ) { if (y > 0) System.out.println("First case"); } else System.out.println("Second case");
تختلف بالطبع نتائج تَعْليمَتي if
السابقتين. فمثلًا إذا كانت قيمة المُتَغيِّر x
أقل من أو تُساوِي الصفر، لا تَطبع التَعْليمَة الأولى شيئًا، بينما تَطبع الثانية السِلسِلة النصية "Second case".
التفريع المتعدد (Multiway Branching)
من الجهة الآخرى، تُصبِح الأمور أكثر تشويقًا عندما تَستخدِم تَعْليمَة if
محل التعليمة else
الأخير-:
if ( <boolean-expression-1> ) <statement-1> else if ( <boolean-expression-2> ) <statement-2> else <statement-3>
ولمّا كان الحاسوب لا يَهتم بطريقة تَنْسِيق الشيفرة على الصفحة، فتقريبًا دائمًا ما يُكتَب المثال السابق بالصيغة التالية:
if ( <boolean-expression-1> ) <statement-1> else if ( <boolean-expression-2> ) <statement-2> else <statement-3>
تُسمى هذه الصياغة من if
-بالأعلى- بتَعْليمَة التَفْرِيع الثلاثي (three-way branch)، وينبغي أن تُفكر بها كتَعْليمَة واحدة؛ فبالنهاية، ستُنفَّذ واحدة فقط من التعليمات الثلاثة true
، سيُنفِّذ الحاسوب التعليمة if
الخارجية مُتخَطِّيًا بذلك العبارتين الآخريتين تمامًا. أما إذا آلت قيمتها إلى القيمة المنطقية false
، فإنه سيتَخَطَّى التعليمة if
الثانية المُتداخِلة (nested)؛ ليَفحْص قيمة التعبير
مثلًا، يَطبع المثال التالي واحدة من ثلاث رسائل مُحتمَلة وفقًا لقيمة المُتَغيِّر temperature
:
if (temperature < 50) System.out.println("It's cold."); else if (temperature < 80) System.out.println("It's nice."); else System.out.println("It's hot.");
على سبيل المثال، إذا كان المُتَغيِّر temperature
يَحمِل القيمة ٤٢، فسيَتحقَّق أول شَّرْط، ومِنْ ثَمَّ تُطبَع الرسالة "It's cold"، لينتقل بَعْدها الحاسوب إلى ما بعد التَعْليمَة مُتخَطِّيًا بقيتها، وبدون حتى محاولة اختبار الشَّرْط الثاني. أما إذا كانت قيمته تُساوِي ٧٥، فلن يتحقَّق أول شَّرْط، لذلك سينتقل الحاسوب لاختبار الشَّرْط الثاني، الذي سيتحقَّق لتتم طباعة الرسالة "It's nice"، ثم سيتَخَطَّى بقية التَعْليمَة. أخيرًا إذا كانت قيمته تُساوِي ١٧٣، لا يتحقَّق أي من الشَّرْطين، وتُطبَع الرسالة "It's hot" (لو لم تَكن دوائره الكهربية قد اِحترقَت بفِعْل الحرارة).
يُمكنك الاستمرار بإضافة المزيد من عبارات else-if
بأيّ عَدَد، وفي تلك الحالة، يُطلَق عليها اسم تَعْليمَة التَفْرِيع المُتعدِّد (multiway branches)، كالتالي:
if ( <test-1> ) <statement-1> else if ( <test-2> ) <statement-2> else if ( <test-3> ) <statement-3> . . // أضف المزيد . else if ( <test-N> ) <statement-N> else <statement-(N+1)>
الاختبارات **true
، فيُنفِّذ عندها الحاسوب التعليمة true
، تُنفَّذ عندها التعليمة else
. لاحِظ أنه دائمًا ما ستُنفَّذ واحدة فقط لا غَيْر من كل هذه التعليمات else
الأخير، ولكن -في تلك الحالة- إذا لم تتحقَّق أيّ من التعبيرات المنطقية، وآلت جميعا إلى القيمة المنطقية false
، فلن تُنفَّذ أيّ عبارة نهائيًا. يُمكن بالطبع لأيّ من التعليمات
قد يَنْتابك شُعور بالارتباك لوجود الكثير من قواعد الصياغة (syntax) الجديدة هنا، ولكن أَضمَن لك أنه مع قليل من الممارسة، ستعتاد عليها. يُمكنك أيضًا أن تُلقي نظرة على المُخطط التالي، والذي يُوضِح مَسار التحكُّم (flow control) أثناء تَّنْفيذ الصيغة الأعم من تَعْليمَة if..else if
والمعروفة باسم تَعْليمَة التَفْرِيع المُتعدِّد:
أمثلة
لنفْترَض أن لدينا ثلاثة مُتَغيِّرات x
و y
و z
من النوع العددي int
، يَحتوِي كل منها على قيمة عددية معينة. المطلوب هو طباعة قيم المُتَغيِّرات الثلاثة بحيث تكون مُرَتَّبة ترتيبًا تصاعديًا. فمثلًا، إذا كانت قيم المُتَغيِّرات هي ٤٢ و ١٧ و ٢٠، فلابُدّ من طباعتها على الترتيب ١٧ و ٢٠ و ٤٢.
لحل هذه المسألة، سنحاول الإجابة على السؤال التالي: "لنتخيل أن لدينا قائمة مُرَتَّبة بالفعل، فبأيّ مكان يَنبغي للمُتَغيِّر x
أن يقع؟" ببساطة، إذا كانت قيمة المُتَغيِّر x
أصغر من قيمة كلا المُتَغيِّرين y
و z
، فإنه سيأتي بأول القائمة، أما إذا كان أكبر من كليهما، فإنه سيأتي بذيل القائمة، وأخيرًا، سيأتي بوسط القائمة في أيّ حالة غَيْر تلك الحالتين. يُمكن التعبير عن الحالات الثلاثة السابقة بتَعْليمَة التَفْرِيع الثلاثي if
، مع ذلك ما يزال أمامنا تحديًا لإيجاد طريقة نُحدِّد من خلالها ترتيب طباعة المُتَغيِّرين y
و z
. انظر الشيفرة الوهمية (pseudocode):
if (x < y && x < z) { // اطبع x متبوعة بكلا من y و z بترتيبها الصحيح output x, followed by y and z in their correct order } else if (x > y && x > z) { // اطبع y و z بترتيبها الصحيح متبوعين بقيمة x output y and z in their correct order, followed by x } else { // اطبع x بين y و z بترتيبها الصحيح output x in between y and z in their correct order }
يتطلب تَحْدِيد ترتيب طباعة المُتَغيِّرين y
و z
تَعْليمَة if
آخرى داخلية. انظر الشيفرة التالية بلغة الجافا:
if (x < y && x < z) { // إذا كانت x بالبداية if (y < z) System.out.println( x + " " + y + " " + z ); else System.out.println( x + " " + z + " " + y ); } else if (x > y && x > z) { // إذا كانت x بالنهاية if (y < z) System.out.println( y + " " + z + " " + x ); else System.out.println( z + " " + y + " " + x ); } else { // إذا كانت x في الوسط if (y < z) System.out.println( y + " " + x + " " + z); else System.out.println( z + " " + x + " " + y); }
حَاوِل اختبار ما إذا كانت الشيفرة بالأعلى ستَعمَل بشكل سليم حتى في حالة وجود أكثر من مُتَغيِّر يَحمِل نفس القيمة. عمومًا إذا كان هناك مُتَغيِّرين بنفس القيمة، فإنه لم يَعُدْ مهمًا بأيّ ترتيب سيَتِمّ طباعتهما.
بخلاف اللغات الطبيعية التي تَسمَح بكتابة جملة مثل "إذا كان x أصغر من y و z"، لا يُمكنك أن تَفعَل الشيء نفسه -أيّ كتابة التعبير if (x < y && z)
- بلغة الجافا. لا تَسير الأمور بهذه البساطة، فلابُدّ أن يَستقبِل العَامِل (operator) المنطقي &&
مُعامِلين منطقيين (boolean)، ولهذا ستحتاج إلى إِجراء الاختبارين x<y
و x<z
بشكل منفصل، ثم تُطبِّق العَامِل المنطقي &&
على نتيجتيهما.
ربما تَتَّخذ منحى آخر لحل نفس المسألة، وذلك بمحاولة الإجابة على السؤال: "بأيّ ترتيب يَنبغي طباعة المُتَغيِّرين x
و y
؟". بمُجرَّد أن تتَوصَّل لإجابة، سيتبقَّى فقط أن تُحدِّد مكان المُتَغيِّر z
. انظر الشيفرة التالية بلغة الجافا:
if ( x < y ) { // x comes before y if ( z < x ) // z comes first System.out.println( z + " " + x + " " + y); else if ( z > y ) // z comes last System.out.println( x + " " + y + " " + z); else // z is in the middle System.out.println( x + " " + z + " " + y); } else { // y comes before x if ( z < y ) // z comes first System.out.println( z + " " + y + " " + x); else if ( z > x ) // z comes last System.out.println( y + " " + x + " " + z); else // z is in the middle System.out.println( y + " " + z + " " + x); }
تتوفَّر عادةً عدة طرائق وأساليب مختلفة لحل نفس المشكلة. فمثلًا، بالمثال السابق، تَعرَّضنا لحلّين فقط ضِمْن عدة حلول مُحتمَلة آخرى كثيرة. فمثلًا، قد يقوم حل آخر ثالث بتبديل قيمة (swap) المُتَغيِّرين x
و y
إذا كانت قيمة x
أكبر من قيمة y
، ومِنْ ثَمَّ سيكون من الضروري طباعة قيمة المُتَغيِّر x
قبل y
.
سنحاول أخيرًا كتابة برنامج كامل يَستخدِم تَعْليمَة if
بطريقة مُشوِّقة. هدف البرنامج عمومًا هو تَحْوِيل قياسات الطول (measurements of length) من إحدى وَحَدات قياس الطول (units of measure) إلى آخرى، فمثلًا من المِيل (miles) إلى اليَارْدَة (yards)، أو من البُوصَة (inches) إلى القَدَم (feet). سنحتاج بالتأكيد أن نكون أكثر تحديدًا بخُصوص مُتطلَّبات البرنامج؛ فما تزال المسألة غَيْر واضحة المعالِم حتى الآن، ولهذا سنفْترَض أن البرنامج يتَعامَل فقط مع وَحَدات القياس التالية: البُوصَة، والقَدَم، واليَارْدَة، والمِيل؛ وسيكون من السهل إضافة المزيد منها فيما بَعْد. سيُدْخِل المُستخدِم قياس الطول بأي وَحدة من وَحَدات القياس المسموح بها، كأن يَكتُب "١٧ قدم" أو "٢.٧٣ ميل"، ربما بَعْدها قد تَطلُب من المُستخدِم إِدْخَال اسم وَحدة القياس المطلوب التَحْوِيل إليها، بحيث تُطبَع كخَرْج (output) للبرنامج. لكننا في الواقع سنكتفي بطباعة قياس الطول بجميع وَحَدات القياس المسموح بها؛ وذلك في محاولة لتبسيط المسألة. انظر الخوارزمية التالية المبدئية:
// اقرأ كلا من قياس الطول ووحدة القياس المستخدمة Read the user's input measurement and units of measure // حول قيمة قياس الطول المعطاة إلى وحدات القياس الأخرى Express the measurement in inches, feet, yards, and miles // اطبع قياسات الطول بالوحدات الأربعة Display the four results
لابُدّ أن يَستقبِل البرنامج مُدْخَلين (input) من المُستخدِم، هما قياس الطول ذاته بالإضافة إلى وَحدة القياس المُستخدَمة (units of measure)، ولهذا تُستخدَم الدالتين TextIO.getDouble()
و TextIO.getlnWord()
؛ لقراءة كلًا من قياس الطول العددي واسم وَحدة القياس من نفس السَطْر على الترتيب.
سنبدأ دائمًا بتَحْوِيل قياس الطول المُعْطى إلى إِحدى وَحَدات قياس الطول -ولتكن البُوصَة-؛ وذلك لتوحيد الخطوات التالية المسئولة عن التَحْوِيل إلى وَحَدات القياس الأخرى. يَلزَمنا الآن فقط تَحدِّيد وَحدة القياس التي أَدْخَل بها المُستخدِم قياس الطول؛ وذلك لنتمكن من تَحْوِيلها إلى وَحدة البُوصَة. بَعْد إجراء ذلك التَحْوِيل، سيكون من السهل تَحْوِيل قياس الطول بوَحدة البُوصَة إلى كلًا من القَدَم، واليَارْدَة، والمِيل. اُنظر الخوارزمية التالية:
Let measurement = TextIO.getDouble() Let units = TextIO.getlnWord() // إذا اسم وحدة القياس المعطى هو البوصة if the units are inches Let inches = measurement // إذا اسم وحدة القياس المعطى هو القدم else if the units are feet Let inches = measurement * 12 // 12 inches per foot // إذا اسم وحدة القياس المعطى هو الياردة else if the units are yards Let inches = measurement * 36 // 36 inches per yard // إذا اسم وحدة القياس المعطى هو الميل else if the units are miles Let inches = measurement * 12 * 5280 // 5280 feet per mile // إذا لم يكن اسم وحدة القياس المعطى أي من القيم الأربعة السابقة else // اسم وحدة القياس المعطى غير صالح The units are illegal! // اطبع رسالة خطأ واوقف المعالجة Print an error message and stop processing // إجراء التحويلات Let feet = inches / 12.0 Let yards = inches / 36.0 Let miles = inches / (12.0 * 5280.0) // اعرض النتائج Display the results
لمّا كنا سنقرأ اسم وَحدة القياس المُعْطاة إلى المُتَغيِّر units
، وهو من النوع String
، فسنحتاج إلى إجراء موازنة نصية (comparison) لتَحدِّيد وَحدة القياس المُناظِرة. تُستخدَم الدالة units.equals("inches")
لفَحْص ما إذا كانت قيمة المُتَغيِّر units
تُساوِي السِلسِلة النصية "inches"، لكن لا يَنطوِي إِلزام المُستخدِم على إِدْخَال الكلمة "inches" حرفيًا على أفضل تجربة للمُستخدِم (user experience)؛ فمن الأفضل أن نَسمَح له بكتابة كلمات أخرى مثل "inch" أو "in"، ولذلك سنُجري الفَحْص على التعبير المنطقي التالي:
units.equals("inches") || units.equals("inch") || units.equals("in")
وذلك للسماح بالاحتمالات الثلاثة. يُمكننا أيضًا أن نَسمَح له بكتابة وَحدة القياس بحروف كبيرة (upper case) مثل "Inches" أو "IN" إِمّا عن طريق تَحْوِيل السِلسِلة النصية المُعْطاة units
إلى حروف صغيرة (lower case) قبل إجراء الفَحْص، أو باِستخدَام الدالة units.equalsIgnoreCase
للموازنة بدلًا من units.equals
.
تَسمَح النسخة النهائية من البرنامج للمُستخدِم بتَكْرار عمليتي الإِدْخَال والطباعة أكثر من مرة؛ حيث سيَتوقَف البرنامج فقط عند إِدْخَال القيمة صفر. كل ما تَطلبه الأمر هو إِحاطة الخوارزمية بالأعلى ضِمْن حَلْقة التَكْرار while
، والتأكد من إِيقافها عندما يُدخِل المُستخدِم القيمة صفر. اُنظر الشيفرة بالكامل:
import textio.TextIO; public class LengthConverter { public static void main(String[] args) { double measurement; // قياس الطول المعُطى String units; // اسم وحدة قياس المعطاة // قياس الطول بوحدات القياس الأربعة المتاحة double inches, feet, yards, miles; System.out.println("Enter measurements in inches, feet, yards, or miles."); System.out.println("For example: 1 inch 17 feet 2.73 miles"); System.out.println("You can use abbreviations: in ft yd mi"); System.out.println("I will convert your input into the other units"); System.out.println("of measure."); System.out.println(); while (true) { // اقرأ مُدخَل المستخدم System.out.print("Enter your measurement, or 0 to end: "); measurement = TextIO.getDouble(); if (measurement == 0) break; // اِنهي حلقة while units = TextIO.getlnWord(); units = units.toLowerCase(); // صغر الحروف // حول قياس الطول المعطى إلى وحدة البوصة if (units.equals("inch") || units.equals("inches") || units.equals("in")) { inches = measurement; } else if (units.equals("foot") || units.equals("feet") || units.equals("ft")) { inches = measurement * 12; } else if (units.equals("yard") || units.equals("yards") || units.equals("yd")) { inches = measurement * 36; } else if (units.equals("mile") || units.equals("miles") || units.equals("mi")) { inches = measurement * 12 * 5280; } else { System.out.println("Sorry, but I don't understand \"" + units + "\"."); continue; // عد إلى بداية حلقة while } // حوِّل قياس الطول بوحدة البوصة إلى وحدات القياس الآخرى feet = inches / 12; yards = inches / 36; miles = inches / (12*5280); // اطبع قياس الطول بوحدات القياس الأربعة System.out.println(); System.out.println("That's equivalent to:"); System.out.printf("%14.5g inches%n", inches); System.out.printf("%14.5g feet%n", feet); System.out.printf("%14.5g yards%n", yards); System.out.printf("%14.5g miles%n", miles); System.out.println(); } // نهاية تعليمة while System.out.println(); System.out.println("OK! Bye for now."); } // نهاية برنامج main } // نهاية الصنف LengthConverter
لمّا كنا غَيْر مُتحكِّمين بقيم الأعداد الحقيقية (real numbers) المُدْخَلة؛ حيث تَعتمِد على المُستخدِم الذي ربما قد يَرغَب بإِدْخَال قياسات صغيرة جدًا أو ربما كبيرة جدًا، فكان لابُدّ من صياغة الخَرْج باِستخدَام مُحدِّدات الصيغة (format specifiers). اُستخدِم تحديدًا مُحدِّد الصيغة g
-بالبرنامج-، والذي يَعمَل كالتالي: إذا كان العَدَد كبيرًا جدًا أو صغيرًا جدًا، فإنه يَطبَعه بصيغة أسّية (exponential form)، أمّا إن لم يَكُن كذلك، فإنه يَطبَعه بالصيغة الرقمية (decimal form) العادية. تَذَكَّر أن القيمة 5
، مثلًا، بمُحدِّد الصيغة %14.5g
تُشير إلى العدد الكلي للأرقام المعنوية (significant digits) المَطبُوعة، وبذلك سنَحصُل دائمًا على نفس العَدَد من الأرقام المعنوية (significant digits) بالخَرْج بِغَضّ النظر عن قيمة العَدَد المُدْخَل. يَختلف ذلك عن مُحدِّد الصيغة f
، والذي يَطبَع الخَرْج بصيغة رقمية (decimal form)، ولكن تُشير فيه القيمة 5
، مثلًا، بمُحدِّد الصيغة %14.5f
إلى عَدَد الأرقام بَعْد العلامة العَشريّة (decimal point)، أيّ إذا كان لدينا العَدَد 0.000000000745482
فإن مُحدِّد الصيغة f
سيَطبَعه إلى 0.00000
، بدون أيّ أرقام معنوية (significant digits) على الإطلاق، أما مُحدِّد الصيغة g
فسيَطبَعه 7.4549e-10
.
التعليمة الفارغة (Empty Statement)
تُوفِّر لغة الجافا تَعْليمَة آخرى يُطلَق عليها اسم التَعْليمَة الفارغة (empty statement)، وهي ببساطة مُجرَّد فاصلة منقوطة ;
، وتَطلُب من الحاسوب أن يَفعَل "لا شيء". اُنظر المثال التالي:
if (x < 0) { x = -x; };
عملية إِضافة فاصلة منقوطة (semicolon) بَعْد القوس {
، كما بالمثال السابق، هي عملية صحيحة تمامًا وِفقًا لقواعد بناء الجملة (syntax)، لكن، في هذه الحالة، لا يعدّها الحاسوب جزءًا من تَعْليمَة if
، وإنما يُعامِلها معاملة تَعْليمَة فارغة (empty statement) مستقلة بذاتها. عمومًا ليس هذا الغرض من تَوفَّر التَعْليمَة الفارغة بلغة الجافا، ولن تجدها مُستخدَمة بهذه الطريقة إلا نادرًا، وإنما ستَستخدِمها أحيانًا عندما تُريد أن تَطلُب من الحاسوب ألا يَفعَل شيئًا. على سبيل المثال:
if ( done ) ; // تعليمة فارغة else System.out.println( "Not done yet.");
تَطلُب الشيفرة بالأعلى من الحاسوب ألا يَفعَل شيئًا إذا كانت قيمة المُتَغيِّر المنطقي done
مساوية للقيمة المنطقية true
، وأن يَطبَع السِلسِلة النصية "Not done yet" إذا كانت قيمته مُساوية للقيمة المنطقية false
. لا يمكنك في هذه الحالة أن تَحذِف الفاصلة المنقوطة (semicolon)؛ لأن قواعد الصياغة بلغة الجافا (Java syntax) تَتَطلَّب وجود تَعْليمَة بين if
و else
. يُفضِّل الكاتب على الرغم من ذلك اِستخدَام كُتلَة (block) فارغة أي اِستخدَام قوسين فارغين في تلك الحالات.
عادةً ما تَتسبَّب إضافة التَعْليمَة الفارغة ;
دون قصد بحُدوث أخطاء (errors) يَصعُب إِيجادها. انظر المثال التالي:
for (i = 0; i < 10; i++); System.out.println("Hello");
يَطبَع المثال بالأعلى كلمة "Hello" مرة واحدة فقط وليس عشر مرات كما قد تَظُنّ -بالأخص مع وجود المسافة البادئة (indentation) ببداية السطر الثاني-. السبب ببساطة هو وجود فاصلة منقوطة ;
بنهاية تَعْليمَة for
بنهاية السَطْر الأول. تُعدّ هذه الفاصلة المنقوطة ;
-في هذه الحالة- تَعْليمَة بحد ذاتها، هي التَعْليمَة الفارغة (empty statement)، وهي في الواقع ما يتم تَّنْفيذه عشر مرات، أي أن حَلْقة التَكْرار for
بالأعلى تَفعَل "لا شئ" عشر مرات. في المقابل، لا تُعدّ التَعْليمَة System.out.println
جزءً من تَعْليمَة for
أساسًا، ولذلك تُنفَّذ مرة واحدة فقط بعد انتهاء تَعْليمَة حَلْقة for
.
ترجمة -بتصرّف- للقسم Section 5: The If Statement من فصل Chapter 3: Programming in the Small II: Control من كتاب Introduction to Programming Using Java.
أفضل التعليقات
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.