<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های زرتشت سپیدمان</title>
        <link>https://virgool.io/feed/@zartosht</link>
        <description>یه برنامه‌نویس ساده‌ی بک‌اند که گاهی مجسمه‌های چوبی هم می‌سازه و همیشه دوست داره مشکلات رو یه‌جوری حل کنه که کس دیگه‌ای حلش نکرده. اینجا راه حل مشکلاتی که حل می‌کنم رو سعی می‌کنم بنویسم.</description>
        <language>fa</language>
        <pubDate>2026-06-16 15:58:56</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/180354/avatar/CFzirQ.png?height=120&amp;width=120</url>
            <title>زرتشت سپیدمان</title>
            <link>https://virgool.io/@zartosht</link>
        </image>

                    <item>
                <title>چرا نباید در لوپ await وجود داشته باشد</title>
                <link>https://virgool.io/CodeLovers/%DA%86%D8%B1%D8%A7-%D9%86%D8%A8%D8%A7%DB%8C%D8%AF-%D8%AF%D8%B1-%D9%84%D9%88%D9%BE-await-%D9%88%D8%AC%D9%88%D8%AF-%D8%AF%D8%A7%D8%B4%D8%AA%D9%87-%D8%A8%D8%A7%D8%B4%D8%AF-bdyunv7whnwh</link>
                <description>چرا نباید در لوپ await وجود داشته باشد.یکی از اشتباهاتی که معمولا هر تازه‌کاری در مواجهه با زبان جاواسکریپت انجام می‌ده. استفاده نابجا از await توی لوپ هستش. این اشتباه یعنی چی؟const list: number[] = [1,2,3,4,5];
list.map(async (i): Promise&lt;void&gt; =&gt; {
    await someAsyncFunction(i);
});احتمالا خیلیا (خود من تا یک ماه پیش!) این اشتباه رو می‌کردم. فرض کنید که این تابع someAsyncFunction توی مثال بالا قراره ۳۰۰ میلی ثانیه زمان صرف کنه تا محاسبتاش رو انجام بده! (آره خیلی کار خاصی با یه ورودی اینتجر می‌کنه?).خب با این زمانی که قراره صرف کنه کل این لوپ ۱.۵ ثانیه زمان برای انجامش کد شما/کاربر شما/ خط بعدی کد شما و ... غیره باید خیره با آفاق مغربی بمونه تا جواب برگرده.اما راه حل بهتر شدن بازدهیکد بالا با یه تغییر کوچیک می‌تونه به شدت توی پرفورمنس و بازدهی تغییر ایجاد کنه:async someAsyncFunction(i: number) : Promise&lt;void&gt; {
    ... ANJAME YE KARE ZAMANBAR...
}

const list: number[] = [1,2,3,4,5];
const queries: Promise&lt;void[]&gt; = [];
list.map(i =&gt; queries.push(someAsyncFunction(i)));

await Promise.all(queries);الان چه اتفاقای افتاد؟ ما به‌جای این‌که برای حل شدن هر مرحله صبر کنیم، به همه گفتیم که برن اجرا بشن و اون Promise ها رو ریختیم تو یه آرایه که بتونیم کنترلشون کنیم. تو خط آخر هم منتظر می‌مونیم اونایی که هنوز تموم نشدن تموم شن.این‌جوری شاید یکم بیشتر از زمان مورد نیاز برای یک بار انجام شدن این محاسبه زمان نیاز داشته باشین! یعنی همون ۳۰۰ میلی ثانیه!یه راه دیگه هم برای نوشتن همون مثال بالا هست:async someAsyncFunction(i: number) : Promise&lt;void&gt; {
     ... ANJAME YE KARE ZAMANBAR...
}

