SUB FPS | دانشنامه پورت بازی‌ها
راهنمای فنی و آموزشی

دایرةالمعارف روش‌های پورت غیررسمی بازی‌ها به کامپیوتر

راهنمای فناوری‌ها، مهندسی معکوس، بازسازی کد و اجرای Native بازی‌های کنسولی و موبایلی روی PC

تهیه‌شده برای Sub FPSمفاهیم و فناوری‌هانسخه وب تک‌فایلی
این مقاله میان «پورت Native»، «بازکامپایل»، «بازسازی موتور» و «شبیه‌سازی» تفاوت قائل می‌شود. همه پروژه‌هایی که بازی کنسولی را روی PC اجرا می‌کنند، لزوماً پورت Native نیستند.

مقدمه: پورت غیررسمی بازی چیست؟

بسیاری از بازی‌های ویدیویی ابتدا برای کنسول‌هایی مانند PlayStation، Xbox و Nintendo یا سیستم‌عامل‌های موبایلی Android و iOS ساخته می‌شوند. در بعضی موارد، سازندگان هیچ نسخه رسمی برای ویندوز منتشر نمی‌کنند؛ اما این موضوع لزوماً به معنای غیرممکن بودن اجرای آن بازی‌ها روی کامپیوتر نیست.

در سال‌های اخیر، توسعه‌دهندگان مستقل با استفاده از روش‌هایی مانند مهندسی معکوس (Reverse Engineering)، بازکامپایل ایستا (Static Recompilation)، بازسازی موتور بازی (Engine Reimplementation) و ترجمه دستورالعمل‌های پردازنده توانسته‌اند بعضی از این بازی‌ها را به برنامه‌هایی با قابلیت اجرای Native روی ویندوز تبدیل کنند.

اجرای یک بازی کنسولی روی کامپیوتر با پورت Native آن یکسان نیست. شبیه‌ساز ممکن است بازی را با تقلید از سخت‌افزار کنسول اجرا کند؛ درحالی‌که یک پروژه Recompilation می‌تواند کد بازی را به کد قابل اجرای پردازنده کامپیوتر تبدیل کند.

بعضی پروژه‌ها نه شبیه‌ساز هستند و نه بازکامپایل مستقیم؛ بلکه با بازسازی بخش‌های اصلی موتور بازی، امکان اجرای نسخه‌ای جدید از بازی را فراهم می‌کنند.

۱. شناخت تفاوت روش‌های پورت غیررسمی

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

Reverse Engineeringفرایند بررسی و شناخت عملکرد نرم‌افزار بدون دسترسی کامل به کد اصلی.
Recompilationتبدیل کد یا دستورالعمل‌های برنامه به شکلی دیگر، معمولاً برای معماری متفاوت.
Emulationشبیه‌سازی رفتار سخت‌افزار یا محیط اجرای سیستم اصلی.
Native Portنسخه‌ای که برای اجرا در محیط و معماری مقصد پیاده‌سازی شده است.
Engine Recreationبازسازی موتور بازی با استفاده از تحلیل رفتار نسخه اصلی.
Source Portانتقال کد منبع موجود به پلتفرم جدید.

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

نمای کلی مسیرهای اصلی پورت

بازی اصلی کنسولی یا موبایلی←مسیر شبیه‌سازی
Emulation / HLE / LLE
یامسیر بازسازی
Recompilation / Recreation / Source Port
←محیط سخت‌افزاری مجازی یا کد و موتور سازگار با PC←خروجی قابل اجرا روی کامپیوتر

این نمودار یک دسته‌بندی مفهومی است؛ پروژه‌های واقعی ممکن است از چند مسیر به‌صورت ترکیبی استفاده کنند.

۲. بررسی تخصصی روش‌های پورت غیررسمی

برای جلوگیری از اشتباه، فناوری‌ها را در چهار گروه قرار می‌دهیم:

  • روش‌های انتقال و بازسازی کد بازی
  • روش‌های شبیه‌سازی و ترجمه دستورالعمل‌ها
  • روش‌های بازسازی موتور و سازگاری نرم‌افزاری
  • فناوری‌های پشتیبان و مراحل مهندسی معکوس

