You are on page 1of 9

‫إختصارات‬

‫‪‬‬ ‫مقدمة ›‬
‫‪‬‬ ‫‪ Serialization‬خطوات الـ ›‬
‫‪‬‬ ‫‪ Deserialization‬خطوات الـ ›‬
‫‪‬‬ ‫مثال شامل ›‬
‫‪‬‬ ‫‪ serialVersionUID‬المتغير ›‬
‫مقدمة‬
‫صص البرنامج بالشكل الذي‬ ‫في معظم البرامج التي نستخدمها‪ ,‬نالحظ أنه يوجد مكان خاص لضبط إعدادات البرنامج يسمح للمستخدم أن يخ ّ‬
‫‪.‬يريده‬
‫أن هذه اإلعدادات تظ ّل محفوظة في البرنامج حتى إذا خرج من البرنامج و فتحه من جديد‬ ‫‪.‬بعد أن يقوم المستخدم بضبط إعدادت برنامجه‪ ,‬نالحظ ّ‬
‫فمثالً في البرامج التي تستخدم للكتابة‪ ,‬تجد في صفحة اإلعدادات أنه بإمكانك تغير أنواع الخطوط المستخدمة في البرنامج‪ ,‬و تغيير أحجامها و‬
‫إلخ‬ ‫لغة‬ ‫من‬ ‫بأكثر‬ ‫التطبيق‬ ‫إستخدام‬ ‫بإمكانك‬ ‫أيضا ً أنه‬ ‫اإلعدادات‬ ‫في‬ ‫تجد‬ ‫وقد‬ ‫و‬ ‫‪..‬ألوانها‪.‬‬
‫بالنسبة لأللعاب‪ ,‬غالبا ً ما تجد أنه في صفحة اإلعدادات يمكنك تحديد ما إذا كنت تريد سماع نغمات حماسيّة أثناء اللعب أم ال‪ ,‬باإلضافة إلى إمكانية‬
‫‪ ).‬سهل ‪ -‬متوسّط ‪ -‬صعب ‪ -‬صعب جدا ً ( تحديد مستوى الصوت‪ .‬أيضا ً أحيانا ً تجد أنه يمكنك تحديد مستوى اللعب‬
‫‪.‬للحفاظ على إعدادات البرنامج التي ضبطها المستخدم‪ ,‬نقوم بحفظ هذه اإلعدادات بداخل ملّف و هذا ما ستتعلمه في هذا الدرس‬
‫‪.‬جيّدا ً حتى تستطيع فهم هذا الدرس‪ ,‬ألننا سنقوم بتخزن المعلومات في ملف التعامل مع الملفات عليك فهم درس مالحظة‬

‫شكل الكائن في الذاكرة‬


‫‪.‬يفهمها نظام التشغيل ‪ Bytes‬أثناء تشغيل البرنامج‪ ,‬ك ّل كائن يت ّم إنشاءه فيه‪ ,‬يت ّم تمثيله في الذاكرة كسلسلة كبيرة من الـ‬
‫‪:‬هذه السلسلة تحتوي على جميع معلومات الكائن‪ ,‬مثل‬

‫الكالس المشتق منه‪.‬‬ ‫‪‬‬

‫كل كالس يرث منه‪.‬‬ ‫‪‬‬

‫كل إنترفيس يطبّقه‪.‬‬ ‫‪‬‬

‫كل دالّة يملكها‪.‬‬ ‫‪‬‬

‫كل متغيّر يملكه‪ ,‬باإلضافة إلى نوعه و قيمته الحالية إلخ‪..‬‬ ‫‪‬‬
‫عند تنفيذ جميع األوامر الموجودة في البرنامج أو عند الخروج منه‪ ,‬يتم مسح جميع البيانات المتعلقة بهذا البرنامج من الذاكرة ألنه لم يعد لها‬
‫حاجة‪ .‬أي يتم مسح جميع الكائنات‪ ,‬المتغيرات و الدوال‪ ,‬و بالتالي يتوقف أي إتصال قائم بين البرنامج و أشياء خارجية مثل ملف‪ ,‬شبكة أو قاعدة‬
‫‪..‬بيانات إلخ‬

‫‪ Deserialization‬و الـ ‪ Serialization‬مفهوم الـ‬


‫ملف ‪Serialization‬‬ ‫بداخل‬ ‫الحالية‬ ‫الكائن‬ ‫حالة‬ ‫حفظ‬ ‫‪.‬تعني‬
‫‪.‬عندما نقول‪" :‬حفظ حالة الكائن"‪ ,‬فنحن بذلك نقصد إنشاء نسخة مطابقة من الكائن الموجود في الذاكرة و وضعها في ملّف خارجي‬
‫ملف ‪Deserialization‬‬ ‫في‬ ‫الموجودة‬ ‫الكائن‬ ‫حالة‬ ‫استرجاع‬ ‫‪.‬تعني‬
‫‪.‬عندما نقول‪" :‬استرجاع حالة الكائن"‪ ,‬فنحن بذلك نقصد خلق الكائن الموجود في ملف خارجي بداخل ذاكرة الجهاز‬
‫و نسترجعها‪ ,‬نقول أننا نفعل مالحظة‬ ‫الكائن‬ ‫حالة‬ ‫نحفظ‬ ‫عندما‬ ‫عام‬ ‫‪ Serialization‬بشكل‬ ‫فعليا ً‬ ‫لكننا‬ ‫و‬
‫‪ Serialization + Deserialization.‬نفعل‬

‫‪ Serialization‬أهميّة الـ‬

‫حفظ حالة الكائن الذي ت ّم إنشاءه في الذاكرة في ملف خارجي‪.‬‬ ‫‪‬‬

‫حالة الكائن المحفوظة في ملف يمكن إستخدامها متى شئنا لخلق الكائن من جديد في الذاكرة‪.‬‬ ‫‪‬‬

‫مشاركة حالة الكائن عبر شبكة‪ ,‬حيث أنه يمكن استخدام الملف الذي حفظنا فيه حالة الكائن لخلق الكائن في جهاز آخر‪.‬‬ ‫‪‬‬

‫تخزين الصور في قواعد البيانات ( الصورة تحفظ في قاعدة البيانات كـ ‪.) BLOB‬‬ ‫‪‬‬
‫إذا ً في حال أردت حفظ معلومات الكائن قبل الخروج من البرنامج يمكنك إنشاء ملف متزامن يحفظ لك حالة الكائن‪ ,‬و بعدها يمكنك استرجاعها‬
‫‪.‬عند تشغيل البرنامج من جديد‬

‫‪ Deserialization‬و الـ ‪ Serialization‬تطبيق الـ‬


‫إلنشاء نسخة من الكائن الموجود في الذاكرة و وضعها في ‪ ObjectOutputStream‬نستخدم الكالس ‪ Serialization,‬لتحقيق الـ‬
‫‪.‬ملف‬
‫‪.‬لخلق الكائن المحفوظ في الملف في الذاكرة من جديد ‪ ObjectInputStream‬نستخدم الكالس ‪ Deserialization,‬لتحقيق الـ‬
‫‪.‬كل كالس منهم يملك عدّة كونستركتورات و دوال‪ ,‬سنشرح فقط األشياء التي سنستخدمها في هذا الدرس‬

‫‪ Serialization‬خطوات الـ‬
‫‪:‬إلنشاء كائن من كالس معيّن و حفظ حالته عليك اتباع الخطوات التالية‬
‫الكائن الذي تريد حفظ حالته‪ ,‬يجب أن يكون في األساس مشتق من كالس يفعل ‪ implements‬لإلنترفيس ‪.Serializable‬‬ ‫‪.1‬‬
‫إنشاء ملف إمتداده ‪ .ser‬بواسطة الكالس ‪.FileOutputStream‬‬ ‫‪.2‬‬
‫تجهيز كائن من الكالس ‪ ObjectOutputStream‬الذي يستخدم لكتابة حالة الكائن في الملف‪.‬‬ ‫‪.3‬‬
‫نسخ حالة الكائن الموجود في الذاكرة في هذا الملف بواسطة الدالة )(‪.writeObject‬‬ ‫‪.4‬‬
‫‪ .5‬عند اإلنتهاء من عملية النسخ‪ ,‬نقوم بقطع ك ّل إتصال قمنا بإجرائه مع هذا الملف‪.‬‬

‫‪ transient‬الكلمة المحجوزة‬
‫في تعريف ك ّل شيء ال تريده أن ينسخ ‪ transient‬في حال أردت عدم نسخ جميع األشياء المتعلقة بالكائن في الذاكرة‪ ,‬عليك وضع الكلمة‬
‫‪.‬في الملف‪ ,‬و عندها سيتم تجاهله‬
‫‪ Deserialization‬خطوات الـ‬
‫‪:‬إلسترجاع حالة الكائن التي ت ّم حفظها في ملف معيّن‪ ,‬عليك اتباع الخطوات التالية‬
‫‪ .1‬إنشاء كائن فارغ من نفس نوع الكائن الذي نريد إستراجعه حالته من الملف‪.‬‬
‫‪ .2‬تجهيز كائن من الكالس ‪ FileInputStream‬الذي يستخدم إلدخال بيانات ملف محدّد في الذاكرة‪.‬‬
‫‪ .3‬تجهيز كائن من الكالس ‪ ObjectInputStream‬ليعيد خلق الكائن في الذاكرة‪.‬‬
‫‪ .4‬قراءة حالة الكائن بواسطة الدالّة )(‪ readObject‬و تخزينها في الكائن الفارغ الذي قمنا بإنشائه في الخطوة األولى‪ ,‬و هنا سيكون عليك أن‬
‫لتحول نوع الكائن الذي ترجعه الدالّة )(‪ readObject‬إلى نوع الكائن الحقيقي ألنّها ترجع الكائن الموجود في‬ ‫تفعل ‪ّ DownCasting‬‬
‫الذاكرة كـ ‪ Object‬و ليس كنوعه الحقيقي‪.‬‬
‫‪ .5‬عند اإلنتهاء من عملية النسخ‪ ,‬نقوم بقطع ك ّل إتصال قمنا بإجرائه مع هذا الملف‪.‬‬

‫مثال شامل‬
‫‪ Serializable,‬يطبّق اإلنترفيس ‪ Editor,‬في المثال التالي قمنا بتعرف كالس إسمه‬ ‫و يملك المتغيّرات‬
‫‪: language, encoding, fontSize, fontFamily, autoSave, autoComplete, direction.‬التالية‬
‫‪ Serialization.‬ألننا ال نريد أن يتم حفظ قيمته عندما نفعل ‪ transient‬قمنا بتعريفه كـ ‪ direction‬المتغير‬
‫‪ Deserialization.‬و الـ ‪ Serialization‬قمنا فيه بتطبيق مبدأي الـ ‪ Test‬بعدها قمنا بتعريف كالس آخر إسمه‬
‫السطر‬ ‫السطر ‪ 22‬من‬ ‫الـ ‪ 52‬إلى‬ ‫مبدأ‬ ‫بتطبيق‬ ‫‪ Deserialization.‬قمنا‬
‫من السطر‬ ‫‪59‬‬ ‫إلى السطر‬ ‫‪90‬‬ ‫‪ Serialization.‬قمنا بتطبيق مبدأ الـ‬
‫عند تشغيل البرنامج سيتم خلقه في المجلّد الذي يحتوي ‪ user-prefrences.ser.‬الملف الذي قمنا بتخزين حالة الكائن فيه أسميناه‬
‫‪.‬على المشروع‬

‫‪.‬و سنشرح لك معنى هذا السطر الحقا ً ‪ 6‬قم فقط بإضافة الكود التالي في السطر رقم ‪ Editor‬في حال ظهرت لك مشكلة في الكالس إنتبه‬
‫;‪private static final long serialVersionUID = 1L‬‬

‫مثال‬
‫‪Editor.java‬‬

‫‪1. package‬‬ ‫;‪serialization‬‬

‫‪2.‬‬
‫‪3.‬‬ ‫‪import‬‬ ‫;‪java.io.Serializable‬‬ ‫‪// Serializable‬‬ ‫هنا قمنا‬

‫باستدعاء اإلنترفيس‬
‫‪4.‬‬
‫‪5.‬‬ ‫‪public class‬‬ ‫‪Editor‬‬ ‫‪implements‬‬ ‫{ ‪Serializable‬‬ ‫‪// Serializable‬‬ ‫ّق‬
‫يطب‬

‫هنا قمنا بتعريف كالس إسمه ‪ Student‬اإلنترفيس‬


‫‪6.‬‬
‫‪7.‬‬ ‫‪public‬‬ ‫‪String‬‬ ‫; ‪language‬‬
8. public String encoding ;

9. public String fontSize ;

10. public String fontFamily ;

11. public boolean autoSave ;

12. public boolean autoComplete ;

13. public transient String direction ; // transient ‫كـ‬

direction ‫ّر‬
‫قمنا بتعرف المتغي‬
14.
15. }

Test.java

1. package serialization;

2.
3. import java.io.File; // File ‫هنا قمنا باستدعاء‬

‫الكالس‬
4. import java.io.FileInputStream; // FileInputStream ‫هنا قمنا‬

‫باستدعاء الكالس‬
5. import java.io.FileOutputStream; // FileOutputStream ‫هنا‬

‫قمنا باستدعاء الكالس‬


6. import java.io.ObjectInputStream; // ObjectInputStream ‫هنا‬

‫قمنا باستدعاء الكالس‬


7. import java.io.ObjectOutputStream; // ObjectOutputStream ‫هنا‬

‫قمنا باستدعاء الكالس‬


8. import java.io.IOException; // IOException ‫هنا قمنا‬

‫باستدعاء الكالس‬
9.
10. public class Test {

11.
12. public static void main (String[] args) {

13.
14. // e ‫ إسمه‬Editor ‫ّ مرة نقوم فيها بتشغيل البرنامج سيتم إنشاء كائن‬
‫في كل‬
‫من الكالس‬
15. Editor e = new Editor();

16.
17.
18. // ‫ لمعرفة إذا كان يوجد ملف يحفظ حالة الكائن أم ال‬user-prefrences.ser
‫بعدها سيتم البحث عن الملف‬
19. if ( new File( "./user-prefrences.ser" ).exists() )

20. {
21. // ‫ منه‬e ‫ موجودا سيحاول البرنامج إستعادة حالة الكائن‬user-
prefrences.ser ‫في حال كان الملف‬
22. try
23. {
24. // ‫ في الذاكرة‬user-prefrences.ser ‫حتى نستطيع إدخال المعلومات‬
‫ الموجودة في الملف‬FileInputStream ‫هنا قمنا بإنشاء كائن نوعه‬
25. FileInputStream fis = new FileInputStream( "./user-

prefrences.ser" );

26.
27. // ‫ في الذاكرة‬user-prefrences.ser ‫ المحفوظ في الملف‬Editor
‫ لنتمكن من إعادة خلق كائن الـ‬ObjectInputStream ‫هنا قمنا بإنشاء كائن نوعه‬
28. ObjectInputStream ois = new ObjectInputStream(fis);

29.
30. // e ‫ و قمنا بتخزين حالته في الكائن‬Editor ‫هنا قمنا بقراءة حالة‬
‫ّ خلقه في الذاكرة ككائن من الكالس‬
‫الكائن الي تم‬
31. e = (Editor) ois.readObject();
32.
33. // user-prefrences.ser ‫ّ إتصال قمنا‬
‫في األخير قمنا بقطع كل‬
‫بإجرائه مع الملف‬
34. fis.close();
35. ois.close();

36.
37. // ‫ سيتم طباعة الجملة التالية التي تعني‬,‫في حال عدم حدوث أي خطأ‬
‫ّت بنجاح‬ ّ‫أ‬
‫ن العملية تم‬
38. System.out.println( "Deserialized data has been created in the
memory" );

39. System.out.println( "Language: " + e.language);

40. System.out.println( "Encoding: " + e.encoding);


41. System.out.println( "Font size: " + e.fontSize);

42. System.out.println( "Font family: " + e.fontFamily);

43. System.out.println( "Auto save: " + e.autoSave);

44. System.out.println( "Direction: " + e.direction);

45. System.out.println( "Auto Complete: " + e.autoComplete);

46. System.out.println();
47. }
48. catch (IOException | ClassNotFoundException ex)

49. {
50. // ‫في حال حدوث أي خطأ عند محاولة إسترجاع حالة الكائن سيتم‬
‫عرضعه‬
51. System.out.println(ex.getMessage());
52. }
53. }
54.
55.
56.
57.
58. // user-prefrences.ser ‫ و حفظها في ملف جديد إسمه‬e ‫هنا حاولنا تغيير‬
‫حالة الكائن‬
59. try
60. {
61. // ( ‫ ) أي قمنا بتغيير إعدادات البرنامج‬e ‫هنا قمنا بتغيير قيم‬
‫الكائن‬
62. e. language = "arabic" ;

63. e. encoding = "utf-8" ;

64. e. fontSize = "12pt" ;

65. e. fontFamily = "tahoma" ;

66. e. autoSave = true ;

67. e. direction = "right to left" ;

68.
69. // .ser ‫ إمتداده‬,user-prefrences.ser ‫هنا قمنا بإنشاء ملف إسمه‬
‫‪70.‬‬ ‫= ‪FileOutputStream fos‬‬ ‫‪new‬‬ ‫‪FileOutputStream( "./user-‬‬

‫;) "‪prefrences.ser‬‬

‫‪71.‬‬
‫‪72.‬‬ ‫لنتمكن من استخراج حالة أي كائن موجود في ‪// user-prefrences.ser‬‬
‫هنا قمنا بإنشاء كائن نوعه ‪ ObjectOutputStream‬الذاكرة و وضعها في الملف‬
‫‪73.‬‬ ‫= ‪ObjectOutputStream oos‬‬ ‫‪new‬‬ ‫;)‪ObjectOutputStream(fos‬‬

‫‪74.‬‬
‫‪75.‬‬ ‫‪ e‬في الملف ‪ user-prefrences.ser‬لحفظ اإلعدادات التي قمنا بإدخالها ‪//‬‬
‫هنا قمنا بنسخ حالة الكائن‬
‫‪76.‬‬ ‫;)‪oos.writeObject(e‬‬
‫‪77.‬‬
‫‪78.‬‬ ‫‪// user-prefrences.ser‬‬ ‫ّ إتصال قمنا بإجرائه مع‬
‫في األخير قمنا بقطع كل‬
‫الملف‬
‫‪79.‬‬ ‫;)(‪oos.close‬‬
‫‪80.‬‬ ‫;)(‪fos.flush‬‬
‫‪81.‬‬ ‫;)(‪fos.close‬‬
‫‪82.‬‬
‫‪83.‬‬ ‫‪//‬‬ ‫في حال عدم حدوث أي خطأ‪ ,‬سيتم طباعة الجملة التالية التي تعني ّ‬
‫أن‬
‫ّت بنجاح‬
‫العملية تم‬
‫‪84.‬‬ ‫‪System.out.println( "Serialized data has been saved in the project‬‬
‫;) "‪in a file called user-prefrences.ser‬‬

‫‪85.‬‬ ‫}‬
‫‪86.‬‬ ‫)‪catch (IOException ex‬‬

‫‪87.‬‬ ‫{‬
‫‪88.‬‬ ‫‪//‬‬ ‫في حال حدوث أي خطأ عند نسخ البيانات من الذاكرة إلى الملف سيتم‬
‫عرضه‬
‫‪89.‬‬ ‫;))(‪System.out.println(ex.getMessage‬‬
‫‪90.‬‬ ‫}‬
‫‪91.‬‬
‫‪92.‬‬ ‫}‬
‫‪93.‬‬
‫‪94.‬‬ ‫}‬

‫المرة األولى التي تقوم فيها بتشغيل البرنامج ستحصل على النتيجة التالية •‬
‫‪.‬في ّ‬
‫‪Serialized data has been saved in the project in a file called user-prefrences.ser‬‬

‫المرة الثانية التي تقوم فيها بتشغيل البرنامج ستحصل على النتيجة التالية •‬
‫‪.‬في ّ‬
‫‪Deserialized data has been created in the memory‬‬

‫‪Language:‬‬ ‫‪arabic‬‬

‫‪Encoding:‬‬ ‫‪utf-8‬‬

‫‪Font size:‬‬ ‫‪12pt‬‬

‫‪Font family:‬‬ ‫‪tahoma‬‬

‫‪Auto save:‬‬ ‫‪true‬‬

‫‪Direction:‬‬ ‫‪null‬‬

‫‪Auto Complete: false‬‬

‫‪Serialized data has been saved in the project in a file called user-prefrences.ser‬‬

‫محرر و عندها ستتمكن من رؤية ‪ user-prefrences.ser‬بما أنّه قد تم إنشاء الملف‬ ‫ّ‬ ‫ي‬
‫بنجاح‪ ,‬يمكنك البحث عنه و فتحه بواسطة أ ّ‬
‫‪.‬شكل المعلومات التي كانت مسجّلة في الذاكرة‬
‫كقيمة ‪ null‬لذلك تم إعطائه القيمة ‪ transient,‬في الملف ألننا قمنا بتعريفها كـ ‪ direction‬الحظ أنّه لم يت ّم حفظ قيمة المتغيّر‬
‫‪.‬إفتراضية‬

‫‪ serialVersionUID‬المتغير‬
‫اإلنترفيس‬ ‫يطبّق‬ ‫كالس‬ ‫فيه ‪ Serializable‬كل‬ ‫خاص‬ ‫إصدار‬ ‫رقم‬ ‫إعطاءه‬ ‫‪.‬يتم‬
‫‪ serialVersionUID.‬هذا الرقم يتم تخزينه في المتغير‬
‫‪.‬حتى لو لم يت ّم تعريفه ‪ serialVersionUID‬يملك متغيّر إسمه ‪ Serializable,‬إذا ً كل كالس يطبّق اإلنترفيس‬
‫‪.‬رقم اإلصدار يضمن أن المرسل و المستقبل للملف على الشبكة يملكون نفس نسخة الكالس للكائن المحفوظ في الملف‬
‫في حال كان رقم اإلصدار في كالس المرسل مختلف عن رقم اإلصدار في كالس المستقبل يتم رمي إستثناء من‬
‫‪ InvalidClassException.‬النوع‬
‫مهم جدا ً عند بناء تطبيق يشارك البيانات بين سيرفر و عميل‪ ,‬أي يوجد تطبيق على السيرفر و ‪ serialVersionUID‬إذا ً رقم اإلصدار‬
‫‪.‬تطبيق عند المستخدم العادي مرتبطان مع بعضهما البعض‪ .‬سنرى ذلك في الدرس التالي‬
‫ليس أمرا ً إجباريا ً في حال كنت تبني برنامج ال تشارك فيه البيانات مع برنامج آخر‪ serialVersionUID ,‬بشكل عام‪ ,‬تعريف المتغيّر‬
‫أن ‪ Eclipse,‬ألن جافا أصالً ستقوم بتعريفه عنك في حال لم تقم بتعريفه بنفسك‪ ,‬لكن في بعض بيئات العمل مثل بيئة‬ ‫نالحظ ّ‬
‫من جديد في البرنامج‪ ,‬لذلك ننصحك بتعريفه في ‪ serialVersionUID‬يظهر تحذير في حال لم نقم بتعريف المتغيّر ‪ Complier‬الـ‬
‫‪.‬جميع الحاالت ألنه لن يؤثر أصالً على الكود‬
‫‪ serialVersionUID‬طريقة تعريف المتغيّر‬
‫‪ static final long.‬و لن يشكل ذلك أي فرق هنا‪ ,‬لكنك مجبر على تعريفه كـ ‪ Access Modifier‬في البداية يمكنك وضع أي‬

‫مثال‬
‫‪ 1L‬وضعنا قيمته ‪ Editor‬في اإلصدار األول من الكالس •‬
‫‪private static final long‬‬ ‫‪serialVersionUID‬‬ ‫;‪= 1L‬‬

‫‪ 2L‬وضعنا قيمته ‪ Editor‬في اإلصدار الثاني من الكالس •‬


‫‪private static final long‬‬ ‫‪serialVersionUID‬‬ ‫;‪= 2L‬‬

You might also like

  • Adv 11
    Adv 11
    Document18 pages
    Adv 11
    hisham
    No ratings yet
  • Adv 12
    Adv 12
    Document5 pages
    Adv 12
    hisham
    No ratings yet
  • Adv 8
    Adv 8
    Document39 pages
    Adv 8
    hisham
    No ratings yet
  • Adv 9
    Adv 9
    Document11 pages
    Adv 9
    hisham
    No ratings yet
  • Adv 8
    Adv 8
    Document39 pages
    Adv 8
    hisham
    No ratings yet
  • Adv 7
    Adv 7
    Document6 pages
    Adv 7
    hisham
    No ratings yet
  • Adv 6
    Adv 6
    Document4 pages
    Adv 6
    hisham
    No ratings yet
  • Adv 3
    Adv 3
    Document42 pages
    Adv 3
    hisham
    No ratings yet
  • Adv 1
    Adv 1
    Document9 pages
    Adv 1
    hisham
    No ratings yet
  • Adv 5
    Adv 5
    Document22 pages
    Adv 5
    hisham
    No ratings yet
  • Adv 4
    Adv 4
    Document23 pages
    Adv 4
    hisham
    No ratings yet
  • Adv 2
    Adv 2
    Document55 pages
    Adv 2
    hisham
    No ratings yet