<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های حامد ذقاقی</title>
        <link>https://virgool.io/feed/@zaghaghi</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-16 20:04:42</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/621/avatar/kevvpC.png?height=120&amp;width=120</url>
            <title>حامد ذقاقی</title>
            <link>https://virgool.io/@zaghaghi</link>
        </image>

                    <item>
                <title>ویژگی‌های C++20</title>
                <link>https://virgool.io/@zaghaghi/cpp20-lang-new-features-sez585fzfmdl</link>
                <description>بعد از C++14 و C++17 حالا نوبت C++20 هست و ویژگی‌های جدیدی که به این زبان اضافه شده و در این مطلب سعی می‌کنم تعدادی از این ویژگی‌ها رو لیست کنم.ویژگی Modulesماژول‌ها راهی برای جایگزین کردن header  فایل‌ها هستند، در ماژول‌ها نیاز هست که به صورت صریح چیزهایی که قرار است قابل استفاده باشند (مانند: توابع، کلاس‌ها) را export کنید. فایل‌های interface و فایل‌های implementation نیازی نیست که از هم جدا باشند، هر چند که این امکان وجود دارد.تعریف یک ماژول نمونهبرای استفاده از یک ماژول باید از import استفاده کنید.بعد از import کردن ماژول مد نظر، فقط می‌توانید از توابع، کلاس‌ها و ... که export شده‌اند استفاده کنید و استفاده از بقیه موارد باعث به وجود آمدن خطای کامپایل می‌شه.همانطور که در مثال بالا می‌بینید، کتابخانه استاندارد C++ را هم می‌توانید به جای #include به کمک import به برنامه اضافه کنید.در ماژول‌ها نیازی به نوشتن include guard ندارید.وقتی متغیری، تابعی، کلاسی و یا تعریف نوع داده‌ای export نشده است، نیازی نیست که نگران تداخل نامش با دیگر ماژول‌ها باشیم.ماژول‌ها فقط یکبار کامپایل می‌شوند و اگر بخشی از یک ماژول که export نشده است تغییر کند، فقط ماژول مجدد کامپایل می‌شود و دیگر سورس کدهایی که از این ماژول استفاده کرده‌اند نیازی به کامپایل مجدد ندارند، برخلاف اتفاقی که در header فایل‌ها می‌افتاد.و در نهایت ترتیب import کردن ماژول‌ها اهمیتی ندارد. چرا که ماکروهایی که در یک ماژول تعریف شده‌اند در بیرون ماژول تاثیری ندارند.البته در زمانی که در حال نوشتن این مطلب هستم، تنها کامپایرهای MSVC و Clang این ویژگی را پیاده‌سازی کرده‌اند و خبری از این ویژگی در  GCC نیست.ویژگی Conceptکانسپت‌ها، روشی برای محدود کردن پارامترهای تمپلیتی است، به شکلی که می‌توانیم محدودیت‌ها را تعریف کنیم و از این تعریف برای پارامترهای تمپلیتی استفاده کنیم.تعریف یک کانسپت برای محدود کردن تمپلیت‌هایی که عملیات ++ را پیشتیبانی می‌کنندبرای این ویژگی، دو کلمه concept و requires به استاندارد زبان اضافه شده است. در بلاک مربوط به requires شرایط و محدودیت‌ها را  می‌نویسیم و این شرایط در زمان کامپایل بررسی می‌شوند.استفاده از کانسپت تعریف شده در تعریف یک تابع تمپلیتیکانسپت‌های بسیار پیچیده‌تری هم می‌توان تعریف کرد.تعریف کانسپتی با این شرایط که فراخوانی تابع swap باعث ایجاد یک exception نشود و تابع size مقداری از نوع size_t برگرداندکانسپت‌ها را می‌توان با یکدیگر ترکیب کرد و کانسپت‌های جدیدتری ایجاد کرد.تعریف یک کانسپت بر اساس ترکیب دو کانسپت دیگرکانسپت‌ها را به شکل دیگری نیز می‌تواند استفاده کرد.و صد البته خود کتابخانه استاندارد زبان، حاوی تعداد زیادی کانسپت تعریف شده در &lt;concepts&gt; است.در زمان نوشتن این مطلب، کانسپت‌ها تقریبا در هر سه کامپایلر پر استفاده C++ یعنی MSVC، Clang و GCC پیاده سازی شده‌اند.کتابخانه rangesاین کتابخانه جدید در اصل مجموعه‌ای از کانسپت‌ها، کلاس‌ها و متدهاست، که در &lt;ranges&gt; تعریف شده است. مفهوم یا کانسپت range شامل تمامی انواع داده‌ای می‌شود که std::ranges::begin و std::ranges::end برای آن نوع داده تعریف شده باشد.یکی از اهداف اصلی این کتابخانه کار راحتتر و بدون ایراد با iterator هاست.به کمک range factories، هم می‌توانیم subrange های جدید بسازیم و از آن‌ها استفاده کنیم.استفاده از views::counted برای ساخت یک subrange  بر روی dataویژگی اصلی دیگر ranges امکان فیلتر کردن، تغییر دادن و انجام عملیات زنجیره‌ای بر روی مجموعه‌ای از داده‌هاست، البته به صورت کاهلانه (lazy)! که به کمک view ها امکان پذیر است.استفاده از filter برای فیلتر کردن دیتای ورودی به زنجیرهاستفاده از take  برای برداشتن بخشی از نتایجاستفاده از transform برای تغییر داده‌ها در انتهای زنجیرهنکته بسیار مهم این هست که تا زمانی که بر روی این range حرکت (iterate) نکنیم، این توابع اجرا نمی‌شوند. همین ویژگی به ما این امکان را می‌دهد تا بر روی rangeهای نامتناهی کار کنیم!تعداد ویژگی‌های C++20 خیلی بیشتر از سه موردی است که در این مطلب گفتم، برای آشنایی بیشتر با این ویژگی‌ها پیشنهاد می‌کنم که ویدئوهای کنفرانس امسال CppCon در یوتیوب را ببینید.</description>
                <category>حامد ذقاقی</category>
                <author>حامد ذقاقی</author>
                <pubDate>Wed, 07 Oct 2020 20:19:34 +0330</pubDate>
            </item>
                    <item>
                <title>راه‌اندازی سرور استریم در ۵ دقیقه</title>
                <link>https://virgool.io/@zaghaghi/%D8%B1%D8%A7%D9%87%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C-%D8%B3%D8%B1%D9%88%D8%B1-%D8%A7%D8%B3%D8%AA%D8%B1%DB%8C%D9%85-%D8%AF%D8%B1-%DB%B5-%D8%AF%D9%82%DB%8C%D9%82%D9%87-sh82biljnigb</link>
                <description>این روز‌ها به دلایل مختلف از جمله دورکاری‌ها و نداشتن جلسات حضوری، استفاده از ابزارهای آنلاین رو بسیار زیاد کرده و خیلی‌هامون تا الان از سرویس‌های مختلف استفاده کرده‌ایم. یکی از این سرویس‌ها، استریم ویدئو است، چه برای استریم بازی و چه استریم یک وبینار یا یک کلاس درس. البته کلی هم ارائه دهنده سرویس خود چه در ایران و چه در جهان داریم که نیازی به معرفی نیست.اما چرا نیاز هست که با وجود سرویس‌دهندگان خوب، خودمون این کار رو انجام بدیم؟ یکی از دلایلش که دلیلی هست که خودم سراغش رفتم، ارائه یک وبینار در داخل شرکت بود، به نحوی که نیاز نباشه همکاران من  توی اتاق کنفرانس دور هم جمع بشوند. برای همین با کمی گشتن و با کمک نرم‌افزارهای متن باز و رایگان این امر در شرکت شدنی شد و خلاصه این روال رو اینجا با شما به اشتراک می‌گذارم.برای شروع از یک معماری کلی و خیلی خیلی خیلی ساده شروع می‌کنم.معماری بسیار ساده برای استریم سروردر این معماری سه عنصر اصلی وجود داره:ضبط کننده، که اطلاعات ویدئویی را ضبط کرده و برای سرور استریم ارسال می‌کندتماشاگران، که از طریق مرورگر یا یک مدیاپلیر استریم را تماشا می‌کنندسرور استریم که وظیفه دریافت استریم از ضبط کننده و در اختیار قرار دادن آن به تماشاگران است. همچنین وظیفه نگهداری تمام استریم را هم دارد.سرور استریمبرای راه‌اندازی سرور استریم از nginx و ماژول nginx-rtmp استفاده کردم و البته در داکرهاب، داکر آماده‌اش رو پیدا کردم با این نام tiangolo/nginx-rtmp و برای راه‌اندازی آن چیزی که نیاز داشتم یک docker-compose نوشتم که در گیت‌هاب به آدرس zaghaghi/live-stream-server  قابل دسترس هست.برای راه‌اندازی سرور استریم به روش زیر عمل کنید.git clone https://github.com/zaghaghi/live-stream-server.git