۲.۱. Native Porting – پورت بومی انتقال بازی

Native Porting به معنای انتقال بازی به یک پلتفرم جدید با استفاده از کدی است که مستقیماً برای محیط مقصد کامپایل و اجرا می‌شود. در این روش، برنامه به‌جای تکیه بر شبیه‌سازی کامل سخت‌افزار کنسول، از امکانات سیستم‌عامل و سخت‌افزار کامپیوتر استفاده می‌کند.

برای مثال، اگر یک بازی قدیمی با پردازنده PowerPC و API گرافیکی اختصاصی کنسول ساخته شده باشد، توسعه‌دهنده می‌تواند منطق بازی را به محیط x86-64 منتقل کند و بخش گرافیکی آن را با DirectX یا Vulkan پیاده‌سازی کند.

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

زبان‌ها و فناوری‌ها: C، C++، Rust، C# و در برخی پروژه‌ها زبان‌های اختصاصی موتور بازی.

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

نکته: Native بودن خروجی به این معنا نیست که کل بازی از ابتدا نوشته شده است. یک بازی می‌تواند با استفاده از کد Recompiled نیز به برنامه‌ای Native تبدیل شود.

۲.۲. Static Recompilation – بازکامپایل ایستا یکی از روش‌های مهم مدرن

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

برای مثال، اگر بازی اصلی برای پردازنده MIPS ساخته شده باشد، Recompiler می‌تواند دستورالعمل‌های آن را به کد C یا C++ تبدیل کند تا کامپایلر ویندوز آن را برای پردازنده x86-64 یا ARM64 بسازد.

فایل اجرایی کنسول←تحلیل و شناسایی دستورالعمل‌ها
Disassembly / Metadata
←تولید کد C یا C++←کامپایل←برنامه Native کامپیوتر

یکی از پروژه‌های مهم این حوزه N64Recomp است. این پروژه فایل‌های اجرایی Nintendo 64 را به کد C تبدیل می‌کند. سپس کد تولیدشده با کامپایلر پلتفرم مقصد ساخته می‌شود.

این روش الزاماً به سورس کد اصلی بازی نیاز ندارد؛ بااین‌حال، اطلاعاتی مانند مرزبندی توابع، نمادها و اطلاعات جانبی می‌توانند فرایند را آسان‌تر کنند.

ابزارها و زبان‌ها: C و C++، LLVM و Clang، CMake، ابزارهای Disassembly و تحلیل ELF و Symbol.

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

مثال: پروژه Zelda 64: Recompiled از این فناوری استفاده می‌کند.

۲.۳. Dynamic Recompilation – بازکامپایل پویا

در Dynamic Recompilation، دستورالعمل‌های پردازنده اصلی هنگام اجرای بازی تحلیل و به دستورالعمل‌های قابل اجرا روی پردازنده میزبان تبدیل می‌شوند. تفاوت اصلی آن با Static Recompilation در زمان انجام ترجمه است.

  • بازی یک بلوک کد را اجرا می‌کند.
  • Recompiler دستورالعمل‌های آن بلوک را دریافت می‌کند.
  • دستورالعمل‌ها به کد ماشین پردازنده PC تبدیل می‌شوند.
  • کد ترجمه‌شده در حافظه نگهداری می‌شود.
  • در اجرای مجدد همان بلوک، از نسخه ترجمه‌شده استفاده می‌شود.

این فناوری معمولاً از Cache برای نگهداری بلوک‌های ترجمه‌شده استفاده می‌کند.

مزایا
  • امکان اجرای برنامه‌های دارای کد پویا.
  • عدم نیاز به ترجمه کامل پیش از اجرا.
  • مدیریت کدهایی که هنگام اجرا بارگذاری می‌شوند.
چالش‌ها
  • هزینه اولیه ترجمه در زمان اجرا.
  • پیچیدگی مدیریت Cache.
  • تشخیص تغییر کد و بی‌اعتبار کردن بلوک‌های قدیمی.
  • احتمال تأخیر در اولین اجرای بخش‌ها.

