You are here

داده‌های خام

Subscribe to داده‌های خام feed
در تکاپوی پردازش جرعه‌ای از این جام پُر داده
Updated: 2 ساعت 49 دقیقه پیش

با کدام زبان برنامه‌نویسی شروع کنیم؟

Fri, 01/29/2016 - 13:24

اگر قصد دارید برنامه‌نویسی رو شروع کنید، به احتمال زیاد این سوال براتون پیش اومده که چه زبانی برای شروع مناسب‌تره؟ گاهی افراد تازه‌کار ماه‌ها وقت صرف این می‌کنن که یک زبان رو انتخاب کنن و برنامه‌نویسی رو شروع کنن. طبیعیه که سوالات زیادی برای کسی که می‌خواد الفبای برنامه‌نویسی رو یاد بگیره پیش بیاد. سوالاتی از قبیل این که کدام زبان «قدرت»‌ بیشتری داره؟ کدام زبان برای یادگیری «ساده‌تر» است؟ ویا کدام زبان «سرعت» بیشتری داره؟

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

/images/programming-langs-comic.thumbnail.jpg
اولین زبان برای یادگیری: زبان انگلیسی

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

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

بهترین زبان برای شروع: ...

زبان‌های زیادی برای برنامه‌نویسی وجود داره و هر کدوم از اون‌ها یک سری ویژگی‌های خوب دارن و طبیعتا یک سری مشکلات. من بهتون قول می‌دم که با بررسی مزایا و معایب این زبان‌‌ها به جای خاصی نمی‌رسیم و نهایتا لیستمون رو بتونیم برسونیم به پنج، شش زبان. همچنین نتیجه‌ی مشورت با سایر برنامه‌نویس‌ها هم که سردرگمی بیشتر بود. بنابراین باید با یک دید دیگه به قضیه نگاه کنیم. برای این کار بیاید اول از خودمون بپرسیم که «اگر زبان برنامه‌نویسی اشتباه رو برای شروع انتخاب کنم چی می‌شه؟»

/images/html-comic.thumbnail.jpg
اگر زبان برنامه‌نویسی اشتباه رو برای شروع آغاز کنم چی؟

حقیقت اینه که در ابتدای کار، بیشتر از این که زبان برنامه‌نویسی رو یاد بگیرید، نگاه برنامه‌نویسی رو یاد می‌گیرید. یعنی یاد می‌گیرید که چطور مثل یک برنامه‌نویس به مسائل نگاه کنید و بتونید با استفاده از الگوریتم‌های برنامه‌نویسی مشکلات رو حل کنید. این مساله مهم‌ترین چیزیه که یک برنامه‌نویس تازه‌کار باید یاد بگیره و بیشتر پیچیدگی‌های اولیه برنامه‌نویسی هم مربوط به شکل گرفتن این روش نگاه به مسائل در ذهن می‌شه.

هر یک از زبان‌های برنامه‌نویسی رو که انتخاب کنید، برای این منظور مناسب‌اند. ضمن این که برنامه‌نویسی که این طرز نگاه رو یاد گرفته می‌تونه سایر زبان‌های برنامه‌نویسی رو هم به سرعت یاد بگیره و ظرف چند ماه به یک زبان دیگه کوچ کنه.

بنابراین از این نظر هیچ زبانِ برنامه‌نویسیِ اشتباهی برای شروع وجود نداره. و باید کلا این نگرانی رو از ذهنتون پاک کنید که ممکنه زبانی که انتخاب کردید اشتباه باشه.

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

۱- دوستانتون با چه زبان‌های برنامه‌نویسی‌ای برنامه می‌نویسند؟ این مهم‌ترین سوالیه که باید بپرسید. اگر اطرافیانتون هم برنامه‌نویس هستند و می‌تونن در زمینه‌ی زبان خاصی راهنمایی‌تون کنند، پیشرفت سریع‌تری خواهید داشت.

۲- برای کدام زبان منابع بیشتری برای آموزش در دسترس دارید؟ این روزها بسیاری از دانشگاه‌های مطرح دنیا در سایت‌های آموزشی از جمله کورسرا و یوداسیتی‌ کلاس‌های آموزشی خوبی در زمینه‌ی برنامه‌نویسی می‌ذارن، که بیشترشون رایگان هستن. یک مسیر رو انتخاب کنید و پیش برید.

Categories:

اسکریپت اصلاح نمایش راست به چپ توییت‌دک

Tue, 11/03/2015 - 22:16

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

/images/tweetdeck_sample_ltr.thumbnail.jpg

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

/images/tweetdeck_sample_rtl.thumbnail.jpg
نصب اسکریپت

