البرنامج التعليمي: إنشاء تطبيق ويب Node.js باستخدام JavaScript SDK لإدارة واجهة برمجة التطبيقات لحساب NoSQL في Azure Cosmos DB

ينطبق على: NoSQL

بصفتك مطورًا، قد تمتلك تطبيقات تستخدم بيانات مستندات بنظام NoSQL. يمكنك استخدام واجهة برمجة تطبيقات لحساب NoSQL في Azure Cosmos DB لتخزين بيانات هذا المستند والوصول إليها. يوضح لك هذا البرنامج التعليمي Node.js كيفية تخزين البيانات والوصول إليها من واجهة برمجة التطبيقات لحساب NoSQL في Azure Cosmos DB. يستخدم البرنامج التعليمي تطبيق Node.js Express المستضاف على ميزة Web Apps في Microsoft Azure App Service. في هذا البرنامج التعليمي، يمكنك إنشاء تطبيق مستند إلى الويب (تطبيق Todo) يسمح لك بإنشاء المهام واستردادها وإكمالها. يتم تخزين المهام كمستندات JSON في Azure Cosmos DB.

يوضح هذا البرنامج التعليمي كيفية إنشاء API لحساب NoSQL في Azure Cosmos DB باستخدام مدخل Microsoft Azure. بدون بطاقة ائتمان أو اشتراك Azure، يمكنك:

  • إعداد حساب تجربة Azure Cosmos DB مجاني.
  • إنشاء وتشغيل تطبيق ويب مبني على Node.js SDK لإنشاء قاعدة بيانات وحاوية.
  • إضافة عناصر إلى الحاوية.

يستخدم هذا البرنامج التعليمي JavaScript SDK الإصدار 3.0 ويغطي المهام التالية:

  • إنشاء حساب Azure Cosmos DB
  • إنشاء تطبيق Node.js جديد
  • توصيل التطبيق بـAzure Cosmos DB
  • تشغيل التطبيق ونشره في Azure

المتطلبات الأساسية

قبل اتباع الإرشادات الواردة في هذه المقالة، تأكد من توفر الموارد الآتية لديك:

إنشاء حساب Azure Cosmos DB

