جستجو برای:
سبد خرید 0
  • صفحه اصلی
  • دوره‌های آموزشی
  • وبلاگ
  • درباره ما
  • قوانین و مقررات
  • همکاری با ما
  • تماس با ما
محتوای باز
ورود
[suncode_otp_login_form]
گذرواژه خود را فراموش کرده اید؟
عضویت
[suncode_otp_registration_form]
  • خانه
  • کتاب آنلاین
  • درباره سایت
  • درباره لوگو
  • تماس با ما
محتوای باز
  • صفحه اصلی
  • دوره‌های آموزشی
  • وبلاگ
  • درباره ما
  • قوانین و مقررات
  • همکاری با ما
  • تماس با ما
شروع کنید
آخرین اطلاعیه ها
لطفا برای نمایش اطلاعیه ها وارد شوید
0
[wcas-search-form]

خواندن ورودی صفحه کلید در اسکریپت‌نویسی

28 بهمن 1403
ارسال شده توسط فرشید نوتاش حقیقت
خط فرمان، گنو/لینوکس

اسکریپتی که تا اینجا نوشتیم فاقد یک ویژگی رایج در برنامه‌ها می‌باشد. این ویژگی تعامل (Interactivity) نام دارد. یعنی توانایی اینکه برنامه با کاربر تعامل داشته باشد. در حالیکه بسیاری از برنامه‌ها نیاز ندارند تا تعاملی باشند ولی در مقابل برنامه‌های زیادی از این قابلیت سود می‌برند و از این طریق به صورت مستقیم داده را از کاربر قبول می‌کنند.

برای مثال این اسکریپت را از فصل قبل به یاد بیاورید:

#!/bin/bash

# test-integer2: evaluate the value of an integer.

INT=-5

if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
    if [ $INT -eq 0 ]; then
        echo "INT is zero."
    else
        if [ $INT -lt 0 ]; then
            echo "INT is negative."
        else
            echo "INT is positive."
        fi
        if [ $((INT % 2)) -eq 0 ]; then
            echo "INT is even."
        else
            echo "INT is odd."
        fi
    fi
else
    echo "INT is not an integer." >&2
    exit 1
fi

هر زمان که می‌خواهیم مقدار INT را تغییر دهیم بایستی اسکریپت را ویرایش کنیم. در حالیکه اگر اسکریپت هر بار برای مقدار مورد نظر از کاربر سوال کند بسیار بهتر خواهد بود. در این درس ما یاد می‌گیریم که چگونه قابلیت تعاملی را به برنامه‌های خود اضافه کنیم.

فرمان read – خواندن مقادیر از ورودی استاندارد

فرمان read یک فرمان درون ساخت شل (Shell Balls-in Command) که به منظور خواندن یک خط از ورودی استاندارد به کار می‌رود. این فرمان را می‌توان به‌منظور خواندن ورودی صفحه کلید یا زمانی که هدایت و تغییر مسیر یک خط از داده را از یک قابل به کار گرفته می‌گیرد. استفاده کرد.

read [-options] [variable...]

که در این فرمان options یکی از گزینه‌های موجود لیست شده در جدول زیر هست و variable نام یک یا چند متغیر استفاده شده به منظور نگهداری مقدار ورودی میباشد. اگر هیچ نام متغیری ارایه نشده باشد. متغیر شل REPLY ارایه می‌شود.

گزینهتوضیحات
-a arrayاختصاص ورودی به آرایه که با ایندکس صفر آغاز می‌شود.
-d delimiterاولین کاراکتر در رشته delimiter (جداکننده) استفاده شده تا پایان ورودی را نشان دهد.
-eاستفاده از readline برای بکارگیری ورودی. این گزینه موجب می‌شود که ویرایش ورودی به همان شیوه خط فرمان امکان‌پذیر شود.
-n numخواندن کاراکترهای num از ورودی به جای کل خط
-p promptنمایش یک پیام‌واره برای ورودی با استفاده از رشته prompt
-rRaw mode. کاراکترهای بک‌اسلش را به‌عنوان کاراکتر Escape در نظر نگیر.
-sSilent mode. کاراکترها را در صفحه‌نمایش چاپ نکن/ این کار زمان وارد کردن پسوردها مفید خواهد بود.
-t secondsTimeout. پایان دادن ورودی پس از چند seconds. فرمان read یک وضعیت خروج غیر از صفر را بازمی‌گرداند.
-u fdاستفاده از ورودی توصیف‌کننده فایل fd به جای ورودی استاندارد.

