<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" href="https://mehdix.ir/feed.xsl" ?>

<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fa">
  <link rel="alternate" type="text/html" href="https://mehdix.ir" hreflang="fa" />
  <link rel="self" type="application/atom+xml" href="https://mehdix.ir/feed.xml" />

  <id>https://mehdix.ir/</id>
  <title type="text" xml:lang="fa">مهدی صادقی</title>
  <subtitle>خلاصه‌ی مقالات</subtitle>
  <generator>فید حاوی متن کامل مقالات است.</generator>
  <updated>2026-01-06T16:38:06Z</updated>
  <rights>Commons Attribution 4.0 International</rights>

  
  <author>
    <name>مهدی صادقی</name>
    <email>mehdi@mehdix.ir</email>
    <uri>https://mehdix.ir</uri>
  </author>
  


<entry>
    
    <id>urn:uuid:0f7dd450-d612-4a44-b489-3d018a157e2b</id>
    
    <title>آفتابه لگن هفت دست</title>
    <updated>2026-01-06T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/overhaul.html"/>
    <category term="وب"/><category term="جکیل"/><category term="بیهنه‌سازی"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>در تعطیلات سال نو فرصتی و همتی فراهم شد که نگاه دوباره‌ای به سایت‌ساز وبسایتم داشته باشم. تغییرات گسترده‌ای ایجاد کردم که در ادامه شرح می‌دهم.</p>

<p>قصدم در ابتدا نوشتن مقاله‌ای درباره‌ی یک پروژه‌ی کوچک چندین ساله بود و قصد داشتم از نوشتن مقاله‌ی دیگری در مورد وبسایت پرهیز کنم. ولی چند سال کم‌کاری باعث شده بود که تا حدود زیادی فراموش کنم که اصلا چطور سایتم را می‌سازم و اجزاء آن چگونه کار می‌کنند. وقتی دقیق‌تر به سورس نگاه کردم به عمق فاجعه پی بردم. بنابراین چاره‌ای جز پنج روز کار بی‌وقفه روی وبسایت باقی نمانده بود.</p>

<p>خاطرتان باشد در گذشته مقاله‌ای نوشته بودم بنام <a href="upcoming-changes.html">گزارش تغییرات اساسی در پیش رو</a>. به جرأت می‌توانم بگویم مهمترین یادداشتی است که در این وبسایت منتشر کرده‌ام و از اسفند ۹۹ سرلوحه‌ی کارم بوده است. وقتی با آن نگاه و البته تجربه‌ی سالهای گذشته به نحوه‌ی ساخت این سایت تقریبا<sup id="fnref:۱"><a href="#fn:۱" class="footnote" rel="footnote" role="doc-noteref">۱</a></sup> استاتیک نگاه کردم مشکلات زیر نظرم را جلب کرد:</p>

<ul>
  <li>تعداد زیادی افزونه‌ی ریز و درشت</li>
  <li>تعداد زیادی فایل با روابط فی‌مابین پنهان از دید برنامه‌ساز</li>
  <li>تعداد زیادی فایل SASS برای قالب‌ها به شکلی در هم ریخته</li>
  <li>عدم امکان دیباگ فرم کامنت‌دونی (سرور وب داخلی جکیل فقط فایل سرو می‌کند)</li>
  <li>مارک‌آپ تکراری (یکپارچکی را از میان می‌برد چرا که صفحات شبیه هستند اما نه کاملا)</li>
  <li>مخلوط پایتون و روبی</li>
  <li>عدم استفاده از متغیرهای  CSS (زمانی که وبسایت را ساختم هنوز وجود نداشتند)</li>
  <li>نداشتن قالب متغیر تیره و روشن (شب‌ها قالب تیره برای مطالعه برای چشم‌هایم راحت‌تر است)</li>
  <li>کدهای مرده</li>
  <li>برچسب‌های فراوان و همچنین ترکیب برچسب و سرفصل با نام یکسان</li>
</ul>

<p>و نکات ریز و درشت دیگری مانند اینها. به طور کلی پیچیدگی بالا بود و خوانایی پایین. آن هم برای تبدیل یک مشت فایل مارک‌داون به صفحات وب.</p>

<p>لازم است توضیح بدهم که قوانین متعدد CSS و تکثر فایل‌های بکاررفته در قالب‌بندی و همچنین تکثر زبان‌های برنامه‌نویسی (روبی و پایتون) و نبود دسترسی مستقیم به افزونه‌ها، که هر تغییر را منوط به تغییر یک پروژه‌های خارجی می‌کند، از مهمترین مشکلات بودند چرا که فهم آنچه در پروژه می‌گذرد را سخت می‌کردند. مثلا من افزونه‌ای نوشته بودم به نام jekyll-hinduarabic و برای آن هم مخزن جداگانه‌ای ساخته بودم و آن را رویRubyGems منتشر کرده بودم. تنها کاری که می‌کرد تبدیل اعداد لاتین به اعداد فارسی بود. آن همه قیل و قال برای هیچ. آن را آوردم داخل پروژه و تبدیل کردمش به یک پلاگین ساده‌ی روبی که با یک کلیک در دسترس است و امکان تغییرش وجود دارد. آن مخزن را هم آرشیو کردم.</p>

<p>بعد همینکار را با افزونه‌ی سایت‌مپ کردم. این افزونه اصلا به روبی احتیاج نداشت. تبدیل شد به یک فایل ساده‌ی sitemap.xml با مقداری کد قالب Liquid و افزونه حذف شد.</p>

<p>بعد رفتم سروقت تقویم جلالی و افزونه‌ی جکیلی که برای آن نوشته بودم. الگوریتم تبدیل تاریخ میلادی به شمسی را به کمک هوش مصنوعی نوشتم و مطالعه و کد تولیدی را اصلاح کردم و به افزونه‌های روبی اضافه کردم. افزونه‌ی تبدیل اعداد و فیلترهای قالب را هم درونش ادغام کردم. فورا هم با خطی یا به اصطلاح اینلاین شدن این افزونه‌ی خارجی تغییراتی برای رفع نیاز وبسایتم در آن انجام دادم. مثلا یک فیلتر اضافه کردم که خروجی‌اش مقداری کد HTML است که به تاریخ جلالی تولیدی به کمک المان‌های وب ساختار می‌دهد (به کمک time و همچنین روز و ماه و سال را جدا می‌کند که بتوان استیلش را تغییر داد) و همچنین تاریخ میلادی را در عنوان اضافه می‌کند (اگر با ماوس روی تاریخ‌ها بروید تاریخ میلادی نمایش داده می‌شود - یک هک کوچک سودمند).</p>

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

<p>در ادامه حذفیات افزونه‌های پیچیده‌ای که شخص شخیص خودم فورک و هک و منتشر کرده بود را نیز به دیار باقی فرستادم. از جمله افزونه‌هایی برای تولید برچسب‌ها و صفحات مشابه هر پست. تولید برچسب‌ها و صفحات مشابه هم به افزونه‌های روبی تبدیل شدند که به من اختیار کامل تغییر فوری آنها را می‌دهند. مثلا تولید برچسب‌ها را به گونه‌ای تغییر دادم که سرفصل‌ها را هم در نبود برچسب‌های مشابه در نظر بگیرد. آن هم بدون اینکه در پروژه‌های ثانویه درگیر بشوم برای چیزی که واقعا ارزش مشارکت ندارد. در مقابل تصور کنید اگر مشکل سخت و پیچیده‌ی راست‌به‌چپ‌نویسی در ترمینال حل بشود تمام سیستم‌های عامل شبیه یونیکس از آن بهره‌مند خواهد شد پس چنین چیزی ارزش مشارکت دارد. اما پروژه‌ی شخصی مثلا چون منی که اصلا وقت رسیدگی به آن را ندارم و اصلا چیز مهمی هم نیست و جای خاصی به کار نرفته ارزش مشارکت ندارد. کد را کپی کنید و تغییرات دلخواهتان را ایجاد کنید و والسلام.</p>

<p>در ادامه افزونه‌های جدیدی هم اضافه کردم. یکی برای ممانعت از استفاده‌ی یک برچسب به عنوان سرفصل (کتگوری). دیگری برای فرمت خروجی وب پیش از انتشار (چون سورس صفحات تولیدی را مینیمایز نمی‌کنم و در مرورگر می‌خوانم که پیش از این شلخته بود و تلاش برای اصلاح سورس پرهزینه و کم‌فایده بود و به نتیجه نرسید).</p>

<p>علاوه بر اینها در گذشته به کمک پایتون نظرات را از بک‌آپ دیسکاس ایمپورت کرده بودم که دیگر نیازی به آن نداشتم و آن را هم خذف کردم (که البته همچنان در حافظه‌ی گیت باقی است). کدهایی هم برای ارسال ایمیل به کمک سرویس لامبدای آمازون نوشته بودم که حذف کردم در حالی که در ذهنم تکرار می‌کردم: آفتابه لگن هفت دست، از شام و ناهار هیچی…</p>

<p>افزونه‌ی دیگری بود برای تولید جدول مطالب که فقط یکجا استفاده کردم که آنرا هم به کمک هوش مصنوعی کلاود آوردم داخل پروژه و تغییر دادم تا عناوین داخلی هر پست را هم به لینک‌های داخلی تبدیل کند (تا بشود بدون سرفصل مطالب هم به یک زیرعنوان مسقیما لینک داد).</p>

<p>یک افزونه‌ی دیگر هم برای سئو بود که داخل هدرهای سایت مرج کردم و او هم به ابدیت ملحق شد. یکی دیگر هم برای ساخت لینک صفحات قبلی و بعدی بود که در گذشته مثل جگر زلیخا مقداری‌اش داخل پلاگین بود و مقداری هم پراکنده داخل سایت (بسیاری افزونه‌ها مقداری هم کد Liquid لازم دارند چون فقط داده را فراهم می‌کنند و مانند اینها). آن را هم به کمک هوش مصنوعی دوباره نوشتم و اصلاح کردم تا فقط نیازهای سایت را برآورده کند.</p>

<p>قالب اصلی به نام لیست را هم طوری تغییر داده‌ام که گروه‌بندی بر اساس تاریخ و برچسب و مانند اینها را قبول می‌کند و فعال کردن لینک به صفحات قبلی و بعدی هم فقط یک فلگ است و به این ترتیب چندین فایل یکی شدند. به انتهای پست‌ها هم لینک قبلی و بعدی استفاده کردم که کلید میان‌بری نیز دارد. به لاتین j و k و به فارسی ت و ن همین‌کار را می‌کنند. امتحانش خالی از لطف نخواهد بود.</p>

<p>حالا که دستم گرم شده بود یک پلاگین دیگر هم ایجاد کردم که اجازه بدهد فرم کامنت‌دونی را روی سرور داخلی جکیل ثبت کنم. کاری که می‌کند اینست که اجازه می‌دهد به صورت لوکال نظر ثبت کنم و ایمیل‌های ارسالی را هم با پرینت داخل ترمینال شبیه‌سازی می‌کند. در گذشته فقط روی سرورم امکان تست داشتم.</p>

<p>تمام این پلاگین‌ها حذف یا جذب شدند:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">group</span> <span class="ss">:jekyll_plugins</span> <span class="k">do</span>
  <span class="n">gem</span> <span class="s2">"jekyll-paginate"</span>
  <span class="n">gem</span> <span class="s2">"jekyll-sitemap"</span>
  <span class="n">gem</span> <span class="s2">"jekyll-jalali"</span>
  <span class="n">gem</span> <span class="s2">"jekyll-hinduarabic"</span>
  <span class="n">gem</span> <span class="s2">"jekyll-tagging-lite"</span>
  <span class="n">gem</span> <span class="s2">"jekyll-tagging-related_posts"</span><span class="p">,</span> <span class="ss">:git</span> <span class="o">=&gt;</span> <span class="s2">"https://github.com/mehdisadeghi/jekyll-tagging-related_posts"</span><span class="p">,</span> <span class="ss">:ref</span> <span class="o">=&gt;</span> <span class="s2">"a58844c"</span>
  <span class="n">gem</span> <span class="s2">"liquid_reading_time"</span>
  <span class="n">gem</span> <span class="s2">"jekyll-seo-tag"</span>
  <span class="n">gem</span> <span class="s2">"jekyll-include-cache"</span>
  <span class="n">gem</span> <span class="s2">"jekyll-toc"</span>
<span class="k">end</span>
</code></pre></div></div>

<p>تعداد فایل‌هایی که برای قالب‌های ریز و درشت و استیل‌های وب استفاده کرده بودم هم از دستم دررفته بود. به شدت تعداشان را کاهش داده‌ام. این کار خوانایی را بالا می‌برد. این وبسایت و بیشتر سایت‌های مشابه شخصی هستند. معیارهایی که توسط شرکت‌های بزرگ تعریف می‌شود بدرد اینجا نمی‌خورد و پیروی از آنها اتلاف وقت گرانبهای برنامه‌ساز است. اگر به این نکته دقت نکنید مدل‌های هوش مصنوعی بسیاری از الگویهای شرکت‌های بزرگ را دنبال خواهند کرد.  برای مثلا سعی خواهند کرد برنامه حتما «امن» باشد. یعنی همه‌ی خطاها را کنترل بکند یا قابل توسعه باشد یا سطوح مختلف انتزاعی داشته باشد و مانند اینها. برای بیشتر پروژه‌های من حتی برای کار اینها سم هستند. بویژه کنترل خطا. برنامه‌ای که انتظاراتش برآورده نشده است باید فورا منفجر بشود بجای اینکه سعی کند خطاها را کنترل و به نوعی پنهان بکند. به عنوان یک اصل کلی خطاها باید همواره در مبدا اصلاح بشوند.</p>

<p>مقایسه‌ی تعداد فایل‌های CSS قدیم و جدید:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">ls </span>src/_sass/ old/src/_sass/
../mdx/src/_sass/:
_base.scss	_fonts.scss   _print.scss     _vars.scss
_comments.scss	_layout.scss  _pygments.scss
_dark.scss	_post.scss    _tagcloud.scss

src/_sass/:
base.scss  layout.scss	pygments.scss
</code></pre></div></div>

<p>مقایسه‌ی تعداد فایل‌های قالب قدیم و جدید:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">ls </span>src/_layouts/ old/src/_layouts/
old/src/_layouts/:
bare.html	     feed_per_post.xml	message.html  post.html
category_index.html  headless.html	minimal.html  project.html
default.html	     home.html		page.html     tag_page.html

src/_layouts/:
atom.liquid  comments_feed.liquid  post.liquid	   tag.liquid
base.liquid  list.liquid	   project.liquid
</code></pre></div></div>

<p>تغییری که مدتها بود دوست داشتم انجام بدهم استفاده از متغیرهای CSS بود. رنگ‌ها را هم تغییر دادم. الگوی فعلی تک‌رنگی است. یک رنگ اصلی وجود دارد که روی چرخ رنگ‌ها به روش HSL تعریف شده است. در این روش رنگ‌ها به کمک سه تا چهار عدد تعریف می‌شوند. یکی شماره‌ی رنگ روی چرخ رنگ‌هاست و دیگر شدت آن و بعدی هم شدت نور. یک فاکتور انتخابی چهارم هم ترنسپرنسی است که نمی‌دانم به فارسی چه می‌شود. یعنی تا چه حد می‌شود آن سوی آن را دید.</p>

