Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

از لحاظ تاریخی، ابزارهای خط فرمان در سیستم های یونیکس بهتر از ویندوز توسعه یافته اند، اما با ظهور یک راه حل جدید، وضعیت تغییر کرده است.

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

PowerShell را می توان در یک زبان تفسیر شده و چند پارادایم اسکریپت نوشت که دارای عناصر برنامه نویسی کلاسیک رویه ای، شی گرا و حتی تابعی است: شاخه بندی شرطی، حلقه ها، متغیرها، آرایه ها، جداول هش، کلاس ها، مدیریت خطا، و همچنین توابع، cmdlet ها و خطوط لوله مقاله قبلی به اصول اولیه کار در محیط اختصاص داده شده بود و اکنون یک کتاب مرجع کوچک برای برنامه نویسان به خوانندگان خود ارائه می دهیم.

شرح:

نظرات
متغیرها و انواع آنها
متغیرهای سیستم
محدوده ها
متغیرهای محیطی (محیط زیست)
عملگرهای محاسباتی و مقایسه ای
اپراتورهای واگذاری
عملگرهای منطقی
پرش مشروط
چرخه ها
آرایه ها
جداول هش
توابع
خطا در پردازش

شما می توانید کد را در هر ویرایشگر متنی یا با استفاده از یک محیط توسعه یکپارچه بنویسید - ساده ترین راه استفاده از Windows PowerShell ISE است که با سیستم عامل های سرور مایکروسافت ارائه می شود. این فقط برای اسکریپت های نسبتاً پیچیده ضروری است: اجرای مجموعه های کوتاه دستورات به صورت تعاملی آسان تر است.

نظرات

استفاده از نظرات بخشی از سبک برنامه نویسی خوب همراه با تورفتگی و فضای خالی مناسب در نظر گرفته می شود:

# Для строчных комментариев используется символ решетки — содержимое строки интерпретатор не обрабатывает.

<# 

       Так обозначаются начало и конец блочного комментария. 
       Заключенный между ними текст интерпретатор игнорирует.

#>

متغیرها و انواع آنها

متغیرها در PowerShell اشیاء نامیده می شوند. نام آنها می تواند شامل کاراکتر زیر خط، و همچنین حروف و اعداد باشد. نماد $ همیشه قبل از نام استفاده می شود و برای اعلام یک متغیر کافی است یک نام معتبر به مفسر بدهید:

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

برای مقداردهی اولیه یک متغیر (تخصیص مقداری به آن)، عملگر تخصیص (نماد =) استفاده می شود:

$test = 100

شما می توانید یک متغیر را با تعیین نوع آن در براکت (نوع عملگر ریخته گری) قبل از نام یا مقدار، اعلام کنید:

[int]$test = 100

$test = [int]100

درک این نکته مهم است که متغیرها در PowerShell اشیا (کلاس‌ها) تمام عیار با ویژگی‌ها و روش‌هایی هستند که انواع آن‌ها بر اساس موارد موجود در NET Core هستند. ما موارد اصلی را لیست می کنیم:

نوع (کلاس NET)

شرح

نمونه کد

[رشته] System.string

رشته یونیکد 

$test = "تست"
$test = "تست"

[char]System.Char

کاراکتر یونیکد (16 بیت)

[char]$test = 'c'

[bool] System.Boolean

نوع بولی (بولی درست یا غلط)

[bool]$test = $true

[int] System.Int32

عدد صحیح سی و دو بیت (32 بیت)

[int]$test = 123456789

[طولانی] System.Int64

عدد صحیح شصت و چهار بیت (64 بیت)

[long]$test = 12345678910

[تک] System.Single

عدد ممیز شناور 32 بیت طول دارد

[single]$test = 12345.6789

[دوبل]سیستم.دوبل

تعداد ممیز شناور به طول 64 بیت (8 بایت)

[دو برابر]$test = 123456789.101112

[اعشاری]سیستم.اعشاری