const list: number[] = [1,2,3,4,5]; 
await Promise.all(list.map(i =&gt; someAsyncFunction(i)));فرق این حال با حالت قبلی اینه که کل این داستان‌ها باید تموم شن تا خطوط بعدی اجرا بشن اما گاهی ما اصلا به انجام شدن این لوپ تا آخر مسیر نیازی نداریم. پس می‌تونیم اون بخش:await Promise.all(queries);رو بذاریم آخر متدمون اجرا بشه. به این تکنیک می‌گن Concurrent programming.امیدوارم براتون مفید بوده باشه و اگر چیز دیگه‌ای به ذهنتون می‌رسه که من ننوشتم خوشحال می‌شم برام بنویسید?</description>
                <category>زرتشت سپیدمان</category>
                <author>زرتشت سپیدمان</author>
                <pubDate>Fri, 01 Jan 2021 14:07:27 +0330</pubDate>
            </item>
                    <item>
                <title>حل مشکل اتصال از لوکال به کافکا داکرایز شده</title>
                <link>https://virgool.io/@zartosht/%D8%AD%D9%84-%D9%85%D8%B4%DA%A9%D9%84-%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%D8%A7%D8%B2-%D9%84%D9%88%DA%A9%D8%A7%D9%84-%D8%A8%D9%87-%DA%A9%D8%A7%D9%81%DA%A9%D8%A7-%D8%AF%D8%A7%DA%A9%D8%B1%D8%A7%DB%8C%D8%B2-%D8%B4%D8%AF%D9%87-ec16p3hhqjaq</link>
                <description>امروز درگیر یادگیری کافکا شدم و قصد داشتم یه پروژه تستی رو باهاش بیارم بالا. طبق عادت، زوکیپر و کافکا رو با داکر آوردم بالا و شروع کردم به کد زدن با kafkajs. ولی هرکاری می‌کردم وصل نمی‌شد!ظاهرا کار خیلی ساده باید پیش می‌رفت. هرچیم سرچ می‌کردم یسری خط کد نوشته بودن که اینارو کپی پیست کن درست میشه و فلان! منم تا نفهمم مشکل کار از کجاست راه حل رو اجرا نمی‌کنم?ارور این بود:{&amp;quotlevel&amp;quot:&amp;quotERROR&amp;quot,&amp;quottimestamp&amp;quot:&amp;quot2020-09-13T12:46:25.123Z&amp;quot,&amp;quotlogger&amp;quot:&amp;quotkafkajs&amp;quot,&amp;quotmessage&amp;quot:&amp;quot[Connection] Connection error: getaddrinfo EAI_AGAIN 3f8ce0d39217 3f8ce0d39217:9092&amp;quot,&amp;quotbroker&amp;quot:&amp;quot3f8ce0d39217:9092&amp;quot,&amp;quotclientId&amp;quot:&amp;quotmy-app&amp;quot,&amp;quotstack&amp;quot:&amp;quotError: getaddrinfo EAI_AGAIN 3f8ce0d39217 3f8ce0d39217:9092\n    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:56:26)&amp;quot}اما مشکل از کجاست؟ مشکل خیلیا اینه که نمی‌دونیم که برای اتصال به کافکا، تماس اولیه زیاد مهم نیست! تماس دوم که بر اساس متادیتای دریافتی برقرار می‌شه مهمه!یعنی چی؟ یعنی اینکه در اول کار:const { Kafka } = require(&#039;kafkajs&#039;)
const kafka = new Kafka({
    clientId: &#039;my-app&#039;,
    brokers: [&#039;localhost:9092&#039;]
});یه اتصال با بروکر برقرار می‌شه و لیستی از بروکرهای اون کلاستر تحویل می‌گیره و از اون به بعد با اونا صحبت می‌کنه! برای دولوپ هم که نمیشه ما پروژمونو توی داکر دولوپ کنیم! پس باید چی‌کار کنیم؟ باید به کافکا بگیم که advertised.listeners رو آیپی ماشین لوکال ما معرفی کن به‌جای آدرس لوکال خودت که توی نتورک داکر در دسترسه!خوب برای این‌کار باید این تنظیمات رو توی کافکا انجام بدین:advertised.listeners=PLAINTEXT://${HOST_IP}:9092 
listeners=PLAINTEXT://0.0.0.0:9092داخل پرانتز:(می‌تونین دستی آیپیتونو بزنین که کثیف کاریه یا می‌تونین آیپی رو به صورت environment بدین بهش.)یا مثل من توی داکر کامپوز این Environment رو وارد کنین:environment:
    ...
    - KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://192.168.1.133:9092
    ...همین! تموم شد! به همین سادگی! امیدوارم شما مثل من گیر نکنین این‌جا!نمونه کد اتصال رو هم می‌تونین از اینجا ببینین. کافکای داکرایز شده‌ی منم نسخه‌ی بیتنامی بود که می‌تونین از اینجا دریافت کنین.</description>
                <category>زرتشت سپیدمان</category>
                <author>زرتشت سپیدمان</author>
                <pubDate>Sun, 13 Sep 2020 18:56:13 +0430</pubDate>
            </item>
                    <item>
                <title>توسعه نرم‌افزار با روش TDD یا Test Driven Development</title>
                <link>https://virgool.io/coderlife/%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D9%86%D8%B1%D9%85%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D8%A8%D8%A7-%D8%B1%D9%88%D8%B4-tdd-%DB%8C%D8%A7-test-driven-development-jyedanj9l01a</link>
                <description>معمولا توی بیشتر شرکت‌ها وقتی تسکی به یه برنامه‌نویس محول میشه، هیچ مطالعه‌ی درستی روی ورودی و خروجیش انجام نشده. نه تنها خود کارفرما نمی‌دونه چی می‌خواد، که خود برنامه‌نویس هم نمی‌دونه داره چی می‌نویسه و چه انتظاری داره از برنامه‌ای که در حال توسعش هست!این مشکل وقتی خیلی به چشم می‌خوره که تیم بزرگ بشه و مسئول توسعه‌ی هر بخش یک نفر باشه. تست نوشتن و داکیومنت نوشتن هم که برای برنامه‌نویس‌ها مثل شکنجست. کد رو می‌نویسن و می‌گن کار می‌کنه دیگه. این می‌شه که فردایی پس‌فردایی که قراره یه فیچر جدید به اپلیکیشن اضافه بشه یهو می‌بینی همه چی از بیخ و بن از کار افتاد! حالا تو بدو ارور استک بدو!کد نویسی به روش TDD یا Test Driven Developmentشما فرض می‌کنین که وقتی به یه‌نفر می‌گین «دوستت دارم» جوابش «مرسی» باشه! پس خودتون برای این ضایع شدن آماده می‌کنین و شرایط رو برای این شکست آماده می‌کنین و می‌رین و پیشنهاد می‌دین!یه فرض محال دیگه که وقتی به یه‌نفر می‌گین «دوستت دارم» جوابش «منم دوستت دارم» باشه! پس شما می‌دونید که قراره به احتمال هرچند کم خوش‌بخت بشین، پس شروع می‌کنید به آماده سازی شرایط?توی دو مثال بالا شما کامل می‌دونید ورودی‌تون چیه «دوستت دارم» و خروجی قراره تو هرکدوم از این شرایط چی باشه: ۱-مرسی ۲-منم دوستت دارم و ... . اما شخص مقابلی وجود داره؟ نه لزوما! شما فقط می‌دونید در جواب این سوال این دو خروجی صادر می‌شه.رو به دیوار می‌ایستین و می‌گین «دوستت دارم»!دیوار:Response:
    status: 404
    message: Route not found exceptionخب چی شد؟؟ شما از ورودی و خروجی‌تون مطمئن بودین ولی آیا جای درستی ازش استفاده کردین؟ نه!حالا که فهمیدیم نمیشه به دیوار عشق ورزید می‌ریم مدت‌ها و سالیان می‌گردیم و می‌چرخیم و یک نفر رو که فکر می‌کنیم گزینه مناسبیه پیدا می‌کنیم و رو بهش می‌ایستیم و بهش می‌گیم: «دوستت دارم»شخص مناسب:Response:
    status: 403
    message: You are not authorized to do thisباز مشکل کجاست؟ مشکل این‌جاست که شخص رو پیدا کردین ولی آیا مقدمات رو آماده کرده بودین؟ اون طفلک روحشم از قضیه خبر داشت آیا؟ مسلما نه!زمان می‌ذارین بهش توجه می‌کنین و بعد از یه مدت که طرف مقابل دوزاریش افتاد. مجدد رو بهش می‌گین: «دوستت دارم»یکی از پاسخ‌های احتمالی شخصِ مناسبِ آماده شده:Response:
    status: 200
    message: منم دوستت دارمپاسخ احتمالی دوم:Response:
    status: 204
    message: مرسیپاسخ احتمالی سوم:Response:
    status: 301
    message: منم دوستت دارم داداشی/خواهر گلمو یه‌سری پاسخ دیگه!ما این‌جا چه کردیم؟ یه پروسه‌ای (تست) توی مغزمون تشکیل دادیم که در ازای این ورودی چه خروجی‌هایی ممکنه تحویل بگیریم. و یک بار پروسه‌رو صدا کردیم (تست اولیه) ولی چون کدی وجود نداشت، اتفاقی نیفتاد. پس به‌صورت ابتدایی تا اونجا که فکر می‌کردیم درسته پروسه‌رو آماده کردیم (دولوپ) و باز اون چیزی که تو ذهنمون بود را اجرا کردیم (تست). به ارور خوردیم چون فکر یه‌جایی - آماده بودن کامل موقعیت - رو نکرده بودیم. پس با انجام یک‌سری تغییرات (دیباگ) دوباره تست رو انجام دادیم (تست). این پروسه رو انقدر انجام می‌دیم تا تمام باگ‌ها گرفته بشه و در ازای ورودی‌های ما خروجی‌های مورد انتظارمون برآورده بشن.حالا چرا باید اول تست بنویسیم، بعد کد؟یکی از مهم‌ترین مزایای این روش به‌نظرم اینه که شما با نوشتن تست اولیه، تکلیفتون رو با خودتون مشخص می‌کنید و اگر چیزی رو ندونید یا سوالی اون گوشه‌های ذهنتون قایم شده باشه پیدا می‌شه و قبل شروع به‌کار حلشون می‌کنید و از ری‌فکتور کردن‌های بیهوده اجتناب می‌کنین.یکی دیگه از مزایای این روش باز هم به‌نظر من اینه که شما وقتی اول کد رو بنویسین و بعد به‌زور بیاین تستش رو بنویسین، در حقیقت دارین خودتونو گول می‌زنین. انگاری اول درو بسازین، قفلشم بسازین. بعد سعی کنین با خمیر و آدامس (عین این فیلما) کلیدی که اون در رو باز می‌کنه رو بسازین! قشنگ‌تر نیست اگر اولش بدونین این کلید این قفل رو باز می‌کنه و بعد قفل رو روی یه در سوار کنین؟یکی دیگه از مزیت‌هاشم به‌نظر من اینه که وقتی اول تست رو بنویسین، آخر پروژه درگیر فرآیند خسته کننده تست نوشتن نمی‌شین و احتمال زیاد بخش زیادی از تست‌ها رو نمی‌پیچونید!و در آخر هم وقتی همه‌ی کدتون با تست نوشته شده باشه، با هر ریلیز، راحت با انجام یه تست یک‌پارچگی از سلامت نرم‌افزارتون مطمئن می‌شین!اولین بار که با این روش آشنا شدم، مغزم خیلی مقاومت کرد ولی الان که چند وقتیه این‌جوری کد می‌زنم به‌نظرم اومد که چرا از اول این‌کارو نمی‌کردم؟!</description>
                <category>زرتشت سپیدمان</category>
                <author>زرتشت سپیدمان</author>
                <pubDate>Sat, 15 Aug 2020 13:53:49 +0430</pubDate>
            </item>
                    <item>
                <title>ACL برای Lumen و Laravel 7+</title>
                <link>https://virgool.io/@zartosht/acl-%D8%A8%D8%B1%D8%A7%DB%8C-lumen-%D9%88-laravel-7-nsix54fsxvqm</link>
                <description>نقش‌ها و مجوزها همیشه یه بخش مهم از هر وب‌سایت و وب‌اپ رو تشکیل می‌دن. برای این‌کار پلاگین‌ها و ماژول‌های زیادی نوشته شدن ولی وقتی که می‌خواین از یه فریم‌ورک مثل Lumen استفاده کنین، یکم پیدا کردن یه ماژول که بی‌دردسر با پروژتون یک‌پارچه بشه کار راحتی نیست. تازگی‌ها به یه پروژه برخوردم که توش باشد ACL رو پیاده می‌کردم و طبق معمول رفتم سراغ Packagist ولی هرچی نصب کردم اونی نشد که می‌خواستم! آخرشم گفتم کس نخارد پشت من جز نخن انگشت من و شروع کردم به نوشتن این سیستم خیلی ساده و بی‌دردسر.قدم اول: ساخت مدل‌هابرای شروع این‌کار ما به دو مدل اصلی نیاز داریم: Permission و Role. (مدل User هم که قاعدتا وقتی نباشه که چرا پس داریم این‌کارو انجام می‌دیم؟ ?)php artisan make:model Role -m
php artisan make:model Permission -mاون کلید m- هم کارش ساخت فایل‌های migration هستش.قدم دوم: ویرایش فایل‌های migrationمحتوای فایل‌های migration تون رو به شکل زیر  تغییر بدین:مدل User (این مدل خیلی لازم نیست این شکلی باشه، شما می‌تونید بر اساس نیازتون هر فیلدی که دوست داشتید رو بهش اضافه یا ازش کم کنید):public function up()
    {
       Schema::create(&#039;users&#039;, function (Blueprint $table) {
            $table-&gt;increments(&#039;id&#039;);
            $table-&gt;string(&#039;name&#039;);
            $table-&gt;string(&#039;email&#039;,191)-&gt;unique();
            $table-&gt;timestamp(&#039;email_verified_at&#039;)-&gt;nullable();
            $table-&gt;string(&#039;password&#039;);
            $table-&gt;rememberToken();
            $table-&gt;timestamps();
    });
}مدل Permission:use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePermissionsTable extends Migration
{
    
    public function up()
    {
        Schema::create(&#039;permissions&#039;, function (Blueprint $table) {
            $table-&gt;increments(&#039;id&#039;);
            $table-&gt;string(&#039;name&#039;); // edit posts
            $table-&gt;string(&#039;slug&#039;); //edit-posts
            $table-&gt;timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists(&#039;permissions&#039;);
    }
}مدل Role:use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateRolesTable extends Migration
{
    public function up()
    {
        Schema::create(&#039;roles&#039;, function (Blueprint $table) {
            $table-&gt;increments(&#039;id&#039;);
            $table-&gt;string(&#039;name&#039;); // edit posts
            $table-&gt;string(&#039;slug&#039;); //edit-posts
            $table-&gt;timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists(&#039;roles&#039;);
    }
}قدم سوم: ساخت جداول pivot:ارتباط بین user و permissionها:php artisan make:migration create_users_permissions_table --create=users_permissionsو محتواش:use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersPermissionsTable extends Migration
{
    public function up()
    {
        Schema::create(&#039;users_permissions&#039;, function (Blueprint $table) {
            $table-&gt;unsignedInteger(&#039;user_id&#039;);
            $table-&gt;unsignedInteger(&#039;permission_id&#039;);

            //FOREIGN KEY CONSTRAINTS
            $table-&gt;foreign(&#039;user_id&#039;)-&gt;references(&#039;id&#039;)-&gt;on(&#039;users&#039;)-&gt;onDelete(&#039;cascade&#039;);
            $table-&gt;foreign(&#039;permission_id&#039;)-&gt;references(&#039;id&#039;)-&gt;on(&#039;permissions&#039;)-&gt;onDelete(&#039;cascade&#039;);
 
            //SETTING THE PRIMARY KEYS
            $table-&gt;primary([&#039;user_id&#039;,&#039;permission_id&#039;]);
        });
    }

    public function down()
    {
        Schema::dropIfExists(&#039;users_permissions&#039;);
    }
}حالا یکی دیگه، ارتباط بین user و roleها:php artisan make:migration create_users_roles_table --create=users_rolesو محتواش:use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersRolesTable extends Migration
{
    public function up()
    {
        Schema::create(&#039;users_roles&#039;, function (Blueprint $table) {
            $table-&gt;unsignedInteger(&#039;user_id&#039;);
            $table-&gt;unsignedInteger(&#039;role_id&#039;);

         //FOREIGN KEY CONSTRAINTS
           $table-&gt;foreign(&#039;user_id&#039;)-&gt;references(&#039;id&#039;)-&gt;on(&#039;users&#039;)-&gt;onDelete(&#039;cascade&#039;);
           $table-&gt;foreign(&#039;role_id&#039;)-&gt;references(&#039;id&#039;)-&gt;on(&#039;roles&#039;)-&gt;onDelete(&#039;cascade&#039;);

         //SETTING THE PRIMARY KEYS
           $table-&gt;primary([&#039;user_id&#039;,&#039;role_id&#039;]);
        });
    }

    public function down()
    {
        Schema::dropIfExists(&#039;users_roles&#039;);
    }
}و آخری برای ارتباط بین role و permission:php artisan make:migration create_roles_permissions_table --create=roles_permissionsو محتوای آخری:use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateRolesPermissionsTable extends Migration
{
    public function up()
    {
        Schema::create(&#039;roles_permissions&#039;, function (Blueprint $table) {
             $table-&gt;unsignedInteger(&#039;role_id&#039;);
             $table-&gt;unsignedInteger(&#039;permission_id&#039;);

             //FOREIGN KEY CONSTRAINTS
             $table-&gt;foreign(&#039;role_id&#039;)-&gt;references(&#039;id&#039;)-&gt;on(&#039;roles&#039;)-&gt;onDelete(&#039;cascade&#039;);
             $table-&gt;foreign(&#039;permission_id&#039;)-&gt;references(&#039;id&#039;)-&gt;on(&#039;permissions&#039;)-&gt;onDelete(&#039;cascade&#039;);

             //SETTING THE PRIMARY KEYS
             $table-&gt;primary([&#039;role_id&#039;,&#039;permission_id&#039;]);
        });
    }

    public function down()
    {
        Schema::dropIfExists(&#039;roles_permissions&#039;);
    }
}حالا نوبت چیه؟ migrate کردن!php artisan migrateقدم چهارم: راه‌اندازی ارتباطات در مدل‌هامدل Rolepublic function permissions() {

   return $this-&gt;belongsToMany(Permission::class,&#039;roles_permissions&#039;);
       
}

public function users() {

   return $this-&gt;belongsToMany(User::class,&#039;users_roles&#039;);
       
}مدل Permission:public function roles() {

   return $this-&gt;belongsToMany(Role::class,&#039;roles_permissions&#039;);
       
}

public function users() {

   return $this-&gt;belongsToMany(User::class,&#039;users_permissions&#039;);
       
}حالا باید یه trait درست کنیم و متدهای مورد نیاز ACL رو توش اضافه کنیم.داخل پوشه app یه پوشه درست کنین به این Permissions و توش یه trait بسازین به اسم HasPermissionsTrait.php.حالا توی مدل User این trait رو import کنین:namespace App;

use App\Permissions\HasPermissionsTrait;

class User extends Authenticatable
{
    use HasPermissionsTrait; //Import The Trait
}محتوای فایل HasPermissionsTrait.php رو به شکل زیر تایپ کنید:namespace App\Permissions;

use App\Permission;
use App\Role;

trait HasPermissionsTrait {

   public function givePermissionsTo(... $permissions) {

    $permissions = $this-&gt;getAllPermissions($permissions);

    if($permissions === null) {
      return $this;
    }
    $this-&gt;permissions()-&gt;saveMany($permissions);
    return $this;
  }

  public function withdrawPermissionsFrom( ... $permissions ) {

    $permissions = $this-&gt;getAllPermissions($permissions);
    $this-&gt;permissions()-&gt;detach($permissions);
    return $this;

  }

  public function refreshPermissions( ... $permissions ) {

    $this-&gt;permissions()-&gt;detach();
    return $this-&gt;givePermissionsTo($permissions);
  }

  public function hasPermissionTo($permission) {

    return $this-&gt;hasPermissionThroughRole($permission) || $this-&gt;hasPermission($permission);
  }

  public function hasPermissionThroughRole($permission) {

    foreach ($permission-&gt;roles as $role){
      if($this-&gt;roles-&gt;contains($role)) {
        return true;
      }
    }
    return false;
  }

  public function hasRole( ... $roles ) {

    foreach ($roles as $role) {
      if ($this-&gt;roles-&gt;contains(&#039;slug&#039;, $role)) {
        return true;
      }
    }
    return false;
  }

  public function roles() {

    return $this-&gt;belongsToMany(Role::class,&#039;users_roles&#039;);

  }
  public function permissions() {

    return $this-&gt;belongsToMany(Permission::class,&#039;users_permissions&#039;);

  }
  protected function hasPermission($permission) {

    return (bool) $this-&gt;permissions-&gt;where(&#039;slug&#039;, $permission-&gt;slug)-&gt;count();
  }

  protected function getAllPermissions(array $permissions) {

    return Permission::whereIn(&#039;slug&#039;,$permissions)-&gt;get();
    
  }

}با استفاده از این trait می‌تونیم این‌جوری ازش استفاده کنیم:$user = $request-&gt;user(); //getting the current logged in user
dd($user-&gt;hasRole(&#039;admin&#039;,&#039;editor&#039;)); // and so onقدم پنجم: ساخت Service Providerلاراول یه متد قشنگ داره به اسم can، ولی ما یه متد داریم به اسم hasPermissionTo. قشنگ نیست نه؟ خب باید یکاری کنیم که بتونیم از اون can استفاده کنیم:php artisan make:provider PermissionsServiceProviderتوی این Provider این محتوا رو تایپ کنین:namespace App\Providers;

use App\Permission;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\ServiceProvider;

class PermissionsServiceProvider extends ServiceProvider
{
   
    public function register()
    {
        //
    }

    public function boot()
    {
        try {
            Permission::get()-&gt;map(function ($permission) {
                Gate::define($permission-&gt;slug, function ($user) use ($permission) {
                    return $user-&gt;hasPermissionTo($permission);
                });
            });
        } catch (\Exception $e) {
            report($e);
            return false;
        }
// اگر Lumen استفاده می‌کنین این پایین رو بیخیال شین
        //Blade directives
        Blade::directive(&#039;role&#039;, function ($role) {
             return &amp;quotif(auth()-&gt;check() &amp;&amp; auth()-&gt;user()-&gt;hasRole({$role})) :&amp;quot //return this if statement inside php tag
        });

        Blade::directive(&#039;endrole&#039;, function ($role) {
             return &amp;quotendif;&amp;quot //return this endif statement inside php tag
        });

    }
}config\app.php&#039;providers&#039; =&gt; [

        App\Providers\PermissionsServiceProvider::class,
    
 ],توی Lumen:bootstrap/app.php$app-&gt;register(App\Providers\PermissionServiceProvider::class);قدم ششم: ساخت Middlewareبرای اینکه بتونیم چک کنیم چه کاربری با چه سطح دسترسی‌ای می‌تونه به کجا دسترسی پیدا کنه و یا نه باید یه Middleware بسازیم و توی اون این چک رو انجام بدیم. این Middleware رو به اسم role برای لاراول توی:app/Http/Kernel.phpو برای لومن توی:bootstrap/app.phpمحتوای این ‌Middleware باید به شکل زیر باشه:&lt;?php
namespace App\Http\Middleware;
use Closure;
class RoleMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request  $request
* @param \Closure  $next
* @return mixed
*/
public function handle($request, Closure $next, $roles = &amp;quot&amp;quot, $permissions = &amp;quot&amp;quot)
{
    // Allow user with this permissions to pass
    if ($request-&gt;user()-&gt;hasRole(&amp;quotMASTER&amp;quot) || $request-&gt;user()-&gt;can(&amp;quotFULL_CONTROL&amp;quot)) {
        return $next($request);
    }

    // Check user roles
    $roles = explode(&amp;quot|&amp;quot, $roles);
    if ($request-&gt;user()-&gt;hasRole($roles)) {
        return $next($request);
    }

    // Check user permissions
    $permissions = explode(&amp;quot|&amp;quot, str_replace(&amp;quotpermissions:&amp;quot, &amp;quot&amp;quot, $permissions));
    foreach ($permissions as $permission) {
        if ($request-&gt;user()-&gt;can($permission)) {
            return $next($request);
        }
    }

    // send failed message to user
    abort(403, trans(&#039;validations.you_are_not_authorized&#039;));
    }
}حالا برای استفاده از این Middleware کافیه که روی route هاتون این رو بنویسید:Route::get(&amp;quottest&amp;quot, &amp;quotTestController@yeMethod&amp;quot)
    -&gt;middleware([&#039;auth&#039;, &#039;role:role1|role2,permissions:permission1,permission2&#039;])همین! به همین سادگی و قشنگی بدون استفاده از پکیج شخص ثالث و درگیری با Dependency ها یه سیستم ACL مجلسی برای پروژتون که با لاراول یا لومن +7 نوشته بودین ساختین!خیلی سعی کردم ساده و مختصر بنویسم و مثل خارجیا از بیخ و بن composer ننویسم ولی امیدوارم گیج کننده نشده باشه!</description>
                <category>زرتشت سپیدمان</category>
                <author>زرتشت سپیدمان</author>
                <pubDate>Thu, 13 Aug 2020 21:44:25 +0430</pubDate>
            </item>
                    <item>
                <title>مدیریت سرور چیست؟ Server Management به زبان ساده</title>
                <link>https://virgool.io/@zartosht/%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%B3%D8%B1%D9%88%D8%B1-%DA%86%DB%8C%D8%B3%D8%AA-server-management-%D8%A8%D9%87-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B3%D8%A7%D8%AF%D9%87-rrux8v65j71m</link>
                <description>قبل از این‌که به توضیح مفهوم مدیریت سرور بپردازیم باید اول ببینیم سرور چیه تا بعد از اون بفهمیم که چرا نیاز به مدیریت داره.سرور چیست؟به بیان ساده، یک کامپیوتر بسیار قدرتمند متشکل از چندین هسته (core)، هارددیسک یا فضای ذخیره‌سازی چندین ترابایتی و RAM بسیار بالاست. خدمات و منابع متعددی رو در اختیار کاربران (Clients) قرار می‌ده. اگر با دید گسترده‌تر به مفهوم سرور نگاه کنیم، می‌بینیم که فضای اینترنت متشکل از تعداد بسیار زیادی از Serverها و Clientهاست که با هم ارتباط دارن. محتوای همه وب‌سایت‌هایی که می‌بینید توی یک یا چندین سرور ذخیره شدن و وقتی که می‌خواین اونها رو ببینین یا توشون تغییراتی ایجاد کنین، در واقع از اونجا فراخوانی می‌شن.سرورها به چند دسته تقسیم می‌شن؟سرورها از لحاظ سیستم عامل، تخصیص منابع و کاربرد به چند دسته تقسیم می‌شن. تخصیص منابع یعنی چه مقدار از منابع اون به کار (وبسایت، اپلیکیشن و…) شما اختصاص داده بشه. اگر یه سایت کوچیک دارین و نیازی به فضای زیادی برای نگه‌داری منابع‌تون ندارین، می‌تونین از شرکت‌هایی که این خدمات رو ارائه می‌دن، سرویس اشتراکی بگیرین. یعنی یه بخشی از یه تمام منابع رو در اختیار داشته باشین.سرور اختصاصی برای کسب و کارهای بزرگ‌تره. سرویس مجازی هم اینطوریه که یه سرور اختصاصی با چندتا ماشین مجازی (VM) به چندتا سرویس مجازی تقسیم می‌شه و کیفیت و تخصیص منابعش از حالت اشتراکی بهتره. حالا همه این سرورها باز به دو دسته داخل کشور و خارج کشور تقسیم می‌شن و شما بسته به نیازمندی‌تون مثلاً سرویس اختصاصی در خارج از کشور (که گرون‌ترینه) تا سرویس اشتراکی ایران یعنی داخل کشور (که ارزون‌ترینه) رو تهیه می‌کنید.حالا مدیریت سرور یعنی چی؟حالا که سرور رو شناختیم صحبت درباره مدیریتش راحت‎‌تر می‌شه. از اون‌جایی که باید همیشه روشن و فعال باشه و دچار اختلال نشه، معمولاً در محیط‌های خاصی مجهز به خنک‌کننده‌های قوی، اینترنت پرسرعت و دارای برق اضطراری نگه‌داری می‌شه. به جایی که این شرایط رو داره و سرورهای زیادی رو در خودش جای می‌ده، دیتا سنتر (Data Center) می‌گن.مدیریت سرور یعنی اجرا و پیاده‌سازی یه سری وظایف از جمله نگه‌داری، به‌روز رسانی، مانیتورینگ و سرویس، امنیت، بهینه‌سازی و سایر کارهایی که باید مرتب روی سرور انجام بشه. این عملیات در بعضی از شرکت‌ها درون خود شرکت و توسط افرادی توی بخش IT انجام می‌شه و در بعضی از شرکت‌های دیگه برون‌سپاری می‌شه. یعنی به شرکت‌هایی که کلاً کارشون رسیدگی به کارهای سرور و مدیریت کردن اونهاست و دیتاسنترهای بزرگی دارن، سپرده می‌شه.هرچقدر بار این کار مهم بیشتر روی دوش خود شرکت باشه، تعداد نیروهای IT بیشتری باید زمان خودشون رو برای کارهای مدیریت سرورشون اختصاص بدن. ولی با برون‌سپاری این بخش و کارهای مربوط به اون، این بار از روی دوش افراد شرکت برداشته می‌شه و در ضمن شرایط نگه‌داری معمولاً مناسب‌تری هم نسبت به یک شرکت برای سرورها فراهم می‌شه.جمع بندیشما تا بحال تجربه مدیریت سرور داشتین؟ با چه مشکلاتی توی این زمینه روبرو شدین؟منبع</description>
                <category>زرتشت سپیدمان</category>
                <author>زرتشت سپیدمان</author>
                <pubDate>Fri, 15 May 2020 14:30:53 +0430</pubDate>
            </item>
                    <item>
                <title>کد نویسی تمیز چیست؟ هر آنچه را که لازم است بدانید</title>
                <link>https://virgool.io/javacup/%DA%A9%D8%AF-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%AA%D9%85%DB%8C%D8%B2-%DA%86%DB%8C%D8%B3%D8%AA-dgsoh3bk7zl7</link>
                <description>اگر اهل برنامه‌نویسی نباشید یا به تازگی قصد ورود به این عرصه را داشته باشید، شاید عنوان این یادداشت برایتان عجیب باشد. چرا کد نویسی تمیز اهمیت دارد؟ مگر در نهایت عملکرد آن مهم نیست؟ چرا چگونگی نوشتن کد، دستخوش نگارش چندین مقاله و کتاب شده است؟در این یادداشت درباره Clean Code و چرایی اهمیت این موضوع در دنیای برنامه‌نویسی توضیحات کوتاهی می‌دهیم. با ما همراه باشید:تعاریف Clean Code و Dirty Codeهمان‌طور که از نام این دو عبارت پیداست، یکی از آن‌ها کدهای تمیز هستند (Clean Code) و از نظر مفهومی در مقابل کدهای کثیف (Dirty Code) قرار می‌گیرند. کد تمیز به کدی گفته می‌شود که کاملاً شفاف و گویا نگاشته شده است و اگر برنامه‌نویس دیگری کد را بخواند، کاملاً متوجه آن می‌شود.در این نوع کد تمامی عملکردها (Functions) و دستورات شفاف هستند، علائم دستوری به شکل منظم در جای خود قرار گرفته‌اند، در برخی از دستورات پیچیده، کامنت‌هایی کاربردی برای شفاف‌سازی وجود دارد و نکاتی دیگری که آن‌ها را در آموزش کد نویسی تمیز معرفی خواهیم کرد.اما در کد نویسی کثیف، حتی اگر کد هم کار کند و خروجی مورد انتظار ما را ارائه دهد، به جز کسی که برنامه را نوشته شخص دیگری از آن سر در نمی‌آورد. در بیشتر پروژه‌های نرم‌افزاری که معمولاً گروهی از برنامه‌نویسان روی یک پروژه کار می‌کنند، این کار یک فاجعه محسوب می‌شود.چرا کد نویسی تمیز اهمیت دارد؟اگر قواعد تمیز کدنوشتن را رعایت نکنید، نه تنها افرادی که بعد از شما روی پروژه کار خواهند کرد و همکارهای فعلی شما برای درک کارتان به مشکل برخواهند خورد، بلکه خودتان هم پس از گذشت مدت کوتاهی، در صورت نیاز به ایجاد تغییرات و رفع مشکل، برای درک کد خودتان با مشکل مواجه می‌شوید.در برخی از مقالات گفته می‌شود که یک برنامه‌نویس 20 تا 30 درصد زمان خود را به خلق کردن کد اختصاص می‌دهد و بیشترین زمان او صرف ایجاد تغییرات در کد به سفارش مشتری، رفع مشکل یا بهینه‌سازی پروژه می‌شود. برای کد نویسی تمیز بیش از هرچیز به تمرین بسیار زیاد و دیسیپلین نیاز دارید. در نظر داشتن موارد زیر نیز می‌توانند برای بهبود کار شما کمک کننده باشند:تا حد امکان ساده بنویسید؛ اگر قرار است کد دستوری شما چند کار را به‌صورت پیچیده انجام دهد، آن را در حد امکان ساده کنید و دستورهای آن را جداسازی کنید.در گذاشتن کامنت افراط و تفریط نکنید؛ برای تمیزنوشتن کد نیازی نیست برای هر دستور یک خط کامنت بنویسید، اصولاً بیشتر کدها باید به‌خودی‌خود گویا باشند و نیازی به توضیح نداشته باشند، اما در جاهای پیچیده‌تر کد حتماً یک کامنت گویا و شفاف درباره عملکرد آن بنویسید.قاعده اجتناب از تکرار یا Don’t Repeat Yourself) DRY)؛ با استفاده از کلاس‌ها و توابعی که قبلاً آن‌ها را تولید کرده‌اید، از دوباره کاری بپرهیزید.بازبینی کدها، بهینه سازی کدها، کاهش حجم توابع و وابستگی‌ها؛ تمامی این موارد تأثیر به‌سزایی روی پیشرفت شما در اصول کد نویسی تمیز دارند.انتخاب اسامی با معنی برای کلاس‌ها و متدها؛ با این روش نه خودتان و نه هم‌تیمی‌هایتان برای درک عملکرد کد، دچار سردرگمی نمی‌شوید.و در نهایت به یاد داشته باشید که در برنامه‌نویسی، از آزمون و خطا نترسید. این تنها راه یادگیری، پیشرفت و بهینه کردن مهارت‌های شما است.شما چطور؟ تمیز کد می‌نویسید؟منبع</description>
                <category>زرتشت سپیدمان</category>
                <author>زرتشت سپیدمان</author>
                <pubDate>Fri, 08 May 2020 14:50:13 +0430</pubDate>
            </item>
                    <item>
                <title>بلاک‌شهر، شهر تاریخی؛ بلاک چین به زبان ساده</title>
                <link>https://virgool.io/@zartosht/%D8%A8%D9%84%D8%A7%DA%A9%D8%B4%D9%87%D8%B1-%D8%B4%D9%87%D8%B1-%D8%AA%D8%A7%D8%B1%DB%8C%D8%AE%DB%8C-%D8%A8%D9%84%D8%A7%DA%A9-%DA%86%DB%8C%D9%86-%D8%A8%D9%87-%D8%B2%D8%A8%D8%A7%D9%86-%D8%B3%D8%A7%D8%AF%D9%87-qxa1zbi9obp6</link>
                <description>تازگی‌ها بلاک چین سر و صدای زیادی به‌پا کرده. بلاک چین چیه؟ بیت کوین همون بلاک چینه؟ این دوتا با هم فرق دارن؟ در این پست می‌خوام همون چیزی که خودم از بلاک چین یاد گرفتم رو به زبون ساده بازگو کنم.برای شرح بهتر پایه‌های بلاک چین من یک شهر رو مثال می‌زنم، یک شهر خیلی قدیمی! قبل از به‌وجود اومدن بانک‌ها! توی این شهر قدیمی مردم برای به‌دست آوردن کالاهی مورد نیازشون برای تضمین معامله و قرض و وام به هم قول می‌دادن. همه چیز خوب پیش می‌رفت تا اینکه قول‌ها شکسته شد و فساد رشد کرد.اما وقتی بانک نبود چطور میشد این مشکلات رو حل کرد؟ یک سیستم غیرمتمرکز (شما بگید بلاک چین) ایجاد کردن!بذارید اسم این شهر رو بذاریم بلاک‌شهرتوی بلاک‌شهر، مردم کالاها رو در قبال کالا از هم می‌گرفتن. شکر در ازای نمک، شیر در ازای مرغ و … .همه‌ی صد خانوار بلاک‌شهر معاملاتشون رو توی دفتر یک معتمد توی شهر ثبت می‌کردن، اسمش آرمان بود.آرمان توی دفترچش رد معاملات رو می‌گرفت. حواسش به قول و قرار ها (دو سر معاملات)‌ بود و در ازای این کارش یک درصدی از جنس معامله شده می‌گرفت.آرمان خیلی شبیه بانک نیست بنظرتون؟ تمام معاملات یک جا ثبت میشن و همون یک جا/نفر مسئول نگه داشتن اطلاعات معاملات بوده!اوضاع یک مدتی خوب پیشرفت و آرمان کم کم دارا شد از درصدی که می‌گرفت و حرص و طمع توی دلش زیاد شد.مردم شهر به آرمان رشوه می‌دادن تا قول‌هایی که دادن رو نادیده بگیره و قرض‌هاشونو حذف کنه! یا بهش باج می‌دادن که معامله‌ها رو تموم شده ثبت کنه حتی اگر هنوز تموم نشده بودن!این اوضاع پیش رفت و خود آرمان هم دیگه نمی‌دونست کدوم معامله واقعی بوده و کدوم نه! دفترش پر از اطلاعات اشتباه بود. دفترش (Ledger) آرمان تبدیل به یک فاجعه شد و اقتصاد شهر در شرف نابودی بود.مردمی که بخاطر رشوه‌های دیگران به آرمان بهشون ظلم شده بود شروع کردن به اعتراض و دیگه به آرمان اعتماد نداشتند. مردم بلاک‌شهر مطمئن شدن که باید یک سیستم جدید رو برای معاملاتشون انتخاب کنن.تولد بلاک چینیکی از اعضای شهر یک پیشنهاد خوب داد، پیشنهاد داد که آرمان رو کنار بذارن و هرکسی خودش جداگونه توی دفتر خودش (Ledger) معاملات خودش رو ثبت کنه.هر هفته، مردم بلاک‌شهر دور هم جمع میشن و معاملاتشون رو با چیزی که تو دفتر بقیه ثبت شده تطبیق می‌دن و تکمیل می‌کنن. و در حقیقت آماری کامل از کل معاملات انجام شده توی دفترشون ثبت می‌شه. (consensus)این ابتکار باعث شد که دیگه نیازی به اعتماد داشتن به آرمان نبود.فرض کنید دو هفته از این اتفاق گذشته و همه‌ی ۱۰۰ خانوار بلاک‌شهر دور هم جمع شدند و دفترهاشونو در اختیار همدیگه قرار دادن.از اونجایی که همه تمام معاملات رو در اختیار دارند، به راحتی قرض‌هایی که پرداخت شدند رو تایید می‌کنند و معاملات رو به‌روزرسانی می‌کنند. و به یک تایید دسته‌جمعی می‌رسند.کسب اعتماد از جمعاگر چند شهروند ناخلف توی شهر وجود داشت چی؟ اگر قصد داشتند که اطلاعات اشتباه توی دفتر (Ledger) هاشون ثبت کنن. وقتی همه شروع به چک کردن دفترهای همدیگه کنن، اون افرادی که اطلاعات اشتباه داشتن مشخص میشن و احتمالا سطح اعتبارشون پیش بقیه کم میشه! دیگه بهشون اعتماد نمیشه!یکی از مزایای این روش این بود که به‌جای اعتماد کردن به یک نفر، باید به حرف جماعت اعتماد کرد و از اونجایی که احتمال اشتباه بودن اکثریت (در این مورد) خیلی کمه، پس معاملات امن‌تر پیش می‌رن.مادامی که این سیستم کار می‌کنه، نگرانی‌ای وجود نداره. اینجاست که مفهوم بلاک چین به‌وجود میاد. بلاک چین بخش کسب اعتماد دسته جمعی رو به صورت اتوماتیک پیش می‌بره و یک محیط بدون نیاز به اعتماد به‌وجود میاره.برای نتیجه‌گیری نهایی، ایده‌ی داشتن پایگاه داده‌ی غیر متمرکز به شکلی که هرکسی Ledger خودش رو داشته باشه و تمام اطلاعات توی اون به صورت اشتراکی ثبت شده باشه، طرز کار بلاک چین در سطح تکنیکال هستش.برای اطلاعات بیشتر می‌تونید به اینجا مراجعه کنین.خیلی سعی کردم این مبحث پیچیده که چند روزی طول کشید تا درکش کنم رو ساده یاد بدم. امیدوارم که موفق بوده باشم. خوش‌حال می‌شم نظرتون رو بدونم. منبع </description>
                <category>زرتشت سپیدمان</category>
                <author>زرتشت سپیدمان</author>
                <pubDate>Thu, 30 Apr 2020 22:32:12 +0430</pubDate>
            </item>
                    <item>
                <title>به‌روزرسانی Ubuntu از 18.04 به 20.04</title>
                <link>https://virgool.io/@zartosht/%D8%A8%D9%87%D8%B1%D9%88%D8%B2%D8%B1%D8%B3%D8%A7%D9%86%DB%8C-ubuntu-%D8%A7%D8%B2-1804-%D8%A8%D9%87-2004-bfqxxdj1fexw</link>
                <description>توی این پست می‌خوام روش آپگرید سیستم ubuntu تون رو از نسخه‌ی 18.04 به 20.04 یاد بدم، در ادامه خلاصه‌ای از کل کارهایی که باید انجام بدین رو می‌نویسم و بعدش به هر هرکدوم رو بررسی می‌کنیم:از کامپیوتر Ubuntu و یا سرور مجازی Ubuntu خودتون بک‌آپ بگیرین.بعد از گرفتن بک‌آپ از سیستمتون (باز هم تاکید می‌کنم!) همه‌ی نرم‌افزارهای موجودتون رو آپدیت کنید. برای این کار دستورهای زیر رو اجرا کنید:sudo apt update -y &amp;&amp; sudo apt dist-upgrade -yبعد از این کار، سیستمتون رو با دستور sudo reboot ریستارت کنین.بعدش ابزار آپدیت Ubuntu رو نصب کنین:sudo apt install update-manager-coreبعد از این دستورها آپگرید رو استارت بزنین:sudo do-release-upgradeبعد از اتمام آپگرید، سیستمتون رو مجدد ریستارت کنین:sudo rebootحالا چک کنین که آپگرید به درستی انجام شده باشه.آپگرید Ubuntu از نسخه‌ی 18.04 به 20.04توجه داشته باشین که برای انجام این آپگرید رو فقط از نسخه‌های 18.04 و یا 19.10 می‌تونید انجام بدین و برای بقیه‌ی نسخه‌ها باید حتما از اول سیستم عامل رو نصب کنین!بک آپ بگیرین!هرچقدر هم تاکید کنم باز هم کافی نیست که گرفتن بک‌آپ از سیستمتون چقدر اهمیت داره!نسخه‌ی لینوکستون رو یجا یادداشت کنین:lsb_release -aخروجی:No LSB modules are available.Distributor ID: UbuntuDescription: Ubuntu 18.04.3 LTSRelease: 18.04Codename: bionicنسخه‌ی کرنلتون رو هم یجا یادداشت کنین:uname -mrsخروجی:Linux 4.15.0-96-generic x86_64به‌روزرسانی تمام پکیج‌های نصب شده بر روی Ubuntu 18.04حالا که حتما بک‌آپ گرفتین از سیستمتون! با استفاده از دستورای زیر سیستمتون رو آپدیت و سپس آپگرید کنین:sudo apt updatesudo apt list –upgradablesudo apt upgrade https://virgool.io/d/bfqxxdj1fexw/%F0%9F%93%B7%D8%A8%D9%87%E2%80%8C%D8%B1%D9%88%D8%B2%D8%B1%D8%B3%D8%A7%D9%86%DB%8C%D8%B3%DB%8C%D8%B3%D8%AA%D9%85 بعد از آپگرید پکیج‌های نصب شده روی Ubuntu 18.04 سیستمتون را با دستور زیر ریستارت کنین:sudo rebootبرای اطلاعات بیشتر به «Ubuntu 18.04 update installed packages for security مراجعه کنین.تمام پکیج‌های بلااستفادتون رو با دستور زیر پاک کنین:sudo apt –purge autoremoveخروجی:Reading package lists… DoneBuilding dependency treeReading state information… DoneThe following packages will be REMOVED:linux-headers-4.15.0-45* linux-headers-4.15.0-45-generic*linux-image-4.15.0-45-generic* linux-modules-4.15.0-45-generic*linux-modules-extra-4.15.0-45-generic*0 upgraded, 0 newly installed, 5 to remove and 0 not upgraded.After this operation, 334 MB disk space will be freed.Do you want to continue? [Y/n] y(Reading database … 138353 files and directories currently installed.)Removing linux-headers-4.15.0-45-generic (4.15.0-45.48) …Removing linux-headers-4.15.0-45 (4.15.0-45.48) …Removing linux-modules-extra-4.15.0-45-generic (4.15.0-45.48) …Removing linux-image-4.15.0-45-generic (4.15.0-45.48) …مطمئن باشین که پکیج update-manager-core روی سیستمتون نصب هستش:sudo apt install update-manager-coreبه‌روزرسانی Ubuntu به آخرین نسخه‌ی LTSبرای این کار دستور زیر رو اجرا کنین:sudo do-release-upgradeاحتمال زیاد با پیغام زیر مواجه می‌شین:Checking for a new Ubuntu releaseThere is no development version of an LTS available.To upgrade to the latest non-LTS develoment releaseset Prompt=normal in /etc/update-manager/release-upgrades.در این صورت همون دستور را با فلگ -d اجرا کنین که مجبور بشه نسخه‌ی جدید رو پیدا کنه:sudo do-release-upgrade -dخروجی:Reading cacheChecking package managerContinue running under SSH?This session appears to be running under ssh. It is not recommendedto perform a upgrade over ssh currently because in case of failure itis harder to recover.If you continue, an additional ssh daemon will be started at port‘1022’.Do you want to continue?Continue [yN] yStarting additional sshdTo make recovery in case of failure easier, an additional sshd willbe started on port ‘1022’. If anything goes wrong with the runningssh you can still connect to the additional one.If you run a firewall, you may need to temporarily open this port. Asthis is potentially dangerous it’s not done automatically. You canopen the port with e.g.:‘iptables -I INPUT -p tcp –dport 1022 -j ACCEPT’To continue please press [ENTER]No valid mirror found warning:Updating repository informationWhile scanning your repository information no mirror entry for theupgrade was found. This can happen if you run an internal mirror orif the mirror information is out of date.Do you want to rewrite your ‘sources.list’ file anyway? If you choose‘Yes’ here it will update all ‘bionic’ to ‘focal’ entries.If you select ‘No’ the upgrade will cancel.Continue [yN]همه سوالاتشون با Y جواب بدین!ریستارت سیستموقتی سیستم ازتون خواست،‌ریستارتش کنین: ?ریبوتسیستم تبریک می‌گم، آپگرید شما از نسخه‌ی 18.04 به 20.04 تموم شده و می‌تونید سیستم رو ریستارت کنین.دوباره نسخه‌ی سیستمتون رو چک کنین:lsb_release -aخروجی:No LSB modules are available.Distributor ID: UbuntuDescription: Ubuntu 20.04 LTSRelease: 20.04Codename: focalنسخه‌ی کرنل و لاگ فایلتون رو هم با دستورای زیر چک کنین:tail -f /var/log/my-app.loguname -mrsخروجی:Linux 5.4.0-24-generic x86_64ریپوزیتوریای شخص ثالث رو فعال کنیندر حین انجام عملیات آپگرید، تمام ریپوزیتوری‌های شخص ثالث برای جلوگیری از شکست عملیات غیرفعال میشن. برای مثال، گوگل کروم و بقیه‌ی نرم‌افزاراتون غیرفعال شدن و ما باید با استفاده از CLI و یا GUI که به اسم Software and Updates شناخته میشه فعال کنین. از فرمان cd به شکل زیر استفاده کنین:cd /etc/apt/sources.list.d/ریپوزیتوری‌هارو لیست کنین:ls -lبرای مثال لیست گوگل رو با دستور زیر ببینید:cat google-chrome.listخروجی:### THIS FILE IS AUTOMATICALLY CONFIGURED #### You may comment out this entry, but any other modifications may be lost.# deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main # disabled on upgrade to focalEdit the file:sudo nano google-chrome.list## OR ##sudo vim google-chrome.listحالا این فایل رو با برداشتن # از بعضی خطوط آپدیت کنین که به شکل زیر در بیاد:### THIS FILE IS AUTOMATICALLY CONFIGURED #### You may comment out this entry, but any other modifications may be lost.deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main # disabled on upgrade to focalفایل رو ذخیره کنین و ببندینش و در نهایت مجدد نرم‌افزارهاتون رو به‌روزرسانی و آپگرید کنین:sudo apt updatesudo apt upgradeجمع‌بندیخب موفق شدین! شما سیستم‌عاملتون رو (امیدوارم) با موفقیت به Ubuntu 20.04 LTS آپگرید کردین. حالا چک کنین که کدوم نرم‌افزارها به درستی کار می‌کنن.صلب مسئولیتاین آموزش برای حرفه‌ای‌ها طراحی شده و فقط اگر می‌دونید دارین چیکار می‌کنید ازش استفاده کنین! فقط دستورهارو از اینجا کپی و به ترمینالتون پیست نکنین لطفا!خوش‌حال میشم نظرتون رو بدونم ?منبع</description>
                <category>زرتشت سپیدمان</category>
                <author>زرتشت سپیدمان</author>
                <pubDate>Sat, 25 Apr 2020 23:18:57 +0430</pubDate>
            </item>
            </channel>
</rss>