تفاوت با روش ایستا: در روش ایستا بخش بزرگی از کار پیش از اجرای بازی انجام می‌شود؛ اما در روش پویا، موتور ترجمه بخشی از محیط اجرای بازی است.

۲.۴. Static Binary Translation – ترجمه ایستای باینری

این فناوری دستورالعمل‌های یک فایل اجرایی را به دستورالعمل‌های معماری مقصد تبدیل می‌کند؛ برای مثال، تبدیل کد ماشین PowerPC به کد ماشین x86-64.

  • Binary Translation اصطلاح عمومی‌تری برای ترجمه باینری است.
  • Recompilation معمولاً به تولید یک نمایش میانی یا کد قابل کامپایل و ساخت مجدد اشاره می‌کند.

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

۲.۵. Dynamic Binary Translation – ترجمه پویای باینری

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

برای نمونه، یک برنامه ARM ممکن است روی سیستم x86 اجرا شود؛ درحالی‌که بخشی از دستورالعمل‌های آن هنگام اجرا به دستورالعمل‌های x86 تبدیل می‌شوند. این روش با Dynamic Recompilation هم‌پوشانی زیادی دارد.

۲.۶. Reverse Engineering – مهندسی معکوس فرایند پشتیبان

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

موضوعات بررسی‌شده می‌توانند شامل ساختار فایل اجرایی، توابع و ارتباط آن‌ها، ساختار حافظه، ورودی‌ها، رندرینگ، فایل‌های صوتی و تصویری، بارگذاری مراحل و ارتباط بخش‌های موتور باشند.

ابزارهایی مانند Ghidra و IDA Free برای تحلیل باینری‌ها استفاده می‌شوند. مهندسی معکوس در پروژه‌های Recompilation، Engine Recreation و Porting کاربرد فراوانی دارد.

۲.۷. Source Porting – انتقال سورس کد

Source Porting یکی از مستقیم‌ترین روش‌های انتقال بازی به کامپیوتر است؛ البته به شرطی که سورس کد بازی در دسترس باشد. در این روش، توسعه‌دهنده کد اصلی بازی را برای سیستم‌عامل و سخت‌افزار جدید آماده می‌کند.

برای مثال، اگر سورس یک بازی قدیمی C++ در دسترس باشد، می‌توان بخش‌های وابسته به کنسول را با معادل‌های مناسب ویندوز جایگزین کرد.

نمونه‌های نزدیک به این رویکرد: OpenMW برای The Elder Scrolls III: Morrowind و OpenRCT2 برای RollerCoaster Tycoon 2. این دو پروژه صرفاً پورت مستقیم سورس رسمی منتشرشده نیستند؛ بلکه نمونه‌هایی از بازپیاده‌سازی مبتنی بر مهندسی معکوس و کد مستقل‌اند.

مزایا
  • دسترسی به منطق برنامه.
  • امکان تغییر مستقیم بخش‌های مختلف بازی.
  • قابلیت بهینه‌سازی و افزودن ویژگی‌ها.
چالش‌ها
  • نبود سورس کد در بسیاری از بازی‌ها.
  • وابستگی به کتابخانه‌های قدیمی.
  • نیاز به سازگار کردن بخش‌های سخت‌افزاری و سیستم‌عامل.

۲.۸. Engine Recreation – بازسازی موتور بازی

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

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

۲.۹. Engine Reimplementation – پیاده‌سازی مجدد موتور

این روش با Engine Recreation هم‌پوشانی دارد، اما تأکید آن بیشتر بر پیاده‌سازی مجدد رفتار و رابط‌های موتور اصلی است. توسعه‌دهندگان بدون دسترسی به سورس موتور، پیاده‌سازی مستقلی ایجاد می‌کنند که بتواند فایل‌ها و منطق بازی را پشتیبانی کند.

مثال: OpenGOAL نمونه‌ای از این رویکرد در مجموعه Jak and Daxter است.