عدد ممیز شناور 128 بیتی (برای پایان دادن به d ضروری است)

[اعشاری]$تست = 12345.6789d

[DateTime]System.DateTime

تاریخ و زمان 

$test = GetDate

[آرایه] System.Object[]

آرایه ای که شاخص عنصر آن از 0 شروع می شود

$test_array = 1، 2، "test"، 3، 4

[hashtable] System.Collections.Hashtable

جداول هش آرایه‌های ارتباطی با کلیدهای نام‌گذاری شده هستند که بر اساس این اصل ساخته شده‌اند: @{key = "value"}

$test_hashtable = @{one="one"; دو = "دو"; سه = "سه"}

PowerShell از تبدیل نوع ضمنی پشتیبانی می کند، علاوه بر این، اگر به اجبار مشخص نشده باشد، نوع متغیر را می توان در حال تغییر تغییر داد (به عنوان مثال، با استفاده از یک عملگر انتساب)، در این حالت، مفسر خطا می دهد. با فراخوانی متد GetType() می توانید نوع متغیر را از مثال قبلی تعیین کنید:

$test.GetType().FullName

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

تعدادی cmdlet برای دستکاری متغیرها وجود دارد. لیست آنها در یک فرم مناسب با استفاده از دستور نمایش داده می شود:

Get-Command -Noun Variable | ft -Property Name, Definition -AutoSize -Wrap

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

برای مشاهده متغیرهای اعلام شده و مقادیر آنها، می توانید از cmdlet ویژه استفاده کنید:

Get-Variable | more

این روش بیش از حد دست و پا گیر به نظر می رسد، کار با متغیرها از طریق عملگرها یا دسترسی مستقیم به ویژگی ها و روش های آنها بسیار راحت تر است. با این حال، cmdlet ها حق وجود دارند زیرا به شما اجازه می دهند برخی از پارامترهای اضافی را تنظیم کنید. درک این نکته مهم است که متغیرهای کاربر فقط در جلسه جاری تعریف می شوند. هنگامی که کنسول بسته می شود یا اسکریپت به پایان می رسد، آنها حذف می شوند.

متغیرهای سیستم

علاوه بر موارد اعلام شده توسط کاربر، متغیرهای داخلی (سیستم) وجود دارد که پس از پایان جلسه فعلی حذف نمی شوند. آنها به دو نوع تقسیم می شوند، در حالی که داده های حالت PowerShell در متغیرهای خودکار ذخیره می شوند که نمی توانند مقادیر دلخواه را به خودی خود اختصاص دهند. برای مثال، $PWD عبارتند از:

$PWD.Path

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

متغیرهای ترجیحی برای ذخیره تنظیمات برگزیده کاربر مورد نیاز است که مقادیر آنها قابل تغییر است. به عنوان مثال، با استفاده از $ErrorActionPreference، واکنش مفسر دستور به وقوع خطاهای غیر کشنده تنظیم می شود.

علاوه بر عملگرها و cmdlet ها برای دسترسی به متغیرهای اعلام شده، یک متغیر وجود دارد: شبه انباشته. شما می توانید با آن به صورت قیاس با درایوهای دیگر کار کنید، و متغیرها در این مورد شبیه اشیاء سیستم فایل هستند:

Get-ChildItem Variable: | more

یا

ls Variable: | more

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

محدوده ها

برای متغیرها در PowerShell، مفهوم scope (Scope) وجود دارد. عمل دامنه جهانی (Global) برای کل جلسه جاری اعمال می شود - به عنوان مثال، متغیرهای سیستم را شامل می شود. متغیرهای محلی (محلی) فقط در محدوده ای که تعریف شده اند در دسترس هستند: مثلاً در داخل یک تابع. همچنین مفهوم محدوده اسکریپت (Script) وجود دارد، اما برای دستورات اسکریپت، اساساً محلی است. به طور پیش فرض، هنگام اعلان متغیرها، یک محدوده محلی به آنها داده می شود، و برای تغییر آن، به یک ساختار خاص مانند: $Global: variable = value نیاز دارید.