cd live-stream-server
docker-compose upضبط کنندهضبط کننده یا استریمر می‌تواند از نرم‌افزار OBS Studio استفاده کند و در تنظیمات همانند تصویر زیر عمل کند.در قسمت Server به جای streamserver از آدرس و یا نام سرور استریم که در مرحله قبل راه‌اندازی کردید استفاده کنید.در قسمت Stream Key می‌توانید یک کلید به ازای هر وبینار در نظر بگیرید و ضبط کننده از اون کلید استفاده کنه که در اینجا از webinar1 استفاده کردم. در ادامه از این کلید استفاده می‌کنیم تا استریم این ضبط کننده را ببینیم.تماشاگرانبعد از اینکه سرور استریم را راه‌اندازی کردید و ضبط کننده شروع به استریم کرد. تماشاگران می‌توانند با استفاده از یک مرورگر و با رفتن به آدرس http://streamserver:8080?webinar1 ویدئوی استریم شده را به صورت زنده مشاهده کند. برای نمایش در مرورگر از کتابخانه جاوااسکریپتی videojs استفاده شده است و این کتابخانه به کمک پروتکل HLS بر روی HTTP استریم را نمایش می‌دهد.همچنین تماشاگران می‌توانند از مدیاپلیرهایی که امکان نمایش استریم را دارند همانند VLC استفاده کنند و از یکی از دو پروتکل RTMP یا HLS استفاده کنند.استفاده از VLC برای تماشای استریم پروتکل HLS+HTTPاستفاده از VLC برای تماشای استریم پروتکل RTMP اگر بخواهید پروتکل RTMP برای تماشاگران قابل استفاده باشد باید در فایل تنظیمات NGINX این مورد را حذف کنید.deny play all;امیدوارم که این مطلب کوتاه براتون مفید بوده باشه.</description>
                <category>حامد ذقاقی</category>
                <author>حامد ذقاقی</author>
                <pubDate>Thu, 30 Jul 2020 23:13:08 +0430</pubDate>
            </item>
                    <item>
                <title>که عشق آسان نمود اول، ولی افتاد مشکل‌ها</title>
                <link>https://virgool.io/@zaghaghi/probabilistic-data-structures-y5bk8ty88xce</link>
                <description>یکی از اولین توانایی‌هایی که یک برنامه‌نویس فرا می‌گیرد، توانایی حل مساله است. از حل مسایل ساده تا مسایل بسیار پیچیده. اما چیزی که در این‌جا می‌خوام مطرح کنم حل مسایل بسیار ساده است که در نگاه اول، بسیار بدیهی و آسان به نظر می‌رسند ولی در عمل و در شرایط خاص، حل آن‌ها بسیار سخت و مشکل خواهد بود و برنامه‌نویسان باید بتوانند از پس این مسایل بربیان.منظورم از مسایل ساده، مسایلی از این دست است:بررسی عضویت یک عنصر در مجموعه داده (membership)، به عنوان مثال، پاسخ به این سوال که آیا یک عدد در یک آرایه وجود داره یا نداره؟شمارش تعداد عناصر متمایز در یک مجموعه داده (cardinality)، به عنوان مثال، در یک آرایه چند نوع عدد متفاوت وجود دارهمحاسبه تعداد دفعات تکرار یک عنصر در یک مجموعه، یا شناسایی عناصر پرتکرار (frequency)، به عنوان مثال عدد ۴۲ چندبار در یک آرایه تکرار شدهو یا مسایل ساده‌ی دیگری از این جنس.حل این مسایل بسیار ساده در بعضی شرایط بسیار سخت می‌شود.حجم (Volume)  بسیار زیاد داده‌هاسرعت (Velocity) تولید و پردازش داده‌هاتنوع (Variety) و گوناگونی داده‌هادر حل مسایلِ دنیای واقعی، ممکن است تمامی این شرایط یا بعضی از آن‌ها وجود داشته باشند و وجود همین شرایط باعث سخت شدن حل مسایل ساده‌ای خواهد شد که گفتم. وجود این شرایط همان چیزیه که ما با عنوان Big Data یا کلان داده می‌شناسیم.داده‌ها از همه جا سرازیر می‌شوند، از شبکه‌های مجازی، از سنسورها، از تراکنش‌های مالی و .... از طرفی هم شرکت‌ها می‌خواهند که از داده‌ها سر در بیارن و از آن‌ها ارزش تولید کنند. این عوامل باعث رشد بسیار سریعِ بازارِ نرم‌افزارهای مرتبط با کلان داده شده است و به عنوان یک برنامه‌نویس در این بازار باید الگوریتم‌ها و داده‌ساختارهای مورد نیاز برای حل این مسایل را فرا بگیریم. مرورگر امنفرض کنید برنامه‌نویس یک مرورگر هستم، مثلا گوگل کروم! و قراره یک امکان به مرورگر اضافه کنم که از ورود به سایت‌های مشکوک جلوگیری کنه. به عبارت دیگه یک لیست چند میلیونی (معمولا بیش از ۲ میلیون) از آدرس‌های مربوط به این سایت‌ها دارم و برای هر آدرسی که کاربر در نوار آدرس مرورگر وارد می‌کنه، برنامه باید در این لیست چند میلیونی جستجو کنه و در صورتی که در این لیست وجود داشته باشد به کاربر اخطار بده. آیا برای این کار می‌توانم تمامی آدرس‌ها را در حافظه نگهداری کنم و به ازای هر درخواست در بین آن‌ها جستجو کنم؟یا مثلا برای همین مرورگر، لیستی از تمامی رمزعبورهای لو رفته دارم (معمولا در حد چند میلیارد) و می‌خواهم در زمان‌هایی که کاربر، در سایتی رمز عبور وارد می‌کند، با این لیست مقایسه شود و در صورت استفاده از این رمز عبورها به کاربر اخطار داده شود. آیا برای این کار می‌توانم تمام رمزعبورها را در حافظه نگهداری کنم و در هر ورودِ رمزعبوری، در این لیست میلیاردی جستجو کنم؟ اصلا کار درستی است که پسور‌دها به صورت خام ذخیره شوند؟پیشنهادهافرض کنید که برنامه نویس سایت Medium یا ویرگول هستم! و قرار است که به هر کاربر چندین مقاله برای مطالعه پیشنهاد بدم، ولی می‌خوام مطمئن باشم که کاربر این مقاله را قبلا مطالعه نکرده باشه. به عبارت دیگر بعد از این‌که به کمک الگوریتم‌های توصیه‌گر، مجموعه‌ای از مقاله‌ها را برای کاربر ایجاد کردم، مقاله‌هایی که قبلا مطالعه کرده را از آن حذف کنم. بر اساس توئیت ویرگول در سال ۹۸ بیش از ۱۸ میلیون کاربر از ویرگول استفاده کرده‌اند. آیا برای این کار می‌توانم مقاله‌هایی که هر کاربر مطالعه کرده را در دیتابیس ذخیره کنم و برای حذف مقاله‌های قبلا خوانده شده از این دیتابیس استفاده کنم؟توزیع محتوافرض کنید من برنامه نویس Akamai یا ابرآروان هستم! و قرار است که الگوریتمی برای مسیردهی درخواست‌ها ایجاد کنم به طوری که درخواست‌ها به کَش سروری مسیردهی شوند که پاسخ این درخواست در آن وجود دارد، و برای این کار باید تمامی کَش سرورها از اطلاعات کَش شده در دیگر کَش سرورها اطلاع داشته باشند (Cache Sharing)، آیا درست است که برای این کار، هر کَش سرور، آدرس درخواست‌هایی را که کَش کرده است را به تمامی کَش‌سرورها ارسال کند؟سهام عدالتفرض کنید من برنامه نویس سامانه سهام عدالت هستم!! و قرار است که وب‌سایتی راه‌اندازی کنم که ۸۰ میلیون ایرانی جستجو کنند که آیا سهام عدالت دارند یا نه. آیا راه درستیه که به ازای هر درخواست من در دیتابیس چند ده میلیونی دارندگان سهام عدالت جستجو کنم؟فایروالفرض کنید من برنامه نویس Fortigate یا یک شرکت ایرانی در این زمینه هستم! و قرار است بر روی یک پهنای باند ۱۰ گیگابیت در ثانیه، تمامی بسته‌ها (Packets) را بررسی کنم و لیستی از آی‌پی‌های پرتکرار بسازم. آیا می‌توانم به ازای هر بسته، در لیست آی‌پی‌ها جستجو کنم و شمارنده این آی‌پی را افزایش بدهم و در انتها با مرتب کردن تمامی این لیست، آی‌پی‌های پرتکرار را بسازم؟توییترفرض کنید من برنامه نویس توییتر هستم! و قرار است قسمت هشتگ‌های ترند شده را بسازم. به عبارت دیگر به ازای هر توییتی که می‌شود، هشتگ‌ها را استخراج کنم و در لیست احتمالا چند میلیاردی آن هشتگ را پیدا کنم و شمارنده‌اش را افزایش بدهم و هر چند دقیقه این لیست را مرتب کنم و هشتگ‌های ترند شده را بسازم. البته قرار است که این کار را به تفکیک برای ۱۰۰ کشور مختلط هم انجام دهم! آیا این راه درستی است؟خوب فکر کنم مثال‌ها کافی هستند، برای اینکه نشان دهند که حل مسایل راحت در تولید سرویس‌ها و محصولات واقعی به راحتی امکان پذیر نیستند.داده‌ساختارهای احتمالاتییکی از راه‌کارها برای حل این مسایل در دنیای واقعی استفاده از داده‌ساختارهای احتمالاتی است. داده‌ساختارهایی که برخی از آن‌ها در یکی دو سال گذشته معرفی شده‌اند و صد البته در سال‌های آینده می‌توانیم منتظر داده‌ساختارهای بهتری هم باشیم. داده ساختارهای احتمالاتی، مانند دیگر داده‌ساختارها جواب قطعی نمی‌دهند و با یک احتمال قابل محاسبه‌ای می‌توان خطاهای احتمالی را تخمین زد و خوشبختانه خطاها و کمبودهای این داده‌ساختارها به واسطه حافظه کمی که اشغال می‌کنند، زمان پرس‌وجوی ثابتی که دارند و مقیاس پذیری آن‌ها قابل چشم پوشی هستند.به عنوان مثال به کمک فیلتر کوکو (Cuckoo Filter) که یک داده‌ساختار احتمالاتی برای حل مساله عضویت (membership) در یک مجموعه است، برای پردازش یک میلیارد اِلِمان مجزا به کمی کمتر از یک گیگابایت حافظه نیاز دارد، پیچیدگی زمانی حذف و اضافه و جستجو O(1)‎ است.چشم‌پوشیآیا خطا در داده‌ساختار قابل چشم پوشی است؟ در بسیاری از موارد بله، قابل چشم پوشی‌است، به عنوان نمونه داده‌ساختارهایی که برای حل مساله عضویت وجود دارند، مانند فیلتر کوکو، یا فیلتر بلوم؛ دارای خطای «مثبت کاذب» (False-Positive) هستند ولی خطای «منفی کاذب» ندارند.به عنوان مثال، برای حل رمزعبورهای لو رفته، می‌توانیم از فیلتر بلوم استفاده کنیم به صورتی که فقط ۱ درصد خطای «مثبت کاذب» داشته باشد. یعنی ۱ درصد احتمال دارد رمزعبوری را لو رفته حساب کند در صورتی که رمزعبور امنی است و هیچ خطایی در شناسایی رمزعبوری که لو رفته است یعنی خطای «منفی کاذب» ندارد و در یک مرورگر این خطا قابل چشم‌پوشی است.در داده‌ساختارهای احتمالاتی می‌توان، احتمال وقوع خطا را با بالابردن فضای اشغالی و بیشتر کردن پردازش کمتر کرد و به عبارتی قابل تنظیم است. به عنوان نمونه می‌توانید ماشین حساب فیلتر بلوم را ببینید.درهم‌سازیپایه و اساس تمامی داده‌ساختارهای احتمالاتی توابع درهم‌ساز یا همان توابع هَش (Hash Functions) است.توابع درهم‌سازی در دو دسته قرار می‌گیرند:توابع درهم‌ساز رمزنگارانه (Cryptographic Hash Functions)توابع درهم‌ساز غیررمزنگارانهدسته اول برای استفاده در حوزه امنیت و رمزنگاری کاربرد دارند و معمولا به خاطر ویژگی‌هایی که دارند سرعت پردازشی کمتری به نسبت توابع درهم‌ساز دسته دوم دارند. به عنوان مثال SHA1-32 توانایی پردازش تقریبا ۳۰۰ مگابایت در ثانیه را دارد ولی MurMurHash3 توانایی پردازش نزدیک به ۳ گیگابایت در ثانیه، یا xxHash قدرت پردازشی نزدیک به 5.5 گیگابایت در ثانیه را دارد.همانطور که حدس زده‌اید، در داده‌ساختارهای احتمالاتی از توابع درهم‌ساز غیر رمزنگارانه استفاده می‌شود که نرخ برخورد ( Collision Rate) کم و سرعت بسیار بالا دارند.پیاده‌سازییکی از پیاده‌سازی‌های داده‌ساختارهای احتمالاتی که البته متعلق به نویسنده همین مطلب هم هست :-) در گیت‌هاب (github.com/zaghaghi/pdstl) قابل دسترس است. البته پیاده‌سازی‌های دیگری نیز به صورت متن‌باز وجود دارد ولی سعی شده و خواهد شد که در این پیاده‌سازی تقریبا بیشتر داده‌ساختارهای احتمالاتی به صورت یک‌جا و یک شکل پیاده‌سازی شود.به عنوان مثال برای استفاده از فیلتر بلوم (Bloom Filter) به کمک کتابخانه PDSTL می‌توان به شکل زیر عمل کرد.#include &lt;membership/bloom_filter.h&gt;