به اسکریپت‌های جاوااسکریپتی که به این شکل برای تغییر عملکرد صفحه‌های وب نوشته می‌شن user script می‌گن و برای نصبشون در هر مرورگر، باید از افزونه‌ی خاص اون مرورگر استفاده کرد. بنابراین کافیه که مراحل زیر رو انجام بدین تا بتونید این اسکریپت رو نصب و ازش استفاده کنید.

۱- نصب افزونه تمپرمانکی برای مرورگر گوگل کروم و یا نصب افزونه گریزمانکی برای مرورگر فایرفاکس (پس از نصب باید فایرفاکس را بسته و دوباره باز کنید).

۲- مراجعه به صفحه اسکریپت اصلاح نمایش راست به چپ توییت‌دک در گیت‌هاب، کلیک بر روی دکمه‌ی Raw و نصب اسکریپت.

نحوه کار

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

در واقع ما با کمک جی‌کوئری و لایوکوئری منتظر توییت‌های جدید می‌مونیم و بعد هر کدوم از اون‌ها رو بررسی می‌کیم که ببینیم چه تعداد کاراکتر راست به چپ در اون‌ها استفاده شده تا اگر لازم بود، توییت رو به صورت راست به چپ نمایش بده.

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

Categories:

بررسی نظریه احتمالات در پایتون - بخش اول

Fri, 06/12/2015 - 18:51

بازی‌هایی که در اون‌ها از تاس استفاده می‌شه معمولا تا حد زیادی به شانس بستگی داره. افراد مختلف تعاریف مختلفی از شانس دارن، عده‌ای سعی می‌کنن که با تمرکز روی یک عدد یا دعا کردن شانس خودشون رو برای ریختن تاس مناسب افزایش بدن و عده‌ای هم به روش‌های مختلف دست به تقلب می‌زنن. اما ریاضیات تعریف متفاوتی از شانس داره. ریاضیات، شانس رو «اندازه‌ی احتمالِ وقوعِ یک رویداد» تعریف می‌کنه که با یک عدد بین ۰ و ۱ نمایش داده می‌شه و همون‌طور که می‌دونین در مبحث احتمالات بررسیش می‌کنه.

از اونجا که ایده‌ی تاس اینه که ما به یک روشی یک عدد تصادفی بین ۱ تا ۶ انتخاب کنیم، من این کار رو به راحتی با استفاده از ماژول random در پایتون شبیه‌سازی می‌کنم تا بتونم بعدا بررسیش کنم:

die_probability.py

import random


def roll_die(num_sides, true_random=False):
    '''simulates rolling a die, if true_random is set, it will use random.org
    to produce true random numbers. be careful though, it might take a lot
    of time and the difference is really not that much.'''
    if true_random is True:
        import randomdotorg
        r = randomdotorg.RandomDotOrg('alimsvi.ir')
        return r.randrange(1, num_sides + 1)
    return random.randrange(1, num_sides + 1)

بر اساس چیزی که ریاضیات می‌گه، فرض کنید ما یک تاس عادلانه‌ی ۶ وجهی داشته باشیم که روی هر وجه اون یکی از اعداد بازه‌‌ی از ۱ تا ۶ نوشته شده باشه. هر عددی رو که در این بازه در نظر بگیریم و تاس رو بریزیم، احتمال این که عدد مورد نظر ما بیاد \(\frac{1}{6}\) است.

یک روش امتحان کردن این مساله می‌تونه به این صورت باشه که ما بارها تاس مورد نظرمون رو بریزیم و انتظار داشته باشیم که میانگین دفعاتی که تاس مورد نظرمون ریخته شده نزدیک به \(\frac{1}{6}\) باشه. و این یعنی اگر میانگین رو M در نظر بگیریم، اختلاف M با عدد \(\frac{1}{6}\) باید نزدیک به صفر باشه.

از اونجایی که من حوصله ندارم یک تاس رو «بارها» بریزم و نتیجه‌ها رو یادداشت کنم و در آخر میانگین مورد نظرم رو بررسی کنم، چند خط کد پایتون می‌نویسم و این مساله رو با یک نمودار بررسی می‌کنم:

die_probability.py

def plot_fairness_line(num_sides, max_trials, step, side):
    '''tests the difference between expected average and the real average
    produced after rolling a die for a range of trials.'''
    diff_data = []
    num_trials_data = []
    for num_trials in range(1, max_trials, step):
        side_count = 0
        for dummy_idx in range(num_trials):
            result = roll_die(num_sides)
            if result == side:
                side_count += 1

        statistical_prb = 1.0 / 6
        computed_prb = side_count / float(num_trials)
        diff_data.append(computed_prb - statistical_prb)
        num_trials_data.append(num_trials)

    pyplot.plot(num_trials_data, diff_data)
    pyplot.xlabel("Number of trials ran on dice.")
    pyplot.ylabel("Difference between expected and computed results")
    pyplot.grid(True)
    pyplot.ylim((-0.5, 0.5))
    pyplot.title("Fairness of a Die in Python")
    pyplot.show()