ابدأ بإنشاء حساب Azure Cosmos DB. إذا كان لديك حساب بالفعل أو إذا كنت تستخدم Azure Cosmos DB Emulator لهذا البرنامج التعليمي، يمكنك التخطي إلى إنشاء تطبيق Node.js جديد.

  1. من قائمة مدخل Azure أو الصفحة الرئيسية، حدد Create a resource.

  2. ابحث عن Azure Cosmos DB. حدد Create>Azure Cosmos DB.

  3. في صفحة Create an Azure Cosmos DB account ، حدد الخيار Create ضمن قسم Azure Cosmos DB for NoSQL .

    يوفر Azure Cosmos DB العديد من واجهات برمجة التطبيقات:

    • NoSQL، لبيانات المستند
    • PostgreSQL
    • MongoDB، لبيانات المستند
    • Apache Cassandra
    • جدول
    • Apache Gremlin، لبيانات الرسم البياني

    لمعرفة المزيد حول واجهة برمجة التطبيقات ل NoSQL، راجع مرحبا بك في Azure Cosmos DB.

  4. في صفحة إنشاء حساب Azure Cosmos DB، أدخل الإعدادات الأساسية لحساب Azure Cosmos DB الجديد.

    الإعداد قيمة ‏‏الوصف
    الاشتراك اسم الاشتراك حدد اشتراك Azure الذي تريد استخدامه لحساب Azure Cosmos DB هذا.
    مجموعة الموارد اسم مجموعة الموارد حدد مجموعة موارد، أو حدد إنشاء جديد، ثم أدخل اسمًا فريدًا لمجموعة الموارد الجديدة.
    اسم الحساب اسم فريد أدخل اسما لتعريف حساب Azure Cosmos DB الخاص بك. لأنه يتم إلحاق documents.azure.com إلى الاسم الذي تقوم بتوفيره لإنشاء URI الخاص بك، استخدم اسمًا فريدًا. يمكن أن يحتوي الاسم على أحرف صغيرة وأرقام وحرف الواصلة (-) فقط. يجب أن يكون من 3 إلى 44 حرفا.
    الموقع المنطقة الأقرب إلى مستخدميك حدد موقعًا جغرافيًّا لاستضافة حساب Azure Cosmos DB. استخدم الموقع الأقرب إلى المستخدمين لمنحهم أسرع وصول إلى البيانات.
    وضع السعة معدل النقل المقدم أو بلا خادم حدد "Provisioned throughput" لإنشاء حساب في وضع معدل النقل المتوفر. حدد Serverless لإنشاء حساب في وضع دون خادم.
    تطبيق خصم طبقة Azure Cosmos DB المجاني تطبيق أو عدم تطبيق مع الطبقة المجانية لـ Azure Cosmos DB، ستحصل على أول 1000 RU/ثانية و25 غيغابايت من التخزين مجاناً في الحساب. تعرف على المزيد حول الطبقة المجانية.
    ضع حدُا لمعدل نقل الحساب محدد أم لا حدد إجمالي مقدار معدل النقل الذي يمكن توفيره على هذا الحساب. يمنع هذا الحد الرسوم غير المتوقعة المتعلقة بمعدل النقل المقدم. يمكنك تحديث هذا الحد أو إزالته بعد إنشاء حسابك.

    يمكن أن يكون لديك ما يصل إلى حساب Azure Cosmos DB مجاني واحد لكل اشتراك Azure ويجب عليك الاشتراك عند إنشاء الحساب. إذا كنت لا ترى خيار تطبيق خصم الطبقة المجانية، فهذا يعني تمكين حساب آخر بالفعل في الاشتراك مع الطبقة المجانية.

    تظهر لقطة الشاشة صفحة إنشاء حساب Azure Cosmos DB.

    إشعار

    الخيارات التالية غير متوفرة إذا قمت بتحديد دون خادمباعتبارهاوضع السعة:

    • تطبيق خصم من الدرجة المجانية
    • ضع حدُا لمعدل نقل الحساب
  5. في علامة تبويب Global Distributionكوّن التفاصيل التالية. يمكنك ترك القيم الافتراضية لهذه البداية السريعة:

    الإعداد قيمة ‏‏الوصف
    التكرار الجغرافي تعطيل تمكين التوزيع العمومي على حسابك أو تعطيله عن طريق إقران منطقتك بمنطقة زوج. يمكنك إضافة المزيد من المناطق إلى حسابك لاحقًا.
    كتابات متعددة المناطق تعطيل تتيح لك إمكانية الكتابة متعددة المناطق الاستفادة من الإنتاجية المقدمة لقواعد البيانات والحاويات الخاصة بك في جميع أنحاء العالم.
    مجموعات التوافر تعطيل تساعدك مناطق التوفر على تحسين توفر التطبيق ومرونته.

    إشعار

    لا تتوفر الخيارات التالية إذا قمت بتحديد Serverless كوضع Capacity في صفحة Basics السابقة:

    • Geo-redundancy
    • كتابات متعددة المناطق
  6. اختياريا، يمكنك تكوين مزيد من التفاصيل في علامات التبويب التالية:

    • الشبكات. تكوين الوصول من شبكة ظاهرية.
    • نهج النسخ الاحتياطي. تكوين نهج النسخ الاحتياطي الدوري أو المستمر .
    • التشفير. استخدم إما مفتاحا مدارا بواسطة الخدمة أو مفتاحا يديره العميل.
    • العلامات. العلامات هي أزواج أسماء/قيم تمكنك من تصنيف الموارد وعرض الفوترة الموحدة من خلال تطبيق العلامة نفسها على موارد ومجموعات موارد متعددة.
  7. حدد "Review + create".

  8. راجع الإعدادات، ثم حدد Create. يستغرق إنشاء جهاز ظاهر بضع دقائق. انتظر حتى يتم عرض صفحة المدخل، اكتمل النشر.

    تظهر لقطة الشاشة اكتمال النشر.

  9. حدد الانتقال إلى المورد للانتقال إلى صفحة حساب Azure Cosmos DB.

    تظهر لقطة الشاشة صفحة حساب Azure Cosmos DB.

انتقل إلى صفحة حساب Azure Cosmos DB، وحدد Keys. انسخ القيم المراد استخدامها في تطبيق الويب الذي تنشئه بعد ذلك.