#include &lt;vector&gt;
#include &lt;string&gt;
#include &lt;iostream&gt;

int main() {
    // Read all urls from file or database into urls 
    std::vector&lt;std::string&gt; urls;
    // Define bloom filter with 11 hash functions and 16M memory bits
    bloom_filter&lt;11, 16000000&gt; url_bloom_filter;
    std::for_each(urls.begin(), urls.end(), [&amp;url_bloom_filter](auto&amp; item) {
        // Insert items into bloom filter
        url_bloom_filter.insert(item);
    });

    // Check that bloom filter contains an item or not
    if (url_bloom_filter.contains(&amp;quothttps://gmail.com&amp;quot)) {
        std::cout &lt;&lt; &amp;quotFOUND!!!!!&amp;quot &lt;&lt; std::endl;
    } else {
        std::cout &lt;&lt; &amp;quotNOT FOUND&amp;quot &lt;&lt; std::endl;
    }
}بیشتر بخوانیمیکی از مراجعی که برای خواندن در مورد این داده‌ساختارها وجود دارد، ویکی‌پدیا است. همچنین بهترین مرجع خود مقالات داده‌ساختارهاست و البته کتابی در سال ۲۰۱۹ منتشر شده که این داده‌ساختارها را یکجا جمع‌آوری کرده:Probabilistic Data Structures and Algorithms for Big Data Applications by Andrii Gakhov, 2019, ISBN: 978-3748190486 (paperback) ASIN: B07MYKTY8W (e-book)</description>
                <category>حامد ذقاقی</category>
                <author>حامد ذقاقی</author>
                <pubDate>Wed, 03 Jun 2020 09:34:26 +0430</pubDate>
            </item>
                    <item>
                <title>مزیت رقابتی ناعادلانه</title>
                <link>https://virgool.io/@zaghaghi/unfair-advantages-udtyw4dz5dxy</link>
                <description>امروز داشتم یک ویدئو تو یوتیوب می‌دیدم، که دسته بندی خوبی از مواردی که می‌توانند «مزیت رقابتی ناعادلانه» باشند داشت و قصد دارم در ادامه بخش‌هایی که به نظرم مهم بودند را بنویسم.انواع مزیت رقابتی ناعادلانهدارا بودن یا ساختن «مزیت رقابتی ناعادلانه» را می‌توان در یکی یا چند تا از این ۵ بخش انجام داد:بنیانگذاربازارمحصولجذب مشتریانحصاربنیانگذار«بنیانگذار» یک استارت‌آپ یا شرکت می‌تونه یک «مزیت رقابتی ناعادلانه» باشه. اگه مسأله‌ای که این استارت‌آپ حل می‌کنه، فقط ۱۰ نفر در کل دنیا توانایی حلش را دارند و بنیانگذار یکی از آن ۱۰ نفره. اونوقت بنیانگذار یک «مزیت رقابتی ناعادلانه» حساب می‌شه.مدیر محصول در گوگل بوده‌اید؟ تیم لیدر در مایکروسافت بوده‌اید؟ پس شما یکی از ۱۰ نفر در کل دنیا نیستید. اما اگر در یک حوزه خاص تخصص دارید، تحصیل کرده‌اید و یک پتنت ثبت کرده‌اید؟ آن وقت می‌توانید یک «مزیت رقابتی ناعادلانه» باشید برای رقبایتان.بازار«بازار»ی که یک استارت‌آپ در آن به دنبال مشتری است می‌تونه یک «مزیت رقابتی ناعادلانه» باشه.  اگه بازاری که در آن فعالیت می‌کنید ۲۰ درصد در سال رشد می‌کنه این می‌تونه یک «مزیت رقابتی ناعادلانه» باشه.محصول«محصول»ی که می‌سازید می‌تونه یک «مزیت رقابتی ناعادلانه» باشه. اگه محصولی که می‌سازید ۱۰ برابر بهتر از محصولاتی هست که در بازاره، اونوقت این محصول پتانسیل تبدیل شدن به یک «مزیت رقابتی ناعادلانه» را داره. محصول شما ۱۰ برابر سریع‌تره؟ یا ۱۰ برابر ارزونتره؟جذب مشترینحوه «جذب» مشتری هم می‌تونه یک «مزیت رقابتی ناعادلانه» باشه. اگه می‌تونید با هزینه صفر مشتریان خود را جذب کنید، اونوقت این نحوه جذب مشتری توانایی تبدیل شدن به یک «مزیت رقابتی ناعادلانه» را دارد.انحصارقدرت «انحصار» می‌تونه یک «مزیت رقابتی ناعادلانه» باشه. آیا در حینی که در حال رشد هستید، شکست دادن شرکت شما توسط رقبا سخت  و سخت‌تر می‌شود؟ اگر اینطوری هست، پس «انحصار» می‌تواند یک «مزیت رقابتی ناعادلانه» باشد.</description>
                <category>حامد ذقاقی</category>
                <author>حامد ذقاقی</author>
                <pubDate>Thu, 03 Oct 2019 12:26:35 +0330</pubDate>
            </item>
                    <item>
                <title>آسیب‌پذیری‌ها را جدی بگیریم! - قسمت سوم</title>
                <link>https://virgool.io/@zaghaghi/vulnerability-browser-part-3-sg0tkzdyyqlj</link>
                <description>فهرستقسمت اول - معرفی مراکز انتشار آسیب‌پذیریقسمت دوم - نصب و پیکره‌بندی گراف دیتابیس Neo4jقسمت سوم - جستجو و گزارش‌گیریمقدمهدر دو قسمت قبلی نگاهی اجمالی به مراکز انتشار آسیب‌پذیری‌ها، فرمت‌های انتشار آسیب‌پذیری داشتم و همچنین نحوه نصب و پیکره‌بندی گراف دیتابیس Neo4j را بررسی کردم و اطلاعات مربوط به آسیب‌پذیری‌ها را در Neo4j وارد کردم.اکنون زمان نمایش اطلاعات درج شده است.دریافت اطلاعات یک آسیب‌پذیری بر اساس شناسه آنفرض کنید که می‌خواهیم در داشبورد Neo4j اطلاعات مربوط به آسیب‌پذیری به شناسه CVE-2019-9978 را مشاهد کنیم. برای این کار می‌توانیم ابتدا دستور زیر را اجرا کرده و پس از دریافت گره(node) آسیب‌پذیری، آن را بسط می‌دهیم تا اطلاعات دیگر آن را هم مشاهده کنیم.MATCH (n:CVE) WHERE n.name = &#039;CVE-2019-9977&#039; RETURN nدریافت اطلاعات یک آسیب‌پذیری بر اساس نام محصول و نسخهفرض کنید که شما می‌خواهید برای نوشتن یک برنامه از پایتون نسخه 2.7.16 استفاده کنید. به راحتی و با اجرای دستور زیر می‌توانید آسیب‌پذیری‌های آن را مشاهده کنید.MATCH (c:CVE)-[]-&gt;(v:ProductVersion)-[:VERSION_OF]-&gt;(p:Product) WHERE p.name = &quot;python&quot;  AND v.version_value = &quot;2.7.16&quot; RETURN p, v, cبررسی آسیب‌پذیری یک کتابخانهفرض کنید برای انجام پروژه‌ای به زبان پایتون می‌خواهید از کتابخانه urllib3 استفاده کنید. با استفاده از دستور زیر می‌توانید آسیب‌پذیری‌های مربوط به این کتابخانه با نسخه 1.24.1 را مشاهده کنید.MATCH (c:CVE)-[]-&gt;(v:ProductVersion)-[:VERSION_OF]-&gt;(p:Product) WHERE p.name = &quot;urllib3&quot; AND v.version_value = &quot;1.24.2&quot; RETURN p, v, cیافتن ضعف‌های امنیتی مرتبط با حافظهیکی از گزارش‌هایی که می‌توان از این اطلاعات به دست آورد، آشنایی با آسیب‌پذیری‌ها و ضعف‌های امنیتی است. به عنوان مثال با اجرای دستور زیر می‌توانید ضغف‌های امنیتی مرتبط با حافظه را ببینید و بشناسیدMATCH (w:CWE) WHERE w.affected_resources = &quot;::Memory::&quot; RETURN w.name, w.title, w.affected_resources LIMIT 25یافتن آسیب‌پذیری بر اساس یک ضعف امنیتیفرض کنید که می‌خواهید متوجه شوید که نرم‌افزار فتوشاپی که با آن کار می‌کنید (به عنوان مثال فتوشاپ نسخه CC 2017.1.1) از ضعف امنیتی CWE-416 رنج می‌برد یا خیر؟ این ضعف امنیتی مربوط به شرایطی است که نرم‌افزار از حافظه‌ای استفاده می‌کند که قبلا آن را آزاد کرده است. برای به دست آوردن شماره نسخه فتوشاپی که گفته شد می‌توانید از لیست نسخه‌های فتوشاپ در ویکی‌پدیا استفاده کنید. شماره نسخه‌ای که عنوان شده برابر است با 18.1.1 است. پس با اجرای دستور زیر می‌توانید متوجه آسیب‌پذیری‌های مرتبط با این ضعف امنیتی شوید.MATCH (c:CVE)--&gt;(w:CWE {name: &quot;CWE-416&quot;}), (c)--&gt;(v:ProductVersion {version_value: &quot;18.1.1&quot;})--&gt;(p:Product {name: &quot;photoshop&quot;}) RETURN v, c, p, w LIMIT 25به تفاوت فیلتر کردن گره‌ها در دستور اخیر و بقیه دستورها دقت کنید. در دستور اخیر فیلتر کردن در دستور MATCH انجام شده است و در دیگر دستورات در WHERE. هر دو روش صحیح هست و می‌توانید استفاده کنید.بررسی Graphqlبرای اینکه مطمئن شویم که تعاریف مربوط به Graphql به درستی در Neo4j وارد شده‌اند می‌توان از فراخوانی زیر استفاده کرد.CALL graphql.schema()نصب و راه Graphiqlبرای کوئری گرفتن با استفاده از Graphql، اگر ابزاری ندارید پیشنهاد می‌کنم که ابزار Graphiql را نصب کنید و اجرا کنید. سپس در قسمت GraphQL Endpoint از آدرس http://localhost:7474/graphql استفاده نمایید.اکنون می‌توانیم همان جستجوهایی که در داشبورد Neo4j و با استفاده از زبان Cypher انجام دادیم را با استفاده از زبان Graphql انجام دهیم.دریافت اطلاعات یک آسیب‌پذیری بر اساس شناسه آنquery {
  CVE(name: &quot;CVE-2019-9977&quot;) {
      name
      description
   }
}دریافت اطلاعات یک آسیب‌پذیری بر اساس نام محصول و نسخهquery {
  ProductVersion(filter: {product: {name: &quot;python&quot;}, version_value: &quot;2.7.16&quot;}) {
    name
    version_value
    cves {
         name
     }
  }
}بررسی آسیب‌پذیری یک کتابخانهquery {   
    ProductVersion(filter: {product: {name: &quot;urllib3&quot;}, version_value: &quot;1.24.2&quot;}) {
         name
         version_value
         cves {
              name
         } 
    }
}یافتن ضعف‌های امنیتی مرتبط با حافظهquery {
  CWE (filter: {affected_resources: &quot;::Memory::&quot;}, first: 25) {
    name
    title
    affected_resources
  }
}یافتن آسیب‌پذیری بر اساس یک ضعف امنیتیquery {
  CVE (filter: {
    	problems_single: {name: &quot;CWE-416&quot;},
    	productVersions_single: {version_value: &quot;18.1.1&quot;, product: {name: &quot;photoshop&quot;}}
    }, first: 25) {
    name
    productVersions {
      name
      version_value
    }
    products {
      name
    }
    problems {
      name
    }
  }
}از آن‌جایی که من به تازگی با Graphql آشنا شده‌ام، ممکن است این جستجو‌ها بهینه نباشند. پس اگر جستجو‌های بهینه‌تری می‌شناسید، خوشحال می‌شوم که در نظرات با من و بقیه خوانندگان به اشتراک بگذارید.</description>
                <category>حامد ذقاقی</category>
                <author>حامد ذقاقی</author>
                <pubDate>Wed, 08 May 2019 02:04:01 +0430</pubDate>
            </item>
                    <item>
                <title>آسیب‌پذیری‌ها را جدی بگیریم! - قسمت دوم</title>
                <link>https://virgool.io/@zaghaghi/vulnerability-browser-part-2-spnved0hh6v0</link>
                <description>فهرستقسمت اول - معرفی مراکز انتشار آسیب‌پذیریقسمت دوم - نصب و پیکره‌بندی گراف دیتابیس Neo4jقسمت سوم - جستجو و گزارش‌گیریمقدمهدر قسمت اول توضیحاتی کلی درباره آسیب‌پذیری‌ها، مراکز انتشار اطلاعیه‌ها و همچنین پایگاه‌داده Neo4j صحبت شد و در این قسمت به نحوه نصب و پیکره‌بندی Neo4j، نصب پلاگین‌های مورد نیاز، دریافت اطلاعات آسیب‌پذیری‌ها و وارد کردن آن‌ها در ‌Neo4j خواهم پرداخت.نصب و راه‌اندازی Neo4jابتدا به مرکز دانلود Neo4j رفته و Neo4j Community Edition را دانلود کنید و پس از دانلود Neo4j را در یک دایرکتوری از حالت فشرده خارج کنید. در زمان نوشتن این مطلب آخرین نسخه انتشار یافته 3.5.5 بود.زیردایرکتوری‌هایی که ما با آن‌ها سر و کار داریم به شرح زیر است:دایرکتوری bin: حاوی اسکریپت‌های اجراییدایرکتوری conf: شامل فایل neo4j.conf است که فایل پیکره‌بندی Neo4j استدایرکتوری plugins: دایرکتوری مربوط به پلاگین‌هادایرکتوری import: دایرکتوری مربوط به فایل‌های مورد نیاز برای پر کردن اطلاعات Neo4j استبرای راه‌اندازی سرویس Neo4j می‌توانید به روش زیر عمل کنیدcd bin