اساسا فرمان read فیلدها را از ورودی استاندارد به متغیرهای تعیین شده اختصاص می دهد. اگر که اسکریپت ارزیابی عدد صحیح خود را به منظور استفاده از فرمان read تغییر دهیم. به صورت زیر می‌شود:

#!/bin/bash

# read-integer: evaluate the value of an integer.

echo -n "Please enter an integer -> "
read int

if [[ "$int" =~ ^-?[0-9]+$ ]]; then
    if [ $int -eq 0 ]; then
        echo "$int is zero."
    else
        if [ $int -lt 0 ]; then
            echo "$int is negative."
        else
            echo "$int is positive."
        fi
        if [ $((int % 2)) -eq 0 ]; then
            echo "$int is even."
        else
            echo "$int is odd."
        fi
    fi
else
    echo "Input value is not an integer." >&2
    exit 1
fi

ما از فرمان echo به همراه گزینه -n که از ایجاد خط جدید در ادامه جلوگیری می‌کند برای نمایش یک پیام‌ واره (Prompt) و سپس از read استفاده کرده تا یک مقدار برای متغیر 100 وارد کنیم. فرمان را به صورت زیر اجرا می‌کنیم:

[me@linuxbox ~]$ read-integer
Please enter an integer -> 5
5 is positive.
5 is odd.

Read می‌تواند ورودی را به چندین متغیر اختصاص دهد درست مثل زیر:

#!/bin/bash

# read-multiple: read multiple values from keyboard

echo -n "Enter one or more values > "
read var1 var2 var3 var4 var5

echo "var1 = '$var1'"
echo "var2 = '$var2'"
echo "var3 = '$var3'"
echo "var4 = '$var4'"
echo "var5 = '$var5'"

در این اسکریپت می‌توانیم چهار مقدار را نمایش و اختصاص دهیم. توجه کنید چگونه read تعداد متفاوتی از مقادیر را دریافت می‌کند:

[me@linuxbox ~]$ read-multiple
Enter one or more values > a b c d e
var1 = 'a'
var2 = 'b'
var3 = 'c'
var4 = 'd'
var5 = 'e'
[me@linuxbox ~]$ read-multiple
Enter one or more values > a
var1 = 'a'
var2 = ''
var3 = ''
var4 = ''
var5 = ''
[me@linuxbox ~]$ read-multiple
Enter one or more values > a b c d e f g
var1 = 'a'
var2 = 'b'
var3 = 'c'
var4 = 'd'
var5 = 'e f g'

اگر فرمان read تعداد کمتر از میزانی که توقع داریم را دریافت کند. دیگر متغیرها خالی هستند. در حالیکه مقدار زیادی از نتایج ورودی در متغیر نهایی حاوی دیگر ورودی های اضافی هستند. اگر هیچ متغیری پس از فرمان read لیست نشده باشد. یک متغير شل (متغیر REPLY) همه ورودی‌ها را دریافت خواهد کرد:

#!/bin/bash

# read-single: read multiple values into default variable

echo -n "Enter one or more values > "
read

echo "REPLY = '$REPLY'"

اجرای نتایج اسکریپت در این:

[me@linuxbox ~]$ read-single
Enter one or more values > a b c d
REPLY = 'a b c d'

گزینه‌ها

فرمان read از گزینه هایی که در جدول قبلی در درس قبل پشتیبانی می‌کنند. با استفاده از گزینه‌های مختلف می‌توانیم کارهای جالبی را با read انجام دهیم. برای مثال با گزینه -p میتوانیم یک رشته پیام‌واره (Prompt) را فراهم کنیم:

#!/bin/bash

# read-single: read multiple values into default variable

read -p "Enter one or more values > "

echo "REPLY = '$REPLY'"

با استفاده از گزینه -t و گزینه -s می‌توانیم اسکریپتی که ورودی “secrets” را میخواند بنویسیم و در صورتی که ورودی در زمان تعیین شده کامل نشود یک زمان اضافی مجدد تعیین کند:

#!/bin/bash

# read-secret: input a secret passphrase

if read -t 10 -sp "Enter secret passphrase > " secret_pass; then
    echo -e "\nSecret passphrase = '$secret_pass'"
else
    echo -e "\nInput timed out" >&2
    exit 1
fi

اسکریپت کاربر را متوقف کرده تا عبارت secret را وارد کند و برای ورودی ۱۰ ثانیه صبر می‌کند. اگر که ورودی در این زمان تعیین شده کامل نشود. اسکریپت خارج می‌شود و یک پیام خطا نمایش می‌دهد. از آنجایی که گزینه شامل شده است. کاراکترهای عبارت همانطور که وارد می‌شوند در صفحه‌نمایش نشان داده نمی‌شوند.

جدا کردن فیلدهای ورودی با IFS

به طور طبیعی، Shell جداسازی کلمات را ورودی که به read داده می‌شود انجام می‌دهد. همانطور که دیدیم. به این معنی است که چندین کلمه با یک یا چند فاصله تبدیل به آیتم‌هایی جدا در خط ورودی می‌شوند و توسط read به متغیرهای جداگانه‌ای تبدیل می‌شوند. این رفتار بوسیله یک متغیر شل (Shell Variable) که IFS نامیده می‌شود انجام می‌شود. مقدار پیشفرض IFS حاوی یک فاصله یک‌ tab و یک کاراکتر خط جدید است که هر کدام آیتم ها را از یکدیگر جدا می‌کنند.

ما می‌توانیم مقدار متغیر IFS را تغییر دهیم تا جداسازی فیلدهای ورودی به دستور read را کنترل کنیم. برای مال مسیر etc/passwd/ حاوی خطوطی از داده است که از کاراکتر دو نقطه به منظور جداسازی فیلدها استفاده می‌کند. با تغییر مقدار متغیر IFS به یک نقطه می‌توانیم از دستور read به منظور وارد کردن محتویات etc/passwd و جداسازی موفقیت‌آمیز فیلدها به متغیرهای متفاوت استفاده کنیم. در اینجا اسکریپتی داریم که این کار را انجام می‌دهد:

#!/bin/bash

# read-ifs: read fields from a file

FILE=/etc/passwd

read -p "Enter a username > " user_name

file_info=$(grep "^$user_name:" $FILE)

if [ -n "$file_info" ]; then
    IFS=":" read user pw uid gid name home shell <<< "$file_info" 􀁙
    echo "User = '$user'"
    echo "UID = '$uid'"
    echo "GID = '$gid'"
    echo "Full Name = '$name'"
    echo "Home Dir. = '$home'"
    echo "Shell = '$shell'"
else
    echo "No such user '$user_name'" >&2
    exit 1
fi

این اسکربیت کاربر را به منظور وارد کردن نام کاربر حساب خود در سیستم متوقف کرده و سپس فیلدهای متفاوتی که در رکورد کاربر پیدا شده در فایل etc/passwd/ را نمایش می‌دهد. اسکریپت دارای دو خط جالب توجه است.
file_info=$(grep “^$user_name:” $FILE)
اولی که نتایج دستور grep را به متغیر file_info اختصاص می‌دهد. عبارت منظمی که توسط grep استفاده شده اطمینان حاصل می‌کنند که نام کاربری فقط با یک خط در فایل etc/passwd/ مطابقت دارد.

دومین خط جالب توجه “$file_info” ]; then
IFS=”:” read user pw uid gid name home shell <<< “$file_info” شامل از سه بخش است: یک اختصاص متغیر، یک فرمان read به همراه لیستی از اسامی متغیرها به عنوان آرگومان و یک عملگر هدایت جدید عجیب ابتدا نگاهی به اختصاص متغیر می‌اندازیم.

شل (Shell) اجازه اختصاص یک یا چند متغیر بلافاصله قبل از فرمان را می‌دهد. این اختصاص‌ها محیط را برای فرمان پس از آن تغییر می‌دهد. تاثیر اختصاص موقتی است و محیط را فقط برای دوره زمانی فرمان تغییر می‌دهد. در مثال ما مقدار IFS به یک کاراکتر نقطه تغییر کرده به روش دیگر می‌توانیم کد زیر را داشته باشیم:

OLD_IFS="$IFS"
IFS=":"
read user pw uid gid name home shell <<< "$file_info"
IFS="$OLD_IFS"

که در آن مقدار متغیر IFS را تعیین میکنیم فرمان read را اجرا می‌کنیم و سپس مقدار IFS را مجدد به مقدار اولیه بازیابی می‌کنیم. واضح است که قرار دادن اختصاص متغیر در جلو فرمان شیوه‌ای کوتاهتر برای انجام این کار است. عملگر >>> نشان دهنده یک here string است. here string درست شبیه یک here document است فقط کوتاهتر است و فقط شامل یک رشته می‌باشد. در مثال ما خط داده از فایل etc/passwd/ به ورودی استاندارد فرمان read تغذیه می‌شود . شاید تعجب کنید که چرا این شیوه عجیب غریب را برای وارد کردن داده استفاده کرده‌ایم؟ چرا به جای آن از شیوه زیر استفاده نکردیم؟

echo "$file_info" | IFS=":" read user pw uid gid name home shell

دلیل آن این است که دستور read را نمی‌توان پایپ کرد.

اعتبارسنجی ورودی

با اضافه کردن قابلیت جدید حالت تعاملی در برنامه‌ها و دریافت ورودی از کاربر از طریق صفحه کلید با یک چالش جدید روبرو می‌شویم و آن اعتبارسنجی داده‌های ورودی است. در بسیاری از مواقع تفاوت بین یک کدنویسی خوب با یک کد بد به توانایی برنامه‌نویس در مواجهه با موقعیت‌های غیرمنتظره برمی‌گردد.

اغلب اوقات این موقعیت‌های ناخوشایند و غیرمنتظره زمان وارد کردن داده‌های نابهنجار خود را نشان می‌دهند. در درس قبلی زمانی که مقادیر عدد صحیح را بررسی می‌کردیم و حتی مقادیر خالی و کاراکترهای غیرعددی را بررسی می‌کردیم. در حقیقت داشیتم برنامه را ارزیابی می‌کردیم.

این نوع کارها در زمان نوشتن برنامه بسیار ضروری هستند چرا که برنامه‌هایی که داده‌های ورودی را دریافت می‌کنند نیاز به یک محافظ و گارد ورودی دارند تا داده‌های نامعتبر برنامه را از بین نبرد. این کار بویژه برای برنامه‌هایی که بین چندین کاربر به اشتراک گذاشته می‌شود ضروری است. حتی زمانی که خود برنامه می‌خواهد وظایفی مثل حذف داده را انجام دهد. قرار دادن این محافظ‌ها قبل از اجرای دستور حذف و انجام اعتبارسنجی کاری حیاتی به شمار می‌رود. در اینجا برنامه‌ای نمونه را آورده‌ایم که انواع مختلف اعتبارسنجی بر روی داده‌های ورودی را انجام می‌دهد:

#!/bin/bash

# read-validate: validate input


invalid_input () {
    echo "Invalid input '$REPLY'" >&2
    exit 1
}

read -p "Enter a single item > "

# input is empty (invalid)
[[ -z $REPLY ]] && invalid_input

# input is multiple items (invalid)
(( $(echo $REPLY | wc -w) > 1 )) && invalid_input

# is input a valid filename?
if [[ $REPLY =~ ^[-[:alnum:]\._]+$ ]]; then
    echo "'$REPLY' is a valid filename."
    if [[ -e $REPLY ]]; then
        echo "And file '$REPLY' exists."
    else
        echo "However, file '$REPLY' does not exist."
    fi

    # is input a floating point number?
    if [[ $REPLY =~ ^-?[[:digit:]]*\.[[:digit:]]+$ ]]; then
        echo "'$REPLY' is a floating point number."
    else
        echo "'$REPLY' is not a floating point number."
    fi

    # is input an integer?
    if [[ $REPLY =~ ^-?[[:digit:]]+$ ]]; then
        echo "'$REPLY' is an integer."
    else
        echo "'$REPLY' is not an integer."
    fi
else
    echo "The string '$REPLY' is not a valid filename."
fi