plot_fairness_line(6, 10000, 10, 2)

نموداری که با اجرای این کد نمایش داده می‌شه مشخص می‌کنه که هر چه تاس بیشتری ریخته شده اختلاف میانگین با \(\frac{1}{6}\) بیشتر به صفر نزدیک شده:

/images/die_probability_1.thumbnail.jpeg

برای این که مفهوم‌تر بشه، قضیه رو یک جور دیگه امتحان می‌کنیم. فرض کنید تاس رو ۳۰۰۰ بار بریزیم، با توجه به این که \(\frac{1}{6}*3000=500\) ، می‌تونیم انتظار داشته باشیم که هر یک از اعداد روی تاس حدوداً ۵۰۰ بار ریخته بشن. بنابراین می‌تونیم چند خط کد دیگه بنویسم که ۳۰۰۰ بار تابع ما رو اجرا کنه، اعدادی رو که ریخته می‌شن بشمره و در نهایت نتیجه رو در یک نمودار دیگه بررسی کنیم:

die_probability.py

def plot_fairness_bar(num_sides, num_trials, true_random=False):
    '''rolls the die for "num_trials" times and calculates the number of
    times each side of the die was shown, it then shows a bar plot'''
    data = {key: 0 for key in range(1, num_sides + 1)}
    for dummy_idx in range(num_trials):
        data[roll_die(num_sides, true_random)] += 1

    x_data = [key for key in data.keys()]
    y_data = [value for value in data.values()]

    pyplot.bar(x_data, y_data, width=0.3, align='center')
    pyplot.title("Fairness of a Die in Python")
    pyplot.xlabel("side of the die")
    pyplot.ylabel("Number of times the number produced")
    pyplot.grid(True)
    pyplot.show()

plot_fairness_bar(6, 3000)

نمودار به دست اومده این مساله رو تایید می‌کنه:

/images/die_probability_2.thumbnail.jpeg
نتیجه‌

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

در بخش بعدی به معرفی روش مونت کارلو (Monte Carlo method) و استفاده‌‌اش در طراحی هوش مصنوعی برای انجام بازی‌ها و محاسبه حرکت بعدی در بازی، خواهم پرداخت.

ویرایش

مهدی توی فیس‌بوک برای من نوشته:

یک نکته توی کامپیوتر چیزی به نام تولید اعداد صد درصد تصادفی نداریم. یعنی تو اگه یک سیستم بسته داشته باشی (مثل همین کامپیوترت) اعدادی که تصادفی تولید میشه در حقیقت تصادفی نیستند! و اگه آزمایشت رو بی‌نهایت تکرار کنی میتونی این تصادفی نبودن رو کشف کنی. راه‌حلش هم استفاده از سرویس‌هایی مثل random.org اه که اونها هم روشهای خاص خودشون رو دارن برای تولید اعداد رندوم (مثلا از امواج کیهانی استفاده می‌کنن)

برای امتحان حرف مهدی، من کد توابع رو توی پست عوض کردم و همین‌طور که می‌بینید به تابع roll_die یک آرگومان جدید اضافه کردم که در صورت استفاده ازش، با استفاده از ماژول randomdotorg از طریق وبسایت مذکور اعداد تصادفی واقعی به دست بیاد و این رو در تابع plot_fairness_bar اعمال کردم و با خط زیر امتحانش کردم:

die_probability.py

plot_fairness_bar(6, 3000, true_random=True)

طبیعتا مدت زیادی طول کشید تا ۳۰۰۰ عدد تصادفی از طریق وبسایت random.org تولید بشه و با سرعت و کیفیت بالای اینترنت اینجا، به دست من برسه. ولی نتیجه‌ی نهایی نمودار زیر شد:

/images/die_probability_3.thumbnail.jpeg

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

Categories:

سلام، دنیا!

Mon, 04/13/2015 - 19:15

سلام، این بار از یک دامین تازه، بر روی بستر نیکولا.

حقیقت اینه که بعد از مدت‌ها ننوشتن تصمیم گرفتم این بار در یک فضای شخصی و قابل کنترل [1] دوباره شروع به نوشتن کنم. برای این کار این دامین رو انتخاب کردم و برای مدیریت محتوا هم "نیکولا" رو که یک سیستم ایجاد سایت استاتیک ساده است که با پایتون نوشته شده و امکانات خوبی داره.

چرا استاتیک؟

