1. نظرة عامة
تهدف سلسلة البرامج التعليمية حول Serverless Migration Station (برامج تعليمية ذاتية السرعة وعملية) ومقاطع الفيديو ذات الصلة إلى مساعدة مطوّري الحوسبة بدون خادم على Google Cloud في تحديث تطبيقاتهم من خلال إرشادهم خلال عملية نقل واحدة أو أكثر، مع التركيز بشكل أساسي على التخلّي عن الخدمات القديمة. يؤدي ذلك إلى زيادة قابلية نقل تطبيقاتك ويمنحك المزيد من الخيارات والمرونة، ما يتيح لك الدمج مع مجموعة أكبر من منتجات Cloud والوصول إليها، كما يسهّل عليك الترقية إلى أحدث إصدارات اللغة. على الرغم من أنّ هذه السلسلة تركّز في البداية على أوائل مستخدمي Cloud، وخاصةً مطوّري App Engine (البيئة العادية)، إلا أنّها واسعة النطاق بما يكفي لتشمل منصات أخرى بلا خادم، مثل Cloud Functions وCloud Run، أو في أي مكان آخر إذا كان ذلك منطبقًا.
في بعض الحالات، لا يكون لديك "تطبيق كامل" يتطلّب موارد App Engine أو Cloud Run. إذا كان الرمز يتألف فقط من خدمة مصغّرة أو وظيفة بسيطة، من المرجّح أن تكون Cloud Functions هي الخيار الأفضل. يعلّمك هذا الدرس التطبيقي حول الترميز كيفية نقل تطبيقات App Engine البسيطة (أو تقسيم التطبيقات الأكبر إلى خدمات مصغّرة متعددة) وتفعيلها على Cloud Functions، وهي منصة أخرى للحوسبة بدون خادم تم إنشاؤها خصيصًا لحالات الاستخدام المشابهة.
ستتعرَّف على كيفية إجراء ما يلي:
- استخدام Cloud Shell
- تفعيل Google Cloud Translation API
- مصادقة طلبات البيانات من واجهة برمجة التطبيقات
- تحويل تطبيق صغير على App Engine لتشغيله على Cloud Functions
- نشر الرمز البرمجي في "وظائف السحابة الإلكترونية"
المتطلبات
- مشروع Google Cloud Platform مع حساب فوترة نشط على Google Cloud Platform
- مهارات أساسية في لغة Python
- معرفة عملية بالأوامر الشائعة على نظام التشغيل Linux
- معرفة أساسية بشأن تطوير ونشر تطبيقات App Engine
- تطبيق يعمل على الوحدة 2 من Cloud NDB Python 3 في App Engine
- يُنصح بما يلي: إكمال الدرس التطبيقي حول الترميز للوحدة 2 بالإضافة إلى الخطوة الإضافية لتكييف البرنامج من Python 2 إلى 3
استطلاع
كيف ستستخدم هذا البرنامج التعليمي؟
كيف تقيّم تجربتك مع Python؟
ما هو تقييمك لتجربة استخدام خدمات Google Cloud؟
2. الخلفية
توفّر أنظمة PaaS، مثل Google App Engine وCloud Functions، العديد من الميزات المريحة للمستخدمين. تتيح هذه المنصات التي لا تتطلّب خادمًا لفريقك الفني التركيز على إنشاء حلول للأنشطة التجارية بدلاً من إضاعة الوقت في البحث عن المنصات التي يجب استخدامها وتحديد مقدار الأجهزة المطلوبة. يمكن للتطبيقات أن تتوسّع تلقائيًا حسب الحاجة، وأن تتراجع إلى الصفر مع إمكانية الدفع حسب الاستخدام للتحكّم في التكاليف، كما أنّها تتيح استخدام مجموعة متنوعة من لغات التطوير الشائعة اليوم.
ومع ذلك، على الرغم من أنّ تطوير تطبيقات الويب المتكاملة أو الأنظمة الخلفية المعقّدة للتطبيقات على الأجهزة الجوّالة مناسب تمامًا لخدمة App Engine، غالبًا ما يحاول المطوّرون بشكل أساسي توفير بعض الوظائف على الإنترنت، مثل تعديل خلاصة الأخبار أو الحصول على آخر نتيجة لمباراة فريقك المفضّل. على الرغم من توفّر منطق الترميز لكلا السيناريوهين، لا يبدو أنّ أيًا منهما "تطبيقات" كاملة تتطلّب إمكانات App Engine. وهنا يأتي دور Cloud Functions.
تُستخدَم Cloud Functions لنشر جزء صغير من الرمز البرمجي الذي:
- لا يشكّل جزءًا من تطبيق كامل
- ليست مطلوبة في حزمة تطوير كاملة
- أن يكون في تطبيق أو خلفية تطبيق جوّال واحدة تركّز على شيء واحد
يمكنك أيضًا استخدام Cloud Functions لتقسيم تطبيق كبير ومتكامل إلى عدة خدمات مصغّرة، يستخدم كل منها قاعدة بيانات مشتركة مثل Cloud Firestore أو Cloud SQL. وإذا أردت أن تكون الدالة أو الخدمة المصغّرة في حاوية ويتم تنفيذها بدون خادم على Cloud Run، يمكنك إجراء ذلك أيضًا.
تطبيق App Engine النموذجي الذي تم عرضه في جميع برامج تعليم الهجرة تقريبًا هو تطبيق قصير يتضمّن وظائف أساسية تعمل بشكل جيد تمامًا في Cloud Functions. في هذا البرنامج التعليمي، ستتعرّف على كيفية تعديل هذا التطبيق ليعمل على Cloud Functions. من منظور App Engine، بما أنّ الدوال أبسط من التطبيقات الكاملة، من المفترض أن تكون تجربة البدء أسهل (وأسرع)، وبأقل "تكلفة إضافية" بشكل عام. تتضمّن عملية النقل هذه الخطوات التالية:
- الإعداد/العمل التحضيري
- إزالة ملفات الإعداد
- تعديل ملفات التطبيق
3- الإعداد/العمل التحضيري
يبدأ هذا الدرس التطبيقي حول الترميز بإصدار Python 3 من نموذج تطبيق App Engine في Cloud NDB لأنّ Cloud Functions لا تتوافق مع Python 2. لنبدأ أولاً بإعداد مشروعنا والحصول على الرمز البرمجي، ثم ننشر التطبيق الأساسي للتأكّد من أنّنا نبدأ برمز برمجي يعمل.
1. إعداد المشروع
إذا أكملت برنامج الدرس التطبيقي حول الترميز 2 (وتكييف البرنامج إلى Python 3)، ننصحك بإعادة استخدام المشروع (والرمز البرمجي) نفسه. يمكنك بدلاً من ذلك إنشاء مشروع جديد تمامًا أو إعادة استخدام مشروع حالي آخر. تأكَّد من أنّ المشروع يتضمّن حساب فوترة نشطًا مع تفعيل خدمة App Engine.
2. الحصول على نموذج تطبيق أساسي
من المتطلبات الأساسية لهذا الدرس التطبيقي حول الترميز أن يكون لديك نموذج تطبيق من الوحدة التدريبية 2. إذا لم يكن لديك نموذج، عليك إكمال أحد الأدلة التوجيهية/التعليمية المرتبطَين أعلاه قبل المتابعة هنا. وإذا كنت على دراية بمحتواه، يمكنك البدء بالحصول على رمز الوحدة التدريبية 2 أدناه.
سواء استخدمت الرمز البرمجي الخاص بك أو الرمز البرمجي الذي نوفّره، سنبدأ بالرمز البرمجي الخاص بالوحدة 2 في Python 3. يرشدك هذا الدرس العملي من الوحدة 11 إلى كل خطوة، وينتهي بتوفير رمز برمجي يشبه الرمز الموجود في مجلد مستودع الوحدة 11 (FINISH).
- START: رمز الوحدة 2 (3.x [Module 2b repo folder])
- إنهاء: رمز الوحدة 11 (الإصدار 3.x)
- المستودع بأكمله (لنسخه أو تنزيل ملف ZIP)
يجب أن يبدو دليل ملفات STARTing الخاص بالوحدة 2 من Python 3 (ملفاتك أو ملفاتنا) على النحو التالي:
$ ls README.md main.py templates app.yaml requirements.txt
3- (إعادة) نشر التطبيق الأساسي
في ما يلي الخطوات المتبقية التي يجب تنفيذها الآن:
- التعرّف من جديد على أداة سطر الأوامر
gcloud - إعادة نشر نموذج التطبيق باستخدام
gcloud app deploy - تأكَّد من أنّ التطبيق يعمل على App Engine بدون أي مشاكل
بعد تنفيذ هذه الخطوات بنجاح، ستكون مستعدًا لتحويلها إلى Cloud Function.
4. إزالة ملفات الإعداد
الملف app.yaml هو عنصر App Engine لا يُستخدَم مع Cloud Functions، لذا احذِفه الآن. إذا لم تفعل ذلك أو نسيت، لن يكون هناك أي ضرر لأنّ Cloud Functions لا تستخدمه. هذا هو التغيير الوحيد في الإعدادات، لأنّ requirements.txt يظلّ مطابقًا لما كان عليه في الوحدة 2.
إذا كنت تنقل أيضًا تطبيق Python 2 App Engine إلى Python 3، احذف appengine_config.py والمجلد lib إذا كان لديك واحد. وهي عناصر App Engine غير مستخدَمة في وقت تشغيل Python 3.
5- تعديل ملفات التطبيق
لا يوجد سوى ملف تطبيق واحد، وهو main.py، لذا تحدث جميع التغييرات اللازمة للانتقال إلى Cloud Functions في هذا الملف.
عمليات الاستيراد
بما أنّنا نعمل فقط مع الدوال، لا حاجة إلى إطار عمل لتطبيق الويب. ومع ذلك، لتسهيل الأمر، عند استدعاء دوال Cloud Functions المستندة إلى Python، يتم تلقائيًا تمرير كائن طلب إلى الرمز البرمجي لاستخدامه حسب الحاجة. (اختار فريق Cloud Functions أن يكون كائن طلب Flask يتم تمريره إلى الدالة).
بما أنّ أُطر عمل الويب ليست جزءًا من بيئة Cloud Functions، لا يتم استيراد أي بيانات من Flask إلا إذا كان تطبيقك يستخدم ميزات أخرى من Flask. هذا هو الحال بالفعل، لأنّ عرض النموذج لا يزال يحدث بعد التحويل إلى دالة، ما يعني أنّه لا يزال مطلوبًا استدعاء flask.render_template()، وبالتالي استيراده من Flask. عدم توفّر إطار عمل للويب يعني عدم الحاجة إلى إنشاء مثيل لتطبيق Flask، لذا احذف app = Flask(__name__). يبدو الرمز البرمجي على النحو التالي، قبل تطبيق التغييرات وبعده:
قبل:
from flask import Flask, render_template, request
from google.cloud import ndb
app = Flask(__name__)
ds_client = ndb.Client()
بعد:
from flask import render_template
from google.cloud import ndb
ds_client = ndb.Client()
إذا كنت تعتمد على عنصر التطبيق (app) أو أي بنية أساسية أخرى لإطار عمل الويب، عليك حلّ جميع هذه التبعيات أو العثور على حلول بديلة مناسبة أو إزالة استخدامها بالكامل أو العثور على وكلاء. عندها فقط يمكنك تحويل الرمز البرمجي إلى Cloud Function. في ما عدا ذلك، من الأفضل البقاء على App Engine أو حفظ تطبيقك في حاوية لاستخدام Cloud Run.
تعديل توقيع دالة المعالجة الرئيسية
التغييرات المطلوبة في توقيع الدالة هي كما يلي:
- لم يعُد يتم استخدام Flask بعد تحويل التطبيق إلى Cloud Function، لذا عليك إزالة أدوات تزيين المسارات.
- تمرِّر Cloud Functions تلقائيًا العنصر
RequestFlask كمعلَمة، لذا أنشئ متغيرًا له. في نموذج تطبيقنا، سنسمّيهrequest. - يجب تسمية دوال Cloud Functions التي تم نشرها. تمت تسمية المعالج الرئيسي بشكل مناسب
root()في App Engine لوصف وظيفته (معالج التطبيق الجذر). وبما أنّها دالة Cloud، لا يبدو من المنطقي استخدام هذا الاسم. بدلاً من ذلك، سنفعّل Cloud Function بالاسمvisitme، لذا استخدِم هذا الاسم أيضًا كاسم لدالة Python. وبالمثل، في الوحدتين 4 و5، أطلقنا أيضًا على خدمة Cloud Run الاسمvisitme.
في ما يلي التغييرات التي ستظهر قبل هذه التعديلات وبعدها:
قبل:
@app.route('/')
def root():
'main application (GET) handler'
store_visit(request.remote_addr, request.user_agent)
visits = fetch_visits(10)
return render_template('index.html', visits=visits)
بعد:
def visitme(request):
'main application (GET) handler'
store_visit(request.remote_addr, request.user_agent)
visits = fetch_visits(10)
return render_template('index.html', visits=visits)
هذا كل ما يلزم من تحديثات. يُرجى العِلم أنّ التغييرات التي تم إجراؤها أثّرت فقط في رمز "البنية الأساسية" للتطبيق. لا يلزم إجراء أي تغييرات في الرمز البرمجي الأساسي للتطبيق، ولم يتم تعديل أي من وظائف التطبيق. في ما يلي تمثيل صوري للتغييرات التي تم إجراؤها لتوضيح هذه النقطة:

التطوير والاختبار على الجهاز
في حين أنّ App Engine يتضمّن dev_appserver.py خادم تطوير محلي، تتضمّن Cloud Functions إطار عمل الوظائف. باستخدام إطار العمل هذا، يمكنك تطوير التطبيقات واختبارها محليًا. يمكن نشر الرمز البرمجي على Cloud Functions، ولكن يمكن أيضًا نشره على منصات حوسبة أخرى، مثل Compute Engine أو Cloud Run أو حتى على أنظمة السحابة الإلكترونية المحلية أو المختلطة التي تتوافق مع Knative. يمكنك الاطّلاع أدناه على روابط إضافية إلى Functions Framework.
6. التطوير والنشر
يختلف النشر في Cloud Functions قليلاً عن النشر في App Engine. بما أنّه لا يتم استخدام أي ملفات إعداد خارج requirements.txt، يجب تحديد المزيد من المعلومات حول الرمز البرمجي في سطر الأوامر. يمكنك نشر Cloud Function الجديدة التي يتم تشغيلها باستخدام Python 3.10 والتي يتم تشغيلها من خلال HTTP باستخدام الأمر التالي:
$ gcloud functions deploy visitme --runtime python310 --trigger-http --allow-unauthenticated
توقَّع ناتجًا مشابهًا لما يلي:
Deploying function (may take a while - up to 2 minutes)...⠛ For Cloud Build Logs, visit: https://console.cloud.google.com/cloud-build/builds;region=REGION/f5f6fc81-1bb3-4cdb-8bfe?project=PROJECT_ID Deploying function (may take a while - up to 2 minutes)...done. availableMemoryMb: 256 buildId: f5f6fc81-1bb3-4cdb-8bfe buildName: projects/PROJECT_ID/locations/REGION/builds/f5f6fc81-1bb3-4cdb-8bfe dockerRegistry: CONTAINER_REGISTRY entryPoint: visitme httpsTrigger: securityLevel: SECURE_OPTIONAL url: https://REGION-PROJECT_ID.cloudfunctions.net/visitme ingressSettings: ALLOW_ALL labels: deployment-tool: cli-gcloud name: projects/PROJECT_ID/locations/REGION/functions/visitme runtime: python310 serviceAccountEmail: PROJECT_ID@appspot.gserviceaccount.com sourceUploadUrl: https://storage.googleapis.com/uploads-853031211983.REGION.cloudfunctions.appspot.com/8c923758-cee8-47ce-8e97-5720a5301c34.zip status: ACTIVE timeout: 60s updateTime: '2022-05-16T18:28:06.153Z' versionId: '8'
بعد نشر الدالة، استخدِم عنوان URL من ناتج النشر وانتقِل إلى تطبيقك. يكون عنوان URL بالتنسيق التالي: REGION-PROJECT_ID.cloudfunctions.net/visitme. يجب أن تكون النتيجة مماثلة للنتيجة التي حصلت عليها عند نشرها سابقًا على App Engine:

كما هو الحال مع معظم فيديوهات وسلسلة دروس الترميز الأخرى، لن تتغير وظائف التطبيق الأساسية. والغرض من ذلك هو تطبيق إحدى تقنيات التحديث وجعل التطبيق يعمل تمامًا كما كان من قبل ولكن باستخدام بنية أساسية أحدث، مثل الانتقال من خدمة قديمة من App Engine إلى منتج Cloud المستقل البديل، أو، كما هو الحال في هذا الدليل التوجيهي/التعليمي، نقل تطبيق إلى منصة أخرى بلا خادم من Google Cloud.
7. الملخّص/التنظيف
تهانينا على تحويل تطبيق App Engine الصغير هذا إلى Cloud Function. حالة استخدام أخرى مناسبة: تقسيم تطبيق كبير متكامل في App Engine إلى سلسلة من الخدمات المصغّرة، كل منها عبارة عن Cloud Function. هذه تقنية تطوير أكثر حداثة تؤدي إلى إنشاء مكوّن أكثر سهولة في الاستخدام (على غرار حزمة JAM). تتيح هذه البنية إمكانية الدمج والمطابقة وإعادة استخدام الرموز البرمجية، وهما هدفان أساسيان، ولكن من المزايا الأخرى أنّ هذه الخدمات الصغيرة ستستمر في تصحيح الأخطاء بمرور الوقت، ما يعني الحصول على رموز برمجية ثابتة وتكاليف صيانة أقل بشكل عام.
تَنظيم
بعد إكمال هذا الدرس العملي، يمكنك إيقاف تطبيق الوحدة 2 على App Engine (مؤقتًا أو نهائيًا) لتجنُّب تحمّل تكاليف الفوترة. تتضمّن منصة App Engine حصّة مجانية، لذا لن يتم تحصيل رسوم منك ما دمت ضمن مستوى الاستخدام. وينطبق الأمر نفسه على Datastore. لمزيد من التفاصيل، يُرجى الاطّلاع على صفحة أسعار Cloud Datastore.
يؤدي النشر على منصات مثل App Engine وCloud Functions إلى تكبُّد تكاليف بسيطة للإنشاء والتخزين. في بعض المناطق، تتوفر حصة مجانية خاصة بخدمة Cloud Build، كما هو الحال مع خدمة Cloud Storage. تستهلك عمليات الإنشاء بعضًا من هذا الحصة. يجب أن تكون على دراية بمقدار استخدامك لمساحة التخزين للحدّ من التكاليف المحتملة، خاصةً إذا لم تكن منطقتك تتضمّن هذا المستوى المجاني.
لا تتوفّر ميزة "الإيقاف" في Cloud Functions. احتفِظ بنسخة احتياطية من الرمز البرمجي واحذف الدالة فقط. ويمكنك دائمًا إعادة نشره بالاسم نفسه لاحقًا. ومع ذلك، إذا كنت لن تواصل استخدام أي من دروس الترميز الأخرى الخاصة بنقل البيانات وأردت حذف كل شيء نهائيًا، عليك إيقاف مشاريعك على السحابة الإلكترونية.
الخطوات التالية
بالإضافة إلى هذا البرنامج التعليمي، تتضمّن وحدات نقل البيانات الأخرى التي يجب الاطّلاع عليها تحويل تطبيق App Engine إلى حاوية لاستخدامه مع Cloud Run. اطّلِع على روابط الدرس التطبيقي حول الترميز الرابع والدرس التطبيقي حول الترميز الخامس:
- الوحدة 4: نقل البيانات إلى Cloud Run باستخدام Docker
- وضع تطبيقك في حاوية لتشغيله على Cloud Run باستخدام Docker
- تتيح لك عملية النقل هذه البقاء على الإصدار 2 من Python.
- الوحدة 5: نقل البيانات إلى Cloud Run باستخدام Cloud Buildpacks
- وضع تطبيقك في حاوية لتشغيله على Cloud Run باستخدام Cloud Buildpacks
- لا تحتاج إلى معرفة أي شيء عن Docker أو الحاويات أو
Dockerfiles. - يجب أن يكون تطبيقك قد تم نقله إلى Python 3 (لا تتوافق حزم الإنشاء مع Python 2)
تركّز العديد من الوحدات الأخرى على توضيح كيفية نقل البيانات من الخدمات المجمّعة في App Engine إلى البدائل المستقلة في Cloud:
- الوحدة 2: نقل البيانات من App Engine
ndbإلى Cloud NDB - الوحدات من 7 إلى 9: نقل المهام من مهام الدفع في "قائمة انتظار المهام" في App Engine إلى Cloud Tasks
- الوحدتان 12 و13: نقل البيانات من App Engine Memcache إلى Cloud Memorystore
- الوحدتان 15 و16: نقل البيانات من App Engine Blobstore إلى Cloud Storage
- الوحدتان 18 و19: نقل البيانات من "قائمة انتظار المهام" في App Engine (مهام السحب) إلى Cloud Pub/Sub
إذا أصبحت عملية إنشاء الحاويات جزءًا من سير عمل تطوير التطبيقات، خاصةً إذا كانت تتألف من مسار CI/CD (التكامل المستمر/التسليم المتواصل أو النشر المستمر)، ننصحك بنقل التطبيق إلى Cloud Run بدلاً من Cloud Functions. راجِع الوحدة 4 لتضمين تطبيقك في حاوية باستخدام Docker، أو الوحدة 5 لتنفيذ ذلك بدون حاويات أو معرفة بـ Docker أو Dockerfile. سواء كنت تفكّر في استخدام Cloud Functions أو Cloud Run، فإنّ الانتقال إلى منصة أخرى بلا خادم هو أمر اختياري، وننصحك بالاطّلاع على أفضل الخيارات لتطبيقاتك وحالات الاستخدام قبل إجراء أي تغييرات.
بغض النظر عن وحدة النقل التي ستختارها، يمكنك الوصول إلى كل محتوى Serverless Migration Station (الدروس البرمجية والفيديوهات ورمز المصدر [عند توفّره]) من خلال مستودع المصدر المفتوح. يوفّر مستودع README أيضًا إرشادات حول عمليات نقل البيانات التي يجب أخذها في الاعتبار وأي "ترتيب" ذي صلة لوحدات نقل البيانات.
8. مراجع إضافية
مشاكل/ملاحظات حول دروس الترميز التطبيقية الخاصة بوحدة نقل البيانات في App Engine
إذا واجهت أي مشاكل في هذا الدرس العملي، يُرجى البحث عن مشكلتك أولاً قبل إرسالها. روابط للبحث عن مشاكل جديدة وإنشائها:
مراجع لنقل البيانات
يمكنك العثور على روابط لمجلدات المستودع للوحدة التدريبية 8 (البداية) والوحدة التدريبية 9 (النهاية) في الجدول أدناه. يمكن أيضًا الوصول إليها من مستودع جميع عمليات نقل Codelab في App Engine الذي يمكنك استنساخه أو تنزيل ملف ZIP منه.
Codelab | Python 3 |
مراجع متوفرة على الإنترنت
في ما يلي مراجع على الإنترنت قد تكون ذات صلة بهذا البرنامج التعليمي:
App Engine
- مستندات App Engine
- وقت تشغيل Python 2 App Engine (البيئة العادية)
- وقت تشغيل Python 3 App Engine (البيئة العادية)
- الاختلافات بين أوقات تشغيل Python 2 و3 في App Engine (البيئة العادية)
- دليل نقل البيانات من Python 2 إلى Python 3 في App Engine (البيئة العادية)
- معلومات الأسعار والحصص في App Engine
- إطلاق الجيل الثاني من منصة App Engine (2018)
- مقارنة بين الجيل الأول والثاني من المنصات
- الدعم الطويل الأمد لأوقات التشغيل القديمة
- مستودع نماذج نقل المستندات
- مستودع نماذج نقل البيانات التي ساهم بها المنتدى
وظائف السحابة الإلكترونية
- أمر gcloud functions deploy
- معلومات التسعير
- إعلان عن الجيل التالي من Cloud Functions
- الاختلافات بين وظائف الجيل الأول والثاني
- Functions Framework (التطوير المحلي) كيفية الاستخدام و مستندات الاستخدام و المستودع
- صفحات المنتجات
- الوثائق
معلومات أخرى حول السحابة الإلكترونية
- Python على Google Cloud Platform
- مكتبات برامج Python في Google Cloud
- فئة "دائمًا مجانية" في Google Cloud
- Google Cloud SDK (أداة سطر الأوامر
gcloud) - جميع مستندات Google Cloud
الفيديوهات
- Serverless Migration Station
- أداة "استكشافات" بدون خادم
- الاشتراك في قناة Google Cloud Tech
- الاشتراك في Google Developers
الترخيص
يخضع هذا العمل لترخيص المشاع الإبداعي مع نسب العمل إلى مؤلفه 2.0 Generic License.