اذهب إلى المحتوى

وليد زيوش

الأعضاء
  • المساهمات

    78
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    1

كل منشورات العضو وليد زيوش

  1. Vagrant هو برنامج يُمكّنك من إنشاء وإعداد بيئات عمل خفيفة للتطوير عليها عن طريق تشغيل آلة وهمية. لماذا أستعمل Vagrant إذا كنت مطور ويب فسيساعدك البرنامج على محاكاة بيئة الخادوم عن طريق تنصيب إحدى نسخ لينكس للخواديم على جهازك. كما يساعدك أيضًا على تجربة تطبيقات الويب خاصتك بدون خوف من الخطأ أو الخوف على جهازك. وإذا كنت تعمل ضمن فريق عمل فإنه سيجعل من العمل أسهل بجعل بيئات التطوير واحدة بنفس البرمجيات والأنظمة. البدء في استعمال Vagrant قبل البدء يجب أن يكون لديك برنامج للآلات الوهمية مثبت ويفضل أن يكون Virtualbox. سيأتي ذكر كيفية ربطه مع برامج أخرى في آخر المقالة. بعد تثبيت Virtualbox يمكنك تثبيت النسخة المناسبة من Vagrant من هنا. أنشأ مجلدًا جديدًا لبيئة العمل خاصتك. وادخل إليه من الطرفية عن طريق الأمر: $ cd myfirst_project_dir ثم اكتب الأمر التالي: $ vagrant init ubuntu/trusty32 ستلاحظ أنه وفي أول مرة فقط بدأ بتحميل الملفات الخاصة بهذه الآلة وستلحظ أيضًا إنشاء ملف في هذا المجلد باسم Vagrantfile. بعد الانتهاء من التحميل قم بتشغيل الآلة الوهمية عن طريق الأمر التالي مع التأكد أنك ما زلت في نفس المجلد : $ vagrant up انتظر قليلًا، بعد الانتهاء، مبارك لك تم تشغيل نظام أوبنتو 14.04 للخادم. بدأ العمل يمكنك الآن للتحكم في النظام كتابة الأمر التالي : $ vargant ssh وسيتم الدخول إلى جلسة الطرفية عن طريق بروتوكول SSH . يمكنك الآن كتابة أوامر لنظام أوبنتو كما تشاء. يمكنك لتثبيت حزمة LAMP $ sudo apt-get install lamp-server^ يمكنك تثبيت أي برامج أو تطبيقات عن طريق سطر الأوامر يمكنك إذا أردت تثبيت Ngnix الاطلاع على هذا الدرس اتبع الإرشادات الخاصة بأوبنتو لأن الصندوق الذي استعملناه هو الخاص بأوبنتو (كما سيأتي لاحقًا في شرح الصناديق). يمكنك أيضًا تثبيت phpmyadmin كما يشرح الدرس لتالي. المجلدات المشتركة انتهيت من إعداد بيئة العمل تريد الآن البدأ في البرمجة ولكن هل ستضطر للدخول إلى جلسة الطرفية هذه كل مرة والعمل عن طريق محررات نصية كـ vim كي تستطيع العمل؟؟ الإجابة هي لا ففي الحقيقة المجلد الذي مساره داخل البيئة الوهمية /vagrant هو نفسه المجلد الذي أنشأت فيه الآلة في البداية أي المجلد الذي يتواجد بداخله ملفVagrantfile. ولتتأكد من كلامي هذا أنشأ في المجلد الحالي ملفًا نصيًا اسمه foo.txt ثم ادخل الآن إلى جلسة الطرفية الخاصة بالآلة الوهمية واكتب : $ cd /vagrant $ ls ستفاجئ بوجود الملف الذي أنشأته سابقًا وبهذا يمكننا Vagrant من العمل على المحررات التي نفضلها من واجهتنا الرسومية ومشاركة كل ما نعمله مع الآلة الضيف. يمكنك أيضًالمشاركة مجلدات أخرى غير هذا المجلد كتابة الآتي داخلVagrantfile : config.vm.synced_folder "src/", "/srv/website" حيث أن المسار الأول هو مسار المجلد الذي تريد مشاركته على آلتك المضيفة والمسار الثاني هو مسار المجلد الموجود في الآلة الوهمية. تهيئة الشبكة الآن بعد تثبيت apache مع حزمة LAMP تريد تصفح الموقع المتواجد على الخادوم على الآلة الضيف من على متصفحك من جهازك فكيف تفعل هذا. يمكنك فعل هذا بتعديل ملف Vagrantfile بحيث سيشبه الآتي : Vagrant.configure("2") do |config| config.vm.box = "ubuntu/trusty32" config.vm.network :forwarded_port, guest: 80, host: 4567 end اكتب الأمر التالي في حاسوبك (ليس بداخل الآلة الوهمية) داخل مجلد الآلة الوهمية: $ vagrant reload الآن يمكنك تصفح موقعك من على الرابط التالي http://127.0.0.1:4567 داخل متصفحك. جعل المجلد الافتراضي لـapache في/vagrant أنت الآن تريد إضافة ملفات البرمجة الخاصة بك وبدأت العمل عليها في المُجلّد/vagrant ولكن لا تزال هناك مشكلة فـapache يحدد المُجلّد /var/www/htmlكمُجلّد افتراضي توجد عليه الملفات التي سوف تمثل واجهة الموقع لذا علينا أن نجعل المُجلّد الافتراضي هو /vagrant/my_awesome_project والذي ستضع عليه ملفات الـPHP الخاصة بمشروعك. في البداية أنشئ في المُجلّد الذي تتواجد فيه الآلة الافتراضية مُجلّدًا فرعيًا وسمه my_awesome_project ثم اكتب الأمر التالي في جلسة الطرفية للآلة الضيف: $ sudo nano /etc/apache2/sites-available/000-default.conf أضف الآتي: DocumentRoot /vagrant/my_awesome_project احفظ التغييرات عن طريق الضغط على Ctrl + X ثم اكتب الأمر التالي: $ sudo nano /etc/apache2/apache2.conf أضف الآتي: <Directory /vagrant> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> احفظه عن طريق الضغط على Ctrl + X ثم اكتب الأمر التالي لإعادة تشغيل الخادوم والعمل بالتغييرات : sudo service apache2 restart مبارك لك الآن يمكنك الدخول إلى المُجلّد الذي يحتوي الآلة الوهمية والدخول إلى المُجلّد المسمى my_awesome_project بداخله وبدأ العمل ومشاهدة التغييرات مباشرة على: http://127.0.0.1:4567 إغلاق الآلة بعد الإنتهاء من العمل سيتوجب عليك إغلاق الآلة الوهمية ويمكن هذا بواحد من ثلاث أوامر داخل دليل الآلة: $ vagrant suspend $ vagrant halt $ vagrant destroy الأمر الأول يقوم بحفظ حالة الآلة كما هي وعند الإقلاع مرة أخرى بالأمرvargant up يكون الإقلاع سريعًا لأنه فقط يقوم بإيقاظ الآلة. الأمر الثاني يعمل على إغلاق الآلة بالكامل وإغلاق كافة البرامج التي كانت تعمل على الآلة وأيضًا يتم الإقلاع مرة أخرى بالأمر vagrant up . الأمر الثالث يمحو الآلة مع كل شيء داخل المجلد الذي يحتويها. الصناديق (Boxes) يستعمل Vagrant الصناديق بدلًا من ترجمة ملفات الآلة الوهمية من الصفر مما يؤدي إلى ضياع الكثير. تعتبر الصناديق كالأنظمة والإعدادات معها المجهزة مسبقًا كي يتم استعمالها مباشرة. يعد الأمر الآتي الذي استعملناه في أول الدرس مثالًا على استخدام أحد الصناديق : $ vagrant init ubuntu/trusty32 والذي من المفترض أن ينشئ آلة وهمية في المجلد الحالي اتخدامًا للصناديق فقد استعمل الصندوق المسمى بـubuntu/trusty32 حالما يتم تنزيل الصندوق يمكنك استعماله في أي مكان وفي أي آلة تنشؤها ويمكنك إضافة أي صندوق جديد عن طريق الأمر التالي: $ vagrant box add box_name وفائدة هذه الصناديق هي استعمال إعدادات وأنظمة جاهزة ومختلفة فمثلًا إذا أردت استعمال CentOS بدلًا من أوبونتو يمكنك استبدال اسم الصندوق بـdanmikita/centos . يمكنك البحث عن الصناديق المتوفرة وأسمائها من خلال الرابط التالي: https://atlas.hashicorp.com/boxes/search التّجهيز (Provisioning) يمكنك التّجهز (Provisioning) من تنفيذ أوامر معينة على الآلة الوهمية بدون الدخول إليها ويمكن ذلك عن طريق التعديل في ملف Vagrantfile وذلك يمكنك من استعمال نفس البرامج والإعدادات على جميع الآلات. لتتمكن من استعمال التزويد عليك إضافة الأمر التالي إلى ملف Vagrantfile لـ: config.vm.provision :shell, path: "bootstrap.sh" هذا الأمر يجعل من ملف bootstrap.sh ملفًا يعمل عند تشغيل الآلة. هناك مجموعة كبيرة أخرى من الأوامر يمكنك الاطلاع عليها من التوثيق الرسمي للبرنامج. يمكنك تفعيل التزويد في الآلة التي تعمل الآن عن طريق الأمر التالي: vagrant reload --provision تغيير Virtualbox يمكنك بكل بساطة استعمال أي برنامج محاكاة مدعوم كـبرنامج VMware على سبيل المثال عن طريق الأمر التالي مع أمر vagrant up: $ vagrant up --provider=vmware_fusion مشاركة الآلة يمكنك مشاركة الآلة خاصتك مع فريق العمل وجعلهم يتمكنون من مراقبتها أو التحكم بها من أي مكان. هناك ثلاثة طرق للمشاركة: مشاركة HTTP ويشارك هذا الآلة عبر منفذ HTTP ويمكن عمل هذا عبر تنفيذ الأمر vagrant share وبعد ذلك وبعد انتهاء الأمر سيظهر في آخره رابطًا يمكنك مشاركته مع فريق عملك. مشاركة SSH يمكن هذا عن طريق كتابة الأمر: vagrant share --ssh سيطلب منك هذا الأمر كتابة كلمة السر التي سيتم التأكد بها من المتصل. بعد الانتهاء من الأمر يمكنك التوصل إلى الآلة من حاسوب آخر عن طريق الأمر: vagrant connect --ssh NAME حيث NAME اسم الآلة الذي ظهر عند نهاية أمر vagrant share --ssh مشاركة عامة وهي تشارك جميع المنافذ الممكنة ويكون ذلك عن طريق الأمرvagrant share ثم كتابة الأمر vagrant connect NAME على الجهاز المتحكم حيث NAME هو اسم الآلة الذي يظهر في نهاية تنفيذ الأمر vagrant share . الخاتمة يمكنك إنشاء أي عدد من الآلات في مُجلّدات مختلفة والعمل عليها جميعًا أو على واحدة منها واستعمال أي صناديق تريد معها وإضافة إعدادات معينة للتزويد ونشرها مع فريق العمل ليتسنى لهم ضبط آلتهم كما هو عندك ومشاركة آلتك عن بعد كي يتحكم جميع فريق العمل في آلة واحدة . المراجع https://docs.vagrantup.com/v2/ http://stackoverflow.com/questions/5891802/how-do-i-change-the-root-directory-of-an-apache-server https://help.ubuntu.com/community/ApacheMySQLPHP
  2. كيف تبدو البرمجة بلغة Go؟ وكيف أقوم بتشغيل برنامج كُتب بـ Go؟ هذا ما سنتعرف عليه خلال هذا الدرس من سلسلة مدخل إلى لغة البرمجة Go، وقبل متابعة الدرس، أحب أن أتأكد أنك تابعت الدرسين السابقين منها أولا. أهلا بالعالمسنحاول اتباع العادة التي جرت عليها دروس تعلم لغات البرمجة، وهي ببساطة كتابة جملة "أهلا بالعالم" (بالانجليزية "Hello World") باللغة المُراد تعلمها، ببساطة هذا ما سيبدو عليه برنامج أهلا بالعالم في Go: package main import "fmt" func main() { fmt.Print("أهلا بالعالم\n") }ضع هذا في ملف باسم helloworld.go داخل مجلد باسم hellogo مثلا، تحت مسار: $GOPATH/src/github.com/YOUR_USER/حيث GOPATH$ هو مسار بيئة عملك، راجع الدرس الثاني لتفهم آلية عمله.غيّر YOUR_USER إلى اسم مستخدمك على github.com مثلا أو أحد خدمات إدارة الشفرة البرمجية.بالتالي سيكون المسار النهائي للملف الجديد الذي أنشأناه هو: $GOPATH/src/github.com/YOUR_USER/hellogo/helloworld.goكل ما عليك فعله الآن هو التنقل إلى مسار الملف وكتابة أمر go run helloworld.go $ go run helloworld.go أهلا بالعالمإذا كانت طرفية سطر الأوامر لديك لا تدعم اللغة العربية، فقد تجد أن الكتابة العربية مقلوبة والحروف متقطعة، لا بأس بذلك حاليا، لكن لاحظ أن Go قبلت بالحروف العربية داخل نص الشفرة البرمجية وتعاملت معها بشكل عادي، ذلك لأن كل شيء تعتبره unicode افتراضا. لنشرح البرنامج سطرًا بسطر: package mainببساطة: لابد لكل ملف شيفرة برمجية في Go أن ينتمي إلى حزمة (package) ما.ولابد لكل حزمة في Go أن تنتمي إلى مجلد ما.لا يمكن لحزمتين التواجد على مستوى نفس المجلد، لكن يمكن لعدة ملفات أن تنتمي إلى نفس الحزمة (يعني مجلد به عدة ملفات)، كما يمكن أن تتواجد حزمة داخل حزمة أخرى لكن كلٌ في مجلد فرعي على حِدى.في مثالنا السابق، أعطينا main كاسم لحزمتنا، وهو اسم خاص، حيث يُعامل مُجمّع (compiler) لغة Go هذه الحزمة على أنها مدخل البرنامج (program entry)، أي أن التعليمات الموجودة في هذه الحزمة يتم تشغيلها أولا. أسبقنا اسم الحزمة بالكملة المفتاحية package. import "fmt"import: كلمة مفتاحية أخرى وتعني "استرِد" أو "اجلِب" المكتبة الفلانية أو الحزمة الفلانية."fmt" اختصار لـ format أو formatting وهي مكتبة قياسية (standard library) تأتي مع تنصيب Go، خاصة ببناء وطباعة النص. لاحظ أن اسم المكتبات أو الحزم المُراد استيرادها دائما ما يتم إحاطتها بعلامة اقتباس "".func main() {هنا قمنا بإنشاء دالة تحمل اسم main: لإنشاء الدالة استعملنا الكملة المفتاحية func ثم مسافة، ثم اسم الدالة.مثل حزمة main فإن دالة main أيضا يعاملها المجمع (Compiler) معاملة خاصة، حيث تعتبر هي نقطة دخول البرنامج (Entry point)، أي أن التعليمات الموجودة في هذه الدالة تحديدا، داخل حزمة main تحديدًا، يتم تشغيلها أولا، إلا في حالة وجود دالة أخرى باسم ()init والتي سنتعرض لها في دروس أخرى.مثل جافاسكريبت وباقي اللغات، فإن } يفتح جسم الدالة (function body).fmt.Print("أهلا بالعالم\n")هنا قمنا باستعمال حزمة "fmt" التي قمنا باستيرادها أعلاه، لاستعمال أي حزمة في Go يكفي كتابة اسمها، ثم نقطة، ثم اسم الدالة التي تريدها استعمالها من تلك الحزمة، في حالتنا هذه، أردنا ببساطة طباعة نص "أهلا بالعالم" والرجوع إلى السطر، لذلك استعملنا دالة Print ومررلنا لها القيمة "n\أهلا بالعالم":مررنا القيمة بين علامتي اقتباس "" ﻷنها عبارة عن سلسلة نصية (string).أنهينا سلسلتنا النصية بعلامة n\ وهي علامة خاصة في أغلب لغات البرمجة، وتعني "سطر جديد"، استعملناها للرجوع إلى السطر.نُمرّر القيم والمعاملات للداوال عبر وضعها بين قوسين مباشرة بجنب اسم الدالة.}أغلقنا جسم الدالة main باستعمال علامة {، أي أن تعليمات هذه الدالة قد انتهت.لاحظ غياب علامة الفاصلة المنقوطة ";" بعد نهاية كل تعليمة، لا حاجة لها في Go.مفهوم الحزم (Packages) في Goالحزم (packages) طريقة بسيطة لتجزئة برنامجك إلى أجزاء أصغر مُقسّمة حسب الغرض أو الوظيفة، يُمكن الاشارة للحزم على أنهم "مكتبات" (libraries) أو وحدات (modules)، تركيب الحزم مع بعضها يشكل مُجمل برنامجك. تتبع Go القواعد التالية في كيفية تقسيم برنامج إلى حزم: الحزمة غالبا عبارة عن مجلد داخل مشروعك به الملفات التي تحمل اسم الحزمة.لابد من وجود حزمة واحدة على الأقل في أي برنامج أو مكتبة.إذا كان البرنامج عبارة عن برنامج تنفيذي (وليس مكتبة - library) فإنه يجب وجود حزمة باسم main (أي package main) تكون هي مدخل البرنامج كما رأيناه في مثالنا الأول.وكتذكير لما ذكرناه سابقا: لابد لكل ملف شفرة برمجية في Go أن ينتمي إلى حزمة (package) ما.ولابد لكل حزمة في Go أن تنتمي إلى مجلد ما.لا يمكن لحزمتين التواجد على مستوى نفس المجلد، لكن يمكن لعدة ملفات أن تنتمي إلى نفس الحزمة (يعني مجلد به عدة ملفات).يمكن أن تتواجد حزمة داخل حزمة أخرى لكن كلٌ في مجلد فرعي على حِدى.يمكن للمجلد الرئيسي لمشروعك أن يحتوي على حزمة ما، واحدة فقط، باقي الحزم الخاصة به يمكنها أن تتواجد في مجلدات فرعية.غياب حزمة main من برنامج ما، يجعل منه مكتبة فقط وليس برنامجا تشغيليا قائما بحد ذاته.عند كتابة الحزم، أي اسم دالة أو متغير أو بُنية (Struct) يبدأ بحرف كبير (Uppercase) يعني أن هذه الدالة/المتغير/البنية متوفر بشكل عام لجميع من يقوم باستيراد هذه الحزمة عبر الكلمة المفتاحية import. وأي اسم دالة/متغير يبدأ بحالة أحرف صغيرة (Lowercase) يعني أنه خاص ولن يتم تصديره (لن يكون متاحا) لباقي الحزم والبرامج. في مثالنا السابق، وفّرت حزمة "fmt" دالة Print لنا بشكل مُتاح، لاحظ أن Print تبدأ بحرف P كبير (Uppercase). وكان فقط يكفي كتابة (...)fmt.Print مكتبة (حزمة) أهلا بالعالمماذا لو أردنا قول "أهلا بالعالم" في أكثر من مشروع؟ ربما سيكون من الأمثل جعل طباعة "أهلا بالعالم" في مكتبة مستقلة نقوم باستيرادها في مشاريع أخرى، هذا مثال فقط لكيفية بناء مكتبة في Go، فطبعا لن تحتاج إلى مكتبة كل ما تقوم به هو "أهلا بالعالم". دعنا نحاول كتابة هذا في دالة بسيطة، نسميها SayHello ولنضها في حزمة خاصة، نسميها sayhello. دعنا نبني هذه المكتبة في مشروع مستقل، لتكون مكتبة يُمكن جلبها في أكثر من برنامج أو مشروع آخر. سنسمي المشروع sayhello، أي بنفس اسم الحزمة لتسهيل الأمر. لن نحتاج إلى package main ﻷننا سنبني مكتبة فقط وليس برنامجا تنفيذيا في حد ذاته. بالتالي قم بإنشاء مجلد مشروع جديد تحت مسار: $GOPATH/src/github.com/YOUR_USER/بنفس الطريقة التي شرحناها سابقا. أنشئ ملفا باسم sayhello.go تحت مجلد sayhello، ليكون مسار الملف أشبه بهذا: $GOPATH/src/github.com/YOUR_USER/sayhelo/sayhello.goوالآن، نفتح ملف sayhello.go بمحرر النصوص المفضل لديك ثم نشرع في كتابة دالتنا المذهلة، لا يُفترض بك فهم كل شيء حاليا، فالغرض شرح مفهوم الحزم والمكتبات، مع ذلك سنحاول شرح تعليمات هذه الدالة: package sayhello // SayHello returns Hello World in Arabic. func SayHello() string { return "أهلا بالعالم\n" } لاحظ أن دالتنا لا تختلف كثيرًا عن برنامج "أهلا بالعالم" الذي كتبناه أول مرة: استعملنا package sayhello عوض package main.سمينا الدالة ()func SayHello عوض ()func main. لاحظ أننا جعلنا اسم الدالة يبدأ بحرف كبير (Uppercase) ذلك ﻷننا نريد تصدير هذه الدالة وإتاحتها لباقي المشاريع التي تسترد حزمة sayhello.قمنا بتصريح أن الدالة تُرجع سلسلة نصية عبر كتابة الكلمة المفتاحية string على يمين الدالة.قمنا بإرجاع السلسلة النصية "n\أهلا بالعالم" عبر الكلمة المفتاحية return عوض طباعتها باستخدام مكتبة fmt كما فعلنا أول مرة.أصبح الآن لدينا "أهلا بالعالم" في شكل مكتبة! لكن كيف نجعلها قابلة للجلب؟ أي كيف نضعها في مجلد pkg حتى تستطيع باقي المشاريع جلبها والاستفادة منها؟ كل ما علينا فعله هو كتابة go install داخل مجلد مشروع sayhello. طبعا لن يكون بإمكانك تشغيل هذه المكتبة عبر أمر go run sayhello.go مثل ما فعلنا أو مرّة، ﻷن ما قمنا بكتابته هذه المرة عبارة عن مكتبة وليس برنامجًا تنفيذيًا! فحص مكتبة "أهلا بالعالم"هل تعمل دالتنا بشكل جيد؟ كيف يمكن التحقق من برامجنا وحزمنا التي نكتبها في Go؟ هل مكتبة "أهلا بالعالم" تطبع حقا "أهلا بالعالم"؟ دعنا نتأكد من ذلك عبر كتابة فحص مؤتمت لهذه الدالة! في لغة Go: يمكن كتابة فحوصات واختبار وحدات (Unit testing) بسهولة، يكفي إنشاء ملف بنفس اسم الملف المُراد اختباره مع إضافة test_ له.يمكن فحص دالة معينة بمجرد كتابة Test ثم اسم الدالة.في حالتنا هذه، وفي نفس مسار مشروع sayhello أنشئ ملفا باسم sayhello_test.go بجانب ملف sayhello.go نفسه لنقوم باختبار حزمة sayhello. افتح ملف sayhello_test.go بمحرر النصوص المفضل لديك. كل ما علينا فعله لتجربة دالتنا هو جلبها وفحص إذا كانت نتيجة الطباعة هي فعلا "أهلا بالعالم"! كما هو موضح في الشفرة التالية: package sayhello import "testing" func TestSayHello(t *testing.T) { greeting := SayHello() if greeting != "أهلا بالعالم\n" { t.Error("TEST FAILED!") } } في الشِيفرة أعلاه: قمنا باستيراد حزمة "testing" القياسية التي توفرها لغة Go بشكل افتراضي لأغراض إنشاء الفحوصات المؤتمتة.بما أننا نريد فحص دالة SayHello قمنا بإنشاء دالة TestSayHello مع تمرير testing.T لها، أي أن هذه الدالة تُعتبر "حالة فحص"، لا يجب عليك فهم هذا التعبير حاليا، يمكنك تجاهله، الغرض هو فهم آلية عمل الفحوصات المؤتمتة في Go.داخل هذه الدالة الفاحصة، قمنا ببساطة بنداء دالتنا SayHello وفحص إذا كانت القيمة التي تُرجعها عبارة عن "n\أهلا بالعالم" فإن كانت كذلك، يمر الفحص بسلام ولن نطبع أي شيء، وإن لم تكن كذلك، نطبع "!TEST FAILED" باستخدام المعامل t التابع لحزمة testing القياسية باستعمال الدالة Error، والتي تُخبر بدورها أن حالة الفحص هذه قد فشلت. الآن، في نفس المجلد الذي أنت به يكفي كتابة go test لفحص حزمة sayhello الخاص بنا! يُفترض أن تتلقى نتيجة مشابهة لهذه: PASS ok github.com/01walid/sayhello 0.001sيمكن إضافة v- أو cover-- إلى الأمر السابق لطباعة المزيد من المعلومات حول الفحوصات التي يقوم بها المُجمع، مثلا go test -v --cover === RUN TestSayHello --- PASS: TestSayHello (0.00s) PASS coverage: 100.0% of statements ok github.com/01walid/sayhello 0.001s لاحظ أننا تحصلنا على coverage: 100.0%! أي أن الفحوص التي قمنا بها تغطي جميع الدوال التي قمنا بكتابتها في هذا المشروع (بما أن لدينا دالة واحدة فقط وفحص واحد، فالنتيجة طبيعية)، من المستحسن دائما إبقاء نسبة تغطية الفحوصات مرتفعة في برامجك، حتى تضمن أن استقرارها جيد ويمكن التعويل عليها. إنشاء توثيق لمكتبة "أهلا بالعالم"أنهينا مكتبتنا المذهلة، تأكدنا من صحة عملها، ماذا لو أمكننا توليد ومشاركة توثيق لها؟ لن تحتاج الكثير لفعل ذلك! كل ما عليك فعله هو كتابة الأمر godoc -http=:6060 ثم زيارة localhost:6060 على متصفحك! ستحتاج إلى التنقل إلى توثيق مكتبتك بشكل خاص عبر زيادة http://localhost:6060/pkg/github.com/YOUR_USER/sayhello/طبعا قم بتغيير YOUR_USER إلى اسم المستخدم الخاص بك، تماما مثل مسار المكتبة في بيئة GOPATH$ الخاص بك. استعمال مكتبة "أهلا بالعالم"دعنا نستعمل هذه المكتبة في برنامجنا الأول، سنحتاج إلى تغييرات بسيطة لجعله يستغل مكتبة "أهلا بالعالم" كما هو موضح (تذكر: مشروعنا الأول في مجلد لوحده باسم sayhello): package main import "fmt" import "github.com/01walid/sayhello" func main() { fmt.Print(sayhello.SayHello()) } قمنا فقط بجلب مكتبتنا الجديدة عبر كتابة: import "github.com/YOUR_USER/sayhello"ثم استعمالها عبر مناداة دالة SayHello منها داخل fmt.Print عوض كتابة "أهلا بالعالم" مباشرة: fmt.Print(sayhello.SayHello())الآن شغّل البرنامج مجددا عبر كتابة go run helloworld.go، هذا كل ما في الأمر! تهانينا لك أول برنامج وأول مكتبة لك باستخدام لغة البرمجة Go! إضافة (Bonus)في إضافة هذا الدرس، اخترت أن أشير إلى بعض إضافات محررات النصوص البرمجية الشهيرة، والتي من شأنها أن تسهل عليك البرمجة بـ Go بشكل معتبر. ستجد من هنا قائمة بهذه الإضافات، مثلا إن كنت من مستعملي SublimeText فقم بتنصيب إضافة GoSublime وإن كنت من مستعملي محرر Atom فقط بتنصيب Go-plus. خاتمةتعرفنا في هذا الدرس على كيفية كتابة برنامج باستخدام لغة Go، ثم جعل البرنامج على شكل مكتبة عوض تركه في شكله التنفيذي. من المهم جعل برامجك عبارة عن مجموعة مكتبات منفصلة حسب الغرض، عوض جعل كل شيء متداخل في حزمة واحد أو في برنامج تنفيذي. فكما رأينا إنشاء برنامج تنفيذي أسهل ما يكون، إذ يكفي كتابة ملف به package main ثم func main واستدعاء باقي الحزم، بالتالي الأهم من ذلك هو التفكير التجريدي وفصل المهام عن بعضها في مكتبات وحزم حسب الغرض، كلٌ يقوم بمهمة/غرض ما، ويقوم به بشكل جيد ومُختبر (unit tests). في درسنا هذا، كانت المكتبة منفصلة تماما عن البرنامج التنفيذي. مشاريعك القادمة ستكون على الأغلب مقسمة إلى حزم/مكتبات داخل مجلد المشروع نفسه وليس بالضرورة في مجلد/مشروع آخر، لكن المفهوم هو نفسه. رأينا أيضا، أن التعليقات في Go وسيلة ممتازة لتوليد التوثيق بأدنى جهد، لذلك يجدر بك كمبرمج عدم إهمالها والاهتمام بها وبتفاصيلها. كل هذا كان سهلا! لعلك كنت تسمع بهذه الأمور فتفزع (tests, docs, cover.. الخ) لكني قدمت هذه المفاهيم عمدا في الدروس الأولى لترى أن لا شيء يستحق الهروب منه. وأن البرامج ذات الجودة العالية مجرد اتباع لسلوكيات مهذبة وممارسات محبذة بخطوات ثابتة ينبغي أن تُعوّد نفسك عليها من الآن وتجعل منها أسلوب تطوير/برمجة. في الدروس القادمة سنتطرق إلى أنواع المتغيرات، هيكلة البيانات، كيفية إنشاء متغير، الحلقات والجمل الشرطية.
  3. ما هو نظام التحكّم في النسخ Git، ولماذا حرّي بك أن توليه اهتماما؟ إن التحكّم في النّسخ، هو نظام يسجل التغيرات التي تحدث عبر الزمن على ملف أو مجموعة ملفات بحيث يمكنك الرجوع إلى مرحلة معينة (إصدار) لاحقًا. عمليا، يمكنك أن تقوم بهذا على جُل أنواع ملفات الحاسوب. إذا كنت تعمل كمصمم رسوميات أو ويب، مبرمج أو ما شابه وتريد طريقة لمتابعة جميع الإصدارات والتعديلات التي تجريها على صورة أو قالب ما (الأمر الذي سيعجبك بالتأكيد)، فإنه من الحكمة استعمال نظام إدارة الإصدارات VCS. حيث يمكّنك من إرجاع الملفات إلى حالٍ كانت عليه سابقًا، أو إرجاع مشروع بأكمله، يمكنك أيضًا مقارنة التغيرات الحاصلة مع مرور الزمن، أو معرفة من قام بآخر تعديل قد يكون سبب خطأ ما، من أشَارَ إلى خطْبٍ ما ومتى، وغيرهم المزيد. استخدامك لنظام إدارة الإصدارات يعني أيضًا أنه إذا قمت بعبث وتبعثرت أشياء، أو خسرت ملفات المشروع لسبب ما، يمكنك استرجاعها إلى حالها بسهولة. بل وبأدنى مشقة منك. أنظمة إدارة إصدارات المصدر المحلية الطريقة المثلى لدى كثير من الناس في التحكّم النسخ، هي نَسخ الملفات في مجلد مغاير (قد يكون مُعّلما بالزمن، في حالة كان الشخص حذِقا). هذا النهج منتشر بكثرة لبساطته، لكنه وبشكل مفرط، مَدعاة للغلط. فمن السهل نسيان أيٌ من المجلدات أنت فيها فتكتب عن غير قصد في الملف الخطأ، أو تنسخ فوق ملفات لم تكن تعنيها. للتعامل مع هذا المشكل، عمل المبرمجون قديما على تطوير VCSs مزودة بقاعدة بيانات بسيطة تحفظ جميع التغيرات التي تطرأ على الملفات التي هي تحت إدارة المراجعة (انظر الصورة). إحدى أدوات VCS الأكثر شعبية كان نظاما تدعى rcs والتي لا تزال تُوّزع مع العديد من حواسيب اليوم. حتى نظام OS X المشهور يحوي أمر rcs عند تنصيبك لأدوات المطور، تعمل هذه الأداة أساسا بحفظ مجموع الرقع (أي الاختلافات الحاصلة بين الملفات) بين كل عملية تغيير واحدة ومثيلتها في هيئة خاصة على القرص الصلب، يمكنها بهذا إعادة إنشاء أي ملف بنفس الهيئة التي كان عليها في نقطة ما من الزمن عن طريق دمج الرقع. أنظمة إدارة إصدارات المصدر المركزية المشكل الكبير التالي الذي واجه المستخدمين هو حاجتهم إلى التعاون مع مُبرمجين آخرين على أنظمة تشغيل أخرى. ولحل هذا المُشكل تم تطوير أنظمة لإدارة إصدارات المصدر مركزية (CVCSs). تستخدم هذه الأنظمة، مثل كل من CVS ،Subversion أو Perforce خادوما واحدا يحتوي كل الملفات التي نقوم بإدارة إصداراتها، إضافة إلى مجموعة من العملاء الذين يقومون باسترجاع الملفات من هذا الخادوم المركزي. ظلت هذه الأنظمة لسنوات عديدة المعيار القياسي لأنظمة إدارة إصدارات المصدر. توفر هذه الأنظمة مزايا عديدة خاصة إذا ما قارناها بأنظمة إدارة الإصدارات المحلية، فعلى سبيل المثال يُمكن للجميع –إلى حد مُعين من الدقة- معرفة ما الذي يقوم به الجميع على المشروع، كما أن للمدراء القدرة على التحكم بشكل دقيق فيما يُمكن لأي مشارك أن يقوم به. دون أن ننسى أنه من الأسهل التعامل مع نظام إدارة إصدارات مركزي مقارنة مع إدارة قواعد بيانات على جهاز كل مشارك. في المقابل، تأتي هذه الأنظمة مرفقة ببعض العيوب والتي قد يكون أخطرها هو اعتماد النظام على نقطة مركزية وحيدة، فإن تعطل الخادوم لساعة من الزمن، فإنه من غير المُمكن لأي كان أن يتشارك التحديثات التي تمت خلال تلك الفترة. أما لو تعرض القرص الصلب على الخادوم لعطب، فإنه -ما لم يتم أخذ نسخ احتياط قبل حصول ذلك- فإن احتمال فقدان المشروع بكامل تاريخه أمر وارد جدا، باستثناء النسخ المحلية المتواجدة على أجهزة المتعاونين في المشروع. أنظمة إدارة الإصدارات الموزعة ولمثل هذه الأوضاع ظهرت أنظمة إدارة الإصدارات المُوزعة (DVCSs). في مثل هذه الأنظمة كـ Git ،Mercurial ،Bazaar أو Darcs فإن ما يقوم به المستخدمون ليس مُجرد التحقق من آخر إصدار للملفات، لكن يقومون بإخذ نسخ كاملة عن المستودعات التي يعملون عليها. وعليه، فإن تعرض الخادوم لأي خلل فإنه يُمكن مواصلة العمل عبر نسخ المستودع الموجود على أي من أجهزة المستخدمين بحكم أن أي عملية تحقق يقوم بها المستخدم هي عبارة عن عملية نسخ احتياطي كامل لكامل بيانات المشروع (انظر الصورة التالية). وعلاوة على ذلك، فإن العديد من هذه الأنظمة المُوزعة تتعامل بشكل جيد مع المشاريع التي تملك عدة مستودعات تعمل عليها مجموعات مختلفة من المستخدمين بطرق مختلفة وضمن نفس المشروع. هذا الأمر يسمح باعتماد مهام لسير العمل لم يكن بالإمكان اعتمادها على الأنظمة المركزية مثل النماذج الهرمية. ترجمة -وبتصرف- لـ About Version Control من كتاب Pro Git لصاحبه Scott Chacon.
  4. ما هو Git، ولماذا كل هذا الاهتمام المتزايد به؟ هل أحتاج فعلا إلى استعماله؟ هل سأصبح مُبرمجا من الدرجة الثانية لو لم تكن لدي أدنى فكرة حول ماهية Git؟ كيف لي أن أستعمله لأزيد مردوديتي البرمجية؟ هل سأصبح [ضع أي وصف هنا] لو استعملت Git؟ هذا المقال سيحاول الإجابة على بعض هذه الأسئلة، يُشوقك للبحث عن إجابات لأخرى، أو يدفعك لقراءة المقال إلى آخره لترى إن كانت هناك أية إجابة على السؤال الأخير. فلنبدأ ببساطة وبكلام يفهمه الجميع، … ما هو Git؟ هل هو لغة برمجة؟ – لاهل هو قاعدة بيانات؟ – لاهل هو نظام تشغيل؟ – لا(جميع هذه الأسئلة وردتني شخصيا) إذا ماهو Git؟ وما وظيفته بالتحديد؟ لفهم ماهيته، علينا أولا فهم المشكلة التي أدّت إلى وجوده، فخذ هذا كمثال بسيط، وأسقطه على نفسك لتفهم المشكلة. المشكلةأنت مبرمج أو مطور ويب، تعمل على مشروع ما، سهرت الليالي فرحًا، لقد حققت تقدما وإنجازا في مشروعك، مرّت بضعة أيام أو بضعة أسابيع، فإذ بك تجد نفسك في مشكلة، كتبت شفرة برمجية عاثت في مشروعك فسادًا، وليتك تستطيع الرجوع للوراء، أو وصلت إلى مرحلة أين يشتغل فيها المشروع بشكل جيد، لكنك تخاف أن تُفسد الخطوة التالية عليه، ﻷنك لست متأكدا أن الميزة القادمة التي ستبرمجها في المشروع ستتكامل معه ولن تقلبه رأسا على عقب، حسنا، أنت شخص ذكي (ربما أنت بلال؟)، لن تقع في فخ كهذا! تبدأ بإنشاء مجلد يحوي المشروع في حالته الحالية، وإن كنت حَذِقا زيادة، ستعطي المجلد اسما بتاريخ اليوم وتوقيته، وتعمل على نسخة أخرى منه في مجلد آخر، وهكذا تفعل في كل مرة يتكرر المشكل، وبهذا يسهل عليك الرجوع إلى حالة المشروع السابقة في حال سارت الأمور علي عكس ما كنت تُخطط له مستقبلا. مرّ مزيد من الوقت، كَبُر المشروع، أصبحتَ مرّة تتكاسل عن إنشاء مجلد جديد ﻷنه ليس لديك وقت لهذا، ومرّة تريد الرجوع إلى حالة سابقة للمشروع لاسترجاع جزء من الشفرة البرمجية في الملف الفلاني كانت تعمل بشكل أفضل، دقيقة، متى كان هذا؟ أين وضعت ذاك المجلد؟ ما كل هذه المجلدات الكثيرة! أيّها هي المجلد الذي أحتاجه؟ حسنا لقد وجدته، أين كانت تلك الشفرة البرمجية حينذاك وفي أي ملف؟! ضاعت الدقائق والساعات، وضاع الجهد والسّهر. مرّ مزيد من الوقت، لقد كبُر المشروع أكثر، بل وزادت أهميته ومسؤوليته، انضم إلى مشروعك أشخاص آخرون، أصدقاؤك المبرمجون يتعاونون معك لتطويره، أو زملاؤك في العمل يتشاركون فيه، أنتم فريق رائع وذكي، لقد وجدتم طريقة لتشارك الشفرة البرمجية، تتراسلونها عبر البريد، أو ترفعونها على خادوم شركتكم البعيد، أو تضعونها على خادومكم الخاص بكل تأكيد، أو ربما ترفعونها على إحدى خدمات التخزين مثل Dropbox. مهلا، فُلان أضاف شيئا في المشروع، في نفس الوقت أضفت أنت أيضا شيئا فيه، كيف أدمج نسخته مع النسخة التي لدي؟! مشكلة، لقد كتبنا شفرة في نفس الموضع، لتقوم بنفس العمل، فأي الشفرتين أفضل؟ قد تحرّيت الوضع وتبين أن لكلا الشفرتين مزايا وعيوب، فكيف أدمج مزايا الشفرتين في واحدة؟ في نفس الوقت أرسل زيد وسعيد شفرتيهما، أنت مدير المشروع وعلى مسؤوليتك دمج التغيرات التي يُرسلها الفريق، لقد أرفق زيد رسالة وقال يمكنك أن تبدل الملف الفلاني بالملف الذي أرسلته ولا تخف، وقال أنه أفضل من الملف الذي أرسله سعيد، صدّقت زيدًا وتخطيت سعيدا، وتسرعت في استبدال الملف وأنت سعيد، وإذا بالملف يُفسد عليك كامل المشروع، ولا تملك نسخة منه بالحالة التي كان عليها لا من قريب ولا من بعيد،… زيدٌ ذاك له منّي أشد وعيد! وضاعت دقائق وساعات أخرى. الحللست وحدك في هذا المشكل، فلقد عانى منه المبرمجون قديما، وعملوا على حلّه بتطوير أدوات تتولى أو تسهّل عليهم حفظ التغيرات التي يجرونها عبر الزمن على ملفات الشفرة البرمجية، وتسجيلها (أي التغيّرات) في قاعدة بيانات تحفظ الفروقات بين نُسَخ الشفرة البرمجية عبر الزمن، بحيث يمكن الرجوع إلى نسخة معينة، في مرحلة معينة من الشفرة البرمجية، تماما كما كانت عليه وقت حفظها. ليس هذا وحسب، حيث يمكن للأداة أن تدمج التغيرات التي أجراها أكثر من شخص بعضها ببعض، وتُعلمك بوجود تضاربات بين شفرة فلان وعلان في الملف الفلاني من سطر كذا إلى سطر كذا. بل وتطورت هذه الأدوات أكثر، وأصبحت تتولى مهمة رفع التغيرات التي أجريتها إلى خادوم بعيد (عبر إنشاء ما يُعرف بالمستودع أو Repository على الخادوم)، أو جلب التغيرات التي أجراها الآخرون من خادوم بعيد (من المستودع)، بل وحتى أكثر من خادوم في نفس الوقت، ثم مساعدتك في عرض الفروقات Diffs بين النُّسخ، ودمج أحدث التغيرات في نسخة واحدة. سمّوا هذه الأدوات بعدة مسمّيات تصب كلّها في نفس المعنى، من ذلك: نظام التحكم في النسخ، بالانجليزية: Version Control System أو اختصارًا: VCS، وهذا المُسمّى أشهرهم.نظام التحكم بالمصدر، بالانجليزية: Source Control.نظام التحكم بالمراجعات، بالانجليزية: Revision Control.إدارة الشفرة المصدرية، بالانجليزية: Source Code Management وتختصر إلى: SCM.كلها مسمّيات يُقصد بها الأداة التي تقوم بتسجيل التغيرات التي تحدث عبر الزمن على ملف أو مجموعة ملفات بحيث يمكن الرجوع إلى مرحلة معينة (نسخة، أو إصدار) لاحقًا. ماهي التغيرات التي حصلت، ما هي التعارضات الموجودة بين نسختين لنفس الملف، من قام بكتابة الشفرة الفلانية، ومن سبب مشكلا ما، ومن عمل على حل المشكل الفلاني. وغير ذلك المزيد. من بين تلك الأدوات، نعرض أشهرها عبر الزمن، وهي: rcs وقد كانت من بين أشهر الأدوات. حتى نظام OS X المشهور يحتوي على أمر rcs عند تنصيبك لأدوات المطور، تعمل هذه الأداة أساسا على حفظ مجموع الرُّقع (أي الاختلافات الحاصلة بين الملفات) بين كل عملية تغيير ومثيلتها في هيئة خاصة على القرص الصلب، يمكنها بهذا إعادة إنشاء أي ملف بنفس الهيئة التي كان عليها في نقطة ما من الزمن عن طريق دمج الرقع، لكنها أداة بدائية في حال كان يعمل على المشروع أكثر من شخص.أنظمة التحكم بالنُّسخ المركزية، أو Centralized Version Control Systems وتعرف اختصارا بـ CVCSs، جاءت لتحل المشكل الكبير التالي الذي واجه المستخدمين، وهو حاجتهم إلى التعاون مع مُبرمجين آخرين على أنظمة تشغيل أخرى. تستخدم هذه الأنظمة، مثل كل من CVS، Subversion أو Perforce خادوما واحدا يحتوي كل الملفات التي نقوم بالتحكّم في نُسَخها، إضافة إلى مجموعة من العملاء الذين يقومون باسترجاع الملفات من هذا الخادوم المركزي. ظلت هذه الأنظمة لسنوات عديدة المعيار القياسي لأنظمة التحكم في النّسخ VCS.أنظمة التحكم في النّسخ المُوزعة أو Distributed Version Control Systems و تعرف اختصارًا بـ DVCSs. في مثل هذه الأنظمة كـ Git، Mercurial، Bazaar أو Darcs فإن ما يقوم به المستخدمون ليس مُجرد التحقق من آخر نسخة من الملفات، لكن يقومون أيضا بأخذ نُسَخٍ كاملة عن المستودعات التي يعملون عليها. وعليه، فإن، وفي حال ما إذا تعرّض الخادوم لأي خلل، فإنه يُمكن مواصلة العمل عبر نَسْخ المستودع الموجود على أي من أجهزة المستخدمين بحكم أن أي عملية التحقق التي يقوم بها المستخدم هي عبارة عن عملية نسخ احتياطي لكامل بيانات المشروع.كل هذه تدخل تحت مسمّى VCS. أما Git، فيعتبر نقلة نوعية في عالم VCS بشكل عام، ﻷنه جاء بإدارة التفرعات (branches) المتوازية وإعادة دمجها مع بعض، وهو الأمر الذي كان يُعدّ كابوسا في الأدوات القديمة مثل CVS. وللأمانة، فإن Git ليس أول نظام جاء بهذه الفكرة، بل سبقه إليها bitkeeper لكنه لم يكن برنامجا مجانيا ولا حرّا، وبالتالي فإن Git أوّل نظام حر ومجاني يأتي بإدارة التفرعات المتوازية (mercurial أيضا جاء بها وهو حر مجاني، وقد تم تطويرهما أصلا ليكونا بديلا لـbitkeeper). إذا، إجابة على السؤال الأول، ماهو Git؟ باختصار هو: نظام التحكم في النسخ الموزّع غير المركزي، وهي جملة يُفترض أنه يمكنك فهمها الآن. أسئلة شائعة:هل تعلّم Git صعب؟ وهل يحتاج أن يكون لدي خلفية برمجية؟لا، ليس صعبا، وليس غاية في حد ذاته، فهو فقط أداةٌ وسيلة، تعلمّها يأتي بالتمرّس، فقط بضعة أوامر ستتعود عليها وتصبح بداهة مع مرور الزمن، ولن تحتاج إلى أي خلفية برمجية. عليك البدء في إدخاله في سير عملك، واعلم أنك ستربح الوقت به ولن تضيعه. قلت أوامر؟؟ أنا أخاف من الطرفية، هل له واجهات رسومية؟!نعم، له عدة واجهات رسومية على مختلف أنظمة التشغيل، لكنه من غير المحبذ للمبتدئ أن يبدأ بها، بل من المستحسن أن يصبر مع الطرفية ليفهم آلية عمله جيدا، ثم له أن ينتقل لما يصل لمرحلة متقدمة، ولو أن حتى المتقدمين لا يزالون يفضلون الطرفية. هل يعمل على Linux فقط؟ هل له نسخة Windows؟يعمل على جميع الأنظمة المعروفة، سواء Linux ،Mac أو Windows بل حتى على أنظمة أخرى، ويعمل بنفس الكيفية وبنفس الأوامر، الشي الوحيد الذي يختلف نوعا ما هو طريقة التنصيب. هل يمكن التحكم بنُسخ الملفات غير البرمجية؟ كأنواع الملفات الأخرى؟نعم، يمكن الإستفادة من Git في التحكم بنُسخ الملفات على اختلاف أنواعها، فإن كنت مثلا مصمما، أو كاتبا، أو مهندسا معماريا أو ما شابه، فإنه يمكن إدارة نسخ الملفات التي تعمل عليها بنفس الطريقة. لكن الملفات التنفيذية أو غير النصية يصعب معرفة ما تغير فيها عبر الزمن وعرض الفروقات فيها أو بينها، نظرًا لطبيعتها (binary). هل يجب وجود خادوم بعيد للعمل بـ Git؟لا، بتاتا، يمكن إنشاء المستودعات على حاسوبك، وإبقائه عندك ولن تحتاج ﻷي خادوم بعيد. كيف يُنطق Git؟ينطق چيت، بنفس الجيم التي ينطقون بها في مصر. متصفحك لا يدعم تشغيل ملفات الصوت.من طور Git؟نفسه من بدأ بتطوير نواة Linux، وهو Linus Torvalds. ما معنى كلمة Git؟تعني شخصا غبيا أو لنقل أحمقا، وهي كلمة عامية بريطانية، وهو ما قد يشعر به المرء لما يكتشف أنه ضيع سنوات دون استعماله. آمل أن أكون قد وُفقت في شرح ماهية Git بشكل خاص و VCS بشكل عام. إذا كان لديكم أية أسئلة إضافية أو اقتراحات، فاطرحوها بالتعليقات وسيتم تحديث الموضوع.
  5. سيتم بالفعل نقل مقالاته هنا وتوفير المزيد من الدروس حول Git على الأكاديمية
  6. بعد تعرُّفنا في الدرس السابق على لغة Go ونقاط اختلافها مع باقي لغات البرمجة، سنحاول في هذا الدرس شرح كيفية تنصيبها، تهيئة وفهم بيئة العمل (Workspace) الخاصة بها. من المهم جدا فهم تقسيم المجلدات الذي تمليه عليك بيئة عمل Go، حيث سيمكّنك ذلك من ترتيب مشروعك بشكل أفضل، تسهيل مشاركته، وجعله قابلا للجلب والتضمين في مشاريع أخرى عبر أمر go get الذي سنتعرّف عليه لاحقا. تملك Go نوعين من المُجمّعات (Compilers). وكتذكير سريع، وظيفة المُجمّع هي أخذ شيفرتك البرمجية في شكلها النصّي البحت، وتحويلها إلى برنامج تنفيذي (أو مكتبة). أحد مجمّعَيْ Go هو المجمع القياسي الذي يحمل اسم gc اختصارًا لـ Go Compiler، والآخر مُجمّع يعتمد على مجمّع gcc وما يوفره كمنصة ودعم معماريات معالجات (CPU) أكثر ويحمل اسم gccgo. يجدر الإشارة إلى أن مجمع gccgo متأخر نوعا ما في زرع كامل مواصفات النسخة الأحدث من Go، فعلى سبيل المثال، ولدى كتابة هذا الدرس، يوفر gccgo نسخة 1.4.1 من Go في حين يوفر gc دائما آخر نسخة (1.5.2) من اللغة. ذكرت هذا من باب العلم بالشيء، وباختصار، إن لم يهمك دعم معماريات أكثر أو بعض تفاصيل منصة gcc فلن تحتاج إلى gccgo وستكتفي بـ gc القياسي وهو ما سنتبعه خلال هذه السلسلة. تنصيب Goكما ذكرنا في الدرس السابق، فإن Go لغة متعددة المنصّات بامتياز، وهي جاهزة للتحميل والتنصيب على نظامك المفضل لكلا معماريتي 32bit و 64bit. تنصيب Go على Windows و Mac OSيكفي التوجه إلى موقع اللغة ثم تحميل النسخة الخاصة بنظامك. عملية تنصيبها عادية وهي مشابهة لعملية تنصيب أي برنامج عادي آخر. بعد التنصيب، تأكد من أن العملية تمت بنجاح عبر كتابة go version أو فقط go في سطر الأوامر. إن كنت على Windows تأكد من غلق أي نافذة سطر أوامر مفتوحة مسبقا (إن وُجدت) ثم فتح نافذة جديدة. تنصيب Go على Linuxأنصحك بالاطلاع على مدير حزم توزيعتك قبل تحميل وتنصيب Go من أي مكان آخر. فإن وجدت أن مدير حزم توزيعتك يوفر آخر نسخة من Go فسيكون الأمر أسهل بكثير، إن وجدت أن توزيعتك توفر نسخة أقدم من Go 1.5.1 فعليك تنصيب آخر نسخة منها إن كنت تريد متابعة هذه السلسلة. إن كنت على Ubuntu والتوزيعات المبنية عليها، فأغلب الظن أن نسخة Go التي يوفرها مدير الحزم apt قديمة، كون التوزيعة يتم تحديثها كل 6 أشهر أو عامين (في حال كانت LTS). لذلك أنصحك بالتنصيب من خلال إضافة مستودع etherneum. sudo add-apt-repository -y ppa:ethereum/ethereum sudo apt-get update sudo apt-get install golangيُفترض بباقي التوزيعات أن تحتوي على آخر نسخة من Go، يكفي حينئذ التنصيب من مدير الحزم، مثلا على Arch Linux: sudo pacman -S goبعد التنصيب، تأكد من أن عملية التنصيب تمت بنجاح عبر كتابة go version أو فقط go في سطر الأوامر. من المفروض تتلقى نتيجة مشابهة لهذه: go version go1.5.2 linux/amd64فهم بيئة العملنقصد ببيئة العمل هنا أمران أساسيان: مجلد على حاسوبك، تقوم بإنشائه في أي مكان تريد، سيكون مكانا لجميع مشاريع Go.متغير بيئة (environment variable) يحمل اسم GOPATH يشير إلى هذ المجلد.لنفرض أنك سمّيت مجلد العمل باسم work، فإن هذا الأخير بدوره يجدر به أن يحوي ثلاث مجلدات فرعية أخرى: مجلد فرعي باسم src، حيث ستضع فيه جميع الشيفرات البرمجية لكامل مشاريع Go خاصتك.مجلد فرعي باسم bin، حيث سيقوم مجمع gc بنقل الملفات التنفيذية الناتجة عن شيفراتك البرمجية مباشرة إلى هذا المجلد.مجلد فرعي باسم pkg، مثل bin لكن ليس للملفات التنفيذية، إن كتبت برنامجا عبارة عن مكتبة وليس برنامجا تنفيذيا في حد ذاته، أو جلبت مكتبة خارجية عبر أمر go get، فسيتم تجميعها كمكتبة يتم وضعها في هذا المجلد حتى يسهل جلبها في باقي البرامج دون إعادة تجميعها في كل مرة (هذا يُسرّع من عملية تجميع برنامجك التنفيذي الذي يستخدم هذه المكتبات).باعتبار ما سبق، فإن بيئة Go ستكون مشابهة لهذا التقسيم الشجري: work # مجلد العمل ├── bin # مجلد الملفات التنفيذية الناتجة ├── pkg # مجلد المكتبات البرمجية الناتجة └── src # مجلد شيفراتنا البرمجية هل هذا كل شيء؟ طبعا لا. بما أن Go لغة حديثة نسبيا، فإنها تفترض أنك ستستضيف شيفرتك البرمجية في مكان (مستودع) ما، وهذه عادة أي مبرمج محترف، خشية على الشيفرة البرمجية من الضياع أو من أجل مشاركتها مع أناس آخرين. طبعا مستودع شيفرتك البرمجية سيكون مُدارا بأحد أدوات إدارة النُسخ (VCS) مثل Git أو Mercurial مثلا. قد تكون الشيفرة على خادومك الخاص (Server)، أو على أحد خدمات استضافة المشاريع البرمجية مثل Github و Bitbucket. بما أن Github أشهر المنصات لمشاركة الشيفرات البرمجية، فسأضرب به المثال. تدفعك Go (أي أنه من المستحسن) إلى وضع شيفرتك البرمجية في مسار مشابه لمسار حسابك على github مثلا -وحتى أقرّب الصورة- لنفرض أن حسابك على github اسمه HsoubAcademy وبالتالي رابط حسابك هو: https://github.com/HsoubAcademyإذا أنشأت مشروعا بـ Go يحمل اسم example على سبيل المثال ثم رفعته على Github باستخدام حسابك HsoubAcademy فسيكون رابط المشروع هو: https://github.com/HsoubAcademy/exampleبالتالي فإن Go تدفعك ﻷن يكون مجلد المشروع على حاسوبك مشابها لهذا الرابط، أي تحت هذا المسار: work/src/github.com/HsoubAcademy/exampleحيث: github.com هو مجلد فرعي تحت مجلد src.HsoubAcademy هو مجلد فرعي تحت مجلد github.com آنف الذكر، غيّره إلى حسابك على Github مثلا.example هو مجلد فرعي يحوي ملفات مشروعك تحت مجلد HsoubAcademy.ملاحظة: أسماء المجلدات حسّاسة لحالة الأحرف (case-sensitive) ماعدا على نظام Windows. لماذا ترتيب بيئة العمل بهذا الشكل؟ببساطة ﻷن التنظيم بهذا الشكل مفيد جدًا من ناحيتين: 1. بالإمكان جلب أي مكتبة خارجية بمجرد عمل import لها من مسار مستودعها، مثلا: لنفرض أننا نريد استعمال مكتبة لنزع التشكيل عن النص العربي، سنستخدم مكتبة goarabic، سيكفي لتضمينها في مشروعنا البرمجي كتابة الأمر: go get github.com/01walid/goarabic2. يقوم أمر go get بوضع ناتج تجميع هذه المكتبة في مجلد pkg بنفس مسار رابطها على github، أي سيضعها داخل مجلد فرعي باسم 01walid داخل مجلد github.com الذي هو بدوره عبارة عن مجلد فرعي داخل مجلد العمل، بالتالي يمكن تضمينها مباشرة في مشروعنا بهذا الشكل: import "github.com/01walid/goarabic" لاحظ أن مسار استيراد هذه المكتبة هو نفسه رابطها على github. هذا يُسهّل من عملية مشاركة المكتبات البرمجية وإثراء مكتبات اللغة نفسها. من المهم جدا أن يتبع مشروعك نفس هذا المنهاج، خاصة إن كان عبارة عن مكتبة. تهيئة بيئة العملإن كنت على لينكس أو Mac OS، يمكنك مثلا إنشاء مجلد باسم work داخل مجلد Home خاصتك بكتابة أمر: mkdir $HOME/workثم جعل هذا الأخير هو بيئة عمل Go عبر إنشاء متغير بيئة باسم GOPATH (حسّاس لحالة الأحرف) يُشير له: export GOPATH=$HOME/workطبعا لجعل هذا المتغير دائم حتى بعد إعادة التشغيل، سيكون عليك كتابته في bashrc. (في حال كنت تستعمل صدفة bash، أو ملف zshrc. إن كنت تستعمل صدفة zsh كمثال، وهي ملفات موجود داخل مجلد المنزل خاصتك HOME$). أما إن كنت على Windows فيكفي إضافة متغير باسم GOPATH عبر التوجه إلى: خصائص النظام (System -> Advanced system settings)ثم النقر على متغيرات البيئة (Environment Variables)ثم إضافة المتغير من قسم System variables كما هو مبين أسفله. إذا كان مجلد عملك مثلا في Windows هو C:\Projects\Go فسيكون عليك إضافته بهذا الشكل: يمكنك التحقق من أنه تم إضافة المتغير الجديد، عبر فتح نافذة سطر أوامر جديدة، وكتابة الأمر: %echo %GOPATH كما هو موضح أسفله: إن تم إظهار المسار المُختار لمجلد عملك، فقد قمت أخيرًا بتنصيب Go وتهيئتها بنجاح. إضافة (Bonus)ماذا لو أمكننا جعل البرامج التنفيذية التي نكتبها أو نجلبها عبر أمر go get متوفرة مباشرة لدينا في نافذة سطر الأوامر دون التصفح إليها في كل مرة؟ مثلا لنقل أننا نريد الاستفادة من أداة ha المكتوبة بلغة Go، لتحويل ملفات Markdown إلى HTML جاهز للّصق على محرر آخر، نقوم بجلب الأداة: go get github.com/HsoubAcademy/haبما أن أداة ha عبارة عن برنامج تنفيذي فإن أمر go get سينقله مباشرة إلى مجلد bin داخل بيئة العمل. لكن لا نريد التنقل إلى مجلد bin داخل مجلد العمل لاستعمالها، نريد فقط كتابة ha في سطر الأوامر مباشرة للاستفادة من الأداة واستعمالها حتى وإن كنا في مجلد آحر. بما أن Go تقوم بوضع ناتج الملفات التنفيذية في مجلد bin تحت مجلد العمل، بالتالي، يكفي إضافة مسار مجلد bin إلى مسارات متغير البيئة PATH ليكون كل شيء متوفر لديك! حتى برامجك التنفيذية التي تكتبها بنفسك. بالنسبة لمستخدي Linux أو Mac OS فإن ذلك ممكن عبر إضافة مسار مجلد bin داخل مجلد العمل إلى متغير البيئة PATH: export PATH=$PATH:$GOPATH/binأما لمستخدمي Windows فعليهم إضافة مسار مجلد bin داخل مجلد العمل إلى متغير البيئة PATH عبر التوجه إلى: خصائص النظام (System -> Advanced system settings)ثم النقر على متغيرات البيئة (Environment Variables)البحث عن قيمة Path في قسم System variables ثم الضغط على edit وإضافة المسار إلى آخر السطة مسبوقا بفاصلة منقوطة (;) كما هو مبين أسفله. الآن ستجد أن كل ما هو موجود في مجلد bin من برامج وأدوات متاح لك، من ذلك أداة ha التي أشرنا إليها سابقا (جرب فتح نافذة سطر أوامر جديدة وكتابة الأمر ha). بهذا نأتي إلى نهاية الدرس الثاني من هذه السلسلة، سنشرع في الدرس القادم في كيفية بدء البرمجة بـ Go والاستفادة من بيئة العمل هذه.
  7. لعلّك سمعت في السنوات القليلة الماضية عن لغة برمجة جديدة نشأت من داخل شركة Google تحمل اسم Go (أو Golang كمصطلح قابل للبحث على محركات البحث)، سنحاول من خلال هذه السلسلة التعرّف على هذه اللغة، مزاياها، عيوبها وما يجعلها مختلفة عن غيرها. سيكون الدرس الأول من هذه السلسلة درسًا كلاميا فقط، يركز على نقاط اختلاف اللغة مع باقي اللغات، وهو موجه لمن له خلفية برمجية نوعا ما مع باقي اللغات، لكن ستكون باقي الدروس موجهة للمبتدئين. كعادة كل عقد من الزمن، فإنه تظهر هناك أدوات وتقنيات جديدة تحاول الاستفادة من أخطاء أسلافها من الأدوات والتقنيات، هذا يشمل لغات البرمجة أيضا، لذلك دعك من قول "لماذا لغة برمجة جديدة؟" و "ما الحاجة للغة برمجة جديدة؟" أو "لماذا لا يتفقون على لغة برمجة واحدة؟"، فما لغة البرمجة إلا أداة تقضي بها مهامك، وكل منها يكون أصلح لنوع مهام ما. فاختر لكل مهمة أنسب أداة، ولا داعي لتقديس الأداة وإنشاء الحروب الكلامية -غير التقنية- حولها أو خلق هاجس وهمي يحول عن تعلمها. أَحَسَّ فريقٌ من المبرمجين (العريقين) من داخل Google أنه حان الوقت لتحسين سير عملهم بلغة C و ++C، وأنهم يحتاجون إلى أداة جديدة تلغي عيوب هاتين الأخيرين وتحسن من إنتاجيتهم أكثر، وتكون ملائمة لنوعية احتياجات Google الحسابية. أسسوا لغة البرمجة Go داخل Google عام 2007. الفريق العريق المؤسس لهذه اللغة يشمل مؤسس نظام Unix نفسه Ken Thompson (عَلَمٌ في عِلم الحاسوب، يُعرف اختصارًا بـ Ken) الذي عمل لدى Bell Labs، كذلك Robert Pike الذي كان أيضا من ضمن فريق Unix لدى Bell Labs وأحد مؤسسي ترميز UTF-8 وأخيرًا Robert Griesemer أحد العاملين على محرك جافاسكريب V8. Ken على يسار الصورة بجانب Dennis Ritchie مؤسس لغة C بمعرفة هذه النبذة التاريخية البسيطة عن Go، أحب أن أقتل فيك كل حماس مُفرط، فلا أحب منك أن تعشق لغة برمجة بسبب مؤسيسها، أو أنها خرجت من شركة تحبها، لذلك سأبدأ بسرد أشياء قد لا تحبها حول لغة البرمجة Go، حتى إذا قرأتها ولم تعجبك، فقد يجدر بك التوقف عن القراءة حينها. سأكون سعيدا شخصيا بمتابعة عدد قليل جدا من القراء لهذه السلسلة يدركون حقا ما يفعلون، عوض زخم يتحمس لكل جديد دون وعي وإلمام بالأمور. أشياء قد لن تحبها حول لغة البرمجة Go1. ليست كائنية التوجههذا إن كنت تظن أنها كذلك، فلا يوجد مفهوم الصنف (Class) ولا الكائنات (Objects) وبالتالي لا يوجد وراثة (inheritance). مع ذلك فإن Go تحمل بضعا من مزايا البرمجة الكائنية كتوفيرها لـ Interface و دوال البنيات (Struct methods) وتركيب البنيات (Struct composition). لماذا؟ مؤسسي اللغة يرون أن اللغات كائنية التوجه تحمل العديد من العيوب والتعقيدات التي يمكن إلغاؤها بالتخلي عن بعض هذه المفاهيم كلية. حتى مبرمجي Java أنفسهم ينصحون بـ Composition مثلا في كثير من الأحيان عوض inheritance، مؤسسي اللغة ممن يرون أن البرمجة كائنية التوجه غالبا ما تكون فكرة سيئة -تقنيا-. 2. لا توجد معالجة للاستثناءات Exception Handlingقد تكون هذه نتيجة طبيعية بسبب غياب مفهوم البرمجة الكائنية لدى Go، فمعالجة الأخطاء في Go تتم بطريقة واضحة وتقليدية نوعا ما، حيث أن الأخطاء تُرجع كقيم عادية من نوع error. حيث error هو نوع بدائي في حد ذاته مثله مثل أي نوع أصلي آخر (int, string .. الخ). مع ذلك تسمح لك Go بقذف خطأ للحالات الاستثنائية عبر الكلمة المفتاحية panic (أشبه بـ raise أو throw في باقي اللغات) وكذا التعافي من هذه الأخطاء عن طريق recover. 3. لا توجد معامِلات افتراضية أو اختيارية يمكن تمريرها للدوال (default/optional arguments)ربما قد اعتدت في لغات البرمجة الأخرى على القيام بشيء مثل: function listFolders(path, subfolders=false, recursive=false){ ... } لكن في Go لن يمكنك تمرير subfolder=false ولا recursive=false كإمضاء للدالة listFolders لأنها لن تقبل مثل هذه المعاملات الافتراضية/الاختيارية، وسينتج عن ذلك خطأ عند التجميع (compile error). لماذا؟ يرى مؤسسوا اللغة أن هذه السلوكيات تساهم في بناء واجهات برمجية (API) غير ثابتة أو تساهم في جعل تصرفها غير مُتوقع. في مثالنا السابق مثلا، هم يفضلون كتابة الدالة من دون معاملات افتراضية، أي: func listFolders(path string, subfolders bool, recursive bool) { ... }يجبرك هذا على كتابة التصرف الذي تريده من الدالة بشكل صريح عوض ترك الواجهة البرمجية تملي عليك التصرف الافتراضي، هذا لتقليل الأخطاء البشرية. أيضا قد يدفعك هذا إلى كتابة ثلاث دوال، كل بتصرفها الخاص الواضح من اسمها، مثال: listFolders, listFoldersRecursivly و listFoldersWithFirstLevelSubFolders. 4. لا توجد ميزة إثقال الدوال (Method Overloading)لنفس الأسباب السابقة، فإنه لا يوجد Method overloading، أي لا يمكنك إعادة تعريف دالة تحمل نفس الاسم لكن بإمضاء مغاير. مثلا، إذا وُجدت دالة باسم: func listFolders(path string) { ... }فلا يمكنك إنشاء دالة أخرى بنفس الاسم لكن بإمضاء مغاير مثل: func listFolder(path string, level int) { ... }بل عليك تغيير اسمها إلى مثلا: dunc listFolderToLevel(path string, level int) { ... }على الرغم من ذلك فهناك طريقة غير مباشرة لجعل دالة ما تقبل قيما اعتباطية عبر جعل الإمضاء من نوع {}interface سنتطرق إليها في الدروس القادمة. 5. لا وجود للعموميات (generics)تمكّنك باقي اللغات من كتابة دوال أو أصناف عامة، حيث لا تصرّح عند كتابتها بنوع المعاملات التي تقبلها لكن تترك لها مهمة معرفة نوع المعاملات لاحقا عند استدعائها، لعل أقرب مثال هو ما توفره لغة Java مثلا في صنف <List<T حيث T يرمز إلى أي نوع يتم تحديده لاحقا، بالتالي يمكن إنشاء <List<String أو <List<Integer بكل سهولة مع الحفاظ على نفس الوظائف والعمليات التي يمكن إجراؤها على القائمة List بشكل عام. لا يوجد في Go مثل هذا، وعوضا عن ذلك فهناك {}interface كنوع شامل يرضي جميع الأنواع، لكنه ليس كبديل تام لـ Generics. لماذا؟ سبب عدم توفر العموميات (Generics) في Go هو أن مؤسسيها لم يتبيّنوا بعد الطريقة الأنسب لهم لإضافة هذه الميزة إلى اللغة دون زيادة حِمل أثناء وقت التشغيل (run-time). 6. Go لُغة مملة كما أنها ليست أفضل لغة برمجة!لشدة بساطة اللغة وعدم إتيانها بشيء جديد، فإن الكثيرين يعتبرها لغة مملة. فعدد الكلمات المفتاحية بها والأنواع الأصلية فيها ضئيل مقارنة بباقي اللغات، كما أنها تقلل كثيرا من وجود أكثر من طريقة للقيام بمهمة معينة. حتى أنها لا تحتوي على حلقة while وتقتصر فقط على حلقة for، الكثيرون يعتبرون هذا من مزايا اللغة، لكني ذكرتها لك حتى لا تتوقع شيئا جديدا يصلح للتباهي. أيضا لن تسمح لك اللغة بترك متغير دون استعمال أو استيراد شيء غير مستعمل (unused import/variable) ولن يقبل المُجمع (compiler) أبدا بذلك. 7. لغة عنيدةمؤسسوا اللغة متشبثون برأيهم وقراراتهم في تصميم اللغة، فلا تتوقع تغيرات جوهرية قد تحدث على المدى القريب أو المتوسط في اللغة أو تغيرات في طريقة القيام بالأمور وسلوك المُجمّع (compiler). ولا داعي لفتح نقاشات فارغة حول تصميم اللغة وعيوبها إلا إذا كنت في نفس مستوى خبرتهم وحكمتهم. هم نفسهم يصرحون بهذا، ويذكرون أن هناك خيارات ولغات برمجة أخرى إن لم تعجبك Go. 8. لا يوجد إجماع على مدير حزم واحدتملك بايثون pip، وجافاسكريب تملك npm، وغيرهم من اللغات تملك مدير حزم (package manager) شهير أو متفق عليه، لا تخلو Go من مدير حزم، فهي تملك الكثير من ذلك، لكنها لم تتفق بعد على مدير حزم واحد ولا عن كيفية جلب وسرد الاعتماديات بطريقة قياسية، لكن حديثا يتم العمل على ذلك عبر مفهوم Vendoring. هذه الأمور الثمانية، للذكر وليس للحصر من أشد الانتقادات التي توجّه إلى Go كلغة برمجة، فإن كنت توافقها فقد لا تناسبك اللغة، وإن كنت ترى أن من ورائها حكمة -مثلي- فأكمل قراءة المقال حول أمور قد تعجبك حول Go. أشياء قد تحبها حول لغة البرمجة Go1. خيوط المعالجة المتوازية الخفيفة (goroutines)تسمح لك Go بعمل معالجة متوازية والاستفادة من كامل قوة المعالج (CPU) لديك بكل بساطة، حيث تملك ما يسمى بـ goroutine وهو خيط معالجة متوازي أخف من thread في باقي اللغات. يسمح لك هذا بإطلاق عشرات الآلاف من خيوط المعالجة المتوازية (عوض مثلا عشرات أو مئات threads فقط) دون عناء إنشائها وجعلها تتواصل فيما بينها أو تُكمّل بعضها البعض. يكفي مثلا لعمل دالة تعمل في خيط معالجة لوحدها بسبقها بالكلمة المفتاحية go، مثلا: go func(){ // دالة نكرة تقوم بعمل أمور في خيط معالجة لوحدها .... }هذا يسمح بكتابة تطبيقات عالية الأداء بشكل أسهل بكثير. 2. لغة تجميعية سريعة (compiled)عكس Ruby, Python, Java و PHP فإن Go لغة تجميعية، حيث أن الناتج النهائي لبرنامجك سيكون عبارة عن ملف تنفيذي قائم بذاته يحوي جميع الاعتماديات اللازمة لتشغيله دون الحاجة لاعتماديات خارجية، هذا مفيد جدا في تطوير الويب مثلا للتخلص أو تقليص مشاكل الاعتمادية (dependency hell). أيضا تساهم هذه الميزة في تسهيل عملية نشر التطبيق الخاص بك (deployment) حيث سيكون عليك فقط نقل الملف التنفيذي إلى الخادوم مثلا ثم تشغيله وكفى. لا حاجة لتنصيب أي شيء آخر لتشغيل برمجيتك، لا حاجة حتى لتنصيب Go على الخادوم نفسه. قد يتبادر إلى الذهن أن عملية التجميع (compiling) قد تأخذ وقتا خاصة إذا كان حجم البرنامج كبيرا، لكن الحقيقة أن عملية تجميع Go سريعة جدا وفي كثير من الأحيان لن تلاحظها حتى. 3. لغة إنتاجيةبسبب أنها لغة مملة، فإنها تضيق عليك مجال المجادلة مع زميلك في العمل أو من يعمل معك على المشروع أو البحث عن أفضل طريقة -مذهلة- للقيام بشيء ما، فكل شيء واضح وبسيط. 4. متعددة المنصات بامتيازنفس البرنامج يمكن إعادة تجميعه ليعمل على ويندوز، لينكس، Mac OSx أو حتى الهواتف الذكية ومعمارية ARM. حتى أنه بعد الإصدارة رقم 1.5 من Go يمكن إنشاء ملف تنفيذي لجميع المنصات من خلال المنصة التي أنت فيها، مثلا يمكن من خلال نظام لينكس إنشاء ملف تنفيذي لنظام ويندوز و Mac OS دون الحاجة ﻷن تكون على ذلك النظام. 5. مكتبة قياسية قوية (Rich Standard Library)على الرغم من حداثة اللغة، فإن مكتبتها القياسية حققت تقدما في ظرف قياسي. وغالبا ما يُنصح بالاعتماد على المكتبة القياسية قدر الإمكان، حيث تحتوي على أمور كثيرة تحتاجها أغلب أنواع التطبيقات، حتى أنها تحتوي على محرك قوالب html، أدوات للتعامل مع ترميز json، تشفير كلمات المرور وغيرها من الأمور الصالحة للاستعمال في تطبيقات الويب على سبيل المثال. 6. كل شيء Unicode افتراضاموضوع ترميز السلاسل النصية وكيفية التعامل مع الحرف رقميا كبير، لكن Go جعلت كل شيء unicode بشكل افتراضي إلا إذا تم تعيين غير ذلك صراحة. تملك Go نوع rune عوض نوع char في باقي اللغات، وهو ببساطة اختصار (alias) لنوع int32 فقط يشير إلى نقطة ترميز Unicode لذلك الحرف. بالتي فإن string في Go عبارة عن سلسلة rune وليس عن سلسلة char يشير إلى byte كما في C مثلا. 7. أدوات مساعدة جيدة مضمنة يمكن توليد توثيق برمجيتك بمجرد كتابة أمر godoc أو تحسين التنسيق بكتابة gofmt أو بدء إجراءات فحص الشفرة البرمجية (Unit testing مثلا) عبر كتابة go test وكلها أدوات تأتي مع تنصيب Go. 8. لغة سهلة من حيث الكتابة والتنسيق (Syntax)تنسيق اللغة شبيه نوعا ما بلغة بايثون، حيث لا وجود للفاصلة المنقوطة بعد نهاية كل تعليمة (;)، كما يمكن عمل متغير جديد دون تحديد نوعه، على الرغم من أن اللغة شديدة النوعية strongly styped إلا أنها توحي أنها سَلِسَة وديناميكية، مثلا يمكن كتابة age := 35 وسيتم اسناد نوع int إلى المتغير age. كما أنه يمكن للدوال إرجاع أكثر من قيمة كما في بايثون مثلا. لعل أكثر شيء مغاير لباقي اللغات هو طريقة كتابة الدوال، حيث أن القيمة التي تُرجعها الدالة تُكتب على يمين الدالة (كما في Pascal) وليس على يسارها، مثلا: func HelloHsoub() string { return "Hello Hsoub Academy!" }لاحظ أنه تم كتابة string على يمين الدالة وليس يسارها، أي أن هذه الدالة تُرجع قيمة من نوع string. يمكن للدوال إرجاع دوال أخرى أيضا كقيمة كما يمكن للمتغيرات أن تشير إلى دوال (كما في جافاسكريبت وبايثون...) مثلا: sayHi := HelloHsoub حتى لا أنحاز، فهذه 8 أشياء قد تحبها سأتوقف عندها مقابل 8 قد لا تعجبك كنت قد ذكرتها. بهذا نكون وصلنا إلى ختام الدرس الأول -الكلامي- من هذه السلسلة، والتي رأيت أن أبدأها هكذا عمدا ولو أن بعضا مما قيل في هذا الدرس قد لا يكون بالضرورة موجها للمبرمج المبتدئ، لكني سأحاول جعل الدروس القادمة أبسط ما يكون وتُعنى بالمبتدئ أولا.
  8. هل خادومك apache أم nginx؟ ماهو رابط موقعك ؟
  9. كصاحب أي موقع جدّي، فإن أمن زوّارك أو مستخدمي موقعك يجب أن يكون من أولى أولوياتك، ولعلنا كمديري مواقع لطالما أردنا أيقونة القفل تلك (أحيانا تكون خضراء) بجانب عنوان (URL) الموقع، تُشير إلى أن موقعنا آمن ويستخدم اتصالا مشفرًا بين الزائر والخادوم. لحظة، ماهي شهادة SSL/TLS أولا؟SSL/TLS اختصارٌ لـِ Secure Socket Layer/Transport Layer Security وببساطة هو بروتوكول لتشفير نقل البيانات بين طرفين، في حالتنا هذه بين الخادوم والمستخدم (المتصفح)، ما يضيف ميزة الحماية على بروتوكول التصّفح HTTP، ومنه جاءت إضافة حرف S له فأصبح HTTPS. لماذا؟بدون هذا التشفير، يتم استعمال بروتوكول التصفح العادي HTTP، وهو بروتوكول ذو طبيعة نقل بيانات في شكلها النصّي البحت. أمّا مع HTTPS فسيقوم المتصفح بتشفير البيانات أوّلا قبل إرسالها، ثم يتم فكّ تشفيرها لمّا تصل إلى الخادوم، فإن التقط أحدهم هذه البيانات وسط الطريق، لن يكون بإمكانه قراءتها ﻷنها مشفّرة. تخيل أن لديك صفحة تسجيل دخول على موقعك (Login)، وموقعك لا يزال يستعمل HTTP، فإن حدث وأن كان أحد المتطفلين/المخترقين على نفس شبكة مُستخدمك (مثلا يتشارك معه نفس اتصال WiFi) والتقط هذا الأخير البيانات التي يرسلها مُستخدم موقعك، فسيعرف ماهو اسم المستخدم/بريده وكلمة مروره بكل سهولة ودون عناءٍ حتى. لا يقتصر هذا على المتطفلين فقط، فقد يكون مزود الخدمة لديك (ISP) ممن يسجّل تحركات زبائنه وبالتالي يمكنه أيضا كشف بيانات الدخول أيضا. هذه أمثلة فقط فالخطر لا يُمكن حصره، فالأجدر سدّ هذا الباب. بسبب هذا، نما في السنوات القليلة الماضية وعيٌ لدى مستخدمي الويب عموما، وجهات الويب المفتوح وحقوق المستخدم بضرورة تعميم استعمال بروتوكول HTTPS وتسهيل عملية تفعيله عوض تعقيدات التنصيب وتكلفة الشراء الباهضة. حيث قبل أيام قليلة فقط، كان الحصول على شهادة SSL/TLS أمرًا عسيرًا وقد يتطلب ميزانية مالية سنوية معتبرة زائدة على صاحب الموقع. فإما أن تشتري شهادة من طرف أحد الهيئات العالمية المعترف بها من طرف أغلب المتصفحات (مثل Comodo و Symantec)، أو تطلب شهادة شخصية مجانية واحدة فقط غير صالحة للاستخدام التجاري من عند StartSSL، أو تمر عبر خدمة Cloudflare التي تنصب نفسها وسطا بين خادوم موقعك وزوَاره حتى تنعم بـ SSL مجاني. مبادرة Let's encrypt من منطلق الوعي الحاصل بضرورة توفير شهادات SSL بطريقة سهلة، مجانية، مفتوحة وتلقائية، بادرت كل من Mozilla, Facebook, Cisco، منظمة لينكس وغيرها بإنشاء هيئة ذات سلطة توليد، تفعيل وإمضاء شهادات SSL، وقد نجحت في جعلها جهة مُعترفًا بها من طرف متصفحات الويب، وأطلقتها مؤخرا لعامة الناس كمرحلة Beta لكنها فعّالة ويمكن التعويل عليها من الآن فصاعدا. تحميل عميل أتمتة طلب شهادات Let's encrypt ملاحظة: حاليا، أداة العميل (client tool) تدعم فقط أنظمة يونكس، ولا يوجد دعم لخواديم Windows بعد. أولا، يجب طبعا الدخول على خادومك عبر ssh، إن كنت لا تعرف كيفية القيام بذلك، فأكاديمية حسوب تأخذ بيدك. تأكد أنك تملك صلاحيات root. ثانيا، عليك بتنصيب git، إن كنت على Ubuntu أو Debian مثلا فقم بالأمر التالي: sudo apt-get install gitأما على Fedora/Centos: sudo yum install gitوإن كنت على Arch Linux يكفي كتابة الأمر: sudo pacman -S gitثالثا: حمّل عميل Let's encrypt على خادومك عبر كتابة هذه الأوامر: git clone https://github.com/letsencrypt/letsencrypt طلب وتنصيب الشهادة لخادوم nginxملاحظة 1: عليك توقيف خادوم nginx للحظات لغاية انتهاء التنصيب، العميل لا يدعم توقيف وإعادة تشعيل nginx بشكل تلقائي بعد، لذلك يجب القيام بهذا يدويا. يمكنك توقيف خادوم nginx بكتابة الأمر التالي على Debian ومشتقالتها: sudo service nginx stopأو عبر: sudo systemctl stop nginxللأنظمة التي تعتمد على systemd. إن كنت تجهل كيفية التعامل مع خادوم nginx فإليك قسما كاملا على أكاديمية حسوب يهتم بهذا الجانب، وأنصحك أن تبدأ بهذا الدرس، عليك أن تألف إعادات nginx وكيفية عملها قبل المواصلة مع هذا الدرس. ملاحظة 2: أي إعداد خاطئ في هذه المرحلة قد يسبب توقف موقعك لمدة مُعتبرة، يجدر بك أولا معرفة مبادئ التعامل مع nginx. أولا يجب الدخول إلى حيث قمنا بتحميل عميل let's encrypt: cd letsencryptثم طلب الشهادة بهذ الطريقة: sudo ./letsencrypt-auto certonly --standalone -d example.com -d www.example.com الأمر أعلاه يقوم بالتالي: sudo ./letsencrypt-auto: تشغيل عميل طلب الشهادة بصلاحيات root.certonly: أي أننا نطلب فقط الشهادة لوحدها دون التنصيب التلقائي لها على nginx أو ما شابه (كون هذه الخاصية لا تزال تجريبية ولا يمكن التعويل عليها).standalone--: أي استعمل خادوم ويب خاص يتم تشغيله للاستماع على كل من منفذي 80 و 433 لتوثيق الشهادة من طرف سلطة let's encrypt (ضروري، ولهذا وجب توقيف nginx أولا).d-: اختصارًا لـ domain أي النطاق أو النطاقات الفرعية التي ستكون هذه الشهادة صالحة لها.ملاحظة: لا يمكن حاليا تمرير example.com.* مثلا إلى تعليمة d- حيث لم يتم بعد دعم wildcard domain، أي النطاقات التعميمية، لكن من السهل إضافة دعم أي نطاق فرعي آخر عبر إضافته إلى تعليمة d-. ستجلب الأداة بعض الاعتماديات اللازمة وتنصبها على النظام ثم تُظهِر لك الرسالة التالية: أدخل عنوان بريدك الالكتروني صحيحًا، ﻷنه سيكون مهما لاستعادة المفاتيح الضائعة أولإشعارك بأمور مهمة خاصة بشهادتك (كقرب موعد انتهاء صلاحيتها). ثم اضغط على مفتاح Enter. ستظهر بعدها إتفاقية الاستحدام -كما هو ظاهر أدناه- قم بقراءتها ثم الموافقة عليها: سيباشر بعدها العميل بطلب الشهادة وتوثيقها، لتظهر أخيرًا الرسالة التالية: IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at /etc/letsencrypt/live/example.com/fullchain.pem. Your cert will expire on 2016-03-04. To obtain a new version of the certificate in the future, simply run Let's Encrypt again. - If like Let's Encrypt, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le كما هو موضّح في الرسالة، فقد تم تنصيب الشهادة في مسار /etc/letsencrypt/live/example.com/ حيث example.com هو اسم نطاق موقعك. يمكن تنصيب الشهادة على خادوم nginx بسهولة عبر تحرير الملف الخاص بموقعك وإضافة بضعة سطور، كالتالي: sudo nano /etc/nginx/sites-available/www.example.comحيث www.example.com هو اسم ملف، ويجب تغييره باسم ملف إعدادات موقعك مع nginx. ثم إضافة الأسطر التالية في كتلة server ضمن ملف الإعدادات: http { server { listen 443 ssl; server_name www.example.com; ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; ... // باقي الإعدادات تجاهلها } }قم بإعادة تشغيل خادوم nginx عبر الأمر التالي: sudo service nginx startإن كنت على أحد الأنظمة التي تستعمل systemd فقد يكون عليك إعادة تشغيل nginx بالأمر التالي: sudo systemctl start nginxتهانينا لك شهادة SSL مجانية صالحة لمدة 90 يوم، يمكنك طبعا تجديدها بتشغيل نفس الأمر، كما يمكنك أتمتة عملية التجديد عبر برمجتها كمهمة cron job عبر crontab (كل شهر مثلا لتفادي أي مشكل). تنصيب الشهادة على خادوم apacheيمكن طلب الشهادة بنفس الطريقة ثم فقط تنصيبها يدويا على خادوم Apache كما فعلنا مع nginx، يمكنك اتباع الدرس التالي من على أكاديمية حسوب لمعرفة كيفية القيام بذلك، أما إن كنت على أحد أنظمة Debian أو مشتقاتها (مثل Ubuntu) فيمكنك أتمتة العملية بأكملها (دون الحاجة لتوقيف الخادوم) عبر تشغيل الأمر التالي: sudo ./letsencrypt-auto --apacheسيتم سؤالك طبعا عن أسماء النطاقات، بريدك الالكتروني وشروط الخدمة. أجب عليها واترك الأداة تعمل لغاية ظهور رسالة التهنئة. ملاحظة: في حين احتاج nginx لملفي fullchain.pem و privkey.pem فإن Apache يحتاج لملفي: chain.pem لتعلمية SSLCertificateChainFile.وprivkey.pem لتعليمة SSLCertificateKeyFile.بهذا نكون قد تحصلنا على شهادتنا، يمكن إلقاء نظرة على التوثيق الرسمي لتخصيص الأداة وزيادة نسبة الأتمتة وكيفية التجديد التلقائي. على أمل أن نجعل الويب النّاطق بالعربية أكثر أمنا وخصوصية!
  10. يمكنك الاستزادة وتعلم Git من موقع https://www.arabicgit.com/ وهذا مقال يجيب على سؤالك بالتحديد: https://www.arabicgit.com/what-is-git/
  11. تأكد أن لديك: git config --global color.ui trueفقط أكتب هذا السطر على الطرفية. وإن كنت تريد أمور متقدمة في دمج مع الطرفية مع git بطريقة أحسن، اطلع على مشروع oh my zsh: http://ohmyz.sh/ إذا أردت استعماله عليك أولا تغيير طرفيتك من bash إلى zsh.
  12. تم نشر الجزء الثاني: http://academy.hsoub.com/marketing/inbound-marketing/الأدوات-المستخدمة-لإنشاء-الإنفوجرافيك-r69/
  13. في الدروس السابقة قمنا بدراسة الأدوات القياسية والتي لابد من استخدامها في معظم تطبيقات ASP.Net، سنتناول في الدروس القادمة أدوات تحكم أكثر تخصصا وتعرف مجموعة الأدوات هذه باسم Rich controls. في هذا الدرس ستتعلم كيف تسمح للمتصفحين بأن يرفعوا ملفاتهم على الموقع، كأن يقوموا مثلا برفع صور، ملفات فيديو ... إلخ. رفع الملفات إلى الموقع نستخدم أداة التحكم FileUpload لرفع الملفات إلى الموقع، ونقوم بتحديد المكان الذي سيتم تخزين ملفات المستخدمين فيه، إما مجلد داخل الموقع أو ضمن قاعدة بيانات الموقع وسنستعرض كلا الحالتين. خصائص أداة التحكم FileUpload Enabled: تفعيل أو إلغاء تفعيل هذه الأداة. FileBytes: للحصول على محتويات الملف كمصفوفة بايتات. FileContent: للحصول على محتويات الملف كمجرى stream. FileName: الحصول على اسم الملف. HasFile: تعيد True عندما يتم رفع الملف. PostedFile: تعيد الملف المرفوع مغلف بغرض من الصف HttpPostedFile. كما أن أداة التحكم FileUpload تدعم الطرائق التالية: Focus: تسمح بوضع التركيز على هذه الأداة. SaveAs: تقوم بتخزين الملف (المراد رفعه) على الموقع. تقوم الخاصية PostedFile بتغليف الملف المرفوع بغرض HttpPostedFile، هذا الأمر يسمح بالحصول على معلومات إضافية حول الملف. خصائص الصف HttpPostedFile ContentLenght: لمعرفة حجم الملف بالبايتات. ContentType: لمعرفة نوع الملف ( اللاحقة). FileName: لمعرفة اسم الملف. InputStream: الحصول على الملف كمجرى stream. كما أن الصف HttpPostedFile يدعم الطريقة SaveAs والتي تقوم بتخزين الملف على الموقع. لاحظ أن الصف HttpPostedFile يقدم بعض الخصائص المتوفرة مسبقا مع أداة التحكم FileUpload والتي يمكن التعامل معها دون الحاجة للصف HttpPostedFile، على سبيل المثال للحصول على اسم الملف يمكن اتباع أحد الأسلوبين: FileUpload.FileName HttpPostedFile.FileName كما أن الطريقة SaveAs موجودة في الصف HttpPostedFile على الرغم من توافرها مع أداة التحكم FileUpload بشكل صريح. مثال: أنشئ صفحة جديدة وأضف عليها الأدوات FileUpload1 ،Button1 ،Label1. أنشئ مجلد جديد داخل ملفات الموقع باسم uploads لنقوم برفع الملفات إليه، في حدث الضغط على الزر اكتب الكود التالي: كود #C protected void Button1_Click(object sender, EventArgs e) { try { if (FileUpload1.HasFile) { string path = "~/uploads/" + FileUpload1.FileName; FileUpload1.SaveAs(MapPath(path)); Label1.Text = "File Uploaded successfuly..."; } } catch (Exception ex) { } } كود VB Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click If (FileUpload1.HasFile) Then Dim filePath As String = "~/uploads/" & FileUpload1.FileName FileUpload1.SaveAs(MapPath(filePath)) End If End Sub كود الصفحة يجب أن يكون كالتالي: كود ASP.net <div> <asp:FileUpload ID="FileUpload1" runat="server" /> <br /> <asp:Button ID="Button1" runat="server" Text="Upload" onclick="Button1_Click" /> <br /> <asp:Label ID="Label1" runat="server" Text=""/> </div> نفذ التطبيق السابق وحاول رفع ملف ما ( صورة مثلا)، أغلق التنفيذ. يجب أن يكون الملف قد أضيف للمجلد Upload، إن لم تره اضغط على تحديث ملفات الموقع كالتالي: في المثال السابق يستطيع المستخدم أن يرفع أي نوع كان من الملفات، سنقوم في المثال التالي بتحديد الأنماط التي نسمح للمستخدم بأن يقوم برفعها ( فقط بعض أنواع الصور). مثال: أنشئ صفحة جديدة وأضف عليها الأدوات FileUpload1 ،Button1 ،Label1. أنشئ مجلد جديد داخل ملفات الموقع باسم uploads لنقوم برفع الملفات إليه. في حدث الضغط على الزر اكتب الكود التالي: كود #C protected void Button1_Click(object sender, EventArgs e) { try { if (FileUpload1.HasFile) { if (CheckFileType(FileUpload1.FileName)) { string path = "~/uploads/" + FileUpload1.FileName; FileUpload1.SaveAs(MapPath(path)); Label1.Text = "File Uploaded successfuly..."; } } } catch (Exception ex) { } } كود VB Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click If (FileUpload1.HasFile) Then If (CheckFileType(FileUpload1.FileName)) Then Dim filePath As String = "~/uploads/" & FileUpload1.FileName FileUpload1.SaveAs(MapPath(filePath)) End If End If End Sub قم باستدعاء فضاء الأسماء الخاص بالدخل والخرج IO، حيث نضيف الكود التالي أعلى الصفحة: كود #C using System.IO; كود VB Imports System.IO أما الدالة CheckFileType المسؤولة عن فحص نوع الملف فهي: كود #C bool CheckFileType(string fileName) { string ext = Path.GetExtension(fileName); switch (ext.ToLower()) { case ".gif": return true; case ".png": return true; case ".jpg": return true; case ".jpeg": return true; default: return false; } } كود VB Function CheckFileType(ByVal fileName As String) As Boolean Dim ext As String = Path.GetExtension(fileName) Select Case ext.ToLower() Case ".gif" Return True Case ".png" Return True Case ".jpg" Return True Case ".jpeg" Return True Case Else Return False End Select End Function كود الصفحة السابقة: كود ASP.net <div> <asp:FileUpload ID="FileUpload1" runat="server" /> <br /> <asp:Button ID="Button1" runat="server" Text="Upload" onclick="Button1_Click" /> <br /> <asp:Label ID="Label1" runat="server" Text=""/> </div> نفذ التطبيق السابق وحاول أن ترفع ملف ما مغاير للأنواع المحددة، ستلاحظ عدم رفع الملف، أعد التجربة مع أحد أنواع الصور السابقة لترى قبول عملية الرفع. رفع الملفات إلى قاعدة بيانات حيث نقوم بتخزين الملفات في قاعدة بيانات عوضا عن مجلد عادي، هذا الأسلوب يسبب كبر هائل بحجم قاعدة البيانات وبالتالي صعوبة وبطء في نقلها والتعامل معها، كما أننا نحتاج لتحويل الملفات إلى بيانات ثنائية (0,1) لنتمكن من تخزينها في الجدول، الأسلوب الأفضل والمتبع في المواقع هو رفع الملفات إلى مجلد عادي وتخزين أسماء الملفات المرفوعة ضمن قاعدة البيانات مع تخزين معلومات أخرى عنها كتاريخ الرفع مثلا. على العموم لن ندخل بهذه التفاصيل الآن على اعتبار أننا لم نتطرق لموضوع قواعد البيانات، سيكون لنا عودة لمناقشة كيفية رفع الملفات بأسلوب احترافي في الدروس المتقدمة. ملاحظة: يتم قبول رفع الملفات ذات الأحجام أصغر من 4 ميغابايت ( عد للمثال الأول وحاول رفع ملف أكبر من هذا الحجم لترى عدم قبول العملية )، ولتغيير الحجم الأقصى المسموح به لكل ملف، نفتح الملف Web.config ونضيف كود السطر الرابع: كود XML <configuration> <system.web> <compilation debug="true" targetFramework="4.0"/> <httpRuntime maxRequestLength="10240"/> </system.web> </configuration> حيث تم تحديد الحجم الأعظمي بـ 10240 كيلو بايت ( أي 10 ميغا بايت ).
  14. شكرا لك عبد الرحمان تم تصحيح رابط الفيديو العفو، بالنسبة مررت على بعض الأخطاء المطبعية، كــ: جميع هذه الخطوات يمكن أتمتتها (أتِمتُها) أيضًا: فأنصحك بمشاهدة الفيديو التالية (التالي). لم يُؤثرا على الشكل العام للمقال فيديو كلمة مؤنثة، اعتمدنا هذا في المجلة التقنية وهنا بالنسبة ﻷتمتة، فهي في ظني صحيحة، راجع: https://ar.wikipedia.org/wiki/أتمتة هل لك دليل على هذا التشكيل؟
  15. شكرا لك عبد الرحمان تم تصحيح رابط الفيديو
  16. قمنا في الدرس السابق من سلسلة "مدخل إلى ASP.NET" بالتعرف على كيفية إرسال بيانات النماذج إلى الخادوم بواسطة أدوات الأزرار المتنوعة. سنقوم في هذا الدرس بالتعرف على أداتين لعرض الصور في ASP.NET. منصة عمل ASP.NET تقدم أداتين لعرض الصور وهي Image وImageMap. تقوم أداة التحكم Image بعرض الصور بأسلوب بسيط، في حين أن الأداة ImageMap تقدم مزايا أكثر تعقيدا، سنتعرف على كلا الأداتين في الفقرات التالية. استخدام أداة التحكم Image تستخدم أداة التحكم Image لعرض صورة محددة عبر الخاصية ImageUrl، سنتعرف على بعض بعض خصائص هذه الأداة ثم نطبق مثال عليها. خصائص أداة التحكم Image: AlternateText: نص بديل يتم عرضه في حال عدم عرض الصورة المحددة. DescriptionUrl: لتحديد رابط إلى صفحة تحتوي تفاصيل عن الصورة. GenerateEmptyAlternateText: إسناد سلسلة فارغة كنص بديل للصورة. ImageAlign: تحديد موقع الصورة بالنسبة لأدوات html أخرى ويمكن أن تأخذ إحدى القيم التالية: AbsBottom ،AbsMiddle ،Baseline ،Bottom ،Left ،Middle ،NotSet ،Right ،TextTop ،Top. ImageUrl: لتحديد مسار واسم الصورة التي سيتم عرضها. مثال: سنقوم في المثال التالي بجعل أداة Image تقوم بعرض واحدة من ثلاث صور وبشكل عشوائي، أنشئ صفحة جديدة وأضف عليها أداة Image، أنشئ ضمن المشروع مجلد جديد باسم images أضف عليه ثلاث صور ولتكن أسماؤها pic1 ،pic2 ،pic3 افتح ملف الكود الخلفي أي الصفحة Default.aspx.cs وفي حدث تحميل الصفحة (Page_Load) اكتب الكود التالي: كود #C protected void Page_Load(object sender، EventArgs e) { Random rnd = new Random(); switch (rnd.Next(3)) { case 0: Image1.ImageUrl = "~/images/pic1.png"; Image1.AlternateText = "picture1"; break; case 1: Image1.ImageUrl = "~/images/pic2.png"; Image1.AlternateText = "picture2"; break; case 2: Image1.ImageUrl = "~/images/pic3.png"; Image1.AlternateText = "picture3"; break; } } كود VB Protected Sub Page_Load(ByVal sender As Object، ByVal e As EventArgs) Handles Me.Load Dim rnd As New Random() Select Case rnd.[Next](3) Case 0 Image1.ImageUrl = "~/images/pic1.bmp" Image1.AlternateText = "picture1" Exit Select Case 1 Image1.ImageUrl = "~/images/pic2.jpg" Image1.AlternateText = "picture2" Exit Select Case 2 Image1.ImageUrl = "~/images/pic3.bmp" Image1.AlternateText = "picture3" Exit Select End Select End Sub نفذ الصفحة السابقة ليتم عرض إحدى الصور الثلاث، اضغط على زر تحديث الصفحة (أو F5) ليتم عرض صورة أخرى وبشكل عشوائي. مماسبق نلاحظ مدى بساطة التعامل مع أداة التحكم Image، في الفقرة التالية سنتعرف على أداة تستخدم أيضا لعرض الصور ولكن بخيارات ومزايا أكثر تنوعا ً. استخدام أداة التحكم ImageMap تستخدم هذه الأداة لعرض صورة ما بالإضافة لربطها مع خريطة غير مرئية، بمعنى آخر عند نقر المستخدم على أجزاء مختلفة من الصورة فبإمكاننا الاستجابة بردود فعل مختلفة أيضا بحسب إحداثيات موقع النقر على الصورة، وعلى هذا الأساس فبإمكاننا استخدام هذه الأداة كوسيلة للتنقل بين الصفحات مثلا ً، حيث نقوم بعرض صورة تحتوي على رسومات معبرة عن صفحات تالية ثم نحدد عند النقر على موقع ما من هذه الصورة الصفحة التي سيتم الإنتقال لها، استخدام آخر لهذه الأداة هو تحديد دخل المستخدم حيث بإمكاننا عرض صورة تحتوي على منتجات عديدة ويكون خيار المستخدم بحسب المنتج الذي تم الضغط عليه على الصورة. أداة التحكم ImageMap ترتبط تلقائيا مع صف HotSpot class والذي يسمح بتحديد مناطق قابلة للنقر على الأداة ImageMap، منصة العمل ASP.Net تقدم ثلاثة صفوف من النمط HotSpot بإمكاننا التعامل معها وهي: CircleHotSpot: تمكننا من تحديد منطقة دائرية على خريطة الصورة. PolygonHotSpot: تمكننا من تحديد شكل غير منتظم على خريطة الصورة. RectangleHotSpot: تمكننا من تحديد منطقة مستطيلة على خريطة الصورة. خصائص أداة التحكم ImageMap: AccessKey: لتحديد مفتاح من لوحة المفاتيح عند الضغط عليه يتم نقل التركيز لهذه الأداة. AlternateText: نص بديل يتم عرضه في حال عدم عرض الصورة المحددة. DescriptionUrl: لتحديد رابط إلى صفحة تحتوي تفاصيل عن الصورة. GenerateEmptyAlternateText: إسناد سلسلة فارغة كنص بديل للصورة. HotSpotMode: تحديد السلوك الذي سيتم تنفيذه عند الضغط على منطقة من الصورة وتأخذ إحدى القيم التالية: Inactive ،Navigate ،NotSet ،PostBack. HotSpots: تكمننا من الحصول على جميع النقاط الساخنة (HotSpots) الموجودة ضمن أداة التحكم ImageMap. ImageAlign: تحديد موقع الصورة بالنسبة لأدوات html أخرى ويمكن أن تأخذ إحدى القيم التالية: AbsBottom ،AbsMiddle ،Baseline ،Bottom ،Left ،Middle ،NotSet، Right ،TextTop ،Top. ImageUrl: لتحديد مسار واسم الصورة التي سيتم عرضها. TabIndex: تحديد رقم يدل على ترتيب الوصول لهذه الأداة عبر مفتاح Tab. Target: تسمح لنا بفتح الصفحة في نافذة جديدة. أداة التحكم ImageMap تدعم الطريقة Focus التي تسمح بوضع التركيز عليها عند التنفيذ، كما أنها تدعم الحدث Click والذي يتم إطلاقه عند الضغط على منطقة من هذه الأداة وكانت الخاصية HotSpotMode تأخذ القيمة PostBack. مثال: سنقوم في المثال بعرض كيفية استخدام أحد جوانب أداة التحكم ImageMap، حيث سنقوم بإنشاء قائمة للتنقل بين صفحات مختلفة، أنشئ مشروع جديد وأضف أربع صفحات ولتكن أسماؤها Dafault، page1 ،page2 ،page3. أضف على الصفحة Default أداة ImageMap واجعلها تعرض صورة مناسبة للغرض السابق. حيث سنقوم بتقسيم أداة الصورة السابقة إلى ثلاث مناطق وكل منطقة تنقلنا إلى صفحة محددة. كود صفحة Default.aspx: كود ASP.net <div> <asp:ImageMap ID="ImageMap1" runat="server" ImageUrl="~/images/navigationBar.jpg"> <asp:RectangleHotSpot NavigateUrl="~/page1.aspx" Left="0" Top="0" Right="100" Bottom="30" AlternateText="go to page1" /> <asp:RectangleHotSpot NavigateUrl="~/page2.aspx" Left="100" Top="0" Right="200" Bottom="30" AlternateText="go to page2" /> <asp:RectangleHotSpot NavigateUrl="~/page3.aspx" Left="200" Top="0" Right="300" Bottom="30" AlternateText="go to page3" /> </asp:ImageMap> </div> نلاحظ من الكود السابق أن للخاصية RectangleHotSpot الخصائص الفرعية Left ،Right ،Top ،Bottom لنحدد إحداثيات المنطقة (حجم الصورة في المثال 300x30). وكل منطقة تم ربطها بصفحة معينة عبر الخاصية NavigateUrl ليتم نقل المتصفح إليها عند النقر على تلك المنطقة. مثال آخر: بعد أن تعرفنا على كيفية استخدام الأداة ImageMap للتنقل بين الصفحات المختلفة، سنعرض هنا آلية العمل مع PostBack أي البقاء ضمن نفس الصفحة، أضف صفحة جديدة وأضف عليها TextBox وImageMap، الصورة المطلوبة ليتم عرضها. المطلوب تنفيذه هو أنه عند الضغط المنطقة الأولى (ToUpper) يتم تحويل النص المكتوب في أداة TextBox إلى حالة أحرف كبيرة، وعند الضغط المنطقة الثانية (ToLower) يتم تحويل النص المكتوب في أداة TextBox إلى حالة أحرف صغيرة، ويؤدي الضغط على المنطقة الثالثة إلى مسح (Erase) النص الموجدود في الأداة TextBox، انقر على الأداة ImageMap مرتين وأضف الكود التالي: كود #C protected void ImageMap1_Click(object sender، ImageMapEventArgs e) { switch (e.PostBackValue) { case "ToUpper": TextBox1.Text = TextBox1.Text.ToUpper(); break; case "ToLower": TextBox1.Text = TextBox1.Text.ToLower(); break; case "Erase": TextBox1.Text = String.Empty; break; } } كود VB Select Case e.PostBackValue Case "ToUpper" TextBox1.Text = TextBox1.Text.ToUpper() Exit Select Case "ToLower" TextBox1.Text = TextBox1.Text.ToLower() Exit Select Case "Erase" TextBox1.Text = [String].Empty Exit Select End Select في الكود السابق استقبلنا الخاصية PostBackVlaue والتي يتم تحديد قيمتها بحسب المنطقة التي يتم الضغط عليها في الأداة ImageMap كما سنرى، كود الصفحة: كود ASP.net <div> <asp:ImageMap ID="ImageMap1" runat="server" HotSpotMode="PostBack" ImageUrl="~/images/textCase.jpg" onclick="ImageMap1_Click"> <asp:RectangleHotSpot PostBackValue="ToUpper" Left="0" Top="0" Right="100" Bottom="30" AlternateText="ToUpper" /> <asp:RectangleHotSpot PostBackValue="ToLower" Left="100" Top="0" Right="200" Bottom="30" AlternateText="ToLower" /> <asp:RectangleHotSpot PostBackValue="Erase" Left="200" Top="0" Right="300" Bottom="30" AlternateText="Erase" /> </asp:ImageMap> <br /> <asp:TextBox ID="TextBox1" runat="server" TextMode="MultiLine" /> </div> نلاحظ في الكود السابق تحديد الخاصية HotSpotMode إلى القيمة PostBack، وفي كل منطقة ساخنة تم تحديد قيمة مختلفة للخاصية PostBackValue لتمييز المنطقة التي تم النقر عليها. استخدام أداة التحكم Panel تمكننا هذه الأداة من التعامل مع مجموعة أدوات ASP.Net دفعة واحدة، حيث يتم تطبيق سلوك ما على جميع أدوات التحكم الموجودة ضمن أداة Panel، على سبيل المثال لو تم إخفاء أداة التحكم هذه فسيختفي معها جميع الأدوات المحتوات ضمنها وكذلك لو تم إلغاء تفعيل أداة Panel فسيتم إلغاء تفعيل جميع أدوات التحكم الموجودة ضمنها وهكذا. خصائص أداة التحكم Panel: DefaultButton: تمكننا هذه الخاصية من تحديد زر افتراضي ضمن الأداة Panel بيحث يتم تنفيذ الكود داخله بمجرد الضغط على مفتاح Enter من لوحة المفاتيح. Direction: تحديد اتجاه النص والأدوات ضمن Panel يمكن أن تأخذ إحدى القيم التالية NotSet ،LeftToRight ،RightToLeft. GroupingText: تحديد عنوان لأداة Panel. HorizontalAlign: تحديد المحاذاة الأفقية لمحتويات أداة Panel ويمكن أن تأخذ إحدى القيم التالية NotSet ،Justify ،Left ،Center ،Right. ScrollBars: تمكننا من إظهار شريط تمرير أفقي أو عمودي (أو كلاهما) لأداة Panel وتأخذ إحدى القيم التالية None ،Horizontal ،Vertical ،Both ،Auto. مثال: سنقوم في التطبيق التالي بإضافة Panel ومن ثم نضف إليها مجموعة من أدوات التحكم المختلفة لنرى أن تطبيق أمر ما على Panel سيتم تطبيقه على الأدوات داخلها أيضا ً، أنشئ صفحة جديدة، أضف أداة تحكم Panel وضع داخلها مجموعة من أدوات التحكم ثم ضع زر واحد خارجها وليكن كود الصفحة شبيه بالآتي: كود ASP.net <div> <asp:Panel id="pnlContact" GroupingText="Contact Information" Runat="server"> <asp:Label id="lblFirstName" Text="First Name:" AssociatedControlID="txtFirstName" Runat="server" /> <br /> <asp:TextBox id="txtFirstName" AutoCompleteType="FirstName" Runat="server" /> <br /><br /> <asp:Label id="lblLastname" Text="Last Name:" AssociatedControlID="txtLastName" Runat="server" /> <br /> <asp:TextBox id="txtLastName" AutoCompleteType="LastName" Runat="server" /> <br /><br /> <asp:Button id="btnSubmit" Text="Submit" Runat="server" /> </asp:Panel> <br /> <asp:Button ID="Button1" runat="server" Text="Visible" onclick="Button1_Click" /> </div> أما الكود الذي يتم إضافته لحدث الضغط على الزر Button1 فهو: كود #C protected void Button1_Click(object sender، EventArgs e) { pnlContact.Visible = !pnlContact.Visible; } كود VB Protected Sub Button1_Click(ByVal sender As Object، ByVal e As EventArgs) pnlContact.Visible = Not pnlContact.Visible End Sub نفذ التطبيق السابق لترى تأثير خصائص الأداة Panel على محتوياتها. إذا تعمل أداة التحكم Panel على تجميع أدوات التحكم ذات وظيفة أو صفات مشتركة يحددها أسلوب العمل في مجموعات، بغرض تنظيم الصفحة والاستفادة من المزايا التي تقدمها هذه الأداة.
  17. قمنا في الدرس السابق من سلسلة "مدخل إلى ASP.NET" بالتعرف على عناصر التحكم الأساسية المضمنة في منصة العمل ASP.NET. في هذا الدرس سنتعرف على كيفية إرسال بيانات النماذج إلى الخادوم بواسطة أدوات الأزرار المتنوعة. تزودنا منصة عمل ASP.Net بثلاث أدوات لإرسال بيانات النموذج إلى الخادوم وهي Button ،LinkButton ،ImageButton وهم يؤدون نفس الوظيفة ولكن لكل منهم مظهر وبعض الخصائص التي تميزه عن غيره. استخدام أداة التحكم Button تقوم هذه الأداة عند النقر عليها بإرسال بيانات الصفحة إلى الخادوم لتتم معالجتها كما يتم تنفيذ الكود الموجود ضمن الحدث Click الخاص بهذه الأداة، يقوم المثال التالي بعرض الوقت الحالي في أداة Label عند النقر على الزر Button، أنشئ صفحة جديدة أضف لها Button وLabel اضغط على الزر مرتين واكتب الكود التالي: كود #C protected void Button1_Click(object sender، EventArgs e) { Label1.Text = DateTime.Now.ToString("T"); } كود VB Protected Sub Button1_Click(ByVal sender As Object، ByVal e As System.EventArgs) Handles Button1.Click Label1.Text = DateTime.Now.ToString("T") End Sub كود الصفحة كاملا ً: كود ASP.net <div> <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" /> <br /> <asp:Label ID="Label1" runat="server" Text="" /> </div> لاحظ عند الضغط على الزر يتم إعادة تحميل الصفحة بالكامل حيث تم إرسالها للخادوم وقام بعملية المعالجة المطلوبة ثم أعادة النتيجة للمستخدم. خصائص أداة التحكم Button AccessKey: لتحديد مفتاح من لوحة المفاتيح عند الضغط عليه يتم نقل التركيز لهذه الأداة. CommandArgument: تحديد متغير يتم إرساله إلى الحدث Command. CommandName: تحديد اسم الأمر الذي يتم إرساله إلى الحدث Command. Enabled: تفعيل أو إلغاء تفعيل هذه الأداة. OnClientClick: لتحديد كود يتم تنفيذه على جهاز المستخدم عند الضغط على الزر. PostBackUrl: للإنتقال إلى صفحة معينة بعد إرسال البيانات إلى الخادوم. TabIndex: تحديد رقم يدل على ترتيب الوصول لهذه الأداة عبر مفتاح Tab. Text: تحديد النص الذي يظهر على هذه الأداة. UseSubmitBehavior: تمكننا من استخدام الجافا سكربت لإرسال بيانات النموذج. أداة التحكم Button تدعم الطريقة Focus التي تسمح بوضع التركيز عليها عند التنفيذ، كما أنها تدعم الحدثين: Click: يتم إطلاقه عند الضغط على الزر. Command: يتم إطلاقه عند الضغط على الزر، ويتم تمرير CommandArgument وCommandName إلى هذا الحدث. استخدام أداة التحكم LinkButton تؤدي نفس عمل الأداة Button ولكنها تختلف من حيث المظهر فهي تبدو كرابط وليس كزر وبالتالي يمكن تحديد صفحة للانتقال إليها عبر هذه الأداة، لنقم بتنفيذ نفس المثال السابق ولكن نستبدل الأداة Button بالأداة LinkButton، الكود الذي يتم تنفيذه عند الضغط على LinkButton: كود #C protected void LinkButton1_Click(object sender، EventArgs e) { Label1.Text = DateTime.Now.ToString("T"); } كود VB Protected Sub LinkButton1_Click(ByVal sender As Object، ByVal e As System.EventArgs) Handles LinkButton1.Click Label1.Text = DateTime.Now.ToString("T") End Sub كود الصفحة: كود ASP.net <div> <asp:LinkButton ID="LinkButton1" runat="server" onclick="LinkButton1_Click">LinkButton</asp:LinkButton> <br /> <asp:Label ID="Label1" runat="server" Text="" /> </div> تقوم الأداة LinkButton وبشكل غير مرئي بتنفيذ كود جافا سكربت وعلى وجه التحديد يتم تنفيذ الطريقة doPostBack_ وهو المسؤول عن إرسال البيانات إلى الخادوم، في مثالنا السابق فإن الكود يبدو كالتالي: كود ASP.net <a id="LinkButton1" href="javascript:__doPostBack(‘LinkButton1’،’’)">Submit</a> خصائص أداة التحكم LinkButton AccessKey: لتحديد مفتاح من لوحة المفاتيح عند الضغط عليه يتم نقل التركيز لهذه الأداة. CommandArgument: تحديد متغير يتم إرساله إلى الحدث Command. CommandName: تحديد اسم الأمر الذي يتم إرساله إلى الحدث Command. Enabled: تفعيل أو إلغاء تفعيل هذه الأداة. OnClientClick: لتحديد كود يتم تنفيذه على جهاز المستخدم عند الضغط على هذه الأداة. PostBackUrl: للإنتقال إلى صفحة معينة بعد إرسال البيانات إلى الخادوم. TabIndex: تحديد رقم يدل على ترتيب الوصول لهذه الأداة عبر مفتاح Tab. Text: تحديد النص الذي يظهر على هذه الأداة. أداة التحكم LinkButton تدعم الطريقة Focus التي تسمح بوضع التركيز عليها عند التنفيذ، كما أنها تدعم الحدثين: Click: يتم إطلاقه عند الضغط على هذه الأداة. Command: يتم إطلاقه عند الضغط على الأداة، ويتم تمرير CommandArgument وCommandName إلى هذا الحدث. استخدام أداة التحكم HyperLink تعد هذه الأداة الطريقة الأكثر شيوعا ًوبساطة للتنقل بين الصفحات المختلفة، وعلى النقيض من الأداة LinkButton فهي لاتقوم بإرسال البيانات إلى السيرفر. خصائص أداة التحكم HyperLink: Enabled: تفعيل أو إلغاء تفعيل هذه الأداة. ImageUrl: لتحديد مسار واسم صورة ليتم عرضها كرابط. NavigateUrl: تحديد عنوان URL يتم الانتقال إليه عند الضغط على هذه الأداة. Text: تحديد النص الذي يظهر على هذه الأداة. Target: تمكننا من فتح صفحة الرابط في نافذة جديدة بالمستعرض. ملاحظة : لو تم تحديد قيم للخاصيتين Text و ImageUrl معا ً، عندئذ سيتم عرض الصورة لأن أولويتها أعلى ولن يتم عرض النص المحدد بالخاصية Text. مثال: أنشئ صفحة جديدة، أضف أداة HyperLink وحدد خصائصها كالتالي: كود ASP.net <div> <asp:HyperLink ID="HyperLink1" runat="server" ImageUrl="~/images/img.png" NavigateUrl="~/Default14.aspx">Go to Page Defaul14 page </asp:HyperLink> </div> نفذ الصفحة السابقة ولاحظ عدم ظهور النص Go to Page Defaul14 page إنما ظهرت الصورة المحددة فقط. استخدام أداة التحكم ImageButton تؤدي نفس وظيفة الأداتين السابقتين حيث تقوم بإرسال بيانات النموذج إلى الخادوم وتظهر كصورة على صفحة الانترنت، لنتعرف بداية ًعلى خصائص هذه الأداة ثم نطبق مثال توضيحي. خصائص أداة التحكم ImageButton: AccessKey: لتحديد مفتاح من لوحة المفاتيح عند الضغط عليه يتم نقل التركيز لهذه الأداة. AlternateText: نص بديل يتم عرضه في حال عدم عرض الصورة المحددة. DescriptionUrl: لتحديد رابط إلى صفحة تحتوي تفاصيل عن الصورة. CommandArgument: تحديد متغير يتم إرساله إلى الحدث Command. CommandName: تحديد اسم الأمر الذي يتم إرساله إلى الحدث Command. Enabled: تفعيل أو إلغاء تفعيل هذه الأداة. ImageAlign: تحديد موقع الصورة بالنسبة لأدوات html أخرى ويمكن أن تأخذ إحدى القيم التالية: AbsBottom ،AbsMiddle ،Baseline ،Bottom ،Left ،Middle ،NotSet، Right ،TextTop ،Top. ImageUrl: لتحديد مسار واسم الصورة التي سيتم عرضها. OnClientClick: لتحديد كود يتم تنفيذه على جهاز المستخدم عند الضغط على هذه الأداة. PostBackUrl: للإنتقال إلى صفحة معينة بعد إرسال البيانات إلى الخادوم. TabIndex: تحديد رقم يدل على ترتيب الوصول لهذه الأداة عبر مفتاح Tab. أداة التحكم ImageButton تدعم الطريقة Focus التي تسمح بوضع التركيز عليها عند التنفيذ، كما أنها تدعم الحدثين: Click: يتم إطلاقه عند الضغط على هذه الأداة. Command: يتم إطلاقه عند الضغط على الأداة، ويتم تمرير CommandArgument وCommandName إلى هذا الحدث. مثال: سنقوم في المثال التالي بتحديد إحداثيات مكان ضغط المستخدم على الأداة ImageButton. أنشئ صفحة جديدة ضع فيها أداة ImageButton واجعلها تعرض صورة ما عبر الخاصية ImageUrl ثم أضف أداتي Label، اضغط على ImageButton مرتين واكتب الكود التالي: كود #C protected void ImageButton1_Click(object sender، ImageClickEventArgs e) { Label1.Text = "X = " + e.X.ToString(); Label2.Text = "Y = " + e.Y.ToString(); } كود VB Protected Sub ImageButton1_Click(ByVal sender As Object، ByVal e As System.Web.UI.ImageClickEventArgs) Handles ImageButton1.Click Label1.Text = "X = " + e.X.ToString() Label2.Text = "Y = " + e.Y.ToString() End Sub كود الصفحة: كود ASP.net <div> <asp:ImageButton ID="ImageButton1" runat="server" ImageUrl="~/images/img.png" onclick="ImageButton1_Click" /> <br /> <asp:Label ID="Label1" runat="server" Text=""/> <asp:Label ID="Label2" runat="server" Text=""/> </div> ملاحظة: عند التعامل مع أي أداة تقوم بعرض الصور ينصح بشدة أن نستخدم الخاصية AlternateText لتقوم بعرض نص بديل فبعض المستخدمين يلغون خيار عرض الصور في المتصفح بهدف الحصول على سرعة أكبر في التصفح. إرسال البيانات عبر الصفحات بشكل افتراضي، عند الضغط على زر ما في الصفحة، يتم إرسالها إلى الخادوم ومعالجة البيانات ثم عرضها على نفس الصفحة، أي يحدث إعادة تحميل للصفحة ببيانات معدلة، الآن سنتعلم كيف نجعل الخادوم يعيدنا إلى صفحة أخرى لعرض النتائج بعد أن نضغط على زر ما في صفحة أولى. مثال: أنشئ صفحة جديدة سمها search.aspx أضف لها TextBox وButton، أعطي الخاصية PostBackUrl القيمة results.aspx وهي صفحة ثانية نقوم بإنشائها، هذه الخاصية كما رأينا سابقا تجعل الخادوم يعيد توجيه المتصفح إلى صفحة محددة عند الضغط على الزر، مانريده من مثالنا هذا أن يقوم المستخدم بإدخال نص ما في TextBox ثم الضغط على الزر ليقوم الخادوم بعرض نفس النص ولكن في صفحة أخرى، كود الصفحة search.aspx: كود ASP.net <div> <asp:TextBox ID="TxtSearch" runat="server"></asp:TextBox> <br /> <asp:Button ID="BtnSearch" runat="server" Text="search" PostBackUrl="~/results.aspx" /> </div> ننتقل الآن إلى الصفحة results.aspx ونضيف عليها فقط أداة Label لنعرض فيها النص المدخل في الصفحة الأولى حيث يكون الكود كالتالي: كود ASP.net <div> <asp:Label ID="LblSearch" runat="server" Text="" /> </div> وفي حدث تحميل الصفحة نكتب الكود التالي: كود #C protected void Page_Load(object sender، EventArgs e) { if (PreviousPage != null) { TextBox txtSearch = (TextBox)PreviousPage.FindControl("TxtSearch"); LblSearch.Text = String.Format("Search for: {0}"، txtSearch.Text); } } كود VB Protected Sub Page_Load(ByVal sender As Object، ByVal e As System.EventArgs) Handles Me.Load If PreviousPage IsNot Nothing Then Dim txtSearch As TextBox = DirectCast(PreviousPage.FindControl("TxtSearch")، TextBox) LblSearch.Text = [String].Format("Search for: {0}"، txtSearch.Text) End If End Sub تحليل الكود السابق: تستخدم الخاصية PreviousPage للحصول على مؤشر للصفحة السابقة التي سببت نقلنا إلى هذه الصفحة، الطريقة FindControl تعيد أداة تحكم محددة وبجميع خصائصها الحالية (ونحن نريد استرجاع قيمة الخاصية Text منها) المتغير الذي تم تمريره هو Id أداة التحكم المطلوبة، ننفذ الكود الصفحة search وندخل نص ما ثم نضغط على الزر لنرى آلية عمل الكود والخاصية PostBackUrl وكيف استطعنا الوصول لبيانات صفحة سابقة من صفحة تالية. ملاحظة: يوجد أساليب أكثر فاعلية لنقل البيانات بين صفحات الموقع مثل Cookies وSession وغيرهم وسنناقشهم بالتفصيل في دروس لاحقة إن شاء الله. تحديد الزر الإفتراضي تسمح هذه الخاصية يتحديد زر في الصفحة بحيث يتم تنفيذ الكود داخله بمجرد الضغط على مفتاح Enter من لوحة المفاتيح ودون الحاجة للضغط على الزر من خلال الماوس، تدعى هذه الخاصية defaultButton ويتم تحديدها كخاصية للنموذج. مثال: أنشئ صفحة جديدة، أضف عليها أداتي Button وأداة Label واحدة، في حدث النقر على الزر الأول اكتب الكود التالي: كود #C protected void Button1_Click(object sender، EventArgs e) { Label1.Text = "you click Button1 "; } كود VB Protected Sub Button1_Click(ByVal sender As Object، ByVal e As System.EventArgs) Handles Button1.Click Label1.Text = "you click Button1 " End Sub وفي حدث النقر على الزر الثاني: كود #C protected void Button2_Click(object sender، EventArgs e) { Label1.Text = "you click Button2 "; } Protected Sub Button2_Click(ByVal sender As Object، ByVal e As System.EventArgs) Handles Button2.Click Label1.Text = "you click Button2 " End Sub الآن نأتي إلى بيت القصيد وهي تحديد الخاصية defaultButton التابعة للفورم وإعطائها كقيمة أحد الزرين السابقين كما في الكود التالي: كود ASP.net <form id="form1" runat="server" defaultbutton="Button2"> <div> <asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" /> <br /> <asp:Button ID="Button2" runat="server" Text="Button" onclick="Button2_Click" /> <br /> <asp:Label ID="Label1" runat="server" Text=""></asp:Label> </div> </form> حيث تم تحديد Button2 كزر افتراضي، نفذ الصفحة واضغط على Enter لترى مايحدث، أعد تنفيذ المثال بعد تعديل الخاصية السابقة وجعلها تساوي القيمة Button1. ملاحظة: يمكن استخدام الخاصية defaultButton مع أداة التحكم Panel، سنتعرف على هذه الأداة بالتفصيل في دروس قادمة. معالجة الحدث Command أدوات التحكم Buttons بأنواعهم الثلاثة يدعمون الحدثين Click و Command كما رأينا سابقا ً، الفرق بين هذين الحدثين هو أنه عند العمل مع Command فبإمكاننا تمرير اسم أمر ما ومتغير للأمر أيضاً وهذه الأمور غير مدعومة مع الحدث Click. مثال توضيحي: أنشئ صفحة جديدة، أضف عليها أداتي Button وأداة Label واحدة، أضف للأداتين Button الخصائص onCommand ،CommandName ،CommandArgument وفق التالي: الخاصية القيمة الأداة Button1 onCommand Button_Command CommandName Colors CommandArgument Red الأداة Button2 onCommand Button_Command CommandName Colors CommandArgument Blue وبالتالي يصبح كود الصفحة: كود ASP.net <div> <asp:Button ID="Button1" runat="server" Text="Red" oncommand="Button_Command" CommandName="colors" CommandArgument="Red"/> <asp:Button ID="Button2" runat="server" Text="Blue" oncommand="Button_Command" CommandName="colors" CommandArgument="Blue"/> <asp:Label ID="Label1" runat="server" Text=""></asp:Label> </div> نفتح ملف الكود الخلفي Default.aspx.cs ونكتب فيه الكود التالي: كود #C protected void Button_Command(object sender، CommandEventArgs e) { if (e.CommandName == "colors") { switch (e.CommandArgument.ToString()) { case "Red": Label1.Text = "RED"; break; case "Blue": Label1.Text = "BLUE"; break; } } } كود VB Protected Sub Button_Command(ByVal sender As Object، ByVal e As CommandEventArgs) If e.CommandName = "colors" Then Select Case e.CommandArgument.ToString() Case "Red" Label1.Text = "RED" Exit Select Case "Blue" Label1.Text = "BLUE" Exit Select End Select End If End Sub لاحظ أن كلا الزرين يقوم باستدعاء نفس الكود Button_Commaen مع تحديد CommandName للقيمة colors والإختلاف الوحيد بينهما هو بالمتغير المرر حيث إن الزر الأول يرسل المتغير Red في حين أن الزر الثاني يرسل المتغير Blue، نفذ الصفحة لترى نتيجة العمل، إن العمل مع الحدث Command فعال عندما تؤدي مجموعة من الأزرار نفس الكود ولكن بمتغيرات مختلفة حيث يوفر علينا عناء إعادة كتابة الكود لو تم استخدام الحدث Click. قمنا في هذا الدرس بالتعرف على ثلاثة أدوات لإرسال بيانات النموذج إلى الخادوم وهي Button ،LinkButton ،ImageButton مع أمثلة لكل منها. سنتعرف في الدرس القادم على أداتين جديدتين لعرض الصور في ASP.NET.
  18. قد يهمك أيضا قراءة هذه المقالات: كيفيّة تنصيب واستخدام Redis على Ubuntuكيفيّة تثبيت وإعداد الذّاكرة المُخبّئة (Memcache) على Ubuntuفبهما معلومات عن طبيعة كلا التقنيتين.
  19. راجع كلا من مقالات "مدخل إلى Bootstrap" و"مدخل إلى تطوير قوالب Wordpress" وستعرف كيفية عمل ذلك إن شاء الله. هناك أيضا مشروع Roots الذي يأتي بقالب Sage، وهو قالب Wordpress قاعدي مبني على إطار عمل bootstrap يمكنك بدورك تحسينه والبناء عليه.
  20. في كثير من الجوانب هو جاهز لتعويض Sublime Text وله مجتمع نشط وعدد إضافات لا بأس به، لكن في نظري لا يزال Sublime Text أخف منهلا يمكنه فتح الملفات التي يفوق حجمها 2Mbوهذا ما يمنعني شخصيا من الإعتماد عليه بشكل يومي أنصحك بتجربته بنفسك وتقييم ما إذا كان يناسب احتياجاتك الشخصية
  21. شخصيا، أرى أنه بإمكانك استعمال Docker بدل Vagrant إذا كنت على لينكس وكذلك فريق العمل (إن لم تكن وحدك) أو إذا كان باقي الفريق غير معني بالأمر. ﻷن لينكس بيئة Docker الأصلية، ولتشغيله على باقي أنظمة التشغيل ستحتاج أصلا إلى Virtual Machine وبالتالي أرى استعمال Vagrant مباشرة في هذه الحالة   والله أعلم...
  22. إذا كنت تستخدم النسخة 3.0.1 فما فوق، يمكنك استعمال الصنف center-block. وهو يُستخدم لتوسيط أي block. <img src="..." class="center-block" /> 
  23. ​لماذا لا تقوم بإنشاء مدونة على Wordpress.com إذا كنت لا تريد الخوض في أمور البرمجة وغيرها؟ يمكنك ربط اسم نطاق خاص، واستعمال قالب مجاني أو شراء قالب خاص أما إذا كنت تريد التحكم بزمام الأمور على استضافة خاصة بك، فلا مجال من التهرب من تعلم كيفية تنصيب ووردبريس وقاعدة بيانات وربطهما، وتعلم كيفية تنصيب قالب خاص يدويا، على الأقل... كخيار آخر، قد يهمك التعرف على static site generators يُمكنك متابعة الدرسين الذين قمت بترجمتهما، ستجد فيهما مثالا حيا للناتج النهائي: http://academy.hsoub.com/code/ruby/مدونتك-الخاصة-باستعمال-jekyll-الجزء-الأول-r39/ http://academy.hsoub.com/code/ruby/مدونتك-الخاصة-باستعمال-jekyll-الجزء-الثاني-r45/
  24. في الجزء الأول من هذا الدرس، قمنا بتغطية كيفية إعداد بيئة تطوير محلية خاصة بك، استعمال إطار عمل CSS وإنشاء منشورات للمدونة. في هذا الجزء سنضيف بعض اللمسات النهائية للصفحة الرئيسية، إضافة شيء من التفاعل، وأخيرًا، نشر المدونة على الويب. فهرس الجزء الثاني من هذا الدرس: مدى التقدّم لحد الآن التصفيح (pagination) التعليقات الأيقونات صفحة 404 المشاركة والشبكات الاجتماعية إحصائيات الزوار الخروج للعلن سَير عمل مُتواصل الناتج النهائي (بالتقريب) لما ستتحصل عليه بعد متابعة كامل الدرس: يُكن أيضا معاينة الناتج النهائي مُباشرة من هنا. مدى التقدم لحد الآنلتلخيص ما تم تغطيته لحد الآن، فيجدر بنا حاليا أن يكون لدينا مدونة Jekyll تشتغل بشكل جيد على حاسوبنا المحلي. مع تنسيق للصفحة الرئيسية، وتنسيق آخر خاص بصفحة المنشور، كذلك يجدر بنا أن نكون الآن قادرين على إنشاء منشور جديد وكتابة محتوى له. هذه المنشورات تُعرض على الصفحة الرئيسية، كلٌ له رابط يصل إلى صفحة المنشور الخاصة به. في ما يلي سنُحسن قليلا من الصفحة الرئيسية لإضافة التصفيح (pagination). التصفيح (pagination)يأتي Jekyll بآلية تصفيح بسيطة يُمكن استعمالها للتحكم بعدد المنشورات التي يجب عرضها على الصفحة الرئيسية في كل مرة. الخطوة الأولى لإضافة التصفيح هي زيادة خيار لملف config.yml_ بالشكل التالي: paginate: 5سيُخبر هذا Jekyll بعرض 5 منشورات فقط في كل مرة. قد تحتاج لإعادة تشغيل Jekyll من خلال سطر الأوامر خاصتك، وذلك عبر إيقافه (Ctrl+c) ثم إعادة تشغيله مُجَدَدًا عبر تنفيذ: Jekyll serve --watchكذلك سيُمرر خيار paginate بعض المعلومات الإضافية لقوالب Liquid التي تستعملها صفحاتنا. يمكننا الاستفادة من هذه المعلومات لإنشاء روابط "التالي" و "السابق" . افتح ملف index.html (الصفحة الرئيسية) وأضف الشفرة التالية في الموضع التي تريد أن تظهر فيه تلك الروابط: <!-- Pagination links --> <nav class="pagination"> {% if paginator.previous_page %} {% if paginator.previous_page == 1 %} <a href="/" class="previous">&laquo;</a> {% else %} <a href="/page" class="previous">&laquo;</a> {% endif %} {% endif %} {% if paginator.next_page %} <a href="/page" class="next ">&raquo;</a> {% endif %} </nav>آلية عمل الشفرة أعلاه بسيطة، فهي فقط تفحص عنصر التصفيح إن كان يحتوي على صفحة تالية أو سابقة، ثم إظهار روابط "السابق" أو "التالي" حسب نتيجة الفحص. يمكن استعمال الشفرة أعلاه في أي صفحة تريد أن تعرض فيها قائمة المنشورات. أما حلقة قائمة المنشورات فهي كالتالي: {% for post in paginator.posts %} ... شفرة قائمة المنشورات ... {% endfor %}باستعمال هذه الحلقة، يمكنك الوصول إلى معلومات المنشور عن طريق post.value حيث value عبارة عن أحد متغيرات frontmatter التي قمنا بتعيينها في أعلى ملف المنشور . مزيد من المعلومات حول Frontmatter. التعليقاتمنصات التدوين مثل Wordpress تأتي بنظام تعليقات ضمني، بما أن المدونة التي نعمل عليها عبارة عن صفحات HTML ثابتة، فليس لدينا هذه الخاصية. لكن هناك بعض الخدمات الرائعة التي تعتمد على Javascript. من أشهر الحلول، نظام تعليقات Disqus. فهو سهل التنصيب، ومُجهّز بأدوات إدارية كاملة للتحكم بالتعليقات، والأروع أنه مجاني. يكفي فقط زيارة موقع الخدمة والنقر على "Add Disqus to your site” ثم تسجيل موقعك. عند إتمام عملية التسجيل ستعطيك الخدمة قُصاصة لشفرة Javascript يمكنك وضعها في أي مكان تريد أن يظهر فيه نظام التعليقات في ملف posts.html، وانتهى الأمر. الأيقوناتإلى هنا، أنهينا الأمور المتعلقة بالمُحتوى وتنسيقه، وقد حان الوقت الآن للاعتناء ببعض التفاصيل الصغيرة التي تُبدي بها مدى اعتنائك بمُدونتك. من ذلك أيقونة المدونة favicon التي تَظهر بجانب العنوان على ألسنة المتصفح أو عند إضافة أحدهم موقعك لمُفضلته. عند إنشاء أيقونة favicon فيجب أن تأخذ في الحسبان أنها أيقونة صغيرة جدا، اختر شيئا يُبرز هوية المدونة، قد يكون ذلك شعار المُدونة أو أحد رُموزها. اسم ملف الأيقونة favicon.ico وهي ذو أبعاد 16 على 16 بكسل. يُمكنك البدء عن طريق إنشاء مُربع صغير على برنامج فوتوشوب أو محررك المُفضل. عادة، من السهل البدء بمُربع أكبر من 16 بكسل (أقترح 500 على 500 بكسل) ثم تصغيره لاحقا. بمُجرد تجميعك لصورة مُعينة، فإن أسرع طريقة لتوليد أيقونة favicon هي عبر رفع التصميم إلى موقع Iconifier. سيقوم الموقع بتصغير الملف المرفوع إلى 16 بكسل وتوليد ملف favicon.ico تلقائيا. ضع هذا الملف في جذر مُجلد مشروع مُدونتك. بعدها، أضف السطر التالي في قسم head لشفرة HTML خاصتك، سيُخبر المتصفح بمكان الأيقونة لجلبها: <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">أيقونات أُخرى من مزايا موقع Iconifier أيضا أنه سيُولد لنا أيقونات أخرى، منها ما هو خاص بأجهزة Apple التي تظهر عند إضافة أحدهم موقعك لشاشة هاتفه مثلا. ستجد أن هناك العديد من أحجام الأيقونات لمختلف الاحتياجات مثل iPad، iPhone .. الخ، هذه الملفات توضع في جذر مُجلد المدونة. صفحة 404قُمنا بتغطية جميع الصفحات المهمة على المدونة لحد الآن، لكن هناك صفحة لا يجب نسيانها، إنها صفحة "صفحة غير موجودة"! يتم عرض هذه الصفحة عندما يكتب أحدهم عنوانا خاطئا على مدونتك أو في حال تم نقل المُحتوى إلى مكان آخر. هدف هذه الصفحة هو مساعدة الزائر وإعلامه أنه وقع على مكان ليس به مُحتوى، واقتراح أمكنة أخرى قد تُهمه أكثر. أنشئ ملفا باسم 404.html في جذر مجلد المدونة. سيقوم Jekyll تلقائيا بعرض هذه الصفحة عندما يزور أحدهم عنوانا خاطئًا. مُحتوى ملف 404.html من الشكل التالي: --- layout: default title: صفحة غير موجودة --- <article> <header id="404"> <h1>صفحة غير موجودة</h1> </header> <section class="entry"> <p>عفوا، لكن يبدو أن هذه الصفحة غير موجودة <a href="/">توجّه إلى الصفحة الرئيسية</a>. </p> </section> </article>بعضهم قد يختار وضع صفحات مَرِحَة أو مُضحكة، أنت حر في تعديل شفرة HTML أعلاه وتخصيصها بما يُناسبك. المُشاركة والشبكات الاجتماعيةيعتمد هذا على رغباتك، لكن قد تود وضع روابط لحساباتك على الشبكات الاجتماعية أو أزرار مشاركة المنشورات، إن كنت تريد كذلك، فقد تودّ الاعتماد على أحد الخدمات المتوفرة مُسبقا، من ذلك خدمة AddThis. سيُتيح لك موقع AddThis تخصيص أزرار الشبكات الاجتماعية وكيفية عرضها، ثم يعطيك قُصاصة شفرة Javascript لزرعها في موقعك، في هذه الحالة، يُمكنك وضعها في ملف default.html مثلا كي تظهر الأزرار في جميع أنحاء المُدونة! إحصائيات الزوارعادة قبل نشر أي موقع، أقوم بإضافة Google Analytics. فهي خدمة جيدة للاطلاع على نسبة الزوار، موقعهم الجغرافي ووقت الزيارة. ستساعدك الخدمة أيضا في معرفة أي من المنشورات لاقى رواجا. لاستعمال Google Analytics يكفي أن يكون لديك حساب Google عبر التسجيل بالموقع، ثم وضع قصاصة شفرة Javascript في قسم head أو في ذيل شفرة HTML. وضع شفرة Google Analytics في قسم head قد يُعيق عملية رسم الصفحة، لذلك أفضّل وضعها أسفل المحتوى، قبل غلق عنصر <body/> حتى يتسنّى للمتصفح تحميل المحتوى أولا وعرضه ثم تحميل Google Analytics تبعا. من المُحبذ أيضا وضع الشفرة في ملف default.html حتى تعمل خوارزمية التعقّب على جميع صفحات المُدونة. الخروج للعلنإذا وصلت لهذا الحد، فأنت مُستعد الآن للكشف عن مدونتك في العلن، ستحتاج -على الخيار- إلى اسم نطاق. إن لم تكن تملك أحدها، قد ترغب في شراء اسم نطاق من أحد مزودي أسماء النطاقات المعتمدين كـ name.com أو hover.com. بعد اختيار اسم نطاق، ستحتاج إلى مكان لتستضيف فيه المُدونة. بما أن Jekyll تم تطوير من طرف أحد مؤسسي موقع Github، يُمكنك استضافة مُدونة Jekyll مجانا على Github pages. و هو الخيار الذي سنعتمد عليه في درسنا هذا. قبل نشر مُدونتك على Github pages، ستحتاج إلى إنشاء ملف باسم CNAME. هذا الملف سيُخبر Github باسم النطاق الذي اخترته للمدونة أو اسم النطاق الفرعي على Github الذي تريده كعنوان ويب للمدونة. بمُجرد إنشاء هذا الملف ووضعه في جذر مجلد العمل، فأنت جاهز الآن لدفع مدونتك لاستضافة Github pages. دفع الملفات إلى Githubستحتاج إلى حساب بموقع Github، بعد تسجيلك في الموقع، أنقر على زر + ثم على خيار "New repository". إذا كانت هذه أول مرة تُنشئ فيها Github page، فإن أبسط طريقة هي أن تسمي مُستودعك (repository) باسم username.github.io حيث username هو اسم المستخدم لحسابك على github. ضع وصفا على الخيار، واترك خيار "public”، لن تحتاج بالضرورة إلى ملف Readme. سيقوم بعدها Github بعرض بعض الإرشادات حول كيفية دفع مشروعك، لكن قبل ذلك، أقترح أن تذهب أولا إلى مجلد مشروعك وحذف مُجلد .git الذي بداخله لمسح مُخلفات Git التي يمكن أن تكون عالقة هناك بسبب استعمالنا قالب بداية Necolas. يمكنك فعل ذلك مباشرة من الطرفية عبر تنفيذ الأمر التالي في مجلد العمل: rm -rf ./.gitيمكنك بعدها اتباع إرشادات Github الخاصة بإنشاء مستودع جديد (initialising new Git repository)، إضافة الخادوم البعيد (remote) للدفع إليه، ثم عمل إيداع. ستحتاج بعدها إلى إضافة جميع ملفات المشروع إلى مستدوع git عبر تنفيذ الأوامر التالية: git add --all git commit -am "Adding all the files" git push origin masterسيُضيف هذا جميع ملفاتك ويدفعها إلى خادوم Github. توجيه اسم النطاق إلى مدونتكبعد إنشاء مستودع Github، سنحتاج إلى توجيه اسم نطاقك إلى مكان استضافة المدونة. ستحتاج إلى إنشاء سِجِل (record) من صنف "A” عند مزود اسم النطاق الخاص بك. Github لديه دليل خاص بهذا لإرشادك حول كيفية ضبط إعدادات DNS. بعد توجيه اسم النطاق ستحتاج إلى مدة انتظار لا تتجاوز 48 ساعة (غالبا ما تكون ساعة أو ساعتين) لتتم عملية الربط بين استضافتك واسم نطاقك، بعدها سيكون لديك مُدونة على الهواء مُباشرة! سير عمل مُتواصلبمُجرد مواصلة عملك على المدونة، يكفي دفع التغيرات التي تجريها إلى Github وستظهر مباشرة على موقع المدونة. سير عمل git قد يحتاج منك بعض الوقت حتى تألفه وتعتاد عليه، لكنه يستحق ذلك. عند انتهائك من ضبط مدونتك وهيكلتها، إضافة منشور جديد ما هو إلا عبارة عن إضافة ملف جديد في مجلد posts_، إضافة معلومات frontmatter ، كتابة مُحتوىً رائع، ثم إضافة الملف الجديد في git ودفعه إلى Github! إلى هنا نصل إلى نهاية كامل الدرس، مُبارك عليك مدونة آمنة، ثابنة، سريعة، قليلة الصيانة، فقط ركزّ على المحتوى! ترجمة -وبتصرف- للمقال Your Own Blog لصاحبه Donovan Hutchinson.
×
×
  • أضف...