۲.۱۰. Game Code Reconstruction – بازسازی کد بازی

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

بازسازی کد می‌تواند به تولید نسخه‌ای قابل کامپایل از منطق بازی منجر شود؛ اما لزوماً به معنای بازیابی سورس کد دقیق و اصلی نیست.

۲.۱۱. Decompilation – دی‌کامپایل

Decompilation تلاش می‌کند فایل باینری کامپایل‌شده را به یک نمایش سطح بالاتر، مانند کد شبه‌C، تبدیل کند. خروجی Decompiler معمولاً سورس کد اصلی نیست.

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

۲.۱۲. JIT Compilation – کامپایل هنگام اجرا

JIT مخفف Just-In-Time Compilation است. در این روش، کد در زمان اجرای برنامه به کد ماشین تبدیل می‌شود. JIT می‌تواند در شبیه‌سازها یا موتورهای بازی مورد استفاده قرار بگیرد.

JIT مفهومی گسترده‌تر از Dynamic Recompilation است و می‌تواند کدهای یک زبان سطح بالا یا یک نمایش میانی را نیز به کد ماشین تبدیل کند.

۲.۱۳. HLE – شبیه‌سازی سطح بالا

High-Level Emulation به‌جای تقلید دقیق از تک‌تک رفتارهای سخت‌افزار، عملکرد بخش‌های مهم سیستم اصلی را در سطح بالاتری بازسازی می‌کند.

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

۲.۱۴. LLE – شبیه‌سازی سطح پایین

Low-Level Emulation تلاش می‌کند رفتار سخت‌افزار اصلی را با جزئیات بیشتری شبیه‌سازی کند. در این روش، بخش‌هایی مانند پردازنده، حافظه و واحدهای اختصاصی سخت‌افزار با دقت بیشتری مدل‌سازی می‌شوند.

ویژگیHLELLE
سطح شبیه‌سازیسطح بالاسطح پایین
پیچیدگیمعمولاً کمترمعمولاً بیشتر
دقت سخت‌افزاریوابسته به پیاده‌سازیبالقوه بیشتر
سرعتمعمولاً بالاترمعمولاً هزینه‌برتر
سازگاریوابسته به بازیبالقوه دقیق‌تر

۲.۱۵. Emulator-Based Execution – اجرای مبتنی بر شبیه‌ساز

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

  • PCSX2
  • RPCS3
  • Dolphin
  • Xenia

این روش با پورت Native تفاوت دارد؛ زیرا بازی همچنان در محیط شبیه‌سازی‌شده اجرا می‌شود.

۲.۱۶. API Translation – ترجمه رابط برنامه‌نویسی

API Translation به معنای تبدیل فراخوانی‌های یک رابط برنامه‌نویسی به رابط دیگری است. برای مثال، یک برنامه ممکن است از API اختصاصی کنسول استفاده کند، اما لایه ترجمه درخواست‌های آن را به فراخوانی‌های معادل در ویندوز تبدیل کند.

این فناوری در لایه‌های سازگاری و برخی شبیه‌سازها کاربرد دارد.

۲.۱۷. Graphics API Translation – ترجمه API گرافیکی

این روش روی بخش گرافیکی تمرکز دارد. برای مثال، دستورات یک API گرافیکی می‌توانند به دستورات API دیگری تبدیل شوند.

  • DXVK
  • vkd3d-proton

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

۲.۱۸. Compatibility Layers – لایه‌های سازگاری

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

این فناوری به‌تنهایی معماری پردازنده متفاوت را شبیه‌سازی نمی‌کند؛ بنابراین نباید آن را با Emulator یکی دانست.

۲.۱۹. Runtime Wrappers – پوشش‌دهنده‌های زمان اجرا

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

Wrapperها ممکن است برای سازگار کردن سیستم ورودی، صدا، فایل‌ها، حافظه یا گرافیک استفاده شوند.

۲.۲۰. Hybrid Porting – پورت ترکیبی

