برنامه هاي وب يكي از مهمترين دستاوردهاي اخير در صنعت نرم افزار مي باشند كه علل آن را مي بايست در تاثير اينترنت بر دنياي گسترده نرم افزار جستجو كرد . آشنائي با معماري برنامه هاي وب و بكارگيري فن آوري هاي متعدد با توجه به ساختار اين نوع برنامه هاي كامپيوتري براي تمامي پياده كنندگان علاقه مند حضور موثر و مستمر در اين عرصه ، امري لازم و ضروري است .
برنامه هاي وب داراي سه ويژگي مهم و برجسته مي باشند :
• مبتني بر وب مي باشند ( Web-based )
• از معماري سرويس گيرنده - سرويس دهنده Three tire استفاده مي نمايند .
• سيستم هاي پردازش اطلاعات مي باشند ( در مقابل سيستم هاي عرضه اطلاعات )
با توجه به موضوع اين مقاله اجازه دهيد بر روي ويژگي دوم متمركز شده و با آن بيشتر آشنا شويم .
واژه "سرويس گيرنده - سرويس دهنده " نشاندهنده اين واقعيت است كه از شبكه هاي مبتني بر سرويس دهندگان به منظور مديريت اشتراك منابع استفاده مي گردد . براي توزيع پردازش از پتانسيل هاي سخت افزاري و نرم افزاري سرويس دهندگان و سرويس گيرندگان استفاده مي گردد و هر يك داراي سهمي در كل پردازش مي باشند ( گرچه در توزيع سهم پردازش ، عدالت به درستي رعايت نشده باشد ) .
با توجه به رويكرد فوق، پياده كنندگان برنامه هاي وب مي توانند به منظور تامين خواسته هاي يك برنامه از پتانسيل هاي پردازش سمت سرويس دهنده و يا سمت سرويس گيرنده استفاده نمايند . براي تحقق پردازش هاي سمت سرويس دهنده و سرويس گيرنده از فن آوري هاي متعددي استفاده مي گردد .
ASP.NET ، يك فن آوري سمت سرويس دهنده است و نمي تواند مستقيما" با مرورگر تعامل و يا ارتباط داشته باشد .به عنوان نمونه ، در ASP.NET مكانيزمي وجود ندارد كه بتوان با استفاده از آن داده تايپ شده از طريق صفحه كليد توسط كاربر در برنامه مرورگر را دريافت ، به رويدادهاي موس پاسخ و عملياتي را انجام داد كه مستلزم تعامل مستقيم با كاربر مي باشند . ASP.NET صرفا" مي تواند نتايج اينچنين تعاملاتي را پس از ارسال صفحه مشاهده و از آنان استفاده نمايد و قادر به پاسخگوئي مستقيم به رويدادهاي ايجاد شده در سطح مرورگر نمي باشد .
به منظور برخورد و مديريت تعامل با مرورگر و رويدادهاي محقق شده در آن سطح ، بهترين گزينه استفاده از اسكريپت هاي سمت سرويس گيرنده است كه توسط يكي از زبان هاي اسكريپت نويسي نظير جاوااسكريپت نوشته مي گردند . اسكريپت هاي سمت سرويس گيرنده در مرورگر اجراء شده و مي توانند بلافاصله نسبت به عمليات انجام شده توسط كاربر از خود واكنش نشان دهند . مثلا" با استفاده از اسكريپت هاي سمت سرويس گيرنده مي توان يك افكت rollover را ايجاد و يا واكنش مناسبي را در زمان حركت موس بر روي يك button و يا يك آيتم خاص موجود در منو انجام داد .
اسكريپت هاي سمت سرويس گيرنده توان عملياتي پياده كنندگان را به منظور برخورد با رويدادهائي كه در سطح لايه رابط كاربر محقق مي شوند و لازم است كه بلافاصله به آنان پاسخ داده شود ، افزايش مي دهد .
كنترل هاي سرويس دهنده ASP.NET و اسكريپت هاي سمت سرويس گيرنده
تعدادي از كنترل هاي سرويس دهنده ASP.NET به منظور انجام وظايف از قبل تعريف شده خود نيازمند استفاده از اسكريپت هاي سمت سرويس گيرنده مي باشند . به عنوان نمونه كنترل LinkButton براي انجام فرآيند Postback نيازمند استفاده از اسكريپت هاي سمت سرويس گيرنده است . كد زيرنحوه استفاده ازكنترل LinkButton را نشان مي دهد . ( پس از كليك بر روي آن يك متن در كنترل label نمايش داده مي شود) .
<%@ Page Language="VB" AutoEventWireup="True" %>
<script language="VB" runat="server"> Sub LinkButton_Click(sender As Object, e As EventArgs) Label1.Text = "You clicked the link button" End Sub </script>
<html> <body> <form runat=server> <h3>LinkButton Example</h3> <asp:LinkButton id="LinkButton1" Text="Test LinkButton" Font-Name="Tahoma" Font-Size="14pt" OnClick="LinkButton_Click" runat="server"/> <p> <asp:Label id=Label1 runat=server /> </form></body></html> |
تحقق برخي از پتانسيل و قابليت هاي صفحات ASP.NET نيز در ارتباط با اسكريپت هاي سمت سرويس گيرنده است و لازم است با نحوه استفاده كنترل هاي سرويس دهنده ASP.NET از اسكريپت هاي سمت سرويس گيرنده آشنا شويم چراكه از اين طريق برداشت ما از نحوه تاثير اسكريپت هاي سمت سرويس گيرنده بر روي صفحات وب ASP.NET شكل واقعي و منطقي خود را پيدا خواهد كرد .
اسكريپت هاي سمت سرويس گيرنده مورد نياز كنترل هاي سرويس دهنده ASP.NET به صورت اتوماتيك به صفحه اضافه مي گردند. توجه داشته باشيد كه اسكريپت سمت سرويس گيرنده كه به صورت اتوماتيك براي كنترل هاي سرويس دهنده ايجاد مي گردد ، مستقل از ساير اسكريپت هاي سمت سرويس گيرنده اي است كه توسط پياده كنندگان نوشته مي گردد .
عناصر زير از اسكريپت هاي سمت سرويس گيرنده استفاده مي نمايند ( كنترل و يا برخي خصلت هاي مرتبط با يك كنترل) :
• كنترل هاي Page .HtmlForm و Panel : خصلت هاي DefaultFocus ، DefaultButton و MaintainScrollPositionOnPostback نيازمند استفاده از اسكريپت هاي سمت سرويس گيرنده مي باشند .
• كنترل هاي LinkButton, ImageButton و HtmlButton از اسكريت هاي سمت سرويس گيرنده به منظور حمايت از رويداد Postback استفاده مي نمايند. توجه داشته باشيد كه كنترل هاي Button Web server control، HtmlInputButton و HtmlInputImage به اسكريت هاي سمت سرويس گيرنده نياز ندارند .
• Calendar : كنترل فوق از كنترل LinkButton به منظور پياده سازي حركت در بين روز ، هفته و ماه استفاده مي نمايد . كنترل LinkButton از اسكريپت هاي سمت سرويس گيرنده براي رويداد postback استفاده مي نمايد . در صورتي كه از كنترل calendar صرفا" به منظور نمايش يك ماه بدون امكان انتخاب و يا حركت استفاده مي گردد ، كنترل فوق نيازي به استفاده از اسكريت هآي سمت سرويس گيرنده ندارد .
• DetailsView : در صورتي كه كنترل شامل دكمه هائي باشد كه به عنوان كنترل هاي LinkButton پيكربندي شده باشند ( براي ويرايش ، paging و ...)، به منظور انجام عمليات فوق از اسكريپت هاي سمت سرويس گيرنده استفاده مي گردد . در صورتي كه خصلت EnablePagingCallbacks فعال و مقدار آن True باشد ، از اسكريپت هاي سمت سرويس گيرنده به منظور مديريت callback استفاده مي گردد .
• GridView : در صورتي كه كنترل شامل دكمه هائي است كه به عنوان كنترل هاي LinkButton پيكربندي شده باشند ( براي ويرايش ، paging و ...) ، به منظور انجام عمليات فوق از اسكريپت هاي سمت سرويس گيرنده استفاده مي گردد . از اسكريپت هاي سمت سرويس گيرنده به منظور مرتب سازي و paging استفاده مي گردد (در صورت حمايت كنترل منبع داده مرتبط با آن ). در صورتي كه خصلت EnablePagingCallbacks فعال و مقدار آن True باشد ، از اسكريپت هاي سمت سرويس گيرنده به منظور مديريت callback استفاده مي گردد .
• Label : خصلت AssociatedControlID به همراه خصلت AccessKey اسكريپت هاي سمت سرويس دهنده اي را در پاسخ به keyboard shortcut توليد مي نمايند. در صورتي كه خصلت هاي فوق مقداردهي نشده باشند ، كنترل Label نيازي به استفاده از اسكريپت هاي سمت سرويس گيرنده ندارد .
• Menu: از اسكريپت هاي سمت سرويس گيرنده براي باز وبستن آيتم هاي منو ، نمايش پانل هاي pop-out و كنترل نمايش زماني كه كاربر اشاره گر موس را بر روي آيتم هاي موجود در منو قرار مي دهد ، استفاده مي گردد .
• TreeView ، از اسكريپت هاي سمت سرويس گيرنده به منظور باز و بستن گره ها استفاده مي نمايد .
• هر نوع كنترل سرويس دهنده اي كه خصلت PostBack آن true باشد : رفتار خصلت AutoPostBack براي كنترل هاي غير button با استفاده از اسكريپت هاي سمت سرويس گيرنده پياده سازي مي گردد .
• كنترل هاي Web Part از اسكريپت هاي سمت سرويس گيرنده به منظور حمايت از Drag-and-drop ، افزودن كنترل هاي Web part به Zones و Verbs و صدور و يا ورود توانمندي ها استفاده مي گردد .
• كنترل هاي Validator ( شامل CompareValidator، CustomValidator ، RangeValidator ، RegularExpressionValidator ، RequiredFieldValidator ) ، از اسكريت هاي سمت سرويس گيرنده به منظور ارائه پاسخ فوري پس از بررسي اعتبار داده استفاده مي نمايند. در صورتي كه سرويس گيرنده از اسكريپت حمايت نمي نمايد ، validation صرفا" بر روي سرويس دهنده اجراء خواهد شد .
• هر متد و يا خصلتي كه بر روي كنترل ها focus مي نمايد ، نظير متد Focus بر روي كنترل ها و متد SetFocus صفحه : از اسكريپت هاي سمت سرويس گيرنده به منظور تنظيم focus بر روي كنترل مورد نظر استفاده مي گردد .
اسكريت هاي سمت سرويس گيرنده مورد نياز براي هر يك از كنترل ها و اعضاء به صورت اتوماتيك توليد و به همراه صفحه ارسال مي گردد .
در برخي موارد ممكن است كاربران امكان استفاده از اسكريپت را در مرورگر خود غيرفعال نمايند ( اقدامي در جهت افزايش ايمني سيستم ) . در صورت انجام اين كار ، نمي توان از پتانسيل هاي ارائه شده توسط اسكريپت هاي سمت سرويس گيرنده استفاده نمود و بديهي است كه برخي كنترل ها نظير كنترل LinkButton ، بطور كامل از كار بيافتد و يا قابليت هاي خصلت AutoPostBack غيرفعال گردد . برخي كنترل ها از وضعيت فوق كمتر متاثر شده و در شرايط خاصي مي توانند عمليات خود را انجام دهند . مثلا" كنترل هاي Validation مي توانند در صورت بروز مشكل در خصوص اجراي اسكريپت هاي سمت سرويس گيرنده ، آنان را سمت سرويس دهنده اجراء نمايند ( با اين تفاوت كه به دليل اجراي آنان بر روي سرويس دهنده به كاربر سريعا" پاسخ داده نمي شود ) .
استفاده از اسكريپت هاي سمت سرويس گيرنده توسط پياده كننده در صفحات ASP.NET
با توجه به اين كه رفتار صفحات ASP.NET در برخي موارد مشابه صفحات HTML است ، مي توان اسكريپت هاي سمت سرويس گيرنده خود را به صفحات ASP.NET اضافه نمود . در صفحات ASP.NET از اسكريپت هاي سمت سرويس گيرنده به منظور پاسخ به رويدادهاي محقق شده در سطح لايه رابط كاربر، حمايت مي گردد . استفاده از اسكريپت هاي سمت سرويس گيرنده در يك صفحه ASP.NET همانند ساير صفحات HTML است . با افزودن يك بلاك script به صفحه امكان نوشتن اسكريپت هاي سمت سرويس گيرنده فراهم مي گردد . پياده كنندگان مي توانند از اسكريپت هاي سمت سرويس گيرنده به منظور نوشتن event handler به منظور پاسخ به رويدادهاي محقق شده در سمت سرويس گيرنده نظير رويداد onload صفحه نيز استفاده نمايند . زماني كه يك صفحه ASP.NET در مرورگر اجراء مي گردد ، با استفاده از اسكريپت هاي سمت سرويس گيرنده مي توان عناصر موجود بر روي صفحه را آدرس دهي و متناسب با رويداد محقق شده ، مديريت آنان را در سمت سرويس گيرنده برعهده گرفت .
استفاده از اسكريپت هاي سمت سرويس گيرنده در صفحات ASP.NET نسبت به صفحات HTML در برخي موارد متفاوت است :
• اضافه كردن event handler سمت سرويس گيرنده به كنترل هاي سرويس دهنده ASP.NET
• مراجعه به كنترل هاي سرويس دهنده از طريق اسكريپت هاي سمت سرويس گيرنده
• افزودن اسكريپت هاي سمت سرويس گيرنده به صفحه به صورت پويا
• ايجاد رويداد كليك سمت سرويس گيرنده براي كنترل هاي سرويس دهنده
• اشتراك اطلاعات بين اسكريپت هاي سمت سرويس گيرنده و كدهاي سمت سرويس دهنده
• فراخواني كدهاي سمت سرويس دهنده از طريق اسكريپت هاي سمت سرويس گيرنده بدون نياز به postback
اضافه كردن event handler سمت سرويس گيرنده به كنترل هاي سرويس دهنده ASP.NET
با توجه به اين كه با كنترل هاي سرويس دهنده ASP.NET در يك صفحه به عنوان element برخورد مي شود (نوع عنصر تفسير شده توسط يك كنترل به زبان نشانه گذاري استفاده شده در يك صفحه بستگي دارد : HTML ، XHTML و يا ... ) ، مي توان اسكريپت هاي سمت سرويس گيرنده event handler را به كنترل ها همانند ساير عناصر موجود در صفحه اضافه نمود . توجه به اين موضوع كه كنترل چگونه خروجي خود را تفسير مي نمايد و كدام خصلت را براي خود رزو نموده است ، حائز اهميت است .
افزودن event handler سمت سرويس گيرنده به صورت تعريفي
از طريق تگ هاي كنترل هاي سرويس دهنده ASP.NET ، مي توان با استفاده از Attributes مقادير مورد نظر خصلت ها را مشخص نمود . مثلا" براي مقداردهي خصلت Text كنترل TextBox ، مي توان از تگ زير استفاده نمود :
<asp:textbox id="TextBox1" runat="server" text="Sample Text" /> |
در صورتي كه از يك attribute استفاده گردد كه نتوان آن را به يك خصلت خاص map نمود ، ASP.NET در زمان پردازش سمت سرويس دهنده از آن صرفنظر نموده و آن را به عنوان as-is به همراه ساير تگ هاي HTML توليد شده براي كنترل سرويس دهنده به مقصد مرورگر ارسال مي نمايد . مثلا" كنترل TextBox داراي خصلتي با نام onKeyup نمي باشد . بنابراين در صورتي كه به همراه كنترل TextBox از خصلت فوق استفاده گردد ، ASP.NET بدون انجام هيچگونه واكنشي آن را براي مرورگر سرويس گيرنده ارسال مي نمايد . با توجه به نحوه برخورد ASP.NET با اينچنين خصلت هائي ، مي توان رويدادهآي مورد نظر را به كنترل هاي سرويس دهنده و از طريق تعريف تگ هاي مربوطه نسبت داد .
كد زير نحوه استفاده از يك event handler سمت سرويس گيرنده به همراه كنترل سرويس دهنده TextBox را نشان مي دهد . پس از درج هر حرف در TextBox ( بروز رويداد ) ، طول آن در يك عنصر span با نام spanCounter نمايش داده مي شود ( event handler ) .
<%@ Page Language="VB"%> <html> <head > <title>تست يك</title> </head> <body> <form id="form1" runat="server"> <asp:textbox id="TextBox1" runat="server" text="Sample Text" onkeyup="spanCounter.innerText=this.value.length;" /> <Span id="spanCounter" /> </form> </body> </html> |
در صورت ضرورت مي توان event handler سمت سرويس گيرنده را در قالب يك تابع سازماندهي تا پس از بروز رويداد ( فشردن يك كليد ) مرتبط با يك كنترل سرويس دهنده ، فعال و وظايف خود را انجام دهد .
<%@ Page Language="VB"%> <html> <head > <title>تست دو</title> <script type="text/javascript"> function DisplayCount(a) { spanCounter.innerText=a.value.length; } </script> </head> <body> <form id="form1" runat="server"> <asp:textbox id="TextBox1" runat="server" text="Sample Text" onkeyup="DisplayCount(this);" /> <Span id="spanCounter" /> </form></body></html> |
افزودن يك event handler سمت سرويس گيرنده از طريق برنامه و در زمان اجراء
در صورت ضرورت مي توان event handler سمت سرويس گيرنده را از طريق برنامه و در زمان اجراء به يك كنترل سرويس دهنده ASP.NET اضافه نمود . استفاده از ويژگي فوق در مواردي مفيد است كه رويداد و يا كد مرتبط با آن به اطلاعاتي نياز دارند كه صرفا" در زمان اجراء قابل دسترسي است . در چنين مواردي مي توان از رويداده Load و يا Init صفحه به منظور اضافه كردن خصلت مورد نظر به يك كنترل استفاده نمود (استفاده از متد Add ) .
كد زير نحوه اضافه كردن يك خصلت به يك كنترل سرويس دهنده در زمان اجراء و به منظور اجراي يك event handler را نشان مي دهد . اسكريپت سمت سرويس گيرنده طول متن تايپ شده در كنترل TextBox را در هر لحظه نمايش مي دهد . در اسكريپت فوق ،فرض شده است كه صفحه داراي يك عنصر span با نام spanCounter است .
<%@ Page Language="VB"%> <html> <head > <title>تست سه</title> <Script RunAt="Server"> Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Dim displayControlName As String = "spanCounter" TextBox1.Attributes.Add("onkeyup", _ displayControlName & ".innerText=this.value.length;") End Sub </Script>
</head> <body> <form id="form1" runat="server"> <asp:textbox id="TextBox1" runat="server" text="Sample Text" /> <Span id="spanCounter" /> </form></body></html> |
افزودن يك رويداد onClick سمت سرويس گيرنده به كنترل سرويس دهنده Button
با كليك بر روي كنترل سرويس دهنده button بلافاصله و به صورت پيش فرض يك postback اتفاق مي افتد تا event handler مرتبط با آن در سمت سرويس دهنده اجراء گردد . در صورت ضرورت مي توان از خصلت OnClientClick كنترل Button ( كنترل هائي نظير Button , LinkButton و ImageButton ) ، به منظور معرفي يك event handler استفاده نمود تا پس از كليك بر روي button ، درابتدا event handler سمت سرويس گيرنده اجراء گردد و در ادامه عمليات postback انجام شود .
كد زير نحوه اضافه كردن يك رويداد كليك سمت سرويس گيرنده به كنترل Button را نشان مي دهد . پس از كليك بر روي Button يك پيام ارائه و در صورت تائيد ، اطلاعات براي سرويس دهنده ارسال مي گردد . ( با كليك اول ، از يك روتين سمت سرويس گيرنده پراي پاسخگوئي به آْن استفاده مي شود و پس از كليك مجدد بر روي Button نمايش داده شده در جعبه محاوره اي ، اطلاعات براي سرويس دهنده ارسال تا متناسب با شرايط برنامه با آنان برخورد شود) .
<%@ Page Language="VB" %> <script runat="server"> Sub Button1_Click(ByVal sender As Object,ByVal e As System.EventArgs) Label1.Text = "Server click handler called." End Sub </script>
<body> <form id="form1" runat="server"> <asp:Button ID="Button1" Runat="server" OnClick="Button1_Click" OnClientClick="return confirm('Ready to submit.')" Text="Test Client Click" /> <br /> <asp:Label ID="Label1" Runat="server" text="" /> </form> </body> </html> |
شناسائي و مراجعه به كنترل هاي سرويس دهنده از طريق اسكريپت هاي سمت سرويس گيرنده
زماني كه يك كنترل سرويس دهنده ASP.NET تفسير مي گردد ، خصلت ClientID آن در بردارنده خصلت هاي Id و name عنصر توليد شده است . ( خصلت ClientID به صورت اتوماتيك و همزمان با مقداردهي به خصلت ID مقدار لازم را خواهد گرفت ) . فرض كنيد با استفاده از نمونه كد زير ، يك كنترل سرويس دهنده ASP.NET را ايجاد كرده باشيم :
<asp:textbox id="TextBox1" runat="server" text="Sample Text" /> |
خصلت ClientID ، مقدار TextBox1 را خواهد گرفت و در نهايت نتايج توليد شده زير براي يك مرورگر مبتني بر HTML ارسال مي گردد :
<input name="TextBox1" type="text" value="Sample Text" id="TextBox1" /> |
بنابراين ، به منظور دستيابي به يك كنترل سرويس دهنده ASP.NET از طريق اسكريپت هاي سمت سرويس گيرنده ، مي توان از خصلت هاي Id و name استفاده نمود . براي آدرس دهي يك كنترل سرويس دهنده ASP.NET توسط اسكريپت هاي سمت سرويس گيرنده ، مي توان از نام كامل آن نيز استفاده نمود ( fully qualified reference ). در صورتي كه كنترل سرويس دهنده فرزند عنصر form در صفحه باشد ، مي توان از گرامر زير به منظور مراجعه به كنترل در اسكريپت هاي سمت سرويس گيرنده استفاده نمود .
<document.forms[0].TextBox1.value = "New value"; |
گرامر واقعي مورد نياز براي مراجعه به يك كنترل سرويس دهنده به نوع كنترل و اين كه آيا كنترل فرزند كنترل ديگري است ، بستگي خواهد داشت .
مراجعه به كنترل ها ئي كه درون ساير كنترل ها قرار دارند
برخي كنترل ها ، كنترل هاي فرزند را درون صفحه تفسير مي نمايند . كنترل هاي GridView, DetailsView, FormView, DataList , Repeater , user controls و Web Parts نمونه هائي در اين زمينه مي باشند . در چنين مواردي ، كنترل فرزند ممكن است داراي يك ID منحصربفرد نباشد چراكه كنترل هاي فرزند در تمپليتي تعريف شده اند كه براي هر سطر نمونه ، كنترل هاي جديدي توليد و يا ممكن است كنترل parent از طريق يك منبع خارجي به صفحه اضافه شده باشد ( نظير كنترل هاي Web part و user ) . كنترل هاي parent به منزله naming containers ميباشند (توسط INamingContainer پياده سازي شده اند ). يك naming containers منحصربفرد بودن IDs كنترل هاي فرزند را تضمين مي نمايد .
مثلا" مي توان يك خصلت ItemTemplate را در كنترل DataList ايجاد و يك كنترل Checkbox را به آن اضافه نمود كه مقدار ID آن CheckEnabled در نظر گرفته شده باشد . در زمان تفسير كنترل DataList ، يك كنترل جديد CheckEnabled براي هر آيتم داده در نظر گرفته مي شود . صفحه تفسير شده نمي بايست شامل چندين نمونه از يك عنصر با نام CheckEnabled باشد ، بنابراين كنترل DataList يك شناسه منحصربفرد برايهر يك از كنترل هاي فرزند خود ايجاد مي نمايد .
شناسه هاي منحصربفرد براي كنترل هاي فرزند يك naming container با بررسي دو خصلت توليد مي گردند . براي هر كنترل فرزند :
• خصلت UniqueID كنترل به عنوان خصلت name در نظر گرفته مي شود .
• خصلت ClientID كنترل به عنوان خصلت Id در نظر گرفته مي شود .
هم ClientID و هم UniqueID بر اساس خصلت ID اوليه توليد مي گردند تا اطلاعات لازم به منظور تضمين منحصربفرد بودن نتايج در يك صفحه تامين گردد .از مقدار ClientID كه در واقع ID عنصر تفسير شده است ، مي توان در اسكريپت هاي سمت سرويس گيرنده استفاده نمود . پس از اجراي يك صفحه حاوي يك naming container و مشاهده Source آن ، مي توان ID توليد شده براي هر يك از كنترل هاي فرزند را مشاهده نمود .