الفرق بين المراجعتين لصفحة: «Cordova/plugins windows»

من موسوعة حسوب
أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE:إضافات ويندوز في كوردوفا}}</noinclude> تصنيف: Cordova تصنيف: plugins تصنيف: Windows يقد...'
 
لا ملخص تعديل
سطر 3: سطر 3:
[[تصنيف: plugins]]
[[تصنيف: plugins]]
[[تصنيف: Windows]]
[[تصنيف: Windows]]
يقدم هذا القسم تفاصيل عن كيفية تقديم (implement) إضافة لاستخدامها في متجر تطبيقات ويندوز (ويندوز Store app) للهاتف وسطح المكتب ويندوز 8.1، ومنصة ويندوز الكونية (Universal ويندوز ‎Platform [ويندوز 10+]‎‎). قبل قراءة هذه الصفحة، راجع صفحة دليل تطوير الإضافات [../../hybrid/plugins/index.html  Create your first plugin] للحصول على نظرة عامة على بنية الإضافات وواجهة [[JavaScript|[[Java|جافا]]اسكريبت]] الخاصة بها. يستمر هذا القسم في تطوير مثال الإضافة echo الوارد في دليل تطوير الإضافات، والذي يتواصل بين المعرض [[Cordova/webviews|webview]] الخاص بكوردوفا وبين المنصة الأصلية.  
يقدم هذا القسم تفاصيل عن كيفية تقديم (implement) إضافة لاستخدامها في متجر تطبيقات ويندوز للهواتف وسطح المكتب في ويندوز 8.1، ومنصة ويندوز الكونية (Universal Windows [ويندوز 10+]‎‎). قبل قراءة هذه الصفحة، المرجو مراجعة صفحة [[Cordova/plugins|دليل تطوير الإضافات]] .