این اسکریپت از کاربر میخواهد که یک آیتم را وارد کنند. آیتم متعاقبا آنالیز شده تا محتویات آن شناسایی شود. همانطور که می بینیم این اسکربیت مفاهیم زیادی را شامل می‌شود که تا اینجا کار آنها را توضیح داده‌ایم.

برنامه‌های دارای منو (Menu Driven Programs)

یک نوع از ویژگی‌های رایج تعاملی menu driven نامیده میشود. یعنی برنامه‌های دارای منو در برنامه‌های دارای منو، کاربر با لیستی از انتخاب‌ها که همان منوهاست مواجه میشود و از وی درخواست می‌شود که یک منو را انتخاب کند. برای مثال ما می‌توانیم برنامه‌ای را فرض کنیم که موارد زیر را به ما ارایه می‌کند:

Please Select:

1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit

Enter selection [0-3] >

با توجه به آنچه در نوشتن برنامه sys_info_page یاد گرفتیم. اکنون می‌توانیم یک برنامه منو دار برای انجام وظایف بالا ایجاد کنیم. با استفاده از کد زیر:

#!/bin/bash

# read-menu: a menu driven system information program

clear
echo "
Please Select:

1. Display System Information
2. Display Disk Space
3. Display Home Space Utilization
0. Quit
"

read -p "Enter selection [0-3] > "