در Hybrid Porting، توسعه‌دهنده از چند روش مختلف به‌صورت هم‌زمان استفاده می‌کند. برای مثال، یک پروژه می‌تواند:

  • کد اصلی را با Static Recompilation تبدیل کند.
  • سیستم گرافیکی را با Renderer جدید بازسازی کند.
  • از Wrapper برای برخی توابع کنسول استفاده کند.
  • فایل‌های بازی را از نسخه اصلی بارگذاری کند.
  • بخش‌هایی از سخت‌افزار را به‌صورت نرم‌افزاری شبیه‌سازی کند.

بسیاری از پروژه‌های مدرن دقیقاً در یک دسته‌بندی ساده قرار نمی‌گیرند.

۲.۲۱. Asset Extraction & Reimplementation – استخراج منابع و بازپیاده‌سازی

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

استخراج منابع به‌تنهایی پورت محسوب نمی‌شود. برای تبدیل این منابع به یک بازی قابل اجرا، باید موتور یا سیستمی وجود داشته باشد که بتواند آن‌ها را بارگذاری و پردازش کند. به همین دلیل این روش معمولاً در کنار Engine Recreation، Native Porting یا Recompilation استفاده می‌شود.

۳. ابزارها و پروژه‌های متن‌باز مهم

در این بخش، پروژه‌هایی معرفی می‌شوند که در توسعه پورت‌های غیررسمی، مهندسی معکوس و اجرای بازی‌های کنسولی روی کامپیوتر نقش دارند. تمام پروژه‌های این فهرست پورت نیستند؛ بعضی ابزار تولیدکننده کد، بعضی شبیه‌ساز و بعضی موتورهای بازسازی‌شده هستند.

۱. N64Recomp Static Recompilation

ابزاری برای تبدیل باینری بازی‌های Nintendo 64 به کد C و آماده‌سازی آن برای کامپایل در سیستم‌های جدید. از پروژه‌های الهام‌بخش نسل جدید Recompilerهاست.

۲. Zelda 64: Recompiled Native PC Port

نمونه موفق استفاده از Static Recompilation برای تبدیل Majora's Mask به نسخه قابل اجرای Native. این پروژه از RT64 برای رندرینگ و امکانات گرافیکی جدید استفاده می‌کند. برای اجرا به فایل‌های بازی اصلی نیاز دارد و شبیه‌ساز عمومی N64 نیست.

۳. XenonRecomp Static Recompilation

ابزاری برای تبدیل کد اجرایی Xbox 360 به C++. معماری پردازنده Xbox 360 بر پایه PowerPC است و این ابزار دستورالعمل‌های آن را به کد قابل کامپایل در پلتفرم مقصد تبدیل می‌کند. XenonRecomp به‌تنهایی Runtime کامل بازی را فراهم نمی‌کند و توسعه‌دهنده باید محیط اجرای مناسب را نیز پیاده‌سازی کند.

۴. XenosRecomp ابزار گرافیکی

ابزار مرتبط با تبدیل و پردازش Shaderهای گرافیکی Xbox 360. نام آن را نباید با XenonRecomp اشتباه گرفت؛ Xenon به پردازنده اصلی کنسول اشاره دارد و Xenos نام GPU آن است. ترجمه کد پردازنده و سازگار کردن Shaderها دو مسئله جداگانه‌اند.

۵. PS2 Web Recomp Recompilation / WebAssembly

پروژه‌ای برای تبدیل دستورالعمل‌های Emotion Engine کنسول PS2 به C++ و سپس WebAssembly. از یک Runtime برای شبیه‌سازی قسمت‌های لازم از سخت‌افزار و سیستم‌عامل PS2 استفاده می‌کند. Gran Turismo 4 و God of War II از نمونه‌های آزمایش‌شده آن هستند. این پروژه نشان می‌دهد Recompilation فقط به کنسول‌های ساده و قدیمی محدود نیست.

فهرست ابزارها در این نسخه تا بخشی ادامه دارد که متن ورودی در اختیارمان قرار داده است. می‌توان بخش‌های بعدی مقاله را هم به همین صفحه اضافه کرد.
↑