لقطة شاشة لمدخل Azure مع تمييز الزر «Keys» في صفحة حساب Azure Cosmos DB

إنشاء تطبيق Node.js جديد

الآن، تعرف على كيفية إنشاء مشروع مرحبًا بالعالم Node.js أساسي باستخدام إطار عمل Express.

  1. افتح محطتك الطرفية المفضلة، مثل موجه أوامر Node.js.

  2. انتقل إلى الدليل الذي تريد تخزين التطبيق الجديد فيه.

  3. استخدام مُنشئ express لإنشاء تطبيق جديد يسمى todo.

    express todo
    
  4. افتح دليل todo وثبّت التبعيات.

    cd todo
    npm install
    
  5. شغّل التطبيق الجديد.

    npm start
    
  6. لعرض تطبيقك الجديد في مستعرض، انتقل إلى http://localhost:3000.

    لقطة شاشة لتطبيق مرحبًا بالعالم في نافذة المستعرض.

    أوقف تشغيل التطبيق باستخدام CTRL+C في نافذة المحطة الطرفية ثم حدد y لإنهاء مهمة الدفعة.

ثبّت الوحدات النمطية المطلوبة

ملف package.json هو أحد الملفات التي تم إنشاؤها في جذر المشروع. يحتوي هذا الملف على قائمة من الوحدات النمطية الإضافية المطلوبة لتطبيق Node.js. عند نشر هذا التطبيق في Azure، يتم استخدام هذا الملف لتحديد الوحدات النمطية التي يجب تثبيتها على Azure لدعم تطبيقك. ثبّت حزمتين إضافيتين لهذا البرنامج التعليمي.

  1. ثبّت وحدة @azure/cosmos عبر npm.

    npm install @azure/cosmos
    

ربط تطبيق Node.js بـAzure Cosmos DB

بعد إكمال الإعداد والتكوين الأوليين، تعرف على كيفية كتابة التعليمات البرمجية التي يتطلبها تطبيق todo للاتصال ب Azure Cosmos DB.

إنشاء النموذج

  1. في جذر الدليل لمشروعك، أنشئ دليلاً جديداً باسم models.

  2. وفي دليل models، أنشئ ملفاً جديداً باسم taskDao.js. يحتوي هذا الملف على التعليمة البرمجية المطلوبة لإنشاء قاعدة البيانات والحاوية. كما أنه يحدد أساليب قراءة المهام وتحديثها وإنشاءها والبحث عنها في Azure Cosmos DB.

  3. انسخ التعليمة البرمجية الآتية في الملف taskDao.js:

     // @ts-check
     const CosmosClient = require('@azure/cosmos').CosmosClient
     const debug = require('debug')('todo:taskDao')
    
     // For simplicity we'll set a constant partition key
     const partitionKey = undefined
     class TaskDao {
       /**
        * Manages reading, adding, and updating Tasks in Azure Cosmos DB
        * @param {CosmosClient} cosmosClient
        * @param {string} databaseId
        * @param {string} containerId
        */
       constructor(cosmosClient, databaseId, containerId) {
         this.client = cosmosClient
         this.databaseId = databaseId
         this.collectionId = containerId
    
         this.database = null
         this.container = null
       }
    
       async init() {
         debug('Setting up the database...')
         const dbResponse = await this.client.databases.createIfNotExists({
           id: this.databaseId
         })
         this.database = dbResponse.database
         debug('Setting up the database...done!')
         debug('Setting up the container...')
         const coResponse = await this.database.containers.createIfNotExists({
           id: this.collectionId
         })
         this.container = coResponse.container
         debug('Setting up the container...done!')
       }
    
       async find(querySpec) {
         debug('Querying for items from the database')
         if (!this.container) {
           throw new Error('Collection is not initialized.')
         }
         const { resources } = await this.container.items.query(querySpec).fetchAll()
         return resources
       }
    
       async addItem(item) {
         debug('Adding an item to the database')
         item.date = Date.now()
         item.completed = false
         const { resource: doc } = await this.container.items.create(item)
         return doc
       }
    
       async updateItem(itemId) {
         debug('Update an item in the database')
         const doc = await this.getItem(itemId)
         doc.completed = true
    
         const { resource: replaced } = await this.container
           .item(itemId, partitionKey)
           .replace(doc)
         return replaced
       }
    
       async getItem(itemId) {
         debug('Getting an item from the database')
         const { resource } = await this.container.item(itemId, partitionKey).read()
         return resource
       }
     }
    
     module.exports = TaskDao
    
  4. احفظ الملف taskDao.js وأغلقه.