if [[ $REPLY =~ ^[0-3]$ ]]; then
    if [[ $REPLY == 0 ]]; then
        echo "Program terminated."
        exit
    fi
    if [[ $REPLY == 1 ]]; then
        echo "Hostname: $HOSTNAME"
        uptime
        exit
    fi
    if [[ $REPLY == 2 ]]; then
        df -h
        exit
    fi
    if [[ $REPLY == 3 ]]; then
        if [[ $(id -u) -eq 0 ]]; then
            echo "Home Space Utilization (All Users)"
            du -sh /home/*
        else
            echo "Home Space Utilization ($USER)"
            du -sh $HOME
        fi
        exit
    fi
else
    echo "Invalid entry." >&2
    exit 1
fi

این اسکریپت به صورت منطقی به دو بخش تقسیم شده است. بخش اول منو را نمایش می‌دهد و پاسخ مورد نظر را از کاربر دریافت می‌کنند و بخش دوم پاسخ را شناسایی می‌کند و گزینه انتخاب شده را به کار می‌گیرد. به استفاده از دستور exit در این اسکریپت توجه داشته باشید. در اینجا به کار رفته تا از اجرای غیرضروری کند جلوگیری به عمل آورد. حضور چندین است در برنامه در کل ایده خوبی نیست و باعث می شود مفهوم برنامه پیچیده‌تر شود ولی در این اسکربیت وظیفه خود را به خوبی انجام می‌دهد.

درباره فرشید نوتاش حقیقت

همیشه نیازمند یک منبع آموزشی فارسی در حوزه نرم‌افزارهای آزاد/ متن‌باز و سیستم‌عامل گنو/لینوکس بودم. از این رو این رسالت رو برای خودم تعریف کردم تا رسانه «محتوای باز» رو بوجود بیارم.

نوشته‌های بیشتر از فرشید نوتاش حقیقت
قبلی کنترل جریان با if در اسکریپت‌نویسی
بعدی کنترل جریان: ایجاد حلقه با while و until در اسکریپت‌نویسی

دیدگاهتان را بنویسید لغو پاسخ

این سایت از اکیسمت برای کاهش جفنگ استفاده می‌کند. درباره چگونگی پردازش داده‌های دیدگاه خود بیشتر بدانید.

جستجو
جستجو برای:
دسته‌بندی موضوعی مقالات
  • برنامه‌نویسی
    • پایتون
    • دواپس
  • پایگاه‌داده
    • MariaDB
    • MySQL
  • تجارت الکترونیک
    • بازاریابی اینترنتی
    • دیجیتال مارکتینگ
    • شبکه‌های اجتماعی
  • جامعه کاربری
    • لاگ
  • دسته‌بندی نشده
  • شبکه و امنیت
  • طراحی وب
    • سئو
    • سیستم مدیریت محتوا
      • وردپرس
  • فناوری‌های نوظهور
    • اینترنت اشیاء
    • رایانش ابری
      • OpenStack
    • کلان‌داده‌ها
  • گنو/لینوکس
    • توزیع
      • CentOS
      • اوبونتو
      • دبیان
      • فدورا
    • چیست
    • خط فرمان
  • مهاجرت به آزاد/متن‌باز
  • نرم‌افزار
    • اداری
      • لیبره آفیس
        • ایمپرس
        • بیس
        • دراو
        • رایتر
        • کالک
    • کاربردی
    • گرافیک و انیمیشن
      • بلندر
      • گیمپ
نماد الکترونیکی (اینماد)
پرداخت‌یار

محتوای باز؛ مرجع آموزشی نرم‌افزارهای آزاد/ متن‌باز

از اینکه قصد همکاری با رسانه «محتوای باز» را دارید بسیار خرسندیم و این مایه مباهات ماست.

نحوه همکاری با ما چندان پیچیده نیست و شرایط آن در ادامه، ارائه گردیده است.

دستمزد مدرسین

پیش از بیان شرایط ضبط ویدئو شایان ذکر است اشاره‌ای به دستمزد مدرسین سایت داشته باشیم.

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

صرف نظر از هر حالت ممکنه، می‌بایست شرایطی که در ادامه ذکر شده‌اند را رعایت کرده باشید.

در حالت اول (رایگان) رسانه محتوای باز (Open Content)، نه وجهی از شما برای نشر ویدئو می‌گیرد و نه وجهی به شما پرداخت می‌نماید و دوره آموزشی شما را به رایگان منتشر می‌کند.

اما در حالت بعدی طریقه همکاری به روش درآمد از فروش خواهد بود، به گونه‌ای که 70 درصد از کل مبلغ فروش دوره آموزشی متعلق به مدرس دوره بوده و 30 درصد مابقی به رسانه محتوای باز تعلق می‌گیرد.

شرایط کلی ضبط دوره آموزشی

دوره آموزشی مربوطه، صرف نظر از هر محتوایی که دارد می‌بایست در یکی از توزیعات گنو/لینوکسی ضبط شده باشد. (به‌عنوان مثال دوره دروپال در اوبونتو، دوره آموزشی کار با آردوینو در دبیان و امثالهم). اگر دوره آموزشی شما در محیط ویندوز و یا هر پلتفرم/سیستم‌عامل دیگری ضبط شده باشد از همکاری با شما معذوریم.

پیشنهاد می‌گردد برای ضبط دوره آموزشی در توزیع گنو/لینوکس از ابزار قدرتمند OBS استفاده نمایید. البته این صرفا یک پیشنهاد است و شما می‌توانید از هر ابزار مناسب دیگری برای این کار بهره ببرید.

برای آشنایی یا تسلط بیشتر می‌توانید دوره رایگان آموزش OBS محمد عابدینی را ببینید:

مشاهده دوره آموزش OBS
شرایط کیفی ضبط دوره آموزشی

کیفیت صدا از اهمیت ویژه‌ای برخوردار می‌باشد و می‌بایست فاقد هر گونه نویز یا صدای اضافی دیگری (صدای محیط پیرامون) باشد.

دوره آموزشی تهیه شده صرفا باید برای رسانه محتوای باز تدوین شده باشد و در هیچ سایت مشابه دیگری قرار نگرفته باشد.

از قرار دادن موسیقی متن، در بک‌گراند دوره آموزشی شدیدا پرهیز کنید. این کار موجب حواس‌پرتی مخاطب و ضعیف شدن صدای مدرس می‌گردد.

دوره آموزشی ضبط شده می‌باید فاقد هر گونه لوگو یا آدرس سایت دیگری (در گوشه تصویر یا بک‌گراند صفحه دسکتاپ و هر جای دیگری) باشد.

در حین دوره، مدرس نباید به برند خاصی اشاره کند که جز رقبای ما به‌شمار می‌آیند.

مدرس باید در ابتدا در اواسط و در انتهای دوره به برند ما یعنی رسانه محتوای باز (Open Content) بصورت کلامی اشاره نماید.

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

قبل از تدوین دوره آموزشی حتما با ما در تماس باشید و یک ویدیوی چنددقیقه‌ای (ترجیحا 5 الی 10 دقیقه)، بصورت نمونه‌کار برای ما بفرستید.

از همکاری با شما سپاسگزاریم.

فراخوان همکاری