<p>این روش باعث شد که تعریف رنگ‌ها ساده‌تر بشود. تمام رنگ‌های دیگر را به کمک متغیرها و امکانات امروزی وب بر اساس این رنگ مبداء تعریف کرده‌ام. هیچ رنگی جز یک رنگ در سایت تعریف نشده است. حسن اینکار اینست که براحتی می‌توان رنگ‌ها را تغییر داد حتی هنگامی که سایت ساخته شده است. برای اینکار یک هک کوچک در سایت قرار داده‌ام. کافیست کلید بک‌تیک را فشار بدهید (‍`). باید یک نوار افقی بالای پست‌ها ظاهر شود که اجازه می‌دهد این رنگ اصلی را تغییر بدهید و مشاهده کنید چطور تمام رنگ‌ها نسبت به آن تغییر می‌کنند.</p>

<p>رنگ‌های به کار رفته در کدها را هم تغییر دادم تا بجای پروژه‌ی پایتونی که به کار گرفته بودم اینبار از معادل روبی استفاده کنند و نیز چیز انتخاب کردم که مستقل از تیره و روشن بودن قالب خوانا باشد.</p>

<p>قالب تیره هم به وبسایت اضافه کرده‌ام. به شکل خودکار رنگ سیستم‌عامل را انتخاب خواهد کرد. در غیر اینصورت کلیدی روی صفحه‌ی اصلی تعبیه کرده‌ام که متغییرها را تغییر می‌دهد و قالب را تیره می‌کند. روی صفحات مقالات اگر روی عنوان کلیک کنید همین اتفاق می‌افتد. تا زمان بستن پنجره انتخاب کاربر ذخیره می‌شود. دفعه‌ی بعدی باز هم انتخاب سیستم‌عامل ارجحیت خواهد داشت.</p>

<p>بخشی از اسریپت‌های پراکنده را هم به Rakefile پروژه منتقل کردم که معادل Makefile است منتها برای پروژه‌های روبی. ابتدا قصدم حذف کامل Makefile بود ولی متاسفانه به جهت کم‌سوادی محقق نشد حالا هر دو را داریم! دستوراتی هم اضافه کردم که ساخت مقاله‌ی جدید یا مقاله‌ی ناتمام را ساده کنند.</p>

<p>تغییرات ریز و درشت بسیاری نیز داده‌ام که در کامیت‌های گیت شرح داده‌ام. باقی هم در کد هست. نتیجه این شد که وبسایت دیگر هیچ افزونه‌ی خارجی جکیل ندارد. بیلد کمی کند شده است که بعدا بهبود می‌دهم (بیشتر به خاطر فرمت خروجی). بسیار راضی هستم. تعداد فایل‌ها کاهش جدی و خوانایی پروژه افزاش جدی پیدا کرد. از سوی دیگر اگر کسی دیگری بخواهد از این سایت استفاده کند تمام آن چیزی که به آن نیاز است داخل مخزن همین پروژه است و هیچ نیازی نیست پایش را از آن بیرون بگذارد.</p>

<p>در نهایت هم به این نتیجه رسیدم که به جای این همه هک و افزونه به راه حل بهتری نیاز است…</p>

<p>امیدوارم که این قصه‌ی ساده‌سازی تشویقت کند پروژه‌هایت را ساده کنی.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:۱">
      <p>ثبت دیدگاه به یک سرور احتیاج دارد. <a href="#fnref:۱" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
</div>]]>
    </content>
    <summary>در تعطیلات سال نو فرصتی و همتی فراهم شد که نگاه دوباره‌ای به سایت‌ساز وبسایتم داشته باشم. تغییرات گسترده‌ای ایجاد کردم که در ادامه شرح می‌دهم. قصدم در ابتدا نوشتن مقاله‌ای درباره‌ی یک پروژه‌ی کوچک چندین ساله بود و قصد داشتم از نوشتن مقاله‌ی دیگری در مورد وبسایت پرهیز کنم. ولی چند سال کم‌کاری باعث شده بود که تا حدود زیادی فراموش کنم که اصلا چطور سایتم را می‌سازم و اجزاء آن چگونه کار می‌کنند. وقتی دقیق‌تر به سورس نگاه کردم به عمق فاجعه پی بردم. بنابراین چاره‌ای جز پنج روز کار بی‌وقفه روی وبسایت باقی نمانده بود. خاطرتان باشد...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:c5f087cd-211f-4fef-86f9-407d2531c4f6</id>
    
    <title>قصه‌ی یک هک</title>
    <updated>2025-12-31T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/hackstory.html"/>
    <category term="هک"/><category term="کودکی"/><category term="جرثقیل"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>سالها پیش در کودکی در مدرسه‌ی شهید قدس میرحیدری در محله‌ی امیرآباد تهران در مقطع راهنمایی تحصیل می‌کردم. معلمی از ما خواست که یک کاردستی درست کنیم. من هم یک جرثقیل درست کردم که قصه‌اش را برای شما تعریف می‌کنم.</p>

<p>حوالی سال ۱۳۷۲ هجری شمسی تهران. فکر می‌کنم درسی داشتیم بنام پرورشی در دوران راهنمایی. من هم شاید اول راهنمایی بودم. معلم جوان بیست و چند ساله‌ای هم داشتیم که خیلی آدم دوست داشتنی‌ای بود. متاسفانه اسمش خاطرم نیست. از هر کدام از ما خواست که یک کاردستی درست کنیم. من هم نمی‌دانم از کجا به فکرم رسید که یک جرثقیل کوچک بسازم که حرکت کند و اهرمی هم بالایش داشته باشد برای برداشتن اجسام که آن هم حرکت بکند.</p>

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

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

<p>نمی‌دانم ایده‌ی جرثقیل از کجا به ذهنم رسیده بود ولی فکر می‌کنم شاید دیدن پروژه‌های جاده‌سازی بسیار در اطراف منزلمان در آن بی‌تاثیر نبوده باشد. ایده‌ی بلندپروازانه‌ی من شامل یک جرثقیل متحرک می‌شد که همزمان که خودش به جلو پیش می‌رفت یک بازوی متحرک هم روی آن به بالا و پایین حرکت می‌کرد. الان که به آن فکر می‌کنم بیشتر شبیه ماشین‌های آتش‌نشانی با نردبان متحرک می‌آید. به هر حال پس از برخواستن از پشت میز طراحی فهمیدم که قطعات لازم برای ساخت را ندارم و البته که اصلا به خرید فکر نکردم که چیزی دور از ذهن بود.  پیدا کردن بدنه‌ی جرثقیل البته کار سختی نبود. یک کامیون پلاستیکی بزرگ بدون موتور در منزل پیدا کردم که کافی بود. اما پیدا کردن موتور کمی کار داشت.</p>

<p>خانواده‌ی ما پرتعداد بود و برخی از بچه‌های یاغی خانواده شاید به جهت شرایط رؤیایی زندگی ما علاقه‌ی شدیدی به خرد کردن اسباب‌بازی‌ها داشتند. برخی اسباب‌بازی‌ها درونشان قطعات بدردبخوری داشتند از جمله موتور متحرک که از دید من پنهان نمانده بود. با اینکه از این اسباب‌بازی‌ها جز لاشه‌ای باقی نمانده بود اما همچنان متعلق به آنها بود و امکان نداشت جنازه‌اش را هم به من بدهند. یکی از آنها یک ماشین ساده بود اما تعداد قابل توجهی چرخ‌دنده داخلی داشت و چرخ‌هایش با سرعت پایین ولی قدرت بالا حرکت می‌کردند که گزینه‌ی خوبی برای موتور جرثقیل به نظر می‌رسید. موتور را از این ماشین شکسته استخراج کردم و با چرخ‌هایش به زیر کامیون بزرگ پلاستیکی چسباندم. فکر می‌کنم چرخ‌های کامیون بزرگ را درآوردم تا جا برای موتور باز بشود.</p>

<p>برای جرثیقیل متحرک یک هواپیمای شکسته پیدا کردم. آن زمان خیلی رایج بود. زیر بالهایش چرخ داشت و یک چرخ هم در نوک هواپیما داشت. چرخ جلو حین حرکت هواپیما بالا و پایین می‌رفت تا فرود و صعود را شبیه‌سازی کند. موتور بازوی جرثیل پیدا شده بود!</p>

<p>پنهانی موتور را از هواپیما درآوردم و بعد آن را برعکس به پشت جرثقیلم چسباندم. یک خط‌کش پلاستکی هم کار نردبان یا بازودی جرثقیل را انجام داد که آن را به بازوی متحرک موتور هواپیما چسباندم. فکر می‌کنم یک اتاقک یا یک قلاب هم به نوک خط‌کش چسباندم. این را خاطرم نمانده است.</p>

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

<p>چندی پیش (هشت سال!) که این ماجرا را مثل ده‌ها و صدها ماجرای کودکی‌ام مرور می‌کردم به نظرم رسید که این اولین هک زندگی‌ام بوده است. ساخت یک وسیله برای رسیدن یک مقصود خاص از چیزهای نسبتا بی‌ربط که اگر خلاقانه به آنها بنگری به کارت می‌آیند.</p>

<p>امیدوارم خواندن این داستان باعث به خاطر آوردن هک‌های کودکی‌ات بشود.</p>

<p>پی‌نوشت: طی خانه‌تکانی وبساتم نسخه‌ی ناتمام این یادداشت را از آذر ۹۵ پیدا کردم و ادامه‌اش را نوشتم و امروز منتشر کردم. سه پاراگراف اول هشت سال پیش نوشته شده‌اند. شاید مقایسه‌شان با باقی متن خالی از لطف نباشد.</p>

</div>]]>
    </content>
    <summary>سالها پیش در کودکی در مدرسه‌ی شهید قدس میرحیدری در محله‌ی امیرآباد تهران در مقطع راهنمایی تحصیل می‌کردم. معلمی از ما خواست که یک کاردستی درست کنیم. من هم یک جرثقیل درست کردم که قصه‌اش را برای شما تعریف می‌کنم. حوالی سال ۱۳۷۲ هجری شمسی تهران. فکر می‌کنم درسی داشتیم بنام پرورشی در دوران راهنمایی. من هم شاید اول راهنمایی بودم. معلم جوان بیست و چند ساله‌ای هم داشتیم که خیلی آدم دوست داشتنی‌ای بود. متاسفانه اسمش خاطرم نیست. از هر کدام از ما خواست که یک کاردستی درست کنیم. من هم نمی‌دانم از کجا به فکرم رسید که یک...</summary>
  </entry>

<entry>
    
    <id>https://mehdix.ir/42.html</id>
    
    <title>۴۲</title>
    <updated>2024-11-11T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/42.html"/>
    <category term="آشپزی"/><category term="زندگی"/><category term="دو"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>امروز چهل و دومین سالروز تولد من بود.به مناسبت روز تولدم با اینکه باران می‌بارید سه کیلومتر دویدم. دویدن مثل شنا کردن بر خلاف جریان رودخانه است. باور دارم هر حرکتی که با سکون مبارزه کند سند زنده بودن ماست. یادآوری اینکه مبارزه با نیستی، خود هستی ماست! از طرفی هیچ کس هم تا بحال از دویدن پشیمان نشده است. شاید پیش از خروج از منزل به قصد دویدن، هزار دلیل برای انصراف از این کار وجود داشته باشد، اما پس از آن فقط خوشحالی و رضایت است. فرصتی است برای ایجاد یک پیروزی شخصی کوچک در زندگی.</p>

<p>پس از این موفقیت کوچک برای امشب خودم هوموس لذیذی مهیا کردم (برای بار نخست با اندازه‌گیری چشمی!) و برنامه‌ی مختصری برای تماشای یکی دو قسمت دیگر از سریال Star Trek TNG آماده کردم که به محض انتشار این مطلب به سراغش خواهم رفت. قصدم از انتشار این یادداشت یادآوری قدردانی بابت خوشی‌های کوچک زندگی است و اینکه این ما هستیم که تعریف می‌کنیم یک روز خوب چه جور روزی است و اینکه امروز برای من روز خوبی است هرچند اینجا پشه هم پر نمی‌زند :)</p>

<p>اگر دستور پخت هوموس را هم خواستید بدانید در خدمتم!</p>

<p>زنده باشید.</p>

<p>پی‌نوشت:
امروز صبح هم، در کنار پیام‌های خانوادگی،  دوستی عزیز از یزد به روزم با پیام تبریک سرشار از محبتش رنگ و بویی دیگر داد. در پیامش اشاره کرده بود که ما گاهی خوبی‌های کوچکی در حق یکدیگر می‌کنیم که شاید خودمان به اهمیت آن پی نبریم اما برای دیگری به یادماندنی و با ارزش باشد. قدرشناس این دوستی هستم.</p>
</div>]]>
    </content>
    <summary>امروز چهل و دومین سالروز تولد من بود.به مناسبت روز تولدم با اینکه باران می‌بارید سه کیلومتر دویدم. دویدن مثل شنا کردن بر خلاف جریان رودخانه است. باور دارم هر حرکتی که با سکون مبارزه کند سند زنده بودن ماست. یادآوری اینکه مبارزه با نیستی، خود هستی ماست! از طرفی هیچ کس هم تا بحال از دویدن پشیمان نشده است. شاید پیش از خروج از منزل به قصد دویدن، هزار دلیل برای انصراف از این کار وجود داشته باشد، اما پس از آن فقط خوشحالی و رضایت است. فرصتی است برای ایجاد یک پیروزی شخصی کوچک در زندگی. پس از...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:43d53a11-8aba-4f1f-b1d4-bdde7fcd1ffa</id>
    
    <title>بازیابی متادیتای کلی عکس</title>
    <updated>2024-03-01T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/filefix.html"/>
    <category term="لینوکس"/><category term="فایل‌سیستم"/><category term="exif"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>مشکلی با عکس‌های آرشیوی‌ام پیش آمده که بد نیست بنویسم برای خود آینده‌ام و رهگذران عزیز.</p>

<p>من عکس‌هایی که با گوشی‌های مختلف گرفته‌ام را به کمک Syncthing با کامپیوترم سینک می‌کنم. در حال حاضر یکسالی می‌شود که روی یک Rock64 فسقلی Libreelec ریخته‌ام و یک هارد پنج‌ترابایتی هم برای سینک به درگاه USB 3 آن متصل کرده‌ام (که ممکن است دیر یا زود به خاطر روشن و خاموش شدن متعدد عمرش را بدهد به شما). سینک‌تینگ روی راک است و فایل‌ها سنک می‌شود روی آن هارددیسک.
حالا مشکلی که پیش امده این است که من گوشی جدیدی خریده‌ام و تمام فایل‌ها را روی آن به شکل ترکیبی! (دستی و سینک‌تینگ) کپی کردم. حالا تاریخ آخرین تغییر فایل‌ها به هم ریخته است و وقتی در برنامه‌ی گالری گوشی عکس‌ها را باز می‌کنم تاریخ‌ها اشتباه است. این تغییر نه تنها باعث می‌شود که سورت کردن تصاویر براحتی امکانپذیر نباشد بلکه برنامه‌هایی که از روی عکس‌ها کلیپ‌های کوچک می‌سازند به اشتباه می‌افتند. تصور بکنید در حال تماشای عکس‌های سال‌های گذشته هستیم و به کمک توالی تاریخ عکس‌ها در حال بازسازی گذر ایام در ذهنمان که به یکباره عکسی نامربوط ظاهر می‌شود که دلپذیر نیست.</p>

<p>خلاصه برای حل این مشکل طبق معمول با یک مقدمه دست به دامن خط فرمان می‌شویم.</p>

<p>خبر خوش اینکه در نام همه‌ی عکس‌ها روز عکاسی در فرمت ساده‌ی ISO8601 آمده است. یعنی از چپ به راست اولی تاریخ چهار رقمی و بعد ماه دو رقمی و بعد روز دو رقمی (حالا دیگری هم دارد که از بحث ما خارج است). در برخی فایل‌ها اولی چیز ثابتی آمده و بعد تاریخ که مشکلی نیست. از این گذشته عکس‌ها حاوی اطلاعات Exif هستند که تاریخ اصلی عکاسی در آن ثبت شده است. پس در بدترین حالت می‌توانیم تاریخ را از روی نام فایل‌ها بازسازی کنیم.</p>

<p>داشتن تاریخ یک رویداد در نام فایل به قدری کاربردی است که افزودن تاریخ به فرمتISO8601 به ابتدای نام تمام فایل‌ها به یک عادت دائمی برای من تبدیل شده است. معمولا وقتی قصد کپی گرفتن از یک فایل دارم از دستور زیر استفاده می‌کنم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ copy myfile.jpg $(date -I)_myfile.jpg
</code></pre></div></div>

<p>یا بدون خط تیره در نام فایل:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ copy myfile.jpg $(date +%+4Y%m%d)_myfile.jpg
</code></pre></div></div>

<p>حسن این فرمت اینست که نام فایل ابتدا با سال و سپس با ماه و روز شروع می‌شود که کار سورت کردن فایل‌ها را خیلی ساده می‌کند.</p>

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

<p>مهم است که بدانیم متادیتا (داده در مورد داده) چیست و کجا ذخیره می‌شود. تاریخ ساخت و تغییر و دسترسی و مانند اینها در حالت عادی داخل فایل ذخیره نمی‌شوند و هر فایل‌سیستم و سیستم‌عامل آن را جداگانه ذخیره می‌کند. فایل‌سیستم ما در این مورد ext4 و سیستم عامل هم ما مبتنی بر لینوکس است. من اطلاعی در مورد ویندوز ندارم اما در سیستم‌عامل‌های مشابه یونیکس متادیتای فایل در ساختاری بنام inode ذخیره می‌شود (از جایی که مک‌اوس هم از خانواده‌ی یونیکس است آنجا هم باید این موارد صادق باشد). به کمک فرمان <code dir="ltr" class="language-plaintext highlighter-rouge">ls -i</code> می‌توانیم  inode یکتای مختص هر فایل را ببینیم. inode اطلاعات مختلفی از جمله حق دسترسی‌ها و همچنین چندین تاریخ (timestamp) مختلف را در خود ذخیره می‌کند. برای مشکلی که ما اینجا با آن روبرو هستیم ctime یا همان <code dir="ltr" class="language-plaintext highlighter-rouge">creation_time</code> و mtime یا همان <code dir="ltr" class="language-plaintext highlighter-rouge">modification_time</code> مهم است. اولی تاریخ ساخت و دومی تاریخ آخرین تغییر فایل است. atime یا همان <code dir="ltr" class="language-plaintext highlighter-rouge">access_time</code> هم وجود دارد که تاریخ آخرین دسترسی یا خوانده شدن محتوای فایل است. در <a href="https://www.kernel.org/doc/html/latest/filesystems/ext4/inodes.html?highlight=inode">مستندات کرنل لینوکس برای ext4</a> جزئیات پیاده‌سازی inode در لینوکس آمده است.</p>

<p>نکته‌ی جالبی که در مستندات یاد شده آمده است اینست که متغیری که برای ذخیره‌ی برخی از این تاریخ‌ها استفاده شده چهار بایت (سی و دو بیت) است. نحوه‌ی رایج ذخیره‌ی timestamp یا لحظه‌ی خاص در امتداد محور زمان یک عدد است که تعداد ثانیه‌های سپری شده از بامداد روز اول ژانویه‌ی سال ۱۹۷۰ به وقت گرینویچ در خود ذخیره می‌کند. منتها در سال ۲۰۳۸ تعداد این ثانیه‌ها دیگر در چهار بایت جا نمی‌شود و به اصطلاح overflow یا سرریز می‌کند. برای رفع این مشکل تمهیداتی اندیشیده شده است که شرح آن در  مستندات ذکر شده آمده است.</p>

<p>به کمک دو دستور ls و stat می‌توانیم برخی از اطلاعات inode را ببینیم. مثلا بیایید خروجی زیر را برای یکی از عکس‌های خراب من ببینیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mx@playground[21250]:/home/mx/Sync/Everything/DCIM/Camera
$ stat 20190928_200752.jpg
stat 20190928_200752.jpg
  File: 20190928_200752.jpg
  Size: 1828942   	Blocks: 3576       IO Block: 4096   regular file
Device: 253,0	Inode: 15409043    Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1100/      mx)   Gid: (  985/   users)
Access: 2024-03-01 10:48:49.262525490 +0100
Modify: 2021-10-27 23:04:21.000000000 +0200
Change: 2022-05-14 12:07:15.297708323 +0200
 Birth: 2021-11-08 10:43:23.375113903 +0100
mx@playground[21249]:/home/mx/Sync/Everything/DCIM/Camera
$ ls -l !$
ls -l 20190928_200752.jpg
-rw-rw-r-- 1 mx users 1828942 Oct 27  2021 20190928_200752.jpg
</code></pre></div></div>

<p>از مقایسه‌ی خروجی stat با ls پیداست که ls تاریخ آخرین تغییر را در خروجی‌اش نمایش می‌دهد (که ۲۷ اکتبر ۲۰۲۱ است).</p>

<p>همانطور که از مقایسه‌ی نام فایل با خروجی دستوارت بالا پیداست ایرادی که برای عکس‌های ما پیش آمده اینست که به طریقی این متاداده حین کپی فایل‌ها از یک کامپیوتر (لینوکس) به دیگری (لینوکس) و در نهایت موبایل تغییر کرده است (اندروید هم لینوکس است  البته در مورد گوشی سامسونگم از نوع فایل‌سیستم مطمئن نیستم). مثلا عکسی که سال ۲۰۱۹ گرفته شده است تغییر کرده است به سال ۲۰۲۱ یا ۲۰۲۳. با جستجو در فروم سینک‌تینگ متوجه شدم که سینک‌تینگ تاریخ آخرین تغییر را سینک می‌کند. بنابراین برنامه اصلاح تاریخ آخرین تغییر است. در حقیقت این مسئله به قدری رایج است که برنامه‌های cp و scp و rsync و غیره فلگی برای حفظ متادیتای فایل مرجع دارند. مثلا در مورد cp نگاهی به <code dir="ltr" class="language-plaintext highlighter-rouge">man cp</code> به ما می‌گوید که <code dir="ltr" class="language-plaintext highlighter-rouge">-p</code> (حرف اول preserve) باعث حفظ تاریخ‌ها و حق‌دسترسی‌های فایل مرجع می‌شود.</p>

<p>برگردیم سروقت مشکل اصلی. از جایی که متاداده‌های inode عکس‌های ما خراب شده باید تاریخ را یا از نام فایل بگیریم یا از خود فایل. بسته به نوع فایل ممکن است اطلاعاتی اضافه بر داده‌ی خام نیز داخل آن ذخیره شده باشد که می‌شود نوع دوم متاداده. در مورد عکس‌ها (و اصوات ضبط شده در قالب WAV) این قضیه صادق است و برخی انواع فایل مانند JPG و TIF و WAV و PNG و WEBP می‌توانند متاداده با قالب Exif در خود ذخیره کنند (ممکن است انواع دیگری هم باشد که من از آن بی اطلاعم).</p>

<p>برای دیدن متادیتای اگزیف از برنامه‌ای قدیمی به نام <a href="https://exiftool.org/">exiftool</a> کمک می‌گیریم (که به زبان پرل توسط فیل هاروی نوشته شده است). مثلا به کمک دستور زیر می‌توان تمام تاریخ‌های ذخیره شده در یک فایل سالم را دید:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ exiftool -time:all -s 20190307_144822.jpg
FileModifyDate                  : 2019:03:07 14:48:22+01:00
FileAccessDate                  : 2024:02:28 08:25:22+01:00
FileInodeChangeDate             : 2024:02:28 08:25:21+01:00
ModifyDate                      : 2019:03:07 14:48:22
DateTimeOriginal                : 2019:03:07 14:48:22
CreateDate                      : 2019:03:07 14:48:22
SubSecTime                      : 0611
SubSecTimeOriginal              : 0611
SubSecTimeDigitized             : 0611
TimeStamp                       : 2019:03:07 14:48:22.654+01:00
SubSecCreateDate                : 2019:03:07 14:48:22.0611
SubSecDateTimeOriginal          : 2019:03:07 14:48:22.0611
SubSecModifyDate                : 2019:03:07 14:48:22.0611
</code></pre></div></div>

<p>می‌بینیم که «تگ»های مختلفی در اطلاعات اگزیف وجود دارد (ممکن است exiftool اطلاعات inode را هم به خروجی اضافه کرده باشد). اگر نام فایل را با تاریخ‌های ذخیره شده مقایسه کنیم هم می‌بینیم که تاریخ‌ها درست هستند (بجز تاریخ آخرین دسترسی و تاریخ آخرین تغییر inode). مثال دیگری از یک فایل خراب (دقت کنید که متادیتای کمتری دارد):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ exiftool -time:all -s 20190928_200752.jpg
FileModifyDate                  : 2021:10:27 23:04:21+02:00
FileAccessDate                  : 2024:01:21 23:56:30+01:00
FileInodeChangeDate             : 2022:05:14 12:07:15+02:00
ModifyDate                      : 2019:09:28 20:07:52
DateTimeOriginal                : 2019:09:28 20:07:52
CreateDate                      : 2019:09:28 20:07:52
TimeStamp                       : 2019:09:28 20:07:52.812+02:00
</code></pre></div></div>

<p>در این مورد مقایسه نام فایل با FileModifyDate نشان می‌دهد تاریخ آخرین تغییر غلط است (من این فایل‌ها را از زمان عکاسی ویرایش نکرده‌ام البته شاید سهوا کپی کرده باشم). از جایی که با بررسی فایل‌های مختلف متوجه شدم مقدار CreateDate صحیح است بیایید به کمک آن اطلاعات inode عکس‌هایمان را تصحیح کنیم.</p>

<p>برای بیرون کشیدن CreateDate از فرمت زیر کمک می‌گیریم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg 20190307_144822.jpg
CreateDate: 201903071448.22
</code></pre></div></div>

<p>علت فرمت کردن خروجی اینست که ما می‌خواهیم در گام‌های بعدی آن را به خورد touch بدهیم و این فرمتی است که touch قبول می‌کند. <code dir="ltr" class="language-plaintext highlighter-rouge">man exiftool</code> را ببینید.</p>

<p>روش کار به کمک دستوارت ساده‌ی یونیکس و همچنین Bash خیلی ساده است:</p>

<ol>
  <li>فایل‌های تمام عکس‌ها را لیست می‌کنیم</li>
  <li>روی هر فایل دستور exiftool را اجرا می‌کنیم و  CreateDate آنرا در خروجی چاپ می‌کنیم</li>
  <li>از خروجی exiftool مقدار دقیق CreateDate را «می‌بریم»</li>
  <li>به کمک xargs خروجی cut را به خورد touch می‌دهیم که زمان آخرین تغییر را با مقداری که از exiftool گرفتیم جایگزین می‌کند</li>
</ol>

<p>هر چهار مرحله‌ی بالا به هم به کمک <code dir="ltr" class="language-plaintext highlighter-rouge">|</code> به هم وصل شده است. به <code dir="ltr" class="language-plaintext highlighter-rouge">|</code> می‌گویند «پایپ» یا «لوله». یعنی ما دستورات مختلف (پراسس‌های مختلف) را به یک لوله به هم وصل می‌کنیم (لوله‌کشی می‌کنیم!). کار این لوله وصل کردن خروجی استاندارد هر دستور به ورودی استاندارد دستور بعدی است. لوله اختراع  <a href="https://en.wikipedia.org/wiki/Douglas_McIlroy">Douglas McIlroy</a> یونیکس‌کار ۹۲ ساله‌ی آمریکایی است و یکی از معجزات یونیکس به شمار می‌رود. جالب است بدانید او در ۹۲ سالگی هنوز هم در میلینگ لیست <a href="https://www.tuhs.org/">TUHS</a> فعال است.</p>

<p>برای لیست کردن فایل‌ها در یک حلقه از حلقه‌ی for که در Bash فراهم است کمک می‌گیریم. کافیست به <code dir="ltr" class="language-plaintext highlighter-rouge">man bash</code> نگاهی بکنیم و چند صفحه پایین برویم تا برسیم به Compound Commands و کمی پایین‌تر نحوه‌ی نوشتن for را پیدا می‌کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for name [ [ in [ word ... ] ] ; ] do list ; done
    The list of words following in is expanded, generating a list of items.  The variable name is set to each ele‐
    ment of this list in turn, and list is executed each time.  If the in word is omitted, the  for  command  exe‐
    cutes  list  once  for each positional parameter that is set (see PARAMETERS below).  The return status is the
    exit status of the last command that executes.  If the expansion of the items following in results in an empty
    list, no commands are executed, and the return status is 0.
</code></pre></div></div>

<p>در بدنه‌ی یک حلقه‌ی for می‌شود به آن مقدار یا لغتی که در آن لحظه به آن رسیده‌ام با بکارگیری <code dir="ltr" class="language-plaintext highlighter-rouge">$name</code> دسترسی داشت. <code dir="ltr" class="language-plaintext highlighter-rouge">name</code> مقداری است اختیاری که ما انتخاب می‌کنیم. باید دقت داشته باشیم که از دید for هر آنچه در برابرش ظاهر می‌شود چیزی جز یک کلمه نیست. مثلا اگر خروجی دستور ls را به آن بدهیم و نام فایل‌های ما خط فاصله داشته باشد for آنها را چند لغت جدا از هم خواهد دید. این نکته‌ی بسیار مهمی است و برای رفع آن همواره باید متغیرها را درون گیومه قرار داد. بیایید اول یک لیست ساده بنویسیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ for i in $(ls *.jpg | head -n3); do echo "$i"; done
20190307_144822.jpg
20190307_144826.jpg
20190313_172658.jpg
</code></pre></div></div>

<p>این دستور عکس‌های ما را لیست می‌کند. ما فقط نام فایل را echo کردیم (دستوری که هر آنچه به آن بدهید در خروجی استاندارد خودش می‌نویسد). نام متغیر را <code dir="ltr" class="language-plaintext highlighter-rouge">i</code> انتخاب کرده‌ایم. علاوه بر آن بجای word مقدار <code dir="ltr" class="language-plaintext highlighter-rouge">$(ls *.jpg | head)</code> گذاشته‌ایم. Bash هر چیزی که درون <code dir="ltr" class="language-plaintext highlighter-rouge">$()</code> بگذاریم همیشه به عنوان یک فرمان اجرا می‌کند و با خروجی آن جایگزین می‌کند. ما دستور <code dir="ltr" class="language-plaintext highlighter-rouge">ls *.jpg | head -n3</code> داخل آن گذاشته‌ایم. ls که فایل‌های منتهی به <code dir="ltr" class="language-plaintext highlighter-rouge">.jpg</code> را لیست می‌کند و خروجی آن را به کمک لوله می‌دهد به <code dir="ltr" class="language-plaintext highlighter-rouge">head</code> که دستور ساده‌ایست که فقط چند خط اول را نگه می‌دارد (چون فایل‌ها زیاد است و برای مثال ما همین کافی بود). جلوتر هم طبق مستندات for دستوری که می‌خواهیم برای هر «لغت» اجرا شود آورده‌ایم که چیزی جز <code dir="ltr" class="language-plaintext highlighter-rouge">echo "$i"</code> نیست. برای فهم بهتر در نظر بگیرید که دستور بالا دقیقا معادل دستور پایین است:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ for in in 20190307_144822.jpg 20190307_144826.jpg 20190313_172658.jpg; do echo $i; done
20190322_200524.jpg
20190322_200524.jpg
20190322_200524.jpg
</code></pre></div></div>

<p>با این مقدمه در مورد for حالا دستور exiftool را در دل آن جای می‌دهیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ for i in $(ls *.jpg | head -n3); do exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg "$i"; done
CreateDate: 201903071448.22
CreateDate: 201903071448.26
CreateDate: 201903131726.58
</code></pre></div></div>

<p>به همین ترتیب ادامه می‌دهیم و اینبار خروجی را می‌بریم تا فقط تاریخ فرمت شده باقی بماند:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ for i in $(ls *.jpg | head -n3); do exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg "$i" | cut -d ' ' -f 2; done
201903071448.22
201903071448.26
201903131726.58
</code></pre></div></div>

<p>می‌بینید که دوباره خروجی یک دستور را لوله کرده‌ایم در ورودی دستور بعدی، اینجا دستور <code dir="ltr" class="language-plaintext highlighter-rouge">cut</code>. این دستور هر خط ورودی‌اش را به کمک یک جداکننده (اینجا خط فاصله) قیچی می‌کند و آنها را به چند ستون تبدیل می‌کند که بعد ما می‌توانیم یک ستون خاص را با پارامتر <code dir="ltr" class="language-plaintext highlighter-rouge">-f</code> انتخاب کنیم. حالا نام هر فایل و تاریخ صحیح را داریم، ماند اصلاح فایل‌ها.</p>

<p>برای اصلاح فایل از دستور <code dir="ltr" class="language-plaintext highlighter-rouge">touch</code> استفاده می‌کنیم. <code dir="ltr" class="language-plaintext highlighter-rouge">man touch</code> به ما می‌گوید که <code dir="ltr" class="language-plaintext highlighter-rouge">touch</code> می‌توان تاریخ همین لحظه یا یک تاریخ دلخواه را در inode یک فایل بنویسد. تاریخ فرمت‌شده مطابق خواست <code dir="ltr" class="language-plaintext highlighter-rouge">touch</code> را که قبلا ساختیم و نام فایل را هم که در متغیر <code dir="ltr" class="language-plaintext highlighter-rouge">i</code> داریم. منتها از جایی که ما می‌خواهیم فایل‌های مختلفی را با تاریخ‌های مختلف اصلاح کنیم باید دستور touch را برای تک‌تک آنها جداگانه اجرا کنیم. به همین منظور از دستور <code dir="ltr" class="language-plaintext highlighter-rouge">xargs</code> کمک می‌گیریم. xargs برای هر خط که در ورودی استانداردش نوشته بشود یکبار دستوری که به آن در خط فرمان داده‌ایم اجرا می‌کند.</p>

<p>حالا فقط می‌ماند اجرای دستور نهایی. منتها برای تست اول یکبار همه را <code dir="ltr" class="language-plaintext highlighter-rouge">echo</code> می‌کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ for i in $(ls *.jpg | head -n3); do exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg "$i" | cut -d ' ' -f 2 | xargs echo touc
h "$i" -t; done
touch 20190307_144822.jpg -t 201903071448.22
touch 20190307_144826.jpg -t 201903071448.26
touch 20190313_172658.jpg -t 201903131726.58
</code></pre></div></div>

<p>این خروجی دستور نهایی است. که خوب به نظر می‌رسد. فقط کافیست <code dir="ltr" class="language-plaintext highlighter-rouge">head -n3</code> را به همراه <code dir="ltr" class="language-plaintext highlighter-rouge">echo</code>ی قبل از <code dir="ltr" class="language-plaintext highlighter-rouge">xargs</code> حذف کنیم و آن را دوباره اجرا کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ for i in $(ls *.jpg); do exiftool -CreateDate -S -d %Y%m%d%H%M.%S -ext jpg "$i" | cut -d ' ' -f 2 | xargs touch "$i" -t; done
</code></pre></div></div>

<p>و تمام.</p>

<p>در این مقاله‌ی کوتاه نگاهی کردیم به متادیتای فایل‌ها در یونیکس و نیز متادیتای اگزیف موجود در عکس‌ها و به کمک مقادیر صحیح تگ CreateDate اگزیف تاریخ آخرین تغییر فایل‌هایمان را اصلاح کردیم تا برنامه‌های گالری عکس بتوانند عکس‌ها را با توالی صحیح نمایش بدهند.</p>

</div>]]>
    </content>
    <summary>مشکلی با عکس‌های آرشیوی‌ام پیش آمده که بد نیست بنویسم برای خود آینده‌ام و رهگذران عزیز. من عکس‌هایی که با گوشی‌های مختلف گرفته‌ام را به کمک Syncthing با کامپیوترم سینک می‌کنم. در حال حاضر یکسالی می‌شود که روی یک Rock64 فسقلی Libreelec ریخته‌ام و یک هارد پنج‌ترابایتی هم برای سینک به درگاه USB 3 آن متصل کرده‌ام (که ممکن است دیر یا زود به خاطر روشن و خاموش شدن متعدد عمرش را بدهد به شما). سینک‌تینگ روی راک است و فایل‌ها سنک می‌شود روی آن هارددیسک. حالا مشکلی که پیش امده این است که من گوشی جدیدی خریده‌ام و تمام...</summary>
  </entry>

<entry>
    
    <id>https://mehdix.ir/aoc.html</id>
    
    <title>معرفی Advent of Code</title>
    <updated>2023-12-10T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/aoc.html"/>
    <category term="تفریح"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>پس از وقفه‌ای یکساله که شاید در آینده درباره‌اش بنویسم برمی‌گردیم سروقت نوشتن. اینبار قصد دارم چالش Advent of Code را به خوانندگان عزیر معرفی کنم.</p>

<h2 id="چیست-این-advent"><a href="#چیست-این-advent">چیست این Advent؟</a></h2>
<p>در عموم کشورهای مسیحی به ایامی که مؤمنین خود را برای جشن تولد مسیح آماده می‌کنند Advent گفته می‌شود. این ایام معمولا سه هفته اول ماه دسامبر است تا روز اول کریسمس (۲۵ دسامبر در آلمان). مثلا در کشور آلمان در این ایام بازارچه‌های سال نو برپا هستند (که همگی حداکثر یکی دو روز قبل از کریسمس تعطیل می‌کنند) و برنامه‌های مختلف سرگرم‌کننده برای کودکان و بزرگسالان در سراسر کشور برپاست. رایج است که در این کشورها مردم به شکل‌های مختلف به استقبال کریسمس می‌روند. یکی از رایج‌ترین اقلامی که در این ایام بویژه برای کودکان خریداری می‌شود یک تقویم ادونت است. یک تقویم ادونت بیست و پنج خانه دارد، یکی برای هر روز. معمولا این تقویم‌ها برای هر روز یک خانه دارند که می‌توان درب آن را باز کرد و داخل آن معمولا تصویر یا متن یا یک جایزه قرار دارد.</p>

<h2 id="advent-of-code"><a href="#advent-of-code">Advent of Code</a></h2>
<p>برنامه‌نویس خوش‌قریحه‌ای بنام <a href="http://was.tl/">Eric Wastl</a> از سال ۲۰۱۵ هر ساله در این ایام چالشی بنام <a href="https://adventofcode.com/">Advent of Code</a> منتشر می‌کند. این چالش از روز اول دسامبر شروع می‌شود و ۲۵ روز ادامه دارد. در بامداد هر روز او یک سوال روی سایت چالش منتشر می‌کند که دو بخش دارد. با حل هر بخش می‌توان یک ستاره دریافت کرد و در پایان ۲۵ روز حداکثر ۵۰ ستاره جمع‌آوری کرد.</p>

<h3 id="ساختار-چالش"><a href="#ساختار-چالش">ساختار چالش</a></h3>
<p>هر چالش دو بخش دارد. یک بخش اول و اصلی که ساده‌تر است و یک بخش دوم. بخش دوم معمولا ادامه‌ی همان بخش اول است و می‌توان از راه‌حل بخش اول در حل بخشی از آن استفاده کرد یا کلا همان بخش اول است اما ورودی بزرگتری دارد و نکته‌دار است. برای گرفتن هر ستاره کافیست که پاسخ صحیح را در کادر مربوطه وارد کرد و نیازی به ارسال کد نیست. از جایی که ورودی‌ها برای هر کاربر می‌تواند متفاوت باشد باید در سایت چالش ثبت‌نام کرد. دسترسی به سوالات سالهای گذشته نیز روز وبسایت چالش امکانپذیر است.</p>

<p>ساختار چالش‌ها شبیه مسابقات <a href="https://icpc.global/worldfinals/past-problems">ICPC</a> است (زمان ما می‌گفتیم ACM). به این صورت که یک ورودی تست و یک خروجی تست به همراه یک ورودی اصلی برای هر قسمت ارائه می‌شود. گاهی قسمت دوم هم از همان ورودی قسمت اول استفاده می‌کند و ورودی جدیدی ندارد. برنامه‌نویس فقط کافیست که جواب صحیح را وارد کند و نیازی به سابمیت کردن کدی که نوشته است نیست. اصلا هم مهم نیست که به چه زبانی مسئله‌ها را حل می‌کنیم. در ضمن نیازی به حل تمام مسائل نیست. اگر سوالی وقت‌گیر یا مشکل بود می‌توان رفت سروقت بعدی و از ستاره‌ی سوال سخت صرف‌نظر کرد.</p>

<h3 id="روش-کار-من"><a href="#روش-کار-من">روش کار من</a></h3>
<p>من سال گذشته تا روز ۱۹ را حل کردم. البته در روز ۱۹ گیر کردم و دیگر نتوانستم پیشروی کنم! البته سعی کرده بودم حتما هر روز را حل کنم تا بروم روز بعدی که توصیه می‌کنم شما اینکار را نکنید و اگر سوالی خیلی سخت بود بروید سروقت بعدی. در ضمن سعی کرده بودم که همه را با زبان برنامه‌نویسی Go بنویسم که آنهم کمی وقت گرفت ولی در مجموع خوب بود.
پیشنهاد من اینست که در هر برنامه‌ای که می‌نویسید یک ساختار یکسان را رعایت کنید:</p>

<p>۱. ورودی را از فایل بخوانید (فایل‌ها را با یک ساختار خوب ذخیره کنید مثلا dayXinput و  dayXtestinput).</p>

<p>۲. فایل را پارس کنید و در یک ساختار داده‌ی درست ذخیره کنید. مثلا اگر گراف است در یک ساختار گراف درست با جستجو و حذف و اضافه ذخیره کنید.</p>

<p>۳. چالش را برای ورودی تستی حل کنید.</p>

<p>۴. چالش را برای ورودی اصلی حل کنید.</p>

<h3 id="کتابهای-لازم"><a href="#کتابهای-لازم">کتابهای لازم</a></h3>
<p>برای حل مسائل الگوریتمی اگر می‌توانید حتما دو کتاب را دم دست داشته باشید. هر دو کتاب رفرنس‌های بسیار معتبر و شناخته‌شده‌ای هستند.</p>

<figure class="center border">
  <p><img src="assets/pimg/clrs.jpg" alt="" title="aka. CLRS" /></p>
  <figcaption>
Introduction to Algorithms by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein (aka CLRS)
</figcaption>
</figure>

<figure class="center border">
  <p><img src="assets/pimg/algoskiena.png" alt="" /></p>
  <figcaption>
The Algorithm Design Manual by Steve S. Skiena
</figcaption>
</figure>

<h3 id="گروه‌های-پشتیانی"><a href="#گروه‌های-پشتیانی">گروه‌های پشتیانی</a></h3>
<p>اگر به سایت چالش دقت کنید همانجا تعدادی گروه معمولا انگلیسی زبان برای پشتیبانی لیست شده. فعالترین آنها <a href="https://www.reddit.com/r/adventofcode">ساب‌ردیت خود چالش</a> است. آنها اگر مثلا دنبال 2022 day 5 بگردید پست‌های مربوط به آن را پیدا می‌کنید. در ضمن می‌توانید از سایدبار بخوانید که چطور سوال بپرسید. چون پست‌ها انواع مختلفی دارند، مثلا بعضی افراد هر سال برای راه‌حل‌هایشان جلوه‌های بصری تولید می‌کنند و با بقیه به اشتراک می‌گذارند. در پست‌های خاصی هم جواب‌هایشان را منتشر و مقایسه می‌کنند. حتما سایدبار را بخوانید که بتوانید جواب درست بگیرید.</p>

<p>جدای از کامیونیتی انگلیسی زبان هم می‌توانید اینجا بپرسید (که طول می‌کشد منتشر بشود) یا ایمیل بزنید و یا روی اتاق ماتریکس یا آی‌آر‌سی بپرسید یا روش بهتری پیدا کنید یا یکی بسازید.</p>

<p>بیش از این روده‌درازی نمی‌کنم. این شما و این هم <a href="https://adventofcode.com/2023">چالش ادونت آو کد سال ۲۰۲۳</a>!</p>

<p>موفق باشید.</p>

</div>]]>
    </content>
    <summary>پس از وقفه‌ای یکساله که شاید در آینده درباره‌اش بنویسم برمی‌گردیم سروقت نوشتن. اینبار قصد دارم چالش Advent of Code را به خوانندگان عزیر معرفی کنم. چیست این Advent؟ در عموم کشورهای مسیحی به ایامی که مؤمنین خود را برای جشن تولد مسیح آماده می‌کنند Advent گفته می‌شود. این ایام معمولا سه هفته اول ماه دسامبر است تا روز اول کریسمس (۲۵ دسامبر در آلمان). مثلا در کشور آلمان در این ایام بازارچه‌های سال نو برپا هستند (که همگی حداکثر یکی دو روز قبل از کریسمس تعطیل می‌کنند) و برنامه‌های مختلف سرگرم‌کننده برای کودکان و بزرگسالان در سراسر کشور برپاست....</summary>
  </entry>

<entry>
    
    <id>https://mehdix.ir/canbus.html</id>
    
    <title>راهنمای کوچک کار با کَن‌باس</title>
    <updated>2022-09-04T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/canbus.html"/>
    <category term="صنعت"/><category term="شبکه"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>در این نوشته به طور خلاصه با کَن‌باس <em><a href="https://en.wikipedia.org/wiki/CAN_bus">CAN bus</a></em><sup id="fnref:a"><a href="#fn:a" class="footnote" rel="footnote" role="doc-noteref">۱</a></sup> آشنا می‌شویم و یاد می‌گیریم چطور با آن کار کنیم. طبق معمول ابزارهای بکار رفته همه آزاد هستند.</p>

<p>کن‌باس یک <a href="https://en.wikipedia.org/wiki/Bus_(computing)">باس</a> یا گذرگاه داده‌ی بسیار ساده و مقاوم و ارزان است که برای ساده‌سازی سیم‌کشی درون خودروها و ارتباط اجزاء مختلف با کنترلرها و کامپیوترهای خودرو در سال ۱۹۸۶ توسط شرکت بوش آلمان به خودروسازان جهان <a href="https://www.can-cia.org/can-knowledge/can/can-history/">معرفی</a> شده است. مستندات فنی نسخه‌ی ۲ آن به سال ۱۹۹۱ را می‌توانید <a href="/assets/can20.pdf">در این آدرس</a> بخوانید. بعدها در سال ۱۹۹۳ مشخصات فنی کن‌باس به استاندارد ایزو شماره‌ی ۱۱۸۹۸ تبدیل شد.</p>

<p>بدون وجود یک باس، می‌بایست درون خودرو کیلومترها سیم برای اتصال اجزاء مختلف به کنترلرها بکار رود. علاوه بر این بدون یک باس نمی‌توان از سیم‌ها برای مقاصد مختلف استفاده کرد. مثلا تصور کنید چراغ ترمز یک خودرو خراب شده است، اما چراغ خطر اضافی عقب خودرو سالم است. کامپیوتر خودرو می‌تواند خرابی را تشخیص بدهد و از چراغ خطر اضافی عقب بجای چراغ ترمز استفاده کند. بدون یک باس امکان اینکار وجود ندارد. علت اینکه به چنین گذرگاهی «باس» می‌گویند اینست که شبیه یک اتوبوس عمل می‌کند. یعنی داده‌های قطعات مختلف همگی می‌توانند سوار این اتوبوس بشوند و از یک ایستگاه به ایستگاه دیگری بروند.</p>

<p>یک کن‌باس حداقل به دو نود (عضو) برای کار نیاز دارد. همه‌ی اعضا با <a href="https://fa.wikipedia.org/wiki/%D8%B2%D9%88%D8%AC_%D8%A8%D9%87%E2%80%8C%D9%87%D9%85%E2%80%8C%D8%AA%D8%A7%D8%A8%DB%8C%D8%AF%D9%87">یک زوج سیم پیچ‌ و تاب خورده</a> به یکدیگر متصل می‌شوند. یکی از این سیم‌ها CAN High و دیگری CAN Low نام دارد. هر دو انتهای این سیم‌ها باید با یک مقاومت ۱۲۰ اهمی به هم بسته بشوند. تصویر زیر از ویکی‌پدیا به خوبی این معماری را نمایش می‌دهد.</p>

<p class="center"><img src="assets/pimg/CAN_ISO11898-2_Network.png" alt="" />
<em>By EE JRW - Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=38256600</em></p>

<p>هر یک از نودهای برای اتصال به کن‌باس به یک مدار ساده احتیاج خواهد داشت. این مدار معمولا حاوی سه جزء است. یکی ترنسیور<sup id="fnref:c"><a href="#fn:c" class="footnote" rel="footnote" role="doc-noteref">۲</a></sup> و دیگری کنترلر<sup id="fnref:d"><a href="#fn:d" class="footnote" rel="footnote" role="doc-noteref">۳</a></sup> و آخری هم میکروکنترلر (پردازنده‌ی میزبان) نام دارد. زوج سیم‌های باس تنها به ترنسیور وصل می‌شود و ترنسیور به نوبه خود به کنترلر. ترنسیور قطعه‌ی بسیار ساده‌ایست. کارش اینست که ولتاژهای الکتریکی CAN Low و CAN High را به سطوح منطقی صفر و یک قابل فهم برای کنترلر تبدیل بکند. از سوی دیگر کنترلر قطعه‌ی مهمی است و کارش پیاده‌سازی قرارداد ارتباطی است که در مستندات فنی کن‌باس قید شده است. کنترلر است که تصمیم می‌گیرد چه زمانی با باس صحبت بکند و اینکه چگونه پیام را ارسال بکند و چه زمانی تنها گوش بکند و چه زمانی کاملا خاموش باشد.</p>

<p>دست آخر هم هر نود باید برای ارسال و دریافت پیام روی باس با کنترلر خودش صحبت بکند. این کار را میکروکنترلر انجام می‌دهد. جایی که کاربر معمولا برنامه‌اش را باید بنویسد و فلش و اجرا کند. میکروکنترلر معمولا از یک طرف به سنسورها یا پمپ‌ها و مانند این متصل است و از سوی دیگر به کنترلر. مثلا در مثال چراغ خطر بالا میکروکنترلر از یک سو به چراغ خطر وصل خواهد بود و از سوی دیگر به کنترلر. به این ترتیب او می‌تواند هم وضعیت چراغ خطر را پیوسته از طریق باس به کامپیوتر خودرو ارسال بکند و از سوی دیگر فرامین کامپیوتر خودرو را دریافت و مثلا کاربری چراغ خطر را تغییر بدهد. امروزه میکروکنترلرهای زیادی حاوی کن کنترلر درونی هستند (اما فاقد ترنسیور مثل برخی پردازنده‌های سری <a href="https://docs.espressif.com/projects/esp-idf/en/release-v3.3/api-reference/peripherals/can.html">ESP32</a>).</p>

<p>تصویر زیر از ویکی‌پدیا معماری یک نود را به خوبی نمایش می‌دهد.</p>

<p class="center"><img src="assets/pimg/CAN_Node.png" alt="" />
<em>EE JRW, CC BY-SA 4.0 <a href="https://creativecommons.org/licenses/by-sa/4.0">https://creativecommons.org/licenses/by-sa/4.0</a>, via Wikimedia Commons</em></p>

<p>مشخصاتی که در سال ۱۹۹۱ از طرف بوش برای کن‌باس منتشر شده است حاوی دو بخش A و B است. پیاده‌سازی‌هایی که طبق بخش A ساخته شده‌اند به CAN2.0A و آنهایی که سازگار با بخش B طراحی شده‌اند به نام CAN2.0B (نسخه‌ی توسعه‌یافته) شناخته می‌شوند. هر دو با هم سازگار هستند و می‌توانند در آن واحد در باس مشارکت کنند. تنها تفاوت آنها در طول شناسه‌ی پیام‌هاست. در کن‌باس نودهای باس به یکدیگر پیام (یک فریم) ارسال می‌کنند. هر نود باید پیام‌هایش را با یک شناسه‌ی یکتا ارسال بکند. هر پیام هم به نوبه خود حاوی شناسه‌ی نود فرستنده و یک بدنه است. شناسه می‌تواند طبق CAN2.0A و ۱۱ بیت یا طبق CAN2.0B و ۲۹ بیت باشد. کن‌باس محدودیتی تئوریک برای تعداد نودهای حاضر در باس تعریف نمی‌کند. تمام نودهای حاضر در باس تمام پیام‌ها را دریافت می‌کنند حتی نود فرستنده. تصویر زیر ساختار یک فریم یازده بیتی را نمایش می‌دهد.</p>

<p class="center"><img src="assets/pimg/CAN_telegramm_2.0A.svg" alt="" />
<em>Fröstel (S.G.), CC0, via Wikimedia Commons</em></p>

<p>کن چهار نوع فریم تعریف می‌کند: داده و ریموت و خطا و اوورلود. مهمترین نوع فریم داده است که نودها با آن داده ارسال می‌کنند. هر فریم داده می‌تواند صفر تا ۶۴ بیت (۸ بایت) داده داشته باشد. نودها نیز نیازی به تنظیمات مرکزی ندارند. هر نود به محض اتصال می‌تواند در باس مشارکت بکند. کنترلر وظیفه‌ی ارسال و دریافت پیام‌ها را طبق مشخصات فنی کن‌باس بر عهده می‌گیرد. مثلا ارسال فریم خطا هنگام دریافت فریم ناقص یا سکوت کامل هنگام دریافت خطا بیش از حد مجاز یا خاموش کردن کامل نود (bus-off) در برخورد با خطاهای غیر قابل اصلاح و چشم‌پوشی.</p>

<p>علاوه بر نسخه‌ی‌ای که در بالا معرفی کردیم نسخه‌های سطح بالاتری از کن هم توسط بوش و دیگران ساخته شده است که برای کاربردهای پیچیده‌تر به کار می‌روند. از میان آنها می‌توان به CAN-FD توسط بوش و CANopen اشاره کرد. ویژگی مشترک اغلب آنها اینست که از کن‌باس به عنوان پایین‌ترین لایه‌ی ارتباطی استفاده می‌کنند.</p>

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

<p>از طرفی کن برخلاف پروتکل اترنت (شبکه‌های کامپوتری) شکل فیزیکی پورت اتصال کابل به نود را محدود نمی‌کند. تا آنجا که به کن مربوط است فقط کافیست دو سیم برای اتصال وجود داشته باشد. اینکه چگونه نودها به یکدیگر متصل می‌شوند برای کن مهم نیست. از این رو در بازار روش‌های مختلفی رایج شده است. محبوب‌ترین و ارزانترین پورت اتصالی ترمینال پیچی است:</p>

<p class="center"><img src="assets/pimg/screw_terminal.png" alt="" />
<em><code dir="ltr" class="language-plaintext highlighter-rouge">Phoenix Contact https://www.phoenixcontact.com/</code></em></p>

<p>پورت بعدی که گران است ولی در محصولات صنعتی رایج است انواع اتصالات گرد از سری محصولات شرکت فونیکس کانتکت است. هر تولید‌کننده‌ای تصمیم می‌گیرد که چه متصل‌کننده‌ای برایش مناسب‌تر است و اینکه کدام پین‌ها باید برای CAN High و CAN Low بکار برود. این جزئیات هم در دیتاشیت تولید کننده منتشر می‌شود. شکل زیر تعدادی متصل‌کننده را نشان می‌دهد:</p>

<p class="center"><img src="assets/pimg/M12_Power_HighRes-1564697842.jpg" alt="" />
<em><code dir="ltr" class="language-plaintext highlighter-rouge">Phoenix Contact https://www.phoenixcontact.com/</code></em></p>

<p>آخرین پورت رایجی که نام می‌بریم <a href="https://en.wikipedia.org/wiki/On-board_diagnostics">OBD II</a> نام دارد که در خودروها بکار می‌رود. البته این پورت فقط برای کن نیست بلکه کاربرد اصلی آن استاندارد کردن نحوه دسترسی به اطلاعات فنی خودرو بوده است. چرا که خودروسازان مانند بسیاری شرکت‌های دیگر علاقه‌ی شدیدی به انحصاری کردن خدماتشان دارند. بنابراین هر یک برای دسترسی به اطلاعات کامپیوتر خودرو که برای تعمیر و نگهداری خودرو لازم است پروتکل‌های انحصاری خودشان را بکار می‌بردند و به تعمیرگاه‌های مستقل امکان دسترسی نمی‌دادند (مگر مثلا با اخذ مجوز و خرید دستگاه‌های لازم از خودشان). ODB II پاسخ قانونگذاران در آمریکا و اروپا به این وضع بود. از سال ۱۹۹۶ در آمریکا و از سال ۲۰۰۱ در اروپا خودروسازان مجبورند یک پورت ODB II با شکل فیزیکی و پیام‌های تعریف شده در استاندارد در خودرو تعبیه کنند. از این طریق تعمیرکاران مستقل و حتی مصرف‌کنندگان می‌توانند به اطلاعات پایه‌ی خودرو دسترسی پیدا کنند بدون اینکه تولید کننده بتواند مانع آنها بشود و درخواست وجه بکند. این پورت طبق استاندارد باید در فاصله‌ی ۶۱ سانتی‌متری فرمان باشد. اگر به زیر فرمان خودروهای ساخت خارج نگاهی بیندازید حتما این پورت را پیدا می‌کنید:</p>

<p class="center"><img src="assets/pimg/1024px-OBD_002.jpg" alt="" />
<em>By M.M.Minderhoud - Own work, Female OBD-II connector on a car, CC BY-SA 4.0, vie Wikimedia Commons</em></p>

<p>طبق استاندارد دو پین شماره‌ی ۶ و ۱۴ برای کن در نظر گرفته شده است که به رنگ سبز در تصویر زیر مشخص است:</p>

<p class="center"><img src="assets/pimg/OBD-II_type_A_female_connector_pinout.svg.png" alt="" />
*Xoneca - Own work, CC0, via Wikimedia Commons *</p>

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

<p class="center"><img src="assets/pimg/canbus_obd1.jpg" alt="" />
<em>آداپتور OBD II بلوتوث من</em></p>

<p class="center"><img src="assets/pimg/canbus_obd2.jpg" alt="" />
<em>آداپتور OBD II بلوتوث من</em></p>

<h2 id="آماده‌سازی-سخت‌افزار-کن-در-لینوکس"><a href="#آماده‌سازی-سخت‌افزار-کن-در-لینوکس">آماده‌سازی سخت‌افزار کن در لینوکس</a></h2>
<p>در ادامه شرح می‌دهم که چطور می‌توان روی لینوکس با کن کار کرد. همانطور که در ابتدا دیدیم نودها می‌توانند با کن‌باس ارتباط برقرار کنند و پیام دریافت و ارسال بکنند. دستگاه لینوکسی ما هم باید به باس وصل و تبدیل به یک نود بشود تا بتوانیم پیام‌ها را دریافت و ارسال بکنیم. برای اینکار در درجه اول نیاز به سخت‌افزار کن داریم. در بازار آداپتورهای کن به USB فراوانی وجود دارد که معمولا مبتنی به تراشه‌های ارزان میکروچیپ هستند. مثل ترنسیور MCP2551 و کنترلر MCP2515. من دو نمونه آداپتور از سایت <a href="https://canable.io/">canable.io</a> تهیه کرده‌ام که در زیر می‌بینید:</p>

<p class="center"><img src="assets/pimg/canbus_can_adaptor.jpg" alt="" />
<em>CANable Pro &amp; CANable</em></p>

<p>تفاوت مهم نسخه‌ی بزرگتر با نسخه کوچکتر در ایزولاسیون است که از لپ‌تاپ من در صورت اتصالی یا مانند اینها حفاظت می‌کند. به جز این هر دو شبیه هستند، در یک سو پورت میکرو یو‌اس‌بی است که با یک کابل به کامپیوتر وصل می‌شود و در صوی دیگر ترمینال پیجی برای سیم‌های CAN High و CAN Low و در صورت نیاز گراوند قرار گرفته. یک جامپر هم روی هر یک تعبیه شده که مقاومت ۱۲۰ اهمی را فعال و غیرفعال می‌کند. در مورد نحوه‌ی بکارگیری گراوند من نمی‌توانم راهنمایی مفیدی بکنم چرا که از حوزه‌ی تخصص من خارج است. یک مهندس الکترونیک می‌تواند اهمیت آن را بهتر شرح بدهد فقط اضافه کنم که اتصال اشتباه گراوند/زمین می‌تواند منجر خرابی باس بشود و گیرنده هیچ پیامی دریافت نمی‌کند و معمولا نیازی به اتصال آن نیست.</p>

<p>دو روش رایج برای کار با کن در لینوکس عبارت است از <a href="https://python-can.readthedocs.io/en/master/interfaces/slcan.html">slcan</a> و <a href="https://www.kernel.org/doc/html/latest/networking/can.html">socketcan</a>. هر دو درایور در تنه‌ی اصلی کرنل قرار دارند و بنابراین بدون نصب هیچ گونه نرم‌افزار اضافی در دسترس قرار دارد. هرچند پیش از استفاده باید مطمئن شد که ماژولهای مورد نظر لود شده‌اند:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo modprobe can
$ sudo modprobe slcan #for slcan
</code></pre></div></div>

<p>در ادامه من فقط به شرح کار با socketcan می‌پردازم.</p>

<h2 id="کار-با-socketcan-در-لینوکس"><a href="#کار-با-socketcan-در-لینوکس">کار با SocketCAN در لینوکس</a></h2>
<p>سوکت‌کن از ‌Berkly sockets استفاده می‌کند که همان سوکت یونیکس است که کل اینترنت روی آن بنا شده است. یعنی مثل رابط شبکه رفتار می‌کند. این به معنای اینست که تمام ابزارهای رایج لینوکس مانند دستور ip می‌توانند با آداپتور کن ارتباط برقرار کنند. برای این منظور یک رابط نرم‌افزاری CAN-to-USB هم نیاز است. آداپتورهایی که من دارم از درایور slcan و gs_usb (هردو به لینوکس اضافه شده‌اند) پشتیبانی می‌کنند. من نسخه‌ای بنام <a href="https://github.com/normaldotcom/candleLight_fw">CandleLight</a> را فلش کرده‌ام که به کمک آن آداپتور من بی‌واسطه توسط کرنل به عنوان یک سخت‌افزار شبکه مبتنی بر SocketCAN  شناخته می‌شود. ناگفته پیداست که اینکه یک سخت‌افزار چگونه خود را به سیستم عامل معرفی کند وابسته به firmware ایست که روی آن فلش شده است.</p>

<p>با اتصال آداپتور به کامپیوترم کرنل براحتی آن را تشخیص می‌دهد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo dmesg -w
[21050.404363] usb 3-2.2: new full-speed USB device number 11 using xhci_hcd
[21050.509412] usb 3-2.2: New USB device found, idVendor=1d50, idProduct=606f, bcdDevice= 0.00
[21050.509421] usb 3-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[21050.509424] usb 3-2.2: Product: canable gs_usb
[21050.509426] usb 3-2.2: Manufacturer: canable.io
[21050.509428] usb 3-2.2: SerialNumber: 00238008574D430820333735
[21050.510049] gs_usb 3-2.2:1.0: Configuring for 1 interfaces
</code></pre></div></div>
<p>شش خط اول از درایور یو‌اس‌بی است و خط آخر از درایور gs_usb که اینترفیس را ایجاد می‌کند. با دستور ip می‌توانیم سخت‌افزارهای واقعی و مجازی شبکه شناخته شده توسط کرنل لینوکس را ببینیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ip link
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp4s0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 04:92:26:da:0a:6b brd ff:ff:ff:ff:ff:ff
3: can0: &lt;NOARP,ECHO&gt; mtu 16 qdisc noop state DOWN mode DEFAULT group default qlen 10
    link/can
</code></pre></div></div>
<p>اولی دیوایس لوپ‌بک است که لینوکس می‌تواند به کمک آن با خودش روی یک شبکه مجازی حرف بزند. دومی کارت اترنت من است و سومی آداپتور کن ماست.</p>

<h2 id="ساخت-یک-کن‌باس-با-دو-نود"><a href="#ساخت-یک-کن‌باس-با-دو-نود">ساخت یک کن‌باس با دو نود</a></h2>
<p>قبل از اینکه ببینیم چطور می‌شود پیام از کن‌باس بخوانیم و به آن ارسال کنیم بیایید یک باس واقعی بسازیم.</p>

<p>برای اینکار من هر دو آداپتورم را بکار می‌گیرم. جامپرهای ۱۲۰ اهم را در هر دو سو فعال می‌کنم و با دو کابل CAN High  را به CAN High و CAN Low را به CAN Low وصل می‌کنم:</p>

<p class="center"><img src="assets/pimg/canbus.jpg" alt="" />
<em>ساخت کن باس با دو آداپتور کن به یو‌اس‌بی</em></p>

<p class="center"><img src="assets/pimg/canbus_closeup.jpg" alt="" />
<em>به نحوه‌ی اتصال سیم‌ها توجه کنید (جامپرهای مقاومت هم بسته است ولی در عکس پیدا نیست)</em></p>

<p>حالا هر دو آنها را به دو پورت یو‌اس‌بی متصل می‌کنم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo dmesg -w
[24221.741438] usb 3-2.1: new full-speed USB device number 19 using xhci_hcd
[24221.842849] usb 3-2.1: New USB device found, idVendor=1d50, idProduct=606f, bcdDevice= 0.00
[24221.842857] usb 3-2.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[24221.842860] usb 3-2.1: Product: canable gs_usb
[24221.842863] usb 3-2.1: Manufacturer: canable.io
[24221.842865] usb 3-2.1: SerialNumber: 00238008574D430820333735
[24221.843491] gs_usb 3-2.1:1.0: Configuring for 1 interfaces
[24224.554745] usb 3-2.2: new full-speed USB device number 20 using xhci_hcd
[24224.659402] usb 3-2.2: New USB device found, idVendor=1d50, idProduct=606f, bcdDevice= 0.00
[24224.659407] usb 3-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[24224.659408] usb 3-2.2: Product: canable gs_usb
[24224.659410] usb 3-2.2: Manufacturer: canable.io
[24224.659410] usb 3-2.2: SerialNumber: 00330023574D430820333735
[24224.659961] gs_usb 3-2.2:1.0: Configuring for 1 interfaces
</code></pre></div></div>
<p>هر دو آداپتور به لیست سخت‌افزارهای شبکه اضافه شده:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ip link
1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp4s0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 04:92:26:da:0a:6b brd ff:ff:ff:ff:ff:ff
3: can0: &lt;NOARP,ECHO&gt; mtu 16 qdisc noop state DOWN mode DEFAULT group default qlen 10
    link/can 
4: can1: &lt;NOARP,ECHO&gt; mtu 16 qdisc noop state DOWN mode DEFAULT group default qlen 10
    link/can 
</code></pre></div></div>

<p>برای اینکه از یک اینترفیس سوکت‌کن بتوان استفاده کرد باید آن را تنظیم کرد و بالا آورد. فعلا هر دو قطعه پایین هستند (DOWN). با دستور ip آنها را بالا می‌آوریم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo ip link set can0 up type can bitrate 500000
$ sudo ip link set can1 up type can bitrate 500000
$ ip link
...
3: can0: &lt;NOARP,UP,LOWER_UP,ECHO&gt; mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
    link/can 
4: can1: &lt;NOARP,UP,LOWER_UP,ECHO&gt; mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
    link/can 
</code></pre></div></div>
<p>می‌بینیم که هر دو UP شده‌اند. از جایی که هر کن‌باس یک bitrate یکسان دارد باید مقدار آن را هنگام بالا آوردن آداپتور بدهیم. من پانصد کیلوبیت را انتخاب کردم که رقم رایجی است. اگر فلگ <a href="https://www.kernel.org/doc/html/latest/networking/statistics.html"><code dir="ltr" class="language-plaintext highlighter-rouge">-statistics</code></a> را به دستور ip بدهیم اطلاعات بیشتری می‌بینیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ip -statistics link show can0
3: can0: &lt;NOARP,UP,LOWER_UP,ECHO&gt; mtu 16 qdisc pfifo_fast state UP mode DEFAULT group default qlen 10
    link/can 
    RX:  bytes packets errors dropped  missed   mcast           
             0       0      0       0       0       0 
    TX:  bytes packets errors dropped carrier collsns           
             0       0      0       0       0       0 
</code></pre></div></div>

<p>حالا شبکه‌ی ما آماده است و می‌توانیم برویم سروقت ارسال و دریافت پیام. برای اینکار به ابزارهای موجود در <a href="https://github.com/linux-can/can-utils">can-utils</a> نیاز خواهیم داشت. پروژه‌ی can-utils حاوی ابزارهای userspace برای SocketCAN است. این پروژه در برخی دیستروها پکیج شده است و در سایرین باید زحمت نصب آن را کشید که از حوصله‌ی این مقاله خارج است. ما از دو ابزار موجود در این پروژه استفاده می‌کنیم: candump و cansend. اولی برای خواندن پیام‌های باس و دیگری برای ارسال پیام روی باس. دو ابزار دیگر هم که برای تمرین خوب است یکی cangen است که پیام‌های رندوم می‌سازد و به باس ارسال می‌کند و دیگری canplayer که می‌تواند پیام‌های ضبط شده با candump را دوباره ارسال کند.</p>

<p>حالا که نرم‌افزار لازم را هم داریم لحظه‌ی امتحان نهایی فرا رسیده است! بیایید پیامی از نود صفر به باس ارسال کنیم و آن را در نود شماره‌ی یک بخوانیم. اول در یک ترمینال candump را باز می‌کنیم و در ترمینال دیگر cansend را اجرا می‌کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ candump can1
  can1  1FF   [0] 

...
$ cansend can0 1FF#
</code></pre></div></div>
<p>در اسکرین‌کست کوتاه زیر می‌توانید پروسه را ببینید. مقدار قبل از # آدرس فریم یا CAN ID است و مقدار بعد از # داده است (که من خالی گذاشتم، تا هشت کاراکتر HEX می‌توان داده پاس داد یعنی FFFFFFFF). توجه کنید که من یکبار با فرمت کوتاه و یکبار دیگر با فرمت بلند CAN ID دلبخواهی می‌سازم و فریم را ارسال می‌کنم.</p>

<video controls="">
  <source src="/assets/pimg/canbus_send.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>در زیر هم استفاده از cangen برای ساخت فریم‌های تصادفی را می‌توانید ببینید. باز هم توجه کنید که یکبار فریم‌ها را با فرمت کوتاه (CAN2.0A) و یکبار با فرمت بلند (توسعه‌یافته CAN2.0B) ارسال می‌کنم.</p>

<video controls="">
  <source src="/assets/pimg/canbus_cangen.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>ابزارهای موجود در پروژه‌ی can-utils بسیار ساده و سریع و مفید هستند. یکی از قابلیت‌های مجبوب من ضبط پیام‌های یک باس به کمک candump (<code dir="ltr" class="language-plaintext highlighter-rouge">candump -l</code>) و پخش آن با canplayer (<code dir="ltr" class="language-plaintext highlighter-rouge">cat dump.log | canplyer can0=can0</code>) روی یک باس مجازی هنگام برنامه‌نویسی یا بررسی یک مشکل است. اما شاید بپرسید مگر بدون آداپتور هم می‌شود کن‌باس را امتحان کرد؟ در جهان نرم‌افزار آزاد پاسخ اغلب این پرسش‌ها «آری» است! (بد نیست بدانید که شرکت‌های تولیدکننده دستگاه‌های صنعتی اغلب برای بررسی اشکال یک Logger (دستگاهی مشابه آداپتور که پیام‌ها را روی یک کارت حافظه ضبط می‌کند) به مشتری ارسال می‌کنند تا پیام‌ها را ضبط کند و فایل آن را برای بررسی توسط مهندسان ارسال کند.)</p>

<h2 id="کن‌باس-مجازی"><a href="#کن‌باس-مجازی">کن‌باس مجازی</a></h2>
<p>برای امتحان کن‌باس و پخش لاگ فایل‌های ضبط شده بدون دسترسی به یک آداپتور می‌توان از ماژول <a href="https://www.kernel.org/doc/html/latest/networking/can.html?highlight=vcan#the-virtual-can-driver-vcan">vcan</a> لینوکس استفاده کرد.  ابتدا باید از لود بودن ماژول vcan مطمئن شد و بعد به کمک دستور ip می‌توان یک اینترفیس مجازی از نوع vcan ساخت:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo modprobe vcan
$ sudo ip link add type vcan
</code></pre></div></div>
<p>در اسکرین‌کست مختصر زیر یک اینترفیس مجازی کن می‌سازم و آن را فعال می‌کنم و پیام‌های رندوم روی آن ارسال می‌کنم.</p>

<video controls="">
  <source src="/assets/pimg/canbus_vcan.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<h2 id="پارس-کردن-پیام‌ها"><a href="#پارس-کردن-پیام‌ها">پارس کردن پیام‌ها</a></h2>
<p>آخرین موضوعی که به طور خلاصه به آن می‌پردازیم پارس کردن پیام‌هاست. ابزارهای پروژه‌ی can-utils تنها با فریم‌های خام کار می‌کنند. برای دیکد کردن این اطلاعات به ابزارهای سطح بالاتری نیاز است. آنچه در صنایع و دنیای برنامه‌نویسی توکار رایج است ذخیره‌ی فرمت داده‌ها و ماتریس پیام‌های ارسالی و نیز آدرس‌های آنها در فایل‌هایی با فرمت‌های مختلف از جمله <a href="http://socialledge.com/sjsu/index.php/DBC_Format">DBC</a> است. (فرمت <a href="https://github.com/julietkilo/kcd">KCD</a> یک فرمت آزاد است که استفاده نکرده‌ام). استاندارد خاصی در این حوزه وجود ندارد و به طور سنتی تولیدکننده‌های آداپتورها هر یک طبق وزن خودشان در دنیای صنعت فرمت‌های خودشان را ساخته‌اند که اغلب هم انحصاری هستند. از جایی که کمتر تولید‌کننده‌ای ابزارهای آزاد منتشر می‌کند پروژه‌های مختلفی برای دیکد کردن لاگ‌فایل‌ها و نیز فایل‌ها تعریف فرمت فریم‌ها بوجود آمده است. دوپروژه‌ی خوبی که در این حوزه از آن بسیار بهره برده‌ام یکی <a href="https://github.com/hardbyte/python-can">python-can</a> و دیگری <a href="https://github.com/cantools/cantools">cantools</a> است. اولی می‌تواند با آداپتورهای مختلف ارتباط برقرار کند و دومی هم امکان دیکد کردن داده‌ها با استفاده از فرمت DBC و دیگر فرمت‌ها فراهم می‌کند. یکی از ویژگی‌های جالب پروژه‌ی cantools آن امکان دیکد کردن زنده‌ی پیام‌های ارسالی روی باس است که هنگام بررسی و رفع اشکال توسط تیم‌های پشتیبانی یا برنامه‌نویسان بسیار مفید است. من در اینجا به تکرار آنچه روی سایت پروژه آمده است نمی‌پردازم چرا که مثال‌های مختلف روی ریپازیتوری <a href="https://github.com/cantools/cantools">cantools</a> به تفصیل شرح داده شده است.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:a">
      <p>Computer Area Network <a href="#fnref:a" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:c">
      <p>CAN Transceiver <a href="#fnref:c" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
    <li id="fn:d">
      <p>CAN Controller <a href="#fnref:d" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>
</div>]]>
    </content>
    <summary>در این نوشته به طور خلاصه با کَن‌باس CAN bus۱ آشنا می‌شویم و یاد می‌گیریم چطور با آن کار کنیم. طبق معمول ابزارهای بکار رفته همه آزاد هستند. کن‌باس یک باس یا گذرگاه داده‌ی بسیار ساده و مقاوم و ارزان است که برای ساده‌سازی سیم‌کشی درون خودروها و ارتباط اجزاء مختلف با کنترلرها و کامپیوترهای خودرو در سال ۱۹۸۶ توسط شرکت بوش آلمان به خودروسازان جهان معرفی شده است. مستندات فنی نسخه‌ی ۲ آن به سال ۱۹۹۱ را می‌توانید در این آدرس بخوانید. بعدها در سال ۱۹۹۳ مشخصات فنی کن‌باس به استاندارد ایزو شماره‌ی ۱۱۸۹۸ تبدیل شد. بدون وجود یک...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:e53d270e-99cd-4edd-b784-912029b3c4b6</id>
    
    <title>راهنمای مختصر فونت‌فورج</title>
    <updated>2022-04-10T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/fontforge.html"/>
    <category term="فونت"/><category term="طراحی"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>به درخواست عرفان راهنمای ویدیویی کوچکی در مورد کار با فونت فورج ساختم که می‌توانید در ادامه تماشا کنید. از این گذشته تغییرات بسیاری در فونت نقطه داده‌ام که در آخرین نسخه بتا می‌توانید به آن دسترسی داشته باشید. علاوه بر اینها در وبسایت هم فونت نقطه را اضافه کرده‌ام که آن را هم می‌توانید دانلود کنید.</p>

<div style="font-family: noqte;font-size: 96px;" class="center">
نقطه
</div>

<div style="font-family: noqte;font-size: 32px;" class="center">
غلام همت آنم که زیر چرخ کبود
<br />
ز هرچه رنگ تعلق پذیرد آزاد است
</div>
<p><br />
شرح ویدیوها هم به این گونه است که به کمک فونت‌فورج یک فونت ساده حاوی دو کاراکتر «الف» و «ب» می‌سازیم و آن را در سیستم عامل اضافه می‌کنم و در برنامه‌ی لیبره‌آفیس برای تایپ کلمات «بابا» و «مادر» بکار می‌گیریم.</p>

<p>متاسفانه فرصتی برای ادیت نداشتم و ویدیوها خام هستند. ویدیو اول معرفی است تا جایی که دوستی زنگ زد و مجبور شدم کار را متوقف کنم. ویدیو دوم ادامه ماجرا تا انتهاست. به دلیلی نامعلوم هم در ضبط صدا یک تاخیر ۷۰۰ میلی‌ثانیه‌ای وجود دارد که زحمت بکشید موقع پخش خودتان اصلاح کنید.</p>

<p>ویدیوی اول حاوی معرفی و مقدمات</p>
<video controls="">
  <source src="https://mehdix.org/~mx/fontforge/2022-04-10-fontforge-p1.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>این هم ویدیوی دوم تا انتهای مطلب</p>

<video controls="">
  <source src="https://mehdix.org/~mx/fontforge/2022-04-10-fontforge-p2.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>آپدیت: شرمنده به جهت کم‌تجربگی سمت راست مانیتور در کادر نیفتاده. خوشبختانه اصل ماجرا قابل استفاده است بجز لیبره‌افیس که در انتها در پنجره دیده نمی‌شه که خروج را اسکرین‌شات گرفتم در زیر قابل دیدن است.</p>

<p><img src="assets/pimg/fontforge_baba.png" alt="" /></p>

<p>زنده باشید</p>
</div>]]>
    </content>
    <summary>به درخواست عرفان راهنمای ویدیویی کوچکی در مورد کار با فونت فورج ساختم که می‌توانید در ادامه تماشا کنید. از این گذشته تغییرات بسیاری در فونت نقطه داده‌ام که در آخرین نسخه بتا می‌توانید به آن دسترسی داشته باشید. علاوه بر اینها در وبسایت هم فونت نقطه را اضافه کرده‌ام که آن را هم می‌توانید دانلود کنید. نقطه غلام همت آنم که زیر چرخ کبود ز هرچه رنگ تعلق پذیرد آزاد است شرح ویدیوها هم به این گونه است که به کمک فونت‌فورج یک فونت ساده حاوی دو کاراکتر «الف» و «ب» می‌سازیم و آن را در سیستم عامل اضافه...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:30cd7244-f691-45df-a773-7c1344c4337d</id>
    
    <title>انتشار فونت نقطه</title>
    <updated>2022-03-22T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/noqte.html"/>
    <category term="بازی"/><category term="تفریح"/><category term="طراحی"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>طی هفته گذشته تقریبا شبانه‌روز از بیخ و بن مشغول ساختن یک پیکسل‌فونت جدید و آزاد فارسی بوده‌ام. امروز اصل کار تقریبا تمام شده است. نام این قلم را «نقطه» گذاشته‌ام.</p>

<p><img src="assets/pimg/noqte.png" alt="" /></p>

<p>نقطه به اصطلاح یک پیکسل‌فونت است. یعنی تمام «گلیف‌های» درون فونت از اجزائی شبیه به پیکسل ساخته شده‌اند و بنابراین روی صفحه‌های نمایش قدیمی یا «رترو» بویژه برای بازی‌های دوبعدی برای کنسول‌ها به خوبی نمایش داده می‌شود.</p>

<h2 id="چرا-نقطه-را-ساختم"><a href="#چرا-نقطه-را-ساختم">چرا نقطه را ساختم؟</a></h2>
<p>معمولا جواب این پرسش این است: «چرا که نه؟» ولی شرح می‌دهم. مدتها پیش می‌خواستم یک صفحه‌ی خطای ۴۰۴ رترو برای وبسایتم بسازم و مدتی پیش هم حین ساختن یک بازی کوچک دوبعدی به جستجوی یک قلم رترو آزاد فارسی برآمدم. اصلا چیزی پیدا نکردم چه برسد به یک فونت آزاد. بنابراین تصمیم گرفتم یکی بسازم.</p>

<h2 id="اصول-طراحی-نقطه"><a href="#اصول-طراحی-نقطه">اصول طراحی نقطه</a></h2>
<p>ایده‌ی کلی‌ام این بود که مثل حروفچینی و تایپوگرافی سنتی ایرانی یک نقطه را بع عنوان مبدا انتخاب کنم و تمام گلیف‌ها را از روی آن و با کنار هم قرار دادن مربع‌ها بسازم. هرچند حین ساخت پی بردم به دلیل استفاده زیاد از منحنی در الفبای عربی و نیز اتصال گیلف‌ها از هر دو طرف این کار بسیار سخت است. بویژه هنگامی که اعراب وارد معادله می‌شود، چرا که طراحی آنها با مربع مرجع من به طول ۶۴ نقطه یک چالش جدی است. فعلا برای طراحی اعراب از یک مربع کوچکتر به طول ۳۲ نقطه استفاده کرده‌ام.</p>

<p>با مطالعه‌ی کتاب تایپوگرافی آقای فرشید مثقالی سعی کردم اصولی را در طراحی‌ام رعایت کنم. بویژه استفاده از کرسی‌های مشخص برای دندانه‌ها و نقطه‌ها و اعراب و مانند آن. از طرفی در طراحی گلیف‌ها هم تصمیماتی گرفته و سعی کردم در طراحی تمام گلیف‌ها آنها را به صورت یکپارچه راعایت کنم:</p>

<p>۱. ارتفاع تمام گلیف‌ها معمولا حداکثر ۷ بلاک است (هر بلاک ۶۴×۶۴ نقطه است)</p>

<p>۲. هر گلیف آغازی یک بلاک خالی سمت راست دارد</p>

<p>۳. هیچ گلیف میانی بلاک خالی دست راست ندارد</p>

<p>۴. هیچ گلیف بلاک خالی سمت چپ ندارد</p>

<p>۵. هر گلیف میانی  موظف است به مقدار کافی از سمت چپ جا رزرو کند (بخاطر قانون ۲)</p>

<p>یادآوری کنم که هر حرف به چهار حالت نیاز دارد: آغازی و میانی و پایانی و منزوی. یعنی چهار گلیف برای هر حرف که جمعا می‌شود ۱۳۳ گلیف فقط برای حروف الفبا بدون احتساب ارقام و نشانه‌ها.</p>

<h2 id="چطور-نقطه-را-ساختم"><a href="#چطور-نقطه-را-ساختم">چطور نقطه را ساختم؟</a></h2>
<p>برای ساخت نقطه از برنامه‌ی FontForge استفاده کردم. از جایی که می‌دانستم صابر راستی‌کردار تعداد زیادی قلم با آن طراحی کرده است متقاعد شدم که حتما کار من را هم راه می‌اندازد! <a href="http://rastikerdar.github.io/getting-started-with-fontforge/">راهنمای صابر</a> را هم برای شروع خواندم که سودمند بود بویژه شرح رفرنس‌ها. برای فهم طرز کار فونت‌فورج مرتب از <a href="http://designwithfontforge.com/en-US/index.html">کتاب فونت‌فورج</a> بهره گرفتم که بسیار سودمند بود. همچنین از یک <a href="https://github.com/pixeldroid/fonts/tree/master/console">فونت کنسول آزاد</a> ایده گرفتم. همینطور به کرات از <a href="https://fontforge.org/docs/index.html">مستندات فونت‌فورج</a> برای فهم عملکرد برنامه و دیالوگ‌های مختلف آن استفاده کردم. در طراحی هم به وفور از رفرنس‌ها استفاده کرده‌ام تا از تکرار مکررات پرهیز کنم.</p>

<h2 id="کدام-گلیف‌ها-را-پیاده‌سازی-کرده‌ام"><a href="#کدام-گلیف‌ها-را-پیاده‌سازی-کرده‌ام">کدام گلیف‌ها را پیاده‌سازی کرده‌ام؟</a></h2>
<p>بیشتر گلیف‌های لازم برای نمایش صحیح نوشتار فارسی و تا حدودی عربی و برخی از گلیف‌های اسکی را از میان چهار بلاک یونیکد زیر پیاده‌سازی کرده‌ام:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Arabic (0600–06FF)
Arabic Presentation Forms-A (FB50–FDFF)
Arabic Presentation Forms-B (FE70–FEFF)
Basic Latin (ASCII) - letters missing
</code></pre></div></div>

<p><img src="assets/pimg/glyphs.png" alt="" /></p>

<p>توجه کنید که در حال حاضر نقطه همچنان نیاز به بهینه‌سازی دارد و در وضعیت بتا است. اشکالاتی وجود دارد که باید برطرف کنم بویژه در اعراب و قرارگیری نقطه‌ها ولی برای استفاده اولیه مناسب است و در بازی کوچکی که دارم می‌سازم از آن استفاده کرده‌ام. سعی می‌کنم حروف لاتین را هم به آن اضافه کنم.</p>

<p><img src="assets/pimg/noqtegame.png" alt="" /></p>

<h2 id="کجاست-این-نقطه"><a href="#کجاست-این-نقطه">کجاست این نقطه؟</a></h2>
<p><a href="https://git.sr.ht/~mehdix/noqte">سورس نقطه</a> را روی سورس‌هات منتشر کرده‌ام. سورس تنها یک فایل است بنام <code dir="ltr" class="language-plaintext highlighter-rouge">noqte.sfd</code> که می‌توانید با سورس‌فورج باز کنید. <a href="https://git.sr.ht/~mehdix/noqte/refs/download/0.1.0-beta1/noqte.ttf">فایل ttf نقطه</a> هم از ریپازیتوری قابل دانلود است. اگر سورس‌فورس را نصب دارید (روی لینوکس و مانند آن) کافیست دستور <code dir="ltr" class="language-plaintext highlighter-rouge">make</code> را در فولدر نقطه وارید کنید تا فایل <code dir="ltr" class="language-plaintext highlighter-rouge">noqte.ttf</code> ساخته شود. روی لینوکس می‌توانید این فایل را در پوشه‌ی <code dir="ltr" class="language-plaintext highlighter-rouge">~/.fonts</code> کپی کنید و بعد با دستور <code dir="ltr" class="language-plaintext highlighter-rouge">fc-cache -v</code> کش سیستم را بروز کنید. بعد از آن باید بتوانید آن را در برنامه‌ها ببینید و بکار ببرید. نقطه تحت مجوز آزاد OFL منتشر شده است.</p>

<p>این هم عیدی امسال من به شما.</p>

<p>آپدیت ۲۱ فروردین: افزودن پانگرام با فونت نقطه (جمله‌ای که دربردگیرنده‌ی همه‌ی حروف باشد)</p>
<div style="font-family: noqte;font-size: 36px;">
در صورت حذف این چند واژه غلط به شکیل، ثابت و جامع‌تر ساختن پاراگراف شعر از لحاظ دوری از قافیه‌های اضافه کمک می‌شود.
</div>

</div>]]>
    </content>
    <summary>طی هفته گذشته تقریبا شبانه‌روز از بیخ و بن مشغول ساختن یک پیکسل‌فونت جدید و آزاد فارسی بوده‌ام. امروز اصل کار تقریبا تمام شده است. نام این قلم را «نقطه» گذاشته‌ام. نقطه به اصطلاح یک پیکسل‌فونت است. یعنی تمام «گلیف‌های» درون فونت از اجزائی شبیه به پیکسل ساخته شده‌اند و بنابراین روی صفحه‌های نمایش قدیمی یا «رترو» بویژه برای بازی‌های دوبعدی برای کنسول‌ها به خوبی نمایش داده می‌شود. چرا نقطه را ساختم؟ معمولا جواب این پرسش این است: «چرا که نه؟» ولی شرح می‌دهم. مدتها پیش می‌خواستم یک صفحه‌ی خطای ۴۰۴ رترو برای وبسایتم بسازم و مدتی پیش هم حین...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:855ea93b-7af5-4b23-b949-ed398fb9f7d7</id>
    
    <title>راهنمای کوچک GNU Make</title>
    <updated>2021-12-11T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/makefile.html"/>
    <category term="make"/><category term="اتوماسیون"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>از زمانی که <a href="upcoming-changes.html">تصمیم به ساده‌سازی</a> گرفته‌ام چند ابزار خیلی به کارم آمده است. یکی از آنها <a href="https://www.gnu.org/software/make/">GNU Make</a> است که در ادامه شرح می‌دهم.</p>

<p>کم و بیش طبق شرح وبسایت خودش:</p>

<p>GNU Make ابزاری است که تولید خروجی‌های اجرایی و غیراجرایی از سورس‌های یک برنامه را کنترل می‌کند.</p>

<p>اگر سورس برنامه‌ای را دانلود و کامپایل کرده باشید احتمالا به دستوراتی مانند <code dir="ltr" class="language-plaintext highlighter-rouge">make</code> و <code dir="ltr" class="language-plaintext highlighter-rouge">make install</code> برخورد کرده‌اید. لازمه‌ی کار کردن این دستورات هم وجود فایلی بنام <code dir="ltr" class="language-plaintext highlighter-rouge">Makefile</code> در فولدر مربوطه است.</p>

<p>در حقیقت Make ابزار ساده ایست که می‌تواند دستوراتی که ما تعریف می‌کنیم اجرا کند. ما به هر گروه از دستورات یک نام اختصاص می‌دهیم و Make آنها را اجرا می‌کند و از خودش چیزی ندارد، حتی دستور <code dir="ltr" class="language-plaintext highlighter-rouge">install</code> فقط یک نام سنتی است و باید توسط برنامه‌ساز تعریف شود.</p>

<p>برای استفاده از Make باید تعدادی «قانون» یا Rule داخل فایلی بنام Makefile نوشت. دقت کنید که تورفتگی‌های داخل این فایل حتما باید با TAB باشد. ساختار این فایل اینگونه است:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Rule No 1
target: dependencies ...
	commands
	...
</code></pre></div></div>

<p>هر قانون Make از سه بخش تشکیل شده است:</p>

<ul>
  <li>نام فایل خروجی یا همان target</li>
  <li>نام فایل‌های مبداء یا همان dependencyها</li>
  <li>دستوراتی برای تولید فایل خروجی از روی فایل‌های مبداء</li>
</ul>

<p>هر Makefile هم می‌تواند تعداد دلخواهی قانون داشته باشد. وقتی در کامندلاین دستور <code dir="ltr" class="language-plaintext highlighter-rouge">make</code> را وارد می‌کنیم اولین قانون داخل فایل اجرا می‌شود، فارغ از نام target. از طرفی هم می‌توان اسم یک قانون را وارد کرد مثلا <code dir="ltr" class="language-plaintext highlighter-rouge">make install</code>، یعنی اجرای قانون <code dir="ltr" class="language-plaintext highlighter-rouge">install</code>.</p>

<p>فرض کنید یک فایل C بنام <code dir="ltr" class="language-plaintext highlighter-rouge">dorood.c</code> را می‌خواهیم کامپایل کنیم:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
		<span class="n">puts</span><span class="p">(</span><span class="s">"Hello World!"</span><span class="p">);</span>
		<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>می‌توانیم Makefile زیر را برای برنامه‌مان بنویسیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dorood: dorood.c
	gcc -o dorood dorood.c
</code></pre></div></div>

<p>حالا اگر در کامندلاین <code dir="ltr" class="language-plaintext highlighter-rouge">make</code> یا <code dir="ltr" class="language-plaintext highlighter-rouge">make dorood</code> وارد کنیم این دستورات اجرا می‌شوند:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ make
gcc -o dorood dorood.c
</code></pre></div></div>

<p>اما اگر دوباره <code dir="ltr" class="language-plaintext highlighter-rouge">make</code> وارد کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ make
make: 'dorood' is up to date.
</code></pre></div></div>

<p>چه اتفاقی افتاد؟ Make از کجا فهمید که دستور اجرا شده؟ روش کار ساده است. بار اول فایل خروجی بنام <code dir="ltr" class="language-plaintext highlighter-rouge">dorood</code> وجود نداشت پس Make دستور را اجرا کرد. بار دوم اما این فایل ساخته شده بود بنابراین نیازی به اجرای دوباره‌ی دستور نبود.</p>

<p>حالا بگذارید فایل <code dir="ltr" class="language-plaintext highlighter-rouge">dorood.c</code> را تغییر بدهیم و دوباره Make را اجرا کنیم. من اینکار را با تغییر آخرین زمان تغییر این فایل به کمک دستور <code dir="ltr" class="language-plaintext highlighter-rouge">touch</code> انجام می‌دهم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ touch dorood.c
$ make
gcc -o dorood dorood.c
</code></pre></div></div>

<p>اینبار چه شد؟ Make تاریخ آخرین تغییر خروجی را با ورودی‌ها مقایسه می‌کند. اگر خروجی جدیدتر باشد یعنی همه چیز روبراه است. اگر خروجی قدیمی‌تر از هر یک از وابستگی‌ها باشد یعنی باید دوباره ساخته شود. به این ترتیب Make در وقت کامپایل صرفه‌جویی می‌کند.</p>

<p>همه دستورات هم نیاز نیست مروبط به کامپایل باشند. ما می‌توانیم قوانین “phony” داشته باشیم، یعنی «الکی». بیایید یک قانون <code dir="ltr" class="language-plaintext highlighter-rouge">clean</code> اضافه کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.PHONY: clean

dorood: dorood.c
	gcc -o dorood dorood.c

clean:
	rm dorood
</code></pre></div></div>

<p>دستورات «الکی» لزومی ندارد سورس‌کد بخوانند و خروجی بسازند. یعنی Make دنبال فایل ورودی و خروجی برای آنها نمی‌گردد و اگر دستور بدهیم همیشه اجرا می‌شوند. مثلا برای پاک کردن خروجی‌ها دستور زیر کافیست:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ make clean
rm dorood
</code></pre></div></div>

<p>قوانین Make را می‌توان به یکدیگر زنجیر کرد. مثلا فرض کنید ما می‌خواهیم فایل بالا را در دو مرحله تولید کنیم. اول سورس را کامپیال می‌کنیم به object file و بعد آن را لینک می‌کنیم و خروجی اجرایی را می‌سازیم. برای این منظور یک قانون جدید نیاز داریم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.PHONY: clean

dorood: dorood.o
	gcc -o dorood dorood.o

dorood.o: dorood.c
	gcc -c dorood.c

clean:
	rm dorood dorood.o
</code></pre></div></div>

<p>و حالا اجرا:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ make clean
rm dorood dorood.o

$ make
gcc -c dorood.c
gcc -o dorood dorood.o
</code></pre></div></div>

<p>به صورت سنتی Make برای کامپایل سورس‌کد استفاده شده است، هرچند من از Make در هر پروژه برای تجمیع دستورات پراکنده‌ای استفاده می‌کنم که معمولا باید در هیستوری ترمینالم به دنبال آنها بگردم. مثلا بیایید نگاهی به Makefile ساخت وبسایتم بیندازیم:</p>

<pre><code class="language-Makefile">DBPATH=mehdix.db
all: build
.PHONY: init serve publish clean

init: init_db
	bundle config set path vendor/bundle
	bundle install
	pip install -r scripts/requirements.txt

build: comments
	bundle exec jekyll build

comments:
	@echo rebuilding alef comments
	python scripts/rebuild_comments.py

serve: build
	bundle exec jekyll serve

publish: build
	rsync -vr _site/* mehdix.ir:/var/www/mehdix.ir/

clean:
	rm -rf _site
	rm -rf **/.jekyll-cache

init_db: scripts/schema.sql
	sqlite3 ${DBPATH} &lt; scripts/schema.sql
</code></pre>

<p>مجال شرح این دستورات نیست، ولی تمام اینها را در دوران پیش از Make در حافظه‌ی ترمینالم جستجو می‌کردم و گاهی فراموش می‌کردم. حالا در ابتدای ساخت هر پروژه همواره یک Makefile می‌سازم که مثل یک اسفنج عمل می‌کند و تمام دستورات ریز و درشتی که به آن پروژه مربوط است را به تدریج به خودش جذب می‌کند.</p>

<p>امیدورام مفید فایده شده باشد.</p>

</div>]]>
    </content>
    <summary>از زمانی که تصمیم به ساده‌سازی گرفته‌ام چند ابزار خیلی به کارم آمده است. یکی از آنها GNU Make است که در ادامه شرح می‌دهم. کم و بیش طبق شرح وبسایت خودش: GNU Make ابزاری است که تولید خروجی‌های اجرایی و غیراجرایی از سورس‌های یک برنامه را کنترل می‌کند. اگر سورس برنامه‌ای را دانلود و کامپایل کرده باشید احتمالا به دستوراتی مانند make و make install برخورد کرده‌اید. لازمه‌ی کار کردن این دستورات هم وجود فایلی بنام Makefile در فولدر مربوطه است. در حقیقت Make ابزار ساده ایست که می‌تواند دستوراتی که ما تعریف می‌کنیم اجرا کند. ما به هر...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:9a62bed3-73df-4687-a2bf-6d911059596b</id>
    
    <title>بازگشت کامنت‌دونی</title>
    <updated>2021-12-05T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/cgi-comments.html"/>
    <category term="کامنت‌دونی"/><category term="cgi"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>یادتان باشد روز اول خرداد ۱۴۰۰ غزل خداحافظی نتلیفای را خواندیم. از آن روز کامنت‌دونی تعطیل بود. حالا کامنتدونی با قدرت تمام به صحنه برگشته!</p>

<h2 id="کامنت‌دونی-دیروز"><a href="#کامنت‌دونی-دیروز">کامنت‌دونی دیروز</a></h2>
<p>با انتقال وبسایت از سرورهای دیگران به سرور خودم بخش نیمه خودکار و نیمه داینامیک وبسایتم یعنی کامنت‌دونی از کار افتاد چرا که پیش از این از سرویس‌های سرویس‌دهنده‌ی قبلی برای ثبت فرم HTML کامنت و بیلد سایت استفاده کرده بودم. حالا این بخش را خودم نوشته‌ام و دوباره راه‌انداخته‌ام که جلوتر شرح می‌دهم.</p>

<h2 id="کامنت‌دونی-امروز"><a href="#کامنت‌دونی-امروز">کامنت‌دونی امروز</a></h2>
<p>برای راه‌اندازی نسخه‌ی جدید یک اسکریپت ساده‌ی <a href="https://datatracker.ietf.org/doc/html/rfc3875">CGI</a> با Bash نوشته‌ام و آنرا به کمک وب سرور nginx برای اجرا آماده کرده‌ام. CGI یک روش نسبتا قدیمی اما ساده برای تولید خروجی توسط برنامه‌های موجود روی سرور است.</p>

<p>یک سرور وب وقتی یک درخواست HTTP دریافت می‌کند نگاه می‌کند که آیا آن آدرس یک فایل مثلا <code dir="ltr" class="language-plaintext highlighter-rouge">index.html</code> است یا اینکه باید توسط یک برنامه تولید بشود. اگر درخواست برای یک فایل باشد، وب سرور آن فایل را از دیسک می‌خواند و به براوزر ما تحویل می‌دهد. براوزر هم آن را نمایش می‌دهد. تمام صفحات این وبسایت فایل‌هایی روی هارددیسک سرور من هستند و مستقیما خوانده شده و به درخواست‌کننده تحویل داده می‌شود.</p>

<p>اما اگر درخواست برای یک فایل نباشد و یک درخواست داینامیک باشد، وب سرور درخواست را یک پراسس دیگر ارجاع می‌کند و پاسخ آن پراسس را در نهایت به براوزر ما تحویل می‌دهد. این وبسایت تنها یک عدد آدرس داینامیک دارد که آنهم به عنوان آدرس فرم HTML کامنتدونی تنظیم شده است. (اگر Ctrl + U را بگیرید می‌توانید در سورس وبسایت فرم را ببینید.)</p>

<p>برای ارتباط بین سرور وب و پراسس‌های دیگر (مثل پایتون یا PHP و مانند اینها) که به درخواست‌های داینامیک رسیدگی می‌کنند پروتکل‌های مختلفی وجود دارد. CGI یکی از این پروتکل‌هاست.</p>

<h2 id="cgi"><a href="#cgi">CGI</a></h2>
<p>اما CGI چگونه کار می‌کند؟ برای فهم روش کار باید بدانیم ورودی و خروجی‌های یک پراسس در لینوکس و سیستم‌های یونیکسی چگونه است. وقتی سیستم عامل یک پراسس می‌سازد برای آن سه نوع ورودی و خروجی تعریف می‌کند. برنامه می‌تواند از ورودی بخواند و در خروجی‌ها بنویسد. به ترتیب زیر:</p>

<ol>
  <li>Standard Input - ورودی استاندارد</li>
  <li>Standard Output - خروجی استاندارد</li>
  <li>Standard Error - خروجی خطا</li>
</ol>

<p>مثلا وقتی ما در یک ترمینال مشغول کار با شل هستیم (مثلا Bash یا Zsh) و فرامین مختلف را اجرا می‌کنیم، ترمینال می‌تواند در ورودی استاندارد ابزارهای مختلف بنویسید و یا خروجی‌های آنها را بخواند. مثلا دستور ساده‌ی <code dir="ltr" class="language-plaintext highlighter-rouge">ls</code> که لیستی از یک مسیری در سیستم فایل کامپیوتر به ما نشان می‌دهد چطور کار می‌کند؟ ترمینال فرمان را اجرا می‌کند و <code dir="ltr" class="language-plaintext highlighter-rouge">ls</code> هم نتیجه را در خروجی استاندارد می‌نویسد و ترمینال این خروجی استاندارد را روی صفحه چاپ می‌کند. اگر خطایی تولید شود ترمینال همین کار را برای خروجی خطا انجام می‌دهد. برای استفاده موثر از ترمینال باید این مفاهیم و نحوه‌ی کنترل آنها را بلد بود. مثلا به کمک اوپراتور کنترلی <code dir="ltr" class="language-plaintext highlighter-rouge">|</code> می‌توان در شل لوله‌کشی کرد! یعنی استاندارد یا خطای یک دستور را به ورودی بعدی وصل کرد و الی آخر. بحث مفصلی است که از حوصله‌ی این مقاله خارج است.</p>

<p>حالا CGI هم از همین موضوع استفاده می‌کند. یعنی ما سرور را طوری تنظیم می‌کنیم که درخواست‌هایی که به آدرس خاصی ارسال می‌شود را تحویل بدهد به اسکریپ/برنامه‌ی ما و خروجی استاندارد برنامه‌ی ما را به عنوان نتیجه به بازدیدکننده تحویل بدهد.</p>

<p>اگر درخواست HTTP POST باشد، سرور وب پارامترهای فرم ما را یا به عبارتی همان Query String را در ورودی استاندارد برنامه می‌نویسد و برنامه باید آن را از آنها بردارد و پردازش بکند. این بسته به هر زبان فرق می‌کند. اگر درخواست HTTP GET باشد، سرور وب Query String را در یک متغیر محیطی بنام QUERY_STRING می‌نویسد و برنامه می‌تواند آن را بخواند و استفاده کند. سایر اطلاعات نیز در متغیرهای محیطی (Environment Variables) نوشته می‌شوند و برنامه می‌تواند از آنها استفاده کند. مثلا اگر شما برای این مقاله دیدگاهی بنویسید در خروجی آدرس IP خودتان و نیز <code dir="ltr" class="language-plaintext highlighter-rouge">USER_AGENT</code> ارسالی از مرورگرتان را خواهید دید (جواب معما را در فرم غلط بدهید و فرم را سابمیت کنید خودتان می‌بینید). هر دو اینها از متغیرهای محیطی ارسالی از سرور وب خوانده می‌شوند که آن هم به نوبه‌ی خود از درخواست شبکه‌ای که به دست آن رسیده است استخراج می‌شود.</p>

<h2 id="تنیظم-nginx-و-fcgiwrap"><a href="#تنیظم-nginx-و-fcgiwrap">تنیظم nginx و fcgiwrap</a></h2>
<p>با nginx نمی‌شود مستقیم یک اسکریپت را اجرا کرد بلکه باید از FastCGI استفاده کرد. علت هم اینست که در CGI اولیه سرور وب می‌بایست برای هر درخواست وب یک پراسس بسازد و بعد از اجرا آن را نابود کند. این کار هزینه‌بر است و منابع سرور را هدر می‌دهد هر چند برای سایت‌هایی با ترافیک پایین این موضوع اهمیت چندانی ندارد (مگر اینکه به سایت حمله بشود). با FastCGI تعدادی پراسس در پشت صحنه همیشه گوش به زنگ می‌ایستند و وقتی درخواستی آمد یکی از آنها فورا به آن رسیدگی می‌کند. اما از جایی که من یک اسکرپیت Bash نوشته‌ام خبری از این قرطی‌بازی‌ها نیست! برای اینکه اسکریپت‌هایی مثل اسکرپیت ما را بشود با nginx اجرا کرد برنامه‌نویسی چیزی نوشته بنام <a href="https://github.com/gnosek/fcgiwrap/">fcgiwrap</a> که به nginx امکان اجرای اسکریپت‌های مستقل را می‌دهد.</p>

<p>تنظیم بلاک cgi در nginx روی سرور اوبونتو خیلی ساده است و زیر آمده است:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>location /cgi-bin/ {
        gzip off;
        fastcgi_pass  unix:/run/fcgiwrap.socket;
        include /etc/nginx/fastcgi_params;
        fastcgi_param   ALEF_DB "آدرس فایل بانک داده";
        fastcgi_param   ALEF_PUZZLE     "جواب معما";
        fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
}
</code></pre></div></div>

<p>این بلاک به nginx می‌گوید که درخواست‌هایی که زیر آدرس <code dir="ltr" class="language-plaintext highlighter-rouge">/cgi_bin/</code> قرار می‌گیرند را بدهد به سوکت fcgiwrap. دو متغیر محیطی اضافه هم من به آن داده‌ام که یکی جواب معما است و دیگری آدرس بانک داده. بله یک بانک داده هم داریم…</p>

<h2 id="sqlite3"><a href="#sqlite3">sqlite3</a></h2>
<p>بالاخره داده‌ها را باید جایی نوشت. یا در سرور دیگری یا در سرور خودت. اسکریپت ما برای ثبت دیدگاه‌ها از پایگاه داده‌ی بسیار ساده‌ اما قدرتمند <a href="https://www.sqlite.org/">sqlite3</a> استفاده می‌کند. این پایگاه داده از فرط سادگی نیازی به runtime ندارد. یعنی نیازی نیست که برنامه‌ای در حال اجرا باشد تا بتوان از آن استفاده کرد. تا حجم عظیمی داده را هم می‌تواند در خودش ذخیره کند. مادامی که ما به محدودیت‌هایش احترام بگذاریم، یعنی سعی نکنیم همزمان از چند جای مختلف در پایگاه داده چیزی بنویسیم. البته اسکریپت ما هنوز جلوی اینکار را نمی‌گیرد (انصافا احتمالش خیلی کم است). با اضافه کردن یک Lock مثلا Semaphore یا حتی یک فایل موقتی می‌شود آن مشکل را رفع کرد. می‌گذاریمش برای بعد.</p>

<p>ما یک جدول ساده لازم داریم که می‌سازیم و همزمان به خورد برنامه‌ی sqlite3 می‌دهیم (همه اینها در Makefile هست):</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cat</span> <span class="o">&lt;&lt;</span><span class="n">EOF</span> <span class="o">|</span> <span class="n">sqlite3</span> <span class="nv">"$ALEF_DB"</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">IF</span> <span class="k">NOT</span> <span class="k">EXISTS</span> <span class="n">comments</span> <span class="p">(</span>
<span class="c1">-- A unique ID for each comment</span>
<span class="n">id</span> <span class="nb">INTEGER</span> <span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="n">AUTOINCREMENT</span><span class="p">,</span>
<span class="c1">-- ISO8601 strings with UTC/zulu timezone, try date --iso-8601=seconds --utc</span>
<span class="nb">time</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="c1">-- Comment author's name</span>
<span class="n">name</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="c1">-- Comment author's email</span>
<span class="n">email</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="c1">-- The page where the comment belongs to</span>
<span class="n">page_id</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="c1">-- The ID of a parent comment</span>
<span class="n">reply_to</span> <span class="nb">TEXT</span><span class="p">,</span>
<span class="c1">-- Some URL</span>
<span class="n">website</span> <span class="nb">TEXT</span><span class="p">,</span>
<span class="c1">-- Whether this is a spam (wrong puzzle answer)</span>
<span class="n">spam</span> <span class="nb">INTEGER</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span>
<span class="c1">-- The body of the comment</span>
<span class="n">message</span> <span class="nb">TEXT</span> <span class="k">NOT</span> <span class="k">NULL</span>
<span class="p">);</span>
<span class="n">EOF</span>
</code></pre></div></div>

<p>به این روش خوراندن یک متن چند خطی به یک برنامه می‌گویند <a href="https://linuxize.com/post/bash-heredoc/">heredocs</a>. (از طریق ورودی استاندارد! بعله!) همانطور که می‌بینید تعدادی فیلد داریم که برای ثبت یک دیدگاه ضروری است.</p>

<p>اگر به اسکریپت <a href="https://raw.githubusercontent.com/mehdisadeghi/mehdix.ir/master/src/cgi-bin/submit">submit</a> هم نظری بیفکنیم می‌بینیم که کارهای زیر را در Bash انجام می‌دهد:</p>

<ol>
  <li>بیت executable ست شده است و فایل یک <a href="https://en.wikipedia.org/wiki/Shebang_(Unix)">Shebang</a> هم دارد که می‌گوید که با Bash اجرا بشود</li>
  <li>بلافاصله بعد از اجرا HTTP Code و Content-Type را می‌نویسد در خروجی (چون حروف فارسی داریم!)</li>
  <li>بلافاصله یک trap ست می‌کند، یعنی این کار را در هر صورت در آخرین لحظه پیش از خروج انجام بده</li>
  <li>ورودی استاندارد را می‌خواند و می‌ریزد در POST_STRING (چون فرم ما POST است)</li>
  <li>یک تابع داریم که URL <a href="https://en.wikipedia.org/wiki/Percent-encoding">Percend-encoding</a> را دیکد می‌کند</li>
  <li>پارامترها را از هم باز می‌کنیم (چون با <code dir="ltr" class="language-plaintext highlighter-rouge">&amp;</code> از هم جدا شده‌اند)</li>
  <li>چک می‌کنیم که فیلدهای ضروری وجود داشته باشد اگر ناقص بود درجا خطا و خروج</li>
  <li>جواب معما را چک می‌کنیم اگر غلط بود درجا خطا و خروج</li>
  <li>اگر متغیر محیطی آدرس فایل پایگاه داده هست کوئری ساخت جدول را ارسال می‌کنیم</li>
  <li>یک رکورد در جدول می‌نویسیم</li>
  <li>پیام خروج را می‌نویسیم</li>
  <li>یک ایمیل هم به وبلاگ‌صاحاب ارسال می‌کنیم (از قبل در سرور آماده است)</li>
</ol>

<p>این اسکریپت نکات زیادی دارد که هر کدام مقاله‌ای برای خودش می‌طلبد. فقط بگویم که هرچه <code dir="ltr" class="language-plaintext highlighter-rouge">echo</code> می‌کنیم در خروجی استاندارد نوشته می‌شود و درنهایت به کاربر ارسال می‌شود و آنچه <code dir="ltr" class="language-plaintext highlighter-rouge">echo</code> شده اما یک <code dir="ltr" class="language-plaintext highlighter-rouge">&gt;&amp;2</code> در آخر خط دارد در خروجی خطا نوشته می‌شود و به بازدیدکننده ارسال نمی‌شود (بلکه در لاگ‌های سرور نوشته می‌شود که بنده می‌روم می‌خوانم :)).</p>

<p>این اسکرپیت کاستی زیاد دارد. مثلا چک نمی‌کند که پیام تکراری است یا اسپم را بررسی نمی‌کند (بجز اینکه جواب معما درست باشد) و حتی ممکن است نقطه ضعف امنیتی داشته باشد. هرچند کاربر اجرا کننده‌ی این اسکریپت روی سرور به همین منظور کاربر محدودی است. ولی کار را انجام می‌دهد.</p>

<h2 id="ختم-کلام"><a href="#ختم-کلام">ختم کلام</a></h2>
<p>خلاصه با این مقدمه‌ی طولانی خواستم بگویم که کامنت‌دونی برگشته است و از نظرات شما استقبال می‌کند! من بخش نظرات وبسایت را محلی برای تعامل جمیع خوانندگان و خودم در نظرم می‌گیرم نه محلی برای دیالوگ فقط بین نویسنده و خواننده. بنابراین اگر جوابی برای سوال دیگری داشتید بنویسید و از سوال هم نهراسید!</p>

</div>]]>
    </content>
    <summary>یادتان باشد روز اول خرداد ۱۴۰۰ غزل خداحافظی نتلیفای را خواندیم. از آن روز کامنت‌دونی تعطیل بود. حالا کامنتدونی با قدرت تمام به صحنه برگشته! کامنت‌دونی دیروز با انتقال وبسایت از سرورهای دیگران به سرور خودم بخش نیمه خودکار و نیمه داینامیک وبسایتم یعنی کامنت‌دونی از کار افتاد چرا که پیش از این از سرویس‌های سرویس‌دهنده‌ی قبلی برای ثبت فرم HTML کامنت و بیلد سایت استفاده کرده بودم. حالا این بخش را خودم نوشته‌ام و دوباره راه‌انداخته‌ام که جلوتر شرح می‌دهم. کامنت‌دونی امروز برای راه‌اندازی نسخه‌ی جدید یک اسکریپت ساده‌ی CGI با Bash نوشته‌ام و آنرا به کمک وب سرور...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:893db180-375a-11ec-a99f-5f8505a0170f</id>
    
    <title>راهنمای کوچک روت اندروید</title>
    <updated>2021-11-05T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/galaxys8.html"/>
    <category term="اندروید"/><category term="روت"/><category term="adb"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>من یک گوشی گلکسی ۸ سامسونگ دارم که از ژانویه ۲۰۲۰ آپدیت نشده است و حداقل برای رفع باگ‌های امنیتی که در این فاصله ترمیم شده‌اند وقت خانه‌تکانی‌اش رسیده است. در ادامه آن را بروز و روت می‌کنیم و F-Droid و برنامه‌های بانکی و سایر چیزهای مفید و آزاد را هم روی آن نصب می‌کنیم.</p>

<p>علت آپدیت نبودن اینست که گوشی من روت است و بنابراین آپدیت‌های OTA را دریافت نمی‌کند. البته آپدیت خاصی هم دیگر براش وجود ندارد چرا که آخرین آپدیت حاوی پچ امنیتی سامسونگ برایش در آوریل ۲۰۲۱ بوده است که به همان نسخه ارتقا می‌دهیم. در این مقاله گوشی را آپدیت و دوباره روت می‌کنم. بعد هم تنظیمات معمول شامل سینک را هم انجام می‌دهم و اپ‌ها را هم معرفی و شرح می‌دهم.</p>

<p>فقط بخاطر داشته باشید که همه‌ی این پیچیدگی‌ها که در ادامه خواهیم دید به خاطر سیستمی است که می‌خواهد به کمک قفل‌های سخت‌افزاری و Secure Boot و غیره دست‌های کاربر را ببندد و قدرت را در دست تولیدکننده‌های غول‌پیکری مثل سامسونگ و گوگل و مانند اینها نگاه دارد. به همین خاطر من از پروژه‌های آزادی مانند <a href="https://wiki.pine64.org/index.php/PinePhone">PinePhone</a> حمایت می‌کنم و در آینده سویچ می‌کنم (امروز هم سالهاست که از دیگر از سرویس‌های سامسونگ و گوگل و مانند آنها استفاده نمی‌کنم و اکثر نیازهام با <a href="https://f-droid.org/">F-Droid</a> و Syncthing و Decsync <a href="decsync.html">برآورده می‌شود</a>).</p>

<blockquote>
  <p>هشدار: در ادامه معمولا اطلاعات روی گوشی کامل پاک می‌شود.</p>
</blockquote>

<p>در طول مقاله از برنامه‌های اوپن سورس و آزاد مختلفی استفاده می‌کنیم که شرح خواهم داد. سیستم عامل هم آرچ‌ لینوکس است و شل هم bash. پیش از هرچیز باید Android Debug Bridge یا همان adb را نصب داشت که من پیشتر نصب کرده‌ام. <code dir="ltr" class="language-plaintext highlighter-rouge">adb devices</code> هم باید گوشی را وقتی با کابل USB به دستگاه وصل است نشان بدهد. برای اینکار باید USB Debugging در تنظیمات برنام‌نویس یا Developer Options گوشی فعال باشد. خود Developer Option هم وقتی ظاهر می‌شود که در تنظیمات اندروید روی Build Number چند بار پشت سر هم کلیک کنید. بعد از اینکار و بعد با اتصال کابل USB و اجرای adb یک پنجره روی گوشی ظاهر می‌شود و می‌پرسد که آیا به این کامپیوتر اعتماد می‌کنیم یا نه. با اعتماد به کامپیوتر می‌توانیم ادامه بدهیم. (در اسکرین‌شات‌ها می‌توانید این مراحل را ببینید، زبان گوشی آلمانی است ولی به نظرم واضح است که منظور چیست.)</p>

<p class="center post-image-float"><img src="assets/s8/s8debug.jpg" alt="" /></p>

<p class="center post-image-float"><img src="assets/s8/s8devopts.jpg" alt="" /></p>

<h2 id="بک‌آپ"><a href="#بک‌آپ">بک‌آپ!</a></h2>
<p>تا حالا کسی را دیده‌اید که افسوس بخورد چرا از عکس‌ها و پیغام‌هایش بک‌آپ گرفته است؟ من که ندیده‌ام. اما برعکسش را زیاد دیده‌ام. پس اول به هر روشی که بلد هستید اطلاعات ارزشمند خود را از گوشی بیرون بکشید. من برنامه‌های مهم را جداگانه و بعد اس‌دی کارت را با adb روی کامپیوترم کپی کردم.</p>

<h3 id="بک‌آپ-با-adb"><a href="#بک‌آپ-با-adb">بک‌آپ با adb</a></h3>
<p>به چند روش می‌شود بک‌آپ گرفت، یکی به کمک adb است:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ adb pull sdcard
</code></pre></div></div>

<p>به کمک adb همچنین می‌توان اپ‌ها و داده‌هایشان را کپی کرد البته بجز اپ‌هایی که نمی‌خواهند داده‌هایشان بک‌آپ گرفته شود (مثل سیگنال). برخی اپ‌ها هم حتی اگر با روت از آنها بزور بک‌اپ گرفته شود و روی یک گوشی جدید بازگردانده بشود باز هم کار نخواهند کرد، چرا که کلیدهای سری آنها درون سی‌پی‌یو نگهداری می‌شود و قابل بک‌آپ گرفت نیست (باز هم مثل سیگنال).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ for APP in $(adb shell pm list packages -3 -f); do adb pull $( echo ${APP} | sed "s/^package://" | sed "s/base.apk=/base.apk /").apk; done این دستور اول لیست پکیج‌ها را از گوشی می‌گیرد و بعد یکی یکی آنها را داخل یک حلقه دانلود می‌کند.
</code></pre></div></div>

<p>می‌شود یکجا هم بک‌آپ گرفت و بعد اکسپورت کرد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ adb backup -f backup.adb -all -apk -nosystem
$ dd if=backup.adb bs=24 skip=1 | zlib-flate -uncompress | tar xf -
</code></pre></div></div>

<p>ظاهرا بک‌آپ کلی adb فرمت خاصی دارد که به طریق بالا می‌توان آن را باز کرد. جزئیاتش زیاد مهم نیست. مهم اینست که از این طریق بسیاری برنامه‌ها بک‌آپ گرفته نمی‌شوند و باید برنامه‌های مهم را یا از خود برنامه یا از طریق اپ‌های دیگر بک‌آپ گرفت. شرح بیشتر در <a href="https://gist.github.com/AnatomicJC/e773dd55ae60ab0b2d6dd2351eb977c1">این جیست گیتهاب</a>.</p>

<p>من از <a href="https://github.com/machiav3lli/oandbackupx">oandbackupx</a> استفاده کردم و برنامه‌ها را روی کارت‌حافظه بک‌آپ گرفتم.</p>

<h3 id="بک‌آپ-با-smart-switch"><a href="#بک‌آپ-با-smart-switch">بک‌آپ با Smart Switch</a></h3>
<p>به کمک اپ Smart Switch سامسونگ هم می‌توان از بسیاری چیزها مخصوصا تنظیمات دسکتاپ و هیستوری تماس‌ها و این قبیل چیزها روی کارت حافظه بک‌آپ گرفت. روی اکانت سامسونگ هم می‌شود که من با این اپ استفاده نکردم. کافیست یک کارت حافظه اضافی یا یک فلش‌دیسک به گوشی وصل بکنید و در صفحه‌ی اصلی برنامه عکس کارت‌حافظه را لمس کنید. ادامه‌ی کار آسان است. برنامه به من خطای نبود حافظه‌ی کافی می‌داد که دسته آخر معلوم شد بخاطر کارت‌حافظه بود که بعد از فرمت کردن آن مشکل رفع شد.</p>

<h3 id="بک‌آپ-با-oandbackupx"><a href="#بک‌آپ-با-oandbackupx">بک‌آپ با oandbackupx</a></h3>
<p>من با برنامه‌ی <a href="https://github.com/machiav3lli/oandbackupx">oandbackupx</a> به کمک روت از همه‌ی اپ‌ها و داده‌هایشان بک‌آپ گرفته بودم. متاسفانه نتیجه بدردبخور نبود. از طرفی پسورد بک‌آپ را ظاهرا فراموش کرده بودم (یه اصلا برنامه درست کار نکرد) و از طرف دیگر برنامه با تعداد بالای اپ‌ها مشکل جدی دارد. رابط کاربری هم ضعیف است، مثلا من به اشتباه اپ‌های سیستم را بازگردانی کردم که منجر به خراب شدن تنظیمات و بلوتوث گوشی شد و برنامه هم هیچ هشداری نداد (مجبور شدم پارتیشن سیستم را مجددا فلش بکنم). توصیه می‌کنم به این برنامه تکیه نکنید یا حتما بک‌آپ را تست بکنید.</p>

<h3 id="بک‌آپ-جداگانه-اپ-به-اپ"><a href="#بک‌آپ-جداگانه-اپ-به-اپ">بک‌آپ جداگانه اپ به اپ</a></h3>
<p>از برخی اپ‌های مهم هم می‌توان جدا جدا نسخه‌ی پشتیبان تهیه کرد. برای مثال:</p>
<ul>
  <li>سینگنال</li>
  <li>واتس‌آپ</li>
  <li>اپ K9</li>
  <li>والت‌های دیجیتال</li>
  <li>و بسیاری دیگر</li>
</ul>

<p>ناگفته پیداست که باید بک‌آپ را از گوشی به یک حافظه‌ی جانبی منتقل کرد (مثلا به کمک Syncthing) و آن را امتحان کرد.</p>

<blockquote>
  <p>بک‌آپی که تست نشده است همانند بک‌آپی است که اصلا وجود ندارد.</p>
</blockquote>

<p>با پشت سر گذاشتن مقدمات می‌رویم سروقت آپدیت.</p>

<h2 id="دانلود-آپدیت"><a href="#دانلود-آپدیت">دانلود آپدیت</a></h2>
<p>آخرین آپدیت سامسونگ برای گوشی من را می‌توان در اینترنت پیدا کرد ولی از همه بهتر دانلود مستقیم از سرورهای آپدیت خود سامسونگ است. برای اینکار از ابزار خوب <a href="https://github.com/nlscc/samloader">samloader</a> استفاده می‌کنیم.</p>

<p>برای استفاده از samloader باید مدل گوشی و کد CSC منطقه‌ی دلخواهمان را بدانیم. مدل رسمی گوشی من SM-G950F است. سامسونگ این گوشی را با دو چیپ مختلف تولید و عرضه کرده است: Snapdragon و Exynos. گوشی من Exynos است. کد CSC یعنی Country Specific Code. من کد آلمان را پیدا کردم که DBT است. در گوشی بخش تنظیمات نرم‌افزاری هم کد CSC گوشی قابل رؤیت است.</p>

<p>بعد از پیدا کردن اینها می‌توانیم چک کنیم چه آپدیتهایی برای این گوشی و این منطقه وجود دارد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ samloader -m SM-G950F -r DBT checkupdate
G950FXXUCDUD1/G950FOXMCDUD1/G950FXXUCDUD1/G950FXXUCDUD1
</code></pre></div></div>

<p>و حالا دانلود:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ samloader -m SM-G950F -r DBT download -v 'G950FXXUCDUD1/G950FOXMCDUD1/G950FXXUCDUD1/G950FXXUCDUD1' -O .
</code></pre></div></div>

<p>و بعد باز کردن قفل:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ samloader -m SM-G950F -r DBT decrypt -v 'G950FXXUCDUD1/G950FOXMCDUD1/G950FXXUCDUD1/G950FXXUCDUD1' -i SM-G950F_1_20210407122336_qro5zx59p1_fac.zip.enc4 -o SM-G950F_1_20210407122336_qro5zx59p1_fac.zip
</code></pre></div></div>

<p>و در نهایت بازکردن فایل زیپ:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ unzip SM-G950F_1_20210407122336_qro5zx59p1_fac.zip
$ ls
SM-G950F_1_20210407122336_qro5zx59p1_fac.zip.enc4
AP_G950FXXUCDUD1_CL21427293_QB39365966_REV00_user_low_ship_meta_OS9.tar.md5
BL_G950FXXUCDUD1_CL21427293_QB39365966_REV00_user_low_ship.tar.md5
CP_G950FXXUCDUD1_CP18734711_CL21427293_QB39365966_REV00_user_low_ship.tar.md5
CSC_OXM_G950FOXMCDUD1_CL21427293_QB39365966_REV00_user_low_ship.tar.md5
HOME_CSC_OXM_G950FOXMCDUD1_CL21427293_QB39365966_REV00_user_low_ship.tar.md5
SM-G950F_1_20210407122336_qro5zx59p1_fac.zip
</code></pre></div></div>

<p>این فایل‌هایی پارتیشن‌های مختلفی هستند که ما در ادامه روی گوشی فلش می‌کنیم. البته بد نیست بدانیم که می‌شود این <a href="http://muzso.hu/2012/08/10/how-to-pack-and-unpack-system.img-and-userdata.img-from-an-android-factory-image">فایل‌ها را باز کرد</a> و محتوای آنها را تغییر داد که البته در این مورد امتحان نکرده‌ام (ممکن است بوت نشود).</p>

<h2 id="فلش"><a href="#فلش">فلش</a></h2>
<p>گوشی را با کابل USB به کامپیوتر متصل می‌کنیم و می‌رویم سروقت فلش.</p>

<h3 id="مقدمات-فلش"><a href="#مقدمات-فلش">مقدمات فلش</a></h3>
<p>برای اینکه بتوان یک گوشی اندرویدی را فلش کرد باید قفل bootloader را باز کرد. برای اینکار باید از منوی تنظیمات برنامه‌نویس گزینه OEM Unlocking را فعال کرد. در برخی گوشی‌ها این گزینه وجود ندارد که باید در اینترنت گشت فهمید چرا.</p>

<p class="center post-image-float"><img src="assets/s8/oemunlocking.jpg" alt="" /></p>

<p>در مورد گوشی گلکسی ۸ برایم جالب بود که این گزینه وقتی گوشی را برای اولین بار روشن می‌کنید غیرفعال است تا زمانی که به وایفای وصل بشویم که بعد از اتصال با سرور سامسونگ و احتمالا بررسی اینکه گوشی به صورت آنلاک فروخته شده است باز می‌شود. این واقعا جای تاسف است که یک گوشی که در زمان خودش گرانقیمت محسوب می‌شد هنوز هم در چنگال تولید‌کننده است و نشان از اهمیت پروژه‌هایی مثل Pinephone دارد که در تلاشند یک گوشی با سخت‌افزار و نرم‌افزار آزاد در اختیار ما بگذارند (دقیقا به همین خاطر و برای پشتیبانی از پروژه‌های Pine64 مدتهاتس که یک گوشی Pinephone سفارش داده‌ام که اگر اجل امانم دهد درباره‌اش می‌نویسم).</p>

<h3 id="ابزار-فلش"><a href="#ابزار-فلش">ابزار فلش</a></h3>
<p>برای فلش کردن گوشی‌های اندرویدی اغلب از برنامه‌ی Odin استفاده می‌شود. این برنامه آزاد و همگانی نیست بلکه از سامسونگ نشت کرده است. من برای فلش کردن از ابزار آزاد <a href="https://glassechidna.com.au/heimdall/">Heimdall</a> استفاده می‌کنم که برای گوشی‌های گلکسی نوشته شده است. این برنامه نسخه‌ی گرافیکی هم دارد ولی برای کار ما فقط نسخه‌ی ترمینال کفایت می‌کند. (نسخه‌ی گرافیکی heimdall-frontend نام دارد و به فایل pit که پایین‌تر دانلود خواهیم کرد برای فلش کردن نیاز دارد.)</p>

<h3 id="download-mode"><a href="#download-mode">Download Mode</a></h3>
<p>در مرحله‌ی بعدی باید گوشی را وارد Download Mode کرد. توضیح مختصر اینکه گوشی‌های اندرویدی دو وضعیت Recovery و Fastboot دارند. Recovery مثل یک سیستم عامل کوچک است (یک پارتیشن مجزا هم برای خودش دارد) که می‌توان از آن برای بک آپ گرفتن و نصب آپدیت و آپگرید و نصب ROM یا فرمت پارتیشن‌ها و این قبیل کارها استفاده کرده. Fastboot هم برای ظاهرا برای فلش کردن مستقیم پارتیشن‌ها و حتی تغییر پارتیشن‌بندی است. اما گوشی‌های سامسونگ بجای Fastboot چیزی به نام Download mode دارند که برای فلش کردن گوشی است. به چند طریق می‌توان وارد دانلود مود شد. اگر گوشی قبلا برای adb تنظیم شده (شرح آن پیشتر رفت) می‌توان فرمان زیر را بکار برد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ adb reboot download
</code></pre></div></div>

<video controls="">
  <source src="/assets/s8/dlmode.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>راه دیگر هم روشن کردن گوشی است با فشار همزان کلیدهای Volume Down + Bixby + Power. ممکن است موقع شروع گوشی برای ورود تاییدیه بخواهد که فشردن کلید Volume Up است.</p>

<video controls="">
  <source src="/assets/s8/dlmodeadb.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<h3 id="heimdall"><a href="#heimdall">Heimdall</a></h3>
<p>حالا که مقدمات را پشت سر گذاشتیم و از سیر تا پیاز گوشی هم بک‌آپ گرفته‌ایم (آن درد کشیده‌ها می‌فهمند چرا!) وقت فلش کردن است. اول چک می‌کنیم که گوشی در دسترس است یا نه:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ heimdall detect
Device detected
</code></pre></div></div>

<p>برای اطمینان از جدول پارتیشن‌های گوشی هم یک بک‌اپ می‌گیرم، یکبار به صورت باینری و یکبار متنی:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ heimdall download-pit --output sm-g950f.pit --no-reboot
Heimdall v1.4.2

Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
http://www.glassechidna.com.au/

This software is provided free of charge. Copying and redistribution is
encouraged.

If you appreciate this software and you would like to support future
development please consider donating:
http://www.glassechidna.com.au/donate/

Initialising connection...
Detecting device...
Claiming interface...
Setting up interface...

Initialising protocol...
Protocol initialisation successful.

Beginning session...

Some devices may take up to 2 minutes to respond.
Please be patient!

Session begun.

Downloading device's PIT file...
PIT file download successful.

Ending session...
Releasing device interface...

$ heimdall print-pit --no-reboot &gt; sm-g950f_text.pit
</code></pre></div></div>
<p>حسن بک‌اپ دوم (متنی) اینست که داخل آن می‌شود اسم پارتیشن‌ها و نام معمول فایل آنها را که برای فلش با heimdall لازم است پیدا کرد.</p>

<p>بسته‌ای که قبلا دانلود کردیم حاوی تعدادی ایمیج است شامل:‌ AP و BL و CP و CSC_OXM و HOME_CSC_OXM. فرق CSC_OXM و HOME_CSC_OXM هم در این است که دومی را اگر فلش کنیم اندروید بعد از نصب فایل‌های داخل کارت حافظه‌ی داخلی‌اش را پاک نمی‌کند. ‬‏<a href="https://www.droidviews.com/difference-between-csc-and-home_csc-samsung-firmware/">در جایی</a> هم خواندم که آنها که پسوند OXM دارند Multi-CSC خوانده می‌شوند و کد کشور را از سیم‌کارت می‌گیرند.</p>

<p>برای فلش کردن با Heimdall بر خلاف Odin باید همه‌ی این فایل‌ها را باز کرد و پارتیشن‌ها را یک به یک فلش کرد. پس ما فایل‌های بالا را به همراه HOME_CSC_OXM به یک فولدر جدید کپی و باز می‌کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ for i in $(ls *.tar.md5); do tar xvf "$i"; done
$ for i in $(ls *.lz4); do unlz4 "$i"; done
$ rm *.tar.md5 *.lz4
$ ls
meta-data  cm.bin  modem.bin  modem_debug.bin  param.bin  sboot.bin  up_param.bin  boot.img  cache.img  recovery.img  system.img  userdata.img
</code></pre></div></div>
<p>حالا که فایل‌ها را داریم وقت فلش کردن است. اسم پارتیشن‌ها را از فایل <code dir="ltr" class="language-plaintext highlighter-rouge">sm-g950f_text.pit</code> استخراج می‌کنیم و فرمان زیر را اجرا می‌کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ heimdall flash --CM cm.bin --PARAM param.bin --UP_PARAM up_param.bin --BOOT boot.img --CACHE cache.img --SYSTEM system.img --USERDATA userdata.img
</code></pre></div></div>
<p>می‌شد فرمان زیر را هم اجرا کرد ولی من نخواستم همه‌ی پارتیشن‌ها را جایگزین کنم تا از مشکلات احتمالی جلوگیری کنم. تصمیم گرفتم اگر فرمان قبلی کار نکرد همه را فلش کنم که البته مشکلی پیش نیامد.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ heimdall flash --CM cm.bin --RADIO modem.bin --CP_DEBUG modem_debug.bin --PARAM param.bin --BOOTLOADER sboot.bin --UP_PARAM up_param.bin --BOOT boot.img --CACHE cache.img --RECOVERY recovery.img --SYSTEM system.img --USERDATA userdata.img
</code></pre></div></div>
<p>گوشی را ریبوت کردم و خوشبختانه بی درسر بود شد. البته اول وارد ریکاوری شد که ریستارت کردم. انتظار داشتم که کارت حافظه‌ی داخلی پاک نشده باشد که شده بود. بهرحال آپدیت درست انجام شد.</p>

<video controls="">
  <source src="/assets/s8/flashing.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>پی‌نوشت برای این بخش:‌ البته که عشق آسان نمود اول ولی افتاد مشکل‌ها! بعد از فلش متوجه شدم که سایز کارت‌حافظه از ۶۴ به ۱۶ کاهش پیدا کرده که احتمالا به خاطر اشتباه بودن سایز ایمیج HOME_CSC_OXM بود. با فلش ایمیج داخل CSC_OXM این مشکل رفع شد. مشکلات دیگری هم در میانه‌ی کار پیش‌آمد که باعث شد <a href="https://wiki.lineageos.org/devices/a5y17lte/install">LineageOS</a> روی گوشی بریزم که خیلی خوب کار کرد و برخلاف سیستم سامسونگ هیچ چیز بیهوده‌ای داخلش وجود ندارد (سامسونگ برنامه‌های خودش و گوگل و فیسبوک و خیلی‌های دیگر را پیش‌فرض نصب می‌کند که برای من فقط زحمت حذف آنها باقی می‌ماند). ولی فعلا آمادگی سویچ به یک محیط کاملا جدید را نداشتم چرا که با گرافیک گلکسی (One UI 1.0) فعلی خیلی راحتم و کارم راه می‌افتد. بنابراین با همان سامسونگ ادامه می‌دهیم (من همیشه اپ‌های اضافه را غیرفعال می‌کنم یا با برنامه‌های روت کاملا حذف می‌کنم).</p>

<p>تا اینجا گوشی آپدیت شده و در حال تنظیمات کارخانه است. از جایی که همه چیز ریست شده است دوباره تنظمات برنامه‌نویس را که پیشتر دیدیم فعال می‌کنیم و بعد هم USB Debugging را و ورود به دانلود مود و درنهایت می‌رویسم سروقت روت کردن گوشی.</p>

<h2 id="روت"><a href="#روت">روت</a></h2>
<p>من گوشی را روت می‌کنم تا بتوانم نرم‌افزارهای زورکی سامسونگ و گوگل و مانند اینها را از رام گوشی حذف کنم. علاوه بر این می‌خواهم برنامه‌ی AdAway را نصب کنم تا درخواست‌هایی که به دامین‌های تبلیغاتی و ترکینگ و مانند اینها ارسال می‌شود از بیخ بلاک شوند. اینکار فقط با روت امکانپذیر است. از طرفی با روت گوشی نرم‌افزارهای بانکی از کار می‌افتند که در ادامه شرح می‌دهیم چطور آنها را دوباره فعال کنیم. هرچند بخاطر داشته باشید که روت گوشی کار خطرناکی است. هر برنامه‌ای که دسترسی روت داشته باشد می‌تواند همه‌ی سیستم را تغییر بدهد. گوشی من گارانتی ندارد و من هم از برنامه‌های روت استفاده‌ی چندانی جز آنچه گفتم نمی‌کنم و به برنامه‌های رندوم و ناشناخته هم هیچگونه دسترسی چه روت و غیر روت نمی‌دهم. (اصلا نصبشان نمی‌کنم!) بنابراین با مسئولیت خودتان ادامه بدهید . و البته به خاطر داشته باشید که با کمک امکانات سخت‌افزاری تعبیه شده در چیپ گوشی هر برنامه‌ای که اراده بکند می‌توان به کمک سرویس‌های گوگل از روت بودن گوشی مطلع بشود. منتها این را باید گوگل فعال بکند که تا به امروز اینکار را نکرده.</p>

<blockquote>
  <p>هر برنامه‌ای که دسترسی روت داشته باشد می‌تواند همه‌ی سیستم را تغییر بدهد.</p>
</blockquote>

<h3 id="نصب-ریکاوری"><a href="#نصب-ریکاوری">نصب ریکاوری</a></h3>
<p>برای روت گوشی نیاز است ریکاوری سامسونگ را با <a href="https://github.com/TeamWin/android_bootable_recovery">TWRP</a> جایگزین کنیم چرا که ریکاوری پیش‌فرض سامسونگ کار بدرد ما نمی‌خورد. اول باید ریکاوری مناسب گوشی را پیدا کرد. من از سایت twrp.me و بخش مخصوص گلکسی ۸ <a href="https://eu.dl.twrp.me/dreamlte/twrp-3.5.2_9-0-dreamlte.img">ریکاوری مخصوص گلکسی ۸</a> را دریافت کردم (این سایت متاسفانه پر از تبلیغات است، نصب ublock را فراموش نکنید). البته می‌شود <a href="https://github.com/coderbymistake/android_device_samsung_dreamlte">ریکاوری را بیلد کنیم</a> که کار پرزحمت اما مطمئن‌تری است. فکر می‌کنم بدون ریکاوری هم می‌شود به کمک adb در مود دانلود کرنل را عوض کرد و گوشی را روت کرد اما درست و حسابی امتحانش نکرده‌ام. در آنصورت اصلا نیازی به TWRP نخواهد بود.</p>

<p>نرم‌افزار پیش‌فرض سامسونگ اگر تشخیص بدهد که ریکاوری دیگری بجز سامسونگ نصب شده است آن را حذف می‌کند و ریکاوری خودش را جایگزین می‌کند. (بالا گفتم که این پدرسوخته‌بازی‌ها مال سیستم‌های بسته‌ای مثل این گوشی است که امیدوارم در آینده از شر آنها خلاص بشویم.) به همین خاطر نصب ریکاوری کمی دردسرساز است. با Heimdall باید ریکاوری را نصب کنیم ولی موقع ریبوت باید فورا کلیدهای Volume Up + Bixby + Power را همزمان فشار دهیم تا ریکاوری لود شود در غیر اینصورت بعد از سیستم آن را حذف می‌کند:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ adb reboot download
$ heimdall flash --no-reboot --RECOVERY ~/Downloads/twrp-3.5.2_9-0-dreamlte.img
Heimdall v1.4.2

Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
http://www.glassechidna.com.au/

This software is provided free of charge. Copying and redistribution is
encouraged.

If you appreciate this software and you would like to support future
development please consider donating:
http://www.glassechidna.com.au/donate/

Initialising connection...
Detecting device...
Claiming interface...
Setting up interface...

Initialising protocol...
Protocol initialisation successful.

Beginning session...

Some devices may take up to 2 minutes to respond.
Please be patient!

Session begun.

Downloading device's PIT file...
PIT file download successful.

Uploading RECOVERY
100%
RECOVERY upload successful

Ending session...
Releasing device interface...
</code></pre></div></div>

<video controls="">
  <source src="/assets/s8/modifytwrp.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>بعد از ریبوت مجدد به ریکاوری باید به TWRP اجازه‌ی تغییر سیستم را بدهیم تا جلوی حذف شدن خودش به دست سامسونگ را بگیرد. البته به همین سادگی نیست. (بار اول خودش می‌پرسد که اینکار را بکند یا نه) TWRP می‌تواند جلوی حذف شدن خودش را بگیرد اما برخی گوشی‌ها مثل این گوشی از <a href="https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html">dm-verify</a> استفاده می‌کنند که یک قابلیت از کرنل لینوکس است برای کشف دستکاری و تغییر در فایل‌سیستم. سامسونگ و دوستان از این فیچر برای کشف تغییر در پارتیشن‌های پیش‌فرض سیستم و حذف ریکاوری و مانند اینها استفاده می‌کنند، بله بر علیه ما کاربران! بنابراین ما مجبوریم بر علیه این ضدفیچر هم یک هک دیگر بکار ببریم و این کنترل را از کار بیندازیم. به این منظور باید یک پچ را دانلود و همزمان که به طور موقتی در ریکاوری هستیم آن را نصب کنیم. من پچ <a href="https://github.com/coderbymistake/Disable_Dm-Verity_ForceEncrypt">Disable_Dm-Verity_ForceEncrypt</a> را دانلود کردم (این لینک یک کپی است) کد آن را خواندم، چیز خطرناکی داخلش ندیدم. کافیست محتوای ریپازیتوری را زیپ کنیم (ساختار فایل‌ها مطابق یک بسته‌ی قابل فلش کردن اندرویدی است، بیشتر نمی‌دانم) و روی گوشی کپی کنیم. می‌شود از داخل ریپازیتوری فایل را کپی کرد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ adb push Disable_Dm-Verity_ForceEncrypt_quota_11.02.2020.zip /sdcard/
</code></pre></div></div>

<p>اسم فایل مهم است. اسکریپت درون این بسته از روی اسم فایل می‌فهمد چه چیزهایی را غیرفعال کند. بعد از کپی کافی است از منوی Install ریکاوری فایل را انتخاب و اعمال و بعد ریبوت کنیم.</p>

<p>پس‌نوشت: من بار اول که وارد ریکاوری شدم به TWRP اجازه دادم پارتیشن سیستم من را تغییر بدهد تا جلوی حذف خودش را بگیرد. بدون اپلای پچ بالا ریبوت کردم و گوشی داخل boot-loop گرفتار شد. با اپلای پچ مشکل رفع شد.</p>

<video controls="">
  <source src="/assets/s8/losgehts.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>

<p>حالا بالاخره می‌رویم سروقت روت کردن.</p>

<h3 id="magisk"><a href="#magisk">Magisk</a></h3>
<p>برای روت گوشی ما از <a href="https://github.com/topjohnwu/Magisk">Magisk</a> استفاده می‌کنیم که ایمج بوت گوشی را پچ می‌کند و بدون تغییر پارتیشن سیستم دسترسی روت برایمان فراهم می‌کند و امکان کور کردن اپ‌ها را می‌دهد تا از روت شدن گوشی مطلع نشوند. ماژول‌های مختلفی هم دارد برای اعمال تغییرات خاص روی گوشی که برای روت نیازی به آنها نیست.</p>

<p>آخرین نسخه را ‬<a href="https://github.com/topjohnwu/Magisk/releases">از روی گیت‌هاب مجیسک</a> می‌گیریم (هنگام نوشتن v23.0) و روی گوشی مثل قبل کپی می‌کنیم (یا در حالت ریکاوری با <code dir="ltr" class="language-plaintext highlighter-rouge">adb push Magisk-v23.0.apk /sdcard/</code>). حالا کافیست وارد ریکاوری بشویم و این فایل را نصب کنیم (بله همین فایل با پسوند apk را). همانند قبل در بخش Install ریکاوری فایل را انتخاب و اعمال می‌کنیم و بعد ریبوت.</p>

<p>بعد از ریبوت از داخل گوشی هم همین فایل را دوباره نصب می‌کنیم تا اپ MagiskManager به گوشی اضافه شود. داخل آن می‌توانیم وضعیت روت را بررسی کنیم و MagiskHide را فعال کنیم یا ماژول‌های مختلف را به گوشی اضافه کنیم. من بیش از این آن را شرح نمی‌دهم که از حوصله‌ی این نوشته خارج می‌شود. اطلاعات بیشتر و کلی عکس روی سایت <a href="https://magiskmanager.com/">magiskmanager</a>.</p>

<h3 id="safetynet-test"><a href="#safetynet-test">SafetyNet Test</a></h3>
<p>تا اینجا گوشی را روت کردیم اما این برای استفاده از برنامه‌های بانکی و مانند اینها کافی نیست (مثلا اپ موبیلت بانک سامان). این قبیل برنامه‌ها از API مخصوص امنیت در اندروید بنام <a href="https://en.wikipedia.org/wiki/SafetyNet_API">SafetyNet API</a> استفاده می‌کنند که به برنامه می‌گوید که آیا گوشی دستکاری شده است یا نه. در حال حاضر به کمک مجیسک می‌شود اندروید را فریب داد چرا که این فیچر نرم‌افزاری است. هرچند به محض اینکه گوگل اراده بکند می‌تواند از قابلیت‌های امنیتی موجود در پردازنده‌های موجود آرم استفاده کند و به کمک سخت‌افزار این موضوع را کنترل کند که در آن صورت هنوز راهی برای فرار از این موضوع پیدا نشده است. معنایش اینست که اگر گوشی از سخت‌افزار برای کنترل روت استفاده کند راهی برای فریب برنامه‌هایی که از این API استفاده کنند وجود ندارد. بعضی برنامه‌ها هم چک می‌کنند که آیا مجیسک روی گوشی وجود دارد یا نه (باز هم موبیلت) که البته با تغییر نام پکیج مجیسک از داخل خود اپ این مشکل حل می‌شود.</p>

<p>در گذشته با نصب مجیسک این تست‌ها هم پاس می‌شد ولی اینبار Basic Attestation و ctsProfile پاس نشدند (اسمی که اپ مجیسک برای این کنترل‌ها بکار می‌برد). با مقداری تحقیق متوجه شدم که به کمک <a href="https://github.com/coderbymistake/MagiskHidePropsConf">MagiskHidePropsConf</a> مشکل حل می‌شود (این هم یک کپی است). البته اگر SafetyNet Test داخل اپ مجیسک پاس شد نیازی به اینکار نیست. به هرحال روش کار اینطور است:</p>

<ol>
  <li>داخل مجیسک ماژول MagiskHide Props Config را نصب می‌کنیم</li>
  <li>ریبوت</li>
  <li>اجرای شبیه‌ساز ترمینال مانند <a href="https://termux.com/">Termux</a></li>
  <li>اجرای دستور <code dir="ltr" class="language-plaintext highlighter-rouge">su</code> و اجازه‌ی روت موقتی به ترموکس</li>
  <li>اجرای دستور <code dir="ltr" class="language-plaintext highlighter-rouge">props</code></li>
  <li>انتخاب گزینه ۲ (Force basic attestation)</li>
  <li>انتخاب پاسخ y</li>
  <li>ریبوت با انتخاب گزینه‌ی y</li>
</ol>

<p>با اجرای این مراحل SafetyNet Test هم پاس شد.</p>

<h2 id="تغییر-دگمه‌ی-bixby"><a href="#تغییر-دگمه‌ی-bixby">تغییر دگمه‌ی Bixby</a></h2>
<p>این گوشی یک دگمه‌ی خوب اما بی‌مصرف دارد که فقط تبلیغات سامسونگ را باز می‌کند. من دوست دارم وقتی این دگمه را می‌فشارم از صفحه یک اسکرین‌شات گرفته شود. این کار هم فقط با روت امکانپذیر است. از روی کامپیوتر یا داخل ترموکس:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ adb shell
$ su
# [mount] -o rw,remount /system
# cd /system/usr/keylayout
# # now replace WINK mit [SYSRQ]
# sed -i "s/WINK/SYSRQ/" Generic.kl
# reboot
</code></pre></div></div>

<h2 id="بازگردانی-داده‌ها"><a href="#بازگردانی-داده‌ها">بازگردانی داده‌ها</a></h2>
<p>اگر همه چیز درست پیش رفته باشد (که برای من نرفت!) یک گوشی گلکسی ۸ روت با اندروید ۹ داریم که خالی است. حالا کافیست بک‌آپ را بازگردانی بکنیم و اپ‌ها را دوباره نصب کنیم. البته احتمالا اگر آن بالا پارتیشن userdata را فلش نمی‌کردیم و اپلای کردن پچ dm-verify هم فراموش نشده بود داده‌ها حذف نمی‌شدند. (پارتیشن userdata حاولی اپ‌ها و اطلاعات کاربر است، اپ‌های سیستم روی پارتیشن system هستند.)</p>

<p>پس‌نوشت: در ابتدای مقاله گفتم که بازگردانی داده‌ها و نصب اپ‌های بانکی را هم انجام می‌دهیم اما سخن به درازا کشید و به آنجا نرسیدیم. اجل امان دهد در مطلبی دیگر :)</p>

</div>]]>
    </content>
    <summary>من یک گوشی گلکسی ۸ سامسونگ دارم که از ژانویه ۲۰۲۰ آپدیت نشده است و حداقل برای رفع باگ‌های امنیتی که در این فاصله ترمیم شده‌اند وقت خانه‌تکانی‌اش رسیده است. در ادامه آن را بروز و روت می‌کنیم و F-Droid و برنامه‌های بانکی و سایر چیزهای مفید و آزاد را هم روی آن نصب می‌کنیم. علت آپدیت نبودن اینست که گوشی من روت است و بنابراین آپدیت‌های OTA را دریافت نمی‌کند. البته آپدیت خاصی هم دیگر براش وجود ندارد چرا که آخرین آپدیت حاوی پچ امنیتی سامسونگ برایش در آوریل ۲۰۲۱ بوده است که به همان نسخه ارتقا می‌دهیم. در...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:38440fda-cce7-4e38-9a53-ca30f8bcd94a</id>
    
    <title>ساخت یک کامپیوتر فسقلی با رزبری‌پای زیرو</title>
    <updated>2021-08-06T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/tinymac.html"/>
    <category term="رزبری‌پای"/><category term="آمپلی‌فایر"/><category term="rpi"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>در این پست شرح می‌دهم چطور به همراه <a href="https://bekindtozombies.com">شایگان</a> یک کامپیوتر فسقلی با صفحه لمسی و بلندگوی توکار در ابعاد بسیار کوچک ساختیم تا آن را به دوستش هدیه بدهد. از جایی که این مقاله بسیار طولانی است، جایی را بخوانید که بدرد کارتان می‌خورد.</p>

<h2 id="شروع-ماجرا"><a href="#شروع-ماجرا">شروع ماجرا</a></h2>
<p>ماجرا از آنجا شروع شد که شایگان با من برای ساخت و سرهم کردن یک کامپیوتر کوچک و نسبتا ارزان مبتنی بر رزبری‌پای  تماس گرفت. ایده‌اش این بود که این کامپیوتر به محض روشن شدن تصویر گیف آلبوم صوتی مورد علاقه دوستش را، در حالی که همزمان تعدادی ترانه از آن آلبوم را پخش می‌کند، به صورت تمام‌صفحه نمایش بدهد. بله، باید یک کامپیوتر می‌ساختیم! برای اینکار به دو چیز احتیاج داشتیم: سخت‌افزار و نرم‌افزار. چالش اصلی انتخاب و تهیه و ساخت و مونتاژ قطعات اصلی بود. پس اول می‌پردازیم به سخت‌افزار.</p>

<p><img src="assets/tinymac/rangi.gif" alt="" />
<em>کاور آلبوم رنگی</em></p>

<h2 id="سخت‌افزار"><a href="#سخت‌افزار">سخت‌افزار</a></h2>
<p>همچنان که در اینترنت در جستجوی ایده‌های مشابه بودیم به پروژه‌ای به نام <a href="https://www.instructables.com/Making-a-Tiny-Mac-From-a-Raspberry-Pi-Zero/">تاینی مک</a> یعنی «مک فسقلی» از اوستاکاری بنام «cgenco» رسیدیم و تصمیم گرفتیم آن را الگو قرار دهیم. cgenco یک رزبری‌پای زیرو و یک صفحه‌ی نمایش لمسی را برای ساخت یک کامپیوتر مکینتاش کوچک بکار برده است. او برای اینکار یک بدنه‌ی عالی با نهایت ظرافت و توجه به جزئیات طراحی کرده است. او در نهایت یک شبیه‌ساز مکینتاش هم روی رزبری‌پای زیرو نصب می‌کند و به یک مکینتاش کوچک می‌رسد. برای پخش صدا هم از یک اسپیکر خارجی بلوتوث استفاده می‌کند. ما سخت‌افزار او را الگو قرار دادیم و تغییراتی در آن ایجاد کردیم. از جمله افزودن مدار فیلتر صوتی و یک جک ۳.۵ میلیمتری صوتی و یک پیج کم و زیاد کردن صدا و یک جفت اسپیکر توکار. با این اوصاف کامپیوتر کوچک ما چند بخش کوچک و ارزان لازم داشت:</p>

<ul>
  <li>یک بورد کامپیوتر توکار که جور همه چیز را بکشد</li>
  <li>یک صفحه‌ی نمایش که گیف را نمایش بدهد</li>
  <li>یک جفت اسپیکر که موزیک را پخش بکند</li>
  <li>یک مدار فیلتر صوتی با جک ۳.۵ میلیمتری و پتانسیومتر</li>
  <li>یک کارت حافظه برای نرم‌افزار</li>
  <li>یک بدنه که همه چیز را در خودش جا بدهد</li>
</ul>

<p>ما تصمیم گرفتیم که از رزبری‌پای برای بورد اصلی استفاده کنیم چون کامیونیتی بزرگی دارد و پیدا کردن اطلاعات و نمونه‌ها و قطعات لازم ساده‌تر است. شرکت سازنده‌ی رزبری‌پای مدل‌های مختلفی از کامپیوترهای تک‌بورد با امکانات مختلف تولید می‌کند. از جایی که همه‌ی این کامپیوترها می‌توانند آنچه ما می‌خواهیم انجام بدهند ما کوچکترین و ارزانترین عضو خانواده یعنی رزبری‌پای زیرو را انتخاب کردیم. صفحه‌ی نمایش را از چین سفارش دادیم و یک جفت اسپیکر هم دوست و همکارم <a href="https://fgarciafineart.blogspot.com/">فدریکو</a>، وقتی داشتیم راجع به نحوه‌ی کار فیلترهای صوتی صحبت می‌کردیم در اختیارم گذاشت. کارت حافظه خودم داشتم. مدار فیلتر صوتی را ساختم و بدنه را هم با چاپگر سه بعدی چاپ کردم. جزئیات را در ادامه شرح می‌دهم که قصه طولانی است.</p>

<h3 id="شرح-مختصری-در-مورد-رزبری‌پای"><a href="#شرح-مختصری-در-مورد-رزبری‌پای">شرح مختصری در مورد رزبری‌پای</a></h3>
<p>وقتی نوجوان بودم خیلی دوست داشتم که یک کامپیوتر کوچک داشته باشم و آنرا جایی در خانه روی دیوار نصب کنم و همیشه روشن بگذارم و بتوانم از آن به عنوان یک ایستگاه کنترل از راه دور استفاده کنم. آنزمان اما کامپیوترها بزرگ و حجیم و پرمصرف بودند و امکان اتصال آنها به سیستم‌های برقی دیگر وجود نداشت یا خیلی گران بود. مثلا تصور کنید که می‌خواهیم یک لامپ را با کامپیوتر روشن و خاموش کنیم. چطور می‌توانستم آن را به یک کامپیوتر وصل کنم؟ نمی‌دانم. شاید از طریقی می‌شد ولی امکانش برای من نوجوان وجود نداشت، آنهم با جیب‌های خالی.</p>

<p>حتی امروز هم اینکار با کامپیوترهای خانگی معمولی سخت است. این کامپیوترها پورت‌های USB و شبکه و گرافیک دارند و حتی دیگر از پورتهای سریال برای دستگاه‌های قدیمی خبری نیست. این کامپیوترها برای سرگرمی و کارهای رایج خانگی و اداری ساخته شده‌اند. برق مصرفی آنها هم بیش از آنست که شبانه روز روشن بمانند یا شاید سر و صدای فن کامپیوتر مانع روشن گذاشتن آن بشود.</p>

<p>اما امروزه مدلهای متنوعی از کامپیوترهای کوچک در بازار یافت می‌شود. کامپیوترهایی کم‌مصرف که توی کف دست جا می‌شوند و فن هم نیاز ندارند. اغلب این کامپیوترهای کوچک مبتنی بر پردازنده‌های خانواده ARM هستند نه اینتل. مهمترین ویژگی این معماری کم مصرف بودن آن است. این هم به معنی خود یعنی خنک بودن و عدم نیاز به فن. از طرفی معمولا CPU با یک یا چند هسته‌ی ARM به همراه رم و چندین ورودی/خروجی و حافظه‌ی دائمی معمولا در یک پکیج بنام System on Chip (SoC) بسته‌بندی می‌شود و در این کامپیوترهای کوچک بکار می‌رود. این کامپیوترها را Single Board Computer (SBC) می‌نامند، یعنی کامپیوتر تک‌بورده. مشهورترین SBC هم رزبری‌پای است.</p>

<p>اما مهمترین چیزی که یک SBC بویژه رزبری‌پای را از یک کامپیوتر معمولی متمایز می‌کند، در کنار کم‌مصرف و کوچک بودن، وجود <a href="https://www.raspberrypi.org/documentation/hardware/raspberrypi/gpio/README.md">GPIO</a> است. GPIO مخفف General Purpose Input/Output است. یعنی ورودی/خروجی چند منظوره. به زبان ساده روی هر رزبری‌پای حدود چهل پین کنار هم چیده شده‌اند که قابل برنامه‌ریزی هستند. این پین‌ها را می‌توان به ابزارهای جانبی وصل کرد و رفتار آنها را در یک برنامه کنترل کرد. یک ابزار جانبی می‌تواند به سادگی یک مقاومت و یک LED باشد که مستقیما با برق ۵ یا ۳ ولت از پین‌ها تغذیه می‌شود (که از داخل برنامه قابل فعال/غیرفعال شدن هستند) یا به پیچیدگی یک صفحه‌ی نمایش لمسی. از این گذشته ابزارهای جانبی که معمولا Hardware Attached on Top یا HAT نامیده می‌شوند از پروتکل‌های مختلفی مانند SPI یا I²C برای اتصال به رزبری‌پای می‌توانند استفاده کنند. در سایت <a href="https://pinout.xyz">pinout.xyz</a> می‌توان چیدمان پین‌های بوردهای مختلف رزبری‌پای و کاربردهای هر پین را مشاهده کرد.</p>

<h3 id="raspberry-pi-zero-w"><a href="#raspberry-pi-zero-w">Raspberry Pi Zero W</a></h3>

<p class="center"><img src="assets/tinymac/rpizerow.png" alt="Raspberry Pi Zero W" />
<em>تصویر یک رزبری‌پای زیرو از سایت رزبری‌پای</em></p>

<p>رزبری‌پای زیرو ساده‌ترین عضو خانواده رزبری است. تنها دارای یک پورت micro USB و یک پورت mini HDMI است. دومین پورت میکرو یو‌اس‌بی برای تغذیه بورد است و هیچ کاربرد دیگری ندارد. این بورد ۵۱۲ مگابایت RAM دارد و فاقد حافظه‌ی دائمی است. درگاه SD Card نقش حافظه‌ی دائمی را بازی می‌کند. آخرین درگاه موجود روی این بورد مخصوص دوربین است. این بورد در دو مدل عرضه می‌شود، یکی بدون وایفای و بلوتوث و دیگری با هردوی آنها. ما برای پروژه‌مان نیاز جدی به وایفای و بلوتوث نداشتیم ولی از جایی که داشتن وایفای هم کار من را راحت می‌کرد و هم کامپیوتر فسقلی ما را به اینترنت وصل می‌کرد تصمیم گرفتیم از این نسخه استفاده کنیم. توجه کنید که رزبری‌پای زیرو خروجی ۳.۵ میلیمتری برای جک صوتی و نیز هیچ نوع صفحه نمایش ندارد. ما برای این پروژه به هر دوی آنها نیاز داریم و در ادامه شرح می‌دهم که چطور آنها را اضافه کردیم. البته پیش از وصل کردن صفحه‌ی نمایش چهل پین به بورد لحیم کردم، چرا که ما بخاطر صرفه‌جویی بوردی سفارش دادیم که پین‌ها از پیش به آن لحیم نشده بودند (فقط حفره‌هایی برای اتصال آنها روی بورد قرار داشت).</p>

<h3 id="صفحه‌ی-نمایش-۲۸-اینچی"><a href="#صفحه‌ی-نمایش-۲۸-اینچی">صفحه‌ی نمایش ۲.۸ اینچی</a></h3>
<p>ما عینا همان <a href="https://wiki.geekworm.com/index.php/2.8_inch_Touch_Screen_for_Pi_zero">صفحه‌ی نمایشی</a> را که cgenco انتخاب کرده بود از سایت علی‌اکسپرس سفارش دادیم که دو سه هفته بعد به دست من رسید. همانطور که پیشتر در مورد پین‌ها توضیح دادم، این صفحه نمایش هم مستقیم به پین‌های GPIO متصل می‌شود. من از یک کابل چهل سیمه استفاده کردم تا زیرو را به صفحه‌ی نمایش متصل کنم.</p>

<p class="center"><img src="assets/tinymac/20210727_164000.jpg" alt="" />
<em>صفحه‌ی نمایش که با کابل ۴۰ سیمه به زیرو متصل شده است</em></p>

<p>برخلاف خروجی‌های ویژه‌ی مانیتورها مانند HDMI، برای آنکه چیزی روی این صفحه‌ی نمایش ببینیم باید سیستم عامل را تنظیم کنیم. صرف وصل کردن آن به پین‌ها هیچ اتفاقی نمی‌افتد. خوشبختانه مدتهاست که کرنل لینوکس از معماری آرم پشتیبانی می‌کند و سیستم عامل دبیان و نسخه‌ی رزبری‌پای آن امکان تنظیم سیستم عامل برای استفاده از پین‌ها را فراهم می‌کند. در بخش نرم‌افزار شرح می‌دهم که چطور اینکار را کردیم.</p>

<p>نصب سخت‌افزار صفحه‌ی نمایش در کل کار نسبتا ساده‌ای بود بنابراین می‌رویم سروقت بخش بعدی.</p>

<h3 id="اضافه-کردن-یک-جفت-اسپیکر"><a href="#اضافه-کردن-یک-جفت-اسپیکر">اضافه کردن یک جفت اسپیکر</a></h3>
<p>برای پخش موزیک از کامپیوترمان باید یک جفت اسپیکر به رزبری‌پای زیرو اضافه می‌کردیم. تصور خام اولیه‌ی من این بود که می‌تواتم به سادگی یک جفت اسپیکر کوچک را مستقیما به پین‌های رزبری‌های متصل کنم. ولی به سرعت پی به اشتباهم بردم.
رزبری‌پای زیرو بر خلاف اعضای قوی‌تر خانواده مثل رزبری‌پای ۳ و ۴ فاقد خروجی ۳.۵ میلیمتری جک صوتی است. بنابراین اتصال یک هدفن یا یک اسپیکر خارجی دارای آمپلی‌فایر منتفی است. هرچند آنچه از نظر پنهان است یک مدار کوچک فیلتر صداست که آن هم در رزبری‌پای زیرو وجود ندارد. برای اینکه بتوان یک هدفن یا اسپیکر را به رزبری‌پای زیرو اضافه کردن باید ابتدا این مدار را ساخت.</p>

<blockquote>
  <p>رزبری‌پای زیرو فاقد فیلتر صدا و خروجی ۳.۵ میلیمتری جک صوتی است.</p>
</blockquote>

<p>یک هدفن یا اسپیکر یا یک آمپلی‌فایر (تقویت کننده صدا) نیاز به یک سیگنال آنالوگ ورودی دارد نه یک سیگنال دیجیتال. مثلا یک فایل mp3 حاوی تخمینی دیجیتال/گسسته از یک سیگنال آنالوگ/پیوسته است و کیفیت آن هم بسته به دقت نمونه‌گیری (sampling rate) آن است. از طرفی رزبری‌پای زیرو تبدیل کننده‌ی دیجیتال به آنالوگ (Digital to Analog Converter - DAC) ندارد. پس نمی‌تواند خروجی مناسب برای اسپیکر تولید کند. یک پین GPIO رزبری‌پای می‌تواند در یک لحظه یک منطقی (۳.۳. ولت) یا صفر منطقی (صفر ولت) باشد و نه چیزی بین این دو (البته همه پین‌ها GPIO نیستند). با مقداری جستجو و مطالعه یادگرفتم که همه مدل‌های رزبری‌پای برای تولید صدا از تکنیکی بنام <a href="https://en.wikipedia.org/wiki/Pulse-width_modulation">Pulse Width Modulation (PWM)</a> استفاده می‌کنند. به کمک این روش می‌توان یک سیگنال آنالوگ را به کمک یک سیگنال دیجیتال شبیه‌سازی کرد. در این روش ولتاژ پین‌ها با فرکانسی بالا بین صفر و ۳.۳ ولت سویچ می‌شود (بسته به نوع اپلیکیشن مورد نیاز، مثلا یک موتور یا یک آمپلی‌فایر). با کنترل مدت زمانی که هر پالس خروجی را روشن می‌کند (۳.۳ ولت) می‌توان میزان جریان الکتریکی و مجموع توان منتقل شده به مصرف کننده (اینجا اسپیکر) را کنترل کرد. شرح عمیق‌تر این موضوع از منظر الکتریکی فعلا در حیطه‌ی تخصص من نیست.</p>

<p>خوشبختانه کرنل لینوکس چیپ <a href="https://elinux.org/RPi_BCM2835_GPIOs">BCM2835</a> بکار رفته در رزبری را به خوبی ساپورت می‌کند و ما در نهایت کافیست کرنل را بدرستی تنظیم کنیم و مدار فیلتر را به رزبری‌پای زیرو اضافه کنیم. مدار فیلتر ساده‌ای که در در سایر رزبری‌پای‌ها بجز زیرو وجود دارد ترکیبی است از تعدادی خازن و مقاومت که حاوی یک Low Pass Filter و یک High Pass Filter است که فقط یک رنج فرکانس خاص را از خودش عبور می‌دهد و باقی را حذف می‌کند که حداقل باعث حذف نویز می‌شود. اگر فهم عمیق‌تری از فیلترها دارید در بخش نظرات بنویسید که مفید فایده بشود. ما این مدار را می‌سازیم و به کامپیوترمان اضافه می‌کنیم.</p>

<p class="center"><img src="assets/tinymac/raspberry_pi_audiofilter.png" alt="" />
<em>فیلتر صوتی محصولات رزبری بجز زیرو. سمت راست خروجی ۳.۵ میلیمتری است و سمت چپ دو ورودی‌ PWM. ما از دیودها سمت راست پایین صرف نظر کردیم.</em></p>

<p>مدار این فیلتر خیلی ساده است. اگر به تصویر بالا دقت کنید دو بخش بالا و پایین عینا مثل هم هستند. حتی یکی از آنها کافی است اما خروجی احتمالا مونو و تک کاناله خواهد شد. من هر دو را اضافه کردم. برای هر بازوی مدار به قطعات زیر احتیاح است:</p>

<ul>
  <li>یک مقاومت ۲۷۰ اهمی</li>
  <li>یک خازن ۳۳ نانو فارادی</li>
  <li>یک مقاومت ۱۵۰ اهمی</li>
  <li>یک خازن ۱۰ پیکو فارادی</li>
</ul>

<p>من بیشتر این قطعات را در خانه داشتم بجز خازن ۳۳ نانو فارادی که تعدادی تهیه کردم. تصویر زیر مداری را نشان می‌دهد که ساختم.</p>

<p class="center"><img src="assets/tinymac/20210711_135944.jpg" alt="" />
<em>اولین تلاش من برای ساخت فیلتر صوتی</em></p>

<p>مدارهای ساده را اول روی Breadboard می‌سازند. بردبورد از دو بخش کلا مجزای بالا و پایین تشکیل شده. هر طرف هم به نوبه خود به دو بخش تقسیم شده. در امتداد لبه‌ی کناری بورد تمام حفره‌های آبی به هم وصل هستند و همه‌ی حفره‌های قرمز هم همینطور. یکی برای منفی است و دیگری برای اتصال مثبت. حفره‌های درونی برد برد که با پنج حرف a b c d e مشخص شده‌اند پنج تا پنج تا به صورت عمودی به هم وصل هستند.</p>

<p>ورودی این فیلتر را به پین‌های PWM متصل کردم (شرح در بخش نرم‌افزار) و خروجی آن را به یک هدفن. بدون مشکل کار کرد صدا هم خوب بود (البته من خوره صدا نیستم!). هرچند با اتصال آن به اسپیکرهای ۳ واتی که از فدریکو گرفتم متوجه شدم که صدا بی‌نهایت ضعیف است و باید گوشت را به اسپیکرها بچسبانی تا بتوانی به زحمت چیزی بشنوی. وقت اضافه کردن یک آمپلی‌فایر رسیده بود!</p>

<p>بعد از مقداری مطالعه در اینترنت و صحبت با همکارم که متخصص الکترونیک است فهمیدم که برای اینکه سیم‌های یک اسپیکر را مستقیم به خروجی فیلتر وصل کنم نیاز به یک آمپلی‌فایر (تقویت‌کننده) دارم چرا که توان خروجی فیلتر برای تغذیه‌ی اسپیکر سه واتی من کافی نبود (تصور کنید که اگر اسپیکر بزرگتری با توان بالاتر داشتم احتمالا اصلا چیزی نمی‌شنیدم). اینجا لازم است اضافه کنم که بیشتر اسپیکرهایی که ما دور و برمان داریم و به کامپیوتر و موبایل متصل می‌کنم یک مدار آمپلی‌فایر داخل خودشان دارند. هدفن‌ها به خاطر کوچکی‌شان و توان پایین نیازی به آمپلی‌فایر ندارند بنابرین می‌توانیم آنها را مستقیما به خروجی ۳.۵ میلیمتری وصل کنیم.</p>

<p>حالا دو انتخاب در پیش رو داشتیم: فقط به هدفن اکتفا کنیم یا یک آمپلی‌فایر هم بسازیم. خوب، جواب را خودتان حد بزنید :)</p>

<p>با توضیحات فدریکو و مطالعه مقالات دیگرانی که فیلتر صوتی ساخته بودند فهمیدم که می‌توان حتی با یک ترانزیستور یک مدار تقویت‌کننده‌ی ساده ساخت. کافیست یکسوی آنرا به خروجی ۳.۳ یا ۵ ولت (از رزبری) متصل کرد و سوی دیگر را به خروجی فیلتر صوتی با مقداری جزئیات بیشتر. ولی در این مرحله آنقدر کار باقی مانده بود که تصمیم گرفتم یک مدار نقلی آمپلی فایر بخرم و به فیلتر اضافه کنم. با مقداری جستجو یک آمپلی‌فایر یک دلاری پیدا کردم بنام PAM8403 (در ایران هم به قیمت ناچیزی پیدا می‌شود).</p>

<p class="center"><img src="assets/tinymac/PAM8403_electrodragon.jpg" alt="" />
<em>آمپلی‌فایر ارزان و کوچک PAM8403. سمت راست بالا ورودی مثبت و منفی از منبع تغذیه. سمت راست پایین ورودی چپ و راست از فیلتر صدا. سمت چپ بالا خروجی اسپیکر سمت راست. سمت چپ پایین خروجی اسپیکر سمت چپ. عکس از سایت electrodragon.com</em></p>

<p>با کمک این آمپلی‌فایر می‌توان اسپیکرهای کوچک و متوسط را مستقیما پشتیبانی کرد. به خاطر بیاورید که بدون آمپلی‌فایر با مدار ما بیش از یک هدفن کوچک را به زحمت می‌توان پشتیبانی کرد. روش کار هم ساده است. ما خروجی فیلتر صدا و منبع تغذیه را به آمپلی‌فایر وصل می‌کنیم و سپس خروجی آمپلی‌فایر را به اسپیکرهایمان متصل می‌کنیم. نکته مهم در مورد این آمپلی‌فایر اینست که نباید گراوند (زمین/قطب منفی) خروجی به اسپیکرها به هم متصل شود. این را وقتی متوجه شدم که قصد داشتم یک خروجی ۳.۵ میلیمتری به مدار اضافه کنم که گراوند چپ و راست در آن مشترک است. ابتدا این خروجی را به اشتباه بعد از آمپلی‌فایر قرار داده بودم و با اتصال کابل هدفن گراوند چپ و راست آمپلی‌فایر به هم وصل می‌شد و باعث می‌شد که تقویت کننده از کار بیفتد. البته این را اصلاح کردم. در دیزاین آخر آمپلی‌فایر بعد از خروجی ۳.۵ میلیمتری قرار گرفته و دو اسپیکر به طور مجزا به خروجی‌های آن وصل شده‌اند.</p>

<h3 id="جک-۳۵-میلیمتری"><a href="#جک-۳۵-میلیمتری">جک ۳.۵ میلیمتری</a></h3>
<p>اضافه کردن یک جک ۳.۵ میلیمتری کاری مفرح بود. من نمی‌دانستم که جک‌های ۳.۵ میلیمتری مثل یک کلید عمل می‌کنند. یعنی نحوه‌ی نصب کردن آن مهم است. جکی که من اضافه کردم ۵ پین داشت. یک پین گراوند و دو پین ورودی صدا و دو پین خروجی صدا. در حالتی که هیچ فیشی به جک وصل نیست ورودی‌ها به خروجی‌ها وصل هستند و صدا می‌رود به طرف آمپلی‌فایر و بعد اسپیکرها. اما به محض اتصال فیش یک هدفن سویچ باز می‌شود و صدا می‌رود به هدفن و ورودی آمپلی‌فایر قطع می‌شود. به همین سادگی! هیچ تکنولوژی خاصی در کار نیست. یک کلید ساده. البته من در ابتدا جک ۳.۵ میلیمتری را هم به خروجی آمپلی‌فایر وصل کرده بودم که نه تنها مشکل‌آفرین بود (اتصال کوتاه آمپلی‌فایر) بلکه کلا اشتباه بود چرا که هدفن به آنهمه توان خروجی نیاز نداشت و صدا گوش کر کن می‌شد. که همانطور که پیشتر گفتم آنرا اصلاح کردم.</p>

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

<h3 id="پتانسیومتر-برای-کم-و-زیاد-کردن-صدا"><a href="#پتانسیومتر-برای-کم-و-زیاد-کردن-صدا">پتانسیومتر برای کم و زیاد کردن صدا</a></h3>
<p>پتانسیومترها را خیلی جاها دیده‌اید. روی رادیوهای قدیمی برای کم و زیاد کرن صدا و روی تجهیزات صوتی یا گاهی برای کم و زیاد کردن نور لامپ‌هها یا کم و زیاد کردن گرم‌کننده‌های برقی و مانند اینها زیاد پیدا می‌شود. ساده‌ترین کارش اینست که مثل یک مقاومت متغیر عمل می‌کند. البته بسته به نحوه‌ی قرار دادن آن در مدار می‌توان با آن ولتاژ متغیر هم بوجود آورد. اینجا ما از آن به عنوان مقاومت متغیر برای کم و زیاد کردن صدا استفاده می‌کنیم.</p>

<p class="center"><img src="assets/tinymac/237px-Electronic-Component-Potentiometer.jpg" alt="" />
<em>یک پتانسیومتر. عکس از ویکی‌پدیا</em></p>

<p>اولین اشتباه از سری اشتباهاتم انتخاب مقاومت بسیار بزرگ بود. بعد از نصب پتانسومتر متوجه شدم که به محض اینکه ذره‌ای پیچ صدا را می‌چرخانم صدا به سرعت قطع می‌شود. در حقیقت فقط وقتی می‌توانستم چیزی بشنوم که مقاومت پتانسیومتر صفر یا نزدیک صفر بود. به سرعت یک پتانسومتر خطی دیگر با مقاومت ۱۰ کیلواهم سفارش دادم. هنوز روحم خبر نداشت که این هم کار نخواهد کرد.</p>

<p>مهمترین اشتباهم این بود که تصور کردم پتانسیومتر فقط یک مقاومت متغیر خطی است. یعنی مقاومت را با یک شیب خطی زیاد می‌کند و باعث افت جریان می‌شود و این برای یک مدار صوتی کفایت می‌کند. مثلا فکر می‌کردم اگر پیج صدا را ۴۵ درجه بچرخانم با ۲۵ درصد افزایش مقاومت، صدا هم ۲۵ درصد کم می‌شود و اگر ۱۸۰ درجه بچرخانم با ۵۰ درصد افزایش مقاومت، صدا هم ۵۰ درصد کم می‌شود. تنها بعد از نصب پتانسومتر بود که متوجه شدم اصلا اینطور نیست…</p>

<h4 id="گوش-انسان-خطی-نیست"><a href="#گوش-انسان-خطی-نیست">گوش انسان خطی نیست</a></h4>
<p>بعد از این کشف جالب بیشتر مطالعه کردم و فهمیدم که گوش انسان شدت صدا را به صورت خطی حس نمی‌کند بلکه آنرا به صورت لگاریتمی حس می‌کند. این [سوال روی استک‌اکسجنج] کمکم کرد تا موضوع را بفهمم. خلاصه‌اش اینست که شدت صدا به دسی‌بل محاسبه می‌شود و ده دسی‌بل افزایش یا کاهش شدت سیگنال صدا منجر به دو برابر یا نصف شدن سیگنالی می‌شود که گوش انسان حس می‌کند. این یعنی هرچند پات من مقامت را مثلا ۵۰ درصد زیاد می‌کرد ولی این باعث نصف شدن سیگنالی نمی‌شد که گوش انسان حس می‌کرد. اینجا بود که تفاومت پات‌های خطی و لگاریتمی را فهمیدم (مدتی هم طول کشید تا بفهمم اسم کوچک پتانسیومتر، «پات/pot» است).</p>

<p>یک پات خطی برای کم و زیاد کردن نور لامپ یا شدت چرخش یک پنکه مناسب است اما برای کم و زیاد کردن شدت صدا مناسب نیست. برای اپلیکیشن‌های صوتی باید از پات‌های لگاریتمی استفاده کرد که مقاومت را نه به صورت خطی، بلکه به صورت لگاریتمی تغییر می‌دهند. یعنی نمودار تغییر خروجی خطی نیست بلکه منحنی است. بنابراین اگر پیچ صدای یک پات لگاریتمی را ۲۵ درصد بچرخانیم سیگنال صدا هم ۲۵ دسی‌بل تغییر می‌کند. همانطوری که ما انتظار آن را داریم. پس کافی بود که یک پات لگاریتمی سفارش بدهم. ولی به دلیل مسافرت دیگر فرصت سفارش پات دیگری نداشتم. در این مرحله حتما تصدیق می‌فرمایید که دیگر چاره‌ای نبود جز ساخت یک پات لگاریمتی!!!</p>

<h4 id="ساخت-یک-پتانسومتر-لگاریتمی"><a href="#ساخت-یک-پتانسومتر-لگاریتمی">ساخت یک پتانسومتر لگاریتمی</a></h4>
<p>حالا که چند پات خطی روی دستم مانده بود و فرصت سفارش پات لگاریتمی هم نبود دوباره دست به دامن اینترنت شدم اینبار وبسایت یکی از بچه‌های قدیم را پیدا کردم. (از کجا می‌دانم بچه‌ی قدیم است؟ خودتان وبسایت نویسنده‌ی <a href="http://www.geofex.com/Article_Folders/potsecrets/potscret.htm">زندگی سحرآمیز پات‌ها</a> را ببینید و قضاوت کنید! دود همچنان از کنده بلند می‌شود!) بهترین مقاله‌ای که در این رابطه خواندم مقاله‌ی <a href="http://www.geofex.com/Article_Folders/potsecrets/potscret.htm">زندگی سحرآمیز پات‌ها</a> است. ظاهرا به دلایل مختلفی از جمله سرمایه‌داری و تلاش برای حداکثر کردن سود، شرکت‌ها دیگر پتانسیومترهای لگاریتمی آنهم با مقاومت‌های دلخواه و کلا هرچه کمتر مصرف شود را کمتر تولید می‌کنند یا دیگر اصلا تولید نمی‌کنند. ظاهرا نان توی تولید انبوه چیزی است که بیشتر مشتری دارد. اما این وسط هکرها و بچه‌های قدیم بیکار ننشسته‌اند و کشف کرده‌اند چطور مقاومت خطی را به لگاریتمی تبدیل کنند.</p>

<p>اگر جزئیات را دوست دارید بداند آن مقاله را به هر ضرب و زوری که می‌توانید بخوانید. خیلی آموزنده بود. خلاصه‌اش این بود که باید هر سه پین پتانسیومتر را بکار می‌گرفتم. دقت کنید که پتانسیومتر معمولا سه پین دارد. البته پات من شش پین داشت. یکی برای اسپیکر چپ یکی هم برای اسپیکر راست. اما در حقیقت چیزی جز دو پات به هم چسبیده نیست. پس من همان سه پین را شرح می‌دهم.</p>

<p>وقتی از یک پات به صورت مقاومت خطی استفاده می‌شود فقط دو پین کفایت می‌کند. یک پین ورودی است و یک پین خروجی. پین سوم هم وصل نیست. اما برای تبدیل یک مقاومت خطی به لگاریتمی (یا بکار گرفتن پات به عنوان متغیر ولتاژ) باید هر سه را به کار گرفت. تغییر البته ساده بود. فقط کافی بود پین سوم به گراوند مدار وصل بشود و بین پین ورودی و خروجی هم یک مقاومت اضافه بشود. میزان این مقاومت را به کمک فرمولی که در مقاله بالا داده شده بود محاسبه کردم.</p>

<p class="center"><img src="assets/tinymac/revser.gif" alt="" />
<em>http://www.geofex.com/Article_Folders/potsecrets/potscret.htm</em></p>

<p>بنابراین فقط کافی بود که فرمول ساده‌ی زیر را برای پات ده کیلویی‌ام حل کنم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Rt=Rpot/b b=1,2,3,4,5(max)
Rt=10K/5=2K
</code></pre></div></div>

<p>از جایی که من یک پات ده کیلویی داشتم فقط به دو کیلو مقاومت احتیاج بود. پس پین سوم هر طرف پتانسیومتر را به گراند وصل کردم و در هر سوی پات بین ورودی و خروجی یک مقاومت دو کیلویی اضافه کردم و مشکل حل شد.</p>

<h3 id="مدار-کامل-صوتی-و-مونتاژ-قطعات"><a href="#مدار-کامل-صوتی-و-مونتاژ-قطعات">مدار کامل صوتی و مونتاژ قطعات</a></h3>
<p>پس از حل همه‌ی چالش‌های بالا من مدار فیلتر و پتانسیومتر استریو و جک ۳.۵ میلیمتری و اسپیکرها را در مدار زیر ادغام کردم. <a href="assets/tinymac/circuit.cddx">فایل دیزاین</a> را می‌توانید دانلود کنید و در <a href="https://www.circuit-diagram.org/editor/open">ادیتور سایت circuit-diagram.org</a> ایمپورت کنید.</p>

<p class="center"><img src="assets/tinymac/circuit.png" alt="" />
<em>مدار صوتی حاوی فیلتر و پتانسیومتر و جت ۳.۵ میلیمتری و اسپیکرها. طراحی به کمک www.circuit-diagram.org.</em></p>

<p class="center"><img src="assets/tinymac/20210726_221157.jpg" alt="" />
<em>مدار صوتی کامل</em></p>

<p class="center"><img src="assets/tinymac/20210728_010857.jpg" alt="" />
<em>یکی از مقاومت‌های دو کیلویی بین پتانسومتر و آمپلی‌فایر، بالا سمت چپ، قابل دیدن است. دیگری زیر پات است و دیده نمی‌شود. توجه کنید از جایی که مقاومت بیست اهمی نداشتم، دو مقاومت ده اهمی را سری کرده‌ام که در بخش چپ پایین عکس قابل مشاهده است. برای ورودی‌ها و خروجی‌ها هم تعدادی پین لحیم کردم که اتصال آنها را ساده کند.</em></p>

<p>تصویر بالا بورد صوتی با همه‌ی ملحقات آن را نمایش می‌دهد. سیم‌کشی‌ها و اتصالات زیر بورد قابل دیدن نیست. متاسفانه حین مسافرت تجهیزات کافی همراه نداشتم و هویه و سیم لحیم و سیم‌های مسی که بکار بردم مناسب نبودند و سیم‌ها به سختی لحیم شدند و خیلی مستحکم از آب درنیامد. از طرفی چون برای رفع مشکلات مختلف مجبور شدم سیم‌کشی را تغییر بدهم خروجی سیم‌کشی زیگ زاگ از آب درآمد که از نمایش آن صرف نظر می‌کنم (چسب کاغذی را برای فیکس کردن سیم‌ها و جلوگیری از شکستن اتصالات بکار برده‌ام).</p>

<p>حالا وقت سر هم کردن همه قطعات سخت‌افزاری بود: زیرو و بورد صدا و صفحه‌ی نمایش. برای اتصال صفحه‌ی نمایش فقط کافی بود کابل آن را به زیرو وصل کنم. اما از جایی که کابل صفحه‌ی نمایش تمام پین‌ها را می‌پوشاند، مجبور شدم پین‌های PWM و گراند و پنج ولت تغذیه آمپلی‌فایر را از زیر به زیرو لحیم کنم. مهمترین چالشی که حین ادغام بورد صوتی و صفحه‌ی نمایش نگران آن بودم این بود که صفحه‌ی نمایش تمام پین‌های GPIO را استفاده کند و دیگر پین آزاد برای PWM باقی نماند. خوشبختانه با مطالعه‌ی مستندات صفحه‌ی نمایش و <a href="assets/tinymac/ZERO-PIN.xls">فایل اکسل</a> شرح پین‌های آن متوجه شدم که تعدادی از پین‌ها استفاده نشده‌اند (هرچند اتصال کابل همه را می‌پوشاند). از سوی دیگر بخت با ما یار بود و PWM روی پین‌های باقی مانده قابل فعالسازی بود. طبق مستندات رزبری‌پای هر پین تعدادی کاربری دارد، می‌تواند GPIO باشد یا مثلا PWM یا SPI و مانند اینها باشد. اینها را از طریق تنظیمات سیستم عامل قابل تغییر است که جلوتر اشاره خواهم کرد.</p>

<p>شاید بپرسید چرا کاربری‌های مختلفی برای پین‌ها در نظر گرفته شده است. علت اینست که چیپ بکار رفته در زیرو قابلیت‌های بسیاری دارد که برای همه‌ی آنها پین کافی وجود ندارد. چرا که اقتصادی نیست و جا هم روی بورد برای آنهمه پین وجود ندارد. بنابراین رایج است که با نرم‌افزار قابلیت دلخواه را فعال می‌کنند.</p>

<h3 id="سورپرایز-بعدی-ریست-شدن-ناگهانی"><a href="#سورپرایز-بعدی-ریست-شدن-ناگهانی">سورپرایز بعدی: ریست شدن ناگهانی</a></h3>
<p>بعد از اتصال همه قطعات و تست پخش صدا و گیف مشکل جدیدی پیش آمد. به محض زیاد کردن صدا یا پخش تصاویر متحرک رزبری‌پای زیرو ریست می‌شد. ابتدا فکر کردم مشکل جایی در اتصالات بورد صدا و آمپلی‌فایر است (چون به محض متصل کردن آن دستگاه ریست می‌شد). اما مشکل جای دیگری بود:‌ منبع‌تغذیه. رزبری‌پای زیرو را برای تغذیه ابتدا به پورت usb کامپیوتر وصل کرده بودم. در استاندارد USB ویژگی‌های مکانیکی و الکتریکی این پورت‌ها تعریف شده است منجمله ولتاژ و حداکثر جریان خروجی. در استاندارد USB برای USB 2.0 ولتاژ ۵ ولت و حداکثر جریان ۵۰۰ میلی‌آمپر تعریف شده است. برای USB 3.0 این مقدار ۵ ولت و حداکثر ۹۰۰ میلی‌آمپر تعریف شده است. از طرفی تولیدکنندگان همگی این استاندارد را رعایت نمی‌کنند، پس ممکن است یک کامپیوتر بتواند این را تامین کند و دیگر نتواند. من زیرو را به لپ‌تاپ ۱۹۹ دلاری Pinebook Pro خودم متصل کرده بودم که با اتصال صفحه‌ی نمایش و پخش صدا ریست می‌شد (بدون اینها مشکلی پیش نمی‌آمد). طبق <a href="https://www.raspberrypi.org/documentation/hardware/raspberrypi/power/README.md">مستندات رزبری در مورد منبع تغذیه</a> جریان مصرفی زیرو در حالت عادی ۱۰۰ میلی‌آمپر است و منبع تغذیه باید تا ۱.۲ آمپر را بتواند تامین کند که بیش از توان خروجی پورت‌های USB است. از طرفی اتصال صفحه‌هی نمایش و اسپیکرها میزان جریان مصرفی را افزایش می‌دهد که با مراجعه به مشخصات هر قطعه قابل محاسبه است (من محاسبه نکردم). جریان مصرفی برابر خواهد بود با مجموع جریان مصرفی هر قطعه. بعد از استفاده از یک منبع تغذیه‌ی USB با ۲ آمپر جریان مشکل حل شد (شارژر یک بلندگو را بکار بردم).</p>

<blockquote>
  <p>منبع تغذیه‌ی رزبری‌پای زیرو باید بتواند حداقل ۱.۲ آمپر جریان را تامین بکند.</p>
</blockquote>

<p>خلاصه با اطمینان از اینکه سخت‌افزار ما کار می‌کند می‌رویم سروقت بدنه.</p>

<h3 id="چاپ-سه-بعدی-بدنه"><a href="#چاپ-سه-بعدی-بدنه">چاپ سه بعدی بدنه</a></h3>
<p>همانطور که در ابتدا اشاره کردم ما از بدنه‌ای که قبلا طراحی شده استفاده کردیم. cgenco زحمت طراحی یک بدنه شبیه یک مکینتاش قدیمی را کشیده است که برای ما ایده‌آل بود. من <a href="assets/tinymac/tinymac3d.tar.gz">فایل‌های stl</a> برای چاپ سه بعدی آن را دانلود کردم و به کمک یک پرینتر سه  بعدی پروسا Prusa I3 MK3S چاپ کردم. اما از روی کم تجربگی «ساپورت» مناسبی برای چاپ انتخاب نکرده بودم. یعنی موقع چاپ بخش‌هایی که زیرشان خالی است (مثل یک حفره) ممکن است خراب شود. برای ممانعت از اینکار باید از ساپورت استفاده کرد. در آنصورت چاپگر یک ساختار پوک که براحتی قابل حذف کردن است زیر و درون حفره‌ها چاپ می‌کند که مانع ریزش آنها حین چاپ می‌شود (ماده‌ای که از نازل چاپگر خارج می‌شود داغ و نرم است و فرو می‌ریزد).</p>

<p class="center"><img src="assets/tinymac/20210720_082514.jpg" alt="" />
<em>دست راست: چاپ شده بدون ساپورت. دست چپ چاپ شده با ساپورت.</em></p>

<p>ما مجبور بودیم دو حفره برای پتانسیومتر و جت ۳.۵ میلیمتری در بدنه ایجاد کنیم. باید فایل‌های سه بعدی را در یک برنامه‌ی CAD اصلاح می‌کردیم و حفره‌های لازم را در بنده ایجاد می‌کردیم و فایل تغییر یافته را پرینت می‌گرفتیم. متاسفانه از جایی که هنوز  اینکار را بلند نیستم و فرصت یادگیری هم فراهم نشد به روش سنتی سیخ داغ مراجعه کردیم! و البته کار انجام شد.</p>

<p class="center"><img src="assets/tinymac/itworks.jpg" alt="" />
<em>اگه کار می‌کنه احمقانه نیست!</em></p>

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

<p class="center"><img src="assets/tinymac/20210728_010831.jpg" alt="" />
<em>بدنه‌ی اول به رنگ آبی را برای تست بکار بردیم.</em></p>

<p class="center"><img src="assets/tinymac/20210728_134016.jpg" alt="" />
<em>بدنه‌ی نمونه‌ی اول (پروتوتایپ) در مقایسه با بدنه‌ی اصلی.</em></p>

<p class="center"><img src="assets/tinymac/20210728_133935.jpg" alt="" />
<em>بدنه‌ی نمونه‌ی اول (پروتوتایپ) در مقایسه با بدنه‌ی اصلی.</em></p>

<p>حالا می‌رویم سر وقت اسپیکرها.</p>

<h3 id="نصب-نهایی-اسپیکرها"><a href="#نصب-نهایی-اسپیکرها">نصب نهایی اسپیکرها</a></h3>
<p>اسپیکرهای ما حداکثر سه وات توان دارند و مقاومت درونی هر یک از آنها چهار اهم است. متاسفانه فراموش کردم پیش از نصب از مشخصات فنی پرینت شده روی آنها عکس بگیرم و ممکن است این ارقام اشتباه باشد (طی فرآیند نصب برچسب مشخصات فنی اسپیکر از بین رفت). صدای اسپیکرها چندان بلند نیست و وقتی داخل بدنه قرار می‌گیرد کمتر هم می‌شود. اول می‌خواستیم تعدادی حفره هم برای اسپیکرها ایجاد کنیم (اینکار را روی بدنه‌ی آبی امتحان کردیم)، اما از نظر ظاهری خوب درنیامد و از اینکار صرف‌نظر کردیم. برای هدف ما صدا به اندازه‌ی کافی خوب بود. بنابراین اسپیکرها را به پین‌های خروجی که روی بورد صدا در نظر گرفته بودم متصل کردم و آنها را داخل قاب روی دیواره‌ها چسباندم.</p>

<p class="center"><img src="assets/tinymac/20210726_221725.jpg" alt="" />
<em>همه آنچه برای پخش صدا از اسپیکرها نیاز است: رزبری‌پای زیرو و بورد صدا و یک جفت اسپیکر. دقت کنید که در این تصویر سیم‌ها از رو به پین‌های زیرو متصل شده‌اند در حالی که در قاب اصلی از زیر به آن لحیم شده‌اند.</em></p>

<p>برای اسپیکرها هم جای خاصی داخل بدنه در نظر گرفته نشده بود اما خوشبختانه فضا به اندازه‌ی کافی برای اسپیکرها وجود داشت.</p>

<p class="center"><img src="assets/tinymac/20210728_143409.jpg" alt="" />
<em>جای کافی برای اسپیکرها وجود داشت.</em></p>

<p class="center"><img src="assets/tinymac/20210728_144740.jpg" alt="" />
<em>بورد صدا و اسپیکرها داخل قاب اصلی. کابل‌های بورد صدا از زیر به زیرو لحیم شده‌اند چرا که کابل صفحه‌های نمایش همه فضای بیرونی را اشغال کرده است.</em></p>

<p>با نصب اسپیکرها دیگر می‌توانستیم درب قاب را ببنیدیم.</p>

<p class="center"><img src="assets/tinymac/20210728_145412.jpg" alt="" />
<em>سخت‌افزار کامل مک فسقلی با سیستم عامل رزبری (دبیان با گرافیک xfce).</em></p>

<p>با پایان کار سخت‌افزار حالا با اعتماد بنفس خیلی بیشتر می‌رویم سروقت چیزی که از آن خیلی بیشتر سردرمی‌آورم یعنی نرم‌افزار!</p>

<h2 id="نرم‌افزار"><a href="#نرم‌افزار">نرم‌افزار</a></h2>
<p>در مقایسه با ساختن کامپیوتر کوچکمان کار نرم‌افزاری زیادی نداریم. با اینحال موارد زیر را شرح می‌دهم:</p>

<ul>
  <li>سیستم عامل: فلش و بوت کردن سیستم عامل مناسب رزبری</li>
  <li>دسترسی سریال: اتصال سریال به رزبری بدون دسترسی به شبکه و مانیتور و کیبورد</li>
  <li>اتصال به وایفای: متصل شدن به شبکه‌ی خانگی</li>
  <li>دسترسی شبکه: فعالسازی ssh و اتصال به رزبری از راه دور</li>
  <li>نصب صفحه‌ی نمایش: نصب و فعالسازی overlay صفحه‌ی نمایش</li>
  <li>راه‌اندازی بورد صدا</li>
  <li>کپی‌کردن فایل‌ها</li>
  <li>برنامه‌ی اصلی:‌نوشتن یک شل‌اسکریپت ساده برای پخش موزیک و نمایش گیف آلبوم</li>
</ul>

<h3 id="سیستم-عامل"><a href="#سیستم-عامل">سیستم عامل</a></h3>
<p>در کامپیوترهای مبتنی بر چیپ‌ست‌های شرکت اینتل (معماری x86) کامپیوتر با یک برنامه‌ی کمکی در BIOS یا جدیدا UEFI بوت می‌شود. در کامپیوترهای مبتنی بر ARM بایوس یا UEFI وجود ندارد و بوت به گونه‌ی دیگری و به نوعی ساده‌تر است. ما فقط نیاز است که سیستم‌عامل مناسبی را به درستی روی یک کارت حافظه فلش کنیم و آنرا در درگاه کارتخوان رزبری‌پای زیرو وارد کنیم و کامپیوتر را روشن کنیم. یعنی فرآیند نصب و بود خلاصه می‌شود به دانلود ایمیج مناسب کامپیوتر و فلش کردن آن روی یک کارت حافظه.</p>

<p>برای کامپیوتر فسقلی‌مان ما یک کارت حافظه‌ی ۳۲ گیگاباتی استفاده کردیم (من در وسایلم داشتم). برای دانلود سیستم عامل و فلش کردن آن راه‌های زیادی هست اما ساده‌ترین آن استفاده از [ایمیجساز رزبری ]است. ایمیجساز رزبری می‌تواند همزمان سیستم عامل مناسب را دانلود کند و آن را روی کارت حافظه بنویسد. من سیستم عامل دسکتاپ رزبری را انتخاب کردم که از همه ساده‌تر است و البته با حدود ۸ گیگابایت حجم، بزرگترین آنها.</p>

<p class="center"><img src="assets/tinymac/imager.png" alt="" />
<em>ایمیجساز رزبری برای ویندوز و لینوکس و مک قابل دانلود است.</em></p>

<p>بعد از دانلود سیستم عامل و فلش کارت حافظه کافیست آن را در درگاه کارتخوان وارد کردن و زیرو را روشن کرد. شرح بدهم که هیچ یک از محصولات خانواده رزبری کلید روشن و خاموش ندارند و به محض اتصال کابل منبع تغذیه روشن می‌شوند و فرآیند بوت آغاز می‌شود. در مورد زیرو منبع تغذیه پورت میکرو usb است که باید به یک منبع تغذیه‌ی مناسب (همانگونه که پیش از این شرح آن رفت) متصل بشود.</p>

<h4 id="تنظیمات-رایج-سیستم-عامل-رزبری"><a href="#تنظیمات-رایج-سیستم-عامل-رزبری">تنظیمات رایج سیستم عامل رزبری</a></h4>
<p>رزبری‌پای را به دو شیوه می‌توان تنظیم کرد (تنظیمات صدا و HDMI و GPIO و SSH و پورت سریال و مانند اینها). یکی تغییر دو فایل موجود در پارتیشن بوت آن است: cmdline.txt و config.txt. این فایل‌ها به ترتیب پارامترهای کرنل لینوکس و تنظیمات overlay رزبری هستند (دومی ممکن است بیش از این هم باشد، دقیق نمی‌دانم). این فایل‌ها را می‌شود مستقیما با اتصال کارت حافظه به یک کامپیوتر تغییر داد بدون آنکه از رزبری‌پای استفاده کرد. ما هر دو اینها را تغییر خواهیم داد تا کارهای زیر را انجام بدهیم:</p>

<ul>
  <li>فعال و غیرفعال کردن کنسول لینوکس و پورت سریال</li>
  <li>فعال کردن خروجی صدا روی خروجی PWM</li>
  <li>فعال کردن صفحه‌ی نمایش</li>
</ul>

<p>روش دیگر تنظیم رزبری‌پای رزبری استفاده از برنامه‌ایست بنام raspi-config که از پیش روی سیستم‌عامل رزبری نصب است. ناگفته پیداست که برای استفاده از این برنامه باید به رزبری‌پای وصل شد که مستلزم دیدن خروجی (کنسول یا گرافیکی) و اتصال کیبورد و مانیتور با کابل mini hdmi و اتصال سریال یا شبکه است. اما آیا می‌شود بدون کیبورد و ماوس و اتصال شبکه و اتصال مونیتور یک رزبری‌پای را تنظیم کرد؟ بله می‌شود! با اتصال UART به اختصار آشنا شوید.</p>

<h3 id="اتصال-سریال-یا-uart"><a href="#اتصال-سریال-یا-uart">اتصال سریال یا UART</a></h3>
<p>شاید گزاف نباشد اگر بگویم که در عالم کامپیوترهای کوچک و بوردهای الکترونیکی توکار <a href="https://fa.wikipedia.org/wiki/%D9%81%D8%B1%D8%B3%D8%AA%D9%86%D8%AF%D9%87_%D9%88_%DA%AF%DB%8C%D8%B1%D9%86%D8%AF%D9%87_%D8%B3%D8%B1%DB%8C%D8%A7%D9%84_%D8%BA%DB%8C%D8%B1_%D9%87%D9%85%D8%B2%D9%85%D8%A7%D9%86_%D8%AC%D9%87%D8%A7%D9%86%DB%8C">UART</a> محبوب‌ترین روش اتصال و تبادل اطلاعات با یک دستگاه است. در این روش تنها به دو سیم احتیاج است و هیچ برنامه یا درایور خاصی نیاز نیست و در همه‌ی سیستم عامل‌ها هم فراهم است. UART یک کابل TX به معنای ترانسفر و یک کابل RX به معنای دریافت نیاز دارد. و نیز یک سیم سوم برای اتصال گراوند که بدون آن هم شاید کار کند. رزبری‌پای هم میان انبوه پین‌ها UART هم دارد. کافیست سه پین‌های ۸ (TX) و ۱۰ (RX) را به ترتیب به RX و TX یک دستگاه دیگر وصل کرد (TX یکی به RX دیگری وصل می‌شود و بلعکس). برای متصل کردن رزبری‌پای به لپ‌تاپ لینوکسی‌ام از یک تبدیل کننده‌ی سریال به USB استفاده کردم چون لپ‌تاپم خروجی UART ندارد (شاید دارد و هنوز نمی‌دانم). البته این کار خیلی رایجی است.</p>

<p class="center"><img src="assets/tinymac/20210711_133408.jpg" alt="" />
<em>اتصال به رزبری از طریق پورت سریال. در سمت راست تصویر می‌تواند تبدیل‌کننده USB-UART را که با سه سیم به پین‌های رزبری متصل شده است را ببینید.</em></p>

<p class="center"><img src="assets/tinymac/usbuart.png" alt="" />
<em>یک تبدیل‌کننده‌ی USB-UART. عکس از waveshare</em></p>

<p>برای اینکه بتوان خروجی کنسول لینوکس را به کمک UART روی کامپیوتر دید باید به غیر از اتصال صحیح کابل‌ها (TX به RX و RX به TX) رزبری‌پای را هم تنظیم کرد. یکی برای فعال کردن UART و دیگری برای فعال کردن یا اطمینان از فعال بودن کنسول لینوکس (کنسول لینوکس همه آن چیزی است که کرنل در خروجی/مانیتور به صورت متنی نمایش می‌دهد که معمولا شامل یک خط فرمان هم می‌شود). هدف اینست که روی کامپیوترمان به این خط فرمان وصل بشویم و زیرو را کنترل و تنظیم کنیم و نیز آن را به شبکه‌ی وایرلیس خانگی وصل بکنیم.</p>

<p class="center"><img src="assets/tinymac/zeropins.png" alt="" />
<em>چیدمان پین‌های رزبری‌پای زیرو و برخی از قابلیت‌های هر پین. بالا سمت راست پینهای سریال را می‌بینید. عکس از سایت pinout.xyz</em></p>

<p>برای فعال کردن UART رزبری‌پای زیرو کافیست که فایل <code dir="ltr" class="language-plaintext highlighter-rouge">/boot/config.txt</code> را روی کارت حافظه ویرایش کنیم و مطمئن شویم خط زیر در آن وجود دارد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>enable_uart=1
</code></pre></div></div>
<p>از طرفی باید فایل <code dir="ltr" class="language-plaintext highlighter-rouge">/boot/cmdline.txt</code> شامل تنظیمات زیر باشد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>console=serial0,115200 console=tty1 
</code></pre></div></div>

<p>با اطمینان از وجود این تنظیمات کافیست کارت حافظه را در زیرو قرار دهیم و آن را روشن کنیم. با این تغییرات خروجی کنسول لینوکس روی UART فراهم خواهد بود. برای دیدن آن (و گرفتن یک خط فرمان) کافیست از برنامه‌ای مانند picocom برای اتصال به پورت سریال استفاده کنیم. البته تبدیل USB-to-UART ما باید وصل باشد. با فرض اینکه تبدیل با اتصال تبدیل، یک پورت سریال در آدرس <code dir="ltr" class="language-plaintext highlighter-rouge">/dev/ttyUSB0</code> باز شده است به آن وصل می‌شویم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rock@rock:~$ sudo picocom -b 115200 /dev/ttyUSB0
</code></pre></div></div>

<p>ممکن است تبدیل‌کننده در آدرسی به جز این پدیدار بشود. اگر پیش از اتصال تبدیل‌کننده فرمان <code dir="ltr" class="language-plaintext highlighter-rouge">sudo dmesg -w</code> را در یک ترمینال باز کرده باشیم در خروجی لاگ کرنل خواهیم دید که تبدیل‌کننده در چه آدرسی در دسترس قرار می‌گیرد.</p>

<p>اگر همه چیز درست پیش رفته باشد از این مرحله به بعد ما یک خط فرمان خواهیم داشت که می‌توانیم با نام کاربری pi و پسورد دیفالت raspberry در سیستم وارد شویم و کارمان را ادامه دهیم. اگر در این کار موفق نشدید وحشت نکنید. رزبری‌پای را با یک کابل mini hdmi به یک مانیتور وصل کنید و به کمک یک مبدل micro USB به USB A (معمول) یک کیبورد و ماوس به آن وصل کنید و کار را دنبال کنید.</p>

<p>من تنها حین راه‌اندازی اولیه و ساخت بورد صوتی از خروجی سریال استفاده کردم. چرا که به محض فعالسازی صفحه‌ی نمایش پین‌هایی که برای سریال بکار رفته برای صفحه‌ی نمایش نیاز است و بنابراین باید UART را غیرفعال می‌کردم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>enable_uart=0
</code></pre></div></div>
<h3 id="اتصال-به-وایفای"><a href="#اتصال-به-وایفای">اتصال به وایفای</a></h3>
<p>برای نصب بسته‌های نرم‌افزاری لازم و نیز اتصال از طریق شبکه نیاز است زیرو را به شبکه خانگی و اینترنت متصل کنیم. از جایی که ما رزبری‌پای زیرو نسخه وایفای سفارش داده‌ایم می‌توانیم آنرا به شبکه وایرلس خانگی متصل کنیم. برای اینکار از wpa_supplicant استفاده می‌کنیم. این ابزار از پیش روی سیستم‌عامل رزبری نصب است. مطابق <a href="https://www.raspberrypi.org/documentation/configuration/wireless/headless.md">مستندات رزبری</a> کافیست فایل <code dir="ltr" class="language-plaintext highlighter-rouge">/etc/wpa_supplicant/wpa_supplicant.conf</code> را تغییر بدهیم و سرویس wpa_supplicant را فعال و کامپیوتر را ریبوت کنیم. به فایل بالا کد کشور و نام و پسورد وایفای خانگی را اضافه می‌کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
country=IR
update_config=1

network={
 ssid="&lt;Name of your wireless LAN&gt;"
 psk="&lt;Password for your wireless LAN&gt;"
}
</code></pre></div></div>

<p>علت اضافه کردن کد کشور اینست که چیپ وایرلس فرکانس صحبح آن کشور را بکار بگیرد و در ارتباطات رادیویی دیگر اختلال ایجاد نکند. بعد سرویس را فعال و استارت کنید و بعد ریبوت:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo systemctl enable wpa_supplicant.service 
$ sudo systemctl start wpa_supplicant.service 
$ sudo reboot
</code></pre></div></div>

<p>بعد از ریبوت باید اتصال شبکه و اینترنت (اگر برقرار باشد) فراهم شده باشد. یک پینگ ساده معمولا برای بررسی این موضوع کافیست:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rock@rock:~$ ping 1.1
PING 1.1 (1.0.0.1) 56(84) bytes of data.
64 bytes from 1.0.0.1: icmp_seq=1 ttl=49 time=141 ms
64 bytes from 1.0.0.1: icmp_seq=2 ttl=49 time=145 ms
64 bytes from 1.0.0.1: icmp_seq=3 ttl=49 time=391 ms
^C
--- 1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 140.939/225.884/391.216/116.922 ms
</code></pre></div></div>
<p>بد نیست اشاره کنم که با در نهایت پس از تنظیم صفحه‌ی نمایش و صفحه‌ی لمسی حتی بدون کیبورد و ماوس می‌شود از این کامپیوتر کوچک استفاده کرد و مثلا به وایفای خانگی متصل شد. فقط باید برای تایپ پسورد از صفحه کلید کوچک مجازی که از پیش روی سیستم عامل نصب است بکار گرفت. آن را می‌توان از منوی برنامه‌ها پیدا کرد.</p>

<p>حال با برقراری اتصال وایرلس و اینترنت می‌رویم سروقت بخش بعدی: فعالسازی ssh.</p>

<h3 id="فعالسازی-ssh-و-اتصال-به-رزبری-از-راه-دور"><a href="#فعالسازی-ssh-و-اتصال-به-رزبری-از-راه-دور">فعالسازی ssh و اتصال به رزبری از راه دور</a></h3>
<p>فعالسازی ssh اجازه می‌دهد که بدون اتصال مانیتور و کیبورد و بدون دسترسی به پورت سریال به کامپیوتر وصل شد و دستوراتی را اجرا کرد. برای فعالسازی آن روی رزبری دو راه وجود دارد. یکی قرار دادن یک فایل خالی به نام ssh در پارتیشن بوت کارت حافظه قبل از اولین بوت رزبری است، یعنی بلافاصله بعد از فلش کردن کارت حافظه. روش دوم به کمک خط فرمان است، یعنی یا باید از طریق کنسول یا با کیبورد و مانیتور به رزبری وصل شده باشیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo systemctl enable ssh
$ sudo systemctl start ssh
</code></pre></div></div>

<p>تمام این روش‌ها [در بخش ssh مستندات رزبری] شرح داده شده است. از جایی که برای فعالسازی صفحه‌ی نمایش باید UART را غیرفعال می‌کردم فعالسازی ssh ضروری بود. از اینجا به بعد تمام دستورات از طریق ssh انجام شده است. برای پیدا کردن آی پی رزبری هم کافیست در ترمینال دستور <code dir="ltr" class="language-plaintext highlighter-rouge">ip addr show</code> را وارد کنید یا در مودم آن را پیدا کنید.</p>

<p>مرحله بعدی نصب صفحه‌ی نمایش است.</p>

<h3 id="نصب-صفحه‌ی-نمایش"><a href="#نصب-صفحه‌ی-نمایش">نصب صفحه‌ی نمایش</a></h3>
<p>برای نصب صفحه‌ی نمایش من <a href="https://wiki.geekworm.com/index.php/2.8_inch_Touch_Screen_for_Pi_zero">راهنمای سازنده</a> را دنبال کردم:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ git clone https://github.com/tianyoujian/MZDPI.git
$ cd MZDPI/vga
$ sudo chmod +x mzdpi-vga-autoinstall-online
$ sudo ./mzdpi-vga-autoinstall-online
$ sudo reboot
</code></pre></div></div>

<p>اگر نصب به درستی انجام شود بجز اضافه شدن یک یا چند فایل جدید به پوشه‌ی <code dir="ltr" class="language-plaintext highlighter-rouge">/boot/overlays</code> تنظیمات زیر به انتهای فایل config.txt اضافه خواهد شد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#gpio=18=op,dh
gpio=7-8=a2
dtparam=spi=on
dtoverlay=ads7846,penirq=27,swapxy=1,xmin=200,xmax=3850,ymin=200,ymax=3850
display_rotate=3
dtoverlay=mzdpi
framebuffer_width=640
framebuffer_height=480
enable_dpi_lcd=1
display_default_lcd=1
dpi_group=2
dpi_mode=87
dpi_output_format=0x07f003
hdmi_timings=480 0 41 20 60 640 0 5 10 10 0 0 0 60 0 32000000 1
</code></pre></div></div>
<p>البته خط اول را من کامنت کرده‌ام چرا که به گمانم اسکرین با PWM روی این پین کانفلیکت داشت و من کاربری دیگری برای این پین تعریف کرده بودم (PWM). درس حاشیه‌ای اینست که اگر گزارش طویل را هنگام ساخت اندک اندک نوشته بودم الان بهتر بخاطر داشتم که چرا اینکار را کرده‌ام!!</p>

<p>این دستورات هم کار محیرالعقولی انجام نمی‌دهد. اصل کارش اینست که Device Tree Overlay این صفحه‌ی نمایش را دانلود و کامپایل و نصب می‌کند. نصب هم چیزی جز کپی کردن در مسیری در پارتیشن بوت و افزودن چند خط به فایل config.txt نیست.</p>

<h4 id="توضیح-کوتاه-در-مورد-device-tree"><a href="#توضیح-کوتاه-در-مورد-device-tree">توضیح کوتاه در مورد <a href="https://www.raspberrypi.org/documentation/configuration/device-tree.md">Device Tree</a></a></h4>
<p>وقتی ما یک وسیله‌ی USB به یک دستگاه وصل می‌کنیم آن وسیله طبق پروتکل USB با کامپیوتر صحبت می‌کند. اما وقتی یک وسیله به چند یا چندین پین رزبری‌پای متصل می‌کنیم چه اتفاقی می‌افتد؟ آنجا دیگر USB یا مانند آن در کار نیست، بلکه قطعات با پروتکل‌هایی مانند SPI و I²C یا UART با رزبری‌پای ارتباط برقرار می‌کنند. برای اینکه سیستم عامل این قطعات را بفهمد نیاز به چیزی شبیه به درایور است که آن سخت‌افزار جانبی را تعریف کند و عملکردش را شرح بدهد. بواسطه‌ی پیچیدگی SoCهای امروزی و نیز تنوع زیاد HATها، رزبری‌پای و کرنل لینوکس از Device Tree و overlayها برای فهمیدن سخت‌افزارهای مختلف استفاده می‌کنند.</p>

<p>اما یک overlay چیست؟</p>

<p>کرنل‌های رزبری‌پای و Firmware آن برای شرح سخت‌افزار موجود در رزبری‌پای از Device Tree یا «درخت تجهیزات» استفاده می‌کنند. اگر با سیستم‌های فایل یونیکسی آشنا باشید، می‌دانید که فایل‌سیستم از چشم کرنل مثل یک درخت است. ریشه روت است یعنی <code dir="ltr" class="language-plaintext highlighter-rouge">/</code> و «همه چیز فایل است». مثلا پیشتر برای وصل شدن به تبدیل کننده‌ی UART به USB با یک برنامه فایلی بنام <code dir="ltr" class="language-plaintext highlighter-rouge">/dev/ttyUSB0</code> را باز کردیم یا مثلا فایل‌های کاربر در «خانه‌ی» او قرار دارند مثلا <code dir="ltr" class="language-plaintext highlighter-rouge">/home/pi</code>.  همین سبک در Device Tree بکار رفته و در بخشی مشترک مشخصات سی‌پی‌یو و حافظه‌ی موجود در دستگاه و جزئیات مشترک تعریف شده و سایر سخت‌افزارهای دلبخواهی هر یک این درخت اصلی را توسعه می‌دهند و آن را با مشخصات خودشان بروز می‌کنند. به این بخش‌های اضافی می‌گویند overlay.</p>

<p>برای فعال‌کردن overlayهای مختلف باید در فایل config.txt خطی مانند dtoverlay=… اضافه کرد. هر Device Tree Overlay هم می‌تواند تنظیماتی داشته باشد که با کلید dtparams=… در فایل کانفیگ اضافه می‌شود. اسکریپت بالا اینکار را برای صفحه‌ی نمایش ما انجام می‌دهد. شرح بیشتر این موضوع از حوصله‌ی این مقاله خارج است.</p>

<h3 id="راه‌اندازی-بورد-صدا"><a href="#راه‌اندازی-بورد-صدا">راه‌اندازی بورد صدا</a></h3>
<p>بورد صدای ما هم به مانند صفحه‌ی نمایش نیاز به تغییراتی در config.txt به شرح زیر دارد:</p>

<ul>
  <li>فعال کردن overlay برای PWM</li>
  <li>تنظیم GPIOهای لازم برای PWM</li>
  <li>تنظیم ALSA برای کار با PWM</li>
</ul>

<p>در این مورد البته کار ساده‌تر است. مورد اول و دوم را با هم در یک خط به config.txt اضافه می‌کنیم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dtoverlay=pwm-2chan,pin=18,func=2,pin2=19,func2=2
</code></pre></div></div>
<p>این خط GPIO شماره ۱۸ و ۱۹ را برای PWM0 و PWM1 تنظیم می‌کند. برای اطلاعات بیشتر سورس <a href="https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/overlays/pwm-2chan-overlay.dts">pwm-2chan overlay</a> را بخوانید.</p>

<p>به محض اضافه کردن این خط و حتی بدون تنظیمات صدای لینوکس می‌توان مستقیما روی GPIO شماره ۱۸ و ۱۹ موزیک پخش کرد! البته فقط با برنامه‌ی زیر که برای رزبری‌پای ساخته شده:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ omxplayer &lt;somemusic.mp3&gt; --adev local
</code></pre></div></div>
<p>در ویدیوی زیر با پورت سریال به رزبری وصل می‌شوم و آهنگ بازی Hotline Miami را پخش می‌کنم.</p>

<video controls="" src="assets/tinymac/20210726_221746.mp4" poster="assets/tinymac/20210726_221725.jpg" width="100%">
متاسفانه براوزر شما ویدیوهای توکار را پشتیبانی نمی‌کند. شما می‌توانید این ویدیو را مستقیما 
<a href="assets/tinymac/IMG_3819.mp4">از اینجا </a>
دانلود و با پلیر دلخواهتان تماشا کنید!
</video>

<p>اگر یک اسیلوسکوپ به این پین‌ها وصل کنید جهش‌های ولتاژ را خواهید دید. با وصل کردن مستقیم یک هدفن هم باید چیزی شبیه موزیک پخش شود اما مواظب گوش خودتان باشید چرا که ممکن است صدای زیاد ناگهانی به گوش صدمه بزند.</p>

<p>تنظیمات بالا هرچند برای پخش صدا با دستوری که گفتیم کفایت می‌کند اما اگر دسکتاپ را بوت کنید متوجه می‌شوید که هیچ برنامه‌ای قادر به پخش صدا نخواهد بود و از دید لینوکس کارت صوتی وجود ندارد. برای این مشکل کافیست پارامتر زیر را به کرنل رزبری‌پای با ویرایش فایل cmdline.txt پاس بدهیم تا کرنل سخت‌افزارهایی را شبیه‌سازی بکند که ALSA (مخفف Advanced Linux Sound Archiitecture) یک سخت‌افزار صوتی ببیند و بتواند خروجی صدای برنامه‌ها را به آن هدایت بکند:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>snd_bcm2835.enable_compat_alsa=1
</code></pre></div></div>

<p>و ریبوت. کانفیگ‌فایل‌های نهایی را می‌توانید با کلیک روی <a href="assets/tinymac/config.txt">config.txt</a> و <a href="assets/tinymac/cmdline.txt">cmdline.txt</a> دانلود کنید. حالا بالاخره بعد از طی راهی طولانی می‌توانیم برویم سروقت پخش موزیک و گیف.</p>

<h3 id="برنامه‌ی-اصلی‌نوشتن-یک-شل‌اسکریپت-ساده"><a href="#برنامه‌ی-اصلی‌نوشتن-یک-شل‌اسکریپت-ساده">برنامه‌ی اصلی:‌نوشتن یک شل‌اسکریپت ساده</a></h3>
<p>حالا با در دست داشتن یک کامپیوتر معمولی که می‌تواند صدا و گرافیک پخش بکند کافیست به آن بگوییم هر بار که بوت می‌شود یک گیف را در حالت تمام صفحه پخش بکند و همزمان تعدادی موزیک به ترتیب از اسپیکرها پخش بشود. یعنی دو کار زیر:</p>

<ul>
  <li>اسکریپتی که گیف و آلبوم صوتی را پخش بکند.</li>
  <li>تنظیماتی که این اسکریپت پس از هر بوت اجرا بشود.</li>
</ul>

<p>اول می‌خواستم برای این کار برنامه‌ای با پایتون بنویسم. اما دیدم با شل اسکریپت بسیار ساده‌تر است. از سویی می‌خواستم که بشود از کامپیوتر بدون این برنامه هم استفاده کرد. بنابراین روشی را انتخاب کردم که مانع استفاده عادی از کامپیوتر نشود. اسکریپت ما یک برنامه را در حالت تمام صفحه باز می‌کند که می‌توان آن را با فشردن کلید ESC یا با لمس صفحه نمایش و لمس دگمه‌ی ضربدر پنجره بست. از سوی دیگر پس از پخش همه‌ی فایل‌های صوتی خود به خود برنامه تمام شده و پنجره بسته خواهد شد.</p>

<p>ابتدا فایل‌های لازم شامل گیف و ترک‌های آلبوم صوتی را در پوشه‌ی خانه/home روی کارت حافظه کپی کردم. من اینکار را با scp انجام دادم.سپس <a href="assets/tinymac/rangi.sh">شل اسکریپت</a> زیر را برای برنامه اصلی نوشتم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/bin/bash

sleep 5

cd /home/pi/Rangi

IFS=$(echo -en "\n\b")

sxiv -bfa rangi.gif &amp;

for i in $(ls *.mp3); do 
	omxplayer "$i" --adev local
done;

</code></pre></div></div>
<p>برنامه چه کار می‌کند؟ خط اول که به Shebang معروف است می‌گوید در صورتی که این فایل به صورت مستقیم اجرا شود کدام برنامه باید آن را هندل کند. بعد برنامه در صورت اجرا ۵ ثانیه به خواب می‌رود. اینکار برای این لازم بود تا اجازه دهد دسکتاپ رزبری کامل لود شود، در غیر اینصورت پنجره بعدی تمام صفحه نمی‌شد. بعد برنامه مسیر جاری خودش را به فولدری که حاوی فایل‌های صوتی و تصویری است تغییر می‌دهد. خط بعدی که حاوی IFS به bash می‌گوید که برای جدا کردن خروجی دستوراتی مانند ls از newline استفاده کند. دیفالت space است.</p>

<p>خط بعدی به کمک برنامه‌ی sxiv که مخفف Simple X Image Viewer است گیف را در حالت تمام صفحه باز می‌کند و آن را به بک‌گراند می‌فرستد. هر فرمانی که &amp; در انتها داشته باشد می‌رود به بک‌گراند و اجرای آن ادامه پیدا می‌کند و شل می‌رود سروقت فرمان بعدی.</p>

<p>بعد یک لوپ ساده داریم. روی خروجی دستوری <code dir="ltr" class="language-plaintext highlighter-rouge">ls *.mp3</code> لوپ می‌زنیم (که با newline تفکیک خواهد شد) و به ازای هر خروجی با برنامه‌ی omxplayer آن فایل را پخش می‌کنیم.</p>

<p>تنها لازم بود برنامه‌ی sxiv را روی رزبری نصب کنم که با دستورات زیر انجام شد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt update
$ sudp apt install sxiv
</code></pre></div></div>

<p>اسکریپت را هم قابل اجرا کردم که بتوان آن را مستقیم اجرا کرد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ chmod +x rangi.sh
</code></pre></div></div>

<h4 id="اجرای-خودکار-اسکریپت-پس-از-بوت"><a href="#اجرای-خودکار-اسکریپت-پس-از-بوت">اجرای خودکار اسکریپت پس از بوت</a></h4>
<p>سیستم‌عامل رزبری از دسکتاپ XFCE استفاده می‌کند. بنابراین من برای اجرای خودکار اسکریپت پس از هر بوت از قابلیت autostart در XFCE استفاده کردم. برای اینکار فایلی بنام <code dir="ltr" class="language-plaintext highlighter-rouge">rangi.desktop</code> با محتویات زیر ساختم و در مسیر <code dir="ltr" class="language-plaintext highlighter-rouge">/etc/xdg/autostart/</code> کپی کردم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[Desktop Entry]
Name=Rangi
Exec=/home/pi/Rangi/rangi.sh
</code></pre></div></div>
<p>این باعث می‌شود که شل اسکریپت ما پس از هر بوت به دسکتاپ اجرا شود. و تمام.</p>

<h3 id="خلاصه"><a href="#خلاصه">خلاصه</a></h3>
<p>در این مقاله شرح دادیم که چطور یک کامپیوتر کوچک ساختیم. کامپیوتری با صفحه‌ای لمسی و دو اسپیکر توکار و نیز پیچ تنظیم بلندی صدا و یک خروجی ۳.۵ میلیمتری صوتی و یک بدنه چاپ شده توسط یک چاپگر سه بعدی. به تفصیل چگونگی ساخت یک بورد صوتی را شرح دادیم و مداری برای آن طراحی کردیم. و نیز نحوه اتصال از طریق پورت سریال و شبکه را نشان دادیم و Overlay‌های لازم را راه‌اندازی کردیم.</p>

<p>ویدیوی زیر توسط شایگان ادیت شده که خروجی نهایی را نمایش می‌دهد.</p>

<video controls="" src="assets/tinymac/IMG_3819.mp4" poster="assets/tinymac/20210728_145412.jpg" width="100%">
متاسفانه براوزر شما ویدیوهای توکار را پشتیبانی نمی‌کند. شما می‌توانید این ویدیو را مستقیما 
<a href="assets/tinymac/IMG_3819.mp4">از اینجا </a>
دانلود و با پلیر دلخواهتان تماشا کنید!
</video>

<p>مقاله‌ای بود بسیار طولانی در مورد پروژه‌ای طولانی! امیدوارم برای علاقه‌مندی مفید فایده بشود. زنده باشید.</p>

</div>]]>
    </content>
    <summary>در این پست شرح می‌دهم چطور به همراه شایگان یک کامپیوتر فسقلی با صفحه لمسی و بلندگوی توکار در ابعاد بسیار کوچک ساختیم تا آن را به دوستش هدیه بدهد. از جایی که این مقاله بسیار طولانی است، جایی را بخوانید که بدرد کارتان می‌خورد. شروع ماجرا ماجرا از آنجا شروع شد که شایگان با من برای ساخت و سرهم کردن یک کامپیوتر کوچک و نسبتا ارزان مبتنی بر رزبری‌پای تماس گرفت. ایده‌اش این بود که این کامپیوتر به محض روشن شدن تصویر گیف آلبوم صوتی مورد علاقه دوستش را، در حالی که همزمان تعدادی ترانه از آن آلبوم را...</summary>
  </entry>

<entry>
    
    <id>https://mehdix.ir/irc-bouncer.html</id>
    
    <title>راه‌اندازی باونسر آی‌آر‌سی</title>
    <updated>2021-06-13T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/irc-bouncer.html"/>
    <category term="irc"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>قبلا در مورد <a href="irc-with-screen.html">پروتکل چت اینترنتی</a> بنام <a href="irc.html">irc</a> نوشته‌ام. اینبار در مورد znc (یک باونسر) و weechat و revolution irc می‌نویسم.</p>

<p>آی‌آر‌سی یک پروتکل قدیمی است که هنوز هم میان کاربران نرم‌افزار آزاد به خاطر سادگی‌اش محبوبیت دارد. بویژه از این جهت که در ترمینال یک سرور می‌توانید برنامه‌ی چت را باز کنید و از آن استفاده کنید. منتها سرور پیام‌ها را فقط به کاربرانی که در لحظه به سرور متصل هستند ارسال می‌کند و به تازه‌واردین (یا کسانی که اتصالشان قطع و وصل شده است) پیام‌های قبلی را ارسال نمی‌کند. برای رفع این مشکل قبلا از screen و irssi و نیز برای مدتی از thelounge استفاده می‌کردم. اما روش درست استفاده از یک «باونسر» آی‌آر‌سی است.</p>

<p>باونسر یک برنامه است که روی یک کامپیوتر همیشه روشن (مثلا یک رزبری‌پای در منزل) جا خوش کرده است و به نمایندگی از شما به اتاق‌های مختلف وصل می‌شود و همانجا حاضر می‌ماند و مکالمات را دریافت و ذخیره می‌کند. ما هم بجای وصل شدن به سرورهای اصلی به باونسر وصل می‌شویم که پیام‌های قبلی را ذخیره کرده است. وصل شدن به یک باونسر مثل وصل شدن به یک سرور آی‌آر‌سی است.</p>

<h2 id="وضعیت-فارسی‌نویسی-در-آی‌آر‌سی"><a href="#وضعیت-فارسی‌نویسی-در-آی‌آر‌سی">وضعیت فارسی‌نویسی در آی‌آر‌سی</a></h2>
<p>متاسفانه آی‌آر‌سی در ترمینال به جهت ساپورت بسیار ضعیف کنسول لینوکس و نیز ترمینال‌های موجود از حروف عربی کاربرد چندانی برای فارسی‌نویسی ندارد. اما از جایی که معماری‌ آی‌آر‌سی کلاینت سرور است (یعنی اتاق‌ها روی یک سرور قرار دارد)، کلاینت‌های متنوعی برای آن وجود دارد که کاربران از آن طریق به سرور و اتاق‌ها وصل می‌شوند. و خوشبختانه کلاینت‌های گرافیکی برای لینوکس و اندروید مشکلی با متن فارسی ندارند.</p>

<h2 id="znc"><a href="#znc">znc</a></h2>
<p>یکی از باونسرهای قدیمی و جاافتاده <a href="https://wiki.znc.in/ZNC">znc</a> است. نصب این برنامه روی سرور اوبونتو کار تقریبا بی‌دردسری بود:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install znc
sudo -u _znc znc --makeconf
</code></pre></div></div>

<p>دستور بالا برای تنظیم اولیه‌ی znc است (اوبونتو از یوزر <code dir="ltr" class="language-plaintext highlighter-rouge">_znc</code> برای znc استفاده می‌کند). باید آدرس سرور مقصد و پورت و یک نام برای آن و نیز نیک‌نیم دلخواهمان را وارد کنیم. من مقادیر زیر را وارد کردم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server name:	libera
server:		irc.libera.chat
server port:	6697
nick:		mehdix
</code></pre></div></div>

<p>از شما یک پسورد هم خواسته می‌شود برای اتصال به سرور که وارد کنید. بعد از اینها باید بشود یونیت systemd مربوطه را استارت کرد که البته روی اوبونتوی ۲۰ استارت نشد. علت هم نقص در کانفیگ systemd بود که اوبونتو برای znc اضافه کرده است که اصلاح کردم (هرچقدر یک سیستم عامل برنامه‌ها را کمتر دستکاری کند بهتر است):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Edit /lib/systemd/system/znc.service
# Change this line:
ExecStart=/usr/bin/znc -f --datadir=/var/lib/znc/
# to:
ExecStart=/usr/bin/znc -f --datadir=/var/lib/znc/.znc/
</code></pre></div></div>

<p>کار بالا را می‌شود در یک خط هم انجام داد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># sed 's/\/znc\//\/znc\/.znc\//' /lib/systemd/system/znc.service &gt; /lib/systemd/system/znc.service
</code></pre></div></div>

<p>بعد از هر تغییر در فایل‌های systemd باید آنرا ریلود کرد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># systemd --daemon-reload
</code></pre></div></div>

<p>مطمئن شوید znc در حال اجرا نیست و سرویس systemd را فعال و استارت کنید:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo killall znc
$ sudo systemctl enable --now znc.service
</code></pre></div></div>

<h2 id="چرا-سرور-لیبرا-چت"><a href="#چرا-سرور-لیبرا-چت">چرا سرور لیبرا چت؟</a></h2>
<p>مدتی پیش مالک جدید برزگترین سرور آی‌آر‌سی بنام Freenode سیاست‌های جدیدی در پیش گرفت که منجر به ترک این شرکت توسط بخش بزرگی از کارمندان و راه‌اندازی <a href="https://libera.chat/">Libera.Chat</a> شد. فری‌نود هم اتاق هر کسی که اسم لیبرا چت آورد را بست. بخش مهمی از کامیونیتی هم به لیبراچت مهاجرت کرد.</p>

<h2 id="کلاینت‌ها"><a href="#کلاینت‌ها">کلاینت‌ها</a></h2>
<p>برای اتصال به باونسر znc من سه برنامه را امتحان کردم که همگی بدون مشکل کار کردند: weechat و hexchat و revolution irc. از میان اینها weechat برای ترمینال است و hexchat برای ویندوز و لینوکس و revolution irc برای اندروید.</p>

<p>روی ویکی znc <a href="https://wiki.znc.in/Weechat">تنظیمات وی‌چت</a> و نیز <a href="https://wiki.znc.in/HexChat">تنظیمات هگزچت</a> دقیقا شرح داده شده، بنابراین از تکرار آن خودداری می‌کنم. روی اندروید من از برنامه‌ی آزاد و خوب <a href="https://github.com/MCMrARM/revolution-irc">revolution irc</a> استفاده کردم (نصب از F-Droid). اتصال به باونسر هم ساده بود، کافی بود آدرس سرور و پورت و نیک و پسوردی که در ابتدا انتخاب کرده بودم وارد کنم. این هم نتیجه:</p>

<p class="center"><img src="assets/pimg/revolution_irc.jpg" alt="revolution irc" /></p>

<h2 id="کانال-مهدیکس-روی-لیبراچت-بعضی‌ها-می‌خوانند-لینود"><a href="#کانال-مهدیکس-روی-لیبراچت-بعضی‌ها-می‌خوانند-لینود">کانال مهدیکس روی لیبراچت (بعضی‌ها می‌خوانند لینود)</a></h2>
<p>به بهانه‌ی این مقاله یک کانال آی‌آر‌سی روی لیبراچت برای خوانندگان این وبسایت ایجاد کردم. فقط کافی بود روی یکی از کلاینت‌هایی که بالاتر تنظیم کرده‌ام دستور زیر را اجرا کنم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/join #mehdix.ir
</code></pre></div></div>

<p>از جایی که این کانال وجود نداشت ساخته شد (البته من پیشتر آی‌دی مهدیکس را روی لیبرا رجیستر کرده بودم). من این کانال را همواره باز نگه خواهم داشت. خواستید آی‌آر‌سی تمرین کنید دریغ نکنید.</p>

</div>]]>
    </content>
    <summary>قبلا در مورد پروتکل چت اینترنتی بنام irc نوشته‌ام. اینبار در مورد znc (یک باونسر) و weechat و revolution irc می‌نویسم. آی‌آر‌سی یک پروتکل قدیمی است که هنوز هم میان کاربران نرم‌افزار آزاد به خاطر سادگی‌اش محبوبیت دارد. بویژه از این جهت که در ترمینال یک سرور می‌توانید برنامه‌ی چت را باز کنید و از آن استفاده کنید. منتها سرور پیام‌ها را فقط به کاربرانی که در لحظه به سرور متصل هستند ارسال می‌کند و به تازه‌واردین (یا کسانی که اتصالشان قطع و وصل شده است) پیام‌های قبلی را ارسال نمی‌کند. برای رفع این مشکل قبلا از screen و irssi...</summary>
  </entry>

<entry>
    
    <id>https://mehdix.ir/why.html</id>
    
    <title>چرا از فلان چیز استفاده می‌کنم؟</title>
    <updated>2021-05-27T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/why.html"/>
    <category term="ابزار"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>همانطور که از نوشته‌های اخیرم پیداست در حال کوچکسازی جعبه‌ی‌ابزار فنی و ذهنی‌ام هستم. برای کشف چیزهایی که باید مرخص بشوند یک تکنیک ساده پیدا کرده‌ام که شرح می‌دهم.</p>

<p>این تکنیک چیزی جز یک پرسش ساده نیست. آگاهانه ابزارهای مورد استفاده‌ام را مورد پرسش قرار می‌دهم. مثلا از خودم می‌پرسم چرا من از zsh استفاده می‌کنم؟ اگر بتوانم به این پرسش پاسخ درخوری بدهم و دلیل قانع‌کننده‌ای داشته باشم آن ابزار سرجایش باقی می‌ماند. اگر نتوانم به این پرسش پاسخ بدهم آن ابزار یا تکنولوژی را با یک چیز ساده‌تر جایگزین می‌کنم یا کلا کنار می‌گذارم.</p>

<p>مثلا در مثال zsh من نتوانستم به پرسش خودم جواب بدهم. پاسخ‌های جسته و گریخته‌ای دادم ولی پاسخ قانع‌کننده‌ای نداشتم. فهمیدم که بلد نبودن کار با bash (که شل پیشفرض سیستم عامل‌های من بوده است) مهمترین دلیلم بوده است. هر چیزی که گفتم با zsh می‌توانم انجام بدهم دیدم که با bash هم می‌شود. البته zsh ویژگی‌های مهمی دارد که فهمیدم من نه به درستی از آنها اطلاع دارم نه هرگز استفاده کرده‌ام. یعنی نادانی از آنچه با ابزار ساده‌تر و پیش‌فرض مقدور بوده باعث شده که ابزار جدیدی به زندگی‌ام اضافه کنم بدون آنکه هیچ کدام را به درستی فرا بگیرم و از مزایای آنها بهره‌مند شوم. بنابراین zsh را بازنشست کردم و به bash برگشتم.</p>

<p>بعد از خودم پرسیدم که آیا من به bash احتیاج دارم؟ شاید sh (همان bourne shell) برای من کفایت کند؟ فعلا با هر دو کار می‌کنم و جرئت نکردم کامل سراغ sh بروم که بزرگترین مخرج مشترک شل‌های رایج است. حسن این دو اینست که تقریبا جهانشمول هستند و روی توزیع‌های مخلتف لینوکس و BSD و مک و مانند اینها یافت می‌شود. از سوی دیگر من از ایمیج‌های Alpine به شدت استفاده می‌کنم که پیشفرض از bourne shell استفاده می‌کند و بنابراین می‌خواهم به نوشتن ساده‌ترین شکل‌اسکریپت ممکن عادت بکنم و در همان محیط هم کار بکنم.</p>

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

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ exec sway
</code></pre></div></div>

<p>(دستور exec پراسس جاری(شل) را با پراسس جدید جایگزین می‌کند.)</p>

<p>یک عکس هم ضرر ندارد:</p>

<p><img src="assets/pimg/ps_20210527214702.png" alt="sway" /></p>

<p>ممکن است بپرسید علت این حساسیت چیست؟ من روزانه حداقل ده ساعت با کامپیوتر کار می‌کنم. هر انتخاب اشتباهم در صدها و بلکه هزاران ساعت تکثیر می‌شود. هر ابزار جدید مشکلاتی با خودش به همراه می‌آورد. باید آنرا نصب کرد، فرا گرفت و از آن نگهداری کرد. ذهن ما را درگیر می‌کند. بنابراین از بکارگیری ابزار جدید بدون دلیل محکم خودداری می‌کنم و به جای آن سعی می‌کنم ابزارهای رایج یونیکس را بهتر یاد بگیرم. مثلا برای فراگیری شل اواخر <a href="https://www.grymoire.com/Unix/Sh.html">این مقاله‌ی مفصل</a> را مطالعه کردم که فورا نتایجش را در طول هفته حس کردم (اسکریپت‌های مختلف را فهمیدم، ضعف‌هایشان را دیدم و شروع کردم به نوشتن).</p>

</div>]]>
    </content>
    <summary>همانطور که از نوشته‌های اخیرم پیداست در حال کوچکسازی جعبه‌ی‌ابزار فنی و ذهنی‌ام هستم. برای کشف چیزهایی که باید مرخص بشوند یک تکنیک ساده پیدا کرده‌ام که شرح می‌دهم. این تکنیک چیزی جز یک پرسش ساده نیست. آگاهانه ابزارهای مورد استفاده‌ام را مورد پرسش قرار می‌دهم. مثلا از خودم می‌پرسم چرا من از zsh استفاده می‌کنم؟ اگر بتوانم به این پرسش پاسخ درخوری بدهم و دلیل قانع‌کننده‌ای داشته باشم آن ابزار سرجایش باقی می‌ماند. اگر نتوانم به این پرسش پاسخ بدهم آن ابزار یا تکنولوژی را با یک چیز ساده‌تر جایگزین می‌کنم یا کلا کنار می‌گذارم. مثلا در مثال zsh...</summary>
  </entry>

<entry>
    
    <id>https://mehdix.ir/hastasiempre-netlify.html</id>
    
    <title>بدرود نتلیفای</title>
    <updated>2021-05-22T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/hastasiempre-netlify.html"/>
    <category term="نتلیفای"/><category term="ایمیل"/><category term="ماتریکس"/><category term="کامنت‌دونی"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>بعد از سالها استفاده از نتلیفای بالاخره زمان مهاجرت فرا رسید، البته به سرور خودم.</p>

<p>دیروز اول دیدگاه‌های خوانندگان را از سرور نتلیفای استخراج کردم (اسکریپت بیلدم اینکار را انجام می‌دهد) و سایت را لوکال ساختم و در سرور خودم کپی کردم (با scp). سپس مشخصات سرویس DNS سرویس‌دهنده‌ی سرور مجازی‌ام را در nic.ir وارد کردم. (پیش از این از سرویس DNS رایگان نتلیفای استفاده کرده بودم.) روی صفحه‌ی ادمین سرویس‌دهنده‌‌ام هم آی‌پی‌های سرور را به دامنه متصل کردم. بعد اول تنظیمات دامنه را از نتلیفای حذف کردم. تقریبا درجا سایت از کار افتاد. بعد خود سایت را از نتلیفای حذف کردم و بعد هم اکانتم را.</p>

<p>سایت همانطور که پیش‌بینی می‌کردم از کار افتاد. عجله‌ای نداشتم. تقریبا دو ساعتی طول کشید تا تغییرات از nic.ir به سایر بخش‌های اینترنت برسد. التبه این را امروز به کمک یک سرویس کوچک دیگر (که قصد بازنشسته کردنش را دارم) متوجه شدم. این سرویس کوچک در فواصل زمانی مشخص سرور را پینگ می‌کند و اگر جوابی نیامد ایمیل می‌زند که سرور داون است. وقتی هم که برگشت بالا مدت داون بودن را گزارش می‌کند. من از وب‌سرور nginx استفاده می‌کنم. یک بلاک جدید برای سایت اضافه کردم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>server {
	listen 80;
	root /var/www/mehdix.ir;
	index index.html;
	server_name mehdix.ir;
	location / {
		try_files $uri $uri/ =404;
	}
}
</code></pre></div></div>

<p>بعد از این هم با کمک certbot سرتیفیکیت‌های لازم برای https را ساختم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo certbot
</code></pre></div></div>

<p>و وب‌سرور را ریلود کردم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo nginx -s reload
</code></pre></div></div>

<p>انتشار سایت هم می‌شود یک بیلد:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ bundler exec jekyll build
</code></pre></div></div>

<p>و یک کپی:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ scp -r _site mehdix.ir:/var/www/mehdix.ir;
</code></pre></div></div>

<p>حالا سایت روی سرور جدید است. همانطور که قبلا نوشتم تا اطلاع ثانوی کامنتدونی کار نمی‌کند. تا زمانی که آن را تعمیر کنم دو راه حل در نظر گرفته‌ام. یکی یک <a href="https://app.element.io/#/room/#mehdix.ir:matrix.org">کانال ماتریکس</a> است که ساخته‌ام. فعلا که خالی است اما پرسشی داشتید آنجا در خدمتم. فعلا پشه پر نمی‌زند البته. اگر اسم <a href="https://matrix.org/">ماتریکس</a> (بجز فیلم آن!) تا بحال به گوشتان نخورده نگاهی به آن بیندازید. ماتریکس یک پروتکل فدراتیو برای ارتباط امن سرتاسری است (End-to-End or e2e). یعنی سرور مرکزی ندارد و هرکس می‌تواند از یک سرور با سرورهای دیگر حرف بزند. اتاق مهدیکس که ساخته‌ام روی سرور شرکت المنت سازنده‌ی ماتریکس است. در تعریف ماتریکس هم بگویم که کل رویداد امسال <a href="https://fosdem.org/2021/">FOSDEM</a> به صورت آنلاین روی ماتریکس برگزار شد، به همراه ویدیو و صوت و چت و اموجی و مانند اینها.</p>

<p>راه دیگر گفتگو هم ایمیل است. اواخر بیش از همیشه به میلینگ‌لیست‌های علاقه پیدا کرده‌ام و در اندک اندک در تعداد بیشتری عضو می‌شوم. برای سایت مهدیکس هم یک میلینگ‌لیست ساخته‌م که در آن به روی همه‌ی شما باز است، البته اگر توان پنچه‌درانداختن با کلایننت‌های میل قراضه و وب‌میل‌های ضد راست به چپ در شما هست! اینباکس عمومی سایت مهدیکس دات آی‌آر در <a href="https://lists.sr.ht/~mehdix/public-inbox">این آدرس</a> در خدمت شماست. عضویت برای عموم آزاد است. پیام‌ها به صورت استاندارد روی سورس‌هات قابل مشاهده خواهند بود. ایمیل فقط می‌تواند متن باشد (html ریجکت می‌شود، با دلایل خوب). سایت متن راست به چپ را به درستی نماش می‌دهد (حمل بر خودپرستی نشود خودم تعمیرش کرده‌ام). امتحان بکنید شاید سبب خیری شد.</p>

<p>شاید کنجکاو باشید که مزایای اینکار چیست؟ عرض می‌کنم. اول اینکه من از تغییرات ناگهانی در شرکت سرویس‌دهنده که دست برقضا میلیونها دلار هم سرمایه از سرمایه‌گذاران دریافت کرده و متعاقبا باید منافع آنها را تامین بکند رها هستم. فردا ایمیل نمی‌اید که داریم در سرویس مفتی را می‌بندیم بیا سایتت را ببند یا فلان و بهمان. دیگر اینکه لازم نیست یاد بگیرم نتلیفای چطور کار می‌کند. شاید بگویید خوب حالا مجبوری یاد بگیری nginx و کامنت‌دونی جدیدت و یا سایر ابزارها چطور کار می‌کنند. در جواب بگویم که ایرادی ندارد. ترجیح من اینست که کار با فناوری و ابزار کمتر و بنیادی‌تر را یادبگیرم که تا ده‌ها سال بکارم بیاید. دیگر اینکه حالا می‌توانم سایت را نه تنها روی http بلکه مثلا با <a href="https://gemini.circumlunar.space/">gemini</a> هم سرو بکنم. یا لاگ‌های وب‌سرورم را خودم بخوانم یا کامنت‌دونی خودم را هاست بکنم. منی که سرم برای این کارها درد می‌کند خوب برایم همین بهتر است.</p>

<p>خلاصه به این ترتیب پایان یک دوران رقم خورد و دوره‌ی جدیدی برای من شروع شد. دوره‌ای خلوت‌تر از گذشته اما عمیق‌تر.</p>

</div>]]>
    </content>
    <summary>بعد از سالها استفاده از نتلیفای بالاخره زمان مهاجرت فرا رسید، البته به سرور خودم. دیروز اول دیدگاه‌های خوانندگان را از سرور نتلیفای استخراج کردم (اسکریپت بیلدم اینکار را انجام می‌دهد) و سایت را لوکال ساختم و در سرور خودم کپی کردم (با scp). سپس مشخصات سرویس DNS سرویس‌دهنده‌ی سرور مجازی‌ام را در nic.ir وارد کردم. (پیش از این از سرویس DNS رایگان نتلیفای استفاده کرده بودم.) روی صفحه‌ی ادمین سرویس‌دهنده‌‌ام هم آی‌پی‌های سرور را به دامنه متصل کردم. بعد اول تنظیمات دامنه را از نتلیفای حذف کردم. تقریبا درجا سایت از کار افتاد. بعد خود سایت را از نتلیفای...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:8a1c0733-de69-4661-b7fa-3bc701d40380</id>
    
    <title>ماجرای بازگشت استالمن به FSF</title>
    <updated>2021-04-09T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/stallman.html"/>
    <category term="fsf"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>سال ۲۰۱۹ ریچارد استالمن بنانگذار بنیاد نرم‌افزار آزاد و emacs و GNU بعد از انتقادات عمومی نسبت به رفتارش و نظراتش بویژه در مورد ارتباط بزرگسالان با نوجوانان از سمتش در FSF و MIT کناره گرفت. دو هفته پیش او بازگشتش را به FSF اعلام کرد که یک بحث عمومی را برانگیخته است. در این مقاله به این موضوع می‌پردازم.</p>

<p>توجه: پیش از شروع بنویسم که قصد من شرح کامل داستان و عکس‌العمل آنچه در آمریکا گذشته است نیست. من تا آنجا که این موضوع به جامعه‌ی نرم‌افزار آزاد می‌تواند مربوط باشد به این موضوع توجه می‌کنم و بیش از آن برایم مهم نیست.</p>

<p>در آن سال <a href="https://archive.is/kV4PT">یک مقاله در مورد جفری اپستاین</a> در شرح ارتباط جنسی یکی از دخترانی که او از آنها بهره‌برداری جنسی می‌کرد با ماروین مینسکی، یکی از اساتید دانشگاه MIT و از همکاران (یا دوستان) استالمن، منتشر شد.</p>

<p>پس از این مقاله و انتقادات به کمک مالی اپستاین به MIT و کمپین‌هایی در این رابطه پای استالمن با یک <a href="https://archive.is/kV4PT">مقاله در انتقاد از رفتار و نظرات استالمن</a> در مورد زنان در دانشگاه MIT و FSF به ماجرا باز شد. در این مقاله نویسنده با نقل قول از ایمیل استالمن او را به عدم رواداری و تبعیض و سوءرفتار نسبت به سایر زنان در حوزه‌ی تکنولوژی متهم می‌کند، چرا که او در میلینگ لیست دانشگاه به جمله‌بندی و کلمات یک کمپین علیه مینسکی و اپستاین انتقاد کرده بود.</p>

<p>با وجود انتقاداتی که به محتوای این مقالات شد، بویژه این <a href="https://sterling-archermedes.github.io/">مقاله‌ی مفصل</a> این ماجرا ادامه پیدا کرد و افراد و شرکت‌های مختلف به نفع یا بر علیه استالمن موضع‌گیری کردند و در نهایت او از سمت‌هایش کناره گرفت و ماجرا فروکش کرد. تا اینکه دو هفته پیش پس از رویداد اینترنتی <a href="https://libreplanet.org/2021/">Libreplanet 2021</a> او به طور ناگهانی اعلام کرد که به هیئت مدیره‌ی FSF بازگشته است، اینبار نه به عنوان مدیر بلکه به عنوان یک عضو.</p>

<p>به فاصله‌ی یک روز <a href="https://rms-open-letter.github.io/">یک نامه‌ی اینترنتی بر علیه استالمن</a> با امضای افراد و شرکت‌های مختلف منتشر شد که با خطاب کردن او به عنوان «زن‌ستیز» و «معلول‌ستیز» و «ترنس‌هراس» درخواست کرده‌اند نه تنها استالمن از سمتش در FSF و GNU و هرنوع سمت مدیریتی کنار گذاشته شود، بلکه تمام اعضای هیئت مدیره‌ی بنیاد نرم‌افزار آزاد از سمتشان کناره بگیرند. در زمان نوشتن این متن پای این نامه ۳۰۱۲ امضا از اشخاص و ۶۱ امضا از شرکت‌های مختلف وجود دارد. اگر به لیست نگاه کنید اسامی شناخته‌شده‌ی زیادی در آن خواهید دید. از شرکت‌های بزرگ تا افراد فعال در پروژه‌های مختلف و مانند اینها. هموطن از دور و نزدیک هم در لیست پیدا خواهید کرد.</p>

<p>این نامه بی‌پاسخ نماند و به فاصله‌ی کوتاهی <a href="https://rms-support-letter.github.io/">یک نامه‌ی اینترنتی دیگر در حمایت از استالمن</a> منتشر شد. در این نامه از استالمن به عنوان نیروی محرک جنبش نرم‌افزار آزاد نام برده شده و از نامه‌ی اول به عنوان یک حمله‌ی اینترنتی سابقه‌دار نام برده می‌شود و از FSF می‌خواهد که تسلیم نشود. پای این نامه در لحظه‌ی نوشتن این متن ۶۰۸۲ امضا از افراد مختلف وجود دارد. بیش از دو برابر نامه‌ی اول. طرفداران استالمن و مخالفین نامه‌ی اول (که آن را به یک حمله از نوع mob یا lynch تعبیر می‌کنند) وبسایت‌های دیگری هم راه انداخته‌اند. یکی <a href="https://free-software-fight.gitlab.io/">سایت گزارش نبرد است</a> و دیگری <a href="https://stallmansupport.org/index.html">در حمایت او</a> یک هم <a href="https://rms.zezic.ru/">فقط گزارش ارقام</a> است.</p>

<p>هر کدام از نامه‌ها را می‌توان با پول‌ریکوئست روی گیت‌هاب امضا کرد، <a href="https://github.com/rms-support-letter/rms-support-letter.github.io/pulls">حمایت اینجا</a> و <a href="https://github.com/rms-open-letter/rms-open-letter.github.io/pulls">تقبیح اینجا</a>. برای کسانی که به دلایل مختلف از گیت‌هاب صرف‌نظر کرده‌اند دیگران روی <a href="https://lists.sr.ht/~tyil/rms-support/patches">sourcehut</a> و <a href="https://codeberg.org/rms-support-letter/rms-support-letter/issues/1">codeberg</a> امکاناتی فراهم کرده‌اند.</p>

<p>بحث و گفتگو در مورد این جریان همچنان ادامه دارد. شاید یکی از مهمترین‌ها <a href="https://www.debian.org/vote/2021/vote_002">رای‌گیری در دبیان</a> باشد، چرا که پروژه‌ی دبیان به نوعی الگوی اداره‌ی یک پروژه مثل یک کشور دموکراتیک است. حالا هم کابران پیشنهاداتی مطرح کرده‌اند از امضای نامه‌ی تقبیح در یک سو تا امضای نامه‌ی حمایت در سوی دیگر. این رای‌گیری تا چند روز دیگر ادامه خواهد داشت و خروجی در حال حاضر معلوم نیست. <a href="https://vote.debian.org/~secretary/gr_rms/">تعداد آرای ثبت شده</a> پیوسته در حال افزایش است.</p>

<p>خوب حالا که شرح قصه تمام شد نظر خودم را می‌نویسم. من شخصا از دوقطبی شدن اجتماع بیزارم. این بیشتر یک محصول آمریکایی است. در جای دیگر با این شدت تجربه نکرده‌ام. در آلمان هم ندیده‌ام. شخصا از حملات اینترنتی بیزارم. اینکه تصمیم من نوعی و سرنوشت یک انسان باید با یک حمله‌ی اینترنتی و اعمال قدرت ناگهانی بدون آنکه مرتکب جرمی شده باشم تغییر بکند مرا منزجر می‌کند. گوئی که در اجتماع دیدگاه‌های مختلف وجود ندارد. منی که درخت وجودم در ایران شکل گرفته است و هستی‌ام با فرهنگ و مشکلات آن تنیده شده است قادر نیستم با این قبیل حملات همذات‌پنداری کنم. حملاتی از این دست در گذشته دیده‌ام ولی نمی‌خواهم سیاست و عقاید یک فرد در مورد یک موضوع به همه‌جای زندگی و همه‌ی فعالیت‌های آن فرد کشیده شود. من علاقه‌مند و نوع سنتی فرهنگ هکرها هستم (اگر چنین چیزی وجود دارد). آیا طرفدار چیزی هستید که من مخالف آنم؟ آیا باید این مخالفت روزنه‌ی هرگونه مدارا و دیالوگ بویژه فنی را مسدود کند؟</p>

<p>طرفداران حذف استالمن دنبال چه چیزی هستند؟ فرض کنیم که او آدم خاص یا عجیب یا نچسبی است. آیا خاص یا عجیب یا نچسب بودن در دمکراسی غربی جرم است؟ (توجه کنید که اینجا در مورد ایران حرف نمی‌زنیم که یک انسان می‌تواند به واسطه‌ی رفتار خصوصی‌اش یا رفتار جنسی‌اش به مرگ با چوبه‌ی دار محکوم شود.) آیا باید استالمن از چیزی که خودش بوجود آورده و شاید موثرترین فرد بر علیه سلطه‌ی نرم‌افزارهای بسته و تجاری بر تمام زندگی ما بوده است حذف بشود؟ این آدم زندگی‌اش با این جنبش معنی شده است. این از او گرفته شود چه بکند؟‌ خودش را از نزدیکتر پل محل زندگی‌اش پرت کند زیر اولین قطار عبوری؟ این درخواست حذف را من نمی‌فهمم. درخواست پاسخگو بودن و شفاف بودن را چرا.</p>

<p>تصور کنید ما بخواهیم اینکار را در جامعه‌ی ایرانیان داخل و خارج ایران انجام بدهیم. نتیجه چه می‌شود؟ من طی زندگی‌ام در ایران با آدم‌های زیادی سر و کار داشته‌ام. انسان محبوبی را می‌شناختم که افکار نژادپرستانه راجع به اعراب داشت یا دیگری از همنجنسگرایان وحشت داشت و دیگری اعتقادات مذهبی خاصی داشت. البته معمولا تعصبی روی اعتقاداتشان نداشتند و معمولا چیزی بود موروثی و اگر از نزدیک با عواقب رویکردشان روبرو می‌شدند انعطافپذیر بودند و تجدیدنظر می‌کردند. و البته اگر می‌خواستم تبر تفکیک و تقبیح در دست بگیرم باید پیوسته به کوبیدن این یکی یا له کردن آن یکی می‌پرداختم. از این رویکرد در زندگی خیری ندیده‌ام بویژه که بواسطه تجربیات خانوادگی سالها تقاص رویکردهای انقلابی مشابه را پرداخته‌ام. بازگردیم به استالمن که از نرم‌افزار آزاد و حواشی آن دور افتادیم.</p>

<p>در رابطه با انتقاداتی که به استالمن شده است خواندن <a href="https://sterling-archermedes.github.io/">مقاله‌ی مفصل</a> را که در بالاتر هم اشاره کردم توصیه می‌کنم. چرا که با دقت و با موشکافی و با نقل قول دقیق شرح می‌دهد که چرا بسیاری از اتهامات مطرح شده در سال ۲۰۱۹ از بیخ و بن یا بی اساسند یا قابل تردید. این به معنی تطهیر استالمن نیست، بلکه تقبیح سبک گزارشگری اینترنتی است، یعنی هرچه بیشتر کلیک و لایک جمع بکند محبوب‌تر است. حقیقت و رفرنس مهم نیست، مهم افزایش هیجان و شور و هیاهو است. چه کسی حوصله دارد یک مقاله‌ی بلند بالا را بخواند؟ یک توئیت و چند جمله‌ی حماسی کافی است تا آتشی بر افروخته شود و هر خواننده‌ای به این احساس برسد که باید یا طرف خیر را بگیر یا طرف شر را. مثلا استالمن را «ترنس‌هراس» خوانده‌اند بواسطه‌ی مقاله‌ای که در مورد استفاده از ضمایر خنثی منتشر کرده است. من این مقاله را خواندم و ترنس‌هراسی در آن ندیدم. ولی چند نفر از امضا کنندگان نامه آن را خوانده‌اند؟ حدس شما چیست؟ چند نفر اصلا زحمت پیدا کردن سایت او را به خودشان داده‌اند؟ یا بیشتر با نیت خیر به کسی اعتماد کرده‌اند که شاید خودش به کس دیگری اعتماد کرده است و شاید هم اصلا خواهی نشوی رسوا همرنگ جماعت شو؟ شاید هم بگویید ترنس نیستی ولی چندین مقاله هم از ترنس‌ها خوانده‌ام که با وجود انتقاد به استالمن این حمله را نفی کرده‌اند.</p>

<p>اضافه کنم که من از دیدن امضای شرکت‌های بزرگ زیر پای نامه‌ی اول شگفت‌زده نیستم. همه این شرکت‌ها PR یعنی روابط عمومی دارند که تصمیم می‌گیرد چه موضعی برای منافع شرکت مفید است و شرکت هم همان را اعلام می‌کند. ریسک نمی‌کنند، چیزی را می‌گویند که مشتری‌ها دوست دارند بشنوند. بسیاری از نام‌های بزرگ فنی هم شرکت‌هایی هستند که طی سالهای گذشته متاسفانه روی نرم‌افزار آزاد سایه انداخته‌اند.</p>

<p>نکته‌ی دیگری که توجه مرا جلب کرد نبود یا کمبود نام شرکت‌های بزرگ میان امضا کنندگان نامه‌ی حمایت از استالمن بود. عده‌ای این را تعبیر کرده‌اند به اعلام جنگ شرکت‌های تجاری علیه نرم‌افزار آزاد. شاید اینگونه باشد، ولی من همانطور که در بالاتر گفتم آنها احتمالا مشتریان و برنامه‌نویسان خودشان را در نظر دارند. امضاکنندگان نامه‌ی حمایت تکثر بیشتری دارند و در میانشان کسانی دیدم که از پلتفرم‌هایی مثل codeberg یا sourcehut استفاده می‌کنند که نشاندهنده‌ی نگرانی آنها از تسلط شرکت‌های بزرگ بر جهان نرم‌افزار است. این برای من نشانه‌ی خوبی است هرچند دلیل به نفع یا بر علیه استالمن نیست.</p>

<p>در اینجا اضافه کنم که طبق چیزهایی که خوانده‌ام استالمن ظاهرا آدم سختی است برای همکاری و به نرم‌افزار آزاد هم مثل یک ایدئولوژی اعتقاد دارد، مثلا اگر نرم‌افزار غیرآزاد روی یک سایت وجود داشته باشد و لینکش را برایش بفرستید آن را باز نخواهد کرد. لزوما هم به احساسات دیگران توجه نمی‌کند و البته نظراتش را هرچند بحث‌برانگیز در <a href="https://stallman.org/">وبسایت شخصی‌اش</a> می‌نویسد. عده‌ای این را به کاستی مهارت‌های اجتماعی او بواسطه‌ی اختلالات رفتاری نظیر اوتیسم مرتبط می‌کنند. من شخصا تجربه‌ی همکاری مستقیم و اینترنتی با متخصصان و هکرهای فنی مختلفی را داشته‌ام که بسیاری از قیود رایج کلامی یا رفتاری را مراعات نمی‌کردند (منظورم توهین یا سوءرفتار یا خشونت نیست بلکه انتخاب کلمات و ارتباط چشمی یا مکالمات روزمره و مانند اینهاست) و بسته به روحیه و فرهنگ یک آدم ممکن بود که رفتارشان سنگدلانه به نظر برسد. این را در جامعه‌ی فنی زیاد دیده‌ام، آدم‌هایی که با کامپیوتر یا یک فن و تکنیک آشنایی زیادی دارند، می‌توانند خوب بنویسند یا بخوانند اما از یک سلام و احوالپرسی ساده عاجزند.
خودم هم تا حدودی اینطور هستم. مثلا ممکن از پاسخی به نظرات ندهم یا سلام نکنم یا ایمیلی را بدون پاسخ بگذارم یا تماسی تلفنی را جواب ندهم یا از پیوستن به یک گروه یا شبکه‌ی اجتماعی و مانند اینها صرف‌نظر کنم. به دلایل مختلف. این می‌تواند برای کسی که با روحیات و افکار شما آشنا نیست عجیب به نظر برسد. حالا این تفاوت را یا باید پذیرفت یا انکار کرد و پنهان شد، از بیم اینکه جامعه ممکن است انسان را شماتت بکند یا از جمع کنار بگذارد.</p>

<p>در مجموع ترجیح شخصی من اینست که این قبیل حملات اینترنتی برچیده بشود. برداشت من غلبه‌ی احساسات جمعی بر منطق جمعی است. من مخالفت شفافیت در FSF نیستم و فکر می‌کنم باید روی شفافیت بیشتر کار بکنند. متاسفانه طی هفته‌های گذشته بسیاری از حمایت FSF دست‌کشیده‌اند و افراد مختلفی در حال استعفا و کناره‌گیری هستند و عده‌ای هم در حال حذف استالمن. مثلا GCC یک کمیته‌ی هماهنگی دارد که اعلام کرد نام استالمن را حذف می‌کند (ظاهرا بیشتر اعضایش برای شرکت‌های بزرگ کار می‌کنند). و البته استالمن هم پیامبر من نیست. ارادت شخصی به او ندارم. اما از قدرت‌گیری حرکات اینچنینی برای حذف افراد بواسطه‌ی ابراز عقایدشان نگرانم. استدلال‌های منتقدین هم برایم قانع کننده نبود و چنین حمله‌ی گسترده‌ای را توجه نمی‌کرد. شاید مهمترین آنها این بود که عقیده استالمن در مورد حداقل سن برای داشتن رابطه‌ی جنسی (در دفاع از مینسکی)، داینامیک قدرت بین یک بزرگسال و یک نوجوان را در نظر نمی‌گیرد (ارتباط عاطفی و عاشقانه بین دو انسان با سطوح قدرت مختلف می‌تواند به سوءاستفاده یکی از دیگری منجر بشود). و در نتیجه او برای اداره‌ی موارد مربوط به یک کامیونیتی که می‌توان اعضای نوجوان داشته باشد مناسب نیست، که بین موافقین و مخالفین بحث است. انتقاداتی به نحوه‌ی مدیریتش شده که به نظرم بلاموضوع است و آنچه از رفتارش با زنان نقل شده در مقاله‌ی مفصلی که لینک دادم به شدت زیر سوال رفته است. موضوع داینامیک قدرت برای من معقول است و به نظرم نیاز است که اینجا استالمن خیلی شفاف این را بیان کند و او و FSF به اعضا با تغییرات جدی اطمینان بدهند که قادرند از محیط امن و سالمی برای اعضا فراهم بیاورند.</p>

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

</div>]]>
    </content>
    <summary>سال ۲۰۱۹ ریچارد استالمن بنانگذار بنیاد نرم‌افزار آزاد و emacs و GNU بعد از انتقادات عمومی نسبت به رفتارش و نظراتش بویژه در مورد ارتباط بزرگسالان با نوجوانان از سمتش در FSF و MIT کناره گرفت. دو هفته پیش او بازگشتش را به FSF اعلام کرد که یک بحث عمومی را برانگیخته است. در این مقاله به این موضوع می‌پردازم. توجه: پیش از شروع بنویسم که قصد من شرح کامل داستان و عکس‌العمل آنچه در آمریکا گذشته است نیست. من تا آنجا که این موضوع به جامعه‌ی نرم‌افزار آزاد می‌تواند مربوط باشد به این موضوع توجه می‌کنم و بیش از...</summary>
  </entry>

<entry>
    
    <id>https://mehdix.ir/manquotes.html</id>
    
    <title>یک سایت‌ساز کوچک</title>
    <updated>2021-03-19T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/manquotes.html"/>
    <category term="yaml"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>همین اواخر قصد داشتم از روی یک فایل YAML تعدادی صفحه استاتیک تولید کنم. مقداری گشتم ولی هیچ سایت‌سازی پیدا نکردم که اینکار را انجام بدهد. چند ساعتی وقت گذاشتم و خودم یک سایت‌ساز مختصر ۶۷ خطی با پایتون نوشتم.</p>

<p>کاری که این سایت‌ساز کوچک انجام می‌دهد اینست که تعدادی نقل قول را از یک فایل YAML به کمک پکیج pyyaml می‌خواند و برای هر کدام یک صفحه‌ی وب جداگانه می‌سازد، یک صفحه ایندکس هم تولید می‌کند و دست آخر یک <a href="https://mehdix.org/~mx/manquotes/feed.xml">خوراک اتم</a> هم ضمیمه‌اش می‌کند و والسلام.</p>

<p>برنامه صفحه‌ها را به کمک پکیج مفید jinja2 می‌سازد. برای استایل هم از بوت‌استرپ استفاده کردم. برنامه‌ی خیلی ساده‌ایست که نیاز من را به نحو احسن برطرف می‌کند. سورس آن را برای آزمایش روی <a href="https://git.sr.ht/~mehdix/manquotes">سورس‌هات</a> آپلود کردم. فایل gen.py را ببینید. خروجی سایت را هم می‌توانید روی <a href="https://mehdix.org/~mx/manquotes/">وبسایتم</a> ببینید.</p>

</div>]]>
    </content>
    <summary>همین اواخر قصد داشتم از روی یک فایل YAML تعدادی صفحه استاتیک تولید کنم. مقداری گشتم ولی هیچ سایت‌سازی پیدا نکردم که اینکار را انجام بدهد. چند ساعتی وقت گذاشتم و خودم یک سایت‌ساز مختصر ۶۷ خطی با پایتون نوشتم. کاری که این سایت‌ساز کوچک انجام می‌دهد اینست که تعدادی نقل قول را از یک فایل YAML به کمک پکیج pyyaml می‌خواند و برای هر کدام یک صفحه‌ی وب جداگانه می‌سازد، یک صفحه ایندکس هم تولید می‌کند و دست آخر یک خوراک اتم هم ضمیمه‌اش می‌کند و والسلام. برنامه صفحه‌ها را به کمک پکیج مفید jinja2 می‌سازد. برای استایل هم...</summary>
  </entry>

<entry>
    
    <id>https://mehdix.ir/upcoming-changes.html</id>
    
    <title>گزارش تغییرات اساسی در پیش رو</title>
    <updated>2021-03-13T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/upcoming-changes.html"/>
    <category term="وب"/><category term="rtl"/><category term="کامنت‌دونی"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>طی سالهای گذشته من این وبسایت استاتیک را روی جکیل و گیت‌هاب و نتلیفای اداره کرده‌ام. برای کامنت‌دونی هم از اول از دیسکاس و بعد از کامنتدونی دست‌ساز خودم استفاده کرده‌ام. الان در حال مهاجرت به سرور خودم هستم. شرح می‌دهم چرا.</p>

<p>در گذشته من انواع و اقسام روش‌ها برای تولید و انتشار اتومات برای سایت استاتیک را شرح داده‌ام. بعضا هم ابزارهایی ساخته‌ام که برای دیگران هم به همین منظور سودمند باشد. طی ماه‌های گذشته از سویی رفته رفته به این نتیجه رسیده‌ام که برای انتشار چهار خط نوشته به این همه قیل و قال نیازی نیست. چرا که یک سایت استاتیک را می‌توان لوکال ساخت و در یک سرور ریموت با بسیاری ابزارها و پروتکل‌های استاندارد لود کرد. حتی می‌شود شخصا تک تک فایل‌ها را نوشت، یا روی یک ادیتور ساده متن را مستقیم در یک فایل ویرایش کرد، یا مستقیم تکست نوشت، چرا که نه؟ به نوعی از پیچیدگی وب مدرن و دنگ و فنگ سرویس‌های ابری خسته شده‌ام. قدرت از کاربر و نرم‌افزارهای آزاد به سرویس‌دهنده‌های ابری منتقل شده است و برنامه‌نویس بجای یادگیری عصاره‌ی علوم کامپیوتر به یادگیری رابط‌های کاربری شرکت‌های بزرگ می‌پردازد که درنهایت همان کاری را انجام می‌دهد که شاید خود برنامه‌نویس خیلی ساده‌تر به کمک نرم‌افزارهای آزاد از پس انجامش بربیاید. البته شروطی دارد، باید از بسیاری دنگ و فنگ‌ها گذشت کرد. باید از فرع گذشت و به اصل چسبید.</p>

<p>شاید بپرسید فرع چیست و اصل چیست. من از دید خودم اینها را برای خودم تعریف می‌کنم. برای من دانش خام کامپیوتر اصل است. مثلا اینکه چطور دو پراسس روی دو کامپیوتر با هم حرف می‌زنند؟ کامپیوتر که نمی‌تواند با کسی حرف بزند، هر چیزی که الان روی این صفحه‌های موبایل یا لیپ‌تاپ که در مقابل شماست در یک پراسس تولید شده است. فهمیدن این اصل است. سیستم عامل اصل است. مهمترین اصل است. اینکه یک اپ یا برنامه‌ی خوشگل روی صفحه چه وعده و وعیدی به کاربر می‌دهد فرع است. این سخت‌افزاری که دارد دستوارت این پراسس‌ها را پردازش می‌کند اصل است. دستوارت اسمبلی آن اصل است. فهمیدن اینکه چه می‌کند، بک‌دور دارد یا نه، نرم‌افزارهای بسته داخل سی‌پی‌یو هست یا نه اصل است (از حدودا ۲۰۰۸ به این سو همه سی‌پی‌یو‌ها بک‌دور دارند، آنها می‌گویند برای آی‌تی‌و شرکت‌های بزرگ است، ما می‌گوییم هر چیز که من کاربر نمی‌توانم از کار بیندازمش بک‌دور است). مثلا اینکه یک پروتکل مثل http چطور کار می‌کند اصل است، اینکه یک درخواست و پاسخ آن چه شکلی است اصل است. فلان فریم‌ورک وب فرع است. اینکه پروتکل ایمیل چطور کار می‌کند و یک پیام ایمیل چه هدرهایی دارد اصل است، سرویس میلیاردی ایمیل گوگل فرع است هرچند باور آن سخت باشد. کاربر یک برنامه اصل است، یک برنامه‌نویس اصل است، شرکت و سرمایه‌گذار و همه اینها فرع است. به آن فکر کنید، کسی نیست که در جهان بگوید ماست من ترش است و بدون من هم جهان به راه خودش خواهد رفت. و شاید بی ربط نباشد که اضافه کنم که وب را سودجویان به نابودی کشیده‌اند و تبدیل کرده‌اند به باتلاقی از تراکینگ و سرقت اطلاعات و دزدی توجه کاربران و دستکاری اندیشه‌های آنان و تاثیرگذاری روی تصمیمات زندگی آنها که شرح آن مجالی دیگر می‌طلبد.</p>

<p>اگر جوان هستید، اگر دانشجو هستید و اگر تازه وارد این دنیا شده‌اید و اگر به نرم‌افزار آزاد علاقه دارید قبل از هر تصمیم به استفاده از یک تکنولوژی «جدید» یا محصول فلان شرکت و مانند اینها دو بار فکر کنید. وقت گرانبهای خودتان را مجانی نفروشید چه بسا که با پرداختن به اصل چیزی خلق کنید که کسی باور نکند. با پرداختن به فرع امکان خرق عادت نخواهد بود و مجالی برای گریز از آنچه هست و اینکه همه چیز ساخته شده است و مانند اینها نخواهد بود.</p>

<p>از سوی دیگر حساسیتی ویژه پیدا کرده‌ام به بکارگیری سرویس‌های ابری و یکی پس از دیگری مشغول حذف آنها بوده‌ام. چرا تابحال به این سادگی مشغول باز کردن اکانت روی هر سرویس‌دهنده‌ی شناس و ناشناسی بوده‌ام؟ به نوعی همواره گول زرق و برق یک سایت یا لندینگ‌پیج طراحی شده توسط دپارتمان مارکتینگ یک شرکت معمولا خصوصی با پشتبیانی سرمایه‌گذارهایی که هر یک در صدد تزاید سود خویش بوده‌اند را خورده‌ام. همانطور که بالاتر گفتم عیب بزرگ این عادت دور ماندن از اصل و چسبیدن به فرع است. یک شرکت به شما یک رابط کاربری خوشدست می‌دهد ولی بین شما و دانش و نرم‌افزار و سخت‌افزار فاصله می‌اندازد. از سویی هر زمان شرایط استفاده می‌تواند به دلایل مخلتف تغییر بکند که شوکی ناگهانی به برنامه‌نویس وارد می‌کند. ساده‌ترینش شاید این باشد که فلان شرکت بگوید به خاطر تحریم به شما سرویس نمی‌دهم. یا شرکتی دیگری بگوید فلان ورژن را دیگر ساپورت نمی‌کنیم یا فلان را آپگرید می‌کنیم و مجبورت بکند که تن به تغییری ناخواسته بدهی.</p>

<p>چیزی که ما معمولا از آن غافل هستیم ارزش وقت و توجه ماست. وقتی بجای کنسول سرور شخصی خودت روی کنسول و وبسایت یک شرکت ثالث هستی، آن شرکت به راحتی با یک آپدیت یا یک نوتیفیکیشن این وقت و توجه قیمتی را به سرقت می‌برد. کس دیگری تصمیم می‌گیرد که امروز من چه چیزی ببینم و نگاهم در هر ساعتی به چه چیزی خیره بشود. این بزرگترین خسارتی است که می‌توانم تصور بکنم.</p>

<p>همین ماجرا هم به نوع دیگری وقتی از نرم‌افزارهای غول‌آسا استفاده می‌کنی اتفاق می‌افتد. مثلا مدتهاست که «اوپن سورس» به واژه‌ای برای دپارتمان‌های مارکتینگ شرکت‌های مختلف تبدیل شده است. هر یک در تلاشند تا برنامه‌نویس را در تله‌ای گرفتار کنند و به او سرویسی بفروشند یا نگاهش را تغییر بدهند و به سرویس‌های خودشان وابسته بکنند. این هم خسارتی بزرگ است.</p>

<p>به همین خاطر مثلا در حال مهاجرت از گیت‌هاب هستم به سورس‌هات. سورس‌هات سرویسی است در وضعیت آلفا. یعنی به شدت در حال توسعه. برنامه‌نویس اصلی آن برنامه‌نویس wlroots و sway است. یعنی پیش از این حداقل دو کار در خور و ارزنده انجام داده است. این سرویس کاملا از بیخ و بن اوپن سورس است اما پولی است. چرا از سرویس خوش رنگ و لعاب گیت‌هاب به کوزه شکسته‌ی سورس‌هات می‌روم؟ (البته می‌توانم خودتم مثلا با cgit یا مانند آن حتی ریپازیتاری‌های خودم را هاست بکنم). جواب ساده است. اگر برای استفاده از سرویسی که میلیارها دلار ارزش دارد (ماکروسافت گیتهاب را به بهایی بیش از پنج یا شش میلیارد دلار خرید، حجم این مبلغ دیوانه کننده است)  و سالیانه میلیونها دلار خرج دارد پولی نمی‌دهید محصول خودت شما هستید. و البته لازم به گفتن نیست که من در این جهان فانی تنها کاری که قصد انجامش را ندارم اینست که محصول باشم. قصد من توصیه‌ی سورس‌هات نیست. این هم فقط یک مثال است. حسن آن چیست؟ سورس‌هات سرمایه‌گذار ندارد. فاینانس مستقیم از کاربران می‌اید. بله من برای این سرویس پول پرداخت می‌کنم چون می‌خواهم آلترناتیوری در برار ابرقدرت‌های نرم‌افزاری بوجود بیاید. آلترناتیوی که از سرویس‌ها و پروتکل‌های آزاد استفاده می‌کند. من رابط کاربری سورس‌هات را برای فارسی و عربی تعمیر کردم. آیا می‌توانستم اینکار را برای گیت‌هاب انجام دهم؟ نه. باید التماس می‌کردم. اما سورس‌هات نمونه‌ی یک تیم کوچک مستقل است، می‌توان مسقیتم با برنامه‌نویسان همکاری کرد که حسن بزرگی است.</p>

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

<p>بگذارید مثالی بزنم. یک شرکتی بود که الان نامش یادم نیست، تی‌شرت می‌داد به هرکس که فلان تعداد پول‌ریکوئست روی گیت‌هاب داشته باشد. آنزمان برای من هم جالب بود، ولی بعدها جایی خواندم که با این کارش هزاران پول‌ریکوئست اسپم بوجود می‌آورد که سرازیر می‌شود داخل پروژه‌های اوپن‌سورس که اغلب توسط علاقه‌مندان و داوطلبان اداره می‌شود و وقت آنها را می‌گیرد بدون اینکه سودی عملی در پی داشته باشد. آن شرکت هم در پاسخ اعتراض این برنامه‌نویس گفته بود که نمی‌تواند کاری بکند. ولی فکرش را بکنید هزار تا یا ده هزارتا تی‌شرت چقدر ارزش دارد؟ دپارتمان مارکتینگ آن شرکت این جریان را راه‌می‌اندازد تا برای شرکت کسب شهرت بکند، و در ادامه وقت هزاران برنامه‌نویس دیگر را تلف می‌کند.</p>

<p>خلاصه بگویم که تا جایی که در توان دارم مشغول تزکیه هستم. هر جا بتوانم از آلترناتیوهایی استفاده می‌کنم که توسط برنامه‌نویس‌هایی ساخته شده است که آزادی و کاربر برایشان در اولویت بوده نه منافع تجاری شرکت. چرا که باید دیر یا زود بین منافع شرکت و سرمایه‌گذارانش و منافع کابران یکی را انتخاب بکند و سخت است که هر دو با هم بشود.</p>

<p>این شد که تصمیم گرفتم که هم از شر کنترل شرکت‌های مختلف خلاص بشوم و هم وقتم را بی واسطه صرف دانش پایه‌ای کامپیوتر بکنم، مثلا بجای یادگرفتم رابط کاربری فلان شرکت، یاد بگیرم چطور مستقیم برای شبکه برنامه بنویسم، پروتکل‌ها را بشناسم و مانند اینها. لازمه‌اش اینست که وقتم را روی سرور خودم بگذارنم و مستقیم به دست خودم همه کارها را انجام بدهم. وقت یک منبع محدود است، یکجا که مصرف شد یعنی جای دیگر مصرف نشده. پس با حذف واسطه‌ها و رابطه‌ها می‌روم سروقت اصل مطلب که سودمندتر است و مفرح است.</p>

<p>این وبسایت هم مستثنی از جریان نیست. در حال مهاجرت هستم به سرور خودم. از سویی یکی از خوانندگان عزیز پیام داد که نتلیفای را مثل بسیاری چیزهای بدرد بخور دیگر در ایران از بیخ بسته‌اند که مبادا یک برنامه‌نویس خسته یک وبسایت آنچا آپ بکند، اما بهرحال پیش از این من چمدان‌ها را بسته بودم. یعنی بیلد و هوک‌ها و هاست وبسایت و ایمیل و کامنت‌ها را باید خودم اداره بکنم.</p>

<ul>
  <li>وب سرور بجای وب سرور نتلیفای تبدیل می‌شود به nginx
– عینی کنترل کامل روی لود ریکوئست‌ها و کش و البته از دست دادن CDN
– یعنی اگر DDoS ایک به سرور من بشود فعلا بی‌دفاع هستم و سایت داون خواهد شد
– یعنی تولید سرتیفیکیت سایت توسط خودم (Let’s Encrypt)</li>
  <li>پوش و بیلد از گیت‌هاب از کار می‌افتد
– فعلا روی سرور بیلد می‌کنم و نیازی به گیت‌هاب نمی‌بینم
– لازم نیست منتظر بیلد و انتشار روی نتلیفای باشم
– بیلد اتومات پس از ثبث کامنت جدید از کار می‌افتد
– بیلد از روی موبایل بدون دسترسی به سرور از کار می‌افتد</li>
  <li>ثبت کامنت‌ها از کار می‌افتد
– در حال نوشتن یک کامنتدونی جدید هستم که روی سرور اجرا می‌شود و کامنت‌ها را مدیریت خواهد کرد
– گوگل کپجا از کار می‌افتد (چه بهتر!). برنامه‌ای ساده برای کشف و علامتگذاری کامنت‌های جفنگ می‌نویسم</li>
  <li>ارسال ایمیل پس از ثبت پاسخ به کامنت از کار می‌افتد
– از ایمیل سرور خودم استفاده خواهم کرد</li>
</ul>

<p>خواننده‌ی عزیز، از اینکه وقت گذاشتی و این مطلب را خواندی تشکر می‌کنم. از دیدگاه‌ها هم طبق معمول استقبال می‌کنم.</p>

<p>پینوشت:
این مطلب روی لپ‌تاپ پاین‌بوک‌پرو ۱۹۹ دلاری‌ام با سیستم عامل مانجارو مبتنی بر آرچ لینوکس و در ادیتور gedit نوشته و منتشر شد.</p>
</div>]]>
    </content>
    <summary>طی سالهای گذشته من این وبسایت استاتیک را روی جکیل و گیت‌هاب و نتلیفای اداره کرده‌ام. برای کامنت‌دونی هم از اول از دیسکاس و بعد از کامنتدونی دست‌ساز خودم استفاده کرده‌ام. الان در حال مهاجرت به سرور خودم هستم. شرح می‌دهم چرا. در گذشته من انواع و اقسام روش‌ها برای تولید و انتشار اتومات برای سایت استاتیک را شرح داده‌ام. بعضا هم ابزارهایی ساخته‌ام که برای دیگران هم به همین منظور سودمند باشد. طی ماه‌های گذشته از سویی رفته رفته به این نتیجه رسیده‌ام که برای انتشار چهار خط نوشته به این همه قیل و قال نیازی نیست. چرا که...</summary>
  </entry>

<entry>
    
    <id>https://mehdix.ir/cyberpunk-arch-wayland-sway.html</id>
    
    <title>چطور روی آرچ‌لینوکس سایبرپانک بازی می‌کنم</title>
    <updated>2021-03-11T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/cyberpunk-arch-wayland-sway.html"/>
    <category term="بازی"/><category term="لینوکس"/><category term="گرافیک"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>من چندان اهل بازی کردن نیستم، گه‌گاه بازی‌های دوبعدی بازی می‌کنم و اواخر هم به اصرار <a href="https://bekindtozombies.com/">شایگان</a> کلی Stardew Valley دو نفری بازی کردیم که البته بسیار لذت بخش و حتی آموزنده بود.</p>

<p class="center"><img src="assets/pimg/StardewValley-2020-09-04-16-54-32.png" alt="" /></p>

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

<p>به عنوان آدمی که از کوزه شکسته آب می‌خوره، سیستم عامل من ترکیبی از غریب‌ترین نرم‌افزارهای موجوده. بواسطه‌ی آرچ لینوکس بودن که همواره در لبه‌ی تیغ حرکت می‌کنیم. ولی من پا رو از این فراتر گذاشتم و پس از سالها از xorg به Wayland و از GNOME به Sway مهاجرت کردم تا نفسی تازه کنم و در پی تصمیمی که اواخر گرفتم از نرم‌افزارهایی که توسط‌ شرکت‌های بزرگ اداره می‌شوند به طرف نرم‌افزارهای کوچک‌تر و سبک‌تر که توسط گروه‌های کوچک و مستقل اداره می‌شوند حرکت کنم.</p>

<p>بنابراین اصلا فکر نمی‌کردم امکان اجرای یک بازی ویندوزی روی چنین سیستمی وجود داشته باشه. ولی بخت با من یار بود و برنامه‌هایی مثل Wine به قدری پیشرفت کردند که این امکان فراهم شده.</p>

<p>توجه کنید که من اینجا بازی رو مستقیم روی سیستم اجرا می‌کنم و کارت گرافیکی دومی هم ندارم. سی‌پی‌یو من AMD Ryzen 3000 بدون گرافیک توکاره و کارت گرافیکم هم AMD RX580. علت انتخاب گرافیک AMD از ابتدا اطلاع از وجود درایورهای بهتر روی لینوکس بود.</p>

<p>اگر کارت گرافیکی دومی داشتم از GPU Passthrough استفاده می‌کردم. با یک سرچ کوچک <a href="https://github.com/bryansteiner/gpu-passthrough-tutorial/">راهنمای خوبی</a> پیدا کردم که جزئیات کار رو شرح داده. در این روش دو کارت گرافیک نیازه و یکی اختصاصا به یک ماشین مجازی ویندوز داده می‌شه و به این طریق می‌شه با سرعت بالا بازی کرد.</p>

<p>از طرف دیگر اگر کسی بازی رو روی استیم خریداری کرده باشه، استیم می‌تونه مستقیما به کمک <a href="https://github.com/ValveSoftware/Proton">پروتون</a> و <a href="https://www.winehq.org/">واین</a> در پشت صحنه بازی رو اجرا می‌کنه. هرچند از جایی که من از اسیتم بازی رو نخریده بودم امکان اینکار نبود. من برای بازی یک کد دانلود دریافت کرده بودم که بازی رو از <a href="https://www.gog.com/game/cyberpunk_2077">gog store</a> دانلود کنم. اما این فروشگاه فقط کلاینت ویندوز داره. یه انسان دوست داشتنی برنامه‌ای عالی به نام <a href="https://github.com/sharkwouter/minigalaxy">مینی گلکسی</a> برای لینوکس نوشته که اجازه استفاده از اکانت gog روی لینوکس رو فراهم می‌کنه.</p>

<p>اول به کمک مینی گلکسی بازی رو دانلود کردم. این برنامه هیچ فیچری نداره. فقط می‌تونه بازی‌ها رو از اکانت دانلود کنه که من هم همین رو لازم داشتم. بعد از دانلود دیگه به برنامه نیازی نیست مگر برای آپدیت.</p>

<p>برای اجرا نیاز به نصب پروتون بود که از ریپازیتوری کاربران آرچ (aur: arch user repository) نصب کردم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ yay proton-ge-custom-bin
</code></pre></div></div>

<p>از جایی که من بدون استیم بازی رو می‌خواستم اجرا کنم با جستجوی متوجه شدم که نیاز به رانتایم استیم دارم که در ریپازیتوری اصلی آرچ فراهم بود:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo pacman -S steam-native-runtime
</code></pre></div></div>

<p>(قبلا مجبور شده بودم که mesa-git رو هم نصب کنم ولی الان نیازی نیست چون تغییرات لازم در ریپازیتوری‌های اصلی اعمال و منتشر شده.)</p>

<p>با این تغییرات بازی روی کامپیوترم اجرا شد، البته از ترمینال باز می‌کنم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ proton GOG\ Games/Cyberpunk\ 2077/bin/x64/Cyberpunk2077.exe
</code></pre></div></div>

<p class="center"><img src="assets/pimg/ps_20210311210516.png" alt="" /></p>

<p>بازی معمولا بدون مشکل اجرا می‌شه. من حتی استک صوتی کامپیوتر رو با برنامه‌ی جدیدالتاسیس <a href="https://pipewire.org">پایپ‌وایر</a> جایگزین کردم و تصورم این بود که اصلا از بازی صدا درنیاد (به هر دلیلی، مثل همیشه!) ولی کار کرد!</p>

<p>گاهی بعد از آپدیت پکیج‌ها پیش آمده که بازی باز نمی‌شه که در این مواقع اول فایل‌های سیو بازی رو از داخل پوشه‌ی پروتون کپی می‌کنم و بعد پوشه رو کامل حذف می‌کنم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cp -r .local/share/proton-pfx/0/pfx/dosdevices/c:/users/steamuser/Saved\ Games/CD\ Projekt\ Red ~/Backups/
$ rm -rf .local/share/proton-pfx
</code></pre></div></div>

<p>و بازی رو دوباره اجرا می‌کنم و می‌بندم و بعد سیوها رو برمی‌گردم سر جای اولشون:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cp -r Backups/Cyberpunk\ 2077/ .local/share/proton-pfx/0/pfx/dosdevices/c:/users/steamuser/Saved\ Games/CD\ Projekt\ Red/
</code></pre></div></div>

<p>بازی باگ کم نداره اوایل چند بار کرش کرد یا آرتیفکت‌هایی در هوا معلق بودند یکبار هم تو یک کوچه گیر کردم و هر کار کردم نتونستم در برم :) ولی در مجموع خیلی راضی هستم.</p>

<p class="center"><img src="assets/pimg/ps_20210212225630.png" alt="" /></p>

</div>]]>
    </content>
    <summary>من چندان اهل بازی کردن نیستم، گه‌گاه بازی‌های دوبعدی بازی می‌کنم و اواخر هم به اصرار شایگان کلی Stardew Valley دو نفری بازی کردیم که البته بسیار لذت بخش و حتی آموزنده بود. وقتی که بازی سایبرپانک منتشر شد به درخواست شایگان نسخه‌ای سفارش دادم. از جایی که او به خاطر باگ‌های بسیار گزارش شده در بازی فعلا از بازی کردن صرف نظر کرده، تصمیم گرفتم خودم بازی کنم. به عنوان آدمی که از کوزه شکسته آب می‌خوره، سیستم عامل من ترکیبی از غریب‌ترین نرم‌افزارهای موجوده. بواسطه‌ی آرچ لینوکس بودن که همواره در لبه‌ی تیغ حرکت می‌کنیم. ولی من پا...</summary>
  </entry>

<entry>
    
    <id>urn:uuid:2c0823a1-b84b-47e1-9bab-b30a0ca5c4b1</id>
    
    <title>ضبط و انتشار ۱۰۶ رباعی خیام</title>
    <updated>2020-12-28T00:00:00Z</updated>
    <link rel="alternate" type="text/html" href="https://mehdix.ir/khayyam-audio-files.html"/>
    <category term="خیام"/><category term="ساقی"/>
    <content type="html">
        <![CDATA[<div dir="rtl"><p>در گذشته ۱۰۶ رباعی خیام را به فرمت YAML منتشر کرده بودم. طی روزهای گذشته همین‌ها را با میکروفن ضبط کردم و فایل‌های صوتی آنها را منتشر کردم.</p>

<p>هدفم این بود که بتوان رباعی‌ها را علاوه بر خواندن گوش کرد. اکثر این رباعی‌ها و هزاران شعر دیگر در سایت خوب گنجور هم در دسترس است و بسیاری از آنها را هم می‌توان گوش کرد. من هم برای فهم تلفظ صحیح بعضی لغات به کامنت‌های سایت گنجور و نیز فایل‌های صوتی آن مراجعه کردم.</p>

<p>ابیات را با میکروفن <a href="http://www.samsontech.com/site_media/support/manuals/Q2U_OM_5L_v6.pdf">Q2U ساخت SAMSON</a> در خانه ضبط کرده‌ام. این میکروفن صداهای مزاحم محیط را کمتر ضبط می‌کند. ابیات اول کمی کم‌جان از آب درآمدند ولی مجدد ضبط نکردم، از یک چهارم اول به بعد باید صدا خوب باشد.</p>

<p>برای ضبط از برنامه‌ی Sound Recorder گنوم استفاده کردم. برنامه برای ضبط تعداد زیادی فایل چندان مناسب نیست چرا که نمی‌توان همه فایل‌ها را با هم ذخیره کرد ولی کار را انجام داد. فرمت فایل‌های اصلی flac است اما نسخه ogg که کم‌حجم‌تر است را برای انتشار انتخاب کردم.</p>

<p>برای تبدیل فایل‌های flac به ogg از برنامه‌ی ffmpeg به صورت زیر استفاده کردم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>for i in `ls`; do ffmpeg -i $i $i.ogg; done
</code></pre></div></div>

<p>تمامی فایل‌ها را هم پیش از تبدیل با برنامه‌ی EasyTAG به نحو مطلوب تگ‌گذاری کرده‌ام. برنامه‌های مختلف مانند VLC و یا mpv تگ‌ها را موقع پخش به درستی نمایش می‌دهند. برای اینکه تگ عنوان هر فایل را به راحتی به شکل تزایدی تغییر بدهم از برنامه‌ی lltag و bash استفاده کردم:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>c=1;for i in `ls`; do lltag --yes --tag title="Quatrain No. `printf "%03d" $c`" $i &amp;&amp; ((c=c+1)); done
</code></pre></div></div>

<p>برای هر فایل هم یک Album Art که همان تصویر خیام از سایت ویکی‌پدیاست با ذکر منبع به کار گرفته‌ام. همه چیز هم تحت مجوز CC BY-SA 4.0 قرار دارد. یعنی دست بزن اما خیانت مکن :)</p>

<p>البته شاید بگویید به چه درد می‌خورد؟ اول اینکه انتشار آزاد محتوای بیشتر با مجوز درست و تگ حسابی که ضرر ندارد. دیگر اینکه فکر کردم از این ۱۰۶ متن و صوت بتوان به عنوان یک دیتاست کوچک آزمایشی برای پردازش صوت استفاده کرد.</p>

<p>همه‌ی فایل‌ها <a href="https://github.com/mehdisadeghi/khayyam/tree/master/audio">روی گیت‌هاب</a> است. <a href="https://github.com/mehdisadeghi/khayyam/archive/master.zip">فایل زیپ</a> مستقیما قابل دانلود است.</p>

</div>]]>
    </content>
    <summary>در گذشته ۱۰۶ رباعی خیام را به فرمت YAML منتشر کرده بودم. طی روزهای گذشته همین‌ها را با میکروفن ضبط کردم و فایل‌های صوتی آنها را منتشر کردم. هدفم این بود که بتوان رباعی‌ها را علاوه بر خواندن گوش کرد. اکثر این رباعی‌ها و هزاران شعر دیگر در سایت خوب گنجور هم در دسترس است و بسیاری از آنها را هم می‌توان گوش کرد. من هم برای فهم تلفظ صحیح بعضی لغات به کامنت‌های سایت گنجور و نیز فایل‌های صوتی آن مراجعه کردم. ابیات را با میکروفن Q2U ساخت SAMSON در خانه ضبط کرده‌ام. این میکروفن صداهای مزاحم محیط را...</summary>
  </entry>


</feed>