إنشاء وحدة التحكم

  1. في الدليل routes لمشروعك، أنشئ ملفاً جديداً باسم tasklist.js.

  2. أضف التعليمة البرمجية الآتية إلى الملف tasklist.js. تحمّل هذه التعليمة البرمجية CosmosClient والوحدات النمطية غير المتزامنة التي يستخدمها الملف tasklist.js. تحدد هذه التعليمة البرمجية أيضاً فئة TaskList، التي يتم تمريرها كمثيل للكائن TaskDao الذي عرّفناه سابقاً:

     const TaskDao = require("../models/TaskDao");
    
     class TaskList {
       /**
        * Handles the various APIs for displaying and managing tasks
        * @param {TaskDao} taskDao
        */
       constructor(taskDao) {
         this.taskDao = taskDao;
       }
       async showTasks(req, res) {
         const querySpec = {
           query: "SELECT * FROM root r WHERE r.completed=@completed",
           parameters: [
             {
               name: "@completed",
               value: false
             }
           ]
         };
    
         const items = await this.taskDao.find(querySpec);
         res.render("index", {
           title: "My ToDo List ",
           tasks: items
         });
       }
    
       async addTask(req, res) {
         const item = req.body;
    
         await this.taskDao.addItem(item);
         res.redirect("/");
       }
    
       async completeTask(req, res) {
         const completedTasks = Object.keys(req.body);
         const tasks = [];
    
         completedTasks.forEach(task => {
           tasks.push(this.taskDao.updateItem(task));
         });
    
         await Promise.all(tasks);
    
         res.redirect("/");
       }
     }
    
     module.exports = TaskList;
    
  3. احفظ الملف tasklist.js وأغلقه.

إضافة config.js

  1. في جذر الدليل لمشروعك، أنشئ ملفاً جديداً باسم config.js.

  2. أضف التعليمة البرمجية الآتية إلى الملف config.js. تحدد هذه التعليمة البرمجية إعدادات التكوين وقيمه المطلوبة لتطبيقنا.

    const config = {};
    
    config.host = process.env.HOST || "[the endpoint URI of your Azure Cosmos DB account]";
    config.authKey =
      process.env.AUTH_KEY || "[the PRIMARY KEY value of your Azure Cosmos DB account";
    config.databaseId = "ToDoList";
    config.containerId = "Items";
    
    if (config.host.includes("https://localhost:")) {
      console.log("Local environment detected");
      console.log("WARNING: Disabled checking of self-signed certs. Do not have this code in production.");
      process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
      console.log(`Go to http://localhost:${process.env.PORT || '3000'} to try the sample.`);
    }
    
    module.exports = config;
    
  3. في ملف config.js ، قم بتحديث قيم HOST و AUTH_KEY باستخدام القيم الموجودة في صفحة Keys لحساب Azure Cosmos DB على مدخل Microsoft Azure.

  4. احفظ الملف config.js وأغلقه.