به عنوان مثال، مانند این:

$Global:test = 100

متغیرهای محیطی (محیط زیست)

شبه درایو دیگری به نام Env: از PowerShell در دسترس است و می توان از آن برای دسترسی به متغیرهای محیطی استفاده کرد. هنگامی که پوسته شروع می شود، آنها از فرآیند والد (یعنی از برنامه ای که جلسه فعلی را شروع کرده است) کپی می شوند و معمولاً مقادیر اولیه آنها با مقادیر موجود در کنترل پنل یکسان است. برای مشاهده متغیرهای محیطی، از cmdlet Get-ChildItem یا نام مستعار آن (مستعار): ls و dir استفاده کنید.

dir Env:

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

این متغیرها دنباله ای از بایت ها (یا کاراکترها، در صورت تمایل) هستند که تفسیر آنها فقط به برنامه ای که از آنها استفاده می کند بستگی دارد. cmdlet های *-Variable با متغیرهای محیط کار نمی کنند. برای دسترسی به آنها، باید از پیشوند درایو استفاده کنید:

$env:TEST = "Hello, World!"

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

عملگرهای محاسباتی و مقایسه ای

PowerShell عملگرهای حسابی زیر را ارائه می دهد: + (جمع)، - (تفریق)، * (ضرب)، / (تقسیم)، و % (مدول یا مدول). نتیجه یک عبارت حسابی از چپ به راست مطابق با ترتیب پذیرفته شده عملیات ارزیابی می شود و از پرانتز برای گروه بندی قسمت هایی از عبارت استفاده می شود. فاصله بین اپراتورها نادیده گرفته می شود، آنها فقط برای آسان تر خواندن استفاده می شوند. عملگر + نیز به هم متصل می شود و عملگر * رشته ها را تکرار می کند. اگر بخواهید عددی را به رشته اضافه کنید، به رشته تبدیل می شود. علاوه بر این، زبان PowerShell عملگرهای مقایسه ای زیادی دارد که مطابقت بین دو مقدار را بررسی می کنند و درست یا نادرست بولی را برمی گردانند:

عملگر

شرح

نمونه کد

معادله

برابر / برابر (مشابه = یا == در سایر زبان ها)

$test = 100
$test -eq 123 

-نه

مساوی نیست / مساوی نیست (مشابه <> یا !=)

$test = 100
$test -ne 123   

-بله

بزرگتر از / بیشتر (آنالوگ >)

$test = 100
$test -gt 123

-GE

بزرگتر یا مساوی / بزرگتر یا مساوی (مشابه >=)

$test = 100
$test -ge 123

-آن

کمتر از / کمتر (مشابه <)

$test = 100
$test -lt 123  

کمتر یا مساوی / کمتر یا مساوی (مشابه <=)

$test = 100
$test -le 123

عملگرهای مشابه دیگری وجود دارند که به شما امکان می دهند، برای مثال، رشته ها را بر اساس یک علامت عام مقایسه کنید یا از عبارات منظم برای مطابقت با یک الگو استفاده کنید. در مقالات بعدی به تفصیل به آنها خواهیم پرداخت. نمادهای <، > و = برای مقایسه استفاده نمی شوند زیرا برای اهداف دیگری استفاده می شوند.

اپراتورهای واگذاری

علاوه بر متداول ترین عملگر =، عملگرهای تخصیص دیگری نیز وجود دارد: +=، -=، *=، /= و %=. آنها مقدار را قبل از تخصیص تغییر می دهند. عملگرهای یکنواخت ++ و - که مقدار یک متغیر را افزایش یا کاهش می دهند، رفتار مشابهی دارند - آنها همچنین برای عملگرهای انتساب اعمال می شوند.

عملگرهای منطقی