./neo4j startپس از گذشتن چندین ثانیه سرویس Neo4j راه‌اندازی شده است و شما می‌توانید از طریق داشبورد تحت وب آن به آدرس http://localhost:7474 فرامین Neo4j را اجرا کنید. نام‌کاربری و رمزعبور پیش‌فرض neo4j است.نصب پلاگین‌هابرای وارد کردن راحتتر اطلاعات مربوط به آسیب‌پذیری‌ها و ضعف‌های نرم‌افزاری و سخت‌افزاری نیاز به پلاگین APOC داریم. این پلاگین را می‌توانید از صفحه گیت‌هاب پروژه APOC دانلود کنید. فایل با پسوند jar را دانلود کنید و در دایرکتوری plugins کپی کنید. در زمان نوشتن این مطلب من از نسخه 3.5.0.5 استفاده کردم.برای اینکه بتوانیم فایل‌های JSON و CSV مربوط به آسیب‌پذیری‌ها را با استفاده از این پلاگین به Neo4j وارد کنیم، بایستی در فایل پیکره‌بندی Neo4j که در مسیر conf/neo4j.conf قرار دارد، خط زیر اضافه کنیم.apoc.import.file.enabled=trueپس از اضافه کردن این خط نیاز هست که Neo4j را دوباره راه‌اندازی کنید../neo4j restartدومین پلاگینی که نیاز به نصب دارد، پلاگین Graphql است. همان‌طور که در قسمت اول به آن اشاره شد. با کمک این پلاگین این امکان فراهم می‌شود که برای جستجو در اطلاعات داخل ‌Neo4j از کوئری‌های Graphql استفاده کنیم. این پلاگین را می‌توانید از صفحه گیت‌هاب آن دانلود کنید. همانند پلاگین قبلی، فایل با پسوند jar این پلاگین را دانلود کنید و در دایرکتوری plugins کپی کنید. در زمان نوشتن این مطلب من از نسخه 3.5.0.3 استفاده کردم.برای فعال کردن این پلاگین نیاز هست که در فایل پیکره‌بندی Neo4j خط زیر را اضافه کنید.dbms.unmanaged_extension_classes=org.neo4j.graphql=/graphqlو مجددا Neo4j را راه‌اندازی مجدد کنید../neo4j restartدانلود اطلاعات آسیب‌پذیری‌ها(CVE) و ضعف‌ها(CWE)اکنون که Neo4j به همراه پلاگین‌های مورد نیاز نصب و راه‌اندازی شده است. نیاز به دانلود فایل‌های آسیب‌پذیری داریم. این فایل‌ها را می‌توانید به صورت دستی از اینجا دانلود کنید و در دایرکتوری import قرار دهید یا با استفاده از اسکریپت‌هایی که در گیت‌هاب قرار داده‌ام به روش زیر دانلود کنید.git clone https://github.com/zaghaghi/neo4j-cve-scripts
cd neo4j-cve-scripts
pip install -r requirements.txt
python download-cve.py --neo4j-dir &lt;Neo4j-Installation-Directory&gt; --start-year 2002 --end-year 2019علاوه بر آسیب‌پذیری‌ها، اطلاعات جامعی هم در مورد ضعف‌های امنیتی نرم‌افزاری و سخت‌افزاری وجود دارد که می‌بایستی فایل آن را از اینجا دانلود کرده و از حالت فشرده خارج کنید و در دایرکتوری import قرار دهید. در زمان نوشتن این مطلب من این فایل را دانلود و استفاده کردم.واردکردن اطلاعات در Neo4jبرای وارد کردن تمامی اطلاعات می‌بایستی از اسکریپت‌هایی که در پروژه گیت‌هاب قرار داده‌ام استفاده کنید. قبل از اجرای دستورات زیر بایستی دایرکتوری bin مربوط به Neo4j را در PATH قرار دهید تا بتوانیم به راحتی از برنامه cypher-shell استفاده کنیم.git clone https://github.com/zaghaghi/neo4j-cve-scripts
cd neo4j-cve-scripts
# اعمال محدودیت‌ها بر روی فیلد‌های منحصر به فرد
cat constraints.cypher | cypher-shell -u neo4j -p &lt;PASSWORD&gt;
# وارد کردن اطلاعات مربوط به آسیب‌پذیری‌ها
cat load-cve.cypher | cypher-shell -u neo4j -p &lt;PASSWORD&gt;
‌# وارد کردن اطلاعات مربوط به ضعف‌ها
cat load-cwe.cypher | cypher-shell -u neo4j -p &lt;PASSWORD&gt;
# ثبت شمای داده‌ها برای گراف‌کیو‌ال
cat graphql-schema.cypher | cypher-shell -u neo4j -p &lt;PASSWORD&gt;اگر در هنگام اجرای دستورات بالا با خطاهایی مرتبط با کافی نبودن حافظه، می‌توانید مقادیر مربوط به حافظه را در فایل پیکره‌بندی به شکل زیر تغییر دهید.dbms.memory.heap.initial_size=1024m
dbms.memory.heap.max_size=4096mاکنون که اطلاعات دانلود شده‌اند و در Neo4j قرار گرفته‌اند زمان کوئری گرفتن بر روی اطلاعات است که در قسمت سوم در این‌باره به صورت کامل صحبت خواهم کرد.</description>
                <category>حامد ذقاقی</category>
                <author>حامد ذقاقی</author>
                <pubDate>Tue, 07 May 2019 20:23:36 +0430</pubDate>
            </item>
                    <item>
                <title>آسیب‌پذیری‌ها را جدی بگیریم! - قسمت اول</title>
                <link>https://virgool.io/@zaghaghi/vulnerability-browser-part-1-oha0hvdtfv8j</link>
                <description>فهرستقسمت اول - معرفی مراکز انتشار آسیب‌پذیریقسمت دوم - نصب و پیکره‌بندی گراف دیتابیس Neo4jقسمت سوم - جستجو و گزارش‌گیریمقدمههمیشه و هر زمان یکی از اخبار همیشگی تکنولوژی، خبرها و اطلاعیه‌های مربوط به نفوذ به سیستم‌هایی است که به نحوی حاوی اطلاعات طبقه‌بندی شده، اطلاعات شخصی و امثال این‌ها هستند و هکرها توانسته‌اند با استفاده از آسیب‌پذیری‌هایی که در این سیستم‌ها وجود داشته‌اند استفاده کنند و به آن‌ها نفوذ کنند.اگر به هر نحوی با توسعه، استقرار و نگهداری سیستم‌های نرم‌افزاری سر و کار دارید، دانستن آسیب‌پذیری‌های  آن‌ها از مهم‌ترین کارهاست. چرا که کمک میکنه قبل از نفوذ خرابکارها نسبت به برطرف کردن این آسیب‌پذیری‌ها اقدام کنید.اگر کمی در مورد آسیب‌پذیری‌ها جستجو کنید متوجه خواهید شد که سازمان‌های مختلفی به صورت پیوسته در حال شناسایی و اطلاع رسانی این آسیب‌پذیری‌ها هستند و اگر امنیت سیستم‌های نرم‌افزاری‌تان برایتان اهمیت دارد باید جزو اولین نفراتی باشید که از آن‌ها با خبر می‌شوید.یکی از این سازمان‌ها NSA یا همان آژانس امنیت ملی آمریکاست که این اطلاعات را در پایگاه آسیب‌پذیری‌ها منتشر می‌کند. تمامی آسیب‌پذیری‌ها از سال ۲۰۰۲ میلادی تا الان در قسمت دانلود پایگاه آسیب‌پذیری‌ها قابل دریافت است. اطلاعات در فرمت‌های مختلفی قرار داده شده است از جمله XML و JSON که فرمت XML قدیمی شده و در آینده پشتیبانی نمی‌شود. در فرمت JSON، آسیب‌پذیری‌های هر سال در یک فایل با نام همان سال آورده شده است و دو فایل دیگر که حاوی اطلاعات به روزرسانی است به شرح زیر است:فایل recent: حاوی آخرین آسیب‌پذیری‌ها در ۸ روز گذشته است و هر دو ساعت یک بار به روز می‌شود.فایل modified: حاوی تغییرات مربوط به آسیب‌پذیری‌هایی است که قبلا ارائه شده‌اند. این فایل نیز تغییرات ۸ روز گذشته را شامل می‌شود و هر دو ساعت یکبار به روز می‌شود.هر آسیب‌پذیری یک نام منحصر به فرد به صورت CVE-2019-0240 دارد که از سه بخش تشکیل شده. بخش میانی سالی است که آسیب‌پذیری گزارش شده است و بخش آخر شماره این آسیب‌پذیری در آن سال است.در اینجا می‌توانید یک سند JSON شامل یک نمونه از آسیب‌پذیری‌ها را مشاهده کنید. همانطور که در این سند مشاهده می‌کنید، اطلاعات بسیار متنوع و مفیدی هستند و باید از این اطلاعات به خوبی استفاده کرد.پایگاه‌دادهبه احتمال زیاد شما هم مثل من بعد از دیدن این حجم بسیار زیاد از اطلاعات مربوط به آسیب‌پذیری‌ها، به این نتیجه رسیده‌اید که بهترین کار پردازش این فایل‌های JSON و ذخیره کردن‌شون در یک پایگاه‌داده است و از آن جایی که هر آسیب‌پذیری یک سند JSON است یکی از اولین پایگاه داده‌هایی که به ذهن خطور می‌کند پایگاه‌داده‌ای همچون MongoDB است.اما به نظر من دلایل خوبی وجود دارد که استفاده از یک گراف دیتابیس می‌تواند چشم‌انداز بهتری از اطلاعات را به ما نشان دهد. آسیب‌پذیری‌ها از جنبه‌های مختلفی به هم مرتبط هستند از جمله محصولی که دارای این آسیب‌پذیری استنسخه‌های مختلف یک محصول که دارای این آسیب‌پذیری هستندسازنده‌ای که این آسیب‌پذیری در محصولاتش پیدا شده استنحوه و میزان ضربه‌ای که این آسیب‌پذیری می‌تواند وارد کندضعف امنیتی که باعث این آسیب‌پذیری شده استاگر این ارتباطات به خوبی و درستی حفظ شوند به یافتن و بازیابی هرچه بهتر آسیب‌پذیری‌ها کمک می‌کنه. در هر حال اگر شما هم مثل من فکر می‌کنید که استفاده از یک گراف دیتابیس گزینه خوبی است، ادامه مطلب را دنبال کنید.کدام گراف دیتابیسبا کمی جستجو متوجه می‌شوید که تعداد گراف دیتابیس‌ها اصلا کم نیست و انتخاب هر کدامشان می‌تواند معایب و مزایای خودش را داشته باشد و من قصد دارم که از گراف دیتابیس Neo4j برای ذخیره سازی اطلاعات استفاده کنم. یکی از دلایلی که در قسمت بعد بیشتر در موردش توضیح خواهم داد این موضوع است که Neo4j برای جستجو در پایگاه‌داده علاوه بر زبان مخصوص به خودش یعنی Cypher امکان استفاده از Graphql را هم فراهم کرده است.در قسمت دوم نحوه نصب و پیکره‌بندی Neo4j به همراه نحوه وارد کردن اطلاعات به Neo4j و راه‌اندازی Graphql</description>
                <category>حامد ذقاقی</category>
                <author>حامد ذقاقی</author>
                <pubDate>Tue, 07 May 2019 20:15:25 +0430</pubDate>
            </item>
                    <item>
                <title>بررسی تصاویر تولید شده توسط کاربران</title>
                <link>https://virgool.io/@zaghaghi/nsfw-image-classifier-on-browser-kk4bivo1oyja</link>
                <description>تقریبا تمامی کسانی که کسب و کارهایی دارند که بر مبنای تصاویر یا ویدئوهای تولید شده توسط کاربر کار‌میکند، دغدغه این را دارند که این تصاویر حاوی محتوای غیر اخلاقی نباشند. این دغدغه به دلایل مختلفی از جمله فیلترینگ برای صاحبان این کسب و کارها دارای اهمیت است.معمولا کسب و کارهای بزرگ که با تصاویر تولید شده توسط کاربران سروکار دارند، به روش‌های مختلف این مشکل را حل کرده‌اند، چه با کمک اپراتورهای انسانی چه با کمک یادگیری ماشین.امروزه استفاده از یادگیری ماشین در کسب و کارهای مختلف جایگاه ویژه‌ای دارد و اگر شما هم برای حل این مشکل در کسب و کار خودتون تصمیم به استفاده از یادگیری ماشین را دارید موارد زیر را در نظر بگیرید:ساخت یک تیم کوچک از مهندسان یادگیری ماشینجمع آوری دیتای مورد نیازآموزش شبکه‌های مختلف برای رسیدن به نتیجه مطلوبدر نظر گرفتن سرور یا سرورهای مورد نیاز برای بررسی تصاویرخوشبختانه بیشتر فارغ‌التحصیلان رشته هوش‌مصنوعی یا رشته‌های مرتبط بر روی مسایل مرتبط با تصویر کار کرده‌اند و از این جهت برای ساخت این تیم خیلی با مشکل مواجه نخواهید شد.معمولا برای مسايل مختلف مرتبط با تصویر می‌توان از دیتاست‌های عمومی در این زمینه استفاده کرد ولی اینجا و در این مساله کمی اوضاع متفاوت است، چرا که ممکن است تعریفی که شما از محتوای غیراخلاقی دارید با تعریفی که در دیتاست‌های عمومی موجود است متفاوت باشد و شما نیاز به جمع‌ آوری دیتاست دارید. اگر از مدل‌هایی استفاده کنید که دارای فایل‌های پیش‌آموزش داده شده باشند (Pretrained Models) به عنوان مثال مدل GoogLeNet که بر روی دیتاست ImageNet آموزش داده شده باشد، نیاز به جمع آوری دیتای بسیار زیاد ندارید و می‌توانید با استفاده از انتقال آموزش (Transfer Learning) کار خود را تسریع کنید و نتایج بهتری بگیرید.یکی از جاهایی که معمولا با مشکل روبرو می‌شوید تجهیز سرورهایی است که باید عملیات بررسی تصاویر را بر روی مدل‌های آموزش داده شده انجام دهد. معمولا نیاز به کارت‌های گرافیکی گران قیمت به همراه سرورهایی که بتوانند تعداد بالای کارت‌های گرافیکی را پشتیبانی کنند، دارید و این بخشی است که هزینه بسیاری را به شما متحمل می‌کند. در ادامه به راه‌حلی برای این مشکل می‌پردازم.یکی از راه‌ها برای کم کردن پردازش سمت سرور انجام تمامی و یا بخشی از آن سمت کلاینت است. در زمان‌هایی که نرم‌افزار بر روی دسکتاپ و یا موبایل اجرا می‌شود انجام این کار پیچیدگی چندانی ندارد به همین در بخش بعدی به حل این مساله در زمانی که کاربر از طریق وب اپلیکیشن تصویر را ارسال می‌کند می‌پردازم.وب‌اسمبلی و WebDNNبا همه‌گیر شدن وب‌اسمبلی (WebAssembly) و پشتیبانی بر روی بیشتر مرورگرها و امکان اجرای کدهای نوشته شده به زبان‌هایی همچون C/C++ بر روی مرورگر، ابزارهای بسیار زیادی برای مرورگرها توسعه داده شده‌اند از جمله کتابخانه‌های مختلفی برای اجرای مدل‌های یادگیری ماشین بر روی مرورگر. یکی از این‌ها WebDNN است که امکان اجرای مدل‌های آموزش‌داده شده زیر را دارد.Tensorflow (v1.2.0 - v1.4.0)Keras (v2.1.3 - )PyTorch (v0.3.0 - v0.4.1)Chainer (v1.23.0 - v4.0.0)Caffeبرای اینکه با ابزارهای مختلف یادگیری ماشین به خصوص یادگیری عمیق بر روی مرورگر بیشتر آشنا شوید، پیشنهاد می‌کنم این مقاله را مطالعه کنید.Moving Deep Learning into Web Browser: How Far Can We Go?مدل OpenNSFW تصاویر NSFW، تصاویر نامناسب برای محیط کار هستند و در زیر تعبیر ویکی‌پدیا برای آن را می‌بینیدیک اصلاح عامیانه یا تندنویسی است که به رسانه (تصاویر، کلیپ، ویدئو، فیلم) یا وب سایت‌هایی که شامل برهنگی، پورنوگرافی، ناسزا، خشونت، و/یا دیگر موضوعات به‌طور بالقوه آزاردهنده است، که بیننده ممکن است مایل به دیدن در یک محیط عمومی یا رسمی، از جمله محل کار یا مدرسه نباشد، گفته می‌شود.تقریبا ۳ سال پیش یاهو یک مدل برای شناسایی این تصاویر ارائه کرد به نام OpenNSFW  که در گیت‌هاب قابل مشاهده است. این مدل به همراه فایل پیش‌آموزش داده شده ارائه شده است. یاهو برای این پروژه از Caffe استفاده کرده است و در اصل یک مدل بر پایه ResNet50 است.ترکیب OpenNSFW و WebDNNهمانطور که در ابتدای این نوشته گفتم، یکی از مسایل پیش روی بررسی تصاویر تولید شده توسط کاربر با استفاده از یادگیری ماشین تجهیز سرورهایی برای این امر بود و راه‌حل این مساله انتقال بخش و یا تمامی پردازش به سمت کاربر است. با ترکیب آنچه در بخش دوم گفته شد ما می‌توانیم تصویری را که کاربر می‌خواهد ارسال کند قبل از ارسال به سرور و بر روی مرورگر کاربر بررسی کنیم.برای این کار می‌توانید از پروژه NSFW-WebDNN که در گیت‌هاب قرار داده‌ام به شکل زیر استفاده کنید.git clone https://github.com/zaghaghi/nsfw-webdnn 