تعديل app.js

  1. في دليل المشروع، افتح الملف app.js. تم إنشاء هذا الملف في وقت سابق عند إنشاء تطبيق الويب بإطار العمل Express.

  2. أضف التعليمة البرمجية الآتية إلى الملف app.js. تحدد هذه التعليمة البرمجية ملف التكوين الذي سيتم استخدامه وتحميل القيم في بعض المتغيرات التي ستستخدمها في الأقسام التالية.

     const CosmosClient = require('@azure/cosmos').CosmosClient
     const config = require('./config')
     const TaskList = require('./routes/tasklist')
     const TaskDao = require('./models/taskDao')
    
     const express = require('express')
     const path = require('path')
     const logger = require('morgan')
     const cookieParser = require('cookie-parser')
     const bodyParser = require('body-parser')
    
     const app = express()
    
     // view engine setup
     app.set('views', path.join(__dirname, 'views'))
     app.set('view engine', 'jade')
    
     // uncomment after placing your favicon in /public
     //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
     app.use(logger('dev'))
     app.use(bodyParser.json())
     app.use(bodyParser.urlencoded({ extended: false }))
     app.use(cookieParser())
     app.use(express.static(path.join(__dirname, 'public')))
    
     //Todo App:
     const cosmosClient = new CosmosClient({
       endpoint: config.host,
       key: config.authKey
     })
     const taskDao = new TaskDao(cosmosClient, config.databaseId, config.containerId)
     const taskList = new TaskList(taskDao)
     taskDao
       .init(err => {
         console.error(err)
       })
       .catch(err => {
         console.error(err)
         console.error(
           'Shutting down because there was an error settinig up the database.'
         )
         process.exit(1)
       })
    
     app.get('/', (req, res, next) => taskList.showTasks(req, res).catch(next))
     app.post('/addtask', (req, res, next) => taskList.addTask(req, res).catch(next))
     app.post('/completetask', (req, res, next) =>
       taskList.completeTask(req, res).catch(next)
     )
     app.set('view engine', 'jade')
    
     // catch 404 and forward to error handler
     app.use(function(req, res, next) {
       const err = new Error('Not Found')
       err.status = 404
       next(err)
     })
    
     // error handler
     app.use(function(err, req, res, next) {
       // set locals, only providing error in development
       res.locals.message = err.message
       res.locals.error = req.app.get('env') === 'development' ? err : {}
    
       // render the error page
       res.status(err.status || 500)
       res.render('error')
     })
    
     module.exports = app
    
  3. وأخيراً، احفظ الملف app.js وأغلقه.

إنشاء واجهة المستخدم

الآن قم بإنشاء واجهة المستخدم بحيث يمكن للمستخدم التفاعل مع التطبيق. يستخدم تطبيق Express الذي أنشأته في الأقسام السابقة Jade كمحرك عرض.

  1. يُستخدم ملف layout.jade في دليل views كقالب عام لملفات .jade الأخرى. في هذه الخطوة، يمكنك تعديله لاستخدام Twitter Bootstrap، وهو مجموعة أدوات تستخدم لتصميم موقع ويب.

  2. افتح ملف layout.jade الموجود في مجلد views واستبدل المحتويات بالتعليمة البرمجية الآتية:

    doctype html
    html
      head
        title= title
        link(rel='stylesheet', href='//ajax.aspnetcdn.com/ajax/bootstrap/3.3.2/css/bootstrap.min.css')
        link(rel='stylesheet', href='/stylesheets/style.css')
      body
        nav.navbar.navbar-inverse.navbar-fixed-top
          div.navbar-header
            a.navbar-brand(href='#') My Tasks
        block content
        script(src='//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.2.min.js')
        script(src='//ajax.aspnetcdn.com/ajax/bootstrap/3.3.2/bootstrap.min.js')
    

    تخبر هذه التعليمة البرمجية محرك Jade بعرض بعض HTML للتطبيق وإنشاء كتلة تسمى المحتوى حيث يمكنك توفير تخطيط صفحات المحتوى. احفظ الملف layout.jade وأغلقه.

  3. افتح ملف index.jade ، طريقة العرض المستخدمة من قبل التطبيق. استبدل محتوى الملف بالتعليمات البرمجية التالية:

    extends layout
    block content
         h1 #{title}
         br
    
         form(action="/completetask", method="post")
          table.table.table-striped.table-bordered
             tr
               td Name
               td Category
               td Date
               td Complete
             if (typeof tasks === "undefined")
               tr
                 td
             else
               each task in tasks
                 tr
                   td #{task.name}
                   td #{task.category}
                   - var date  = new Date(task.date);
                   - var day   = date.getDate();
                   - var month = date.getMonth() + 1;
                   - var year  = date.getFullYear();
                   td #{month + "/" + day + "/" + year}
                   td
                    if(task.completed) 
                     input(type="checkbox", name="#{task.id}", value="#{!task.completed}", checked=task.completed)
                    else
                     input(type="checkbox", name="#{task.id}", value="#{!task.completed}", checked=task.completed)
           button.btn.btn-primary(type="submit") Update tasks
         hr
         form.well(action="/addtask", method="post")
           label Item Name:
           input(name="name", type="textbox")
           label Item Category:
           input(name="category", type="textbox")
           br
           button.btn(type="submit") Add item
    