مقایسه به تنهایی برای توصیف شرایط پیچیده کافی نیست. شما می توانید هر عبارت منطقی را با استفاده از عملگرها بنویسید: -and, -or, -xor, -not and! .. آنها مانند سایر زبان های برنامه نویسی کار می کنند، در حالی که می توانید از پرانتز برای تعیین ترتیب ارزیابی استفاده کنید:

("Тест" -eq "Тест") -and (100 -eq 100)

-not (123 -gt 321) 

!(123 -gt 321)

پرش مشروط

اپراتورهای شعبه در PowerShell استاندارد هستند: IF(IF…ELSE,IF…ELSEIF…ELSE) و SWITCH. بیایید با مثال به کاربرد آنها نگاه کنیم:

[int]$test = 100
if ($test -eq 100) {
      Write-Host "test = 100"
}



[int]$test = 50
if ($test -eq 100) {
       Write-Host "test = 100"
}
else {
      Write-Host "test <> 100"
}



[int]$test = 10
if ($test -eq 100) {
      Write-Host "test = 100"
}
elseif ($test -gt 100) {
      Write-Host "test > 100"
}
else {
       Write-Host "test < 100"
}



[int]$test = 5
switch ($test) {
     0 {Write-Host "test = 0"}
     1 {Write-Host "test = 1"}
     2 {Write-Host "test = 2"}
     3 {Write-Host "test = 3"}
     4 {Write-Host "test = 4"}
     5 {Write-Host "test = 5"}
     default {Write-Host "test > 5 или значение не определено"}
}

چرخه ها

PowerShell چندین نوع حلقه دارد: WHILE، DO WHILE، DO UNTIL، FOR و FOREACH.

یک حلقه با پیش شرط کار می کند اگر/تا زمانی که درست باشد:

[int]$test = 0
while ($test -lt 10) {
      Write-Host $test
      $test = $test + 1
}

حلقه‌های دارای شرط پست حداقل یک بار اجرا می‌شوند، زیرا این شرط پس از تکرار بررسی می‌شود. در عین حال، DO WHILE در حالی که شرط درست است کار می کند و DO تا زمانی که نادرست است کار می کند:

[int]$test = 0
do {
      Write-Host $test
      $test = $test + 1 
}
while ($test -lt 10)



[int]$test = 0
do {
      Write-Host $test
      $test = $test + 1 
}
until ($test -gt 9)

تعداد تکرارهای حلقه FOR از قبل مشخص است:

for ([int]$test = 0; $test -lt 10; $test++) {
       Write-Host $test
}

در حلقه FOREACH، روی عناصر یک آرایه یا مجموعه (جدول هش) تکرار می شود:

$test_collection = "item1", "item2", "item3"
foreach ($item in $test_collection)
{
        Write-Host $item
}

آرایه ها

متغیرهای PowerShell نه تنها اشیاء منفرد (عدد، رشته و غیره)، بلکه چندین مورد را نیز ذخیره می کنند. ساده ترین نوع چنین متغیرهایی آرایه ها هستند. یک آرایه می تواند از چندین عنصر تشکیل شده باشد، یک عنصر، یا خالی باشد، یعنی. حاوی هیچ عنصری نیست با استفاده از عملگر @() اعلام شده است که در مقاله بعدی به آن نیاز خواهیم داشت - برای افزودن آرایه های دیگر به یک آرایه (ایجاد آرایه های چند بعدی)، ارسال آرایه ها به توابع به عنوان آرگومان و کارهای مشابه بسیار مهم است:

$test_array = @() #создаем пустой массив

هنگامی که یک آرایه مقداردهی اولیه می شود، مقادیر آن با کاما از هم جدا می شوند (اپراتور ویژه):

$test_array = @(1, 2, 3, 4) # создаем массив из четырех элементов 

در بیشتر موارد، عملگر @() را می توان حذف کرد:

$test_array = 1, 2, 3, 4

در این حالت، آرایه ای از یک عنصر به صورت زیر مقداردهی اولیه می شود

$test_array = , 1