== إنشاء إضافة ويندوز عبر [[Java|جافا]]اسكريبت ==
للحصول على نظرة عامة على بنية الإضافات وواجهة [[JavaScript|جافاسكريبت]] الخاصة بها. يستمر هذا القسم في تطوير [[Cordova/plugins#.D9.85.D8.AB.D8.A7.D9.84 JavaScript|مثال الإضافة <code>echo</code>]] الوارد في دليل تطوير الإضافات، والذي يربط الاتصال بين المعرض [[Cordova/webviews|webview]] الخاص بكوردوفا وبين المنصة الأصلية.


إضافات ويندوز كوردوفا هي بالأساس أغلفة رقيقة (thin wrapper) حول دوالة مكتبة WinJS، ولكن بفرض أنك ستحتاج إلى تعريف واجهة [[JavaScript|[[Java|جافا]]اسكريبت]] مشتركة لعدة أجهزة، فستحتاج عادةً إلى ملف [[JavaScript|[[Java|جافا]]اسكريبت]] واحد يوفر تلك الواجهة البرمجية (API):  
== إنشاء إضافة ويندوز عبر جافاسكريبت ==
 
إضافات ويندوز كوردوفا هي بالأساس أغلفة رقيقة (thin wrapper) حول دوال المكتبة WinJS، ولكن إن كنت تحتاج إلى تعريف واجهة [[JavaScript|جافاسكريبت]] مشتركة بين عدة أجهزة، فستحتاج عادةً إلى ملف [[JavaScript|جافاسكريبت]] واحد يوفر تلك الواجهة البرمجية (API):  
<syntaxhighlight lang="javascript">// inside file echoplugin.js
<syntaxhighlight lang="javascript">// inside file echoplugin.js
var EchoPlugin = {
var EchoPlugin = {
سطر 17: سطر 19:
}‎</syntaxhighlight>  
}‎</syntaxhighlight>  


يختلف تعريف الدالة <code>cordova.exec</code> من منصة إلى أخرى، وذلك لأن كل منصة لديها طريقتها الخاصة في التواصل بين شيفرة ال[[JavaScript|[[Java|جافا]]اسكريبت]]، والشيفرة الأصلية المُغلّفة (native wrapper code). ولكن في حالة ويندوز، لا يوجد غلاف أصلي، لذلك فاستدعاء exec موجود فقط لأجل توفير واجهة متناسقة. لذلك، على الرغم من أنه يمكنك كتابة الشيفرة البرمجية الخاصة بويندوز كجزء من ملف [[JavaScript|[[Java|جافا]]اسكريبت]] المشترك (الخاص بالإضافة) مباشرةً، إلا أننا لا نوصى بذلك، يجب على مطوري الإضافات استخدام نفس الواجهة البرمجية exec في ويندوز كما في بقية المنصات الأخرى. وبهذه الطريقة تصبح الواجهة البرمجية للإضافات متسقة، ويمكنك أيضًا الاستفادة من أي فحص للوسائط، أو أي الشيفرات الأخرى الشائعة التي يوفرها مطورو البرامج على منصات أخرى.  
يختلف تعريف الدالة <code>cordova.exec</code> من منصة إلى أخرى، وذلك لأن لكل منصة طريقتها الخاصة في التواصل بين شيفرة ال[[JavaScript|جافاسكريبت]]، والشيفرة الأصلية المُغلّفة (native wrapper code). ولكن في حالة ويندوز، لا يوجد غلاف أصلي، لذلك فاستدعاء <code>exec</code> هو فقط لتوفير واجهة متناسقة. لذلك، على الرغم من أنه يمكنك كتابة الشيفرة البرمجية الخاصة بويندوز كجزء من ملف [[JavaScript|جافاسكريبت]] المشترك (الخاص بالإضافة) مباشرةً، إلا أننا لا نوصى بذلك، فيجب على مطوري الإضافات استخدام نفس الواجهة البرمجية <code>exec</code> في ويندوز كما في بقية المنصات الأخرى. وبهذه الطريقة تصبح الواجهة البرمجية للإضافات متسقة، كما يمكنك أيضًا الاستفادة من أي فحص للوسائط، أو أي الشيفرات الأخرى الشائعة التي يوفرها المطورون على المنصات الأخرى.  


على ويندوز، توفر كوردوفا خادمًا وسيطًا (proxy) يمكنك استخدامه لتسجيل كائن معين للتعامل مع جميع استدعاءات cordova.exec في الواجهة البرمجية (API). لذلك في حالتنا، سنفترض أن الشيفرة الموجودة في الملف <code>echoplugin.js</code> ستعالج أكواد [[JavaScript|[[Java|جافا]]اسكريبت]] العابرة للمنصات (cross platform)، ويمكننا ببساطة كتابة خادم وسيطً لنظام ويندوز.  
على ويندوز، توفر كوردوفا خادمًا وسيطًا (proxy) يمكن استخدامه لتسجيل كائن معين يتكلّف بالتعامل مع جميع استدعاءات <code>cordova.exec</code> في الواجهة البرمجية (API). لذلك في حالتنا، سنفترض أن الشيفرة الموجودة في الملف <code>echoplugin.js</code> ستعالج أكواد [[JavaScript|جافاسكريبت]] العابرة للمنصات (cross platform)، وهكذا يمكننا ببساطة كتابة خادمٍ وسيطٍ لنظام ويندوز.  
<syntaxhighlight lang="javascript">// in file echoplugin.js
<syntaxhighlight lang="javascript">// in file echoplugin.js
window.echo = function(str, callback) {
window.echo = function(str, callback) {
سطر 38: سطر 40:
});‎</syntaxhighlight>  
});‎</syntaxhighlight>  


سيعيد الملف <code>echoplugin.js</code> توجيه استدعاء الدالة <code>echo</code> إلى هذا الوكيل الوسيط من خلال الأمر <code>cordova.exec</code> وتنفيذ هذا التقديم (implementation).  
سيعيد الملف <code>echoplugin.js</code> توجيه استدعاء الدالة <code>echo</code> إلى الخادم الوسيط عبر الأمر <code>cordova.exec</code> ثم ينفّذ هذا التقديم (implementation).  