cd nsfw-webdnn 
emrun --no_browser --port 8081 .اگر می‌خواهید از مدل‌هایی که خودتان آموزش داده‌اید استفاده کنید، ادامه مطلب را بخوانیدمراحل ساختبرای اینکه بتوانید مدل خود را به معادل WebDNN آن تبدیل کنید نیاز به نصب Emscripten و WebDNN دارید. چنانچه از لینوکس یا مک استفاده نمی‌کنید مراحل نصب را طبق آنچه در مستندات سایت‌های این دو گفته شده است پیش بروید.ابتدا emscripten را نصب کنیدgit clone https://github.com/emscripten-core/emsdk.git
cd emsdk
export EMSDKPATH=$(pwd)
./emsdk install latest
./emsdk activate latestسپس WebDNN را نصب کنید. من برای نصب نیازمندی‌های پایتون از conda استفاده کردم و شما می‌توانید به روشی دیگر انجام دهید.conda create -p env/ python=3.6
source activate env/
pip install numpy setuptools chainer
git clone https://github.com/mil-tokyo/webdnn
cd webdnn
export WEBDNN=$(pwd)
python3 setup.py install
wget http://bitbucket.org/eigen/eigen/get/3.3.3.tar.bz2
tar jxf 3.3.3.tar.bz2
ln -s $(pwd)/eigen-eigen-67e894c6cd8f/Eigen $EMSDKPATH/emscripten/*/system/local/includeبرای تبدیل مدل آموزش داده شده از اسکریپتی که به همراه WebDNN آمده است به شکل زیر استفاده کردم. چنانچه شما مدل خود را آموزش داده‌اید می‌توانید به جای مدل یاهو از مدل خود استفاده کنید و اگر مدل آموزش داده شده با Caffe نبوده است می‌توانید با استفاده از مستندات WebDNN مدل خود را تبدیل کنید.git clone https://github.com/yahoo/open_nsfw
cd open_nsfw/nsfw_model
python $WEBDNN/bin/convert_caffe.py  --input_name data --input_shape &#039;(1,3,224,224)&#039; --output_names fc_nsfw --out output resnet_50_1by2_nsfw.caffemodelیکی از مراحلی که نباید فراموش کنید پیش‌پردازش تصویر است. مدل‌های مختلف پیش‌پردازش‌های مختلفی دارند و برای رسیدن به جواب‌های درست حتما باید این پیش‌پردازش‌ها بر روی تصاویر انجام شوند. WebDNN برای این کار متدی دارد که در زیر می‌بینید.پیش پردازش مدل OpenNSFW که با استفاده ابزارهای Caffe انجام شده است.caffe_transformer = caffe.io.Transformer({&#039;data&#039;: nsfw_net.blobs[&#039;data&#039;].data.shape})
caffe_transformer.set_transpose(&#039;data&#039;, (2, 0, 1))  # move image channels to outermost
caffe_transformer.set_mean(&#039;data&#039;, np.array([104, 117, 123]))  # subtract the dataset-mean value in each channel
caffe_transformer.set_raw_scale(&#039;data&#039;, 255)  # rescale from [0, 1] to [0, 255]
caffe_transformer.set_channel_swap(&#039;data&#039;, (2, 1, 0))  # swap channels from RGB to BGRانجام همین پیش‌پردازش با استفاده از WebDNNlet image_array = await WebDNN.Image.getImageArray(img_src, {
    dstW: 224, dstH: 224,
    bias: [104, 117, 123],
    color: WebDNN.Image.Color.BGR,
    order: WebDNN.Image.Order.CHW,
});</description>
                <category>حامد ذقاقی</category>
                <author>حامد ذقاقی</author>
                <pubDate>Tue, 02 Apr 2019 16:44:08 +0430</pubDate>
            </item>
                    <item>
                <title>تخفیف هایپربولیک: چرا انتخاب‌های بسیار بدی در زندگی می‌کنید</title>
                <link>https://virgool.io/@zaghaghi/hyperbolic-discount-h7rnuw77bjne</link>
                <description>نوشته: Lakshmi Maniنسخه اصلی:https://www.nirandfar.com/2017/08/hyperbolic-discounting-why-you-make-terrible-life-choices.htmlتا حالا اتفاق افتاده که کوهی از کارها برای انجام داشته باشید ولی بنا به دلایلی نخواهید انجام دهید؟ یک ضرب‌العجل مهم کاری در حال نزدیک شدنه، رئیس‌تون روی شما تمرکز کرده و فشار زیادی روی شما است. به عبارتی تمامی نشانه‌ها مبنی بر این هست که شما باید آن کار را به اتمام برسانید. با این حال کار رو کناری میذارید، تلویزیون رو روشن می‌کنید و در خیالتون خودتون رو تصور میکنید که فردا در حال انجام اون کار هستید. شما قربانی تخفیف هایپربولیک هستید. تخفیف هایپربولیک یک سوگیری شناختی است که افراد ترجیح می‌دهند پاداش‌های کوچک و سریع را انتخاب کنند تا اینکه پاداش‌ّهای بزرگتر ولی دیرتر را.محققان آزمایشی انجام داده‌اند که این پدیده را نشان می‌دهد. تصور کنید که شما ۲ انتخاب دارید: امروز ۱۰۰ هزار تومان جایزه بگیرید یا یک هفته بعد ۱۲۰ هزار تومان. کدام را انتخاب می‌کنید؟ بیشتر افراد این‌گونه انتخاب می‌کنند.اما وقتی همین سوال برای یک سال بعد و با همین فاصله یک هفته‌ای پرسیده بشود، اکثر ما پاداش بزرگ‌تر را انتخاب می‌کنیم. ما بی‌صبر هستیم و پاداش‌های بلافاصله را در بازه زمانی کم ترجیح می‌دهیم. اما در مورد پاداش‌های بلند مدت پاداش‌های بهتر را ترجیح می‌دهیم و برای آن صبر می‌کنیم.متاسفانه انتخاب‌های شما در زندگی روز‌مره به این شکل واضح و قابل مقایسه نیستند. فرض کنید تصمیم دارید در چند ماه آینده به تعطیلات بروید. چگونه بین لذت بردن از یک شیرینی خوشمزه همین الان و خوب ظاهر شدن در کنار ساحل یکی را انتخاب می‌کنید؟  بسیاری از انتخاب‌های مهم زندگی‌مان شامل سلامتی جسم و روحمان، وضع مالی‌مان و اوضاع کاری‌مان تحت تاثیر تخفیف هایپربولیک قرار می‌گیرند. تمامی این انتخاب‌ها نیازمند گذشتن از لذت‌های کنونی برای آینده‌ای بهتر است.هنگامی که کاری را به تعویق می‌اندازید، بین خشنودی لحظه‌ای از لذت بردن‌تان در حال حاضر و پاداش به اتمام رساندن کاری را که باید انجام دهید، اولی را انتخاب می‌کنید.شما می‌دانید که پول بیمه بازنشستگی بسیار مهم است. با این حال، شما ولخرجی و ریخت و پاش برای خوشی در یک شب با دوستان‌تان را که هم اکنون لذت بخش است، انتخاب می‌کنید، در حالی که ممکن است بهترین انتخاب برای آینده شما نباشد.چرا اینطوری هستم؟ سوگیری‌های شناختی، میان‌برهای ذهنی ما هستند که معمولا به ما در جهت سریع انتخاب کردن کمک می‌کنند، اما این انتخاب‌ها همیشه بهترین نیستند.مغز ما هیچ وقت برای واقعا معقول بودن ساخته نشده است چرا که پردازش اطلاعات بسیار زیاد موجود در جهان بسیار بیشتر از توان‌مان است.  در عوض به شکلی تکامل یافته‌ایم که بتوانیم انتخاب‌های سریعی داشته باشیم.یک غارنشین مجبور نبوده است که با انتخاب‌های پیچیده‌ای که امروزه ما با آن سر و کار داریم، دست و پنجه نرم کند. یک غارنشین هرگز نیازی نداشته است تا بین اینکه امروز یک خوک بخورد یا سرمایه‌گذاری کند تا در آینده ۴ خوک برای خوردن داشته باشد، انتخاب کند.به خاطر زندگی کردن تحت شرایط خشن و سخت‌، ما نمی‌دانستیم که تا آخر روز زنده خواهیم ماند یا نه، بنابراین گونه ما به شکلی تکامل پیدا کرد تا سریع‌ترین گزینه‌ای که شانس زنده ماندن‌مان را بیشتر می‌کرد، انتخاب کند. مغز ما به شکلی ساخته شده است که چیز‌های قطعی و زود را به جای چیز‌های بالقوه و دیر انتخاب می‌کند.پس... بیچاره شدم؟نه! راه‌هایی برای بهتر انتخاب کردن وجود دارد.۱. دلتون به حال «شُمایِ آینده» هم بسوزه«شمای آینده» همان شما هستید در آینده. همان کسی که شما کارها را به او محول می‌کنید. این کار را می‌کنید چون ساده است. ساده است که فرض کنید «شمایِ آینده» انرژی، توان و انگیزه نامحدودی دارد. متاسفانه این چشم انداز تمام عیار در مورد آینده اصلا حقیقت ندارد.قبل از اینکه کاری رو به آینده محول کنید درباره وضعیت ذهنی «شمایِ آینده» فکر کنید، به اینکه چقدر ممکن است خسته، بی‌حال و خواب‌آلود باشه. سنجیدن آگاهانه اینکه به چه اندازه می‌توان به «شمایِ آینده» برای انجام آن کار اطمینان و امید داشت، می‌تواند انگیزه‌ای شود برای انجام کارهایی که می‌خواهید امروز انجام دهید.۲. پیش تعهدتخفیف هایپربولیک، این نکته را عنوان می‌کند که زمانی‌که تصمیم‌گیری‌ها نزدیک نیستند، ما علاقه داریم که کارها را به تعویق بیاندازیم.یک پیش تعهد، راهی است برای مجبور کردن «شمایِ آینده» به تصمیم‌گیری. «شمایِ آینده» ممکن است که الان شما را وسوسه کند ولی بعدا از زیرش شانه خالی کند. با از بین بردن این وسوسه شانس‌تان برای موفقیت را افزایش می‌دهید.  تحقیقات نشان داده است که افرادی که به پرداخت بخشی از حقوق‌شان برای بازنشستگی متعهد می‌شوند، بیشتر از بقیه هم پول جمع می‌کنند.سامانه‌های اشتراک تحویل غذا مانند Freshly و Blue Apron از روش پیش تعهد استفاده می‌کنند تا مشتریانشان سفارش غذاهایشان را به صورت خودکار دریافت کنند. شما می‌توانید با مشترک شدن در این سامانه‌ها و دریافت هفتگی غذاهای سالم در جایی که هستید، شانس درست غذا خوردن در زمان مناسب را افزایش دهید.روش‌های دیگر پیش تعهد می‌توانند شامل این‌ها باشند: برنامه ریزی روزانه، کمک گرفتن از شخص دیگری برای پیگیری درست انجام دادن کارهایتان یا به روش «Nir Eyal»، پولی را کنار بگذارید و اگر کاری را که تعهد به انجامش داده‌اید را به انجام نرساندید، آن پول را آتش بزنید!۳. اهداف بزرگ را به قسمت‌های کوچک قابل مدیریت بشکنیدآیا شما کسی هستید که اهداف بزرگ و رفیع را هدف می‌گیرید تا به پاداش عظیمی که دارد دست یابید؟ معمولا نه. دست یابی به اهداف بزرگی مثل یادگیری زبان اسپانیایی یا کم کردن ۱۰ کیلوگرم وزن، نیازمند صرف زمان زیادی است، پس مستعد افتادن در دام تخفیف هایپربولیک است.اگر قرار باشید بین تماشای تلویزیون همین حالا که پاداشی زود و کوچک دارد و کار کردن در جهت هدف بزرگ‌تان که پاداشی بزرگ ولی دیر دارد، یکی را انتخاب کنید، در اکثر مواقع پاداش کوچک و زود را ترجیح می‌دهید.با شکستن اهداف بزرگ به وظایف کوچک، به جای اینکه پاداش را در انتها دریافت کنید آن را با اتمام هر وظیفه کوچکی دریافت می‌کنید. با این روش، پاداش دیگر یک امکان دور از دسترس نیست بلکه چیزی است سریع و قابل دست یابی. نتیجهقبول کردن تاثیر تخفیف هایپربولیک در تصمیم‌گیری‌های روزمره و ارزیابی آگاهانه معامله بین آینده و حال، به شما کمک می‌کند تا کاری را که واقعا می‌خواهید انجام دهید. به من اعتماد کنید، در آینده قدردان من خواهید شد.</description>
                <category>حامد ذقاقی</category>
                <author>حامد ذقاقی</author>
                <pubDate>Tue, 22 Aug 2017 20:51:21 +0430</pubDate>
            </item>
            </channel>
</rss>