عناصر آرایه با استفاده از یک شاخص عدد صحیح مبتنی بر صفر و عملگر شاخص (براکت های مربع) قابل دسترسی هستند:

$test_array[0] = 1

می توانید چندین نمایه را مشخص کنید که با کاما از هم جدا شده اند. مکرر:

$test_array = "один", "два", "три", "четыре"
$test_array[0,1,2,3]
$test_array[1,1,3,3,0]

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

عملگر .. (دو نقطه - عملگر محدوده) آرایه ای از اعداد صحیح را در محدوده بالا و پایین مشخص شده برمی گرداند. برای مثال عبارت 1..4 آرایه ای از چهار عنصر @(1، 2، 3، 4) و عبارت 8..5 یک آرایه @(8، 7، 6، 5) را خروجی می دهد.

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

با استفاده از عملگر محدوده، می توانید یک آرایه را مقداردهی اولیه کنید ($test_array = 1..4) یا یک برش (slice) دریافت کنید. دنباله ای از عناصر از یک آرایه با شاخص هایی از آرایه دیگر. در این حالت، یک عدد منفی -1 نشان دهنده آخرین عنصر آرایه، -2 - ماقبل آخر و غیره است.

$test_array = "один", "два", "три", "четыре"
$test_array[0..2]
$test_array[2..0]
$test_array[-1..0]
$test_array[-2..1]

توجه داشته باشید که مقادیر آرایه عدد صحیح می تواند از حداکثر مقدار شاخص آرایه داده بیشتر باشد. در این حالت، تمام مقادیر تا آخرین مقدار برگردانده می شوند:

$test_array[0..100]

اگر سعی کنید به یک عنصر آرایه ای که وجود ندارد دسترسی پیدا کنید، $null برگردانده می شود.

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

در PowerShell، آرایه‌ها می‌توانند عناصری از انواع مختلف داشته باشند یا به شدت تایپ شوند:

$test_array = 1, 2, "тест", 3, 4
for ([int]$i = 0; $i -lt $test_array.count; $i++)
{
          Write-Host $test_array[$i]
}

جایی که ویژگی $test_array.count تعداد عناصر آرایه است.

نمونه ای از ایجاد یک آرایه با تایپ قوی:

[int[]]$test_array = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

جداول هش

یکی دیگر از انواع اصلی متغیرها در زبان PowerShell، جداول هش هستند که به عنوان آرایه های انجمنی نیز شناخته می شوند. Hashtable ها مشابه اشیاء JSON هستند و بر اساس ارزش کلیدی ساخته می شوند. برخلاف آرایه‌های معمولی، عناصر آن‌ها با کلیدهای نام‌گذاری شده، که ویژگی‌های شی هستند، قابل دسترسی هستند (می‌توانید از عملگر شاخص - براکت‌های مربع نیز استفاده کنید).

یک جدول هش خالی با استفاده از نماد @ و براکت های عملگر اعلام می شود:

$test_hashtable = @{}

هنگام اعلام، می توانید بلافاصله کلیدها را ایجاد کرده و مقادیری را به آنها اختصاص دهید:

$test_hashtable = @{one="один"; two="два"; three="три"; "some key"="some value"}

برای افزودن یک عنصر به جدول هش، باید کلیدی را که هنوز وجود ندارد به آن اختصاص دهید یا از متد Add () استفاده کنید. اگر به یک کلید موجود تخصیص داده شود، مقدار آن تغییر خواهد کرد. متد Remove() برای حذف یک عنصر از جدول هش استفاده می شود.

$test_hashtable."some key"
$test_hashtable["some key"]
$test_hashtable.Add("four", "четыре")
$test_hashtable.five = "пять"
$test_hashtable['five'] = "заменяем значение"
$test_hashtable.Remove("one")

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

متغیرهای این نوع را می توان به عنوان آرگومان به توابع و cmdlet ها منتقل کرد - در مقاله بعدی نحوه انجام این کار را مطالعه خواهیم کرد و همچنین نوع مشابه دیگری - PSCustomObject را در نظر خواهیم گرفت.