بیشتر وبسایت‌های مدرن، پویا (داینامیک) هستن به این معنی که بیشتر محتوای سایت در یک پایگاه داده ذخیره شده و فقط زمانی که کاربر نیاز به مشاهده‌‌ی اونا داشته باشه، تبدیل به HTML شده و نمایش داده می‌شن. سایت‌های پویا امکانات زیادی دارن، و در مقابلِ این امکانات، به هزینه‌ی بیشتری برای نگهداری نیاز دارن. تصور کنید که برای هر بار خوندن یک صفحه از یک وبسایت پویا چند بار با پایگاه داده ارتباط برقرار می‌شه و برای این ارتباطات و تبدیل محتوا به کدهای HTML طبیعتا مقداری از رم و سی‌پی‌یو مصرف می‌شه، در صورتی که برای نگهداری یک وبسایت ایستاتیک، نیازی به رم و سی‌پی‌یو نیست و فقط فضای کمی از هارد دیسک برای ذخیره‌سازی فایل‌های HTML وبسایت نیاز است. در واقع کار به این صورت انجام می‌شه که شما فایل‌های مربوط به پست‌ها و صفحات مختلف سایت خودتون رو توی هارد دیسک خودتون ذخیره می‌کنید، و سپس با استفاده از یک نرم‌افزارِ "تولید وبسایت ایستاتیک" فایل‌ها رو به HTML تبدیل می‌کنید و بعد فایل‌های تبدیل شده رو در فضای سرور خودتون یا هر فضایی که ترجیح می‌دین، میذارین.

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

چرا نیکولا؟

نرم‌افزارهای زیادی برای ایجاد وبسایت‌های استاتیک وجود داره که از بین اون‌ها گزینه‌های خوب زیادی رو می‌شه پیدا کرد. نیکولا یکی از همین نرم‌افزارهاست که با زبان پایتون نوشته شده. زبانی که من با آن راحت‌ترم و اولین دلیل من برای انتخاب "نیکولا" بود، چرا که شاید نیاز به تغییرات در کدش داشته باشم. دلیل دوم من این بود که نیکولا یک نرم‌افزار متن باز است و در صورتی که بتونم، در بهبود کد آن شریک می‌شم. نگارش توسط زبان ساده‌ی مارک آپ (استفاده از reStructuredText یا Markdown) دلیل بعدی بود. سایر دلایلی که من رو برای استفاده از نیکولا ترغیب کرد رو می‌تونید در کتابچه‌ی راهنمای نیکولا بخونید.

چرا گیت‌هاب؟

من برای ذخیره‌سازی فایل‌های این وبسایت، گیت‌هاب رو انتخاب کردم. اهل فن از راحتی کار با سیستم مدیریت ورژن "گیت" و شهرت وبسایت "گیت‌هاب" آگاهی دارن و برای توضیح نحوه کار گیت و گیت‌هاب نیاز به یک یا حتی چند پست طولانی هست. پس به همین چند خط اکتفا می‌کنم. یکی از مهمترین دلایل این می‌تونه باشه که با استفاده از گیت‌هاب کارها می‌تونن اشتراکی انجام بشن، یعنی شما می‌تونید در صورت تمایل با فورک کردن پروژه وبسایت در گیت‌هاب، ایجاد تغییرات و بعد Pull Request، به من در رفع اشکالات و بهبود وبسایت کمک کنید.

محتوا

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

آینده
  • در حال حاضر وبسایت در مراحل اولیه خودشه. قالب وبلاگ رو با دستکاری قالب‌های پیش‌فرض و اضافه و کم کردن بخش‌های مختلفش و تغییر رنگ‌بندی، ایجاد کردم و فکر می‌کنم در حالی که امکانات اولیه یک وبلاگ رو داره، ظاهرش هم خوب شده. مسلما در آینده تغییرات دیگه‌ای هم بهش خواهم داد، و خوشحال خواهم شد اگر با دادن ایده به من کمک کنید.
  • یکی از کارهای دیگه هم که دوست دارم انجام بدم، تغییر تاریخ میلادی پست‌ها، به تاریخ شمسی است، این کار سخت‌تر از اون چیزیه که به نظر می‌رسه و نیازمند دست‌کاری توی کدهای نیکولاست. در صورتی که در آینده فرصت کنم سعی خودم رو خواهم کرد.
  • اگر توجه کرده باشید آدرس ریشه‌ی وبسایت، شما رو به پوشه‌ی "blog" هدایت می‌کنه. قصد دارم صفحه‌ی ایندکس وبسایت رو به چیز معقول‌تری تغییر بدم.
  • احتمالا بعضی از نوشته‌های قبلی خودم رو به این وبسایت منتقل کنم.
[1]قابل کنترل از نظر من یعنی این که به دلیل راحتی، مجبور به درگیر شدن با یک سیستم مدیریت محتوای پیچیده با کدهای نامفهموم نشم.
Categories:
Trigup Fanap O'Reilly Media
iranserver

زبان‌ها