سيحتوي الملف plugin.xml على الإعدادات المطلوبة في الََإضافة. في هذه الحالة، نريد إضافة الملف <code>echoplugin.js</code> في المجلد <code>www</code>، وإضافة الملف <code>echopluginProxy.js</code> داخل الشيفرة المصدرية <code>windows</code> الخاصة بتتطبيقنا. يمكن العثور على مزيد من التفاصيل حول هذه العناصر في المرجع [../../../plugin_ref/spec.html Plugin.xml].  
سيحتوي الملف <code>plugin.xml</code> على الإعدادات المطلوبة في الََإضافة. وفي هذه الحالة، نريد إضافة الملف <code>echoplugin.js</code> في المجلد <code>www</code>، وإضافة الملف <code>echopluginProxy.js</code> داخل الشيفرة المصدرية <code>windows</code> الخاصة بتطبيقنا. يمكن العثور على مزيد من التفاصيل حول هذه العناصر في المرجع <code>[https://cordova.apache.org/docs/en/latest/plugin_ref/spec.html Plugin xml]</code>.  
<syntaxhighlight lang="javascript"><?xml version="1.0" encoding="UTF-8"?>
<syntaxhighlight lang="xml"><?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
     id="echoplugin"
     id="echoplugin"
سطر 55: سطر 57:
     </platform>
     </platform>
     <!-- other platforms -->
     <!-- other platforms -->
</plugin></syntaxhighlight>  
</plugin>‎c</syntaxhighlight>  


هذا يعطينا إضافة ويتدوز-[[JavaScript|[[Java|جافا]]اسكريبت]] تستخدم ملفًا مشتركًا (echoplugin.js) وتستخدم خادمًا وسيطًا لتوفير الأجزاء المخصوصة بويندوز في الملف (echopluginProxy.js). إذن، كيف يمكننا إضافة شيفرة أصلية ومٌدارة (native/managed code) إلى هذا؟ حسنا سنعيد ما فعلناه من قبل، مع فرق وحيد يتمثل في ما سنفعله داخل توابع echopluginProxy.  
سينتج عن هذا إضافة ويندوز-[[JavaScript|جافاسكريبت]] جاهزة، والتي تستخدم ملفًا مشتركًا (<code>echoplugin.js</code>)، وخادمًا وسيطًا لتوفير الأجزاء المخصوصة بويندوز في الملف (<code>echopluginProxy.js</code>). إذن، كيف يمكننا إضافة شيفرة أصلية ومٌدارة (native/managed code) إلى هذا؟ حسنًا، سنعيد ما فعلناه من قبل، الفرق الوحيد هو ما سنفعله داخل توابع <code>echopluginProxy</code>.  


== إنشاء إضافات ويندوز عبر C ++ أو الشيفرة المُدارة (Creating a Windows Plugin in C++ or managed code).==  
== إنشاء إضافات ويندوز في C++أو الشيفرة المُدارة (managed code).==  


في نظام ويندوز، تستطيع تطبيقات [[JavaScript|[[Java|جافا]]اسكريبت]] أن تتداخل مع اللغات الأصلية (C++‎) والشيفرات المُدارة (C#، VB) عن طريق إنشاء مُركّبة (component) في ويندوز تعمل وقت تشغيل. يمكنك تعلم الأساسيات والحصول على مزيد من التفاصيل في مراجع MSDN:  
في نظام ويندوز، تستطيع تطبيقات [[JavaScript|جافااسكريبت]] أن تتداخل مع اللغات الأصلية (C++‎) والشيفرات المُدارة (C#، VB) عن طريق إنشاء مُركّبة (component) في ويندوز تعمل وقت تشغيل. يمكنك تعلم الأساسيات والحصول على مزيد من التفاصيل في مراجع MSDN:  
[https://msdn.microsoft.com/en-us/library/windows/apps/br230301.aspx Creating Windows Runtime Components in C# and Visual Basic]  
[https://msdn.microsoft.com/en-us/library/windows/apps/br230301.aspx Creating Windows Runtime Components in C# and Visual Basic]  
[http://msdn.microsoft.com/en-us/library/windows/apps/hh441569.aspx Creating Windows Runtime Components in C++]  
[http://msdn.microsoft.com/en-us/library/windows/apps/hh441569.aspx Creating Windows Runtime Components in C++]  


عندما تقوم بإنشاء مركبة وقت التشغيل في ويندوز (Windows Runtime Component)، فإن كل الأصناف التي عُرِّفت وفق الصيغة <code>public ref class sealed</code> ستُعد "صنفًا فعالا" (activatable class)، وسيكون قابلًا للاستدعاء من [[JavaScript|[[Java|جافا]]اسكريبت]].  
عندما تقوم بإنشاء مركبة وقت التشغيل في ويندوز (Windows Runtime Component)، فإن كل الأصناف التي عُرِّفت وفق الصيغة <code>public ref class sealed</code> ستُعد "صنفًا فعالا" (activatable class)، وسيكون قابلًا للاستدعاء من [[JavaScript|جافااسكريبت]].  
<syntaxhighlight lang="javascript">// in your header file .h
<syntaxhighlight lang="javascript">// in your header file .h
namespace EchoRuntimeComponent
namespace EchoRuntimeComponent
سطر 107: سطر 109:
});‎</syntaxhighlight>  
});‎</syntaxhighlight>  


وهذا كل شيء، صارت لدينا إضافة ويندوز كوردوفا مع ملف [[JavaScript|[[Java|جافا]]اسكريبت]] قابل للاستدعاء ومربوط ومدعوم بملف C++‎.  
وهذا كل شيء، صارت لدينا إضافة ويندوز كوردوفا مع ملف [[JavaScript|جافااسكريبت]] قابل للاستدعاء ومربوط ومدعوم بملف C++‎.  
=== اعتبارات ===  
=== اعتبارات ===  
* عادة ما يكون الرد (callback ) غير متزامن، لذلك قد لا يتوقع المُستدعي (caller) أن يكون الرد فوريًا. لكن إن لم يكن الاستدعاء غير متزامن، فعليك على الأقل استخدام مهلة [[JavaScript|[[Java|جافا]]اسكريبت]] (javascript timeout) لضمان أن يكون استدعاء الرد غير متزامن.  
* عادة ما يكون الرد (callback ) غير متزامن، لذلك قد لا يتوقع المُستدعي (caller) أن يكون الرد فوريًا. لكن إن لم يكن الاستدعاء غير متزامن، فعليك على الأقل استخدام مهلة [[JavaScript|جافااسكريبت]] (javascript timeout) لضمان أن يكون استدعاء الرد غير متزامن.  
* يمكن استخدام الأصناف القابلة للتنشيط (Activatable classes) لإرسال الأحداث (event dispatching)، أو الردود المتزامنة، أو تمرير أنواع كائنات خاصة، أو المصفوفات، أو المجموعات، أو التوابع المُتحاملة (overloaded methods)، وغير ذلك. ارجع إلى [http://msdn.microsoft.com/en-us/library/windows/apps/hh441569.aspx Creating Windows Runtime Components in C++] لمزيد من التفاصيل.  
* يمكن استخدام الأصناف القابلة للتنشيط (Activatable classes) لإرسال الأحداث (event dispatching)، أو الردود المتزامنة، أو تمرير أنواع كائنات خاصة، أو المصفوفات، أو المجموعات، أو التوابع المُتحاملة (overloaded methods)، وغير ذلك. ارجع إلى [http://msdn.microsoft.com/en-us/library/windows/apps/hh441569.aspx Creating Windows Runtime Components in C++] لمزيد من التفاصيل.  
=== تعريف الإضافة في الملف plugin.xml ===  
=== تعريف الإضافة في الملف plugin.xml ===  



مراجعة 14:12، 23 نوفمبر 2018

 يقدم هذا القسم تفاصيل عن كيفية تقديم (implement) إضافة لاستخدامها في متجر تطبيقات ويندوز للهواتف وسطح المكتب في ويندوز 8.1، ومنصة ويندوز الكونية (Universal Windows [ويندوز 10+]‎‎). قبل قراءة هذه الصفحة، المرجو مراجعة صفحة دليل تطوير الإضافات .

للحصول على نظرة عامة على بنية الإضافات وواجهة جافاسكريبت الخاصة بها. يستمر هذا القسم في تطوير مثال الإضافة echo الوارد في دليل تطوير الإضافات، والذي يربط الاتصال بين المعرض webview الخاص بكوردوفا وبين المنصة الأصلية.

إنشاء إضافة ويندوز عبر جافاسكريبت

إضافات ويندوز كوردوفا هي بالأساس أغلفة رقيقة (thin wrapper) حول دوال المكتبة WinJS، ولكن إن كنت تحتاج إلى تعريف واجهة جافاسكريبت مشتركة بين عدة أجهزة، فستحتاج عادةً إلى ملف جافاسكريبت واحد يوفر تلك الواجهة البرمجية (API):

// inside file echoplugin.js
var EchoPlugin = {
    // the echo function calls successCallback with the provided text in strInput
    // if strInput is empty, it will call the errorCallback
    echo:function(successCallback, errorCallback, strInput) {
        cordova.exec(successCallback,errorCallback,"EchoPlugin","echo",[strInput]);
    }
}

يختلف تعريف الدالة cordova.exec من منصة إلى أخرى، وذلك لأن لكل منصة طريقتها الخاصة في التواصل بين شيفرة الجافاسكريبت، والشيفرة الأصلية المُغلّفة (native wrapper code). ولكن في حالة ويندوز، لا يوجد غلاف أصلي، لذلك فاستدعاء exec هو فقط لتوفير واجهة متناسقة. لذلك، على الرغم من أنه يمكنك كتابة الشيفرة البرمجية الخاصة بويندوز كجزء من ملف جافاسكريبت المشترك (الخاص بالإضافة) مباشرةً، إلا أننا لا نوصى بذلك، فيجب على مطوري الإضافات استخدام نفس الواجهة البرمجية exec في ويندوز كما في بقية المنصات الأخرى. وبهذه الطريقة تصبح الواجهة البرمجية للإضافات متسقة، كما يمكنك أيضًا الاستفادة من أي فحص للوسائط، أو أي الشيفرات الأخرى الشائعة التي يوفرها المطورون على المنصات الأخرى.

على ويندوز، توفر كوردوفا خادمًا وسيطًا (proxy) يمكن استخدامه لتسجيل كائن معين يتكلّف بالتعامل مع جميع استدعاءات cordova.exec في الواجهة البرمجية (API). لذلك في حالتنا، سنفترض أن الشيفرة الموجودة في الملف echoplugin.js ستعالج أكواد جافاسكريبت العابرة للمنصات (cross platform)، وهكذا يمكننا ببساطة كتابة خادمٍ وسيطٍ لنظام ويندوز.

// in file echoplugin.js
window.echo = function(str, callback) {
    cordova.exec(callback, function(err) {
        callback('Nothing to echo.');
    }, "Echo", "echo", [str]);
};
// in file echopluginProxy.js
cordova.commandProxy.add("Echo",{
    echo:function(successCallback,errorCallback,strInput) {
        if(!strInput || !strInput.length) {
            errorCallback("Error, something was wrong with the input string. =>" + strInput);
        }
        else {
            successCallback(strInput + "echo");
        }
    }
});

سيعيد الملف echoplugin.js توجيه استدعاء الدالة echo إلى الخادم الوسيط عبر الأمر cordova.exec ثم ينفّذ هذا التقديم (implementation).

سيحتوي الملف plugin.xml على الإعدادات المطلوبة في الََإضافة. وفي هذه الحالة، نريد إضافة الملف echoplugin.js في المجلد www، وإضافة الملف echopluginProxy.js داخل الشيفرة المصدرية windows الخاصة بتطبيقنا. يمكن العثور على مزيد من التفاصيل حول هذه العناصر في المرجع Plugin xml.

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
    id="echoplugin"
    version="0.1.0">
    <js-module src="www/echoplugin.js" name="echoplugin">
        <clobbers target="window.echoplugin" />
    </js-module>
    <!-- windows -->
    <platform name="windows">
        <js-module src="src/windows/echopluginProxy.js" name="EchoProxy">
            <merges target="" />
        </js-module>
    </platform>
    <!-- other platforms -->
</plugin>‎c

سينتج عن هذا إضافة ويندوز-جافاسكريبت جاهزة، والتي تستخدم ملفًا مشتركًا (echoplugin.js)، وخادمًا وسيطًا لتوفير الأجزاء المخصوصة بويندوز في الملف (echopluginProxy.js). إذن، كيف يمكننا إضافة شيفرة أصلية ومٌدارة (native/managed code) إلى هذا؟ حسنًا، سنعيد ما فعلناه من قبل، الفرق الوحيد هو ما سنفعله داخل توابع echopluginProxy.

إنشاء إضافات ويندوز في C++‎ أو الشيفرة المُدارة (managed code).

في نظام ويندوز، تستطيع تطبيقات جافااسكريبت أن تتداخل مع اللغات الأصلية (C++‎) والشيفرات المُدارة (C#، VB) عن طريق إنشاء مُركّبة (component) في ويندوز تعمل وقت تشغيل. يمكنك تعلم الأساسيات والحصول على مزيد من التفاصيل في مراجع MSDN: Creating Windows Runtime Components in C# and Visual Basic Creating Windows Runtime Components in C++

عندما تقوم بإنشاء مركبة وقت التشغيل في ويندوز (Windows Runtime Component)، فإن كل الأصناف التي عُرِّفت وفق الصيغة public ref class sealed ستُعد "صنفًا فعالا" (activatable class)، وسيكون قابلًا للاستدعاء من جافااسكريبت.

// in your header file .h
namespace EchoRuntimeComponent
{
    public ref class EchoPluginRT sealed
    {
        public:
        static Platform::String^ Echo(Platform::String^ input);
    }
}
// in the implementation file .cpp
using namespace EchoRuntimeComponent;
using namespace Platform;
Platform::String^ EchoPluginRT::Echo(Platform::String^ input)
{
    if(input->IsEmpty())
    {
        return "Error: input string is empty.";
    }
    else
    {
        return input->ToString() + "echo";
    }
}

الآن حتى يتسنى لنا استدعاء الشيفرة الأصلية، نستخدم اسم المجال (namespace)، واسم الصنف، و الاسم المُحدب (lowerCamelCase) للتابع الذي نستدعيه.

var res = EchoRuntimeComponent.EchoPluginRT.echo("boom");

بنقل هذا إلى الملف echopluginProxy.js، سنحصل على:

// in file echopluginProxy.js
cordova.commandProxy.add("EchoPlugin",{
    echo:function(successCallback, errorCallback, strInput) {
        var res = EchoRuntimeComponent.EchoPluginRT.echo(strInput);
        if(res.indexOf("Error") == 0) {
            errorCallback(res);
        }
        else {
            successCallback(res);
        }
    }
});

وهذا كل شيء، صارت لدينا إضافة ويندوز كوردوفا مع ملف جافااسكريبت قابل للاستدعاء ومربوط ومدعوم بملف C++‎.

اعتبارات

  • عادة ما يكون الرد (callback ) غير متزامن، لذلك قد لا يتوقع المُستدعي (caller) أن يكون الرد فوريًا. لكن إن لم يكن الاستدعاء غير متزامن، فعليك على الأقل استخدام مهلة جافااسكريبت (javascript timeout) لضمان أن يكون استدعاء الرد غير متزامن.
  • يمكن استخدام الأصناف القابلة للتنشيط (Activatable classes) لإرسال الأحداث (event dispatching)، أو الردود المتزامنة، أو تمرير أنواع كائنات خاصة، أو المصفوفات، أو المجموعات، أو التوابع المُتحاملة (overloaded methods)، وغير ذلك. ارجع إلى Creating Windows Runtime Components in C++ لمزيد من التفاصيل.

تعريف الإضافة في الملف plugin.xml

والآن بعد أن أصبحت إضافتنا جاهزة للعمل، سيكون علينا إعادة النظر في التعريف السابق للإضافة لكي ننشره. يمكننا الآن إضافة مركب وقت التشغيل (runtime component) كإطار عمل، من خلال الوسم <framework> داخل إعدادات منصتنا. لاحظ أن نوع مخرجات WindowsRuntimeComponent قد تكون إما ‎.winmd أو ‎.‎dll

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
    id="echoplugin"
    version="0.2.0">
    <js-module src="www/echoplugin.js" name="echoplugin">
        <clobbers target="window.echoplugin" />
    </js-module>
    <!-- windows -->
    <platform name="windows">
        <js-module src="src/windows/echopluginProxy.js" name="EchoProxy">
            <merges target="" />
        </js-module>
        <framework src="src/windows/EchoRuntimeComponent.winmd" custom="true"/>
    </platform>
    <!-- other platforms -->
</plugin>‎

هذا كل شيء، إضافتك الآن صارت جاهزة لتشاركها مع العالم!

مصادر