توابع

PowerShell همه چیزهایی را که برای برنامه نویسی رویه ای نیاز دارید، از جمله توابع، دارد. برای توصیف آنها از کلمه تابع Function استفاده می شود که پس از آن باید نام تابع و بدنه محصور شده در براکت های عملگر را مشخص کنید. اگر نیاز به ارسال آرگومان‌هایی به تابع دارید، می‌توانید بلافاصله بعد از نام داخل پرانتز آن‌ها را مشخص کنید.

function имя-функции (аргумент1, ..., аргументN) 
{ 
        тело-функции 
} 

تابع همیشه یک نتیجه را برمی گرداند - آرایه ای از نتایج تمام عبارات آن است، اگر بیش از یک وجود داشته باشد. اگر فقط یک دستور وجود داشته باشد، تنها مقدار نوع مربوطه برگردانده می شود. ساختار return $value عنصری با مقدار $value به آرایه نتیجه اضافه می‌کند و اجرای لیست دستورات را لغو می‌کند و تابع خالی $null را برمی‌گرداند.

به عنوان مثال، بیایید یک تابع برای مربع کردن یک عدد ایجاد کنیم:

function sqr ($number)
{
      return $number * $number
}

توجه داشته باشید که در بدنه یک تابع، می‌توانید از هر متغیری که قبل از فراخوانی آن اعلام شده است استفاده کنید، و فراخوانی توابع در PowerShell ممکن است غیرعادی به نظر برسد: آرگومان‌ها (در صورت وجود) در داخل پرانتز قرار نمی‌گیرند و با فاصله از هم جدا می‌شوند.

sqr 2

یا:

sqr -number 2

به دلیل نحوه ارسال آرگومان‌ها، گاهی اوقات خود تابع باید در پرانتز قرار گیرد:

function test_func ($n) {}
test_func -eq $null     # функция не вызывалась
(test_func) -eq $null   # результат выражения — $true

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

هنگام توصیف یک تابع، می توانید مقادیر پیش فرض را به آرگومان ها اختصاص دهید:

function func ($arg = value) {
         #тело функции
}

دستور دیگری برای توصیف آرگومان های تابع وجود دارد، علاوه بر این، پارامترها را می توان از خط لوله خواند - همه اینها در مقاله بعدی مفید خواهد بود، وقتی به ماژول های صادر شده نگاه می کنیم و cmdlet های خود را ایجاد می کنیم.

خطا در پردازش

PowerShell دارای مکانیزم Try...Catch... در نهایت برای رسیدگی به استثناها است. بلوک Try حاوی کدی است که ممکن است خطا در آن رخ دهد و بلوک Catch حاوی کنترل کننده آن است. اگر خطایی وجود نداشته باشد، اجرا نمی شود. بعد از بلوک Try بدون توجه به بروز خطا، بلوک آخر اجرا می شود و می تواند چندین بلوک Catch برای انواع مختلف استثنا وجود داشته باشد. خود استثنا روی یک متغیر پیش‌فرض اعلام‌نشده ($_) نوشته می‌شود و به راحتی قابل بازیابی است. در مثال زیر، ما محافظت در برابر وارد کردن یک مقدار نامعتبر را اجرا می کنیم:

try {

        [int]$test = Read-Host "Введите число"
        100 / $test

} catch {

         Write-Warning "Некорректное число"
         Write-Host $_

}

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

این به بررسی مبانی برنامه نویسی در زبان پاورشل می پردازد. در مقالات بعدی کار با متغیرهای مختلف، مجموعه ها، عبارات منظم، ایجاد توابع، ماژول ها و cmdlet های سفارشی و همچنین برنامه نویسی شی گرا را با جزئیات بیشتری مطالعه خواهیم کرد.

Windows PowerShell چیست و با چه چیزی خورده می شود؟ بخش دوم: مقدمه ای بر زبان برنامه نویسی

منبع: www.habr.com

اضافه کردن نظر