تعمل هذه التعليمة البرمجية على توسيع التخطيط وتوفير محتوى للعن العنصر النائب للمحتوى الذي شاهدته في ملف layout.jade. في هذا التخطيط، قمت بإنشاء نموذجي HTML.

يحتوي النموذج الأول على جدول لبياناتك وزر يسمح لك بتحديث العناصر عن طريق النشر إلى أسلوب /completeTask لوحدة التحكم.

يحتوي النموذج الثاني على حقلي إدخال وزر يسمح لك بإنشاء عنصر جديد عن طريق النشر إلى أسلوب /addtask لوحدة التحكم، وهو كل ما تحتاجه لكي يعمل التطبيق.

تشغيل التطبيق على المستوى المحلي

بعد إنشاء التطبيق، يمكنك تشغيله محليا باستخدام الخطوات التالية:

  1. لاختبار التطبيق على جهازك المحلي، قم بتشغيل npm start في المحطة الطرفية لبدء تشغيل التطبيق الخاص بك، ثم قم بتحديث http://localhost:3000 الصفحة. يجب أن تبدو الصفحة الآن مثل لقطة الشاشة التالية:

    لقطة شاشة لتطبيق قائمة Todo الخاصة بي في مستعرض.

    تلميح

    إذا تلقيت خطأ حول المسافة البادئة في الملف layout.jade أو ملف index.jade ، فتأكد من أن أول سطرين في كلا الملفين يتم تبريرهما إلى اليسار، بدون مسافات. إذا كانت هناك مسافات قبل السطرين الأولين، فقم بإزالتها واحفظ الملفين ثم حدّث نافذة المتصفح.

  2. استخدم الحقلين اسم العنصر وفئة العنصر لإدخال مهمة جديدة، ثم حدد إضافة عنصر لإنشاء مستند في Azure Cosmos DB بهذه الخصائص.

  3. يتم تحديث الصفحة لعرض العنصر الذي تم إنشاؤه حديثا في قائمة ToDo.

    لقطة شاشة للتطبيق مع عنصر جديد في قائمة ToDo.

  4. لإكمال مهمة، حدد خانة الاختيار في العمود إكمال، ثم حدد تحديث المهام لتحديث المستند الذي قمت بإنشائه بالفعل وإزالته من طريقة العرض.

  5. لإيقاف التطبيق، اضغط على CTRL+C في نافذة المحطة الطرفية ثم حدد y لإنهاء مهمة الدفعة.

وزع التطبيق على خدمات التطبيق.

بعد نجاح تطبيقك على المستوى المحلي، يمكنك نشره في Azure App Service في المحطة الطرفية، تأكد من اطلاعك على دليل تطبيق بنود يجب القيام بها انشر التعليمات البرمجية في المجلد المحلي (todo) باستخدام الأمر az webapp up التالي:

az webapp up --sku F1 --name <app-name>

استبدل <app_name> باسم فريد عبر كل Azure (الأحرف الصالحة هي a-z و0-9 و-). النمط الجيد هو استخدام مزيج من اسم شركتك ومعرف التطبيق. لمعرفة المزيد حول نشر التطبيق، راجع Node.js نشر التطبيق في Azure.

قد يستغرق الأمر بضع دقائق حتى يكتمل. يوفر الأمر رسائل حول إنشاء مجموعة الموارد وخطة App Service ومورد التطبيق وتكوين التسجيل والقيام بنشر ZIP. يوفر الأمر هذه الرسائل أثناء التشغيل. ثم يمنحك عنوان ويب محدد مواقع ويب لإطلاق التطبيق في http://<app-name>.azurewebsites.netوهو عنوان محدد مواقع ويب للتطبيق على Azure.

تنظيف الموارد

عندما لا تكون هناك حاجة إلى هذه الموارد، يمكنك حذف مجموعة الموارد وحساب Azure Cosmos DB وجميع الموارد ذات الصلة. وللقيام بذلك، حدد مجموعة الموارد التي استخدمتها لحساب Azure Cosmos DB ثم حدد حذف وأكد اسم مجموعة الموارد التي تريد حذفها.

الخطوات التالية

يمكنك استخدام معلومات حول نظام مجموعة قاعدة البيانات الموجودة لديك لـ تخطيط السعة.